Leaked source code of windows server 2003
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.
 
 
 
 
 
 

2259 lines
83 KiB

/*==========================================================================;
*
* Copyright (C) 1995 Microsoft Corporation. All Rights Reserved.
*
* File: halexe.c
* Content: Direct3D HAL execute calles
*@@BEGIN_MSINTERNAL
*
* $Id: halexe.c,v 1.1 1995/11/21 15:12:37 sjl Exp $
*
* History:
* Date By Reason
* ==== == ======
* 07/11/95 stevela Initial rev.
* 12/11/95 stevela Lock surface before calling HAL's execute.
* 29/08/96 stevela Just bit test instead of calling IsLost()
*@@END_MSINTERNAL
*
***************************************************************************/
#include "pch.cpp"
#pragma hdrstop
#include "commdrv.hpp"
#include "genpick.hpp"
#include "d3dfei.h"
#include "clipfunc.h"
//---------------------------------------------------------------------
#define CHECK(ddrval, str) \
if (ddrval != DD_OK) \
{ \
D3D_ERR(str); \
return (ddrval); \
}
//---------------------------------------------------------------------
__inline BOOL DDSurfaceLost(LPDIRECTDRAWSURFACE s)
{
return ((LPDDRAWI_DDRAWSURFACE_INT)s)->lpLcl->dwFlags & DDRAWISURF_INVALID;
}
#ifdef USE_INTERNAL_LOCK
__inline HRESULT DDLockSurface(LPDIRECTDRAWSURFACE s)
{
LPDDRAWI_DDRAWSURFACE_INT lpInt;
lpInt = (LPDDRAWI_DDRAWSURFACE_INT)s;
return DDInternalLock(lpInt->lpLcl);
}
__inline HRESULT DDUnockSurface(LPDIRECTDRAWSURFACE s)
{
LPDDRAWI_DDRAWSURFACE_INT lpInt;
lpInt = (LPDDRAWI_DDRAWSURFACE_INT)s;
return DDInternalUnlock(lpInt->lpLcl);
}
#endif
__inline BOOL DDCheckSurfaceCaps(LPDIRECTDRAWSURFACE s, DWORD flag)
{
LPDDRAWI_DDRAWSURFACE_INT lpInt = (LPDDRAWI_DDRAWSURFACE_INT)s;
return lpInt->lpLcl->ddsCaps.dwCaps & flag;
}
//---------------------------------------------------------------------
#define CHECKLOST(lpDevI) \
{ \
if (DDSurfaceLost(lpDevI->lpDDSTarget) || \
(lpDevI->lpDDSZBuffer && DDSurfaceLost(lpDevI->lpDDSZBuffer))) \
{ \
D3D_WARN(0, "Render-target or ZBuffer surface lost"); \
lpDevI->dwFEFlags |= D3DFE_LOSTSURFACES; \
return DDERR_SURFACELOST; \
} \
}
#define NEXTINSTRUCTION(ptr, type, num) \
ptr = (LPD3DINSTRUCTION)((LPBYTE)ptr + sizeof(D3DINSTRUCTION) + \
(num * sizeof(type)))
//---------------------------------------------------------------------
#ifdef DBG
int
validateTriangleFlags(LPD3DINSTRUCTION ins,
LPD3DTRIANGLE tri)
{
int count = ins->wCount;
int v1,v2,v3;
int flat;
int flat_count;
unsigned flags;
D3D_INFO(5, "Start %d triangle instruction", count);
flat = 0;
flat_count = 0;
for (; count; count--)
{
flags = tri->wFlags;
flags &= 0x1f;
switch (flags)
{
case D3DTRIFLAG_START:
v1 = tri->v1;
v2 = tri->v2;
v3 = tri->v3;
D3D_INFO(9, " triangle %d is START", ins->wCount - count);
break;
case D3DTRIFLAG_ODD:
v1 = v3;
v2 = v2;
v3 = tri->v3;
if ((v1 != tri->v1) || (v2 != tri->v2))
{
D3D_WARN(1, " triangle %d is not an odd triangle",
ins->wCount - count);
return FALSE;
}
break;
case D3DTRIFLAG_EVEN:
v1 = v1;
v2 = v3;
v3 = tri->v3;
if ((v1 != tri->v1) || (v2 != tri->v2))
{
D3D_WARN(1, " triangle %d is not an even triangle",
ins->wCount - count);
return FALSE;
}
break;
default:
/* (flags > 0) && (flags < 30) */
v1 = tri->v1;
v2 = tri->v2;
v3 = tri->v3;
D3D_INFO(9, " triangle %d is START FLAT of %d", ins->wCount - count, flags);
flat_count = flags;
break;
}
tri = (D3DTRIANGLE*) ((char*) tri + ins->bSize);
}
return TRUE;
}
//---------------------------------------------------------------------
D3DVERTEXTYPE GetVertexType(LPDIRECT3DDEVICEI lpDevI)
{
if (lpDevI->dwFEFlags & D3DFE_TLVERTEX)
return D3DVT_TLVERTEX;
else
if (lpDevI->dwFlags & D3DPV_LIGHTING)
return D3DVT_VERTEX;
else
return D3DVT_LVERTEX;
}
#endif // DBG
//---------------------------------------------------------------------
// Returns TRUE, if driver should be notified about the state
BOOL
trackState(LPDIRECT3DDEVICEI lpDevI, LPD3DSTATE state)
{
DWORD type = (DWORD) state->drstRenderStateType;
D3D_INFO(9, "trackState: state = %d", state->drstRenderStateType);
if (IS_OVERRIDE(type))
{
DWORD override = GET_OVERRIDE(type);
if (state->dwArg[0])
{
D3D_INFO(9, "trackState: setting override for state %d", override);
STATESET_SET(lpDevI->renderstate_overrides, override);
}
else
{
D3D_INFO(9, "trackState: clearing override for state %d", override);
STATESET_CLEAR(lpDevI->renderstate_overrides, override);
}
return TRUE;
}
if (STATESET_ISSET(lpDevI->renderstate_overrides, type))
{
D3D_INFO(9, "trackState: state %d is overridden, ignoring", type);
return FALSE;
}
/* Save latest state for GetRenderState(). This will break if
someone actually implements the Execute in DDI i.e. when
D3DHAL_Execute{Un}Clipped calls us. */
SetDeviceRenderState(lpDevI, state->drstRenderStateType, state->dwArg[0]);
return TRUE;
}
//----------------------------------------------------------------------
// This function does not copy the data if pIn = pOut
//
void ConvertColorsToRamp(LPDIRECT3DDEVICEI lpDevI, D3DTLVERTEX *pIn,
D3DTLVERTEX *pOut, DWORD count)
{
RAMP_RANGE_INFO RampInfo;
BOOL theSameInAndOut = pIn == pOut;
CallRampService(lpDevI, RAMP_SERVICE_FIND_LIGHTINGRANGE,
(ULONG_PTR)&RampInfo, 0);
D3DVALUE colorScale = D3DVAL(max(min((INT32)RampInfo.size - 1, 0x7fff), 0));
for (DWORD i=count; i; i--)
{
const D3DVALUE B_SCALE = 1.000f / 255.0f;
// Convert diffuse color to shade value
D3DVALUE color = RGBA_GETBLUE (pIn->color)*B_SCALE;
if (RampInfo.specular)
{
// Convert specular color to shade value
D3DVALUE specular = RGBA_GETBLUE (pIn->specular)*B_SCALE;
color = 0.75f*color*(1.0f - specular) + specular;
}
DWORD outColor = (DWORD)(color * colorScale) + RampInfo.base;
if (theSameInAndOut)
{
pIn->color = CI_MAKE(RGBA_GETALPHA(pIn->color), outColor, 0);
pIn->specular = PtrToUlong(RampInfo.pTexRampMap);
}
else
{
pOut->color = CI_MAKE(RGBA_GETALPHA(pIn->color), outColor, 0);
pOut->specular = PtrToUlong(RampInfo.pTexRampMap);
pOut->sx = pIn->sx;
pOut->sy = pIn->sy;
pOut->sz = pIn->sz;
pOut->rhw = pIn->rhw;
pOut->tu = pIn->tu;
pOut->tv = pIn->tv;
pOut++;
}
pIn++;
}
}
//---------------------------------------------------------------------
void WaitForFlip(LPDIRECTDRAWSURFACE lpDDS)
{
if (DDCheckSurfaceCaps(lpDDS, DDSCAPS_FLIP))
{
HRESULT ret;
D3D_WARN(4, "Waiting for flip");
do
{
ret = lpDDS->GetFlipStatus(DDGFS_ISFLIPDONE);
} while (ret == DDERR_WASSTILLDRAWING);
}
}
//---------------------------------------------------------------------
// DrawPrim for execute buffers using RenderPrimitive
// This function is called by the clipper
//
HRESULT CDirect3DDeviceIHW::DrawExeBuf()
{
D3DHAL_RENDERPRIMITIVEDATA data;
LPDIRECTDRAWSURFACE lpDDS = this->lpDDSTarget;
HRESULT ret;
WORD wFirstPointIndex;
memset(&data, 0, sizeof data);
data.dwhContext = this->dwhContext;
data.dwStatus = this->iClipStatus;
data.dwTLOffset = 0;
if (this->dwFlags & D3DPV_CLIPPERPRIM)
{
// For clipped primitive vertices are generated in ClipperState.clipBuf
data.lpTLBuf = this->ClipperState.clipBuf.GetDDS();
data.lpExeBuf = this->ClipperState.clipBufPrim.GetDDS();
data.dwOffset = 0;
wFirstPointIndex = 0;
}
else
{
data.lpTLBuf = this->TLVbuf.GetDDS();
if (this->primType == D3DPT_POINTLIST)
{
data.lpExeBuf = this->ClipperState.clipBufPrim.GetDDS();
data.dwOffset = 0;
wFirstPointIndex = (WORD)(((BYTE*)this->lpvOut -
(BYTE*)this->TLVbuf.GetAddress()) >> 5);
}
else
{
data.lpExeBuf = this->ClipperState.lpDDExeBuf;
data.dwOffset = (DWORD)
((BYTE*)this->lpwIndices - (BYTE*)this->ClipperState.lpvExeBufMem);
}
}
switch (this->primType)
{
case D3DPT_POINTLIST:
{
D3DPOINT *pPoint = (D3DPOINT*)this->ClipperState.clipBufPrim.GetAddress();
// Size of TLVERTEX is 32
pPoint->wFirst = wFirstPointIndex;
pPoint->wCount = (WORD)this->dwNumVertices;
data.diInstruction.bOpcode = D3DOP_POINT;
data.diInstruction.bSize = sizeof(D3DPOINT);
data.diInstruction.wCount = 1;
break;
}
case D3DPT_LINELIST:
{
data.diInstruction.bOpcode = D3DOP_LINE;
data.diInstruction.bSize = sizeof(D3DLINE);
D3DLINE *pLine= (D3DLINE*)this->ClipperState.clipBufPrim.GetAddress();
if (this->dwFlags & D3DPV_CLIPPERPRIM)
{
// Clipped line is not indexed
pLine->v1 = 0;
pLine->v2 = 1;
data.diInstruction.wCount = 1;
}
else
data.diInstruction.wCount = (WORD)(this->dwNumIndices >> 1);
break;
}
case D3DPT_TRIANGLEFAN:
case D3DPT_TRIANGLELIST:
{
data.diInstruction.bOpcode = D3DOP_TRIANGLE;
data.diInstruction.bSize = sizeof(D3DTRIANGLE);
D3DTRIANGLE *pTri = (D3DTRIANGLE*)
this->ClipperState.clipBufPrim.GetAddress();
if (this->dwFlags & D3DPV_CLIPPERPRIM)
{
// Clipped triangle is non-indexed triangle fan
// We have to convert it to indexed triangle list and compute
// edge flags
ClipVertex **clip = this->ClipperState.current_vbuf;
pTri->wFlags = D3DTRIFLAG_STARTFLAT((WORD)this->dwNumPrimitives);
if (clip[0]->clip & CLIPPED_ENABLE)
pTri->wFlags |= D3DTRIFLAG_EDGEENABLE1;
DWORD i;
for (i=1; i <= this->dwNumPrimitives; i++)
{
pTri->v1 = 0;
pTri->v2 = (WORD)i;
pTri->v3 = (WORD)(i+1);
if (clip[i]->clip & CLIPPED_ENABLE)
pTri->wFlags |= D3DTRIFLAG_EDGEENABLE2;
pTri++;
pTri->wFlags = D3DTRIFLAG_EVEN; // All except first are EVEN
}
pTri--;
// Edge 3 is enabled only for the last triangle in the fan
// Not that "i" points to the last clip vertex
if (clip[i]->clip & CLIPPED_ENABLE)
pTri->wFlags |= D3DTRIFLAG_EDGEENABLE3;
data.diInstruction.wCount = (WORD)this->dwNumPrimitives;
}
else
data.diInstruction.wCount = (WORD)this->dwNumPrimitives;
break;
}
}
#ifndef WIN95
if((ret = CheckContextSurfaceNOLOCK(this)) != D3D_OK)
return (D3DERR_EXECUTE_FAILED);
#endif //WIN95
#if _D3D_FORCEDOUBLE
CD3DForceFPUDouble ForceFPUDouble(this);
#endif //_D3D_FORCEDOUBLE
CALL_HALONLY_NOLOCK(ret, this, RenderPrimitive, &data);
if (ret != DDHAL_DRIVER_HANDLED)
{
D3D_ERR("HAL failed to handle RenderPrimitive call from Execute API");
return (D3DERR_EXECUTE_FAILED);
}
this->iClipStatus = data.dwStatus;
if (data.ddrval != DD_OK)
{
D3D_ERR("HAL error in RenderPrimitive call from Execute API");
return (data.ddrval);
}
return (D3D_OK);
}
//---------------------------------------------------------------------
HRESULT DIRECT3DDEVICEI::PickExeBuf()
{
LPD3DTRIANGLE tri;
DWORD i;
LPD3DRECT pick_region = &this->pick_data.pick;
D3DVALUE result;
LPD3DTLVERTEX lpTLV;
HRESULT ret;
if (this->dwFlags & D3DPV_CLIPPERPRIM)
{
// For clipped primitive vertices are generated in ClipperState.clipBuf
lpTLV = (D3DTLVERTEX*)this->ClipperState.clipBuf.GetAddress();
D3DTRIANGLE tri;
tri.v1 = 0;
for (i=1; i <= this->dwNumPrimitives; i++)
{
tri.v2 = (WORD)i;
tri.v3 = (WORD)(i+1);
tri.wFlags = D3DTRIFLAG_EDGEENABLETRIANGLE;
if (GenPickTriangle(this, lpTLV, &tri, pick_region, &result))
{
if ((ret = GenAddPickRecord(this,
D3DOP_TRIANGLE,
this->dwClipIns_offset,
result)) != D3D_OK)
return ret;
}
}
}
else
{
lpTLV = (D3DTLVERTEX*)this->TLVbuf.GetAddress();
tri = (LPD3DTRIANGLE)this->lpwIndices;
for (i = this->dwNumPrimitives; i; i--, tri++)
{
if (GenPickTriangle(this, lpTLV, tri, pick_region, &result))
{
if ((ret = GenAddPickRecord(this,
D3DOP_TRIANGLE,
(DWORD)((BYTE*)tri - (BYTE*)this->lpbClipIns_base),
result)) != D3D_OK)
return ret;
}
}
}
return D3D_OK;
}
/*************************************************************************/
/* Points */
/*************************************************************************/
HRESULT D3DFEClipPointsHW(LPDIRECT3DDEVICEI lpDevI, D3DPOINT *point, DWORD dwCount)
{
DWORD icount = dwCount;
HRESULT ret;
lpDevI->primType = D3DPT_LINELIST;
lpDevI->lpwIndices = 0; // Points are not indexed
for (; icount; icount--)
{
lpDevI->dwNumVertices = point->wCount;
lpDevI->lpvOut = &((D3DTLVERTEX*)lpDevI->TLVbuf.GetAddress())[point->wFirst];
WORD *lpClipFlagsOld = lpDevI->lpClipFlags;
lpDevI->lpClipFlags = &lpDevI->lpClipFlags[point->wFirst];
ret = ProcessClippedPoints(lpDevI);
if (ret != D3D_OK)
{
D3D_ERR("ProcessClippedPoints failed!");
return ret;
}
lpDevI->lpClipFlags = lpClipFlagsOld;
point++;
}
return D3D_OK;
}
/*************************************************************************/
/* Lines */
/*************************************************************************/
inline HRESULT D3DFEClipLinesHW(LPDIRECT3DDEVICEI lpDevI, D3DLINE *line, DWORD dwCount)
{
HRESULT ret;
lpDevI->primType = D3DPT_LINELIST;
lpDevI->dwNumIndices = dwCount << 1;
lpDevI->dwNumPrimitives = dwCount;
lpDevI->lpvOut = lpDevI->TLVbuf.GetAddress();
lpDevI->lpwIndices = (WORD*)line;
ret = ProcessClippedIndexedLine(lpDevI);
return ret;
}
/*************************************************************************/
/* Triangles */
/*************************************************************************/
inline HRESULT D3DFEClipTrianglesHW(LPDIRECT3DDEVICEI lpDevI, D3DTRIANGLE *tri, DWORD dwCount)
{
HRESULT ret;
lpDevI->primType = D3DPT_TRIANGLELIST;
lpDevI->dwNumPrimitives = dwCount;
lpDevI->lpvOut = lpDevI->TLVbuf.GetAddress();
lpDevI->dwNumIndices = dwCount * 3;
lpDevI->lpwIndices = (WORD*)tri;
ret = ProcessClippedIndexedTriangleList(lpDevI);
return ret;
}
/*************************************************************************/
/* Pick triangles */
/*************************************************************************/
inline HRESULT GenPickTriangles(LPDIRECT3DDEVICEI lpDevI, D3DTRIANGLE *tri, DWORD dwCount)
{
HRESULT ret;
lpDevI->primType = D3DPT_TRIANGLELIST;
lpDevI->dwNumIndices = dwCount * 3;
lpDevI->dwNumPrimitives = dwCount;
lpDevI->lpvOut = lpDevI->TLVbuf.GetAddress();
lpDevI->lpwIndices = (WORD*)tri;
ret = ProcessClippedIndexedTriangleList(lpDevI);
return ret;
}/*----------------------------------------------------------------------------
*
* Instruction emulation.
*/
HRESULT D3DHELInst_D3DOP_MATRIXLOAD(LPDIRECT3DDEVICEI lpDevI,
DWORD dwCount,
LPD3DMATRIXLOAD lpMatLoad)
{
LPD3DMATRIXI lpSrcMat;
LPD3DMATRIXI lpDestMat;
DWORD i;
HRESULT ret;
D3DFE_TRANSFORM& TRANSFORM = lpDevI->transform;
for (i = 0; i < dwCount; i++)
{
D3DMATRIXHANDLE hSrc = lpMatLoad[i].hSrcMatrix;
D3DMATRIXHANDLE hDst = lpMatLoad[i].hDestMatrix;
lpSrcMat = HANDLE_TO_MAT(lpDevI, hSrc);
lpDestMat = HANDLE_TO_MAT(lpDevI, hDst);
if (lpSrcMat == NULL || lpDestMat == NULL)
return (DDERR_INVALIDPARAMS);
memcpy (lpDestMat, lpSrcMat, offsetof(D3DMATRIXI, link));
if (hDst == TRANSFORM.hWorld)
ret = D3DFE_SetMatrixWorld(lpDevI, (D3DMATRIX*)lpSrcMat);
else
if (hDst == TRANSFORM.hView)
ret = D3DFE_SetMatrixView(lpDevI, (D3DMATRIX*)lpSrcMat);
else
if (hDst == TRANSFORM.hProj)
ret = D3DFE_SetMatrixProj(lpDevI, (D3DMATRIX*)lpSrcMat);
if (ret != D3D_OK)
return (DDERR_GENERIC);
}
return (D3D_OK);
}
//---------------------------------------------------------------------
HRESULT D3DHELInst_D3DOP_MATRIXMULTIPLY(LPDIRECT3DDEVICEI lpDevI,
DWORD dwCount,
LPD3DMATRIXMULTIPLY lpMmult)
{
LPD3DMATRIXI lpMat1, lpMat2;
LPD3DMATRIXI result;
DWORD i;
D3DFE_TRANSFORM& TRANSFORM = lpDevI->transform;
for (i = 0; i < dwCount; i++)
{
D3DMATRIXHANDLE hSrc1 = lpMmult[i].hSrcMatrix1;
D3DMATRIXHANDLE hSrc2 = lpMmult[i].hSrcMatrix2;
D3DMATRIXHANDLE hDst = lpMmult[i].hDestMatrix;
lpMat1 = HANDLE_TO_MAT(lpDevI, hSrc1);
lpMat2 = HANDLE_TO_MAT(lpDevI, hSrc2);
result = HANDLE_TO_MAT(lpDevI, hDst);
if (!lpMat1 || !lpMat2)
{
return (DDERR_GENERIC);
}
MatrixProduct(result, lpMat1, lpMat2);
if (hDst == TRANSFORM.hWorld)
{
D3DFE_SetMatrixWorld(lpDevI, (D3DMATRIX*)result);
}
else
if (hDst == TRANSFORM.hView)
{
D3DFE_SetMatrixView(lpDevI, (D3DMATRIX*)result);
}
else
if (hDst == TRANSFORM.hProj)
{
D3DFE_SetMatrixProj(lpDevI, (D3DMATRIX*)result);
}
}
return (D3D_OK);
}
//---------------------------------------------------------------------
HRESULT D3DHELInst_D3DOP_STATETRANSFORM(LPDIRECT3DDEVICEI lpDevI,
DWORD count,
LPD3DSTATE lpMset)
{
DWORD i;
D3DFE_TRANSFORM& TRANSFORM = lpDevI->transform;
for (i = 0; i < count; i++)
{
DWORD type = (DWORD) lpMset[i].dtstTransformStateType;
D3D_INFO(9, "HEL D3DOP_STATETRANSFORM: state = %d", type);
if (IS_OVERRIDE(type))
{
DWORD override = GET_OVERRIDE(type);
if (lpMset[i].dwArg[0])
{
D3D_WARN(5, "HEL D3DOP_STATETRANSFORM: setting override for state %d", override);
STATESET_SET(lpDevI->transformstate_overrides, override);
} else
{
D3D_WARN(5, "HEL D3DOP_STATETRANSFORM: clearing override for state %d", override);
STATESET_CLEAR(lpDevI->transformstate_overrides, override);
}
continue;
}
if (STATESET_ISSET(lpDevI->transformstate_overrides, type))
{
D3D_WARN(5, "HEL D3DOP_STATETRANSFORM: state %d is overridden, ignoring", type);
continue;
}
D3DMATRIXHANDLE hSrc = lpMset[i].dwArg[0];
D3DMATRIX *lpSrcMat = (D3DMATRIX*)HANDLE_TO_MAT(lpDevI, hSrc);
if (lpSrcMat == NULL)
{
// In DX5 days, this error was not propagated back.
if (lpDevI->dwVersion <= 2)
return D3D_OK;
else
{
D3D_ERR("NULL srcMat in D3DHELInst_D3DOP_STATETRANSFORM");
return (DDERR_INVALIDPARAMS);
}
}
switch (type)
{
case D3DTRANSFORMSTATE_WORLD:
D3DFE_SetMatrixWorld(lpDevI, lpSrcMat);
TRANSFORM.hWorld = hSrc;
break;
case D3DTRANSFORMSTATE_VIEW:
D3DFE_SetMatrixView(lpDevI, lpSrcMat);
TRANSFORM.hView = hSrc;
break;
case D3DTRANSFORMSTATE_PROJECTION:
D3DFE_SetMatrixProj(lpDevI, lpSrcMat);
TRANSFORM.hProj = hSrc;
break;
default:
D3D_ERR("Bad State in D3DopStateTransform emulation.");
return DDERR_GENERIC;
}
}
return (D3D_OK);
}
//---------------------------------------------------------------------
#if DBG
HRESULT validateProcessVertices(LPDIRECT3DDEVICEI lpDevI,
LPD3DPROCESSVERTICES data)
{
LPD3DHAL_GLOBALDRIVERDATA lpGlob = lpDevI->lpD3DHALGlobalDriverData;
unsigned int vnum;
vnum = (unsigned int)(lpGlob->dwNumVertices ? lpGlob->dwNumVertices :
D3DHAL_DEFAULT_TL_NUM);
if (data->wDest >= vnum) {
D3D_ERR("Dest index to large for Execute Buffer.");
return DDERR_INVALIDPARAMS;
} else if ((data->wDest + data->dwCount) > vnum) {
D3D_ERR("Process vertices exceeds Execute Buffer size.");
return DDERR_INVALIDPARAMS;
}
return D3D_OK;
}
#endif
//---------------------------------------------------------------------
HRESULT D3DHELInst_D3DOP_TRANSFORM(LPDIRECT3DDEVICEI lpDevI,
DWORD count,
LPD3DPROCESSVERTICES data,
LPD3DEXECUTEBUFFERDESC eb)
{
LPD3DTLVERTEX lpTlv;
DWORD i;
DWORD op;
HRESULT ret = DD_OK;
lpDevI->primType = D3DPT_TRIANGLELIST;
lpDevI->dwOutputSize = sizeof(D3DVERTEX);
lpDevI->position.dwStride = sizeof(D3DVERTEX);
lpDevI->nTexCoord = 1;
for (i = 0; i < count; i++)
{
#if DBG
if ((ret = validateProcessVertices(lpDevI, data)))
return ret;
#endif
int nVertices = data->wDest+data->dwCount;
lpTlv = (LPD3DTLVERTEX)lpDevI->TLVbuf.GetAddress();
lpDevI->dwNumVertices = data->dwCount;
lpDevI->position.lpvData = ((char*)eb->lpData) +
data->wStart * sizeof(D3DVERTEX);
lpDevI->lpvOut = lpTlv + data->wDest;
/*
* Transform the vertices
*/
op = data->dwFlags & D3DPROCESSVERTICES_OPMASK;
if (op == D3DPROCESSVERTICES_COPY)
{
lpDevI->dwVIDIn = d3dVertexToFVF[D3DVT_TLVERTEX];
memcpy(lpDevI->lpvOut, lpDevI->position.lpvData,
data->dwCount * sizeof(D3DVERTEX));
D3DFE_updateExtents(lpDevI);
D3D_INFO(4, "TLVERTEX encountered. Will not clip.");
lpDevI->dwFEFlags |= D3DFE_TLVERTEX;
// Apply ramp post-lighting stuff only for D3DTLVERTEX.
// For other vertex types this is done in the transformation loop
//
if (lpDevI->pfnRampService != NULL)
{
ConvertColorsToRamp(lpDevI, (D3DTLVERTEX*)lpDevI->lpvOut,
(D3DTLVERTEX*)lpDevI->lpvOut, data->dwCount);
}
lpDevI->iClipStatus &= ~D3DSTATUS_CLIPINTERSECTIONALL;
}
else
{
if (op == D3DPROCESSVERTICES_TRANSFORMLIGHT)
{
lpDevI->dwVIDIn = d3dVertexToFVF[D3DVT_VERTEX];
lpDevI->dwFlags |= D3DPV_LIGHTING;
}
else
{
lpDevI->dwVIDIn = d3dVertexToFVF[D3DVT_LVERTEX];
}
if (lpDevI->dwFlags & D3DDP_DONOTCLIP)
{
D3DFE_ProcessVertices(lpDevI);
lpDevI->iClipStatus &= ~D3DSTATUS_CLIPINTERSECTIONALL;
}
else
{
lpDevI->lpClipFlags = (D3DFE_CLIPCODE*)lpDevI->HVbuf.GetAddress() +
data->wDest;
D3DFE_ProcessVertices(lpDevI);
D3DFE_UpdateClipStatus(lpDevI);
D3D_INFO(4, "Status Change -> Clip flags. status = %08x", lpDevI->iClipStatus);
// Restore initial value for lpClipFlags
lpDevI->lpClipFlags = (D3DFE_CLIPCODE*)lpDevI->HVbuf.GetAddress();
}
}
/* update stats
*/
lpDevI->D3DStats.dwVerticesProcessed += data->dwCount;
data++;
}
//out_of_here:
return (ret);
}
//--------------------------------------------------------------------
inline HRESULT GrowTLandHbuffers(LPDIRECT3DDEVICEI lpDevI, DWORD dwUsedVertexCount)
{
HRESULT ddrval;
if (dwUsedVertexCount > 4096)
dwUsedVertexCount = 4096;
else
if (dwUsedVertexCount < lpDevI->lpD3DHALGlobalDriverData->hwCaps.dwMaxVertexCount)
dwUsedVertexCount = lpDevI->lpD3DHALGlobalDriverData->hwCaps.dwMaxVertexCount;
ddrval = lpDevI->TLVbuf.CheckAndGrow(lpDevI, dwUsedVertexCount << 5);
if (ddrval != D3D_OK)
{
D3D_ERR("Failed to check and grow TLVbuf in Execute");
return ddrval;
}
ddrval = lpDevI->HVbuf.CheckAndGrow(dwUsedVertexCount*sizeof(D3DFE_CLIPCODE));
if (ddrval != D3D_OK)
{
D3D_ERR("Failed to check and grow HVbuf in Execute");
return ddrval;
}
return D3D_OK;
}
//--------------------------------------------------------------------
//
#define WAIT_FOR_FLIP() \
if (!waitedForFlip) \
{ \
WaitForFlip(lpDDS); \
waitedForFlip = TRUE; \
}
HRESULT
CDirect3DDeviceIHW::ExecuteI(LPD3DI_EXECUTEDATA lpExData, DWORD mode)
{
BOOL waitedForFlip = FALSE;
D3DINSTRUCTION* lpIns;
D3DHAL_RENDERSTATEDATA stateData;
D3DHAL_RENDERPRIMITIVEDATA primitiveData;
D3DEXECUTEBUFFERDESC debDesc;
LPDIRECTDRAWSURFACE lpDDS = this->lpDDSTarget;
LPBYTE prim;
D3DFE_TRANSFORM *transform = &this->transform;
LPDIRECTDRAWSURFACE lpDDExeBuf;
HRESULT ddrval;
CHECKLOST(this);
// Do we need to map new texture stage operations to DX5 renderstates?
if(this->dwFEFlags & D3DFE_MAP_TSS_TO_RS) {
MapTSSToRS();
this->dwFEFlags &= ~D3DFE_MAP_TSS_TO_RS; // Reset request bit
}
/* Update textures */
UpdateTextures();
if (mode == D3DEXECUTE_UNCLIPPED)
this->dwFlags |= D3DDP_DONOTCLIP;
else if (mode != D3DEXECUTE_CLIPPED)
return DDERR_INVALIDPARAMS;
/*
* If the driver can process triangles while the hardware has a
* pending page-flip such as the 3Dfx voodoo chipset, then we
* don't need to call WaitForFlip. We pretend that it has already
* been called to keep the code simple.
*/
if (this->lpD3DHALGlobalDriverData->hwCaps.dwDevCaps &
D3DDEVCAPS_CANRENDERAFTERFLIP)
{
waitedForFlip = TRUE;
}
/*
* Lock the HAL for the duration.
*/
LOCK_HAL(ddrval, this);
if (ddrval != DD_OK)
{
D3D_ERR("Failed to lock HAL in Execute");
return (ddrval);
}
#if _D3D_FORCEDOUBLE
CD3DForceFPUDouble ForceFPUDouble(this);
#endif //_D3D_FORCEDOUBLE
/*
* Execute the buffer through the HAL
*/
{
LPD3DHAL_EXDATA hexData = (LPD3DHAL_EXDATA) lpExData->dwHandle;
debDesc.lpData = SURFACE_MEMORY(hexData->lpDDS);
lpDDExeBuf = hexData->lpDDS;
}
memset(&stateData, 0, sizeof(D3DHAL_RENDERSTATEDATA));
stateData.dwhContext = this->dwhContext;
stateData.lpExeBuf = lpDDExeBuf;
memset(&primitiveData, 0, sizeof(D3DHAL_RENDERPRIMITIVEDATA));
primitiveData.dwhContext = this->dwhContext;
primitiveData.lpExeBuf = lpDDExeBuf;
primitiveData.dwTLOffset = 0L;
this->ClipperState.lpDDExeBuf = lpDDExeBuf;
this->ClipperState.lpvExeBufMem = debDesc.lpData;
// Modify driver funcs for EB case
PFN_DRAWPRIM pfnOldDrawPrim = this->pfnDrawPrim;
PFN_DRAWPRIM pfnOldDrawIndexedPrim = this->pfnDrawIndexedPrim;
this->pfnDrawPrim = &DIRECT3DDEVICEI::DrawExeBuf;
this->pfnDrawIndexedPrim = &DIRECT3DDEVICEI::DrawExeBuf;
/*
* The first instruction.
*/
lpIns = (LPD3DINSTRUCTION)((LPBYTE)debDesc.lpData +
lpExData->dwInstructionOffset);
ddrval = GrowTLandHbuffers(this, lpExData->dwVertexCount);
if (ddrval != D3D_OK)
goto execute_failed;
// do this after CheckAndGrow, because TL buffer could be re-created
primitiveData.lpTLBuf = this->TLVbuf.GetDDS();
while (lpIns->bOpcode != D3DOP_EXIT)
{
prim = (LPBYTE)lpIns + sizeof(D3DINSTRUCTION);
D3D_INFO(5, "HAL parsing instruction %d", lpIns->bOpcode);
/*
* Parse the instruction.
*/
switch (lpIns->bOpcode)
{
case D3DOP_MATRIXLOAD:
{
D3D_INFO(5, "Emulating D3DOP_MATRIXLOAD for HAL");
ddrval = D3DHELInst_D3DOP_MATRIXLOAD(this,
lpIns->wCount,
(LPD3DMATRIXLOAD)prim);
if (ddrval != D3D_OK)
{
D3D_ERR("Emulated D3DOP_MATRIXLOAD failed.");
goto execute_failed;
}
NEXTINSTRUCTION(lpIns, D3DMATRIXLOAD, lpIns->wCount);
break;
}
case D3DOP_MATRIXMULTIPLY:
{
D3D_INFO(5, "Emulating D3DOP_MATRIXMULTIPLY for HAL");
ddrval = D3DHELInst_D3DOP_MATRIXMULTIPLY(this,
lpIns->wCount,
(LPD3DMATRIXMULTIPLY)prim);
if (ddrval != D3D_OK)
{
D3D_ERR("Emulated D3DOP_MATRIXMULTIPLY failed.");
goto execute_failed;
}
NEXTINSTRUCTION(lpIns, D3DMATRIXMULTIPLY, lpIns->wCount);
break;
}
case D3DOP_PROCESSVERTICES:
{
D3D_INFO(5, "Emulating D3DOP_PROCESSVERTICES for HAL");
ddrval = D3DHELInst_D3DOP_TRANSFORM
(this, lpIns->wCount, (LPD3DPROCESSVERTICES)prim,
&debDesc);
if (ddrval != D3D_OK)
{
D3D_ERR("Emulated D3DOP_PROCESSVERTICES failed.");
goto execute_failed;
}
NEXTINSTRUCTION(lpIns, D3DPROCESSVERTICES, lpIns->wCount);
break;
}
case D3DOP_STATETRANSFORM:
{
D3D_INFO(5, "Emulating D3DOP_STATETRANSFORM for HAL");
ddrval = D3DHELInst_D3DOP_STATETRANSFORM(this,
lpIns->wCount,
(LPD3DSTATE)prim);
if (ddrval != D3D_OK)
{
D3D_ERR("Emulated D3DOP_STATETRANSFORM failed.");
goto execute_failed;
}
NEXTINSTRUCTION(lpIns, D3DSTATE, lpIns->wCount);
break;
}
case D3DOP_STATELIGHT:
{
D3D_INFO(5, "Emulating D3DOP_STATELIGHT for HAL");
ddrval = D3DHELInst_D3DOP_STATELIGHT(this,
lpIns->wCount,
(LPD3DSTATE)prim);
if (ddrval != D3D_OK) {
D3D_ERR("Emulated D3DOP_STATELIGHT failed.");
goto execute_failed;
}
NEXTINSTRUCTION(lpIns, D3DSTATE, lpIns->wCount);
break;
}
case D3DOP_BRANCHFORWARD:
{
D3DBRANCH* branch = (D3DBRANCH*)prim;
LPBYTE target;
BOOL isTaken = FALSE;
D3D_INFO(5, "Emulating D3DOP_BRANCHFORWARD");
if (branch->bNegate)
{
if ((branch->dwMask & this->iClipStatus) != branch->dwValue)
{
D3D_INFO(4, "Taking forward branch");
if (branch->dwOffset)
{
isTaken = TRUE;
target = (LPBYTE)lpIns + branch->dwOffset;
}
else
{
D3D_INFO(4, "branch says to exit.");
goto execute_done;
}
}
}
else
{
if ((branch->dwMask & this->iClipStatus) == branch->dwValue)
{
D3D_INFO(4, "Taking forward branch");
if (branch->dwOffset)
{
isTaken = TRUE;
target = (LPBYTE)lpIns + branch->dwOffset;
} else
{
D3D_INFO(2, "branch says to exit.");
goto execute_done;
}
}
}
if (isTaken)
{
D3D_INFO(5, "D3DOP_BRANCHFORWARD instruction: branch taken");
lpIns = (LPD3DINSTRUCTION) target;
}
else
{
D3D_INFO(5, "D3DOP_BRANCHFORWARD instruction: branch not taken");
NEXTINSTRUCTION(lpIns, D3DBRANCH, lpIns->wCount);
}
break;
}
case D3DOP_TEXTURELOAD:
{
D3D_INFO(5, "Emulating D3DOP_TEXTURELOAD for HAL");
ddrval = D3DHELInst_D3DOP_TEXTURELOAD(this,
lpIns->wCount,
(LPD3DTEXTURELOAD)prim);
if (ddrval != D3D_OK)
{
D3D_ERR("Emulated D3DOP_TEXTURELOAD failed.");
goto execute_failed;
}
NEXTINSTRUCTION(lpIns, D3DTEXTURELOAD, lpIns->wCount);
break;
}
case D3DOP_STATERENDER:
{
LPD3DSTATE lpState;
DWORD i,j,statek,valuek;
lpState = (LPD3DSTATE) (lpIns + 1);
for (i = 0,j=0,statek=(DWORD)-1; i < lpIns->wCount; i++)
{
trackState(this, &lpState[i]);
}
stateData.dwOffset = (DWORD)(prim - (LPBYTE) debDesc.lpData);
stateData.dwCount = lpIns->wCount;
CALL_HALONLY_NOLOCK(ddrval, this, RenderState, &stateData);
if (stateData.ddrval != DD_OK)
{
D3D_ERR("HAL error in RenderState call from Execute API");
ddrval = stateData.ddrval;
goto execute_failed;
}
NEXTINSTRUCTION(lpIns, D3DSTATE, lpIns->wCount);
break;
}
case D3DOP_SETSTATUS:
{
LPD3DSTATUS status = (LPD3DSTATUS)prim;
if (status->dwFlags & D3DSETSTATUS_STATUS)
this->iClipStatus = status->dwStatus;
if (status->dwFlags & D3DSETSTATUS_EXTENTS)
{
this->rExtents.x1 = D3DVAL(status->drExtent.x1);
this->rExtents.y1 = D3DVAL(status->drExtent.y1);
this->rExtents.x2 = D3DVAL(status->drExtent.x2);
this->rExtents.y2 = D3DVAL(status->drExtent.y2);
}
NEXTINSTRUCTION(lpIns, D3DSTATUS, lpIns->wCount);
break;
}
default:
if (mode == D3DEXECUTE_UNCLIPPED || this->dwFEFlags & D3DFE_TLVERTEX)
{
switch (lpIns->bOpcode)
{
case D3DOP_POINT:
case D3DOP_LINE:
case D3DOP_SPAN:
case D3DOP_TRIANGLE:
{
if (lpIns->wCount == 0)
goto noprim;
#if DBG
switch (lpIns->bOpcode)
{
case D3DOP_POINT:
Profile(PROF_EXECUTE, D3DPT_POINTLIST, GetVertexType(this));
break;
case D3DOP_LINE:
Profile(PROF_EXECUTE, D3DPT_LINELIST, GetVertexType(this));
break;
case D3DOP_TRIANGLE:
Profile(PROF_EXECUTE, D3DPT_TRIANGLELIST, GetVertexType(this));
break;
}
#endif // DBG
if (!waitedForFlip)
{
WaitForFlip(lpDDS);
waitedForFlip = TRUE;
}
primitiveData.dwOffset = (DWORD)(prim - (LPBYTE) debDesc.lpData);
primitiveData.dwStatus = this->iClipStatus;
primitiveData.diInstruction = *lpIns;
#ifndef WIN95
if((ddrval = CheckContextSurfaceNOLOCK (this)) != D3D_OK)
{
goto execute_failed;
}
#endif //WIN95
CALL_HALONLY_NOLOCK(ddrval, this, RenderPrimitive,
&primitiveData);
if (primitiveData.ddrval != DD_OK)
{
D3D_ERR("HAL error in RenderPrimitive call from Execute API");
ddrval = primitiveData.ddrval;
goto execute_failed;
}
switch (lpIns->bOpcode)
{
int i;
case D3DOP_LINE:
this->D3DStats.dwLinesDrawn += lpIns->wCount;
break;
case D3DOP_TRIANGLE:
#if DBG
if (!validateTriangleFlags(lpIns, (LPD3DTRIANGLE) prim))
{
ddrval = DDERR_INVALIDPARAMS;
goto execute_failed;
}
#endif
this->D3DStats.dwTrianglesDrawn += lpIns->wCount;
break;
case D3DOP_POINT:
{
LPD3DPOINT point = (LPD3DPOINT)prim;
for (i = 0; i < lpIns->wCount; i++)
{
this->D3DStats.dwPointsDrawn += point->wCount;
point++;
}
}
break;
case D3DOP_SPAN:
{
LPD3DSPAN span = (LPD3DSPAN)prim;
for (i = 0; i < lpIns->wCount; i++)
{
this->D3DStats.dwSpansDrawn += span->wCount;
span++;
}
}
break;
}
this->iClipStatus = primitiveData.dwStatus;
noprim:
lpIns = (LPD3DINSTRUCTION)((LPBYTE)lpIns +
sizeof(D3DINSTRUCTION) +
(lpIns->bSize * lpIns->wCount));
break;
}
default:
D3D_ERR("HAL detected invalid instruction opcode in Execute");
goto execute_failed;
}
}
else
{
switch (lpIns->bOpcode)
{
case D3DOP_TRIANGLE:
if (lpIns->wCount == 0)
{
NEXTINSTRUCTION(lpIns, D3DTRIANGLE, lpIns->wCount);
break;
}
Profile(PROF_EXECUTE, D3DPT_TRIANGLELIST, GetVertexType(this));
WAIT_FOR_FLIP();
#if DBG
if (!validateTriangleFlags(lpIns, (LPD3DTRIANGLE) prim))
{
ddrval = DDERR_INVALIDPARAMS;
goto execute_failed;
}
#endif
this->D3DStats.dwTrianglesDrawn += lpIns->wCount;
D3D_INFO(5, "Emulating D3DOP_TRIANGLE for HAL and clipping");
ddrval = D3DFEClipTrianglesHW(this, (LPD3DTRIANGLE)prim, lpIns->wCount);
if (ddrval != D3D_OK)
{
D3D_ERR("D3DFEClipTrianglesHW failed");
goto execute_failed;
}
NEXTINSTRUCTION(lpIns, D3DTRIANGLE, lpIns->wCount);
break;
case D3DOP_LINE:
if (lpIns->wCount == 0)
{
NEXTINSTRUCTION(lpIns, D3DLINE, lpIns->wCount);
break;
}
Profile(PROF_EXECUTE, D3DPT_LINELIST, GetVertexType(this));
WAIT_FOR_FLIP();
D3D_INFO(5, "Emulating D3DOP_LINE for HAL and clipping");
this->D3DStats.dwLinesDrawn += lpIns->wCount;
ddrval = D3DFEClipLinesHW(this, (LPD3DLINE)prim, lpIns->wCount);
if (ddrval != D3D_OK)
{
D3D_ERR("D3DFEClipLinesHW failed");
goto execute_failed;
}
NEXTINSTRUCTION(lpIns, D3DLINE, lpIns->wCount);
break;
case D3DOP_POINT:
WAIT_FOR_FLIP();
Profile(PROF_EXECUTE, D3DPT_POINTLIST, GetVertexType(this));
D3D_INFO(5, "Emulating D3DOP_POINT for HAL and clipping");
{
LPD3DPOINT point = (LPD3DPOINT) prim;
int i;
for (i = 0; i < lpIns->wCount; i++)
{
this->D3DStats.dwPointsDrawn += point->wCount;
point++;
}
}
if ((ddrval = D3DFEClipPointsHW(this, (LPD3DPOINT)prim, lpIns->wCount)) != D3D_OK)
{
D3D_ERR("Failed D3DFEClipPointsHW");
goto execute_failed;
}
NEXTINSTRUCTION(lpIns, D3DPOINT, lpIns->wCount);
break;
case D3DOP_SPAN:
{
LPD3DSPAN span = (LPD3DSPAN)prim;
D3DHAL_RENDERPRIMITIVEDATA primitiveData;
int i;
WAIT_FOR_FLIP();
memset(&primitiveData, 0, sizeof(D3DHAL_RENDERPRIMITIVEDATA));
primitiveData.dwhContext = this->dwhContext;
primitiveData.lpExeBuf = lpDDExeBuf;
primitiveData.dwTLOffset = 0L;
primitiveData.lpTLBuf = this->TLVbuf.GetDDS();
primitiveData.dwOffset = (DWORD)(prim - (LPBYTE) debDesc.lpData);
primitiveData.dwStatus = this->iClipStatus;
primitiveData.diInstruction = *lpIns;
#ifndef WIN95
if((ddrval = CheckContextSurfaceNOLOCK(this)) != D3D_OK)
goto execute_failed;
#endif //WIN95
CALL_HALONLY_NOLOCK(ddrval, this, RenderPrimitive,
&primitiveData);
if (primitiveData.ddrval != DD_OK)
{
D3D_ERR("HAL error in RenderPrimitive call from Execute API");
ddrval = primitiveData.ddrval;
goto execute_failed;
}
for (i = 0; i < lpIns->wCount; i++)
{
this->D3DStats.dwSpansDrawn += span->wCount;
span++;
}
this->iClipStatus = primitiveData.dwStatus;
lpIns = (LPD3DINSTRUCTION)((LPBYTE)lpIns
+ sizeof(D3DINSTRUCTION)
+ (lpIns->bSize * lpIns->wCount));
break;
}
default:
D3D_ERR("HAL detected invalid instruction opcode in Execute");
goto execute_failed;
}
ClampExtents(this);
}
}
}
execute_done:
ddrval = D3D_OK;
D3DFE_ConvertExtent(this, &this->rExtents, &lpExData->dsStatus.drExtent);
lpExData->dsStatus.dwStatus = this->iClipStatus;
execute_failed:
UNLOCK_HAL(this);
// Restore driver funcs
this->pfnDrawIndexedPrim = pfnOldDrawIndexedPrim;
this->pfnDrawPrim = pfnOldDrawPrim;
return ddrval;
}
//-------------------------------------------------------------------------------------------------
void TrackAllStates(LPDIRECT3DDEVICEI lpDevI, LPD3DINSTRUCTION lpIns, LPD3DINSTRUCTION lpEnd)
{
while (lpIns->bOpcode != D3DOP_EXIT && (lpEnd == NULL || lpIns < lpEnd))
{
LPBYTE prim = (LPBYTE)lpIns + sizeof(D3DINSTRUCTION);
switch (lpIns->bOpcode)
{
case D3DOP_MATRIXLOAD:
{
NEXTINSTRUCTION(lpIns, D3DMATRIXLOAD, lpIns->wCount);
break;
}
case D3DOP_MATRIXMULTIPLY:
{
NEXTINSTRUCTION(lpIns, D3DMATRIXMULTIPLY, lpIns->wCount);
break;
}
case D3DOP_PROCESSVERTICES:
{
NEXTINSTRUCTION(lpIns, D3DPROCESSVERTICES, lpIns->wCount);
break;
}
case D3DOP_STATETRANSFORM:
{
NEXTINSTRUCTION(lpIns, D3DSTATE, lpIns->wCount);
break;
}
case D3DOP_STATELIGHT:
{
NEXTINSTRUCTION(lpIns, D3DSTATE, lpIns->wCount);
break;
}
case D3DOP_BRANCHFORWARD:
{
D3DBRANCH* branch = (D3DBRANCH*)prim;
LPBYTE target;
BOOL isTaken = FALSE;
if (branch->bNegate)
{
if ((branch->dwMask & lpDevI->iClipStatus) != branch->dwValue)
{
if (branch->dwOffset)
{
isTaken = TRUE;
target = (LPBYTE)lpIns + branch->dwOffset;
}
else
{
D3D_INFO(5, "D3DOP_BRANCHFORWARD instruction: branch says to exit.");
break;
}
}
}
else
{
if ((branch->dwMask & lpDevI->iClipStatus) == branch->dwValue)
{
if (branch->dwOffset)
{
isTaken = TRUE;
target = (LPBYTE)lpIns + branch->dwOffset;
} else
{
break;
}
}
}
if (isTaken)
{
lpIns = (LPD3DINSTRUCTION) target;
}
else
{
NEXTINSTRUCTION(lpIns, D3DBRANCH, lpIns->wCount);
}
break;
}
case D3DOP_TEXTURELOAD:
{
NEXTINSTRUCTION(lpIns, D3DTEXTURELOAD, lpIns->wCount);
break;
}
case D3DOP_SETSTATUS:
{
NEXTINSTRUCTION(lpIns, D3DSTATUS, lpIns->wCount);
break;
}
case D3DOP_STATERENDER:
{
LPD3DSTATE lpState;
DWORD i,j,statek,valuek;
lpState = (LPD3DSTATE) (lpIns + 1);
for (i = 0,j=0,statek=(DWORD)-1; i < lpIns->wCount; i++)
{
trackState(lpDevI, &lpState[i]);
}
NEXTINSTRUCTION(lpIns, D3DSTATE, lpIns->wCount);
}
break;
case D3DOP_TRIANGLE:
NEXTINSTRUCTION(lpIns, D3DTRIANGLE, lpIns->wCount);
break;
case D3DOP_LINE:
NEXTINSTRUCTION(lpIns, D3DLINE, lpIns->wCount);
break;
case D3DOP_POINT:
NEXTINSTRUCTION(lpIns, D3DPOINT, lpIns->wCount);
break;
case D3DOP_SPAN:
// This case is NOOP since we do not implement spans in DP2 DDI
{
lpIns = (LPD3DINSTRUCTION)((LPBYTE)lpIns
+ sizeof(D3DINSTRUCTION)
+ (lpIns->bSize * lpIns->wCount));
break;
}
default:
D3D_ERR("Invalid instruction opcode in TrackAllStates");
break;
} // switch
} // while
}
//-------------------------------------------------------------------------------------------------
// New execute for DP2 HAL
//
HRESULT
CDirect3DDeviceIDP2::ExecuteI(LPD3DI_EXECUTEDATA lpExData, DWORD mode)
{
BOOL waitedForFlip = FALSE;
D3DINSTRUCTION* lpIns;
D3DEXECUTEBUFFERDESC debDesc;
LPDIRECTDRAWSURFACE lpDDS = this->lpDDSTarget;
LPBYTE prim;
D3DFE_TRANSFORM *transform = &this->transform;
LPDIRECTDRAWSURFACE lpDDExeBuf;
HRESULT ddrval, dp2dataddrval;
CHECKLOST(this);
/* Update textures */
UpdateTextures();
if (mode == D3DEXECUTE_UNCLIPPED)
this->dwFlags |= D3DDP_DONOTCLIP;
else if (mode != D3DEXECUTE_CLIPPED)
return DDERR_INVALIDPARAMS;
/*
* If the driver can process triangles while the hardware has a
* pending page-flip such as the 3Dfx voodoo chipset, then we
* don't need to call WaitForFlip. We pretend that it has already
* been called to keep the code simple.
*/
if (this->lpD3DHALGlobalDriverData->hwCaps.dwDevCaps &
D3DDEVCAPS_CANRENDERAFTERFLIP)
{
waitedForFlip = TRUE;
}
/*
* Lock the HAL for the duration.
*/
LOCK_HAL(ddrval, this);
if (ddrval != DD_OK)
{
D3D_ERR("Failed to lock HAL in Execute");
return (ddrval);
}
/*
* Execute the buffer through the HAL
*/
LPD3DHAL_EXDATA hexData = (LPD3DHAL_EXDATA) lpExData->dwHandle;
debDesc.lpData = SURFACE_MEMORY(hexData->lpDDS);
lpDDExeBuf = hexData->lpDDS;
/*
* The first instruction.
*/
lpIns = (LPD3DINSTRUCTION)((LPBYTE)debDesc.lpData +
lpExData->dwInstructionOffset);
// Fill up common part of dp2Data
this->dp2data.dwVertexType = D3DFVF_TLVERTEX;
this->dp2data.dwVertexSize = sizeof(D3DTLVERTEX);
this->dp2data.dwVertexOffset = 0;
ddrval = GrowTLandHbuffers(this, lpExData->dwVertexCount);
if (ddrval != D3D_OK)
goto execute_failed;
this->dwOutputSize = sizeof(D3DTLVERTEX);
// Start new primitive batch
ddrval= StartPrimVB(this->TLVbuf.GetVBI(), 0);
if (ddrval != D3D_OK)
{
UNLOCK_HAL(this);
D3D_ERR("Failed to start new primitve batch in Execute");
return ddrval;
}
// Since many legacy apps do not bother to set the dwVertexLength correctly, we estimate
// the vertex length here to be thse size of buffer allocated. This atleast guarantees
// that the memory is valid. It may still contain garbage data which the driver needs
// to protect itself from
this->dp2data.dwVertexLength = this->TLVbuf.GetSize() >> 5; // divide by sizeof(D3DTLVERTEX)
this->ClipperState.lpDDExeBuf = lpDDExeBuf;
this->ClipperState.lpvExeBufMem = debDesc.lpData;
while (lpIns->bOpcode != D3DOP_EXIT)
{
prim = (LPBYTE)lpIns + sizeof(D3DINSTRUCTION);
D3D_INFO(5, "HAL parsing instruction %d", lpIns->bOpcode);
/*
* Parse the instruction.
*/
switch (lpIns->bOpcode)
{
case D3DOP_MATRIXLOAD:
{
D3D_INFO(5, "Emulating D3DOP_MATRIXLOAD for HAL");
ddrval = D3DHELInst_D3DOP_MATRIXLOAD(this,
lpIns->wCount,
(LPD3DMATRIXLOAD)prim);
if (ddrval != D3D_OK)
{
D3D_ERR("Emulated D3DOP_MATRIXLOAD failed.");
goto execute_failed;
}
NEXTINSTRUCTION(lpIns, D3DMATRIXLOAD, lpIns->wCount);
break;
}
case D3DOP_MATRIXMULTIPLY:
{
D3D_INFO(5, "Emulating D3DOP_MATRIXMULTIPLY for HAL");
ddrval = D3DHELInst_D3DOP_MATRIXMULTIPLY(this,
lpIns->wCount,
(LPD3DMATRIXMULTIPLY)prim);
if (ddrval != D3D_OK)
{
D3D_ERR("Emulated D3DOP_MATRIXMULTIPLY failed.");
goto execute_failed;
}
NEXTINSTRUCTION(lpIns, D3DMATRIXMULTIPLY, lpIns->wCount);
break;
}
case D3DOP_PROCESSVERTICES:
{
D3D_INFO(5, "Emulating D3DOP_PROCESSVERTICES for HAL");
ddrval = D3DHELInst_D3DOP_TRANSFORM
(this, lpIns->wCount, (LPD3DPROCESSVERTICES)prim,
&debDesc);
if (ddrval != D3D_OK)
{
D3D_ERR("Emulated D3DOP_PROCESSVERTICES failed.");
goto execute_failed;
}
NEXTINSTRUCTION(lpIns, D3DPROCESSVERTICES, lpIns->wCount);
break;
}
case D3DOP_STATETRANSFORM:
{
D3D_INFO(5, "Emulating D3DOP_STATETRANSFORM for HAL");
ddrval = D3DHELInst_D3DOP_STATETRANSFORM(this,
lpIns->wCount,
(LPD3DSTATE)prim);
if (ddrval != D3D_OK)
{
D3D_ERR("Emulated D3DOP_STATETRANSFORM failed.");
goto execute_failed;
}
NEXTINSTRUCTION(lpIns, D3DSTATE, lpIns->wCount);
break;
}
case D3DOP_STATELIGHT:
{
D3D_INFO(5, "Emulating D3DOP_STATELIGHT for HAL");
ddrval = D3DHELInst_D3DOP_STATELIGHT(this,
lpIns->wCount,
(LPD3DSTATE)prim);
if (ddrval != D3D_OK) {
D3D_ERR("Emulated D3DOP_STATELIGHT failed.");
goto execute_failed;
}
NEXTINSTRUCTION(lpIns, D3DSTATE, lpIns->wCount);
break;
}
case D3DOP_BRANCHFORWARD:
{
D3DBRANCH* branch = (D3DBRANCH*)prim;
LPBYTE target;
BOOL isTaken = FALSE;
D3D_INFO(5, "Emulating D3DOP_BRANCHFORWARD");
if (branch->bNegate)
{
if ((branch->dwMask & this->iClipStatus) != branch->dwValue)
{
D3D_INFO(5, "D3DOP_BRANCHFORWARD instruction: Taking forward branch");
if (branch->dwOffset)
{
isTaken = TRUE;
target = (LPBYTE)lpIns + branch->dwOffset;
}
else
{
D3D_INFO(5, "D3DOP_BRANCHFORWARD instruction: branch says to exit.");
goto execute_done;
}
}
}
else
{
D3D_INFO(5, "dwMask = %lx, iClipStatus = %lx, dwValue = %lx", branch->dwMask, this->iClipStatus, branch->dwValue);
if ((branch->dwMask & this->iClipStatus) == branch->dwValue)
{
D3D_INFO(5, "D3DOP_BRANCHFORWARD instruction: Taking forward branch");
if (branch->dwOffset)
{
isTaken = TRUE;
target = (LPBYTE)lpIns + branch->dwOffset;
} else
{
D3D_INFO(5, "D3DOP_BRANCHFORWARD instruction: branch says to exit.");
goto execute_done;
}
}
}
if (isTaken)
{
D3D_INFO(5, "D3DOP_BRANCHFORWARD instruction: branch taken");
lpIns = (LPD3DINSTRUCTION) target;
}
else
{
D3D_INFO(5, "D3DOP_BRANCHFORWARD instruction: branch not taken");
NEXTINSTRUCTION(lpIns, D3DBRANCH, lpIns->wCount);
}
break;
}
case D3DOP_TEXTURELOAD:
{
D3D_INFO(5, "Emulating D3DOP_TEXTURELOAD for HAL");
ddrval = D3DHELInst_D3DOP_TEXTURELOAD(this,
lpIns->wCount,
(LPD3DTEXTURELOAD)prim);
if (ddrval != D3D_OK)
{
D3D_ERR("Emulated D3DOP_TEXTURELOAD failed.");
goto execute_failed;
}
NEXTINSTRUCTION(lpIns, D3DTEXTURELOAD, lpIns->wCount);
break;
}
case D3DOP_SETSTATUS:
{
LPD3DSTATUS status = (LPD3DSTATUS)prim;
if (status->dwFlags & D3DSETSTATUS_STATUS)
this->iClipStatus = status->dwStatus;
if (status->dwFlags & D3DSETSTATUS_EXTENTS)
{
this->rExtents.x1 = D3DVAL(status->drExtent.x1);
this->rExtents.y1 = D3DVAL(status->drExtent.y1);
this->rExtents.x2 = D3DVAL(status->drExtent.x2);
this->rExtents.y2 = D3DVAL(status->drExtent.y2);
}
NEXTINSTRUCTION(lpIns, D3DSTATUS, lpIns->wCount);
break;
}
default:
if ((this->dwFEFlags & D3DFE_TLVERTEX) || (mode == D3DEXECUTE_UNCLIPPED))
{
switch (lpIns->bOpcode)
{
case D3DOP_STATERENDER:
case D3DOP_POINT:
case D3DOP_LINE:
case D3DOP_SPAN:
// ATTENTION
// We need to disallow SPAN from going through since the new DDI spec
// does not account for spans. We probably want to deprecate spans in
// any case so them being slower might not be too bad. Right now, though
// we are passing them to the driver.
case D3DOP_TRIANGLE:
#if DBG
switch (lpIns->bOpcode)
{
case D3DOP_POINT:
Profile(PROF_EXECUTE, D3DPT_POINTLIST, GetVertexType(this));
break;
case D3DOP_LINE:
Profile(PROF_EXECUTE, D3DPT_LINELIST, GetVertexType(this));
break;
case D3DOP_TRIANGLE:
Profile(PROF_EXECUTE, D3DPT_TRIANGLELIST, GetVertexType(this));
break;
}
#endif // DBG
if (lpIns->wCount == 0)
{
lpIns = (LPD3DINSTRUCTION)((LPBYTE)lpIns +
sizeof(D3DINSTRUCTION) +
(lpIns->bSize * lpIns->wCount));
break;
}
if (!waitedForFlip)
{
WaitForFlip(lpDDS);
waitedForFlip = TRUE;
}
this->dp2data.dwVertexType = D3DFVF_TLVERTEX;
this->dp2data.dwVertexSize = sizeof(D3DTLVERTEX);
this->dp2data.lpDDCommands = ((LPDDRAWI_DDRAWSURFACE_INT)lpDDExeBuf)->lpLcl;
this->dp2data.dwCommandOffset = (DWORD)((LPBYTE)lpIns - (LPBYTE) debDesc.lpData);
this->dp2data.dwCommandLength = lpExData->dwInstructionOffset + lpExData->dwInstructionLength -
this->dp2data.dwCommandOffset;
// Can't swap command buffer in this case
this->dp2data.dwFlags &= ~(D3DHALDP2_SWAPCOMMANDBUFFER | D3DHALDP2_SWAPVERTEXBUFFER);
this->dp2data.lpdwRStates = this->rstates;
#ifndef WIN95
if (!IS_DX7HAL_DEVICE(this))
{
if((ddrval = CheckContextSurfaceNOLOCK (this)) != D3D_OK)
{
goto execute_failed;
}
}
#endif //WIN95
// and tell driver to update lpdwRStates
this->dp2data.dwFlags |= D3DHALDP2_EXECUTEBUFFER;
// Spin waiting on the driver
do {
CALL_HAL3ONLY_NOLOCK(ddrval, this, DrawPrimitives2, &this->dp2data);
if (ddrval != DDHAL_DRIVER_HANDLED)
{
D3D_ERR ( "Driver not handled in DrawPrimitives2" );
// Need sensible return value in this case,
// currently we return whatever the driver stuck in here.
goto execute_failed;
}
} while (dp2data.ddrval == DDERR_WASSTILLDRAWING);
// restore right value of dwVertexSize as it is a union with ddrval
dp2dataddrval = this->dp2data.ddrval;
#if _WIN32_WINNT >= 0x0501
this->dp2data.dwVertexSize = sizeof(D3DTLVERTEX);
#endif
// clear this bit in case drawprimitive calls after this
this->dp2data.dwFlags &= ~D3DHALDP2_EXECUTEBUFFER;
if (dp2dataddrval != DD_OK)
{
if (dp2dataddrval == D3DERR_COMMAND_UNPARSED)
{
LPD3DINSTRUCTION lpStart = lpIns;
lpIns = (LPD3DINSTRUCTION)(this->dp2data.dwErrorOffset + (LPBYTE)debDesc.lpData);
TrackAllStates(this, lpStart, lpIns);
break; // Continue parsing
}
else
{
D3D_ERR("HAL error in DrawPrimitives2 call from Execute API");
ddrval = dp2dataddrval;
goto execute_failed;
}
}
else
{
TrackAllStates(this, lpIns, NULL);
goto execute_done;
}
default:
D3D_ERR("HAL detected invalid instruction opcode in Execute");
goto execute_failed;
} // switch
} // if unclipped
else
{ // Execute Clipped
switch (lpIns->bOpcode)
{
case D3DOP_STATERENDER:
// We do not track state. This means GetRenderState needs a DDI to
// work. More importantly, state overrides will get ignored. To fix
// this, the ParseUnknownCommand function needs to be called by the
// driver if it cannot understand the state change value.
// This function should examine if the renderstate had an override,
// and if so, inform the driver to request the runtime to parse the EB
{
LPD3DSTATE lpState;
DWORD i,j,statek,valuek;
lpState = (LPD3DSTATE) (lpIns + 1);
for (i = 0,j=0,statek=(DWORD)-1; i < lpIns->wCount; i++)
{
// This call also calls SetDeviceRenderState which
// is not required. But this is an optimization which
// can wait till later (if required)
if (trackState(this, &lpState[i]))
this->SetRenderStateI(lpState[i].drstRenderStateType, lpState[i].dwArg[0]);
}
NEXTINSTRUCTION(lpIns, D3DSTATE, lpIns->wCount);
}
break;
case D3DOP_TRIANGLE:
if (lpIns->wCount == 0)
{
NEXTINSTRUCTION(lpIns, D3DTRIANGLE, lpIns->wCount);
break;
}
Profile(PROF_EXECUTE, D3DPT_TRIANGLELIST, GetVertexType(this));
WAIT_FOR_FLIP();
#if DBG
if (!validateTriangleFlags(lpIns, (LPD3DTRIANGLE) prim))
{
ddrval = DDERR_INVALIDPARAMS;
goto execute_failed;
}
#endif
this->D3DStats.dwTrianglesDrawn += lpIns->wCount;
D3D_INFO(5, "Emulating D3DOP_TRIANGLE for HAL and clipping");
if (this->rstates[D3DRENDERSTATE_ZVISIBLE])
{
this->iClipStatus &= ~D3DSTATUS_ZNOTVISIBLE;
}
else
{
ddrval = D3DFEClipTrianglesHW(this, (LPD3DTRIANGLE)prim, lpIns->wCount);
if (ddrval != D3D_OK)
{
D3D_ERR("D3DFEClipLinesHW failed");
goto execute_failed;
}
}
NEXTINSTRUCTION(lpIns, D3DTRIANGLE, lpIns->wCount);
break;
case D3DOP_LINE:
if (lpIns->wCount == 0)
{
NEXTINSTRUCTION(lpIns, D3DLINE, lpIns->wCount);
break;
}
Profile(PROF_EXECUTE, D3DPT_LINELIST, GetVertexType(this));
WAIT_FOR_FLIP();
D3D_INFO(5, "Emulating D3DOP_LINE for HAL and clipping");
this->D3DStats.dwLinesDrawn += lpIns->wCount;
if (this->rstates[D3DRENDERSTATE_ZVISIBLE])
{
this->iClipStatus &= ~D3DSTATUS_ZNOTVISIBLE;
}
else
{
ddrval = D3DFEClipLinesHW(this, (LPD3DLINE)prim, lpIns->wCount);
if (ddrval != D3D_OK)
{
D3D_ERR("D3DFEClipLinesHW failed");
goto execute_failed;
}
}
NEXTINSTRUCTION(lpIns, D3DLINE, lpIns->wCount);
break;
case D3DOP_POINT:
WAIT_FOR_FLIP();
Profile(PROF_EXECUTE, D3DPT_POINTLIST, GetVertexType(this));
D3D_INFO(5, "Emulating D3DOP_POINT for HAL and clipping");
{
LPD3DPOINT point = (LPD3DPOINT) prim;
int i;
for (i = 0; i < lpIns->wCount; i++)
{
this->D3DStats.dwPointsDrawn += point->wCount;
point++;
}
}
if (this->rstates[D3DRENDERSTATE_ZVISIBLE])
{
this->iClipStatus &= ~D3DSTATUS_ZNOTVISIBLE;
}
else
{
ddrval = D3DFEClipPointsHW(this, (LPD3DPOINT)prim, lpIns->wCount);
if (ddrval != D3D_OK)
{
D3D_ERR("D3DFEClipPointsHW failed");
goto execute_failed;
}
}
NEXTINSTRUCTION(lpIns, D3DPOINT, lpIns->wCount);
break;
case D3DOP_SPAN:
// This case is NOOP since we do not implement spans in DP2 DDI
{
lpIns = (LPD3DINSTRUCTION)((LPBYTE)lpIns
+ sizeof(D3DINSTRUCTION)
+ (lpIns->bSize * lpIns->wCount));
break;
}
default:
D3D_ERR("HAL detected invalid instruction opcode in Execute");
goto execute_failed;
} // switch
ClampExtents(this);
} // Execute Clipped
} // switch
} // while
execute_done:
D3DFE_ConvertExtent(this, &this->rExtents, &lpExData->dsStatus.drExtent);
lpExData->dsStatus.dwStatus = this->iClipStatus;
ddrval = D3D_OK;
execute_failed:
// Restore Command Buffer in case of Unclipped EB
if ((this->dwFEFlags & D3DFE_TLVERTEX) || (mode == D3DEXECUTE_UNCLIPPED))
{
this->dp2data.lpDDCommands = ((LPDDRAWI_DDRAWSURFACE_INT)this->lpDDSCB1)->lpLcl;
this->dp2data.dwCommandOffset = 0;
this->dp2data.dwCommandLength = 0;
this->dp2data.dwFlags |= D3DHALDP2_SWAPCOMMANDBUFFER;
}
this->dwFlags &= ~D3DPV_WITHINPRIMITIVE;
UNLOCK_HAL(this);
return ddrval;
#undef WAIT_FOR_FLIP
}
//---------------------------------------------------------------------
HRESULT D3DHAL_ExecutePick(LPDIRECT3DDEVICEI lpDevI,
LPD3DI_PICKDATA lpPickData)
{
LPD3DI_EXECUTEDATA lpExData = lpPickData->exe;
D3DRECT* pick_rect = &lpPickData->pick;
D3DINSTRUCTION* lpIns;
D3DEXECUTEBUFFERDESC debDesc;
LPBYTE prim;
LPD3DDEVICEDESC_V1 halCaps = &lpDevI->lpD3DHALGlobalDriverData->hwCaps;
BOOL bMustDoTransform = halCaps->dwFlags & D3DDD_TRANSFORMCAPS;
D3DI_PICKDATA* pdata = &lpDevI->pick_data;
LPDIRECTDRAWSURFACE lpDDExeBuf;
HRESULT ddrval;
D3DFE_TRANSFORM *transform = &lpDevI->transform;
DWORD i;
LPD3DSTATE lpState;
D3D_INFO(3, "ExecutePick called.%d");
/*
* Clear all the old pick records.
*/
pdata->pick_count = 0;
if (pdata->records)
D3DFree(pdata->records);
pdata->records = NULL;
//Flush the cached states
ddrval = lpDevI->FlushStates();
if (ddrval != D3D_OK)
{
D3D_ERR("Error trying to render batched commands in D3DHAL_ExecutePick");
return ddrval;
}
// Grow internal buffers to hold vertices
ddrval = lpDevI->TLVbuf.CheckAndGrow
(lpDevI, lpDevI->lpD3DHALGlobalDriverData->hwCaps.dwMaxVertexCount << 5);
if (ddrval != D3D_OK)
{
D3D_ERR("Failed to check and grow TLVbuf in ExecutePick");
return ddrval;
}
ddrval = lpDevI->HVbuf.CheckAndGrow
(lpDevI->lpD3DHALGlobalDriverData->hwCaps.dwMaxVertexCount*sizeof(D3DFE_CLIPCODE));
if (ddrval != D3D_OK)
{
D3D_ERR("Failed to check and grow HVbuf in ExecutePick");
return ddrval;
}
/*
* Execute the buffer through the HAL
*/
D3D_INFO(4, "Locking execute buffer for execution");
memset(&debDesc, 0, sizeof(D3DEXECUTEBUFFERDESC));
debDesc.dwSize = sizeof(D3DEXECUTEBUFFERDESC);
ddrval = D3DHAL_LockBuffer(lpDevI, lpExData->dwHandle, &debDesc, &lpDDExeBuf);
CHECK(ddrval, "Lock of execute buffer for execution failed");
// Modify driver funcs for EB pick case
PFN_DRAWPRIM pfnOldDrawPrim = lpDevI->pfnDrawPrim;
PFN_DRAWPRIM pfnOldDrawIndexedPrim = lpDevI->pfnDrawIndexedPrim;
lpDevI->pfnDrawPrim = &DIRECT3DDEVICEI::PickExeBuf;
lpDevI->pfnDrawIndexedPrim = &DIRECT3DDEVICEI::PickExeBuf;
/*
* Calculate the instruction that could not be handled.
*/
lpIns = (LPD3DINSTRUCTION)((LPBYTE)debDesc.lpData + lpExData->dwInstructionOffset);
lpDevI->lpbClipIns_base = (unsigned char*)lpIns;
while (lpIns->bOpcode != D3DOP_EXIT)
{
prim = (LPBYTE)(lpIns + 1);
/*
* Parse the instruction, passing rasterisation calls to HAL.
*/
switch (lpIns->bOpcode)
{
/*
* Instructions that must be emulated.
*/
case D3DOP_MATRIXLOAD:
D3D_INFO(5, "Emulating D3DOP_MATRIXLOAD for HAL");
ddrval = D3DHELInst_D3DOP_MATRIXLOAD(lpDevI,
lpIns->wCount,
(LPD3DMATRIXLOAD)prim);
if (ddrval != D3D_OK)
{
D3D_ERR("Emulated D3DOP_MATRIXLOAD failed.");
goto executePick_failed;
}
NEXTINSTRUCTION(lpIns, D3DMATRIXLOAD, lpIns->wCount);
break;
case D3DOP_MATRIXMULTIPLY:
D3D_INFO(5, "Emulating D3DOP_MATRIXMULTIPLY for HAL");
ddrval = D3DHELInst_D3DOP_MATRIXMULTIPLY(lpDevI,
lpIns->wCount,
(LPD3DMATRIXMULTIPLY)prim);
if (ddrval != D3D_OK)
{
D3D_ERR("Emulated D3DOP_MATRIXMULTIPLY failed.");
goto executePick_failed;
}
NEXTINSTRUCTION(lpIns, D3DMATRIXMULTIPLY, lpIns->wCount);
break;
case D3DOP_STATERENDER:
lpState = (LPD3DSTATE) (lpIns + 1);
{
D3DHAL_RENDERSTATEDATA stateData;
DWORD j,statek,valuek;
stateData.dwhContext = lpDevI->dwhContext;
stateData.lpExeBuf = lpDDExeBuf;
stateData.dwOffset = (DWORD)((ULONG_PTR)lpIns - (ULONG_PTR)debDesc.lpData +
sizeof(D3DINSTRUCTION));
stateData.dwCount = lpIns->wCount;
CALL_HALONLY(ddrval, lpDevI, RenderState, &stateData);
if (stateData.ddrval != DD_OK)
{
D3D_ERR("HAL error in RenderState call from ExecutePick API");
ddrval = stateData.ddrval;
goto executePick_failed;
}
}
for (i = 0; i < lpIns->wCount; i++)
{
trackState(lpDevI, &lpState[i]);
}
NEXTINSTRUCTION(lpIns, D3DSTATE, lpIns->wCount);
break;
case D3DOP_STATETRANSFORM:
D3D_INFO(5, "Emulating D3DOP_STATETRANSFORM for HAL");
ddrval = D3DHELInst_D3DOP_STATETRANSFORM(lpDevI, lpIns->wCount,
(LPD3DSTATE)prim);
if (ddrval != D3D_OK)
{
D3D_ERR("Emulated D3DOP_STATETRANSFORM failed.");
goto executePick_failed;
}
NEXTINSTRUCTION(lpIns, D3DSTATE, lpIns->wCount);
break;
/*
* Operations that require clipping.
*/
case D3DOP_PROCESSVERTICES:
D3D_INFO(5, "Emulating D3DOP_PROCESSVERTICES for HAL and clipping");
ddrval = D3DHELInst_D3DOP_TRANSFORM
(lpDevI, lpIns->wCount, (LPD3DPROCESSVERTICES)prim, &debDesc);
if (ddrval != D3D_OK)
{
D3D_ERR("Emulated D3DOP_PROCESSVERTICES failed.");
goto executePick_failed;
}
NEXTINSTRUCTION(lpIns, D3DPROCESSVERTICES, lpIns->wCount);
break;
case D3DOP_TRIANGLE:
if (!lpDevI->rstates[D3DRENDERSTATE_ZVISIBLE])
{
D3D_INFO(5, "Picking D3DOP_TRIANGLE for HAL and clipping");
lpDevI->pick_data.pick = *pick_rect;
HRESULT ret;
if (lpDevI->dwFEFlags & D3DFE_TLVERTEX)
{
lpDevI->primType = D3DPT_TRIANGLELIST;
lpDevI->dwNumIndices = lpIns->wCount * 3;
lpDevI->dwNumPrimitives = lpIns->wCount;
lpDevI->lpvOut = lpDevI->TLVbuf.GetAddress();
lpDevI->lpwIndices = (WORD*)prim;
ret = lpDevI->PickExeBuf();
}
else
ret = GenPickTriangles(lpDevI, (LPD3DTRIANGLE)prim, lpIns->wCount);
if (ret != D3D_OK)
goto executePick_failed;
}
NEXTINSTRUCTION(lpIns, D3DTRIANGLE, lpIns->wCount);
break;
case D3DOP_SETSTATUS:
{
LPD3DSTATUS status = (LPD3DSTATUS)prim;
if (status->dwFlags & D3DSETSTATUS_STATUS)
lpDevI->iClipStatus = status->dwStatus;
if (status->dwFlags & D3DSETSTATUS_EXTENTS)
{
lpDevI->rExtents.x1 = D3DVAL(status->drExtent.x1);
lpDevI->rExtents.y1 = D3DVAL(status->drExtent.y1);
lpDevI->rExtents.x2 = D3DVAL(status->drExtent.x2);
lpDevI->rExtents.y2 = D3DVAL(status->drExtent.y2);
}
}
NEXTINSTRUCTION(lpIns, D3DSTATUS, lpIns->wCount);
break;
case D3DOP_BRANCHFORWARD:
{
D3DBRANCH* branch = (D3DBRANCH*)prim;
LPBYTE target;
BOOL isTaken = FALSE;
D3D_INFO(5, "Emulating D3DOP_BRANCHFORWARD for HAL.");
if (branch->bNegate)
{
if ((branch->dwMask & lpDevI->iClipStatus) != branch->dwValue)
{
D3D_INFO(5, "D3DOP_BRANCHFORWARD instruction: Taking forward branch");
if (branch->dwOffset)
{
isTaken = TRUE;
target = (LPBYTE)lpIns + branch->dwOffset;
} else
goto early_out;
}
}
else
{
if ((branch->dwMask & lpDevI->iClipStatus) == branch->dwValue)
{
D3D_INFO(5, "D3DOP_BRANCHFORWARD instruction: Taking forward branch");
if (branch->dwOffset)
{
isTaken = TRUE;
target = (LPBYTE)lpIns + branch->dwOffset;
}
else
goto early_out;
}
}
if (isTaken)
lpIns = (LPD3DINSTRUCTION)target;
else
{
NEXTINSTRUCTION(lpIns, D3DBRANCH, lpIns->wCount);
}
}
break;
default:
D3D_INFO(4, "Skipping instruction %d in ExecutePick",
lpIns->bOpcode);
lpIns = (LPD3DINSTRUCTION)((LPBYTE)lpIns +
sizeof(D3DINSTRUCTION) +
(lpIns->wCount * lpIns->bSize));
break;
}
}
early_out:
D3DHAL_UnlockBuffer(lpDevI, lpExData->dwHandle);
D3DFE_ConvertExtent(lpDevI, &lpDevI->rExtents, &lpExData->dsStatus.drExtent);
lpExData->dsStatus.dwStatus = lpDevI->iClipStatus;
// Restore driver funcs
lpDevI->pfnDrawIndexedPrim = pfnOldDrawIndexedPrim;
lpDevI->pfnDrawPrim = pfnOldDrawPrim;
return (D3D_OK);
executePick_failed:
D3D_ERR("ExecutePick Failed.");
D3DHAL_UnlockBuffer(lpDevI, lpExData->dwHandle);
// Restore driver funcs
lpDevI->pfnDrawIndexedPrim = pfnOldDrawIndexedPrim;
lpDevI->pfnDrawPrim = pfnOldDrawPrim;
return ddrval;
}