TIA emulation is now more accurate wrt irregular scanline counts.

git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@2524 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
stephena 2012-06-04 15:52:56 +00:00
parent 2145c38087
commit 02ebafaf7d
7 changed files with 49 additions and 27 deletions

View File

@ -14,8 +14,13 @@
3.7 to 3.7.1: (xxxx xx, 2012)
* Improved TIA emulation with ROMs that have too few or too many
scanlines; the output is now blanked as on a real TV. Special thanks
to Omegamatrix of AtariAge for test ROMs in this area.
* Fixed several bugs in DPC+ bankswitching scheme, including ability to
load and save state files.
load and save state files. As well, ROMs now work correctly after
console format autodetection.
-Have fun!

View File

@ -199,6 +199,12 @@ void FBSurfaceTIA::update()
myFB.myDirtyFlag = true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceTIA::invalidate()
{
SDL_FillRect(myTexture, NULL, 0);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceTIA::free()
{

View File

@ -50,6 +50,7 @@ class FBSurfaceTIA : public FBSurface
uInt32 getHeight() const { return myImageH; }
void translateCoords(Int32& x, Int32& y) const;
void update();
void invalidate();
void free();
void reload();

View File

@ -332,6 +332,8 @@ bool FrameBufferGL::setVidMode(VideoMode& mode)
void FrameBufferGL::invalidate()
{
p_gl.Clear(GL_COLOR_BUFFER_BIT);
if(myTiaSurface)
myTiaSurface->invalidate();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -812,6 +812,12 @@ class FBSurface
*/
virtual void update() { }
/**
This method should be called to reset the surface to empty
pixels / colour black.
*/
virtual void invalidate() { }
/**
This method should be called to free any resources being used by
the surface.

View File

@ -46,7 +46,6 @@ TIA::TIA(Console& console, Sound& sound, Settings& settings)
: myConsole(console),
mySound(sound),
mySettings(settings),
myFrameWidth(160),
myFrameYStart(34),
myFrameHeight(210),
myMaximumNumberOfScanlines(262),
@ -194,8 +193,7 @@ void TIA::frameReset()
// Calculate color clock offsets for starting and stopping frame drawing
// Note that although we always start drawing at scanline zero, the
// framebuffer that is exposed outside the class actually starts at 'ystart'
myFramePointerOffset = myFrameWidth * myFrameYStart;
myStartDisplayOffset = 0;
myFramePointerOffset = 160 * myFrameYStart;
// NTSC screens will process at least 262 scanlines,
// while PAL will have at least 312
@ -209,7 +207,7 @@ void TIA::frameReset()
// Reasonable values to start and stop the current frame drawing
myClockWhenFrameStarted = mySystem->cycles() * 3;
myClockStartDisplay = myClockWhenFrameStarted + myStartDisplayOffset;
myClockStartDisplay = myClockWhenFrameStarted;
myClockStopDisplay = myClockWhenFrameStarted + myStopDisplayOffset;
myClockAtLastUpdate = myClockWhenFrameStarted;
myClocksToEndOfScanLine = 228;
@ -558,7 +556,7 @@ inline void TIA::startFrame()
// Setup clocks that'll be used for drawing this frame
myClockWhenFrameStarted = -1 * clocks;
myClockStartDisplay = myClockWhenFrameStarted + myStartDisplayOffset;
myClockStartDisplay = myClockWhenFrameStarted;
myClockStopDisplay = myClockWhenFrameStarted + myStopDisplayOffset;
myClockAtLastUpdate = myClockStartDisplay;
myClocksToEndOfScanLine = 228;
@ -622,22 +620,32 @@ inline void TIA::endFrame()
myStopDisplayOffset = offset;
}
// This is a bit of a hack for those ROMs which generate too many
// scanlines each frame, usually caused by VBLANK taking too long
// When this happens, the frame pointers sometimes get 'confused',
// and the framebuffer class doesn't properly overwrite data from
// the previous frame, causing graphical garbage
//
// We basically erase the entire contents of both buffers, making
// sure that they're also different from one another
// This will force the framebuffer class to completely re-render
// the screen
if(previousCount > myMaximumNumberOfScanlines &&
myScanlineCountForLastFrame <= myMaximumNumberOfScanlines)
// The following handle cases where scanlines either go too high or too
// low compared to the previous frame, in which case certain portions
// of the framebuffer are cleared to zero (black pixels)
// Due to the FrameBuffer class (potentially) doing dirty-rectangle
// updates, each internal buffer must be set slightly differently,
// otherwise they won't know anything has changed
// Hence, the front buffer is set to pixel 0, and the back to pixel 1
// Did we generate too many scanlines?
// (usually caused by VBLANK taking too long)
// If so, blank entire viewable area
if(myScanlineCountForLastFrame > 342 && previousCount <= 342)
{
memset(myCurrentFrameBuffer, 0, 160 * 320);
memset(myPreviousFrameBuffer, 1, 160 * 320);
}
// Did the number of scanlines decrease?
// If so, blank scanlines that weren't rendered this frame
else if(myScanlineCountForLastFrame < previousCount &&
myScanlineCountForLastFrame < 320 && previousCount < 320)
{
uInt32 offset = myScanlineCountForLastFrame * 160,
stride = (previousCount - myScanlineCountForLastFrame) * 160;
memset(myCurrentFrameBuffer + offset, 0, stride);
memset(myPreviousFrameBuffer + offset, 1, stride);
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -188,9 +188,9 @@ class TIA : public Device
/**
Answers the width and height of the frame buffer
*/
uInt32 width() const { return myFrameWidth; }
uInt32 height() const { return myFrameHeight; }
uInt32 ystart() const { return myFrameYStart; }
inline uInt32 width() const { return 160; }
inline uInt32 height() const { return myFrameHeight; }
inline uInt32 ystart() const { return myFrameYStart; }
/**
Changes the current Height/YStart properties.
@ -403,18 +403,12 @@ class TIA : public Device
// (this is used when loading state files with a 'partial' frame)
uInt32 myFramePointerClocks;
// Indicates the width of the visible scanline
uInt32 myFrameWidth;
// Indicated what scanline the frame should start being drawn at
uInt32 myFrameYStart;
// Indicates the height of the frame in scanlines
uInt32 myFrameHeight;
// Indicates offset in color clocks when display should begin
uInt32 myStartDisplayOffset;
// Indicates offset in color clocks when display should stop
uInt32 myStopDisplayOffset;