From bae67e2d0ca9ea49b61392b47ca1e732b9b68946 Mon Sep 17 00:00:00 2001 From: rogerman Date: Sat, 2 Mar 2024 15:18:51 -0800 Subject: [PATCH] GPU: Implement the DISPCNT register's ForceBlank bit by clearing the line to white if the ForceBlank bit is set. (Fixes #775.) --- desmume/src/GPU.cpp | 104 +++++++++++++++++++++++++++----------------- desmume/src/GPU.h | 7 ++- 2 files changed, 70 insertions(+), 41 deletions(-) diff --git a/desmume/src/GPU.cpp b/desmume/src/GPU.cpp index 66696443d..8081ad2b0 100644 --- a/desmume/src/GPU.cpp +++ b/desmume/src/GPU.cpp @@ -924,6 +924,11 @@ const GPU_IOREG& GPUEngineBase::GetIORegisterMap() const return *this->_IORegisterMap; } +bool GPUEngineBase::IsForceBlankSet() const +{ + return (this->_IORegisterMap->DISPCNT.ForceBlank != 0); +} + bool GPUEngineBase::IsMasterBrightMaxOrMin() const { return this->_currentRenderState.masterBrightnessIsMaxOrMin; @@ -2940,11 +2945,18 @@ void GPUEngineBase::RenderLayerBG(const GPULayerID layerID, u16 *dstColorBuffer) } } +void GPUEngineBase::_RenderLineBlank(const size_t l) +{ + // Native rendering only. + // Just clear the line using white pixels. + memset_u16_fast(this->_targetDisplay->GetNativeBuffer16() + (l * GPU_FRAMEBUFFER_NATIVE_WIDTH), 0xFFFF); +} + void GPUEngineBase::_HandleDisplayModeOff(const size_t l) { // Native rendering only. - // In this display mode, the display is cleared to white. - memset_u16_fast(this->_targetDisplay->GetNativeBuffer16() + (l * GPU_FRAMEBUFFER_NATIVE_WIDTH), 0xFFFF); + // In this display mode, the line is cleared to white. + this->_RenderLineBlank(l); } void GPUEngineBase::_HandleDisplayModeNormal(const size_t l) @@ -3536,23 +3548,30 @@ void GPUEngineA::RenderLine(const size_t l) } // Fill the display output - switch (compInfo.renderState.displayOutputMode) + if ( this->IsForceBlankSet() ) { - case GPUDisplayMode_Off: // Display Off (Display white) - this->_HandleDisplayModeOff(l); - break; - - case GPUDisplayMode_Normal: // Display BG and OBJ layers - this->_HandleDisplayModeNormal(l); - break; - - case GPUDisplayMode_VRAM: // Display VRAM framebuffer - this->_HandleDisplayModeVRAM(compInfo.line); - break; - - case GPUDisplayMode_MainMemory: // Display Memory FIFO - this->_HandleDisplayModeMainMemory(compInfo.line); - break; + this->_RenderLineBlank(l); + } + else + { + switch (compInfo.renderState.displayOutputMode) + { + case GPUDisplayMode_Off: // Display Off (clear line to white) + this->_HandleDisplayModeOff(l); + break; + + case GPUDisplayMode_Normal: // Display BG and OBJ layers + this->_HandleDisplayModeNormal(l); + break; + + case GPUDisplayMode_VRAM: // Display VRAM framebuffer + this->_HandleDisplayModeVRAM(compInfo.line); + break; + + case GPUDisplayMode_MainMemory: // Display Memory FIFO + this->_HandleDisplayModeMainMemory(compInfo.line); + break; + } } //capture after displaying so that we can safely display vram before overwriting it here @@ -4533,29 +4552,36 @@ void GPUEngineB::RenderLine(const size_t l) { GPUEngineCompositorInfo &compInfo = this->_currentCompositorInfo[l]; - switch (compInfo.renderState.displayOutputMode) + if ( this->IsForceBlankSet() ) { - case GPUDisplayMode_Off: // Display Off(Display white) - this->_HandleDisplayModeOff(l); - break; - - case GPUDisplayMode_Normal: // Display BG and OBJ layers + this->_RenderLineBlank(l); + } + else + { + switch (compInfo.renderState.displayOutputMode) { - if (compInfo.renderState.isAnyWindowEnabled) - { - this->_RenderLine_Layers(compInfo); - } - else - { - this->_RenderLine_Layers(compInfo); - } + case GPUDisplayMode_Off: // Display Off (clear line to white) + this->_HandleDisplayModeOff(l); + break; - this->_HandleDisplayModeNormal(l); - break; + case GPUDisplayMode_Normal: // Display BG and OBJ layers + { + if (compInfo.renderState.isAnyWindowEnabled) + { + this->_RenderLine_Layers(compInfo); + } + else + { + this->_RenderLine_Layers(compInfo); + } + + this->_HandleDisplayModeNormal(l); + break; + } + + default: + break; } - - default: - break; } if (compInfo.line.indexNative >= 191) @@ -5454,7 +5480,7 @@ void GPUSubsystem::RenderLine(const size_t l) this->_engineSub->UpdateRenderStates(l); } - if ( (isFramebufferRenderNeeded[GPUEngineID_Main] || isDisplayCaptureNeeded) && !this->_willFrameSkip ) + if ( (isFramebufferRenderNeeded[GPUEngineID_Main] || this->_engineMain->IsForceBlankSet() || isDisplayCaptureNeeded) && !this->_willFrameSkip ) { // GPUEngineA:WillRender3DLayer() and GPUEngineA:WillCapture3DLayerDirect() both rely on register // states that might change on a per-line basis. Therefore, we need to check these states on a @@ -5502,7 +5528,7 @@ void GPUSubsystem::RenderLine(const size_t l) this->_engineMain->UpdatePropertiesWithoutRender(l); } - if (isFramebufferRenderNeeded[GPUEngineID_Sub] && !this->_willFrameSkip) + if ( (isFramebufferRenderNeeded[GPUEngineID_Sub] || this->_engineSub->IsForceBlankSet()) && !this->_willFrameSkip) { switch (this->_engineSub->GetTargetDisplay()->GetColorFormat()) { diff --git a/desmume/src/GPU.h b/desmume/src/GPU.h index 5808fa304..43ff7d44a 100644 --- a/desmume/src/GPU.h +++ b/desmume/src/GPU.h @@ -117,7 +117,7 @@ typedef union u8 OBJ_Tile_mapping:1; // 4: A+B; 0=2D (32KB), 1=1D (32..256KB) u8 OBJ_BMP_2D_dim:1; // 5: A+B; 0=128x512, 1=256x256 pixels u8 OBJ_BMP_mapping:1; // 6: A+B; 0=2D (128KB), 1=1D (128..256KB) - u8 ForceBlank:1; // 7: A+B; + u8 ForceBlank:1; // 7: A+B; 0=Disable, 1=Enable (causes the line to render all white) u8 BG0_Enable:1; // 8: A+B; 0=Disable, 1=Enable u8 BG1_Enable:1; // 9: A+B; 0=Disable, 1=Enable @@ -143,7 +143,7 @@ typedef union u8 ExBGxPalette_Enable:1; // 30: A+B; 0=Disable, 1=Enable BG extended Palette u8 ExOBJPalette_Enable:1; // 31: A+B; 0=Disable, 1=Enable OBJ extended Palette #else - u8 ForceBlank:1; // 7: A+B; + u8 ForceBlank:1; // 7: A+B; 0=Disable, 1=Enable (causes the line to render all white) u8 OBJ_BMP_mapping:1; // 6: A+B; 0=2D (128KB), 1=1D (128..256KB) u8 OBJ_BMP_2D_dim:1; // 5: A+B; 0=128x512, 1=256x256 pixels u8 OBJ_Tile_mapping:1; // 4: A+B; 0=2D (32KB), 1=1D (32..256KB) @@ -1543,6 +1543,8 @@ protected: void _RenderLine_SetupSprites(GPUEngineCompositorInfo &compInfo); template void _RenderLine_Layers(GPUEngineCompositorInfo &compInfo); + void _RenderLineBlank(const size_t l); + void _HandleDisplayModeOff(const size_t l); void _HandleDisplayModeNormal(const size_t l); @@ -1609,6 +1611,7 @@ public: const GPU_IOREG& GetIORegisterMap() const; + bool IsForceBlankSet() const; bool IsMasterBrightMaxOrMin() const; bool GetEnableState();