1 #include "stdafx.h"
2 #include "HdPpu.h"
3 #include "CPU.h"
4 #include "Console.h"
5 #include "HdNesPack.h"
6 #include "VideoDecoder.h"
7 #include "RewindManager.h"
8 #include "HdPackConditions.h"
9 #include "NotificationManager.h"
10 #include "BaseMapper.h"
11 #include "MemoryManager.h"
12 
DrawPixel()13 void HdPpu::DrawPixel()
14 {
15 	uint16_t bufferOffset = (_scanline << 8) + _cycle - 1;
16 	uint16_t &pixel = _currentOutputBuffer[bufferOffset];
17 	_lastSprite = nullptr;
18 
19 	if(IsRenderingEnabled() || ((_state.VideoRamAddr & 0x3F00) != 0x3F00)) {
20 		bool isChrRam = !_console->GetMapper()->HasChrRom();
21 		BaseMapper *mapper = _console->GetMapper();
22 
23 		uint32_t color = GetPixelColor();
24 		pixel = (_paletteRAM[color & 0x03 ? color : 0] & _paletteRamMask) | _intensifyColorBits;
25 
26 		TileInfo* lastTile = &((_state.XScroll + ((_cycle - 1) & 0x07) < 8) ? _previousTile : _currentTile);
27 		uint32_t backgroundColor = 0;
28 		if(_flags.BackgroundEnabled && _cycle > _minimumDrawBgCycle) {
29 			backgroundColor = (((_state.LowBitShift << _state.XScroll) & 0x8000) >> 15) | (((_state.HighBitShift << _state.XScroll) & 0x8000) >> 14);
30 		}
31 
32 		HdPpuPixelInfo &tileInfo = _info->ScreenTiles[bufferOffset];
33 
34 		tileInfo.Grayscale = _paletteRamMask == 0x30;
35 		tileInfo.EmphasisBits = _intensifyColorBits >> 6;
36 		tileInfo.Tile.PpuBackgroundColor = ReadPaletteRAM(0);
37 		tileInfo.Tile.BgColorIndex = backgroundColor;
38 		if(backgroundColor == 0) {
39 			tileInfo.Tile.BgColor = tileInfo.Tile.PpuBackgroundColor;
40 		} else {
41 			tileInfo.Tile.BgColor = ReadPaletteRAM(lastTile->PaletteOffset + backgroundColor);
42 		}
43 
44 		tileInfo.XScroll = _state.XScroll;
45 		tileInfo.TmpVideoRamAddr = _state.TmpVideoRamAddr;
46 
47 		if(_lastSprite && _flags.SpritesEnabled) {
48 			int j = 0;
49 			for(uint8_t i = 0; i < _spriteCount; i++) {
50 				int32_t shift = (int32_t)_cycle - _spriteTiles[i].SpriteX - 1;
51 				SpriteInfo& sprite = _spriteTiles[i];
52 				if(shift >= 0 && shift < 8) {
53 					tileInfo.Sprite[j].TileIndex = sprite.AbsoluteTileAddr / 16;
54 					if(isChrRam) {
55 						mapper->CopyChrTile(sprite.AbsoluteTileAddr & 0xFFFFFFF0, tileInfo.Sprite[j].TileData);
56 					}
57 					if(_version >= 100) {
58 						tileInfo.Sprite[j].PaletteColors = 0xFF000000 | _paletteRAM[sprite.PaletteOffset + 3] | (_paletteRAM[sprite.PaletteOffset + 2] << 8) | (_paletteRAM[sprite.PaletteOffset + 1] << 16);
59 					} else {
60 						tileInfo.Sprite[j].PaletteColors = _paletteRAM[sprite.PaletteOffset + 3] | (_paletteRAM[sprite.PaletteOffset + 2] << 8) | (_paletteRAM[sprite.PaletteOffset + 1] << 16);
61 					}
62 					if(sprite.OffsetY >= 8) {
63 						tileInfo.Sprite[j].OffsetY = sprite.OffsetY - 8;
64 					} else {
65 						tileInfo.Sprite[j].OffsetY = sprite.OffsetY;
66 					}
67 
68 					tileInfo.Sprite[j].OffsetX = shift;
69 					tileInfo.Sprite[j].HorizontalMirroring = sprite.HorizontalMirror;
70 					tileInfo.Sprite[j].VerticalMirroring = sprite.VerticalMirror;
71 					tileInfo.Sprite[j].BackgroundPriority = sprite.BackgroundPriority;
72 
73 					int32_t shift = (int32_t)_cycle - sprite.SpriteX - 1;
74 					if(sprite.HorizontalMirror) {
75 						tileInfo.Sprite[j].SpriteColorIndex = ((sprite.LowByte >> shift) & 0x01) | ((sprite.HighByte >> shift) & 0x01) << 1;
76 					} else {
77 						tileInfo.Sprite[j].SpriteColorIndex = ((sprite.LowByte << shift) & 0x80) >> 7 | ((sprite.HighByte << shift) & 0x80) >> 6;
78 					}
79 
80 					if(tileInfo.Sprite[j].SpriteColorIndex == 0) {
81 						tileInfo.Sprite[j].SpriteColor = ReadPaletteRAM(0);
82 					} else {
83 						tileInfo.Sprite[j].SpriteColor = ReadPaletteRAM(sprite.PaletteOffset + tileInfo.Sprite[j].SpriteColorIndex);
84 					}
85 
86 					tileInfo.Sprite[j].PpuBackgroundColor = tileInfo.Tile.PpuBackgroundColor;
87 					tileInfo.Sprite[j].BgColorIndex = tileInfo.Tile.BgColorIndex;
88 
89 					j++;
90 					if(j >= 4) {
91 						break;
92 					}
93 				}
94 			}
95 			tileInfo.SpriteCount = j;
96 		} else {
97 			tileInfo.SpriteCount = 0;
98 		}
99 
100 		if(_flags.BackgroundEnabled && _cycle > _minimumDrawBgCycle) {
101 			tileInfo.Tile.TileIndex = lastTile->AbsoluteTileAddr / 16;
102 			if(isChrRam) {
103 				mapper->CopyChrTile(lastTile->AbsoluteTileAddr & 0xFFFFFFF0, tileInfo.Tile.TileData);
104 			}
105 			if(_version >= 100) {
106 				tileInfo.Tile.PaletteColors = _paletteRAM[lastTile->PaletteOffset + 3] | (_paletteRAM[lastTile->PaletteOffset + 2] << 8) | (_paletteRAM[lastTile->PaletteOffset + 1] << 16) | (_paletteRAM[0] << 24);
107 			} else {
108 				tileInfo.Tile.PaletteColors = _paletteRAM[lastTile->PaletteOffset + 3] | (_paletteRAM[lastTile->PaletteOffset + 2] << 8) | (_paletteRAM[lastTile->PaletteOffset + 1] << 16);
109 			}
110 			tileInfo.Tile.OffsetY = lastTile->OffsetY;
111 			tileInfo.Tile.OffsetX = (_state.XScroll + ((_cycle - 1) & 0x07)) & 0x07;
112 		} else {
113 			tileInfo.Tile.TileIndex = HdPpuTileInfo::NoTile;
114 		}
115 	} else {
116 		//"If the current VRAM address points in the range $3F00-$3FFF during forced blanking, the color indicated by this palette location will be shown on screen instead of the backdrop color."
117 		pixel = ReadPaletteRAM(_state.VideoRamAddr) | _intensifyColorBits;
118 		_info->ScreenTiles[bufferOffset].Tile.TileIndex = HdPpuTileInfo::NoTile;
119 		_info->ScreenTiles[bufferOffset].SpriteCount = 0;
120 	}
121 }
122 
HdPpu(shared_ptr<Console> console,HdPackData * hdData)123 HdPpu::HdPpu(shared_ptr<Console> console, HdPackData * hdData) : PPU(console)
124 {
125 	_hdData = hdData;
126 
127 	if(_hdData) {
128 		_version = _hdData->Version;
129 
130 		bool isChrRamGame = !console->GetMapper()->HasChrRom();
131 		_screenInfo[0] = new HdScreenInfo(isChrRamGame);
132 		_screenInfo[1] = new HdScreenInfo(isChrRamGame);
133 		_info = _screenInfo[0];
134 	}
135 }
136 
~HdPpu()137 HdPpu::~HdPpu()
138 {
139 	if(_hdData) {
140 		delete _screenInfo[0];
141 		delete _screenInfo[1];
142 	}
143 }
144 
SendFrame()145 void HdPpu::SendFrame()
146 {
147 	_console->GetNotificationManager()->SendNotification(ConsoleNotificationType::PpuFrameDone, _currentOutputBuffer);
148 
149 	_info->FrameNumber = _frameCount;
150 	_info->WatchedAddressValues.clear();
151 	for(uint32_t address : _hdData->WatchedMemoryAddresses) {
152 		if(address & HdPackBaseMemoryCondition::PpuMemoryMarker) {
153 			if((address & 0x3FFF) >= 0x3F00) {
154 				_info->WatchedAddressValues[address] = ReadPaletteRAM(address);
155 			} else {
156 				_info->WatchedAddressValues[address] = _console->GetMapper()->DebugReadVRAM(address & 0x3FFF, true);
157 			}
158 		} else {
159 			_info->WatchedAddressValues[address] = _console->GetMemoryManager()->DebugRead(address);
160 		}
161 	}
162 
163 #ifdef  LIBRETRO
164 	_console->GetVideoDecoder()->UpdateFrameSync(_currentOutputBuffer, _info);
165 #else
166 	if(_console->GetRewindManager()->IsRewinding()) {
167 		_console->GetVideoDecoder()->UpdateFrameSync(_currentOutputBuffer, _info);
168 	} else {
169 		_console->GetVideoDecoder()->UpdateFrame(_currentOutputBuffer, _info);
170 	}
171 	_currentOutputBuffer = (_currentOutputBuffer == _outputBuffers[0]) ? _outputBuffers[1] : _outputBuffers[0];
172 	_info = (_info == _screenInfo[0]) ? _screenInfo[1] : _screenInfo[0];
173 #endif
174 }
175