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.
1979 lines
71 KiB
1979 lines
71 KiB
/*==========================================================================;
|
|
*
|
|
* Copyright (C) 1995 Microsoft Corporation. All Rights Reserved.
|
|
*
|
|
* File: vertbuf.cpp
|
|
* Content: Direct3DVertexBuffer implementation
|
|
*@@BEGIN_MSINTERNAL
|
|
*
|
|
* History:
|
|
* Date By Reason
|
|
* ==== == ======
|
|
*@@END_MSINTERNAL
|
|
*
|
|
***************************************************************************/
|
|
|
|
#include "pch.cpp"
|
|
#pragma hdrstop
|
|
#include "drawprim.hpp"
|
|
#include "d3dfei.h"
|
|
#include "clipfunc.h"
|
|
#include "pvvid.h"
|
|
|
|
// The bit is set when a vertex buffer was the destination in a ProcessVerticesCall
|
|
// with clipping enabled. We cannot pass such a buffer to TL HAL, because some vertices
|
|
// could be in the screen space and some in the clipping space. There is no DDI to pass
|
|
// clip codes together with a vertex buffer
|
|
const DWORD D3DPV_CLIPCODESGENERATED = D3DPV_RESERVED2;
|
|
|
|
const DWORD D3DVOP_RENDER = 1 << 31;
|
|
const DWORD D3DVBCAPS_VALID = D3DVBCAPS_SYSTEMMEMORY |
|
|
D3DVBCAPS_WRITEONLY |
|
|
D3DVBCAPS_OPTIMIZED |
|
|
D3DVBCAPS_DONOTCLIP;
|
|
|
|
void hookVertexBufferToD3D(LPDIRECT3DI lpDirect3DI,
|
|
LPDIRECT3DVERTEXBUFFERI lpVBufI)
|
|
{
|
|
|
|
LIST_INSERT_ROOT(&lpDirect3DI->vbufs, lpVBufI, list);
|
|
lpVBufI->lpDirect3DI = lpDirect3DI;
|
|
|
|
lpDirect3DI->numVBufs++;
|
|
}
|
|
|
|
/*
|
|
* Direct3DVertexBuffer::QueryInterface
|
|
*/
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "Direct3DVertexBuffer::QueryInterface"
|
|
|
|
HRESULT D3DAPI CDirect3DVertexBuffer::QueryInterface(REFIID riid, LPVOID* ppvObj)
|
|
{
|
|
CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock.
|
|
#if DBG
|
|
if (!VALID_DIRECT3DVERTEXBUFFER_PTR(this)) {
|
|
D3D_ERR( "Invalid Direct3DVertexBuffer pointer" );
|
|
return DDERR_INVALIDOBJECT;
|
|
}
|
|
if (!VALID_OUTPTR(ppvObj)) {
|
|
D3D_ERR( "Invalid pointer to pointer" );
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
#endif
|
|
*ppvObj = NULL;
|
|
if(IsEqualIID(riid, IID_IUnknown) ||
|
|
IsEqualIID(riid, IID_IDirect3DVertexBuffer7))
|
|
{
|
|
AddRef();
|
|
*ppvObj = static_cast<LPVOID>(static_cast<LPDIRECT3DVERTEXBUFFER7>(this));
|
|
return(D3D_OK);
|
|
}
|
|
else
|
|
{
|
|
D3D_ERR( "Don't know this riid" );
|
|
return (E_NOINTERFACE);
|
|
}
|
|
} /* CDirect3DVertexBuffer::QueryInterface */
|
|
|
|
/*
|
|
* Direct3DVertexBuffer::AddRef
|
|
*/
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "Direct3DVertexBuffer::AddRef"
|
|
|
|
ULONG D3DAPI CDirect3DVertexBuffer::AddRef()
|
|
{
|
|
DWORD rcnt;
|
|
|
|
CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock.
|
|
#if DBG
|
|
if (!VALID_DIRECT3DVERTEXBUFFER_PTR(this))
|
|
{
|
|
D3D_ERR( "Invalid Direct3DVertexBuffer pointer" );
|
|
return 0;
|
|
}
|
|
#endif
|
|
this->refCnt++;
|
|
rcnt = this->refCnt;
|
|
|
|
return (rcnt);
|
|
|
|
} /* Direct3DVertexBuffer::AddRef */
|
|
|
|
/*
|
|
* Direct3DVertexBuffer::Release
|
|
*
|
|
*/
|
|
//---------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "Direct3DVertexBuffer::Release"
|
|
|
|
ULONG D3DAPI CDirect3DVertexBuffer::Release()
|
|
{
|
|
DWORD lastrefcnt;
|
|
|
|
CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock.
|
|
#if DBG
|
|
if (!VALID_DIRECT3DVERTEXBUFFER_PTR(this))
|
|
{
|
|
D3D_ERR( "Invalid Direct3DVertexBuffer pointer" );
|
|
return 0;
|
|
}
|
|
#endif
|
|
/*
|
|
* decrement the ref count. if we hit 0, free the object
|
|
*/
|
|
this->refCnt--;
|
|
lastrefcnt = this->refCnt;
|
|
|
|
if( lastrefcnt == 0 )
|
|
{
|
|
delete this;
|
|
return 0;
|
|
}
|
|
|
|
return lastrefcnt;
|
|
|
|
} /* D3DTex3_Release */
|
|
//---------------------------------------------------------------------
|
|
// Internal version.
|
|
// No D3D lock, no checks
|
|
//
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "DIRECT3DI::CreateVertexBufferI"
|
|
|
|
HRESULT DIRECT3DI::CreateVertexBufferI(LPD3DVERTEXBUFFERDESC lpDesc,
|
|
LPDIRECT3DVERTEXBUFFER7 *lplpVBuf,
|
|
DWORD dwFlags)
|
|
{
|
|
CDirect3DVertexBuffer* lpVBufI;
|
|
HRESULT ret = D3D_OK;
|
|
|
|
*lplpVBuf = NULL;
|
|
|
|
lpVBufI = static_cast<LPDIRECT3DVERTEXBUFFERI>(new CDirect3DVertexBuffer(this));
|
|
if (!lpVBufI) {
|
|
D3D_ERR("failed to allocate space for vertex buffer");
|
|
return (DDERR_OUTOFMEMORY);
|
|
}
|
|
|
|
if ((ret=lpVBufI->Init(this, lpDesc, dwFlags))!=D3D_OK)
|
|
{
|
|
D3D_ERR("Failed to initialize the vertex buffer object");
|
|
delete lpVBufI;
|
|
return ret;
|
|
}
|
|
*lplpVBuf = (LPDIRECT3DVERTEXBUFFER7)lpVBufI;
|
|
|
|
return(D3D_OK);
|
|
}
|
|
//---------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "DIRECT3DI::CreateVertexBuffer"
|
|
|
|
HRESULT D3DAPI DIRECT3DI::CreateVertexBuffer(
|
|
LPD3DVERTEXBUFFERDESC lpDesc,
|
|
LPDIRECT3DVERTEXBUFFER7* lplpVBuf,
|
|
DWORD dwFlags)
|
|
{
|
|
CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock.
|
|
#if DBG
|
|
/*
|
|
* validate parms
|
|
*/
|
|
if (!VALID_DIRECT3D_PTR(this))
|
|
{
|
|
D3D_ERR( "Invalid Direct3D pointer" );
|
|
return DDERR_INVALIDOBJECT;
|
|
}
|
|
if (!VALID_OUTPTR(lplpVBuf))
|
|
{
|
|
D3D_ERR( "Invalid pointer to pointer pointer" );
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
if ((lpDesc->dwCaps & D3DVBCAPS_VALID) != lpDesc->dwCaps)
|
|
{
|
|
D3D_ERR("Invalid caps");
|
|
return DDERR_INVALIDCAPS;
|
|
}
|
|
if (dwFlags != 0)
|
|
{
|
|
D3D_ERR("Invalid dwFlags");
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
#endif
|
|
return CreateVertexBufferI(lpDesc, lplpVBuf, dwFlags);
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "Direct3DVertexBuffer::constructor"
|
|
|
|
CDirect3DVertexBuffer::CDirect3DVertexBuffer(LPDIRECT3DI lpD3DI)
|
|
{
|
|
refCnt = 1;
|
|
/*
|
|
* Put this vertex buffer in the list of those owned by the
|
|
* Direct3D object
|
|
*/
|
|
hookVertexBufferToD3D(lpD3DI, this);
|
|
srcVOP = dstVOP = dwPVFlags = position.dwStride = dwLockCnt = 0;
|
|
position.lpvData = NULL;
|
|
clipCodes = NULL;
|
|
lpDDSVB = NULL;
|
|
dwCaps = 0;
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "Direct3DVertexBuffer::destructor"
|
|
|
|
CDirect3DVertexBuffer::~CDirect3DVertexBuffer()
|
|
{
|
|
/*
|
|
* Remove ourselves from the Direct3D object
|
|
*/
|
|
LIST_DELETE(this, list);
|
|
this->lpDirect3DI->numVBufs--;
|
|
delete [] clipCodes;
|
|
if (lpDDSVB)
|
|
{
|
|
lpDDSVB->Release();
|
|
lpDDS1VB->Release();
|
|
}
|
|
}
|
|
//---------------------------------------------------------------------
|
|
//
|
|
// Create the vertex memory buffer through DirectDraw
|
|
//
|
|
// Notes:
|
|
// this->dwMemType should be set before calling this function
|
|
// this->dwCaps should be set too.
|
|
// this->dwMemType is set to DDSCAPS_VIDEOMEMORY is the VB was driver allocated
|
|
//
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "Direct3DVertexBuffer::CreateMemoryBuffer"
|
|
HRESULT CDirect3DVertexBuffer::CreateMemoryBuffer(
|
|
LPDIRECT3DI lpD3DI,
|
|
LPDIRECTDRAWSURFACE7 *lplpSurface7,
|
|
LPDIRECTDRAWSURFACE *lplpSurface,
|
|
LPVOID *lplpMemory,
|
|
DWORD dwBufferSize)
|
|
{
|
|
HRESULT ret;
|
|
DDSURFACEDESC2 ddsd;
|
|
memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
|
|
ddsd.dwSize = sizeof(DDSURFACEDESC2);
|
|
ddsd.dwFlags = DDSD_WIDTH | DDSD_CAPS | DDSD_FVF;
|
|
ddsd.dwWidth = dwBufferSize;
|
|
ddsd.ddsCaps.dwCaps = DDSCAPS_EXECUTEBUFFER;
|
|
ddsd.ddsCaps.dwCaps2 = this->dwMemType;
|
|
ddsd.dwFVF = this->fvf; // Let driver know about the FVF
|
|
|
|
// The meaning of DDSCAPS_VIDEOMEMORY and DDSCAPS_SYSTEMEMORY are
|
|
// slightly different in case of VBs. the former only means that
|
|
// the buffer is driver allocated and could be in any memory type.
|
|
// The latter means that the driver did not care to allocate VBs
|
|
// hence they are always in DDraw allocated system memory.
|
|
|
|
// The reason we try video memory followed by system memory
|
|
// (rather than simply not specifying the memory type) is for
|
|
// drivers which do not care to do any special VB allocations, we
|
|
// do not want DDraw to take the Win16 lock for locking system memory
|
|
// surfaces.
|
|
|
|
bool bTLHAL = DDGBL(lpD3DI)->lpD3DGlobalDriverData &&
|
|
(DDGBL(lpD3DI)->lpD3DGlobalDriverData->hwCaps.dwDevCaps &
|
|
D3DDEVCAPS_HWTRANSFORMANDLIGHT);
|
|
|
|
if ((this->dwCaps & D3DVBCAPS_SYSTEMMEMORY) || !(bTLHAL || FVF_TRANSFORMED(fvf)))
|
|
{
|
|
// This VB cannot reside in driver friendly memory since either:
|
|
// 1. The app explicitly specified system memory
|
|
// 2. The vertex buffer is untransformed and it is not a T&L hal
|
|
// thus the driver will never see this VB
|
|
D3D_INFO(8, "Trying to create a sys mem vertex buffer");
|
|
ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
|
|
ret = lpD3DI->lpDD7->CreateSurface(&ddsd, lplpSurface7, NULL);
|
|
if (ret != DD_OK)
|
|
{
|
|
D3D_ERR("Could not allocate the Vertex buffer.");
|
|
return ret;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Try explicit video memory first
|
|
ddsd.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY;
|
|
if ((this->dwCaps & D3DVBCAPS_DONOTCLIP) || bTLHAL)
|
|
ddsd.ddsCaps.dwCaps |= this->dwCaps & DDSCAPS_WRITEONLY;
|
|
D3D_INFO(8, "Trying to create a vid mem vertex buffer");
|
|
#ifdef __DISABLE_VIDMEM_VBS__
|
|
if ((lpD3DI->bDisableVidMemVBs == TRUE) ||
|
|
(lpD3DI->lpDD7->CreateSurface(&ddsd, lplpSurface7, NULL) != DD_OK))
|
|
#else //__DISABLE_VIDMEM_VBS__
|
|
if (lpD3DI->lpDD7->CreateSurface(&ddsd, lplpSurface7, NULL) != DD_OK)
|
|
#endif //__DISABLE_VIDMEM_VBS__
|
|
{
|
|
// If that failed, or user requested sys mem, try explicit system
|
|
// memory
|
|
D3D_INFO(6, "Trying to create a sys mem vertex buffer");
|
|
ddsd.ddsCaps.dwCaps &= ~(DDSCAPS_VIDEOMEMORY | DDSCAPS_WRITEONLY);
|
|
ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
|
|
ret = lpD3DI->lpDD7->CreateSurface(&ddsd, lplpSurface7, NULL);
|
|
if (ret != DD_OK)
|
|
{
|
|
D3D_ERR("Could not allocate the Vertex buffer.");
|
|
return ret;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
this->dwMemType = DDSCAPS_VIDEOMEMORY;
|
|
// Stick in our pointer so that we can be notified about mode changes
|
|
DDSLCL(*lplpSurface7)->lpSurfMore->lpVB = static_cast<LPVOID>(this);
|
|
}
|
|
}
|
|
ret = (*lplpSurface7)->QueryInterface(IID_IDirectDrawSurfaceNew, (LPVOID*)lplpSurface);
|
|
if (ret != DD_OK)
|
|
{
|
|
D3D_ERR("failed to QI for DDS1");
|
|
return ret;
|
|
}
|
|
ret = (*lplpSurface7)->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_NOSYSLOCK, NULL);
|
|
if (ret != DD_OK)
|
|
{
|
|
D3D_ERR("Could not lock vertex buffer.");
|
|
return ret;
|
|
}
|
|
*lplpMemory = ddsd.lpSurface;
|
|
return D3D_OK;
|
|
}
|
|
//---------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "Direct3DVertexBuffer::init"
|
|
|
|
HRESULT CDirect3DVertexBuffer::Init(LPDIRECT3DI lpD3DI, LPD3DVERTEXBUFFERDESC lpDesc, DWORD dwFlags)
|
|
{
|
|
HRESULT ret;
|
|
|
|
bReallyOptimized = FALSE;
|
|
dwCaps = lpDesc->dwCaps;
|
|
fvf = lpDesc->dwFVF;
|
|
dwNumVertices = lpDesc->dwNumVertices;
|
|
#ifdef VTABLE_HACK
|
|
// Copy with vtable
|
|
lpVtbl = *((LPVOID**)this);
|
|
memcpy(newVtbl, lpVtbl, sizeof(PVOID)*D3DVB_NUM_VIRTUAL_FUNCTIONS);
|
|
// Point to the new one
|
|
*((LPVOID*)this) = (LPVOID)newVtbl;
|
|
#endif // VTABLE_HACK
|
|
if (dwNumVertices > MAX_DX6_VERTICES)
|
|
{
|
|
D3D_ERR("Direct3D for DirectX 6.0 cannot handle greater than 64K vertices");
|
|
return D3DERR_TOOMANYVERTICES;
|
|
}
|
|
if (lpDesc->dwCaps & D3DVBCAPS_OPTIMIZED)
|
|
{
|
|
D3D_ERR("D3DVBCAPS_OPTIMIZED flag should not be set");
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
|
|
this->nTexCoord = FVF_TEXCOORD_NUMBER(fvf);
|
|
this->dwTexCoordSizeTotal = ComputeTextureCoordSize(this->fvf, this->dwTexCoordSize);
|
|
position.dwStride = GetVertexSizeFVF(this->fvf) + this->dwTexCoordSizeTotal;
|
|
if (position.dwStride == 0)
|
|
{
|
|
D3D_ERR("Vertex size is zero according to the FVF id");
|
|
return D3DERR_INVALIDVERTEXFORMAT;
|
|
}
|
|
|
|
if (dwFlags & D3DVBFLAGS_CREATEMULTIBUFFER)
|
|
dwMemType = 0;
|
|
else
|
|
dwMemType = DDSCAPS2_VERTEXBUFFER;
|
|
#ifdef DBG
|
|
// Allocate space for one more vertex and fill with deadbeef. Used to check for
|
|
// overwrites during unlock
|
|
ret = CreateMemoryBuffer(lpD3DI, &lpDDSVB, &lpDDS1VB, &position.lpvData,
|
|
position.dwStride * (dwNumVertices + 1));
|
|
if (ret != D3D_OK)
|
|
return ret;
|
|
LPDWORD pPad = (LPDWORD)((LPBYTE)(position.lpvData) + position.dwStride * dwNumVertices);
|
|
for (unsigned i = 0; i < position.dwStride / sizeof(DWORD); ++i)
|
|
*pPad++ = 0xdeadbeef;
|
|
#else
|
|
ret = CreateMemoryBuffer(lpD3DI, &lpDDSVB, &lpDDS1VB, &position.lpvData,
|
|
position.dwStride * dwNumVertices);
|
|
if (ret != D3D_OK)
|
|
return ret;
|
|
#endif
|
|
|
|
/* Classify the operations that can be done using this VB */
|
|
if ((fvf & D3DFVF_POSITION_MASK))
|
|
{
|
|
if ((fvf & D3DFVF_POSITION_MASK) != D3DFVF_XYZRHW)
|
|
{
|
|
D3D_INFO(4, "D3DFVF_XYZ set. Can be source VB for Transform");
|
|
srcVOP = D3DVOP_TRANSFORM | D3DVOP_EXTENTS | D3DVOP_CLIP;
|
|
}
|
|
else
|
|
{
|
|
D3D_INFO(4, "D3DFVF_XYZRHW set. Can be dest VB for Transform");
|
|
dstVOP = D3DVOP_TRANSFORM | D3DVOP_EXTENTS;
|
|
srcVOP = D3DVOP_EXTENTS;
|
|
if ((dwCaps & D3DVBCAPS_DONOTCLIP) == 0)
|
|
{
|
|
clipCodes = new D3DFE_CLIPCODE[dwNumVertices];
|
|
if (clipCodes == NULL)
|
|
{
|
|
D3D_ERR("Could not allocate space for clip flags");
|
|
return DDERR_OUTOFMEMORY;
|
|
}
|
|
memset(clipCodes, 0, dwNumVertices * sizeof(D3DFE_CLIPCODE));
|
|
dstVOP |= D3DVOP_CLIP;
|
|
}
|
|
}
|
|
}
|
|
if (srcVOP & D3DVOP_TRANSFORM)
|
|
{
|
|
D3D_INFO(4, "Can be src VB for lighting.");
|
|
srcVOP |= D3DVOP_LIGHT;
|
|
}
|
|
if (fvf & D3DFVF_DIFFUSE)
|
|
{
|
|
D3D_INFO(4, "D3DFVF_DIFFUSE set. Can be dest VB for lighting");
|
|
dstVOP |= D3DVOP_LIGHT;
|
|
}
|
|
if (dstVOP & D3DVOP_TRANSFORM)
|
|
{
|
|
D3D_INFO(4, "VB can be rendered");
|
|
srcVOP |= D3DVOP_RENDER;
|
|
}
|
|
|
|
return(D3D_OK);
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "Direct3DVertexBuffer::Lock"
|
|
|
|
HRESULT D3DAPI CDirect3DVertexBuffer::Lock(DWORD dwFlags, LPVOID* lplpData, DWORD* lpdwSize)
|
|
{
|
|
CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock.
|
|
HRESULT ret;
|
|
#if DBG
|
|
if (!VALID_DIRECT3DVERTEXBUFFER_PTR(this))
|
|
{
|
|
D3D_ERR( "Invalid Direct3DVertexBuffer pointer" );
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
if (IsBadWritePtr( lplpData, sizeof(LPVOID)))
|
|
{
|
|
D3D_ERR( "Invalid lpData pointer" );
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
if (lpdwSize)
|
|
{
|
|
if (IsBadWritePtr( lpdwSize, sizeof(DWORD)))
|
|
{
|
|
D3D_ERR( "Invalid lpData pointer" );
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
}
|
|
#endif
|
|
if (this->dwCaps & D3DVBCAPS_OPTIMIZED)
|
|
{
|
|
D3D_ERR("Cannot lock optimized vertex buffer");
|
|
return(D3DERR_VERTEXBUFFEROPTIMIZED);
|
|
}
|
|
if (!this->position.lpvData)
|
|
{
|
|
// Unlock if previous lock was broken due to mode switch
|
|
if (DDSGBL(lpDDSVB)->dwUsageCount > 0)
|
|
{
|
|
DDASSERT(DDSGBL(lpDDSVB)->dwUsageCount == 1);
|
|
D3D_INFO(2, "Lock: Unlocking broken VB lock");
|
|
lpDDSVB->Unlock(NULL);
|
|
}
|
|
if (lpDevIBatched)
|
|
{
|
|
ret = lpDevIBatched->FlushStates();
|
|
if (ret != D3D_OK)
|
|
{
|
|
D3D_ERR("Could not flush batch referring to VB during Lock");
|
|
return ret;
|
|
}
|
|
}
|
|
#ifdef DBG
|
|
LPVOID pOldBuf = (LPVOID)((LPDDRAWI_DDRAWSURFACE_INT)lpDDSVB)->lpLcl->lpGbl->fpVidMem;
|
|
#endif // DBG
|
|
// Do a real Lock
|
|
DDSURFACEDESC2 ddsd;
|
|
memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
|
|
ddsd.dwSize = sizeof(DDSURFACEDESC2);
|
|
ret = lpDDSVB->Lock(NULL, &ddsd, dwFlags | DDLOCK_NOSYSLOCK, NULL);
|
|
if (ret != DD_OK)
|
|
{
|
|
D3D_ERR("Lock: Could not lock Vertex Buffer: %08x", ret);
|
|
return ret;
|
|
}
|
|
position.lpvData = ddsd.lpSurface;
|
|
#if DBG
|
|
if(ddsd.lpSurface != pOldBuf)
|
|
{
|
|
D3D_INFO(2, "Driver swapped VB pointer in Lock");
|
|
}
|
|
LPDWORD pPad = (LPDWORD)((LPBYTE)(position.lpvData) + position.dwStride * dwNumVertices);
|
|
for (unsigned i = 0; i < position.dwStride / sizeof(DWORD); ++i)
|
|
*pPad++ = 0xdeadbeef;
|
|
#endif
|
|
}
|
|
#ifdef VTABLE_HACK
|
|
/* Single threaded or Multi threaded app ? */
|
|
if (!(((LPDDRAWI_DIRECTDRAW_INT)lpDirect3DI->lpDD)->lpLcl->dwLocalFlags & DDRAWILCL_MULTITHREADED))
|
|
VtblLockFast();
|
|
#endif // VTABLE_HACK
|
|
return this->LockI(dwFlags, lplpData, lpdwSize);
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
// Side effect:
|
|
// position.lpvData is set.
|
|
//
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "Direct3DVertexBuffer::LockI"
|
|
|
|
HRESULT D3DAPI CDirect3DVertexBuffer::LockI(DWORD dwFlags, LPVOID* lplpData,
|
|
DWORD* lpdwSize)
|
|
{
|
|
dwLockCnt++;
|
|
D3D_INFO(6, "VB Lock: %lx Lock Cnt =%d", this, dwLockCnt);
|
|
if (!(dwFlags & (DDLOCK_READONLY | DDLOCK_NOOVERWRITE)) && lpDevIBatched)
|
|
{
|
|
HRESULT ret;
|
|
if (dwFlags & DDLOCK_OKTOSWAP)
|
|
{
|
|
ret = lpDevIBatched->FlushStatesReq(position.dwStride * dwNumVertices);
|
|
#if DBG
|
|
if (!(this->dwCaps & D3DVBCAPS_OPTIMIZED))
|
|
{
|
|
// Make sure the size of the new buffer is the same
|
|
DDASSERT(position.dwStride * (dwNumVertices + 1) <= DDSGBL(lpDDSVB)->dwLinearSize);
|
|
// Write deadbeaf in the pad area
|
|
LPDWORD pPad = (LPDWORD)((LPBYTE)(position.lpvData) + position.dwStride * dwNumVertices);
|
|
for (unsigned i = 0; i < position.dwStride / sizeof(DWORD); ++i)
|
|
*pPad++ = 0xdeadbeef;
|
|
}
|
|
#endif
|
|
}
|
|
else
|
|
ret = lpDevIBatched->FlushStates();
|
|
if (ret != D3D_OK)
|
|
{
|
|
D3D_ERR("Could not flush batch referring to VB during Lock");
|
|
return ret;
|
|
}
|
|
}
|
|
*lplpData = position.lpvData;
|
|
if (lpdwSize)
|
|
*lpdwSize = position.dwStride * dwNumVertices;
|
|
return D3D_OK;
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "Direct3DVertexBuffer::Unlock"
|
|
|
|
HRESULT D3DAPI CDirect3DVertexBuffer::Unlock()
|
|
{
|
|
if (dwLockCnt)
|
|
{
|
|
dwLockCnt--;
|
|
}
|
|
#ifdef DBG
|
|
if (!(this->dwCaps & D3DVBCAPS_OPTIMIZED))
|
|
{
|
|
// Check for VB overruns
|
|
LPDWORD pPad = (LPDWORD)((LPBYTE)(position.lpvData) + position.dwStride * dwNumVertices);
|
|
for (unsigned i = 0; i < position.dwStride / sizeof(DWORD); ++i)
|
|
if (*pPad++ != 0xdeadbeef)
|
|
{
|
|
D3D_ERR("Vertex buffer was overrun. Make sure that you do not write past the VB size!");
|
|
return D3DERR_VERTEXBUFFERUNLOCKFAILED;
|
|
}
|
|
D3D_INFO(6, "VB Unlock: %lx Lock Cnt =%d", this, dwLockCnt);
|
|
}
|
|
#endif
|
|
return D3D_OK;
|
|
}
|
|
|
|
// Called from FlushStates to undo cached VB pointer so that the next lock causes a driver lock
|
|
// This is necessary if the we did not flush with SWAPVERTEXBUFFER.
|
|
void CDirect3DVertexBuffer::UnlockI()
|
|
{
|
|
if ((this->dwMemType == DDSCAPS_VIDEOMEMORY) && (dwLockCnt == 0))
|
|
{
|
|
#ifdef VTABLE_HACK
|
|
VtblLockDefault();
|
|
#endif
|
|
lpDDSVB->Unlock(NULL);
|
|
position.lpvData = 0;
|
|
}
|
|
else if (dwLockCnt !=0 )
|
|
{
|
|
D3D_WARN(4, "App has a lock on VB %08x so driver call may be slow", this);
|
|
}
|
|
}
|
|
|
|
#ifndef WIN95
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "Direct3DVertexBuffer::LockWorkAround"
|
|
|
|
HRESULT CDirect3DVertexBuffer::LockWorkAround(CDirect3DDeviceIDP2 *pDev)
|
|
{
|
|
if (this->dwMemType == DDSCAPS_VIDEOMEMORY)
|
|
{
|
|
#ifdef DBG
|
|
LPVOID pOldBuf = (LPVOID)((LPDDRAWI_DDRAWSURFACE_INT)lpDDSVB)->lpLcl->lpGbl->fpVidMem;
|
|
#endif // DBG
|
|
// Do a real Lock
|
|
DDSURFACEDESC2 ddsd;
|
|
memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
|
|
ddsd.dwSize = sizeof(DDSURFACEDESC2);
|
|
HRESULT ret = lpDDSVB->Lock(NULL, &ddsd, DDLOCK_OKTOSWAP | DDLOCK_NOSYSLOCK, NULL);
|
|
if (ret != DD_OK)
|
|
{
|
|
D3D_ERR("Lock: Could not lock Vertex Buffer: %08x", ret);
|
|
return ret;
|
|
}
|
|
position.lpvData = ddsd.lpSurface;
|
|
pDev->alignedBuf = ddsd.lpSurface;
|
|
#ifdef DBG
|
|
if(ddsd.lpSurface != pOldBuf)
|
|
{
|
|
D3D_INFO(2, "Driver swapped TLVBuf pointer in Lock");
|
|
}
|
|
#endif
|
|
// Make sure the size of the new buffer is the same
|
|
DDASSERT(position.dwStride * (dwNumVertices + 1) <= DDSGBL(lpDDSVB)->dwLinearSize);
|
|
}
|
|
return D3D_OK;
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "Direct3DVertexBuffer::UnlockWorkAround"
|
|
|
|
void CDirect3DVertexBuffer::UnlockWorkAround()
|
|
{
|
|
if ((this->dwMemType == DDSCAPS_VIDEOMEMORY) &&
|
|
(position.lpvData != 0))
|
|
{
|
|
lpDDSVB->Unlock(NULL);
|
|
position.lpvData = 0;
|
|
}
|
|
}
|
|
|
|
#endif // WIN95
|
|
|
|
// Cause us to go thru the slow path and force a lock
|
|
// The slow path will do the unlock if necessary. This
|
|
// is because we are called from DDraw's invalidate
|
|
// surface code and it might not be the best time to
|
|
// call back ddraw to unlock the surface.
|
|
void CDirect3DVertexBuffer::BreakLock()
|
|
{
|
|
D3D_INFO(6, "Notified of restore on VB %08x", this);
|
|
#ifdef VTABLE_HACK
|
|
VtblLockDefault();
|
|
#endif
|
|
position.lpvData = 0;
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "Direct3DVertexBuffer::GetVertexBufferDesc"
|
|
|
|
HRESULT D3DAPI CDirect3DVertexBuffer::GetVertexBufferDesc(LPD3DVERTEXBUFFERDESC lpDesc)
|
|
{
|
|
#if DBG
|
|
if (!VALID_DIRECT3DVERTEXBUFFER_PTR(this))
|
|
{
|
|
D3D_ERR( "Invalid Direct3DVertexBuffer pointer" );
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
if (IsBadWritePtr( lpDesc, lpDesc->dwSize))
|
|
{
|
|
D3D_ERR( "Invalid lpData pointer" );
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
if (! VALID_D3DVERTEXBUFFERDESC_PTR(lpDesc) )
|
|
{
|
|
D3D_ERR( "Invalid D3DVERTEXBUFFERDESC" );
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
#endif
|
|
lpDesc->dwCaps = dwCaps;
|
|
lpDesc->dwFVF = fvf;
|
|
lpDesc->dwNumVertices = this->dwNumVertices;
|
|
return D3D_OK;
|
|
}
|
|
//---------------------------------------------------------------------
|
|
// Common validation for ProcessVertices and ProcessVerticesStrided
|
|
//
|
|
HRESULT CDirect3DVertexBuffer::ValidateProcessVertices(
|
|
DWORD vertexOP,
|
|
DWORD dwDstIndex,
|
|
DWORD dwCount,
|
|
LPVOID lpSrc,
|
|
LPDIRECT3DDEVICE7 lpDevice,
|
|
DWORD dwFlags)
|
|
{
|
|
if (!VALID_DIRECT3DVERTEXBUFFER_PTR(this))
|
|
{
|
|
D3D_ERR( "Invalid destination Direct3DVertexBuffer pointer" );
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
if (!VALID_DIRECT3DDEVICE_PTR(lpDevice))
|
|
{
|
|
D3D_ERR( "Invalid Direct3DDevice pointer" );
|
|
return DDERR_INVALIDOBJECT;
|
|
}
|
|
LPDIRECT3DDEVICEI lpDevI = static_cast<LPDIRECT3DDEVICEI>(lpDevice);
|
|
if (lpDevI->ValidateFVF(this->fvf) != D3D_OK)
|
|
{
|
|
D3D_ERR("Invalid vertex buffer FVF for the device");
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
if (dwFlags & ~D3DPV_DONOTCOPYDATA)
|
|
{
|
|
D3D_ERR( "Invalid dwFlags set" );
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
if ((dwDstIndex + dwCount) > this->dwNumVertices)
|
|
{
|
|
D3D_ERR( "Vertex count plus destination index is greater than number of vertices" );
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
// Validate Dst Vertex Formats
|
|
if (lpSrc)
|
|
{
|
|
if ((this->dstVOP & vertexOP) != vertexOP)
|
|
goto error;
|
|
}
|
|
else
|
|
{
|
|
if ((this->fvf & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW)
|
|
{
|
|
if (vertexOP & ~(D3DVOP_CLIP | D3DVOP_EXTENTS))
|
|
goto error;
|
|
}
|
|
else
|
|
{
|
|
if (vertexOP & ~(D3DVOP_CLIP))
|
|
goto error;
|
|
}
|
|
}
|
|
return D3D_OK;
|
|
error:
|
|
D3D_ERR("Destination VB cannot support this operation");
|
|
return D3DERR_INVALIDVERTEXFORMAT;
|
|
}
|
|
//---------------------------------------------------------------------
|
|
// Common part for ProcessVertices and ProcessVerticesStrided
|
|
//
|
|
HRESULT CDirect3DVertexBuffer::DoProcessVertices(
|
|
LPDIRECT3DVERTEXBUFFERI lpSrcI,
|
|
LPDIRECT3DDEVICEI lpDevI,
|
|
DWORD vertexOP,
|
|
DWORD dwSrcIndex,
|
|
DWORD dwDstIndex,
|
|
DWORD dwFlags)
|
|
{
|
|
lpDevI->lpClipFlags = clipCodes + dwDstIndex;
|
|
// Compute needed output FVF
|
|
{
|
|
DWORD dwInputVertexSize;
|
|
HRESULT ret = lpDevI->SetupFVFDataCommon(&dwInputVertexSize);
|
|
if (ret != D3D_OK)
|
|
return ret;
|
|
// Make sure we have specular in output VB if the current state settings
|
|
// require us to write to specular
|
|
if (vertexOP & D3DVOP_LIGHT)
|
|
if (lpDevI->rstates[D3DRENDERSTATE_SPECULARENABLE] || lpDevI->rstates[D3DRENDERSTATE_FOGENABLE])
|
|
if (!(fvf & D3DFVF_SPECULAR))
|
|
{
|
|
D3D_ERR("Destination VB FVF format cannot be used with the current D3D settings");
|
|
return D3DERR_INVALIDVERTEXFORMAT;
|
|
}
|
|
// Check number of texture coordinates and texture formats in the
|
|
// destination VB are the same as in the computed FVF
|
|
DWORD dwComputedOutFVF = lpDevI->dwVIDOut & 0xFFFF0000;
|
|
if (lpDevI->nOutTexCoord > this->nTexCoord ||
|
|
((fvf & dwComputedOutFVF) != dwComputedOutFVF))
|
|
{
|
|
D3D_ERR("Destination VB FVF format cannot be used with the current D3D settings");
|
|
return D3DERR_INVALIDVERTEXFORMAT;
|
|
}
|
|
}
|
|
// Output
|
|
lpDevI->lpvOut = LPVOID(LPBYTE(position.lpvData) + dwDstIndex * position.dwStride);
|
|
lpDevI->dwOutputSize = this->position.dwStride;
|
|
lpDevI->dwVIDOut = fvf;
|
|
|
|
// Set up vertex pointers, because SetupFVFData works with "computed" FVF
|
|
UpdateGeometryLoopData(lpDevI);
|
|
|
|
// Save current flags to restore later
|
|
DWORD dwOrigDeviceFlags = lpDevI->dwDeviceFlags;
|
|
if (vertexOP & D3DVOP_CLIP)
|
|
{
|
|
lpDevI->dwDeviceFlags &= ~D3DDEV_DONOTCLIP;
|
|
this->dwPVFlags |= D3DPV_CLIPCODESGENERATED;
|
|
}
|
|
else
|
|
{
|
|
lpDevI->dwDeviceFlags |= D3DDEV_DONOTCLIP;
|
|
}
|
|
|
|
if (vertexOP & D3DVOP_LIGHT)
|
|
lpDevI->dwDeviceFlags |= D3DDEV_LIGHTING;
|
|
else
|
|
lpDevI->dwDeviceFlags &= ~D3DDEV_LIGHTING;
|
|
|
|
if (vertexOP & D3DVOP_EXTENTS)
|
|
{
|
|
lpDevI->dwDeviceFlags &= ~D3DDEV_DONOTUPDATEEXTENTS;
|
|
}
|
|
else
|
|
{
|
|
lpDevI->dwDeviceFlags |= D3DDEV_DONOTUPDATEEXTENTS;
|
|
}
|
|
|
|
DoUpdateState(lpDevI);
|
|
|
|
if (lpSrcI)
|
|
{
|
|
if (lpSrcI->bReallyOptimized)
|
|
{ // SOA
|
|
// Assume that SOA.lpvData is the same as position.lpvData
|
|
lpDevI->SOA.lpvData = lpSrcI->position.lpvData;
|
|
lpDevI->SOA.dwStride = lpSrcI->dwNumVertices;
|
|
lpDevI->dwSOAStartVertex = dwSrcIndex;
|
|
lpDevI->dwOutputSize = position.dwStride;
|
|
}
|
|
else
|
|
{ // AOS FVF
|
|
lpDevI->dwOutputSize = position.dwStride;
|
|
lpDevI->position.lpvData = LPVOID(LPBYTE(lpSrcI->position.lpvData) + dwSrcIndex * lpSrcI->position.dwStride);
|
|
lpDevI->position.dwStride = lpSrcI->position.dwStride;
|
|
}
|
|
}
|
|
|
|
if (dwFlags & D3DPV_DONOTCOPYDATA)
|
|
{
|
|
lpDevI->dwFlags |= D3DPV_DONOTCOPYDIFFUSE | D3DPV_DONOTCOPYSPECULAR |
|
|
D3DPV_DONOTCOPYTEXTURE;
|
|
// If D3DIM generates colors or texture, we should clear DONOTCOPY bits
|
|
if (lpDevI->dwFlags & D3DPV_LIGHTING)
|
|
{
|
|
lpDevI->dwFlags &= ~D3DPV_DONOTCOPYDIFFUSE;
|
|
if (lpDevI->dwDeviceFlags & D3DDEV_SPECULARENABLE)
|
|
lpDevI->dwFlags &= ~D3DPV_DONOTCOPYSPECULAR;
|
|
}
|
|
if (lpDevI->dwFlags & D3DPV_FOG)
|
|
lpDevI->dwFlags &= ~D3DPV_DONOTCOPYSPECULAR;
|
|
// If front-end is asked to do something with texture coordinates
|
|
// we disable DONOTCOPYTEXTURE
|
|
if (__TEXTURETRANSFORMENABLED(lpDevI) || lpDevI->dwFlags2 & __FLAGS2_TEXGEN)
|
|
{
|
|
lpDevI->dwFlags &= ~D3DPV_DONOTCOPYTEXTURE;
|
|
}
|
|
}
|
|
|
|
lpDevI->pGeometryFuncs->ProcessVertices(lpDevI);
|
|
|
|
// This bit should be cleared, because for ProcessVertices calls user should
|
|
// set texture stage indices and wrap modes himself
|
|
lpDevI->dwDeviceFlags &= ~D3DDEV_REMAPTEXTUREINDICES;
|
|
|
|
if (!(lpDevI->dwDeviceFlags & D3DDEV_DONOTCLIP))
|
|
D3DFE_UpdateClipStatus(lpDevI);
|
|
// Restore _DONOTCLIP & _DONOTUPDATEEXTENTS flags
|
|
const DWORD PRESERVED_FLAGS = D3DDEV_DONOTCLIP |
|
|
D3DDEV_DONOTUPDATEEXTENTS |
|
|
D3DDEV_LIGHTING;
|
|
lpDevI->dwDeviceFlags = (dwOrigDeviceFlags & PRESERVED_FLAGS) |
|
|
(lpDevI->dwDeviceFlags & ~PRESERVED_FLAGS);
|
|
|
|
// Force recompute fvf next time around
|
|
lpDevI->ForceFVFRecompute();
|
|
|
|
// Unlock the VB
|
|
Unlock();
|
|
|
|
// If we used SOA then the dwVIDIn <-> position.dwStride relationship
|
|
// violated. This fixes that. This is required since in non VB code
|
|
// we will not recompute position.dwStride if FVF matched dwVIDIn.
|
|
if (lpSrcI)
|
|
lpDevI->position.dwStride = lpSrcI->position.dwStride;
|
|
|
|
return D3D_OK;
|
|
}
|
|
//---------------------------------------------------------------------
|
|
// lpSrc should be NULL for XYZRHW buffers
|
|
//
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "Direct3DVertexBuffer::ProcessVertices"
|
|
|
|
HRESULT D3DAPI CDirect3DVertexBuffer::ProcessVertices(DWORD vertexOP, DWORD dwDstIndex, DWORD dwCount,
|
|
LPDIRECT3DVERTEXBUFFER7 lpSrc,
|
|
DWORD dwSrcIndex,
|
|
LPDIRECT3DDEVICE7 lpDevice, DWORD dwFlags)
|
|
{
|
|
LPDIRECT3DVERTEXBUFFERI lpSrcI;
|
|
LPDIRECT3DDEVICEI lpDevI;
|
|
HRESULT ret = D3D_OK;
|
|
|
|
#if DBG
|
|
ret = this->ValidateProcessVertices(vertexOP, dwDstIndex, dwCount, lpSrc, lpDevice, dwFlags);
|
|
if (ret != D3D_OK)
|
|
return ret;
|
|
lpDevI = static_cast<LPDIRECT3DDEVICEI>(lpDevice);
|
|
if (lpSrc != NULL)
|
|
{
|
|
if (!VALID_DIRECT3DVERTEXBUFFER_PTR(lpSrc))
|
|
{
|
|
D3D_ERR( "Invalid Direct3DVertexBuffer pointer" );
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
lpSrcI = static_cast<LPDIRECT3DVERTEXBUFFERI>(lpSrc);
|
|
if (lpDevI->ValidateFVF(lpSrcI->fvf) != D3D_OK)
|
|
{
|
|
D3D_ERR("Invalid source vertex buffer FVF for the device");
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
// Validate Src Vertex Formats
|
|
if ((lpSrcI->srcVOP & vertexOP) != vertexOP)
|
|
{
|
|
D3D_ERR("Source VB cannot support this operation");
|
|
return D3DERR_INVALIDVERTEXFORMAT;
|
|
}
|
|
if ((dwSrcIndex + dwCount) > lpSrcI->dwNumVertices)
|
|
{
|
|
D3D_ERR( "Source index plus vertex count is greater than number of vertices" );
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
if (!(vertexOP & D3DVOP_TRANSFORM))
|
|
{
|
|
D3D_ERR("D3DVOP_TRANSFORM flag should be set");
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
// Source to ProcessVertices must be in system memory. This is for reasons similar
|
|
// to why we insist on sys mem VB for SW rast. For instance, a driver may have optimized
|
|
// the VB into some cryptic format which D3D FE will have no clue to decipher.
|
|
if (!(lpSrcI->dwCaps & D3DVBCAPS_SYSTEMMEMORY))
|
|
{
|
|
D3D_ERR("Source VB must be created with D3DVBCAPS_SYSTEMMEMORY");
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
}
|
|
#else
|
|
lpSrcI = static_cast<LPDIRECT3DVERTEXBUFFERI>(lpSrc);
|
|
lpDevI = static_cast<LPDIRECT3DDEVICEI>(lpDevice);
|
|
#endif
|
|
|
|
CLockD3DMT lockObject(lpDevI, DPF_MODNAME, REMIND("")); // Takes D3D lock.
|
|
|
|
lpDevI->dwNumVertices = dwCount;
|
|
|
|
// Lock the VBs
|
|
LPVOID lpVoid;
|
|
// We call the API level lock since dest VB may be in vid mem. This function will fail for
|
|
// optimized VBs and that is OK since we cannot write out optimized vertices anyway.
|
|
ret = Lock(DDLOCK_WAIT, &lpVoid, NULL);
|
|
if (ret != D3D_OK)
|
|
{
|
|
D3D_ERR("Could not lock the vertex buffer");
|
|
return ret;
|
|
}
|
|
|
|
if (lpSrc == NULL)
|
|
{
|
|
lpDevI->lpvOut = LPVOID(LPBYTE(position.lpvData) + dwDstIndex * position.dwStride);
|
|
if ((fvf & D3DFVF_POSITION_MASK) != D3DFVF_XYZRHW)
|
|
{
|
|
if (vertexOP & D3DVOP_CLIP)
|
|
{
|
|
CD3DFPstate D3DFPstate; // Sets optimal FPU state for D3D.
|
|
if (lpDevI->dwFEFlags & (D3DFE_TRANSFORM_DIRTY | D3DFE_CLIPPLANES_DIRTY))
|
|
{
|
|
DoUpdateState(lpDevI);
|
|
}
|
|
lpDevI->CheckClipStatus((D3DVALUE*)lpDevI->lpvOut,
|
|
position.dwStride,
|
|
dwCount,
|
|
&lpDevI->dwClipUnion,
|
|
&lpDevI->dwClipIntersection);
|
|
D3DFE_UpdateClipStatus(lpDevI);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// For transformed vertices we support only clip code generation and extens
|
|
lpDevI->lpClipFlags = clipCodes + dwDstIndex;
|
|
lpDevI->position.lpvData = lpDevI->lpvOut;
|
|
lpDevI->position.dwStride = position.dwStride;
|
|
lpDevI->dwOutputSize = position.dwStride;
|
|
if (vertexOP & D3DVOP_CLIP)
|
|
{
|
|
D3DFE_GenClipFlags(lpDevI);
|
|
D3DFE_UpdateClipStatus(lpDevI);
|
|
// Mark this buffer as "transformed" for clipping
|
|
dwPVFlags |= D3DPV_TLVCLIP;
|
|
}
|
|
if (vertexOP & D3DVOP_EXTENTS)
|
|
{
|
|
D3DFE_updateExtents(lpDevI);
|
|
}
|
|
}
|
|
Unlock();
|
|
return D3D_OK;
|
|
}
|
|
// Safe to LockI since source is guaranteed to be in system memory
|
|
// Cannot call API Lock since we need to be able to lock optimized VBs
|
|
ret = lpSrcI->LockI(DDLOCK_WAIT | DDLOCK_READONLY, &lpVoid, NULL);
|
|
if (ret != D3D_OK)
|
|
{
|
|
D3D_ERR("Could not lock the vertex buffer");
|
|
return ret;
|
|
}
|
|
|
|
dwPVFlags &= ~D3DPV_TLVCLIP; // Mark the dest VB as "not transformed" for clipping
|
|
lpDevI->dwFlags = (lpSrcI->dwPVFlags & D3DPV_SOA) | D3DPV_VBCALL;
|
|
lpDevI->dwDeviceFlags &= ~D3DDEV_STRIDE;
|
|
|
|
// Input
|
|
lpDevI->dwVIDIn = lpSrcI->fvf;
|
|
|
|
ret = this->DoProcessVertices(lpSrcI, lpDevI, vertexOP, dwSrcIndex, dwDstIndex, dwFlags);
|
|
if (ret != D3D_OK)
|
|
lpSrcI->Unlock();
|
|
else
|
|
ret = lpSrc->Unlock();
|
|
return ret;
|
|
}
|
|
//---------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "Direct3DVertexBuffer::ProcessVerticesStrided"
|
|
|
|
HRESULT D3DAPI CDirect3DVertexBuffer::ProcessVerticesStrided(DWORD vertexOP, DWORD dwDstIndex, DWORD dwCount,
|
|
LPD3DDRAWPRIMITIVESTRIDEDDATA lpDrawData,
|
|
DWORD dwSrcFVF,
|
|
LPDIRECT3DDEVICE7 lpDevice, DWORD dwFlags)
|
|
{
|
|
LPDIRECT3DDEVICEI lpDevI;
|
|
HRESULT ret = D3D_OK;
|
|
|
|
#if DBG
|
|
ret = this->ValidateProcessVertices(vertexOP, dwDstIndex, dwCount, lpDrawData, lpDevice, dwFlags);
|
|
if (ret != D3D_OK)
|
|
return ret;
|
|
lpDevI = static_cast<LPDIRECT3DDEVICEI>(lpDevice);
|
|
if (lpDevI->ValidateFVF(dwSrcFVF) != D3D_OK)
|
|
{
|
|
D3D_ERR("Invalid source FVF for the device");
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
if ((dwSrcFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW)
|
|
{
|
|
D3D_ERR("ProcessVerticesStrided cannot handle transformed vertices");
|
|
return D3DERR_INVALIDVERTEXTYPE;
|
|
}
|
|
if (!(vertexOP & D3DVOP_TRANSFORM))
|
|
{
|
|
D3D_ERR("D3DVOP_TRANSFORM flag should be set");
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
#else
|
|
lpDevI = static_cast<LPDIRECT3DDEVICEI>(lpDevice);
|
|
#endif
|
|
|
|
CLockD3DMT lockObject(lpDevI, DPF_MODNAME, REMIND("")); // Takes D3D lock.
|
|
|
|
// Lock the VBs
|
|
LPVOID lpVoid;
|
|
// We call the API level lock since dest VB may be in vid mem. This function will fail for
|
|
// optimized VBs and that is OK since we cannot write out optimized vertices anyway.
|
|
ret = Lock(DDLOCK_WAIT, &lpVoid, NULL);
|
|
if (ret != D3D_OK)
|
|
{
|
|
D3D_ERR("Could not lock the vertex buffer");
|
|
return ret;
|
|
}
|
|
|
|
dwPVFlags &= ~D3DPV_TLVCLIP; // Mark the dest VB as "not transformed" for clipping
|
|
lpDevI->dwDeviceFlags |= D3DDEV_STRIDE;
|
|
lpDevI->dwFlags = D3DPV_VBCALL;
|
|
|
|
// Input
|
|
lpDevI->dwNumVertices = dwCount;
|
|
lpDevI->dwVIDIn = dwSrcFVF;
|
|
lpDevI->position = lpDrawData->position;
|
|
lpDevI->normal = lpDrawData->normal;
|
|
lpDevI->diffuse = lpDrawData->diffuse;
|
|
lpDevI->specular = lpDrawData->specular;
|
|
for (DWORD i=0; i < this->nTexCoord; i++)
|
|
lpDevI->textures[i] = lpDrawData->textureCoords[i];
|
|
|
|
return this->DoProcessVertices(NULL, lpDevI, vertexOP, 0, dwDstIndex, dwFlags);
|
|
}
|
|
//---------------------------------------------------------------------
|
|
#ifdef DBG
|
|
HRESULT DIRECT3DDEVICEI::CheckDrawPrimitiveVB(LPDIRECT3DVERTEXBUFFER7 lpVBuf, DWORD dwStartVertex, DWORD dwNumVertices, DWORD dwFlags)
|
|
{
|
|
LPDIRECT3DVERTEXBUFFERI lpVBufI;
|
|
if (!VALID_DIRECT3DVERTEXBUFFER_PTR(lpVBuf))
|
|
{
|
|
D3D_ERR( "Invalid Direct3DVertexBuffer pointer" );
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
lpVBufI = static_cast<LPDIRECT3DVERTEXBUFFERI>(lpVBuf);
|
|
if (!VALID_DIRECT3DDEVICE_PTR(this))
|
|
{
|
|
D3D_ERR( "Invalid Direct3DDevice pointer" );
|
|
return DDERR_INVALIDOBJECT;
|
|
}
|
|
if (this->ValidateFVF(lpVBufI->fvf) != D3D_OK)
|
|
{
|
|
D3D_ERR("Invalid vertex buffer FVF for the device");
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
if (!IsDPFlagsValid(dwFlags))
|
|
{
|
|
D3D_ERR("Invalid Flags in dwFlags field");
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
if (!(dwDeviceFlags & D3DDEV_DONOTCLIP) && (lpVBufI->clipCodes == NULL) && (lpVBufI->srcVOP & D3DVOP_RENDER))
|
|
{
|
|
D3D_ERR("Vertex buffer does not support clipping");
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
if (!(IS_HW_DEVICE(this) || (lpVBufI->dwCaps & D3DVBCAPS_SYSTEMMEMORY)))
|
|
{
|
|
D3D_ERR("Cannot use vid mem vertex buffers with SW devices");
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
/* If we are on HAL with an untransformed vid mem VB then we disallow
|
|
This will happen only on T&L HW. The reason we disallow this is that
|
|
it'll be very slow so this is not an interesting thing to do anyway */
|
|
if ( !IS_TLHAL_DEVICE(this) &&
|
|
!(lpVBufI->dwCaps & D3DVBCAPS_SYSTEMMEMORY) &&
|
|
!FVF_TRANSFORMED(lpVBufI->fvf) )
|
|
{
|
|
D3D_ERR("DrawPrimitiveVB: Untransformed VB for HAL device must be created with D3DVBCAPS_SYSTEMMEMORY");
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
if (lpVBufI->dwLockCnt)
|
|
{
|
|
D3D_ERR("Cannot render using a locked vertex buffer");
|
|
return D3DERR_VERTEXBUFFERLOCKED;
|
|
}
|
|
if (dwStartVertex + dwNumVertices > lpVBufI->dwNumVertices)
|
|
{
|
|
D3D_ERR("Vertex range is outside the vertex buffer");
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
return D3D_OK;
|
|
}
|
|
#endif
|
|
//---------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "DIRECT3DDEVICEI::DrawIndexedPrimitiveVB"
|
|
|
|
HRESULT D3DAPI DIRECT3DDEVICEI::DrawIndexedPrimitiveVB(D3DPRIMITIVETYPE dptPrimitiveType,
|
|
LPDIRECT3DVERTEXBUFFER7 lpVBuf,
|
|
DWORD dwStartVertex, DWORD dwNumVertices,
|
|
LPWORD lpwIndices, DWORD dwIndexCount,
|
|
DWORD dwFlags)
|
|
{
|
|
CLockD3DMT lockObject(this, DPF_MODNAME, REMIND("")); // Takes D3D lock.
|
|
HRESULT ret;
|
|
LPDIRECT3DVERTEXBUFFERI lpVBufI = static_cast<LPDIRECT3DVERTEXBUFFERI>(lpVBuf);
|
|
#if DBG
|
|
ret = CheckDrawPrimitiveVB(lpVBuf, dwStartVertex, dwNumVertices, dwFlags);
|
|
if (ret != D3D_OK)
|
|
return ret;
|
|
Profile(PROF_DRAWINDEXEDPRIMITIVEVB,dptPrimitiveType,lpVBufI->fvf);
|
|
#endif
|
|
this->dwFlags = dwFlags | lpVBufI->dwPVFlags;
|
|
this->primType = dptPrimitiveType;
|
|
this->dwNumVertices = dwNumVertices;
|
|
this->dwNumIndices = dwIndexCount;
|
|
this->lpwIndices = lpwIndices;
|
|
GetNumPrim(this, dwNumIndices); // Calculate dwNumPrimitives and update stats
|
|
#if DBG
|
|
if (dwNumPrimitives > MAX_DX6_PRIMCOUNT)
|
|
{
|
|
D3D_ERR("D3D for DX7 cannot handle greater that 64K sized primitives");
|
|
return D3DERR_TOOMANYPRIMITIVES;
|
|
}
|
|
#endif
|
|
|
|
if (lpVBufI->srcVOP & D3DVOP_RENDER || IS_TLHAL_DEVICE(this))
|
|
{ // TLVERTEX or TLHAL
|
|
|
|
this->dwOutputSize = lpVBufI->position.dwStride;
|
|
this->position.dwStride = lpVBufI->position.dwStride;
|
|
this->dwVIDOut = lpVBufI->fvf;
|
|
DWORD dwOldVidIn = this->dwVIDIn;
|
|
this->dwVIDIn = lpVBufI->fvf;
|
|
BOOL bNoClipping = this->dwDeviceFlags & D3DDEV_DONOTCLIP ||
|
|
(!(lpVBufI->dwPVFlags & D3DPV_CLIPCODESGENERATED) && IS_TLHAL_DEVICE(this));
|
|
if (IS_DP2HAL_DEVICE(this))
|
|
{
|
|
this->nTexCoord = lpVBufI->nTexCoord;
|
|
CDirect3DDeviceIDP2 *dev = static_cast<CDirect3DDeviceIDP2*>(this);
|
|
ret = dev->StartPrimVB(lpVBufI, dwStartVertex);
|
|
if (ret != D3D_OK)
|
|
return ret;
|
|
lpVBufI->lpDevIBatched = this;
|
|
#ifdef VTABLE_HACK
|
|
if (bNoClipping && !IS_MT_DEVICE(this))
|
|
VtblDrawIndexedPrimitiveVBTL();
|
|
#endif
|
|
this->nOutTexCoord = lpVBufI->nTexCoord;
|
|
}
|
|
else
|
|
{
|
|
// needed for legacy drivers' DrawIndexPrim code
|
|
this->lpvOut = (BYTE*)(lpVBufI->position.lpvData) +
|
|
dwStartVertex * this->dwOutputSize;
|
|
ComputeTCI2CopyLegacy(this, lpVBufI->nTexCoord, lpVBufI->dwTexCoordSize, TRUE);
|
|
}
|
|
if (bNoClipping)
|
|
{
|
|
return DrawIndexPrim();
|
|
}
|
|
else
|
|
{
|
|
this->dwTextureCoordSizeTotal = lpVBufI->dwTexCoordSizeTotal;
|
|
for (DWORD i=0; i < this->nOutTexCoord; i++)
|
|
{
|
|
this->dwTextureCoordSize[i] = lpVBufI->dwTexCoordSize[i];
|
|
}
|
|
this->lpClipFlags = lpVBufI->clipCodes + dwStartVertex;
|
|
this->dwClipUnion = ~0; // Force clipping
|
|
if (dwOldVidIn != lpVBufI->fvf)
|
|
{
|
|
ComputeOutputVertexOffsets(this);
|
|
}
|
|
// If lpvData is NULL, it is a driver allocated buffer which
|
|
// means IS_DPHAL_DEVICE() is true.
|
|
// We need to lock such a buffer only if we need to clip
|
|
if (!lpVBufI->position.lpvData)
|
|
{
|
|
// Lock VB
|
|
DDSURFACEDESC2 ddsd;
|
|
memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
|
|
ddsd.dwSize = sizeof(DDSURFACEDESC2);
|
|
ret = lpVBufI->lpDDSVB->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_READONLY | DDLOCK_NOSYSLOCK, NULL);
|
|
if (ret != DD_OK)
|
|
{
|
|
D3D_ERR("Could not lock vertex buffer.");
|
|
return ret;
|
|
}
|
|
this->lpvOut = (BYTE*)(ddsd.lpSurface) +
|
|
dwStartVertex * this->dwOutputSize;
|
|
|
|
// Draw with clipping
|
|
this->position.lpvData = this->lpvOut;
|
|
#if DBG
|
|
ret = CheckDrawIndexedPrimitive(this, dwStartVertex);
|
|
if (ret == D3D_OK)
|
|
ret = DoDrawIndexedPrimitive(this);
|
|
#else
|
|
ret = DoDrawIndexedPrimitive(this);
|
|
#endif
|
|
// Unlock VB
|
|
if (ret == D3D_OK)
|
|
return lpVBufI->lpDDSVB->Unlock(NULL);
|
|
else
|
|
lpVBufI->lpDDSVB->Unlock(NULL);
|
|
return ret;
|
|
}
|
|
else
|
|
{
|
|
// Draw with clipping
|
|
this->lpvOut = (BYTE*)lpVBufI->position.lpvData + dwStartVertex * this->dwOutputSize;
|
|
this->position.lpvData = this->lpvOut;
|
|
#if DBG
|
|
ret = CheckDrawIndexedPrimitive(this, dwStartVertex);
|
|
if (ret != D3D_OK)
|
|
return ret;
|
|
#endif
|
|
return DoDrawIndexedPrimitive(this);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (lpVBufI->bReallyOptimized)
|
|
{
|
|
// Assume that SOA.lpvData is the same as position.lpvData
|
|
this->SOA.lpvData = lpVBufI->position.lpvData;
|
|
this->SOA.dwStride = lpVBufI->dwNumVertices;
|
|
this->dwSOAStartVertex = dwStartVertex;
|
|
}
|
|
else
|
|
{
|
|
this->position.lpvData = (BYTE*)(lpVBufI->position.lpvData) +
|
|
dwStartVertex * lpVBufI->position.dwStride;
|
|
this->position.dwStride = lpVBufI->position.dwStride;
|
|
#ifdef VTABLE_HACK
|
|
if (IS_DP2HAL_DEVICE(this) && !IS_MT_DEVICE(this))
|
|
{
|
|
CDirect3DDeviceIDP2 *dev = static_cast<CDirect3DDeviceIDP2*>(this);
|
|
dev->lpDP2LastVBI = lpVBufI;
|
|
dev->VtblDrawIndexedPrimitiveVBFE();
|
|
}
|
|
#endif
|
|
}
|
|
if (this->dwVIDIn != lpVBufI->fvf || this->dwDeviceFlags & D3DDEV_STRIDE)
|
|
{
|
|
this->dwDeviceFlags &= ~D3DDEV_STRIDE;
|
|
this->dwVIDIn = lpVBufI->fvf;
|
|
ret = SetupFVFData(NULL);
|
|
if (ret != D3D_OK)
|
|
goto l_exit;
|
|
}
|
|
#if DBG
|
|
ret = CheckDrawIndexedPrimitive(this, dwStartVertex);
|
|
if (ret != D3D_OK)
|
|
goto l_exit;
|
|
#endif
|
|
ret = this->ProcessPrimitive(__PROCPRIMOP_INDEXEDPRIM);
|
|
l_exit:
|
|
// If we used SOA then the dwVIDIn <-> position.dwStride relationship
|
|
// violated. This fixes that. This is required since in non VB code
|
|
// we will not recompute position.dwStride if FVF matched dwVIDIn.
|
|
this->position.dwStride = lpVBufI->position.dwStride;
|
|
return ret;
|
|
}
|
|
}
|
|
//---------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "DIRECT3DDEVICEI::DrawPrimitiveVB"
|
|
|
|
HRESULT D3DAPI DIRECT3DDEVICEI::DrawPrimitiveVB(D3DPRIMITIVETYPE dptPrimitiveType,
|
|
LPDIRECT3DVERTEXBUFFER7 lpVBuf,
|
|
DWORD dwStartVertex, DWORD dwNumVertices,
|
|
DWORD dwFlags)
|
|
{
|
|
CLockD3DMT lockObject(this, DPF_MODNAME, REMIND("")); // Takes D3D lock
|
|
HRESULT ret;
|
|
LPDIRECT3DVERTEXBUFFERI lpVBufI = static_cast<LPDIRECT3DVERTEXBUFFERI>(lpVBuf);
|
|
#if DBG
|
|
ret = CheckDrawPrimitiveVB(lpVBuf, dwStartVertex, dwNumVertices, dwFlags);
|
|
if (ret != D3D_OK)
|
|
return ret;
|
|
Profile(PROF_DRAWPRIMITIVEVB,dptPrimitiveType,lpVBufI->fvf);
|
|
#endif
|
|
this->dwFlags = dwFlags | lpVBufI->dwPVFlags;
|
|
this->primType = dptPrimitiveType;
|
|
this->dwNumVertices = dwNumVertices;
|
|
GetNumPrim(this, dwNumVertices); // Calculate dwNumPrimitives and update stats
|
|
#if DBG
|
|
if (dwNumPrimitives > MAX_DX6_PRIMCOUNT)
|
|
{
|
|
D3D_ERR("D3D for DX7 cannot handle greater that 64K sized primitives");
|
|
return D3DERR_TOOMANYPRIMITIVES;
|
|
}
|
|
#endif
|
|
if (lpVBufI->srcVOP & D3DVOP_RENDER || IS_TLHAL_DEVICE(this))
|
|
{ // TLVERTEX or TLHAL
|
|
this->position.dwStride = lpVBufI->position.dwStride;
|
|
this->dwOutputSize = lpVBufI->position.dwStride;
|
|
DWORD dwOldVidIn = this->dwVIDIn;
|
|
this->dwVIDIn = lpVBufI->fvf;
|
|
this->dwVIDOut = lpVBufI->fvf;
|
|
BOOL bNoClipping = this->dwDeviceFlags & D3DDEV_DONOTCLIP ||
|
|
(!(lpVBufI->dwPVFlags & D3DPV_CLIPCODESGENERATED) && IS_TLHAL_DEVICE(this));
|
|
if (IS_DP2HAL_DEVICE(this))
|
|
{
|
|
this->nTexCoord = lpVBufI->nTexCoord;
|
|
CDirect3DDeviceIDP2 *dev = static_cast<CDirect3DDeviceIDP2*>(this);
|
|
ret = dev->StartPrimVB(lpVBufI, dwStartVertex);
|
|
if (ret != D3D_OK)
|
|
return ret;
|
|
lpVBufI->lpDevIBatched = this;
|
|
#ifdef VTABLE_HACK
|
|
if (bNoClipping && !IS_MT_DEVICE(this))
|
|
VtblDrawPrimitiveVBTL();
|
|
#endif
|
|
this->nOutTexCoord = lpVBufI->nTexCoord;
|
|
}
|
|
else
|
|
{
|
|
// needed for legacy drivers' DrawPrim code
|
|
this->lpvOut = (BYTE*)(lpVBufI->position.lpvData) +
|
|
dwStartVertex * this->dwOutputSize;
|
|
ComputeTCI2CopyLegacy(this, lpVBufI->nTexCoord, lpVBufI->dwTexCoordSize, TRUE);
|
|
}
|
|
if (bNoClipping)
|
|
{
|
|
return DrawPrim();
|
|
}
|
|
else
|
|
{
|
|
this->dwTextureCoordSizeTotal = lpVBufI->dwTexCoordSizeTotal;
|
|
for (DWORD i=0; i < this->nOutTexCoord; i++)
|
|
{
|
|
this->dwTextureCoordSize[i] = lpVBufI->dwTexCoordSize[i];
|
|
}
|
|
this->lpClipFlags = lpVBufI->clipCodes + dwStartVertex;
|
|
this->dwClipUnion = ~0; // Force clipping
|
|
if (dwOldVidIn != lpVBufI->fvf)
|
|
{
|
|
ComputeOutputVertexOffsets(this);
|
|
}
|
|
// If lpvData is NULL, it is a driver allocated buffer which
|
|
// means IS_DPHAL_DEVICE() is true.
|
|
// We need to lock such a buffer only if we need to clip
|
|
if (!lpVBufI->position.lpvData)
|
|
{
|
|
// Lock VB
|
|
DDSURFACEDESC2 ddsd;
|
|
memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
|
|
ddsd.dwSize = sizeof(DDSURFACEDESC2);
|
|
ret = lpVBufI->lpDDSVB->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_READONLY | DDLOCK_NOSYSLOCK, NULL);
|
|
if (ret != DD_OK)
|
|
{
|
|
D3D_ERR("Could not lock vertex buffer.");
|
|
return ret;
|
|
}
|
|
this->lpvOut = (BYTE*)(ddsd.lpSurface) +
|
|
dwStartVertex * this->dwOutputSize;
|
|
|
|
// Draw with clipping
|
|
this->position.lpvData = this->lpvOut;
|
|
#if DBG
|
|
ret=CheckDrawPrimitive(this);
|
|
if (ret == D3D_OK)
|
|
ret = DoDrawPrimitive(this);
|
|
#else
|
|
ret = DoDrawPrimitive(this);
|
|
#endif
|
|
// Unlock VB
|
|
if (ret == D3D_OK)
|
|
return lpVBufI->lpDDSVB->Unlock(NULL);
|
|
else
|
|
lpVBufI->lpDDSVB->Unlock(NULL);
|
|
return ret;
|
|
}
|
|
else
|
|
{
|
|
// Draw with clipping
|
|
this->lpvOut = (BYTE*)lpVBufI->position.lpvData + dwStartVertex * this->dwOutputSize;
|
|
this->position.lpvData = this->lpvOut;
|
|
#if DBG
|
|
ret=CheckDrawPrimitive(this);
|
|
if (ret != D3D_OK)
|
|
return ret;
|
|
#endif
|
|
return DoDrawPrimitive(this);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (lpVBufI->bReallyOptimized)
|
|
{
|
|
// Assume that SOA.lpvData is the same as position.lpvData
|
|
this->SOA.lpvData = lpVBufI->position.lpvData;
|
|
this->SOA.dwStride = lpVBufI->dwNumVertices;
|
|
this->dwSOAStartVertex = dwStartVertex;
|
|
}
|
|
else
|
|
{
|
|
this->position.lpvData = (BYTE*)(lpVBufI->position.lpvData) +
|
|
dwStartVertex * lpVBufI->position.dwStride;
|
|
this->position.dwStride = lpVBufI->position.dwStride;
|
|
#ifdef VTABLE_HACK
|
|
if (IS_DP2HAL_DEVICE(this) && !IS_MT_DEVICE(this) && IS_FPU_SETUP(this))
|
|
{
|
|
CDirect3DDeviceIDP2 *dev = static_cast<CDirect3DDeviceIDP2*>(this);
|
|
dev->lpDP2LastVBI = lpVBufI;
|
|
dev->VtblDrawPrimitiveVBFE();
|
|
}
|
|
#endif
|
|
}
|
|
if (this->dwVIDIn != lpVBufI->fvf || this->dwDeviceFlags & D3DDEV_STRIDE)
|
|
{
|
|
this->dwDeviceFlags &= ~D3DDEV_STRIDE;
|
|
this->dwVIDIn = lpVBufI->fvf;
|
|
ret = SetupFVFData(NULL);
|
|
if (ret != D3D_OK)
|
|
goto l_exit;
|
|
}
|
|
#if DBG
|
|
ret=CheckDrawPrimitive(this);
|
|
if (ret != D3D_OK)
|
|
goto l_exit;
|
|
#endif
|
|
ret = this->ProcessPrimitive();
|
|
l_exit:
|
|
// If we used SOA then the dwVIDIn <-> position.dwStride relationship
|
|
// violated. This fixes that. This is required since in non VB code
|
|
// we will not recompute position.dwStride if FVF matched dwVIDIn.
|
|
this->position.dwStride = lpVBufI->position.dwStride;
|
|
return ret;
|
|
}
|
|
}
|
|
//---------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDirect3DVertexBuffer::Optimize"
|
|
|
|
HRESULT D3DAPI CDirect3DVertexBuffer::Optimize(LPDIRECT3DDEVICE7 lpDevice, DWORD dwFlags)
|
|
{
|
|
HRESULT ret;
|
|
LPDIRECT3DDEVICEI lpDevI;
|
|
DWORD bufferSize;
|
|
LPDIRECTDRAWSURFACE7 lpSurface7;
|
|
LPDIRECTDRAWSURFACE lpSurface;
|
|
LPVOID lpMemory;
|
|
|
|
|
|
// Validate parms
|
|
if (!VALID_DIRECT3DVERTEXBUFFER_PTR(this))
|
|
{
|
|
D3D_ERR( "Invalid Direct3DVertexBuffer pointer" );
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
if (!VALID_DIRECT3DDEVICE_PTR(lpDevice))
|
|
{
|
|
D3D_ERR( "Invalid Direct3DDevice pointer" );
|
|
return DDERR_INVALIDOBJECT;
|
|
}
|
|
lpDevI = static_cast<LPDIRECT3DDEVICEI>(lpDevice);
|
|
if (dwFlags != 0)
|
|
{
|
|
D3D_ERR("dwFlags should be zero");
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
|
|
CLockD3DMT lockObject(lpDevI, DPF_MODNAME, REMIND(""));
|
|
|
|
if (lpDevI->ValidateFVF(this->fvf) != D3D_OK)
|
|
{
|
|
D3D_ERR("Invalid vertex buffer FVF for the device");
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
if (this->dwCaps & D3DVBCAPS_OPTIMIZED)
|
|
{
|
|
D3D_ERR("The vertex buffer already optimized");
|
|
return D3DERR_VERTEXBUFFEROPTIMIZED;
|
|
}
|
|
if (this->dwLockCnt != 0)
|
|
{
|
|
D3D_ERR("Could not optimize locked vertex buffer");
|
|
return D3DERR_VERTEXBUFFERLOCKED;
|
|
}
|
|
if (IS_TLHAL_DEVICE(lpDevI) && (this->dwCaps & D3DVBCAPS_SYSTEMMEMORY)==0)
|
|
{
|
|
if (this->dwPVFlags & D3DPV_CLIPCODESGENERATED || (!IS_HW_DEVICE(lpDevI)))
|
|
{
|
|
// silently ignore since we'll be either
|
|
// using our front end or this is ref rast
|
|
// Either way we need no special optimization
|
|
goto success;
|
|
}
|
|
DDSURFACEDESC2 ddsd;
|
|
memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
|
|
ddsd.dwSize = sizeof(DDSURFACEDESC2);
|
|
ddsd.dwFlags = DDSD_CAPS | DDSD_FVF | DDSD_SRCVBHANDLE;
|
|
ddsd.ddsCaps.dwCaps = DDSCAPS_EXECUTEBUFFER;
|
|
ddsd.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY;
|
|
ddsd.ddsCaps.dwCaps2 = DDSCAPS2_VERTEXBUFFER;
|
|
ddsd.dwFVF = this->fvf; // Let driver know about the FVF
|
|
ddsd.dwSrcVBHandle = DDSLCL(this->lpDDSVB)->lpSurfMore->dwSurfaceHandle;
|
|
if (lpDevI->lpDirect3DI->lpDD7->CreateSurface(&ddsd, &lpSurface7, NULL) != DD_OK)
|
|
{
|
|
// Driver could not or did not want to optimize the VB
|
|
goto success;
|
|
}
|
|
ret = lpSurface7->QueryInterface(IID_IDirectDrawSurfaceNew, (LPVOID*)&lpSurface);
|
|
if (ret != DD_OK)
|
|
{
|
|
D3D_ERR("failed to QI for DDS1");
|
|
lpSurface7->Release();
|
|
return ret;
|
|
}
|
|
// Destroy old surfaces
|
|
lpDDSVB->Release();
|
|
lpDDS1VB->Release();
|
|
// And use new ones
|
|
lpDDSVB = lpSurface7;
|
|
lpDDS1VB = lpSurface;
|
|
|
|
this->dwCaps |= D3DVBCAPS_OPTIMIZED;
|
|
#ifdef VTABLE_HACK
|
|
VtblLockDefault();
|
|
#endif // VTABLE_HACK
|
|
return D3D_OK;
|
|
}
|
|
else
|
|
{
|
|
// Do nothing for transformed vertices
|
|
if ((this->fvf & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW)
|
|
{
|
|
goto success;
|
|
}
|
|
// Get the buffer size to allocate
|
|
bufferSize = lpDevI->pGeometryFuncs->ComputeOptimizedVertexBufferSize
|
|
(this->fvf, this->position.dwStride,
|
|
dwNumVertices);
|
|
// Create new surfaces for optimized vertex buffer
|
|
if (bufferSize == 0)
|
|
{
|
|
goto success;
|
|
}
|
|
|
|
ret = CreateMemoryBuffer(lpDevI->lpDirect3DI, &lpSurface7, &lpSurface,
|
|
&lpMemory, bufferSize);
|
|
if (ret != D3D_OK)
|
|
return ret;
|
|
// Try to optimize
|
|
// If optimized vertex buffer are not supported by the implementation
|
|
// it returns E_NOTIMPL. In this case we still set D3DVBCAPS_OPTIMIZED to prevent
|
|
// locking of the vertex buffer. But bReallyOptimized is set to FALSE, to use
|
|
// the original buffer.
|
|
ret = lpDevI->pGeometryFuncs->OptimizeVertexBuffer
|
|
(fvf, dwNumVertices, position.dwStride, position.lpvData,
|
|
lpMemory, dwFlags);
|
|
|
|
if (ret)
|
|
{
|
|
lpSurface7->Release();
|
|
lpSurface->Release();
|
|
if (ret == E_NOTIMPL)
|
|
{
|
|
goto success;
|
|
}
|
|
else
|
|
{
|
|
D3D_ERR("Failed to optimize vertex buffer");
|
|
return ret;
|
|
}
|
|
}
|
|
bReallyOptimized = TRUE;
|
|
this->dwPVFlags |= D3DPV_SOA;
|
|
// Destroy old surfaces
|
|
lpDDSVB->Release();
|
|
lpDDS1VB->Release();
|
|
// And use new ones
|
|
lpDDSVB = lpSurface7;
|
|
lpDDS1VB = lpSurface;
|
|
position.lpvData = lpMemory;
|
|
success:
|
|
this->dwCaps |= D3DVBCAPS_OPTIMIZED;
|
|
#ifdef VTABLE_HACK
|
|
// Disable all fast path optimizations
|
|
VtblLockDefault();
|
|
if (this->lpDevIBatched)
|
|
{
|
|
this->lpDevIBatched->VtblDrawPrimitiveVBDefault();
|
|
this->lpDevIBatched->VtblDrawIndexedPrimitiveVBDefault();
|
|
}
|
|
#endif
|
|
return D3D_OK;
|
|
}
|
|
}
|
|
|
|
#ifdef VTABLE_HACK
|
|
//---------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "DIRECT3DDEVICEI::DrawPrimitiveVBTL"
|
|
|
|
HRESULT D3DAPI CDirect3DDeviceIDP2::DrawPrimitiveVBTL(D3DPRIMITIVETYPE dptPrimitiveType,
|
|
LPDIRECT3DVERTEXBUFFER7 lpVBuf,
|
|
DWORD dwStartVertex, DWORD dwNumVertices,
|
|
DWORD dwFlags)
|
|
{
|
|
LPDIRECT3DVERTEXBUFFERI lpVBufI = static_cast<LPDIRECT3DVERTEXBUFFERI>(lpVBuf);
|
|
#if DBG
|
|
HRESULT ret = CheckDrawPrimitiveVB(lpVBuf, dwStartVertex, dwNumVertices, dwFlags);
|
|
if (ret != D3D_OK)
|
|
return ret;
|
|
Profile(PROF_DRAWPRIMITIVEVB,dptPrimitiveType,lpVBufI->fvf);
|
|
#endif
|
|
if ((lpVBufI == lpDP2CurrBatchVBI) && (this->dwVIDIn))
|
|
{
|
|
this->primType = dptPrimitiveType;
|
|
this->dwNumVertices = dwNumVertices;
|
|
this->dwFlags = dwFlags | lpVBufI->dwPVFlags;
|
|
this->dwVertexBase = dwStartVertex;
|
|
GetNumPrim(this, dwNumVertices); // Calculate dwNumPrimitives
|
|
#if DBG
|
|
if (dwNumPrimitives > MAX_DX6_PRIMCOUNT)
|
|
{
|
|
D3D_ERR("D3D for DX7 cannot handle greater that 64K sized primitives");
|
|
return D3DERR_TOOMANYPRIMITIVES;
|
|
}
|
|
#endif
|
|
this->dp2data.dwFlags &= ~D3DHALDP2_SWAPVERTEXBUFFER;
|
|
this->dwDP2VertexCount = max(this->dwDP2VertexCount, this->dwVertexBase + this->dwNumVertices);
|
|
lpVBufI->lpDevIBatched = this;
|
|
return DrawPrim();
|
|
}
|
|
VtblDrawPrimitiveVBDefault();
|
|
return DrawPrimitiveVB(dptPrimitiveType, lpVBuf, dwStartVertex, dwNumVertices, dwFlags);
|
|
}
|
|
//---------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "DIRECT3DDEVICEI::DrawIndexedPrimitiveVBTL"
|
|
|
|
HRESULT D3DAPI CDirect3DDeviceIDP2::DrawIndexedPrimitiveVBTL(D3DPRIMITIVETYPE dptPrimitiveType,
|
|
LPDIRECT3DVERTEXBUFFER7 lpVBuf,
|
|
DWORD dwStartVertex, DWORD dwNumVertices,
|
|
LPWORD lpwIndices, DWORD dwIndexCount,
|
|
DWORD dwFlags)
|
|
{
|
|
LPDIRECT3DVERTEXBUFFERI lpVBufI = static_cast<LPDIRECT3DVERTEXBUFFERI>(lpVBuf);
|
|
#if DBG
|
|
HRESULT ret = CheckDrawPrimitiveVB(lpVBuf, dwStartVertex, dwNumVertices, dwFlags);
|
|
if (ret != D3D_OK)
|
|
return ret;
|
|
Profile(PROF_DRAWINDEXEDPRIMITIVEVB,dptPrimitiveType,lpVBufI->fvf);
|
|
#endif
|
|
if ((lpVBufI == lpDP2CurrBatchVBI) && (this->dwVIDIn))
|
|
{
|
|
this->primType = dptPrimitiveType;
|
|
this->dwNumVertices = dwNumVertices;
|
|
this->dwFlags = dwFlags | lpVBufI->dwPVFlags;
|
|
this->dwVertexBase = dwStartVertex;
|
|
this->dwNumIndices = dwIndexCount;
|
|
this->lpwIndices = lpwIndices;
|
|
GetNumPrim(this, dwNumIndices); // Calculate dwNumPrimitives
|
|
#if DBG
|
|
if (dwNumPrimitives > MAX_DX6_PRIMCOUNT)
|
|
{
|
|
D3D_ERR("D3D for DX7 cannot handle greater that 64K sized primitives");
|
|
return D3DERR_TOOMANYPRIMITIVES;
|
|
}
|
|
#endif
|
|
this->dp2data.dwFlags &= ~D3DHALDP2_SWAPVERTEXBUFFER;
|
|
this->dwDP2VertexCount = max(this->dwDP2VertexCount, this->dwVertexBase + this->dwNumVertices);
|
|
lpVBufI->lpDevIBatched = this;
|
|
return DrawIndexPrim();
|
|
}
|
|
VtblDrawIndexedPrimitiveVBDefault();
|
|
return DrawIndexedPrimitiveVB(dptPrimitiveType, lpVBuf, dwStartVertex, dwNumVertices, lpwIndices, dwIndexCount, dwFlags);
|
|
}
|
|
//---------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "DIRECT3DDEVICEI::DrawPrimitiveVBFE"
|
|
|
|
HRESULT D3DAPI CDirect3DDeviceIDP2::DrawPrimitiveVBFE(D3DPRIMITIVETYPE dptPrimitiveType,
|
|
LPDIRECT3DVERTEXBUFFER7 lpVBuf,
|
|
DWORD dwStartVertex, DWORD dwNumVertices,
|
|
DWORD dwFlags)
|
|
{
|
|
LPDIRECT3DVERTEXBUFFERI lpVBufI = static_cast<LPDIRECT3DVERTEXBUFFERI>(lpVBuf);
|
|
HRESULT ret;
|
|
#if DBG
|
|
ret = CheckDrawPrimitiveVB(lpVBuf, dwStartVertex, dwNumVertices, dwFlags);
|
|
if (ret != D3D_OK)
|
|
return ret;
|
|
Profile(PROF_DRAWPRIMITIVEVB,dptPrimitiveType,lpVBufI->fvf);
|
|
#endif
|
|
if ((lpVBufI == lpDP2LastVBI) &&
|
|
!(this->dwFEFlags & D3DFE_FRONTEND_DIRTY))
|
|
{
|
|
this->primType = dptPrimitiveType;
|
|
this->dwNumVertices = dwNumVertices;
|
|
this->dwFlags = this->dwLastFlags | dwFlags | lpVBufI->dwPVFlags;
|
|
this->position.lpvData = (BYTE*)(lpVBufI->position.lpvData) +
|
|
dwStartVertex * lpVBufI->position.dwStride;
|
|
#if DBG
|
|
GetNumPrim(this, dwNumVertices); // Calculate dwNumPrimitives
|
|
if (dwNumPrimitives > MAX_DX6_PRIMCOUNT)
|
|
{
|
|
D3D_ERR("D3D for DX7 cannot handle greater that 64K sized primitives");
|
|
return D3DERR_TOOMANYPRIMITIVES;
|
|
}
|
|
#endif
|
|
this->dwVertexPoolSize = dwNumVertices * this->dwOutputSize;
|
|
if (this->dwVertexPoolSize > this->TLVbuf_GetSize())
|
|
{
|
|
// try
|
|
// {
|
|
if (this->TLVbuf_Grow(this->dwVertexPoolSize, true) != D3D_OK)
|
|
{
|
|
D3D_ERR( "Could not grow TL vertex buffer" );
|
|
return DDERR_OUTOFMEMORY;
|
|
}
|
|
// }
|
|
// catch (HRESULT ret)
|
|
// {
|
|
// return ret;
|
|
// }
|
|
}
|
|
if (dwNumVertices * sizeof(D3DFE_CLIPCODE) > this->HVbuf.GetSize())
|
|
{
|
|
if (this->HVbuf.Grow(dwNumVertices * sizeof(D3DFE_CLIPCODE)) != D3D_OK)
|
|
{
|
|
D3D_ERR( "Could not grow clip buffer" );
|
|
ret = DDERR_OUTOFMEMORY;
|
|
return ret;
|
|
}
|
|
this->lpClipFlags = (D3DFE_CLIPCODE*)this->HVbuf.GetAddress();
|
|
}
|
|
DDASSERT(this->dwDP2VertexCount * this->dwOutputSize == this->TLVbuf_Base());
|
|
this->dwVertexBase = this->dwDP2VertexCount;
|
|
DDASSERT(this->dwVertexBase < MAX_DX6_VERTICES);
|
|
dp2data.dwFlags |= D3DHALDP2_SWAPVERTEXBUFFER;
|
|
this->dwDP2VertexCount = this->dwVertexBase + this->dwNumVertices;
|
|
this->lpvOut = this->TLVbuf_GetAddress();
|
|
// try
|
|
// {
|
|
switch (this->primType)
|
|
{
|
|
case D3DPT_POINTLIST:
|
|
this->dwNumPrimitives = dwNumVertices;
|
|
ret = this->pGeometryFuncs->ProcessPrimitive(this);
|
|
break;
|
|
case D3DPT_LINELIST:
|
|
this->dwNumPrimitives = dwNumVertices >> 1;
|
|
ret = this->pGeometryFuncs->ProcessPrimitive(this);
|
|
break;
|
|
case D3DPT_LINESTRIP:
|
|
this->dwNumPrimitives = dwNumVertices - 1;
|
|
ret = this->pGeometryFuncs->ProcessPrimitive(this);
|
|
break;
|
|
case D3DPT_TRIANGLEFAN:
|
|
this->dwNumPrimitives = dwNumVertices - 2;
|
|
ret = this->pGeometryFuncs->ProcessTriangleFan(this);
|
|
break;
|
|
case D3DPT_TRIANGLESTRIP:
|
|
this->dwNumPrimitives = dwNumVertices - 2;
|
|
ret = this->pGeometryFuncs->ProcessTriangleStrip(this);
|
|
break;
|
|
case D3DPT_TRIANGLELIST:
|
|
#ifdef _X86_
|
|
{
|
|
DWORD tmp;
|
|
__asm
|
|
{
|
|
mov eax, 0x55555555 // fractional part of 1.0/3.0
|
|
mul dwNumVertices
|
|
add eax, 0x80000000 // Rounding
|
|
adc edx, 0
|
|
mov tmp, edx
|
|
}
|
|
this->dwNumPrimitives = tmp;
|
|
}
|
|
#else
|
|
this->dwNumPrimitives = dwNumVertices / 3;
|
|
#endif
|
|
ret = this->pGeometryFuncs->ProcessTriangleList(this);
|
|
break;
|
|
}
|
|
// }
|
|
// catch (HRESULT ret)
|
|
// {
|
|
// return ret;
|
|
// }
|
|
D3DFE_UpdateClipStatus(this);
|
|
this->TLVbuf_Base() += this->dwVertexPoolSize;
|
|
DDASSERT(TLVbuf_base <= TLVbuf_size);
|
|
DDASSERT(TLVbuf_base == this->dwDP2VertexCount * this->dwOutputSize);
|
|
return ret;
|
|
}
|
|
VtblDrawPrimitiveVBDefault();
|
|
return DrawPrimitiveVB(dptPrimitiveType, lpVBuf, dwStartVertex, dwNumVertices, dwFlags);
|
|
}
|
|
//---------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "DIRECT3DDEVICEI::DrawIndexedPrimitiveVBFE"
|
|
|
|
HRESULT D3DAPI CDirect3DDeviceIDP2::DrawIndexedPrimitiveVBFE(D3DPRIMITIVETYPE dptPrimitiveType,
|
|
LPDIRECT3DVERTEXBUFFER7 lpVBuf,
|
|
DWORD dwStartVertex, DWORD dwNumVertices,
|
|
LPWORD lpwIndices, DWORD dwIndexCount,
|
|
DWORD dwFlags)
|
|
{
|
|
LPDIRECT3DVERTEXBUFFERI lpVBufI = static_cast<LPDIRECT3DVERTEXBUFFERI>(lpVBuf);
|
|
HRESULT ret;
|
|
#if DBG
|
|
ret = CheckDrawPrimitiveVB(lpVBuf, dwStartVertex, dwNumVertices, dwFlags);
|
|
if (ret != D3D_OK)
|
|
return ret;
|
|
Profile(PROF_DRAWINDEXEDPRIMITIVEVB,dptPrimitiveType,lpVBufI->fvf);
|
|
#endif
|
|
if ((lpVBufI == lpDP2LastVBI) &&
|
|
!(this->dwFEFlags & D3DFE_FRONTEND_DIRTY))
|
|
{
|
|
this->primType = dptPrimitiveType;
|
|
this->dwNumVertices = dwNumVertices;
|
|
this->dwFlags = this->dwLastFlags | dwFlags | lpVBufI->dwPVFlags;
|
|
this->dwVertexBase = 0;
|
|
this->dwNumIndices = dwIndexCount;
|
|
this->lpwIndices = lpwIndices;
|
|
GetNumPrim(this, dwNumIndices); // Calculate dwNumPrimitives
|
|
this->position.lpvData = (BYTE*)(lpVBufI->position.lpvData) +
|
|
dwStartVertex * lpVBufI->position.dwStride;
|
|
#if DBG
|
|
if (dwNumPrimitives > MAX_DX6_PRIMCOUNT)
|
|
{
|
|
D3D_ERR("D3D for DX7 cannot handle greater that 64K sized primitives");
|
|
return D3DERR_TOOMANYPRIMITIVES;
|
|
}
|
|
#endif
|
|
this->dwVertexPoolSize = dwNumVertices * this->dwOutputSize;
|
|
if (this->dwVertexPoolSize > this->TLVbuf_GetSize())
|
|
{
|
|
// try
|
|
// {
|
|
if (this->TLVbuf_Grow(this->dwVertexPoolSize,
|
|
(this->dwDeviceFlags & D3DDEV_DONOTCLIP)!=0) != D3D_OK)
|
|
{
|
|
D3D_ERR( "Could not grow TL vertex buffer" );
|
|
return DDERR_OUTOFMEMORY;
|
|
}
|
|
// }
|
|
// catch (HRESULT ret)
|
|
// {
|
|
// return ret;
|
|
// }
|
|
}
|
|
if (dwNumVertices * sizeof(D3DFE_CLIPCODE) > this->HVbuf.GetSize())
|
|
{
|
|
if (this->HVbuf.Grow(dwNumVertices * sizeof(D3DFE_CLIPCODE)) != D3D_OK)
|
|
{
|
|
D3D_ERR( "Could not grow clip buffer" );
|
|
ret = DDERR_OUTOFMEMORY;
|
|
return ret;
|
|
}
|
|
this->lpClipFlags = (D3DFE_CLIPCODE*)this->HVbuf.GetAddress();
|
|
}
|
|
this->dwVertexBase = this->dwDP2VertexCount;
|
|
DDASSERT(this->dwVertexBase < MAX_DX6_VERTICES);
|
|
dp2data.dwFlags |= D3DHALDP2_SWAPVERTEXBUFFER;
|
|
this->dwDP2VertexCount = this->dwVertexBase + this->dwNumVertices;
|
|
this->lpvOut = this->TLVbuf_GetAddress();
|
|
// try
|
|
// {
|
|
ret = this->pGeometryFuncs->ProcessIndexedPrimitive(this);
|
|
// }
|
|
// catch (HRESULT ret)
|
|
// {
|
|
// return ret;
|
|
// }
|
|
D3DFE_UpdateClipStatus(this);
|
|
this->TLVbuf_Base() += this->dwVertexPoolSize;
|
|
DDASSERT(TLVbuf_base <= TLVbuf_size);
|
|
DDASSERT(TLVbuf_base == this->dwDP2VertexCount * this->dwOutputSize);
|
|
return ret;
|
|
}
|
|
VtblDrawIndexedPrimitiveVBDefault();
|
|
return DrawIndexedPrimitiveVB(dptPrimitiveType, lpVBuf, dwStartVertex, dwNumVertices, lpwIndices, dwIndexCount, dwFlags);
|
|
}
|
|
#endif // VTABLE_HACK
|