mirror of https://github.com/stella-emu/stella.git
Implement triple buffering in TIA.
This commit is contained in:
parent
f7a9a12c23
commit
a5ce457b72
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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.;
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue