refactor: change GS architecture

This commit is contained in:
Ran-j
2026-08-13 09:33:49 -03:00
parent 8b57926df6
commit 3b9b14c618
31 changed files with 4146 additions and 4388 deletions
+4 -4
View File
@@ -377,12 +377,12 @@ endfunction()
add_library(ps2_runtime STATIC
src/lib/game_overrides.cpp
src/lib/ps2_gif_arbiter.cpp
src/lib/gs/ps2_gif_arbiter.cpp
src/lib/ps2_audio.cpp
src/lib/ps2_audio_vag.cpp
src/lib/ps2_gs_gpu.cpp
src/lib/ps2_gs_memory.cpp
src/lib/ps2_gs_rasterizer.cpp
src/lib/gs/ps2_gs_memory.cpp
src/lib/gs/gs_frontend.cpp
src/lib/gs/gs_cpu_backend.cpp
src/lib/ps2_iop_host.cpp
src/lib/ps2_memory.cpp
src/lib/ps2_pad.cpp
+2 -2
View File
@@ -24,9 +24,9 @@
#include "ps2_log.h"
#include "runtime/ps2_address.h"
#include "runtime/ps2_gif_arbiter.h"
#include "runtime/gs/ps2_gif_arbiter.h"
#include "runtime/ps2_memory.h"
#include "runtime/ps2_gs_gpu.h"
#include "runtime/gs/gs_frontend.h"
#include "runtime/ps2_vu1.h"
#include "runtime/ps2_audio.h"
#include "runtime/ps2_pad.h"
@@ -0,0 +1,33 @@
#pragma once
#include "runtime/gs/gs_types.h"
#include <cstdint>
#include <vector>
class GSRasterBackend
{
public:
virtual ~GSRasterBackend() = default;
virtual void Initialize(uint8_t *vram, uint32_t vramSize) = 0;
virtual void Reset() = 0;
virtual void Submit(const GSPrimitiveBatch &batch) = 0;
virtual void BeginTransfer(const GSTransferCommand &command) = 0;
virtual void UploadImage(const uint8_t *data, uint32_t sizeBytes) = 0;
virtual void Flush() = 0;
virtual void TextureFlush() = 0;
virtual void Sync(GSSyncReason reason) = 0;
virtual PresentationFrame Present(const GSPresentationRequest &request) = 0;
virtual bool ClearFramebuffer(const GSContext &context, uint32_t rgba) = 0;
virtual uint32_t ConsumeLocalToHostBytes(uint8_t *dst, uint32_t maxBytes) = 0;
virtual uint32_t ReadVram(uint32_t psm, uint32_t base, uint32_t bw, uint32_t x, uint32_t y) const = 0;
virtual void WriteVram(uint32_t psm, uint32_t base, uint32_t bw, uint32_t x, uint32_t y, uint32_t value) = 0;
virtual void SnapshotVram(std::vector<uint8_t> &out) const = 0;
virtual GSTransferSnapshot GetTransferSnapshot() const = 0;
};
@@ -0,0 +1,75 @@
#pragma once
#include "runtime/gs/gs_backend.h"
#include <array>
#include <functional>
#include <mutex>
#include <vector>
class GSCpuBackend final : public GSRasterBackend
{
public:
GSCpuBackend();
void Initialize(uint8_t *vram, uint32_t vramSize) override;
void Reset() override;
void Submit(const GSPrimitiveBatch &batch) override;
void BeginTransfer(const GSTransferCommand &command) override;
void UploadImage(const uint8_t *data, uint32_t sizeBytes) override;
void Flush() override;
void TextureFlush() override;
void Sync(GSSyncReason reason) override;
PresentationFrame Present(const GSPresentationRequest &request) override;
bool ClearFramebuffer(const GSContext &context, uint32_t rgba) override;
uint32_t ConsumeLocalToHostBytes(uint8_t *dst, uint32_t maxBytes) override;
uint32_t ReadVram(uint32_t psm, uint32_t base, uint32_t bw, uint32_t x, uint32_t y) const override;
void WriteVram(uint32_t psm, uint32_t base, uint32_t bw, uint32_t x, uint32_t y, uint32_t value) override;
void SnapshotVram(std::vector<uint8_t> &out) const override;
GSTransferSnapshot GetTransferSnapshot() const override;
private:
void ResetUnlocked();
uint32_t ReadVramUnlocked(uint32_t psm, uint32_t base, uint32_t bw, uint32_t x, uint32_t y) const;
void WriteVramUnlocked(uint32_t psm, uint32_t base, uint32_t bw, uint32_t x, uint32_t y, uint32_t value);
void DrawPrimitive(const GSPrimitiveBatch &batch);
void DrawSprite(const GSPrimitiveBatch &batch);
void DrawTriangle(const GSPrimitiveBatch &batch);
void DrawLine(const GSPrimitiveBatch &batch);
void WritePixel(const GSDrawState &state, int x, int y, int z, uint8_t r, uint8_t g, uint8_t b, uint8_t a, uint8_t fog);
uint32_t SampleTexture(const GSDrawState &state, float s, float t, float q, uint16_t u, uint16_t v);
uint32_t LookupCLUT(const GSDrawState &state, uint8_t index, uint32_t cbp, uint8_t cpsm, uint8_t csm, uint8_t csa, uint8_t sourcePsm);
void PerformLocalToLocalTransfer();
void PerformLocalToHostTransfer();
PresentationFrame PresentFromLocalMemory(const GSPresentationRequest &request);
bool CopyFrameToHostRgba(const GSFrameReg &frame,
uint32_t width,
uint32_t height,
std::vector<uint8_t> &outPixels,
bool preserveAlpha,
bool useLocalMemoryLayout,
bool frameBaseIsPages,
uint32_t sourceOriginX,
uint32_t sourceOriginY) const;
using WriteVramFunc = std::function<void(uint8_t *, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t)>;
using ReadVramFunc = std::function<uint32_t(uint8_t *, uint32_t, uint32_t, uint32_t, uint32_t)>;
static constexpr size_t kPsmHandlerCount = 1u << 6u;
mutable std::mutex m_mutex;
uint8_t *m_vram = nullptr;
uint32_t m_vramSize = 0;
std::array<ReadVramFunc, kPsmHandlerCount> m_readVramFuncs{};
std::array<WriteVramFunc, kPsmHandlerCount> m_writeVramFuncs{};
GSTransferCommand m_transfer{};
GSTransferSnapshot m_transferState{};
std::vector<uint8_t> m_localToHostBuffer;
size_t m_localToHostReadPos = 0;
};
@@ -1,229 +1,14 @@
#ifndef PS2_GS_GPU_H
#define PS2_GS_GPU_H
#ifndef PS2_GS_FRONTEND_H
#define PS2_GS_FRONTEND_H
#include <array>
#include <cstddef>
#include <functional>
#include <cstdint>
#include <cstring>
#include <memory>
#include <mutex>
#include <vector>
#include "ps2_gs_rasterizer.h"
#include "ps2_gs_memory.h"
enum GSPrimType : uint8_t
{
GS_PRIM_POINT = 0,
GS_PRIM_LINE = 1,
GS_PRIM_LINESTRIP = 2,
GS_PRIM_TRIANGLE = 3,
GS_PRIM_TRISTRIP = 4,
GS_PRIM_TRIFAN = 5,
GS_PRIM_SPRITE = 6,
};
enum GSPsm : uint8_t
{
GS_PSM_CT32 = 0,
GS_PSM_CT24 = 1,
GS_PSM_CT16 = 2,
GS_PSM_CT16S = 10,
GS_PSM_T8 = 19,
GS_PSM_T4 = 20,
GS_PSM_T8H = 27,
GS_PSM_T4HL = 36,
GS_PSM_T4HH = 44,
GS_PSM_Z32 = 48,
GS_PSM_Z24 = 49,
GS_PSM_Z16 = 50,
GS_PSM_Z16S = 58,
};
enum GSGifFormat : uint8_t
{
GIF_FMT_PACKED = 0,
GIF_FMT_REGLIST = 1,
GIF_FMT_IMAGE = 2,
GIF_FMT_DISABLED = 3,
};
enum GSRegId : uint8_t
{
GS_REG_PRIM = 0x00,
GS_REG_RGBAQ = 0x01,
GS_REG_ST = 0x02,
GS_REG_UV = 0x03,
GS_REG_XYZF2 = 0x04,
GS_REG_XYZ2 = 0x05,
GS_REG_TEX0_1 = 0x06,
GS_REG_TEX0_2 = 0x07,
GS_REG_CLAMP_1 = 0x08,
GS_REG_CLAMP_2 = 0x09,
GS_REG_FOG = 0x0A,
GS_REG_XYZF3 = 0x0C,
GS_REG_XYZ3 = 0x0D,
GS_REG_AD = 0x0F,
GS_REG_TEX1_1 = 0x14,
GS_REG_TEX1_2 = 0x15,
GS_REG_TEX2_1 = 0x16,
GS_REG_TEX2_2 = 0x17,
GS_REG_XYOFFSET_1 = 0x18,
GS_REG_XYOFFSET_2 = 0x19,
GS_REG_PRMODECONT = 0x1A,
GS_REG_PRMODE = 0x1B,
GS_REG_TEXCLUT = 0x1C,
GS_REG_SCANMSK = 0x22,
GS_REG_MIPTBP1_1 = 0x34,
GS_REG_MIPTBP1_2 = 0x35,
GS_REG_MIPTBP2_1 = 0x36,
GS_REG_MIPTBP2_2 = 0x37,
GS_REG_TEXA = 0x3B,
GS_REG_FOGCOL = 0x3D,
GS_REG_TEXFLUSH = 0x3F,
GS_REG_SCISSOR_1 = 0x40,
GS_REG_SCISSOR_2 = 0x41,
GS_REG_ALPHA_1 = 0x42,
GS_REG_ALPHA_2 = 0x43,
GS_REG_DIMX = 0x44,
GS_REG_DTHE = 0x45,
GS_REG_COLCLAMP = 0x46,
GS_REG_TEST_1 = 0x47,
GS_REG_TEST_2 = 0x48,
GS_REG_PABE = 0x49,
GS_REG_FBA_1 = 0x4A,
GS_REG_FBA_2 = 0x4B,
GS_REG_FRAME_1 = 0x4C,
GS_REG_FRAME_2 = 0x4D,
GS_REG_ZBUF_1 = 0x4E,
GS_REG_ZBUF_2 = 0x4F,
GS_REG_BITBLTBUF = 0x50,
GS_REG_TRXPOS = 0x51,
GS_REG_TRXREG = 0x52,
GS_REG_TRXDIR = 0x53,
GS_REG_HWREG = 0x54,
GS_REG_SIGNAL = 0x60,
GS_REG_FINISH = 0x61,
GS_REG_LABEL = 0x62,
};
struct GSVertex
{
float x, y;
// double because float isnt accurate enough for values near UINT32_MAX
double z;
uint8_t r, g, b, a;
float q;
float s, t;
uint16_t u, v;
uint8_t fog;
};
struct GSFrameReg
{
uint32_t fbp;
uint32_t fbw;
uint8_t psm;
uint32_t fbmsk;
};
struct GSZbufReg
{
u32 zbp;
u8 psm;
bool zmask;
};
struct GSScissorReg
{
uint16_t x0, x1, y0, y1;
};
struct GSTex0Reg
{
uint32_t tbp0;
uint8_t tbw;
uint8_t psm;
uint8_t tw;
uint8_t th;
uint8_t tcc;
uint8_t tfx;
uint32_t cbp;
uint8_t cpsm;
uint8_t csm;
uint8_t csa;
uint8_t cld;
};
struct GSXYOffsetReg
{
uint16_t ofx;
uint16_t ofy;
};
struct GSTexaReg
{
uint8_t ta0;
bool aem;
uint8_t ta1;
};
struct GSTexClutReg
{
uint8_t cbw;
uint8_t cou;
uint16_t cov;
};
struct GSContext
{
GSFrameReg frame;
GSScissorReg scissor;
GSTex0Reg tex0;
GSXYOffsetReg xyoffset;
GSZbufReg zbuf;
uint64_t tex1;
uint64_t clamp;
uint64_t alpha;
uint64_t test;
uint64_t fba;
};
struct GSPrimReg
{
GSPrimType type;
bool iip;
bool tme;
bool fge;
bool abe;
bool aa1;
bool fst;
bool ctxt;
bool fix;
};
struct GSBitBltBuf
{
uint32_t sbp;
uint8_t sbw;
uint8_t spsm;
uint32_t dbp;
uint8_t dbw;
uint8_t dpsm;
};
struct GSTrxPos
{
uint16_t ssax, ssay;
uint16_t dsax, dsay;
uint8_t dir;
};
struct GSTrxReg
{
uint16_t rrw, rrh;
};
#include "runtime/gs/gs_backend.h"
struct GSDebugSnapshot
{
@@ -231,6 +16,10 @@ struct GSDebugSnapshot
GSPrimReg prim{};
GSTexaReg texa{};
GSTexClutReg texclut{};
uint64_t scanmsk = 0;
uint64_t dimx = 0;
uint64_t dthe = 0;
uint64_t colclamp = 0;
GSBitBltBuf bitbltbuf{};
GSTrxPos trxpos{};
GSTrxReg trxreg{};
@@ -307,18 +96,15 @@ struct GSDebugHistoryEntry
bool usedPreferred = false;
};
class GSRasterizer;
class GS
{
friend class GSRasterizer;
public:
GS();
~GS() = default;
void init(uint8_t *vram, uint32_t vramSize, struct GSRegisters *privRegs = nullptr);
void reset();
void setRasterBackend(std::unique_ptr<GSRasterBackend> backend);
void processGIFPacket(const uint8_t *data, uint32_t sizeBytes);
bool processNativePackedGIFPacket(const uint8_t *data, uint32_t sizeBytes);
@@ -359,8 +145,8 @@ public:
void refreshDisplaySnapshot();
inline void WriteVram(u32 psm, uint32_t base, uint32_t bw, uint32_t x, uint32_t y, uint32_t value);
inline u32 ReadVram(u32 psm, u32 base, u32 bw, u32 x, u32 y) const;
void WriteVram(uint32_t psm, uint32_t base, uint32_t bw, uint32_t x, uint32_t y, uint32_t value);
uint32_t ReadVram(uint32_t psm, uint32_t base, uint32_t bw, uint32_t x, uint32_t y) const;
private:
void snapshotVRAM();
@@ -373,7 +159,6 @@ private:
const uint8_t *data,
uint32_t sizeBytes);
void vertexKick(bool drawing);
void latchHostPresentationFrameUnlocked();
void recordDebugEventUnlocked(GSDebugHistoryEntry entry);
GSDebugHistoryEntry makeDebugEventUnlocked(GSDebugEventKind kind) const;
@@ -385,24 +170,18 @@ private:
void processImageData(const uint8_t *data, uint32_t sizeBytes);
bool tryProcessNativeImageUploadPacket(const uint8_t *data, uint32_t sizeBytes);
void performLocalToLocalTransfer();
void performLocalToHostToBuffer();
bool copyFrameToHostRgbaUnlocked(const GSFrameReg &frame,
uint32_t width,
uint32_t height,
std::vector<uint8_t> &outPixels,
bool preserveAlpha = false,
bool useLocalMemoryLayout = false,
bool frameBaseIsPages = true,
uint32_t sourceOriginX = 0u,
uint32_t sourceOriginY = 0u) const;
GSPrimitiveBatch buildDrawBatch(int vertexCount) const;
void updatePreferredDisplaySourceForDraw(const GSPrimitiveBatch &batch);
GSPresentationRequest buildPresentationRequestUnlocked() const;
GSContext &activeContext();
uint8_t *m_vram = nullptr;
uint32_t m_vramSize = 0;
uint8_t *m_localMemoryStorage = nullptr;
uint32_t m_localMemorySize = 0u;
struct GSRegisters *m_privRegs = nullptr;
mutable std::recursive_mutex m_stateMutex;
mutable std::mutex m_backendLifetimeMutex;
mutable std::mutex m_presentationMutex;
GSContext m_ctx[2];
@@ -419,6 +198,10 @@ private:
bool m_prmodecont = true;
bool m_pabe = false;
uint64_t m_scanmsk = 0;
uint64_t m_dimx = 0;
uint64_t m_dthe = 0;
uint64_t m_colclamp = 0;
GSTexaReg m_texa{0u, false, 0u};
GSTexClutReg m_texclut{0u, 0u, 0u};
@@ -427,13 +210,6 @@ private:
GSTrxReg m_trxreg{};
uint32_t m_trxdir = 3;
struct
{
uint32_t x{ 0 };
uint32_t y{ 0 };
uint32_t total_pixels{ 0 };
uint32_t copied_pixels{ 0 };
} m_transferState;
static constexpr int kMaxVerts = 6;
GSVertex m_vtxQueue[kMaxVerts];
@@ -456,9 +232,6 @@ private:
uint64_t m_nativeImageUploadCount = 0;
uint64_t m_nativePackedGIFPacketCount = 0;
std::vector<uint8_t> m_localToHostBuffer;
size_t m_localToHostReadPos = 0;
static constexpr size_t kDebugHistoryCapacity = 512;
std::array<GSDebugHistoryEntry, kDebugHistoryCapacity> m_debugHistory{};
size_t m_debugHistoryWrite = 0;
@@ -468,24 +241,7 @@ private:
uint64_t m_debugLastVsyncTick = UINT64_MAX;
bool m_debugHistoryPaused = true;
GSRasterizer m_rasterizer;
using WriteVramFunc = std::function<void(u8*, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t)>;
using ReadVramFunc = std::function<u32(u8*, u32, u32, u32, u32)>;
static constexpr size_t kPsmHandlerCount = 1u << 6u;
std::array<ReadVramFunc, kPsmHandlerCount> m_read_vram_funcs{ };
std::array<WriteVramFunc, kPsmHandlerCount> m_write_vram_funcs{ };
std::unique_ptr<GSRasterBackend> m_backend;
};
inline u32 GS::ReadVram(u32 psm, u32 base, u32 bw, u32 x, u32 y) const
{
return m_read_vram_funcs[psm & 0x3F](m_vram, base, bw, x, y);
}
inline void GS::WriteVram(u32 psm, u32 base, u32 bw, u32 x, u32 y, u32 value)
{
m_write_vram_funcs[psm & 0x3F](m_vram, base, bw, x, y, value);
}
#endif
+315
View File
@@ -0,0 +1,315 @@
#pragma once
#include <cstddef>
#include <array>
#include <cstdint>
#include <vector>
enum GSPrimType : uint8_t
{
GS_PRIM_POINT = 0,
GS_PRIM_LINE = 1,
GS_PRIM_LINESTRIP = 2,
GS_PRIM_TRIANGLE = 3,
GS_PRIM_TRISTRIP = 4,
GS_PRIM_TRIFAN = 5,
GS_PRIM_SPRITE = 6,
};
enum GSPsm : uint8_t
{
GS_PSM_CT32 = 0,
GS_PSM_CT24 = 1,
GS_PSM_CT16 = 2,
GS_PSM_CT16S = 10,
GS_PSM_T8 = 19,
GS_PSM_T4 = 20,
GS_PSM_T8H = 27,
GS_PSM_T4HL = 36,
GS_PSM_T4HH = 44,
GS_PSM_Z32 = 48,
GS_PSM_Z24 = 49,
GS_PSM_Z16 = 50,
GS_PSM_Z16S = 58,
};
enum GSGifFormat : uint8_t
{
GIF_FMT_PACKED = 0,
GIF_FMT_REGLIST = 1,
GIF_FMT_IMAGE = 2,
GIF_FMT_DISABLED = 3,
};
enum GSRegId : uint8_t
{
GS_REG_PRIM = 0x00,
GS_REG_RGBAQ = 0x01,
GS_REG_ST = 0x02,
GS_REG_UV = 0x03,
GS_REG_XYZF2 = 0x04,
GS_REG_XYZ2 = 0x05,
GS_REG_TEX0_1 = 0x06,
GS_REG_TEX0_2 = 0x07,
GS_REG_CLAMP_1 = 0x08,
GS_REG_CLAMP_2 = 0x09,
GS_REG_FOG = 0x0A,
GS_REG_XYZF3 = 0x0C,
GS_REG_XYZ3 = 0x0D,
GS_REG_AD = 0x0F,
GS_REG_TEX1_1 = 0x14,
GS_REG_TEX1_2 = 0x15,
GS_REG_TEX2_1 = 0x16,
GS_REG_TEX2_2 = 0x17,
GS_REG_XYOFFSET_1 = 0x18,
GS_REG_XYOFFSET_2 = 0x19,
GS_REG_PRMODECONT = 0x1A,
GS_REG_PRMODE = 0x1B,
GS_REG_TEXCLUT = 0x1C,
GS_REG_SCANMSK = 0x22,
GS_REG_MIPTBP1_1 = 0x34,
GS_REG_MIPTBP1_2 = 0x35,
GS_REG_MIPTBP2_1 = 0x36,
GS_REG_MIPTBP2_2 = 0x37,
GS_REG_TEXA = 0x3B,
GS_REG_FOGCOL = 0x3D,
GS_REG_TEXFLUSH = 0x3F,
GS_REG_SCISSOR_1 = 0x40,
GS_REG_SCISSOR_2 = 0x41,
GS_REG_ALPHA_1 = 0x42,
GS_REG_ALPHA_2 = 0x43,
GS_REG_DIMX = 0x44,
GS_REG_DTHE = 0x45,
GS_REG_COLCLAMP = 0x46,
GS_REG_TEST_1 = 0x47,
GS_REG_TEST_2 = 0x48,
GS_REG_PABE = 0x49,
GS_REG_FBA_1 = 0x4A,
GS_REG_FBA_2 = 0x4B,
GS_REG_FRAME_1 = 0x4C,
GS_REG_FRAME_2 = 0x4D,
GS_REG_ZBUF_1 = 0x4E,
GS_REG_ZBUF_2 = 0x4F,
GS_REG_BITBLTBUF = 0x50,
GS_REG_TRXPOS = 0x51,
GS_REG_TRXREG = 0x52,
GS_REG_TRXDIR = 0x53,
GS_REG_HWREG = 0x54,
GS_REG_SIGNAL = 0x60,
GS_REG_FINISH = 0x61,
GS_REG_LABEL = 0x62,
};
struct GSVertex
{
float x = 0.0f;
float y = 0.0f;
double z = 0.0;
uint8_t r = 0;
uint8_t g = 0;
uint8_t b = 0;
uint8_t a = 0;
float q = 1.0f;
float s = 0.0f;
float t = 0.0f;
uint16_t u = 0;
uint16_t v = 0;
uint8_t fog = 0;
};
struct GSFrameReg
{
uint32_t fbp = 0;
uint32_t fbw = 0;
uint8_t psm = 0;
uint32_t fbmsk = 0;
};
struct GSZbufReg
{
uint32_t zbp = 0;
uint8_t psm = 0;
bool zmask = false;
};
struct GSScissorReg
{
uint16_t x0 = 0;
uint16_t x1 = 0;
uint16_t y0 = 0;
uint16_t y1 = 0;
};
struct GSTex0Reg
{
uint32_t tbp0 = 0;
uint8_t tbw = 0;
uint8_t psm = 0;
uint8_t tw = 0;
uint8_t th = 0;
uint8_t tcc = 0;
uint8_t tfx = 0;
uint32_t cbp = 0;
uint8_t cpsm = 0;
uint8_t csm = 0;
uint8_t csa = 0;
uint8_t cld = 0;
};
struct GSXYOffsetReg
{
uint16_t ofx = 0;
uint16_t ofy = 0;
};
struct GSTexaReg
{
uint8_t ta0 = 0;
bool aem = false;
uint8_t ta1 = 0;
};
struct GSTexClutReg
{
uint8_t cbw = 0;
uint8_t cou = 0;
uint16_t cov = 0;
};
struct GSContext
{
GSFrameReg frame;
GSScissorReg scissor;
GSTex0Reg tex0;
GSXYOffsetReg xyoffset;
GSZbufReg zbuf;
uint64_t tex1 = 0;
uint64_t miptbp1 = 0;
uint64_t miptbp2 = 0;
uint64_t clamp = 0;
uint64_t alpha = 0;
uint64_t test = 0;
uint64_t fba = 0;
};
struct GSPrimReg
{
GSPrimType type = GS_PRIM_POINT;
bool iip = false;
bool tme = false;
bool fge = false;
bool abe = false;
bool aa1 = false;
bool fst = false;
bool ctxt = false;
bool fix = false;
};
struct GSBitBltBuf
{
uint32_t sbp = 0;
uint8_t sbw = 0;
uint8_t spsm = 0;
uint32_t dbp = 0;
uint8_t dbw = 0;
uint8_t dpsm = 0;
};
struct GSTrxPos
{
uint16_t ssax = 0;
uint16_t ssay = 0;
uint16_t dsax = 0;
uint16_t dsay = 0;
uint8_t dir = 0;
};
struct GSTrxReg
{
uint16_t rrw = 0;
uint16_t rrh = 0;
};
struct GSDrawState
{
GSContext context{};
GSPrimReg prim{};
GSTexaReg texa{};
GSTexClutReg texclut{};
bool pabe = false;
uint64_t scanmsk = 0;
uint64_t dimx = 0;
uint64_t dthe = 0;
uint64_t colclamp = 0;
uint8_t fogR = 0;
uint8_t fogG = 0;
uint8_t fogB = 0;
uint16_t textureWidth = 1;
uint16_t textureHeight = 1;
bool linearFilter = false;
};
struct GSPrimitiveBatch
{
std::array<GSVertex, 3> vertices{};
uint8_t vertexCount = 0;
GSDrawState state{};
};
struct GSTransferCommand
{
GSBitBltBuf bitbltbuf{};
GSTrxPos trxpos{};
GSTrxReg trxreg{};
uint32_t direction = 3;
};
struct GSTransferSnapshot
{
uint32_t x = 0;
uint32_t y = 0;
uint32_t totalPixels = 0;
uint32_t copiedPixels = 0;
uint32_t direction = 3;
size_t localToHostPendingBytes = 0;
};
struct GSPresentationRequest
{
uint64_t pmode = 0;
uint64_t smode2 = 0;
uint64_t dispfb1 = 0;
uint64_t display1 = 0;
uint64_t dispfb2 = 0;
uint64_t display2 = 0;
uint64_t bgcolor = 0;
uint64_t vsyncTick = 0;
GSFrameReg contextFrames[2]{};
GSFrameReg preferredSource{};
uint32_t preferredDestFbp = 0;
bool hasPreferredSource = false;
};
struct PresentationFrame
{
std::vector<uint8_t> pixels;
uint32_t width = 0;
uint32_t height = 0;
uint32_t displayFbp = 0;
uint32_t sourceFbp = 0;
bool usedPreferred = false;
explicit operator bool() const
{
return !pixels.empty() && width != 0u && height != 0u;
}
};
enum class GSSyncReason : uint8_t
{
Finish,
LocalToHost,
Presentation,
DebugReadback,
Reset,
};
@@ -1,7 +1,7 @@
#ifndef PS2_GS_COMMON_H
#define PS2_GS_COMMON_H
#include "ps2_gs_gpu.h"
#include "runtime/gs/gs_types.h"
#include <cstdint>
namespace GSInternal
@@ -1,22 +0,0 @@
#ifndef PS2_GS_RASTERIZER_H
#define PS2_GS_RASTERIZER_H
#include <cstdint>
class GS;
class GSRasterizer
{
public:
void drawPrimitive(GS *gs);
void writePixel(GS *gs, int x, int y, int z, uint8_t r, uint8_t g, uint8_t b, uint8_t a, uint8_t fog);
uint32_t sampleTexture(GS *gs, float s, float t, float q, uint16_t u, uint16_t v);
uint32_t lookupCLUT(GS *gs, uint8_t index, uint32_t cbp, uint8_t cpsm, uint8_t csm, uint8_t csa, uint8_t sourcePsm);
private:
void drawSprite(GS *gs);
void drawTriangle(GS *gs);
void drawLine(GS *gs);
};
#endif
+1 -1
View File
@@ -11,7 +11,7 @@
#include <iostream>
#include <mutex>
#include "ps2_gif_arbiter.h"
#include "gs/ps2_gif_arbiter.h"
#if defined(_MSC_VER)
#include <intrin.h>
#elif defined(USE_SSE2NEON)
+2 -2
View File
@@ -1,8 +1,8 @@
#include "Common.h"
#include "GS.h"
#include "ps2_log.h"
#include "runtime/ps2_gs_common.h"
#include "runtime/ps2_gs_psmct16.h"
#include "runtime/gs/ps2_gs_common.h"
#include "runtime/gs/ps2_gs_psmct16.h"
#include "runtime/ee_scheduler.h"
namespace ps2_stubs
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -1,4 +1,4 @@
#include "runtime/ps2_gif_arbiter.h"
#include "runtime/gs/ps2_gif_arbiter.h"
#include <algorithm>
#include <cstring>
@@ -1,6 +1,6 @@
#include <array>
#include "runtime/ps2_gs_memory.h"
#include "runtime/gs/ps2_gs_memory.h"
namespace GSMem
{
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1,6 +1,6 @@
#include "runtime/ps2_memory.h"
#include "runtime/ps2_address.h"
#include "runtime/ps2_gs_gpu.h"
#include "runtime/gs/gs_frontend.h"
#include "ps2_log.h"
#include <atomic>
#include <cstring>
+1 -1
View File
@@ -4,7 +4,7 @@
#include "ps2_syscalls.h"
#include "game_overrides.h"
#include "ps2_runtime_macros.h"
#include "runtime/ps2_gs_gpu.h"
#include "runtime/gs/gs_frontend.h"
#include "runtime/ee_scheduler.h"
#include "ThreadNaming.h"
#include "Kernel/Stubs/Audio.h"
-1
View File
@@ -1 +0,0 @@
// VU1 interpreter implementation has been split into src/lib/vu/*.cpp.
+2 -2
View File
@@ -1,6 +1,6 @@
#include "runtime/ps2_vu1.h"
#include "runtime/ps2_gif_arbiter.h"
#include "runtime/ps2_gs_gpu.h"
#include "runtime/gs/ps2_gif_arbiter.h"
#include "runtime/gs/gs_frontend.h"
#include "runtime/ps2_memory.h"
#include "ps2_vu1_detail.h"
+2 -2
View File
@@ -1,6 +1,6 @@
#include "runtime/ps2_vu1.h"
#include "runtime/ps2_gif_arbiter.h"
#include "runtime/ps2_gs_gpu.h"
#include "runtime/gs/ps2_gif_arbiter.h"
#include "runtime/gs/gs_frontend.h"
#include "runtime/ps2_memory.h"
#include "ps2_vu1_detail.h"
+48 -10
View File
@@ -3,13 +3,12 @@
#include "ps2_runtime.h"
#include "ps2_stubs.h"
#include "ps2_syscalls.h"
#include "runtime/ps2_gs_gpu.h"
#include "runtime/gs/gs_frontend.h"
#include "runtime/ee_scheduler.h"
#include "runtime/ps2_gs_memory.h"
#include "runtime/ps2_gs_rasterizer.h"
#include "runtime/ps2_gs_psmct32.h"
#include "runtime/ps2_gs_psmt4.h"
#include "runtime/ps2_gs_psmt8.h"
#include "runtime/gs/ps2_gs_memory.h"
#include "runtime/gs/ps2_gs_psmct32.h"
#include "runtime/gs/ps2_gs_psmt4.h"
#include "runtime/gs/ps2_gs_psmt8.h"
#include "Stubs/Helpers/Support.h"
#include "Stubs/GS.h"
@@ -2861,9 +2860,13 @@ void register_ps2_gs_tests()
std::vector<uint8_t> vram(PS2_GS_VRAM_SIZE, 0u);
GS gs;
gs.init(vram.data(), static_cast<uint32_t>(vram.size()), nullptr);
GSRasterizer rasterizer;
constexpr uint32_t kTexTbp = 64u;
constexpr uint64_t kFrameReg =
(0ull << 0) |
(1ull << 16) |
(static_cast<uint64_t>(GS_PSM_CT32) << 24);
constexpr uint64_t kZbuf = (1ull << 32);
constexpr uint64_t kTex0 =
(static_cast<uint64_t>(kTexTbp) << 0) |
(16ull << 14) |
@@ -2873,22 +2876,57 @@ void register_ps2_gs_tests()
(1ull << 34) |
(1ull << 35);
constexpr uint64_t kPrim =
static_cast<uint64_t>(GS_PRIM_TRIANGLE) |
static_cast<uint64_t>(GS_PRIM_SPRITE) |
(1ull << 4);
constexpr uint32_t kExpectedColor = 0xFF3366CCu;
constexpr uint32_t kUnsaturatedColor = 0xFF00FF00u;
auto packFloat = [](float value) -> uint32_t
{
uint32_t bits = 0u;
std::memcpy(&bits, &value, sizeof(bits));
return bits;
};
auto packSt = [&](float s, float tValue) -> uint64_t
{
return static_cast<uint64_t>(packFloat(s)) |
(static_cast<uint64_t>(packFloat(tValue)) << 32u);
};
gs.WriteVram(GS_PSM_CT32, kTexTbp, 16u, 1u, 0u, kExpectedColor);
gs.WriteVram(GS_PSM_CT32, kTexTbp, 16u, 32u, 0u, kUnsaturatedColor);
gs.writeRegister(GS_REG_FRAME_1, kFrameReg);
gs.writeRegister(GS_REG_ZBUF_1, kZbuf);
gs.writeRegister(GS_REG_SCISSOR_1, 0ull);
gs.writeRegister(GS_REG_XYOFFSET_1, 0ull);
gs.writeRegister(GS_REG_TEST_1, 0x30000ull);
gs.writeRegister(GS_REG_TEX0_1, kTex0);
gs.writeRegister(GS_REG_PRIM, kPrim);
gs.writeRegister(GS_REG_RGBAQ, 0x3F80000080808080ull);
gs.writeRegister(GS_REG_ST, packSt(1.0f / 1024.0f, 0.0f));
gs.writeRegister(GS_REG_XYZ2, 0ull);
gs.writeRegister(GS_REG_ST, packSt(1.0f / 1024.0f, 0.0f));
gs.writeRegister(GS_REG_XYZ2, (16ull << 0) | (16ull << 16));
const uint32_t sampled =
rasterizer.sampleTexture(&gs, 1.0f / 1024.0f, 0.0f, 1.0f, 0u, 0u);
const uint32_t sampled = gs.ReadVram(GS_PSM_CT32, 0u, 1u, 0u, 0u);
t.Equals(sampled, kExpectedColor,
"TW/TH values above 10 should address a 1024-pixel texture instead of growing beyond GS limits");
});
tc.Run("GS backend replacement preserves canonical local memory", [](TestCase &t)
{
std::vector<uint8_t> vram(PS2_GS_VRAM_SIZE, 0u);
GS gs;
gs.init(vram.data(), static_cast<uint32_t>(vram.size()), nullptr);
constexpr uint32_t kColor = 0xA55A33CCu;
gs.WriteVram(GS_PSM_CT32, 64u, 1u, 3u, 2u, kColor);
gs.setRasterBackend(nullptr);
t.Equals(gs.ReadVram(GS_PSM_CT32, 64u, 1u, 3u, 2u), kColor,
"switching raster backends must retain the logical 4 MiB GS local memory");
});
tc.Run("GS TEX2 updates CLUT state independently from TEX0", [](TestCase &t)
{
std::vector<uint8_t> vram(PS2_GS_VRAM_SIZE, 0u);
+2 -2
View File
@@ -1,7 +1,7 @@
#include "MiniTest.h"
#include "runtime/ps2_memory.h"
#include "runtime/ps2_gs_gpu.h"
#include "runtime/ps2_gs_psmct32.h"
#include "runtime/gs/gs_frontend.h"
#include "runtime/gs/ps2_gs_psmct32.h"
#include "ps2_runtime.h"
#include "ps2_runtime_macros.h"
#include "Stubs/DMA.h"
+2 -2
View File
@@ -7,9 +7,9 @@
#include "runtime/ps2_memory.h"
#include "ps2_syscalls.h"
#include "ps2_stubs.h"
#include "runtime/ps2_gs_gpu.h"
#include "runtime/gs/gs_frontend.h"
#include "runtime/ee_scheduler.h"
#include "runtime/ps2_gs_psmct32.h"
#include "runtime/gs/ps2_gs_psmct32.h"
#include "ps2_runtime_macros.h"
#include "Stubs/MPEG.h"
#include "Stubs/CD.h"
+3 -3
View File
@@ -1,7 +1,7 @@
#include "MiniTest.h"
#include "runtime/ps2_gif_arbiter.h"
#include "runtime/ps2_gs_gpu.h"
#include "runtime/ps2_gs_psmct32.h"
#include "runtime/gs/ps2_gif_arbiter.h"
#include "runtime/gs/gs_frontend.h"
#include "runtime/gs/ps2_gs_psmct32.h"
#include "runtime/ps2_memory.h"
#include "runtime/ps2_vu1.h"