Phosphor effect now working for software render in 16/32 bit color modes;

still TODO for 24 bit mode.

I've benchmarked the CPU usage in Linux under 16/32 bit modes, and they're
within 1% of those for z26.  Not bad for C++ vs. assembly code :)  I still
need to test in Windows, which (ironically enough) tends to be slower than
Linux in graphics performance.

Note that CPU usage ranges from 6% (Linux/1x/software/phosphor/16bit) to
85% (Linux/3x/software/phosphor/32bit).  Using OpenGL, the usage is always
12%, whatever the zoom/color depth/phosphor.  I just love OpenGL ...


git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@955 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
stephena 2006-01-12 16:23:36 +00:00
parent b4525b5ff7
commit 53d70797d8
3 changed files with 249 additions and 211 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.47 2006-01-11 20:28:06 stephena Exp $
// $Id: FrameBufferGL.cxx,v 1.48 2006-01-12 16:23:36 stephena Exp $
//============================================================================
#ifdef DISPLAY_OPENGL
@ -221,16 +221,16 @@ void FrameBufferGL::drawMediaSource()
uInt16* buffer = (uInt16*) myTexture->pixels;
// TODO - is this fast enough?
register uInt32 x, y;
switch((int)myUsePhosphor) // use switch/case, since we'll eventually have filters
{
case 0:
for(y = 0; y < height; ++y )
{
uInt32 bufofsY = 0;
uInt32 screenofsY = 0;
for(uInt32 y = 0; y < height; ++y )
{
const uInt32 bufofsY = y * width;
const uInt32 screenofsY = y * myTexture->w;
for(x = 0; x < width; ++x )
uInt32 pos = screenofsY;
for(uInt32 x = 0; x < width; ++x )
{
const uInt32 bufofs = bufofsY + x;
uInt8 v = currentFrame[bufofs];
@ -243,62 +243,41 @@ void FrameBufferGL::drawMediaSource()
// are drawn in postFrameUpdate()
myDirtyFlag = true;
// x << 1 is times 2 ( doubling width )
const uInt32 pos = screenofsY + (x << 1);
buffer[pos] = buffer[pos+1] = (uInt16) myPalette[v];
}
pos += 2;
}
bufofsY += width;
screenofsY += myTexture->w;
}
/*
for(y = 0; y < height; ++y )
{
const uInt32 bufofsY = y * width;
const uInt32 screenofsY = y * myTexture->w;
for(x = 0; x < width; ++x )
{
const uInt32 bufofs = bufofsY + x;
uInt8 v = currentFrame[bufofs];
uInt8 w = previousFrame[bufofs];
if(v != w || 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()
myDirtyFlag = true;
// x << 1 is times 2 ( doubling width )
const uInt32 pos = screenofsY + (x << 1);
buffer[pos] = buffer[pos+1] = (uInt16) myPalette[v];
}
}
}
*/
break;
}
case 1:
{
// Phosphor mode always implies a dirty update,
// so we don't care about theRedrawTIAIndicator
myDirtyFlag = true;
for(y = 0; y < height; ++y )
{
const uInt32 bufofsY = y * width;
const uInt32 screenofsY = y * myTexture->w;
for(x = 0; x < width; ++x )
uInt32 bufofsY = 0;
uInt32 screenofsY = 0;
for(uInt32 y = 0; y < height; ++y )
{
uInt32 pos = screenofsY;
for(uInt32 x = 0; x < width; ++x )
{
const uInt32 bufofs = bufofsY + x;
uInt8 v = currentFrame[bufofs];
uInt8 w = previousFrame[bufofs];
// x << 1 is times 2 ( doubling width )
const uInt32 pos = screenofsY + (x << 1);
buffer[pos] = buffer[pos+1] = (uInt16) myAvgPalette[v][w];
buffer[pos++] = (uInt16) myAvgPalette[v][w];
buffer[pos++] = (uInt16) myAvgPalette[v][w];
}
bufofsY += width;
screenofsY += myTexture->w;
}
break;
}
}
}
@ -495,11 +474,6 @@ void FrameBufferGL::enablePhosphor(bool enable)
{
myUsePhosphor = enable;
myPhosphorBlend = myOSystem->settings().getInt("ppblend");
cerr << "phosphor effect: " << (myUsePhosphor ? "yes" : "no") << endl
<< "phosphor amount: " << myPhosphorBlend << endl << endl;
// FIXME - change rendering method
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

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: FrameBufferSoft.cxx,v 1.41 2006-01-11 20:28:06 stephena Exp $
// $Id: FrameBufferSoft.cxx,v 1.42 2006-01-12 16:23:36 stephena Exp $
//============================================================================
#include <SDL.h>
@ -117,7 +117,7 @@ void FrameBufferSoft::drawMediaSource()
uInt32 width = mediasrc.width();
uInt32 height = mediasrc.height();
switch(myRenderType) // use switch/case, since we'll eventually have filters
switch((int)myRenderType) // use switch/case, since we'll eventually have filters
{
case kSoftZoom:
{
@ -138,76 +138,119 @@ void FrameBufferSoft::drawMediaSource()
// 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)
// 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)
{
uInt8* c = (uInt8*)current;
uInt8* p = (uInt8*)previous;
// Indicates the number of current rectangles
uInt16 currentCount = 0;
// Look at each of the bytes that make up the uInt32
for(uInt16 i = 0; i < 4; ++i, ++c, ++p)
// 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)
{
// See if this pixel has changed
if((*c != *p) || theRedrawTIAIndicator)
// Has something changed in this set of four pixels?
if((*current != *previous) || 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)))
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)
{
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++;
// 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 * screenMultiple << 1;
temp.y = active.y * screenMultiple;
temp.w = active.width * screenMultiple << 1;
temp.h = active.height * screenMultiple;
myRectList->add(&temp);
SDL_FillRect(myScreen, &temp, myPalette[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 * screenMultiple << 1;
temp.y = active.y * screenMultiple;
temp.w = active.width * screenMultiple << 1;
temp.h = active.height * screenMultiple;
myRectList->add(&temp);
SDL_FillRect(myScreen, &temp, myPalette[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;
}
}
// 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))
// Flush any rectangles that are still active
for(uInt16 t = 0; t < activeCount; ++t)
{
current.y = active.y;
current.height = active.height + 1;
Rectangle& active = activeRectangles[t];
++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 * screenMultiple << 1;
temp.y = active.y * screenMultiple;
temp.w = active.width * screenMultiple << 1;
@ -215,55 +258,11 @@ void FrameBufferSoft::drawMediaSource()
myRectList->add(&temp);
SDL_FillRect(myScreen, &temp, myPalette[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 * screenMultiple << 1;
temp.y = active.y * screenMultiple;
temp.w = active.width * screenMultiple << 1;
temp.h = active.height * screenMultiple;
myRectList->add(&temp);
SDL_FillRect(myScreen, &temp, myPalette[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 * screenMultiple << 1;
temp.y = active.y * screenMultiple;
temp.w = active.width * screenMultiple << 1;
temp.h = active.height * screenMultiple;
myRectList->add(&temp);
SDL_FillRect(myScreen, &temp, myPalette[active.color]);
}
break; // case 0
}
case kPhosphor2x_16:
case kPhosphor_16:
{
// Since phosphor mode updates the whole screen,
// we might as well use SDL_Flip (see postFrameUpdate)
@ -273,53 +272,114 @@ void FrameBufferSoft::drawMediaSource()
myRectList->add(&temp);
uInt16* buffer = (uInt16*)myScreen->pixels;
int pixel;
for(uInt32 y = 0; y < height; ++y)
{
for(int i = 0; i < width>>2; ++i)
{
pixel = myAvgPalette[*currentFrame++][*previousFrame++];
*buffer++ = pixel; *buffer++ = pixel;
*buffer++ = pixel; *buffer++ = pixel;
pixel = myAvgPalette[*currentFrame++][*previousFrame++];
*buffer++ = pixel; *buffer++ = pixel;
*buffer++ = pixel; *buffer++ = pixel;
pixel = myAvgPalette[*currentFrame++][*previousFrame++];
*buffer++ = pixel; *buffer++ = pixel;
*buffer++ = pixel; *buffer++ = pixel;
pixel = myAvgPalette[*currentFrame++][*previousFrame++];
*buffer++ = pixel; *buffer++ = pixel;
*buffer++ = pixel; *buffer++ = pixel;
}
buffer+=myScreen->pitch/2;
}
/*
uInt32 bufofsY = 0;//y * width;
uInt32 screenofsY = 0;//y * myScreen->pitch/2;
uInt32 bufofsY = 0;
uInt32 screenofsY = 0;
for(uInt32 y = 0; y < height; ++y )
{
for(uInt32 x = 0; x < width; ++x)
uInt32 ystride = theZoomLevel;
while(ystride--)
{
const uInt32 bufofs = bufofsY + x;
uInt8 v = currentFrame[bufofs];
uInt8 w = previousFrame[bufofs];
uInt32 pos = screenofsY;
for(uInt32 x = 0; x < width; ++x )
{
const uInt32 bufofs = bufofsY + x;
uInt32 xstride = theZoomLevel;
// x << 1 is times 2 ( doubling width )
int pos = screenofsY + (x << 2);
buffer[pos++] = (uInt16) myAvgPalette[v][w];
buffer[pos++] = (uInt16) myAvgPalette[v][w];
buffer[pos++] = (uInt16) myAvgPalette[v][w];
buffer[pos++] = (uInt16) myAvgPalette[v][w];
uInt8 v = currentFrame[bufofs];
uInt8 w = previousFrame[bufofs];
while(xstride--)
{
buffer[pos++] = (uInt16) myAvgPalette[v][w];
buffer[pos++] = (uInt16) myAvgPalette[v][w];
}
}
screenofsY += myScreen->w;
}
bufofsY += width;
screenofsY += myScreen->pitch/2;
}
*/
break;
break; // kPhosphor_16
}
case kPhosphor_24:
{
// FIXME - implement 24 bit mode
#if 0
// Since phosphor mode updates the whole screen,
// we might as well use SDL_Flip (see postFrameUpdate)
myUseDirtyRects = false;
SDL_Rect temp;
temp.x = temp.y = temp.w = temp.h = 0;
myRectList->add(&temp);
uInt16* buffer = (uInt16*)myScreen->pixels;
uInt32 bufofsY = 0;
uInt32 screenofsY = 0;
for(uInt32 y = 0; y < height; ++y )
{
uInt32 ystride = theZoomLevel;
while(ystride--)
{
uInt32 pos = screenofsY;
for(uInt32 x = 0; x < width; ++x )
{
const uInt32 bufofs = bufofsY + x;
uInt32 xstride = theZoomLevel;
uInt8 v = currentFrame[bufofs];
uInt8 w = previousFrame[bufofs];
while(xstride--)
{
buffer[pos++] = (uInt16) myAvgPalette[v][w];
buffer[pos++] = (uInt16) myAvgPalette[v][w];
}
}
screenofsY += myScreen->w;
}
bufofsY += width;
}
#endif
break; // kPhosphor_24
}
case kPhosphor_32:
{
// Since phosphor mode updates the whole screen,
// we might as well use SDL_Flip (see postFrameUpdate)
myUseDirtyRects = false;
SDL_Rect temp;
temp.x = temp.y = temp.w = temp.h = 0;
myRectList->add(&temp);
uInt32* buffer = (uInt32*)myScreen->pixels;
uInt32 bufofsY = 0;
uInt32 screenofsY = 0;
for(uInt32 y = 0; y < height; ++y )
{
uInt32 ystride = theZoomLevel;
while(ystride--)
{
uInt32 pos = screenofsY;
for(uInt32 x = 0; x < width; ++x )
{
const uInt32 bufofs = bufofsY + x;
uInt32 xstride = theZoomLevel;
uInt8 v = currentFrame[bufofs];
uInt8 w = previousFrame[bufofs];
while(xstride--)
{
buffer[pos++] = (uInt32) myAvgPalette[v][w];
buffer[pos++] = (uInt32) myAvgPalette[v][w];
}
}
screenofsY += myScreen->w;
}
bufofsY += width;
}
break; // kPhosphor_32
}
}
}
@ -557,12 +617,25 @@ void FrameBufferSoft::enablePhosphor(bool enable)
myPhosphorBlend = myOSystem->settings().getInt("ppblend");
if(myUsePhosphor)
myRenderType = kPhosphor2x_16;
{
switch(myScreen->format->BitsPerPixel)
{
case 16:
myRenderType = kPhosphor_16;
break;
case 24:
myRenderType = kPhosphor_24;
break;
case 32:
myRenderType = kPhosphor_32;
break;
default:
myRenderType = kSoftZoom; // What else should we do here?
break;
}
}
else
myRenderType = kSoftZoom;
cerr << "phosphor effect: " << (myUsePhosphor ? "yes" : "no") << endl
<< "phosphor amount: " << myPhosphorBlend << endl << endl;
}

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: FrameBufferSoft.hxx,v 1.27 2006-01-11 20:28:06 stephena Exp $
// $Id: FrameBufferSoft.hxx,v 1.28 2006-01-12 16:23:36 stephena Exp $
//============================================================================
#ifndef FRAMEBUFFER_SOFT_HXX
@ -35,7 +35,7 @@ class RectList;
This class implements an SDL software framebuffer.
@author Stephen Anthony
@version $Id: FrameBufferSoft.hxx,v 1.27 2006-01-11 20:28:06 stephena Exp $
@version $Id: FrameBufferSoft.hxx,v 1.28 2006-01-12 16:23:36 stephena Exp $
*/
class FrameBufferSoft : public FrameBuffer
{
@ -201,18 +201,9 @@ class FrameBufferSoft : public FrameBuffer
private:
enum RenderType {
kSoftZoom,
kPhosphor1x_16,
kPhosphor2x_16,
kPhosphor3x_16,
kPhosphor4x_16,
kPhosphor1x_24,
kPhosphor2x_24,
kPhosphor3x_24,
kPhosphor4x_24,
kPhosphor1x_32,
kPhosphor2x_32,
kPhosphor3x_32,
kPhosphor4x_32,
kPhosphor_16,
kPhosphor_24,
kPhosphor_32
};
RenderType myRenderType;
};