| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133 |
- // Copyright 2019 yuzu Emulator Project
- // Licensed under GPLv2 or any later version
- // Refer to the license.txt file included.
- #pragma once
- #include <array>
- #include <atomic>
- #include <condition_variable>
- #include <memory>
- #include <mutex>
- #include <optional>
- #include <thread>
- #include <variant>
- namespace Tegra {
- struct FramebufferConfig;
- class DmaPusher;
- } // namespace Tegra
- namespace VideoCore {
- class RendererBase;
- } // namespace VideoCore
- namespace VideoCommon::GPUThread {
- /// Command to signal to the GPU thread that a command list is ready for processing
- struct SubmitListCommand final {
- explicit SubmitListCommand(Tegra::CommandList&& entries) : entries{std::move(entries)} {}
- Tegra::CommandList entries;
- };
- /// Command to signal to the GPU thread that a swap buffers is pending
- struct SwapBuffersCommand final {
- explicit SwapBuffersCommand(std::optional<const Tegra::FramebufferConfig> framebuffer)
- : framebuffer{std::move(framebuffer)} {}
- std::optional<const Tegra::FramebufferConfig> framebuffer;
- };
- /// Command to signal to the GPU thread to flush a region
- struct FlushRegionCommand final {
- explicit constexpr FlushRegionCommand(VAddr addr, u64 size) : addr{addr}, size{size} {}
- const VAddr addr;
- const u64 size;
- };
- /// Command to signal to the GPU thread to invalidate a region
- struct InvalidateRegionCommand final {
- explicit constexpr InvalidateRegionCommand(VAddr addr, u64 size) : addr{addr}, size{size} {}
- const VAddr addr;
- const u64 size;
- };
- /// Command to signal to the GPU thread to flush and invalidate a region
- struct FlushAndInvalidateRegionCommand final {
- explicit constexpr FlushAndInvalidateRegionCommand(VAddr addr, u64 size)
- : addr{addr}, size{size} {}
- const VAddr addr;
- const u64 size;
- };
- using CommandData = std::variant<SubmitListCommand, SwapBuffersCommand, FlushRegionCommand,
- InvalidateRegionCommand, FlushAndInvalidateRegionCommand>;
- /// Struct used to synchronize the GPU thread
- struct SynchState final {
- std::atomic<bool> is_running{true};
- std::atomic<bool> is_idle{true};
- std::condition_variable signal_condition;
- std::mutex signal_mutex;
- std::condition_variable idle_condition;
- std::mutex idle_mutex;
- // We use two queues for sending commands to the GPU thread, one for writing (push_queue) to and
- // one for reading from (pop_queue). These are swapped whenever the current pop_queue becomes
- // empty. This allows for efficient thread-safe access, as it does not require any copies.
- using CommandQueue = std::queue<CommandData>;
- std::array<CommandQueue, 2> command_queues;
- CommandQueue* push_queue{&command_queues[0]};
- CommandQueue* pop_queue{&command_queues[1]};
- void UpdateIdleState() {
- std::lock_guard<std::mutex> lock{idle_mutex};
- is_idle = command_queues[0].empty() && command_queues[1].empty();
- }
- };
- /// Class used to manage the GPU thread
- class ThreadManager final {
- public:
- explicit ThreadManager(VideoCore::RendererBase& renderer, Tegra::DmaPusher& dma_pusher);
- ~ThreadManager();
- /// Push GPU command entries to be processed
- void SubmitList(Tegra::CommandList&& entries);
- /// Swap buffers (render frame)
- void SwapBuffers(
- std::optional<std::reference_wrapper<const Tegra::FramebufferConfig>> framebuffer);
- /// Notify rasterizer that any caches of the specified region should be flushed to Switch memory
- void FlushRegion(VAddr addr, u64 size);
- /// Notify rasterizer that any caches of the specified region should be invalidated
- void InvalidateRegion(VAddr addr, u64 size);
- /// Notify rasterizer that any caches of the specified region should be flushed and invalidated
- void FlushAndInvalidateRegion(VAddr addr, u64 size);
- private:
- /// Pushes a command to be executed by the GPU thread
- void PushCommand(CommandData&& command_data, bool wait_for_idle, bool allow_on_cpu);
- /// Returns true if this is called by the GPU thread
- bool IsGpuThread() const {
- return std::this_thread::get_id() == thread_id;
- }
- private:
- SynchState state;
- VideoCore::RendererBase& renderer;
- Tegra::DmaPusher& dma_pusher;
- std::thread thread;
- std::thread::id thread_id;
- };
- } // namespace VideoCommon::GPUThread
|