mirror of
https://github.com/encounter/aurora.git
synced 2026-07-09 18:19:33 -07:00
Add GX_AUTO Aurora extension for GXBegin
This commit is contained in:
@@ -61,6 +61,14 @@ extern "C" {
|
||||
|
||||
#define GX_LOAD_AURORA_DESTROY_COPY_TEX 0x0034
|
||||
|
||||
/**
|
||||
* Draw primitives with the vertex count derived from a byte length, as written by
|
||||
* GXBegin(prim, fmt, GX_AUTO). Must be followed by a u8 draw opcode (vtxfmt|prim),
|
||||
* a u32 vertex data byte length, then that many bytes of vertex data. The byte length
|
||||
* must be a whole multiple of the current vertex size or zero (no draw).
|
||||
*/
|
||||
#define GX_LOAD_AURORA_DRAW_SIZED 0x0040
|
||||
|
||||
#define GX2_SET_POLYGON_OFFSET 0x1000
|
||||
|
||||
|
||||
|
||||
@@ -14,6 +14,13 @@ void GXSetVtxAttrFmtv(GXVtxFmt vtxfmt, const GXVtxAttrFmtList* list);
|
||||
void GXSetVtxAttrFmt(GXVtxFmt vtxfmt, GXAttr attr, GXCompCnt cnt, GXCompType type, u8 frac);
|
||||
void GXSetNumTexGens(u8 nTexGens);
|
||||
void GXBegin(GXPrimitive type, GXVtxFmt vtxfmt, u16 nverts);
|
||||
#ifdef TARGET_PC
|
||||
/**
|
||||
* Aurora extension: pass as GXBegin's vertex count to have it derived automatically from
|
||||
* the number of bytes written before GXEnd. Not supported while recording a display list.
|
||||
*/
|
||||
#define GX_AUTO 0xFFFF
|
||||
#endif
|
||||
void GXSetTexCoordGen2(GXTexCoordID dst_coord, GXTexGenType func, GXTexGenSrc src_param, u32 mtx, GXBool normalize,
|
||||
u32 postmtx);
|
||||
void GXSetLineWidth(u8 width, GXTexOffset texOffsets);
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
static u16 sBeginNVerts = 0;
|
||||
static u32 sBeginFifoSize = 0;
|
||||
static bool sInBegin = false;
|
||||
// GX_AUTO: offset of the u32 byte-length placeholder to patch in GXEnd
|
||||
static u32 sBeginSizeOffset = 0;
|
||||
static bool sBeginAuto = false;
|
||||
|
||||
extern "C" {
|
||||
|
||||
@@ -22,8 +25,18 @@ void GXBegin(GXPrimitive primitive, GXVtxFmt vtxFmt, u16 nVerts) {
|
||||
__GXSendFlushPrim();
|
||||
}
|
||||
|
||||
GX_WRITE_U8(vtxFmt | primitive);
|
||||
GX_WRITE_U16(nVerts);
|
||||
const u8 drawCmd = static_cast<u8>(vtxFmt) | static_cast<u8>(primitive);
|
||||
sBeginAuto = nVerts == GX_AUTO;
|
||||
if (sBeginAuto) {
|
||||
ASSERT(!aurora::gx::fifo::in_display_list(), "GXBegin: GX_AUTO not supported in display lists");
|
||||
GX_WRITE_AURORA(GX_LOAD_AURORA_DRAW_SIZED);
|
||||
GX_WRITE_U8(drawCmd);
|
||||
sBeginSizeOffset = aurora::gx::fifo::get_buffer_size();
|
||||
GX_WRITE_U32(0);
|
||||
} else {
|
||||
GX_WRITE_U8(drawCmd);
|
||||
GX_WRITE_U16(nVerts);
|
||||
}
|
||||
|
||||
// Record state for vertex count validation in GXEnd
|
||||
sBeginNVerts = nVerts;
|
||||
@@ -34,7 +47,10 @@ void GXBegin(GXPrimitive primitive, GXVtxFmt vtxFmt, u16 nVerts) {
|
||||
void GXEnd() {
|
||||
if (sInBegin) {
|
||||
u32 bytesWritten = aurora::gx::fifo::get_buffer_size() - sBeginFifoSize;
|
||||
if (sBeginNVerts > 0 && bytesWritten > 0) {
|
||||
if (sBeginAuto) {
|
||||
aurora::gx::fifo::patch_u32(sBeginSizeOffset, bytesWritten);
|
||||
sBeginAuto = false;
|
||||
} else if (sBeginNVerts > 0 && bytesWritten > 0) {
|
||||
u32 vtxSize = bytesWritten / sBeginNVerts;
|
||||
u32 remainder = bytesWritten % sBeginNVerts;
|
||||
if (remainder != 0) {
|
||||
|
||||
@@ -1542,16 +1542,8 @@ static void handle_draw_unmerged(GXPrimitive prim, GXVtxFmt fmt, u16 vtxCount, g
|
||||
// Draw command handler - parses vertices inline and caches results
|
||||
static ByteBuffer handle_draw_idx_buf;
|
||||
|
||||
static void handle_draw(u8 cmd, const u8* data, u32& pos, u32 size, bool bigEndian) {
|
||||
static void draw_prim(GXPrimitive prim, GXVtxFmt fmt, u16 vtxCount, const u8* data, u32& pos, u32 size) {
|
||||
ZoneScoped;
|
||||
u8 opcode = cmd & CP_OPCODE_MASK;
|
||||
GXVtxFmt fmt = static_cast<GXVtxFmt>(cmd & CP_VAT_MASK);
|
||||
GXPrimitive prim = static_cast<GXPrimitive>(opcode);
|
||||
|
||||
CHECK(pos + 2 <= size, "draw vtxCount read overrun");
|
||||
u16 vtxCount = read_u16(data + pos, bigEndian);
|
||||
pos += 2;
|
||||
|
||||
u32 vtxSize;
|
||||
if (g_gxState.lastVtxFmt == fmt)
|
||||
LIKELY { vtxSize = g_gxState.lastVtxSize; }
|
||||
@@ -1608,6 +1600,17 @@ static void handle_draw(u8 cmd, const u8* data, u32& pos, u32 size, bool bigEndi
|
||||
handle_draw_unmerged(prim, fmt, vtxCount, vertRange);
|
||||
}
|
||||
|
||||
static void handle_draw(u8 cmd, const u8* data, u32& pos, u32 size, bool bigEndian) {
|
||||
GXVtxFmt fmt = static_cast<GXVtxFmt>(cmd & CP_VAT_MASK);
|
||||
GXPrimitive prim = static_cast<GXPrimitive>(cmd & CP_OPCODE_MASK);
|
||||
|
||||
CHECK(pos + 2 <= size, "draw vtxCount read overrun");
|
||||
u16 vtxCount = read_u16(data + pos, bigEndian);
|
||||
pos += 2;
|
||||
|
||||
draw_prim(prim, fmt, vtxCount, data, pos, size);
|
||||
}
|
||||
|
||||
static ByteBuffer handle_draw_unmerged_idxBuf;
|
||||
|
||||
static void handle_draw_unmerged(GXPrimitive prim, GXVtxFmt fmt, u16 vtxCount, gfx::Range vertRange) {
|
||||
@@ -1810,6 +1813,27 @@ void handle_aurora(const u8* data, u32& pos, u32 size, bool bigEndian) {
|
||||
CHECK(pos + 8 <= size, "GX_LOAD_AURORA_DESTROY_COPY_TEX read overrun");
|
||||
evict_copy_texture(reinterpret_cast<const void*>(read_u64(data + pos, bigEndian)));
|
||||
pos += 8;
|
||||
} else if (subCmd == GX_LOAD_AURORA_DRAW_SIZED) {
|
||||
CHECK(pos + 5 <= size, "GX_LOAD_AURORA_DRAW_SIZED read overrun");
|
||||
u8 cmd = data[pos];
|
||||
pos += 1;
|
||||
u32 byteLen = read_u32(data + pos, bigEndian);
|
||||
pos += 4;
|
||||
GXVtxFmt fmt = static_cast<GXVtxFmt>(cmd & CP_VAT_MASK);
|
||||
GXPrimitive prim = static_cast<GXPrimitive>(cmd & CP_OPCODE_MASK);
|
||||
if (byteLen != 0) {
|
||||
u32 vtxSize;
|
||||
if (g_gxState.lastVtxFmt == fmt) {
|
||||
vtxSize = g_gxState.lastVtxSize;
|
||||
} else {
|
||||
vtxSize = calculate_last_vtx_size(fmt);
|
||||
}
|
||||
ASSERT(vtxSize != 0 && byteLen % vtxSize == 0,
|
||||
"GX_LOAD_AURORA_DRAW_SIZED: {} bytes is not a whole number of size-{} vertices", byteLen, vtxSize);
|
||||
u32 vtxCount = byteLen / vtxSize;
|
||||
ASSERT(vtxCount <= 0xFFFF, "GX_LOAD_AURORA_DRAW_SIZED: too many vertices ({})", vtxCount);
|
||||
draw_prim(prim, fmt, static_cast<u16>(vtxCount), data, pos, size);
|
||||
}
|
||||
} else if (subCmd == GX_LOAD_AURORA_DEBUG_GROUP_PUSH) {
|
||||
auto label = read_string(data, pos, size, bigEndian);
|
||||
gfx::push_debug_group(std::move(label));
|
||||
|
||||
@@ -39,6 +39,13 @@ void write_data_grow(const void* data, uint32_t length) {
|
||||
detail::sBufferCapacity = newCap;
|
||||
}
|
||||
|
||||
void patch_u32(const uint32_t offset, const uint32_t val) {
|
||||
ASSERT(!detail::sInDisplayList && offset + sizeof(uint32_t) <= detail::sBufferSize,
|
||||
"fifo::patch_u32: invalid patch offset {} (buffer size {})", offset, detail::sBufferSize);
|
||||
const auto out = bswap(val);
|
||||
std::memcpy(detail::sBufferData + offset, &out, sizeof(out));
|
||||
}
|
||||
|
||||
void begin_display_list(uint8_t* buf, uint32_t size) {
|
||||
detail::sInDisplayList = true;
|
||||
detail::sDlBuffer = buf;
|
||||
|
||||
@@ -73,6 +73,10 @@ inline void write_f32(const float val) {
|
||||
write_data(&out, sizeof(out));
|
||||
}
|
||||
|
||||
// Overwrites a u32 previously written to the FIFO buffer at the given offset.
|
||||
// Not valid during display list recording.
|
||||
void patch_u32(uint32_t offset, uint32_t val);
|
||||
|
||||
// Display list recording
|
||||
void begin_display_list(uint8_t* buf, uint32_t size);
|
||||
uint32_t end_display_list();
|
||||
|
||||
Reference in New Issue
Block a user