Minor refactoring of the FrameBuffer classes. OpenGL mode is now

quite fast, and is approaching software rendering speed for lower
resolutions.  In higher resolutions, OpenGL always beats software
mode.

Screen redraws are now done as rarely as possible.  For example,
when switching to menu/debugger mode or pausing emulation, CPU
usage normally drops to almost nothing.

This hasn't been tested in Windows yet, so I'm sure there'll be
some issues (there always are ...)


git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@682 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
stephena 2005-07-20 15:52:58 +00:00
parent 1694cff72d
commit d15978825a
5 changed files with 64 additions and 73 deletions

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of // See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES. // this file, and for a DISCLAIMER OF ALL WARRANTIES.
// //
// $Id: FrameBufferGL.cxx,v 1.34 2005-07-02 01:28:42 stephena Exp $ // $Id: FrameBufferGL.cxx,v 1.35 2005-07-20 15:52:57 stephena Exp $
//============================================================================ //============================================================================
#ifdef DISPLAY_OPENGL #ifdef DISPLAY_OPENGL
@ -230,17 +230,19 @@ void FrameBufferGL::drawMediaSource()
{ {
const uInt32 bufofs = bufofsY + x; const uInt32 bufofs = bufofsY + x;
uInt8 v = currentFrame[bufofs]; uInt8 v = currentFrame[bufofs];
if(v == previousFrame[bufofs] && !theRedrawTIAIndicator) if(v != previousFrame[bufofs] || theRedrawTIAIndicator)
continue; {
// If we ever get to this point, we know the current and previous
// buffers differ. In that case, make sure the changes are
// are drawn in postFrameUpdate()
theRedrawTIAIndicator = true;
// x << 1 is times 2 ( doubling width ) // x << 1 is times 2 ( doubling width )
const uInt32 pos = screenofsY + (x << 1); const uInt32 pos = screenofsY + (x << 1);
buffer[pos] = buffer[pos+1] = (uInt16) myPalette[v]; buffer[pos] = buffer[pos+1] = (uInt16) myPalette[v];
}
} }
} }
// The frame doesn't need to be completely redrawn anymore
theRedrawTIAIndicator = false;
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -251,22 +253,37 @@ void FrameBufferGL::preFrameUpdate()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBufferGL::postFrameUpdate() void FrameBufferGL::postFrameUpdate()
{ {
// Texturemap complete texture to surface so we have free scaling // Do the following twice, since OpenGL mode is double-buffered,
// and antialiasing // and we need the contents placed in both buffers
glBindTexture(GL_TEXTURE_2D, myTextureID); if(theRedrawTIAIndicator || theRedrawOverlayIndicator)
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, myTexture->w, myTexture->h, {
GL_RGB, GL_UNSIGNED_SHORT_5_6_5, myTexture->pixels); // Texturemap complete texture to surface so we have free scaling
// and antialiasing
uInt32 w = myBaseDim.w, h = myBaseDim.h;
uInt32 w = myBaseDim.w, h = myBaseDim.h; glBindTexture(GL_TEXTURE_2D, myTextureID);
glBegin(GL_QUADS); glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, myTexture->w, myTexture->h,
glTexCoord2f(myTexCoord[0], myTexCoord[1]); glVertex2i(0, 0); GL_RGB, GL_UNSIGNED_SHORT_5_6_5, myTexture->pixels);
glTexCoord2f(myTexCoord[2], myTexCoord[1]); glVertex2i(w, 0); glBegin(GL_QUADS);
glTexCoord2f(myTexCoord[2], myTexCoord[3]); glVertex2i(w, h); glTexCoord2f(myTexCoord[0], myTexCoord[1]); glVertex2i(0, 0);
glTexCoord2f(myTexCoord[0], myTexCoord[3]); glVertex2i(0, h); glTexCoord2f(myTexCoord[2], myTexCoord[1]); glVertex2i(w, 0);
glEnd(); glTexCoord2f(myTexCoord[2], myTexCoord[3]); glVertex2i(w, h);
glTexCoord2f(myTexCoord[0], myTexCoord[3]); glVertex2i(0, h);
glEnd();
// Now show all changes made to the textures // Now show all changes made to the textures
SDL_GL_SwapBuffers(); SDL_GL_SwapBuffers();
glBegin(GL_QUADS);
glTexCoord2f(myTexCoord[0], myTexCoord[1]); glVertex2i(0, 0);
glTexCoord2f(myTexCoord[2], myTexCoord[1]); glVertex2i(w, 0);
glTexCoord2f(myTexCoord[2], myTexCoord[3]); glVertex2i(w, h);
glTexCoord2f(myTexCoord[0], myTexCoord[3]); glVertex2i(0, h);
glEnd();
// The frame doesn't need to be completely redrawn anymore
theRedrawTIAIndicator = theRedrawOverlayIndicator = false;
}
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of // See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES. // this file, and for a DISCLAIMER OF ALL WARRANTIES.
// //
// $Id: FrameBuffer.cxx,v 1.54 2005-07-19 18:21:27 stephena Exp $ // $Id: FrameBuffer.cxx,v 1.55 2005-07-20 15:52:57 stephena Exp $
//============================================================================ //============================================================================
#include <sstream> #include <sstream>
@ -38,14 +38,13 @@
FrameBuffer::FrameBuffer(OSystem* osystem) FrameBuffer::FrameBuffer(OSystem* osystem)
: myOSystem(osystem), : myOSystem(osystem),
theRedrawTIAIndicator(true), theRedrawTIAIndicator(true),
theRedrawOverlayIndicator(false),
theZoomLevel(2), theZoomLevel(2),
theMaxZoomLevel(2), theMaxZoomLevel(2),
theAspectRatio(1.0), theAspectRatio(1.0),
myFrameRate(0), myFrameRate(0),
myPauseStatus(false), myPauseStatus(false),
theRedrawOverlayIndicator(false), myMessageTime(-1),
myOverlayRedraws(2),
myMessageTime(0),
myMessageText(""), myMessageText(""),
myNumRedraws(0) myNumRedraws(0)
{ {
@ -138,7 +137,6 @@ void FrameBuffer::initialize(const string& title, uInt32 width, uInt32 height,
// Erase any messages from a previous run // Erase any messages from a previous run
myMessageTime = 0; myMessageTime = 0;
theRedrawTIAIndicator = true; //FIX
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -183,7 +181,10 @@ void FrameBuffer::update()
// Erase this message on next update // Erase this message on next update
if(myMessageTime == 0) if(myMessageTime == 0)
theRedrawTIAIndicator = true; // FIX {
myMessageTime = -1;
theRedrawTIAIndicator = true;
}
} }
} }
break; // S_EMULATE break; // S_EMULATE
@ -197,55 +198,32 @@ void FrameBuffer::update()
// Only update the overlay if it's changed // Only update the overlay if it's changed
if(theRedrawOverlayIndicator) if(theRedrawOverlayIndicator)
{
// Then overlay any menu items
myOSystem->menu().draw(); myOSystem->menu().draw();
// This is a performance hack to only draw the overlay when necessary break; // S_MENU
// Software mode is single-buffered, so we don't have to worry
// However, OpenGL mode is double-buffered, so we need to draw the
// menus at least twice (so they'll be in both buffers)
// Otherwise, we get horrible flickering
myOverlayRedraws--;
theRedrawOverlayIndicator = (myOverlayRedraws != 0);
}
break;
} }
case EventHandler::S_LAUNCHER: case EventHandler::S_LAUNCHER:
{ {
// Only update the screen if it's been invalidated or the overlay have changed // Only update the screen if it's been invalidated or the overlay have changed
if(theRedrawOverlayIndicator) if(theRedrawOverlayIndicator)
{
// Overlay the ROM launcher
myOSystem->launcher().draw(); myOSystem->launcher().draw();
// This is a performance hack to only draw the overlay when necessary break; // S_LAUNCHER
// Software mode is single-buffered, so we don't have to worry
// However, OpenGL mode is double-buffered, so we need to draw the
// menus at least twice (so they'll be in both buffers)
// Otherwise, we get horrible flickering
myOverlayRedraws--;
theRedrawOverlayIndicator = (myOverlayRedraws != 0);
}
break;
} }
case EventHandler::S_DEBUGGER: case EventHandler::S_DEBUGGER:
{ {
// Only update the overlay if it's changed // Only update the overlay if it's changed
// This is a performance hack to only draw the menus when necessary
if(theRedrawOverlayIndicator) if(theRedrawOverlayIndicator)
{ {
// Overlay the ROM launcher
myOSystem->debugger().draw(); myOSystem->debugger().draw();
// This is a performance hack to only draw the menus when necessary // This needs to be here, otherwise software mode uses a lot
// Software mode is single-buffered, so we don't have to worry // of CPU when drawing the debugger. I'm sure it's a bug,
// However, OpenGL mode is double-buffered, so we need to draw the // but at least it's a documented one :)
// menus at least twice (so they'll be in both buffers) theRedrawOverlayIndicator = false;
// Otherwise, we get horrible flickering
myOverlayRedraws--;
theRedrawOverlayIndicator = (myOverlayRedraws != 0);
} }
break; // S_DEBUGGER break; // S_DEBUGGER
} }
@ -279,7 +257,6 @@ void FrameBuffer::refreshOverlay(bool now)
refreshTIA(now); refreshTIA(now);
theRedrawOverlayIndicator = true; theRedrawOverlayIndicator = true;
myOverlayRedraws = 2;
if(now) update(); if(now) update();
} }
@ -288,7 +265,6 @@ void FrameBuffer::showMessage(const string& message)
{ {
myMessageText = message; myMessageText = message;
myMessageTime = myFrameRate << 1; // Show message for 2 seconds myMessageTime = myFrameRate << 1; // Show message for 2 seconds
theRedrawTIAIndicator = true; // FIXME
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of // See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES. // this file, and for a DISCLAIMER OF ALL WARRANTIES.
// //
// $Id: FrameBuffer.hxx,v 1.49 2005-07-19 18:21:28 stephena Exp $ // $Id: FrameBuffer.hxx,v 1.50 2005-07-20 15:52:58 stephena Exp $
//============================================================================ //============================================================================
#ifndef FRAMEBUFFER_HXX #ifndef FRAMEBUFFER_HXX
@ -52,7 +52,7 @@ enum FrameStyle {
All GUI elements (ala ScummVM) are drawn here as well. All GUI elements (ala ScummVM) are drawn here as well.
@author Stephen Anthony @author Stephen Anthony
@version $Id: FrameBuffer.hxx,v 1.49 2005-07-19 18:21:28 stephena Exp $ @version $Id: FrameBuffer.hxx,v 1.50 2005-07-20 15:52:58 stephena Exp $
*/ */
class FrameBuffer class FrameBuffer
{ {
@ -414,6 +414,9 @@ class FrameBuffer
// Indicates if the TIA area should be redrawn // Indicates if the TIA area should be redrawn
bool theRedrawTIAIndicator; bool theRedrawTIAIndicator;
// Indicates if the overlay area should be redrawn
bool theRedrawOverlayIndicator;
// The SDL video buffer // The SDL video buffer
SDL_Surface* myScreen; SDL_Surface* myScreen;
@ -448,12 +451,6 @@ class FrameBuffer
// Indicates the current pause status // Indicates the current pause status
bool myPauseStatus; bool myPauseStatus;
// Indicates if the overlay area should be redrawn
bool theRedrawOverlayIndicator;
// Number of times menu have been drawn
int myOverlayRedraws;
// Message timer // Message timer
Int32 myMessageTime; Int32 myMessageTime;

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of // See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES. // this file, and for a DISCLAIMER OF ALL WARRANTIES.
// //
// $Id: DialogContainer.cxx,v 1.11 2005-06-23 14:33:11 stephena Exp $ // $Id: DialogContainer.cxx,v 1.12 2005-07-20 15:52:58 stephena Exp $
//============================================================================ //============================================================================
#include "OSystem.hxx" #include "OSystem.hxx"
@ -86,6 +86,7 @@ void DialogContainer::draw()
void DialogContainer::addDialog(Dialog* d) void DialogContainer::addDialog(Dialog* d)
{ {
myDialogStack.push(d); myDialogStack.push(d);
myOSystem->frameBuffer().refreshTIA();
myOSystem->frameBuffer().refreshOverlay(); myOSystem->frameBuffer().refreshOverlay();
} }
@ -95,6 +96,7 @@ void DialogContainer::removeDialog()
if(!myDialogStack.empty()) if(!myDialogStack.empty())
{ {
myDialogStack.pop(); myDialogStack.pop();
myOSystem->frameBuffer().refreshTIA();
myOSystem->frameBuffer().refreshOverlay(); myOSystem->frameBuffer().refreshOverlay();
} }
} }
@ -105,7 +107,7 @@ void DialogContainer::reStack()
// Pop all items from the stack, and then add the base menu // Pop all items from the stack, and then add the base menu
while(!myDialogStack.empty()) while(!myDialogStack.empty())
myDialogStack.pop(); myDialogStack.pop();
myDialogStack.push(myBaseDialog); addDialog(myBaseDialog);
// Now make sure all dialog boxes are in a known (closed) state // Now make sure all dialog boxes are in a known (closed) state
myBaseDialog->reset(); myBaseDialog->reset();

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of // See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES. // this file, and for a DISCLAIMER OF ALL WARRANTIES.
// //
// $Id: PromptWidget.cxx,v 1.27 2005-07-16 16:09:38 urchlay Exp $ // $Id: PromptWidget.cxx,v 1.28 2005-07-20 15:52:58 stephena Exp $
// //
// Based on code from ScummVM - Scumm Interpreter // Based on code from ScummVM - Scumm Interpreter
// Copyright (C) 2002-2004 The ScummVM project // Copyright (C) 2002-2004 The ScummVM project
@ -207,7 +207,6 @@ bool PromptWidget::handleKeyDown(int ascii, int keycode, int modifiers)
break; break;
} }
case 27: // escape FIXME - possibly remove this one?
case 9: // tab case 9: // tab
{ {
// Tab completion: we complete either commands or labels, but not // Tab completion: we complete either commands or labels, but not