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; uInt32 scanx, scany, scanoffset;
bool visible = instance().console().tia().electronBeamPos(scanx, scany); bool visible = instance().console().tia().electronBeamPos(scanx, scany);
scanoffset = width * scany + scanx; scanoffset = width * scany + scanx;
uInt8* tiaOutputBuffer = instance().console().tia().outputBuffer();
TIASurface& tiaSurface(instance().frameBuffer().tiaSurface());
for(uInt32 y = 0, i = 0; y < height; ++y) 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) for(uInt32 x = 0; x < width; ++x, ++i)
{ {
uInt8 shift = i >= scanoffset ? 1 : 0; 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;
*line_ptr++ = pixel; *line_ptr++ = pixel;
} }

View File

@ -43,7 +43,7 @@ class DispatchResult
void setOk(uInt32 cycles); 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); void setFatal(uInt32 cycles);

View File

@ -678,8 +678,8 @@ void OSystem::mainLoop()
timesliceSeconds = dispatchEmulation(myConsole ? myConsole->emulationTiming().cyclesPerSecond() : 1); timesliceSeconds = dispatchEmulation(myConsole ? myConsole->emulationTiming().cyclesPerSecond() : 1);
if (myConsole && myConsole->tia().newFramePending()) { if (myConsole && myConsole->tia().newFramePending()) {
myConsole->tia().renderToFrameBuffer();
myFrameBuffer->updateInEmulationMode(); myFrameBuffer->updateInEmulationMode();
myConsole->tia().clearNewFramePending();
} }
} else { } else {
timesliceSeconds = 1. / 30.; 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) void TIASurface::setNTSC(NTSCFilter::Preset preset, bool show)
{ {

View File

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

View File

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

View File

@ -210,9 +210,15 @@ class TIA : public Device
bool newFramePending() { return myNewFramePending; } bool newFramePending() { return myNewFramePending; }
/** /**
Clear the flag Render the pending frame to the framebuffer and clear the flag.
*/ */
void clearNewFramePending() { myNewFramePending = false; } 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. 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 // The frame is rendered to the backbuffer and only copied to the framebuffer
// upon completion // upon completion
uInt8 myBackBuffer[160 * TIAConstants::frameBufferHeight]; uInt8 myBackBuffer[160 * TIAConstants::frameBufferHeight];
uInt8 myFrontBuffer[160 * TIAConstants::frameBufferHeight];
// Did we emit a frame? // Did we emit a frame?
bool myNewFramePending; bool myNewFramePending;