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.

442 lines
13 KiB

  1. /*==========================================================================;
  2. *
  3. * Copyright (C) 1999-2000 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: d3dobj.cpp
  6. * Content: Base class implementation for resources and buffers
  7. *
  8. *
  9. ***************************************************************************/
  10. #include "ddrawpr.h"
  11. #include "d3dobj.hpp"
  12. // Declare static data for CLockD3D
  13. #ifdef DEBUG
  14. DWORD CLockD3D::m_Count = 0;
  15. #endif // DEBUG
  16. #undef DPF_MODNAME
  17. #define DPF_MODNAME "CBaseObject::AddRefImpl"
  18. // Internal Implementations of AddRef and Release
  19. DWORD CBaseObject::AddRefImpl()
  20. {
  21. // Internal objects should never be add-ref'ed
  22. // or released
  23. DXGASSERT(m_refType != REF_INTERNAL);
  24. // Only Intrinsic objects should have a ref
  25. // count of zero. (Internal objects also have
  26. // a ref count of zero; but AddRef shouldn't
  27. // be called for those.)
  28. DXGASSERT(m_cRef > 0 || m_refType == REF_INTRINSIC);
  29. // The first extra ref for an intrinsic
  30. // object causes an add-ref to the device
  31. if (m_cRef == 0)
  32. {
  33. DXGASSERT(m_refType == REF_INTRINSIC);
  34. UINT crefDevice = m_pDevice->AddRef();
  35. DXGASSERT(crefDevice > 1);
  36. }
  37. // InterlockedIncrement requires the memory
  38. // to be aligned on DWORD boundary
  39. DXGASSERT(((ULONG_PTR)(&m_cRef) & 3) == 0);
  40. InterlockedIncrement((LONG *)&m_cRef);
  41. return m_cRef;
  42. } // AddRefImpl
  43. #undef DPF_MODNAME
  44. #define DPF_MODNAME "CBaseObject::AddRefImpl"
  45. DWORD CBaseObject::ReleaseImpl()
  46. {
  47. // Internal objects should never be add-ref'ed
  48. // or released
  49. DXGASSERT(m_refType != REF_INTERNAL);
  50. // Assert that we are not being
  51. // over-released.
  52. DXGASSERT(m_cRef > 0);
  53. if (m_cRef == 0)
  54. {
  55. // This heinous state can happen if a texture
  56. // was being held by the device; but not
  57. // only has the app held onto a pointer to
  58. // the texture, but they have released
  59. // their own pointer.
  60. // For this case, the safest thing to do
  61. // is return zero instead of crashing.
  62. return 0;
  63. }
  64. // InterlockedDecrement requires the memory
  65. // to be aligned on DWORD boundary
  66. DXGASSERT(((ULONG_PTR)(&m_cRef) & 3) == 0);
  67. InterlockedDecrement((LONG *)&m_cRef);
  68. if (m_cRef != 0)
  69. {
  70. // For a non-zero ref count,
  71. // just return the value
  72. return m_cRef;
  73. }
  74. // If we are not in use, then we delete ourselves
  75. // otherwise we wait until we are no longer marked
  76. // in use
  77. if (m_cUseCount == 0)
  78. {
  79. DXGASSERT(m_cRef == 0);
  80. // Before deleting a BaseObject,
  81. // we need to call OnDestroy to make sure that
  82. // there is nothing pending in the command
  83. // stream that uses this object
  84. OnDestroy();
  85. delete this;
  86. }
  87. else
  88. {
  89. // To make sure that we don't again release the
  90. // device at our destructor, we mark the object
  91. // as being non-external (refcount is zero and usecount is
  92. // non-zero). At this point, we know the object
  93. // is not an internal one: hence it was either
  94. // external or intrinsic. In either case, it could
  95. // potentially be handed out again (through GetBackBuffer or
  96. // GetTexture) and so we need to handle the case
  97. // where AddRef might be called. We mark the object as
  98. // INTRINSIC to indicate that that even though we don't
  99. // have a Ref on the device (as soon as we release it below),
  100. // we may need to acquire one if it gets add-ref'ed.
  101. DXGASSERT(m_refType != REF_INTERNAL);
  102. m_refType = REF_INTRINSIC;
  103. // We are still in use by the device; but we don't
  104. // have any external references; so we can
  105. // release our reference on the device. (Note that
  106. // even though this should be done before
  107. // changing the reftype, this must be the LAST
  108. // thing we do in this function.)
  109. m_pDevice->Release();
  110. // But this could have been the LAST reference to the
  111. // device; which means that device will now have
  112. // freed us; and the current object has now been
  113. // deleted. So don't access any member data!!
  114. //
  115. // How can this happen? Imagine an app that releases
  116. // everything except an external vb that is the current
  117. // stream source: in this case, the only device ref is from
  118. // the external object; but that extrenal object has a use
  119. // count of 1; when the app calls release on the
  120. // the vb, we end up here; calling release on the device
  121. // causes in turn a call to DecrementUseCount on the
  122. // current object; which causes the object to be freed.
  123. }
  124. // DO NOT PUT CODE HERE (see comment above)
  125. return 0;
  126. } // ReleaseImpl
  127. #undef DPF_MODNAME
  128. #define DPF_MODNAME "CBaseObject::SetPrivateDataImpl"
  129. // Internal function that adds some private data
  130. // information to an object. Supports having private
  131. // data for multiple levels through the optional
  132. // iLevel parameter
  133. HRESULT CBaseObject::SetPrivateDataImpl(REFGUID refguidTag,
  134. CONST VOID* pvData,
  135. DWORD cbSize,
  136. DWORD dwFlags,
  137. BYTE iLevel)
  138. {
  139. if (cbSize > 0 &&
  140. !VALID_PTR(pvData, cbSize))
  141. {
  142. DPF_ERR("Invalid pvData pointer to SetPrivateData");
  143. return D3DERR_INVALIDCALL;
  144. }
  145. if (!VALID_PTR(&refguidTag, sizeof(GUID)))
  146. {
  147. DPF_ERR("Invalid guid to SetPrivateData");
  148. return D3DERR_INVALIDCALL;
  149. }
  150. if (dwFlags & ~D3DSPD_IUNKNOWN)
  151. {
  152. DPF_ERR("Invalid flags to SetPrivateData");
  153. return D3DERR_INVALIDCALL;
  154. }
  155. if (dwFlags & D3DSPD_IUNKNOWN)
  156. {
  157. if (cbSize != sizeof(LPVOID))
  158. {
  159. DPF_ERR("Invalid size for IUnknown to SetPrivateData");
  160. return D3DERR_INVALIDCALL;
  161. }
  162. }
  163. // Remember if we allocated a new node or
  164. // not for error handling
  165. BOOL fNewNode;
  166. // Find the node in our list (if there)
  167. CPrivateDataNode *pNode = Find(refguidTag, iLevel);
  168. if (pNode)
  169. {
  170. // Clean up whatever it has already
  171. pNode->Cleanup();
  172. fNewNode = FALSE;
  173. }
  174. else
  175. {
  176. // Allocate a new node
  177. pNode = new CPrivateDataNode;
  178. if (pNode == NULL)
  179. {
  180. DPF_ERR("SetPrivateData failed a memory allocation");
  181. return E_OUTOFMEMORY;
  182. }
  183. // Initialize a few fields
  184. fNewNode = TRUE;
  185. pNode->m_guid = refguidTag;
  186. pNode->m_iLevel = iLevel;
  187. }
  188. // Initialize the other fields
  189. pNode->m_dwFlags = dwFlags;
  190. pNode->m_cbSize = cbSize;
  191. // Copy the data portion over
  192. if (dwFlags & D3DSPD_IUNKNOWN)
  193. {
  194. // We add-ref the object while we
  195. // keep a pointer to it
  196. pNode->m_pUnknown = (IUnknown *)pvData;
  197. pNode->m_pUnknown->AddRef();
  198. }
  199. else
  200. {
  201. // Allocate a buffer to store our data
  202. // into
  203. pNode->m_pvData = new BYTE[cbSize];
  204. if (pNode->m_pvData == NULL)
  205. {
  206. DPF_ERR("SetPrivateData failed a memory allocation");
  207. // If memory allocation failed,
  208. // then we may need to free the Node
  209. if (fNewNode)
  210. {
  211. delete pNode;
  212. }
  213. return E_OUTOFMEMORY;
  214. }
  215. memcpy(pNode->m_pvData, pvData, cbSize);
  216. }
  217. // If we allocated a new Node then
  218. // we need to put it into our list somewhere
  219. if (fNewNode)
  220. {
  221. // Stuff it at the beginning
  222. pNode->m_pNodeNext = m_pPrivateDataHead;
  223. m_pPrivateDataHead = pNode;
  224. }
  225. return S_OK;
  226. } // CBaseObject::SetPrivateDataImpl
  227. #undef DPF_MODNAME
  228. #define DPF_MODNAME "CBaseObject::GetPrivateDataImpl"
  229. // Internal function that searches the private data list
  230. // for a match. This supports a single list for a container
  231. // and all of its children by using the iLevel parameter.
  232. HRESULT CBaseObject::GetPrivateDataImpl(REFGUID refguidTag,
  233. LPVOID pvBuffer,
  234. LPDWORD pcbSize,
  235. BYTE iLevel) const
  236. {
  237. if (!VALID_WRITEPTR(pcbSize, sizeof(DWORD)))
  238. {
  239. DPF_ERR("Invalid pcbSize pointer to GetPrivateData");
  240. return D3DERR_INVALIDCALL;
  241. }
  242. if (pvBuffer)
  243. {
  244. if (*pcbSize > 0 &&
  245. !VALID_WRITEPTR(pvBuffer, *pcbSize))
  246. {
  247. DPF_ERR("Invalid pvData pointer to GetPrivateData");
  248. return D3DERR_INVALIDCALL;
  249. }
  250. }
  251. if (!VALID_PTR(&refguidTag, sizeof(GUID)))
  252. {
  253. DPF_ERR("Invalid guid to GetPrivateData");
  254. return D3DERR_INVALIDCALL;
  255. }
  256. // Find the node in our list
  257. CPrivateDataNode *pNode = Find(refguidTag, iLevel);
  258. if (pNode == NULL)
  259. {
  260. DPF_ERR("GetPrivateData failed to find a match.");
  261. return D3DERR_NOTFOUND;
  262. }
  263. // Is the user just asking for the size?
  264. if (pvBuffer == NULL)
  265. {
  266. // Return the amount of buffer that was used
  267. *pcbSize = pNode->m_cbSize;
  268. // Return Ok in this case.
  269. return S_OK;
  270. }
  271. // Check if we were given a large enough buffer
  272. if (*pcbSize < pNode->m_cbSize)
  273. {
  274. DPF(2, "GetPrivateData called with insufficient buffer.");
  275. // If the buffer is insufficient, return
  276. // the necessary size in the out parameter
  277. *pcbSize = pNode->m_cbSize;
  278. // An error is returned since pvBuffer != NULL and
  279. // no data was actually returned.
  280. return D3DERR_MOREDATA;
  281. }
  282. // There is enough room; so just overwrite with
  283. // the right size
  284. *pcbSize = pNode->m_cbSize;
  285. // Handle the IUnknown case
  286. if (pNode->m_dwFlags & D3DSPD_IUNKNOWN)
  287. {
  288. *(IUnknown**)pvBuffer = pNode->m_pUnknown;
  289. // We Add-Ref the returned object
  290. pNode->m_pUnknown->AddRef();
  291. return S_OK;
  292. }
  293. memcpy(pvBuffer, pNode->m_pvData, pNode->m_cbSize);
  294. return S_OK;
  295. } // CBaseObject::GetPrivateDataImpl
  296. #undef DPF_MODNAME
  297. #define DPF_MODNAME "CBaseObject::FreePrivateDataImpl"
  298. HRESULT CBaseObject::FreePrivateDataImpl(REFGUID refguidTag,
  299. BYTE iLevel)
  300. {
  301. if (!VALID_PTR(&refguidTag, sizeof(GUID)))
  302. {
  303. DPF_ERR("Invalid guid to FreePrivateData");
  304. return D3DERR_INVALIDCALL;
  305. }
  306. // Keep track of the address of the pointer
  307. // that points to our current node
  308. CPrivateDataNode **ppPrev = &m_pPrivateDataHead;
  309. // Keep track of our current node
  310. CPrivateDataNode *pNode = m_pPrivateDataHead;
  311. // Find the node in our list
  312. while (pNode)
  313. {
  314. // A match means that iLevel AND the guid
  315. // match up
  316. if (pNode->m_iLevel == iLevel &&
  317. pNode->m_guid == refguidTag)
  318. {
  319. // If found, update the pointer
  320. // the points to the current node to
  321. // point to our Next
  322. *ppPrev = pNode->m_pNodeNext;
  323. // Delete the current node
  324. delete pNode;
  325. // We're done
  326. return S_OK;
  327. }
  328. // Update our previous pointer address
  329. ppPrev = &pNode->m_pNodeNext;
  330. // Update our current node to point
  331. // to the next node
  332. pNode = pNode->m_pNodeNext;
  333. }
  334. DPF_ERR("FreePrivateData called but failed to find a match");
  335. return D3DERR_NOTFOUND;
  336. } // CBaseObject::FreePrivateDataImpl
  337. #undef DPF_MODNAME
  338. #define DPF_MODNAME "CBaseObject::Find"
  339. // Helper function to iterate through the list of
  340. // data members
  341. CBaseObject::CPrivateDataNode * CBaseObject::Find(REFGUID refguidTag,
  342. BYTE iLevel) const
  343. {
  344. CPrivateDataNode *pNode = m_pPrivateDataHead;
  345. while (pNode)
  346. {
  347. if (pNode->m_iLevel == iLevel &&
  348. pNode->m_guid == refguidTag)
  349. {
  350. return pNode;
  351. }
  352. pNode = pNode->m_pNodeNext;
  353. }
  354. return NULL;
  355. } // CBaseObject::Find
  356. #undef DPF_MODNAME
  357. #define DPF_MODNAME "CBaseObject::CPrivateDataNode::Cleanup"
  358. void CBaseObject::CPrivateDataNode::Cleanup()
  359. {
  360. if (m_dwFlags & D3DSPD_IUNKNOWN)
  361. {
  362. DXGASSERT(m_cbSize == sizeof(IUnknown *));
  363. m_pUnknown->Release();
  364. }
  365. else
  366. {
  367. delete [] m_pvData;
  368. }
  369. m_pvData = NULL;
  370. m_cbSize = 0;
  371. m_dwFlags &= ~D3DSPD_IUNKNOWN;
  372. return;
  373. } // CBaseObject::CPrivateDataNode::Cleanup
  374. // End of file : d3dobj.cpp