5546 lines
182 KiB
C
5546 lines
182 KiB
C
/******************************************************************************\
|
||
*
|
||
* 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
|