/*========================================================================== * * Copyright (C) 1994-1995 Microsoft Corporation. All Rights Reserved. * * File: ddsblt.c * Content: DirectDraw Surface support for blt * History: * Date By Reason * ==== == ====== * 24-jan-95 craige split out of ddsurf.c, enhanced * 31-jan-95 craige and even more ongoing work... * 03-feb-95 craige performance tuning, ongoing work * 21-feb-95 craige work work work * 27-feb-95 craige new sync. macros * 08-mar-95 craige new stretch flags * 11-mar-95 craige take Win16 lock on Win95 before calling 32-bit fns * 15-mar-95 craige HEL integration * 19-mar-95 craige use HRESULTs * 29-mar-95 craige make colorfill work * 01-apr-95 craige happy fun joy updated header file * 03-apr-95 craige off by one when rect specified; need to validate * rectangles against surfaces * 12-apr-95 craige pulled out clipped stretching code optimization for now * 15-apr-95 craige can't allow source surface with colorfill; don't * allow < 0 left, top coords * 06-may-95 craige use driver-level csects only * 11-jun-95 craige check for locked surface before blt * 21-jun-95 kylej lock non-emulated surfaces before calling HEL blt * 21-jun-95 craige clipping changes * 24-jun-95 kylej move video memory source surfaces to system memory * if there is no hardware blt support. * 25-jun-95 craige one ddraw mutex * 26-jun-95 craige reorganized surface structure * 27-jun-95 craige use clipper to do clipping; started BltBatch; * moved CheckBltStretching back in * 28-jun-95 craige ENTER_DDRAW at very start of fns; disabled alpha & Z blt * 04-jul-95 craige YEEHAW: new driver struct; SEH * 05-jul-95 kylej debugged clipping code and added clipped stretched blts * 07-jul-95 craige added test for BUSY * 07-jul-95 kylej replace inline code with call to XformRect * 08-jul-95 craige BltFast: need to use HEL if src or dest is in * system memory! * 09-jul-95 craige hasvram flag in MoveToSystemMemory; handle loss * of color key resource after blt * 10-jul-95 kylej added mirroring caps checks in Blt * 13-jul-95 craige ENTER_DDRAW is now the win16 lock * 16-jul-95 craige check DDRAWISURF_HELCB * 27-jul-95 craige check for color fill support in hardware! * 31-jul-95 craige check Lock calls for WASSTILLDRAWING; * test for valid flags * 01-aug-95 craige hold win16 early to keep busy bit test valid * 01-aug-95 toddla added DD16_Exclude and DD16_Unexclude * 04-aug-95 craige use InternalLock/Unlock * 06-aug-95 craige do DD16_Exclude before lock, unexclude after unlock * 10-aug-95 toddla added DDBLT_WAIT and DDBLTFAST_WAIT flags * 12-aug-95 craige use_full_lock parm for MoveToSystemMemory and * ChangeToSoftwareColorKey * 23-aug-95 craige wasn't unlocking surfaces or unexcluding cursor on * a few error conditions * 16-sep-95 craige bug 1175: set return code if NULL clip list * 02-jan-96 kylej handle new interface structures * 04-jan-96 colinmc added DDBLT_DEPTHFILL for clearing Z-buffers * 01-feb-96 jeffno NT: pass user-mode ptrs to vram surfaces to HEL * in Blt and BltFast * 12-feb-96 colinmc Surface lost flag moved from global to local object * 29-feb-96 kylej Enable System->Video bltting * 03-mar-96 colinmc Fixed a couple of nasty bugs causing blts to system * memory to be done by hardware * 21-mar-96 colinmc Bug 14011: Insufficient parameter validation on * BltFast * 26-mar-96 jeffno Handle visrgn changes under NT * 20-apr-96 colinmc Fixed problem with releasePageLocks spinning on * busy bit * 23-apr-96 kylej Bug 10196: Added check for software dest blt * 17-may-96 craige bug 21499: perf problems with BltFast * 14-jun-96 kylej NT Bug 38227: Internal lock was not correctly reporting * when the visrgn had changed. * 13-aug-96 colinmc Bug 3194: Blitting through a clipper without * DDBLT_WAIT could cause infinite loop in app. * 01-oct-96 ketand Perf for clipped blits * 21-jan-97 ketand Fix rectangle checking for multi-mon systems. Clip blits to * the destination surface if a clipper is used. * 31-jan-97 colinmc Bug 5457: Fixed Win16 lock problem causing hang * with mutliple AMovie instances on old cards * 03-mar-97 jeffno Bug #5061: Trashing fpVidMem on blt. * 08-mar-97 colinmc Support for DMA style AGP parts * 11-mar-97 jeffno Asynchronous DMA support * 24-mar-97 jeffno Optimized Surfaces * ***************************************************************************/ #include "ddrawpr.h" #define DONE_BUSY() \ (*pdflags) &= ~BUSY; \ #define LEAVE_BOTH_NOBUSY() \ { if(pdflags)\ (*pdflags) &= ~BUSY; \ } \ LEAVE_BOTH(); #define DONE_LOCKS() \ if( dest_lock_taken ) \ { \ if (subrect_lock_taken) \ { \ InternalUnlock( this_dest_lcl, NULL, &subrect_lock_rect, 0); \ subrect_lock_taken = FALSE; \ } \ else \ { \ InternalUnlock( this_dest_lcl,NULL,NULL,0 ); \ } \ dest_lock_taken = FALSE; \ } \ if( src_lock_taken && this_src_lcl) \ { \ InternalUnlock( this_src_lcl,NULL,NULL,0 ); \ src_lock_taken = FALSE; \ } #undef DPF_MODNAME #define DPF_MODNAME "BltFast" DWORD dwSVBHack; // turns off SEH for bltfast #define FASTFAST typedef struct _bltcaps { LPDWORD dwCaps; LPDWORD dwFXCaps; LPDWORD dwCKeyCaps; LPDWORD dwRops; LPDWORD dwHELCaps; LPDWORD dwHELFXCaps; LPDWORD dwHELCKeyCaps; LPDWORD dwHELRops; LPDWORD dwBothCaps; LPDWORD dwBothFXCaps; LPDWORD dwBothCKeyCaps; LPDWORD dwBothRops; BOOL bHALSeesSysmem; BOOL bSourcePagelockTaken; BOOL bDestPagelockTaken; } BLTCAPS, *LPBLTCAPS; void initBltCaps( DWORD dwDstCaps, DWORD dwDstFlags, DWORD dwSrcCaps, LPDDRAWI_DIRECTDRAW_GBL pdrv, LPBLTCAPS lpbc, LPBOOL helonly ) { #ifdef WINNT BOOL bPrimaryHack = FALSE; #endif if (lpbc) { /* * Not really expecting lpbc to be null, but this is late and I'm paranoid */ lpbc->bSourcePagelockTaken = FALSE; lpbc->bDestPagelockTaken = FALSE; } #ifdef WINNT // On NT, the kernel needs to handle blts from system to the primary // surface, otherwise the sprite stuff won't work if( ( dwDstFlags & DDRAWISURFGBL_ISGDISURFACE ) && ( dwDstCaps & DDSCAPS_VIDEOMEMORY ) && ( dwSrcCaps & DDSCAPS_SYSTEMMEMORY ) && !(pdrv->ddCaps.dwCaps & DDCAPS_CANBLTSYSMEM) && ( pdrv->ddCaps.dwCaps & DDCAPS_BLT ) ) { bPrimaryHack = TRUE; pdrv->ddCaps.dwCaps |= DDCAPS_CANBLTSYSMEM; } #endif if( ( ( dwSrcCaps & DDSCAPS_NONLOCALVIDMEM ) || ( dwDstCaps & DDSCAPS_NONLOCALVIDMEM ) ) && ( pdrv->ddCaps.dwCaps2 & DDCAPS2_NONLOCALVIDMEMCAPS ) ) { /* * At least one of the surfaces is non local and the device exports * different capabilities for non-local video memory. If this is non-local * to local transfer then check the appropriate caps. Otherwise force * emulation. */ if( ( dwSrcCaps & DDSCAPS_NONLOCALVIDMEM ) && ( dwDstCaps & DDSCAPS_LOCALVIDMEM ) ) { /* * Non-local to local video memory transfer. */ DDASSERT( NULL != pdrv->lpddNLVCaps ); DDASSERT( NULL != pdrv->lpddNLVHELCaps ); DDASSERT( NULL != pdrv->lpddNLVBothCaps ); /* * We have specific caps. Use them */ lpbc->dwCaps = &(pdrv->lpddNLVCaps->dwNLVBCaps); lpbc->dwFXCaps = &(pdrv->lpddNLVCaps->dwNLVBFXCaps); lpbc->dwCKeyCaps = &(pdrv->lpddNLVCaps->dwNLVBCKeyCaps); lpbc->dwRops = pdrv->lpddNLVCaps->dwNLVBRops; lpbc->dwHELCaps = &(pdrv->lpddNLVHELCaps->dwNLVBCaps); lpbc->dwHELFXCaps = &(pdrv->lpddNLVHELCaps->dwNLVBFXCaps); lpbc->dwHELCKeyCaps = &(pdrv->lpddNLVHELCaps->dwNLVBCKeyCaps); lpbc->dwHELRops = pdrv->lpddNLVHELCaps->dwNLVBRops; lpbc->dwBothCaps = &(pdrv->lpddNLVBothCaps->dwNLVBCaps); lpbc->dwBothFXCaps = &(pdrv->lpddNLVBothCaps->dwNLVBFXCaps); lpbc->dwBothCKeyCaps = &(pdrv->lpddNLVBothCaps->dwNLVBCKeyCaps); lpbc->dwBothRops = pdrv->lpddNLVBothCaps->dwNLVBRops; lpbc->bHALSeesSysmem = FALSE; return; } else if( ( dwSrcCaps & DDSCAPS_SYSTEMMEMORY ) && ( dwDstCaps & DDSCAPS_NONLOCALVIDMEM ) && ( pdrv->ddCaps.dwCaps2 & DDCAPS2_SYSTONONLOCAL_AS_SYSTOLOCAL ) ) { /* * See the definition of the above caps bit in ddrawp.h for more details */ DPF(4,"System to non-local Blt is a candidate for passing to driver."); lpbc->dwCaps = &(pdrv->ddCaps.dwSVBCaps); lpbc->dwFXCaps = &(pdrv->ddCaps.dwSVBFXCaps); lpbc->dwCKeyCaps = &(pdrv->ddCaps.dwSVBCKeyCaps); lpbc->dwRops = pdrv->ddCaps.dwSVBRops; lpbc->dwHELCaps = &(pdrv->ddHELCaps.dwSVBCaps); lpbc->dwHELFXCaps = &(pdrv->ddHELCaps.dwSVBFXCaps); lpbc->dwHELCKeyCaps = &(pdrv->ddHELCaps.dwSVBCKeyCaps); lpbc->dwHELRops = pdrv->ddHELCaps.dwSVBRops; lpbc->dwBothCaps = &(pdrv->ddBothCaps.dwSVBCaps); lpbc->dwBothFXCaps = &(pdrv->ddBothCaps.dwSVBFXCaps); lpbc->dwBothCKeyCaps = &(pdrv->ddBothCaps.dwSVBCKeyCaps); lpbc->dwBothRops = pdrv->ddBothCaps.dwSVBRops; lpbc->bHALSeesSysmem = TRUE; return; } else { /* * Non-local to non-local or local to non-local transfer. Force emulation. */ *helonly = TRUE; } } if( !(pdrv->ddCaps.dwCaps & DDCAPS_CANBLTSYSMEM) ) { if( (dwSrcCaps & DDSCAPS_SYSTEMMEMORY) || (dwDstCaps & DDSCAPS_SYSTEMMEMORY) ) { *helonly = TRUE; } } if( ( (dwSrcCaps & DDSCAPS_VIDEOMEMORY) && (dwDstCaps & DDSCAPS_VIDEOMEMORY) ) || !( pdrv->ddCaps.dwCaps & DDCAPS_CANBLTSYSMEM ) ) { lpbc->dwCaps = &(pdrv->ddCaps.dwCaps); lpbc->dwFXCaps = &(pdrv->ddCaps.dwFXCaps); lpbc->dwCKeyCaps = &(pdrv->ddCaps.dwCKeyCaps); lpbc->dwRops = pdrv->ddCaps.dwRops; lpbc->dwHELCaps = &(pdrv->ddHELCaps.dwCaps); lpbc->dwHELFXCaps = &(pdrv->ddHELCaps.dwFXCaps); lpbc->dwHELCKeyCaps = &(pdrv->ddHELCaps.dwCKeyCaps); lpbc->dwHELRops = pdrv->ddHELCaps.dwRops; lpbc->dwBothCaps = &(pdrv->ddBothCaps.dwCaps); lpbc->dwBothFXCaps = &(pdrv->ddBothCaps.dwFXCaps); lpbc->dwBothCKeyCaps = &(pdrv->ddBothCaps.dwCKeyCaps); lpbc->dwBothRops = pdrv->ddBothCaps.dwRops; lpbc->bHALSeesSysmem = FALSE; } else if( (dwSrcCaps & DDSCAPS_SYSTEMMEMORY) && (dwDstCaps & DDSCAPS_VIDEOMEMORY) ) { lpbc->dwCaps = &(pdrv->ddCaps.dwSVBCaps); lpbc->dwFXCaps = &(pdrv->ddCaps.dwSVBFXCaps); lpbc->dwCKeyCaps = &(pdrv->ddCaps.dwSVBCKeyCaps); lpbc->dwRops = pdrv->ddCaps.dwSVBRops; lpbc->dwHELCaps = &(pdrv->ddHELCaps.dwSVBCaps); lpbc->dwHELFXCaps = &(pdrv->ddHELCaps.dwSVBFXCaps); lpbc->dwHELCKeyCaps = &(pdrv->ddHELCaps.dwSVBCKeyCaps); lpbc->dwHELRops = pdrv->ddHELCaps.dwSVBRops; lpbc->dwBothCaps = &(pdrv->ddBothCaps.dwSVBCaps); lpbc->dwBothFXCaps = &(pdrv->ddBothCaps.dwSVBFXCaps); lpbc->dwBothCKeyCaps = &(pdrv->ddBothCaps.dwSVBCKeyCaps); lpbc->dwBothRops = pdrv->ddBothCaps.dwSVBRops; lpbc->bHALSeesSysmem = TRUE; } else if( (dwSrcCaps & DDSCAPS_VIDEOMEMORY) && (dwDstCaps & DDSCAPS_SYSTEMMEMORY) ) { lpbc->dwCaps = &(pdrv->ddCaps.dwVSBCaps); lpbc->dwFXCaps = &(pdrv->ddCaps.dwVSBFXCaps); lpbc->dwCKeyCaps = &(pdrv->ddCaps.dwVSBCKeyCaps); lpbc->dwRops = pdrv->ddCaps.dwVSBRops; lpbc->dwHELCaps = &(pdrv->ddHELCaps.dwVSBCaps); lpbc->dwHELFXCaps = &(pdrv->ddHELCaps.dwVSBFXCaps); lpbc->dwHELCKeyCaps = &(pdrv->ddHELCaps.dwVSBCKeyCaps); lpbc->dwHELRops = pdrv->ddHELCaps.dwVSBRops; lpbc->dwBothCaps = &(pdrv->ddBothCaps.dwVSBCaps); lpbc->dwBothFXCaps = &(pdrv->ddBothCaps.dwVSBFXCaps); lpbc->dwBothCKeyCaps = &(pdrv->ddBothCaps.dwVSBCKeyCaps); lpbc->dwBothRops = pdrv->ddBothCaps.dwVSBRops; lpbc->bHALSeesSysmem = TRUE; } else if( (dwSrcCaps & DDSCAPS_SYSTEMMEMORY) && (dwDstCaps & DDSCAPS_SYSTEMMEMORY) ) { lpbc->dwCaps = &(pdrv->ddCaps.dwSSBCaps); lpbc->dwFXCaps = &(pdrv->ddCaps.dwSSBFXCaps); lpbc->dwCKeyCaps = &(pdrv->ddCaps.dwSSBCKeyCaps); lpbc->dwRops = pdrv->ddCaps.dwSSBRops; lpbc->dwHELCaps = &(pdrv->ddHELCaps.dwSSBCaps); lpbc->dwHELFXCaps = &(pdrv->ddHELCaps.dwSSBFXCaps); lpbc->dwHELCKeyCaps = &(pdrv->ddHELCaps.dwSSBCKeyCaps); lpbc->dwHELRops = pdrv->ddHELCaps.dwSSBRops; lpbc->dwBothCaps = &(pdrv->ddBothCaps.dwSSBCaps); lpbc->dwBothFXCaps = &(pdrv->ddBothCaps.dwSSBFXCaps); lpbc->dwBothCKeyCaps = &(pdrv->ddBothCaps.dwSSBCKeyCaps); lpbc->dwBothRops = pdrv->ddBothCaps.dwSSBRops; lpbc->bHALSeesSysmem = TRUE; } #ifdef WINNT if( bPrimaryHack ) { pdrv->ddCaps.dwCaps &= ~DDCAPS_CANBLTSYSMEM; dwSVBHack = DDCAPS_BLT; lpbc->dwCaps = &dwSVBHack; lpbc->dwBothCaps = &dwSVBHack; } #endif } __inline void initBltCapsFast( DWORD dwDstCaps, DWORD dwSrcCaps, LPDDRAWI_DIRECTDRAW_GBL pdrv, LPBLTCAPS lpbc ) { if (lpbc) { /* * Not really expecting lpbc to be null, but this is late and I'm paranoid */ lpbc->bSourcePagelockTaken = FALSE; lpbc->bDestPagelockTaken = FALSE; } if( ( ( dwSrcCaps & DDSCAPS_NONLOCALVIDMEM ) && ( dwDstCaps && DDSCAPS_LOCALVIDMEM ) ) && ( pdrv->ddCaps.dwCaps2 & DDCAPS2_NONLOCALVIDMEMCAPS ) ) { DDASSERT( NULL != pdrv->lpddNLVCaps ); lpbc->dwCaps = &(pdrv->lpddNLVCaps->dwNLVBCaps); lpbc->dwHELCaps = &(pdrv->lpddNLVHELCaps->dwNLVBCaps); lpbc->dwBothCaps = &(pdrv->lpddNLVBothCaps->dwNLVBCaps); lpbc->dwCKeyCaps = &(pdrv->lpddNLVCaps->dwNLVBCKeyCaps); lpbc->dwHELCKeyCaps = &(pdrv->lpddNLVHELCaps->dwNLVBCKeyCaps); lpbc->dwBothCKeyCaps = &(pdrv->lpddNLVBothCaps->dwNLVBCKeyCaps); lpbc->bHALSeesSysmem = FALSE; } else if( ( (dwSrcCaps & DDSCAPS_VIDEOMEMORY) && (dwDstCaps & DDSCAPS_VIDEOMEMORY) ) || !( pdrv->ddCaps.dwCaps & DDCAPS_CANBLTSYSMEM ) ) { lpbc->dwCaps = &(pdrv->ddCaps.dwCaps); lpbc->dwHELCaps = &(pdrv->ddHELCaps.dwCaps); lpbc->dwBothCaps = &(pdrv->ddBothCaps.dwCaps); lpbc->dwCKeyCaps = &(pdrv->ddCaps.dwCKeyCaps); lpbc->dwHELCKeyCaps = &(pdrv->ddHELCaps.dwCKeyCaps); lpbc->dwBothCKeyCaps = &(pdrv->ddBothCaps.dwCKeyCaps); lpbc->bHALSeesSysmem = FALSE; } else if( (dwSrcCaps & DDSCAPS_SYSTEMMEMORY) && (dwDstCaps & DDSCAPS_VIDEOMEMORY) ) { lpbc->dwCaps = &(pdrv->ddCaps.dwSVBCaps); lpbc->dwHELCaps = &(pdrv->ddHELCaps.dwSVBCaps); lpbc->dwBothCaps = &(pdrv->ddBothCaps.dwSVBCaps); lpbc->dwCKeyCaps = &(pdrv->ddCaps.dwSVBCKeyCaps); lpbc->dwHELCKeyCaps = &(pdrv->ddHELCaps.dwSVBCKeyCaps); lpbc->dwBothCKeyCaps = &(pdrv->ddBothCaps.dwSVBCKeyCaps); lpbc->bHALSeesSysmem = TRUE; } else if( (dwSrcCaps & DDSCAPS_VIDEOMEMORY) && (dwDstCaps & DDSCAPS_SYSTEMMEMORY) ) { lpbc->dwCaps = &(pdrv->ddCaps.dwVSBCaps); lpbc->dwHELCaps = &(pdrv->ddHELCaps.dwVSBCaps); lpbc->dwBothCaps = &(pdrv->ddBothCaps.dwVSBCaps); lpbc->dwCKeyCaps = &(pdrv->ddCaps.dwVSBCKeyCaps); lpbc->dwHELCKeyCaps = &(pdrv->ddHELCaps.dwVSBCKeyCaps); lpbc->dwBothCKeyCaps = &(pdrv->ddBothCaps.dwVSBCKeyCaps); lpbc->bHALSeesSysmem = TRUE; } else if( (dwSrcCaps & DDSCAPS_SYSTEMMEMORY) && (dwDstCaps & DDSCAPS_SYSTEMMEMORY) ) { lpbc->dwCaps = &(pdrv->ddCaps.dwSSBCaps); lpbc->dwHELCaps = &(pdrv->ddHELCaps.dwSSBCaps); lpbc->dwBothCaps = &(pdrv->ddBothCaps.dwSSBCaps); lpbc->dwCKeyCaps = &(pdrv->ddCaps.dwSSBCKeyCaps); lpbc->dwHELCKeyCaps = &(pdrv->ddHELCaps.dwSSBCKeyCaps); lpbc->dwBothCKeyCaps = &(pdrv->ddBothCaps.dwSSBCKeyCaps); lpbc->bHALSeesSysmem = TRUE; } } /* * OverlapsDevices * * This function checks for Blts that are on the destop, but not entirely * on the device. When found, we will emulate the Blt (punting to GDI). */ BOOL OverlapsDevices( LPDDRAWI_DDRAWSURFACE_LCL lpSurf_lcl, LPRECT lpRect ) { LPDDRAWI_DIRECTDRAW_GBL lpGbl; RECT rect; lpGbl = lpSurf_lcl->lpSurfMore->lpDD_lcl->lpGbl; /* * If the device was explicitly specified, assume that they know * what they're doing. */ if( lpSurf_lcl->lpSurfMore->lpDD_lcl->dwLocalFlags & DDRAWILCL_EXPLICITMONITOR ) { return FALSE; } /* * Do a real quick check w/o accounting for the clipper */ if( ( lpRect->top < lpGbl->rectDevice.top ) || ( lpRect->left < lpGbl->rectDevice.left ) || ( lpRect->right > lpGbl->rectDevice.right ) || ( lpRect->bottom > lpGbl->rectDevice.bottom ) ) { /* * It may only be that part of the rect is off of the desktop, * in which case we don't neccesarily need to drop to emulation. */ IntersectRect( &rect, lpRect, &lpGbl->rectDesktop ); if( ( rect.top < lpGbl->rectDevice.top ) || ( rect.left < lpGbl->rectDevice.left ) || ( rect.right > lpGbl->rectDevice.right ) || ( rect.bottom > lpGbl->rectDevice.bottom ) ) { return TRUE; } } return FALSE; } /* * WaitForDriverToFinishWithSurface * * This function waits for the hardware driver to report that it has finished * operating on the given surface. We should only call this function if the * surface was a system memory surface involved in a DMA/busmastering transfer. * Note this function clears the DDRAWISURFGBL_HARDWAREOPSTARTED flags (both * of them). */ void WaitForDriverToFinishWithSurface(LPDDRAWI_DIRECTDRAW_LCL pdrv_lcl, LPDDRAWI_DDRAWSURFACE_LCL this_lcl) { HRESULT hr; #ifdef DEBUG DWORD dwStart; BOOL bSentMessage=FALSE; dwStart = GetTickCount(); #endif DDASSERT( this_lcl->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY ); DPF(4,"Waiting for driver to finish with %08x",this_lcl->lpGbl); do { hr = InternalGetBltStatus( pdrv_lcl , this_lcl , DDGBS_ISBLTDONE ); #ifdef DEBUG if ( GetTickCount() -dwStart >= 10000 ) { if (!bSentMessage) { bSentMessage = TRUE; DPF_ERR("Driver reports operation still pending on surface after 5s! Driver error!"); } } #endif } while (hr == DDERR_WASSTILLDRAWING); DDASSERT(hr == DD_OK); DPF(5,B,"Driver finished with that surface"); this_lcl->lpGbl->dwGlobalFlags &= ~DDRAWISURFGBL_HARDWAREOPSTARTED; } /* * DD_Surface_BltFast * * Bit Blt from one surface to another FAST */ HRESULT DDAPI DD_Surface_BltFast( LPDIRECTDRAWSURFACE lpDDDestSurface, DWORD dwX, DWORD dwY, LPDIRECTDRAWSURFACE lpDDSrcSurface, LPRECT lpSrcRect, DWORD dwTrans ) { LPDDRAWI_DIRECTDRAW_LCL pdrv_lcl; LPDDRAWI_DIRECTDRAW_GBL pdrv; LPDDRAWI_DDRAWSURFACE_INT this_src_int; LPDDRAWI_DDRAWSURFACE_INT this_dest_int; LPDDRAWI_DDRAWSURFACE_LCL this_src_lcl; LPDDRAWI_DDRAWSURFACE_LCL this_dest_lcl; LPDDRAWI_DDRAWSURFACE_GBL this_src; LPDDRAWI_DDRAWSURFACE_GBL this_dest; DDHAL_BLTDATA bd; DWORD rc; LPDDHALSURFCB_BLT bltfn; BOOL halonly; BOOL helonly; BOOL gdiblt; int src_height; int src_width; BOOL dest_lock_taken=FALSE; BOOL src_lock_taken=FALSE; LPVOID dest_bits; LPVOID src_bits; HRESULT ddrval; BLTCAPS bc; LPBLTCAPS lpbc = &bc; LPWORD pdflags=0; DWORD dwSourceLockFlags=0; DWORD dwDestLockFlags=0; BOOL subrect_lock_taken = FALSE; RECT subrect_lock_rect; ENTER_BOTH(); DPF(2,A,"ENTERAPI: DD_Surface_BltFast"); /* DPF_ENTERAPI(lpDDDestSurface); */ /* * prepare parameters. An exception here is considered a bad parameter */ #ifndef FASTFAST TRY #endif { ZeroMemory(&bd, sizeof(bd)); // initialize to zero this_dest_int = (LPDDRAWI_DDRAWSURFACE_INT) lpDDDestSurface; if( !VALID_DIRECTDRAWSURFACE_PTR( this_dest_int ) ) { LEAVE_BOTH() return DDERR_INVALIDOBJECT; } this_dest_lcl = this_dest_int->lpLcl; this_dest = this_dest_lcl->lpGbl; if( SURFACE_LOST( this_dest_lcl ) ) { DPF( 1, "Destination (%08lx) is lost", this_dest_int ); LEAVE_BOTH(); return DDERR_SURFACELOST; } this_src_int = (LPDDRAWI_DDRAWSURFACE_INT) lpDDSrcSurface; if( !VALID_DIRECTDRAWSURFACE_PTR( this_src_int ) ) { LEAVE_BOTH(); return DDERR_INVALIDOBJECT; } this_src_lcl = this_src_int->lpLcl; this_src = this_src_lcl->lpGbl; if( SURFACE_LOST( this_src_lcl ) ) { DPF( 1, "Source (%08lx) is lost", this_src_int ); LEAVE_BOTH(); return DDERR_SURFACELOST; } if( lpSrcRect != NULL ) { if( !VALID_RECT_PTR( lpSrcRect ) ) { LEAVE_BOTH() return DDERR_INVALIDPARAMS; } } if( dwTrans & ~DDBLTFAST_VALID ) { DPF_ERR( "Invalid flags") ; LEAVE_BOTH(); return DDERR_INVALIDPARAMS; } // // If either surface is optimized, quit // if (this_src_lcl->ddsCaps.dwCaps & DDSCAPS_OPTIMIZED) { DPF_ERR( "Can't blt from an optimized surface") ; LEAVE_BOTH(); return DDERR_INVALIDPARAMS; } if (this_dest_lcl->ddsCaps.dwCaps & DDSCAPS_OPTIMIZED) { DPF_ERR( "Can't blt to optimized surfaces") ; LEAVE_BOTH(); return DDERR_INVALIDPARAMS; } /* * BEHAVIOUR CHANGE FOR DX5 * * We do not allow bltting between surfaces created with different DirectDraw * objects. */ if (this_dest_lcl->lpSurfMore->lpDD_lcl->lpGbl != this_src_lcl->lpSurfMore->lpDD_lcl->lpGbl) { if ((this_dest_lcl->lpSurfMore->lpDD_lcl->lpGbl->dwFlags & DDRAWI_DISPLAYDRV) && (this_src_lcl->lpSurfMore->lpDD_lcl->lpGbl->dwFlags & DDRAWI_DISPLAYDRV)) { DPF_ERR("Can't blt surfaces between different direct draw devices"); LEAVE_BOTH(); return DDERR_DEVICEDOESNTOWNSURFACE; } } pdrv = this_dest->lpDD; pdrv_lcl = this_dest_lcl->lpSurfMore->lpDD_lcl; #ifdef WINNT // Update DDraw handle in driver GBL object. pdrv->hDD = pdrv_lcl->hDD; #endif /* * DX5 or greater drivers get to know about read/write only locks * Note that dwDestFlags may later be zeroed for dest color key. * We pass read+write if the blt goes to/from the same buffer, of course. */ if (pdrv->dwInternal1 >= 0x500 && this_src != this_dest ) { dwSourceLockFlags = DDLOCK_READONLY; dwDestLockFlags = DDLOCK_WRITEONLY; } #ifdef USE_ALIAS if( pdrv->dwBusyDueToAliasedLock > 0 ) { /* * Aliased locks (the ones that don't take the Win16 lock) don't * set the busy bit either (it can't or USER get's very confused). * However, we must prevent blits happening via DirectDraw as * otherwise we get into the old host talking to VRAM while * blitter does at the same time. Bad. So fail if there is an * outstanding aliased lock just as if the BUST bit had been * set. */ DPF_ERR( "Graphics adapter is busy (due to a DirectDraw lock)" ); LEAVE_BOTH(); return DDERR_SURFACEBUSY; } #endif /* USE_ALIAS */ /* * Behavior change: In DX7, the default is to wait unless DDFASTBLT_DONOTWAIT=1. * In earlier releases, the default was to NOT wait unless DDFASTBLT_WAIT=1. * (The DDFASTBLT_DONOTWAIT flag was not defined until the DX7 release.) */ if (!LOWERTHANSURFACE7(this_dest_int)) { if (dwTrans & DDBLTFAST_DONOTWAIT) { if (dwTrans & DDBLTFAST_WAIT) { DPF_ERR( "WAIT and DONOTWAIT flags are mutually exclusive" ); LEAVE_BOTH(); return DDERR_INVALIDPARAMS; } } else { dwTrans |= DDBLTFAST_WAIT; } } FlushD3DStates(this_src_lcl); // Need to flush src because it could be a rendertarget FlushD3DStates(this_dest_lcl); // Test and set the busy bit. If it was already set, bail. { BOOL isbusy = 0; pdflags = pdrv->lpwPDeviceFlags; #ifdef WIN95 _asm { mov eax, pdflags bts word ptr [eax], BUSY_BIT adc byte ptr isbusy,0 } #else isbusy -= (InterlockedExchange((LPDWORD)pdflags, *((LPDWORD)pdflags) | (1<ddsCaps.dwCaps & DDSCAPS_VIDEOPORT ) { LPDDRAWI_DDVIDEOPORT_INT lpVideoPort; LPDDRAWI_DDVIDEOPORT_LCL lpVideoPort_lcl; // Look at all video ports to see if any of them recently // flipped from this surface. lpVideoPort = pdrv->dvpList; while( NULL != lpVideoPort ) { lpVideoPort_lcl = lpVideoPort->lpLcl; if( lpVideoPort_lcl->fpLastFlip == this_src->fpVidMem ) { // This can potentially tear - check the flip status LPDDHALVPORTCB_GETFLIPSTATUS pfn; DDHAL_GETVPORTFLIPSTATUSDATA GetFlipData; LPDDRAWI_DIRECTDRAW_LCL pdrv_lcl; pdrv_lcl = this_src_lcl->lpSurfMore->lpDD_lcl; pfn = pdrv_lcl->lpDDCB->HALDDVideoPort.GetVideoPortFlipStatus; if( pfn != NULL ) // Will simply tear if function not supproted { GetFlipData.lpDD = pdrv_lcl; GetFlipData.fpSurface = this_src->fpVidMem; KeepTrying: rc = DDHAL_DRIVER_NOTHANDLED; DOHALCALL_NOWIN16( GetVideoPortFlipStatus, pfn, GetFlipData, rc, 0 ); if( ( DDHAL_DRIVER_HANDLED == rc ) && ( DDERR_WASSTILLDRAWING == GetFlipData.ddRVal ) ) { if( dwTrans & DDBLTFAST_WAIT) { goto KeepTrying; } LEAVE_BOTH_NOBUSY(); return DDERR_WASSTILLDRAWING; } } } lpVideoPort = lpVideoPort->lpLink; } } RESTART_BLTFAST: /* * Remove any cached RLE stuff for source surface */ if( this_dest_lcl->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY ) { extern void FreeRleData(LPDDRAWI_DDRAWSURFACE_LCL psurf); //in fasthel.c FreeRleData( this_dest_lcl ); } BUMP_SURFACE_STAMP(this_dest); /* * is either surface locked? */ if( this_src->dwUsageCount > 0 || this_dest->dwUsageCount > 0 ) { DPF_ERR( "Surface is locked" ); LEAVE_BOTH_NOBUSY() return DDERR_SURFACEBUSY; } /* * It is possible this function could be called in the middle * of a mode, in which case we could trash the frame buffer. * To avoid regression, we will simply succeed the call without * actually doing anything. */ if( ( pdrv->dwFlags & DDRAWI_CHANGINGMODE ) && !( this_dest_lcl->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY ) ) { LEAVE_BOTH_NOBUSY() return DD_OK; } // no restrictions yet halonly = FALSE; helonly = FALSE; gdiblt = FALSE; // initialize the blit caps according to the surface types initBltCapsFast( this_dest_lcl->ddsCaps.dwCaps, this_src_lcl->ddsCaps.dwCaps, pdrv, lpbc ); if( !( pdrv->ddCaps.dwCaps & DDCAPS_CANBLTSYSMEM ) && ( ( this_dest_lcl->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY ) || ( this_src_lcl->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY ) ) ) { lpbc->bHALSeesSysmem = FALSE; helonly = TRUE; #ifdef WINNT // On NT, the kernel needs to handle blts from system to the primary // surface, otherwise the sprite stuff won't work if( ( this_dest->dwGlobalFlags & DDRAWISURFGBL_ISGDISURFACE ) && ( this_dest_lcl->ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY ) && ( this_src_lcl->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY ) ) { // However, there are several cases that the kernel // emulation will not handle, so filter these out: if (((dwTrans & DDBLTFAST_COLORKEY_MASK) == 0) && doPixelFormatsMatch(&this_src->ddpfSurface, &this_dest->lpDD->vmiData.ddpfDisplay)) { lpbc->bHALSeesSysmem = TRUE; helonly = FALSE; } } #endif } if( ( this_dest_lcl->ddsCaps.dwCaps & DDSCAPS_NONLOCALVIDMEM ) && ( pdrv->ddCaps.dwCaps2 & DDCAPS2_NONLOCALVIDMEMCAPS ) ) { /* * All blits where the destination is non-local are emulated, * unless its sys->NL, in which case we let the driver see it * if it set DDCAPS2_SYSTONONLOCAL_AS_SYSTOLOCAL. * initBltFastCaps() set up the correct caps for emulation as * both surfaces are video memory so all we need to do is to force * on emulation */ if (! ((this_src_lcl->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY) && (pdrv->ddCaps.dwCaps2 & DDCAPS2_SYSTONONLOCAL_AS_SYSTOLOCAL )) ) { lpbc->bHALSeesSysmem = FALSE; helonly = TRUE; } } /* * check for HEL composition buffer */ if( (this_dest_lcl->dwFlags & DDRAWISURF_HELCB) || (this_src_lcl->dwFlags & DDRAWISURF_HELCB) ) { lpbc->bHALSeesSysmem = FALSE; helonly = TRUE; } /* * does the driver even allow bltting? */ if( !(*(lpbc->dwBothCaps) & DDCAPS_BLT) ) { BOOL fail; fail = FALSE; GETFAILCODEBLT( *(lpbc->dwCaps), *(lpbc->dwHELCaps), halonly, helonly, DDCAPS_BLT ); if( fail ) { DPF_ERR( "Blt not supported" ); LEAVE_BOTH_NOBUSY() return DDERR_NOBLTHW; } } /* * Check for special cases involving FOURCC surfaces: * -- Copy blits between surfaces with identical FOURCC formats * -- Compression/decompression of DXT* compressed textures */ { DWORD dwDest4CC = 0; DWORD dwSrc4CC = 0; /* * Does either the source or dest surface have a FOURCC format? */ if ((this_dest_lcl->dwFlags & DDRAWISURF_HASPIXELFORMAT) && (this_dest->ddpfSurface.dwFlags & DDPF_FOURCC)) { dwDest4CC = this_dest->ddpfSurface.dwFourCC; // dest FOURCC format } if ((this_src_lcl->dwFlags & DDRAWISURF_HASPIXELFORMAT) && (this_src->ddpfSurface.dwFlags & DDPF_FOURCC)) { dwSrc4CC = this_src->ddpfSurface.dwFourCC; // source FOURCC format } if (dwDest4CC | dwSrc4CC) { /* * Yes, at least one of the two surfaces has a FOURCC format. * Do the source and dest surfaces have precisely the same * FOURCC format? (If so, this is a FOURCC copy blit.) */ if (dwDest4CC == dwSrc4CC) { // Yes, this is a FOURCC copy blit. Can the driver handle this? if ((pdrv->ddCaps.dwCaps2 & DDCAPS2_COPYFOURCC) == 0) { // The driver cannot handle FOURCC copy blits. helonly = TRUE; } } else { /* * No, the two surfaces have different pixel formats. * Now determine if either surface has a DXT* FOURCC format. * The rule for the Blt API call is that the HEL _ALWAYS_ * performs a blit involving a DXT* source or dest surface. * Hardware acceleration for DXT* blits is available only * with the AlphaBlt API call. We now enforce this rule: */ switch (dwDest4CC) { case MAKEFOURCC('D','X','T','1'): case MAKEFOURCC('D','X','T','2'): case MAKEFOURCC('D','X','T','3'): case MAKEFOURCC('D','X','T','4'): case MAKEFOURCC('D','X','T','5'): // This is a blit to a DXT*-formatted surface. helonly = TRUE; break; default: break; } switch (dwSrc4CC) { case MAKEFOURCC('D','X','T','1'): case MAKEFOURCC('D','X','T','2'): case MAKEFOURCC('D','X','T','3'): case MAKEFOURCC('D','X','T','4'): case MAKEFOURCC('D','X','T','5'): // This is a blit from a DXT*-formatted surface. helonly = TRUE; break; default: break; } } } } /* * get src rectangle */ if( lpSrcRect == NULL ) { MAKE_SURF_RECT( this_src, this_src_lcl, bd.rSrc ); src_height = this_src->wHeight; src_width = this_src->wWidth; } else { bd.rSrc = *(LPRECTL)lpSrcRect; src_height = (bd.rSrc.bottom-bd.rSrc.top); src_width = (bd.rSrc.right-bd.rSrc.left); if( (src_height <= 0) || ((int)src_width <= 0) ) { DPF_ERR( "BLTFAST error. Can't have non-positive height or width for source rect" ); LEAVE_BOTH_NOBUSY(); return DDERR_INVALIDRECT; } // Multi-mon: is this the primary for the desktop? This // is the only case where the upper-left coord of the surface is not // (0,0) if( (this_src->lpDD->dwFlags & DDRAWI_VIRTUALDESKTOP) && (this_src_lcl->ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE) ) { if( (bd.rSrc.left < this_src->lpDD->rectDesktop.left) || (bd.rSrc.top < this_src->lpDD->rectDesktop.top) || (bd.rSrc.right > this_src->lpDD->rectDesktop.right)|| (bd.rSrc.bottom > this_src->lpDD->rectDesktop.bottom) ) { DPF_ERR( "BltFast Source dimensions doesn't fit on Desktop" ); LEAVE_BOTH_NOBUSY(); return DDERR_INVALIDRECT; } if( OverlapsDevices( this_src_lcl, (LPRECT) &bd.rSrc ) ) { helonly = gdiblt = TRUE; } } else { if( (int)bd.rSrc.left < 0 || (int)bd.rSrc.top < 0 || (DWORD)bd.rSrc.bottom > (DWORD)this_src->wHeight || (DWORD)bd.rSrc.right > (DWORD)this_src->wWidth ) { DPF_ERR( "Invalid BltFast Source dimensions" ); LEAVE_BOTH_NOBUSY(); return DDERR_INVALIDRECT; } } } /* * get destination rectangle */ bd.rDest.top = dwY; bd.rDest.left = dwX; bd.rDest.bottom = dwY + (DWORD) src_height; bd.rDest.right = dwX + (DWORD) src_width; /* * Ensure the destination offsets are valid. */ // Multi-mon: is this the primary for the desktop? This // is the only case where the upper-left coord of the surface is not // (0,0) if( (pdrv->dwFlags & DDRAWI_VIRTUALDESKTOP) && (this_dest_lcl->ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE) ) { if( (bd.rDest.left < pdrv->rectDesktop.left) || (bd.rDest.top < pdrv->rectDesktop.top) || (bd.rDest.right > pdrv->rectDesktop.right)|| (bd.rDest.bottom > pdrv->rectDesktop.bottom) ) { DPF_ERR( "BltFast Destination doesn't fit on Desktop And No Clipper was specified" ); LEAVE_BOTH_NOBUSY(); return DDERR_INVALIDRECT; } if( OverlapsDevices( this_dest_lcl, (LPRECT) &bd.rDest ) ) { helonly = gdiblt = TRUE; } } else { if( (int)bd.rDest.left < 0 || (int)bd.rDest.top < 0 || (DWORD)bd.rDest.bottom > (DWORD)this_dest->wHeight || (DWORD)bd.rDest.right > (DWORD)this_dest->wWidth ) { DPF_ERR( "Invalid BltFast destination dimensions" ); LEAVE_BOTH_NOBUSY(); return DDERR_INVALIDRECT; } } /* * transparent? */ switch( dwTrans & DDBLTFAST_COLORKEY_MASK ) { case DDBLTFAST_NOCOLORKEY: bd.dwFlags = DDBLT_ROP; break; case DDBLTFAST_SRCCOLORKEY: if( !(this_src_lcl->dwFlags & DDRAWISURF_HASCKEYSRCBLT) ) { DPF_ERR( "No colorkey on source" ); LEAVE_BOTH_NOBUSY() return DDERR_INVALIDPARAMS; } if( !(*(lpbc->dwBothCKeyCaps) & DDCKEYCAPS_SRCBLT) ) { BOOL fail; fail = FALSE; GETFAILCODEBLT( *(lpbc->dwCKeyCaps), *(lpbc->dwHELCKeyCaps), halonly, helonly, DDCKEYCAPS_SRCBLT ); if( fail ) { DPF_ERR( "KEYSRC specified, not supported" ); LEAVE_BOTH_NOBUSY(); return DDERR_NOCOLORKEYHW; } } bd.bltFX.ddckSrcColorkey = this_src_lcl->ddckCKSrcBlt; bd.dwFlags = DDBLT_ROP | DDBLT_KEYSRCOVERRIDE; break; case DDBLTFAST_DESTCOLORKEY: if( !(this_dest_lcl->dwFlags & DDRAWISURF_HASCKEYDESTBLT) ) { DPF_ERR( "No colorkey on dest" ); LEAVE_BOTH_NOBUSY() return DDERR_INVALIDPARAMS; } if( !(*(lpbc->dwBothCKeyCaps) & DDCKEYCAPS_DESTBLT) ) { BOOL fail; fail = FALSE; GETFAILCODEBLT( *(lpbc->dwCKeyCaps), *(lpbc->dwHELCKeyCaps), halonly, helonly, DDCKEYCAPS_DESTBLT ); if( fail ) { DPF_ERR( "KEYDEST specified, not supported" ); LEAVE_BOTH_NOBUSY(); return DDERR_NOCOLORKEYHW; } } bd.bltFX.ddckDestColorkey = this_dest_lcl->ddckCKDestBlt; bd.dwFlags = DDBLT_ROP | DDBLT_KEYDESTOVERRIDE; dwDestLockFlags = 0; //this means read/write break; } } #ifndef FASTFAST EXCEPT( EXCEPTION_EXECUTE_HANDLER ) { DPF_ERR( "Exception encountered validating parameters" ); LEAVE_BOTH_NOBUSY() return DDERR_INVALIDPARAMS; } #endif /* * do the blt */ #ifndef FASTFAST TRY #endif { bd.bltFX.dwROP = SRCCOPY; bd.lpDDDestSurface = this_dest_lcl; bd.lpDDSrcSurface = this_src_lcl; if( helonly && halonly ) { DPF_ERR( "BLT not supported in software or hardware" ); LEAVE_BOTH_NOBUSY() return DDERR_NOBLTHW; } // Did the mode change since ENTER_DDRAW? #ifdef WINNT if ( DdQueryDisplaySettingsUniqueness() != uDisplaySettingsUnique ) { // mode changed, don't do the blt DPF_ERR( "Mode changed between ENTER_DDRAW and HAL call" ); LEAVE_BOTH_NOBUSY() return DDERR_SURFACELOST; } if( !helonly ) { if (!this_src_lcl->hDDSurface && !CompleteCreateSysmemSurface(this_src_lcl)) { DPF_ERR("Can't blt from SYSTEM surface w/o Kernel Object"); LEAVE_BOTH_NOBUSY() return DDERR_GENERIC; } if (!this_dest_lcl->hDDSurface && !CompleteCreateSysmemSurface(this_dest_lcl)) { DPF_ERR("Can't blt to SYSTEM surface w/o Kernel Object"); LEAVE_BOTH_NOBUSY() return DDERR_GENERIC; } } #endif if( helonly ) // must be HEL call { DPF( 4, "Software FastBlt"); bltfn = pdrv_lcl->lpDDCB->HELDDSurface.Blt; // take locks on vram surfaces if( ( ( this_dest_lcl->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY ) == 0) && ( !gdiblt || !( this_dest_lcl->ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE ) ) ) { while( 1 ) { ddrval = InternalLock( this_dest_lcl, &dest_bits, NULL, dwDestLockFlags ); if( ddrval == DD_OK ) { GET_LPDDRAWSURFACE_GBL_MORE(this_dest)->fpNTAlias = (FLATPTR) dest_bits; break; } if( ddrval == DDERR_WASSTILLDRAWING ) { continue; } LEAVE_BOTH_NOBUSY() return ddrval; } dest_lock_taken = TRUE; } else { /* * If either surface was involved in a hardware op, we need to * probe the driver to see if it's done. NOTE this assumes * that only one driver can be responsible for a system memory * operation. */ if( this_dest->dwGlobalFlags & DDRAWISURFGBL_HARDWAREOPSTARTED ) { WaitForDriverToFinishWithSurface(pdrv_lcl, this_dest_lcl ); } dest_lock_taken = FALSE; } if( (lpDDSrcSurface != lpDDDestSurface) && ( ( this_src_lcl->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY ) == 0) ) { if( MoveToSystemMemory( this_src_int, TRUE, FALSE ) == DD_OK ) { /* * Don't need to check for continuing hardware op here because * MoveToSystemMemory does InternalLock */ src_lock_taken = FALSE; } else { while( 1 ) { ddrval = InternalLock( this_src_lcl, &src_bits, NULL, dwSourceLockFlags ); if( ddrval == DD_OK ) { GET_LPDDRAWSURFACE_GBL_MORE(this_src)->fpNTAlias = (FLATPTR) src_bits; break; } if( ddrval == DDERR_WASSTILLDRAWING ) { continue; } if( dest_lock_taken ) { InternalUnlock( this_dest_lcl, NULL, NULL, 0 ); } LEAVE_BOTH_NOBUSY() return ddrval; } src_lock_taken = TRUE; } } else { if( ( this_src_lcl->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY ) && (this_src->dwGlobalFlags & DDRAWISURFGBL_HARDWAREOPSTARTED ) ) { WaitForDriverToFinishWithSurface(pdrv_lcl, this_src_lcl ); } src_lock_taken = FALSE; } } else { DPF( 4, "Hardware FastBlt"); bltfn = pdrv_lcl->lpDDCB->HALDDSurface.Blt; bd.Blt = pdrv_lcl->lpDDCB->cbDDSurfaceCallbacks.Blt; /* * Take pagelocks if required. * If we take the pagelocks, then the blt becomes synchronous. * A failure taking the pagelocks is pretty catastrophic, so no attempt * is made to fail over to software. */ lpbc->bSourcePagelockTaken=FALSE; lpbc->bDestPagelockTaken=FALSE; if ( lpbc->bHALSeesSysmem ) { /* * If the HAL requires page locks... */ if ( !( pdrv->ddCaps.dwCaps2 & DDCAPS2_NOPAGELOCKREQUIRED ) ) { HRESULT hr; /* * ...then setup to take them if they're not already pagelocked. */ if ( ( this_dest_lcl->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY && this_dest_lcl->lpSurfMore->dwPageLockCount == 0 ) ) { hr = InternalPageLock( this_dest_lcl, pdrv_lcl ); if (FAILED(hr)) { LEAVE_BOTH_NOBUSY() return hr; } else { lpbc->bDestPagelockTaken=TRUE; } } if ( ( this_src_lcl->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY && this_src_lcl->lpSurfMore->dwPageLockCount == 0 )) { hr = InternalPageLock( this_src_lcl, pdrv_lcl ); if (FAILED(hr)) { if (lpbc->bDestPagelockTaken) InternalPageUnlock( this_dest_lcl, pdrv_lcl ); LEAVE_BOTH_NOBUSY() return hr; } else { lpbc->bSourcePagelockTaken=TRUE; } } /* { if (pdrv->dwFlags & DDRAWI_DISPLAYDRV) { lpbc->bHALSeesSysmem = FALSE; helonly = TRUE; } } */ } } } bd.lpDD = pdrv; bd.bltFX.dwSize = sizeof( bd.bltFX ); if( this_dest_lcl->lpDDClipper == NULL ) { bd.IsClipped = FALSE; // no clipping in BltFast try_again: if( helonly ) { // Release busy now or GDI blt will fail DONE_BUSY(); } DOHALCALL_NOWIN16( Blt, bltfn, bd, rc, helonly ); #ifdef WINNT if (rc == DDHAL_DRIVER_HANDLED && bd.ddRVal == DDERR_VISRGNCHANGED) { DPF(5,"Resetting VisRgn for surface %x", this_dest_lcl); DdResetVisrgn(this_dest_lcl, (HWND)0); goto try_again; } #endif if ( (dwTrans & DDBLTFAST_WAIT) && rc == DDHAL_DRIVER_HANDLED && bd.ddRVal == DDERR_WASSTILLDRAWING ) { DPF(4, "Waiting..."); goto try_again; } DPF(5,"Driver returned %08x",bd.ddRVal); /* * Note that the !helonly here is pretty much an assert. * Thought it safer to actually test it, since that is actually what we mean. */ if( !helonly && lpbc->bHALSeesSysmem && rc == DDHAL_DRIVER_HANDLED && bd.ddRVal == DD_OK) { DPF(5,B,"Tagging surfaces %08x and %08x",this_dest,this_src); if( this_dest_lcl->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY) this_dest->dwGlobalFlags |= DDRAWISURFGBL_HARDWAREOPDEST; if( this_src_lcl->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY) this_src->dwGlobalFlags |= DDRAWISURFGBL_HARDWAREOPSOURCE; } } else { DPF_ERR( "Can't clip in BltFast" ); bd.ddRVal = DDERR_BLTFASTCANTCLIP; rc = DDHAL_DRIVER_HANDLED; } if( helonly ) { DONE_LOCKS(); } if( rc != DDHAL_DRIVER_HANDLED ) { /* * did the driver run out of hardware color key resources? */ if( (rc == DDHAL_DRIVER_NOCKEYHW) && ((dwTrans & DDBLTFAST_COLORKEY_MASK) == DDBLTFAST_SRCCOLORKEY) ) { ddrval = ChangeToSoftwareColorKey( this_src_int, FALSE ); if( ddrval == DD_OK ) { halonly = FALSE; helonly = FALSE; if (lpbc->bSourcePagelockTaken) { lpbc->bSourcePagelockTaken = FALSE; InternalPageUnlock(this_src_lcl, pdrv_lcl); } if (lpbc->bDestPagelockTaken) { lpbc->bDestPagelockTaken = FALSE; InternalPageUnlock(this_dest_lcl, pdrv_lcl); } goto RESTART_BLTFAST; } else { bd.ddRVal = DDERR_NOCOLORKEYHW; } } else { bd.ddRVal = DDERR_UNSUPPORTED; } } DONE_BUSY(); /* * Maintain old behaviour for old drivers (which do not export the * GetSysmemBltStatus HAL call) and just spin until they're done. * Any alternative could exercise new code paths in the driver * (e.g. reentered for a DMA operation) * We also spin if we had to take either pagelock ourselves. */ if ( lpbc->bHALSeesSysmem && (NULL == pdrv_lcl->lpDDCB->HALDDMiscellaneous.GetSysmemBltStatus || lpbc->bDestPagelockTaken || lpbc->bSourcePagelockTaken) ) { if( this_src->dwGlobalFlags & DDRAWISURFGBL_HARDWAREOPSTARTED ) { /* * Wait on the destination surface only */ DDASSERT(this_src_lcl->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY); while (DDERR_WASSTILLDRAWING == InternalGetBltStatus(pdrv_lcl, this_dest_lcl, DDGBS_ISBLTDONE)) ; this_src_lcl->lpGbl->dwGlobalFlags &= ~DDRAWISURFGBL_HARDWAREOPSTARTED; this_dest_lcl->lpGbl->dwGlobalFlags &= ~DDRAWISURFGBL_HARDWAREOPSTARTED; } /* * Unpagelock if we took the pagelocks */ if (lpbc->bDestPagelockTaken ) InternalPageUnlock(this_dest_lcl, pdrv_lcl); if (lpbc->bSourcePagelockTaken) InternalPageUnlock(this_src_lcl, pdrv_lcl); } LEAVE_BOTH(); if(IsD3DManaged(this_dest_lcl)) { LPREGIONLIST lpRegionList = this_dest_lcl->lpSurfMore->lpRegionList; MarkDirty(this_dest_lcl); if(lpRegionList->rdh.nCount != NUM_RECTS_IN_REGIONLIST) { lpRegionList->rect[(lpRegionList->rdh.nCount)++] = bd.rDest; lpRegionList->rdh.nRgnSize += sizeof(RECT); if(bd.rDest.left < lpRegionList->rdh.rcBound.left) lpRegionList->rdh.rcBound.left = bd.rDest.left; if(bd.rDest.right > lpRegionList->rdh.rcBound.right) lpRegionList->rdh.rcBound.right = bd.rDest.right; if(bd.rDest.top < lpRegionList->rdh.rcBound.top) lpRegionList->rdh.rcBound.top = bd.rDest.top; if(bd.rDest.bottom > lpRegionList->rdh.rcBound.bottom) lpRegionList->rdh.rcBound.bottom = bd.rDest.bottom; } } return bd.ddRVal; } #ifndef FASTFAST EXCEPT( EXCEPTION_EXECUTE_HANDLER ) { DPF_ERR( "Exception encountered processing blt" ); DONE_LOCKS(); DONE_BUSY(); /* * Maintain old behaviour for old drivers (which do not export the * GetSysmemBltStatus HAL call) and just spin until they're done. * Any alternative could exercise new code paths in the driver * (e.g. reentered for a DMA operation) */ if ( lpbc->bHALSeesSysmem && (NULL == pdrv_lcl->lpDDCB->HALDDMiscellaneous.GetSysmemBltStatus || lpbc->bDestPagelockTaken || lpbc->bSourcePagelockTaken) ) { if( this_src->dwGlobalFlags & DDRAWISURFGBL_HARDWAREOPSTARTED ) { /* * Wait on the destination surface only */ DDASSERT(this_src_lcl->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY); while (DDERR_WASSTILLDRAWING == InternalGetBltStatus(pdrv_lcl, this_dest_lcl, DDGBS_ISBLTDONE)) ; this_src_lcl->lpGbl->dwGlobalFlags &= ~DDRAWISURFGBL_HARDWAREOPSTARTED; this_dest_lcl->lpGbl->dwGlobalFlags &= ~DDRAWISURFGBL_HARDWAREOPSTARTED; } /* * Unpagelock if we took the pagelocks */ if (lpbc->bDestPagelockTaken ) InternalPageUnlock(this_dest_lcl, pdrv_lcl); if (lpbc->bSourcePagelockTaken) InternalPageUnlock(this_src_lcl, pdrv_lcl); } LEAVE_BOTH(); return DDERR_EXCEPTION; } #endif } /* DD_Surface_BltFast */ #undef DPF_MODNAME #define DPF_MODNAME "Blt" /* * ROP table * * tells which ROPS require pattern surfaces and/or source surfaces */ static char cROPTable[] = { 0, // 00 0 BLACKNESS ROP_HAS_SOURCEPATTERN, // 01 DPSoon ROP_HAS_SOURCEPATTERN, // 02 DPSona ROP_HAS_SOURCEPATTERN, // 03 PSon ROP_HAS_SOURCEPATTERN, // 04 SDPona ROP_HAS_PATTERN, // 05 DPon ROP_HAS_SOURCEPATTERN, // 06 PDSxnon ROP_HAS_SOURCEPATTERN, // 07 PDSaon ROP_HAS_SOURCEPATTERN, // 08 SDPnaa ROP_HAS_SOURCEPATTERN, // 09 PDSxon ROP_HAS_PATTERN, // 0A DPna ROP_HAS_SOURCEPATTERN, // 0B PSDnaon ROP_HAS_SOURCEPATTERN, // 0C SPna ROP_HAS_SOURCEPATTERN, // 0D PDSnaon ROP_HAS_SOURCEPATTERN, // 0E PDSonon ROP_HAS_PATTERN, // 0F Pn ROP_HAS_SOURCEPATTERN, // 10 PDSona ROP_HAS_SOURCE, // 11 DSon NOTSRCERASE ROP_HAS_SOURCEPATTERN, // 12 SDPxnon ROP_HAS_SOURCEPATTERN, // 13 SDPaon ROP_HAS_SOURCEPATTERN, // 14 DPSxnon ROP_HAS_SOURCEPATTERN, // 15 DPSaon ROP_HAS_SOURCEPATTERN, // 16 PSDPSanaxx ROP_HAS_SOURCEPATTERN, // 17 SSPxDSxaxn ROP_HAS_SOURCEPATTERN, // 18 SPxPDxa ROP_HAS_SOURCEPATTERN, // 19 SDPSanaxn ROP_HAS_SOURCEPATTERN, // 1A PDSPaox ROP_HAS_SOURCEPATTERN, // 1B SDPSxaxn ROP_HAS_SOURCEPATTERN, // 1C PSDPaox ROP_HAS_SOURCEPATTERN, // 1D DSPDxaxn ROP_HAS_SOURCEPATTERN, // 1E PDSox ROP_HAS_SOURCEPATTERN, // 1F PDSoan ROP_HAS_SOURCEPATTERN, // 20 DPSnaa ROP_HAS_SOURCEPATTERN, // 21 SDPxon ROP_HAS_SOURCE, // 22 DSna ROP_HAS_SOURCEPATTERN, // 23 SPDnaon ROP_HAS_SOURCEPATTERN, // 24 SPxDSxa ROP_HAS_SOURCEPATTERN, // 25 PDSPanaxn ROP_HAS_SOURCEPATTERN, // 26 SDPSaox ROP_HAS_SOURCEPATTERN, // 27 SDPSxnox ROP_HAS_SOURCEPATTERN, // 28 DPSxa ROP_HAS_SOURCEPATTERN, // 29 PSDPSaoxxn ROP_HAS_SOURCEPATTERN, // 2A DPSana ROP_HAS_SOURCEPATTERN, // 2B SSPxPDxaxn ROP_HAS_SOURCEPATTERN, // 2C SPDSoax ROP_HAS_SOURCEPATTERN, // 2D PSDnox ROP_HAS_SOURCEPATTERN, // 2E PSDPxox ROP_HAS_SOURCEPATTERN, // 2F PSDnoan ROP_HAS_SOURCEPATTERN, // 30 PSna ROP_HAS_SOURCEPATTERN, // 31 SDPnaon ROP_HAS_SOURCEPATTERN, // 32 SDPSoox ROP_HAS_SOURCE, // 33 Sn NOTSRCCOPY ROP_HAS_SOURCEPATTERN, // 34 SPDSaox ROP_HAS_SOURCEPATTERN, // 35 SPDSxnox ROP_HAS_SOURCEPATTERN, // 36 SDPox ROP_HAS_SOURCEPATTERN, // 37 SDPoan ROP_HAS_SOURCEPATTERN, // 38 PSDPoax ROP_HAS_SOURCEPATTERN, // 39 SPDnox ROP_HAS_SOURCEPATTERN, // 3A SPDSxox ROP_HAS_SOURCEPATTERN, // 3B SPDnoan ROP_HAS_SOURCEPATTERN, // 3C PSx ROP_HAS_SOURCEPATTERN, // 3D SPDSonox ROP_HAS_SOURCEPATTERN, // 3E SPDSnaox ROP_HAS_SOURCEPATTERN, // 3F PSan ROP_HAS_SOURCEPATTERN, // 40 PSDnaa ROP_HAS_SOURCEPATTERN, // 41 DPSxon ROP_HAS_SOURCEPATTERN, // 42 SDxPDxa ROP_HAS_SOURCEPATTERN, // 43 SPDSanaxn ROP_HAS_SOURCE, // 44 SDna SRCERASE ROP_HAS_SOURCEPATTERN, // 45 DPSnaon ROP_HAS_SOURCEPATTERN, // 46 DSPDaox ROP_HAS_SOURCEPATTERN, // 47 PSDPxaxn ROP_HAS_SOURCEPATTERN, // 48 SDPxa ROP_HAS_SOURCEPATTERN, // 49 PDSPDaoxxn ROP_HAS_SOURCEPATTERN, // 4A DPSDoax ROP_HAS_SOURCEPATTERN, // 4B PDSnox ROP_HAS_SOURCEPATTERN, // 4C SDPana ROP_HAS_SOURCEPATTERN, // 4D SSPxDSxoxn ROP_HAS_SOURCEPATTERN, // 4E PDSPxox ROP_HAS_SOURCEPATTERN, // 4F PDSnoan ROP_HAS_PATTERN, // 50 PDna ROP_HAS_SOURCEPATTERN, // 51 DSPnaon ROP_HAS_SOURCEPATTERN, // 52 DPSDaox ROP_HAS_SOURCEPATTERN, // 53 SPDSxaxn ROP_HAS_SOURCEPATTERN, // 54 DPSonon 0, // 55 Dn DSTINVERT ROP_HAS_SOURCEPATTERN, // 56 DPSox ROP_HAS_SOURCEPATTERN, // 57 DPSoan ROP_HAS_SOURCEPATTERN, // 58 PDSPoax ROP_HAS_SOURCEPATTERN, // 59 DPSnox ROP_HAS_PATTERN, // 5A DPx PATINVERT ROP_HAS_SOURCEPATTERN, // 5B DPSDonox ROP_HAS_SOURCEPATTERN, // 5C DPSDxox ROP_HAS_SOURCEPATTERN, // 5D DPSnoan ROP_HAS_SOURCEPATTERN, // 5E DPSDnaox ROP_HAS_PATTERN, // 5F DPan ROP_HAS_SOURCEPATTERN, // 60 PDSxa ROP_HAS_SOURCEPATTERN, // 61 DSPDSaoxxn ROP_HAS_SOURCEPATTERN, // 62 DSPDoax ROP_HAS_SOURCEPATTERN, // 63 SDPnox ROP_HAS_SOURCEPATTERN, // 64 SDPSoax ROP_HAS_SOURCEPATTERN, // 65 DSPnox ROP_HAS_SOURCE, // 66 DSx SRCINVERT ROP_HAS_SOURCEPATTERN, // 67 SDPSonox ROP_HAS_SOURCEPATTERN, // 68 DSPDSonoxxn ROP_HAS_SOURCEPATTERN, // 69 PDSxxn ROP_HAS_SOURCEPATTERN, // 6A DPSax ROP_HAS_SOURCEPATTERN, // 6B PSDPSoaxxn ROP_HAS_SOURCEPATTERN, // 6C SDPax ROP_HAS_SOURCEPATTERN, // 6D PDSPDoaxxn ROP_HAS_SOURCEPATTERN, // 6E SDPSnoax ROP_HAS_SOURCEPATTERN, // 6F PDSxnan ROP_HAS_SOURCEPATTERN, // 70 PDSana ROP_HAS_SOURCEPATTERN, // 71 SSDxPDxaxn ROP_HAS_SOURCEPATTERN, // 72 SDPSxox ROP_HAS_SOURCEPATTERN, // 73 SDPnoan ROP_HAS_SOURCEPATTERN, // 74 DSPDxox ROP_HAS_SOURCEPATTERN, // 75 DSPnoan ROP_HAS_SOURCEPATTERN, // 76 SDPSnaox ROP_HAS_SOURCE, // 77 DSan ROP_HAS_SOURCEPATTERN, // 78 PDSax ROP_HAS_SOURCEPATTERN, // 79 DSPDSoaxxn ROP_HAS_SOURCEPATTERN, // 7A DPSDnoax ROP_HAS_SOURCEPATTERN, // 7B SDPxnan ROP_HAS_SOURCEPATTERN, // 7C SPDSnoax ROP_HAS_SOURCEPATTERN, // 7D DPSxnan ROP_HAS_SOURCEPATTERN, // 7E SPxDSxo ROP_HAS_SOURCEPATTERN, // 7F DPSaan ROP_HAS_SOURCEPATTERN, // 80 DPSaa ROP_HAS_SOURCEPATTERN, // 81 SPxDSxon ROP_HAS_SOURCEPATTERN, // 82 DPSxna ROP_HAS_SOURCEPATTERN, // 83 SPDSnoaxn ROP_HAS_SOURCEPATTERN, // 84 SDPxna ROP_HAS_SOURCEPATTERN, // 85 PDSPnoaxn ROP_HAS_SOURCEPATTERN, // 86 DSPDSoaxx ROP_HAS_SOURCEPATTERN, // 87 PDSaxn ROP_HAS_SOURCE, // 88 DSa SRCAND ROP_HAS_SOURCEPATTERN, // 89 SDPSnaoxn ROP_HAS_SOURCEPATTERN, // 8A DSPnoa ROP_HAS_SOURCEPATTERN, // 8B DSPDxoxn ROP_HAS_SOURCEPATTERN, // 8C SDPnoa ROP_HAS_SOURCEPATTERN, // 8D SDPSxoxn ROP_HAS_SOURCEPATTERN, // 8E SSDxPDxax ROP_HAS_SOURCEPATTERN, // 8F PDSanan ROP_HAS_SOURCEPATTERN, // 90 PDSxna ROP_HAS_SOURCEPATTERN, // 91 SDPSnoaxn ROP_HAS_SOURCEPATTERN, // 92 DPSDPoaxx ROP_HAS_SOURCEPATTERN, // 93 SPDaxn ROP_HAS_SOURCEPATTERN, // 94 PSDPSoaxx ROP_HAS_SOURCEPATTERN, // 95 DPSaxn ROP_HAS_SOURCEPATTERN, // 96 DPSxx ROP_HAS_SOURCEPATTERN, // 97 PSDPSonoxx ROP_HAS_SOURCEPATTERN, // 98 SDPSonoxn ROP_HAS_SOURCE, // 99 DSxn ROP_HAS_SOURCEPATTERN, // 9A DPSnax ROP_HAS_SOURCEPATTERN, // 9B SDPSoaxn ROP_HAS_SOURCEPATTERN, // 9C SPDnax ROP_HAS_SOURCEPATTERN, // 9D DSPDoaxn ROP_HAS_SOURCEPATTERN, // 9E DSPDSaoxx ROP_HAS_SOURCEPATTERN, // 9F PDSxan ROP_HAS_PATTERN, // A0 DPa ROP_HAS_SOURCEPATTERN, // A1 PDSPnaoxn ROP_HAS_SOURCEPATTERN, // A2 DPSnoa ROP_HAS_SOURCEPATTERN, // A3 DPSDxoxn ROP_HAS_SOURCEPATTERN, // A4 PDSPonoxn ROP_HAS_PATTERN, // A5 PDxn ROP_HAS_SOURCEPATTERN, // A6 DSPnax ROP_HAS_SOURCEPATTERN, // A7 PDSPoaxn ROP_HAS_SOURCEPATTERN, // A8 DPSoa ROP_HAS_SOURCEPATTERN, // A9 DPSoxn 0, // AA D ROP_HAS_SOURCEPATTERN, // AB DPSono ROP_HAS_SOURCEPATTERN, // AC SPDSxax ROP_HAS_SOURCEPATTERN, // AD DPSDaoxn ROP_HAS_SOURCEPATTERN, // AE DSPnao ROP_HAS_PATTERN, // AF DPno ROP_HAS_SOURCEPATTERN, // B0 PDSnoa ROP_HAS_SOURCEPATTERN, // B1 PDSPxoxn ROP_HAS_SOURCEPATTERN, // B2 SSPxDSxox ROP_HAS_SOURCEPATTERN, // B3 SDPanan ROP_HAS_SOURCEPATTERN, // B4 PSDnax ROP_HAS_SOURCEPATTERN, // B5 DPSDoaxn ROP_HAS_SOURCEPATTERN, // B6 DPSDPaoxx ROP_HAS_SOURCEPATTERN, // B7 SDPxan ROP_HAS_SOURCEPATTERN, // B8 PSDPxax ROP_HAS_SOURCEPATTERN, // B9 DSPDaoxn ROP_HAS_SOURCEPATTERN, // BA DPSnao ROP_HAS_SOURCE, // BB DSno MERGEPAINT ROP_HAS_SOURCEPATTERN, // BC SPDSanax ROP_HAS_SOURCEPATTERN, // BD SDxPDxan ROP_HAS_SOURCEPATTERN, // BE DPSxo ROP_HAS_SOURCEPATTERN, // BF DPSano MERGECOPY ROP_HAS_SOURCEPATTERN, // C0 PSa ROP_HAS_SOURCEPATTERN, // C1 SPDSnaoxn ROP_HAS_SOURCEPATTERN, // C2 SPDSonoxn ROP_HAS_SOURCEPATTERN, // C3 PSxn ROP_HAS_SOURCEPATTERN, // C4 SPDnoa ROP_HAS_SOURCEPATTERN, // C5 SPDSxoxn ROP_HAS_SOURCEPATTERN, // C6 SDPnax ROP_HAS_SOURCEPATTERN, // C7 PSDPoaxn ROP_HAS_SOURCEPATTERN, // C8 SDPoa ROP_HAS_SOURCEPATTERN, // C9 SPDoxn ROP_HAS_SOURCEPATTERN, // CA DPSDxax ROP_HAS_SOURCEPATTERN, // CB SPDSaoxn ROP_HAS_SOURCE, // CC S SRCCOPY ROP_HAS_SOURCEPATTERN, // CD SDPono ROP_HAS_SOURCEPATTERN, // CE SDPnao ROP_HAS_SOURCEPATTERN, // CF SPno ROP_HAS_SOURCEPATTERN, // D0 PSDnoa ROP_HAS_SOURCEPATTERN, // D1 PSDPxoxn ROP_HAS_SOURCEPATTERN, // D2 PDSnax ROP_HAS_SOURCEPATTERN, // D3 SPDSoaxn ROP_HAS_SOURCEPATTERN, // D4 SSPxPDxax ROP_HAS_SOURCEPATTERN, // D5 DPSanan ROP_HAS_SOURCEPATTERN, // D6 PSDPSaoxx ROP_HAS_SOURCEPATTERN, // D7 DPSxan ROP_HAS_SOURCEPATTERN, // D8 PDSPxax ROP_HAS_SOURCEPATTERN, // D9 SDPSaoxn ROP_HAS_SOURCEPATTERN, // DA DPSDanax ROP_HAS_SOURCEPATTERN, // DB SPxDSxan ROP_HAS_SOURCEPATTERN, // DC SPDnao ROP_HAS_SOURCE, // DD SDno ROP_HAS_SOURCEPATTERN, // DE SDPxo ROP_HAS_SOURCEPATTERN, // DF SDPano ROP_HAS_SOURCEPATTERN, // E0 PDSoa ROP_HAS_SOURCEPATTERN, // E1 PDSoxn ROP_HAS_SOURCEPATTERN, // E2 DSPDxax ROP_HAS_SOURCEPATTERN, // E3 PSDPaoxn ROP_HAS_SOURCEPATTERN, // E4 SDPSxax ROP_HAS_SOURCEPATTERN, // E5 PDSPaoxn ROP_HAS_SOURCEPATTERN, // E6 SDPSanax ROP_HAS_SOURCEPATTERN, // E7 SPxPDxan ROP_HAS_SOURCEPATTERN, // E8 SSPxDSxax ROP_HAS_SOURCEPATTERN, // E9 DSPDSanaxxn ROP_HAS_SOURCEPATTERN, // EA DPSao ROP_HAS_SOURCEPATTERN, // EB DPSxno ROP_HAS_SOURCEPATTERN, // EC SDPao ROP_HAS_SOURCEPATTERN, // ED SDPxno ROP_HAS_SOURCE, // EE DSo SRCPAINT ROP_HAS_SOURCEPATTERN, // EF SDPnoo ROP_HAS_PATTERN, // F0 P PATCOPY ROP_HAS_SOURCEPATTERN, // F1 PDSono ROP_HAS_SOURCEPATTERN, // F2 PDSnao ROP_HAS_SOURCEPATTERN, // F3 PSno ROP_HAS_SOURCEPATTERN, // F4 PSDnao ROP_HAS_PATTERN, // F5 PDno ROP_HAS_SOURCEPATTERN, // F6 PDSxo ROP_HAS_SOURCEPATTERN, // F7 PDSano ROP_HAS_SOURCEPATTERN, // F8 PDSao ROP_HAS_SOURCEPATTERN, // F9 PDSxno ROP_HAS_PATTERN, // FA DPo ROP_HAS_SOURCEPATTERN, // FB DPSnoo PATPAINT ROP_HAS_SOURCEPATTERN, // FC PSo ROP_HAS_SOURCEPATTERN, // FD PSDnoo ROP_HAS_SOURCEPATTERN, // FE DPSoo 0 // FF 1 WHITENESS }; /* * checkBltStretching * * check and see if we can stretch or not */ HRESULT checkBltStretching( LPBLTCAPS lpbc, LPSPECIAL_BLT_DATA psbd ) { DWORD caps; BOOL fail; fail = FALSE; /* * can we even stretch at all? */ if( !(*(lpbc->dwBothCaps) & DDCAPS_BLTSTRETCH)) { GETFAILCODEBLT( *(lpbc->dwCaps), *(lpbc->dwHELCaps), psbd->halonly, psbd->helonly, DDCAPS_BLTSTRETCH ); if( fail ) { return DDERR_NOSTRETCHHW; } } if (psbd->helonly) caps = *(lpbc->dwHELFXCaps); else caps = *(lpbc->dwFXCaps); /* * verify height */ if( psbd->src_height != psbd->dest_height ) { if( psbd->src_height > psbd->dest_height ) { /* * can we shrink Y arbitrarily? */ if( !(caps & (DDFXCAPS_BLTSHRINKY) ) ) { /* * see if this is a non-integer shrink */ if( (psbd->src_height % psbd->dest_height) != 0 ) { GETFAILCODEBLT( *(lpbc->dwFXCaps), *(lpbc->dwHELFXCaps), psbd->halonly, psbd->helonly, DDFXCAPS_BLTSHRINKY ); if( fail ) { return DDERR_NOSTRETCHHW; } /* * see if we can integer shrink */ } else if( !(caps & DDFXCAPS_BLTSHRINKYN) ) { GETFAILCODEBLT( *(lpbc->dwFXCaps), *(lpbc->dwHELFXCaps), psbd->halonly, psbd->helonly, DDFXCAPS_BLTSHRINKYN ); if( fail ) { return DDERR_NOSTRETCHHW; } } } } else { if( !(caps & DDFXCAPS_BLTSTRETCHY) ) { /* * see if this is a non-integer stretch */ if( (psbd->dest_height % psbd->src_height) != 0 ) { GETFAILCODEBLT( *(lpbc->dwFXCaps), *(lpbc->dwHELFXCaps), psbd->halonly, psbd->helonly, DDFXCAPS_BLTSTRETCHY ); if( fail ) { return DDERR_NOSTRETCHHW; } /* * see if we can integer stretch */ } else if( !(caps & DDFXCAPS_BLTSTRETCHYN) ) { GETFAILCODEBLT( *(lpbc->dwFXCaps), *(lpbc->dwHELFXCaps), psbd->halonly, psbd->helonly, DDFXCAPS_BLTSTRETCHYN ); if( fail ) { return DDERR_NOSTRETCHHW; } } } } } /* * verify width */ if( psbd->src_width != psbd->dest_width ) { if( psbd->src_width > psbd->dest_width ) { if( !(caps & DDFXCAPS_BLTSHRINKX) ) { /* * see if this is a non-integer shrink */ if( (psbd->src_width % psbd->dest_width) != 0 ) { GETFAILCODEBLT( *(lpbc->dwFXCaps), *(lpbc->dwHELFXCaps), psbd->halonly, psbd->helonly, DDFXCAPS_BLTSHRINKX ); if( fail ) { return DDERR_NOSTRETCHHW; } /* * see if we can integer shrink */ } else if( !(caps & DDFXCAPS_BLTSHRINKXN) ) { GETFAILCODEBLT( *(lpbc->dwFXCaps), *(lpbc->dwHELFXCaps), psbd->halonly, psbd->helonly, DDFXCAPS_BLTSHRINKXN ); if( fail ) { return DDERR_NOSTRETCHHW; } } } } else { if( !(caps & DDFXCAPS_BLTSTRETCHX) ) { /* * see if this is a non-integer stretch */ if( (psbd->dest_width % psbd->src_width) != 0 ) { GETFAILCODEBLT( *(lpbc->dwFXCaps), *(lpbc->dwHELFXCaps), psbd->halonly, psbd->helonly, DDFXCAPS_BLTSTRETCHX ); if( fail ) { return DDERR_NOSTRETCHHW; } } if( !(caps & DDFXCAPS_BLTSTRETCHXN) ) { GETFAILCODEBLT( *(lpbc->dwFXCaps), *(lpbc->dwHELFXCaps), psbd->halonly, psbd->helonly, DDFXCAPS_BLTSTRETCHXN ); if( fail ) { return DDERR_NOSTRETCHHW; } } } } } return DD_OK; } /* checkBltStretching */ /* * FindAttached * * find an attached surface with particular caps */ LPDDRAWI_DDRAWSURFACE_LCL FindAttached( LPDDRAWI_DDRAWSURFACE_LCL ptr_lcl, DWORD caps ) { LPATTACHLIST pal; LPDDRAWI_DDRAWSURFACE_LCL psurf_lcl; pal = ptr_lcl->lpAttachList; while( pal != NULL ) { psurf_lcl = pal->lpAttached; if( psurf_lcl->ddsCaps.dwCaps & caps ) { return psurf_lcl; } pal = pal->lpLink; } return NULL; } /* FindAttached */ #if defined(WIN95) #define DONE_EXCLUDE() \ if( this_dest_lcl->lpDDClipper != NULL ) \ { \ if ( (pdrv->dwFlags & DDRAWI_DISPLAYDRV) && pdrv->dwPDevice && \ !(*pdrv->lpwPDeviceFlags & HARDWARECURSOR)) \ { \ DD16_Unexclude(pdrv->dwPDevice); \ } \ } #elif defined(WINNT) #define DONE_EXCLUDE() ; #endif /* * DD_Surface_Blt * * Bit Blt from one surface to another */ HRESULT DDAPI DD_Surface_Blt( LPDIRECTDRAWSURFACE lpDDDestSurface, LPRECT lpDestRect, LPDIRECTDRAWSURFACE lpDDSrcSurface, LPRECT lpSrcRect, DWORD dwFlags, LPDDBLTFX lpDDBltFX ) { DWORD rc; DWORD rop; LPDDRAWI_DDRAWSURFACE_LCL psurf_lcl; LPDDRAWI_DDRAWSURFACE_INT psurf_int; LPDDRAWI_DDRAWSURFACE_LCL this_src_lcl; LPDDRAWI_DDRAWSURFACE_LCL this_dest_lcl; LPDDRAWI_DDRAWSURFACE_GBL this_src; LPDDRAWI_DDRAWSURFACE_GBL this_dest; LPDDRAWI_DDRAWSURFACE_INT this_src_int; LPDDRAWI_DDRAWSURFACE_INT this_dest_int; BOOL need_pat; SPECIAL_BLT_DATA sbd; BOOL stretch_blt; LPDDRAWI_DIRECTDRAW_LCL pdrv_lcl; LPDDRAWI_DIRECTDRAW_GBL pdrv; DDHAL_BLTDATA bd; RECT DestRect; BOOL fail; BOOL dest_lock_taken=FALSE; BOOL src_lock_taken=FALSE; BOOL dest_pagelock_taken=FALSE; BOOL src_pagelock_taken=FALSE; LPVOID dest_bits; LPVOID src_bits; HRESULT ddrval; BLTCAPS bc; LPBLTCAPS lpbc=&bc; LPWORD pdflags=0; DWORD dwSourceLockFlags=0; DWORD dwDestLockFlags=0; BOOL gdiblt; LPDDPIXELFORMAT pddpf; BOOL subrect_lock_taken = FALSE; RECT subrect_lock_rect; ENTER_BOTH(); DPF(2,A,"ENTERAPI: DD_Surface_Blt"); TRY { ZeroMemory(&bd, sizeof(bd)); // initialize to zero /* * validate surface ptrs */ this_dest_int = (LPDDRAWI_DDRAWSURFACE_INT) lpDDDestSurface; this_src_int = (LPDDRAWI_DDRAWSURFACE_INT) lpDDSrcSurface; if( !VALID_DIRECTDRAWSURFACE_PTR( this_dest_int ) ) { DPF_ERR( "Invalid dest specified") ; LEAVE_BOTH(); return DDERR_INVALIDOBJECT; } this_dest_lcl = this_dest_int->lpLcl; this_dest = this_dest_lcl->lpGbl; if( SURFACE_LOST( this_dest_lcl ) ) { DPF( 1, "Dest lost") ; LEAVE_BOTH(); return DDERR_SURFACELOST; } if( this_src_int != NULL ) { if( !VALID_DIRECTDRAWSURFACE_PTR( this_src_int ) ) { DPF_ERR( "Invalid source specified" ); LEAVE_BOTH(); return DDERR_INVALIDOBJECT; } this_src_lcl = this_src_int->lpLcl; this_src = this_src_lcl->lpGbl; if( SURFACE_LOST( this_src_lcl ) ) { DPF_ERR( "Src lost") ; LEAVE_BOTH(); return DDERR_SURFACELOST; } } else { this_src_lcl = NULL; this_src = NULL; } if ( ( DDBLT_DX8ORHIGHER & dwFlags ) && ( DDBLT_WINDOWCLIP & dwFlags ) ) { LPDDRAWI_DDRAWCLIPPER_INT lpDDIClipper = this_dest_lcl->lpSurfMore->lpDDIClipper; if (lpDDIClipper && (DDSCAPS_PRIMARYSURFACE & this_dest_lcl->ddsCaps.dwCaps)) { HWND hWnd = (HWND)lpDDIClipper->lpLcl->lpGbl->hWnd; if (GetClientRect(hWnd, &DestRect)) { if(( lpDestRect != NULL ) && VALID_RECT_PTR( lpDestRect )) { if (DestRect.right > lpDestRect->right) DestRect.right = lpDestRect->right; if (DestRect.bottom > lpDestRect->bottom) DestRect.bottom = lpDestRect->bottom; if (0 < lpDestRect->left) DestRect.left = lpDestRect->left; if (0 < lpDestRect->top) DestRect.top = lpDestRect->top; if (DestRect.top >= DestRect.bottom || DestRect.left >= DestRect.right) { // in case of insane RECT, fail it DPF_ERR("Unable to Blt with invalid dest RECT"); LEAVE_BOTH(); return DDERR_INVALIDPARAMS; } } if (!ClientToScreen(hWnd,(POINT*)&DestRect)) DPF_ERR("ClientToScreen Failed on DestRect?"); if (!ClientToScreen(hWnd,(POINT*)&DestRect.right)) DPF_ERR("ClientToScreen Failed on DestRect.right?"); // in DX8 we always have DDRAWILCL_EXPLICITMONITOR so // DestRect must be checked and adjusted against DeviceRect pdrv = this_dest->lpDD; /* * Do a real quick check w/o accounting for the clipper */ if( ( DestRect.top < pdrv->rectDevice.top ) || ( DestRect.left < pdrv->rectDevice.left ) || ( DestRect.right > pdrv->rectDevice.right ) || ( DestRect.bottom > pdrv->rectDevice.bottom ) ) { RECT rect; /* * It may only be that part of the rect is off of the desktop, * in which case we don't neccesarily need to drop to emulation. */ IntersectRect( &rect, &DestRect, &pdrv->rectDesktop ); if( ( rect.top < pdrv->rectDevice.top ) || ( rect.left < pdrv->rectDevice.left ) || ( rect.right > pdrv->rectDevice.right ) || ( rect.bottom > pdrv->rectDevice.bottom ) ) { // fail crossdevice blt and let GDI do it in DdBlt() LEAVE_BOTH(); return DDERR_INVALIDPARAMS; } } if (!OffsetRect(&DestRect, -pdrv->rectDevice.left, -pdrv->rectDevice.top)) DPF_ERR("OffsetRect Failed on DestRect?"); lpDestRect = &DestRect; // replace it with new Rect DPF(10,"Got a new dest RECT !!"); if (DDBLT_COPYVSYNC & dwFlags) { DWORD msCurrentTime = 0; DWORD msStartTime = GetTickCount(); LPDDHAL_GETSCANLINE gslhalfn; LPDDHAL_GETSCANLINE gslfn; LPDDRAWI_DIRECTDRAW_LCL this_lcl = this_dest_lcl->lpSurfMore->lpDD_lcl; gslfn = this_lcl->lpDDCB->HALDD.GetScanLine; gslhalfn = this_lcl->lpDDCB->cbDDCallbacks.GetScanLine; if( gslhalfn != NULL ) { DDHAL_GETSCANLINEDATA gsld; DWORD rc; gsld.GetScanLine = gslhalfn; gsld.lpDD = this_lcl->lpGbl; do { DOHALCALL_NOWIN16( GetScanLine, gslfn, gsld, rc, FALSE ); if ( DD_OK != gsld.ddRVal ) break; if ( (LONG)gsld.dwScanLine >= DestRect.bottom ) break; msCurrentTime = GetTickCount(); // If we've been spinning here for 30ms // then blt anyway; probably something // taking up CPU cycles if ( (msCurrentTime - msStartTime) > 30 ) { break; } } while ( DDHAL_DRIVER_HANDLED == rc ); } } } else { DPF_ERR("GetClientRect Failed ?"); } } // Don't let these DX8-only flags propagate to driver (or rest of Blt code) // since they alias other existing flags. dwFlags &= ~(DDBLT_WINDOWCLIP | DDBLT_COPYVSYNC | DDBLT_DX8ORHIGHER); } if( dwFlags & ~DDBLT_VALID ) { DPF_ERR( "Invalid flags") ; LEAVE_BOTH(); return DDERR_INVALIDPARAMS; } /* * BEHAVIOUR CHANGE FOR DX5 * * We do not allow bltting between surfaces created with different DirectDraw * objects. */ if (this_src) { if (this_dest_lcl->lpSurfMore->lpDD_lcl->lpGbl != this_src_lcl->lpSurfMore->lpDD_lcl->lpGbl) { if ((this_dest_lcl->lpSurfMore->lpDD_lcl->lpGbl->dwFlags & DDRAWI_DISPLAYDRV) && (this_src_lcl->lpSurfMore->lpDD_lcl->lpGbl->dwFlags & DDRAWI_DISPLAYDRV)) { DPF_ERR("Can't blt surfaces between different direct draw devices"); LEAVE_BOTH(); return DDERR_DEVICEDOESNTOWNSURFACE; } } } // // If either surface is optimized, quit // if (this_dest_lcl->ddsCaps.dwCaps & DDSCAPS_OPTIMIZED) { DPF_ERR( "Can't blt optimized surfaces") ; LEAVE_BOTH(); return DDERR_INVALIDPARAMS; } if (this_src) { if (this_src_lcl->ddsCaps.dwCaps & DDSCAPS_OPTIMIZED) { DPF_ERR( "Can't blt optimized surfaces") ; LEAVE_BOTH(); return DDERR_INVALIDPARAMS; } } /* * Since Z Blts are currently turned off, we might as well give some * hint that this is the case. */ #ifdef DEBUG if( dwFlags & ( DDBLT_ZBUFFER | DDBLT_ZBUFFERDESTCONSTOVERRIDE | DDBLT_ZBUFFERDESTOVERRIDE | DDBLT_ZBUFFERSRCCONSTOVERRIDE | DDBLT_ZBUFFERSRCOVERRIDE ) ) { DPF_ERR( "Z aware BLTs are not currently supported" ); LEAVE_BOTH(); return DDERR_NOZBUFFERHW; } #endif pdrv = this_dest->lpDD; pdrv_lcl = this_dest_lcl->lpSurfMore->lpDD_lcl; #ifdef WINNT // Update DDraw handle in driver GBL object. pdrv->hDD = pdrv_lcl->hDD; #endif /* * DX5 or greater drivers get to know about read/write only locks * Note that dwDestFlags may later be modified for dest color key. * Pass zero for both flags unless: * -it's a color fill, in which case turn on writeonly for dest. * -the blt goes from/to different surfaces, */ if ( (pdrv->dwInternal1 >= 0x500) && ((this_src == NULL) || (this_src != this_dest) ) ) { dwSourceLockFlags = DDLOCK_READONLY; dwDestLockFlags = DDLOCK_WRITEONLY; } } EXCEPT( EXCEPTION_EXECUTE_HANDLER ) { DPF_ERR( "Exception encountered validating parameters" ); LEAVE_BOTH(); return DDERR_INVALIDPARAMS; } #ifdef USE_ALIAS if( pdrv->dwBusyDueToAliasedLock > 0 ) { /* * Aliased locks (the ones that don't take the Win16 lock) don't * set the busy bit either (it can't or USER get's very confused). * However, we must prevent blits happening via DirectDraw as * otherwise we get into the old host talking to VRAM while * blitter does at the same time. Bad. So fail if there is an * outstanding aliased lock just as if the BUST bit had been * set. */ DPF_ERR( "Graphics adapter is busy (due to a DirectDraw lock)" ); LEAVE_BOTH(); return DDERR_SURFACEBUSY; } #endif /* USE_ALIAS */ /* * Behavior change: In DX7, the default is to wait unless DDBLT_DONOTWAIT=1. * In earlier releases, the default was to NOT wait unless DDBLT_WAIT=1. * (The DDBLT_DONOTWAIT flag was not defined until the DX7 release.) */ if (!LOWERTHANSURFACE7(this_dest_int)) { if (dwFlags & DDBLT_DONOTWAIT) { if (dwFlags & DDBLT_WAIT) { DPF_ERR( "WAIT and DONOTWAIT flags are mutually exclusive" ); LEAVE_BOTH(); return DDERR_INVALIDPARAMS; } } else { dwFlags |= DDBLT_WAIT; } } if(this_src_lcl) FlushD3DStates(this_src_lcl); // Need to flush src because it could be a rendertarget FlushD3DStates(this_dest_lcl); // Test and set the busy bit. If it was already set, bail. { BOOL isbusy = 0; pdflags = pdrv->lpwPDeviceFlags; #ifdef WIN95 _asm { mov eax, pdflags bts word ptr [eax], BUSY_BIT adc byte ptr isbusy,0 } #else isbusy -= (InterlockedExchange((LPDWORD)pdflags, *((LPDWORD)pdflags) | (1<ddsCaps.dwCaps & DDSCAPS_VIDEOPORT ) ) { LPDDRAWI_DDVIDEOPORT_INT lpVideoPort; LPDDRAWI_DDVIDEOPORT_LCL lpVideoPort_lcl; // Look at all video ports to see if any of them recently // flipped from this surface. lpVideoPort = pdrv->dvpList; while( NULL != lpVideoPort ) { lpVideoPort_lcl = lpVideoPort->lpLcl; if( lpVideoPort_lcl->fpLastFlip == this_src->fpVidMem ) { // This can potentially tear - check the flip status LPDDHALVPORTCB_GETFLIPSTATUS pfn; DDHAL_GETVPORTFLIPSTATUSDATA GetFlipData; LPDDRAWI_DIRECTDRAW_LCL pdrv_lcl; pdrv_lcl = this_src_lcl->lpSurfMore->lpDD_lcl; pfn = pdrv_lcl->lpDDCB->HALDDVideoPort.GetVideoPortFlipStatus; if( pfn != NULL ) // Will simply tear if function not supproted { GetFlipData.lpDD = pdrv_lcl; GetFlipData.fpSurface = this_src->fpVidMem; KeepTrying: rc = DDHAL_DRIVER_NOTHANDLED; DOHALCALL_NOWIN16( GetVideoPortFlipStatus, pfn, GetFlipData, rc, 0 ); if( ( DDHAL_DRIVER_HANDLED == rc ) && ( DDERR_WASSTILLDRAWING == GetFlipData.ddRVal ) ) { if( dwFlags & DDBLT_WAIT) { goto KeepTrying; } LEAVE_BOTH_NOBUSY(); return DDERR_WASSTILLDRAWING; } } } lpVideoPort = lpVideoPort->lpLink; } } RESTART_BLT: TRY { /* * Remove any cached RLE stuff for source surface */ if( this_dest_lcl->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY ) { extern void FreeRleData(LPDDRAWI_DDRAWSURFACE_LCL psurf); //in fasthel.c FreeRleData( this_dest_lcl ); } /* * is either surface locked? */ if( (this_dest->dwUsageCount > 0) || ((this_src != NULL) && (this_src->dwUsageCount > 0)) ) { DPF_ERR( "Surface is locked" ); LEAVE_BOTH_NOBUSY(); return DDERR_SURFACEBUSY; } BUMP_SURFACE_STAMP(this_dest); /* * It is possible this function could be called in the middle * of a mode, in which case we could trash the frame buffer. * To avoid regression, we will simply succeed the call without * actually doing anything. */ if( ( pdrv->dwFlags & DDRAWI_CHANGINGMODE ) && !( this_dest_lcl->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY ) ) { LEAVE_BOTH_NOBUSY() return DD_OK; } sbd.halonly = FALSE; sbd.helonly = FALSE; gdiblt = FALSE; if( this_src != NULL ) { // initialize the blit caps according to the surface types initBltCaps( this_dest_lcl->ddsCaps.dwCaps, this_dest->dwGlobalFlags, this_src_lcl->ddsCaps.dwCaps, pdrv, lpbc, &(sbd.helonly) ); } else { // no source surface, use vram->vram caps and determine hal or hel // based on system memory status of destination surface // if the destination is non-local we also force emulation as we // don't currently support accelerated operation with non-local // video memory are a target initBltCaps( DDSCAPS_VIDEOMEMORY, 0, DDSCAPS_VIDEOMEMORY, pdrv, lpbc, &sbd.helonly ); if( ( this_dest_lcl->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY ) || ( this_dest_lcl->ddsCaps.dwCaps & DDSCAPS_NONLOCALVIDMEM ) ) { lpbc->bHALSeesSysmem = FALSE; sbd.helonly = TRUE; } } fail = FALSE; /* * can we really blt? */ if( !(*(lpbc->dwBothCaps) & DDCAPS_BLT) ) { if( *(lpbc->dwCaps) & DDCAPS_BLT ) { sbd.halonly = TRUE; } else if( *(lpbc->dwHELCaps) & DDCAPS_BLT ) { lpbc->bHALSeesSysmem = FALSE; sbd.helonly = TRUE; } else { DPF_ERR( "Driver does not support Blt" ); LEAVE_BOTH_NOBUSY(); return DDERR_NOBLTHW; } } /* * Check for special cases involving FOURCC surfaces: * -- Copy blits between surfaces with identical FOURCC formats * -- Compression/decompression of DXT* compressed textures */ { DWORD dwDest4CC = 0; DWORD dwSrc4CC = 0; /* * Does either the source or dest surface have a FOURCC format? */ if ((this_dest_lcl->dwFlags & DDRAWISURF_HASPIXELFORMAT) && (this_dest->ddpfSurface.dwFlags & DDPF_FOURCC)) { dwDest4CC = this_dest->ddpfSurface.dwFourCC; // dest FOURCC format } if ((this_src_lcl != NULL) && (this_src_lcl->dwFlags & DDRAWISURF_HASPIXELFORMAT) && (this_src->ddpfSurface.dwFlags & DDPF_FOURCC)) { dwSrc4CC = this_src->ddpfSurface.dwFourCC; // source FOURCC format } if (dwDest4CC | dwSrc4CC) { /* * Yes, at least one of the two surfaces has a FOURCC format. * Do the source and dest surfaces have precisely the same * FOURCC format? (If so, this is a FOURCC copy blit.) */ if (dwDest4CC == dwSrc4CC) { // Yes, this is a FOURCC copy blit. Can the driver handle this? if ((pdrv->ddCaps.dwCaps2 & DDCAPS2_COPYFOURCC) == 0) { // The driver cannot handle FOURCC copy blits. sbd.helonly = TRUE; } } else { /* * No, the two surfaces have different pixel formats. * Now determine if either surface has a DXT* FOURCC format. * The rule for the Blt API call is that the HEL _ALWAYS_ * performs a blit involving a DXT* source or dest surface. * Hardware acceleration for DXT* blits is available only * with the AlphaBlt API call. We now enforce this rule: */ switch (dwDest4CC) { case MAKEFOURCC('D','X','T','1'): case MAKEFOURCC('D','X','T','2'): case MAKEFOURCC('D','X','T','3'): case MAKEFOURCC('D','X','T','4'): case MAKEFOURCC('D','X','T','5'): // This is a blit to a DXT*-formatted surface. sbd.helonly = TRUE; break; default: break; } switch (dwSrc4CC) { case MAKEFOURCC('D','X','T','1'): case MAKEFOURCC('D','X','T','2'): case MAKEFOURCC('D','X','T','3'): case MAKEFOURCC('D','X','T','4'): case MAKEFOURCC('D','X','T','5'): // This is a blit from a DXT*-formatted surface. sbd.helonly = TRUE; break; default: break; } } } } /* * check for HEL composition buffer */ if( (this_dest_lcl->dwFlags & DDRAWISURF_HELCB) || ((this_src_lcl != NULL) && (this_src_lcl->dwFlags & DDRAWISURF_HELCB)) ) { lpbc->bHALSeesSysmem = FALSE; sbd.helonly = TRUE; } bd.lpDD = pdrv; /* * make sure BltFX struct is OK */ bd.bltFX.dwSize = sizeof( bd.bltFX ); if( lpDDBltFX != NULL ) { if( !VALID_DDBLTFX_PTR( lpDDBltFX ) ) { DPF_ERR( "Invalid BLTFX specified" ); LEAVE_BOTH_NOBUSY(); return DDERR_INVALIDPARAMS; } } else { if( dwFlags & ( DDBLT_ALPHASRCCONSTOVERRIDE | DDBLT_ALPHADESTCONSTOVERRIDE | DDBLT_ALPHASRCSURFACEOVERRIDE | DDBLT_ALPHADESTSURFACEOVERRIDE | DDBLT_COLORFILL | DDBLT_DDFX | DDBLT_DDROPS | DDBLT_DEPTHFILL | DDBLT_KEYDESTOVERRIDE | DDBLT_KEYSRCOVERRIDE | DDBLT_ROP | DDBLT_ROTATIONANGLE | DDBLT_ZBUFFERDESTCONSTOVERRIDE | DDBLT_ZBUFFERDESTOVERRIDE | DDBLT_ZBUFFERSRCCONSTOVERRIDE | DDBLT_ZBUFFERSRCOVERRIDE ) ) { DPF_ERR( "BltFX required but not specified" ); LEAVE_BOTH_NOBUSY(); return DDERR_INVALIDPARAMS; } } /* * make sure flags & associated bd.bltFX are specified OK */ need_pat = FALSE; if( dwFlags & ~DDBLT_WAIT ) { /* * isolate lower use tests together */ if( dwFlags & (DDBLT_KEYSRCOVERRIDE| DDBLT_KEYDESTOVERRIDE| DDBLT_KEYSRC | DDBLT_KEYDEST ) ) { #pragma message( REMIND( "Alpha turned off in Rev 1" ) ) #pragma message( REMIND( "Set read/write flags for alpha and Z" ) ) #if 0 /* * verify ALPHA */ if( dwFlags & DDBLT_ANYALPHA ) { BOOL no_alpha; no_alpha = TRUE; // check to see if alpha is supported if( !(*(lpbc->dwBothCaps) & DDCAPS_ALPHA) ) { GETFAILCODEBLT( *(lpbc->dwCaps), *(lpbc->dwHELCaps), sbd.halonly, sbd.helonly, DDCAPS_ALPHA ); if( fail ) { DPF_ERR( "Alpha blt requested, not supported" ); LEAVE_BOTH_NOBUSY(); return DDERR_NOALPHAHW; } } /* * dest alpha */ if( dwFlags & DDBLT_ALPHADEST ) { if( dwFlags & ( DDBLT_ALPHADESTCONSTOVERRIDE | DDBLT_ALPHADESTSURFACEOVERRIDE) ) { DPF_ERR( "ALPHADEST and other alpha dests specified" ); LEAVE_BOTH_NOBUSY(); return DDERR_INVALIDPARAMS; } psurf_lcl = FindAttached( this_dest_lcl, DDSCAPS_ALPHA ); if( psurf_lcl == NULL ) { DPF_ERR( "ALPHADEST requires an attached alpha to the dest" ); LEAVE_BOTH_NOBUSY(); return DDERR_INVALIDPARAMS; } dwFlags &= ~DDBLT_ALPHADEST; dwFlags |= DDBLT_ALPHADESTSURFACEOVERRIDE; bd.bltFX.lpDDSAlphaDest = (LPDIRECTDRAWSURFACE) psurf_lcl; no_alpha = FALSE; // check to see if alpha surfaces are supported if( !(*(lpbc->dwBothCaps) & DDFXCAPS_ALPHASURFACES) ) { GETFAILCODEBLT( *(lpbc->dwFXCaps), *(lpbc->dwHELFXCaps), sbd.halonly, sbd.helonly, DDFXCAPS_ALPHASURFACES ); if( fail ) { DPF_ERR( "AlphaDest surface requested, not supported" ); LEAVE_BOTH_NOBUSY(); return DDERR_NOALPHAHW; } } } else if( dwFlags & DDBLT_ALPHADESTCONSTOVERRIDE ) { if( dwFlags & ( DDBLT_ALPHADESTSURFACEOVERRIDE )) { DPF_ERR( "ALPHADESTCONSTOVERRIDE and other alpha sources specified" ); LEAVE_BOTH_NOBUSY(); return DDERR_INVALIDPARAMS; } bd.bltFX.dwConstAlphaDest = lpDDBltFX->dwConstAlphaDest; no_alpha = FALSE; } else if( dwFlags & DDBLT_ALPHADESTSURFACEOVERRIDE ) { psurf_lcl = (LPDDRAWI_DDRAWSURFACE_LCL) lpDDBltFX->lpDDSAlphaDest; if( !VALID_DIRECTDRAWSURFACE_PTR( psurf_lcl ) ) { DPF_ERR( "ALPHASURFACEOVERRIDE requires surface ptr" ); LEAVE_BOTH_NOBUSY(); return DDERR_INVALIDPARAMS; } if( SURFACE_LOST( psurf_lcl ) ) { LEAVE_BOTH_NOBUSY(); return DDERR_SURFACELOST; } bd.bltFX.lpDDSAlphaDest = (LPDIRECTDRAWSURFACE) psurf_lcl; no_alpha = FALSE; // check to see if alpha surfaces are supported if( !(*(lpbc->dwBothCaps) & DDFXCAPS_ALPHASURFACES) ) { GETFAILCODEBLT( *(lpbc->dwFXCaps), *(lpbc->dwHELFXCaps), sbd.halonly, sbd.helonly, DDFXCAPS_ALPHASURFACES ); if( fail ) { DPF_ERR( "AlphaDestOvr surface requested, not supported" ); LEAVE_BOTH_NOBUSY(); return DDERR_NOALPHAHW; } } } /* * source alpha */ if( dwFlags & DDBLT_ALPHASRC ) { if( dwFlags & (DDBLT_ALPHASRCCONSTOVERRIDE| DDBLT_ALPHASRCSURFACEOVERRIDE) ) { DPF_ERR( "ALPHASRC and other alpha sources specified" ); LEAVE_BOTH_NOBUSY(); return DDERR_INVALIDPARAMS; } if( this_src == NULL ) { DPF_ERR( "ALPHASRC requires a source surface" ); LEAVE_BOTH_NOBUSY(); return DDERR_INVALIDPARAMS; } psurf_lcl = FindAttached( this_src_lcl, DDSCAPS_ALPHA ); if( psurf_lcl == NULL ) { DPF_ERR( "ALPHASRC requires an attached alpha to the src" ); LEAVE_BOTH_NOBUSY(); return DDERR_INVALIDPARAMS; } dwFlags &= ~DDBLT_ALPHASRC; dwFlags |= DDBLT_ALPHASRCSURFACEOVERRIDE; bd.bltFX.lpDDSAlphaSrc = (LPDIRECTDRAWSURFACE) psurf_lcl; no_alpha = FALSE; // check to see if alpha surfaces are supported if( !(*(lpbc->dwBothCaps) & DDFXCAPS_ALPHASURFACES) ) { GETFAILCODEBLT( *(lpbc->dwFXCaps), *(lpbc->dwHELFXCaps), sbd.halonly, sbd.helonly, DDFXCAPS_ALPHASURFACES ); if( fail ) { DPF_ERR( "AlphaSrc surface requested, not supported" ); LEAVE_BOTH_NOBUSY(); return DDERR_NOALPHAHW; } } } else if( dwFlags & DDBLT_ALPHASRCCONSTOVERRIDE ) { if( dwFlags & ( DDBLT_ALPHASRCSURFACEOVERRIDE )) { DPF_ERR( "ALPHASRCCONSTOVERRIDE and other alpha sources specified" ); LEAVE_BOTH_NOBUSY(); return DDERR_INVALIDPARAMS; } bd.bltFX.dwConstAlphaSrc = lpDDBltFX->dwConstAlphaSrc; no_alpha = FALSE; } else if( dwFlags & DDBLT_ALPHASRCSURFACEOVERRIDE ) { psurf_int = (LPDDRAWI_DDRAWSURFACE_INT) lpDDBltFX->lpDDSAlphaSrc; if( !VALID_DIRECTDRAWSURFACE_PTR( psurf_int ) ) { DPF_ERR( "ALPHASURFACEOVERRIDE requires surface ptr" ); LEAVE_BOTH_NOBUSY(); return DDERR_INVALIDPARAMS; } psurf_lcl = psurf_int->lpLcl; if( SURFACE_LOST( psurf_lcl ) ) { LEAVE_BOTH_NOBUSY(); return DDERR_SURFACELOST; } bd.bltFX.lpDDSAlphaSrc = (LPDIRECTDRAWSURFACE) psurf_lcl; no_alpha = FALSE; // check to see if alpha surfaces are supported if( !(*(lpbc->dwBothCaps) & DDFXCAPS_ALPHASURFACES) ) { GETFAILCODEBLT( *(lpbc->dwFXCaps), *(lpbc->dwHELFXCaps), sbd.halonly, sbd.helonly, DDFXCAPS_ALPHASURFACES ); if( fail ) { DPF_ERR( "AlphaSrcOvr surface requested, not supported" ); LEAVE_BOTH_NOBUSY(); return DDERR_NOALPHAHW; } } } if( no_alpha ) { DPF_ERR( "ALPHA specified with no alpha surface to use" ); LEAVE_BOTH_NOBUSY(); return DDERR_INVALIDPARAMS; } } #endif #pragma message( REMIND( "Z blts turned off in Rev 1" ) ) #if 0 /* * verify Z Buffer */ if( dwFlags & DDBLT_ZBUFFER ) { if( this_src_lcl == NULL ) { DPF_ERR( "ZBUFFER specified, but no source data" ); LEAVE_BOTH_NOBUSY(); return DDERR_INVALIDPARAMS; } // check to see if the driver supports zbuffer blts if( !(*(lpbc->dwBothCaps) & DDCAPS_ZBLTS) ) { GETFAILCODEBLT( *(lpbc->dwCaps), *(lpbc->dwHELCaps), sbd.halonly, sbd.helonly, DDCAPS_ZBLTS ); if( fail ) { DPF_ERR( "ZBuffer blt requested, not supported" ); LEAVE_BOTH_NOBUSY(); return DDERR_NOZBUFFERHW; } } bd.bltFX.dwZBufferOpCode = lpDDBltFX->dwZBufferOpCode; if( dwFlags & DDBLT_ZBUFFERCONSTDESTOVERRIDE ) { if( dwFlags & (DDBLT_ZBUFFERDESTOVERRIDE) ) { DPF_ERR( "ZBUFFERCONSTDESTOVERRIDE and z surface specified" ); LEAVE_BOTH_NOBUSY(); return DDERR_INVALIDPARAMS; } bd.bltFX.dwConstZDest = lpDDBltFX->dwConstZDest; } else if( dwFlags & DDBLT_ZBUFFERDESTOVERRIDE ) { psurf_int = (LPDDRAWI_DDRAWSURFACE_INT) lpDDBltFX->lpDDSZBufferDest; if( !VALID_DIRECTDRAWSURFACE_PTR( psurf_int ) ) { DPF_ERR( "ZBUFFERSURFACEDESTOVERRIDE requires surface ptr" ); LEAVE_BOTH_NOBUSY(); return DDERR_INVALIDPARAMS; } psurf_lcl = psurf_int->lpLcl; if( SURFACE_LOST( psurf_lcl ) ) { LEAVE_BOTH_NOBUSY(); return DDERR_SURFACELOST; } bd.bltFX.lpDDSZBufferDest = (LPDIRECTDRAWSURFACE) psurf_lcl; } else { psurf_lcl = FindAttached( this_dest_lcl, DDSCAPS_ZBUFFER ); if( psurf_lcl == NULL ) { DPF_ERR( "ZBUFFER requires an attached Z to dest" ); LEAVE_BOTH_NOBUSY(); return DDERR_INVALIDPARAMS; } dwFlags |= DDBLT_ZBUFFERDESTOVERRIDE; bd.bltFX.lpDDSZBufferDest = (LPDIRECTDRAWSURFACE) psurf_lcl; } if( dwFlags & DDBLT_ZBUFFERCONSTSRCOVERRIDE ) { if( dwFlags & (DDBLT_ZBUFFERSRCOVERRIDE) ) { DPF_ERR( "ZBUFFERCONSTSRCOVERRIDE and z surface specified" ); LEAVE_BOTH_NOBUSY(); return DDERR_INVALIDPARAMS; } bd.bltFX.dwConstZSrc = lpDDBltFX->dwConstZSrc; } else if( dwFlags & DDBLT_ZBUFFERSRCOVERRIDE ) { psurf_int = (LPDDRAWI_DDRAWSURFACE_INT) lpDDBltFX->lpDDSZBufferSrc; if( !VALID_DIRECTDRAWSURFACE_PTR( psurf_int ) ) { DPF_ERR( "ZBUFFERSURFACESRCOVERRIDE requires surface ptr" ); LEAVE_BOTH_NOBUSY(); return DDERR_INVALIDPARAMS; } psurf_lcl = psurf_int->lpLcl if( SURFACE_LOST( psurf_lcl ) ) { LEAVE_BOTH_NOBUSY(); return DDERR_SURFACELOST; } bd.bltFX.lpDDSZBufferSrc = (LPDIRECTDRAWSURFACE) psurf_lcl; } else { psurf_lcl = FindAttached( this_src_lcl, DDSCAPS_ZBUFFER ); if( psurf_lcl == NULL ) { DPF_ERR( "ZBUFFER requires an attached Z to src" ); LEAVE_BOTH_NOBUSY(); return DDERR_INVALIDPARAMS; } dwFlags |= DDBLT_ZBUFFERSRCOVERRIDE; bd.bltFX.lpDDSZBufferSrc = (LPDIRECTDRAWSURFACE) psurf_lcl; } } #endif /* * verify color key overrides */ if( dwFlags & (DDBLT_KEYSRCOVERRIDE|DDBLT_KEYDESTOVERRIDE) ) { // see if the driver supports color key blts if( !(*(lpbc->dwBothCaps) & DDCAPS_COLORKEY) ) { GETFAILCODEBLT( *(lpbc->dwCaps), *(lpbc->dwHELCaps), sbd.halonly, sbd.helonly, DDCAPS_COLORKEY ); if( fail ) { DPF_ERR( "KEYOVERRIDE specified, not supported" ); LEAVE_BOTH_NOBUSY(); return DDERR_NOCOLORKEYHW; } } if( dwFlags & DDBLT_KEYSRCOVERRIDE ) { if( !(*(lpbc->dwBothCKeyCaps) & DDCKEYCAPS_SRCBLT) ) { GETFAILCODEBLT( *(lpbc->dwCKeyCaps), *(lpbc->dwHELCKeyCaps), sbd.halonly, sbd.helonly, DDCKEYCAPS_SRCBLT ); if( fail ) { DPF_ERR( "KEYSRCOVERRIDE specified, not supported" ); LEAVE_BOTH_NOBUSY(); return DDERR_NOCOLORKEYHW; } } bd.bltFX.ddckSrcColorkey = lpDDBltFX->ddckSrcColorkey; } if( dwFlags & DDBLT_KEYDESTOVERRIDE ) { if( !(*(lpbc->dwBothCKeyCaps) & DDCKEYCAPS_DESTBLT) ) { GETFAILCODEBLT( *(lpbc->dwCKeyCaps), *(lpbc->dwHELCKeyCaps), sbd.halonly, sbd.helonly, DDCKEYCAPS_DESTBLT ); if( fail ) { DPF_ERR( "KEYDESTOVERRIDE specified, not supported" ); LEAVE_BOTH_NOBUSY(); return DDERR_NOCOLORKEYHW; } } bd.bltFX.ddckDestColorkey = lpDDBltFX->ddckDestColorkey; dwDestLockFlags = 0; //meaning read/write } } /* * verify src color key */ if( dwFlags & DDBLT_KEYSRC ) { if( this_src == NULL ) { DPF_ERR( "KEYSRC specified, but no source data" ); LEAVE_BOTH_NOBUSY(); return DDERR_INVALIDOBJECT; } if( dwFlags & DDBLT_KEYSRCOVERRIDE ) { DPF_ERR( "KEYSRC specified with KEYSRCOVERRIDE" ); LEAVE_BOTH_NOBUSY(); return DDERR_INVALIDPARAMS; } if( !(this_src_lcl->dwFlags & DDRAWISURF_HASCKEYSRCBLT) ) { DPF_ERR( "KEYSRC specified, but no color key" ); DPF( 1, "srcFlags = %08lx", this_src_lcl->dwFlags ); LEAVE_BOTH_NOBUSY(); return DDERR_INVALIDPARAMS; } // make sure we can do this if( !(*(lpbc->dwBothCKeyCaps) & DDCKEYCAPS_SRCBLT) ) { GETFAILCODEBLT( *(lpbc->dwCKeyCaps), *(lpbc->dwHELCKeyCaps), sbd.halonly, sbd.helonly, DDCKEYCAPS_SRCBLT ); if( fail ) { DPF_ERR( "KEYSRC specified, not supported" ); LEAVE_BOTH_NOBUSY(); return DDERR_NOCOLORKEYHW; } } bd.bltFX.ddckSrcColorkey = this_src_lcl->ddckCKSrcBlt; dwFlags &= ~DDBLT_KEYSRC; dwFlags |= DDBLT_KEYSRCOVERRIDE; } /* * verify dest color key */ if( dwFlags & DDBLT_KEYDEST ) { if( dwFlags & DDBLT_KEYDESTOVERRIDE ) { DPF_ERR( "KEYDEST specified with KEYDESTOVERRIDE" ); LEAVE_BOTH_NOBUSY(); return DDERR_INVALIDPARAMS; } if( !(this_dest_lcl->dwFlags & DDRAWISURF_HASCKEYDESTBLT) ) { DPF_ERR( "KEYDEST specified, but no color key" ); LEAVE_BOTH_NOBUSY(); return DDERR_INVALIDPARAMS; } // make sure we can do this if( !(*(lpbc->dwBothCKeyCaps) & DDCKEYCAPS_DESTBLT) ) { GETFAILCODEBLT( *(lpbc->dwCKeyCaps), *(lpbc->dwHELCKeyCaps), sbd.halonly, sbd.helonly, DDCKEYCAPS_DESTBLT ); if( fail ) { DPF_ERR( "KEYDEST specified, not supported" ); LEAVE_BOTH_NOBUSY(); return DDERR_NOCOLORKEYHW; } } /* * This next part is bug that has existed since DX1. * We'd like to fix it, but we fear regression, so we * only fix it for surface 3 interfaces. */ if( ( this_src_int->lpVtbl == &ddSurfaceCallbacks ) || ( this_src_int->lpVtbl == &ddSurface2Callbacks ) ) { bd.bltFX.ddckDestColorkey = this_src_lcl->ddckCKDestBlt; } else { bd.bltFX.ddckDestColorkey = this_dest_lcl->ddckCKDestBlt; } dwFlags &= ~DDBLT_KEYDEST; dwFlags |= DDBLT_KEYDESTOVERRIDE; dwDestLockFlags = 0; //meaning read/write } } /* * verify various flags */ if( !(dwFlags &(DDBLT_ROP | DDBLT_COLORFILL | DDBLT_DDROPS | DDBLT_DEPTHFILL | DDBLT_ROTATIONANGLE | DDBLT_DDFX) ) ) { if( this_src == NULL ) { DPF_ERR( "Need a source for blt" ); LEAVE_BOTH_NOBUSY(); return DDERR_INVALIDPARAMS; } dwFlags |= DDBLT_ROP; bd.bltFX.dwROP = SRCCOPY; } /* * verify ROP */ else if( dwFlags & DDBLT_ROP ) { DWORD idx; DWORD bit; if( dwFlags & (DDBLT_DDFX | DDBLT_COLORFILL| DDBLT_DEPTHFILL| DDBLT_ROTATIONANGLE| DDBLT_DDROPS)) { DPF_ERR( "Invalid flags specified with ROP" ); LEAVE_BOTH_NOBUSY(); return DDERR_INVALIDPARAMS; } bd.bltFX.dwROP = lpDDBltFX->dwROP; rop = (DWORD) LOBYTE( HIWORD( bd.bltFX.dwROP ) ); idx = rop/32; bit = 1 << (rop % 32 ); DPF( 4, "Trying ROP %d, idx=%d, bit=%08lx", rop, idx, bit ); /* * We disable ROP flags on NT, so don't fail if they're only doing a SRCCOPY */ if( lpDDBltFX->dwROP != SRCCOPY ) { /* * see if both HEL & HAL support the ROP */ if( !(lpbc->dwBothRops[idx] & bit ) ) { GETFAILCODEBLT( lpbc->dwRops[idx], lpbc->dwHELRops[idx], sbd.halonly, sbd.helonly, bit ); if( fail ) { DPF_ERR( "ROP not supported" ); LEAVE_BOTH_NOBUSY(); return DDERR_NORASTEROPHW; } } } bd.dwROPFlags = cROPTable[ rop ]; if( bd.dwROPFlags & ROP_HAS_SOURCE ) { if( this_src == NULL ) { DPF_ERR( "ROP required a surface" ); LEAVE_BOTH_NOBUSY(); return DDERR_INVALIDPARAMS; } } if( bd.dwROPFlags & ROP_HAS_PATTERN ) { need_pat = TRUE; } } /* * verify COLORFILL */ else if( dwFlags & DDBLT_COLORFILL ) { if( this_src != NULL ) { DPF_ERR( "COLORFILL specified along with source surface" ); LEAVE_BOTH_NOBUSY(); return DDERR_INVALIDPARAMS; } /* * You cannot use COLORFILL to clear Z-buffers anymore. You must * explicitly use DEPTHFILL. Disallow Z-buffer destinations. */ if( this_dest_lcl->ddsCaps.dwCaps & DDSCAPS_ZBUFFER ) { DPF_ERR( "Z-Buffer cannot be target of a color fill blt" ); LEAVE_BOTH_NOBUSY(); return DDERR_INVALIDPARAMS; } if( !(*(lpbc->dwBothCaps) & DDCAPS_BLTCOLORFILL) ) { GETFAILCODEBLT( *(lpbc->dwCaps), *(lpbc->dwHELCaps), sbd.halonly, sbd.helonly, DDCAPS_BLTCOLORFILL ); if( fail ) { DPF_ERR( "COLORFILL specified, not supported" ); LEAVE_BOTH_NOBUSY(); return DDERR_UNSUPPORTED; } } /* * Maks off the high order bits of the colorfill * value since some drivers will fail if they're set. */ GET_PIXEL_FORMAT( this_dest_lcl, this_dest, pddpf ); if( pddpf->dwRGBBitCount <= 8 ) { lpDDBltFX->dwFillColor &= 0x00ff; } else if( pddpf->dwRGBBitCount == 16 ) { lpDDBltFX->dwFillColor &= 0x00ffff; } else if( pddpf->dwRGBBitCount == 24 ) { lpDDBltFX->dwFillColor &= 0x00ffffff; } bd.bltFX.dwFillColor = lpDDBltFX->dwFillColor; } /* * verify DEPTHFILL */ else if( dwFlags & DDBLT_DEPTHFILL ) { if( this_src != NULL ) { DPF_ERR( "DEPTHFILL specified along with source surface" ); LEAVE_BOTH_NOBUSY(); return DDERR_INVALIDPARAMS; } /* * Ensure the destination is a z-buffer. */ if( !( this_dest_lcl->ddsCaps.dwCaps & DDSCAPS_ZBUFFER ) ) { DPF_ERR( "DEPTHFILL specified but destination is not a Z-buffer" ); LEAVE_BOTH_NOBUSY(); return DDERR_INVALIDPARAMS; } if( !(*(lpbc->dwBothCaps) & DDCAPS_BLTDEPTHFILL) ) { GETFAILCODEBLT( *(lpbc->dwCaps), *(lpbc->dwHELCaps), sbd.halonly, sbd.helonly, DDCAPS_BLTDEPTHFILL ); if( fail ) { DPF_ERR( "DEPTHFILL specified, not supported" ); LEAVE_BOTH_NOBUSY(); return DDERR_UNSUPPORTED; } } bd.bltFX.dwFillDepth = lpDDBltFX->dwFillDepth; // hack to pass DepthBlt WriteMask to BlitLib bd.bltFX.dwZDestConstBitDepth = lpDDBltFX->dwZDestConstBitDepth; } /* * verify DDROPS */ else if( dwFlags & DDBLT_DDROPS ) { if( dwFlags & (DDBLT_DDFX | DDBLT_COLORFILL| DDBLT_DEPTHFILL| DDBLT_ROTATIONANGLE) ) { DPF_ERR( "Invalid flags specified with DDROPS" ); LEAVE_BOTH_NOBUSY(); return DDERR_INVALIDPARAMS; } bd.bltFX.dwDDROP = lpDDBltFX->dwDDROP; DPF_ERR( "DDROPS unsupported" ); LEAVE_BOTH_NOBUSY(); return DDERR_NODDROPSHW; } /* * verify DDFX */ else if( dwFlags & DDBLT_DDFX ) { if( dwFlags & (DDBLT_COLORFILL | DDBLT_DEPTHFILL | DDBLT_ROTATIONANGLE) ) { DPF_ERR( "Invalid flags specified with DDFX" ); LEAVE_BOTH_NOBUSY(); return DDERR_INVALIDPARAMS; } if( lpDDBltFX->dwDDFX & ( DDBLTFX_ARITHSTRETCHY ) ) { DPF_ERR( "DDBLTFX_ARITHSTRETCHY unsupported" ); LEAVE_BOTH_NOBUSY(); return DDERR_NOSTRETCHHW; } if( lpDDBltFX->dwDDFX & ( DDBLTFX_MIRRORLEFTRIGHT ) ) { GETFAILCODEBLT( *(lpbc->dwFXCaps), *(lpbc->dwHELFXCaps), sbd.halonly, sbd.helonly, DDFXCAPS_BLTMIRRORLEFTRIGHT ); if( fail ) { DPF_ERR( "Mirroring along vertical axis not supported" ); LEAVE_BOTH_NOBUSY(); return DDERR_NOMIRRORHW; } } if( lpDDBltFX->dwDDFX & ( DDBLTFX_MIRRORUPDOWN ) ) { GETFAILCODEBLT( *(lpbc->dwFXCaps), *(lpbc->dwHELFXCaps), sbd.halonly, sbd.helonly, DDFXCAPS_BLTMIRRORUPDOWN ); if( fail ) { DPF_ERR( "Mirroring along horizontal axis not supported" ); LEAVE_BOTH_NOBUSY(); return DDERR_NOMIRRORHW; } } if( lpDDBltFX->dwDDFX & ( DDBLTFX_ROTATE90 | DDBLTFX_ROTATE180 | DDBLTFX_ROTATE270 ) ) { GETFAILCODEBLT( *(lpbc->dwFXCaps), *(lpbc->dwHELFXCaps), sbd.halonly, sbd.helonly, DDFXCAPS_BLTROTATION90 ); if( fail ) { DPF_ERR( "90-degree rotations not supported" ); LEAVE_BOTH_NOBUSY(); return DDERR_NOROTATIONHW; } } bd.bltFX.dwDDFX = lpDDBltFX->dwDDFX; dwFlags |= DDBLT_ROP; bd.bltFX.dwROP = SRCCOPY; /* * verify ROTATIONANGLE */ } else if( dwFlags & DDBLT_ROTATIONANGLE ) { if( dwFlags & (DDBLT_COLORFILL | DDBLT_DEPTHFILL) ) { DPF_ERR( "Invalid flags specified with ROTATIONANGLE" ); LEAVE_BOTH_NOBUSY(); return DDERR_INVALIDPARAMS; } bd.bltFX.dwRotationAngle = lpDDBltFX->dwRotationAngle; DPF_ERR( "ROTATIONANGLE unsupported" ); LEAVE_BOTH_NOBUSY(); return DDERR_NOROTATIONHW; /* * you should have told me SOMETHING! */ } else { DPF_ERR( "no blt type specified!" ); LEAVE_BOTH_NOBUSY(); return DDERR_INVALIDPARAMS; } /* * no flags, we are doing a generic SRCCOPY */ } else { if( this_src == NULL ) { DPF_ERR( "Need a source for blt" ); LEAVE_BOTH_NOBUSY(); return DDERR_INVALIDPARAMS; } dwFlags |= DDBLT_ROP; bd.bltFX.dwROP = SRCCOPY; } /* * verify pattern */ if( need_pat ) { psurf_int = (LPDDRAWI_DDRAWSURFACE_INT) lpDDBltFX->lpDDSPattern; if( !VALID_DIRECTDRAWSURFACE_PTR( psurf_int ) ) { DPF_ERR( "Invalid pattern surface specified" ); LEAVE_BOTH_NOBUSY(); return DDERR_INVALIDOBJECT; } psurf_lcl = psurf_int->lpLcl; bd.bltFX.lpDDSPattern = (LPDIRECTDRAWSURFACE) psurf_lcl; if( SURFACE_LOST( psurf_lcl ) ) { LEAVE_BOTH_NOBUSY(); return DDERR_SURFACELOST; } #pragma message( REMIND( "What about general (non-8x8) patterns?" )) if( psurf_lcl->lpGbl->wHeight != 8 || psurf_lcl->lpGbl->wWidth != 8 ) { DPF_ERR( "Pattern surface must be 8 by 8" ); LEAVE_BOTH_NOBUSY(); return DDERR_INVALIDPARAMS; } dwFlags |= DDBLT_PRIVATE_ALIASPATTERN; } /* * make sure dest rect is OK */ if( lpDestRect != NULL ) { if( !VALID_RECT_PTR( lpDestRect ) ) { DPF_ERR( "Invalid dest rect specified" ); LEAVE_BOTH_NOBUSY(); return DDERR_INVALIDRECT; } bd.rDest = *(LPRECTL)lpDestRect; } else { MAKE_SURF_RECT( this_dest, this_dest_lcl, bd.rDest ); } /* * make sure src rect is OK */ if( lpSrcRect != NULL ) { if( !VALID_RECT_PTR( lpSrcRect ) ) { DPF_ERR( "Invalid src rect specified" ); LEAVE_BOTH_NOBUSY(); return DDERR_INVALIDRECT; } bd.rSrc = *(LPRECTL)lpSrcRect; } else { if( this_src != NULL ) { MAKE_SURF_RECT( this_src, this_src_lcl, bd.rSrc ); } } /* * get dimensions & check them */ stretch_blt = FALSE; sbd.dest_height = bd.rDest.bottom - bd.rDest.top; sbd.dest_width = bd.rDest.right - bd.rDest.left; // Need positive heights/widths if( ((int)sbd.dest_height <= 0) || ((int)sbd.dest_width <= 0) ) { DPF_ERR( "Invalid destination dimensions: Zero/Negative Heights and/or Widths not allowed"); DPF(0,"Erroneous dest dimensions were: (wid %d, hgt %d)",(int)sbd.dest_width,(int)sbd.dest_height); LEAVE_BOTH_NOBUSY(); return DDERR_INVALIDRECT; } // Is there a clipper? If so no more checks. if( this_dest_lcl->lpDDClipper == NULL ) { // Multi-mon: is this the primary for the desktop? This // is the only case where the upper-left coord of the surface is not // (0,0) if( (pdrv->dwFlags & DDRAWI_VIRTUALDESKTOP) && (this_dest_lcl->ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE) ) { if( (bd.rDest.left < pdrv->rectDesktop.left) || (bd.rDest.top < pdrv->rectDesktop.top) || (bd.rDest.right > pdrv->rectDesktop.right)|| (bd.rDest.bottom > pdrv->rectDesktop.bottom) ) { DPF_ERR( "Blt Destination doesn't fit on Desktop And No Clipper was specified" ); LEAVE_BOTH_NOBUSY(); return DDERR_INVALIDRECT; } if( OverlapsDevices( this_dest_lcl, (LPRECT) &bd.rDest ) ) { sbd.helonly = gdiblt = TRUE; } } else { if( (int)bd.rDest.left < 0 || (int)bd.rDest.top < 0 || (DWORD)bd.rDest.bottom > (DWORD)this_dest->wHeight || (DWORD)bd.rDest.right > (DWORD)this_dest->wWidth ) { DPF_ERR( "Invalid Blt destination dimensions" ); DPF(0, "width/height = %d x %d, dest rect = (%d, %d)-(%d, %d)", this_dest->wWidth, this_dest->wHeight, bd.rDest.left, bd.rDest.top, bd.rDest.right, bd.rDest.bottom); LEAVE_BOTH_NOBUSY(); return DDERR_INVALIDRECT; } } } else if( (pdrv->dwFlags & DDRAWI_VIRTUALDESKTOP) && (this_dest_lcl->ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE) ) { if( OverlapsDevices( this_dest_lcl, (LPRECT) &bd.rDest ) ) { sbd.helonly = gdiblt = TRUE; } } if( this_src != NULL ) { sbd.src_height = bd.rSrc.bottom - bd.rSrc.top; sbd.src_width = bd.rSrc.right - bd.rSrc.left; if( ((int)sbd.src_height <= 0) || ((int)sbd.src_width <= 0) ) { DPF_ERR( "BLT error. Can't have non-positive height or width" ); LEAVE_BOTH_NOBUSY(); return DDERR_INVALIDRECT; } // Multi-mon: is this the primary for the desktop? This // is the only case where the upper-left coord of the surface is not // (0,0) if( (this_src->lpDD->dwFlags & DDRAWI_VIRTUALDESKTOP) && (this_src_lcl->ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE) ) { if( (bd.rSrc.left < this_src->lpDD->rectDesktop.left) || (bd.rSrc.top < this_src->lpDD->rectDesktop.top) || (bd.rSrc.right > this_src->lpDD->rectDesktop.right)|| (bd.rSrc.bottom > this_src->lpDD->rectDesktop.bottom) ) { DPF_ERR( "Blt Source dimension doesn't fit on Desktop" ); LEAVE_BOTH_NOBUSY(); return DDERR_INVALIDRECT; } if( OverlapsDevices( this_src_lcl, (LPRECT) &bd.rSrc ) ) { sbd.helonly = gdiblt = TRUE; } } else { if( (int)bd.rSrc.left < 0 || (int)bd.rSrc.top < 0 || (DWORD)bd.rSrc.bottom > (DWORD)this_src->wHeight || (DWORD)bd.rSrc.right > (DWORD)this_src->wWidth ) { DPF_ERR( "Invalid Blt Source dimensions" ); LEAVE_BOTH_NOBUSY(); return DDERR_INVALIDRECT; } } /* * verify stretching... * */ if( sbd.src_height != sbd.dest_height || sbd.src_width != sbd.dest_width ) { HRESULT ddrval; ddrval = checkBltStretching( lpbc, &sbd ); if( ddrval != DD_OK ) { DPF_ERR( "Failed checkBltStretching" ); LEAVE_BOTH_NOBUSY(); return ddrval; } stretch_blt = TRUE; } } } EXCEPT( EXCEPTION_EXECUTE_HANDLER ) { DPF_ERR( "Exception encountered validating parameters" ); LEAVE_BOTH_NOBUSY(); return DDERR_INVALIDPARAMS; } /* * now shovel the data... */ TRY { /* * final bits of blt data */ bd.lpDDDestSurface = this_dest_lcl; bd.lpDDSrcSurface = this_src_lcl; bd.dwFlags = dwFlags; /* * Set up for a HAL or a HEL call */ if( pdrv_lcl->lpDDCB->HALDDSurface.Blt == NULL ) { sbd.helonly = TRUE; } if( sbd.helonly && sbd.halonly ) { DPF_ERR( "BLT not supported in software or hardware" ); LEAVE_BOTH_NOBUSY(); return DDERR_NOBLTHW; } // Did the mode change since ENTER_DDRAW? #ifdef WINNT if ( DdQueryDisplaySettingsUniqueness() != uDisplaySettingsUnique ) { // mode changed, don't do the blt DPF_ERR( "Mode changed between ENTER_DDRAW and HAL call" ); LEAVE_BOTH_NOBUSY() return DDERR_SURFACELOST; } if( !sbd.helonly ) { if (this_src_lcl && !this_src_lcl->hDDSurface && !CompleteCreateSysmemSurface(this_src_lcl)) { DPF_ERR("Can't blt from SYSTEM surface w/o Kernel Object"); LEAVE_BOTH_NOBUSY() return DDERR_GENERIC; } if (!this_dest_lcl->hDDSurface && !CompleteCreateSysmemSurface(this_dest_lcl)) { DPF_ERR("Can't blt to SYSTEM surface w/o Kernel Object"); LEAVE_BOTH_NOBUSY() return DDERR_GENERIC; } } #endif /* * Some drivers (like S3) do stuff in their BeginAccess call * that screws up stuff that they did in their DDHAL Lock Call. * * Exclusion needs to happen BEFORE the lock call to prevent this. * */ #if defined(WIN95) if( this_dest_lcl->lpDDClipper != NULL ) { /* * exclude the mouse cursor. * * we only need to do this for the windows display driver * * we only need to do this if we are blting to or from the * primary surface. * * we only do this in the clipping case, we figure if the * app cares enough to not scribble all over other windows * he also cares enough to not to wipe out the cursor. * * we only need to do this if the driver is using a * software cursor. * * NOTE * we should check and only do this on the primary? * we should make sure the clipper is window based? * we should check for the source being the primary? * */ if ( (pdrv->dwFlags & DDRAWI_DISPLAYDRV) && pdrv->dwPDevice && !(*pdrv->lpwPDeviceFlags & HARDWARECURSOR) && (this_dest->dwGlobalFlags & DDRAWISURFGBL_ISGDISURFACE) ) { if ( lpDDDestSurface == lpDDSrcSurface ) { RECTL rcl; UnionRect((RECT*)&rcl, (RECT*)&bd.rDest, (RECT*)&bd.rSrc); DD16_Exclude(pdrv->dwPDevice, &rcl); } else { DD16_Exclude(pdrv->dwPDevice, &bd.rDest); } } } #endif if( !sbd.helonly ) // must not be HEL call { DPF( 4, "Hardware Blt"); sbd.bltfn = pdrv_lcl->lpDDCB->HALDDSurface.Blt; bd.Blt = pdrv_lcl->lpDDCB->cbDDSurfaceCallbacks.Blt; /* * Take pagelocks if required */ dest_lock_taken = FALSE; src_lock_taken = FALSE; dest_pagelock_taken = FALSE; src_pagelock_taken = FALSE; if ( lpbc->bHALSeesSysmem ) { /* * If the HAL requires page locks... */ if ( !( pdrv->ddCaps.dwCaps2 & DDCAPS2_NOPAGELOCKREQUIRED ) ) { HRESULT hr; /* * ...then setup to take them if they're not already pagelocked. */ if ( ( this_dest_lcl->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY && this_dest_lcl->lpSurfMore->dwPageLockCount == 0 ) ) { hr = InternalPageLock( this_dest_lcl, pdrv_lcl ); if (FAILED(hr)) { LEAVE_BOTH_NOBUSY() return hr; } else { dest_pagelock_taken=TRUE; } } if ( this_src_lcl && ( this_src_lcl->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY && this_src_lcl->lpSurfMore->dwPageLockCount == 0 )) { hr = InternalPageLock( this_src_lcl, pdrv_lcl ); if (FAILED(hr)) { if (dest_pagelock_taken) InternalPageUnlock( this_dest_lcl, pdrv_lcl ); LEAVE_BOTH_NOBUSY() return hr; } else { src_pagelock_taken=TRUE; } } } } } /* * Blt the unclipped case */ if( this_dest_lcl->lpDDClipper == NULL ) { bd.IsClipped = FALSE; // no clipping // if hel only, check and take locks on video mem surfaces. if( sbd.helonly ) { sbd.bltfn = pdrv_lcl->lpDDCB->HELDDSurface.Blt; /* * take locks on vram surfaces */ if( !(this_dest_lcl->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY) && ( !gdiblt || !( this_dest_lcl->ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE ) ) ) { while( 1 ) { ddrval = InternalLock( this_dest_lcl, &dest_bits , NULL, dwDestLockFlags ); if( ddrval == DD_OK ) { GET_LPDDRAWSURFACE_GBL_MORE(this_dest)->fpNTAlias = (FLATPTR) dest_bits; break; } if( ddrval == DDERR_WASSTILLDRAWING ) { continue; } DONE_EXCLUDE(); (*pdflags) &= ~BUSY; LEAVE_BOTH(); return ddrval; } dest_lock_taken = TRUE; } else { /* * If this surface was involved in a hardware op, we need to * probe the driver to see if it's done. NOTE this assumes * that only one driver can be responsible for a system memory * operation. See comment with WaitForDriverToFinishWithSurface. */ if( this_dest->dwGlobalFlags & DDRAWISURFGBL_HARDWAREOPSTARTED ) { WaitForDriverToFinishWithSurface(pdrv_lcl, this_dest_lcl ); } dest_lock_taken = FALSE; } if( ( this_src != NULL) && (lpDDSrcSurface != lpDDDestSurface) && ( ( this_src_lcl->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY ) == 0) ) { while( 1 ) { ddrval = InternalLock( this_src_lcl, &src_bits, NULL, dwSourceLockFlags ); if( ddrval == DD_OK ) { GET_LPDDRAWSURFACE_GBL_MORE(this_src)->fpNTAlias = (FLATPTR) src_bits; break; } if( ddrval == DDERR_WASSTILLDRAWING ) { continue; } if( dest_lock_taken ) { InternalUnlock( this_dest_lcl,NULL,NULL,0 ); dest_lock_taken=FALSE; } DONE_EXCLUDE(); (*pdflags) &= ~BUSY; LEAVE_BOTH(); return ddrval; } src_lock_taken = TRUE; } else { /* * If this surface was involved in a hardware op, we need to * probe the driver to see if it's done. NOTE this assumes * that only one driver can be responsible for a system memory * operation. See comment with WaitForDriverToFinishWithSurface. */ if( this_src && ( this_src_lcl->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY ) && (this_src->dwGlobalFlags & DDRAWISURFGBL_HARDWAREOPSTARTED) ) { WaitForDriverToFinishWithSurface(pdrv_lcl, this_src_lcl ); } src_lock_taken = FALSE; } } /* * Add a rect to the region list if this is a managed surface */ if(IsD3DManaged(this_dest_lcl)) { LPREGIONLIST lpRegionList = this_dest_lcl->lpSurfMore->lpRegionList; if(lpDestRect) { if(lpRegionList->rdh.nCount != NUM_RECTS_IN_REGIONLIST) { lpRegionList->rect[(lpRegionList->rdh.nCount)++] = bd.rDest; lpRegionList->rdh.nRgnSize += sizeof(RECT); if(bd.rDest.left < lpRegionList->rdh.rcBound.left) lpRegionList->rdh.rcBound.left = bd.rDest.left; if(bd.rDest.right > lpRegionList->rdh.rcBound.right) lpRegionList->rdh.rcBound.right = bd.rDest.right; if(bd.rDest.top < lpRegionList->rdh.rcBound.top) lpRegionList->rdh.rcBound.top = bd.rDest.top; if(bd.rDest.bottom > lpRegionList->rdh.rcBound.bottom) lpRegionList->rdh.rcBound.bottom = bd.rDest.bottom; } } else { /* Mark everything dirty */ lpRegionList->rdh.nCount = NUM_RECTS_IN_REGIONLIST; } } try_again: if( sbd.helonly ) { // Release busy now or GDI blt will fail DONE_BUSY(); } if (bd.dwFlags & DDBLT_PRESENTATION) { bd.dwFlags |= DDBLT_LAST_PRESENTATION; } DOHALCALL_NOWIN16( Blt, sbd.bltfn, bd, rc, sbd.helonly ); #ifdef WINNT if (rc == DDHAL_DRIVER_HANDLED && bd.ddRVal == DDERR_VISRGNCHANGED) { DPF(5,"Resetting VisRgn for surface %x", this_dest_lcl); DdResetVisrgn(this_dest_lcl, (HWND)0); goto try_again; } #endif if ( rc == DDHAL_DRIVER_HANDLED ) { if ( (dwFlags & DDBLT_WAIT) && bd.ddRVal == DDERR_WASSTILLDRAWING ) { DPF(4, "Waiting....."); goto try_again; } /* * Note that the !helonly here is pretty much an assert. * Thought it safer to actually test it, since that is actually what we mean. */ if( !sbd.helonly && lpbc->bHALSeesSysmem && (bd.ddRVal == DD_OK) ) { DPF(5,B,"Tagging surface %08x",this_dest); if (this_dest_lcl->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY) this_dest->dwGlobalFlags |= DDRAWISURFGBL_HARDWAREOPDEST; if (this_src) { DPF(5,B,"Tagging surface %08x",this_src); if (this_src_lcl->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY) this_src->dwGlobalFlags |= DDRAWISURFGBL_HARDWAREOPSOURCE; } } } } else { /* * Blt when the destination is clipped */ DWORD cnt; DWORD total; LPRECT prect; DWORD size; LPRGNDATA prd=(LPRGNDATA)0; int x_offset; int y_offset; DWORD scale_x; DWORD scale_y; RECT rSurfDst; // Keep a flag to indicate whether we need to free 'prd' or not BOOL fMustFreeRegion = FALSE; // Use a stack buffer for most clipping cases BYTE buffer[sizeof(RGNDATAHEADER) + NUM_RECTS_IN_REGIONLIST * sizeof(RECTL)]; bd.rOrigSrc = bd.rSrc; bd.rOrigDest = bd.rDest; #ifdef WINNT // For NT, we need to deal with a clip-list change // at many different points of the BLT get_clipping_info: if ( fMustFreeRegion ) { MemFree( prd ); prd = NULL; fMustFreeRegion = FALSE; } #endif bd.IsClipped = TRUE; // yes, we are clipping // Call the internal GetClipList which avoids the checking DDASSERT( !fMustFreeRegion ); prd = (LPRGNDATA)&buffer[0]; size = sizeof(buffer); ddrval = InternalGetClipList( (LPDIRECTDRAWCLIPPER) this_dest_lcl->lpSurfMore->lpDDIClipper, (LPRECT)&bd.rOrigDest, prd, &size, pdrv ); // Fatal error? if( ddrval != DD_OK && ddrval != DDERR_REGIONTOOSMALL ) { DPF_ERR( "GetClipList FAILED" ); DONE_LOCKS(); DONE_EXCLUDE(); if (dest_pagelock_taken) InternalPageUnlock( this_dest_lcl, pdrv_lcl ); if (src_pagelock_taken) InternalPageUnlock( this_src_lcl, pdrv_lcl ); LEAVE_BOTH_NOBUSY(); return ddrval; } if ( size <= sizeof(RGNDATA) ) { DPF( 4, "Totally clipped" ); rc = DDHAL_DRIVER_HANDLED; bd.ddRVal = DD_OK; goto null_clip_rgn; } // If the clip region is larger than our stack buffer, // then allocate a buffer if ( size > sizeof(buffer) ) { DDASSERT( !fMustFreeRegion ); prd = MemAlloc( size ); if( prd == NULL ) { DONE_LOCKS(); DONE_EXCLUDE(); if (dest_pagelock_taken) InternalPageUnlock( this_dest_lcl, pdrv_lcl ); if (src_pagelock_taken) InternalPageUnlock( this_src_lcl, pdrv_lcl ); LEAVE_BOTH_NOBUSY(); return DDERR_OUTOFMEMORY; } fMustFreeRegion = TRUE; ddrval = InternalGetClipList( (LPDIRECTDRAWCLIPPER) this_dest_lcl->lpSurfMore->lpDDIClipper, (LPRECT)&bd.rOrigDest, prd, &size, pdrv ); if( ddrval != DD_OK ) { #ifdef WINNT if( ddrval == DDERR_REGIONTOOSMALL ) { // the visrgn changed between the first and second calls to GetClipList. // try again. DDASSERT( fMustFreeRegion ); MemFree( prd ); prd = NULL; fMustFreeRegion = FALSE; goto get_clipping_info; } #else // Region can't change size on Win95! We took a lock! DDASSERT( ddrval != DDERR_REGIONTOOSMALL ); #endif DPF_ERR( "GetClipList FAILED" ); DDASSERT( fMustFreeRegion ); MemFree( prd ); DONE_LOCKS(); DONE_EXCLUDE(); if (dest_pagelock_taken) InternalPageUnlock( this_dest_lcl, pdrv_lcl ); if (src_pagelock_taken) InternalPageUnlock( this_src_lcl, pdrv_lcl ); LEAVE_BOTH_NOBUSY(); return ddrval; } } // Clip region to surface dimensions MAKE_SURF_RECT( this_dest, this_dest_lcl, rSurfDst ); // Clip the regiondata the we have down to // the surface that we care about. Prevents // memory trashing. if( !gdiblt ) { ClipRgnToRect( &rSurfDst, prd ); } total = prd->rdh.nCount; DPF( 5, "total vis rects = %ld", total ); prect = (LPRECT) &prd->Buffer[0]; rc = DDHAL_DRIVER_HANDLED; bd.ddRVal = DD_OK; // if hel only, check and take locks on video mem surfaces. if( sbd.helonly ) { sbd.bltfn = pdrv_lcl->lpDDCB->HELDDSurface.Blt; /* * take locks on vram surfaces */ if( !(this_dest_lcl->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY) && ( !gdiblt || !( this_dest_lcl->ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE ) ) ) { while( 1 ) { DPF(5,"Locking dest: %x", this_dest_lcl); #ifdef WINNT /* * On Win2K, locking the entire primary is expensive as it often causes GDI * to needlessly rebuild it's sprites. Hence, we will only lock the rect * that we actually care about. */ if( this_dest_lcl->ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE ) { ddrval = InternalLock( this_dest_lcl, &dest_bits, (LPRECT)&bd.rDest, DDLOCK_FAILONVISRGNCHANGED | dwDestLockFlags ); if( ddrval == DD_OK ) { subrect_lock_taken = TRUE; subrect_lock_rect.left = bd.rDest.left; subrect_lock_rect.right = bd.rDest.right; subrect_lock_rect.top = bd.rDest.top; subrect_lock_rect.bottom = bd.rDest.bottom; } } else { #endif ddrval = InternalLock( this_dest_lcl, &dest_bits , NULL, DDLOCK_FAILONVISRGNCHANGED | dwDestLockFlags ); #ifdef WINNT } if (ddrval == DDERR_VISRGNCHANGED) { DPF(5,"Resetting VisRgn for surface %x", this_dest_lcl); DdResetVisrgn(this_dest_lcl, (HWND)0); DONE_LOCKS(); //should do nothing... here for ortho goto get_clipping_info; } #endif if( ddrval == DD_OK ) { GET_LPDDRAWSURFACE_GBL_MORE(this_dest)->fpNTAlias = (FLATPTR) dest_bits; break; } if( ddrval == DDERR_WASSTILLDRAWING ) { continue; } if( fMustFreeRegion ) MemFree( prd ); DONE_LOCKS(); DONE_EXCLUDE(); (*pdflags) &= ~BUSY; LEAVE_BOTH(); return ddrval; } dest_lock_taken = TRUE; } else { /* * If this surface was involved in a hardware op, we need to * probe the driver to see if it's done. NOTE this assumes * that only one driver can be responsible for a system memory * operation. See comment with WaitForDriverToFinishWithSurface. */ if( (this_dest_lcl->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY) && (this_dest->dwGlobalFlags & DDRAWISURFGBL_HARDWAREOPSTARTED) ) { WaitForDriverToFinishWithSurface(pdrv_lcl, this_dest_lcl ); } dest_lock_taken = FALSE; } if( ( this_src != NULL) && (lpDDSrcSurface != lpDDDestSurface) && ( ( this_src_lcl->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY ) == 0) ) { while( 1 ) { DPF(5,"Locking src: %x", this_src_lcl); ddrval = InternalLock( this_src_lcl, &src_bits , NULL, DDLOCK_FAILONVISRGNCHANGED | dwSourceLockFlags ); #ifdef WINNT if (ddrval == DDERR_VISRGNCHANGED) { DPF(5,"Resetting VisRgn for surface %x", this_dest_lcl); DdResetVisrgn(this_dest_lcl, (HWND)0); DONE_LOCKS(); goto get_clipping_info; } #endif if( ddrval == DD_OK ) { GET_LPDDRAWSURFACE_GBL_MORE(this_src)->fpNTAlias = (FLATPTR) src_bits; break; } if( ddrval == DDERR_WASSTILLDRAWING ) { continue; } if( fMustFreeRegion ) MemFree( prd ); DONE_LOCKS(); DONE_EXCLUDE(); (*pdflags) &= ~BUSY; LEAVE_BOTH(); return ddrval; } src_lock_taken = TRUE; } else { /* * If this surface was involved in a hardware op, we need to * probe the driver to see if it's done. NOTE this assumes * that only one driver can be responsible for a system memory * operation. See comment with WaitForDriverToFinishWithSurface. */ if( this_src && (this_src_lcl->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY) && (this_src->dwGlobalFlags & DDRAWISURFGBL_HARDWAREOPSTARTED) ) { WaitForDriverToFinishWithSurface(pdrv_lcl, this_src_lcl ); } src_lock_taken = FALSE; } } /* * See if the driver wants to do the clipping */ if( (stretch_blt && (*(lpbc->dwCaps) & DDCAPS_CANCLIPSTRETCHED)) || (!stretch_blt && (*(lpbc->dwCaps) & DDCAPS_CANCLIP)) ) { // The driver will do the clipping bd.dwRectCnt = total; bd.prDestRects = prect; if(IsD3DManaged(this_dest_lcl)) { /* We don't want to deal with this mess, so mark everything dirty */ this_dest_lcl->lpSurfMore->lpRegionList->rdh.nCount = NUM_RECTS_IN_REGIONLIST; } /* * pass the whole mess off to the driver */ drvclip_try_again: if( sbd.helonly ) { // Release busy now or GDI blt will fail DONE_BUSY(); } if (bd.dwFlags & DDBLT_PRESENTATION) { bd.dwFlags |= DDBLT_LAST_PRESENTATION; } #ifdef WINNT if (subrect_lock_taken) { // If we took a subrect lock on the primary, we need // to adjust the dest rect so the HEL will draw it // in the right spot. We couldn't do it before because // the above stretch code reuqires the corfrect rect. bd.rDest.right -= subrect_lock_rect.left; bd.rDest.left -= subrect_lock_rect.left; bd.rDest.bottom -= subrect_lock_rect.top; bd.rDest.top -= subrect_lock_rect.top; } #endif DOHALCALL_NOWIN16( Blt, sbd.bltfn, bd, rc, sbd.helonly ); #ifdef WINNT if (subrect_lock_taken) { // Adjust it back so we don't screw anything up. bd.rDest.right += subrect_lock_rect.left; bd.rDest.left += subrect_lock_rect.left; bd.rDest.bottom += subrect_lock_rect.top; bd.rDest.top += subrect_lock_rect.top; } #endif if( rc == DDHAL_DRIVER_HANDLED ) { #ifdef WINNT if (bd.ddRVal == DDERR_VISRGNCHANGED) { DONE_LOCKS(); DPF(5,"Resetting VisRgn for surface %x", this_dest_lcl); DdResetVisrgn(this_dest_lcl, (HWND)0); goto get_clipping_info; } #endif if ( (dwFlags & DDBLT_WAIT) && bd.ddRVal == DDERR_WASSTILLDRAWING ) { DPF(4, "Waiting....."); goto drvclip_try_again; } /* * Only mark the surface as in use by the hardware if we didn't wait for it * to finish and it succeeded. Don't mark it if it's HEL, since * the HEL will never be asynchronous. */ if( !sbd.helonly && lpbc->bHALSeesSysmem && (bd.ddRVal == DD_OK) ) { DPF(5,B,"Tagging surface %08x",this_dest); if (this_dest_lcl->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY) this_dest->dwGlobalFlags |= DDRAWISURFGBL_HARDWAREOPDEST; if (this_src) { DPF(5,B,"Tagging surface %08x",this_src); if (this_src_lcl->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY) this_src->dwGlobalFlags |= DDRAWISURFGBL_HARDWAREOPSOURCE; } } } } else { // We will do the clipping bd.dwRectCnt =1; bd.prDestRects = (LPVOID)&(bd.rDest); // precalculate a couple of variables if( !stretch_blt ) { x_offset = bd.rSrc.left - bd.rDest.left; y_offset = bd.rSrc.top - bd.rDest.top; } else { // scale_x and scale_y are fixed point variables scaled // 16.16 (16 integer bits and 16 fractional bits) scale_x = ((bd.rSrc.right - bd.rSrc.left) << 16) / (bd.rDest.right - bd.rDest.left); scale_y = ((bd.rSrc.bottom - bd.rSrc.top) << 16) / (bd.rDest.bottom - bd.rDest.top); } /* * traverse the visible rect list and send each piece to * the driver to blit. */ for( cnt=0;cntleft; bd.rDest.right = prect->right; bd.rDest.top = prect->top; bd.rDest.bottom = prect->bottom; bd.rSrc.left = bd.rDest.left + x_offset; bd.rSrc.right = bd.rDest.right + x_offset; bd.rSrc.top = bd.rDest.top + y_offset; bd.rSrc.bottom = bd.rDest.bottom + y_offset; } else { // stretching // linear mapping from source to destination bd.rDest.left = prect->left; bd.rDest.right = prect->right; bd.rDest.top = prect->top; bd.rDest.bottom = prect->bottom; // calculate the source rect which transforms to the // dest rect XformRect( (RECT *)&(bd.rOrigSrc), (RECT *)&(bd.rOrigDest), (RECT *)prect, (RECT *)&(bd.rSrc), scale_x, scale_y ); } /* * Add a rect to the region list if this is a managed surface */ if(IsD3DManaged(this_dest_lcl)) { LPREGIONLIST lpRegionList = this_dest_lcl->lpSurfMore->lpRegionList; if(lpRegionList->rdh.nCount != NUM_RECTS_IN_REGIONLIST) { lpRegionList->rect[(lpRegionList->rdh.nCount)++] = bd.rDest; lpRegionList->rdh.nRgnSize += sizeof(RECT); if(bd.rDest.left < lpRegionList->rdh.rcBound.left) lpRegionList->rdh.rcBound.left = bd.rDest.left; if(bd.rDest.right > lpRegionList->rdh.rcBound.right) lpRegionList->rdh.rcBound.right = bd.rDest.right; if(bd.rDest.top < lpRegionList->rdh.rcBound.top) lpRegionList->rdh.rcBound.top = bd.rDest.top; if(bd.rDest.bottom > lpRegionList->rdh.rcBound.bottom) lpRegionList->rdh.rcBound.bottom = bd.rDest.bottom; } } /* * blt this little piece */ clip_try_again: if( sbd.helonly ) { // Release busy now or GDI blt will fail DONE_BUSY(); } // If mirror Blt, we must fix up source rect here! if (bd.dwFlags & DDBLT_DDFX) { int temp; if (bd.bltFX.dwDDFX & DDBLTFX_MIRRORLEFTRIGHT) { temp = bd.rSrc.left; bd.rSrc.left = bd.rOrigSrc.left + bd.rOrigSrc.right - bd.rSrc.right; bd.rSrc.right = bd.rOrigSrc.left + bd.rOrigSrc.right - temp; } if (bd.bltFX.dwDDFX & DDBLTFX_MIRRORUPDOWN) { temp = bd.rSrc.top; bd.rSrc.top = bd.rOrigSrc.top + bd.rOrigSrc.bottom - bd.rSrc.bottom; bd.rSrc.bottom = bd.rOrigSrc.top + bd.rOrigSrc.bottom - temp; } } if (bd.dwFlags & DDBLT_PRESENTATION) { if (cnt == total-1) { bd.dwFlags |= DDBLT_LAST_PRESENTATION; } } #ifdef WINNT if (subrect_lock_taken) { // Adjust the dest rect so the HEL will draw to the // right place. bd.rDest.right -= subrect_lock_rect.left; bd.rDest.left -= subrect_lock_rect.left; bd.rDest.bottom -= subrect_lock_rect.top; bd.rDest.top -= subrect_lock_rect.top; } #endif DOHALCALL_NOWIN16( Blt, sbd.bltfn, bd, rc, sbd.helonly ); #ifdef WINNT if (subrect_lock_taken) { // Adjust it back so we don't screw anything up. bd.rDest.right += subrect_lock_rect.left; bd.rDest.left += subrect_lock_rect.left; bd.rDest.bottom += subrect_lock_rect.top; bd.rDest.top += subrect_lock_rect.top; } #endif if( rc == DDHAL_DRIVER_HANDLED ) { #ifdef WINNT if (bd.ddRVal == DDERR_VISRGNCHANGED) { DONE_LOCKS(); DPF(5,"Resetting VisRgn for surface %x", this_dest_lcl); DdResetVisrgn(this_dest_lcl, (HWND)0); /* * restore original source rect if vis region * changed, for mirrored/clipped cases */ bd.rSrc=bd.rOrigSrc; bd.rDest=bd.rOrigDest; goto get_clipping_info; } #endif /* * NOTE: If clipping has introduced more than * one rectangle we behave as if DDBLT_WAIT * was specified on all rectangles after the * first. This is necessary as the first * rectangle will probably cause the accelerator * to be busy. Hence, the attempt to blit the * second rectangle will fail with * DDERR_WASSTILLDRAWING. If we pass this to * the application (rather than busy waiting) * the application is likely to retry the blit * (which will fail on the second rectangle again) * and we have an application sitting in an * infinite loop). */ if ( ( (dwFlags & DDBLT_WAIT) || (cnt > 0) ) && bd.ddRVal == DDERR_WASSTILLDRAWING ) { DPF(4, "Waiting....."); goto clip_try_again; } if( bd.ddRVal != DD_OK ) { break; } /* * Only mark the surface as in use by the hardware if we didn't wait for it * to finish and it succeeded. Only mark surfaces if it's not the HEL * because the HEL is never async. */ if( !sbd.helonly && lpbc->bHALSeesSysmem ) { DPF(5,B,"Tagging surface %08x",this_dest); if (this_dest_lcl->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY) this_dest->dwGlobalFlags |= DDRAWISURFGBL_HARDWAREOPDEST; if (this_src) { DPF(5,B,"Tagging surface %08x",this_src); if (this_src_lcl->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY) this_src->dwGlobalFlags |= DDRAWISURFGBL_HARDWAREOPSOURCE; } } } /* * next clipping rect */ prect++; } } if( fMustFreeRegion ) MemFree( prd ); null_clip_rgn: ; } DONE_LOCKS(); /* * Exclusion needs to happen after unlock call */ DONE_EXCLUDE(); if( rc != DDHAL_DRIVER_HANDLED ) { /* * did the driver run out of hardware color key resources? */ if( (rc == DDHAL_DRIVER_NOCKEYHW) && (dwFlags & DDBLT_KEYSRCOVERRIDE) ) { ddrval = ChangeToSoftwareColorKey( this_src_int, FALSE ); if( ddrval == DD_OK ) { sbd.halonly = FALSE; sbd.helonly = FALSE; if (src_pagelock_taken) { src_pagelock_taken = FALSE; InternalPageUnlock(this_src_lcl, pdrv_lcl); } if (dest_pagelock_taken) { dest_pagelock_taken = FALSE; InternalPageUnlock(this_dest_lcl, pdrv_lcl); } goto RESTART_BLT; } else { bd.ddRVal = DDERR_NOCOLORKEYHW; } } else { bd.ddRVal = DDERR_UNSUPPORTED; } } DONE_BUSY(); /* * Maintain old behaviour for old drivers (which do not export the * GetSysmemBltStatus HAL call) and just spin until they're done. * Any alternative could exercise new code paths in the driver * (e.g. reentered for a DMA operation) */ if ( lpbc->bHALSeesSysmem && (NULL == pdrv_lcl->lpDDCB->HALDDMiscellaneous.GetSysmemBltStatus || dest_pagelock_taken || src_pagelock_taken) ) { if( this_src->dwGlobalFlags & DDRAWISURFGBL_HARDWAREOPSTARTED ) { /* * Wait on the destination surface only */ DDASSERT(this_src && this_src_lcl->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY); while (DDERR_WASSTILLDRAWING == InternalGetBltStatus(pdrv_lcl, this_dest_lcl, DDGBS_ISBLTDONE)) ; this_src_lcl->lpGbl->dwGlobalFlags &= ~DDRAWISURFGBL_HARDWAREOPSTARTED; this_dest_lcl->lpGbl->dwGlobalFlags &= ~DDRAWISURFGBL_HARDWAREOPSTARTED; } /* * Unpagelock if we took the pagelocks */ if (dest_pagelock_taken) InternalPageUnlock(this_dest_lcl, pdrv_lcl); if (src_pagelock_taken) InternalPageUnlock(this_src_lcl, pdrv_lcl); } if(IsD3DManaged(this_dest_lcl)) MarkDirty(this_dest_lcl); LEAVE_BOTH(); return bd.ddRVal; } EXCEPT( EXCEPTION_EXECUTE_HANDLER ) { DPF_ERR( "Exception encountered doing blt" ); DONE_LOCKS(); DONE_EXCLUDE(); DONE_BUSY(); /* * Maintain old behaviour for old drivers (which do not export the * GetSysmemBltStatus HAL call) and just spin until they're done. * Any alternative could exercise new code paths in the driver * (e.g. reentered for a DMA operation) */ if ( lpbc->bHALSeesSysmem && (NULL == pdrv_lcl->lpDDCB->HALDDMiscellaneous.GetSysmemBltStatus || dest_pagelock_taken || src_pagelock_taken) ) { if( this_src->dwGlobalFlags & DDRAWISURFGBL_HARDWAREOPSTARTED ) { /* * Wait on the destination surface only */ DDASSERT(this_src && this_src_lcl->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY); while (DDERR_WASSTILLDRAWING == InternalGetBltStatus(pdrv_lcl, this_dest_lcl, DDGBS_ISBLTDONE)) ; this_src_lcl->lpGbl->dwGlobalFlags &= ~DDRAWISURFGBL_HARDWAREOPSTARTED; this_dest_lcl->lpGbl->dwGlobalFlags &= ~DDRAWISURFGBL_HARDWAREOPSTARTED; } /* * Unpagelock if we took the pagelocks */ if (dest_pagelock_taken) InternalPageUnlock(this_dest_lcl, pdrv_lcl); if (src_pagelock_taken) InternalPageUnlock(this_src_lcl, pdrv_lcl); } LEAVE_BOTH(); return DDERR_EXCEPTION; } } /* DD_Surface_Blt */ #undef DPF_MODNAME #define DPF_MODNAME "BltBatch" /* * DD_Surface_BltBatch * * BitBlt a whole pile of surfaces */ HRESULT DDAPI DD_Surface_BltBatch( LPDIRECTDRAWSURFACE lpDDDestSurface, LPDDBLTBATCH lpDDBltBatch, DWORD dwCount, DWORD dwFlags ) { LPDDRAWI_DDRAWSURFACE_LCL this_src_lcl; LPDDRAWI_DDRAWSURFACE_LCL this_dest_lcl; LPDDRAWI_DDRAWSURFACE_INT this_src_int; LPDDRAWI_DDRAWSURFACE_INT this_dest_int; HRESULT ddrval; int i; ENTER_BOTH(); DPF(2,A,"ENTERAPI: DD_Surface_BltBatch"); /* * validate surface ptrs */ this_dest_int = (LPDDRAWI_DDRAWSURFACE_INT) lpDDDestSurface; if( !VALID_DIRECTDRAWSURFACE_PTR( this_dest_int ) ) { DPF_ERR( "Invalid dest specified") ; LEAVE_BOTH(); return DDERR_INVALIDOBJECT; } this_dest_lcl = this_dest_int->lpLcl; if( SURFACE_LOST( this_dest_lcl ) ) { DPF( 1, "Dest lost") ; LEAVE_BOTH(); return DDERR_SURFACELOST; } if( this_dest_lcl->lpGbl->dwUsageCount > 0 ) { DPF( 1, "Dest surface %08lx is still locked", this_dest_int ); LEAVE_BOTH(); return DDERR_SURFACEBUSY; } /* * validate BltBatch ptr */ if( !VALID_DDBLTBATCH_PTR( lpDDBltBatch ) ) { DPF( 1, "Invalid Blt batch ptr" ); LEAVE_BOTH(); return DDERR_INVALIDPARAMS; } /* * validate blt batch params */ for( i=0;i<(int)dwCount;i++ ) { /* * validate dest rect */ if( lpDDBltBatch[i].lprDest != NULL ) { if( !VALID_RECT_PTR(lpDDBltBatch[i].lprDest) ) { DPF( 1, "dest rectangle invalid, entry %d", i ); LEAVE_BOTH(); return DDERR_INVALIDRECT; } } /* * validate source surface */ this_src_int = (LPDDRAWI_DDRAWSURFACE_INT)lpDDBltBatch[i].lpDDSSrc; if( this_src_int != NULL ) { if( !VALID_DIRECTDRAWSURFACE_PTR( this_src_int ) ) { DPF( 1, "Invalid source specified, entry %d", i ); LEAVE_BOTH(); return DDERR_INVALIDOBJECT; } this_src_lcl = this_src_int->lpLcl; if( SURFACE_LOST( this_src_lcl ) ) { DPF( 1, "Src lost, entry %d", i) ; LEAVE_BOTH(); return DDERR_SURFACELOST; } if( this_src_lcl->lpGbl->dwUsageCount > 0 ) { DPF( 2, "Source surface %08lx is still locked, entry %d", this_src_int, i ); LEAVE_BOTH(); return DDERR_SURFACEBUSY; } if (this_src_lcl->ddsCaps.dwCaps & DDSCAPS_OPTIMIZED) { DPF_ERR( "It is an optimized surface" ); LEAVE_DDRAW(); return DDERR_ISOPTIMIZEDSURFACE; } } if (this_dest_lcl->ddsCaps.dwCaps & DDSCAPS_OPTIMIZED) { DPF_ERR( "It is an optimized surface" ); LEAVE_DDRAW(); return DDERR_ISOPTIMIZEDSURFACE; } /* * validate src rect */ if( lpDDBltBatch[i].lprSrc != NULL ) { if( !VALID_RECT_PTR(lpDDBltBatch[i].lprSrc) ) { DPF( 1, "src rectangle invalid, entry %d", i ); LEAVE_BOTH(); return DDERR_INVALIDRECT; } } /* * validate bltfx ptr */ if( lpDDBltBatch[i].lpDDBltFx != NULL ) { if( !VALID_DDBLTFX_PTR( lpDDBltBatch[i].lpDDBltFx ) ) { DPF( 1, "Invalid BLTFX specified, entry %d", i ); LEAVE_BOTH(); return DDERR_INVALIDPARAMS; } } else { if( lpDDBltBatch[i].dwFlags & ( DDBLT_ALPHASRCCONSTOVERRIDE | DDBLT_ALPHADESTCONSTOVERRIDE | DDBLT_ALPHASRCSURFACEOVERRIDE | DDBLT_ALPHADESTSURFACEOVERRIDE | DDBLT_COLORFILL | DDBLT_DDFX | DDBLT_DDROPS | DDBLT_DEPTHFILL | DDBLT_KEYDESTOVERRIDE | DDBLT_KEYSRCOVERRIDE | DDBLT_ROP | DDBLT_ROTATIONANGLE | DDBLT_ZBUFFERDESTCONSTOVERRIDE | DDBLT_ZBUFFERDESTOVERRIDE | DDBLT_ZBUFFERSRCCONSTOVERRIDE | DDBLT_ZBUFFERSRCOVERRIDE ) ) { DPF( 1, "BltFX required but not specified, entry %d", i ); LEAVE_BOTH(); return DDERR_INVALIDPARAMS; } } } ddrval = DDERR_UNSUPPORTED; for( i=0;i<(int)dwCount;i++ ) { #if 0 while( 1 ) { ddrval = doBlt( this_dest_lcl, lpDDBltBatch[i].lprDest, lpDDBltBatch[i].lpDDSSrc, lpDDBltBatch[i].lprSrc, lpDDBltBatch[i].dwFlags, lpDDBltBatch[i].lpDDBltFX ); if( ddrval != DDERR_WASSTILLDRAWING ) { break; } } #endif if( ddrval != DD_OK ) { break; } } LEAVE_BOTH(); return ddrval; } /* BltBatch */ /* * XformRect * * Transform a clipped rect in destination space to the corresponding clipped * rect in src space. So, if we're stretching from src to dest, this yields * the unstretched clipping rect in src space. * * PARAMETERS: * prcSrc - unclipped rect in the source space * prcDest - unclipped rect in the destination space * prcClippedDest - the rect we want to transform * prcClippedSrc - the resulting rect in the source space. return value. * scale_x - 16.16 fixed point src/dest width ratio * scale_y - 16.16 fixed point src/dest height ratio * * DESCRIPTION: * Given an rect in source space and a rect in destination space, and a * clipped rectangle in the destination space (prcClippedDest), return * the rectangle in the source space (prcClippedSrc) that maps to * prcClippedDest. * * Use 16.16 fixed point math for more accuracy. (Shift left, do math, * shift back (w/ round)) * * RETURNS: * DD_OK always. prcClippedSrc is the mapped rectangle. * */ HRESULT XformRect(RECT * prcSrc, RECT * prcDest, RECT * prcClippedDest, RECT * prcClippedSrc, DWORD scale_x, DWORD scale_y) { /* * This first calculation is done with fixed point arithmetic (16.16). * The result is converted to (32.0) below. Scale back into source space */ prcClippedSrc->left = (prcClippedDest->left - prcDest->left) * scale_x; prcClippedSrc->right = (prcClippedDest->right - prcDest->left) * scale_x; prcClippedSrc->top = (prcClippedDest->top - prcDest->top) * scale_y; prcClippedSrc->bottom = (prcClippedDest->bottom - prcDest->top) * scale_y; /* * now round (adding 0x8000 rounds) and translate (offset by the * src offset) */ prcClippedSrc->left = (((DWORD)prcClippedSrc->left + 0x8000) >> 16) + prcSrc->left; prcClippedSrc->right = (((DWORD)prcClippedSrc->right + 0x8000) >> 16) + prcSrc->left; prcClippedSrc->top = (((DWORD)prcClippedSrc->top + 0x8000) >> 16) + prcSrc->top; prcClippedSrc->bottom = (((DWORD)prcClippedSrc->bottom + 0x8000) >> 16) + prcSrc->top; /* * Check for zero-sized source rect dimensions and bump if necessary */ if (prcClippedSrc->left == prcClippedSrc->right) { if (prcClippedSrc->right == prcSrc->right) { (prcClippedSrc->left)--; } else { (prcClippedSrc->right)++; } } if (prcClippedSrc->top == prcClippedSrc->bottom) { if (prcClippedSrc->bottom == prcSrc->bottom) { (prcClippedSrc->top)--; } else { (prcClippedSrc->bottom)++; } } return DD_OK; } /* XformRect */