/******************************Module*Header**********************************\ * * ******************* * * D3D SAMPLE CODE * * ******************* * * Module Name: d3ddx6.c * * Content: Direct3D DX6 Callback function interface * * Copyright (c) 1994-1998 3Dlabs Inc. Ltd. All rights reserved. * Copyright (c) 1995-1999 Microsoft Corporation. All rights reserved. \*****************************************************************************/ #include "precomp.h" #include "d3dhw.h" #include "d3dcntxt.h" #include "dd.h" #include "d3dtxman.h" #define ALLOC_TAG ALLOC_TAG_6D2P //----------------------------------------------------------------------------- // // DX6 allows driver-level acceleration of the new vertex-buffer API. It // allows data and commands, indices and statechanges to be contained in // two separate DirectDraw surfaces. The DirectDraw surfaces can reside // in system, AGP, or video memory depending on the type of allocation // requested by the user The interface is designed to accomodate legacy // ExecuteBuffer applications with no driver impact. This allows higher // performance on both legacy applications as well as the highest // possible performance through the vertex buffer API. // //----------------------------------------------------------------------------- #define STARTVERTEXSIZE (sizeof(D3DHAL_DP2STARTVERTEX)) // Macros for updating properly our instruction pointer to our next instruction // in the command buffer #define NEXTINSTRUCTION(ptr, type, num, extrabytes) \ NEXTINSTRUCTION_S(ptr, sizeof(type), num, extrabytes) #define NEXTINSTRUCTION_S(ptr, typesize, num, extrabytes) \ ptr = (LPD3DHAL_DP2COMMAND)((LPBYTE)ptr + sizeof(D3DHAL_DP2COMMAND) + \ ((num) * (typesize)) + (extrabytes)) // Error reporting macro , sets up error code and exits DrawPrimitives2 #define PARSE_ERROR_AND_EXIT( pDP2Data, pIns, pStartIns, ddrvalue) \ { \ pDP2Data->dwErrorOffset = (DWORD)((LPBYTE)pIns-(LPBYTE)pStartIns); \ pDP2Data->ddrval = ddrvalue; \ goto Exit_DrawPrimitives2; \ } // Macros for verifying validity of the command and vertex buffers. This MUST // be done by the driver even on free builds as the runtime avoids this check // in order to not parse the command buffer too. #define CHECK_CMDBUF_LIMITS( pDP2Data, pBuf, type, num, extrabytes) \ CHECK_CMDBUF_LIMITS_S( pDP2Data, pBuf, sizeof(type), num, extrabytes) #define CHECK_CMDBUF_LIMITS_S( pDP2Data, pBuf, typesize, num, extrabytes) \ { \ LPBYTE pBase,pEnd,pBufEnd; \ pBase = (LPBYTE)(pDP2Data->lpDDCommands->lpGbl->fpVidMem + \ pDP2Data->dwCommandOffset); \ pEnd = pBase + pDP2Data->dwCommandLength; \ pBufEnd = ((LPBYTE)pBuf + ((num) * (typesize)) + (extrabytes) - 1); \ if (! ((LPBYTE)pBufEnd < pEnd) && ( pBase <= (LPBYTE)pBuf)) \ { \ DBG_D3D((0,"DX6 D3D: Trying to read past Command Buffer limits " \ "%x %x %x %x",pBase ,(LPBYTE)pBuf, pBufEnd, pEnd )); \ PARSE_ERROR_AND_EXIT( pDP2Data, lpIns, lpInsStart, \ D3DERR_COMMAND_UNPARSED ); \ } \ } #define CHECK_DATABUF_LIMITS( pDP2Data, iIndex) \ { \ if (! (((LONG)iIndex >= 0) && \ ((LONG)iIndex <(LONG)pDP2Data->dwVertexLength))) \ { \ DBG_D3D((0,"DX6 D3D: Trying to read past Vertex Buffer limits " \ "%d limit= %d ",(LONG)iIndex, (LONG)pDP2Data->dwVertexLength));\ PARSE_ERROR_AND_EXIT( pDP2Data, lpIns, lpInsStart, \ D3DERR_COMMAND_UNPARSED ); \ } \ } // Macros for accessing vertexes in the vertex buffer based on an index or on // a previous accessed vertex #define LP_FVF_VERTEX(lpBaseAddr, wIndex, P2FVFOffs) \ (LPD3DTLVERTEX)((LPBYTE)(lpBaseAddr) + (wIndex) * (P2FVFOffs).dwStride) #define LP_FVF_NXT_VTX(lpVtx, P2FVFOffs ) \ (LPD3DTLVERTEX)((LPBYTE)(lpVtx) + (P2FVFOffs).dwStride) // Forward declaration of utility functions DWORD __CheckFVFRequest(DWORD dwFVF, LPP2FVFOFFSETS lpP2FVFOff); D3DFVFDRAWTRIFUNCPTR __HWSetTriangleFunc(PERMEDIA_D3DCONTEXT *pContext); HRESULT __Clear( PERMEDIA_D3DCONTEXT* pContext, DWORD dwFlags, DWORD dwFillColor, D3DVALUE dvFillDepth, DWORD dwFillStencil, LPD3DRECT lpRects, DWORD dwNumRects); HRESULT __TextureBlt(PERMEDIA_D3DCONTEXT* pContext, D3DHAL_DP2TEXBLT* lpdp2texblt); HRESULT __SetRenderTarget(PERMEDIA_D3DCONTEXT* pContext, DWORD hRenderTarget, DWORD hZBuffer); HRESULT __PaletteUpdate(PERMEDIA_D3DCONTEXT* pContext, DWORD dwPaletteHandle, WORD wStartIndex, WORD wNumEntries, BYTE * pPaletteData); HRESULT __PaletteSet(PERMEDIA_D3DCONTEXT* pContext, DWORD dwSurfaceHandle, DWORD dwPaletteHandle, DWORD dwPaletteFlags); void __BeginStateSet(PERMEDIA_D3DCONTEXT*, DWORD); void __EndStateSet(PERMEDIA_D3DCONTEXT*); void __DeleteStateSet(PERMEDIA_D3DCONTEXT*, DWORD); void __ExecuteStateSet(PERMEDIA_D3DCONTEXT*, DWORD); void __CaptureStateSet(PERMEDIA_D3DCONTEXT*, DWORD); void __RestoreD3DContext(PPDev ppdev, PERMEDIA_D3DCONTEXT* pContext); //-----------------------------Public Routine---------------------------------- // // DWORD D3DDrawPrimitives2 // // The D3DDrawPrimitives2 callback is filled in by drivers which directly // support the rendering primitives using the new DDI. If this entry is // left as NULL, the API will be emulated through DX5-level HAL interfaces. // // PARAMETERS // // lpdp2d This structure is used when D3DDrawPrimitives2 is called // to draw a set of primitives using a vertex buffer. The // surface specified by the lpDDCommands in // D3DHAL_DRAWPRIMITIVES2DATA contains a sequence of // D3DHAL_DP2COMMAND structures. Each D3DHAL_DP2COMMAND // specifies either a primitive to draw, a state change to // process, or a re-base command. // //----------------------------------------------------------------------------- DWORD CALLBACK D3DDrawPrimitives2_P2( LPD3DHAL_DRAWPRIMITIVES2DATA lpdp2d ); DWORD CALLBACK D3DDrawPrimitives2( LPD3DHAL_DRAWPRIMITIVES2DATA lpdp2d ) { // User memory might become invalid under some circumstances, // exception handler is used for protection __try { return (D3DDrawPrimitives2_P2(lpdp2d)); } __except(EXCEPTION_EXECUTE_HANDLER) { // On Perm2 driver, no special handling is done DBG_D3D((0, "D3DDrawPrimitives2 : exception happened.")); lpdp2d->ddrval = DDERR_EXCEPTION; return (DDHAL_DRIVER_HANDLED); } } DWORD CALLBACK D3DDrawPrimitives2_P2( LPD3DHAL_DRAWPRIMITIVES2DATA lpdp2d ) { LPDDRAWI_DDRAWSURFACE_LCL lpCmdLcl, lpDataLcl; LPD3DHAL_DP2COMMAND lpIns, lpResumeIns; LPD3DTLVERTEX lpVertices=NULL, lpV0, lpV1, lpV2, lpV3; LPBYTE lpInsStart, lpPrim; PERMEDIA_D3DCONTEXT *pContext; UINT i,j; WORD wCount, wIndex, wIndex1, wIndex2, wIndex3, wFlags, wIndxBase; HRESULT ddrval; P2FVFOFFSETS P2FVFOff; D3DHAL_DP2TEXTURESTAGESTATE *lpRState; D3DFVFDRAWTRIFUNCPTR pTriangle; D3DFVFDRAWPNTFUNCPTR pPoint; DWORD dwEdgeFlags; DBG_D3D((6,"Entering D3DDrawPrimitives2")); DBG_D3D((8," dwhContext = %x",lpdp2d->dwhContext)); DBG_D3D((8," dwFlags = %x",lpdp2d->dwFlags)); DBG_D3D((8," dwVertexType = %d",lpdp2d->dwVertexType)); DBG_D3D((8," dwCommandOffset = %d",lpdp2d->dwCommandOffset)); DBG_D3D((8," dwCommandLength = %d",lpdp2d->dwCommandLength)); DBG_D3D((8," dwVertexOffset = %d",lpdp2d->dwVertexOffset)); DBG_D3D((8," dwVertexLength = %d",lpdp2d->dwVertexLength)); // Retrieve permedia d3d context from context handle pContext = (PERMEDIA_D3DCONTEXT*)ContextSlots[lpdp2d->dwhContext]; // Check if we got a valid context CHK_CONTEXT(pContext, lpdp2d->ddrval, "DrawPrimitives2"); PPDev ppdev = pContext->ppdev; PERMEDIA_DEFS(ppdev); __P2RegsSoftwareCopy* pSoftPermedia = &pContext->Hdr.SoftCopyP2Regs; // Switch hw context, and force the next switch to wait for the Permedia SET_CURRENT_D3D_CONTEXT(pContext->hPermediaContext); // Restore our D3D rendering context __RestoreD3DContext(ppdev, pContext); // Get appropriate pointers to command buffer lpInsStart = (LPBYTE)(lpdp2d->lpDDCommands->lpGbl->fpVidMem); if (lpInsStart == NULL) { DBG_D3D((0,"DX6 Command Buffer pointer is null")); lpdp2d->ddrval = DDERR_INVALIDPARAMS; goto Exit_DrawPrimitives2; } lpIns = (LPD3DHAL_DP2COMMAND)(lpInsStart + lpdp2d->dwCommandOffset); // Check if the FVF format being passed is valid. if (__CheckFVFRequest(lpdp2d->dwVertexType, &P2FVFOff) != DD_OK) { DBG_D3D((0,"DrawPrimitives2 cannot handle " "Flexible Vertex Format requested")); PARSE_ERROR_AND_EXIT(lpdp2d, lpIns, lpInsStart, D3DERR_COMMAND_UNPARSED); } // Check if vertex size calculated from dwVertexType is the same as // dwVertexSize, this is to make sure that CHECK_DATABUF_LIMITS's index // checking is done using the correct step size if (lpdp2d->dwVertexSize != P2FVFOff.dwStride) { DBG_D3D((0,"DrawPrimitives2 : invalid vertex size from runtime.")); PARSE_ERROR_AND_EXIT(lpdp2d, lpIns, lpInsStart, D3DERR_COMMAND_UNPARSED); } // Process commands while we haven't exhausted the command buffer while ((LPBYTE)lpIns < (lpInsStart + lpdp2d->dwCommandLength + lpdp2d->dwCommandOffset)) { // Get pointer to first primitive structure past the D3DHAL_DP2COMMAND lpPrim = (LPBYTE)lpIns + sizeof(D3DHAL_DP2COMMAND); DBG_D3D((4,"D3DDrawPrimitive2: parsing instruction %d count = %d @ %x", lpIns->bCommand, lpIns->wPrimitiveCount, lpIns)); // If our next command involves some actual rendering, we have to make // sure that our rendering context is realized switch( lpIns->bCommand ) { case D3DDP2OP_POINTS: case D3DDP2OP_LINELIST: case D3DDP2OP_INDEXEDLINELIST: case D3DDP2OP_INDEXEDLINELIST2: case D3DDP2OP_LINESTRIP: case D3DDP2OP_INDEXEDLINESTRIP: case D3DDP2OP_TRIANGLELIST: case D3DDP2OP_INDEXEDTRIANGLELIST: case D3DDP2OP_INDEXEDTRIANGLELIST2: case D3DDP2OP_TRIANGLESTRIP: case D3DDP2OP_INDEXEDTRIANGLESTRIP: case D3DDP2OP_TRIANGLEFAN: case D3DDP2OP_INDEXEDTRIANGLEFAN: // Check if vertex buffer resides in user memory or in a DDraw surface if (NULL == lpVertices) { if (NULL == lpdp2d->lpVertices) { DBG_D3D((0,"DX6 Vertex Buffer pointer is null")); lpdp2d->ddrval = DDERR_INVALIDPARAMS; goto Exit_DrawPrimitives2; } if (lpdp2d->dwFlags & D3DHALDP2_USERMEMVERTICES) { // Get appropriate pointer to vertices , memory is already secured lpVertices = (LPD3DTLVERTEX)((LPBYTE)lpdp2d->lpVertices + lpdp2d->dwVertexOffset); } else { // Get appropriate pointer to vertices lpVertices = (LPD3DTLVERTEX)((LPBYTE)lpdp2d->lpDDVertex->lpGbl->fpVidMem + lpdp2d->dwVertexOffset); } if (NULL == lpVertices) { DBG_D3D((0,"DX6 Vertex Buffer pointer is null")); lpdp2d->ddrval = DDERR_INVALIDPARAMS; goto Exit_DrawPrimitives2; } } // fall through intentionally, no break here case D3DDP2OP_LINELIST_IMM: case D3DDP2OP_TRIANGLEFAN_IMM: // Update triangle rendering function pTriangle = __HWSetTriangleFunc(pContext); pPoint = __HWSetPointFunc(pContext, &P2FVFOff); // Handle State changes that may need to update the chip if (pContext->dwDirtyFlags) { // Handle the dirty states __HandleDirtyPermediaState(ppdev, pContext, &P2FVFOff); } break; } // Execute the current command buffer command switch( lpIns->bCommand ) { case D3DDP2OP_RENDERSTATE: // Specifies a render state change that requires processing. // The rendering state to change is specified by one or more // D3DHAL_DP2RENDERSTATE structures following D3DHAL_DP2COMMAND. DBG_D3D((8,"D3DDP2OP_RENDERSTATE " "state count = %d", lpIns->wStateCount)); // Check we are in valid buffer memory CHECK_CMDBUF_LIMITS(lpdp2d, lpPrim, D3DHAL_DP2RENDERSTATE, lpIns->wStateCount, 0); lpdp2d->ddrval = __ProcessPermediaStates(pContext, lpIns->wStateCount, (LPD3DSTATE) (lpPrim), lpdp2d->lpdwRStates); if ( FAILED(lpdp2d->ddrval) ) { DBG_D3D((2,"Error processing D3DDP2OP_RENDERSTATE")); PARSE_ERROR_AND_EXIT(lpdp2d, lpIns, lpInsStart, ddrval); } NEXTINSTRUCTION(lpIns, D3DHAL_DP2RENDERSTATE, lpIns->wStateCount, 0); break; case D3DDP2OP_TEXTURESTAGESTATE: // Specifies texture stage state changes, having wStateCount // D3DNTHAL_DP2TEXTURESTAGESTATE structures follow the command // buffer. For each, the driver should update its internal // texture state associated with the texture at dwStage to // reflect the new value based on TSState. DBG_D3D((8,"D3DDP2OP_TEXTURESTAGESTATE")); // Verify the command buffer validity CHECK_CMDBUF_LIMITS(lpdp2d, lpPrim, D3DHAL_DP2TEXTURESTAGESTATE, lpIns->wStateCount, 0); lpRState = (D3DHAL_DP2TEXTURESTAGESTATE *)(lpPrim); for (i = 0; i < lpIns->wStateCount; i++) { if (0 == lpRState->wStage) { // Tell __HWSetupPrimitive to look at stage state data DIRTY_MULTITEXTURE; if ((lpRState->TSState >= D3DTSS_TEXTUREMAP) && (lpRState->TSState <= D3DTSS_TEXTURETRANSFORMFLAGS)) { #if D3D_STATEBLOCKS if (!pContext->bStateRecMode) { #endif //D3D_STATEBLOCKS if (pContext->TssStates[lpRState->TSState] != lpRState->dwValue) { // Store value associated to this stage state pContext->TssStates[lpRState->TSState] = lpRState->dwValue; // Perform any necessary preprocessing of it __HWPreProcessTSS(pContext, 0, lpRState->TSState, lpRState->dwValue); DBG_D3D((8,"TSS State Chg , Stage %d, " "State %d, Value %d", (LONG)lpRState->wStage, (LONG)lpRState->TSState, (LONG)lpRState->dwValue)); DIRTY_TEXTURE; //AZN5 } #if D3D_STATEBLOCKS } else { if (pContext->pCurrSS != NULL) { DBG_D3D((6,"Recording RS %x = %x", lpRState->TSState, lpRState->dwValue)); // Recording the state in a stateblock pContext->pCurrSS->u.uc.TssStates[lpRState->TSState] = lpRState->dwValue; FLAG_SET(pContext->pCurrSS->u.uc.bStoredTSS, lpRState->TSState); } } #endif //D3D_STATEBLOCKS } else { DBG_D3D((2,"Unhandled texture stage state %d value %d", (LONG)lpRState->TSState, (LONG)lpRState->dwValue)); } } else { DBG_D3D((0,"Texture Stage other than 0 received," " not supported in hw")); } lpRState ++; } NEXTINSTRUCTION(lpIns, D3DHAL_DP2TEXTURESTAGESTATE, lpIns->wStateCount, 0); break; case D3DNTDP2OP_VIEWPORTINFO: // Specifies the clipping rectangle used for guard-band // clipping by guard-band aware drivers. The clipping // rectangle (i.e. the viewing rectangle) is specified // by the D3DHAL_DP2 VIEWPORTINFO structures following // D3DHAL_DP2COMMAND // Verify the command buffer validity CHECK_CMDBUF_LIMITS(lpdp2d, lpPrim, D3DHAL_DP2VIEWPORTINFO, lpIns->wStateCount, 0); // We don't implement guard band clipping in this driver so // we just skip any of this data that might be sent to us NEXTINSTRUCTION(lpIns, D3DHAL_DP2VIEWPORTINFO, lpIns->wStateCount, 0); break; case D3DNTDP2OP_WINFO: // Specifies the w-range for W buffering. It is specified // by one or more D3DHAL_DP2WINFO structures following // D3DHAL_DP2COMMAND. // Verify the command buffer validity CHECK_CMDBUF_LIMITS(lpdp2d, lpPrim, D3DHAL_DP2WINFO, lpIns->wStateCount, 0); // We dont implement a w-buffer in this driver so we just // skip any of this data that might be sent to us NEXTINSTRUCTION(lpIns, D3DHAL_DP2WINFO, lpIns->wStateCount, 0); break; case D3DDP2OP_POINTS: DBG_D3D((8,"D3DDP2OP_POINTS")); // Point primitives in vertex buffers are defined by the // D3DHAL_DP2POINTS structure. The driver should render // wCount points starting at the initial vertex specified // by wFirst. Then for each D3DHAL_DP2POINTS, the points // rendered will be (wFirst),(wFirst+1),..., // (wFirst+(wCount-1)). The number of D3DHAL_DP2POINTS // structures to process is specified by the wPrimitiveCount // field of D3DHAL_DP2COMMAND. // Verify the command buffer validity CHECK_CMDBUF_LIMITS(lpdp2d, lpPrim, D3DHAL_DP2POINTS, lpIns->wPrimitiveCount, 0); for (i = lpIns->wPrimitiveCount; i > 0; i--) { wIndex = ((D3DHAL_DP2POINTS*)lpPrim)->wVStart; wCount = ((D3DHAL_DP2POINTS*)lpPrim)->wCount; lpV0 = LP_FVF_VERTEX(lpVertices, wIndex, P2FVFOff); // Check first & last vertex CHECK_DATABUF_LIMITS(lpdp2d, wIndex); CHECK_DATABUF_LIMITS(lpdp2d, ((LONG)wIndex + wCount - 1)); for (j = 0; j < wCount; j++) { (*pPoint)(pContext, lpV0, &P2FVFOff); lpV0 = LP_FVF_NXT_VTX(lpV0, P2FVFOff); } lpPrim += sizeof(D3DHAL_DP2POINTS); } NEXTINSTRUCTION(lpIns, D3DHAL_DP2POINTS, lpIns->wPrimitiveCount, 0); break; case D3DDP2OP_LINELIST: DBG_D3D((8,"D3DDP2OP_LINELIST")); // Non-indexed vertex-buffer line lists are defined by the // D3DHAL_DP2LINELIST structure. Given an initial vertex, // the driver will render a sequence of independent lines, // processing two new vertices with each line. The number // of lines to render is specified by the wPrimitiveCount // field of D3DHAL_DP2COMMAND. The sequence of lines // rendered will be // (wVStart, wVStart+1),(wVStart+2, wVStart+3),..., // (wVStart+(wPrimitiveCount-1)*2), wVStart+wPrimitiveCount*2 - 1). // Verify the command buffer validity CHECK_CMDBUF_LIMITS(lpdp2d, lpPrim, D3DHAL_DP2LINELIST, 1, 0); wIndex = ((D3DHAL_DP2LINELIST*)lpPrim)->wVStart; lpV0 = LP_FVF_VERTEX(lpVertices, wIndex, P2FVFOff); lpV1 = LP_FVF_NXT_VTX(lpV0, P2FVFOff); // Check first & last vertex CHECK_DATABUF_LIMITS(lpdp2d, wIndex); CHECK_DATABUF_LIMITS(lpdp2d, ((LONG)wIndex + 2*lpIns->wPrimitiveCount - 1) ); for (i = lpIns->wPrimitiveCount; i > 0; i--) { P2_Draw_FVF_Line(pContext, lpV0, lpV1, lpV0, &P2FVFOff); lpV0 = LP_FVF_NXT_VTX(lpV1, P2FVFOff); lpV1 = LP_FVF_NXT_VTX(lpV0, P2FVFOff); } NEXTINSTRUCTION(lpIns, D3DHAL_DP2LINELIST, 1, 0); break; case D3DDP2OP_INDEXEDLINELIST: DBG_D3D((8,"D3DDP2OP_INDEXEDLINELIST")); // The D3DHAL_DP2INDEXEDLINELIST structure specifies // unconnected lines to render using vertex indices. // The line endpoints for each line are specified by wV1 // and wV2. The number of lines to render using this // structure is specified by the wPrimitiveCount field of // D3DHAL_DP2COMMAND. The sequence of lines // rendered will be (wV[0], wV[1]), (wV[2], wV[3]),... // (wVStart[(wPrimitiveCount-1)*2], wVStart[wPrimitiveCount*2-1]). // Verify the command buffer validity CHECK_CMDBUF_LIMITS(lpdp2d, lpPrim, D3DHAL_DP2INDEXEDLINELIST, lpIns->wPrimitiveCount, 0); for (i = lpIns->wPrimitiveCount; i > 0; i--) { wIndex1 = ((D3DHAL_DP2INDEXEDLINELIST*)lpPrim)->wV1; wIndex2 = ((D3DHAL_DP2INDEXEDLINELIST*)lpPrim)->wV2; lpV1 = LP_FVF_VERTEX(lpVertices, wIndex1, P2FVFOff); lpV2 = LP_FVF_VERTEX(lpVertices, wIndex2, P2FVFOff); // Must check each new vertex CHECK_DATABUF_LIMITS(lpdp2d, wIndex1); CHECK_DATABUF_LIMITS(lpdp2d, wIndex2); P2_Draw_FVF_Line(pContext, lpV1, lpV2, lpV1, &P2FVFOff); lpPrim += sizeof(D3DHAL_DP2INDEXEDLINELIST); } NEXTINSTRUCTION(lpIns, D3DHAL_DP2INDEXEDLINELIST, lpIns->wPrimitiveCount, 0); break; case D3DDP2OP_INDEXEDLINELIST2: DBG_D3D((8,"D3DDP2OP_INDEXEDLINELIST2")); // The D3DHAL_DP2INDEXEDLINELIST structure specifies // unconnected lines to render using vertex indices. // The line endpoints for each line are specified by wV1 // and wV2. The number of lines to render using this // structure is specified by the wPrimitiveCount field of // D3DHAL_DP2COMMAND. The sequence of lines // rendered will be (wV[0], wV[1]), (wV[2], wV[3]), // (wVStart[(wPrimitiveCount-1)*2], wVStart[wPrimitiveCount*2-1]). // The indexes are relative to a base index value that // immediately follows the command // Verify the command buffer validity CHECK_CMDBUF_LIMITS(lpdp2d, lpPrim, D3DHAL_DP2INDEXEDLINELIST, lpIns->wPrimitiveCount, STARTVERTEXSIZE); // Access base index wIndxBase = ((D3DHAL_DP2STARTVERTEX*)lpPrim)->wVStart; lpPrim = lpPrim + sizeof(D3DHAL_DP2STARTVERTEX); for (i = lpIns->wPrimitiveCount; i > 0; i--) { wIndex1 = ((D3DHAL_DP2INDEXEDLINELIST*)lpPrim)->wV1; wIndex2 = ((D3DHAL_DP2INDEXEDLINELIST*)lpPrim)->wV2; lpV1 = LP_FVF_VERTEX(lpVertices, (wIndex1+wIndxBase), P2FVFOff); lpV2 = LP_FVF_VERTEX(lpVertices, (wIndex2+wIndxBase), P2FVFOff); // Must check each new vertex CHECK_DATABUF_LIMITS(lpdp2d, wIndex1 + wIndxBase); CHECK_DATABUF_LIMITS(lpdp2d, wIndex2 + wIndxBase); P2_Draw_FVF_Line(pContext, lpV1, lpV2, lpV1, &P2FVFOff); lpPrim += sizeof(D3DHAL_DP2INDEXEDLINELIST); } NEXTINSTRUCTION(lpIns, D3DHAL_DP2INDEXEDLINELIST, lpIns->wPrimitiveCount, STARTVERTEXSIZE); break; case D3DDP2OP_LINESTRIP: DBG_D3D((8,"D3DDP2OP_LINESTRIP")); // Non-index line strips rendered with vertex buffers are // specified using D3DHAL_DP2LINESTRIP. The first vertex // in the line strip is specified by wVStart. The // number of lines to process is specified by the // wPrimitiveCount field of D3DHAL_DP2COMMAND. The sequence // of lines rendered will be (wVStart, wVStart+1), // (wVStart+1, wVStart+2),(wVStart+2, wVStart+3),..., // (wVStart+wPrimitiveCount, wVStart+wPrimitiveCount+1). // Verify the command buffer validity CHECK_CMDBUF_LIMITS(lpdp2d, lpPrim, D3DHAL_DP2LINESTRIP, 1, 0); wIndex = ((D3DHAL_DP2LINESTRIP*)lpPrim)->wVStart; lpV0 = LP_FVF_VERTEX(lpVertices, wIndex, P2FVFOff); lpV1 = LP_FVF_NXT_VTX(lpV0, P2FVFOff); // Check first & last vertex CHECK_DATABUF_LIMITS(lpdp2d, wIndex); CHECK_DATABUF_LIMITS(lpdp2d, wIndex + lpIns->wPrimitiveCount); for (i = lpIns->wPrimitiveCount; i > 0; i--) { P2_Draw_FVF_Line(pContext, lpV0, lpV1, lpV0, &P2FVFOff); lpV0 = lpV1; lpV1 = LP_FVF_NXT_VTX(lpV1, P2FVFOff); } NEXTINSTRUCTION(lpIns, D3DHAL_DP2LINESTRIP, 1, 0); break; case D3DDP2OP_INDEXEDLINESTRIP: DBG_D3D((8,"D3DDP2OP_INDEXEDLINESTRIP")); // Indexed line strips rendered with vertex buffers are // specified using D3DHAL_DP2INDEXEDLINESTRIP. The number // of lines to process is specified by the wPrimitiveCount // field of D3DHAL_DP2COMMAND. The sequence of lines // rendered will be (wV[0], wV[1]), (wV[1], wV[2]), // (wV[2], wV[3]), ... // (wVStart[wPrimitiveCount-1], wVStart[wPrimitiveCount]). // Although the D3DHAL_DP2INDEXEDLINESTRIP structure only // has enough space allocated for a single line, the wV // array of indices should be treated as a variable-sized // array with wPrimitiveCount+1 elements. // The indexes are relative to a base index value that // immediately follows the command // Verify the command buffer validity CHECK_CMDBUF_LIMITS(lpdp2d, lpPrim, WORD, lpIns->wPrimitiveCount + 1, STARTVERTEXSIZE); wIndxBase = ((D3DHAL_DP2STARTVERTEX*)lpPrim)->wVStart; lpPrim = lpPrim + sizeof(D3DHAL_DP2STARTVERTEX); // guard defensively against pathological commands if ( lpIns->wPrimitiveCount > 0 ) { wIndex1 = ((D3DHAL_DP2INDEXEDLINESTRIP*)lpPrim)->wV[0]; wIndex2 = ((D3DHAL_DP2INDEXEDLINESTRIP*)lpPrim)->wV[1]; lpV1 = lpV2 = LP_FVF_VERTEX(lpVertices, wIndex1+wIndxBase, P2FVFOff); //We need to check each vertex separately CHECK_DATABUF_LIMITS(lpdp2d, wIndex1 + wIndxBase); } for (i = 0; i < lpIns->wPrimitiveCount; i++) { lpV1 = lpV2; lpV2 = LP_FVF_VERTEX(lpVertices, wIndex2 + wIndxBase, P2FVFOff); CHECK_DATABUF_LIMITS(lpdp2d, wIndex2 + wIndxBase); P2_Draw_FVF_Line(pContext, lpV1, lpV2, lpV1, &P2FVFOff); if ( i % 2 ) { wIndex2 = ((D3DHAL_DP2INDEXEDLINESTRIP*)lpPrim)->wV[1]; } else if ( (i+1) < lpIns->wPrimitiveCount ) { // advance to the next element only if we're not done yet lpPrim += sizeof(D3DHAL_DP2INDEXEDLINESTRIP); wIndex2 = ((D3DHAL_DP2INDEXEDLINESTRIP*)lpPrim)->wV[0]; } } // Point to next D3DHAL_DP2COMMAND in the command buffer // Advance only as many vertex indices there are, with no padding! NEXTINSTRUCTION(lpIns, WORD, lpIns->wPrimitiveCount + 1, STARTVERTEXSIZE); break; case D3DDP2OP_TRIANGLELIST: DBG_D3D((8,"D3DDP2OP_TRIANGLELIST")); // Non-indexed vertex buffer triangle lists are defined by // the D3DHAL_DP2TRIANGLELIST structure. Given an initial // vertex, the driver will render independent triangles, // processing three new vertices with each triangle. The // number of triangles to render is specified by the // wPrimitveCount field of D3DHAL_DP2COMMAND. The sequence // of vertices processed will be (wVStart, wVStart+1, // vVStart+2), (wVStart+3, wVStart+4, vVStart+5),..., // (wVStart+(wPrimitiveCount-1)*3), wVStart+wPrimitiveCount*3-2, // vStart+wPrimitiveCount*3-1). // Verify the command buffer validity CHECK_CMDBUF_LIMITS(lpdp2d, lpPrim, D3DHAL_DP2TRIANGLELIST, 1, 0); wIndex = ((D3DHAL_DP2TRIANGLELIST*)lpPrim)->wVStart; lpV0 = LP_FVF_VERTEX(lpVertices, wIndex, P2FVFOff); lpV1 = LP_FVF_NXT_VTX(lpV0, P2FVFOff); lpV2 = LP_FVF_NXT_VTX(lpV1, P2FVFOff); // Check first & last vertex CHECK_DATABUF_LIMITS(lpdp2d, wIndex); CHECK_DATABUF_LIMITS(lpdp2d, ((LONG)wIndex + 3*lpIns->wPrimitiveCount - 1) ); for (i = lpIns->wPrimitiveCount; i > 0; i--) { if (!CULL_TRI(pContext,lpV0,lpV1,lpV2)) (*pTriangle)(pContext, lpV0, lpV1, lpV2, &P2FVFOff); lpV0 = LP_FVF_NXT_VTX(lpV2, P2FVFOff); lpV1 = LP_FVF_NXT_VTX(lpV0, P2FVFOff); lpV2 = LP_FVF_NXT_VTX(lpV1, P2FVFOff); } NEXTINSTRUCTION(lpIns, D3DHAL_DP2TRIANGLELIST, 1, 0); break; case D3DDP2OP_INDEXEDTRIANGLELIST: DBG_D3D((8,"D3DDP2OP_INDEXEDTRIANGLELIST")); // The D3DHAL_DP2INDEXEDTRIANGLELIST structure specifies // unconnected triangles to render with a vertex buffer. // The vertex indices are specified by wV1, wV2 and wV3. // The wFlags field allows specifying edge flags identical // to those specified by D3DOP_TRIANGLE. The number of // triangles to render (that is, number of // D3DHAL_DP2INDEXEDTRIANGLELIST structures to process) // is specified by the wPrimitiveCount field of // D3DHAL_DP2COMMAND. // This is the only indexed primitive where we don't get // an offset into the vertex buffer in order to maintain // DX3 compatibility. A new primitive // (D3DDP2OP_INDEXEDTRIANGLELIST2) has been added to handle // the corresponding DX6 primitive. // Verify the command buffer validity CHECK_CMDBUF_LIMITS(lpdp2d, lpPrim, D3DHAL_DP2INDEXEDTRIANGLELIST, lpIns->wPrimitiveCount, 0); for (i = lpIns->wPrimitiveCount; i > 0; i--) { wIndex1 = ((D3DHAL_DP2INDEXEDTRIANGLELIST*)lpPrim)->wV1; wIndex2 = ((D3DHAL_DP2INDEXEDTRIANGLELIST*)lpPrim)->wV2; wIndex3 = ((D3DHAL_DP2INDEXEDTRIANGLELIST*)lpPrim)->wV3; wFlags = ((D3DHAL_DP2INDEXEDTRIANGLELIST*)lpPrim)->wFlags; lpV1 = LP_FVF_VERTEX(lpVertices, wIndex1, P2FVFOff); lpV2 = LP_FVF_VERTEX(lpVertices, wIndex2, P2FVFOff); lpV3 = LP_FVF_VERTEX(lpVertices, wIndex3, P2FVFOff); // Must check each new vertex CHECK_DATABUF_LIMITS(lpdp2d, wIndex1); CHECK_DATABUF_LIMITS(lpdp2d, wIndex2); CHECK_DATABUF_LIMITS(lpdp2d, wIndex3); if (!CULL_TRI(pContext,lpV1,lpV2,lpV3)) { if (pContext->Hdr.FillMode == D3DFILL_POINT) { (*pPoint)( pContext, lpV1, &P2FVFOff); (*pPoint)( pContext, lpV2, &P2FVFOff); (*pPoint)( pContext, lpV3, &P2FVFOff); } else if (pContext->Hdr.FillMode == D3DFILL_WIREFRAME) { if ( wFlags & D3DTRIFLAG_EDGEENABLE1 ) P2_Draw_FVF_Line( pContext, lpV1, lpV2, lpV1, &P2FVFOff); if ( wFlags & D3DTRIFLAG_EDGEENABLE2 ) P2_Draw_FVF_Line( pContext, lpV2, lpV3, lpV1, &P2FVFOff); if ( wFlags & D3DTRIFLAG_EDGEENABLE3 ) P2_Draw_FVF_Line( pContext, lpV3, lpV1, lpV1, &P2FVFOff); } else (*pTriangle)(pContext, lpV1, lpV2, lpV3, &P2FVFOff); } lpPrim += sizeof(D3DHAL_DP2INDEXEDTRIANGLELIST); } NEXTINSTRUCTION(lpIns, D3DHAL_DP2INDEXEDTRIANGLELIST, lpIns->wPrimitiveCount, 0); break; case D3DDP2OP_INDEXEDTRIANGLELIST2: DBG_D3D((8,"D3DDP2OP_INDEXEDTRIANGLELIST2 ")); // The D3DHAL_DP2INDEXEDTRIANGLELIST2 structure specifies // unconnected triangles to render with a vertex buffer. // The vertex indices are specified by wV1, wV2 and wV3. // The wFlags field allows specifying edge flags identical // to those specified by D3DOP_TRIANGLE. The number of // triangles to render (that is, number of // D3DHAL_DP2INDEXEDTRIANGLELIST structures to process) // is specified by the wPrimitiveCount field of // D3DHAL_DP2COMMAND. // The indexes are relative to a base index value that // immediately follows the command // Verify the command buffer validity CHECK_CMDBUF_LIMITS(lpdp2d, lpPrim, D3DHAL_DP2INDEXEDTRIANGLELIST2, lpIns->wPrimitiveCount, STARTVERTEXSIZE); // Access base index here wIndxBase = ((D3DHAL_DP2STARTVERTEX*)lpPrim)->wVStart; lpPrim = lpPrim + sizeof(D3DHAL_DP2STARTVERTEX); for (i = lpIns->wPrimitiveCount; i > 0; i--) { wIndex1 = ((D3DHAL_DP2INDEXEDTRIANGLELIST2*)lpPrim)->wV1; wIndex2 = ((D3DHAL_DP2INDEXEDTRIANGLELIST2*)lpPrim)->wV2; wIndex3 = ((D3DHAL_DP2INDEXEDTRIANGLELIST2*)lpPrim)->wV3; lpV1 = LP_FVF_VERTEX(lpVertices, wIndex1+wIndxBase, P2FVFOff); lpV2 = LP_FVF_VERTEX(lpVertices, wIndex2+wIndxBase, P2FVFOff); lpV3 = LP_FVF_VERTEX(lpVertices, wIndex3+wIndxBase, P2FVFOff); // Must check each new vertex CHECK_DATABUF_LIMITS(lpdp2d, wIndex1 + wIndxBase); CHECK_DATABUF_LIMITS(lpdp2d, wIndex2 + wIndxBase); CHECK_DATABUF_LIMITS(lpdp2d, wIndex3 + wIndxBase); if (!CULL_TRI(pContext,lpV1,lpV2,lpV3)) { if (pContext->Hdr.FillMode == D3DFILL_POINT) { (*pPoint)( pContext, lpV1, &P2FVFOff); (*pPoint)( pContext, lpV2, &P2FVFOff); (*pPoint)( pContext, lpV3, &P2FVFOff); } else if (pContext->Hdr.FillMode == D3DFILL_WIREFRAME) { P2_Draw_FVF_Line( pContext, lpV1, lpV2, lpV1, &P2FVFOff); P2_Draw_FVF_Line( pContext, lpV2, lpV3, lpV1, &P2FVFOff); P2_Draw_FVF_Line( pContext, lpV3, lpV1, lpV1, &P2FVFOff); } else (*pTriangle)(pContext, lpV1, lpV2, lpV3, &P2FVFOff); } lpPrim += sizeof(D3DHAL_DP2INDEXEDTRIANGLELIST2); } NEXTINSTRUCTION(lpIns, D3DHAL_DP2INDEXEDTRIANGLELIST2, lpIns->wPrimitiveCount, STARTVERTEXSIZE); break; case D3DDP2OP_TRIANGLESTRIP: DBG_D3D((8,"D3DDP2OP_TRIANGLESTRIP")); // Non-index triangle strips rendered with vertex buffers // are specified using D3DHAL_DP2TRIANGLESTRIP. The first // vertex in the triangle strip is specified by wVStart. // The number of triangles to process is specified by the // wPrimitiveCount field of D3DHAL_DP2COMMAND. The sequence // of triangles rendered for the odd-triangles case will // be (wVStart, wVStart+1, vVStart+2), (wVStart+1, // wVStart+3, vVStart+2),.(wVStart+2, wVStart+3, // vVStart+4),.., (wVStart+wPrimitiveCount-1), // wVStart+wPrimitiveCount, vStart+wPrimitiveCount+1). For an // even number of , the last triangle will be ., // (wVStart+wPrimitiveCount-1, vStart+wPrimitiveCount+1, // wVStart+wPrimitiveCount). // Verify the command buffer validity CHECK_CMDBUF_LIMITS(lpdp2d, lpPrim, D3DHAL_DP2TRIANGLESTRIP, 1, 0); // guard defensively against pathological commands if ( lpIns->wPrimitiveCount > 0 ) { wIndex = ((D3DHAL_DP2TRIANGLESTRIP*)lpPrim)->wVStart; lpV2 = LP_FVF_VERTEX(lpVertices, wIndex, P2FVFOff); lpV1 = LP_FVF_NXT_VTX(lpV2, P2FVFOff); // Check first and last vertex CHECK_DATABUF_LIMITS(lpdp2d, wIndex); CHECK_DATABUF_LIMITS(lpdp2d, wIndex + lpIns->wPrimitiveCount + 1); } for (i = 0; i < lpIns->wPrimitiveCount; i++) { if ( i % 2 ) { lpV0 = lpV1; lpV1 = LP_FVF_NXT_VTX(lpV2, P2FVFOff); } else { lpV0 = lpV2; lpV2 = LP_FVF_NXT_VTX(lpV1, P2FVFOff); } if (!CULL_TRI(pContext,lpV0,lpV1,lpV2)) (*pTriangle)(pContext, lpV0, lpV1, lpV2, &P2FVFOff); } // Point to next D3DHAL_DP2COMMAND in the command buffer NEXTINSTRUCTION(lpIns, D3DHAL_DP2TRIANGLESTRIP, 1, 0); break; case D3DDP2OP_INDEXEDTRIANGLESTRIP: DBG_D3D((8,"D3DDP2OP_INDEXEDTRIANGLESTRIP")); // Indexed triangle strips rendered with vertex buffers are // specified using D3DHAL_DP2INDEXEDTRIANGLESTRIP. The number // of triangles to process is specified by the wPrimitiveCount // field of D3DHAL_DP2COMMAND. The sequence of triangles // rendered for the odd-triangles case will be // (wV[0],wV[1],wV[2]),(wV[1],wV[3],wV[2]), // (wV[2],wV[3],wV[4]),...,(wV[wPrimitiveCount-1], // wV[wPrimitiveCount],wV[wPrimitiveCount+1]). For an even // number of triangles, the last triangle will be // (wV[wPrimitiveCount-1],wV[wPrimitiveCount+1], // wV[wPrimitiveCount]).Although the // D3DHAL_DP2INDEXEDTRIANGLESTRIP structure only has // enough space allocated for a single line, the wV // array of indices should be treated as a variable-sized // array with wPrimitiveCount+2 elements. // The indexes are relative to a base index value that // immediately follows the command // Verify the command buffer validity CHECK_CMDBUF_LIMITS(lpdp2d, lpPrim, WORD, lpIns->wPrimitiveCount + 2, STARTVERTEXSIZE); // Access base index wIndxBase = ((D3DHAL_DP2STARTVERTEX*)lpPrim)->wVStart; lpPrim = lpPrim + sizeof(D3DHAL_DP2STARTVERTEX); // guard defensively against pathological commands if ( lpIns->wPrimitiveCount > 0 ) { wIndex = ((D3DHAL_DP2INDEXEDTRIANGLESTRIP*)lpPrim)->wV[0]; wIndex1 = ((D3DHAL_DP2INDEXEDTRIANGLESTRIP*)lpPrim)->wV[1]; // We need to check each vertex CHECK_DATABUF_LIMITS(lpdp2d, wIndex + wIndxBase); CHECK_DATABUF_LIMITS(lpdp2d, wIndex1 + wIndxBase); lpV2 = LP_FVF_VERTEX(lpVertices, wIndex + wIndxBase, P2FVFOff); lpV1 = LP_FVF_VERTEX(lpVertices, wIndex1 + wIndxBase, P2FVFOff); } for (i = 0; i < lpIns->wPrimitiveCount; i++) { wIndex2 = ((D3DHAL_DP2INDEXEDTRIANGLESTRIP*)lpPrim)->wV[2]; // We need to check each new vertex CHECK_DATABUF_LIMITS(lpdp2d, wIndex2+wIndxBase); if ( i % 2 ) { lpV0 = lpV1; lpV1 = LP_FVF_VERTEX(lpVertices, wIndex2+wIndxBase, P2FVFOff); } else { lpV0 = lpV2; lpV2 = LP_FVF_VERTEX(lpVertices, wIndex2+wIndxBase, P2FVFOff); } if (!CULL_TRI(pContext,lpV0,lpV1,lpV2)) (*pTriangle)(pContext, lpV0, lpV1, lpV2, &P2FVFOff); // We will advance our pointer only one WORD in order // to fetch the next index lpPrim += sizeof(WORD); } // Point to next D3DHAL_DP2COMMAND in the command buffer NEXTINSTRUCTION(lpIns, WORD , lpIns->wPrimitiveCount + 2, STARTVERTEXSIZE); break; case D3DDP2OP_TRIANGLEFAN: DBG_D3D((8,"D3DDP2OP_TRIANGLEFAN")); // The D3DHAL_DP2TRIANGLEFAN structure is used to draw // non-indexed triangle fans. The sequence of triangles // rendered will be (wVstart+1, wVStart+2, wVStart), // (wVStart+2,wVStart+3,wVStart), (wVStart+3,wVStart+4 // wVStart),...,(wVStart+wPrimitiveCount, // wVStart+wPrimitiveCount+1,wVStart). // Verify the command buffer validity CHECK_CMDBUF_LIMITS(lpdp2d, lpPrim, D3DHAL_DP2TRIANGLEFAN, 1, 0); wIndex = ((D3DHAL_DP2TRIANGLEFAN*)lpPrim)->wVStart; lpV0 = LP_FVF_VERTEX(lpVertices, wIndex, P2FVFOff); lpV1 = LP_FVF_NXT_VTX(lpV0, P2FVFOff); lpV2 = LP_FVF_NXT_VTX(lpV1, P2FVFOff); // Check first & last vertex CHECK_DATABUF_LIMITS(lpdp2d, wIndex); CHECK_DATABUF_LIMITS(lpdp2d, wIndex + lpIns->wPrimitiveCount + 1); for (i = 0; i < lpIns->wPrimitiveCount; i++) { if (!CULL_TRI(pContext,lpV0,lpV1,lpV2)) (*pTriangle)(pContext, lpV1, lpV2, lpV0, &P2FVFOff); lpV1 = lpV2; lpV2 = LP_FVF_NXT_VTX(lpV2, P2FVFOff); } NEXTINSTRUCTION(lpIns, D3DHAL_DP2TRIANGLEFAN, 1, 0); break; case D3DDP2OP_INDEXEDTRIANGLEFAN: DBG_D3D((8,"D3DDP2OP_INDEXEDTRIANGLEFAN")); // The D3DHAL_DP2INDEXEDTRIANGLEFAN structure is used to // draw indexed triangle fans. The sequence of triangles // rendered will be (wV[1], wV[2],wV[0]), (wV[2], wV[3], // wV[0]), (wV[3], wV[4], wV[0]),..., // (wV[wPrimitiveCount], wV[wPrimitiveCount+1],wV[0]). // The indexes are relative to a base index value that // immediately follows the command // Verify the command buffer validity CHECK_CMDBUF_LIMITS(lpdp2d, lpPrim, WORD, lpIns->wPrimitiveCount + 2, STARTVERTEXSIZE); wIndxBase = ((D3DHAL_DP2STARTVERTEX*)lpPrim)->wVStart; lpPrim = lpPrim + sizeof(D3DHAL_DP2STARTVERTEX); // guard defensively against pathological commands if ( lpIns->wPrimitiveCount > 0 ) { wIndex = ((D3DHAL_DP2INDEXEDTRIANGLEFAN*)lpPrim)->wV[0]; wIndex1 = ((D3DHAL_DP2INDEXEDTRIANGLEFAN*)lpPrim)->wV[1]; lpV0 = LP_FVF_VERTEX(lpVertices, wIndex + wIndxBase, P2FVFOff); lpV1 = lpV2 = LP_FVF_VERTEX(lpVertices, wIndex1 + wIndxBase, P2FVFOff); // We need to check each vertex CHECK_DATABUF_LIMITS(lpdp2d, wIndex + wIndxBase); CHECK_DATABUF_LIMITS(lpdp2d, wIndex1 + wIndxBase); } for (i = 0; i < lpIns->wPrimitiveCount; i++) { wIndex2 = ((D3DHAL_DP2INDEXEDTRIANGLEFAN*)lpPrim)->wV[2]; lpV1 = lpV2; lpV2 = LP_FVF_VERTEX(lpVertices, wIndex2 + wIndxBase, P2FVFOff); // We need to check each vertex CHECK_DATABUF_LIMITS(lpdp2d, wIndex2 + wIndxBase); if (!CULL_TRI(pContext,lpV0,lpV1,lpV2)) (*pTriangle)(pContext, lpV1, lpV2, lpV0, &P2FVFOff); // We will advance our pointer only one WORD in order // to fetch the next index lpPrim += sizeof(WORD); } // Point to next D3DHAL_DP2COMMAND in the command buffer NEXTINSTRUCTION(lpIns, WORD , lpIns->wPrimitiveCount + 2, STARTVERTEXSIZE); break; case D3DDP2OP_LINELIST_IMM: DBG_D3D((8,"D3DDP2OP_LINELIST_IMM")); // Draw a set of lines specified by pairs of vertices // that immediately follow this instruction in the // command stream. The wPrimitiveCount member of the // D3DHAL_DP2COMMAND structure specifies the number // of lines that follow. The type and size of the // vertices are determined by the dwVertexType member // of the D3DHAL_DRAWPRIMITIVES2DATA structure. // Primitives in an IMM instruction are stored in the // command buffer and are DWORD aligned lpPrim = (LPBYTE)((ULONG_PTR)(lpPrim + 3 ) & ~3 ); // Verify the command buffer validity CHECK_CMDBUF_LIMITS_S(lpdp2d, lpPrim, P2FVFOff.dwStride, lpIns->wPrimitiveCount + 1, 0); // Get vertex pointers lpV0 = (LPD3DTLVERTEX)lpPrim; lpV1 = LP_FVF_NXT_VTX(lpV0, P2FVFOff); for (i = 0; i < lpIns->wPrimitiveCount; i++) { P2_Draw_FVF_Line(pContext, lpV0, lpV1, lpV0, &P2FVFOff); lpV0 = lpV1; lpV1 = LP_FVF_NXT_VTX(lpV1, P2FVFOff); } // Realign next command since vertices are dword aligned // and store # of primitives before affecting the pointer wCount = lpIns->wPrimitiveCount; lpIns = (LPD3DHAL_DP2COMMAND)(( ((ULONG_PTR)lpIns) + 3 ) & ~ 3); NEXTINSTRUCTION_S(lpIns, P2FVFOff.dwStride, wCount + 1, 0); break; case D3DDP2OP_TRIANGLEFAN_IMM: DBG_D3D((8,"D3DDP2OP_TRIANGLEFAN_IMM")); // Draw a triangle fan specified by pairs of vertices // that immediately follow this instruction in the // command stream. The wPrimitiveCount member of the // D3DHAL_DP2COMMAND structure specifies the number // of triangles that follow. The type and size of the // vertices are determined by the dwVertexType member // of the D3DHAL_DRAWPRIMITIVES2DATA structure. // Verify the command buffer validity for the first structure CHECK_CMDBUF_LIMITS(lpdp2d, lpPrim, BYTE , 0 , sizeof(D3DHAL_DP2TRIANGLEFAN_IMM)); // Get Edge flags (we still have to process them) dwEdgeFlags = ((D3DHAL_DP2TRIANGLEFAN_IMM *)lpPrim)->dwEdgeFlags; lpPrim = (LPBYTE)lpPrim + sizeof(D3DHAL_DP2TRIANGLEFAN_IMM); // Vertices in an IMM instruction are stored in the // command buffer and are DWORD aligned lpPrim = (LPBYTE)((ULONG_PTR)(lpPrim + 3 ) & ~3 ); // Verify the rest of the command buffer CHECK_CMDBUF_LIMITS_S(lpdp2d, lpPrim, P2FVFOff.dwStride, lpIns->wPrimitiveCount + 2, 0); // Get vertex pointers lpV0 = (LPD3DTLVERTEX)lpPrim; lpV1 = LP_FVF_NXT_VTX(lpV0, P2FVFOff); lpV2 = LP_FVF_NXT_VTX(lpV1, P2FVFOff); for (i = 0 ; i < lpIns->wPrimitiveCount ; i++) { if (!CULL_TRI(pContext,lpV0,lpV1,lpV2)) { if (pContext->Hdr.FillMode == D3DFILL_POINT) { if (0 == i) { (*pPoint)( pContext, lpV0, &P2FVFOff); (*pPoint)( pContext, lpV1, &P2FVFOff); } (*pPoint)( pContext, lpV2, &P2FVFOff); } else if (pContext->Hdr.FillMode == D3DFILL_WIREFRAME) { // dwEdgeFlags is a bit sequence representing the edge // flag for each one of the outer edges of the // triangle fan if (0 == i) { if (dwEdgeFlags & 0x0001) P2_Draw_FVF_Line( pContext, lpV0, lpV1, lpV0, &P2FVFOff); dwEdgeFlags >>= 1; } if (dwEdgeFlags & 0x0001) P2_Draw_FVF_Line( pContext, lpV1, lpV2, lpV0, &P2FVFOff); dwEdgeFlags >>= 1; if (i == (UINT)lpIns->wPrimitiveCount - 1) { // last triangle fan edge if (dwEdgeFlags & 0x0001) P2_Draw_FVF_Line( pContext, lpV2, lpV0, lpV0, &P2FVFOff); } } else (*pTriangle)(pContext, lpV1, lpV2, lpV0, &P2FVFOff); } lpV1 = lpV2; lpV2 = LP_FVF_NXT_VTX(lpV2, P2FVFOff); } // Realign next command since vertices are dword aligned // and store # of primitives before affecting the pointer wCount = lpIns->wPrimitiveCount; lpIns = (LPD3DHAL_DP2COMMAND)(( ((ULONG_PTR)lpIns) + 3 ) & ~ 3); NEXTINSTRUCTION_S(lpIns, P2FVFOff.dwStride, wCount + 2, sizeof(D3DHAL_DP2TRIANGLEFAN_IMM)); break; case D3DDP2OP_TEXBLT: // Inform the drivers to perform a BitBlt operation from a source // texture to a destination texture. A texture can also be cubic // environment map. The driver should copy a rectangle specified // by rSrc in the source texture to the location specified by pDest // in the destination texture. The destination and source textures // are identified by handles that the driver was notified with // during texture creation time. If the driver is capable of // managing textures, then it is possible that the destination // handle is 0. This indicates to the driver that it should preload // the texture into video memory (or wherever the hardware // efficiently textures from). In this case, it can ignore rSrc and // pDest. Note that for mipmapped textures, only one D3DDP2OP_TEXBLT // instruction is inserted into the D3dDrawPrimitives2 command stream. // In this case, the driver is expected to BitBlt all the mipmap // levels present in the texture. // Verify the command buffer validity CHECK_CMDBUF_LIMITS(lpdp2d, lpPrim, D3DHAL_DP2TEXBLT, lpIns->wStateCount, 0); DBG_D3D((8,"D3DDP2OP_TEXBLT")); for ( i = 0; i < lpIns->wStateCount; i++) { __TextureBlt(pContext, (D3DHAL_DP2TEXBLT*)(lpPrim)); lpPrim += sizeof(D3DHAL_DP2TEXBLT); } //need to restore following registers RESERVEDMAPTR(15); SEND_PERMEDIA_DATA(FBReadPixel, pSoftPermedia->FBReadPixel); COPY_PERMEDIA_DATA(FBReadMode, pSoftPermedia->FBReadMode); SEND_PERMEDIA_DATA(FBSourceOffset, 0x0); SEND_PERMEDIA_DATA(FBPixelOffset, pContext->PixelOffset); SEND_PERMEDIA_DATA(FBWindowBase,0); COPY_PERMEDIA_DATA(Window, pSoftPermedia->Window); COPY_PERMEDIA_DATA(AlphaBlendMode, pSoftPermedia->AlphaBlendMode); COPY_PERMEDIA_DATA(DitherMode, pSoftPermedia->DitherMode); COPY_PERMEDIA_DATA(ColorDDAMode, pSoftPermedia->ColorDDAMode); COPY_PERMEDIA_DATA(TextureColorMode, pSoftPermedia->TextureColorMode); COPY_PERMEDIA_DATA(TextureReadMode, pSoftPermedia->TextureReadMode); COPY_PERMEDIA_DATA(TextureAddressMode, pSoftPermedia->TextureAddressMode); COPY_PERMEDIA_DATA(TextureDataFormat, pSoftPermedia->TextureDataFormat); COPY_PERMEDIA_DATA(TextureMapFormat, pSoftPermedia->TextureMapFormat); if (pContext->CurrentTextureHandle) { PERMEDIA_D3DTEXTURE* pTexture; pTexture = TextureHandleToPtr(pContext->CurrentTextureHandle, pContext); if (NULL != pTexture) { SEND_PERMEDIA_DATA(TextureBaseAddress, pTexture->MipLevels[0].PixelOffset); } } COMMITDMAPTR(); NEXTINSTRUCTION(lpIns, D3DHAL_DP2TEXBLT, lpIns->wStateCount, 0); break; case D3DDP2OP_STATESET: { P2D3DHAL_DP2STATESET *pStateSetOp = (P2D3DHAL_DP2STATESET*)(lpPrim); DBG_D3D((8,"D3DDP2OP_STATESET")); #if D3D_STATEBLOCKS for (i = 0; i < lpIns->wStateCount; i++, pStateSetOp++) { switch (pStateSetOp->dwOperation) { case D3DHAL_STATESETBEGIN : __BeginStateSet(pContext,pStateSetOp->dwParam); break; case D3DHAL_STATESETEND : __EndStateSet(pContext); break; case D3DHAL_STATESETDELETE : __DeleteStateSet(pContext,pStateSetOp->dwParam); break; case D3DHAL_STATESETEXECUTE: __ExecuteStateSet(pContext,pStateSetOp->dwParam); break; case D3DHAL_STATESETCAPTURE: __CaptureStateSet(pContext,pStateSetOp->dwParam); break; default : DBG_D3D((0,"D3DDP2OP_STATESET has invalid" "dwOperation %08lx",pStateSetOp->dwOperation)); } } #endif //D3D_STATEBLOCKS // Update the command buffer pointer NEXTINSTRUCTION(lpIns, P2D3DHAL_DP2STATESET, lpIns->wStateCount, 0); } break; case D3DDP2OP_SETPALETTE: // Attach a palette to a texture, that is , map an association // between a palette handle and a surface handle, and specify // the characteristics of the palette. The number of // D3DNTHAL_DP2SETPALETTE structures to follow is specified by // the wStateCount member of the D3DNTHAL_DP2COMMAND structure { D3DHAL_DP2SETPALETTE* lpSetPal = (D3DHAL_DP2SETPALETTE*)(lpPrim); DBG_D3D((8,"D3DDP2OP_SETPALETTE")); // Verify the command buffer validity CHECK_CMDBUF_LIMITS(lpdp2d, lpPrim, D3DHAL_DP2SETPALETTE, lpIns->wStateCount, 0); for (i = 0; i < lpIns->wStateCount; i++, lpSetPal++) { __PaletteSet(pContext, lpSetPal->dwSurfaceHandle, lpSetPal->dwPaletteHandle, lpSetPal->dwPaletteFlags ); } NEXTINSTRUCTION(lpIns, D3DHAL_DP2SETPALETTE, lpIns->wStateCount, 0); } break; case D3DDP2OP_UPDATEPALETTE: // Perform modifications to the palette that is used for palettized // textures. The palette handle attached to a surface is updated // with wNumEntries PALETTEENTRYs starting at a specific wStartIndex // member of the palette. (A PALETTENTRY (defined in wingdi.h and // wtypes.h) is actually a DWORD with an ARGB color for each byte.) // After the D3DNTHAL_DP2UPDATEPALETTE structure in the command // stream the actual palette data will follow (without any padding), // comprising one DWORD per palette entry. There will only be one // D3DNTHAL_DP2UPDATEPALETTE structure (plus palette data) following // the D3DNTHAL_DP2COMMAND structure regardless of the value of // wStateCount. { D3DHAL_DP2UPDATEPALETTE* lpUpdatePal = (D3DHAL_DP2UPDATEPALETTE*)(lpPrim); PERMEDIA_D3DPALETTE* pPalette; DBG_D3D((8,"D3DDP2OP_UPDATEPALETTE")); // Verify the command buffer validity CHECK_CMDBUF_LIMITS(lpdp2d, lpPrim, D3DHAL_DP2UPDATEPALETTE, 1, lpUpdatePal->wNumEntries * sizeof(PALETTEENTRY)); // We will ALWAYS have only 1 palette update structure + palette // following the D3DDP2OP_UPDATEPALETTE token ASSERTDD(1 == lpIns->wStateCount, "1 != wStateCount in D3DDP2OP_UPDATEPALETTE"); __PaletteUpdate(pContext, lpUpdatePal->dwPaletteHandle, lpUpdatePal->wStartIndex, lpUpdatePal->wNumEntries, (BYTE*)(lpUpdatePal+1) ); NEXTINSTRUCTION(lpIns, D3DHAL_DP2UPDATEPALETTE, 1, (DWORD)lpUpdatePal->wNumEntries * sizeof(PALETTEENTRY)); } break; case D3DDP2OP_SETRENDERTARGET: // Map a new rendering target surface and depth buffer in // the current context. This replaces the old D3dSetRenderTarget // callback. { D3DHAL_DP2SETRENDERTARGET* pSRTData; // Verify the command buffer validity CHECK_CMDBUF_LIMITS(lpdp2d, lpPrim, D3DHAL_DP2SETRENDERTARGET, lpIns->wStateCount, 0); // Get new data by ignoring all but the last structure pSRTData = (D3DHAL_DP2SETRENDERTARGET*)lpPrim + (lpIns->wStateCount - 1); __SetRenderTarget(pContext, pSRTData->hRenderTarget, pSRTData->hZBuffer); NEXTINSTRUCTION(lpIns, D3DHAL_DP2SETRENDERTARGET, lpIns->wStateCount, 0); } break; case D3DDP2OP_CLEAR: // Perform hardware-assisted clearing on the rendering target, // depth buffer or stencil buffer. This replaces the old D3dClear // and D3dClear2 callbacks. { D3DHAL_DP2CLEAR* pClear; // Verify the command buffer validity CHECK_CMDBUF_LIMITS(lpdp2d, lpPrim, RECT, lpIns->wStateCount, (sizeof(D3DHAL_DP2CLEAR) - sizeof(RECT))); // Get new data by ignoring all but the last structure pClear = (D3DHAL_DP2CLEAR*)lpPrim; DBG_D3D((8,"D3DDP2OP_CLEAR dwFlags=%08lx dwColor=%08lx " "dvZ=%08lx dwStencil=%08lx", pClear->dwFlags, pClear->dwFillColor, (DWORD)(pClear->dvFillDepth*0x0000FFFF), pClear->dwFillStencil)); __Clear(pContext, pClear->dwFlags, // in: surfaces to clear pClear->dwFillColor, // in: Color value for rtarget pClear->dvFillDepth, // in: Depth value for // Z-buffer (0.0-1.0) pClear->dwFillStencil, // in: value used to clear stencil // in: Rectangles to clear (LPD3DRECT)((LPBYTE)pClear + sizeof(D3DHAL_DP2CLEAR) - sizeof(RECT)), (DWORD)lpIns->wStateCount); // in: Number of rectangles //need to restore following registers RESERVEDMAPTR(4); SEND_PERMEDIA_DATA(FBReadPixel, pSoftPermedia->FBReadPixel); COPY_PERMEDIA_DATA(FBReadMode, pSoftPermedia->FBReadMode); SEND_PERMEDIA_DATA(FBPixelOffset, pContext->PixelOffset); SEND_PERMEDIA_DATA(FBWindowBase,0); COMMITDMAPTR(); NEXTINSTRUCTION(lpIns, RECT, lpIns->wStateCount, (sizeof(D3DHAL_DP2CLEAR) - sizeof(RECT))); } break; #if D3DDX7_TL case D3DDP2OP_SETMATERIAL: // We don't support T&L in this driver so we only skip this data NEXTINSTRUCTION(lpIns, D3DHAL_DP2SETMATERIAL, lpIns->wStateCount, 0); break; case D3DDP2OP_SETLIGHT: // We don't support T&L in this driver so we only skip this data NEXTINSTRUCTION(lpIns, D3DHAL_DP2SETLIGHT, lpIns->wStateCount, 0); break; case D3DDP2OP_CREATELIGHT: // We don't support T&L in this driver so we only skip this data NEXTINSTRUCTION(lpIns, D3DHAL_DP2CREATELIGHT, lpIns->wStateCount, 0); break; case D3DDP2OP_SETTRANSFORM: // We don't support T&L in this driver so we only skip this data NEXTINSTRUCTION(lpIns, D3DHAL_DP2SETTRANSFORM, lpIns->wStateCount, 0); break; case D3DDP2OP_ZRANGE: // We don't support T&L in this driver so we only skip this data NEXTINSTRUCTION(lpIns, D3DHAL_DP2ZRANGE, lpIns->wStateCount, 0); break; #endif //D3DDX7_TL default: ASSERTDD((pContext->ppdev->pD3DParseUnknownCommand), "D3D DX6 ParseUnknownCommand callback == NULL"); // Call the ParseUnknown callback to process // any unidentifiable token ddrval = (pContext->ppdev->pD3DParseUnknownCommand) ( (VOID **) lpIns , (VOID **) &lpResumeIns); if ( SUCCEEDED(ddrval) ) { // Resume buffer processing after D3DParseUnknownCommand // was succesful in processing an unknown command lpIns = lpResumeIns; break; } DBG_D3D((2,"unhandled opcode (%d)- returning " "D3DERR_COMMAND_UNPARSED @ addr %x", lpIns->bCommand,lpIns)); PARSE_ERROR_AND_EXIT( lpdp2d, lpIns, lpInsStart, ddrval); } // switch } //while lpdp2d->ddrval = DD_OK; Exit_DrawPrimitives2: // any necessary housekeeping can be done here before leaving DBG_D3D((6,"Exiting D3DDrawPrimitives2")); return DDHAL_DRIVER_HANDLED; } // D3DDrawPrimitives2 //-----------------------------Public Routine---------------------------------- // // DWORD D3DValidateTextureStageState // // ValidateTextureStageState evaluates the current state for blending // operations (including multitexture) and returns the number of passes the // hardware can do it in. This is a mechanism to query the driver about // whether it is able to handle the current stage state setup that has been // set up in hardware. For example, some hardware cannot do two simultaneous // modulate operations because they have only one multiplication unit and one // addition unit. // // The other reason for this function is that some hardware may not map // directly onto the Direct3D state architecture. This is a mechanism to map // the hardware's capabilities onto what the Direct3D DDI expects. // // Parameters // // lpvtssd // // .dwhContext // Context handle // .dwFlags // Flags, currently set to 0 // .dwReserved // Reserved // .dwNumPasses // Number of passes the hardware can perform the operation in // .ddrval // return value // //----------------------------------------------------------------------------- DWORD CALLBACK D3DValidateTextureStageState( LPD3DHAL_VALIDATETEXTURESTAGESTATEDATA lpvtssd ) { PERMEDIA_D3DTEXTURE *lpTexture; PERMEDIA_D3DCONTEXT *pContext; DWORD mag, min, cop, ca1, ca2, aop, aa1, aa2; DBG_D3D((6,"Entering D3DValidateTextureStageState")); pContext = (PERMEDIA_D3DCONTEXT*)ContextSlots[lpvtssd->dwhContext]; // Check if we got a valid context handle. CHK_CONTEXT(pContext, lpvtssd->ddrval, "D3DValidateTextureStageState"); lpvtssd->dwNumPasses = 0; lpvtssd->ddrval = DD_OK; mag = pContext->TssStates[D3DTSS_MAGFILTER]; min = pContext->TssStates[D3DTSS_MINFILTER]; cop = pContext->TssStates[D3DTSS_COLOROP]; ca1 = pContext->TssStates[D3DTSS_COLORARG1]; ca2 = pContext->TssStates[D3DTSS_COLORARG2]; aop = pContext->TssStates[D3DTSS_ALPHAOP]; aa1 = pContext->TssStates[D3DTSS_ALPHAARG1]; aa2 = pContext->TssStates[D3DTSS_ALPHAARG2]; if (!pContext->TssStates[D3DTSS_TEXTUREMAP]) { lpvtssd->dwNumPasses = 1; // Current is the same as diffuse in stage 0 if (ca2 == D3DTA_CURRENT) ca2 = D3DTA_DIFFUSE; if (aa2 == D3DTA_CURRENT) aa2 = D3DTA_DIFFUSE; // Check TSS even with texture handle = 0 since // certain operations with the fragments colors might // be possible. Here we only allow plain "classic" rendering if ((ca1 == D3DTA_DIFFUSE ) && (cop == D3DTOP_SELECTARG1) && (aa1 == D3DTA_DIFFUSE ) && (aop == D3DTOP_SELECTARG1)) { } else if ((ca2 == D3DTA_DIFFUSE ) && (cop == D3DTOP_SELECTARG2) && (aa2 == D3DTA_DIFFUSE) && (aop == D3DTOP_SELECTARG2)) { } // Default modulation else if ((ca2 == D3DTA_DIFFUSE) && (ca1 == D3DTA_TEXTURE) && (cop == D3DTOP_MODULATE) && (aa1 == D3DTA_TEXTURE) && (aop == D3DTOP_SELECTARG1)) { } // Check disable else if (cop == D3DTOP_DISABLE) { } else goto Fail_Validate; } else if ((mag != D3DTFG_POINT && mag != D3DTFG_LINEAR) || (min != D3DTFG_POINT && min != D3DTFG_LINEAR) ) { lpvtssd->ddrval = D3DERR_CONFLICTINGTEXTUREFILTER; DBG_D3D((2,"D3DERR_CONFLICTINGTEXTUREFILTER")); } else { lpvtssd->dwNumPasses = 1; // Current is the same as diffuse in stage 0 if (ca2 == D3DTA_CURRENT) ca2 = D3DTA_DIFFUSE; if (aa2 == D3DTA_CURRENT) aa2 = D3DTA_DIFFUSE; // Check decal if ((ca1 == D3DTA_TEXTURE ) && (cop == D3DTOP_SELECTARG1) && (aa1 == D3DTA_TEXTURE) && (aop == D3DTOP_SELECTARG1)) { } // Check all modulate variations else if ((ca2 == D3DTA_DIFFUSE) && (ca1 == D3DTA_TEXTURE) && (cop == D3DTOP_MODULATE)) { if ( // legacy (DX5) mode ((aa1 == D3DTA_TEXTURE) && (aop == D3DTOP_LEGACY_ALPHAOVR)) || // modulate color & pass diffuse alpha ((aa2 == D3DTA_DIFFUSE) && (aop == D3DTOP_SELECTARG2)) ) { PermediaSurfaceData* pPrivateData; // Get Texture for current stage (0) to verify properties lpTexture = TextureHandleToPtr( pContext->TssStates[D3DTSS_TEXTUREMAP], pContext); if (!CHECK_D3DSURFACE_VALIDITY(lpTexture)) { // we're lacking key information about the texture DBG_D3D((0,"D3DValidateTextureStageState gets " "NULL == lpTexture")); lpvtssd->ddrval = D3DERR_WRONGTEXTUREFORMAT; lpvtssd->dwNumPasses = 0; goto Exit_ValidateTSS; } pPrivateData = lpTexture->pTextureSurface; if (NULL == pPrivateData) { // we're lacking key information about the texture DBG_D3D((0,"D3DValidateTextureStageState gets " "NULL == lpTexture->pTextureSurface")); lpvtssd->ddrval = D3DERR_WRONGTEXTUREFORMAT; lpvtssd->dwNumPasses = 0; goto Exit_ValidateTSS; } // legacy texture modulation must have texture alpha if (!pPrivateData->SurfaceFormat.bAlpha && (aop == D3DTOP_LEGACY_ALPHAOVR)) { lpvtssd->ddrval = D3DERR_WRONGTEXTUREFORMAT; lpvtssd->dwNumPasses = 0; DBG_D3D((2,"D3DERR_WRONGTEXTUREFORMAT a format " "with alpha must be used")); goto Exit_ValidateTSS; } // modulation w diffuse alpha channel must lack texture // alpha channel due to Permedia2 limitations on // texture blending operations if (pPrivateData->SurfaceFormat.bAlpha && (aop == D3DTOP_SELECTARG2)) { lpvtssd->ddrval = D3DERR_WRONGTEXTUREFORMAT; lpvtssd->dwNumPasses = 0; DBG_D3D((2,"D3DERR_WRONGTEXTUREFORMAT a format " "with alpha must be used")); goto Exit_ValidateTSS; } } // modulate alpha else if ((aa2 == D3DTA_DIFFUSE) && (aa1 == D3DTA_TEXTURE) && (aop == D3DTOP_MODULATE)) { } // modulate color & pass texture alpha else if ((aa1 == D3DTA_TEXTURE) && (aop == D3DTOP_SELECTARG1)) { } else { goto Fail_Validate; } } // Check decal alpha else if ((ca2 == D3DTA_DIFFUSE) && (ca1 == D3DTA_TEXTURE) && (cop == D3DTOP_BLENDTEXTUREALPHA) && (aa2 == D3DTA_DIFFUSE) && (aop == D3DTOP_SELECTARG2)) { } // Check add else if ((ca2 == D3DTA_DIFFUSE) && (ca1 == D3DTA_TEXTURE) && (cop == D3DTOP_ADD) && (aa2 == D3DTA_DIFFUSE) && (aop == D3DTOP_SELECTARG2)) { } // Check disable else if ((cop == D3DTOP_DISABLE) || (cop == D3DTOP_SELECTARG2 && ca2 == D3DTA_DIFFUSE && aop == D3DTOP_SELECTARG2 && aa2 == D3DTA_DIFFUSE) ) { } // Don't understand else { Fail_Validate: DBG_D3D((4,"Failing with cop=%d ca1=%d ca2=%d aop=%d aa1=%d aa2=%d", cop,ca1,ca2,aop,aa1,aa2)); if (!((cop == D3DTOP_DISABLE) || (cop == D3DTOP_ADD) || (cop == D3DTOP_MODULATE) || (cop == D3DTOP_BLENDTEXTUREALPHA) || (cop == D3DTOP_SELECTARG2) || (cop == D3DTOP_SELECTARG1))) lpvtssd->ddrval = D3DERR_UNSUPPORTEDCOLOROPERATION; else if (!((aop == D3DTOP_SELECTARG1) || (aop == D3DTOP_SELECTARG2) || (aop == D3DTOP_MODULATE) || (aop == D3DTOP_LEGACY_ALPHAOVR))) lpvtssd->ddrval = D3DERR_UNSUPPORTEDALPHAOPERATION; else if (!(ca1 == D3DTA_TEXTURE)) lpvtssd->ddrval = D3DERR_UNSUPPORTEDCOLORARG; else if (!(ca2 == D3DTA_DIFFUSE)) lpvtssd->ddrval = D3DERR_UNSUPPORTEDCOLORARG; else if (!(aa1 == D3DTA_TEXTURE)) lpvtssd->ddrval = D3DERR_UNSUPPORTEDALPHAARG; else if (!(aa2 == D3DTA_DIFFUSE)) lpvtssd->ddrval = D3DERR_UNSUPPORTEDALPHAARG; else lpvtssd->ddrval = D3DERR_UNSUPPORTEDCOLOROPERATION; lpvtssd->dwNumPasses = 0; DBG_D3D((2,"D3DERR_UNSUPPORTEDCOLOROPERATION")); goto Exit_ValidateTSS; } } Exit_ValidateTSS: DBG_D3D((6,"Exiting D3DValidateTextureStageState with dwNumPasses=%d", lpvtssd->dwNumPasses)); return DDHAL_DRIVER_HANDLED; } // D3DValidateTextureStageState //-----------------------------Public Routine---------------------------------- // // DWORD __CheckFVFRequest // // This utility function verifies that the requested FVF format makes sense // and computes useful offsets into the data and a stride between succesive // vertices. // //----------------------------------------------------------------------------- DWORD __CheckFVFRequest(DWORD dwFVF, LPP2FVFOFFSETS lpP2FVFOff) { DWORD stride; UINT iTexCount; DBG_D3D((10,"Entering __CheckFVFRequest")); memset(lpP2FVFOff, 0, sizeof(P2FVFOFFSETS)); if ( (dwFVF & (D3DFVF_RESERVED0 | D3DFVF_RESERVED1 | D3DFVF_RESERVED2 | D3DFVF_NORMAL)) || ((dwFVF & (D3DFVF_XYZ | D3DFVF_XYZRHW)) == 0) ) { // can't set reserved bits, shouldn't have normals in // output to rasterizers, and must have coordinates return DDERR_INVALIDPARAMS; } lpP2FVFOff->dwStride = sizeof(D3DVALUE) * 3; if (dwFVF & D3DFVF_XYZRHW) { lpP2FVFOff->dwStride += sizeof(D3DVALUE); } if (dwFVF & D3DFVF_DIFFUSE) { lpP2FVFOff->dwColOffset = lpP2FVFOff->dwStride; lpP2FVFOff->dwStride += sizeof(D3DCOLOR); } if (dwFVF & D3DFVF_SPECULAR) { lpP2FVFOff->dwSpcOffset = lpP2FVFOff->dwStride; lpP2FVFOff->dwStride += sizeof(D3DCOLOR); } //@@BEGIN_DDKSPLIT #if D3D_POINTSPRITES if (dwFVF & D3DFVF_S) { lpP2FVFOff->dwPntSizeOffset = lpP2FVFOff->dwStride; lpP2FVFOff->dwStride += sizeof(D3DVALUE); } #endif // D3D_POINTSPRITES //@@END_DDKSPLIT iTexCount = (dwFVF & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT; if (iTexCount >= 1) { lpP2FVFOff->dwTexBaseOffset = lpP2FVFOff->dwStride; lpP2FVFOff->dwTexOffset = lpP2FVFOff->dwTexBaseOffset; if (0xFFFF0000 & dwFVF) { //expansion of FVF, these 16 bits are designated for up to //8 sets of texture coordinates with each set having 2bits //Normally a capable driver has to process all coordinates //However, code below only show correct parsing w/o really //observing all the texture coordinates.In reality,this would //result in incorrect result. UINT i,numcoord; DWORD extrabits; for (i = 0; i < iTexCount; i++) { extrabits= (dwFVF >> (16+2*i)) & 0x0003; switch(extrabits) { case 1: // one more D3DVALUE for 3D textures numcoord = 3; break; case 2: // two more D3DVALUEs for 4D textures numcoord = 4; break; case 3: // one less D3DVALUE for 1D textures numcoord = 1; break; default: // i.e. case 0 regular 2 D3DVALUEs numcoord = 2; break; } DBG_D3D((0,"Expanded TexCoord set %d has a offset %8lx", i,lpP2FVFOff->dwStride)); lpP2FVFOff->dwStride += sizeof(D3DVALUE) * numcoord; } DBG_D3D((0,"Expanded dwVertexType=0x%08lx has %d Texture Coords " "with total stride=0x%08lx", dwFVF, iTexCount, lpP2FVFOff->dwStride)); } else lpP2FVFOff->dwStride += iTexCount * sizeof(D3DVALUE) * 2; } else { lpP2FVFOff->dwTexBaseOffset = 0; lpP2FVFOff->dwTexOffset = 0; } DBG_D3D((10,"Exiting __CheckFVFRequest")); return DD_OK; } // __CheckFVFRequest //----------------------------------------------------------------------------- // // D3DFVFDRAWTRIFUNCPTR __HWSetTriangleFunc // // Select the appropiate triangle rendering function depending on the // current fillmode set for the current context // //----------------------------------------------------------------------------- D3DFVFDRAWTRIFUNCPTR __HWSetTriangleFunc(PERMEDIA_D3DCONTEXT *pContext) { if ( pContext->Hdr.FillMode == D3DFILL_SOLID ) return P2_Draw_FVF_Solid_Tri; else { if ( pContext->Hdr.FillMode == D3DFILL_WIREFRAME ) return P2_Draw_FVF_Wire_Tri; else // if it isn't solid nor line it must be a point filled triangle return P2_Draw_FVF_Point_Tri; } } //----------------------------------------------------------------------------- // // D3DFVFDRAWPNTFUNCPTR __HWSetPointFunc // // Select the appropiate point rendering function depending on the // current point sprite mode set for the current context // //----------------------------------------------------------------------------- D3DFVFDRAWPNTFUNCPTR __HWSetPointFunc(PERMEDIA_D3DCONTEXT *pContext, LPP2FVFOFFSETS lpP2FVFOff) { //@@BEGIN_DDKSPLIT #if D3D_POINTSPRITES // Only if we are not enabling point sprites and the default point size // is 1.0f and vertexes don't have their own point size, then use // classical points for rendering if ( pContext->bPointSpriteEnabled || (pContext->fPointSize != 1.0f) || (lpP2FVFOff->dwPntSizeOffset) ) return P2_Draw_FVF_Point_Sprite; else #endif // D3D_POINTSPRITES //@@END_DDKSPLIT return P2_Draw_FVF_Point; } //----------------------------------------------------------------------------- // // void __TextureBlt // // Transfer a texture from system memory into AGP or video memory //----------------------------------------------------------------------------- HRESULT __TextureBlt(PERMEDIA_D3DCONTEXT* pContext, D3DHAL_DP2TEXBLT* lpdp2texblt) { PPERMEDIA_D3DTEXTURE dsttex,srctex; RECTL rDest; PPDev ppdev=pContext->ppdev; DBG_D3D((10,"Entering __TextureBlt")); if (0 == lpdp2texblt->dwDDSrcSurface) { DBG_D3D((0,"Inavlid handle TexBlt from %08lx to %08lx", lpdp2texblt->dwDDSrcSurface,lpdp2texblt->dwDDDestSurface)); return DDERR_INVALIDPARAMS; } srctex = TextureHandleToPtr(lpdp2texblt->dwDDSrcSurface,pContext); if(!CHECK_D3DSURFACE_VALIDITY(srctex)) { DBG_D3D((0,"D3DDP2OP_TEXBLT: invalid dwDDSrcSurface !")); return DDERR_INVALIDPARAMS; } if (0 == lpdp2texblt->dwDDDestSurface) { PPERMEDIA_D3DTEXTURE pTexture = srctex; PermediaSurfaceData* pPrivateData = pTexture->pTextureSurface; if (!(pTexture->dwCaps2 & DDSCAPS2_TEXTUREMANAGE)) { DBG_D3D((0,"Must be a managed texture to do texture preload")); return DDERR_INVALIDPARAMS; } if (NULL==pPrivateData->fpVidMem) { TextureCacheManagerAllocNode(pContext,pTexture); if (NULL==pPrivateData->fpVidMem) { DBG_D3D((0,"EnableTexturePermedia unable to " "allocate memory from heap")); return DDERR_OUTOFVIDEOMEMORY; } pPrivateData->dwFlags |= P2_SURFACE_NEEDUPDATE; } if (pPrivateData->dwFlags & P2_SURFACE_NEEDUPDATE) { RECTL rect; rect.left=rect.top=0; rect.right=pTexture->wWidth; rect.bottom=pTexture->wHeight; // texture download // Switch to DirectDraw context pPrivateData->dwFlags &= ~P2_SURFACE_NEEDUPDATE; // .. Convert it to Pixels pTexture->MipLevels[0].PixelOffset = (ULONG)(pPrivateData->fpVidMem); switch(pTexture->pTextureSurface->SurfaceFormat.PixelSize) { case __PERMEDIA_4BITPIXEL: pTexture->MipLevels[0].PixelOffset <<= 1; break; case __PERMEDIA_8BITPIXEL: /* No Change*/ break; case __PERMEDIA_16BITPIXEL: pTexture->MipLevels[0].PixelOffset >>= 1; break; case __PERMEDIA_24BITPIXEL: pTexture->MipLevels[0].PixelOffset /= 3; break; case __PERMEDIA_32BITPIXEL: pTexture->MipLevels[0].PixelOffset >>= 2; break; default: ASSERTDD(0,"Invalid Texture Pixel Size!"); pTexture->MipLevels[0].PixelOffset >>= 1; break; } PermediaPatchedTextureDownload(pContext->ppdev, pPrivateData, pTexture->fpVidMem, pTexture->lPitch, &rect, pPrivateData->fpVidMem, pTexture->lPitch, &rect); DBG_D3D((10, "Copy from %08lx to %08lx w=%08lx h=%08lx " "p=%08lx b=%08lx", pTexture->fpVidMem,pPrivateData->fpVidMem,pTexture->wWidth, pTexture->wHeight,pTexture->lPitch,pTexture->dwRGBBitCount)); } return DD_OK; } else { dsttex = TextureHandleToPtr(lpdp2texblt->dwDDDestSurface,pContext); if(!CHECK_D3DSURFACE_VALIDITY(dsttex)) { DBG_D3D((0,"D3DDP2OP_TEXBLT: invalid dwDDDestSurface !")); return DDERR_INVALIDPARAMS; } } if (NULL != dsttex && NULL != srctex) { rDest.left = lpdp2texblt->pDest.x; rDest.top = lpdp2texblt->pDest.y; rDest.right = rDest.left + lpdp2texblt->rSrc.right - lpdp2texblt->rSrc.left; rDest.bottom = rDest.top + lpdp2texblt->rSrc.bottom - lpdp2texblt->rSrc.top; DBG_D3D((4,"TexBlt from %d %08lx %08lx to %d %08lx %08lx", lpdp2texblt->dwDDSrcSurface,srctex->dwCaps,srctex->dwCaps2, lpdp2texblt->dwDDDestSurface,dsttex->dwCaps,dsttex->dwCaps2)); dsttex->dwPaletteHandle = srctex->dwPaletteHandle; dsttex->pTextureSurface->dwPaletteHandle = srctex->dwPaletteHandle; if ((DDSCAPS_VIDEOMEMORY & srctex->dwCaps) && !(DDSCAPS2_TEXTUREMANAGE & srctex->dwCaps2)) { PermediaSurfaceData* pPrivateDest = dsttex->pTextureSurface; PermediaSurfaceData* pPrivateSource = srctex->pTextureSurface; // If the surface sizes don't match, then we are stretching. // Also the blits from Nonlocal- to Videomemory have to go through // the texture unit! if (!(DDSCAPS_VIDEOMEMORY & dsttex->dwCaps) || (DDSCAPS2_TEXTUREMANAGE & dsttex->dwCaps2)) { DBG_DD((0,"DDBLT_ROP: NOT ABLE TO BLT FROM " "VIDEO TO NON-VIDEO SURFACE")); return DDERR_INVALIDPARAMS; } if ( DDSCAPS_NONLOCALVIDMEM & srctex->dwCaps) { DBG_DD((3,"DDBLT_ROP: STRETCHCOPYBLT OR " "MIRROR OR BOTH OR AGPVIDEO")); PermediaStretchCopyBlt( ppdev, NULL, pPrivateDest, pPrivateSource, &rDest, &lpdp2texblt->rSrc, dsttex->MipLevels[0].PixelOffset, srctex->MipLevels[0].PixelOffset); } else { ULONG ulDestPixelShift=ShiftLookup[dsttex->dwRGBBitCount>>3]; LONG lPixPitchDest = dsttex->lPitch >> ulDestPixelShift; LONG lPixPitchSrc = srctex->lPitch >> ulDestPixelShift; LONG srcOffset=(LONG)((srctex->fpVidMem - dsttex->fpVidMem) >> ulDestPixelShift); DBG_DD((3,"DDBLT_ROP: COPYBLT %08lx %08lx %08lx", srctex->fpVidMem, dsttex->fpVidMem, ulDestPixelShift)); // For some reason, the user might want // to do a conversion on the data as it is // blitted from VRAM->VRAM by turning on Patching. // If Surf1Patch XOR Surf2Patch then // do a special blit that isn't packed and does patching. if (((pPrivateDest->dwFlags & P2_CANPATCH) ^ (pPrivateSource->dwFlags & P2_CANPATCH)) & P2_CANPATCH) { DBG_DD((4,"Doing Patch-Conversion!")); PermediaPatchedCopyBlt( ppdev, lPixPitchDest, lPixPitchSrc, pPrivateDest, pPrivateSource, &rDest, &lpdp2texblt->rSrc, dsttex->MipLevels[0].PixelOffset, srcOffset); } else { DBG_DD((4,"Doing PermediaPackedCopyBlt!")); PermediaPackedCopyBlt( ppdev, lPixPitchDest, lPixPitchSrc, pPrivateDest, pPrivateSource, &rDest, &lpdp2texblt->rSrc, dsttex->MipLevels[0].PixelOffset, srcOffset); } } } else if (dsttex->dwCaps2 & DDSCAPS2_TEXTUREMANAGE) { // texture download if (pContext->CurrentTextureHandle == lpdp2texblt->dwDDDestSurface) DIRTY_TEXTURE; dsttex->pTextureSurface->dwFlags |= P2_SURFACE_NEEDUPDATE; SysMemToSysMemSurfaceCopy( srctex->fpVidMem, srctex->lPitch, srctex->dwRGBBitCount, dsttex->fpVidMem, dsttex->lPitch, dsttex->dwRGBBitCount, &lpdp2texblt->rSrc, &rDest); } else if (DDSCAPS_NONLOCALVIDMEM & dsttex->dwCaps) { // Blt from system to AGP memory SysMemToSysMemSurfaceCopy(srctex->fpVidMem, srctex->lPitch, srctex->dwRGBBitCount, dsttex->fpVidMem, dsttex->lPitch, dsttex->dwRGBBitCount, &lpdp2texblt->rSrc, &rDest); } else if (DDSCAPS_LOCALVIDMEM & dsttex->dwCaps) { // texture download PermediaPatchedTextureDownload(ppdev, dsttex->pTextureSurface, srctex->fpVidMem, srctex->lPitch, &lpdp2texblt->rSrc, dsttex->fpVidMem, dsttex->lPitch, &rDest); } else { DBG_DD((0,"DDBLT_ROP: NOT ABLE TO BLT FROM " "SYSTEM TO NON-VIDEO SURFACE")); return DDERR_INVALIDPARAMS; } } DBG_D3D((10,"Exiting __TextureBlt")); return DD_OK; } //__TextureBlt //----------------------------------------------------------------------------- // // void __SetRenderTarget // // Set new render and z buffer target surfaces //----------------------------------------------------------------------------- HRESULT __SetRenderTarget(PERMEDIA_D3DCONTEXT* pContext, DWORD hRenderTarget, DWORD hZBuffer) { DBG_D3D((10,"Entering __SetRenderTarget Target=%d Z=%d", hRenderTarget,hZBuffer)); // Call a function to initialise registers that will setup the rendering pContext->RenderSurfaceHandle = hRenderTarget; pContext->ZBufferHandle = hZBuffer; SetupPermediaRenderTarget(pContext); // The AlphaBlending may need to be changed. DIRTY_ALPHABLEND; // Dirty the Z Buffer (the new target may not have one) DIRTY_ZBUFFER; DBG_D3D((10,"Exiting __SetRenderTarget")); return DD_OK; } // __SetRenderTarget //----------------------------------------------------------------------------- // // void __Clear // // Clears selectively the frame buffer, z buffer and stencil buffer for the // D3D Clear2 callback and for the D3DDP2OP_CLEAR command token. // //----------------------------------------------------------------------------- HRESULT __Clear( PERMEDIA_D3DCONTEXT* pContext, DWORD dwFlags, // in: surfaces to clear DWORD dwFillColor, // in: Color value for rtarget D3DVALUE dvFillDepth, // in: Depth value for // Z-buffer (0.0-1.0) DWORD dwFillStencil, // in: value used to clear stencil buffer LPD3DRECT lpRects, // in: Rectangles to clear DWORD dwNumRects) // in: Number of rectangles { int i; PermediaSurfaceData* pPrivateData; RECTL* pRect; PPDev ppdev=pContext->ppdev; PERMEDIA_DEFS(pContext->ppdev); if (D3DCLEAR_TARGET & dwFlags) { DWORD a,r,g,b; PPERMEDIA_D3DTEXTURE pSurfRender = TextureHandleToPtr(pContext->RenderSurfaceHandle, pContext); if(!CHECK_D3DSURFACE_VALIDITY(pSurfRender)) { DBG_D3D((0,"D3DDP2OP_CLEAR: invalid RenderSurfaceHandle !")); return DDERR_INVALIDPARAMS; } pPrivateData = pSurfRender->pTextureSurface; if( NULL == pPrivateData) { DBG_D3D((0,"D3DDP2OP_CLEAR: NULL == pPrivateData(pSurfRender)!")); return DDERR_INVALIDPARAMS; } // Translate into HW specific format a = RGB888ToHWFmt(dwFillColor, pPrivateData->SurfaceFormat.AlphaMask, 0x80000000); r = RGB888ToHWFmt(dwFillColor, pPrivateData->SurfaceFormat.RedMask, 0x00800000); g = RGB888ToHWFmt(dwFillColor, pPrivateData->SurfaceFormat.GreenMask, 0x00008000); b = RGB888ToHWFmt(dwFillColor, pPrivateData->SurfaceFormat.BlueMask, 0x00000080); dwFillColor = a | r | g | b; DBG_D3D((8,"D3DDP2OP_CLEAR convert to %08lx with Mask %8lx %8lx %8lx", dwFillColor, pPrivateData->SurfaceFormat.RedMask, pPrivateData->SurfaceFormat.GreenMask, pPrivateData->SurfaceFormat.BlueMask)); pRect = (RECTL*)lpRects; // Do clear for each Rect that we have for (i = dwNumRects; i > 0; i--) { PermediaFastClear(ppdev, pPrivateData, pRect, pContext->PixelOffset, dwFillColor); pRect++; } } if (((D3DCLEAR_ZBUFFER #if D3D_STENCIL | D3DCLEAR_STENCIL #endif //D3D_STENCIL ) & dwFlags) && (0 != pContext->ZBufferHandle)) { DWORD dwZbufferClearValue = 0x0000FFFF; //no stencil case DWORD dwWriteMask; PPERMEDIA_D3DTEXTURE pSurfZBuffer = TextureHandleToPtr(pContext->ZBufferHandle, pContext); if(!CHECK_D3DSURFACE_VALIDITY(pSurfZBuffer)) { DBG_D3D((0,"D3DDP2OP_CLEAR: invalid ZBufferHandle !")); return DDERR_INVALIDPARAMS; } // get z buffer pixelformat info pPrivateData = pSurfZBuffer->pTextureSurface; if( NULL == pPrivateData) { DBG_D3D((0,"D3DDP2OP_CLEAR: NULL == pPrivateData(pSurfZBuffer)!")); return DDERR_INVALIDPARAMS; } #if D3D_STENCIL //actually check dwStencilBitMask if (0 == pPrivateData->SurfaceFormat.BlueMask) { dwWriteMask = 0xFFFFFFFF; //all 16bits are for Z dwZbufferClearValue = (DWORD)(dvFillDepth*0x0000FFFF); } else { dwWriteMask = 0; dwZbufferClearValue = (DWORD)(dvFillDepth*0x00007FFF); if (D3DCLEAR_ZBUFFER & dwFlags) dwWriteMask |= 0x7FFF7FFF; if (D3DCLEAR_STENCIL & dwFlags) { dwWriteMask |= 0x80008000; if (0 != dwFillStencil) { dwZbufferClearValue |= 0x8000; //or stencil bit } } if (0xFFFFFFFF != dwWriteMask) { RESERVEDMAPTR(1); SEND_PERMEDIA_DATA(FBHardwareWriteMask, dwWriteMask); COMMITDMAPTR(); } } #endif //D3D_STENCIL pRect = (RECTL*)lpRects; for (i = dwNumRects; i > 0; i--) { PermediaFastLBClear(ppdev, pPrivateData, pRect, (DWORD)((UINT_PTR)pSurfZBuffer->fpVidMem >> P2DEPTH16), dwZbufferClearValue); pRect++; } #if D3D_STENCIL // Restore the LB write mask is we didn't clear stencil & zbuffer if (0xFFFFFFFF != dwWriteMask) { RESERVEDMAPTR(1); SEND_PERMEDIA_DATA(FBHardwareWriteMask, 0xFFFFFFFF); //restore COMMITDMAPTR(); } #endif //D3D_STENCIL } return DD_OK; } // __Clear //----------------------------------------------------------------------------- // // void __PaletteSet // // Attaches a palette handle to a texture in the given context // The texture is the one associated to the given surface handle. // //----------------------------------------------------------------------------- HRESULT __PaletteSet(PERMEDIA_D3DCONTEXT* pContext, DWORD dwSurfaceHandle, DWORD dwPaletteHandle, DWORD dwPaletteFlags) { PERMEDIA_D3DTEXTURE * pTexture; ASSERTDD(0 != dwSurfaceHandle, "dwSurfaceHandle==0 in D3DDP2OP_SETPALETTE"); DBG_D3D((8,"SETPALETTE %d to %d", dwPaletteHandle, dwSurfaceHandle)); pTexture = TextureHandleToPtr(dwSurfaceHandle, pContext); if (!CHECK_D3DSURFACE_VALIDITY(pTexture)) { DBG_D3D((0,"__PaletteSet:NULL==pTexture Palette=%08lx Surface=%08lx", dwPaletteHandle, dwSurfaceHandle)); return DDERR_INVALIDPARAMS; // invalid dwSurfaceHandle, skip it } pTexture->dwPaletteHandle = dwPaletteHandle; // need to make it into private data if driver created this surface if (NULL != pTexture->pTextureSurface) pTexture->pTextureSurface->dwPaletteHandle = dwPaletteHandle; if (pContext->CurrentTextureHandle == dwSurfaceHandle) DIRTY_TEXTURE; if (0 == dwPaletteHandle) { return D3D_OK; //palette association is OFF } // Check if we need to grow our palette list for this handle element if (NULL == pContext->pHandleList->dwPaletteList || dwPaletteHandle >= PtrToUlong(pContext->pHandleList->dwPaletteList[0])) { DWORD newsize = ((dwPaletteHandle + LISTGROWSIZE)/LISTGROWSIZE)*LISTGROWSIZE; PPERMEDIA_D3DPALETTE *newlist = (PPERMEDIA_D3DPALETTE *) ENGALLOCMEM( FL_ZERO_MEMORY, sizeof(PPERMEDIA_D3DPALETTE)*newsize, ALLOC_TAG); DBG_D3D((8,"Growing pDDLcl=%x's " "PaletteList[%x] size to %08lx", pContext->pDDLcl, newlist, newsize)); if (NULL == newlist) { DBG_D3D((0,"D3DDP2OP_SETPALETTE Out of memory.")); return DDERR_OUTOFMEMORY; } memset(newlist,0,newsize); if (NULL != pContext->pHandleList->dwPaletteList) { memcpy(newlist,pContext->pHandleList->dwPaletteList, PtrToUlong(pContext->pHandleList->dwPaletteList[0]) * sizeof(PPERMEDIA_D3DPALETTE)); ENGFREEMEM(pContext->pHandleList->dwPaletteList); DBG_D3D((8,"Freeing pDDLcl=%x's old PaletteList[%x]", pContext->pDDLcl, pContext->pHandleList->dwPaletteList)); } pContext->pHandleList->dwPaletteList = newlist; //store size in dwSurfaceList[0] *(DWORD*)pContext->pHandleList->dwPaletteList = newsize; } // If we don't have a palette hanging from this palette list // element we have to create one. The actual palette data will // come down in the D3DDP2OP_UPDATEPALETTE command token. if (NULL == pContext->pHandleList->dwPaletteList[dwPaletteHandle]) { pContext->pHandleList->dwPaletteList[dwPaletteHandle] = (PERMEDIA_D3DPALETTE*)ENGALLOCMEM( FL_ZERO_MEMORY, sizeof(PERMEDIA_D3DPALETTE), ALLOC_TAG); if (NULL == pContext->pHandleList->dwPaletteList[dwPaletteHandle]) { DBG_D3D((0,"D3DDP2OP_SETPALETTE Out of memory.")); return DDERR_OUTOFMEMORY; } } // driver may store this dwFlags to decide whether // ALPHA exists in Palette pContext->pHandleList->dwPaletteList[dwPaletteHandle]->dwFlags = dwPaletteFlags; return DD_OK; } // PaletteSet //----------------------------------------------------------------------------- // // void __PaletteUpdate // // Updates the entries of a palette attached to a texture in the given context // //----------------------------------------------------------------------------- HRESULT __PaletteUpdate(PERMEDIA_D3DCONTEXT* pContext, DWORD dwPaletteHandle, WORD wStartIndex, WORD wNumEntries, BYTE * pPaletteData) { PERMEDIA_D3DPALETTE* pPalette; DBG_D3D((8,"UPDATEPALETTE %d (%d,%d) %d", dwPaletteHandle, wStartIndex, wNumEntries, pContext->CurrentTextureHandle)); pPalette = PaletteHandleToPtr(dwPaletteHandle,pContext); if (NULL != pPalette) { ASSERTDD(256 >= wStartIndex + wNumEntries, "wStartIndex+wNumEntries>256 in D3DDP2OP_UPDATEPALETTE"); // Copy the palette & associated data pPalette->wStartIndex = wStartIndex; pPalette->wNumEntries = wNumEntries; memcpy((LPVOID)&pPalette->ColorTable[wStartIndex], (LPVOID)pPaletteData, (DWORD)wNumEntries*sizeof(PALETTEENTRY)); // If we are currently texturing and the texture is using the // palette we just updated, dirty the texture flag so that // it set up with the right (updated) palette if (pContext->CurrentTextureHandle) { PERMEDIA_D3DTEXTURE * pTexture= TextureHandleToPtr(pContext->CurrentTextureHandle,pContext); if (pTexture && pTexture->pTextureSurface) { if (pTexture->dwPaletteHandle == dwPaletteHandle) { DIRTY_TEXTURE; DBG_D3D((8,"UPDATEPALETTE DIRTY_TEXTURE")); } } } } else { return DDERR_INVALIDPARAMS; } return DD_OK; } // __PaletteUpdate //----------------------------------------------------------------------------- // // void __RestoreD3DContext // // Restores the P2 registers to what they were when we last left this D3D context // //----------------------------------------------------------------------------- void __RestoreD3DContext(PPDev ppdev, PERMEDIA_D3DCONTEXT* pContext) { __P2RegsSoftwareCopy* pSoftPermedia = &pContext->Hdr.SoftCopyP2Regs; PERMEDIA_DEFS(ppdev); // Dirty everything in order to restore the D3D state DIRTY_TEXTURE; DIRTY_ZBUFFER; DIRTY_ALPHABLEND; // Restore the correct surface (render & depth buffer) characteristics SetupPermediaRenderTarget(pContext); //Bring back manually some registers which we care about RESERVEDMAPTR(5); COPY_PERMEDIA_DATA(DeltaMode, pSoftPermedia->DeltaMode); COPY_PERMEDIA_DATA(ColorDDAMode, pSoftPermedia->ColorDDAMode); COPY_PERMEDIA_DATA(FogColor, pSoftPermedia->FogColor); SEND_PERMEDIA_DATA(FBHardwareWriteMask, -1 ); COMMITDMAPTR(); }