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
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;
|
|
}
|