diff --git a/F3DEX3/F3DEX3_BrW.code.bps b/F3DEX3/F3DEX3_BrW.code.bps index e99491aedd..6634c5d5c8 100644 Binary files a/F3DEX3/F3DEX3_BrW.code.bps and b/F3DEX3/F3DEX3_BrW.code.bps differ diff --git a/F3DEX3/F3DEX3_BrW.data.bps b/F3DEX3/F3DEX3_BrW.data.bps index 24239c6702..8b24e5598a 100644 Binary files a/F3DEX3/F3DEX3_BrW.data.bps and b/F3DEX3/F3DEX3_BrW.data.bps differ diff --git a/F3DEX3/F3DEX3_BrW_NOC.code.bps b/F3DEX3/F3DEX3_BrW_NOC.code.bps index f1198e8457..dc05eb2968 100644 Binary files a/F3DEX3/F3DEX3_BrW_NOC.code.bps and b/F3DEX3/F3DEX3_BrW_NOC.code.bps differ diff --git a/F3DEX3/F3DEX3_BrW_NOC.data.bps b/F3DEX3/F3DEX3_BrW_NOC.data.bps index 081bf4d106..1e0fdedd73 100644 Binary files a/F3DEX3/F3DEX3_BrW_NOC.data.bps and b/F3DEX3/F3DEX3_BrW_NOC.data.bps differ diff --git a/F3DEX3/F3DEX3_BrW_NOC_PA.code.bps b/F3DEX3/F3DEX3_BrW_NOC_PA.code.bps index f8a7477add..564f956864 100644 Binary files a/F3DEX3/F3DEX3_BrW_NOC_PA.code.bps and b/F3DEX3/F3DEX3_BrW_NOC_PA.code.bps differ diff --git a/F3DEX3/F3DEX3_BrW_NOC_PA.data.bps b/F3DEX3/F3DEX3_BrW_NOC_PA.data.bps index 4075990a34..8ec527bd7e 100644 Binary files a/F3DEX3/F3DEX3_BrW_NOC_PA.data.bps and b/F3DEX3/F3DEX3_BrW_NOC_PA.data.bps differ diff --git a/F3DEX3/F3DEX3_BrW_NOC_PB.code.bps b/F3DEX3/F3DEX3_BrW_NOC_PB.code.bps index 9f4b8ab38e..ebba9d608d 100644 Binary files a/F3DEX3/F3DEX3_BrW_NOC_PB.code.bps and b/F3DEX3/F3DEX3_BrW_NOC_PB.code.bps differ diff --git a/F3DEX3/F3DEX3_BrW_NOC_PB.data.bps b/F3DEX3/F3DEX3_BrW_NOC_PB.data.bps index f8cdc3abb5..41d89c19fb 100644 Binary files a/F3DEX3/F3DEX3_BrW_NOC_PB.data.bps and b/F3DEX3/F3DEX3_BrW_NOC_PB.data.bps differ diff --git a/F3DEX3/F3DEX3_BrW_NOC_PC.code.bps b/F3DEX3/F3DEX3_BrW_NOC_PC.code.bps index 3c67794fdc..3df9fb567a 100644 Binary files a/F3DEX3/F3DEX3_BrW_NOC_PC.code.bps and b/F3DEX3/F3DEX3_BrW_NOC_PC.code.bps differ diff --git a/F3DEX3/F3DEX3_BrW_NOC_PC.data.bps b/F3DEX3/F3DEX3_BrW_NOC_PC.data.bps index a398eb2a86..3707a35800 100644 Binary files a/F3DEX3/F3DEX3_BrW_NOC_PC.data.bps and b/F3DEX3/F3DEX3_BrW_NOC_PC.data.bps differ diff --git a/F3DEX3/F3DEX3_BrW_PA.code.bps b/F3DEX3/F3DEX3_BrW_PA.code.bps index 7fcf493236..8b5b60723d 100644 Binary files a/F3DEX3/F3DEX3_BrW_PA.code.bps and b/F3DEX3/F3DEX3_BrW_PA.code.bps differ diff --git a/F3DEX3/F3DEX3_BrW_PA.data.bps b/F3DEX3/F3DEX3_BrW_PA.data.bps index c2bef5814c..c606e60fe0 100644 Binary files a/F3DEX3/F3DEX3_BrW_PA.data.bps and b/F3DEX3/F3DEX3_BrW_PA.data.bps differ diff --git a/F3DEX3/F3DEX3_BrW_PB.code.bps b/F3DEX3/F3DEX3_BrW_PB.code.bps index b098cb33bf..28d82b7cdb 100644 Binary files a/F3DEX3/F3DEX3_BrW_PB.code.bps and b/F3DEX3/F3DEX3_BrW_PB.code.bps differ diff --git a/F3DEX3/F3DEX3_BrW_PB.data.bps b/F3DEX3/F3DEX3_BrW_PB.data.bps index 2ab8b5ac8b..cb5948acfc 100644 Binary files a/F3DEX3/F3DEX3_BrW_PB.data.bps and b/F3DEX3/F3DEX3_BrW_PB.data.bps differ diff --git a/F3DEX3/F3DEX3_BrW_PC.code.bps b/F3DEX3/F3DEX3_BrW_PC.code.bps index 83e25ffb1d..86569b0683 100644 Binary files a/F3DEX3/F3DEX3_BrW_PC.code.bps and b/F3DEX3/F3DEX3_BrW_PC.code.bps differ diff --git a/F3DEX3/F3DEX3_BrW_PC.data.bps b/F3DEX3/F3DEX3_BrW_PC.data.bps index 3356cd5d80..2756caf107 100644 Binary files a/F3DEX3/F3DEX3_BrW_PC.data.bps and b/F3DEX3/F3DEX3_BrW_PC.data.bps differ diff --git a/include/functions.h b/include/functions.h index 23eb5dfc30..efc2b88332 100644 --- a/include/functions.h +++ b/include/functions.h @@ -1086,6 +1086,7 @@ Gfx* Gfx_TwoTexScrollEnvColor(GraphicsContext* gfxCtx, s32 tile1, u32 x1, u32 y1 u32 x2, u32 y2, s32 width2, s32 height2, s32 r, s32 g, s32 b, s32 a); Gfx* Gfx_EnvColor(GraphicsContext* gfxCtx, s32 r, s32 g, s32 b, s32 a); void Gfx_SetupFrame(GraphicsContext* gfxCtx, s32 clearFB, u8 r, u8 g, u8 b); +void Gfx_ClearZBuffer(GraphicsContext* gfxCtx); void func_80095974(GraphicsContext* gfxCtx); void func_80095AA0(PlayState* play, Room* room, Input* input, s32 arg3); void Room_DrawBackground2D(Gfx** gfxP, void* tex, void* tlut, u16 width, u16 height, u8 fmt, u8 siz, u16 tlutMode, diff --git a/include/ultra64/gbi.f3dex3.h b/include/ultra64/gbi.f3dex3.h index 15d01f9447..1f49fa30dd 100644 --- a/include/ultra64/gbi.f3dex3.h +++ b/include/ultra64/gbi.f3dex3.h @@ -44,6 +44,7 @@ of warnings if you use -Wpedantic. */ /*#define G_SPECIAL_3 0xD3 no-op in F3DEX2 */ /*#define G_SPECIAL_2 0xD4 no-op in F3DEX2 */ /*#define G_SPECIAL_1 0xD5 triggered MVP recalculation, not supported in F3DEX3 */ +#define G_MEMSET 0xD5 #define G_DMA_IO 0xD6 #define G_TEXTURE 0xD7 #define G_POPMTX 0xD8 @@ -2385,6 +2386,25 @@ _DW({ \ #define gSPDmaWrite(pkt,dmem,dram,size) gSPDma_io((pkt),1,(dmem),(dram),(size)) #define gsSPDmaWrite(dmem,dram,size) gsSPDma_io( 1,(dmem),(dram),(size)) +/** + * Use RSP DMAs to set a region of memory to a repeated 16-bit value. This can + * clear the color framebuffer or Z-buffer faster than the RDP can in fill mode. + * SPMemset overwrites the DMEM vertex buffer, so vertices loaded before this + * command cannot be used after it (though this would not normally be done). + * + * dram: Segmented or physical start address. Must be aligned to 16 bytes. + * value: 16-bit value to fill the memory with. e.g. 0 for color, 0xFFFC for Z. + * size: Size in bytes to fill, must be nonzero and a multiple of 16 bytes. + */ +#define gSPMemset(pkt, dram, value, size) \ +_DW({ \ + gImmp1(pkt, G_RDPHALF_1, ((value) & 0xFFFF)); \ + gDma0p(pkt, G_MEMSET, (dram), ((size) & 0xFFFFF0)); \ +}) + +#define gsSPMemset(pkt, dram, value, size) \ + gsImmp1(G_RDPHALF_1, ((value) & 0xFFFF)), \ + gsDma0p(G_MEMSET, (dram), ((size) & 0xFFFFF0)) /* * RSP short command (no DMA required) macros diff --git a/include/variables.h b/include/variables.h index 75fc491757..2a171a8c53 100644 --- a/include/variables.h +++ b/include/variables.h @@ -223,13 +223,7 @@ extern volatile s8 gLoadedF3DEX3Version; extern volatile s8 gF3DEX3ProfVersion; extern volatile s8 gF3DEX3NOCVersion; extern s8 gF3DEX3OccMode; -#endif - -#if ENABLE_F3DEX3 -extern u8 gF3DEX3TextBuffer[]; -extern volatile s8 gF3DEX3ProfVersion; -extern volatile s8 gF3DEX3NOCVersion; -extern s8 gF3DEX3OccMode; +extern u8 gUseMemsetForZBuffer; #endif extern SfxBankEntry D_8016BAD0[9]; diff --git a/src/code/z_play.c b/src/code/z_play.c index 007023d312..d04db072f6 100644 --- a/src/code/z_play.c +++ b/src/code/z_play.c @@ -1258,7 +1258,7 @@ void Play_Draw(PlayState* this) { clearG = this->lightCtx.fogColor[1]; clearB = this->lightCtx.fogColor[2]; } - // Clear the fb only if we aren't drawing a skybox, but always clear zb + // Clear the fb only if we aren't drawing a skybox Gfx_SetupFrame(gfxCtx, clearFB, clearR, clearG, clearB); } @@ -1378,6 +1378,15 @@ void Play_Draw(PlayState* this) { Environment_DrawSkyboxFilters(this); } + // The Z buffer has to be cleared at some point before anything using it + // is drawn (lighting strike is the first which does). But if we are + // using F3DEX3's SPMemset to clear it, it should be done as late as + // possible, after the RSP has already sent commands to the RDP for the + // skybox or framebuffer clear. This is so that the RSP can clear the Z + // buffer while the RDP is working on the framebuffer, without making + // the RDP wait for new work to be available. + Gfx_ClearZBuffer(gfxCtx); + if (!IS_DEBUG || (R_HREG_MODE != HREG_MODE_PLAY) || (R_PLAY_DRAW_ENV_FLAGS & PLAY_ENV_DRAW_LIGHTNING)) { Environment_UpdateLightningStrike(this); Environment_DrawLightning(this, 0); diff --git a/src/code/z_prenmi.c b/src/code/z_prenmi.c index 0e0d2ed2e7..d8b6af8e78 100644 --- a/src/code/z_prenmi.c +++ b/src/code/z_prenmi.c @@ -34,6 +34,7 @@ void PreNMI_Draw(PreNMIState* this) { gSPSegment(POLY_OPA_DISP++, 0x00, NULL); Gfx_SetupFrame(gfxCtx, true, 0, 0, 0); + Gfx_ClearZBuffer(gfxCtx); Gfx_SetupDL_36Opa(gfxCtx); gDPSetFillColor(POLY_OPA_DISP++, (GPACK_RGBA5551(255, 255, 255, 1) << 16) | GPACK_RGBA5551(255, 255, 255, 1)); gDPFillRectangle(POLY_OPA_DISP++, 0, this->timer + 100, SCREEN_WIDTH - 1, this->timer + 100); diff --git a/src/code/z_rcp.c b/src/code/z_rcp.c index adbeff3b63..84f27878e1 100644 --- a/src/code/z_rcp.c +++ b/src/code/z_rcp.c @@ -1,5 +1,9 @@ #include "global.h" +#if ENABLE_F3DEX3 +u8 gUseMemsetForZBuffer = 1; +#endif + Gfx sSetupDL[SETUPDL_MAX][6] = { { /* SETUPDL_0 */ @@ -1472,7 +1476,6 @@ void Gfx_SetupFrame(GraphicsContext* gfxCtx, s32 clearFB, u8 r, u8 g, u8 b) { // Set up the framebuffer, primitives will be drawn here gDPSetColorImage(POLY_OPA_DISP++, G_IM_FMT_RGBA, G_IM_SIZ_16b, gScreenWidth, gfxCtx->curFrameBuffer); - gDPSetColorImage(POLY_OPA_DISP++, G_IM_FMT_RGBA, G_IM_SIZ_16b, gScreenWidth, gfxCtx->curFrameBuffer); gDPSetColorImage(POLY_XLU_DISP++, G_IM_FMT_RGBA, G_IM_SIZ_16b, gScreenWidth, gfxCtx->curFrameBuffer); gDPSetColorImage(OVERLAY_DISP++, G_IM_FMT_RGBA, G_IM_SIZ_16b, gScreenWidth, gfxCtx->curFrameBuffer); @@ -1529,17 +1532,8 @@ void Gfx_SetupFrame(GraphicsContext* gfxCtx, s32 clearFB, u8 r, u8 g, u8 b) { } #endif - // Set the whole z buffer to maximum depth - // Don't bother with pixels that are being covered by the letterbox - gDPSetColorImage(POLY_OPA_DISP++, G_IM_FMT_RGBA, G_IM_SIZ_16b, gScreenWidth, gZBuffer); - gDPSetRenderMode(POLY_OPA_DISP++, G_RM_NOOP, G_RM_NOOP2); - gDPSetFillColor(POLY_OPA_DISP++, (GPACK_ZDZ(G_MAXFBZ, 0) << 16) | GPACK_ZDZ(G_MAXFBZ, 0)); - gDPFillRectangle(POLY_OPA_DISP++, 0, letterboxSize, gScreenWidth - 1, gScreenHeight - letterboxSize - 1); - gDPPipeSync(POLY_OPA_DISP++); - // Fill the whole screen with the base color, only done when there is no skybox or if it is a solid color. // Don't bother with pixels that are being covered by the letterbox - gDPSetColorImage(POLY_OPA_DISP++, G_IM_FMT_RGBA, G_IM_SIZ_16b, gScreenWidth, gfxCtx->curFrameBuffer); if (clearFB) { gDPSetRenderMode(POLY_OPA_DISP++, G_RM_NOOP, G_RM_NOOP2); gDPSetFillColor(POLY_OPA_DISP++, (GPACK_RGBA5551(r, g, b, 1) << 16) | GPACK_RGBA5551(r, g, b, 1)); @@ -1560,6 +1554,36 @@ void Gfx_SetupFrame(GraphicsContext* gfxCtx, s32 clearFB, u8 r, u8 g, u8 b) { CLOSE_DISPS(gfxCtx, "../z_rcp.c", 2497); } +void Gfx_ClearZBuffer(GraphicsContext* gfxCtx) { + s32 letterboxSize = Letterbox_GetSize(); + OPEN_DISPS(gfxCtx, "../z_rcp.c", __LINE__); + + // Set the whole z buffer to maximum depth + // Don't bother with pixels that are being covered by the letterbox +#if ENABLE_F3DEX3 + if (gUseMemsetForZBuffer) { + s32 w2 = gScreenWidth * 2; // 2 bytes per pixel + if (letterboxSize < 0 || letterboxSize > 100) { + letterboxSize = 0; + } + gSPMemset(POLY_OPA_DISP++, (u8*)gZBuffer + letterboxSize * w2, GPACK_ZDZ(G_MAXFBZ, 0), + (gScreenHeight - 2 * letterboxSize) * w2); + } else { +#endif + gSPDisplayList(POLY_OPA_DISP++, sFillSetupDL); + gDPSetColorImage(POLY_OPA_DISP++, G_IM_FMT_RGBA, G_IM_SIZ_16b, gScreenWidth, gZBuffer); + gDPSetRenderMode(POLY_OPA_DISP++, G_RM_NOOP, G_RM_NOOP2); + gDPSetFillColor(POLY_OPA_DISP++, (GPACK_ZDZ(G_MAXFBZ, 0) << 16) | GPACK_ZDZ(G_MAXFBZ, 0)); + gDPFillRectangle(POLY_OPA_DISP++, 0, letterboxSize, gScreenWidth - 1, gScreenHeight - letterboxSize - 1); + gDPPipeSync(POLY_OPA_DISP++); + gDPSetColorImage(POLY_OPA_DISP++, G_IM_FMT_RGBA, G_IM_SIZ_16b, gScreenWidth, gfxCtx->curFrameBuffer); +#if ENABLE_F3DEX3 + } +#endif + + CLOSE_DISPS(gfxCtx, "../z_rcp.c", __LINE__); +} + void func_80095974(GraphicsContext* gfxCtx) { OPEN_DISPS(gfxCtx, "../z_rcp.c", 2503); diff --git a/src/code/z_sample.c b/src/code/z_sample.c index 0f31fc299a..e76b7ad3e7 100644 --- a/src/code/z_sample.c +++ b/src/code/z_sample.c @@ -17,6 +17,7 @@ void Sample_Draw(SampleState* this) { gSPSegment(POLY_OPA_DISP++, 0x01, this->staticSegment); Gfx_SetupFrame(gfxCtx, true, 0, 0, 0); + Gfx_ClearZBuffer(gfxCtx); view->flags = VIEW_VIEWING | VIEW_VIEWPORT | VIEW_PROJECTION_PERSPECTIVE; View_Apply(view, VIEW_ALL); diff --git a/src/overlays/gamestates/ovl_file_choose/z_file_choose.c b/src/overlays/gamestates/ovl_file_choose/z_file_choose.c index 4a8450fd00..156fd0f8f9 100644 --- a/src/overlays/gamestates/ovl_file_choose/z_file_choose.c +++ b/src/overlays/gamestates/ovl_file_choose/z_file_choose.c @@ -69,6 +69,7 @@ void FileSelect_InitModeDraw(GameState* thisx) { FileSelectState* this = (FileSelectState*)thisx; Gfx_SetupFrame(this->state.gfxCtx, true, 0, 0, 0); + Gfx_ClearZBuffer(this->state.gfxCtx); } /** @@ -1136,6 +1137,7 @@ void FileSelect_ConfigModeDraw(GameState* thisx) { Gfx_SetupFrame(this->state.gfxCtx, false, 0, 0, 0); Skybox_Draw(&this->skyboxCtx, this->state.gfxCtx, NULL, SKYBOX_NORMAL_SKY, this->envCtx.skyboxBlend, eyeX, eyeY, eyeZ); + Gfx_ClearZBuffer(this->state.gfxCtx); gDPSetTextureLUT(POLY_OPA_DISP++, G_TT_NONE); ZREG(11) += ZREG(10); Environment_UpdateSkybox(SKYBOX_NORMAL_SKY, &this->envCtx, &this->skyboxCtx); @@ -1551,6 +1553,7 @@ void FileSelect_SelectModeDraw(GameState* thisx) { Gfx_SetupFrame(this->state.gfxCtx, false, 0, 0, 0); Skybox_Draw(&this->skyboxCtx, this->state.gfxCtx, NULL, SKYBOX_NORMAL_SKY, this->envCtx.skyboxBlend, eyeX, eyeY, eyeZ); + Gfx_ClearZBuffer(this->state.gfxCtx); gDPSetTextureLUT(POLY_OPA_DISP++, G_TT_NONE); ZREG(11) += ZREG(10); Environment_UpdateSkybox(SKYBOX_NORMAL_SKY, &this->envCtx, &this->skyboxCtx); diff --git a/src/overlays/gamestates/ovl_opening/z_opening.c b/src/overlays/gamestates/ovl_opening/z_opening.c index 3ba1db3718..5b806eb904 100644 --- a/src/overlays/gamestates/ovl_opening/z_opening.c +++ b/src/overlays/gamestates/ovl_opening/z_opening.c @@ -69,6 +69,7 @@ void TitleSetup_Main(GameState* thisx) { TitleSetupState* this = (TitleSetupState*)thisx; Gfx_SetupFrame(this->state.gfxCtx, true, 0, 0, 0); + Gfx_ClearZBuffer(this->state.gfxCtx); TitleSetup_SetupTitleScreen(this); func_80803C5C(this); } diff --git a/src/overlays/gamestates/ovl_select/z_select.c b/src/overlays/gamestates/ovl_select/z_select.c index ac7dafc626..24924e418b 100644 --- a/src/overlays/gamestates/ovl_select/z_select.c +++ b/src/overlays/gamestates/ovl_select/z_select.c @@ -92,6 +92,7 @@ void MapSelect_Draw(MapSelectState* this) { Gfx_SetupFrame(gfxCtx, true, 0, 0, 0); SET_FULLSCREEN_VIEWPORT(&this->view); View_Apply(&this->view, VIEW_ALL); + Gfx_SetupDL_28Opa(gfxCtx); if (!this->state.running) { MapSelect_DrawLoadingScreen(this); @@ -333,12 +334,6 @@ void MapSelect_DrawMenu(MapSelectState* this) { OPEN_DISPS(gfxCtx, __FILE__, __LINE__); - gSPSegment(POLY_OPA_DISP++, 0x00, NULL); - Gfx_SetupFrame(gfxCtx, true, 0, 0, 0); - SET_FULLSCREEN_VIEWPORT(&this->view); - View_Apply(&this->view, VIEW_ALL); - Gfx_SetupDL_28Opa(gfxCtx); - printer = alloca(sizeof(GfxPrint)); GfxPrint_Init(printer); GfxPrint_Open(printer, POLY_OPA_DISP); @@ -366,12 +361,6 @@ void MapSelect_DrawLoadingScreen(MapSelectState* this) { OPEN_DISPS(gfxCtx, __FILE__, __LINE__); - gSPSegment(POLY_OPA_DISP++, 0x00, NULL); - Gfx_SetupFrame(gfxCtx, true, 0, 0, 0); - SET_FULLSCREEN_VIEWPORT(&this->view); - View_Apply(&this->view, VIEW_ALL); - Gfx_SetupDL_28Opa(gfxCtx); - printer = alloca(sizeof(GfxPrint)); GfxPrint_Init(printer); GfxPrint_Open(printer, POLY_OPA_DISP); diff --git a/src/overlays/gamestates/ovl_title/z_title.c b/src/overlays/gamestates/ovl_title/z_title.c index 7d7fd5b54b..748b3b1daf 100644 --- a/src/overlays/gamestates/ovl_title/z_title.c +++ b/src/overlays/gamestates/ovl_title/z_title.c @@ -155,6 +155,7 @@ void ConsoleLogo_Main(GameState* thisx) { gSPSegment(POLY_OPA_DISP++, 0, NULL); gSPSegment(POLY_OPA_DISP++, 1, this->staticSegment); Gfx_SetupFrame(this->state.gfxCtx, true, 0, 0, 0); + Gfx_ClearZBuffer(this->state.gfxCtx); ConsoleLogo_Calc(this); ConsoleLogo_Draw(this);