gpu_thread.h 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. // Copyright 2019 yuzu Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #pragma once
  5. #include <array>
  6. #include <atomic>
  7. #include <condition_variable>
  8. #include <memory>
  9. #include <mutex>
  10. #include <optional>
  11. #include <thread>
  12. #include <variant>
  13. #include "common/threadsafe_queue.h"
  14. #include "video_core/gpu.h"
  15. namespace Tegra {
  16. struct FramebufferConfig;
  17. class DmaPusher;
  18. } // namespace Tegra
  19. namespace VideoCore {
  20. class RendererBase;
  21. } // namespace VideoCore
  22. namespace VideoCommon::GPUThread {
  23. /// Command to signal to the GPU thread that processing has ended
  24. struct EndProcessingCommand final {};
  25. /// Command to signal to the GPU thread that a command list is ready for processing
  26. struct SubmitListCommand final {
  27. explicit SubmitListCommand(Tegra::CommandList&& entries) : entries{std::move(entries)} {}
  28. Tegra::CommandList entries;
  29. };
  30. /// Command to signal to the GPU thread that a swap buffers is pending
  31. struct SwapBuffersCommand final {
  32. explicit SwapBuffersCommand(std::optional<const Tegra::FramebufferConfig> framebuffer)
  33. : framebuffer{std::move(framebuffer)} {}
  34. std::optional<Tegra::FramebufferConfig> framebuffer;
  35. };
  36. /// Command to signal to the GPU thread to flush a region
  37. struct FlushRegionCommand final {
  38. explicit constexpr FlushRegionCommand(CacheAddr addr, u64 size) : addr{addr}, size{size} {}
  39. CacheAddr addr;
  40. u64 size;
  41. };
  42. /// Command to signal to the GPU thread to invalidate a region
  43. struct InvalidateRegionCommand final {
  44. explicit constexpr InvalidateRegionCommand(CacheAddr addr, u64 size) : addr{addr}, size{size} {}
  45. CacheAddr addr;
  46. u64 size;
  47. };
  48. /// Command to signal to the GPU thread to flush and invalidate a region
  49. struct FlushAndInvalidateRegionCommand final {
  50. explicit constexpr FlushAndInvalidateRegionCommand(CacheAddr addr, u64 size)
  51. : addr{addr}, size{size} {}
  52. CacheAddr addr;
  53. u64 size;
  54. };
  55. using CommandData =
  56. std::variant<EndProcessingCommand, SubmitListCommand, SwapBuffersCommand, FlushRegionCommand,
  57. InvalidateRegionCommand, FlushAndInvalidateRegionCommand>;
  58. struct CommandDataContainer {
  59. CommandDataContainer() = default;
  60. CommandDataContainer(CommandData&& data) : data{std::move(data)} {}
  61. CommandDataContainer& operator=(const CommandDataContainer& t) {
  62. data = std::move(t.data);
  63. return *this;
  64. }
  65. CommandData data;
  66. };
  67. /// Struct used to synchronize the GPU thread
  68. struct SynchState final {
  69. std::atomic_bool is_running{true};
  70. std::atomic_int queued_frame_count{};
  71. std::mutex frames_mutex;
  72. std::mutex commands_mutex;
  73. std::condition_variable commands_condition;
  74. std::condition_variable frames_condition;
  75. void IncrementFramesCounter() {
  76. std::lock_guard<std::mutex> lock{frames_mutex};
  77. ++queued_frame_count;
  78. }
  79. void DecrementFramesCounter() {
  80. {
  81. std::lock_guard<std::mutex> lock{frames_mutex};
  82. --queued_frame_count;
  83. if (queued_frame_count) {
  84. return;
  85. }
  86. }
  87. frames_condition.notify_one();
  88. }
  89. void WaitForFrames() {
  90. {
  91. std::lock_guard<std::mutex> lock{frames_mutex};
  92. if (!queued_frame_count) {
  93. return;
  94. }
  95. }
  96. // Wait for the GPU to be idle (all commands to be executed)
  97. {
  98. std::unique_lock<std::mutex> lock{frames_mutex};
  99. frames_condition.wait(lock, [this] { return !queued_frame_count; });
  100. }
  101. }
  102. void SignalCommands() {
  103. {
  104. std::unique_lock<std::mutex> lock{commands_mutex};
  105. if (queue.Empty()) {
  106. return;
  107. }
  108. }
  109. commands_condition.notify_one();
  110. }
  111. void WaitForCommands() {
  112. std::unique_lock<std::mutex> lock{commands_mutex};
  113. commands_condition.wait(lock, [this] { return !queue.Empty(); });
  114. }
  115. using CommandQueue = Common::SPSCQueue<CommandDataContainer>;
  116. CommandQueue queue;
  117. };
  118. /// Class used to manage the GPU thread
  119. class ThreadManager final {
  120. public:
  121. explicit ThreadManager(VideoCore::RendererBase& renderer, Tegra::DmaPusher& dma_pusher);
  122. ~ThreadManager();
  123. /// Push GPU command entries to be processed
  124. void SubmitList(Tegra::CommandList&& entries);
  125. /// Swap buffers (render frame)
  126. void SwapBuffers(
  127. std::optional<std::reference_wrapper<const Tegra::FramebufferConfig>> framebuffer);
  128. /// Notify rasterizer that any caches of the specified region should be flushed to Switch memory
  129. void FlushRegion(CacheAddr addr, u64 size);
  130. /// Notify rasterizer that any caches of the specified region should be invalidated
  131. void InvalidateRegion(CacheAddr addr, u64 size);
  132. /// Notify rasterizer that any caches of the specified region should be flushed and invalidated
  133. void FlushAndInvalidateRegion(CacheAddr addr, u64 size);
  134. private:
  135. /// Pushes a command to be executed by the GPU thread
  136. void PushCommand(CommandData&& command_data);
  137. private:
  138. SynchState state;
  139. VideoCore::RendererBase& renderer;
  140. Tegra::DmaPusher& dma_pusher;
  141. std::thread thread;
  142. std::thread::id thread_id;
  143. };
  144. } // namespace VideoCommon::GPUThread