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)
|
// Determine which mode we are in (from the EventHandler)
|
||||||
// Take care of S_EMULATE mode here, otherwise let the GUI
|
// Take care of S_EMULATE mode here, otherwise let the GUI
|
||||||
// figure out what to draw
|
// figure out what to draw
|
||||||
|
|
||||||
Int64 cycles = -1;
|
|
||||||
|
|
||||||
invalidate();
|
invalidate();
|
||||||
switch(myOSystem.eventHandler().state())
|
switch(myOSystem.eventHandler().state())
|
||||||
{
|
{
|
||||||
case EventHandlerState::EMULATION:
|
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();
|
myTIASurface->render();
|
||||||
|
|
||||||
// Show frame statistics
|
// Show frame statistics
|
||||||
|
@ -342,7 +329,7 @@ Int64 FrameBuffer::update(uInt32 maxCycles)
|
||||||
}
|
}
|
||||||
|
|
||||||
case EventHandlerState::NONE:
|
case EventHandlerState::NONE:
|
||||||
return -1;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw any pending messages
|
// Draw any pending messages
|
||||||
|
@ -351,8 +338,6 @@ Int64 FrameBuffer::update(uInt32 maxCycles)
|
||||||
|
|
||||||
// Do any post-frame stuff
|
// Do any post-frame stuff
|
||||||
postFrameUpdate();
|
postFrameUpdate();
|
||||||
|
|
||||||
return cycles;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
|
@ -116,7 +116,7 @@ class FrameBuffer
|
||||||
drawing the TIA, any pending menus, etc. Returns the numbers of CPU cycles
|
drawing the TIA, any pending menus, etc. Returns the numbers of CPU cycles
|
||||||
spent during emulation, or -1 if not applicable.
|
spent during emulation, or -1 if not applicable.
|
||||||
*/
|
*/
|
||||||
Int64 update(uInt32 maxCycles = 50000);
|
void update();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Shows a message onscreen.
|
Shows a message onscreen.
|
||||||
|
|
|
@ -52,6 +52,7 @@
|
||||||
#include "SerialPort.hxx"
|
#include "SerialPort.hxx"
|
||||||
#include "StateManager.hxx"
|
#include "StateManager.hxx"
|
||||||
#include "Version.hxx"
|
#include "Version.hxx"
|
||||||
|
#include "TIA.hxx"
|
||||||
|
|
||||||
#include "OSystem.hxx"
|
#include "OSystem.hxx"
|
||||||
|
|
||||||
|
@ -646,23 +647,38 @@ void OSystem::mainLoop()
|
||||||
myEventHandler->poll(getTicks());
|
myEventHandler->poll(getTicks());
|
||||||
if(myQuitLoop) break; // Exit if the user wants to quit
|
if(myQuitLoop) break; // Exit if the user wants to quit
|
||||||
|
|
||||||
Int64 totalCycles = 0;
|
double timesliceSeconds;
|
||||||
const Int64 minCycles = myConsole ? myConsole->emulationTiming().minCyclesPerTimeslice() : 50000;
|
|
||||||
const Int64 maxCycles = myConsole ? myConsole->emulationTiming().maxCyclesPerTimeslice() : 0;
|
|
||||||
const uInt32 cyclesPerSecond = myConsole ? myConsole->emulationTiming().cyclesPerSecond() : 1;
|
|
||||||
|
|
||||||
do {
|
if (myEventHandler->state() == EventHandlerState::EMULATION) {
|
||||||
Int64 cycles = myFrameBuffer->update(totalCycles > 0 ? minCycles - totalCycles : maxCycles);
|
Int64 totalCycles = 0;
|
||||||
if (cycles < 0) break;
|
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;
|
do {
|
||||||
} while (totalCycles < minCycles);
|
Int64 cycles = myConsole ? myConsole->tia().update(totalCycles > 0 ? minCycles - totalCycles : maxCycles) : 0;
|
||||||
|
|
||||||
duration<double> timeslice (
|
totalCycles += cycles;
|
||||||
(totalCycles > 0) ?
|
} while (myConsole && totalCycles < minCycles && myEventHandler->state() == EventHandlerState::EMULATION);
|
||||||
static_cast<double>(totalCycles) / static_cast<double>(cyclesPerSecond) :
|
|
||||||
1. / 30.
|
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);
|
virtualTime += duration_cast<high_resolution_clock::duration>(timeslice);
|
||||||
time_point<high_resolution_clock> now = high_resolution_clock::now();
|
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)
|
if (duration_cast<duration<double>>(now - virtualTime).count() > 0)
|
||||||
virtualTime = now;
|
virtualTime = now;
|
||||||
else if (virtualTime > now) {
|
else if (virtualTime > now) {
|
||||||
if (busyWait && totalCycles > 0) {
|
if (busyWait && myEventHandler->state() == EventHandlerState::EMULATION) {
|
||||||
while (high_resolution_clock::now() < virtualTime);
|
while (high_resolution_clock::now() < virtualTime);
|
||||||
}
|
}
|
||||||
else std::this_thread::sleep_until(virtualTime);
|
else std::this_thread::sleep_until(virtualTime);
|
||||||
|
|
|
@ -180,6 +180,8 @@ void TIA::reset()
|
||||||
frameReset(); // Recalculate the size of the display
|
frameReset(); // Recalculate the size of the display
|
||||||
}
|
}
|
||||||
|
|
||||||
|
myNewFramePending = false;
|
||||||
|
|
||||||
// Must be done last, after all other items have reset
|
// Must be done last, after all other items have reset
|
||||||
enableFixedColors(mySettings.getBool(mySettings.getBool("dev.settings") ? "dev.debugcolors" : "plr.debugcolors"));
|
enableFixedColors(mySettings.getBool(mySettings.getBool("dev.settings") ? "dev.debugcolors" : "plr.debugcolors"));
|
||||||
setFixedColorPalette(mySettings.getString("tia.dbgcolors"));
|
setFixedColorPalette(mySettings.getString("tia.dbgcolors"));
|
||||||
|
@ -192,6 +194,7 @@ void TIA::reset()
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void TIA::frameReset()
|
void TIA::frameReset()
|
||||||
{
|
{
|
||||||
|
memset(myBackBuffer, 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");
|
||||||
}
|
}
|
||||||
|
@ -778,7 +781,9 @@ bool TIA::saveDisplay(Serializer& out) const
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
out.putByteArray(myFramebuffer, 160*TIAConstants::frameBufferHeight);
|
out.putByteArray(myFramebuffer, 160* TIAConstants::frameBufferHeight);
|
||||||
|
out.putByteArray(myBackBuffer, 160 * TIAConstants::frameBufferHeight);
|
||||||
|
out.putBool(myNewFramePending);
|
||||||
}
|
}
|
||||||
catch(...)
|
catch(...)
|
||||||
{
|
{
|
||||||
|
@ -796,6 +801,8 @@ 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);
|
||||||
|
myNewFramePending = in.getBool();
|
||||||
}
|
}
|
||||||
catch(...)
|
catch(...)
|
||||||
{
|
{
|
||||||
|
@ -1149,12 +1156,15 @@ void TIA::onFrameComplete()
|
||||||
myCyclesAtFrameStart = mySystem->cycles();
|
myCyclesAtFrameStart = mySystem->cycles();
|
||||||
|
|
||||||
if (myXAtRenderingStart > 0)
|
if (myXAtRenderingStart > 0)
|
||||||
memset(myFramebuffer, 0, myXAtRenderingStart);
|
memset(myBackBuffer, 0, myXAtRenderingStart);
|
||||||
|
|
||||||
// Blank out any extra lines not drawn this frame
|
// Blank out any extra lines not drawn this frame
|
||||||
const Int32 missingScanlines = myFrameManager->missingScanlines();
|
const Int32 missingScanlines = myFrameManager->missingScanlines();
|
||||||
if (missingScanlines > 0)
|
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;
|
myHctrDelta = 225 - myHctr;
|
||||||
if (myFrameManager->isRendering())
|
if (myFrameManager->isRendering())
|
||||||
memset(myFramebuffer + myFrameManager->getY() * 160 + x, 0, 160 - x);
|
memset(myBackBuffer + myFrameManager->getY() * 160 + x, 0, 160 - x);
|
||||||
|
|
||||||
myHctr = 225;
|
myHctr = 225;
|
||||||
}
|
}
|
||||||
|
@ -1304,7 +1314,7 @@ void TIA::cloneLastLine()
|
||||||
|
|
||||||
if (!myFrameManager->isRendering() || y == 0) return;
|
if (!myFrameManager->isRendering() || y == 0) return;
|
||||||
|
|
||||||
uInt8* buffer = myFramebuffer;
|
uInt8* buffer = myBackBuffer;
|
||||||
|
|
||||||
memcpy(buffer + y * 160, buffer + (y-1) * 160, 160);
|
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()
|
void TIA::clearHmoveComb()
|
||||||
{
|
{
|
||||||
if (myFrameManager->isRendering() && myHstate == HState::blank)
|
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);
|
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.
|
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
|
// Pointer to the internal color-index-based frame buffer
|
||||||
uInt8 myFramebuffer[160 * TIAConstants::frameBufferHeight];
|
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.
|
* Setting this to true injects random values into undefined reads.
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in New Issue