|
|
/*==========================================================================
* * 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<<BUSY_BIT) ) == (1<<BUSY_BIT) ); #endif
if( isbusy ) { DPF( 1, "BUSY - BltFast" ); LEAVE_BOTH(); return DDERR_SURFACEBUSY; } } /*
* The following code was added to keep all of the HALs from * changing their Blt() code when they add video port support. * If the video port was using this surface but was recently * flipped, we will make sure that the flip actually occurred * before allowing access. This allows double buffered capture * w/o tearing. */ if( this_src_lcl->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<<BUSY_BIT) ) == (1<<BUSY_BIT) ); #endif
if( isbusy ) { DPF( 1, "BUSY - Blt" ); LEAVE_BOTH(); return DDERR_SURFACEBUSY; }
} /*
* The following code was added to keep all of the HALs from * changing their Blt() code when they add video port support. * If the video port was using this surface but was recently * flipped, we will make sure that the flip actually occurred * before allowing access. This allows double buffered capture * w/o tearing. */ if( ( this_src_lcl != NULL ) && ( this_src_lcl->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;cnt<total;cnt++ ) { /*
* find out where on the src rect we need to get * the data from. */ if( !stretch_blt ) { // no stretch
// one-to-one 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; 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 */
|