PPU: Support for mode 5, hires, interlace, and overscan mode
This commit is contained in:
parent
19a6663ed9
commit
85f1333c3d
10 changed files with 208 additions and 133 deletions
|
@ -20,6 +20,16 @@ BaseVideoFilter::~BaseVideoFilter()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BaseVideoFilter::SetBaseFrameInfo(FrameInfo frameInfo)
|
||||||
|
{
|
||||||
|
_baseFrameInfo = frameInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
FrameInfo BaseVideoFilter::GetFrameInfo()
|
||||||
|
{
|
||||||
|
return _baseFrameInfo;
|
||||||
|
}
|
||||||
|
|
||||||
void BaseVideoFilter::UpdateBufferSize()
|
void BaseVideoFilter::UpdateBufferSize()
|
||||||
{
|
{
|
||||||
uint32_t newBufferSize = GetFrameInfo().Width*GetFrameInfo().Height;
|
uint32_t newBufferSize = GetFrameInfo().Width*GetFrameInfo().Height;
|
||||||
|
|
|
@ -13,6 +13,7 @@ private:
|
||||||
SimpleLock _frameLock;
|
SimpleLock _frameLock;
|
||||||
OverscanDimensions _overscan;
|
OverscanDimensions _overscan;
|
||||||
bool _isOddFrame;
|
bool _isOddFrame;
|
||||||
|
FrameInfo _baseFrameInfo;
|
||||||
|
|
||||||
void UpdateBufferSize();
|
void UpdateBufferSize();
|
||||||
|
|
||||||
|
@ -33,5 +34,7 @@ public:
|
||||||
void TakeScreenshot(VideoFilterType filterType, string filename, std::stringstream *stream = nullptr);
|
void TakeScreenshot(VideoFilterType filterType, string filename, std::stringstream *stream = nullptr);
|
||||||
|
|
||||||
virtual OverscanDimensions GetOverscan();
|
virtual OverscanDimensions GetOverscan();
|
||||||
virtual FrameInfo GetFrameInfo() = 0;
|
|
||||||
|
void SetBaseFrameInfo(FrameInfo frameInfo);
|
||||||
|
virtual FrameInfo GetFrameInfo();
|
||||||
};
|
};
|
|
@ -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()
|
void DefaultVideoFilter::OnBeforeApplyFilter()
|
||||||
{
|
{
|
||||||
/*PictureSettings currentSettings = _console->GetSettings()->GetPictureSettings();
|
/*PictureSettings currentSettings = _console->GetSettings()->GetPictureSettings();
|
||||||
|
@ -99,7 +93,8 @@ void DefaultVideoFilter::DecodePpuBuffer(uint16_t *ppuOutputBuffer, uint32_t* ou
|
||||||
void DefaultVideoFilter::ApplyFilter(uint16_t *ppuOutputBuffer)
|
void DefaultVideoFilter::ApplyFilter(uint16_t *ppuOutputBuffer)
|
||||||
{
|
{
|
||||||
uint32_t *out = GetOutputBuffer();
|
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];
|
uint16_t rgb555 = ppuOutputBuffer[i];
|
||||||
uint8_t b = (rgb555 >> 10) * 256 / 32;
|
uint8_t b = (rgb555 >> 10) * 256 / 32;
|
||||||
uint8_t g = ((rgb555 >> 5) & 0x1F) * 256 / 32;
|
uint8_t g = ((rgb555 >> 5) & 0x1F) * 256 / 32;
|
||||||
|
|
|
@ -24,5 +24,4 @@ protected:
|
||||||
public:
|
public:
|
||||||
DefaultVideoFilter(shared_ptr<Console> console);
|
DefaultVideoFilter(shared_ptr<Console> console);
|
||||||
void ApplyFilter(uint16_t *ppuOutputBuffer);
|
void ApplyFilter(uint16_t *ppuOutputBuffer);
|
||||||
FrameInfo GetFrameInfo();
|
|
||||||
};
|
};
|
|
@ -20,12 +20,6 @@ protected:
|
||||||
virtual void InternalDraw() = 0;
|
virtual void InternalDraw() = 0;
|
||||||
__forceinline void DrawPixel(uint32_t x, uint32_t y, int color)
|
__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);
|
uint32_t alpha = (color & 0xFF000000);
|
||||||
if(alpha > 0) {
|
if(alpha > 0) {
|
||||||
if(_yScale == 1) {
|
if(_yScale == 1) {
|
||||||
|
@ -82,8 +76,8 @@ public:
|
||||||
_argbBuffer = argbBuffer;
|
_argbBuffer = argbBuffer;
|
||||||
_overscan = overscan;
|
_overscan = overscan;
|
||||||
_lineWidth = lineWidth;
|
_lineWidth = lineWidth;
|
||||||
_yScale = lineWidth / overscan.GetScreenWidth();
|
_yScale = 1; //TODO
|
||||||
_xScale = (float)lineWidth / overscan.GetScreenWidth();
|
_xScale = 2; //TODO
|
||||||
|
|
||||||
InternalDraw();
|
InternalDraw();
|
||||||
|
|
||||||
|
|
229
Core/Ppu.cpp
229
Core/Ppu.cpp
|
@ -14,8 +14,8 @@ Ppu::Ppu(shared_ptr<Console> console)
|
||||||
_console = console;
|
_console = console;
|
||||||
_regs = console->GetInternalRegisters();
|
_regs = console->GetInternalRegisters();
|
||||||
|
|
||||||
_outputBuffers[0] = new uint16_t[256 * 224];
|
_outputBuffers[0] = new uint16_t[512 * 478];
|
||||||
_outputBuffers[1] = new uint16_t[256 * 224];
|
_outputBuffers[1] = new uint16_t[512 * 478];
|
||||||
|
|
||||||
_currentBuffer = _outputBuffers[0];
|
_currentBuffer = _outputBuffers[0];
|
||||||
|
|
||||||
|
@ -64,9 +64,9 @@ void Ppu::Exec()
|
||||||
|
|
||||||
_rangeOver = false;
|
_rangeOver = false;
|
||||||
_timeOver = false;
|
_timeOver = false;
|
||||||
if(_scanline < 224) {
|
if(_scanline < (_overscanMode ? 240 : 224)) {
|
||||||
RenderScanline();
|
RenderScanline();
|
||||||
} else if(_scanline == 225) {
|
} else if(_scanline == (_overscanMode ? 241 : 225)) {
|
||||||
//Reset OAM address at the start of vblank?
|
//Reset OAM address at the start of vblank?
|
||||||
if(!_forcedVblank) {
|
if(!_forcedVblank) {
|
||||||
_internalOamAddress = (_oamRamAddress << 1);
|
_internalOamAddress = (_oamRamAddress << 1);
|
||||||
|
@ -238,8 +238,6 @@ void Ppu::RenderSprites()
|
||||||
}
|
}
|
||||||
|
|
||||||
if(forMainScreen) {
|
if(forMainScreen) {
|
||||||
uint16_t outBaseAddress = (_scanline << 8);
|
|
||||||
|
|
||||||
for(int x = 0; x < 256; x++) {
|
for(int x = 0; x < 256; x++) {
|
||||||
if(!_rowPixelFlags[x] && _spritePriority[x] == priority) {
|
if(!_rowPixelFlags[x] && _spritePriority[x] == priority) {
|
||||||
if(activeWindowCount && ProcessMaskWindow<Ppu::SpriteLayerIndex>(activeWindowCount, x)) {
|
if(activeWindowCount && ProcessMaskWindow<Ppu::SpriteLayerIndex>(activeWindowCount, x)) {
|
||||||
|
@ -247,7 +245,7 @@ void Ppu::RenderSprites()
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
_currentBuffer[outBaseAddress | x] = _spritePixels[x];
|
_mainScreenBuffer[x] = _spritePixels[x];
|
||||||
_rowPixelFlags[x] |= PixelFlags::Filled | (((_colorMathEnabled & 0x10) && _spritePalette[x] > 3) ? PixelFlags::AllowColorMath : 0);
|
_rowPixelFlags[x] |= PixelFlags::Filled | (((_colorMathEnabled & 0x10) && _spritePalette[x] > 3) ? PixelFlags::AllowColorMath : 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -347,6 +345,20 @@ void Ppu::RenderMode4()
|
||||||
RenderBgColor<forMainScreen>();
|
RenderBgColor<forMainScreen>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<bool forMainScreen>
|
||||||
|
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<forMainScreen>();
|
||||||
|
}
|
||||||
|
|
||||||
template<bool forMainScreen>
|
template<bool forMainScreen>
|
||||||
void Ppu::RenderMode7()
|
void Ppu::RenderMode7()
|
||||||
{
|
{
|
||||||
|
@ -388,32 +400,26 @@ void Ppu::RenderScanline()
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
MessageManager::Log("[Debug] Using mode 2");
|
|
||||||
RenderMode2<true>();
|
RenderMode2<true>();
|
||||||
RenderMode2<false>();
|
RenderMode2<false>();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 3:
|
case 3:
|
||||||
MessageManager::Log("[Debug] Using mode 3");
|
|
||||||
RenderMode3<true>();
|
RenderMode3<true>();
|
||||||
RenderMode3<false>();
|
RenderMode3<false>();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 4:
|
case 4:
|
||||||
MessageManager::Log("[Debug] Using mode 4");
|
|
||||||
RenderMode4<true>();
|
RenderMode4<true>();
|
||||||
RenderMode4<false>();
|
RenderMode4<false>();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 5:
|
case 5:
|
||||||
MessageManager::Log("[Debug] Using mode 5");
|
RenderMode5<true>();
|
||||||
RenderTilemap<1, 2, false, true>();
|
RenderMode5<false>();
|
||||||
RenderTilemap<0, 4, false, true>();
|
|
||||||
RenderBgColor<true>();
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 6:
|
case 6:
|
||||||
MessageManager::Log("[Debug] Using mode 6");
|
|
||||||
RenderTilemap<0, 8, false, true>();
|
RenderTilemap<0, 8, false, true>();
|
||||||
RenderBgColor<true>();
|
RenderBgColor<true>();
|
||||||
break;
|
break;
|
||||||
|
@ -425,7 +431,8 @@ void Ppu::RenderScanline()
|
||||||
}
|
}
|
||||||
|
|
||||||
ApplyColorMath();
|
ApplyColorMath();
|
||||||
ApplyBrightness();
|
ApplyBrightness<true>();
|
||||||
|
ApplyHiResMode();
|
||||||
|
|
||||||
//Process sprites for next scanline
|
//Process sprites for next scanline
|
||||||
EvaluateNextLineSprites();
|
EvaluateNextLineSprites();
|
||||||
|
@ -439,12 +446,11 @@ void Ppu::RenderBgColor()
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t bgColor = _cgram[0] | (_cgram[1] << 8);
|
uint16_t bgColor = _cgram[0] | (_cgram[1] << 8);
|
||||||
uint16_t outBaseAddress = (_scanline << 8);
|
|
||||||
for(int x = 0; x < 256; x++) {
|
for(int x = 0; x < 256; x++) {
|
||||||
if(forMainScreen) {
|
if(forMainScreen) {
|
||||||
if(!_rowPixelFlags[x]) {
|
if(!_rowPixelFlags[x]) {
|
||||||
uint8_t pixelFlags = PixelFlags::Filled | ((_colorMathEnabled & 0x20) ? PixelFlags::AllowColorMath : 0);
|
uint8_t pixelFlags = PixelFlags::Filled | ((_colorMathEnabled & 0x20) ? PixelFlags::AllowColorMath : 0);
|
||||||
_currentBuffer[outBaseAddress | x] = bgColor;
|
_mainScreenBuffer[x] = bgColor;
|
||||||
_rowPixelFlags[x] = pixelFlags;
|
_rowPixelFlags[x] = pixelFlags;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -455,8 +461,8 @@ void Ppu::RenderBgColor()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<uint8_t layerIndex, uint8_t bpp, bool processHighPriority, bool forMainScreen, uint16_t basePaletteOffset>
|
template<uint8_t layerIndex, uint8_t bpp, bool processHighPriority, bool forMainScreen, bool largeTileWidth, bool largeTileHeight, uint16_t basePaletteOffset>
|
||||||
void Ppu::RenderTilemap()
|
void Ppu::RenderTilemapLargeTiles()
|
||||||
{
|
{
|
||||||
uint8_t activeWindowCount = 0;
|
uint8_t activeWindowCount = 0;
|
||||||
if((forMainScreen && _windowMaskMain[layerIndex]) || (!forMainScreen && _windowMaskSub[layerIndex])) {
|
if((forMainScreen && _windowMaskMain[layerIndex]) || (!forMainScreen && _windowMaskSub[layerIndex])) {
|
||||||
|
@ -465,50 +471,49 @@ void Ppu::RenderTilemap()
|
||||||
|
|
||||||
bool applyMosaic = forMainScreen && ((_mosaicEnabled >> layerIndex) & 0x01) != 0;
|
bool applyMosaic = forMainScreen && ((_mosaicEnabled >> layerIndex) & 0x01) != 0;
|
||||||
|
|
||||||
if(_layerConfig[layerIndex].LargeTiles) {
|
if(activeWindowCount == 0) {
|
||||||
if(activeWindowCount == 0) {
|
if(applyMosaic) {
|
||||||
if(applyMosaic) {
|
RenderTilemap<layerIndex, bpp, processHighPriority, forMainScreen, largeTileWidth, largeTileHeight, basePaletteOffset, 0, true>();
|
||||||
RenderTilemap<layerIndex, bpp, processHighPriority, forMainScreen, true, basePaletteOffset, 0, true>();
|
|
||||||
} else {
|
|
||||||
RenderTilemap<layerIndex, bpp, processHighPriority, forMainScreen, true, basePaletteOffset, 0, false>();
|
|
||||||
}
|
|
||||||
} else if(activeWindowCount == 1) {
|
|
||||||
if(applyMosaic) {
|
|
||||||
RenderTilemap<layerIndex, bpp, processHighPriority, forMainScreen, true, basePaletteOffset, 1, true>();
|
|
||||||
} else {
|
|
||||||
RenderTilemap<layerIndex, bpp, processHighPriority, forMainScreen, true, basePaletteOffset, 1, false>();
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if(applyMosaic) {
|
RenderTilemap<layerIndex, bpp, processHighPriority, forMainScreen, largeTileWidth, largeTileHeight, basePaletteOffset, 0, false>();
|
||||||
RenderTilemap<layerIndex, bpp, processHighPriority, forMainScreen, true, basePaletteOffset, 2, true>();
|
}
|
||||||
} else {
|
} else if(activeWindowCount == 1) {
|
||||||
RenderTilemap<layerIndex, bpp, processHighPriority, forMainScreen, true, basePaletteOffset, 2, false>();
|
if(applyMosaic) {
|
||||||
}
|
RenderTilemap<layerIndex, bpp, processHighPriority, forMainScreen, largeTileWidth, largeTileHeight, basePaletteOffset, 1, true>();
|
||||||
|
} else {
|
||||||
|
RenderTilemap<layerIndex, bpp, processHighPriority, forMainScreen, largeTileWidth, largeTileHeight, basePaletteOffset, 1, false>();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if(activeWindowCount == 0) {
|
if(applyMosaic) {
|
||||||
if(applyMosaic) {
|
RenderTilemap<layerIndex, bpp, processHighPriority, forMainScreen, largeTileWidth, largeTileHeight, basePaletteOffset, 2, true>();
|
||||||
RenderTilemap<layerIndex, bpp, processHighPriority, forMainScreen, false, basePaletteOffset, 0, true>();
|
|
||||||
} else {
|
|
||||||
RenderTilemap<layerIndex, bpp, processHighPriority, forMainScreen, false, basePaletteOffset, 0, false>();
|
|
||||||
}
|
|
||||||
} else if(activeWindowCount == 1) {
|
|
||||||
if(applyMosaic) {
|
|
||||||
RenderTilemap<layerIndex, bpp, processHighPriority, forMainScreen, false, basePaletteOffset, 1, true>();
|
|
||||||
} else {
|
|
||||||
RenderTilemap<layerIndex, bpp, processHighPriority, forMainScreen, false, basePaletteOffset, 1, false>();
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if(applyMosaic) {
|
RenderTilemap<layerIndex, bpp, processHighPriority, forMainScreen, largeTileWidth, largeTileHeight, basePaletteOffset, 2, false>();
|
||||||
RenderTilemap<layerIndex, bpp, processHighPriority, forMainScreen, false, basePaletteOffset, 2, true>();
|
|
||||||
} else {
|
|
||||||
RenderTilemap<layerIndex, bpp, processHighPriority, forMainScreen, false, basePaletteOffset, 2, false>();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<uint8_t layerIndex, uint8_t bpp, bool processHighPriority, bool forMainScreen, bool largeTiles, uint16_t basePaletteOffset, uint8_t activeWindowCount, bool applyMosaic>
|
template<uint8_t layerIndex, uint8_t bpp, bool processHighPriority, bool forMainScreen, uint16_t basePaletteOffset>
|
||||||
|
void Ppu::RenderTilemap()
|
||||||
|
{
|
||||||
|
bool largeTileWidth = _layerConfig[layerIndex].LargeTiles || _bgMode == 5;
|
||||||
|
bool largeTileHeight = _layerConfig[layerIndex].LargeTiles;
|
||||||
|
|
||||||
|
if(largeTileWidth) {
|
||||||
|
if(largeTileHeight) {
|
||||||
|
RenderTilemapLargeTiles<layerIndex, bpp, processHighPriority, forMainScreen, true, true, basePaletteOffset>();
|
||||||
|
} else {
|
||||||
|
RenderTilemapLargeTiles<layerIndex, bpp, processHighPriority, forMainScreen, true, false, basePaletteOffset>();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(largeTileHeight) {
|
||||||
|
RenderTilemapLargeTiles<layerIndex, bpp, processHighPriority, forMainScreen, false, true, basePaletteOffset>();
|
||||||
|
} else {
|
||||||
|
RenderTilemapLargeTiles<layerIndex, bpp, processHighPriority, forMainScreen, false, false, basePaletteOffset>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<uint8_t layerIndex, uint8_t bpp, bool processHighPriority, bool forMainScreen, bool largeTileWidth, bool largeTileHeight, uint16_t basePaletteOffset, uint8_t activeWindowCount, bool applyMosaic>
|
||||||
void Ppu::RenderTilemap()
|
void Ppu::RenderTilemap()
|
||||||
{
|
{
|
||||||
if(forMainScreen) {
|
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);
|
uint8_t pixelFlags = PixelFlags::Filled | (((_colorMathEnabled >> layerIndex) & 0x01) ? PixelFlags::AllowColorMath : 0);
|
||||||
|
|
||||||
|
/* The current layer's options */
|
||||||
LayerConfig &config = _layerConfig[layerIndex];
|
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;
|
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 baseOffset = tilemapAddr + addrVerticalScrollingOffset + ((row & 0x1F) << 5);
|
||||||
|
|
||||||
uint16_t outBaseAddress = (_scanline << 8);
|
|
||||||
|
|
||||||
for(int x = 0; x < 256; x++) {
|
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;
|
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)
|
//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(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
|
//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;
|
_rowPixelFlags[x] = pixelFlags;
|
||||||
if(forMainScreen) {
|
if(forMainScreen) {
|
||||||
_pixelsDrawn++;
|
_pixelsDrawn++;
|
||||||
|
@ -575,11 +606,11 @@ void Ppu::RenderTilemap()
|
||||||
bool hMirror = (_vram[addr + 1] & 0x40) != 0;
|
bool hMirror = (_vram[addr + 1] & 0x40) != 0;
|
||||||
|
|
||||||
uint16_t tileIndex = ((_vram[addr + 1] & 0x03) << 8) | _vram[addr];
|
uint16_t tileIndex = ((_vram[addr + 1] & 0x03) << 8) | _vram[addr];
|
||||||
if(largeTiles) {
|
if(largeTileWidth || largeTileHeight) {
|
||||||
tileIndex = (
|
tileIndex = (
|
||||||
tileIndex +
|
tileIndex +
|
||||||
(((_scanline + config.VScroll) & 0x08) ? (vMirror ? 0 : 16) : (vMirror ? 16 : 0)) +
|
(largeTileHeight ? (((realY + config.VScroll) & 0x08) ? (vMirror ? 0 : 16) : (vMirror ? 16 : 0)) : 0) +
|
||||||
(((x + config.HScroll) & 0x08) ? (hMirror ? 0 : 1) : (hMirror ? 1 : 0))
|
(largeTileWidth ? (((realX + config.HScroll) & 0x08) ? (hMirror ? 0 : 1) : (hMirror ? 1 : 0)) : 0)
|
||||||
) & 0x3FF;
|
) & 0x3FF;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -588,8 +619,9 @@ void Ppu::RenderTilemap()
|
||||||
uint8_t yOffset = vMirror ? (7 - baseYOffset) : baseYOffset;
|
uint8_t yOffset = vMirror ? (7 - baseYOffset) : baseYOffset;
|
||||||
uint16_t pixelStart = tileStart + yOffset * 2;
|
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);
|
uint8_t shift = hMirror ? xOffset : (7 - xOffset);
|
||||||
|
|
||||||
uint16_t color = 0;
|
uint16_t color = 0;
|
||||||
if(bpp == 2) {
|
if(bpp == 2) {
|
||||||
color |= (((_vram[pixelStart + 0] >> shift) & 0x01) << 0);
|
color |= (((_vram[pixelStart + 0] >> shift) & 0x01) << 0);
|
||||||
|
@ -628,8 +660,6 @@ void Ppu::RenderTilemap()
|
||||||
template<uint8_t layerIndex, bool forMainScreen, bool applyMosaic, bool processHighPriority>
|
template<uint8_t layerIndex, bool forMainScreen, bool applyMosaic, bool processHighPriority>
|
||||||
void Ppu::RenderTilemapMode7()
|
void Ppu::RenderTilemapMode7()
|
||||||
{
|
{
|
||||||
uint16_t realY = _mode7.VerticalMirroring ? (255 - _scanline) : _scanline;
|
|
||||||
|
|
||||||
if(forMainScreen) {
|
if(forMainScreen) {
|
||||||
if(_pixelsDrawn == 256 || ((_mainScreenLayers >> layerIndex) & 0x01) == 0) {
|
if(_pixelsDrawn == 256 || ((_mainScreenLayers >> layerIndex) & 0x01) == 0) {
|
||||||
//This screen is disabled, or we've drawn all pixels already
|
//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 vScroll = ((int32_t)_mode7.VScroll << 19) >> 19;
|
||||||
int32_t centerX = ((int32_t)_mode7.CenterX << 19) >> 19;
|
int32_t centerX = ((int32_t)_mode7.CenterX << 19) >> 19;
|
||||||
int32_t centerY = ((int32_t)_mode7.CenterY << 19) >> 19;
|
int32_t centerY = ((int32_t)_mode7.CenterY << 19) >> 19;
|
||||||
|
uint16_t realY = _mode7.VerticalMirroring ? (255 - _scanline) : _scanline;
|
||||||
|
|
||||||
lutX[0] = (
|
lutX[0] = (
|
||||||
((_mode7.Matrix[0] * clip(hScroll - centerX)) & ~63) +
|
((_mode7.Matrix[0] * clip(hScroll - centerX)) & ~63) +
|
||||||
|
@ -731,7 +762,7 @@ void Ppu::RenderTilemapMode7()
|
||||||
template<bool applyMosaic>
|
template<bool applyMosaic>
|
||||||
void Ppu::DrawMainPixel(uint8_t x, uint16_t paletteRamOffset, uint8_t flags)
|
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;
|
_rowPixelFlags[x] = flags;
|
||||||
|
|
||||||
if(applyMosaic && x % _mosaicSize == 0) {
|
if(applyMosaic && x % _mosaicSize == 0) {
|
||||||
|
@ -764,7 +795,7 @@ void Ppu::ApplyColorMath()
|
||||||
for(int x = 0; x < 256; x++) {
|
for(int x = 0; x < 256; x++) {
|
||||||
if(_rowPixelFlags[x] & PixelFlags::AllowColorMath) {
|
if(_rowPixelFlags[x] & PixelFlags::AllowColorMath) {
|
||||||
uint8_t halfShift = _colorMathHalveResult ? 1 : 0;
|
uint8_t halfShift = _colorMathHalveResult ? 1 : 0;
|
||||||
uint16_t &mainPixel = _currentBuffer[outBaseAddress | x];
|
uint16_t &mainPixel = _mainScreenBuffer[x];
|
||||||
|
|
||||||
bool isInsideWindow = activeWindowCount && ProcessMaskWindow<Ppu::ColorWindowIndex>(activeWindowCount, x);
|
bool isInsideWindow = activeWindowCount && ProcessMaskWindow<Ppu::ColorWindowIndex>(activeWindowCount, x);
|
||||||
//Set color to black as needed based on clip mode
|
//Set color to black as needed based on clip mode
|
||||||
|
@ -839,13 +870,12 @@ void Ppu::ApplyColorMath()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<bool forMainScreen>
|
||||||
void Ppu::ApplyBrightness()
|
void Ppu::ApplyBrightness()
|
||||||
{
|
{
|
||||||
if(_screenBrightness != 15) {
|
if(_screenBrightness != 15) {
|
||||||
uint16_t outBaseAddress = (_scanline << 8);
|
|
||||||
|
|
||||||
for(int x = 0; x < 256; x++) {
|
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 r = (pixel & 0x1F) * _screenBrightness / 15;
|
||||||
uint16_t g = ((pixel >> 5) & 0x1F) * _screenBrightness / 15;
|
uint16_t g = ((pixel >> 5) & 0x1F) * _screenBrightness / 15;
|
||||||
uint16_t b = ((pixel >> 10) & 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<false>();
|
||||||
|
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<uint8_t layerIndex>
|
template<uint8_t layerIndex>
|
||||||
bool Ppu::ProcessMaskWindow(uint8_t activeWindowCount, int x)
|
bool Ppu::ProcessMaskWindow(uint8_t activeWindowCount, int x)
|
||||||
{
|
{
|
||||||
|
@ -890,8 +935,27 @@ void Ppu::ProcessWindowMaskSettings(uint8_t value, uint8_t offset)
|
||||||
void Ppu::SendFrame()
|
void Ppu::SendFrame()
|
||||||
{
|
{
|
||||||
_console->GetNotificationManager()->SendNotification(ConsoleNotificationType::PpuFrameDone);
|
_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()
|
uint8_t* Ppu::GetVideoRam()
|
||||||
|
@ -1080,6 +1144,9 @@ void Ppu::Write(uint32_t addr, uint8_t value)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x2105:
|
case 0x2105:
|
||||||
|
if(_bgMode != (value & 0x07)) {
|
||||||
|
MessageManager::DisplayMessage("Debug", "Entering mode: " + std::to_string(value & 0x07));
|
||||||
|
}
|
||||||
_bgMode = value & 0x07;
|
_bgMode = value & 0x07;
|
||||||
_mode1Bg3Priority = (value & 0x08) != 0;
|
_mode1Bg3Priority = (value & 0x08) != 0;
|
||||||
|
|
||||||
|
@ -1323,10 +1390,10 @@ void Ppu::Write(uint32_t addr, uint8_t value)
|
||||||
//SETINI - Screen Mode/Video Select
|
//SETINI - Screen Mode/Video Select
|
||||||
//_externalSync = (value & 0x80) != 0; //NOT USED
|
//_externalSync = (value & 0x80) != 0; //NOT USED
|
||||||
_mode7.ExtBgEnabled = (value & 0x40) != 0;
|
_mode7.ExtBgEnabled = (value & 0x40) != 0;
|
||||||
//_hiresMode = (value & 0x08) != 0; //TODO
|
_hiresMode = (value & 0x08) != 0;
|
||||||
//_overscanMode = (value & 0x04) != 0; //TODO
|
_overscanMode = (value & 0x04) != 0;
|
||||||
//_objInterlace = (value & 0x02) != 0; //TODO
|
//_objInterlace = (value & 0x02) != 0; //TODO
|
||||||
//_screenInterlace = (value & 0x01) != 0; //TODO
|
_screenInterlace = (value & 0x01) != 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
18
Core/Ppu.h
18
Core/Ppu.h
|
@ -76,6 +76,7 @@ private:
|
||||||
uint8_t _cgram[Ppu::CgRamSize];
|
uint8_t _cgram[Ppu::CgRamSize];
|
||||||
|
|
||||||
uint16_t *_outputBuffers[2];
|
uint16_t *_outputBuffers[2];
|
||||||
|
uint16_t *_currentBuffer;
|
||||||
|
|
||||||
SpriteInfo _sprites[32] = {};
|
SpriteInfo _sprites[32] = {};
|
||||||
uint8_t _spriteCount = 0;
|
uint8_t _spriteCount = 0;
|
||||||
|
@ -87,7 +88,7 @@ private:
|
||||||
uint16_t _subPixelsDrawn = 0;
|
uint16_t _subPixelsDrawn = 0;
|
||||||
|
|
||||||
uint8_t _rowPixelFlags[256];
|
uint8_t _rowPixelFlags[256];
|
||||||
uint16_t *_currentBuffer;
|
uint16_t _mainScreenBuffer[256];
|
||||||
|
|
||||||
bool _subScreenFilled[256];
|
bool _subScreenFilled[256];
|
||||||
uint16_t _subScreenBuffer[256];
|
uint16_t _subScreenBuffer[256];
|
||||||
|
@ -111,6 +112,9 @@ private:
|
||||||
bool _timeOver = false;
|
bool _timeOver = false;
|
||||||
bool _rangeOver = false;
|
bool _rangeOver = false;
|
||||||
|
|
||||||
|
bool _hiresMode = false;
|
||||||
|
bool _screenInterlace = false;
|
||||||
|
bool _overscanMode = false;
|
||||||
bool _directColorMode = false;
|
bool _directColorMode = false;
|
||||||
|
|
||||||
ColorWindowMode _colorMathClipMode = ColorWindowMode::Never;
|
ColorWindowMode _colorMathClipMode = ColorWindowMode::Never;
|
||||||
|
@ -150,6 +154,9 @@ private:
|
||||||
template<bool forMainScreen>
|
template<bool forMainScreen>
|
||||||
void RenderMode4();
|
void RenderMode4();
|
||||||
|
|
||||||
|
template<bool forMainScreen>
|
||||||
|
void RenderMode5();
|
||||||
|
|
||||||
template<bool forMainScreen>
|
template<bool forMainScreen>
|
||||||
void RenderMode7();
|
void RenderMode7();
|
||||||
|
|
||||||
|
@ -158,10 +165,13 @@ private:
|
||||||
template<bool forMainScreen>
|
template<bool forMainScreen>
|
||||||
void RenderBgColor();
|
void RenderBgColor();
|
||||||
|
|
||||||
|
template<uint8_t layerIndex, uint8_t bpp, bool processHighPriority, bool forMainScreen, bool largeTileWidth, bool largeTileHeight, uint16_t basePaletteOffset>
|
||||||
|
void RenderTilemapLargeTiles();
|
||||||
|
|
||||||
template<uint8_t layerIndex, uint8_t bpp, bool processHighPriority, bool forMainScreen, uint16_t basePaletteOffset = 0>
|
template<uint8_t layerIndex, uint8_t bpp, bool processHighPriority, bool forMainScreen, uint16_t basePaletteOffset = 0>
|
||||||
void RenderTilemap();
|
void RenderTilemap();
|
||||||
|
|
||||||
template<uint8_t layerIndex, uint8_t bpp, bool processHighPriority, bool forMainScreen, bool largeTiles, uint16_t basePaletteOffset, uint8_t activeWindowCount, bool applyMosaic>
|
template<uint8_t layerIndex, uint8_t bpp, bool processHighPriority, bool forMainScreen, bool largeTileWidth, bool largeTileHeight, uint16_t basePaletteOffset, uint8_t activeWindowCount, bool applyMosaic>
|
||||||
void RenderTilemap();
|
void RenderTilemap();
|
||||||
|
|
||||||
template<uint8_t layerIndex, bool forMainScreen, bool applyMosaic, bool processHighPriority>
|
template<uint8_t layerIndex, bool forMainScreen, bool applyMosaic, bool processHighPriority>
|
||||||
|
@ -173,8 +183,12 @@ private:
|
||||||
__forceinline void DrawSubPixel(uint8_t x, uint16_t paletteRamOffset);
|
__forceinline void DrawSubPixel(uint8_t x, uint16_t paletteRamOffset);
|
||||||
|
|
||||||
void ApplyColorMath();
|
void ApplyColorMath();
|
||||||
|
|
||||||
|
template<bool forMainScreen>
|
||||||
void ApplyBrightness();
|
void ApplyBrightness();
|
||||||
|
|
||||||
|
void ApplyHiResMode();
|
||||||
|
|
||||||
template<uint8_t layerIndex>
|
template<uint8_t layerIndex>
|
||||||
bool ProcessMaskWindow(uint8_t activeWindowCount, int x);
|
bool ProcessMaskWindow(uint8_t activeWindowCount, int x);
|
||||||
void ProcessWindowMaskSettings(uint8_t value, uint8_t offset);
|
void ProcessWindowMaskSettings(uint8_t value, uint8_t offset);
|
||||||
|
|
|
@ -62,28 +62,10 @@ enum class VideoAspectRatio
|
||||||
|
|
||||||
struct OverscanDimensions
|
struct OverscanDimensions
|
||||||
{
|
{
|
||||||
static const int ScreenWidth = 256;
|
|
||||||
static const int ScreenHeight = 224;
|
|
||||||
|
|
||||||
uint32_t Left = 0;
|
uint32_t Left = 0;
|
||||||
uint32_t Right = 0;
|
uint32_t Right = 0;
|
||||||
uint32_t Top = 0;
|
uint32_t Top = 0;
|
||||||
uint32_t Bottom = 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
|
struct PictureSettings
|
||||||
|
@ -116,9 +98,6 @@ struct FrameInfo
|
||||||
{
|
{
|
||||||
uint32_t Width;
|
uint32_t Width;
|
||||||
uint32_t Height;
|
uint32_t Height;
|
||||||
uint32_t OriginalWidth;
|
|
||||||
uint32_t OriginalHeight;
|
|
||||||
uint32_t BitsPerPixel;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ScreenSize
|
struct ScreenSize
|
||||||
|
|
|
@ -43,15 +43,23 @@ void VideoDecoder::GetScreenSize(ScreenSize &size, bool ignoreScale)
|
||||||
}
|
}
|
||||||
|
|
||||||
size.Scale = scale;*/
|
size.Scale = scale;*/
|
||||||
|
|
||||||
if(ignoreScale) {
|
|
||||||
size.Width = 256;
|
|
||||||
size.Height = 224;
|
|
||||||
} else {
|
|
||||||
size.Width = 512;
|
|
||||||
size.Height = 448;
|
|
||||||
}
|
|
||||||
size.Scale = 2;
|
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();
|
UpdateVideoFilter();
|
||||||
|
|
||||||
|
_videoFilter->SetBaseFrameInfo(_baseFrameInfo);
|
||||||
_videoFilter->SendFrame(_ppuOutputBuffer, _frameNumber);
|
_videoFilter->SendFrame(_ppuOutputBuffer, _frameNumber);
|
||||||
|
|
||||||
uint32_t* outputBuffer = _videoFilter->GetOutputBuffer();
|
uint32_t* outputBuffer = _videoFilter->GetOutputBuffer();
|
||||||
|
@ -150,15 +159,17 @@ uint32_t VideoDecoder::GetFrameCount()
|
||||||
return _frameCount;
|
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;
|
_frameNumber = frameNumber;
|
||||||
_ppuOutputBuffer = ppuOutputBuffer;
|
_ppuOutputBuffer = ppuOutputBuffer;
|
||||||
DecodeFrame(true);
|
DecodeFrame(true);
|
||||||
_frameCount++;
|
_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) {
|
if(_frameChanged) {
|
||||||
//Last frame isn't done decoding yet - sometimes Signal() introduces a 25-30ms delay
|
//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
|
//At this point, we are sure that the decode thread is no longer busy
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_baseFrameInfo.Width = width;
|
||||||
|
_baseFrameInfo.Height = height;
|
||||||
_frameNumber = frameNumber;
|
_frameNumber = frameNumber;
|
||||||
_ppuOutputBuffer = ppuOutputBuffer;
|
_ppuOutputBuffer = ppuOutputBuffer;
|
||||||
_frameChanged = true;
|
_frameChanged = true;
|
||||||
|
|
|
@ -28,6 +28,7 @@ private:
|
||||||
atomic<bool> _stopFlag;
|
atomic<bool> _stopFlag;
|
||||||
uint32_t _frameCount = 0;
|
uint32_t _frameCount = 0;
|
||||||
|
|
||||||
|
FrameInfo _baseFrameInfo = { 256, 224 };
|
||||||
ScreenSize _previousScreenSize = {};
|
ScreenSize _previousScreenSize = {};
|
||||||
double _previousScale = 0;
|
double _previousScale = 0;
|
||||||
FrameInfo _lastFrameInfo;
|
FrameInfo _lastFrameInfo;
|
||||||
|
@ -54,8 +55,8 @@ public:
|
||||||
FrameInfo GetFrameInfo();
|
FrameInfo GetFrameInfo();
|
||||||
void GetScreenSize(ScreenSize &size, bool ignoreScale);
|
void GetScreenSize(ScreenSize &size, bool ignoreScale);
|
||||||
|
|
||||||
void UpdateFrameSync(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, uint32_t frameNumber);
|
void UpdateFrame(uint16_t *ppuOutputBuffer, uint16_t width, uint16_t height, uint32_t frameNumber);
|
||||||
|
|
||||||
bool IsRunning();
|
bool IsRunning();
|
||||||
void StartThread();
|
void StartThread();
|
||||||
|
|
Loading…
Add table
Reference in a new issue