/******************************Module*Header**********************************\ * * ************************** * * DirectDraw SAMPLE CODE * * ************************** * * Module Name: dd.c * * Content: Main DirectDraw callbacks * * Copyright (c) 1994-1999 3Dlabs Inc. Ltd. All rights reserved. * Copyright (c) 1995-2003 Microsoft Corporation. All rights reserved. \*****************************************************************************/ #define INITGUID #include "glint.h" #if W95_DDRAW #include "ddkmmini.h" #include #endif #include "dma.h" #include "tag.h" void __GetDDHALInfo(P3_THUNKEDDATA* pThisDisplay, DDHALINFO* pHALInfo); #if W95_DDRAW // These variables MUST be initialised, therby forcing them into DATA. // This segment is shared. P3_THUNKEDDATA* g_pDriverData = NULL; //----------------------------------------------------------------------------- // // ***************************WIN9x ONLY********************************** // // DllMain // // DLL Entry point. // //----------------------------------------------------------------------------- BOOL WINAPI DllMain( HINSTANCE hModule, DWORD dwReason, LPVOID lpvReserved) { // The 16 bit side requires an HINSTANCE g_DXGlobals.hInstance = hModule; switch( dwReason ) { case DLL_PROCESS_ATTACH: // We don't care about thread attach messages. DisableThreadLibraryCalls( hModule ); break; case DLL_PROCESS_DETACH: break; case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: default: break; } return TRUE; } // DllMain //-----------------------------Public Routine---------------------------------- // // ***************************WIN9x ONLY********************************** // // DdDestroyDriver // // Destroys a DirectDraw driver. // // Parameters // pddd // Address of a DDHAL_DESTROYDRIVERDATA structure that contains // information necessary to destroy the driver. // Members // // LPDDRAWI_DIRECTDRAW_GBL // lpDD // Address of the DirectDraw structure representing // the DirectDraw object. // HRESULT // ddRVal // Passes the DirectDraw return values. // LPDDHAL_DESTROYDRIVER // DestroyDriver // This member is used by the DirectDraw API and should // not be filled in by the driver. // // Return Value // Returns one of the following values: // // DDHAL_DRIVER_HANDLED // DDHAL_DRIVER_NOTHANDLED //----------------------------------------------------------------------------- // // (!!!) Temp patch, move to Win9x header later, this CB is currently not used. // #define DIRECTX_DESTROYDRIVER_ESCAPE 0xbadbadee DWORD CALLBACK DdDestroyDriver( LPDDHAL_DESTROYDRIVERDATA pddd) { HDC hDC; P3_THUNKEDDATA* pThisDisplay; LPGLINTINFO pGLInfo; DISPDBG((DBGLVL,"*** In DdDestroyDriver")); GET_THUNKEDDATA(pThisDisplay, pddd->lpDD); pGLInfo = pThisDisplay->pGLInfo; // Destroy the hash table HT_DestroyHashTable(pThisDisplay->pDirectDrawLocalsHashTable, pThisDisplay); DISPDBG((DBGLVL,"Calling Display Driver's DestroyDriver16")); hDC = CREATE_DRIVER_DC ( pThisDisplay->pGLInfo ); if ( hDC != NULL ) { DISPDBG((DBGLVL,"HDC: 0x%x", hDC)); ExtEscape ( hDC, DIRECTX_DESTROYDRIVER_ESCAPE, sizeof(DDHAL_DESTROYDRIVERDATA), (LPCSTR)pddd, 0, NULL ); DELETE_DRIVER_DC ( hDC ); } pddd->ddRVal = DD_OK; return DDHAL_DRIVER_HANDLED; } // DdDestroyDriver //-----------------------------Public Routine---------------------------------- // // ***************************WIN9x ONLY********************************** // // DriverInit // // The entry point called by DirectDraw to initialize the 32-bit driver. // // DriverInit is called after the control function receives QUERYESCAPESUPPORT // with DDGET32BITDRIVERNAME escapes and returns the entry point (szEntryPoint). // DriverInit is only called once during driver initialization; it is not // called on mode changes. // // The dwDriverData parameter points to a region of shared data between the // 16- and 32-bit address space. It must be aliased through MapSLFix (a // standard Windows driver routine), which converts it to a 32-bit pointer, // g_pDriverData. MapSLFix creates a 16-bit selector for a 32-bit pointer, so // you can use what it returns from the 16-bit side. A 16:16 pointer is created // to point to the needed 32-bit objects, so a 64K piece of memory is shared // between 16- and 32-bit sides. Since only 64K of linear address space is // accessible with a 16:16 pointer, any objects larger than 64K will require // two 16:16 pointers tiled together (most objects should be smaller than 64K). // The pointer is used to set the fReset flag to TRUE because the display // parameters are being reset. The buildDDHALInfo32 function is called from // this function to fill out all of the 32-bit function names and driver // information. // // Returns 1. // // Parameters // DWORD // dwDriverData // Doubleword pointer that points to a shared memory region // between 16- and 32-bit address space. //----------------------------------------------------------------------------- DWORD CALLBACK DriverInit( DWORD dwDriverData ) { P3_THUNKEDDATA* pThisDisplay; DWORD DataPointer = 0; HANDLE hDevice = NULL; DWORD InPtr = dwDriverData; DWORD dwSizeRet; DWORD bResult; // The g_pThisTemp may have been hosed, so we must reset // it to continue #if DBG g_pThisTemp = NULL; #endif //extern LPVOID _stdcall MapSL( DWORD ); // 16:16 -> 0:32 //DataPointer = (DWORD)MapSL(dwDriverData); //!! Don't laugh at this... I tried calling the MapSL function //to fix up the pointer, but couldn't get it to work all of the time //(When the display was running the second instance of itself). hDevice = CreateFile("\\\\.\\perm3mvd", GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, (LPSECURITY_ATTRIBUTES) NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, (HANDLE) NULL); if (hDevice == (HANDLE) INVALID_HANDLE_VALUE) { DISPDBG((ERRLVL, "ERROR: Invalid Handle")); return 0; } else { DISPDBG((DBGLVL, "Got handle")); bResult = DeviceIoControl(hDevice, GLINT_16TO32_POINTER, &InPtr, sizeof(DWORD), &DataPointer, sizeof(DWORD), &dwSizeRet, 0); if (!bResult || (DataPointer == 0)) { DISPDBG((ERRLVL,"ERROR: Pointer conversion failed!")); CloseHandle(hDevice); return 0; } } CloseHandle(hDevice); #if DBG g_pThisTemp = (P3_THUNKEDDATA*)DataPointer; #endif // // Sanity check // if (! (((P3_THUNKEDDATA*)DataPointer)->pGLInfo)) { return 0; } if (((P3_THUNKEDDATA*)DataPointer)->pGLInfo->dwDeviceHandle == 1) { g_pDriverData = (P3_THUNKEDDATA*)DataPointer; DISPDBG((ERRLVL, "Device is the Primary, Setting sData: 0x%x", g_pDriverData)); } else { DISPDBG((ERRLVL, "Device NOT Primary Display, " "Setting dwReturn: 0x%x", DataPointer)); } pThisDisplay = (P3_THUNKEDDATA*)DataPointer; if (pThisDisplay->dwSetupThisDisplay == 0) { // Pass the current pointer to the init function if (! _DD_InitDDHAL32Bit((P3_THUNKEDDATA*)DataPointer)) { DISPDBG((ERRLVL,"ERROR: DriverInit Failed!")); return 0; } else { // // Initialize the heap manager data structure // _DX_LIN_UnInitialiseHeapManager(&pThisDisplay->LocalVideoHeap0Info); if (!_DX_LIN_InitialiseHeapManager( &pThisDisplay->LocalVideoHeap0Info, pThisDisplay->LocalVideoHeap0Info.dwMemStart, pThisDisplay->LocalVideoHeap0Info.dwMemEnd)) { DISPDBG((ERRLVL, "ERROR: Heap0 initialization failed!")); } DISPDBG((ERRLVL,"Returned g_pDriverData")); } } // Increase the reference count on the display object. pThisDisplay->dwSetupThisDisplay++; // Set up the size of the ddCaps pThisDisplay->ddhi32.ddCaps.dwSize = sizeof(DDCORECAPS); // Set the flag that says we have to handle a mode change. // This will cause the chip to be initialised properly at the // right time (whilst in a Win16Lock) ((P3_THUNKEDDATA*)DataPointer)->bResetMode = TRUE; ((P3_THUNKEDDATA*)DataPointer)->bStartOfDay = TRUE; ((P3_THUNKEDDATA*)DataPointer)->pGLInfo->dwDirectXState = DIRECTX_LASTOP_UNKNOWN; return (DWORD)DataPointer; } // DriverInit //-----------------------------Public Routine---------------------------------- // // ***************************WIN9x ONLY********************************** // // DdControlColor // // Controls the luminance and brightness controls of an overlay surface // or a primary surface. This callback is optional. // // Parameters // lpColorControl // Points to a DD_COLORCONTROLDATA structure that contains // the color control information for a specified overlay // surface. // // Members // // PDD_DIRECTDRAW_GLOBAL // lpDD // Points to a DD_DIRECTDRAW_GLOBAL structure that // describes the driver. // PDD_SURFACE_LOCAL // lpDDSurface // Points to the DD_SURFACE_LOCAL structure // representing the overlay surface. // DDCOLORCONTROL // ColorData // Is a DDCOLORCONTROL structure. See dwFlags to // determine how to use this member. The // DDCOLORCONTROL structure is defined in ddraw.h. // DWORD // dwFlags // Is the color control flags. This member can be // one of the following values: // // DDRAWI_GETCOLOR The driver should return the color // controls it supports for the // specified overlay in ColorData. // The driver should set the appropriate // flags in the dwFlags member of the // DDCOLORCONTROL structure to indicate // which other members the driver has // returned valid data in. // DDRAWI_SETCOLOR // The driver should set the current color // controls for the specified overlay // using the values specified in ColorData. // HRESULT // ddRVal // Is the location in which the driver writes the // return value of the DdControlColor callback. A // return code of DD_OK indicates success. // VOID* // ColorControl // Is unused on Windows 2000. // // Return Value // DdControlColor returns one of the following callback codes: // // DDHAL_DRIVER_HANDLED // DDHAL_DRIVER_NOTHANDLED // Comments // // DdControlColor can be optionally implemented in a DirectDraw driver. //----------------------------------------------------------------------------- // Set this to 1 to support gamma correction, or zero to disable. #define COLCON_SUPPORTS_GAMMA 1 DWORD CALLBACK DdControlColor( LPDDHAL_COLORCONTROLDATA lpColConData ) { P3_THUNKEDDATA* pThisDisplay; P3_SURF_FORMAT* pFormatSurface; GET_THUNKEDDATA(pThisDisplay, lpColConData->lpDD); DISPDBG((DBGLVL,"DdControlColor")); // // What the DDCOLORCONTROL structure looks like: // { // DWORD dwSize; // DWORD dwFlags; // LONG lBrightness; // LONG lContrast; // LONG lHue; // LONG lSaturation; // LONG lSharpness; // LONG lGamma; // LONG lColorEnable; // DWORD dwReserved1; // } DDCOLORCONTROL; // pFormatSurface = _DD_SUR_GetSurfaceFormat(lpColConData->lpDDSurface); if ( pFormatSurface->dwBitsPerPixel <= 8 ) { // Can't do colour control on this format screen. // Only works on true-colour screens (and we don't // support 332 as a primary). lpColConData->lpColorData->dwFlags = 0; lpColConData->ddRVal = DD_OK; return ( DDHAL_DRIVER_HANDLED ); } // See what they want. if ( lpColConData->dwFlags == DDRAWI_GETCOLOR ) { // Get the colour info. lpColConData->lpColorData->lBrightness = pThisDisplay->ColConBrightness; lpColConData->lpColorData->lContrast = pThisDisplay->ColConContrast; #if COLCON_SUPPORTS_GAMMA lpColConData->lpColorData->lGamma = pThisDisplay->ColConGamma; lpColConData->lpColorData->dwFlags = DDCOLOR_BRIGHTNESS | DDCOLOR_CONTRAST | DDCOLOR_GAMMA; #else // We don't support gamma values. lpColConData->lpColorData->lGamma = 0; lpColConData->lpColorData->dwFlags = DDCOLOR_BRIGHTNESS | DDCOLOR_CONTRAST; #endif } else if ( lpColConData->dwFlags == DDRAWI_SETCOLOR ) { WORD wRamp[256*3]; WORD *pwRampR, *pwRampG, *pwRampB; BOOL bRes; HDC hDC; float fCol1, fCol2, fCol3, fCol4; float fBrightGrad, fBrightBase; float fContGrad1, fContBase1; float fContGrad2, fContBase2; float fContGrad3, fContBase3; float fContCutoff12, fContCutoff23; float fGammaGrad1, fGammaBase1; float fGammaGrad2, fGammaBase2; float fGammaCutoff12; float fTemp; int iTemp, iCount; // Set some new colour info. if ( ( lpColConData->lpColorData->dwFlags & DDCOLOR_BRIGHTNESS ) != 0 ) { pThisDisplay->ColConBrightness = lpColConData->lpColorData->lBrightness; } if ( ( lpColConData->lpColorData->dwFlags & DDCOLOR_CONTRAST ) != 0 ) { pThisDisplay->ColConContrast = lpColConData->lpColorData->lContrast; } #if COLCON_SUPPORTS_GAMMA if ( ( lpColConData->lpColorData->dwFlags & DDCOLOR_GAMMA ) != 0 ) { pThisDisplay->ColConGamma = lpColConData->lpColorData->lGamma; } #endif // Set up the constants. // Brightness. // 0->10000 maps to 0.0->1.0. Default is 0 fCol1 = (float)(pThisDisplay->ColConBrightness) / 10000.0f; fBrightGrad = 1.0f - fCol1; fBrightBase = fCol1; // Contrast // 0->20000 maps to 0.0->1.0. Default 10000 maps to 0.5 fCol1 = (float)(pThisDisplay->ColConContrast) / 20000.0f; fContCutoff12 = fCol1 / 2.0f; fContCutoff23 = 1.0f - ( fCol1 / 2.0f ); fContGrad1 = ( 1.0f - fCol1 ) / fCol1; fContBase1 = 0.0f; fContGrad2 = fCol1 / ( 1.0f - fCol1 ); fContBase2 = ( 0.5f - fCol1 ) / ( 1.0f - fCol1 ); fContGrad3 = ( 1.0f - fCol1 ) / fCol1; fContBase3 = ( ( 2.0f * fCol1 ) - 1.0f ) / fCol1; // Gamma // 1->500 maps to 0.01->5.0, default of 100 maps to 1.0 // But then map to 0.0->0.5->1.0 non-linearly. if ( pThisDisplay->ColConGamma <= 2 ) { // App is probably using the old docs that forgot to point // out the *100 ASSERTDD ( FALSE, "** Colorcontrol32: App set gamma value of 2" " or less - probably using old DX docs" ); fTemp = (float)(pThisDisplay->ColConGamma); } else { fTemp = (float)(pThisDisplay->ColConGamma) / 100.0f; } fTemp = 1.0f - ( 1.0f / ( 1.0f + fTemp ) ); fGammaCutoff12 = 1.0f - fTemp; fGammaGrad1 = fTemp / ( 1.0f - fTemp ); fGammaBase1 = 0.0f; fGammaGrad2 = ( 1.0f - fTemp ) / fTemp; fGammaBase2 = ( 2.0f * fTemp - 1.0f ) / fTemp; // Now set up the table. fCol1 = 0.0f; pwRampR = &(wRamp[0]); pwRampG = &(wRamp[256]); pwRampB = &(wRamp[512]); for ( iCount = 256; iCount > 0; iCount-- ) { fCol1 += 1.0f / 256.0f; // Apply linear approximation gamma. if ( fCol1 < fGammaCutoff12 ) { fCol2 = fGammaBase1 + fGammaGrad1 * fCol1; } else { fCol2 = fGammaBase2 + fGammaGrad2 * fCol1; } // Apply contrast if ( fCol2 < fContCutoff12 ) { fCol3 = fContBase1 + fContGrad1 * fCol2; } else if ( fCol2 < fContCutoff23 ) { fCol3 = fContBase2 + fContGrad2 * fCol2; } else { fCol3 = fContBase3 + fContGrad3 * fCol2; } // Apply brightness fCol4 = fBrightBase + fBrightGrad * fCol3; // Convert 0.0->1.0 to 0->65535 fTemp = ( fCol4 * 65536.0f ); myFtoi ( &iTemp, fTemp ); if ( iTemp < 0 ) { iTemp = 0; } else if ( iTemp > 65535 ) { iTemp = 65535; } *pwRampR = (WORD)iTemp; *pwRampG = (WORD)iTemp; *pwRampB = (WORD)iTemp; pwRampR++; pwRampG++; pwRampB++; } // And do the hardware itself. hDC = CREATE_DRIVER_DC ( pThisDisplay->pGLInfo ); if ( hDC != NULL ) { bRes = SetDeviceGammaRamp ( hDC, wRamp ); DELETE_DRIVER_DC ( hDC ); ASSERTDD ( bRes, "DdControlColor - SetDeviceGammaRamp failed" ); } else { ASSERTDD ( FALSE, "DdControlColor - CREATE_DRIVER_DC failed" ); } } else { // Don't know what they want to do. Panic. ASSERTDD ( FALSE, "DdControlColor - don't know what to do." ); lpColConData->ddRVal = DDERR_INVALIDPARAMS; return ( DDHAL_DRIVER_HANDLED ); } lpColConData->ddRVal = DD_OK; return ( DDHAL_DRIVER_HANDLED ); } // DdControlColor #endif // W95_DDRAW DirectXGlobals g_DXGlobals = { 0 }; #if WNT_DDRAW //-----------------------------Public Routine---------------------------------- // // ***************************WIN NT ONLY********************************** // // DdMapMemory // // Maps application-modifiable portions of the frame buffer into the // user-mode address space of the specified process, or unmaps memory. // // DdMapMemory is called to perform memory mapping before the first call to // DdLock. The handle returned by the driver in fpProcess will be passed to // every DdLock call made on the driver. // // DdMapMemory is also called to unmap memory after the last DdUnLock call is // made. // // To prevent driver crashes, the driver must not map any portion of the frame // buffer that must not be modified by an application. // // Parameters // lpMapMemory // Points to a DD_MAPMEMORYDATA structure that contains details for // the memory mapping or unmapping operation. // // .lpDD // Points to a DD_DIRECTDRAW_GLOBAL structure that represents // the driver. // .bMap // Specifies the memory operation that the driver should perform. // A value of TRUE indicates that the driver should map memory; // FALSE means that the driver should unmap memory. // .hProcess // Specifies a handle to the process whose address space is // affected. // .fpProcess // Specifies the location in which the driver should return the // base address of the process's memory mapped space when bMap // is TRUE. When bMap is FALSE, fpProcess contains the base // address of the memory to be unmapped by the driver. // .ddRVal // Specifies the location in which the driver writes the return // value of the DdMapMemory callback. A return code of DD_OK // indicates success. // //----------------------------------------------------------------------------- DWORD CALLBACK DdMapMemory( PDD_MAPMEMORYDATA lpMapMemory) { PDEV* ppdev; VIDEO_SHARE_MEMORY ShareMemory; VIDEO_SHARE_MEMORY_INFORMATION ShareMemoryInformation; DWORD ReturnedDataLength; DBG_CB_ENTRY(DdMapMemory); ppdev = (PDEV*) 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); if (EngDeviceIoControl(ppdev->hDriver, IOCTL_VIDEO_SHARE_VIDEO_MEMORY, &ShareMemory, sizeof(VIDEO_SHARE_MEMORY), &ShareMemoryInformation, sizeof(VIDEO_SHARE_MEMORY_INFORMATION), &ReturnedDataLength)) { DISPDBG((ERRLVL, "Failed IOCTL_VIDEO_SHARE_MEMORY")); lpMapMemory->ddRVal = DDERR_GENERIC; DISPDBG((ERRLVL, "DdMapMemory: Exit GEN, DDHAL_DRIVER_HANDLED")); DBG_CB_EXIT(DdMapMemory, DDERR_GENERIC); return(DDHAL_DRIVER_HANDLED); } lpMapMemory->fpProcess = (FLATPTR) ShareMemoryInformation.VirtualAddress; } else { ShareMemory.ProcessHandle = lpMapMemory->hProcess; ShareMemory.ViewOffset = 0; ShareMemory.ViewSize = 0; ShareMemory.RequestedVirtualAddress = (VOID*) lpMapMemory->fpProcess; 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; DBG_CB_EXIT(DdMapMemory, DD_OK); return(DDHAL_DRIVER_HANDLED); } // DdMapMemory //-----------------------------Public Routine---------------------------------- // // ***************************WIN NT ONLY********************************** // // BOOL DrvGetDirectDrawInfo // // Function called by DirectDraw to returns the capabilities of the graphics // hardware // // Parameters: // // dhpdev-------Is a handle to the PDEV returned by the driver's DrvEnablePDEV // routine. // pHalInfo-----Points to a DD_HALINFO structure in which the driver should // return the hardware capabilities that it supports. // pdwNumHeaps--Points to the location in which the driver should return the // number of VIDEOMEMORY structures pointed to by pvmList. // pvmList------Points to an array of VIDEOMEMORY structures in which the // driver should return information about each video memory chunk // that it controls. The driver should ignore this parameter when // it is NULL. // pdwNumFourCC-Points to the location in which the driver should return the // number of DWORDs pointed to by pdwFourCC. // pdwFourCC----Points to an array of DWORDs in which the driver should return // information about each FOURCC that it supports. The driver // should ignore this parameter when it is NULL. // // Return: // Returns TRUE if it succeeds; otherwise, it returns FALSE // // Note: // This function will be called twice before DrvEnableDirectDraw is called. // // Comments // The driver's DrvGetDirectDrawInfo routine should do the following: // 1)When pvmList and pdwFourCC are NULL: // Reserve off-screen video memory for DirectDraw use. Write the number of // driver video memory heaps and supported FOURCCs in pdwNumHeaps and // pdwNumFourCC, respectively. // // 2)When pvmList and pdwFourCC are not NULL: // Write the number of driver video memory heaps and supported FOURCCs in // pdwNumHeaps and pdwNumFourCC, respectively. // Get ptr to reserved offscreen mem? // For each VIDEOMEMORY structure in the list to which pvmList points, fill in // the appropriate members to describe a particular chunk of display memory. // The list of structures provides DirectDraw with a complete description of // the driver's off-screen memory. // // 3)Initialize the members of the DD_HALINFO structure with driver-specific // information as follows: // Initialize the appropriate members of the VIDEOMEMORYINFO structure to // describe the general characteristics of the display's memory. // Initialize the appropriate members of the DDNTCORECAPS structure to // describe the capabilities of the hardware. // If the driver implements a DdGetDriverInfo function, set GetDriverInfo to // point to it and set dwFlags to DDHALINFO_GETDRIVERINFOSET // //----------------------------------------------------------------------------- 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 { BOOL bCanFlip; PDEV* ppdev; LONGLONG li; DWORD Unused = 0; P3_THUNKEDDATA* pThisDisplay; DWORD dwChipConfig; DWORD cHeaps; static DWORD fourCC[] = { FOURCC_YUV422 }; // The FourCC's we support ppdev = (PDEV*) dhpdev; pThisDisplay = (P3_THUNKEDDATA*) ppdev->thunkData; DBG_CB_ENTRY(DrvGetDirectDrawInfo); *pdwNumFourCC = 0; // We may not support DirectDraw on this card: if (!(ppdev->flStatus & STAT_DIRECTDRAW)) { DISPDBG((ERRLVL, "DrvGetDirectDrawInfo: exit, not enabled")); DBG_CB_EXIT(DrvGetDirectDrawInfo,FALSE); return(FALSE); } // Need a pointer to the registers to read config info pThisDisplay->pGLInfo->pRegs = (ULONG_PTR) ppdev->pulCtrlBase[0]; //@@BEGIN_DDKSPLIT //azn - loss of bits 64->32 //@@END_DDKSPLIT pThisDisplay->control = (FLATPTR)pThisDisplay->pGLInfo->pRegs; pThisDisplay->pGlint = (FPGLREG)pThisDisplay->control; #if DBG // We can only initialise g_pThisTemp after // the registers have been mapped in. g_pThisTemp = pThisDisplay; #endif // Decide if we can use AGP or not dwChipConfig = (DWORD)((PREGISTERS)pThisDisplay->pGLInfo->pRegs)->Glint.ChipConfig; // Make the AGP decision (NT Only!) if ( ((dwChipConfig & PM_CHIPCONFIG_AGP1XCAPABLE) || (dwChipConfig & PM_CHIPCONFIG_AGP2XCAPABLE) || (dwChipConfig & PM_CHIPCONFIG_AGP4XCAPABLE)) ) { DISPDBG((WRNLVL,"AGP Permedia3 Board detected!")); pThisDisplay->bCanAGP = TRUE; } else { DISPDBG((WRNLVL,"Permedia3 Board is NOT AGP")); pThisDisplay->bCanAGP = FALSE; } // Fill in the DDHAL Informational caps that Win95 has setup. __GetDDHALInfo(pThisDisplay, pHalInfo); // On Win2K we need to return the D3D callbacks DISPDBG((DBGLVL ,"Creating Direct3D info")); _D3DHALCreateDriver(pThisDisplay); // Record the pointers that were created. Note that the above call // may not have recreated a previous set of data. pHalInfo->lpD3DGlobalDriverData = (void*)pThisDisplay->lpD3DGlobalDriverData; pHalInfo->lpD3DHALCallbacks = (void*)pThisDisplay->lpD3DHALCallbacks; pHalInfo->lpD3DBufCallbacks = (void *)pThisDisplay->lpD3DBufCallbacks; if ( (pHalInfo->lpD3DBufCallbacks) && (pHalInfo->lpD3DBufCallbacks->dwSize != 0)) { pHalInfo->ddCaps.ddsCaps.dwCaps |= DDSCAPS_EXECUTEBUFFER; } // Fill in any DDHAL caps that are specific to Windows NT. // Current primary surface attributes: pHalInfo->vmiData.pvPrimary = ppdev->pjScreen; pHalInfo->vmiData.fpPrimary = 0; pHalInfo->vmiData.dwDisplayWidth = ppdev->cxScreen; pHalInfo->vmiData.dwDisplayHeight = ppdev->cyScreen; pHalInfo->vmiData.lDisplayPitch = ppdev->lDelta; pHalInfo->vmiData.ddpfDisplay.dwSize = sizeof(DDPIXELFORMAT); pHalInfo->vmiData.ddpfDisplay.dwFlags = DDPF_RGB; pHalInfo->vmiData.ddpfDisplay.dwRGBBitCount = ppdev->cjPelSize * 8; if (ppdev->iBitmapFormat == BMF_8BPP) { 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; //@@BEGIN_DDKSPLIT // Free up as much off-screen memory as possible: //TMM ?? bMoveAllDfbsFromOffscreenToDibs(ppdev); //@@END_DDKSPLIT // We have to tell DirectDraw our preferred off-screen alignment, even // if we're doing our own off-screen memory management: pHalInfo->vmiData.dwOffscreenAlign = 4; pHalInfo->vmiData.dwZBufferAlign = 4; pHalInfo->vmiData.dwTextureAlign = 4; pHalInfo->vmiData.dwOverlayAlign = 4; // Since we do our own memory allocation, we have to set dwVidMemTotal // ourselves. Note that this represents the amount of available off- // screen memory, not all of video memory: pHalInfo->ddCaps.dwVidMemTotal = ppdev->heap.cxMax * ppdev->heap.cyMax * ppdev->cjPelSize; // If we are on Permedia, then setup the YUV modes for Video playback // acceleration. We can do YUV conversions at any depth except 8 bits... // On Win95 this information is setup in the Mini Display Driver. if (ppdev->iBitmapFormat != BMF_8BPP) { *pdwNumFourCC = sizeof( fourCC ) / sizeof( fourCC[0] ); if (pdwFourCC) { memcpy(pdwFourCC, fourCC, sizeof(fourCC)); } } cHeaps = 0; if(pThisDisplay->bCanAGP) { ++cHeaps; // agp memory heap } // Report the heaps we want DD to manage. // Currently this is needed in this sample for the AGP heap. if(pvmList) { VIDEOMEMORY *pVm = pvmList; // If we support AGP , then define the AGP heap if(pThisDisplay->bCanAGP) { DWORD dwAGPMemBytes; //@@BEGIN_DDKSPLIT // azn This business of hard-allocating 32MB is not right. // We need to fix it and verify with JeffN what's the best // policy to show in the sample // Request a suitably sized AGP heap, don't ask for a heap // larger than the available memory // This is taken care of by the W2000 runtime policy, so I don't // think we need to do this for W2k. CTM. //@@END_DDKSPLIT // Default to 32Mb of AGP memory dwAGPMemBytes = 32*1024*1024; // Report the AGP heap // fpStart---Points to the starting address of a memory range in the // heap. // fpEnd-----Points to the ending address of a memory range if the heap // is linear. This address is inclusive, that is, it specifies the last // valid address in the range. Thus, the number of bytes specified by // fpStart and fpEnd is (fpEnd-fpStart+1). // DDraw ignores our start address so just set to zero pVm->fpStart = 0; // Fetch the last byte of AGP memory pVm->fpEnd = dwAGPMemBytes - 1; pVm->dwFlags = VIDMEM_ISNONLOCAL | VIDMEM_ISLINEAR | VIDMEM_ISWC; // Only use AGP memory for texture surfaces pVm->ddsCaps.dwCaps = DDSCAPS_OVERLAY | DDSCAPS_OFFSCREENPLAIN | DDSCAPS_FRONTBUFFER | DDSCAPS_BACKBUFFER | DDSCAPS_ZBUFFER | DDSCAPS_3DDEVICE; pVm->ddsCapsAlt.dwCaps = DDSCAPS_OVERLAY | DDSCAPS_OFFSCREENPLAIN | DDSCAPS_FRONTBUFFER | DDSCAPS_BACKBUFFER | DDSCAPS_ZBUFFER | DDSCAPS_3DDEVICE; DISPDBG((DBGLVL, "Initialised AGP Heap for P2, Start:0x%x, End:0x%x", pVm->fpStart, pVm->fpEnd)); ++pVm; } else { DISPDBG((WRNLVL, "NOT reporting AGP heap")); } } else { DISPDBG((DBGLVL, "Heap info NOT requested")); } // Report the number of heaps we support if (pdwNumHeaps) { *pdwNumHeaps = cHeaps; } DBG_CB_EXIT(DrvGetDirectDrawInfo,TRUE); return(TRUE); } // DrvGetDirectDrawInfo #endif // WNT_DDRAW #if USE_FLIP_BACKOFF //----------------------------------------------------------------------------- // // __WaitTimeDelay // //----------------------------------------------------------------------------- #define WAIT_TIME_DELAY 2 void __WaitTimeDelay(void) { static DWORD dwLastTime; // Doesn't matter what the // start value is (honest!) DWORD dwCurTime, iTimeDiff; // Make sure that we don't start hammering on the chip. // If someone uses the WAIT flag, or they do a loop // themselves, we will constantly be reading the chip, // which will disrupt the DMA stream. Therefore, // make sure we don't start reading it too often. // This #define will need tweaking, of course. do { dwCurTime = timeGetTime(); // Be careful about wraparound conditions. iTimeDiff = (signed int)( dwCurTime - dwLastTime ); } while ( ( iTimeDiff > 0 ) && ( iTimeDiff < WAIT_TIME_DELAY ) ); // And store the new "last" time. dwLastTime = dwCurTime; } // __WaitTimeDelay #endif //#if USE_FLIP_BACKOFF //----------------------------------------------------------------------------- // // __QueryRenderIDStatus // // Checks to see if the given two RenderIDs have been finished yet. // // If there is a problem, the pipeline will be flushed and the // RenderIDs set to the newest ID. // // If bAllowDMAFlush is TRUE, then if either RenderID is still in the // pipe, the current DMA buffer is flushed. Otherwise there is a // fairly good chance that the command with that RenderID may simply // sit in the DMA buffer and never be executed. To disable this, // pass in FALSE. This may be needed because the routine has already // grabbed the DMA buffer, etc. and in that case it needs to do the flush // itself when it gets DDERR_WASSTILLDRAWING. // // The return value is either DD_OK (both RenderIDs have been finished), // or DDERR_WASSTILLDRAWING. // //----------------------------------------------------------------------------- HRESULT __QueryRenderIDStatus( P3_THUNKEDDATA* pThisDisplay, BOOL bAllowDMAFlush ) { P3_DMA_DEFS(); ASSERTDD ( CHIP_RENDER_ID_IS_VALID(), "** __QueryRenderIDStatus:Chip RenderID was invalid - fix it!"); if ( RENDER_ID_HAS_COMPLETED ( pThisDisplay->dwLastFlipRenderID )) { // OK, the RenderID has cleared the pipe, so we can carry on. return ( DD_OK ); } else { // Can't flip yet - one surface is still pending. if (!NEED_TO_RESYNC_CHIP_AND_SURFACE (pThisDisplay->dwLastFlipRenderID)) { // No error - we just need to wait. We'll flush the buffer and // return DDERR_WASSTILLDRAWING if ( bAllowDMAFlush ) { DDRAW_OPERATION(pContext, pThisDisplay); P3_DMA_GET_BUFFER(); P3_DMA_FLUSH_BUFFER(); } #if USE_FLIP_BACKOFF __WaitTimeDelay(); #endif return ( DDERR_WASSTILLDRAWING ); } else { // Something went wrong - need to do a safety-net resync. DISPDBG((ERRLVL,"__QueryRenderIDStatus: " "RenderID failure - need a resync")); SYNC_WITH_GLINT; pThisDisplay->dwLastFlipRenderID = GET_HOST_RENDER_ID(); // And continue with the operation. return ( DD_OK ); } } } // __QueryRenderIDStatus //----------------------------------------------------------------------------- // // _DX_QueryFlipStatus // // Checks and sees if the most recent flip has occurred. If so returns DD_OK. // //----------------------------------------------------------------------------- HRESULT _DX_QueryFlipStatus( P3_THUNKEDDATA* pThisDisplay, FLATPTR fpVidMem, BOOL bAllowDMAFlush ) { // If fpVidMem == 0, the Query is asking for the 'general flip status'. // The question is "Am I safe to add another flip, independent of surfaces". // If fpVidmem != 0, the Query is asking if it is safe to 'use' the current // fpvidmem surface. It will only be safe to use unconditionally if that // surface has been succesfully flipped away from, OR it was not the last // surface flipped away from. // The answers will be yes, iff the RenderID of the flip travelling down // the core has been sent to the MemoryController and put in the scratch ID, // and iff the bypass pending bit has been cleared. These two checks // effectively guarantee that the previously queue'd flip has taken place. // The fpFlipFrom is a record of the last surface that was flipped away from if((fpVidMem == 0) || (fpVidMem == pThisDisplay->flipRecord.fpFlipFrom)) { DWORD dwVidControl; HRESULT hres; // Check if the pThisDisplay->dwLastFlipRenderID has completed hres = __QueryRenderIDStatus ( pThisDisplay, bAllowDMAFlush ); if ( SUCCEEDED(hres) ) { BOOL bFlipHasFinished; // OK, the previous flip has got to the end of the pipe, // but it may not actually have happened yet. // Read the Bypass pending bit. If it's clear then // we proceed. #if W95_DDRAW if ( ( ( pThisDisplay->pGLInfo->dwFlags & GMVF_DFP_DISPLAY ) != 0 ) && ( ( pThisDisplay->pGLInfo->dwScreenWidth != pThisDisplay->pGLInfo->dwVideoWidth ) || ( pThisDisplay->pGLInfo->dwScreenHeight != pThisDisplay->pGLInfo->dwVideoHeight ) ) ) { // Display driver is using the overlay on a DFP, so we need to // check the overlay pending bit, not the screen pending bit. if ( ( ( READ_GLINT_CTRL_REG(VideoOverlayUpdate) ) & 0x1 ) == 0 ) { bFlipHasFinished = TRUE; } else { bFlipHasFinished = FALSE; } } else #endif // W95_DDRAW { dwVidControl = READ_GLINT_CTRL_REG(VideoControl); if (dwVidControl & (0x1 << 7)) { bFlipHasFinished = FALSE; } else { bFlipHasFinished = TRUE; } } if ( bFlipHasFinished ) { // This flip has actually completed. return ( DD_OK ); } else { #if USE_FLIP_BACKOFF __WaitTimeDelay(); #endif //#if USE_FLIP_BACKOFF return ( DDERR_WASSTILLDRAWING ); } } else { // No, still waiting for the flip command to exit the pipe. return ( DDERR_WASSTILLDRAWING ); } } else { return ( DD_OK ); } } // _DX_QueryFlipStatus //-----------------------------Public Routine---------------------------------- // // DdFlip // // Causes the surface memory associated with the target surface to become // the primary surface, and the current surface to become the nonprimary // surface. // // DdFlip allows a display driver to perform multi-buffering. DirectDraw drivers // must implement this function. // // The driver should update its surface pointers so that the next frame will be // written to the surface to which lpSurfTarg points. If a previous flip request // is still pending, the driver should fail the call and return // DDERR_WASSTILLDRAWING. The driver should ensure that the scan line is not in // the vertical blank before performing the flip. DdFlip does not affect the // actual display of the video data. // // If the driver's hardware supports overlays or textures, DdFlip should make // any necessary checks based on the surface type before performing the flip. // // Parameters // // lpFlipData // Points to a DD_FLIPDATA structure that contains the information // required to perform the flip. // // .lpDD // Points to the DD_DIRECTDRAW_GLOBAL structure that describes // the driver. // .lpSurfCurr // Points to the DD_SURFACE_LOCAL structure describing the // current surface. // .lpSurfTarg // Points to the DD_SURFACE_LOCAL structure describing the // target surface; that is, the surface to which the driver // should flip. // .dwFlags // This is a set of flags that provide the driver with details // for the flip. This member can be a bit-wise OR of the // following flags: // // DDFLIP_EVEN // The surface to which lpSurfTarg points contains only // the even field of video data. This flag is valid only when // the surface is an overlay, and is mutually exclusive of // DDFLIP_ODD. // DDFLIP_ODD // The surface to which lpSurfTarg points contains only the // odd field of video data. This flag is valid only when the // surface is an overlay, and is mutually exclusive of // DDFLIP_EVEN. // DDFLIP_NOVSYNC // The driver should perform the flip and return immediately. // Typically, the now current back buffer (which used to be // the front buffer) is still visible until the next vertical // retrace. Subsequent operations involving the surfaces // to which lpSurfCurr and lpSurfTarg point will not check // to see if the physical flip has finished. This allows an // application to perform flips at a higher frequency than // the monitor refresh rate, although it might introduce // visible artifacts. // DDFLIP_INTERVAL2 // The driver should perform the flip on every other vertical // sync. It should return DDERR_WASSTILLDRAWING until the // second vertical retrace has occurred. This flag is mutually // exclusive of DDFLIP_INTERVAL3 and DDFLIP_INTERVAL4. // DDFLIP_INTERVAL3 // The driver should perform the flip on every third vertical // sync. It should return DDERR_WASSTILLDRAWING until the // third vertical retrace has occurred. This flag is mutually // exclusive of DDFLIP_INTERVAL2 and DDFLIP_INTERVAL4. // DDFLIP_INTERVAL4 // The driver should perform the flip on every fourth vertical // sync. It should return DDERR_WASSTILLDRAWING until the // fourth vertical retrace has occurred. This flag is mutually // exclusive of DDFLIP_INTERVAL2 and DDFLIP_INTERVAL3. // // .ddRVal // Specifies the location in which the driver writes the return // value of the DdFlip callback. A return code of DD_OK indicates // success. // .Flip // This is unused on Windows 2000. // .lpSurfCurrLeft // Points to the DD_SURFACE_LOCAL structure describing the current // left surface. // .lpSurfTargLeft // Points to the DD_SURFACE_LOCAL structure describing the left // target surface to flip to. // //----------------------------------------------------------------------------- DWORD CALLBACK DdFlip( LPDDHAL_FLIPDATA lpFlipData) { DWORD dwDDSurfaceOffset; P3_THUNKEDDATA* pThisDisplay; HRESULT ddrval; GET_THUNKEDDATA(pThisDisplay, lpFlipData->lpDD); DBG_CB_ENTRY(DdFlip); VALIDATE_MODE_AND_STATE(pThisDisplay); STOP_SOFTWARE_CURSOR(pThisDisplay); // Is the previous Flip already done? Check if the current surface is // already displayed and don't allow a new flip (unless the DDFLIP_NOVSYNC // is set) to queue if the old one isn't finished. ddrval = _DX_QueryFlipStatus(pThisDisplay, 0, TRUE); if((FAILED(ddrval)) && !(lpFlipData->dwFlags & DDFLIP_NOVSYNC)) { lpFlipData->ddRVal = DDERR_WASSTILLDRAWING; START_SOFTWARE_CURSOR(pThisDisplay); DBG_CB_EXIT(DdFlip,DDERR_WASSTILLDRAWING); return DDHAL_DRIVER_HANDLED; } // Set the flipped flag so that the D3D side does any necessary // setup updates before starting to render the next frame pThisDisplay->bFlippedSurface = TRUE; // Do the flip { P3_DMA_DEFS(); DWORD dwNewRenderID; DDRAW_OPERATION(pContext, pThisDisplay); P3_DMA_GET_BUFFER_ENTRIES(12); // Make sure all the rendering is finished SYNC_WITH_GLINT; // Check the surface type (overlay or not overlay) // Update the overlay if ((((pThisDisplay->pGLInfo->dwFlags & GMVF_DFP_DISPLAY) != 0) && ((pThisDisplay->pGLInfo->dwScreenWidth != pThisDisplay->pGLInfo->dwVideoWidth) || (pThisDisplay->pGLInfo->dwScreenHeight != pThisDisplay->pGLInfo->dwVideoHeight))) || (lpFlipData->lpSurfTarg->ddsCaps.dwCaps & DDSCAPS_OVERLAY)) { DWORD dwVideoOverlayUpdate; do { dwVideoOverlayUpdate = READ_GLINT_CTRL_REG(VideoOverlayUpdate); } while ((dwVideoOverlayUpdate & 0x1) != 0); // Just let the overlay routine do the hard work. // Tell it that this is a screen emulation. _DD_OV_UpdateSource(pThisDisplay, lpFlipData->lpSurfTarg); UPDATE_OVERLAY(pThisDisplay, !(lpFlipData->dwFlags & DDFLIP_NOVSYNC), FALSE); } else // Normal mode - flip the screen address. { ULONG ulVControl; #if W95_DDRAW // Apps should use the DDFLIP_NOVSYNC to take advantage of // the new capability of the Perm3 if (! (lpFlipData->dwFlags & DDFLIP_NOVSYNC)) { if (READ_GLINT_CTRL_REG(VideoControl) & __GP_VIDEO_ENABLE) { LOAD_GLINT_CTRL_REG(IntFlags, INTR_VBLANK_SET); while (((READ_GLINT_CTRL_REG(IntFlags)) & INTR_VBLANK_SET) == 0); } } #endif #if DX7_STEREO if (lpFlipData->dwFlags & DDFLIP_STEREO ) // will be stereo { if (lpFlipData->lpSurfTargLeft) { dwDDSurfaceOffset = (DWORD)(lpFlipData->lpSurfTargLeft->lpGbl->fpVidMem - pThisDisplay->dwScreenFlatAddr); // Update the screenbase address using the DownloadAddress // & Data mechanism (therefore through the core) SEND_P3_DATA(VTGAddress, VTG_VIDEO_ADDRESS(VID_SCREENBASERIGHT)); SEND_P3_DATA(VTGData, (dwDDSurfaceOffset >> 4) ); } ulVControl = READ_GLINT_CTRL_REG(VideoControl); LOAD_GLINT_CTRL_REG(VideoControl, ulVControl | __VIDEO_STEREOENABLE); } else { ulVControl = READ_GLINT_CTRL_REG(VideoControl); LOAD_GLINT_CTRL_REG(VideoControl, ulVControl & (~__VIDEO_STEREOENABLE)); } #endif // Get the surface offset from the start of memory dwDDSurfaceOffset = (DWORD)(lpFlipData->lpSurfTarg->lpGbl->fpVidMem - pThisDisplay->dwScreenFlatAddr); // Update the screenbase address using the DownloadAddress/data // mechanism (therefore through the core) // Setup so that DownloadData will update the ScreenBase Address. SEND_P3_DATA(VTGAddress, VTG_VIDEO_ADDRESS(VID_SCREENBASE)); SEND_P3_DATA(VTGData, (dwDDSurfaceOffset >> 4) ); } // Send a new RenderID to the chip. dwNewRenderID = GET_NEW_HOST_RENDER_ID(); SEND_HOST_RENDER_ID ( dwNewRenderID ); pThisDisplay->dwLastFlipRenderID = dwNewRenderID; // Flush the P3 Data P3_DMA_COMMIT_BUFFER(); P3_DMA_FLUSH_BUFFER(); } // Remember where we flipped from pThisDisplay->flipRecord.fpFlipFrom = lpFlipData->lpSurfCurr->lpGbl->fpVidMem; lpFlipData->ddRVal = DD_OK; START_SOFTWARE_CURSOR(pThisDisplay); DBG_CB_EXIT(DdFlip,DD_OK); return DDHAL_DRIVER_HANDLED; } // DdFlip //-----------------------------Public Routine---------------------------------- // // DdWaitForVerticalBlank // // Returns the vertical blank status of the device. // // Parameters // // lpWaitForVerticalBlank // Points to a DD_WAITFORVERTICALBLANKDATA structure that // contains the information required to obtain the vertical // blank status. // // PDD_DIRECTDRAW_GLOBAL // lpDD // Points to the DirectDraw structure representing // the DirectDraw object. // DWORD // dwFlags // Specifies how the driver should wait for the vertical blank. // This member can be one of the following values: // // DDWAITVB_I_TESTVB The driver should determine whether // a vertical blank is currently // occurring and return the status in // bIsInVB. // DDWAITVB_BLOCKBEGIN The driver should return when it // detects the beginning of the vertical // blank interval. // DDWAITVB_BLOCKBEGINEVENT Is currently unsupported on Windows // 2000 and should be ignored by the // driver. // DDWAITVB_BLOCKEND The driver should return when it // detects the end of the vertical // blank interval and display begins. // DWORD // bIsInVB // Indicates the status of the vertical blank. A value of // TRUE indicates that the device is in a vertical blank; // FALSE means that it is not. The driver should return the // current vertical blanking status in this member when // dwFlags is DDWAITVB_I_TESTVB. // DWORD // hEvent // Is currently unsupported on Windows 2000 and should be ignored // by the driver. // HRESULT // ddRVal // Is the location in which the driver writes the return value of // the DdWaitForVerticalBlank callback. A return code of DD_OK // indicates success. // VOID* // WaitForVerticalBlank // Is unused on Windows 2000. // // Return Value // DdWaitForVerticalBlank returns one of the following callback codes: // // DDHAL_DRIVER_HANDLED // DDHAL_DRIVER_NOTHANDLED // // Comments // Depending on the value of dwFlags, the driver should do the following: // // If dwFlags is DDWAITVB_I_TESTVB, the driver should query the current // vertical blanking status. The driver should set bIsInVB to TRUE if the // monitor is currently in a vertical blank; otherwise it should set it // to FALSE. // // If dwFlags is DDWAITVB_BLOCKBEGIN, the driver should block and wait // until a vertical blank begins. If a vertical blank is in progress when // the driver begins the block, the driver should wait until the next // vertical blank begins before returning. // // If dwFlags is DDWAITVB_BLOCKEND, the driver should block and wait // until a vertical blank ends. // // When the driver successfully handles the action specified in dwFlags, // it should set DD_OK in ddRVal and return DDHAL_DRIVER_HANDLED. The // driver should return DDHAL_DRIVER_NOTHANDLED for those flags that it // is incapable of handling. // // DdWaitForVerticalBlank allows an application to synchronize itself // with the vertical blanking interval (VBI). // //----------------------------------------------------------------------------- // bit in VideoControl Register #define __GP_VIDEO_ENABLE 0x0001 DWORD CALLBACK DdWaitForVerticalBlank( LPDDHAL_WAITFORVERTICALBLANKDATA lpWaitForVerticalBlank) { static BOOL bBlankReturn = TRUE; P3_THUNKEDDATA* pThisDisplay; GET_THUNKEDDATA(pThisDisplay, lpWaitForVerticalBlank->lpDD); DBG_CB_ENTRY(DdWaitForVerticalBlank); switch(lpWaitForVerticalBlank->dwFlags) { case DDWAITVB_I_TESTVB: // // just toggle the return bit when monitor is powered off // if( ! ( READ_GLINT_CTRL_REG(VideoControl) & __GP_VIDEO_ENABLE ) ) { lpWaitForVerticalBlank->bIsInVB = bBlankReturn; bBlankReturn = !bBlankReturn; } else { // Just a request for current VBLANK status lpWaitForVerticalBlank->bIsInVB = IN_VBLANK; } lpWaitForVerticalBlank->ddRVal = DD_OK; DBG_CB_EXIT(DdWaitForVerticalBlank,DD_OK); return DDHAL_DRIVER_HANDLED; case DDWAITVB_BLOCKBEGIN: // // only wait when the monitor is on // if( READ_GLINT_CTRL_REG(VideoControl) & __GP_VIDEO_ENABLE ) { // if blockbegin is requested we wait until the vertical // retrace is over, and then wait for the display period to end. while(IN_VBLANK) NULL; while(!IN_VBLANK) NULL; } lpWaitForVerticalBlank->ddRVal = DD_OK; DBG_CB_EXIT(DdWaitForVerticalBlank,DD_OK); return DDHAL_DRIVER_HANDLED; case DDWAITVB_BLOCKEND: // // only wait when the monitor is on // if( READ_GLINT_CTRL_REG(VideoControl) & __GP_VIDEO_ENABLE ) { // if blockend is requested we wait for the vblank interval to end. if( IN_VBLANK ) { while( IN_VBLANK ) NULL; } else { while(IN_DISPLAY) NULL; while(IN_VBLANK) NULL; } } lpWaitForVerticalBlank->ddRVal = DD_OK; DBG_CB_EXIT(DdWaitForVerticalBlank,DD_OK); return DDHAL_DRIVER_HANDLED; } DBG_CB_EXIT(DdWaitForVerticalBlank,0); return DDHAL_DRIVER_NOTHANDLED; } // DdWaitForVerticalBlank //-----------------------------Public Routine---------------------------------- // // DdLock // // Locks a specified area of surface memory and provides a valid pointer to a // block of memory associated with a surface. // // Parameters // lpLock // Points to a DD_LOCKDATA structure that contains the information // required to perform the lockdown. // // Members // // PDD_DIRECTDRAW_GLOBAL // lpDD // Points to a DD_DIRECTDRAW_GLOBAL structure that // describes the driver. // PDD_SURFACE_LOCAL // lpDDSurface // Points to a DD_SURFACE_LOCAL structure that describes the // surface associated with the memory region to be locked down. // DWORD // bHasRect // Specifies whether the area in rArea is valid. // RECTL // rArea // Is a RECTL structure that defines the area on the // surface to lock down. // LPVOID // lpSurfData // Is the location in which the driver can return a pointer // to the memory region that it locked down. // HRESULT // ddRVal // Is the location in which the driver writes the return value // of the DdLock callback. A return code of DD_OK // indicates success. // VOID* // Lock // Is unused on Windows 2000. // DWORD // dwFlags // Is a bitmask that tells the driver how to perform the // memory lockdown. This member is a bitwise-OR of any // of the following values: // // DDLOCK_SURFACEMEMORYPTR The driver should return a valid // memory pointer to the top of the // rectangle specified in rArea. If // no rectangle is specified, the // driver should return a pointer to // the top of the surface. // DDLOCK_WAIT This flag is reserved for system // use and should be ignored by the // driver. Otherwise performance may // be adversely hurt. // DDLOCK_READONLY The surface being locked will only // be read from. On Windows 2000, // this flag is currently never set. // DDLOCK_WRITEONLY The surface being locked will only // be written to. On Windows 2000, // this flag is currently never set. // DDLOCK_EVENT This flag is reserved for system // use and should be ignored by the // driver. // FLATPTR // fpProcess // Is a pointer to a user-mode mapping of the driver's memory. // The driver performs this mapping in DdMapMemory. // Return Value // DdLock returns one of the following callback codes: // // DDHAL_DRIVER_HANDLED // DDHAL_DRIVER_NOTHANDLED // Comments // // DdLock should set ddRVal to DDERR_WASSTILLDRAWING and return // DDHAL_DRIVER_HANDLED if a blt or flip is in progress. // // Unless otherwise specified by dwFlags, the driver can return a memory // pointer to the top of the surface in lpSurfData. If the driver needs // to calculate its own address for the surface, it can rely on the // pointer passed in fpProcess as being a per-process pointer to the // user-mode mapping of its DirectDraw-accessible frame buffer. // // A lock does not provide exclusive access to the requested memory block; // that is, multiple threads can lock the same surface at the same time. // It is the application's responsibility to synchronize access to the // memory block whose pointer is being obtained. // //----------------------------------------------------------------------------- DWORD CALLBACK DdLock( LPDDHAL_LOCKDATA lpLockData ) { HRESULT ddrval; P3_THUNKEDDATA* pThisDisplay; GET_THUNKEDDATA(pThisDisplay, lpLockData->lpDD); DBG_CB_ENTRY(DdLock); VALIDATE_MODE_AND_STATE(pThisDisplay); DBGDUMP_DDRAWSURFACE_LCL(DBGLVL, lpLockData->lpDDSurface); // This call is invoked to lock a DirectDraw Videomemory surface. To make // sure there are no pending drawing operations on the surface, flush all // drawing operations and wait for a flip if it is still pending. STOP_SOFTWARE_CURSOR(pThisDisplay); // Check to see if any pending physical flip has occurred. ddrval = _DX_QueryFlipStatus(pThisDisplay, lpLockData->lpDDSurface->lpGbl->fpVidMem, TRUE); if( FAILED(ddrval) ) { lpLockData->ddRVal = DDERR_WASSTILLDRAWING; START_SOFTWARE_CURSOR(pThisDisplay); DBG_CB_EXIT(DdLock,DDERR_WASSTILLDRAWING); return DDHAL_DRIVER_HANDLED; } // don't allow a lock if a blt is in progress if(DRAW_ENGINE_BUSY(pThisDisplay)) { lpLockData->ddRVal = DDERR_WASSTILLDRAWING; START_SOFTWARE_CURSOR(pThisDisplay); DBG_CB_EXIT(DdLock, lpLockData->ddRVal); return DDHAL_DRIVER_HANDLED; } #if DX7_TEXMANAGEMENT // // If the user attempts to lock a driver managed surface, // mark it as dirty and return. This way next time we attempt // to use the surface we will reload it from the sysmem copy // if (lpLockData->lpDDSurface->lpSurfMore->ddsCapsEx.dwCaps2 & DDSCAPS2_TEXTUREMANAGE) { DISPDBG((DBGLVL, "DDraw:Lock %08lx %08lx", lpLockData->lpDDSurface->lpSurfMore->dwSurfaceHandle, lpLockData->lpDDSurface->lpGbl->fpVidMem)); _D3D_TM_MarkDDSurfaceAsDirty(pThisDisplay, lpLockData->lpDDSurface, TRUE); if (lpLockData->bHasRect) { #if DX8_3DTEXTURES if (lpLockData->dwFlags & DDLOCK_HASVOLUMETEXTUREBOXRECT) { DWORD left, right, front, back; // Sub Volume Lock suppport (DX8.1 feature) // Check if we are able to lock just a subvolume instead of // the whole volume texture and therefore potentially increase // performance. // left and .right subfields of the rArea field have to be // reinterpreted as also containing respectively the Front and // Back coordinates of the locked volume in their higher 16 bits front = lpLockData->rArea.left >> 16; back = lpLockData->rArea.right >> 16; left = lpLockData->rArea.left && 0xFFFF; right = lpLockData->rArea.right && 0xFFFF; lpLockData->lpSurfData = (LPVOID) (lpLockData->lpDDSurface->lpGbl->fpVidMem + (front * lpLockData->lpDDSurface->lpGbl->dwBlockSizeY ) + (lpLockData->lpDDSurface->lpGbl->lPitch * lpLockData->rArea.top) + (lpLockData->rArea.left << DDSurf_GetPixelShift(lpLockData->lpDDSurface))); } else #endif // DX8_3DTEXTURES { lpLockData->lpSurfData = (LPVOID) (lpLockData->lpDDSurface->lpGbl->fpVidMem + (lpLockData->lpDDSurface->lpGbl->lPitch * lpLockData->rArea.top) + (lpLockData->rArea.left << DDSurf_GetPixelShift(lpLockData->lpDDSurface))); } } else { lpLockData->lpSurfData = (LPVOID) (lpLockData->lpDDSurface->lpGbl->fpVidMem); } lpLockData->ddRVal = DD_OK; START_SOFTWARE_CURSOR(pThisDisplay); DBG_CB_EXIT(DdLock, lpLockData->ddRVal); return DDHAL_DRIVER_HANDLED; } #endif // DX7_TEXMANAGEMENT // Switch to DirectDraw context DDRAW_OPERATION(pContext, pThisDisplay); // send a flush and wait for outstanding operations // before allowing surfaces to be locked. {P3_DMA_DEFS(); P3_DMA_GET_BUFFER(); P3_DMA_FLUSH_BUFFER(); } // Wait for outstanding operations before allowing surfaces to be locked SYNC_WITH_GLINT; // Since all our surfaces are linear we don't need to do // a patch->unpatch conversion here. START_SOFTWARE_CURSOR(pThisDisplay); lpLockData->ddRVal = DD_OK; DBG_CB_EXIT(DdLock,lpLockData->ddRVal); // Because we correctly set fpVidMem to be the offset into our frame // buffer when we created the surface, DirectDraw will automatically take // care of adding in the user-mode frame buffer address if we return // DDHAL_DRIVER_NOTHANDLED return(DDHAL_DRIVER_NOTHANDLED); } // DdLock //-----------------------------Public Routine---------------------------------- // // DdUnlock // // Releases the lock held on the specified surface. // // Parameters // // lpUnlock // Points to a DD_UNLOCKDATA structure that contains the // information required to perform the lock release. // // Members // // PDD_DIRECTDRAW_GLOBAL // lpDD // Points to a DD_DIRECTDRAW_GLOBAL structure that // describes the driver. // PDD_SURFACE_LOCAL // lpDDSurface // Points to a DD_SURFACE_LOCAL structure that describes the // surface to be unlocked. // HRESULT // ddRVal // Is the location in which the driver writes the return value // of the DdUnlock callback. A return code of DD_OK indicates // success. // VOID* // Unlock // Is unused on Windows 2000. // // Return Value // DdUnlock returns one of the following callback codes: // // DDHAL_DRIVER_HANDLED // DDHAL_DRIVER_NOTHANDLED // // Comments // The driver does not need to verify that the memory was previously // locked down by DdLock, because DirectDraw does parameter validation // before calling this routine. //----------------------------------------------------------------------------- DWORD CALLBACK DdUnlock( LPDDHAL_UNLOCKDATA lpUnlockData ) { P3_THUNKEDDATA* pThisDisplay; DBG_CB_ENTRY(DdUnlock); lpUnlockData->ddRVal = DD_OK; DBG_CB_EXIT(DdUnlock,lpUnlockData->ddRVal); return ( DDHAL_DRIVER_HANDLED ); } // DdUnlock //-----------------------------Public Routine---------------------------------- // DdGetScanLine // // Returns the number of the current physical scan line. // // Parameters // pGetScanLine // Points to a DD_GETSCANLINEDATA structure in which the // driver returns the number of the current scan line. // Members // // PDD_DIRECTDRAW_GLOBAL // lpDD // Points to a DD_DIRECTDRAW_GLOBAL structure that // represents the driver. // DWORD // dwScanLine // Is the location in which the driver returns the number // of the current scan line. // HRESULT // ddRVal // Is the location in which the driver writes the return // value of the DdGetScanLine callback. A return code of // DD_OK indicates success. // VOID * // GetScanLine // Is unused on Windows 2000. // Return Value // DdGetScanLine returns one of the following callback codes: // // DDHAL_DRIVER_HANDLED // DDHAL_DRIVER_NOTHANDLED // // Comments // If the monitor is not in vertical blank, the driver should write // the scan line value in dwScanLine. The number must be between zero // and n, where scan line 0 is the first visible scan line and n is // the last visible scan line on the screen. The driver should then // set DD_OK in ddRVal and return DDHAL_DRIVER_HANDLED. // // The scan line is indeterminate if a vertical blank is in progress. // In this situation, the driver should set ddRVal to // DDERR_VERTICALBLANKINPROGRESS and return DDHAL_DRIVER_HANDLED. // //----------------------------------------------------------------------------- DWORD CALLBACK DdGetScanLine( LPDDHAL_GETSCANLINEDATA lpGetScanLine) { P3_THUNKEDDATA* pThisDisplay; GET_THUNKEDDATA(pThisDisplay, lpGetScanLine->lpDD); DBG_CB_ENTRY(DdGetScanLine); VALIDATE_MODE_AND_STATE(pThisDisplay); // // 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( IN_VBLANK ) { lpGetScanLine->ddRVal = DDERR_VERTICALBLANKINPROGRESS; lpGetScanLine->dwScanLine = 0; } else { LONG lVBEnd = READ_GLINT_CTRL_REG(VbEnd); LONG lScanline = READ_GLINT_CTRL_REG(LineCount); // Need to return a number from 0 -> (ScreenHeight + VBlank Size) lScanline = lScanline - lVBEnd; if (lScanline < 0) { lScanline = pThisDisplay->dwScreenHeight + (lVBEnd + lScanline); } // Modes less than 400 high are line-doubled. if (pThisDisplay->dwScreenHeight < 400) { lScanline >>= 1; } DISPDBG((DBGLVL,"Scanline: %d", lScanline)); lpGetScanLine->dwScanLine = (DWORD)lScanline; lpGetScanLine->ddRVal = DD_OK; } DBG_CB_EXIT(DdGetScanLine,lpGetScanLine->ddRVal); return DDHAL_DRIVER_HANDLED; } // DdGetScanLine //-----------------------------Public Routine---------------------------------- // DdGetBltStatus // // Queries the blt status of the specified surface. // // Parameters // lpGetBltStatus // Points to a DD_GETBLTSTATUSDATA structure that contains the // information required to perform the blt status query. // // Members // // PDD_DIRECTDRAW_GLOBAL // lpDD // Points to a DD_DIRECTDRAW_GLOBAL structure that // describes the driver. // PDD_SURFACE_LOCAL // lpDDSurface // Points to a DD_SURFACE_LOCAL structure // representing the surface whose blt status is // being queried. // DWORD // dwFlags // Specifies the blt status being requested. This // member can be one of the following values which // are defined in ddraw.h: // // DDGBS_CANBLT Queries whether the driver // can currently perform a blit. // DDGBS_ISBLTDONE Queries whether the driver // has completed the last blit. // HRESULT // ddRVal // Is the location in which the driver writes the // return value of the DdGetBltStatus callback. // A return code of DD_OK indicates success. // VOID* // GetBltStatus // Is unused on Windows 2000. // Return Value // DdGetBltStatus returns one of the following callback codes: // // DDHAL_DRIVER_HANDLED // DDHAL_DRIVER_NOTHANDLED // // Comments // The blt status that the driver returns is based on the dwFlags // member of the structure that lpGetBltStatus points to as follows: // // If the flag is DDGBS_CANBLT, the driver should determine whether // the surface is currently involved in a flip. If a flip is not in // progress and if the hardware is otherwise capable of currently // accepting a blt request, the driver should return DD_OK in ddRVal. // If a flip is in progress or if the hardware cannot currently // accept another blt request, the driver should set ddRVal to // DDERR_WASSTILLDRAWING. // // If the flag is DDGBS_ISBLTDONE, the driver should set ddRVal to // DDERR_WASSTILLDRAWING if a blt is currently in progress; otherwise // it should return DD_OK. // // //----------------------------------------------------------------------------- DWORD CALLBACK DdGetBltStatus( LPDDHAL_GETBLTSTATUSDATA lpGetBltStatus ) { P3_THUNKEDDATA* pThisDisplay; GET_THUNKEDDATA(pThisDisplay, lpGetBltStatus->lpDD); DBG_CB_ENTRY(DdGetBltStatus); STOP_SOFTWARE_CURSOR(pThisDisplay); // Notice that your implementation could be optimized to check for the // particular surface specified. Here we are just querying the general // blt status of the engine. // Driver is being queried whether it can add a blt if( lpGetBltStatus->dwFlags == DDGBS_CANBLT ) { // Must explicitely wait for the flip lpGetBltStatus->ddRVal = _DX_QueryFlipStatus(pThisDisplay, lpGetBltStatus->lpDDSurface->lpGbl->fpVidMem, TRUE); if( SUCCEEDED( lpGetBltStatus->ddRVal ) ) { // so there was no flip going on, is the engine idle to add a blt? if( DRAW_ENGINE_BUSY(pThisDisplay) ) { lpGetBltStatus->ddRVal = DDERR_WASSTILLDRAWING; } else { lpGetBltStatus->ddRVal = DD_OK; } } } else if ( lpGetBltStatus->dwFlags == DDGBS_ISBLTDONE ) { if ( DRAW_ENGINE_BUSY(pThisDisplay) ) { lpGetBltStatus->ddRVal = DDERR_WASSTILLDRAWING; } else { lpGetBltStatus->ddRVal = DD_OK; } } START_SOFTWARE_CURSOR(pThisDisplay); DBG_CB_EXIT(DdGetBltStatus, lpGetBltStatus->ddRVal); return DDHAL_DRIVER_HANDLED; } // DdGetBltStatus //-----------------------------Public Routine---------------------------------- // // DdGetFlipStatus // // Determines whether the most recently requested flip // on a surface has occurred. // // Parameters // lpGetFlipStatus // Points to a DD_GETFLIPSTATUSDATA structure that contains // the information required to perform the flip status query. // // Members // // PDD_DIRECTDRAW_GLOBAL // lpDD // Points to a DD_DIRECTDRAW_GLOBAL structure // representing the driver. // PDD_SURFACE_LOCAL // lpDDSurface // Points to a DD_SURFACE_LOCAL structure that // describes the surface whose flip status is // being queried. // DWORD // dwFlags // Specifies the flip status being requested. This // member can be one of the following values which // are defined in ddraw.h: // // DDGFS_CANFLIP Queries whether the driver can // currently perform a flip. // DDGFS_ISFLIPDONE Queries whether the driver has // finished the last flip. // HRESULT // ddRVal // Is the location in which the driver writes the // return value of the DdGetFlipStatus callback. // A return code of DD_OK indicates success. // VOID* // GetFlipStatus // Is unused on Windows 2000. // // Return Value // DdGetFlipStatus returns one of the following callback codes: // // DDHAL_DRIVER_HANDLED // DDHAL_DRIVER_NOTHANDLED // // Comments // // The driver should report its flip status based on the flag set in // the dwFlags member of the structure that lpGetFlipStatus points // to as follows: // // If the flag is DDGFS_CANFLIP, the driver should determine whether // the surface is currently involved in a flip. If a flip or a blt is // not in progress and if the hardware is otherwise capable of // currently accepting a flip request, the driver should return DD_OK // in ddRVal. If a flip is in progress or if the hardware cannot // currently accept a flip request, the driver should set ddRVal to // DDERR_WASSTILLDRAWING. // // If the flag is DDGFS_ISFLIPDONE, the driver should set ddRVal to // DDERR_WASSTILLDRAWING if a flip is currently in progress; otherwise // it should return DD_OK. // // Notes: // // If the display has went through one refresh cycle since the flip // occurred we return DD_OK. If it has not went 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 // // On the Permedia, flips are done using SuspendUntilFrameBlank, // so no syncs ever need to be done in software, so this always // returns DD_OK. // //----------------------------------------------------------------------------- DWORD CALLBACK DdGetFlipStatus( LPDDHAL_GETFLIPSTATUSDATA lpGetFlipStatus ) { P3_THUNKEDDATA* pThisDisplay; GET_THUNKEDDATA(pThisDisplay, lpGetFlipStatus->lpDD); DBG_CB_ENTRY(DdGetFlipStatus); STOP_SOFTWARE_CURSOR(pThisDisplay); // // 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 // lpGetFlipStatus->ddRVal = _DX_QueryFlipStatus(pThisDisplay, 0, TRUE); // // check if the bltter busy if someone wants to know if they can flip // if( lpGetFlipStatus->dwFlags == DDGFS_CANFLIP ) { if( ( SUCCEEDED( lpGetFlipStatus->ddRVal ) ) && ( DRAW_ENGINE_BUSY(pThisDisplay) ) ) { lpGetFlipStatus->ddRVal = DDERR_WASSTILLDRAWING; } } START_SOFTWARE_CURSOR(pThisDisplay); DBG_CB_EXIT(DdGetFlipStatus,lpGetFlipStatus->ddRVal); return DDHAL_DRIVER_HANDLED; } // DdGetFlipStatus //----------------------------------------------------------------------------- // __SetupRops // // Build array for supported ROPS //----------------------------------------------------------------------------- static void __SetupRops( LPBYTE proplist, LPDWORD proptable, int cnt ) { int i; DWORD idx; DWORD bit; DWORD rop; for(i=0; idwScreenWidth)); //@@BEGIN_DDKSPLIT #if AZN // If the driver has just started, reset the DMA Buffers to a known state. if (pThisDisplay->bStartOfDay) { #if 0 unsigned long i; for (i = 0; i < pThisDisplay->pGLInfo->NumberOfSubBuffers; i++) { pThisDisplay->pGLInfo->DMAPartition[i].bStampedDMA = TRUE; pThisDisplay->pGLInfo->DMAPartition[i].Locked = FALSE; //azn - this is hard to say in 64 bits! memset((void*)pThisDisplay->pGLInfo->DMAPartition[i].VirtAddr, 0x4D, (pThisDisplay->pGLInfo->DMAPartition[i].MaxAddress - pThisDisplay->pGLInfo->DMAPartition[i].VirtAddr)); } #endif // We don't need start of day setup anymore pThisDisplay->bStartOfDay = FALSE; } #endif //@@END_DDKSPLIT STOP_SOFTWARE_CURSOR(pThisDisplay); // Switch to DirectDraw context DDRAW_OPERATION(pContext, pThisDisplay); // Set up video Control #if WNT_DDRAW { ULONG vidCon; vidCon = READ_GLINT_CTRL_REG(VideoControl); vidCon &= ~(3 << 9); vidCon |= (0 << 9); // P3/P2 Limit to frame rate LOAD_GLINT_CTRL_REG(VideoControl, vidCon); } #endif // WNT_DDRAW // We have handled the display mode change pThisDisplay->bResetMode = 0; pThisDisplay->ModeChangeCount++; START_SOFTWARE_CURSOR(pThisDisplay); } // ChangeDDHAL32Mode //----------------------------------------------------------------------------- // // Function: __GetDDHALInfo // // Returns: void // // Description: // // Takes a pointer to a partially or fully filled in pThisDisplay and a pointer // to an empty DDHALINFO and fills in the DDHALINFO. This eases porting to NT // and means that caps changes are done in only one place. The pThisDisplay // may not be fully constructed here, so you should only: // a) Query the registry // b) DISPDBG // If you need to add anything to pThisDisplay for NT, you should fill it in // during the DrvGetDirectDraw call. // // The problem here is when the code is run on NT. If there was any other way... // // The following caps have been found to cause NT to bail.... // DDCAPS_GDI, DDFXCAPS_BLTMIRRORUPDOWN, DDFXCAPS_BLTMIRRORLEFTRIGHT // // //----------------------------------------------------------------------------- // // use bits to indicate which ROPs you support. // // DWORD 0, bit 0 == ROP 0 // DWORD 8, bit 31 == ROP 255 // static DWORD ropsAGP[DD_ROP_SPACE] = { 0 }; void __GetDDHALInfo( P3_THUNKEDDATA* pThisDisplay, DDHALINFO* pHALInfo) { DWORD dwResult; BOOL bRet; int i; static BYTE ropList95[] = { SRCCOPY >> 16, WHITENESS >> 16, BLACKNESS >> 16 }; static BYTE ropListNT[] = { SRCCOPY >> 16 }; static BYTE ropListAGP[] = { SRCCOPY >> 16, WHITENESS >> 16, BLACKNESS >> 16 }; static DWORD rops[DD_ROP_SPACE] = { 0 }; // Setup the HAL driver caps. memset( pHALInfo, 0, sizeof(DDHALINFO) ); pHALInfo->dwSize = sizeof(DDHALINFO); // Setup the ROPS we do. #ifdef WNT_DDRAW __SetupRops( ropListNT, rops, sizeof(ropListNT)/sizeof(ropListNT[0])); #else __SetupRops( ropList95, rops, sizeof(ropList95)/sizeof(ropList95[0])); #endif __SetupRops( ropListAGP, ropsAGP, sizeof(ropListAGP)/sizeof(ropListAGP[0])); // The most basic DirectDraw functionality pHALInfo->ddCaps.dwCaps = DDCAPS_BLT | DDCAPS_BLTQUEUE | DDCAPS_BLTCOLORFILL | DDCAPS_READSCANLINE; pHALInfo->ddCaps.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP; // More caps on Win95 than on NT (mainly for D3D) #ifdef WNT_DDRAW pHALInfo->ddCaps.dwCaps |= DDCAPS_3D | DDCAPS_BLTDEPTHFILL; pHALInfo->ddCaps.ddsCaps.dwCaps |= DDSCAPS_3DDEVICE | DDSCAPS_ZBUFFER | DDSCAPS_ALPHA; pHALInfo->ddCaps.dwCaps2 = 0; #else pHALInfo->ddCaps.dwCaps |= DDCAPS_3D | DDCAPS_GDI | DDCAPS_ALPHA | DDCAPS_BLTDEPTHFILL; pHALInfo->ddCaps.ddsCaps.dwCaps |= DDSCAPS_ALPHA | DDSCAPS_3DDEVICE | DDSCAPS_ZBUFFER; pHALInfo->ddCaps.dwCaps2 = DDCAPS2_NOPAGELOCKREQUIRED | DDCAPS2_FLIPNOVSYNC; #endif // WNT_DDRAW #if DX7_TEXMANAGEMENT // We need to set this bit up in order to be able to do // out own texture management pHALInfo->ddCaps.dwCaps2 |= DDCAPS2_CANMANAGETEXTURE; #if DX8_DDI pHALInfo->ddCaps.dwCaps2 |= DDCAPS2_CANMANAGERESOURCE; #endif #endif #if DX8_DDI // We need to flag we can run in windowed mode, otherwise we // might get restricted by apps to run in fullscreen only pHALInfo->ddCaps.dwCaps2 |= DDCAPS2_CANRENDERWINDOWED; #endif pHALInfo->ddCaps.dwFXCaps = 0; // P3RX can do: // 1. Stretching/Shrinking // 2. YUV->RGB conversion // 3. Mirroring in X and Y // 4. ColorKeying from a source color and a source color space pHALInfo->ddCaps.dwCaps |= DDCAPS_BLTSTRETCH | DDCAPS_BLTFOURCC | DDCAPS_COLORKEY | DDCAPS_CANBLTSYSMEM; // Special effects caps pHALInfo->ddCaps.dwFXCaps = DDFXCAPS_BLTSTRETCHY | DDFXCAPS_BLTSTRETCHX | DDFXCAPS_BLTSTRETCHYN | DDFXCAPS_BLTSTRETCHXN | DDFXCAPS_BLTSHRINKY | DDFXCAPS_BLTSHRINKX | DDFXCAPS_BLTSHRINKYN | DDFXCAPS_BLTSHRINKXN; // ColorKey caps pHALInfo->ddCaps.dwCKeyCaps = DDCKEYCAPS_SRCBLT | DDCKEYCAPS_SRCBLTCLRSPACE | DDCKEYCAPS_DESTBLT | DDCKEYCAPS_DESTBLTCLRSPACE; pHALInfo->ddCaps.dwSVBCaps = DDCAPS_BLT; // We can do a texture from sysmem to video mem. pHALInfo->ddCaps.dwSVBCKeyCaps = DDCKEYCAPS_DESTBLT | DDCKEYCAPS_DESTBLTCLRSPACE; pHALInfo->ddCaps.dwSVBFXCaps = 0; // Fill in the sysmem->vidmem rops (only can copy); for( i=0;iddCaps.dwSVBRops[i] = rops[i]; } pHALInfo->ddCaps.dwFXCaps |= DDFXCAPS_BLTMIRRORUPDOWN | DDFXCAPS_BLTMIRRORLEFTRIGHT; pHALInfo->ddCaps.dwCKeyCaps |= DDCKEYCAPS_SRCBLTCLRSPACEYUV; pHALInfo->ddCaps.ddsCaps.dwCaps |= DDSCAPS_TEXTURE; #if DX7_STEREO // Report the stereo capability back to runtime pHALInfo->ddCaps.dwCaps2 |= DDCAPS2_STEREO; pHALInfo->ddCaps.dwSVCaps = DDSVCAPS_STEREOSEQUENTIAL; #endif // Z Buffer is only 16 Bits pHALInfo->ddCaps.dwZBufferBitDepths = DDBD_16; pHALInfo->ddCaps.ddsCaps.dwCaps |= DDSCAPS_MIPMAP; if (pThisDisplay->bCanAGP && (pThisDisplay->dwDXVersion > DX5_RUNTIME)) { pHALInfo->ddCaps.dwCaps2 |= DDCAPS2_NONLOCALVIDMEM; pHALInfo->ddCaps.ddsCaps.dwCaps |= DDSCAPS_LOCALVIDMEM | DDSCAPS_NONLOCALVIDMEM; // We support the hybrid AGP model. This means we have // specific things we can do from AGP->Video memory, but // we can also texture directly from AGP memory pHALInfo->ddCaps.dwCaps2 |= DDCAPS2_NONLOCALVIDMEMCAPS; } else { DISPDBG((WRNLVL,"P3 Board is NOT AGP")); } // If we are a P3 we can do videoports if (RENDERCHIP_PERMEDIAP3) { #ifdef SUPPORT_VIDEOPORT // We support 1 video port. Must set CurrVideoPorts to 0 // We can't do interleaved bobbing yet - maybe in the future. pHALInfo->ddCaps.dwCaps2 |= DDCAPS2_VIDEOPORT | DDCAPS2_CANBOBNONINTERLEAVED; pHALInfo->ddCaps.dwMaxVideoPorts = 1; pHALInfo->ddCaps.dwCurrVideoPorts = 0; #if W95_DDRAW pHALInfo->ddCaps.ddsCaps.dwCaps |= DDSCAPS_VIDEOPORT; #endif // W95_DDRAW #endif // SUPPORT_VIDEOPORT if ( ( ( pThisDisplay->pGLInfo->dwFlags & GMVF_DFP_DISPLAY ) != 0 ) && ( ( pThisDisplay->pGLInfo->dwScreenWidth != pThisDisplay->pGLInfo->dwVideoWidth ) || ( pThisDisplay->pGLInfo->dwScreenHeight != pThisDisplay->pGLInfo->dwVideoHeight ) ) ) { // Display driver is using the overlay to show the // picture - disable the overlay. pHALInfo->ddCaps.dwMaxVisibleOverlays = 0; pHALInfo->ddCaps.dwCurrVisibleOverlays = 0; } #if WNT_DDRAW else if (pThisDisplay->ppdev->flCaps & CAPS_DISABLE_OVERLAY) #else else if (pThisDisplay->pGLInfo->dwFlags & GMVF_DISABLE_OVERLAY) #endif { // Overlays not supported in hw pHALInfo->ddCaps.dwMaxVisibleOverlays = 0; pHALInfo->ddCaps.dwCurrVisibleOverlays = 0; } else { // Overlay is free to use. pHALInfo->ddCaps.dwMaxVisibleOverlays = 1; pHALInfo->ddCaps.dwCurrVisibleOverlays = 0; pHALInfo->ddCaps.dwCaps |= DDCAPS_OVERLAY | DDCAPS_OVERLAYFOURCC | DDCAPS_OVERLAYSTRETCH | DDCAPS_COLORKEYHWASSIST | DDCAPS_OVERLAYCANTCLIP; pHALInfo->ddCaps.dwCKeyCaps |= DDCKEYCAPS_SRCOVERLAY | DDCKEYCAPS_SRCOVERLAYONEACTIVE | DDCKEYCAPS_SRCOVERLAYYUV | DDCKEYCAPS_DESTOVERLAY | DDCKEYCAPS_DESTOVERLAYONEACTIVE | DDCKEYCAPS_DESTOVERLAYYUV; pHALInfo->ddCaps.ddsCaps.dwCaps |= DDSCAPS_OVERLAY; pHALInfo->ddCaps.dwFXCaps |= DDFXCAPS_OVERLAYSHRINKX | DDFXCAPS_OVERLAYSHRINKXN | DDFXCAPS_OVERLAYSHRINKY | DDFXCAPS_OVERLAYSHRINKYN | DDFXCAPS_OVERLAYSTRETCHX | DDFXCAPS_OVERLAYSTRETCHXN | DDFXCAPS_OVERLAYSTRETCHY | DDFXCAPS_OVERLAYSTRETCHYN; // Indicates that Perm3 has no stretch ratio limitation pHALInfo->ddCaps.dwMinOverlayStretch = 1; pHALInfo->ddCaps.dwMaxOverlayStretch = 32000; } } #ifdef W95_DDRAW // Enable colour control asc brightness, contrast, gamma. pHALInfo->ddCaps.dwCaps2 |= DDCAPS2_COLORCONTROLPRIMARY; #endif // Also permit surfaces wider than the display buffer. pHALInfo->ddCaps.dwCaps2 |= DDCAPS2_WIDESURFACES; // Enable copy blts betweemn Four CC formats for DShow acceleration pHALInfo->ddCaps.dwCaps2 |= DDCAPS2_COPYFOURCC; // Won't do Video-Sys mem Blits. pHALInfo->ddCaps.dwVSBCaps = 0; pHALInfo->ddCaps.dwVSBCKeyCaps = 0; pHALInfo->ddCaps.dwVSBFXCaps = 0; for( i=0;iddCaps.dwVSBRops[i] = 0; } // Won't do Sys-Sys mem Blits pHALInfo->ddCaps.dwSSBCaps = 0; pHALInfo->ddCaps.dwSSBCKeyCaps = 0; pHALInfo->ddCaps.dwSSBFXCaps = 0; for( i=0;iddCaps.dwSSBRops[i] = 0; } // // bit depths supported for alpha and Z // pHALInfo->ddCaps.dwAlphaBltConstBitDepths = DDBD_2 | DDBD_4 | DDBD_8; pHALInfo->ddCaps.dwAlphaBltPixelBitDepths = DDBD_1 | DDBD_8; pHALInfo->ddCaps.dwAlphaBltSurfaceBitDepths = DDBD_1 | DDBD_2 | DDBD_4 | DDBD_8; // No alpha blending for overlays, so I'm not sure what these should be. // Because we support 32bpp overlays, it's just that you can't use the // alpha bits for blending. Pass. pHALInfo->ddCaps.dwAlphaBltConstBitDepths = DDBD_2 | DDBD_4 | DDBD_8; pHALInfo->ddCaps.dwAlphaBltPixelBitDepths = DDBD_1 | DDBD_8; pHALInfo->ddCaps.dwAlphaBltSurfaceBitDepths = DDBD_1 | DDBD_2 | DDBD_4 | DDBD_8; // // ROPS supported // for( i=0;iddCaps.dwRops[i] = rops[i]; } #if W95_DDRAW // Reset to NULL for debugging pThisDisplay->lpD3DGlobalDriverData = 0; ZeroMemory(&pThisDisplay->DDExeBufCallbacks, sizeof(DDHAL_DDEXEBUFCALLBACKS)); // Note that the NT code does this elsewhere _D3DHALCreateDriver( pThisDisplay); // (LPD3DHAL_GLOBALDRIVERDATA*)&pThisDisplay->lpD3DGlobalDriverData, // (LPD3DHAL_CALLBACKS*) &pThisDisplay->lpD3DHALCallbacks, // &pThisDisplay->DDExeBufCallbacks); // If we filled in the execute buffer callbacks, set the cap bit if (pThisDisplay->DDExeBufCallbacks.dwSize != 0) { pHALInfo->ddCaps.ddsCaps.dwCaps |= DDSCAPS_EXECUTEBUFFER; } #endif // For DX5 and beyond we support this new informational callback. pHALInfo->GetDriverInfo = DdGetDriverInfo; pHALInfo->dwFlags |= DDHALINFO_GETDRIVERINFOSET; #if DX8_DDI // Flag our support for a new class of GUIDs that may come through // GetDriverInfo for DX8 drivers. (This support will be compulsory) pHALInfo->dwFlags |= DDHALINFO_GETDRIVERINFO2; #endif DX8_DDI } // __GetDDHALInfo static HashTable* g_pDirectDrawLocalsHashTable = NULL; // azn //----------------------------------------------------------------------------- // // _DD_InitDDHAL32Bit // // CALLED ONCE AT START OF DAY // No Chip register setup is done here - it is all handled in the mode // change code. DO NOT DO IT HERE - THERE IS NO WIN16LOCK AT THIS TIME!!! // //----------------------------------------------------------------------------- BOOL _DD_InitDDHAL32Bit( P3_THUNKEDDATA* pThisDisplay) { BOOL bRet; DWORD Result; LPGLINTINFO pGLInfo = pThisDisplay->pGLInfo; ASSERTDD(pGLInfo != NULL, "ERROR: pGLInfo not valid!"); // Note: Can't use P3_DMA_DEFS macro here, as pGlint isn't initialised yet. DISPDBG((DBGLVL, "** In _DD_InitDDHAL32Bit, pGlint 0x%x", pThisDisplay->control)); DISPDBG((DBGLVL, "Sizeof DDHALINFO: %d", (int) sizeof(DDHALINFO))); // Force D3D to setup surface offsets as if a flip had happened pThisDisplay->bFlippedSurface = TRUE; // A flag to say that the driver is essentially at the start of day. This // is set to let later calls in the driver know that they have work to do. pThisDisplay->bStartOfDay = TRUE; #if W95_DDRAW // At start of day the videoport is dead to the world pThisDisplay->VidPort.bActive = FALSE; #endif // W95_DDRAW // Reset the GART copies. pThisDisplay->dwGARTLin = 0; pThisDisplay->dwGARTDev = 0; pThisDisplay->dwGARTLinBase = 0; pThisDisplay->dwGARTDevBase = 0; pThisDisplay->pGlint = (FPGLREG)pThisDisplay->control; // Set up the global overlay data pThisDisplay->bOverlayVisible = (DWORD)FALSE; pThisDisplay->OverlayDstRectL = 0; pThisDisplay->OverlayDstRectR = 0; pThisDisplay->OverlayDstRectT = 0; pThisDisplay->OverlayDstRectB = 0; pThisDisplay->OverlaySrcRectL = 0; pThisDisplay->OverlaySrcRectR = 0; pThisDisplay->OverlaySrcRectT = 0; pThisDisplay->OverlaySrcRectB = 0; pThisDisplay->OverlayDstSurfLcl = (ULONG_PTR)NULL; pThisDisplay->OverlaySrcSurfLcl = (ULONG_PTR)NULL; pThisDisplay->OverlayDstColourKey = CLR_INVALID; pThisDisplay->OverlaySrcColourKey = CLR_INVALID; pThisDisplay->OverlayClipRgnMem = (ULONG_PTR)NULL; pThisDisplay->OverlayClipRgnMemSize = 0; pThisDisplay->OverlayUpdateCountdown = 0; pThisDisplay->bOverlayFlippedThisVbl = (DWORD)FALSE; pThisDisplay->bOverlayUpdatedThisVbl = (DWORD)FALSE; pThisDisplay->OverlayTempSurf.VidMem = (ULONG_PTR)NULL; pThisDisplay->OverlayTempSurf.Pitch = (DWORD)0; #if W95_DDRAW // Set up colour control data. pThisDisplay->ColConBrightness = 0; pThisDisplay->ColConContrast = 10000; pThisDisplay->ColConGamma = 100; #endif // W95_DDRAW #if DX7_VIDMEM_VB // Set up DrawPrim temporary index buffer. pThisDisplay->DrawPrimIndexBufferMem = (ULONG_PTR)NULL; pThisDisplay->DrawPrimIndexBufferMemSize = 0; pThisDisplay->DrawPrimVertexBufferMem = (ULONG_PTR)NULL; pThisDisplay->DrawPrimVertexBufferMemSize = 0; #endif // DX7_VIDMEM_VB // Set up current RenderID to be as far away from a "sensible" // value as possible. Hopefully, if the context switch fails and // someone starts using it for something else, these values and // the ones they use will be very different, and various asserts // will scream immediately. // Also, say that the RenderID is invalid, because we have not actually // set up the chip. The context switch should set up & flush the // chip, and then it will set bRenderIDValid to TRUE. // Loads of asserts throughout the code will scream if something // doesn't do the setup & flush for some reason. pThisDisplay->dwRenderID = 0x8eaddead | RENDER_ID_KNACKERED_BITS; pThisDisplay->dwLastFlipRenderID = 0x8eaddead | RENDER_ID_KNACKERED_BITS; pThisDisplay->bRenderIDValid = (DWORD)FALSE; #if W95_DDRAW // Create a shared heap if (g_DXGlobals.hHeap32 == 0) g_DXGlobals.hHeap32 = (DWORD)HeapCreate( HEAP_SHARED, 2500, 0); #endif // W95_DDRAW // Make sure we're running the right chip. If not, STOP. ASSERTDD((RENDERCHIP_P3RXFAMILY),"ERROR: Invalid RENDERFAMILY!!"); // Dump some debugging information DISPDBG((DBGLVL, "************* _DD_InitDDHAL32Bit *************************************" )); DISPDBG((DBGLVL, " dwScreenFlatAddr=%08lx", pThisDisplay->dwScreenFlatAddr )); DISPDBG((DBGLVL, " dwScreenStart =%08lx", pThisDisplay->dwScreenStart)); DISPDBG((DBGLVL, " dwLocalBuffer=%08lx", pThisDisplay->dwLocalBuffer )); DISPDBG((DBGLVL, " dwScreenWidth=%08lx", pThisDisplay->dwScreenWidth )); DISPDBG((DBGLVL, " dwScreenHeight=%08lx", pThisDisplay->dwScreenHeight )); DISPDBG((DBGLVL, " bReset=%08lx", pThisDisplay->bResetMode )); DISPDBG((DBGLVL, " dwRGBBitCount=%ld", pThisDisplay->ddpfDisplay.dwRGBBitCount )); DISPDBG((DBGLVL, " pGLInfo=%08lp", pGLInfo )); DISPDBG((DBGLVL, " Render: 0x%x, Rev:0x%x", pGLInfo->dwRenderChipID, pGLInfo->dwRenderChipRev)); #if W95_DDRAW DISPDBG((DBGLVL, " Support: 0x%x, Rev:0x%x", pGLInfo->dwSupportChipID, pGLInfo->dwSupportChipRev)); DISPDBG((DBGLVL, " Board: 0x%x, Rev:0x%x", pGLInfo->dwBoardID, pGLInfo->dwBoardRev)); // DISPDBG((DBGLVL, " BF Size: 0x%x, LB Depth:0x%x", pGLInfo->cBlockFillSize, pGLInfo->cLBDepth)); #endif // W95_DDRAW DISPDBG((DBGLVL, " FB Size: 0x%x", pGLInfo->ddFBSize)); DISPDBG((DBGLVL, " RMask: 0x%x", pThisDisplay->ddpfDisplay.dwRBitMask )); DISPDBG((DBGLVL, " GMask: 0x%x", pThisDisplay->ddpfDisplay.dwGBitMask )); DISPDBG((DBGLVL, " BMask: 0x%x", pThisDisplay->ddpfDisplay.dwBBitMask )); DISPDBG((DBGLVL, "******************************************************************" )); // Allocate a DMA buffer for the DX driver HWC_AllocDMABuffer(pThisDisplay); #define SURFCB pThisDisplay->DDSurfCallbacks #define HALCB pThisDisplay->DDHALCallbacks // Fill in the HAL Callback pointers memset(&HALCB, 0, sizeof(DDHAL_DDCALLBACKS)); HALCB.dwSize = sizeof(DDHAL_DDCALLBACKS); // Field the HAL DDraw callbacks we support HALCB.CanCreateSurface = DdCanCreateSurface; HALCB.CreateSurface = DdCreateSurface; HALCB.WaitForVerticalBlank = DdWaitForVerticalBlank; HALCB.GetScanLine = DdGetScanLine; #if WNT_DDRAW HALCB.MapMemory = DdMapMemory; #else HALCB.DestroyDriver = DdDestroyDriver; // Only on Win95. #endif // WNT_DDRAW HALCB.dwFlags = DDHAL_CB32_WAITFORVERTICALBLANK | #if WNT_DDRAW DDHAL_CB32_MAPMEMORY | #else // WNT_DDRAW DDHAL_CB32_DESTROYDRIVER | #endif DDHAL_CB32_GETSCANLINE | DDHAL_CB32_CANCREATESURFACE | DDHAL_CB32_CREATESURFACE; // Fill in the Surface Callback pointers memset(&SURFCB, 0, sizeof(DDHAL_DDSURFACECALLBACKS)); SURFCB.dwSize = sizeof(DDHAL_DDSURFACECALLBACKS); // Field the Ddraw Surface callbacks we support SURFCB.DestroySurface = DdDestroySurface; SURFCB.Lock = DdLock; SURFCB.Unlock = DdUnlock; SURFCB.GetBltStatus = DdGetBltStatus; SURFCB.GetFlipStatus = DdGetFlipStatus; SURFCB.SetColorKey = DdSetColorKey; SURFCB.Flip = DdFlip; SURFCB.Blt = DdBlt; SURFCB.dwFlags = DDHAL_SURFCB32_DESTROYSURFACE | DDHAL_SURFCB32_FLIP | DDHAL_SURFCB32_LOCK | DDHAL_SURFCB32_BLT | DDHAL_SURFCB32_GETBLTSTATUS | DDHAL_SURFCB32_GETFLIPSTATUS | DDHAL_SURFCB32_SETCOLORKEY | DDHAL_SURFCB32_UNLOCK; pThisDisplay->hInstance = g_DXGlobals.hInstance; #if WNT_DDRAW if (0 == (pThisDisplay->ppdev->flCaps & CAPS_DISABLE_OVERLAY)) #else if (0 == (pThisDisplay->pGLInfo->dwFlags & GMVF_DISABLE_OVERLAY)) #endif { SURFCB.UpdateOverlay = DdUpdateOverlay; // Now supporting overlays. SURFCB.SetOverlayPosition = DdSetOverlayPosition; SURFCB.dwFlags |= DDHAL_SURFCB32_UPDATEOVERLAY | // Now supporting DDHAL_SURFCB32_SETOVERLAYPOSITION ; // overlays. } // Fill in the DDHAL Informational caps __GetDDHALInfo(pThisDisplay, &pThisDisplay->ddhi32); // Create/get DD locals hash table to store our DX surface handles //@@BEGIN_DDKSPLIT // azn // We need to move this creation/destruction of g_pDirectDrawLocalsHashTable // into DrvEnableDriver and DrvDisableDriver and maybe maintain a Ref count // as we might be running on a multi-Perm3 machine. //@@END_DDKSPLIT if (g_pDirectDrawLocalsHashTable == NULL) { DISPDBG((DBGLVL,"pDirectDrawLocalsHashTable CREATED")); g_pDirectDrawLocalsHashTable = pThisDisplay->pDirectDrawLocalsHashTable = HT_CreateHashTable(); } else { DISPDBG((DBGLVL,"Hash table for DirectDraw locals already exists")); pThisDisplay->pDirectDrawLocalsHashTable = g_pDirectDrawLocalsHashTable; } if (pThisDisplay->pDirectDrawLocalsHashTable == NULL) { return (FALSE); } HT_SetDataDestroyCallback(pThisDisplay->pDirectDrawLocalsHashTable, _D3D_SU_DirectDrawLocalDestroyCallback); #if W95_DDRAW if ( g_DXGlobals.hHeap32 == 0 ) { return ( FALSE ); } else { return ( TRUE ); } #endif return (TRUE); } // _DD_InitDDHAL32Bit #if DX7_STEREO //----------------------------------------------------------------------------- // // _DD_bIsStereoMode // // Decide if mode can be displayed as stereo mode. Here we limit stereo // modes so that two front and two backbuffers can be created for rendering. // //----------------------------------------------------------------------------- BOOL _DD_bIsStereoMode( P3_THUNKEDDATA* pThisDisplay, DWORD dwWidth, DWORD dwHeight, DWORD dwBpp) { DWORD dwLines; // we need to check dwBpp for a valid value as PDD_STEREOMODE.dwBpp is a // parameter passed on from the user mode API call and which is expected // to have the values 8,16,24,32 (though we don't really support 24bpp) if ((dwWidth >= 320) && (dwHeight >= 240) && ((dwBpp == 8) || (dwBpp == 16) || (dwBpp == 24) || (dwBpp ==32) ) ) { // This the total number of "lines" that fit in our available vidmem // at the given width and pixel format dwLines = pThisDisplay->pGLInfo->ddFBSize / (dwWidth*dwBpp/8); // Here we limit stereo modes so that two front and two backbuffers // can be created for rendering. if (dwLines > (dwHeight*4)) { return TRUE; } } return FALSE; } #endif // DX7_STEREO #ifdef WNT_DDRAW typedef DD_NONLOCALVIDMEMCAPS DDNONLOCALVIDMEMCAPS; #else #define DD_MISCELLANEOUSCALLBACKS DDHAL_DDMISCELLANEOUSCALLBACKS #endif //-----------------------------Public Routine---------------------------------- // // DdGetDriverInfo // // Queries the driver for additional information about itself. // // Parameters // lpGetDriverInfo // Points to a DD_GETDRIVERINFODATA structure that contains the // information required to perform the query. // // Members // // VOID * // dphdev // Is a handle to the driver's PDEV. // DWORD // dwSize // Specifies the size in bytes of this // DD_GETDRIVERINFODATA structure. // DWORD // dwFlags // Is currently unused and is set to zero. // GUID // guidInfo // Specifies the GUID of the DirectX support for which the // driver is being queried. In a Windows 2000 DirectDraw // driver, this member can be one of the following values // (in alphabetic order): // // GUID_ColorControlCallbacks Queries whether the driver supports // DdControlColor. If the driver does // support it, the driver should // initialize and return a // DD_COLORCONTROLCALLBACKS structure // in the buffer to which lpvData // points. // GUID_D3DCallbacks Queries whether the driver supports // any of the functionality specified // through the D3DNTHAL_CALLBACKS // structure. If the driver does not // provide any of this support, it // should initialize and return a // D3DNTHAL_CALLBACKS structure in // the buffer to which lpvData points // GUID_D3DCallbacks2 Obsolete. // GUID_D3DCallbacks3 Queries whether the driver supports // any of the functionality specified // through the D3DNTHAL_CALLBACKS3 // structure. If the driver does provide // any of this support, it should // initialize and return a // D3DNTHAL_CALLBACKS3 structure in // the buffer to which lpvData points. // GUID_D3DCaps Obsolete. // GUID_D3DExtendedCaps Queries whether the driver supports // any of the Direct3D functionality // specified through the // D3DNTHAL_D3DEXTENDEDCAPS structure. // If the driver does provide any of // this support, it should initialize // and return a // D3DNTHAL_D3DEXTENDEDCAPS structure // in the buffer to which lpvData // points. // GUID_D3DParseUnknownCommandCallback Provides the Direct3D // portion of the driver with the // Direct3D runtime's // D3dParseUnknownCommandCallback. // The driver's D3dDrawPrimitives2 // callback calls // D3dParseUnknownCommandCallback // to parse commands from the // command buffer that the driver // doesn't understand. // DirectDraw passes a pointer to this // function in the buffer to which // lpvData points. If the driver // supports this aspect of Direct3D, // it should store the pointer. // GUID_GetHeapAlignment Queries whether the driver supports // surface alignment requirements on a // per-heap basis. If the driver does // provide this support, it should // initialize and return a // DD_GETHEAPALIGNMENTDATA structure // in the buffer to which lpvData // points. // GUID_KernelCallbacks Queries whether the driver supports // any of the functionality specified // through the DD_KERNELCALLBACKS // structure. If the driver does // provide any of this support, it // should initialize and return a // DD_KERNELCALLBACKS structure in the // buffer to which lpvData points. // GUID_KernelCaps Queries whether the driver supports // any of the kernel-mode capabilities // specified through the DDKERNELCAPS // structure. If the driver does // provide any of this support, it // should initialize and return a // DDKERNELCAPS structure in the buffer // to which lpvData points. // GUID_MiscellaneousCallbacks Queries whether the driver supports // DdGetAvailDriverMemory. If the // driver does support it, the driver // should initialize and return a // DD_MISCELLANEOUSCALLBACKS structure // in the buffer to which lpvData // points. // GUID_Miscellaneous2Callbacks Queries whether the driver // supports the additional miscellaneous // functionality specified in the // DD_MISCELLANEOUS2CALLBACKS structure. // If the driver does support any of // this support, the driver should // initialize and return a // DD_MISCELLANEOUS2CALLBACKS structure // in the buffer to which lpvData // points. // GUID_MotionCompCallbacks Queries whether the driver supports // the motion compensation // functionality specified through the // DD_MOTIONCOMPCALLBACKS structure. // If the driver does provide any of // this support, is should initialize // and return a DD_MOTIONCOMPCALLBACKS // structure in the buffer to which // lpvData points. // GUID_NonLocalVidMemCaps Queries whether the driver supports // any of the nonlocal display memory // capabilities specified through the // DD_NONLOCALVIDMEMCAPS structure. // If the driver does provide any of // this support, it should initialize // and return a DD_NONLOCALVIDMEMCAPS // structure in the buffer to which // lpvData points. // GUID_NTCallbacks Queries whether the driver supports // any of the functionality specified // through the DD_NTCALLBACKS structure. // If the driver does provide any of // this support, it should initialize // and return a DD_NTCALLBACKS // structure in the buffer to which // lpvData points. // GUID_NTPrivateDriverCaps Queries whether the driver supports // the Windows 95/ Windows 98-style // surface creation techniques // specified through the // DD_NTPRIVATEDRIVERCAPS structure. // If the driver does provide any of // this support, it should initialize // and return a DD_NTPRIVATEDRIVERCAPS // structure in the buffer to which // lpvData points. // GUID_UpdateNonLocalHeap Queries whether the driver supports // retrieval of the base addresses of // each nonlocal heap in turn. If the // driver does provide this support, // it should initialize and return a // DD_UPDATENONLOCALHEAPDATA structure // in the buffer to which lpvData // points. // GUID_VideoPortCallbacks Queries whether the driver supports // the video port extensions (VPE). If // the driver does support VPE, it // should initialize and return a // DD_VIDEOPORTCALLBACKS structure in // the buffer to which lpvData points. // GUID_VideoPortCaps Queries whether the driver supports // any of the VPE object capabilities // specified through the DDVIDEOPORTCAPS // structure. If the driver does provide // any of this support, it should // initialize and return a // DDVIDEOPORTCAPS structure in the // buffer to which lpvData points. // GUID_ZPixelFormats Queries the pixel formats supported // by the depth buffer. If the driver // supports Direct3D, it should allocate // and initialize the appropriate // members of a DDPIXELFORMAT structure // for every z-buffer format that it // supports and return these in the // buffer to which lpvData points. // // DWORD // dwExpectedSize // Specifies the number of bytes of data that DirectDraw // expects the driver to pass back in the buffer to which // lpvData points. // PVOID // lpvData // Points to a DirectDraw-allocated buffer into which the // driver copies the requested data. This buffer is // typically dwExpectedSize bytes in size. The driver must // not write more than dwExpectedSize bytes of data in it. // DWORD // dwActualSize // Is the location in which the driver returns the number // of bytes of data it writes in lpvData. // HRESULT // ddRVal // Specifies the driver's return value. // // Return Value // DdGetDriverInfo must return DDHAL_DRIVER_HANDLED. // // Comments // // Drivers must implement DdGetDriverInfo to expose driver-supported // DirectDraw functionality that is not returnable through // DrvEnableDirectDraw. // // The driver's DrvGetDirectDrawInfo function returns a pointer to // DdGetDriverInfo in the GetDriverInfo member of the DD_HALINFO structure. // // To inform DirectDraw that the DdGetDriverInfo member has been set // correctly, the driver must also set the DDHALINFO_GETDRIVERINFOSET bit // of dwFlags in the DD_HALINFO structure. // // DdGetDriverInfo should determine whether the driver and its hardware // support the callbacks or capabilities requested by the specified GUID. // For all GUIDs except GUID_D3DParseUnknownCommandCallback, if the driver // does provide the requested support, it should set the following members // of the DD_GETDRIVERINFODATA structure: // // Set dwActualSize to be the size in bytes of the callback or capability // structure being returned by the driver. // // In the memory that lpvData points to, initialize the members of the // callback or capability structure that corresponds with the requested // feature as follows: // // Set the dwSize member to be the size in bytes of the structure. // // For callbacks, set the function pointers to point to those callbacks // implemented by the driver, and set the bits in the dwFlags member to // indicate which functions the driver supports. // // For capabilities, set the appropriate members of the capability // structure with values supported by the driver/device. // // Return DD_OK in ddRVal. // If the driver does not support the feature, it should set ddRVal // to DDERR_CURRENTLYNOTAVAIL and return. // // DirectDraw informs the driver of the expected amount of data in the // dwExpectedSize member of the DD_GETDRIVERINFODATA structure. The // driver must not fill in more data than dwExpectedSize bytes. // // To avoid problems using DdGetDriverInfo: // // Do not implement dependencies based on the order in which DdGetDriverInfo // is called. For example, avoid hooking driver initialization steps into // DdGetDriverInfo. // // Do not try to ascertain the DirectDraw version based on the calls to // DdGetDriverInfo. // // Do not assume anything about the number of times DirectDraw will call the // driver, or the number of times DirectDraw will query a given GUID. It is // possible that DirectDraw will probe the driver repeatedly with the same // GUID. Implementing assumptions about this in the driver hampers its // compatibility with future runtimes. // //----------------------------------------------------------------------------- DWORD CALLBACK DdGetDriverInfo( LPDDHAL_GETDRIVERINFODATA lpData) { DWORD dwSize; P3_THUNKEDDATA* pThisDisplay; #if WNT_DDRAW pThisDisplay = (P3_THUNKEDDATA*)(((PPDEV)(lpData->dhpdev))->thunkData); #else pThisDisplay = (P3_THUNKEDDATA*)lpData->dwContext; if (! pThisDisplay) { pThisDisplay = g_pDriverData; } #endif DBG_CB_ENTRY(DdGetDriverInfo); // Default to 'not supported' lpData->ddRVal = DDERR_CURRENTLYNOTAVAIL; //------------------------------------ // Process any D3D related GUIDs here //------------------------------------ _D3DGetDriverInfo(lpData); //------------------------------------ // any other GUIDS are handled here //------------------------------------ if (MATCH_GUID((lpData->guidInfo), GUID_MiscellaneousCallbacks) ) { DD_MISCELLANEOUSCALLBACKS MISC_CB; DISPDBG((DBGLVL," GUID_MiscellaneousCallbacks")); memset(&MISC_CB, 0, sizeof(DD_MISCELLANEOUSCALLBACKS)); MISC_CB.dwSize = sizeof(DD_MISCELLANEOUSCALLBACKS); #if W95_DDRAW MISC_CB.GetHeapAlignment = DdGetHeapAlignment; MISC_CB.dwFlags = DDHAL_MISCCB32_GETHEAPALIGNMENT; // Setup the AGP callback if running on an AGP board. if ((pThisDisplay->dwDXVersion > DX5_RUNTIME) && pThisDisplay->bCanAGP) { MISC_CB.dwFlags |= DDHAL_MISCCB32_UPDATENONLOCALHEAP; MISC_CB.UpdateNonLocalHeap = DdUpdateNonLocalHeap; } #endif // W95_DDRAW MISC_CB.dwFlags |= DDHAL_MISCCB32_GETAVAILDRIVERMEMORY; MISC_CB.GetAvailDriverMemory = DdGetAvailDriverMemory; // Copy the filled in structure into the passed data area dwSize = min(lpData->dwExpectedSize , sizeof(MISC_CB)); lpData->dwActualSize = sizeof(MISC_CB); memcpy(lpData->lpvData, &MISC_CB, dwSize ); lpData->ddRVal = DD_OK; } #if WNT_DDRAW if (MATCH_GUID((lpData->guidInfo), GUID_UpdateNonLocalHeap)) { // On NT kernels the AGP heap details are passed into the driver // here, rather than through a seperate callback. if (pThisDisplay->bCanAGP) { DDHAL_UPDATENONLOCALHEAPDATA* plhd; DISPDBG((DBGLVL, " GUID_UpdateNonLocalHeap")); plhd = (DDHAL_UPDATENONLOCALHEAPDATA*)lpData->lpvData; // Fill in the base pointers pThisDisplay->dwGARTDevBase = (DWORD)plhd->fpGARTDev; pThisDisplay->dwGARTLinBase = (DWORD)plhd->fpGARTLin; // Fill in the changeable base pointers. pThisDisplay->dwGARTDev = pThisDisplay->dwGARTDevBase; pThisDisplay->dwGARTLin = pThisDisplay->dwGARTLinBase; lpData->ddRVal = DD_OK; } } #endif // WNT_DDRAW if (MATCH_GUID((lpData->guidInfo), GUID_NonLocalVidMemCaps) && (pThisDisplay->bCanAGP)) { int i; DDNONLOCALVIDMEMCAPS NLVCAPS; DISPDBG((DBGLVL," GUID_NonLocalVidMemCaps")); if (lpData->dwExpectedSize != sizeof(DDNONLOCALVIDMEMCAPS) ) { DISPDBG((ERRLVL,"ERROR: NON-Local vidmem caps size incorrect!")); DBG_CB_EXIT(DdGetDriverInfo, lpData->ddRVal ); return DDHAL_DRIVER_HANDLED; } // The flag D3DDEVCAPS_TEXTURENONLOCALVIDMEM in the D3D caps // indicates that although we are exposing DMA-Model AGP, we // can still texture directly from AGP memory. memset(&NLVCAPS, 0, sizeof(DDNONLOCALVIDMEMCAPS)); NLVCAPS.dwSize = sizeof(DDNONLOCALVIDMEMCAPS); NLVCAPS.dwNLVBCaps = DDCAPS_BLT | DDCAPS_ALPHA | DDCAPS_BLTSTRETCH | DDCAPS_BLTQUEUE | DDCAPS_BLTFOURCC | DDCAPS_COLORKEY | DDCAPS_CANBLTSYSMEM; NLVCAPS.dwNLVBCaps2 = DDCAPS2_WIDESURFACES; NLVCAPS.dwNLVBCKeyCaps = DDCKEYCAPS_SRCBLT | DDCKEYCAPS_SRCBLTCLRSPACE | DDCKEYCAPS_DESTBLT | DDCKEYCAPS_DESTBLTCLRSPACE; NLVCAPS.dwNLVBFXCaps = DDFXCAPS_BLTSTRETCHY | DDFXCAPS_BLTSTRETCHX | DDFXCAPS_BLTSTRETCHYN | DDFXCAPS_BLTSTRETCHXN | DDFXCAPS_BLTSHRINKY | DDFXCAPS_BLTSHRINKX | DDFXCAPS_BLTSHRINKYN | DDFXCAPS_BLTSHRINKXN; for( i=0;idwExpectedSize, sizeof(DDNONLOCALVIDMEMCAPS)); lpData->dwActualSize = sizeof(DDNONLOCALVIDMEMCAPS); memcpy(lpData->lpvData, &NLVCAPS, dwSize ); lpData->ddRVal = DD_OK; } //@@BEGIN_DDKSPLIT #ifdef SUPPORT_VIDEOPORT #if W95_DDRAW // Fill in the VideoPort callbacks if (MATCH_GUID((lpData->guidInfo), GUID_VideoPortCallbacks) ) { DDHAL_DDVIDEOPORTCALLBACKS VIDCB; DISPDBG((DBGLVL," GUID_VideoPortCallbacks")); memset(&VIDCB, 0, sizeof(DDHAL_DDVIDEOPORTCALLBACKS)); VIDCB.dwSize = sizeof(DDHAL_DDVIDEOPORTCALLBACKS); VIDCB.CanCreateVideoPort = DdCanCreateVideoPort; VIDCB.CreateVideoPort = DdCreateVideoPort; VIDCB.FlipVideoPort = DdFlipVideoPort; VIDCB.GetVideoPortBandwidth = DdGetVideoPortBandwidth; VIDCB.GetVideoPortInputFormats = DdGetVideoPortInputFormats; VIDCB.GetVideoPortOutputFormats = DdGetVideoPortOutputFormats; VIDCB.GetVideoPortField = DdGetVideoPortField; VIDCB.GetVideoPortLine = DdGetVideoPortLine; VIDCB.GetVideoPortConnectInfo = DDGetVideoPortConnectInfo; VIDCB.DestroyVideoPort = DdDestroyVideoPort; VIDCB.GetVideoPortFlipStatus = DdGetVideoPortFlipStatus; VIDCB.UpdateVideoPort = DdUpdateVideoPort; VIDCB.WaitForVideoPortSync = DdWaitForVideoPortSync; VIDCB.GetVideoSignalStatus = DdGetVideoSignalStatus; VIDCB.dwFlags = DDHAL_VPORT32_CANCREATEVIDEOPORT | DDHAL_VPORT32_CREATEVIDEOPORT | DDHAL_VPORT32_DESTROY | DDHAL_VPORT32_FLIP | DDHAL_VPORT32_GETBANDWIDTH | DDHAL_VPORT32_GETINPUTFORMATS | DDHAL_VPORT32_GETOUTPUTFORMATS | DDHAL_VPORT32_GETFIELD | DDHAL_VPORT32_GETLINE | DDHAL_VPORT32_GETFLIPSTATUS | DDHAL_VPORT32_UPDATE | DDHAL_VPORT32_WAITFORSYNC | DDHAL_VPORT32_GETCONNECT | DDHAL_VPORT32_GETSIGNALSTATUS; // Copy the filled in structure into the // passed data area dwSize = lpData->dwExpectedSize; if ( sizeof(VIDCB) < dwSize ) { dwSize = sizeof(VIDCB); } lpData->dwActualSize = sizeof(VIDCB); memcpy(lpData->lpvData, &VIDCB, dwSize ); lpData->ddRVal = DD_OK; } // Fill in the VideoPortCaps if (MATCH_GUID((lpData->guidInfo), GUID_VideoPortCaps) ) { DDVIDEOPORTCAPS VIDCAPS; DISPDBG((DBGLVL," GUID_VideoPortCaps")); if (lpData->dwExpectedSize != sizeof(VIDCAPS) ) { DISPDBG((ERRLVL,"ERROR: VIDCAPS size incorrect")); DBG_CB_EXIT(DdGetDriverInfo, lpData->ddRVal ); return DDHAL_DRIVER_HANDLED; } // Now fill in the videoport description (it's easier if it's on // the 32 bit side..) VIDCAPS.dwSize = sizeof(DDVIDEOPORTCAPS); VIDCAPS.dwFlags = DDVPD_ALIGN | DDVPD_AUTOFLIP | DDVPD_WIDTH | DDVPD_HEIGHT | DDVPD_FX | DDVPD_CAPS; VIDCAPS.dwMaxWidth = 2048; VIDCAPS.dwMaxVBIWidth = 2048; VIDCAPS.dwMaxHeight = 2048; VIDCAPS.dwVideoPortID = 0; VIDCAPS.dwCaps = DDVPCAPS_AUTOFLIP | DDVPCAPS_NONINTERLACED | DDVPCAPS_INTERLACED | DDVPCAPS_READBACKFIELD | DDVPCAPS_READBACKLINE | DDVPCAPS_SKIPEVENFIELDS | DDVPCAPS_SKIPODDFIELDS | DDVPCAPS_VBISURFACE | DDVPCAPS_OVERSAMPLEDVBI; VIDCAPS.dwFX = DDVPFX_CROPX | DDVPFX_CROPY | DDVPFX_INTERLEAVE | DDVPFX_MIRRORLEFTRIGHT | DDVPFX_MIRRORUPDOWN | DDVPFX_PRESHRINKXB | DDVPFX_VBICONVERT | DDVPFX_VBINOSCALE | DDVPFX_PRESHRINKYB | DDVPFX_IGNOREVBIXCROP; VIDCAPS.dwNumAutoFlipSurfaces = 2; VIDCAPS.dwAlignVideoPortBoundary = 4; VIDCAPS.dwAlignVideoPortPrescaleWidth = 4; VIDCAPS.dwAlignVideoPortCropBoundary = 4; VIDCAPS.dwAlignVideoPortCropWidth = 4; VIDCAPS.dwPreshrinkXStep = 1; VIDCAPS.dwPreshrinkYStep = 1; lpData->dwActualSize = sizeof(VIDCAPS); memcpy(lpData->lpvData, &VIDCAPS, sizeof(VIDCAPS) ); lpData->ddRVal = DD_OK; } // Fill in the kernel Callbacks if (MATCH_GUID((lpData->guidInfo), GUID_KernelCallbacks) ) { DDHAL_DDKERNELCALLBACKS KERNCB; DISPDBG((DBGLVL," GUID_KernelCallbacks")); memset(&KERNCB, 0, sizeof(DDHAL_DDKERNELCALLBACKS)); KERNCB.dwSize = sizeof(KERNCB); KERNCB.SyncSurfaceData = DdSyncSurfaceData; KERNCB.SyncVideoPortData = DdSyncVideoPortData; KERNCB.dwFlags = DDHAL_KERNEL_SYNCSURFACEDATA | DDHAL_KERNEL_SYNCVIDEOPORTDATA; dwSize = lpData->dwExpectedSize; if ( sizeof(KERNCB) < dwSize ) { dwSize = sizeof(KERNCB); } lpData->dwActualSize = sizeof(KERNCB); memcpy(lpData->lpvData, &KERNCB, dwSize ); lpData->ddRVal = DD_OK; } // Fill in the kernel caps if (MATCH_GUID((lpData->guidInfo), GUID_KernelCaps) ) { DDKERNELCAPS KERNCAPS; DISPDBG((DBGLVL," GUID_KernelCaps")); if (lpData->dwExpectedSize != sizeof(DDKERNELCAPS) ) { DISPDBG((ERRLVL,"ERROR: Kernel caps structure invalid size!")); return DDHAL_DRIVER_HANDLED; } ZeroMemory(&KERNCAPS, sizeof(KERNCAPS)); KERNCAPS.dwSize = sizeof(KERNCAPS); KERNCAPS.dwCaps = DDKERNELCAPS_LOCK | DDKERNELCAPS_FLIPOVERLAY | DDKERNELCAPS_SETSTATE; if (!(pThisDisplay->pGLInfo->dwFlags & GMVF_NOIRQ)) { KERNCAPS.dwCaps |= DDKERNELCAPS_CAPTURE_SYSMEM | DDKERNELCAPS_FIELDPOLARITY | DDKERNELCAPS_SKIPFIELDS | DDKERNELCAPS_FLIPVIDEOPORT | DDKERNELCAPS_AUTOFLIP; KERNCAPS.dwIRQCaps = DDIRQ_VPORT0_VSYNC | DDIRQ_DISPLAY_VSYNC | DDIRQ_BUSMASTER; } lpData->dwActualSize = sizeof(DDKERNELCAPS); memcpy(lpData->lpvData, &KERNCAPS, sizeof(DDKERNELCAPS) ); lpData->ddRVal = DD_OK; } #endif // W95_DDRAW #endif // SUPPORT_VIDEOPORT //@@END_DDKSPLIT #ifdef W95_DDRAW #ifdef USE_DD_CONTROL_COLOR // Fill in the colour control callbacks. if (MATCH_GUID((lpData->guidInfo), GUID_ColorControlCallbacks) ) { DDHAL_DDCOLORCONTROLCALLBACKS ColConCB; DISPDBG((DBGLVL," GUID_ColorControlCallbacks")); memset(&ColConCB, 0, sizeof(ColConCB)); ColConCB.dwSize = sizeof(ColConCB); ColConCB.dwFlags = DDHAL_COLOR_COLORCONTROL; ColConCB.ColorControl = DdControlColor; dwSize = min( lpData->dwExpectedSize, sizeof(ColConCB)); lpData->dwActualSize = sizeof(ColConCB); memcpy(lpData->lpvData, &ColConCB, dwSize); lpData->ddRVal = DD_OK; } #endif #endif #if !defined(_WIN64) && WNT_DDRAW // Fill in the NT specific callbacks if (MATCH_GUID((lpData->guidInfo), GUID_NTCallbacks) ) { DD_NTCALLBACKS NtCallbacks; memset(&NtCallbacks, 0, sizeof(NtCallbacks)); dwSize = min(lpData->dwExpectedSize, sizeof(DD_NTCALLBACKS)); NtCallbacks.dwSize = dwSize; NtCallbacks.dwFlags = DDHAL_NTCB32_FREEDRIVERMEMORY | DDHAL_NTCB32_SETEXCLUSIVEMODE | DDHAL_NTCB32_FLIPTOGDISURFACE; NtCallbacks.FreeDriverMemory = DdFreeDriverMemory; NtCallbacks.SetExclusiveMode = DdSetExclusiveMode; NtCallbacks.FlipToGDISurface = DdFlipToGDISurface; memcpy(lpData->lpvData, &NtCallbacks, dwSize); lpData->ddRVal = DD_OK; } #endif #if DX7_STEREO if (MATCH_GUID((lpData->guidInfo), GUID_DDMoreSurfaceCaps) ) { #if WNT_DDRAW DD_MORESURFACECAPS DDMoreSurfaceCaps; #else DDMORESURFACECAPS DDMoreSurfaceCaps; #endif DDSCAPSEX ddsCapsEx, ddsCapsExAlt; ULONG ulCopyPointer; DISPDBG((DBGLVL," GUID_DDMoreSurfaceCaps")); // fill in everything until expectedsize... memset(&DDMoreSurfaceCaps, 0, sizeof(DDMoreSurfaceCaps)); // Caps for heaps 2..n memset(&ddsCapsEx, 0, sizeof(ddsCapsEx)); memset(&ddsCapsExAlt, 0, sizeof(ddsCapsEx)); DDMoreSurfaceCaps.dwSize=lpData->dwExpectedSize; if (_DD_bIsStereoMode(pThisDisplay, pThisDisplay->dwScreenWidth, pThisDisplay->dwScreenHeight, pThisDisplay->ddpfDisplay.dwRGBBitCount)) { DDMoreSurfaceCaps.ddsCapsMore.dwCaps2 = DDSCAPS2_STEREOSURFACELEFT; } lpData->dwActualSize = lpData->dwExpectedSize; dwSize = min(sizeof(DDMoreSurfaceCaps),lpData->dwExpectedSize); memcpy(lpData->lpvData, &DDMoreSurfaceCaps, dwSize); // Now fill in ddsCapsEx and ddsCapsExAlt heaps // Hardware with different restrictions for different heaps // should prepare ddsCapsEx and ddsCapsExAlt carefully and // fill them into lpvData in proper order while (dwSize < lpData->dwExpectedSize) { memcpy( (PBYTE)lpData->lpvData+dwSize, &ddsCapsEx, sizeof(DDSCAPSEX)); dwSize += sizeof(DDSCAPSEX); memcpy( (PBYTE)lpData->lpvData+dwSize, &ddsCapsExAlt, sizeof(DDSCAPSEX)); dwSize += sizeof(DDSCAPSEX); } lpData->ddRVal = DD_OK; } #endif // DX7_STEREO // We always handled it. DBG_CB_EXIT(DdGetDriverInfo, lpData->ddRVal ); return DDHAL_DRIVER_HANDLED; } // DdGetDriverInfo