You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3111 lines
133 KiB
3111 lines
133 KiB
/******************************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
|
|
|