FenceManager: Manage syncpoints and rename fences to semaphores.
This commit is contained in:
parent
96bb961a64
commit
b7bc3c2549
11 changed files with 123 additions and 25 deletions
|
@ -229,6 +229,13 @@ public:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool HasUncommitedFlushes() {
|
||||||
|
if (uncommited_flushes) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void PopAsyncFlushes() {
|
void PopAsyncFlushes() {
|
||||||
if (commited_flushes.empty()) {
|
if (commited_flushes.empty()) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -405,7 +405,7 @@ void Maxwell3D::ProcessQueryGet() {
|
||||||
switch (regs.query.query_get.operation) {
|
switch (regs.query.query_get.operation) {
|
||||||
case Regs::QueryOperation::Release:
|
case Regs::QueryOperation::Release:
|
||||||
if (regs.query.query_get.fence == 1) {
|
if (regs.query.query_get.fence == 1) {
|
||||||
rasterizer.SignalFence(regs.query.QueryAddress(), regs.query.query_sequence);
|
rasterizer.SignalSemaphore(regs.query.QueryAddress(), regs.query.query_sequence);
|
||||||
} else {
|
} else {
|
||||||
StampQueryResult(regs.query.query_sequence, regs.query.query_get.short_query == 0);
|
StampQueryResult(regs.query.query_sequence, regs.query.query_get.short_query == 0);
|
||||||
}
|
}
|
||||||
|
@ -487,7 +487,7 @@ void Maxwell3D::ProcessSyncPoint() {
|
||||||
const u32 increment = regs.sync_info.increment.Value();
|
const u32 increment = regs.sync_info.increment.Value();
|
||||||
[[maybe_unused]] const u32 cache_flush = regs.sync_info.unknown.Value();
|
[[maybe_unused]] const u32 cache_flush = regs.sync_info.unknown.Value();
|
||||||
if (increment) {
|
if (increment) {
|
||||||
system.GPU().IncrementSyncPoint(sync_point);
|
rasterizer.SignalSyncPoint(sync_point);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,11 @@ namespace VideoCommon {
|
||||||
|
|
||||||
class FenceBase {
|
class FenceBase {
|
||||||
public:
|
public:
|
||||||
FenceBase(GPUVAddr address, u32 payload) : address{address}, payload{payload} {}
|
FenceBase(u32 payload, bool is_stubbed)
|
||||||
|
: address{}, payload{payload}, is_semaphore{false}, is_stubbed{is_stubbed} {}
|
||||||
|
|
||||||
|
FenceBase(GPUVAddr address, u32 payload, bool is_stubbed)
|
||||||
|
: address{address}, payload{payload}, is_semaphore{true}, is_stubbed{is_stubbed} {}
|
||||||
|
|
||||||
constexpr GPUVAddr GetAddress() const {
|
constexpr GPUVAddr GetAddress() const {
|
||||||
return address;
|
return address;
|
||||||
|
@ -32,22 +36,49 @@ public:
|
||||||
return payload;
|
return payload;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constexpr bool IsSemaphore() const {
|
||||||
|
return is_semaphore;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
GPUVAddr address;
|
GPUVAddr address;
|
||||||
u32 payload;
|
u32 payload;
|
||||||
|
bool is_semaphore;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool is_stubbed;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename TFence, typename TTextureCache, typename TTBufferCache>
|
template <typename TFence, typename TTextureCache, typename TTBufferCache>
|
||||||
class FenceManager {
|
class FenceManager {
|
||||||
public:
|
public:
|
||||||
void SignalFence(GPUVAddr addr, u32 value) {
|
void SignalSemaphore(GPUVAddr addr, u32 value) {
|
||||||
TryReleasePendingFences();
|
TryReleasePendingFences();
|
||||||
|
bool should_flush = texture_cache.HasUncommitedFlushes();
|
||||||
|
should_flush |= buffer_cache.HasUncommitedFlushes();
|
||||||
texture_cache.CommitAsyncFlushes();
|
texture_cache.CommitAsyncFlushes();
|
||||||
buffer_cache.CommitAsyncFlushes();
|
buffer_cache.CommitAsyncFlushes();
|
||||||
TFence new_fence = CreateFence(addr, value);
|
TFence new_fence = CreateFence(addr, value, !should_flush);
|
||||||
fences.push(new_fence);
|
fences.push(new_fence);
|
||||||
QueueFence(new_fence);
|
QueueFence(new_fence);
|
||||||
rasterizer.FlushCommands();
|
if (should_flush) {
|
||||||
|
rasterizer.FlushCommands();
|
||||||
|
}
|
||||||
|
rasterizer.SyncGuestHost();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SignalSyncPoint(u32 value) {
|
||||||
|
TryReleasePendingFences();
|
||||||
|
bool should_flush = texture_cache.HasUncommitedFlushes();
|
||||||
|
should_flush |= buffer_cache.HasUncommitedFlushes();
|
||||||
|
texture_cache.CommitAsyncFlushes();
|
||||||
|
buffer_cache.CommitAsyncFlushes();
|
||||||
|
TFence new_fence = CreateFence(value, !should_flush);
|
||||||
|
fences.push(new_fence);
|
||||||
|
QueueFence(new_fence);
|
||||||
|
if (should_flush) {
|
||||||
|
rasterizer.FlushCommands();
|
||||||
|
}
|
||||||
rasterizer.SyncGuestHost();
|
rasterizer.SyncGuestHost();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,8 +93,12 @@ public:
|
||||||
texture_cache.PopAsyncFlushes();
|
texture_cache.PopAsyncFlushes();
|
||||||
buffer_cache.PopAsyncFlushes();
|
buffer_cache.PopAsyncFlushes();
|
||||||
auto& gpu{system.GPU()};
|
auto& gpu{system.GPU()};
|
||||||
auto& memory_manager{gpu.MemoryManager()};
|
if (current_fence->IsSemaphore()) {
|
||||||
memory_manager.Write<u32>(current_fence->GetAddress(), current_fence->GetPayload());
|
auto& memory_manager{gpu.MemoryManager()};
|
||||||
|
memory_manager.Write<u32>(current_fence->GetAddress(), current_fence->GetPayload());
|
||||||
|
} else {
|
||||||
|
gpu.IncrementSyncPoint(current_fence->GetPayload());
|
||||||
|
}
|
||||||
fences.pop();
|
fences.pop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -74,7 +109,8 @@ protected:
|
||||||
: system{system}, rasterizer{rasterizer}, texture_cache{texture_cache}, buffer_cache{
|
: system{system}, rasterizer{rasterizer}, texture_cache{texture_cache}, buffer_cache{
|
||||||
buffer_cache} {}
|
buffer_cache} {}
|
||||||
|
|
||||||
virtual TFence CreateFence(GPUVAddr addr, u32 value) = 0;
|
virtual TFence CreateFence(u32 value, bool is_stubbed) = 0;
|
||||||
|
virtual TFence CreateFence(GPUVAddr addr, u32 value, bool is_stubbed) = 0;
|
||||||
virtual void QueueFence(TFence& fence) = 0;
|
virtual void QueueFence(TFence& fence) = 0;
|
||||||
virtual bool IsFenceSignaled(TFence& fence) = 0;
|
virtual bool IsFenceSignaled(TFence& fence) = 0;
|
||||||
virtual void WaitFence(TFence& fence) = 0;
|
virtual void WaitFence(TFence& fence) = 0;
|
||||||
|
@ -96,8 +132,12 @@ private:
|
||||||
texture_cache.PopAsyncFlushes();
|
texture_cache.PopAsyncFlushes();
|
||||||
buffer_cache.PopAsyncFlushes();
|
buffer_cache.PopAsyncFlushes();
|
||||||
auto& gpu{system.GPU()};
|
auto& gpu{system.GPU()};
|
||||||
auto& memory_manager{gpu.MemoryManager()};
|
if (current_fence->IsSemaphore()) {
|
||||||
memory_manager.Write<u32>(current_fence->GetAddress(), current_fence->GetPayload());
|
auto& memory_manager{gpu.MemoryManager()};
|
||||||
|
memory_manager.Write<u32>(current_fence->GetAddress(), current_fence->GetPayload());
|
||||||
|
} else {
|
||||||
|
gpu.IncrementSyncPoint(current_fence->GetPayload());
|
||||||
|
}
|
||||||
fences.pop();
|
fences.pop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,8 +49,11 @@ public:
|
||||||
/// Records a GPU query and caches it
|
/// Records a GPU query and caches it
|
||||||
virtual void Query(GPUVAddr gpu_addr, QueryType type, std::optional<u64> timestamp) = 0;
|
virtual void Query(GPUVAddr gpu_addr, QueryType type, std::optional<u64> timestamp) = 0;
|
||||||
|
|
||||||
/// Signal a GPU based fence
|
/// Signal a GPU based semaphore as a fence
|
||||||
virtual void SignalFence(GPUVAddr addr, u32 value) = 0;
|
virtual void SignalSemaphore(GPUVAddr addr, u32 value) = 0;
|
||||||
|
|
||||||
|
/// Signal a GPU based syncpoint as a fence
|
||||||
|
virtual void SignalSyncPoint(u32 value) = 0;
|
||||||
|
|
||||||
/// Release all pending fences.
|
/// Release all pending fences.
|
||||||
virtual void ReleaseFences() = 0;
|
virtual void ReleaseFences() = 0;
|
||||||
|
|
|
@ -8,17 +8,26 @@
|
||||||
|
|
||||||
namespace OpenGL {
|
namespace OpenGL {
|
||||||
|
|
||||||
GLInnerFence::GLInnerFence(GPUVAddr address, u32 payload)
|
GLInnerFence::GLInnerFence(u32 payload, bool is_stubbed)
|
||||||
: VideoCommon::FenceBase(address, payload), sync_object{} {}
|
: VideoCommon::FenceBase(payload, is_stubbed), sync_object{} {}
|
||||||
|
|
||||||
|
GLInnerFence::GLInnerFence(GPUVAddr address, u32 payload, bool is_stubbed)
|
||||||
|
: VideoCommon::FenceBase(address, payload, is_stubbed), sync_object{} {}
|
||||||
|
|
||||||
GLInnerFence::~GLInnerFence() = default;
|
GLInnerFence::~GLInnerFence() = default;
|
||||||
|
|
||||||
void GLInnerFence::Queue() {
|
void GLInnerFence::Queue() {
|
||||||
|
if (is_stubbed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
ASSERT(sync_object.handle == 0);
|
ASSERT(sync_object.handle == 0);
|
||||||
sync_object.Create();
|
sync_object.Create();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GLInnerFence::IsSignaled() const {
|
bool GLInnerFence::IsSignaled() const {
|
||||||
|
if (is_stubbed) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
ASSERT(sync_object.handle != 0);
|
ASSERT(sync_object.handle != 0);
|
||||||
GLsizei length;
|
GLsizei length;
|
||||||
GLint sync_status;
|
GLint sync_status;
|
||||||
|
@ -27,6 +36,9 @@ bool GLInnerFence::IsSignaled() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLInnerFence::Wait() {
|
void GLInnerFence::Wait() {
|
||||||
|
if (is_stubbed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
ASSERT(sync_object.handle != 0);
|
ASSERT(sync_object.handle != 0);
|
||||||
while (glClientWaitSync(sync_object.handle, 0, 1000) == GL_TIMEOUT_EXPIRED)
|
while (glClientWaitSync(sync_object.handle, 0, 1000) == GL_TIMEOUT_EXPIRED)
|
||||||
;
|
;
|
||||||
|
@ -36,8 +48,12 @@ FenceManagerOpenGL::FenceManagerOpenGL(Core::System& system, VideoCore::Rasteriz
|
||||||
TextureCacheOpenGL& texture_cache, OGLBufferCache& buffer_cache)
|
TextureCacheOpenGL& texture_cache, OGLBufferCache& buffer_cache)
|
||||||
: GenericFenceManager(system, rasterizer, texture_cache, buffer_cache) {}
|
: GenericFenceManager(system, rasterizer, texture_cache, buffer_cache) {}
|
||||||
|
|
||||||
Fence FenceManagerOpenGL::CreateFence(GPUVAddr addr, u32 value) {
|
Fence FenceManagerOpenGL::CreateFence(u32 value, bool is_stubbed) {
|
||||||
return std::make_shared<GLInnerFence>(addr, value);
|
return std::make_shared<GLInnerFence>(value, is_stubbed);
|
||||||
|
}
|
||||||
|
|
||||||
|
Fence FenceManagerOpenGL::CreateFence(GPUVAddr addr, u32 value, bool is_stubbed) {
|
||||||
|
return std::make_shared<GLInnerFence>(addr, value, is_stubbed);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FenceManagerOpenGL::QueueFence(Fence& fence) {
|
void FenceManagerOpenGL::QueueFence(Fence& fence) {
|
||||||
|
|
|
@ -17,7 +17,8 @@ namespace OpenGL {
|
||||||
|
|
||||||
class GLInnerFence : public VideoCommon::FenceBase {
|
class GLInnerFence : public VideoCommon::FenceBase {
|
||||||
public:
|
public:
|
||||||
GLInnerFence(GPUVAddr address, u32 payload);
|
GLInnerFence(u32 payload, bool is_stubbed);
|
||||||
|
GLInnerFence(GPUVAddr address, u32 payload, bool is_stubbed);
|
||||||
~GLInnerFence();
|
~GLInnerFence();
|
||||||
|
|
||||||
void Queue();
|
void Queue();
|
||||||
|
@ -39,7 +40,8 @@ public:
|
||||||
TextureCacheOpenGL& texture_cache, OGLBufferCache& buffer_cache);
|
TextureCacheOpenGL& texture_cache, OGLBufferCache& buffer_cache);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Fence CreateFence(GPUVAddr addr, u32 value) override;
|
Fence CreateFence(u32 value, bool is_stubbed) override;
|
||||||
|
Fence CreateFence(GPUVAddr addr, u32 value, bool is_stubbed) override;
|
||||||
void QueueFence(Fence& fence) override;
|
void QueueFence(Fence& fence) override;
|
||||||
bool IsFenceSignaled(Fence& fence) override;
|
bool IsFenceSignaled(Fence& fence) override;
|
||||||
void WaitFence(Fence& fence) override;
|
void WaitFence(Fence& fence) override;
|
||||||
|
|
|
@ -683,14 +683,23 @@ void RasterizerOpenGL::SyncGuestHost() {
|
||||||
buffer_cache.SyncGuestHost();
|
buffer_cache.SyncGuestHost();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerOpenGL::SignalFence(GPUVAddr addr, u32 value) {
|
void RasterizerOpenGL::SignalSemaphore(GPUVAddr addr, u32 value) {
|
||||||
auto& gpu{system.GPU()};
|
auto& gpu{system.GPU()};
|
||||||
if (!gpu.IsAsync()) {
|
if (!gpu.IsAsync()) {
|
||||||
auto& memory_manager{gpu.MemoryManager()};
|
auto& memory_manager{gpu.MemoryManager()};
|
||||||
memory_manager.Write<u32>(addr, value);
|
memory_manager.Write<u32>(addr, value);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
fence_manager.SignalFence(addr, value);
|
fence_manager.SignalSemaphore(addr, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RasterizerOpenGL::SignalSyncPoint(u32 value) {
|
||||||
|
auto& gpu{system.GPU()};
|
||||||
|
if (!gpu.IsAsync()) {
|
||||||
|
gpu.IncrementSyncPoint(value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fence_manager.SignalSyncPoint(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerOpenGL::ReleaseFences() {
|
void RasterizerOpenGL::ReleaseFences() {
|
||||||
|
|
|
@ -71,7 +71,8 @@ public:
|
||||||
void InvalidateRegion(VAddr addr, u64 size) override;
|
void InvalidateRegion(VAddr addr, u64 size) override;
|
||||||
void OnCPUWrite(VAddr addr, u64 size) override;
|
void OnCPUWrite(VAddr addr, u64 size) override;
|
||||||
void SyncGuestHost() override;
|
void SyncGuestHost() override;
|
||||||
void SignalFence(GPUVAddr addr, u32 value) override;
|
void SignalSemaphore(GPUVAddr addr, u32 value) override;
|
||||||
|
void SignalSyncPoint(u32 value) override;
|
||||||
void ReleaseFences() override;
|
void ReleaseFences() override;
|
||||||
void FlushAndInvalidateRegion(VAddr addr, u64 size) override;
|
void FlushAndInvalidateRegion(VAddr addr, u64 size) override;
|
||||||
void FlushCommands() override;
|
void FlushCommands() override;
|
||||||
|
|
|
@ -543,7 +543,7 @@ void RasterizerVulkan::SyncGuestHost() {
|
||||||
buffer_cache.SyncGuestHost();
|
buffer_cache.SyncGuestHost();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerVulkan::SignalFence(GPUVAddr addr, u32 value) {
|
void RasterizerVulkan::SignalSemaphore(GPUVAddr addr, u32 value) {
|
||||||
auto& gpu{system.GPU()};
|
auto& gpu{system.GPU()};
|
||||||
auto& memory_manager{gpu.MemoryManager()};
|
auto& memory_manager{gpu.MemoryManager()};
|
||||||
memory_manager.Write<u32>(addr, value);
|
memory_manager.Write<u32>(addr, value);
|
||||||
|
@ -553,7 +553,19 @@ void RasterizerVulkan::SignalFence(GPUVAddr addr, u32 value) {
|
||||||
memory_manager.Write<u32>(addr, value);
|
memory_manager.Write<u32>(addr, value);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
fence_manager.SignalFence(addr, value);
|
fence_manager.SignalSemaphore(addr, value);
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
void RasterizerVulkan::SignalSyncPoint(u32 value) {
|
||||||
|
auto& gpu{system.GPU()};
|
||||||
|
gpu.IncrementSyncPoint(value);
|
||||||
|
/*
|
||||||
|
if (!gpu.IsAsync()) {
|
||||||
|
gpu.IncrementSyncPoint(value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fence_manager.SignalSyncPoint(value);
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -122,7 +122,8 @@ public:
|
||||||
void InvalidateRegion(VAddr addr, u64 size) override;
|
void InvalidateRegion(VAddr addr, u64 size) override;
|
||||||
void OnCPUWrite(VAddr addr, u64 size) override;
|
void OnCPUWrite(VAddr addr, u64 size) override;
|
||||||
void SyncGuestHost() override;
|
void SyncGuestHost() override;
|
||||||
void SignalFence(GPUVAddr addr, u32 value) override;
|
void SignalSemaphore(GPUVAddr addr, u32 value) override;
|
||||||
|
void SignalSyncPoint(u32 value) override;
|
||||||
void ReleaseFences() override;
|
void ReleaseFences() override;
|
||||||
void FlushAndInvalidateRegion(VAddr addr, u64 size) override;
|
void FlushAndInvalidateRegion(VAddr addr, u64 size) override;
|
||||||
void FlushCommands() override;
|
void FlushCommands() override;
|
||||||
|
|
|
@ -337,6 +337,13 @@ public:
|
||||||
uncommited_flushes.reset();
|
uncommited_flushes.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool HasUncommitedFlushes() {
|
||||||
|
if (uncommited_flushes) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool ShouldWaitAsyncFlushes() {
|
bool ShouldWaitAsyncFlushes() {
|
||||||
if (commited_flushes.empty()) {
|
if (commited_flushes.empty()) {
|
||||||
return false;
|
return false;
|
||||||
|
|
Loading…
Reference in a new issue