Migrate remaining GX functions to FIFO

This commit is contained in:
Luke Street
2026-06-22 20:29:39 -07:00
parent 0d78e100df
commit 05495810ba
10 changed files with 149 additions and 92 deletions
+4 -4
View File
@@ -76,11 +76,11 @@ void GX2SetPolygonOffset(f32 mFrontOffset, f32 mFrontScale, f32 mBackOffset, f32
}
void GXCreateFrameBuffer(u32 width, u32 height) {
aurora::gx::fifo::drain();
aurora::gfx::begin_offscreen(width, height);
GX_WRITE_AURORA(GX_AURORA_BEGIN_OFFSCREEN);
GX_WRITE_U32(width);
GX_WRITE_U32(height);
}
void GXRestoreFrameBuffer() {
aurora::gx::fifo::drain();
aurora::gfx::end_offscreen();
GX_WRITE_AURORA(GX_AURORA_END_OFFSCREEN);
}
+4 -2
View File
@@ -1,7 +1,9 @@
#include "gx.hpp"
#include "__gx.h"
#include "../../gfx/depth_peek.hpp"
#include <dolphin/gx/GXAurora.h>
#include <dolphin/gx/GXCpu2Efb.h>
void GXPeekZ(u16 x, u16 y, u32* z) {
@@ -10,9 +12,9 @@ void GXPeekZ(u16 x, u16 y, u32* z) {
if (aurora::gfx::depth_peek::read_latest(x, y, value)) {
*z = value;
} else {
*z = g_gxState.clearDepth & 0x00ffffffu;
*z = 0;
}
}
aurora::gfx::depth_peek::request_snapshot();
GX_WRITE_AURORA(GX_AURORA_REQUEST_DEPTH_SNAPSHOT);
}
-20
View File
@@ -1,7 +1,6 @@
#include "gx.hpp"
#include "__gx.h"
#include "../../gx/command_processor.hpp"
#include "../../gx/fifo.hpp"
#include <cstring>
@@ -66,23 +65,4 @@ void GXCallDisplayList(const void* data, u32 nbytes) {
// aurora::gx::fifo::process(static_cast<const u8*>(data), nbytes, true);
}
void GXCallDisplayListLE(const void* data, u32 nbytes) {
// Flush any pending dirty state before calling
if (__gx->dirtyState != 0) {
__GXSetDirtyState();
}
// Flush pending primitives
if (*reinterpret_cast<u32*>(&__gx->vNum) != 0) {
__GXSendFlushPrim();
}
// Drain the internal FIFO so that any pending CP register writes
// (VCD, VAT, etc.) are processed into g_gxState before the display
// list's draw commands reference them.
aurora::gx::fifo::drain();
// Process the display list through the command processor (little-endian)
aurora::gx::fifo::process(static_cast<const u8*>(data), nbytes, false);
}
}
+72 -54
View File
@@ -31,6 +31,60 @@ aurora::Vec2<uint32_t> scale_copy_dst(u32 logicalWidth, u32 logicalHeight) {
}
} // namespace
namespace aurora::gx {
void copy_tex(const void* dest, GXBool clear) noexcept {
const auto rect = map_logical_scissor(g_gxState.texCopySrc);
const auto [dstWidth, dstHeight] = scale_copy_dst(g_gxState.texCopyDstWidth, g_gxState.texCopyDstHeight);
const auto texCopyFmt = g_gxState.texCopyFmt;
const GXState::CopyTextureKey key{
.dest = dest,
.width = dstWidth,
.height = dstHeight,
.format = texCopyFmt,
};
auto it = g_gxState.copyTextureCache.find(key);
if (it == g_gxState.copyTextureCache.end()) {
gfx::TextureHandle handle;
if (gfx::tex_copy_conv::needs_conversion(texCopyFmt)) {
handle = gfx::new_conv_texture(dstWidth, dstHeight, texCopyFmt, "Copy Conv Texture");
} else {
// Configure the texture swizzle to use alpha 1.0 if targeting RGB565 or EFB doesn't have alpha
const auto fmt = texCopyFmt == GX_TF_RGB565 || g_gxState.pixelFmt == GX_PF_RGB8_Z24 ||
g_gxState.pixelFmt == GX_PF_RGB565_Z16
? GX_TF_RGB565
: GX_TF_RGBA8;
handle = gfx::new_render_texture(dstWidth, dstHeight, fmt, "Resolved Texture");
}
it = g_gxState.copyTextureCache.emplace(key, GXState::CopyTextureRef{.handle = handle, .revision = 0}).first;
}
auto& handle = it->second;
if (g_gxState.alphaUpdate && g_gxState.dstAlpha != UINT32_MAX) {
if (!clear) {
// TODO: figure out the right behavior here.
// should the copy have a specific alpha value but the EFB remains untouched?
}
// Overwrite alpha before resolving
gfx::push_draw_command(gfx::clear::DrawData{
.pipeline = gfx::pipeline_ref(gfx::clear::PipelineConfig{
.clearColor = false,
.clearAlpha = true,
.clearDepth = false,
}),
.color = wgpu::Color{0.f, 0.f, 0.f, g_gxState.dstAlpha / 255.f},
});
}
const auto clearColor = clear && g_gxState.colorUpdate;
const auto clearAlpha = clear && g_gxState.alphaUpdate;
const auto clearDepth = clear && g_gxState.depthUpdate;
gfx::resolve_pass(handle.handle, rect, clearColor, clearAlpha, clearDepth, g_gxState.clearColor, clear_depth_value(),
texCopyFmt);
++handle.revision;
g_gxState.copyTextures[dest] = handle;
}
} // namespace aurora::gx
extern "C" {
GXRenderModeObj GXNtsc480IntDf = {
VI_TVMODE_NTSC_INT,
@@ -103,14 +157,22 @@ void GXAdjustForOverscan(GXRenderModeObj* rmin, GXRenderModeObj* rmout, u16 hor,
void GXSetDispCopySrc(u16 left, u16 top, u16 wd, u16 ht) {}
void GXSetTexCopySrc(u16 left, u16 top, u16 wd, u16 ht) { g_gxState.texCopySrc = {left, top, wd, ht}; }
void GXSetTexCopySrc(u16 left, u16 top, u16 wd, u16 ht) {
GX_WRITE_AURORA(GX_AURORA_LOAD_COPY_SRC);
GX_WRITE_U32(left);
GX_WRITE_U32(top);
GX_WRITE_U32(wd);
GX_WRITE_U32(ht);
}
void GXSetDispCopyDst(u16 wd, u16 ht) {}
void GXSetTexCopyDst(u16 wd, u16 ht, GXTexFmt fmt, GXBool mipmap) {
g_gxState.texCopyFmt = fmt;
g_gxState.texCopyDstWidth = wd;
g_gxState.texCopyDstHeight = ht;
GX_WRITE_AURORA(GX_AURORA_LOAD_COPY_DST);
GX_WRITE_U32(wd);
GX_WRITE_U32(ht);
GX_WRITE_U32(fmt);
GX_WRITE_U8(mipmap != GX_FALSE);
}
// TODO GXSetDispCopyFrame2Field
@@ -148,57 +210,13 @@ void GXSetDispCopyGamma(GXGamma gamma) {}
void GXCopyDisp(void* dest, GXBool clear) {}
void GXCopyTex(void* dest, GXBool clear) {
aurora::gx::fifo::drain();
GX_WRITE_AURORA(GX_AURORA_LOAD_COPY_DEST);
GX_WRITE_U64(reinterpret_cast<u64>(dest));
const auto rect = aurora::gx::map_logical_scissor(g_gxState.texCopySrc);
const auto [dstWidth, dstHeight] = scale_copy_dst(g_gxState.texCopyDstWidth, g_gxState.texCopyDstHeight);
const auto texCopyFmt = g_gxState.texCopyFmt;
const aurora::gx::GXState::CopyTextureKey key{
.dest = dest,
.width = dstWidth,
.height = dstHeight,
.format = texCopyFmt,
};
auto it = g_gxState.copyTextureCache.find(key);
if (it == g_gxState.copyTextureCache.end()) {
aurora::gfx::TextureHandle handle;
if (aurora::gfx::tex_copy_conv::needs_conversion(texCopyFmt)) {
handle = aurora::gfx::new_conv_texture(dstWidth, dstHeight, texCopyFmt, "Copy Conv Texture");
} else {
// Configure the texture swizzle to use alpha 1.0 if targeting RGB565 or EFB doesn't have alpha
const auto fmt = texCopyFmt == GX_TF_RGB565 || g_gxState.pixelFmt == GX_PF_RGB8_Z24 ||
g_gxState.pixelFmt == GX_PF_RGB565_Z16
? GX_TF_RGB565
: GX_TF_RGBA8;
handle = aurora::gfx::new_render_texture(dstWidth, dstHeight, fmt, "Resolved Texture");
}
it = g_gxState.copyTextureCache.emplace(key, aurora::gx::GXState::CopyTextureRef{.handle = handle, .revision = 0}).first;
}
auto& handle = it->second;
if (g_gxState.alphaUpdate && g_gxState.dstAlpha != UINT32_MAX) {
if (!clear) {
// TODO: figure out the right behavior here.
// should the copy have a specific alpha value but the EFB remains untouched?
}
// Overwrite alpha before resolving
aurora::gfx::push_draw_command(aurora::gfx::clear::DrawData{
.pipeline = aurora::gfx::pipeline_ref(aurora::gfx::clear::PipelineConfig{
.clearColor = false,
.clearAlpha = true,
.clearDepth = false,
}),
.color = wgpu::Color{0.f, 0.f, 0.f, g_gxState.dstAlpha / 255.f},
});
}
const auto clearColor = clear && g_gxState.colorUpdate;
const auto clearAlpha = clear && g_gxState.alphaUpdate;
const auto clearDepth = clear && g_gxState.depthUpdate;
aurora::gfx::resolve_pass(handle.handle, rect, clearColor, clearAlpha, clearDepth, g_gxState.clearColor,
aurora::gx::clear_depth_value(), texCopyFmt);
++handle.revision;
g_gxState.copyTextures[dest] = handle;
SET_REG_FIELD(0, __gx->cpTex, 1, 11, clear != GX_FALSE);
SET_REG_FIELD(0, __gx->cpTex, 1, 14, 0);
SET_REG_FIELD(0, __gx->cpTex, 8, 24, 0x52);
GX_WRITE_RAS_REG(__gx->cpTex);
}
// TODO GXGetYScaleFactor
+1
View File
@@ -71,6 +71,7 @@ GXFifoObj* GXInit(void* base, u32 size) {
SET_REG_FIELD(0, __gx->cmode1, 8, 24, 0x42);
SET_REG_FIELD(0, __gx->zmode, 8, 24, 0x40);
SET_REG_FIELD(0, __gx->peCtrl, 8, 24, 0x43);
SET_REG_FIELD(0, __gx->cpTex, 2, 7, 0);
SET_REG_FIELD(0, __gx->IndTexScale0, 8, 24, 0x25);
SET_REG_FIELD(0, __gx->IndTexScale1, 8, 24, 0x26);
+2 -2
View File
@@ -83,8 +83,7 @@
GX_WRITE_U32(value); \
} while (0)
// Shadow register struct - mirrors the hardware GX state
// This is the subset of __GXData_struct needed for aurora's TARGET_PC emulation.
// Shadow register struct
struct __GXData_struct {
u16 vNum; // vertex count for flush prim
u16 bpSent; // BP register was sent (need flush prim before next draw)
@@ -126,6 +125,7 @@ struct __GXData_struct {
u32 cmode1; // destination alpha register
u32 zmode; // Z-buffer mode register
u32 peCtrl; // pixel engine control
u32 cpTex; // copy texture trigger register
u32 genMode; // general mode (numTexGens, numChans, numTevStages, cullMode, numIndStages)
+49 -1
View File
@@ -1,6 +1,7 @@
#include "command_processor.hpp"
#include "../gfx/common.hpp"
#include "../gfx/depth_peek.hpp"
#include "dolphin/gx/GXAurora.h"
#include "gx.hpp"
#include "gx_fmt.hpp"
@@ -12,6 +13,7 @@
#include <tracy/Tracy.hpp>
#include <cmath>
#include <cstdint>
#include <cstring>
#include <optional>
@@ -502,7 +504,7 @@ static void handle_bp(u32 value, bool bigEndian) {
g_gxState.bpRegCache[0xFE] = 0x00FFFFFF;
const u32 merged = (g_gxState.bpRegCache[regId] & ~ssMask) | (value & ssMask);
value = (regId << 24) | (merged & 0x00FFFFFF);
if (g_gxState.bpRegCache[regId] == value)
if (g_gxState.bpRegCache[regId] == value && regId != 0x52)
return;
g_gxState.bpRegCache[regId] = value;
}
@@ -785,6 +787,17 @@ static void handle_bp(u32 value, bool bigEndian) {
break;
}
// Texture copy
case 0x52: {
const bool clear = bp_get(value, 1, 11) != 0;
if (bp_get(value, 1, 14) != 0) {
Log.warn("STUB: display copy is not implemented");
} else {
copy_tex(g_gxState.texCopyDest, clear);
}
break;
}
// TLUT load address / execute (0x64, 0x65)
case 0x64:
break;
@@ -1808,6 +1821,41 @@ void handle_aurora(const u8* data, u32& pos, u32 size, bool bigEndian) {
g_gxState.clamp = read_f32(data + pos, bigEndian);
pos += 4;
g_gxState.stateDirty = true;
} else if (subCmd == GX_AURORA_LOAD_COPY_SRC) {
CHECK(pos + 16 <= size, "GX_AURORA_LOAD_COPY_SRC read overrun");
const int32_t left = static_cast<int32_t>(read_u32(data + pos, bigEndian));
pos += 4;
const int32_t top = static_cast<int32_t>(read_u32(data + pos, bigEndian));
pos += 4;
const int32_t width = static_cast<int32_t>(read_u32(data + pos, bigEndian));
pos += 4;
const int32_t height = static_cast<int32_t>(read_u32(data + pos, bigEndian));
pos += 4;
g_gxState.texCopySrc = {left, top, width, height};
} else if (subCmd == GX_AURORA_LOAD_COPY_DST) {
CHECK(pos + 13 <= size, "GX_AURORA_LOAD_COPY_DST read overrun");
g_gxState.texCopyDstWidth = read_u32(data + pos, bigEndian);
pos += 4;
g_gxState.texCopyDstHeight = read_u32(data + pos, bigEndian);
pos += 4;
g_gxState.texCopyFmt = static_cast<GXTexFmt>(read_u32(data + pos, bigEndian));
pos += 4;
g_gxState.texCopyDstWide = true;
} else if (subCmd == GX_AURORA_LOAD_COPY_DEST) {
CHECK(pos + 8 <= size, "GX_AURORA_LOAD_COPY_DEST read overrun");
g_gxState.texCopyDest = reinterpret_cast<const void*>(read_u64(data + pos, bigEndian));
pos += 8;
} else if (subCmd == GX_AURORA_REQUEST_DEPTH_SNAPSHOT) {
gfx::depth_peek::request_snapshot();
} else if (subCmd == GX_AURORA_BEGIN_OFFSCREEN) {
CHECK(pos + 8 <= size, "GX_AURORA_BEGIN_OFFSCREEN read overrun");
const u32 width = read_u32(data + pos, bigEndian);
pos += 4;
const u32 height = read_u32(data + pos, bigEndian);
pos += 4;
gfx::begin_offscreen(width, height);
} else if (subCmd == GX_AURORA_END_OFFSCREEN) {
gfx::end_offscreen();
} else if (subCmd == GX_AURORA_DESTROY_TEXOBJ) {
CHECK(pos + 4 <= size, "GX_AURORA_DESTROY_TEXOBJ read overrun");
evict_texture_object(read_u32(data + pos, bigEndian));
+5 -2
View File
@@ -345,8 +345,10 @@ struct GXState {
std::array<AttrArray, MaxVtxAttr> arrays;
gfx::ClipRect texCopySrc;
GXTexFmt texCopyFmt;
u16 texCopyDstWidth = 0;
u16 texCopyDstHeight = 0;
u32 texCopyDstWidth = 0;
u32 texCopyDstHeight = 0;
bool texCopyDstWide = false;
const void* texCopyDest = nullptr;
struct CopyTextureKey {
const void* dest = nullptr;
u32 width = 0;
@@ -406,6 +408,7 @@ void set_logical_viewport(const gfx::Viewport& viewport) noexcept;
void set_render_viewport(const gfx::Viewport& viewport) noexcept;
void set_logical_scissor(const gfx::ClipRect& scissor) noexcept;
void set_render_scissor(const gfx::ClipRect& scissor) noexcept;
void copy_tex(const void* dest, GXBool clear) noexcept;
const gfx::TextureBind& get_texture(GXTexMapID id) noexcept;
void resolve_sampled_textures(const ShaderInfo& info) noexcept;