/** ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** * Copyright 2022 Ben Vanik. All rights reserved. * * Released under the BSD license - see LICENSE in the root for more details. * ****************************************************************************** * * @modified Tom Clay, 2026 - Adapted for ReXGlue runtime */ #pragma once #include "rex/system/function_dispatcher.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // Forward declarations namespace rex { class Memory; namespace stream { class ByteStream; } // namespace stream } // namespace rex namespace rex::ui { class WindowedAppContext; } // namespace rex::ui namespace rex::graphics { class CommandProcessor; class GraphicsSystem : public system::IGraphicsSystem { public: virtual ~GraphicsSystem(); virtual std::string name() const = 0; memory::Memory* memory() const { return memory_; } runtime::FunctionDispatcher* function_dispatcher() const { return function_dispatcher_; } system::KernelState* kernel_state() const { return kernel_state_; } ::rex::ui::GraphicsProvider* provider() const { return provider_.get(); } ::rex::ui::Presenter* presenter() const { return presenter_.get(); } X_STATUS SetupPresentation(::rex::ui::WindowedAppContext* app_context) override; X_STATUS SetupGuestGpu(runtime::FunctionDispatcher* function_dispatcher, system::KernelState* kernel_state) override; bool has_presentation() const override { return presenter_ != nullptr; } void Shutdown() override; // May be called from any thread any number of times, even during recovery // from a device loss. void OnHostGpuLossFromAnyThread(bool is_responsible); RegisterFile* register_file() { return ®ister_file_; } CommandProcessor* command_processor() const { return command_processor_.get(); } virtual void InitializeRingBuffer(uint32_t ptr, uint32_t size_log2); virtual void EnableReadPointerWriteBack(uint32_t ptr, uint32_t block_size_log2); virtual void SetInterruptCallback(uint32_t callback, uint32_t user_data); void DispatchInterruptCallback(uint32_t source, uint32_t cpu); virtual void ClearCaches(); virtual void InvalidateGpuMemory(); void InitializeShaderStorage(const std::filesystem::path& cache_root, uint32_t title_id, bool blocking); void RequestFrameTrace(); void BeginTracing(); void EndTracing(); bool is_paused() const { return paused_; } void Pause(); void Resume(); bool Save(::rex::stream::ByteStream* stream); bool Restore(::rex::stream::ByteStream* stream); protected: GraphicsSystem(); // Backends build their provider here. Called lazily from either setup // entry point; with_presentation is false only on headless guest-GPU paths. virtual void CreateProvider(bool with_presentation) = 0; virtual std::unique_ptr CreateCommandProcessor() = 0; static uint32_t ReadRegisterThunk(void* ppc_context, GraphicsSystem* gs, uint32_t addr); static void WriteRegisterThunk(void* ppc_context, GraphicsSystem* gs, uint32_t addr, uint32_t value); uint32_t ReadRegister(uint32_t addr); void WriteRegister(uint32_t addr, uint32_t value); void MarkVblank(); memory::Memory* memory_ = nullptr; runtime::FunctionDispatcher* function_dispatcher_ = nullptr; system::KernelState* kernel_state_ = nullptr; ::rex::ui::WindowedAppContext* app_context_ = nullptr; std::unique_ptr<::rex::ui::GraphicsProvider> provider_; bool provider_supports_presentation_ = false; uint32_t interrupt_callback_ = 0; uint32_t interrupt_callback_data_ = 0; std::atomic shutting_down_{false}; std::atomic vsync_worker_running_; system::object_ref vsync_worker_thread_; RegisterFile register_file_; std::unique_ptr command_processor_; bool paused_ = false; private: std::unique_ptr<::rex::ui::Presenter> presenter_; std::atomic_flag host_gpu_loss_reported_; }; } // namespace rex::graphics