fence_manager.h 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #pragma once
  4. #include <algorithm>
  5. #include <cstring>
  6. #include <deque>
  7. #include <functional>
  8. #include <memory>
  9. #include <queue>
  10. #include "common/common_types.h"
  11. #include "video_core/delayed_destruction_ring.h"
  12. #include "video_core/gpu.h"
  13. #include "video_core/host1x/host1x.h"
  14. #include "video_core/host1x/syncpoint_manager.h"
  15. #include "video_core/rasterizer_interface.h"
  16. namespace VideoCommon {
  17. class FenceBase {
  18. public:
  19. explicit FenceBase(bool is_stubbed_) : is_stubbed{is_stubbed_} {}
  20. protected:
  21. bool is_stubbed;
  22. };
  23. template <typename TFence, typename TTextureCache, typename TTBufferCache, typename TQueryCache>
  24. class FenceManager {
  25. public:
  26. /// Notify the fence manager about a new frame
  27. void TickFrame() {
  28. delayed_destruction_ring.Tick();
  29. }
  30. // Unlike other fences, this one doesn't
  31. void SignalOrdering() {
  32. std::scoped_lock lock{buffer_cache.mutex};
  33. buffer_cache.AccumulateFlushes();
  34. }
  35. void SyncOperation(std::function<void()>&& func) {
  36. uncommitted_operations.emplace_back(std::move(func));
  37. }
  38. void SignalFence(std::function<void()>&& func) {
  39. TryReleasePendingFences();
  40. const bool should_flush = ShouldFlush();
  41. CommitAsyncFlushes();
  42. uncommitted_operations.emplace_back(std::move(func));
  43. CommitOperations();
  44. TFence new_fence = CreateFence(!should_flush);
  45. fences.push(new_fence);
  46. QueueFence(new_fence);
  47. if (should_flush) {
  48. rasterizer.FlushCommands();
  49. }
  50. }
  51. void SignalSyncPoint(u32 value) {
  52. syncpoint_manager.IncrementGuest(value);
  53. std::function<void()> func([this, value] { syncpoint_manager.IncrementHost(value); });
  54. SignalFence(std::move(func));
  55. }
  56. void WaitPendingFences() {
  57. while (!fences.empty()) {
  58. TFence& current_fence = fences.front();
  59. if (ShouldWait()) {
  60. WaitFence(current_fence);
  61. }
  62. PopAsyncFlushes();
  63. auto operations = std::move(pending_operations.front());
  64. pending_operations.pop_front();
  65. for (auto& operation : operations) {
  66. operation();
  67. }
  68. PopFence();
  69. }
  70. }
  71. protected:
  72. explicit FenceManager(VideoCore::RasterizerInterface& rasterizer_, Tegra::GPU& gpu_,
  73. TTextureCache& texture_cache_, TTBufferCache& buffer_cache_,
  74. TQueryCache& query_cache_)
  75. : rasterizer{rasterizer_}, gpu{gpu_}, syncpoint_manager{gpu.Host1x().GetSyncpointManager()},
  76. texture_cache{texture_cache_}, buffer_cache{buffer_cache_}, query_cache{query_cache_} {}
  77. virtual ~FenceManager() = default;
  78. /// Creates a Fence Interface, does not create a backend fence if 'is_stubbed' is
  79. /// true
  80. virtual TFence CreateFence(bool is_stubbed) = 0;
  81. /// Queues a fence into the backend if the fence isn't stubbed.
  82. virtual void QueueFence(TFence& fence) = 0;
  83. /// Notifies that the backend fence has been signaled/reached in host GPU.
  84. virtual bool IsFenceSignaled(TFence& fence) const = 0;
  85. /// Waits until a fence has been signalled by the host GPU.
  86. virtual void WaitFence(TFence& fence) = 0;
  87. VideoCore::RasterizerInterface& rasterizer;
  88. Tegra::GPU& gpu;
  89. Tegra::Host1x::SyncpointManager& syncpoint_manager;
  90. TTextureCache& texture_cache;
  91. TTBufferCache& buffer_cache;
  92. TQueryCache& query_cache;
  93. private:
  94. void TryReleasePendingFences() {
  95. while (!fences.empty()) {
  96. TFence& current_fence = fences.front();
  97. if (ShouldWait() && !IsFenceSignaled(current_fence)) {
  98. return;
  99. }
  100. PopAsyncFlushes();
  101. auto operations = std::move(pending_operations.front());
  102. pending_operations.pop_front();
  103. for (auto& operation : operations) {
  104. operation();
  105. }
  106. PopFence();
  107. }
  108. }
  109. bool ShouldWait() const {
  110. std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex};
  111. return texture_cache.ShouldWaitAsyncFlushes() || buffer_cache.ShouldWaitAsyncFlushes() ||
  112. query_cache.ShouldWaitAsyncFlushes();
  113. }
  114. bool ShouldFlush() const {
  115. std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex};
  116. return texture_cache.HasUncommittedFlushes() || buffer_cache.HasUncommittedFlushes() ||
  117. query_cache.HasUncommittedFlushes();
  118. }
  119. void PopAsyncFlushes() {
  120. {
  121. std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex};
  122. texture_cache.PopAsyncFlushes();
  123. buffer_cache.PopAsyncFlushes();
  124. }
  125. query_cache.PopAsyncFlushes();
  126. }
  127. void CommitAsyncFlushes() {
  128. {
  129. std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex};
  130. texture_cache.CommitAsyncFlushes();
  131. buffer_cache.CommitAsyncFlushes();
  132. }
  133. query_cache.CommitAsyncFlushes();
  134. }
  135. void PopFence() {
  136. delayed_destruction_ring.Push(std::move(fences.front()));
  137. fences.pop();
  138. }
  139. void CommitOperations() {
  140. pending_operations.emplace_back(std::move(uncommitted_operations));
  141. }
  142. std::queue<TFence> fences;
  143. std::deque<std::function<void()>> uncommitted_operations;
  144. std::deque<std::deque<std::function<void()>>> pending_operations;
  145. DelayedDestructionRing<TFence, 6> delayed_destruction_ring;
  146. };
  147. } // namespace VideoCommon