Skip to content

Commit

Permalink
GPU: Implement the DISPCNT register's ForceBlank bit by clearing the …
Browse files Browse the repository at this point in the history
…line to white if the ForceBlank bit is set. (Fixes #775.)
  • Loading branch information
rogerman committed Mar 2, 2024
1 parent 0a6eca6 commit bae67e2
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 40 deletions.
102 changes: 64 additions & 38 deletions desmume/src/GPU.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -2940,13 +2945,20 @@ void GPUEngineBase::RenderLayerBG(const GPULayerID layerID, u16 *dstColorBuffer)
}
}

void GPUEngineBase::_HandleDisplayModeOff(const size_t l)
void GPUEngineBase::_RenderLineBlank(const size_t l)
{
// Native rendering only.
// In this display mode, the display is cleared to white.
// Just clear the line using white pixels.
memset_u16_fast<GPU_FRAMEBUFFER_NATIVE_WIDTH>(this->_targetDisplay->GetNativeBuffer16() + (l * GPU_FRAMEBUFFER_NATIVE_WIDTH), 0xFFFF);
}

void GPUEngineBase::_HandleDisplayModeOff(const size_t l)
{
// Native rendering only.
// In this display mode, the line is cleared to white.
this->_RenderLineBlank(l);
}

void GPUEngineBase::_HandleDisplayModeNormal(const size_t l)
{
if (!this->_isLineRenderNative[l])
Expand Down Expand Up @@ -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<OUTPUTFORMAT>(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<OUTPUTFORMAT>(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
Expand Down Expand Up @@ -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<OUTPUTFORMAT, true>(compInfo);
}
else
case GPUDisplayMode_Off: // Display Off (clear line to white)
this->_HandleDisplayModeOff(l);
break;

case GPUDisplayMode_Normal: // Display BG and OBJ layers
{
this->_RenderLine_Layers<OUTPUTFORMAT, false>(compInfo);
if (compInfo.renderState.isAnyWindowEnabled)
{
this->_RenderLine_Layers<OUTPUTFORMAT, true>(compInfo);
}
else
{
this->_RenderLine_Layers<OUTPUTFORMAT, false>(compInfo);
}

this->_HandleDisplayModeNormal(l);
break;
}

this->_HandleDisplayModeNormal(l);
break;
default:
break;
}

default:
break;
}

if (compInfo.line.indexNative >= 191)
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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())
{
Expand Down
7 changes: 5 additions & 2 deletions desmume/src/GPU.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)
Expand Down Expand Up @@ -1543,6 +1543,8 @@ class GPUEngineBase
void _RenderLine_SetupSprites(GPUEngineCompositorInfo &compInfo);
template<NDSColorFormat OUTPUTFORMAT, bool WILLPERFORMWINDOWTEST> void _RenderLine_Layers(GPUEngineCompositorInfo &compInfo);

void _RenderLineBlank(const size_t l);

void _HandleDisplayModeOff(const size_t l);
void _HandleDisplayModeNormal(const size_t l);

Expand Down Expand Up @@ -1609,6 +1611,7 @@ class GPUEngineBase

const GPU_IOREG& GetIORegisterMap() const;

bool IsForceBlankSet() const;
bool IsMasterBrightMaxOrMin() const;

bool GetEnableState();
Expand Down

0 comments on commit bae67e2

Please sign in to comment.