/******************************Module*Header**********************************\ * * ******************* * * D3D SAMPLE CODE * * ******************* * * Module Name: d3ddp2op.c * * Content: D3D DrawPrimitives2 command buffer operations support * * Copyright (c) 1994-1999 3Dlabs Inc. Ltd. All rights reserved. * Copyright (c) 1995-2003 Microsoft Corporation. All rights reserved. \*****************************************************************************/ #include "glint.h" #include "dma.h" #include "tag.h" //----------------------------------------------------------------------------- // // __OP_IntersectRectl // // This function intersects two RECTLs. If no intersection exists returns FALSE // //----------------------------------------------------------------------------- BOOL __OP_IntersectRectl( RECTL* prcresult, RECTL* prcin1, RECT* prcin2) { prcresult->left = max(prcin1->left, prcin2->left); prcresult->right = min(prcin1->right, prcin2->right); if (prcresult->left < prcresult->right) { prcresult->top = max(prcin1->top, prcin2->top); prcresult->bottom = min(prcin1->bottom, prcin2->bottom); if (prcresult->top < prcresult->bottom) { return TRUE; } } return FALSE; } // __OP_IntersectRectl #if DX7_TEXMANAGEMENT VOID __OP_MarkManagedSurfDirty(P3_D3DCONTEXT* pContext, DWORD dwSurfHandle, P3_SURF_INTERNAL* pTexture); #endif //----------------------------------------------------------------------------- // // _D3D_OP_Clear2 // // This function processes the D3DDP2OP_CLEAR DP2 command token. // // It builds a mask and a value for the stencil/depth clears. The mask is used // to stop unwanted bits being updated during the clear. The value is scaled in // the case of the Z depth, and is shifted in the case of the stencil. This // results in the correct value being written, at the correct location in the // ZBuffer, while doing fast-block fills through SGRAM //----------------------------------------------------------------------------- #define P3RX_UPDATE_WRITE_MASK(a) \ if (dwCurrentMask != a) \ { \ P3_DMA_GET_BUFFER_ENTRIES(2); \ SEND_P3_DATA(FBHardwareWriteMask, a); \ P3_DMA_COMMIT_BUFFER(); \ dwCurrentMask = a; \ } VOID _D3D_OP_Clear2( P3_D3DCONTEXT* pContext, D3DHAL_DP2CLEAR* lpcd2, DWORD dwNumRects) { DWORD i; RECTL rect, rect_vwport; DWORD dwDepthValue; DWORD dwStencilValue; DWORD dwStencilMask; DWORD dwDepthMask; DWORD color; DWORD dwCurrentMask = 0xFFFFFFFF; BOOL bNoBlockFillZ = FALSE; BOOL bNoBlockFillStencil = FALSE; BOOL bComputeIntersections = FALSE; BYTE Bytes[4]; P3_THUNKEDDATA* pThisDisplay = pContext->pThisDisplay; HRESULT ddrval; D3DHAL_DP2CLEAR WholeViewport; P3_DMA_DEFS(); DBG_CB_ENTRY(_D3D_OP_Clear2); // Check if we were asked to clear a valid buffer if ( (lpcd2->dwFlags & (D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER | D3DCLEAR_STENCIL) ) == 0) { // We have been asked to do nothing - and that's what we've done. DBG_CB_EXIT(_D3D_OP_Clear2, DD_OK); return; } #if DX8_DDI // When zero clear rects is passed to a DX8 driver with D3DDP2OP_CLEAR // token, the driver should clear the whole viewport. The zero number // of rects could be passed only if D3D is using a pure device. // D3DCLEAR_COMPUTERECTS has been added to the dwFlags of D3DHAL_CLEARDATA. // When set, the flag means that user provided clear rects should be // culled against the current viewport. if (!(lpcd2->dwFlags & D3DCLEAR_COMPUTERECTS)) { // Do nothing for non-pure device } else if (dwNumRects == 0) { // When wStateCount is zero we need to clear whole viewport WholeViewport.dwFlags = lpcd2->dwFlags; WholeViewport.dwFillColor = lpcd2->dwFillColor; WholeViewport.dvFillDepth = lpcd2->dvFillDepth; WholeViewport.dwFillStencil = lpcd2->dwFillStencil; WholeViewport.Rects[0].left = pContext->ViewportInfo.dwX; WholeViewport.Rects[0].top = pContext->ViewportInfo.dwY; WholeViewport.Rects[0].right = pContext->ViewportInfo.dwX + pContext->ViewportInfo.dwWidth; WholeViewport.Rects[0].bottom = pContext->ViewportInfo.dwY + pContext->ViewportInfo.dwHeight; // Replace pointers and continue as usual lpcd2 = &WholeViewport; dwNumRects = 1; } else { // We need to cull all rects against the current viewport // but in order not to allocate a temporary RECT array in // kernel heap we'll compute this inside the clearing loop rect_vwport.left = pContext->ViewportInfo.dwX; rect_vwport.top = pContext->ViewportInfo.dwY; rect_vwport.right = pContext->ViewportInfo.dwX + pContext->ViewportInfo.dwWidth; rect_vwport.bottom = pContext->ViewportInfo.dwY + pContext->ViewportInfo.dwHeight; bComputeIntersections = TRUE; } #endif // DX8_DDI // Check if there is any rect to clear at all if ( dwNumRects == 0) { // We have been asked to do nothing - and that's what we've done. DBG_CB_EXIT(_D3D_OP_Clear2, DD_OK); return; } // Wait until we have we finished flipping before clearing anything do { ddrval = _DX_QueryFlipStatus(pContext->pThisDisplay, pContext->pSurfRenderInt->fpVidMem, TRUE); } while ( FAILED (ddrval) ); // Switch to hw Ddraw context in order to do the clears DDRAW_OPERATION(pContext, pThisDisplay); // Prepare any data necessary to clear the render target if ((lpcd2->dwFlags & D3DCLEAR_TARGET) && (pContext->pSurfRenderInt != NULL)) { color = lpcd2->dwFillColor; // Clear depending on depth switch (pContext->pSurfRenderInt->dwPixelSize) { // 16 Bit colors come in as 32 Bit RGB Values // Color will be packed in the clear function case __GLINT_16BITPIXEL: if (pThisDisplay->ddpfDisplay.dwRBitMask == 0x7C00) { color = ((color & 0xf8) >> 3) | ((color & 0xf800) >> (16 - 10)) | ((color & 0xf80000) >> (24 - 15)); } else { color = ((color & 0xff) >> 3) | ((color & 0xfc00) >> (16 - 11)) | ((color & 0xf80000) >> (24 - 16)); } break; case __GLINT_24BITPIXEL: DISPDBG((ERRLVL,"P3 doesn't support 24 bpp render target")); break; default: break; } } // if (lpcd2->dwFlags & D3DCLEAR_TARGET) // Prepare any data necessary to clear the depth buffer if ((lpcd2->dwFlags & D3DCLEAR_ZBUFFER) && (pContext->pSurfZBufferInt != NULL)) { float fDepth; DDPIXELFORMAT* pPixFormat = &pContext->pSurfZBufferInt->pixFmt; DWORD dwZBitDepth = pPixFormat->dwZBufferBitDepth; // Find the depth bits, remembering to remove any stencil bits. if (pPixFormat->dwFlags & DDPF_STENCILBUFFER) { dwZBitDepth -= pPixFormat->dwStencilBitDepth; } dwDepthMask = (0xFFFFFFFF >> (32 - dwZBitDepth)); // 32 bit depth buffers on Perm3 are really // limited to 31 bits of precision if (dwZBitDepth == 32) { dwDepthMask = dwDepthMask >> 1; } if (lpcd2->dvFillDepth == 1.0f) { dwDepthValue = dwDepthMask; } else { fDepth = lpcd2->dvFillDepth * (float)dwDepthMask; // This is a hardware dependency on how the Perm3 handles the // limited precision of 32bit floats(24 bits of mantissa) and // converts the value into a 32bit z buffer value. This doesn't // happen with any other z bit depth but 32. if (dwZBitDepth == 32) { fDepth += 0.5f; } myFtoi((int*)&dwDepthValue, fDepth); } // As we are fast-block filling, make sure we copy the // Mask to the top bits. switch (pContext->pSurfZBufferInt->dwPixelSize) { case __GLINT_16BITPIXEL: dwDepthMask &= 0xFFFF; dwDepthMask |= (dwDepthMask << 16); break; case __GLINT_8BITPIXEL: dwDepthMask &= 0xFF; dwDepthMask |= dwDepthMask << 8; dwDepthMask |= dwDepthMask << 16; break; } if (pThisDisplay->pGLInfo->bDRAMBoard) { // Check for a DRAM fill that the chip isn't emulating. Bytes[0] = (BYTE)(dwDepthMask & 0xFF); Bytes[1] = (BYTE)((dwDepthMask & 0xFF00) >> 8); Bytes[2] = (BYTE)((dwDepthMask & 0xFF0000) >> 16); Bytes[3] = (BYTE)((dwDepthMask & 0xFF000000) >> 24); if (((Bytes[0] != 0) && (Bytes[0] != 0xFF)) || ((Bytes[1] != 0) && (Bytes[1] != 0xFF)) || ((Bytes[2] != 0) && (Bytes[2] != 0xFF)) || ((Bytes[3] != 0) && (Bytes[3] != 0xFF))) { bNoBlockFillZ = TRUE; } } DISPDBG((DBGLVL,"ZClear Value = 0x%x, ZClear Mask = 0x%x", dwDepthValue, dwDepthMask)); } // if (lpcd2->dwFlags & D3DCLEAR_ZBUFFER) // Prepare any data necessary to clear the stencil buffer if ((lpcd2->dwFlags & D3DCLEAR_STENCIL) && (pContext->pSurfZBufferInt != NULL)) { int dwShiftCount = 0; DDPIXELFORMAT* pPixFormat = &pContext->pSurfZBufferInt->pixFmt; // Find out where to shift the dwStencilMask = pPixFormat->dwStencilBitMask; if (dwStencilMask != 0) { while ((dwStencilMask & 0x1) == 0) { dwStencilMask >>= 1; dwShiftCount++; } dwStencilValue = (lpcd2->dwFillStencil << dwShiftCount); dwStencilMask = pPixFormat->dwStencilBitMask; // As we are fast-block filling, make sure we copy the // Mask to the top bits. switch (pContext->pSurfZBufferInt->dwPixelSize) { case __GLINT_16BITPIXEL: dwStencilMask &= 0xFFFF; dwStencilMask |= (dwStencilMask << 16); break; case __GLINT_8BITPIXEL: dwStencilMask &= 0xFF; dwStencilMask |= dwStencilMask << 8; dwStencilMask |= dwStencilMask << 16; break; } DISPDBG((DBGLVL,"Stencil Clear Value = 0x%x, Stencil Mask = 0x%x", dwStencilValue, dwStencilMask)); } else { DISPDBG((ERRLVL,"ERROR: Stencil mask is not valid!")); dwStencilValue = 0; dwStencilMask = 0; } if (pThisDisplay->pGLInfo->bDRAMBoard) { // Check for a DRAM fill that the chip isn't emulating. Bytes[0] = (BYTE)(dwStencilMask & 0xFF); Bytes[1] = (BYTE)((dwStencilMask & 0xFF00) >> 8); Bytes[2] = (BYTE)((dwStencilMask & 0xFF0000) >> 16); Bytes[3] = (BYTE)((dwStencilMask & 0xFF000000) >> 24); if (((Bytes[0] != 0) && (Bytes[0] != 0xFF)) || ((Bytes[1] != 0) && (Bytes[1] != 0xFF)) || ((Bytes[2] != 0) && (Bytes[2] != 0xFF)) || ((Bytes[3] != 0) && (Bytes[3] != 0xFF))) { bNoBlockFillStencil = TRUE; } } } // if (lpcd2->dwFlags & D3DCLEAR_STENCIL) // Loop through each clearing rect and perform the clearing hw operations i = dwNumRects; while (i-- > 0) { if (bComputeIntersections) { // Compute intersection between the viewport and the incoming // RECTLs. If no intersection exists skip into next one. if (!__OP_IntersectRectl(&rect, &rect_vwport, &lpcd2->Rects[i])) { // No intersection, so skip it goto Next_Rectl_To_Clear; } } else { // We already have the rects we need to clear, so // just use them in reverse order rect.left = lpcd2->Rects[i].left; rect.right = lpcd2->Rects[i].right; rect.top = lpcd2->Rects[i].top; rect.bottom = lpcd2->Rects[i].bottom; } // Clear the frame buffer if ((lpcd2->dwFlags & D3DCLEAR_TARGET) && (pContext->pSurfRenderInt != NULL)) { P3RX_UPDATE_WRITE_MASK(__GLINT_ALL_WRITEMASKS_SET); #if DX8_MULTISAMPLING || DX7_ANTIALIAS if (pContext->Flags & SURFACE_ANTIALIAS) { RECTL Temp = rect; Temp.left *= 2; Temp.right *= 2; Temp.top *= 2; Temp.bottom *= 2; _DD_BLT_P3Clear_AA(pThisDisplay, &Temp, pContext->dwAliasBackBuffer - pThisDisplay->dwScreenFlatAddr, color, FALSE, pContext->pSurfRenderInt->dwPatchMode, pContext->pSurfRenderInt->dwPixelPitch, pContext->pSurfRenderInt->pixFmt.dwRGBBitCount, pContext->pSurfRenderInt->ddsCapsInt); } else #endif // DX8_MULTISAMPLING || DX7_ANTIALIAS { _DD_BLT_P3Clear(pThisDisplay, &rect, color, FALSE, FALSE, pContext->pSurfRenderInt->fpVidMem, pContext->pSurfRenderInt->dwPatchMode, pContext->pSurfRenderInt->dwPixelPitch, pContext->pSurfRenderInt->pixFmt.dwRGBBitCount); } } // Clear the z buffer if ((lpcd2->dwFlags & D3DCLEAR_ZBUFFER) && (pContext->pSurfZBufferInt != NULL) ) { P3RX_UPDATE_WRITE_MASK(dwDepthMask); if (bNoBlockFillZ) { P3_DMA_GET_BUFFER_ENTRIES(4); SEND_P3_DATA(FBSoftwareWriteMask, dwDepthMask); SEND_P3_DATA(FBDestReadMode, P3RX_FBDESTREAD_READENABLE(__PERMEDIA_ENABLE) | P3RX_FBDESTREAD_ENABLE0(__PERMEDIA_ENABLE)); P3_DMA_COMMIT_BUFFER(); } #if DX8_MULTISAMPLING || DX7_ANTIALIAS if (pContext->Flags & SURFACE_ANTIALIAS) { RECTL Temp = rect; Temp.left *= 2; Temp.right *= 2; Temp.top *= 2; Temp.bottom *= 2; _DD_BLT_P3Clear_AA(pThisDisplay, &Temp, pContext->dwAliasZBuffer - pThisDisplay->dwScreenFlatAddr, dwDepthValue, bNoBlockFillZ, pContext->pSurfZBufferInt->dwPatchMode, pContext->pSurfZBufferInt->dwPixelPitch, pContext->pSurfZBufferInt->pixFmt.dwRGBBitCount, pContext->pSurfZBufferInt->ddsCapsInt); } else #endif // DX8_MULTISAMPLING || DX7_ANTIALIAS { _DD_BLT_P3Clear(pThisDisplay, &rect, dwDepthValue, bNoBlockFillZ, TRUE, pContext->pSurfZBufferInt->fpVidMem, pContext->pSurfZBufferInt->dwPatchMode, pContext->pSurfZBufferInt->dwPixelPitch, pContext->pSurfZBufferInt->pixFmt.dwRGBBitCount ); } if (bNoBlockFillZ) { P3_DMA_GET_BUFFER_ENTRIES(4); SEND_P3_DATA(FBSoftwareWriteMask, __GLINT_ALL_WRITEMASKS_SET); SEND_P3_DATA(FBDestReadMode, __PERMEDIA_DISABLE); P3_DMA_COMMIT_BUFFER(); } } // Clear the stencil buffer if ((lpcd2->dwFlags & D3DCLEAR_STENCIL) && (pContext->pSurfZBufferInt != NULL) ) { P3RX_UPDATE_WRITE_MASK(dwStencilMask); if (bNoBlockFillStencil) { P3_DMA_GET_BUFFER_ENTRIES(4); SEND_P3_DATA(FBSoftwareWriteMask, dwStencilMask); SEND_P3_DATA(FBDestReadMode, P3RX_FBDESTREAD_READENABLE(__PERMEDIA_ENABLE) | P3RX_FBDESTREAD_ENABLE0(__PERMEDIA_ENABLE)); P3_DMA_COMMIT_BUFFER(); } #if DX8_MULTISAMPLING || DX7_ANTIALIAS if (pContext->Flags & SURFACE_ANTIALIAS) { RECTL Temp = rect; Temp.left *= 2; Temp.right *= 2; Temp.top *= 2; Temp.bottom *= 2; _DD_BLT_P3Clear_AA(pThisDisplay, &Temp, pContext->dwAliasZBuffer - pThisDisplay->dwScreenFlatAddr, dwStencilValue, bNoBlockFillStencil, pContext->pSurfZBufferInt->dwPatchMode, pContext->pSurfZBufferInt->dwPixelPitch, pContext->pSurfZBufferInt->pixFmt.dwRGBBitCount, pContext->pSurfZBufferInt->ddsCapsInt ); } else #endif // DX8_MULTISAMPLING || DX7_ANTIALIAS { _DD_BLT_P3Clear(pThisDisplay, &rect, dwStencilValue, bNoBlockFillStencil, TRUE, pContext->pSurfZBufferInt->fpVidMem, pContext->pSurfZBufferInt->dwPatchMode, pContext->pSurfZBufferInt->dwPixelPitch, pContext->pSurfZBufferInt->pixFmt.dwRGBBitCount ); } if (bNoBlockFillStencil) { P3_DMA_GET_BUFFER_ENTRIES(4); SEND_P3_DATA(FBSoftwareWriteMask, __GLINT_ALL_WRITEMASKS_SET); SEND_P3_DATA(FBDestReadMode, __PERMEDIA_DISABLE); P3_DMA_COMMIT_BUFFER(); } } Next_Rectl_To_Clear: ; } // while // Make sure the WriteMask is reset to it's default value { P3_DMA_GET_BUFFER_ENTRIES(4); SEND_P3_DATA(FBHardwareWriteMask, __GLINT_ALL_WRITEMASKS_SET); SEND_P3_DATA(FBDestReadMode, __PERMEDIA_DISABLE); P3_DMA_COMMIT_BUFFER(); } DBG_CB_EXIT(_D3D_OP_Clear2, DD_OK); return; } // _D3D_OP_Clear2 //----------------------------------------------------------------------------- // // _D3D_OP_TextureBlt // // This function processes the D3DDP2OP_TEXBLT DP2 command token. // //----------------------------------------------------------------------------- VOID _D3D_OP_TextureBlt(P3_D3DCONTEXT* pContext, P3_THUNKEDDATA*pThisDisplay, D3DHAL_DP2TEXBLT* pBlt) { LPDDRAWI_DDRAWSURFACE_LCL pSrcLcl; LPDDRAWI_DDRAWSURFACE_LCL pDestLcl; P3_SURF_INTERNAL* pSrcTexture; P3_SURF_INTERNAL* pDestTexture; P3_SURF_FORMAT* pFormatSource; P3_SURF_FORMAT* pFormatDest; MIPTEXTURE *pSrcMipLevel, *pDstMipLevel; RECTL rSrc, rDest; int iMaxLogWidth, iCurrLogWidth; int iSrcLOD, iDestLOD, iCurrSrcLOD, iCurrDstLOD; BOOL bMipMap, bMipMapLevelsMatch; DISPDBG((DBGLVL, "TextureBlt Source %d Dest %d", pBlt->dwDDSrcSurface, pBlt->dwDDDestSurface)); if (0 == pBlt->dwDDSrcSurface) { DISPDBG((ERRLVL,"Invalid handle TexBlt from %08lx to %08lx", pBlt->dwDDSrcSurface,pBlt->dwDDDestSurface)); return; } // Get the source texture structure pointer pSrcTexture = GetSurfaceFromHandle(pContext, pBlt->dwDDSrcSurface); // Check that the source texture is valid if (pSrcTexture == NULL) { DISPDBG((ERRLVL, "ERROR: Source texture %d is invalid!", pBlt->dwDDSrcSurface)); return; } // Validate the destination texture handle if (0 == pBlt->dwDDDestSurface) { #if DX7_TEXMANAGEMENT // If we do texture management then a destination handle of 0 // has the special meaning of preloading the source texture. if (!_D3D_TM_Preload_Tex_IntoVidMem(pContext, pSrcTexture)) { DISPDBG((ERRLVL,"_D3D_OP_TextureBlt unable to " "preload texture")); } return; #else // If there's no driver texture managament support we can't go // on if the destination handle is 0 DISPDBG((ERRLVL,"Invalid handle TexBlt from %08lx to %08lx", pBlt->dwDDSrcSurface,pBlt->dwDDDestSurface)); return; #endif } // Get the destination texture structure pointer for regular TexBlts pDestTexture = GetSurfaceFromHandle(pContext, pBlt->dwDDDestSurface); // Check that the destination texture is valid if (pDestTexture == NULL) { DISPDBG((ERRLVL, "ERROR: Dest texture %d is invalid!", pBlt->dwDDDestSurface)); return; } // Make sure the textures are of the same proportion if ((pSrcTexture->wWidth * pDestTexture->wHeight) != (pSrcTexture->wHeight * pDestTexture->wWidth)) { DISPDBG((ERRLVL, "ERROR: TEXBLT the src and dest textures are not of the same proportion")); return; } // It is possible that the source and destination textures may contain // different number of mipmap levels. In this case, the driver is // expected to BitBlt the common levels. For example, if a 256x256 source // texture has 8 mipmap levels, and if the destination is a 64x64 texture // with 6 levels, then the driver should BitBlt the 6 corresponding levels // from the source. The driver can expect the dimensions of the top mip // level of destination texture to be always equal to or lesser than the // dimensions of the top mip level of the source texture. // It might also be the case that only one of the textures is mipmapped // Since we keep all relevant info also in the MipLevels substructre for // the surface, we can treat both surfaces as mipmapped even if only // one of them was created as such and proceed with the TexBlt. if (pSrcTexture->bMipMap || pDestTexture->bMipMap) { bMipMap = TRUE; iMaxLogWidth = max(pSrcTexture->logWidth, pDestTexture->logWidth); iCurrLogWidth = iMaxLogWidth; iSrcLOD = 0; // start LOD for src iDestLOD = 0; // start LOD for dest } else { // just one level bMipMap = FALSE; // No mipmapping cases to be handled iMaxLogWidth = iCurrLogWidth = iSrcLOD = iDestLOD = 0; } // Init the rects from and into which we will blt . This is top level // mipmap or non-mipmap texture, just use rect from Blt. rSrc = pBlt->rSrc; // Create a destination rectangle for compatibility // with the DD blitting function we are calling. rDest.left = pBlt->pDest.x; rDest.top = pBlt->pDest.y; rDest.right = (pBlt->rSrc.right - pBlt->rSrc.left) + rDest.left; rDest.bottom = (pBlt->rSrc.bottom - pBlt->rSrc.top) + rDest.top; // Traverse all the mip map levels and try to match them for a blt to be // done. If no mipmaps are present just do for the "first" and only // levels present. do { DISPDBG((DBGLVL,"TEXBLT iteration %d %d %d %d", iMaxLogWidth,iCurrLogWidth,iSrcLOD,iDestLOD)); // Get the local surface pointers and make sure the level sizes // match in the case of mip map Texblts. if (bMipMap) { bMipMapLevelsMatch = FALSE; // Verify you only look at valid mipmap levels - they might // be incomplete (and we want not to AV or access garbage!) // for example, a source 256x256 texture may contain 5 levels, // but the destination 256x256 texture may contain 8. The // driver is expected to safely handle this case, but it is // not expected to produce correct results if ((iSrcLOD < pSrcTexture->iMipLevels) && (iDestLOD < pDestTexture->iMipLevels)) { DISPDBG((DBGLVL,"Checking match! %d vs. %d", pSrcTexture->MipLevels[iSrcLOD].logWidth, pDestTexture->MipLevels[iDestLOD].logWidth)); // Do we currently have two levels that match in size ? bMipMapLevelsMatch = ( pSrcTexture->MipLevels[iSrcLOD].logWidth == pDestTexture->MipLevels[iDestLOD].logWidth); } // Record which levels are we currently blitting iCurrSrcLOD = iSrcLOD; iCurrDstLOD = iDestLOD; // Get ready for next loop by updating the LODs to use // increment LOD# if we are currently looking at a level // equal or smaller to mip maps level 0 size if (iCurrLogWidth <= pSrcTexture->logWidth) { iSrcLOD++; } if (iCurrLogWidth <= pDestTexture->logWidth) { iDestLOD++; } // Decrease the width into next smaller level iCurrLogWidth--; } else { // Single level blt - we set bMipMapLevelsMatch in order to blt it! bMipMapLevelsMatch = TRUE; iCurrSrcLOD = 0; iCurrDstLOD = 0; } if (bMipMapLevelsMatch) { // Switch to the DirectDraw context DDRAW_OPERATION(pContext, pThisDisplay); DISPDBG((DBGLVL,"Blitting level %d into level %d", iCurrSrcLOD, iCurrDstLOD)); pSrcMipLevel = &pSrcTexture->MipLevels[iCurrSrcLOD]; pDstMipLevel = &pDestTexture->MipLevels[iCurrDstLOD]; /////////////////////////////////////////////////////////////////// // Here we handle all possible blt cases between different types // of memory and different scenarios of managed/unmanaged surfaces /////////////////////////////////////////////////////////////////// #if DX7_TEXMANAGEMENT if ((0 == (pDestTexture->dwCaps2 & DDSCAPS2_TEXTUREMANAGE)) && (0 == (pSrcTexture->dwCaps2 & DDSCAPS2_TEXTUREMANAGE)) ) #endif // DX7_TEXMANAGEMENT { //---------------------------------- //---------------------------------- // TEXBLT among non-managed textures //---------------------------------- //---------------------------------- if ((pSrcTexture->Location == SystemMemory) && (pDestTexture->Location == VideoMemory)) { //---------------------------- // Do the system->videomem blt //---------------------------- _DD_P3Download(pThisDisplay, pSrcMipLevel->fpVidMem, pDstMipLevel->fpVidMem, pSrcTexture->dwPatchMode, pDestTexture->dwPatchMode, pSrcMipLevel->lPitch, pDstMipLevel->lPitch, pDstMipLevel->P3RXTextureMapWidth.Width, pDestTexture->dwPixelSize, &rSrc, &rDest); } else if ((pSrcTexture->Location == VideoMemory) && (pDestTexture->Location == VideoMemory)) { //------------------------------ // Do the videomem->videomem blt //------------------------------ _DD_BLT_P3CopyBlt(pThisDisplay, pSrcMipLevel->fpVidMem, pDstMipLevel->fpVidMem, pSrcTexture->dwPatchMode, pDestTexture->dwPatchMode, pSrcMipLevel->P3RXTextureMapWidth.Width, pDstMipLevel->P3RXTextureMapWidth.Width, pSrcMipLevel->dwOffsetFromMemoryBase, pDstMipLevel->dwOffsetFromMemoryBase, pDestTexture->dwPixelSize, &rSrc, &rDest); } else if ((pSrcTexture->Location == AGPMemory) && (pDestTexture->Location == VideoMemory)) { //------------------------------- // Do the AGP mem -> videomem blt //------------------------------- DDCOLORKEY ddck_dummy = { 0 , 0 }; // We use the strecth blt because it handles AGP source // surfaces, not becuase we should stretch the surface in any way _DD_P3BltStretchSrcChDstCh( pThisDisplay, // src data pSrcMipLevel->fpVidMem, pSrcTexture->pFormatSurface, pSrcTexture->dwPixelSize, pSrcMipLevel->wWidth, pSrcMipLevel->wHeight, pSrcMipLevel->P3RXTextureMapWidth.Width, pSrcMipLevel->P3RXTextureMapWidth.Layout, pSrcMipLevel->dwOffsetFromMemoryBase, pSrcTexture->dwFlagsInt, &pSrcTexture->pixFmt, 1, // src IS AGP, otherwise we //would'nt call this // dest data pDstMipLevel->fpVidMem, pDestTexture->pFormatSurface, pDestTexture->dwPixelSize, pDstMipLevel->wWidth, pDstMipLevel->wHeight, pDstMipLevel->P3RXTextureMapWidth.Width, pDstMipLevel->P3RXTextureMapWidth.Layout, pDstMipLevel->dwOffsetFromMemoryBase, 0, // dwBltFlags no special blt effects 0, // dwBltDDFX no special effects info ddck_dummy, // BltSrcColorKey dummy arg ddck_dummy, // BltDestColorKey dummy arg &rSrc, &rDest ); } else { DISPDBG((ERRLVL,"Non-managed Tex Blt variation unimplemented! " "(from %d into %d)", pSrcTexture->Location, pDestTexture->Location)); } } #if DX7_TEXMANAGEMENT else if (pSrcTexture->dwCaps2 & DDSCAPS2_TEXTUREMANAGE) { //---------------------------------- //---------------------------------- // TEXBLT from a managed texture //---------------------------------- //---------------------------------- if ((pDestTexture->Location == SystemMemory) || (pDestTexture->dwCaps2 & DDSCAPS2_TEXTUREMANAGE)) { //------------------------------------------------- // Do the Managed surf -> sysmem | managed surf blt //------------------------------------------------- // make sure we'll reload the vidmem copy of the dest surf if (pDestTexture->dwCaps2 & DDSCAPS2_TEXTUREMANAGE) { __OP_MarkManagedSurfDirty(pContext, pBlt->dwDDDestSurface, pDestTexture); } _DD_BLT_SysMemToSysMemCopy( pSrcMipLevel->fpVidMem, pSrcMipLevel->lPitch, pSrcTexture->dwBitDepth, pDstMipLevel->fpVidMem, pDstMipLevel->lPitch, pDestTexture->dwBitDepth, &rSrc, &rDest); } else if (pDestTexture->Location == VideoMemory) { //------------------------------------------------- // 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, pSrcMipLevel->fpVidMem, pDstMipLevel->fpVidMem, pSrcTexture->dwPatchMode, pDestTexture->dwPatchMode, pSrcMipLevel->lPitch, pDstMipLevel->lPitch, pDstMipLevel->P3RXTextureMapWidth.Width, pDestTexture->dwPixelSize, &rSrc, &rDest); } else { DISPDBG((ERRLVL,"Src-managed Tex Blt variation unimplemented! " "(from %d into %d)", pSrcTexture->Location, pDestTexture->Location)); } } else if (pDestTexture->dwCaps2 & DDSCAPS2_TEXTUREMANAGE) { //-------------------------------------------------------------- //-------------------------------------------------------------- // TEXBLT into a managed texture (except from a managed texture) //-------------------------------------------------------------- //-------------------------------------------------------------- // managed->managed is handled in the previous case if (pSrcTexture->Location == SystemMemory) { //------------------------------------------------- // Do the sysmem surf -> managed surf blt //------------------------------------------------- // make sure we'll reload the vidmem copy of the dest surf __OP_MarkManagedSurfDirty(pContext, pBlt->dwDDDestSurface, pDestTexture); _DD_BLT_SysMemToSysMemCopy( pSrcMipLevel->fpVidMem, pSrcMipLevel->lPitch, pSrcTexture->dwBitDepth, pDstMipLevel->fpVidMem, pDstMipLevel->lPitch, pDestTexture->dwBitDepth, &rSrc, &rDest); } else if (pSrcTexture->Location == VideoMemory) { //------------------------------------------------- // Do the vidmem surf -> Managed surf blt //------------------------------------------------- if (0 != pSrcMipLevel->fpVidMemTM) { // Destination is already in vidmem so instead of // "dirtying" the managed texture lets do the // vidmem->vidmem blt which is faster than doing the // update later (in the hope we'll really use it) _DD_BLT_P3CopyBlt(pThisDisplay, pSrcMipLevel->fpVidMem, pDstMipLevel->fpVidMemTM, pSrcTexture->dwPatchMode, pDestTexture->dwPatchMode, pSrcMipLevel->P3RXTextureMapWidth.Width, pDstMipLevel->P3RXTextureMapWidth.Width, pSrcMipLevel->dwOffsetFromMemoryBase, pDstMipLevel->dwOffsetFromMemoryBase, pDestTexture->dwPixelSize, &rSrc, &rDest); } else { // make sure we'll reload the // vidmem copy of the dest surf __OP_MarkManagedSurfDirty(pContext, pBlt->dwDDDestSurface, pDestTexture); } // 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( D3DMIPLVL_GETPOINTER(pSrcMipLevel, pThisDisplay), pSrcMipLevel->lPitch, pSrcTexture->dwBitDepth, pDstMipLevel->fpVidMem, pDstMipLevel->lPitch, pDestTexture->dwBitDepth, &rSrc, &rDest); } else if (pSrcTexture->Location == AGPMemory) { // make sure we'll reload the vidmem copy of the dest surf __OP_MarkManagedSurfDirty(pContext, pBlt->dwDDDestSurface, pDestTexture); _DD_BLT_SysMemToSysMemCopy( pSrcMipLevel->fpVidMem, pSrcMipLevel->lPitch, pSrcTexture->dwBitDepth, pDstMipLevel->fpVidMem, pDstMipLevel->lPitch, pDestTexture->dwBitDepth, &rSrc, &rDest); } else { DISPDBG((ERRLVL,"Dest-managed Tex Blt variation unimplemented! " "(from %d into %d)", pSrcTexture->Location, pDestTexture->Location)); } } else { DISPDBG((ERRLVL,"Tex Blt variation unimplemented! " "(from %d into %d)", pSrcTexture->Location, pDestTexture->Location)); } #endif // DX7_TEXMANAGEMENT // Switch back to the Direct3D context D3D_OPERATION(pContext, pThisDisplay); } // if (bMipMapLevelsMatch) // Update transfer rectangles if mip mapping if (bMipMap) { DWORD right, bottom; // Update source rectangle , the regions to be copied in mipmap // sub-levels can be obtained by dividing rSrc and pDest by // 2 at each level. rSrc.left >>= 1; rSrc.top >>= 1; right = (rSrc.right + 1) >> 1; bottom = (rSrc.bottom + 1) >> 1; rSrc.right = ((right - rSrc.left) < 1) ? (rSrc.left + 1) : (right); rSrc.bottom = ((bottom - rSrc.top ) < 1) ? (rSrc.top + 1) : (bottom); // Update destination rectangle rDest.left >>= 1; rDest.top >>= 1; right = (rDest.right + 1) >> 1; bottom = (rDest.bottom + 1) >> 1; rDest.right = ((right - rDest.left) < 1) ? (rDest.left + 1) : (right); rDest.bottom = ((bottom - rDest.top ) < 1) ? (rDest.top + 1) : (bottom); } } while (bMipMap && ((iSrcLOD < pSrcTexture->iMipLevels) && (iDestLOD < pDestTexture->iMipLevels))); // do until we're done looking at 1x1 } // _D3D_OP_TextureBlt //----------------------------------------------------------------------------- // // _D3D_OP_SetRenderTarget // // Sets up the hw for the chosen render target and depth buffer // //----------------------------------------------------------------------------- HRESULT _D3D_OP_SetRenderTarget( P3_D3DCONTEXT* pContext, P3_SURF_INTERNAL* pRenderInt, P3_SURF_INTERNAL* pZBufferInt, BOOL bNewAliasBuffers) { P3_SOFTWARECOPY* pSoftP3RX = &pContext->SoftCopyGlint; P3_THUNKEDDATA *pThisDisplay = pContext->pThisDisplay; DWORD AAMultiplier = 1; P3_DMA_DEFS(); DBG_ENTRY(_D3D_OP_SetRenderTarget); // Verify the render target is in video memory if (pRenderInt) { if (pRenderInt->ddsCapsInt.dwCaps & DDSCAPS_SYSTEMMEMORY) { DISPDBG((ERRLVL, "ERROR: Render Surface in SYSTEM MEMORY")); return DDERR_GENERIC; } } else { // Must have a render target DISPDBG((ERRLVL, "ERROR: Render Surface is NULL")); return DDERR_GENERIC; } // If a Z Buffer verify it if (pZBufferInt) { if (pZBufferInt->ddsCapsInt.dwCaps & DDSCAPS_SYSTEMMEMORY) { DISPDBG((ERRLVL, "ERROR: Z Surface in SYSTEM MEMORY, failing")); return DDERR_GENERIC; } } // Validate the RenderTarget to be 32 bit or 16 bit 565 if ((pRenderInt->pixFmt.dwRGBBitCount == 32 ) && (pRenderInt->pixFmt.dwRBitMask == 0x00FF0000) && (pRenderInt->pixFmt.dwGBitMask == 0x0000FF00) && (pRenderInt->pixFmt.dwBBitMask == 0x000000FF)) { // were OK at 32bpp } else if ((pRenderInt->pixFmt.dwRGBBitCount == 16 ) && (pRenderInt->pixFmt.dwRBitMask == 0xF800) && (pRenderInt->pixFmt.dwGBitMask == 0x07E0) && (pRenderInt->pixFmt.dwBBitMask == 0x001F)) { // were OK at 16bpp } else { // we cant set our render target to this format !!! DISPDBG((WRNLVL, " SRT Error !!!")); DISPDBG((WRNLVL, " dwRGBBitCount: 0x%x", pRenderInt->pixFmt.dwRGBBitCount)); DISPDBG((WRNLVL, " dwR/Y BitMask: 0x%x", pRenderInt->pixFmt.dwRBitMask)); DISPDBG((WRNLVL, " dwG/U BitMask: 0x%x", pRenderInt->pixFmt.dwGBitMask)); DISPDBG((WRNLVL, " dwB/V BitMask: 0x%x", pRenderInt->pixFmt.dwBBitMask)); DISPDBG((WRNLVL, " dwRGBAlphaBitMask: 0x%x", pRenderInt->pixFmt.dwRGBAlphaBitMask)); return DDERR_GENERIC; } #if DX8_MULTISAMPLING // Decide whether antialising is requested and can be handled if ((pContext->pSurfRenderInt->dwSampling) && (! _D3D_ST_CanRenderAntialiased(pContext, bNewAliasBuffers))) { return DDERR_OUTOFMEMORY; } #endif // DX8_MULTISAMPLING // If we page flipped, clear the flag pThisDisplay->bFlippedSurface = FALSE; P3_DMA_GET_BUFFER(); P3_ENSURE_DX_SPACE(46); WAIT_FIFO(26); pContext->pSurfRenderInt = pRenderInt; pContext->pSurfZBufferInt = pZBufferInt; // Check for Z Buffer if (pZBufferInt) { DDPIXELFORMAT* pZFormat = &pZBufferInt->pixFmt; if( pThisDisplay->dwDXVersion >= DX6_RUNTIME) { // On DX6 we look in the pixel format for the depth and stencil info. switch(pZFormat->dwZBufferBitDepth) { default: DISPDBG((ERRLVL,"ERROR: Unknown Z Pixel format!")); // Regard the buffer as 16 bit one and fall through case 16: if (pZFormat->dwStencilBitDepth == 1) { // 15 bit Z, 1 bit stencil pSoftP3RX->P3RXLBReadFormat.StencilPosition = 0; // Ignored in this mode pSoftP3RX->P3RXLBReadFormat.StencilWidth = P3RX_STENCIL_WIDTH_1; pSoftP3RX->P3RXLBReadFormat.DepthWidth = P3RX_DEPTH_WIDTH_15; pSoftP3RX->P3RXStencilMode.StencilWidth = P3RX_STENCIL_WIDTH_1; pSoftP3RX->P3RXLBWriteFormat.StencilPosition = 0; // Ignored in this mode pSoftP3RX->P3RXLBWriteFormat.StencilWidth = P3RX_STENCIL_WIDTH_1; pSoftP3RX->P3RXLBWriteFormat.DepthWidth = P3RX_DEPTH_WIDTH_15; pSoftP3RX->P3RXDepthMode.Width = P3RX_DEPTH_WIDTH_15; pSoftP3RX->P3RXLBSourceReadMode.Packed16 = 1; pSoftP3RX->P3RXLBDestReadMode.Packed16 = 1; pSoftP3RX->P3RXLBWriteMode.Packed16 = 1; pSoftP3RX->P3RXLBWriteMode.ByteEnables = 0x3; } else { // 16 bit Z, no stencil pSoftP3RX->P3RXLBReadFormat.StencilPosition = 0; // Ignored in this mode pSoftP3RX->P3RXLBReadFormat.StencilWidth = P3RX_STENCIL_WIDTH_0; pSoftP3RX->P3RXStencilMode.StencilWidth = P3RX_STENCIL_WIDTH_0; pSoftP3RX->P3RXLBReadFormat.DepthWidth = P3RX_DEPTH_WIDTH_16; pSoftP3RX->P3RXLBWriteFormat.StencilPosition = 0; // Ignored in this mode pSoftP3RX->P3RXLBWriteFormat.StencilWidth = P3RX_STENCIL_WIDTH_0; pSoftP3RX->P3RXLBWriteFormat.DepthWidth = P3RX_DEPTH_WIDTH_16; pSoftP3RX->P3RXDepthMode.Width = P3RX_DEPTH_WIDTH_16; pSoftP3RX->P3RXLBWriteMode.ByteEnables = 0x3; pSoftP3RX->P3RXLBSourceReadMode.Packed16 = 1; pSoftP3RX->P3RXLBDestReadMode.Packed16 = 1; pSoftP3RX->P3RXLBWriteMode.Packed16 = 1; } break; case 32: if (pZFormat->dwStencilBitDepth == 8) { // 24 bit Z, 8 bit stencil pSoftP3RX->P3RXLBReadFormat.StencilPosition = P3RX_STENCIL_POSITION_24; pSoftP3RX->P3RXLBReadFormat.StencilWidth = P3RX_STENCIL_WIDTH_8; pSoftP3RX->P3RXStencilMode.StencilWidth = P3RX_STENCIL_WIDTH_8; pSoftP3RX->P3RXLBReadFormat.DepthWidth = P3RX_DEPTH_WIDTH_24; pSoftP3RX->P3RXLBWriteFormat.StencilPosition = P3RX_STENCIL_POSITION_24; pSoftP3RX->P3RXLBWriteFormat.StencilWidth = P3RX_STENCIL_WIDTH_8; pSoftP3RX->P3RXLBWriteFormat.DepthWidth = P3RX_DEPTH_WIDTH_24; pSoftP3RX->P3RXDepthMode.Width = P3RX_DEPTH_WIDTH_24; pSoftP3RX->P3RXLBWriteMode.ByteEnables = 0xF; pSoftP3RX->P3RXLBSourceReadMode.Packed16 = 0; pSoftP3RX->P3RXLBDestReadMode.Packed16 = 0; pSoftP3RX->P3RXLBWriteMode.Packed16 = 0; } else { // 32 bit Z, no stencil pSoftP3RX->P3RXLBReadFormat.StencilPosition = 0; pSoftP3RX->P3RXLBReadFormat.StencilWidth = P3RX_STENCIL_WIDTH_0; pSoftP3RX->P3RXStencilMode.StencilWidth = P3RX_STENCIL_WIDTH_0; pSoftP3RX->P3RXLBReadFormat.DepthWidth = P3RX_DEPTH_WIDTH_32; pSoftP3RX->P3RXLBWriteFormat.StencilPosition = 0; pSoftP3RX->P3RXLBWriteFormat.StencilWidth = P3RX_STENCIL_WIDTH_0; pSoftP3RX->P3RXLBWriteFormat.DepthWidth = P3RX_DEPTH_WIDTH_32; pSoftP3RX->P3RXDepthMode.Width = P3RX_DEPTH_WIDTH_32; pSoftP3RX->P3RXLBWriteMode.ByteEnables = 0xF; pSoftP3RX->P3RXLBSourceReadMode.Packed16 = 0; pSoftP3RX->P3RXLBDestReadMode.Packed16 = 0; pSoftP3RX->P3RXLBWriteMode.Packed16 = 0; } break; } } else // On DX5 we don't look at the pixel format, just the depth of the Z Buffer. { // Choose the correct Z Buffer depth switch(pZBufferInt->pixFmt.dwRGBBitCount) { default: DISPDBG((ERRLVL,"ERROR: Unknown depth format in _D3D_OP_SetRenderTarget!")); // Regard the buffer as 16 bit one and fall through case 16: pSoftP3RX->P3RXLBReadFormat.DepthWidth = __GLINT_DEPTH_WIDTH_16; pSoftP3RX->P3RXLBWriteFormat.DepthWidth = __GLINT_DEPTH_WIDTH_16; pSoftP3RX->P3RXDepthMode.Width = __GLINT_DEPTH_WIDTH_16; pSoftP3RX->P3RXLBWriteMode.ByteEnables = 0x3; pSoftP3RX->P3RXLBSourceReadMode.Packed16 = 1; pSoftP3RX->P3RXLBDestReadMode.Packed16 = 1; pSoftP3RX->P3RXLBWriteMode.Packed16 = 1; break; case 24: pSoftP3RX->P3RXLBReadFormat.DepthWidth = __GLINT_DEPTH_WIDTH_24; pSoftP3RX->P3RXLBWriteFormat.DepthWidth = __GLINT_DEPTH_WIDTH_24; pSoftP3RX->P3RXDepthMode.Width = __GLINT_DEPTH_WIDTH_24; pSoftP3RX->P3RXLBWriteMode.ByteEnables = 0x7; pSoftP3RX->P3RXLBSourceReadMode.Packed16 = 0; pSoftP3RX->P3RXLBDestReadMode.Packed16 = 0; pSoftP3RX->P3RXLBWriteMode.Packed16 = 0; break; case 32: pSoftP3RX->P3RXLBReadFormat.DepthWidth = __GLINT_DEPTH_WIDTH_32; pSoftP3RX->P3RXLBWriteFormat.DepthWidth = __GLINT_DEPTH_WIDTH_32; pSoftP3RX->P3RXDepthMode.Width = __GLINT_DEPTH_WIDTH_32; pSoftP3RX->P3RXLBWriteMode.ByteEnables = 0xF; pSoftP3RX->P3RXLBSourceReadMode.Packed16 = 0; pSoftP3RX->P3RXLBDestReadMode.Packed16 = 0; pSoftP3RX->P3RXLBWriteMode.Packed16 = 0; break; } } pSoftP3RX->P3RXLBSourceReadMode.Layout = pZBufferInt->dwPatchMode; pSoftP3RX->P3RXLBDestReadMode.Layout = pZBufferInt->dwPatchMode; pSoftP3RX->P3RXLBWriteMode.Layout = pZBufferInt->dwPatchMode; } // if (pZBufferInt) switch (pRenderInt->dwPixelSize) { case __GLINT_8BITPIXEL: // 8 Bit color index mode pSoftP3RX->DitherMode.ColorFormat = pSoftP3RX->P3RXAlphaBlendColorMode.ColorFormat = P3RX_ALPHABLENDMODE_COLORFORMAT_CI; SEND_P3_DATA(PixelSize, 2 - __GLINT_8BITPIXEL); break; case __GLINT_16BITPIXEL: if (pThisDisplay->ddpfDisplay.dwRBitMask == 0x7C00) { // 5551 format pSoftP3RX->DitherMode.ColorFormat = P3RX_DITHERMODE_COLORFORMAT_5551; pSoftP3RX->P3RXAlphaBlendColorMode.ColorFormat = P3RX_ALPHABLENDMODE_COLORFORMAT_5551; } else { // 565 format pSoftP3RX->DitherMode.ColorFormat = P3RX_DITHERMODE_COLORFORMAT_565; pSoftP3RX->P3RXAlphaBlendColorMode.ColorFormat = P3RX_ALPHABLENDMODE_COLORFORMAT_565; } SEND_P3_DATA(PixelSize, 2 - __GLINT_16BITPIXEL); break; case __GLINT_24BITPIXEL: case __GLINT_32BITPIXEL: // 32 Bit Color Index mode pSoftP3RX->DitherMode.ColorFormat = pSoftP3RX->P3RXAlphaBlendColorMode.ColorFormat = P3RX_ALPHABLENDMODE_COLORFORMAT_8888; SEND_P3_DATA(PixelSize, 2 - __GLINT_32BITPIXEL); break; } pSoftP3RX->P3RXFBDestReadMode.Layout0 = pRenderInt->dwPatchMode; pSoftP3RX->P3RXFBWriteMode.Layout0 = pRenderInt->dwPatchMode; pSoftP3RX->P3RXFBSourceReadMode.Layout = pRenderInt->dwPatchMode; COPY_P3_DATA(FBWriteMode, pSoftP3RX->P3RXFBWriteMode); COPY_P3_DATA(FBDestReadMode, pSoftP3RX->P3RXFBDestReadMode); COPY_P3_DATA(FBSourceReadMode, pSoftP3RX->P3RXFBSourceReadMode); #if DX8_MULTISAMPLING || DX7_ANTIALIAS if (!(pContext->Flags & SURFACE_ANTIALIAS) || (pContext->dwAliasBackBuffer == 0)) { #endif // DX8_MULTISAMPLING || DX7_ANTIALIAS pContext->PixelOffset = (DWORD)(pRenderInt->fpVidMem - pThisDisplay->dwScreenFlatAddr ); if (pContext->pSurfZBufferInt) { pContext->ZPixelOffset = (DWORD)(pZBufferInt->fpVidMem - pThisDisplay->dwScreenFlatAddr); } AAMultiplier = 1; SEND_P3_DATA(PixelSize, (2 - pRenderInt->dwPixelSize)); #if DX8_MULTISAMPLING || DX7_ANTIALIAS } else { pContext->PixelOffset = pContext->dwAliasPixelOffset; pContext->ZPixelOffset = pContext->dwAliasZPixelOffset; AAMultiplier = 2; } #endif // DX8_MULTISAMPLING || DX7_ANTIALIAS COPY_P3_DATA(AlphaBlendColorMode, pSoftP3RX->P3RXAlphaBlendColorMode); COPY_P3_DATA(DitherMode, pSoftP3RX->DitherMode); SEND_P3_DATA(FBWriteBufferAddr0, pContext->PixelOffset); SEND_P3_DATA(FBDestReadBufferAddr0, pContext->PixelOffset); SEND_P3_DATA(FBSourceReadBufferAddr, pContext->PixelOffset); SEND_P3_DATA(FBWriteBufferWidth0, pContext->pSurfRenderInt->dwPixelPitch * AAMultiplier); SEND_P3_DATA(FBDestReadBufferWidth0, pContext->pSurfRenderInt->dwPixelPitch * AAMultiplier); SEND_P3_DATA(FBSourceReadBufferWidth, pContext->pSurfRenderInt->dwPixelPitch * AAMultiplier); WAIT_FIFO(20); // Is there a Z Buffer? if (pContext->pSurfZBufferInt != NULL) { // Offset is in BYTES SEND_P3_DATA(LBSourceReadBufferAddr, pContext->ZPixelOffset); SEND_P3_DATA(LBDestReadBufferAddr, pContext->ZPixelOffset); SEND_P3_DATA(LBWriteBufferAddr, pContext->ZPixelOffset); pSoftP3RX->P3RXLBWriteMode.Width = pContext->pSurfZBufferInt->dwPixelPitch * AAMultiplier; pSoftP3RX->P3RXLBSourceReadMode.Width = pContext->pSurfZBufferInt->dwPixelPitch * AAMultiplier; pSoftP3RX->P3RXLBDestReadMode.Width = pContext->pSurfZBufferInt->dwPixelPitch * AAMultiplier; COPY_P3_DATA(LBDestReadMode, pSoftP3RX->P3RXLBDestReadMode); COPY_P3_DATA(LBSourceReadMode, pSoftP3RX->P3RXLBSourceReadMode); COPY_P3_DATA(LBWriteMode, pSoftP3RX->P3RXLBWriteMode); COPY_P3_DATA(StencilMode, pSoftP3RX->P3RXStencilMode); COPY_P3_DATA(LBReadFormat, pSoftP3RX->P3RXLBReadFormat); COPY_P3_DATA(LBWriteFormat, pSoftP3RX->P3RXLBWriteFormat); COPY_P3_DATA(DepthMode, pSoftP3RX->P3RXDepthMode); } DIRTY_VIEWPORT(pContext); P3_DMA_COMMIT_BUFFER(); DBG_EXIT(_D3D_OP_SetRenderTarget,0); return DD_OK; } // _D3D_OP_SetRenderTarget //----------------------------------------------------------------------------- // // _D3D_OP_SceneCapture // // This function is called twice, once at the start of the rendering, // and once at the end of the rendering. The start is ignored, but // the end might be used to ensure that the DMA buffer has been flushed. // This is needed for the case where a scene has little in it, and // doesn't fill the buffer up. // //----------------------------------------------------------------------------- VOID _D3D_OP_SceneCapture( P3_D3DCONTEXT *pContext, DWORD dwFlag) { P3_THUNKEDDATA *pThisDisplay; pThisDisplay = pContext->pThisDisplay; if (dwFlag == D3DHAL_SCENE_CAPTURE_START) { DISPDBG((DBGLVL,"Scene Start")); } else if (dwFlag == D3DHAL_SCENE_CAPTURE_END) { #if DX8_MULTISAMPLING || DX7_ANTIALIAS if (pContext->Flags & SURFACE_ANTIALIAS) { // Since we were antialiasing we need to put the data where // the user asked which requires a copy from our AA buffer // into the true target buffer // P3 Shrinking is done in the DDRAW context. This means you // don't have to save and restore the state around the call // - the next D3D_OPERATION will recover for you DDRAW_OPERATION(pContext, pThisDisplay); P3RX_AA_Shrink(pContext); } #endif // DX8_MULTISAMPLING || DX7_ANTIALIAS DISPDBG((DBGLVL,"Scene End")); } return; } // _D3D_OP_SceneCapture #if DX7_TEXMANAGEMENT //----------------------------------------------------------------------------- // // __OP_MarkManagedSurfDirty // // Make sure textures are setup again if the texture is being used in any of // the texture stages (for reloading purpouses) and make sure we mark it as // dirty (since we're modifying the sysmem copy of the texture) // //----------------------------------------------------------------------------- VOID __OP_MarkManagedSurfDirty(P3_D3DCONTEXT* pContext, DWORD dwSurfHandle, P3_SURF_INTERNAL* pTexture) { // If the destination texture is in use in any of the texture // stages, make sure hw gets re-setup again before using it. if ((pContext->TextureStageState[0].m_dwVal[D3DTSS_TEXTUREMAP] == dwSurfHandle) || (pContext->TextureStageState[1].m_dwVal[D3DTSS_TEXTUREMAP] == dwSurfHandle)) { DIRTY_TEXTURE(pContext); } // Mark the destination texture as needing to be updated // into vidmem before using it. pTexture->m_bTMNeedUpdate = TRUE; } // __OP_MarkManagedSurfDirty //----------------------------------------------------------------------------- // // _D3D_OP_SetTexLod // // This function processes the D3DDP2OP_SETTEXLOD DP2 command token. // This communicates to the texture manager the most detailed mip map level // required to load for a given managed surface. // //----------------------------------------------------------------------------- VOID _D3D_OP_SetTexLod( P3_D3DCONTEXT *pContext, D3DHAL_DP2SETTEXLOD* pSetTexLod) { P3_SURF_INTERNAL* pTexture; // Get the source texture structure pointer pTexture = GetSurfaceFromHandle(pContext, pSetTexLod->dwDDSurface); if (pTexture == NULL) { return; } // Set up the HW texture states again if this texture is in use // and the new LOD value is smaller than the current setting. if (((pContext->TextureStageState[0].m_dwVal[D3DTSS_TEXTUREMAP] == pSetTexLod->dwDDSurface) || (pContext->TextureStageState[1].m_dwVal[D3DTSS_TEXTUREMAP] == pSetTexLod->dwDDSurface)) && (pSetTexLod->dwLOD < pTexture->m_dwTexLOD)) { DIRTY_TEXTURE(pContext); } // Change the texture's largest level to be actually used pTexture->m_dwTexLOD = pSetTexLod->dwLOD; } // _D3D_OP_SetTexLod //----------------------------------------------------------------------------- // // _D3D_OP_SetPriority // // This function processes the D3DDP2OP_SETPRIORITY DP2 command token. // //----------------------------------------------------------------------------- VOID _D3D_OP_SetPriority( P3_D3DCONTEXT *pContext, D3DHAL_DP2SETPRIORITY* pSetPriority) { P3_SURF_INTERNAL* pTexture; // Get the source texture structure pointer #if WNT_DDRAW pTexture = GetSurfaceFromHandle(pContext, pSetPriority->dwDDDestSurface); #else pTexture = GetSurfaceFromHandle(pContext, pSetPriority->dwDDSurface); #endif if (NULL != pTexture) { // Managed resources should be evicted depending on their priorities. // If of same priority then LRU is used to break the tie. pTexture->m_dwPriority = pSetPriority->dwPriority; } } // _D3D_OP_SetPriority #if DX8_DDI //----------------------------------------------------------------------------- // // _D3D_OP_AddDirtyRect // // This function processes the D3DDP2OP_ADDDIRTYRECT DP2 command token. // //----------------------------------------------------------------------------- VOID _D3D_OP_AddDirtyRect( P3_D3DCONTEXT *pContext, D3DHAL_DP2ADDDIRTYRECT* pAddDirtyRect) { P3_SURF_INTERNAL* pTexture; // Get the source texture structure pointer pTexture = GetSurfaceFromHandle(pContext, pAddDirtyRect->dwSurface); if (NULL != pTexture) { //azn TODO // As a first implementation in this driver we mark the whole surface // as dirty instead of marking just the indicated rect - which could be // transferred more efficiently __OP_MarkManagedSurfDirty(pContext, pAddDirtyRect->dwSurface, pTexture); } } // _D3D_OP_AddDirtyRect //----------------------------------------------------------------------------- // // _D3D_OP_AddDirtyBox // // This function processes the D3DDP2OP_ADDDIRTYBOX DP2 command token. // //----------------------------------------------------------------------------- VOID _D3D_OP_AddDirtyBox( P3_D3DCONTEXT *pContext, D3DHAL_DP2ADDDIRTYBOX* pAddDirtyBox) { P3_SURF_INTERNAL* pTexture; // Get the source texture structure pointer pTexture = GetSurfaceFromHandle(pContext, pAddDirtyBox->dwSurface); if (NULL != pTexture) { //azn TODO // As a first implementation in this driver we mark the whole surface // as dirty instead of marking just the indicated rect - which could be // transferred more efficiently __OP_MarkManagedSurfDirty(pContext, pAddDirtyBox->dwSurface, pTexture); } } // _D3D_OP_AddDirtyBox #endif #endif // DX7_TEXMANAGEMENT #if DX8_3DTEXTURES //----------------------------------------------------------------------------- // // __OP_BasicVolumeBlt // // This function blts one single level/slice at a time for volume textures // //----------------------------------------------------------------------------- VOID __OP_BasicVolumeBlt(P3_D3DCONTEXT* pContext, P3_THUNKEDDATA*pThisDisplay, P3_SURF_INTERNAL* pSrcTexture, P3_SURF_INTERNAL* pDestTexture, DWORD dwDestSurfHandle, RECTL *prSrc, RECTL *prDest) { #if DX7_TEXMANAGEMENT if ((0 == (pDestTexture->dwCaps2 & DDSCAPS2_TEXTUREMANAGE)) && (0 == (pSrcTexture->dwCaps2 & DDSCAPS2_TEXTUREMANAGE)) ) #endif // DX7_TEXMANAGEMENT { if ((pSrcTexture->Location == SystemMemory) && (pDestTexture->Location == VideoMemory)) { //---------------------------- // Do the system->videomem blt //---------------------------- _DD_P3Download(pThisDisplay, pSrcTexture->fpVidMem, pDestTexture->fpVidMem, pSrcTexture->dwPatchMode, pDestTexture->dwPatchMode, pSrcTexture->lPitch, pDestTexture->lPitch, pDestTexture->dwPixelPitch, pDestTexture->dwPixelSize, prSrc, prDest); } else { DISPDBG((ERRLVL, "ERROR: __OP_BasicVolumeBlt b3DTexture (%d -> %d)" "not suported yet!", pSrcTexture->Location, pDestTexture->Location)); } } #if DX7_TEXMANAGEMENT else if (pSrcTexture->dwCaps2 & DDSCAPS2_TEXTUREMANAGE) { //---------------------------------- //---------------------------------- // TEXBLT from a managed texture //---------------------------------- //---------------------------------- if ((pDestTexture->Location == SystemMemory) || (pDestTexture->dwCaps2 & DDSCAPS2_TEXTUREMANAGE)) { //------------------------------------------------- // Do the Managed surf -> sysmem | managed surf blt //------------------------------------------------- // make sure we'll reload the vidmem copy of the dest surf if (pDestTexture->dwCaps2 & DDSCAPS2_TEXTUREMANAGE) { __OP_MarkManagedSurfDirty(pContext, dwDestSurfHandle, pDestTexture); } _DD_BLT_SysMemToSysMemCopy( pSrcTexture->fpVidMem, pSrcTexture->lPitch, pSrcTexture->dwBitDepth, pDestTexture->fpVidMem, pDestTexture->lPitch, pDestTexture->dwBitDepth, prSrc, prDest); } else if (pDestTexture->Location == VideoMemory) { //------------------------------------------------- // 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, pSrcTexture->fpVidMem, pDestTexture->fpVidMem, pSrcTexture->dwPatchMode, pDestTexture->dwPatchMode, pSrcTexture->lPitch, pDestTexture->lPitch, pDestTexture->dwPixelPitch, pDestTexture->dwPixelSize, prSrc, prDest); } else { DISPDBG((ERRLVL,"Src-managed __OP_BasicVolumeBlt variation " "unimplemented! (from %d into %d)", pSrcTexture->Location, pDestTexture->Location)); } } else if (pDestTexture->dwCaps2 & DDSCAPS2_TEXTUREMANAGE) { //-------------------------------------------------------------- //-------------------------------------------------------------- // TEXBLT into a managed texture (except from a managed texture) //-------------------------------------------------------------- //-------------------------------------------------------------- // managed->managed is handled in the previous case if (pSrcTexture->Location == SystemMemory) { //------------------------------------------------- // Do the sysmem surf -> managed surf blt //------------------------------------------------- // make sure we'll reload the vidmem copy of the dest surf __OP_MarkManagedSurfDirty(pContext, dwDestSurfHandle, pDestTexture); _DD_BLT_SysMemToSysMemCopy( pSrcTexture->fpVidMem, pSrcTexture->lPitch, pSrcTexture->dwBitDepth, pDestTexture->fpVidMem, pDestTexture->lPitch, pDestTexture->dwBitDepth, prSrc, prDest); } else if (pSrcTexture->Location == VideoMemory) { //------------------------------------------------- // Do the vidmem surf -> Managed surf blt //------------------------------------------------- if (0 != pSrcTexture->MipLevels[0].fpVidMemTM) { // Destination is already in vidmem so instead of // "dirtying" the managed texture lets do the // vidmem->vidmem blt which is faster than doing the // update later (in the hope we'll really use it) _DD_BLT_P3CopyBlt(pThisDisplay, pSrcTexture->fpVidMem, pDestTexture->MipLevels[0].fpVidMemTM, pSrcTexture->dwPatchMode, pDestTexture->dwPatchMode, pSrcTexture->dwPixelPitch, pDestTexture->dwPixelPitch, pSrcTexture->MipLevels[0].dwOffsetFromMemoryBase, pDestTexture->MipLevels[0].dwOffsetFromMemoryBase, pDestTexture->dwPixelSize, prSrc, prDest); } else { // make sure we'll reload the // vidmem copy of the dest surf __OP_MarkManagedSurfDirty(pContext, dwDestSurfHandle, pDestTexture); } // 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( D3DSURF_GETPOINTER(pSrcTexture, pThisDisplay), pSrcTexture->lPitch, pSrcTexture->dwBitDepth, pDestTexture->fpVidMem, pDestTexture->lPitch, pDestTexture->dwBitDepth, prSrc, prDest); } else if (pSrcTexture->Location == AGPMemory) { // make sure we'll reload the vidmem copy of the dest surf __OP_MarkManagedSurfDirty(pContext, dwDestSurfHandle, pDestTexture); _DD_BLT_SysMemToSysMemCopy( pSrcTexture->fpVidMem, pSrcTexture->lPitch, pSrcTexture->dwBitDepth, pDestTexture->fpVidMem, pDestTexture->lPitch, pDestTexture->dwBitDepth, prSrc, prDest); } else { DISPDBG((ERRLVL,"Dest-managed __OP_BasicVolumeBlt variation " "unimplemented! (from %d into %d)", pSrcTexture->Location, pDestTexture->Location)); } } else { DISPDBG((ERRLVL,"__OP_BasicVolumeBlt variation unimplemented! " "(from %d into %d)", pSrcTexture->Location, pDestTexture->Location)); } #endif // DX7_TEXMANAGEMENT } // __OP_BasicVolumeBlt //----------------------------------------------------------------------------- // // _D3D_OP_VolumeBlt // // This function processes the D3DDP2OP_VOLUMEBLT DP2 command token. // //----------------------------------------------------------------------------- VOID _D3D_OP_VolumeBlt(P3_D3DCONTEXT* pContext, P3_THUNKEDDATA*pThisDisplay, D3DHAL_DP2VOLUMEBLT* pBlt) { LPDDRAWI_DDRAWSURFACE_LCL pSrcLcl; LPDDRAWI_DDRAWSURFACE_LCL pDestLcl; P3_SURF_INTERNAL* pSrcTexture; P3_SURF_INTERNAL* pDestTexture; P3_SURF_FORMAT* pFormatSource; P3_SURF_FORMAT* pFormatDest; RECTL rSrc, rDest; DWORD dwSrcCurrDepth, dwDestCurrDepth, dwEndDepth; // Get the texture structure pointers pSrcTexture = GetSurfaceFromHandle(pContext, pBlt->dwDDSrcSurface); pDestTexture = GetSurfaceFromHandle(pContext, pBlt->dwDDDestSurface); // Check that the textures are valid if (pSrcTexture == NULL) { DISPDBG((ERRLVL, "ERROR: Source texture %d is invalid!", pBlt->dwDDSrcSurface)); return; } if (pDestTexture == NULL) { DISPDBG((ERRLVL, "ERROR: Dest texture %d is invalid!", pBlt->dwDDDestSurface)); return; } // If we are going to blt 3D texture, both have to be 3D texture if ((pSrcTexture->b3DTexture == FALSE) != (pDestTexture->b3DTexture == FALSE)) { DISPDBG((ERRLVL, "ERROR: TEXBLT b3DTexture (%d %d)does not match!", pSrcTexture->b3DTexture, pDestTexture->b3DTexture)); return; } // Do we blt whole 3D texture ? if ((pBlt->srcBox.Left == 0) && (pBlt->srcBox.Top == 0) && (pBlt->srcBox.Right == pSrcTexture->wWidth) && (pBlt->srcBox.Bottom == pSrcTexture->wHeight) && (pBlt->srcBox.Front == 0) && (pBlt->srcBox.Back == pSrcTexture->wDepth) && (pBlt->dwDestX == 0) && (pBlt->dwDestY == 0) && (pBlt->dwDestZ == 0) && (pSrcTexture->wWidth == pDestTexture->wWidth) && (pSrcTexture->wHeight == pDestTexture->wHeight) && (pSrcTexture->wDepth == pDestTexture->wDepth)) { // Build source rectangle rSrc.left = 0; rSrc.top = 0; rSrc.right = pBlt->srcBox.Right; rSrc.bottom = pBlt->srcBox.Bottom * pBlt->srcBox.Back; // Destination rectangle is same as source. rDest = rSrc; // Switch to the DirectDraw context DDRAW_OPERATION(pContext, pThisDisplay); // Do the Blt! __OP_BasicVolumeBlt(pContext, pThisDisplay, pSrcTexture, pDestTexture, pBlt->dwDDDestSurface, &rSrc, &rDest); // Switch back to the Direct3D context D3D_OPERATION(pContext, pThisDisplay); return; } // Build source rectangle. rSrc.left = pBlt->srcBox.Left; rSrc.top = pBlt->srcBox.Top; rSrc.right = pBlt->srcBox.Right; rSrc.bottom = pBlt->srcBox.Bottom; // Build destination rectangle. rDest.left = pBlt->dwDestX; rDest.top = pBlt->dwDestY; rDest.right = pBlt->dwDestX + (rSrc.right - rSrc.left); rDest.bottom = pBlt->dwDestY + (rSrc.bottom - rSrc.top); // Adjust rectangle if blt from non-1st slice. if (pBlt->srcBox.Front) { ULONG ulOffset = pSrcTexture->wDepth * pBlt->srcBox.Front; rSrc.top += ulOffset; rSrc.bottom += ulOffset; } // Adjust rectangle if blt to non-1st slice. if (pBlt->dwDestZ) { ULONG ulOffset = pDestTexture->wDepth * pBlt->dwDestZ; rDest.top += ulOffset; rDest.bottom += ulOffset; } dwSrcCurrDepth = pBlt->srcBox.Front; dwDestCurrDepth = pBlt->dwDestZ; dwEndDepth = min(pBlt->dwDestZ + (pBlt->srcBox.Back - pBlt->srcBox.Front), pDestTexture->wDepth); dwEndDepth = min(dwEndDepth, pSrcTexture->wDepth); while(dwDestCurrDepth < dwEndDepth) { // Switch to the DirectDraw context DDRAW_OPERATION(pContext, pThisDisplay); // Do the Blt! __OP_BasicVolumeBlt(pContext, pThisDisplay, pSrcTexture, pDestTexture, pBlt->dwDDDestSurface, &rSrc, &rDest); // Switch back to the Direct3D context D3D_OPERATION(pContext, pThisDisplay); // Move the source and destination rect to next slice. rSrc.top += pSrcTexture->wDepth; rSrc.bottom += pSrcTexture->wDepth; rDest.top += pDestTexture->wDepth; rDest.bottom += pDestTexture->wDepth; // Move on to next slice. dwSrcCurrDepth++; dwDestCurrDepth++; } } // _D3D_OP_VolumeBlt #endif // DX8_3DTEXTURES #if DX8_DDI //----------------------------------------------------------------------------- // // _D3D_OP_BufferBlt // // This function processes the D3DDP2OP_BUFFERBLT DP2 command token. // //----------------------------------------------------------------------------- VOID _D3D_OP_BufferBlt(P3_D3DCONTEXT* pContext, P3_THUNKEDDATA*pThisDisplay, D3DHAL_DP2BUFFERBLT* pBlt) { #if DX7_VERTEXBUFFERS // This command token is only sent to drivers // supporting videomemory vertexbuffers. That is // why we won't see it come down to this driver. #endif DX7_VERTEXBUFFERS } // _D3D_OP_BufferBlt #endif // DX8_DDI #if DX8_VERTEXSHADERS //----------------------------------------------------------------------------- // // _D3D_OP_VertexShader_Create // // This function processes the D3DDP2OP_CREATEVERTEXSHADER DP2 command token. // //----------------------------------------------------------------------------- HRESULT _D3D_OP_VertexShader_Create( P3_D3DCONTEXT* pContext, DWORD dwVtxShaderHandle, DWORD dwDeclSize, DWORD dwCodeSize, BYTE *pShader) { // Here we would use the data passed by the vertex shader // creation block in order to instantiate or compile the // given vertex shader. Since this hardware can't support // vertex shaders at this time, we just skip the data. return DD_OK; } // _D3D_OP_VertexShader_Create //----------------------------------------------------------------------------- // // _D3D_OP_VertexShader_Delete // // This function processes the D3DDP2OP_DELETEVERTEXSHADER DP2 command token. // //----------------------------------------------------------------------------- VOID _D3D_OP_VertexShader_Delete( P3_D3DCONTEXT* pContext, DWORD dwVtxShaderHandle) { // Here we would use the data passed by the vertex shader // delete block in order to destroy the given vertex shader. // Since this hardware can't support vertex shaders at // this time, we just skip the data. } // _D3D_OP_VertexShader_Delete #define RDVSD_ISLEGACY(ShaderHandle) !(ShaderHandle & D3DFVF_RESERVED0) //----------------------------------------------------------------------------- // // _D3D_OP_VertexShader_Set // // This function processes the D3DDP2OP_SETVERTEXSHADER DP2 command token. // //----------------------------------------------------------------------------- VOID _D3D_OP_VertexShader_Set( P3_D3DCONTEXT* pContext, DWORD dwVtxShaderHandle) { // Here we would use the data passed by the vertex shader // set block in order to setup the given vertex shader. // Since this hardware can't support vertex shaders at // this time, we usually just skip the data. However under // the circumstances described below, we might be passed a // FVF vertex format DISPDBG((DBGLVL,"Setting up shader # 0x%x",dwVtxShaderHandle)); #if DX7_D3DSTATEBLOCKS if ( pContext->bStateRecMode ) { _D3D_SB_Record_VertexShader_Set(pContext, dwVtxShaderHandle); return; } #endif // DX7_D3DSTATEBLOCKS // Zero is a special handle that tells the driver to // invalidate the currently set shader. if( dwVtxShaderHandle == 0 ) { DISPDBG((WRNLVL,"Invalidating the currently set shader")); return ; } if( RDVSD_ISLEGACY(dwVtxShaderHandle) ) { // Make it parse the FVF pContext->dwVertexType = dwVtxShaderHandle; } else { DISPDBG((ERRLVL,"_D3D_OP_VertexShader_Set: Illegal shader handle " "(This driver cant do vertex processing)")); } } // _D3D_OP_VertexShader_Set //----------------------------------------------------------------------------- // // _D3D_OP_VertexShader_SetConst // // This function processes the D3DDP2OP_SETVERTEXSHADERCONST DP2 command token. // //----------------------------------------------------------------------------- VOID _D3D_OP_VertexShader_SetConst( P3_D3DCONTEXT* pContext, DWORD dwRegister, DWORD dwConst, DWORD *pdwValues) { // Here we would use the data passed by the vertex shader // constant block in order to set up the constant entry. // Since this hardware can't support vertex shaders at // this time, we just skip the data. } // _D3D_OP_VertexShader_SetConst #endif // DX8_VERTEXSHADERS #if DX8_PIXELSHADERS //----------------------------------------------------------------------------- // // _D3D_OP_PixelShader_Create // // This function processes the D3DDP2OP_CREATEPIXELSHADER DP2 command token. // //----------------------------------------------------------------------------- HRESULT _D3D_OP_PixelShader_Create( P3_D3DCONTEXT* pContext, DWORD dwPxlShaderHandle, DWORD dwCodeSize, BYTE *pShader) { // Here we would use the data passed by the pixel shader // creation block in order to instantiate or compile the // given pixel shader. // Since this hardware can't support pixel shaders at this // time, we fail the call in case we're called to create a // 255.255 version shader! return D3DERR_DRIVERINVALIDCALL; } // _D3D_OP_PixelShader_Create //----------------------------------------------------------------------------- // // _D3D_OP_PixelShader_Delete // // This function processes the D3DDP2OP_DELETEPIXELSHADER DP2 command token. // //----------------------------------------------------------------------------- VOID _D3D_OP_PixelShader_Delete( P3_D3DCONTEXT* pContext, DWORD dwPxlShaderHandle) { // Here we would use the data passed by the pixel shader // delete block in order to destroy the given pixel shader. // Since this hardware can't support pixel shaders at // this time, we just skip the data. } // _D3D_OP_PixelShader_Delete //----------------------------------------------------------------------------- // // _D3D_OP_PixelShader_Set // // This function processes the D3DDP2OP_SETPIXELSHADER DP2 command token. // //----------------------------------------------------------------------------- VOID _D3D_OP_PixelShader_Set( P3_D3DCONTEXT* pContext, DWORD dwPxlShaderHandle) { // Here we would use the data passed by the pixel shader // set block in order to setup the given pixel shader. // Since this hardware can't support pixel shaders at // this time, we just skip the data. } // _D3D_OP_PixelShader_Set //----------------------------------------------------------------------------- // // _D3D_OP_PixelShader_SetConst // // This function processes the D3DDP2OP_SETPIXELSHADERCONST DP2 command token. // //----------------------------------------------------------------------------- VOID _D3D_OP_PixelShader_SetConst( P3_D3DCONTEXT* pContext, DWORD dwRegister, DWORD dwCount, DWORD *pdwValues) { // Here we would use the data passed by the pixel shader // set block in order to setup the given pixel shader constants. // Since this hardware can't support pixel shaders at // this time, we just skip the data. } // _D3D_OP_PixelShader_SetConst #endif // DX8_PIXELSHADERS #if DX8_MULTSTREAMS //----------------------------------------------------------------------------- // // _D3D_OP_MStream_SetSrc // // This function processes the D3DDP2OP_SETSTREAMSOURCE DP2 command token. // //----------------------------------------------------------------------------- VOID _D3D_OP_MStream_SetSrc( P3_D3DCONTEXT* pContext, DWORD dwStream, DWORD dwVBHandle, DWORD dwStride) { P3_SURF_INTERNAL *pSrcStream; DBG_ENTRY(_D3D_OP_MStream_SetSrc); #if DX7_D3DSTATEBLOCKS if ( pContext->bStateRecMode ) { _D3D_SB_Record_MStream_SetSrc(pContext, dwStream, dwVBHandle, dwStride); return; } #endif // DX7_D3DSTATEBLOCKS if (dwVBHandle != 0) { if (dwStream == 0) { // Get the surface structure pointers for stream #0 pSrcStream = GetSurfaceFromHandle(pContext, dwVBHandle); if (pSrcStream) { DISPDBG((DBGLVL,"Address of VB = 0x%x " "dwVBHandle = %d , dwStride = %d", pSrcStream->fpVidMem,dwVBHandle, dwStride)); pContext->lpVertices = (LPDWORD)pSrcStream->fpVidMem; pContext->dwVerticesStride = dwStride; if (dwStride > 0) { // DX8 has mixed types of vertices in one VB, size in bytes // of the vertex buffer must be preserved pContext->dwVBSizeInBytes = pSrcStream->lPitch; // for VBs the wHeight should always be == 1. // dwNumVertices stores the # of vertices in the VB // On Win2K, both wWidth and lPitch are the buffer size // On Win9x, only lPitch is the buffer size, wWidth is 0 // The same fact is also true for the index buffer pContext->dwNumVertices = pSrcStream->lPitch / dwStride; DISPDBG((DBGLVL,"dwVBHandle pContext->dwNumVertices = " "pSrcStream->lPitch / dwStride = %d %d %d %d", dwVBHandle, pContext->dwNumVertices, pSrcStream->lPitch,dwStride)); #if DX7_D3DSTATEBLOCKS pContext->dwVBHandle = dwVBHandle; #endif // DX7_D3DSTATEBLOCKS } else { pContext->dwVBSizeInBytes = 0; pContext->dwNumVertices = 0; DISPDBG((ERRLVL,"INVALID Stride is 0. VB Size undefined")); } } else { DISPDBG((ERRLVL,"ERROR Address of VB is NULL, " "dwStream = %d dwVBHandle = %d , dwStride = %d", dwStream, dwVBHandle, dwStride)); } } else { DISPDBG((WRNLVL,"We don't handle other streams than #0")); } } else { // We are unsetting the stream pContext->lpVertices = NULL; DISPDBG((WRNLVL,"Unsetting a stream: " "dwStream = %d dwVBHandle = %d , dwStride = %d", dwStream, dwVBHandle, dwStride)); } DBG_EXIT(_D3D_OP_MStream_SetSrc, 0); } // _D3D_OP_MStream_SetSrc //----------------------------------------------------------------------------- // // _D3D_OP_MStream_SetSrcUM // // This function processes the D3DDP2OP_SETSTREAMSOURCEUM DP2 command token. // //----------------------------------------------------------------------------- VOID _D3D_OP_MStream_SetSrcUM( P3_D3DCONTEXT* pContext, DWORD dwStream, DWORD dwStride, LPBYTE pUMVtx, DWORD dwVBSize) { DBG_ENTRY(_D3D_OP_MStream_SetSrcUM); if (dwStream == 0) { // Set the stream # 0 information DISPDBG((DBGLVL,"_D3D_OP_MStream_SetSrcUM: " "Setting VB@ 0x%x dwstride=%d", pUMVtx, dwStride)); pContext->lpVertices = (LPDWORD)pUMVtx; pContext->dwVerticesStride = dwStride; pContext->dwVBSizeInBytes = dwVBSize * dwStride; pContext->dwNumVertices = dwVBSize ; // comes from the DP2 data // structure } else { DISPDBG((WRNLVL,"_D3D_OP_MStream_SetSrcUM: " "We don't handle other streams than #0")); } DBG_EXIT(_D3D_OP_MStream_SetSrcUM, 0); } // _D3D_OP_MStream_SetSrcUM //----------------------------------------------------------------------------- // // _D3D_OP_MStream_SetIndices // // This function processes the D3DDP2OP_SETINDICES DP2 command token. // //----------------------------------------------------------------------------- VOID _D3D_OP_MStream_SetIndices( P3_D3DCONTEXT* pContext, DWORD dwVBHandle, DWORD dwStride) { P3_SURF_INTERNAL *pIndxStream; DBG_ENTRY(_D3D_OP_MStream_SetIndices); #if DX7_D3DSTATEBLOCKS if ( pContext->bStateRecMode ) { _D3D_SB_Record_MStream_SetIndices(pContext, dwVBHandle, dwStride); return; } #endif // DX7_D3DSTATEBLOCKS // NULL dwVBHandle just means that the Index should be unset if (dwVBHandle != 0) { // Get the indices surface structure pointer pIndxStream = GetSurfaceFromHandle(pContext, dwVBHandle); if (pIndxStream) { DISPDBG((DBGLVL,"Address of VB = 0x%x", pIndxStream->fpVidMem)); pContext->lpIndices = (LPDWORD)pIndxStream->fpVidMem; pContext->dwIndicesStride = dwStride; // 2 or 4 for 16/32bit indices #if DX7_D3DSTATEBLOCKS pContext->dwIndexHandle = dwVBHandle; // Index buffer handle #endif } else { DISPDBG((ERRLVL,"ERROR Address of Index Surface is NULL, " "dwVBHandle = %d , dwStride = %d", dwVBHandle, dwStride)); } } else { // We are unsetting the stream pContext->lpIndices = NULL; DISPDBG((WRNLVL,"Unsetting an index stream: " "dwVBHandle = %d , dwStride = %d", dwVBHandle, dwStride)); } DBG_EXIT(_D3D_OP_MStream_SetIndices, 0); } // _D3D_OP_MStream_SetIndices //----------------------------------------------------------------------------- // // _D3D_OP_MStream_DrawPrim // // This function processes the D3DDP2OP_DRAWPRIMITIVE DP2 command token. // //----------------------------------------------------------------------------- VOID _D3D_OP_MStream_DrawPrim( P3_D3DCONTEXT* pContext, D3DPRIMITIVETYPE primType, DWORD VStart, DWORD PrimitiveCount) { DBG_ENTRY(_D3D_OP_MStream_DrawPrim); DISPDBG((DBGLVL,"_D3D_OP_MStream_DrawPrim " "primType=0x%x VStart=%d PrimitiveCount=%d", primType, VStart, PrimitiveCount)); _D3D_OP_MStream_DrawPrim2(pContext, primType, VStart * pContext->FVFData.dwStride, PrimitiveCount); DBG_EXIT(_D3D_OP_MStream_DrawPrim, 0); } // _D3D_OP_MStream_DrawPrim //----------------------------------------------------------------------------- // // _D3D_OP_MStream_DrawIndxP // // This function processes the D3DDP2OP_DRAWINDEXEDPRIMITIVE DP2 command token. // //----------------------------------------------------------------------------- VOID _D3D_OP_MStream_DrawIndxP( P3_D3DCONTEXT* pContext, D3DPRIMITIVETYPE primType, DWORD BaseVertexIndex, DWORD MinIndex, DWORD NumVertices, DWORD StartIndex, DWORD PrimitiveCount) { DBG_ENTRY(_D3D_OP_MStream_DrawIndxP); DISPDBG((DBGLVL,"_D3D_OP_MStream_DrawIndxP " "primType=0x%x BaseVertexIndex=%d MinIndex=%d" "NumVertices =%d StartIndex=%d PrimitiveCount=%d", primType, BaseVertexIndex, MinIndex, NumVertices, StartIndex, PrimitiveCount)); _D3D_OP_MStream_DrawIndxP2(pContext, primType, BaseVertexIndex * pContext->FVFData.dwStride, MinIndex, NumVertices, StartIndex * pContext->dwIndicesStride, PrimitiveCount); DBG_EXIT(_D3D_OP_MStream_DrawIndxP, 0); } // _D3D_OP_MStream_DrawIndxP //----------------------------------------------------------------------------- // // Validate the context settings to use the current streams // //----------------------------------------------------------------------------- BOOL __OP_ValidateStreams( P3_D3DCONTEXT* pContext, BOOL bCheckIndexStream) { if ((pContext->dwVerticesStride == 0) || (pContext->FVFData.dwStride == 0)) { DISPDBG((ERRLVL,"The zero'th stream is doesn't have a valid VB set")); return FALSE; } if (pContext->dwVerticesStride < pContext->FVFData.dwStride) { DISPDBG((ERRLVL,"The stride set for the vertex stream is " "less than the FVF vertex size")); return FALSE; } //@@BEGIN_DDKSPLIT // This shouldn't happen, but lets watch for it since it would show // up as weird mangled & distorted triangles if (pContext->dwVerticesStride != pContext->FVFData.dwStride) { DISPDBG((ERRLVL,"Strides(indx-prim) <> %d %d ", pContext->dwVerticesStride,pContext->FVFData.dwStride)); } //@@END_DDKSPLIT if ((bCheckIndexStream) && (NULL == pContext->lpIndices)) { DISPDBG((ERRLVL,"Pointer to index buffer is null")); return FALSE; } if (NULL == pContext->lpVertices) { DISPDBG((ERRLVL,"Pointer to vertex buffer is null")); return FALSE; } return TRUE; } // __OP_ValidateStreams //----------------------------------------------------------------------------- // // _D3D_OP_MStream_DrawPrim2 // // This function processes the D3DDP2OP_DRAWPRIMITIVE2 DP2 command token. // //----------------------------------------------------------------------------- VOID _D3D_OP_MStream_DrawPrim2( P3_D3DCONTEXT* pContext, D3DPRIMITIVETYPE primType, DWORD FirstVertexOffset, DWORD PrimitiveCount) { BOOL bError; WORD wVStart; DWORD dwFillMode = pContext->RenderStates[D3DRENDERSTATE_FILLMODE]; LPBYTE lpVertices; DWORD dwNumVertices; DBG_ENTRY(_D3D_OP_MStream_DrawPrim2); DISPDBG((DBGLVL ,"_D3D_OP_MStream_DrawPrim2 " "primType=0x%x FirstVertexOffset=%d PrimitiveCount=%d", primType, FirstVertexOffset, PrimitiveCount)); if (!__OP_ValidateStreams(pContext, FALSE)) { return; } // Watchout: Sometimes (particularly when CLIPPEDTRIFAN are drawn), // FirstVertexOffset might not be divided evenly by the dwStride lpVertices = ((LPBYTE)pContext->lpVertices) + FirstVertexOffset; dwNumVertices = pContext->dwVBSizeInBytes - FirstVertexOffset; dwNumVertices /= pContext->dwVerticesStride; wVStart = 0; switch(primType) { case D3DPT_POINTLIST: { D3DHAL_DP2POINTS dp2Points; dp2Points.wVStart = wVStart; #if DX8_POINTSPRITES if(IS_POINTSPRITE_ACTIVE(pContext)) { _D3D_R3_DP2_PointsSprite_DWCount(pContext, PrimitiveCount, (LPBYTE)&dp2Points, (LPD3DTLVERTEX)lpVertices, dwNumVertices, &bError); } else #endif // DX8_POINTSPRITES { _D3D_R3_DP2_Points_DWCount(pContext, PrimitiveCount, (LPBYTE)&dp2Points, (LPD3DTLVERTEX)lpVertices, dwNumVertices, &bError); } } break; case D3DPT_LINELIST: _D3D_R3_DP2_LineList(pContext, PrimitiveCount, (LPBYTE)&wVStart, (LPD3DTLVERTEX)lpVertices, dwNumVertices, &bError); break; case D3DPT_LINESTRIP: _D3D_R3_DP2_LineStrip(pContext, PrimitiveCount, (LPBYTE)&wVStart, (LPD3DTLVERTEX)lpVertices, dwNumVertices, &bError); break; case D3DPT_TRIANGLELIST: _D3D_R3_DP2_TriangleList(pContext, PrimitiveCount, (LPBYTE)&wVStart, (LPD3DTLVERTEX)lpVertices, dwNumVertices, &bError); break; case D3DPT_TRIANGLESTRIP: _D3D_R3_DP2_TriangleStrip(pContext, PrimitiveCount, (LPBYTE)&wVStart, (LPD3DTLVERTEX)lpVertices, dwNumVertices, &bError); break; case D3DPT_TRIANGLEFAN: _D3D_R3_DP2_TriangleFan(pContext, PrimitiveCount, (LPBYTE)&wVStart, (LPD3DTLVERTEX)lpVertices, dwNumVertices, &bError); break; } DBG_EXIT(_D3D_OP_MStream_DrawPrim2, 0); } // _D3D_OP_MStream_DrawPrim2 //----------------------------------------------------------------------------- // // _D3D_OP_MStream_DrawIndxP2 // // This function processes the D3DDP2OP_DRAWINDEXEDPRIMITIVE2 DP2 command token. // //----------------------------------------------------------------------------- VOID _D3D_OP_MStream_DrawIndxP2( P3_D3DCONTEXT* pContext, D3DPRIMITIVETYPE primType, INT BaseVertexOffset, DWORD MinIndex, DWORD NumVertices, DWORD StartIndexOffset, DWORD PrimitiveCount) { INT BaseIndexOffset; LPDWORD lpVertices; LPBYTE lpIndices; BOOL bError; R3_DP2_PRIM_TYPE_MS *pRenderFunc; DBG_ENTRY(_D3D_OP_MStream_DrawIndxP2); DISPDBG((DBGLVL,"_D3D_OP_MStream_DrawIndxP2 " "primType=0x%x BaseVertexOffset=%d MinIndex=%d " "NumVertices=%d StartIndexOffset=%d PrimitiveCount=%d", primType, BaseVertexOffset, MinIndex, NumVertices, StartIndexOffset, PrimitiveCount)); if (!__OP_ValidateStreams(pContext, TRUE)) { return; } // The MinIndex and NumVertices parameters specify the range of vertex i // ndices used for each DrawIndexedPrimitive call. These are used to // optimize vertex processing of indexed primitives by processing a // sequential range of vertices prior to indexing into these vertices // ********** IMPORTANT NOTE ********** // // BaseVertexOffset is a signed quantity (INT) unlike the other parameters // to this call which are DWORDS. This may appear strange. Why would // the offset into the vertex buffer be negative? Clearly you cannot access // vertex data before the start of the vertex buffer, and indeed, you never // do. When you have a negative BaseVertexOffset you will also receive // indices which are large enough that when applied to the start pointer // (obtained from adding a negative BaseVertexOffset to the vertex data // pointer) which fall within the correct range of the vertices in the // actual vertex buffer, i.e., the indices "undo" any negative vertex offset // and vertex accesses will end up being in the legal range for that vertex // buffer. // // Hence, you must write your driver code with this in mind. For example, // you can't assume that given an index i and with a current vertex buffer // of size v: // // ((StartIndexOffset + i) >= 0) && ((StartIndexOffset + i) < v) // // Your code needs to take into account that your indices are not offsets // from the start of the vertex buffer but rather from the start of the // vertex buffer plus BaseVertexOffset and that furthermore BaseVertexOffset // may be negative. // // The reason BaseVertexOffset can be negative is that it provides a // significant advantage to the runtime in certain vertex processing scenarios. lpVertices = (LPDWORD)((LPBYTE)pContext->lpVertices + BaseVertexOffset); lpIndices = (LPBYTE)pContext->lpIndices + StartIndexOffset; // Select the appropriate rendering function pRenderFunc = NULL; if (pContext->dwIndicesStride == 2) { // Handle 16 bit indices switch(primType) { case D3DPT_LINELIST: pRenderFunc = _D3D_R3_DP2_IndexedLineList_MS_16IND; break; case D3DPT_LINESTRIP: pRenderFunc = _D3D_R3_DP2_IndexedLineStrip_MS_16IND; break; case D3DPT_TRIANGLELIST: pRenderFunc = _D3D_R3_DP2_IndexedTriangleList_MS_16IND; break; case D3DPT_TRIANGLESTRIP: pRenderFunc = _D3D_R3_DP2_IndexedTriangleStrip_MS_16IND; break; case D3DPT_TRIANGLEFAN: pRenderFunc = _D3D_R3_DP2_IndexedTriangleFan_MS_16IND; break; } } else { // Handle 32 bit indices switch(primType) { case D3DPT_LINELIST: pRenderFunc = _D3D_R3_DP2_IndexedLineList_MS_32IND; break; case D3DPT_LINESTRIP: pRenderFunc = _D3D_R3_DP2_IndexedLineStrip_MS_32IND; break; case D3DPT_TRIANGLELIST: pRenderFunc = _D3D_R3_DP2_IndexedTriangleList_MS_32IND; break; case D3DPT_TRIANGLESTRIP: pRenderFunc = _D3D_R3_DP2_IndexedTriangleStrip_MS_32IND; break; case D3DPT_TRIANGLEFAN: pRenderFunc = _D3D_R3_DP2_IndexedTriangleFan_MS_32IND; break; } } // Call our rendering function if (pRenderFunc) { // As mentioned above, the actual range of indices seen by the driver // doesn't necessarily lie within the range zero to one less than // the number of vertices in the vertex buffer due to BaseVertexOffset. // If BaseVertexOffset is positive the range of valid indices is // smaller than the size of the vertex buffer (the vertices that // lie in the vertex buffer before the BaseVertexOffset are not // considered). Furthermore, if BaseVertexOffset a valid index can // actually by greater than the number of vertices in the vertex // buffer. // // To assist with the validation performed by the rendering functions // we here compute a minimum and maximum index which take into // account the value of BaseVertexOffset. Thus a test for a valid // index becomes: // // ((BaseIndexOffset + StartIndexOffset + Index) >= 0) && // ((BaseIndexOffset + StartIndexOffset + Index) < VertexCount) BaseIndexOffset = (BaseVertexOffset / (int)pContext->dwVerticesStride); DISPDBG((DBGLVL,"_D3D_OP_MStream_DrawIndxP2 BaseIndexOffset = %d", BaseIndexOffset)); (*pRenderFunc)(pContext, PrimitiveCount, (LPBYTE)lpIndices, (LPD3DTLVERTEX)lpVertices, BaseIndexOffset, pContext->dwNumVertices, &bError); } DBG_EXIT(_D3D_OP_MStream_DrawIndxP2, 0); } // _D3D_OP_MStream_DrawIndxP2 //----------------------------------------------------------------------------- // // _D3D_OP_MStream_ClipTriFan // // This function processes the D3DDP2OP_CLIPPEDTRIANGLEFAN DP2 command token. // //----------------------------------------------------------------------------- VOID _D3D_OP_MStream_ClipTriFan( P3_D3DCONTEXT* pContext, DWORD FirstVertexOffset, DWORD dwEdgeFlags, DWORD PrimitiveCount) { BOOL bError; DBG_ENTRY(_D3D_OP_MStream_ClipTriFan); DISPDBG((DBGLVL,"_D3D_OP_MStream_ClipTriFan " "FirstVertexOffset=%d dwEdgeFlags=0x%x PrimitiveCount=%d", FirstVertexOffset, dwEdgeFlags, PrimitiveCount)); if (pContext->RenderStates[D3DRENDERSTATE_FILLMODE] == D3DFILL_WIREFRAME) { D3DHAL_DP2TRIANGLEFAN_IMM dp2TriFanWire; if (!__OP_ValidateStreams(pContext, FALSE)) { DBG_EXIT(_D3D_OP_MStream_ClipTriFan, 0); return; } dp2TriFanWire.dwEdgeFlags = dwEdgeFlags; _D3D_R3_DP2_TriangleFanImm(pContext, (WORD)PrimitiveCount, (LPBYTE)&dp2TriFanWire, (LPD3DTLVERTEX)pContext->lpVertices, pContext->dwNumVertices, &bError); } else { _D3D_OP_MStream_DrawPrim2(pContext, D3DPT_TRIANGLEFAN, FirstVertexOffset, PrimitiveCount); } DBG_EXIT(_D3D_OP_MStream_ClipTriFan, 0); } // _D3D_OP_MStream_ClipTriFan //----------------------------------------------------------------------------- // // _D3D_OP_MStream_DrawRectSurface // // This function processes the D3DDP2OP_DRAWRECTSURFACE DP2 command token. // //----------------------------------------------------------------------------- VOID _D3D_OP_MStream_DrawRectSurface(P3_D3DCONTEXT* pContext, DWORD Handle, DWORD Flags, PVOID lpPrim) { // High order surfaces are only supported for hw/drivers with // TnL support and 1.0 vertex shader support } // _D3D_OP_MStream_DrawRectSurface //----------------------------------------------------------------------------- // // _D3D_OP_MStream_DrawTriSurface // // This function processes the D3DDP2OP_DRAWTRISURFACE DP2 command token. // //----------------------------------------------------------------------------- VOID _D3D_OP_MStream_DrawTriSurface(P3_D3DCONTEXT* pContext, DWORD Handle, DWORD Flags, PVOID lpPrim) { // High order surfaces are only supported for hw/drivers with // TnL support and 1.0 vertex shader support } // _D3D_OP_MStream_DrawTriSurface #endif // DX8_MULTSTREAMS //----------------------------------------------------------------------------- // // _D3D_OP_Viewport // // This function processes the D3DDP2OP_VIEWPORTINFO DP2 command token. // //----------------------------------------------------------------------------- VOID _D3D_OP_Viewport(P3_D3DCONTEXT* pContext, D3DHAL_DP2VIEWPORTINFO* lpvp) { #if DX7_D3DSTATEBLOCKS if ( pContext->bStateRecMode ) { _D3D_SB_Record_Viewport(pContext, lpvp); } else #endif // DX7_D3DSTATEBLOCKS { pContext->ViewportInfo = *lpvp; DIRTY_VIEWPORT(pContext); } } // _D3D_OP_Viewport //----------------------------------------------------------------------------- // // _D3D_OP_ZRange // // This function processes the D3DDP2OP_ZRANGE DP2 command token. // //----------------------------------------------------------------------------- VOID _D3D_OP_ZRange(P3_D3DCONTEXT* pContext, D3DHAL_DP2ZRANGE* lpzr) { #if DX7_D3DSTATEBLOCKS if ( pContext->bStateRecMode ) { _D3D_SB_Record_ZRange(pContext, lpzr); } else #endif // DX7_D3DSTATEBLOCKS { pContext->ZRange = *lpzr; DIRTY_VIEWPORT(pContext); } } // _D3D_OP_ZRange //----------------------------------------------------------------------------- // // _D3D_OP_UpdatePalette // // This function processes the D3DDP2OP_UPDATEPALETTE DP2 command token. // // Note : This function is need to skip D3DDP2OP_UPDATEPALETTE sent down // by some DX6 apps, even if when PALETTE TEXTURE is not supported // Also notice that for legacy DX apps, the palette doesn't get // properly restored in another app transitions into full screen // mode and back. This is because the (legacy) runtimes don't // sent proper notification (through UpdatePalette/SetPalette) of // this event // //----------------------------------------------------------------------------- HRESULT _D3D_OP_UpdatePalette(P3_D3DCONTEXT* pContext, D3DHAL_DP2UPDATEPALETTE* pUpdatePalette, DWORD* pdwPalEntries) { #if DX7_PALETTETEXTURE D3DHAL_DP2UPDATEPALETTE* pPalette; P3_SURF_INTERNAL* pTexture; // Find internal palette pointer from handle pPalette = GetPaletteFromHandle(pContext, pUpdatePalette->dwPaletteHandle); // Palette doesn't exist if (! pPalette) { DISPDBG((WRNLVL, "_D3D_OP_UpdatePalette : Can't find palette")); return DDERR_INVALIDPARAMS; } // Check the range of palette entries if (pUpdatePalette->wStartIndex > LUT_ENTRIES) { DISPDBG((WRNLVL, "_D3D_OP_UpdatePalette : wStartIndex (%d) is bigger than 256", pUpdatePalette->wStartIndex)); return DDERR_INVALIDPARAMS; } if ((pUpdatePalette->wStartIndex + pUpdatePalette->wNumEntries) > LUT_ENTRIES) { DISPDBG((WRNLVL, "_D3D_OP_UpdatePalette : too many entries")); return DDERR_INVALIDPARAMS; } // Each palette is ARGB 8:8:8:8 memcpy(((LPBYTE)(pPalette + 1)) + pUpdatePalette->wStartIndex*sizeof(DWORD), pdwPalEntries, pUpdatePalette->wNumEntries*sizeof(DWORD)); // Check if the palette is in use // Palette Texture can not be used alone in the 2nd stage, so only the // 1st stage must be checked. if (pContext->TextureStageState[0].m_dwVal[D3DTSS_TEXTUREMAP]) { pTexture = GetSurfaceFromHandle(pContext, pContext->TextureStageState[0].m_dwVal[D3DTSS_TEXTUREMAP]); if (pTexture) { if ((pTexture->pFormatSurface->DeviceFormat == SURF_CI8) && (pTexture->dwPaletteHandle == pUpdatePalette->dwPaletteHandle)) { DIRTY_TEXTURE(pContext); } } } return DD_OK; #else return DD_OK; #endif // DX7_PALETTETEXTURE } // D3D_OP_UpdatePalette //----------------------------------------------------------------------------- // // _D3D_OP_SetPalette // // This function processes the D3DDP2OP_SETPALETTE DP2 command token. // // Note : This function is need to skip D3DDP2OP_SETPALETTE sent down // by some DX6 apps, even if when PALETTE TEXTURE is not supported // //----------------------------------------------------------------------------- HRESULT _D3D_OP_SetPalettes(P3_D3DCONTEXT* pContext, D3DHAL_DP2SETPALETTE* pSetPalettes, int iNumSetPalettes) { #if DX7_PALETTETEXTURE int i; P3_SURF_INTERNAL* pTexture; D3DHAL_DP2UPDATEPALETTE* pPalette; // Loop to process N surface palette association for (i = 0; i < iNumSetPalettes; i++, pSetPalettes++) { DISPDBG((DBGLVL,"SETPALETTE: Binding surf # %d to palette # %d", pSetPalettes->dwSurfaceHandle, pSetPalettes->dwPaletteHandle)); // Find internal surface pointer from handle pTexture = GetSurfaceFromHandle(pContext, pSetPalettes->dwSurfaceHandle); if (! pTexture) { // Associated texture can't be found DISPDBG((WRNLVL, "SetPalettes : invalid texture handle %08lx", pSetPalettes->dwSurfaceHandle)); return DDERR_INVALIDPARAMS; } // Create the internal palette structure if necessary if (pSetPalettes->dwPaletteHandle) { // Find internal palette pointer from handle pPalette = GetPaletteFromHandle(pContext, pSetPalettes->dwPaletteHandle); if (! pPalette) { pPalette = (D3DHAL_DP2UPDATEPALETTE *) HEAP_ALLOC(FL_ZERO_MEMORY, sizeof(D3DHAL_DP2UPDATEPALETTE) + LUT_ENTRIES*sizeof(DWORD), ALLOC_TAG_DX(P)); // Out of memory case if (! pPalette) { DISPDBG((WRNLVL, "_D3D_OP_SetPalettes : Out of memory.")); return DDERR_OUTOFMEMORY; } // Add this texture to the surface list if (! PA_SetEntry(pContext->pPalettePointerArray, pSetPalettes->dwPaletteHandle, pPalette)) { HEAP_FREE(pPalette); DISPDBG((WRNLVL, "_D3D_OP_SetPalettes : " "PA_SetEntry() failed.")); return DDERR_OUTOFMEMORY; } // Set up the internal data structure pPalette->dwPaletteHandle = pSetPalettes->dwPaletteHandle; pPalette->wStartIndex = 0; pPalette->wNumEntries = LUT_ENTRIES; } } // Record palette handle and flags in internal surface data pTexture->dwPaletteHandle = pSetPalettes->dwPaletteHandle; pTexture->dwPaletteFlags = pSetPalettes->dwPaletteFlags; // Mark texture as dirty if current texture is affected if ((pContext->TextureStageState[0].m_dwVal[D3DTSS_TEXTUREMAP] == pSetPalettes->dwSurfaceHandle) || (pContext->TextureStageState[1].m_dwVal[D3DTSS_TEXTUREMAP] == pSetPalettes->dwSurfaceHandle)) { DIRTY_TEXTURE(pContext); } } return DD_OK; #else return DD_OK; #endif // DX7_PALETTETEXTURE } // _D3D_OP_SetPalettes