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