mirror of https://github.com/stella-emu/stella.git
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:
parent
2145c38087
commit
02ebafaf7d
|
@ -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!
|
||||||
|
|
||||||
|
|
|
@ -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()
|
||||||
{
|
{
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue