Optimizations (+25% speed), changed the way frame buffer is sent to the GUI
This commit is contained in:
parent
e4692cdd9c
commit
0bac761beb
8 changed files with 59 additions and 70 deletions
|
@ -87,6 +87,7 @@
|
|||
<ClInclude Include="BaseMapper.h" />
|
||||
<ClInclude Include="IMemoryHandler.h" />
|
||||
<ClInclude Include="Console.h" />
|
||||
<ClInclude Include="IVideoDevice.h" />
|
||||
<ClInclude Include="PPU.h" />
|
||||
<ClInclude Include="CPU.h" />
|
||||
<ClInclude Include="MemoryManager.h" />
|
||||
|
|
|
@ -42,6 +42,9 @@
|
|||
<ClInclude Include="Console.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="IVideoDevice.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Timer.h">
|
||||
|
|
9
Core/IVideoDevice.h
Normal file
9
Core/IVideoDevice.h
Normal file
|
@ -0,0 +1,9 @@
|
|||
#pragma once
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
class IVideoDevice
|
||||
{
|
||||
public:
|
||||
virtual void UpdateFrame(uint8_t *outputBuffer) = 0;
|
||||
};
|
67
Core/PPU.cpp
67
Core/PPU.cpp
|
@ -2,6 +2,8 @@
|
|||
#include "PPU.h"
|
||||
#include "CPU.h"
|
||||
|
||||
IVideoDevice *PPU::VideoDevice = nullptr;
|
||||
|
||||
uint32_t PPU_PALETTE_RGB[] = {
|
||||
0x666666, 0x002A88, 0x1412A7, 0x3B00A4, 0x5C007E,
|
||||
0x6E0040, 0x6C0600, 0x561D00, 0x333500, 0x0B4800,
|
||||
|
@ -18,9 +20,6 @@ uint32_t PPU_PALETTE_RGB[] = {
|
|||
0xB5EBF2, 0xB8B8B8, 0x000000, 0x000000,
|
||||
};
|
||||
|
||||
uint8_t *PPU::FrameBuffer = new uint8_t[256*240*4];
|
||||
atomic<int> PPU::WaitCounter = 0;
|
||||
|
||||
PPU::PPU(MemoryManager *memoryManager)
|
||||
{
|
||||
_memoryManager = memoryManager;
|
||||
|
@ -267,13 +266,13 @@ void PPU::LoadShiftRegisters()
|
|||
|
||||
void PPU::DrawPixel()
|
||||
{
|
||||
uint8_t tileXPixel = (_cycle - 1) % 8;
|
||||
uint8_t offset = (15 - tileXPixel - _state.XScroll);
|
||||
uint32_t tileXPixel = (_cycle - 1) % 8;
|
||||
uint32_t offset = (15 - tileXPixel - _state.XScroll);
|
||||
|
||||
uint8_t pixelColor = ((_state.LowBitShift >> offset) & 0x01) | (((_state.HighBitShift >> offset) & 0x01) << 1);
|
||||
|
||||
// If we're grabbing the pixel from the high part of the shift register, use the buffered palette, not the current one
|
||||
uint8_t palette = 0;
|
||||
uint32_t palette = 0;
|
||||
if(offset < 8) {
|
||||
palette = GetBGPaletteEntry(_nextTile.Attributes, pixelColor);
|
||||
} else {
|
||||
|
@ -314,7 +313,7 @@ void PPU::ProcessVisibleScanline()
|
|||
|
||||
if(_cycle == 256) {
|
||||
if(_scanline == 239) {
|
||||
CopyFrame();
|
||||
PPU::VideoDevice->UpdateFrame(_outputBuffer);
|
||||
}
|
||||
if(_flags.BackgroundEnabled) {
|
||||
//Ppu_renderTileRow(p);
|
||||
|
@ -328,51 +327,11 @@ void PPU::ProcessVisibleScanline()
|
|||
|
||||
uint8_t PPU::GetBGPaletteEntry(uint8_t a, uint16_t pix)
|
||||
{
|
||||
uint16_t baseAddr = 0x3F00;
|
||||
if(pix == 0x0) {
|
||||
return _memoryManager->ReadVRAM(baseAddr);
|
||||
if(pix == 0) {
|
||||
return _memoryManager->ReadVRAM(0x3F00);
|
||||
} else {
|
||||
return _memoryManager->ReadVRAM(0x3F00 + a + pix);
|
||||
}
|
||||
|
||||
switch(a) {
|
||||
case 0x0:
|
||||
return _memoryManager->ReadVRAM(baseAddr + pix);
|
||||
case 0x4:
|
||||
return _memoryManager->ReadVRAM(baseAddr + 0x04 + pix);
|
||||
case 0x8:
|
||||
return _memoryManager->ReadVRAM(baseAddr + 0x08 + pix);
|
||||
case 0xC:
|
||||
return _memoryManager->ReadVRAM(baseAddr + 0x0C + pix);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void PPU::CopyFrame()
|
||||
{
|
||||
int counter = PPU::WaitCounter.fetch_add(1);
|
||||
if(counter != 0) {
|
||||
//We weren't the first thread to increment the value, wait until other locks are released
|
||||
while(PPU::WaitCounter > 1) {}
|
||||
}
|
||||
|
||||
memcpy(PPU::FrameBuffer, _outputBuffer, 256 * 240 * 4);
|
||||
PPU::WaitCounter--;
|
||||
}
|
||||
|
||||
uint8_t* PPU::GetFrame()
|
||||
{
|
||||
uint8_t *copyBuffer = new uint8_t[256 * 240 * 4];
|
||||
|
||||
int counter = PPU::WaitCounter.fetch_add(1);
|
||||
if(counter != 0) {
|
||||
//We weren't the first thread to increment the value, wait until other locks are released
|
||||
while(PPU::WaitCounter > 1) {}
|
||||
}
|
||||
|
||||
memcpy(copyBuffer, PPU::FrameBuffer, 256 * 240 * 4);
|
||||
PPU::WaitCounter--;
|
||||
|
||||
return copyBuffer;
|
||||
}
|
||||
|
||||
void PPU::BeginVBlank()
|
||||
|
@ -402,7 +361,9 @@ void PPU::EndVBlank()
|
|||
void PPU::Exec()
|
||||
{
|
||||
uint64_t equivalentCycleCount = CPU::GetCycleCount() * 3;
|
||||
while(_cycleCount < equivalentCycleCount) {
|
||||
uint32_t gap = equivalentCycleCount - _cycleCount;
|
||||
_cycleCount += gap;
|
||||
while(gap > 0) {
|
||||
if(_scanline == -1) {
|
||||
ProcessPrerenderScanline();
|
||||
} else if(_scanline < 240) {
|
||||
|
@ -424,6 +385,6 @@ void PPU::Exec()
|
|||
_cycle++;
|
||||
}
|
||||
|
||||
_cycleCount++;
|
||||
gap--;
|
||||
}
|
||||
}
|
20
Core/PPU.h
20
Core/PPU.h
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include "stdafx.h"
|
||||
#include "MemoryManager.h"
|
||||
#include "IVideoDevice.h"
|
||||
|
||||
enum PPURegisters
|
||||
{
|
||||
|
@ -66,23 +67,21 @@ struct TileInfo
|
|||
class PPU : public IMemoryHandler
|
||||
{
|
||||
private:
|
||||
static uint8_t *FrameBuffer;
|
||||
static atomic<int> WaitCounter;
|
||||
static IVideoDevice *VideoDevice;
|
||||
|
||||
MemoryManager *_memoryManager;
|
||||
|
||||
PPUState _state;
|
||||
uint64_t _cycleCount;
|
||||
int32_t _scanline = 0;
|
||||
uint32_t _cycle = 0;
|
||||
uint32_t _frameCount = 0;
|
||||
uint64_t _cycleCount = 0;
|
||||
uint8_t _memoryReadBuffer = 0;
|
||||
|
||||
uint8_t _memoryReadBuffer;
|
||||
uint8_t _spriteRAM[0x100];
|
||||
|
||||
uint8_t *_outputBuffer;
|
||||
|
||||
int16_t _scanline = 0;
|
||||
uint16_t _cycle = 0;
|
||||
uint32_t _frameCount = 0;
|
||||
|
||||
PPUControlFlags _flags;
|
||||
PPUStatusFlags _statusFlags;
|
||||
|
||||
|
@ -135,7 +134,10 @@ class PPU : public IMemoryHandler
|
|||
|
||||
void Exec();
|
||||
|
||||
static uint8_t* GetFrame();
|
||||
static void RegisterVideoDevice(IVideoDevice *videoDevice)
|
||||
{
|
||||
PPU::VideoDevice = videoDevice;
|
||||
}
|
||||
|
||||
uint32_t GetFrameCount()
|
||||
{
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
namespace NES
|
||||
{
|
||||
bool Renderer::Initialize(HINSTANCE hInstance, HWND hWnd) {
|
||||
PPU::RegisterVideoDevice(this);
|
||||
|
||||
_hInst = hInstance;
|
||||
_hWnd = hWnd;
|
||||
|
||||
|
@ -141,8 +143,10 @@ namespace NES
|
|||
renderTargetViewDescription.Format = desc.Format;
|
||||
renderTargetViewDescription.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; // MS;
|
||||
|
||||
_videoRAM = new byte[screenwidth*screenheight * 4];
|
||||
memset(_videoRAM, 0xFF, screenwidth*screenheight*4);
|
||||
_videoRAM = new uint8_t[screenwidth*screenheight * 4];
|
||||
_nextFrameBuffer = new uint8_t[screenwidth*screenheight * 4];
|
||||
memset(_videoRAM, 0x00, screenwidth*screenheight*4);
|
||||
memset(_nextFrameBuffer, 0x00, screenwidth*screenheight*4);
|
||||
|
||||
D3D11_SUBRESOURCE_DATA tbsd;
|
||||
tbsd.pSysMem = (void *)_videoRAM;
|
||||
|
@ -194,12 +198,9 @@ namespace NES
|
|||
dd.RowPitch = screenwidth * 4;
|
||||
dd.DepthPitch = screenwidth* screenheight * 4;
|
||||
|
||||
uint8_t *frameData = PPU::GetFrame();
|
||||
_pImmediateContext->Map(_pTexture, 0, D3D11_MAP_WRITE_DISCARD, 0, &dd);
|
||||
memcpy(dd.pData, frameData, screenwidth*screenheight * 4);
|
||||
memcpy(dd.pData, _nextFrameBuffer, screenwidth*screenheight * 4);
|
||||
_pImmediateContext->Unmap(_pTexture, 0);
|
||||
delete[] frameData;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
|
||||
|
@ -232,6 +233,8 @@ namespace NES
|
|||
_sprites->Draw(pSRView, x);
|
||||
_sprites->End();
|
||||
|
||||
pSRView->Release();
|
||||
|
||||
// Present the information rendered to the back buffer to the front buffer (the screen)
|
||||
_pSwapChain->Present(0, 0);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "stdafx.h"
|
||||
#include "DirectXTK\SpriteBatch.h"
|
||||
#include "../Core/IVideoDevice.h"
|
||||
|
||||
using namespace DirectX;
|
||||
|
||||
|
@ -9,7 +10,7 @@ namespace NES {
|
|||
XMFLOAT3 Pos;
|
||||
};
|
||||
|
||||
class Renderer
|
||||
class Renderer : IVideoDevice
|
||||
{
|
||||
private:
|
||||
HINSTANCE _hInst = nullptr;
|
||||
|
@ -30,6 +31,7 @@ namespace NES {
|
|||
ID3D11Texture2D* _pTexture = nullptr;
|
||||
|
||||
byte* _videoRAM;
|
||||
uint8_t* _nextFrameBuffer;
|
||||
|
||||
std::unique_ptr<SpriteBatch> _sprites;
|
||||
|
||||
|
@ -39,5 +41,10 @@ namespace NES {
|
|||
public:
|
||||
bool Initialize(HINSTANCE hInst, HWND hWnd);
|
||||
void Render();
|
||||
|
||||
void UpdateFrame(uint8_t* frameBuffer)
|
||||
{
|
||||
memcpy(_nextFrameBuffer, frameBuffer, 256 * 240 * 4);
|
||||
}
|
||||
};
|
||||
}
|
3
NES.sln
3
NES.sln
|
@ -28,4 +28,7 @@ Global
|
|||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(Performance) = preSolution
|
||||
HasPerformanceSessions = true
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
|
Loading…
Add table
Reference in a new issue