diff --git a/include/dolphin/gx/GXDispList.h b/include/dolphin/gx/GXDispList.h index b9a664d..41597c1 100644 --- a/include/dolphin/gx/GXDispList.h +++ b/include/dolphin/gx/GXDispList.h @@ -7,8 +7,15 @@ extern "C" { #endif +#ifdef AURORA +#define GXCallDisplayListNative GXCallDisplayListLE +#else +#define GXCallDisplayListNative GXCallDisplayList +#endif + void GXBeginDisplayList(void* list, u32 size); u32 GXEndDisplayList(void); +void GXCallDisplayListLE(const void* list, u32 nbytes); void GXCallDisplayList(const void* list, u32 nbytes); #ifdef __cplusplus diff --git a/lib/dolphin/gx/GXDispList.cpp b/lib/dolphin/gx/GXDispList.cpp index e11a704..c2a9d1e 100644 --- a/lib/dolphin/gx/GXDispList.cpp +++ b/lib/dolphin/gx/GXDispList.cpp @@ -2,17 +2,28 @@ #include "../../gfx/model/shader.hpp" +#define ROUNDUP32(x) (((x) + 31) & ~31) + extern "C" { void GXBeginDisplayList(void* list, u32 size) { - // TODO + CHECK(!g_gxState.dynamicDlBuf, "Display list began twice!"); + g_gxState.dynamicDlBuf.emplace(static_cast(list), size); } u32 GXEndDisplayList() { - // TODO - return 0; + auto &dlBuf = g_gxState.dynamicDlBuf; + size_t size = dlBuf->size(); + size_t paddedSize = ROUNDUP32(size); + dlBuf->append_zeroes(paddedSize - size); + dlBuf.reset(); + return paddedSize; +} + +void GXCallDisplayListLE(const void* data, u32 nbytes) { + aurora::gfx::model::queue_surface(static_cast(data), nbytes, false); } void GXCallDisplayList(const void* data, u32 nbytes) { - aurora::gfx::model::queue_surface(static_cast(data), nbytes); + aurora::gfx::model::queue_surface(static_cast(data), nbytes, true); +} } -} \ No newline at end of file diff --git a/lib/dolphin/gx/GXVert.cpp b/lib/dolphin/gx/GXVert.cpp index c96b330..d6604b8 100644 --- a/lib/dolphin/gx/GXVert.cpp +++ b/lib/dolphin/gx/GXVert.cpp @@ -117,6 +117,12 @@ static u16 lastVertexStart = 0; extern "C" { void GXBegin(GXPrimitive primitive, GXVtxFmt vtxFmt, u16 nVerts) { + if (auto& dlBuf = g_gxState.dynamicDlBuf) { + const u8 fmtAndPrimitive = vtxFmt | primitive; + dlBuf->append(fmtAndPrimitive); + dlBuf->append(nVerts); + return; + } CHECK(!sStreamState, "Stream began twice!"); uint16_t vertexSize = 0; @@ -180,267 +186,508 @@ void GXBegin(GXPrimitive primitive, GXVtxFmt vtxFmt, u16 nVerts) { } void GXPosition3f32(f32 x, f32 y, f32 z) { - sStreamState->check_direct(GX_VA_POS, GX_POS_XYZ, GX_F32); - sStreamState->append(aurora::Vec3{x, y, z}); + if (auto& dlBuf = g_gxState.dynamicDlBuf) { + dlBuf->append(aurora::Vec3{x, y, z}); + } else if (auto& stream = sStreamState) { + stream->check_direct(GX_VA_POS, GX_POS_XYZ, GX_F32); + stream->append(aurora::Vec3{x, y, z}); + } else { + FATAL("Stream function called with no stream or DL active"); + } } void GXPosition3u16(u16 x, u16 y, u16 z) { - const auto frac = sStreamState->check_direct(GX_VA_POS, GX_POS_XYZ, GX_U16); - sStreamState->append(aurora::Vec3{ - static_cast(x) / static_cast(1 << frac), - static_cast(y) / static_cast(1 << frac), - static_cast(z) / static_cast(1 << frac), - }); + if (auto& dlBuf = g_gxState.dynamicDlBuf) { + dlBuf->append(x); + dlBuf->append(y); + dlBuf->append(z); + } else if (auto& stream = sStreamState) { + const auto frac = stream->check_direct(GX_VA_POS, GX_POS_XYZ, GX_U16); + stream->append(aurora::Vec3{ + static_cast(x) / static_cast(1 << frac), + static_cast(y) / static_cast(1 << frac), + static_cast(z) / static_cast(1 << frac), + }); + } else { + FATAL("Stream function called with no stream or DL active"); + } } void GXPosition3s16(s16 x, s16 y, s16 z) { - const auto frac = sStreamState->check_direct(GX_VA_POS, GX_POS_XYZ, GX_S16); - sStreamState->append(aurora::Vec3{ - static_cast(x) / static_cast(1 << frac), - static_cast(y) / static_cast(1 << frac), - static_cast(z) / static_cast(1 << frac), - }); + if (auto& dlBuf = g_gxState.dynamicDlBuf) { + dlBuf->append(x); + dlBuf->append(y); + dlBuf->append(z); + } else if (auto& stream = sStreamState) { + const auto frac = stream->check_direct(GX_VA_POS, GX_POS_XYZ, GX_S16); + stream->append(aurora::Vec3{ + static_cast(x) / static_cast(1 << frac), + static_cast(y) / static_cast(1 << frac), + static_cast(z) / static_cast(1 << frac), + }); + } else { + FATAL("Stream function called with no stream or DL active"); + } } void GXPosition3u8(u8 x, u8 y, u8 z) { - const auto frac = sStreamState->check_direct(GX_VA_POS, GX_POS_XYZ, GX_U8); - sStreamState->append(aurora::Vec3{ - static_cast(x) / static_cast(1 << frac), - static_cast(y) / static_cast(1 << frac), - static_cast(z) / static_cast(1 << frac), - }); + if (auto& dlBuf = g_gxState.dynamicDlBuf) { + dlBuf->append(x); + dlBuf->append(y); + dlBuf->append(z); + } else if (auto& stream = sStreamState) { + const auto frac = stream->check_direct(GX_VA_POS, GX_POS_XYZ, GX_U8); + stream->append(aurora::Vec3{ + static_cast(x) / static_cast(1 << frac), + static_cast(y) / static_cast(1 << frac), + static_cast(z) / static_cast(1 << frac), + }); + } else { + FATAL("Stream function called with no stream or DL active"); + } } void GXPosition3s8(s8 x, s8 y, s8 z) { - const auto frac = sStreamState->check_direct(GX_VA_POS, GX_POS_XYZ, GX_S8); - sStreamState->append(aurora::Vec3{ - static_cast(x) / static_cast(1 << frac), - static_cast(y) / static_cast(1 << frac), - static_cast(z) / static_cast(1 << frac), - }); + if (auto& dlBuf = g_gxState.dynamicDlBuf) { + dlBuf->append(x); + dlBuf->append(y); + dlBuf->append(z); + } else if (auto& stream = sStreamState) { + const auto frac = stream->check_direct(GX_VA_POS, GX_POS_XYZ, GX_S8); + stream->append(aurora::Vec3{ + static_cast(x) / static_cast(1 << frac), + static_cast(y) / static_cast(1 << frac), + static_cast(z) / static_cast(1 << frac), + }); + } else { + FATAL("Stream function called with no stream or DL active"); + } } void GXPosition2f32(f32 x, f32 y) { - sStreamState->check_direct(GX_VA_POS, GX_POS_XY, GX_F32); - sStreamState->append(aurora::Vec3{x, y, 0.f}); + if (auto& dlBuf = g_gxState.dynamicDlBuf) { + dlBuf->append(aurora::Vec2{x, y}); + } else if (auto& stream = sStreamState) { + stream->check_direct(GX_VA_POS, GX_POS_XY, GX_F32); + stream->append(aurora::Vec3{x, y, 0.f}); + } else { + FATAL("Stream function called with no stream or DL active"); + } } void GXPosition2u16(u16 x, u16 y) { - const auto frac = sStreamState->check_direct(GX_VA_POS, GX_POS_XY, GX_U16); - sStreamState->append(aurora::Vec3{ - static_cast(x) / static_cast(1 << frac), - static_cast(y) / static_cast(1 << frac), - 0.f, - }); + if (auto& dlBuf = g_gxState.dynamicDlBuf) { + dlBuf->append(x); + dlBuf->append(y); + } else if (auto& stream = sStreamState) { + const auto frac = stream->check_direct(GX_VA_POS, GX_POS_XY, GX_U16); + stream->append(aurora::Vec3{ + static_cast(x) / static_cast(1 << frac), + static_cast(y) / static_cast(1 << frac), + 0.f, + }); + } else { + FATAL("Stream function called with no stream or DL active"); + } } void GXPosition2s16(s16 x, s16 y) { - const auto frac = sStreamState->check_direct(GX_VA_POS, GX_POS_XY, GX_S16); - sStreamState->append(aurora::Vec3{ - static_cast(x) / static_cast(1 << frac), - static_cast(y) / static_cast(1 << frac), - 0.f, - }); + if (auto& dlBuf = g_gxState.dynamicDlBuf) { + dlBuf->append(x); + dlBuf->append(y); + } else if (auto& stream = sStreamState) { + const auto frac = stream->check_direct(GX_VA_POS, GX_POS_XY, GX_S16); + stream->append(aurora::Vec3{ + static_cast(x) / static_cast(1 << frac), + static_cast(y) / static_cast(1 << frac), + 0.f, + }); + } else { + FATAL("Stream function called with no stream or DL active"); + } } void GXPosition2u8(u8 x, u8 y) { - const auto frac = sStreamState->check_direct(GX_VA_POS, GX_POS_XY, GX_U8); - sStreamState->append(aurora::Vec3{ - static_cast(x) / static_cast(1 << frac), - static_cast(y) / static_cast(1 << frac), - 0.f, - }); + if (auto& dlBuf = g_gxState.dynamicDlBuf) { + dlBuf->append(x); + dlBuf->append(y); + } else if (auto& stream = sStreamState) { + const auto frac = stream->check_direct(GX_VA_POS, GX_POS_XY, GX_U8); + stream->append(aurora::Vec3{ + static_cast(x) / static_cast(1 << frac), + static_cast(y) / static_cast(1 << frac), + 0.f, + }); + } else { + FATAL("Stream function called with no stream or DL active"); + } } void GXPosition2s8(s8 x, s8 y) { - const auto frac = sStreamState->check_direct(GX_VA_POS, GX_POS_XY, GX_S8); - sStreamState->append(aurora::Vec3{ - static_cast(x) / static_cast(1 << frac), - static_cast(y) / static_cast(1 << frac), - 0.f, - }); + if (auto& dlBuf = g_gxState.dynamicDlBuf) { + dlBuf->append(x); + dlBuf->append(y); + } else if (auto& stream = sStreamState) { + const auto frac = stream->check_direct(GX_VA_POS, GX_POS_XY, GX_S8); + stream->append(aurora::Vec3{ + static_cast(x) / static_cast(1 << frac), + static_cast(y) / static_cast(1 << frac), + 0.f, + }); + } else { + FATAL("Stream function called with no stream or DL active"); + } } void GXPosition1x16(u16 idx) { - sStreamState->check_indexed(GX_VA_POS, GX_INDEX16); - sStreamState->append(idx); + if (auto& dlBuf = g_gxState.dynamicDlBuf) { + dlBuf->append(idx); + } else if (auto& stream = sStreamState) { + stream->check_indexed(GX_VA_POS, GX_INDEX16); + stream->append(idx); + } else { + FATAL("Stream function called with no stream or DL active"); + } } void GXPosition1x8(u8 idx) { - sStreamState->check_indexed(GX_VA_POS, GX_INDEX8); - sStreamState->append(idx); + if (auto& dlBuf = g_gxState.dynamicDlBuf) { + dlBuf->append(idx); + } else if (auto& stream = sStreamState) { + stream->check_indexed(GX_VA_POS, GX_INDEX8); + stream->append(idx); + } else { + FATAL("Stream function called with no stream or DL active"); + } } void GXNormal3f32(f32 x, f32 y, f32 z) { - sStreamState->check_direct(GX_VA_NRM, GX_NRM_XYZ, GX_F32); - sStreamState->append(aurora::Vec3{x, y, z}); + if (auto& dlBuf = g_gxState.dynamicDlBuf) { + dlBuf->append(aurora::Vec3{x, y, z}); + } else if (auto& stream = sStreamState) { + stream->check_direct(GX_VA_NRM, GX_NRM_XYZ, GX_F32); + stream->append(aurora::Vec3{x, y, z}); + } else { + FATAL("Stream function called with no stream or DL active"); + } } void GXNormal3s16(s16 x, s16 y, s16 z) { - const auto frac = sStreamState->check_direct(GX_VA_NRM, GX_NRM_XYZ, GX_S16); - sStreamState->append(aurora::Vec3{ - static_cast(x) / static_cast(1 << frac), - static_cast(y) / static_cast(1 << frac), - static_cast(z) / static_cast(1 << frac), - }); + if (auto& dlBuf = g_gxState.dynamicDlBuf) { + dlBuf->append(x); + dlBuf->append(y); + dlBuf->append(z); + } else if (auto& stream = sStreamState) { + const auto frac = stream->check_direct(GX_VA_NRM, GX_NRM_XYZ, GX_S16); + stream->append(aurora::Vec3{ + static_cast(x) / static_cast(1 << frac), + static_cast(y) / static_cast(1 << frac), + static_cast(z) / static_cast(1 << frac), + }); + } else { + FATAL("Stream function called with no stream or DL active"); + } } void GXNormal3s8(s8 x, s8 y, s8 z) { - const auto frac = sStreamState->check_direct(GX_VA_NRM, GX_NRM_XYZ, GX_S8); - sStreamState->append(aurora::Vec3{ - static_cast(x) / static_cast(1 << frac), - static_cast(y) / static_cast(1 << frac), - static_cast(z) / static_cast(1 << frac), - }); + if (auto& dlBuf = g_gxState.dynamicDlBuf) { + dlBuf->append(x); + dlBuf->append(y); + dlBuf->append(z); + } else if (auto& stream = sStreamState) { + const auto frac = stream->check_direct(GX_VA_NRM, GX_NRM_XYZ, GX_S8); + stream->append(aurora::Vec3{ + static_cast(x) / static_cast(1 << frac), + static_cast(y) / static_cast(1 << frac), + static_cast(z) / static_cast(1 << frac), + }); + } else { + FATAL("Stream function called with no stream or DL active"); + } } void GXNormal1x16(u16 index) { - sStreamState->check_indexed(GX_VA_NRM, GX_INDEX16); - sStreamState->append(index); + if (auto& dlBuf = g_gxState.dynamicDlBuf) { + dlBuf->append(index); + } else if (auto& stream = sStreamState) { + stream->check_indexed(GX_VA_NRM, GX_INDEX16); + stream->append(index); + } else { + FATAL("Stream function called with no stream or DL active"); + } } void GXNormal1x8(u8 index) { - sStreamState->check_indexed(GX_VA_POS, GX_INDEX8); - sStreamState->append(index); + if (auto& dlBuf = g_gxState.dynamicDlBuf) { + dlBuf->append(index); + } else if (auto& stream = sStreamState) { + stream->check_indexed(GX_VA_POS, GX_INDEX8); + stream->append(index); + } else { + FATAL("Stream function called with no stream or DL active"); + } } void GXColor4f32(f32 r, f32 g, f32 b, f32 a) { - sStreamState->check_direct(GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8); - sStreamState->append(aurora::Vec4{r, g, b, a}); + if (auto& dlBuf = g_gxState.dynamicDlBuf) { + dlBuf->append(aurora::Vec4{r, g, b, a}); + } else if (auto& stream = sStreamState) { + stream->check_direct(GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8); + stream->append(aurora::Vec4{r, g, b, a}); + } else { + FATAL("Stream function called with no stream or DL active"); + } } void GXColor4u8(u8 r, u8 g, u8 b, u8 a) { - sStreamState->check_direct(GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8); - sStreamState->append(aurora::Vec4{ - static_cast(r) / 255.f, - static_cast(g) / 255.f, - static_cast(b) / 255.f, - static_cast(a) / 255.f, - }); + if (auto& dlBuf = g_gxState.dynamicDlBuf) { + dlBuf->append(r); + dlBuf->append(g); + dlBuf->append(b); + dlBuf->append(a); + } else if (auto& stream = sStreamState) { + stream->check_direct(GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8); + stream->append(aurora::Vec4{ + static_cast(r) / 255.f, + static_cast(g) / 255.f, + static_cast(b) / 255.f, + static_cast(a) / 255.f, + }); + } else { + FATAL("Stream function called with no stream or DL active"); + } } void GXColor3u8(u8 r, u8 g, u8 b) { - sStreamState->check_direct(GX_VA_CLR0, GX_CLR_RGB, GX_RGB8); - sStreamState->append(aurora::Vec4{ - static_cast(r) / 255.f, - static_cast(g) / 255.f, - static_cast(b) / 255.f, - 1.f, - }); + if (auto& dlBuf = g_gxState.dynamicDlBuf) { + dlBuf->append(r); + dlBuf->append(g); + dlBuf->append(b); + } else if (auto& stream = sStreamState) { + stream->check_direct(GX_VA_CLR0, GX_CLR_RGB, GX_RGB8); + stream->append(aurora::Vec4{ + static_cast(r) / 255.f, + static_cast(g) / 255.f, + static_cast(b) / 255.f, + 1.f, + }); + } else { + FATAL("Stream function called with no stream or DL active"); + } } void GXColor1u32(u32 clr) { - sStreamState->check_direct(GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8); - sStreamState->append(aurora::Vec4{ - static_cast((clr >> 24) & 0xff) / 255.f, - static_cast((clr >> 16) & 0xff) / 255.f, - static_cast((clr >> 8) & 0xff) / 255.f, - static_cast(clr & 0xff) / 255.f, - }); + if (auto& dlBuf = g_gxState.dynamicDlBuf) { + dlBuf->append(clr); + } else if (auto& stream = sStreamState) { + stream->check_direct(GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8); + stream->append(aurora::Vec4{ + static_cast((clr >> 24) & 0xff) / 255.f, + static_cast((clr >> 16) & 0xff) / 255.f, + static_cast((clr >> 8) & 0xff) / 255.f, + static_cast(clr & 0xff) / 255.f, + }); + } else { + FATAL("Stream function called with no stream or DL active"); + } } void GXColor1u16(u16 clr) { - sStreamState->check_direct(GX_VA_CLR0, GX_CLR_RGB, GX_RGB565); - sStreamState->append(aurora::Vec4{ - static_cast((clr >> 11) & 0x1f) / 31.f, - static_cast((clr >> 5) & 0x3f) / 63.f, - static_cast(clr & 0x1f) / 31.f, - 1.f, - }); + if (auto& dlBuf = g_gxState.dynamicDlBuf) { + dlBuf->append(clr); + } else if (auto& stream = sStreamState) { + stream->check_direct(GX_VA_CLR0, GX_CLR_RGB, GX_RGB565); + stream->append(aurora::Vec4{ + static_cast((clr >> 11) & 0x1f) / 31.f, + static_cast((clr >> 5) & 0x3f) / 63.f, + static_cast(clr & 0x1f) / 31.f, + 1.f, + }); + } else { + FATAL("Stream function called with no stream or DL active"); + } } void GXColor1x16(u16 index) { - sStreamState->check_indexed(GX_VA_CLR0, GX_INDEX16); - sStreamState->append(index); + if (auto& dlBuf = g_gxState.dynamicDlBuf) { + dlBuf->append(index); + } else if (auto& stream = sStreamState) { + stream->check_indexed(GX_VA_CLR0, GX_INDEX16); + stream->append(index); + } else { + FATAL("Stream function called with no stream or DL active"); + } } void GXColor1x8(u8 index) { - sStreamState->check_indexed(GX_VA_CLR0, GX_INDEX8); - sStreamState->append(index); + if (auto& dlBuf = g_gxState.dynamicDlBuf) { + dlBuf->append(index); + } else if (auto& stream = sStreamState) { + stream->check_indexed(GX_VA_CLR0, GX_INDEX8); + stream->append(index); + } else { + FATAL("Stream function called with no stream or DL active"); + } } void GXTexCoord2f32(f32 s, f32 t) { - sStreamState->check_direct(GX_VA_TEX0, GX_TEX_ST, GX_F32); - sStreamState->append(aurora::Vec2{s, t}); + if (auto& dlBuf = g_gxState.dynamicDlBuf) { + dlBuf->append(aurora::Vec2{s, t}); + } else if (auto& stream = sStreamState) { + stream->check_direct(GX_VA_TEX0, GX_TEX_ST, GX_F32); + stream->append(aurora::Vec2{s, t}); + } else { + FATAL("Stream function called with no stream or DL active"); + } } void GXTexCoord2u16(u16 s, u16 t) { - const auto frac = sStreamState->check_direct(GX_VA_TEX0, GX_TEX_ST, GX_U16); - sStreamState->append(aurora::Vec2{ - static_cast(s) / static_cast(1 << frac), - static_cast(t) / static_cast(1 << frac), - }); + if (auto& dlBuf = g_gxState.dynamicDlBuf) { + dlBuf->append(s); + dlBuf->append(t); + } else if (auto& stream = sStreamState) { + const auto frac = stream->check_direct(GX_VA_TEX0, GX_TEX_ST, GX_U16); + stream->append(aurora::Vec2{ + static_cast(s) / static_cast(1 << frac), + static_cast(t) / static_cast(1 << frac), + }); + } else { + FATAL("Stream function called with no stream or DL active"); + } } void GXTexCoord2s16(s16 s, s16 t) { - const auto frac = sStreamState->check_direct(GX_VA_TEX0, GX_TEX_ST, GX_S16); - sStreamState->append(aurora::Vec2{ - static_cast(s) / static_cast(1 << frac), - static_cast(t) / static_cast(1 << frac), - }); + if (auto& dlBuf = g_gxState.dynamicDlBuf) { + dlBuf->append(s); + dlBuf->append(t); + } else if (auto& stream = sStreamState) { + const auto frac = stream->check_direct(GX_VA_TEX0, GX_TEX_ST, GX_S16); + stream->append(aurora::Vec2{ + static_cast(s) / static_cast(1 << frac), + static_cast(t) / static_cast(1 << frac), + }); + } else { + FATAL("Stream function called with no stream or DL active"); + } } void GXTexCoord2u8(u8 s, u8 t) { - const auto frac = sStreamState->check_direct(GX_VA_TEX0, GX_TEX_ST, GX_U8); - sStreamState->append(aurora::Vec2{ - static_cast(s) / static_cast(1 << frac), - static_cast(t) / static_cast(1 << frac), - }); + if (auto& dlBuf = g_gxState.dynamicDlBuf) { + dlBuf->append(s); + dlBuf->append(t); + } else if (auto& stream = sStreamState) { + const auto frac = stream->check_direct(GX_VA_TEX0, GX_TEX_ST, GX_U8); + stream->append(aurora::Vec2{ + static_cast(s) / static_cast(1 << frac), + static_cast(t) / static_cast(1 << frac), + }); + } else { + FATAL("Stream function called with no stream or DL active"); + } } void GXTexCoord2s8(s8 s, s8 t) { - const auto frac = sStreamState->check_direct(GX_VA_TEX0, GX_TEX_ST, GX_S8); - sStreamState->append(aurora::Vec2{ - static_cast(s) / static_cast(1 << frac), - static_cast(t) / static_cast(1 << frac), - }); + if (auto& dlBuf = g_gxState.dynamicDlBuf) { + dlBuf->append(s); + dlBuf->append(t); + } else if (auto& stream = sStreamState) { + const auto frac = stream->check_direct(GX_VA_TEX0, GX_TEX_ST, GX_S8); + stream->append(aurora::Vec2{ + static_cast(s) / static_cast(1 << frac), + static_cast(t) / static_cast(1 << frac), + }); + } else { + FATAL("Stream function called with no stream or DL active"); + } } void GXTexCoord1f32(f32 s) { - sStreamState->check_direct(GX_VA_TEX0, GX_TEX_S, GX_F32); - sStreamState->append(aurora::Vec2{s, 0.f}); + if (auto& dlBuf = g_gxState.dynamicDlBuf) { + dlBuf->append(s); + } else if (auto& stream = sStreamState) { + stream->check_direct(GX_VA_TEX0, GX_TEX_S, GX_F32); + stream->append(aurora::Vec2{s, 0.f}); + } else { + FATAL("Stream function called with no stream or DL active"); + } } void GXTexCoord1u16(u16 s) { - const auto frac = sStreamState->check_direct(GX_VA_TEX0, GX_TEX_S, GX_U16); - sStreamState->append(aurora::Vec2{ - static_cast(s) / static_cast(1 << frac), - 0.f, - }); + if (auto& dlBuf = g_gxState.dynamicDlBuf) { + dlBuf->append(s); + } else if (auto& stream = sStreamState) { + const auto frac = stream->check_direct(GX_VA_TEX0, GX_TEX_S, GX_U16); + stream->append(aurora::Vec2{ + static_cast(s) / static_cast(1 << frac), + 0.f, + }); + } else { + FATAL("Stream function called with no stream or DL active"); + } } void GXTexCoord1s16(s16 s) { - const auto frac = sStreamState->check_direct(GX_VA_TEX0, GX_TEX_S, GX_S16); - sStreamState->append(aurora::Vec2{ - static_cast(s) / static_cast(1 << frac), - 0.f, - }); + if (auto& dlBuf = g_gxState.dynamicDlBuf) { + dlBuf->append(s); + } else if (auto& stream = sStreamState) { + const auto frac = stream->check_direct(GX_VA_TEX0, GX_TEX_S, GX_S16); + stream->append(aurora::Vec2{ + static_cast(s) / static_cast(1 << frac), + 0.f, + }); + } else { + FATAL("Stream function called with no stream or DL active"); + } } void GXTexCoord1u8(u8 s) { - const auto frac = sStreamState->check_direct(GX_VA_TEX0, GX_TEX_S, GX_U8); - sStreamState->append(aurora::Vec2{ - static_cast(s) / static_cast(1 << frac), - 0.f, - }); + if (auto& dlBuf = g_gxState.dynamicDlBuf) { + dlBuf->append(s); + } else if (auto& stream = sStreamState) { + const auto frac = stream->check_direct(GX_VA_TEX0, GX_TEX_S, GX_U8); + stream->append(aurora::Vec2{ + static_cast(s) / static_cast(1 << frac), + 0.f, + }); + } else { + FATAL("Stream function called with no stream or DL active"); + } } void GXTexCoord1s8(s8 s) { - const auto frac = sStreamState->check_direct(GX_VA_TEX0, GX_TEX_S, GX_S8); - sStreamState->append(aurora::Vec2{ - static_cast(s) / static_cast(1 << frac), - 0.f, - }); + if (auto& dlBuf = g_gxState.dynamicDlBuf) { + dlBuf->append(s); + } else if (auto& stream = sStreamState) { + const auto frac = stream->check_direct(GX_VA_TEX0, GX_TEX_S, GX_S8); + stream->append(aurora::Vec2{ + static_cast(s) / static_cast(1 << frac), + 0.f, + }); + } else { + FATAL("Stream function called with no stream or DL active"); + } } void GXTexCoord1x16(u16 index) { - sStreamState->check_indexed(GX_VA_TEX0, GX_INDEX16); - sStreamState->append(index); + if (auto& dlBuf = g_gxState.dynamicDlBuf) { + dlBuf->append(index); + } else if (auto& stream = sStreamState) { + stream->check_indexed(GX_VA_TEX0, GX_INDEX16); + stream->append(index); + } else { + FATAL("Stream function called with no stream or DL active"); + } } void GXTexCoord1x8(u8 index) { - sStreamState->check_indexed(GX_VA_TEX0, GX_INDEX8); - sStreamState->append(static_cast(index)); + if (auto& dlBuf = g_gxState.dynamicDlBuf) { + dlBuf->append(index); + } else if (auto& stream = sStreamState) { + stream->check_indexed(GX_VA_TEX0, GX_INDEX8); + stream->append(static_cast(index)); + } else { + FATAL("Stream function called with no stream or DL active"); + } } void GXEnd() { diff --git a/lib/gfx/display_list.cpp b/lib/gfx/display_list.cpp index a946c34..4a797d5 100644 --- a/lib/gfx/display_list.cpp +++ b/lib/gfx/display_list.cpp @@ -17,7 +17,7 @@ struct DisplayListCache { static absl::flat_hash_map sCachedDisplayLists; -static u32 prepare_vtx_buffer(ByteBuffer& buf, GXVtxFmt vtxfmt, const u8* ptr, u16 vtxCount) { +static u32 prepare_vtx_buffer(ByteBuffer& buf, GXVtxFmt vtxfmt, const u8* ptr, u16 vtxCount, bool bigEndian) { using gx::g_gxState; struct { u8 count; @@ -114,7 +114,8 @@ static u32 prepare_vtx_buffer(ByteBuffer& buf, GXVtxFmt vtxfmt, const u8* ptr, u buf.append(static_cast(*ptr)); ++ptr; } else if (g_gxState.vtxDesc[attr] == GX_INDEX16) { - buf.append(bswap(*reinterpret_cast(ptr))); + const auto value = *reinterpret_cast(ptr); + buf.append(bigEndian ? bswap(value) : value); ptr += 2; } if (g_gxState.vtxDesc[attr] != GX_DIRECT) { @@ -141,23 +142,24 @@ static u32 prepare_vtx_buffer(ByteBuffer& buf, GXVtxFmt vtxfmt, const u8* ptr, u break; case GX_U16: for (int i = 0; i < count; ++i) { - const auto value = bswap(reinterpret_cast(ptr)[i]); - out[i] = static_cast(value) / static_cast(1 << attrFmt.frac); + auto value = reinterpret_cast(ptr)[i]; + out[i] = static_cast(bigEndian ? bswap(value) : value) / static_cast(1 << attrFmt.frac); } buf.append(out.data(), sizeof(f32) * count); ptr += count * sizeof(u16); break; case GX_S16: for (int i = 0; i < count; ++i) { - const auto value = bswap(reinterpret_cast(ptr)[i]); - out[i] = static_cast(value) / static_cast(1 << attrFmt.frac); + const auto value = reinterpret_cast(ptr)[i]; + out[i] = static_cast(bigEndian ? bswap(value) : value) / static_cast(1 << attrFmt.frac); } buf.append(out.data(), sizeof(f32) * count); ptr += count * sizeof(s16); break; case GX_F32: for (int i = 0; i < count; ++i) { - out[i] = bswap(reinterpret_cast(ptr)[i]); + const auto value = reinterpret_cast(ptr)[i]; + out[i] = bigEndian ? bswap(value) : value; } buf.append(out.data(), sizeof(f32) * count); ptr += count * sizeof(f32); @@ -182,7 +184,26 @@ static u32 prepare_vtx_buffer(ByteBuffer& buf, GXVtxFmt vtxfmt, const u8* ptr, u static u16 prepare_idx_buffer(ByteBuffer& buf, GXPrimitive prim, u16 vtxStart, u16 vtxCount) { u16 numIndices = 0; - if (prim == GX_TRIANGLES) { + if (prim == GX_QUADS) { + buf.reserve_extra((vtxCount / 4) * 6 * sizeof(u16)); + + for (u16 v = 0; v < vtxCount; v += 4) { + u16 idx0 = vtxStart + v; + u16 idx1 = vtxStart + v + 1; + u16 idx2 = vtxStart + v + 2; + u16 idx3 = vtxStart + v + 3; + + buf.append(idx0); + buf.append(idx1); + buf.append(idx2); + numIndices += 3; + + buf.append(idx2); + buf.append(idx3); + buf.append(idx0); + numIndices += 3; + } + } else if (prim == GX_TRIANGLES) { buf.reserve_extra(vtxCount * sizeof(u16)); for (u16 v = 0; v < vtxCount; ++v) { const u16 idx = vtxStart + v; @@ -222,7 +243,7 @@ static u16 prepare_idx_buffer(ByteBuffer& buf, GXPrimitive prim, u16 vtxStart, u return numIndices; } -auto process_display_list(const u8* dlStart, u32 dlSize) -> DisplayListResult { +auto process_display_list(const u8* dlStart, u32 dlSize, bool bigEndian) -> DisplayListResult { const auto hash = xxh3_hash_s(dlStart, dlSize, 0); Range vertRange, idxRange; u32 numIndices = 0; @@ -259,9 +280,11 @@ auto process_display_list(const u8* dlStart, u32 dlSize) -> DisplayListResult { FATAL("Vertex format changed mid-display list: {} -> {}", fmt, newFmt); } fmt = newFmt; - u16 vtxCount = bswap(*reinterpret_cast(data + pos)); + u16 vtxCount = *reinterpret_cast(data + pos); + if (bigEndian) + vtxCount = bswap(vtxCount); pos += 2; - pos += vtxCount * prepare_vtx_buffer(vtxBuf, fmt, data + pos, vtxCount); + pos += vtxCount * prepare_vtx_buffer(vtxBuf, fmt, data + pos, vtxCount, bigEndian); numIndices += prepare_idx_buffer(idxBuf, prim, vtxStart, vtxCount); vtxStart += vtxCount; break; diff --git a/lib/gfx/display_list.hpp b/lib/gfx/display_list.hpp index 4a8774f..7bac908 100644 --- a/lib/gfx/display_list.hpp +++ b/lib/gfx/display_list.hpp @@ -10,5 +10,5 @@ struct DisplayListResult { GXVtxFmt fmt; }; -auto process_display_list(const u8* dlStart, u32 dlSize) -> DisplayListResult; +auto process_display_list(const u8* dlStart, u32 dlSize, bool bigEndian) -> DisplayListResult; }; // namespace aurora::gfx::gx diff --git a/lib/gfx/gx.hpp b/lib/gfx/gx.hpp index 4c5d16d..ea7582a 100644 --- a/lib/gfx/gx.hpp +++ b/lib/gfx/gx.hpp @@ -294,6 +294,7 @@ struct GXState { ClipRect texCopySrc; GXTexFmt texCopyFmt; absl::flat_hash_map copyTextures; + std::optional dynamicDlBuf; bool depthCompare = true; bool depthUpdate = true; bool colorUpdate = true; diff --git a/lib/gfx/gx_shader.cpp b/lib/gfx/gx_shader.cpp index 3aad44a..6c847a2 100644 --- a/lib/gfx/gx_shader.cpp +++ b/lib/gfx/gx_shader.cpp @@ -38,6 +38,20 @@ static inline std::string_view chan_comp(GXTevColorChan chan) noexcept { } } +u8 color_channel(GXChannelID id) { + switch (id) { + DEFAULT_FATAL("unimplemented color channel {}", id); + case GX_COLOR0: + case GX_ALPHA0: + case GX_COLOR0A0: + return 0; + case GX_COLOR1: + case GX_ALPHA1: + case GX_COLOR1A1: + return 1; + } +} + static std::string color_arg_reg(GXTevColorArg arg, size_t stageIdx, const ShaderConfig& config, const TevStage& stage) { switch (arg) { @@ -77,9 +91,7 @@ static std::string color_arg_reg(GXTevColorArg arg, size_t stageIdx, const Shade if (stage.channelId == GX_COLOR_ZERO) { return "vec3f(0.0)"; } - CHECK(stage.channelId >= GX_COLOR0A0 && stage.channelId <= GX_COLOR1A1, "invalid color channel {} for stage {}", - underlying(stage.channelId), stageIdx); - u32 idx = stage.channelId - GX_COLOR0A0; + u32 idx = color_channel(stage.channelId); const auto& swap = config.tevSwapTable[stage.tevSwapRas]; return fmt::format("rast{}.{}{}{}", idx, chan_comp(swap.red), chan_comp(swap.green), chan_comp(swap.blue)); } @@ -88,9 +100,7 @@ static std::string color_arg_reg(GXTevColorArg arg, size_t stageIdx, const Shade if (stage.channelId == GX_COLOR_ZERO) { return "vec3f(0.0)"; } - CHECK(stage.channelId >= GX_COLOR0A0 && stage.channelId <= GX_COLOR1A1, "invalid color channel {} for stage {}", - underlying(stage.channelId), stageIdx); - u32 idx = stage.channelId - GX_COLOR0A0; + u32 idx = color_channel(stage.channelId); const auto& swap = config.tevSwapTable[stage.tevSwapRas]; return fmt::format("vec3f(rast{}.{})", idx, chan_comp(swap.alpha)); } @@ -188,9 +198,7 @@ static std::string alpha_arg_reg(GXTevAlphaArg arg, size_t stageIdx, const Shade if (stage.channelId == GX_COLOR_ZERO) { return "0.0"; } - CHECK(stage.channelId >= GX_COLOR0A0 && stage.channelId <= GX_COLOR1A1, "invalid color channel {} for stage {}", - underlying(stage.channelId), stageIdx); - u32 idx = stage.channelId - GX_COLOR0A0; + u32 idx = color_channel(stage.channelId); const auto& swap = config.tevSwapTable[stage.tevSwapRas]; return fmt::format("rast{}.{}", idx, chan_comp(swap.alpha)); } @@ -319,6 +327,9 @@ static inline std::string vtx_attr(const ShaderConfig& config, GXAttr attr) { // Default normal return "vec3f(1.0, 0.0, 0.0)"s; } + if (attr == GX_VA_CLR0 || attr == GX_VA_CLR1) { + return "vec4f(0.0, 0.0, 0.0, 0.0)"s; + } UNLIKELY FATAL("unmapped vtx attr {}", underlying(attr)); } if (attr == GX_VA_POS) { @@ -499,6 +510,16 @@ auto storage_load(const StorageConfig& mapping, u32 attrIdx) -> StorageLoadResul std::string attrLoad; switch (compType) { + case GX_S8: + switch (compCnt) { + case 3: + arrType = "i32"; + attrLoad = fmt::format("fetch_i8_3(&v_arr_{}, {}, {})", attrName, idxFetch, mapping.frac); + break; + default: + Log.fatal("storage_load: Unsupported {} count {}", compType, compCnt); + } + break; case GX_U16: switch (compCnt) { case 2: @@ -541,6 +562,10 @@ auto storage_load(const StorageConfig& mapping, u32 attrIdx) -> StorageLoadResul Log.fatal("storage_load: Unsupported {} count {}", compType, compCnt); } break; + case GX_RGBA8: + arrType = "u32"; + attrLoad = fmt::format("unpack4x8unorm(v_arr_{}[{}])", attrName, idxFetch); + break; default: Log.fatal("storage_load: Unimplemented {}", compType); } @@ -1136,6 +1161,22 @@ fn fetch_u8_2(p: ptr>, idx: u32, frac: u32) -> vec2 {{ var o1 = select(extractBits(v0, 8, 8), extractBits(v0, 24, 8), r); return vec2(f32(o0), f32(o1)) / f32(1u << frac); }} +fn fetch_i8_3(p: ptr>, idx: u32, frac: u32) -> vec3 {{ + let byte_idx = idx * 3u; + let word0 = p[byte_idx / 4u]; + let word1 = p[(byte_idx + 1u) / 4u]; + let word2 = p[(byte_idx + 2u) / 4u]; + + let shift0 = (byte_idx % 4u) * 8u; + let shift1 = ((byte_idx + 1u) % 4u) * 8u; + let shift2 = ((byte_idx + 2u) % 4u) * 8u; + + let o0 = extractBits(word0, shift0, 8); + let o1 = extractBits(word1, shift1, 8); + let o2 = extractBits(word2, shift2, 8); + + return vec3(f32(o0), f32(o1), f32(o2)) / f32(1u << frac); +}} fn fetch_u16_2(p: ptr>, idx: u32, frac: u32) -> vec2 {{ var v0 = p[idx]; var o0 = extractBits(v0, 0, 16); diff --git a/lib/gfx/model/shader.cpp b/lib/gfx/model/shader.cpp index da26c9d..eb4526d 100644 --- a/lib/gfx/model/shader.cpp +++ b/lib/gfx/model/shader.cpp @@ -10,8 +10,8 @@ namespace aurora::gfx::model { static Module Log("aurora::gfx::model"); -void queue_surface(const u8* dlStart, u32 dlSize) noexcept { - const auto result = aurora::gfx::gx::process_display_list(dlStart, dlSize); +void queue_surface(const u8* dlStart, u32 dlSize, bool bigEndian) noexcept { + const auto result = aurora::gfx::gx::process_display_list(dlStart, dlSize, bigEndian); gx::BindGroupRanges ranges{}; for (int i = 0; i < GX_VA_MAX_ATTR; ++i) { diff --git a/lib/gfx/model/shader.hpp b/lib/gfx/model/shader.hpp index d1020e9..82f99a5 100644 --- a/lib/gfx/model/shader.hpp +++ b/lib/gfx/model/shader.hpp @@ -23,5 +23,5 @@ State construct_state(); wgpu::RenderPipeline create_pipeline(const State& state, [[maybe_unused]] const PipelineConfig& config); void render(const State& state, const DrawData& data, const wgpu::RenderPassEncoder& pass); -void queue_surface(const u8* dlStart, u32 dlSize) noexcept; +void queue_surface(const u8* dlStart, u32 dlSize, bool bigEndian) noexcept; } // namespace aurora::gfx::model diff --git a/lib/gfx/shader_info.cpp b/lib/gfx/shader_info.cpp index f60b21a..f69a336 100644 --- a/lib/gfx/shader_info.cpp +++ b/lib/gfx/shader_info.cpp @@ -39,9 +39,7 @@ void color_arg_reg_info(GXTevColorArg arg, const TevStage& stage, ShaderInfo& in break; case GX_CC_RASC: case GX_CC_RASA: - if (stage.channelId >= GX_COLOR0A0 && stage.channelId <= GX_COLOR1A1) { - info.sampledColorChannels.set(stage.channelId - GX_COLOR0A0); - } + info.sampledColorChannels.set(color_channel(stage.channelId)); break; case GX_CC_KONST: switch (stage.kcSel) { @@ -111,9 +109,7 @@ void alpha_arg_reg_info(GXTevAlphaArg arg, const TevStage& stage, ShaderInfo& in info.sampledTextures.set(stage.texMapId); break; case GX_CA_RASA: - if (stage.channelId >= GX_COLOR0A0 && stage.channelId <= GX_COLOR1A1) { - info.sampledColorChannels.set(stage.channelId - GX_COLOR0A0); - } + info.sampledColorChannels.set(color_channel(stage.channelId)); break; case GX_CA_KONST: switch (stage.kaSel) { diff --git a/lib/gfx/shader_info.hpp b/lib/gfx/shader_info.hpp index a68673f..1924159 100644 --- a/lib/gfx/shader_info.hpp +++ b/lib/gfx/shader_info.hpp @@ -5,4 +5,5 @@ namespace aurora::gfx::gx { ShaderInfo build_shader_info(const ShaderConfig& config) noexcept; Range build_uniform(const ShaderInfo& info) noexcept; +u8 color_channel(GXChannelID id) noexcept; }; // namespace aurora::gfx::gx