diff options
| author | 2019-01-23 22:17:55 -0500 | |
|---|---|---|
| committer | 2019-03-06 21:48:57 -0500 | |
| commit | 7b574f406b25c02a0e0efd8b7ec13d68ecb55497 (patch) | |
| tree | 375d4637d49ffe506129ce9cb679b5902328106a /src/video_core/gpu_thread.h | |
| parent | bootmanager: Ensure that we have a context for shader loading. (diff) | |
| download | yuzu-7b574f406b25c02a0e0efd8b7ec13d68ecb55497.tar.gz yuzu-7b574f406b25c02a0e0efd8b7ec13d68ecb55497.tar.xz yuzu-7b574f406b25c02a0e0efd8b7ec13d68ecb55497.zip | |
gpu: Move command processing to another thread.
Diffstat (limited to 'src/video_core/gpu_thread.h')
| -rw-r--r-- | src/video_core/gpu_thread.h | 135 |
1 files changed, 135 insertions, 0 deletions
diff --git a/src/video_core/gpu_thread.h b/src/video_core/gpu_thread.h new file mode 100644 index 000000000..ad9f9462b --- /dev/null +++ b/src/video_core/gpu_thread.h | |||
| @@ -0,0 +1,135 @@ | |||
| 1 | // Copyright 2019 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <array> | ||
| 8 | #include <atomic> | ||
| 9 | #include <condition_variable> | ||
| 10 | #include <memory> | ||
| 11 | #include <mutex> | ||
| 12 | #include <optional> | ||
| 13 | #include <thread> | ||
| 14 | #include <variant> | ||
| 15 | |||
| 16 | namespace Tegra { | ||
| 17 | struct FramebufferConfig; | ||
| 18 | class DmaPusher; | ||
| 19 | } // namespace Tegra | ||
| 20 | |||
| 21 | namespace VideoCore { | ||
| 22 | class RendererBase; | ||
| 23 | } // namespace VideoCore | ||
| 24 | |||
| 25 | namespace VideoCommon::GPUThread { | ||
| 26 | |||
| 27 | /// Command to signal to the GPU thread that a command list is ready for processing | ||
| 28 | struct SubmitListCommand final { | ||
| 29 | explicit SubmitListCommand(Tegra::CommandList&& entries) : entries{std::move(entries)} {} | ||
| 30 | |||
| 31 | Tegra::CommandList entries; | ||
| 32 | }; | ||
| 33 | |||
| 34 | /// Command to signal to the GPU thread that a swap buffers is pending | ||
| 35 | struct SwapBuffersCommand final { | ||
| 36 | explicit SwapBuffersCommand(std::optional<const Tegra::FramebufferConfig> framebuffer) | ||
| 37 | : framebuffer{std::move(framebuffer)} {} | ||
| 38 | |||
| 39 | std::optional<const Tegra::FramebufferConfig> framebuffer; | ||
| 40 | }; | ||
| 41 | |||
| 42 | /// Command to signal to the GPU thread to flush a region | ||
| 43 | struct FlushRegionCommand final { | ||
| 44 | explicit constexpr FlushRegionCommand(VAddr addr, u64 size) : addr{addr}, size{size} {} | ||
| 45 | |||
| 46 | const VAddr addr; | ||
| 47 | const u64 size; | ||
| 48 | }; | ||
| 49 | |||
| 50 | /// Command to signal to the GPU thread to invalidate a region | ||
| 51 | struct InvalidateRegionCommand final { | ||
| 52 | explicit constexpr InvalidateRegionCommand(VAddr addr, u64 size) : addr{addr}, size{size} {} | ||
| 53 | |||
| 54 | const VAddr addr; | ||
| 55 | const u64 size; | ||
| 56 | }; | ||
| 57 | |||
| 58 | /// Command to signal to the GPU thread to flush and invalidate a region | ||
| 59 | struct FlushAndInvalidateRegionCommand final { | ||
| 60 | explicit constexpr FlushAndInvalidateRegionCommand(VAddr addr, u64 size) | ||
| 61 | : addr{addr}, size{size} {} | ||
| 62 | |||
| 63 | const VAddr addr; | ||
| 64 | const u64 size; | ||
| 65 | }; | ||
| 66 | |||
| 67 | using CommandData = std::variant<SubmitListCommand, SwapBuffersCommand, FlushRegionCommand, | ||
| 68 | InvalidateRegionCommand, FlushAndInvalidateRegionCommand>; | ||
| 69 | |||
| 70 | /// Struct used to synchronize the GPU thread | ||
| 71 | struct SynchState final { | ||
| 72 | std::atomic<bool> is_running{true}; | ||
| 73 | std::condition_variable signal_condition; | ||
| 74 | std::mutex signal_mutex; | ||
| 75 | std::condition_variable idle_condition; | ||
| 76 | std::mutex idle_mutex; | ||
| 77 | |||
| 78 | // We use two queues for sending commands to the GPU thread, one for writing (push_queue) to and | ||
| 79 | // one for reading from (pop_queue). These are swapped whenever the current pop_queue becomes | ||
| 80 | // empty. This allows for efficient thread-safe access, as it does not require any copies. | ||
| 81 | |||
| 82 | using CommandQueue = std::queue<CommandData>; | ||
| 83 | std::array<CommandQueue, 2> command_queues; | ||
| 84 | CommandQueue* push_queue{&command_queues[0]}; | ||
| 85 | CommandQueue* pop_queue{&command_queues[1]}; | ||
| 86 | |||
| 87 | /// Returns true if the GPU thread should be idle, meaning there are no commands to process | ||
| 88 | bool IsIdle() const { | ||
| 89 | return command_queues[0].empty() && command_queues[1].empty(); | ||
| 90 | } | ||
| 91 | }; | ||
| 92 | |||
| 93 | /// Class used to manage the GPU thread | ||
| 94 | class ThreadManager final { | ||
| 95 | public: | ||
| 96 | explicit ThreadManager(VideoCore::RendererBase& renderer, Tegra::DmaPusher& dma_pusher); | ||
| 97 | ~ThreadManager(); | ||
| 98 | |||
| 99 | /// Push GPU command entries to be processed | ||
| 100 | void SubmitList(Tegra::CommandList&& entries); | ||
| 101 | |||
| 102 | /// Swap buffers (render frame) | ||
| 103 | void SwapBuffers( | ||
| 104 | std::optional<std::reference_wrapper<const Tegra::FramebufferConfig>> framebuffer); | ||
| 105 | |||
| 106 | /// Notify rasterizer that any caches of the specified region should be flushed to Switch memory | ||
| 107 | void FlushRegion(VAddr addr, u64 size); | ||
| 108 | |||
| 109 | /// Notify rasterizer that any caches of the specified region should be invalidated | ||
| 110 | void InvalidateRegion(VAddr addr, u64 size); | ||
| 111 | |||
| 112 | /// Notify rasterizer that any caches of the specified region should be flushed and invalidated | ||
| 113 | void FlushAndInvalidateRegion(VAddr addr, u64 size); | ||
| 114 | |||
| 115 | /// Waits the caller until the GPU thread is idle, used for synchronization | ||
| 116 | void WaitForIdle(); | ||
| 117 | |||
| 118 | private: | ||
| 119 | /// Pushes a command to be executed by the GPU thread | ||
| 120 | void PushCommand(CommandData&& command_data, bool wait_for_idle, bool allow_on_cpu); | ||
| 121 | |||
| 122 | /// Returns true if this is called by the GPU thread | ||
| 123 | bool IsGpuThread() const { | ||
| 124 | return std::this_thread::get_id() == thread_id; | ||
| 125 | } | ||
| 126 | |||
| 127 | private: | ||
| 128 | SynchState state; | ||
| 129 | std::thread thread; | ||
| 130 | std::thread::id thread_id; | ||
| 131 | VideoCore::RendererBase& renderer; | ||
| 132 | Tegra::DmaPusher& dma_pusher; | ||
| 133 | }; | ||
| 134 | |||
| 135 | } // namespace VideoCommon::GPUThread | ||