First pass at tying the NTSC filtering code into the OpenGL TIA

rendering code.  This is just infrastructure for now.  Pressing
Alt-f will toggle the filtering, but there's no output yet.


git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@2430 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
stephena 2012-03-25 17:51:13 +00:00
parent db6e1c7c81
commit 303fb5bdbc
12 changed files with 143 additions and 43 deletions

View File

@ -1488,6 +1488,12 @@
<td>Control + f</td> <td>Control + f</td>
</tr> </tr>
<tr>
<td>Toggle Blargg NTSC filtering</td>
<td>Alt + f</td>
<td>Cmd + f</td>
</tr>
<tr> <tr>
<td>Save current properties to a new properties file</td> <td>Save current properties to a new properties file</td>
<td>Control + s</td> <td>Control + s</td>
@ -1766,6 +1772,11 @@
period. This can result in smoother updates, and eliminate tearing.</td> period. This can result in smoother updates, and eliminate tearing.</td>
</tr> </tr>
<tr>
<td><pre>-ntsc_filter &lt;1|0&gt;</pre></td>
<td>OpenGL mode only. Enables Blargg NTSC filtering.</td>
</tr>
<!-- FIXME <!-- FIXME
<tr> <tr>
<td><pre>-tv_tex &lt;off|normal|stag&gt;</pre></td> <td><pre>-tv_tex &lt;off|normal|stag&gt;</pre></td>

View File

@ -22,6 +22,7 @@
#include "Font.hxx" #include "Font.hxx"
#include "FrameBufferGL.hxx" #include "FrameBufferGL.hxx"
#include "TIA.hxx" #include "TIA.hxx"
#include "NTSCFilter.hxx"
#include "FBSurfaceTIA.hxx" #include "FBSurfaceTIA.hxx"
@ -97,35 +98,46 @@ void FBSurfaceTIA::update()
uInt32 height = myTIA->height(); uInt32 height = myTIA->height();
uInt16* buffer = (uInt16*) myTexture->pixels; uInt16* buffer = (uInt16*) myTexture->pixels;
if(!myFB.myUsePhosphor) switch(myFB.myFilterType)
{ {
uInt32 bufofsY = 0; case FrameBufferGL::kNone:
uInt32 screenofsY = 0;
for(uInt32 y = 0; y < height; ++y )
{ {
uInt32 pos = screenofsY; uInt32 bufofsY = 0;
for(uInt32 x = 0; x < width; ++x ) uInt32 screenofsY = 0;
buffer[pos++] = (uInt16) myFB.myDefPalette[currentFrame[bufofsY + x]]; for(uInt32 y = 0; y < height; ++y)
bufofsY += width;
screenofsY += myPitch;
}
}
else
{
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; uInt32 pos = screenofsY;
buffer[pos++] = (uInt16) for(uInt32 x = 0; x < width; ++x)
myFB.myAvgPalette[currentFrame[bufofs]][previousFrame[bufofs]]; buffer[pos++] = (uInt16) myFB.myDefPalette[currentFrame[bufofsY + x]];
bufofsY += width;
screenofsY += myPitch;
} }
bufofsY += width; break;
screenofsY += myPitch; }
case FrameBufferGL::kPhosphor:
{
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;
buffer[pos++] = (uInt16)
myFB.myAvgPalette[currentFrame[bufofs]][previousFrame[bufofs]];
}
bufofsY += width;
screenofsY += myPitch;
}
break;
}
case FrameBufferGL::kBlarggNTSC:
{
break;
} }
} }
@ -345,4 +357,10 @@ void FBSurfaceTIA::updateCoords()
} }
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceTIA::setTIAPalette(const uInt32* palette)
{
myNTSCFilter.setTIAPalette(palette);
}
#endif #endif

View File

@ -25,6 +25,7 @@
#include "bspf.hxx" #include "bspf.hxx"
#include "FrameBuffer.hxx" #include "FrameBuffer.hxx"
#include "FrameBufferGL.hxx" #include "FrameBufferGL.hxx"
#include "NTSCFilter.hxx"
/** /**
A surface suitable for OpenGL rendering mode, but specifically for A surface suitable for OpenGL rendering mode, but specifically for
@ -56,6 +57,7 @@ class FBSurfaceTIA : public FBSurface
private: private:
void setTIA(const TIA& tia) { myTIA = &tia; } void setTIA(const TIA& tia) { myTIA = &tia; }
void setTIAPalette(const uInt32* palette);
void setFilter(const string& name); void setFilter(const string& name);
void updateCoords(); void updateCoords();
@ -64,6 +66,7 @@ class FBSurfaceTIA : public FBSurface
const FrameBufferGL::GLpointers& myGL; const FrameBufferGL::GLpointers& myGL;
const TIA* myTIA; const TIA* myTIA;
SDL_Surface* myTexture; SDL_Surface* myTexture;
NTSCFilter myNTSCFilter;
uInt32 myPitch; uInt32 myPitch;
GLuint myTexID[2], myVBOID; GLuint myTexID[2], myVBOID;

View File

@ -40,6 +40,7 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FrameBufferGL::FrameBufferGL(OSystem* osystem) FrameBufferGL::FrameBufferGL(OSystem* osystem)
: FrameBuffer(osystem), : FrameBuffer(osystem),
myFilterType(kNone),
myTiaSurface(NULL), myTiaSurface(NULL),
myFilterParamName("GL_NEAREST"), myFilterParamName("GL_NEAREST"),
myDirtyFlag(true) myDirtyFlag(true)
@ -131,10 +132,6 @@ bool FrameBufferGL::loadFuncs(GLFunctionality functionality)
OGL_INIT(BufferData,void,glBufferData,(GLenum,GLsizei,const void*,GLenum)); OGL_INIT(BufferData,void,glBufferData,(GLenum,GLsizei,const void*,GLenum));
OGL_INIT(DeleteBuffers,void,glDeleteBuffers,(GLsizei, const GLuint*)); OGL_INIT(DeleteBuffers,void,glDeleteBuffers,(GLsizei, const GLuint*));
break; // kGL_VBO break; // kGL_VBO
case kGL_FBO:
return false; // TODO - implement this
break; // kGL_FBO
} }
} }
else else
@ -196,7 +193,6 @@ string FrameBufferGL::about() const
<< " Filter: " << myFilterParamName << endl << " Filter: " << myFilterParamName << endl
<< " Extensions: "; << " Extensions: ";
if(myVBOAvailable) out << "VBO "; if(myVBOAvailable) out << "VBO ";
if(myFBOAvailable) out << "FBO ";
out << endl; out << endl;
return out.str(); return out.str();
} }
@ -280,7 +276,6 @@ bool FrameBufferGL::setVidMode(VideoMode& mode)
myGLVersion = atof(version.substr(0, 3).c_str()); myGLVersion = atof(version.substr(0, 3).c_str());
myVBOAvailable = myOSystem->settings().getBool("gl_vbo") && loadFuncs(kGL_VBO); myVBOAvailable = myOSystem->settings().getBool("gl_vbo") && loadFuncs(kGL_VBO);
myFBOAvailable = false;
} }
else else
return false; return false;
@ -389,10 +384,29 @@ void FrameBufferGL::enablePhosphor(bool enable, int blend)
{ {
myUsePhosphor = enable; myUsePhosphor = enable;
myPhosphorBlend = blend; myPhosphorBlend = blend;
myFilterType = enable ? kPhosphor : kNone;
myRedrawEntireFrame = true; myRedrawEntireFrame = true;
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBufferGL::enableNTSC(bool enable)
{
if(enable)
myFilterType = kBlarggNTSC;
else
myFilterType = myUsePhosphor ? kPhosphor : kNone;
myRedrawEntireFrame = true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBufferGL::setTIAPalette(const uInt32* palette)
{
myTiaSurface->setTIAPalette(palette);
FrameBuffer::setTIAPalette(palette);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FBSurface* FrameBufferGL::createSurface(int w, int h, bool isBase) const FBSurface* FrameBufferGL::createSurface(int w, int h, bool isBase) const
{ {
@ -423,7 +437,4 @@ float FrameBufferGL::myGLVersion = 0.0;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool FrameBufferGL::myVBOAvailable = false; bool FrameBufferGL::myVBOAvailable = false;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool FrameBufferGL::myFBOAvailable = false;
#endif // DISPLAY_OPENGL #endif // DISPLAY_OPENGL

View File

@ -79,11 +79,6 @@ class FrameBufferGL : public FrameBuffer
*/ */
static float glVersion() { return myGLVersion; } static float glVersion() { return myGLVersion; }
/**
Indicates whether GL FBO functionality was detected and enabled.
*/
static bool isFBOAvailable() { return myFBOAvailable; }
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
// The following are derived from public methods in FrameBuffer.hxx // The following are derived from public methods in FrameBuffer.hxx
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
@ -92,6 +87,18 @@ class FrameBufferGL : public FrameBuffer
*/ */
void enablePhosphor(bool enable, int blend); void enablePhosphor(bool enable, int blend);
/**
Enable/disable NTSC filtering effects.
*/
void enableNTSC(bool enable);
/**
Set up the TIA/emulation palette for a screen of any depth > 8.
@param palette The array of colors
*/
void setTIAPalette(const uInt32* palette);
/** /**
This method is called to retrieve the R/G/B data from the given pixel. This method is called to retrieve the R/G/B data from the given pixel.
@ -185,10 +192,17 @@ class FrameBufferGL : public FrameBuffer
private: private:
enum GLFunctionality { enum GLFunctionality {
kGL_BASIC, kGL_VBO, kGL_FBO kGL_BASIC, kGL_VBO
}; };
bool loadFuncs(GLFunctionality functionality); bool loadFuncs(GLFunctionality functionality);
enum FilterType {
kNone,
kPhosphor,
kBlarggNTSC
};
FilterType myFilterType;
static uInt32 power_of_two(uInt32 input) static uInt32 power_of_two(uInt32 input)
{ {
uInt32 value = 1; uInt32 value = 1;
@ -223,8 +237,8 @@ class FrameBufferGL : public FrameBuffer
// Indicates the OpenGL version found (0 indicates none) // Indicates the OpenGL version found (0 indicates none)
static float myGLVersion; static float myGLVersion;
// Indicates whether Vertex/Frame Buffer Object functions were properly loaded // Indicates whether Vertex Buffer Objects (VBO) are available
static bool myVBOAvailable, myFBOAvailable; static bool myVBOAvailable;
// Structure containing dynamically-loaded OpenGL function pointers // Structure containing dynamically-loaded OpenGL function pointers
#define OGL_DECLARE(NAME,RET,FUNC,PARAMS) RET (APIENTRY* NAME) PARAMS #define OGL_DECLARE(NAME,RET,FUNC,PARAMS) RET (APIENTRY* NAME) PARAMS

View File

@ -58,6 +58,11 @@ class FrameBufferSoft : public FrameBuffer
*/ */
void enablePhosphor(bool enable, int blend); void enablePhosphor(bool enable, int blend);
/**
Enable/disable NTSC filtering effects (not supported in software mode).
*/
void enableNTSC(bool enable) { }
/** /**
This method is called to retrieve the R/G/B data from the given pixel. This method is called to retrieve the R/G/B data from the given pixel.

View File

@ -86,7 +86,7 @@ extern atari_ntsc_setup_t const atari_ntsc_svideo; /* color bleeding only */
extern atari_ntsc_setup_t const atari_ntsc_rgb; /* crisp image */ extern atari_ntsc_setup_t const atari_ntsc_rgb; /* crisp image */
extern atari_ntsc_setup_t const atari_ntsc_monochrome;/* desaturated + artifacts */ extern atari_ntsc_setup_t const atari_ntsc_monochrome;/* desaturated + artifacts */
enum { atari_ntsc_palette_size = 256 }; enum { atari_ntsc_palette_size = 128 };
/* Initializes and adjusts parameters. Can be called multiple times on the same /* Initializes and adjusts parameters. Can be called multiple times on the same
atari_ntsc_t object. Can pass NULL for either parameter. */ atari_ntsc_t object. Can pass NULL for either parameter. */

View File

@ -441,6 +441,24 @@ void Console::togglePhosphor()
myOSystem->frameBuffer().enablePhosphor(enable, blend); myOSystem->frameBuffer().enablePhosphor(enable, blend);
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Console::toggleNTSC()
{
ostringstream buf;
if(myOSystem->frameBuffer().type() == kDoubleBuffer)
{
bool state = !myOSystem->settings().getBool("ntsc_filter");
myOSystem->frameBuffer().enableNTSC(state);
myOSystem->settings().setBool("ntsc_filter", state);
buf << "NTSC filtering " << (state ? "enabled" : "disabled");
myOSystem->frameBuffer().showMessage(buf.str());
}
else
buf << "NTSC filtering not available";
myOSystem->frameBuffer().showMessage(buf.str());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Console::setProperties(const Properties& props) void Console::setProperties(const Properties& props)
{ {
@ -468,6 +486,7 @@ FBInitStatus Console::initializeVideo(bool full)
bool enable = myProperties.get(Display_Phosphor) == "YES"; bool enable = myProperties.get(Display_Phosphor) == "YES";
int blend = atoi(myProperties.get(Display_PPBlend).c_str()); int blend = atoi(myProperties.get(Display_PPBlend).c_str());
myOSystem->frameBuffer().enablePhosphor(enable, blend); myOSystem->frameBuffer().enablePhosphor(enable, blend);
myOSystem->frameBuffer().enableNTSC(myOSystem->settings().getBool("ntsc_filter"));
setPalette(myOSystem->settings().getString("palette")); setPalette(myOSystem->settings().getString("palette"));
// Set the correct framerate based on the format of the ROM // Set the correct framerate based on the format of the ROM

View File

@ -201,6 +201,11 @@ class Console : public Serializable
*/ */
void togglePhosphor(); void togglePhosphor();
/**
Toggles NTSC filtering effects.
*/
void toggleNTSC();
/** /**
Toggles the PAL color-loss effect. Toggles the PAL color-loss effect.
*/ */

View File

@ -375,6 +375,10 @@ void EventHandler::poll(uInt64 time)
myOSystem->console().changeYStart(-1); myOSystem->console().changeYStart(-1);
break; break;
case KBDK_f: // Alt-f toggles NTSC filtering
myOSystem->console().toggleNTSC();
break;
case KBDK_z: case KBDK_z:
if(mod & KMOD_SHIFT) if(mod & KMOD_SHIFT)
myOSystem->console().toggleP0Collision(); myOSystem->console().toggleP0Collision();

View File

@ -299,6 +299,11 @@ class FrameBuffer
*/ */
virtual void enablePhosphor(bool enable, int blend) = 0; virtual void enablePhosphor(bool enable, int blend) = 0;
/**
Enable/disable NTSC filtering effects.
*/
virtual void enableNTSC(bool enable) = 0;
/** /**
This method is called to retrieve the R/G/B data from the given pixel. This method is called to retrieve the R/G/B data from the given pixel.

View File

@ -59,6 +59,9 @@ Settings::Settings(OSystem* osystem)
setInternal("timing", "sleep"); setInternal("timing", "sleep");
setInternal("uimessages", "true"); setInternal("uimessages", "true");
// NTSC filtering options
setInternal("ntsc_filter", "false");
// Sound options // Sound options
setInternal("sound", "true"); setInternal("sound", "true");
setInternal("fragsize", "512"); setInternal("fragsize", "512");
@ -340,6 +343,8 @@ void Settings::usage()
<< " -gl_vsync <1|0> Enable 'synchronize to vertical blank interrupt'\n" << " -gl_vsync <1|0> Enable 'synchronize to vertical blank interrupt'\n"
<< " -gl_vbo <1|0> Enable 'vertex buffer objects'\n" << " -gl_vbo <1|0> Enable 'vertex buffer objects'\n"
<< endl << endl
<< " -ntsc_filter <1|0> Enable Blargg NTSC filtering effects\n"
<< endl
#endif #endif
<< " -tia_filter <filter> Use the specified filter in emulation mode\n" << " -tia_filter <filter> Use the specified filter in emulation mode\n"
<< " -fullscreen <1|0|-1> Use fullscreen mode (1 or 0), or disable switching to fullscreen entirely\n" << " -fullscreen <1|0|-1> Use fullscreen mode (1 or 0), or disable switching to fullscreen entirely\n"