Support SHR video modes with a VidHD card (#997, PR #1004)

Support VidHD in slot 3 (via Config GUI or '-s3 vidhd') for SHR video modes only.
- AppleWin window is slightly enlarged when VidHD card is inserted.
Support IIgs 320x200 (and fill mode) and 640x200 video modes.
Debugger: add 'shr' command to view video
CUI: Allow user to specify width & height (for full-screen); and allow separate x,y scaling in full-screen mode.
This commit is contained in:
TomCh
2021-11-30 21:41:02 +00:00
committed by GitHub
parent 0b2104cc89
commit 443545b0f6
28 changed files with 653 additions and 113 deletions
+86 -7
View File
@@ -27,6 +27,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "Memory.h" // MemGetMainPtr(), MemGetAuxPtr(), MemGetAnnunciator()
#include "Interface.h" // GetFrameBuffer()
#include "RGBMonitor.h"
#include "VidHD.h"
#include "NTSC_CharSet.h"
@@ -100,11 +101,14 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#define VIDEO_SCANNER_HORZ_START 25 // first displayable horz scanner index
#define VIDEO_SCANNER_Y_MIXED 160 // num scanlins for mixed graphics + text
#define VIDEO_SCANNER_Y_DISPLAY 192 // max displayable scanlines
#define VIDEO_SCANNER_Y_DISPLAY_IIGS 200
// these are initialized in NTSC_VideoInit
// These 3 vars are initialized in NTSC_VideoInit()
static bgra_t* g_pVideoAddress = 0;
static bgra_t *g_pScanLines[VIDEO_SCANNER_Y_DISPLAY*2]; // To maintain the 280x192 aspect ratio for 560px width, we double every scan line -> 560x384
static UINT g_kFrameBufferWidth;
// To maintain the 280x192 aspect ratio for 560px width, we double every scan line -> 560x384
// NB. For IIgs SHR, the 320x200 is again doubled (to 640x400), but this gives a ~16:9 ratio, when 4:3 is probably required (ie. stretch height from 200 to 240)
static bgra_t* g_pScanLines[VIDEO_SCANNER_Y_DISPLAY_IIGS * 2];
static UINT g_kFrameBufferWidth = 0;
static unsigned short (*g_pHorzClockOffset)[VIDEO_SCANNER_MAX_HORZ] = 0;
@@ -348,6 +352,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
static void updateScreenText80RGB ( long cycles6502 );
static void updateScreenDoubleHires80Simplified(long cycles6502);
static void updateScreenDoubleHires80RGB(long cycles6502);
static void updateScreenSHR(long cycles6502);
//===========================================================================
static void set_csbits()
@@ -712,13 +717,37 @@ inline void updateVideoScannerHorzEOL()
}
}
inline void updateVideoScannerHorzEOL_SHR()
{
if (VIDEO_SCANNER_MAX_HORZ == ++g_nVideoClockHorz)
{
g_nVideoClockHorz = 0;
if (++g_nVideoClockVert == g_videoScannerMaxVert)
{
g_nVideoClockVert = 0;
}
if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY_IIGS)
{
updateVideoScannerAddress();
}
}
}
//===========================================================================
inline void updateVideoScannerAddress()
{
if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED && GetVideo().GetVideoRefreshRate() == VR_50HZ) // GH#763
g_nColorBurstPixels = 0; // instantaneously kill color-burst!
g_pVideoAddress = g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY ? g_pScanLines[2*g_nVideoClockVert] : g_pScanLines[0];
if (g_pFuncUpdateGraphicsScreen == updateScreenSHR)
{
g_pVideoAddress = g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY_IIGS ? g_pScanLines[2 * g_nVideoClockVert] : g_pScanLines[0];
return;
}
g_pVideoAddress = g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY ? g_pScanLines[2 * g_nVideoClockVert] : g_pScanLines[0];
// Adjust, as these video styles have 2x 14M pixels of pre-render
// NB. For VT_COLOR_MONITOR_NTSC, also check color-burst so that TEXT and MIXED(HGR+TEXT) render the TEXT at the same offset (GH#341)
@@ -740,6 +769,9 @@ inline void updateVideoScannerAddress()
g_pVideoAddress -= 1;
}
// Centre the older //e video modes when running with a VidHD
g_pVideoAddress += GetVideo().GetFrameBufferCentringValue();
g_nColorPhaseNTSC = INITIAL_COLOR_PHASE;
g_nLastColumnPixelNTSC = 0;
g_nSignalBitsNTSC = 0;
@@ -760,7 +792,6 @@ INLINE uint16_t getVideoScannerAddressHGR()
APPLE_IIE_HORZ_CLOCK_OFFSET[g_nVideoClockVert/64][g_nVideoClockHorz] + (g_nHiresPage * 0x2000));
}
// Non-Inline _________________________________________________________
// Build the 4 phase chroma lookup table
@@ -1709,6 +1740,42 @@ void updateScreenText80RGB(long cycles6502)
}
}
//===========================================================================
void updateScreenSHR(long cycles6502)
{
for (; cycles6502 > 0; --cycles6502)
{
// 2 pixels per byte in 320-pixel mode = 160 bytes/scanline
// 4 pixels per byte in 640-pixel mode = 160 bytes/scanline
const UINT kBytesPerScanline = 160;
const UINT kBytesPerCycle = 4;
uint16_t addr = 0x2000 + kBytesPerScanline * g_nVideoClockVert + kBytesPerCycle * (g_nVideoClockHorz - VIDEO_SCANNER_HORZ_START);
if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY_IIGS)
{
if (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_START)
{
uint32_t* pAux = (uint32_t*) MemGetAuxPtr(addr); // 8 pixels (320 mode) / 16 pixels (640 mode)
uint32_t a = pAux[0];
uint8_t* pControl = MemGetAuxPtr(0x9D00 + g_nVideoClockVert); // scan-line control byte
uint8_t c = pControl[0];
bool is640Mode = c & 0x80;
bool isColorFillMode = c & 0x20;
UINT paletteSelectCode = c & 0xf;
const UINT kColorsPerPalette = 16;
const UINT kColorSize = 2;
uint16_t addrPalette = 0x9E00 + paletteSelectCode * kColorsPerPalette * kColorSize;
VidHDCard::UpdateSHRCell(is640Mode, isColorFillMode, addrPalette, g_pVideoAddress, a);
g_pVideoAddress += 16;
}
}
updateVideoScannerHorzEOL_SHR();
}
}
// Functions (Public) _____________________________________________________________________________
//===========================================================================
@@ -1803,6 +1870,19 @@ void NTSC_SetVideoTextMode( int cols )
//===========================================================================
void NTSC_SetVideoMode( uint32_t uVideoModeFlags, bool bDelay/*=false*/ )
{
if (uVideoModeFlags & VF_SHR)
{
g_pFuncUpdateGraphicsScreen = updateScreenSHR;
g_pFuncUpdateTextScreen = updateScreenSHR;
return;
}
if (g_pFuncUpdateGraphicsScreen == updateScreenSHR && !(uVideoModeFlags & VF_SHR))
{
// Was SHR mode, so clear the framebuffer to remove any SHR residue in the borders
GetVideo().ClearFrameBuffer();
}
if (bDelay && !g_bFullSpeed)
{
// (GH#670) NB. if g_bFullSpeed then NTSC_VideoUpdateCycles() won't be called on the next 6502 opcode.
@@ -1812,7 +1892,6 @@ void NTSC_SetVideoMode( uint32_t uVideoModeFlags, bool bDelay/*=false*/ )
return;
}
g_nVideoMixed = uVideoModeFlags & VF_MIXED;
g_nVideoCharSet = GetVideo().VideoGetSWAltCharSet() ? 1 : 0;
@@ -2104,7 +2183,7 @@ void NTSC_VideoInit( uint8_t* pFramebuffer ) // wsVideoInit
g_kFrameBufferWidth = GetVideo().GetFrameBufferWidth();
for (int y = 0; y < (VIDEO_SCANNER_Y_DISPLAY*2); y++)
for (int y = 0; y < (VIDEO_SCANNER_Y_DISPLAY_IIGS*2); y++)
{
uint32_t offset = sizeof(bgra_t) * GetVideo().GetFrameBufferWidth()
* ((GetVideo().GetFrameBufferHeight() - 1) - y - GetVideo().GetFrameBufferBorderHeight())