Optimizations (+25% speed), changed the way frame buffer is sent to the GUI

This commit is contained in:
Souryo 2014-06-19 17:06:00 -04:00
parent e4692cdd9c
commit 0bac761beb
8 changed files with 59 additions and 70 deletions

View file

@ -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" />

View file

@ -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
View file

@ -0,0 +1,9 @@
#pragma once
#include "stdafx.h"
class IVideoDevice
{
public:
virtual void UpdateFrame(uint8_t *outputBuffer) = 0;
};

View file

@ -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--;
}
}

View file

@ -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()
{

View file

@ -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);
}

View file

@ -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);
}
};
}

View file

@ -28,4 +28,7 @@ Global
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(Performance) = preSolution
HasPerformanceSessions = true
EndGlobalSection
EndGlobal