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.

1586 lines
44 KiB

  1. /***************************************************************************\
  2. *
  3. * File: Buffer.cpp
  4. *
  5. * Description:
  6. * Buffer.cpp implementats objects used in buffering operations, including
  7. * double buffering, DX-Transforms, etc. These objects are maintained by a
  8. * central BufferManager that is available process-wide.
  9. *
  10. *
  11. * History:
  12. * 1/18/2000: JStall: Created
  13. *
  14. * Copyright (C) 2000 by Microsoft Corporation. All rights reserved.
  15. *
  16. \***************************************************************************/
  17. #include "stdafx.h"
  18. #include "Services.h"
  19. #include "Buffer.h"
  20. #include "FastDib.h"
  21. #include "GdiCache.h"
  22. #include "OSAL.h"
  23. #include "ResourceManager.h"
  24. #include "Surface.h"
  25. #include "Context.h"
  26. #define DEBUG_COPYTOCLIPBOARD 0 // Copy buffer to clipboard
  27. #define DEBUG_DUMPREGION 0 // Dump regions
  28. #if DEBUG_DUMPREGION
  29. #define DUMP_REGION(name, rgn)
  30. DumpRegion(name, rgn)
  31. void
  32. DumpRegion(LPCTSTR pszName, HRGN hrgn)
  33. {
  34. RECT rc;
  35. int nType = GetRgnBox(hrgn, &rc);
  36. switch (nType)
  37. {
  38. case NULLREGION:
  39. Trace("Null region %s = 0x%p\n", pszName, hrgn);
  40. break;
  41. case SIMPLEREGION:
  42. Trace("Simple region %s = 0x%p (%d,%d)-(%d,%d)\n", pszName, hrgn, rc.left, rc.top, rc.right, rc.bottom);
  43. break;
  44. case COMPLEXREGION:
  45. Trace("Complex region %s = 0x%p (%d,%d)-(%d,%d)\n", pszName, hrgn, rc.left, rc.top, rc.right, rc.bottom);
  46. break;
  47. default:
  48. Trace("Illegal region %s = 0x%p\n", pszName, hrgn);
  49. }
  50. }
  51. #else
  52. #define DUMP_REGION(name, rgn) ((void) 0)
  53. #endif
  54. /***************************************************************************\
  55. *****************************************************************************
  56. *
  57. * class BufferManager
  58. *
  59. *****************************************************************************
  60. \***************************************************************************/
  61. //------------------------------------------------------------------------------
  62. BufferManager::BufferManager()
  63. {
  64. #if ENABLE_DUMPCACHESTATS
  65. m_cacheDCBmpCached.SetName("DCBmpCached");
  66. m_cacheGpBmpCached.SetName("GpBmpCached");
  67. #endif
  68. }
  69. //------------------------------------------------------------------------------
  70. BufferManager::~BufferManager()
  71. {
  72. if (m_pbufGpBmpShared != NULL) {
  73. ProcessDelete(GpBmpBuffer, m_pbufGpBmpShared);
  74. m_pbufGpBmpShared = NULL;
  75. }
  76. AssertMsg(m_pbufTrx == NULL, "Ensure all buffers have been destroyed");
  77. }
  78. //------------------------------------------------------------------------------
  79. void
  80. BufferManager::Destroy()
  81. {
  82. RemoveAllTrxBuffers();
  83. m_cacheDCBmpCached.Destroy();
  84. m_cacheGpBmpCached.Destroy();
  85. }
  86. /***************************************************************************\
  87. *
  88. * BufferManager::BeginTransition
  89. *
  90. * BeginTransition() finds a TrxBuffer to be used for a new Transition. If
  91. * no cached, correct-format TrxBuffers are available, a new TrxBuffer is
  92. * created. When the caller is finished with the buffer, it should be
  93. * returned with EndTransition().
  94. *
  95. \***************************************************************************/
  96. HRESULT
  97. BufferManager::BeginTransition(
  98. IN SIZE sizePxl, // Minimum size of each buffer, in pixels
  99. IN int cSurfaces, // Number of buffers
  100. IN BOOL fExactSize, // Buffer size must be an exact match
  101. OUT TrxBuffer ** ppbuf) // Transition Buffer
  102. {
  103. AssertMsg((sizePxl.cx > 0) && (sizePxl.cy > 0) && (sizePxl.cx < 2000) && (sizePxl.cy < 2000),
  104. "Ensure reasonable buffer size");
  105. AssertMsg((cSurfaces > 0) && (cSurfaces <= 3), "Ensure reasonable number of buffers");
  106. AssertWritePtr(ppbuf);
  107. HRESULT hr;
  108. *ppbuf = NULL;
  109. //
  110. // Part 1: Check if an existing buffer is large enough / the correct size.
  111. //
  112. if (m_pbufTrx != NULL) {
  113. SIZE sizeExistPxl = m_pbufTrx->GetSize();
  114. if (fExactSize) {
  115. if ((sizePxl.cx != sizeExistPxl.cx) || (sizePxl.cy != sizeExistPxl.cy)) {
  116. ClientDelete(TrxBuffer, m_pbufTrx);
  117. m_pbufTrx = NULL;
  118. }
  119. } else {
  120. if ((sizePxl.cx > sizeExistPxl.cx) || (sizePxl.cy > sizeExistPxl.cy)) {
  121. ClientDelete(TrxBuffer, m_pbufTrx);
  122. m_pbufTrx = NULL;
  123. }
  124. }
  125. }
  126. //
  127. // Part 2: Create a new buffer, if needed
  128. //
  129. if (m_pbufTrx == NULL) {
  130. hr = TrxBuffer::Build(sizePxl, cSurfaces, &m_pbufTrx);
  131. if (FAILED(hr)) {
  132. return hr;
  133. }
  134. }
  135. AssertMsg(!m_pbufTrx->GetInUse(), "Ensure the buffer isn't already in use");
  136. m_pbufTrx->SetInUse(TRUE);
  137. *ppbuf = m_pbufTrx;
  138. return S_OK;
  139. }
  140. /***************************************************************************\
  141. *
  142. * BufferManager::EndTransition
  143. *
  144. * EndTransition() is called to return a TrxBuffer to the BufferManager
  145. * after use.
  146. *
  147. \***************************************************************************/
  148. void
  149. BufferManager::EndTransition(
  150. IN TrxBuffer * pbufTrx, // TrxBuffer being returned
  151. IN BOOL fCache) // Add the buffer to the available cache
  152. {
  153. AssertMsg(m_pbufTrx->GetInUse(), "Ensure the buffer was being used");
  154. AssertMsg(m_pbufTrx == pbufTrx, "Ensure correct buffer");
  155. pbufTrx->SetInUse(FALSE);
  156. if (!fCache) {
  157. //
  158. // For now, since DxXForm's must always be the correct size, there
  159. // isn't much point in caching them and we can reclaim the memory. If
  160. // this changes, reinvestigate caching them.
  161. //
  162. ClientDelete(TrxBuffer, m_pbufTrx);
  163. m_pbufTrx = NULL;
  164. }
  165. }
  166. /***************************************************************************\
  167. *
  168. * BufferManager::FlushTrxBuffers
  169. *
  170. * FlushTrxBuffers() is called when all TrxBuffers must be forceably released,
  171. * for example when DXTX shuts down.
  172. *
  173. \***************************************************************************/
  174. void
  175. BufferManager::FlushTrxBuffers()
  176. {
  177. RemoveAllTrxBuffers();
  178. }
  179. /***************************************************************************\
  180. *
  181. * BufferManager::RemoveAllTrxBuffers
  182. *
  183. * RemoveAllTrxBuffers() cleans up all resources associated with all
  184. * TrxBuffers.
  185. *
  186. \***************************************************************************/
  187. void
  188. BufferManager::RemoveAllTrxBuffers()
  189. {
  190. if (m_pbufTrx != NULL) {
  191. AssertMsg(!m_pbufTrx->GetInUse(), "Buffer should not be in use");
  192. ClientDelete(TrxBuffer, m_pbufTrx);
  193. m_pbufTrx = NULL;
  194. }
  195. }
  196. //------------------------------------------------------------------------------
  197. HRESULT
  198. BufferManager::GetCachedBuffer(DuSurface::EType type, BmpBuffer ** ppbuf)
  199. {
  200. AssertWritePtr(ppbuf);
  201. switch (type)
  202. {
  203. case DuSurface::stDC:
  204. if ((*ppbuf = m_cacheDCBmpCached.Get()) == NULL) {
  205. return E_OUTOFMEMORY;
  206. }
  207. break;
  208. case DuSurface::stGdiPlus:
  209. if ((*ppbuf = m_cacheGpBmpCached.Get()) == NULL) {
  210. return E_OUTOFMEMORY;
  211. }
  212. break;
  213. default:
  214. AssertMsg(0, "Unknown surface type");
  215. return E_NOTIMPL;
  216. }
  217. return S_OK;
  218. }
  219. //------------------------------------------------------------------------------
  220. void
  221. BufferManager::ReleaseCachedBuffer(BmpBuffer * pbuf)
  222. {
  223. AssertReadPtr(pbuf);
  224. switch (pbuf->GetType())
  225. {
  226. case DuSurface::stDC:
  227. m_cacheDCBmpCached.Release(static_cast<DCBmpBuffer*>(pbuf));
  228. break;
  229. case DuSurface::stGdiPlus:
  230. m_cacheGpBmpCached.Release(static_cast<GpBmpBuffer*>(pbuf));
  231. break;
  232. default:
  233. AssertMsg(0, "Unknown surface type");
  234. }
  235. }
  236. /***************************************************************************\
  237. *****************************************************************************
  238. *
  239. * class DCBmpBuffer
  240. *
  241. *****************************************************************************
  242. \***************************************************************************/
  243. /***************************************************************************\
  244. *
  245. * DCBmpBuffer::DCBmpBuffer
  246. *
  247. * DCBmpBuffer() fully initializes a new DCBmpBuffer object.
  248. *
  249. \***************************************************************************/
  250. DCBmpBuffer::DCBmpBuffer()
  251. {
  252. }
  253. /***************************************************************************\
  254. *
  255. * DCBmpBuffer::~DCBmpBuffer
  256. *
  257. * ~DCBmpBuffer() cleans up all resources associated with the buffer.
  258. *
  259. \***************************************************************************/
  260. DCBmpBuffer::~DCBmpBuffer()
  261. {
  262. EndDraw(FALSE);
  263. FreeBitmap();
  264. }
  265. /***************************************************************************\
  266. *
  267. * DCBmpBuffer::BeginDraw
  268. *
  269. * BeginDraw() sets up the DCBmpBuffer to begin a drawing cycle. The final
  270. * destination HDC and size are passed in, and a new "temporary" HDC is
  271. * returned out.
  272. *
  273. \***************************************************************************/
  274. HRESULT
  275. DCBmpBuffer::BeginDraw(
  276. IN DuSurface * psrfDraw, // Final destination Surface
  277. IN const RECT * prcInvalid, // Invalid area of destination
  278. IN UINT nCmd, // How the buffer is to be used
  279. OUT DuSurface ** ppsrfBuffer) // Surface of buffer or NULL if not needed
  280. {
  281. AssertMsg(prcInvalid != NULL, "Must specify a valid area");
  282. AssertWritePtr(ppsrfBuffer);
  283. *ppsrfBuffer = NULL;
  284. HDC hdcDraw = CastHDC(psrfDraw);
  285. //
  286. // Ensure not in the middle of drawing.
  287. //
  288. EndDraw(FALSE);
  289. //
  290. // Determine the size of the area to draw and ensure that the buffer is
  291. // large enough.
  292. //
  293. SIZE sizeBmp;
  294. sizeBmp.cx = prcInvalid->right - prcInvalid->left;
  295. sizeBmp.cy = prcInvalid->bottom - prcInvalid->top;
  296. if ((sizeBmp.cx == 0) || (sizeBmp.cy == 0)) {
  297. //
  298. // Nothing to draw / buffer, so just let drawing occur in the given
  299. // buffer. Signal this by returning NULL so that the caller knows
  300. // not to create extra, unnecessary data.
  301. //
  302. AssertMsg(!m_fChangeOrg, "Ensure valid state");
  303. AssertMsg(m_hdcDraw == NULL, "Ensure valid state");
  304. return S_OK;
  305. }
  306. if ((sizeBmp.cx > m_sizeBmp.cx) || (sizeBmp.cy > m_sizeBmp.cy)) {
  307. //
  308. // When allocating a new bitmap, make it large enough to consume the
  309. // existing bitmap. This helps avoid swapping between two different
  310. // bitmaps.
  311. //
  312. // TODO: Need to add code into the BufferManager that maintains multiple
  313. // bitmaps of different sizes so that we don't get many rarely-used,
  314. // giant bitmaps.
  315. //
  316. if (!AllocBitmap(hdcDraw,
  317. max(sizeBmp.cx, m_sizeBmp.cx),
  318. max(sizeBmp.cy, m_sizeBmp.cy))) {
  319. return DU_E_OUTOFGDIRESOURCES;
  320. }
  321. }
  322. AssertMsg((prcInvalid->right >= prcInvalid->left) &&
  323. (prcInvalid->bottom >= prcInvalid->top), "Check normalized");
  324. //
  325. // Setup the drawing
  326. //
  327. m_hdcBitmap = CreateCompatibleDC(hdcDraw);
  328. if (m_hdcBitmap == NULL) {
  329. return DU_E_OUTOFGDIRESOURCES;
  330. }
  331. if (SupportXForm()) {
  332. m_nOldGfxMode = SetGraphicsMode(m_hdcBitmap, GM_ADVANCED);
  333. }
  334. m_hbmpOld = (HBITMAP) SelectObject(m_hdcBitmap, m_hbmpBuffer);
  335. HPALETTE hpal = (HPALETTE) GetCurrentObject(hdcDraw, OBJ_PAL);
  336. if (hpal != NULL) {
  337. m_hpalOld = SelectPalette(m_hdcBitmap, hpal, FALSE);
  338. } else {
  339. m_hpalOld = NULL;
  340. }
  341. m_hdcDraw = hdcDraw;
  342. m_ptDraw.x = prcInvalid->left;
  343. m_ptDraw.y = prcInvalid->top;
  344. m_sizeDraw.cx = prcInvalid->right - prcInvalid->left;
  345. m_sizeDraw.cy = prcInvalid->bottom - prcInvalid->top;
  346. m_nCmd = nCmd;
  347. if ((m_ptDraw.x != 0) || (m_ptDraw.y != 0)) {
  348. /*
  349. * The buffer size is minimized to the painting area, so we need to
  350. * setup some stuff to "fake" GDI and do the right thing:
  351. * 1. Change the brush origin so that it the end result appears
  352. * consistent
  353. * 2. Change the window origin so that the drawing is in the upper
  354. * left corner.
  355. *
  356. * We will set this back when we are done drawing.
  357. */
  358. POINT ptBrushOrg;
  359. GetBrushOrgEx(m_hdcBitmap, &ptBrushOrg);
  360. SetBrushOrgEx(m_hdcBitmap,
  361. ptBrushOrg.x - m_ptDraw.x, ptBrushOrg.y - m_ptDraw.y,
  362. &m_ptOldBrushOrg);
  363. m_fChangeOrg = TRUE;
  364. } else {
  365. m_fChangeOrg = FALSE;
  366. }
  367. OS()->PushXForm(m_hdcBitmap, &m_xfOldBitmap);
  368. OS()->PushXForm(m_hdcDraw, &m_xfOldDraw);
  369. m_fChangeXF = TRUE;
  370. m_fClip = FALSE;
  371. #if DEBUG_COPYTOCLIPBOARD
  372. #if DBG
  373. RECT rcFill;
  374. rcFill.left = 0;
  375. rcFill.top = 0;
  376. rcFill.right = m_sizeBmp.cx;
  377. rcFill.bottom = m_sizeBmp.cy;
  378. FillRect(m_hdcBitmap, &rcFill, GetStdColorBrushI(SC_Plum));
  379. #endif // DBG
  380. #endif // DEBUG_COPYTOCLIPBOARD
  381. //
  382. // Setup the buffer as necessary
  383. //
  384. if (m_nCmd == BmpBuffer::dcCopyBkgnd) {
  385. //
  386. // Copy the destination to the buffer to be used as a background.
  387. //
  388. BitBlt(m_hdcBitmap, 0, 0, m_sizeDraw.cx, m_sizeDraw.cy,
  389. m_hdcDraw, m_ptDraw.x, m_ptDraw.y, SRCCOPY);
  390. }
  391. //
  392. // Clip drawing in the buffer to the actual used part of the buffer. Since
  393. // this is the only part that will be copied over, we don't want to draw
  394. // outside of this area since it slows down performance.
  395. //
  396. GdiCache * pgc = GetGdiCache();
  397. HRGN hrgnClip = pgc->GetTempRgn();
  398. if (hrgnClip != NULL) {
  399. SetRectRgn(hrgnClip, 0, 0, m_sizeDraw.cx, m_sizeDraw.cy);
  400. ExtSelectClipRgn(m_hdcBitmap, hrgnClip, RGN_COPY);
  401. //
  402. // If the destination surface had a clipping region, we need to
  403. // propagate it over to the buffer.
  404. //
  405. HRGN hrgnDraw = pgc->GetTempRgn();
  406. if (hrgnDraw != NULL) {
  407. if (GetClipRgn(m_hdcDraw, hrgnDraw) == 1) {
  408. OffsetRgn(hrgnDraw, -m_ptDraw.x, -m_ptDraw.y);
  409. ExtSelectClipRgn(m_hdcBitmap, hrgnDraw, RGN_AND);
  410. }
  411. pgc->ReleaseTempRgn(hrgnDraw);
  412. }
  413. pgc->ReleaseTempRgn(hrgnClip);
  414. }
  415. //
  416. // Create a new Surface to contain the buffer.
  417. //
  418. return DuDCSurface::Build(m_hdcBitmap, (DuDCSurface **) ppsrfBuffer);
  419. }
  420. /***************************************************************************\
  421. *
  422. * DCBmpBuffer::Fill
  423. *
  424. * TOOD:
  425. *
  426. \***************************************************************************/
  427. void
  428. DCBmpBuffer::Fill(COLORREF cr)
  429. {
  430. HBRUSH hbr = CreateSolidBrush(cr);
  431. RECT rcFill;
  432. rcFill.left = 0;
  433. rcFill.top = 0;
  434. rcFill.right = m_sizeDraw.cx;
  435. rcFill.bottom = m_sizeDraw.cy;
  436. FillRect(m_hdcBitmap, &rcFill, hbr);
  437. DeleteObject(hbr);
  438. }
  439. /***************************************************************************\
  440. *
  441. * DCBmpBuffer::PreEndDraw
  442. *
  443. * PreEndDraw() finished a drawing cycle that was previously started with
  444. * BeginDraw(). If fCommit is TRUE, the temporary buffer is prepared to be
  445. * copied to the final destination. The called MUST also call EndDraw()
  446. * to properly end the drawing cycle.
  447. *
  448. \***************************************************************************/
  449. void
  450. DCBmpBuffer::PreEndDraw(
  451. IN BOOL fCommit) // Copy to final destination
  452. {
  453. //
  454. // Resource the destination and buffer surfaces back to where they started.
  455. // This is important because they will be changed during the drawing.
  456. //
  457. if (m_fChangeXF) {
  458. OS()->PopXForm(m_hdcBitmap, &m_xfOldBitmap);
  459. OS()->PopXForm(m_hdcDraw, &m_xfOldDraw);
  460. m_fChangeXF = FALSE;
  461. }
  462. if (m_fChangeOrg) {
  463. SetBrushOrgEx(m_hdcBitmap, m_ptOldBrushOrg.x, m_ptOldBrushOrg.y, NULL);
  464. m_fChangeOrg = FALSE;
  465. }
  466. if ((fCommit) && (m_hdcDraw != NULL)) {
  467. //
  468. // Setup any clipping region needed to limit the buffer to an area
  469. // in the destination surface.
  470. //
  471. if (m_fClip) {
  472. AssertMsg(m_hrgnDrawClip != NULL, "Must have valid region");
  473. AssertMsg(m_hrgnDrawOld == NULL, "Ensure no outstanding region");
  474. m_hrgnDrawOld = GetGdiCache()->GetTempRgn();
  475. if (m_hrgnDrawOld != NULL) {
  476. DUMP_REGION("m_hrgnDrawOld", m_hrgnDrawOld);
  477. if (GetClipRgn(m_hdcDraw, m_hrgnDrawOld) <= 0) {
  478. GetGdiCache()->ReleaseTempRgn(m_hrgnDrawOld);
  479. m_hrgnDrawOld = NULL;
  480. }
  481. DUMP_REGION("m_hrgnDrawClip", m_hrgnDrawClip);
  482. ExtSelectClipRgn(m_hdcDraw, m_hrgnDrawClip, RGN_COPY);
  483. }
  484. }
  485. }
  486. }
  487. /***************************************************************************\
  488. *
  489. * DCBmpBuffer::EndDraw
  490. *
  491. * EndDraw() presents a drawing cycle that was previously started with
  492. * BeginDraw(). If fCommit is TRUE, the temporary buffer is copied to the
  493. * final destination. The caller MUST first call PreEndDraw() to properly
  494. * setup any state needed to end the drawing cycle.
  495. *
  496. \***************************************************************************/
  497. void
  498. DCBmpBuffer::EndDraw(
  499. IN BOOL fCommit, // Copy to final destination
  500. IN BYTE bAlphaLevel, // General alpha level
  501. IN BYTE bAlphaFormat) // Pixel alpha format
  502. {
  503. if ((fCommit) && (m_hdcDraw != NULL)) {
  504. //
  505. // Copy the bits over
  506. //
  507. if (bAlphaLevel == BLEND_OPAQUE) {
  508. BitBlt(m_hdcDraw, m_ptDraw.x, m_ptDraw.y, m_sizeDraw.cx, m_sizeDraw.cy,
  509. m_hdcBitmap, 0, 0, SRCCOPY);
  510. } else {
  511. BLENDFUNCTION bf;
  512. bf.AlphaFormat = bAlphaFormat;
  513. bf.BlendFlags = 0;
  514. bf.BlendOp = AC_SRC_OVER;
  515. bf.SourceConstantAlpha = bAlphaLevel;
  516. AlphaBlend(m_hdcDraw, m_ptDraw.x, m_ptDraw.y, m_sizeDraw.cx, m_sizeDraw.cy,
  517. m_hdcBitmap, 0, 0, m_sizeDraw.cx, m_sizeDraw.cy, bf);
  518. }
  519. }
  520. }
  521. /***************************************************************************\
  522. *
  523. * DCBmpBuffer::PostEndDraw
  524. *
  525. * PostEndDraw() finished a drawing cycle that was previously started with
  526. * BeginDraw(). After this function finishes, the buffer is ready to be used
  527. * again.
  528. *
  529. \***************************************************************************/
  530. void
  531. DCBmpBuffer::PostEndDraw()
  532. {
  533. if (m_hdcDraw != NULL) {
  534. //
  535. // Cleanup the temporary clipping region. This is VERY important to
  536. // do so that the destination surface can continued to be drawn on.
  537. // (For example, more Gadget siblings...)
  538. //
  539. if (m_fClip) {
  540. //
  541. // NOTE: m_hrgnDrawOld may be NULL if there was no previous clipping
  542. // region.
  543. //
  544. ExtSelectClipRgn(m_hdcDraw, m_hrgnDrawOld, RGN_COPY);
  545. if (m_hrgnDrawOld != NULL) {
  546. GetGdiCache()->ReleaseTempRgn(m_hrgnDrawOld);
  547. m_hrgnDrawOld = NULL;
  548. }
  549. }
  550. }
  551. //
  552. // Cleanup the clipping region
  553. //
  554. if (m_fClip) {
  555. AssertMsg(m_hrgnDrawClip != NULL, "Must have a valid region");
  556. GetGdiCache()->ReleaseTempRgn(m_hrgnDrawClip);
  557. m_hrgnDrawClip = NULL;
  558. m_fClip = FALSE;
  559. }
  560. AssertMsg(m_hrgnDrawClip == NULL, "Should no longer have a clipping region");
  561. //
  562. // Cleanup associated resources
  563. //
  564. if (m_hdcBitmap != NULL) {
  565. if (m_hpalOld != NULL) {
  566. SelectPalette(m_hdcBitmap, m_hpalOld, TRUE);
  567. m_hpalOld = NULL;
  568. }
  569. SelectObject(m_hdcBitmap, m_hbmpOld);
  570. if (SupportXForm()) {
  571. SetGraphicsMode(m_hdcBitmap, m_nOldGfxMode);
  572. }
  573. DeleteDC(m_hdcBitmap);
  574. m_hdcBitmap = NULL;
  575. #if DEBUG_COPYTOCLIPBOARD
  576. #if DBG
  577. if (OpenClipboard(NULL)) {
  578. EmptyClipboard();
  579. HBITMAP hbmpCopy = (HBITMAP) CopyImage(m_hbmpBuffer, IMAGE_BITMAP, 0, 0, 0);
  580. HDC hdc = GetGdiCache()->GetCompatibleDC();
  581. HBITMAP hbmpOld = (HBITMAP) SelectObject(hdc, hbmpCopy);
  582. // Outline the actual drawn area
  583. RECT rcDraw;
  584. rcDraw.left = 0;
  585. rcDraw.top = 0;
  586. rcDraw.right = m_sizeDraw.cx;
  587. rcDraw.bottom = m_sizeDraw.cy;
  588. GdDrawOutlineRect(hdc, &rcDraw, GetStdColorBrushI(SC_Crimson), 1);
  589. SelectObject(hdc, hbmpOld);
  590. GetGdiCache()->ReleaseCompatibleDC(hdc);
  591. SetClipboardData(CF_BITMAP, hbmpCopy);
  592. CloseClipboard();
  593. }
  594. #endif // DBG
  595. #endif // DEBUG_COPYTOCLIPBOARD
  596. }
  597. m_hdcDraw = NULL;
  598. m_hbmpOld = NULL;
  599. if (GetContext()->GetPerfMode() == IGPM_SIZE) {
  600. FreeBitmap();
  601. }
  602. }
  603. //------------------------------------------------------------------------------
  604. void
  605. DCBmpBuffer::SetupClipRgn()
  606. {
  607. AssertMsg(!m_fClip, "Only should setup clip region once per cycle");
  608. AssertMsg(m_hrgnDrawClip == NULL, "Should not already have a clip region");
  609. m_hrgnDrawClip = GetGdiCache()->GetTempRgn();
  610. if (m_hrgnDrawClip == NULL) {
  611. return;
  612. }
  613. //
  614. // NOTE: GetClipRgn() does NOT return the standard region return values.
  615. //
  616. if (GetClipRgn(m_hdcBitmap, m_hrgnDrawClip) == 1) {
  617. DUMP_REGION("m_hrgnDrawClip", m_hrgnDrawClip);
  618. OffsetRgn(m_hrgnDrawClip, m_ptDraw.x, m_ptDraw.y);
  619. m_fClip = TRUE;
  620. } else {
  621. GetGdiCache()->ReleaseTempRgn(m_hrgnDrawClip);
  622. m_hrgnDrawClip = NULL;
  623. }
  624. }
  625. /***************************************************************************\
  626. *
  627. * DCBmpBuffer::InUse
  628. *
  629. * InUse() returns if the DCBmpBuffer is currently in a draw cycle started from
  630. * BeginDraw().
  631. *
  632. \***************************************************************************/
  633. BOOL
  634. DCBmpBuffer::InUse() const
  635. {
  636. return m_hdcDraw != NULL;
  637. }
  638. /***************************************************************************\
  639. *
  640. * DCBmpBuffer::AllocBitmap
  641. *
  642. * AllocBitmap() allocates the internal bitmap buffer that is used to
  643. * temporarily draw into. This bitmap will be compatible with the final
  644. * destination surface.
  645. *
  646. \***************************************************************************/
  647. BOOL
  648. DCBmpBuffer::AllocBitmap(
  649. IN HDC hdcDraw, // Final destination HDC
  650. IN int cx, // Width of new bitmap
  651. IN int cy) // Height of new bitmap
  652. {
  653. FreeBitmap();
  654. //
  655. // When allocating a bitmap, round up to a multiple of 16 x 16. This helps
  656. // to reduce unnecessary reallocations because we grew by one or two pixels.
  657. //
  658. cx = ((cx + 15) / 16) * 16;
  659. cy = ((cy + 15) / 16) * 16;
  660. //
  661. // Allocate the bitmap
  662. //
  663. #if 0
  664. m_hbmpBuffer = CreateCompatibleBitmap(hdcDraw, cx, cy);
  665. #else
  666. m_hbmpBuffer = ResourceManager::RequestCreateCompatibleBitmap(hdcDraw, cx, cy);
  667. #endif
  668. if (m_hbmpBuffer == NULL) {
  669. return FALSE;
  670. }
  671. m_sizeBmp.cx = cx;
  672. m_sizeBmp.cy = cy;
  673. return TRUE;
  674. }
  675. /***************************************************************************\
  676. *
  677. * DCBmpBuffer::FreeBitmap
  678. *
  679. * FreeBitmap() cleans up allocated resources.
  680. *
  681. \***************************************************************************/
  682. void
  683. DCBmpBuffer::FreeBitmap()
  684. {
  685. if (m_hbmpBuffer != NULL) {
  686. DeleteObject(m_hbmpBuffer);
  687. m_hbmpBuffer = NULL;
  688. m_sizeBmp.cx = 0;
  689. m_sizeBmp.cy = 0;
  690. }
  691. }
  692. /***************************************************************************\
  693. *****************************************************************************
  694. *
  695. * class GpBmpBuffer
  696. *
  697. *****************************************************************************
  698. \***************************************************************************/
  699. /***************************************************************************\
  700. *
  701. * GpBmpBuffer::GpBmpBuffer
  702. *
  703. * GpBmpBuffer() fully initializes a new GpBmpBuffer object.
  704. *
  705. \***************************************************************************/
  706. GpBmpBuffer::GpBmpBuffer()
  707. {
  708. }
  709. /***************************************************************************\
  710. *
  711. * GpBmpBuffer::~GpBmpBuffer
  712. *
  713. * ~GpBmpBuffer() cleans up all resources associated with the buffer.
  714. *
  715. \***************************************************************************/
  716. GpBmpBuffer::~GpBmpBuffer()
  717. {
  718. EndDraw(FALSE);
  719. FreeBitmap();
  720. }
  721. /***************************************************************************\
  722. *
  723. * GpBmpBuffer::BeginDraw
  724. *
  725. * BeginDraw() sets up the GpBmpBuffer to begin a drawing cycle. The final
  726. * destination HDC and size are passed in, and a new "temporary" HDC is
  727. * returned out.
  728. *
  729. \***************************************************************************/
  730. HRESULT
  731. GpBmpBuffer::BeginDraw(
  732. IN DuSurface * psrfDraw, // Final destination Surface
  733. IN const RECT * prcInvalid, // Invalid area of destination
  734. IN UINT nCmd, // How the buffer is to be used
  735. OUT DuSurface ** ppsrfBuffer) // Surface of buffer or NULL if not needed
  736. {
  737. AssertMsg(prcInvalid != NULL, "Must specify a valid area");
  738. AssertWritePtr(ppsrfBuffer);
  739. *ppsrfBuffer = NULL;
  740. Gdiplus::Graphics * pgpgrDraw = CastGraphics(psrfDraw);
  741. if (!ResourceManager::IsInitGdiPlus()) {
  742. return DU_E_NOTINITIALIZED;
  743. }
  744. //
  745. // Ensure not in the middle of drawing.
  746. //
  747. EndDraw(FALSE);
  748. //
  749. // Determine the size of the area to draw and ensure that the buffer is
  750. // large enough.
  751. //
  752. SIZE sizeBmp;
  753. sizeBmp.cx = prcInvalid->right - prcInvalid->left;
  754. sizeBmp.cy = prcInvalid->bottom - prcInvalid->top;
  755. if ((sizeBmp.cx == 0) || (sizeBmp.cy == 0)) {
  756. //
  757. // Nothing to draw / buffer, so just let drawing occur in the given
  758. // buffer. Signal this by returning NULL so that the caller knows
  759. // not to create extra, unnecessary data.
  760. //
  761. AssertMsg(!m_fChangeOrg, "Ensure valid state");
  762. AssertMsg(m_pgpgrDraw == NULL, "Ensure valid state");
  763. return S_OK;
  764. }
  765. if ((sizeBmp.cx > m_sizeBmp.cx) || (sizeBmp.cy > m_sizeBmp.cy)) {
  766. //
  767. // When allocating a new bitmap, make it large enough to consume the
  768. // existing bitmap. This helps avoid swapping between two different
  769. // bitmaps.
  770. //
  771. // TODO: Need to add code into the BufferManager that maintains multiple
  772. // bitmaps of different sizes so that we don't get many rarely-used,
  773. // giant bitmaps.
  774. //
  775. if (!AllocBitmap(pgpgrDraw,
  776. max(sizeBmp.cx, m_sizeBmp.cx),
  777. max(sizeBmp.cy, m_sizeBmp.cy))) {
  778. return DU_E_OUTOFGDIRESOURCES;
  779. }
  780. }
  781. AssertMsg((prcInvalid->right >= prcInvalid->left) &&
  782. (prcInvalid->bottom >= prcInvalid->top), "Check normalized");
  783. //
  784. // Setup the drawing
  785. //
  786. #if ENABLE_USEFASTDIB
  787. HDC hdcTemp = GetGdiCache()->GetTempDC();
  788. m_hdcBitmap = CreateCompatibleDC(hdcTemp);
  789. GetGdiCache()->ReleaseTempDC(hdcTemp);
  790. if (m_hdcBitmap == NULL) {
  791. return DU_E_OUTOFGDIRESOURCES;
  792. }
  793. m_hbmpOld = (HBITMAP) SelectObject(m_hdcBitmap, m_hbmpBuffer);
  794. m_pgpgrBitmap = new Gdiplus::Graphics(m_hdcBitmap);
  795. if (m_pgpgrBitmap == NULL) {
  796. return DU_E_OUTOFGDIRESOURCES;
  797. }
  798. #else
  799. m_pgpgrBitmap = new Gdiplus::Graphics(m_pgpbmpBuffer);
  800. if (m_pgpgrBitmap == NULL) {
  801. return DU_E_OUTOFGDIRESOURCES;
  802. }
  803. #endif
  804. #if 0
  805. m_pgpgrBitmap->SetAlphaLevel(pgpgrDraw->GetAlphaLevel());
  806. #endif
  807. m_pgpgrBitmap->SetCompositingMode(pgpgrDraw->GetCompositingMode());
  808. m_pgpgrBitmap->SetCompositingQuality(pgpgrDraw->GetCompositingQuality());
  809. m_pgpgrBitmap->SetInterpolationMode(pgpgrDraw->GetInterpolationMode());
  810. m_pgpgrBitmap->SetSmoothingMode(pgpgrDraw->GetSmoothingMode());
  811. m_pgpgrBitmap->SetPixelOffsetMode(pgpgrDraw->GetPixelOffsetMode());
  812. m_pgpgrBitmap->SetTextContrast(pgpgrDraw->GetTextContrast());
  813. m_pgpgrBitmap->SetTextRenderingHint(pgpgrDraw->GetTextRenderingHint());
  814. m_pgpgrDraw = pgpgrDraw;
  815. m_ptDraw.x = prcInvalid->left;
  816. m_ptDraw.y = prcInvalid->top;
  817. m_sizeDraw.cx = prcInvalid->right - prcInvalid->left;
  818. m_sizeDraw.cy = prcInvalid->bottom - prcInvalid->top;
  819. m_nCmd = nCmd;
  820. m_fChangeOrg = FALSE;
  821. m_pgpgrBitmap->GetTransform(&m_gpmatOldBitmap);
  822. m_pgpgrDraw->GetTransform(&m_gpmatOldDraw);
  823. m_fChangeXF = TRUE;
  824. m_fClip = FALSE;
  825. //
  826. // Setup the buffer as necessary
  827. //
  828. if (m_nCmd == BmpBuffer::dcCopyBkgnd) {
  829. //
  830. // Copy the destination to the buffer to be used as a background.
  831. //
  832. // TODO: This is not supported because GDI+ can't BLT from one
  833. // Graphics directly to another.
  834. }
  835. //
  836. // Clip drawing in the buffer to the actual used part of the buffer. Since
  837. // this is the only part that will be copied over, we don't want to draw
  838. // outside of this area since it slows down performance.
  839. //
  840. Gdiplus::RectF rc(0.0f, 0.0f, (float) m_sizeDraw.cx + 1.0f, (float) m_sizeDraw.cy + 1.0f);
  841. m_pgpgrBitmap->SetClip(rc);
  842. if (!m_pgpgrDraw->IsClipEmpty()) {
  843. //
  844. // Destination surface has a clipping region, so we need to propagate
  845. // it over to the buffer.
  846. //
  847. Gdiplus::Region gprgn;
  848. m_pgpgrDraw->GetClip(&gprgn);
  849. gprgn.Translate(-m_ptDraw.x, -m_ptDraw.y);
  850. m_pgpgrBitmap->SetClip(&gprgn, Gdiplus::CombineModeIntersect);
  851. }
  852. //
  853. // Create a new Surface to contain the buffer.
  854. //
  855. return DuGpSurface::Build(m_pgpgrBitmap, (DuGpSurface **) ppsrfBuffer);
  856. }
  857. /***************************************************************************\
  858. *
  859. * GpBmpBuffer::Fill
  860. *
  861. * TOOD:
  862. *
  863. \***************************************************************************/
  864. void
  865. GpBmpBuffer::Fill(COLORREF cr)
  866. {
  867. //
  868. // Determine packing
  869. //
  870. HBRUSH hbr = CreateSolidBrush(cr);
  871. RECT rcFill;
  872. rcFill.left = 0;
  873. rcFill.top = 0;
  874. rcFill.right = m_sizeDraw.cx;
  875. rcFill.bottom = m_sizeDraw.cy;
  876. FillRect(m_hdcBitmap, &rcFill, hbr);
  877. DeleteObject(hbr);
  878. }
  879. /***************************************************************************\
  880. *
  881. * GpBmpBuffer::PreEndDraw
  882. *
  883. * PreEndDraw() finished a drawing cycle that was previously started with
  884. * BeginDraw(). If fCommit is TRUE, the temporary buffer is prepared to be
  885. * copied to the final destination. The called MUST also call EndDraw()
  886. * to properly end the drawing cycle.
  887. *
  888. \***************************************************************************/
  889. void
  890. GpBmpBuffer::PreEndDraw(
  891. IN BOOL fCommit) // Copy to final destination
  892. {
  893. //
  894. // Resource the destination and buffer surfaces back to where they started.
  895. // This is important because they will be changed during the drawing.
  896. //
  897. if (m_fChangeXF) {
  898. m_pgpgrDraw->SetTransform(&m_gpmatOldDraw);
  899. m_pgpgrBitmap->SetTransform(&m_gpmatOldBitmap);
  900. m_fChangeXF = FALSE;
  901. }
  902. Assert(!m_fChangeOrg);
  903. if ((fCommit) && (m_pgpgrDraw != NULL)) {
  904. //
  905. // Setup any clipping region needed to limit the buffer to an area
  906. // in the destination surface.
  907. //
  908. if (m_fClip) {
  909. AssertMsg(m_pgprgnDrawClip != NULL, "Must have valid region");
  910. AssertMsg(m_pgprgnDrawOld == NULL, "Ensure no outstanding region");
  911. m_pgprgnDrawOld = new Gdiplus::Region;
  912. if (m_pgprgnDrawOld != NULL) {
  913. m_pgpgrDraw->GetClip(m_pgprgnDrawOld);
  914. m_pgpgrDraw->SetClip(m_pgprgnDrawClip);
  915. }
  916. }
  917. }
  918. }
  919. /***************************************************************************\
  920. *
  921. * GpBmpBuffer::EndDraw
  922. *
  923. * EndDraw() finished a drawing cycle that was previously started with
  924. * BeginDraw(). If fCommit is TRUE, the temporary buffer is copied to the
  925. * final destination. After this function finishes, the GpBmpBuffer is ready
  926. * be used again. The called MUST first call PreEndDraw() to properly setup
  927. * any state needed to end the drawing cycle.
  928. *
  929. \***************************************************************************/
  930. void
  931. GpBmpBuffer::EndDraw(
  932. IN BOOL fCommit, // Copy to final destination
  933. IN BYTE bAlphaLevel, // General alpha level
  934. IN BYTE bAlphaFormat) // Pixel alpha format
  935. {
  936. UNREFERENCED_PARAMETER(bAlphaFormat);
  937. if ((fCommit) && (m_pgpgrDraw != NULL)) {
  938. //
  939. // Copy the bits over
  940. //
  941. #if ENABLE_USEFASTDIB
  942. HDC hdcDraw = m_pgpgrDraw->GetHDC();
  943. if (bAlphaLevel == BLEND_OPAQUE) {
  944. BitBlt(hdcDraw, m_ptDraw.x, m_ptDraw.y, m_sizeDraw.cx, m_sizeDraw.cy,
  945. m_hdcBitmap, 0, 0, SRCCOPY);
  946. } else {
  947. BLENDFUNCTION bf;
  948. bf.AlphaFormat = bAlphaFormat;
  949. bf.BlendFlags = 0;
  950. bf.BlendOp = AC_SRC_OVER;
  951. bf.SourceConstantAlpha = bAlphaLevel;
  952. AlphaBlend(hdcDraw, m_ptDraw.x, m_ptDraw.y, m_sizeDraw.cx, m_sizeDraw.cy,
  953. m_hdcBitmap, 0, 0, m_sizeDraw.cx, m_sizeDraw.cy, bf);
  954. }
  955. m_pgpgrDraw->ReleaseHDC(hdcDraw);
  956. #else
  957. if (bAlphaLevel == BLEND_OPAQUE) {
  958. m_pgpgrDraw->DrawImage(m_pgpbmpBuffer, m_ptDraw.x, m_ptDraw.y,
  959. 0, 0, m_sizeDraw.cx, m_sizeDraw.cy, Gdiplus::UnitPixel);
  960. } else {
  961. // TODO: Need to alpha-blend using GDI+
  962. }
  963. #endif
  964. }
  965. }
  966. /***************************************************************************\
  967. *
  968. * GpBmpBuffer::PostEndDraw
  969. *
  970. * PostEndDraw() finished a drawing cycle that was previously started with
  971. * BeginDraw(). After this function finishes, the buffer is ready to be used
  972. * again.
  973. *
  974. \***************************************************************************/
  975. void
  976. GpBmpBuffer::PostEndDraw()
  977. {
  978. if (m_pgpgrDraw != NULL) {
  979. //
  980. // Cleanup the temporary clipping region. This is VERY important to
  981. // do so that the destination surface can continued to be drawn on.
  982. // (For example, more Gadget siblings...)
  983. //
  984. if (m_fClip) {
  985. m_pgpgrDraw->SetClip(m_pgprgnDrawOld);
  986. if (m_pgprgnDrawOld != NULL) {
  987. delete m_pgprgnDrawOld;
  988. m_pgprgnDrawOld = NULL;
  989. }
  990. }
  991. }
  992. //
  993. // Cleanup the clipping region
  994. //
  995. if (m_fClip) {
  996. AssertMsg(m_pgprgnDrawClip!= NULL, "Must have a valid region");
  997. delete m_pgprgnDrawClip;
  998. m_pgprgnDrawClip = NULL;
  999. m_fClip = FALSE;
  1000. }
  1001. AssertMsg(m_pgprgnDrawClip == NULL, "Should no longer have a clipping region");
  1002. //
  1003. // Cleanup associated resources
  1004. //
  1005. if (m_pgpgrBitmap != NULL) {
  1006. delete m_pgpgrBitmap;
  1007. m_pgpgrBitmap = NULL;
  1008. }
  1009. if (m_hdcBitmap != NULL) {
  1010. SelectObject(m_hdcBitmap, m_hbmpOld);
  1011. DeleteDC(m_hdcBitmap);
  1012. m_hdcBitmap = NULL;
  1013. }
  1014. m_pgpgrDraw = NULL;
  1015. if (GetContext()->GetPerfMode() == IGPM_SIZE) {
  1016. FreeBitmap();
  1017. }
  1018. }
  1019. //------------------------------------------------------------------------------
  1020. void
  1021. GpBmpBuffer::SetupClipRgn()
  1022. {
  1023. AssertMsg(!m_fClip, "Only should setup clip region once per cycle");
  1024. AssertMsg(m_pgprgnDrawClip == NULL, "Should not already have a clip region");
  1025. m_pgprgnDrawClip = new Gdiplus::Region;
  1026. if (m_pgprgnDrawClip == NULL) {
  1027. return;
  1028. }
  1029. m_pgpgrBitmap->GetClip(m_pgprgnDrawClip);
  1030. m_pgprgnDrawClip->Translate(m_ptDraw.x, m_ptDraw.y);
  1031. m_fClip = TRUE;
  1032. }
  1033. /***************************************************************************\
  1034. *
  1035. * GpBmpBuffer::InUse
  1036. *
  1037. * InUse() returns if the GpBmpBuffer is currently in a draw cycle started from
  1038. * BeginDraw().
  1039. *
  1040. \***************************************************************************/
  1041. BOOL
  1042. GpBmpBuffer::InUse() const
  1043. {
  1044. return m_pgpgrDraw != NULL;
  1045. }
  1046. /***************************************************************************\
  1047. *
  1048. * GpBmpBuffer::AllocBitmap
  1049. *
  1050. * AllocBitmap() allocates the internal bitmap buffer that is used to
  1051. * temporarily draw into. This bitmap will be compatible with the final
  1052. * destination surface.
  1053. *
  1054. \***************************************************************************/
  1055. BOOL
  1056. GpBmpBuffer::AllocBitmap(
  1057. IN Gdiplus::Graphics * pgpgr, // Final destination Graphics
  1058. IN int cx, // Width of new bitmap
  1059. IN int cy) // Height of new bitmap
  1060. {
  1061. FreeBitmap();
  1062. Assert(ResourceManager::IsInitGdiPlus());
  1063. //
  1064. // When allocating a bitmap, round up to a multiple of 16 x 16. This helps
  1065. // to reduce unnecessary reallocations because we grew by one or two pixels.
  1066. //
  1067. cx = ((cx + 15) / 16) * 16;
  1068. cy = ((cy + 15) / 16) * 16;
  1069. //
  1070. // Allocate the bitmap
  1071. //
  1072. #if ENABLE_USEFASTDIB
  1073. UNREFERENCED_PARAMETER(pgpgr);
  1074. HPALETTE hpal = NULL;
  1075. HDC hdcTemp = GetGdiCache()->GetTempDC();
  1076. ZeroMemory(&m_bmih, sizeof(m_bmih));
  1077. m_bmih.biSize = sizeof(m_bmih);
  1078. m_hbmpBuffer = CreateCompatibleDIB(hdcTemp, hpal, cx, cy, &m_pvBits, &m_bmih);
  1079. GetGdiCache()->ReleaseTempDC(hdcTemp);
  1080. if (m_hbmpBuffer == NULL) {
  1081. return FALSE;
  1082. }
  1083. #else
  1084. m_pgpbmpBuffer = new Gdiplus::Bitmap(cx, cy, pgpgr);
  1085. if (m_pgpbmpBuffer == NULL) {
  1086. return FALSE;
  1087. }
  1088. #endif
  1089. m_sizeBmp.cx = cx;
  1090. m_sizeBmp.cy = cy;
  1091. return TRUE;
  1092. }
  1093. /***************************************************************************\
  1094. *
  1095. * GpBmpBuffer::FreeBitmap
  1096. *
  1097. * FreeBitmap() cleans up allocated resources.
  1098. *
  1099. \***************************************************************************/
  1100. void
  1101. GpBmpBuffer::FreeBitmap()
  1102. {
  1103. #if ENABLE_USEFASTDIB
  1104. if (m_hbmpBuffer != NULL) {
  1105. DeleteObject(m_hbmpBuffer);
  1106. m_hbmpBuffer = NULL;
  1107. m_sizeBmp.cx = 0;
  1108. m_sizeBmp.cy = 0;
  1109. }
  1110. #else
  1111. if (m_pgpbmpBuffer != NULL) {
  1112. delete m_pgpbmpBuffer;
  1113. m_pgpbmpBuffer = NULL;
  1114. m_sizeBmp.cx = 0;
  1115. m_sizeBmp.cy = 0;
  1116. }
  1117. #endif
  1118. }
  1119. /***************************************************************************\
  1120. *****************************************************************************
  1121. *
  1122. * class DCBmpBufferCache
  1123. *
  1124. *****************************************************************************
  1125. \***************************************************************************/
  1126. //------------------------------------------------------------------------------
  1127. void *
  1128. DCBmpBufferCache::Build()
  1129. {
  1130. return ClientNew(DCBmpBuffer);
  1131. }
  1132. //------------------------------------------------------------------------------
  1133. void
  1134. DCBmpBufferCache::DestroyObject(void * pObj)
  1135. {
  1136. DCBmpBuffer * pbufBmp = reinterpret_cast<DCBmpBuffer *>(pObj);
  1137. ClientDelete(DCBmpBuffer, pbufBmp);
  1138. }
  1139. /***************************************************************************\
  1140. *****************************************************************************
  1141. *
  1142. * class GpBmpBufferCache
  1143. *
  1144. *****************************************************************************
  1145. \***************************************************************************/
  1146. //------------------------------------------------------------------------------
  1147. void *
  1148. GpBmpBufferCache::Build()
  1149. {
  1150. return ClientNew(GpBmpBuffer);
  1151. }
  1152. //------------------------------------------------------------------------------
  1153. void
  1154. GpBmpBufferCache::DestroyObject(void * pObj)
  1155. {
  1156. GpBmpBuffer * pbufBmp = reinterpret_cast<GpBmpBuffer *>(pObj);
  1157. ClientDelete(GpBmpBuffer, pbufBmp);
  1158. }
  1159. /***************************************************************************\
  1160. *****************************************************************************
  1161. *
  1162. * class TrxBuffer
  1163. *
  1164. *****************************************************************************
  1165. \***************************************************************************/
  1166. /***************************************************************************\
  1167. *
  1168. * TrxBuffer::TrxBuffer
  1169. *
  1170. * TrxBuffer() constructs a new TrxBuffer object. To create new, initialized
  1171. * TrxBuffer's, call the Build() function instead.
  1172. *
  1173. \***************************************************************************/
  1174. TrxBuffer::TrxBuffer()
  1175. {
  1176. ZeroMemory(m_rgpsur, sizeof(m_rgpsur));
  1177. }
  1178. /***************************************************************************\
  1179. *
  1180. * TrxBuffer::~TrxBuffer
  1181. *
  1182. * ~TrxBuffer() cleans up all resources associated with the buffer.
  1183. *
  1184. \***************************************************************************/
  1185. TrxBuffer::~TrxBuffer()
  1186. {
  1187. RemoveAllSurfaces();
  1188. }
  1189. /***************************************************************************\
  1190. *
  1191. * TrxBuffer::Build
  1192. *
  1193. * Build() fully initializes a new TrxBuffer object that contains several
  1194. * DxSurfaces of a common size. These buffers are used to provide both
  1195. * input and output buffers for DirectX Transforms.
  1196. *
  1197. \***************************************************************************/
  1198. HRESULT
  1199. TrxBuffer::Build(
  1200. IN SIZE sizePxl, // Size of each surface in pixels
  1201. IN int cSurfaces, // Number of surfaces
  1202. OUT TrxBuffer ** ppbufNew) // New buffer
  1203. {
  1204. HRESULT hr;
  1205. TrxBuffer * pbuf = ClientNew(TrxBuffer);
  1206. if (pbuf == NULL) {
  1207. return E_OUTOFMEMORY;
  1208. }
  1209. pbuf->m_cSurfaces = cSurfaces;
  1210. pbuf->m_sizePxl = sizePxl;
  1211. for (int idx = 0; idx < cSurfaces; idx++) {
  1212. hr = pbuf->BuildSurface(idx);
  1213. if (FAILED(hr)) {
  1214. ClientDelete(TrxBuffer, pbuf);
  1215. return hr;
  1216. }
  1217. }
  1218. *ppbufNew = pbuf;
  1219. return S_OK;
  1220. }
  1221. /***************************************************************************\
  1222. *
  1223. * TrxBuffer::BuildSurface
  1224. *
  1225. * BuildSurface() internally builds a new DxSurface and assigns it in the
  1226. * specified slot.
  1227. *
  1228. \***************************************************************************/
  1229. HRESULT
  1230. TrxBuffer::BuildSurface(
  1231. IN int idxSurface) // Surface slot
  1232. {
  1233. AssertMsg((idxSurface < m_cSurfaces) && (idxSurface >= 0), "Ensure valid index");
  1234. AssertMsg((m_sizePxl.cx <= 4000) && (m_sizePxl.cx >= 0) &&
  1235. (m_sizePxl.cy <= 4000) && (m_sizePxl.cy >= 0), "Ensure reasonable size");
  1236. AssertMsg(m_rgpsur[idxSurface] == NULL, "Ensure not already created");
  1237. HRESULT hr;
  1238. DxSurface * psurNew = ClientNew(DxSurface);
  1239. if (psurNew == NULL) {
  1240. return E_OUTOFMEMORY;
  1241. }
  1242. hr = psurNew->Create(m_sizePxl);
  1243. if (FAILED(hr)) {
  1244. ClientDelete(DxSurface, psurNew);
  1245. return hr;
  1246. }
  1247. m_rgpsur[idxSurface] = psurNew;
  1248. return S_OK;
  1249. }
  1250. /***************************************************************************\
  1251. *
  1252. * TrxBuffer::RemoveAllSurfaces
  1253. *
  1254. * RemoveAllSurfaces() destroys all DxSurfaces owned by the TrxBuffer.
  1255. *
  1256. \***************************************************************************/
  1257. void
  1258. TrxBuffer::RemoveAllSurfaces()
  1259. {
  1260. for (int idx = 0; idx < MAX_Surfaces; idx++) {
  1261. if (m_rgpsur != NULL) {
  1262. ClientDelete(DxSurface, m_rgpsur[idx]);
  1263. }
  1264. }
  1265. }