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

  1. /*==========================================================================;
  2. *
  3. * Copyright (C) 1995 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: vertbuf.cpp
  6. * Content: Direct3DVertexBuffer implementation
  7. *@@BEGIN_MSINTERNAL
  8. *
  9. * History:
  10. * Date By Reason
  11. * ==== == ======
  12. *@@END_MSINTERNAL
  13. *
  14. ***************************************************************************/
  15. #include "pch.cpp"
  16. #pragma hdrstop
  17. #include "drawprim.hpp"
  18. #include "d3dfei.h"
  19. #include "clipfunc.h"
  20. #include "pvvid.h"
  21. // The bit is set when a vertex buffer was the destination in a ProcessVerticesCall
  22. // with clipping enabled. We cannot pass such a buffer to TL HAL, because some vertices
  23. // could be in the screen space and some in the clipping space. There is no DDI to pass
  24. // clip codes together with a vertex buffer
  25. const DWORD D3DPV_CLIPCODESGENERATED = D3DPV_RESERVED2;
  26. const DWORD D3DVOP_RENDER = 1 << 31;
  27. const DWORD D3DVBCAPS_VALID = D3DVBCAPS_SYSTEMMEMORY |
  28. D3DVBCAPS_WRITEONLY |
  29. D3DVBCAPS_OPTIMIZED |
  30. D3DVBCAPS_DONOTCLIP;
  31. void hookVertexBufferToD3D(LPDIRECT3DI lpDirect3DI,
  32. LPDIRECT3DVERTEXBUFFERI lpVBufI)
  33. {
  34. LIST_INSERT_ROOT(&lpDirect3DI->vbufs, lpVBufI, list);
  35. lpVBufI->lpDirect3DI = lpDirect3DI;
  36. lpDirect3DI->numVBufs++;
  37. }
  38. /*
  39. * Direct3DVertexBuffer::QueryInterface
  40. */
  41. #undef DPF_MODNAME
  42. #define DPF_MODNAME "Direct3DVertexBuffer::QueryInterface"
  43. HRESULT D3DAPI CDirect3DVertexBuffer::QueryInterface(REFIID riid, LPVOID* ppvObj)
  44. {
  45. CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock.
  46. #if DBG
  47. if (!VALID_DIRECT3DVERTEXBUFFER_PTR(this)) {
  48. D3D_ERR( "Invalid Direct3DVertexBuffer pointer" );
  49. return DDERR_INVALIDOBJECT;
  50. }
  51. if (!VALID_OUTPTR(ppvObj)) {
  52. D3D_ERR( "Invalid pointer to pointer" );
  53. return DDERR_INVALIDPARAMS;
  54. }
  55. #endif
  56. *ppvObj = NULL;
  57. if(IsEqualIID(riid, IID_IUnknown) ||
  58. IsEqualIID(riid, IID_IDirect3DVertexBuffer7))
  59. {
  60. AddRef();
  61. *ppvObj = static_cast<LPVOID>(static_cast<LPDIRECT3DVERTEXBUFFER7>(this));
  62. return(D3D_OK);
  63. }
  64. else
  65. {
  66. D3D_ERR( "Don't know this riid" );
  67. return (E_NOINTERFACE);
  68. }
  69. } /* CDirect3DVertexBuffer::QueryInterface */
  70. /*
  71. * Direct3DVertexBuffer::AddRef
  72. */
  73. #undef DPF_MODNAME
  74. #define DPF_MODNAME "Direct3DVertexBuffer::AddRef"
  75. ULONG D3DAPI CDirect3DVertexBuffer::AddRef()
  76. {
  77. DWORD rcnt;
  78. CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock.
  79. #if DBG
  80. if (!VALID_DIRECT3DVERTEXBUFFER_PTR(this))
  81. {
  82. D3D_ERR( "Invalid Direct3DVertexBuffer pointer" );
  83. return 0;
  84. }
  85. #endif
  86. this->refCnt++;
  87. rcnt = this->refCnt;
  88. return (rcnt);
  89. } /* Direct3DVertexBuffer::AddRef */
  90. /*
  91. * Direct3DVertexBuffer::Release
  92. *
  93. */
  94. //---------------------------------------------------------------------
  95. #undef DPF_MODNAME
  96. #define DPF_MODNAME "Direct3DVertexBuffer::Release"
  97. ULONG D3DAPI CDirect3DVertexBuffer::Release()
  98. {
  99. DWORD lastrefcnt;
  100. CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock.
  101. #if DBG
  102. if (!VALID_DIRECT3DVERTEXBUFFER_PTR(this))
  103. {
  104. D3D_ERR( "Invalid Direct3DVertexBuffer pointer" );
  105. return 0;
  106. }
  107. #endif
  108. /*
  109. * decrement the ref count. if we hit 0, free the object
  110. */
  111. this->refCnt--;
  112. lastrefcnt = this->refCnt;
  113. if( lastrefcnt == 0 )
  114. {
  115. delete this;
  116. return 0;
  117. }
  118. return lastrefcnt;
  119. } /* D3DTex3_Release */
  120. //---------------------------------------------------------------------
  121. // Internal version.
  122. // No D3D lock, no checks
  123. //
  124. #undef DPF_MODNAME
  125. #define DPF_MODNAME "DIRECT3DI::CreateVertexBufferI"
  126. HRESULT DIRECT3DI::CreateVertexBufferI(LPD3DVERTEXBUFFERDESC lpDesc,
  127. LPDIRECT3DVERTEXBUFFER7 *lplpVBuf,
  128. DWORD dwFlags)
  129. {
  130. CDirect3DVertexBuffer* lpVBufI;
  131. HRESULT ret = D3D_OK;
  132. *lplpVBuf = NULL;
  133. lpVBufI = static_cast<LPDIRECT3DVERTEXBUFFERI>(new CDirect3DVertexBuffer(this));
  134. if (!lpVBufI) {
  135. D3D_ERR("failed to allocate space for vertex buffer");
  136. return (DDERR_OUTOFMEMORY);
  137. }
  138. if ((ret=lpVBufI->Init(this, lpDesc, dwFlags))!=D3D_OK)
  139. {
  140. D3D_ERR("Failed to initialize the vertex buffer object");
  141. delete lpVBufI;
  142. return ret;
  143. }
  144. *lplpVBuf = (LPDIRECT3DVERTEXBUFFER7)lpVBufI;
  145. return(D3D_OK);
  146. }
  147. //---------------------------------------------------------------------
  148. #undef DPF_MODNAME
  149. #define DPF_MODNAME "DIRECT3DI::CreateVertexBuffer"
  150. HRESULT D3DAPI DIRECT3DI::CreateVertexBuffer(
  151. LPD3DVERTEXBUFFERDESC lpDesc,
  152. LPDIRECT3DVERTEXBUFFER7* lplpVBuf,
  153. DWORD dwFlags)
  154. {
  155. CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock.
  156. #if DBG
  157. /*
  158. * validate parms
  159. */
  160. if (!VALID_DIRECT3D_PTR(this))
  161. {
  162. D3D_ERR( "Invalid Direct3D pointer" );
  163. return DDERR_INVALIDOBJECT;
  164. }
  165. if (!VALID_OUTPTR(lplpVBuf))
  166. {
  167. D3D_ERR( "Invalid pointer to pointer pointer" );
  168. return DDERR_INVALIDPARAMS;
  169. }
  170. if ((lpDesc->dwCaps & D3DVBCAPS_VALID) != lpDesc->dwCaps)
  171. {
  172. D3D_ERR("Invalid caps");
  173. return DDERR_INVALIDCAPS;
  174. }
  175. if (dwFlags != 0)
  176. {
  177. D3D_ERR("Invalid dwFlags");
  178. return DDERR_INVALIDPARAMS;
  179. }
  180. #endif
  181. return CreateVertexBufferI(lpDesc, lplpVBuf, dwFlags);
  182. }
  183. #undef DPF_MODNAME
  184. #define DPF_MODNAME "Direct3DVertexBuffer::constructor"
  185. CDirect3DVertexBuffer::CDirect3DVertexBuffer(LPDIRECT3DI lpD3DI)
  186. {
  187. refCnt = 1;
  188. /*
  189. * Put this vertex buffer in the list of those owned by the
  190. * Direct3D object
  191. */
  192. hookVertexBufferToD3D(lpD3DI, this);
  193. srcVOP = dstVOP = dwPVFlags = position.dwStride = dwLockCnt = 0;
  194. position.lpvData = NULL;
  195. clipCodes = NULL;
  196. lpDDSVB = NULL;
  197. dwCaps = 0;
  198. }
  199. #undef DPF_MODNAME
  200. #define DPF_MODNAME "Direct3DVertexBuffer::destructor"
  201. CDirect3DVertexBuffer::~CDirect3DVertexBuffer()
  202. {
  203. /*
  204. * Remove ourselves from the Direct3D object
  205. */
  206. LIST_DELETE(this, list);
  207. this->lpDirect3DI->numVBufs--;
  208. delete [] clipCodes;
  209. if (lpDDSVB)
  210. {
  211. lpDDSVB->Release();
  212. lpDDS1VB->Release();
  213. }
  214. }
  215. //---------------------------------------------------------------------
  216. //
  217. // Create the vertex memory buffer through DirectDraw
  218. //
  219. // Notes:
  220. // this->dwMemType should be set before calling this function
  221. // this->dwCaps should be set too.
  222. // this->dwMemType is set to DDSCAPS_VIDEOMEMORY is the VB was driver allocated
  223. //
  224. #undef DPF_MODNAME
  225. #define DPF_MODNAME "Direct3DVertexBuffer::CreateMemoryBuffer"
  226. HRESULT CDirect3DVertexBuffer::CreateMemoryBuffer(
  227. LPDIRECT3DI lpD3DI,
  228. LPDIRECTDRAWSURFACE7 *lplpSurface7,
  229. LPDIRECTDRAWSURFACE *lplpSurface,
  230. LPVOID *lplpMemory,
  231. DWORD dwBufferSize)
  232. {
  233. HRESULT ret;
  234. DDSURFACEDESC2 ddsd;
  235. memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
  236. ddsd.dwSize = sizeof(DDSURFACEDESC2);
  237. ddsd.dwFlags = DDSD_WIDTH | DDSD_CAPS | DDSD_FVF;
  238. ddsd.dwWidth = dwBufferSize;
  239. ddsd.ddsCaps.dwCaps = DDSCAPS_EXECUTEBUFFER;
  240. ddsd.ddsCaps.dwCaps2 = this->dwMemType;
  241. ddsd.dwFVF = this->fvf; // Let driver know about the FVF
  242. // The meaning of DDSCAPS_VIDEOMEMORY and DDSCAPS_SYSTEMEMORY are
  243. // slightly different in case of VBs. the former only means that
  244. // the buffer is driver allocated and could be in any memory type.
  245. // The latter means that the driver did not care to allocate VBs
  246. // hence they are always in DDraw allocated system memory.
  247. // The reason we try video memory followed by system memory
  248. // (rather than simply not specifying the memory type) is for
  249. // drivers which do not care to do any special VB allocations, we
  250. // do not want DDraw to take the Win16 lock for locking system memory
  251. // surfaces.
  252. bool bTLHAL = DDGBL(lpD3DI)->lpD3DGlobalDriverData &&
  253. (DDGBL(lpD3DI)->lpD3DGlobalDriverData->hwCaps.dwDevCaps &
  254. D3DDEVCAPS_HWTRANSFORMANDLIGHT);
  255. if ((this->dwCaps & D3DVBCAPS_SYSTEMMEMORY) || !(bTLHAL || FVF_TRANSFORMED(fvf)))
  256. {
  257. // This VB cannot reside in driver friendly memory since either:
  258. // 1. The app explicitly specified system memory
  259. // 2. The vertex buffer is untransformed and it is not a T&L hal
  260. // thus the driver will never see this VB
  261. D3D_INFO(8, "Trying to create a sys mem vertex buffer");
  262. ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
  263. ret = lpD3DI->lpDD7->CreateSurface(&ddsd, lplpSurface7, NULL);
  264. if (ret != DD_OK)
  265. {
  266. D3D_ERR("Could not allocate the Vertex buffer.");
  267. return ret;
  268. }
  269. }
  270. else
  271. {
  272. // Try explicit video memory first
  273. ddsd.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY;
  274. if ((this->dwCaps & D3DVBCAPS_DONOTCLIP) || bTLHAL)
  275. ddsd.ddsCaps.dwCaps |= this->dwCaps & DDSCAPS_WRITEONLY;
  276. D3D_INFO(8, "Trying to create a vid mem vertex buffer");
  277. #ifdef __DISABLE_VIDMEM_VBS__
  278. if ((lpD3DI->bDisableVidMemVBs == TRUE) ||
  279. (lpD3DI->lpDD7->CreateSurface(&ddsd, lplpSurface7, NULL) != DD_OK))
  280. #else //__DISABLE_VIDMEM_VBS__
  281. if (lpD3DI->lpDD7->CreateSurface(&ddsd, lplpSurface7, NULL) != DD_OK)
  282. #endif //__DISABLE_VIDMEM_VBS__
  283. {
  284. // If that failed, or user requested sys mem, try explicit system
  285. // memory
  286. D3D_INFO(6, "Trying to create a sys mem vertex buffer");
  287. ddsd.ddsCaps.dwCaps &= ~(DDSCAPS_VIDEOMEMORY | DDSCAPS_WRITEONLY);
  288. ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
  289. ret = lpD3DI->lpDD7->CreateSurface(&ddsd, lplpSurface7, NULL);
  290. if (ret != DD_OK)
  291. {
  292. D3D_ERR("Could not allocate the Vertex buffer.");
  293. return ret;
  294. }
  295. }
  296. else
  297. {
  298. this->dwMemType = DDSCAPS_VIDEOMEMORY;
  299. // Stick in our pointer so that we can be notified about mode changes
  300. DDSLCL(*lplpSurface7)->lpSurfMore->lpVB = static_cast<LPVOID>(this);
  301. }
  302. }
  303. ret = (*lplpSurface7)->QueryInterface(IID_IDirectDrawSurfaceNew, (LPVOID*)lplpSurface);
  304. if (ret != DD_OK)
  305. {
  306. D3D_ERR("failed to QI for DDS1");
  307. return ret;
  308. }
  309. ret = (*lplpSurface7)->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_NOSYSLOCK, NULL);
  310. if (ret != DD_OK)
  311. {
  312. D3D_ERR("Could not lock vertex buffer.");
  313. return ret;
  314. }
  315. *lplpMemory = ddsd.lpSurface;
  316. return D3D_OK;
  317. }
  318. //---------------------------------------------------------------------
  319. #undef DPF_MODNAME
  320. #define DPF_MODNAME "Direct3DVertexBuffer::init"
  321. HRESULT CDirect3DVertexBuffer::Init(LPDIRECT3DI lpD3DI, LPD3DVERTEXBUFFERDESC lpDesc, DWORD dwFlags)
  322. {
  323. HRESULT ret;
  324. bReallyOptimized = FALSE;
  325. dwCaps = lpDesc->dwCaps;
  326. fvf = lpDesc->dwFVF;
  327. dwNumVertices = lpDesc->dwNumVertices;
  328. #ifdef VTABLE_HACK
  329. // Copy with vtable
  330. lpVtbl = *((LPVOID**)this);
  331. memcpy(newVtbl, lpVtbl, sizeof(PVOID)*D3DVB_NUM_VIRTUAL_FUNCTIONS);
  332. // Point to the new one
  333. *((LPVOID*)this) = (LPVOID)newVtbl;
  334. #endif // VTABLE_HACK
  335. if (dwNumVertices > MAX_DX6_VERTICES)
  336. {
  337. D3D_ERR("Direct3D for DirectX 6.0 cannot handle greater than 64K vertices");
  338. return D3DERR_TOOMANYVERTICES;
  339. }
  340. if (lpDesc->dwCaps & D3DVBCAPS_OPTIMIZED)
  341. {
  342. D3D_ERR("D3DVBCAPS_OPTIMIZED flag should not be set");
  343. return DDERR_INVALIDPARAMS;
  344. }
  345. this->nTexCoord = FVF_TEXCOORD_NUMBER(fvf);
  346. this->dwTexCoordSizeTotal = ComputeTextureCoordSize(this->fvf, this->dwTexCoordSize);
  347. position.dwStride = GetVertexSizeFVF(this->fvf) + this->dwTexCoordSizeTotal;
  348. if (position.dwStride == 0)
  349. {
  350. D3D_ERR("Vertex size is zero according to the FVF id");
  351. return D3DERR_INVALIDVERTEXFORMAT;
  352. }
  353. if (dwFlags & D3DVBFLAGS_CREATEMULTIBUFFER)
  354. dwMemType = 0;
  355. else
  356. dwMemType = DDSCAPS2_VERTEXBUFFER;
  357. #ifdef DBG
  358. // Allocate space for one more vertex and fill with deadbeef. Used to check for
  359. // overwrites during unlock
  360. ret = CreateMemoryBuffer(lpD3DI, &lpDDSVB, &lpDDS1VB, &position.lpvData,
  361. position.dwStride * (dwNumVertices + 1));
  362. if (ret != D3D_OK)
  363. return ret;
  364. LPDWORD pPad = (LPDWORD)((LPBYTE)(position.lpvData) + position.dwStride * dwNumVertices);
  365. for (unsigned i = 0; i < position.dwStride / sizeof(DWORD); ++i)
  366. *pPad++ = 0xdeadbeef;
  367. #else
  368. ret = CreateMemoryBuffer(lpD3DI, &lpDDSVB, &lpDDS1VB, &position.lpvData,
  369. position.dwStride * dwNumVertices);
  370. if (ret != D3D_OK)
  371. return ret;
  372. #endif
  373. /* Classify the operations that can be done using this VB */
  374. if ((fvf & D3DFVF_POSITION_MASK))
  375. {
  376. if ((fvf & D3DFVF_POSITION_MASK) != D3DFVF_XYZRHW)
  377. {
  378. D3D_INFO(4, "D3DFVF_XYZ set. Can be source VB for Transform");
  379. srcVOP = D3DVOP_TRANSFORM | D3DVOP_EXTENTS | D3DVOP_CLIP;
  380. }
  381. else
  382. {
  383. D3D_INFO(4, "D3DFVF_XYZRHW set. Can be dest VB for Transform");
  384. dstVOP = D3DVOP_TRANSFORM | D3DVOP_EXTENTS;
  385. srcVOP = D3DVOP_EXTENTS;
  386. if ((dwCaps & D3DVBCAPS_DONOTCLIP) == 0)
  387. {
  388. clipCodes = new D3DFE_CLIPCODE[dwNumVertices];
  389. if (clipCodes == NULL)
  390. {
  391. D3D_ERR("Could not allocate space for clip flags");
  392. return DDERR_OUTOFMEMORY;
  393. }
  394. memset(clipCodes, 0, dwNumVertices * sizeof(D3DFE_CLIPCODE));
  395. dstVOP |= D3DVOP_CLIP;
  396. }
  397. }
  398. }
  399. if (srcVOP & D3DVOP_TRANSFORM)
  400. {
  401. D3D_INFO(4, "Can be src VB for lighting.");
  402. srcVOP |= D3DVOP_LIGHT;
  403. }
  404. if (fvf & D3DFVF_DIFFUSE)
  405. {
  406. D3D_INFO(4, "D3DFVF_DIFFUSE set. Can be dest VB for lighting");
  407. dstVOP |= D3DVOP_LIGHT;
  408. }
  409. if (dstVOP & D3DVOP_TRANSFORM)
  410. {
  411. D3D_INFO(4, "VB can be rendered");
  412. srcVOP |= D3DVOP_RENDER;
  413. }
  414. return(D3D_OK);
  415. }
  416. #undef DPF_MODNAME
  417. #define DPF_MODNAME "Direct3DVertexBuffer::Lock"
  418. HRESULT D3DAPI CDirect3DVertexBuffer::Lock(DWORD dwFlags, LPVOID* lplpData, DWORD* lpdwSize)
  419. {
  420. CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock.
  421. HRESULT ret;
  422. #if DBG
  423. if (!VALID_DIRECT3DVERTEXBUFFER_PTR(this))
  424. {
  425. D3D_ERR( "Invalid Direct3DVertexBuffer pointer" );
  426. return DDERR_INVALIDPARAMS;
  427. }
  428. if (IsBadWritePtr( lplpData, sizeof(LPVOID)))
  429. {
  430. D3D_ERR( "Invalid lpData pointer" );
  431. return DDERR_INVALIDPARAMS;
  432. }
  433. if (lpdwSize)
  434. {
  435. if (IsBadWritePtr( lpdwSize, sizeof(DWORD)))
  436. {
  437. D3D_ERR( "Invalid lpData pointer" );
  438. return DDERR_INVALIDPARAMS;
  439. }
  440. }
  441. #endif
  442. if (this->dwCaps & D3DVBCAPS_OPTIMIZED)
  443. {
  444. D3D_ERR("Cannot lock optimized vertex buffer");
  445. return(D3DERR_VERTEXBUFFEROPTIMIZED);
  446. }
  447. if (!this->position.lpvData)
  448. {
  449. // Unlock if previous lock was broken due to mode switch
  450. if (DDSGBL(lpDDSVB)->dwUsageCount > 0)
  451. {
  452. DDASSERT(DDSGBL(lpDDSVB)->dwUsageCount == 1);
  453. D3D_INFO(2, "Lock: Unlocking broken VB lock");
  454. lpDDSVB->Unlock(NULL);
  455. }
  456. if (lpDevIBatched)
  457. {
  458. ret = lpDevIBatched->FlushStates();
  459. if (ret != D3D_OK)
  460. {
  461. D3D_ERR("Could not flush batch referring to VB during Lock");
  462. return ret;
  463. }
  464. }
  465. #ifdef DBG
  466. LPVOID pOldBuf = (LPVOID)((LPDDRAWI_DDRAWSURFACE_INT)lpDDSVB)->lpLcl->lpGbl->fpVidMem;
  467. #endif // DBG
  468. // Do a real Lock
  469. DDSURFACEDESC2 ddsd;
  470. memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
  471. ddsd.dwSize = sizeof(DDSURFACEDESC2);
  472. ret = lpDDSVB->Lock(NULL, &ddsd, dwFlags | DDLOCK_NOSYSLOCK, NULL);
  473. if (ret != DD_OK)
  474. {
  475. D3D_ERR("Lock: Could not lock Vertex Buffer: %08x", ret);
  476. return ret;
  477. }
  478. position.lpvData = ddsd.lpSurface;
  479. #if DBG
  480. if(ddsd.lpSurface != pOldBuf)
  481. {
  482. D3D_INFO(2, "Driver swapped VB pointer in Lock");
  483. }
  484. LPDWORD pPad = (LPDWORD)((LPBYTE)(position.lpvData) + position.dwStride * dwNumVertices);
  485. for (unsigned i = 0; i < position.dwStride / sizeof(DWORD); ++i)
  486. *pPad++ = 0xdeadbeef;
  487. #endif
  488. }
  489. #ifdef VTABLE_HACK
  490. /* Single threaded or Multi threaded app ? */
  491. if (!(((LPDDRAWI_DIRECTDRAW_INT)lpDirect3DI->lpDD)->lpLcl->dwLocalFlags & DDRAWILCL_MULTITHREADED))
  492. VtblLockFast();
  493. #endif // VTABLE_HACK
  494. return this->LockI(dwFlags, lplpData, lpdwSize);
  495. }
  496. //---------------------------------------------------------------------
  497. // Side effect:
  498. // position.lpvData is set.
  499. //
  500. #undef DPF_MODNAME
  501. #define DPF_MODNAME "Direct3DVertexBuffer::LockI"
  502. HRESULT D3DAPI CDirect3DVertexBuffer::LockI(DWORD dwFlags, LPVOID* lplpData,
  503. DWORD* lpdwSize)
  504. {
  505. dwLockCnt++;
  506. D3D_INFO(6, "VB Lock: %lx Lock Cnt =%d", this, dwLockCnt);
  507. if (!(dwFlags & (DDLOCK_READONLY | DDLOCK_NOOVERWRITE)) && lpDevIBatched)
  508. {
  509. HRESULT ret;
  510. if (dwFlags & DDLOCK_OKTOSWAP)
  511. {
  512. ret = lpDevIBatched->FlushStatesReq(position.dwStride * dwNumVertices);
  513. #if DBG
  514. if (!(this->dwCaps & D3DVBCAPS_OPTIMIZED))
  515. {
  516. // Make sure the size of the new buffer is the same
  517. DDASSERT(position.dwStride * (dwNumVertices + 1) <= DDSGBL(lpDDSVB)->dwLinearSize);
  518. // Write deadbeaf in the pad area
  519. LPDWORD pPad = (LPDWORD)((LPBYTE)(position.lpvData) + position.dwStride * dwNumVertices);
  520. for (unsigned i = 0; i < position.dwStride / sizeof(DWORD); ++i)
  521. *pPad++ = 0xdeadbeef;
  522. }
  523. #endif
  524. }
  525. else
  526. ret = lpDevIBatched->FlushStates();
  527. if (ret != D3D_OK)
  528. {
  529. D3D_ERR("Could not flush batch referring to VB during Lock");
  530. return ret;
  531. }
  532. }
  533. *lplpData = position.lpvData;
  534. if (lpdwSize)
  535. *lpdwSize = position.dwStride * dwNumVertices;
  536. return D3D_OK;
  537. }
  538. #undef DPF_MODNAME
  539. #define DPF_MODNAME "Direct3DVertexBuffer::Unlock"
  540. HRESULT D3DAPI CDirect3DVertexBuffer::Unlock()
  541. {
  542. if (dwLockCnt)
  543. {
  544. dwLockCnt--;
  545. }
  546. #ifdef DBG
  547. if (!(this->dwCaps & D3DVBCAPS_OPTIMIZED))
  548. {
  549. // Check for VB overruns
  550. LPDWORD pPad = (LPDWORD)((LPBYTE)(position.lpvData) + position.dwStride * dwNumVertices);
  551. for (unsigned i = 0; i < position.dwStride / sizeof(DWORD); ++i)
  552. if (*pPad++ != 0xdeadbeef)
  553. {
  554. D3D_ERR("Vertex buffer was overrun. Make sure that you do not write past the VB size!");
  555. return D3DERR_VERTEXBUFFERUNLOCKFAILED;
  556. }
  557. D3D_INFO(6, "VB Unlock: %lx Lock Cnt =%d", this, dwLockCnt);
  558. }
  559. #endif
  560. return D3D_OK;
  561. }
  562. // Called from FlushStates to undo cached VB pointer so that the next lock causes a driver lock
  563. // This is necessary if the we did not flush with SWAPVERTEXBUFFER.
  564. void CDirect3DVertexBuffer::UnlockI()
  565. {
  566. if ((this->dwMemType == DDSCAPS_VIDEOMEMORY) && (dwLockCnt == 0))
  567. {
  568. #ifdef VTABLE_HACK
  569. VtblLockDefault();
  570. #endif
  571. lpDDSVB->Unlock(NULL);
  572. position.lpvData = 0;
  573. }
  574. else if (dwLockCnt !=0 )
  575. {
  576. D3D_WARN(4, "App has a lock on VB %08x so driver call may be slow", this);
  577. }
  578. }
  579. #ifndef WIN95
  580. #undef DPF_MODNAME
  581. #define DPF_MODNAME "Direct3DVertexBuffer::LockWorkAround"
  582. HRESULT CDirect3DVertexBuffer::LockWorkAround(CDirect3DDeviceIDP2 *pDev)
  583. {
  584. if (this->dwMemType == DDSCAPS_VIDEOMEMORY)
  585. {
  586. #ifdef DBG
  587. LPVOID pOldBuf = (LPVOID)((LPDDRAWI_DDRAWSURFACE_INT)lpDDSVB)->lpLcl->lpGbl->fpVidMem;
  588. #endif // DBG
  589. // Do a real Lock
  590. DDSURFACEDESC2 ddsd;
  591. memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
  592. ddsd.dwSize = sizeof(DDSURFACEDESC2);
  593. HRESULT ret = lpDDSVB->Lock(NULL, &ddsd, DDLOCK_OKTOSWAP | DDLOCK_NOSYSLOCK, NULL);
  594. if (ret != DD_OK)
  595. {
  596. D3D_ERR("Lock: Could not lock Vertex Buffer: %08x", ret);
  597. return ret;
  598. }
  599. position.lpvData = ddsd.lpSurface;
  600. pDev->alignedBuf = ddsd.lpSurface;
  601. #ifdef DBG
  602. if(ddsd.lpSurface != pOldBuf)
  603. {
  604. D3D_INFO(2, "Driver swapped TLVBuf pointer in Lock");
  605. }
  606. #endif
  607. // Make sure the size of the new buffer is the same
  608. DDASSERT(position.dwStride * (dwNumVertices + 1) <= DDSGBL(lpDDSVB)->dwLinearSize);
  609. }
  610. return D3D_OK;
  611. }
  612. #undef DPF_MODNAME
  613. #define DPF_MODNAME "Direct3DVertexBuffer::UnlockWorkAround"
  614. void CDirect3DVertexBuffer::UnlockWorkAround()
  615. {
  616. if ((this->dwMemType == DDSCAPS_VIDEOMEMORY) &&
  617. (position.lpvData != 0))
  618. {
  619. lpDDSVB->Unlock(NULL);
  620. position.lpvData = 0;
  621. }
  622. }
  623. #endif // WIN95
  624. // Cause us to go thru the slow path and force a lock
  625. // The slow path will do the unlock if necessary. This
  626. // is because we are called from DDraw's invalidate
  627. // surface code and it might not be the best time to
  628. // call back ddraw to unlock the surface.
  629. void CDirect3DVertexBuffer::BreakLock()
  630. {
  631. D3D_INFO(6, "Notified of restore on VB %08x", this);
  632. #ifdef VTABLE_HACK
  633. VtblLockDefault();
  634. #endif
  635. position.lpvData = 0;
  636. }
  637. #undef DPF_MODNAME
  638. #define DPF_MODNAME "Direct3DVertexBuffer::GetVertexBufferDesc"
  639. HRESULT D3DAPI CDirect3DVertexBuffer::GetVertexBufferDesc(LPD3DVERTEXBUFFERDESC lpDesc)
  640. {
  641. #if DBG
  642. if (!VALID_DIRECT3DVERTEXBUFFER_PTR(this))
  643. {
  644. D3D_ERR( "Invalid Direct3DVertexBuffer pointer" );
  645. return DDERR_INVALIDPARAMS;
  646. }
  647. if (IsBadWritePtr( lpDesc, lpDesc->dwSize))
  648. {
  649. D3D_ERR( "Invalid lpData pointer" );
  650. return DDERR_INVALIDPARAMS;
  651. }
  652. if (! VALID_D3DVERTEXBUFFERDESC_PTR(lpDesc) )
  653. {
  654. D3D_ERR( "Invalid D3DVERTEXBUFFERDESC" );
  655. return DDERR_INVALIDPARAMS;
  656. }
  657. #endif
  658. lpDesc->dwCaps = dwCaps;
  659. lpDesc->dwFVF = fvf;
  660. lpDesc->dwNumVertices = this->dwNumVertices;
  661. return D3D_OK;
  662. }
  663. //---------------------------------------------------------------------
  664. // Common validation for ProcessVertices and ProcessVerticesStrided
  665. //
  666. HRESULT CDirect3DVertexBuffer::ValidateProcessVertices(
  667. DWORD vertexOP,
  668. DWORD dwDstIndex,
  669. DWORD dwCount,
  670. LPVOID lpSrc,
  671. LPDIRECT3DDEVICE7 lpDevice,
  672. DWORD dwFlags)
  673. {
  674. if (!VALID_DIRECT3DVERTEXBUFFER_PTR(this))
  675. {
  676. D3D_ERR( "Invalid destination Direct3DVertexBuffer pointer" );
  677. return DDERR_INVALIDPARAMS;
  678. }
  679. if (!VALID_DIRECT3DDEVICE_PTR(lpDevice))
  680. {
  681. D3D_ERR( "Invalid Direct3DDevice pointer" );
  682. return DDERR_INVALIDOBJECT;
  683. }
  684. LPDIRECT3DDEVICEI lpDevI = static_cast<LPDIRECT3DDEVICEI>(lpDevice);
  685. if (lpDevI->ValidateFVF(this->fvf) != D3D_OK)
  686. {
  687. D3D_ERR("Invalid vertex buffer FVF for the device");
  688. return DDERR_INVALIDPARAMS;
  689. }
  690. if (dwFlags & ~D3DPV_DONOTCOPYDATA)
  691. {
  692. D3D_ERR( "Invalid dwFlags set" );
  693. return DDERR_INVALIDPARAMS;
  694. }
  695. if ((dwDstIndex + dwCount) > this->dwNumVertices)
  696. {
  697. D3D_ERR( "Vertex count plus destination index is greater than number of vertices" );
  698. return DDERR_INVALIDPARAMS;
  699. }
  700. // Validate Dst Vertex Formats
  701. if (lpSrc)
  702. {
  703. if ((this->dstVOP & vertexOP) != vertexOP)
  704. goto error;
  705. }
  706. else
  707. {
  708. if ((this->fvf & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW)
  709. {
  710. if (vertexOP & ~(D3DVOP_CLIP | D3DVOP_EXTENTS))
  711. goto error;
  712. }
  713. else
  714. {
  715. if (vertexOP & ~(D3DVOP_CLIP))
  716. goto error;
  717. }
  718. }
  719. return D3D_OK;
  720. error:
  721. D3D_ERR("Destination VB cannot support this operation");
  722. return D3DERR_INVALIDVERTEXFORMAT;
  723. }
  724. //---------------------------------------------------------------------
  725. // Common part for ProcessVertices and ProcessVerticesStrided
  726. //
  727. HRESULT CDirect3DVertexBuffer::DoProcessVertices(
  728. LPDIRECT3DVERTEXBUFFERI lpSrcI,
  729. LPDIRECT3DDEVICEI lpDevI,
  730. DWORD vertexOP,
  731. DWORD dwSrcIndex,
  732. DWORD dwDstIndex,
  733. DWORD dwFlags)
  734. {
  735. lpDevI->lpClipFlags = clipCodes + dwDstIndex;
  736. // Compute needed output FVF
  737. {
  738. DWORD dwInputVertexSize;
  739. HRESULT ret = lpDevI->SetupFVFDataCommon(&dwInputVertexSize);
  740. if (ret != D3D_OK)
  741. return ret;
  742. // Make sure we have specular in output VB if the current state settings
  743. // require us to write to specular
  744. if (vertexOP & D3DVOP_LIGHT)
  745. if (lpDevI->rstates[D3DRENDERSTATE_SPECULARENABLE] || lpDevI->rstates[D3DRENDERSTATE_FOGENABLE])
  746. if (!(fvf & D3DFVF_SPECULAR))
  747. {
  748. D3D_ERR("Destination VB FVF format cannot be used with the current D3D settings");
  749. return D3DERR_INVALIDVERTEXFORMAT;
  750. }
  751. // Check number of texture coordinates and texture formats in the
  752. // destination VB are the same as in the computed FVF
  753. DWORD dwComputedOutFVF = lpDevI->dwVIDOut & 0xFFFF0000;
  754. if (lpDevI->nOutTexCoord > this->nTexCoord ||
  755. ((fvf & dwComputedOutFVF) != dwComputedOutFVF))
  756. {
  757. D3D_ERR("Destination VB FVF format cannot be used with the current D3D settings");
  758. return D3DERR_INVALIDVERTEXFORMAT;
  759. }
  760. }
  761. // Output
  762. lpDevI->lpvOut = LPVOID(LPBYTE(position.lpvData) + dwDstIndex * position.dwStride);
  763. lpDevI->dwOutputSize = this->position.dwStride;
  764. lpDevI->dwVIDOut = fvf;
  765. // Set up vertex pointers, because SetupFVFData works with "computed" FVF
  766. UpdateGeometryLoopData(lpDevI);
  767. // Save current flags to restore later
  768. DWORD dwOrigDeviceFlags = lpDevI->dwDeviceFlags;
  769. if (vertexOP & D3DVOP_CLIP)
  770. {
  771. lpDevI->dwDeviceFlags &= ~D3DDEV_DONOTCLIP;
  772. this->dwPVFlags |= D3DPV_CLIPCODESGENERATED;
  773. }
  774. else
  775. {
  776. lpDevI->dwDeviceFlags |= D3DDEV_DONOTCLIP;
  777. }
  778. if (vertexOP & D3DVOP_LIGHT)
  779. lpDevI->dwDeviceFlags |= D3DDEV_LIGHTING;
  780. else
  781. lpDevI->dwDeviceFlags &= ~D3DDEV_LIGHTING;
  782. if (vertexOP & D3DVOP_EXTENTS)
  783. {
  784. lpDevI->dwDeviceFlags &= ~D3DDEV_DONOTUPDATEEXTENTS;
  785. }
  786. else
  787. {
  788. lpDevI->dwDeviceFlags |= D3DDEV_DONOTUPDATEEXTENTS;
  789. }
  790. DoUpdateState(lpDevI);
  791. if (lpSrcI)
  792. {
  793. if (lpSrcI->bReallyOptimized)
  794. { // SOA
  795. // Assume that SOA.lpvData is the same as position.lpvData
  796. lpDevI->SOA.lpvData = lpSrcI->position.lpvData;
  797. lpDevI->SOA.dwStride = lpSrcI->dwNumVertices;
  798. lpDevI->dwSOAStartVertex = dwSrcIndex;
  799. lpDevI->dwOutputSize = position.dwStride;
  800. }
  801. else
  802. { // AOS FVF
  803. lpDevI->dwOutputSize = position.dwStride;
  804. lpDevI->position.lpvData = LPVOID(LPBYTE(lpSrcI->position.lpvData) + dwSrcIndex * lpSrcI->position.dwStride);
  805. lpDevI->position.dwStride = lpSrcI->position.dwStride;
  806. }
  807. }
  808. if (dwFlags & D3DPV_DONOTCOPYDATA)
  809. {
  810. lpDevI->dwFlags |= D3DPV_DONOTCOPYDIFFUSE | D3DPV_DONOTCOPYSPECULAR |
  811. D3DPV_DONOTCOPYTEXTURE;
  812. // If D3DIM generates colors or texture, we should clear DONOTCOPY bits
  813. if (lpDevI->dwFlags & D3DPV_LIGHTING)
  814. {
  815. lpDevI->dwFlags &= ~D3DPV_DONOTCOPYDIFFUSE;
  816. if (lpDevI->dwDeviceFlags & D3DDEV_SPECULARENABLE)
  817. lpDevI->dwFlags &= ~D3DPV_DONOTCOPYSPECULAR;
  818. }
  819. if (lpDevI->dwFlags & D3DPV_FOG)
  820. lpDevI->dwFlags &= ~D3DPV_DONOTCOPYSPECULAR;
  821. // If front-end is asked to do something with texture coordinates
  822. // we disable DONOTCOPYTEXTURE
  823. if (__TEXTURETRANSFORMENABLED(lpDevI) || lpDevI->dwFlags2 & __FLAGS2_TEXGEN)
  824. {
  825. lpDevI->dwFlags &= ~D3DPV_DONOTCOPYTEXTURE;
  826. }
  827. }
  828. lpDevI->pGeometryFuncs->ProcessVertices(lpDevI);
  829. // This bit should be cleared, because for ProcessVertices calls user should
  830. // set texture stage indices and wrap modes himself
  831. lpDevI->dwDeviceFlags &= ~D3DDEV_REMAPTEXTUREINDICES;
  832. if (!(lpDevI->dwDeviceFlags & D3DDEV_DONOTCLIP))
  833. D3DFE_UpdateClipStatus(lpDevI);
  834. // Restore _DONOTCLIP & _DONOTUPDATEEXTENTS flags
  835. const DWORD PRESERVED_FLAGS = D3DDEV_DONOTCLIP |
  836. D3DDEV_DONOTUPDATEEXTENTS |
  837. D3DDEV_LIGHTING;
  838. lpDevI->dwDeviceFlags = (dwOrigDeviceFlags & PRESERVED_FLAGS) |
  839. (lpDevI->dwDeviceFlags & ~PRESERVED_FLAGS);
  840. // Force recompute fvf next time around
  841. lpDevI->ForceFVFRecompute();
  842. // Unlock the VB
  843. Unlock();
  844. // If we used SOA then the dwVIDIn <-> position.dwStride relationship
  845. // violated. This fixes that. This is required since in non VB code
  846. // we will not recompute position.dwStride if FVF matched dwVIDIn.
  847. if (lpSrcI)
  848. lpDevI->position.dwStride = lpSrcI->position.dwStride;
  849. return D3D_OK;
  850. }
  851. //---------------------------------------------------------------------
  852. // lpSrc should be NULL for XYZRHW buffers
  853. //
  854. #undef DPF_MODNAME
  855. #define DPF_MODNAME "Direct3DVertexBuffer::ProcessVertices"
  856. HRESULT D3DAPI CDirect3DVertexBuffer::ProcessVertices(DWORD vertexOP, DWORD dwDstIndex, DWORD dwCount,
  857. LPDIRECT3DVERTEXBUFFER7 lpSrc,
  858. DWORD dwSrcIndex,
  859. LPDIRECT3DDEVICE7 lpDevice, DWORD dwFlags)
  860. {
  861. LPDIRECT3DVERTEXBUFFERI lpSrcI;
  862. LPDIRECT3DDEVICEI lpDevI;
  863. HRESULT ret = D3D_OK;
  864. #if DBG
  865. ret = this->ValidateProcessVertices(vertexOP, dwDstIndex, dwCount, lpSrc, lpDevice, dwFlags);
  866. if (ret != D3D_OK)
  867. return ret;
  868. lpDevI = static_cast<LPDIRECT3DDEVICEI>(lpDevice);
  869. if (lpSrc != NULL)
  870. {
  871. if (!VALID_DIRECT3DVERTEXBUFFER_PTR(lpSrc))
  872. {
  873. D3D_ERR( "Invalid Direct3DVertexBuffer pointer" );
  874. return DDERR_INVALIDPARAMS;
  875. }
  876. lpSrcI = static_cast<LPDIRECT3DVERTEXBUFFERI>(lpSrc);
  877. if (lpDevI->ValidateFVF(lpSrcI->fvf) != D3D_OK)
  878. {
  879. D3D_ERR("Invalid source vertex buffer FVF for the device");
  880. return DDERR_INVALIDPARAMS;
  881. }
  882. // Validate Src Vertex Formats
  883. if ((lpSrcI->srcVOP & vertexOP) != vertexOP)
  884. {
  885. D3D_ERR("Source VB cannot support this operation");
  886. return D3DERR_INVALIDVERTEXFORMAT;
  887. }
  888. if ((dwSrcIndex + dwCount) > lpSrcI->dwNumVertices)
  889. {
  890. D3D_ERR( "Source index plus vertex count is greater than number of vertices" );
  891. return DDERR_INVALIDPARAMS;
  892. }
  893. if (!(vertexOP & D3DVOP_TRANSFORM))
  894. {
  895. D3D_ERR("D3DVOP_TRANSFORM flag should be set");
  896. return DDERR_INVALIDPARAMS;
  897. }
  898. // Source to ProcessVertices must be in system memory. This is for reasons similar
  899. // to why we insist on sys mem VB for SW rast. For instance, a driver may have optimized
  900. // the VB into some cryptic format which D3D FE will have no clue to decipher.
  901. if (!(lpSrcI->dwCaps & D3DVBCAPS_SYSTEMMEMORY))
  902. {
  903. D3D_ERR("Source VB must be created with D3DVBCAPS_SYSTEMMEMORY");
  904. return DDERR_INVALIDPARAMS;
  905. }
  906. }
  907. #else
  908. lpSrcI = static_cast<LPDIRECT3DVERTEXBUFFERI>(lpSrc);
  909. lpDevI = static_cast<LPDIRECT3DDEVICEI>(lpDevice);
  910. #endif
  911. CLockD3DMT lockObject(lpDevI, DPF_MODNAME, REMIND("")); // Takes D3D lock.
  912. lpDevI->dwNumVertices = dwCount;
  913. // Lock the VBs
  914. LPVOID lpVoid;
  915. // We call the API level lock since dest VB may be in vid mem. This function will fail for
  916. // optimized VBs and that is OK since we cannot write out optimized vertices anyway.
  917. ret = Lock(DDLOCK_WAIT, &lpVoid, NULL);
  918. if (ret != D3D_OK)
  919. {
  920. D3D_ERR("Could not lock the vertex buffer");
  921. return ret;
  922. }
  923. if (lpSrc == NULL)
  924. {
  925. lpDevI->lpvOut = LPVOID(LPBYTE(position.lpvData) + dwDstIndex * position.dwStride);
  926. if ((fvf & D3DFVF_POSITION_MASK) != D3DFVF_XYZRHW)
  927. {
  928. if (vertexOP & D3DVOP_CLIP)
  929. {
  930. CD3DFPstate D3DFPstate; // Sets optimal FPU state for D3D.
  931. if (lpDevI->dwFEFlags & (D3DFE_TRANSFORM_DIRTY | D3DFE_CLIPPLANES_DIRTY))
  932. {
  933. DoUpdateState(lpDevI);
  934. }
  935. lpDevI->CheckClipStatus((D3DVALUE*)lpDevI->lpvOut,
  936. position.dwStride,
  937. dwCount,
  938. &lpDevI->dwClipUnion,
  939. &lpDevI->dwClipIntersection);
  940. D3DFE_UpdateClipStatus(lpDevI);
  941. }
  942. }
  943. else
  944. {
  945. // For transformed vertices we support only clip code generation and extens
  946. lpDevI->lpClipFlags = clipCodes + dwDstIndex;
  947. lpDevI->position.lpvData = lpDevI->lpvOut;
  948. lpDevI->position.dwStride = position.dwStride;
  949. lpDevI->dwOutputSize = position.dwStride;
  950. if (vertexOP & D3DVOP_CLIP)
  951. {
  952. D3DFE_GenClipFlags(lpDevI);
  953. D3DFE_UpdateClipStatus(lpDevI);
  954. // Mark this buffer as "transformed" for clipping
  955. dwPVFlags |= D3DPV_TLVCLIP;
  956. }
  957. if (vertexOP & D3DVOP_EXTENTS)
  958. {
  959. D3DFE_updateExtents(lpDevI);
  960. }
  961. }
  962. Unlock();
  963. return D3D_OK;
  964. }
  965. // Safe to LockI since source is guaranteed to be in system memory
  966. // Cannot call API Lock since we need to be able to lock optimized VBs
  967. ret = lpSrcI->LockI(DDLOCK_WAIT | DDLOCK_READONLY, &lpVoid, NULL);
  968. if (ret != D3D_OK)
  969. {
  970. D3D_ERR("Could not lock the vertex buffer");
  971. return ret;
  972. }
  973. dwPVFlags &= ~D3DPV_TLVCLIP; // Mark the dest VB as "not transformed" for clipping
  974. lpDevI->dwFlags = (lpSrcI->dwPVFlags & D3DPV_SOA) | D3DPV_VBCALL;
  975. lpDevI->dwDeviceFlags &= ~D3DDEV_STRIDE;
  976. // Input
  977. lpDevI->dwVIDIn = lpSrcI->fvf;
  978. ret = this->DoProcessVertices(lpSrcI, lpDevI, vertexOP, dwSrcIndex, dwDstIndex, dwFlags);
  979. if (ret != D3D_OK)
  980. lpSrcI->Unlock();
  981. else
  982. ret = lpSrc->Unlock();
  983. return ret;
  984. }
  985. //---------------------------------------------------------------------
  986. #undef DPF_MODNAME
  987. #define DPF_MODNAME "Direct3DVertexBuffer::ProcessVerticesStrided"
  988. HRESULT D3DAPI CDirect3DVertexBuffer::ProcessVerticesStrided(DWORD vertexOP, DWORD dwDstIndex, DWORD dwCount,
  989. LPD3DDRAWPRIMITIVESTRIDEDDATA lpDrawData,
  990. DWORD dwSrcFVF,
  991. LPDIRECT3DDEVICE7 lpDevice, DWORD dwFlags)
  992. {
  993. LPDIRECT3DDEVICEI lpDevI;
  994. HRESULT ret = D3D_OK;
  995. #if DBG
  996. ret = this->ValidateProcessVertices(vertexOP, dwDstIndex, dwCount, lpDrawData, lpDevice, dwFlags);
  997. if (ret != D3D_OK)
  998. return ret;
  999. lpDevI = static_cast<LPDIRECT3DDEVICEI>(lpDevice);
  1000. if (lpDevI->ValidateFVF(dwSrcFVF) != D3D_OK)
  1001. {
  1002. D3D_ERR("Invalid source FVF for the device");
  1003. return DDERR_INVALIDPARAMS;
  1004. }
  1005. if ((dwSrcFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW)
  1006. {
  1007. D3D_ERR("ProcessVerticesStrided cannot handle transformed vertices");
  1008. return D3DERR_INVALIDVERTEXTYPE;
  1009. }
  1010. if (!(vertexOP & D3DVOP_TRANSFORM))
  1011. {
  1012. D3D_ERR("D3DVOP_TRANSFORM flag should be set");
  1013. return DDERR_INVALIDPARAMS;
  1014. }
  1015. #else
  1016. lpDevI = static_cast<LPDIRECT3DDEVICEI>(lpDevice);
  1017. #endif
  1018. CLockD3DMT lockObject(lpDevI, DPF_MODNAME, REMIND("")); // Takes D3D lock.
  1019. // Lock the VBs
  1020. LPVOID lpVoid;
  1021. // We call the API level lock since dest VB may be in vid mem. This function will fail for
  1022. // optimized VBs and that is OK since we cannot write out optimized vertices anyway.
  1023. ret = Lock(DDLOCK_WAIT, &lpVoid, NULL);
  1024. if (ret != D3D_OK)
  1025. {
  1026. D3D_ERR("Could not lock the vertex buffer");
  1027. return ret;
  1028. }
  1029. dwPVFlags &= ~D3DPV_TLVCLIP; // Mark the dest VB as "not transformed" for clipping
  1030. lpDevI->dwDeviceFlags |= D3DDEV_STRIDE;
  1031. lpDevI->dwFlags = D3DPV_VBCALL;
  1032. // Input
  1033. lpDevI->dwNumVertices = dwCount;
  1034. lpDevI->dwVIDIn = dwSrcFVF;
  1035. lpDevI->position = lpDrawData->position;
  1036. lpDevI->normal = lpDrawData->normal;
  1037. lpDevI->diffuse = lpDrawData->diffuse;
  1038. lpDevI->specular = lpDrawData->specular;
  1039. for (DWORD i=0; i < this->nTexCoord; i++)
  1040. lpDevI->textures[i] = lpDrawData->textureCoords[i];
  1041. return this->DoProcessVertices(NULL, lpDevI, vertexOP, 0, dwDstIndex, dwFlags);
  1042. }
  1043. //---------------------------------------------------------------------
  1044. #ifdef DBG
  1045. HRESULT DIRECT3DDEVICEI::CheckDrawPrimitiveVB(LPDIRECT3DVERTEXBUFFER7 lpVBuf, DWORD dwStartVertex, DWORD dwNumVertices, DWORD dwFlags)
  1046. {
  1047. LPDIRECT3DVERTEXBUFFERI lpVBufI;
  1048. if (!VALID_DIRECT3DVERTEXBUFFER_PTR(lpVBuf))
  1049. {
  1050. D3D_ERR( "Invalid Direct3DVertexBuffer pointer" );
  1051. return DDERR_INVALIDPARAMS;
  1052. }
  1053. lpVBufI = static_cast<LPDIRECT3DVERTEXBUFFERI>(lpVBuf);
  1054. if (!VALID_DIRECT3DDEVICE_PTR(this))
  1055. {
  1056. D3D_ERR( "Invalid Direct3DDevice pointer" );
  1057. return DDERR_INVALIDOBJECT;
  1058. }
  1059. if (this->ValidateFVF(lpVBufI->fvf) != D3D_OK)
  1060. {
  1061. D3D_ERR("Invalid vertex buffer FVF for the device");
  1062. return DDERR_INVALIDPARAMS;
  1063. }
  1064. if (!IsDPFlagsValid(dwFlags))
  1065. {
  1066. D3D_ERR("Invalid Flags in dwFlags field");
  1067. return DDERR_INVALIDPARAMS;
  1068. }
  1069. if (!(dwDeviceFlags & D3DDEV_DONOTCLIP) && (lpVBufI->clipCodes == NULL) && (lpVBufI->srcVOP & D3DVOP_RENDER))
  1070. {
  1071. D3D_ERR("Vertex buffer does not support clipping");
  1072. return DDERR_INVALIDPARAMS;
  1073. }
  1074. if (!(IS_HW_DEVICE(this) || (lpVBufI->dwCaps & D3DVBCAPS_SYSTEMMEMORY)))
  1075. {
  1076. D3D_ERR("Cannot use vid mem vertex buffers with SW devices");
  1077. return DDERR_INVALIDPARAMS;
  1078. }
  1079. /* If we are on HAL with an untransformed vid mem VB then we disallow
  1080. This will happen only on T&L HW. The reason we disallow this is that
  1081. it'll be very slow so this is not an interesting thing to do anyway */
  1082. if ( !IS_TLHAL_DEVICE(this) &&
  1083. !(lpVBufI->dwCaps & D3DVBCAPS_SYSTEMMEMORY) &&
  1084. !FVF_TRANSFORMED(lpVBufI->fvf) )
  1085. {
  1086. D3D_ERR("DrawPrimitiveVB: Untransformed VB for HAL device must be created with D3DVBCAPS_SYSTEMMEMORY");
  1087. return DDERR_INVALIDPARAMS;
  1088. }
  1089. if (lpVBufI->dwLockCnt)
  1090. {
  1091. D3D_ERR("Cannot render using a locked vertex buffer");
  1092. return D3DERR_VERTEXBUFFERLOCKED;
  1093. }
  1094. if (dwStartVertex + dwNumVertices > lpVBufI->dwNumVertices)
  1095. {
  1096. D3D_ERR("Vertex range is outside the vertex buffer");
  1097. return DDERR_INVALIDPARAMS;
  1098. }
  1099. return D3D_OK;
  1100. }
  1101. #endif
  1102. //---------------------------------------------------------------------
  1103. #undef DPF_MODNAME
  1104. #define DPF_MODNAME "DIRECT3DDEVICEI::DrawIndexedPrimitiveVB"
  1105. HRESULT D3DAPI DIRECT3DDEVICEI::DrawIndexedPrimitiveVB(D3DPRIMITIVETYPE dptPrimitiveType,
  1106. LPDIRECT3DVERTEXBUFFER7 lpVBuf,
  1107. DWORD dwStartVertex, DWORD dwNumVertices,
  1108. LPWORD lpwIndices, DWORD dwIndexCount,
  1109. DWORD dwFlags)
  1110. {
  1111. CLockD3DMT lockObject(this, DPF_MODNAME, REMIND("")); // Takes D3D lock.
  1112. HRESULT ret;
  1113. LPDIRECT3DVERTEXBUFFERI lpVBufI = static_cast<LPDIRECT3DVERTEXBUFFERI>(lpVBuf);
  1114. #if DBG
  1115. ret = CheckDrawPrimitiveVB(lpVBuf, dwStartVertex, dwNumVertices, dwFlags);
  1116. if (ret != D3D_OK)
  1117. return ret;
  1118. Profile(PROF_DRAWINDEXEDPRIMITIVEVB,dptPrimitiveType,lpVBufI->fvf);
  1119. #endif
  1120. this->dwFlags = dwFlags | lpVBufI->dwPVFlags;
  1121. this->primType = dptPrimitiveType;
  1122. this->dwNumVertices = dwNumVertices;
  1123. this->dwNumIndices = dwIndexCount;
  1124. this->lpwIndices = lpwIndices;
  1125. GetNumPrim(this, dwNumIndices); // Calculate dwNumPrimitives and update stats
  1126. #if DBG
  1127. if (dwNumPrimitives > MAX_DX6_PRIMCOUNT)
  1128. {
  1129. D3D_ERR("D3D for DX7 cannot handle greater that 64K sized primitives");
  1130. return D3DERR_TOOMANYPRIMITIVES;
  1131. }
  1132. #endif
  1133. if (lpVBufI->srcVOP & D3DVOP_RENDER || IS_TLHAL_DEVICE(this))
  1134. { // TLVERTEX or TLHAL
  1135. this->dwOutputSize = lpVBufI->position.dwStride;
  1136. this->position.dwStride = lpVBufI->position.dwStride;
  1137. this->dwVIDOut = lpVBufI->fvf;
  1138. DWORD dwOldVidIn = this->dwVIDIn;
  1139. this->dwVIDIn = lpVBufI->fvf;
  1140. BOOL bNoClipping = this->dwDeviceFlags & D3DDEV_DONOTCLIP ||
  1141. (!(lpVBufI->dwPVFlags & D3DPV_CLIPCODESGENERATED) && IS_TLHAL_DEVICE(this));
  1142. if (IS_DP2HAL_DEVICE(this))
  1143. {
  1144. this->nTexCoord = lpVBufI->nTexCoord;
  1145. CDirect3DDeviceIDP2 *dev = static_cast<CDirect3DDeviceIDP2*>(this);
  1146. ret = dev->StartPrimVB(lpVBufI, dwStartVertex);
  1147. if (ret != D3D_OK)
  1148. return ret;
  1149. lpVBufI->lpDevIBatched = this;
  1150. #ifdef VTABLE_HACK
  1151. if (bNoClipping && !IS_MT_DEVICE(this))
  1152. VtblDrawIndexedPrimitiveVBTL();
  1153. #endif
  1154. this->nOutTexCoord = lpVBufI->nTexCoord;
  1155. }
  1156. else
  1157. {
  1158. // needed for legacy drivers' DrawIndexPrim code
  1159. this->lpvOut = (BYTE*)(lpVBufI->position.lpvData) +
  1160. dwStartVertex * this->dwOutputSize;
  1161. ComputeTCI2CopyLegacy(this, lpVBufI->nTexCoord, lpVBufI->dwTexCoordSize, TRUE);
  1162. }
  1163. if (bNoClipping)
  1164. {
  1165. return DrawIndexPrim();
  1166. }
  1167. else
  1168. {
  1169. this->dwTextureCoordSizeTotal = lpVBufI->dwTexCoordSizeTotal;
  1170. for (DWORD i=0; i < this->nOutTexCoord; i++)
  1171. {
  1172. this->dwTextureCoordSize[i] = lpVBufI->dwTexCoordSize[i];
  1173. }
  1174. this->lpClipFlags = lpVBufI->clipCodes + dwStartVertex;
  1175. this->dwClipUnion = ~0; // Force clipping
  1176. if (dwOldVidIn != lpVBufI->fvf)
  1177. {
  1178. ComputeOutputVertexOffsets(this);
  1179. }
  1180. // If lpvData is NULL, it is a driver allocated buffer which
  1181. // means IS_DPHAL_DEVICE() is true.
  1182. // We need to lock such a buffer only if we need to clip
  1183. if (!lpVBufI->position.lpvData)
  1184. {
  1185. // Lock VB
  1186. DDSURFACEDESC2 ddsd;
  1187. memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
  1188. ddsd.dwSize = sizeof(DDSURFACEDESC2);
  1189. ret = lpVBufI->lpDDSVB->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_READONLY | DDLOCK_NOSYSLOCK, NULL);
  1190. if (ret != DD_OK)
  1191. {
  1192. D3D_ERR("Could not lock vertex buffer.");
  1193. return ret;
  1194. }
  1195. this->lpvOut = (BYTE*)(ddsd.lpSurface) +
  1196. dwStartVertex * this->dwOutputSize;
  1197. // Draw with clipping
  1198. this->position.lpvData = this->lpvOut;
  1199. #if DBG
  1200. ret = CheckDrawIndexedPrimitive(this, dwStartVertex);
  1201. if (ret == D3D_OK)
  1202. ret = DoDrawIndexedPrimitive(this);
  1203. #else
  1204. ret = DoDrawIndexedPrimitive(this);
  1205. #endif
  1206. // Unlock VB
  1207. if (ret == D3D_OK)
  1208. return lpVBufI->lpDDSVB->Unlock(NULL);
  1209. else
  1210. lpVBufI->lpDDSVB->Unlock(NULL);
  1211. return ret;
  1212. }
  1213. else
  1214. {
  1215. // Draw with clipping
  1216. this->lpvOut = (BYTE*)lpVBufI->position.lpvData + dwStartVertex * this->dwOutputSize;
  1217. this->position.lpvData = this->lpvOut;
  1218. #if DBG
  1219. ret = CheckDrawIndexedPrimitive(this, dwStartVertex);
  1220. if (ret != D3D_OK)
  1221. return ret;
  1222. #endif
  1223. return DoDrawIndexedPrimitive(this);
  1224. }
  1225. }
  1226. }
  1227. else
  1228. {
  1229. if (lpVBufI->bReallyOptimized)
  1230. {
  1231. // Assume that SOA.lpvData is the same as position.lpvData
  1232. this->SOA.lpvData = lpVBufI->position.lpvData;
  1233. this->SOA.dwStride = lpVBufI->dwNumVertices;
  1234. this->dwSOAStartVertex = dwStartVertex;
  1235. }
  1236. else
  1237. {
  1238. this->position.lpvData = (BYTE*)(lpVBufI->position.lpvData) +
  1239. dwStartVertex * lpVBufI->position.dwStride;
  1240. this->position.dwStride = lpVBufI->position.dwStride;
  1241. #ifdef VTABLE_HACK
  1242. if (IS_DP2HAL_DEVICE(this) && !IS_MT_DEVICE(this))
  1243. {
  1244. CDirect3DDeviceIDP2 *dev = static_cast<CDirect3DDeviceIDP2*>(this);
  1245. dev->lpDP2LastVBI = lpVBufI;
  1246. dev->VtblDrawIndexedPrimitiveVBFE();
  1247. }
  1248. #endif
  1249. }
  1250. if (this->dwVIDIn != lpVBufI->fvf || this->dwDeviceFlags & D3DDEV_STRIDE)
  1251. {
  1252. this->dwDeviceFlags &= ~D3DDEV_STRIDE;
  1253. this->dwVIDIn = lpVBufI->fvf;
  1254. ret = SetupFVFData(NULL);
  1255. if (ret != D3D_OK)
  1256. goto l_exit;
  1257. }
  1258. #if DBG
  1259. ret = CheckDrawIndexedPrimitive(this, dwStartVertex);
  1260. if (ret != D3D_OK)
  1261. goto l_exit;
  1262. #endif
  1263. ret = this->ProcessPrimitive(__PROCPRIMOP_INDEXEDPRIM);
  1264. l_exit:
  1265. // If we used SOA then the dwVIDIn <-> position.dwStride relationship
  1266. // violated. This fixes that. This is required since in non VB code
  1267. // we will not recompute position.dwStride if FVF matched dwVIDIn.
  1268. this->position.dwStride = lpVBufI->position.dwStride;
  1269. return ret;
  1270. }
  1271. }
  1272. //---------------------------------------------------------------------
  1273. #undef DPF_MODNAME
  1274. #define DPF_MODNAME "DIRECT3DDEVICEI::DrawPrimitiveVB"
  1275. HRESULT D3DAPI DIRECT3DDEVICEI::DrawPrimitiveVB(D3DPRIMITIVETYPE dptPrimitiveType,
  1276. LPDIRECT3DVERTEXBUFFER7 lpVBuf,
  1277. DWORD dwStartVertex, DWORD dwNumVertices,
  1278. DWORD dwFlags)
  1279. {
  1280. CLockD3DMT lockObject(this, DPF_MODNAME, REMIND("")); // Takes D3D lock
  1281. HRESULT ret;
  1282. LPDIRECT3DVERTEXBUFFERI lpVBufI = static_cast<LPDIRECT3DVERTEXBUFFERI>(lpVBuf);
  1283. #if DBG
  1284. ret = CheckDrawPrimitiveVB(lpVBuf, dwStartVertex, dwNumVertices, dwFlags);
  1285. if (ret != D3D_OK)
  1286. return ret;
  1287. Profile(PROF_DRAWPRIMITIVEVB,dptPrimitiveType,lpVBufI->fvf);
  1288. #endif
  1289. this->dwFlags = dwFlags | lpVBufI->dwPVFlags;
  1290. this->primType = dptPrimitiveType;
  1291. this->dwNumVertices = dwNumVertices;
  1292. GetNumPrim(this, dwNumVertices); // Calculate dwNumPrimitives and update stats
  1293. #if DBG
  1294. if (dwNumPrimitives > MAX_DX6_PRIMCOUNT)
  1295. {
  1296. D3D_ERR("D3D for DX7 cannot handle greater that 64K sized primitives");
  1297. return D3DERR_TOOMANYPRIMITIVES;
  1298. }
  1299. #endif
  1300. if (lpVBufI->srcVOP & D3DVOP_RENDER || IS_TLHAL_DEVICE(this))
  1301. { // TLVERTEX or TLHAL
  1302. this->position.dwStride = lpVBufI->position.dwStride;
  1303. this->dwOutputSize = lpVBufI->position.dwStride;
  1304. DWORD dwOldVidIn = this->dwVIDIn;
  1305. this->dwVIDIn = lpVBufI->fvf;
  1306. this->dwVIDOut = lpVBufI->fvf;
  1307. BOOL bNoClipping = this->dwDeviceFlags & D3DDEV_DONOTCLIP ||
  1308. (!(lpVBufI->dwPVFlags & D3DPV_CLIPCODESGENERATED) && IS_TLHAL_DEVICE(this));
  1309. if (IS_DP2HAL_DEVICE(this))
  1310. {
  1311. this->nTexCoord = lpVBufI->nTexCoord;
  1312. CDirect3DDeviceIDP2 *dev = static_cast<CDirect3DDeviceIDP2*>(this);
  1313. ret = dev->StartPrimVB(lpVBufI, dwStartVertex);
  1314. if (ret != D3D_OK)
  1315. return ret;
  1316. lpVBufI->lpDevIBatched = this;
  1317. #ifdef VTABLE_HACK
  1318. if (bNoClipping && !IS_MT_DEVICE(this))
  1319. VtblDrawPrimitiveVBTL();
  1320. #endif
  1321. this->nOutTexCoord = lpVBufI->nTexCoord;
  1322. }
  1323. else
  1324. {
  1325. // needed for legacy drivers' DrawPrim code
  1326. this->lpvOut = (BYTE*)(lpVBufI->position.lpvData) +
  1327. dwStartVertex * this->dwOutputSize;
  1328. ComputeTCI2CopyLegacy(this, lpVBufI->nTexCoord, lpVBufI->dwTexCoordSize, TRUE);
  1329. }
  1330. if (bNoClipping)
  1331. {
  1332. return DrawPrim();
  1333. }
  1334. else
  1335. {
  1336. this->dwTextureCoordSizeTotal = lpVBufI->dwTexCoordSizeTotal;
  1337. for (DWORD i=0; i < this->nOutTexCoord; i++)
  1338. {
  1339. this->dwTextureCoordSize[i] = lpVBufI->dwTexCoordSize[i];
  1340. }
  1341. this->lpClipFlags = lpVBufI->clipCodes + dwStartVertex;
  1342. this->dwClipUnion = ~0; // Force clipping
  1343. if (dwOldVidIn != lpVBufI->fvf)
  1344. {
  1345. ComputeOutputVertexOffsets(this);
  1346. }
  1347. // If lpvData is NULL, it is a driver allocated buffer which
  1348. // means IS_DPHAL_DEVICE() is true.
  1349. // We need to lock such a buffer only if we need to clip
  1350. if (!lpVBufI->position.lpvData)
  1351. {
  1352. // Lock VB
  1353. DDSURFACEDESC2 ddsd;
  1354. memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
  1355. ddsd.dwSize = sizeof(DDSURFACEDESC2);
  1356. ret = lpVBufI->lpDDSVB->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_READONLY | DDLOCK_NOSYSLOCK, NULL);
  1357. if (ret != DD_OK)
  1358. {
  1359. D3D_ERR("Could not lock vertex buffer.");
  1360. return ret;
  1361. }
  1362. this->lpvOut = (BYTE*)(ddsd.lpSurface) +
  1363. dwStartVertex * this->dwOutputSize;
  1364. // Draw with clipping
  1365. this->position.lpvData = this->lpvOut;
  1366. #if DBG
  1367. ret=CheckDrawPrimitive(this);
  1368. if (ret == D3D_OK)
  1369. ret = DoDrawPrimitive(this);
  1370. #else
  1371. ret = DoDrawPrimitive(this);
  1372. #endif
  1373. // Unlock VB
  1374. if (ret == D3D_OK)
  1375. return lpVBufI->lpDDSVB->Unlock(NULL);
  1376. else
  1377. lpVBufI->lpDDSVB->Unlock(NULL);
  1378. return ret;
  1379. }
  1380. else
  1381. {
  1382. // Draw with clipping
  1383. this->lpvOut = (BYTE*)lpVBufI->position.lpvData + dwStartVertex * this->dwOutputSize;
  1384. this->position.lpvData = this->lpvOut;
  1385. #if DBG
  1386. ret=CheckDrawPrimitive(this);
  1387. if (ret != D3D_OK)
  1388. return ret;
  1389. #endif
  1390. return DoDrawPrimitive(this);
  1391. }
  1392. }
  1393. }
  1394. else
  1395. {
  1396. if (lpVBufI->bReallyOptimized)
  1397. {
  1398. // Assume that SOA.lpvData is the same as position.lpvData
  1399. this->SOA.lpvData = lpVBufI->position.lpvData;
  1400. this->SOA.dwStride = lpVBufI->dwNumVertices;
  1401. this->dwSOAStartVertex = dwStartVertex;
  1402. }
  1403. else
  1404. {
  1405. this->position.lpvData = (BYTE*)(lpVBufI->position.lpvData) +
  1406. dwStartVertex * lpVBufI->position.dwStride;
  1407. this->position.dwStride = lpVBufI->position.dwStride;
  1408. #ifdef VTABLE_HACK
  1409. if (IS_DP2HAL_DEVICE(this) && !IS_MT_DEVICE(this) && IS_FPU_SETUP(this))
  1410. {
  1411. CDirect3DDeviceIDP2 *dev = static_cast<CDirect3DDeviceIDP2*>(this);
  1412. dev->lpDP2LastVBI = lpVBufI;
  1413. dev->VtblDrawPrimitiveVBFE();
  1414. }
  1415. #endif
  1416. }
  1417. if (this->dwVIDIn != lpVBufI->fvf || this->dwDeviceFlags & D3DDEV_STRIDE)
  1418. {
  1419. this->dwDeviceFlags &= ~D3DDEV_STRIDE;
  1420. this->dwVIDIn = lpVBufI->fvf;
  1421. ret = SetupFVFData(NULL);
  1422. if (ret != D3D_OK)
  1423. goto l_exit;
  1424. }
  1425. #if DBG
  1426. ret=CheckDrawPrimitive(this);
  1427. if (ret != D3D_OK)
  1428. goto l_exit;
  1429. #endif
  1430. ret = this->ProcessPrimitive();
  1431. l_exit:
  1432. // If we used SOA then the dwVIDIn <-> position.dwStride relationship
  1433. // violated. This fixes that. This is required since in non VB code
  1434. // we will not recompute position.dwStride if FVF matched dwVIDIn.
  1435. this->position.dwStride = lpVBufI->position.dwStride;
  1436. return ret;
  1437. }
  1438. }
  1439. //---------------------------------------------------------------------
  1440. #undef DPF_MODNAME
  1441. #define DPF_MODNAME "CDirect3DVertexBuffer::Optimize"
  1442. HRESULT D3DAPI CDirect3DVertexBuffer::Optimize(LPDIRECT3DDEVICE7 lpDevice, DWORD dwFlags)
  1443. {
  1444. HRESULT ret;
  1445. LPDIRECT3DDEVICEI lpDevI;
  1446. DWORD bufferSize;
  1447. LPDIRECTDRAWSURFACE7 lpSurface7;
  1448. LPDIRECTDRAWSURFACE lpSurface;
  1449. LPVOID lpMemory;
  1450. // Validate parms
  1451. if (!VALID_DIRECT3DVERTEXBUFFER_PTR(this))
  1452. {
  1453. D3D_ERR( "Invalid Direct3DVertexBuffer pointer" );
  1454. return DDERR_INVALIDPARAMS;
  1455. }
  1456. if (!VALID_DIRECT3DDEVICE_PTR(lpDevice))
  1457. {
  1458. D3D_ERR( "Invalid Direct3DDevice pointer" );
  1459. return DDERR_INVALIDOBJECT;
  1460. }
  1461. lpDevI = static_cast<LPDIRECT3DDEVICEI>(lpDevice);
  1462. if (dwFlags != 0)
  1463. {
  1464. D3D_ERR("dwFlags should be zero");
  1465. return DDERR_INVALIDPARAMS;
  1466. }
  1467. CLockD3DMT lockObject(lpDevI, DPF_MODNAME, REMIND(""));
  1468. if (lpDevI->ValidateFVF(this->fvf) != D3D_OK)
  1469. {
  1470. D3D_ERR("Invalid vertex buffer FVF for the device");
  1471. return DDERR_INVALIDPARAMS;
  1472. }
  1473. if (this->dwCaps & D3DVBCAPS_OPTIMIZED)
  1474. {
  1475. D3D_ERR("The vertex buffer already optimized");
  1476. return D3DERR_VERTEXBUFFEROPTIMIZED;
  1477. }
  1478. if (this->dwLockCnt != 0)
  1479. {
  1480. D3D_ERR("Could not optimize locked vertex buffer");
  1481. return D3DERR_VERTEXBUFFERLOCKED;
  1482. }
  1483. if (IS_TLHAL_DEVICE(lpDevI) && (this->dwCaps & D3DVBCAPS_SYSTEMMEMORY)==0)
  1484. {
  1485. if (this->dwPVFlags & D3DPV_CLIPCODESGENERATED || (!IS_HW_DEVICE(lpDevI)))
  1486. {
  1487. // silently ignore since we'll be either
  1488. // using our front end or this is ref rast
  1489. // Either way we need no special optimization
  1490. goto success;
  1491. }
  1492. DDSURFACEDESC2 ddsd;
  1493. memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
  1494. ddsd.dwSize = sizeof(DDSURFACEDESC2);
  1495. ddsd.dwFlags = DDSD_CAPS | DDSD_FVF | DDSD_SRCVBHANDLE;
  1496. ddsd.ddsCaps.dwCaps = DDSCAPS_EXECUTEBUFFER;
  1497. ddsd.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY;
  1498. ddsd.ddsCaps.dwCaps2 = DDSCAPS2_VERTEXBUFFER;
  1499. ddsd.dwFVF = this->fvf; // Let driver know about the FVF
  1500. ddsd.dwSrcVBHandle = DDSLCL(this->lpDDSVB)->lpSurfMore->dwSurfaceHandle;
  1501. if (lpDevI->lpDirect3DI->lpDD7->CreateSurface(&ddsd, &lpSurface7, NULL) != DD_OK)
  1502. {
  1503. // Driver could not or did not want to optimize the VB
  1504. goto success;
  1505. }
  1506. ret = lpSurface7->QueryInterface(IID_IDirectDrawSurfaceNew, (LPVOID*)&lpSurface);
  1507. if (ret != DD_OK)
  1508. {
  1509. D3D_ERR("failed to QI for DDS1");
  1510. lpSurface7->Release();
  1511. return ret;
  1512. }
  1513. // Destroy old surfaces
  1514. lpDDSVB->Release();
  1515. lpDDS1VB->Release();
  1516. // And use new ones
  1517. lpDDSVB = lpSurface7;
  1518. lpDDS1VB = lpSurface;
  1519. this->dwCaps |= D3DVBCAPS_OPTIMIZED;
  1520. #ifdef VTABLE_HACK
  1521. VtblLockDefault();
  1522. #endif // VTABLE_HACK
  1523. return D3D_OK;
  1524. }
  1525. else
  1526. {
  1527. // Do nothing for transformed vertices
  1528. if ((this->fvf & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW)
  1529. {
  1530. goto success;
  1531. }
  1532. // Get the buffer size to allocate
  1533. bufferSize = lpDevI->pGeometryFuncs->ComputeOptimizedVertexBufferSize
  1534. (this->fvf, this->position.dwStride,
  1535. dwNumVertices);
  1536. // Create new surfaces for optimized vertex buffer
  1537. if (bufferSize == 0)
  1538. {
  1539. goto success;
  1540. }
  1541. ret = CreateMemoryBuffer(lpDevI->lpDirect3DI, &lpSurface7, &lpSurface,
  1542. &lpMemory, bufferSize);
  1543. if (ret != D3D_OK)
  1544. return ret;
  1545. // Try to optimize
  1546. // If optimized vertex buffer are not supported by the implementation
  1547. // it returns E_NOTIMPL. In this case we still set D3DVBCAPS_OPTIMIZED to prevent
  1548. // locking of the vertex buffer. But bReallyOptimized is set to FALSE, to use
  1549. // the original buffer.
  1550. ret = lpDevI->pGeometryFuncs->OptimizeVertexBuffer
  1551. (fvf, dwNumVertices, position.dwStride, position.lpvData,
  1552. lpMemory, dwFlags);
  1553. if (ret)
  1554. {
  1555. lpSurface7->Release();
  1556. lpSurface->Release();
  1557. if (ret == E_NOTIMPL)
  1558. {
  1559. goto success;
  1560. }
  1561. else
  1562. {
  1563. D3D_ERR("Failed to optimize vertex buffer");
  1564. return ret;
  1565. }
  1566. }
  1567. bReallyOptimized = TRUE;
  1568. this->dwPVFlags |= D3DPV_SOA;
  1569. // Destroy old surfaces
  1570. lpDDSVB->Release();
  1571. lpDDS1VB->Release();
  1572. // And use new ones
  1573. lpDDSVB = lpSurface7;
  1574. lpDDS1VB = lpSurface;
  1575. position.lpvData = lpMemory;
  1576. success:
  1577. this->dwCaps |= D3DVBCAPS_OPTIMIZED;
  1578. #ifdef VTABLE_HACK
  1579. // Disable all fast path optimizations
  1580. VtblLockDefault();
  1581. if (this->lpDevIBatched)
  1582. {
  1583. this->lpDevIBatched->VtblDrawPrimitiveVBDefault();
  1584. this->lpDevIBatched->VtblDrawIndexedPrimitiveVBDefault();
  1585. }
  1586. #endif
  1587. return D3D_OK;
  1588. }
  1589. }
  1590. #ifdef VTABLE_HACK
  1591. //---------------------------------------------------------------------
  1592. #undef DPF_MODNAME
  1593. #define DPF_MODNAME "DIRECT3DDEVICEI::DrawPrimitiveVBTL"
  1594. HRESULT D3DAPI CDirect3DDeviceIDP2::DrawPrimitiveVBTL(D3DPRIMITIVETYPE dptPrimitiveType,
  1595. LPDIRECT3DVERTEXBUFFER7 lpVBuf,
  1596. DWORD dwStartVertex, DWORD dwNumVertices,
  1597. DWORD dwFlags)
  1598. {
  1599. LPDIRECT3DVERTEXBUFFERI lpVBufI = static_cast<LPDIRECT3DVERTEXBUFFERI>(lpVBuf);
  1600. #if DBG
  1601. HRESULT ret = CheckDrawPrimitiveVB(lpVBuf, dwStartVertex, dwNumVertices, dwFlags);
  1602. if (ret != D3D_OK)
  1603. return ret;
  1604. Profile(PROF_DRAWPRIMITIVEVB,dptPrimitiveType,lpVBufI->fvf);
  1605. #endif
  1606. if ((lpVBufI == lpDP2CurrBatchVBI) && (this->dwVIDIn))
  1607. {
  1608. this->primType = dptPrimitiveType;
  1609. this->dwNumVertices = dwNumVertices;
  1610. this->dwFlags = dwFlags | lpVBufI->dwPVFlags;
  1611. this->dwVertexBase = dwStartVertex;
  1612. GetNumPrim(this, dwNumVertices); // Calculate dwNumPrimitives
  1613. #if DBG
  1614. if (dwNumPrimitives > MAX_DX6_PRIMCOUNT)
  1615. {
  1616. D3D_ERR("D3D for DX7 cannot handle greater that 64K sized primitives");
  1617. return D3DERR_TOOMANYPRIMITIVES;
  1618. }
  1619. #endif
  1620. this->dp2data.dwFlags &= ~D3DHALDP2_SWAPVERTEXBUFFER;
  1621. this->dwDP2VertexCount = max(this->dwDP2VertexCount, this->dwVertexBase + this->dwNumVertices);
  1622. lpVBufI->lpDevIBatched = this;
  1623. return DrawPrim();
  1624. }
  1625. VtblDrawPrimitiveVBDefault();
  1626. return DrawPrimitiveVB(dptPrimitiveType, lpVBuf, dwStartVertex, dwNumVertices, dwFlags);
  1627. }
  1628. //---------------------------------------------------------------------
  1629. #undef DPF_MODNAME
  1630. #define DPF_MODNAME "DIRECT3DDEVICEI::DrawIndexedPrimitiveVBTL"
  1631. HRESULT D3DAPI CDirect3DDeviceIDP2::DrawIndexedPrimitiveVBTL(D3DPRIMITIVETYPE dptPrimitiveType,
  1632. LPDIRECT3DVERTEXBUFFER7 lpVBuf,
  1633. DWORD dwStartVertex, DWORD dwNumVertices,
  1634. LPWORD lpwIndices, DWORD dwIndexCount,
  1635. DWORD dwFlags)
  1636. {
  1637. LPDIRECT3DVERTEXBUFFERI lpVBufI = static_cast<LPDIRECT3DVERTEXBUFFERI>(lpVBuf);
  1638. #if DBG
  1639. HRESULT ret = CheckDrawPrimitiveVB(lpVBuf, dwStartVertex, dwNumVertices, dwFlags);
  1640. if (ret != D3D_OK)
  1641. return ret;
  1642. Profile(PROF_DRAWINDEXEDPRIMITIVEVB,dptPrimitiveType,lpVBufI->fvf);
  1643. #endif
  1644. if ((lpVBufI == lpDP2CurrBatchVBI) && (this->dwVIDIn))
  1645. {
  1646. this->primType = dptPrimitiveType;
  1647. this->dwNumVertices = dwNumVertices;
  1648. this->dwFlags = dwFlags | lpVBufI->dwPVFlags;
  1649. this->dwVertexBase = dwStartVertex;
  1650. this->dwNumIndices = dwIndexCount;
  1651. this->lpwIndices = lpwIndices;
  1652. GetNumPrim(this, dwNumIndices); // Calculate dwNumPrimitives
  1653. #if DBG
  1654. if (dwNumPrimitives > MAX_DX6_PRIMCOUNT)
  1655. {
  1656. D3D_ERR("D3D for DX7 cannot handle greater that 64K sized primitives");
  1657. return D3DERR_TOOMANYPRIMITIVES;
  1658. }
  1659. #endif
  1660. this->dp2data.dwFlags &= ~D3DHALDP2_SWAPVERTEXBUFFER;
  1661. this->dwDP2VertexCount = max(this->dwDP2VertexCount, this->dwVertexBase + this->dwNumVertices);
  1662. lpVBufI->lpDevIBatched = this;
  1663. return DrawIndexPrim();
  1664. }
  1665. VtblDrawIndexedPrimitiveVBDefault();
  1666. return DrawIndexedPrimitiveVB(dptPrimitiveType, lpVBuf, dwStartVertex, dwNumVertices, lpwIndices, dwIndexCount, dwFlags);
  1667. }
  1668. //---------------------------------------------------------------------
  1669. #undef DPF_MODNAME
  1670. #define DPF_MODNAME "DIRECT3DDEVICEI::DrawPrimitiveVBFE"
  1671. HRESULT D3DAPI CDirect3DDeviceIDP2::DrawPrimitiveVBFE(D3DPRIMITIVETYPE dptPrimitiveType,
  1672. LPDIRECT3DVERTEXBUFFER7 lpVBuf,
  1673. DWORD dwStartVertex, DWORD dwNumVertices,
  1674. DWORD dwFlags)
  1675. {
  1676. LPDIRECT3DVERTEXBUFFERI lpVBufI = static_cast<LPDIRECT3DVERTEXBUFFERI>(lpVBuf);
  1677. HRESULT ret;
  1678. #if DBG
  1679. ret = CheckDrawPrimitiveVB(lpVBuf, dwStartVertex, dwNumVertices, dwFlags);
  1680. if (ret != D3D_OK)
  1681. return ret;
  1682. Profile(PROF_DRAWPRIMITIVEVB,dptPrimitiveType,lpVBufI->fvf);
  1683. #endif
  1684. if ((lpVBufI == lpDP2LastVBI) &&
  1685. !(this->dwFEFlags & D3DFE_FRONTEND_DIRTY))
  1686. {
  1687. this->primType = dptPrimitiveType;
  1688. this->dwNumVertices = dwNumVertices;
  1689. this->dwFlags = this->dwLastFlags | dwFlags | lpVBufI->dwPVFlags;
  1690. this->position.lpvData = (BYTE*)(lpVBufI->position.lpvData) +
  1691. dwStartVertex * lpVBufI->position.dwStride;
  1692. #if DBG
  1693. GetNumPrim(this, dwNumVertices); // Calculate dwNumPrimitives
  1694. if (dwNumPrimitives > MAX_DX6_PRIMCOUNT)
  1695. {
  1696. D3D_ERR("D3D for DX7 cannot handle greater that 64K sized primitives");
  1697. return D3DERR_TOOMANYPRIMITIVES;
  1698. }
  1699. #endif
  1700. this->dwVertexPoolSize = dwNumVertices * this->dwOutputSize;
  1701. if (this->dwVertexPoolSize > this->TLVbuf_GetSize())
  1702. {
  1703. // try
  1704. // {
  1705. if (this->TLVbuf_Grow(this->dwVertexPoolSize, true) != D3D_OK)
  1706. {
  1707. D3D_ERR( "Could not grow TL vertex buffer" );
  1708. return DDERR_OUTOFMEMORY;
  1709. }
  1710. // }
  1711. // catch (HRESULT ret)
  1712. // {
  1713. // return ret;
  1714. // }
  1715. }
  1716. if (dwNumVertices * sizeof(D3DFE_CLIPCODE) > this->HVbuf.GetSize())
  1717. {
  1718. if (this->HVbuf.Grow(dwNumVertices * sizeof(D3DFE_CLIPCODE)) != D3D_OK)
  1719. {
  1720. D3D_ERR( "Could not grow clip buffer" );
  1721. ret = DDERR_OUTOFMEMORY;
  1722. return ret;
  1723. }
  1724. this->lpClipFlags = (D3DFE_CLIPCODE*)this->HVbuf.GetAddress();
  1725. }
  1726. DDASSERT(this->dwDP2VertexCount * this->dwOutputSize == this->TLVbuf_Base());
  1727. this->dwVertexBase = this->dwDP2VertexCount;
  1728. DDASSERT(this->dwVertexBase < MAX_DX6_VERTICES);
  1729. dp2data.dwFlags |= D3DHALDP2_SWAPVERTEXBUFFER;
  1730. this->dwDP2VertexCount = this->dwVertexBase + this->dwNumVertices;
  1731. this->lpvOut = this->TLVbuf_GetAddress();
  1732. // try
  1733. // {
  1734. switch (this->primType)
  1735. {
  1736. case D3DPT_POINTLIST:
  1737. this->dwNumPrimitives = dwNumVertices;
  1738. ret = this->pGeometryFuncs->ProcessPrimitive(this);
  1739. break;
  1740. case D3DPT_LINELIST:
  1741. this->dwNumPrimitives = dwNumVertices >> 1;
  1742. ret = this->pGeometryFuncs->ProcessPrimitive(this);
  1743. break;
  1744. case D3DPT_LINESTRIP:
  1745. this->dwNumPrimitives = dwNumVertices - 1;
  1746. ret = this->pGeometryFuncs->ProcessPrimitive(this);
  1747. break;
  1748. case D3DPT_TRIANGLEFAN:
  1749. this->dwNumPrimitives = dwNumVertices - 2;
  1750. ret = this->pGeometryFuncs->ProcessTriangleFan(this);
  1751. break;
  1752. case D3DPT_TRIANGLESTRIP:
  1753. this->dwNumPrimitives = dwNumVertices - 2;
  1754. ret = this->pGeometryFuncs->ProcessTriangleStrip(this);
  1755. break;
  1756. case D3DPT_TRIANGLELIST:
  1757. #ifdef _X86_
  1758. {
  1759. DWORD tmp;
  1760. __asm
  1761. {
  1762. mov eax, 0x55555555 // fractional part of 1.0/3.0
  1763. mul dwNumVertices
  1764. add eax, 0x80000000 // Rounding
  1765. adc edx, 0
  1766. mov tmp, edx
  1767. }
  1768. this->dwNumPrimitives = tmp;
  1769. }
  1770. #else
  1771. this->dwNumPrimitives = dwNumVertices / 3;
  1772. #endif
  1773. ret = this->pGeometryFuncs->ProcessTriangleList(this);
  1774. break;
  1775. }
  1776. // }
  1777. // catch (HRESULT ret)
  1778. // {
  1779. // return ret;
  1780. // }
  1781. D3DFE_UpdateClipStatus(this);
  1782. this->TLVbuf_Base() += this->dwVertexPoolSize;
  1783. DDASSERT(TLVbuf_base <= TLVbuf_size);
  1784. DDASSERT(TLVbuf_base == this->dwDP2VertexCount * this->dwOutputSize);
  1785. return ret;
  1786. }
  1787. VtblDrawPrimitiveVBDefault();
  1788. return DrawPrimitiveVB(dptPrimitiveType, lpVBuf, dwStartVertex, dwNumVertices, dwFlags);
  1789. }
  1790. //---------------------------------------------------------------------
  1791. #undef DPF_MODNAME
  1792. #define DPF_MODNAME "DIRECT3DDEVICEI::DrawIndexedPrimitiveVBFE"
  1793. HRESULT D3DAPI CDirect3DDeviceIDP2::DrawIndexedPrimitiveVBFE(D3DPRIMITIVETYPE dptPrimitiveType,
  1794. LPDIRECT3DVERTEXBUFFER7 lpVBuf,
  1795. DWORD dwStartVertex, DWORD dwNumVertices,
  1796. LPWORD lpwIndices, DWORD dwIndexCount,
  1797. DWORD dwFlags)
  1798. {
  1799. LPDIRECT3DVERTEXBUFFERI lpVBufI = static_cast<LPDIRECT3DVERTEXBUFFERI>(lpVBuf);
  1800. HRESULT ret;
  1801. #if DBG
  1802. ret = CheckDrawPrimitiveVB(lpVBuf, dwStartVertex, dwNumVertices, dwFlags);
  1803. if (ret != D3D_OK)
  1804. return ret;
  1805. Profile(PROF_DRAWINDEXEDPRIMITIVEVB,dptPrimitiveType,lpVBufI->fvf);
  1806. #endif
  1807. if ((lpVBufI == lpDP2LastVBI) &&
  1808. !(this->dwFEFlags & D3DFE_FRONTEND_DIRTY))
  1809. {
  1810. this->primType = dptPrimitiveType;
  1811. this->dwNumVertices = dwNumVertices;
  1812. this->dwFlags = this->dwLastFlags | dwFlags | lpVBufI->dwPVFlags;
  1813. this->dwVertexBase = 0;
  1814. this->dwNumIndices = dwIndexCount;
  1815. this->lpwIndices = lpwIndices;
  1816. GetNumPrim(this, dwNumIndices); // Calculate dwNumPrimitives
  1817. this->position.lpvData = (BYTE*)(lpVBufI->position.lpvData) +
  1818. dwStartVertex * lpVBufI->position.dwStride;
  1819. #if DBG
  1820. if (dwNumPrimitives > MAX_DX6_PRIMCOUNT)
  1821. {
  1822. D3D_ERR("D3D for DX7 cannot handle greater that 64K sized primitives");
  1823. return D3DERR_TOOMANYPRIMITIVES;
  1824. }
  1825. #endif
  1826. this->dwVertexPoolSize = dwNumVertices * this->dwOutputSize;
  1827. if (this->dwVertexPoolSize > this->TLVbuf_GetSize())
  1828. {
  1829. // try
  1830. // {
  1831. if (this->TLVbuf_Grow(this->dwVertexPoolSize,
  1832. (this->dwDeviceFlags & D3DDEV_DONOTCLIP)!=0) != D3D_OK)
  1833. {
  1834. D3D_ERR( "Could not grow TL vertex buffer" );
  1835. return DDERR_OUTOFMEMORY;
  1836. }
  1837. // }
  1838. // catch (HRESULT ret)
  1839. // {
  1840. // return ret;
  1841. // }
  1842. }
  1843. if (dwNumVertices * sizeof(D3DFE_CLIPCODE) > this->HVbuf.GetSize())
  1844. {
  1845. if (this->HVbuf.Grow(dwNumVertices * sizeof(D3DFE_CLIPCODE)) != D3D_OK)
  1846. {
  1847. D3D_ERR( "Could not grow clip buffer" );
  1848. ret = DDERR_OUTOFMEMORY;
  1849. return ret;
  1850. }
  1851. this->lpClipFlags = (D3DFE_CLIPCODE*)this->HVbuf.GetAddress();
  1852. }
  1853. this->dwVertexBase = this->dwDP2VertexCount;
  1854. DDASSERT(this->dwVertexBase < MAX_DX6_VERTICES);
  1855. dp2data.dwFlags |= D3DHALDP2_SWAPVERTEXBUFFER;
  1856. this->dwDP2VertexCount = this->dwVertexBase + this->dwNumVertices;
  1857. this->lpvOut = this->TLVbuf_GetAddress();
  1858. // try
  1859. // {
  1860. ret = this->pGeometryFuncs->ProcessIndexedPrimitive(this);
  1861. // }
  1862. // catch (HRESULT ret)
  1863. // {
  1864. // return ret;
  1865. // }
  1866. D3DFE_UpdateClipStatus(this);
  1867. this->TLVbuf_Base() += this->dwVertexPoolSize;
  1868. DDASSERT(TLVbuf_base <= TLVbuf_size);
  1869. DDASSERT(TLVbuf_base == this->dwDP2VertexCount * this->dwOutputSize);
  1870. return ret;
  1871. }
  1872. VtblDrawIndexedPrimitiveVBDefault();
  1873. return DrawIndexedPrimitiveVB(dptPrimitiveType, lpVBuf, dwStartVertex, dwNumVertices, lpwIndices, dwIndexCount, dwFlags);
  1874. }
  1875. #endif // VTABLE_HACK