Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

509 lines
16 KiB

/***************************************************************************
*
* ******************************************
* * Copyright (c) 1996, Cirrus Logic, Inc. *
* * All Rights Reserved *
* ******************************************
*
* PROJECT: Laguna I (CL-GD546x) -
*
* FILE: ddflip.c
*
* AUTHOR: Benny Ng
*
* DESCRIPTION:
* This module implements the DirectDraw FLIP components
* for the Laguna NT driver.
*
* MODULES:
* vGetDisplayDuration()
* vUpdateFlipStatus()
* DdFlip()
* DdWaitForVerticalBlank()
* DdGetFlipStatus()
*
* REVISION HISTORY:
* 7/12/96 Benny Ng Initial version
*
* $Log: X:/log/laguna/nt35/displays/cl546x/ddflip.c $
*
* Rev 1.10 16 Sep 1997 15:04:06 bennyn
*
* Modified for NT DD overlay
*
* Rev 1.9 29 Aug 1997 17:42:20 RUSSL
* Added 65 overlay support
*
* Rev 1.8 11 Aug 1997 14:07:58 bennyn
*
* Enabled GetScanLine() (for PDR 10254)
*
****************************************************************************
****************************************************************************/
/*----------------------------- INCLUDES ----------------------------------*/
#include "precomp.h"
//
// This file isn't used in NT 3.51
//
#ifndef WINNT_VER35
/*----------------------------- DEFINES -----------------------------------*/
//#define DBGBRK
#define DBGLVL 1
#define CSL 0x00C4
#define CSL_5464 0x0140
/*--------------------- STATIC FUNCTION PROTOTYPES ------------------------*/
/*--------------------------- ENUMERATIONS --------------------------------*/
/*----------------------------- TYPEDEFS ----------------------------------*/
/*-------------------------- STATIC VARIABLES -----------------------------*/
/*-------------------------- GLOBAL FUNCTIONS -----------------------------*/
#if DRIVER_5465 && defined(OVERLAY)
// CurrentVLine is in ddinline.h for overlay
#else
/***************************************************************************
*
* FUNCTION: CurrentVLine
*
* DESCRIPTION:
*
****************************************************************************/
static __inline int CurrentVLine (PDEV* ppdev)
{
WORD cline;
PBYTE pMMReg = (PBYTE) ppdev->pLgREGS_real;
PWORD pCSL;
BYTE tmpb;
// on 5462 there is no CurrentScanLine register
// on RevAA of 5465 it's busted
if ((CL_GD5462 == ppdev->dwLgDevID) ||
((CL_GD5465 == ppdev->dwLgDevID) && (0 == ppdev->dwLgDevRev)))
return 0;
if (IN_VBLANK)
return 0;
// read current scanline
if (ppdev->dwLgDevID == CL_GD5464)
pCSL = (PWORD) (pMMReg + CSL_5464);
else
pCSL = (PWORD) (pMMReg + CSL);
cline = *pCSL & 0x0FFF;
// if scanline doubling is enabled, divide current scanline by 2
tmpb = (BYTE) LLDR_SZ (grCR9);
if (0x80 & tmpb)
cline /= 2;
// if current scanline is past end of visible screen return 0
if (cline >= ppdev->cyScreen)
return 0;
else
return cline;
}
#endif
/****************************************************************************
* FUNCTION NAME: vGetDisplayDuration
*
* DESCRIPTION: Get the length, in EngQueryPerformanceCounter() ticks,
* of a refresh cycle.
* (Based on S3 DirectDraw code)
****************************************************************************/
#define NUM_VBLANKS_TO_MEASURE 1
#define NUM_MEASUREMENTS_TO_TAKE 8
VOID vGetDisplayDuration(PFLIPRECORD pflipRecord)
{
LONG i, j;
LONGLONG li, liMin;
LONGLONG aliMeasurement[NUM_MEASUREMENTS_TO_TAKE + 1];
DISPDBG((DBGLVL, "DDraw - vGetDisplayDuration\n"));
#ifdef DBGBRK
DBGBREAKPOINT();
#endif
memset(pflipRecord, 0, sizeof(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(IN_VBLANK);
while(IN_DISPLAY);
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(IN_DISPLAY);
for (j = 0; j < NUM_VBLANKS_TO_MEASURE; j++)
{
while(IN_VBLANK);
while(IN_DISPLAY);
};
};
EngQueryPerformanceCounter(&aliMeasurement[NUM_MEASUREMENTS_TO_TAKE]);
// Use the minimum:
liMin = aliMeasurement[1] - aliMeasurement[0];
for (i = 2; i <= NUM_MEASUREMENTS_TO_TAKE; i++)
{
li = aliMeasurement[i] - aliMeasurement[i - 1];
if (li < liMin)
liMin = li;
};
// Round the result:
pflipRecord->liFlipDuration
= (DWORD) (liMin + (NUM_VBLANKS_TO_MEASURE / 2)) / NUM_VBLANKS_TO_MEASURE;
pflipRecord->liFlipTime = aliMeasurement[NUM_MEASUREMENTS_TO_TAKE];
pflipRecord->bFlipFlag = FALSE;
pflipRecord->fpFlipFrom = 0;
} // getDisplayDuration
/****************************************************************************
* FUNCTION NAME: vUpdateFlipStatus
*
* DESCRIPTION: Checks and sees if the most recent flip has occurred.
* (Based on S3 DirectDraw code)
****************************************************************************/
HRESULT vUpdateFlipStatus(PFLIPRECORD pflipRecord, FLATPTR fpVidMem)
{
LONGLONG liTime;
DISPDBG((DBGLVL, "DDraw - vUpdateFlipStatus\n"));
#ifdef DBGBRK
DBGBREAKPOINT();
#endif
// see if a flip has happened recently
if ((pflipRecord->bFlipFlag) &&
((fpVidMem == 0xFFFFFFFF) || (fpVidMem == pflipRecord->fpFlipFrom)))
{
if ((IN_VBLANK))
{
if (pflipRecord->bWasEverInDisplay)
pflipRecord->bHaveEverCrossedVBlank = TRUE;
}
else if (!(IN_DISPLAYENABLE))
{
if (pflipRecord->bHaveEverCrossedVBlank)
{
pflipRecord->bFlipFlag = FALSE;
return(DD_OK);
};
pflipRecord->bWasEverInDisplay = TRUE;
};
EngQueryPerformanceCounter(&liTime);
if (liTime - pflipRecord->liFlipTime <= pflipRecord->liFlipDuration)
{
return(DDERR_WASSTILLDRAWING);
};
pflipRecord->bFlipFlag = FALSE;
};
return(DD_OK);
} // updateFlipStatus
/****************************************************************************
* FUNCTION NAME: DdFlip
*
* DESCRIPTION:
* (Based on S3 DirectDraw code)
****************************************************************************/
DWORD DdFlip(PDD_FLIPDATA lpFlip)
{
DRIVERDATA* pDriverData;
PDEV* ppdev;
HRESULT ddrval;
ULONG ulMemoryOffset;
ULONG ulLowOffset;
ULONG ulMiddleOffset;
ULONG ulHighOffset;
BYTE tmpb;
DISPDBG((DBGLVL, "DDraw - DdFlip\n"));
#ifdef DBGBRK
DBGBREAKPOINT();
#endif
ppdev = (PDEV*) lpFlip->lpDD->dhpdev;
pDriverData = (DRIVERDATA*) &ppdev->DriverData;
SYNC_W_3D(ppdev);
#if DRIVER_5465 && defined(OVERLAY)
if (DDSCAPS_OVERLAY & lpFlip->lpSurfCurr->ddsCaps.dwCaps)
return pDriverData->OverlayTable.pfnFlip(ppdev,lpFlip);
#endif
// 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.
ddrval = vUpdateFlipStatus(&ppdev->flipRecord, 0xFFFFFFFF);
if ((ddrval != DD_OK) || (DrawEngineBusy(pDriverData)))
{
lpFlip->ddRVal = DDERR_WASSTILLDRAWING;
return(DDHAL_DRIVER_HANDLED);
};
// everything is OK, do the flip here
{
DWORD dwOffset;
// Determine the offset to the new area.
dwOffset = lpFlip->lpSurfTarg->lpGbl->fpVidMem >> 2;
// 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 (IN_DISPLAYENABLE)
;
// Flip the primary surface by changing CRD, CRC, CR1B and CR1D
// Do CRD last because the start address is double buffered and
// will take effect after CRD is updated.
// need bits 19 & 20 of address in bits 3 & 4 of CR1D
tmpb = (BYTE) LLDR_SZ (grCR1D);
tmpb = (tmpb & ~0x18) | (BYTE3FROMDWORD(dwOffset) & 0x18);
LL8(grCR1D, tmpb);
// need bits 16, 17 & 18 of address in bits 0, 2 & 3 of CR1B
tmpb = (BYTE) LLDR_SZ (grCR1B);
tmpb = (tmpb & ~0x0D) |
((((BYTE3FROMDWORD(dwOffset) & 0x06) << 1) |
(BYTE3FROMDWORD(dwOffset) & 0x01)));
LL8(grCR1B, tmpb);
// bits 8-15 of address go in CRC
LL8(grCRC, BYTE2FROMDWORD(dwOffset));
// bits 0-7 of address go in CRD
LL8(grCRD, BYTE1FROMDWORD(dwOffset));
};
// remember where/when we were when we did the flip
EngQueryPerformanceCounter(&ppdev->flipRecord.liFlipTime);
ppdev->flipRecord.bFlipFlag = TRUE;
ppdev->flipRecord.bHaveEverCrossedVBlank = FALSE;
ppdev->flipRecord.bWasEverInDisplay = FALSE;
ppdev->flipRecord.fpFlipFrom = lpFlip->lpSurfCurr->lpGbl->fpVidMem;
lpFlip->ddRVal = DD_OK;
return(DDHAL_DRIVER_HANDLED);
} // Flip
/****************************************************************************
* FUNCTION NAME: DdWaitForVerticalBlank
*
* DESCRIPTION:
****************************************************************************/
DWORD DdWaitForVerticalBlank(PDD_WAITFORVERTICALBLANKDATA lpWaitForVerticalBlank)
{
PDEV* ppdev;
DISPDBG((DBGLVL, "DDraw - DdWaitForVerticalBlank\n"));
#ifdef DBGBRK
DBGBREAKPOINT();
#endif
ppdev = (PDEV*) lpWaitForVerticalBlank->lpDD->dhpdev;
lpWaitForVerticalBlank->ddRVal = DD_OK;
switch (lpWaitForVerticalBlank->dwFlags)
{
case DDWAITVB_I_TESTVB:
// If TESTVB, it's just a request for the current vertical blank
// status:
lpWaitForVerticalBlank->bIsInVB = IN_VBLANK;
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(IN_VBLANK);
while(IN_DISPLAY);
return(DDHAL_DRIVER_HANDLED);
case DDWAITVB_BLOCKEND:
// If BLOCKEND is requested, we wait for the vblank interval to end:
while(IN_DISPLAY);
while(IN_VBLANK);
return(DDHAL_DRIVER_HANDLED);
default:
return DDHAL_DRIVER_NOTHANDLED;
}; // end switch
return(DDHAL_DRIVER_NOTHANDLED);
} // WaitForVerticalBlank
/****************************************************************************
* FUNCTION NAME: DdGetFlipStatus
*
* DESCRIPTION: 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)
{
DRIVERDATA* pDriverData;
PDEV* ppdev;
ppdev = (PDEV*) lpGetFlipStatus->lpDD->dhpdev;
pDriverData = (DRIVERDATA*) &ppdev->DriverData;
DISPDBG((DBGLVL, "DDraw - DdGetFlipStatus\n"));
#ifdef DBGBRK
DBGBREAKPOINT();
#endif
SYNC_W_3D(ppdev);
#if DRIVER_5465 && defined(OVERLAY)
if (DDSCAPS_OVERLAY & lpGetFlipStatus->lpDDSurface->ddsCaps.dwCaps)
{
DWORD dwVWIndex;
LP_SURFACE_DATA pSurfaceData = (LP_SURFACE_DATA) lpGetFlipStatus->lpDDSurface->dwReserved1;
dwVWIndex = GetVideoWindowIndex(pSurfaceData->dwOverlayFlags);
lpGetFlipStatus->ddRVal =
pDriverData->OverlayTable.pfnGetFlipStatus(ppdev,
lpGetFlipStatus->lpDDSurface->lpGbl->fpVidMem,
dwVWIndex);
}
else
#endif
{
// We don't want a flip to work until after the last flip is done,
// so we ask for the general flip status.
lpGetFlipStatus->ddRVal = vUpdateFlipStatus(&ppdev->flipRecord, 0xFFFFFFFF);
}
// Check if the bltter is busy if someone wants to know if they can flip
if (lpGetFlipStatus->dwFlags == DDGFS_CANFLIP)
{
if ((lpGetFlipStatus->ddRVal == DD_OK) && DrawEngineBusy(pDriverData))
lpGetFlipStatus->ddRVal = DDERR_WASSTILLDRAWING;
}
return(DDHAL_DRIVER_HANDLED);
} // GetFlipStatus
// #ifdef DDDRV_GETSCANLINE /************/
/****************************************************************************
* FUNCTION NAME: GetScanLine
*
* DESCRIPTION:
* (Based on Laguna Win95 DirectDraw code)
****************************************************************************/
DWORD GetScanLine(PDD_GETSCANLINEDATA lpGetScanLine)
{
PDEV* ppdev;
ppdev = (PDEV*) lpGetScanLine->lpDD->dhpdev;
// 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
SYNC_W_3D(ppdev); // if 3D context(s) active, make sure 3D engine idle before continuing...
if (IN_VBLANK)
{
lpGetScanLine->ddRVal = DDERR_VERTICALBLANKINPROGRESS;
}
else
{
lpGetScanLine->dwScanLine = CurrentVLine(ppdev);
lpGetScanLine->ddRVal = DD_OK;
};
return DDHAL_DRIVER_HANDLED;
} // GetScanLine
// #endif // DDDRV_GETSCANLINE ************
#endif // ! ver 3.51