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.

1028 lines
29 KiB

  1. /*==========================================================================;
  2. *
  3. * Copyright (C) 1999-2000 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: surface.cpp
  6. * Content: Implementation of the CSurface class.
  7. *
  8. *
  9. ***************************************************************************/
  10. #include "ddrawpr.h"
  11. #include "surface.hpp"
  12. #include "pixel.hpp"
  13. #include "swapchan.hpp"
  14. #undef DPF_MODNAME
  15. #define DPF_MODNAME "CSurface::Create"
  16. // Static class function for creating a RenderTarget/ZStencil object.
  17. // (Because it is static; it doesn't have a this pointer.)
  18. HRESULT CSurface::Create(CBaseDevice *pDevice,
  19. DWORD Width,
  20. DWORD Height,
  21. DWORD Usage,
  22. D3DFORMAT UserFormat,
  23. D3DMULTISAMPLE_TYPE MultiSampleType,
  24. REF_TYPE refType,
  25. IDirect3DSurface8 **ppSurface)
  26. {
  27. HRESULT hr;
  28. // Do parameter checking here
  29. if (!VALID_PTR_PTR(ppSurface))
  30. {
  31. DPF_ERR("Bad parameter passed for ppSurface for creating a surface. CreateRenderTarget/CreateDepthStencil failed");
  32. return D3DERR_INVALIDCALL;
  33. }
  34. // Zero-out return parameter
  35. *ppSurface = NULL;
  36. // Size may need to be 4x4
  37. if (CPixel::Requires4X4(UserFormat))
  38. {
  39. if ((Width & 3) ||
  40. (Height & 3))
  41. {
  42. DPF_ERR("DXT Formats require width/height to be a multiple of 4. CreateRenderTarget/CreateDepthStencil failed.");
  43. return D3DERR_INVALIDCALL;
  44. }
  45. }
  46. // Validate against zero width/height
  47. if (Width == 0 ||
  48. Height == 0)
  49. {
  50. DPF_ERR("Width/Height must be non-zero. CreateRenderTarget/CreateDepthStencil failed");
  51. return D3DERR_INVALIDCALL;
  52. }
  53. // Now verify that the device can support the specified format
  54. hr = pDevice->CheckDeviceFormat(
  55. Usage & (D3DUSAGE_RENDERTARGET |
  56. D3DUSAGE_DEPTHSTENCIL),
  57. D3DRTYPE_SURFACE,
  58. UserFormat);
  59. if (FAILED(hr))
  60. {
  61. DPF_ERR("The format is not supported by this device. CreateRenderTarget/CreateDepthStencil failed");
  62. return D3DERR_INVALIDCALL;
  63. }
  64. // Infer lockability for DepthStencil from format
  65. if (Usage & D3DUSAGE_DEPTHSTENCIL)
  66. {
  67. if (!CPixel::IsNonLockableZ(UserFormat))
  68. {
  69. Usage |= D3DUSAGE_LOCK;
  70. }
  71. }
  72. // Validate lockability
  73. if ((MultiSampleType != D3DMULTISAMPLE_NONE) &&
  74. (Usage & D3DUSAGE_LOCK))
  75. {
  76. // RT have explicit lockability
  77. if (Usage & D3DUSAGE_RENDERTARGET)
  78. {
  79. DPF_ERR("Multi-Sampled render-targets are not lockable. CreateRenderTarget failed");
  80. return D3DERR_INVALIDCALL;
  81. }
  82. else
  83. {
  84. DPF_ERR("Multi-Sampled Depth Stencil buffers are not lockable. "
  85. "Use D3DFMT_D16 instead of D3DFMT_D16_LOCKABLE. CreateDepthStencil failed");
  86. return D3DERR_INVALIDCALL;
  87. }
  88. }
  89. // Map depth/stencil format
  90. D3DFORMAT RealFormat = pDevice->MapDepthStencilFormat(UserFormat);
  91. // Create the surface
  92. CSurface *pSurface;
  93. pSurface = new CDriverSurface(pDevice,
  94. Width,
  95. Height,
  96. Usage,
  97. UserFormat,
  98. RealFormat,
  99. MultiSampleType,
  100. 0, // hKernelHandle
  101. refType,
  102. &hr);
  103. if (pSurface == NULL)
  104. {
  105. DPF_ERR("Out of Memory creating surface. CreateRenderTarget/CreateDepthStencil failed");
  106. return E_OUTOFMEMORY;
  107. }
  108. if (FAILED(hr))
  109. {
  110. DPF_ERR("Error during initialization of surface. CreateRenderTarget/CreateDepthStencil failed");
  111. if (refType == REF_EXTERNAL)
  112. {
  113. // External objects get released
  114. pSurface->Release();
  115. }
  116. else
  117. {
  118. // Internal and intrinsic objects get decremented
  119. DXGASSERT(refType == REF_INTERNAL || refType == REF_INTRINSIC);
  120. pSurface->DecrementUseCount();
  121. }
  122. return hr;
  123. }
  124. // We're done; just return the object
  125. *ppSurface = pSurface;
  126. return hr;
  127. } // static Create for ZBuffers and RenderTargets
  128. #undef DPF_MODNAME
  129. #define DPF_MODNAME "CSurface::CreateImageSurface"
  130. // Function for creating sys-mem stand-alone surfaces
  131. // that can be used with CopyRect and SetCursorSurface and
  132. // ReadBuffer
  133. HRESULT CSurface::CreateImageSurface(CBaseDevice *pDevice,
  134. DWORD Width,
  135. DWORD Height,
  136. D3DFORMAT Format,
  137. REF_TYPE refType,
  138. IDirect3DSurface8 **ppSurface)
  139. {
  140. HRESULT hr;
  141. // Do parameter checking here
  142. if (!VALID_PTR_PTR(ppSurface))
  143. {
  144. DPF_ERR("Bad parameter passed for ppSurface for creating a surface. CreateImageSurface failed.");
  145. return D3DERR_INVALIDCALL;
  146. }
  147. // Zero-out return parameter
  148. *ppSurface = NULL;
  149. // Has to be supported format
  150. if (!CPixel::IsSupported(D3DRTYPE_SURFACE, Format))
  151. {
  152. DPF_ERR("This format is not supported for CreateImageSurface");
  153. return D3DERR_INVALIDCALL;
  154. }
  155. if (CPixel::IsNonLockableZ(Format))
  156. {
  157. DPF_ERR("This Z format is not supported for CreateImageSurface");
  158. return D3DERR_INVALIDCALL;
  159. }
  160. // Size may need to be 4x4
  161. if (CPixel::Requires4X4(Format))
  162. {
  163. if ((Width & 3) ||
  164. (Height & 3))
  165. {
  166. DPF_ERR("DXT Formats require width/height to be a multiple of 4. CreateImageSurface failed.");
  167. return D3DERR_INVALIDCALL;
  168. }
  169. }
  170. // Validate against zero width/height
  171. if (Width == 0 ||
  172. Height == 0)
  173. {
  174. DPF_ERR("Width/Height must be non-zero. CreateImageSurface failed.");
  175. return D3DERR_INVALIDCALL;
  176. }
  177. // Usage is explictly just Usage_LOCK
  178. DWORD Usage = D3DUSAGE_LOCK;
  179. CSurface *pSurface = new CSysMemSurface(pDevice,
  180. Width,
  181. Height,
  182. Usage,
  183. Format,
  184. refType,
  185. &hr);
  186. if (pSurface == NULL)
  187. {
  188. DPF_ERR("Out of Memory creating surface. CreateImageSurface failed.");
  189. return E_OUTOFMEMORY;
  190. }
  191. if (FAILED(hr))
  192. {
  193. DPF_ERR("Error during initialization of surface. CreateImageSurface failed.");
  194. if (refType == REF_EXTERNAL)
  195. {
  196. // External objects get released
  197. pSurface->Release();
  198. }
  199. else
  200. {
  201. // Internal and intrinsic objects get decremented
  202. DXGASSERT(refType == REF_INTERNAL || refType == REF_INTRINSIC);
  203. pSurface->DecrementUseCount();
  204. }
  205. return hr;
  206. }
  207. // We're done; just return the object
  208. *ppSurface = pSurface;
  209. return S_OK;
  210. } // static CreateImageSurface
  211. #undef DPF_MODNAME
  212. #define DPF_MODNAME "CSurface::CSurface"
  213. // Constructor the surface class; this is the
  214. // base class for render targets/zbuffers/and backbuffers
  215. CSurface::CSurface(CBaseDevice *pDevice,
  216. DWORD Width,
  217. DWORD Height,
  218. DWORD Usage,
  219. D3DFORMAT Format,
  220. REF_TYPE refType,
  221. HRESULT *phr
  222. ) :
  223. CBaseObject(pDevice, refType),
  224. m_qwBatchCount(0)
  225. {
  226. // Sanity check
  227. DXGASSERT(phr);
  228. // Initialize basic structures
  229. m_desc.Format = Format;
  230. m_desc.Pool = D3DPOOL_DEFAULT;
  231. m_desc.Usage = Usage;
  232. m_desc.Type = D3DRTYPE_SURFACE;
  233. m_desc.Width = Width;
  234. m_desc.Height = Height;
  235. m_formatUser = Format;
  236. m_poolUser = D3DPOOL_DEFAULT;
  237. // Return success
  238. *phr = S_OK;
  239. } // CSurface::CSurface
  240. #undef DPF_MODNAME
  241. #define DPF_MODNAME "CSurface::~CSurface"
  242. // Destructor
  243. CSurface::~CSurface()
  244. {
  245. // The destructor has to handle partially
  246. // created objects.
  247. // Check to make sure that we aren't deleting
  248. // an object that is referenced in the current (unflushed)
  249. // command stream buffer.
  250. DXGASSERT(m_qwBatchCount <= static_cast<CD3DBase*>(Device())->CurrentBatch());
  251. } // CSurface::~CSurface
  252. // IUnknown methods
  253. #undef DPF_MODNAME
  254. #define DPF_MODNAME "CSurface::QueryInterface"
  255. STDMETHODIMP CSurface::QueryInterface(REFIID riid,
  256. LPVOID FAR *ppvObj)
  257. {
  258. API_ENTER(Device());
  259. if (!VALID_PTR_PTR(ppvObj))
  260. {
  261. DPF_ERR("Invalid ppvObj parameter passed to CSurface::QueryInterface");
  262. return D3DERR_INVALIDCALL;
  263. }
  264. if (!VALID_PTR(&riid, sizeof(GUID)))
  265. {
  266. DPF_ERR("Invalid guid memory address to CSurface::QueryInterface");
  267. return D3DERR_INVALIDCALL;
  268. }
  269. if (riid == IID_IDirect3DSurface8 || riid == IID_IUnknown)
  270. {
  271. *ppvObj = static_cast<void*>(static_cast<IDirect3DSurface8 *>(this));
  272. AddRef();
  273. return S_OK;
  274. }
  275. DPF_ERR("Unsupported Interface identifier passed to CSurface::QueryInterface");
  276. // Null out param
  277. *ppvObj = NULL;
  278. return E_NOINTERFACE;
  279. } // QueryInterface
  280. #undef DPF_MODNAME
  281. #define DPF_MODNAME "CSurface::AddRef"
  282. STDMETHODIMP_(ULONG) CSurface::AddRef()
  283. {
  284. API_ENTER_NO_LOCK(Device());
  285. return AddRefImpl();
  286. } // AddRef
  287. #undef DPF_MODNAME
  288. #define DPF_MODNAME "CSurface::Release"
  289. STDMETHODIMP_(ULONG) CSurface::Release()
  290. {
  291. API_ENTER_SUBOBJECT_RELEASE(Device());
  292. return ReleaseImpl();
  293. } // Release
  294. // IDirect3DBuffer methods
  295. #undef DPF_MODNAME
  296. #define DPF_MODNAME "CSurface::GetDevice"
  297. STDMETHODIMP CSurface::GetDevice(IDirect3DDevice8 ** ppObj)
  298. {
  299. API_ENTER(Device());
  300. return GetDeviceImpl(ppObj);
  301. } // GetDevice
  302. #undef DPF_MODNAME
  303. #define DPF_MODNAME "CSurface::SetPrivateData"
  304. STDMETHODIMP CSurface::SetPrivateData(REFGUID riid,
  305. CONST VOID* pvData,
  306. DWORD cbData,
  307. DWORD dwFlags)
  308. {
  309. API_ENTER(Device());
  310. // We use level zero for our data
  311. return SetPrivateDataImpl(riid, pvData, cbData, dwFlags, 0);
  312. } // SetPrivateData
  313. #undef DPF_MODNAME
  314. #define DPF_MODNAME "CSurface::GetPrivateData"
  315. STDMETHODIMP CSurface::GetPrivateData(REFGUID riid,
  316. LPVOID pvData,
  317. LPDWORD pcbData)
  318. {
  319. API_ENTER(Device());
  320. // We use level zero for our data
  321. return GetPrivateDataImpl(riid, pvData, pcbData, 0);
  322. } // GetPrivateData
  323. #undef DPF_MODNAME
  324. #define DPF_MODNAME "CSurface::FreePrivateData"
  325. STDMETHODIMP CSurface::FreePrivateData(REFGUID riid)
  326. {
  327. API_ENTER(Device());
  328. // We use level zero for our data
  329. return FreePrivateDataImpl(riid, 0);
  330. } // FreePrivateData
  331. #undef DPF_MODNAME
  332. #define DPF_MODNAME "CSurface::GetContainer"
  333. STDMETHODIMP CSurface::GetContainer(REFIID riid,
  334. void **ppContainer)
  335. {
  336. API_ENTER(Device());
  337. // Our 'container' is just the device since
  338. // we are a standalone surface object
  339. return Device()->QueryInterface( riid, ppContainer);
  340. } // OpenContainer
  341. #undef DPF_MODNAME
  342. #define DPF_MODNAME "CSurface::GetDesc"
  343. STDMETHODIMP CSurface::GetDesc(D3DSURFACE_DESC *pDesc)
  344. {
  345. API_ENTER(Device());
  346. // If parameters are bad, then we should fail some stuff
  347. if (!VALID_WRITEPTR(pDesc, sizeof(*pDesc)))
  348. {
  349. DPF_ERR("bad pointer for pDesc passed to CSurface::GetDesc");
  350. return D3DERR_INVALIDCALL;
  351. }
  352. *pDesc = m_desc;
  353. pDesc->Format = m_formatUser;
  354. pDesc->Pool = m_poolUser;
  355. pDesc->Usage &= D3DUSAGE_EXTERNAL;
  356. return S_OK;
  357. } // GetDesc
  358. #undef DPF_MODNAME
  359. #define DPF_MODNAME "CSurface::InternalGetDesc"
  360. D3DSURFACE_DESC CSurface::InternalGetDesc() const
  361. {
  362. return m_desc;
  363. } // InternalGetDesc
  364. #ifdef DEBUG
  365. #undef DPF_MODNAME
  366. #define DPF_MODNAME "CSurface::ReportWhyLockFailed"
  367. // DPF why Lock failed as clearly as possible
  368. void CSurface::ReportWhyLockFailed(void) const
  369. {
  370. // If there are multiple reasons that lock failed; we report
  371. // them all to minimize user confusion
  372. if (InternalGetDesc().MultiSampleType != D3DMULTISAMPLE_NONE)
  373. {
  374. DPF_ERR("Lock is not supported for surfaces that have multi-sampling enabled.");
  375. }
  376. if (InternalGetDesc().Usage & D3DUSAGE_DEPTHSTENCIL)
  377. {
  378. DPF_ERR("Lock is not supported for depth formats other than D3DFMT_D16_LOCKABLE");
  379. }
  380. // If this is not a non-lockable Z format, and
  381. // we are not multisampled; then the user must
  382. // have explicitly chosen to create us in an non-lockable way
  383. if (InternalGetDesc().Usage & D3DUSAGE_BACKBUFFER)
  384. {
  385. DPF_ERR("Backbuffers are not lockable unless application specifies "
  386. "D3DPRESENTFLAG_LOCKABLE_BACKBUFFER at CreateDevice and Reset. "
  387. "Lockable backbuffers incur a performance cost on some "
  388. "graphics hardware.");
  389. }
  390. else if (InternalGetDesc().Usage & D3DUSAGE_RENDERTARGET)
  391. {
  392. DPF_ERR("RenderTargets are not lockable unless application specifies "
  393. "TRUE for the Lockable parameter for CreateRenderTarget. Lockable "
  394. "render targets incur a performance cost on some graphics hardware.");
  395. }
  396. // If we got here; then USAGE_LOCK should not have been set
  397. DXGASSERT(!(InternalGetDesc().Usage & D3DUSAGE_LOCK));
  398. return;
  399. } // CSurface::ReportWhyLockFailed
  400. #endif // DEBUG
  401. //=============================================
  402. // Methods for the CSysMemSurface class
  403. //=============================================
  404. #undef DPF_MODNAME
  405. #define DPF_MODNAME "CSysMemSurface::CSysMemSurface"
  406. CSysMemSurface::CSysMemSurface(CBaseDevice *pDevice,
  407. DWORD Width,
  408. DWORD Height,
  409. DWORD Usage,
  410. D3DFORMAT Format,
  411. REF_TYPE refType,
  412. HRESULT *phr
  413. ) :
  414. CSurface(pDevice,
  415. Width,
  416. Height,
  417. Usage,
  418. Format,
  419. refType,
  420. phr),
  421. m_rgbPixels(NULL)
  422. {
  423. if (FAILED(*phr))
  424. return;
  425. // Compute how much memory we need
  426. m_desc.Size = CPixel::ComputeSurfaceSize(Width,
  427. Height,
  428. Format);
  429. // Specify system memory
  430. m_desc.Pool = D3DPOOL_SYSTEMMEM;
  431. m_poolUser = D3DPOOL_SYSTEMMEM;
  432. // Specify no multisampling
  433. m_desc.MultiSampleType = D3DMULTISAMPLE_NONE;
  434. // Allocate the memory
  435. m_rgbPixels = new BYTE[m_desc.Size];
  436. if (m_rgbPixels == NULL)
  437. {
  438. DPF_ERR("Out of memory allocating surface.");
  439. *phr = E_OUTOFMEMORY;
  440. return;
  441. }
  442. // Figure out our pitch
  443. D3DLOCKED_RECT lock;
  444. CPixel::ComputeSurfaceOffset(&m_desc,
  445. m_rgbPixels,
  446. NULL, // pRect
  447. &lock);
  448. // Create a DDSURFACE and CreateSurfaceData object
  449. DDSURFACEINFO SurfInfo;
  450. ZeroMemory(&SurfInfo, sizeof(SurfInfo));
  451. // If we are not passed a handle, then we need to get one from
  452. // the DDI
  453. D3D8_CREATESURFACEDATA CreateSurfaceData;
  454. ZeroMemory(&CreateSurfaceData, sizeof(CreateSurfaceData));
  455. // Set up the basic information
  456. CreateSurfaceData.hDD = pDevice->GetHandle();
  457. CreateSurfaceData.pSList = &SurfInfo;
  458. CreateSurfaceData.dwSCnt = 1;
  459. // ImageSurface is an internal type so that the thunk layer
  460. // knows that it is not really a texture
  461. CreateSurfaceData.Type = D3DRTYPE_IMAGESURFACE;
  462. CreateSurfaceData.Pool = m_desc.Pool;
  463. CreateSurfaceData.dwUsage = m_desc.Usage;
  464. CreateSurfaceData.MultiSampleType = D3DMULTISAMPLE_NONE;
  465. CreateSurfaceData.Format = Format;
  466. // Specify the surface data
  467. SurfInfo.cpWidth = Width;
  468. SurfInfo.cpHeight = Height;
  469. SurfInfo.pbPixels = (BYTE*)lock.pBits;
  470. SurfInfo.iPitch = lock.Pitch;
  471. *phr = pDevice->GetHalCallbacks()->CreateSurface(&CreateSurfaceData);
  472. if (FAILED(*phr))
  473. {
  474. DPF_ERR("Failed to create sys-mem surface");
  475. return;
  476. }
  477. DXGASSERT(CreateSurfaceData.Pool == D3DPOOL_SYSTEMMEM);
  478. DXGASSERT(m_desc.Pool == D3DPOOL_SYSTEMMEM);
  479. DXGASSERT(m_poolUser == D3DPOOL_SYSTEMMEM);
  480. SetKernelHandle(SurfInfo.hKernelHandle);
  481. return;
  482. } // CSysMemSurface::CSysMemSurface
  483. #undef DPF_MODNAME
  484. #define DPF_MODNAME "CSysMemSurface::~CSysMemSurface"
  485. CSysMemSurface::~CSysMemSurface()
  486. {
  487. if (KernelHandle() != 0)
  488. {
  489. D3D8_DESTROYSURFACEDATA DestroyData;
  490. ZeroMemory(&DestroyData, sizeof DestroyData);
  491. DestroyData.hDD = Device()->GetHandle();
  492. DestroyData.hSurface = KernelHandle();
  493. Device()->GetHalCallbacks()->DestroySurface(&DestroyData);
  494. }
  495. // Free the memory we've allocated for the surface
  496. delete [] m_rgbPixels;
  497. return;
  498. } // CSysMemSurface::CSysMemSurface
  499. #undef DPF_MODNAME
  500. #define DPF_MODNAME "CSysMemSurface::LockRect"
  501. STDMETHODIMP CSysMemSurface::LockRect(D3DLOCKED_RECT *pLockedRectData,
  502. CONST RECT *pRect,
  503. DWORD dwFlags)
  504. {
  505. API_ENTER(Device());
  506. // If parameters are bad, then we should fail some stuff
  507. if (!VALID_WRITEPTR(pLockedRectData, sizeof(D3DLOCKED_RECT)))
  508. {
  509. DPF_ERR("bad pointer for m_pLockedRectData passed to LockRect for an ImageSurface.");
  510. return D3DERR_INVALIDCALL;
  511. }
  512. // Zero out returned data
  513. ZeroMemory(pLockedRectData, sizeof(D3DLOCKED_RECT));
  514. // Validate Rect
  515. if (pRect != NULL)
  516. {
  517. if (!CPixel::IsValidRect(m_desc.Format,
  518. m_desc.Width,
  519. m_desc.Height,
  520. pRect))
  521. {
  522. DPF_ERR("LockRect for a Surface failed");
  523. return D3DERR_INVALIDCALL;
  524. }
  525. }
  526. if (dwFlags & ~D3DLOCK_SURF_VALID)
  527. {
  528. DPF_ERR("Invalid dwFlags parameter passed to LockRect for an ImageSurface");
  529. DPF_EXPLAIN_BAD_LOCK_FLAGS(0, dwFlags & ~D3DLOCK_SURF_VALID);
  530. return D3DERR_INVALIDCALL;
  531. }
  532. // Can't lock surfaces that are not lockable
  533. if (!IsLockable())
  534. {
  535. ReportWhyLockFailed();
  536. return D3DERR_INVALIDCALL;
  537. }
  538. return InternalLockRect(pLockedRectData, pRect, dwFlags);
  539. } // LockRect
  540. #undef DPF_MODNAME
  541. #define DPF_MODNAME "CSysMemSurface::InternalLockRect"
  542. HRESULT CSysMemSurface::InternalLockRect(D3DLOCKED_RECT *pLockedRectData,
  543. CONST RECT *pRect,
  544. DWORD dwFlags)
  545. {
  546. // Only one lock outstanding at a time is supported
  547. // (even internally)
  548. if (m_isLocked)
  549. {
  550. DPF_ERR("LockRect failed on a surface; surface was already locked for an ImageSurface");
  551. return D3DERR_INVALIDCALL;
  552. }
  553. CPixel::ComputeSurfaceOffset(&m_desc,
  554. m_rgbPixels,
  555. pRect,
  556. pLockedRectData);
  557. // Mark ourselves as locked
  558. m_isLocked = TRUE;
  559. // Done
  560. return S_OK;
  561. } // InternalLockRect
  562. #undef DPF_MODNAME
  563. #define DPF_MODNAME "CSysMemSurface::UnlockRect"
  564. STDMETHODIMP CSysMemSurface::UnlockRect()
  565. {
  566. API_ENTER(Device());
  567. // If we aren't locked; then something is wrong
  568. if (!m_isLocked)
  569. {
  570. DPF_ERR("UnlockRect failed on a mip level; surface wasn't locked for an ImageSurface");
  571. return D3DERR_INVALIDCALL;
  572. }
  573. DXGASSERT(IsLockable());
  574. return InternalUnlockRect();
  575. } // UnlockRect
  576. #undef DPF_MODNAME
  577. #define DPF_MODNAME "CSysMemSurface::InternalUnlockRect"
  578. HRESULT CSysMemSurface::InternalUnlockRect()
  579. {
  580. DXGASSERT(m_isLocked);
  581. // Clear our locked state
  582. m_isLocked = FALSE;
  583. // Done
  584. return S_OK;
  585. } // InternalUnlockRect
  586. //=============================================
  587. // Methods for the CDriverSurface class
  588. //=============================================
  589. #undef DPF_MODNAME
  590. #define DPF_MODNAME "CDriverSurface::CDriverSurface"
  591. CDriverSurface::CDriverSurface(CBaseDevice *pDevice,
  592. DWORD Width,
  593. DWORD Height,
  594. DWORD Usage,
  595. D3DFORMAT UserFormat,
  596. D3DFORMAT RealFormat,
  597. D3DMULTISAMPLE_TYPE MultiSampleType,
  598. HANDLE hKernelHandle,
  599. REF_TYPE refType,
  600. HRESULT *phr
  601. ) :
  602. CSurface(pDevice,
  603. Width,
  604. Height,
  605. Usage,
  606. RealFormat,
  607. refType,
  608. phr)
  609. {
  610. // Even in failure paths, we need to remember
  611. // the passed in kernel handle so we can uniformly
  612. // free it
  613. if (hKernelHandle)
  614. SetKernelHandle(hKernelHandle);
  615. // On failure; just return here
  616. if (FAILED(*phr))
  617. {
  618. return;
  619. }
  620. // Remember User Format
  621. m_formatUser = UserFormat;
  622. // Remember multi-sample type
  623. m_desc.MultiSampleType = MultiSampleType;
  624. // Parameter check MS types; (since swapchan bypasses
  625. // the static Create; we need to parameter check here.)
  626. if (MultiSampleType != D3DMULTISAMPLE_NONE)
  627. {
  628. *phr = pDevice->CheckDeviceMultiSampleType(RealFormat,
  629. pDevice->SwapChain()->Windowed(),
  630. MultiSampleType);
  631. if (FAILED(*phr))
  632. {
  633. DPF_ERR("Unsupported multisample type requested. CreateRenderTarget/CreateDepthStencil failed.");
  634. return;
  635. }
  636. }
  637. // Back buffers are actually, for now, created just like other device
  638. // surfaces.
  639. // Otherwise, we need to call the driver
  640. // and get ourselves a handle.
  641. // Create a DDSURFACE and CreateSurfaceData object
  642. DDSURFACEINFO SurfInfo;
  643. ZeroMemory(&SurfInfo, sizeof(SurfInfo));
  644. if ((hKernelHandle == NULL) &&
  645. (!(pDevice->Enum()->NoDDrawSupport(pDevice->AdapterIndex())) ||
  646. !(D3DUSAGE_PRIMARYSURFACE & Usage))
  647. )
  648. {
  649. // If we are not passed a handle, then we need to get one from
  650. // the DDI
  651. D3D8_CREATESURFACEDATA CreateSurfaceData;
  652. ZeroMemory(&CreateSurfaceData, sizeof(CreateSurfaceData));
  653. // Set up the basic information
  654. CreateSurfaceData.hDD = pDevice->GetHandle();
  655. CreateSurfaceData.pSList = &SurfInfo;
  656. CreateSurfaceData.dwSCnt = 1;
  657. CreateSurfaceData.Type = D3DRTYPE_SURFACE;
  658. CreateSurfaceData.Pool = m_desc.Pool;
  659. CreateSurfaceData.dwUsage = m_desc.Usage;
  660. CreateSurfaceData.Format = RealFormat;
  661. CreateSurfaceData.MultiSampleType = MultiSampleType;
  662. // Specify the surface data
  663. SurfInfo.cpWidth = Width;
  664. SurfInfo.cpHeight = Height;
  665. *phr = pDevice->GetHalCallbacks()->CreateSurface(&CreateSurfaceData);
  666. if (FAILED(*phr))
  667. {
  668. DPF_ERR("Failed to create driver surface");
  669. return;
  670. }
  671. // Remember the kernel handle
  672. SetKernelHandle(SurfInfo.hKernelHandle);
  673. // Remember the actual pool
  674. m_desc.Pool = CreateSurfaceData.Pool;
  675. }
  676. else
  677. {
  678. // If the caller has already allocated this
  679. // then we assume that the pool is LocalVidMem
  680. SurfInfo.hKernelHandle = hKernelHandle;
  681. m_desc.Pool = D3DPOOL_LOCALVIDMEM;
  682. }
  683. m_desc.Size = SurfInfo.iPitch * Height;
  684. if (m_desc.MultiSampleType != D3DMULTISAMPLE_NONE)
  685. m_desc.Size *= (UINT)m_desc.MultiSampleType;
  686. return;
  687. } // CDriverSurface::CDriverSurface
  688. #undef DPF_MODNAME
  689. #define DPF_MODNAME "CDriverSurface::~CDriverSurface"
  690. CDriverSurface::~CDriverSurface()
  691. {
  692. if (KernelHandle() != 0)
  693. {
  694. D3D8_DESTROYSURFACEDATA DestroyData;
  695. ZeroMemory(&DestroyData, sizeof DestroyData);
  696. DestroyData.hDD = Device()->GetHandle();
  697. DestroyData.hSurface = KernelHandle();
  698. Device()->GetHalCallbacks()->DestroySurface(&DestroyData);
  699. }
  700. return;
  701. } // CDriverSurface::CDriverSurface
  702. #undef DPF_MODNAME
  703. #define DPF_MODNAME "CDriverSurface::LockRect"
  704. STDMETHODIMP CDriverSurface::LockRect(D3DLOCKED_RECT *pLockedRectData,
  705. CONST RECT *pRect,
  706. DWORD dwFlags)
  707. {
  708. API_ENTER(Device());
  709. // If parameters are bad, then we should fail some stuff
  710. if (!VALID_WRITEPTR(pLockedRectData, sizeof(D3DLOCKED_RECT)))
  711. {
  712. DPF_ERR("bad pointer for m_pLockedRectData passed to LockRect");
  713. return D3DERR_INVALIDCALL;
  714. }
  715. // Zero out returned data
  716. ZeroMemory(pLockedRectData, sizeof(D3DLOCKED_RECT));
  717. // Validate Rect
  718. if (pRect != NULL)
  719. {
  720. if (!CPixel::IsValidRect(m_desc.Format,
  721. m_desc.Width,
  722. m_desc.Height,
  723. pRect))
  724. {
  725. DPF_ERR("LockRect for a driver-allocated Surface failed");
  726. return D3DERR_INVALIDCALL;
  727. }
  728. }
  729. if (dwFlags & ~D3DLOCK_SURF_VALID)
  730. {
  731. DPF_ERR("Invalid dwFlags parameter passed to LockRect");
  732. DPF_EXPLAIN_BAD_LOCK_FLAGS(0, dwFlags & ~D3DLOCK_SURF_VALID);
  733. return D3DERR_INVALIDCALL;
  734. }
  735. // Can't lock surfaces that are not lockable
  736. if (!IsLockable())
  737. {
  738. ReportWhyLockFailed();
  739. return D3DERR_INVALIDCALL;
  740. }
  741. return InternalLockRect(pLockedRectData, pRect, dwFlags);
  742. }
  743. #undef DPF_MODNAME
  744. #define DPF_MODNAME "CDriverSurface::InternalLockRect"
  745. HRESULT CDriverSurface::InternalLockRect(D3DLOCKED_RECT *pLockedRectData,
  746. CONST RECT *pRect,
  747. DWORD dwFlags)
  748. {
  749. // Only one lock outstanding at a time is supported
  750. // (even internally)
  751. if (m_isLocked)
  752. {
  753. DPF_ERR("LockRect failed on a surface; surface was already locked.");
  754. return D3DERR_INVALIDCALL;
  755. }
  756. D3D8_LOCKDATA lockData;
  757. ZeroMemory(&lockData, sizeof lockData);
  758. lockData.hDD = Device()->GetHandle();
  759. lockData.hSurface = KernelHandle();
  760. lockData.dwFlags = dwFlags;
  761. if (pRect != NULL)
  762. {
  763. lockData.bHasRect = TRUE;
  764. lockData.rArea = *((RECTL *) pRect);
  765. }
  766. else
  767. {
  768. DXGASSERT(lockData.bHasRect == FALSE);
  769. }
  770. // Sync before allowing read or write access
  771. Sync();
  772. HRESULT hr = Device()->GetHalCallbacks()->Lock(&lockData);
  773. if (FAILED(hr))
  774. {
  775. DPF_ERR("Error trying to lock driver surface");
  776. return hr;
  777. }
  778. // Fill in the Locked_Rect fields
  779. if (CPixel::IsDXT(m_desc.Format))
  780. {
  781. // Pitch is the number of bytes for
  782. // one row's worth of blocks for linear formats
  783. // Start with our width
  784. UINT Width = m_desc.Width;
  785. // Convert to blocks
  786. Width = Width / 4;
  787. // At least one block
  788. if (Width == 0)
  789. Width = 1;
  790. if (m_desc.Format == D3DFMT_DXT1)
  791. {
  792. // 8 bytes per block for DXT1
  793. pLockedRectData->Pitch = Width * 8;
  794. }
  795. else
  796. {
  797. // 16 bytes per block for DXT2-5
  798. pLockedRectData->Pitch = Width * 16;
  799. }
  800. }
  801. else
  802. {
  803. pLockedRectData->Pitch = lockData.lPitch;
  804. }
  805. pLockedRectData->pBits = lockData.lpSurfData;
  806. // Mark ourselves as locked
  807. m_isLocked = TRUE;
  808. // Done
  809. return hr;
  810. } // LockRect
  811. #undef DPF_MODNAME
  812. #define DPF_MODNAME "CDriverSurface::UnlockRect"
  813. STDMETHODIMP CDriverSurface::UnlockRect()
  814. {
  815. API_ENTER(Device());
  816. // If we aren't locked; then something is wrong
  817. if (!m_isLocked)
  818. {
  819. DPF_ERR("UnlockRect failed; surface wasn't locked.");
  820. return D3DERR_INVALIDCALL;
  821. }
  822. return InternalUnlockRect();
  823. }
  824. #undef DPF_MODNAME
  825. #define DPF_MODNAME "CDriverSurface::InternalUnlockRect"
  826. HRESULT CDriverSurface::InternalUnlockRect()
  827. {
  828. DXGASSERT(m_isLocked);
  829. D3D8_UNLOCKDATA unlockData = {
  830. Device()->GetHandle(),
  831. KernelHandle()
  832. };
  833. HRESULT hr = Device()->GetHalCallbacks()->Unlock(&unlockData);
  834. if (SUCCEEDED(hr))
  835. {
  836. // Clear our locked state
  837. m_isLocked = FALSE;
  838. }
  839. // Done
  840. return hr;
  841. } // UnlockRect
  842. // End of file : surface.cpp