Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

5010 lines
203 KiB

/*==========================================================================
*
* 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 */