Constant-size texture scroll display lists via G_SETTILESIZE_LERP (#6902)

Rewrite Gfx_TexScrollEx / Gfx_TwoTexScrollEx / Gfx_TwoTexScrollEnvColorEx to
emit one command per tile instead of one baked tile size per interpolated frame,
so texture DL memory no longer scales with InterpolationFPS
This commit is contained in:
Philip Dubé
2026-07-24 18:35:24 +00:00
committed by GitHub
parent 5af79defb6
commit c4e92a70f4
9 changed files with 49 additions and 105 deletions
+30 -89
View File
@@ -1395,33 +1395,18 @@ Gfx* Gfx_TexScroll(GraphicsContext* gfxCtx, u32 x, u32 y, s32 width, s32 height)
}
Gfx* Gfx_TexScrollEx(GraphicsContext* gfxCtx, u32 x, u32 y, s32 width, s32 height, s32 xStep, s32 yStep) {
int interpFrames = Ship_GetInterpolationFrameCount();
Gfx* gfx = Graph_Alloc(gfxCtx, (2 + (interpFrames * 4)) * sizeof(Gfx));
Gfx* gfx = Graph_Alloc(gfxCtx, 7 * sizeof(Gfx));
x %= 2048;
y %= 2048;
float xFlt = (float)x;
float yFlt = (float)y;
s32 xEnd = (s32)x + xStep;
s32 yEnd = (s32)y + yStep;
float xInc = (float)xStep / (float)interpFrames;
float yInc = (float)yStep / (float)interpFrames;
int idx = 0;
gDPTileSync(&gfx[idx++]);
for (int i = 0; i < interpFrames; i++) {
gDPSetInterpolation(&gfx[idx++], i);
gDPSetTileSizeInterp(&gfx[idx], 0, xFlt, yFlt, (xFlt + ((width - 1) << 2)), (yFlt + ((height - 1) << 2)));
idx += 3;
xFlt += xInc;
yFlt += yInc;
}
gSPEndDisplayList(&gfx[idx++]);
gDPTileSync(&gfx[0]);
gDPSetTileSizeLerp(&gfx[1], 0, x, y, x + ((width - 1) << 2), y + ((height - 1) << 2), xEnd, yEnd,
xEnd + ((width - 1) << 2), yEnd + ((height - 1) << 2));
gSPEndDisplayList(&gfx[6]);
return gfx;
}
@@ -1446,46 +1431,24 @@ Gfx* Gfx_TwoTexScroll(GraphicsContext* gfxCtx, s32 tile1, u32 x1, u32 y1, s32 wi
Gfx* Gfx_TwoTexScrollEx(GraphicsContext* gfxCtx, s32 tile1, u32 x1, u32 y1, s32 width1, s32 height1, s32 tile2, u32 x2,
u32 y2, s32 width2, s32 height2, s32 xStep1, s32 yStep1, s32 xStep2, s32 yStep2) {
int interpFrames = Ship_GetInterpolationFrameCount();
Gfx* gfx = Graph_Alloc(gfxCtx, (5 + (interpFrames * 7)) * sizeof(Gfx));
Gfx* gfx = Graph_Alloc(gfxCtx, 12 * sizeof(Gfx));
x1 %= 2048;
y1 %= 2048;
x2 %= 2048;
y2 %= 2048;
float x1Flt = (float)x1;
float y1Flt = (float)y1;
float x2Flt = (float)x2;
float y2Flt = (float)y2;
s32 x1End = (s32)x1 + xStep1;
s32 y1End = (s32)y1 + yStep1;
s32 x2End = (s32)x2 + xStep2;
s32 y2End = (s32)y2 + yStep2;
int index = 0;
gDPTileSync(&gfx[index++]);
float xInc1 = (float)xStep1 / (float)interpFrames;
float yInc1 = (float)yStep1 / (float)interpFrames;
float xInc2 = (float)xStep2 / (float)interpFrames;
float yInc2 = (float)yStep2 / (float)interpFrames;
for (int i = 0; i < interpFrames; i++) {
gDPSetInterpolation(&gfx[index++], i);
gDPSetTileSizeInterp(&gfx[index], tile1, x1Flt, y1Flt, (x1Flt + ((width1 - 1) << 2)),
(y1Flt + ((height1 - 1) << 2)));
index += 3;
gDPSetTileSizeInterp(&gfx[index], tile2, x2Flt, y2Flt, (x2Flt + ((width2 - 1) << 2)),
(y2Flt + ((height2 - 1) << 2)));
index += 3;
x1Flt += xInc1;
x2Flt += xInc2;
y1Flt += yInc1;
y2Flt += yInc2;
}
gSPEndDisplayList(&gfx[index]);
gDPTileSync(&gfx[0]);
gDPSetTileSizeLerp(&gfx[1], tile1, x1, y1, x1 + ((width1 - 1) << 2), y1 + ((height1 - 1) << 2), x1End, y1End,
x1End + ((width1 - 1) << 2), y1End + ((height1 - 1) << 2));
gDPSetTileSizeLerp(&gfx[6], tile2, x2, y2, x2 + ((width2 - 1) << 2), y2 + ((height2 - 1) << 2), x2End, y2End,
x2End + ((width2 - 1) << 2), y2End + ((height2 - 1) << 2));
gSPEndDisplayList(&gfx[11]);
return gfx;
}
@@ -1512,47 +1475,25 @@ Gfx* Gfx_TwoTexScrollEnvColor(GraphicsContext* gfxCtx, s32 tile1, u32 x1, u32 y1
Gfx* Gfx_TwoTexScrollEnvColorEx(GraphicsContext* gfxCtx, s32 tile1, u32 x1, u32 y1, s32 width1, s32 height1, s32 tile2,
u32 x2, u32 y2, s32 width2, s32 height2, s32 r, s32 g, s32 b, s32 a, s32 xStep1,
s32 yStep1, s32 xStep2, s32 yStep2) {
int interpFrames = Ship_GetInterpolationFrameCount();
Gfx* gfx = Graph_Alloc(gfxCtx, (6 + (interpFrames * 7)) * sizeof(Gfx));
Gfx* gfx = Graph_Alloc(gfxCtx, 13 * sizeof(Gfx));
x1 %= 2048;
y1 %= 2048;
x2 %= 2048;
y2 %= 2048;
float x1Flt = (float)x1;
float y1Flt = (float)y1;
float x2Flt = (float)x2;
float y2Flt = (float)y2;
s32 x1End = (s32)x1 + xStep1;
s32 y1End = (s32)y1 + yStep1;
s32 x2End = (s32)x2 + xStep2;
s32 y2End = (s32)y2 + yStep2;
int index = 0;
gDPTileSync(&gfx[index++]);
float xInc1 = (float)xStep1 / (float)interpFrames;
float yInc1 = (float)yStep1 / (float)interpFrames;
float xInc2 = (float)xStep2 / (float)interpFrames;
float yInc2 = (float)yStep2 / (float)interpFrames;
for (int i = 0; i < interpFrames; i++) {
gDPSetInterpolation(&gfx[index++], i);
gDPSetTileSizeInterp(&gfx[index], tile1, x1Flt, y1Flt, (x1Flt + ((width1 - 1) << 2)),
(y1Flt + ((height1 - 1) << 2)));
index += 3;
gDPSetTileSizeInterp(&gfx[index], tile2, x2Flt, y2Flt, (x2Flt + ((width2 - 1) << 2)),
(y2Flt + ((height2 - 1) << 2)));
index += 3;
x1Flt += xInc1;
x2Flt += xInc2;
y1Flt += yInc1;
y2Flt += yInc2;
}
gDPSetEnvColor(&gfx[index++], r, g, b, a);
gSPEndDisplayList(&gfx[index]);
gDPTileSync(&gfx[0]);
gDPSetTileSizeLerp(&gfx[1], tile1, x1, y1, x1 + ((width1 - 1) << 2), y1 + ((height1 - 1) << 2), x1End, y1End,
x1End + ((width1 - 1) << 2), y1End + ((height1 - 1) << 2));
gDPSetTileSizeLerp(&gfx[6], tile2, x2, y2, x2 + ((width2 - 1) << 2), y2 + ((height2 - 1) << 2), x2End, y2End,
x2End + ((width2 - 1) << 2), y2End + ((height2 - 1) << 2));
gDPSetEnvColor(&gfx[11], r, g, b, a);
gSPEndDisplayList(&gfx[12]);
return gfx;
}
@@ -5044,8 +5044,9 @@ void BossTw_DrawEffects(PlayState* play) {
if (sp18F == 0) {
gSPDisplayList(POLY_XLU_DISP++, SEGMENTED_TO_VIRTUAL(gTwinrovaIceSurroundingPlayerMaterialDL));
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 195, 225, 235, 255);
gSPSegment(POLY_XLU_DISP++, 8,
Gfx_TwoTexScroll(play->state.gfxCtx, 0, 0, 0, 0x20, 0x40, 1, 0, 0, 0x20, 0x20));
gSPSegment(
POLY_XLU_DISP++, 8,
Gfx_TwoTexScrollEx(play->state.gfxCtx, 0, 0, 0, 0x20, 0x40, 1, 0, 0, 0x20, 0x20, 0, 0, 0, 0));
sp18F++;
BossTw_InitRand(1, 0x71AC, 0x263A);
}
@@ -5097,8 +5098,9 @@ void BossTw_DrawEffects(PlayState* play) {
}
gSPSegment(POLY_XLU_DISP++, 8,
Gfx_TwoTexScroll(play->state.gfxCtx, 0, (currentEffect->frame * 3) & 0x7F,
(-currentEffect->frame * 15) & 0xFF, 0x20, 0x40, 1, 0, 0, 0x20, 0x20));
Gfx_TwoTexScrollEx(play->state.gfxCtx, 0, (currentEffect->frame * 3) & 0x7F,
(-currentEffect->frame * 15) & 0xFF, 0x20, 0x40, 1, 0, 0, 0x20, 0x20, 3, -15,
0, 0));
Matrix_Translate(currentEffect->pos.x, currentEffect->pos.y, currentEffect->pos.z, MTXMODE_NEW);
Matrix_ReplaceRotation(&play->billboardMtxF);
Matrix_Scale(currentEffect->workf[EFF_SCALE], currentEffect->workf[EFF_SCALE], 1.0f, MTXMODE_APPLY);
+2 -2
View File
@@ -886,8 +886,8 @@ void EnFz_DrawIceSmoke(EnFz* this, PlayState* play) {
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 195, 225, 235, iceSmoke->primAlpha);
gSPSegment(POLY_XLU_DISP++, 0x08,
Gfx_TwoTexScroll(play->state.gfxCtx, 0, 3 * (iceSmoke->timer + (3 * i)),
15 * (iceSmoke->timer + (3 * i)), 32, 64, 1, 0, 0, 32, 32));
Gfx_TwoTexScrollEx(play->state.gfxCtx, 0, 3 * (iceSmoke->timer + (3 * i)),
15 * (iceSmoke->timer + (3 * i)), 32, 64, 1, 0, 0, 32, 32, 3, 15, 0, 0));
Matrix_Translate(iceSmoke->pos.x, iceSmoke->pos.y, iceSmoke->pos.z, MTXMODE_NEW);
Matrix_ReplaceRotation(&play->billboardMtxF);
Matrix_Scale(iceSmoke->xyScale, iceSmoke->xyScale, 1.0f, MTXMODE_APPLY);
@@ -122,8 +122,8 @@ void EffectSsEnIce_Draw(PlayState* play, u32 index, EffectSs* this) {
Gfx_SetupDL_25Xlu(play->state.gfxCtx);
func_8002EB44(&this->pos, &play->view.eye, &hiliteLightDir, play->state.gfxCtx);
gSPSegment(POLY_XLU_DISP++, 0x08,
Gfx_TwoTexScroll(play->state.gfxCtx, 0, 0, gameplayFrames & 0xFF, 0x20, 0x10, 1, 0,
(gameplayFrames * 2) & 0xFF, 0x40, 0x20));
Gfx_TwoTexScrollEx(play->state.gfxCtx, 0, 0, gameplayFrames & 0xFF, 0x20, 0x10, 1, 0,
(gameplayFrames * 2) & 0xFF, 0x40, 0x20, 0, 1, 0, 2));
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0x80, this->rPrimColorR, this->rPrimColorG, this->rPrimColorB,
this->rPrimColorA);
gDPSetEnvColor(POLY_XLU_DISP++, this->rEnvColorR, this->rEnvColorG, this->rEnvColorB, (u32)alpha);