From 3cfb3f7f25836b8abbc21a8fbecd54ae81800e41 Mon Sep 17 00:00:00 2001 From: Sour Date: Sat, 2 Mar 2019 18:00:27 -0500 Subject: [PATCH] PPU: Improved hires/interlace support (allow mid-screen changes) --- Core/Ppu.cpp | 71 ++++++++++++++++++++++++++++++---------------------- Core/Ppu.h | 3 +++ 2 files changed, 44 insertions(+), 30 deletions(-) diff --git a/Core/Ppu.cpp b/Core/Ppu.cpp index 7f2be90..5ab4702 100644 --- a/Core/Ppu.cpp +++ b/Core/Ppu.cpp @@ -131,7 +131,7 @@ void Ppu::EvaluateNextLineSprites() memset(_spritePixels, 0xFF, sizeof(_spritePixels)); memset(_spritePalette, 0, sizeof(_spritePalette)); _spriteCount = 0; - uint16_t screenY = _objInterlace ? ((_frameCount & 0x01) ? ((_scanline << 1) + 1) : (_scanline << 1)) : _scanline; + uint16_t screenY = _scanline; uint16_t baseAddr = _enableOamPriority ? (_internalOamAddress & 0x1FC) : 0; for(int i = 0; i < 512; i += 4) { @@ -143,6 +143,9 @@ void Ppu::EvaluateNextLineSprites() uint8_t highTableValue = _oamRam[0x200 | highTableOffset] >> shift; uint8_t largeSprite = (highTableValue & 0x02) >> 1; uint8_t height = _oamSizes[_oamMode][largeSprite][1] << 3; + if(_objInterlace) { + height /= 2; + } if(y > screenY || y + height <= screenY) { //Not visible on this scanline @@ -188,12 +191,17 @@ void Ppu::EvaluateNextLineSprites() uint8_t yOffset; int rowOffset; + int yGap = (screenY - info.Y); + if(_objInterlace) { + yGap <<= 1; + yGap |= (_frameCount & 0x01); + } if(info.VerticalMirror) { - yOffset = (height - 1 - (screenY - info.Y)) & 0x07; - rowOffset = (height - 1 - (screenY - info.Y)) >> 3; + yOffset = (height - 1 - yGap) & 0x07; + rowOffset = (height - 1 - yGap) >> 3; } else { - yOffset = (screenY - info.Y) & 0x07; - rowOffset = (screenY - info.Y) >> 3; + yOffset = yGap & 0x07; + rowOffset = yGap >> 3; } uint8_t row = (info.TileRow + rowOffset) & 0x0F; @@ -232,10 +240,6 @@ void Ppu::EvaluateNextLineSprites() _spritePalette[x] = info.Palette; } } - - if(_timeOver) { - break; - } } } @@ -503,7 +507,7 @@ void Ppu::RenderTilemap() } /* Current scanline (in interlaced mode, switches between even and odd rows every frame */ - uint16_t realY = _screenInterlace ? ((_frameCount & 0x01) ? ((_scanline << 1) + 1) : (_scanline << 1)) : _scanline; + uint16_t realY = IsDoubleHeight() ? ((_frameCount & 0x01) ? ((_scanline << 1) + 1) : (_scanline << 1)) : _scanline; /* True when the entire scanline has to be replaced by a mosaic pattern */ bool mosaicScanline = applyMosaic && (realY - _mosaicStartScanline) % _mosaicSize != 0; @@ -533,7 +537,7 @@ void Ppu::RenderTilemap() uint16_t baseOffset = tilemapAddr + addrVerticalScrollingOffset + ((row & 0x1F) << 5); uint16_t vScroll = config.VScroll; - uint16_t hScroll = config.HScroll; + uint16_t hScroll = IsDoubleWidth() ? (config.HScroll << 1) : config.HScroll; //"Offset per tile" mode (modes 2, 4 and 6 support this) bool offsetPerTileMode = (_bgMode & 0x03) == 2; @@ -965,16 +969,24 @@ void Ppu::ApplyBrightness() void Ppu::ApplyHiResMode() { uint16_t scanline = _scanline - 1; - uint32_t screenY = _screenInterlace ? ((_frameCount & 0x01) ? ((scanline << 1) + 1) : (scanline << 1)) : scanline; + uint32_t screenY = IsDoubleHeight() ? ((_frameCount & 0x01) ? ((scanline << 1) + 1) : (scanline << 1)) : (scanline << 1); + uint32_t baseAddr = (screenY << 9); - if(_hiResMode || _bgMode == 5 || _bgMode == 6) { + if(IsDoubleWidth()) { ApplyBrightness(); for(int i = 0; i < 512; i += 2) { - _currentBuffer[(screenY << 9) + i] = _subScreenBuffer[i >> 1]; - _currentBuffer[(screenY << 9) + i + 1] = _mainScreenBuffer[i >> 1]; + _currentBuffer[baseAddr + i] = _subScreenBuffer[i >> 1]; + _currentBuffer[baseAddr + i + 1] = _mainScreenBuffer[i >> 1]; } } else { - memcpy(_currentBuffer + (screenY << 8), _mainScreenBuffer, sizeof(_mainScreenBuffer)); + for(int i = 0; i < 512; i += 2) { + _currentBuffer[baseAddr + i] = _mainScreenBuffer[i >> 1]; + _currentBuffer[baseAddr + i + 1] = _mainScreenBuffer[i >> 1]; + } + } + + if(!IsDoubleHeight()) { + memcpy(_currentBuffer + baseAddr + 512, _currentBuffer + baseAddr, 512 * 2); } } @@ -1015,19 +1027,8 @@ void Ppu::SendFrame() { _console->GetNotificationManager()->SendNotification(ConsoleNotificationType::PpuFrameDone); - uint16_t width; - uint16_t height; - if(_hiResMode || _bgMode == 5 || _bgMode == 6) { - width = 512; - } else { - width = 256; - } - - if(_screenInterlace && (_bgMode == 5 || _bgMode == 6)) { - height = _overscanMode ? 478 : 448; - } else { - height = _overscanMode ? 239 : 224; - } + uint16_t width = 512; + uint16_t height = _overscanMode ? 478 : 448; if(_screenInterlace) { _console->GetVideoDecoder()->UpdateFrameSync(_currentBuffer, width, height, _frameCount); @@ -1052,6 +1053,16 @@ uint8_t* Ppu::GetSpriteRam() return _oamRam; } +bool Ppu::IsDoubleHeight() +{ + return _screenInterlace && (_bgMode == 5 || _bgMode == 6); +} + +bool Ppu::IsDoubleWidth() +{ + return _hiResMode || _bgMode == 5 || _bgMode == 6; +} + void Ppu::LatchLocationValues() { _horizontalLocation = _cycle; @@ -1579,7 +1590,7 @@ void Ppu::RenderTilemap() template void Ppu::RenderTilemap() { - if(_hiResMode || _bgMode == 5 || _bgMode == 6) { + if(IsDoubleWidth()) { RenderTilemap(); } else { RenderTilemap(); diff --git a/Core/Ppu.h b/Core/Ppu.h index 7ee1ca5..8353b75 100644 --- a/Core/Ppu.h +++ b/Core/Ppu.h @@ -212,6 +212,9 @@ private: void SendFrame(); + bool IsDoubleHeight(); + bool IsDoubleWidth(); + public: Ppu(shared_ptr console); ~Ppu();