PPU: Window support (except color window)
This commit is contained in:
parent
7f5d93d680
commit
a009e899a2
3 changed files with 174 additions and 2 deletions
130
Core/Ppu.cpp
130
Core/Ppu.cpp
|
@ -126,17 +126,32 @@ void Ppu::Exec()
|
||||||
template<uint8_t priority, bool forMainScreen>
|
template<uint8_t priority, bool forMainScreen>
|
||||||
void Ppu::RenderSprites()
|
void Ppu::RenderSprites()
|
||||||
{
|
{
|
||||||
|
uint8_t activeWindowCount = 0;
|
||||||
if(forMainScreen) {
|
if(forMainScreen) {
|
||||||
if(_pixelsDrawn == 256 || (_mainScreenLayers & 0x10) == 0) {
|
if(_pixelsDrawn == 256 || (_mainScreenLayers & 0x10) == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else if(_subPixelsDrawn == 256 || (_subScreenLayers & 0x10) == 0) {
|
if(_windowMaskMain[Ppu::SpriteLayerIndex]) {
|
||||||
return;
|
activeWindowCount = (uint8_t)_window[0].ActiveLayers[Ppu::SpriteLayerIndex] + (uint8_t)_window[1].ActiveLayers[Ppu::SpriteLayerIndex];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(_subPixelsDrawn == 256 || (_subScreenLayers & 0x10) == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(_windowMaskSub[Ppu::SpriteLayerIndex]) {
|
||||||
|
activeWindowCount = (uint8_t)_window[0].ActiveLayers[Ppu::SpriteLayerIndex] + (uint8_t)_window[1].ActiveLayers[Ppu::SpriteLayerIndex];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(forMainScreen) {
|
if(forMainScreen) {
|
||||||
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)) {
|
||||||
|
//This pixel was masked
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
_currentBuffer[(_scanline << 8) | x] = _spritePixels[x];
|
_currentBuffer[(_scanline << 8) | 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);
|
||||||
}
|
}
|
||||||
|
@ -144,6 +159,11 @@ void Ppu::RenderSprites()
|
||||||
} else {
|
} else {
|
||||||
for(int x = 0; x < 256; x++) {
|
for(int x = 0; x < 256; x++) {
|
||||||
if(!_subScreenFilled[x] && _spritePriority[x] == priority) {
|
if(!_subScreenFilled[x] && _spritePriority[x] == priority) {
|
||||||
|
if(activeWindowCount && ProcessMaskWindow<Ppu::SpriteLayerIndex>(activeWindowCount, x)) {
|
||||||
|
//This pixel was masked
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
_subScreenBuffer[x] = _spritePixels[x];
|
_subScreenBuffer[x] = _spritePixels[x];
|
||||||
_subScreenFilled[x] = true;
|
_subScreenFilled[x] = true;
|
||||||
}
|
}
|
||||||
|
@ -431,6 +451,11 @@ void Ppu::RenderTilemap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8_t activeWindowCount = 0;
|
||||||
|
if((forMainScreen && _windowMaskMain[layerIndex]) || (!forMainScreen && _windowMaskSub[layerIndex])) {
|
||||||
|
activeWindowCount = (uint8_t)_window[0].ActiveLayers[layerIndex] + (uint8_t)_window[1].ActiveLayers[layerIndex];
|
||||||
|
}
|
||||||
|
|
||||||
bool applyMosaic = forMainScreen && ((_mosaicEnabled >> layerIndex) & 0x01) != 0;
|
bool applyMosaic = forMainScreen && ((_mosaicEnabled >> layerIndex) & 0x01) != 0;
|
||||||
bool mosaicScanline = applyMosaic && (_scanline - _mosaicStartScanline) % _mosaicSize != 0;
|
bool mosaicScanline = applyMosaic && (_scanline - _mosaicStartScanline) % _mosaicSize != 0;
|
||||||
|
|
||||||
|
@ -459,6 +484,11 @@ void Ppu::RenderTilemap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(activeWindowCount && ProcessMaskWindow<layerIndex>(activeWindowCount, x)) {
|
||||||
|
//This pixel was masked
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if(mosaicScanline || (applyMosaic && x % _mosaicSize != 0)) {
|
if(mosaicScanline || (applyMosaic && 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[(_scanline << 8) | x] = _mosaicColor[x];
|
_currentBuffer[(_scanline << 8) | x] = _mosaicColor[x];
|
||||||
|
@ -569,6 +599,39 @@ void Ppu::ApplyColorMath()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<uint8_t layerIndex>
|
||||||
|
bool Ppu::ProcessMaskWindow(uint8_t activeWindowCount, int x)
|
||||||
|
{
|
||||||
|
if(activeWindowCount == 1) {
|
||||||
|
if(_window[0].ActiveLayers[layerIndex]) {
|
||||||
|
return _window[0].PixelNeedsMasking<layerIndex>(x);
|
||||||
|
} else {
|
||||||
|
return _window[1].PixelNeedsMasking<layerIndex>(x);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
switch(_maskLogic[layerIndex]) {
|
||||||
|
default:
|
||||||
|
case WindowMaskLogic::Or: return _window[0].PixelNeedsMasking<layerIndex>(x) | _window[1].PixelNeedsMasking<layerIndex>(x);
|
||||||
|
case WindowMaskLogic::And: return _window[0].PixelNeedsMasking<layerIndex>(x) & _window[1].PixelNeedsMasking<layerIndex>(x);
|
||||||
|
case WindowMaskLogic::Xor: return _window[0].PixelNeedsMasking<layerIndex>(x) ^ _window[1].PixelNeedsMasking<layerIndex>(x);
|
||||||
|
case WindowMaskLogic::Xnor: return !(_window[0].PixelNeedsMasking<layerIndex>(x) ^ _window[1].PixelNeedsMasking<layerIndex>(x));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Ppu::ProcessWindowMaskSettings(uint8_t value, uint8_t offset)
|
||||||
|
{
|
||||||
|
_window[0].ActiveLayers[0 + offset] = (value & 0x02) != 0;
|
||||||
|
_window[0].ActiveLayers[1 + offset] = (value & 0x20) != 0;
|
||||||
|
_window[0].InvertedLayers[0 + offset] = (value & 0x01) != 0;
|
||||||
|
_window[0].InvertedLayers[1 + offset] = (value & 0x10) != 0;
|
||||||
|
|
||||||
|
_window[1].ActiveLayers[0 + offset] = (value & 0x08) != 0;
|
||||||
|
_window[1].ActiveLayers[1 + offset] = (value & 0x80) != 0;
|
||||||
|
_window[1].InvertedLayers[0 + offset] = (value & 0x04) != 0;
|
||||||
|
_window[1].InvertedLayers[1 + offset] = (value & 0x40) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
void Ppu::SendFrame()
|
void Ppu::SendFrame()
|
||||||
{
|
{
|
||||||
_console->GetNotificationManager()->SendNotification(ConsoleNotificationType::PpuFrameDone);
|
_console->GetNotificationManager()->SendNotification(ConsoleNotificationType::PpuFrameDone);
|
||||||
|
@ -876,6 +939,55 @@ void Ppu::Write(uint32_t addr, uint8_t value)
|
||||||
_cgramAddress = (_cgramAddress + 1) & (Ppu::CgRamSize - 1);
|
_cgramAddress = (_cgramAddress + 1) & (Ppu::CgRamSize - 1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 0x2123:
|
||||||
|
//W12SEL - Window Mask Settings for BG1 and BG2
|
||||||
|
ProcessWindowMaskSettings(value, 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x2124:
|
||||||
|
//W34SEL - Window Mask Settings for BG3 and BG4
|
||||||
|
ProcessWindowMaskSettings(value, 2);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x2125:
|
||||||
|
//WOBJSEL - Window Mask Settings for OBJ and Color Window
|
||||||
|
ProcessWindowMaskSettings(value, 4);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x2126:
|
||||||
|
//WH0 - Window 1 Left Position
|
||||||
|
_window[0].Left = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x2127:
|
||||||
|
//WH1 - Window 1 Right Position
|
||||||
|
_window[0].Right = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x2128:
|
||||||
|
//WH2 - Window 2 Left Position
|
||||||
|
_window[1].Left = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x2129:
|
||||||
|
//WH3 - Window 2 Right Position
|
||||||
|
_window[1].Right = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x212A:
|
||||||
|
//WBGLOG - Window mask logic for BG
|
||||||
|
_maskLogic[0] = (WindowMaskLogic)(value & 0x03);
|
||||||
|
_maskLogic[1] = (WindowMaskLogic)((value >> 2) & 0x03);
|
||||||
|
_maskLogic[2] = (WindowMaskLogic)((value >> 4) & 0x03);
|
||||||
|
_maskLogic[3] = (WindowMaskLogic)((value >> 6) & 0x03);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x212B:
|
||||||
|
//WOBJLOG - Window mask logic for OBJs and Color Window
|
||||||
|
_maskLogic[5] = (WindowMaskLogic)((value >> 0) & 0x03);
|
||||||
|
_maskLogic[6] = (WindowMaskLogic)((value >> 2) & 0x03);
|
||||||
|
break;
|
||||||
|
|
||||||
case 0x212C:
|
case 0x212C:
|
||||||
//TM - Main Screen Designation
|
//TM - Main Screen Designation
|
||||||
_mainScreenLayers = value & 0x1F;
|
_mainScreenLayers = value & 0x1F;
|
||||||
|
@ -885,6 +997,20 @@ void Ppu::Write(uint32_t addr, uint8_t value)
|
||||||
//TS - Subscreen Designation
|
//TS - Subscreen Designation
|
||||||
_subScreenLayers = value & 0x1F;
|
_subScreenLayers = value & 0x1F;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 0x212E:
|
||||||
|
//TMW - Window Mask Designation for the Main Screen
|
||||||
|
for(int i = 0; i < 5; i++) {
|
||||||
|
_windowMaskMain[i] = ((value >> i) & 0x01) != 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x212F:
|
||||||
|
//TSW - Window Mask Designation for the Subscreen
|
||||||
|
for(int i = 0; i < 5; i++) {
|
||||||
|
_windowMaskSub[i] = ((value >> i) & 0x01) != 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case 0x2130:
|
case 0x2130:
|
||||||
//CGWSEL - Color Addition Select
|
//CGWSEL - Color Addition Select
|
||||||
|
|
12
Core/Ppu.h
12
Core/Ppu.h
|
@ -27,6 +27,8 @@ public:
|
||||||
constexpr static uint32_t VideoRamSize = 0x10000;
|
constexpr static uint32_t VideoRamSize = 0x10000;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
constexpr static int SpriteLayerIndex = 4;
|
||||||
|
|
||||||
constexpr static const uint8_t _oamSizes[8][2][2] = {
|
constexpr static const uint8_t _oamSizes[8][2][2] = {
|
||||||
{ { 1, 1 }, { 2, 2 } }, //8x8 + 16x16
|
{ { 1, 1 }, { 2, 2 } }, //8x8 + 16x16
|
||||||
{ { 1, 1 }, { 4, 4 } }, //8x8 + 32x32
|
{ { 1, 1 }, { 4, 4 } }, //8x8 + 32x32
|
||||||
|
@ -54,6 +56,11 @@ private:
|
||||||
uint8_t _mainScreenLayers = 0;
|
uint8_t _mainScreenLayers = 0;
|
||||||
uint8_t _subScreenLayers = 0;
|
uint8_t _subScreenLayers = 0;
|
||||||
LayerConfig _layerConfig[4];
|
LayerConfig _layerConfig[4];
|
||||||
|
|
||||||
|
WindowConfig _window[2];
|
||||||
|
WindowMaskLogic _maskLogic[6];
|
||||||
|
bool _windowMaskMain[5];
|
||||||
|
bool _windowMaskSub[5];
|
||||||
|
|
||||||
uint8_t *_vram;
|
uint8_t *_vram;
|
||||||
uint16_t _vramAddress;
|
uint16_t _vramAddress;
|
||||||
|
@ -150,6 +157,11 @@ private:
|
||||||
|
|
||||||
void RenderScanline();
|
void RenderScanline();
|
||||||
void ApplyColorMath();
|
void ApplyColorMath();
|
||||||
|
|
||||||
|
template<uint8_t layerIndex>
|
||||||
|
bool ProcessMaskWindow(uint8_t activeWindowCount, int x);
|
||||||
|
void ProcessWindowMaskSettings(uint8_t value, uint8_t offset);
|
||||||
|
|
||||||
void SendFrame();
|
void SendFrame();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -20,4 +20,38 @@ struct LayerConfig
|
||||||
bool VerticalMirroring;
|
bool VerticalMirroring;
|
||||||
|
|
||||||
bool LargeTiles;
|
bool LargeTiles;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct WindowConfig
|
||||||
|
{
|
||||||
|
bool ActiveLayers[6];
|
||||||
|
bool InvertedLayers[6];
|
||||||
|
uint8_t Left;
|
||||||
|
uint8_t Right;
|
||||||
|
|
||||||
|
template<uint8_t layerIndex>
|
||||||
|
bool PixelNeedsMasking(int x)
|
||||||
|
{
|
||||||
|
if(InvertedLayers[layerIndex]) {
|
||||||
|
if(Left > Right) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return x < Left || x > Right;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(Left > Right) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return x >= Left && x <= Right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class WindowMaskLogic
|
||||||
|
{
|
||||||
|
Or = 0,
|
||||||
|
And = 1,
|
||||||
|
Xor = 2,
|
||||||
|
Xnor = 3
|
||||||
};
|
};
|
Loading…
Add table
Reference in a new issue