mirror of https://github.com/stella-emu/stella.git
Rerender only if there is actual change.
This commit is contained in:
parent
639b6af1e9
commit
ed6eae6a67
|
@ -258,30 +258,17 @@ FBInitStatus FrameBuffer::createDisplay(const string& title,
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Int64 FrameBuffer::update(uInt32 maxCycles)
|
||||
void FrameBuffer::update()
|
||||
{
|
||||
// Determine which mode we are in (from the EventHandler)
|
||||
// Take care of S_EMULATE mode here, otherwise let the GUI
|
||||
// figure out what to draw
|
||||
|
||||
Int64 cycles = -1;
|
||||
|
||||
invalidate();
|
||||
switch(myOSystem.eventHandler().state())
|
||||
{
|
||||
case EventHandlerState::EMULATION:
|
||||
{
|
||||
// Run the console for one frame
|
||||
// Note that the debugger can cause a breakpoint to occur, which changes
|
||||
// the EventHandler state 'behind our back' - we need to check for that
|
||||
cycles = myOSystem.console().tia().update(maxCycles);
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
if(myOSystem.eventHandler().state() != EventHandlerState::EMULATION) break;
|
||||
#endif
|
||||
if(myOSystem.eventHandler().frying())
|
||||
myOSystem.console().fry();
|
||||
|
||||
// And update the screen
|
||||
myTIASurface->render();
|
||||
|
||||
// Show frame statistics
|
||||
|
@ -342,7 +329,7 @@ Int64 FrameBuffer::update(uInt32 maxCycles)
|
|||
}
|
||||
|
||||
case EventHandlerState::NONE:
|
||||
return -1;
|
||||
return;
|
||||
}
|
||||
|
||||
// Draw any pending messages
|
||||
|
@ -351,8 +338,6 @@ Int64 FrameBuffer::update(uInt32 maxCycles)
|
|||
|
||||
// Do any post-frame stuff
|
||||
postFrameUpdate();
|
||||
|
||||
return cycles;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -116,7 +116,7 @@ class FrameBuffer
|
|||
drawing the TIA, any pending menus, etc. Returns the numbers of CPU cycles
|
||||
spent during emulation, or -1 if not applicable.
|
||||
*/
|
||||
Int64 update(uInt32 maxCycles = 50000);
|
||||
void update();
|
||||
|
||||
/**
|
||||
Shows a message onscreen.
|
||||
|
|
|
@ -52,6 +52,7 @@
|
|||
#include "SerialPort.hxx"
|
||||
#include "StateManager.hxx"
|
||||
#include "Version.hxx"
|
||||
#include "TIA.hxx"
|
||||
|
||||
#include "OSystem.hxx"
|
||||
|
||||
|
@ -646,23 +647,38 @@ void OSystem::mainLoop()
|
|||
myEventHandler->poll(getTicks());
|
||||
if(myQuitLoop) break; // Exit if the user wants to quit
|
||||
|
||||
Int64 totalCycles = 0;
|
||||
const Int64 minCycles = myConsole ? myConsole->emulationTiming().minCyclesPerTimeslice() : 50000;
|
||||
const Int64 maxCycles = myConsole ? myConsole->emulationTiming().maxCyclesPerTimeslice() : 0;
|
||||
const uInt32 cyclesPerSecond = myConsole ? myConsole->emulationTiming().cyclesPerSecond() : 1;
|
||||
double timesliceSeconds;
|
||||
|
||||
do {
|
||||
Int64 cycles = myFrameBuffer->update(totalCycles > 0 ? minCycles - totalCycles : maxCycles);
|
||||
if (cycles < 0) break;
|
||||
if (myEventHandler->state() == EventHandlerState::EMULATION) {
|
||||
Int64 totalCycles = 0;
|
||||
const Int64 minCycles = myConsole ? myConsole->emulationTiming().minCyclesPerTimeslice() : 50000;
|
||||
const Int64 maxCycles = myConsole ? myConsole->emulationTiming().maxCyclesPerTimeslice() : 0;
|
||||
const uInt32 cyclesPerSecond = myConsole ? myConsole->emulationTiming().cyclesPerSecond() : 1;
|
||||
|
||||
totalCycles += cycles;
|
||||
} while (totalCycles < minCycles);
|
||||
do {
|
||||
Int64 cycles = myConsole ? myConsole->tia().update(totalCycles > 0 ? minCycles - totalCycles : maxCycles) : 0;
|
||||
|
||||
duration<double> timeslice (
|
||||
(totalCycles > 0) ?
|
||||
static_cast<double>(totalCycles) / static_cast<double>(cyclesPerSecond) :
|
||||
1. / 30.
|
||||
);
|
||||
totalCycles += cycles;
|
||||
} while (myConsole && totalCycles < minCycles && myEventHandler->state() == EventHandlerState::EMULATION);
|
||||
|
||||
if (myEventHandler->state() == EventHandlerState::EMULATION && myEventHandler->frying())
|
||||
myConsole->fry();
|
||||
|
||||
timesliceSeconds = static_cast<double>(totalCycles) / static_cast<double>(cyclesPerSecond);
|
||||
}
|
||||
else
|
||||
timesliceSeconds = 1. / 30.;
|
||||
|
||||
if (myEventHandler->state() == EventHandlerState::EMULATION) {
|
||||
if (myConsole && myConsole->tia().newFramePending()) {
|
||||
myFrameBuffer->update();
|
||||
myConsole->tia().clearNewFramePending();
|
||||
}
|
||||
}
|
||||
else
|
||||
myFrameBuffer->update();
|
||||
|
||||
duration<double> timeslice(timesliceSeconds);
|
||||
|
||||
virtualTime += duration_cast<high_resolution_clock::duration>(timeslice);
|
||||
time_point<high_resolution_clock> now = high_resolution_clock::now();
|
||||
|
@ -670,7 +686,7 @@ void OSystem::mainLoop()
|
|||
if (duration_cast<duration<double>>(now - virtualTime).count() > 0)
|
||||
virtualTime = now;
|
||||
else if (virtualTime > now) {
|
||||
if (busyWait && totalCycles > 0) {
|
||||
if (busyWait && myEventHandler->state() == EventHandlerState::EMULATION) {
|
||||
while (high_resolution_clock::now() < virtualTime);
|
||||
}
|
||||
else std::this_thread::sleep_until(virtualTime);
|
||||
|
|
|
@ -180,6 +180,8 @@ void TIA::reset()
|
|||
frameReset(); // Recalculate the size of the display
|
||||
}
|
||||
|
||||
myNewFramePending = false;
|
||||
|
||||
// Must be done last, after all other items have reset
|
||||
enableFixedColors(mySettings.getBool(mySettings.getBool("dev.settings") ? "dev.debugcolors" : "plr.debugcolors"));
|
||||
setFixedColorPalette(mySettings.getString("tia.dbgcolors"));
|
||||
|
@ -192,6 +194,7 @@ void TIA::reset()
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void TIA::frameReset()
|
||||
{
|
||||
memset(myBackBuffer, 0, 160 * TIAConstants::frameBufferHeight);
|
||||
memset(myFramebuffer, 0, 160 * TIAConstants::frameBufferHeight);
|
||||
enableColorLoss(mySettings.getBool("dev.settings") ? "dev.colorloss" : "plr.colorloss");
|
||||
}
|
||||
|
@ -778,7 +781,9 @@ bool TIA::saveDisplay(Serializer& out) const
|
|||
{
|
||||
try
|
||||
{
|
||||
out.putByteArray(myFramebuffer, 160*TIAConstants::frameBufferHeight);
|
||||
out.putByteArray(myFramebuffer, 160* TIAConstants::frameBufferHeight);
|
||||
out.putByteArray(myBackBuffer, 160 * TIAConstants::frameBufferHeight);
|
||||
out.putBool(myNewFramePending);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
|
@ -796,6 +801,8 @@ bool TIA::loadDisplay(Serializer& in)
|
|||
{
|
||||
// Reset frame buffer pointer and data
|
||||
in.getByteArray(myFramebuffer, 160*TIAConstants::frameBufferHeight);
|
||||
in.getByteArray(myBackBuffer, 160 * TIAConstants::frameBufferHeight);
|
||||
myNewFramePending = in.getBool();
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
|
@ -1149,12 +1156,15 @@ void TIA::onFrameComplete()
|
|||
myCyclesAtFrameStart = mySystem->cycles();
|
||||
|
||||
if (myXAtRenderingStart > 0)
|
||||
memset(myFramebuffer, 0, myXAtRenderingStart);
|
||||
memset(myBackBuffer, 0, myXAtRenderingStart);
|
||||
|
||||
// Blank out any extra lines not drawn this frame
|
||||
const Int32 missingScanlines = myFrameManager->missingScanlines();
|
||||
if (missingScanlines > 0)
|
||||
memset(myFramebuffer + 160 * myFrameManager->getY(), 0, missingScanlines * 160);
|
||||
memset(myBackBuffer + 160 * myFrameManager->getY(), 0, missingScanlines * 160);
|
||||
|
||||
memcpy(&myFramebuffer, &myBackBuffer, 160 * TIAConstants::frameBufferHeight);
|
||||
myNewFramePending = true;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -1265,7 +1275,7 @@ void TIA::applyRsync()
|
|||
|
||||
myHctrDelta = 225 - myHctr;
|
||||
if (myFrameManager->isRendering())
|
||||
memset(myFramebuffer + myFrameManager->getY() * 160 + x, 0, 160 - x);
|
||||
memset(myBackBuffer + myFrameManager->getY() * 160 + x, 0, 160 - x);
|
||||
|
||||
myHctr = 225;
|
||||
}
|
||||
|
@ -1304,7 +1314,7 @@ void TIA::cloneLastLine()
|
|||
|
||||
if (!myFrameManager->isRendering() || y == 0) return;
|
||||
|
||||
uInt8* buffer = myFramebuffer;
|
||||
uInt8* buffer = myBackBuffer;
|
||||
|
||||
memcpy(buffer + y * 160, buffer + (y-1) * 160, 160);
|
||||
}
|
||||
|
@ -1377,7 +1387,7 @@ void TIA::renderPixel(uInt32 x, uInt32 y)
|
|||
}
|
||||
}
|
||||
|
||||
myFramebuffer[y * 160 + x] = color;
|
||||
myBackBuffer[y * 160 + x] = color;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -1403,7 +1413,7 @@ void TIA::flushLineCache()
|
|||
void TIA::clearHmoveComb()
|
||||
{
|
||||
if (myFrameManager->isRendering() && myHstate == HState::blank)
|
||||
memset(myFramebuffer + myFrameManager->getY() * 160, myColorHBlank, 8);
|
||||
memset(myBackBuffer + myFrameManager->getY() * 160, myColorHBlank, 8);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -201,6 +201,16 @@ class TIA : public Device
|
|||
*/
|
||||
uInt64 update(uInt32 maxCycles = 50000);
|
||||
|
||||
/**
|
||||
Did we generate a new frame?
|
||||
*/
|
||||
bool newFramePending() { return myNewFramePending; }
|
||||
|
||||
/**
|
||||
Clear the flag
|
||||
*/
|
||||
void clearNewFramePending() { myNewFramePending = false; }
|
||||
|
||||
/**
|
||||
Returns a pointer to the internal frame buffer.
|
||||
*/
|
||||
|
@ -657,6 +667,13 @@ class TIA : public Device
|
|||
// Pointer to the internal color-index-based frame buffer
|
||||
uInt8 myFramebuffer[160 * TIAConstants::frameBufferHeight];
|
||||
|
||||
// The frame is rendered to the backbuffer and only copied to the framebuffer
|
||||
// upon completion
|
||||
uInt8 myBackBuffer[160 * TIAConstants::frameBufferHeight];
|
||||
|
||||
// Did we emit a frame?
|
||||
bool myNewFramePending;
|
||||
|
||||
/**
|
||||
* Setting this to true injects random values into undefined reads.
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue