suyu/src/video_core/fence_manager.h

168 lines
5.2 KiB
C++
Raw Normal View History

2020-02-17 19:19:26 -05:00
// Copyright 2020 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <algorithm>
#include <queue>
2020-02-17 19:19:26 -05:00
#include "common/common_types.h"
#include "core/core.h"
#include "video_core/gpu.h"
#include "video_core/memory_manager.h"
#include "video_core/rasterizer_interface.h"
namespace VideoCommon {
class FenceBase {
public:
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} {}
2020-02-17 19:19:26 -05:00
2020-04-16 12:29:53 -04:00
GPUVAddr GetAddress() const {
2020-02-17 19:19:26 -05:00
return address;
}
2020-04-16 12:29:53 -04:00
u32 GetPayload() const {
2020-02-17 19:19:26 -05:00
return payload;
}
2020-04-16 12:29:53 -04:00
bool IsSemaphore() const {
return is_semaphore;
}
2020-02-17 19:19:26 -05:00
private:
GPUVAddr address;
u32 payload;
bool is_semaphore;
protected:
bool is_stubbed;
2020-02-17 19:19:26 -05:00
};
2020-04-15 16:36:14 -04:00
template <typename TFence, typename TTextureCache, typename TTBufferCache, typename TQueryCache>
2020-02-17 19:19:26 -05:00
class FenceManager {
public:
void SignalSemaphore(GPUVAddr addr, u32 value) {
2020-02-17 19:19:26 -05:00
TryReleasePendingFences();
2020-04-22 11:14:40 -04:00
const bool should_flush = ShouldFlush();
2020-04-16 12:29:53 -04:00
CommitAsyncFlushes();
TFence new_fence = CreateFence(addr, value, !should_flush);
2020-02-19 09:49:07 -05:00
fences.push(new_fence);
QueueFence(new_fence);
if (should_flush) {
rasterizer.FlushCommands();
}
rasterizer.SyncGuestHost();
}
void SignalSyncPoint(u32 value) {
TryReleasePendingFences();
2020-04-22 11:14:40 -04:00
const bool should_flush = ShouldFlush();
2020-04-16 12:29:53 -04:00
CommitAsyncFlushes();
TFence new_fence = CreateFence(value, !should_flush);
fences.push(new_fence);
QueueFence(new_fence);
if (should_flush) {
rasterizer.FlushCommands();
}
2020-02-17 19:19:26 -05:00
rasterizer.SyncGuestHost();
}
void WaitPendingFences() {
2020-04-22 11:14:40 -04:00
auto& gpu{system.GPU()};
auto& memory_manager{gpu.MemoryManager()};
2020-02-17 19:19:26 -05:00
while (!fences.empty()) {
TFence& current_fence = fences.front();
2020-04-16 12:29:53 -04:00
if (ShouldWait()) {
2020-02-17 21:15:43 -05:00
WaitFence(current_fence);
}
2020-04-16 12:29:53 -04:00
PopAsyncFlushes();
if (current_fence->IsSemaphore()) {
memory_manager.template Write<u32>(current_fence->GetAddress(),
current_fence->GetPayload());
} else {
gpu.IncrementSyncPoint(current_fence->GetPayload());
}
2020-02-17 19:19:26 -05:00
fences.pop();
}
}
protected:
FenceManager(Core::System& system, VideoCore::RasterizerInterface& rasterizer,
2020-04-15 16:36:14 -04:00
TTextureCache& texture_cache, TTBufferCache& buffer_cache,
TQueryCache& query_cache)
: system{system}, rasterizer{rasterizer}, texture_cache{texture_cache},
buffer_cache{buffer_cache}, query_cache{query_cache} {}
2020-02-17 19:19:26 -05:00
2020-04-16 12:29:53 -04:00
virtual ~FenceManager() {}
/// Creates a Sync Point Fence Interface, does not create a backend fence if 'is_stubbed' is
/// true
virtual TFence CreateFence(u32 value, bool is_stubbed) = 0;
2020-04-16 12:29:53 -04:00
/// Creates a Semaphore Fence Interface, does not create a backend fence if 'is_stubbed' is true
virtual TFence CreateFence(GPUVAddr addr, u32 value, bool is_stubbed) = 0;
2020-04-16 12:29:53 -04:00
/// Queues a fence into the backend if the fence isn't stubbed.
2020-02-17 19:19:26 -05:00
virtual void QueueFence(TFence& fence) = 0;
2020-04-16 12:29:53 -04:00
/// Notifies that the backend fence has been signaled/reached in host GPU.
virtual bool IsFenceSignaled(TFence& fence) const = 0;
/// Waits until a fence has been signalled by the host GPU.
2020-02-17 19:19:26 -05:00
virtual void WaitFence(TFence& fence) = 0;
Core::System& system;
VideoCore::RasterizerInterface& rasterizer;
TTextureCache& texture_cache;
TTBufferCache& buffer_cache;
2020-04-15 16:36:14 -04:00
TQueryCache& query_cache;
2020-02-17 19:19:26 -05:00
private:
void TryReleasePendingFences() {
2020-04-22 11:14:40 -04:00
auto& gpu{system.GPU()};
auto& memory_manager{gpu.MemoryManager()};
2020-02-17 19:19:26 -05:00
while (!fences.empty()) {
TFence& current_fence = fences.front();
2020-04-16 12:29:53 -04:00
if (ShouldWait() && !IsFenceSignaled(current_fence)) {
2020-02-17 19:19:26 -05:00
return;
}
2020-04-16 12:29:53 -04:00
PopAsyncFlushes();
if (current_fence->IsSemaphore()) {
memory_manager.template Write<u32>(current_fence->GetAddress(),
current_fence->GetPayload());
} else {
gpu.IncrementSyncPoint(current_fence->GetPayload());
}
2020-02-17 19:19:26 -05:00
fences.pop();
}
}
2020-04-16 12:29:53 -04:00
bool ShouldWait() const {
return texture_cache.ShouldWaitAsyncFlushes() || buffer_cache.ShouldWaitAsyncFlushes() ||
query_cache.ShouldWaitAsyncFlushes();
}
bool ShouldFlush() const {
return texture_cache.HasUncommittedFlushes() || buffer_cache.HasUncommittedFlushes() ||
query_cache.HasUncommittedFlushes();
}
void PopAsyncFlushes() {
texture_cache.PopAsyncFlushes();
buffer_cache.PopAsyncFlushes();
query_cache.PopAsyncFlushes();
}
void CommitAsyncFlushes() {
texture_cache.CommitAsyncFlushes();
buffer_cache.CommitAsyncFlushes();
query_cache.CommitAsyncFlushes();
}
2020-02-17 19:19:26 -05:00
std::queue<TFence> fences;
};
} // namespace VideoCommon