Source code of Windows XP (NT5)
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.

589 lines
20 KiB

  1. #ifndef __D3DOBJ_HPP__
  2. #define __D3DOBJ_HPP__
  3. /*==========================================================================;
  4. *
  5. * Copyright (C) 1999-2000 Microsoft Corporation. All Rights Reserved.
  6. *
  7. * File: d3dobj.hpp
  8. * Content: Base class header for resources and buffers
  9. *
  10. *
  11. ***************************************************************************/
  12. // Helper function for parameter checking
  13. inline BOOL IsPowerOfTwo(DWORD dwNumber)
  14. {
  15. if (dwNumber == 0 || (dwNumber & (dwNumber-1)) != 0)
  16. return FALSE;
  17. else
  18. return TRUE;
  19. } // IsPowerOfTwo
  20. // forward decls
  21. class CBaseObject;
  22. // Entry-points that are inside/part of a device/enum may need to
  23. // take a critical section. They do this by putting this
  24. // line of code at the beginning of the API.
  25. //
  26. // Use API_ENTER for APIs that return an HRESULT;
  27. // Use API_ENTER_RET for APIs that return a struct (as an out param)
  28. // Use API_ENTER_VOID for APIs that return void.
  29. // Use API_ENTER_SUBOBJECT_RELEASE for Release methods on sub-objects.
  30. // Use API_ENTER_NOLOCK for Release methods on the Device or Enum itself.
  31. // Use API_ENTER_NOLOCK for AddRef on anything.
  32. //
  33. //
  34. // (Release is special because the action of release may cause the
  35. // destruction of the device/enum; which would free the critical section
  36. // before we got a chance to call Unlock on that critical section.)
  37. //
  38. // The class CLockOwner is a common base class for both CBaseDevice
  39. // and CEnum.
  40. #ifdef DEBUG
  41. #define API_ENTER(pLockOwner) \
  42. if (IsBadWritePtr((void *)this, sizeof(*this)) || \
  43. IsBadWritePtr((void *)pLockOwner, sizeof(*pLockOwner)) || \
  44. !pLockOwner->IsValid()) \
  45. { \
  46. DPF_ERR("Invalid 'this' parameter to D3D8 API."); \
  47. return D3DERR_INVALIDCALL; \
  48. } \
  49. CLockD3D _lock(pLockOwner, DPF_MODNAME, __FILE__)
  50. // Use this for API's that return something other than an HRESULT
  51. #define API_ENTER_RET(pLockOwner, RetType) \
  52. if (IsBadWritePtr((void *)this, sizeof(*this)) || \
  53. IsBadWritePtr((void *)pLockOwner, sizeof(*pLockOwner)) || \
  54. !pLockOwner->IsValid()) \
  55. { \
  56. DPF_ERR("Invalid 'this' parameter to D3D8 API.."); \
  57. /* We only allow DWORD types of returns for compat */ \
  58. /* with C users. */ \
  59. return (RetType)0; \
  60. } \
  61. CLockD3D _lock(pLockOwner, DPF_MODNAME, __FILE__)
  62. // Use this for API's that return void
  63. #define API_ENTER_VOID(pLockOwner) \
  64. if (IsBadWritePtr((void *)this, sizeof(*this)) || \
  65. IsBadWritePtr((void *)pLockOwner, sizeof(*pLockOwner)) || \
  66. !pLockOwner->IsValid()) \
  67. { \
  68. DPF_ERR("Invalid 'this' parameter to D3D8 API..."); \
  69. return; \
  70. } \
  71. CLockD3D _lock(pLockOwner, DPF_MODNAME, __FILE__)
  72. // Use this for Release API's of subobjects i.e. not Device or Enum
  73. #define API_ENTER_SUBOBJECT_RELEASE(pLockOwner) \
  74. if (IsBadWritePtr((void *)this, sizeof(*this)) || \
  75. IsBadWritePtr((void *)pLockOwner, sizeof(*pLockOwner)) || \
  76. !pLockOwner->IsValid()) \
  77. { \
  78. DPF_ERR("Invalid 'this' parameter to D3D8 API...."); \
  79. return 0; \
  80. } \
  81. CLockD3D _lock(pLockOwner, DPF_MODNAME, __FILE__, TRUE)
  82. // Use this for API tracing for methods
  83. // that don't need a crit-sec lock at-all in Retail.
  84. #define API_ENTER_NO_LOCK_HR(pLockOwner) \
  85. if (IsBadWritePtr((void *)this, sizeof(*this)) || \
  86. IsBadWritePtr((void *)pLockOwner, sizeof(*pLockOwner)) || \
  87. !pLockOwner->IsValid()) \
  88. { \
  89. DPF_ERR("Invalid 'this' parameter to D3D8 API....."); \
  90. return D3DERR_INVALIDCALL; \
  91. } \
  92. CNoLockD3D _noLock(DPF_MODNAME, __FILE__)
  93. // Use this for API tracing for Release for the device or enum
  94. // (which is special; see note above). Also for AddRef for anything
  95. #define API_ENTER_NO_LOCK(pLockOwner) \
  96. if (IsBadWritePtr((void *)this, sizeof(*this)) || \
  97. IsBadWritePtr((void *)pLockOwner, sizeof(*pLockOwner)) || \
  98. !pLockOwner->IsValid()) \
  99. { \
  100. DPF_ERR("Invalid 'this' parameter to D3D8 API......"); \
  101. return 0; \
  102. } \
  103. CNoLockD3D _noLock(DPF_MODNAME, __FILE__)
  104. #else // !DEBUG
  105. #define API_ENTER(pLockOwner) \
  106. CLockD3D _lock(pLockOwner)
  107. #define API_ENTER_RET(pLockOwner, RetType) \
  108. CLockD3D _lock(pLockOwner)
  109. #define API_ENTER_VOID(pLockOwner) \
  110. CLockD3D _lock(pLockOwner)
  111. #define API_ENTER_SUBOBJECT_RELEASE(pLockOwner) \
  112. CLockD3D _lock(pLockOwner, TRUE)
  113. #define API_ENTER_NO_LOCK(pLockOwner)
  114. #define API_ENTER_NO_LOCK_HR(pLockOwner)
  115. #endif // !DEBUG
  116. // This is a locking object that is supposed to work with
  117. // the device/enum to determine whether and which critical section needs to
  118. // be taken. The use of a destructor means that "Unlock" will happen
  119. // automatically as part of the destructor
  120. class CLockD3D
  121. {
  122. public:
  123. #ifdef DEBUG
  124. CLockD3D(CLockOwner *pLockOwner, char *moduleName, char *fileName, BOOL bSubObjectRelease = FALSE)
  125. #else // !DEBUG
  126. CLockD3D(CLockOwner *pLockOwner, BOOL bSubObjectRelease = FALSE)
  127. #endif // !DEBUG
  128. {
  129. // Remember the device
  130. m_pLockOwner = pLockOwner;
  131. // Add-ref the LockOwner if there is a risk that
  132. // that we might cause the LockOwner to go away in processing
  133. // the current function i.e. SubObject Release
  134. if (bSubObjectRelease)
  135. {
  136. m_pLockOwner->AddRefOwner();
  137. // Remember to unlock it
  138. m_bNeedToReleaseLockOwner = TRUE;
  139. }
  140. else
  141. {
  142. // No need to AddRef/Release the device
  143. m_bNeedToReleaseLockOwner = FALSE;
  144. }
  145. // Ask the LockOwner to take a lock for us
  146. m_pLockOwner->Lock();
  147. #ifdef DEBUG
  148. m_Count++;
  149. DPF(6, "*** LOCK_D3D: CNT = %ld %s %s", m_Count, moduleName, fileName);
  150. #endif
  151. } // CD3DLock
  152. ~CLockD3D()
  153. {
  154. #ifdef DEBUG
  155. DPF(6, "*** UNLOCK_D3D: CNT = %ld", m_Count);
  156. m_Count--;
  157. #endif // DEBUG
  158. m_pLockOwner->Unlock();
  159. // Call Release if we need to
  160. if (m_bNeedToReleaseLockOwner)
  161. m_pLockOwner->ReleaseOwner();
  162. } // ~CD3DLock
  163. private:
  164. #ifdef DEBUG
  165. static DWORD m_Count;
  166. #endif // DEBUG
  167. CLockOwner *m_pLockOwner;
  168. BOOL m_bNeedToReleaseLockOwner;
  169. }; // class CLockD3D
  170. #ifdef DEBUG
  171. // Helper debug-only class for API tracing
  172. class CNoLockD3D
  173. {
  174. public:
  175. CNoLockD3D(char *moduleName, char *fileName)
  176. {
  177. DPF(6, "*** LOCK_D3D: Module= %s %s", moduleName, fileName);
  178. } // CD3DLock
  179. ~CNoLockD3D()
  180. {
  181. DPF(6, "*** UNLOCK_D3D:");
  182. } // ~CD3DLock
  183. }; // CNoLockD3D
  184. #endif // DEBUG
  185. //
  186. // This header file contains the base class for all resources and buffers x
  187. // types of objects
  188. //
  189. // The CBaseObject class contains functionality for the following
  190. // services which can be used by the derived classes:
  191. // AddRefImpl/ReleaseImpl
  192. // Get/SetPrivateDataImpl data
  193. // OpenDeviceImpl
  194. //
  195. // Base objects should allocated with "new" which is means that they
  196. // should be 32-byte aligned by our default allocator.
  197. //
  198. // Resources inherit from CBaseObject and add functionality for
  199. // priority
  200. //
  201. // Add-ref semantics for these objects is complex; a constructor
  202. // flag indicates how/when/if the object will add-ref the device.
  203. typedef enum
  204. {
  205. // External objects add-ref the device; they are
  206. // freed by calling Release()
  207. REF_EXTERNAL = 0,
  208. // Intrinsic objects don't add-ref the device
  209. // except for additional add-refs. They are freed
  210. // when the number of releases equals the number of
  211. // addrefs AND the device has called DecrUseCount
  212. // on the object.
  213. REF_INTRINSIC = 1,
  214. // Internal is like intrinsic except that we
  215. // assert that no one should ever call AddRef or Release
  216. // on this object at all. To free it, you have to
  217. // call DecrUseCount
  218. REF_INTERNAL = 2,
  219. } REF_TYPE;
  220. class CBaseObject
  221. {
  222. public:
  223. // Provides access to the two handles represent
  224. // this object to the DDI/TokenStream. Specifically,
  225. // this represents the Real Sys-Mem data in the
  226. // case of Managed Resources. (To find
  227. // the vid-mem mapping for a managed resource;
  228. // see resource.hpp)
  229. DWORD BaseDrawPrimHandle() const
  230. {
  231. return D3D8GetDrawPrimHandle(m_hKernelHandle);
  232. } // DrawPrimHandle
  233. HANDLE BaseKernelHandle() const
  234. {
  235. return m_hKernelHandle;
  236. } // KernelHandle
  237. // NOTE: No internal object should ever add-ref another
  238. // internal object; otherwise we may end up with ref-count
  239. // cycles that prevent anything from ever going away.
  240. // Instead, an internal object may mark another internal
  241. // object as being "InUse" which will force it to be kept
  242. // in memory until it is no-longer in use (and the ref-count
  243. // is zero.)
  244. // Internal Implementations of AddRef and Release
  245. DWORD AddRefImpl();
  246. DWORD ReleaseImpl();
  247. DWORD IncrementUseCount()
  248. {
  249. DXGASSERT(m_refType != REF_INTERNAL || m_cRef == 0);
  250. m_cUseCount++;
  251. return m_cUseCount;
  252. } // IncrUseCount
  253. DWORD DecrementUseCount()
  254. {
  255. DXGASSERT(m_refType != REF_INTERNAL || m_cRef == 0);
  256. DXGASSERT(m_cUseCount > 0);
  257. m_cUseCount--;
  258. if (m_cUseCount == 0 && m_cRef == 0)
  259. {
  260. // Before deleting a BaseObject,
  261. // we need to call OnDestroy to make sure that
  262. // there is nothing pending in the command
  263. // stream that uses this object
  264. OnDestroy();
  265. // Ok; now safe to delete the object
  266. delete this;
  267. return 0;
  268. }
  269. return m_cUseCount;
  270. } // DecrUseCount
  271. // Internal implementation functions for
  272. // the PrivateData set of methods
  273. HRESULT SetPrivateDataImpl(REFGUID refguidTag,
  274. CONST VOID* pvData,
  275. DWORD cbSize,
  276. DWORD dwFlags,
  277. BYTE iLevel);
  278. HRESULT GetPrivateDataImpl(REFGUID refguidTag,
  279. LPVOID pvBuffer,
  280. LPDWORD pcbSize,
  281. BYTE iLevel) const;
  282. HRESULT FreePrivateDataImpl(REFGUID refguidTag,
  283. BYTE iLevel);
  284. // Implements the OpenDevice method
  285. HRESULT GetDeviceImpl(IDirect3DDevice8 ** ppvInterface) const
  286. {
  287. if (!VALID_PTR_PTR(ppvInterface))
  288. {
  289. DPF_ERR("Invalid ppvInterface parameter passed to GetDevice");
  290. return D3DERR_INVALIDCALL;
  291. }
  292. return m_pDevice->QueryInterface(IID_IDirect3DDevice8, (void**) ppvInterface);
  293. }; // OpenDeviceImpl
  294. CBaseDevice * Device() const
  295. {
  296. return m_pDevice;
  297. } // Device
  298. // Method to for swapping the underlying identity of
  299. // a surface. Caller must make sure that we're not locked
  300. // or other such badness.
  301. void SwapKernelHandles(HANDLE *phKernelHandle)
  302. {
  303. DXGASSERT(m_hKernelHandle != NULL);
  304. DXGASSERT(*phKernelHandle != NULL);
  305. HANDLE tmp = m_hKernelHandle;
  306. m_hKernelHandle = *phKernelHandle;
  307. *phKernelHandle = tmp;
  308. }
  309. protected:
  310. // The following are methods that are only
  311. // accessible by derived classes: they don't make
  312. // sense for other classes to call explicitly.
  313. // Constructor
  314. //
  315. CBaseObject(CBaseDevice *pDevice, REF_TYPE ref = REF_EXTERNAL) :
  316. m_pDevice(pDevice),
  317. m_refType(ref),
  318. m_hKernelHandle(NULL)
  319. {
  320. DXGASSERT(m_pDevice);
  321. DXGASSERT(m_refType == REF_EXTERNAL ||
  322. m_refType == REF_INTRINSIC ||
  323. m_refType == REF_INTERNAL);
  324. m_pPrivateDataHead = NULL;
  325. if (ref == REF_EXTERNAL)
  326. {
  327. // External objects add-ref the device
  328. // as well as having their own reference
  329. // count set to one
  330. m_pDevice->AddRef();
  331. m_cRef = 1;
  332. m_cUseCount = 0;
  333. }
  334. else
  335. {
  336. // Internal and intrinsic objects have no
  337. // initial ref-count; but they are
  338. // marked as InUse; the device frees them
  339. // by calling DecrUseCount
  340. m_cUseCount = 1;
  341. m_cRef = 0;
  342. }
  343. }; // CBaseObject
  344. // The destructor is marked virtual so that delete calls to
  345. // the base interface will be handled properly
  346. virtual ~CBaseObject()
  347. {
  348. DXGASSERT(m_pDevice);
  349. DXGASSERT(m_cRef == 0);
  350. DXGASSERT(m_cUseCount == 0);
  351. CPrivateDataNode *pNode = m_pPrivateDataHead;
  352. while (pNode)
  353. {
  354. CPrivateDataNode *pNodeNext = pNode->m_pNodeNext;
  355. delete pNode;
  356. pNode = pNodeNext;
  357. }
  358. if (m_refType == REF_EXTERNAL)
  359. {
  360. // Release our reference on the
  361. // device
  362. m_pDevice->Release();
  363. }
  364. }; // ~CBaseObject
  365. // OnDestroy function is called just
  366. // before an object is about to get deleted; we
  367. // use this to provide synching as well as notification
  368. // to FE when a texture is going away.
  369. virtual void OnDestroy()
  370. {
  371. // Not all classes have to worry about this;
  372. // so the default is to do nothing.
  373. }; // OnDestroy
  374. void SetKernelHandle(HANDLE hKernelHandle)
  375. {
  376. // This better be null; or we either leaking something
  377. // or we had some uninitialized stuff that will hurt later
  378. DXGASSERT(m_hKernelHandle == NULL);
  379. // Remember our handles
  380. m_hKernelHandle = hKernelHandle;
  381. DXGASSERT(m_hKernelHandle != NULL);
  382. } // SetHandle
  383. BOOL IsInUse()
  384. {
  385. return (m_cUseCount > 0);
  386. } // IsInUse
  387. private:
  388. //
  389. // RefCount must be DWORD aligned
  390. //
  391. DWORD m_cRef;
  392. // Keep a "Use Count" which indicates whether
  393. // the device (or other object tied to the lifetime of
  394. // the device) is relying on this object from staying around.
  395. // This is used to prevent ref-count cycles that would
  396. // occur whenever something like SetTexture add-ref'ed the
  397. // the texture that was passed in.
  398. DWORD m_cUseCount;
  399. // Keep Track of the device that owns this object
  400. // This is an add-ref'ed value
  401. CBaseDevice *m_pDevice;
  402. // We need an internal handle so that
  403. // we can communicate to the driver/kernel.
  404. //
  405. // Note that the base object does not release this
  406. // and it is the responsibility of the derived
  407. // class to do so.
  408. HANDLE m_hKernelHandle;
  409. // Keep track of list of private data objects
  410. class CPrivateDataNode;
  411. CPrivateDataNode *m_pPrivateDataHead;
  412. // Need to keep track of an intrinsic flag
  413. // to decide whether to release the device on
  414. // free
  415. // CONSIDER: Try to merge this flag into some
  416. // other variable.
  417. REF_TYPE m_refType;
  418. // Helper function to find the right node
  419. CPrivateDataNode* Find(REFGUID refguidTag, BYTE iLevel) const;
  420. // Each private data is stored in this node
  421. // object which is only used for this purpose
  422. // by this class
  423. class CPrivateDataNode
  424. {
  425. public:
  426. CPrivateDataNode() {};
  427. ~CPrivateDataNode()
  428. {
  429. Cleanup();
  430. } // ~CPrivateDateNode
  431. GUID m_guid;
  432. CPrivateDataNode *m_pNodeNext;
  433. DWORD m_cbSize;
  434. DWORD m_dwFlags;
  435. BYTE m_iLevel;
  436. union
  437. {
  438. void *m_pvData;
  439. IUnknown *m_pUnknown;
  440. };
  441. void Cleanup();
  442. }; // CPrivateDataNode
  443. }; // class CBaseObject
  444. // Helper class for all surface types
  445. //
  446. class CBaseSurface : public IDirect3DSurface8
  447. {
  448. public:
  449. CBaseSurface() :
  450. m_isLocked(FALSE) {}
  451. // Methods to allow D3D methods to treat all surface
  452. // variants the same way
  453. virtual DWORD DrawPrimHandle() const PURE;
  454. virtual HANDLE KernelHandle() const PURE;
  455. // See CBaseObject::IncrementUseCount and
  456. // CBaseObject::DecrementUseCount and the
  457. // description of the REF_TYPEs above.
  458. virtual DWORD IncrementUseCount() PURE;
  459. virtual DWORD DecrementUseCount() PURE;
  460. // Batching logic is necessary to make sure
  461. // that the command buffer is flushed before
  462. // any read or write access is made to a
  463. // a surface. This should be called at
  464. // SetRenderTarget time; and it should be
  465. // called for the currently set rendertarget
  466. // and zbuffer when the batch count is updated
  467. virtual void Batch() PURE;
  468. // Sync should be called when a surface is
  469. // about to be modified; Normally this is taken
  470. // care of automatically by Lock; but it also
  471. // needs to be called prior to using the Blt
  472. // DDI.
  473. virtual void Sync() PURE;
  474. // Internal lock functions bypass
  475. // parameter checking and also whether the
  476. // surface marked as Lockable or LockOnce
  477. // etc.
  478. virtual HRESULT InternalLockRect(D3DLOCKED_RECT *pLockedRectData,
  479. CONST RECT *pRect,
  480. DWORD dwFlags) PURE;
  481. virtual HRESULT InternalUnlockRect() PURE;
  482. BOOL IsLocked() const
  483. {
  484. return m_isLocked;
  485. }; // IsLocked
  486. // Determines if a LOAD_ONCE surface has already
  487. // been loaded
  488. virtual BOOL IsLoaded() const PURE;
  489. // Provides a method to access basic structure of the
  490. // pieces of the resource.
  491. virtual D3DSURFACE_DESC InternalGetDesc() const PURE;
  492. // Access the device of the surface
  493. virtual CBaseDevice *InternalGetDevice() const PURE;
  494. public:
  495. BOOL m_isLocked;
  496. }; // class CBaseSurface
  497. #endif // __D3DOBJ_HPP__