GPU: Convert frontend to namespace

pull/3745/head
Stenzek 4 months ago
parent f484af5f4d
commit b123c8e2bf
No known key found for this signature in database

@ -1891,7 +1891,7 @@ template<MemoryAccessSize size>
u32 Bus::HWHandlers::GPURead(PhysicalMemoryAddress address)
{
const u32 offset = address & GPU_MASK;
u32 value = g_gpu.ReadRegister(FIXUP_WORD_OFFSET(size, offset));
u32 value = GPU::ReadRegister(FIXUP_WORD_OFFSET(size, offset));
value = FIXUP_WORD_READ_VALUE(size, offset, value);
BUS_CYCLES(2);
return value;
@ -1901,7 +1901,7 @@ template<MemoryAccessSize size>
void Bus::HWHandlers::GPUWrite(PhysicalMemoryAddress address, u32 value)
{
const u32 offset = address & GPU_MASK;
g_gpu.WriteRegister(FIXUP_WORD_OFFSET(size, offset), FIXUP_WORD_WRITE_VALUE(size, offset, value));
GPU::WriteRegister(FIXUP_WORD_OFFSET(size, offset), FIXUP_WORD_WRITE_VALUE(size, offset, value));
}
template<MemoryAccessSize size>

@ -821,9 +821,9 @@ TickCount DMA::TransferMemoryToDevice(u32 address, u32 increment, u32 word_count
{
case Channel::GPU:
{
if (g_gpu.BeginDMAWrite()) [[likely]]
if (GPU::BeginDMAWrite()) [[likely]]
{
if (GPUDump::Recorder* dump = g_gpu.GetGPUDump()) [[unlikely]]
if (GPUDump::Recorder* dump = GPU::GetGPUDump()) [[unlikely]]
{
// No wraparound?
dump->BeginGP0Packet(word_count);
@ -850,10 +850,10 @@ TickCount DMA::TransferMemoryToDevice(u32 address, u32 increment, u32 word_count
{
u32 value;
std::memcpy(&value, &ram_pointer[address], sizeof(u32));
g_gpu.DMAWrite(address, value);
GPU::DMAWrite(address, value);
address = (address + increment) & mask;
}
g_gpu.EndDMAWrite();
GPU::EndDMAWrite();
}
}
break;
@ -928,7 +928,7 @@ TickCount DMA::TransferDeviceToMemory(u32 address, u32 increment, u32 word_count
switch (channel)
{
case Channel::GPU:
g_gpu.DMARead(dest_pointer, word_count);
GPU::DMARead(dest_pointer, word_count);
break;
case Channel::CDROM:

File diff suppressed because it is too large Load Diff

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2019-2025 Connor McLaughlin <stenzek@gmail.com>
// SPDX-FileCopyrightText: 2019-2026 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
#pragma once
@ -6,502 +6,139 @@
#include "gpu_types.h"
#include "types.h"
#include "common/bitfield.h"
#include "common/fifo_queue.h"
#include "common/gsvector.h"
#include "common/types.h"
#include <algorithm>
#include <array>
#include <deque>
#include <memory>
#include <span>
#include <string>
#include <tuple>
#include <vector>
#include <utility>
class Error;
class Image;
class SmallStringBase;
class StateWrapper;
class GPUDevice;
class GPUTexture;
class GPUPipeline;
class MediaCapture;
namespace GPUDump {
enum class PacketType : u8;
class Recorder;
class Player;
} // namespace GPUDump
class GPUBackend;
struct Settings;
namespace System {
struct MemorySaveState;
}
struct GPUBackendCommand;
struct GPUBackendDrawCommand;
class GPU final
{
public:
enum class BlitterState : u8
{
Idle,
ReadingVRAM,
WritingVRAM,
DrawingPolyLine
};
enum : u32
{
MAX_FIFO_SIZE = 4096,
DOT_TIMER_INDEX = 0,
HBLANK_TIMER_INDEX = 1,
MAX_RESOLUTION_SCALE = 32,
DRAWING_AREA_COORD_MASK = 1023,
};
enum : u16
{
NTSC_TICKS_PER_LINE = 3413,
NTSC_TOTAL_LINES = 263,
PAL_TICKS_PER_LINE = 3406,
PAL_TOTAL_LINES = 314,
};
enum : u16
{
NTSC_HORIZONTAL_ACTIVE_START = 488,
NTSC_HORIZONTAL_ACTIVE_END = 3288,
NTSC_VERTICAL_ACTIVE_START = 16,
NTSC_VERTICAL_ACTIVE_END = 256,
NTSC_OVERSCAN_HORIZONTAL_ACTIVE_START = 608,
NTSC_OVERSCAN_HORIZONTAL_ACTIVE_END = 3168,
NTSC_OVERSCAN_VERTICAL_ACTIVE_START = 24,
NTSC_OVERSCAN_VERTICAL_ACTIVE_END = 248,
PAL_HORIZONTAL_ACTIVE_START = 488,
PAL_HORIZONTAL_ACTIVE_END = 3300,
PAL_VERTICAL_ACTIVE_START = 20,
PAL_VERTICAL_ACTIVE_END = 308,
PAL_OVERSCAN_HORIZONTAL_ACTIVE_START = 628,
PAL_OVERSCAN_HORIZONTAL_ACTIVE_END = 3188,
PAL_OVERSCAN_VERTICAL_ACTIVE_START = 30,
PAL_OVERSCAN_VERTICAL_ACTIVE_END = 298,
};
// Base class constructor.
GPU();
~GPU();
void Initialize();
void Shutdown();
void Reset(bool clear_vram);
bool DoState(StateWrapper& sw);
void DoMemoryState(StateWrapper& sw, System::MemorySaveState& mss);
// Render statistics debug window.
void DrawDebugStateWindow(float scale);
void CPUClockChanged();
// MMIO access
u32 ReadRegister(u32 offset);
void WriteRegister(u32 offset, u32 value);
// DMA access
void DMARead(u32* words, u32 word_count);
ALWAYS_INLINE bool BeginDMAWrite() const
{
return (m_GPUSTAT.dma_direction == GPUDMADirection::CPUtoGP0 || m_GPUSTAT.dma_direction == GPUDMADirection::FIFO);
}
ALWAYS_INLINE void DMAWrite(u32 address, u32 value)
{
m_fifo.Push((ZeroExtend64(address) << 32) | ZeroExtend64(value));
}
void EndDMAWrite();
/// Writing to GPU dump.
GPUDump::Recorder* GetGPUDump() const { return m_gpu_dump.get(); }
bool StartRecordingGPUDump(const char* path, u32 num_frames = 1);
void StopRecordingGPUDump();
void WriteCurrentVideoModeToDump(GPUDump::Recorder* dump) const;
void ProcessGPUDumpPacket(GPUDump::PacketType type, const std::span<const u32> data);
/// Returns true if no data is being sent from VRAM to the DAC or that no portion of VRAM would be visible on screen.
ALWAYS_INLINE bool IsDisplayDisabled() const
{
return m_GPUSTAT.display_disable || m_crtc_state.display_vram_width == 0 || m_crtc_state.display_vram_height == 0;
}
/// Returns true if scanout should be interlaced.
ALWAYS_INLINE bool IsInterlacedDisplayEnabled() const
{
return (!m_force_progressive_scan && m_GPUSTAT.vertical_interlace);
}
/// Returns true if scanout is forced to progressive.
ALWAYS_INLINE bool IsProgressiveDisplayScanForced() const
{
return (m_force_progressive_scan && m_GPUSTAT.vertical_interlace);
}
/// Returns true if interlaced rendering is enabled and force progressive scan is disabled.
ALWAYS_INLINE bool IsInterlacedRenderingEnabled() const
{
return (!m_force_progressive_scan && m_GPUSTAT.SkipDrawingToActiveField());
}
/// Returns true if we're in PAL mode, otherwise false if NTSC.
ALWAYS_INLINE bool IsInPALMode() const { return m_GPUSTAT.pal_mode; }
/// Returns the number of pending GPU ticks.
TickCount GetPendingCRTCTicks() const;
TickCount GetPendingCommandTicks() const;
TickCount GetRemainingCommandTicks() const;
/// Returns true if enough ticks have passed for the raster to be on the next line.
bool IsCRTCScanlinePending() const;
/// Returns true if a raster scanline or command execution is pending.
bool IsCommandCompletionPending() const;
/// Synchronizes the CRTC, updating the hblank timer.
void SynchronizeCRTC();
/// Recompile shaders/recreate framebuffers when needed.
void UpdateSettings(const Settings& old_settings);
/// Returns the full display resolution of the GPU, including padding.
std::tuple<u32, u32> GetFullDisplayResolution() const;
/// Computes clamped drawing area.
static GSVector4i GetClampedDrawingArea(const GPUDrawingArea& drawing_area);
float ComputeHorizontalFrequency() const;
float ComputeVerticalFrequency() const;
float ComputePixelAspectRatio() const;
/// Computes aspect ratio correction, i.e. the scale to apply to the source aspect ratio to preserve
/// the original pixel aspect ratio regardless of how much cropping has been applied.
float ComputeAspectRatioCorrection() const;
/// Applies the pixel aspect ratio to a given size, preserving the larger dimension.
static GSVector2 CalculateRenderWindowSize(DisplayFineCropMode mode, std::span<const s16, 4> amount,
float pixel_aspect_ratio, const GSVector2 video_size,
const GSVector2 source_size, const GSVector2 window_size);
// Converts window coordinates into horizontal ticks and scanlines. Returns -1 if out of range. Used for lightguns.
GSVector2 ConvertScreenCoordinatesToDisplayCoordinates(GSVector2 window_pos) const;
bool ConvertDisplayCoordinatesToBeamTicksAndLines(const GSVector2& display_pos, float x_scale, u32* out_tick,
u32* out_line) const;
// Returns the current beam position.
void GetBeamPosition(u32* out_ticks, u32* out_line);
// Returns the number of system clock ticks until the specified tick/line.
TickCount GetSystemTicksUntilTicksAndLine(u32 ticks, u32 line);
// Returns the number of visible lines.
ALWAYS_INLINE u16 GetCRTCActiveStartLine() const { return m_crtc_state.vertical_display_start; }
ALWAYS_INLINE u16 GetCRTCActiveEndLine() const { return m_crtc_state.vertical_display_end; }
// Returns the video clock frequency.
TickCount GetCRTCFrequency() const;
// Video output access.
GSVector2i GetCRTCVideoSize() const;
GSVector4i GetCRTCVideoActiveRect() const;
GSVector4i GetCRTCVRAMSourceRect() const;
// Ticks for hblank/vblank.
void CRTCTickEvent(TickCount ticks);
void CommandTickEvent(TickCount ticks);
void FrameDoneEvent(TickCount ticks);
// Dumps raw VRAM to a file.
bool DumpVRAMToFile(std::string path, Error* error);
// Kicks the current frame to the backend for display.
void UpdateDisplay(bool submit_frame);
// Queues the current frame for presentation. Should only be used with runahead.
void QueuePresentCurrentFrame();
namespace GPU {
/// The maximum resolution scale factor that can be applied to rendering.
inline constexpr u32 MAX_RESOLUTION_SCALE = 32;
void Initialize();
void Shutdown();
void Reset(bool clear_vram);
bool DoState(StateWrapper& sw);
void DoMemoryState(StateWrapper& sw, System::MemorySaveState& mss);
// Render statistics debug window.
void DrawDebugStateWindow(float scale);
void CPUClockChanged();
// MMIO access
u32 ReadRegister(u32 offset);
void WriteRegister(u32 offset, u32 value);
// DMA access
void DMARead(u32* words, u32 word_count);
bool BeginDMAWrite();
void DMAWrite(u32 address, u32 value);
void EndDMAWrite();
/// Writing to GPU dump.
GPUDump::Recorder* GetGPUDump();
bool StartRecordingGPUDump(const char* path, u32 num_frames = 1);
void StopRecordingGPUDump();
void WriteCurrentVideoModeToDump(GPUDump::Recorder* dump);
void ProcessGPUDumpPacket(GPUDump::PacketType type, const std::span<const u32> data);
/// Returns true if scanout should be interlaced.
bool IsInterlacedDisplayEnabled();
/// Returns true if scanout is forced to progressive.
bool IsProgressiveDisplayScanForced();
/// Returns true if we're in PAL mode, otherwise false if NTSC.
bool IsInPALMode();
/// Returns true if enough ticks have passed for the raster to be on the next line.
bool IsCRTCScanlinePending();
/// Synchronizes the CRTC, updating the hblank timer.
void SynchronizeCRTC();
/// Recompile shaders/recreate framebuffers when needed.
void UpdateSettings(const Settings& old_settings);
/// Returns the full display resolution of the GPU, including padding.
std::pair<u32, u32> GetFullDisplayResolution();
/// Computes clamped drawing area.
GSVector4i GetClampedDrawingArea(const GPUDrawingArea& drawing_area);
/// Computes the pixel aspect ratio based on the current display mode and settings.
float ComputePixelAspectRatio();
/// Computes aspect ratio correction, i.e. the scale to apply to the source aspect ratio to preserve
/// the original pixel aspect ratio regardless of how much cropping has been applied.
float ComputeAspectRatioCorrection();
/// Applies the pixel aspect ratio to a given size, preserving the larger dimension.
GSVector2 CalculateRenderWindowSize(DisplayFineCropMode mode, std::span<const s16, 4> amount, float pixel_aspect_ratio,
const GSVector2 video_size, const GSVector2 source_size,
const GSVector2 window_size);
// Converts window coordinates into horizontal ticks and scanlines. Returns -1 if out of range. Used for lightguns.
GSVector2 ConvertScreenCoordinatesToDisplayCoordinates(GSVector2 window_pos);
bool ConvertDisplayCoordinatesToBeamTicksAndLines(const GSVector2& display_pos, float x_scale, u32* out_tick,
u32* out_line);
// Returns the current beam position.
void GetBeamPosition(u32* out_ticks, u32* out_line);
// Returns the number of system clock ticks until the specified tick/line.
TickCount GetSystemTicksUntilTicksAndLine(u32 ticks, u32 line);
// Returns the number of visible lines.
u16 GetCRTCActiveStartLine();
u16 GetCRTCActiveEndLine();
// Returns the video clock frequency.
TickCount GetCRTCFrequency();
// Video output access.
GSVector2i GetCRTCVideoSize();
GSVector4i GetCRTCVideoActiveRect();
GSVector4i GetCRTCVRAMSourceRect();
// Dumps raw VRAM to a file.
bool DumpVRAMToFile(std::string path, Error* error);
// Kicks the current frame to the backend for display.
void UpdateDisplay(bool submit_frame);
/// Computes the effective resolution scale when it is set to automatic.
u8 CalculateAutomaticResolutionScale() const;
/// Helper function for computing the draw rectangle in a larger window.
static void CalculateDrawRect(const GSVector2i& window_size, const GSVector2i& video_size,
const GSVector4i& video_active_rect, const GSVector4i& source_rect,
DisplayRotation rotation, DisplayAlignment alignment, float pixel_aspect_ratio,
bool integer_scale, DisplayFineCropMode fine_crop,
const std::span<const s16, 4>& fine_crop_amount, GSVector4i* out_source_rect,
GSVector4i* out_display_rect, GSVector4i* out_draw_rect,
GSVector4* out_crop_amount = nullptr);
// Queues the current frame for presentation. Should only be used with runahead.
void QueuePresentCurrentFrame();
private:
TickCount CRTCTicksToSystemTicks(TickCount crtc_ticks, TickCount fractional_ticks) const;
TickCount SystemTicksToCRTCTicks(TickCount sysclk_ticks, TickCount* fractional_ticks) const;
/// Computes the effective resolution scale when it is set to automatic.
u8 CalculateAutomaticResolutionScale();
// The GPU internally appears to run at 2x the system clock.
ALWAYS_INLINE static constexpr TickCount GPUTicksToSystemTicks(TickCount gpu_ticks)
{
return std::max<TickCount>((gpu_ticks + 1) >> 1, 1);
}
ALWAYS_INLINE static constexpr TickCount SystemTicksToGPUTicks(TickCount sysclk_ticks) { return sysclk_ticks << 1; }
/// Helper function for computing the draw rectangle in a larger window.
void CalculateDrawRect(const GSVector2i& window_size, const GSVector2i& video_size, const GSVector4i& video_active_rect,
const GSVector4i& source_rect, DisplayRotation rotation, DisplayAlignment alignment,
float pixel_aspect_ratio, bool integer_scale, DisplayFineCropMode fine_crop,
const std::span<const s16, 4>& fine_crop_amount, GSVector4i* out_source_rect,
GSVector4i* out_display_rect, GSVector4i* out_draw_rect, GSVector4* out_crop_amount = nullptr);
}; // namespace GPU
static bool DumpVRAMToFile(std::string path, u32 width, u32 height, u32 stride, const void* buffer, bool remove_alpha,
Error* error = nullptr);
void SoftReset();
void ClearDisplay();
// Sets dots per scanline
void UpdateCRTCConfig();
void UpdateCRTCDisplayParameters();
// Update ticks for this execution slice
void UpdateCRTCTickEvent();
void UpdateCommandTickEvent();
u8 UpdateOrGetGPUBusyPct();
// Updates dynamic bits in GPUSTAT (ready to send VRAM/ready to receive DMA)
void UpdateDMARequest();
void UpdateGPUIdle();
/// Updates drawing area that's suitable for clamping.
void SetClampedDrawingArea();
/// Sets/decodes GP0(E1h) (set draw mode).
void SetDrawMode(u16 bits);
/// Sets/decodes polygon/rectangle texture palette value.
void SetTexturePalette(u16 bits);
/// Sets/decodes texture window bits.
void SetTextureWindow(u32 value);
u32 ReadGPUREAD();
void FinishVRAMWrite();
/// Returns the number of vertices in the buffered poly-line.
u32 GetPolyLineVertexCount() const;
void AddCommandTicks(TickCount ticks);
void WriteGP1(u32 value);
void EndCommand();
void ExecuteCommands();
void TryExecuteCommands();
void HandleGetGPUInfoCommand(u32 value);
void UpdateCLUTIfNeeded(GPUTextureMode texmode, GPUTexturePaletteReg clut);
void InvalidateCLUT();
bool IsCLUTValid() const;
void ReadVRAM(u16 x, u16 y, u16 width, u16 height);
void UpdateVRAM(u16 x, u16 y, u16 width, u16 height, const void* data, bool set_mask, bool check_mask);
void PrepareForDraw();
void FinishPolyline();
void FillDrawCommand(GPUBackendDrawCommand* RESTRICT cmd, GPURenderCommand rc) const;
void AddDrawTriangleTicks(GSVector2i v1, GSVector2i v2, GSVector2i v3, bool shaded, bool textured,
bool semitransparent);
void AddDrawRectangleTicks(const GSVector4i rect, bool textured, bool semitransparent);
void AddDrawLineTicks(const GSVector4i rect, bool shaded);
GPUSTAT m_GPUSTAT = {};
bool m_console_is_pal = false;
bool m_set_texture_disable_mask = false;
bool m_drawing_area_changed = false;
bool m_force_progressive_scan = false;
struct DrawMode
{
static constexpr u16 PALETTE_MASK = UINT16_C(0b0111111111111111);
static constexpr u32 TEXTURE_WINDOW_MASK = UINT32_C(0b11111111111111111111);
// original values
GPUDrawModeReg mode_reg;
GPUTexturePaletteReg palette_reg; // from vertex
u32 texture_window_value;
// decoded values
// TODO: Make this a command
GPUTextureWindow texture_window;
bool texture_x_flip;
bool texture_y_flip;
} m_draw_mode = {};
GPUDrawingArea m_drawing_area = {};
GPUDrawingOffset m_drawing_offset = {};
GSVector4i m_clamped_drawing_area = {};
struct CRTCState
{
struct Regs
{
static constexpr u32 DISPLAY_ADDRESS_START_MASK = 0b111'11111111'11111110;
static constexpr u32 HORIZONTAL_DISPLAY_RANGE_MASK = 0b11111111'11111111'11111111;
static constexpr u32 VERTICAL_DISPLAY_RANGE_MASK = 0b1111'11111111'11111111;
union
{
u32 display_address_start;
BitField<u32, u16, 0, 10> X;
BitField<u32, u16, 10, 9> Y;
};
union
{
u32 horizontal_display_range;
BitField<u32, u16, 0, 12> X1;
BitField<u32, u16, 12, 12> X2;
};
union
{
u32 vertical_display_range;
BitField<u32, u16, 0, 10> Y1;
BitField<u32, u16, 10, 10> Y2;
};
} regs;
u16 dot_clock_divider;
// Size of the simulated screen in pixels. Depending on crop mode, this may include overscan area.
u16 display_width;
u16 display_height;
// Top-left corner in screen coordinates where the outputted portion of VRAM is first visible.
u16 display_origin_left;
u16 display_origin_top;
// Rectangle in VRAM coordinates describing the area of VRAM that is visible on screen.
u16 display_vram_left;
u16 display_vram_top;
u16 display_vram_width;
u16 display_vram_height;
// Visible range of the screen, in GPU ticks/lines. Clamped to lie within the active video region.
u16 horizontal_visible_start;
u16 horizontal_visible_end;
u16 vertical_visible_start;
u16 vertical_visible_end;
u16 horizontal_display_start;
u16 horizontal_display_end;
u16 vertical_display_start;
u16 vertical_display_end;
u16 horizontal_active_start;
u16 horizontal_active_end;
u16 horizontal_total;
u16 vertical_total;
u16 current_scanline;
TickCount fractional_ticks;
TickCount current_tick_in_scanline;
TickCount fractional_dot_ticks; // only used when timer0 is enabled
bool in_hblank;
bool in_vblank;
/// 0 if the currently-displayed field is on odd lines (1,3,5,...) or 1 if even (2,4,6,...)
u8 interlaced_field;
u8 interlaced_display_field;
/// 0 if the currently-displayed field is on an even line in VRAM, otherwise 1.
u8 active_line_lsb;
ALWAYS_INLINE void UpdateHBlankFlag()
{
in_hblank =
(current_tick_in_scanline < horizontal_active_start || current_tick_in_scanline >= horizontal_active_end);
}
} m_crtc_state = {};
u32 m_command_total_words = 0;
TickCount m_pending_command_ticks = 0;
u32 m_active_ticks_since_last_update = 0;
/// True if currently executing/syncing.
bool m_executing_commands = false;
BlitterState m_blitter_state = BlitterState::Idle;
struct VRAMTransfer
{
u16 x;
u16 y;
u16 width;
u16 height;
u16 col;
u16 row;
} m_vram_transfer = {};
// One byte free, store the GPU usage here.
u8 m_last_gpu_busy_pct = 0;
// These are the bits from the palette register, but zero extended to 32-bit, so we can have an "invalid" value.
// If an extra byte is ever not needed here for padding, the 8-bit flag could be packed into the MSB of this value.
bool m_current_clut_is_8bit = false;
u32 m_current_clut_reg_bits = {};
/// GPUREAD value for non-VRAM-reads.
u32 m_GPUREAD_latch = 0;
std::unique_ptr<GPUDump::Recorder> m_gpu_dump;
HeapFIFOQueue<u64, MAX_FIFO_SIZE> m_fifo;
TickCount m_max_run_ahead = 128;
u32 m_fifo_size = 128;
u32 m_blit_remaining_words;
GPURenderCommand m_render_command{};
std::vector<u32> m_blit_buffer;
std::vector<u64> m_polyline_buffer;
ALWAYS_INLINE u32 FifoPop() { return Truncate32(m_fifo.Pop()); }
ALWAYS_INLINE u32 FifoPeek() { return Truncate32(m_fifo.Peek()); }
ALWAYS_INLINE u32 FifoPeek(u32 i) { return Truncate32(m_fifo.Peek(i)); }
private:
using GP0CommandHandler = bool (GPU::*)();
using GP0CommandHandlerTable = std::array<GP0CommandHandler, 256>;
static GP0CommandHandlerTable GenerateGP0CommandHandlerTable();
// Rendering commands, returns false if not enough data is provided
bool HandleUnknownGP0Command();
bool HandleNOPCommand();
bool HandleClearCacheCommand();
bool HandleInterruptRequestCommand();
bool HandleSetDrawModeCommand();
bool HandleSetTextureWindowCommand();
bool HandleSetDrawingAreaTopLeftCommand();
bool HandleSetDrawingAreaBottomRightCommand();
bool HandleSetDrawingOffsetCommand();
bool HandleSetMaskBitCommand();
bool HandleRenderPolygonCommand();
bool HandleRenderRectangleCommand();
bool HandleRenderLineCommand();
bool HandleRenderPolyLineCommand();
bool HandleFillRectangleCommand();
bool HandleCopyRectangleCPUToVRAMCommand();
bool HandleCopyRectangleVRAMToCPUCommand();
bool HandleCopyRectangleVRAMToVRAMCommand();
static const GP0CommandHandlerTable s_GP0_command_handler_table;
};
extern GPU g_gpu;
extern u16 g_vram[VRAM_SIZE / sizeof(u16)];
extern u16 g_gpu_clut[GPU_CLUT_SIZE];

@ -76,7 +76,7 @@ std::unique_ptr<GPUDump::Recorder> GPUDump::Recorder::Create(std::string path, s
ret = std::unique_ptr<Recorder>(new Recorder(std::move(fp), num_frames, std::move(path)));
ret->WriteHeaders(serial);
g_gpu.WriteCurrentVideoModeToDump(ret.get());
GPU::WriteCurrentVideoModeToDump(ret.get());
ret->WriteCurrentVRAM();
// Write start of stream.
@ -285,7 +285,7 @@ void GPUDump::Recorder::WriteHeaders(std::string_view serial)
// Write textual video mode.
BeginPacket(PacketType::TextualVideoFormat);
WriteString(g_gpu.IsInPALMode() ? "PAL" : "NTSC");
WriteString(GPU::IsInPALMode() ? "PAL" : "NTSC");
EndPacket();
// Write DuckStation version.
@ -520,7 +520,7 @@ void GPUDump::Player::ProcessPacket(const PacketRef& pkt)
if (pkt.type <= PacketType::VSyncEvent)
{
// gp0/gp1/vsync => direct to gpu
g_gpu.ProcessGPUDumpPacket(pkt.type, pkt.data);
GPU::ProcessGPUDumpPacket(pkt.type, pkt.data);
return;
}
}

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
// SPDX-FileCopyrightText: 2019-2026 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
#include "gpu_sw_rasterizer.h"
@ -7,6 +7,7 @@
#include "cpuinfo.h"
#include "common/assert.h"
#include "common/gsvector.h"
#include "common/log.h"
#include "common/string_util.h"

@ -167,7 +167,7 @@ union GP1SetDisplayMode
BitField<u32, bool, 7, 1> reverse_flag;
};
union GPUSTAT
union GPUSTATReg
{
// During transfer/render operations, if ((dst_pixel & mask_and) == 0) { pixel = src_pixel | mask_or }

@ -208,13 +208,13 @@ void GunCon::UpdatePosition()
{
const auto& [window_x, window_y] = (m_has_relative_binds) ? GetAbsolutePositionFromRelativeAxes() :
InputManager::GetPointerAbsolutePosition(m_cursor_index);
const GSVector2 display_pos = g_gpu.ConvertScreenCoordinatesToDisplayCoordinates(GSVector2(window_x, window_y));
const GSVector2 display_pos = GPU::ConvertScreenCoordinatesToDisplayCoordinates(GSVector2(window_x, window_y));
// are we within the active display area?
u32 tick, line;
s32 offset_tick, offset_line;
if ((display_pos < GSVector2::zero()).anytrue() ||
!g_gpu.ConvertDisplayCoordinatesToBeamTicksAndLines(display_pos, m_x_scale, &tick, &line) ||
!GPU::ConvertDisplayCoordinatesToBeamTicksAndLines(display_pos, m_x_scale, &tick, &line) ||
(offset_tick = static_cast<s32>(tick) + m_tick_offset) < 0 ||
(offset_line = static_cast<s32>(line) + m_line_offset) < 0 || m_shoot_offscreen)
{
@ -225,7 +225,7 @@ void GunCon::UpdatePosition()
}
// 8MHz units for X = 44100*768*11/7 = 53222400 / 8000000 = 6.6528
const double divider = static_cast<double>(g_gpu.GetCRTCFrequency()) / 8000000.0;
const double divider = static_cast<double>(GPU::GetCRTCFrequency()) / 8000000.0;
m_position_x = static_cast<u16>(static_cast<float>(offset_tick) / static_cast<float>(divider));
m_position_y = static_cast<u16>(offset_line);
DEV_LOG("Lightgun window coordinates {} -> tick {} line {} 8mhz ticks {}", display_pos, offset_tick, offset_line,

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
// SPDX-FileCopyrightText: 2019-2026 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
#include "imgui_overlays.h"
@ -29,6 +29,7 @@
#include "util/media_capture.h"
#include "util/translation.h"
#include "common/assert.h"
#include "common/align.h"
#include "common/error.h"
#include "common/file_system.h"
@ -118,7 +119,7 @@ static constexpr const std::array<DebugWindowInfo, NUM_DEBUG_WINDOWS> s_debug_wi
{"Freecam", "Free Camera", ":icons/applications-system.png", &GTE::DrawFreecamWindow, 510, 500},
{"SPU", "SPU State", ":icons/applications-system.png", &SPU::DrawDebugStateWindow, 820, 950},
{"CDROM", "CD-ROM State", ":icons/applications-system.png", &CDROM::DrawDebugWindow, 820, 555},
{"GPU", "GPU State", ":icons/applications-system.png", [](float sc) { g_gpu.DrawDebugStateWindow(sc); }, 450, 550},
{"GPU", "GPU State", ":icons/applications-system.png", &GPU::DrawDebugStateWindow, 450, 550},
{"DMA", "DMA State", ":icons/applications-system.png", &DMA::DrawDebugStateWindow, 860, 180},
{"MDEC", "MDEC State", ":icons/applications-system.png", &MDEC::DrawDebugStateWindow, 300, 350},
{"Timers", "Timers State", ":icons/applications-system.png", &Timers::DrawDebugStateWindow, 800, 95},
@ -443,10 +444,10 @@ void ImGuiManager::DrawPerformanceOverlay(const GPUBackend* gpu, float& position
{
const u32 resolution_scale = gpu->GetResolutionScale();
const bool pgxp = gpu->IsUsingHardwareBackend() && g_gpu_settings.gpu_pgxp_enable;
const auto [display_width, display_height] = g_gpu.GetFullDisplayResolution(); // NOTE: Racey read.
const bool interlaced = g_gpu.IsInterlacedDisplayEnabled();
const bool progressive_forced = g_gpu.IsProgressiveDisplayScanForced();
const bool pal = g_gpu.IsInPALMode();
const auto [display_width, display_height] = GPU::GetFullDisplayResolution(); // NOTE: Racey read.
const bool interlaced = GPU::IsInterlacedDisplayEnabled();
const bool progressive_forced = GPU::IsProgressiveDisplayScanForced();
const bool pal = GPU::IsInPALMode();
text.format("{}x{} " BOLD("{} {}") " | {}x " BOLD("IR") "{}", display_width * resolution_scale,
display_height * resolution_scale, pal ? "PAL" : "NTSC",
interlaced ? "Interlaced" : (progressive_forced ? "Forced-Progressive" : "Progressive"),

@ -219,12 +219,12 @@ void Justifier::UpdatePosition()
const auto [window_x, window_y] = (m_has_relative_binds) ? GetAbsolutePositionFromRelativeAxes() :
InputManager::GetPointerAbsolutePosition(m_cursor_index);
const GSVector2 display_pos = g_gpu.ConvertScreenCoordinatesToDisplayCoordinates(GSVector2(window_x, window_y));
const GSVector2 display_pos = GPU::ConvertScreenCoordinatesToDisplayCoordinates(GSVector2(window_x, window_y));
// are we within the active display area?
u32 tick, line;
if ((display_pos < GSVector2::zero()).anytrue() ||
!g_gpu.ConvertDisplayCoordinatesToBeamTicksAndLines(display_pos, m_x_scale, &tick, &line) || m_shoot_offscreen)
!GPU::ConvertDisplayCoordinatesToBeamTicksAndLines(display_pos, m_x_scale, &tick, &line) || m_shoot_offscreen)
{
DEV_LOG("Lightgun out of range for window coordinates {:.0f},{:.0f}", window_x, window_y);
m_position_valid = false;
@ -237,11 +237,11 @@ void Justifier::UpdatePosition()
m_irq_tick = static_cast<u16>(static_cast<TickCount>(tick) +
System::ScaleTicksToOverclock(static_cast<TickCount>(m_tick_offset)));
m_irq_first_line = static_cast<u16>(std::clamp<s32>(static_cast<s32>(line) + m_first_line_offset,
static_cast<s32>(g_gpu.GetCRTCActiveStartLine()),
static_cast<s32>(g_gpu.GetCRTCActiveEndLine())));
static_cast<s32>(GPU::GetCRTCActiveStartLine()),
static_cast<s32>(GPU::GetCRTCActiveEndLine())));
m_irq_last_line = static_cast<u16>(std::clamp<s32>(static_cast<s32>(line) + m_last_line_offset,
static_cast<s32>(g_gpu.GetCRTCActiveStartLine()),
static_cast<s32>(g_gpu.GetCRTCActiveEndLine())));
static_cast<s32>(GPU::GetCRTCActiveStartLine()),
static_cast<s32>(GPU::GetCRTCActiveEndLine())));
DEV_LOG("Lightgun window coordinates {},{} -> dpy {} -> tick {} line {} [{}-{}]", window_x, window_y, display_pos,
tick, line, m_irq_first_line, m_irq_last_line);
@ -258,7 +258,7 @@ void Justifier::UpdateIRQEvent()
return;
u32 current_tick, current_line;
g_gpu.GetBeamPosition(&current_tick, &current_line);
GPU::GetBeamPosition(&current_tick, &current_line);
u32 target_line;
if (current_line < m_irq_first_line || current_line >= m_irq_last_line)
@ -266,7 +266,7 @@ void Justifier::UpdateIRQEvent()
else
target_line = current_line + 1;
const TickCount ticks_until_pos = g_gpu.GetSystemTicksUntilTicksAndLine(m_irq_tick, target_line);
const TickCount ticks_until_pos = GPU::GetSystemTicksUntilTicksAndLine(m_irq_tick, target_line);
DEBUG_LOG("Triggering IRQ in {} ticks @ tick {} line {}", ticks_until_pos, m_irq_tick, target_line);
m_irq_event.Schedule(ticks_until_pos);
}

@ -10,6 +10,7 @@
#include "util/media_capture.h"
#include "common/assert.h"
#include "common/log.h"
#include "common/threading.h"
#include "common/timer.h"

@ -490,7 +490,7 @@ void System::UpdateOverclock()
s_state.max_slice_ticks = ScaleTicksToOverclock(MASTER_CLOCK / 10);
SPU::CPUClockChanged();
CDROM::CPUClockChanged();
g_gpu.CPUClockChanged();
GPU::CPUClockChanged();
Timers::CPUClocksChanged();
UpdateThrottlePeriod();
}
@ -1009,7 +1009,7 @@ void System::RecreateGPU(GPURenderer renderer)
ClearMemorySaveStates(true, false);
g_gpu.UpdateDisplay(false);
GPU::UpdateDisplay(false);
if (IsPaused())
VideoThread::PresentCurrentFrame();
}
@ -1029,7 +1029,7 @@ void System::LoadSettings(bool display_osd_messages)
// Fix up automatic resolution scale, yuck.
if (g_settings.gpu_automatic_resolution_scale && IsValid())
g_settings.gpu_resolution_scale = g_gpu.CalculateAutomaticResolutionScale();
g_settings.gpu_resolution_scale = GPU::CalculateAutomaticResolutionScale();
// show safe mode warning if it's toggled on, or on startup
if (IsValidOrInitializing() && (display_osd_messages || (!previous_safe_mode && g_settings.disable_all_enhancements)))
@ -1807,8 +1807,7 @@ bool System::Initialize(std::unique_ptr<CDImage> disc, DiscRegion disc_region, b
return false;
}
// TODO: Drop class
g_gpu.Initialize();
GPU::Initialize();
// Game info must be set prior to backend creation because of texture replacements.
// We don't do it in UpdateRunningGame() when booting because it can fail in a number of locations.
@ -1889,7 +1888,7 @@ void System::DestroySystem()
Timers::Shutdown();
Pad::Shutdown();
CDROM::Shutdown();
g_gpu.Shutdown();
GPU::Shutdown();
DMA::Shutdown();
PIO::Shutdown();
CPU::CodeCache::Shutdown();
@ -2049,7 +2048,7 @@ void System::FrameDone()
}
// Late submission of frame. This is needed because the input poll can determine whether we need to rewind.
g_gpu.QueuePresentCurrentFrame();
GPU::QueuePresentCurrentFrame();
SaveMemoryState(AllocateMemoryState());
}
@ -2350,7 +2349,7 @@ bool System::DoState(StateWrapper& sw, bool update_display)
if (!sw.DoMarker("InterruptController") || !InterruptController::DoState(sw))
return false;
if (!sw.DoMarker("GPU") || !g_gpu.DoState(sw))
if (!sw.DoMarker("GPU") || !GPU::DoState(sw))
return false;
if (!sw.DoMarker("CDROM") || !CDROM::DoState(sw))
@ -2415,7 +2414,7 @@ bool System::DoState(StateWrapper& sw, bool update_display)
// If we're paused, need to update the display FB.
if (update_display)
g_gpu.UpdateDisplay(false);
GPU::UpdateDisplay(false);
return true;
}
@ -2627,7 +2626,7 @@ void System::DoMemoryState(StateWrapper& sw, MemorySaveState& mss, bool update_d
SAVE_COMPONENT("DMA", DMA::DoState(sw));
SAVE_COMPONENT("InterruptController", InterruptController::DoState(sw));
g_gpu.DoMemoryState(sw, mss);
GPU::DoMemoryState(sw, mss);
SAVE_COMPONENT("CDROM", CDROM::DoState(sw));
SAVE_COMPONENT("Pad", Pad::DoState(sw, true));
@ -2641,7 +2640,7 @@ void System::DoMemoryState(StateWrapper& sw, MemorySaveState& mss, bool update_d
#undef SAVE_COMPONENT
if (update_display)
g_gpu.UpdateDisplay(false);
GPU::UpdateDisplay(false);
}
bool System::LoadBIOS(Error* error)
@ -2679,7 +2678,7 @@ void System::InternalReset()
PIO::Reset();
DMA::Reset();
InterruptController::Reset();
g_gpu.Reset(true);
GPU::Reset(true);
CDROM::Reset();
Pad::Reset();
Timers::Reset();
@ -2893,7 +2892,7 @@ bool System::LoadStateFromBuffer(const SaveStateBuffer& buffer, Error* error, bo
ResetThrottler();
if (update_display)
g_gpu.UpdateDisplay(true);
GPU::UpdateDisplay(true);
return true;
}
@ -3952,7 +3951,7 @@ bool System::DumpVRAM(std::string path, Error* error)
return false;
}
return g_gpu.DumpVRAMToFile(path, error);
return GPU::DumpVRAMToFile(path, error);
}
bool System::DumpSPURAM(std::string path, Error* error)
@ -4467,7 +4466,7 @@ void System::CheckForSettingsChanges(const Settings& old_settings)
g_settings.display_line_start_offset != old_settings.display_line_start_offset ||
g_settings.display_line_end_offset != old_settings.display_line_end_offset)
{
g_gpu.UpdateSettings(old_settings);
GPU::UpdateSettings(old_settings);
}
if (g_settings.gpu_renderer != old_settings.gpu_renderer)
@ -4542,7 +4541,7 @@ void System::CheckForSettingsChanges(const Settings& old_settings)
if (IsPaused())
{
// resolution change needs display updated
g_gpu.UpdateDisplay(false);
GPU::UpdateDisplay(false);
VideoThread::PresentCurrentFrame();
}
}
@ -4593,7 +4592,7 @@ void System::CheckForSettingsChanges(const Settings& old_settings)
if (IsPaused())
{
// and display the current frame on the new device
g_gpu.UpdateDisplay(false);
GPU::UpdateDisplay(false);
VideoThread::PresentCurrentFrame();
}
}
@ -5458,7 +5457,7 @@ bool System::StartRecordingGPUDump(const char* path /*= nullptr*/, u32 num_frame
.c_str();
}
return g_gpu.StartRecordingGPUDump(path, num_frames);
return GPU::StartRecordingGPUDump(path, num_frames);
}
void System::StopRecordingGPUDump()
@ -5466,7 +5465,7 @@ void System::StopRecordingGPUDump()
if (!IsValid())
return;
g_gpu.StopRecordingGPUDump();
GPU::StopRecordingGPUDump();
}
static std::string_view GetCaptureTypeForMessage(bool capture_video, bool capture_audio)
@ -6029,8 +6028,8 @@ void System::RequestDisplaySize(float scale /*= 0.0f*/)
{
const WindowInfo& wi = VideoThread::GetRenderWindowInfo();
requested_size = GPU::CalculateRenderWindowSize(
g_settings.display_fine_crop_mode, g_settings.display_fine_crop_amount, g_gpu.ComputePixelAspectRatio(),
GSVector2(g_gpu.GetCRTCVideoSize()), GSVector2(g_gpu.GetCRTCVRAMSourceRect().rsize()) * scale,
g_settings.display_fine_crop_mode, g_settings.display_fine_crop_amount, GPU::ComputePixelAspectRatio(),
GSVector2(GPU::GetCRTCVideoSize()), GSVector2(GPU::GetCRTCVRAMSourceRect().rsize()) * scale,
GSVector2(GSVector2i(wi.surface_width, wi.surface_height)));
}
@ -6078,7 +6077,7 @@ void System::UpdateGTEAspectRatio()
{
// Pre-apply the native aspect ratio correction to the window size.
// MatchWindow does not correct the display aspect ratio, so we need to apply it here.
const float correction = g_gpu.ComputeAspectRatioCorrection();
const float correction = GPU::ComputeAspectRatioCorrection();
custom_num =
static_cast<u32>(std::max(std::round(static_cast<float>(main_window_info.surface_width) / correction), 1.0f));
custom_denom = std::max<u32>(main_window_info.surface_height, 1u);
@ -6099,7 +6098,7 @@ void System::UpdateAutomaticResolutionScale()
if (!IsValidOrInitializing() || !g_settings.gpu_automatic_resolution_scale)
return;
const u32 new_scale = g_gpu.CalculateAutomaticResolutionScale();
const u32 new_scale = GPU::CalculateAutomaticResolutionScale();
if (g_settings.gpu_resolution_scale == new_scale)
return;
@ -6111,7 +6110,7 @@ void System::UpdateAutomaticResolutionScale()
if (IsPaused())
{
// resolution change needs display updated
g_gpu.UpdateDisplay(false);
GPU::UpdateDisplay(false);
VideoThread::PresentCurrentFrame();
}
}

@ -315,8 +315,8 @@ u32 Timers::ReadRegister(u32 offset)
if (timer_index < 2 && cs.external_counting_enabled)
{
// timers 0/1 depend on the GPU
if (timer_index == 0 || g_gpu.IsCRTCScanlinePending())
g_gpu.SynchronizeCRTC();
if (timer_index == 0 || GPU::IsCRTCScanlinePending())
GPU::SynchronizeCRTC();
}
s_state.sysclk_event.InvokeEarly();
@ -329,8 +329,8 @@ u32 Timers::ReadRegister(u32 offset)
if (timer_index < 2 && cs.external_counting_enabled)
{
// timers 0/1 depend on the GPU
if (timer_index == 0 || g_gpu.IsCRTCScanlinePending())
g_gpu.SynchronizeCRTC();
if (timer_index == 0 || GPU::IsCRTCScanlinePending())
GPU::SynchronizeCRTC();
}
s_state.sysclk_event.InvokeEarly();
@ -365,8 +365,8 @@ void Timers::WriteRegister(u32 offset, u32 value)
if (timer_index < 2 && cs.external_counting_enabled)
{
// timers 0/1 depend on the GPU
if (timer_index == 0 || g_gpu.IsCRTCScanlinePending())
g_gpu.SynchronizeCRTC();
if (timer_index == 0 || GPU::IsCRTCScanlinePending())
GPU::SynchronizeCRTC();
}
s_state.sysclk_event.InvokeEarly();

@ -3103,7 +3103,7 @@ void CoreThread::updatePerformanceCounters(const GPUBackend* gpu_backend)
if (gpu_backend)
{
const u32 render_scale = gpu_backend->GetResolutionScale();
std::tie(render_width, render_height) = g_gpu.GetFullDisplayResolution();
std::tie(render_width, render_height) = GPU::GetFullDisplayResolution();
render_width *= render_scale;
render_height *= render_scale;
}

Loading…
Cancel
Save