Address Feedback.

merge-requests/60/head
Fernando Sahmkow 2020-04-16 12:29:53 +07:00
parent ec2f3e48e1
commit f616dc0b59
13 changed files with 117 additions and 132 deletions

@ -154,12 +154,9 @@ public:
std::lock_guard lock{mutex}; std::lock_guard lock{mutex};
std::vector<MapInterval> objects = GetMapsInRange(addr, size); std::vector<MapInterval> objects = GetMapsInRange(addr, size);
for (auto& object : objects) { return std::any_of(objects.begin(), objects.end(), [](const MapInterval& map) {
if (object->IsModified() && object->IsRegistered()) { return map->IsModified() && map->IsRegistered();
return true; });
}
}
return false;
} }
/// Mark the specified region as being invalidated /// Mark the specified region as being invalidated
@ -199,9 +196,9 @@ public:
} }
void CommitAsyncFlushes() { void CommitAsyncFlushes() {
if (uncommited_flushes) { if (uncommitted_flushes) {
auto commit_list = std::make_shared<std::list<MapInterval>>(); auto commit_list = std::make_shared<std::list<MapInterval>>();
for (auto& map : *uncommited_flushes) { for (auto& map : *uncommitted_flushes) {
if (map->IsRegistered() && map->IsModified()) { if (map->IsRegistered() && map->IsModified()) {
// TODO(Blinkhawk): Implement backend asynchronous flushing // TODO(Blinkhawk): Implement backend asynchronous flushing
// AsyncFlushMap(map) // AsyncFlushMap(map)
@ -209,41 +206,34 @@ public:
} }
} }
if (!commit_list->empty()) { if (!commit_list->empty()) {
commited_flushes.push_back(commit_list); committed_flushes.push_back(commit_list);
} else { } else {
commited_flushes.emplace_back(); committed_flushes.emplace_back();
} }
} else { } else {
commited_flushes.emplace_back(); committed_flushes.emplace_back();
} }
uncommited_flushes.reset(); uncommitted_flushes.reset();
} }
bool ShouldWaitAsyncFlushes() { bool ShouldWaitAsyncFlushes() const {
if (commited_flushes.empty()) { if (committed_flushes.empty()) {
return false; return false;
} }
auto& flush_list = commited_flushes.front(); return committed_flushes.front() != nullptr;
if (!flush_list) {
return false;
}
return true;
} }
bool HasUncommitedFlushes() { bool HasUncommittedFlushes() const {
if (uncommited_flushes) { return uncommitted_flushes != nullptr;
return true;
}
return false;
} }
void PopAsyncFlushes() { void PopAsyncFlushes() {
if (commited_flushes.empty()) { if (committed_flushes.empty()) {
return; return;
} }
auto& flush_list = commited_flushes.front(); auto& flush_list = committed_flushes.front();
if (!flush_list) { if (!flush_list) {
commited_flushes.pop_front(); committed_flushes.pop_front();
return; return;
} }
for (MapInterval& map : *flush_list) { for (MapInterval& map : *flush_list) {
@ -252,7 +242,7 @@ public:
FlushMap(map); FlushMap(map);
} }
} }
commited_flushes.pop_front(); committed_flushes.pop_front();
} }
virtual BufferType GetEmptyBuffer(std::size_t size) = 0; virtual BufferType GetEmptyBuffer(std::size_t size) = 0;
@ -568,10 +558,10 @@ private:
} }
void MarkForAsyncFlush(MapInterval& map) { void MarkForAsyncFlush(MapInterval& map) {
if (!uncommited_flushes) { if (!uncommitted_flushes) {
uncommited_flushes = std::make_shared<std::unordered_set<MapInterval>>(); uncommitted_flushes = std::make_shared<std::unordered_set<MapInterval>>();
} }
uncommited_flushes->insert(map); uncommitted_flushes->insert(map);
} }
VideoCore::RasterizerInterface& rasterizer; VideoCore::RasterizerInterface& rasterizer;
@ -605,8 +595,8 @@ private:
std::vector<u8> staging_buffer; std::vector<u8> staging_buffer;
std::list<MapInterval> marked_for_unregister; std::list<MapInterval> marked_for_unregister;
std::shared_ptr<std::unordered_set<MapInterval>> uncommited_flushes{}; std::shared_ptr<std::unordered_set<MapInterval>> uncommitted_flushes{};
std::list<std::shared_ptr<std::list<MapInterval>>> commited_flushes; std::list<std::shared_ptr<std::list<MapInterval>>> committed_flushes;
std::recursive_mutex mutex; std::recursive_mutex mutex;
}; };

@ -28,15 +28,15 @@ public:
FenceBase(GPUVAddr address, u32 payload, bool is_stubbed) FenceBase(GPUVAddr address, u32 payload, bool is_stubbed)
: address{address}, payload{payload}, is_semaphore{true}, is_stubbed{is_stubbed} {} : address{address}, payload{payload}, is_semaphore{true}, is_stubbed{is_stubbed} {}
constexpr GPUVAddr GetAddress() const { GPUVAddr GetAddress() const {
return address; return address;
} }
constexpr u32 GetPayload() const { u32 GetPayload() const {
return payload; return payload;
} }
constexpr bool IsSemaphore() const { bool IsSemaphore() const {
return is_semaphore; return is_semaphore;
} }
@ -54,12 +54,8 @@ class FenceManager {
public: public:
void SignalSemaphore(GPUVAddr addr, u32 value) { void SignalSemaphore(GPUVAddr addr, u32 value) {
TryReleasePendingFences(); TryReleasePendingFences();
bool should_flush = texture_cache.HasUncommitedFlushes(); bool should_flush = ShouldFlush();
should_flush |= buffer_cache.HasUncommitedFlushes(); CommitAsyncFlushes();
should_flush |= query_cache.HasUncommitedFlushes();
texture_cache.CommitAsyncFlushes();
buffer_cache.CommitAsyncFlushes();
query_cache.CommitAsyncFlushes();
TFence new_fence = CreateFence(addr, value, !should_flush); TFence new_fence = CreateFence(addr, value, !should_flush);
fences.push(new_fence); fences.push(new_fence);
QueueFence(new_fence); QueueFence(new_fence);
@ -71,12 +67,8 @@ public:
void SignalSyncPoint(u32 value) { void SignalSyncPoint(u32 value) {
TryReleasePendingFences(); TryReleasePendingFences();
bool should_flush = texture_cache.HasUncommitedFlushes(); bool should_flush = ShouldFlush();
should_flush |= buffer_cache.HasUncommitedFlushes(); CommitAsyncFlushes();
should_flush |= query_cache.HasUncommitedFlushes();
texture_cache.CommitAsyncFlushes();
buffer_cache.CommitAsyncFlushes();
query_cache.CommitAsyncFlushes();
TFence new_fence = CreateFence(value, !should_flush); TFence new_fence = CreateFence(value, !should_flush);
fences.push(new_fence); fences.push(new_fence);
QueueFence(new_fence); QueueFence(new_fence);
@ -89,15 +81,10 @@ public:
void WaitPendingFences() { void WaitPendingFences() {
while (!fences.empty()) { while (!fences.empty()) {
TFence& current_fence = fences.front(); TFence& current_fence = fences.front();
bool should_wait = texture_cache.ShouldWaitAsyncFlushes(); if (ShouldWait()) {
should_wait |= buffer_cache.ShouldWaitAsyncFlushes();
should_wait |= query_cache.ShouldWaitAsyncFlushes();
if (should_wait) {
WaitFence(current_fence); WaitFence(current_fence);
} }
texture_cache.PopAsyncFlushes(); PopAsyncFlushes();
buffer_cache.PopAsyncFlushes();
query_cache.PopAsyncFlushes();
auto& gpu{system.GPU()}; auto& gpu{system.GPU()};
if (current_fence->IsSemaphore()) { if (current_fence->IsSemaphore()) {
auto& memory_manager{gpu.MemoryManager()}; auto& memory_manager{gpu.MemoryManager()};
@ -116,10 +103,18 @@ protected:
: system{system}, rasterizer{rasterizer}, texture_cache{texture_cache}, : system{system}, rasterizer{rasterizer}, texture_cache{texture_cache},
buffer_cache{buffer_cache}, query_cache{query_cache} {} buffer_cache{buffer_cache}, query_cache{query_cache} {}
virtual ~FenceManager() {}
/// Creates a Sync Point Fence Interface, does not create a backend fence if 'is_stubbed' is
/// true
virtual TFence CreateFence(u32 value, bool is_stubbed) = 0; virtual TFence CreateFence(u32 value, bool is_stubbed) = 0;
/// Creates a Semaphore Fence Interface, does not create a backend fence if 'is_stubbed' is true
virtual TFence CreateFence(GPUVAddr addr, u32 value, bool is_stubbed) = 0; virtual TFence CreateFence(GPUVAddr addr, u32 value, bool is_stubbed) = 0;
/// Queues a fence into the backend if the fence isn't stubbed.
virtual void QueueFence(TFence& fence) = 0; virtual void QueueFence(TFence& fence) = 0;
virtual bool IsFenceSignaled(TFence& fence) = 0; /// Notifies that the backend fence has been signaled/reached in host GPU.
virtual bool IsFenceSignaled(TFence& fence) const = 0;
/// Waits until a fence has been signalled by the host GPU.
virtual void WaitFence(TFence& fence) = 0; virtual void WaitFence(TFence& fence) = 0;
Core::System& system; Core::System& system;
@ -132,15 +127,10 @@ private:
void TryReleasePendingFences() { void TryReleasePendingFences() {
while (!fences.empty()) { while (!fences.empty()) {
TFence& current_fence = fences.front(); TFence& current_fence = fences.front();
bool should_wait = texture_cache.ShouldWaitAsyncFlushes(); if (ShouldWait() && !IsFenceSignaled(current_fence)) {
should_wait |= buffer_cache.ShouldWaitAsyncFlushes();
should_wait |= query_cache.ShouldWaitAsyncFlushes();
if (should_wait && !IsFenceSignaled(current_fence)) {
return; return;
} }
texture_cache.PopAsyncFlushes(); PopAsyncFlushes();
buffer_cache.PopAsyncFlushes();
query_cache.PopAsyncFlushes();
auto& gpu{system.GPU()}; auto& gpu{system.GPU()};
if (current_fence->IsSemaphore()) { if (current_fence->IsSemaphore()) {
auto& memory_manager{gpu.MemoryManager()}; auto& memory_manager{gpu.MemoryManager()};
@ -152,6 +142,28 @@ private:
} }
} }
bool ShouldWait() const {
return texture_cache.ShouldWaitAsyncFlushes() || buffer_cache.ShouldWaitAsyncFlushes() ||
query_cache.ShouldWaitAsyncFlushes();
}
bool ShouldFlush() const {
return texture_cache.HasUncommittedFlushes() || buffer_cache.HasUncommittedFlushes() ||
query_cache.HasUncommittedFlushes();
}
void PopAsyncFlushes() {
texture_cache.PopAsyncFlushes();
buffer_cache.PopAsyncFlushes();
query_cache.PopAsyncFlushes();
}
void CommitAsyncFlushes() {
texture_cache.CommitAsyncFlushes();
buffer_cache.CommitAsyncFlushes();
query_cache.CommitAsyncFlushes();
}
std::queue<TFence> fences; std::queue<TFence> fences;
}; };

@ -125,7 +125,7 @@ bool GPU::CancelSyncptInterrupt(const u32 syncpoint_id, const u32 value) {
return true; return true;
} }
u64 GPU::RequestFlush(CacheAddr addr, std::size_t size) { u64 GPU::RequestFlush(VAddr addr, std::size_t size) {
std::unique_lock lck{flush_request_mutex}; std::unique_lock lck{flush_request_mutex};
const u64 fence = ++last_flush_fence; const u64 fence = ++last_flush_fence;
flush_requests.emplace_back(fence, addr, size); flush_requests.emplace_back(fence, addr, size);
@ -137,7 +137,7 @@ void GPU::TickWork() {
while (!flush_requests.empty()) { while (!flush_requests.empty()) {
auto& request = flush_requests.front(); auto& request = flush_requests.front();
const u64 fence = request.fence; const u64 fence = request.fence;
const CacheAddr addr = request.addr; const VAddr addr = request.addr;
const std::size_t size = request.size; const std::size_t size = request.size;
flush_requests.pop_front(); flush_requests.pop_front();
flush_request_mutex.unlock(); flush_request_mutex.unlock();

@ -155,16 +155,22 @@ public:
/// Calls a GPU method. /// Calls a GPU method.
void CallMethod(const MethodCall& method_call); void CallMethod(const MethodCall& method_call);
/// Flush all current written commands into the host GPU for execution.
void FlushCommands(); void FlushCommands();
/// Synchronizes CPU writes with Host GPU memory.
void SyncGuestHost(); void SyncGuestHost();
/// Signal the ending of command list.
virtual void OnCommandListEnd(); virtual void OnCommandListEnd();
u64 RequestFlush(CacheAddr addr, std::size_t size); /// Request a host GPU memory flush from the CPU.
u64 RequestFlush(VAddr addr, std::size_t size);
/// Obtains current flush request fence id.
u64 CurrentFlushRequestFence() const { u64 CurrentFlushRequestFence() const {
return current_flush_fence.load(std::memory_order_relaxed); return current_flush_fence.load(std::memory_order_relaxed);
} }
/// Tick pending requests within the GPU.
void TickWork(); void TickWork();
/// Returns a reference to the Maxwell3D GPU engine. /// Returns a reference to the Maxwell3D GPU engine.
@ -336,10 +342,10 @@ private:
std::condition_variable sync_cv; std::condition_variable sync_cv;
struct FlushRequest { struct FlushRequest {
FlushRequest(u64 fence, CacheAddr addr, std::size_t size) FlushRequest(u64 fence, VAddr addr, std::size_t size)
: fence{fence}, addr{addr}, size{size} {} : fence{fence}, addr{addr}, size{size} {}
u64 fence; u64 fence;
CacheAddr addr; VAddr addr;
std::size_t size; std::size_t size;
}; };

@ -176,41 +176,34 @@ public:
} }
void CommitAsyncFlushes() { void CommitAsyncFlushes() {
commited_flushes.push_back(uncommited_flushes); committed_flushes.push_back(uncommitted_flushes);
uncommited_flushes.reset(); uncommitted_flushes.reset();
} }
bool HasUncommitedFlushes() { bool HasUncommittedFlushes() const {
if (uncommited_flushes) { return uncommitted_flushes != nullptr;
return true;
}
return false;
} }
bool ShouldWaitAsyncFlushes() { bool ShouldWaitAsyncFlushes() const {
if (commited_flushes.empty()) { if (committed_flushes.empty()) {
return false; return false;
} }
auto& flush_list = commited_flushes.front(); return committed_flushes.front() != nullptr;
if (!flush_list) {
return false;
}
return true;
} }
void PopAsyncFlushes() { void PopAsyncFlushes() {
if (commited_flushes.empty()) { if (committed_flushes.empty()) {
return; return;
} }
auto& flush_list = commited_flushes.front(); auto& flush_list = committed_flushes.front();
if (!flush_list) { if (!flush_list) {
commited_flushes.pop_front(); committed_flushes.pop_front();
return; return;
} }
for (VAddr query_address : *flush_list) { for (VAddr query_address : *flush_list) {
FlushAndRemoveRegion(query_address, 4); FlushAndRemoveRegion(query_address, 4);
} }
commited_flushes.pop_front(); committed_flushes.pop_front();
} }
protected: protected:
@ -268,10 +261,10 @@ private:
} }
void AsyncFlushQuery(VAddr addr) { void AsyncFlushQuery(VAddr addr) {
if (!uncommited_flushes) { if (!uncommitted_flushes) {
uncommited_flushes = std::make_shared<std::unordered_set<VAddr>>(); uncommitted_flushes = std::make_shared<std::unordered_set<VAddr>>();
} }
uncommited_flushes->insert(addr); uncommitted_flushes->insert(addr);
} }
static constexpr std::uintptr_t PAGE_SIZE = 4096; static constexpr std::uintptr_t PAGE_SIZE = 4096;
@ -286,8 +279,8 @@ private:
std::array<CounterStream, VideoCore::NumQueryTypes> streams; std::array<CounterStream, VideoCore::NumQueryTypes> streams;
std::shared_ptr<std::unordered_set<VAddr>> uncommited_flushes{}; std::shared_ptr<std::unordered_set<VAddr>> uncommitted_flushes{};
std::list<std::shared_ptr<std::unordered_set<VAddr>>> commited_flushes; std::list<std::shared_ptr<std::unordered_set<VAddr>>> committed_flushes;
}; };
template <class QueryCache, class HostCounter> template <class QueryCache, class HostCounter>

@ -64,6 +64,7 @@ public:
/// Notify rasterizer that any caches of the specified region should be flushed to Switch memory /// Notify rasterizer that any caches of the specified region should be flushed to Switch memory
virtual void FlushRegion(VAddr addr, u64 size) = 0; virtual void FlushRegion(VAddr addr, u64 size) = 0;
/// Check if the the specified memory area requires flushing to CPU Memory.
virtual bool MustFlushRegion(VAddr addr, u64 size) = 0; virtual bool MustFlushRegion(VAddr addr, u64 size) = 0;
/// Notify rasterizer that any caches of the specified region should be invalidated /// Notify rasterizer that any caches of the specified region should be invalidated

@ -62,7 +62,7 @@ void FenceManagerOpenGL::QueueFence(Fence& fence) {
fence->Queue(); fence->Queue();
} }
bool FenceManagerOpenGL::IsFenceSignaled(Fence& fence) { bool FenceManagerOpenGL::IsFenceSignaled(Fence& fence) const {
return fence->IsSignaled(); return fence->IsSignaled();
} }

@ -46,7 +46,7 @@ protected:
Fence CreateFence(u32 value, bool is_stubbed) override; Fence CreateFence(u32 value, bool is_stubbed) override;
Fence CreateFence(GPUVAddr addr, u32 value, bool is_stubbed) override; Fence CreateFence(GPUVAddr addr, u32 value, bool is_stubbed) override;
void QueueFence(Fence& fence) override; void QueueFence(Fence& fence) override;
bool IsFenceSignaled(Fence& fence) override; bool IsFenceSignaled(Fence& fence) const override;
void WaitFence(Fence& fence) override; void WaitFence(Fence& fence) override;
}; };

@ -653,9 +653,6 @@ void RasterizerOpenGL::FlushRegion(VAddr addr, u64 size) {
} }
bool RasterizerOpenGL::MustFlushRegion(VAddr addr, u64 size) { bool RasterizerOpenGL::MustFlushRegion(VAddr addr, u64 size) {
if (!Settings::IsGPULevelExtreme()) {
return buffer_cache.MustFlushRegion(addr, size);
}
return texture_cache.MustFlushRegion(addr, size) || buffer_cache.MustFlushRegion(addr, size); return texture_cache.MustFlushRegion(addr, size) || buffer_cache.MustFlushRegion(addr, size);
} }
@ -672,7 +669,7 @@ void RasterizerOpenGL::InvalidateRegion(VAddr addr, u64 size) {
void RasterizerOpenGL::OnCPUWrite(VAddr addr, u64 size) { void RasterizerOpenGL::OnCPUWrite(VAddr addr, u64 size) {
MICROPROFILE_SCOPE(OpenGL_CacheManagement); MICROPROFILE_SCOPE(OpenGL_CacheManagement);
if (!addr || !size) { if (addr == 0 || size == 0) {
return; return;
} }
texture_cache.OnCPUWrite(addr, size); texture_cache.OnCPUWrite(addr, size);

@ -90,7 +90,7 @@ void VKFenceManager::QueueFence(Fence& fence) {
fence->Queue(); fence->Queue();
} }
bool VKFenceManager::IsFenceSignaled(Fence& fence) { bool VKFenceManager::IsFenceSignaled(Fence& fence) const {
return fence->IsSignaled(); return fence->IsSignaled();
} }

@ -63,7 +63,7 @@ protected:
Fence CreateFence(u32 value, bool is_stubbed) override; Fence CreateFence(u32 value, bool is_stubbed) override;
Fence CreateFence(GPUVAddr addr, u32 value, bool is_stubbed) override; Fence CreateFence(GPUVAddr addr, u32 value, bool is_stubbed) override;
void QueueFence(Fence& fence) override; void QueueFence(Fence& fence) override;
bool IsFenceSignaled(Fence& fence) override; bool IsFenceSignaled(Fence& fence) const override;
void WaitFence(Fence& fence) override; void WaitFence(Fence& fence) override;
private: private:

@ -533,7 +533,7 @@ void RasterizerVulkan::InvalidateRegion(VAddr addr, u64 size) {
} }
void RasterizerVulkan::OnCPUWrite(VAddr addr, u64 size) { void RasterizerVulkan::OnCPUWrite(VAddr addr, u64 size) {
if (!addr || !size) { if (addr == 0 || size == 0) {
return; return;
} }
texture_cache.OnCPUWrite(addr, size); texture_cache.OnCPUWrite(addr, size);

@ -120,15 +120,8 @@ public:
std::lock_guard lock{mutex}; std::lock_guard lock{mutex};
auto surfaces = GetSurfacesInRegion(addr, size); auto surfaces = GetSurfacesInRegion(addr, size);
if (surfaces.empty()) { return std::any_of(surfaces.begin(), surfaces.end(),
return false; [](const TSurface& surface) { return surface->IsModified(); });
}
for (const auto& surface : surfaces) {
if (surface->IsModified()) {
return true;
}
}
return false;
} }
TView GetTextureSurface(const Tegra::Texture::TICEntry& tic, TView GetTextureSurface(const Tegra::Texture::TICEntry& tic,
@ -333,41 +326,34 @@ public:
} }
void CommitAsyncFlushes() { void CommitAsyncFlushes() {
commited_flushes.push_back(uncommited_flushes); committed_flushes.push_back(uncommitted_flushes);
uncommited_flushes.reset(); uncommitted_flushes.reset();
} }
bool HasUncommitedFlushes() { bool HasUncommittedFlushes() const {
if (uncommited_flushes) { return uncommitted_flushes != nullptr;
return true;
}
return false;
} }
bool ShouldWaitAsyncFlushes() { bool ShouldWaitAsyncFlushes() const {
if (commited_flushes.empty()) { if (committed_flushes.empty()) {
return false; return false;
} }
auto& flush_list = commited_flushes.front(); return committed_flushes.front() != nullptr;
if (!flush_list) {
return false;
}
return true;
} }
void PopAsyncFlushes() { void PopAsyncFlushes() {
if (commited_flushes.empty()) { if (committed_flushes.empty()) {
return; return;
} }
auto& flush_list = commited_flushes.front(); auto& flush_list = committed_flushes.front();
if (!flush_list) { if (!flush_list) {
commited_flushes.pop_front(); committed_flushes.pop_front();
return; return;
} }
for (TSurface& surface : *flush_list) { for (TSurface& surface : *flush_list) {
FlushSurface(surface); FlushSurface(surface);
} }
commited_flushes.pop_front(); committed_flushes.pop_front();
} }
protected: protected:
@ -1206,10 +1192,10 @@ private:
}; };
void AsyncFlushSurface(TSurface& surface) { void AsyncFlushSurface(TSurface& surface) {
if (!uncommited_flushes) { if (!uncommitted_flushes) {
uncommited_flushes = std::make_shared<std::list<TSurface>>(); uncommitted_flushes = std::make_shared<std::list<TSurface>>();
} }
uncommited_flushes->push_back(surface); uncommitted_flushes->push_back(surface);
} }
VideoCore::RasterizerInterface& rasterizer; VideoCore::RasterizerInterface& rasterizer;
@ -1258,8 +1244,8 @@ private:
std::list<TSurface> marked_for_unregister; std::list<TSurface> marked_for_unregister;
std::shared_ptr<std::list<TSurface>> uncommited_flushes{}; std::shared_ptr<std::list<TSurface>> uncommitted_flushes{};
std::list<std::shared_ptr<std::list<TSurface>>> commited_flushes; std::list<std::shared_ptr<std::list<TSurface>>> committed_flushes;
StagingCache staging_cache; StagingCache staging_cache;
std::recursive_mutex mutex; std::recursive_mutex mutex;