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
// 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
@ -230,17 +230,19 @@ void FrameBufferGL::drawMediaSource()
{
const uInt32 bufofs = bufofsY + x;
uInt8 v = currentFrame[bufofs];
if(v == previousFrame[bufofs] && !theRedrawTIAIndicator)
continue;
if(v != previousFrame[bufofs] || theRedrawTIAIndicator)
{
// 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 )
const uInt32 pos = screenofsY + (x << 1);
buffer[pos] = buffer[pos+1] = (uInt16) myPalette[v];
// x << 1 is times 2 ( doubling width )
const uInt32 pos = screenofsY + (x << 1);
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()
{
// Texturemap complete texture to surface so we have free scaling
// and antialiasing
glBindTexture(GL_TEXTURE_2D, myTextureID);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, myTexture->w, myTexture->h,
GL_RGB, GL_UNSIGNED_SHORT_5_6_5, myTexture->pixels);
// Do the following twice, since OpenGL mode is double-buffered,
// and we need the contents placed in both buffers
if(theRedrawTIAIndicator || theRedrawOverlayIndicator)
{
// 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;
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();
glBindTexture(GL_TEXTURE_2D, myTextureID);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, myTexture->w, myTexture->h,
GL_RGB, GL_UNSIGNED_SHORT_5_6_5, myTexture->pixels);
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();
// Now show all changes made to the textures
SDL_GL_SwapBuffers();
// Now show all changes made to the textures
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
// 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>
@ -38,14 +38,13 @@
FrameBuffer::FrameBuffer(OSystem* osystem)
: myOSystem(osystem),
theRedrawTIAIndicator(true),
theRedrawOverlayIndicator(false),
theZoomLevel(2),
theMaxZoomLevel(2),
theAspectRatio(1.0),
myFrameRate(0),
myPauseStatus(false),
theRedrawOverlayIndicator(false),
myOverlayRedraws(2),
myMessageTime(0),
myMessageTime(-1),
myMessageText(""),
myNumRedraws(0)
{
@ -138,7 +137,6 @@ void FrameBuffer::initialize(const string& title, uInt32 width, uInt32 height,
// Erase any messages from a previous run
myMessageTime = 0;
theRedrawTIAIndicator = true; //FIX
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -183,7 +181,10 @@ void FrameBuffer::update()
// Erase this message on next update
if(myMessageTime == 0)
theRedrawTIAIndicator = true; // FIX
{
myMessageTime = -1;
theRedrawTIAIndicator = true;
}
}
}
break; // S_EMULATE
@ -197,55 +198,32 @@ void FrameBuffer::update()
// Only update the overlay if it's changed
if(theRedrawOverlayIndicator)
{
// Then overlay any menu items
myOSystem->menu().draw();
// This is a performance hack to only draw the overlay when necessary
// 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;
break; // S_MENU
}
case EventHandler::S_LAUNCHER:
{
// Only update the screen if it's been invalidated or the overlay have changed
if(theRedrawOverlayIndicator)
{
// Overlay the ROM launcher
myOSystem->launcher().draw();
// This is a performance hack to only draw the overlay when necessary
// 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;
break; // S_LAUNCHER
}
case EventHandler::S_DEBUGGER:
{
// Only update the overlay if it's changed
// This is a performance hack to only draw the menus when necessary
if(theRedrawOverlayIndicator)
{
// Overlay the ROM launcher
myOSystem->debugger().draw();
// This is a performance hack to only draw the menus when necessary
// 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);
// This needs to be here, otherwise software mode uses a lot
// of CPU when drawing the debugger. I'm sure it's a bug,
// but at least it's a documented one :)
theRedrawOverlayIndicator = false;
}
break; // S_DEBUGGER
}
@ -279,7 +257,6 @@ void FrameBuffer::refreshOverlay(bool now)
refreshTIA(now);
theRedrawOverlayIndicator = true;
myOverlayRedraws = 2;
if(now) update();
}
@ -288,7 +265,6 @@ void FrameBuffer::showMessage(const string& message)
{
myMessageText = message;
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
// 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
@ -52,7 +52,7 @@ enum FrameStyle {
All GUI elements (ala ScummVM) are drawn here as well.
@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
{
@ -414,6 +414,9 @@ class FrameBuffer
// Indicates if the TIA area should be redrawn
bool theRedrawTIAIndicator;
// Indicates if the overlay area should be redrawn
bool theRedrawOverlayIndicator;
// The SDL video buffer
SDL_Surface* myScreen;
@ -448,12 +451,6 @@ class FrameBuffer
// Indicates the current pause status
bool myPauseStatus;
// Indicates if the overlay area should be redrawn
bool theRedrawOverlayIndicator;
// Number of times menu have been drawn
int myOverlayRedraws;
// Message timer
Int32 myMessageTime;

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// 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"
@ -86,6 +86,7 @@ void DialogContainer::draw()
void DialogContainer::addDialog(Dialog* d)
{
myDialogStack.push(d);
myOSystem->frameBuffer().refreshTIA();
myOSystem->frameBuffer().refreshOverlay();
}
@ -95,6 +96,7 @@ void DialogContainer::removeDialog()
if(!myDialogStack.empty())
{
myDialogStack.pop();
myOSystem->frameBuffer().refreshTIA();
myOSystem->frameBuffer().refreshOverlay();
}
}
@ -105,7 +107,7 @@ void DialogContainer::reStack()
// Pop all items from the stack, and then add the base menu
while(!myDialogStack.empty())
myDialogStack.pop();
myDialogStack.push(myBaseDialog);
addDialog(myBaseDialog);
// Now make sure all dialog boxes are in a known (closed) state
myBaseDialog->reset();

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// 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
// Copyright (C) 2002-2004 The ScummVM project
@ -207,7 +207,6 @@ bool PromptWidget::handleKeyDown(int ascii, int keycode, int modifiers)
break;
}
case 27: // escape FIXME - possibly remove this one?
case 9: // tab
{
// Tab completion: we complete either commands or labels, but not