|
|
/******************************************************************************\
* * Copyright (c) 1996-1997 Microsoft Corporation. * Copyright (c) 1996-1997 Cirrus Logic, Inc. * * Module Name: * * D D R A W . C * * * Implements all the DirectDraw components for the driver. * * * $Log: S:/projects/drivers/ntsrc/display/ddraw.c_v $ * * Rev 1.14 07 Apr 1997 11:37:02 PLCHU * * * Rev 1.13 Apr 03 1997 15:38:44 unknown * * * * Rev 1.10 Jan 14 1997 15:15:12 unknown * Add new double clock detecting method. * * Rev 1.8 Jan 08 1997 11:23:34 unknown * Add 2x clock support and double scan line counter support * * Rev 1.7 Dec 17 1996 18:31:12 unknown * Update the bandwidth equation again. * * Rev 1.6 Dec 13 1996 12:15:04 unknown * update bandwith equation. * * Rev 1.5 Dec 12 1996 11:09:52 unknown * Add double scan line counter support * * Rev 1.5 Dec 12 1996 11:02:12 unknown * Add double scan line counter support. * * Rev 1.5 Nov 26 1996 14:29:58 unknown * Turn off the video window before the moving and then turn it on. * * Rev 1.4 Nov 25 1996 14:39:32 unknown * Fixed AVI file playback and 16bpp transparent Blt bugs. * * Rev 1.4 Nov 18 1996 13:58:58 JACKIEC * * * Rev 1.3 Nov 07 1996 16:47:56 unknown * * * Rev 1.2 Oct 16 1996 14:41:04 unknown * NT 3.51 does not have DDRAW support, So turn off overlay.h in NT 3.51 * * Rev 1.1 Oct 10 1996 15:36:28 unknown * * * Rev 1.10 12 Aug 1996 16:51:04 frido * Added NT 3.5x/4.0 auto detection. * * Rev 1.9 06 Aug 1996 18:37:12 frido * DirectDraw works! Video mapping is the key! * * Rev 1.8 24 Jul 1996 14:38:44 frido * Cleaned up font cache after DirectDraw is done. * * Rev 1.7 24 Jul 1996 14:30:04 frido * Added a call to destroy all cached fonts to make more room. * * Rev 1.6 20 Jul 1996 00:00:44 frido * Fixed filling of DirectDraw in 24-bpp. * Changed off-screen alignment to 4 bytes. * Added compile switch to manage DirectDraw support in 24-bpp. * * Rev 1.5 16 Jul 1996 18:55:22 frido * Fixed DirectDraw in 24-bpp mode. * * Rev 1.4 15 Jul 1996 18:03:22 frido * Changed CP_MM_DST_ADDR to CP_MM_DST_ADDR_ABS. * * Rev 1.3 15 Jul 1996 10:58:28 frido * Changed back to S3 base. * * Rev 1.1 09 Jul 1996 14:52:30 frido * Only support chips 5436 and 5446. * * Rev 1.0 03 Jul 1996 13:53:02 frido * Ported from S3 DirectDraw code. * * jl01 10-08-96 Do Transparent BLT w/o Solid Fill. Refer to PDRs#5511/6817. * * chu01 11-17-96 For 24-bpp, aligned destination boundary/size values are * wrong. Refer to PDR#7312. * * sge01 11-19-96 Write CR37 at last For 5480. * * * sge02 11-21-96 We have to set the Color Expand Width even in * non-expand transparency mode. * * * sge03 12-04-96 Add double scan line counter support . * * sge04 12-13-96 Change bandwidth for 5446BE and later chips. * * sge05 01-07-97 Use dword align for double clock mode. * * chu02 01-08-97 Disable ActiveX/Active Movie Player for interlaced modes. * Refer to PDR#7312, 7866. * * jc01 10-18-96 Port Microsoft recent change. * tao1 10-21-96 Added direct draw support for CL-GD7555. * myf21 11-21-96 Change CAPS_IS_7555 to check ppdev->ulChipID * * sge06 01-27-97 Extend VCLK Denominator to 7 bits from 5 bits. * sge07 02-13-97 Use replication when in 1280x1024x8 mode. * myf31 02-24-97 Fixed enable HW Video, panning scrolling enable,screen move * video window have follow moving * chu03 03-26-97 Bandwidth eqution for the CL-GD5480. * myf33 :03-31-97 : Fixed PDR #8709, read true VCLK in getVCLK() * & panning scrolling enable, support HW Video * chu04 04-02-97 No matterwhat color depth is, always turn on COLORKEY and * SRCBLT in the DD/DD colorkey capabilities for the 5480. * \******************************************************************************/
#include "PreComp.h"
#if DIRECTDRAW
#include "overlay.h"
LONG MIN_OLAY_WIDTH = 4;
//#define ONLY54x6 // Comment this line out if DirectDraw should be 'generic'
// The next flag controls DirectDraw support in 24-bpp.
#define DIRECTX_24 2 // 0 - no support
// 1 - blt support, no heap (flip)
// 2 - full support
//
// Some handy macros.
//
#define BLT_BUSY(ppdev, pjBase) (CP_MM_ACL_STAT(ppdev, pjBase) & 0x01)
#ifdef ONLY54x6
#define BLT_READY(ppdev, pjBase) (!(CP_MM_ACL_STAT(ppdev, pjBase) & 0x10))
#else
#define BLT_READY(ppdev, pjBase) (!(CP_MM_ACL_STAT(ppdev, pjBase) & \
((ppdev->flCaps & CAPS_AUTOSTART) ? 0x10 : 0x01))) #endif
#define NUM_VBLANKS_TO_MEASURE 1
#define NUM_MEASUREMENTS_TO_TAKE 8
/******************************Public*Routine******************************\
* * DWORD dwGetPaletteEntry * \**************************************************************************/
DWORD dwGetPaletteEntry( PDEV* ppdev, DWORD iIndex) { BYTE* pjPorts; DWORD dwRed; DWORD dwGreen; DWORD dwBlue;
pjPorts = ppdev->pjPorts;
CP_OUT_BYTE(pjPorts, DAC_PEL_READ_ADDR, iIndex);
dwRed = CP_IN_BYTE(pjPorts, DAC_PEL_DATA); dwGreen = CP_IN_BYTE(pjPorts, DAC_PEL_DATA); dwBlue = CP_IN_BYTE(pjPorts, DAC_PEL_DATA);
return((dwRed << 16) | (dwGreen << 8) | (dwBlue)); }
/******************************Public*Routine******************************\
* VOID vGetDisplayDuration * * Get the length, in EngQueryPerformanceCounter() ticks, of a refresh cycle. * * If we could trust the miniport to return back and accurate value for * the refresh rate, we could use that. Unfortunately, our miniport doesn't * ensure that it's an accurate value. * \**************************************************************************/
VOID vGetDisplayDuration( PDEV* ppdev) { BYTE* pjPorts; DWORD dwTemp; LONG i, j; LONGLONG li; LONGLONG liMin; LONGLONG aliMeasurement[NUM_MEASUREMENTS_TO_TAKE + 1];
pjPorts = ppdev->pjPorts;
memset(&ppdev->flipRecord, 0, sizeof(ppdev->flipRecord));
// Warm up EngQUeryPerformanceCounter to make sure it's in the working set.
EngQueryPerformanceCounter(&li);
// Unfortunately, since NT is a proper multitasking system, we can't just
// disable interrupts to take an accurate reading. We also can't do anything
// so goofy as dynamically change our thread's priority to real-time.
//
// So we just do a bunch of short measurements and take the minimum.
//
// It would be 'okay' if we got a result that's longer than the actual
// VBlank cycle time -- nothing bad would happen except that the app would
// run a little slower. We don't want to get a result that's shorter than
// the actual VBlank cycle time -- that could cause us to start drawing over
// a frame before the Flip has occured.
while (CP_IN_BYTE(pjPorts, STATUS_1) & VBLANK_ACTIVE) ; while (!(CP_IN_BYTE(pjPorts, STATUS_1) & VBLANK_ACTIVE)) ;
for (i = 0; i < NUM_MEASUREMENTS_TO_TAKE; i++) { // We're at the start of the VBlank active cycle!
EngQueryPerformanceCounter(&aliMeasurement[i]);
// Okay, so life in a multi-tasking environment isn't all that simple.
// What if we had taken a context switch just before the above
// EngQueryPerformanceCounter call, and now were half way through the
// VBlank inactive cycle? Then we would measure only half a VBlank
// cycle, which is obviously bad. The worst thing we can do is get a
// time shorter than the actual VBlank cycle time.
//
// So we solve this by making sure we're in the VBlank active time
// before and after we query the time. If it's not, we'll sync up to the
// next VBlank (it's okay to measure this period -- it will be
// guaranteed to be longer than the VBlank cycle and will likely be
// thrown out when we select the minimum sample). There's a chance that
// we'll take a context switch and return just before the end of the
// active VBlank time -- meaning that the actual measured time would be
// less than the true amount -- but since the VBlank is active less than
// 1% of the time, this means that we would have a maximum of 1% error
// approximately 1% of the times we take a context switch. An acceptable
// risk.
//
// This next line will cause us wait if we're no longer in the VBlank
// active cycle as we should be at this point.
while (!(CP_IN_BYTE(pjPorts, STATUS_1) & VBLANK_ACTIVE)) ;
for (j = 0; j < NUM_VBLANKS_TO_MEASURE; j++) { while (CP_IN_BYTE(pjPorts, STATUS_1) & VBLANK_ACTIVE) ; while (!(CP_IN_BYTE(pjPorts, STATUS_1) & VBLANK_ACTIVE)) ; } }
EngQueryPerformanceCounter(&aliMeasurement[NUM_MEASUREMENTS_TO_TAKE]);
// Use the minimum.
liMin = aliMeasurement[1] - aliMeasurement[0];
DISPDBG((2, "Refresh count: %li - %li", 1, (ULONG) liMin));
for (i = 2; i <= NUM_MEASUREMENTS_TO_TAKE; i++) { li = aliMeasurement[i] - aliMeasurement[i - 1];
DISPDBG((2, " %li - %li", i, (ULONG) li));
if (li < liMin) { liMin = li; } }
// Round the result:
ppdev->flipRecord.liFlipDuration = (DWORD) (liMin + (NUM_VBLANKS_TO_MEASURE / 2)) / NUM_VBLANKS_TO_MEASURE;
DISPDBG((2, "Frequency %li.%03li Hz", (ULONG) (EngQueryPerformanceFrequency(&li), li / ppdev->flipRecord.liFlipDuration), (ULONG) (EngQueryPerformanceFrequency(&li), ((li * 1000) / ppdev->flipRecord.liFlipDuration) % 1000)));
ppdev->flipRecord.liFlipTime = aliMeasurement[NUM_MEASUREMENTS_TO_TAKE]; ppdev->flipRecord.bFlipFlag = FALSE; ppdev->flipRecord.fpFlipFrom = 0;
// sge
// Get the line on which the VSYNC occurs
CP_OUT_BYTE(pjPorts, CRTC_INDEX, 0x7); dwTemp = (DWORD)CP_IN_BYTE(pjPorts, CRTC_DATA); ppdev->dwVsyncLine = ((dwTemp & 0x80) << 2); ppdev->dwVsyncLine |= ((dwTemp & 0x04) << 6); CP_OUT_BYTE(pjPorts, CRTC_INDEX, 0x10); ppdev->dwVsyncLine |= CP_IN_BYTE(pjPorts, CRTC_DATA); }
/******************************Public*Routine******************************\
* HRESULT dwUpdateFlipStatus * * Checks and sees if the most recent flip has occurred. * \**************************************************************************/
HRESULT UpdateFlipStatus(PDEV* ppdev, FLATPTR fpVidMem) { BYTE* pjPorts; LONGLONG liTime;
pjPorts = ppdev->pjPorts;
if ((ppdev->flipRecord.bFlipFlag) && //#jc01 ((fpVidMem == 0) || (fpVidMem == ppdev->flipRecord.fpFlipFrom)))
((fpVidMem == 0xffffffff) || (fpVidMem == ppdev->flipRecord.fpFlipFrom))) //#jc01
{ #if 0 // sge use scanline
if (CP_IN_BYTE(pjPorts, STATUS_1) & VBLANK_ACTIVE) { if (ppdev->flipRecord.bWasEverInDisplay) { ppdev->flipRecord.bHaveEverCrossedVBlank = TRUE; } } else if (!(CP_IN_BYTE(pjPorts, STATUS_1) & DISPLAY_MODE_INACTIVE)) { if( ppdev->flipRecord.bHaveEverCrossedVBlank ) { ppdev->flipRecord.bFlipFlag = FALSE; return(DD_OK); } ppdev->flipRecord.bWasEverInDisplay = TRUE; }
EngQueryPerformanceCounter(&liTime);
if (liTime - ppdev->flipRecord.liFlipTime <= ppdev->flipRecord.liFlipDuration) { return(DDERR_WASSTILLDRAWING); } #else
/*
* if we aren't in the vertical retrace, we can use the scanline * to help decide on what to do */ if( !(CP_IN_BYTE(pjPorts, STATUS_1) & VBLANK_ACTIVE) ) { if( ppdev->flipRecord.bHaveEverCrossedVBlank == FALSE ) { ppdev->flipRecord.bWasEverInDisplay = TRUE; if( GetCurrentVLine(ppdev) >= ppdev->flipRecord.dwFlipScanLine ) { EngQueryPerformanceCounter(&liTime);
if (liTime - ppdev->flipRecord.liFlipTime <= ppdev->flipRecord.liFlipDuration) { return(DDERR_WASSTILLDRAWING); } } } } /*
* in the vertical retrace, scanline is useless */ else { if( ppdev->flipRecord.bWasEverInDisplay ) { ppdev->flipRecord.bHaveEverCrossedVBlank = TRUE; // return DD_OK;
} EngQueryPerformanceCounter(&liTime); if (liTime - ppdev->flipRecord.liFlipTime <= ppdev->flipRecord.liFlipDuration) { return(DDERR_WASSTILLDRAWING); } } #endif // endif use scanline
ppdev->flipRecord.bFlipFlag = FALSE; }
return(DD_OK); }
/******************************Public*Routine******************************\
* DWORD DdBlt * \**************************************************************************/
DWORD DdBlt( PDD_BLTDATA lpBlt) { PDD_SURFACE_GLOBAL srcSurf; PDD_SURFACE_GLOBAL dstSurf; PDEV* ppdev; BYTE* pjBase; DWORD dstOffset; DWORD dstPitch; DWORD dstX, dstY; DWORD dwFlags; DWORD width, height; DWORD srcOffset; DWORD srcPitch; DWORD srcX, srcY; ULONG ulBltCmd; DWORD xExt, yExt; DWORD xDiff, yDiff;
ppdev = lpBlt->lpDD->dhpdev; pjBase = ppdev->pjBase; dstSurf = lpBlt->lpDDDestSurface->lpGbl;
// Is a flip in progress?
if (UpdateFlipStatus(ppdev, dstSurf->fpVidMem) != DD_OK) { lpBlt->ddRVal = DDERR_WASSTILLDRAWING; return(DDHAL_DRIVER_HANDLED); }
dwFlags = lpBlt->dwFlags;
if (dwFlags & DDBLT_ASYNC) { // If async, then only work if we won't have to wait on the accelerator
// to start the command.
if (!BLT_READY(ppdev, pjBase)) { lpBlt->ddRVal = DDERR_WASSTILLDRAWING; return(DDHAL_DRIVER_HANDLED); } }
DISPDBG((2, "DdBlt Entered"));
// Calculate destination parameters.
dstX = lpBlt->rDest.left; dstY = lpBlt->rDest.top; width = PELS_TO_BYTES(lpBlt->rDest.right - dstX) - 1; height = (lpBlt->rDest.bottom - dstY) - 1; dstPitch = dstSurf->lPitch; dstOffset = (DWORD)(dstSurf->fpVidMem + PELS_TO_BYTES(dstX) + (dstY * dstPitch));
// Color fill?
if (dwFlags & DDBLT_COLORFILL) { ULONG ulBltMode = ENABLE_COLOR_EXPAND | ENABLE_8x8_PATTERN_COPY | ppdev->jModeColor;
// Wait for the accelerator.
while (!BLT_READY(ppdev, pjBase)) ;
// Program bitblt engine.
CP_MM_ROP(ppdev, pjBase, HW_P); CP_MM_DST_Y_OFFSET(ppdev, pjBase, dstPitch); CP_MM_BLT_MODE(ppdev, pjBase, ulBltMode); CP_MM_FG_COLOR(ppdev, pjBase, lpBlt->bltFX.dwFillColor); if (ppdev->flCaps & CAPS_AUTOSTART) { CP_MM_BLT_EXT_MODE(ppdev, pjBase, ENABLE_SOLID_FILL); } else { CP_MM_SRC_ADDR(ppdev, pjBase, ppdev->ulSolidColorOffset); } CP_MM_XCNT(ppdev, pjBase, width); CP_MM_YCNT(ppdev, pjBase, height); CP_MM_DST_ADDR_ABS(ppdev, pjBase, dstOffset); CP_MM_START_BLT(ppdev, pjBase);
lpBlt->ddRVal = DD_OK; return(DDHAL_DRIVER_HANDLED); }
// We specified with Our ddCaps.dwCaps that we handle a limited number of
// commands, and by this point in our routine we've handled everything
// except DDBLT_ROP. DirectDraw and GDI shouldn't pass us anything else;
// we'll assert on debug builds to prove this.
ASSERTDD((dwFlags & DDBLT_ROP) && (lpBlt->lpDDSrcSurface), "Expected dwFlags commands of only DDBLT_ASYNC and DDBLT_COLORFILL");
// Get offset, width, and height for source.
srcSurf = lpBlt->lpDDSrcSurface->lpGbl; srcX = lpBlt->rSrc.left; srcY = lpBlt->rSrc.top; srcPitch = srcSurf->lPitch; srcOffset = (DWORD)(srcSurf->fpVidMem + PELS_TO_BYTES(srcX) + (srcY * srcPitch));
/*
* Account for PackJR. If the start and the width are not 4 pixel * aligned, we need to BLT this by hand. Otherwsie, if they think * they are BLTing 16 bit data, we must adjust the parameters now. * * This is also a good place to check that YUV BLTs are 2 pixel * aligned. */ if (lpBlt->lpDDDestSurface->dwReserved1 & (OVERLAY_FLG_PACKJR | OVERLAY_FLG_YUV422)) {
ASSERTDD(0, "Who will get here?"); #if 0 // software blt
/*
* Check YUV first. We can fail this if incorrect because the client * should know better (since they are explicitly use YUV). */ if ((lpBlt->lpDDDestSurface->dwReserved1 & OVERLAY_FLG_YUV422) && ((lpBlt->rSrc.left & 0x01) != (lpBlt->rDest.left & 0x01))) { lpBlt->ddRVal = DDERR_XALIGN; return (DDHAL_DRIVER_HANDLED); }
/*
* If PackJR is wrong, we must make this work ourselves because we * may be converting to this w/o the client knowing. */ else if (lpBlt->lpDDDestSurface->dwReserved1 & OVERLAY_FLG_PACKJR) { if (dwFlags & DDBLT_COLORFILL) { lpBlt->ddRVal = DDERR_XALIGN; return (DDHAL_DRIVER_HANDLED); }
if ((lpBlt->rSrc.left & 0x03) || (lpBlt->rDest.left & 0x03)) { /*
* The start doesn't align - we have to do this the slow way */ PackJRBltAlign ((LPBYTE) ppdev->pjScreen + srcOffset, (LPBYTE) ppdev->pjScreen + dstOffset, lpBlt->rDest.right - lpBlt->rDest.left, lpBlt->rDest.bottom - lpBlt->rDest.top, srcPitch, dstPitch);
lpBlt->ddRVal = DD_OK; return (DDHAL_DRIVER_HANDLED); } else if (lpBlt->rSrc.right & 0x03) { /*
* The end doesn't align - we will do the BLT as normal, but * write the last pixels the slow way */ if (lpBlt->lpDDDestSurface->dwReserved1 & (OVERLAY_FLG_CONVERT_PACKJR | OVERLAY_FLG_MUST_RASTER)) { srcPitch >>= 1; srcOffset = srcSurf->fpVidMem + PELS_TO_BYTES(srcX) + (srcY * srcPitch); dstPitch >>= 1; dstOffset = dstSurf->fpVidMem + PELS_TO_BYTES(dstX) + (dstY * dstPitch); } width = ((WORD)lpBlt->rSrc.right & ~0x03) - (WORD)lpBlt->rSrc.left; PackJRBltAlignEnd ((LPBYTE) ppdev->pjScreen + srcOffset + width, (LPBYTE) ppdev->pjScreen + dstOffset + width, lpBlt->rSrc.right & 0x03, lpBlt->rDest.bottom - lpBlt->rDest.top, srcPitch, dstPitch); } else if (lpBlt->lpDDDestSurface->dwReserved1 & (OVERLAY_FLG_CONVERT_PACKJR | OVERLAY_FLG_MUST_RASTER)) { /*
* Everything aligns, but we have to re-calculate the start * address and the pitch. */ srcPitch >>= 1; srcOffset = srcSurf->fpVidMem + PELS_TO_BYTES(srcX) + (srcY * srcPitch); dstPitch >>= 1; dstOffset = dstSurf->fpVidMem + PELS_TO_BYTES(dstX) + (dstY * dstPitch); width >>= 1; } } #endif
}
if ((dstSurf == srcSurf) && (srcOffset < dstOffset)) { // Okay, we have to do the blt bottom-to-top, right-to-left.
ulBltCmd = DIR_BTRL; ; srcOffset += width + (srcPitch * height); dstOffset += width + (dstPitch * height); } else { // Okay, we have to do the blt top-to-bottom, left-to-right.
ulBltCmd = DIR_TBLR; }
// Wait for the accelerator.
while (!BLT_READY(ppdev, pjBase)) ;
//
// What about source color key
//
ASSERTDD((!(dwFlags & DDBLT_KEYSRC)), "Do not expected source color key");
if (dwFlags & DDBLT_KEYSRCOVERRIDE) { ULONG ulColor;
//
// sge02
//
ulBltCmd |= ENABLE_TRANSPARENCY_COMPARE | ppdev->jModeColor; ulColor = lpBlt->bltFX.ddckSrcColorkey.dwColorSpaceLowValue; if (ppdev->cBpp == 1) { ulColor |= ulColor << 8; } CP_WRITE_USHORT(pjBase, MM_BLT_COLOR_KEY, ulColor); }
if ( (ulBltCmd & DIR_BTRL) && (ulBltCmd & ENABLE_TRANSPARENCY_COMPARE) && (ppdev->cBpp > 1) ) { ulBltCmd &= ~DIR_BTRL; xExt = lpBlt->rDest.right - lpBlt->rDest.left; yExt = lpBlt->rDest.bottom - lpBlt->rDest.top; xDiff = dstX - srcX; yDiff = dstY - srcY;
if (yDiff == 0) { srcOffset -= srcPitch * height - 1; dstOffset -= dstPitch * height - 1;
while (xExt) { width = PELS_TO_BYTES(min(xDiff, xExt)); srcOffset -= width; dstOffset -= width;
while (!BLT_READY(ppdev, pjBase)) ;
CP_MM_ROP(ppdev, pjBase, CL_SRC_COPY); CP_MM_BLT_MODE(ppdev, pjBase, ulBltCmd); CP_MM_BLT_EXT_MODE(ppdev, pjBase, 0); CP_MM_SRC_Y_OFFSET(ppdev, pjBase, srcPitch); CP_MM_DST_Y_OFFSET(ppdev, pjBase, dstPitch); CP_MM_XCNT(ppdev, pjBase, width - 1); CP_MM_YCNT(ppdev, pjBase, height); CP_MM_SRC_ADDR(ppdev, pjBase, srcOffset); CP_MM_DST_ADDR_ABS(ppdev, pjBase, dstOffset); CP_MM_START_BLT(ppdev, pjBase);
xExt -= min(xDiff, xExt); } } else { srcOffset -= width - srcPitch; dstOffset -= width - dstPitch;
while (yExt) { height = min(yDiff, yExt); srcOffset -= height * srcPitch; dstOffset -= height * dstPitch;
while (!BLT_READY(ppdev, pjBase)) ;
CP_MM_ROP(ppdev, pjBase, CL_SRC_COPY); CP_MM_BLT_MODE(ppdev, pjBase, ulBltCmd); CP_MM_BLT_EXT_MODE(ppdev, pjBase, 0); CP_MM_SRC_Y_OFFSET(ppdev, pjBase, srcPitch); CP_MM_DST_Y_OFFSET(ppdev, pjBase, dstPitch); CP_MM_XCNT(ppdev, pjBase, width); CP_MM_YCNT(ppdev, pjBase, height - 1); CP_MM_SRC_ADDR(ppdev, pjBase, srcOffset); CP_MM_DST_ADDR_ABS(ppdev, pjBase, dstOffset); CP_MM_START_BLT(ppdev, pjBase);
yExt -= min(yDiff, yExt); } } }
else { CP_MM_ROP(ppdev, pjBase, CL_SRC_COPY); CP_MM_BLT_MODE(ppdev, pjBase, ulBltCmd); CP_MM_BLT_EXT_MODE(ppdev, pjBase, 0); // jl01
CP_MM_SRC_Y_OFFSET(ppdev, pjBase, srcPitch); CP_MM_DST_Y_OFFSET(ppdev, pjBase, dstPitch); CP_MM_XCNT(ppdev, pjBase, width); CP_MM_YCNT(ppdev, pjBase, height); CP_MM_SRC_ADDR(ppdev, pjBase, srcOffset); CP_MM_DST_ADDR_ABS(ppdev, pjBase, dstOffset); CP_MM_START_BLT(ppdev, pjBase); }
lpBlt->ddRVal = DD_OK; return(DDHAL_DRIVER_HANDLED); }
/******************************Public*Routine******************************\
* DWORD DdFlip * \**************************************************************************/
DWORD DdFlip( PDD_FLIPDATA lpFlip) { PDEV* ppdev; BYTE* pjPorts; ULONG ulMemoryOffset; ULONG ulLowOffset; ULONG ulMiddleOffset; ULONG ulHighOffset1, ulHighOffset2;
ppdev = lpFlip->lpDD->dhpdev; pjPorts = ppdev->pjPorts;
DISPDBG((2, "DdFlip: %d x %d at %08x(%d, %d) Pitch=%d", lpFlip->lpSurfTarg->lpGbl->wWidth, lpFlip->lpSurfTarg->lpGbl->wHeight, lpFlip->lpSurfTarg->lpGbl->fpVidMem, lpFlip->lpSurfTarg->lpGbl->xHint, lpFlip->lpSurfTarg->lpGbl->yHint, lpFlip->lpSurfTarg->lpGbl->lPitch));
// Is the current flip still in progress?
//
// Don't want a flip to work until after the last flip is done, so we ask
// for the general flip status and ignore the vmem.
//#jc01 if ((UpdateFlipStatus(ppdev, 0) != DD_OK) ||
if ((UpdateFlipStatus(ppdev, 0xffffffff) != DD_OK) || /* #jc01 */ (BLT_BUSY(ppdev, ppdev->pjBase))) { lpFlip->ddRVal = DDERR_WASSTILLDRAWING; return(DDHAL_DRIVER_HANDLED); }
ulMemoryOffset = (ULONG)(lpFlip->lpSurfTarg->lpGbl->fpVidMem); // Make sure that the border/blanking period isn't active; wait if it is. We
// could return DDERR_WASSTILLDRAWING in this case, but that will increase
// the odds that we can't flip the next time.
while (CP_IN_BYTE(pjPorts, STATUS_1) & DISPLAY_MODE_INACTIVE) ; DISPDBG((2, "DdFlip Entered")); #if 1 // OVERLAY #sge
if (lpFlip->lpSurfCurr->ddsCaps.dwCaps & DDSCAPS_OVERLAY) { DWORD dwOffset; BYTE bRegCR3A; BYTE bRegCR3B; BYTE bRegCR3C; // Make sure that the overlay surface we're flipping from is
// currently visible. If you don't do this check, you'll get
// really weird results when someone starts up two ActiveMovie
// or DirectVideo movies simultaneously!
if (lpFlip->lpSurfCurr->lpGbl->fpVidMem == ppdev->fpVisibleOverlay) { ppdev->fpVisibleOverlay = ulMemoryOffset; /*
* Determine the offset to the new area. */ // dwOffset = ((ulMemoryOffset - (ULONG)ppdev->pjScreen) + ppdev->sOverlay1.lAdjustSource) >> 2; // sss
dwOffset = ((ulMemoryOffset + ppdev->sOverlay1.lAdjustSource) >> 2);
/*
* Flip the overlay surface by changing CR3A, CR3B, and CR3C */ bRegCR3A = (BYTE) dwOffset & 0xfe; // Align on word boundary (5446 bug)
dwOffset >>= 8; bRegCR3B = (BYTE) dwOffset; dwOffset >>= 8; bRegCR3C = (BYTE) (dwOffset & 0x0f); // if(GetOverlayFlipStatus(0) != DD_OK || DRAW_ENGINE_BUSY || IN_VBLANK)
// {
// lpFlipData->ddRVal = DDERR_WASSTILLDRAWING;
// return DDHAL_DRIVER_HANDLED;
// }
CP_OUT_BYTE(pjPorts, CRTC_INDEX, 0x3C); CP_OUT_BYTE(pjPorts, CRTC_DATA, (CP_IN_BYTE(pjPorts, CRTC_DATA) & 0xf0) | bRegCR3C); CP_OUT_WORD(pjPorts, CRTC_INDEX, ((WORD)bRegCR3A << 8) | 0x3A); CP_OUT_WORD(pjPorts, CRTC_INDEX, ((WORD)bRegCR3B << 8) | 0x3B); } else { lpFlip->ddRVal = DDERR_OUTOFCAPS; return(DDHAL_DRIVER_HANDLED); } } else #endif // OVERLAY
{ // Do the flip.
ulMemoryOffset >>= 2;
ulLowOffset = 0x0D | ((ulMemoryOffset & 0x0000FF) << 8); ulMiddleOffset = 0x0C | ((ulMemoryOffset & 0x00FF00)); ulHighOffset1 = 0x1B | ((ulMemoryOffset & 0x010000) >> 8) | ((ulMemoryOffset & 0x060000) >> 7) | ppdev->ulCR1B; ulHighOffset2 = 0x1D | ((ulMemoryOffset & 0x080000) >> 4) | ppdev->ulCR1D;
// Too bad that the Cirrus flip can't be done in a single atomic register
// write; as it is, we stand a small chance of being context-switched out
// and exactly hitting the vertical blank in the middle of doing these outs,
// possibly causing the screen to momentarily jump.
//
// There are some hoops we could jump through to minimize the chances of
// this happening; we could try to align the flip buffer such that the minor
// registers are ensured to be identical for either flip position, ans so
// that only the high address need be written, an obviously atomic
// operation.
//
// However, I'm simply not going to worry about it.
CP_OUT_WORD(pjPorts, CRTC_INDEX, ulHighOffset2); CP_OUT_WORD(pjPorts, CRTC_INDEX, ulHighOffset1); CP_OUT_WORD(pjPorts, CRTC_INDEX, ulMiddleOffset); CP_OUT_WORD(pjPorts, CRTC_INDEX, ulLowOffset); } // Remember where and when we were when we did the flip.
EngQueryPerformanceCounter(&ppdev->flipRecord.liFlipTime);
ppdev->flipRecord.bFlipFlag = TRUE; ppdev->flipRecord.bHaveEverCrossedVBlank = FALSE;
ppdev->flipRecord.fpFlipFrom = lpFlip->lpSurfCurr->lpGbl->fpVidMem;
if((CP_IN_BYTE(pjPorts, STATUS_1) & VBLANK_ACTIVE)) { ppdev->flipRecord.dwFlipScanLine = 0; ppdev->flipRecord.bWasEverInDisplay = FALSE; } else { ppdev->flipRecord.dwFlipScanLine = GetCurrentVLine(ppdev); ppdev->flipRecord.bWasEverInDisplay = TRUE; }
lpFlip->ddRVal = DD_OK; return(DDHAL_DRIVER_HANDLED); }
/******************************Public*Routine******************************\
* DWORD DdLock * \**************************************************************************/
DWORD DdLock(PDD_LOCKDATA lpLock) { PDEV* ppdev = lpLock->lpDD->dhpdev; BYTE* pjPorts = ppdev->pjPorts;
// Check to see if any pending physical flip has occurred. Don't allow a
// lock if a blt is in progress.
if (UpdateFlipStatus(ppdev, lpLock->lpDDSurface->lpGbl->fpVidMem) != DD_OK) { lpLock->ddRVal = DDERR_WASSTILLDRAWING; return(DDHAL_DRIVER_HANDLED); } if (lpLock->dwFlags & DDLOCK_WAIT) { CP_MM_WAIT_FOR_BLT_COMPLETE(ppdev, ppdev->pjBase); } if (BLT_BUSY(ppdev, ppdev->pjBase)) { lpLock->ddRVal = DDERR_WASSTILLDRAWING; return(DDHAL_DRIVER_HANDLED); }
/*
* Force them to use the video apperture */ if ((lpLock->lpDDSurface->dwReserved1 & OVERLAY_FLG_OVERLAY) && (lpLock->dwFlags == DDLOCK_SURFACEMEMORYPTR) && (ppdev->fpBaseOverlay != 0xffffffff)) {
if (lpLock->lpDDSurface->dwReserved1 & OVERLAY_FLG_DECIMATE) { /*
* Turn on decimation */ CP_OUT_BYTE(pjPorts, CRTC_INDEX, 0x3f); CP_OUT_BYTE(pjPorts, CRTC_DATA, CP_IN_BYTE(pjPorts, CRTC_DATA) | 0x10);
} if( lpLock->lpDDSurface->lpGbl->ddpfSurface.dwFourCC == FOURCC_YUY2) lpLock->lpSurfData = (LPVOID)(ppdev->fpBaseOverlay + lpLock->lpDDSurface->lpGbl->fpVidMem + 0x400000); else lpLock->lpSurfData = (LPVOID)(ppdev->fpBaseOverlay + lpLock->lpDDSurface->lpGbl->fpVidMem + 0x400000 * 3);
// When a driver returns DD_OK and DDHAL_DRIVER_HANDLED from DdLock,
// DirectDraw expects it to have adjusted the resulting pointer
// to point to the upper left corner of the specified rectangle, if
// any:
if (lpLock->bHasRect) { lpLock->lpSurfData = (VOID*) ((BYTE*) lpLock->lpSurfData + lpLock->rArea.top * lpLock->lpDDSurface->lpGbl->lPitch + lpLock->rArea.left * (lpLock->lpDDSurface->lpGbl->ddpfSurface.dwYUVBitCount >> 3)); }
lpLock->ddRVal = DD_OK; return(DDHAL_DRIVER_HANDLED); } return(DDHAL_DRIVER_NOTHANDLED); }
/******************************Public*Routine******************************\
* DWORD DdUnlock * \**************************************************************************/
DWORD DdUnlock(PDD_UNLOCKDATA lpUnlock) { PDEV* ppdev = lpUnlock->lpDD->dhpdev; BYTE* pjPorts = ppdev->pjPorts;
if ((lpUnlock->lpDDSurface->dwReserved1 & OVERLAY_FLG_YUVPLANAR) && !(lpUnlock->lpDDSurface->dwReserved1 & OVERLAY_FLG_ENABLED)) { CP_OUT_WORD(pjPorts, CRTC_INDEX, (0x00 << 8) | 0x3f); // Turn off YUV Planar
}
else if (lpUnlock->lpDDSurface->dwReserved1 & OVERLAY_FLG_DECIMATE) { CP_OUT_WORD(pjPorts, CRTC_INDEX, (0x00 << 8) | 0x3f); // Turn off YUV Planar
}
return(DDHAL_DRIVER_NOTHANDLED); }
/******************************Public*Routine******************************\
* DWORD DdGetBltStatus * * Doesn't currently really care what surface is specified, just checks * and goes. * \**************************************************************************/
DWORD DdGetBltStatus(PDD_GETBLTSTATUSDATA lpGetBltStatus) { PDEV* ppdev; HRESULT ddRVal; PBYTE pjBase;
ppdev = lpGetBltStatus->lpDD->dhpdev; pjBase = ppdev->pjBase;
ddRVal = DD_OK; if (lpGetBltStatus->dwFlags == DDGBS_CANBLT) { // DDGBS_CANBLT case: can we add a blt?
ddRVal = UpdateFlipStatus(ppdev, lpGetBltStatus->lpDDSurface->lpGbl->fpVidMem);
if (ddRVal == DD_OK) { // There was no flip going on, so can the blitter accept new
// register writes?
if (!BLT_READY(ppdev, pjBase)) { ddRVal = DDERR_WASSTILLDRAWING; } } } else { // DDGBS_ISBLTDONE case: is a blt in progress?
if (BLT_BUSY(ppdev, pjBase)) { ddRVal = DDERR_WASSTILLDRAWING; } }
lpGetBltStatus->ddRVal = ddRVal; return(DDHAL_DRIVER_HANDLED); }
/******************************Public*Routine******************************\
* DWORD DdMapMemory * * This is a new DDI call specific to Windows NT that is used to map * or unmap all the application modifiable portions of the frame buffer * into the specified process's address space. * \**************************************************************************/
DWORD DdMapMemory(PDD_MAPMEMORYDATA lpMapMemory) { PDEV* ppdev; VIDEO_SHARE_MEMORY ShareMemory; VIDEO_SHARE_MEMORY_INFORMATION ShareMemoryInformation; DWORD ReturnedDataLength;
ppdev = lpMapMemory->lpDD->dhpdev;
if (lpMapMemory->bMap) { ShareMemory.ProcessHandle = lpMapMemory->hProcess;
// 'RequestedVirtualAddress' isn't actually used for the SHARE IOCTL.
ShareMemory.RequestedVirtualAddress = 0;
// We map in starting at the top of the frame buffer.
ShareMemory.ViewOffset = 0;
// We map down to the end of the frame buffer.
//
// Note: There is a 64k granularity on the mapping (meaning that we
// have to round up to 64k).
//
// Note: If there is any portion of the frame buffer that must not be
// modified by an application, that portion of memory MUST NOT be
// mapped in by this call. This would include any data that, if
// modified by a malicious application, would cause the driver to
// crash. This could include, for example, any DSP code that is
// kept in off-screen memory.
ShareMemory.ViewSize = ROUND_UP_TO_64K(ppdev->cyMemory * ppdev->lDelta + 0x400000 * 3);
if (EngDeviceIoControl(ppdev->hDriver, IOCTL_VIDEO_SHARE_VIDEO_MEMORY, &ShareMemory, sizeof(VIDEO_SHARE_MEMORY), &ShareMemoryInformation, sizeof(VIDEO_SHARE_MEMORY_INFORMATION), &ReturnedDataLength)) { DISPDBG((0, "Failed IOCTL_VIDEO_SHARE_MEMORY"));
lpMapMemory->ddRVal = DDERR_GENERIC; return(DDHAL_DRIVER_HANDLED); }
lpMapMemory->fpProcess =(FLATPTR)ShareMemoryInformation.VirtualAddress; ppdev->fpBaseOverlay = lpMapMemory->fpProcess; } else { ShareMemory.ProcessHandle = lpMapMemory->hProcess; ShareMemory.ViewOffset = 0; ShareMemory.ViewSize = 0; ShareMemory.RequestedVirtualAddress = (VOID*) lpMapMemory->fpProcess; //
// Active movie will unmap memory twice
//
//if (ppdev->fpBaseOverlay == lpMapMemory->fpProcess)
// ppdev->fpBaseOverlay = 0;
if (EngDeviceIoControl(ppdev->hDriver, IOCTL_VIDEO_UNSHARE_VIDEO_MEMORY, &ShareMemory, sizeof(VIDEO_SHARE_MEMORY), NULL, 0, &ReturnedDataLength)) { RIP("Failed IOCTL_VIDEO_UNSHARE_MEMORY"); } }
lpMapMemory->ddRVal = DD_OK; return(DDHAL_DRIVER_HANDLED); }
/******************************Public*Routine******************************\
* DWORD DdGetFlipStatus * * If the display has gone through one refresh cycle since the flip * occurred, we return DD_OK. If it has not gone through one refresh * cycle we return DDERR_WASSTILLDRAWING to indicate that this surface * is still busy "drawing" the flipped page. We also return * DDERR_WASSTILLDRAWING if the bltter is busy and the caller wanted * to know if they could flip yet. * \**************************************************************************/
DWORD DdGetFlipStatus( PDD_GETFLIPSTATUSDATA lpGetFlipStatus) { HRESULT ddRVal; PDEV* ppdev = lpGetFlipStatus->lpDD->dhpdev;
// We don't want a flip to work until after the last flip is done, so we ask
// for the general flip status and ignore the vmem.
//#jc01 ddRVal = UpdateFlipStatus(ppdev, 0);
ddRVal = UpdateFlipStatus(ppdev, 0xffffffff); //#jc01
// Check if the blitter is busy if someone wants to know if they can flip.
if ((lpGetFlipStatus->dwFlags == DDGFS_CANFLIP) && (ddRVal == DD_OK)) { if (BLT_BUSY(ppdev, ppdev->pjBase)) { ddRVal = DDERR_WASSTILLDRAWING; } }
lpGetFlipStatus->ddRVal = ddRVal; return(DDHAL_DRIVER_HANDLED); }
/******************************Public*Routine******************************\
* DWORD DdWaitForVerticalBlank * \**************************************************************************/
DWORD DdWaitForVerticalBlank( PDD_WAITFORVERTICALBLANKDATA lpWaitForVerticalBlank) { PDEV* ppdev; BYTE* pjPorts;
ppdev = lpWaitForVerticalBlank->lpDD->dhpdev; pjPorts = ppdev->pjPorts;
lpWaitForVerticalBlank->ddRVal = DD_OK;
switch (lpWaitForVerticalBlank->dwFlags) { case DDWAITVB_I_TESTVB:
// If TESTVB, it's just a request for the current vertical blank status.
if (CP_IN_BYTE(pjPorts, STATUS_1) & VBLANK_ACTIVE) lpWaitForVerticalBlank->bIsInVB = TRUE; else lpWaitForVerticalBlank->bIsInVB = FALSE;
return(DDHAL_DRIVER_HANDLED);
case DDWAITVB_BLOCKBEGIN:
// If BLOCKBEGIN is requested, we wait until the vertical blank is over,
// and then wait for the display period to end.
while (CP_IN_BYTE(pjPorts, STATUS_1) & VBLANK_ACTIVE) ; while (!(CP_IN_BYTE(pjPorts, STATUS_1) & VBLANK_ACTIVE)) ;
return(DDHAL_DRIVER_HANDLED);
case DDWAITVB_BLOCKEND:
// If BLOCKEND is requested, we wait for the vblank interval to end.
while (!(CP_IN_BYTE(pjPorts, STATUS_1) & VBLANK_ACTIVE)) ; while (CP_IN_BYTE(pjPorts, STATUS_1) & VBLANK_ACTIVE) ;
return(DDHAL_DRIVER_HANDLED); }
return(DDHAL_DRIVER_NOTHANDLED); }
/******************************Public*Routine******************************\
* DWORD DdGetScanLine * * Reads the scan line currently being scanned by the CRT. * \**************************************************************************/
DWORD DdGetScanLine( PDD_GETSCANLINEDATA lpGetScanLine) { PDEV* ppdev; BYTE* pjPorts;
ppdev = (PDEV*) lpGetScanLine->lpDD->dhpdev; pjPorts = ppdev->pjPorts;
/*
* If a vertical blank is in progress the scan line is in * indeterminant. If the scan line is indeterminant we return * the error code DDERR_VERTICALBLANKINPROGRESS. * Otherwise we return the scan line and a success code */ if( CP_IN_BYTE(pjPorts, STATUS_1) & VBLANK_ACTIVE ) { lpGetScanLine->ddRVal = DDERR_VERTICALBLANKINPROGRESS; } else { lpGetScanLine->dwScanLine = GetCurrentVLine(ppdev); lpGetScanLine->ddRVal = DD_OK; } return(DDHAL_DRIVER_HANDLED); }
/******************************Public*Routine******************************\
* DWORD DdCanCreateSurface * \**************************************************************************/
DWORD DdCanCreateSurface( PDD_CANCREATESURFACEDATA lpCanCreateSurface) { PDEV* ppdev; DWORD dwRet; LPDDSURFACEDESC lpSurfaceDesc;
ppdev = (PDEV*) lpCanCreateSurface->lpDD->dhpdev; lpSurfaceDesc = lpCanCreateSurface->lpDDSurfaceDesc;
dwRet = DDHAL_DRIVER_NOTHANDLED;
DISPDBG((2, "DdCanCreateSurface Entered"));
if (!lpCanCreateSurface->bIsDifferentPixelFormat) { // It's trivially easy to create plain surfaces that are the same
// type as the primary surface:
dwRet = DDHAL_DRIVER_HANDLED; }
else if (ppdev->flStatus & STAT_STREAMS_ENABLED) { // When using the Streams processor, we handle only overlays of
// different pixel formats -- not any off-screen memory:
if (lpSurfaceDesc->ddsCaps.dwCaps & DDSCAPS_OVERLAY) { /*
* YUV Planar surfaces cannot co-exist with other overlay surfaces. */ if (ppdev->OvlyCnt >= 1) { lpCanCreateSurface->ddRVal = DDERR_OUTOFCAPS; return (DDHAL_DRIVER_HANDLED); } if ((lpSurfaceDesc->ddpfPixelFormat.dwFourCC == FOURCC_YUVPLANAR) && ppdev->OvlyCnt) { lpCanCreateSurface->ddRVal = DDERR_INVALIDPIXELFORMAT; return (DDHAL_DRIVER_HANDLED); } else if (ppdev->PlanarCnt) { lpCanCreateSurface->ddRVal = DDERR_INVALIDPIXELFORMAT; return (DDHAL_DRIVER_HANDLED); } // We handle four types of YUV overlay surfaces:
if (lpSurfaceDesc->ddpfPixelFormat.dwFlags & DDPF_FOURCC) { // Check first for a supported YUV type:
if (lpSurfaceDesc->ddpfPixelFormat.dwFourCC == FOURCC_YUV422) { lpSurfaceDesc->ddpfPixelFormat.dwYUVBitCount = 16; dwRet = DDHAL_DRIVER_HANDLED; } else if ((lpSurfaceDesc->ddpfPixelFormat.dwFourCC == FOURCC_YUY2) && ((ppdev->ulChipID != 0x40) && (ppdev->ulChipID != 0x4C)) ) //tao1
{ lpSurfaceDesc->ddpfPixelFormat.dwYUVBitCount = 16; dwRet = DDHAL_DRIVER_HANDLED; } else if (lpSurfaceDesc->ddpfPixelFormat.dwFourCC == FOURCC_PACKJR) { if( ppdev->cBitsPerPixel <= 16) { lpSurfaceDesc->ddpfPixelFormat.dwYUVBitCount = 8; dwRet = DDHAL_DRIVER_HANDLED; } } else if (lpSurfaceDesc->ddpfPixelFormat.dwFourCC == FOURCC_YUVPLANAR) { lpSurfaceDesc->ddpfPixelFormat.dwYUVBitCount = 8; dwRet = DDHAL_DRIVER_HANDLED; } }
else if (lpSurfaceDesc->ddpfPixelFormat.dwFlags & DDPF_RGB) { if((lpSurfaceDesc->ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8) && ppdev->cBitsPerPixel == 16 ) { dwRet = DDHAL_DRIVER_HANDLED; } else if (lpSurfaceDesc->ddpfPixelFormat.dwRGBBitCount == 16) { dwRet = DDHAL_DRIVER_HANDLED; }
} } }
// Print some spew if this was a surface we refused to create:
if (dwRet == DDHAL_DRIVER_NOTHANDLED) { if (lpSurfaceDesc->ddpfPixelFormat.dwFlags & DDPF_RGB) { DISPDBG((0, "Failed creation of %libpp RGB surface %lx %lx %lx", lpSurfaceDesc->ddpfPixelFormat.dwRGBBitCount, lpSurfaceDesc->ddpfPixelFormat.dwRBitMask, lpSurfaceDesc->ddpfPixelFormat.dwGBitMask, lpSurfaceDesc->ddpfPixelFormat.dwBBitMask)); } else { DISPDBG((0, "Failed creation of type 0x%lx YUV 0x%lx surface", lpSurfaceDesc->ddpfPixelFormat.dwFlags, lpSurfaceDesc->ddpfPixelFormat.dwFourCC)); } }
lpCanCreateSurface->ddRVal = DD_OK; return(dwRet); }
/******************************Public*Routine******************************\
* DWORD DdCreateSurface * \**************************************************************************/
DWORD DdCreateSurface( PDD_CREATESURFACEDATA lpCreateSurface) { PDEV* ppdev; DD_SURFACE_LOCAL* lpSurfaceLocal; DD_SURFACE_GLOBAL* lpSurfaceGlobal; LPDDSURFACEDESC lpSurfaceDesc; DWORD dwByteCount; LONG lLinearPitch; DWORD dwHeight;
ppdev = (PDEV*) lpCreateSurface->lpDD->dhpdev;
DISPDBG((2, "DdCreateSurface Entered")); // On Windows NT, dwSCnt will always be 1, so there will only ever
// be one entry in the 'lplpSList' array:
lpSurfaceLocal = lpCreateSurface->lplpSList[0]; lpSurfaceGlobal = lpSurfaceLocal->lpGbl; lpSurfaceDesc = lpCreateSurface->lpDDSurfaceDesc;
// We repeat the same checks we did in 'DdCanCreateSurface' because
// it's possible that an application doesn't call 'DdCanCreateSurface'
// before calling 'DdCreateSurface'.
ASSERTDD(lpSurfaceGlobal->ddpfSurface.dwSize == sizeof(DDPIXELFORMAT), "NT is supposed to guarantee that ddpfSurface.dwSize is valid");
// DdCanCreateSurface already validated whether the hardware supports
// the surface, so we don't need to do any validation here. We'll
// just go ahead and allocate it.
//
// Note that we don't do anything special for RGB surfaces that are
// the same pixel format as the display -- by returning DDHAL_DRIVER_
// NOTHANDLED, DirectDraw will automatically handle the allocation
// for us.
//
// Also, since we'll be making linear surfaces, make sure the width
// isn't unreasonably large.
//
// Note that on NT, an overlay can be created only if the driver
// okay's it here in this routine. Under Win95, the overlay will be
// created automatically if it's the same pixel format as the primary
// display.
if ((lpSurfaceLocal->ddsCaps.dwCaps & DDSCAPS_OVERLAY) || (lpSurfaceGlobal->ddpfSurface.dwFlags & DDPF_FOURCC) || (lpSurfaceGlobal->ddpfSurface.dwRBitMask != ppdev->flRed)) { if (lpSurfaceGlobal->wWidth <= (DWORD) ppdev->cxMemory) {
lLinearPitch = (lpSurfaceGlobal->wWidth + 7) & ~7; if (lpSurfaceGlobal->ddpfSurface.dwFlags & DDPF_FOURCC) { ASSERTDD((lpSurfaceGlobal->ddpfSurface.dwFourCC == FOURCC_YUV422) || (lpSurfaceGlobal->ddpfSurface.dwFourCC == FOURCC_YUY2) || (lpSurfaceGlobal->ddpfSurface.dwFourCC == FOURCC_PACKJR) || (lpSurfaceGlobal->ddpfSurface.dwFourCC == FOURCC_YUVPLANAR), "Expected our DdCanCreateSurface to allow only UYVY, YUY2, CLPJ, CLPL"); if((lpSurfaceGlobal->ddpfSurface.dwFourCC == FOURCC_YUV422) || (lpSurfaceGlobal->ddpfSurface.dwFourCC == FOURCC_YUY2)) { dwByteCount = 2; lLinearPitch <<= 1; lpSurfaceLocal->dwReserved1 |= OVERLAY_FLG_YUV422; } else if((lpSurfaceGlobal->ddpfSurface.dwFourCC == FOURCC_PACKJR)) { dwByteCount = 1; lpSurfaceLocal->dwReserved1 |= OVERLAY_FLG_PACKJR; } else if((lpSurfaceGlobal->ddpfSurface.dwFourCC == FOURCC_YUVPLANAR)) { dwByteCount = 1; lpSurfaceLocal->dwReserved1 |= OVERLAY_FLG_YUVPLANAR; } else { dwByteCount = 1; DISPDBG((1, "Created RGB %libpp: %li x %li Red: %lx", 8 * dwByteCount, lpSurfaceGlobal->wWidth, lpSurfaceGlobal->wHeight, lpSurfaceGlobal->ddpfSurface.dwRBitMask)); }
// We have to fill in the bit-count for FourCC surfaces:
lpSurfaceGlobal->ddpfSurface.dwYUVBitCount = 8 * dwByteCount; lpSurfaceGlobal->ddpfSurface.dwYBitMask = (DWORD)-1; lpSurfaceGlobal->ddpfSurface.dwUBitMask = (DWORD)-1; lpSurfaceGlobal->ddpfSurface.dwVBitMask = (DWORD)-1;
DISPDBG((1, "Created YUV: %li x %li", lpSurfaceGlobal->wWidth, lpSurfaceGlobal->wHeight)); } else { dwByteCount = lpSurfaceGlobal->ddpfSurface.dwRGBBitCount >> 3;
if (dwByteCount == 2) lLinearPitch <<= 1;
DISPDBG((1, "Created RGB %libpp: %li x %li Red: %lx", 8 * dwByteCount, lpSurfaceGlobal->wWidth, lpSurfaceGlobal->wHeight, lpSurfaceGlobal->ddpfSurface.dwRBitMask));
}
// We want to allocate a linear surface to store the FourCC
// surface, but DirectDraw is using a 2-D heap-manager because
// the rest of our surfaces have to be 2-D. So here we have to
// convert the linear size to a 2-D size.
//
// The stride has to be a dword multiple:
dwHeight = (lpSurfaceGlobal->wHeight * lLinearPitch + ppdev->lDelta - 1) / ppdev->lDelta;
// Now fill in enough stuff to have the DirectDraw heap-manager
// do the allocation for us:
lpSurfaceGlobal->fpVidMem = DDHAL_PLEASEALLOC_BLOCKSIZE; lpSurfaceGlobal->dwBlockSizeX = ppdev->lDelta; // Specified in bytes
lpSurfaceGlobal->dwBlockSizeY = dwHeight; lpSurfaceGlobal->lPitch = lLinearPitch;
lpSurfaceDesc->lPitch = lLinearPitch; lpSurfaceDesc->dwFlags |= DDSD_PITCH; lpSurfaceLocal->dwReserved1 |= OVERLAY_FLG_OVERLAY; if (lpSurfaceGlobal->ddpfSurface.dwFourCC == FOURCC_YUVPLANAR) { ppdev->PlanarCnt++; } else { ppdev->OvlyCnt++; } ppdev->fpBaseOverlay = 0xffffffff; } else { DISPDBG((1, "Refused to create surface with large width")); } }
return(DDHAL_DRIVER_NOTHANDLED); }
/******************************Public*Routine******************************\
* DWORD DdDestroySurface * \**************************************************************************/
DWORD DdDestroySurface (PDD_DESTROYSURFACEDATA lpDestroySurface) { PDEV* ppdev; BYTE* pjPorts;
ppdev = (PDEV*) lpDestroySurface->lpDD->dhpdev; pjPorts = ppdev->pjPorts;
DISPDBG((2, "In DestroyOverlaySurface")); if (lpDestroySurface->lpDDSurface->dwReserved1 & OVERLAY_FLG_ENABLED) { BYTE bTemp; /*
* Turn the video off */ DISPDBG((1,"Turning off video in DestroySurface")); ppdev->pfnDisableOverlay(ppdev); ppdev->pfnClearAltFIFOThreshold(ppdev);
if (lpDestroySurface->lpDDSurface->dwReserved1 & OVERLAY_FLG_COLOR_KEY) { CP_OUT_BYTE(pjPorts, CRTC_INDEX, 0x1a); bTemp = CP_IN_BYTE(pjPorts, CRTC_DATA); // Clear CR1A[3:2]
CP_OUT_BYTE(pjPorts, CRTC_DATA, bTemp & ~0x0C); }
/*
* Turn off YUV Planar */ if (lpDestroySurface->lpDDSurface->dwReserved1 & OVERLAY_FLG_YUVPLANAR) { CP_OUT_WORD(pjPorts, CRTC_INDEX, (0x00 << 8) | 0x3f); // Turn off YUV Planar
} ppdev->fpVisibleOverlay = (FLATPTR)NULL;
ppdev->dwPanningFlag &= ~OVERLAY_OLAY_SHOW; } if (lpDestroySurface->lpDDSurface->dwReserved1 & OVERLAY_FLG_YUVPLANAR) { if (ppdev->PlanarCnt > 0) ppdev->PlanarCnt--; } else { if (ppdev->OvlyCnt > 0) ppdev->OvlyCnt--; }
if (lpDestroySurface->lpDDSurface->ddsCaps.dwCaps & DDSCAPS_LIVEVIDEO) { BYTE bTemp; CP_OUT_BYTE(pjPorts, CRTC_INDEX, 0x51); bTemp= CP_IN_BYTE(pjPorts, CRTC_DATA); CP_OUT_BYTE(pjPorts, CRTC_DATA, bTemp & ~0x08); }
return(DDHAL_DRIVER_NOTHANDLED); }
/******************************Public*Routine******************************\
* DWORD DdSetColorKey * \**************************************************************************/
DWORD DdSetColorKey( PDD_SETCOLORKEYDATA lpSetColorKey) { PDEV* ppdev; BYTE* pjPorts; BYTE* pjBase; DD_SURFACE_GLOBAL* lpSurface; DWORD dwKeyLow; DWORD dwKeyHigh;
ppdev = (PDEV*) lpSetColorKey->lpDD->dhpdev;
DISPDBG((2, "DdSetColorKey Entered"));
ASSERTDD(ppdev->flStatus & STAT_STREAMS_ENABLED, "Shouldn't have hooked call");
pjPorts = ppdev->pjPorts; pjBase = ppdev->pjBase; lpSurface = lpSetColorKey->lpDDSurface->lpGbl;
// We don't have to do anything for normal blt source colour keys:
if (lpSetColorKey->dwFlags & DDCKEY_SRCBLT) { lpSetColorKey->ddRVal = DD_OK; return(DDHAL_DRIVER_HANDLED); } else if ((lpSetColorKey->dwFlags & DDCKEY_DESTOVERLAY) && (lpSetColorKey->lpDDSurface == ppdev->lpColorSurface)) { if (lpSurface->fpVidMem == ppdev->fpVisibleOverlay) { ppdev->wColorKey = (WORD) lpSetColorKey->ckNew.dwColorSpaceLowValue; ppdev->pfnRegInitVideo(ppdev, lpSetColorKey->lpDDSurface); } lpSetColorKey->ddRVal = DD_OK; return(DDHAL_DRIVER_HANDLED); } else if ((lpSetColorKey->dwFlags & DDCKEY_SRCOVERLAY) && (lpSetColorKey->lpDDSurface == ppdev->lpSrcColorSurface)) { if (lpSurface->fpVidMem == ppdev->fpVisibleOverlay) { ppdev->dwSrcColorKeyLow = lpSetColorKey->ckNew.dwColorSpaceLowValue; ppdev->dwSrcColorKeyHigh = lpSetColorKey->ckNew.dwColorSpaceHighValue; if (ppdev->dwSrcColorKeyLow > ppdev->dwSrcColorKeyHigh) { ppdev->dwSrcColorKeyHigh = ppdev->dwSrcColorKeyLow; } ppdev->pfnRegInitVideo(ppdev, lpSetColorKey->lpDDSurface); } lpSetColorKey->ddRVal = DD_OK; return(DDHAL_DRIVER_HANDLED); }
DISPDBG((1, "DdSetColorKey: Invalid command")); return(DDHAL_DRIVER_NOTHANDLED); }
/******************************Public*Routine******************************\
* DWORD DdUpdateOverlay * \**************************************************************************/
DWORD DdUpdateOverlay( PDD_UPDATEOVERLAYDATA lpUpdateOverlay) { PDEV* ppdev; BYTE* pjPorts; BYTE* pjBase; DD_SURFACE_GLOBAL* lpSource; DD_SURFACE_GLOBAL* lpDestination; DWORD dwStride; LONG srcWidth; LONG srcHeight; LONG dstWidth; LONG dstHeight; DWORD dwBitCount; DWORD dwStart; DWORD dwTmp; BOOL bColorKey; DWORD dwKeyLow; DWORD dwKeyHigh; DWORD dwBytesPerPixel;
DWORD dwSecCtrl; DWORD dwBlendCtrl;
DWORD dwFourcc; BOOL bCheckBandwidth; WORD wBitCount; DWORD_PTR dwOldStatus; BYTE bTemp;
ppdev = (PDEV*) lpUpdateOverlay->lpDD->dhpdev;
DISPDBG((2, "DdUpdateOverlay Entered")); ASSERTDD(ppdev->flStatus & STAT_STREAMS_ENABLED, "Shouldn't have hooked call");
pjPorts = ppdev->pjPorts; pjBase = ppdev->pjBase;
//myf33 begin
// Initialize the bandwidth registers
Regs.bSR2F = 0; Regs.bSR32 = 0; Regs.bSR34 = 0; Regs.bCR42 = 0; //myf33 end
if (lpUpdateOverlay->lpDDSrcSurface->dwFlags & DDRAWISURF_HASPIXELFORMAT) { GetFormatInfo(ppdev, &(lpUpdateOverlay->lpDDSrcSurface->lpGbl->ddpfSurface), &dwFourcc, &wBitCount); } else { // This needs to be changed when primary surface is RGB 5:6:5
dwFourcc = BI_RGB; wBitCount = (WORD) ppdev->cBitsPerPixel; }
/*
* Are we color keying? */ bCheckBandwidth = TRUE; ppdev->lpColorSurface = ppdev->lpSrcColorSurface = NULL; dwOldStatus = lpUpdateOverlay->lpDDSrcSurface->dwReserved1; if ((lpUpdateOverlay->dwFlags & (DDOVER_KEYDEST | DDOVER_KEYDESTOVERRIDE)) && (lpUpdateOverlay->dwFlags & (DDOVER_KEYSRC | DDOVER_KEYSRCOVERRIDE))) { /*
* Cannot perform src colorkey and dest colorkey at the same time */ lpUpdateOverlay->ddRVal = DDERR_NOCOLORKEYHW; return (DDHAL_DRIVER_HANDLED); } lpUpdateOverlay->lpDDSrcSurface->dwReserved1 &= ~(OVERLAY_FLG_COLOR_KEY|OVERLAY_FLG_SRC_COLOR_KEY); if (lpUpdateOverlay->dwFlags & (DDOVER_KEYDEST | DDOVER_KEYDESTOVERRIDE)) { if (ppdev->pfnIsSufficientBandwidth(ppdev, wBitCount, &(lpUpdateOverlay->rSrc), &(lpUpdateOverlay->rDest), OVERLAY_FLG_COLOR_KEY)) { bCheckBandwidth = FALSE; lpUpdateOverlay->lpDDSrcSurface->dwReserved1 |= OVERLAY_FLG_COLOR_KEY; if (lpUpdateOverlay->dwFlags & DDOVER_KEYDEST) { ppdev->wColorKey = (WORD) lpUpdateOverlay->lpDDDestSurface->ddckCKDestOverlay.dwColorSpaceLowValue; ppdev->lpColorSurface = lpUpdateOverlay->lpDDDestSurface; } else { ppdev->wColorKey = (WORD) lpUpdateOverlay->overlayFX.dckDestColorkey.dwColorSpaceLowValue; } } else { lpUpdateOverlay->ddRVal = DDERR_NOCOLORKEYHW; return (DDHAL_DRIVER_HANDLED); } } else if (lpUpdateOverlay->dwFlags & (DDOVER_KEYSRC | DDOVER_KEYSRCOVERRIDE)) { if (ppdev->pfnIsSufficientBandwidth(ppdev, wBitCount, &(lpUpdateOverlay->rSrc), &(lpUpdateOverlay->rDest), OVERLAY_FLG_SRC_COLOR_KEY)) { bCheckBandwidth = FALSE; lpUpdateOverlay->lpDDSrcSurface->dwReserved1 |= OVERLAY_FLG_SRC_COLOR_KEY; ppdev->lpSrcColorSurface = lpUpdateOverlay->lpDDSrcSurface; if (lpUpdateOverlay->dwFlags & DDOVER_KEYSRC) { ppdev->dwSrcColorKeyLow = lpUpdateOverlay->lpDDSrcSurface->ddckCKSrcOverlay.dwColorSpaceLowValue; ppdev->dwSrcColorKeyHigh = lpUpdateOverlay->lpDDSrcSurface->ddckCKSrcOverlay.dwColorSpaceHighValue; } else { ppdev->dwSrcColorKeyLow = lpUpdateOverlay->overlayFX.dckSrcColorkey.dwColorSpaceLowValue; ppdev->dwSrcColorKeyHigh = lpUpdateOverlay->overlayFX.dckSrcColorkey.dwColorSpaceHighValue; } if (ppdev->dwSrcColorKeyHigh < ppdev->dwSrcColorKeyHigh) { ppdev->dwSrcColorKeyHigh = ppdev->dwSrcColorKeyLow; } } else { DISPDBG((0, "Insufficient bandwidth for colorkeying")); lpUpdateOverlay->ddRVal = DDERR_NOCOLORKEYHW; return (DDHAL_DRIVER_HANDLED); } }
// 'Source' is the overlay surface, 'destination' is the surface to
// be overlayed:
lpSource = lpUpdateOverlay->lpDDSrcSurface->lpGbl;
if (lpUpdateOverlay->dwFlags & DDOVER_HIDE) { if (lpSource->fpVidMem == ppdev->fpVisibleOverlay) { /*
* Turn the video off */ ppdev->pfnDisableOverlay(ppdev); ppdev->pfnClearAltFIFOThreshold(ppdev);
/*
* If we are color keying, we will disable that now */ if (dwOldStatus & OVERLAY_FLG_COLOR_KEY) { CP_OUT_BYTE(pjPorts, CRTC_INDEX, 0x1a); bTemp = CP_IN_BYTE(pjPorts, CRTC_DATA); // Clear CR1A[3:2]
CP_OUT_BYTE(pjPorts, CRTC_DATA, bTemp & ~0x0C); }
ppdev->dwPanningFlag &= ~OVERLAY_OLAY_SHOW; lpUpdateOverlay->lpDDSrcSurface->dwReserved1 &= ~OVERLAY_FLG_ENABLED; ppdev->fpVisibleOverlay = 0; }
lpUpdateOverlay->ddRVal = DD_OK; return(DDHAL_DRIVER_HANDLED); } // Dereference 'lpDDDestSurface' only after checking for the DDOVER_HIDE
// case:
#if 0
/*
* Turn the video off first to protect side effect when moving. * Later RegIniVideo will turn it on if needed. */ CP_OUT_BYTE(pjPorts, CRTC_INDEX, 0x3e); bTemp = CP_IN_BYTE(pjPorts, CRTC_DATA); CP_OUT_BYTE(pjPorts, CRTC_DATA, bTemp & ~0x01); // Clear CR3E[0]
#endif
lpDestination = lpUpdateOverlay->lpDDDestSurface->lpGbl;
if (lpSource->fpVidMem != ppdev->fpVisibleOverlay) { if (lpUpdateOverlay->dwFlags & DDOVER_SHOW) { if (ppdev->fpVisibleOverlay != 0) { // Some other overlay is already visible:
DISPDBG((0, "DdUpdateOverlay: An overlay is already visible"));
lpUpdateOverlay->ddRVal = DDERR_OUTOFCAPS; return(DDHAL_DRIVER_HANDLED); } else { // We're going to make the overlay visible, so mark it as
// such:
ppdev->fpVisibleOverlay = lpSource->fpVidMem; } } else { // The overlay isn't visible, and we haven't been asked to make
// it visible, so this call is trivially easy:
lpUpdateOverlay->ddRVal = DD_OK; return(DDHAL_DRIVER_HANDLED); } }
/*
* Is there sufficient bandwidth to work? */ if (bCheckBandwidth && !ppdev->pfnIsSufficientBandwidth(ppdev, wBitCount, &(lpUpdateOverlay->rSrc), &(lpUpdateOverlay->rDest), 0)) { lpUpdateOverlay->ddRVal = DDERR_OUTOFCAPS; return (DDHAL_DRIVER_HANDLED); }
/*
* Save the rectangles */ ppdev->rOverlaySrc = lpUpdateOverlay->rSrc; ppdev->rOverlayDest = lpUpdateOverlay->rDest;
if (lpUpdateOverlay->lpDDSrcSurface->dwReserved1 & OVERLAY_FLG_DECIMATE) { ppdev->rOverlaySrc.right = ppdev->rOverlaySrc.left + ((ppdev->rOverlaySrc.right - ppdev->rOverlaySrc.left) >> 1); }
if (ppdev->rOverlaySrc.right - ppdev->rOverlaySrc.left <= MIN_OLAY_WIDTH) { lpUpdateOverlay->ddRVal = DDERR_OUTOFCAPS; return (DDHAL_DRIVER_HANDLED); }
lpUpdateOverlay->lpDDSrcSurface->dwReserved1 |= OVERLAY_FLG_ENABLED;
//
// Assign 5c to 1F when video is on while no color key for 5446BE.
//
// sge04
//if (bCheckBandwidth && ppdev->flCaps & CAPS_SECOND_APERTURE)
if (ppdev->flCaps & CAPS_SECOND_APERTURE) ppdev->lFifoThresh = 0x0E;
ppdev->pfnRegInitVideo(ppdev, lpUpdateOverlay->lpDDSrcSurface);
lpUpdateOverlay->ddRVal = DD_OK; return(DDHAL_DRIVER_HANDLED); }
/******************************Public*Routine******************************\
* DWORD DdSetOverlayPosition * \**************************************************************************/
DWORD DdSetOverlayPosition( PDD_SETOVERLAYPOSITIONDATA lpSetOverlayPosition) { PDEV* ppdev; BYTE* pjPorts; BYTE* pjBase;
ppdev = (PDEV*) lpSetOverlayPosition->lpDD->dhpdev; pjPorts = ppdev->pjPorts; pjBase = ppdev->pjBase;
DISPDBG((2, "DdSetOverlayPosition Entered")); ASSERTDD(ppdev->flStatus & STAT_STREAMS_ENABLED, "Shouldn't have hooked call");
if(lpSetOverlayPosition->lpDDSrcSurface->lpGbl->fpVidMem == ppdev->fpVisibleOverlay) { /*
* Update the rectangles */ ppdev->rOverlayDest.right = (ppdev->rOverlayDest.right - ppdev->rOverlayDest.left) + lpSetOverlayPosition->lXPos; ppdev->rOverlayDest.left = lpSetOverlayPosition->lXPos; ppdev->rOverlayDest.bottom = (ppdev->rOverlayDest.bottom - ppdev->rOverlayDest.top) + lpSetOverlayPosition->lYPos; ppdev->rOverlayDest.top = lpSetOverlayPosition->lYPos;
//myf29 RegMoveVideo(ppdev, lpSetOverlayPosition->lpDDSrcSurface);
ppdev->pfnRegMoveVideo(ppdev, lpSetOverlayPosition->lpDDSrcSurface); }
lpSetOverlayPosition->ddRVal = DD_OK; return(DDHAL_DRIVER_HANDLED); }
/******************************************************************************\
* * Function: DrvGetDirectDrawInfo * * This function returns te capabilities of the DirectDraw implementation. It is * called twice during the connect phase. * * Parameters: dhpdev Handle to physical device. * pHalInfo Pointer to a DD_HALINFO structure. * pdwNumHeaps Pointer to a variable that holds the number of * heaps. * pvmList Pointer to the heap array. * pdwNumFourCC Pointer to a variable that holds the number of * FourCC IDs. * pdwFourCC Pointer to FourCC IDs. * * Returns: TRUE if successful. * \******************************************************************************/ BOOL DrvGetDirectDrawInfo( DHPDEV dhpdev, DD_HALINFO* pHalInfo, DWORD* pdwNumHeaps, VIDEOMEMORY* pvmList, DWORD* pdwNumFourCC, DWORD* pdwFourCC) { BOOL bCanFlip; PDEV* ppdev = (PPDEV) dhpdev; LONGLONG li; OH* poh; RECTL rSrc, rDest; LONG lZoom; BYTE* pjPorts = ppdev->pjPorts; BYTE bTemp;
// We may not support DirectDraw on this card.
if (!(ppdev->flStatus & STAT_DIRECTDRAW)) { return(FALSE); }
DISPDBG((2, "DrvGetDirectDrawInfo Entered")); pHalInfo->dwSize = sizeof(DD_HALINFO);
// Current primary surface attributes. Since HalInfo is zero-initialized by
// GDI, we only have to fill in the fields which should be non-zero.
pHalInfo->vmiData.pvPrimary = ppdev->pjScreen; pHalInfo->vmiData.dwDisplayWidth = ppdev->cxScreen; pHalInfo->vmiData.dwDisplayHeight = ppdev->cyScreen; pHalInfo->vmiData.lDisplayPitch = ppdev->lDelta; pHalInfo->vmiData.dwOffscreenAlign = 4;
pHalInfo->vmiData.ddpfDisplay.dwSize = sizeof(DDPIXELFORMAT); pHalInfo->vmiData.ddpfDisplay.dwFlags = DDPF_RGB;
pHalInfo->vmiData.ddpfDisplay.dwRGBBitCount = ppdev->cBitsPerPixel;
if (ppdev->cBpp == 1) { pHalInfo->vmiData.ddpfDisplay.dwFlags |= DDPF_PALETTEINDEXED8; }
// These masks will be zero at 8bpp.
pHalInfo->vmiData.ddpfDisplay.dwRBitMask = ppdev->flRed; pHalInfo->vmiData.ddpfDisplay.dwGBitMask = ppdev->flGreen; pHalInfo->vmiData.ddpfDisplay.dwBBitMask = ppdev->flBlue;
if (ppdev->cBpp == 4) { pHalInfo->vmiData.ddpfDisplay.dwRGBAlphaBitMask = ~(ppdev->flRed | ppdev->flGreen | ppdev->flBlue); }
// Set up the pointer to the first available video memory after the primary
// surface.
bCanFlip = FALSE; *pdwNumHeaps = 0;
// Free up as much off-screen memory as possible.
bMoveAllDfbsFromOffscreenToDibs(ppdev); // Move all DFBs to DIB.s
vAssertModeText(ppdev, FALSE); // Destroy all cached fonts.
if ((ppdev->ulChipID == CL7555_ID) || (ppdev->ulChipID == CL7556_ID))//myf32
{ MIN_OLAY_WIDTH = 16; #if (_WIN32_WINNT >= 0x0400)
ppdev->flCaps |= CAPS_VIDEO; #endif
ppdev->pfnIsSufficientBandwidth=Is7555SufficientBandwidth; ppdev->pfnRegInitVideo=RegInit7555Video; ppdev->pfnRegMoveVideo=RegMove7555Video; ppdev->pfnDisableOverlay=DisableVideoWindow; ppdev->pfnClearAltFIFOThreshold=ClearAltFIFOThreshold; } else { ppdev->pfnIsSufficientBandwidth = (ppdev->ulChipID != 0xBC) ? IsSufficientBandwidth : Is5480SufficientBandwidth ; // chu03
ppdev->pfnRegInitVideo=RegInitVideo; ppdev->pfnRegMoveVideo=RegMoveVideo; ppdev->pfnDisableOverlay=DisableOverlay_544x; ppdev->pfnClearAltFIFOThreshold=ClearAltFIFOThreshold_544x; }
// Now simply reserve the biggest chunk for use by DirectDraw.
poh = ppdev->pohDirectDraw; #if (DIRECTX_24 < 2)
if ((poh == NULL) && (ppdev->cBpp != 3)) #else
if (poh == NULL) #endif
{ LONG cxMax, cyMax;
cxMax = ppdev->heap.cxMax & ~(HEAP_X_ALIGNMENT - 1); cyMax = ppdev->heap.cyMax;
poh = pohAllocatePermanent(ppdev, cxMax, cyMax); if (poh == NULL) { // Could not allocate all memory, find the biggest area now.
cxMax = cyMax = 0; for (poh = ppdev->heap.ohAvailable.pohNext; poh != &ppdev->heap.ohAvailable; poh = poh->pohNext) { if ((poh->cx * poh->cy) > (cxMax * cyMax)) { cxMax = poh->cx & ~(HEAP_X_ALIGNMENT - 1); cyMax = poh->cy; } }
poh = pohAllocatePermanent(ppdev, cxMax, cyMax); }
ppdev->pohDirectDraw = poh; }
if (poh != NULL) { *pdwNumHeaps = 1;
// Fill in the list of off-screen rectangles if we've been asked to do
// so.
if (pvmList != NULL) { DISPDBG((1, "DirectDraw gets %d x %d surface at (%d, %d)", poh->cx, poh->cy, poh->x, poh->y));
#if 0
if (PELS_TO_BYTES(poh->cx) != ppdev->lDelta) { #endif
pvmList->dwFlags = VIDMEM_ISRECTANGULAR; pvmList->fpStart = poh->xy; pvmList->dwWidth = PELS_TO_BYTES(poh->cx); pvmList->dwHeight = poh->cy; #if 0
} else { pvmList->dwFlags = VIDMEM_ISLINEAR; pvmList->fpStart = poh->xy; pvmList->fpEnd = poh->xy - 1 + PELS_TO_BYTES(poh->cx) + poh->cy * ppdev->lDelta; } #endif
pvmList->ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; if ((poh->cx >= ppdev->cxScreen) && (poh->cy >= ppdev->cyScreen)) { bCanFlip = TRUE; } } }
// Capabilities supported.
pHalInfo->ddCaps.dwFXCaps = 0; pHalInfo->ddCaps.dwCaps = DDCAPS_BLT | DDCAPS_BLTCOLORFILL | DDCAPS_READSCANLINE; // sge08 add this bit
pHalInfo->ddCaps.dwCaps2 = DDCAPS2_COPYFOURCC;
if ( (ppdev->flCaps & CAPS_VIDEO) && (ppdev->cBpp <= 2) ) { pHalInfo->ddCaps.dwCaps |= DDCAPS_COLORKEY; pHalInfo->ddCaps.dwCKeyCaps = DDCKEYCAPS_SRCBLT; }
pHalInfo->ddCaps.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_PRIMARYSURFACE; if (bCanFlip) { pHalInfo->ddCaps.ddsCaps.dwCaps |= DDSCAPS_FLIP; }
// FourCCs supported.
*pdwNumFourCC = 0;
#if 0 // smac - disable overlays due to too many bugs
{
//
// Interlaced mode ?
//
BOOL Interlaced ; // chu02
CP_OUT_BYTE(pjPorts, CRTC_INDEX, 0x1a) ; Interlaced = CP_IN_BYTE(pjPorts, CRTC_DATA) & 0x01 ;
//
// Needs check more later
//
if ((ppdev->flCaps & CAPS_VIDEO) && (!Interlaced)) // chu02
ppdev->flStatus |= STAT_STREAMS_ENABLED;
if (ppdev->flStatus & STAT_STREAMS_ENABLED) {
/*
* Are we double clocked? */ ppdev->bDoubleClock = FALSE; //
// use SR7 to check the double clock instead of hidden register
//
//
CP_OUT_BYTE(pjPorts, SR_INDEX, 0x7); bTemp = CP_IN_BYTE(pjPorts, SR_DATA);
if ((((bTemp & 0x0E) == 0x06) && ppdev->cBitsPerPixel == 8) || (((bTemp & 0x0E) == 0x08) && ppdev->cBitsPerPixel == 16)) { ppdev->bDoubleClock = TRUE; }
pHalInfo->vmiData.dwOverlayAlign = 8;
pHalInfo->ddCaps.dwCaps |= DDCAPS_OVERLAY | DDCAPS_OVERLAYSTRETCH | DDCAPS_OVERLAYFOURCC | DDCAPS_OVERLAYCANTCLIP | DDCAPS_ALIGNSTRIDE;
pHalInfo->ddCaps.dwFXCaps |= DDFXCAPS_OVERLAYSTRETCHX | DDFXCAPS_OVERLAYSTRETCHY | DDFXCAPS_OVERLAYARITHSTRETCHY;
pHalInfo->ddCaps.dwCKeyCaps |= DDCKEYCAPS_DESTOVERLAY | DDCKEYCAPS_DESTOVERLAYYUV | DDCKEYCAPS_DESTOVERLAYONEACTIVE;
pHalInfo->ddCaps.dwCKeyCaps |= DDCKEYCAPS_SRCOVERLAY | DDCKEYCAPS_SRCOVERLAYCLRSPACE | DDCKEYCAPS_SRCOVERLAYCLRSPACEYUV | DDCKEYCAPS_SRCOVERLAYONEACTIVE | DDCKEYCAPS_SRCOVERLAYYUV;
pHalInfo->ddCaps.ddsCaps.dwCaps |= DDSCAPS_OVERLAY;
*pdwNumFourCC = 3; if ((ppdev->ulChipID == 0x40) || (ppdev->ulChipID == 0x4C)) //tao1
*pdwNumFourCC = 2; //tao1
if (pdwFourCC) { pdwFourCC[0] = FOURCC_YUV422; pdwFourCC[1] = FOURCC_PACKJR; if ((ppdev->ulChipID != 0x40) && (ppdev->ulChipID != 0x4C)) //tao1
pdwFourCC[2] = FOURCC_YUY2; //tao1
}
pHalInfo->ddCaps.dwMaxVisibleOverlays = 1; pHalInfo->ddCaps.dwCurrVisibleOverlays = 0; pHalInfo->ddCaps.dwNumFourCCCodes = 2; # if 1
pHalInfo->ddCaps.dwAlignBoundarySrc = 1; pHalInfo->ddCaps.dwAlignSizeSrc = 1; // chu01 sge05
#if 1
if ((ppdev->cBpp == 3) || ppdev->bDoubleClock ) { pHalInfo->ddCaps.dwAlignBoundaryDest = 4; pHalInfo->ddCaps.dwAlignSizeDest = 4; } else { pHalInfo->ddCaps.dwAlignBoundaryDest = 1; pHalInfo->ddCaps.dwAlignSizeDest = 1; } #else
pHalInfo->ddCaps.dwAlignBoundaryDest = 1; pHalInfo->ddCaps.dwAlignSizeDest = 1; #endif // 1
pHalInfo->ddCaps.dwAlignStrideAlign = 8; pHalInfo->ddCaps.dwMinOverlayStretch = 8000; pHalInfo->ddCaps.dwMinLiveVideoStretch = 8000; pHalInfo->ddCaps.dwMinHwCodecStretch = 8000; pHalInfo->ddCaps.dwMaxOverlayStretch = 8000; pHalInfo->ddCaps.dwMaxLiveVideoStretch = 8000; pHalInfo->ddCaps.dwMaxHwCodecStretch = 8000; //
// maybe there are special requirement for VCLK > 85Hz
//
#endif
rSrc.left = rSrc.top = 0; rSrc.right = 320; rSrc.bottom = 240; rDest.left = rDest.top = 0; rDest.right = 1280; rDest.bottom = 960; lZoom = 1000; do { rDest.right = (320 * lZoom)/ 1000; rDest.bottom = (240 * lZoom)/1000; if (ppdev->pfnIsSufficientBandwidth(ppdev, 16, (LPRECTL) &rSrc, (LPRECTL) &rDest, 0)) { DISPDBG((1, "Minimum zoom factor: %d", lZoom)); pHalInfo->ddCaps.dwMinOverlayStretch = lZoom; pHalInfo->ddCaps.dwMinLiveVideoStretch = lZoom; pHalInfo->ddCaps.dwMinHwCodecStretch = lZoom; lZoom = 4000; } lZoom += 100; } while (lZoom < 4000); } } #endif // smac
return(TRUE); }
/******************************************************************************\
* * Function: DrvEnableDirectDraw * * Enable DirectDraw. This function is called when an application opens a * DirectDraw connection. * * Parameters: dhpdev Handle to physical device. * pCallBacks Pointer to DirectDraw callbacks. * pSurfaceCallBacks Pointer to surface callbacks. * pPaletteCallBacks Pointer to palette callbacks. * * Returns: TRUE if successful. * \******************************************************************************/ BOOL DrvEnableDirectDraw( DHPDEV dhpdev, DD_CALLBACKS* pCallBacks, DD_SURFACECALLBACKS* pSurfaceCallBacks, DD_PALETTECALLBACKS* pPaletteCallBacks) { PDEV* ppdev = (PPDEV) dhpdev;
pCallBacks->WaitForVerticalBlank = DdWaitForVerticalBlank; pCallBacks->MapMemory = DdMapMemory; pCallBacks->GetScanLine = DdGetScanLine; pCallBacks->dwFlags = DDHAL_CB32_WAITFORVERTICALBLANK | DDHAL_CB32_MAPMEMORY | DDHAL_CB32_GETSCANLINE;
pSurfaceCallBacks->Blt = DdBlt; pSurfaceCallBacks->Flip = DdFlip; pSurfaceCallBacks->Lock = DdLock; pSurfaceCallBacks->GetBltStatus = DdGetBltStatus; pSurfaceCallBacks->GetFlipStatus = DdGetFlipStatus; pSurfaceCallBacks->dwFlags = DDHAL_SURFCB32_BLT | DDHAL_SURFCB32_FLIP | DDHAL_SURFCB32_LOCK | DDHAL_SURFCB32_GETBLTSTATUS | DDHAL_SURFCB32_GETFLIPSTATUS;
if (ppdev->flStatus & STAT_STREAMS_ENABLED) { pCallBacks->CreateSurface = DdCreateSurface; pCallBacks->CanCreateSurface = DdCanCreateSurface; pCallBacks->dwFlags |= DDHAL_CB32_CREATESURFACE | DDHAL_CB32_CANCREATESURFACE;
pSurfaceCallBacks->SetColorKey = DdSetColorKey; pSurfaceCallBacks->UpdateOverlay = DdUpdateOverlay; pSurfaceCallBacks->SetOverlayPosition = DdSetOverlayPosition; pSurfaceCallBacks->DestroySurface = DdDestroySurface; pSurfaceCallBacks->dwFlags |= DDHAL_SURFCB32_SETCOLORKEY | DDHAL_SURFCB32_UPDATEOVERLAY | DDHAL_SURFCB32_SETOVERLAYPOSITION | DDHAL_SURFCB32_DESTROYSURFACE;
// The DrvEnableDirectDraw call can occur while we're in full-
// screen DOS mode. Do not turn on the streams processor now
// if that's the case, instead wait until AssertMode switches
// us back to graphics mode:
}
// Note that we don't call 'vGetDisplayDuration' here, for a couple of
// reasons:
//
// o Because the system is already running, it would be disconcerting
// to pause the graphics for a good portion of a second just to read
// the refresh rate;
// o More importantly, we may not be in graphics mode right now.
//
// For both reasons, we always measure the refresh rate when we switch
// to a new mode.
return(TRUE); }
/******************************************************************************\
* * Function: DrvDisableDirectDraw * * Disable DirectDraw. This function is called when an application closes the * DirectDraw connection. * * Parameters: dhpdev Handle to physical device. * * Returns: Nothing. * \******************************************************************************/ VOID DrvDisableDirectDraw( DHPDEV dhpdev) { PDEV* ppdev; OH* poh;
// DirectDraw is done with the display, so we can go back to using
// all of off-screen memory ourselves.
ppdev = (PPDEV) dhpdev; poh = ppdev->pohDirectDraw;
if (poh) { DISPDBG((1, "Releasing DirectDraw surface %d x %d at (%d, %d)", poh->cx, poh->cy, poh->x, poh->y)); }
pohFree(ppdev, poh); ppdev->pohDirectDraw = NULL;
// Invalidate all cached fonts.
vAssertModeText(ppdev, TRUE); }
/******************************************************************************\
* * Function: vAssertModeDirectDraw * * Perform specific DirectDraw initialization when the screen switches focus * (from graphics to full screen MS-DOS and vice versa). * * Parameters: ppdev Pointer to physical device. * bEnabled True if the screen is in graphics mode. * * Returns: Nothing. * \******************************************************************************/ VOID vAssertModeDirectDraw( PDEV* ppdev, BOOL bEnabled) { }
/******************************************************************************\
* * Function: bEnableDirectDraw * * Enable DirectDraw. Called from DrvEnableSurface. * * Parameters: ppdev Pointer to phsyical device. * * Returns: Nothing. * \******************************************************************************/ BOOL bEnableDirectDraw( PDEV* ppdev) {
if (DIRECT_ACCESS(ppdev) && // Direct access must be enabled.
#if (DIRECTX_24 < 1)
(ppdev->cBpp != 3) && // Turn off DirectDraw in 24-bpp.
#endif
(ppdev->flCaps & CAPS_ENGINEMANAGED) && // Only support CL-GD5436/5446.
(ppdev->flCaps & CAPS_MM_IO)) // Memory Mapped I/O must be on.
{ // We have to preserve the contents of the CR1B and CR1D registers on a
// page flip.
CP_OUT_BYTE(ppdev->pjPorts, CRTC_INDEX, 0x1B); ppdev->ulCR1B = (CP_IN_BYTE(ppdev->pjPorts, CRTC_DATA) & 0xF2) << 8; CP_OUT_BYTE(ppdev->pjPorts, CRTC_INDEX, 0x1D); ppdev->ulCR1D = (CP_IN_BYTE(ppdev->pjPorts, CRTC_DATA) & 0x7F) << 8;
// Accurately measure the refresh rate for later.
vGetDisplayDuration(ppdev);
// DirectDraw is all set to be used on this card.
ppdev->flStatus |= STAT_DIRECTDRAW;
#if 1 // sge
EnableStartAddrDoubleBuffer(ppdev); #endif // sge
}
return(TRUE); }
/******************************************************************************\
* * Function: vDisableDirectDraw * * Disbale DirectDraw. Called from DrvDisableSurface. * * Parameters: ppdev Pointer to physical device. * * Returns: Nothing. * \******************************************************************************/ VOID vDisableDirectDraw( PDEV* ppdev) { }
#if 1 // OVERLAY #sge
/******************************************************************************\
* * Function: GetFormatInfo * * Get DirectDraw information, * * Parameters: ppdev Pointer to physical device. * * Returns: Nothing. * \******************************************************************************/ VOID GetFormatInfo(PDEV* ppdev, LPDDPIXELFORMAT lpFormat, LPDWORD lpFourcc, LPWORD lpBitCount) {
if (lpFormat->dwFlags & DDPF_FOURCC) { *lpFourcc = lpFormat->dwFourCC; if (lpFormat->dwFourCC == BI_RGB) { *lpBitCount = (WORD) lpFormat->dwRGBBitCount; #ifdef DEBUG
if (lpFormat->dwRGBBitCount == 8) { DISPDBG((1, "Format: RGB 8")); } else if (lpFormat->dwRGBBitCount == 16) { DISPDBG ((1,"Format: RGB 5:5:5")); } #endif
} else if (lpFormat->dwFourCC == BI_BITFIELDS) { if ((lpFormat->dwRGBBitCount != 16) || (lpFormat->dwRBitMask != 0xf800) || (lpFormat->dwGBitMask != 0x07e0) || (lpFormat->dwBBitMask != 0x001f)) { *lpFourcc = (DWORD) -1; } else { *lpBitCount = 16; DISPDBG((1,"Format: RGB 5:6:5")); } } else { lpFormat->dwRBitMask = (DWORD) -1; lpFormat->dwGBitMask = (DWORD) -1; lpFormat->dwBBitMask = (DWORD) -1; if (lpFormat->dwFourCC == FOURCC_PACKJR) { *lpBitCount = 8; DISPDBG((1, "Format: CLJR")); } else if (lpFormat->dwFourCC == FOURCC_YUY2) { *lpBitCount = 16; DISPDBG((1,"Format: YUY2")); } else { *lpBitCount = 16; DISPDBG((1,"Format: UYVY")); } } } else if (lpFormat->dwFlags & DDPF_RGB) { if (lpFormat->dwRGBBitCount == 8) { *lpFourcc = BI_RGB; DISPDBG((1, "Format: RGB 8")); } else if ((lpFormat->dwRGBBitCount == 16) && (lpFormat->dwRBitMask == 0xf800) && (lpFormat->dwGBitMask == 0x07e0) && (lpFormat->dwBBitMask == 0x001f)) { *lpFourcc = BI_BITFIELDS; DISPDBG((1,"Format: RGB 5:6:5")); } else if ((lpFormat->dwRGBBitCount == 16) && (lpFormat->dwRBitMask == 0x7C00) && (lpFormat->dwGBitMask == 0x03e0) && (lpFormat->dwBBitMask == 0x001f)) { *lpFourcc = BI_RGB; DISPDBG((1,"Format: RGB 5:5:5")); } else if (((lpFormat->dwRGBBitCount == 24) || (lpFormat->dwRGBBitCount == 32)) && (lpFormat->dwRBitMask == 0xff0000) && (lpFormat->dwGBitMask == 0x00ff00) && (lpFormat->dwBBitMask == 0x0000ff)) { *lpFourcc = BI_RGB; DISPDBG((1, "Format: RGB 8:8:8")); } else { *lpFourcc = (DWORD) -1; } *lpBitCount = (WORD) lpFormat->dwRGBBitCount; } else if (ppdev->cBitsPerPixel == 16) { *lpFourcc = BI_RGB; *lpBitCount = (WORD) lpFormat->dwRGBBitCount; } else { *lpFourcc = (DWORD) -1; } }
/**********************************************************
* * Name: RegInitVideo * * Module Abstract: * ---------------- * This function is called to program the video format and * the physicall offset of the video data in the frame buffer. * * Output Parameters: * ------------------ * none * *********************************************************** * Author: Shuhua Ge * Date: 09/24/96 * * Revision History: * ----------------- * WHO WHEN WHAT/WHY/HOW * --- ---- ------------ * *********************************************************/
VOID RegInitVideo(PDEV* ppdev, PDD_SURFACE_LOCAL lpSurface) { DWORD dwTemp; DWORD dwFourcc; LONG lPitch; LONG lLeft; WORD wTemp; WORD wBitCount = 0; RECTL rVideoRect; BYTE bRegCR31; BYTE bRegCR32; BYTE bRegCR33; BYTE bRegCR34; BYTE bRegCR35; BYTE bRegCR36; BYTE bRegCR37; BYTE bRegCR38; BYTE bRegCR39; BYTE bRegCR3A; BYTE bRegCR3B; BYTE bRegCR3C; BYTE bRegCR3D; BYTE bRegCR3E; BYTE bRegCR5C; BYTE bRegCR5D; BYTE bTemp; DWORD dwTemp1; BOOL bOverlayTooSmall = FALSE; BYTE* pjPorts = ppdev->pjPorts;
/*
* Determine the format of the video data */ if (lpSurface->dwFlags & DDRAWISURF_HASPIXELFORMAT) { GetFormatInfo(ppdev, &(lpSurface->lpGbl->ddpfSurface), &dwFourcc, &wBitCount); } else { // This needs to be changed when primary surface is RGB 5:6:5
dwFourcc = BI_RGB; wBitCount = (WORD) ppdev->cBitsPerPixel; }
rVideoRect = ppdev->rOverlayDest; lPitch = lpSurface->lpGbl->lPitch;
/*
* Determine value in CR31 (Horizontal Zoom Code) */ if ((ppdev->rOverlayDest.right - ppdev->rOverlayDest.left) == (ppdev->rOverlaySrc.right - ppdev->rOverlaySrc.left)) { /*
* No zooming is occuring */ bRegCR31 = 0; } else { /*
* The zoom code = (256 * <src width>) / <dest width> */ dwTemp = (DWORD) ((DWORD) (ppdev->rOverlaySrc.right - ppdev->rOverlaySrc.left)) * 256; if (ppdev->bDoubleClock) { dwTemp <<= 1; } dwTemp1= (DWORD) (ppdev->rOverlayDest.right - ppdev->rOverlayDest.left); dwTemp= ((2 * dwTemp) + dwTemp1) / (2*dwTemp1); bRegCR31= (BYTE) dwTemp; }
/*
* Determine value in CR32 (Vertical Zoom Code) */ if ((ppdev->rOverlayDest.bottom - ppdev->rOverlayDest.top) == (ppdev->rOverlaySrc.bottom - ppdev->rOverlaySrc.top)) { /*
* No zooming is occuring */ bRegCR32 = 0; } else { /*
* The zoom code = (256 * <src height>) / <dest height> * The -1 is so that it won't mangle the last line by mixing it * with garbage data while Y interpolating. */ dwTemp = (DWORD) ((DWORD) ((ppdev->rOverlaySrc.bottom - 1) - ppdev->rOverlaySrc.top)) * 256; dwTemp /= (DWORD) (ppdev->rOverlayDest.bottom - ppdev->rOverlayDest.top); bRegCR32 = (BYTE) dwTemp; }
/*
* Determine value in CR33 (Region 1 Size) */ wTemp = (WORD) rVideoRect.left; if (ppdev->cBitsPerPixel == 8) { wTemp >>= 2; // 4 Pixels per DWORD
} else if (ppdev->cBitsPerPixel == 16) { wTemp >>= 1; // 2 Pixels per DWORD
} else if (ppdev->cBitsPerPixel == 24) { wTemp *= 3; wTemp /= 4; } bRegCR33 = (BYTE) wTemp; bRegCR36 = (BYTE) (WORD) (wTemp >> 8);
/*
* Determine value in CR34 (Region 2 size) */ wTemp = (WORD) (rVideoRect.right - rVideoRect.left); if (ppdev->cBitsPerPixel == 8) { wTemp >>= 2; // 4 Pixels per DWORD
} else if (ppdev->cBitsPerPixel == 16) { wTemp >>= 1; // 2 Pixels per DWORD
} else if (ppdev->cBitsPerPixel == 24) { wTemp *= 3; wTemp /= 4; } bRegCR34 = (BYTE) wTemp; wTemp >>= 6; bRegCR36 |= (BYTE) (wTemp & 0x0C);
/*
* Determine value in CR35 (Region 2 SDSize) */ dwTemp = (DWORD) (rVideoRect.right - rVideoRect.left); dwTemp *= (DWORD) (ppdev->rOverlaySrc.right - ppdev->rOverlaySrc.left); dwTemp /= (DWORD) (ppdev->rOverlayDest.right - ppdev->rOverlayDest.left); wTemp = (WORD) dwTemp; if ((dwFourcc == FOURCC_PACKJR) || (wBitCount == 8)) { wTemp >>= 2; // 4 Pixels per DWORD
} else { wTemp >>= 1; // 2 Pixels per DWORD
} bRegCR35 = (BYTE) wTemp; wTemp >>= 4; bRegCR36 |= (BYTE) (wTemp & 0x30);
//
// Check double scan line counter feature
//
CP_OUT_BYTE(pjPorts, CRTC_INDEX, 0x17); bTemp = CP_IN_BYTE(pjPorts, CRTC_DATA); if (bTemp & 0x04) { //
// Double scan line count
//
/*
* Determine value in CR37 (Vertical Start) */ wTemp = (WORD) rVideoRect.top; bRegCR37 = (BYTE)(wTemp >> 1); if ( wTemp & 0x01 ) { wTemp >>= 9; bRegCR39 = (BYTE) wTemp | 0x10; //
// Odd scan line trigger
// Hardware has a bug now.
// So reduce dest end by 1
//
wTemp = (WORD) rVideoRect.bottom - 1 - 1; } else { wTemp >>= 9; bRegCR39 = (BYTE) wTemp; /*
* Determine value in CR38 (Vertical End) */ wTemp = (WORD) rVideoRect.bottom - 1; } bRegCR38 = (BYTE)(wTemp >> 1); if (wTemp & 0x01) bRegCR39 |= 0x20; wTemp >>= 7; bRegCR39 |= (BYTE) (wTemp & 0x0C); } else { /*
* Determine value in CR37 (Vertical Start) */ wTemp = (WORD) rVideoRect.top; bRegCR37 = (BYTE) wTemp; wTemp >>= 8; bRegCR39 = (BYTE) wTemp;
/*
* Determine value in CR38 (Vertical End) */ wTemp = (WORD) rVideoRect.bottom - 1; bRegCR38 = (BYTE) wTemp; wTemp >>= 6; bRegCR39 |= (BYTE) (wTemp & 0x0C); } /*
* Determine values in CR3A, CR3B, CR3C (Start Address) */ dwTemp = 0;
if (bRegCR31 != 0) { //
// overlay is zoomed, re-initialize zoom factor
//
CalculateStretchCode(ppdev->rOverlaySrc.right - ppdev->rOverlaySrc.left, ppdev->rOverlayDest.right - ppdev->rOverlayDest.left, ppdev->HorStretchCode); }
//
// Here, we want to ensure the source rectangle's clipped width is bigger
// than what the HW can support, sigh!
//
if (!bOverlayTooSmall) { LONG lSrcPels;
//
// compute non-clip amount on right edge
//
lSrcPels = rVideoRect.right - rVideoRect.left;
if (bRegCR31 != 0) // source is zoomed if non-zero
{ WORD wRightCnt;
wRightCnt = 0; while (lSrcPels > 0) { lSrcPels -= ppdev->HorStretchCode[wRightCnt]; if (lSrcPels >= 0) { wRightCnt++; } } lSrcPels = (LONG)wRightCnt; }
if ((lSrcPels == 0) || (lSrcPels <= MIN_OLAY_WIDTH)) { bOverlayTooSmall = TRUE; } }
lLeft = ppdev->rOverlaySrc.left; if (dwFourcc == FOURCC_PACKJR) { lLeft &= ~0x03; } else if (dwFourcc == FOURCC_YUV422 || dwFourcc == FOURCC_YUY2 ) { lLeft &= ~0x01; }
//
// dwTemp has adjusted dest. rect., add in source adjustment
//
dwTemp += (ppdev->rOverlaySrc.top * lPitch) + ((lLeft * wBitCount) >>3);
ppdev->sOverlay1.lAdjustSource = dwTemp; // dwTemp += ((BYTE*)lpSurface->lpGbl->fpVidMem - ppdev->pjScreen); // sss
dwTemp += (DWORD)(lpSurface->lpGbl->fpVidMem);
bRegCR5D = (BYTE) ((dwTemp << 2) & 0x0C); dwTemp >>= 2; bRegCR3A = (BYTE) dwTemp & 0xfe; // Align to even byte (5446 bug)
dwTemp >>= 8; bRegCR3B = (BYTE) dwTemp; dwTemp >>= 8; bRegCR3C = (BYTE) (dwTemp & 0x0f);
/*
* Determine value in CR3D (Address Offset/Pitch) */ wTemp = (WORD) (lPitch >> 3); if (lpSurface->dwReserved1 & OVERLAY_FLG_DECIMATE) { wTemp >>= 1; } bRegCR3D = (BYTE) wTemp; wTemp >>= 3; bRegCR3C |= (BYTE) (wTemp & 0x20);
/*
* Determine value in CR3E (Master Control Register) */ bRegCR3E = 0; if (lpSurface->dwReserved1 & OVERLAY_FLG_ENABLED) { bRegCR3E = 0x01; } if (dwFourcc == FOURCC_PACKJR) { bRegCR3E |= 0x20; // Always error difuse when using PackJR
} if ((bRegCR32 == 0) || MustLineReplicate (ppdev, lpSurface, wBitCount)) { bRegCR3E |= 0x10; lpSurface->dwReserved1 &= ~OVERLAY_FLG_INTERPOLATE; } else { lpSurface->dwReserved1 |= OVERLAY_FLG_INTERPOLATE; } if (dwFourcc == FOURCC_PACKJR) { bRegCR3E |= 0x02; } else if (dwFourcc == BI_RGB) { if (wBitCount == 16) { bRegCR3E |= 0x08; } else if (wBitCount == 8) { bRegCR3E |= 0x04; } } else if (dwFourcc == BI_BITFIELDS) { bRegCR3E |= 0x0A; }
/*
* If we are color keying, we will set that up now */ if (lpSurface->dwReserved1 & OVERLAY_FLG_COLOR_KEY) { bRegCR3E |= 0x80;
CP_OUT_BYTE(pjPorts, CRTC_INDEX, 0x1a); bTemp = CP_IN_BYTE(pjPorts, CRTC_DATA); // Set CR1A[3:2] to timing ANDed w/ color
bTemp &= ~0x0C; CP_OUT_BYTE(pjPorts, CRTC_DATA, bTemp);
CP_OUT_BYTE(pjPorts, CRTC_INDEX, 0x1d); // Clear CR1D[5:4]
bTemp = CP_IN_BYTE(pjPorts, CRTC_DATA); if (ppdev->cBitsPerPixel == 8) { CP_OUT_BYTE(pjPorts, CRTC_DATA, bTemp & ~0x38); CP_OUT_WORD(pjPorts, INDEX_REG, (ppdev->wColorKey << 8) | 0x0c); // Output color to GRC
CP_OUT_WORD(pjPorts, INDEX_REG, 0x0d); // Output color to GRD
} else { CP_OUT_BYTE(pjPorts, CRTC_DATA, (bTemp & ~0x30) | 0x08); CP_OUT_WORD(pjPorts, INDEX_REG, (ppdev->wColorKey << 8) | 0x0c); // Output color to GRC
CP_OUT_WORD(pjPorts, INDEX_REG, (ppdev->wColorKey & 0xff00) | 0x0d);// Output color to GRD
} } else if (lpSurface->dwReserved1 & OVERLAY_FLG_SRC_COLOR_KEY) { BYTE bYMax, bYMin, bUMax, bUMin, bVMax, bVMin;
bRegCR3E |= 0x80;
CP_OUT_BYTE(pjPorts, CRTC_INDEX, 0x1a); bTemp = CP_IN_BYTE(pjPorts, CRTC_DATA); // Set CR1A[3:2] to timing ANDed w/ color
bTemp &= ~0x0C; CP_OUT_BYTE(pjPorts, CRTC_DATA, bTemp);
CP_OUT_BYTE(pjPorts, CRTC_INDEX, 0x1d); // Set CR1D[5:4] to 10
CP_OUT_BYTE(pjPorts, CRTC_DATA, CP_IN_BYTE(pjPorts, CRTC_DATA) | 0x20);
/*
* Determine min/max values */ if ((dwFourcc == FOURCC_YUV422) || (dwFourcc == FOURCC_YUY2) || (dwFourcc == FOURCC_PACKJR)) { bYMax = (BYTE)(DWORD)(ppdev->dwSrcColorKeyHigh >> 16); bYMin = (BYTE)(DWORD)(ppdev->dwSrcColorKeyLow >> 16); bUMax = (BYTE)(DWORD)((ppdev->dwSrcColorKeyHigh >> 8) & 0xff); bUMin = (BYTE)(DWORD)((ppdev->dwSrcColorKeyLow >> 8) & 0xff); bVMax = (BYTE)(ppdev->dwSrcColorKeyHigh & 0xff); bVMin = (BYTE)(ppdev->dwSrcColorKeyLow & 0xff); if (dwFourcc == FOURCC_PACKJR) { bYMax |= 0x07; bUMax |= 0x03; bVMax |= 0x03; bYMin &= ~0x07; bUMin &= ~0x03; bVMin &= ~0x03; } } else if ((dwFourcc == 0) && (wBitCount == 16)) { /*
* RGB 5:5:5 */ bYMax = (BYTE)(DWORD)((ppdev->dwSrcColorKeyHigh >> 7) & 0xF8); bYMin = (BYTE)(DWORD)((ppdev->dwSrcColorKeyLow >> 7) & 0xF8); bUMax = (BYTE)(DWORD)((ppdev->dwSrcColorKeyHigh >> 2) & 0xF8); bUMin = (BYTE)(DWORD)((ppdev->dwSrcColorKeyLow >> 2) & 0xF8); bVMax = (BYTE)(ppdev->dwSrcColorKeyHigh << 3); bVMin = (BYTE)(ppdev->dwSrcColorKeyLow << 3); bYMax |= 0x07; bUMax |= 0x07; bVMax |= 0x07;
} else if (dwFourcc == BI_BITFIELDS) { /*
* RGB 5:6:5 */ bYMax = (BYTE)(DWORD)((ppdev->dwSrcColorKeyHigh >> 8) & 0xF8); bYMin = (BYTE)(DWORD)((ppdev->dwSrcColorKeyLow >> 8) & 0xF8); bUMax = (BYTE)(DWORD)((ppdev->dwSrcColorKeyHigh >> 3) & 0xFC); bUMin = (BYTE)(DWORD)((ppdev->dwSrcColorKeyLow >> 3) & 0xFC); bVMax = (BYTE)(ppdev->dwSrcColorKeyHigh << 3); bVMin = (BYTE)(ppdev->dwSrcColorKeyLow << 3); bYMax |= 0x07; bUMax |= 0x03; bVMax |= 0x07; }
CP_OUT_WORD(pjPorts, INDEX_REG, ((WORD)bYMin << 8) | 0x0C); // GRC
CP_OUT_WORD(pjPorts, INDEX_REG, ((WORD)bYMax << 8) | 0x0D); // GRD
CP_OUT_WORD(pjPorts, INDEX_REG, ((WORD)bUMin << 8) | 0x1C); // GR1C
CP_OUT_WORD(pjPorts, INDEX_REG, ((WORD)bUMax << 8) | 0x1D); // GR1D
CP_OUT_WORD(pjPorts, INDEX_REG, ((WORD)bVMin << 8) | 0x1E); // GR1E
CP_OUT_WORD(pjPorts, INDEX_REG, ((WORD)bVMax << 8) | 0x1F); // GR1F
} else { CP_OUT_BYTE(pjPorts, CRTC_INDEX, 0x1a); bTemp = CP_IN_BYTE(pjPorts, CRTC_DATA); // Clear CR1A[3:2]
CP_OUT_BYTE(pjPorts, CRTC_DATA, bTemp & ~0x0C); }
/*
* Set up alignment info */ if (ppdev->cBitsPerPixel != 24) { WORD wXAlign; WORD wXSize;
if (ppdev->cBitsPerPixel == 8) { wXAlign = (WORD)rVideoRect.left & 0x03; wXSize = (WORD)(rVideoRect.right - rVideoRect.left) & 0x03; } else { wXAlign = (WORD)(rVideoRect.left & 0x01) << 1; wXSize = (WORD)((rVideoRect.right - rVideoRect.left) & 0x01) << 1; } bRegCR5D |= (BYTE) (wXAlign | (wXSize << 4)); } else { bRegCR5D = 0; }
/*
* Set up the FIFO threshold value. Make sure that the value we use is * not less than the default value. */ CP_OUT_BYTE(pjPorts, SR_INDEX, 0x16); bTemp = CP_IN_BYTE(pjPorts, SR_DATA) & 0x0f; if (bTemp > (ppdev->lFifoThresh & 0x0f)) { ppdev->lFifoThresh = bTemp; } if (ppdev->lFifoThresh < 0x0f) { ppdev->lFifoThresh++; // Eliminates possible errata
} bRegCR5C = 0x10 | ((BYTE) ppdev->lFifoThresh & 0x0f);
/*
* Now start programming the registers */ CP_OUT_WORD(pjPorts, CRTC_INDEX, ((WORD) bRegCR31 << 8) | 0x31); // CR31
CP_OUT_WORD(pjPorts, CRTC_INDEX, ((WORD) bRegCR32 << 8) | 0x32); // CR32
if (lpSurface->dwReserved1 & OVERLAY_FLG_YUVPLANAR) { CP_OUT_WORD(pjPorts, CRTC_INDEX, ((WORD) 0x10 << 8) | 0x3F); // CR3F
} CP_OUT_WORD(pjPorts, CRTC_INDEX, ((WORD) bRegCR5C << 8) | 0x5C); // CR5C
//
// disable overlay if overlay is too small to be supported by HW
//
if (bOverlayTooSmall) { bRegCR3E &= ~0x01; // disable overlay
ppdev->dwPanningFlag |= OVERLAY_OLAY_REENABLE; // totally clipped
} else { CP_OUT_WORD(pjPorts, CRTC_INDEX, ((WORD) bRegCR33 << 8) | 0x33); // CR33
CP_OUT_WORD(pjPorts, CRTC_INDEX, ((WORD) bRegCR34 << 8) | 0x34); // CR34
CP_OUT_WORD(pjPorts, CRTC_INDEX, ((WORD) bRegCR35 << 8) | 0x35); // CR35
CP_OUT_WORD(pjPorts, CRTC_INDEX, ((WORD) bRegCR36 << 8) | 0x36); // CR36
// CP_OUT_WORD(pjPorts, CRTC_INDEX, ((WORD) bRegCR37 << 8) | 0x37); // CR37
CP_OUT_WORD(pjPorts, CRTC_INDEX, ((WORD) bRegCR38 << 8) | 0x38); // CR38
CP_OUT_WORD(pjPorts, CRTC_INDEX, ((WORD) bRegCR39 << 8) | 0x39); // CR39
CP_OUT_WORD(pjPorts, CRTC_INDEX, ((WORD) bRegCR3A << 8) | 0x3A); // CR3A
CP_OUT_WORD(pjPorts, CRTC_INDEX, ((WORD) bRegCR3B << 8) | 0x3B); // CR3B
CP_OUT_WORD(pjPorts, CRTC_INDEX, ((WORD) bRegCR3C << 8) | 0x3C); // CR3C
CP_OUT_WORD(pjPorts, CRTC_INDEX, ((WORD) bRegCR3D << 8) | 0x3D); // CR3D
CP_OUT_WORD(pjPorts, CRTC_INDEX, ((WORD) bRegCR5D << 8) | 0x5D); // CR5D
//
// Write Vertical start first
//
CP_OUT_WORD(pjPorts, CRTC_INDEX, ((WORD) bRegCR37 << 8) | 0x37); // CR37
} CP_OUT_WORD(pjPorts, CRTC_INDEX, ((WORD) bRegCR3E << 8) | 0x3E); // CR3E
}
/**********************************************************
* Name: DisableOverlay_544x * * Module Abstract: * ---------------- * This is called when an overlay window is totally clipped by * the panning viewport. **********************************************************/ VOID DisableOverlay_544x(PDEV* ppdev) { WORD wCR3E; BYTE* pjPorts = ppdev->pjPorts;
ppdev->dwPanningFlag |= OVERLAY_OLAY_REENABLE; CP_OUT_BYTE(pjPorts, CRTC_INDEX,0x3e); //Video Window Master Control
wCR3E = CP_IN_WORD(pjPorts, CRTC_INDEX) & ~0x100; //clear bit one
CP_OUT_WORD(pjPorts, CRTC_INDEX, wCR3E); //disable overlay window
}
/**********************************************************
* Name: EnableOverlay_544x * * Module Abstract: * ---------------- * Show the overlay window. **********************************************************/ VOID EnableOverlay_544x(PDEV* ppdev) { WORD wCR3E; BYTE* pjPorts = ppdev->pjPorts;
ppdev->dwPanningFlag &= ~OVERLAY_OLAY_REENABLE; CP_OUT_BYTE(pjPorts, CRTC_INDEX,0x3e); //Video Window Master Control
wCR3E = CP_IN_WORD(pjPorts, CRTC_INDEX) | 0x100; //clear bit one
CP_OUT_WORD(pjPorts, CRTC_INDEX, wCR3E); //disable overlay window
}
/**********************************************************
* * Name: ClearAltFIFOThreshold_544x * * Module Abstract: * ---------------- * * * Output Parameters: * ------------------ * none * *********************************************************** * Author: Shuhua Ge * Date: 02/03/97 * * Revision History: * ----------------- * WHO WHEN WHAT/WHY/HOW * --- ---- ------------ * *********************************************************/ VOID ClearAltFIFOThreshold_544x(PDEV * ppdev) { UCHAR bTemp;
BYTE* pjPorts = ppdev->pjPorts; DISPDBG((1, "ClearAltFIFOThreshold"));
CP_OUT_BYTE(pjPorts, CRTC_INDEX, 0x5c); // Clear Alt FIFO Threshold
bTemp = CP_IN_BYTE(pjPorts, CRTC_DATA); CP_OUT_BYTE(pjPorts, CRTC_DATA, bTemp & ~0x10); }
/**********************************************************
* * Name: RegMoveVideo * * Module Abstract: * ---------------- * This function is called to move the video window that has * already been programed. * * Output Parameters: * ------------------ * none * *********************************************************** * Author: Shuhua Ge * Date: 09/25/96 * * Revision History: * ----------------- * WHO WHEN WHAT/WHY/HOW * --- ---- ------------ * *********************************************************/
VOID RegMoveVideo(PDEV* ppdev, PDD_SURFACE_LOCAL lpSurface) { BOOL bZoomX; DWORD dwTemp; DWORD dwFourcc; LONG lLeft; LONG lPitch; WORD wTemp; WORD wBitCount = 0; RECTL rVideoRect; BYTE bRegCR33; BYTE bRegCR34; BYTE bRegCR35; BYTE bRegCR36; BYTE bRegCR37; BYTE bRegCR38; BYTE bRegCR39; BYTE bRegCR3A; BYTE bRegCR3B; BYTE bRegCR3C; BYTE bRegCR3D; BYTE bRegCR5D; BYTE bTemp; BYTE* pjPorts = ppdev->pjPorts;
/*
* Determine the format of the video data */ if (lpSurface->dwFlags & DDRAWISURF_HASPIXELFORMAT) { GetFormatInfo(ppdev, &(lpSurface->lpGbl->ddpfSurface), &dwFourcc, &wBitCount); } else { // This needs to be changed when primary surface is RGB 5:6:5
dwFourcc = BI_RGB; wBitCount = (WORD) ppdev->cBitsPerPixel; }
rVideoRect = ppdev->rOverlayDest; //
// rVideoRect is now adjusted and clipped to the panning viewport.
// Disable overlay if totally clipped by viewport.
//
if (((rVideoRect.right - rVideoRect.left) <= 0) || ((rVideoRect.bottom- rVideoRect.top ) <= 0)) { DisableOverlay_544x(ppdev); // #ew1 cannot display below min. overlay size
return; }
lPitch = lpSurface->lpGbl->lPitch;
/*
* Determine value in CR33 (Region 1 Size) */ wTemp = (WORD) rVideoRect.left; if (ppdev->cBitsPerPixel == 8) { wTemp >>= 2; // 4 Pixels per DWORD
} else if (ppdev->cBitsPerPixel == 16) { wTemp >>= 1; // 2 Pixels per DWORD
} else if (ppdev->cBitsPerPixel == 24) { wTemp *= 3; wTemp /= 4; } bRegCR33 = (BYTE) wTemp; bRegCR36 = (BYTE) (WORD) (wTemp >> 8);
/*
* Determine value in CR34 (Region 2 size) */ wTemp = (WORD) (rVideoRect.right - rVideoRect.left); if (ppdev->cBitsPerPixel == 8) { wTemp >>= 2; // 4 Pixels per DWORD
} else if (ppdev->cBitsPerPixel == 16) { wTemp >>= 1; // 2 Pixels per DWORD
} else if (ppdev->cBitsPerPixel == 24) { wTemp *= 3; wTemp /= 4; } bRegCR34 = (BYTE) wTemp; wTemp >>= 6; bRegCR36 |= (BYTE) (wTemp & 0x0C);
/*
* Determine value in CR35 (Region 2SD Size) */ dwTemp = (DWORD) (rVideoRect.right - rVideoRect.left); dwTemp *= (DWORD) (ppdev->rOverlaySrc.right - ppdev->rOverlaySrc.left); dwTemp /= (DWORD) (ppdev->rOverlayDest.right - ppdev->rOverlayDest.left); wTemp = (WORD) dwTemp; if ((dwFourcc == FOURCC_PACKJR) || (wBitCount == 8)) { wTemp >>= 2; // 4 Pixels per DWORD
} else { wTemp >>= 1; // 2 Pixels per DWORD
} bRegCR35 = (BYTE) wTemp; wTemp >>= 4; bRegCR36 |= (BYTE) (wTemp & 0x30);
//
// Check double scan line counter feature
//
CP_OUT_BYTE(pjPorts, CRTC_INDEX, 0x17); bTemp = CP_IN_BYTE(pjPorts, CRTC_DATA); if (bTemp & 0x04) { //
// Double scan line count
//
/*
* Determine value in CR37 (Vertical Start) */ wTemp = (WORD) rVideoRect.top; bRegCR37 = (BYTE)(wTemp >> 1); if ( wTemp & 0x01 ) { wTemp >>= 9; bRegCR39 = (BYTE) wTemp | 0x10; //
// Odd scan line trigger
// Hardware has a bug now.
// So reduce dest end by 1
//
wTemp = (WORD) rVideoRect.bottom - 1 - 1; } else { wTemp >>= 9; bRegCR39 = (BYTE) wTemp; /*
* Determine value in CR38 (Vertical End) */ wTemp = (WORD) rVideoRect.bottom - 1; } bRegCR38 = (BYTE)(wTemp >> 1); if (wTemp & 0x01) bRegCR39 |= 0x20; wTemp >>= 7; bRegCR39 |= (BYTE) (wTemp & 0x0C); } else { /*
* Determine value in CR37 (Vertical Start) */ wTemp = (WORD) rVideoRect.top; //if (ppdev->bDoubleClock)
//{
// wTemp >>= 1;
//}
bRegCR37 = (BYTE) wTemp; wTemp >>= 8; bRegCR39 = (BYTE) wTemp;
/*
* Determine value in CR38 (Vertical End) */ wTemp = (WORD) rVideoRect.bottom - 1; //if (ppdev->bDoubleClock)
//{
// wTemp >>= 1;
//}
bRegCR38 = (BYTE) wTemp; wTemp >>= 6; bRegCR39 |= (BYTE) (wTemp & 0x0C); }
/*
* Determine values in CR3A, CR3B, CR3C (Start Address) */ dwTemp = 0;
bZoomX = ((ppdev->rOverlayDest.right - ppdev->rOverlayDest.left) != (ppdev->rOverlaySrc.right - ppdev->rOverlaySrc.left));
if (bZoomX) { //
// overlay is zoomed, re-initialize zoom factor
//
CalculateStretchCode(ppdev->rOverlaySrc.right - ppdev->rOverlaySrc.left, ppdev->rOverlayDest.right - ppdev->rOverlayDest.left, ppdev->HorStretchCode); }
//
// Here, we want to ensure the source rectangle's clipped width is bigger
// than what the HW can support, sigh!
//
// if (grOverlayDest.right > sData->rViewport.right)
{ int iSrcPels;
//
// compute non-clip amount on right edge
//
iSrcPels = (int)(rVideoRect.right - rVideoRect.left);
if (bZoomX) { WORD wRightCnt;
wRightCnt = 0; while (iSrcPels > 0) { iSrcPels -= ppdev->HorStretchCode[wRightCnt]; if (iSrcPels >= 0) { wRightCnt++; } } iSrcPels = (int)wRightCnt; }
if ((iSrcPels == 0) || (iSrcPels <= MIN_OLAY_WIDTH)) { DisableOverlay_544x(ppdev); // cannot display below min. overlay size
return; } }
lLeft = ppdev->rOverlaySrc.left; if (dwFourcc == FOURCC_PACKJR) { lLeft &= ~0x03; } else if (dwFourcc == FOURCC_YUV422 || dwFourcc == FOURCC_YUY2) { lLeft &= ~0x01; }
//
// #ew1 dwTemp has adjusted dest. rect., add in source adjustment
//
dwTemp += (ppdev->rOverlaySrc.top * lPitch) + ((lLeft * wBitCount) >>3);
ppdev->sOverlay1.lAdjustSource = dwTemp;
// dwTemp += ((BYTE*)lpSurface->lpGbl->fpVidMem - ppdev->pjScreen); // sss
dwTemp += (DWORD)(lpSurface->lpGbl->fpVidMem);
bRegCR5D = (BYTE) ((dwTemp << 2) & 0x0C); dwTemp >>= 2; bRegCR3A = (BYTE) dwTemp & 0xfe; // Align to even byte (5446 bug)
dwTemp >>= 8; bRegCR3B = (BYTE) dwTemp; dwTemp >>= 8; bRegCR3C = (BYTE) (dwTemp & 0x0f);
/*
* Determine value in CR3D (Address Offset/Pitch) */ wTemp = (WORD) (lPitch >> 3); if (lpSurface->dwReserved1 & OVERLAY_FLG_DECIMATE) { wTemp >>= 1; } bRegCR3D = (BYTE) wTemp; wTemp >>= 3; bRegCR3C |= (BYTE) (wTemp & 0x20);
/*
* Set up alignment info */ if (ppdev->cBitsPerPixel != 24) { WORD wXAlign; WORD wXSize;
if (ppdev->cBitsPerPixel == 8) { wXAlign = (WORD)rVideoRect.left & 0x03; wXSize = (WORD)(rVideoRect.right - rVideoRect.left) & 0x03; } else { wXAlign = (WORD)(rVideoRect.left & 0x01) << 1; wXSize = (WORD)((rVideoRect.right - rVideoRect.left) & 0x01) << 1; } bRegCR5D |= (BYTE) (wXAlign | (wXSize << 4)); }
/*
* Now we will write the actual register values. */ CP_OUT_WORD(pjPorts, CRTC_INDEX, ((WORD) bRegCR33 << 8) | 0x33); // CR33
CP_OUT_WORD(pjPorts, CRTC_INDEX, ((WORD) bRegCR34 << 8) | 0x34); // CR34
CP_OUT_WORD(pjPorts, CRTC_INDEX, ((WORD) bRegCR35 << 8) | 0x35); // CR35
CP_OUT_WORD(pjPorts, CRTC_INDEX, ((WORD) bRegCR36 << 8) | 0x36); // CR36
CP_OUT_WORD(pjPorts, CRTC_INDEX, ((WORD) bRegCR38 << 8) | 0x38); // CR38
CP_OUT_WORD(pjPorts, CRTC_INDEX, ((WORD) bRegCR39 << 8) | 0x39); // CR39
CP_OUT_WORD(pjPorts, CRTC_INDEX, ((WORD) bRegCR3A << 8) | 0x3A); // CR3A
CP_OUT_WORD(pjPorts, CRTC_INDEX, ((WORD) bRegCR3B << 8) | 0x3B); // CR3B
CP_OUT_WORD(pjPorts, CRTC_INDEX, ((WORD) bRegCR3C << 8) | 0x3C); // CR3C
CP_OUT_WORD(pjPorts, CRTC_INDEX, ((WORD) bRegCR3D << 8) | 0x3D); // CR3D
CP_OUT_WORD(pjPorts, CRTC_INDEX, ((WORD) bRegCR5D << 8) | 0x5D); // CR5D
CP_OUT_WORD(pjPorts, CRTC_INDEX, ((WORD) bRegCR37 << 8) | 0x37); // CR37
if (ppdev->dwPanningFlag & OVERLAY_OLAY_REENABLE) EnableOverlay_544x(ppdev); }
/**********************************************************
* * Name: CalculateStretchCode * * Module Abstract: * ---------------- * This code was originally written by Intel and distributed * with the DCI development kit. * * This function takes the zoom factor and determines exactly * how many times we need to replicate each row/column. * * Output Parameters: * ------------------ * none * *********************************************************** * Author: Intel * Date: ??/??/?? * * Revision History: * ----------------- * WHO WHEN WHAT/WHY/HOW * --- ---- ------------ * Scott MacDonald 10/06/94 Incorporated code into DCI provider. * *********************************************************/
VOID CalculateStretchCode (LONG srcLength, LONG dstLength, LPBYTE code) { LONG dwDeltaX, dwDeltaY, dwConst1, dwConst2, dwP; LONG i, j, k; BYTE bStretchIndex = 0; LONG total = 0;
/*
* for some strange reason I'd like to figure out but haven't got time to, the * replication code generation seems to have a problem between 1:1 and 2:1 stretch * ratios. Fix is to zero-initialize index (the problem occurs in the first one * generated) when stretch is betw. those ratios, and one-initialize it otherwise. */ if ((dstLength <= srcLength * 2L) && (dstLength >= srcLength)) { bStretchIndex = 0; } else { bStretchIndex = 1; }
/*
* initialize code array, to get rid of anything which might have been * left over in it. */ for (i = 0; i < srcLength; i++) { code[i] = 0; }
/*
* Variable names roughly represent what you will find in any graphics * text. Consult text for an explanation of Bresenham line alg., it's * beyond the scope of my comments here. */ dwDeltaX = srcLength; dwDeltaY = dstLength;
if (dstLength < srcLength) { /*
* Size is shrinking, use standard Bresenham alg. */ dwConst1 = 2L * dwDeltaY; dwConst2 = 2L * (dwDeltaY - dwDeltaX); dwP = 2L * dwDeltaY - dwDeltaX;
for (i = 0; i < dwDeltaX; i++) { if (dwP <= 0L) { dwP += dwConst1; } else { dwP += dwConst2; code[i]++; total++; } } } else { /*
* Size is increasing. Use Bresenham adapted for slope > 1, and * use a loop invariant to generate code array. Run index i from * 0 to dwDeltaY - 1, and when i = dwDeltaY - 1, j will * be = dwDeltaX - 1. */ dwConst1 = 2L * dwDeltaX; dwConst2 = 2L * (dwDeltaX - dwDeltaY); dwP = 2L * dwDeltaX - dwDeltaY; j = 0;
for (i = 0; i < dwDeltaY; i++) { if (dwP <= 0L) { dwP += dwConst1; bStretchIndex++; } else { dwP += dwConst2; code[j++] = ++bStretchIndex; bStretchIndex = 0; total += (int)code[j - 1]; } }
/*
* UGLY fix up for wacky bug which I have no time to fix properly. * The 'total' of entries is messed up for slopes > 4, so add the * difference back into the array. */ if (total < dwDeltaY) { while (total < dwDeltaY) { j = (int)dwDeltaY - total; k = (int)dwDeltaY / j; for (i = 0; i < dwDeltaX; i++) { if (!(i % k) && (total < dwDeltaY)) { code[i]++; total++; } } } } } }
/**********************************************************
* * Name: GetThresholdValue * * Module Abstract: * ---------------- * Determines the best threshold for the specified * surface. * * Output Parameters: * ------------------ * Threshold * *********************************************************** * Author: Shuhua Ge * Date: 09/25/95 * * Revision History: * ----------------- * WHO WHEN WHAT/WHY/HOW * --- ---- ------------ * *********************************************************/
BYTE GetThresholdValue(VOID) { return ((BYTE) 0x0A); }
/**********************************************************
* * Name: MustLineRelicate * * Module Abstract: * ---------------- * Checks to see if we must line replicate or if we can * interpolate. * * Output Parameters: * ------------------ * TRUE/FALSE * *********************************************************** * Author: Shuhua Ge * Date: 09/25/96 * * Revision History: * ----------------- * WHO WHEN WHAT/WHY/HOW * --- ---- ------------ * *********************************************************/
BOOL MustLineReplicate (PDEV* ppdev, PDD_SURFACE_LOCAL lpSurface, WORD wVideoDepth) { LONG lTempThresh;
/*
* If we are double clocking the data (1280x1024 mode), we must * replicate. We should also always replicate in Performance mode */ if (ppdev->bDoubleClock) { return (TRUE); }
//
// Check the VCLK
//
// sge07
if (GetVCLK(ppdev) > 130000) { return (TRUE); }
/*
* If we are using the chroma key feature, we can't interpolate */ if (lpSurface->dwReserved1 & (OVERLAY_FLG_COLOR_KEY | OVERLAY_FLG_SRC_COLOR_KEY)) { return (TRUE); }
lTempThresh = ppdev->lFifoThresh; if (ppdev->pfnIsSufficientBandwidth(ppdev, wVideoDepth, &ppdev->rOverlaySrc, &ppdev->rOverlayDest, OVERLAY_FLG_INTERPOLATE)) { ppdev->lFifoThresh = lTempThresh; return (FALSE); } ppdev->lFifoThresh = lTempThresh;
return (TRUE); }
/**********************************************************
* * Name: IsSufficientBandwidth * * Module Abstract: * ---------------- * Determines is sufficient bandwidth exists for the requested * configuration. * * Output Parameters: * ------------------ * TRUE/FALSE * It also sets the global parameter lFifoThresh, which gets * programed in RegInitVideo(). * *********************************************************** * Author: Shuhua Ge * Date: 09/25/96 * * Revision History: * ----------------- * WHO WHEN WHAT/WHY/HOW * --- ---- ------------ * *********************************************************/
BOOL IsSufficientBandwidth(PDEV* ppdev, WORD wVideoDepth, LPRECTL lpSrc, LPRECTL lpDest, DWORD dwFlags) { LONG lVideoPixelsPerDWORD; LONG lGraphicsPixelsPerDWORD; LONG lVCLKPeriod; LONG lTransferTime; LONG lDWORDsWritten; LONG lZoom; LONG lReadPeriod; LONG lEffReadPeriod; LONG lWritePeriod; LONG lEffWritePeriod; LONG K1,K2; LONG lTrFifoAFirst4; LONG lTrFifoB2; LONG lDWORDsRead; LONG lFifoAReadPeriod; LONG lFifoBReadPeriod; LONG lFifoAEffWritePeriod; LONG lFifoBEffWritePeriod; LONG lFifoALevels; LONG lFifoBLevels; LONG lFifoAThresh; LONG lFifoBThresh; LONG lVCLK;
BYTE* pjPorts = ppdev->pjPorts;
//#define BLIT_LATENCY 8
#define CRT_FIFO_DEPTH 28
//
// Add 8 clock for BLT_LATENCY for 54446BE and later chips
//
// sge04
LONG BLIT_LATENCY = 8; if (ppdev->flCaps & CAPS_SECOND_APERTURE) BLIT_LATENCY += 2;
/*
* Convert input parameters */ if (wVideoDepth == 16) { lVideoPixelsPerDWORD = 2; } else { lVideoPixelsPerDWORD = 4; }
if (ppdev->cBitsPerPixel == 8) { lGraphicsPixelsPerDWORD = 4; } else if (ppdev->cBitsPerPixel == 16) { lGraphicsPixelsPerDWORD = 2; } else if (ppdev->cBitsPerPixel == 24) { lGraphicsPixelsPerDWORD = 1; } else return (FALSE);
lZoom = ((lpDest->right - lpDest->left) * 256) / (lpSrc->right - lpSrc->left);
/*
* If we are double clocked, fail if we are not zoomed at least 2X */ if (ppdev->bDoubleClock && (lZoom < 512)) { return (FALSE); }
/*
* We need to get the VCLK every time since this can change * at run-time */ lVCLK = GetVCLK(ppdev); if (lVCLK == 0) { return (FALSE); } lVCLKPeriod = (LONG) ((1000000/lVCLK) + 1);
/*
* We only need to setup the following variables once! */ if (!ppdev->lBusWidth) { /*
* We will read the bus width from SR0F[4:3] */ CP_OUT_BYTE(pjPorts, SR_INDEX, 0x0F); if ((CP_IN_BYTE(pjPorts, SR_DATA) & 0x18) == 0x18) { ppdev->lBusWidth = 8; // 64 bit bus
} else { ppdev->lBusWidth = 4; // 32 bit bus
} } if (!ppdev->lRandom) { /*
* Is this EDO or regular? */ CP_OUT_BYTE(pjPorts, SR_INDEX, 0x0f); if (!(CP_IN_BYTE(pjPorts, SR_DATA) & 0x4)) { ppdev->lRandom = 7; ppdev->lPageMiss = 7; } else { ppdev->lRandom = 6; ppdev->lPageMiss = 6; } }
if (!ppdev->lMCLKPeriod) { LONG lMCLK;
/*
* The MCLK period is the amount of time required for one cycle. * We will round up. */ CP_OUT_BYTE(pjPorts, SR_INDEX, 0x1f); // First get the MCLK frequency
lMCLK = CP_IN_BYTE(pjPorts, SR_DATA); lMCLK *= 14318; lMCLK >>= 3; ppdev->lMCLKPeriod = ((1000000/lMCLK) + 1); }
/*
* Check for the case with no color key or Y interpolation */ if (dwFlags == 0) { /*
* This mode utilizes only FIFO A. The fifo is filled with * graphics data during regions 1 and 3, and video data during * region 2. * * The normal memory sequence for this mode goes as follows. * * ------------------------------------------------ * | cpu/blit cycle | FIFO A fill | cpu/blit cycle .... * ------------------------------------------------ * * The cpu/blit cycle is interrupted when the CRT * fifo is depleted to its threshold. Once the * crt cycle is started, it continues until the * FIFO A is full. * * Worst case condition for filling the CRT fifo : * * 1) CPU/blit latency -> * 2) Random cycle for region 2 video -> * 3) Page miss for region 2 video -> * 4) Page miss for region 2 to region 3 transition -> * 5) Page miss for region 3 graphics * * Conditions 3 and 5 depend on the location of the * graphic screen within display memory. For 1024x768, where * the graphics screen starts at location 0 and is offset by * 1024 or 2048 bytes each line, condition 5 is never met. * If a video window starts at beginning of a memory page, * and is offset at the beggining of each line by an even * multiple of a memory page, condition 3 is never met. * * Based on this worst case condition, the amount of time * required to complete 4 transfers into the crt fifo * is approximately: * lTransferTime = (BLIT_LATENCY + lRandom + 3*(lPageMiss)) * * lMCLKPeriod. * the number of dwords transferred to the fifo * during this time is 4 for 32 bit memory interface * or 8 for 64 bit interface. * lDWORDsWritten = 4 * (lBusWidth/4) * * During this period, data continues to be read from the crt * fifo for screen refresh. The amount of data read, * assuming a 1x scale is approximately: * lDWORDsRead = tr_time/(lVideoPixelsPerDWORD * lVCLKPeriod) * * The difference between the dwords read and dwords * written must be accounted for in the fifo trheshold setting * * lFifoThresh = (lDWORDsRead - lDWORDsWritten) rounded * up to next even value. * * To determine if there is adequate bandwidth to support * the mode, the lFifoThresh must not exceed the fifo depth. * For the mode to work, the fifo read rate must not exceed the * fifo write rate. * read_rate = min(lGraphicsPixelsPerDWORD,lVideoPixelsPerDWORD) * lVCLKPeriod. * write_rate = lMCLKPeriod * 2; -- 2 clocks per cas * * A special case occurs if the fifo read rate is very close to the peak * fifo write rate. In this case the crt fill may result in a continuous * page cycle for the entire active line. This could result in 1 extra * page miss at the start of region2. To account for this, I will * add 3 DWORDS to the trheshold if the read and write rates are very close * (arbitrarily defined as within 10% of each other. * * Zooming * Some modes can only be supported at video scale factors greater than 1X. * Even when the video is zoomed, a small number of dwords must be read * from the crt fifo at the unzoomed rate in order to prime the video * pipeline. The video pipeline requires 10 pixel before it slows the fifo * reads to the zoomed rate. * * tr_time - (lVCLKPeriod * 10/lVideoPixelsPerDWORD) * lDWORDsRead = --------------------------------------------- + 10/lVideoPixelsPerDWORDord * (lVideoPixelsPerDWORD * lVCLKPeriod * lZoom) */ lTransferTime = (BLIT_LATENCY + ppdev->lRandom + (3*(ppdev->lPageMiss))) * ppdev->lMCLKPeriod;
lDWORDsWritten = 3 * (ppdev->lBusWidth/4);
/*
* If read rate exceeds write rate, calculate minumum zoom * to keep everything as ints, spec the zoom as 256 times * the fractional zoom */ lWritePeriod = ppdev->lMCLKPeriod * 2/(ppdev->lBusWidth/4); lReadPeriod = lVideoPixelsPerDWORD * lVCLKPeriod;
/*
* Pick worst case of graphics and video depths for calculation * of dwords read. This may be a little pessimistic for the * when the graphics bits per pixel exceeds the video bits per pixel. */ lEffReadPeriod = (lVideoPixelsPerDWORD * lVCLKPeriod * lZoom)/256; if (lEffReadPeriod < lWritePeriod) { /*
* Cannot support overlay at this zoom factor */ return (0); }
if (lGraphicsPixelsPerDWORD > lVideoPixelsPerDWORD) // handle zoom factor
{ lDWORDsRead = ((lTransferTime - (lVCLKPeriod * 10/lVideoPixelsPerDWORD))/ (lEffReadPeriod)) + (10 / lVideoPixelsPerDWORD) + 1; } else { lDWORDsRead = (lTransferTime/ (lGraphicsPixelsPerDWORD * lVCLKPeriod)) + 1; }
// Calculate the fifo threshold setting
ppdev->lFifoThresh = lDWORDsRead - lDWORDsWritten;
// if read rate is within 10% of write rate, up by 3 dwords
if ((11*lEffReadPeriod) < ((10*lWritePeriod*256)/lZoom)) { ppdev->lFifoThresh += 3; }
// fifo trheshold spec'd in QWORDS, so round up by 1 and divide by 2)
ppdev->lFifoThresh = (ppdev->lFifoThresh + 1)/2;
// Add a extra QWORD to account for fifo level sync logic
ppdev->lFifoThresh = ppdev->lFifoThresh + 1; if (ppdev->bDoubleClock) { ppdev->lFifoThresh <<= 1; }
if ((ppdev->lFifoThresh >= CRT_FIFO_DEPTH) || ((lEffReadPeriod) < lWritePeriod)) { return (0); } else { return (1); } }
/*
* Check bandwidth for Y Interpolation */ else if (dwFlags & OVERLAY_FLG_INTERPOLATE) { /*
* This mode utilizes both FIFOs A and B. During horizontal blank, * both fifos are filled. FIFO a is then filled with graphics * data during regions 1 and 3, and video data during region 2. * FIFO B is filled with video data during region 2, and is idle * during regions 1 and 3. * * The normal memory sequence for this mode goes as follows. * * ---------------------------------------------------------------- * | cpu/blit cycle | FIFO A fill | FIFO B fill | cpu/blit cycle . * ---------------------------------------------------------------- * or * ---------------------------------------------------------------- * | cpu/blit cycle | FIFO B fill | FIFO A fill | cpu/blit cycle . * ---------------------------------------------------------------- * * For this mode, the FIFO threshold must be set high enough to allow * enough time to abort the cpu/blt, fill FIFO A, then transfer data * into FIFO B before underflow occurs. * * Worst case condition for filling the CRT fifo : * * 1) CPU/blit latency -> * 2) FIFO A random cycle for region 2 video -> * 3) FIFO A page miss for region 2 video -> * 4) FIFO A page miss for region 2 to region 3 transition -> * 5) FIFO A page miss for region 3 graphics * 6) FIFO A page mode fill * 7) FIFO B random cycle * 8) FIFO B page miss * * lTransferTime = lMCLKPeriod * * (BLIT_LATENCY + lRandom + 3*(lPageMiss) + * fifoa_remaining + * lRandom + lPageMiss; * * * The time required to fill FIFO A depends upon the read rate * of FIFO A and the number of levels that must be filled, * as determined by the threshold setting. * * The worst case fill time for the first four levels of fifo A is * lTrFifoAFirst4 = (BLIT_LATENCY + lRandom + 3*(lPageMiss)) * * lMCLKPeriod; * * The number of dwords depleted from fifo A during the * fill of the first four levels is * lReadPeriod = lVCLKPeriod * lVideoPixelsPerDWORD * lZoom; * fifoa_reads_4 = lTrFifoAFirst4/lReadPeriod; * * The number of empty levels remaining in the fifo after * the fill of the first four levels is * fifoa_remaining = FIFO_DEPTH - lFifoThresh + ((4*ramwidth)/4) * - lTrFifoAFirst4/lReadPeriod; * * The amount of time required to fill the remaining levels of * fifo A is determined by the write rate and the read rate. * lWritePeriod = lMCLKPeriod * 2; // 2 clks per cas
* lEffWritePeriod = ((lReadPeriod * lWritePeriod)/ * (lReadPeriod - lWritePeriod)); * * tr_fifoa_remaining = fifoa_remaining * lEffWritePeriod; * * * The total amount of time for the cpu/blt latency and the * fifo A fill is * tr_fifoa_total = lTrFifoAFirst4 + tr_fifoa_remaining; * * The worse case fill time for fifo B is as follows: * lTrFifoB2 = (lRandom + lPageMiss) * lMCLKPeriod; * * The total amount of time elapsed from the crt request until * the first 2 fifob cycles are completed is * lTransferTime = tr_fifoa_total + lTrFifoB2; * * The number of dwords transferred to the fifo during this * time is 2 for 32 bit memory interface or 4 for 64 bit interface. * lDWORDsWritten = 2 * (lBusWidth/4) * * During this period, data continues to be read from the crt * fifo B for screen refresh. The amount of data read, * is approximately: * dwords_read = lTransferTime/lReadPeriod * * The difference between the dwords read and dwords * written must be accounted for in the fifo trheshold setting * * lFifoThresh = (dwords_read - lDWORDsWritten) rounded * up to next even value. * * Since the lTransferTime and dwords_read depends on * the threshold setting, a bit of algebra is required to determine * the minimum setting to prevent fifo underflow. * * lFifoThresh = (lTransferTime/lReadPeriod) - lDWORDsWritten; * = ((tr_fifoa_4 + lTrFifoB2 + tr_fifoa_remaining)/lReadPeriod) * - lDWORDsWritten * to simplify calcuation, break out constant part of equation * K1 = ((tr_fifoa_4 + lTrFifoB2)/lReadPeriod) - lDWORDsWritten; * * lFifoThresh = K1 + (tr_fifoa_remaining/lReadPeriod); * = K1 + (fifoa_remaining * lEffWritePeriod)/lReadPeriod; * lFifoThresh = K1 + * ((FIFO_DEPTH - lFifoThresh + 4 - (lTrFifoAFirst4/lReadPeriod)) * * lEffWritePeriod)/lReadPeriod; * * break out another constant to simplify reduction * K2 = (FIFO_DEPTH + 4 - (lTrFifoAFirst4/lReadPeriod)) * * (lEffWritePeriod/lReadPeriod); * lFifoThresh = K1 + K2 - (lFifoThresh * (lEffWritePeriod/lReadPeriod)); * lFifoThresh * (1 + (lEffWritePeriod/lReadPeriod)) = K1 + K2; * lFifoThresh = (K1 + K2)/(1 + (lEffWritePeriod/lReadPeriod); * * Once the threshold setting is determined, another calculation must * be performed to determine if available bandwidth exists given the * zoom factor. The worst case is assumed to be when FIFO A and * FIFO B reach the threshold point at the same time. The sequence * is then to abort the cpu/blt, fill fifo a, then fill fifo b. * * Since FIFO A is full when the fill B operation starts, I only have * to determine how long it takes to fill FIFO B and then calculate * the the number of dwords read from A during that time. * * lTransferTime = (lTrFifoB2 + (CRT_FIFO_DEPTH * lEffWritePeriod))/lReadPeriod; * lFifoALevels = CRT_FIFO_DEPTH - (lTransferTime/lReadPeriod); * * if lFifoALevels < 1, then underflow condition may occur. */ if (lZoom < 512) { // 5446 requires at least a 2X zoom for Y interpolation
return (FALSE); }
lWritePeriod = ppdev->lMCLKPeriod * 2/(ppdev->lBusWidth/4); lReadPeriod = (lVideoPixelsPerDWORD * lVCLKPeriod * lZoom)/256;
lEffWritePeriod = ((lReadPeriod * lWritePeriod)/ (lReadPeriod - lWritePeriod)); lTrFifoAFirst4 = (BLIT_LATENCY + ppdev->lRandom + 3*(ppdev->lPageMiss)) * ppdev->lMCLKPeriod; lTrFifoB2 = (ppdev->lRandom + ppdev->lPageMiss) * ppdev->lMCLKPeriod;
lDWORDsWritten = 2 * (ppdev->lBusWidth/4); K1 = ((lTrFifoAFirst4 + lTrFifoB2)/lReadPeriod) - lDWORDsWritten; K2 = (CRT_FIFO_DEPTH + (4*(ppdev->lBusWidth/4)) - (lTrFifoAFirst4/lReadPeriod)) * (lEffWritePeriod/lReadPeriod); ppdev->lFifoThresh = (1 + ((K1 + K2)/(1 + (lEffWritePeriod/lReadPeriod))));
ppdev->lFifoThresh += 3;
lTransferTime = (lTrFifoB2 + (CRT_FIFO_DEPTH * lEffWritePeriod)); lFifoALevels = ((CRT_FIFO_DEPTH - (lTransferTime/lReadPeriod))/2); if (ppdev->bDoubleClock) { ppdev->lFifoThresh <<= 1; }
if ((lFifoALevels < 2) || (ppdev->lFifoThresh > (CRT_FIFO_DEPTH/2))) { return (0); } else { return (1); } }
/*
* Check bandwidth for color keying */ else if (dwFlags & (OVERLAY_FLG_COLOR_KEY | OVERLAY_FLG_SRC_COLOR_KEY)) { /*
* This mode utilizes both FIFOs A and B. During horizontal blank, * both fifos are filled. FIFO a is then filled with graphics data * during regions 1,2 and 3. FIFO B is filled with video data * during region 2, and is idle during regions 1 and 3. * * The normal memory sequence for this mode goes as follows. * * ---------------------------------------------------------------- * | cpu/blit cycle | FIFO A fill | FIFO B fill | cpu/blit cycle . * ---------------------------------------------------------------- * or * ---------------------------------------------------------------- * | cpu/blit cycle | FIFO B fill | FIFO A fill | cpu/blit cycle . * ---------------------------------------------------------------- * * For this mode, the FIFO threshold must be set high enough to allow * enough time to abort the cpu/blt, fill FIFO A, then transfer data * into FIFO B before underflow occurs. If the fifob read rate is * greater than the fifoa read rate, then allow eough time for * a t CPU/blt abort, followed by a fifo B fill, then a FIFO A fill. * * Worst case condition for filling the CRT fifo : * * 1) CPU/blit latency -> * 2) FIFO A random -> * 3) FIFO A page miss -> * 6) FIFO A page mode fill --> * 7) FIFO B random --> * 8) FIFO B page miss * * or * * 1) CPU/blit latency -> * 2) FIFO B random -> * 3) FIFO A page miss -> * 6) FIFO A page mode fill --> * 7) FIFO B random --> * 8) FIFO B page miss * * * 1) lTransferTime = lMCLKPeriod * * (BLIT_LATENCY + lRandom + lPageMiss + * fifoa_remaining + * lRandom + lPageMiss; * * or * 2) lTransferTime = lMCLKPeriod * * (BLIT_LATENCY + lRandom + lPageMiss + * fifob_remaining + * lRandom + lPageMiss; * * * lFifoAReadPeriod = lVCLKPeriod * lGraphicsPixelsPerDWORD; * lFifoBReadPeriod = (lVCLKPeriod * lVideoPixelsPerDWORD * lZoom)*256; * * if (lFifoAReadPeriod > lFifoBReadPeriod), then * first fifo is fifo B, otherwise first is fifo A. * The followinf euqations are written for a fifoa->fifob, * sequence, but the fifob->fifoa sequence can be obtained simply * by swapping the fifo read periods. * * The time required to fill a FIFO depends upon the read rate * of the FIFO and the number of levels that must be filled, * as determined by the threshold setting. * * The worst case fill time for the first four levels of fifo A is * lTrFifoAFirst4 = (BLIT_LATENCY + lRandom + lPageMiss) * * lMCLKPeriod; * * The number of dwords depleted from fifo A during the * fill of the first four levels is * fifoa_reads_4 = lTrFifoAFirst4/lFifoAReadPeriod; * * The number of empty levels remaining in the fifo after * the fill of the first four levels is * fifoa_remaining = FIFO_DEPTH - lFifoThresh + ((4*ramwidth)/4) * - lTrFifoAFirst4/lFifoAReadPeriod; * * The amount of time required to fill the remaining levels of * fifo A is determined by the write rate and the read rate. * lWritePeriod = lMCLKPeriod * 2; * 2 clks per cas * eff_write_period = ((lFifoAReadPeriod * lWritePeriod)/ * (lFifoAReadPeriod - lWritePeriod)); * * tr_fifoa_remaining = fifoa_remaining * eff_write_period; * * * The total amount of time for the cpu/blt latency and the * fifo A fill is * tr_fifoa_total = lTrFifoAFirst4 + tr_fifoa_remaining; * * The worse case fill time for fifo B is as follows: * lTrFifoB2 = (lRandom + lPageMiss) * lMCLKPeriod; * * The total amount of time elapsed from the crt request until * the first 2 fifob cycles are completed is * lTransferTime = tr_fifoa_total + lTrFifoB2; * * The number of dwords transferred to the fifo during this time * is 2 for 32 bit memory interface or 4 for 64 bit interface. * lDWORDsWritten = 2 * (lBusWidth/4) * * During this period, data continues to be read from the crt * fifo B for screen refresh. The amount of data read, * is approximately: * lFifoBReadPeriod = (lVCLKPeriod * lVideoPixelsPerDWORD * lZoom)/256; * dwords_read = lTransferTime/lFifoBReadPeriod * * The difference between the dwords read and dwords * written must be accounted for in the fifo trheshold setting * * lFifoThresh = (dwords_read - lDWORDsWritten) rounded * up to next even value. * * Since the lTransferTime and dwords_read depends on the * threshold setting, a bit of algebra is required to determine * the minimum setting to prevent fifo underflow. * * lFifoThresh = (lTransferTime/lFifoBReadPeriod) - lDWORDsWritten; * = ((tr_fifoa_4 + lTrFifoB2 + tr_fifoa_remaining)/lFifoBReadPeriod) * - lDWORDsWritten * to simplify calcuation, break out constant part of equation * K1 = ((tr_fifoa_4 + lTrFifoB2)/lFifoBReadPeriod) - lDWORDsWritten; * * lFifoThresh = K1 + (tr_fifoa_remaining/lFifoBReadPeriod); * = K1 + (fifoa_remaining * eff_write_period)/lFifoBReadPeriod; * lFifoThresh = K1 + * ((FIFO_DEPTH - lFifoThresh + 4 - (lTrFifoAFirst4/lFifoAReadPeriod)) * * eff_write_period)/read_period; * * break out another constant to simplify reduction * K2 = (FIFO_DEPTH + 4 - (lTrFifoAFirst4/lFifoAReadPeriod)) * * (eff_write_period/lFifoBReadPeriod); * lFifoThresh = K1 + K2 - (lFifoThresh * (eff_write_period/lFifoBReadPeriod)); * lFifoThresh * (1 + (eff_write_period/read_period)) = K1 + K2; * lFifoThresh = (K1 + K2)/(1 + (eff_write_period/lFifoBReadPeriod); * * Once the threshold setting is determined, another calculation must * be performed to determine if available bandwidth exists given the * zoom factor. The worst case is assumed to be when FIFO A and * FIFO B reach the threshold point at the same time. The sequence * is then to abort the cpu/blt, fill fifo a, then fill fifo b. * * Since FIFO A is full when the fill B operation starts, I only have * to determine how long it takes to fill FIFO B and then calculate * the the number of dwords read from A during that time. * * lTransferTime = (lTrFifoB2 + (CRT_FIFO_DEPTH * fifob_eff_write_period))/read_period; * fifoa_levels = CRT_FIFO_DEPTH - (lTransferTime/read_period); * * if fifoa_levels < 1, then underflow condition may occur. */ lWritePeriod = ppdev->lMCLKPeriod * 2/(ppdev->lBusWidth/4); lFifoAReadPeriod = lGraphicsPixelsPerDWORD * lVCLKPeriod; lFifoBReadPeriod = (lVideoPixelsPerDWORD * lVCLKPeriod * lZoom)/256;
if (lFifoAReadPeriod <= lWritePeriod) // this fails, so set a big#
{ lFifoAEffWritePeriod = 5000; } else { lFifoAEffWritePeriod = ((lFifoAReadPeriod * lWritePeriod)/ (lFifoAReadPeriod - lWritePeriod)); }
if (lFifoBReadPeriod <= lWritePeriod) // this fails, so set a big#
{ lFifoBEffWritePeriod = 5000; } else { lFifoBEffWritePeriod = ((lFifoBReadPeriod * lWritePeriod)/ (lFifoBReadPeriod - lWritePeriod)); }
if ((lFifoAReadPeriod == 0) || (lFifoBReadPeriod == 0) || (lWritePeriod == 0)) { return (FALSE); }
// These values should be the same for bot the fifoa->fifob
// and fifob->fifoa sequences
lTrFifoAFirst4 = (BLIT_LATENCY + ppdev->lRandom + 2*(ppdev->lPageMiss)) * ppdev->lMCLKPeriod; lTrFifoB2 = (ppdev->lRandom + ppdev->lPageMiss) * ppdev->lMCLKPeriod;
lDWORDsWritten = 2 * (ppdev->lBusWidth/4);
// Since I'm not sure which sequence is worse
// Try both then pick worse case results
// For fifoa->fifob sequence
K1 = ((lTrFifoAFirst4 + lTrFifoB2)/lFifoBReadPeriod) - lDWORDsWritten; K2 = (CRT_FIFO_DEPTH + (4*(ppdev->lBusWidth/4)) - (lTrFifoAFirst4/lFifoAReadPeriod)) * (lFifoAEffWritePeriod/lFifoBReadPeriod); lFifoAThresh = (1 + ((K1 + K2)/ (1 + (lFifoAEffWritePeriod/lFifoBReadPeriod))));
lFifoAThresh += 3;
lTransferTime = (lTrFifoB2 + (CRT_FIFO_DEPTH * lFifoBEffWritePeriod)); lFifoALevels = ((CRT_FIFO_DEPTH - (lTransferTime/lFifoAReadPeriod))/2);
// For fifob->fifoa sequence
K1 = ((lTrFifoAFirst4 + lTrFifoB2)/lFifoAReadPeriod) - lDWORDsWritten; K2 = (CRT_FIFO_DEPTH + (4*(ppdev->lBusWidth/4)) - (lTrFifoAFirst4/lFifoBReadPeriod)) * (lFifoBEffWritePeriod/lFifoAReadPeriod);
lFifoBThresh = (1 + ((K1 + K2)/ (1 + (lFifoBEffWritePeriod/lFifoAReadPeriod))));
lFifoBThresh += 3;
lTransferTime = (lTrFifoB2 + (CRT_FIFO_DEPTH * lFifoAEffWritePeriod)); lFifoBLevels = ((CRT_FIFO_DEPTH - (lTransferTime/lFifoBReadPeriod))/2);
if (lFifoAThresh > lFifoBThresh) { ppdev->lFifoThresh = lFifoAThresh; } else { ppdev->lFifoThresh = lFifoBThresh; } if (ppdev->bDoubleClock) { ppdev->lFifoThresh <<= 1; }
if ((lFifoBLevels <0) || (lFifoALevels < 0) || (ppdev->lFifoThresh > (CRT_FIFO_DEPTH/2))) { return (0); } else { return (1); } } return (1); // Should never get here!!
}
// chu03
/**********************************************************
* * Name: Is5480SufficientBandwidth * * Module Abstract: * ---------------- * This function reads the current MCLK, VLCK, bus width, etc. * and determines whether the chip has sufficient bandwidth * to handle the requested mode. * * Output Parameters: * ------------------ * none * ***********************************************************/
// -------------------------------------------------------------
// Overview by John Schafer
// -------------------------------------------------------------
// The memory arbitration scheme for the 5480 has changed
// significantly from the 5446. The 5480 is set up on a first
// come, first serve basis. If more than 1 request arrive at
// the same clock edge, then the BankSelect is used to determine
// which request to acknowledge first. Using SDRAM, the row
// access to a differennt bank can be hidden, which saves up to
// 7 MCLKs. If all bank selects for the concurrent requests are
// the same, the default prority is FIFOA->FIFOB->FIFOC->VCAP.
//
// The FIFO sizes for the 5480 are as follows:
// FIFOA, FIFOB, FIFOC : 32x64
// VCAP : 16x64 (two 8x64 fifos)
//
// The Y interpolation mode for the 5480 is "free" due to
// the embedded line store. The available mode combinations
// for the 5480 which effect bandwidth are :
//
// 1) Capture enabled, 1 video window, no occlusion, not 420 format
// 2) Capture enabled, 1 video window, no occlusion, 420 format
// 3) Capture enabled, 1 video window, occlusion, not 420 format
// 4) Capture enabled, 1 video window, occlusion, 420 format
// 5) Capture enabled, 2 video windows (occlusion implied)
// 6) Capture disabled, 1 video window, no occlusion, not 420 format
// 7) Capture disabled, 1 video window, no occlusion, 420 format
// 8) Capture disabled, 1 video window, occlusion, not 420 format
// 9) Capture disabled, 1 video window, occlusion, 420 format
// 10) Capture disabled, 2 video windows (occlusion implied)
//
//
// -------------------------------------------------------------
// FIFO threshold description
// -------------------------------------------------------------
// The memory requests are generated based on the threshold settings
// of each FIFO. CRT FIFO thresholds during non-video window lines
// are determined by SR16(3:0). CRT FIFO thresholds during video
// window lines are determined by CR5C(3:0).
// The VCAP fifo threshold is a fixed setting of 8 QWORDS (half).
//
// The 4 bit threshold for FIFOs A,B, and C indicate the FIFO
// level in double QWORDS at which the FIFO request is asserted.
// For example, a setting of 4 indicates that the request is
// generated when the FIFO level is reduced to 8 QWORDS.
// A setting of 0 is a special case which indicates that the
// FIFO must be full to prevent a request (i.e. 32 QWORDS).
//
// The objective of the bandwidth equations is to calculate
// the optimum threshold setting and determine which display
// modes may be supported for given MCLK and VCLK frequencies.
//
// The critical parameters which determine the bandwidth limits
// are the read and effective write rates for each FIFO.
//
// -------------------------------------------------------------
// FIFO read/write rates for CRT FIFOs
// -------------------------------------------------------------
// The read rate for FIFO A (graphics FIFO) is determined by
// the graphics pixel depth and the VCLK frequency.
// fa_read_rate = gr_bytes_per_pixel * vclk_period
//
// The read rates for FIFO B and C are determined differently
// depending on display mode. For 420 format the read periods
// in nanosecs per byte are as follows:
// fb_read_period = ((vclk_period*4) * hzoom) / hdecimate;
// fc_read_period = ((vclk_period*4) * hzoom) / hdecimate;
//
// In this equation hdecimate is specified as 1/decimation_scale,
// i.e a 1/2 decimate implies hdecimate = 2
//
// For non 420 format the rates are:
// fb_read_period = ((vclk_period/vw_bytes_per_pixel) * hzoom) /
// hdecimate;
// fc_read_period = (vclk_period/vw_bytes_per_pixel);
//
// Since the FIFOs can be read and written simultaneously,
// the effective write rate is determined by the actual fifo
// write rate and tje fifo read rate. The actual write rate is based
// on single mclk display memory reads. The memory read period is
// calculated in terms of nanoseconds per byte.
//
// bytes_per_memory_transfer is equal to 4 for 32 bit i/f, 8 for 64 bit i/f
// mem_read_period = mclk_period/bytes_per_mem_transfer
// fa_eff_write_period = (mem_read_period * fa_read_period)/
// (fa_read_period - mem_read_period);
// fb_eff_write_period = (mem_read_period * fb_read_period)/
// (fb_read_period - mem_read_period);
// fc_eff_write_period = (mem_read_period * fc_read_period)/
// (fc_read_period - mem_read_period);
// -------------------------------------------------------------
// FIFO read/write rates for VCAP fifo
// -------------------------------------------------------------
// The video capture write rate is based on the data rate
// from the video capture interface. Since the video capture
// interface can perform format conversion (e.g. 422->PackJR) and
// decimation, the capture data rate may be smaller than the actual
// video port data rate. The capture period in the following equation
// is defined in terms of nanoseconds per byte. The decimation factor
// may vary from 1 to 1/256.
//
// vcap_write_period = (vport_pixel_period/capture_bytes_per_pixel) *
// (vport_decimation);
// In this equation vport_decimation is specified as 1/decimation_scale,
// i.e a 1/2 decimate implies vport_decimation = 2
//
//
// Since the VCAP fifo can be read and written simultaneously,
// the effective read rate is determined by the fifo write rate as well
// as the actual fifo read rate. The actual fifo read rate is based on two
// memory clock cycle display memory writes. The calculations are in terms
// of nanoseconds per byte.
// bytes_per_memory_transfer = 4 for 32 bit i/f, or 8 for 64 bit i/f
// mem_write_period = 2 * mclk_period/bytes_per_mem_transfer
//
// vcap_eff_read_period = (mem_write_period * vcap_write_period)/
// (vcap_write_period - mem_write_period);
//
// -------------------------------------------------------------------
// How to determine if FIFO ABC underflow or VCAP fifo overflow occurs
// -------------------------------------------------------------------
//
// I will examine a few worst case scenarios to determine if adequate
// bandwidth exists to support a given mode.
//
// Case #1 - start of graphics line where all 3 CRT fifos must be filled
//
// This condition occurs after hsync when the 3 CRT FIFOs are being
// prefilled before the start of the active line. The only risk here is
// that the video capture fifo may overflow during the consecutive fills
// of fifos A,B, and C. The threshold setting does not matter since the
// CRT fifos are cleared on reset and thus guaranteed to be empty.
//
// For a 32 bit memory interface :
// fabc_fill_time = (BLIT_LATENCY * mclk_period) +
// 3 * ((RAS_PRECHARGE + 64) * mclk_period)
//
// For a 64 bit memory interface :
// fabc_fill_time = (BLIT_LATENCY * mclk_period) +
// 3 * ((RAS_PRECHARGE + 32) * mclk_period)
//
// A capture fifo overflow occurs if fabc_fill_time is greater than
// VCAP fill time based on the worst case 30 MB/s capture rate.
//
// For a worst case memory interface scenario, let's assume a 32 bit
// interface with a 66 MHz memory clock, a blit latency of 10 mclks,
// and a ras precharge of 7 mclks. The fabc_fill_time is
// then
// fabc_fill_time = (10 * 15.2) +
// 3 * ((64 + 7) * 15.2) = 3390 ns
//
// Assuming the worst case 30 MB/s capture rate, the number of
// bytes written to the capture fifo during the fabc_fill_time is
// 3390 ns * (1 byte/33 ns) = 103 bytes
//
// Since the capture fifo is 128 bytes deep, the worst case scenario
// is OK so long as the capture fifo is emptied prior to the fabc_fill.
//
//
//
// Case #2 - Consecutive requests
//
// It seems that the worst case for servicing of requests is when the requests occur
// on consecutive mclks with the order of requests being from the slowest to the
// fastest data consumer. In other words, the first to be serviced is the capture fifo,
// then the 3 CRT fifos in the order of decreasing read_period.
//
// First calculate actual and effective read and write periods as decribed above.
// Then determine how many requests are active, this is a maximum of 4 if capture
// is enabled and all 3 CRT fifos are enabled. Assume that the capture rate
// is the slowest and thus is always serviced first. Then order the active
// CRT requests as f1 through f3, where f1 has the longest read period and
// f3 has the shortest.
//
// The sequence of events then becomes:
// empty vcap -> fill 1 -> fill 2 -> fill 3
//
//
// Depending on the number of active crt fifos, the fill 2 and fill 3 operations may
// be ommitted. The vcap empty is obviously ommitted if capture is not enabled.
//
// Now step through the sequence and verify that crt fifo underflows and capture
// underflows do not occur.
//
// If capture is enabled, calculate the latency and empty times
// vcap_latency = (BLIT_LATENCY + RAS_PRECHARGE) * mclk_period;
// vcap_bytes_to_empty = CAP_FIFO_DEPTH;
// vcap_empty_time = (vcap_read_period * vcap_bytes_to_empty);
// Since one of the capture fifos continues to fill while the other is being
// emptied, calculate the number of filled levels in the capture fifo at
// the end of the memory transfer.
// vcap_levels_remaining = (vcap_latency + vcap_empty_time)/vcap_write_period;
// If the number of levels filled exceeds the fifo depth, then an overflow occurred.
//
// Note that the VCAP FIFO operates differently than the CRT fifos. The VCAP
// FIFO operates as 2 8x64 FIFOs. A memory request is asserted when one of the
// FIFOs is full. The capture interface then fills the other fifo while the
// full fifo is being serviced by the sequencer. Using this method, the transfer
// to memory is always 16 QWORDs for VCAP data (except special end of line conditions).
//
// Now check fifo 1. If capture was enabled then the latency for fifo 1 is:
// f1_latency = vcap_latency + vcap_empty_time +
// (BLIT_LATENCY + RAS_PRECHARGE) * mclk_period;
//
// otherwise the latency is:
// f1_latency = (BLIT_LATENCY + RAS_PRECHARGE) * mclk_period;
//
// Calculate the number of empty levels in fifo 1, i.e. the number of bytes
// that must be filled.
// f1_bytes_to_fill = ((16-threshold) * 16) + (f1_latency/f1_read_period);
// If the number of levels to be filled exceeds the fifo depth, then an underflow occurred.
// Calculate the fill time based on the effective fifo write rate.
// f1_fill_time = (f1_eff_write_period * f1_bytes_to_fill);
//
// If fifo_2 is active, calculate its latency and bytes to be filled.
// f2_latency = f1_latency + f1_fill_time +
// (RAS_PRECHARGE * mclk_period);
// f2_bytes_to_fill = ((16-threshold) * 16) + (f2_latency/f2_read_period);
// If the number of levels to be filled exceeds the fifo depth, then an underflow occurred.
// Calculate the fill time based on the effective fifo write rate.
// f2_fill_time = (f2_eff_write_period * f2_bytes_to_fill);
//
// If fifo_2 is active, calculate its latency and bytes to be filled.
// f3_latency = f2_latency + f2_fill_time +
// (RAS_PRECHARGE * mclk_period);
// f3_bytes_to_fill = ((16-threshold) * 16) + (f3_latency/f3_read_period);
// If the number of levels to be filled exceeds the fifo depth, then an underflow occurred.
// Calculate the fill time based on the effective fifo write rate.
// f3_fill_time = (f3_eff_write_period * f3_bytes_to_fill);
//
// Now go back to the start of sequence and make sure that none of the FIFOs
// have already initiated another request. The totla latency is the amount
// of time required to execute the entire sequence.
//
// Check vcap fif status if capture is enabled,
// vcap_latency = total_latency;
// vcap_bytes_to_empty = (total_latency/vcap_write_period);
//
// Check fifo 1 status
// f1_latency = (total_latency - f1_latency - f1_fill_time);
// f1_bytes_to_fill = (f1_latency/f1_read_period);
//
// Check fifo 2 status if active
// f2_latency = (total_latency - f1_latency - f1_fill_time);
// f3_bytes_to_fill = (f1_latency/f1_read_period);
//
//***************************************************************************
static BOOL Is5480SufficientBandwidth (PDEV* ppdev, WORD wVideoDepth, LPRECTL lpSrc, LPRECTL lpDest, DWORD dwFlags) { long lVideoPixelsPerDWORD; long lGraphicsPixelsPerDWORD; long lCapturePixelsPerDWORD; long lVideoBytesPerPixel; long lGraphicsBytesPerPixel; long lCaptureBytesPerPixel; long lVCLKPeriod; long lZoom; long lFifoAReadPeriod; long lFifoBReadPeriod; long lFifoCReadPeriod; long lFifoAEffWritePeriod; long lFifoBEffWritePeriod; long lFifoCEffWritePeriod; long lMemReadPeriod; long lVPortPixelPeriod; long lVCapReadPeriod; long lVCapWritePeriod; long lFifo1ReadPeriod; long lFifo2ReadPeriod; long lFifo3ReadPeriod; long lFifo1EffWritePeriod; long lFifo2EffWritePeriod; long lFifo3EffWritePeriod; long lVCapLatency; long lVCapBytesToEmpty; long lVCapEmptyTime; long lVCapLevelRemaining; long lFifo1Latency; long lFifo1BytesToFill; long lFifo1FillTime; long lFifo2Latency; long lFifo2BytesToFill; long lFifo2FillTime; long lFifo3Latency; long lFifo3BytesToFill; long lFifo3FillTime; long lThreshold; int CrtFifoCount; BOOL bCapture; BOOL bFifoAEnable; BOOL bFifoBEnable; BOOL bFifoCEnable; BOOL bModePass; long lHorizDecimate; long lVPortDecimate; long lTotalLatency; long lVCLK; UCHAR tempB ; BYTE* pjPorts = ppdev->pjPorts ;
#define CAP_FIFO_DEPTH 64
#define RAS_PRECHARGE 7
#define BLIT_LATENCY 9
//
// Parameter checking
//
lHorizDecimate = 1; lVPortDecimate = 1;
//
// Convert input parameters
//
if (wVideoDepth == 16) { lVideoPixelsPerDWORD = 2; lCapturePixelsPerDWORD = 2; } else if (wVideoDepth == 8) { lVideoPixelsPerDWORD = 4; lCapturePixelsPerDWORD = 4; } else return (FALSE);
if (ppdev->cBitsPerPixel == 8) { lGraphicsPixelsPerDWORD = 4; } else if (ppdev->cBitsPerPixel == 16) { lGraphicsPixelsPerDWORD = 2; } else if (ppdev->cBitsPerPixel == 24) { lGraphicsPixelsPerDWORD = 1; } else return (FALSE);
lGraphicsBytesPerPixel = 4 / lGraphicsPixelsPerDWORD; lVideoBytesPerPixel = 4 / lVideoPixelsPerDWORD; lCaptureBytesPerPixel = 4 / lCapturePixelsPerDWORD;
lZoom = (lpDest->right - lpDest->left) / (lpSrc->right - lpSrc->left);
if (lZoom < 1) lZoom = 1;
//
// We need to get the VCLK every time since this can change at run-time
//
lVCLK = GetVCLK(ppdev); lVCLKPeriod = (long) ((1024000000l/lVCLK) + 1);
//
// Video port at 13.5 MHz
//
lVPortPixelPeriod = (long) ((10240000) / 135);
//
// Graphics CRT FIFO read rate
//
lFifoAReadPeriod = lGraphicsBytesPerPixel * lVCLKPeriod;
//
// Video FIFO read rate
//
if(dwFlags & OVERLAY_FLG_YUVPLANAR) { lFifoBReadPeriod = ((lVCLKPeriod * 4) * lZoom) / lHorizDecimate; lFifoCReadPeriod = ((lVCLKPeriod * 4) * lZoom) / lHorizDecimate; } else { lFifoBReadPeriod = ((lVCLKPeriod / lVideoBytesPerPixel) * lZoom) / lHorizDecimate; lFifoCReadPeriod = lVCLKPeriod / lVideoBytesPerPixel; }
DISPDBG ((2, "lFifoAReadPeriod = %ld, lFifoBReadPeriod=%ld\n", lFifoAReadPeriod, lFifoBReadPeriod));
DISPDBG ((2, "lFifoCReadPeriod = %ld\n", lFifoCReadPeriod));
//
// Video capture write period
//
lVCapWritePeriod = (lVPortPixelPeriod / lCaptureBytesPerPixel) * lVPortDecimate;
if (!ppdev->lBusWidth) { //
// We will read the bus width from SR0F[4:3]
//
CP_OUT_BYTE (pjPorts, SR_INDEX, 0x0F) ;
if ((CP_IN_BYTE(pjPorts, SR_DATA) & 0x18) == 0x18) ppdev->lBusWidth = 8; // 64 bit bus
else ppdev->lBusWidth = 4; // 32 bit bus
}
if (!ppdev->lMCLKPeriod) { LONG lMCLK;
//
// The MCLK period is the amount of time required for one cycle.
// We will round up.
//
CP_OUT_BYTE (pjPorts, SR_INDEX, 0x1F) ; // First get the MCLK frequency
lMCLK = CP_IN_BYTE(pjPorts, SR_DATA); lMCLK *= 14318; lMCLK >>= 3; ppdev->lMCLKPeriod = (long) ((1024000000l/lMCLK) + 1); }
//
// Calculate CRT effective read and write periods
//
lMemReadPeriod = ppdev->lMCLKPeriod / ppdev->lBusWidth;
if (lFifoAReadPeriod == lMemReadPeriod) lFifoAEffWritePeriod = 1000000000; else lFifoAEffWritePeriod = (lMemReadPeriod * lFifoAReadPeriod) / (lFifoAReadPeriod - lMemReadPeriod);
if (lFifoBReadPeriod == lMemReadPeriod) lFifoBEffWritePeriod = 1000000000; else lFifoBEffWritePeriod = (lMemReadPeriod * lFifoBReadPeriod) / (lFifoBReadPeriod - lMemReadPeriod);
if (lFifoCReadPeriod == lMemReadPeriod) lFifoCEffWritePeriod = 1000000000; else lFifoCEffWritePeriod = (lMemReadPeriod * lFifoCReadPeriod) / (lFifoCReadPeriod - lMemReadPeriod);
//
// Video capture read period
//
lVCapReadPeriod = (2 * ppdev->lMCLKPeriod) / ppdev->lBusWidth;
if (dwFlags & OVERLAY_FLG_CAPTURE) // is capture enable ?
bCapture = TRUE; else bCapture = FALSE;
if (dwFlags & OVERLAY_FLG_YUVPLANAR) // is 420 format
{ if (dwFlags & (OVERLAY_FLG_COLOR_KEY | OVERLAY_FLG_SRC_COLOR_KEY)) // occlusion
{ // one video window, occlusion, 420 format
bFifoAEnable = TRUE; bFifoBEnable = TRUE; bFifoCEnable = TRUE; } else { // one video window, no occlusion, 420 format
bFifoAEnable = FALSE; bFifoBEnable = TRUE; bFifoCEnable = TRUE; } } else // not 420 format
{ if (dwFlags & (OVERLAY_FLG_COLOR_KEY | OVERLAY_FLG_SRC_COLOR_KEY)) // occlusion
{ if (dwFlags & OVERLAY_FLG_TWO_VIDEO) { // Two video windows, occlusion, not 420 format
bFifoAEnable = TRUE; bFifoBEnable = TRUE; bFifoCEnable = TRUE; } else { // one video window, occlusion, not 420 format
bFifoAEnable = TRUE; bFifoBEnable = TRUE; bFifoCEnable = FALSE; } } else { // one video window, no occlusion, not 420 format
bFifoAEnable = FALSE; bFifoBEnable = TRUE; bFifoCEnable = FALSE; } }
DISPDBG ((4, " FIFOA = %s, FIFOB= %s, FIFOC = %s\n", bFifoAEnable ? "yes" : "no", bFifoBEnable ? "yes" : "no", bFifoCEnable ? "yes" : "no"));
lFifo1ReadPeriod = 0; lFifo2ReadPeriod = 0; lFifo3ReadPeriod = 0;
if (bFifoAEnable) { if (((lFifoAReadPeriod >= lFifoBReadPeriod) || !bFifoBEnable) && // A slower than or equal than B) and
((lFifoAReadPeriod >= lFifoCReadPeriod) || !bFifoCEnable)) // A slower than or equal C
{ lFifo1ReadPeriod = lFifoAReadPeriod; lFifo1EffWritePeriod = lFifoAEffWritePeriod; } else if (((lFifoAReadPeriod >= lFifoBReadPeriod) || !bFifoBEnable) || // A slower than or equal B
((lFifoAReadPeriod >= lFifoCReadPeriod) || !bFifoCEnable)) // A slower than or equal C
{ lFifo2ReadPeriod = lFifoAReadPeriod; lFifo2EffWritePeriod = lFifoAEffWritePeriod; } else // A not slower than A or B
{ lFifo3ReadPeriod = lFifoAReadPeriod; lFifo3EffWritePeriod = lFifoAEffWritePeriod; } }
DISPDBG ((2, "After bFifoAEnable")) ; DISPDBG ((2, "lFifo1ReadPeriod = %ld, lFifo2ReadPeriod=%ld", lFifo1ReadPeriod, lFifo2ReadPeriod)) ; DISPDBG ((2, "lFifo3ReadPeriod = %ld", lFifo3ReadPeriod)) ;
if (bFifoBEnable) { if (((lFifoBReadPeriod > lFifoAReadPeriod) || !bFifoAEnable) && // B slower than A and
((lFifoBReadPeriod >= lFifoCReadPeriod) || !bFifoCEnable)) // slower than or equal A
{ lFifo1ReadPeriod = lFifoBReadPeriod; lFifo1EffWritePeriod = lFifoBEffWritePeriod; } else if (((lFifoBReadPeriod > lFifoAReadPeriod) || !bFifoAEnable) || // B slower than A or
((lFifoBReadPeriod >= lFifoCReadPeriod) || !bFifoCEnable)) // B slower than or equal C
{
lFifo2ReadPeriod = lFifoBReadPeriod; lFifo2EffWritePeriod = lFifoBEffWritePeriod;
} else // (B not slower than A ) and (B not slower than or equal C)
{ lFifo3ReadPeriod = lFifoBReadPeriod; lFifo3EffWritePeriod = lFifoBEffWritePeriod; } }
DISPDBG ((4, "After bFifoBEnable")) ; DISPDBG ((4, "lFifo1ReadPeriod = %ld, lFifo2ReadPeriod=%ld", lFifo1ReadPeriod, lFifo2ReadPeriod)) ; DISPDBG ((4, "lFifo3ReadPeriod = %ld", lFifo3ReadPeriod)) ;
if (bFifoCEnable) { if (((lFifoCReadPeriod > lFifoAReadPeriod) || !bFifoAEnable) && // C slower than A and
((lFifoCReadPeriod > lFifoBReadPeriod) || !bFifoBEnable)) // C slower than B
{ lFifo1ReadPeriod = lFifoCReadPeriod; lFifo1EffWritePeriod = lFifoCEffWritePeriod; } else if (((lFifoCReadPeriod > lFifoAReadPeriod) || !bFifoAEnable) || // C slower than A or
((lFifoCReadPeriod > lFifoBReadPeriod) || !bFifoBEnable)) // C slower than B
{ lFifo2ReadPeriod = lFifoCReadPeriod; lFifo2EffWritePeriod = lFifoCEffWritePeriod; } else { // C not slower than A and C not slower than B
lFifo3ReadPeriod = lFifoCReadPeriod; lFifo3EffWritePeriod = lFifoCEffWritePeriod; } }
DISPDBG ((4, "After bFifoCEnable")) ; DISPDBG ((4, "lFifo1ReadPeriod = %ld, lFifo2ReadPeriod=%ld", lFifo1ReadPeriod, lFifo2ReadPeriod)) ; DISPDBG ((4, "lFifo3ReadPeriod = %ld", lFifo3ReadPeriod)) ; DISPDBG ((4, "lFifo1EffWritePeriod = %ld, lFifo2EffWritePeriod = %ld", lFifo1EffWritePeriod, lFifo2EffWritePeriod)) ; DISPDBG ((4, " lFifo3EffWritePeriod = %ld", lFifo3EffWritePeriod)) ; DISPDBG ((4, " lFifoAEffWritePeriod = %ld, lFifoBEffWritePeriod = %ld", lFifoAEffWritePeriod, lFifoBEffWritePeriod)) ; DISPDBG ((4, " lFifoCEffWritePeriod = %ld", lFifoCEffWritePeriod)) ;
bModePass = FALSE; lThreshold = 1;
CrtFifoCount = 0; if (bFifoAEnable) CrtFifoCount++; if (bFifoBEnable) CrtFifoCount++; if (bFifoCEnable) CrtFifoCount++;
while ((!bModePass) && (lThreshold < 16)) { bModePass = TRUE; // assume pass until proven otherwise.
//
// Checking capture
//
if (bCapture) { lVCapLatency = (BLIT_LATENCY + RAS_PRECHARGE) * ppdev->lMCLKPeriod; lVCapBytesToEmpty = CAP_FIFO_DEPTH; lVCapEmptyTime = lVCapReadPeriod * lVCapBytesToEmpty; lVCapLevelRemaining = (lVCapLatency + lVCapEmptyTime) / lVCapWritePeriod; if (lVCapLevelRemaining > CAP_FIFO_DEPTH) return(FALSE); }
//
// Fill FIFO 1
//
if (bCapture) lFifo1Latency = lVCapLatency + lVCapEmptyTime + (BLIT_LATENCY + RAS_PRECHARGE) * ppdev->lMCLKPeriod; else lFifo1Latency = (BLIT_LATENCY + RAS_PRECHARGE) * ppdev->lMCLKPeriod;
lFifo1BytesToFill = ((16 - lThreshold) * 16) + (lFifo1Latency / lFifo1ReadPeriod); lFifo1FillTime = lFifo1EffWritePeriod * lFifo1BytesToFill; if (lFifo1BytesToFill > 256) bModePass = FALSE;
DISPDBG ((4, "After Fill FIFO1, lFifo1BytesToFillb=%ld, ModePass = %s", lFifo1BytesToFill, bModePass ? "yes" : "no")) ; DISPDBG ((4, "f1_latency=%ld, f1_read_period=%ld", lFifo1Latency, lFifo1ReadPeriod)) ; DISPDBG ((4, "mclkperiod= %ld, vclkperiod=%ld", ppdev->lMCLKPeriod, lVCLKPeriod)) ;
//
// Fill FIFO 2
//
if (CrtFifoCount > 1) { lFifo2Latency = lFifo1Latency + lFifo1FillTime + (RAS_PRECHARGE * ppdev->lMCLKPeriod); lFifo2BytesToFill = ((16 - lThreshold) * 16) + (lFifo2Latency / lFifo2ReadPeriod); lFifo2FillTime = lFifo2EffWritePeriod * lFifo2BytesToFill; if (lFifo2BytesToFill > 256) bModePass = FALSE; } else { lFifo2Latency = lFifo1Latency + lFifo1FillTime; lFifo2BytesToFill = 0; lFifo2FillTime = 0; }
DISPDBG ((4, "After Fill FIFO2, lFifo2BytesToFill=%ld, ModePass = %s", lFifo2BytesToFill, bModePass ? "yes" : "no"));
//
// Fill FIFO 3
//
if (CrtFifoCount > 2) { lFifo3Latency = lFifo2Latency + lFifo2FillTime + (RAS_PRECHARGE * ppdev->lMCLKPeriod); lFifo3BytesToFill = ((16 - lThreshold) * 16) + (lFifo3Latency / lFifo3ReadPeriod); lFifo3FillTime = lFifo3EffWritePeriod * lFifo3BytesToFill; if (lFifo3BytesToFill > 256) bModePass = FALSE; } else { lFifo3Latency = lFifo2Latency + lFifo2FillTime; lFifo3BytesToFill = 0; lFifo3FillTime = 0; }
DISPDBG ((4, "After Fill FIFO3, lFifo3BytesToFill=%ld, ModePass = %s", lFifo3BytesToFill, bModePass ? "yes" : "no")) ;
//
// Determine total latency through the sequence
//
lTotalLatency = lFifo3Latency + lFifo3FillTime;
//
// Now back to start of sequence, make sure that none of the FIFOs
// have already initiated another request.
//
//
// Check capture FIFO status
//
if (bCapture) { lVCapLatency = lTotalLatency; lVCapBytesToEmpty = lTotalLatency / lVCapWritePeriod; if (lVCapBytesToEmpty > CAP_FIFO_DEPTH) bModePass = FALSE; }
//
// Check FIFO 1 status
//
lFifo1Latency = lTotalLatency - lFifo1Latency - lFifo1FillTime; lFifo1BytesToFill = lFifo1Latency / lFifo1ReadPeriod; if (lFifo1BytesToFill > ((16 - lThreshold) * 16)) bModePass = FALSE;
DISPDBG ((4, "After CheckF FIFO1, fifo1bytestofill %ld,bModePass = %s", lFifo1BytesToFill, bModePass ? "yes" : "no")) ;
//
// Check FIFO 2 status
//
if (CrtFifoCount > 1) { lFifo2Latency = lTotalLatency - lFifo2Latency - lFifo2FillTime; lFifo2BytesToFill = lFifo2Latency / lFifo2ReadPeriod; if (lFifo2BytesToFill > ((16 - lThreshold) * 16)) bModePass = FALSE;
DISPDBG ((4, "After Check FIFO 2, fifo1bytestofill=%ld, bModePass = %s", lFifo2BytesToFill, bModePass ? "yes" : "no")) ;
}
if (!bModePass) lThreshold++;
}
if (bModePass) {
DISPDBG ((1, "Is sufficient Bandwidth, thresh = %ld, return TRUE\n", lThreshold));
if (ppdev->cBitsPerPixel == 24) lThreshold = 0x0F;
ppdev->lFifoThresh = lThreshold;
return TRUE ; }
DISPDBG ((2, "Is sufficient Bandwidth, thresh = %ld, rerurn FALSE", lThreshold)); return FALSE;
}
/**********************************************************
* * Name: GetVCLK * * Module Abstract: * ---------------- * Returns the VCLK frequency * 1000. * * Input Parameters: * ----------------- * none * * Output Parameters: * ------------------ * MCLK * *********************************************************** * Author: Shuhua Ge * Date: 09/25/96 * * Revision History: * ----------------- * WHO WHEN WHAT/WHY/HOW * --- ---- ------------ * *********************************************************/
LONG GetVCLK(PDEV* ppdev) { LONG lTemp; LONG lRegSR1F; LONG lRegMISC; LONG lNR; LONG lDR; LONG lPS; BYTE* pjPorts = ppdev->pjPorts;
/*
* First read SR1F. This tells us if VCLK is derived from MCLK * or if it's derived normally. */ CP_OUT_BYTE(pjPorts, SR_INDEX, 0x1f); lRegSR1F = (LONG) CP_IN_BYTE(pjPorts, SR_DATA); if (lRegSR1F & 0x40) { LONG lMCLK;
/*
* It is derived from MCLK, but now we need to read SR1E to see * if VCLK = MCLK or if VCLK = MCLK/2. */ lMCLK = (lRegSR1F & 0x3F) * 14318; CP_OUT_BYTE(pjPorts, SR_INDEX, 0x1e); if (CP_IN_BYTE(pjPorts, SR_DATA) & 0x01) { return (lMCLK >> 4); } else { return (lMCLK >> 3); } } else { /*
* Read MISC[3:2], which tells us where to find our VCLK */ lRegMISC = (LONG) CP_IN_BYTE(pjPorts, 0x3cc); lRegMISC >>= 2;
//myf33 begin
CP_OUT_BYTE(pjPorts, CRTC_INDEX, (BYTE)0x80); if (((ppdev->ulChipID == CL7555_ID) || (ppdev->ulChipID == CL7556_ID)) && (CP_IN_BYTE(pjPorts, CRTC_DATA) & 0x01)) lRegMISC &= 0x02; // Fixed PDR 8709
else //myf33 end
lRegMISC &= 0x03;
lNR = 0x0B + lRegMISC; lDR = 0x1B + lRegMISC;
/*
* Read the values for bP, bDR, and bNR */ CP_OUT_BYTE(pjPorts, SR_INDEX, (BYTE) lDR); lPS = lDR = (LONG)CP_IN_BYTE(pjPorts, SR_DATA); CP_OUT_BYTE(pjPorts, SR_INDEX, (BYTE) lNR); lNR = (LONG)CP_IN_BYTE(pjPorts, SR_DATA); lPS &= 0x01; lPS += 1; lDR >>= 1; //
// Extended the VCLK bits.
//
// sge06
lDR &= 0x7f; lNR &= 0x7f;
/*
* VCLK = (14.31818 * bNR) / (bDR * bPS) */ lTemp = (14318 * lNR); if (!lPS || !lDR) { return (0); } lTemp /= (lDR * lPS); }
return (lTemp); } /**********************************************************
* * Name: EnableStartAddrDoubleBuffer * * Module Abstract: * ---------------- * Enable the double buffering of the start addresses. This allows the page * flipping operation to proceed without the system CPU waiting for VRT. * * Input Parameters: * ----------------- * none * * Output Parameters: * ------------------ * *********************************************************** * Author: Shuhua Ge * Date: 10/01/96 * * Revision History: * ----------------- * WHO WHEN WHAT/WHY/HOW * --- ---- ------------ * *********************************************************/ VOID EnableStartAddrDoubleBuffer(PDEV* ppdev) {
BYTE* pjPorts = ppdev->pjPorts; BYTE cTemp;
CP_OUT_BYTE(pjPorts, CRTC_INDEX, 0x1a); cTemp = CP_IN_BYTE(pjPorts, CRTC_DATA); CP_OUT_BYTE(pjPorts, CRTC_DATA, cTemp | 2); }
/**********************************************************
* * Name: GetCurrentVLine * * Module Abstract: * ---------------- * Get the current scan line * * Input Parameters: * ----------------- * none * * Output Parameters: * ------------------ * *********************************************************** * Author: Shuhua Ge * Date: 10/01/96 * * Revision History: * ----------------- * WHO WHEN WHAT/WHY/HOW * --- ---- ------------ * *********************************************************/ DWORD GetCurrentVLine(PDEV* ppdev) {
DWORD dwLine; BYTE cTemp; BYTE* pjPorts = ppdev->pjPorts;
CP_OUT_BYTE(pjPorts, INDEX_REG, 0x16); /* Index to the low byte. */ dwLine = (ULONG)CP_IN_BYTE(pjPorts, DATA_REG);
CP_OUT_BYTE(pjPorts, INDEX_REG, 0x17); /* Index to the high bits. */ cTemp = CP_IN_BYTE(pjPorts, DATA_REG); dwLine |= (cTemp & 3) << 8;
CP_OUT_BYTE(pjPorts, INDEX_REG, 0x16); /* Index to the low byte. */
/* If we wrapped around while getting the high bits we have a problem. */ /* The high bits may be wrong. */ if((CP_IN_BYTE(pjPorts, DATA_REG)) < (dwLine & 0xff)) { DISPDBG((1, "Recursive call to GetCurrentVLine.")); return GetCurrentVLine(ppdev); } if (dwLine > ppdev->dwVsyncLine) { return 0; } return dwLine; } #endif
#endif // DIRECTDRAW
|