GPU: Implement a Fence Manager.
This commit is contained in:
parent
487379c593
commit
1f345ebe3a
|
@ -23,6 +23,7 @@ add_library(video_core STATIC
|
||||||
engines/shader_bytecode.h
|
engines/shader_bytecode.h
|
||||||
engines/shader_header.h
|
engines/shader_header.h
|
||||||
engines/shader_type.h
|
engines/shader_type.h
|
||||||
|
fence_manager.h
|
||||||
gpu.cpp
|
gpu.cpp
|
||||||
gpu.h
|
gpu.h
|
||||||
gpu_asynch.cpp
|
gpu_asynch.cpp
|
||||||
|
@ -51,6 +52,8 @@ add_library(video_core STATIC
|
||||||
renderer_opengl/gl_buffer_cache.h
|
renderer_opengl/gl_buffer_cache.h
|
||||||
renderer_opengl/gl_device.cpp
|
renderer_opengl/gl_device.cpp
|
||||||
renderer_opengl/gl_device.h
|
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.cpp
|
||||||
renderer_opengl/gl_framebuffer_cache.h
|
renderer_opengl/gl_framebuffer_cache.h
|
||||||
renderer_opengl/gl_rasterizer.cpp
|
renderer_opengl/gl_rasterizer.cpp
|
||||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -101,7 +101,8 @@ 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} {
|
buffer_cache{*this, system, device, STREAM_BUFFER_SIZE}, fence_manager{system, *this,
|
||||||
|
texture_cache} {
|
||||||
CheckExtensions();
|
CheckExtensions();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -677,31 +678,11 @@ void RasterizerOpenGL::SyncGuestHost() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerOpenGL::SignalFence(GPUVAddr addr, u32 value) {
|
void RasterizerOpenGL::SignalFence(GPUVAddr addr, u32 value) {
|
||||||
if (!fences.empty()) {
|
fence_manager.SignalFence(addr, value);
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerOpenGL::ReleaseFences() {
|
void RasterizerOpenGL::ReleaseFences() {
|
||||||
while (!fences.empty()) {
|
fence_manager.WaitPendingFences();
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerOpenGL::FlushAndInvalidateRegion(VAddr addr, u64 size) {
|
void RasterizerOpenGL::FlushAndInvalidateRegion(VAddr addr, u64 size) {
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include "video_core/rasterizer_interface.h"
|
#include "video_core/rasterizer_interface.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_device.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_framebuffer_cache.h"
|
||||||
#include "video_core/renderer_opengl/gl_query_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"
|
||||||
|
@ -226,6 +227,7 @@ private:
|
||||||
SamplerCacheOpenGL sampler_cache;
|
SamplerCacheOpenGL sampler_cache;
|
||||||
FramebufferCacheOpenGL framebuffer_cache;
|
FramebufferCacheOpenGL framebuffer_cache;
|
||||||
QueryCache query_cache;
|
QueryCache query_cache;
|
||||||
|
FenceManagerOpenGL fence_manager;
|
||||||
|
|
||||||
Core::System& system;
|
Core::System& system;
|
||||||
ScreenInfo& screen_info;
|
ScreenInfo& screen_info;
|
||||||
|
|
Reference in New Issue