2
1
Fork 0
mirror of https://github.com/yuzu-emu/yuzu.git synced 2024-07-04 23:31:19 +01:00
yuzu/src/video_core/fence_manager.h

174 lines
5.5 KiB
C++
Raw Normal View History

// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
2020-02-18 00:19:26 +00:00
#pragma once
#include <algorithm>
#include <cstring>
2022-02-06 00:16:11 +00:00
#include <deque>
#include <functional>
#include <memory>
#include <queue>
2020-02-18 00:19:26 +00:00
#include "common/common_types.h"
#include "video_core/delayed_destruction_ring.h"
2020-02-18 00:19:26 +00:00
#include "video_core/gpu.h"
2022-01-30 09:31:13 +00:00
#include "video_core/host1x/host1x.h"
#include "video_core/host1x/syncpoint_manager.h"
2020-02-18 00:19:26 +00:00
#include "video_core/rasterizer_interface.h"
namespace VideoCommon {
class FenceBase {
public:
2022-02-06 00:16:11 +00:00
explicit FenceBase(bool is_stubbed_) : is_stubbed{is_stubbed_} {}
protected:
bool is_stubbed;
2020-02-18 00:19:26 +00:00
};
2020-04-15 21:36:14 +01:00
template <typename TFence, typename TTextureCache, typename TTBufferCache, typename TQueryCache>
2020-02-18 00:19:26 +00:00
class FenceManager {
public:
/// Notify the fence manager about a new frame
void TickFrame() {
delayed_destruction_ring.Tick();
}
2021-07-07 15:42:26 +01:00
// Unlike other fences, this one doesn't
void SignalOrdering() {
std::scoped_lock lock{buffer_cache.mutex};
buffer_cache.AccumulateFlushes();
}
2022-02-06 00:16:11 +00:00
void SyncOperation(std::function<void()>&& func) {
uncommitted_operations.emplace_back(std::move(func));
}
void SignalFence(std::function<void()>&& func) {
2020-02-18 00:19:26 +00:00
TryReleasePendingFences();
2020-04-22 16:14:40 +01:00
const bool should_flush = ShouldFlush();
2020-04-16 17:29:53 +01:00
CommitAsyncFlushes();
2022-02-06 00:16:11 +00:00
uncommitted_operations.emplace_back(std::move(func));
CommitOperations();
TFence new_fence = CreateFence(!should_flush);
2020-02-19 14:49:07 +00:00
fences.push(new_fence);
QueueFence(new_fence);
if (should_flush) {
rasterizer.FlushCommands();
}
}
void SignalSyncPoint(u32 value) {
2022-01-30 09:31:13 +00:00
syncpoint_manager.IncrementGuest(value);
2022-02-06 00:16:11 +00:00
std::function<void()> func([this, value] { syncpoint_manager.IncrementHost(value); });
SignalFence(std::move(func));
2020-02-18 00:19:26 +00:00
}
void WaitPendingFences() {
while (!fences.empty()) {
TFence& current_fence = fences.front();
2020-04-16 17:29:53 +01:00
if (ShouldWait()) {
2020-02-18 02:15:43 +00:00
WaitFence(current_fence);
}
2020-04-16 17:29:53 +01:00
PopAsyncFlushes();
2022-02-06 00:16:11 +00:00
auto operations = std::move(pending_operations.front());
pending_operations.pop_front();
for (auto& operation : operations) {
operation();
}
PopFence();
2020-02-18 00:19:26 +00:00
}
}
protected:
explicit FenceManager(VideoCore::RasterizerInterface& rasterizer_, Tegra::GPU& gpu_,
TTextureCache& texture_cache_, TTBufferCache& buffer_cache_,
TQueryCache& query_cache_)
2022-01-30 09:31:13 +00:00
: rasterizer{rasterizer_}, gpu{gpu_}, syncpoint_manager{gpu.Host1x().GetSyncpointManager()},
texture_cache{texture_cache_}, buffer_cache{buffer_cache_}, query_cache{query_cache_} {}
2020-02-18 00:19:26 +00:00
virtual ~FenceManager() = default;
2020-04-16 17:29:53 +01:00
2022-02-06 00:16:11 +00:00
/// Creates a Fence Interface, does not create a backend fence if 'is_stubbed' is
2020-04-16 17:29:53 +01:00
/// true
2022-02-06 00:16:11 +00:00
virtual TFence CreateFence(bool is_stubbed) = 0;
2020-04-16 17:29:53 +01:00
/// Queues a fence into the backend if the fence isn't stubbed.
2020-02-18 00:19:26 +00:00
virtual void QueueFence(TFence& fence) = 0;
2020-04-16 17:29:53 +01: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-18 00:19:26 +00:00
virtual void WaitFence(TFence& fence) = 0;
VideoCore::RasterizerInterface& rasterizer;
Tegra::GPU& gpu;
2022-01-30 09:31:13 +00:00
Tegra::Host1x::SyncpointManager& syncpoint_manager;
2020-02-18 00:19:26 +00:00
TTextureCache& texture_cache;
TTBufferCache& buffer_cache;
2020-04-15 21:36:14 +01:00
TQueryCache& query_cache;
2020-02-18 00:19:26 +00:00
private:
void TryReleasePendingFences() {
while (!fences.empty()) {
TFence& current_fence = fences.front();
2020-04-16 17:29:53 +01:00
if (ShouldWait() && !IsFenceSignaled(current_fence)) {
2020-02-18 00:19:26 +00:00
return;
}
2020-04-16 17:29:53 +01:00
PopAsyncFlushes();
2022-02-06 00:16:11 +00:00
auto operations = std::move(pending_operations.front());
pending_operations.pop_front();
for (auto& operation : operations) {
operation();
}
PopFence();
2020-02-18 00:19:26 +00:00
}
}
2020-04-16 17:29:53 +01:00
bool ShouldWait() const {
std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex};
2020-04-16 17:29:53 +01:00
return texture_cache.ShouldWaitAsyncFlushes() || buffer_cache.ShouldWaitAsyncFlushes() ||
query_cache.ShouldWaitAsyncFlushes();
}
bool ShouldFlush() const {
std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex};
2020-04-16 17:29:53 +01:00
return texture_cache.HasUncommittedFlushes() || buffer_cache.HasUncommittedFlushes() ||
query_cache.HasUncommittedFlushes();
}
void PopAsyncFlushes() {
2022-02-06 00:16:11 +00:00
{
std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex};
texture_cache.PopAsyncFlushes();
buffer_cache.PopAsyncFlushes();
}
2020-04-16 17:29:53 +01:00
query_cache.PopAsyncFlushes();
}
void CommitAsyncFlushes() {
2022-02-06 00:16:11 +00:00
{
std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex};
texture_cache.CommitAsyncFlushes();
buffer_cache.CommitAsyncFlushes();
}
2020-04-16 17:29:53 +01:00
query_cache.CommitAsyncFlushes();
}
void PopFence() {
delayed_destruction_ring.Push(std::move(fences.front()));
fences.pop();
}
2022-02-06 00:16:11 +00:00
void CommitOperations() {
pending_operations.emplace_back(std::move(uncommitted_operations));
}
2020-02-18 00:19:26 +00:00
std::queue<TFence> fences;
2022-02-06 00:16:11 +00:00
std::deque<std::function<void()>> uncommitted_operations;
std::deque<std::deque<std::function<void()>>> pending_operations;
DelayedDestructionRing<TFence, 6> delayed_destruction_ring;
2020-02-18 00:19:26 +00:00
};
} // namespace VideoCommon