/******************************Module*Header**********************************\ * * ************************** * * DirectDraw SAMPLE CODE * * ************************** * * Module Name: dd.c * * Content: * * Copyright (c) 1994-1998 3Dlabs Inc. Ltd. All rights reserved. * Copyright (c) 1995-1999 Microsoft Corporation. All rights reserved. \*****************************************************************************/ #define INITGUID #include "precomp.h" #include #include "directx.h" #include "dd.h" #include "d3dhw.h" #include "d3dtext.h" #include "heap.h" //----------------------------------------------------------------------------- // // use bits to indicate which ROPs you support. // // DWORD 0, bit 0 == ROP 0 // DWORD 8, bit 31 == ROP 255 // //----------------------------------------------------------------------------- static BYTE ropList[] = { SRCCOPY >> 16, }; static DWORD rops[DD_ROP_SPACE] = { 0 }; // The FourCC's we support static DWORD fourCC[] = { FOURCC_YUV422 }; //----------------------------------------------------------------------------- // // setupRops // // build array for supported ROPS // //----------------------------------------------------------------------------- VOID setupRops( LPBYTE proplist, LPDWORD proptable, int cnt ) { INT i; DWORD idx; DWORD bit; DWORD rop; for(i=0; icyMemory << 16) | (ppdev->cxMemory)); SEND_PERMEDIA_DATA(ScreenSize, (ppdev->cyMemory << 16) | (ppdev->cxMemory)); SEND_PERMEDIA_DATA(WindowOrigin, 0x0); // DirectDraw might not need to set these up SEND_PERMEDIA_DATA(dXDom, 0x0); SEND_PERMEDIA_DATA(dXSub, 0x0); // set max size, no filtering SEND_PERMEDIA_DATA(TextureReadMode, PM_TEXREADMODE_ENABLE(__PERMEDIA_ENABLE) | PM_TEXREADMODE_FILTER(__PERMEDIA_DISABLE) | PM_TEXREADMODE_WIDTH(11) | PM_TEXREADMODE_HEIGHT(11) ); // 16 bit Z, no other buffers SEND_PERMEDIA_DATA(LBWriteFormat, __PERMEDIA_DEPTH_WIDTH_16); // Ensure an extra LBData message doesn't flow through the core. SEND_PERMEDIA_DATA(Window, PM_WINDOW_DISABLELBUPDATE(__PERMEDIA_ENABLE)); SEND_PERMEDIA_DATA(FBReadPixel, ppdev->bPixShift); COMMITDMAPTR(); FLUSHDMA(); } // P2DisableAllUnits //----------------------------------------------------------------------------- // // GetDDHALInfo // // Takes a pointer to a partially or fully filled in ppdev and a pointer // to an empty DDHALINFO and fills in the DDHALINFO. // //----------------------------------------------------------------------------- VOID GetDDHALInfo(PPDev ppdev, DDHALINFO* pHALInfo) { DWORD dwResult; BOOL bRet; DBG_DD(( 5, "DDraw:GetDDHalInfo")); // Setup the HAL driver caps. memset( pHALInfo, 0, sizeof(DDHALINFO)); pHALInfo->dwSize = sizeof(DDHALINFO); // Setup the ROPS we do. setupRops( ropList, rops, sizeof(ropList)/sizeof(ropList[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; // add caps for D3D pHALInfo->ddCaps.dwCaps |= DDCAPS_3D | DDCAPS_ALPHA | DDCAPS_BLTDEPTHFILL; // add surface caps for D3D pHALInfo->ddCaps.ddsCaps.dwCaps |= DDSCAPS_ALPHA | DDSCAPS_3DDEVICE | DDSCAPS_ZBUFFER; // Permedia can do // 1. Stretching/Shrinking // 2. YUV->RGB conversion (only non paletted mode) // 3. Mirroring in X and Y // add Permedia caps to global caps pHALInfo->ddCaps.dwCaps |= DDCAPS_BLTSTRETCH | DDCAPS_COLORKEY | DDCAPS_CANBLTSYSMEM; #if DX7_STEREO // check if mode supports stereo DD_STEREOMODE DDStereoMode; DDStereoMode.dwHeight = ppdev->cyScreen; DDStereoMode.dwWidth = ppdev->cxScreen; DDStereoMode.dwBpp = ppdev->cBitsPerPel; DDStereoMode.dwRefreshRate= 0; ppdev->bCanDoStereo=bIsStereoMode(ppdev,&DDStereoMode); // Stereo caps are set if the driver can do stereo in any mode: pHALInfo->ddCaps.dwCaps2 |= DDCAPS2_STEREO; pHALInfo->ddCaps.dwSVCaps = DDSVCAPS_STEREOSEQUENTIAL; #endif pHALInfo->ddCaps.dwCaps2 |= DDCAPS2_CANMANAGETEXTURE; //declare we can handle textures wider than the primary pHALInfo->ddCaps.dwCaps2 |= DDCAPS2_WIDESURFACES; // Special effects caps pHALInfo->ddCaps.dwFXCaps = DDFXCAPS_BLTSTRETCHY | DDFXCAPS_BLTSTRETCHX | DDFXCAPS_BLTSTRETCHYN | DDFXCAPS_BLTSTRETCHXN | DDFXCAPS_BLTSHRINKY | DDFXCAPS_BLTSHRINKX | DDFXCAPS_BLTSHRINKYN | DDFXCAPS_BLTSHRINKXN | DDFXCAPS_BLTMIRRORUPDOWN | DDFXCAPS_BLTMIRRORLEFTRIGHT; // add AlphaBlt and Filter caps pHALInfo->ddCaps.dwFXCaps |= DDFXCAPS_BLTALPHA | DDFXCAPS_BLTFILTER; // colorkey caps, only src color key supported pHALInfo->ddCaps.dwCKeyCaps = DDCKEYCAPS_SRCBLT | DDCKEYCAPS_SRCBLTCLRSPACE; // We can do a texture from sysmem to video mem blt. pHALInfo->ddCaps.dwSVBCaps = DDCAPS_BLT; pHALInfo->ddCaps.dwSVBCKeyCaps = 0; pHALInfo->ddCaps.dwSVBFXCaps = 0; // Fill in the sysmem->vidmem rops (only can copy); for(int i=0;iddCaps.dwSVBRops[i] = rops[i]; } if (ppdev->iBitmapFormat != BMF_8BPP) { pHALInfo->ddCaps.dwCaps |= DDCAPS_BLTFOURCC; pHALInfo->ddCaps.dwCKeyCaps |= DDCKEYCAPS_SRCBLTCLRSPACEYUV; } pHALInfo->ddCaps.ddsCaps.dwCaps |= DDSCAPS_TEXTURE; // Z Buffer is only 16 Bits on Permedia pHALInfo->ddCaps.dwZBufferBitDepths = DDBD_16; #if D3D_MIPMAPPING // Mip Mapping pHALInfo->ddCaps.ddsCaps.dwCaps |= DDSCAPS_MIPMAP; #endif if (DD_P2AGPCAPABLE(ppdev)) { DBG_DD((1, "GetDDHALInfo: P2 AGP board - supports NONLOCALVIDMEM")); pHALInfo->ddCaps.dwCaps2 |= DDCAPS2_NONLOCALVIDMEM | DDCAPS2_NONLOCALVIDMEMCAPS; pHALInfo->ddCaps.ddsCaps.dwCaps |= DDSCAPS_LOCALVIDMEM | DDSCAPS_NONLOCALVIDMEM; } else { DBG_DD((1,"GetDDHALInfo: P2 Board is NOT AGP")); } // 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; pHALInfo->ddCaps.dwAlphaOverlayConstBitDepths = DDBD_2 | DDBD_4 | DDBD_8; pHALInfo->ddCaps.dwAlphaOverlayPixelBitDepths = DDBD_1 | DDBD_8; pHALInfo->ddCaps.dwAlphaOverlaySurfaceBitDepths = DDBD_1 | DDBD_2 | DDBD_4 | DDBD_8; // ROPS supported for( i=0;iddCaps.dwRops[i] = rops[i]; } // For DX5 and beyond we support this new informational callback. pHALInfo->GetDriverInfo = DdGetDriverInfo; pHALInfo->dwFlags |= DDHALINFO_GETDRIVERINFOSET; // now setup D3D callbacks D3DHALCreateDriver( ppdev, (LPD3DHAL_GLOBALDRIVERDATA*) &pHALInfo->lpD3DGlobalDriverData, (LPD3DHAL_CALLBACKS*) &pHALInfo->lpD3DHALCallbacks, (LPDDHAL_D3DBUFCALLBACKS*) &pHALInfo->lpD3DBufCallbacks); if(pHALInfo->lpD3DGlobalDriverData == NULL) { // no D3D available - kill caps we set before pHALInfo->ddCaps.dwCaps &= ~(DDCAPS_3D | DDCAPS_BLTDEPTHFILL); pHALInfo->ddCaps.ddsCaps.dwCaps &= ~(DDSCAPS_3DDEVICE | DDSCAPS_ZBUFFER); } } // GetHALInfo //----------------------------------------------------------------------------- // // Global DirectDraw Callbacks // //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // // DdFlip // // This callback is invoked whenever we are about to flip to from // one surface to another. lpFlipData->lpSurfCurr is the surface we were at, // lpFlipData->lpSurfTarg is the one we are flipping to. // // You should point the hardware registers at the new surface, and // also keep track of the surface that was flipped away from, so // that if the user tries to lock it, you can be sure that it is done // being displayed // //----------------------------------------------------------------------------- DWORD CALLBACK DdFlip( LPDDHAL_FLIPDATA lpFlipData) { PPDev ppdev=(PPDev)lpFlipData->lpDD->dhpdev; PERMEDIA_DEFS(ppdev); DWORD dwDDSurfaceOffset; HRESULT ddrval; DBG_DD(( 3, "DDraw:Flip")); // Switch to DirectDraw context DDCONTEXT; // is the previous Flip already done? // check if the current surface is already displayed ddrval = updateFlipStatus(ppdev); if( FAILED(ddrval) ) { lpFlipData->ddRVal = ddrval; return DDHAL_DRIVER_HANDLED; } // everything is OK, do the flip. // get offset for Permedia ScreenBase register dwDDSurfaceOffset=(DWORD)lpFlipData->lpSurfTarg->lpGbl->fpVidMem; #if DX7_STEREO if (lpFlipData->dwFlags & DDFLIP_STEREO) // will be stereo { DBG_DD((4,"DDraw:Flip:Stereo")); DBG_DD((5,"ScreenBase: %08lx", dwDDSurfaceOffset)); if (lpFlipData->lpSurfTargLeft!=NULL) { DWORD dwDDLeftSurfaceOffset; dwDDLeftSurfaceOffset=(DWORD) lpFlipData->lpSurfTargLeft->lpGbl->fpVidMem; LD_PERMEDIA_REG(PREG_SCREENBASERIGHT,dwDDLeftSurfaceOffset>>3); DBG_DD((5,"ScreenBaseLeft: %08lx", dwDDLeftSurfaceOffset)); } ULONG ulVControl=READ_PERMEDIA_REG(PREG_VIDEOCONTROL); if ((ulVControl&PREG_VC_STEREOENABLE)==0 || !ppdev->bDdStereoMode) { ppdev->bDdStereoMode=TRUE; LD_PERMEDIA_REG(PREG_VIDEOCONTROL, ulVControl | PREG_VC_STEREOENABLE); } } else #endif // DX7_STEREO { // append flip command to Permedia render pipeline // that makes sure that all buffers are flushed before // the flip occurs #if DX7_STEREO if (ppdev->bDdStereoMode) { ppdev->bDdStereoMode=FALSE; LD_PERMEDIA_REG(PREG_VIDEOCONTROL, READ_PERMEDIA_REG(PREG_VIDEOCONTROL)& ~PREG_VC_STEREOENABLE); } #endif } // adjust base address according to register spec. dwDDSurfaceOffset>>=3; // add new base address to render pipeline RESERVEDMAPTR(1); LD_INPUT_FIFO(__Permedia2TagSuspendUntilFrameBlank, dwDDSurfaceOffset); COMMITDMAPTR(); FLUSHDMA(); // remember new Surface Offset for GetFlipStatus ppdev->dwNewDDSurfaceOffset=dwDDSurfaceOffset; lpFlipData->ddRVal = DD_OK; return DDHAL_DRIVER_HANDLED; } // DdFlip //----------------------------------------------------------------------------- // // DdWaitForVerticalBlank // // This callback is invoked to get information about the vertical blank // status of the display or to wait until the display is at the begin or // the end of the vertical blank // //----------------------------------------------------------------------------- DWORD CALLBACK DdWaitForVerticalBlank(LPDDHAL_WAITFORVERTICALBLANKDATA lpWaitForVerticalBlank) { static int bInVBlank = FALSE; PPDev ppdev=(PPDev)lpWaitForVerticalBlank->lpDD->dhpdev; DBG_DD(( 2, "DDraw:WaitForVerticalBlank")); switch(lpWaitForVerticalBlank->dwFlags) { case DDWAITVB_I_TESTVB: // If the monitor is off, we don't always want to report // the same status or else an app polling this status // might hang if( !(READ_PERMEDIA_REG(PREG_VIDEOCONTROL) & PREG_VC_VIDEO_ENABLE)) { lpWaitForVerticalBlank->bIsInVB = bInVBlank; bInVBlank = !bInVBlank; } else { // Just a request for current VBLANK status. lpWaitForVerticalBlank->bIsInVB = IN_VRETRACE(ppdev); } lpWaitForVerticalBlank->ddRVal = DD_OK; return DDHAL_DRIVER_HANDLED; case DDWAITVB_BLOCKBEGIN: // we don't care to wait if the monitor is off if( READ_PERMEDIA_REG(PREG_VIDEOCONTROL) & PREG_VC_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_VRETRACE(ppdev)); while(IN_DISPLAY(ppdev)); } lpWaitForVerticalBlank->ddRVal = DD_OK; return DDHAL_DRIVER_HANDLED; case DDWAITVB_BLOCKEND: // we don't care to wait if the monitor is off if( READ_PERMEDIA_REG(PREG_VIDEOCONTROL) & PREG_VC_VIDEO_ENABLE) { // if blockend is requested we wait for the vblank interval to end. if( IN_VRETRACE(ppdev) ) { while( IN_VRETRACE(ppdev) ); } else { while(IN_DISPLAY(ppdev)); while(IN_VRETRACE(ppdev)); } } lpWaitForVerticalBlank->ddRVal = DD_OK; return DDHAL_DRIVER_HANDLED; } return DDHAL_DRIVER_NOTHANDLED; } // WaitForVerticalBlank //----------------------------------------------------------------------------- // // Lock // // 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. // //----------------------------------------------------------------------------- DWORD CALLBACK DdLock( LPDDHAL_LOCKDATA lpLockData ) { PPDev ppdev=(PPDev)lpLockData->lpDD->dhpdev; PERMEDIA_DEFS(ppdev); HRESULT ddrval; DWORD pSurf; DBG_DD(( 2, "DDraw:Lock")); // // Switch to DirectDraw context // DDCONTEXT; // check to see if any pending physical flip has occurred ddrval = updateFlipStatus(ppdev); if( FAILED(ddrval) ) { lpLockData->ddRVal = DDERR_WASSTILLDRAWING; return DDHAL_DRIVER_HANDLED; } // // don't allow a lock if a blt is in progress // if(DRAW_ENGINE_BUSY) { DBG_DD((2,"DDraw:Lock, DrawEngineBusy")); FLUSHDMA(); lpLockData->ddRVal = DDERR_WASSTILLDRAWING; return DDHAL_DRIVER_HANDLED; } // send a flush and wait for outstanding operations // before allowing surfaces to be locked. SYNC_WITH_PERMEDIA; // now check if the user wants to lock a texture surface, // which was loaded as patched! In this case we have to to // a blit to unpatch before we return it to the user // This is not expensive, since we leave it unpatched for // the future when the application decides to use it this way LPDDRAWI_DDRAWSURFACE_LCL pLcl=lpLockData->lpDDSurface; LPDDRAWI_DDRAWSURFACE_GBL pGbl=pLcl->lpGbl; PermediaSurfaceData *pPrivate= (PermediaSurfaceData*)pGbl->dwReserved1; // // If the user attempts to lock a managed surface, mark it as dirty // and return. // if (pLcl->lpSurfMore->ddsCapsEx.dwCaps2 & DDSCAPS2_TEXTUREMANAGE) { DBG_DD(( 3, "DDraw:Lock %08lx %08lx", pLcl->lpSurfMore->dwSurfaceHandle, pGbl->fpVidMem)); if (NULL != pPrivate) pPrivate->dwFlags |= P2_SURFACE_NEEDUPDATE; lpLockData->lpSurfData = (LPVOID)(pLcl->lpGbl->fpVidMem + (pLcl->lpGbl->lPitch * lpLockData->rArea.top) + (lpLockData->rArea.left << DDSurf_GetPixelShift(pLcl))); lpLockData->ddRVal = DD_OK; return DDHAL_DRIVER_HANDLED; } DD_CHECK_PRIMARY_SURFACE_DATA(pLcl,pPrivate); // // We only need to unswizzle a surface if the // PrivateData is in a format we know (pPrivate!=NULL) // if (pPrivate!=NULL) { // // if the surface is a texture which was loaded in a swizzled // format, we have to undo the swizzle before succeding the lock. // In this driver, a texture remains unswizzled when a user // attempted to lock it once. // if (pPrivate->dwFlags & P2_ISPATCHED) { // // The scratchpad must be 32 lines high and should have // the same width as our original surface. // PermediaSurfaceData ScratchData=*pPrivate; LONG lScratchDelta; VIDEOMEMORY* pvmHeap; ULONG ulScratchOffset= ulVidMemAllocate( ppdev, DDSurf_Width(pLcl), DDSurf_Height(pLcl), DDSurf_GetPixelShift(pLcl), &lScratchDelta, &pvmHeap, &ScratchData.ulPackedPP, FALSE); DBG_DD(( 5, " unswizzle surface, scratchpad at: %08lx", ulScratchOffset)); if (ulScratchOffset!=0) { RECTL rSurfRect; RECTL rScratchRect; rSurfRect.left=0; rSurfRect.top=0; rSurfRect.right=DDSurf_Width(pLcl); rSurfRect.bottom=32; rScratchRect=rSurfRect; // scratchpad should be non patched ScratchData.dwFlags &= ~(P2_ISPATCHED|P2_CANPATCH); LONG lSurfOffset; DWORD dwSurfBase=(DWORD)pGbl->fpVidMem >> DDSurf_GetPixelShift(pLcl); DWORD dwScratchBase=ulScratchOffset >> DDSurf_GetPixelShift(pLcl); lScratchDelta >>= DDSurf_GetPixelShift(pLcl); LONG lSurfDelta=DDSurf_Pitch(pLcl)>> DDSurf_GetPixelShift(pLcl); for (DWORD i=0; idwFlags &= ~P2_ISPATCHED; // // free scratchpad memory // VidMemFree( pvmHeap->lpHeap, ulScratchOffset); SYNC_WITH_PERMEDIA; } else { lpLockData->ddRVal = DDERR_OUTOFMEMORY; return DDHAL_DRIVER_HANDLED; } } } // 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 //----------------------------------------------------------------------------- // // DdGetScanLine // // This callback is invoked to get the current scanline of our video display // //----------------------------------------------------------------------------- DWORD CALLBACK DdGetScanLine(LPDDHAL_GETSCANLINEDATA lpGetScanLine) { PPDev ppdev=(PPDev)lpGetScanLine->lpDD->dhpdev; DBG_DD(( 2, "DDraw:GetScanLine")); // If a vertical blank is in progress the scan line is // 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_VRETRACE(ppdev) ) { lpGetScanLine->ddRVal = DDERR_VERTICALBLANKINPROGRESS; lpGetScanLine->dwScanLine = 0; } else { lpGetScanLine->dwScanLine = CURRENT_VLINE(ppdev); lpGetScanLine->ddRVal = DD_OK; } return DDHAL_DRIVER_HANDLED; } // DdGetScanLine //----------------------------------------------------------------------------- // // DdGetBltStatus // // This callback is invoked to get the current blit status or to ask if the // user can add the next blit. // //----------------------------------------------------------------------------- DWORD CALLBACK DdGetBltStatus(LPDDHAL_GETBLTSTATUSDATA lpGetBltStatus ) { PPDev ppdev=(PPDev)lpGetBltStatus->lpDD->dhpdev; PERMEDIA_DEFS(ppdev); DBG_DD(( 2, "DDraw:DdGetBltStatus")); // CANBLT: can we add a blt? // On the Permedia we can always add blits if( lpGetBltStatus->dwFlags == DDGBS_CANBLT ) { lpGetBltStatus->ddRVal = DD_OK; } else { if( DRAW_ENGINE_BUSY ) { //@@BEGIN_DDKSPLIT #if MULTITHREADED if(ppdev->ulLockCount) { DBG_DD((MT_LOG_LEVEL, "DdGetBltStatus: re-entry! %d", ppdev->ulLockCount)); } EngAcquireSemaphore(ppdev->hsemLock); ppdev->ulLockCount++; #endif //@@END_DDKSPLIT // switch to DDraw context if necessary DDCONTEXT; FLUSHDMA(); lpGetBltStatus->ddRVal = DDERR_WASSTILLDRAWING; //@@BEGIN_DDKSPLIT #if MULTITHREADED ppdev->ulLockCount--; EngReleaseSemaphore(ppdev->hsemLock); #endif //@@END_DDKSPLIT } else { lpGetBltStatus->ddRVal = DD_OK; } } return DDHAL_DRIVER_HANDLED; } // DdGetBltStatus //----------------------------------------------------------------------------- // // DdGetFlipStatus // // 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 // //----------------------------------------------------------------------------- DWORD CALLBACK DdGetFlipStatus(LPDDHAL_GETFLIPSTATUSDATA lpGetFlipStatus ) { PPDev ppdev=(PPDev)lpGetFlipStatus->lpDD->dhpdev; PERMEDIA_DEFS(ppdev); DBG_DD(( 2, "DDraw:GetFlipStatus")); // switch to DDraw context if necessary DDCONTEXT; // we can always flip, since the flip is pipelined // but we allow only one flip in advance if( lpGetFlipStatus->dwFlags == DDGFS_CANFLIP ) { lpGetFlipStatus->ddRVal = updateFlipStatus(ppdev); return DDHAL_DRIVER_HANDLED; } // 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 = updateFlipStatus(ppdev); return DDHAL_DRIVER_HANDLED; } // DdGetFlipStatus //----------------------------------------------------------------------------- // // DdMapMemory // // This is a new DDI call specific to Windows NT that is used to map // or unmap all the application modifiable portions of the frame buffer // into the specified process's address space. // //----------------------------------------------------------------------------- DWORD CALLBACK DdMapMemory(PDD_MAPMEMORYDATA lpMapMemory) { PDev* ppdev; VIDEO_SHARE_MEMORY ShareMemory; VIDEO_SHARE_MEMORY_INFORMATION ShareMemoryInformation; DWORD ReturnedDataLength; DBG_DD(( 2, "DDraw:MapMemory")); 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)) { DBG_DD((0, "Failed IOCTL_VIDEO_SHARE_MEMORY")); lpMapMemory->ddRVal = 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; return(DDHAL_DRIVER_HANDLED); } //----------------------------------------------------------------------------- // // DdSetExclusiveMode // // This function is called by DirectDraw when we switch from the GDI surface, // to DirectDraw exclusive mode, e.g. to run a game in fullcreen mode. // You only need to implement this function when you are using the // 'HeapVidMemAllocAligned' function and allocate memory for Device Bitmaps // and DirectDraw surfaces from the same heap. // // We use this call to disable GDI DeviceBitMaps when we are running in // DirectDraw exclusive mode. Otherwise a DD app gets confused if both GDI and // DirectDraw allocate memory from the same heap. // // See also DdFlipToGDISurface. // //----------------------------------------------------------------------------- DWORD CALLBACK DdSetExclusiveMode(PDD_SETEXCLUSIVEMODEDATA lpSetExclusiveMode) { PDev* ppdev=(PDev*)lpSetExclusiveMode->lpDD->dhpdev; DBG_DD((6, "DDraw::DdSetExclusiveMode called")); // remember setting of exclusive mode in ppdev, // so GDI can stop to promote DeviceBitmaps into // video memory ppdev->bDdExclusiveMode = lpSetExclusiveMode->dwEnterExcl; if (ppdev->bDdExclusiveMode) { // remove all GDI device bitmaps from video memory here // and make sure they will not be promoted to videomemory // until we leave exclusive mode. bDemoteAll(ppdev); } lpSetExclusiveMode->ddRVal=DD_OK; return (DDHAL_DRIVER_HANDLED); } //----------------------------------------------------------------------------- // // DWORD DdFlipToGDISurface // // This function is called by DirectDraw when it flips to the surface on which // GDI can write to. // //----------------------------------------------------------------------------- DWORD CALLBACK DdFlipToGDISurface(PDD_FLIPTOGDISURFACEDATA lpFlipToGDISurface) { PDev* ppdev=(PDev*)lpFlipToGDISurface->lpDD->dhpdev; DBG_DD((6, "DDraw::DdFlipToGDISurface called")); ppdev->dwNewDDSurfaceOffset=0xffffffff; #if DX7_STEREO if (ppdev->bDdStereoMode) { ppdev->bDdStereoMode=FALSE; LD_PERMEDIA_REG(PREG_VIDEOCONTROL, READ_PERMEDIA_REG(PREG_VIDEOCONTROL) & ~PREG_VC_STEREOENABLE); } #endif lpFlipToGDISurface->ddRVal=DD_OK; // // we return NOTHANDLED, then the ddraw runtime takes // care that we flip back to the primary... // return (DDHAL_DRIVER_NOTHANDLED); } //----------------------------------------------------------------------------- // // DWORD DdFreeDriverMemory // // This function called by DirectDraw when it's running low on memory in // our heap. You only need to implement this function if you use the // DirectDraw 'HeapVidMemAllocAligned' function in your driver, and you // can boot those allocations out of memory to make room for DirectDraw. // // We implement this function in the P2 driver because we have DirectDraw // entirely manage our off-screen heap, and we use HeapVidMemAllocAligned // to put GDI device-bitmaps in off-screen memory. DirectDraw applications // have a higher priority for getting stuff into video memory, though, and // so this function is used to boot those GDI surfaces out of memory in // order to make room for DirectDraw. // //----------------------------------------------------------------------------- DWORD CALLBACK DdFreeDriverMemory(PDD_FREEDRIVERMEMORYDATA lpFreeDriverMemory) { PDev* ppdev; DBG_DD((6, "DDraw::DdFreeDriverMemory called")); ppdev = (PDev*)lpFreeDriverMemory->lpDD->dhpdev; lpFreeDriverMemory->ddRVal = DDERR_OUTOFMEMORY; //@@BEGIN_DDKSPLIT #if MULTITHREADED if(ppdev->ulLockCount) { DBG_DD((MT_LOG_LEVEL, "DdFreeDriverMemory: re-entry! %d", ppdev->ulLockCount)); } EngAcquireSemaphore(ppdev->hsemLock); ppdev->ulLockCount++; #endif //@@END_DDKSPLIT // // If we successfully freed up some memory, set the return value to // 'DD_OK'. DirectDraw will try again to do its allocation, and // will call us again if there's still not enough room. (It will // call us until either there's enough room for its alocation to // succeed, or until we return something other than DD_OK.) // if ( bMoveOldestBMPOut(ppdev) ) { lpFreeDriverMemory->ddRVal = DD_OK; } //@@BEGIN_DDKSPLIT #if MULTITHREADED ppdev->ulLockCount--; EngReleaseSemaphore(ppdev->hsemLock); #endif //@@END_DDKSPLIT return (DDHAL_DRIVER_HANDLED); }// DdFreeDriverMemory() //----------------------------------------------------------------------------- // // 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; BOOL bDefineAGPHeap = FALSE,bDefineDDrawHeap = FALSE; LONGLONG li; VIDEOMEMORY* pVm; DWORD cHeaps; DWORD dwRegistryValue; DBG_DD((3, "DrvGetDirectDrawInfo Called")); PDev *ppdev=(PDev*) dhpdev; *pdwNumFourCC = 0; *pdwNumHeaps = 0; //On the first call, setup the chip info if(!(pvmList && pdwFourCC)) { // // Fill in the DDHAL Informational caps // GetDDHALInfo(ppdev, pHalInfo); // // 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 ) { // // Tell DDRAW that the surface is 8-bit color indexed // 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; // // We have to tell DirectDraw our preferred off-screen alignment // pHalInfo->vmiData.dwOffscreenAlign = 4; pHalInfo->vmiData.dwZBufferAlign = 4; pHalInfo->vmiData.dwTextureAlign = 4; pHalInfo->ddCaps.dwVidMemTotal = (ppdev->lVidMemHeight - ppdev->cyScreen) * ppdev->lDelta; } cHeaps = 0; // // Determine the YUV modes for Video playback acceleration. We can do YUV // conversions at any depth except 8 bits... // if (ppdev->iBitmapFormat != BMF_8BPP) { *pdwNumFourCC = sizeof( fourCC ) / sizeof( fourCC[0] ); } if(DD_P2AGPCAPABLE(ppdev)) { bDefineAGPHeap = TRUE; cHeaps++; } // Do we have sufficient videomemory to create an off-screen heap for // DDraw? Test how much video memory is left after we subtract // that which is being used for the screen. if ( (ppdev->cxScreen < ppdev->lVidMemWidth) ||(ppdev->cyScreen < ppdev->lVidMemHeight)) { bDefineDDrawHeap = TRUE; cHeaps++; } ppdev->cHeaps = cHeaps; *pdwNumHeaps = cHeaps; // Define the fourCC's that we support if (pdwFourCC) { memcpy(pdwFourCC, fourCC, sizeof(fourCC)); } // If pvmList is not NULL then we can go ahead and fill out the VIDEOMEMORY // structures which define our requested heaps. if(pvmList) { pVm=pvmList; // // Snag a pointer to the video-memory list so that we can use it to // call back to DirectDraw to allocate video memory: // ppdev->pvmList = pVm; // // Create one heap to describe the unused portion of video memory for // DirectDraw use // // Note: here lVidMemWidth is in "pixel" unit. So we should multiply it // by cjPelSize to get actually BYTES of video memory // // 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). // // Define the heap for DirectDraw // if ( bDefineDDrawHeap ) { pVm->dwFlags = VIDMEM_ISLINEAR ; pVm->fpStart = ppdev->cyScreen * ppdev->lDelta; pVm->fpEnd = ppdev->lVidMemHeight * ppdev->lDelta - 1; // // DWORD align the size, the hardware should guarantee this // ASSERTDD(((pVm->fpEnd - pVm->fpStart + 1) & 3) == 0, "The off-screen heap size should be DWORD aligned"); pVm->ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; DBG_DD((7, "fpStart %ld fpEnd %ld", pVm->fpStart, pVm->fpEnd)); DBG_DD((7, "DrvGetDirectDrawInfo Creates 1 heap for DDRAW")); pVm++; } //Define the AGP heap if(bDefineAGPHeap) { DWORD dwAGPMemBytes; BOOL bSuccess; // Request 32Mb of AGP Memory, DDRAW will allocate less // if this amount is not available dwAGPMemBytes = P2_AGP_HEAPSIZE*1024*1024; DBG_DD((7, "Initialised AGP Heap for P2")); // The start address of the heap, // just set to zero as DDRAW handles the allocation pVm->fpStart = 0; // Fetch the last byte of AGP memory pVm->fpEnd = dwAGPMemBytes - 1; // drivers can set VIDMEM_ISWC here, // then memory will be write combined. // but memory on AGP buses is always uncached pVm->dwFlags = VIDMEM_ISNONLOCAL | VIDMEM_ISLINEAR | VIDMEM_ISWC; // Only use AGP memory for textures and OFFSCREENPLAIN pVm->ddsCaps.dwCaps = DDSCAPS_OVERLAY | DDSCAPS_FRONTBUFFER | DDSCAPS_BACKBUFFER | DDSCAPS_ZBUFFER | DDSCAPS_3DDEVICE ; pVm->ddsCapsAlt.dwCaps =DDSCAPS_OVERLAY | DDSCAPS_FRONTBUFFER | DDSCAPS_BACKBUFFER | DDSCAPS_ZBUFFER | DDSCAPS_3DDEVICE ; ++pVm; } } DBG_DD((6, "DrvGetDirectDrawInfo return TRUE")); return(TRUE); }// DrvGetDirectDrawInfo() //----------------------------------------------------------------------------- // // InitDDHAL // // do the final initialisation of the HAL: // setup DDraw specific variables for the ppdev and fill in all callbacks // for DirectDraw // // No Chip register setup is done here - it is all handled in the mode // change code which this function calls // //----------------------------------------------------------------------------- BOOL InitDDHAL(PPDev ppdev) { PERMEDIA_DEFS(ppdev); DBG_DD((1, "DDraw:InitDDHAL*************************************" )); DBG_DD((1, " ScreenStart =%08lx", ppdev->dwScreenStart)); DBG_DD((1, " ScreenWidth=%08lx", ppdev->cxScreen )); DBG_DD((1, " ScreenHeight=%08lx", ppdev->cyScreen)); DBG_DD((1, " dwRGBBitCount=%ld", ppdev->ddpfDisplay.dwRGBBitCount )); DBG_DD((1, " RMask: 0x%x", ppdev->ddpfDisplay.dwRBitMask )); DBG_DD((1, " GMask: 0x%x", ppdev->ddpfDisplay.dwGBitMask )); DBG_DD((1, " BMask: 0x%x", ppdev->ddpfDisplay.dwBBitMask )); DBG_DD((1, "*****************************************************" )); // Fill in the HAL Callback pointers memset(&ppdev->DDHALCallbacks, 0, sizeof(DDHAL_DDCALLBACKS)); ppdev->DDHALCallbacks.dwSize = sizeof(DDHAL_DDCALLBACKS); ppdev->DDHALCallbacks.WaitForVerticalBlank = DdWaitForVerticalBlank; ppdev->DDHALCallbacks.CanCreateSurface = DdCanCreateSurface; ppdev->DDHALCallbacks.GetScanLine = DdGetScanLine; ppdev->DDHALCallbacks.MapMemory = DdMapMemory; //@@BEGIN_DDKSPLIT #if MULTITHREADED ppdev->DDHALCallbacks.CreateSurface = MtDdCreateSurface; #else //@@END_DDKSPLIT ppdev->DDHALCallbacks.CreateSurface = DdCreateSurface; //@@BEGIN_DDKSPLIT #endif MULTITHREADED //@@END_DDKSPLIT // Fill in the HAL Callback flags ppdev->DDHALCallbacks.dwFlags = DDHAL_CB32_WAITFORVERTICALBLANK | DDHAL_CB32_MAPMEMORY | DDHAL_CB32_GETSCANLINE | DDHAL_CB32_CANCREATESURFACE | DDHAL_CB32_CREATESURFACE; // Fill in the Surface Callback pointers memset(&ppdev->DDSurfCallbacks, 0, sizeof(DDHAL_DDSURFACECALLBACKS)); ppdev->DDSurfCallbacks.dwSize = sizeof(DDHAL_DDSURFACECALLBACKS); //@@BEGIN_DDKSPLIT #if MULTITHREADED ppdev->DDSurfCallbacks.DestroySurface = MtDdDestroySurface; ppdev->DDSurfCallbacks.Flip = MtDdFlip; ppdev->DDSurfCallbacks.Lock = MtDdLock; ppdev->DDSurfCallbacks.GetBltStatus = DdGetBltStatus; // Internally protected ppdev->DDSurfCallbacks.GetFlipStatus = MtDdGetFlipStatus; ppdev->DDSurfCallbacks.Blt = MtDdBlt; #else //@@END_DDKSPLIT ppdev->DDSurfCallbacks.DestroySurface = DdDestroySurface; ppdev->DDSurfCallbacks.Flip = DdFlip; ppdev->DDSurfCallbacks.Lock = DdLock; ppdev->DDSurfCallbacks.GetBltStatus = DdGetBltStatus; ppdev->DDSurfCallbacks.GetFlipStatus = DdGetFlipStatus; ppdev->DDSurfCallbacks.Blt = DdBlt; //@@BEGIN_DDKSPLIT #endif MULTITHREADED //@@END_DDKSPLIT ppdev->DDSurfCallbacks.dwFlags = DDHAL_SURFCB32_DESTROYSURFACE | DDHAL_SURFCB32_FLIP | DDHAL_SURFCB32_LOCK | DDHAL_SURFCB32_BLT | DDHAL_SURFCB32_GETBLTSTATUS | DDHAL_SURFCB32_GETFLIPSTATUS; //@@BEGIN_DDKSPLIT #if MULTITHREADED ppdev->DDSurfCallbacks.SetColorKey = MtDdSetColorKey; #else //@@END_DDKSPLIT ppdev->DDSurfCallbacks.SetColorKey = DdSetColorKey; //@@BEGIN_DDKSPLIT #endif MULTITHREADED //@@END_DDKSPLIT ppdev->DDSurfCallbacks.dwFlags |= DDHAL_SURFCB32_SETCOLORKEY; // Fill in the DDHAL Informational caps GetDDHALInfo(ppdev, &ppdev->ddhi32); return (TRUE); }// InitDDHAL() //----------------------------------------------------------------------------- // // 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 bIsStereoMode(PDev *ppdev, PDD_STEREOMODE pDDStereoMode) { pDDStereoMode->bSupported = FALSE; // we need to check dwBpp for a valid value as PDD_STEREOMODE.dwBpp is a // parameter passed on from the user mode API call if ((pDDStereoMode->dwWidth >= 320) && (pDDStereoMode->dwHeight >= 240) && (pDDStereoMode->dwBpp >= 8) && (pDDStereoMode->dwBpp <= 32) ) { DWORD dwLines=ppdev->FrameBufferLength/ (pDDStereoMode->dwWidth*pDDStereoMode->dwBpp/8); if (dwLines > (pDDStereoMode->dwHeight*4)) { pDDStereoMode->bSupported = TRUE; } } return pDDStereoMode->bSupported; } //----------------------------------------------------------------------------- // // DdGetDriverInfo // // callback for various new HAL features, post DX3. // //----------------------------------------------------------------------------- DWORD CALLBACK DdGetDriverInfo(LPDDHAL_GETDRIVERINFODATA lpData) { PPDev ppdev=(PPDev)lpData->dhpdev; PERMEDIA_DEFS(ppdev); DWORD dwSize; DBG_DD(( 2, "DDraw:GetDriverInfo")); // Get a pointer to the chip we are on. // Default to 'not supported' lpData->ddRVal = DDERR_CURRENTLYNOTAVAIL; ppdev = (PDev*) lpData->dhpdev; // fill in supported stuff if (IsEqualIID(&lpData->guidInfo, &GUID_D3DCallbacks3)) { D3DHAL_CALLBACKS3 D3DCB3; DBG_DD((3," GUID_D3DCallbacks3")); memset(&D3DCB3, 0, sizeof(D3DHAL_CALLBACKS3)); D3DCB3.dwSize = sizeof(D3DHAL_CALLBACKS3); D3DCB3.lpvReserved = NULL; D3DCB3.ValidateTextureStageState = D3DValidateTextureStageState; //@@BEGIN_DDKSPLIT #if MULTITHREADED D3DCB3.DrawPrimitives2 = MtD3DDrawPrimitives2; #else //@@END_DDKSPLIT D3DCB3.DrawPrimitives2 = D3DDrawPrimitives2; //@@BEGIN_DDKSPLIT #endif MULTITHREADED //@@END_DDKSPLIT D3DCB3.dwFlags |= D3DHAL3_CB32_DRAWPRIMITIVES2 | D3DHAL3_CB32_VALIDATETEXTURESTAGESTATE | 0; lpData->dwActualSize = sizeof(D3DHAL_CALLBACKS3); dwSize=min(lpData->dwExpectedSize,sizeof(D3DHAL_CALLBACKS3)); memcpy(lpData->lpvData, &D3DCB3, dwSize); lpData->ddRVal = DD_OK; } else if (IsEqualIID(&lpData->guidInfo, &GUID_D3DExtendedCaps)) { D3DNTHAL_D3DEXTENDEDCAPS D3DExtendedCaps; DBG_DD((3," GUID_D3DExtendedCaps")); memset(&D3DExtendedCaps, 0, sizeof(D3DExtendedCaps)); dwSize=min(lpData->dwExpectedSize, sizeof(D3DExtendedCaps)); lpData->dwActualSize = dwSize; D3DExtendedCaps.dwSize = dwSize; // number of (multi)textures we support simultaneusly for DX6 D3DExtendedCaps.dwFVFCaps = 1; D3DExtendedCaps.dwMinTextureWidth = 1; D3DExtendedCaps.dwMinTextureHeight = 1; D3DExtendedCaps.dwMaxTextureWidth = 2048; D3DExtendedCaps.dwMaxTextureHeight = 2048; D3DExtendedCaps.dwMinStippleWidth = 8; D3DExtendedCaps.dwMaxStippleWidth = 8; D3DExtendedCaps.dwMinStippleHeight = 8; D3DExtendedCaps.dwMaxStippleHeight = 8; D3DExtendedCaps.dwTextureOpCaps = D3DTEXOPCAPS_DISABLE | D3DTEXOPCAPS_SELECTARG1 | D3DTEXOPCAPS_SELECTARG2 | D3DTEXOPCAPS_MODULATE | D3DTEXOPCAPS_ADD | D3DTEXOPCAPS_BLENDTEXTUREALPHA | 0; D3DExtendedCaps.wMaxTextureBlendStages = 1; D3DExtendedCaps.wMaxSimultaneousTextures = 1; // Full range of the integer (non-fractional) bits of the // post-normalized texture indices. If the // D3DDEVCAPS_TEXREPEATNOTSCALEDBYSIZE bit is set, the // device defers scaling by the texture size until after // the texture address mode is applied. If it isn't set, // the device scales the texture indices by the texture size // (largest level-of-detail) prior to interpolation. D3DExtendedCaps.dwMaxTextureRepeat = 2048; // In order to support stencil buffers in DX6 we need besides // setting these caps and handling the proper renderstates to // declare the appropriate z buffer pixel formats here in // response to the GUID_ZPixelFormats and implement the // Clear2 callback. Also , we need to be able to create the // appropriate ddraw surfaces. #if D3D_STENCIL D3DExtendedCaps.dwStencilCaps = 0 | D3DSTENCILCAPS_KEEP | D3DSTENCILCAPS_ZERO | D3DSTENCILCAPS_REPLACE | D3DSTENCILCAPS_INCRSAT | D3DSTENCILCAPS_DECRSAT | D3DSTENCILCAPS_INVERT; #endif #if D3DDX7_TL // In order to use hw accelerated T&L we must declare // how many simultaneously active lights we can handle. D3DExtendedCaps.dwMaxActiveLights = 0; #endif //D3DDX7_TL //@@BEGIN_DDKSPLIT #if D3D_POINTSPRITES // Parameter for point sprites D3DExtendedCaps.dvMaxPointSize = 10.0; #endif // D3D_POINTSPRITES //@@END_DDKSPLIT memcpy(lpData->lpvData, &D3DExtendedCaps, dwSize); lpData->ddRVal = DD_OK; } else if (IsEqualIID(&lpData->guidInfo, &GUID_ZPixelFormats)) { DDPIXELFORMAT ddZBufPixelFormat[2]; DWORD dwNumZPixelFormats; DBG_DD((3," GUID_ZPixelFormats")); memset(ddZBufPixelFormat, 0, sizeof(ddZBufPixelFormat)); #if D3D_STENCIL dwSize = (DWORD)min(lpData->dwExpectedSize, 2*sizeof(DDPIXELFORMAT)); lpData->dwActualSize = 2*sizeof(DDPIXELFORMAT) + sizeof(DWORD); #else dwSize = (DWORD)min(lpData->dwExpectedSize, 1*sizeof(DDPIXELFORMAT)); lpData->dwActualSize = 1*sizeof(DDPIXELFORMAT) + sizeof(DWORD); #endif // If we didn't support stencils, we would only fill one 16-bit // Z Buffer format since that is all what the Permedia supports. // Drivers that implement stencil buffer support (like this one) // have to report here all Z Buffer formats supported since they // have to support the Clear2 callback (or the D3DDP2OP_CLEAR // token) #if D3D_STENCIL dwNumZPixelFormats = 2; #else dwNumZPixelFormats = 1; #endif ddZBufPixelFormat[0].dwSize = sizeof(DDPIXELFORMAT); ddZBufPixelFormat[0].dwFlags = DDPF_ZBUFFER; ddZBufPixelFormat[0].dwFourCC = 0; ddZBufPixelFormat[0].dwZBufferBitDepth = 16; ddZBufPixelFormat[0].dwStencilBitDepth = 0; ddZBufPixelFormat[0].dwZBitMask = 0xFFFF; ddZBufPixelFormat[0].dwStencilBitMask = 0x0000; ddZBufPixelFormat[0].dwRGBZBitMask = 0; #if D3D_STENCIL ddZBufPixelFormat[1].dwSize = sizeof(DDPIXELFORMAT); ddZBufPixelFormat[1].dwFlags = DDPF_ZBUFFER | DDPF_STENCILBUFFER; ddZBufPixelFormat[1].dwFourCC = 0; // The sum of the z buffer bit depth AND the stencil depth // should be included here ddZBufPixelFormat[1].dwZBufferBitDepth = 16; ddZBufPixelFormat[1].dwStencilBitDepth = 1; ddZBufPixelFormat[1].dwZBitMask = 0x7FFF; ddZBufPixelFormat[1].dwStencilBitMask = 0x8000; ddZBufPixelFormat[1].dwRGBZBitMask = 0; #endif memcpy(lpData->lpvData, &dwNumZPixelFormats, sizeof(DWORD)); memcpy((LPVOID)((LPBYTE)(lpData->lpvData) + sizeof(DWORD)), ddZBufPixelFormat, dwSize); lpData->ddRVal = DD_OK; } else if (IsEqualIID(&(lpData->guidInfo), &GUID_D3DParseUnknownCommandCallback)) { DBG_DD((3," GUID_D3DParseUnknownCommandCallback")); ppdev->pD3DParseUnknownCommand = (PFND3DNTPARSEUNKNOWNCOMMAND)(lpData->lpvData); lpData->ddRVal = DD_OK; } //@@BEGIN_DDKSPLIT #if DX7_ALPHABLT else if (IsEqualIID(&(lpData->guidInfo), &GUID_DDMoreCaps)) { DD_MORECAPS DDMoreCaps; DBG_DD((3," GUID_DDMoreCaps")); // here we set all the caps for the new // DirectDraw 7 AlphaBlt callback memset(&DDMoreCaps, 0, sizeof(DD_MORECAPS)); DDMoreCaps.dwSize=sizeof(DD_MORECAPS); // alpha caps for Vmem->Vmem blts // claim to do lots of stuff, we can still fail in callback DDMoreCaps.dwAlphaCaps = DDALPHACAPS_BLTALPHAPIXELS | DDALPHACAPS_BLTSATURATE | DDALPHACAPS_BLTPREMULT | DDALPHACAPS_BLTNONPREMULT | DDALPHACAPS_BLTALPHAFILL | DDALPHACAPS_BLTARGBSCALE1F | DDALPHACAPS_BLTARGBSCALE2F | DDALPHACAPS_BLTARGBSCALE4F | DDALPHACAPS_BLTALPHAANDARGBSCALING; DDMoreCaps.dwSVBAlphaCaps = 0; // alpha capabilities for System->Vmem blts DDMoreCaps.dwVSBAlphaCaps = 0; // alpha capabilities for Vmem->System blts DDMoreCaps.dwSSBAlphaCaps = 0; // alpha capabilities for System->System blts // filter caps for Vmem->Vmem blts DDMoreCaps.dwFilterCaps = DDFILTCAPS_BLTQUALITYFILTER | DDFILTCAPS_BLTCANDISABLEFILTER; DDMoreCaps.dwSVBFilterCaps= 0; // filter capabilities for System->Vmem blts DDMoreCaps.dwVSBFilterCaps= 0; // filter capabilities for Vmem->System blts DDMoreCaps.dwSSBFilterCaps= 0; // filter capabilities for System->System blts lpData->dwActualSize = sizeof(DDMoreCaps); dwSize=min( sizeof(DDMoreCaps), lpData->dwExpectedSize); memcpy(lpData->lpvData, &DDMoreCaps, dwSize); lpData->ddRVal = DD_OK; } #endif //@@END_DDKSPLIT else if (IsEqualIID(&(lpData->guidInfo), &GUID_Miscellaneous2Callbacks) ) { BOOL bRet; DWORD dwResult; DDHAL_DDMISCELLANEOUS2CALLBACKS MISC2_CB; DBG_DD((3," GUID_Miscellaneous2Callbacks2")); memset(&MISC2_CB, 0, sizeof(DDHAL_DDMISCELLANEOUS2CALLBACKS)); MISC2_CB.dwSize = sizeof(DDHAL_DDMISCELLANEOUS2CALLBACKS); MISC2_CB.dwFlags = 0 //@@BEGIN_DDKSPLIT #if DX7_ALPHABLT | DDHAL_MISC2CB32_ALPHABLT #endif //@@END_DDKSPLIT | DDHAL_MISC2CB32_CREATESURFACEEX | DDHAL_MISC2CB32_GETDRIVERSTATE | DDHAL_MISC2CB32_DESTROYDDLOCAL; MISC2_CB.GetDriverState = D3DGetDriverState; MISC2_CB.CreateSurfaceEx = D3DCreateSurfaceEx; MISC2_CB.DestroyDDLocal = D3DDestroyDDLocal; //@@BEGIN_DDKSPLIT #if DX7_ALPHABLT MISC2_CB.AlphaBlt = DdAlphaBlt; #endif //@@END_DDKSPLIT lpData->dwActualSize = sizeof(MISC2_CB); dwSize = min(sizeof(MISC2_CB),lpData->dwExpectedSize); memcpy(lpData->lpvData, &MISC2_CB, dwSize); lpData->ddRVal = DD_OK; } else if (IsEqualIID(&(lpData->guidInfo), &GUID_UpdateNonLocalHeap)) { LPDDHAL_UPDATENONLOCALHEAPDATA pDDNonLocalHeap; DBG_DD((3," GUID_UpdateNonLocalHeap")); pDDNonLocalHeap = (LPDDHAL_UPDATENONLOCALHEAPDATA)lpData->lpvData; ppdev->dwGARTLinBase = pDDNonLocalHeap->fpGARTLin; ppdev->dwGARTDevBase = pDDNonLocalHeap->fpGARTDev; // These values are used to specify the base address of the // visible 8Mb window of AGP memory ppdev->dwGARTLin = pDDNonLocalHeap->fpGARTLin; ppdev->dwGARTDev = pDDNonLocalHeap->fpGARTDev; DDCONTEXT; SYNC_WITH_PERMEDIA; LD_PERMEDIA_REG (PREG_AGPTEXBASEADDRESS,(ULONG)ppdev->dwGARTDev); DBG_DD((3,"GartLin: 0x%x, GartDev: 0x%x", (ULONG)ppdev->dwGARTLin, ppdev->dwGARTDev)); lpData->ddRVal = DD_OK; } else if (IsEqualIID(&(lpData->guidInfo), &GUID_GetHeapAlignment) ) { LPDDHAL_GETHEAPALIGNMENTDATA lpFData= (LPDDHAL_GETHEAPALIGNMENTDATA) lpData->lpvData; DBG_DD((3," GUID_GetHeapAlignment")); lpData->ddRVal = DD_OK; } else if (IsEqualIID(&(lpData->guidInfo), &GUID_NTPrivateDriverCaps) ) { DD_NTPRIVATEDRIVERCAPS DDPrivateDriverCaps; DBG_DD((3," GUID_NTPrivateDriverCaps")); memset(&DDPrivateDriverCaps, 0, sizeof(DDPrivateDriverCaps)); DDPrivateDriverCaps.dwSize=sizeof(DDPrivateDriverCaps); // we want the kernel to call us when a primary surface is created // so that we can store some private information in the // lpGbl->dwReserved1 field DDPrivateDriverCaps.dwPrivateCaps=DDHAL_PRIVATECAP_NOTIFYPRIMARYCREATION; lpData->dwActualSize =sizeof(DDPrivateDriverCaps); dwSize = min(sizeof(DDPrivateDriverCaps),lpData->dwExpectedSize); memcpy(lpData->lpvData, &DDPrivateDriverCaps, dwSize); lpData->ddRVal = DD_OK; } #if DX7_STEREO else if (IsEqualIID(&(lpData->guidInfo), &GUID_DDMoreSurfaceCaps) ) { DD_MORESURFACECAPS DDMoreSurfaceCaps; DDSCAPSEX ddsCapsEx, ddsCapsExAlt; ULONG ulCopyPointer; DBG_DD((3," 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; DBG_DD((3," stereo support: %ld", ppdev->bCanDoStereo)); if (ppdev->bCanDoStereo) { DDMoreSurfaceCaps.ddsCapsMore.dwCaps2 = DDSCAPS2_STEREOSURFACELEFT; } lpData->dwActualSize = lpData->dwExpectedSize; dwSize = min(sizeof(DDMoreSurfaceCaps),lpData->dwExpectedSize); memcpy(lpData->lpvData, &DDMoreSurfaceCaps, dwSize); // now fill in other heaps... 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; } else if (IsEqualIID(&(lpData->guidInfo), &GUID_DDStereoMode) ) { PDD_STEREOMODE pDDStereoMode; // Permedia supports all modes as stereo modes. // for test purposes, we restrict them to something // larger than 320x240 // // note: this GUID_DDStereoMode is only used on NT to // report stereo modes. There is no need to implement // it in win9x drivers. Win9x drivers report stereo // modes by setting the DDMODEINFO_STEREO bit in the // dwFlags member of the DDHALMODEINFO structure. // It is also recommended to report DDMODEINFO_MAXREFRESH // for stereo modes when running under a runtime >= DX7 to // allow applications to select higher refresh rates for // stereo modes. // if (lpData->dwExpectedSize >= sizeof(PDD_STEREOMODE)) { pDDStereoMode = (PDD_STEREOMODE) lpData->lpvData; bIsStereoMode( ppdev, pDDStereoMode); DBG_DD((3," GUID_DDStereoMode(%d,%d,%d,%d=%d)", pDDStereoMode->dwWidth, pDDStereoMode->dwHeight, pDDStereoMode->dwBpp, pDDStereoMode->dwRefreshRate, pDDStereoMode->bSupported)); lpData->dwActualSize = sizeof(DD_STEREOMODE); lpData->ddRVal = DD_OK; } } #endif else if (IsEqualIID(&(lpData->guidInfo), &GUID_NonLocalVidMemCaps) ) { DD_NONLOCALVIDMEMCAPS DDNonLocalVidMemCaps; DBG_DD((3," GUID_DDNonLocalVidMemCaps")); memset(&DDNonLocalVidMemCaps, 0, sizeof(DDNonLocalVidMemCaps)); DDNonLocalVidMemCaps.dwSize=sizeof(DDNonLocalVidMemCaps); //fill in all supported nonlocal to videomemory blts // DDNonLocalVidMemCaps.dwNLVBCaps = DDCAPS_BLT | DDCAPS_BLTSTRETCH | DDCAPS_BLTQUEUE | DDCAPS_COLORKEY | DDCAPS_ALPHA | DDCAPS_CANBLTSYSMEM; DDNonLocalVidMemCaps.dwNLVBCaps2 = 0; DDNonLocalVidMemCaps.dwNLVBCKeyCaps=DDCKEYCAPS_SRCBLT | DDCKEYCAPS_SRCBLTCLRSPACE; DDNonLocalVidMemCaps.dwNLVBFXCaps = DDFXCAPS_BLTALPHA | DDFXCAPS_BLTFILTER | DDFXCAPS_BLTSTRETCHY | DDFXCAPS_BLTSTRETCHX | DDFXCAPS_BLTSTRETCHYN | DDFXCAPS_BLTSTRETCHXN | DDFXCAPS_BLTSHRINKY | DDFXCAPS_BLTSHRINKX | DDFXCAPS_BLTSHRINKYN | DDFXCAPS_BLTSHRINKXN | DDFXCAPS_BLTMIRRORUPDOWN | DDFXCAPS_BLTMIRRORLEFTRIGHT; if (ppdev->iBitmapFormat != BMF_8BPP) { DDNonLocalVidMemCaps.dwNLVBCaps |= DDCAPS_BLTFOURCC; DDNonLocalVidMemCaps.dwNLVBCKeyCaps|=DDCKEYCAPS_SRCBLTCLRSPACEYUV; } for(INT i = 0; i < DD_ROP_SPACE; i++ ) DDNonLocalVidMemCaps.dwNLVBRops[i] = rops[i]; lpData->dwActualSize =sizeof(DDNonLocalVidMemCaps); dwSize = min(sizeof(DDNonLocalVidMemCaps),lpData->dwExpectedSize); memcpy(lpData->lpvData, &DDNonLocalVidMemCaps, dwSize); lpData->ddRVal = DD_OK; } else if (IsEqualIID(&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 ; //@@BEGIN_DDKSPLIT #if MULTITHREADED NtCallbacks.FreeDriverMemory = DdFreeDriverMemory; // Internally protected NtCallbacks.SetExclusiveMode = MtDdSetExclusiveMode; NtCallbacks.FlipToGDISurface = MtDdFlipToGDISurface; #else //@@END_DDKSPLIT NtCallbacks.FreeDriverMemory = DdFreeDriverMemory; NtCallbacks.SetExclusiveMode = DdSetExclusiveMode; NtCallbacks.FlipToGDISurface = DdFlipToGDISurface; //@@BEGIN_DDKSPLIT #endif MULTITHREADED //@@END_DDKSPLIT memcpy(lpData->lpvData, &NtCallbacks, dwSize); lpData->ddRVal = DD_OK; } // We always handled it. return DDHAL_DRIVER_HANDLED; } // GetDriverInfo //----------------------------------------------------------------------------- // // updateFlipStatus // // return DD_OK when last flip has occured. // //----------------------------------------------------------------------------- HRESULT updateFlipStatus( PPDev ppdev ) { PERMEDIA_DEFS(ppdev); DBG_DD((6, "DDraw:updateFlipStatus")); // we assume that we are already in the DDraw/D3D context. // read Permedia register which tells us if there is a flip pending if (ppdev->dwNewDDSurfaceOffset!=0xffffffff) { ULONG ulScreenBase=READ_PERMEDIA_REG(PREG_SCREENBASE); if (ulScreenBase!= ppdev->dwNewDDSurfaceOffset) { DBG_DD((7," SurfaceOffset %08lx instead of %08lx", ulScreenBase, ppdev->dwNewDDSurfaceOffset)); // // make sure all pending data was flushed! // FLUSHDMA(); // // if we are busy, return // otherwise the pipeline is empty and we can // fall through and to check if the chip already flipped. // if (DRAW_ENGINE_BUSY) return DDERR_WASSTILLDRAWING; } } DWORD dwVideoControl=READ_PERMEDIA_REG(PREG_VIDEOCONTROL); if (dwVideoControl & PREG_VC_SCREENBASEPENDING) { DBG_DD((7," VideoControl still pending (%08lx)",dwVideoControl)); return DDERR_WASSTILLDRAWING; } return DD_OK; } // updateFlipStatus //@@BEGIN_DDKSPLIT #if MULTITHREADED //----------------------------------------------------------------------------- // // Multithread support wrappers for Dx callback functions // //----------------------------------------------------------------------------- //DWORD CALLBACK MtDdBlt( LPDDHAL_BLTDATA lpBlt ); WRAPMTDXCALLBACK(DD, DdBlt, LPDDHAL_BLTDATA, lpBlt, lpBlt->lpDD->dhpdev); //DWORD CALLBACK MtDdCreateSurface( LPDDHAL_CREATESURFACEDATA pcsd); WRAPMTDXCALLBACK(DD, DdCreateSurface, LPDDHAL_CREATESURFACEDATA, pcsd, pcsd->lpDD->dhpdev); //DWORD CALLBACK MtDdDestroySurface( LPDDHAL_DESTROYSURFACEDATA psdd); WRAPMTDXCALLBACK(DD, DdDestroySurface, LPDDHAL_DESTROYSURFACEDATA, psdd, psdd->lpDD->dhpdev); //DWORD CALLBACK MtDdFlip( LPDDHAL_FLIPDATA lpFlipData); WRAPMTDXCALLBACK(DD, DdFlip, LPDDHAL_FLIPDATA, lpFlipData, lpFlipData->lpDD->dhpdev); //DWORD CALLBACK MtDdFlipToGDISurface(PDD_FLIPTOGDISURFACEDATA lpFlipToGDISurface); WRAPMTDXCALLBACK(DD, DdFlipToGDISurface, PDD_FLIPTOGDISURFACEDATA, lpFlipToGDISurface, lpFlipToGDISurface->lpDD->dhpdev); //DWORD CALLBACK MtDdGetFlipStatus(LPDDHAL_GETFLIPSTATUSDATA lpGetFlipStatus); WRAPMTDXCALLBACK(DD, DdGetFlipStatus, LPDDHAL_GETFLIPSTATUSDATA, lpGetFlipStatus, lpGetFlipStatus->lpDD->dhpdev); //DWORD CALLBACK MtDdLock( LPDDHAL_LOCKDATA lpLockData ); WRAPMTDXCALLBACK(DD, DdLock, LPDDHAL_LOCKDATA, lpLockData, lpLockData->lpDD->dhpdev); //DWORD CALLBACK MtDdSetExclusiveMode(PDD_SETEXCLUSIVEMODEDATA lpSetExclusiveMode); WRAPMTDXCALLBACK(DD, DdSetExclusiveMode, PDD_SETEXCLUSIVEMODEDATA, lpSetExclusiveMode, lpSetExclusiveMode->lpDD->dhpdev); #endif MULTITHREADED //@@END_DDKSPLIT