663 lines
20 KiB
C
663 lines
20 KiB
C
|
/******************************Module*Header*******************************\
|
||
|
* Module Name: ddraw.c
|
||
|
*
|
||
|
* Implements all the DirectDraw components for the driver.
|
||
|
*
|
||
|
* Copyright (c) 1995-1996 Microsoft Corporation
|
||
|
\**************************************************************************/
|
||
|
|
||
|
#include "precomp.h"
|
||
|
|
||
|
#define VBLANK_IS_ACTIVE(pjBase) \
|
||
|
(READ_PORT_UCHAR(pjBase + VGA_BASE + IN_STAT_1) & 0x8)
|
||
|
|
||
|
#define DISPLAY_IS_ACTIVE(pjBase) \
|
||
|
(!(READ_PORT_UCHAR(pjBase + VGA_BASE + IN_STAT_1) & 0x1))
|
||
|
|
||
|
#define START_ADDRESS_HIGH 0x0C // Index for Frame Buffer Start
|
||
|
|
||
|
/******************************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.
|
||
|
*
|
||
|
\**************************************************************************/
|
||
|
|
||
|
#define NUM_VBLANKS_TO_MEASURE 1
|
||
|
#define NUM_MEASUREMENTS_TO_TAKE 8
|
||
|
|
||
|
VOID vGetDisplayDuration(
|
||
|
PDEV* ppdev)
|
||
|
{
|
||
|
BYTE* pjBase;
|
||
|
LONG i;
|
||
|
LONG j;
|
||
|
LONGLONG li;
|
||
|
LONGLONG liFrequency;
|
||
|
LONGLONG liMin;
|
||
|
LONGLONG aliMeasurement[NUM_MEASUREMENTS_TO_TAKE + 1];
|
||
|
|
||
|
pjBase = ppdev->pjBase;
|
||
|
|
||
|
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.
|
||
|
//
|
||
|
// Skip a couple of vertical blanks to allow the hardware to settle
|
||
|
// down after the mode change, to make our readings accurate:
|
||
|
|
||
|
for (i = 2; i != 0; i--)
|
||
|
{
|
||
|
while (VBLANK_IS_ACTIVE(pjBase))
|
||
|
;
|
||
|
while (!(VBLANK_IS_ACTIVE(pjBase)))
|
||
|
;
|
||
|
}
|
||
|
|
||
|
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 (!(VBLANK_IS_ACTIVE(pjBase)))
|
||
|
;
|
||
|
|
||
|
for (j = 0; j < NUM_VBLANKS_TO_MEASURE; j++)
|
||
|
{
|
||
|
while (VBLANK_IS_ACTIVE(pjBase))
|
||
|
;
|
||
|
while (!(VBLANK_IS_ACTIVE(pjBase)))
|
||
|
;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
EngQueryPerformanceCounter(&aliMeasurement[NUM_MEASUREMENTS_TO_TAKE]);
|
||
|
|
||
|
// Use the minimum:
|
||
|
|
||
|
liMin = aliMeasurement[1] - aliMeasurement[0];
|
||
|
|
||
|
DISPDBG((1, "Refresh count: %li - %li", 1, (ULONG) liMin));
|
||
|
|
||
|
for (i = 2; i <= NUM_MEASUREMENTS_TO_TAKE; i++)
|
||
|
{
|
||
|
li = aliMeasurement[i] - aliMeasurement[i - 1];
|
||
|
|
||
|
DISPDBG((1, " %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;
|
||
|
ppdev->flipRecord.bFlipFlag = FALSE;
|
||
|
ppdev->flipRecord.fpFlipFrom = 0;
|
||
|
|
||
|
// We need the refresh rate in Hz to query the S3 miniport about the
|
||
|
// streams parameters:
|
||
|
|
||
|
EngQueryPerformanceFrequency(&liFrequency);
|
||
|
|
||
|
DISPDBG((1, "Frequency %li.%03li Hz",
|
||
|
(ULONG) (EngQueryPerformanceFrequency(&li),
|
||
|
li / ppdev->flipRecord.liFlipDuration),
|
||
|
(ULONG) (EngQueryPerformanceFrequency(&li),
|
||
|
((li * 1000) / ppdev->flipRecord.liFlipDuration) % 1000)));
|
||
|
}
|
||
|
|
||
|
/******************************Public*Routine******************************\
|
||
|
* HRESULT ddrvalUpdateFlipStatus
|
||
|
*
|
||
|
* Checks and sees if the most recent flip has occurred.
|
||
|
*
|
||
|
* Unfortunately, the hardware has no ability to tell us whether a vertical
|
||
|
* retrace has occured since the flip command was given other than by
|
||
|
* sampling the vertical-blank-active and display-active status bits.
|
||
|
*
|
||
|
\**************************************************************************/
|
||
|
|
||
|
HRESULT ddrvalUpdateFlipStatus(
|
||
|
PDEV* ppdev,
|
||
|
FLATPTR fpVidMem)
|
||
|
{
|
||
|
BYTE* pjBase;
|
||
|
LONGLONG liTime;
|
||
|
|
||
|
pjBase = ppdev->pjBase;
|
||
|
|
||
|
if ((ppdev->flipRecord.bFlipFlag) &&
|
||
|
((fpVidMem == (FLATPTR) -1) ||
|
||
|
(fpVidMem == ppdev->flipRecord.fpFlipFrom)))
|
||
|
{
|
||
|
if (VBLANK_IS_ACTIVE(pjBase))
|
||
|
{
|
||
|
if (ppdev->flipRecord.bWasEverInDisplay)
|
||
|
{
|
||
|
ppdev->flipRecord.bHaveEverCrossedVBlank = TRUE;
|
||
|
}
|
||
|
}
|
||
|
else if (DISPLAY_IS_ACTIVE(pjBase))
|
||
|
{
|
||
|
if (ppdev->flipRecord.bHaveEverCrossedVBlank)
|
||
|
{
|
||
|
ppdev->flipRecord.bFlipFlag = FALSE;
|
||
|
return(DD_OK);
|
||
|
}
|
||
|
ppdev->flipRecord.bWasEverInDisplay = TRUE;
|
||
|
}
|
||
|
|
||
|
// It's pretty unlikely that we'll happen to sample the vertical-
|
||
|
// blank-active at the first vertical blank after the flip command
|
||
|
// has been given. So to provide better results, we also check the
|
||
|
// time elapsed since the flip. If it's more than the duration of
|
||
|
// one entire refresh of the display, then we know for sure it has
|
||
|
// happened:
|
||
|
|
||
|
EngQueryPerformanceCounter(&liTime);
|
||
|
|
||
|
if (liTime - ppdev->flipRecord.liFlipTime
|
||
|
<= ppdev->flipRecord.liFlipDuration)
|
||
|
{
|
||
|
return(DDERR_WASSTILLDRAWING);
|
||
|
}
|
||
|
|
||
|
ppdev->flipRecord.bFlipFlag = FALSE;
|
||
|
}
|
||
|
|
||
|
return(DD_OK);
|
||
|
}
|
||
|
|
||
|
/******************************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;
|
||
|
|
||
|
ppdev = (PDEV*) lpMapMemory->lpDD->dhpdev;
|
||
|
|
||
|
// By returning DDHAL_DRIVER_NOTHANDLED and setting 'bMap' to -1, we
|
||
|
// have GDI take care of mapping the section that is our 'shadow buffer'
|
||
|
// directly into the application's address space. We tell GDI our kernel
|
||
|
// mode address by sticking it in 'fpProcess':
|
||
|
|
||
|
lpMapMemory->fpProcess = (FLATPTR) ppdev->pjScreen;
|
||
|
lpMapMemory->bMap = (BOOL) -1;
|
||
|
|
||
|
return(DDHAL_DRIVER_NOTHANDLED);
|
||
|
}
|
||
|
|
||
|
/******************************Public*Routine******************************\
|
||
|
* DWORD DdWaitForVerticalBlank
|
||
|
*
|
||
|
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
|
||
|
* Wrote it.
|
||
|
\**************************************************************************/
|
||
|
|
||
|
DWORD DdWaitForVerticalBlank(
|
||
|
PDD_WAITFORVERTICALBLANKDATA lpWaitForVerticalBlank)
|
||
|
{
|
||
|
PDEV* ppdev;
|
||
|
BYTE* pjBase;
|
||
|
|
||
|
ppdev = (PDEV*) lpWaitForVerticalBlank->lpDD->dhpdev;
|
||
|
pjBase = ppdev->pjBase;
|
||
|
|
||
|
lpWaitForVerticalBlank->ddRVal = DD_OK;
|
||
|
|
||
|
switch (lpWaitForVerticalBlank->dwFlags)
|
||
|
{
|
||
|
case DDWAITVB_I_TESTVB:
|
||
|
lpWaitForVerticalBlank->bIsInVB = (VBLANK_IS_ACTIVE(pjBase) != 0);
|
||
|
break;
|
||
|
|
||
|
case DDWAITVB_BLOCKBEGIN:
|
||
|
while (VBLANK_IS_ACTIVE(pjBase))
|
||
|
;
|
||
|
while (!VBLANK_IS_ACTIVE(pjBase))
|
||
|
;
|
||
|
break;
|
||
|
|
||
|
case DDWAITVB_BLOCKEND:
|
||
|
while (!VBLANK_IS_ACTIVE(pjBase))
|
||
|
;
|
||
|
while (VBLANK_IS_ACTIVE(pjBase))
|
||
|
;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return(DDHAL_DRIVER_HANDLED);
|
||
|
}
|
||
|
|
||
|
/******************************Public*Routine******************************\
|
||
|
* DWORD DdLock
|
||
|
*
|
||
|
\**************************************************************************/
|
||
|
|
||
|
DWORD DdLock(
|
||
|
PDD_LOCKDATA lpLock)
|
||
|
{
|
||
|
PDEV* ppdev;
|
||
|
DD_SURFACE_LOCAL* lpSurfaceLocal;
|
||
|
|
||
|
ppdev = (PDEV*) lpLock->lpDD->dhpdev;
|
||
|
lpSurfaceLocal = lpLock->lpDDSurface;
|
||
|
|
||
|
if (lpSurfaceLocal->ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE)
|
||
|
{
|
||
|
// If the application is locking the currently visible flip
|
||
|
// surface, remember the bounds of its lock so that we can
|
||
|
// use it at Unlock time to update the physical display:
|
||
|
|
||
|
ppdev->cLocks++;
|
||
|
|
||
|
if ((ppdev->cLocks == 1) && (lpLock->bHasRect))
|
||
|
{
|
||
|
ppdev->rclLock = lpLock->rArea;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// If we were real keen, we would union the new area with
|
||
|
// the old. But we're not:
|
||
|
|
||
|
ppdev->rclLock.top = 0;
|
||
|
ppdev->rclLock.left = 0;
|
||
|
ppdev->rclLock.right = ppdev->cxScreen;
|
||
|
ppdev->rclLock.bottom = ppdev->cyScreen;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return(DDHAL_DRIVER_NOTHANDLED);
|
||
|
}
|
||
|
|
||
|
/******************************Public*Routine******************************\
|
||
|
* DWORD DdUnlock
|
||
|
*
|
||
|
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
|
||
|
* Wrote it.
|
||
|
\**************************************************************************/
|
||
|
|
||
|
DWORD DdUnlock(
|
||
|
PDD_UNLOCKDATA lpUnlock)
|
||
|
{
|
||
|
PDEV* ppdev;
|
||
|
DD_SURFACE_LOCAL* lpSurfaceLocal;
|
||
|
|
||
|
ppdev = (PDEV*) lpUnlock->lpDD->dhpdev;
|
||
|
lpSurfaceLocal = lpUnlock->lpDDSurface;
|
||
|
|
||
|
// If this flip buffer is visible, then we have to update the physical
|
||
|
// screen with the shadow contents.
|
||
|
|
||
|
if (lpSurfaceLocal->ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE)
|
||
|
{
|
||
|
vUpdate(ppdev, &ppdev->rclLock, NULL);
|
||
|
|
||
|
ppdev->cLocks--;
|
||
|
|
||
|
ASSERTDD(ppdev->cLocks >= 0, "Invalid lock count");
|
||
|
}
|
||
|
|
||
|
return(DDHAL_DRIVER_NOTHANDLED);
|
||
|
}
|
||
|
|
||
|
/******************************Public*Routine******************************\
|
||
|
* DWORD DdFlip
|
||
|
*
|
||
|
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
|
||
|
* Wrote it.
|
||
|
\**************************************************************************/
|
||
|
|
||
|
DWORD DdFlip(
|
||
|
PDD_FLIPDATA lpFlip)
|
||
|
{
|
||
|
PDEV* ppdev;
|
||
|
BYTE* pjBase;
|
||
|
HRESULT ddrval;
|
||
|
ULONG cDwordsPerPlane;
|
||
|
BYTE* pjSourceStart;
|
||
|
BYTE* pjDestinationStart;
|
||
|
BYTE* pjSource;
|
||
|
BYTE* pjDestination;
|
||
|
LONG iPage;
|
||
|
LONG i;
|
||
|
ULONG ul;
|
||
|
FLATPTR fpVidMem;
|
||
|
|
||
|
ppdev = (PDEV*) lpFlip->lpDD->dhpdev;
|
||
|
pjBase = ppdev->pjBase;
|
||
|
|
||
|
// 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.
|
||
|
|
||
|
ddrval = ddrvalUpdateFlipStatus(ppdev, (FLATPTR) -1);
|
||
|
if (ddrval != DD_OK)
|
||
|
{
|
||
|
lpFlip->ddRVal = DDERR_WASSTILLDRAWING;
|
||
|
return(DDHAL_DRIVER_HANDLED);
|
||
|
}
|
||
|
|
||
|
// Make the following page the current back-buffer. We always flip
|
||
|
// between three pages, so watch for our limit:
|
||
|
|
||
|
ppdev->cjVgaOffset += ppdev->cjVgaPageSize;
|
||
|
if (++ppdev->iVgaPage == ppdev->cVgaPages)
|
||
|
{
|
||
|
ppdev->iVgaPage = 0;
|
||
|
ppdev->cjVgaOffset = 0;
|
||
|
}
|
||
|
|
||
|
// Copy from the DIB surface to the current VGA back-buffer. We have
|
||
|
// to convert to planar format on the way:
|
||
|
|
||
|
pjDestinationStart = ppdev->pjVga + ppdev->cjVgaOffset;
|
||
|
fpVidMem = lpFlip->lpSurfTarg->lpGbl->fpVidMem;
|
||
|
pjSourceStart = ppdev->pjScreen + fpVidMem;
|
||
|
cDwordsPerPlane = ppdev->cDwordsPerPlane;
|
||
|
|
||
|
// Remember what DirectDraw surface is currently 'visible':
|
||
|
|
||
|
ppdev->fpScreenOffset = fpVidMem;
|
||
|
|
||
|
// Now do the blt!
|
||
|
|
||
|
WRITE_PORT_UCHAR(pjBase + VGA_BASE + SEQ_ADDR, SEQ_MAP_MASK);
|
||
|
|
||
|
for (iPage = 0; iPage < 4; iPage++, pjSourceStart++)
|
||
|
{
|
||
|
WRITE_PORT_UCHAR(pjBase + VGA_BASE + SEQ_DATA, 1 << iPage);
|
||
|
|
||
|
#if defined(_X86_)
|
||
|
|
||
|
_asm {
|
||
|
mov esi,pjSourceStart
|
||
|
mov edi,pjDestinationStart
|
||
|
mov ecx,cDwordsPerPlane
|
||
|
|
||
|
PixelLoop:
|
||
|
mov al,[esi+8]
|
||
|
mov ah,[esi+12]
|
||
|
shl eax,16
|
||
|
mov al,[esi]
|
||
|
mov ah,[esi+4]
|
||
|
|
||
|
mov [edi],eax
|
||
|
add edi,4
|
||
|
add esi,16
|
||
|
|
||
|
dec ecx
|
||
|
jnz PixelLoop
|
||
|
}
|
||
|
|
||
|
#else
|
||
|
|
||
|
pjSource = pjSourceStart;
|
||
|
pjDestination = pjDestinationStart;
|
||
|
|
||
|
for (i = cDwordsPerPlane; i != 0; i--)
|
||
|
{
|
||
|
ul = (*(pjSource))
|
||
|
| (*(pjSource + 4) << 8)
|
||
|
| (*(pjSource + 8) << 16)
|
||
|
| (*(pjSource + 12) << 24);
|
||
|
|
||
|
WRITE_REGISTER_ULONG((ULONG*) pjDestination, ul);
|
||
|
|
||
|
pjDestination += 4;
|
||
|
pjSource += 16;
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
}
|
||
|
|
||
|
// Now flip to the page we just updated:
|
||
|
|
||
|
WRITE_PORT_USHORT((USHORT*) (pjBase + VGA_BASE + CRTC_ADDR),
|
||
|
(USHORT) ((ppdev->cjVgaOffset) & 0xff00) | START_ADDRESS_HIGH);
|
||
|
|
||
|
// 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.bWasEverInDisplay = FALSE;
|
||
|
|
||
|
ppdev->flipRecord.fpFlipFrom = lpFlip->lpSurfCurr->lpGbl->fpVidMem;
|
||
|
|
||
|
lpFlip->ddRVal = DD_OK;
|
||
|
return(DDHAL_DRIVER_HANDLED);
|
||
|
}
|
||
|
|
||
|
/******************************Public*Routine******************************\
|
||
|
* BOOL DrvGetDirectDrawInfo
|
||
|
*
|
||
|
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
|
||
|
* Wrote it.
|
||
|
\**************************************************************************/
|
||
|
|
||
|
BOOL DrvGetDirectDrawInfo(
|
||
|
DHPDEV dhpdev,
|
||
|
DD_HALINFO* pHalInfo,
|
||
|
DWORD* pdwNumHeaps,
|
||
|
VIDEOMEMORY* pvmList, // Will be NULL on first call
|
||
|
DWORD* pdwNumFourCC,
|
||
|
DWORD* pdwFourCC) // Will be NULL on first call
|
||
|
{
|
||
|
PDEV* ppdev;
|
||
|
|
||
|
ppdev = (PDEV*) dhpdev;
|
||
|
|
||
|
pHalInfo->dwSize = sizeof(*pHalInfo);
|
||
|
|
||
|
// 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.dwDisplayWidth = ppdev->cxScreen;
|
||
|
pHalInfo->vmiData.dwDisplayHeight = ppdev->cyScreen;
|
||
|
pHalInfo->vmiData.lDisplayPitch = ppdev->lScreenDelta;
|
||
|
pHalInfo->vmiData.pvPrimary = ppdev->pjScreen;
|
||
|
|
||
|
pHalInfo->vmiData.ddpfDisplay.dwSize = sizeof(DDPIXELFORMAT);
|
||
|
pHalInfo->vmiData.ddpfDisplay.dwFlags = DDPF_RGB | DDPF_PALETTEINDEXED8;
|
||
|
|
||
|
pHalInfo->vmiData.ddpfDisplay.dwRGBBitCount = 8;
|
||
|
|
||
|
// These masks will be zero at 8bpp:
|
||
|
|
||
|
pHalInfo->vmiData.ddpfDisplay.dwRBitMask = 0;
|
||
|
pHalInfo->vmiData.ddpfDisplay.dwGBitMask = 0;
|
||
|
pHalInfo->vmiData.ddpfDisplay.dwBBitMask = 0;
|
||
|
pHalInfo->vmiData.ddpfDisplay.dwRGBAlphaBitMask = 0;
|
||
|
|
||
|
*pdwNumHeaps = 0;
|
||
|
if (ppdev->cyMemory != ppdev->cyScreen)
|
||
|
{
|
||
|
*pdwNumHeaps = 1;
|
||
|
if (pvmList != NULL)
|
||
|
{
|
||
|
pvmList->dwFlags = VIDMEM_ISRECTANGULAR;
|
||
|
pvmList->fpStart = ppdev->cyScreen * ppdev->lScreenDelta;
|
||
|
pvmList->dwWidth = ppdev->lScreenDelta;
|
||
|
pvmList->dwHeight = ppdev->cyMemory - ppdev->cyScreen;
|
||
|
pvmList->ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Capabilities supported:
|
||
|
|
||
|
pHalInfo->ddCaps.dwFXCaps = 0;
|
||
|
pHalInfo->ddCaps.dwCaps = 0;
|
||
|
pHalInfo->ddCaps.dwCKeyCaps = 0;
|
||
|
pHalInfo->ddCaps.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN
|
||
|
| DDSCAPS_PRIMARYSURFACE
|
||
|
| DDSCAPS_FLIP;
|
||
|
|
||
|
// Required alignments of the scan lines for each kind of memory:
|
||
|
|
||
|
pHalInfo->vmiData.dwOffscreenAlign = 4;
|
||
|
|
||
|
// FourCCs supported:
|
||
|
|
||
|
*pdwNumFourCC = 0;
|
||
|
|
||
|
return(TRUE);
|
||
|
}
|
||
|
|
||
|
/******************************Public*Routine******************************\
|
||
|
* BOOL DrvEnableDirectDraw
|
||
|
*
|
||
|
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
|
||
|
* Wrote it.
|
||
|
\**************************************************************************/
|
||
|
|
||
|
BOOL DrvEnableDirectDraw(
|
||
|
DHPDEV dhpdev,
|
||
|
DD_CALLBACKS* pCallBacks,
|
||
|
DD_SURFACECALLBACKS* pSurfaceCallBacks,
|
||
|
DD_PALETTECALLBACKS* pPaletteCallBacks)
|
||
|
{
|
||
|
pCallBacks->WaitForVerticalBlank = DdWaitForVerticalBlank;
|
||
|
pCallBacks->MapMemory = DdMapMemory;
|
||
|
pCallBacks->dwFlags = DDHAL_CB32_WAITFORVERTICALBLANK
|
||
|
| DDHAL_CB32_MAPMEMORY;
|
||
|
|
||
|
pSurfaceCallBacks->Flip = DdFlip;
|
||
|
pSurfaceCallBacks->Lock = DdLock;
|
||
|
pSurfaceCallBacks->Unlock = DdUnlock;
|
||
|
pSurfaceCallBacks->dwFlags = DDHAL_SURFCB32_FLIP
|
||
|
| DDHAL_SURFCB32_LOCK
|
||
|
| DDHAL_SURFCB32_UNLOCK;
|
||
|
|
||
|
return(TRUE);
|
||
|
}
|
||
|
|
||
|
/******************************Public*Routine******************************\
|
||
|
* VOID DrvDisableDirectDraw
|
||
|
*
|
||
|
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
|
||
|
* Wrote it.
|
||
|
\**************************************************************************/
|
||
|
|
||
|
VOID DrvDisableDirectDraw(
|
||
|
DHPDEV dhpdev)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
/******************************Public*Routine******************************\
|
||
|
* BOOL bEnableDirectDraw
|
||
|
*
|
||
|
* This function is called by enable.c when the mode is first initialized,
|
||
|
* right after the miniport does the mode-set.
|
||
|
*
|
||
|
\**************************************************************************/
|
||
|
|
||
|
BOOL bEnableDirectDraw(
|
||
|
PDEV* ppdev)
|
||
|
{
|
||
|
// Calculate the total number of dwords per plane for flipping:
|
||
|
|
||
|
ppdev->cDwordsPerPlane = (ppdev->cyScreen * ppdev->lVgaDelta) >> 2;
|
||
|
|
||
|
// We only program the high byte of the VGA offset, so the page size must
|
||
|
// be a multiple of 256:
|
||
|
|
||
|
ppdev->cjVgaPageSize = ((ppdev->cyScreen * ppdev->lVgaDelta) + 255) & ~255;
|
||
|
|
||
|
// VGAs can address only 64k of memory, so that limits the number of
|
||
|
// page-flip buffers we can have:
|
||
|
|
||
|
ppdev->cVgaPages = 64 * 1024 / ppdev->cjVgaPageSize;
|
||
|
|
||
|
// Accurately measure the refresh rate for later:
|
||
|
|
||
|
vGetDisplayDuration(ppdev);
|
||
|
|
||
|
return(TRUE);
|
||
|
}
|
||
|
|
||
|
/******************************Public*Routine******************************\
|
||
|
* VOID vAssertModeDirectDraw
|
||
|
*
|
||
|
* This function is called by enable.c when entering or leaving the
|
||
|
* DOS full-screen character mode.
|
||
|
*
|
||
|
\**************************************************************************/
|
||
|
|
||
|
VOID vAssertModeDirectDraw(
|
||
|
PDEV* ppdev,
|
||
|
BOOL bEnable)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
/******************************Public*Routine******************************\
|
||
|
* VOID vDisableDirectDraw
|
||
|
*
|
||
|
* This function is called by enable.c when the driver is shutting down.
|
||
|
*
|
||
|
\**************************************************************************/
|
||
|
|
||
|
VOID vDisableDirectDraw(
|
||
|
PDEV* ppdev)
|
||
|
{
|
||
|
ASSERTDD(ppdev->cLocks == 0, "Invalid lock count");
|
||
|
}
|