mirror of https://github.com/stella-emu/stella.git
Second pass at optimizing the GP2X framebuffer rendering. There's still
at least one more optimization to make after this :) git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@1182 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
parent
84781e064a
commit
dcb74722ad
|
@ -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: FrameBufferGP2X.cxx,v 1.7 2006-12-05 14:53:26 stephena Exp $
|
// $Id: FrameBufferGP2X.cxx,v 1.8 2006-12-05 21:55:15 stephena Exp $
|
||||||
//============================================================================
|
//============================================================================
|
||||||
|
|
||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
|
@ -23,44 +23,24 @@
|
||||||
#include "OSystem.hxx"
|
#include "OSystem.hxx"
|
||||||
#include "Font.hxx"
|
#include "Font.hxx"
|
||||||
#include "GuiUtils.hxx"
|
#include "GuiUtils.hxx"
|
||||||
#include "RectList.hxx"
|
|
||||||
#include "FrameBufferGP2X.hxx"
|
#include "FrameBufferGP2X.hxx"
|
||||||
|
|
||||||
// Comment out entire line to test new rendering code
|
|
||||||
#define DIRTY_RECTS 1
|
|
||||||
|
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
FrameBufferGP2X::FrameBufferGP2X(OSystem* osystem)
|
FrameBufferGP2X::FrameBufferGP2X(OSystem* osystem)
|
||||||
: FrameBuffer(osystem),
|
: FrameBuffer(osystem),
|
||||||
myDirtyFlag(true),
|
myDirtyFlag(true)
|
||||||
myRectList(NULL),
|
|
||||||
myOverlayRectList(NULL)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
FrameBufferGP2X::~FrameBufferGP2X()
|
FrameBufferGP2X::~FrameBufferGP2X()
|
||||||
{
|
{
|
||||||
delete myRectList;
|
|
||||||
delete myOverlayRectList;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
bool FrameBufferGP2X::initSubsystem()
|
bool FrameBufferGP2X::initSubsystem()
|
||||||
{
|
{
|
||||||
// Set up the rectangle list to be used in the dirty update
|
|
||||||
delete myRectList;
|
|
||||||
myRectList = new RectList();
|
|
||||||
delete myOverlayRectList;
|
|
||||||
myOverlayRectList = new RectList();
|
|
||||||
|
|
||||||
if(!myRectList || !myOverlayRectList)
|
|
||||||
{
|
|
||||||
cerr << "ERROR: Unable to get memory for SDL rects" << endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the screen
|
// Create the screen
|
||||||
return createScreen();
|
return createScreen();
|
||||||
}
|
}
|
||||||
|
@ -89,6 +69,7 @@ bool FrameBufferGP2X::createScreen()
|
||||||
// In software mode, the image and screen dimensions are always the same
|
// In software mode, the image and screen dimensions are always the same
|
||||||
myImageDim = myScreenDim;
|
myImageDim = myScreenDim;
|
||||||
|
|
||||||
|
// The GP2X always uses a 16-bit hardware buffer
|
||||||
myScreen = SDL_SetVideoMode(myScreenDim.w, myScreenDim.h, 16, mySDLFlags);
|
myScreen = SDL_SetVideoMode(myScreenDim.w, myScreenDim.h, 16, mySDLFlags);
|
||||||
if(myScreen == NULL)
|
if(myScreen == NULL)
|
||||||
{
|
{
|
||||||
|
@ -96,13 +77,8 @@ bool FrameBufferGP2X::createScreen()
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
myPitch = myScreen->pitch/2;
|
myPitch = myScreen->pitch/2;
|
||||||
|
|
||||||
// Erase old rects, since they've probably been scaled for
|
|
||||||
// a different sized screen
|
|
||||||
myRectList->start();
|
|
||||||
myOverlayRectList->start();
|
|
||||||
|
|
||||||
myDirtyFlag = true;
|
myDirtyFlag = true;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,143 +98,6 @@ void FrameBufferGP2X::drawMediaSource()
|
||||||
|
|
||||||
if(!myUsePhosphor)
|
if(!myUsePhosphor)
|
||||||
{
|
{
|
||||||
#ifdef DIRTY_RECTS
|
|
||||||
struct Rectangle
|
|
||||||
{
|
|
||||||
uInt8 color;
|
|
||||||
uInt16 x, y, width, height;
|
|
||||||
} rectangles[2][160];
|
|
||||||
|
|
||||||
// This array represents the rectangles that need displaying
|
|
||||||
// on the current scanline we're processing
|
|
||||||
Rectangle* currentRectangles = rectangles[0];
|
|
||||||
|
|
||||||
// This array represents the rectangles that are still active
|
|
||||||
// from the previous scanlines we have processed
|
|
||||||
Rectangle* activeRectangles = rectangles[1];
|
|
||||||
|
|
||||||
// Indicates the number of active rectangles
|
|
||||||
uInt16 activeCount = 0;
|
|
||||||
|
|
||||||
// This update procedure requires theWidth to be a multiple of four.
|
|
||||||
// This is validated when the properties are loaded.
|
|
||||||
for(uInt16 y = 0; y < height; ++y)
|
|
||||||
{
|
|
||||||
// Indicates the number of current rectangles
|
|
||||||
uInt16 currentCount = 0;
|
|
||||||
|
|
||||||
// Look at four pixels at a time to see if anything has changed
|
|
||||||
uInt32* current = (uInt32*)(currentFrame);
|
|
||||||
uInt32* previous = (uInt32*)(previousFrame);
|
|
||||||
|
|
||||||
for(uInt16 x = 0; x < width; x += 4, ++current, ++previous)
|
|
||||||
{
|
|
||||||
// Has something changed in this set of four pixels?
|
|
||||||
if((*current != *previous) || theRedrawTIAIndicator)
|
|
||||||
{
|
|
||||||
uInt8* c = (uInt8*)current;
|
|
||||||
uInt8* p = (uInt8*)previous;
|
|
||||||
|
|
||||||
// Look at each of the bytes that make up the uInt32
|
|
||||||
for(uInt16 i = 0; i < 4; ++i, ++c, ++p)
|
|
||||||
{
|
|
||||||
// See if this pixel has changed
|
|
||||||
if((*c != *p) || theRedrawTIAIndicator)
|
|
||||||
{
|
|
||||||
// Can we extend a rectangle or do we have to create a new one?
|
|
||||||
if((currentCount != 0) &&
|
|
||||||
(currentRectangles[currentCount - 1].color == *c) &&
|
|
||||||
((currentRectangles[currentCount - 1].x +
|
|
||||||
currentRectangles[currentCount - 1].width) == (x + i)))
|
|
||||||
{
|
|
||||||
currentRectangles[currentCount - 1].width += 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
currentRectangles[currentCount].x = x + i;
|
|
||||||
currentRectangles[currentCount].y = y;
|
|
||||||
currentRectangles[currentCount].width = 1;
|
|
||||||
currentRectangles[currentCount].height = 1;
|
|
||||||
currentRectangles[currentCount].color = *c;
|
|
||||||
currentCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Merge the active and current rectangles flushing any that are of no use
|
|
||||||
uInt16 activeIndex = 0;
|
|
||||||
|
|
||||||
for(uInt16 t = 0; (t < currentCount) && (activeIndex < activeCount); ++t)
|
|
||||||
{
|
|
||||||
Rectangle& current = currentRectangles[t];
|
|
||||||
Rectangle& active = activeRectangles[activeIndex];
|
|
||||||
|
|
||||||
// Can we merge the current rectangle with an active one?
|
|
||||||
if((current.x == active.x) && (current.width == active.width) &&
|
|
||||||
(current.color == active.color))
|
|
||||||
{
|
|
||||||
current.y = active.y;
|
|
||||||
current.height = active.height + 1;
|
|
||||||
++activeIndex;
|
|
||||||
}
|
|
||||||
// Is it impossible for this active rectangle to be merged?
|
|
||||||
else if(current.x >= active.x)
|
|
||||||
{
|
|
||||||
// Flush the active rectangle
|
|
||||||
SDL_Rect temp;
|
|
||||||
|
|
||||||
temp.x = active.x << 1;
|
|
||||||
temp.y = active.y;
|
|
||||||
temp.w = active.width << 1;
|
|
||||||
temp.h = active.height;
|
|
||||||
|
|
||||||
myRectList->add(&temp);
|
|
||||||
SDL_FillRect(myScreen, &temp, myDefPalette[active.color]);
|
|
||||||
|
|
||||||
++activeIndex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Flush any remaining active rectangles
|
|
||||||
for(uInt16 s = activeIndex; s < activeCount; ++s)
|
|
||||||
{
|
|
||||||
Rectangle& active = activeRectangles[s];
|
|
||||||
SDL_Rect temp;
|
|
||||||
temp.x = active.x << 1;
|
|
||||||
temp.y = active.y;
|
|
||||||
temp.w = active.width << 1;
|
|
||||||
temp.h = active.height;
|
|
||||||
|
|
||||||
myRectList->add(&temp);
|
|
||||||
SDL_FillRect(myScreen, &temp, myDefPalette[active.color]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// We can now make the current rectangles into the active rectangles
|
|
||||||
Rectangle* tmp = currentRectangles;
|
|
||||||
currentRectangles = activeRectangles;
|
|
||||||
activeRectangles = tmp;
|
|
||||||
activeCount = currentCount;
|
|
||||||
|
|
||||||
currentFrame += width;
|
|
||||||
previousFrame += width;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Flush any rectangles that are still active
|
|
||||||
for(uInt16 t = 0; t < activeCount; ++t)
|
|
||||||
{
|
|
||||||
Rectangle& active = activeRectangles[t];
|
|
||||||
SDL_Rect temp;
|
|
||||||
temp.x = active.x << 1;
|
|
||||||
temp.y = active.y;
|
|
||||||
temp.w = active.width << 1;
|
|
||||||
temp.h = active.height;
|
|
||||||
|
|
||||||
myRectList->add(&temp);
|
|
||||||
SDL_FillRect(myScreen, &temp, myDefPalette[active.color]);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
for(uInt32 y = 0; y < height; ++y )
|
for(uInt32 y = 0; y < height; ++y )
|
||||||
{
|
{
|
||||||
uInt32 pos = screenofsY;
|
uInt32 pos = screenofsY;
|
||||||
|
@ -281,7 +120,6 @@ void FrameBufferGP2X::drawMediaSource()
|
||||||
bufofsY += width;
|
bufofsY += width;
|
||||||
screenofsY += myPitch;
|
screenofsY += myPitch;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -310,14 +148,6 @@ void FrameBufferGP2X::drawMediaSource()
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void FrameBufferGP2X::preFrameUpdate()
|
void FrameBufferGP2X::preFrameUpdate()
|
||||||
{
|
{
|
||||||
// Start a new rectlist on each display update
|
|
||||||
myRectList->start();
|
|
||||||
|
|
||||||
// Add all previous overlay rects, then erase
|
|
||||||
SDL_Rect* dirtyOverlayRects = myOverlayRectList->rects();
|
|
||||||
for(unsigned int i = 0; i < myOverlayRectList->numRects(); ++i)
|
|
||||||
myRectList->add(&dirtyOverlayRects[i]);
|
|
||||||
myOverlayRectList->start();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -326,7 +156,6 @@ void FrameBufferGP2X::postFrameUpdate()
|
||||||
if(myDirtyFlag)
|
if(myDirtyFlag)
|
||||||
{
|
{
|
||||||
SDL_Flip(myScreen);
|
SDL_Flip(myScreen);
|
||||||
myRectList->start();
|
|
||||||
myDirtyFlag = false;
|
myDirtyFlag = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -476,20 +305,8 @@ void FrameBufferGP2X::translateCoords(Int32* x, Int32* y)
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void FrameBufferGP2X::addDirtyRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h)
|
void FrameBufferGP2X::addDirtyRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h)
|
||||||
{
|
{
|
||||||
// We may entirely remove the RectList, since it might be faster to just
|
// We're using a hardware buffer; just indicate that the buffer is dirty
|
||||||
// flip the screen (since it's a hardware buffer)
|
|
||||||
myDirtyFlag = true;
|
myDirtyFlag = true;
|
||||||
|
|
||||||
// Add a dirty rect to the overlay rectangle list
|
|
||||||
// They will actually be added to the main rectlist in preFrameUpdate()
|
|
||||||
// TODO - intelligent merging of rectangles, to avoid overlap
|
|
||||||
SDL_Rect temp;
|
|
||||||
temp.x = x;
|
|
||||||
temp.y = y;
|
|
||||||
temp.w = w;
|
|
||||||
temp.h = h;
|
|
||||||
|
|
||||||
myOverlayRectList->add(&temp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
|
@ -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: FrameBufferGP2X.hxx,v 1.4 2006-12-04 19:43:26 stephena Exp $
|
// $Id: FrameBufferGP2X.hxx,v 1.5 2006-12-05 21:55:15 stephena Exp $
|
||||||
//============================================================================
|
//============================================================================
|
||||||
|
|
||||||
#ifndef FRAMEBUFFER_GP2X_HXX
|
#ifndef FRAMEBUFFER_GP2X_HXX
|
||||||
|
@ -23,7 +23,6 @@
|
||||||
|
|
||||||
class OSystem;
|
class OSystem;
|
||||||
class GUI::Font;
|
class GUI::Font;
|
||||||
class RectList;
|
|
||||||
|
|
||||||
#include "bspf.hxx"
|
#include "bspf.hxx"
|
||||||
#include "FrameBuffer.hxx"
|
#include "FrameBuffer.hxx"
|
||||||
|
@ -33,7 +32,7 @@ class RectList;
|
||||||
This class implements an SDL hardware framebuffer for the GP2X device.
|
This class implements an SDL hardware framebuffer for the GP2X device.
|
||||||
|
|
||||||
@author Stephen Anthony
|
@author Stephen Anthony
|
||||||
@version $Id: FrameBufferGP2X.hxx,v 1.4 2006-12-04 19:43:26 stephena Exp $
|
@version $Id: FrameBufferGP2X.hxx,v 1.5 2006-12-05 21:55:15 stephena Exp $
|
||||||
*/
|
*/
|
||||||
class FrameBufferGP2X : public FrameBuffer
|
class FrameBufferGP2X : public FrameBuffer
|
||||||
{
|
{
|
||||||
|
@ -212,14 +211,11 @@ class FrameBufferGP2X : public FrameBuffer
|
||||||
virtual void showCursor(bool show);
|
virtual void showCursor(bool show);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// Indicates that the buffer is dirty, and should be redrawn/flipped
|
||||||
bool myDirtyFlag;
|
bool myDirtyFlag;
|
||||||
|
|
||||||
|
// Pitch (in bytes) of the current screen
|
||||||
int myPitch;
|
int myPitch;
|
||||||
|
|
||||||
// Used in the dirty update of the SDL surface
|
|
||||||
RectList* myRectList;
|
|
||||||
|
|
||||||
// Used in the dirty update of the overlay surface
|
|
||||||
RectList* myOverlayRectList;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue