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.

1333 lines
43 KiB

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