/******************************Module*Header**********************************\ * * ********************* * * DDraw SAMPLE CODE * * ********************* * * Module Name: ddldblt.c * * Content: DirectDraw System to Videomemory download routines * * 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" typedef struct tagSHORTDWORD { BYTE Red; BYTE Green; BYTE Blue; } SHORTDWORD, *LPSHORTDWORD; //----------------------------------------------------------------------------- // // PermediaPatchedTextureDownload // // Do a texture download to the linear region of memory. Access to textures // is faster if they are stored as "patched". This function downloads a texture // from system to videomemory and rearranges the data in the patched format. // // ppdev---------the PPDev // pPrivateDest--DDraw private surface data for the dest. surface // fpSrcVidMem---linear pointer to source systemmemory surface // lSrcPitch-----pitch of source surface // rSrc----------source rectangle // fpDstVidMem---offset in videomemory of dest surface // lDstPitch-----pitch of dest. surface // rDest---------destination rectangle // //----------------------------------------------------------------------------- VOID PermediaPatchedTextureDownload (PPDev ppdev, PermediaSurfaceData* pPrivateDest, FLATPTR fpSrcVidMem, LONG lSrcPitch, RECTL* rSrc, FLATPTR fpDstVidMem, LONG lDstPitch, RECTL* rDest) { PERMEDIA_DEFS(ppdev); ULONG ulTextureBase = (ULONG)(fpDstVidMem); LONG lWidth = rDest->right - rDest->left; LONG lLines = rDest->bottom - rDest->top; DBG_DD((5,"DDraw:PermediaPatchedTextureDownload:, PrivateDest: 0x%x", pPrivateDest)); if (NULL == fpSrcVidMem) { DBG_DD(( 0, "DDraw:PermediaPatchedTextureDownload" " unexpected NULL = fpSrcVidMem")); return; } ASSERTDD(CHECK_P2_SURFACEDATA_VALIDITY(pPrivateDest), "Blt32: Destination Private Data not valid!"); DBG_DD((6," Texture Base: 0x%x DstPitch=0x%x", ulTextureBase, lDstPitch)); DBG_DD((6," Source Base: 0x%x SourcePitch: 0x%x", fpSrcVidMem,lSrcPitch)); DBG_DD((6," rSource->left: 0x%x, rSource->right: 0x%x", rSrc->left,rSrc->right)); DBG_DD((6," rSource->top: 0x%x, rSource->bottom: 0x%x\n", rSrc->top, rSrc->bottom)); DBG_DD((6," rDest->left: 0x%x, rDest->right: 0x%x", rDest->left,rDest->right)); DBG_DD((6," rDest->top: 0x%x, rDest->bottom: 0x%x\n", rDest->top, rDest->bottom)); // // define some handy variables // LONG lPixelSize=pPrivateDest->SurfaceFormat.PixelSize; RESERVEDMAPTR(18); SEND_PERMEDIA_DATA( ColorDDAMode, __PERMEDIA_DISABLE); SEND_PERMEDIA_DATA( AlphaBlendMode, __PERMEDIA_DISABLE); SEND_PERMEDIA_DATA( Window, PM_WINDOW_DISABLELBUPDATE(__PERMEDIA_ENABLE)); SEND_PERMEDIA_DATA( dXDom, 0x0); SEND_PERMEDIA_DATA( dXSub, 0x0); SEND_PERMEDIA_DATA( FBReadPixel, pPrivateDest->SurfaceFormat.FBReadPixel); switch (lPixelSize) { case __PERMEDIA_4BITPIXEL: // There are half as many 8-bit, 4-bit texels DBG_DD((6," Texture is 4-Bit indexed")); lWidth >>= 1; SEND_PERMEDIA_DATA(DitherMode, 0); break; case __PERMEDIA_8BITPIXEL: DBG_DD((6," Texture is 8-Bit indexed")); SEND_PERMEDIA_DATA(DitherMode, 0); break; default: if (lPixelSize != __PERMEDIA_24BITPIXEL) { DBG_DD((6," Texture is BGR")); ulTextureBase >>= lPixelSize; } else { DBG_DD((6," Texture is 24-Bit BGR")); ulTextureBase /= 3; } // Setup the Dither unit SEND_PERMEDIA_DATA(DitherMode,( (INV_COLOR_MODE << PM_DITHERMODE_COLORORDER)| (1 << PM_DITHERMODE_ENABLE) | (pPrivateDest->SurfaceFormat.Format << PM_DITHERMODE_COLORFORMAT) | (pPrivateDest->SurfaceFormat.FormatExtension << PM_DITHERMODE_COLORFORMATEXTENSION) )); break; } DBG_DD((6," Partial Products: 0x%x", pPrivateDest->ulPackedPP)); DBG_DD((6," Texture Width: 0x%x, Downloaded as: 0x%x", (rDest->right - rDest->left),lWidth)); DBG_DD((6," Texture Height: 0x%x", rDest->bottom - rDest->top)); DBG_DD((6," PixelSize: 0x%x", pPrivateDest->SurfaceFormat.PixelSize)); DBG_DD((6," Format: 0x%x", pPrivateDest->SurfaceFormat.Format)); DBG_DD((6," Format Extension: 0x%x", pPrivateDest->SurfaceFormat.FormatExtension)); // Downloading a texture, disable texture colour mode. SEND_PERMEDIA_DATA(TextureColorMode, (0 << PM_TEXCOLORMODE_ENABLE)); SEND_PERMEDIA_DATA(LogicalOpMode, 0); // // all textures get by default marked as P2_CANPATCH, // except 4 bit paletted textures // if (pPrivateDest->dwFlags & P2_CANPATCH) { // Mark the texture as being patched. pPrivateDest->dwFlags |= P2_ISPATCHED; // set up partial product and patch SEND_PERMEDIA_DATA(FBReadMode, PM_FBREADMODE_PARTIAL(pPrivateDest->ulPackedPP) | PM_FBREADMODE_PATCHENABLE(__PERMEDIA_ENABLE) | PM_FBREADMODE_PATCHMODE(__PERMEDIA_SUBPATCH) ); } else { // This texture isn't patched pPrivateDest->dwFlags &= ~P2_ISPATCHED; // Load up the partial products of the texture, don't use patching SEND_PERMEDIA_DATA(FBReadMode, PM_FBREADMODE_PARTIAL(pPrivateDest->ulPackedPP)); } SEND_PERMEDIA_DATA(FBPixelOffset, 0); SEND_PERMEDIA_DATA(FBWindowBase, ulTextureBase); // Use left to right and top to bottom if (lWidth == 2048) { // special case for 2048-wide textures because of the precision // of the StartXSub register SEND_PERMEDIA_DATA(StartXDom, INTtoFIXED(-1)); SEND_PERMEDIA_DATA(StartXSub, INTtoFIXED(lWidth-1)); } else { SEND_PERMEDIA_DATA(StartXDom, INTtoFIXED(0)); SEND_PERMEDIA_DATA(StartXSub, INTtoFIXED(lWidth)); } SEND_PERMEDIA_DATA(StartY, INTtoFIXED(0)); SEND_PERMEDIA_DATA(dY, INTtoFIXED(1)); SEND_PERMEDIA_DATA(Count, (lLines)); SEND_PERMEDIA_DATA(Render, __RENDER_TRAPEZOID_PRIMITIVE | __RENDER_SYNC_ON_HOST_DATA); COMMITDMAPTR(); switch (lPixelSize) { case __PERMEDIA_4BITPIXEL: case __PERMEDIA_8BITPIXEL: { BYTE* pTextureData = (BYTE*)fpSrcVidMem; // // download texture data line by line // while(lLines-- > 0) { LONG lWords=lWidth; BYTE *pData=pTextureData; RESERVEDMAWORDS(lWords+1); LD_INPUT_FIFO_DATA( __Permedia2TagColor | ((lWords-1) << 16)); while (lWords--) { LD_INPUT_FIFO_DATA(*pData++); } COMMITDMAPTR(); // // force flush only every couple of lines // if ((lLines & 3)==0) { FLUSHDMA(); } pTextureData += lSrcPitch; } } break; case __PERMEDIA_16BITPIXEL: { BYTE* pTextureData = (BYTE*)fpSrcVidMem; if (pPrivateDest->SurfaceFormat.RedMask == 0x7c00) { DBG_DD((6," Texture is BGR, 16 bit 5:5:5:1")); // // download texture data line by line // while(lLines-- > 0) { LONG lWords=lWidth; WORD *pData=(WORD*)pTextureData; RESERVEDMAWORDS(lWords+1); LD_INPUT_FIFO_DATA( __Permedia2TagColor | ((lWords-1) << 16)); while (lWords--) { LD_INPUT_FIFO_DATA(FORMAT_5551_32BIT((DWORD)*pData)); pData++; } COMMITDMAPTR(); // // force flush only every couple of lines // if ((lLines & 3)==0) { FLUSHDMA(); } pTextureData += lSrcPitch; } } else if(pPrivateDest->SurfaceFormat.RedMask == 0xF00) { DBG_DD((6," Texture is BGR, 16 bit 4:4:4:4")); // // download texture data line by line // while(lLines-- > 0) { LONG lWords=lWidth; WORD *pData=(WORD*)pTextureData; RESERVEDMAWORDS(lWords+1); LD_INPUT_FIFO_DATA( __Permedia2TagColor | ((lWords-1) << 16)); while (lWords--) { LD_INPUT_FIFO_DATA(FORMAT_4444_32BIT((DWORD)*pData)); pData++; } COMMITDMAPTR(); // // force flush only every couple of lines // if ((lLines & 3)==0) { FLUSHDMA(); } pTextureData += lSrcPitch; } } else { DBG_DD((6," Texture is BGR, 16 bit 5:6:5")); // // download texture data line by line // while(lLines-- > 0) { LONG lWords=lWidth; WORD *pData=(WORD*)pTextureData; RESERVEDMAWORDS(lWords+1); LD_INPUT_FIFO_DATA( __Permedia2TagColor | ((lWords-1) << 16)); while (lWords--) { LD_INPUT_FIFO_DATA(FORMAT_565_32BIT((DWORD)*pData)); pData++; } COMMITDMAPTR(); // // force flush only every couple of lines // if ((lLines & 3)==0) { FLUSHDMA(); } pTextureData += lSrcPitch; } } } break; case __PERMEDIA_24BITPIXEL: case __PERMEDIA_32BITPIXEL: { BYTE* pTextureData = (BYTE*)fpSrcVidMem; // // download texture data line by line // while(lLines-- > 0) { LONG lWords=lWidth; ULONG *pData=(ULONG*)pTextureData; RESERVEDMAWORDS(lWords+1); LD_INPUT_FIFO_DATA( __Permedia2TagColor | ((lWords-1) << 16)); while (lWords--) { LD_INPUT_FIFO_DATA(*pData++); } COMMITDMAPTR(); // // force flush only every couple of lines // if ((lLines & 3)==0) { FLUSHDMA(); } pTextureData += lSrcPitch; } } break; } RESERVEDMAPTR(2); SEND_PERMEDIA_DATA(DitherMode, 0); SEND_PERMEDIA_DATA(WaitForCompletion, 0); COMMITDMAPTR(); } // PermediaPatchedTextureDownload //----------------------------------------------------------------------------- // // PermediaPackedDownload // // Function to do a system to video memory blt. // Uses the packed bit on Permedia to do the packing for us. Needs // to setup the offset bit for alignment and doesn't need to adjust // the partial products. The calling function guarantees that the // source and destination rects have the same size. // // // ppdev----------the PPDev // pPrivateDst----Permedia Surface data for destination // lpSourceSurf---DDraw LCL for source surface // rSrc-----------source rect // lpDestSurf-----DDraw LCL for destination surface // rDest----------dest rect // //----------------------------------------------------------------------------- VOID PermediaPackedDownload(PPDev ppdev, PermediaSurfaceData* pPrivateDst, LPDDRAWI_DDRAWSURFACE_LCL lpSourceSurf, RECTL* rSrc, LPDDRAWI_DDRAWSURFACE_LCL lpDestSurf, RECTL* rDst) { PERMEDIA_DEFS(ppdev); LONG lDstOffset; // dest offset in packed coordinates LONG lSrcOffset; // source offset in buffer in bytes LONG lDstLeft, lDstRight; // left and right dst in packed coordiantes LONG lSrcLeft, lSrcRight; // left and right src in packed coordiantes LONG lPackedWidth; // packed width to download LONG lPixelMask; // mask for pixels per packed DWORD LONG lOffset; // relative offset between src and dest LONG lPixelShift; // handy helper var which contains pixel // shift from packed to surface format LONG lPixelSize; // just a helper LONG lExtraDword; // chip needs extra dummy // DWORD passed at end of line DBG_DD((5,"DDraw:PermediaPackedDownload, PrivateDst: 0x%x", pPrivateDst)); ASSERTDD(CHECK_P2_SURFACEDATA_VALIDITY(pPrivateDst), "Blt: Destination Private Data not valid!"); ASSERTDD((rSrc->right-rSrc->left)==(rDst->right-rDst->left), "PermediaPackedDownload: src and dest rect width not equal"); ASSERTDD((rSrc->bottom-rSrc->top)==(rDst->bottom-rDst->top), "PermediaPackedDownload: src and dest rect height not equal"); // get a handy variable for pixel shifts, masks and size lPixelSize=pPrivateDst->SurfaceFormat.PixelSize; lPixelMask=pPrivateDst->SurfaceFormat.PixelMask; lPixelShift=pPrivateDst->SurfaceFormat.PixelShift; // offset in dst buffer adjusted to packed format lDstOffset =(LONG)((UINT_PTR)(lpDestSurf->lpGbl->fpVidMem) >> lPixelShift); // calculate offset in source buffer adjusted to packed format lSrcOffset = ((rSrc->left & ~lPixelMask) << lPixelShift) + (rSrc->top * lpSourceSurf->lpGbl->lPitch); // Calculate the relative offset within the dword packed dimensions lOffset = ((rDst->left & lPixelMask) - (rSrc->left & lPixelMask)) & 0x7; // set up the left and right end of the unpacked source data lDstLeft = rDst->left; lDstRight = rDst->right; // precalc packed width for 32 bit case lPackedWidth = lDstRight-lDstLeft; lExtraDword=0; if (lPixelSize != __PERMEDIA_32BITPIXEL) { // we need to check both source and dest // if they have different alignments LONG lSrcLeft2 = rSrc->left; LONG lSrcRight2 = rSrc->right; // Set up the relative offset to allow us to download packed word // and byte aligned data. if (lPixelSize == __PERMEDIA_4BITPIXEL) { lDstLeft >>= 3; lSrcLeft2 >>= 3; lDstRight = (lDstRight + 7) >> 3; lSrcRight2 = (lSrcRight2 + 7) >> 3; } else if (lPixelSize == __PERMEDIA_8BITPIXEL) { lDstLeft >>= 2; lSrcLeft2 >>= 2; lDstRight = (lDstRight + 3) >> 2; lSrcRight2 = (lSrcRight2 + 3) >> 2; } else { lDstLeft >>= 1; lSrcLeft2 >>= 1; lDstRight = (lDstRight + 1) >> 1; lSrcRight2 = (lSrcRight2 + 1) >> 1; } if ((lSrcRight2-lSrcLeft2) < (lDstRight-lDstLeft)) { lExtraDword=1; lPackedWidth = lDstRight-lDstLeft; } else { lPackedWidth = lSrcRight2-lSrcLeft2; } } RESERVEDMAPTR(12); SEND_PERMEDIA_DATA(FBReadPixel, pPrivateDst->SurfaceFormat.FBReadPixel); // No logical ops in SYS->VIDMEM Blits SEND_PERMEDIA_DATA(LogicalOpMode, 0); // Load up the partial products of image SEND_PERMEDIA_DATA(FBReadMode, (pPrivateDst->ulPackedPP) | PM_FBREADMODE_PACKEDDATA(__PERMEDIA_ENABLE)| PM_FBREADMODE_RELATIVEOFFSET(lOffset) ); SEND_PERMEDIA_DATA(FBPixelOffset, 0); SEND_PERMEDIA_DATA(FBWindowBase, lDstOffset); // Use left to right and top to bottom SEND_PERMEDIA_DATA(StartXDom, INTtoFIXED(lDstLeft)); SEND_PERMEDIA_DATA(StartXSub, INTtoFIXED(lDstLeft+lPackedWidth)); SEND_PERMEDIA_DATA(PackedDataLimits,PM_PACKEDDATALIMITS_OFFSET(lOffset) | (rDst->left << 16) | rDst->right); SEND_PERMEDIA_DATA(StartY, INTtoFIXED(rDst->top)); SEND_PERMEDIA_DATA(dY, INTtoFIXED(1)); SEND_PERMEDIA_DATA(Count, (rDst->bottom - rDst->top)); SEND_PERMEDIA_DATA(Render, __RENDER_TRAPEZOID_PRIMITIVE | __RENDER_SYNC_ON_HOST_DATA); COMMITDMAPTR(); // // introduce some more handy pointers and LONGs // BYTE *pSurfaceData = (BYTE *)lpSourceSurf->lpGbl->fpVidMem + lSrcOffset; LONG lPitch =lpSourceSurf->lpGbl->lPitch; LONG lHeight=rDst->bottom - rDst->top; // // pump the whole thing in one huge block // if the pitch and linewidth are the same and no extra treatment // for the buffer end is necessary // if ((lExtraDword==0) && (lPackedWidth*(LONG)sizeof(ULONG))==lPitch) { vBlockLoadInputFifo( pP2dma, __Permedia2TagColor, (ULONG*)pSurfaceData, lPackedWidth*lHeight); } else { // // lExtraDword is zero or 1, depends if we have to do a special // treatment after this while block // while (lHeight>lExtraDword) { LONG lWords=lPackedWidth; ULONG *pImage=(ULONG*)pSurfaceData; RESERVEDMAWORDS(lWords+1); LD_INPUT_FIFO_DATA( __Permedia2TagColor | ((lWords-1) << 16)); while (lWords--) { LD_INPUT_FIFO_DATA(*pImage++); } COMMITDMAPTR(); // // force flush only every couple of lines // if ((lHeight & 3)==0) { FLUSHDMA(); } pSurfaceData += lPitch; lHeight--; } // // treat last line separately, because we could read over the // end of buffer here if the source and dest rects are aligned // differently. lHeight will only be one here if lExtraDword==1 // if (lHeight==1) { LONG lWords=lPackedWidth-1; ULONG *pImage=(ULONG*)pSurfaceData; RESERVEDMAWORDS(lWords+1); LD_INPUT_FIFO_DATA( __Permedia2TagColor | ((lWords-1) << 16)); while (lWords--) { LD_INPUT_FIFO_DATA(*pImage++); } COMMITDMAPTR(); // // send extra dummy DWORD // RESERVEDMAPTR(1); SEND_PERMEDIA_DATA( Color, 0); COMMITDMAPTR(); } FLUSHDMA(); } } // PermediaPackedDownload