|
|
/******************************Module*Header**********************************\
* * ******************* * * D3D SAMPLE CODE * * ******************* * * Module Name: d3ddp2p3.c * * Content: D3D DrawPrimitives2 callback 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"
//-----------------------------------------------------------------------------
// in-the-file nonexported forward declarations
//-----------------------------------------------------------------------------
BOOL __DP2_PrimitiveOpsParser( P3_D3DCONTEXT *pContext, LPD3DHAL_DRAWPRIMITIVES2DATA pdp2d, LPD3DHAL_DP2COMMAND *lplpIns, LPBYTE insStart, LPDWORD lpVertices);
//-----------------------------------------------------------------------------
// Macros to access and validate command and vertex buffer data
// These checks need ALWAYS to be made for all builds, free and checked.
//-----------------------------------------------------------------------------
#define STARTVERTEXSIZE (sizeof(D3DHAL_DP2STARTVERTEX))
#define NEXTINSTRUCTION(ptr, type, num, extrabytes) \
ptr = (LPD3DHAL_DP2COMMAND)((LPBYTE)ptr + sizeof(D3DHAL_DP2COMMAND) + \ ((num) * sizeof(type)) + (extrabytes))
#define PARSE_ERROR_AND_EXIT( pDP2Data, pIns, pStartIns, ddrvalue) \
{ \ pDP2Data->dwErrorOffset = (DWORD)((LPBYTE)pIns - (LPBYTE)pStartIns);\ pDP2Data->ddrval = ddrvalue; \ bParseError = TRUE; \ break; \ }
#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)) \ { \ DISPDBG((ERRLVL,"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 LP_FVF_VERTEX(lpBaseAddr, wIndex) \
(LPDWORD)((LPBYTE)(lpBaseAddr) + (wIndex) * pContext->FVFData.dwStride)
#define LP_FVF_NXT_VTX(lpVtx) \
(LPDWORD)((LPBYTE)(lpVtx) + pContext->FVFData.dwStride)
//-----------------------------------------------------------------------------
// These defines are derived from the VertexTagList initialisation in stateset.c
#define FVF_TEXCOORD_BASE 6
#define FVF_XYZ (7 << 0)
#define FVF_RHW (1 << 3)
#define FVF_DIFFUSE (1 << 4)
#define FVF_SPECULAR (1 << 5)
#define FVF_TEXCOORD1 (3 << FVF_TEXCOORD_BASE)
#define FVF_TEXCOORD2 (3 << (FVF_TEXCOORD_BASE + 2))
//-----------------------------------------------------------------------------
//
// ReconsiderStateChanges
//
//-----------------------------------------------------------------------------
static D3DSTATE localState[] = { { (D3DTRANSFORMSTATETYPE)D3DRENDERSTATE_SHADEMODE, 0 }, { (D3DTRANSFORMSTATETYPE)D3DRENDERSTATE_CULLMODE, 0 } };
#define NUM_LOCAL_STATES ( sizeof( localState ) / sizeof( D3DSTATE ))
void ReconsiderStateChanges( P3_D3DCONTEXT *pContext ) { int i;
for( i = 0; i < NUM_LOCAL_STATES; i++ ) { localState[i].dwArg[0] = pContext->RenderStates[localState[i].drstRenderStateType]; }
_D3D_ST_ProcessRenderStates(pContext, NUM_LOCAL_STATES, localState, FALSE);
_D3D_ST_RealizeHWStateChanges( pContext ); } // ReconsiderStateChanges
//-----------------------------------------------------------------------------
//
// __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.
//
//-----------------------------------------------------------------------------
#define FVFEQUAL(fvfcode, fvfmask) \
(((DWORD)fvfcode & (DWORD)fvfmask)) == (DWORD)fvfmask) DWORD __CheckFVFRequest(P3_D3DCONTEXT *pContext, DWORD dwFVF) { UINT i, iTexCount; P3_THUNKEDDATA* pThisDisplay = pContext->pThisDisplay; int nonTexStride, texMask; FVFOFFSETS KeptFVF; P3_SOFTWARECOPY* pSoftP3RX = &pContext->SoftCopyGlint; P3_DMA_DEFS();
DISPDBG((DBGLVL,"Looking at FVF Code %x:",dwFVF));
// Check for bogus fields
if ( (dwFVF & (D3DFVF_RESERVED0 | D3DFVF_RESERVED2)) || (!(dwFVF & (D3DFVF_XYZ | D3DFVF_XYZRHW))) || (dwFVF & (D3DFVF_NORMAL) ) ) { DISPDBG((ERRLVL,"ERROR: Invalid FVF Buffer for this hardware!(%x)" ,dwFVF)); // can't set reserved bits, shouldn't have normals in
// output to rasterizers (since we're not a TnL driver/hw)
// and must have coordinates
return DDERR_INVALIDPARAMS; }
KeptFVF = pContext->FVFData;
// Ensure the default offsets are setup
ZeroMemory(&pContext->FVFData, sizeof(FVFOFFSETS));
// Minimum FVF coordinate fields
pContext->FVFData.dwStride = sizeof(D3DVALUE) * 3; pContext->FVFData.vFmat |= FVF_XYZ;
// RHW if present in FVF
if (dwFVF & D3DFVF_XYZRHW) { DISPDBG((DBGLVL, " D3DFVF_XYZRHW")); pContext->FVFData.dwStride += sizeof(D3DVALUE); pContext->FVFData.vFmat |= FVF_RHW; }
#if DX8_POINTSPRITES
// Point size offsets for point sprites
if (dwFVF & D3DFVF_PSIZE) { pContext->FVFData.dwPntSizeOffset = pContext->FVFData.dwStride; pContext->FVFData.dwStride += sizeof(D3DVALUE); } #else
if (dwFVF & D3DFVF_RESERVED1) { DISPDBG((DBGLVL, " D3DFVF_RESERVED1")); pContext->FVFData.dwStride += sizeof(D3DVALUE); } #endif // DX8_POINTSPRITES
// Diffuse color
if (dwFVF & D3DFVF_DIFFUSE) { DISPDBG((DBGLVL, " D3DFVF_DIFFUSE")); pContext->FVFData.dwColOffset = pContext->FVFData.dwStride; pContext->FVFData.dwStride += sizeof(D3DCOLOR); pContext->FVFData.vFmat |= FVF_DIFFUSE; }
// Specular color
if (dwFVF & D3DFVF_SPECULAR) { DISPDBG((DBGLVL, " D3DFVF_SPECULAR")); pContext->FVFData.dwSpcOffset = pContext->FVFData.dwStride; pContext->FVFData.dwStride += sizeof(D3DCOLOR); pContext->FVFData.vFmat |= FVF_SPECULAR; }
// Store some info for later setting up our inline hostin renderers
nonTexStride = pContext->FVFData.dwStride / sizeof(DWORD); texMask = 0; pContext->FVFData.dwStrideHostInline = pContext->FVFData.dwStride; pContext->FVFData.dwNonTexStride = pContext->FVFData.dwStride;
// Up until this point the vertex format is the same for both
pContext->FVFData.vFmatHostInline = pContext->FVFData.vFmat;
// Get number of texture coordinates present in this FVF code
iTexCount = (dwFVF & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT; pContext->FVFData.dwTexCount = iTexCount;
for (i=0; i<D3DHAL_TSS_MAXSTAGES;i++) { pContext->FVFData.dwTexCoordOffset[i] = 0; }
// Do we have tex coords in FVF? What kinds?
if (iTexCount >= 1) { DISPDBG((DBGLVL,"Texture enabled: %d stages", iTexCount));
// What is the dimensionality of each of our texcoords?
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
//Code below shows correct parsing
UINT numcoord; for (i = 0; i < iTexCount; i++) { if (FVFEQUAL(dwFVF,D3DFVF_TEXCOORDSIZE1(i)) { // one less D3DVALUE for 1D textures
numcoord = 1; } else if (FVFEQUAL(dwFVF,D3DFVF_TEXCOORDSIZE3(i)) { // one more D3DVALUE for 3D textures
numcoord = 3; } else if (FVFEQUAL(dwFVF,D3DFVF_TEXCOORDSIZE4(i)) { // two more D3DVALUEs for 4D textures
numcoord = 4; } else { // D3DFVF_TEXCOORDSIZE2(i) is always 0
// i.e. case 0 regular 2 D3DVALUEs
numcoord = 2; } DISPDBG((DBGLVL,"Expanded TexCoord set %d has a offset %8lx", i,pContext->FVFData.dwStride));
pContext->FVFData.dwTexCoordOffset[i] = pContext->FVFData.dwStride; pContext->FVFData.dwStride += sizeof(D3DVALUE) * numcoord; } DISPDBG((DBGLVL,"Expanded dwVertexType=0x%08lx has %d " "Texture Coords with total stride=0x%08lx", dwFVF, iTexCount, pContext->FVFData.dwStride)); } else { // If the top FVF bits are not set, the default is to consider all
// text coords to be u.v (2D)
for (i = 0; i < iTexCount; i++) { pContext->FVFData.dwTexCoordOffset[i] = pContext->FVFData.dwStride;
pContext->FVFData.dwStride += sizeof(D3DVALUE) * 2; }
}
// Update the offsets to our current (2) textures
if( pContext->iTexStage[0] != -1 ) { DWORD dwTexCoordSet = pContext->TextureStageState[pContext->iTexStage[0]]. m_dwVal[D3DTSS_TEXCOORDINDEX];
// The texture coordinate index may contain texgen flags
// in the high word. These flags are not interesting here
// so we mask them off.
dwTexCoordSet = dwTexCoordSet & 0x0000FFFFul; pContext->FVFData.dwTexOffset[0] = pContext->FVFData.dwTexCoordOffset[dwTexCoordSet];
texMask |= 3 << ( 2 * dwTexCoordSet );
pContext->FVFData.vFmat |= FVF_TEXCOORD1; }
if( pContext->iTexStage[1] != -1 ) { DWORD dwTexCoordSet = pContext->TextureStageState[pContext->iTexStage[1]]. m_dwVal[D3DTSS_TEXCOORDINDEX]; // The texture coordinate index may contain texgen flags
// in the high word. These flags are not interesting here
// so we mask them off.
dwTexCoordSet = dwTexCoordSet & 0x0000FFFFul;
pContext->FVFData.dwTexOffset[1] = pContext->FVFData.dwTexCoordOffset[dwTexCoordSet];
texMask |= 3 << ( 2 * dwTexCoordSet );
pContext->FVFData.vFmat |= FVF_TEXCOORD2; }
} // if (iTexCount >= 1)
//---------------------------------------------------------
// Update Permedia 3 hw registers for host inline rendering
//---------------------------------------------------------
// Update the Hostinline renderers with the correct values.
// These usually aren't the same as the Hostin renderer values
if (pContext->FVFData.vFmat & FVF_TEXCOORD1) { // Add this texture coordinate into the stride
pContext->FVFData.dwStrideHostInline += (sizeof(D3DVALUE) * 2);
// Set up the vertex format bit
pContext->FVFData.vFmatHostInline |= FVF_TEXCOORD1; } if (pContext->FVFData.vFmat & FVF_TEXCOORD2) { P3_SURF_INTERNAL* pTexture = pContext->pCurrentTexture[TEXSTAGE_1];
// If the texture coordinates aren't the same, or we are mipmapping,
// then we must send the second set of texture coordinates
if ((pContext->FVFData.dwTexOffset[0] != pContext->FVFData.dwTexOffset[1]) || ((pTexture != NULL) && (pContext->TextureStageState[TEXSTAGE_1].m_dwVal[D3DTSS_MIPFILTER] != D3DTFP_NONE) && (pTexture->bMipMap))) { pContext->FVFData.dwStrideHostInline += (sizeof(D3DVALUE) * 2);
// Add in the second texture set to the vertex format
pContext->FVFData.vFmatHostInline |= FVF_TEXCOORD2; } }
// VertexValid is all 1's for the stride, because we will never want
// to send a gap in the inline hostin triangle renderer
pContext->FVFData.dwVertexValidHostInline = (1 << (pContext->FVFData.dwStrideHostInline >> 2)) - 1;
// The vertex valid for Hostin renderers is more complex because the chip
// may be required to skip data.
pContext->FVFData.dwVertexValid = ((1 << nonTexStride) - 1) | (texMask << nonTexStride);
// If the FVF has changed, resend the state. This can be improved because
// you don't always have to send the default stuff (only if that state is
// enabled and the vertex doesn't contain it).
if (memcmp(&KeptFVF, &pContext->FVFData, sizeof(KeptFVF)) != 0) { // Update P3 for the changed FVF
P3_DMA_GET_BUFFER_ENTRIES( 12 );
SEND_P3_DATA(V0FloatPackedColour, 0xFFFFFFFF); SEND_P3_DATA(V1FloatPackedColour, 0xFFFFFFFF); SEND_P3_DATA(V2FloatPackedColour, 0xFFFFFFFF); SEND_P3_DATA(V0FloatPackedSpecularFog, 0x0); SEND_P3_DATA(V1FloatPackedSpecularFog, 0x0); SEND_P3_DATA(V2FloatPackedSpecularFog, 0x0);
pSoftP3RX->P3RX_P3VertexControl.CacheEnable = 1;
P3_DMA_COMMIT_BUFFER();
}
DISPDBG((DBGLVL,"FVF stride set to %d",pContext->FVFData.dwStride));
return DD_OK; } // __CheckFVFRequest
//-----------------------------Public Routine----------------------------------
//
// DWORD D3DDrawPrimitives2_P3
//
// Renders primitives and returns the updated render state.
//
// D3dDrawPrimitives2 must be implemented in Direct3D drivers.
//
// The driver must do the following:
//
// -Ensure that the context handle specified by dwhContext is valid.
//
// -Check that a flip to the drawing surface associated with the context is not
// in progress. If the drawing surface is involved in a flip, the driver should
// set ddrval to DDERR_WASSTILLDRAWING and return DDHAL_DRIVER_HANDLED.
//
// -Determine the location at which the first D3DNTHAL_DP2COMMAND structure is
// found by adding dwCommandOffset bytes to the Command Buffer to which
// lpDDCommands points.
//
// -Determine the location in the Vertex Buffer at which the first vertex is found
// This is should only be done if there is data in the Vertex Buffer; that is,
// when a D3DDP2OP_* command token is received (except when the token is
// D3DDP2OP_LINELIST_IMM or D3DDP2OP_TRIANGLEFAN_IMM). These later two opcodes
// indicate that the vertex data is passed immediately in the command stream,
// rather than in a Vertex Buffer. So, assuming there is data in the Vertex
// Buffer, if the Vertex Buffer is in user memory, the first vertex is
// dwVertexOffset bytes into the buffer to which lpVertices points. Otherwise,
// the driver should apply dwVertexOffset to the memory associated with the
// DD_SURFACE_LOCAL structure to which lpDDVertex points.
//
// -Check dwVertexType to ensure that the driver supports the requested FVF. The
// driver should fail the call if any of the following conditions exist:
//
// *Vertex coordinates are not specified; that is, if D3DFVF_XYZRHW is not set.
// *Normals are specified; that is, if D3DFVF_NORMAL is set.
// *Any of the reserved D3DFVF_RESERVEDx bits are set.
//
// -Process all of the commands in the Command Buffer sequentially. For each
// D3DNTHAL_DP2COMMAND structure, the driver should do the following:
//
// *If the command is D3DDP2OP_RENDERSTATE, process the wStateCount
// D3DNTHAL_DP2RENDERSTATE structures that follow in the Command Buffer,
// updating the driver state for each render state structure. When the
// D3DNTHALDP2_EXECUTEBUFFER flag is set, the driver should also reflect the
// state change in the array to which lpdwRStates points.
// *If the command is D3DDP2OP_TEXTURESTAGESTATE, process the wStateCount
// D3DNTHAL_DP2TEXTURESTAGESTATE structures that follow in the Command Buffer,
// updating the driver's texture state associated with the specified texture
// stage for each texture state structure.
// *If the command is D3DDP2OP_VIEWPORTINFO, process the D3DNTHAL_DP2VIEWPORTINFO
// structure that follows in the Command Buffer, updating the viewport
// information stored in the driver's internal rendering context.
// *If the command is D3DDP2OP_WINFO, process the D3DNTHAL_DP2WINFO structure
// that follows in the Command Buffer, updating the w-buffering information
// stored in the driver's internal rendering context.
// *Otherwise, process the D3DNTHAL_DP2Xxx primitive structures that follow the
// D3DDP2OP_Xxx primitive rendering command in the Command Buffer.
// *If the command is unknown, call the runtime's D3dParseUnknownCommand callback
// The runtime provides this callback to the driver's DdGetDriverInfo callback
// with the GUID_D3DPARSEUNKNOWNCOMMANDCALLBACK guid.
//
// The driver doesn't need to probe for readability the memory in which the
// Command and Vertex Buffers are stored. However, the driver is responsible for
// ensuring that it does not exceed the bounds of these buffers; that is, the
// driver must stay within the bounds specified by dwCommandLength and
// dwVertexLength.
//
// If the driver needs to fail D3dDrawPrimitives2, it should fill in
// dwErrorOffset with the offset into Command Buffer at which the first
// unhandled D3DNTHAL_DP2COMMAND can be found.
//
//
// Parameters
//
// pdp2d
// Points to a D3DNTHAL_DRAWPRIMITIVES2DATA structure that contains
// the information required for the driver to render one or more
// primitives.
//
// .dwhContext
// Specifies the context handle of the Direct3D device.
// .dwFlags
// Specifies flags that provide additional instructions to the
// driver or provide information from the driver. This member
// can be a bitwise OR of the following values:
//
// D3DNTHALDP2_USERMEMVERTICES
// The lpVertices member is valid; that is, the driver
// should obtain the vertex data from the user-allocated
// memory to which lpVertices points. This flag is set
// by Direct3D only.
// D3DNTHALDP2_EXECUTEBUFFER
// Indicates that the Command and Vertex Buffers were
// created in system memory. The driver should update
// the state array to which lpdwRStates points. This
// flag is set by Direct3D only.
// D3DNTHALDP2_SWAPVERTEXBUFFER
// Indicates that the driver can swap the buffer to
// which lpDDVertex or lpVertices points with a new
// Vertex Buffer and return immediately, asynchronously
// processing the original buffer while Direct3D fills
// the new Vertex Buffer. Drivers that do not support
// multi-buffering of Vertex Buffers can ignore this
// flag. This flag is set by Direct3D only.
// D3DNTHALDP2_SWAPCOMMANDBUFFER
// Indicates that the driver can swap the buffer to
// which lpDDCommands points with a new Command Buffer
// and return immediately, asynchronously processing
// the original buffer while Direct3D fills the new
// Command Buffer. Drivers that do not support
/// multi-buffering of Command Buffers can ignore this
// flag. This flag is set by Direct3D only.
// D3DNTHALDP2_REQVERTEXBUFSIZE
// Indicates that the driver must be able to allocate
// a Vertex Buffer of at least the size specified in
// dwReqVertexBufSize. Drivers that do not support
// multi-buffering of Vertex Buffers can ignore this
// flag. This flag is set by Direct3D only.
// D3DNTHALDP2_REQCOMMANDBUFSIZE
// Indicates that the driver must be able to allocate
// a Command Buffer of at least the size specified in
// dwReqCommandBufSize. Drivers that do not support
// multi-buffering of Command Buffers can ignore this
// flag. This flag is set by Direct3D only.
// D3DNTHALDP2_VIDMEMVERTEXBUF
// Indicates that the Vertex Buffer allocated by the
// driver as a swap buffer is not in system memory.
// This flag can be set by drivers that support multi-
// buffering of Vertex Buffers.
// D3DNTHALDP2_VIDMEMCOMMANDBUF
// Indicates that the Command Buffer allocated by the
// driver as a swap buffer is not in system memory. This
// flag can be set by drivers that support multi-
// buffering of Command Buffers.
//
// .dwVertexType
// Identifies the FVF of the data in the Vertex Buffer; that is,
// dwVertexType specifies which per-vertex data fields are present
// in the Vertex Buffer to which lpDDVertex or lpVertices points.
// This member can be a bitwise OR of the values in the table that
// follows. Only one of the D3DFVF_TEXx flags will be set.
//
// Value Meaning
// ============== =======
// D3DFVF_XYZRHW Each vertex has an x,y,z, and w.
// This flag is always set.
// D3DFVF_DIFFUSE Each vertex has a diffuse color.
// D3DFVF_SPECULAR Each vertex has a specular color.
// D3DFVF_TEX0 No texture coordinates are provided
// with the vertex data.
// D3DFVF_TEX1 Each vertex has one set of texture
// coordinates.
// D3DFVF_TEX2 Each vertex has two sets of texture
// coordinates.
// D3DFVF_TEX3 Each vertex has three sets of texture
// coordinates.
// D3DFVF_TEX4 Each vertex has four sets of texture
// coordinates.
// D3DFVF_TEX5 Each vertex has five sets of texture
// coordinates.
// D3DFVF_TEX6 Each vertex has six sets of texture
// coordinates.
// D3DFVF_TEX7 Each vertex has seven sets of texture
// coordinates.
// D3DFVF_TEX8 Each vertex has eight sets of texture
// coordinates.
//
// .lpDDCommands
// Points to the DD_SURFACE_LOCAL structure that identifies the
// DirectDraw surface containing the command data. The fpVidMem
// member of the embedded DD_SURFACE_GLOBAL structure points to
// the buffer that contains state change and primitive drawing
// commands for the driver to process. Specifically, this buffer
// contains one or more D3DNTHAL_DP2COMMAND structures, each
// followed by a D3DNTHAL_DP2Xxx structure whose exact type is
// identified by D3DNTHAL_DP2COMMAND's bCommand member.
// .dwCommandOffset
// Specifies the number of bytes into the surface to which
// lpDDCommands points at which the command data starts.
// .dwCommandLength
// Specifies the number of bytes of valid command data in the
// surface to which lpDDCommands points starting at dwCommandOffset.
// .lpDDVertex
// Points to the DD_SURFACE_LOCAL structure that identifies the
// DirectDraw surface containing the vertex data when the
// D3DNTHALDP2_USERMEMVERTICES flag is not set in dwFlags. Union
// with lpVertices.
// .lpVertices
// Points to a user-mode memory block containing vertex data when
// the D3DNTHALDP2_USERMEMVERTICES flag is set in dwFlags.
// .dwVertexOffset
// Specifies the number of bytes into the surface to which
// lpDDVertex or lpVertices points at which the vertex data starts.
// .dwVertexLength
// The number of vertices, for which valid data exists in the
// surface, that lpDDVertex points to (starting at dwVertexOffset).
// Note that dwVertexOffset is specified in bytes.
// .dwReqVertexBufSize
// Specifies the minimum number of bytes that the driver must
// allocate for the swap Vertex Buffer. This member is valid only
// when the D3DNTHALDP2_REQVERTEXBUFSIZE flag is set. Drivers that
// do not support multi-buffering of Vertex Buffers should ignore
// this member.
// .dwReqCommandBufSize
// Specifies the minimum number of bytes that the driver must
// allocate for the swap Command Buffer. This member is valid only
// when the D3DNTHALDP2_REQCOMMANDBUFSIZE flag is set. Drivers that
// do not support multi-buffering of Command Buffers should ignore
// this member.
// .lpdwRStates
// Points to a render state array that the driver should update
// when it parses render state commands from the Command Buffer.
// The driver should update this array only when the
// D3DNTHALDP2_EXECUTEBUFFER flag is set in dwFlags. The driver
// should use the D3DRENDERSTATETYPE enumerated types to update
// the appropriate render state's array element.
// .dwVertexSize
// Used to pass in the size of each vertex in bytes. Union with
// ddrval.
// .ddrval
// Specifies the location in which the driver writes the return
// value of D3dDrawPrimitives2. D3D_OK indicates success;
// otherwise, the driver should return the appropriate
// D3DNTERR_Xxx error code.
// .dwErrorOffset
// Specifies the location in which the driver should write the
// offset into the surface to which lpDDCommands points at which
// the first unhandled D3DNTHAL_DP2COMMAND can be found. The
// driver must set this value when it returns an error condition
// in ddrval.
//
//-----------------------------------------------------------------------------
DWORD WINAPI D3DDrawPrimitives2_P3( LPD3DHAL_DRAWPRIMITIVES2DATA pdp2d ) { P3_THUNKEDDATA* pThisDisplay; P3_D3DCONTEXT* pContext; LPDWORD lpVertices; P3_VERTEXBUFFERINFO* pVertexBufferInfo; P3_VERTEXBUFFERINFO* pCommandBufferInfo; LPD3DHAL_DP2COMMAND lpIns; LPBYTE lpInsStart; LPBYTE lpPrim; BOOL bParseError = FALSE; BOOL bUsedHostIn = FALSE; HRESULT ddrval; LPBYTE pUMVtx; int i;
DBG_CB_ENTRY(D3DDrawPrimitives2_P3);
// Get current context and validate it
pContext = _D3D_CTX_HandleToPtr(pdp2d->dwhContext); if (!CHECK_D3DCONTEXT_VALIDITY(pContext)) { pdp2d->ddrval = D3DHAL_CONTEXT_BAD; DISPDBG((ERRLVL,"ERROR: Context not valid")); DBG_CB_EXIT(D3DDrawPrimitives2_P3, D3DHAL_CONTEXT_BAD); return (DDHAL_DRIVER_HANDLED); } // Get and validate driver data
pThisDisplay = pContext->pThisDisplay; VALIDATE_MODE_AND_STATE(pThisDisplay);
// Debugging messages
DISPDBG((DBGLVL, " dwhContext = %x",pdp2d->dwhContext)); DISPDBG((DBGLVL, " dwFlags = %x",pdp2d->dwFlags)); DBGDUMP_D3DDP2FLAGS(DBGLVL, pdp2d->dwFlags); DISPDBG((DBGLVL, " dwVertexType = %x",pdp2d->dwVertexType)); DISPDBG((DBGLVL, " dwCommandOffset = %d",pdp2d->dwCommandOffset)); DISPDBG((DBGLVL, " dwCommandLength = %d",pdp2d->dwCommandLength)); DISPDBG((DBGLVL, " dwVertexOffset = %d",pdp2d->dwVertexOffset)); DISPDBG((DBGLVL, " dwVertexLength = %d",pdp2d->dwVertexLength)); DISPDBG((DBGLVL, " dwReqVertexBufSize = %d",pdp2d->dwReqVertexBufSize)); DISPDBG((DBGLVL, " dwReqCommandBufSize = %d",pdp2d->dwReqCommandBufSize));
// Get appropriate pointers to commands in command buffer
lpInsStart = (LPBYTE)(pdp2d->lpDDCommands->lpGbl->fpVidMem); if (lpInsStart == NULL) { DISPDBG((ERRLVL, "ERROR: Command Buffer pointer is null")); pdp2d->ddrval = DDERR_INVALIDPARAMS; DBG_CB_EXIT(D3DDrawPrimitives2_P3, DDERR_INVALIDPARAMS); return DDHAL_DRIVER_HANDLED; } lpIns = (LPD3DHAL_DP2COMMAND)(lpInsStart + pdp2d->dwCommandOffset);
// Check if vertex buffer resides in user memory or in a DDraw surface
if (pdp2d->dwFlags & D3DHALDP2_USERMEMVERTICES) { pUMVtx = (LPBYTE)pdp2d->lpVertices; // Get appropriate pointer to vertices , memory is already secured
lpVertices = (LPDWORD)((LPBYTE)pdp2d->lpVertices + pdp2d->dwVertexOffset); } else { // Get appropriate pointer to vertices
lpVertices = (LPDWORD)((LPBYTE)pdp2d->lpDDVertex->lpGbl->fpVidMem + pdp2d->dwVertexOffset); }
if (lpVertices == NULL) { DISPDBG((ERRLVL, "ERROR: Vertex Buffer pointer is null")); pdp2d->ddrval = DDERR_INVALIDPARAMS; DBG_CB_EXIT(D3DDrawPrimitives2_P3, DDERR_INVALIDPARAMS); return DDHAL_DRIVER_HANDLED; }
#if DX8_DDI
// Take notice of the following block of code necessary
// for DX8 drivers to run <= DX7 apps succesfully!
#endif // DX8_DDI
// Take the VB format and address from our header info if we are
// processing a DX7 or earlier context. Otherwise we'll get updates
// through the new DX8 DP2 tokens (D3DDP2OP_SETSTREAMSOURCE &
// D3DDP2OP_SETVERTEXSHADER)
if (IS_DX7_OR_EARLIER_APP(pContext)) { // Update place from where vertices will be processed for this context
pContext->lpVertices = lpVertices;
// Update the FVF code to be used currently.
pContext->dwVertexType = pdp2d->dwVertexType; }
// Switch to the chips D3D context and get ready for rendering
STOP_SOFTWARE_CURSOR(pThisDisplay); D3D_OPERATION(pContext, pThisDisplay);
//@@BEGIN_DDKSPLIT
//AZN This check for flips is here because otherwise DX3 tunnel in FS flickers
//@@END_DDKSPLIT
// Can return if still drawing
pdp2d->ddrval = _DX_QueryFlipStatus(pThisDisplay, pContext->pSurfRenderInt->fpVidMem, TRUE);
if( FAILED( pdp2d->ddrval ) ) { DISPDBG((DBGLVL,"Returning because flip has not occurred")); START_SOFTWARE_CURSOR(pThisDisplay);
DBG_CB_EXIT(D3DDrawPrimitives2_P3, 0); return DDHAL_DRIVER_HANDLED; }
//@@BEGIN_DDKSPLIT
#if DX7_VERTEXBUFFERS
_D3D_EB_GetAndWaitForBuffers(pThisDisplay, pdp2d, &pCommandBufferInfo, &pVertexBufferInfo); #endif
//@@END_DDKSPLIT
DISPDBG((DBGLVL,"Command Buffer @ %x Vertex Buffer @ %x", lpIns, lpVertices));
// Process commands while we haven't exhausted the command buffer
while (!bParseError && ((LPBYTE)lpIns < (lpInsStart + pdp2d->dwCommandLength + pdp2d->dwCommandOffset) ) ) { // Get pointer to first primitive structure past the D3DHAL_DP2COMMAND
lpPrim = (LPBYTE)lpIns + sizeof(D3DHAL_DP2COMMAND);
DISPDBG((DBGLVL, "DrawPrimitive2: Parsing instruction %d Count = %d @ %x", lpIns->bCommand, lpIns->wPrimitiveCount, lpIns));
// Look for opcodes that cause rendering - we need to process state
// changes and wait for any pending flip.
switch( lpIns->bCommand ) { case D3DDP2OP_RENDERSTATE: case D3DDP2OP_TEXTURESTAGESTATE: case D3DDP2OP_STATESET: case D3DDP2OP_VIEWPORTINFO: case D3DDP2OP_WINFO: case D3DDP2OP_UPDATEPALETTE: case D3DDP2OP_SETPALETTE: #if DX7_TEXMANAGEMENT
case D3DDP2OP_SETTEXLOD: case D3DDP2OP_SETPRIORITY: #if DX8_DDI
case D3DDP2OP_ADDDIRTYRECT: case D3DDP2OP_ADDDIRTYBOX: #endif // DX8_DDI
#endif
case D3DDP2OP_ZRANGE: case D3DDP2OP_SETMATERIAL: case D3DDP2OP_SETLIGHT: case D3DDP2OP_CREATELIGHT: case D3DDP2OP_EXT: case D3DDP2OP_SETTRANSFORM: case D3DDP2OP_SETRENDERTARGET:
#if DX8_DDI
case D3DDP2OP_CREATEVERTEXSHADER: case D3DDP2OP_SETVERTEXSHADER: case D3DDP2OP_DELETEVERTEXSHADER: case D3DDP2OP_SETVERTEXSHADERCONST: case D3DDP2OP_CREATEPIXELSHADER: case D3DDP2OP_SETPIXELSHADER: case D3DDP2OP_DELETEPIXELSHADER: case D3DDP2OP_SETPIXELSHADERCONST: case D3DDP2OP_SETSTREAMSOURCE : case D3DDP2OP_SETSTREAMSOURCEUM : case D3DDP2OP_SETINDICES :
#endif // DX8_DDI
// These opcodes don't cause any rendering - do nothing
break;
default:
// The primitive type is not actually important to
// make sure the hw setup changes have been done.
_D3D_ST_RealizeHWStateChanges( pContext );
// Need to reset the FVF data because it
// depends on the texture setup
if (__CheckFVFRequest(pContext, pContext->dwVertexType) != DD_OK) { DISPDBG((ERRLVL, "ERROR: D3DDrawPrimitives2_P3 cannot handle " "Flexible Vertex Format requested"));
PARSE_ERROR_AND_EXIT( pdp2d, lpIns, lpInsStart, D3DERR_COMMAND_UNPARSED); }
// Fall through as we don't need to handle any new state or
// check our FVF formats if we're only clearing or blitting
// surfaces
case D3DDP2OP_CLEAR: case D3DDP2OP_TEXBLT: #if DX8_DDI
case D3DDP2OP_VOLUMEBLT: case D3DDP2OP_BUFFERBLT: #endif // DX8_DDI
// Check to see if any pending physical flip has occurred
//@@BEGIN_DDKSPLIT
//
// The runtime doesn't expect to see DDERR_WASSTILLDRAWING
// when using DP2 to emulate Execute buffers, so we have to
// spin here. Also, if we have processed any of this command
// buffer we are forced into spinning here because if we
// returned the runtime would not know about the already
// processed commands and we would process them again -
// probably a bad thing. We must do this check here rather
// than earlier because in some cases DP2 gets called when
// the render surface has been freed. This causes an exception
// if we try to check the flip status.
if(( pdp2d->dwFlags & D3DHALDP2_EXECUTEBUFFER ) || ( lpIns > (LPD3DHAL_DP2COMMAND)( lpInsStart + pdp2d->dwCommandOffset ))) { while( _DX_QueryFlipStatus(pThisDisplay, pContext->pSurfRenderInt->fpVidMem, TRUE) == DDERR_WASSTILLDRAWING ) { // Waste time - could back off here
} } else //@@END_DDKSPLIT
{ // Can return if still drawing
pdp2d->ddrval = _DX_QueryFlipStatus(pThisDisplay, pContext->pSurfRenderInt->fpVidMem, TRUE);
if( FAILED ( pdp2d->ddrval ) ) { DISPDBG((DBGLVL,"Returning because flip has not occurred")); START_SOFTWARE_CURSOR(pThisDisplay);
DBG_CB_EXIT(D3DDrawPrimitives2_P3, 0); return DDHAL_DRIVER_HANDLED; } } break; }
switch( lpIns->bCommand ) {
case D3DDP2OP_VIEWPORTINFO: // Used to inform the guard-band aware drivers, the view
// clipping rectangle. Non-guard-band drivers should ignore
// and skip over these instructions and continue processing
// the rest of the command buffer. The clipping rectangle is
// specified by the members dwX, dwY, dwWidth and dwHeight.
DISPDBG((DBGLVL, "D3DDP2OP_VIEWPORTINFO")); CHECK_CMDBUF_LIMITS(pdp2d, lpPrim, D3DHAL_DP2VIEWPORTINFO, lpIns->wStateCount, 0);
for( i = 0; i < lpIns->wStateCount; i++) { // There should be only one of these, but we'll pay attention
// to the last one just in case
_D3D_OP_Viewport(pContext, (D3DHAL_DP2VIEWPORTINFO*)lpPrim);
lpPrim += sizeof(D3DHAL_DP2VIEWPORTINFO); } NEXTINSTRUCTION(lpIns, D3DHAL_DP2VIEWPORTINFO, lpIns->wStateCount, 0); break;
case D3DDP2OP_WINFO: // Record the W Buffering info
DISPDBG((DBGLVL, "D3DDP2OP_WINFO")); CHECK_CMDBUF_LIMITS(pdp2d, lpPrim, D3DHAL_DP2WINFO, lpIns->wStateCount, 0);
pContext->WBufferInfo = *((D3DHAL_DP2WINFO*)lpPrim); DIRTY_WBUFFER(pContext);
lpPrim += sizeof(D3DHAL_DP2WINFO); NEXTINSTRUCTION(lpIns, D3DHAL_DP2WINFO, lpIns->wStateCount, 0); break;
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.
DISPDBG((DBGLVL,"D3DDP2OP_RENDERSTATE: state count = %d", lpIns->wStateCount)); CHECK_CMDBUF_LIMITS(pdp2d, lpPrim, D3DHAL_DP2RENDERSTATE, lpIns->wStateCount, 0);
if (pdp2d->dwFlags & D3DHALDP2_EXECUTEBUFFER) { _D3D_ST_ProcessRenderStates(pContext, lpIns->wStateCount, (LPD3DSTATE)lpPrim, TRUE);
// As the render states vector lives in user memory, we need to
// access it bracketing it with a try/except block. This
// is because the user memory might under some circumstances
// become invalid while the driver is running and then it
// would AV. Also, the driver might need to do some cleanup
// before returning to the OS.
__try { for (i = lpIns->wStateCount; i > 0; i--) { pdp2d->lpdwRStates[((D3DHAL_DP2RENDERSTATE*)lpPrim)->RenderState] = ((D3DHAL_DP2RENDERSTATE*)lpPrim)->dwState; lpPrim += sizeof(D3DHAL_DP2RENDERSTATE); } } __except(EXCEPTION_EXECUTE_HANDLER) { // On this driver we don't need to do anything special
DISPDBG((ERRLVL,"Driver caused exception at " "line %u of file %s", __LINE__,__FILE__)); PARSE_ERROR_AND_EXIT( pdp2d, lpIns, lpInsStart, DDERR_GENERIC); }
} else { _D3D_ST_ProcessRenderStates(pContext, lpIns->wStateCount, (LPD3DSTATE)lpPrim, FALSE); lpPrim += (sizeof(D3DHAL_DP2RENDERSTATE) * lpIns->wStateCount); }
NEXTINSTRUCTION(lpIns, D3DHAL_DP2RENDERSTATE, lpIns->wStateCount, 0); break;
case D3DDP2OP_TEXTURESTAGESTATE: DISPDBG((DBGLVL,"D3DDP2OP_TEXTURESTAGESTATE: state count = %d", lpIns->wStateCount)); CHECK_CMDBUF_LIMITS(pdp2d, lpPrim, D3DHAL_DP2TEXTURESTAGESTATE, lpIns->wStateCount , 0);
_D3D_TXT_ParseTextureStageStates( pContext, (D3DHAL_DP2TEXTURESTAGESTATE*)lpPrim, lpIns->wStateCount, TRUE); lpPrim += sizeof(D3DHAL_DP2TEXTURESTAGESTATE) * lpIns->wStateCount; NEXTINSTRUCTION(lpIns, D3DHAL_DP2TEXTURESTAGESTATE, lpIns->wStateCount , 0); break;
case D3DDP2OP_STATESET: { D3DHAL_DP2STATESET *pStateSetOp = (D3DHAL_DP2STATESET*)(lpPrim); DISPDBG((DBGLVL,"D3DDP2OP_STATESET: state count = %d", lpIns->wStateCount));
CHECK_CMDBUF_LIMITS(pdp2d, lpPrim, D3DHAL_DP2STATESET, lpIns->wStateCount, 0); #if DX7_D3DSTATEBLOCKS
for (i = 0; i < lpIns->wStateCount; i++, pStateSetOp++) { switch (pStateSetOp->dwOperation) { #if DX8_DDI
case D3DHAL_STATESETCREATE : // This DDI should be called only for drivers > DX7
// and only for those which support TLHals. It is
// called only when the device created is a pure-device
// On receipt of this request the driver should create
// a state block of the type given in the field sbType
// and capture the current given state into it.
break; #endif //DX8_DDI
case D3DHAL_STATESETBEGIN : _D3D_SB_BeginStateSet(pContext,pStateSetOp->dwParam); break; case D3DHAL_STATESETEND : _D3D_SB_EndStateSet(pContext); break; case D3DHAL_STATESETDELETE : _D3D_SB_DeleteStateSet(pContext,pStateSetOp->dwParam); break; case D3DHAL_STATESETEXECUTE: _D3D_SB_ExecuteStateSet(pContext,pStateSetOp->dwParam); break; case D3DHAL_STATESETCAPTURE: _D3D_SB_CaptureStateSet(pContext,pStateSetOp->dwParam); break; default : DISPDBG((ERRLVL,"D3DDP2OP_STATESET has invalid" "dwOperation %08lx",pStateSetOp->dwOperation)); } } #endif //DX7_D3DSTATEBLOCKS
// Update the command buffer pointer
NEXTINSTRUCTION(lpIns, D3DHAL_DP2STATESET, lpIns->wStateCount, 0); } break;
case D3DDP2OP_ZRANGE: DISPDBG((DBGLVL, "D3DDP2OP_ZRANGE")); CHECK_CMDBUF_LIMITS(pdp2d, lpPrim, D3DHAL_DP2ZRANGE, lpIns->wStateCount, 0);
for( i = 0; i < lpIns->wStateCount; i++) { // There should be only one of these, but we'll pay attention
// to the last one just in case
_D3D_OP_ZRange(pContext, (D3DHAL_DP2ZRANGE*)lpPrim); lpPrim += sizeof(D3DHAL_DP2ZRANGE); } NEXTINSTRUCTION(lpIns, D3DHAL_DP2ZRANGE, 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* pUpdatePalette;
DISPDBG((DBGLVL, "D3DDP2OP_UPDATEPALETTE")); CHECK_CMDBUF_LIMITS(pdp2d, lpPrim, D3DHAL_DP2UPDATEPALETTE, 1, 0);
pUpdatePalette = (D3DHAL_DP2UPDATEPALETTE *)lpPrim; // Each palette entry is a DWORD ARGB 8:8:8:8
CHECK_CMDBUF_LIMITS(pdp2d, lpPrim, D3DHAL_DP2UPDATEPALETTE, 1, pUpdatePalette->wNumEntries * sizeof(DWORD));
ddrval = _D3D_OP_UpdatePalette(pContext, pUpdatePalette, (LPDWORD)(pUpdatePalette + 1)); if ( FAILED(ddrval) ) { PARSE_ERROR_AND_EXIT( pdp2d, lpIns, lpInsStart, ddrval); }
lpPrim += (sizeof(D3DHAL_DP2UPDATEPALETTE) + pUpdatePalette->wNumEntries * 4); // Each palette entry is a DWORD ARGB 8:8:8:8
NEXTINSTRUCTION(lpIns, D3DHAL_DP2UPDATEPALETTE, 1, pUpdatePalette->wNumEntries * sizeof(DWORD)); }
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
{ DISPDBG((DBGLVL, "D3DDP2OP_SETPALETTE")); CHECK_CMDBUF_LIMITS(pdp2d, lpPrim, D3DHAL_DP2SETPALETTE, lpIns->wStateCount, 0);
ddrval = _D3D_OP_SetPalettes(pContext, (D3DHAL_DP2SETPALETTE *)lpPrim, lpIns->wStateCount); if ( FAILED(ddrval) ) { PARSE_ERROR_AND_EXIT( pdp2d, lpIns, lpInsStart, ddrval); }
lpPrim += sizeof(D3DHAL_DP2SETPALETTE) * lpIns->wStateCount; NEXTINSTRUCTION(lpIns, D3DHAL_DP2SETPALETTE, lpIns->wStateCount, 0); } break;
#if DX7_TEXMANAGEMENT
case D3DDP2OP_SETTEXLOD: { D3DHAL_DP2SETTEXLOD* pTexLod; DISPDBG((DBGLVL, "D3DDP2OP_SETTEXLOD")); CHECK_CMDBUF_LIMITS(pdp2d, lpPrim, D3DHAL_DP2SETTEXLOD, lpIns->wStateCount, 0);
for( i = 0; i < lpIns->wStateCount; i++) { // Get the passed material
pTexLod = ((D3DHAL_DP2SETTEXLOD*)lpPrim); lpPrim += sizeof(D3DHAL_DP2SETTEXLOD); _D3D_OP_SetTexLod(pContext, pTexLod); }
NEXTINSTRUCTION(lpIns, D3DHAL_DP2SETTEXLOD, lpIns->wStateCount, 0); } break; case D3DDP2OP_SETPRIORITY: { D3DHAL_DP2SETPRIORITY* pSetPri; DISPDBG((DBGLVL, "D3DDP2OP_SETPRIORITY")); CHECK_CMDBUF_LIMITS(pdp2d, lpPrim, D3DHAL_DP2SETPRIORITY, lpIns->wStateCount, 0);
for( i = 0; i < lpIns->wStateCount; i++) { // Get the passed material
pSetPri = ((D3DHAL_DP2SETPRIORITY*)lpPrim); lpPrim += sizeof(D3DHAL_DP2SETPRIORITY); _D3D_OP_SetPriority(pContext, pSetPri); }
NEXTINSTRUCTION(lpIns, D3DHAL_DP2SETPRIORITY, lpIns->wStateCount, 0); } break;
#if DX8_DDI
case D3DDP2OP_ADDDIRTYRECT: { D3DHAL_DP2ADDDIRTYRECT* pAddRect; DISPDBG((DBGLVL, "D3DDP2OP_ADDDIRTYRECT")); CHECK_CMDBUF_LIMITS(pdp2d, lpPrim, D3DDP2OP_ADDDIRTYRECT, lpIns->wStateCount, 0);
for( i = 0; i < lpIns->wStateCount; i++) { // Get the dirty rect
pAddRect = ((D3DHAL_DP2ADDDIRTYRECT*)lpPrim); lpPrim += sizeof(D3DHAL_DP2ADDDIRTYRECT); _D3D_OP_AddDirtyRect(pContext, pAddRect); }
NEXTINSTRUCTION(lpIns, D3DHAL_DP2ADDDIRTYRECT, lpIns->wStateCount, 0); } break; case D3DDP2OP_ADDDIRTYBOX: { D3DHAL_DP2ADDDIRTYBOX* pAddBox; DISPDBG((DBGLVL, "D3DDP2OP_ADDDIRTYBOX")); CHECK_CMDBUF_LIMITS(pdp2d, lpPrim, D3DDP2OP_ADDDIRTYBOX, lpIns->wStateCount, 0);
for( i = 0; i < lpIns->wStateCount; i++) { // Get the dirty rect
pAddBox = ((D3DHAL_DP2ADDDIRTYBOX*)lpPrim); lpPrim += sizeof(D3DHAL_DP2ADDDIRTYBOX); _D3D_OP_AddDirtyBox(pContext, pAddBox); }
NEXTINSTRUCTION(lpIns, D3DHAL_DP2ADDDIRTYBOX, lpIns->wStateCount, 0); } break; #endif // DX8_DDI
#endif // DX7_TEXMANAGEMENT
case D3DDP2OP_SETCLIPPLANE: { D3DHAL_DP2SETCLIPPLANE* pSetPlane; DISPDBG((DBGLVL, "D3DDP2OP_SETCLIPPLANE")); CHECK_CMDBUF_LIMITS(pdp2d, lpPrim, D3DHAL_DP2SETCLIPPLANE, lpIns->wStateCount, 0);
for( i = 0; i < lpIns->wStateCount; i++) { // Get the passed material
pSetPlane = ((D3DHAL_DP2SETCLIPPLANE*)lpPrim); lpPrim += sizeof(D3DHAL_DP2SETCLIPPLANE);
// (unimplemented OP as we don't support user
// defined clipping planes)
// _D3D_OP_SetClipPlane(pContext, pSetPlane);
}
NEXTINSTRUCTION(lpIns, D3DHAL_DP2SETCLIPPLANE, lpIns->wStateCount, 0); }
break;
case D3DDP2OP_SETMATERIAL: { D3DHAL_DP2SETMATERIAL* pSetMaterial; DISPDBG((DBGLVL, "D3DDP2OP_SETMATERIAL")); CHECK_CMDBUF_LIMITS(pdp2d, lpPrim, D3DHAL_DP2SETMATERIAL, lpIns->wStateCount, 0);
for( i = 0; i < lpIns->wStateCount; i++) { // Get the passed material
pSetMaterial = ((D3DHAL_DP2SETMATERIAL*)lpPrim); lpPrim += sizeof(D3DHAL_DP2SETMATERIAL);
// (unimplemented OP as we are not a TnL driver)
// _D3D_OP_SetMaterial(pContext, pSetMaterial);
DIRTY_MATERIAL; DBGDUMP_D3DMATERIAL7(DBGLVL, &pSetMaterial); }
NEXTINSTRUCTION(lpIns, D3DHAL_DP2SETMATERIAL, lpIns->wStateCount, 0); } break;
case D3DDP2OP_SETLIGHT: { D3DHAL_DP2SETLIGHT* pSetLight;
DISPDBG((DBGLVL, "D3DDP2OP_SETLIGHT")); CHECK_CMDBUF_LIMITS(pdp2d, lpPrim, D3DHAL_DP2SETLIGHT, lpIns->wStateCount, 0);
for( i = 0; i < lpIns->wStateCount; i++) { // Get the passed in light
pSetLight = (D3DHAL_DP2SETLIGHT*)lpPrim; lpPrim += sizeof(D3DHAL_DP2SETLIGHT);
// (unimplemented OP as we are not a TnL driver)
// _D3D_OP_SetLight(pContext, pSetLight);
DIRTY_GAMMA_STATE; }
NEXTINSTRUCTION(lpIns, D3DHAL_DP2SETLIGHT, lpIns->wStateCount, 0);
} break;
case D3DDP2OP_CREATELIGHT: { D3DHAL_DP2CREATELIGHT* pCreateLight;
DISPDBG((DBGLVL, "D3DDP2OP_CREATELIGHT")); CHECK_CMDBUF_LIMITS(pdp2d, lpPrim, D3DHAL_DP2CREATELIGHT, 1, 0);
pCreateLight = (D3DHAL_DP2CREATELIGHT*)lpPrim;
DISPDBG((DBGLVL,"Creating light, handle: 0x%x", pCreateLight->dwIndex));
DIRTY_GAMMA_STATE;
lpPrim += sizeof(D3DHAL_DP2CREATELIGHT); NEXTINSTRUCTION(lpIns, D3DHAL_DP2CREATELIGHT, 1, 0); } break;
case D3DDP2OP_SETTRANSFORM: { D3DHAL_DP2SETTRANSFORM* pTransform;
DISPDBG((DBGLVL, "D3DDP2OP_SETTRANSFORM")); CHECK_CMDBUF_LIMITS(pdp2d, lpPrim, D3DHAL_DP2SETTRANSFORM, lpIns->wStateCount, 0);
for( i = 0; i < lpIns->wStateCount; i++) { pTransform = (D3DHAL_DP2SETTRANSFORM*)lpPrim; switch(pTransform->xfrmType) { case D3DTRANSFORMSTATE_WORLD: DISPDBG((DBGLVL,"D3DTRANSFORMSTATE_WORLD")); DIRTY_MODELVIEW; break;
case D3DTRANSFORMSTATE_VIEW: DISPDBG((DBGLVL,"D3DTRANSFORMSTATE_VIEW")); DIRTY_MODELVIEW; break;
case D3DTRANSFORMSTATE_PROJECTION: DISPDBG((DBGLVL,"D3DTRANSFORMSTATE_PROJECTION")); DIRTY_PROJECTION; break;
default: DISPDBG((ERRLVL,"Texture transform not handled yet!")); break; }
// (unimplemented OP as we are not a TnL driver)
// _D3D_OP_SetTransform(pContext, pTransform);
// display the matrix in the debugger
DBGDUMP_D3DMATRIX(DBGLVL, &pTransform->matrix);
lpPrim += sizeof(D3DHAL_DP2SETTRANSFORM); }
NEXTINSTRUCTION(lpIns, D3DHAL_DP2SETTRANSFORM, lpIns->wStateCount, 0); } break;
case D3DDP2OP_EXT: DISPDBG((ERRLVL, "D3DDP2OP_EXT")); CHECK_CMDBUF_LIMITS(pdp2d, lpPrim, DWORD, 1, 0);
lpPrim += sizeof(DWORD); NEXTINSTRUCTION(lpIns, DWORD, 1, 0);
break;
case D3DDP2OP_CLEAR: { D3DHAL_DP2CLEAR* pClear;
DISPDBG((DBGLVL, "D3DDP2OP_CLEAR")); CHECK_CMDBUF_LIMITS(pdp2d, lpPrim, D3DHAL_DP2CLEAR, 1, (lpIns->wStateCount - 1)*sizeof(RECT) );
pClear = (D3DHAL_DP2CLEAR*)lpPrim;
// Notice that the interpretation of wStateCount for this
// operation is special: wStateCount means the number of
// RECTs following the D3DHAL_DP2CLEAR struct
_D3D_OP_Clear2(pContext, pClear, lpIns->wStateCount);
// Return to the 3D state, because the above call
// will have switched us to a DDRAW hw context
D3D_OPERATION(pContext, pThisDisplay);
lpPrim += sizeof(D3DHAL_DP2CLEAR); NEXTINSTRUCTION(lpIns, D3DHAL_DP2CLEAR, 1, (lpIns->wStateCount - 1)*sizeof(RECT) ); } break;
case D3DDP2OP_SETRENDERTARGET: { D3DHAL_DP2SETRENDERTARGET* pSetRenderTarget; P3_SURF_INTERNAL* pFrameBuffer; P3_SURF_INTERNAL* pZBuffer; BOOL bNewAliasBuffers;
DISPDBG((DBGLVL, "D3DDP2OP_SETRENDERTARGET")); CHECK_CMDBUF_LIMITS(pdp2d, lpPrim, D3DHAL_DP2SETRENDERTARGET, 1, 0);
pSetRenderTarget = (D3DHAL_DP2SETRENDERTARGET*)lpPrim;
pFrameBuffer = GetSurfaceFromHandle(pContext, pSetRenderTarget->hRenderTarget); pZBuffer = GetSurfaceFromHandle(pContext, pSetRenderTarget->hZBuffer);
// Check that the Framebuffer is valid
if (pFrameBuffer == NULL) { DISPDBG((ERRLVL, "ERROR: " "FrameBuffer Surface is invalid!")); PARSE_ERROR_AND_EXIT( pdp2d, lpIns, lpInsStart, DDERR_GENERIC); }
// Decide whether the render target's size has changed
bNewAliasBuffers = TRUE; if ((pContext->pSurfRenderInt) && (pContext->pSurfRenderInt->wWidth == pFrameBuffer->wWidth) && (pContext->pSurfRenderInt->wHeight == pFrameBuffer->wHeight)) { bNewAliasBuffers = FALSE; }
// Setup in hw the new render target and zbuffer
if (FAILED(_D3D_OP_SetRenderTarget(pContext, pFrameBuffer, pZBuffer, bNewAliasBuffers) ) ) { DISPDBG((ERRLVL, "ERROR: " "FrameBuffer Surface Format is invalid!")); PARSE_ERROR_AND_EXIT( pdp2d, lpIns, lpInsStart, DDERR_GENERIC); }
// Dirty the renderstate so that the hw setup is reevaluated
// next time before we render anything
DIRTY_RENDER_OFFSETS(pContext); DIRTY_ALPHABLEND(pContext); DIRTY_OPTIMIZE_ALPHA(pContext); DIRTY_ZBUFFER(pContext); DIRTY_VIEWPORT(pContext);
lpPrim += sizeof(D3DHAL_DP2SETRENDERTARGET); NEXTINSTRUCTION(lpIns, D3DHAL_DP2SETRENDERTARGET, 1, 0); } break;
case D3DDP2OP_TEXBLT: { DISPDBG((DBGLVL, "D3DDP2OP_TEXBLT")); CHECK_CMDBUF_LIMITS(pdp2d, lpPrim, D3DHAL_DP2TEXBLT, lpIns->wStateCount, 0);
for ( i = 0; i < lpIns->wStateCount; i++) { // As the texture might live in user memory, we need to
// access it bracketing it with a try/except block. This
// is because the user memory might under some circumstances
// become invalid while the driver is running and then it
// would AV. Also, the driver might need to do some cleanup
// before returning to the OS.
__try { _D3D_OP_TextureBlt(pContext, pThisDisplay, (D3DHAL_DP2TEXBLT*)(lpPrim)); } __except(EXCEPTION_EXECUTE_HANDLER) { // On this driver we don't need to do anything special
DISPDBG((ERRLVL,"Driver caused exception at " "line %u of file %s", __LINE__,__FILE__)); PARSE_ERROR_AND_EXIT( pdp2d, lpIns, lpInsStart, DDERR_GENERIC); } lpPrim += sizeof(D3DHAL_DP2TEXBLT); } NEXTINSTRUCTION(lpIns, D3DHAL_DP2TEXBLT, lpIns->wStateCount, 0); } break;
#if DX8_VERTEXSHADERS
case D3DDP2OP_CREATEVERTEXSHADER: { D3DHAL_DP2CREATEVERTEXSHADER* pCreateVtxShader; DWORD dwExtraBytes = 0;
DISPDBG((DBGLVL, "D3DDP2OP_CREATEVERTEXSHADER"));
// iterate through each passed vertex shader creation block
for (i = 0; i < lpIns->wStateCount; i++) { // verify that the next vertex shader is readable
CHECK_CMDBUF_LIMITS(pdp2d, lpPrim, D3DHAL_DP2CREATEVERTEXSHADER, 1, 0);
// Get the passed in vertex shader
pCreateVtxShader = (D3DHAL_DP2CREATEVERTEXSHADER*)lpPrim;
// Check if the size of the declaration and body of the
// vertex shader don't exceed the command buffer limits
CHECK_CMDBUF_LIMITS_S(pdp2d, lpPrim, 0, 0, pCreateVtxShader->dwDeclSize + pCreateVtxShader->dwCodeSize);
// Advance lpPrim so that it points to the vertex shader's
// declaration and body
lpPrim += sizeof(D3DHAL_DP2CREATEVERTEXSHADER);
// Create this particular shader
ddrval = _D3D_OP_VertexShader_Create(pContext, pCreateVtxShader->dwHandle, pCreateVtxShader->dwDeclSize, pCreateVtxShader->dwCodeSize, lpPrim);
if ( FAILED(ddrval) ) { DISPDBG((ERRLVL, "ERROR: " "Vertex Shader couldn't be created!")); PARSE_ERROR_AND_EXIT( pdp2d, lpIns, lpInsStart, D3DERR_DRIVERINVALIDCALL); } // Update lpPrim in order to get to the next vertex
// shader creation command block.
dwExtraBytes += pCreateVtxShader->dwDeclSize + pCreateVtxShader->dwCodeSize;
lpPrim += pCreateVtxShader->dwDeclSize + pCreateVtxShader->dwCodeSize; }
// Now skip into the next DP2 token in the command buffer
NEXTINSTRUCTION(lpIns, D3DHAL_DP2CREATEVERTEXSHADER, lpIns->wStateCount, dwExtraBytes); } break; case D3DDP2OP_SETVERTEXSHADER: { D3DHAL_DP2VERTEXSHADER* pSetVtxShader;
DISPDBG((DBGLVL, "D3DHAL_DP2SETVERTEXSHADER"));
// Following the DP2 token there is one and only one
// set vertex shader block. But lets accomodate if for
// any reason we receive more than one
CHECK_CMDBUF_LIMITS(pdp2d, lpPrim, D3DHAL_DP2VERTEXSHADER, lpIns->wStateCount, 0);
for (i = 0; i < lpIns->wStateCount; i++) { // Get the passed in vertex shader
pSetVtxShader = (D3DHAL_DP2VERTEXSHADER*)lpPrim;
// Setup the given vertex shader.
_D3D_OP_VertexShader_Set(pContext, pSetVtxShader->dwHandle);
// Now skip into the next DP2 token in the command buffer
lpPrim += sizeof(D3DHAL_DP2VERTEXSHADER); } NEXTINSTRUCTION(lpIns, D3DHAL_DP2VERTEXSHADER, lpIns->wStateCount, 0); } break; case D3DDP2OP_DELETEVERTEXSHADER: { D3DHAL_DP2VERTEXSHADER* pDelVtxShader;
DISPDBG((DBGLVL, "D3DDP2OP_DELETEVERTEXSHADER"));
// verify that all the following vertex shader
// delete blocks are readable
CHECK_CMDBUF_LIMITS(pdp2d, lpPrim, D3DHAL_DP2VERTEXSHADER, lpIns->wStateCount, 0);
// iterate through each passed vertex shader delete block
for (i = 0; i < lpIns->wStateCount; i++) { // Get the passed in vertex shader
pDelVtxShader = (D3DHAL_DP2VERTEXSHADER*)lpPrim;
// Destroy the given vertex shader.
_D3D_OP_VertexShader_Delete(pContext, pDelVtxShader->dwHandle);
// Update lpPrim in order to get to the next vertex
// shader delete command block.
lpPrim += sizeof(D3DHAL_DP2VERTEXSHADER); }
// Now skip into the next DP2 token in the command buffer
NEXTINSTRUCTION(lpIns, D3DHAL_DP2VERTEXSHADER, lpIns->wStateCount, 0); } break; case D3DDP2OP_SETVERTEXSHADERCONST: { D3DHAL_DP2SETVERTEXSHADERCONST* pVtxShaderConst; DWORD dwExtraBytes = 0;
DISPDBG((DBGLVL, "D3DDP2OP_SETVERTEXSHADERCONST"));
// verify that all the following vertex shader
// constant blocks are readable
CHECK_CMDBUF_LIMITS(pdp2d, lpPrim, D3DHAL_DP2SETVERTEXSHADERCONST, lpIns->wStateCount, 0);
// iterate through each passed vertex shader constant block
for (i = 0; i < lpIns->wStateCount; i++) { // Get the passed in vertex shader constant
pVtxShaderConst = (D3DHAL_DP2SETVERTEXSHADERCONST*)lpPrim;
// Advance lpPrim so that it points to the constant
// values to be loaded
lpPrim += sizeof(D3DHAL_DP2SETVERTEXSHADERCONST);
// constant block in order to Set up the constant entries
_D3D_OP_VertexShader_SetConst(pContext, pVtxShaderConst->dwRegister, pVtxShaderConst->dwCount, (DWORD *)lpPrim);
// Update lpPrim in order to get to the next vertex
// shader constants command block. Each register has 4 floats.
lpPrim += pVtxShaderConst->dwCount * 4 * sizeof(FLOAT);
dwExtraBytes += pVtxShaderConst->dwCount * 4 * sizeof(FLOAT); }
// Now skip into the next DP2 token in the command buffer
NEXTINSTRUCTION(lpIns, D3DHAL_DP2SETVERTEXSHADERCONST, lpIns->wStateCount, dwExtraBytes); } break; #endif // DX8_VERTEXSHADERS
#if DX8_PIXELSHADERS
case D3DDP2OP_CREATEPIXELSHADER: { D3DHAL_DP2CREATEPIXELSHADER* pCreatePxlShader; DWORD dwExtraBytes = 0;
DISPDBG((DBGLVL, "D3DDP2OP_CREATEPIXELSHADER"));
// iterate through each passed pixel shader creation block
for (i = 0; i < lpIns->wStateCount; i++) { // verify that the next pixel shader is readable
CHECK_CMDBUF_LIMITS(pdp2d, lpPrim, D3DHAL_DP2CREATEPIXELSHADER, 1, 0);
// Get the passed in pixel shader
pCreatePxlShader = (D3DHAL_DP2CREATEPIXELSHADER*)lpPrim;
// Check if the size of the declaration and body of the
// pixel shader don't exceed the command buffer limits
CHECK_CMDBUF_LIMITS_S(pdp2d, lpPrim, 0, 0, pCreatePxlShader->dwCodeSize);
// Update lpPrim to point to the actual pixel shader code
lpPrim += sizeof(D3DHAL_DP2CREATEPIXELSHADER);
// Create the given pixel shader
ddrval = _D3D_OP_PixelShader_Create(pContext, pCreatePxlShader->dwHandle, pCreatePxlShader->dwCodeSize, lpPrim);
if ( FAILED(ddrval) ) { DISPDBG((ERRLVL, "ERROR: " "Pixel Shader couldn't be created!")); PARSE_ERROR_AND_EXIT( pdp2d, lpIns, lpInsStart, D3DERR_DRIVERINVALIDCALL); }
// Update lpPrim in order to get to the next vertex
// shader creation command block.
lpPrim += pCreatePxlShader->dwCodeSize; dwExtraBytes += pCreatePxlShader->dwCodeSize; }
// Now skip into the next DP2 token in the command buffer
NEXTINSTRUCTION(lpIns, D3DHAL_DP2CREATEPIXELSHADER, lpIns->wStateCount, dwExtraBytes); } break; case D3DDP2OP_SETPIXELSHADER: { D3DHAL_DP2PIXELSHADER* pSetPxlShader;
DISPDBG((DBGLVL, "D3DHAL_DP2SETPIXELSHADER"));
// Following the DP2 token there is one and only one
// set pixel shader block. But lets accomodate if for
// any reason we receive more than one
CHECK_CMDBUF_LIMITS(pdp2d, lpPrim, D3DHAL_DP2PIXELSHADER, lpIns->wStateCount, 0);
for (i = 0; i < lpIns->wStateCount; i++) { // Get the passed in pixel shader
pSetPxlShader = (D3DHAL_DP2PIXELSHADER*)lpPrim;
// Setup the given pixel shader.
_D3D_OP_PixelShader_Set(pContext, pSetPxlShader->dwHandle);
// Now skip into the next DP2 token in the command buffer
lpPrim += sizeof(D3DHAL_DP2PIXELSHADER); } NEXTINSTRUCTION(lpIns, D3DHAL_DP2PIXELSHADER, lpIns->wStateCount, 0); } break; case D3DDP2OP_DELETEPIXELSHADER: { D3DHAL_DP2PIXELSHADER* pDelPxlShader;
DISPDBG((DBGLVL, "D3DDP2OP_DELETEPIXELSHADER"));
// verify that all the following pixel shader
// delete blocks are readable
CHECK_CMDBUF_LIMITS(pdp2d, lpPrim, D3DHAL_DP2PIXELSHADER, lpIns->wStateCount, 0);
// iterate through each passed vertex shader delete block
for (i = 0; i < lpIns->wStateCount; i++) { // Get the passed in vertex shader
pDelPxlShader = (D3DHAL_DP2PIXELSHADER*)lpPrim;
// Destroy the given pixel shader
_D3D_OP_PixelShader_Delete(pContext, pDelPxlShader->dwHandle);
// Update lpPrim in order to get to the next vertex
// shader delete command block.
lpPrim += sizeof(D3DHAL_DP2PIXELSHADER); }
// Now skip into the next DP2 token in the command buffer
NEXTINSTRUCTION(lpIns, D3DHAL_DP2PIXELSHADER, lpIns->wStateCount, 0); } break; case D3DDP2OP_SETPIXELSHADERCONST: { D3DHAL_DP2SETPIXELSHADERCONST* pPxlShaderConst; DWORD dwExtraBytes = 0;
DISPDBG((DBGLVL, "D3DDP2OP_SETPIXELSHADERCONST"));
// verify that all the following vertex shader
// constant blocks are readable
CHECK_CMDBUF_LIMITS(pdp2d, lpPrim, D3DHAL_DP2SETPIXELSHADERCONST, lpIns->wStateCount, 0);
// iterate through each passed vertex shader constant block
for (i = 0; i < lpIns->wStateCount; i++) { // Get the passed in vertex shader constant
pPxlShaderConst = (D3DHAL_DP2SETPIXELSHADERCONST*)lpPrim;
// Update lpPrim to point to the const data to setup
lpPrim += sizeof(D3DHAL_DP2SETPIXELSHADERCONST);
// Set up the constant entries
_D3D_OP_PixelShader_SetConst(pContext, pPxlShaderConst->dwRegister, pPxlShaderConst->dwCount, (DWORD *)lpPrim);
// Update lpPrim in order to get to the next vertex
// shader delete command block. Each register has 4 floats.
lpPrim += pPxlShaderConst->dwCount * 4 * sizeof(FLOAT);
dwExtraBytes += pPxlShaderConst->dwCount * 4 * sizeof(FLOAT); }
// Now skip into the next DP2 token in the command buffer
NEXTINSTRUCTION(lpIns, D3DHAL_DP2SETPIXELSHADERCONST, lpIns->wStateCount, dwExtraBytes); } break; #endif // DX8_PIXELSHADERS
#if DX8_MULTSTREAMS
case D3DDP2OP_SETSTREAMSOURCE : { D3DHAL_DP2SETSTREAMSOURCE* pSetStreamSrc; DISPDBG((DBGLVL, "D3DDP2OP_SETSTREAMSOURCE")); CHECK_CMDBUF_LIMITS(pdp2d, lpPrim, D3DHAL_DP2SETSTREAMSOURCE, lpIns->wStateCount, 0);
// iterate through each
for ( i = 0; i < lpIns->wStateCount; i++) { pSetStreamSrc = (D3DHAL_DP2SETSTREAMSOURCE*)lpPrim; _D3D_OP_MStream_SetSrc(pContext, pSetStreamSrc->dwStream, pSetStreamSrc->dwVBHandle, pSetStreamSrc->dwStride); lpPrim += sizeof(D3DHAL_DP2SETSTREAMSOURCE); } NEXTINSTRUCTION(lpIns, D3DHAL_DP2SETSTREAMSOURCE, lpIns->wStateCount, 0); } break; case D3DDP2OP_SETSTREAMSOURCEUM : { D3DHAL_DP2SETSTREAMSOURCEUM* pSetStreamSrcUM; DISPDBG((DBGLVL, "D3DDP2OP_SETSTREAMSOURCEUM")); CHECK_CMDBUF_LIMITS(pdp2d, lpPrim, D3DHAL_DP2SETSTREAMSOURCEUM, lpIns->wStateCount, 0); // iterate through each
for ( i = 0; i < lpIns->wStateCount; i++) { pSetStreamSrcUM = (D3DHAL_DP2SETSTREAMSOURCEUM*)lpPrim; _D3D_OP_MStream_SetSrcUM(pContext, pSetStreamSrcUM->dwStream, pSetStreamSrcUM->dwStride, pUMVtx, pdp2d->dwVertexLength); lpPrim += sizeof(D3DHAL_DP2SETSTREAMSOURCEUM); } NEXTINSTRUCTION(lpIns, D3DHAL_DP2SETSTREAMSOURCEUM, lpIns->wStateCount, 0); } break; case D3DDP2OP_SETINDICES : { D3DHAL_DP2SETINDICES* pSetIndices; DISPDBG((DBGLVL, "D3DDP2OP_SETINDICES")); CHECK_CMDBUF_LIMITS(pdp2d, lpPrim, D3DHAL_DP2SETINDICES, lpIns->wStateCount, 0); // iterate through each
for ( i = 0; i < lpIns->wStateCount; i++) { pSetIndices = (D3DHAL_DP2SETINDICES*)lpPrim; _D3D_OP_MStream_SetIndices(pContext, pSetIndices->dwVBHandle, pSetIndices->dwStride); lpPrim += sizeof(D3DHAL_DP2SETINDICES); } NEXTINSTRUCTION(lpIns, D3DHAL_DP2SETINDICES, lpIns->wStateCount, 0); } break; #endif // DX8_MULTSTREAMS
#if DX8_3DTEXTURES
case D3DDP2OP_VOLUMEBLT: { DISPDBG((DBGLVL, "D3DDP2OP_VOLUMEBLT")); CHECK_CMDBUF_LIMITS(pdp2d, lpPrim, D3DHAL_DP2VOLUMEBLT, lpIns->wStateCount, 0);
for ( i = 0; i < lpIns->wStateCount; i++) { // As the texture might live in user memory, we need to
// access it bracketing it with a try/except block. This
// is because the user memory might under some circumstances
// become invalid while the driver is running and then it
// would AV. Also, the driver might need to do some cleanup
// before returning to the OS.
__try { _D3D_OP_VolumeBlt(pContext, pThisDisplay, (D3DHAL_DP2VOLUMEBLT*)(lpPrim)); } __except(EXCEPTION_EXECUTE_HANDLER) { // On this driver we don't need to do anything special
DISPDBG((ERRLVL,"Driver caused exception at " "line %u of file %s", __LINE__,__FILE__)); PARSE_ERROR_AND_EXIT( pdp2d, lpIns, lpInsStart, DDERR_GENERIC); } lpPrim += sizeof(D3DHAL_DP2VOLUMEBLT); } NEXTINSTRUCTION(lpIns, D3DHAL_DP2VOLUMEBLT, lpIns->wStateCount, 0); } break;
#endif // DX8_3DTEXTURES
#if DX8_DDI
case D3DDP2OP_BUFFERBLT: { DISPDBG((DBGLVL, "D3DDP2OP_BUFFERBLT")); CHECK_CMDBUF_LIMITS(pdp2d, lpPrim, D3DHAL_DP2BUFFERBLT, lpIns->wStateCount, 0);
for ( i = 0; i < lpIns->wStateCount; i++) { _D3D_OP_BufferBlt(pContext, pThisDisplay, (D3DHAL_DP2BUFFERBLT*)(lpPrim)); lpPrim += sizeof(D3DHAL_DP2BUFFERBLT); } NEXTINSTRUCTION(lpIns, D3DHAL_DP2BUFFERBLT, lpIns->wStateCount, 0); } break; #endif // DX8_DDI
// This was found to be required for a few D3DRM apps
case D3DOP_EXIT: lpIns = (D3DHAL_DP2COMMAND *)(lpInsStart + pdp2d->dwCommandLength + pdp2d->dwCommandOffset); break;
default:
// Pick up the right rasterizers depending on the
// current rendering state
_D3D_R3_PickVertexProcessor( pContext );
// Check if vertex buffer resides in user memory or in a DDraw surface
if (pdp2d->dwFlags & D3DHALDP2_USERMEMVERTICES) { // As the vertex buffer lives in user memory, we need to
// access it bracketing it with a try/except block. This
// is because the user memory might under some circumstances
// become invalid while the driver is running and then it
// would AV. Also, the driver might need to do some cleanup
// before returning to the OS.
__try { // Try to render as a primitive(s) in a separate loop
// in order not loose performance doing hw setup again
bParseError = __DP2_PrimitiveOpsParser( pContext, pdp2d, &lpIns, lpInsStart, pContext->lpVertices); } __except(EXCEPTION_EXECUTE_HANDLER) { // On this driver we don't need to do anything special
DISPDBG((ERRLVL,"Driver caused exception at " "line %u of file %s", __LINE__,__FILE__)); PARSE_ERROR_AND_EXIT( pdp2d, lpIns, lpInsStart, DDERR_GENERIC); } } else { // Try to render as a primitive(s) in a separate loop
// in order not loose performance doing hw setup again
bParseError = __DP2_PrimitiveOpsParser( pContext, pdp2d, &lpIns, lpInsStart, pContext->lpVertices); }
// We weren't succesful, so we exit with an error code
if (bParseError) { PARSE_ERROR_AND_EXIT( pdp2d, lpIns, lpInsStart, D3DERR_COMMAND_UNPARSED); } } // switch
} // while
//@@BEGIN_DDKSPLIT
#if DX7_VERTEXBUFFERS
if( bUsedHostIn ) { _D3D_EB_UpdateSwapBuffers(pThisDisplay, pdp2d , pVertexBufferInfo, pCommandBufferInfo); } #endif
//@@END_DDKSPLIT
START_SOFTWARE_CURSOR(pThisDisplay);
if (!bParseError) { pdp2d->ddrval = DD_OK; }
DBG_CB_EXIT(D3DDrawPrimitives2_P3, DD_OK); return DDHAL_DRIVER_HANDLED; } // D3DDrawPrimitives2_P3
//-----------------------------------------------------------------------------
//
// __DP2_PrimitiveOpsParser
//
// Render command buffer which contains primitive(s) in a separate loop
// in order not to loose performance doing hw setup repeatedly. We keep
// spinning in this loop until we reach an EOB, a non-rendering DP2 command
// or until an error is detected.
//
//-----------------------------------------------------------------------------
BOOL __DP2_PrimitiveOpsParser( P3_D3DCONTEXT *pContext, LPD3DHAL_DRAWPRIMITIVES2DATA pdp2d, LPD3DHAL_DP2COMMAND *lplpIns, LPBYTE lpInsStart, LPDWORD lpVerts) { P3_THUNKEDDATA* pThisDisplay = pContext->pThisDisplay; LPD3DTLVERTEX lpVertices = (LPD3DTLVERTEX) lpVerts; LPD3DHAL_DP2COMMAND lpIns; LPD3DHAL_DP2COMMAND lpResumeIns; LPBYTE lpPrim, lpChkPrim; HRESULT ddrval; DWORD dwFillMode; BOOL bParseError = FALSE; DWORD i;
DBG_ENTRY(__DP2_PrimitiveOpsParser);
lpIns = *lplpIns;
// This macro includes all parameters passed to all the specialized
// rendering functions (since their parameters are all the same)
// just to save us of some clutter in the actual code
#define P3_RND_PARAMS \
pContext, \ lpIns->wPrimitiveCount, \ lpPrim, \ lpVertices, \ pdp2d->dwVertexLength, \ &bParseError
// Ensure the hostin unit is setup for inline vertex data.
{ P3_DMA_DEFS(); P3_DMA_GET_BUFFER_ENTRIES(6); pContext->SoftCopyGlint.P3RX_P3VertexControl.Size = pContext->FVFData.dwStrideHostInline / sizeof(DWORD); COPY_P3_DATA( VertexControl, pContext->SoftCopyGlint.P3RX_P3VertexControl ); SEND_P3_DATA( VertexValid, pContext->FVFData.dwVertexValidHostInline); SEND_P3_DATA( VertexFormat, pContext->FVFData.vFmatHostInline); P3_DMA_COMMIT_BUFFER(); }
// Process commands while we haven't exhausted the command buffer
while (!bParseError && ((LPBYTE)lpIns < (lpInsStart + pdp2d->dwCommandLength + pdp2d->dwCommandOffset))) { BOOL bNonRenderingOP; // Get pointer to first primitive structure past the D3DHAL_DP2COMMAND
lpPrim = (LPBYTE)lpIns + sizeof(D3DHAL_DP2COMMAND);
// Rendering primitive functions called vary according to
// the fill mode selected ( POINT, WIREFRAME, SOLID );
dwFillMode = pContext->RenderStates[D3DRENDERSTATE_FILLMODE];
DISPDBG((DBGLVL, "__DP2_PrimitiveOpsParser: " "Parsing instruction %d Count = %d @ %x", lpIns->bCommand, lpIns->wPrimitiveCount, lpIns));
// If we are processing a known, though non-rendering opcode
// then its time to quit this function
bNonRenderingOP = ( lpIns->bCommand == D3DDP2OP_RENDERSTATE ) || ( lpIns->bCommand == D3DDP2OP_TEXTURESTAGESTATE ) || ( lpIns->bCommand == D3DDP2OP_STATESET ) || ( lpIns->bCommand == D3DDP2OP_VIEWPORTINFO ) || ( lpIns->bCommand == D3DDP2OP_WINFO ) || ( lpIns->bCommand == D3DDP2OP_ZRANGE ) || ( lpIns->bCommand == D3DDP2OP_SETMATERIAL ) || ( lpIns->bCommand == D3DDP2OP_SETLIGHT ) || ( lpIns->bCommand == D3DDP2OP_TEXBLT ) || ( lpIns->bCommand == D3DDP2OP_SETLIGHT ) || ( lpIns->bCommand == D3DDP2OP_TEXBLT ) || ( lpIns->bCommand == D3DDP2OP_CREATELIGHT ) || ( lpIns->bCommand == D3DDP2OP_EXT ) || ( lpIns->bCommand == D3DDP2OP_SETTRANSFORM ) || ( lpIns->bCommand == D3DDP2OP_CLEAR ) || ( lpIns->bCommand == D3DDP2OP_UPDATEPALETTE ) || ( lpIns->bCommand == D3DDP2OP_SETPALETTE ) || #if DX7_TEXMANAGEMENT
( lpIns->bCommand == D3DDP2OP_SETTEXLOD ) || ( lpIns->bCommand == D3DDP2OP_SETPRIORITY ) || #endif // DX7_TEXMANAGEMENT
#if DX8_DDI
( lpIns->bCommand == D3DDP2OP_CREATEVERTEXSHADER) || ( lpIns->bCommand == D3DDP2OP_SETVERTEXSHADER) || ( lpIns->bCommand == D3DDP2OP_DELETEVERTEXSHADER) || ( lpIns->bCommand == D3DDP2OP_SETVERTEXSHADERCONST) || ( lpIns->bCommand == D3DDP2OP_CREATEPIXELSHADER) || ( lpIns->bCommand == D3DDP2OP_SETPIXELSHADER) || ( lpIns->bCommand == D3DDP2OP_DELETEPIXELSHADER) || ( lpIns->bCommand == D3DDP2OP_SETPIXELSHADERCONST)|| ( lpIns->bCommand == D3DDP2OP_SETSTREAMSOURCE ) || ( lpIns->bCommand == D3DDP2OP_SETSTREAMSOURCEUM ) || ( lpIns->bCommand == D3DDP2OP_SETINDICES ) || #endif //DX8_DDI
( lpIns->bCommand == D3DDP2OP_SETRENDERTARGET);
if (bNonRenderingOP) { break; }
// Main rendering Dp2 opcode switch
switch( lpIns->bCommand ) { case D3DDP2OP_POINTS:
DISPDBG((DBGLVL, "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.
CHECK_CMDBUF_LIMITS(pdp2d, lpPrim, D3DHAL_DP2POINTS, lpIns->wPrimitiveCount, 0);
_D3D_R3_DP2_Points( P3_RND_PARAMS ); NEXTINSTRUCTION(lpIns, D3DHAL_DP2POINTS, lpIns->wPrimitiveCount, 0); break;
case D3DDP2OP_LINELIST:
DISPDBG((DBGLVL, "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).
CHECK_CMDBUF_LIMITS(pdp2d, lpPrim, D3DHAL_DP2LINELIST, 1, 0);
_D3D_R3_DP2_LineList( P3_RND_PARAMS ); NEXTINSTRUCTION(lpIns, D3DHAL_DP2LINELIST, 1, 0); break;
case D3DDP2OP_INDEXEDLINELIST:
DISPDBG((DBGLVL, "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]).
CHECK_CMDBUF_LIMITS(pdp2d, lpPrim, D3DHAL_DP2INDEXEDLINELIST, lpIns->wPrimitiveCount, 0);
_D3D_R3_DP2_IndexedLineList( P3_RND_PARAMS );
NEXTINSTRUCTION(lpIns, D3DHAL_DP2INDEXEDLINELIST, lpIns->wPrimitiveCount, 0); break;
case D3DDP2OP_INDEXEDLINELIST2:
DISPDBG((DBGLVL, "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
CHECK_CMDBUF_LIMITS(pdp2d, lpPrim, D3DHAL_DP2INDEXEDLINELIST, lpIns->wPrimitiveCount, STARTVERTEXSIZE);
_D3D_R3_DP2_IndexedLineList2( P3_RND_PARAMS );
NEXTINSTRUCTION(lpIns, D3DHAL_DP2INDEXEDLINELIST, lpIns->wPrimitiveCount, STARTVERTEXSIZE); break;
case D3DDP2OP_LINESTRIP:
DISPDBG((DBGLVL, "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).
CHECK_CMDBUF_LIMITS(pdp2d, lpPrim,D3DHAL_DP2LINESTRIP, 1, 0);
_D3D_R3_DP2_LineStrip( P3_RND_PARAMS );
NEXTINSTRUCTION(lpIns, D3DHAL_DP2LINESTRIP, 1, 0); break;
case D3DDP2OP_INDEXEDLINESTRIP:
DISPDBG((DBGLVL, "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
CHECK_CMDBUF_LIMITS(pdp2d, lpPrim, WORD, lpIns->wPrimitiveCount + 1, STARTVERTEXSIZE);
_D3D_R3_DP2_IndexedLineStrip( P3_RND_PARAMS );
// 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:
DISPDBG((DBGLVL, "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).
CHECK_CMDBUF_LIMITS(pdp2d, lpPrim, D3DHAL_DP2TRIANGLELIST, 1, 0);
_D3D_R3_DP2_TriangleList( P3_RND_PARAMS );
NEXTINSTRUCTION(lpIns, D3DHAL_DP2TRIANGLELIST, 1, 0); break;
case D3DDP2OP_INDEXEDTRIANGLELIST:
DISPDBG((DBGLVL, "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 D3D primitive.
CHECK_CMDBUF_LIMITS(pdp2d, lpPrim, D3DHAL_DP2INDEXEDTRIANGLELIST, lpIns->wPrimitiveCount, 0); if( lpIns->wPrimitiveCount ) { _D3D_R3_DP2_IndexedTriangleList( P3_RND_PARAMS ); } NEXTINSTRUCTION(lpIns, D3DHAL_DP2INDEXEDTRIANGLELIST, lpIns->wPrimitiveCount, 0); break;
case D3DDP2OP_INDEXEDTRIANGLELIST2:
DISPDBG((DBGLVL, "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
CHECK_CMDBUF_LIMITS(pdp2d, lpPrim, D3DHAL_DP2INDEXEDTRIANGLELIST2, lpIns->wPrimitiveCount, STARTVERTEXSIZE);
_D3D_R3_DP2_IndexedTriangleList2( P3_RND_PARAMS );
NEXTINSTRUCTION(lpIns, D3DHAL_DP2INDEXEDTRIANGLELIST2, lpIns->wPrimitiveCount, STARTVERTEXSIZE); break;
case D3DDP2OP_TRIANGLESTRIP:
DISPDBG((DBGLVL, "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+2,
// wVStart+1, vVStart+3),.(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), wVStart+wPrimitiveCount-1,
// vStart+wPrimitiveCount+1).
CHECK_CMDBUF_LIMITS(pdp2d, lpPrim, D3DHAL_DP2TRIANGLESTRIP, 1, 0);
_D3D_R3_DP2_TriangleStrip( P3_RND_PARAMS );
// Point to next D3DHAL_DP2COMMAND in the command buffer
NEXTINSTRUCTION(lpIns, D3DHAL_DP2TRIANGLESTRIP, 1, 0); break;
case D3DDP2OP_INDEXEDTRIANGLESTRIP:
DISPDBG((DBGLVL, "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[2],wV[1],wV[3]),
// (wV[3],wV[4],wV[5]),...,(wV[wPrimitiveCount-1],
// wV[wPrimitiveCount],wV[wPrimitiveCount+1]). For an even
// number of triangles, the last triangle will be
// (wV[wPrimitiveCount],wV[wPrimitiveCount-1],
// wV[wPrimitiveCount+1]).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
CHECK_CMDBUF_LIMITS(pdp2d, lpPrim, WORD, lpIns->wPrimitiveCount + 2, STARTVERTEXSIZE);
_D3D_R3_DP2_IndexedTriangleStrip( P3_RND_PARAMS ); // Point to next D3DHAL_DP2COMMAND in the command buffer
NEXTINSTRUCTION(lpIns, WORD , lpIns->wPrimitiveCount + 2, STARTVERTEXSIZE); break;
case D3DDP2OP_TRIANGLEFAN:
DISPDBG((DBGLVL, "D3DDP2OP_TRIANGLEFAN"));
// The D3DHAL_DP2TRIANGLEFAN structure is used to draw
// non-indexed triangle fans. The sequence of triangles
// rendered will be (wVStart, wVstart+1, wVStart+2),
// (wVStart,wVStart+2,wVStart+3), (wVStart,wVStart+3,
// wVStart+4),...,(wVStart,wVStart+wPrimitiveCount,
// wVStart+wPrimitiveCount+1).
CHECK_CMDBUF_LIMITS(pdp2d, lpPrim, D3DHAL_DP2TRIANGLEFAN, 1, 0);
_D3D_R3_DP2_TriangleFan( P3_RND_PARAMS ); NEXTINSTRUCTION(lpIns, D3DHAL_DP2TRIANGLEFAN, 1, 0); break;
case D3DDP2OP_INDEXEDTRIANGLEFAN:
DISPDBG((DBGLVL,"D3DDP2OP_INDEXEDTRIANGLEFAN"));
// The D3DHAL_DP2INDEXEDTRIANGLEFAN structure is used to
// draw indexed triangle fans. The sequence of triangles
// rendered will be (wV[0], wV[1], wV[2]), (wV[0], wV[2],
// wV[3]), (wV[0], wV[3], wV[4]),...,(wV[0],
// wV[wPrimitiveCount], wV[wPrimitiveCount+1]).
// The indexes are relative to a base index value that
// immediately follows the command
CHECK_CMDBUF_LIMITS(pdp2d, lpPrim, WORD, lpIns->wPrimitiveCount + 2, STARTVERTEXSIZE);
_D3D_R3_DP2_IndexedTriangleFan( P3_RND_PARAMS );
// Point to next D3DHAL_DP2COMMAND in the command buffer
NEXTINSTRUCTION(lpIns,WORD ,lpIns->wPrimitiveCount + 2, STARTVERTEXSIZE); break;
case D3DDP2OP_LINELIST_IMM:
DISPDBG((DBGLVL, "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.
// 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 (data lives in it!)
CHECK_CMDBUF_LIMITS_S(pdp2d, lpPrim, pContext->FVFData.dwStride, lpIns->wPrimitiveCount + 1, 0);
_D3D_R3_DP2_LineListImm( P3_RND_PARAMS );
// Realign next command since vertices are dword aligned
// and store # of primitives before affecting the pointer
NEXTINSTRUCTION(lpIns, BYTE, ((lpIns->wPrimitiveCount * 2) * pContext->FVFData.dwStride), 0);
// Realign next command since vertices are dword aligned
lpIns = (LPD3DHAL_DP2COMMAND)(( ((ULONG_PTR)lpIns) + 3 ) & ~ 3);
break;
case D3DDP2OP_TRIANGLEFAN_IMM:
DISPDBG((DBGLVL, "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.
// Verify the command buffer validity for the first structure
CHECK_CMDBUF_LIMITS(pdp2d, lpPrim, BYTE , 0 , sizeof(D3DHAL_DP2TRIANGLEFAN_IMM));
// Get pointer where data should start
lpChkPrim = (LPBYTE)((ULONG_PTR)( lpPrim + 3 + sizeof(D3DHAL_DP2TRIANGLEFAN_IMM)) & ~3 );
// Verify the rest of the command buffer
CHECK_CMDBUF_LIMITS_S(pdp2d, lpChkPrim, pContext->FVFData.dwStride, lpIns->wPrimitiveCount + 2, 0); _D3D_R3_DP2_TriangleFanImm( P3_RND_PARAMS ); // Realign next command since vertices are dword aligned
// and store # of primitives before affecting the pointer
NEXTINSTRUCTION(lpIns, BYTE, ((lpIns->wPrimitiveCount + 2) * pContext->FVFData.dwStride), sizeof(D3DHAL_DP2TRIANGLEFAN_IMM));
// Realign next command since vertices are dword aligned
lpIns = (LPD3DHAL_DP2COMMAND)(( ((ULONG_PTR)lpIns) + 3 ) & ~ 3);
break;
#if DX8_MULTSTREAMS
case D3DDP2OP_DRAWPRIMITIVE : { D3DHAL_DP2DRAWPRIMITIVE* pDrawPrim; DISPDBG((DBGLVL, "D3DDP2OP_DRAWPRIMITIVE")); CHECK_CMDBUF_LIMITS(pdp2d, lpPrim, D3DHAL_DP2DRAWPRIMITIVE, lpIns->wStateCount, 0); // iterate through each
for ( i = 0; i < lpIns->wStateCount; i++) { pDrawPrim = (D3DHAL_DP2DRAWPRIMITIVE*)lpPrim; _D3D_OP_MStream_DrawPrim(pContext, pDrawPrim->primType, pDrawPrim->VStart, pDrawPrim->PrimitiveCount); lpPrim += sizeof(D3DHAL_DP2DRAWPRIMITIVE); } NEXTINSTRUCTION(lpIns, D3DHAL_DP2DRAWPRIMITIVE, lpIns->wStateCount, 0); } break; case D3DDP2OP_DRAWINDEXEDPRIMITIVE : { D3DHAL_DP2DRAWINDEXEDPRIMITIVE* pDrawIndxPrim; DISPDBG((DBGLVL, "D3DDP2OP_DRAWINDEXEDPRIMITIVE")); CHECK_CMDBUF_LIMITS(pdp2d, lpPrim, D3DHAL_DP2DRAWINDEXEDPRIMITIVE, lpIns->wStateCount, 0); // iterate through each
for ( i = 0; i < lpIns->wStateCount; i++) { pDrawIndxPrim = (D3DHAL_DP2DRAWINDEXEDPRIMITIVE*)lpPrim; _D3D_OP_MStream_DrawIndxP(pContext, pDrawIndxPrim->primType, pDrawIndxPrim->BaseVertexIndex, pDrawIndxPrim->MinIndex, pDrawIndxPrim->NumVertices, pDrawIndxPrim->StartIndex, pDrawIndxPrim->PrimitiveCount); lpPrim += sizeof(D3DHAL_DP2DRAWINDEXEDPRIMITIVE); } NEXTINSTRUCTION(lpIns, D3DHAL_DP2DRAWINDEXEDPRIMITIVE, lpIns->wStateCount, 0); } break; case D3DDP2OP_DRAWPRIMITIVE2 : { D3DHAL_DP2DRAWPRIMITIVE2* pDrawPrim2; DISPDBG((DBGLVL, "D3DDP2OP_DRAWPRIMITIVE2")); CHECK_CMDBUF_LIMITS(pdp2d, lpPrim, D3DHAL_DP2DRAWPRIMITIVE2, lpIns->wStateCount, 0); // iterate through each
for ( i = 0; i < lpIns->wStateCount; i++) { pDrawPrim2 = (D3DHAL_DP2DRAWPRIMITIVE2*)lpPrim; _D3D_OP_MStream_DrawPrim2(pContext, pDrawPrim2->primType, pDrawPrim2->FirstVertexOffset, pDrawPrim2->PrimitiveCount); lpPrim += sizeof(D3DHAL_DP2DRAWPRIMITIVE2); } NEXTINSTRUCTION(lpIns, D3DHAL_DP2DRAWPRIMITIVE2, lpIns->wStateCount, 0); } break; case D3DDP2OP_DRAWINDEXEDPRIMITIVE2 : { D3DHAL_DP2DRAWINDEXEDPRIMITIVE2* pDrawIndxPrim2; DISPDBG((DBGLVL, "D3DDP2OP_DRAWINDEXEDPRIMITIVE2")); CHECK_CMDBUF_LIMITS(pdp2d, lpPrim, D3DHAL_DP2DRAWINDEXEDPRIMITIVE2, lpIns->wStateCount, 0); // iterate through each
for ( i = 0; i < lpIns->wStateCount; i++) { pDrawIndxPrim2 = (D3DHAL_DP2DRAWINDEXEDPRIMITIVE2*)lpPrim; _D3D_OP_MStream_DrawIndxP2(pContext, pDrawIndxPrim2->primType, pDrawIndxPrim2->BaseVertexOffset, pDrawIndxPrim2->MinIndex, pDrawIndxPrim2->NumVertices, pDrawIndxPrim2->StartIndexOffset, pDrawIndxPrim2->PrimitiveCount); lpPrim += sizeof(D3DHAL_DP2DRAWINDEXEDPRIMITIVE2); } NEXTINSTRUCTION(lpIns, D3DHAL_DP2DRAWINDEXEDPRIMITIVE2, lpIns->wStateCount, 0); } break; case D3DDP2OP_DRAWRECTPATCH : { D3DHAL_DP2DRAWRECTPATCH* pRectSurf; DWORD dwExtraBytes = 0; DISPDBG((DBGLVL, "D3DDP2OP_DRAWRECTPATCH")); CHECK_CMDBUF_LIMITS(pdp2d, lpPrim, D3DHAL_DP2DRAWRECTPATCH, lpIns->wStateCount, 0); // iterate through each
for ( i = 0; i < lpIns->wStateCount; i++) { pRectSurf = (D3DHAL_DP2DRAWRECTPATCH*)lpPrim;
lpPrim += sizeof(D3DHAL_DP2DRAWRECTPATCH); _D3D_OP_MStream_DrawRectSurface(pContext, pRectSurf->Handle, pRectSurf->Flags, lpPrim); if (pRectSurf->Flags & RTPATCHFLAG_HASSEGS) { dwExtraBytes += sizeof(D3DVALUE)* 4; } if (pRectSurf->Flags & RTPATCHFLAG_HASINFO) { dwExtraBytes += sizeof(D3DRECTPATCH_INFO); }
lpPrim += dwExtraBytes; } NEXTINSTRUCTION(lpIns, D3DHAL_DP2DRAWRECTPATCH, lpIns->wStateCount, dwExtraBytes); } break;
case D3DDP2OP_DRAWTRIPATCH : { D3DHAL_DP2DRAWTRIPATCH* pTriSurf; DWORD dwExtraBytes = 0; DISPDBG((DBGLVL, "D3DDP2OP_DRAWTRIPATCH")); CHECK_CMDBUF_LIMITS(pdp2d, lpPrim, D3DHAL_DP2DRAWTRIPATCH, lpIns->wStateCount, 0); // iterate through each
for ( i = 0; i < lpIns->wStateCount; i++) { pTriSurf = (D3DHAL_DP2DRAWTRIPATCH*)lpPrim;
lpPrim += sizeof(D3DHAL_DP2DRAWTRIPATCH);
_D3D_OP_MStream_DrawTriSurface(pContext, pTriSurf->Handle, pTriSurf->Flags, lpPrim); if (pTriSurf->Flags & RTPATCHFLAG_HASSEGS) { dwExtraBytes += sizeof(D3DVALUE)* 3; } if (pTriSurf->Flags & RTPATCHFLAG_HASINFO) { dwExtraBytes += sizeof(D3DTRIPATCH_INFO); }
lpPrim += dwExtraBytes; } NEXTINSTRUCTION(lpIns, D3DHAL_DP2DRAWTRIPATCH, lpIns->wStateCount, dwExtraBytes); } break; case D3DDP2OP_CLIPPEDTRIANGLEFAN : { D3DHAL_CLIPPEDTRIANGLEFAN* pClipdTriFan; DISPDBG((DBGLVL, "D3DDP2OP_CLIPPEDTRIANGLEFAN")); CHECK_CMDBUF_LIMITS(pdp2d, lpPrim, D3DHAL_CLIPPEDTRIANGLEFAN, lpIns->wStateCount, 0);
// iterate through each
for ( i = 0; i < lpIns->wStateCount; i++) { pClipdTriFan = (D3DHAL_CLIPPEDTRIANGLEFAN*)lpPrim; _D3D_OP_MStream_ClipTriFan(pContext, pClipdTriFan->FirstVertexOffset, pClipdTriFan->dwEdgeFlags, pClipdTriFan->PrimitiveCount); lpPrim += sizeof(D3DHAL_CLIPPEDTRIANGLEFAN); } NEXTINSTRUCTION(lpIns, D3DHAL_CLIPPEDTRIANGLEFAN, lpIns->wStateCount, 0); } break;
#endif // DX8_MULTSTREAMS
// This was found to be required for a few D3DRM apps
case D3DOP_EXIT: lpIns = (D3DHAL_DP2COMMAND *)(lpInsStart + pdp2d->dwCommandLength + pdp2d->dwCommandOffset); break;
default:
ASSERTDD((pThisDisplay->pD3DParseUnknownCommand), "D3D ParseUnknownCommand callback == NULL");
if( SUCCEEDED(ddrval=(pThisDisplay->pD3DParseUnknownCommand) ( lpIns , (void**)&lpResumeIns)) ) { // Resume buffer processing after D3DParseUnknownCommand
// was succesful in processing an unknown command
lpIns = lpResumeIns; break; }
DISPDBG((ERRLVL, "Unhandled opcode (%d)- " "returning D3DERR_COMMAND_UNPARSED @ addr %x", lpIns->bCommand, lpIns)); PARSE_ERROR_AND_EXIT( pdp2d, lpIns, lpInsStart, ddrval); } // switch
} //while
*lplpIns = lpIns;
DBG_EXIT(__DP2_PrimitiveOpsParser, bParseError); return bParseError; } // __DP2_PrimitiveOpsParser
//-----------------------------Public Routine----------------------------------
//
// D3DValidateDeviceP3
//
// Returns the number of passes in which the hardware can perform the blending
// operations specified in the current state.
//
// Direct3D drivers that support texturing must implement
// D3dValidateTextureStageState.
//
// The driver must do the following:
//
// Evaluate the current texture state for all texture stages associated with the
// context. If the driver's hardware can perform the specified blending
// operations, the driver should return the number of passes on the state data
// that its hardware requires in order to entirely process the operations. If
// the hardware is incapable of performing the specified blending operations,
// the driver should return one of the following error codes in ddrval:
//
// D3DERR_CONFLICTINGTEXTUREFILTER
// The hardware cannot do both trilinear filtering and
// multi-texturing at the same time.
// D3DERR_TOOMANYOPERATIONS
// The hardware cannot handle the specified number of operations.
// D3DERR_UNSUPPORTEDALPHAARG
// The hardware does not support a specified alpha argument.
// D3DERR_UNSUPPORTEDALPHAOPERATION
// The hardware does not support a specified alpha operation.
// D3DERR_UNSUPPORTEDCOLORARG
// The hardware does not support a specified color argument.
// D3DERR_UNSUPPORTEDCOLOROPERATION
// The hardware does not support a specified color operation.
// D3DERR_UNSUPPORTEDFACTORVALUE
// The hardware does not support a D3DTA_TFACTOR greater than 1.0.
// D3DERR_WRONGTEXTUREFORMAT
// The hardware does not support the current state in the selected
// texture format
//
// Direct3D calls D3dValidateTextureStageState in response to an application
// request through a call to IDirect3DDevice3::ValidateTextureStageState. The
// number of passes returned by the driver is propagated back to the application
// , which can then decide whether it wants to proceed with rendering using the
// current state or if it wants/needs to change the blending operations to
// render faster or render at all. There are no limits to the number of passes
// that a driver can return.
//
// A driver that returns more than one pass is responsible for properly
//executing the passes on all state and primitive data when rendering.
//
// Parameters
//
// pvtssd
//
// .dwhContext
// Specifies the context ID of the Direct3D device.
// .dwFlags
// Is currently set to zero and should be ignored by the driver.
// .dwReserved
// Is reserved for system use and should be ignored by the driver.
// .dwNumPasses
// Specifies the location in which the driver should write the
// number of passes required by the hardware to perform the
// blending operations.
// .ddrval
// return value
//
//-----------------------------------------------------------------------------
// Taken from the registry variable.
#define VDOPMODE_IGNORE_NONFATAL 0 // dualtex + trilinear (for examples)
// not flagged as a bug.
DWORD CALLBACK D3DValidateDeviceP3( LPD3DHAL_VALIDATETEXTURESTAGESTATEDATA pvtssd ) { P3_D3DCONTEXT* pContext; P3_THUNKEDDATA* pThisDisplay;
DBG_CB_ENTRY(D3DValidateDeviceP3); pContext = _D3D_CTX_HandleToPtr(pvtssd->dwhContext); if (!CHECK_D3DCONTEXT_VALIDITY(pContext)) { pvtssd->ddrval = D3DHAL_CONTEXT_BAD; DISPDBG((WRNLVL,"ERROR: Context not valid")); DBG_CB_EXIT(D3DValidateDeviceP3, pvtssd->ddrval);
return (DDHAL_DRIVER_HANDLED); }
pThisDisplay = pContext->pThisDisplay;
STOP_SOFTWARE_CURSOR(pThisDisplay); D3D_OPERATION(pContext, pThisDisplay);
// Re-do all the blend-mode setup from scratch.
RESET_BLEND_ERROR(pContext); DIRTY_EVERYTHING(pContext); // The primitive type is not actually important except to keep the
// rout from asserting various things when it tries to pick the renderer
// (which of course does not need to be done in this case).
ReconsiderStateChanges ( pContext );
START_SOFTWARE_CURSOR(pThisDisplay);
_D3DDisplayWholeTSSPipe ( pContext, DBGLVL);
// And see if anything died.
if (GET_BLEND_ERROR(pContext) == BS_OK ) { // Cool - that worked.
pvtssd->dwNumPasses = 1; pvtssd->ddrval = DD_OK; DBG_CB_EXIT(D3DValidateDeviceP3, pvtssd->ddrval);
return ( DDHAL_DRIVER_HANDLED ); } else { // Oops. Failed.
DISPDBG((DBGLVL,"ValidateDevice: failed ValidateDevice()"));
switch ( GET_BLEND_ERROR(pContext) ) { case BS_OK: DISPDBG((ERRLVL,"ValidateDevice: got BS_OK - that's not " "an error!")); pvtssd->ddrval = DD_OK; break;
case BS_INVALID_FILTER: pvtssd->ddrval = D3DERR_CONFLICTINGTEXTUREFILTER; break;
case BSF_CANT_USE_COLOR_OP_HERE: case BSF_CANT_USE_COLOR_ARG_HERE: case BSF_CANT_USE_ALPHA_OP_HERE: case BSF_CANT_USE_ALPHA_ARG_HERE: pvtssd->ddrval = D3DERR_CONFLICTINGRENDERSTATE; break;
case BSF_INVALID_TEXTURE: case BSF_TEXTURE_NOT_POW2: pvtssd->ddrval = D3DERR_WRONGTEXTUREFORMAT; break;
case BSF_UNDEFINED_COLOR_OP: case BSF_UNSUPPORTED_COLOR_OP: case BSF_UNSUPPORTED_ALPHA_BLEND: // doesn't fit anywhere else.
case BSF_UNDEFINED_ALPHA_BLEND: // doesn't fit anywhere else.
case BSF_UNSUPPORTED_STATE: // doesn't fit anywhere else.
case BSF_UNDEFINED_STATE: // doesn't fit anywhere else.
case BS_PHONG_SHADING: // doesn't fit anywhere else.
pvtssd->ddrval = D3DERR_UNSUPPORTEDCOLOROPERATION; break;
case BSF_UNDEFINED_COLOR_ARG: case BSF_UNSUPPORTED_COLOR_ARG: pvtssd->ddrval = D3DERR_UNSUPPORTEDCOLORARG; break;
case BSF_UNDEFINED_ALPHA_OP: case BSF_UNSUPPORTED_ALPHA_OP: pvtssd->ddrval = D3DERR_UNSUPPORTEDALPHAOPERATION; break;
case BSF_UNDEFINED_ALPHA_ARG: case BSF_UNSUPPORTED_ALPHA_ARG: pvtssd->ddrval = D3DERR_UNSUPPORTEDALPHAARG; break;
case BSF_TOO_MANY_TEXTURES: case BSF_TOO_MANY_BLEND_STAGES: pvtssd->ddrval = D3DERR_TOOMANYOPERATIONS; break;
case BSF_UNDEFINED_FILTER: case BSF_UNSUPPORTED_FILTER: pvtssd->ddrval = D3DERR_UNSUPPORTEDTEXTUREFILTER; break;
case BSF_TOO_MANY_PALETTES: pvtssd->ddrval = D3DERR_CONFLICTINGTEXTUREPALETTE; break;
// Nothing maps to these, but they are valid D3D return
// codes that be used for future errors.
// pvtssd->ddrval = D3DERR_UNSUPPORTEDFACTORVALUE;
// break;
// pvtssd->ddrval = D3DERR_TOOMANYPRIMITIVES;
// break;
// pvtssd->ddrval = D3DERR_INVALIDMATRIX;
// break;
// pvtssd->ddrval = D3DERR_TOOMANYVERTICES;
// break;
case BSF_UNINITIALISED: // Oops.
DISPDBG((ERRLVL,"ValidateDevice: unitialised error" " - logic problem.")); pvtssd->ddrval = D3DERR_TOOMANYOPERATIONS; break; default: // Unknown.
DISPDBG((ERRLVL,"ValidateDevice: unknown " "blend-mode error.")); pvtssd->ddrval = D3DERR_TOOMANYOPERATIONS; break; }
pvtssd->dwNumPasses = 1; DBG_CB_EXIT(D3DValidateDeviceP3, pvtssd->ddrval); return ( DDHAL_DRIVER_HANDLED ); }
} // D3DValidateDeviceP3
|