2020-02-18 03:19:26 +03: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 <array>
|
|
|
|
#include <memory>
|
2020-02-19 00:20:39 +03:00
|
|
|
#include <queue>
|
2020-02-18 03:19:26 +03:00
|
|
|
|
|
|
|
#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:
|
2020-02-19 20:40:37 +03:00
|
|
|
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-18 03:19:26 +03:00
|
|
|
|
|
|
|
constexpr GPUVAddr GetAddress() const {
|
|
|
|
return address;
|
|
|
|
}
|
|
|
|
|
|
|
|
constexpr u32 GetPayload() const {
|
|
|
|
return payload;
|
|
|
|
}
|
|
|
|
|
2020-02-19 20:40:37 +03:00
|
|
|
constexpr bool IsSemaphore() const {
|
|
|
|
return is_semaphore;
|
|
|
|
}
|
|
|
|
|
2020-02-18 03:19:26 +03:00
|
|
|
private:
|
|
|
|
GPUVAddr address;
|
|
|
|
u32 payload;
|
2020-02-19 20:40:37 +03:00
|
|
|
bool is_semaphore;
|
|
|
|
|
|
|
|
protected:
|
|
|
|
bool is_stubbed;
|
2020-02-18 03:19:26 +03:00
|
|
|
};
|
|
|
|
|
2020-04-15 23:36:14 +03:00
|
|
|
template <typename TFence, typename TTextureCache, typename TTBufferCache, typename TQueryCache>
|
2020-02-18 03:19:26 +03:00
|
|
|
class FenceManager {
|
|
|
|
public:
|
2020-02-19 20:40:37 +03:00
|
|
|
void SignalSemaphore(GPUVAddr addr, u32 value) {
|
2020-02-18 03:19:26 +03:00
|
|
|
TryReleasePendingFences();
|
2020-02-19 20:40:37 +03:00
|
|
|
bool should_flush = texture_cache.HasUncommitedFlushes();
|
|
|
|
should_flush |= buffer_cache.HasUncommitedFlushes();
|
2020-04-15 23:36:14 +03:00
|
|
|
should_flush |= query_cache.HasUncommitedFlushes();
|
2020-02-18 03:19:26 +03:00
|
|
|
texture_cache.CommitAsyncFlushes();
|
2020-02-19 00:20:39 +03:00
|
|
|
buffer_cache.CommitAsyncFlushes();
|
2020-04-15 23:36:14 +03:00
|
|
|
query_cache.CommitAsyncFlushes();
|
2020-02-19 20:40:37 +03:00
|
|
|
TFence new_fence = CreateFence(addr, value, !should_flush);
|
2020-02-19 17:49:07 +03:00
|
|
|
fences.push(new_fence);
|
|
|
|
QueueFence(new_fence);
|
2020-02-19 20:40:37 +03:00
|
|
|
if (should_flush) {
|
|
|
|
rasterizer.FlushCommands();
|
|
|
|
}
|
|
|
|
rasterizer.SyncGuestHost();
|
|
|
|
}
|
|
|
|
|
|
|
|
void SignalSyncPoint(u32 value) {
|
|
|
|
TryReleasePendingFences();
|
|
|
|
bool should_flush = texture_cache.HasUncommitedFlushes();
|
|
|
|
should_flush |= buffer_cache.HasUncommitedFlushes();
|
2020-04-15 23:36:14 +03:00
|
|
|
should_flush |= query_cache.HasUncommitedFlushes();
|
2020-02-19 20:40:37 +03:00
|
|
|
texture_cache.CommitAsyncFlushes();
|
|
|
|
buffer_cache.CommitAsyncFlushes();
|
2020-04-15 23:36:14 +03:00
|
|
|
query_cache.CommitAsyncFlushes();
|
2020-02-19 20:40:37 +03:00
|
|
|
TFence new_fence = CreateFence(value, !should_flush);
|
|
|
|
fences.push(new_fence);
|
|
|
|
QueueFence(new_fence);
|
|
|
|
if (should_flush) {
|
|
|
|
rasterizer.FlushCommands();
|
|
|
|
}
|
2020-02-18 03:19:26 +03:00
|
|
|
rasterizer.SyncGuestHost();
|
|
|
|
}
|
|
|
|
|
|
|
|
void WaitPendingFences() {
|
|
|
|
while (!fences.empty()) {
|
|
|
|
TFence& current_fence = fences.front();
|
2020-02-18 05:15:43 +03:00
|
|
|
bool should_wait = texture_cache.ShouldWaitAsyncFlushes();
|
2020-02-19 00:20:39 +03:00
|
|
|
should_wait |= buffer_cache.ShouldWaitAsyncFlushes();
|
2020-04-15 23:36:14 +03:00
|
|
|
should_wait |= query_cache.ShouldWaitAsyncFlushes();
|
2020-02-18 05:15:43 +03:00
|
|
|
if (should_wait) {
|
|
|
|
WaitFence(current_fence);
|
|
|
|
}
|
2020-02-18 03:19:26 +03:00
|
|
|
texture_cache.PopAsyncFlushes();
|
2020-02-19 00:20:39 +03:00
|
|
|
buffer_cache.PopAsyncFlushes();
|
2020-04-15 23:36:14 +03:00
|
|
|
query_cache.PopAsyncFlushes();
|
2020-02-18 03:19:26 +03:00
|
|
|
auto& gpu{system.GPU()};
|
2020-02-19 20:40:37 +03:00
|
|
|
if (current_fence->IsSemaphore()) {
|
|
|
|
auto& memory_manager{gpu.MemoryManager()};
|
|
|
|
memory_manager.Write<u32>(current_fence->GetAddress(), current_fence->GetPayload());
|
|
|
|
} else {
|
|
|
|
gpu.IncrementSyncPoint(current_fence->GetPayload());
|
|
|
|
}
|
2020-02-18 03:19:26 +03:00
|
|
|
fences.pop();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
|
|
|
FenceManager(Core::System& system, VideoCore::RasterizerInterface& rasterizer,
|
2020-04-15 23:36:14 +03: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-18 03:19:26 +03:00
|
|
|
|
2020-02-19 20:40:37 +03:00
|
|
|
virtual TFence CreateFence(u32 value, bool is_stubbed) = 0;
|
|
|
|
virtual TFence CreateFence(GPUVAddr addr, u32 value, bool is_stubbed) = 0;
|
2020-02-18 03:19:26 +03:00
|
|
|
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;
|
2020-02-19 00:20:39 +03:00
|
|
|
TTBufferCache& buffer_cache;
|
2020-04-15 23:36:14 +03:00
|
|
|
TQueryCache& query_cache;
|
2020-02-18 03:19:26 +03:00
|
|
|
|
|
|
|
private:
|
|
|
|
void TryReleasePendingFences() {
|
|
|
|
while (!fences.empty()) {
|
|
|
|
TFence& current_fence = fences.front();
|
2020-02-18 05:15:43 +03:00
|
|
|
bool should_wait = texture_cache.ShouldWaitAsyncFlushes();
|
2020-02-19 00:20:39 +03:00
|
|
|
should_wait |= buffer_cache.ShouldWaitAsyncFlushes();
|
2020-04-15 23:36:14 +03:00
|
|
|
should_wait |= query_cache.ShouldWaitAsyncFlushes();
|
2020-02-18 05:15:43 +03:00
|
|
|
if (should_wait && !IsFenceSignaled(current_fence)) {
|
2020-02-18 03:19:26 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
texture_cache.PopAsyncFlushes();
|
2020-02-19 00:20:39 +03:00
|
|
|
buffer_cache.PopAsyncFlushes();
|
2020-04-15 23:36:14 +03:00
|
|
|
query_cache.PopAsyncFlushes();
|
2020-02-18 03:19:26 +03:00
|
|
|
auto& gpu{system.GPU()};
|
2020-02-19 20:40:37 +03:00
|
|
|
if (current_fence->IsSemaphore()) {
|
|
|
|
auto& memory_manager{gpu.MemoryManager()};
|
|
|
|
memory_manager.Write<u32>(current_fence->GetAddress(), current_fence->GetPayload());
|
|
|
|
} else {
|
|
|
|
gpu.IncrementSyncPoint(current_fence->GetPayload());
|
|
|
|
}
|
2020-02-18 03:19:26 +03:00
|
|
|
fences.pop();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
std::queue<TFence> fences;
|
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace VideoCommon
|