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.

1260 lines
40 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. const DWORD D3DVOP_RENDER = 1 << 31;
  20. const DWORD D3DVBCAPS_VALID = D3DVBCAPS_SYSTEMMEMORY |
  21. D3DVBCAPS_WRITEONLY |
  22. D3DVBCAPS_OPTIMIZED;
  23. void hookVertexBufferToD3D(LPDIRECT3DI lpDirect3DI,
  24. LPDIRECT3DVERTEXBUFFERI lpVBufI)
  25. {
  26. LIST_INSERT_ROOT(&lpDirect3DI->vbufs, lpVBufI, list);
  27. lpVBufI->lpDirect3DI = lpDirect3DI;
  28. lpDirect3DI->numVBufs++;
  29. }
  30. /*
  31. * Direct3DVertexBuffer::QueryInterface
  32. */
  33. #undef DPF_MODNAME
  34. #define DPF_MODNAME "Direct3DVertexBuffer::QueryInterface"
  35. HRESULT D3DAPI CDirect3DVertexBuffer::QueryInterface(REFIID riid, LPVOID* ppvObj)
  36. {
  37. CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock.
  38. #if DBG
  39. /*
  40. * validate parms
  41. */
  42. TRY
  43. {
  44. if (!VALID_DIRECT3DVERTEXBUFFER_PTR(this)) {
  45. D3D_ERR( "Invalid Direct3DVertexBuffer pointer" );
  46. return DDERR_INVALIDOBJECT;
  47. }
  48. if (!VALID_OUTPTR(ppvObj)) {
  49. D3D_ERR( "Invalid pointer to pointer" );
  50. return DDERR_INVALIDPARAMS;
  51. }
  52. *ppvObj = NULL;
  53. }
  54. EXCEPT( EXCEPTION_EXECUTE_HANDLER )
  55. {
  56. D3D_ERR( "Exception encountered validating parameters" );
  57. return DDERR_INVALIDPARAMS;
  58. }
  59. #endif
  60. if(IsEqualIID(riid, IID_IUnknown) ||
  61. IsEqualIID(riid, IID_IDirect3DVertexBuffer) )
  62. {
  63. AddRef();
  64. *ppvObj = static_cast<LPVOID>(static_cast<LPDIRECT3DVERTEXBUFFER>(this));
  65. return(D3D_OK);
  66. }
  67. else
  68. {
  69. D3D_ERR( "Don't know this riid" );
  70. return (E_NOINTERFACE);
  71. }
  72. } /* CDirect3DVertexBuffer::QueryInterface */
  73. /*
  74. * Direct3DVertexBuffer::AddRef
  75. */
  76. #undef DPF_MODNAME
  77. #define DPF_MODNAME "Direct3DVertexBuffer::AddRef"
  78. ULONG D3DAPI CDirect3DVertexBuffer::AddRef()
  79. {
  80. DWORD rcnt;
  81. CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock.
  82. #if DBG
  83. /*
  84. * validate parms
  85. */
  86. TRY
  87. {
  88. if (!VALID_DIRECT3DVERTEXBUFFER_PTR(this)) {
  89. D3D_ERR( "Invalid Direct3DVertexBuffer pointer" );
  90. return 0;
  91. }
  92. }
  93. EXCEPT( EXCEPTION_EXECUTE_HANDLER )
  94. {
  95. D3D_ERR( "Exception encountered validating parameters" );
  96. return 0;
  97. }
  98. #endif
  99. this->refCnt++;
  100. rcnt = this->refCnt;
  101. return (rcnt);
  102. } /* Direct3DVertexBuffer::AddRef */
  103. /*
  104. * Direct3DVertexBuffer::Release
  105. *
  106. */
  107. //---------------------------------------------------------------------
  108. #undef DPF_MODNAME
  109. #define DPF_MODNAME "Direct3DVertexBuffer::Release"
  110. ULONG D3DAPI CDirect3DVertexBuffer::Release()
  111. {
  112. DWORD lastrefcnt;
  113. CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock.
  114. #if DBG
  115. /*
  116. * validate parms
  117. */
  118. TRY
  119. {
  120. if (!VALID_DIRECT3DVERTEXBUFFER_PTR(this)) {
  121. D3D_ERR( "Invalid Direct3DVertexBuffer pointer" );
  122. return 0;
  123. }
  124. }
  125. EXCEPT( EXCEPTION_EXECUTE_HANDLER )
  126. {
  127. D3D_ERR( "Exception encountered validating parameters" );
  128. return 0;
  129. }
  130. #endif
  131. /*
  132. * decrement the ref count. if we hit 0, free the object
  133. */
  134. this->refCnt--;
  135. lastrefcnt = this->refCnt;
  136. if( lastrefcnt == 0 )
  137. {
  138. delete this;
  139. return 0;
  140. }
  141. return lastrefcnt;
  142. } /* D3DTex3_Release */
  143. //---------------------------------------------------------------------
  144. // Internal version.
  145. // No D3D lock, no checks
  146. //
  147. #undef DPF_MODNAME
  148. #define DPF_MODNAME "DIRECT3DI::CreateVertexBufferI"
  149. HRESULT DIRECT3DI::CreateVertexBufferI(LPD3DVERTEXBUFFERDESC lpDesc,
  150. LPDIRECT3DVERTEXBUFFER* lplpVBuf,
  151. DWORD dwFlags)
  152. {
  153. CDirect3DVertexBuffer* lpVBufI;
  154. HRESULT ret = D3D_OK;
  155. *lplpVBuf = NULL;
  156. lpVBufI = static_cast<LPDIRECT3DVERTEXBUFFERI>(new CDirect3DVertexBuffer(this));
  157. if (!lpVBufI) {
  158. D3D_ERR("failed to allocate space for vertex buffer");
  159. return (DDERR_OUTOFMEMORY);
  160. }
  161. if ((ret=lpVBufI->Init(this, lpDesc, dwFlags))!=D3D_OK)
  162. {
  163. D3D_ERR("Failed to initialize the vertex buffer object");
  164. delete lpVBufI;
  165. return ret;
  166. }
  167. *lplpVBuf = (LPDIRECT3DVERTEXBUFFER)lpVBufI;
  168. return(D3D_OK);
  169. }
  170. //---------------------------------------------------------------------
  171. #undef DPF_MODNAME
  172. #define DPF_MODNAME "DIRECT3DI::CreateVertexBuffer"
  173. HRESULT D3DAPI DIRECT3DI::CreateVertexBuffer(LPD3DVERTEXBUFFERDESC lpDesc, LPDIRECT3DVERTEXBUFFER* lplpVBuf,
  174. DWORD dwFlags, LPUNKNOWN pUnkOuter)
  175. {
  176. if(pUnkOuter != NULL) {
  177. D3D_ERR("Unknown pointer should be NULL");
  178. return CLASS_E_NOAGGREGATION;
  179. }
  180. CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock.
  181. #if DBG
  182. /*
  183. * validate parms
  184. */
  185. if (!VALID_DIRECT3D3_PTR(this)) {
  186. D3D_ERR( "Invalid Direct3D pointer" );
  187. return DDERR_INVALIDOBJECT;
  188. }
  189. if (!VALID_OUTPTR(lplpVBuf)) {
  190. D3D_ERR( "Invalid pointer to pointer pointer" );
  191. return DDERR_INVALIDPARAMS;
  192. }
  193. if ((lpDesc->dwCaps & D3DVBCAPS_VALID) != lpDesc->dwCaps)
  194. {
  195. D3D_ERR("Invalid caps");
  196. return DDERR_INVALIDCAPS;
  197. }
  198. if (dwFlags & ~D3DDP_DONOTCLIP)
  199. {
  200. D3D_ERR("Invalid dwFlags");
  201. return DDERR_INVALIDPARAMS;
  202. }
  203. #endif
  204. return CreateVertexBufferI(lpDesc, lplpVBuf, dwFlags);
  205. }
  206. #undef DPF_MODNAME
  207. #define DPF_MODNAME "Direct3DVertexBuffer::constructor"
  208. CDirect3DVertexBuffer::CDirect3DVertexBuffer(LPDIRECT3DI lpD3DI)
  209. {
  210. refCnt = 1;
  211. /*
  212. * Put this vertex buffer in the list of those owned by the
  213. * Direct3D object
  214. */
  215. hookVertexBufferToD3D(lpD3DI, this);
  216. srcVOP = dstVOP = dwPVFlags = position.dwStride = dwLockCnt = 0;
  217. legacyVertexType = (D3DVERTEXTYPE)0;
  218. position.lpvData = NULL;
  219. clipCodes = NULL;
  220. lpDDSVB = NULL;
  221. dwCaps = 0;
  222. }
  223. #undef DPF_MODNAME
  224. #define DPF_MODNAME "Direct3DVertexBuffer::destructor"
  225. CDirect3DVertexBuffer::~CDirect3DVertexBuffer()
  226. {
  227. /*
  228. * Remove ourselves from the Direct3D object
  229. */
  230. LIST_DELETE(this, list);
  231. this->lpDirect3DI->numVBufs--;
  232. delete [] clipCodes;
  233. if (lpDDSVB)
  234. {
  235. lpDDSVB->Release();
  236. lpDDS1VB->Release();
  237. }
  238. }
  239. /* Calculates the per vertex size in bytes based on the vertex ID
  240. * This function ignores the CLIPFLAGS field since it is allocated
  241. * separatly.
  242. */
  243. DWORD calcVertexSize(DWORD fvf)
  244. {
  245. DWORD vertSize=0;
  246. static const BYTE nibble1[]={0, 0,
  247. 12, 12,
  248. 16, 16,
  249. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  250. static const BYTE nibble2[]={0, 12, 4, 16, 4, 16, 8, 20, 4, 16, 8, 20, 8, 20, 12, 24};
  251. #if DBG
  252. if (fvf & D3DFVF_XYZ)
  253. vertSize += 12;
  254. else if (fvf & D3DFVF_XYZRHW)
  255. vertSize += 16;
  256. if (fvf & D3DFVF_NORMAL)
  257. vertSize += 12;
  258. if (fvf & D3DFVF_RESERVED1)
  259. vertSize += 4;
  260. if (fvf & D3DFVF_DIFFUSE)
  261. vertSize += 4;
  262. if (fvf & D3DFVF_SPECULAR)
  263. vertSize += 4;
  264. #else
  265. vertSize = nibble1[fvf&0xf] + nibble2[(fvf>>4)&0xf];
  266. #endif
  267. vertSize += ((fvf >> 8) & 0xf) << 3; // 8 * #textures
  268. return vertSize;
  269. }
  270. //---------------------------------------------------------------------
  271. //
  272. // Create the vertex memory buffer through DirectDraw
  273. //
  274. // Notes:
  275. // this->dwMemType should be set before calling this function
  276. // this->dwCaps should be set too.
  277. // this->dwMemType is set to DDSCAPS_VIDEOMEMORY is the VB was driver allocated
  278. //
  279. #undef DPF_MODNAME
  280. #define DPF_MODNAME "Direct3DVertexBuffer::CreateMemoryBuffer"
  281. HRESULT CDirect3DVertexBuffer::CreateMemoryBuffer(
  282. LPDIRECT3DI lpD3DI,
  283. LPDIRECTDRAWSURFACE4 *lplpSurface4,
  284. LPDIRECTDRAWSURFACE *lplpSurface,
  285. LPVOID *lplpMemory,
  286. DWORD dwBufferSize,
  287. DWORD dwFlags)
  288. {
  289. HRESULT ret;
  290. DDSURFACEDESC2 ddsd;
  291. memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
  292. ddsd.dwSize = sizeof(DDSURFACEDESC2);
  293. ddsd.dwFlags = DDSD_WIDTH | DDSD_CAPS;
  294. ddsd.dwWidth = dwBufferSize;
  295. ddsd.ddsCaps.dwCaps = DDSCAPS_EXECUTEBUFFER;
  296. ddsd.ddsCaps.dwCaps2 = this->dwMemType;
  297. // The meaning of DDSCAPS_VIDEOMEMORY and DDSCAPS_SYSTEMEMORY are
  298. // slightly different in case of VBs. the former only means that
  299. // the buffer is drivers allocated and could be in any memory type.
  300. // The latter means that the driver did not care to allocate VBs
  301. // hence they are always in DDraw allocated system memory.
  302. // The reason we try video memory followed by system memory
  303. // (rather than simply not specifying the memory type) is for
  304. // drivers which do not care to do any special VB allocations, we
  305. // do not DDraw to take the Win16 lock for locking system memory
  306. // surfaces.
  307. if ((dwCaps & D3DVBCAPS_SYSTEMMEMORY) || !FVF_TRANSFORMED(fvf))
  308. {
  309. // This VB cannot reside in driver friendly memory for one of the following reasons:
  310. // 1. The app explicitly specified system memory
  311. // 2. The vertex buffer is untransformed - the driver will never see this VB
  312. D3D_INFO(8, "Trying to create a sys mem vertex buffer");
  313. ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
  314. ret = lpD3DI->lpDD4->CreateSurface(&ddsd, lplpSurface4, NULL);
  315. if (ret != DD_OK)
  316. {
  317. D3D_ERR("Could not allocate the Vertex buffer.");
  318. return ret;
  319. }
  320. }
  321. else
  322. {
  323. // Try explicit video memory first
  324. ddsd.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY;
  325. if (dwFlags & D3DDP_DONOTCLIP)
  326. ddsd.ddsCaps.dwCaps |= dwCaps & DDSCAPS_WRITEONLY;
  327. D3D_INFO(8, "Trying to create a vid mem vertex buffer");
  328. if (lpD3DI->lpDD4->CreateSurface(&ddsd, lplpSurface4, NULL) != DD_OK)
  329. {
  330. // If that failed, or user requested sys mem, try explicit system memory
  331. D3D_INFO(6, "Trying to create a sys mem vertex buffer");
  332. ddsd.ddsCaps.dwCaps &= ~(DDSCAPS_VIDEOMEMORY | DDSCAPS_WRITEONLY);
  333. ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
  334. ret = lpD3DI->lpDD4->CreateSurface(&ddsd, lplpSurface4, NULL);
  335. if (ret != DD_OK)
  336. {
  337. D3D_ERR("Could not allocate the Vertex buffer.");
  338. return ret;
  339. }
  340. }
  341. else
  342. {
  343. // Mark VB as REALLY in vid mem for Lock / Unlock optimizations
  344. this->dwMemType = DDSCAPS_VIDEOMEMORY;
  345. }
  346. }
  347. *lplpMemory = NULL;
  348. if (!(this->dwMemType & DDSCAPS_VIDEOMEMORY))
  349. {
  350. ret = (*lplpSurface4)->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_NOSYSLOCK, NULL);
  351. if (ret != DD_OK)
  352. {
  353. D3D_ERR("Could not lock system memory Vertex Buffer.");
  354. return ret;
  355. }
  356. *lplpMemory = ddsd.lpSurface;
  357. }
  358. ret = lpDDSVB->QueryInterface(IID_IDirectDrawSurface, (LPVOID*)lplpSurface);
  359. if (ret != DD_OK)
  360. {
  361. D3D_ERR("failed to QI for DDS1");
  362. return ret;
  363. }
  364. return D3D_OK;
  365. }
  366. //---------------------------------------------------------------------
  367. #undef DPF_MODNAME
  368. #define DPF_MODNAME "Direct3DVertexBuffer::init"
  369. HRESULT CDirect3DVertexBuffer::Init(LPDIRECT3DI lpD3DI, LPD3DVERTEXBUFFERDESC lpDesc, DWORD dwFlags)
  370. {
  371. HRESULT ret;
  372. bReallyOptimized = FALSE;
  373. dwCaps = lpDesc->dwCaps;
  374. fvf = lpDesc->dwFVF;
  375. dwNumVertices = lpDesc->dwNumVertices;
  376. if (dwNumVertices > MAX_DX6_VERTICES)
  377. {
  378. D3D_ERR("Direct3D for DirectX 6.0 cannot handle greater than 64K vertices");
  379. return D3DERR_TOOMANYVERTICES;
  380. }
  381. if (lpDesc->dwCaps & D3DVBCAPS_OPTIMIZED)
  382. {
  383. D3D_ERR("D3DVBCAPS_OPTIMIZED flag should not be set");
  384. return DDERR_INVALIDPARAMS;
  385. }
  386. if (fvf & 0xfffff000) // Higher order 20 bits must be zero for DX6
  387. {
  388. D3D_ERR("Invalid FVF id");
  389. return D3DERR_INVALIDVERTEXFORMAT;
  390. }
  391. nTexCoord = FVF_TEXCOORD_NUMBER(fvf);
  392. if ((position.dwStride = calcVertexSize(fvf)) == 0)
  393. {
  394. D3D_ERR("Vertex size is zero according to the FVF id");
  395. return D3DERR_INVALIDVERTEXFORMAT;
  396. }
  397. if (dwFlags & D3DVBFLAGS_CREATEMULTIBUFFER)
  398. dwMemType = 0;
  399. else
  400. dwMemType = DDSCAPS2_VERTEXBUFFER;
  401. ret = CreateMemoryBuffer(lpD3DI, &lpDDSVB, &lpDDS1VB, &position.lpvData,
  402. position.dwStride * dwNumVertices, dwFlags);
  403. if (ret != D3D_OK)
  404. return ret;
  405. /* Classify the operations that can be done using this VB */
  406. if ((fvf & D3DFVF_POSITION_MASK) == D3DFVF_XYZ)
  407. {
  408. D3D_INFO(4, "D3DFVF_XYZ set. Can be source VB for Transform");
  409. srcVOP = D3DVOP_TRANSFORM | D3DVOP_EXTENTS | D3DVOP_CLIP;
  410. }
  411. else if ((fvf & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW)
  412. {
  413. D3D_INFO(4, "D3DFVF_XYZRHW set. Can be dest VB for Transform");
  414. dstVOP = D3DVOP_TRANSFORM | D3DVOP_EXTENTS;
  415. srcVOP |= D3DVOP_EXTENTS;
  416. if ((dwFlags & D3DDP_DONOTCLIP) == 0)
  417. {
  418. clipCodes = new D3DFE_CLIPCODE[dwNumVertices];
  419. if (clipCodes == NULL)
  420. {
  421. D3D_ERR("Could not allocate space for clip flags");
  422. return DDERR_OUTOFMEMORY;
  423. }
  424. memset(clipCodes, 0, dwNumVertices * sizeof(D3DFE_CLIPCODE));
  425. dstVOP |= D3DVOP_CLIP;
  426. }
  427. }
  428. if (fvf & D3DFVF_NORMAL)
  429. {
  430. D3D_INFO(4, "D3DFVF_NORMAL set.");
  431. if (srcVOP & D3DVOP_TRANSFORM)
  432. {
  433. D3D_INFO(4, "Can be src VB for lighting.");
  434. srcVOP |= D3DVOP_LIGHT;
  435. }
  436. this->dwPVFlags |= D3DPV_LIGHTING;
  437. }
  438. if (fvf & D3DFVF_DIFFUSE)
  439. {
  440. D3D_INFO(4, "D3DFVF_DIFFUSE set. Can be dest VB for lighting");
  441. dstVOP |= D3DVOP_LIGHT;
  442. }
  443. if (dstVOP & D3DVOP_TRANSFORM)
  444. {
  445. D3D_INFO(4, "VB can be rendered");
  446. srcVOP |= D3DVOP_RENDER;
  447. }
  448. /* Compare with legacy vertex types */
  449. if (fvf == D3DFVF_VERTEX)
  450. {
  451. legacyVertexType = D3DVT_VERTEX;
  452. }
  453. else if (fvf == D3DFVF_LVERTEX)
  454. {
  455. legacyVertexType = D3DVT_LVERTEX;
  456. }
  457. else if (fvf == D3DFVF_TLVERTEX)
  458. {
  459. legacyVertexType = D3DVT_TLVERTEX;
  460. }
  461. return(D3D_OK);
  462. }
  463. #undef DPF_MODNAME
  464. #define DPF_MODNAME "Direct3DVertexBuffer::Lock"
  465. HRESULT D3DAPI CDirect3DVertexBuffer::Lock(DWORD dwFlags, LPVOID* lplpData, DWORD* lpdwSize)
  466. {
  467. CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock.
  468. HRESULT ret;
  469. #if DBG
  470. /*
  471. * validate parms
  472. */
  473. TRY
  474. {
  475. if (!VALID_DIRECT3DVERTEXBUFFER_PTR(this)) {
  476. D3D_ERR( "Invalid Direct3DVertexBuffer pointer" );
  477. return DDERR_INVALIDPARAMS;
  478. }
  479. if (IsBadWritePtr( lplpData, sizeof(LPVOID))) {
  480. D3D_ERR( "Invalid lpData pointer" );
  481. return DDERR_INVALIDPARAMS;
  482. }
  483. if (lpdwSize)
  484. if (IsBadWritePtr( lpdwSize, sizeof(DWORD))) {
  485. D3D_ERR( "Invalid lpData pointer" );
  486. return DDERR_INVALIDPARAMS;
  487. }
  488. }
  489. EXCEPT( EXCEPTION_EXECUTE_HANDLER )
  490. {
  491. D3D_ERR( "Exception encountered validating parameters" );
  492. return 0;
  493. }
  494. #endif
  495. if (this->dwCaps & D3DVBCAPS_OPTIMIZED)
  496. {
  497. D3D_ERR("Cannot lock optimized vertex buffer");
  498. return(D3DERR_VERTEXBUFFEROPTIMIZED);
  499. }
  500. return this->LockI(dwFlags, lplpData, lpdwSize);
  501. }
  502. //---------------------------------------------------------------------
  503. // Side effect:
  504. // position.lpvData is set.
  505. //
  506. #undef DPF_MODNAME
  507. #define DPF_MODNAME "Direct3DVertexBuffer::LockI"
  508. HRESULT D3DAPI CDirect3DVertexBuffer::LockI(DWORD dwFlags, LPVOID* lplpData,
  509. DWORD* lpdwSize)
  510. {
  511. HRESULT ret;
  512. if (lpdwSize)
  513. *lpdwSize = position.dwStride * dwNumVertices;
  514. if (position.lpvData)
  515. {
  516. *lplpData = position.lpvData;
  517. }
  518. else
  519. {
  520. DDSURFACEDESC2 ddsd;
  521. memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
  522. ddsd.dwSize = sizeof(DDSURFACEDESC2);
  523. ret = lpDDSVB->Lock(NULL, &ddsd, dwFlags | DDLOCK_NOSYSLOCK, NULL);
  524. if (ret != DD_OK)
  525. {
  526. D3D_ERR("Could not lock vertex buffer.");
  527. return ret;
  528. }
  529. *lplpData = ddsd.lpSurface;
  530. position.lpvData = ddsd.lpSurface;
  531. }
  532. dwLockCnt++;
  533. D3D_INFO(6, "VB Lock: %lx Lock Cnt =%d", this, dwLockCnt);
  534. if (lpDevIBatched && !(dwFlags & DDLOCK_READONLY))
  535. {
  536. ret = lpDevIBatched->FlushStates();
  537. lpDevIBatched = NULL;
  538. if (ret != D3D_OK)
  539. {
  540. D3D_ERR("Could not flush batch referring to VB during Lock");
  541. return ret;
  542. }
  543. }
  544. return D3D_OK;
  545. }
  546. #undef DPF_MODNAME
  547. #define DPF_MODNAME "Direct3DVertexBuffer::Unlock"
  548. HRESULT D3DAPI CDirect3DVertexBuffer::Unlock()
  549. {
  550. if (dwLockCnt)
  551. {
  552. dwLockCnt--;
  553. if ((dwMemType & DDSCAPS_VIDEOMEMORY) && (dwLockCnt == 0))
  554. {
  555. position.lpvData = NULL;
  556. D3D_INFO(6, "VB Unlock: %lx Lock Cnt =%d", this, dwLockCnt);
  557. return lpDDSVB->Unlock(NULL);
  558. }
  559. }
  560. D3D_INFO(6, "VB Unlock: %lx Lock Cnt =%d", this, dwLockCnt);
  561. return D3D_OK;
  562. }
  563. #undef DPF_MODNAME
  564. #define DPF_MODNAME "Direct3DVertexBuffer::GetVertexBufferDesc"
  565. HRESULT D3DAPI CDirect3DVertexBuffer::GetVertexBufferDesc(LPD3DVERTEXBUFFERDESC lpDesc)
  566. {
  567. #if DBG
  568. /*
  569. * validate parms
  570. */
  571. TRY
  572. {
  573. if (!VALID_DIRECT3DVERTEXBUFFER_PTR(this)) {
  574. D3D_ERR( "Invalid Direct3DVertexBuffer pointer" );
  575. return DDERR_INVALIDPARAMS;
  576. }
  577. if (IsBadWritePtr( lpDesc, lpDesc->dwSize)) {
  578. D3D_ERR( "Invalid lpData pointer" );
  579. return DDERR_INVALIDPARAMS;
  580. }
  581. if (! VALID_D3DVERTEXBUFFERDESC_PTR(lpDesc) )
  582. {
  583. D3D_ERR( "Invalid D3DVERTEXBUFFERDESC" );
  584. return DDERR_INVALIDPARAMS;
  585. }
  586. }
  587. EXCEPT( EXCEPTION_EXECUTE_HANDLER )
  588. {
  589. D3D_ERR( "Exception encountered validating parameters" );
  590. return 0;
  591. }
  592. #endif
  593. lpDesc->dwCaps = dwCaps;
  594. lpDesc->dwFVF = fvf;
  595. lpDesc->dwNumVertices = this->dwNumVertices;
  596. return D3D_OK;
  597. }
  598. #undef DPF_MODNAME
  599. #define DPF_MODNAME "Direct3DVertexBuffer::ProcessVertices"
  600. HRESULT D3DAPI CDirect3DVertexBuffer::ProcessVertices(DWORD vertexOP, DWORD dwDstIndex, DWORD dwCount,
  601. LPDIRECT3DVERTEXBUFFER lpSrc,
  602. DWORD dwSrcIndex,
  603. LPDIRECT3DDEVICE3 lpDevice, DWORD dwFlags)
  604. {
  605. LPDIRECT3DVERTEXBUFFERI lpSrcI;
  606. LPDIRECT3DDEVICEI lpDevI;
  607. #if DBG
  608. /*
  609. * validate parms
  610. */
  611. TRY
  612. {
  613. if (!VALID_DIRECT3DVERTEXBUFFER_PTR(this)) {
  614. D3D_ERR( "Invalid Direct3DVertexBuffer pointer" );
  615. return DDERR_INVALIDPARAMS;
  616. }
  617. if (!VALID_DIRECT3DVERTEXBUFFER_PTR(lpSrc)) {
  618. D3D_ERR( "Invalid Direct3DVertexBuffer pointer" );
  619. return DDERR_INVALIDPARAMS;
  620. }
  621. lpSrcI = static_cast<LPDIRECT3DVERTEXBUFFERI>(lpSrc);
  622. if (!VALID_DIRECT3DDEVICE3_PTR(lpDevice)) {
  623. D3D_ERR( "Invalid Direct3DDevice pointer" );
  624. return DDERR_INVALIDOBJECT;
  625. }
  626. lpDevI = static_cast<LPDIRECT3DDEVICEI>(lpDevice);
  627. }
  628. EXCEPT( EXCEPTION_EXECUTE_HANDLER )
  629. {
  630. D3D_ERR( "Exception encountered validating parameters" );
  631. return 0;
  632. }
  633. if (dwFlags != 0 ||
  634. (dwDstIndex + dwCount) > this->dwNumVertices ||
  635. (dwSrcIndex + dwCount) > lpSrcI->dwNumVertices)
  636. {
  637. D3D_ERR( "Invalid parameters" );
  638. return DDERR_INVALIDPARAMS;
  639. }
  640. /* Validate Src & Dst Vertex Formats */
  641. if ((lpSrcI->srcVOP & vertexOP) != vertexOP)
  642. {
  643. D3D_ERR("Source VB cannot support this operation");
  644. return D3DERR_INVALIDVERTEXFORMAT;
  645. }
  646. if (!(vertexOP & D3DVOP_TRANSFORM))
  647. {
  648. D3D_ERR("D3DVOP_TRANSFORM flag should be set");
  649. return DDERR_INVALIDPARAMS;
  650. }
  651. if ((dstVOP & vertexOP) != vertexOP)
  652. {
  653. D3D_ERR("Destination VB cannot support this operation");
  654. return D3DERR_INVALIDVERTEXFORMAT;
  655. }
  656. if (this->fvf & D3DFVF_NORMAL)
  657. {
  658. D3D_ERR("The destination vertex buffer cannot have normals");
  659. return D3DERR_INVALIDVERTEXFORMAT;
  660. }
  661. #else
  662. lpSrcI = static_cast<LPDIRECT3DVERTEXBUFFERI>(lpSrc);
  663. lpDevI = static_cast<LPDIRECT3DDEVICEI>(lpDevice);
  664. #endif
  665. CLockD3DMT lockObject(lpDevI, DPF_MODNAME, REMIND("")); // Takes D3D lock.
  666. // Fill the D3DFE_PROCESSVERTICES structure
  667. // STRIDE and SOA flags
  668. lpDevI->dwFlags = lpSrcI->dwPVFlags & D3DPV_SOA;
  669. // LIGHTING, EXTENTS and CLIP flags (note extents and clip flags are inverted)
  670. // Currently transform is always done
  671. lpDevI->dwFlags |= (vertexOP ^ (D3DVOP_CLIP | D3DVOP_EXTENTS)) | D3DVOP_TRANSFORM;
  672. HRESULT ret;
  673. // Download viewport ??
  674. if (lpDevI->v_id != lpDevI->lpCurrentViewport->v_id)
  675. {
  676. ret = downloadView(lpDevI->lpCurrentViewport);
  677. if (ret != D3D_OK)
  678. return ret;
  679. }
  680. // Num vertices
  681. lpDevI->dwNumVertices = dwCount;
  682. // Lock the VBs
  683. LPVOID lpVoid;
  684. ret = LockI(DDLOCK_WAIT, &lpVoid, NULL);
  685. if (ret != D3D_OK)
  686. {
  687. D3D_ERR("Could not lock the vertex buffer");
  688. return ret;
  689. }
  690. ret = lpSrcI->LockI(DDLOCK_WAIT | DDLOCK_READONLY, &lpVoid, NULL);
  691. if (ret != D3D_OK)
  692. {
  693. D3D_ERR("Could not lock the vertex buffer");
  694. return ret;
  695. }
  696. // Output
  697. lpDevI->lpvOut = LPVOID(LPBYTE(position.lpvData) + dwDstIndex * position.dwStride);
  698. lpDevI->lpClipFlags = clipCodes + dwDstIndex;
  699. lpDevI->dwVIDIn = lpSrcI->fvf;
  700. lpDevI->dwVIDOut = fvf;
  701. if (lpSrcI->legacyVertexType && legacyVertexType)
  702. { // AOS Legacy
  703. /* We can use the legacy FE codepaths which might
  704. * be faster
  705. */
  706. lpDevI->position.lpvData = LPVOID(LPBYTE(lpSrcI->position.lpvData) + dwSrcIndex * lpSrcI->position.dwStride);
  707. lpDevI->nTexCoord = 1;
  708. lpDevI->position.dwStride = lpSrcI->position.dwStride;
  709. lpDevI->dwOutputSize = position.dwStride;
  710. }
  711. else
  712. {
  713. lpDevI->nTexCoord = min(nTexCoord, lpSrcI->nTexCoord);
  714. if (lpSrcI->bReallyOptimized)
  715. { // SOA
  716. // Assume that SOA.lpvData is the same as position.lpvData
  717. lpDevI->SOA.lpvData = lpSrcI->position.lpvData;
  718. lpDevI->SOA.dwStride = lpSrcI->dwNumVertices;
  719. lpDevI->dwSOAStartVertex = dwSrcIndex;
  720. lpDevI->dwOutputSize = position.dwStride;
  721. }
  722. else
  723. { // AOS FVF
  724. lpDevI->dwOutputSize = position.dwStride;
  725. lpDevI->position.lpvData = LPVOID(LPBYTE(lpSrcI->position.lpvData) + dwSrcIndex * lpSrcI->position.dwStride);
  726. lpDevI->position.dwStride = lpSrcI->position.dwStride;
  727. }
  728. }
  729. lpDevI->dwFlags |= D3DPV_VBCALL;
  730. D3DFE_ProcessVertices(lpDevI);
  731. if (!(lpDevI->dwFlags & D3DDP_DONOTCLIP))
  732. D3DFE_UpdateClipStatus(lpDevI);
  733. // Unlock the VBs
  734. Unlock();
  735. lpSrcI->Unlock();
  736. return D3D_OK;
  737. }
  738. #undef DPF_MODNAME
  739. #define DPF_MODNAME "IDirect3DDevice3::DrawIndexedPrimitiveVB"
  740. HRESULT D3DAPI DIRECT3DDEVICEI::DrawIndexedPrimitiveVB(D3DPRIMITIVETYPE dptPrimitiveType,
  741. LPDIRECT3DVERTEXBUFFER lpVBuf,
  742. LPWORD lpwIndices, DWORD dwIndexCount,
  743. DWORD dwFlags)
  744. {
  745. LPDIRECT3DVERTEXBUFFERI lpVBufI;
  746. CLockD3DMT lockObject(this, DPF_MODNAME, REMIND("")); // Takes D3D lock.
  747. HRESULT ret;
  748. #if DBG
  749. /*
  750. * validate parms
  751. */
  752. TRY
  753. {
  754. if (!VALID_DIRECT3DVERTEXBUFFER_PTR(lpVBuf)) {
  755. D3D_ERR( "Invalid Direct3DVertexBuffer pointer" );
  756. return DDERR_INVALIDPARAMS;
  757. }
  758. lpVBufI = static_cast<LPDIRECT3DVERTEXBUFFERI>(lpVBuf);
  759. if (!VALID_DIRECT3DDEVICE3_PTR(this)) {
  760. D3D_ERR( "Invalid Direct3DDevice pointer" );
  761. return DDERR_INVALIDOBJECT;
  762. }
  763. }
  764. EXCEPT( EXCEPTION_EXECUTE_HANDLER )
  765. {
  766. D3D_ERR( "Exception encountered validating parameters" );
  767. return 0;
  768. }
  769. if (!IsDPFlagsValid(dwFlags))
  770. {
  771. D3D_ERR("Invalid Flags in dwFlags field");
  772. return DDERR_INVALIDPARAMS;
  773. }
  774. if (!(IS_HW_DEVICE(this) || (lpVBufI->dwCaps & D3DVBCAPS_SYSTEMMEMORY)))
  775. {
  776. D3D_ERR("Cannot use vid mem vertex buffers with SW devices");
  777. return DDERR_INVALIDPARAMS;
  778. }
  779. if (lpVBufI->dwLockCnt)
  780. {
  781. D3D_ERR("Cannot render using a locked vertex buffer");
  782. return D3DERR_VERTEXBUFFERLOCKED;
  783. }
  784. if (this->dwNumPrimitives > MAX_DX6_PRIMCOUNT)
  785. {
  786. D3D_ERR("D3D for DX6 cannot handle greater that 64K sized primitives");
  787. return D3DERR_TOOMANYPRIMITIVES;
  788. }
  789. Profile(PROF_DRAWINDEXEDPRIMITIVEVB,dptPrimitiveType,lpVBufI->fvf);
  790. #else
  791. lpVBufI = static_cast<LPDIRECT3DVERTEXBUFFERI>(lpVBuf);
  792. #endif
  793. this->dwFlags = dwFlags | lpVBufI->dwPVFlags;
  794. this->primType = dptPrimitiveType;
  795. this->dwNumVertices = lpVBufI->dwNumVertices;
  796. this->dwNumIndices = dwIndexCount;
  797. this->lpwIndices = lpwIndices;
  798. GetNumPrim(this, dwNumIndices); // Calculate dwNumPrimitives and update stats
  799. this->dwFEFlags |= D3DFE_NEED_TEXTURE_UPDATE; // Need to call UpdateTextures()
  800. if (lpVBufI->srcVOP & D3DVOP_RENDER)
  801. { // TLVERTEX
  802. #if DBG
  803. if (lpVBufI->fvf & D3DFVF_NORMAL)
  804. {
  805. D3D_ERR("The vertex buffer cannot be processed");
  806. D3D_ERR("It has XYZRHW position type and normals");
  807. return DDERR_INVALIDPARAMS;
  808. }
  809. #endif
  810. this->dwOutputSize = lpVBufI->position.dwStride;
  811. this->dwVIDOut = lpVBufI->fvf;
  812. this->dwVIDIn = lpVBufI->fvf;
  813. // needed for legacy drivers' DrawIndexPrim code
  814. this->lpvOut = lpVBufI->position.lpvData;
  815. if (IS_DP2HAL_DEVICE(this))
  816. {
  817. this->nTexCoord = lpVBufI->nTexCoord;
  818. CDirect3DDeviceIDP2 *dev = static_cast<CDirect3DDeviceIDP2*>(this);
  819. ret = dev->StartPrimVB(lpVBufI, 0);
  820. lpVBufI->lpDevIBatched = this;
  821. if (ret != D3D_OK)
  822. return ret;
  823. }
  824. else
  825. {
  826. ComputeTCI2CopyLegacy(this, lpVBufI->nTexCoord, TRUE);
  827. }
  828. if (dwFlags & D3DDP_DONOTCLIP)
  829. {
  830. return DrawIndexPrim();
  831. }
  832. else
  833. {
  834. this->lpClipFlags = lpVBufI->clipCodes;
  835. this->dwClipUnion = ~0; // Force clipping
  836. // If lpvData is NULL, it is a driver allocated buffer which
  837. // means IS_DPHAL_DEVICE() is true.
  838. // We need to lock such a buffer only if we need to clip
  839. if (!lpVBufI->position.lpvData)
  840. {
  841. // Lock VB
  842. DDSURFACEDESC2 ddsd;
  843. memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
  844. ddsd.dwSize = sizeof(DDSURFACEDESC2);
  845. ret = lpVBufI->lpDDSVB->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_READONLY | DDLOCK_NOSYSLOCK, NULL);
  846. if (ret != DD_OK)
  847. {
  848. D3D_ERR("Could not lock vertex buffer.");
  849. return ret;
  850. }
  851. this->lpvOut = ddsd.lpSurface;
  852. // Draw with clipping
  853. #if DBG
  854. // To Do: Check vertices & clip flags against current viewport
  855. this->position.lpvData = this->lpvOut; // Otherwise the check will fail
  856. ret = CheckDrawIndexedPrimitive(this);
  857. if (ret == D3D_OK)
  858. ret = DoDrawIndexedPrimitive(this);
  859. #else
  860. ret = DoDrawIndexedPrimitive(this);
  861. #endif
  862. // Unlock VB
  863. if (ret == D3D_OK)
  864. return lpVBufI->lpDDSVB->Unlock(NULL);
  865. else
  866. lpVBufI->lpDDSVB->Unlock(NULL);
  867. return ret;
  868. }
  869. else
  870. {
  871. // Draw with clipping
  872. #if DBG
  873. // To Do: Check vertices & clip flags against current viewport
  874. this->position.lpvData = this->lpvOut; // Otherwise the check will fail
  875. ret = CheckDrawIndexedPrimitive(this);
  876. if (ret != D3D_OK)
  877. return ret;
  878. #endif
  879. return DoDrawIndexedPrimitive(this);
  880. }
  881. }
  882. }
  883. else
  884. {
  885. this->dwVIDIn = lpVBufI->fvf;
  886. if (lpVBufI->bReallyOptimized)
  887. {
  888. // Assume that SOA.lpvData is the same as position.lpvData
  889. this->SOA.lpvData = lpVBufI->position.lpvData;
  890. this->SOA.dwStride = lpVBufI->dwNumVertices;
  891. this->dwSOAStartVertex = 0;
  892. }
  893. else
  894. {
  895. this->position = lpVBufI->position;
  896. }
  897. ComputeOutputFVF(this);
  898. #if DBG
  899. ret = CheckDrawIndexedPrimitive(this);
  900. if (ret != D3D_OK)
  901. return ret;
  902. #endif
  903. return this->ProcessPrimitive(__PROCPRIMOP_INDEXEDPRIM);
  904. }
  905. }
  906. #undef DPF_MODNAME
  907. #define DPF_MODNAME "Direct3DDevice3::DrawPrimitiveVB"
  908. HRESULT D3DAPI DIRECT3DDEVICEI::DrawPrimitiveVB(D3DPRIMITIVETYPE dptPrimitiveType,
  909. LPDIRECT3DVERTEXBUFFER lpVBuf,
  910. DWORD dwStartVertex, DWORD dwNumVertices,
  911. DWORD dwFlags)
  912. {
  913. LPDIRECT3DVERTEXBUFFERI lpVBufI;
  914. CLockD3DMT lockObject(this, DPF_MODNAME, REMIND("")); // Takes D3D lock
  915. HRESULT ret;
  916. #if DBG
  917. /*
  918. * validate parms
  919. */
  920. TRY
  921. {
  922. if (!VALID_DIRECT3DVERTEXBUFFER_PTR(lpVBuf)) {
  923. D3D_ERR( "Invalid Direct3DVertexBuffer pointer" );
  924. return DDERR_INVALIDPARAMS;
  925. }
  926. lpVBufI = static_cast<LPDIRECT3DVERTEXBUFFERI>(lpVBuf);
  927. if (!VALID_DIRECT3DDEVICE3_PTR(this)) {
  928. D3D_ERR( "Invalid Direct3DDevice pointer" );
  929. return DDERR_INVALIDOBJECT;
  930. }
  931. }
  932. EXCEPT( EXCEPTION_EXECUTE_HANDLER )
  933. {
  934. D3D_ERR( "Exception encountered validating parameters" );
  935. return 0;
  936. }
  937. if (!IsDPFlagsValid(dwFlags) ||
  938. (dwStartVertex + dwNumVertices) > lpVBufI->dwNumVertices)
  939. return DDERR_INVALIDPARAMS;
  940. if (!(IS_HW_DEVICE(this) || (lpVBufI->dwCaps & D3DVBCAPS_SYSTEMMEMORY)))
  941. {
  942. D3D_ERR("Cannot use vid mem vertex buffers with SW devices");
  943. return DDERR_INVALIDPARAMS;
  944. }
  945. if (lpVBufI->dwLockCnt)
  946. {
  947. D3D_ERR("Cannot render using a locked vertex buffer");
  948. return D3DERR_VERTEXBUFFERLOCKED;
  949. }
  950. if (dwNumVertices > MAX_DX6_VERTICES)
  951. {
  952. D3D_ERR("D3D for DX6 cannot handle greater than 64K vertices");
  953. return D3DERR_TOOMANYVERTICES;
  954. }
  955. Profile(PROF_DRAWPRIMITIVEVB,dptPrimitiveType,lpVBufI->fvf);
  956. #else
  957. lpVBufI = static_cast<LPDIRECT3DVERTEXBUFFERI>(lpVBuf);
  958. #endif
  959. this->dwFlags = dwFlags | lpVBufI->dwPVFlags;
  960. this->primType = dptPrimitiveType;
  961. this->dwNumVertices = dwNumVertices;
  962. this->dwNumIndices = 0;
  963. this->lpwIndices = NULL;
  964. GetNumPrim(this, dwNumVertices); // Calculate dwNumPrimitives and update stats
  965. this->dwFEFlags |= D3DFE_NEED_TEXTURE_UPDATE; // Need to call UpdateTextures()
  966. if (lpVBufI->srcVOP & D3DVOP_RENDER)
  967. { // TLVERTEX
  968. #if DBG
  969. if (lpVBufI->fvf & D3DFVF_NORMAL)
  970. {
  971. D3D_ERR("The vertex buffer cannot be processed");
  972. D3D_ERR("It has XYZRHW position type and normals");
  973. return DDERR_INVALIDPARAMS;
  974. }
  975. #endif
  976. this->dwOutputSize = lpVBufI->position.dwStride;
  977. this->dwVIDOut = lpVBufI->fvf;
  978. // needed for legacy drivers' DrawPrim code
  979. this->lpvOut = (BYTE*)(lpVBufI->position.lpvData) +
  980. dwStartVertex * this->dwOutputSize;
  981. if (IS_DP2HAL_DEVICE(this))
  982. {
  983. this->nTexCoord = lpVBufI->nTexCoord;
  984. CDirect3DDeviceIDP2 *dev = static_cast<CDirect3DDeviceIDP2*>(this);
  985. ret = dev->StartPrimVB(lpVBufI, dwStartVertex);
  986. lpVBufI->lpDevIBatched = this;
  987. if (ret != D3D_OK)
  988. return ret;
  989. }
  990. else
  991. {
  992. ComputeTCI2CopyLegacy(this, lpVBufI->nTexCoord, TRUE);
  993. }
  994. if (dwFlags & D3DDP_DONOTCLIP)
  995. {
  996. return DrawPrim();
  997. }
  998. else
  999. {
  1000. this->lpClipFlags = lpVBufI->clipCodes + dwStartVertex;
  1001. this->dwClipUnion = ~0; // Force clipping
  1002. // If lpvData is NULL, it is a driver allocated buffer which
  1003. // means IS_DPHAL_DEVICE() is true.
  1004. // We need to lock such a buffer only if we need to clip
  1005. if (!lpVBufI->position.lpvData)
  1006. {
  1007. // Lock VB
  1008. DDSURFACEDESC2 ddsd;
  1009. memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
  1010. ddsd.dwSize = sizeof(DDSURFACEDESC2);
  1011. ret = lpVBufI->lpDDSVB->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_READONLY | DDLOCK_NOSYSLOCK, NULL);
  1012. if (ret != DD_OK)
  1013. {
  1014. D3D_ERR("Could not lock vertex buffer.");
  1015. return ret;
  1016. }
  1017. this->lpvOut = (BYTE*)(ddsd.lpSurface) +
  1018. dwStartVertex * this->dwOutputSize;
  1019. // Draw with clipping
  1020. #if DBG
  1021. // To Do: Check vertices & clip flags against current viewport
  1022. this->position.lpvData = this->lpvOut; // Otherwise the check will fail
  1023. ret=CheckDrawPrimitive(this);
  1024. if (ret == D3D_OK)
  1025. ret = DoDrawPrimitive(this);
  1026. #else
  1027. ret = DoDrawPrimitive(this);
  1028. #endif
  1029. // Unlock VB
  1030. if (ret == D3D_OK)
  1031. return lpVBufI->lpDDSVB->Unlock(NULL);
  1032. else
  1033. lpVBufI->lpDDSVB->Unlock(NULL);
  1034. return ret;
  1035. }
  1036. else
  1037. {
  1038. // Draw with clipping
  1039. #if DBG
  1040. // To Do: Check vertices & clip flags against current viewport
  1041. this->position.lpvData = this->lpvOut; // Otherwise the check will fail
  1042. ret=CheckDrawPrimitive(this);
  1043. if (ret != D3D_OK)
  1044. return ret;
  1045. #endif
  1046. return DoDrawPrimitive(this);
  1047. }
  1048. }
  1049. }
  1050. else
  1051. {
  1052. this->dwVIDIn = lpVBufI->fvf;
  1053. if (lpVBufI->bReallyOptimized)
  1054. {
  1055. // Assume that SOA.lpvData is the same as position.lpvData
  1056. this->SOA.lpvData = lpVBufI->position.lpvData;
  1057. this->SOA.dwStride = lpVBufI->dwNumVertices;
  1058. this->dwSOAStartVertex = dwStartVertex;
  1059. }
  1060. else
  1061. {
  1062. this->position.lpvData = (BYTE*)(lpVBufI->position.lpvData) +
  1063. dwStartVertex * lpVBufI->position.dwStride;
  1064. this->position.dwStride = lpVBufI->position.dwStride;
  1065. }
  1066. ComputeOutputFVF(this);
  1067. #if DBG
  1068. ret=CheckDrawPrimitive(this);
  1069. if (ret != D3D_OK)
  1070. return ret;
  1071. #endif
  1072. return this->ProcessPrimitive();
  1073. }
  1074. }
  1075. //---------------------------------------------------------------------
  1076. #undef DPF_MODNAME
  1077. #define DPF_MODNAME "CDirect3DVertexBuffer::Optimize"
  1078. HRESULT D3DAPI CDirect3DVertexBuffer::Optimize(LPDIRECT3DDEVICE3 lpDevice, DWORD dwFlags)
  1079. {
  1080. HRESULT ret;
  1081. LPDIRECT3DDEVICEI lpDevI;
  1082. // Validate parms
  1083. //
  1084. TRY
  1085. {
  1086. if (!VALID_DIRECT3DVERTEXBUFFER_PTR(this))
  1087. {
  1088. D3D_ERR( "Invalid Direct3DVertexBuffer pointer" );
  1089. return DDERR_INVALIDPARAMS;
  1090. }
  1091. if (!VALID_DIRECT3DDEVICE3_PTR(lpDevice))
  1092. {
  1093. D3D_ERR( "Invalid Direct3DDevice pointer" );
  1094. return DDERR_INVALIDOBJECT;
  1095. }
  1096. lpDevI = static_cast<LPDIRECT3DDEVICEI>(lpDevice);
  1097. }
  1098. EXCEPT( EXCEPTION_EXECUTE_HANDLER )
  1099. {
  1100. D3D_ERR( "Exception encountered validating parameters" );
  1101. return 0;
  1102. }
  1103. if (dwFlags != 0)
  1104. {
  1105. D3D_ERR("dwFlags should be zero");
  1106. return DDERR_INVALIDPARAMS;
  1107. }
  1108. CLockD3DMT lockObject(lpDevI, DPF_MODNAME, REMIND(""));
  1109. if (this->dwCaps & D3DVBCAPS_OPTIMIZED)
  1110. {
  1111. D3D_ERR("The vertex buffer already optimized");
  1112. return D3DERR_VERTEXBUFFEROPTIMIZED;
  1113. }
  1114. if (this->dwLockCnt != 0)
  1115. {
  1116. D3D_ERR("Could not optimize locked vertex buffer");
  1117. return D3DERR_VERTEXBUFFERLOCKED;
  1118. }
  1119. // Do nothing for transformed vertices
  1120. if ((this->fvf & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW)
  1121. {
  1122. this->dwCaps |= D3DVBCAPS_OPTIMIZED;
  1123. return D3D_OK;
  1124. }
  1125. // Get the buffer size to allocate
  1126. DWORD bufferSize = lpDevI->pGeometryFuncs->ComputeOptimizedVertexBufferSize
  1127. (this->fvf, this->position.dwStride,
  1128. dwNumVertices);
  1129. // Create new surfaces for optimized vertex buffer
  1130. if (bufferSize == 0)
  1131. {
  1132. this->dwCaps |= D3DVBCAPS_OPTIMIZED;
  1133. return D3D_OK;
  1134. }
  1135. LPDIRECTDRAWSURFACE4 lpSurface4;
  1136. LPDIRECTDRAWSURFACE lpSurface;
  1137. LPVOID lpMemory;
  1138. ret = CreateMemoryBuffer(lpDevI->lpDirect3DI, &lpSurface4, &lpSurface,
  1139. &lpMemory, bufferSize,
  1140. clipCodes ? 0 : D3DDP_DONOTCLIP);
  1141. if (ret != D3D_OK)
  1142. return ret;
  1143. // Try to optimize
  1144. // If optimized vertex buffer are not supported by the implementation
  1145. // it returns E_NOTIMPL. In this case we still set D3DVBCAPS_OPTIMIZED to prevent
  1146. // locking of the vertex buffer. But bReallyOptimized is set to FALSE, to use
  1147. // the original buffer.
  1148. ret = lpDevI->pGeometryFuncs->OptimizeVertexBuffer
  1149. (fvf, dwNumVertices, position.dwStride, position.lpvData,
  1150. lpMemory, dwFlags);
  1151. if (ret)
  1152. {
  1153. lpSurface4->Release();
  1154. lpSurface->Release();
  1155. if (ret == E_NOTIMPL)
  1156. {
  1157. this->dwCaps |= D3DVBCAPS_OPTIMIZED;
  1158. return D3D_OK;
  1159. }
  1160. else
  1161. {
  1162. D3D_ERR("Failed to optimize vertex buffer");
  1163. return ret;
  1164. }
  1165. }
  1166. bReallyOptimized = TRUE;
  1167. legacyVertexType = (D3DVERTEXTYPE)0;
  1168. this->dwPVFlags |= D3DPV_SOA;
  1169. this->dwCaps |= D3DVBCAPS_OPTIMIZED;
  1170. // Destroy old surfaces
  1171. lpDDSVB->Release();
  1172. lpDDS1VB->Release();
  1173. // And use new ones
  1174. lpDDSVB = lpSurface4;
  1175. lpDDS1VB = lpSurface;
  1176. position.lpvData = lpMemory;
  1177. return D3D_OK;
  1178. }