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
===========================================================================
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
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
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
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
{ 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
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->frameReset();
myOSystem.frameBuffer().refresh();
ostringstream val;
val << ystart;

View File

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

View File

@ -255,6 +255,8 @@ 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
invalidate();
switch(myOSystem.eventHandler().state())
{
case EventHandler::S_EMULATE:
@ -294,6 +296,8 @@ void FrameBuffer::update()
case EventHandler::S_PAUSE:
{
drawTIA();
// Show a pause message every 5 seconds
if(myPausedCount++ >= 7*myOSystem.frameRate())
{
@ -305,26 +309,28 @@ void FrameBuffer::update()
case EventHandler::S_MENU:
{
myOSystem.menu().draw();
drawTIA();
myOSystem.menu().draw(true);
break; // S_MENU
}
case EventHandler::S_CMDMENU:
{
myOSystem.commandMenu().draw();
drawTIA();
myOSystem.commandMenu().draw(true);
break; // S_CMDMENU
}
case EventHandler::S_LAUNCHER:
{
myOSystem.launcher().draw();
myOSystem.launcher().draw(true);
break; // S_LAUNCHER
}
#ifdef DEBUGGER_SUPPORT
case EventHandler::S_DEBUGGER:
{
myOSystem.debugger().draw();
myOSystem.debugger().draw(true);
break; // S_DEBUGGER
}
#endif
@ -349,10 +355,6 @@ void FrameBuffer::showMessage(const string& message, MessagePosition position,
if(!(force || myOSystem.settings().getBool("uimessages")))
return;
// Erase old messages on the screen
if(myMsg.counter > 0)
refresh();
// Precompute the message coordinates
myMsg.text = message;
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);
myStatsMsg.enabled = enable;
refresh();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -396,8 +397,7 @@ void FrameBuffer::enableMessages(bool enable)
// Erase old messages on the screen
myMsg.enabled = false;
myMsg.counter = 0;
refresh();
update(); // Force update immediately
}
}
@ -458,20 +458,16 @@ inline void FrameBuffer::drawMessage()
myMsg.surface->box(0, 0, myMsg.w, myMsg.h, kColor, kShadowColor);
myMsg.surface->drawString(font(), myMsg.text, 4, 4,
myMsg.w, myMsg.color, kTextAlignLeft);
myMsg.counter--;
// Either erase the entire message (when time is reached),
// or show again this frame
if(myMsg.counter == 0) // Force an immediate update
{
myMsg.enabled = false;
refresh();
}
else
if(myMsg.counter-- > 0)
{
myMsg.surface->setDirty();
myMsg.surface->render();
}
else
myMsg.enabled = false;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -480,81 +476,6 @@ inline void FrameBuffer::drawTIA()
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)
{
@ -623,7 +544,6 @@ void FrameBuffer::setFullscreen(bool enable)
myOSystem.settings().setValue("fullscreen", fullScreen());
resetSurfaces();
setCursorState();
refresh();
}
}
@ -664,7 +584,6 @@ bool FrameBuffer::changeWindowedVidMode(int direction)
resetSurfaces();
showMessage(mode.description);
myOSystem.settings().setValue("tia.zoom", mode.zoom);
refresh();
return true;
}
#endif

View File

@ -252,12 +252,6 @@ class FrameBuffer
*/
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.
*/
@ -336,11 +330,6 @@ class FrameBuffer
*/
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
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();
myFrameBuffer->setCursorState();
myFrameBuffer->refresh();
setFramerate(60);
resetLoopTiming();

View File

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

View File

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

View File

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

View File

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