#ifndef EMULATOR_INCLUDE_EMULATOR_GRAPHICS_GRAPHICSRUN_H_ #define EMULATOR_INCLUDE_EMULATOR_GRAPHICS_GRAPHICSRUN_H_ #include "common/abi.h" #include "common/common.h" #include "common/threads.h" #include "common/uniqueFunction.h" #include "graphics/guest_gpu/command_processor/commandProcessor.h" #include #include #include #include #include #include #include #include #include namespace Libs::Graphics { class RenderContext; class GuestGpu final { public: explicit GuestGpu(RenderContext& renderer); ~GuestGpu(); KYTY_CLASS_NO_COPY(GuestGpu); void Shutdown(); [[nodiscard]] bool IsStopping(); void SendCommand(Common::UniqueFunction&& command); void SendCommandSync(Common::UniqueFunction&& command); // Submitted command memory is borrowed and must remain valid until GPU execution completes. void Submit(std::span draw_commands, std::span constant_commands); void SubmitCompute(uint32_t queue, std::span commands); void SubmitFlipPreparation(uint64_t request_id); // Insert an ordered graphics drain; only a previous suspend point can block the caller. void SuspendPoint(); // Wait for guest command processing, including all compute queues (not native GPU completion). void WaitForIdle(); [[nodiscard]] int GetFrameNum() const; [[nodiscard]] static bool IsGpuThread() noexcept; private: static constexpr uint32_t ComputePipeCount = 7; static constexpr uint32_t QueuesPerComputePipe = 8; static constexpr uint32_t ComputeQueueCount = ComputePipeCount * QueuesPerComputePipe; static constexpr uint32_t ComputeQueueBase = 0x20; static constexpr uint32_t QueueCount = 1 + ComputeQueueCount; enum class SubmissionType { Graphics, Compute, FlipPreparation, SuspendPoint }; struct Submission { SubmissionType type = SubmissionType::Graphics; uint32_t queue_id = 0; std::span commands; std::span constant_commands; Pm4Execution command_execution; Pm4Execution constant_execution; bool started = false; bool command_complete = false; bool constant_complete = false; bool blocked = false; uint64_t flip_request_id = 0; }; void Enqueue(Submission submission); void ProcessCommands(); bool Process(Submission& submission); static void ThreadRun(void* data); CommandProcessor& GetProcessor(uint32_t queue_id); RenderContext& m_renderer; Common::Mutex m_queue_mutex; std::mutex m_shutdown_mutex; Common::CondVar m_work_available; Common::CondVar m_idle; std::array, QueueCount> m_queues; std::deque> m_commands; std::atomic_uint32_t m_pending_commands {0}; uint32_t m_next_queue = 0; uint32_t m_submission_count = 0; bool m_processing = false; bool m_accepting = true; bool m_stopping = false; bool m_shutdown_complete = false; // Completion callbacks can outlive GuestGpu during renderer shutdown. std::shared_ptr m_suspend_point_ready = std::make_shared(1); std::unique_ptr m_gfx_cp; std::array, ComputeQueueCount> m_compute_cp; uint64_t m_submit_id = 0; std::atomic_int m_done_num = 0; std::jthread m_thread; friend class CommandProcessor; }; } // namespace Libs::Graphics #endif /* EMULATOR_INCLUDE_EMULATOR_GRAPHICS_GRAPHICSRUN_H_ */