Implement triple buffering in TIA.

This commit is contained in:
Christian Speckner 2018-05-27 00:26:07 +02:00
parent f7a9a12c23
commit a5ce457b72
7 changed files with 33 additions and 15 deletions

View File

@ -168,6 +168,8 @@ void TiaOutputWidget::drawWidget(bool hilite)
uInt32 scanx, scany, scanoffset;
bool visible = instance().console().tia().electronBeamPos(scanx, scany);
scanoffset = width * scany + scanx;
uInt8* tiaOutputBuffer = instance().console().tia().outputBuffer();
TIASurface& tiaSurface(instance().frameBuffer().tiaSurface());
for(uInt32 y = 0, i = 0; y < height; ++y)
{
@ -175,7 +177,7 @@ void TiaOutputWidget::drawWidget(bool hilite)
for(uInt32 x = 0; x < width; ++x, ++i)
{
uInt8 shift = i >= scanoffset ? 1 : 0;
uInt32 pixel = instance().frameBuffer().tiaSurface().pixel(i, shift);
uInt32 pixel = tiaSurface.mapIndexedPixel(tiaOutputBuffer[i], shift);
*line_ptr++ = pixel;
*line_ptr++ = pixel;
}

View File

@ -43,7 +43,7 @@ class DispatchResult
void setOk(uInt32 cycles);
void setDebugger(uInt32 cycles, const string& message = "", int address = -1, bool wasReadTrap = -1);
void setDebugger(uInt32 cycles, const string& message = "", int address = -1, bool wasReadTrap = false);
void setFatal(uInt32 cycles);

View File

@ -678,8 +678,8 @@ void OSystem::mainLoop()
timesliceSeconds = dispatchEmulation(myConsole ? myConsole->emulationTiming().cyclesPerSecond() : 1);
if (myConsole && myConsole->tia().newFramePending()) {
myConsole->tia().renderToFrameBuffer();
myFrameBuffer->updateInEmulationMode();
myConsole->tia().clearNewFramePending();
}
} else {
timesliceSeconds = 1. / 30.;

View File

@ -138,11 +138,12 @@ const FBSurface& TIASurface::baseSurface(GUI::Rect& rect) const
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt32 TIASurface::pixel(uInt32 idx, uInt8 shift)
uInt32 TIASurface::mapIndexedPixel(uInt8 indexedColor, uInt8 shift)
{
return myPalette[*(myTIA->frameBuffer() + idx) | shift];
return myPalette[indexedColor | shift];
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void TIASurface::setNTSC(NTSCFilter::Preset preset, bool show)
{

View File

@ -73,10 +73,9 @@ class TIASurface
const FBSurface& baseSurface(GUI::Rect& rect) const;
/**
Get the TIA pixel associated with the given TIA buffer index,
shifting by the given offset (for greyscale values).
*/
uInt32 pixel(uInt32 idx, uInt8 shift = 0);
Use the palette to map a single indexed pixel color. This is used by the TIA output widget.
*/
uInt32 mapIndexedPixel(uInt8 indexedColor, uInt8 shift = 0);
/**
Get the NTSCFilter object associated with the framebuffer

View File

@ -196,6 +196,7 @@ void TIA::reset()
void TIA::frameReset()
{
memset(myBackBuffer, 0, 160 * TIAConstants::frameBufferHeight);
memset(myFrontBuffer, 0, 160 * TIAConstants::frameBufferHeight);
memset(myFramebuffer, 0, 160 * TIAConstants::frameBufferHeight);
enableColorLoss(mySettings.getBool("dev.settings") ? "dev.colorloss" : "plr.colorloss");
}
@ -784,6 +785,7 @@ bool TIA::saveDisplay(Serializer& out) const
{
out.putByteArray(myFramebuffer, 160* TIAConstants::frameBufferHeight);
out.putByteArray(myBackBuffer, 160 * TIAConstants::frameBufferHeight);
out.putByteArray(myFrontBuffer, 160 * TIAConstants::frameBufferHeight);
out.putBool(myNewFramePending);
}
catch(...)
@ -803,6 +805,7 @@ bool TIA::loadDisplay(Serializer& in)
// Reset frame buffer pointer and data
in.getByteArray(myFramebuffer, 160*TIAConstants::frameBufferHeight);
in.getByteArray(myBackBuffer, 160 * TIAConstants::frameBufferHeight);
in.getByteArray(myFrontBuffer, 160 * TIAConstants::frameBufferHeight);
myNewFramePending = in.getBool();
}
catch(...)
@ -817,13 +820,19 @@ bool TIA::loadDisplay(Serializer& in)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void TIA::update(DispatchResult& result, uInt32 maxCycles)
{
uInt64 timestampOld = myTimestamp;
mySystem->m6502().execute(maxCycles, result);
updateEmulation();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void TIA::renderToFrameBuffer()
{
if (!myNewFramePending) return;
memcpy(myFramebuffer, myFrontBuffer, 160 * TIAConstants::frameBufferHeight);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void TIA::update(uInt32 maxCycles)
{
@ -1171,7 +1180,7 @@ void TIA::onFrameComplete()
if (missingScanlines > 0)
memset(myBackBuffer + 160 * myFrameManager->getY(), 0, missingScanlines * 160);
memcpy(&myFramebuffer, &myBackBuffer, 160 * TIAConstants::frameBufferHeight);
memcpy(myFrontBuffer, myBackBuffer, 160 * TIAConstants::frameBufferHeight);
myNewFramePending = true;
}

View File

@ -210,9 +210,15 @@ class TIA : public Device
bool newFramePending() { return myNewFramePending; }
/**
Clear the flag
*/
void clearNewFramePending() { myNewFramePending = false; }
Render the pending frame to the framebuffer and clear the flag.
*/
void renderToFrameBuffer();
/**
Return the buffer that holds the currently drawing TIA frame
(the TIA output widget needs this).
*/
uInt8* outputBuffer() { return myBackBuffer; }
/**
Returns a pointer to the internal frame buffer.
@ -673,6 +679,7 @@ class TIA : public Device
// The frame is rendered to the backbuffer and only copied to the framebuffer
// upon completion
uInt8 myBackBuffer[160 * TIAConstants::frameBufferHeight];
uInt8 myFrontBuffer[160 * TIAConstants::frameBufferHeight];
// Did we emit a frame?
bool myNewFramePending;