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.

1362 lines
45 KiB

  1. /*==========================================================================;
  2. *
  3. * Copyright (C) 1999-2000 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: vbuffer.cpp
  6. * Content: Implementation of the CVertexBuffer class.
  7. *
  8. *
  9. ***************************************************************************/
  10. #include "ddrawpr.h"
  11. #include "d3di.hpp"
  12. #include "ddi.h"
  13. #include "drawprim.hpp"
  14. #include "vbuffer.hpp"
  15. #include "resource.inl"
  16. #undef DPF_MODNAME
  17. #define DPF_MODNAME "CVertexBuffer::Create"
  18. // Static class function for creating a VertexBuffer object.
  19. // (Because it is static; it doesn't have a this pointer.)
  20. //
  21. // We do all parameter checking here to reduce the overhead
  22. // in the constructor which is called by the internal Clone
  23. // method which is used by resource management as part of the
  24. // performance critical download operation.
  25. // Creation function for Vertex Buffers
  26. HRESULT CVertexBuffer::Create(CBaseDevice *pDevice,
  27. DWORD cbLength,
  28. DWORD Usage,
  29. DWORD dwFVF,
  30. D3DPOOL Pool,
  31. REF_TYPE refType,
  32. IDirect3DVertexBuffer8 **ppVertexBuffer)
  33. {
  34. HRESULT hr;
  35. // Do parameter checking here
  36. if (!VALID_PTR_PTR(ppVertexBuffer))
  37. {
  38. DPF_ERR("Bad parameter passed for ppVertexBuffer for creating a vertex buffer");
  39. return D3DERR_INVALIDCALL;
  40. }
  41. // Zero-out return parameter
  42. *ppVertexBuffer = NULL;
  43. if (cbLength == 0)
  44. {
  45. DPF_ERR("Vertex buffer cannot be of zero size");
  46. return D3DERR_INVALIDCALL;
  47. }
  48. if (Pool != D3DPOOL_DEFAULT && Pool != D3DPOOL_MANAGED && Pool != D3DPOOL_SYSTEMMEM)
  49. {
  50. DPF_ERR("Vertex buffer pool should be default, managed or sysmem");
  51. return D3DERR_INVALIDCALL;
  52. }
  53. // Usage flag allowed for only mixed mode or software device
  54. if ((Usage & D3DUSAGE_SOFTWAREPROCESSING) != 0 &&
  55. (pDevice->BehaviorFlags() & D3DCREATE_MIXED_VERTEXPROCESSING) == 0 &&
  56. (pDevice->BehaviorFlags() & D3DCREATE_SOFTWARE_VERTEXPROCESSING) == 0)
  57. {
  58. DPF_ERR("D3DUSAGE_SOFTWAREPROCESSING can be set only when device is mixed or software mode. CreateVertexBuffer fails.");
  59. return D3DERR_INVALIDCALL;
  60. }
  61. // USAGE_DYNAMIC not allowed with management
  62. if ((Usage & D3DUSAGE_DYNAMIC) != 0 && Pool == D3DPOOL_MANAGED)
  63. {
  64. DPF_ERR("D3DUSAGE_DYNAMIC cannot be used with managed vertex buffers");
  65. return D3DERR_INVALIDCALL;
  66. }
  67. // Validate FVF
  68. if (dwFVF != 0 && cbLength < ComputeVertexSizeFVF(dwFVF))
  69. {
  70. DPF_ERR("Vertex buffer size needs to enough to hold one vertex");
  71. return D3DERR_INVALIDCALL;
  72. }
  73. D3DPOOL ActualPool = Pool;
  74. DWORD ActualUsage = Usage;
  75. // Infer Lock from absence of LoadOnce
  76. if (!(Usage & D3DUSAGE_LOADONCE))
  77. {
  78. ActualUsage |= D3DUSAGE_LOCK;
  79. }
  80. // On a mixed device, POOL_SYSTEMMEM means the same as D3DUSAGE_SOFTWAREPROCESSING
  81. if ((pDevice->BehaviorFlags() & D3DCREATE_MIXED_VERTEXPROCESSING) != 0 &&
  82. Pool == D3DPOOL_SYSTEMMEM)
  83. {
  84. ActualUsage |= D3DUSAGE_SOFTWAREPROCESSING;
  85. }
  86. /*
  87. * Put a VB in system memory if the following conditions are TRUE
  88. * 1. (USAGE_SOFTWAREPROCESSING is set indicating app. wants to use software pipeline or if it is a software device) except if the vertices are pre-clipped TLVERTEX
  89. * 2. USAGE_POINTS is set and we might do emulation of point sprites except if it is a managed VB on a mixed device
  90. * 3. The driver does not support vidmem VBs
  91. * 4. Usage NPathes and driver does not support NPatches
  92. */
  93. if (!pDevice->DriverSupportsVidmemVBs())
  94. {
  95. ActualPool = D3DPOOL_SYSTEMMEM; // We don't set D3DUSAGE_SOFTWAREPROCESSING to ensure proper validation in fe code
  96. }
  97. if (((pDevice->BehaviorFlags() & D3DCREATE_SOFTWARE_VERTEXPROCESSING) != 0 || (ActualUsage & D3DUSAGE_SOFTWAREPROCESSING) != 0) &&
  98. !((dwFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW && (ActualUsage & D3DUSAGE_DONOTCLIP) != 0))
  99. {
  100. if((ActualUsage & D3DUSAGE_INTERNALBUFFER) == 0)
  101. {
  102. if ((pDevice->BehaviorFlags() & D3DCREATE_SOFTWARE_VERTEXPROCESSING) != 0 ||
  103. ActualPool == D3DPOOL_DEFAULT)
  104. {
  105. ActualPool = D3DPOOL_SYSTEMMEM; // For software processing, pool can be only sysmem (POOLMANAGED is overwritten)
  106. }
  107. ActualUsage |= D3DUSAGE_SOFTWAREPROCESSING;
  108. }
  109. }
  110. if ((ActualUsage & D3DUSAGE_NPATCHES) != 0 &&
  111. (pDevice->GetD3DCaps()->DevCaps & D3DDEVCAPS_NPATCHES) == 0)
  112. {
  113. ActualPool = D3DPOOL_SYSTEMMEM;
  114. ActualUsage |= D3DUSAGE_SOFTWAREPROCESSING;
  115. }
  116. if ((ActualUsage & D3DUSAGE_POINTS) != 0 &&
  117. (static_cast<LPD3DBASE>(pDevice)->m_dwRuntimeFlags & D3DRT_DOPOINTSPRITEEMULATION) != 0)
  118. {
  119. if ((pDevice->BehaviorFlags() & D3DCREATE_SOFTWARE_VERTEXPROCESSING) != 0 ||
  120. ActualPool == D3DPOOL_DEFAULT)
  121. {
  122. ActualPool = D3DPOOL_SYSTEMMEM; // For software processing, pool can be only sysmem (POOLMANAGED is overwritten)
  123. }
  124. ActualUsage |= D3DUSAGE_SOFTWAREPROCESSING;
  125. }
  126. CVertexBuffer *pVertexBuffer;
  127. if (ActualPool == D3DPOOL_SYSTEMMEM ||
  128. IsTypeD3DManaged(pDevice, D3DRTYPE_VERTEXBUFFER, ActualPool))
  129. {
  130. hr = CreateSysmemVertexBuffer(pDevice,
  131. cbLength,
  132. dwFVF,
  133. Usage,
  134. ActualUsage,
  135. Pool,
  136. ActualPool,
  137. refType,
  138. &pVertexBuffer);
  139. }
  140. else
  141. {
  142. if (IsTypeDriverManaged(pDevice, D3DRTYPE_VERTEXBUFFER, ActualPool))
  143. {
  144. // If the vertex buffer is driver managed, but the usage is softwareprocessing, then
  145. // we turn off writeonly since the fe pipe WILL read from the sysmem backup (which
  146. // actually lives in the driver). It follows that when a driver manages a VB/IB without
  147. // writeonly, it MUST have a sysmem backup. (snene - 12/00)
  148. if ((ActualUsage & D3DUSAGE_SOFTWAREPROCESSING) != 0)
  149. {
  150. ActualUsage &= ~D3DUSAGE_WRITEONLY;
  151. }
  152. hr = CreateDriverManagedVertexBuffer(pDevice,
  153. cbLength,
  154. dwFVF,
  155. Usage,
  156. ActualUsage,
  157. Pool,
  158. ActualPool,
  159. refType,
  160. &pVertexBuffer);
  161. // Driver managed vertex buffer creates can NEVER fail, except for catastrophic reasons so
  162. // we don't fallback to sysmem. Even if we do fallback to sysmem here, there is no way
  163. // deferred creates are going to fallback, so no point.
  164. if (FAILED(hr))
  165. {
  166. return hr;
  167. }
  168. }
  169. else
  170. {
  171. hr = CreateDriverVertexBuffer(pDevice,
  172. cbLength,
  173. dwFVF,
  174. Usage,
  175. ActualUsage,
  176. Pool,
  177. ActualPool,
  178. refType,
  179. &pVertexBuffer);
  180. }
  181. if (FAILED(hr) && (hr != D3DERR_OUTOFVIDEOMEMORY || (ActualUsage & D3DUSAGE_INTERNALBUFFER) != 0))
  182. {
  183. if (hr == D3DERR_OUTOFVIDEOMEMORY)
  184. {
  185. DPF(2, "Out of video memory creating internal buffer");
  186. }
  187. if (pDevice->VBFailOversDisabled())
  188. {
  189. DPF_ERR("Cannot create Vidmem or Driver managed vertex buffer. Will ***NOT*** failover to Sysmem.");
  190. return hr;
  191. }
  192. ActualPool = D3DPOOL_SYSTEMMEM;
  193. hr = CreateSysmemVertexBuffer(pDevice,
  194. cbLength,
  195. dwFVF,
  196. Usage,
  197. ActualUsage,
  198. Pool,
  199. ActualPool,
  200. refType,
  201. &pVertexBuffer);
  202. }
  203. }
  204. if (FAILED(hr))
  205. {
  206. return hr;
  207. }
  208. // We're done; just return the object
  209. *ppVertexBuffer = pVertexBuffer;
  210. return hr;
  211. } // static Create
  212. #undef DPF_MODNAME
  213. #define DPF_MODNAME "CVertexBuffer::CreateDriverVertexBuffer"
  214. HRESULT CVertexBuffer::CreateDriverVertexBuffer(CBaseDevice *pDevice,
  215. DWORD cbLength,
  216. DWORD dwFVF,
  217. DWORD Usage,
  218. DWORD ActualUsage,
  219. D3DPOOL Pool,
  220. D3DPOOL ActualPool,
  221. REF_TYPE refType,
  222. CVertexBuffer **pVB)
  223. {
  224. HRESULT hr;
  225. CDriverVertexBuffer *pVertexBuffer;
  226. // Zero out return
  227. *pVB = 0;
  228. if((pDevice->BehaviorFlags() & D3DCREATE_MULTITHREADED) != 0)
  229. {
  230. pVertexBuffer = new CDriverVertexBufferMT(pDevice,
  231. cbLength,
  232. dwFVF,
  233. Usage,
  234. ActualUsage,
  235. Pool,
  236. ActualPool,
  237. refType,
  238. &hr);
  239. }
  240. else
  241. {
  242. pVertexBuffer = new CDriverVertexBuffer(pDevice,
  243. cbLength,
  244. dwFVF,
  245. Usage,
  246. ActualUsage,
  247. Pool,
  248. ActualPool,
  249. refType,
  250. &hr);
  251. }
  252. if (pVertexBuffer == 0)
  253. {
  254. DPF_ERR("Out of Memory creating vertex buffer");
  255. return E_OUTOFMEMORY;
  256. }
  257. if (FAILED(hr))
  258. {
  259. if (refType == REF_EXTERNAL)
  260. {
  261. // External objects get released
  262. pVertexBuffer->Release();
  263. }
  264. else
  265. {
  266. // Internal and intrinsic objects get decremented
  267. DXGASSERT(refType == REF_INTERNAL || refType == REF_INTRINSIC);
  268. pVertexBuffer->DecrementUseCount();
  269. }
  270. return hr;
  271. }
  272. *pVB = static_cast<CVertexBuffer*>(pVertexBuffer);
  273. return hr;
  274. }
  275. #undef DPF_MODNAME
  276. #define DPF_MODNAME "CVertexBuffer::CreateSysmemVertexBuffer"
  277. HRESULT CVertexBuffer::CreateSysmemVertexBuffer(CBaseDevice *pDevice,
  278. DWORD cbLength,
  279. DWORD dwFVF,
  280. DWORD Usage,
  281. DWORD ActualUsage,
  282. D3DPOOL Pool,
  283. D3DPOOL ActualPool,
  284. REF_TYPE refType,
  285. CVertexBuffer **pVB)
  286. {
  287. HRESULT hr;
  288. CVertexBuffer *pVertexBuffer;
  289. // Zero out return
  290. *pVB = 0;
  291. if((pDevice->BehaviorFlags() & D3DCREATE_MULTITHREADED) != 0)
  292. {
  293. pVertexBuffer = new CVertexBufferMT(pDevice,
  294. cbLength,
  295. dwFVF,
  296. Usage,
  297. ActualUsage,
  298. Pool,
  299. ActualPool,
  300. refType,
  301. &hr);
  302. }
  303. else
  304. {
  305. pVertexBuffer = new CVertexBuffer(pDevice,
  306. cbLength,
  307. dwFVF,
  308. Usage,
  309. ActualUsage,
  310. Pool,
  311. ActualPool,
  312. refType,
  313. &hr);
  314. }
  315. if (pVertexBuffer == 0)
  316. {
  317. DPF_ERR("Out of Memory creating vertex buffer");
  318. return E_OUTOFMEMORY;
  319. }
  320. if (FAILED(hr))
  321. {
  322. if (refType == REF_EXTERNAL)
  323. {
  324. // External objects get released
  325. pVertexBuffer->Release();
  326. }
  327. else
  328. {
  329. // Internal and intrinsic objects get decremented
  330. DXGASSERT(refType == REF_INTERNAL || refType == REF_INTRINSIC);
  331. pVertexBuffer->DecrementUseCount();
  332. }
  333. return hr;
  334. }
  335. *pVB = pVertexBuffer;
  336. return hr;
  337. }
  338. #undef DPF_MODNAME
  339. #define DPF_MODNAME "CVertexBuffer::CreateDriverManagedVertexBuffer"
  340. HRESULT CVertexBuffer::CreateDriverManagedVertexBuffer(CBaseDevice *pDevice,
  341. DWORD cbLength,
  342. DWORD dwFVF,
  343. DWORD Usage,
  344. DWORD ActualUsage,
  345. D3DPOOL Pool,
  346. D3DPOOL ActualPool,
  347. REF_TYPE refType,
  348. CVertexBuffer **pVB)
  349. {
  350. HRESULT hr;
  351. CDriverManagedVertexBuffer *pVertexBuffer;
  352. // Zero out return
  353. *pVB = 0;
  354. if((pDevice->BehaviorFlags() & D3DCREATE_MULTITHREADED) != 0)
  355. {
  356. pVertexBuffer = new CDriverManagedVertexBufferMT(pDevice,
  357. cbLength,
  358. dwFVF,
  359. Usage,
  360. ActualUsage,
  361. Pool,
  362. ActualPool,
  363. refType,
  364. &hr);
  365. }
  366. else
  367. {
  368. pVertexBuffer = new CDriverManagedVertexBuffer(pDevice,
  369. cbLength,
  370. dwFVF,
  371. Usage,
  372. ActualUsage,
  373. Pool,
  374. ActualPool,
  375. refType,
  376. &hr);
  377. }
  378. if (pVertexBuffer == 0)
  379. {
  380. DPF_ERR("Out of Memory creating vertex buffer");
  381. return E_OUTOFMEMORY;
  382. }
  383. if (FAILED(hr))
  384. {
  385. if (refType == REF_EXTERNAL)
  386. {
  387. // External objects get released
  388. pVertexBuffer->Release();
  389. }
  390. else
  391. {
  392. // Internal and intrinsic objects get decremented
  393. DXGASSERT(refType == REF_INTERNAL || refType == REF_INTRINSIC);
  394. pVertexBuffer->DecrementUseCount();
  395. }
  396. return hr;
  397. }
  398. *pVB = static_cast<CVertexBuffer*>(pVertexBuffer);
  399. return hr;
  400. }
  401. #undef DPF_MODNAME
  402. #define DPF_MODNAME "CVertexBuffer::CVertexBuffer"
  403. // Constructor the CVertexBuffer class
  404. CVertexBuffer::CVertexBuffer(CBaseDevice *pDevice,
  405. DWORD cbLength,
  406. DWORD dwFVF,
  407. DWORD Usage,
  408. DWORD ActualUsage,
  409. D3DPOOL Pool,
  410. D3DPOOL ActualPool,
  411. REF_TYPE refType,
  412. HRESULT *phr
  413. ) :
  414. CBuffer(pDevice,
  415. cbLength,
  416. dwFVF,
  417. D3DFMT_VERTEXDATA,
  418. D3DRTYPE_VERTEXBUFFER,
  419. Usage, // UserUsage
  420. ActualUsage,
  421. Pool, // UserPool
  422. ActualPool,
  423. refType,
  424. phr)
  425. {
  426. if (FAILED(*phr))
  427. return;
  428. // Initialize basic structures
  429. m_desc.Format = D3DFMT_VERTEXDATA;
  430. m_desc.Pool = ActualPool;
  431. m_desc.Usage = ActualUsage;
  432. m_desc.Type = D3DRTYPE_VERTEXBUFFER;
  433. m_desc.Size = cbLength;
  434. m_desc.FVF = dwFVF;
  435. m_usageUser = Usage;
  436. if (dwFVF != 0)
  437. {
  438. m_vertsize = ComputeVertexSizeFVF(dwFVF);
  439. DXGASSERT(m_vertsize != 0);
  440. m_numverts = cbLength / m_vertsize;
  441. }
  442. else
  443. {
  444. m_vertsize = 0;
  445. m_numverts = 0;
  446. }
  447. m_pClipCodes = 0;
  448. // If this is a D3D managed buffer then we need
  449. // to tell the Resource Manager to remember us. This has to happen
  450. // at the very end of the constructor so that the important data
  451. // members are built up correctly
  452. if (CResource::IsTypeD3DManaged(Device(), D3DRTYPE_VERTEXBUFFER, ActualPool))
  453. {
  454. *phr = InitializeRMHandle();
  455. }
  456. } // CVertexBuffer::CVertexBuffer
  457. #undef DPF_MODNAME
  458. #define DPF_MODNAME "CVertexBuffer::Clone"
  459. HRESULT CVertexBuffer::Clone(D3DPOOL Pool,
  460. CResource **ppResource) const
  461. {
  462. HRESULT hr;
  463. CVertexBuffer *pVertexBuffer;
  464. // Note: we treat clones the same as internal; because
  465. // they are owned by the resource manager which
  466. // is owned by the device.
  467. hr = CreateDriverVertexBuffer(Device(),
  468. m_desc.Size,
  469. m_desc.FVF,
  470. m_desc.Usage,
  471. (m_desc.Usage | D3DUSAGE_WRITEONLY) & ~D3DUSAGE_SOFTWAREPROCESSING, // never seen by API!
  472. Pool,
  473. Pool, // never seen by API!
  474. REF_INTERNAL,
  475. &pVertexBuffer);
  476. *ppResource = static_cast<CResource*>(pVertexBuffer);
  477. return hr;
  478. } // CVertexBuffer::Clone
  479. #undef DPF_MODNAME
  480. #define DPF_MODNAME "CVertexBuffer::GetBufferDesc"
  481. const D3DBUFFER_DESC* CVertexBuffer::GetBufferDesc() const
  482. {
  483. return (const D3DBUFFER_DESC*)&m_desc;
  484. } // CVertexBuffer::GetBufferDesc
  485. // IUnknown methods
  486. #undef DPF_MODNAME
  487. #define DPF_MODNAME "CVertexBuffer::QueryInterface"
  488. STDMETHODIMP CVertexBuffer::QueryInterface(REFIID riid,
  489. LPVOID FAR * ppvObj)
  490. {
  491. API_ENTER(Device());
  492. if (!VALID_PTR_PTR(ppvObj))
  493. {
  494. DPF_ERR("Invalid ppvObj parameter passed to CVertexBuffer::QueryInterface");
  495. return D3DERR_INVALIDCALL;
  496. }
  497. if (!VALID_PTR(&riid, sizeof(GUID)))
  498. {
  499. DPF_ERR("Invalid guid memory address to QueryInterface for VertexBuffer");
  500. return D3DERR_INVALIDCALL;
  501. }
  502. if (riid == IID_IDirect3DVertexBuffer8 ||
  503. riid == IID_IDirect3DResource8 ||
  504. riid == IID_IUnknown)
  505. {
  506. *ppvObj = static_cast<void*>(static_cast<IDirect3DVertexBuffer8 *>(this));
  507. AddRef();
  508. return S_OK;
  509. }
  510. DPF_ERR("Unsupported Interface identifier passed to QueryInterface for VertexBuffer");
  511. // Null out param
  512. *ppvObj = NULL;
  513. return E_NOINTERFACE;
  514. } // QueryInterface
  515. #undef DPF_MODNAME
  516. #define DPF_MODNAME "CVertexBuffer::AddRef"
  517. STDMETHODIMP_(ULONG) CVertexBuffer::AddRef()
  518. {
  519. API_ENTER_NO_LOCK(Device());
  520. return AddRefImpl();
  521. } // AddRef
  522. #undef DPF_MODNAME
  523. #define DPF_MODNAME "CVertexBuffer::Release"
  524. STDMETHODIMP_(ULONG) CVertexBuffer::Release()
  525. {
  526. API_ENTER_SUBOBJECT_RELEASE(Device());
  527. return ReleaseImpl();
  528. } // Release
  529. // IDirect3DResource methods
  530. #undef DPF_MODNAME
  531. #define DPF_MODNAME "CVertexBuffer::GetDevice"
  532. STDMETHODIMP CVertexBuffer::GetDevice(IDirect3DDevice8 ** ppObj)
  533. {
  534. API_ENTER(Device());
  535. return GetDeviceImpl(ppObj);
  536. } // GetDevice
  537. #undef DPF_MODNAME
  538. #define DPF_MODNAME "CVertexBuffer::SetPrivateData"
  539. STDMETHODIMP CVertexBuffer::SetPrivateData(REFGUID riid,
  540. CONST VOID* pvData,
  541. DWORD cbData,
  542. DWORD dwFlags)
  543. {
  544. API_ENTER(Device());
  545. // We use level zero for our data
  546. return SetPrivateDataImpl(riid, pvData, cbData, dwFlags, 0);
  547. } // SetPrivateData
  548. #undef DPF_MODNAME
  549. #define DPF_MODNAME "CVertexBuffer::GetPrivateData"
  550. STDMETHODIMP CVertexBuffer::GetPrivateData(REFGUID riid,
  551. LPVOID pvData,
  552. LPDWORD pcbData)
  553. {
  554. API_ENTER(Device());
  555. // We use level zero for our data
  556. return GetPrivateDataImpl(riid, pvData, pcbData, 0);
  557. } // GetPrivateData
  558. #undef DPF_MODNAME
  559. #define DPF_MODNAME "CVertexBuffer::FreePrivateData"
  560. STDMETHODIMP CVertexBuffer::FreePrivateData(REFGUID riid)
  561. {
  562. API_ENTER(Device());
  563. // We use level zero for our data
  564. return FreePrivateDataImpl(riid, 0);
  565. } // FreePrivateData
  566. #undef DPF_MODNAME
  567. #define DPF_MODNAME "CVertexBuffer::GetPriority"
  568. STDMETHODIMP_(DWORD) CVertexBuffer::GetPriority()
  569. {
  570. API_ENTER_RET(Device(), DWORD);
  571. return GetPriorityImpl();
  572. } // GetPriority
  573. #undef DPF_MODNAME
  574. #define DPF_MODNAME "CVertexBuffer::SetPriority"
  575. STDMETHODIMP_(DWORD) CVertexBuffer::SetPriority(DWORD dwPriority)
  576. {
  577. API_ENTER_RET(Device(), DWORD);
  578. return SetPriorityImpl(dwPriority);
  579. } // SetPriority
  580. #undef DPF_MODNAME
  581. #define DPF_MODNAME "CVertexBuffer::PreLoad"
  582. STDMETHODIMP_(void) CVertexBuffer::PreLoad(void)
  583. {
  584. API_ENTER_VOID(Device());
  585. PreLoadImpl();
  586. return;
  587. } // PreLoad
  588. #undef DPF_MODNAME
  589. #define DPF_MODNAME "CVertexBuffer::GetType"
  590. STDMETHODIMP_(D3DRESOURCETYPE) CVertexBuffer::GetType(void)
  591. {
  592. API_ENTER_RET(Device(), D3DRESOURCETYPE);
  593. return m_desc.Type;
  594. } // GetType
  595. // Vertex Buffer Methods
  596. #undef DPF_MODNAME
  597. #define DPF_MODNAME "CVertexBuffer::GetDesc"
  598. STDMETHODIMP CVertexBuffer::GetDesc(D3DVERTEXBUFFER_DESC *pDesc)
  599. {
  600. API_ENTER(Device());
  601. if (!VALID_WRITEPTR(pDesc, sizeof(D3DVERTEXBUFFER_DESC)))
  602. {
  603. DPF_ERR("bad pointer for pDesc passed to GetDesc for VertexBuffer");
  604. return D3DERR_INVALIDCALL;
  605. }
  606. *pDesc = m_desc;
  607. // Need to return pool/usage that the user specified
  608. pDesc->Pool = GetUserPool();
  609. pDesc->Usage = m_usageUser;
  610. return S_OK;
  611. } // GetDesc
  612. #if DBG
  613. #undef DPF_MODNAME
  614. #define DPF_MODNAME "CVertexBuffer::ValidateLockParams"
  615. HRESULT CVertexBuffer::ValidateLockParams(UINT cbOffsetToLock,
  616. UINT SizeToLock,
  617. BYTE **ppbData,
  618. DWORD dwFlags) const
  619. {
  620. if (!VALID_PTR_PTR(ppbData))
  621. {
  622. DPF_ERR("Bad parameter passed for ppbData for locking a vertexbuffer");
  623. return D3DERR_INVALIDCALL;
  624. }
  625. if ((cbOffsetToLock != 0) && (SizeToLock == 0))
  626. {
  627. DPF_ERR("Cannot lock zero bytes. Vertex Buffer Lock fails.");
  628. return D3DERR_INVALIDCALL;
  629. }
  630. if (dwFlags & ~(D3DLOCK_VALID & ~D3DLOCK_NO_DIRTY_UPDATE)) // D3DLOCK_NO_DIRTY_UPDATE not valid for VBs
  631. {
  632. DPF_ERR("Invalid flags specified. Vertex Buffer Lock fails.");
  633. return D3DERR_INVALIDCALL;
  634. }
  635. // Can it be locked?
  636. if (!m_isLockable)
  637. {
  638. DPF_ERR("Vertex buffer with D3DUSAGE_LOADONCE can only be locked once");
  639. return D3DERR_INVALIDCALL;
  640. }
  641. if ((dwFlags & (D3DLOCK_DISCARD | D3DLOCK_NOOVERWRITE)) != 0 && (m_usageUser & D3DUSAGE_DYNAMIC) == 0)
  642. {
  643. DPF_ERR("Can specify D3DLOCK_DISCARD or D3DLOCK_NOOVERWRITE for only Vertex Buffers created with D3DUSAGE_DYNAMIC");
  644. return D3DERR_INVALIDCALL;
  645. }
  646. if ((dwFlags & (D3DLOCK_READONLY | D3DLOCK_DISCARD)) == (D3DLOCK_READONLY | D3DLOCK_DISCARD))
  647. {
  648. DPF_ERR("Should not specify D3DLOCK_DISCARD along with D3DLOCK_READONLY. Vertex Buffer Lock fails.");
  649. return D3DERR_INVALIDCALL;
  650. }
  651. if ((dwFlags & D3DLOCK_READONLY) != 0 && (m_usageUser & D3DUSAGE_WRITEONLY) != 0)
  652. {
  653. DPF_ERR("Cannot do READ_ONLY lock on a WRITE_ONLY buffer. Vertex Buffer Lock fails.");
  654. return D3DERR_INVALIDCALL;
  655. }
  656. if (ULONGLONG(cbOffsetToLock) + ULONGLONG(SizeToLock) > ULONGLONG(m_desc.Size))
  657. {
  658. DPF_ERR("Lock failed: Locked area exceeds size of buffer. Vertex Buffer Lock fails.");
  659. return D3DERR_INVALIDCALL;
  660. }
  661. if (m_LockCount == 0)
  662. {
  663. if ((m_usageUser & D3DUSAGE_DYNAMIC) == 0)
  664. {
  665. if (static_cast<CD3DBase*>(Device())->m_SceneStamp == m_SceneStamp &&
  666. (m_usageUser & D3DUSAGE_WRITEONLY) != 0 &&
  667. GetUserPool() != D3DPOOL_SYSTEMMEM)
  668. {
  669. DPF(1, "Static vertex buffer locked more than once per frame. Could have severe performance penalty.");
  670. }
  671. ((CVertexBuffer*)this)->m_SceneStamp = static_cast<CD3DBase*>(Device())->m_SceneStamp;
  672. }
  673. else
  674. {
  675. if ((dwFlags & (D3DLOCK_DISCARD | D3DLOCK_NOOVERWRITE)) == 0)
  676. {
  677. if (m_TimesLocked > 0 &&
  678. (m_usageUser & D3DUSAGE_WRITEONLY) != 0 &&
  679. GetUserPool() != D3DPOOL_SYSTEMMEM)
  680. {
  681. DPF(3, "Dynamic vertex buffer locked twice or more in a row without D3DLOCK_NOOVERWRITE or D3DLOCK_DISCARD. Could have severe performance penalty.");
  682. }
  683. ++(((CVertexBuffer*)this)->m_TimesLocked);
  684. }
  685. else
  686. {
  687. ((CVertexBuffer*)this)->m_TimesLocked = 0;
  688. }
  689. }
  690. }
  691. DXGASSERT(m_LockCount < 0x80000000);
  692. return S_OK;
  693. } // ValidateLockParams
  694. #endif //DBG
  695. #undef DPF_MODNAME
  696. #define DPF_MODNAME "CVertexBuffer::Lock"
  697. STDMETHODIMP CVertexBuffer::Lock(UINT cbOffsetToLock,
  698. UINT SizeToLock,
  699. BYTE **ppbData,
  700. DWORD dwFlags)
  701. {
  702. // We do not take the API lock here since the MT class will take it for
  703. // a multithreaded device. For a non-multithreaded device, there is no
  704. // MT class nor do we bother to take the API lock. We still need to
  705. // call API_ENTER_NO_LOCK_HR however for validation of the THIS pointer in
  706. // Debug builds
  707. API_ENTER_NO_LOCK_HR(Device());
  708. #if DBG
  709. HRESULT hr = ValidateLockParams(cbOffsetToLock, SizeToLock, ppbData, dwFlags);
  710. if (FAILED(hr))
  711. {
  712. return hr;
  713. }
  714. #endif // DBG
  715. // Sanity check
  716. #if DBG
  717. if (m_LockCount != 0)
  718. {
  719. DXGASSERT(GetPrivateDataPointer() != 0);
  720. }
  721. #endif // DBG
  722. // Increment our lock count
  723. ++m_LockCount;
  724. if ((dwFlags & (D3DLOCK_READONLY | D3DLOCK_NOOVERWRITE)) == 0 && m_LockCount == 1) // for repeat locks, no syncing
  725. {
  726. Sync(); // Sync with device command queue
  727. }
  728. LockImpl(cbOffsetToLock,
  729. SizeToLock,
  730. ppbData,
  731. dwFlags,
  732. m_desc.Size);
  733. return S_OK;
  734. } // Lock
  735. #undef DPF_MODNAME
  736. #define DPF_MODNAME "CVertexBuffer::Unlock"
  737. STDMETHODIMP CVertexBuffer::Unlock()
  738. {
  739. // We do not take the API lock here since the MT class will take it for
  740. // a multithreaded device. For a non-multithreaded device, there is no
  741. // MT class nor do we bother to take the API lock. We still need to
  742. // call API_ENTER_NO_LOCK however for validation of the THIS pointer in
  743. // Debug builds
  744. API_ENTER_NO_LOCK_HR(Device());
  745. #if DBG
  746. // If we aren't locked; then something is wrong
  747. if (m_LockCount == 0)
  748. {
  749. DPF_ERR("Unlock failed on a buffer; vertex buffer wasn't locked.");
  750. return D3DERR_INVALIDCALL;
  751. }
  752. #endif // DBG
  753. // Decrement our lock count
  754. --m_LockCount;
  755. #if DBG
  756. if ((m_usageUser & D3DUSAGE_LOADONCE) != 0 && m_LockCount == 0)
  757. {
  758. m_isLockable = FALSE;
  759. }
  760. #endif // DBG
  761. return S_OK;
  762. } // Unlock
  763. #undef DPF_MODNAME
  764. #define DPF_MODNAME "CVertexBuffer::AllocateClipCodes"
  765. void CVertexBuffer::AllocateClipCodes()
  766. {
  767. if (m_pClipCodes == 0)
  768. {
  769. DXGASSERT(m_numverts != 0);
  770. m_pClipCodes = new WORD[m_numverts];
  771. }
  772. }
  773. #undef DPF_MODNAME
  774. #define DPF_MODNAME "CVertexBuffer::UpdateDirtyPortion"
  775. HRESULT CVertexBuffer::UpdateDirtyPortion(CResource *pResourceTarget)
  776. {
  777. if (IsDirty())
  778. {
  779. if (Device()->CanBufBlt())
  780. {
  781. D3DRANGE range;
  782. if(m_cbDirtyMin == 0 && m_cbDirtyMax == 0)
  783. {
  784. range.Offset = 0;
  785. range.Size = m_desc.Size;
  786. }
  787. else
  788. {
  789. range.Offset = m_cbDirtyMin;
  790. range.Size = m_cbDirtyMax - m_cbDirtyMin;
  791. }
  792. HRESULT hr = static_cast<LPD3DBASE>(Device())->BufBlt(static_cast<CBuffer*>(pResourceTarget), this, m_cbDirtyMin, &range);
  793. if (FAILED(hr))
  794. {
  795. DPF_ERR("Failed to copy vertex buffer");
  796. return hr;
  797. }
  798. }
  799. else
  800. {
  801. DXGASSERT(pResourceTarget->GetBufferDesc()->Pool == D3DPOOL_DEFAULT); // make sure that it is safe to assume that this is a driver VB
  802. CDriverVertexBuffer *pBufferTarget = static_cast<CDriverVertexBuffer *>(pResourceTarget);
  803. DXGASSERT((pBufferTarget->m_desc.Usage & D3DUSAGE_DYNAMIC) == 0); // Target can never be dynamic
  804. DXGASSERT(pBufferTarget->m_pbData == 0); // Target can never be locked
  805. HRESULT hr = pBufferTarget->LockI(D3DLOCK_NOSYSLOCK);
  806. if (FAILED(hr))
  807. {
  808. DPF_ERR("Failed to lock driver vertex buffer");
  809. return hr;
  810. }
  811. DXGASSERT(pBufferTarget->m_pbData != 0);
  812. if(m_cbDirtyMin == 0 && m_cbDirtyMax == 0)
  813. {
  814. memcpy(pBufferTarget->m_pbData, GetPrivateDataPointer(), m_desc.Size);
  815. }
  816. else
  817. {
  818. memcpy(pBufferTarget->m_pbData + m_cbDirtyMin, GetPrivateDataPointer() + m_cbDirtyMin, m_cbDirtyMax - m_cbDirtyMin);
  819. }
  820. hr = pBufferTarget->UnlockI();
  821. if (FAILED(hr))
  822. {
  823. DPF_ERR("Failed to unlock driver vertex buffer");
  824. return hr;
  825. }
  826. DXGASSERT(pBufferTarget->m_pbData == 0); // Target must be unlocked
  827. }
  828. // Mark ourselves as all clean now.
  829. OnResourceClean();
  830. }
  831. return S_OK;
  832. } // CVertexBuffer::UpdateDirtyPortion
  833. //=============================================
  834. // Methods for the CDriverVertexBuffer class
  835. //=============================================
  836. #undef DPF_MODNAME
  837. #define DPF_MODNAME "CDriverVertexBuffer::CDriverVertexBuffer"
  838. CDriverVertexBuffer::CDriverVertexBuffer(CBaseDevice *pDevice,
  839. DWORD cbLength,
  840. DWORD dwFVF,
  841. DWORD Usage,
  842. DWORD ActualUsage,
  843. D3DPOOL Pool,
  844. D3DPOOL ActualPool,
  845. REF_TYPE refType,
  846. HRESULT *phr
  847. ) :
  848. CVertexBuffer(pDevice,
  849. cbLength,
  850. dwFVF,
  851. Usage,
  852. ActualUsage,
  853. Pool,
  854. ActualPool,
  855. refType,
  856. phr),
  857. m_pbData(0)
  858. {
  859. if (FAILED(*phr))
  860. {
  861. // We want to allow drivers to fail creation of driver vbs. In this
  862. // case we will fail-over to system memory. However, if we
  863. // DPF an error here, it will be misunderstood. So don't DPF.
  864. return;
  865. }
  866. } // CDriverVertexBuffer::CDriverVertexBuffer
  867. #undef DPF_MODNAME
  868. #define DPF_MODNAME "CDriverVertexBuffer::~CDriverVertexBuffer"
  869. CDriverVertexBuffer::~CDriverVertexBuffer()
  870. {
  871. if (m_pbData != 0)
  872. {
  873. HRESULT hr = UnlockI();
  874. if (FAILED(hr))
  875. {
  876. DPF_ERR("Failed to unlock driver vertex buffer");
  877. }
  878. }
  879. } // CDriverVertexBuffer::~CDriverVertexBuffer
  880. #undef DPF_MODNAME
  881. #define DPF_MODNAME "CDriverVertexBuffer::LockI"
  882. HRESULT CDriverVertexBuffer::LockI(DWORD dwFlags)
  883. {
  884. // We sync first to make sure that the
  885. // driver has already processed any data that
  886. // it needs. LockI only gets called if for
  887. // cases where we need the interlock i.e.
  888. // not readonly and not nooverwrite.
  889. Sync();
  890. // Prepare a LockData structure for the HAL call
  891. D3D8_LOCKDATA lockData;
  892. ZeroMemory(&lockData, sizeof lockData);
  893. lockData.hDD = Device()->GetHandle();
  894. lockData.hSurface = BaseKernelHandle();
  895. lockData.bHasRange = FALSE;
  896. lockData.dwFlags = dwFlags;
  897. HRESULT hr = Device()->GetHalCallbacks()->Lock(&lockData);
  898. if (FAILED(hr))
  899. {
  900. DPF_ERR("Failed to lock driver vertex buffer");
  901. }
  902. // Return value
  903. m_pbData = (BYTE*)lockData.lpSurfData;
  904. return hr;
  905. } // LockI
  906. #undef DPF_MODNAME
  907. #define DPF_MODNAME "CDriverVertexBuffer::UnlockI"
  908. HRESULT CDriverVertexBuffer::UnlockI()
  909. {
  910. // It is sometimes possible for the pre-DX8 DDI FlushStates to call
  911. // Unlock twice. We safely filter this case.
  912. if (m_pbData == 0)
  913. {
  914. DXGASSERT(!IS_DX8HAL_DEVICE(Device()));
  915. return D3D_OK;
  916. }
  917. // Call the driver to perform the unlock
  918. D3D8_UNLOCKDATA unlockData = {
  919. Device()->GetHandle(),
  920. BaseKernelHandle()
  921. };
  922. HRESULT hr = Device()->GetHalCallbacks()->Unlock(&unlockData);
  923. if (FAILED(hr))
  924. {
  925. DPF_ERR("Driver vertex buffer failed to unlock");
  926. return hr;
  927. }
  928. m_pbData = 0;
  929. return hr;
  930. } // UnlockI
  931. #undef DPF_MODNAME
  932. #define DPF_MODNAME "CDriverVertexBuffer::Lock"
  933. STDMETHODIMP CDriverVertexBuffer::Lock(UINT cbOffsetToLock,
  934. UINT SizeToLock,
  935. BYTE **ppbData,
  936. DWORD dwFlags)
  937. {
  938. // We do not take the API lock here since the MT class will take it for
  939. // a multithreaded device. For a non-multithreaded device, there is no
  940. // MT class nor do we bother to take the API lock. We still need to
  941. // call API_ENTER_NO_LOCK however for validation of the THIS pointer in
  942. // Debug builds
  943. API_ENTER_NO_LOCK_HR(Device());
  944. HRESULT hr;
  945. #if DBG
  946. hr = ValidateLockParams(cbOffsetToLock, SizeToLock, ppbData, dwFlags);
  947. if (FAILED(hr))
  948. {
  949. return hr;
  950. }
  951. #endif // DBG
  952. // Sanity check
  953. #if DBG
  954. if (m_LockCount != 0)
  955. {
  956. DXGASSERT(m_pbData != 0);
  957. }
  958. #endif // DBG
  959. // Increment our lock count
  960. // This MUST be done first. DO NOT MOVE THIS LINE.
  961. ++m_LockCount;
  962. if(((dwFlags & (D3DLOCK_READONLY | D3DLOCK_NOOVERWRITE)) == 0 || m_pbData == 0) && m_LockCount == 1) // Repeat locks need no work
  963. {
  964. hr = static_cast<LPD3DBASE>(Device())->m_pDDI->LockVB(this, dwFlags);
  965. if (FAILED(hr))
  966. {
  967. DPF_ERR("Failed to lock driver vertex buffer");
  968. *ppbData = 0;
  969. --m_LockCount;
  970. return hr;
  971. }
  972. }
  973. *ppbData = m_pbData + cbOffsetToLock;
  974. // Done
  975. return S_OK;
  976. } // Lock
  977. #undef DPF_MODNAME
  978. #define DPF_MODNAME "CDriverVertexBuffer::Unlock"
  979. STDMETHODIMP CDriverVertexBuffer::Unlock()
  980. {
  981. // We do not take the API lock here since the MT class will take it for
  982. // a multithreaded device. For a non-multithreaded device, there is no
  983. // MT class nor do we bother to take the API lock. We still need to
  984. // call API_ENTER_NO_LOCK however for validation of the THIS pointer in
  985. // Debug builds
  986. API_ENTER_NO_LOCK_HR(Device());
  987. #if DBG
  988. // If we aren't locked; then something is wrong
  989. if (m_LockCount == 0)
  990. {
  991. DPF_ERR("Unlock failed on a vertex buffer; buffer wasn't locked.");
  992. return D3DERR_INVALIDCALL;
  993. }
  994. #endif // DBG
  995. if ((m_desc.Usage & D3DUSAGE_DYNAMIC) == 0 && m_LockCount == 1) // do work only for the last unlock
  996. {
  997. HRESULT hr = static_cast<LPD3DBASE>(Device())->m_pDDI->UnlockVB(this);
  998. if (FAILED(hr))
  999. {
  1000. DPF_ERR("Driver failed to unlock vertex buffer");
  1001. return hr;
  1002. }
  1003. }
  1004. // Decrement our lock count
  1005. --m_LockCount;
  1006. #if DBG
  1007. if ((m_usageUser & D3DUSAGE_LOADONCE) != 0 && m_LockCount == 0)
  1008. {
  1009. m_isLockable = FALSE;
  1010. }
  1011. #endif // DBG
  1012. // Done
  1013. return S_OK;
  1014. } // Unlock
  1015. //=================================================
  1016. // Methods for the CDriverManagedVertexBuffer class
  1017. //=================================================
  1018. #undef DPF_MODNAME
  1019. #define DPF_MODNAME "CDriverManagedVertexBuffer::CDriverManagedVertexBuffer"
  1020. CDriverManagedVertexBuffer::CDriverManagedVertexBuffer(CBaseDevice *pDevice,
  1021. DWORD cbLength,
  1022. DWORD dwFVF,
  1023. DWORD Usage,
  1024. DWORD ActualUsage,
  1025. D3DPOOL Pool,
  1026. D3DPOOL ActualPool,
  1027. REF_TYPE refType,
  1028. HRESULT *phr
  1029. ) :
  1030. CVertexBuffer(pDevice,
  1031. cbLength,
  1032. dwFVF,
  1033. Usage,
  1034. ActualUsage,
  1035. Pool,
  1036. ActualPool,
  1037. refType,
  1038. phr),
  1039. m_pbData(0),
  1040. m_bDriverCalled(FALSE)
  1041. {
  1042. if (FAILED(*phr))
  1043. return;
  1044. // If writeonly is not set, we assume that the vertex/index buffer is going
  1045. // to be read from from time to time. Hence, for optimizing the readonly
  1046. // locks, we lock and cache the pointer. (snene - 12/00)
  1047. if ((ActualUsage & D3DUSAGE_WRITEONLY) == 0)
  1048. {
  1049. *phr = UpdateCachedPointer(pDevice);
  1050. if (FAILED(*phr))
  1051. return;
  1052. }
  1053. } // CDriverManagedVertexBuffer::CDriverManagedVertexBuffer
  1054. #undef DPF_MODNAME
  1055. #define DPF_MODNAME "CDriverManagedVertexBuffer::UpdateCachedPointer"
  1056. HRESULT CDriverManagedVertexBuffer::UpdateCachedPointer(CBaseDevice *pDevice)
  1057. {
  1058. HRESULT hr;
  1059. // Prepare a LockData structure for the HAL call
  1060. D3D8_LOCKDATA lockData;
  1061. ZeroMemory(&lockData, sizeof lockData);
  1062. lockData.hDD = pDevice->GetHandle();
  1063. lockData.hSurface = BaseKernelHandle();
  1064. lockData.bHasRange = FALSE;
  1065. lockData.range.Offset = 0;
  1066. lockData.range.Size = 0;
  1067. lockData.dwFlags = D3DLOCK_READONLY;
  1068. hr = pDevice->GetHalCallbacks()->Lock(&lockData);
  1069. if (FAILED(hr))
  1070. return hr;
  1071. // Call the driver to perform the unlock
  1072. D3D8_UNLOCKDATA unlockData = {
  1073. pDevice->GetHandle(),
  1074. BaseKernelHandle()
  1075. };
  1076. hr = pDevice->GetHalCallbacks()->Unlock(&unlockData);
  1077. if (FAILED(hr))
  1078. return hr;
  1079. m_pbData = (BYTE*)lockData.lpSurfData;
  1080. return S_OK;
  1081. } // CDriverManagedVertexBuffer::UpdateCachedPointer
  1082. #undef DPF_MODNAME
  1083. #define DPF_MODNAME "CDriverManagedVertexBuffer::Lock"
  1084. STDMETHODIMP CDriverManagedVertexBuffer::Lock(UINT cbOffsetToLock,
  1085. UINT SizeToLock,
  1086. BYTE **ppbData,
  1087. DWORD dwFlags)
  1088. {
  1089. // We do not take the API lock here since the MT class will take it for
  1090. // a multithreaded device. For a non-multithreaded device, there is no
  1091. // MT class nor do we bother to take the API lock. We still need to
  1092. // call API_ENTER_NO_LOCK however for validation of the THIS pointer in
  1093. // Debug builds
  1094. API_ENTER_NO_LOCK_HR(Device());
  1095. HRESULT hr = S_OK;
  1096. #if DBG
  1097. hr = ValidateLockParams(cbOffsetToLock, SizeToLock, ppbData, dwFlags);
  1098. if (FAILED(hr))
  1099. {
  1100. return hr;
  1101. }
  1102. #endif // DBG
  1103. // Increment our lock count
  1104. ++m_LockCount;
  1105. if((dwFlags & D3DLOCK_READONLY) == 0)
  1106. {
  1107. // Sync with device command queue
  1108. Sync();
  1109. // Prepare a LockData structure for the HAL call
  1110. D3D8_LOCKDATA lockData;
  1111. ZeroMemory(&lockData, sizeof lockData);
  1112. lockData.hDD = Device()->GetHandle();
  1113. lockData.hSurface = BaseKernelHandle();
  1114. lockData.bHasRange = (SizeToLock != 0);
  1115. lockData.range.Offset = cbOffsetToLock;
  1116. lockData.range.Size = SizeToLock;
  1117. lockData.dwFlags = dwFlags;
  1118. hr = Device()->GetHalCallbacks()->Lock(&lockData);
  1119. if (FAILED(hr))
  1120. {
  1121. *ppbData = 0;
  1122. DPF_ERR("Failed to lock driver managed vertex buffer");
  1123. return hr;
  1124. }
  1125. else
  1126. {
  1127. // Update cached pointer
  1128. m_pbData = (BYTE*)lockData.lpSurfData - cbOffsetToLock;
  1129. m_bDriverCalled = TRUE;
  1130. }
  1131. }
  1132. *ppbData = m_pbData + cbOffsetToLock;
  1133. return hr;
  1134. } // Lock
  1135. #undef DPF_MODNAME
  1136. #define DPF_MODNAME "CDriverManagedVertexBuffer::Unlock"
  1137. STDMETHODIMP CDriverManagedVertexBuffer::Unlock()
  1138. {
  1139. // We do not take the API lock here since the MT class will take it for
  1140. // a multithreaded device. For a non-multithreaded device, there is no
  1141. // MT class nor do we bother to take the API lock. We still need to
  1142. // call API_ENTER_NO_LOCK however for validation of the THIS pointer in
  1143. // Debug builds
  1144. API_ENTER_NO_LOCK_HR(Device());
  1145. #if DBG
  1146. // If we aren't locked; then something is wrong
  1147. if (m_LockCount == 0)
  1148. {
  1149. DPF_ERR("Unlock failed on a vertex buffer; buffer wasn't locked.");
  1150. return D3DERR_INVALIDCALL;
  1151. }
  1152. #endif // DBG
  1153. if (m_bDriverCalled)
  1154. {
  1155. // Call the driver to perform the unlock
  1156. D3D8_UNLOCKDATA unlockData = {
  1157. Device()->GetHandle(),
  1158. BaseKernelHandle()
  1159. };
  1160. HRESULT hr = Device()->GetHalCallbacks()->Unlock(&unlockData);
  1161. if (FAILED(hr))
  1162. {
  1163. DPF_ERR("Driver vertex buffer failed to unlock");
  1164. return hr;
  1165. }
  1166. m_bDriverCalled = FALSE;
  1167. }
  1168. // Decrement our lock count
  1169. --m_LockCount;
  1170. #if DBG
  1171. if ((m_usageUser & D3DUSAGE_LOADONCE) != 0 && m_LockCount == 0)
  1172. {
  1173. m_isLockable = FALSE;
  1174. }
  1175. #endif // DBG
  1176. return S_OK;
  1177. } // Unlock
  1178. // End of file : vbuffer.cpp