/******************************Module*Header**********************************\ * * ********************* * * DDraw SAMPLE CODE * * ********************* * * Module Name: ddcpyblt.c * * Content: several copy and clear blits for Permedia 2 * * Copyright (c) 1994-1998 3Dlabs Inc. Ltd. All rights reserved. * Copyright (c) 1995-1999 Microsoft Corporation. All rights reserved. \*****************************************************************************/ #include "precomp.h" #include "directx.h" #include "dd.h" //----------------------------------------------------------------------------- // // PermediaPackedCopyBlt // // Does a packed blit, allowing for different source and destination // partial products. // // ppdev----------- the ppdev // dwDestPitch----- pitch of destination surface // dwSourcePitch--- pitch of source surface // pDest----------- pointer to private data structure of dest. surface // pSource--------- pointer to private data structure of source surface // *rDest---------- dest. rectangle of blit // *rSrc----------- source rectangle of blit // dwWindowBase---- offset of dest. window in frame buffer // lWindowOffset--- offset of source window in frame buffer // //----------------------------------------------------------------------------- VOID PermediaPackedCopyBlt( PPDev ppdev, // ppdev DWORD dwDestPitch, // pitch of dest DWORD dwSourcePitch, PermediaSurfaceData* pDest, PermediaSurfaceData* pSource, RECTL *rDest, RECTL *rSrc, DWORD dwWindowBase, LONG lWindowOffset ) { PERMEDIA_DEFS(ppdev); LONG lOffset; LONG lSourceOffset; LONG lPixelSize=pDest->SurfaceFormat.PixelSize; LONG lPixelMask=3>>pDest->SurfaceFormat.PixelShift; LONG lPixelShift=2-pDest->SurfaceFormat.PixelShift; DBG_DD(( 5, "DDraw:PermediaPackedCopyBlt " "From %08lx %08lx %08lx %08lx %08lx %08lx %08lx " "To %08lx %08lx %08lx %08lx %08lx %08lx %08lx", dwSourcePitch,pSource,rSrc->bottom,rSrc->left, rSrc->right,rSrc->top,lWindowOffset, dwDestPitch,pDest,rDest->bottom,rDest->left, rDest->right,rDest->top,dwWindowBase)); ASSERTDD(!(rSrc->top<0) && !(rSrc->left<0), "PermediaPackedCopyBlt: cannot handle neg. src coordinates"); ASSERTDD(!(rDest->top<0) && !(rDest->left<0), "PermediaPackedCopyBlt: cannot handle neg. src coordinates"); lOffset = (((rDest->left & lPixelMask)-(rSrc->left & lPixelMask)) & 7); lSourceOffset = lWindowOffset + RECTS_PIXEL_OFFSET(rSrc, rDest, dwSourcePitch, dwDestPitch, lPixelMask ) + LINEAR_FUDGE(dwSourcePitch, dwDestPitch, rDest); RESERVEDMAPTR(14); SEND_PERMEDIA_DATA( FBPixelOffset, 0x0); SEND_PERMEDIA_DATA( FBReadPixel, pDest->SurfaceFormat.FBReadPixel); // set packed with offset SEND_PERMEDIA_DATA( FBWindowBase, dwWindowBase); SEND_PERMEDIA_DATA( FBReadMode, PM_FBREADMODE_PARTIAL(pSource->ulPackedPP) | PM_FBREADMODE_READSOURCE(__PERMEDIA_ENABLE) | PM_FBREADMODE_PACKEDDATA(__PERMEDIA_ENABLE) | PM_FBREADMODE_RELATIVEOFFSET(lOffset)); SEND_PERMEDIA_DATA( FBWriteConfig, PM_FBREADMODE_PARTIAL(pDest->ulPackedPP) | PM_FBREADMODE_READSOURCE(__PERMEDIA_ENABLE) | PM_FBREADMODE_PACKEDDATA(__PERMEDIA_ENABLE) | PM_FBREADMODE_RELATIVEOFFSET(lOffset)); SEND_PERMEDIA_DATA( LogicalOpMode, __PERMEDIA_DISABLE); SEND_PERMEDIA_DATA( FBSourceOffset, lSourceOffset); // Render the rectangle if (lSourceOffset >= 0) { // Use left to right and top to bottom SEND_PERMEDIA_DATA( StartXDom, INTtoFIXED(rDest->left >> lPixelShift)); SEND_PERMEDIA_DATA( StartXSub, INTtoFIXED((rDest->right >> lPixelShift) + lPixelMask)); SEND_PERMEDIA_DATA( PackedDataLimits, PM_PACKEDDATALIMITS_OFFSET(lOffset) | PM_PACKEDDATALIMITS_XSTART(rDest->left) | PM_PACKEDDATALIMITS_XEND(rDest->right)); SEND_PERMEDIA_DATA( StartY, INTtoFIXED(rDest->top)); SEND_PERMEDIA_DATA( dY, INTtoFIXED(1)); } else { // Use right to left and bottom to top SEND_PERMEDIA_DATA( StartXDom, INTtoFIXED(((rDest->right) >> lPixelShift) + lPixelMask)); SEND_PERMEDIA_DATA( StartXSub, INTtoFIXED(rDest->left >> lPixelShift)); SEND_PERMEDIA_DATA( PackedDataLimits, PM_PACKEDDATALIMITS_OFFSET(lOffset) | PM_PACKEDDATALIMITS_XSTART(rDest->right) | PM_PACKEDDATALIMITS_XEND(rDest->left)); SEND_PERMEDIA_DATA( StartY, INTtoFIXED(rDest->bottom - 1)); SEND_PERMEDIA_DATA( dY, (DWORD)INTtoFIXED(-1)); } SEND_PERMEDIA_DATA( Count, rDest->bottom - rDest->top); SEND_PERMEDIA_DATA( Render, __RENDER_TRAPEZOID_PRIMITIVE); COMMITDMAPTR(); FLUSHDMA(); } // PermediaPackedCopyBlt //----------------------------------------------------------------------------- // // PermediaPatchedCopyBlt // // Does a patched blit, i.e. blits from source to destination and // turns on patching. Note that this method cannot use packed blits. // // ppdev----------- the ppdev // dwDestPitch----- pitch of destination surface // dwSourcePitch--- pitch of source surface // pDest----------- pointer to private data structure of dest. surface // pSource--------- pointer to private data structure of source surface // *rDest---------- dest. rectangle of blit // *rSrc----------- source rectangle of blit // dwWindowBase---- offset of dest. window in frame buffer // lWindowOffset--- offset of source window in frame buffer // //----------------------------------------------------------------------------- VOID PermediaPatchedCopyBlt( PPDev ppdev, DWORD dwDestPitch, DWORD dwSourcePitch, PermediaSurfaceData* pDest, PermediaSurfaceData* pSource, RECTL *rDest, RECTL *rSrc, DWORD dwWindowBase, LONG lWindowOffset ) { PERMEDIA_DEFS(ppdev); LONG lSourceOffset; LONG lPixelSize=pDest->SurfaceFormat.PixelSize; LONG lPixelMask=pDest->SurfaceFormat.PixelMask; LONG lPixelShift=pDest->SurfaceFormat.PixelShift; ASSERTDD(!(rSrc->top<0) && !(rSrc->left<0), "PermediaPackedCopyBlt: cannot handle neg. src coordinates"); ASSERTDD(!(rDest->top<0) && !(rDest->left<0), "PermediaPackedCopyBlt: cannot handle neg. src coordinates"); DBG_DD(( 5, "DDraw:PermediaPatchedCopyBlt")); lSourceOffset = lWindowOffset + RECTS_PIXEL_OFFSET(rSrc, rDest, dwSourcePitch, dwDestPitch, lPixelMask) + LINEAR_FUDGE(dwSourcePitch, dwDestPitch, rDest); RESERVEDMAPTR(13); SEND_PERMEDIA_DATA( FBPixelOffset, 0x0); SEND_PERMEDIA_DATA( FBReadPixel, pDest->SurfaceFormat.FBReadPixel); // Patching isn't symetric, so we need to reverse the patch code depending // on the direction of the patch SEND_PERMEDIA_DATA( FBWindowBase, dwWindowBase); if (pDest->dwFlags & P2_CANPATCH) { pDest->dwFlags |= P2_ISPATCHED; SEND_PERMEDIA_DATA( FBReadMode, pSource->ulPackedPP | __FB_READ_SOURCE); SEND_PERMEDIA_DATA( FBWriteConfig, pDest->ulPackedPP | PM_FBREADMODE_PATCHENABLE(__PERMEDIA_ENABLE) | PM_FBREADMODE_PATCHMODE(__PERMEDIA_SUBPATCH)); } else { pDest->dwFlags &= ~P2_ISPATCHED; SEND_PERMEDIA_DATA( FBReadMode, pSource->ulPackedPP | __FB_READ_SOURCE | PM_FBREADMODE_PATCHENABLE(__PERMEDIA_ENABLE) | PM_FBREADMODE_PATCHMODE(__PERMEDIA_SUBPATCH) ); SEND_PERMEDIA_DATA(FBWriteConfig, (pDest->ulPackedPP )); } SEND_PERMEDIA_DATA(LogicalOpMode, __PERMEDIA_DISABLE); SEND_PERMEDIA_DATA(FBSourceOffset, lSourceOffset); // Render the rectangle if (lSourceOffset >= 0) { // Use left to right and top to bottom SEND_PERMEDIA_DATA(StartXDom, INTtoFIXED(rDest->left)); SEND_PERMEDIA_DATA(StartXSub, INTtoFIXED(rDest->right)); SEND_PERMEDIA_DATA(StartY, INTtoFIXED(rDest->top)); SEND_PERMEDIA_DATA(dY, INTtoFIXED(1)); } else { // Use right to left and bottom to top SEND_PERMEDIA_DATA(StartXDom, INTtoFIXED(rDest->right)); SEND_PERMEDIA_DATA(StartXSub, INTtoFIXED(rDest->left)); SEND_PERMEDIA_DATA(StartY, INTtoFIXED(rDest->bottom - 1)); SEND_PERMEDIA_DATA(dY, (DWORD)INTtoFIXED(-1)); } SEND_PERMEDIA_DATA(Count, rDest->bottom - rDest->top); SEND_PERMEDIA_DATA(Render, __RENDER_TRAPEZOID_PRIMITIVE); COMMITDMAPTR(); FLUSHDMA(); } // PermediaPatchedCopyBlt //----------------------------------------------------------------------------- // // PermediaFastClear // // Does a fast clear of a surface. Supports all color depths // Can clear depth or Frame buffer. // // ppdev---------the ppdev // pPrivateData--pointer to private data structure of dest. surface // rDest---------rectangle for colorfill in dest. surface // dwWindowBase--offset of dest. surface in frame buffer // dwColor-------color for fill // //----------------------------------------------------------------------------- VOID PermediaFastClear(PPDev ppdev, PermediaSurfaceData* pPrivateData, RECTL *rDest, DWORD dwWindowBase, DWORD dwColor) { PERMEDIA_DEFS(ppdev); ULONG ulRenderBits; BOOL bFastFill=TRUE; LONG lPixelSize=pPrivateData->SurfaceFormat.PixelSize; DBG_DD(( 5, "DDraw:PermediaFastClear")); ASSERTDD(CHECK_P2_SURFACEDATA_VALIDITY(pPrivateData), "Private Surface data not valid in clear"); ASSERTDD((pPrivateData->dwFlags & P2_PPVALID), "PermediaFastClear called with invalid PP codes"); ulRenderBits = __RENDER_FAST_FILL_ENABLE | __RENDER_TRAPEZOID_PRIMITIVE; // Clear depending on depth switch (lPixelSize) { case __PERMEDIA_4BITPIXEL: dwColor &= 0xF; dwColor |= dwColor << 4; // fall through... case __PERMEDIA_8BITPIXEL: dwColor &= 0xFF; dwColor |= dwColor << 8; // fall through case __PERMEDIA_16BITPIXEL: dwColor &= 0xFFFF; dwColor |= (dwColor << 16); break; case __PERMEDIA_24BITPIXEL: dwColor &= 0xFFFFFF; dwColor |= ((dwColor & 0xFF) << 24); // Can't use SGRAM fast block fills on any color, only on grey. if (((dwColor & 0xFF) == ((dwColor & 0xFF00) >> 8)) && ((dwColor & 0xFF) == ((dwColor & 0xFF0000) >> 16))) { bFastFill = TRUE; } else { bFastFill = FALSE; } break; default: break; } RESERVEDMAPTR(15); SEND_PERMEDIA_DATA( dXDom, 0x0); SEND_PERMEDIA_DATA( dXSub, 0x0); SEND_PERMEDIA_DATA( FBPixelOffset, 0); SEND_PERMEDIA_DATA( FBReadPixel, pPrivateData->SurfaceFormat.FBReadPixel); if (bFastFill) { SEND_PERMEDIA_DATA(FBBlockColor, dwColor); } else { ulRenderBits &= ~__RENDER_FAST_FILL_ENABLE; SEND_PERMEDIA_DATA(FBWriteData, dwColor); } SEND_PERMEDIA_DATA(FBReadMode, PM_FBREADMODE_PARTIAL(pPrivateData->ulPackedPP)| PM_FBREADMODE_PACKEDDATA(__PERMEDIA_DISABLE)); SEND_PERMEDIA_DATA(LogicalOpMode, __PERMEDIA_CONSTANT_FB_WRITE); SEND_PERMEDIA_DATA(FBWindowBase, dwWindowBase); // Render the rectangle SEND_PERMEDIA_DATA(StartXDom, INTtoFIXED(rDest->left)); SEND_PERMEDIA_DATA(StartXSub, INTtoFIXED(rDest->right)); SEND_PERMEDIA_DATA(StartY, INTtoFIXED(rDest->top)); SEND_PERMEDIA_DATA(dY, INTtoFIXED(1)); SEND_PERMEDIA_DATA(Count, rDest->bottom - rDest->top); SEND_PERMEDIA_DATA(Render, ulRenderBits); // Reset our pixel values. SEND_PERMEDIA_DATA(LogicalOpMode, __PERMEDIA_DISABLE); COMMITDMAPTR(); FLUSHDMA(); } //PermediaFastClear //----------------------------------------------------------------------------- // // PermediaClearManagedSurface // // 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 PermediaClearManagedSurface(DWORD PixelSize, RECTL *rDest, FLATPTR fpVidMem, LONG lPitch, DWORD dwColor) { BYTE* pDestStart; LONG i; DBG_DD(( 5, "DDraw:PermediaClearManagedSurface")); 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 __PERMEDIA_4BITPIXEL: { DWORD right=rDest->right,left=rDest->left; dwColor &= 0x0F; dwColor |= dwColor << 4; if (right & 1) { pDestStart = (BYTE*)(fpVidMem + (rDest->top * lPitch)); pDestStart += right/2; for (i=0;itop * lPitch)); pDestStart += left/2; for (i=0;itop * lPitch)); while (--lHeight >= 0) { while (leftleft; while (--lHeight >= 0) { for (i=0;ileft*2; while (--lHeight >= 0) { LPWORD lpWord=(LPWORD)pDestStart; for (i=0;ileft*4; while (--lHeight >= 0) { LPDWORD lpDWord=(LPDWORD)pDestStart; for (i=0;idwFlags & P2_PPVALID), "PermediaFastClear called with invalid PP codes"); // Clear according to Z-Buffer depth dwColor &= 0xFFFF; dwColor |= dwColor << 16; RESERVEDMAPTR(15); SEND_PERMEDIA_DATA( dXDom, 0x0); SEND_PERMEDIA_DATA( dXSub, 0x0); SEND_PERMEDIA_DATA( FBPixelOffset, 0); SEND_PERMEDIA_DATA( FBReadPixel, __PERMEDIA_16BITPIXEL); SEND_PERMEDIA_DATA( FBBlockColor, dwColor); SEND_PERMEDIA_DATA( FBReadMode, PM_FBREADMODE_PARTIAL(pPrivateData->ulPackedPP) | PM_FBREADMODE_PACKEDDATA(__PERMEDIA_DISABLE)); SEND_PERMEDIA_DATA( LogicalOpMode, __PERMEDIA_CONSTANT_FB_WRITE); SEND_PERMEDIA_DATA( FBWindowBase, dwWindowBase); SEND_PERMEDIA_DATA( StartXDom, INTtoFIXED(rDest->left)); SEND_PERMEDIA_DATA( StartXSub, INTtoFIXED(rDest->right)); SEND_PERMEDIA_DATA( StartY, INTtoFIXED(rDest->top)); SEND_PERMEDIA_DATA( dY, INTtoFIXED(1)); SEND_PERMEDIA_DATA( Count, rDest->bottom - rDest->top); SEND_PERMEDIA_DATA( Render, __RENDER_FAST_FILL_ENABLE |__RENDER_TRAPEZOID_PRIMITIVE); // Reset our pixel values. SEND_PERMEDIA_DATA( LogicalOpMode, __PERMEDIA_DISABLE); COMMITDMAPTR(); FLUSHDMA(); } // PermediaFastLBClear //----------------------------------------------------------------------------- // // SysMemToSysMemSurfaceCopy // // Does a copy from System memory to System memory (either from or to an // AGP surface, or any other system memory surface) // //----------------------------------------------------------------------------- VOID SysMemToSysMemSurfaceCopy(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; DBG_DD(( 5, "DDraw:SysMemToSysMemSurfaceCopy")); LONG lByteWidth = rSource->right - rSource->left; LONG lHeight = rSource->bottom - rSource->top; if (NULL == fpSrcVidMem || NULL == fpDstVidMem) { DBG_DD(( 0, "DDraw:SysMemToSysMemSurfaceCopy 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)); // Be careful if the source is 4 bits deep. if(4 == dwSrcBitCount) { // May have to handle horrible single pixel edges. Check if we need to if (!((1 & (rSource->left ^ rDest->left)) == 1)) { pSourceStart += rSource->left / 2; pDestStart += rDest->left / 2; lByteWidth /= 2; // Do we have to account for the odd pixel at the start? if (rSource->left & 0x1) { lByteWidth--; } // If the end is odd then miss of the last nibble (do it later). if (rSource->right & 0x1) { lByteWidth--; } while (--lHeight >= 0) { // Potentially copy the left hand pixel if (rSource->left & 0x1) { *pDestStart &= 0x0F; *pDestStart |= (*pSourceStart & 0xF0); pNewDest = pDestStart + 1; pNewSource = pSourceStart + 1; } else { pNewDest = pDestStart; pNewSource = pSourceStart; } // Byte copy the rest of the field memcpy(pNewDest, pNewSource, lByteWidth); // Potentially copy the right hand pixel if (rSource->right & 0x1) { *(pNewDest + lByteWidth) &= 0xF0; *(pNewDest + lByteWidth) |= (*(pNewSource + lByteWidth) & 0xF); } pDestStart += lDstPitch; pSourceStart += lSrcPitch; } } else { // Do it the hard way - copy single pixels one at a time pSourceStart += rSource->left / 2; pDestStart += rDest->left / 2; while (--lHeight >= 0) { BOOL bOddSource = rSource->left & 0x1; BOOL bOddDest = rDest->left & 0x1; pNewDest = pDestStart; pNewSource = pSourceStart; for (INT i = 0; i < lByteWidth; i++) { if (bOddSource) { pixSource = (*pNewSource & 0xF0) >> 4; pNewSource++; } else { pixSource = (*pNewSource & 0x0F); } if (bOddDest) { *pNewDest &= 0x0F; *pNewDest |= pixSource << 4; pNewDest++; } else { *pNewDest &= 0xF0; *pNewDest |= pixSource; } bOddSource = !bOddSource; bOddDest = !bOddDest; } // Step onto the next line pDestStart += lDstPitch; pSourceStart += lSrcPitch; } } } else // The simple 8, 16 or 24 bit copy { pSourceStart += rSource->left * (dwSrcBitCount >> 3); pDestStart += rDest->left * (dwDstBitCount >> 3); lByteWidth *= (dwSrcBitCount >> 3); while (--lHeight >= 0) { memcpy(pDestStart, pSourceStart, lByteWidth); pDestStart += lDstPitch; pSourceStart += lSrcPitch; }; } } // SysMemToSysMemSurfaceCopy