/******************************Module*Header**********************************\ * * ************************** * * DirectDraw SAMPLE CODE * * ************************** * * Module Name: ddblt.c * * Content: DirectDraw Blt callback implementation for blts and clears * * Copyright (c) 1994-1999 3Dlabs Inc. Ltd. All rights reserved. * Copyright (c) 1995-2003 Microsoft Corporation. All rights reserved. \*****************************************************************************/ #include "glint.h" #include "tag.h" #include "dma.h" //----------------------------------------------------------------------------- // // _DD_BLT_P3Clear // //----------------------------------------------------------------------------- VOID _DD_BLT_P3Clear( P3_THUNKEDDATA* pThisDisplay, RECTL *rDest, DWORD ClearValue, BOOL bDisableFastFill, BOOL bIsZBuffer, FLATPTR pDestfpVidMem, DWORD dwDestPatchMode, DWORD dwDestPixelPitch, DWORD dwDestBitDepth ) { DWORD renderData, pixelSize, pixelScale; BOOL bFastFillOperation = TRUE; DWORD dwOperation; P3_DMA_DEFS(); P3_DMA_GET_BUFFER_ENTRIES(18); if(bDisableFastFill) { bFastFillOperation = FALSE; } switch(dwDestBitDepth) { case 16: ClearValue &= 0xFFFF; ClearValue |= ClearValue << 16; pixelSize = 1; pixelScale = 1; break; case 8: ClearValue &= 0xFF; ClearValue |= ClearValue << 8; ClearValue |= ClearValue << 16; pixelSize = 2; pixelScale = 1; break; case 32: if( bFastFillOperation ) { // Do the operation as 16 bit due to FBWrite bug pixelSize = 1; pixelScale = 2; } else { pixelSize = 0; pixelScale = 1; } break; default: DISPDBG((ERRLVL,"ERROR: Invalid depth for surface during clear!")); // Treat as a 16bpp just as fallback though this should never happen ClearValue &= 0xFFFF; ClearValue |= ClearValue << 16; pixelSize = 1; pixelScale = 1; break; } SEND_P3_DATA(PixelSize, pixelSize ); SEND_P3_DATA(FBWriteBufferAddr0, (DWORD)(pDestfpVidMem - pThisDisplay->dwScreenFlatAddr) ); SEND_P3_DATA(FBWriteBufferWidth0, pixelScale * dwDestPixelPitch ); SEND_P3_DATA(FBWriteBufferOffset0, (rDest->top << 16) | pixelScale * ((rDest->left & 0xFFFF))); SEND_P3_DATA(FBDestReadBufferAddr0, (DWORD)(pDestfpVidMem - pThisDisplay->dwScreenFlatAddr) ); SEND_P3_DATA(FBDestReadBufferWidth0, pixelScale * dwDestPixelPitch ); SEND_P3_DATA(FBDestReadBufferOffset0, (rDest->top << 16) | pixelScale * ((rDest->left & 0xFFFF))); SEND_P3_DATA(RectanglePosition, 0); dwOperation = P3RX_RENDER2D_OPERATION( P3RX_RENDER2D_OPERATION_NORMAL ); SEND_P3_DATA(FBWriteMode, P3RX_FBWRITEMODE_WRITEENABLE(__PERMEDIA_ENABLE) | P3RX_FBWRITEMODE_LAYOUT0(dwDestPatchMode)); P3_DMA_COMMIT_BUFFER(); P3_DMA_GET_BUFFER_ENTRIES(18); if( bFastFillOperation ) { DWORD shift = 0; SEND_P3_DATA(FBBlockColor, ClearValue); renderData = P3RX_RENDER2D_WIDTH( pixelScale * (( rDest->right - rDest->left ) & 0xfff )) | P3RX_RENDER2D_HEIGHT((( rDest->bottom - rDest->top ) & 0xfff ) >> shift ) | P3RX_RENDER2D_SPANOPERATION( P3RX_RENDER2D_SPAN_CONSTANT ) | P3RX_RENDER2D_INCREASINGX( __PERMEDIA_ENABLE ) | P3RX_RENDER2D_INCREASINGY( __PERMEDIA_ENABLE ) | dwOperation; SEND_P3_DATA(Render2D, renderData); } else { SEND_P3_DATA(ConstantColor, ClearValue); SEND_P3_DATA(DitherMode, __PERMEDIA_DISABLE); SEND_P3_DATA(ColorDDAMode, P3RX_COLORDDA_ENABLE(__PERMEDIA_ENABLE) | P3RX_COLORDDA_SHADING(P3RX_COLORDDA_FLATSHADE)); renderData = P3RX_RENDER2D_WIDTH(( rDest->right - rDest->left ) & 0xfff ) | P3RX_RENDER2D_HEIGHT(0) | P3RX_RENDER2D_SPANOPERATION( P3RX_RENDER2D_SPAN_CONSTANT ) | P3RX_RENDER2D_INCREASINGX( __PERMEDIA_ENABLE ) | P3RX_RENDER2D_INCREASINGY( __PERMEDIA_ENABLE ); SEND_P3_DATA(Render2D, renderData); SEND_P3_DATA(Count, rDest->bottom - rDest->top ); SEND_P3_DATA(Render, __RENDER_TRAPEZOID_PRIMITIVE); SEND_P3_DATA(ColorDDAMode, __PERMEDIA_DISABLE); } P3_DMA_COMMIT_BUFFER(); } // _DD_BLT_P3Clear //----------------------------------------------------------------------------- // // _DD_BLT_P3ClearDD // // Does a DDraw surface clear // //----------------------------------------------------------------------------- VOID _DD_BLT_P3ClearDD( P3_THUNKEDDATA* pThisDisplay, LPDDRAWI_DDRAWSURFACE_LCL pDest, P3_SURF_FORMAT* pFormatDest, RECTL *rDest, DWORD ClearValue, BOOL bDisableFastFill, BOOL bIsZBuffer ) { _DD_BLT_P3Clear(pThisDisplay, rDest, ClearValue, bDisableFastFill, bIsZBuffer, pDest->lpGbl->fpVidMem, P3RX_LAYOUT_LINEAR, DDSurf_GetPixelPitch(pDest), DDSurf_BitDepth(pDest) ); } // _DD_BLT_P3ClearDD #if DX7_TEXMANAGEMENT //----------------------------------------------------------------------------- // // _DD_BLT_P3ClearManagedSurf // // Does a clear of a managed surface. Supports all color depths // // PixelSize-----surface color depth // rDest---------rectangle for colorfill in dest. surface // fpVidMem------pointer to fill // lPitch--------Surface Pitch // dwColor-------color for fill // //----------------------------------------------------------------------------- VOID _DD_BLT_P3ClearManagedSurf(DWORD PixelSize, RECTL *rDest, FLATPTR fpVidMem, LONG lPitch, DWORD dwColor) { BYTE* pDestStart; LONG i; LONG lByteWidth = rDest->right - rDest->left; LONG lHeight = rDest->bottom - rDest->top; // Calculate the start pointer for the dest pDestStart = (BYTE*)(fpVidMem + (rDest->top * lPitch)); // Clear depending on depth switch (PixelSize) { case __GLINT_8BITPIXEL: pDestStart += rDest->left; while (--lHeight >= 0) { for (i = 0; i < lByteWidth ; i++) pDestStart[i] = (BYTE)dwColor; pDestStart += lPitch; } break; case __GLINT_16BITPIXEL: pDestStart += rDest->left*2; while (--lHeight >= 0) { LPWORD lpWord=(LPWORD)pDestStart; for (i = 0; i < lByteWidth ; i++) lpWord[i] = (WORD)dwColor; pDestStart += lPitch; } break; case __GLINT_24BITPIXEL: dwColor &= 0xFFFFFF; dwColor |= ((dwColor & 0xFF) << 24); default: // 32 bits! pDestStart += rDest->left*4; while (--lHeight >= 0) { LPDWORD lpDWord = (LPDWORD)pDestStart; for (i = 0; i < lByteWidth; i++) lpDWord[i] = (WORD)dwColor; pDestStart += lPitch; } break; } } // _DD_BLT_P3ClearManagedSurf #endif // DX7_TEXMANAGEMENT #if DX8_MULTISAMPLING || DX7_ANTIALIAS //----------------------------------------------------------------------------- // // _DD_BLT_P3Clear_AA // //----------------------------------------------------------------------------- VOID _DD_BLT_P3Clear_AA( P3_THUNKEDDATA* pThisDisplay, RECTL *rDest, DWORD dwSurfaceOffset, DWORD ClearValue, BOOL bDisableFastFill, DWORD dwDestPatchMode, DWORD dwDestPixelPitch, DWORD dwDestBitDepth, DDSCAPS DestDdsCaps) { DWORD renderData, pixelSize, pixelScale; BOOL bFastFillOperation = TRUE; P3_DMA_DEFS(); P3_DMA_GET_BUFFER(); P3_ENSURE_DX_SPACE(32); WAIT_FIFO(32); if (bDisableFastFill) { bFastFillOperation = FALSE; } switch(dwDestBitDepth) { case 16: ClearValue &= 0xFFFF; ClearValue |= ClearValue << 16; pixelSize = 1; pixelScale = 1; break; case 8: ClearValue &= 0xFF; ClearValue |= ClearValue << 8; ClearValue |= ClearValue << 16; pixelSize = 2; pixelScale = 1; break; case 32: // 32 bit Z-buffer can be used for 16 bit antialiased render buffer if( bFastFillOperation ) { // Do the operation as 16 bit due to FBWrite bug pixelSize = 1; pixelScale = 2; } else { pixelSize = 0; pixelScale = 1; } break; default: DISPDBG((ERRLVL,"ERROR: Invalid depth for surface during clear!")); // Treat as a 16bpp just as fallback ClearValue &= 0xFFFF; ClearValue |= ClearValue << 16; pixelSize = 1; pixelScale = 1; break; } SEND_P3_DATA(PixelSize, pixelSize); SEND_P3_DATA(FBWriteBufferAddr0, dwSurfaceOffset); SEND_P3_DATA(FBWriteBufferWidth0, pixelScale * (dwDestPixelPitch * 2)); SEND_P3_DATA(FBWriteBufferOffset0, (rDest->top << 16) | pixelScale * ((rDest->left & 0xFFFF))); SEND_P3_DATA(FBDestReadBufferAddr0, dwSurfaceOffset ); SEND_P3_DATA(FBDestReadBufferWidth0, pixelScale * dwDestPixelPitch ); SEND_P3_DATA(FBDestReadBufferOffset0, (rDest->top << 16) | pixelScale * ((rDest->left & 0xFFFF))); SEND_P3_DATA(RectanglePosition, 0); SEND_P3_DATA(FBWriteMode, P3RX_FBWRITEMODE_WRITEENABLE(__PERMEDIA_ENABLE) | P3RX_FBWRITEMODE_LAYOUT0(dwDestPatchMode)); if( bFastFillOperation ) { SEND_P3_DATA(FBBlockColor, ClearValue); renderData = P3RX_RENDER2D_WIDTH( pixelScale * (( rDest->right - rDest->left ) & 0xfff )) | P3RX_RENDER2D_HEIGHT(( rDest->bottom - rDest->top ) & 0xfff ) | P3RX_RENDER2D_INCREASINGX( __PERMEDIA_ENABLE ) | P3RX_RENDER2D_INCREASINGY( __PERMEDIA_ENABLE ); SEND_P3_DATA(Render2D, renderData); } else { SEND_P3_DATA(ConstantColor, ClearValue); SEND_P3_DATA(DitherMode, __PERMEDIA_DISABLE); SEND_P3_DATA(ColorDDAMode, P3RX_COLORDDA_ENABLE(__PERMEDIA_ENABLE) | P3RX_COLORDDA_SHADING(P3RX_COLORDDA_FLATSHADE)); renderData = P3RX_RENDER2D_WIDTH(( rDest->right - rDest->left ) & 0xfff ) | P3RX_RENDER2D_HEIGHT(0) | P3RX_RENDER2D_INCREASINGX( __PERMEDIA_ENABLE ) | P3RX_RENDER2D_SPANOPERATION( P3RX_RENDER2D_SPAN_CONSTANT ) | P3RX_RENDER2D_INCREASINGY( __PERMEDIA_ENABLE ); SEND_P3_DATA(Render2D, renderData); SEND_P3_DATA(Count, rDest->bottom - rDest->top ); SEND_P3_DATA(Render, __RENDER_TRAPEZOID_PRIMITIVE); SEND_P3_DATA(ColorDDAMode, __PERMEDIA_DISABLE); } P3_DMA_COMMIT_BUFFER(); } // _DD_BLT_P3Clear_AA //----------------------------------------------------------------------------- // // _DD_BLT_P3Clear_AA_DD // //----------------------------------------------------------------------------- VOID _DD_BLT_P3Clear_AA_DD( P3_THUNKEDDATA* pThisDisplay, LPDDRAWI_DDRAWSURFACE_LCL pDest, P3_SURF_FORMAT* pFormatDest, RECTL *rDest, DWORD dwSurfaceOffset, DWORD ClearValue, BOOL bDisableFastFill) { _DD_BLT_P3Clear_AA(pThisDisplay, rDest, dwSurfaceOffset, ClearValue, bDisableFastFill, P3RX_LAYOUT_LINEAR, DDSurf_GetPixelPitch(pDest), DDSurf_BitDepth(pDest), pDest->ddsCaps ); } // _DD_BLT_P3Clear_AA_DD #endif // DX8_MULTISAMPLING || DX7_ANTIALIAS #if DX7_TEXMANAGEMENT //----------------------------------------------------------------------------- // // _DD_BLT_SysMemToSysMemCopy // // Does a copy from System memory to System memory (either from or to an // AGP surface, or any other system memory surface) // //----------------------------------------------------------------------------- VOID _DD_BLT_SysMemToSysMemCopy(FLATPTR fpSrcVidMem, LONG lSrcPitch, DWORD dwSrcBitCount, FLATPTR fpDstVidMem, LONG lDstPitch, DWORD dwDstBitCount, RECTL* rSource, RECTL* rDest) { BYTE* pSourceStart; BYTE* pDestStart; BYTE pixSource; BYTE* pNewDest; BYTE* pNewSource; // Computing these from the smaller of Dest and Src as it is safer // (we might touch invalid memory if for any weird reason we're // asked to do a stretch blt here!) LONG lByteWidth = min(rDest->right - rDest->left, rSource->right - rSource->left); LONG lHeight = min(rDest->bottom - rDest->top, rSource->bottom - rSource->top); if (0 == fpSrcVidMem || 0 == fpDstVidMem) { DISPDBG((WRNLVL, "DDraw:_DD_BLT_SysMemToSysMemCopy " "unexpected 0 fpVidMem")); return; } // Calculate the start pointer for the source and the dest pSourceStart = (BYTE*)(fpSrcVidMem + (rSource->top * lSrcPitch)); pDestStart = (BYTE*)(fpDstVidMem + (rDest->top * lDstPitch)); // The simple 8, 16 or 32 bit copy pSourceStart += rSource->left * (dwSrcBitCount >> 3); pDestStart += rDest->left * (dwDstBitCount >> 3); lByteWidth *= (dwSrcBitCount >> 3); _try { while (--lHeight >= 0) { memcpy(pDestStart, pSourceStart, lByteWidth); pDestStart += lDstPitch; pSourceStart += lSrcPitch; }; } __except(EXCEPTION_EXECUTE_HANDLER) { // Perm3 driver doesn't need to do anything special DISPDBG((ERRLVL, "Perm3 caused exception at line %u of file %s", __LINE__,__FILE__)); } } // _DD_BLT_SysMemToSysMemCopy #endif // DX7_TEXMANAGEMENT //----------------------------------------------------------------------------- // // _DD_BLT_FixRectlOrigin // // Fix blt coords in case some are negative. If the area is completly NULL // (coordinate-wise) then return FALSE, signaling there is nothing to be // blitted. // //----------------------------------------------------------------------------- BOOL _DD_BLT_FixRectlOrigin(char *pszPlace, RECTL *rSrc, RECTL *rDest) { if ((rSrc->top < 0 && rSrc->bottom < 0) || (rSrc->left < 0 && rSrc->right < 0)) { // There is nothing to be blitted return FALSE; } if (rSrc->top < 0 || rSrc->left < 0 || rDest->top < 0 || rDest->left < 0) { DISPDBG((DBGLVL, "Dodgy blt coords:")); DISPDBG((DBGLVL, " src([%d, %d], [%d, %d]", rSrc->left, rSrc->top, rSrc->right, rSrc->bottom)); DISPDBG((DBGLVL, " dst([%d, %d], [%d, %d]", rDest->left, rDest->top, rDest->right, rDest->bottom)); } if (rSrc->top < 0) { rDest->top -= rSrc->top; rSrc->top = 0; } if (rSrc->left < 0) { rDest->left -= rSrc->left; rSrc->left = 0; } DISPDBG((DBGLVL, "%s from (%d, %d) to (%d,%d) (%d, %d)", pszPlace, rSrc->left, rSrc->top, rDest->left, rDest->top, rDest->right, rDest->bottom)); return TRUE; // Blt is valid } // _DD_BLT_FixRectlOrigin //----------------------------------------------------------------------------- // // _DD_BLT_GetBltDirection // // Determine the direction of the blt // ==1 => increasing-x && increasing-y // ==0 => decreasing-x && decreasing-y // // Also, the boolean pbBlocking determines if there is a potential clash // because of common scan lines. // //----------------------------------------------------------------------------- DWORD _DD_BLT_GetBltDirection( FLATPTR pSrcfpVidMem, FLATPTR pDestfpVidMem, RECTL *rSrc, RECTL *rDest, BOOL *pbBlocking) { DWORD dwRenderDirection; *pbBlocking = FALSE; if( pDestfpVidMem != pSrcfpVidMem ) { // Not the same surface, so always render downwards. dwRenderDirection = 1; } else { // Same surface - must choose render direction. if(rSrc->top < rDest->top) { dwRenderDirection = 0; } else if(rSrc->top > rDest->top) { dwRenderDirection = 1; } else // y1 == y2 { if(rSrc->left < rDest->left) { dwRenderDirection = 0; } else { dwRenderDirection = 1; } // It was found that this condition doesn't guarantee clean blits // therefore we need to do a blocking 2D blit *pbBlocking = TRUE; } } return dwRenderDirection; } // _DD_BLT_GetBltDirection //----------------------------------------------------------------------------- // // _DD_BLT_P3CopyBlt // // Perform a Copy blt between the specified surfaces. // //----------------------------------------------------------------------------- VOID _DD_BLT_P3CopyBlt( P3_THUNKEDDATA* pThisDisplay, FLATPTR pSrcfpVidMem, FLATPTR pDestfpVidMem, DWORD dwSrcChipPatchMode, DWORD dwDestChipPatchMode, DWORD dwSrcPitch, DWORD dwDestPitch, DWORD dwSrcOffset, DWORD dwDestOffset, DWORD dwDestPixelSize, RECTL *rSrc, RECTL *rDest) { DWORD renderData; LONG rSrctop, rSrcleft, rDesttop, rDestleft; DWORD dwSourceOffset; BOOL bBlocking; DWORD dwRenderDirection; P3_DMA_DEFS(); // Beacuse of a bug in RL we sometimes have to fiddle with these values rSrctop = rSrc->top; rSrcleft = rSrc->left; rDesttop = rDest->top; rDestleft = rDest->left; // Fix coords origin if (!_DD_BLT_FixRectlOrigin("_DD_BLT_P3CopyBlt", rSrc, rDest)) { // Nothing to be blitted return; } // Determine the direction of the blt dwRenderDirection = _DD_BLT_GetBltDirection(pSrcfpVidMem, pDestfpVidMem, rSrc, rDest, &bBlocking); P3_DMA_GET_BUFFER(); P3_ENSURE_DX_SPACE(40); WAIT_FIFO(20); SEND_P3_DATA(PixelSize, (2 - dwDestPixelSize)); SEND_P3_DATA(FBWriteBufferAddr0, dwDestOffset); SEND_P3_DATA(FBWriteBufferWidth0, dwDestPitch); SEND_P3_DATA(FBWriteBufferOffset0, 0); SEND_P3_DATA(FBSourceReadBufferAddr, dwSrcOffset); SEND_P3_DATA(FBSourceReadBufferWidth, dwSrcPitch); dwSourceOffset = (( rSrc->top - rDest->top ) << 16 ) | (( rSrc->left - rDest->left ) & 0xffff ); SEND_P3_DATA(FBSourceReadBufferOffset, dwSourceOffset); SEND_P3_DATA(FBDestReadMode, P3RX_FBDESTREAD_READENABLE(__PERMEDIA_DISABLE)); SEND_P3_DATA(FBSourceReadMode, P3RX_FBSOURCEREAD_READENABLE(__PERMEDIA_ENABLE) | P3RX_FBSOURCEREAD_LAYOUT(dwSrcChipPatchMode) | P3RX_FBSOURCEREAD_BLOCKING( bBlocking )); SEND_P3_DATA(FBWriteMode, P3RX_FBWRITEMODE_WRITEENABLE(__PERMEDIA_ENABLE) | P3RX_FBWRITEMODE_LAYOUT0(dwDestChipPatchMode)); WAIT_FIFO(20); SEND_P3_DATA(RectanglePosition, P3RX_RECTANGLEPOSITION_Y(rDest->top) | P3RX_RECTANGLEPOSITION_X(rDest->left)); renderData = P3RX_RENDER2D_WIDTH(( rDest->right - rDest->left ) & 0xfff ) | P3RX_RENDER2D_HEIGHT(( rDest->bottom - rDest->top ) & 0xfff ) | P3RX_RENDER2D_FBREADSOURCEENABLE(__PERMEDIA_ENABLE) | P3RX_RENDER2D_SPANOPERATION( P3RX_RENDER2D_SPAN_VARIABLE ) | P3RX_RENDER2D_INCREASINGX( dwRenderDirection ) | P3RX_RENDER2D_INCREASINGY( dwRenderDirection ); SEND_P3_DATA(Render2D, renderData); // Put back the values if we changed them. rSrc->top = rSrctop; rSrc->left = rSrcleft; rDest->top = rDesttop; rDest->left = rDestleft; P3_DMA_COMMIT_BUFFER(); } // _DD_BLT_P3CopyBlt //----------------------------------------------------------------------------- // // _DD_BLT_P3CopyBltDD // // Perform a Copy blt between the specified Ddraw surfaces. // //----------------------------------------------------------------------------- VOID _DD_BLT_P3CopyBltDD( P3_THUNKEDDATA* pThisDisplay, LPDDRAWI_DDRAWSURFACE_LCL pSource, LPDDRAWI_DDRAWSURFACE_LCL pDest, P3_SURF_FORMAT* pFormatSource, P3_SURF_FORMAT* pFormatDest, RECTL *rSrc, RECTL *rDest) { _DD_BLT_P3CopyBlt(pThisDisplay, pSource->lpGbl->fpVidMem, pDest->lpGbl->fpVidMem, P3RX_LAYOUT_LINEAR, // src P3RX_LAYOUT_LINEAR, // dst DDSurf_GetPixelPitch(pSource), DDSurf_GetPixelPitch(pDest), DDSurf_SurfaceOffsetFromMemoryBase(pThisDisplay, pSource), DDSurf_SurfaceOffsetFromMemoryBase(pThisDisplay, pDest), DDSurf_GetChipPixelSize(pDest), rSrc, rDest); } // _DD_BLT_P3CopyBltDD //----------------------------------------------------------------------------- // // DdBlt // // Performs a bit-block transfer. // // DdBlt can be optionally implemented in DirectDraw drivers. // // Before performing the bit block transfer, the driver should ensure that a // flip involving the destination surface is not in progress. If the destination // surface is involved in a flip, the driver should set ddRVal to // DDERR_WASSTILLDRAWING and return DDHAL_DRIVER_HANDLED. // // The driver should check dwFlags to determine the type of blt operation to // perform. The driver should not check for flags that are undocumented. // // Parameters // // lpBlt // Points to the DD_BLTDATA structure that contains the information // required for the driver to perform the blt. // // .lpDD // Points to a DD_DIRECTDRAW_GLOBAL structure that describes the // DirectDraw object. // .lpDDDestSurface // Points to the DD_SURFACE_LOCAL structure that describes the // surface on which to blt. // .rDest // Points to a RECTL structure that specifies the upper left and // lower right points of a rectangle on the destination surface. // These points define the area in which the blt should occur and // its position on the destination surface // .lpDDSrcSurface // Points to a DD_SURFACE_LOCAL structure that describes the // source surface. // .rSrc // Points to a RECTL structure that specifies the upper left and // lower right points of a rectangle on the source surface. These // points define the area of the source blt data and its position // on the source surface. // .dwFlags // Specify the type of blt operation to perform and which // associated structure members have valid data that the driver // should use. This member is a bit-wise OR of any of the following // flags: // // DDBLT_AFLAGS // This flag is not yet used as of DirectX® 7.0. Indicates to // the driver that the dwAFlags and ddrgbaScaleFactors members // in this structure are valid. This flag is always set if the // DD_BLTDATA structure is passed to the driver from the // DdAlphaBlt callback. Otherwise this flag is zero. If this // flag is set, the DDBLT_ROTATIONANGLE and DDBLT_ROP flags // will be zero. // DDBLT_ASYNC // Do this blt asynchronously through the FIFO in the order // received. If no room exists in the hardware FIFO, the driver // should fail the call and return immediately. // DDBLT_COLORFILL // Use the dwFillColor member in the DDBLTFX structure as the // RGB color with which to fill the destination rectangle on // the destination surface. // DDBLT_DDFX // Use the dwDDFX member in the DDBLTFX structure to determine // the effects to use for the blt. // DDBLT_DDROPS // This is reserved for system use and should be ignored by the // driver. The driver should also ignore the dwDDROPS member of // the DDBLTFX structure. // DDBLT_KEYDESTOVERRIDE // Use the dckDestColorkey member in the DDBLTFX structure as // the color key for the destination surface. If an override // is not being set, then dckDestColorkey does not contain the // color key. The driver should test the surface itself. // DDBLT_KEYSRCOVERRIDE // Use the dckSrcColorkey member in the DDBLTFX structure as // the color key for the source surface. If an override is // not being set, then dckDestColorkey does not contain the // color key. The driver should test the surface itself. // DDBLT_ROP // Use the dwROP member in the DDBLTFX structure for the // raster operation for this blt. Currently, the only ROP // passed to the driver is SRCCOPY. This ROP is the same as // defined in the Win32® API. See the Platform SDK for details. // DDBLT_ROTATIONANGLE // This is not supported on Windows 2000 and should be ignored // by the driver. // // .dwROPFlags // This is unused on Windows 2000 and should be ignored by the // driver. // .bltFX // Specifies a DDBLTFX structure that contains override // information for more complex blt operations. For example, the // dwFillColor field is used for solid color fills, and the // ddckSrcColorKey and ddckDestColorKey fields are used for // color key blts. The driver can determine which members of // bltFX contain valid data by looking at the dwFlags member of // the DD_BLTDATA structure. Note that the DDBLTFX_NOTEARING, // DDBLTFX_MIRRORLEFTRIGHT, and DDBLTFX_MIRRORUPDOWN flags are // unsupported on Windows 2000 and will never be passed to the // driver. See the Platform SDK for DDBLTFX documentation. // .ddRVal // This is the location in which the driver writes the return // value of the DdBlt callback. A return code of DD_OK indicates // success. // .Blt // This is unused on Windows 2000. // .IsClipped // Indicates whether this is a clipped blt. On Windows 2000, // this member is always FALSE, indicating that the blt is // unclipped. // .rOrigDest // This member is unused for Windows 2000. Specifies a RECTL // structure that defines the unclipped destination rectangle. // This member is valid only if IsClipped is TRUE. // .rOrigSrc // This member is unused for Windows 2000. Specifies a RECTL // structure that defines the unclipped source rectangle. This // member is valid only if IsClipped is TRUE. // .dwRectCnt // This member is unused for Windows 2000. Specifies the number // of destination rectangles to which prDestRects points. This // member is valid only if IsClipped is TRUE. // .prDestRects // This member is unused for Windows 2000. Points to an array of // RECTL structures that describe of destination rectangles. This // member is valid only if IsClipped is TRUE. // .dwAFlags // This member is only valid if the DDBLT_AFLAGS flag is set in // the dwFlags member of this structure. This member specifies // operation flags used only by the DdAlphaBlt callback (which // is not yet implemented as of DirectX 7.0). This member is a // bit-wise OR of any of the following flags: // // DDABLT_BILINEARFLITER // Enable bilinear filtering of the source pixels during a // stretch blit. By default, no filtering is performed. // Instead, a nearest neighbor source pixel is copied to a // destination pixel // DDABLT_NOBLEND // Write the source pixel values to the destination surface // without blending. The pixels are converted from the source // pixel format to the destination format, but no color // keying, alpha blending, or RGBA scaling is performed. In // the case of a fill operation (where the lpDDSrcSurface // member is NULL), the lpDDRGBAScaleFactors member of this // structure points to the source alpha and color components // that are to be converted to the destination pixel format // and are used to fill the destination. A blit operation is // performed if a valid source surface is specified, but in // this case, lpDDRGBAScaleFactors must be NULL or the call // will fail. This flag cannot be used in conjunction with // the DDBLT_KEYSRC and DDBLT_KEYDEST flags. // DDABLT_SRCOVERDEST // If set, this flag indicates that the operation originated // from the application's AlphaBlt method. If the call was // originated by the application's Blt method, this flag is // not set. Drivers that have a unified DdBlt and DdAlphaBlt // callback can use this flag to distinguish between the two // application method calls. // // .ddrgbaScaleFactors // This member is only valid if the DDBLT_AFLAGS flag is set in // the dwFlags member of this structure. DDARGB structure that // contains the RGBA-scaling factors used to scale the color and // alpha components of each source pixel before it is composited // to the destination surface. // //----------------------------------------------------------------------------- DWORD CALLBACK DdBlt( LPDDHAL_BLTDATA lpBlt ) { RECTL rSrc; RECTL rDest; DWORD dwFlags; BYTE rop; LPDDRAWI_DDRAWSURFACE_LCL pSrcLcl; LPDDRAWI_DDRAWSURFACE_LCL pDestLcl; LPDDRAWI_DDRAWSURFACE_GBL pSrcGbl; LPDDRAWI_DDRAWSURFACE_GBL pDestGbl; P3_SURF_FORMAT* pFormatSource; P3_SURF_FORMAT* pFormatDest; P3_THUNKEDDATA* pThisDisplay; HRESULT ddrval = DD_OK; BOOL bOverlapStretch = FALSE; DBG_CB_ENTRY(DdBlt); pDestLcl = lpBlt->lpDDDestSurface; pSrcLcl = lpBlt->lpDDSrcSurface; GET_THUNKEDDATA(pThisDisplay, lpBlt->lpDD); VALIDATE_MODE_AND_STATE(pThisDisplay); pDestGbl = pDestLcl->lpGbl; pFormatDest = _DD_SUR_GetSurfaceFormat(pDestLcl); DISPDBG((DBGLVL, "Dest Surface:")); DBGDUMP_DDRAWSURFACE_LCL(DBGLVL, pDestLcl); dwFlags = lpBlt->dwFlags; STOP_SOFTWARE_CURSOR(pThisDisplay); ddrval = _DX_QueryFlipStatus(pThisDisplay, pDestGbl->fpVidMem, TRUE); if( FAILED( ddrval ) ) { lpBlt->ddRVal = ddrval; START_SOFTWARE_CURSOR(pThisDisplay); DBG_CB_EXIT(DdBlt,lpBlt->ddRVal); return DDHAL_DRIVER_HANDLED; } // // If async, then only work if bltter isn't busy // if( dwFlags & DDBLT_ASYNC ) { if(DRAW_ENGINE_BUSY(pThisDisplay)) { DISPDBG((WRNLVL, "ASYNC Blit Failed" )); lpBlt->ddRVal = DDERR_WASSTILLDRAWING; START_SOFTWARE_CURSOR(pThisDisplay); DBG_CB_EXIT(DdBlt,lpBlt->ddRVal); return DDHAL_DRIVER_HANDLED; } #if DBG else { DISPDBG((DBGLVL, "ASYNC Blit Succeeded!")); } #endif } // // copy src/dest rects // rSrc = lpBlt->rSrc; rDest = lpBlt->rDest; rop = (BYTE) (lpBlt->bltFX.dwROP >> 16); // Switch to DirectDraw context DDRAW_OPERATION(pContext, pThisDisplay); if (dwFlags & DDBLT_ROP) { if (rop == (SRCCOPY >> 16)) { DISPDBG((DBGLVL,"DDBLT_ROP: SRCCOPY")); if (pSrcLcl != NULL) { pSrcGbl = pSrcLcl->lpGbl; pFormatSource = _DD_SUR_GetSurfaceFormat(pSrcLcl); DISPDBG((DBGLVL, "Source Surface:")); DBGDUMP_DDRAWSURFACE_LCL(DBGLVL, pSrcLcl); } else { START_SOFTWARE_CURSOR(pThisDisplay); DBG_CB_EXIT(DdBlt,lpBlt->ddRVal); return DDHAL_DRIVER_NOTHANDLED; } #if DX7_TEXMANAGEMENT if ((pSrcLcl->lpSurfMore->ddsCapsEx.dwCaps2 & DDSCAPS2_TEXTUREMANAGE) || (pDestLcl->lpSurfMore->ddsCapsEx.dwCaps2 & DDSCAPS2_TEXTUREMANAGE) ) { // Managed source surface cases // (Including managed destination surfaces case) if (pSrcLcl->lpSurfMore->ddsCapsEx.dwCaps2 & DDSCAPS2_TEXTUREMANAGE) { if ((pDestLcl->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY) || (pDestLcl->lpSurfMore->ddsCapsEx.dwCaps2 & DDSCAPS2_TEXTUREMANAGE) ) { //------------------------------------------------- // Do the Managed surf -> sysmem | managed surf blt //------------------------------------------------- // make sure we'll reload the vidmem copy of the dest surf if (pDestLcl->lpSurfMore->ddsCapsEx.dwCaps2 & DDSCAPS2_TEXTUREMANAGE) { _D3D_TM_MarkDDSurfaceAsDirty(pThisDisplay, pDestLcl, TRUE); } _DD_BLT_SysMemToSysMemCopy( pSrcGbl->fpVidMem, pSrcGbl->lPitch, DDSurf_BitDepth(pSrcLcl), pDestGbl->fpVidMem, pDestGbl->lPitch, DDSurf_BitDepth(pDestLcl), &rSrc, &rDest); } else if ((pDestLcl->ddsCaps.dwCaps & DDSCAPS_LOCALVIDMEM)) { //------------------------------------------------- // Do the Managed surf -> vidmem surf blt //------------------------------------------------- // This might be optimized by doing a vidmem->vidmem // when the source managed texture has a vidmem copy _DD_P3Download(pThisDisplay, pSrcGbl->fpVidMem, pDestGbl->fpVidMem, P3RX_LAYOUT_LINEAR, P3RX_LAYOUT_LINEAR, pSrcGbl->lPitch, pDestGbl->lPitch, DDSurf_GetPixelPitch(pDestLcl), DDSurf_GetChipPixelSize(pDestLcl), &rSrc, &rDest); } else { DISPDBG((ERRLVL,"Src-managed Tex DdBlt" " variation unimplemented!")); } goto Blt32Done; } // Managed destination surface cases if (pDestLcl->lpSurfMore->ddsCapsEx.dwCaps2 & DDSCAPS2_TEXTUREMANAGE) { if (pSrcLcl->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY) { //------------------------------------------------- // Do the sysmem surf -> managed surf blt //------------------------------------------------- // make sure we'll reload the vidmem copy of the dest surf _D3D_TM_MarkDDSurfaceAsDirty(pThisDisplay, pDestLcl, TRUE); _DD_BLT_SysMemToSysMemCopy( pSrcGbl->fpVidMem, pSrcGbl->lPitch, DDSurf_BitDepth(pSrcLcl), pDestGbl->fpVidMem, pDestGbl->lPitch, DDSurf_BitDepth(pDestLcl), &rSrc, &rDest); goto Blt32Done; } else if (pSrcLcl->ddsCaps.dwCaps & DDSCAPS_LOCALVIDMEM) { //------------------------------------------------- // Do the vidmem surf -> Managed surf blt //------------------------------------------------- // make sure we'll reload the // vidmem copy of the dest surf _D3D_TM_MarkDDSurfaceAsDirty(pThisDisplay, pDestLcl, TRUE); // Do slow mem mapped framebuffer blt into sysmem // The source surface lives in video mem so we need to get a // "real" sysmem address for it: _DD_BLT_SysMemToSysMemCopy( DDSURF_GETPOINTER(pSrcGbl, pThisDisplay), pSrcGbl->lPitch, DDSurf_BitDepth(pSrcLcl), pDestGbl->fpVidMem, pDestGbl->lPitch, DDSurf_BitDepth(pDestLcl), &rSrc, &rDest); } else { DISPDBG((ERRLVL,"Dest-managed Tex DdBlt" " variation unimplemented!")); } } goto Blt32Done; } #endif // DX7_TEXMANAGEMENT // Invalid cases... if ((pFormatSource->DeviceFormat == SURF_YUV422) && (pFormatDest->DeviceFormat == SURF_CI8)) { DISPDBG((ERRLVL,"Can't do this blit!")); START_SOFTWARE_CURSOR(pThisDisplay); lpBlt->ddRVal = DDERR_UNSUPPORTED; DBG_CB_EXIT(DdBlt,lpBlt->ddRVal); return DDHAL_DRIVER_NOTHANDLED; } // Operation is System -> Video memory blit, as a texture // download or an image download. if (!(dwFlags & DDBLT_KEYDESTOVERRIDE) && (pSrcLcl->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY) && (pDestLcl->ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY)) { DISPDBG((DBGLVL,"Being Asked to do SYSMEM->VIDMEM Blit")); if (rop != (SRCCOPY >> 16)) { DISPDBG((DBGLVL,"Being asked for non-copy ROP, refusing")); lpBlt->ddRVal = DDERR_NORASTEROPHW; START_SOFTWARE_CURSOR(pThisDisplay); DBG_CB_EXIT(DdBlt,lpBlt->ddRVal); return DDHAL_DRIVER_NOTHANDLED; } DISPDBG((DBGLVL,"Doing image download")); _DD_P3DownloadDD(pThisDisplay, pSrcLcl, pDestLcl, pFormatSource, pFormatDest, &rSrc, &rDest); goto Blt32Done; } // Check for overlapping stretch blits. // Are the surfaces the same? if (pDestLcl->lpGbl->fpVidMem == pSrcLcl->lpGbl->fpVidMem) { // Do they overlap? if ((!((rSrc.bottom < rDest.top) || (rSrc.top > rDest.bottom))) && (!((rSrc.right < rDest.left) || (rSrc.left > rDest.right))) ) { // Are they of different source and dest sizes? if ( ((rSrc.right - rSrc.left) != (rDest.right - rDest.left)) || ((rSrc.bottom - rSrc.top) != (rDest.bottom - rDest.top)) ) { bOverlapStretch = TRUE; } } } // Is it a transparent blit? if ( ( dwFlags & DDBLT_KEYSRCOVERRIDE ) || ( dwFlags & DDBLT_KEYDESTOVERRIDE ) ) { DISPDBG((DBGLVL,"DDBLT_KEYSRCOVERRIDE")); if (rop != (SRCCOPY >> 16)) { lpBlt->ddRVal = DDERR_NORASTEROPHW; START_SOFTWARE_CURSOR(pThisDisplay); DBG_CB_EXIT(DdBlt,lpBlt->ddRVal); return DDHAL_DRIVER_NOTHANDLED; } // If the surface sizes don't match, then we are stretching. // If the surfaces are flipped then do it this was for now... if (((rSrc.right - rSrc.left) != (rDest.right - rDest.left) || (rSrc.bottom - rSrc.top) != (rDest.bottom - rDest.top) ) || ((dwFlags & DDBLT_DDFX) && ((lpBlt->bltFX.dwDDFX & DDBLTFX_MIRRORUPDOWN) || (lpBlt->bltFX.dwDDFX & DDBLTFX_MIRRORLEFTRIGHT)) ) ) { if (!bOverlapStretch) { // Use generic rout. _DD_P3BltStretchSrcChDstCh_DD(pThisDisplay, pSrcLcl, pDestLcl, pFormatSource, pFormatDest, lpBlt, &rSrc, &rDest); } else { // Stretched overlapped blits (DCT case) _DD_P3BltStretchSrcChDstChOverlap(pThisDisplay, pSrcLcl, pDestLcl, pFormatSource, pFormatDest, lpBlt, &rSrc, &rDest); } } else if ( dwFlags & DDBLT_KEYDESTOVERRIDE ) { if ((pSrcLcl->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY) && (pDestLcl->ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY)) { DISPDBG((DBGLVL,"Being Asked to do SYSMEM->VIDMEM " "Blit with DestKey")); if (rop != (SRCCOPY >> 16)) { DISPDBG((DBGLVL,"Being asked for non-copy " "ROP, refusing")); lpBlt->ddRVal = DDERR_NORASTEROPHW; START_SOFTWARE_CURSOR(pThisDisplay); DBG_CB_EXIT(DdBlt,lpBlt->ddRVal); return DDHAL_DRIVER_NOTHANDLED; } // A download routine that does destination colorkey. _DD_P3DownloadDstCh(pThisDisplay, pSrcLcl, pDestLcl, pFormatSource, pFormatDest, lpBlt, &rSrc, &rDest); } else { _DD_P3BltStretchSrcChDstCh_DD(pThisDisplay, pSrcLcl, pDestLcl, pFormatSource, pFormatDest, lpBlt, &rSrc, &rDest); } } else { if (DDSurf_IsAGP(pSrcLcl)) { // Need this rout if we are in // AGP memory because this textures _DD_P3BltStretchSrcChDstCh_DD(pThisDisplay, pSrcLcl, pDestLcl, pFormatSource, pFormatDest, lpBlt, &rSrc, &rDest); } else { // Only source keying, and no stretching. _DD_P3BltSourceChroma(pThisDisplay, pSrcLcl, pDestLcl, pFormatSource, pFormatDest, lpBlt, &rSrc, &rDest); } } goto Blt32Done; } else { // If the surface sizes don't match, then we are stretching. // If the surfaces are flipped then do it this was for now... if (((rSrc.right - rSrc.left) != (rDest.right - rDest.left) || (rSrc.bottom - rSrc.top) != (rDest.bottom - rDest.top)) || ((lpBlt->dwFlags & DDBLT_DDFX) && ((lpBlt->bltFX.dwDDFX & DDBLTFX_MIRRORUPDOWN) || (lpBlt->bltFX.dwDDFX & DDBLTFX_MIRRORLEFTRIGHT)))) { // Is a stretch blit DISPDBG((DBGLVL,"DDBLT_ROP: STRETCHCOPYBLT OR " "MIRROR OR BOTH")); // Can't rop during a stretch blit. if (rop != (SRCCOPY >> 16)) { lpBlt->ddRVal = DDERR_NORASTEROPHW; START_SOFTWARE_CURSOR(pThisDisplay); DBG_CB_EXIT(DdBlt,lpBlt->ddRVal); return DDHAL_DRIVER_NOTHANDLED; } // Do the stretch if (!bOverlapStretch) { // Use the generic rout ATM. _DD_P3BltStretchSrcChDstCh_DD(pThisDisplay, pSrcLcl, pDestLcl, pFormatSource, pFormatDest, lpBlt, &rSrc, &rDest); } else { // DCT case - Stretched overlapped blits _DD_P3BltStretchSrcChDstChOverlap(pThisDisplay, pSrcLcl, pDestLcl, pFormatSource, pFormatDest, lpBlt, &rSrc, &rDest); } } else // ! Stretching { // Must be a standard blit. DISPDBG((DBGLVL,"DDBLT_ROP: COPYBLT")); DISPDBG((DBGLVL,"Standard Copy Blit")); // If the source is in AGP, use a texturing blitter. if ((DDSurf_IsAGP(pSrcLcl)) || ((pFormatSource->DeviceFormat == SURF_YUV422) && (pFormatDest->DeviceFormat != SURF_YUV422))) { _DD_P3BltStretchSrcChDstCh_DD(pThisDisplay, pSrcLcl, pDestLcl, pFormatSource, pFormatDest, lpBlt, &rSrc, &rDest); } else { // A standard, boring blit. // Call the correct CopyBlt Function. _DD_BLT_P3CopyBltDD(pThisDisplay, pSrcLcl, pDestLcl, pFormatSource, pFormatDest, &rSrc, &rDest); } } goto Blt32Done; } } else if ((rop == (BLACKNESS >> 16)) || (rop == (WHITENESS >> 16))) { DWORD color; DISPDBG((DBGLVL,"DDBLT_ROP: BLACKNESS or WHITENESS")); if (rop == (BLACKNESS >> 16)) { color = 0; } else { color = 0xffffffff; } _DD_BLT_P3ClearDD(pThisDisplay, pDestLcl, pFormatDest, &rDest, color, FALSE, FALSE); } else if ((rop & 7) != ((rop >> 4) & 7)) { lpBlt->ddRVal = DDERR_NORASTEROPHW; START_SOFTWARE_CURSOR(pThisDisplay); DBG_CB_EXIT(DdBlt,lpBlt->ddRVal); return DDHAL_DRIVER_NOTHANDLED; } else { DISPDBG((WRNLVL,"P3 BLT case not found!")); START_SOFTWARE_CURSOR(pThisDisplay); DBG_CB_EXIT(DdBlt,lpBlt->ddRVal); return DDHAL_DRIVER_NOTHANDLED; } } else if (dwFlags & DDBLT_COLORFILL) { DISPDBG((DBGLVL,"DDBLT_COLORFILL(P3): Color=0x%x", lpBlt->bltFX.dwFillColor)); #if DX7_TEXMANAGEMENT // If clearing a driver managed texture, clear just the sysmem copy if (pDestLcl->lpSurfMore->ddsCapsEx.dwCaps2 & DDSCAPS2_TEXTUREMANAGE) { _DD_BLT_P3ClearManagedSurf(DDSurf_GetChipPixelSize(pDestLcl), &rDest, pDestGbl->fpVidMem, pDestGbl->lPitch, lpBlt->bltFX.dwFillColor); _D3D_TM_MarkDDSurfaceAsDirty(pThisDisplay, pDestLcl, TRUE); } else #endif // DX7_TEXMANAGEMENT { _DD_BLT_P3ClearDD(pThisDisplay, pDestLcl, pFormatDest, &rDest, lpBlt->bltFX.dwFillColor, FALSE, FALSE); } } else if (dwFlags & DDBLT_DEPTHFILL || ((dwFlags & DDBLT_COLORFILL) && (pDestLcl->ddsCaps.dwCaps & DDSCAPS_ZBUFFER))) { DISPDBG((DBGLVL,"DDBLT_DEPTHFILL(P3): Value=0x%x", lpBlt->bltFX.dwFillColor)); _DD_BLT_P3ClearDD(pThisDisplay, pDestLcl, pFormatDest, &rDest, lpBlt->bltFX.dwFillColor, TRUE, TRUE); } else { START_SOFTWARE_CURSOR(pThisDisplay); DBG_CB_EXIT(DdBlt,lpBlt->ddRVal); return DDHAL_DRIVER_NOTHANDLED; } Blt32Done: if ((pDestLcl->ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE) || (pDestLcl->ddsCaps.dwCaps & DDSCAPS_FRONTBUFFER)) { P3_DMA_DEFS(); DISPDBG((DBGLVL,"Flushing DMA due to primary target in DDRAW")); P3_DMA_GET_BUFFER(); P3_DMA_FLUSH_BUFFER(); } START_SOFTWARE_CURSOR(pThisDisplay); lpBlt->ddRVal = DD_OK; DBG_CB_EXIT(DdBlt,lpBlt->ddRVal); return DDHAL_DRIVER_HANDLED; } // DdBlt