Просмотр исходного кода

GPU: Implement a Fence Manager.

Fernando Sahmkow 6 лет назад
Родитель
Сommit
1f345ebe3a

+ 3 - 0
src/video_core/CMakeLists.txt

@@ -23,6 +23,7 @@ add_library(video_core STATIC
     engines/shader_bytecode.h
     engines/shader_header.h
     engines/shader_type.h
+    fence_manager.h
     gpu.cpp
     gpu.h
     gpu_asynch.cpp
@@ -51,6 +52,8 @@ add_library(video_core STATIC
     renderer_opengl/gl_buffer_cache.h
     renderer_opengl/gl_device.cpp
     renderer_opengl/gl_device.h
+    renderer_opengl/gl_fence_manager.cpp
+    renderer_opengl/gl_fence_manager.h
     renderer_opengl/gl_framebuffer_cache.cpp
     renderer_opengl/gl_framebuffer_cache.h
     renderer_opengl/gl_rasterizer.cpp

+ 97 - 0
src/video_core/fence_manager.h

@@ -0,0 +1,97 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <algorithm>
+#include <array>
+#include <queue>
+#include <memory>
+
+#include "common/assert.h"
+#include "common/common_types.h"
+#include "core/core.h"
+#include "core/memory.h"
+#include "core/settings.h"
+#include "video_core/gpu.h"
+#include "video_core/memory_manager.h"
+#include "video_core/rasterizer_interface.h"
+
+namespace VideoCommon {
+
+class FenceBase {
+public:
+    FenceBase(GPUVAddr address, u32 payload) : address{address}, payload{payload} {}
+
+    constexpr GPUVAddr GetAddress() const {
+        return address;
+    }
+
+    constexpr u32 GetPayload() const {
+        return payload;
+    }
+
+private:
+    GPUVAddr address;
+    u32 payload;
+};
+
+template <typename TFence, typename TTextureCache>
+class FenceManager {
+public:
+    void SignalFence(GPUVAddr addr, u32 value) {
+        TryReleasePendingFences();
+        TFence new_fence = CreateFence(addr, value);
+        QueueFence(new_fence);
+        fences.push(new_fence);
+        texture_cache.CommitAsyncFlushes();
+        rasterizer.FlushCommands();
+        rasterizer.SyncGuestHost();
+    }
+
+    void WaitPendingFences() {
+        while (!fences.empty()) {
+            TFence& current_fence = fences.front();
+            WaitFence(current_fence);
+            texture_cache.PopAsyncFlushes();
+            auto& gpu{system.GPU()};
+            auto& memory_manager{gpu.MemoryManager()};
+            memory_manager.Write<u32>(current_fence->GetAddress(), current_fence->GetPayload());
+            fences.pop();
+        }
+    }
+
+protected:
+    FenceManager(Core::System& system, VideoCore::RasterizerInterface& rasterizer,
+                 TTextureCache& texture_cache)
+        : system{system}, rasterizer{rasterizer}, texture_cache{texture_cache} {}
+
+    virtual TFence CreateFence(GPUVAddr addr, u32 value) = 0;
+    virtual void QueueFence(TFence& fence) = 0;
+    virtual bool IsFenceSignaled(TFence& fence) = 0;
+    virtual void WaitFence(TFence& fence) = 0;
+
+    Core::System& system;
+    VideoCore::RasterizerInterface& rasterizer;
+    TTextureCache& texture_cache;
+
+private:
+    void TryReleasePendingFences() {
+        while (!fences.empty()) {
+            TFence& current_fence = fences.front();
+            if (!IsFenceSignaled(current_fence)) {
+                return;
+            }
+            texture_cache.PopAsyncFlushes();
+            auto& gpu{system.GPU()};
+            auto& memory_manager{gpu.MemoryManager()};
+            memory_manager.Write<u32>(current_fence->GetAddress(), current_fence->GetPayload());
+            fences.pop();
+        }
+    }
+
+    std::queue<TFence> fences;
+};
+
+} // namespace VideoCommon

+ 55 - 0
src/video_core/renderer_opengl/gl_fence_manager.cpp

@@ -0,0 +1,55 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/assert.h"
+
+#include "video_core/renderer_opengl/gl_fence_manager.h"
+
+namespace OpenGL {
+
+GLInnerFence::GLInnerFence(GPUVAddr address, u32 payload)
+    : VideoCommon::FenceBase(address, payload), sync_object{} {}
+
+GLInnerFence::~GLInnerFence() = default;
+
+void GLInnerFence::Queue() {
+    ASSERT(sync_object.handle == 0);
+    sync_object.Create();
+}
+
+bool GLInnerFence::IsSignaled() const {
+    ASSERT(sync_object.handle != 0);
+    GLsizei length;
+    GLint sync_status;
+    glGetSynciv(sync_object.handle, GL_SYNC_STATUS, sizeof(GLint), &length, &sync_status);
+    return sync_status == GL_SIGNALED;
+}
+
+void GLInnerFence::Wait() {
+    ASSERT(sync_object.handle != 0);
+    while (glClientWaitSync(sync_object.handle, 0, 1000) == GL_TIMEOUT_EXPIRED)
+        ;
+}
+
+FenceManagerOpenGL::FenceManagerOpenGL(Core::System& system, VideoCore::RasterizerInterface& rasterizer,
+                               TextureCacheOpenGL& texture_cache)
+    : GenericFenceManager(system, rasterizer, texture_cache) {}
+
+Fence FenceManagerOpenGL::CreateFence(GPUVAddr addr, u32 value) {
+    return std::make_shared<GLInnerFence>(addr, value);
+}
+
+void FenceManagerOpenGL::QueueFence(Fence& fence) {
+    fence->Queue();
+}
+
+bool FenceManagerOpenGL::IsFenceSignaled(Fence& fence) {
+    return fence->IsSignaled();
+}
+
+void FenceManagerOpenGL::WaitFence(Fence& fence) {
+    fence->Wait();
+}
+
+} // namespace OpenGL

+ 47 - 0
src/video_core/renderer_opengl/gl_fence_manager.h

@@ -0,0 +1,47 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <memory>
+#include <glad/glad.h>
+
+#include "common/common_types.h"
+#include "video_core/fence_manager.h"
+#include "video_core/renderer_opengl/gl_resource_manager.h"
+#include "video_core/renderer_opengl/gl_texture_cache.h"
+
+namespace OpenGL {
+
+class GLInnerFence : public VideoCommon::FenceBase {
+public:
+    GLInnerFence(GPUVAddr address, u32 payload);
+    ~GLInnerFence();
+
+    void Queue();
+
+    bool IsSignaled() const;
+
+    void Wait();
+
+private:
+    OGLSync sync_object;
+};
+
+using Fence = std::shared_ptr<GLInnerFence>;
+using GenericFenceManager = VideoCommon::FenceManager<Fence, TextureCacheOpenGL>;
+
+class FenceManagerOpenGL final : public GenericFenceManager {
+public:
+    FenceManagerOpenGL(Core::System& system, VideoCore::RasterizerInterface& rasterizer,
+                   TextureCacheOpenGL& texture_cache);
+
+protected:
+    Fence CreateFence(GPUVAddr addr, u32 value) override;
+    void QueueFence(Fence& fence) override;
+    bool IsFenceSignaled(Fence& fence) override;
+    void WaitFence(Fence& fence) override;
+};
+
+} // namespace OpenGL

+ 4 - 23
src/video_core/renderer_opengl/gl_rasterizer.cpp

@@ -101,7 +101,8 @@ 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} {
+      buffer_cache{*this, system, device, STREAM_BUFFER_SIZE}, fence_manager{system, *this,
+                                                                             texture_cache} {
     CheckExtensions();
 }
 
@@ -677,31 +678,11 @@ void RasterizerOpenGL::SyncGuestHost() {
 }
 
 void RasterizerOpenGL::SignalFence(GPUVAddr addr, u32 value) {
-    if (!fences.empty()) {
-        const std::pair<GPUVAddr, u32>& current_fence = fences.front();
-        const auto [address, payload] = current_fence;
-        texture_cache.PopAsyncFlushes();
-        auto& gpu{system.GPU()};
-        auto& memory_manager{gpu.MemoryManager()};
-        memory_manager.Write<u32>(address, payload);
-        fences.pop_front();
-    }
-    fences.emplace_back(addr, value);
-    texture_cache.CommitAsyncFlushes();
-    FlushCommands();
-    SyncGuestHost();
+    fence_manager.SignalFence(addr, value);
 }
 
 void RasterizerOpenGL::ReleaseFences() {
-    while (!fences.empty()) {
-        const std::pair<GPUVAddr, u32>& current_fence = fences.front();
-        const auto [address, payload] = current_fence;
-        texture_cache.PopAsyncFlushes();
-        auto& gpu{system.GPU()};
-        auto& memory_manager{gpu.MemoryManager()};
-        memory_manager.Write<u32>(address, payload);
-        fences.pop_front();
-    }
+    fence_manager.WaitPendingFences();
 }
 
 void RasterizerOpenGL::FlushAndInvalidateRegion(VAddr addr, u64 size) {

+ 2 - 0
src/video_core/renderer_opengl/gl_rasterizer.h

@@ -23,6 +23,7 @@
 #include "video_core/rasterizer_interface.h"
 #include "video_core/renderer_opengl/gl_buffer_cache.h"
 #include "video_core/renderer_opengl/gl_device.h"
+#include "video_core/renderer_opengl/gl_fence_manager.h"
 #include "video_core/renderer_opengl/gl_framebuffer_cache.h"
 #include "video_core/renderer_opengl/gl_query_cache.h"
 #include "video_core/renderer_opengl/gl_resource_manager.h"
@@ -226,6 +227,7 @@ private:
     SamplerCacheOpenGL sampler_cache;
     FramebufferCacheOpenGL framebuffer_cache;
     QueryCache query_cache;
+    FenceManagerOpenGL fence_manager;
 
     Core::System& system;
     ScreenInfo& screen_info;