QueryCache: Implement Async Flushes.
This commit is contained in:
		@@ -49,15 +49,17 @@ protected:
 | 
			
		||||
    bool is_stubbed;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename TFence, typename TTextureCache, typename TTBufferCache>
 | 
			
		||||
template <typename TFence, typename TTextureCache, typename TTBufferCache, typename TQueryCache>
 | 
			
		||||
class FenceManager {
 | 
			
		||||
public:
 | 
			
		||||
    void SignalSemaphore(GPUVAddr addr, u32 value) {
 | 
			
		||||
        TryReleasePendingFences();
 | 
			
		||||
        bool should_flush = texture_cache.HasUncommitedFlushes();
 | 
			
		||||
        should_flush |= buffer_cache.HasUncommitedFlushes();
 | 
			
		||||
        should_flush |= query_cache.HasUncommitedFlushes();
 | 
			
		||||
        texture_cache.CommitAsyncFlushes();
 | 
			
		||||
        buffer_cache.CommitAsyncFlushes();
 | 
			
		||||
        query_cache.CommitAsyncFlushes();
 | 
			
		||||
        TFence new_fence = CreateFence(addr, value, !should_flush);
 | 
			
		||||
        fences.push(new_fence);
 | 
			
		||||
        QueueFence(new_fence);
 | 
			
		||||
@@ -71,8 +73,10 @@ public:
 | 
			
		||||
        TryReleasePendingFences();
 | 
			
		||||
        bool should_flush = texture_cache.HasUncommitedFlushes();
 | 
			
		||||
        should_flush |= buffer_cache.HasUncommitedFlushes();
 | 
			
		||||
        should_flush |= query_cache.HasUncommitedFlushes();
 | 
			
		||||
        texture_cache.CommitAsyncFlushes();
 | 
			
		||||
        buffer_cache.CommitAsyncFlushes();
 | 
			
		||||
        query_cache.CommitAsyncFlushes();
 | 
			
		||||
        TFence new_fence = CreateFence(value, !should_flush);
 | 
			
		||||
        fences.push(new_fence);
 | 
			
		||||
        QueueFence(new_fence);
 | 
			
		||||
@@ -87,11 +91,13 @@ public:
 | 
			
		||||
            TFence& current_fence = fences.front();
 | 
			
		||||
            bool should_wait = texture_cache.ShouldWaitAsyncFlushes();
 | 
			
		||||
            should_wait |= buffer_cache.ShouldWaitAsyncFlushes();
 | 
			
		||||
            should_wait |= query_cache.ShouldWaitAsyncFlushes();
 | 
			
		||||
            if (should_wait) {
 | 
			
		||||
                WaitFence(current_fence);
 | 
			
		||||
            }
 | 
			
		||||
            texture_cache.PopAsyncFlushes();
 | 
			
		||||
            buffer_cache.PopAsyncFlushes();
 | 
			
		||||
            query_cache.PopAsyncFlushes();
 | 
			
		||||
            auto& gpu{system.GPU()};
 | 
			
		||||
            if (current_fence->IsSemaphore()) {
 | 
			
		||||
                auto& memory_manager{gpu.MemoryManager()};
 | 
			
		||||
@@ -105,9 +111,10 @@ public:
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
    FenceManager(Core::System& system, VideoCore::RasterizerInterface& rasterizer,
 | 
			
		||||
                 TTextureCache& texture_cache, TTBufferCache& buffer_cache)
 | 
			
		||||
        : system{system}, rasterizer{rasterizer}, texture_cache{texture_cache}, buffer_cache{
 | 
			
		||||
                                                                                    buffer_cache} {}
 | 
			
		||||
                 TTextureCache& texture_cache, TTBufferCache& buffer_cache,
 | 
			
		||||
                 TQueryCache& query_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(GPUVAddr addr, u32 value, bool is_stubbed) = 0;
 | 
			
		||||
@@ -119,6 +126,7 @@ protected:
 | 
			
		||||
    VideoCore::RasterizerInterface& rasterizer;
 | 
			
		||||
    TTextureCache& texture_cache;
 | 
			
		||||
    TTBufferCache& buffer_cache;
 | 
			
		||||
    TQueryCache& query_cache;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    void TryReleasePendingFences() {
 | 
			
		||||
@@ -126,11 +134,13 @@ private:
 | 
			
		||||
            TFence& current_fence = fences.front();
 | 
			
		||||
            bool should_wait = texture_cache.ShouldWaitAsyncFlushes();
 | 
			
		||||
            should_wait |= buffer_cache.ShouldWaitAsyncFlushes();
 | 
			
		||||
            should_wait |= query_cache.ShouldWaitAsyncFlushes();
 | 
			
		||||
            if (should_wait && !IsFenceSignaled(current_fence)) {
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            texture_cache.PopAsyncFlushes();
 | 
			
		||||
            buffer_cache.PopAsyncFlushes();
 | 
			
		||||
            query_cache.PopAsyncFlushes();
 | 
			
		||||
            auto& gpu{system.GPU()};
 | 
			
		||||
            if (current_fence->IsSemaphore()) {
 | 
			
		||||
                auto& memory_manager{gpu.MemoryManager()};
 | 
			
		||||
 
 | 
			
		||||
@@ -12,6 +12,7 @@
 | 
			
		||||
#include <mutex>
 | 
			
		||||
#include <optional>
 | 
			
		||||
#include <unordered_map>
 | 
			
		||||
#include <unordered_set>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
#include "common/assert.h"
 | 
			
		||||
@@ -130,6 +131,7 @@ public:
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        query->BindCounter(Stream(type).Current(), timestamp);
 | 
			
		||||
        AsyncFlushQuery(cpu_addr);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// 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)];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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:
 | 
			
		||||
    std::array<QueryPool, VideoCore::NumQueryTypes> query_pools;
 | 
			
		||||
 | 
			
		||||
@@ -224,6 +264,13 @@ private:
 | 
			
		||||
        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 unsigned PAGE_SHIFT = 12;
 | 
			
		||||
 | 
			
		||||
@@ -235,6 +282,9 @@ private:
 | 
			
		||||
    std::unordered_map<u64, std::vector<CachedQuery>> cached_queries;
 | 
			
		||||
 | 
			
		||||
    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>
 | 
			
		||||
 
 | 
			
		||||
@@ -44,9 +44,11 @@ void GLInnerFence::Wait() {
 | 
			
		||||
        ;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
FenceManagerOpenGL::FenceManagerOpenGL(Core::System& system, VideoCore::RasterizerInterface& rasterizer,
 | 
			
		||||
                               TextureCacheOpenGL& texture_cache, OGLBufferCache& buffer_cache)
 | 
			
		||||
    : GenericFenceManager(system, rasterizer, texture_cache, buffer_cache) {}
 | 
			
		||||
FenceManagerOpenGL::FenceManagerOpenGL(Core::System& system,
 | 
			
		||||
                                       VideoCore::RasterizerInterface& rasterizer,
 | 
			
		||||
                                       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) {
 | 
			
		||||
    return std::make_shared<GLInnerFence>(value, is_stubbed);
 | 
			
		||||
 
 | 
			
		||||
@@ -10,6 +10,7 @@
 | 
			
		||||
#include "common/common_types.h"
 | 
			
		||||
#include "video_core/fence_manager.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_texture_cache.h"
 | 
			
		||||
 | 
			
		||||
@@ -32,12 +33,14 @@ private:
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
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 {
 | 
			
		||||
public:
 | 
			
		||||
    FenceManagerOpenGL(Core::System& system, VideoCore::RasterizerInterface& rasterizer,
 | 
			
		||||
                       TextureCacheOpenGL& texture_cache, OGLBufferCache& buffer_cache);
 | 
			
		||||
                       TextureCacheOpenGL& texture_cache, OGLBufferCache& buffer_cache,
 | 
			
		||||
                       QueryCache& query_cache);
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
    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},
 | 
			
		||||
      shader_cache{*this, system, emu_window, device}, query_cache{system, *this}, system{system},
 | 
			
		||||
      screen_info{info}, program_manager{program_manager}, state_tracker{state_tracker},
 | 
			
		||||
      buffer_cache{*this, system, device, STREAM_BUFFER_SIZE}, fence_manager{system, *this,
 | 
			
		||||
                                                                             texture_cache,
 | 
			
		||||
                                                                             buffer_cache} {
 | 
			
		||||
      buffer_cache{*this, system, device, STREAM_BUFFER_SIZE}, fence_manager{
 | 
			
		||||
                                                                   system, *this, texture_cache,
 | 
			
		||||
                                                                   buffer_cache, query_cache} {
 | 
			
		||||
    CheckExtensions();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user