QueryCache: Implement Async Flushes.
This commit is contained in:
parent
131b342130
commit
0649f05900
|
@ -49,15 +49,17 @@ protected:
|
||||||
bool is_stubbed;
|
bool is_stubbed;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename TFence, typename TTextureCache, typename TTBufferCache>
|
template <typename TFence, typename TTextureCache, typename TTBufferCache, typename TQueryCache>
|
||||||
class FenceManager {
|
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 = texture_cache.HasUncommitedFlushes();
|
||||||
should_flush |= buffer_cache.HasUncommitedFlushes();
|
should_flush |= buffer_cache.HasUncommitedFlushes();
|
||||||
|
should_flush |= query_cache.HasUncommitedFlushes();
|
||||||
texture_cache.CommitAsyncFlushes();
|
texture_cache.CommitAsyncFlushes();
|
||||||
buffer_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,8 +73,10 @@ public:
|
||||||
TryReleasePendingFences();
|
TryReleasePendingFences();
|
||||||
bool should_flush = texture_cache.HasUncommitedFlushes();
|
bool should_flush = texture_cache.HasUncommitedFlushes();
|
||||||
should_flush |= buffer_cache.HasUncommitedFlushes();
|
should_flush |= buffer_cache.HasUncommitedFlushes();
|
||||||
|
should_flush |= query_cache.HasUncommitedFlushes();
|
||||||
texture_cache.CommitAsyncFlushes();
|
texture_cache.CommitAsyncFlushes();
|
||||||
buffer_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);
|
||||||
|
@ -87,11 +91,13 @@ public:
|
||||||
TFence& current_fence = fences.front();
|
TFence& current_fence = fences.front();
|
||||||
bool should_wait = texture_cache.ShouldWaitAsyncFlushes();
|
bool should_wait = texture_cache.ShouldWaitAsyncFlushes();
|
||||||
should_wait |= buffer_cache.ShouldWaitAsyncFlushes();
|
should_wait |= buffer_cache.ShouldWaitAsyncFlushes();
|
||||||
|
should_wait |= query_cache.ShouldWaitAsyncFlushes();
|
||||||
if (should_wait) {
|
if (should_wait) {
|
||||||
WaitFence(current_fence);
|
WaitFence(current_fence);
|
||||||
}
|
}
|
||||||
texture_cache.PopAsyncFlushes();
|
texture_cache.PopAsyncFlushes();
|
||||||
buffer_cache.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()};
|
||||||
|
@ -105,9 +111,10 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
FenceManager(Core::System& system, VideoCore::RasterizerInterface& rasterizer,
|
FenceManager(Core::System& system, VideoCore::RasterizerInterface& rasterizer,
|
||||||
TTextureCache& texture_cache, TTBufferCache& buffer_cache)
|
TTextureCache& texture_cache, TTBufferCache& buffer_cache,
|
||||||
: system{system}, rasterizer{rasterizer}, texture_cache{texture_cache}, buffer_cache{
|
TQueryCache& query_cache)
|
||||||
buffer_cache} {}
|
: system{system}, rasterizer{rasterizer}, texture_cache{texture_cache},
|
||||||
|
buffer_cache{buffer_cache}, query_cache{query_cache} {}
|
||||||
|
|
||||||
virtual TFence CreateFence(u32 value, bool is_stubbed) = 0;
|
virtual TFence CreateFence(u32 value, bool is_stubbed) = 0;
|
||||||
virtual TFence CreateFence(GPUVAddr addr, u32 value, bool is_stubbed) = 0;
|
virtual TFence CreateFence(GPUVAddr addr, u32 value, bool is_stubbed) = 0;
|
||||||
|
@ -119,6 +126,7 @@ protected:
|
||||||
VideoCore::RasterizerInterface& rasterizer;
|
VideoCore::RasterizerInterface& rasterizer;
|
||||||
TTextureCache& texture_cache;
|
TTextureCache& texture_cache;
|
||||||
TTBufferCache& buffer_cache;
|
TTBufferCache& buffer_cache;
|
||||||
|
TQueryCache& query_cache;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void TryReleasePendingFences() {
|
void TryReleasePendingFences() {
|
||||||
|
@ -126,11 +134,13 @@ private:
|
||||||
TFence& current_fence = fences.front();
|
TFence& current_fence = fences.front();
|
||||||
bool should_wait = texture_cache.ShouldWaitAsyncFlushes();
|
bool should_wait = texture_cache.ShouldWaitAsyncFlushes();
|
||||||
should_wait |= buffer_cache.ShouldWaitAsyncFlushes();
|
should_wait |= buffer_cache.ShouldWaitAsyncFlushes();
|
||||||
|
should_wait |= query_cache.ShouldWaitAsyncFlushes();
|
||||||
if (should_wait && !IsFenceSignaled(current_fence)) {
|
if (should_wait && !IsFenceSignaled(current_fence)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
texture_cache.PopAsyncFlushes();
|
texture_cache.PopAsyncFlushes();
|
||||||
buffer_cache.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()};
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <unordered_set>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
|
@ -130,6 +131,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
query->BindCounter(Stream(type).Current(), timestamp);
|
query->BindCounter(Stream(type).Current(), timestamp);
|
||||||
|
AsyncFlushQuery(cpu_addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Updates counters from GPU state. Expected to be called once per draw, clear or dispatch.
|
/// Updates counters from GPU state. Expected to be called once per draw, clear or dispatch.
|
||||||
|
@ -170,6 +172,44 @@ public:
|
||||||
return streams[static_cast<std::size_t>(type)];
|
return streams[static_cast<std::size_t>(type)];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CommitAsyncFlushes() {
|
||||||
|
commited_flushes.push_back(uncommited_flushes);
|
||||||
|
uncommited_flushes.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HasUncommitedFlushes() {
|
||||||
|
if (uncommited_flushes) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ShouldWaitAsyncFlushes() {
|
||||||
|
if (commited_flushes.empty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
auto& flush_list = commited_flushes.front();
|
||||||
|
if (!flush_list) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PopAsyncFlushes() {
|
||||||
|
if (commited_flushes.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto& flush_list = commited_flushes.front();
|
||||||
|
if (!flush_list) {
|
||||||
|
commited_flushes.pop_front();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (VAddr query_address : *flush_list) {
|
||||||
|
FlushAndRemoveRegion(query_address, 4);
|
||||||
|
}
|
||||||
|
commited_flushes.pop_front();
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::array<QueryPool, VideoCore::NumQueryTypes> query_pools;
|
std::array<QueryPool, VideoCore::NumQueryTypes> query_pools;
|
||||||
|
|
||||||
|
@ -224,6 +264,13 @@ private:
|
||||||
return found != std::end(contents) ? &*found : nullptr;
|
return found != std::end(contents) ? &*found : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AsyncFlushQuery(VAddr addr) {
|
||||||
|
if (!uncommited_flushes) {
|
||||||
|
uncommited_flushes = std::make_shared<std::unordered_set<VAddr>>();
|
||||||
|
}
|
||||||
|
uncommited_flushes->insert(addr);
|
||||||
|
}
|
||||||
|
|
||||||
static constexpr std::uintptr_t PAGE_SIZE = 4096;
|
static constexpr std::uintptr_t PAGE_SIZE = 4096;
|
||||||
static constexpr unsigned PAGE_SHIFT = 12;
|
static constexpr unsigned PAGE_SHIFT = 12;
|
||||||
|
|
||||||
|
@ -235,6 +282,9 @@ private:
|
||||||
std::unordered_map<u64, std::vector<CachedQuery>> cached_queries;
|
std::unordered_map<u64, std::vector<CachedQuery>> cached_queries;
|
||||||
|
|
||||||
std::array<CounterStream, VideoCore::NumQueryTypes> streams;
|
std::array<CounterStream, VideoCore::NumQueryTypes> streams;
|
||||||
|
|
||||||
|
std::shared_ptr<std::unordered_set<VAddr>> uncommited_flushes{};
|
||||||
|
std::list<std::shared_ptr<std::unordered_set<VAddr>>> commited_flushes;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class QueryCache, class HostCounter>
|
template <class QueryCache, class HostCounter>
|
||||||
|
|
|
@ -44,9 +44,11 @@ void GLInnerFence::Wait() {
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
FenceManagerOpenGL::FenceManagerOpenGL(Core::System& system, VideoCore::RasterizerInterface& rasterizer,
|
FenceManagerOpenGL::FenceManagerOpenGL(Core::System& system,
|
||||||
TextureCacheOpenGL& texture_cache, OGLBufferCache& buffer_cache)
|
VideoCore::RasterizerInterface& rasterizer,
|
||||||
: GenericFenceManager(system, rasterizer, texture_cache, buffer_cache) {}
|
TextureCacheOpenGL& texture_cache,
|
||||||
|
OGLBufferCache& buffer_cache, QueryCache& query_cache)
|
||||||
|
: GenericFenceManager(system, rasterizer, texture_cache, buffer_cache, query_cache) {}
|
||||||
|
|
||||||
Fence FenceManagerOpenGL::CreateFence(u32 value, bool is_stubbed) {
|
Fence FenceManagerOpenGL::CreateFence(u32 value, bool is_stubbed) {
|
||||||
return std::make_shared<GLInnerFence>(value, is_stubbed);
|
return std::make_shared<GLInnerFence>(value, is_stubbed);
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "video_core/fence_manager.h"
|
#include "video_core/fence_manager.h"
|
||||||
#include "video_core/renderer_opengl/gl_buffer_cache.h"
|
#include "video_core/renderer_opengl/gl_buffer_cache.h"
|
||||||
|
#include "video_core/renderer_opengl/gl_query_cache.h"
|
||||||
#include "video_core/renderer_opengl/gl_resource_manager.h"
|
#include "video_core/renderer_opengl/gl_resource_manager.h"
|
||||||
#include "video_core/renderer_opengl/gl_texture_cache.h"
|
#include "video_core/renderer_opengl/gl_texture_cache.h"
|
||||||
|
|
||||||
|
@ -32,12 +33,14 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
using Fence = std::shared_ptr<GLInnerFence>;
|
using Fence = std::shared_ptr<GLInnerFence>;
|
||||||
using GenericFenceManager = VideoCommon::FenceManager<Fence, TextureCacheOpenGL, OGLBufferCache>;
|
using GenericFenceManager =
|
||||||
|
VideoCommon::FenceManager<Fence, TextureCacheOpenGL, OGLBufferCache, QueryCache>;
|
||||||
|
|
||||||
class FenceManagerOpenGL final : public GenericFenceManager {
|
class FenceManagerOpenGL final : public GenericFenceManager {
|
||||||
public:
|
public:
|
||||||
FenceManagerOpenGL(Core::System& system, VideoCore::RasterizerInterface& rasterizer,
|
FenceManagerOpenGL(Core::System& system, VideoCore::RasterizerInterface& rasterizer,
|
||||||
TextureCacheOpenGL& texture_cache, OGLBufferCache& buffer_cache);
|
TextureCacheOpenGL& texture_cache, OGLBufferCache& buffer_cache,
|
||||||
|
QueryCache& query_cache);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Fence CreateFence(u32 value, bool is_stubbed) override;
|
Fence CreateFence(u32 value, bool is_stubbed) override;
|
||||||
|
|
|
@ -101,9 +101,9 @@ RasterizerOpenGL::RasterizerOpenGL(Core::System& system, Core::Frontend::EmuWind
|
||||||
: RasterizerAccelerated{system.Memory()}, texture_cache{system, *this, device, state_tracker},
|
: RasterizerAccelerated{system.Memory()}, texture_cache{system, *this, device, state_tracker},
|
||||||
shader_cache{*this, system, emu_window, device}, query_cache{system, *this}, system{system},
|
shader_cache{*this, system, emu_window, device}, query_cache{system, *this}, system{system},
|
||||||
screen_info{info}, program_manager{program_manager}, state_tracker{state_tracker},
|
screen_info{info}, program_manager{program_manager}, state_tracker{state_tracker},
|
||||||
buffer_cache{*this, system, device, STREAM_BUFFER_SIZE}, fence_manager{system, *this,
|
buffer_cache{*this, system, device, STREAM_BUFFER_SIZE}, fence_manager{
|
||||||
texture_cache,
|
system, *this, texture_cache,
|
||||||
buffer_cache} {
|
buffer_cache, query_cache} {
|
||||||
CheckExtensions();
|
CheckExtensions();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Reference in New Issue