Files

158 lines
5.4 KiB
C++

/**
******************************************************************************
* 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 <atomic>
#include <cstdint>
#include <functional>
#include <memory>
#include <mutex>
#include <string>
#include <thread>
#include <rex/graphics/register_file.h>
#include <rex/kernel.h>
#include <rex/memory.h>
#include <rex/system/interfaces/graphics.h>
#include <rex/system/xthread.h>
#include <rex/thread/mutex.h>
#include <rex/ui/graphics_provider.h>
#include <rex/ui/presenter.h>
// 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 override { return provider_.get(); }
::rex::ui::Presenter* presenter() const override { 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 &register_file_; }
CommandProcessor* command_processor() const { return command_processor_.get(); }
virtual void InitializeRingBuffer(uint32_t ptr, uint32_t size_log2) override;
virtual void EnableReadPointerWriteBack(uint32_t ptr, uint32_t block_size_log2) override;
virtual void SetInterruptCallback(uint32_t callback, uint32_t user_data) override;
virtual void SetFrameBoundaryCallback(std::function<void(rex::memory::Memory*)> callback) override;
virtual bool HandleVideoSwap(const system::GraphicsSwapSubmission& submission) override;
bool GetLastSwapSubmission(system::GraphicsSwapSubmission* out_submission,
uint64_t* out_sequence = nullptr) const;
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();
uint64_t guest_vblank_interval_ticks() const {
return guest_vblank_interval_ticks_.load(std::memory_order_acquire);
}
uint64_t last_vblank_interrupt_guest_tick() const {
return last_vblank_interrupt_guest_tick_.load(std::memory_order_acquire);
}
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<CommandProcessor> 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<bool> vsync_worker_running_;
system::object_ref<system::XHostThread> vsync_worker_thread_;
std::atomic<uint64_t> guest_vblank_interval_ticks_{0};
std::atomic<uint64_t> last_vblank_interrupt_guest_tick_{0};
mutable std::mutex last_swap_submission_mutex_;
system::GraphicsSwapSubmission last_swap_submission_{};
uint64_t last_swap_submission_sequence_ = 0;
std::function<void(rex::memory::Memory*)> frame_boundary_callback_;
RegisterFile register_file_;
std::unique_ptr<CommandProcessor> command_processor_;
bool paused_ = false;
private:
std::unique_ptr<::rex::ui::Presenter> presenter_;
std::atomic_flag host_gpu_loss_reported_;
};
} // namespace rex::graphics