fence_manager.h 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. // Copyright 2020 yuzu Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #pragma once
  5. #include <algorithm>
  6. #include <queue>
  7. #include "common/common_types.h"
  8. #include "common/settings.h"
  9. #include "core/core.h"
  10. #include "video_core/delayed_destruction_ring.h"
  11. #include "video_core/gpu.h"
  12. #include "video_core/memory_manager.h"
  13. #include "video_core/rasterizer_interface.h"
  14. namespace VideoCommon {
  15. class FenceBase {
  16. public:
  17. explicit FenceBase(u32 payload_, bool is_stubbed_)
  18. : address{}, payload{payload_}, is_semaphore{false}, is_stubbed{is_stubbed_} {}
  19. explicit FenceBase(GPUVAddr address_, u32 payload_, bool is_stubbed_)
  20. : address{address_}, payload{payload_}, is_semaphore{true}, is_stubbed{is_stubbed_} {}
  21. GPUVAddr GetAddress() const {
  22. return address;
  23. }
  24. u32 GetPayload() const {
  25. return payload;
  26. }
  27. bool IsSemaphore() const {
  28. return is_semaphore;
  29. }
  30. private:
  31. GPUVAddr address;
  32. u32 payload;
  33. bool is_semaphore;
  34. protected:
  35. bool is_stubbed;
  36. };
  37. template <typename TFence, typename TTextureCache, typename TTBufferCache, typename TQueryCache>
  38. class FenceManager {
  39. public:
  40. /// Notify the fence manager about a new frame
  41. void TickFrame() {
  42. delayed_destruction_ring.Tick();
  43. }
  44. // Unlike other fences, this one doesn't
  45. void SignalOrdering() {
  46. std::scoped_lock lock{buffer_cache.mutex};
  47. buffer_cache.AccumulateFlushes();
  48. }
  49. void SignalSemaphore(GPUVAddr addr, u32 value) {
  50. TryReleasePendingFences();
  51. const bool should_flush = ShouldFlush();
  52. CommitAsyncFlushes();
  53. TFence new_fence = CreateFence(addr, value, !should_flush);
  54. fences.push(new_fence);
  55. QueueFence(new_fence);
  56. if (should_flush) {
  57. rasterizer.FlushCommands();
  58. }
  59. rasterizer.SyncGuestHost();
  60. }
  61. void SignalSyncPoint(u32 value) {
  62. TryReleasePendingFences();
  63. const bool should_flush = ShouldFlush();
  64. CommitAsyncFlushes();
  65. TFence new_fence = CreateFence(value, !should_flush);
  66. fences.push(new_fence);
  67. QueueFence(new_fence);
  68. if (should_flush) {
  69. rasterizer.FlushCommands();
  70. }
  71. rasterizer.SyncGuestHost();
  72. }
  73. void WaitPendingFences() {
  74. while (!fences.empty()) {
  75. TFence& current_fence = fences.front();
  76. if (ShouldWait()) {
  77. WaitFence(current_fence);
  78. }
  79. PopAsyncFlushes();
  80. if (current_fence->IsSemaphore()) {
  81. gpu_memory.template Write<u32>(current_fence->GetAddress(),
  82. current_fence->GetPayload());
  83. } else {
  84. gpu.IncrementSyncPoint(current_fence->GetPayload());
  85. }
  86. PopFence();
  87. }
  88. }
  89. protected:
  90. explicit FenceManager(VideoCore::RasterizerInterface& rasterizer_, Tegra::GPU& gpu_,
  91. TTextureCache& texture_cache_, TTBufferCache& buffer_cache_,
  92. TQueryCache& query_cache_)
  93. : rasterizer{rasterizer_}, gpu{gpu_}, gpu_memory{gpu.MemoryManager()},
  94. texture_cache{texture_cache_}, buffer_cache{buffer_cache_}, query_cache{query_cache_} {}
  95. virtual ~FenceManager() = default;
  96. /// Creates a Sync Point Fence Interface, does not create a backend fence if 'is_stubbed' is
  97. /// true
  98. virtual TFence CreateFence(u32 value, bool is_stubbed) = 0;
  99. /// Creates a Semaphore Fence Interface, does not create a backend fence if 'is_stubbed' is true
  100. virtual TFence CreateFence(GPUVAddr addr, u32 value, bool is_stubbed) = 0;
  101. /// Queues a fence into the backend if the fence isn't stubbed.
  102. virtual void QueueFence(TFence& fence) = 0;
  103. /// Notifies that the backend fence has been signaled/reached in host GPU.
  104. virtual bool IsFenceSignaled(TFence& fence) const = 0;
  105. /// Waits until a fence has been signalled by the host GPU.
  106. virtual void WaitFence(TFence& fence) = 0;
  107. VideoCore::RasterizerInterface& rasterizer;
  108. Tegra::GPU& gpu;
  109. Tegra::MemoryManager& gpu_memory;
  110. TTextureCache& texture_cache;
  111. TTBufferCache& buffer_cache;
  112. TQueryCache& query_cache;
  113. private:
  114. void TryReleasePendingFences() {
  115. while (!fences.empty()) {
  116. TFence& current_fence = fences.front();
  117. if (ShouldWait() && !IsFenceSignaled(current_fence)) {
  118. return;
  119. }
  120. PopAsyncFlushes();
  121. if (current_fence->IsSemaphore()) {
  122. gpu_memory.template Write<u32>(current_fence->GetAddress(),
  123. current_fence->GetPayload());
  124. } else {
  125. gpu.IncrementSyncPoint(current_fence->GetPayload());
  126. }
  127. PopFence();
  128. }
  129. }
  130. bool ShouldWait() const {
  131. std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex};
  132. return texture_cache.ShouldWaitAsyncFlushes() || buffer_cache.ShouldWaitAsyncFlushes() ||
  133. query_cache.ShouldWaitAsyncFlushes();
  134. }
  135. bool ShouldFlush() const {
  136. std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex};
  137. return texture_cache.HasUncommittedFlushes() || buffer_cache.HasUncommittedFlushes() ||
  138. query_cache.HasUncommittedFlushes();
  139. }
  140. void PopAsyncFlushes() {
  141. std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex};
  142. texture_cache.PopAsyncFlushes();
  143. buffer_cache.PopAsyncFlushes();
  144. query_cache.PopAsyncFlushes();
  145. }
  146. void CommitAsyncFlushes() {
  147. std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex};
  148. texture_cache.CommitAsyncFlushes();
  149. buffer_cache.CommitAsyncFlushes();
  150. query_cache.CommitAsyncFlushes();
  151. }
  152. void PopFence() {
  153. delayed_destruction_ring.Push(std::move(fences.front()));
  154. fences.pop();
  155. }
  156. std::queue<TFence> fences;
  157. DelayedDestructionRing<TFence, 6> delayed_destruction_ring;
  158. };
  159. } // namespace VideoCommon