gpu_thread.h 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  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. 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 a command list is ready for processing
  22. struct SubmitListCommand final {
  23. explicit SubmitListCommand(Tegra::CommandList&& entries) : entries{std::move(entries)} {}
  24. Tegra::CommandList entries;
  25. };
  26. /// Command to signal to the GPU thread that a swap buffers is pending
  27. struct SwapBuffersCommand final {
  28. explicit SwapBuffersCommand(std::optional<const Tegra::FramebufferConfig> framebuffer)
  29. : framebuffer{std::move(framebuffer)} {}
  30. std::optional<const Tegra::FramebufferConfig> framebuffer;
  31. };
  32. /// Command to signal to the GPU thread to flush a region
  33. struct FlushRegionCommand final {
  34. explicit constexpr FlushRegionCommand(VAddr addr, u64 size) : addr{addr}, size{size} {}
  35. const VAddr addr;
  36. const u64 size;
  37. };
  38. /// Command to signal to the GPU thread to invalidate a region
  39. struct InvalidateRegionCommand final {
  40. explicit constexpr InvalidateRegionCommand(VAddr addr, u64 size) : addr{addr}, size{size} {}
  41. const VAddr addr;
  42. const u64 size;
  43. };
  44. /// Command to signal to the GPU thread to flush and invalidate a region
  45. struct FlushAndInvalidateRegionCommand final {
  46. explicit constexpr FlushAndInvalidateRegionCommand(VAddr addr, u64 size)
  47. : addr{addr}, size{size} {}
  48. const VAddr addr;
  49. const u64 size;
  50. };
  51. using CommandData = std::variant<SubmitListCommand, SwapBuffersCommand, FlushRegionCommand,
  52. InvalidateRegionCommand, FlushAndInvalidateRegionCommand>;
  53. /// Struct used to synchronize the GPU thread
  54. struct SynchState final {
  55. std::atomic<bool> is_running{true};
  56. std::atomic<bool> is_idle{true};
  57. std::condition_variable signal_condition;
  58. std::mutex signal_mutex;
  59. std::condition_variable idle_condition;
  60. std::mutex idle_mutex;
  61. // We use two queues for sending commands to the GPU thread, one for writing (push_queue) to and
  62. // one for reading from (pop_queue). These are swapped whenever the current pop_queue becomes
  63. // empty. This allows for efficient thread-safe access, as it does not require any copies.
  64. using CommandQueue = std::queue<CommandData>;
  65. std::array<CommandQueue, 2> command_queues;
  66. CommandQueue* push_queue{&command_queues[0]};
  67. CommandQueue* pop_queue{&command_queues[1]};
  68. void UpdateIdleState() {
  69. std::lock_guard<std::mutex> lock{idle_mutex};
  70. is_idle = command_queues[0].empty() && command_queues[1].empty();
  71. }
  72. };
  73. /// Class used to manage the GPU thread
  74. class ThreadManager final {
  75. public:
  76. explicit ThreadManager(VideoCore::RendererBase& renderer, Tegra::DmaPusher& dma_pusher);
  77. ~ThreadManager();
  78. /// Push GPU command entries to be processed
  79. void SubmitList(Tegra::CommandList&& entries);
  80. /// Swap buffers (render frame)
  81. void SwapBuffers(
  82. std::optional<std::reference_wrapper<const Tegra::FramebufferConfig>> framebuffer);
  83. /// Notify rasterizer that any caches of the specified region should be flushed to Switch memory
  84. void FlushRegion(VAddr addr, u64 size);
  85. /// Notify rasterizer that any caches of the specified region should be invalidated
  86. void InvalidateRegion(VAddr addr, u64 size);
  87. /// Notify rasterizer that any caches of the specified region should be flushed and invalidated
  88. void FlushAndInvalidateRegion(VAddr addr, u64 size);
  89. private:
  90. /// Pushes a command to be executed by the GPU thread
  91. void PushCommand(CommandData&& command_data, bool wait_for_idle, bool allow_on_cpu);
  92. /// Returns true if this is called by the GPU thread
  93. bool IsGpuThread() const {
  94. return std::this_thread::get_id() == thread_id;
  95. }
  96. private:
  97. SynchState state;
  98. VideoCore::RendererBase& renderer;
  99. Tegra::DmaPusher& dma_pusher;
  100. std::thread thread;
  101. std::thread::id thread_id;
  102. };
  103. } // namespace VideoCommon::GPUThread