GPU: Implement a Fence Manager.

This commit is contained in:
Fernando Sahmkow 2020-02-17 20:19:26 -04:00
parent 487379c593
commit 1f345ebe3a
6 changed files with 208 additions and 23 deletions

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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) {

View file

@ -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;