From 1f345ebe3a5501b50f26f0c5c21cac5d55dd79c1 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Mon, 17 Feb 2020 20:19:26 -0400 Subject: GPU: Implement a Fence Manager. --- src/video_core/CMakeLists.txt | 3 + src/video_core/fence_manager.h | 97 ++++++++++++++++++++++ .../renderer_opengl/gl_fence_manager.cpp | 55 ++++++++++++ src/video_core/renderer_opengl/gl_fence_manager.h | 47 +++++++++++ src/video_core/renderer_opengl/gl_rasterizer.cpp | 27 +----- src/video_core/renderer_opengl/gl_rasterizer.h | 2 + 6 files changed, 208 insertions(+), 23 deletions(-) create mode 100644 src/video_core/fence_manager.h create mode 100644 src/video_core/renderer_opengl/gl_fence_manager.cpp create mode 100644 src/video_core/renderer_opengl/gl_fence_manager.h diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index 258d58eba..9a3f568f9 100644 --- a/src/video_core/CMakeLists.txt +++ b/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 diff --git a/src/video_core/fence_manager.h b/src/video_core/fence_manager.h new file mode 100644 index 000000000..19cec0f66 --- /dev/null +++ b/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 +#include +#include +#include + +#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 +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(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(current_fence->GetAddress(), current_fence->GetPayload()); + fences.pop(); + } + } + + std::queue fences; +}; + +} // namespace VideoCommon diff --git a/src/video_core/renderer_opengl/gl_fence_manager.cpp b/src/video_core/renderer_opengl/gl_fence_manager.cpp new file mode 100644 index 000000000..4517ef150 --- /dev/null +++ b/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(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 diff --git a/src/video_core/renderer_opengl/gl_fence_manager.h b/src/video_core/renderer_opengl/gl_fence_manager.h new file mode 100644 index 000000000..3cfa8b1d0 --- /dev/null +++ b/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 +#include + +#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; +using GenericFenceManager = VideoCommon::FenceManager; + +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 diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 93bb33e8c..35bed444f 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/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& 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(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& 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(address, payload); - fences.pop_front(); - } + fence_manager.WaitPendingFences(); } void RasterizerOpenGL::FlushAndInvalidateRegion(VAddr addr, u64 size) { diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 486a154ad..6d173a922 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/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; -- cgit v1.2.3