Removed concept of single vs. double buffering, and simply update the frame

on every call to FrameBuffer::update().  This will the same CPU usage for TIA mode,
and a slight increase CPU usage for launcher and debugger modes.  The code to do
this was just too fragile, and not worth the extra effort.

This fixes several rendering issues, such as garbage in fullscreen mode in Linux
when using Intel GPU, triple-buffering issues in Windows, etc.


git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@3148 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
stephena 2015-03-15 17:36:46 +00:00
parent 6f194fcd76
commit 6d8b115b34
11 changed files with 24 additions and 127 deletions

View File

@ -12,7 +12,7 @@
Release History Release History
=========================================================================== ===========================================================================
4.5 to 4.6: (February xx, 2015) 4.5 to 4.6: (March xx, 2015)
* Reverted some minor C++11 features (std::regex and cbegin/cend * Reverted some minor C++11 features (std::regex and cbegin/cend
iterators) in a few places, since otherwise GCC 4.9 is required to iterators) in a few places, since otherwise GCC 4.9 is required to
@ -20,6 +20,12 @@
changes allow Stella to be built with GCC 4.8, which is present in changes allow Stella to be built with GCC 4.8, which is present in
the latest 'long term release' of Ubuntu. the latest 'long term release' of Ubuntu.
* Finally fixed fullscreen rendering issues on some OpenGL
implementations in Linux (mostly Intel-specific). Basically, the
concept of 'dirty updates' as been removed; the window is now
updated continuously. This may also fix issues some people were
having with triple-buffering, etc.
* Fixed error messages on state loading; sometimes multiple messages * Fixed error messages on state loading; sometimes multiple messages
were being added together and displayed. were being added together and displayed.

View File

@ -90,11 +90,6 @@ class FrameBufferSDL2 : public FrameBuffer
inline Uint32 mapRGB(Uint8 r, Uint8 g, Uint8 b) const inline Uint32 mapRGB(Uint8 r, Uint8 g, Uint8 b) const
{ return SDL_MapRGB(myPixelFormat, r, g, b); } { return SDL_MapRGB(myPixelFormat, r, g, b); }
/**
This method is called to query the buffering type of the FrameBuffer.
*/
bool isDoubleBuffered() const { return myDblBufferedFlag; }
/** /**
This method is called to get a copy of the specified ARGB data from the This method is called to get a copy of the specified ARGB data from the
viewable FrameBuffer area. Note that this isn't the same as any viewable FrameBuffer area. Note that this isn't the same as any

View File

@ -491,7 +491,6 @@ void Console::changeYStart(int direction)
myTIA->setYStart(ystart); myTIA->setYStart(ystart);
myTIA->frameReset(); myTIA->frameReset();
myOSystem.frameBuffer().refresh();
ostringstream val; ostringstream val;
val << ystart; val << ystart;

View File

@ -812,10 +812,10 @@ void EventHandler::handleSystemEvent(SystemEvent e, int, int)
{ {
switch(e) switch(e)
{ {
#if 0
case EVENT_WINDOW_EXPOSED: case EVENT_WINDOW_EXPOSED:
myOSystem.frameBuffer().refresh(); myOSystem.frameBuffer().refresh();
break; break;
#if 0
case EVENT_WINDOW_MINIMIZED: case EVENT_WINDOW_MINIMIZED:
if(myState == S_EMULATE) enterMenuMode(S_MENU); if(myState == S_EMULATE) enterMenuMode(S_MENU);
break; break;

View File

@ -255,6 +255,8 @@ 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
invalidate();
switch(myOSystem.eventHandler().state()) switch(myOSystem.eventHandler().state())
{ {
case EventHandler::S_EMULATE: case EventHandler::S_EMULATE:
@ -294,6 +296,8 @@ void FrameBuffer::update()
case EventHandler::S_PAUSE: case EventHandler::S_PAUSE:
{ {
drawTIA();
// Show a pause message every 5 seconds // Show a pause message every 5 seconds
if(myPausedCount++ >= 7*myOSystem.frameRate()) if(myPausedCount++ >= 7*myOSystem.frameRate())
{ {
@ -305,26 +309,28 @@ void FrameBuffer::update()
case EventHandler::S_MENU: case EventHandler::S_MENU:
{ {
myOSystem.menu().draw(); drawTIA();
myOSystem.menu().draw(true);
break; // S_MENU break; // S_MENU
} }
case EventHandler::S_CMDMENU: case EventHandler::S_CMDMENU:
{ {
myOSystem.commandMenu().draw(); drawTIA();
myOSystem.commandMenu().draw(true);
break; // S_CMDMENU break; // S_CMDMENU
} }
case EventHandler::S_LAUNCHER: case EventHandler::S_LAUNCHER:
{ {
myOSystem.launcher().draw(); myOSystem.launcher().draw(true);
break; // S_LAUNCHER break; // S_LAUNCHER
} }
#ifdef DEBUGGER_SUPPORT #ifdef DEBUGGER_SUPPORT
case EventHandler::S_DEBUGGER: case EventHandler::S_DEBUGGER:
{ {
myOSystem.debugger().draw(); myOSystem.debugger().draw(true);
break; // S_DEBUGGER break; // S_DEBUGGER
} }
#endif #endif
@ -349,10 +355,6 @@ void FrameBuffer::showMessage(const string& message, MessagePosition position,
if(!(force || myOSystem.settings().getBool("uimessages"))) if(!(force || myOSystem.settings().getBool("uimessages")))
return; return;
// Erase old messages on the screen
if(myMsg.counter > 0)
refresh();
// Precompute the message coordinates // Precompute the message coordinates
myMsg.text = message; myMsg.text = message;
myMsg.counter = uInt32(myOSystem.frameRate()) << 1; // Show message for 2 seconds myMsg.counter = uInt32(myOSystem.frameRate()) << 1; // Show message for 2 seconds
@ -377,7 +379,6 @@ void FrameBuffer::showFrameStats(bool enable)
{ {
myOSystem.settings().setValue("stats", enable); myOSystem.settings().setValue("stats", enable);
myStatsMsg.enabled = enable; myStatsMsg.enabled = enable;
refresh();
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -396,8 +397,7 @@ void FrameBuffer::enableMessages(bool enable)
// Erase old messages on the screen // Erase old messages on the screen
myMsg.enabled = false; myMsg.enabled = false;
myMsg.counter = 0; myMsg.counter = 0;
update(); // Force update immediately
refresh();
} }
} }
@ -458,20 +458,16 @@ inline void FrameBuffer::drawMessage()
myMsg.surface->box(0, 0, myMsg.w, myMsg.h, kColor, kShadowColor); myMsg.surface->box(0, 0, myMsg.w, myMsg.h, kColor, kShadowColor);
myMsg.surface->drawString(font(), myMsg.text, 4, 4, myMsg.surface->drawString(font(), myMsg.text, 4, 4,
myMsg.w, myMsg.color, kTextAlignLeft); myMsg.w, myMsg.color, kTextAlignLeft);
myMsg.counter--;
// Either erase the entire message (when time is reached), // Either erase the entire message (when time is reached),
// or show again this frame // or show again this frame
if(myMsg.counter == 0) // Force an immediate update if(myMsg.counter-- > 0)
{
myMsg.enabled = false;
refresh();
}
else
{ {
myMsg.surface->setDirty(); myMsg.surface->setDirty();
myMsg.surface->render(); myMsg.surface->render();
} }
else
myMsg.enabled = false;
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -480,81 +476,6 @@ inline void FrameBuffer::drawTIA()
myTIASurface->render(); myTIASurface->render();
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBuffer::refresh()
{
// This method partly duplicates the behaviour in ::update()
// Here, however, make sure to redraw *all* surfaces applicable to the
// current EventHandler state
// We also check for double-buffered modes, and when present
// update both buffers accordingly
//
// This method is in essence a FULL refresh, putting all rendering
// buffers in a known, fully redrawn state
switch(myOSystem.eventHandler().state())
{
case EventHandler::S_EMULATE:
case EventHandler::S_PAUSE:
invalidate();
drawTIA();
break;
case EventHandler::S_MENU:
invalidate();
drawTIA();
myOSystem.menu().draw(true);
if(isDoubleBuffered())
{
postFrameUpdate();
invalidate();
drawTIA();
myOSystem.menu().draw(true);
}
break;
case EventHandler::S_CMDMENU:
invalidate();
drawTIA();
myOSystem.commandMenu().draw(true);
if(isDoubleBuffered())
{
postFrameUpdate();
invalidate();
drawTIA();
myOSystem.commandMenu().draw(true);
}
break;
case EventHandler::S_LAUNCHER:
invalidate();
myOSystem.launcher().draw(true);
if(isDoubleBuffered())
{
postFrameUpdate();
invalidate();
myOSystem.launcher().draw(true);
}
break;
#ifdef DEBUGGER_SUPPORT
case EventHandler::S_DEBUGGER:
invalidate();
myOSystem.debugger().draw(true);
if(isDoubleBuffered())
{
postFrameUpdate();
invalidate();
myOSystem.debugger().draw(true);
}
break;
#endif
default:
break;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
shared_ptr<FBSurface> FrameBuffer::allocateSurface(int w, int h, const uInt32* data) shared_ptr<FBSurface> FrameBuffer::allocateSurface(int w, int h, const uInt32* data)
{ {
@ -623,7 +544,6 @@ void FrameBuffer::setFullscreen(bool enable)
myOSystem.settings().setValue("fullscreen", fullScreen()); myOSystem.settings().setValue("fullscreen", fullScreen());
resetSurfaces(); resetSurfaces();
setCursorState(); setCursorState();
refresh();
} }
} }
@ -664,7 +584,6 @@ bool FrameBuffer::changeWindowedVidMode(int direction)
resetSurfaces(); resetSurfaces();
showMessage(mode.description); showMessage(mode.description);
myOSystem.settings().setValue("tia.zoom", mode.zoom); myOSystem.settings().setValue("tia.zoom", mode.zoom);
refresh();
return true; return true;
} }
#endif #endif

View File

@ -252,12 +252,6 @@ class FrameBuffer
*/ */
TIASurface& tiaSurface() const { return *myTIASurface; } TIASurface& tiaSurface() const { return *myTIASurface; }
/**
Refresh display according to the current state, taking single vs.
double-buffered modes into account, and redrawing accordingly.
*/
void refresh();
/** /**
Enables/disables fullscreen mode. Enables/disables fullscreen mode.
*/ */
@ -336,11 +330,6 @@ class FrameBuffer
*/ */
virtual Uint32 mapRGB(Uint8 r, Uint8 g, Uint8 b) const = 0; virtual Uint32 mapRGB(Uint8 r, Uint8 g, Uint8 b) const = 0;
/**
This method is called to query the buffering type of the FrameBuffer.
*/
virtual bool isDoubleBuffered() const = 0;
/** /**
This method is called to get the specified ARGB data from the viewable This method is called to get the specified ARGB data from the viewable
FrameBuffer area. Note that this isn't the same as any internal FrameBuffer area. Note that this isn't the same as any internal

View File

@ -418,7 +418,6 @@ bool OSystem::createLauncher(const string& startdir)
{ {
myLauncher->reStack(); myLauncher->reStack();
myFrameBuffer->setCursorState(); myFrameBuffer->setCursorState();
myFrameBuffer->refresh();
setFramerate(60); setFramerate(60);
resetLoopTiming(); resetLoopTiming();

View File

@ -162,7 +162,6 @@ void CommandDialog::handleCommand(CommandSender* sender, int cmd,
case kSnapshotCmd: case kSnapshotCmd:
instance().eventHandler().leaveMenuMode(); instance().eventHandler().leaveMenuMode();
instance().frameBuffer().refresh();
instance().eventHandler().handleEvent(Event::TakeSnapshot, 1); instance().eventHandler().handleEvent(Event::TakeSnapshot, 1);
break; break;
@ -195,10 +194,7 @@ void CommandDialog::handleCommand(CommandSender* sender, int cmd,
instance().console().switches().update(); instance().console().switches().update();
instance().console().tia().update(); instance().console().tia().update();
instance().eventHandler().handleEvent(event, 0); instance().eventHandler().handleEvent(event, 0);
instance().frameBuffer().refresh();
} }
else if(stateCmd) else if(stateCmd)
{
instance().eventHandler().handleEvent(event, 1); instance().eventHandler().handleEvent(event, 1);
}
} }

View File

@ -82,9 +82,6 @@ void Dialog::open(bool refresh)
buildCurrentFocusList(); buildCurrentFocusList();
_visible = true; _visible = true;
if(refresh)
instance().frameBuffer().refresh();
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -101,9 +98,6 @@ void Dialog::close(bool refresh)
_visible = false; _visible = false;
parent().removeDialog(); parent().removeDialog();
if(refresh)
instance().frameBuffer().refresh();
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -131,8 +131,6 @@ void DialogContainer::reStack()
myBaseDialog->open(false); // don't force a refresh myBaseDialog->open(false); // don't force a refresh
myOSystem.frameBuffer().refresh();
// Reset all continuous events // Reset all continuous events
reset(); reset();
} }

View File

@ -20,6 +20,8 @@
#ifndef EDITABLE_WIDGET_HXX #ifndef EDITABLE_WIDGET_HXX
#define EDITABLE_WIDGET_HXX #define EDITABLE_WIDGET_HXX
#include <functional>
#include "Widget.hxx" #include "Widget.hxx"
#include "Rect.hxx" #include "Rect.hxx"