Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

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