Skip to content

Commit

Permalink
Support F3DEX3 memset command
Browse files Browse the repository at this point in the history
  • Loading branch information
aglab2 committed Jan 10, 2025
1 parent a1a231d commit 5e8f010
Show file tree
Hide file tree
Showing 4 changed files with 156 additions and 13 deletions.
154 changes: 143 additions & 11 deletions src/gDP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -230,22 +230,28 @@ void gDPSetFillColor( u32 c )
DebugMsg( DEBUG_NORMAL, "gDPSetFillColor( 0x%08X );\n", c );
}

void gDPGetFillColor(f32 _fillColor[4])
static void getFillColor(u32 c, f32 _fillColor[4])
{
const u32 c = gDP.fillColor.color;
if (gDP.colorImage.size < 3) {
_fillColor[0] = _FIXED2FLOATCOLOR( _SHIFTR( c, 11, 5 ), 5 );
_fillColor[1] = _FIXED2FLOATCOLOR( _SHIFTR( c, 6, 5 ), 5 );
_fillColor[2] = _FIXED2FLOATCOLOR( _SHIFTR( c, 1, 5 ), 5 );
_fillColor[3] = (f32)_SHIFTR( c, 0, 1 );
} else {
_fillColor[0] = _FIXED2FLOATCOLOR( _SHIFTR( c, 24, 8 ), 8 );
_fillColor[1] = _FIXED2FLOATCOLOR( _SHIFTR( c, 16, 8 ), 8 );
_fillColor[2] = _FIXED2FLOATCOLOR( _SHIFTR( c, 8, 8 ), 8 );
_fillColor[3] = _FIXED2FLOATCOLOR( _SHIFTR( c, 0, 8 ), 8 );
_fillColor[0] = _FIXED2FLOATCOLOR(_SHIFTR(c, 11, 5), 5);
_fillColor[1] = _FIXED2FLOATCOLOR(_SHIFTR(c, 6, 5), 5);
_fillColor[2] = _FIXED2FLOATCOLOR(_SHIFTR(c, 1, 5), 5);
_fillColor[3] = (f32)_SHIFTR(c, 0, 1);
}
else {
_fillColor[0] = _FIXED2FLOATCOLOR(_SHIFTR(c, 24, 8), 8);
_fillColor[1] = _FIXED2FLOATCOLOR(_SHIFTR(c, 16, 8), 8);
_fillColor[2] = _FIXED2FLOATCOLOR(_SHIFTR(c, 8, 8), 8);
_fillColor[3] = _FIXED2FLOATCOLOR(_SHIFTR(c, 0, 8), 8);
}
}

void gDPGetFillColor(f32 _fillColor[4])
{
const u32 c = gDP.fillColor.color;
return getFillColor(c, _fillColor);
}

void gDPSetPrimColor( u32 m, u32 l, u32 r, u32 g, u32 b, u32 a )
{
gDP.primColor.m = _FIXED2FLOAT( m, 5 );
Expand Down Expand Up @@ -942,6 +948,132 @@ void gDPSetScissor(u32 mode, s16 xh, s16 yh, s16 xl, s16 yl)
#endif
}

template<typename T>
class BackupRestore
{
public:
BackupRestore(T& _value) : value(_value), backup(_value) {}
~BackupRestore() { value = backup; };

private:
T& value;
T backup;
};

// This performs the same thing action as gDPFillRectangle but explicitly specifying what to overwrite
void gDPMemset(u32 value, u32 addr, u32 length)
{
// TODO: Can this be different?
u32 screenWidth = VI.width;
u32 screenHeight = VI.height;

GraphicsDrawer& drawer = dwnd().getDrawer();
u32 fillColor = value | (value << 16);
u32 depthImageStart = gDP.depthImageAddress;
u32 depthImageEnd = gDP.depthImageAddress + 320 * 240 * 2;
if (depthImageStart <= addr && addr < depthImageEnd)
{
// ZB clear
gDP.rectColor.r = _FIXED2FLOATCOLOR(_SHIFTR(fillColor, 11, 5), 5);
gDP.rectColor.g = _FIXED2FLOATCOLOR(_SHIFTR(fillColor, 6, 5), 5);
gDP.rectColor.b = _FIXED2FLOATCOLOR(_SHIFTR(fillColor, 1, 5), 5);
gDP.rectColor.a = (f32)_SHIFTR(fillColor, 0, 1);

// HACK: this usually replaces gDPSetColorImage for zb so save zb
frameBufferList().saveBuffer(gDP.depthImageAddress, (u16)G_IM_FMT_RGBA, (u16)G_IM_SIZ_16b, (u16)screenWidth, false);

if (config.generalEmulation.enableFragmentDepthWrite == 0)
drawer.clearDepthBuffer();
else
depthBufferList().setCleared(true);

// Deduce ulx, uly, lrx, lry from addr, size, and colorImageStart
// Currently I am assuming a simple letterbox case - top and bottom are not cleared
u32 lineSize = screenWidth * 2;
u32 ulx = 0;
u32 uly = (addr - depthImageStart) / lineSize;
u32 lrx = 320;
u32 lry = uly + length / lineSize;

if (config.generalEmulation.enableFragmentDepthWrite != 0)
{
// Pretend that we are drawing the rectangle over ZB with fill mode
BackupRestore backupColorImageAddress(gDP.colorImage.address);
BackupRestore backupWidth(gDP.colorImage.width);
unsigned int backupDepthSource = gDP.otherMode.depthSource;
unsigned int backupCycleType = gDP.otherMode.cycleType;

gDP.colorImage.address = gDP.depthImageAddress;
gDP.colorImage.width = screenWidth;
gDP.otherMode.cycleType = G_CYC_FILL;

drawer.drawRect(ulx, uly, lrx, lry);
frameBufferList().setBufferChanged(f32(lry));

gDP.otherMode.depthSource = backupDepthSource;
gDP.otherMode.cycleType = backupCycleType;
}

// TODO: Following the same logic and not filling in zb values in RDRAM, why?
return;
}

// Either RGBA16 or RGBA32. This heavily assume "niceness" of developers to bind color buffer before memset...
u32 colorSize = gDP.colorImage.size < 3 ? 2 : 4;
u32 colorImageStart = gDP.colorImage.address;
u32 colorImageEnd = gDP.colorImage.address + screenWidth * screenHeight * colorSize;
if (colorImageStart <= addr && addr < colorImageEnd)
{
// FB clear
f32 fillColor32[4];
getFillColor(fillColor, fillColor32);
gDP.rectColor.r = fillColor32[0];
gDP.rectColor.g = fillColor32[1];
gDP.rectColor.b = fillColor32[2];
gDP.rectColor.a = fillColor32[3];

u32 lineSize = colorSize * screenWidth;
u32 ulx = 0;
u32 uly = (addr - colorImageStart) / lineSize;
u32 lrx = 320;
u32 lry = uly + length / lineSize;

{
BackupRestore backupFillColor(gDP.fillColor.color);
unsigned int backupDepthSource = gDP.otherMode.depthSource;
unsigned int backupCycleType = gDP.otherMode.cycleType;

gDP.fillColor.color = fillColor;
gDP.otherMode.cycleType = G_CYC_FILL;

drawer.drawRect(ulx, uly, lrx, lry);
if (auto cur = frameBufferList().getCurrent())
cur->setBufferClearParams(gDP.fillColor.color, ulx, uly, lrx, lry);

frameBufferList().setBufferChanged(f32(lry));

gDP.otherMode.depthSource = backupDepthSource;
gDP.otherMode.cycleType = backupCycleType;
}

if (config.frameBufferEmulation.copyFromRDRAM != 0)
{
for (int i = 0; i < length / 4; i++)
{
*(u32*)(RDRAM + addr + i * 4) = fillColor;
}
}
}
else
{
// TODO: It is something we do not know about... I hope it is not a big deal to just memset it?
for (int i = 0; i < length / 4; i++)
{
*(u32*)(RDRAM + addr + i * 4) = fillColor;
}
}
}

void gDPFillRectangle( s32 ulx, s32 uly, s32 lrx, s32 lry )
{
GraphicsDrawer & drawer = dwnd().getDrawer();
Expand Down
1 change: 1 addition & 0 deletions src/gDP.h
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,7 @@ void gDPLoadTile( u32 tile, u32 uls, u32 ult, u32 lrs, u32 lrt );
void gDPLoadBlock( u32 tile, u32 uls, u32 ult, u32 lrs, u32 dxt );
void gDPLoadTLUT( u32 tile, u32 uls, u32 ult, u32 lrs, u32 lrt );
void gDPSetScissor( u32 mode, s16 xh, s16 yh, s16 xl, s16 yl);
void gDPMemset(u32 value, u32 addr, u32 length);
void gDPFillRectangle( s32 ulx, s32 uly, s32 lrx, s32 lry );
void gDPSetConvert( s32 k0, s32 k1, s32 k2, s32 k3, s32 k4, s32 k5 );
void gDPSetKeyR( u32 cR, u32 sR, u32 wR );
Expand Down
12 changes: 11 additions & 1 deletion src/uCodes/F3DEX3.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

#define F3DEX3_BRANCH_WZ 0x04

#define F3DEX3_MEMSET 0xD5

#define F3DEX3_TRISTRIP 0x08
#define F3DEX3_TRIFAN 0x09
#define F3DEX3_LIGHTTORDP 0x0A
Expand Down Expand Up @@ -248,6 +250,14 @@ static void F3DEX3_RelSegment(u32 w0, u32 w1)
gSPRelSegment(_SHIFTR(w0, 2, 4), w1 & 0x00FFFFFF);
}

static void F3DEX3_Memset(u32 w0, u32 w1)
{
u32 value = (u16) gDP.half_1;
u32 addr = w1;
u32 length = w0 & 0x00FFFFFF;
gDPMemset(value, addr, length);
}

void F3DEX3_Init()
{
gSPSetupFunctions();
Expand All @@ -272,7 +282,6 @@ void F3DEX3_Init()
GBI_SetGBI(G_POPMTX, F3DEX2_POPMTX, F3DEX2_PopMtx);
GBI_SetGBI(G_TEXTURE, F3DEX2_TEXTURE, F3DEX2_Texture);
GBI_SetGBI(G_DMA_IO, F3DEX2_DMA_IO, F3DEX2_DMAIO);
GBI_SetGBI(G_SPECIAL_1, F3DEX2_SPECIAL_1, F3DEX2_Special_1);
GBI_SetGBI(G_SPECIAL_2, F3DEX2_SPECIAL_2, F3DEX2_Special_2);
GBI_SetGBI(G_SPECIAL_3, F3DEX2_SPECIAL_3, F3DEX2_Special_3);

Expand All @@ -287,4 +296,5 @@ void F3DEX3_Init()
GBI_SetGBI(G_TRIFAN, F3DEX3_TRIFAN, F3DEX3_TriFan);
GBI_SetGBI(G_LIGHTTORDP, F3DEX3_LIGHTTORDP, F3DEX3_LightToRDP);
GBI_SetGBI(G_RELSEGMENT, F3DEX3_RELSEGMENT, F3DEX3_RelSegment);
GBI_SetGBI(G_SPECIAL_1, F3DEX3_MEMSET, F3DEX3_Memset);
}
2 changes: 1 addition & 1 deletion src/windows/ZilmarAPIImpl_windows.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ void PluginAPI::GetDllInfo(PLUGIN_INFO * PluginInfo)
{
PluginInfo->Version = 0x103;
PluginInfo->Type = PLUGIN_TYPE_GFX;
sprintf(PluginInfo->Name, "ANGLE %s v4.3.14", pluginName, PLUGIN_REVISION);
sprintf(PluginInfo->Name, "ANGLE %s v4.3.15", pluginName, PLUGIN_REVISION);
PluginInfo->NormalMemory = FALSE;
PluginInfo->MemoryBswaped = TRUE;
}

0 comments on commit 5e8f010

Please sign in to comment.