From 85f1333c3d0194fb897dccf201aec6987c88ea5a Mon Sep 17 00:00:00 2001 From: Sour Date: Sat, 23 Feb 2019 21:39:35 -0500 Subject: [PATCH] PPU: Support for mode 5, hires, interlace, and overscan mode --- Core/BaseVideoFilter.cpp | 10 ++ Core/BaseVideoFilter.h | 5 +- Core/DefaultVideoFilter.cpp | 9 +- Core/DefaultVideoFilter.h | 1 - Core/DrawCommand.h | 10 +- Core/Ppu.cpp | 229 +++++++++++++++++++++++------------- Core/Ppu.h | 18 ++- Core/SettingTypes.h | 21 ---- Core/VideoDecoder.cpp | 33 ++++-- Core/VideoDecoder.h | 5 +- 10 files changed, 208 insertions(+), 133 deletions(-) diff --git a/Core/BaseVideoFilter.cpp b/Core/BaseVideoFilter.cpp index 281d806..2ae5fd7 100644 --- a/Core/BaseVideoFilter.cpp +++ b/Core/BaseVideoFilter.cpp @@ -20,6 +20,16 @@ BaseVideoFilter::~BaseVideoFilter() } } +void BaseVideoFilter::SetBaseFrameInfo(FrameInfo frameInfo) +{ + _baseFrameInfo = frameInfo; +} + +FrameInfo BaseVideoFilter::GetFrameInfo() +{ + return _baseFrameInfo; +} + void BaseVideoFilter::UpdateBufferSize() { uint32_t newBufferSize = GetFrameInfo().Width*GetFrameInfo().Height; diff --git a/Core/BaseVideoFilter.h b/Core/BaseVideoFilter.h index fc07cd4..c5fac71 100644 --- a/Core/BaseVideoFilter.h +++ b/Core/BaseVideoFilter.h @@ -13,6 +13,7 @@ private: SimpleLock _frameLock; OverscanDimensions _overscan; bool _isOddFrame; + FrameInfo _baseFrameInfo; void UpdateBufferSize(); @@ -33,5 +34,7 @@ public: void TakeScreenshot(VideoFilterType filterType, string filename, std::stringstream *stream = nullptr); virtual OverscanDimensions GetOverscan(); - virtual FrameInfo GetFrameInfo() = 0; + + void SetBaseFrameInfo(FrameInfo frameInfo); + virtual FrameInfo GetFrameInfo(); }; \ No newline at end of file diff --git a/Core/DefaultVideoFilter.cpp b/Core/DefaultVideoFilter.cpp index 66c5037..851030b 100644 --- a/Core/DefaultVideoFilter.cpp +++ b/Core/DefaultVideoFilter.cpp @@ -34,12 +34,6 @@ void DefaultVideoFilter::InitConversionMatrix(double hueShift, double saturation } } -FrameInfo DefaultVideoFilter::GetFrameInfo() -{ - OverscanDimensions overscan = GetOverscan(); - return { overscan.GetScreenWidth(), overscan.GetScreenHeight(), OverscanDimensions::ScreenWidth, OverscanDimensions::ScreenHeight, 4 }; -} - void DefaultVideoFilter::OnBeforeApplyFilter() { /*PictureSettings currentSettings = _console->GetSettings()->GetPictureSettings(); @@ -99,7 +93,8 @@ void DefaultVideoFilter::DecodePpuBuffer(uint16_t *ppuOutputBuffer, uint32_t* ou void DefaultVideoFilter::ApplyFilter(uint16_t *ppuOutputBuffer) { uint32_t *out = GetOutputBuffer(); - for(int i = 0; i < 256 * 224; i++) { + uint32_t pixelCount = GetFrameInfo().Width * GetFrameInfo().Height; + for(int i = 0; i < pixelCount; i++) { uint16_t rgb555 = ppuOutputBuffer[i]; uint8_t b = (rgb555 >> 10) * 256 / 32; uint8_t g = ((rgb555 >> 5) & 0x1F) * 256 / 32; diff --git a/Core/DefaultVideoFilter.h b/Core/DefaultVideoFilter.h index 4d3c44c..0bffdfa 100644 --- a/Core/DefaultVideoFilter.h +++ b/Core/DefaultVideoFilter.h @@ -24,5 +24,4 @@ protected: public: DefaultVideoFilter(shared_ptr console); void ApplyFilter(uint16_t *ppuOutputBuffer); - FrameInfo GetFrameInfo(); }; \ No newline at end of file diff --git a/Core/DrawCommand.h b/Core/DrawCommand.h index bacfc49..69c7826 100644 --- a/Core/DrawCommand.h +++ b/Core/DrawCommand.h @@ -20,12 +20,6 @@ protected: virtual void InternalDraw() = 0; __forceinline void DrawPixel(uint32_t x, uint32_t y, int color) { - if(x < _overscan.Left || x >= _overscan.Left + _overscan.GetScreenWidth() || - y < _overscan.Top || y >= _overscan.Top + _overscan.GetScreenHeight()) { - //In overscan (out of bounds), skip drawing - return; - } - uint32_t alpha = (color & 0xFF000000); if(alpha > 0) { if(_yScale == 1) { @@ -82,8 +76,8 @@ public: _argbBuffer = argbBuffer; _overscan = overscan; _lineWidth = lineWidth; - _yScale = lineWidth / overscan.GetScreenWidth(); - _xScale = (float)lineWidth / overscan.GetScreenWidth(); + _yScale = 1; //TODO + _xScale = 2; //TODO InternalDraw(); diff --git a/Core/Ppu.cpp b/Core/Ppu.cpp index e327351..50cebe6 100644 --- a/Core/Ppu.cpp +++ b/Core/Ppu.cpp @@ -14,8 +14,8 @@ Ppu::Ppu(shared_ptr console) _console = console; _regs = console->GetInternalRegisters(); - _outputBuffers[0] = new uint16_t[256 * 224]; - _outputBuffers[1] = new uint16_t[256 * 224]; + _outputBuffers[0] = new uint16_t[512 * 478]; + _outputBuffers[1] = new uint16_t[512 * 478]; _currentBuffer = _outputBuffers[0]; @@ -64,9 +64,9 @@ void Ppu::Exec() _rangeOver = false; _timeOver = false; - if(_scanline < 224) { + if(_scanline < (_overscanMode ? 240 : 224)) { RenderScanline(); - } else if(_scanline == 225) { + } else if(_scanline == (_overscanMode ? 241 : 225)) { //Reset OAM address at the start of vblank? if(!_forcedVblank) { _internalOamAddress = (_oamRamAddress << 1); @@ -238,8 +238,6 @@ void Ppu::RenderSprites() } if(forMainScreen) { - uint16_t outBaseAddress = (_scanline << 8); - for(int x = 0; x < 256; x++) { if(!_rowPixelFlags[x] && _spritePriority[x] == priority) { if(activeWindowCount && ProcessMaskWindow(activeWindowCount, x)) { @@ -247,7 +245,7 @@ void Ppu::RenderSprites() continue; } - _currentBuffer[outBaseAddress | x] = _spritePixels[x]; + _mainScreenBuffer[x] = _spritePixels[x]; _rowPixelFlags[x] |= PixelFlags::Filled | (((_colorMathEnabled & 0x10) && _spritePalette[x] > 3) ? PixelFlags::AllowColorMath : 0); } } @@ -347,6 +345,20 @@ void Ppu::RenderMode4() RenderBgColor(); } +template +void Ppu::RenderMode5() +{ + RenderSprites<3, forMainScreen>(); + RenderTilemap<0, 4, true, forMainScreen>(); + RenderSprites<2, forMainScreen>(); + RenderTilemap<1, 2, true, forMainScreen>(); + RenderSprites<1, forMainScreen>(); + RenderTilemap<0, 4, false, forMainScreen>(); + RenderSprites<0, forMainScreen>(); + RenderTilemap<1, 2, false, forMainScreen>(); + RenderBgColor(); +} + template void Ppu::RenderMode7() { @@ -388,32 +400,26 @@ void Ppu::RenderScanline() break; case 2: - MessageManager::Log("[Debug] Using mode 2"); RenderMode2(); RenderMode2(); break; case 3: - MessageManager::Log("[Debug] Using mode 3"); RenderMode3(); RenderMode3(); break; case 4: - MessageManager::Log("[Debug] Using mode 4"); RenderMode4(); RenderMode4(); break; case 5: - MessageManager::Log("[Debug] Using mode 5"); - RenderTilemap<1, 2, false, true>(); - RenderTilemap<0, 4, false, true>(); - RenderBgColor(); + RenderMode5(); + RenderMode5(); break; case 6: - MessageManager::Log("[Debug] Using mode 6"); RenderTilemap<0, 8, false, true>(); RenderBgColor(); break; @@ -425,7 +431,8 @@ void Ppu::RenderScanline() } ApplyColorMath(); - ApplyBrightness(); + ApplyBrightness(); + ApplyHiResMode(); //Process sprites for next scanline EvaluateNextLineSprites(); @@ -439,12 +446,11 @@ void Ppu::RenderBgColor() } uint16_t bgColor = _cgram[0] | (_cgram[1] << 8); - uint16_t outBaseAddress = (_scanline << 8); for(int x = 0; x < 256; x++) { if(forMainScreen) { if(!_rowPixelFlags[x]) { uint8_t pixelFlags = PixelFlags::Filled | ((_colorMathEnabled & 0x20) ? PixelFlags::AllowColorMath : 0); - _currentBuffer[outBaseAddress | x] = bgColor; + _mainScreenBuffer[x] = bgColor; _rowPixelFlags[x] = pixelFlags; } } else { @@ -455,8 +461,8 @@ void Ppu::RenderBgColor() } } -template -void Ppu::RenderTilemap() +template +void Ppu::RenderTilemapLargeTiles() { uint8_t activeWindowCount = 0; if((forMainScreen && _windowMaskMain[layerIndex]) || (!forMainScreen && _windowMaskSub[layerIndex])) { @@ -465,50 +471,49 @@ void Ppu::RenderTilemap() bool applyMosaic = forMainScreen && ((_mosaicEnabled >> layerIndex) & 0x01) != 0; - if(_layerConfig[layerIndex].LargeTiles) { - if(activeWindowCount == 0) { - if(applyMosaic) { - RenderTilemap(); - } else { - RenderTilemap(); - } - } else if(activeWindowCount == 1) { - if(applyMosaic) { - RenderTilemap(); - } else { - RenderTilemap(); - } + if(activeWindowCount == 0) { + if(applyMosaic) { + RenderTilemap(); } else { - if(applyMosaic) { - RenderTilemap(); - } else { - RenderTilemap(); - } + RenderTilemap(); + } + } else if(activeWindowCount == 1) { + if(applyMosaic) { + RenderTilemap(); + } else { + RenderTilemap(); } } else { - if(activeWindowCount == 0) { - if(applyMosaic) { - RenderTilemap(); - } else { - RenderTilemap(); - } - } else if(activeWindowCount == 1) { - if(applyMosaic) { - RenderTilemap(); - } else { - RenderTilemap(); - } + if(applyMosaic) { + RenderTilemap(); } else { - if(applyMosaic) { - RenderTilemap(); - } else { - RenderTilemap(); - } + RenderTilemap(); } } } -template +template +void Ppu::RenderTilemap() +{ + bool largeTileWidth = _layerConfig[layerIndex].LargeTiles || _bgMode == 5; + bool largeTileHeight = _layerConfig[layerIndex].LargeTiles; + + if(largeTileWidth) { + if(largeTileHeight) { + RenderTilemapLargeTiles(); + } else { + RenderTilemapLargeTiles(); + } + } else { + if(largeTileHeight) { + RenderTilemapLargeTiles(); + } else { + RenderTilemapLargeTiles(); + } + } +} + +template void Ppu::RenderTilemap() { if(forMainScreen) { @@ -523,23 +528,49 @@ void Ppu::RenderTilemap() } } - bool mosaicScanline = applyMosaic && (_scanline - _mosaicStartScanline) % _mosaicSize != 0; + /* 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; + /* True when the entire scanline has to be replaced by a mosaic pattern */ + bool mosaicScanline = applyMosaic && (realY - _mosaicStartScanline) % _mosaicSize != 0; + + /* Keeps track of whether or not the pixel is allowed to participate in color math */ uint8_t pixelFlags = PixelFlags::Filled | (((_colorMathEnabled >> layerIndex) & 0x01) ? PixelFlags::AllowColorMath : 0); + /* The current layer's options */ LayerConfig &config = _layerConfig[layerIndex]; - uint16_t tilemapAddr = config.TilemapAddress >> 1; - uint16_t chrAddr = config.ChrAddress; - uint16_t row = (_scanline + config.VScroll) >> (largeTiles ? 4 : 3); - uint8_t baseYOffset = (_scanline + config.VScroll) & 0x07; + /* Layer's tilemap start address */ + uint16_t tilemapAddr = config.TilemapAddress >> 1; + + /* Layer's CHR data start address */ + uint16_t chrAddr = config.ChrAddress; + + /* The current row of tiles (e.g scanlines 16-23 is row 2) */ + uint16_t row = (realY + config.VScroll) >> (largeTileHeight ? 4 : 3); + + /* The vertical offset to read in the tile we're processing */ + uint8_t baseYOffset = (realY + config.VScroll) & 0x07; + + /* Tilemap offset based on the current row & tilemap size options */ uint16_t addrVerticalScrollingOffset = config.VerticalMirroring ? ((row & 0x20) << (config.HorizontalMirroring ? 6 : 5)) : 0; + + /* The start address for tiles on this row */ uint16_t baseOffset = tilemapAddr + addrVerticalScrollingOffset + ((row & 0x1F) << 5); - uint16_t outBaseAddress = (_scanline << 8); - for(int x = 0; x < 256; x++) { - uint16_t column = (x + config.HScroll) >> (largeTiles ? 4 : 3); + /* The current pixel x position (normally 0-255, but 0-511 in hi-res mode - even on subscreen, odd on main screen) */ + uint16_t realX; + if(largeTileWidth && !largeTileHeight) { + realX = (x << 1) + (forMainScreen ? 1 : 0); + } else { + realX = x; + } + + /* The current column index (in terms of 8x8 or 16x16 tiles) */ + uint16_t column = (realX + config.HScroll) >> (largeTileWidth ? 4 : 3); + + /* The tilemap address to read the tile data from */ uint32_t addr = (baseOffset + (column & 0x1F) + (config.HorizontalMirroring ? ((column & 0x20) << 5) : 0)) << 1; //Skip pixels that were filled by previous layers (or that don't match the priority level currently being processed) @@ -560,7 +591,7 @@ void Ppu::RenderTilemap() if(applyMosaic && (mosaicScanline || x % _mosaicSize != 0)) { //If this is not the top-left pixels in the mosaic pattern, override it with the top-left pixel data - _currentBuffer[outBaseAddress | x] = _mosaicColor[x]; + _mainScreenBuffer[x] = _mosaicColor[x]; _rowPixelFlags[x] = pixelFlags; if(forMainScreen) { _pixelsDrawn++; @@ -575,11 +606,11 @@ void Ppu::RenderTilemap() bool hMirror = (_vram[addr + 1] & 0x40) != 0; uint16_t tileIndex = ((_vram[addr + 1] & 0x03) << 8) | _vram[addr]; - if(largeTiles) { + if(largeTileWidth || largeTileHeight) { tileIndex = ( tileIndex + - (((_scanline + config.VScroll) & 0x08) ? (vMirror ? 0 : 16) : (vMirror ? 16 : 0)) + - (((x + config.HScroll) & 0x08) ? (hMirror ? 0 : 1) : (hMirror ? 1 : 0)) + (largeTileHeight ? (((realY + config.VScroll) & 0x08) ? (vMirror ? 0 : 16) : (vMirror ? 16 : 0)) : 0) + + (largeTileWidth ? (((realX + config.HScroll) & 0x08) ? (hMirror ? 0 : 1) : (hMirror ? 1 : 0)) : 0) ) & 0x3FF; } @@ -588,8 +619,9 @@ void Ppu::RenderTilemap() uint8_t yOffset = vMirror ? (7 - baseYOffset) : baseYOffset; uint16_t pixelStart = tileStart + yOffset * 2; - uint8_t xOffset = (x + config.HScroll) & 0x07; + uint8_t xOffset = (realX + config.HScroll) & 0x07; uint8_t shift = hMirror ? xOffset : (7 - xOffset); + uint16_t color = 0; if(bpp == 2) { color |= (((_vram[pixelStart + 0] >> shift) & 0x01) << 0); @@ -628,8 +660,6 @@ void Ppu::RenderTilemap() template void Ppu::RenderTilemapMode7() { - uint16_t realY = _mode7.VerticalMirroring ? (255 - _scanline) : _scanline; - if(forMainScreen) { if(_pixelsDrawn == 256 || ((_mainScreenLayers >> layerIndex) & 0x01) == 0) { //This screen is disabled, or we've drawn all pixels already @@ -651,6 +681,7 @@ void Ppu::RenderTilemapMode7() int32_t vScroll = ((int32_t)_mode7.VScroll << 19) >> 19; int32_t centerX = ((int32_t)_mode7.CenterX << 19) >> 19; int32_t centerY = ((int32_t)_mode7.CenterY << 19) >> 19; + uint16_t realY = _mode7.VerticalMirroring ? (255 - _scanline) : _scanline; lutX[0] = ( ((_mode7.Matrix[0] * clip(hScroll - centerX)) & ~63) + @@ -731,7 +762,7 @@ void Ppu::RenderTilemapMode7() template void Ppu::DrawMainPixel(uint8_t x, uint16_t paletteRamOffset, uint8_t flags) { - _currentBuffer[(_scanline << 8) | x] = _cgram[paletteRamOffset] | (_cgram[paletteRamOffset + 1] << 8); + _mainScreenBuffer[x] = _cgram[paletteRamOffset] | (_cgram[paletteRamOffset + 1] << 8); _rowPixelFlags[x] = flags; if(applyMosaic && x % _mosaicSize == 0) { @@ -764,7 +795,7 @@ void Ppu::ApplyColorMath() for(int x = 0; x < 256; x++) { if(_rowPixelFlags[x] & PixelFlags::AllowColorMath) { uint8_t halfShift = _colorMathHalveResult ? 1 : 0; - uint16_t &mainPixel = _currentBuffer[outBaseAddress | x]; + uint16_t &mainPixel = _mainScreenBuffer[x]; bool isInsideWindow = activeWindowCount && ProcessMaskWindow(activeWindowCount, x); //Set color to black as needed based on clip mode @@ -839,13 +870,12 @@ void Ppu::ApplyColorMath() } } +template void Ppu::ApplyBrightness() { if(_screenBrightness != 15) { - uint16_t outBaseAddress = (_scanline << 8); - for(int x = 0; x < 256; x++) { - uint16_t &pixel = _currentBuffer[outBaseAddress | x]; + uint16_t &pixel = (forMainScreen ? _mainScreenBuffer : _subScreenBuffer)[x]; uint16_t r = (pixel & 0x1F) * _screenBrightness / 15; uint16_t g = ((pixel >> 5) & 0x1F) * _screenBrightness / 15; uint16_t b = ((pixel >> 10) & 0x1F) * _screenBrightness / 15; @@ -854,6 +884,21 @@ void Ppu::ApplyBrightness() } } +void Ppu::ApplyHiResMode() +{ + uint32_t screenY = _screenInterlace ? ((_frameCount & 0x01) ? ((_scanline << 1) + 1) : (_scanline << 1)) : _scanline; + + if(_hiresMode || _bgMode == 5 || _bgMode == 6) { + ApplyBrightness(); + for(int i = 0; i < 512; i += 2) { + _currentBuffer[(screenY << 9) + i] = _subScreenBuffer[i >> 1]; + _currentBuffer[(screenY << 9) + i + 1] = _mainScreenBuffer[i >> 1]; + } + } else { + memcpy(_currentBuffer + (screenY << 8), _mainScreenBuffer, sizeof(_mainScreenBuffer)); + } +} + template bool Ppu::ProcessMaskWindow(uint8_t activeWindowCount, int x) { @@ -890,8 +935,27 @@ void Ppu::ProcessWindowMaskSettings(uint8_t value, uint8_t offset) void Ppu::SendFrame() { _console->GetNotificationManager()->SendNotification(ConsoleNotificationType::PpuFrameDone); - _console->GetVideoDecoder()->UpdateFrame(_currentBuffer, _frameCount); - _currentBuffer = _currentBuffer == _outputBuffers[0] ? _outputBuffers[1] : _outputBuffers[0]; + + 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; + } + + if(_screenInterlace) { + _console->GetVideoDecoder()->UpdateFrameSync(_currentBuffer, width, height, _frameCount); + } else { + _console->GetVideoDecoder()->UpdateFrame(_currentBuffer, width, height, _frameCount); + _currentBuffer = _currentBuffer == _outputBuffers[0] ? _outputBuffers[1] : _outputBuffers[0]; + } } uint8_t* Ppu::GetVideoRam() @@ -1080,6 +1144,9 @@ void Ppu::Write(uint32_t addr, uint8_t value) break; case 0x2105: + if(_bgMode != (value & 0x07)) { + MessageManager::DisplayMessage("Debug", "Entering mode: " + std::to_string(value & 0x07)); + } _bgMode = value & 0x07; _mode1Bg3Priority = (value & 0x08) != 0; @@ -1323,10 +1390,10 @@ void Ppu::Write(uint32_t addr, uint8_t value) //SETINI - Screen Mode/Video Select //_externalSync = (value & 0x80) != 0; //NOT USED _mode7.ExtBgEnabled = (value & 0x40) != 0; - //_hiresMode = (value & 0x08) != 0; //TODO - //_overscanMode = (value & 0x04) != 0; //TODO + _hiresMode = (value & 0x08) != 0; + _overscanMode = (value & 0x04) != 0; //_objInterlace = (value & 0x02) != 0; //TODO - //_screenInterlace = (value & 0x01) != 0; //TODO + _screenInterlace = (value & 0x01) != 0; break; default: diff --git a/Core/Ppu.h b/Core/Ppu.h index 154a44b..2fb4fb5 100644 --- a/Core/Ppu.h +++ b/Core/Ppu.h @@ -76,6 +76,7 @@ private: uint8_t _cgram[Ppu::CgRamSize]; uint16_t *_outputBuffers[2]; + uint16_t *_currentBuffer; SpriteInfo _sprites[32] = {}; uint8_t _spriteCount = 0; @@ -87,7 +88,7 @@ private: uint16_t _subPixelsDrawn = 0; uint8_t _rowPixelFlags[256]; - uint16_t *_currentBuffer; + uint16_t _mainScreenBuffer[256]; bool _subScreenFilled[256]; uint16_t _subScreenBuffer[256]; @@ -111,6 +112,9 @@ private: bool _timeOver = false; bool _rangeOver = false; + bool _hiresMode = false; + bool _screenInterlace = false; + bool _overscanMode = false; bool _directColorMode = false; ColorWindowMode _colorMathClipMode = ColorWindowMode::Never; @@ -150,6 +154,9 @@ private: template void RenderMode4(); + template + void RenderMode5(); + template void RenderMode7(); @@ -158,10 +165,13 @@ private: template void RenderBgColor(); + template + void RenderTilemapLargeTiles(); + template void RenderTilemap(); - template + template void RenderTilemap(); template @@ -173,8 +183,12 @@ private: __forceinline void DrawSubPixel(uint8_t x, uint16_t paletteRamOffset); void ApplyColorMath(); + + template void ApplyBrightness(); + void ApplyHiResMode(); + template bool ProcessMaskWindow(uint8_t activeWindowCount, int x); void ProcessWindowMaskSettings(uint8_t value, uint8_t offset); diff --git a/Core/SettingTypes.h b/Core/SettingTypes.h index 76edf10..8eedb74 100644 --- a/Core/SettingTypes.h +++ b/Core/SettingTypes.h @@ -62,28 +62,10 @@ enum class VideoAspectRatio struct OverscanDimensions { - static const int ScreenWidth = 256; - static const int ScreenHeight = 224; - uint32_t Left = 0; uint32_t Right = 0; uint32_t Top = 0; uint32_t Bottom = 0; - - uint32_t GetPixelCount() - { - return GetScreenWidth() * GetScreenHeight(); - } - - uint32_t GetScreenWidth() - { - return 256 - Left - Right; - } - - uint32_t GetScreenHeight() - { - return 224 - Top - Bottom; - } }; struct PictureSettings @@ -116,9 +98,6 @@ struct FrameInfo { uint32_t Width; uint32_t Height; - uint32_t OriginalWidth; - uint32_t OriginalHeight; - uint32_t BitsPerPixel; }; struct ScreenSize diff --git a/Core/VideoDecoder.cpp b/Core/VideoDecoder.cpp index 6abae4c..bc03383 100644 --- a/Core/VideoDecoder.cpp +++ b/Core/VideoDecoder.cpp @@ -43,15 +43,23 @@ void VideoDecoder::GetScreenSize(ScreenSize &size, bool ignoreScale) } size.Scale = scale;*/ - - if(ignoreScale) { - size.Width = 256; - size.Height = 224; - } else { - size.Width = 512; - size.Height = 448; - } + size.Scale = 2; + if(ignoreScale) { + size.Width = _baseFrameInfo.Width; + size.Height = _baseFrameInfo.Height; + } else { + if(_baseFrameInfo.Width == 256) { + size.Width = (int32_t)(_baseFrameInfo.Width * size.Scale); + size.Height = (int32_t)(_baseFrameInfo.Height * size.Scale); + } else { + size.Width = (int32_t)_baseFrameInfo.Width; + size.Height = (int32_t)_baseFrameInfo.Height; + if(_baseFrameInfo.Height <= 240) { + size.Height *= 2; + } + } + } } } @@ -93,6 +101,7 @@ void VideoDecoder::DecodeFrame(bool synchronous) { UpdateVideoFilter(); + _videoFilter->SetBaseFrameInfo(_baseFrameInfo); _videoFilter->SendFrame(_ppuOutputBuffer, _frameNumber); uint32_t* outputBuffer = _videoFilter->GetOutputBuffer(); @@ -150,15 +159,17 @@ uint32_t VideoDecoder::GetFrameCount() return _frameCount; } -void VideoDecoder::UpdateFrameSync(uint16_t *ppuOutputBuffer, uint32_t frameNumber) +void VideoDecoder::UpdateFrameSync(uint16_t *ppuOutputBuffer, uint16_t width, uint16_t height, uint32_t frameNumber) { + _baseFrameInfo.Width = width; + _baseFrameInfo.Height = height; _frameNumber = frameNumber; _ppuOutputBuffer = ppuOutputBuffer; DecodeFrame(true); _frameCount++; } -void VideoDecoder::UpdateFrame(uint16_t *ppuOutputBuffer, uint32_t frameNumber) +void VideoDecoder::UpdateFrame(uint16_t *ppuOutputBuffer, uint16_t width, uint16_t height, uint32_t frameNumber) { if(_frameChanged) { //Last frame isn't done decoding yet - sometimes Signal() introduces a 25-30ms delay @@ -168,6 +179,8 @@ void VideoDecoder::UpdateFrame(uint16_t *ppuOutputBuffer, uint32_t frameNumber) //At this point, we are sure that the decode thread is no longer busy } + _baseFrameInfo.Width = width; + _baseFrameInfo.Height = height; _frameNumber = frameNumber; _ppuOutputBuffer = ppuOutputBuffer; _frameChanged = true; diff --git a/Core/VideoDecoder.h b/Core/VideoDecoder.h index d0a3d21..d8d5a73 100644 --- a/Core/VideoDecoder.h +++ b/Core/VideoDecoder.h @@ -28,6 +28,7 @@ private: atomic _stopFlag; uint32_t _frameCount = 0; + FrameInfo _baseFrameInfo = { 256, 224 }; ScreenSize _previousScreenSize = {}; double _previousScale = 0; FrameInfo _lastFrameInfo; @@ -54,8 +55,8 @@ public: FrameInfo GetFrameInfo(); void GetScreenSize(ScreenSize &size, bool ignoreScale); - void UpdateFrameSync(uint16_t *ppuOutputBuffer, uint32_t frameNumber); - void UpdateFrame(uint16_t *ppuOutputBuffer, uint32_t frameNumber); + void UpdateFrameSync(uint16_t *ppuOutputBuffer, uint16_t width, uint16_t height, uint32_t frameNumber); + void UpdateFrame(uint16_t *ppuOutputBuffer, uint16_t width, uint16_t height, uint32_t frameNumber); bool IsRunning(); void StartThread();