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) 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 * 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! -Have fun!

View File

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

View File

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

View File

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

View File

@ -812,6 +812,12 @@ class FBSurface
*/ */
virtual void update() { } 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 This method should be called to free any resources being used by
the surface. the surface.

View File

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