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.
2763 lines
78 KiB
2763 lines
78 KiB
/*==========================================================================
|
|
*
|
|
* Copyright (C) 1997 Microsoft Corporation. All Rights Reserved.
|
|
*
|
|
* File: alphablt.c
|
|
* Content: DirectDraw Surface support for alpha-blended blt
|
|
* History:
|
|
* Date By Reason
|
|
* ==== == ======
|
|
* 30-sep-97 jvanaken Original version adapted from ddsblt.c
|
|
*
|
|
***************************************************************************/
|
|
#include "ddrawpr.h"
|
|
|
|
|
|
// function from ddraw module ddclip.c
|
|
extern HRESULT InternalGetClipList(LPDIRECTDRAWCLIPPER,
|
|
LPRECT,
|
|
LPRGNDATA,
|
|
LPDWORD,
|
|
LPDDRAWI_DIRECTDRAW_GBL);
|
|
|
|
#ifndef WINNT
|
|
#define DONE_BUSY() \
|
|
(*pdflags) &= ~BUSY;
|
|
#define LEAVE_BOTH_NOBUSY() \
|
|
{ if(pdflags) \
|
|
(*pdflags) &= ~BUSY; \
|
|
} \
|
|
LEAVE_BOTH();
|
|
#else
|
|
#define DONE_BUSY()
|
|
#define LEAVE_BOTH_NOBUSY() \
|
|
LEAVE_BOTH();
|
|
#endif
|
|
|
|
#define DONE_LOCKS() \
|
|
if (dest_lock_taken) \
|
|
{ \
|
|
InternalUnlock(surf_dest_lcl,NULL,NULL,0); \
|
|
dest_lock_taken = FALSE; \
|
|
} \
|
|
if (src_lock_taken && surf_src_lcl) \
|
|
{ \
|
|
InternalUnlock(surf_src_lcl,NULL,NULL,0); \
|
|
src_lock_taken = FALSE; \
|
|
}
|
|
|
|
#if defined(WIN95)
|
|
#define DONE_EXCLUDE() \
|
|
if (surf_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
|
|
|
|
|
|
/*
|
|
* Stretch-blit info
|
|
*/
|
|
typedef struct
|
|
{
|
|
DWORD src_height;
|
|
DWORD src_width;
|
|
DWORD dest_height;
|
|
DWORD dest_width;
|
|
BOOL halonly; // HEL can't do this alpha-blit
|
|
BOOL helonly; // hardware driver can't do this alpha-blit
|
|
} STRETCH_BLT_INFO, FAR *LPSTRETCH_BLT_INFO;
|
|
|
|
|
|
/*
|
|
* Alpha-blitting capability bits
|
|
*/
|
|
typedef struct
|
|
{
|
|
// caps for hardware driver
|
|
DWORD dwCaps;
|
|
DWORD dwCKeyCaps;
|
|
DWORD dwFXCaps;
|
|
DWORD dwAlphaCaps;
|
|
DWORD dwFilterCaps;
|
|
|
|
// caps for HEL
|
|
DWORD dwHELCaps;
|
|
DWORD dwHELCKeyCaps;
|
|
DWORD dwHELFXCaps;
|
|
DWORD dwHELAlphaCaps;
|
|
DWORD dwHELFilterCaps;
|
|
|
|
// caps common to hardware driver and HEL
|
|
DWORD dwBothCaps;
|
|
DWORD dwBothCKeyCaps;
|
|
DWORD dwBothFXCaps;
|
|
DWORD dwBothAlphaCaps;
|
|
DWORD dwBothFilterCaps;
|
|
|
|
BOOL bHALSeesSysmem;
|
|
} ALPHA_BLT_CAPS, *LPALPHA_BLT_CAPS;
|
|
|
|
|
|
/*
|
|
* Return a pointer to the DDPIXELFORMAT structure that
|
|
* describes the specified surface's pixel format.
|
|
*/
|
|
static LPDDPIXELFORMAT getPixelFormatPtr(LPDDRAWI_DDRAWSURFACE_LCL surf_lcl)
|
|
{
|
|
LPDDPIXELFORMAT pDDPF;
|
|
|
|
if (surf_lcl == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
if (surf_lcl->dwFlags & DDRAWISURF_HASPIXELFORMAT)
|
|
{
|
|
// surface contains explicitly defined pixel format
|
|
pDDPF = &surf_lcl->lpGbl->ddpfSurface;
|
|
}
|
|
else
|
|
{
|
|
// surface's pixel format is implicit -- same as primary's
|
|
pDDPF = &surf_lcl->lpSurfMore->lpDD_lcl->lpGbl->vmiData.ddpfDisplay;
|
|
}
|
|
return pDDPF;
|
|
|
|
} /* getPixelFormatPtr */
|
|
|
|
|
|
/*
|
|
* Initialize ALPHA_BLT_CAPS structure according to whether source and
|
|
* dest surfaces are in system or video (local or nonlocal) memory.
|
|
*/
|
|
static void initAlphaBltCaps(DWORD dwDstCaps,
|
|
DWORD dwSrcCaps,
|
|
LPDDRAWI_DIRECTDRAW_GBL pdrv,
|
|
LPALPHA_BLT_CAPS pcaps,
|
|
LPBOOL helonly)
|
|
{
|
|
DDASSERT(pcaps != NULL);
|
|
|
|
memset(pcaps, 0, sizeof(ALPHA_BLT_CAPS));
|
|
|
|
if ((dwSrcCaps | dwDstCaps) & DDSCAPS_NONLOCALVIDMEM &&
|
|
pdrv->ddCaps.dwCaps2 & DDCAPS2_NONLOCALVIDMEMCAPS)
|
|
{
|
|
/*
|
|
* At least one of the surfaces is nonlocal video memory. The device
|
|
* exports different capabilities for local and nonlocal video memory.
|
|
* If this is a nonlocal-to-local transfer then check the appropriate
|
|
* caps. Otherwise, force software emulation of the blit.
|
|
*/
|
|
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 for nonlocal video memory. Use them.
|
|
*/
|
|
pcaps->dwCaps = pdrv->lpddNLVCaps->dwNLVBCaps;
|
|
pcaps->dwCKeyCaps = pdrv->lpddNLVCaps->dwNLVBCKeyCaps;
|
|
pcaps->dwFXCaps = pdrv->lpddNLVCaps->dwNLVBFXCaps;
|
|
if (pdrv->lpddMoreCaps)
|
|
{
|
|
if (pcaps->dwFXCaps & DDFXCAPS_BLTALPHA)
|
|
{
|
|
pcaps->dwAlphaCaps = pdrv->lpddMoreCaps->dwAlphaCaps;
|
|
}
|
|
if (pcaps->dwFXCaps & DDFXCAPS_BLTFILTER)
|
|
{
|
|
pcaps->dwFilterCaps = pdrv->lpddMoreCaps->dwFilterCaps;
|
|
}
|
|
}
|
|
|
|
pcaps->dwHELCaps = pdrv->lpddNLVHELCaps->dwNLVBCaps;
|
|
pcaps->dwHELCKeyCaps = pdrv->lpddNLVHELCaps->dwNLVBCKeyCaps;
|
|
pcaps->dwHELFXCaps = pdrv->lpddNLVHELCaps->dwNLVBFXCaps;
|
|
if (pdrv->lpddHELMoreCaps)
|
|
{
|
|
if (pcaps->dwHELFXCaps & DDFXCAPS_BLTALPHA)
|
|
{
|
|
pcaps->dwHELAlphaCaps = pdrv->lpddHELMoreCaps->dwAlphaCaps;
|
|
}
|
|
if (pcaps->dwHELFXCaps & DDFXCAPS_BLTFILTER)
|
|
{
|
|
pcaps->dwHELFilterCaps = pdrv->lpddHELMoreCaps->dwFilterCaps;
|
|
}
|
|
}
|
|
|
|
pcaps->dwBothCaps = pdrv->lpddNLVBothCaps->dwNLVBCaps;
|
|
pcaps->dwBothCKeyCaps = pdrv->lpddNLVBothCaps->dwNLVBCKeyCaps;
|
|
pcaps->dwBothFXCaps = pdrv->lpddNLVBothCaps->dwNLVBFXCaps;
|
|
if (pdrv->lpddBothMoreCaps)
|
|
{
|
|
if (pcaps->dwBothFXCaps & DDFXCAPS_BLTALPHA)
|
|
{
|
|
pcaps->dwBothAlphaCaps = pdrv->lpddBothMoreCaps->dwAlphaCaps;
|
|
}
|
|
if (pcaps->dwBothFXCaps & DDFXCAPS_BLTFILTER)
|
|
{
|
|
pcaps->dwBothFilterCaps = pdrv->lpddBothMoreCaps->dwFilterCaps;
|
|
}
|
|
}
|
|
/*
|
|
* A driver that cannot filter is trivially capable of disabling filtering.
|
|
* By similar logic, a driver than cannot filter does not fail to respect
|
|
* the DDABLT_FILTERTRANSPBORDER flag unless filtering is explicitly enabled.
|
|
*/
|
|
if (!(pcaps->dwFXCaps & DDFXCAPS_BLTFILTER))
|
|
{
|
|
pcaps->dwFilterCaps = DDFILTCAPS_BLTCANDISABLEFILTER | DDFILTCAPS_BLTTRANSPBORDER;
|
|
pcaps->dwFXCaps |= DDFXCAPS_BLTFILTER;
|
|
}
|
|
if (!(pcaps->dwHELFXCaps & DDFXCAPS_BLTFILTER))
|
|
{
|
|
pcaps->dwHELFilterCaps = DDFILTCAPS_BLTCANDISABLEFILTER | DDFILTCAPS_BLTTRANSPBORDER;
|
|
pcaps->dwHELFXCaps |= DDFXCAPS_BLTFILTER;
|
|
}
|
|
if (!(pcaps->dwBothFXCaps & DDFXCAPS_BLTFILTER))
|
|
{
|
|
pcaps->dwBothFilterCaps = DDFILTCAPS_BLTCANDISABLEFILTER | DDFILTCAPS_BLTTRANSPBORDER;
|
|
pcaps->dwBothFXCaps |= DDFXCAPS_BLTFILTER;
|
|
}
|
|
|
|
pcaps->bHALSeesSysmem = FALSE;
|
|
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Nonlocal-to-nonlocal or local-to-nonlocal transfer. Force emulation.
|
|
*/
|
|
*helonly = TRUE;
|
|
}
|
|
|
|
if (!(pdrv->ddCaps.dwCaps & DDCAPS_CANBLTSYSMEM))
|
|
{
|
|
if ((dwSrcCaps | dwDstCaps) & DDSCAPS_SYSTEMMEMORY)
|
|
{
|
|
*helonly = TRUE;
|
|
}
|
|
}
|
|
|
|
if (dwSrcCaps & dwDstCaps & DDSCAPS_VIDEOMEMORY)
|
|
{
|
|
pcaps->dwCaps = pdrv->ddCaps.dwCaps;
|
|
pcaps->dwCKeyCaps = pdrv->ddCaps.dwCKeyCaps;
|
|
pcaps->dwFXCaps = pdrv->ddCaps.dwFXCaps;
|
|
if (pdrv->lpddMoreCaps)
|
|
{
|
|
if (pcaps->dwFXCaps & DDFXCAPS_BLTALPHA)
|
|
{
|
|
pcaps->dwAlphaCaps = pdrv->lpddMoreCaps->dwAlphaCaps;
|
|
}
|
|
if (pcaps->dwFXCaps & DDFXCAPS_BLTFILTER)
|
|
{
|
|
pcaps->dwFilterCaps = pdrv->lpddMoreCaps->dwFilterCaps;
|
|
}
|
|
}
|
|
|
|
pcaps->dwHELCaps = pdrv->ddHELCaps.dwCaps;
|
|
pcaps->dwHELCKeyCaps = pdrv->ddHELCaps.dwCKeyCaps;
|
|
pcaps->dwHELFXCaps = pdrv->ddHELCaps.dwFXCaps;
|
|
if (pdrv->lpddHELMoreCaps)
|
|
{
|
|
if (pcaps->dwHELFXCaps & DDFXCAPS_BLTALPHA)
|
|
{
|
|
pcaps->dwHELAlphaCaps = pdrv->lpddHELMoreCaps->dwAlphaCaps;
|
|
}
|
|
if (pcaps->dwHELFXCaps & DDFXCAPS_BLTFILTER)
|
|
{
|
|
pcaps->dwHELFilterCaps = pdrv->lpddHELMoreCaps->dwFilterCaps;
|
|
}
|
|
}
|
|
|
|
pcaps->dwBothCaps = pdrv->ddBothCaps.dwCaps;
|
|
pcaps->dwBothCKeyCaps = pdrv->ddBothCaps.dwCKeyCaps;
|
|
pcaps->dwBothFXCaps = pdrv->ddBothCaps.dwFXCaps;
|
|
if (pdrv->lpddBothMoreCaps)
|
|
{
|
|
if (pcaps->dwBothFXCaps & DDFXCAPS_BLTALPHA)
|
|
{
|
|
pcaps->dwBothAlphaCaps = pdrv->lpddBothMoreCaps->dwAlphaCaps;
|
|
}
|
|
if (pcaps->dwBothFXCaps & DDFXCAPS_BLTFILTER)
|
|
{
|
|
pcaps->dwBothFilterCaps = pdrv->lpddBothMoreCaps->dwFilterCaps;
|
|
}
|
|
}
|
|
|
|
pcaps->bHALSeesSysmem = FALSE;
|
|
}
|
|
else if ((dwSrcCaps & DDSCAPS_SYSTEMMEMORY) && (dwDstCaps & DDSCAPS_VIDEOMEMORY))
|
|
{
|
|
pcaps->dwCaps = pdrv->ddCaps.dwSVBCaps;
|
|
pcaps->dwCKeyCaps = pdrv->ddCaps.dwSVBCKeyCaps;
|
|
pcaps->dwFXCaps = pdrv->ddCaps.dwSVBFXCaps;
|
|
if (pdrv->lpddMoreCaps)
|
|
{
|
|
if (pcaps->dwFXCaps & DDFXCAPS_BLTALPHA)
|
|
{
|
|
pcaps->dwAlphaCaps = pdrv->lpddMoreCaps->dwSVBAlphaCaps;
|
|
}
|
|
if (pcaps->dwFXCaps & DDFXCAPS_BLTFILTER)
|
|
{
|
|
pcaps->dwFilterCaps = pdrv->lpddMoreCaps->dwSVBFilterCaps;
|
|
}
|
|
}
|
|
|
|
pcaps->dwHELCaps = pdrv->ddHELCaps.dwSVBCaps;
|
|
pcaps->dwHELCKeyCaps = pdrv->ddHELCaps.dwSVBCKeyCaps;
|
|
pcaps->dwHELFXCaps = pdrv->ddHELCaps.dwSVBFXCaps;
|
|
if (pdrv->lpddHELMoreCaps)
|
|
{
|
|
if (pcaps->dwHELFXCaps & DDFXCAPS_BLTALPHA)
|
|
{
|
|
pcaps->dwHELAlphaCaps = pdrv->lpddHELMoreCaps->dwSVBAlphaCaps;
|
|
}
|
|
if (pcaps->dwHELFXCaps & DDFXCAPS_BLTFILTER)
|
|
{
|
|
pcaps->dwHELFilterCaps = pdrv->lpddHELMoreCaps->dwSVBFilterCaps;
|
|
}
|
|
}
|
|
|
|
pcaps->dwBothCaps = pdrv->ddBothCaps.dwSVBCaps;
|
|
pcaps->dwBothCKeyCaps = pdrv->ddBothCaps.dwSVBCKeyCaps;
|
|
pcaps->dwBothFXCaps = pdrv->ddBothCaps.dwSVBFXCaps;
|
|
if (pdrv->lpddBothMoreCaps)
|
|
{
|
|
if (pcaps->dwBothFXCaps & DDFXCAPS_BLTALPHA)
|
|
{
|
|
pcaps->dwBothAlphaCaps = pdrv->lpddBothMoreCaps->dwSVBAlphaCaps;
|
|
}
|
|
if (pcaps->dwBothFXCaps & DDFXCAPS_BLTFILTER)
|
|
{
|
|
pcaps->dwBothFilterCaps = pdrv->lpddBothMoreCaps->dwSVBFilterCaps;
|
|
}
|
|
}
|
|
|
|
pcaps->bHALSeesSysmem = TRUE;
|
|
}
|
|
else if ((dwSrcCaps & DDSCAPS_VIDEOMEMORY) && (dwDstCaps & DDSCAPS_SYSTEMMEMORY))
|
|
{
|
|
pcaps->dwCaps = pdrv->ddCaps.dwVSBCaps;
|
|
pcaps->dwCKeyCaps = pdrv->ddCaps.dwVSBCKeyCaps;
|
|
pcaps->dwFXCaps = pdrv->ddCaps.dwVSBFXCaps;
|
|
if (pdrv->lpddMoreCaps)
|
|
{
|
|
if (pcaps->dwFXCaps & DDFXCAPS_BLTALPHA)
|
|
{
|
|
pcaps->dwAlphaCaps = pdrv->lpddMoreCaps->dwVSBAlphaCaps;
|
|
}
|
|
if (pcaps->dwFXCaps & DDFXCAPS_BLTFILTER)
|
|
{
|
|
pcaps->dwFilterCaps = pdrv->lpddMoreCaps->dwVSBFilterCaps;
|
|
}
|
|
}
|
|
|
|
pcaps->dwHELCaps = pdrv->ddHELCaps.dwVSBCaps;
|
|
pcaps->dwHELCKeyCaps = pdrv->ddHELCaps.dwVSBCKeyCaps;
|
|
pcaps->dwHELFXCaps = pdrv->ddHELCaps.dwVSBFXCaps;
|
|
if (pdrv->lpddHELMoreCaps)
|
|
{
|
|
if (pcaps->dwHELFXCaps & DDFXCAPS_BLTALPHA)
|
|
{
|
|
pcaps->dwHELAlphaCaps = pdrv->lpddHELMoreCaps->dwVSBAlphaCaps;
|
|
}
|
|
if (pcaps->dwHELFXCaps & DDFXCAPS_BLTFILTER)
|
|
{
|
|
pcaps->dwHELFilterCaps = pdrv->lpddHELMoreCaps->dwVSBFilterCaps;
|
|
}
|
|
}
|
|
|
|
pcaps->dwBothCaps = pdrv->ddBothCaps.dwVSBCaps;
|
|
pcaps->dwBothCKeyCaps = pdrv->ddBothCaps.dwVSBCKeyCaps;
|
|
pcaps->dwBothFXCaps = pdrv->ddBothCaps.dwVSBFXCaps;
|
|
if (pdrv->lpddBothMoreCaps)
|
|
{
|
|
if (pcaps->dwBothFXCaps & DDFXCAPS_BLTALPHA)
|
|
{
|
|
pcaps->dwBothAlphaCaps = pdrv->lpddBothMoreCaps->dwVSBAlphaCaps;
|
|
}
|
|
if (pcaps->dwBothFXCaps & DDFXCAPS_BLTFILTER)
|
|
{
|
|
pcaps->dwBothFilterCaps = pdrv->lpddBothMoreCaps->dwVSBFilterCaps;
|
|
}
|
|
}
|
|
|
|
pcaps->bHALSeesSysmem = TRUE;
|
|
}
|
|
else if (dwSrcCaps & dwDstCaps & DDSCAPS_SYSTEMMEMORY)
|
|
{
|
|
pcaps->dwCaps = pdrv->ddCaps.dwSSBCaps;
|
|
pcaps->dwCKeyCaps = pdrv->ddCaps.dwSSBCKeyCaps;
|
|
pcaps->dwFXCaps = pdrv->ddCaps.dwSSBFXCaps;
|
|
if (pdrv->lpddMoreCaps)
|
|
{
|
|
if (pcaps->dwFXCaps & DDFXCAPS_BLTALPHA)
|
|
{
|
|
pcaps->dwAlphaCaps = pdrv->lpddMoreCaps->dwSSBAlphaCaps;
|
|
}
|
|
if (pcaps->dwFXCaps & DDFXCAPS_BLTFILTER)
|
|
{
|
|
pcaps->dwFilterCaps = pdrv->lpddMoreCaps->dwSSBFilterCaps;
|
|
}
|
|
}
|
|
|
|
pcaps->dwHELCaps = pdrv->ddHELCaps.dwSSBCaps;
|
|
pcaps->dwHELCKeyCaps = pdrv->ddHELCaps.dwSSBCKeyCaps;
|
|
pcaps->dwHELFXCaps = pdrv->ddHELCaps.dwSSBFXCaps;
|
|
if (pdrv->lpddHELMoreCaps)
|
|
{
|
|
if (pcaps->dwHELFXCaps & DDFXCAPS_BLTALPHA)
|
|
{
|
|
pcaps->dwHELAlphaCaps = pdrv->lpddHELMoreCaps->dwSSBAlphaCaps;
|
|
}
|
|
if (pcaps->dwHELFXCaps & DDFXCAPS_BLTFILTER)
|
|
{
|
|
pcaps->dwHELFilterCaps = pdrv->lpddHELMoreCaps->dwSSBFilterCaps;
|
|
}
|
|
}
|
|
|
|
pcaps->dwBothCaps = pdrv->ddBothCaps.dwSSBCaps;
|
|
pcaps->dwBothCKeyCaps = pdrv->ddBothCaps.dwSSBCKeyCaps;
|
|
pcaps->dwBothFXCaps = pdrv->ddBothCaps.dwSSBFXCaps;
|
|
if (pdrv->lpddBothMoreCaps)
|
|
{
|
|
if (pcaps->dwBothFXCaps & DDFXCAPS_BLTALPHA)
|
|
{
|
|
pcaps->dwBothAlphaCaps = pdrv->lpddBothMoreCaps->dwSSBAlphaCaps;
|
|
}
|
|
if (pcaps->dwBothFXCaps & DDFXCAPS_BLTFILTER)
|
|
{
|
|
pcaps->dwBothFilterCaps = pdrv->lpddBothMoreCaps->dwSSBFilterCaps;
|
|
}
|
|
}
|
|
|
|
pcaps->bHALSeesSysmem = TRUE;
|
|
}
|
|
|
|
/*
|
|
* A driver that cannot filter is trivially capable of disabling filtering.
|
|
* By similar logic, a driver than cannot filter does not fail to respect
|
|
* the DDABLT_FILTERTRANSPBORDER flag unless filtering is explicitly enabled.
|
|
*/
|
|
if (!(pcaps->dwFXCaps & DDFXCAPS_BLTFILTER))
|
|
{
|
|
pcaps->dwFilterCaps = DDFILTCAPS_BLTCANDISABLEFILTER | DDFILTCAPS_BLTTRANSPBORDER;
|
|
pcaps->dwFXCaps |= DDFXCAPS_BLTFILTER;
|
|
}
|
|
if (!(pcaps->dwHELFXCaps & DDFXCAPS_BLTFILTER))
|
|
{
|
|
pcaps->dwHELFilterCaps = DDFILTCAPS_BLTCANDISABLEFILTER | DDFILTCAPS_BLTTRANSPBORDER;
|
|
pcaps->dwHELFXCaps |= DDFXCAPS_BLTFILTER;
|
|
}
|
|
if (!(pcaps->dwBothFXCaps & DDFXCAPS_BLTFILTER))
|
|
{
|
|
pcaps->dwBothFilterCaps = DDFILTCAPS_BLTCANDISABLEFILTER | DDFILTCAPS_BLTTRANSPBORDER;
|
|
pcaps->dwBothFXCaps |= DDFXCAPS_BLTFILTER;
|
|
}
|
|
|
|
} /* initAlphaBltCaps */
|
|
|
|
|
|
/*
|
|
* Verify that driver can perform requested stretching for blit.
|
|
*/
|
|
static HRESULT validateStretching(LPALPHA_BLT_CAPS pcaps,
|
|
LPSTRETCH_BLT_INFO psbi)
|
|
{
|
|
DWORD caps;
|
|
BOOL fail = FALSE;
|
|
|
|
/*
|
|
* Can we even stretch at all?
|
|
*/
|
|
if (!(pcaps->dwBothCaps & DDCAPS_BLTSTRETCH))
|
|
{
|
|
GETFAILCODEBLT(pcaps->dwCaps,
|
|
pcaps->dwHELCaps,
|
|
psbi->halonly,
|
|
psbi->helonly,
|
|
DDCAPS_BLTSTRETCH);
|
|
if (fail)
|
|
{
|
|
return DDERR_NOSTRETCHHW;
|
|
}
|
|
}
|
|
|
|
if (psbi->helonly)
|
|
caps = pcaps->dwHELFXCaps;
|
|
else
|
|
caps = pcaps->dwFXCaps;
|
|
|
|
/*
|
|
* verify height
|
|
*/
|
|
if (psbi->src_height != psbi->dest_height)
|
|
{
|
|
if (psbi->src_height > psbi->dest_height)
|
|
{
|
|
/*
|
|
* can we shrink Y arbitrarily?
|
|
*/
|
|
if (!(caps & (DDFXCAPS_BLTSHRINKY)))
|
|
{
|
|
/*
|
|
* see if this is a non-integer shrink
|
|
*/
|
|
if ((psbi->src_height % psbi->dest_height) != 0)
|
|
{
|
|
GETFAILCODEBLT(pcaps->dwFXCaps,
|
|
pcaps->dwHELFXCaps,
|
|
psbi->halonly,
|
|
psbi->helonly,
|
|
DDFXCAPS_BLTSHRINKY);
|
|
if (fail)
|
|
{
|
|
return DDERR_NOSTRETCHHW;
|
|
}
|
|
/*
|
|
* see if we can integer shrink
|
|
*/
|
|
}
|
|
else if (!(caps & DDFXCAPS_BLTSHRINKYN))
|
|
{
|
|
GETFAILCODEBLT(pcaps->dwFXCaps,
|
|
pcaps->dwHELFXCaps,
|
|
psbi->halonly,
|
|
psbi->helonly,
|
|
DDFXCAPS_BLTSHRINKYN);
|
|
if (fail)
|
|
{
|
|
return DDERR_NOSTRETCHHW;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!(caps & DDFXCAPS_BLTSTRETCHY))
|
|
{
|
|
/*
|
|
* see if this is a non-integer stretch
|
|
*/
|
|
if ((psbi->dest_height % psbi->src_height) != 0)
|
|
{
|
|
GETFAILCODEBLT(pcaps->dwFXCaps,
|
|
pcaps->dwHELFXCaps,
|
|
psbi->halonly,
|
|
psbi->helonly,
|
|
DDFXCAPS_BLTSTRETCHY);
|
|
if (fail)
|
|
{
|
|
return DDERR_NOSTRETCHHW;
|
|
}
|
|
/*
|
|
* see if we can integer stretch
|
|
*/
|
|
}
|
|
else if (!(caps & DDFXCAPS_BLTSTRETCHYN))
|
|
{
|
|
GETFAILCODEBLT(pcaps->dwFXCaps,
|
|
pcaps->dwHELFXCaps,
|
|
psbi->halonly,
|
|
psbi->helonly,
|
|
DDFXCAPS_BLTSTRETCHYN);
|
|
if (fail)
|
|
{
|
|
return DDERR_NOSTRETCHHW;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* verify width
|
|
*/
|
|
if (psbi->src_width != psbi->dest_width)
|
|
{
|
|
if (psbi->src_width > psbi->dest_width)
|
|
{
|
|
if (!(caps & DDFXCAPS_BLTSHRINKX))
|
|
{
|
|
/*
|
|
* Are we stretching by a non-integer factor?
|
|
*/
|
|
if ((psbi->src_width % psbi->dest_width) != 0)
|
|
{
|
|
GETFAILCODEBLT(pcaps->dwFXCaps,
|
|
pcaps->dwHELFXCaps,
|
|
psbi->halonly,
|
|
psbi->helonly,
|
|
DDFXCAPS_BLTSHRINKX);
|
|
if (fail)
|
|
{
|
|
return DDERR_NOSTRETCHHW;
|
|
}
|
|
/*
|
|
* see if we can integer shrink
|
|
*/
|
|
}
|
|
else if (!(caps & DDFXCAPS_BLTSHRINKXN))
|
|
{
|
|
GETFAILCODEBLT(pcaps->dwFXCaps,
|
|
pcaps->dwHELFXCaps,
|
|
psbi->halonly,
|
|
psbi->helonly,
|
|
DDFXCAPS_BLTSHRINKXN);
|
|
if (fail)
|
|
{
|
|
return DDERR_NOSTRETCHHW;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!(caps & DDFXCAPS_BLTSTRETCHX))
|
|
{
|
|
/*
|
|
* Are we stretching by a non-integer factor?
|
|
*/
|
|
if ((psbi->dest_width % psbi->src_width) != 0)
|
|
{
|
|
GETFAILCODEBLT(pcaps->dwFXCaps,
|
|
pcaps->dwHELFXCaps,
|
|
psbi->halonly,
|
|
psbi->helonly,
|
|
DDFXCAPS_BLTSTRETCHX);
|
|
if (fail)
|
|
{
|
|
return DDERR_NOSTRETCHHW;
|
|
}
|
|
}
|
|
if (!(caps & DDFXCAPS_BLTSTRETCHXN))
|
|
{
|
|
GETFAILCODEBLT(pcaps->dwFXCaps,
|
|
pcaps->dwHELFXCaps,
|
|
psbi->halonly,
|
|
psbi->helonly,
|
|
DDFXCAPS_BLTSTRETCHXN);
|
|
if (fail)
|
|
{
|
|
return DDERR_NOSTRETCHHW;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return DD_OK;
|
|
|
|
} /* validateStretching */
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "AlphaBlt"
|
|
|
|
|
|
/*
|
|
* Wait for pending hardware operation on specified surface to finish.
|
|
*
|
|
* 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 flag.
|
|
*/
|
|
static void WaitForHardwareOp(LPDDRAWI_DIRECTDRAW_LCL pdrv_lcl,
|
|
LPDDRAWI_DDRAWSURFACE_LCL surf_lcl)
|
|
{
|
|
HRESULT hr;
|
|
#ifdef DEBUG
|
|
BOOL bSentMessage = FALSE;
|
|
DWORD dwStart = GetTickCount();
|
|
#endif
|
|
|
|
DDASSERT(surf_lcl->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY);
|
|
DPF(5, B, "Waiting for driver to finish with %08x", surf_lcl->lpGbl);
|
|
do
|
|
{
|
|
hr = InternalGetBltStatus(pdrv_lcl, surf_lcl, DDGBS_ISBLTDONE);
|
|
#ifdef DEBUG
|
|
if (GetTickCount() - dwStart >= 10000 && !bSentMessage)
|
|
{
|
|
bSentMessage = TRUE;
|
|
DPF_ERR("Driver error: Hardware op still pending on surface after 5 sec!");
|
|
}
|
|
#endif
|
|
} while (hr == DDERR_WASSTILLDRAWING);
|
|
|
|
DDASSERT(hr == DD_OK);
|
|
DPF(5, B, "Driver finished with that surface");
|
|
surf_lcl->lpGbl->dwGlobalFlags &= ~DDRAWISURFGBL_HARDWAREOPSTARTED;
|
|
|
|
} /* WaitForHardwareOp */
|
|
|
|
|
|
/*
|
|
* DD_Surface_AlphaBlt
|
|
*
|
|
* BitBLT from one surface to another with alpha blending.
|
|
*/
|
|
HRESULT DDAPI DD_Surface_AlphaBlt(
|
|
LPDIRECTDRAWSURFACE lpDDDestSurface,
|
|
LPRECT lpDestRect,
|
|
LPDIRECTDRAWSURFACE lpDDSrcSurface,
|
|
LPRECT lpSrcRect,
|
|
DWORD dwFlags,
|
|
LPDDALPHABLTFX lpDDAlphaBltFX)
|
|
{
|
|
struct
|
|
{
|
|
RGNDATAHEADER rdh;
|
|
RECT clipRect[8];
|
|
} myRgnBuffer;
|
|
|
|
DWORD rc;
|
|
LPDDRAWI_DDRAWSURFACE_INT surf_src_int;
|
|
LPDDRAWI_DDRAWSURFACE_LCL surf_src_lcl;
|
|
LPDDRAWI_DDRAWSURFACE_GBL surf_src;
|
|
LPDDRAWI_DDRAWSURFACE_INT surf_dest_int;
|
|
LPDDRAWI_DDRAWSURFACE_LCL surf_dest_lcl;
|
|
LPDDRAWI_DDRAWSURFACE_GBL surf_dest;
|
|
LPDDRAWI_DIRECTDRAW_LCL pdrv_lcl;
|
|
LPDDRAWI_DIRECTDRAW_GBL pdrv;
|
|
LPDDHAL_ALPHABLT bltfn;
|
|
DDHAL_BLTDATA bd;
|
|
STRETCH_BLT_INFO sbi;
|
|
BOOL fail;
|
|
BOOL dest_lock_taken=FALSE;
|
|
BOOL src_lock_taken=FALSE;
|
|
LPVOID dest_bits;
|
|
LPVOID src_bits;
|
|
HRESULT ddrval;
|
|
RECT rect;
|
|
ALPHA_BLT_CAPS caps;
|
|
LPWORD pdflags=0;
|
|
LPRGNDATA pRgn;
|
|
DDARGB ddargbScaleFactors;
|
|
DWORD dwFillValue;
|
|
DWORD dwDDPFDestFlags;
|
|
DWORD dwDDPFSrcFlags;
|
|
|
|
DDASSERT(sizeof(DDARGB)==sizeof(DWORD)); // we rely on this
|
|
|
|
ENTER_BOTH();
|
|
|
|
DPF(2,A,"ENTERAPI: DD_Surface_AlphaBlt");
|
|
|
|
TRY
|
|
{
|
|
ZeroMemory(&bd, sizeof(bd)); // initialize to zero
|
|
|
|
/*
|
|
* Validate surface pointers.
|
|
*/
|
|
surf_dest_int = (LPDDRAWI_DDRAWSURFACE_INT) lpDDDestSurface;
|
|
surf_src_int = (LPDDRAWI_DDRAWSURFACE_INT) lpDDSrcSurface;
|
|
if (!VALID_DIRECTDRAWSURFACE_PTR(surf_dest_int))
|
|
{
|
|
DPF_ERR("Invalid dest surface") ;
|
|
LEAVE_BOTH();
|
|
return DDERR_INVALIDOBJECT;
|
|
}
|
|
surf_dest_lcl = surf_dest_int->lpLcl;
|
|
surf_dest = surf_dest_lcl->lpGbl;
|
|
if (SURFACE_LOST(surf_dest_lcl))
|
|
{
|
|
DPF_ERR("Dest surface lost") ;
|
|
LEAVE_BOTH();
|
|
return DDERR_SURFACELOST;
|
|
}
|
|
if (surf_src_int != NULL)
|
|
{
|
|
if (!VALID_DIRECTDRAWSURFACE_PTR(surf_src_int))
|
|
{
|
|
DPF_ERR("Invalid source surface");
|
|
LEAVE_BOTH();
|
|
return DDERR_INVALIDOBJECT;
|
|
}
|
|
surf_src_lcl = surf_src_int->lpLcl;
|
|
surf_src = surf_src_lcl->lpGbl;
|
|
if (SURFACE_LOST(surf_src_lcl))
|
|
{
|
|
DPF_ERR("Src surface lost") ;
|
|
LEAVE_BOTH();
|
|
return DDERR_SURFACELOST;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
surf_src_lcl = NULL;
|
|
surf_src = NULL;
|
|
}
|
|
|
|
if (dwFlags & ~DDABLT_VALID)
|
|
{
|
|
DPF_ERR("Invalid flags") ;
|
|
LEAVE_BOTH();
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
|
|
// Is the DONOTWAIT flag set?
|
|
if (dwFlags & DDABLT_DONOTWAIT)
|
|
{
|
|
if (dwFlags & DDABLT_WAIT)
|
|
{
|
|
DPF_ERR("WAIT and DONOTWAIT flags are mutually exclusive");
|
|
LEAVE_BOTH_NOBUSY();
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Unless the DONOTWAIT flag is explicitly set, use the default (WAIT).
|
|
dwFlags |= DDABLT_WAIT;
|
|
}
|
|
|
|
/*
|
|
* Set ARGB scaling factors and fill value to their default values.
|
|
* Note that setting ddargbScaleFactors to all ones effectively
|
|
* disables ARGB scaling, and a fill value of zero represents black.
|
|
*/
|
|
*(LPDWORD)&ddargbScaleFactors = ~0UL;
|
|
dwFillValue = 0;
|
|
|
|
/*
|
|
* Read parameters pointed to by lpDDAlphaBltFX argument.
|
|
*/
|
|
if (lpDDAlphaBltFX != 0)
|
|
{
|
|
if (IsBadWritePtr((LPVOID)lpDDAlphaBltFX, sizeof(DDALPHABLTFX)))
|
|
{
|
|
DPF_ERR("Argument lpDDAlphaBltFX is a bad pointer") ;
|
|
LEAVE_BOTH();
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
if (dwFlags & DDABLT_USEFILLVALUE)
|
|
{
|
|
dwFillValue = lpDDAlphaBltFX->dwFillValue;
|
|
}
|
|
else
|
|
{
|
|
ddargbScaleFactors = lpDDAlphaBltFX->ddargbScaleFactors;
|
|
}
|
|
}
|
|
|
|
// Is this a color-fill operation that uses dwFillValue?
|
|
if (dwFlags & DDABLT_USEFILLVALUE && surf_src_lcl == NULL)
|
|
{
|
|
// Could this possibly be an alpha-blended fill?
|
|
if (!(dwFlags & DDABLT_NOBLEND))
|
|
{
|
|
HRESULT hres;
|
|
|
|
// If the fill value is less than 100% opaque, we need to
|
|
// do an alpha fill rather than just a simple color fill.
|
|
// Convert physcolor to DDARGB value and test its opacity.
|
|
hres = ConvertFromPhysColor(
|
|
surf_dest_lcl,
|
|
&dwFillValue,
|
|
&ddargbScaleFactors);
|
|
|
|
if ((hres == DD_OK) && (ddargbScaleFactors.alpha != 255))
|
|
{
|
|
// The fill value is not 100% opaque, so do an alpha fill.
|
|
dwFlags &= ~DDABLT_USEFILLVALUE;
|
|
}
|
|
}
|
|
// Make sure DEGRADEARGBSCALING flag is not set.
|
|
if (dwFlags & DDABLT_DEGRADEARGBSCALING)
|
|
{
|
|
DPF_ERR("DEGRADEARGBSCALING and USEFILLVALUE flags are incompatible");
|
|
LEAVE_BOTH();
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* We do not allow blitting to or from an optimized surface.
|
|
*/
|
|
if (surf_dest_lcl->ddsCaps.dwCaps & DDSCAPS_OPTIMIZED ||
|
|
surf_src && surf_src_lcl->ddsCaps.dwCaps & DDSCAPS_OPTIMIZED)
|
|
{
|
|
DPF_ERR("Can't blt optimized surfaces") ;
|
|
LEAVE_BOTH();
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
|
|
pdrv = surf_dest->lpDD;
|
|
pdrv_lcl = surf_dest_lcl->lpSurfMore->lpDD_lcl;
|
|
#ifdef WINNT
|
|
// Update DDraw handle in driver GBL object.
|
|
pdrv->hDD = pdrv_lcl->hDD;
|
|
#endif
|
|
|
|
/*
|
|
* Default behavior is to automatically fail-over to software
|
|
* emulation if hardware driver cannot handle the specified
|
|
* blit. The DDABLT_HARDWAREONLY flag overrides this default.
|
|
*/
|
|
sbi.halonly = dwFlags & DDABLT_HARDWAREONLY;
|
|
sbi.helonly = dwFlags & DDABLT_SOFTWAREONLY;
|
|
|
|
/*
|
|
* Only the HEL can blit between two surfaces created by two
|
|
* different drivers.
|
|
*/
|
|
if (surf_src && surf_src->lpDD != pdrv &&
|
|
surf_src->lpDD->dwFlags & DDRAWI_DISPLAYDRV &&
|
|
pdrv->dwFlags & DDRAWI_DISPLAYDRV)
|
|
{
|
|
sbi.helonly = TRUE;
|
|
}
|
|
}
|
|
EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
DPF_ERR("Exception encountered validating parameters");
|
|
LEAVE_BOTH();
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
|
|
#ifdef USE_ALIAS
|
|
if ((pdrv_lcl->lpDDCB->HALDDMiscellaneous2.AlphaBlt == NULL) &&
|
|
(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 gets 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 BUSY bit had been set.
|
|
*/
|
|
DPF_ERR("Graphics adapter is busy (due to a DirectDraw lock)");
|
|
LEAVE_BOTH();
|
|
return DDERR_SURFACEBUSY;
|
|
}
|
|
#endif /* USE_ALIAS */
|
|
|
|
if(surf_src_lcl)
|
|
FlushD3DStates(surf_src_lcl); // Need to flush src because it could be a rendertarget
|
|
FlushD3DStates(surf_dest_lcl);
|
|
|
|
/*
|
|
* Test and set the busy bit. If it was already set, bail.
|
|
*/
|
|
#ifdef WIN95
|
|
{
|
|
BOOL isbusy = 0;
|
|
|
|
pdflags = pdrv->lpwPDeviceFlags;
|
|
_asm
|
|
{
|
|
mov eax, pdflags
|
|
bts word ptr [eax], BUSY_BIT
|
|
adc byte ptr isbusy,0
|
|
}
|
|
if (isbusy)
|
|
{
|
|
DPF(3, "BUSY - AlphaBlt");
|
|
LEAVE_BOTH();
|
|
return DDERR_SURFACEBUSY;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* 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 ((surf_src_lcl != NULL) &&
|
|
(surf_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 == surf_src->fpVidMem)
|
|
{
|
|
// This can potentially tear - check the flip status
|
|
LPDDHALVPORTCB_GETFLIPSTATUS pfn;
|
|
DDHAL_GETVPORTFLIPSTATUSDATA GetFlipData;
|
|
LPDDRAWI_DIRECTDRAW_LCL pdrv_lcl;
|
|
|
|
pdrv_lcl = surf_src_lcl->lpSurfMore->lpDD_lcl;
|
|
pfn = pdrv_lcl->lpDDCB->HALDDVideoPort.GetVideoPortFlipStatus;
|
|
if (pfn != NULL) // Will simply tear if function not supported
|
|
{
|
|
GetFlipData.lpDD = pdrv_lcl;
|
|
GetFlipData.fpSurface = surf_src->fpVidMem;
|
|
|
|
KeepTrying:
|
|
rc = DDHAL_DRIVER_NOTHANDLED;
|
|
DOHALCALL(GetVideoPortFlipStatus, pfn, GetFlipData, rc, 0);
|
|
if ((DDHAL_DRIVER_HANDLED == rc) &&
|
|
(DDERR_WASSTILLDRAWING == GetFlipData.ddRVal))
|
|
{
|
|
if (dwFlags & DDABLT_WAIT)
|
|
{
|
|
goto KeepTrying;
|
|
}
|
|
LEAVE_BOTH_NOBUSY();
|
|
return DDERR_WASSTILLDRAWING;
|
|
}
|
|
}
|
|
}
|
|
lpVideoPort = lpVideoPort->lpLink;
|
|
}
|
|
}
|
|
|
|
|
|
TRY
|
|
{
|
|
/*
|
|
* Remove any cached run-length-encoded data for the source surface.
|
|
*/
|
|
if (surf_dest_lcl->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY)
|
|
{
|
|
extern void FreeRleData(LPDDRAWI_DDRAWSURFACE_LCL); //in fasthel.c
|
|
|
|
FreeRleData(surf_dest_lcl);
|
|
}
|
|
|
|
/*
|
|
* Is either surface locked?
|
|
*/
|
|
if (surf_dest->dwUsageCount > 0 ||
|
|
surf_src != NULL && surf_src->dwUsageCount > 0)
|
|
{
|
|
DPF_ERR("Surface is locked");
|
|
LEAVE_BOTH_NOBUSY();
|
|
return DDERR_SURFACEBUSY;
|
|
}
|
|
|
|
BUMP_SURFACE_STAMP(surf_dest);
|
|
|
|
/*
|
|
* It is possible this function could be called in the middle
|
|
* of a mode change, 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 &&
|
|
!(surf_dest_lcl->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY))
|
|
{
|
|
LEAVE_BOTH_NOBUSY()
|
|
return DD_OK;
|
|
}
|
|
|
|
/*
|
|
* Some parameters are valid only if a source surface is specified.
|
|
*/
|
|
if (surf_src == NULL)
|
|
{
|
|
/*
|
|
* No source surface is specified, so this must be a fill operation.
|
|
*/
|
|
if (dwFlags & (DDABLT_MIRRORLEFTRIGHT | DDABLT_MIRRORUPDOWN |
|
|
DDABLT_FILTERENABLE | DDABLT_FILTERDISABLE |
|
|
DDABLT_FILTERTRANSPBORDER | DDABLT_KEYSRC))
|
|
{
|
|
DPF_ERR("Specified flag requires source surface");
|
|
LEAVE_BOTH_NOBUSY();
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
if (lpSrcRect != NULL)
|
|
{
|
|
DPF_ERR("Source rectangle specified without source surface");
|
|
LEAVE_BOTH_NOBUSY();
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* A source surface is specified, so this must be a two-operand blit.
|
|
*/
|
|
if (dwFlags & DDABLT_USEFILLVALUE)
|
|
{
|
|
DPF_ERR("USEFILLVALUE flag incompatible with use of source surface");
|
|
LEAVE_BOTH_NOBUSY();
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Get capability bits for source/dest memory combination.
|
|
*/
|
|
if (surf_src != NULL)
|
|
{
|
|
// initialize the blit caps according to the surface types
|
|
initAlphaBltCaps(surf_dest_lcl->ddsCaps.dwCaps,
|
|
surf_src_lcl->ddsCaps.dwCaps,
|
|
pdrv,
|
|
&caps,
|
|
&sbi.helonly);
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* No source surface. Use caps for vram-to-vram blits and choose
|
|
* hal or hel based on whether dest surface is in system memory.
|
|
* If the dest surface is in nonlocal video memory, we also force
|
|
* emulation as we don't currently support accelerated operation
|
|
* with nonlocal video memory as a target.
|
|
*/
|
|
initAlphaBltCaps(DDSCAPS_VIDEOMEMORY,
|
|
DDSCAPS_VIDEOMEMORY,
|
|
pdrv,
|
|
&caps,
|
|
&sbi.helonly);
|
|
|
|
if (surf_dest_lcl->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY ||
|
|
surf_dest_lcl->ddsCaps.dwCaps & DDSCAPS_NONLOCALVIDMEM)
|
|
{
|
|
caps.bHALSeesSysmem = FALSE;
|
|
sbi.helonly = TRUE;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Can we really blit? -- Test DDCAPS_BLTCOLORFILL if src surf is null?
|
|
*/
|
|
if (!(caps.dwBothCaps & DDCAPS_BLT))
|
|
{
|
|
/*
|
|
* Unable to blit with both HEL and hardware driver.
|
|
* Can either of them do the blit?
|
|
*/
|
|
if (caps.dwCaps & DDCAPS_BLT)
|
|
{
|
|
sbi.halonly = TRUE; // hardware driver only
|
|
}
|
|
else if (caps.dwHELCaps & DDCAPS_BLT)
|
|
{
|
|
caps.bHALSeesSysmem = FALSE;
|
|
sbi.helonly = TRUE; // HEL only
|
|
}
|
|
else
|
|
{
|
|
DPF_ERR("Driver does not support blitting");
|
|
LEAVE_BOTH_NOBUSY();
|
|
return DDERR_NOBLTHW;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Validate height and width of destination rectangle.
|
|
*/
|
|
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(surf_dest, surf_dest_lcl, bd.rDest);
|
|
}
|
|
|
|
sbi.dest_height = bd.rDest.bottom - bd.rDest.top;
|
|
sbi.dest_width = bd.rDest.right - bd.rDest.left;
|
|
|
|
if (((int)sbi.dest_height <= 0) || ((int)sbi.dest_width <= 0))
|
|
{
|
|
DPF_ERR("Bad dest width or height -- must be positive and nonzero");
|
|
LEAVE_BOTH_NOBUSY();
|
|
return DDERR_INVALIDRECT;
|
|
}
|
|
|
|
/*
|
|
* Validate height and width of source rectangle.
|
|
*/
|
|
if (surf_src != NULL)
|
|
{
|
|
/*
|
|
* Get source rectangle.
|
|
*/
|
|
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
|
|
{
|
|
MAKE_SURF_RECT(surf_src, surf_src_lcl, bd.rSrc);
|
|
}
|
|
|
|
sbi.src_height = bd.rSrc.bottom - bd.rSrc.top;
|
|
sbi.src_width = bd.rSrc.right - bd.rSrc.left;
|
|
|
|
if (((int)sbi.src_height <= 0) || ((int)sbi.src_width <= 0))
|
|
{
|
|
DPF_ERR("Bad source width or height -- must be positive and nonzero");
|
|
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 ((surf_src->lpDD->dwFlags & DDRAWI_VIRTUALDESKTOP) &&
|
|
(surf_src_lcl->ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE))
|
|
{
|
|
if ((bd.rSrc.left < surf_src->lpDD->rectDevice.left) ||
|
|
(bd.rSrc.top < surf_src->lpDD->rectDevice.top) ||
|
|
(bd.rSrc.right > surf_src->lpDD->rectDevice.right)||
|
|
(bd.rSrc.bottom > surf_src->lpDD->rectDevice.bottom))
|
|
{
|
|
DPF_ERR("Source rect doesn't fit on Desktop");
|
|
LEAVE_BOTH_NOBUSY();
|
|
return DDERR_INVALIDRECT;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ((int)bd.rSrc.left < 0 ||
|
|
(int)bd.rSrc.top < 0 ||
|
|
(DWORD)bd.rSrc.bottom > (DWORD)surf_src->wHeight ||
|
|
(DWORD)bd.rSrc.right > (DWORD)surf_src->wWidth)
|
|
{
|
|
DPF_ERR("Invalid source rect specified");
|
|
LEAVE_BOTH_NOBUSY();
|
|
return DDERR_INVALIDRECT;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Verify stretching...
|
|
*/
|
|
if (sbi.src_height != sbi.dest_height || sbi.src_width != sbi.dest_width)
|
|
{
|
|
HRESULT ddrval = validateStretching(&caps, &sbi);
|
|
|
|
if (ddrval != DD_OK)
|
|
{
|
|
DPF_ERR("Can't perform specified stretching");
|
|
LEAVE_BOTH_NOBUSY();
|
|
return ddrval;
|
|
}
|
|
/*
|
|
* Do source and dest rectangles lie on the same surface and overlap?
|
|
*/
|
|
if (surf_src_lcl == surf_dest_lcl &&
|
|
IntersectRect(&rect, (LPRECT)&bd.rSrc, (LPRECT)&bd.rDest))
|
|
{
|
|
DPF_ERR("Can't stretch if source/dest rectangles overlap");
|
|
LEAVE_BOTH_NOBUSY();
|
|
return DDERR_OVERLAPPINGRECTS;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Get pixel-format flags for source and destination surfaces.
|
|
*/
|
|
dwDDPFDestFlags = getPixelFormatPtr(surf_dest_lcl)->dwFlags;
|
|
if (surf_src_lcl != NULL)
|
|
{
|
|
dwDDPFSrcFlags = getPixelFormatPtr(surf_src_lcl)->dwFlags;
|
|
}
|
|
else
|
|
{
|
|
dwDDPFSrcFlags = 0;
|
|
}
|
|
|
|
/*
|
|
* Special Restrictions on Pixel Formats:
|
|
* -- If the surfaces have pixel formats that either are FOURCCs
|
|
* or are understood by the AlphaBlt HEL, no restrictions are
|
|
* imposed on the range of AlphaBlt features available for
|
|
* blit and fill operations. All formats that are understood
|
|
* by the HEL are listed in the PFTable array in ablthel.c.
|
|
* -- If either surface has a non-FOURCC pixel format that is not
|
|
* understood by AlphaBlt HEL, only a copy blit is permitted.
|
|
* For a copy blit, the source and dest formats are identical,
|
|
* and features such as stretching, mirroring, filtering, color
|
|
* keying, alpha blending, and ARGB scaling are not used.
|
|
*/
|
|
if ((!(dwDDPFDestFlags & DDPF_FOURCC) &&
|
|
(GetSurfPFIndex(surf_dest_lcl) == PFINDEX_UNSUPPORTED)) ||
|
|
((surf_src_lcl != NULL) && !(dwDDPFDestFlags & DDPF_FOURCC) &&
|
|
(GetSurfPFIndex(surf_src_lcl) == PFINDEX_UNSUPPORTED)))
|
|
{
|
|
LPDDPIXELFORMAT pDDPFDest = getPixelFormatPtr(surf_dest_lcl);
|
|
LPDDPIXELFORMAT pDDPFSrc = getPixelFormatPtr(surf_src_lcl);
|
|
/*
|
|
* This blit involves a non-FOURCC format that is unknown to the
|
|
* AlphaBlt HEL. In this case, we accept the blit operation only
|
|
* if it is a simple copy blit. It's okay if the rects overlap.
|
|
*/
|
|
if ((surf_src_lcl == NULL) || !doPixelFormatsMatch(pDDPFDest, pDDPFSrc))
|
|
{
|
|
DPF_ERR("Only copy blits are available with specified pixel format");
|
|
LEAVE_BOTH_NOBUSY();
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
// Is the DDABLT_NOBLEND flag specified?
|
|
if (!(dwFlags & DDABLT_NOBLEND))
|
|
{
|
|
DPF_ERR("NOBLEND flag is required to blit with specified pixel format");
|
|
LEAVE_BOTH_NOBUSY();
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
// Are any inappropriate DDABLT flags set?
|
|
|
|
if (dwFlags & (DDABLT_MIRRORUPDOWN | DDABLT_MIRRORLEFTRIGHT |
|
|
DDABLT_KEYSRC | DDABLT_DEGRADEARGBSCALING |
|
|
DDABLT_FILTERENABLE | DDABLT_FILTERTRANSPBORDER))
|
|
{
|
|
DPF_ERR("Specified DDABLT flag is incompatible with pixel format");
|
|
LEAVE_BOTH_NOBUSY();
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
// Is stretching required for this blit?
|
|
if (sbi.src_height != sbi.dest_height || sbi.src_width != sbi.dest_width)
|
|
{
|
|
DPF_ERR("Stretching is not permitted with specified pixel format");
|
|
LEAVE_BOTH_NOBUSY();
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
// Are the ARGB-scaling factors disabled (i.e., set to all ones)?
|
|
if (*(LPDWORD)&ddargbScaleFactors != ~0UL)
|
|
{
|
|
DPF_ERR("ARGB scaling must be disabled with specified pixel format");
|
|
LEAVE_BOTH_NOBUSY();
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Do source and dest rectangles lie on the same surface and overlap?
|
|
*/
|
|
if (surf_src_lcl == surf_dest_lcl &&
|
|
IntersectRect(&rect, (LPRECT)&bd.rSrc, (LPRECT)&bd.rDest))
|
|
{
|
|
/*
|
|
* Yes, enforce restrictions on blits with overlapping rectangles.
|
|
*/
|
|
if (!(dwFlags & DDABLT_NOBLEND))
|
|
{
|
|
DPF_ERR("Can't blit between overlapping rects unless NOBLEND flag is set");
|
|
LEAVE_BOTH_NOBUSY();
|
|
return DDERR_OVERLAPPINGRECTS;
|
|
}
|
|
if (dwFlags & (DDABLT_MIRRORUPDOWN | DDABLT_MIRRORLEFTRIGHT |
|
|
DDABLT_KEYSRC | DDABLT_DEGRADEARGBSCALING |
|
|
DDABLT_FILTERENABLE | DDABLT_FILTERTRANSPBORDER))
|
|
{
|
|
DPF_ERR("Specified flag is illegal if source/dest rectangles overlap");
|
|
LEAVE_BOTH_NOBUSY();
|
|
return DDERR_OVERLAPPINGRECTS;
|
|
}
|
|
if (dwDDPFDestFlags & DDPF_FOURCC)
|
|
{
|
|
DPF_ERR("Overlapping source/dest rectangles illegal with FOURCC surface");
|
|
LEAVE_BOTH_NOBUSY();
|
|
return DDERR_OVERLAPPINGRECTS;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Does the destination surface have a FOURCC pixel format?
|
|
*/
|
|
if (dwDDPFDestFlags & DDPF_FOURCC)
|
|
{
|
|
// The DDABLT_USEFILLVALUE flag is illegal with a FOURCC dest surface.
|
|
if (dwFlags & DDABLT_USEFILLVALUE)
|
|
{
|
|
DPF_ERR("Can't use USEFILLVALUE flag with FOURCC dest surface");
|
|
LEAVE_BOTH_NOBUSY();
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
}
|
|
|
|
fail = FALSE; // initialize before using GETFAILCODEBLT macro
|
|
|
|
/*
|
|
* Validate source color key.
|
|
*/
|
|
if (dwFlags & DDABLT_KEYSRC)
|
|
{
|
|
DDASSERT(surf_src != NULL);
|
|
// make sure we can do this
|
|
if (!(caps.dwBothCKeyCaps & DDCKEYCAPS_SRCBLT))
|
|
{
|
|
GETFAILCODEBLT(caps.dwCKeyCaps,
|
|
caps.dwHELCKeyCaps,
|
|
sbi.halonly,
|
|
sbi.helonly,
|
|
DDCKEYCAPS_SRCBLT);
|
|
if (fail)
|
|
{
|
|
DPF_ERR("KEYSRC specified, not supported");
|
|
LEAVE_BOTH_NOBUSY();
|
|
return DDERR_NOCOLORKEYHW;
|
|
}
|
|
}
|
|
if (!(surf_src_lcl->dwFlags & DDRAWISURF_HASCKEYSRCBLT) ||
|
|
(dwDDPFSrcFlags & (DDPF_FOURCC | DDPF_ALPHAPIXELS)))
|
|
{
|
|
/*
|
|
* If the src color-key flag is set but the source surface has
|
|
* no associated src color key, just clear the flag instead of
|
|
* treating this as an error.
|
|
*/
|
|
dwFlags &= ~DDABLT_KEYSRC;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Validate up/down mirroring
|
|
*/
|
|
if (dwFlags & DDABLT_MIRRORUPDOWN)
|
|
{
|
|
DDASSERT(surf_src != NULL);
|
|
if (!(caps.dwBothFXCaps & DDFXCAPS_BLTMIRRORUPDOWN))
|
|
{
|
|
GETFAILCODEBLT(caps.dwFXCaps,
|
|
caps.dwHELFXCaps,
|
|
sbi.halonly,
|
|
sbi.helonly,
|
|
DDFXCAPS_BLTMIRRORUPDOWN);
|
|
if (fail)
|
|
{
|
|
DPF_ERR("Mirror up/down specified, not supported");
|
|
LEAVE_BOTH_NOBUSY();
|
|
return DDERR_NOMIRRORHW;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Validate left/right mirroring
|
|
*/
|
|
if (dwFlags & DDABLT_MIRRORLEFTRIGHT)
|
|
{
|
|
DDASSERT(surf_src != NULL);
|
|
if (!(caps.dwBothFXCaps & DDFXCAPS_BLTMIRRORLEFTRIGHT))
|
|
{
|
|
GETFAILCODEBLT(caps.dwFXCaps,
|
|
caps.dwHELFXCaps,
|
|
sbi.halonly,
|
|
sbi.helonly,
|
|
DDFXCAPS_BLTMIRRORLEFTRIGHT);
|
|
if (fail)
|
|
{
|
|
DPF_ERR("Mirror left/right specified, not supported");
|
|
LEAVE_BOTH_NOBUSY();
|
|
return DDERR_NOMIRRORHW;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Does destination surface have a palette-indexed pixel format?
|
|
*/
|
|
if (dwDDPFDestFlags & (DDPF_PALETTEINDEXED1 | DDPF_PALETTEINDEXED2 |
|
|
DDPF_PALETTEINDEXED4 | DDPF_PALETTEINDEXED8))
|
|
{
|
|
/*
|
|
* Is this a blit or a color-fill operation?
|
|
*/
|
|
if (surf_src_lcl == NULL)
|
|
{
|
|
/*
|
|
* Color-Fill: Palette-indexed dest is illegal without USEFILLVALUE flag.
|
|
*/
|
|
if (!(dwFlags & DDABLT_USEFILLVALUE))
|
|
{
|
|
DPF_ERR("USEFILLVALUE flag required to fill palette-indexed dest surface");
|
|
LEAVE_BOTH_NOBUSY();
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* Blit: Destination surface is palette-indexed, so we require source
|
|
* surface to have same pixel format as destination. (Note that this
|
|
* also makes color fills illegal to palette-indexed dest surfaces.)
|
|
*/
|
|
if (dwDDPFSrcFlags != dwDDPFDestFlags)
|
|
{
|
|
DPF_ERR("If dest is palette-indexed, source must have same pixel format");
|
|
LEAVE_BOTH_NOBUSY();
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
if (dwFlags & (DDABLT_FILTERENABLE | DDABLT_FILTERTRANSPBORDER))
|
|
{
|
|
DPF_ERR("Illegal to specify filtering with palette-indexed destination");
|
|
LEAVE_BOTH_NOBUSY();
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
if (*(LPDWORD)&ddargbScaleFactors != ~0UL)
|
|
{
|
|
DPF_ERR("Illegal to enable ARGB scaling with palette-indexed destination");
|
|
LEAVE_BOTH_NOBUSY();
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
/*
|
|
* If source and dest surfaces both have attached palettes, we require that
|
|
* they reference the same palette object. In a later release, we may relax
|
|
* this requirement in order to support color-table conversion or dithering.
|
|
*/
|
|
if ((surf_src_lcl->lpDDPalette != NULL) &&
|
|
(surf_dest_lcl->lpDDPalette != NULL) &&
|
|
(surf_src_lcl->lpDDPalette->lpLcl->lpGbl->lpColorTable !=
|
|
surf_dest_lcl->lpDDPalette->lpLcl->lpGbl->lpColorTable))
|
|
{
|
|
DPF_ERR("If source and dest surfaces both have palettes, must be same palette");
|
|
LEAVE_BOTH_NOBUSY();
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
}
|
|
}
|
|
else if (dwDDPFSrcFlags & (DDPF_PALETTEINDEXED1 | DDPF_PALETTEINDEXED2 |
|
|
DDPF_PALETTEINDEXED4 | DDPF_PALETTEINDEXED8) &&
|
|
(surf_src_lcl->lpDDPalette == NULL ||
|
|
surf_src_lcl->lpDDPalette->lpLcl->lpGbl->lpColorTable == NULL))
|
|
{
|
|
/*
|
|
* Conversion of source pixels to destination pixel format is
|
|
* impossible because source surface has no attached palette.
|
|
*/
|
|
DPF_ERR( "No palette associated with palette-indexed source surface" );
|
|
LEAVE_BOTH_NOBUSY();
|
|
return DDERR_NOPALETTEATTACHED;
|
|
}
|
|
|
|
/*
|
|
* We do no ARGB scaling if NOBLEND flag is set.
|
|
*/
|
|
if (dwFlags & DDABLT_NOBLEND)
|
|
{
|
|
if (dwFlags & DDABLT_DEGRADEARGBSCALING)
|
|
{
|
|
DPF_ERR("NOBLEND and DEGRADEARGBSCALING flags are incompatible");
|
|
LEAVE_BOTH();
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
if (surf_src != NULL && *(LPDWORD)&ddargbScaleFactors != ~0UL)
|
|
{
|
|
DPF_ERR("ARGB scaling of source surface illegal if NOBLEND flag is set");
|
|
LEAVE_BOTH_NOBUSY();
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
}
|
|
else if ((dwDDPFSrcFlags | dwDDPFDestFlags) & DDPF_ALPHAPIXELS)
|
|
{
|
|
/*
|
|
* We've been asked to perform a blit or fill that requires blending
|
|
* with the alpha-channel information in the pixel formats for one
|
|
* or both surfaces. Verify that the driver supports this.
|
|
*/
|
|
if (!(caps.dwBothFXCaps & DDFXCAPS_BLTALPHA))
|
|
{
|
|
GETFAILCODEBLT(caps.dwFXCaps,
|
|
caps.dwHELFXCaps,
|
|
sbi.halonly,
|
|
sbi.helonly,
|
|
DDFXCAPS_BLTALPHA);
|
|
if (fail)
|
|
{
|
|
DPF_ERR("Alpha-blended blit requested, but not supported");
|
|
LEAVE_BOTH_NOBUSY();
|
|
return DDERR_NOALPHAHW;
|
|
}
|
|
}
|
|
/*
|
|
* Verify that the driver supports surfaces whose pixel
|
|
* formats contain an alpha-channel component.
|
|
*/
|
|
if (!(caps.dwBothAlphaCaps & DDALPHACAPS_BLTALPHAPIXELS))
|
|
{
|
|
GETFAILCODEBLT(caps.dwAlphaCaps,
|
|
caps.dwHELAlphaCaps,
|
|
sbi.halonly,
|
|
sbi.helonly,
|
|
DDALPHACAPS_BLTALPHAPIXELS);
|
|
if (fail)
|
|
{
|
|
DPF_ERR("Alpha pixel format specified, but not supported");
|
|
LEAVE_BOTH_NOBUSY();
|
|
return DDERR_NOALPHAHW;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Does dest surface have alpha channel?
|
|
*/
|
|
if (dwDDPFDestFlags & DDPF_ALPHAPIXELS)
|
|
{
|
|
/*
|
|
* Verify that destination surface has a premultiplied-
|
|
* alpha pixel format. Non-premultiplied alpha won't do.
|
|
*/
|
|
if (!(dwDDPFDestFlags & DDPF_ALPHAPREMULT))
|
|
{
|
|
DPF_ERR("Illegal to blend with non-premultiplied alpha in dest surface");
|
|
LEAVE_BOTH_NOBUSY();
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
/*
|
|
* Verify that driver can handle premultiplied-alpha pixel format.
|
|
* (Dest surface is not allowed to be non-premultiplied alpha.)
|
|
*/
|
|
if (!(caps.dwBothAlphaCaps & DDALPHACAPS_BLTPREMULT))
|
|
{
|
|
GETFAILCODEBLT(caps.dwAlphaCaps,
|
|
caps.dwHELAlphaCaps,
|
|
sbi.halonly,
|
|
sbi.helonly,
|
|
DDALPHACAPS_BLTPREMULT);
|
|
if (fail)
|
|
{
|
|
DPF_ERR("No driver support for premultiplied alpha");
|
|
LEAVE_BOTH_NOBUSY();
|
|
return DDERR_NOALPHAHW;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Does source surface have alpha channel?
|
|
*/
|
|
if (dwDDPFSrcFlags & DDPF_ALPHAPIXELS)
|
|
{
|
|
/*
|
|
* Are we asking the driver to handle both ARGB scaling and a
|
|
* source alpha channel when it can't do both at the same time?
|
|
*/
|
|
if (*(LPDWORD)&ddargbScaleFactors != ~0 &&
|
|
!(caps.dwBothAlphaCaps & DDALPHACAPS_BLTALPHAANDARGBSCALING) &&
|
|
!(dwFlags & DDABLT_DEGRADEARGBSCALING))
|
|
{
|
|
if (!(caps.dwBothAlphaCaps & DDALPHACAPS_BLTALPHAANDARGBSCALING))
|
|
{
|
|
GETFAILCODEBLT(caps.dwAlphaCaps,
|
|
caps.dwHELAlphaCaps,
|
|
sbi.halonly,
|
|
sbi.helonly,
|
|
DDALPHACAPS_BLTALPHAANDARGBSCALING);
|
|
if (fail)
|
|
{
|
|
DPF_ERR("No driver support for alpha channel and ARGB scaling in same blit");
|
|
LEAVE_BOTH_NOBUSY();
|
|
return DDERR_NOALPHAHW;
|
|
}
|
|
}
|
|
}
|
|
/*
|
|
* Are color components in pixel format premultiplied by the
|
|
* alpha component or not? In either case, verify that the
|
|
* driver supports the specified alpha format.
|
|
*/
|
|
if (dwDDPFSrcFlags & DDPF_ALPHAPREMULT)
|
|
{
|
|
if (!(caps.dwBothAlphaCaps & DDALPHACAPS_BLTPREMULT))
|
|
{
|
|
GETFAILCODEBLT(caps.dwAlphaCaps,
|
|
caps.dwHELAlphaCaps,
|
|
sbi.halonly,
|
|
sbi.helonly,
|
|
DDALPHACAPS_BLTPREMULT);
|
|
if (fail)
|
|
{
|
|
DPF_ERR("No driver support for premultiplied alpha");
|
|
LEAVE_BOTH_NOBUSY();
|
|
return DDERR_NOALPHAHW;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DWORD val = 0x01010101UL*ddargbScaleFactors.alpha;
|
|
|
|
if (!(caps.dwBothAlphaCaps & DDALPHACAPS_BLTNONPREMULT))
|
|
{
|
|
GETFAILCODEBLT(caps.dwAlphaCaps,
|
|
caps.dwHELAlphaCaps,
|
|
sbi.halonly,
|
|
sbi.helonly,
|
|
DDALPHACAPS_BLTNONPREMULT);
|
|
if (fail)
|
|
{
|
|
DPF_ERR("No driver support for non-premultiplied alpha");
|
|
LEAVE_BOTH_NOBUSY();
|
|
return DDERR_NOALPHAHW;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* We allow only one-factor ARGB scaling with a source
|
|
* surface that has a non-premultiplied alpha pixel format.
|
|
* The following code enforces this rule.
|
|
*/
|
|
if (*(LPDWORD)&ddargbScaleFactors != val)
|
|
{
|
|
if (dwFlags & DDABLT_DEGRADEARGBSCALING)
|
|
{
|
|
*(LPDWORD)&ddargbScaleFactors = val;
|
|
}
|
|
else
|
|
{
|
|
DPF_ERR("Can't do 2 or 4-mult ARGB scaling with non-premultiplied alpha surface");
|
|
LEAVE_BOTH_NOBUSY();
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* If filtering is to be explicitly enabled or disabled, verify that
|
|
* the hardware driver is capable of performing the blit as requested.
|
|
*/
|
|
if (dwFlags & (DDABLT_FILTERENABLE | DDABLT_FILTERDISABLE | DDABLT_FILTERTRANSPBORDER))
|
|
{
|
|
/*
|
|
* Is driver capable of doing any kind of filtering at all?
|
|
*/
|
|
if (!(caps.dwBothFXCaps & DDFXCAPS_BLTFILTER))
|
|
{
|
|
GETFAILCODEBLT(caps.dwFXCaps,
|
|
caps.dwHELFXCaps,
|
|
sbi.halonly,
|
|
sbi.helonly,
|
|
DDFXCAPS_BLTFILTER);
|
|
if (fail)
|
|
{
|
|
DPF_ERR("No driver support for filtered blit");
|
|
LEAVE_BOTH_NOBUSY();
|
|
return DDERR_NOALPHAHW;
|
|
}
|
|
}
|
|
if (!(~dwFlags & (DDABLT_FILTERENABLE | DDABLT_FILTERDISABLE)))
|
|
{
|
|
DPF_ERR("Illegal to both enable and disable filtering");
|
|
LEAVE_BOTH_NOBUSY();
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
if (!(~dwFlags & (DDABLT_FILTERTRANSPBORDER | DDABLT_FILTERDISABLE)))
|
|
{
|
|
DPF_ERR("Illegal to set FILTERTRANSPBORDER if filtering is explicitly disabled");
|
|
LEAVE_BOTH_NOBUSY();
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
if ((dwFlags & DDABLT_FILTERENABLE) &&
|
|
!(caps.dwBothFilterCaps & DDFILTCAPS_BLTQUALITYFILTER))
|
|
{
|
|
GETFAILCODEBLT(caps.dwFilterCaps,
|
|
caps.dwHELFilterCaps,
|
|
sbi.halonly,
|
|
sbi.helonly,
|
|
DDFILTCAPS_BLTQUALITYFILTER);
|
|
if (fail)
|
|
{
|
|
DPF_ERR("No driver support for filtered blit");
|
|
LEAVE_BOTH_NOBUSY();
|
|
return DDERR_NOALPHAHW;
|
|
}
|
|
}
|
|
if ((dwFlags & DDABLT_FILTERDISABLE) &&
|
|
!(caps.dwBothFilterCaps & DDFILTCAPS_BLTCANDISABLEFILTER))
|
|
{
|
|
GETFAILCODEBLT(caps.dwFilterCaps,
|
|
caps.dwHELFilterCaps,
|
|
sbi.halonly,
|
|
sbi.helonly,
|
|
DDFILTCAPS_BLTCANDISABLEFILTER);
|
|
if (fail)
|
|
{
|
|
DPF_ERR("Driver cannot disable filtering for blits");
|
|
LEAVE_BOTH_NOBUSY();
|
|
return DDERR_NOALPHAHW;
|
|
}
|
|
}
|
|
if ((dwFlags & DDABLT_FILTERTRANSPBORDER) &&
|
|
!(caps.dwBothFilterCaps & DDFILTCAPS_BLTTRANSPBORDER))
|
|
{
|
|
GETFAILCODEBLT(caps.dwFilterCaps,
|
|
caps.dwHELFilterCaps,
|
|
sbi.halonly,
|
|
sbi.helonly,
|
|
DDFILTCAPS_BLTTRANSPBORDER);
|
|
if (fail)
|
|
{
|
|
DPF_ERR("Driver cannot filter with transparent border");
|
|
LEAVE_BOTH_NOBUSY();
|
|
return DDERR_NOALPHAHW;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Validate ARGB scaling factors.
|
|
*/
|
|
if (!(dwFlags & DDABLT_DEGRADEARGBSCALING) &&
|
|
*(LPDWORD)&ddargbScaleFactors != ~0UL &&
|
|
!(surf_src_lcl == NULL && ddargbScaleFactors.alpha == 255))
|
|
{
|
|
/*
|
|
* Some kind of ARGB scaling is specified. Can the driver
|
|
* do any kind of alpha blending at all?
|
|
*/
|
|
if (!(caps.dwBothFXCaps & DDFXCAPS_BLTALPHA))
|
|
{
|
|
GETFAILCODEBLT(caps.dwFXCaps,
|
|
caps.dwHELFXCaps,
|
|
sbi.halonly,
|
|
sbi.helonly,
|
|
DDFXCAPS_BLTALPHA);
|
|
if (fail)
|
|
{
|
|
DPF_ERR("ARGB scaling requested for blit, but not supported");
|
|
LEAVE_BOTH_NOBUSY();
|
|
return DDERR_NOALPHAHW;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* We permit a color factor to be bigger than the alpha
|
|
* factor only if the hardware uses saturated arithmetic
|
|
* to prevent the calculated color value from overflowing.
|
|
*/
|
|
if (!(dwFlags & DDABLT_NOBLEND) &&
|
|
(ddargbScaleFactors.red > ddargbScaleFactors.alpha ||
|
|
ddargbScaleFactors.green > ddargbScaleFactors.alpha ||
|
|
ddargbScaleFactors.blue > ddargbScaleFactors.alpha))
|
|
{
|
|
/*
|
|
* Driver must be capable of doing saturated arithmetic.
|
|
*/
|
|
if (!(caps.dwBothAlphaCaps & DDALPHACAPS_BLTSATURATE))
|
|
{
|
|
GETFAILCODEBLT(caps.dwAlphaCaps,
|
|
caps.dwHELAlphaCaps,
|
|
sbi.halonly,
|
|
sbi.helonly,
|
|
DDALPHACAPS_BLTSATURATE);
|
|
if (fail)
|
|
{
|
|
// Neither the H/W driver nor HEL can handle it, so fail.
|
|
DPF_ERR("Driver can't do saturated arithmetic during alpha blending");
|
|
LEAVE_BOTH_NOBUSY();
|
|
return DDERR_NOALPHAHW;
|
|
}
|
|
}
|
|
}
|
|
/*
|
|
* Is this an alpha-blit or an alpha-fill operation?
|
|
*/
|
|
if (surf_src_lcl == NULL)
|
|
{
|
|
/*
|
|
* This is an alpha fill. Can the driver handle it?
|
|
*/
|
|
if (!(caps.dwBothAlphaCaps & DDALPHACAPS_BLTALPHAFILL))
|
|
{
|
|
GETFAILCODEBLT(caps.dwAlphaCaps,
|
|
caps.dwHELAlphaCaps,
|
|
sbi.halonly,
|
|
sbi.helonly,
|
|
DDALPHACAPS_BLTALPHAFILL);
|
|
if (fail)
|
|
{
|
|
// Neither the H/W driver nor HEL can handle it, so fail.
|
|
DPF_ERR("Driver can't do alpha-blended color-fill operation");
|
|
LEAVE_BOTH_NOBUSY();
|
|
return DDERR_NOALPHAHW;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* Alpha blit. Can the driver handle any ARGB scaling at all?
|
|
*/
|
|
#define ARGBSCALINGBITS \
|
|
(DDALPHACAPS_BLTARGBSCALE1F | DDALPHACAPS_BLTARGBSCALE2F | DDALPHACAPS_BLTARGBSCALE4F)
|
|
|
|
if (!(caps.dwBothAlphaCaps & ARGBSCALINGBITS))
|
|
{
|
|
GETFAILCODEBLT(caps.dwAlphaCaps,
|
|
caps.dwHELAlphaCaps,
|
|
sbi.halonly,
|
|
sbi.helonly,
|
|
ARGBSCALINGBITS);
|
|
if (fail)
|
|
{
|
|
// Neither the H/W driver nor HEL can handle it, so fail.
|
|
DPF_ERR("Driver can't handle any ARGB scaling at all");
|
|
LEAVE_BOTH_NOBUSY();
|
|
return DDERR_NOALPHAHW;
|
|
}
|
|
}
|
|
#undef ARGBSCALINGBITS
|
|
|
|
if (ddargbScaleFactors.red != ddargbScaleFactors.green ||
|
|
ddargbScaleFactors.red != ddargbScaleFactors.blue)
|
|
{
|
|
/*
|
|
* Driver must be capable of doing 4-factor ARGB scaling.
|
|
*/
|
|
if (!(caps.dwBothAlphaCaps & DDALPHACAPS_BLTARGBSCALE4F))
|
|
{
|
|
GETFAILCODEBLT(caps.dwAlphaCaps,
|
|
caps.dwHELAlphaCaps,
|
|
sbi.halonly,
|
|
sbi.helonly,
|
|
DDALPHACAPS_BLTARGBSCALE4F);
|
|
if (fail)
|
|
{
|
|
// Neither the H/W driver nor HEL can handle it, so fail.
|
|
DPF_ERR("Driver can't handle 4-factor ARGB scaling");
|
|
LEAVE_BOTH_NOBUSY();
|
|
return DDERR_NOALPHAHW;
|
|
}
|
|
}
|
|
}
|
|
else if (ddargbScaleFactors.red != ddargbScaleFactors.alpha)
|
|
{
|
|
/*
|
|
* Driver must be capable of doing 2-factor ARGB scaling.
|
|
*/
|
|
if (!(caps.dwBothAlphaCaps & (DDALPHACAPS_BLTARGBSCALE2F |
|
|
DDALPHACAPS_BLTARGBSCALE4F)))
|
|
{
|
|
GETFAILCODEBLT(caps.dwAlphaCaps,
|
|
caps.dwHELAlphaCaps,
|
|
sbi.halonly,
|
|
sbi.helonly,
|
|
DDALPHACAPS_BLTARGBSCALE2F |
|
|
DDALPHACAPS_BLTARGBSCALE4F);
|
|
if (fail)
|
|
{
|
|
// Neither the H/W driver nor HEL can handle it, so fail.
|
|
DPF_ERR("Driver can't handle 2-factor ARGB scaling");
|
|
LEAVE_BOTH_NOBUSY();
|
|
return DDERR_NOALPHAHW;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
DPF_ERR("Exception encountered validating parameters");
|
|
LEAVE_BOTH_NOBUSY();
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
|
|
DDASSERT(!(sbi.halonly && sbi.helonly));
|
|
|
|
/*
|
|
* Are we permitted to degrade the specified ARGB-scaling operation
|
|
* to one the driver can handle?
|
|
*/
|
|
if (dwFlags & DDABLT_DEGRADEARGBSCALING)
|
|
{
|
|
DWORD dwFXCaps, dwAlphaCaps;
|
|
|
|
// Get the caps for the selected driver.
|
|
dwFXCaps = (sbi.helonly) ? caps.dwHELFXCaps : caps.dwFXCaps;
|
|
dwAlphaCaps = (sbi.helonly) ? caps.dwHELAlphaCaps : caps.dwAlphaCaps;
|
|
|
|
if (!(dwFXCaps & DDFXCAPS_BLTALPHA))
|
|
{
|
|
/*
|
|
* The driver should have done this anyway, but just in case...
|
|
*/
|
|
dwAlphaCaps = 0;
|
|
}
|
|
|
|
/*
|
|
* Is this a blit or a fill operation?
|
|
*/
|
|
if (surf_src_lcl == NULL)
|
|
{
|
|
/*
|
|
* This is a fill -- and possibly an alpha fill.
|
|
*/
|
|
if (!(dwAlphaCaps & DDALPHACAPS_BLTALPHAFILL))
|
|
{
|
|
/*
|
|
* The driver can't do an alpha fill, so we'll ask
|
|
* it to do just a simple color fill instead.
|
|
*/
|
|
ddargbScaleFactors.alpha = 255;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* This is a blit. What are the driver's ARGB-scaling capabilities?
|
|
*/
|
|
if (!(dwAlphaCaps & (DDALPHACAPS_BLTARGBSCALE1F |
|
|
DDALPHACAPS_BLTARGBSCALE2F |
|
|
DDALPHACAPS_BLTARGBSCALE4F)))
|
|
{
|
|
/*
|
|
* Driver can't do any kind of ARGB scaling at all, so just
|
|
* disable ARGB scaling by setting all four factors to 255.
|
|
*/
|
|
*(LPDWORD)&ddargbScaleFactors = ~0UL;
|
|
}
|
|
else if (!(dwAlphaCaps & (DDALPHACAPS_BLTARGBSCALE2F |
|
|
DDALPHACAPS_BLTARGBSCALE4F)))
|
|
{
|
|
/*
|
|
* The driver can do only 1-factor ARGB scaling, so set the
|
|
* three color factors to the same value as the alpha factor.
|
|
*/
|
|
*(LPDWORD)&ddargbScaleFactors = 0x01010101UL*ddargbScaleFactors.alpha;
|
|
}
|
|
else if (!(dwAlphaCaps & DDALPHACAPS_BLTARGBSCALE4F))
|
|
{
|
|
/*
|
|
* Driver can do only 2-factor ARGB scaling, so make sure
|
|
* all three color factors are set to the same value.
|
|
*/
|
|
if (ddargbScaleFactors.red != ddargbScaleFactors.green ||
|
|
ddargbScaleFactors.red != ddargbScaleFactors.blue)
|
|
{
|
|
/*
|
|
* Set all three color factors to value F, which is the
|
|
* weighted average of their specified values (Fr,Fg,Fb):
|
|
* F = .299*Fr + .587*Fg + .114*Fb
|
|
*/
|
|
DWORD F = 19595UL*ddargbScaleFactors.red +
|
|
38470UL*ddargbScaleFactors.green +
|
|
7471UL*ddargbScaleFactors.blue;
|
|
|
|
ddargbScaleFactors.red =
|
|
ddargbScaleFactors.green =
|
|
ddargbScaleFactors.blue = (BYTE)(F >> 16);
|
|
}
|
|
}
|
|
if (!(dwAlphaCaps & DDALPHACAPS_BLTALPHAANDARGBSCALING))
|
|
{
|
|
/*
|
|
* Driver can't handle both a source alpha channel and ARGB scaling
|
|
* factors in the same blit operation, so just turn off ARGB scaling.
|
|
*/
|
|
*(LPDWORD)&ddargbScaleFactors = ~0UL;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Can driver do saturated arithmetic for alpha blit or alpha fill?
|
|
*/
|
|
if (!(dwAlphaCaps & DDALPHACAPS_BLTSATURATE))
|
|
{
|
|
/*
|
|
* Driver can't do saturated arithmetic, so make sure no
|
|
* no color factors exceed the value of the alpha factor.
|
|
*/
|
|
if (ddargbScaleFactors.red > ddargbScaleFactors.alpha)
|
|
{
|
|
ddargbScaleFactors.red = ddargbScaleFactors.alpha;
|
|
}
|
|
if (ddargbScaleFactors.green > ddargbScaleFactors.alpha)
|
|
{
|
|
ddargbScaleFactors.green = ddargbScaleFactors.alpha;
|
|
}
|
|
if (ddargbScaleFactors.blue > ddargbScaleFactors.alpha)
|
|
{
|
|
ddargbScaleFactors.blue = ddargbScaleFactors.alpha;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Tell the driver to do the blit.
|
|
*/
|
|
TRY
|
|
{
|
|
/*
|
|
* Finish loading blit data for HAL callback.
|
|
*/
|
|
bd.lpDD = pdrv;
|
|
bd.lpDDDestSurface = surf_dest_lcl;
|
|
bd.lpDDSrcSurface = surf_src_lcl;
|
|
bd.ddargbScaleFactors = ddargbScaleFactors;
|
|
bd.bltFX.dwSize = sizeof( DDBLTFX );
|
|
/*
|
|
* For the AlphaBlt callback, the rOrigDest and rOrigSrc members
|
|
* ALWAYS contain the original dest and source rects.
|
|
*/
|
|
bd.rOrigDest = bd.rDest;
|
|
bd.rOrigSrc = bd.rSrc;
|
|
/*
|
|
* The only AlphaBlt API flags that are propagated to the
|
|
* driver are those that have no Blt API equivalents.
|
|
*/
|
|
bd.dwAFlags = dwFlags & (DDABLT_FILTERENABLE | DDABLT_FILTERDISABLE |
|
|
DDABLT_FILTERTRANSPBORDER | DDABLT_NOBLEND);
|
|
/*
|
|
* This flag tells the driver that it's a source-over-dest operation.
|
|
* This flag is never passed by the Blt API, so drivers which have a
|
|
* unified DDI can distinguish who called them
|
|
*/
|
|
bd.dwAFlags |= DDABLT_SRCOVERDEST;
|
|
|
|
if (dwFlags & DDABLT_KEYSRC) // source color key?
|
|
{
|
|
bd.dwFlags |= DDBLT_KEYSRCOVERRIDE;
|
|
bd.bltFX.ddckSrcColorkey = surf_src_lcl->ddckCKSrcBlt;
|
|
}
|
|
|
|
if (dwFlags & (DDABLT_MIRRORLEFTRIGHT | DDABLT_MIRRORUPDOWN))
|
|
{
|
|
bd.dwFlags |= DDBLT_DDFX;
|
|
|
|
if (dwFlags & DDABLT_MIRRORLEFTRIGHT) //left-right mirroring?
|
|
{
|
|
bd.bltFX.dwDDFX |= DDBLTFX_MIRRORLEFTRIGHT;
|
|
}
|
|
if (dwFlags & DDABLT_MIRRORUPDOWN) // up-down mirroring?
|
|
{
|
|
bd.bltFX.dwDDFX |= DDBLTFX_MIRRORUPDOWN;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* If the specified blit operation can be handled by the Blt HAL
|
|
* callback instead of by the AlphaBlt HAL callback, should it
|
|
* treat the blit as a color-fill or a source-copy operation?
|
|
*/
|
|
if (surf_src_lcl != NULL)
|
|
{
|
|
//it's a srccopy. Set flags appropriately
|
|
bd.dwFlags |= DDBLT_ROP;
|
|
bd.bltFX.dwROP = SRCCOPY;
|
|
bd.dwROPFlags = ROP_HAS_SOURCE; // 0x00000001
|
|
}
|
|
else
|
|
{
|
|
// This is a fill operation of some kind.
|
|
if (dwFlags & DDABLT_USEFILLVALUE)
|
|
{
|
|
HRESULT hres;
|
|
|
|
// The client specified a fill value in the dest pixel format.
|
|
bd.bltFX.dwFillColor = dwFillValue;
|
|
bd.dwFlags |= DDBLT_COLORFILL;
|
|
}
|
|
else if ((bd.ddargbScaleFactors.alpha == 255) || (dwFlags & DDABLT_NOBLEND))
|
|
{
|
|
// The client specified an alpha fill, but no alpha blending is
|
|
// required, so we can replace it with a simple color fill.
|
|
// convert the ARGB value to a physcolor:
|
|
HRESULT hres = ConvertToPhysColor(
|
|
surf_dest_lcl,
|
|
&bd.ddargbScaleFactors,
|
|
&bd.bltFX.dwFillColor);
|
|
|
|
// Make sure this is not a FOURCC or some other funny pixel format.
|
|
if (hres == DD_OK)
|
|
{
|
|
bd.dwFlags |= DDBLT_COLORFILL;
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef WINNT
|
|
// Did the mode change since ENTER_DDRAW?
|
|
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;
|
|
}
|
|
#endif
|
|
|
|
#if defined(WIN95)
|
|
/*
|
|
* 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 (surf_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 blitting 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) &&
|
|
(surf_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
|
|
|
|
#ifdef WINNT
|
|
get_clipping_info:
|
|
#endif
|
|
/*
|
|
* Determine clipping region for destination surface.
|
|
*/
|
|
{
|
|
LPDIRECTDRAWCLIPPER pClipper;
|
|
RECT rcDestSurf;
|
|
|
|
pRgn = (LPRGNDATA)&myRgnBuffer; // this buffer's probably big enough
|
|
pClipper = (LPDIRECTDRAWCLIPPER)surf_dest_lcl->lpSurfMore->lpDDIClipper;
|
|
SetRect(&rcDestSurf, 0, 0, surf_dest->wWidth, surf_dest->wHeight);
|
|
|
|
if (pClipper == NULL)
|
|
{
|
|
/*
|
|
* The destination surface has no attached clipper.
|
|
* Set the clip region to a single rectangle the
|
|
* width and height of the primary surface.
|
|
*/
|
|
pRgn->rdh.nCount = 1; // default = a single clip rect
|
|
memcpy((LPRECT)&pRgn->Buffer, &rcDestSurf, sizeof(RECT));
|
|
/*
|
|
* Add a rect to the region list if this is a managed surface
|
|
*/
|
|
if(IsD3DManaged(surf_dest_lcl))
|
|
{
|
|
LPREGIONLIST lpRegionList = surf_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;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DWORD rgnSize = 0;
|
|
LPDDRAWI_DIRECTDRAW_GBL pdrv = surf_dest_lcl->lpGbl->lpDD;
|
|
|
|
/*
|
|
* This surface has an attached clipper. Get the clip list.
|
|
*/
|
|
ddrval = InternalGetClipList(pClipper,
|
|
&rcDestSurf,
|
|
NULL, // we just want rgnSize
|
|
&rgnSize,
|
|
pdrv);
|
|
if (ddrval != DD_OK)
|
|
{
|
|
DPF_ERR("Couldn't get size of clip region");
|
|
LEAVE_BOTH_NOBUSY();
|
|
return DDERR_GENERIC;
|
|
}
|
|
if (rgnSize > sizeof(myRgnBuffer))
|
|
{
|
|
/*
|
|
* Statically allocated region buffer isn't big enough.
|
|
* Need to dynamically allocate a bigger buffer.
|
|
*/
|
|
pRgn = (LPRGNDATA)MemAlloc(rgnSize);
|
|
if (!pRgn)
|
|
{
|
|
// couldn't allocate memory for clip region
|
|
DPF_ERR("Can't allocate memory to buffer clip region");
|
|
LEAVE_BOTH_NOBUSY();
|
|
return DDERR_OUTOFMEMORY;
|
|
}
|
|
}
|
|
ddrval = InternalGetClipList(pClipper,
|
|
&rcDestSurf,
|
|
pRgn,
|
|
&rgnSize,
|
|
pdrv);
|
|
if (ddrval != DD_OK)
|
|
{
|
|
// can't get clip region
|
|
if (pRgn != (LPRGNDATA)&myRgnBuffer)
|
|
{
|
|
MemFree(pRgn);
|
|
}
|
|
DPF_ERR("Can't get dest clip region");
|
|
LEAVE_BOTH_NOBUSY();
|
|
return DDERR_GENERIC;
|
|
}
|
|
|
|
if(IsD3DManaged(surf_dest_lcl))
|
|
{
|
|
/* We don't want to deal with this mess, so mark everything dirty */
|
|
surf_dest_lcl->lpSurfMore->lpRegionList->rdh.nCount = NUM_RECTS_IN_REGIONLIST;
|
|
}
|
|
}
|
|
/*
|
|
* Load clipping info into data struct for HAL callback.
|
|
*/
|
|
bd.dwRectCnt = pRgn->rdh.nCount;
|
|
bd.prDestRects = (LPRECT)&pRgn->Buffer;
|
|
}
|
|
|
|
/*
|
|
* Does the driver have to do any clipping?
|
|
*/
|
|
if (bd.dwRectCnt > 1)
|
|
{
|
|
// Yes, clipping is (probably) required.
|
|
bd.IsClipped = TRUE;
|
|
}
|
|
else if (bd.dwRectCnt == 0)
|
|
{
|
|
// Window is completely obscured, so don't draw anything.
|
|
LEAVE_BOTH_NOBUSY();
|
|
return DD_OK;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* The visibility region consists of a single clip rect.
|
|
* Is any portion of the destination rectangle visible?
|
|
*/
|
|
if (!IntersectRect((LPRECT)&bd.rDest, (LPRECT)&bd.rOrigDest,
|
|
&bd.prDestRects[0]))
|
|
{
|
|
// No portion of the destination rectangle is visible.
|
|
LEAVE_BOTH_NOBUSY();
|
|
return DD_OK;
|
|
}
|
|
|
|
/*
|
|
* Will the source rectangle have to be adjusted to
|
|
* compensate for the clipping of the dest rect?
|
|
*/
|
|
if (surf_src_lcl != NULL &&
|
|
!EqualRect((LPRECT)&bd.rDest, (LPRECT)&bd.rOrigDest))
|
|
{
|
|
// Yes, the source rect must be adjusted.
|
|
if (sbi.dest_width != sbi.src_width ||
|
|
sbi.dest_height != sbi.src_height)
|
|
{
|
|
/*
|
|
* The driver must do the clipping for a stretched blit
|
|
* because bd.rSrc permits us to express the adjusted
|
|
* source rect only to the nearest integer coordinates.
|
|
*/
|
|
bd.IsClipped = TRUE;
|
|
}
|
|
else
|
|
{
|
|
// We can do the clipping here for a nonstretched blit.
|
|
POINT p;
|
|
|
|
p.x = bd.rOrigSrc.left - bd.rOrigDest.left;
|
|
p.y = bd.rOrigSrc.top - bd.rOrigDest.top;
|
|
CopyRect((LPRECT)&bd.rSrc, (LPRECT)&bd.rDest);
|
|
OffsetRect((LPRECT)&bd.rSrc, p.x, p.y);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Older drivers may support the Blt callback, but not the AlphaBlt
|
|
* callback. One of these drivers may be able to perform the specified
|
|
* blit operation as long as it doesn't use any AlphaBlt-specific
|
|
* features such as alpha blending, ARGB scaling, or filtering.
|
|
* In this case, we can use the Blt callback to perform the blit.
|
|
* Decide which DDI to call. Start off assuming Alpha DDI
|
|
*/
|
|
bltfn = pdrv_lcl->lpDDCB->HALDDMiscellaneous2.AlphaBlt;
|
|
bd.dwFlags |= DDBLT_AFLAGS; // assume we'll use AlphaBlt callback
|
|
|
|
/*
|
|
* Check to see if we can pass this call to old blt DDI
|
|
*/
|
|
if ( !((dwDDPFDestFlags | dwDDPFSrcFlags) & DDPF_ALPHAPIXELS) &&
|
|
!(dwFlags & DDABLT_FILTERENABLE) )
|
|
{
|
|
// There are no alpha pixels involved. Maybe we can use the Blt DDI
|
|
if ( (bd.ddargbScaleFactors.alpha == 255) && (!sbi.helonly) )
|
|
{
|
|
LPDDPIXELFORMAT pDDPFDest = getPixelFormatPtr(surf_dest_lcl);
|
|
LPDDPIXELFORMAT pDDPFSrc = getPixelFormatPtr(surf_src_lcl);
|
|
|
|
// If this is a blit (and not a color fill), the source and dest pixel
|
|
// formats must be identical and the scaling factors must all be 1.0.
|
|
if ( (surf_src_lcl == NULL) ||
|
|
(!memcmp(pDDPFDest, pDDPFSrc, sizeof(DDPIXELFORMAT)) &&
|
|
(~0UL == *((LPDWORD)(&bd.ddargbScaleFactors)))) )
|
|
{
|
|
// Make sure the driver doesn't have to do any clipping. Also ensure
|
|
// that the driver does not require DDraw to pagelock sysmem surfaces.
|
|
if (!bd.IsClipped &&
|
|
(!caps.bHALSeesSysmem ||
|
|
pdrv->ddCaps.dwCaps2 & DDCAPS2_NOPAGELOCKREQUIRED))
|
|
{
|
|
// Verify that the driver supports the Blt HAL callback.
|
|
bltfn = (LPDDHAL_ALPHABLT) pdrv_lcl->lpDDCB->HALDDSurface.Blt;
|
|
|
|
if (bltfn)
|
|
{
|
|
bd.dwFlags &= ~DDBLT_AFLAGS; // we'll use Blt callback
|
|
if (surf_src_lcl == NULL)
|
|
{
|
|
DPF(4,"Calling Blt DDI for AlphaBlt color fill");
|
|
}
|
|
else
|
|
{
|
|
DPF(4,"Calling Blt DDI for AlphaBlt copy");
|
|
}
|
|
/*
|
|
* The following thunk address is used by the Blt callback,
|
|
* but is ignored by the AlphaBlt callback.
|
|
*/
|
|
bd.Blt = pdrv_lcl->lpDDCB->cbDDSurfaceCallbacks.Blt;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Set up for a HAL or a HEL call?
|
|
*/
|
|
if (bltfn == NULL)
|
|
{
|
|
/*
|
|
* Neither the alphablt nor blt ddi calls apply or aren't implemented
|
|
*/
|
|
sbi.helonly = TRUE;
|
|
}
|
|
if (sbi.helonly && sbi.halonly)
|
|
{
|
|
DPF_ERR("AlphaBlt not supported in software or hardware");
|
|
if (pRgn != (LPRGNDATA)&myRgnBuffer)
|
|
{
|
|
MemFree(pRgn); // this clip region was malloc'd
|
|
}
|
|
LEAVE_BOTH_NOBUSY();
|
|
return DDERR_NOBLTHW;
|
|
}
|
|
|
|
/*
|
|
* Can the hardware driver perform the blit?
|
|
*/
|
|
if (!sbi.helonly)
|
|
{
|
|
/*
|
|
* Yes, we're going to do a hardware-accelerated blit.
|
|
*/
|
|
DPF(4, "Hardware AlphaBlt");
|
|
/*
|
|
* The DDI was selected above
|
|
*/
|
|
//bd.AlphaBlt = NULL; // 32-bit call, no thunk
|
|
|
|
/*
|
|
* Tell the hardware driver to perform the blit. We may have to wait
|
|
* if the driver is still busy with a previous drawing operation.
|
|
*/
|
|
do
|
|
{
|
|
DOHALCALL_NOWIN16(AlphaBlt, bltfn, bd, rc, sbi.helonly);
|
|
if (rc != DDHAL_DRIVER_HANDLED || bd.ddRVal != DDERR_WASSTILLDRAWING)
|
|
{
|
|
break; // driver's finished for better or worse...
|
|
}
|
|
DPF(4, "Waiting...");
|
|
|
|
} while (dwFlags & DDABLT_WAIT);
|
|
|
|
/*
|
|
* Was the hardware driver able to handle the blit?
|
|
*/
|
|
if (rc == DDHAL_DRIVER_HANDLED)
|
|
{
|
|
#ifdef WINNT
|
|
if (bd.ddRVal == DDERR_VISRGNCHANGED)
|
|
{
|
|
if (pRgn != (LPRGNDATA)&myRgnBuffer)
|
|
{
|
|
MemFree(pRgn);
|
|
}
|
|
DPF(5,"Resetting VisRgn for surface %x", surf_dest_lcl);
|
|
DdResetVisrgn(surf_dest_lcl, (HWND)0);
|
|
goto get_clipping_info;
|
|
}
|
|
#endif
|
|
if (bd.ddRVal != DDERR_WASSTILLDRAWING)
|
|
{
|
|
/*
|
|
* Yes, the blit was handled by the hardware driver.
|
|
* If source or dest surface is in system memory, tag it so
|
|
* we know it's involved in an ongoing hardware operation.
|
|
*/
|
|
if (bd.ddRVal == DD_OK && caps.bHALSeesSysmem)
|
|
{
|
|
DPF(5,B,"Tagging surface %08x", surf_dest);
|
|
if (surf_dest_lcl->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY)
|
|
surf_dest->dwGlobalFlags |= DDRAWISURFGBL_HARDWAREOPDEST;
|
|
if (surf_src)
|
|
{
|
|
DPF(5,B,"Tagging surface %08x", surf_src);
|
|
if (surf_src_lcl->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY)
|
|
surf_src->dwGlobalFlags |= DDRAWISURFGBL_HARDWAREOPSOURCE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DDASSERT(rc == DDHAL_DRIVER_NOTHANDLED);
|
|
/*
|
|
* No, the hardware driver says it could not handle the blit.
|
|
* If sbi.halonly = FALSE, we'll let the HEL do the blit.
|
|
*/
|
|
sbi.helonly = TRUE; // force fail-over to HEL
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Do we need to ask the HEL to perform the blit?
|
|
*/
|
|
if (sbi.helonly && !sbi.halonly)
|
|
{
|
|
/*
|
|
* Yes, we'll ask the HEL to do a software-emulated blit.
|
|
*/
|
|
bltfn = pdrv_lcl->lpDDCB->HELDDMiscellaneous2.AlphaBlt;
|
|
/*
|
|
* Is dest surface in system memory or video memory?
|
|
*/
|
|
if (surf_dest_lcl->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY)
|
|
{
|
|
/*
|
|
* Destination surface is in system memory.
|
|
* 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 WaitForHardwareOp.
|
|
*/
|
|
if (surf_dest->dwGlobalFlags & DDRAWISURFGBL_HARDWAREOPSTARTED)
|
|
{
|
|
WaitForHardwareOp(pdrv_lcl, surf_dest_lcl);
|
|
}
|
|
dest_lock_taken = FALSE;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* Wait loop: Take write lock on dest surface in video memory.
|
|
*/
|
|
while(1)
|
|
{
|
|
ddrval = InternalLock(surf_dest_lcl, &dest_bits, NULL, 0);
|
|
if (ddrval == DD_OK)
|
|
{
|
|
GET_LPDDRAWSURFACE_GBL_MORE(surf_dest)->fpNTAlias = (FLATPTR)dest_bits;
|
|
break; // successfully locked dest surface
|
|
}
|
|
if (ddrval != DDERR_WASSTILLDRAWING)
|
|
{
|
|
/*
|
|
* Can't lock dest surface. Fail the call.
|
|
*/
|
|
if (pRgn != (LPRGNDATA)&myRgnBuffer)
|
|
{
|
|
MemFree(pRgn); // this clip region was malloc'd
|
|
}
|
|
DONE_EXCLUDE();
|
|
DONE_BUSY();
|
|
LEAVE_BOTH();
|
|
return ddrval;
|
|
}
|
|
}
|
|
dest_lock_taken = TRUE;
|
|
}
|
|
|
|
if (surf_src && surf_src != surf_dest)
|
|
{
|
|
/*
|
|
* Is source surface in system memory or video memory?
|
|
*/
|
|
if (surf_src_lcl->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY)
|
|
{
|
|
/*
|
|
* Source surface is in system memory.
|
|
* 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 WaitForHardwareOp.
|
|
*/
|
|
if (surf_src &&
|
|
surf_src_lcl->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY &&
|
|
surf_src->dwGlobalFlags & DDRAWISURFGBL_HARDWAREOPSTARTED)
|
|
{
|
|
WaitForHardwareOp(pdrv_lcl, surf_src_lcl);
|
|
}
|
|
src_lock_taken = FALSE;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* Wait loop: Take lock on source surface in video memory.
|
|
*/
|
|
while(1)
|
|
{
|
|
ddrval = InternalLock(surf_src_lcl, &src_bits, NULL, DDLOCK_READONLY);
|
|
if (ddrval == DD_OK)
|
|
{
|
|
GET_LPDDRAWSURFACE_GBL_MORE(surf_src)->fpNTAlias = (FLATPTR)src_bits;
|
|
break; // successfully locked source surface
|
|
}
|
|
if (ddrval != DDERR_WASSTILLDRAWING)
|
|
{
|
|
/*
|
|
* We can't lock the source surface. Fail the call.
|
|
*/
|
|
if (dest_lock_taken)
|
|
{
|
|
InternalUnlock(surf_dest_lcl, NULL, NULL, 0);
|
|
}
|
|
if (pRgn != (LPRGNDATA)&myRgnBuffer)
|
|
{
|
|
MemFree(pRgn); // this clip region was malloc'd
|
|
}
|
|
DONE_EXCLUDE();
|
|
DONE_BUSY();
|
|
LEAVE_BOTH();
|
|
return ddrval;
|
|
}
|
|
}
|
|
src_lock_taken = TRUE;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Tell the HEL to perform the blit.
|
|
*/
|
|
#ifdef WINNT
|
|
try_again:
|
|
#endif
|
|
DOHALCALL_NOWIN16(AlphaBlt, bltfn, bd, rc, sbi.helonly);
|
|
#ifdef WINNT
|
|
if (rc == DDHAL_DRIVER_HANDLED && bd.ddRVal == DDERR_VISRGNCHANGED)
|
|
{
|
|
DPF(5,"Resetting VisRgn for surface %x", surf_dest_lcl);
|
|
DdResetVisrgn(surf_dest_lcl, (HWND)0);
|
|
goto try_again;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* If clip region was malloc'd, free it now.
|
|
*/
|
|
if (pRgn != (LPRGNDATA)&myRgnBuffer)
|
|
{
|
|
MemFree(pRgn);
|
|
}
|
|
|
|
if(IsD3DManaged(surf_dest_lcl))
|
|
MarkDirty(surf_dest_lcl);
|
|
|
|
DONE_LOCKS();
|
|
|
|
/*
|
|
* Exclusion needs to happen after unlock call
|
|
*/
|
|
DONE_EXCLUDE();
|
|
DONE_BUSY();
|
|
LEAVE_BOTH();
|
|
return bd.ddRVal;
|
|
}
|
|
EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
DPF_ERR("Exception encountered doing alpha blt");
|
|
DONE_LOCKS();
|
|
DONE_EXCLUDE();
|
|
DONE_BUSY();
|
|
LEAVE_BOTH();
|
|
return DDERR_EXCEPTION;
|
|
}
|
|
|
|
} /* DD_Surface_AlphaBlt */
|
|
|
|
|
|
|
|
|