gpu_thread.h 5.1 KB

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