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.

2743 lines
87 KiB

  1. /******************************Module*Header**********************************\
  2. *
  3. * *******************
  4. * * GDI SAMPLE CODE *
  5. * *******************
  6. *
  7. * Module Name: heap.c
  8. *
  9. * Content:
  10. *
  11. * This module contains the routines for a 2-d heap. It is used primarily
  12. * for allocating space for device-format-bitmaps in off-screen memory.
  13. *
  14. * Off-screen bitmaps are a big deal on NT because:
  15. *
  16. * 1) It reduces the working set. Any bitmap stored in off-screen
  17. * memory is a bitmap that isn't taking up space in main memory.
  18. *
  19. * 2) There is a speed win by using the accelerator hardware for
  20. * drawing, in place of NT's GDI code. NT's GDI is written entirely
  21. * in 'C++' and perhaps isn't as fast as it could be.
  22. *
  23. * 3) It leads naturally to nifty tricks that can take advantage of
  24. * the hardware, such as MaskBlt support and cheap double buffering
  25. * for OpenGL.
  26. *
  27. * The heap algorithm employed herein attempts to solve an unsolvable
  28. * problem: the problem of keeping arbitrary sized bitmaps as packed as
  29. * possible in a 2-d space, when the bitmaps can come and go at random.
  30. *
  31. * This problem is due entirely to the nature of the hardware for which this
  32. * driver is written: the hardware treats everything as 2-d quantities. If
  33. * the hardware bitmap pitch could be changed so that the bitmaps could be
  34. * packed linearly in memory, the problem would be infinitely easier (it is
  35. * much easier to track the memory, and the accelerator can be used to re-pack
  36. * the heap to avoid segmentation).
  37. *
  38. * If your hardware can treat bitmaps as one dimensional quantities (as can
  39. * the XGA and ATI), by all means please implement a new off-screen heap.
  40. *
  41. * When the heap gets full, old allocations will automatically be punted
  42. * from off-screen and copied to DIBs, which we'll let GDI draw on.
  43. *
  44. * Note that this heap manages reverse-L shape off-screen memory
  45. * configurations (where the scan pitch is longer than the visible screen,
  46. * such as happens at 800x600 when the scan length must be a multiple of
  47. * 1024).
  48. *
  49. * NOTE: All heap operations must be done under some sort of synchronization,
  50. * whether it's controlled by GDI or explicitly by the driver. All
  51. * the routines in this module assume that they have exclusive access
  52. * to the heap data structures; multiple threads partying in here at
  53. * the same time would be a Bad Thing. (By default, GDI does NOT
  54. * synchronize drawing on device-created bitmaps.)
  55. *
  56. * Copyright (c) 1994-1999 3Dlabs Inc. Ltd. All rights reserved.
  57. * Copyright (c) 1995-2003 Microsoft Corporation. All rights reserved.
  58. \*****************************************************************************/
  59. #include "precomp.h"
  60. #include "glint.h"
  61. #if WNT_DDRAW
  62. #include "linalloc.h"
  63. #endif
  64. #define OH_ALLOC_SIZE 4000 // Do all memory allocations in 4k chunks
  65. #define OH_QUANTUM 4 // The minimum dimension of an allocation
  66. #define CXCY_SENTINEL 0x7fffffff // The sentinel at the end of the available
  67. // list has this very large 'cxcy' value
  68. // This macro results in the available list being maintained with a
  69. // cx-major, cy-minor sort:
  70. #define CXCY(cx, cy) (((cx) << 16) | (cy))
  71. const ULONG HEAP_X_ALIGNMENT_P3[5] = {
  72. 4, // GLINTDEPTH8
  73. 4, // GLINTDEPTH16
  74. 32, // GLINTDEPTH32 = 32 pixels
  75. 0, // ---
  76. 4, // GLINTDEPTH24
  77. };
  78. /******************************Public*Routine******************************\
  79. * void UploadDFBToDIB
  80. \**************************************************************************/
  81. void UploadDFBToDIB(PDEV *ppdev, SURFOBJ *pso, DSURF *pdsurf)
  82. {
  83. OH *poh = pdsurf->poh;
  84. RECTL rclDst;
  85. POINTL ptlSrc;
  86. LONG xOff;
  87. LONG pixOffset;
  88. LONG pixDelta;
  89. ULONG xyOffsetDst;
  90. BOOL bOff;
  91. GLINT_DECL;
  92. rclDst.left = 0;
  93. rclDst.top = 0;
  94. rclDst.right = pdsurf->sizl.cx;
  95. rclDst.bottom = pdsurf->sizl.cy;
  96. ptlSrc.x = 0;
  97. ptlSrc.y = 0;
  98. GET_PPDEV_DST_OFFSETS(ppdev, pixOffset, pixDelta, xyOffsetDst, xOff, bOff);
  99. SET_PPDEV_DST_OFFSETS(ppdev, poh->pixOffset, poh->lPixDelta,
  100. MAKEDWORD_XY(poh->x, poh->y),
  101. poh->bDXManaged ? 0 : poh->x, pdsurf->bOffScreen);
  102. VALIDATE_DD_CONTEXT;
  103. ppdev->pgfnUpload(ppdev, 1, &rclDst, pso, &ptlSrc, &rclDst);
  104. SET_PPDEV_DST_OFFSETS(ppdev, pixOffset, pixDelta, xyOffsetDst, xOff, bOff);
  105. }
  106. /******************************Public*Routine******************************\
  107. * void DownloadDIBToDFB
  108. \**************************************************************************/
  109. void DownloadDIBToDFB(PDEV *ppdev, SURFOBJ *pso, DSURF *pdsurf)
  110. {
  111. OH *poh = pdsurf->poh;
  112. RECTL rclDst;
  113. POINTL ptlSrc;
  114. LONG xOffset;
  115. LONG pixOffset;
  116. LONG pixDelta;
  117. ULONG xyOffsetDst;
  118. BOOL bOff;
  119. GLINT_DECL;
  120. // call low level download routine to download the DIB data to the
  121. // new off-screen DFB. Save and restore the ppdev offsets in case
  122. // we were called from the middle of some blt routine which has
  123. // already set them up.
  124. //
  125. rclDst.left = 0;
  126. rclDst.top = 0;
  127. rclDst.right = pdsurf->sizl.cx;
  128. rclDst.bottom = pdsurf->sizl.cy;
  129. ptlSrc.x = 0;
  130. ptlSrc.y = 0;
  131. GET_PPDEV_DST_OFFSETS(ppdev, pixOffset, pixDelta,
  132. xyOffsetDst, xOffset, bOff);
  133. SET_PPDEV_DST_OFFSETS(ppdev, poh->pixOffset, poh->lPixDelta,
  134. MAKEDWORD_XY(poh->x, poh->y),
  135. poh->bDXManaged ? 0 : poh->x, pdsurf->bOffScreen);
  136. DISPDBG((DBGLVL,"Converting a DIB back to a DFB. calling image download"));
  137. VALIDATE_DD_CONTEXT;
  138. ppdev->pgfnXferImage(ppdev, &rclDst, 1, __GLINT_LOGICOP_COPY,
  139. __GLINT_LOGICOP_COPY, pso, &ptlSrc, &rclDst, NULL);
  140. SET_PPDEV_DST_OFFSETS(ppdev, pixOffset, pixDelta,
  141. xyOffsetDst, xOffset, bOff);
  142. }
  143. /******************************Private*Routine******************************\
  144. * OH* GlintVidMemAlloc
  145. *
  146. * Use the DX heap manager to allocate linear memory from off-screen
  147. *
  148. \**************************************************************************/
  149. OH *GlintVidMemAlloc(PDEV *ppdev, OH *pohThis, LONG cxThis, LONG cyThis)
  150. {
  151. FLATPTR fp = 0;
  152. #if WNT_DDRAW
  153. P3_MEMREQUEST mmrq;
  154. LinearAllocatorInfo *pvmHeap = NULL;
  155. LONG iHeap;
  156. LONG lDelta;
  157. ULONG Mask32bit;
  158. GLINT_DECL;
  159. ASSERTDD((ppdev->flStatus & STAT_LINEAR_HEAP),
  160. "GlintVidMemAlloc: ERROR - "
  161. "linear allocator called when linear heap not enabled!");
  162. DISPDBG((DBGLVL, "GlintVidMemAlloc: want cxy(%xh,%xh), cHeaps(%d)",
  163. cxThis, cyThis, ppdev->heap.cLinearHeaps));
  164. if(ppdev->heap.cLinearHeaps)
  165. {
  166. // align to dword boundaries
  167. Mask32bit = (1 << (2 - ppdev->cPelSize)) - 1;
  168. lDelta = cxThis + Mask32bit;
  169. lDelta &= ~Mask32bit;
  170. lDelta <<= ppdev->cPelSize;
  171. memset(&mmrq, 0, sizeof mmrq);
  172. mmrq.dwSize = sizeof mmrq;
  173. mmrq.dwBytes = lDelta * cyThis;
  174. mmrq.dwAlign = 16; // 16 Byte alignment will work for everything
  175. mmrq.dwFlags = MEM3DL_FIRST_FIT | MEM3DL_FRONT;
  176. retry:
  177. for (iHeap = 0, fp = 0;
  178. iHeap < (LONG)ppdev->heap.cLinearHeaps && fp == 0;
  179. ++iHeap)
  180. {
  181. pvmHeap = &ppdev->heap.pvmLinearHeap[iHeap];
  182. // we don't allocate from the AGP heap at present
  183. if(pvmHeap)
  184. {
  185. if(_DX_LIN_AllocateLinearMemory(pvmHeap, &mmrq) == GLDD_SUCCESS)
  186. {
  187. fp = mmrq.pMem;
  188. }
  189. else
  190. {
  191. DISPDBG((DBGLVL, "GlintVidMemAlloc: allocation failed"));
  192. }
  193. }
  194. }
  195. if(fp == 0)
  196. {
  197. OH *poh;
  198. LONG cxcyThis = cxThis * cyThis;
  199. LONG cxcy;
  200. do
  201. {
  202. poh = ppdev->heap.ohDiscardable.pohPrev;
  203. if (poh == &ppdev->heap.ohDiscardable)
  204. {
  205. DISPDBG((DBGLVL, "GlintVidMemAlloc: FAILED :"
  206. "No discardable bitmaps remaining in "
  207. "offscreen and still not enough room"));
  208. return(NULL);
  209. }
  210. ASSERTDD(poh != &ppdev->heap.ohDiscardable,
  211. "Ran out of discardable entries");
  212. ASSERTDD(poh->ohState == OH_DISCARDABLE,
  213. "Non-discardable node in discardable list");
  214. poh = pohMoveOffscreenDfbToDib(ppdev, poh);
  215. if (poh == NULL)
  216. {
  217. DISPDBG((DBGLVL, "GlintVidMemAlloc: "
  218. "failed to kick DFB into system memory"));
  219. return(NULL);
  220. }
  221. cxcy = poh->cx * poh->cy;
  222. cxcyThis -= cxcy;
  223. }
  224. while (cxcyThis > 0);
  225. goto retry;
  226. }
  227. }
  228. if(fp)
  229. {
  230. ULONG pixOffset, x, y, xAligned;
  231. DISPDBG((DBGLVL, "GlintVidMemAlloc: got some memory"
  232. " - fp(%08xh) lDelta(%xh)", (ULONG)fp, lDelta));
  233. pixOffset = (DWORD)(fp >> ppdev->cPelSize);
  234. y = pixOffset / ppdev->cxMemory;
  235. x = pixOffset % ppdev->cxMemory;
  236. DISPDBG((DBGLVL, "GlintVidMemAlloc: rectangular values are: "
  237. "pixOffset %08xh = xy(%xh,%xh)", pixOffset, x, y));
  238. xAligned = x & ~((1 << (2 - ppdev->cPelSize)) - 1);
  239. pixOffset = y * ppdev->cxMemory + xAligned;
  240. y = 0;
  241. x -= xAligned;
  242. pohThis->x = x;
  243. pohThis->y = y;
  244. pohThis->cx = cxThis;
  245. pohThis->cy = cyThis;
  246. pohThis->lPixDelta = lDelta >> ppdev->cPelSize;
  247. pohThis->pixOffset = pixOffset;
  248. pohThis->cxReserved = 0;
  249. pohThis->cyReserved = 0;
  250. pohThis->cxcy = CXCY(cxThis, cyThis);
  251. pohThis->pdsurf = NULL;
  252. pohThis->pvScan0 = ppdev->pjScreen + fp;
  253. pohThis->bDXManaged = TRUE;
  254. pohThis->pvmHeap = pvmHeap;
  255. pohThis->fpMem = fp;
  256. DISPDBG((DBGLVL, "GlintVidMemAlloc: linear values are: "
  257. "pixOffset(%08xh), xy(%xh,%xh), cxy(%xh,%xh) Delta(%xh)",
  258. pohThis->pixOffset = pixOffset, pohThis->x, pohThis->y,
  259. pohThis->cx, pohThis->cy, pohThis->lPixDelta));
  260. }
  261. else
  262. {
  263. // didn't get any memory - point at the free list
  264. // sentinel to register our disappointment
  265. DISPDBG((DBGLVL, "GlintVidMemAlloc: "
  266. "failed to get any offscreen memory"));
  267. for(pohThis = &ppdev->heap.ohFree;
  268. pohThis->cxcy != CXCY_SENTINEL;
  269. pohThis = pohThis->pohNext)
  270. {
  271. NULL;
  272. }
  273. }
  274. #endif // WNT_DDRAW
  275. return(fp ? pohThis : NULL);
  276. }
  277. /******************************Public*Routine******************************\
  278. * OH* pohNewNode
  279. *
  280. * Allocates a basic memory unit in which we'll pack our data structures.
  281. *
  282. * Since we'll have a lot of OH nodes, most of which we will be
  283. * occasionally traversing, we do our own memory allocation scheme to
  284. * keep them densely packed in memory.
  285. *
  286. * It would be the worst possible thing for the working set to simply
  287. * call EngAllocMem(sizeof(OH)) every time we needed a new node. There
  288. * would be no locality; OH nodes would get scattered throughout memory,
  289. * and as we traversed the available list for one of our allocations,
  290. * it would be far more likely that we would hit a hard page fault.
  291. \**************************************************************************/
  292. OH* pohNewNode(
  293. PDEV* ppdev)
  294. {
  295. LONG i;
  296. LONG cOhs;
  297. OHALLOC* poha;
  298. OH* poh;
  299. if (ppdev->heap.pohFreeList == NULL)
  300. {
  301. DISPDBG((DBGLVL, "pohNewNode(): allocating new poha block"));
  302. // We zero-init to initialize all the OH flags, and to help in
  303. // debugging (we can afford to do this since we'll be doing this
  304. // very infrequently):
  305. poha = ENGALLOCMEM(FL_ZERO_MEMORY, OH_ALLOC_SIZE, ALLOC_TAG_GDI(D));
  306. if (poha == NULL)
  307. {
  308. DISPDBG((DBGLVL, "pohNewNode: failed to alloc node array, "
  309. "returning NULL"));
  310. return(NULL);
  311. }
  312. // Insert this OHALLOC at the begining of the OHALLOC chain:
  313. poha->pohaNext = ppdev->heap.pohaChain;
  314. ppdev->heap.pohaChain = poha;
  315. // This has a '+ 1' because OHALLOC includes an extra OH in its
  316. // structure declaration:
  317. cOhs = (OH_ALLOC_SIZE - sizeof(OHALLOC)) / sizeof(OH) + 1;
  318. // The big OHALLOC allocation is simply a container for a bunch of
  319. // OH data structures in an array. The new OH data structures are
  320. // linked together and added to the OH free list:
  321. poh = &poha->aoh[0];
  322. for (i = cOhs - 1; i != 0; i--)
  323. {
  324. poh->pohNext = poh + 1;
  325. poh = poh + 1;
  326. }
  327. poh->pohNext = NULL;
  328. ppdev->heap.pohFreeList = &poha->aoh[0];
  329. }
  330. poh = ppdev->heap.pohFreeList;
  331. ppdev->heap.pohFreeList = poh->pohNext;
  332. DISPDBG((DBGLVL, "pohNewNode(): returning poh %ph", poh));
  333. return(poh);
  334. }
  335. /******************************Private*Routine******************************\
  336. * OH* GetFreeNode
  337. *
  338. * returns a node from the free list. If nothing free, returns the sentinel
  339. *
  340. \**************************************************************************/
  341. OH *GetFreeNode(PDEV *ppdev, LONG cxThis, LONG cyThis)
  342. {
  343. ULONG cxcyThis = CXCY(cxThis, cyThis);
  344. OH *pohThis;
  345. if((ppdev->flStatus & STAT_LINEAR_HEAP))
  346. {
  347. // We don't used the free list - DX does all the heap management
  348. // just create a node structure and try to alloc from the DX heap.
  349. pohThis = pohNewNode(ppdev);
  350. if(pohThis)
  351. {
  352. // pohNewNode unlinks the node from the free list - link it
  353. // back in as the caller to GetFreeNode will expect it there
  354. pohThis->pohNext = ppdev->heap.ohFree.pohNext;
  355. pohThis->pohPrev = ppdev->heap.ohFree.pohNext->pohPrev;
  356. pohThis->pohNext->pohPrev = pohThis;
  357. pohThis->pohPrev->pohNext = pohThis;
  358. pohThis = GlintVidMemAlloc(ppdev, pohThis, cxThis, cyThis);
  359. }
  360. }
  361. else
  362. {
  363. pohThis = ppdev->heap.ohFree.pohNext;
  364. // The free list shows holds all the unused (rectangular) regions
  365. // on the heap. These are ordered by size. Search through the
  366. // list to find the best fit
  367. while (pohThis->cxcy < cxcyThis)
  368. {
  369. ASSERTDD(pohThis->ohState == OH_FREE,
  370. "Non-free node in free list(1)");
  371. pohThis = pohThis->pohNext;
  372. }
  373. while (pohThis->cy < cyThis)
  374. {
  375. ASSERTDD(pohThis->ohState == OH_FREE,
  376. "Non-free node in free list(2)");
  377. pohThis = pohThis->pohNext;
  378. }
  379. }
  380. return(pohThis);
  381. }
  382. /******************************Public*Routine******************************\
  383. * VOID vOhFreeNode
  384. *
  385. * Frees our basic data structure allocation unit by adding it to a free
  386. * list.
  387. *
  388. \**************************************************************************/
  389. VOID vOhFreeNode(
  390. PDEV* ppdev,
  391. OH* poh)
  392. {
  393. if (poh == NULL)
  394. {
  395. return;
  396. }
  397. DISPDBG((DBGLVL, "vOhFreeNode(): freeing poh %ph", poh));
  398. poh->pohNext = ppdev->heap.pohFreeList;
  399. ppdev->heap.pohFreeList = poh;
  400. poh->ohState = OH_FREE; //azn was -1
  401. }
  402. /******************************Public*Routine******************************\
  403. * VOID vCalculateMaximumNonPermanent
  404. *
  405. * Traverses the list of in-use and available rectangles to find the one
  406. * with the maximal area.
  407. *
  408. \**************************************************************************/
  409. VOID vCalculateMaximumNonPermanent(
  410. PDEV* ppdev)
  411. {
  412. OH* poh;
  413. OH* pohSentinel;
  414. LONG lArea;
  415. LONG lMaxArea;
  416. LONG cxMax;
  417. LONG cyMax;
  418. LONG cxBounds;
  419. LONG cyBounds;
  420. LONG i;
  421. lMaxArea = 0;
  422. cxMax = 0;
  423. cyMax = 0;
  424. cxBounds = 0;
  425. cyBounds = 0;
  426. // First time through, loop through the list of free available
  427. // rectangles:
  428. pohSentinel = &ppdev->heap.ohFree;
  429. for (i = 2; i != 0; i--)
  430. {
  431. for (poh = pohSentinel->pohNext; poh != pohSentinel; poh = poh->pohNext)
  432. {
  433. ASSERTDD(poh->ohState != OH_PERMANENT,
  434. "Permanent node in free or discardable list");
  435. if (poh->cx > cxBounds)
  436. {
  437. cxBounds = poh->cx;
  438. }
  439. if (poh->cy > cyBounds)
  440. {
  441. cyBounds = poh->cy;
  442. }
  443. // We don't have worry about this multiply overflowing
  444. // because we are dealing in physical screen coordinates,
  445. // which will probably never be more than 15 bits:
  446. lArea = poh->cx * poh->cy;
  447. if (lArea > lMaxArea)
  448. {
  449. cxMax = poh->cx;
  450. cyMax = poh->cy;
  451. lMaxArea = lArea;
  452. }
  453. }
  454. // Second time through, loop through the list of discardable
  455. // rectangles:
  456. pohSentinel = &ppdev->heap.ohDiscardable;
  457. }
  458. // All that we are interested in is the dimensions of the rectangle
  459. // that has the largest possible available area (and remember that
  460. // there might not be any possible available area):
  461. ppdev->heap.cxMax = cxMax;
  462. ppdev->heap.cyMax = cyMax;
  463. ppdev->heap.cxBounds = cxBounds;
  464. ppdev->heap.cyBounds = cyBounds;
  465. }
  466. /******************************Public*Routine******************************\
  467. * BOOL bDiscardEverythingInRectangle
  468. *
  469. * Throws out of the heap any discardable bitmaps that intersect with the
  470. * specified rectangle.
  471. *
  472. \**************************************************************************/
  473. BOOL bDiscardEverythingInRectangle(
  474. PDEV* ppdev,
  475. LONG x,
  476. LONG y,
  477. LONG cx,
  478. LONG cy)
  479. {
  480. BOOL bRet;
  481. OH* poh;
  482. OH* pohNext;
  483. bRet = TRUE; // Assume success
  484. poh = ppdev->heap.ohDiscardable.pohNext;
  485. while (poh != &ppdev->heap.ohDiscardable)
  486. {
  487. ASSERTDD(poh->ohState == OH_DISCARDABLE,
  488. "Non-discardable node in discardable list");
  489. pohNext = poh->pohNext;
  490. if ((poh->x < x + cx) &&
  491. (poh->y < y + cy) &&
  492. (poh->x + poh->cx > x) &&
  493. (poh->y + poh->cy > y))
  494. {
  495. // The two rectangles intersect. Give the boot to the
  496. // discardable bitmap:
  497. if (!pohMoveOffscreenDfbToDib(ppdev, poh))
  498. {
  499. bRet = FALSE;
  500. }
  501. }
  502. poh = pohNext;
  503. }
  504. return(bRet);
  505. }
  506. /******************************Public*Routine******************************\
  507. * BOOL bFreeRightAndBottomSpace
  508. *
  509. * Given a free off-screen rectangle, allocates the upper-left part of
  510. * the rectangle to hold the allocation request, and puts the two rectangles
  511. * comprising the unused right and bottom portions on the free list.
  512. *
  513. \**************************************************************************/
  514. BOOL bFreeRightAndBottomSpace(
  515. PDEV* ppdev,
  516. OH* pohThis,
  517. LONG cxThis,
  518. LONG cyThis,
  519. BOOL bQuantum) // Set if inifitely small allocations should be
  520. // allowed
  521. {
  522. ULONG cxcy; // Temporary versions
  523. OH* pohNext;
  524. OH* pohPrev;
  525. LONG cxRem;
  526. LONG cyRem;
  527. OH* pohBelow;
  528. LONG cxBelow;
  529. LONG cyBelow;
  530. OH* pohBeside;
  531. LONG cxBeside;
  532. LONG cyBeside;
  533. LONG cQuantum;
  534. GLINT_DECL;
  535. ASSERTDD(glintInfo != NULL,
  536. "bFreeRightAndBottomSpace: ppdev->glintInfo is NULL");
  537. ASSERTDD(pohThis->bDXManaged == FALSE,
  538. "bFreeRightAndBottomSpace: ERROR - called for linear DFB");
  539. // We're going to use the upper-left corner of our given rectangle,
  540. // and divide the unused remainder into two rectangles which will
  541. // go on the free list.
  542. // Compute the width of the unused rectangle to the right, and the
  543. // height of the unused rectangle below:
  544. cyRem = pohThis->cy - cyThis;
  545. cxRem = pohThis->cx - cxThis;
  546. // Given finite area, we wish to find the two rectangles that are
  547. // most square -- i.e., the arrangement that gives two rectangles
  548. // with the least perimiter:
  549. cyBelow = cyRem;
  550. cxBeside = cxRem;
  551. #if 1
  552. // We may get better performance by keeping screen wide rectangles intact.
  553. if(cyRem < OH_QUANTUM ||
  554. cxRem < OH_QUANTUM ||
  555. pohThis->cx != ppdev->cxScreen)
  556. {
  557. if (cxRem <= cyRem)
  558. {
  559. cxBelow = cxThis + cxRem;
  560. cyBeside = cyThis;
  561. }
  562. else
  563. {
  564. cxBelow = cxThis;
  565. cyBeside = cyThis + cyRem;
  566. }
  567. }
  568. else
  569. {
  570. // we're allocating a block as wide as the screen: force a
  571. // horizontal slice to be taken
  572. cxBelow = cxThis + cxRem;
  573. cyBeside = cyThis;
  574. }
  575. #else
  576. if (cxRem <= cyRem)
  577. {
  578. cxBelow = cxThis + cxRem;
  579. cyBeside = cyThis;
  580. }
  581. else
  582. {
  583. cxBelow = cxThis;
  584. cyBeside = cyThis + cyRem;
  585. }
  586. #endif
  587. // If 'bQuantum' is set, we only make new available rectangles of
  588. // the unused right and bottom portions if they're greater in
  589. // dimension than OH_QUANTUM (it hardly makes sense to do the
  590. // book-work to keep around a 2-pixel wide available space, for
  591. // example):
  592. cQuantum = (bQuantum) ? 1 : OH_QUANTUM;
  593. pohBeside = NULL;
  594. if (cxBeside >= cQuantum)
  595. {
  596. pohBeside = pohNewNode(ppdev);
  597. if (pohBeside == NULL)
  598. return(FALSE);
  599. }
  600. pohBelow = NULL;
  601. if (cyBelow >= cQuantum)
  602. {
  603. pohBelow = pohNewNode(ppdev);
  604. if (pohBelow == NULL)
  605. {
  606. vOhFreeNode(ppdev, pohBeside);
  607. return(FALSE);
  608. }
  609. // Insert this rectangle into the available list (which is
  610. // sorted on ascending cxcy):
  611. cxcy = CXCY(cxBelow, cyBelow);
  612. pohNext = ppdev->heap.ohFree.pohNext;
  613. while (pohNext->cxcy < cxcy)
  614. {
  615. pohNext = pohNext->pohNext;
  616. }
  617. pohPrev = pohNext->pohPrev;
  618. pohPrev->pohNext = pohBelow;
  619. pohNext->pohPrev = pohBelow;
  620. pohBelow->pohPrev = pohPrev;
  621. pohBelow->pohNext = pohNext;
  622. // Now update the adjacency information:
  623. pohBelow->pohLeft = pohThis->pohLeft;
  624. pohBelow->pohUp = pohThis;
  625. pohBelow->pohRight = pohThis->pohRight;
  626. pohBelow->pohDown = pohThis->pohDown;
  627. // Update the rest of the new node information:
  628. pohBelow->cxReserved = 0;
  629. pohBelow->cyReserved = 0;
  630. pohBelow->cxcy = cxcy;
  631. pohBelow->ohState = OH_FREE;
  632. pohBelow->x = pohThis->x;
  633. pohBelow->y = pohThis->y + cyThis;
  634. pohBelow->cx = cxBelow;
  635. pohBelow->cy = cyBelow;
  636. pohBelow->lPixDelta = ppdev->cxMemory;
  637. POH_SET_RECTANGULAR_PIXEL_OFFSET(ppdev, pohBelow);
  638. // Modify the current node to reflect the changes we've made:
  639. pohThis->cy = cyThis;
  640. }
  641. if (cxBeside >= cQuantum)
  642. {
  643. // Insert this rectangle into the available list (which is
  644. // sorted on ascending cxcy):
  645. cxcy = CXCY(cxBeside, cyBeside);
  646. pohNext = ppdev->heap.ohFree.pohNext;
  647. while (pohNext->cxcy < cxcy)
  648. {
  649. pohNext = pohNext->pohNext;
  650. }
  651. pohPrev = pohNext->pohPrev;
  652. pohPrev->pohNext = pohBeside;
  653. pohNext->pohPrev = pohBeside;
  654. pohBeside->pohPrev = pohPrev;
  655. pohBeside->pohNext = pohNext;
  656. // Now update the adjacency information:
  657. pohBeside->pohUp = pohThis->pohUp;
  658. pohBeside->pohLeft = pohThis;
  659. pohBeside->pohDown = pohThis->pohDown;
  660. pohBeside->pohRight = pohThis->pohRight;
  661. // Update the rest of the new node information:
  662. pohBeside->cxReserved = 0;
  663. pohBeside->cyReserved = 0;
  664. pohBeside->cxcy = cxcy;
  665. pohBeside->ohState = OH_FREE;
  666. pohBeside->x = pohThis->x + cxThis;
  667. pohBeside->y = pohThis->y;
  668. pohBeside->cx = cxBeside;
  669. pohBeside->cy = cyBeside;
  670. pohBeside->lPixDelta = ppdev->cxMemory;
  671. POH_SET_RECTANGULAR_PIXEL_OFFSET(ppdev, pohBeside);
  672. // Modify the current node to reflect the changes we've made:
  673. pohThis->cx = cxThis;
  674. }
  675. if (pohBelow != NULL)
  676. {
  677. pohThis->pohDown = pohBelow;
  678. if ((pohBeside != NULL) && (cyBeside == pohThis->cy))
  679. pohBeside->pohDown = pohBelow;
  680. }
  681. if (pohBeside != NULL)
  682. {
  683. pohThis->pohRight = pohBeside;
  684. if ((pohBelow != NULL) && (cxBelow == pohThis->cx))
  685. pohBelow->pohRight = pohBeside;
  686. }
  687. pohThis->cxcy = CXCY(pohThis->cx, pohThis->cy);
  688. return(TRUE);
  689. }
  690. /******************************Public*Routine******************************\
  691. * OH* pohMakeRoomAtLocation
  692. *
  693. * Attempts to allocate a rectangle at a specific position.
  694. *
  695. \**************************************************************************/
  696. OH* pohMakeRoomAtLocation(
  697. PDEV* ppdev,
  698. POINTL* pptl, // Requested position for the rectangle
  699. LONG cxThis, // Width of rectangle to be allocated
  700. LONG cyThis, // Height of rectangle to be allocated
  701. FLONG floh) // Allocation flags
  702. {
  703. OH* poh;
  704. OH* pohTop;
  705. OH* pohLeft;
  706. LONG cxLeft;
  707. LONG cyTop;
  708. OH* pohRight;
  709. ASSERTDD((ppdev->flStatus & STAT_LINEAR_HEAP) == FALSE,
  710. "pohMakeRoomAtLocation: ERROR - called for linear DFB");
  711. if (!(floh & FLOH_ONLY_IF_ROOM))
  712. {
  713. // First off, discard any bitmaps that overlap the requested
  714. // rectangle, assuming we're allowed to:
  715. if (!bDiscardEverythingInRectangle(ppdev,
  716. pptl->x,
  717. pptl->y,
  718. cxThis,
  719. cyThis))
  720. {
  721. return(NULL);
  722. }
  723. }
  724. // Now see if there is a free rectangle that entirely contains the
  725. // requested rectangle.
  726. for (poh = ppdev->heap.ohFree.pohNext;
  727. poh != &ppdev->heap.ohFree;
  728. poh = poh->pohNext)
  729. {
  730. ASSERTDD(poh->ohState == OH_FREE, "Non-free node in free list(3)");
  731. // See if the current free rectangle completely contains the
  732. // requested rectangle:
  733. if ((poh->x <= pptl->x) &&
  734. (poh->y <= pptl->y) &&
  735. (poh->x + poh->cx >= pptl->x + cxThis) &&
  736. (poh->y + poh->cy >= pptl->y + cyThis))
  737. {
  738. // We can't reserve this rectangle, or make it permanent, if it's
  739. // already been reserved:
  740. if ((!poh->cxReserved) ||
  741. ((floh & (FLOH_RESERVE | FLOH_MAKE_PERMANENT)) == 0))
  742. {
  743. // The 'poh' rectangle entirely contains the requested
  744. // rectangle. We may have a situation like this, where
  745. // the smaller rectangle is the requested rectangle, and
  746. // the larger rectangle is the available rectangle:
  747. //
  748. // +-------------------+
  749. // | |
  750. // | +---------+ |
  751. // | |Requested| |
  752. // | | | |
  753. // | +---------+ |
  754. // | |
  755. // +-------------------+
  756. //
  757. // We want to make the space to the left and to the top of
  758. // the requested rectangle available to the heap. Our
  759. // free-space routine only knows how to free space to the
  760. // right and bottom of an allocation, though. So we will
  761. // temporarily allocate temporary rectangles to subdivide
  762. // our rectangle like the following:
  763. //
  764. // +-------------------+
  765. // |Top |
  766. // +----+--------------+
  767. // |Left|Free |
  768. // | | |
  769. // | | |
  770. // | | |
  771. // +----+--------------+
  772. //
  773. // Then, in the resulting 'Free' space, we will allocate the
  774. // upper-left corner for our requested rectangle, after which
  775. // we will go back and free the 'Top' and 'Left' temporary
  776. // rectangles.
  777. pohTop = NULL;
  778. pohLeft = NULL;
  779. cxLeft = pptl->x - poh->x;
  780. cyTop = pptl->y - poh->y;
  781. if (cyTop > 0)
  782. {
  783. if (!bFreeRightAndBottomSpace(ppdev, poh, poh->cx, cyTop,
  784. TRUE))
  785. {
  786. return(NULL);
  787. }
  788. pohTop = poh;
  789. poh = pohTop->pohDown;
  790. }
  791. if (cxLeft > 0)
  792. {
  793. if (!bFreeRightAndBottomSpace(ppdev, poh, cxLeft, poh->cy,
  794. TRUE))
  795. {
  796. pohFree(ppdev, pohTop);
  797. return(NULL);
  798. }
  799. pohLeft = poh;
  800. poh = pohLeft->pohRight;
  801. }
  802. ASSERTDD((poh->x == pptl->x) &&
  803. (poh->y == pptl->y) &&
  804. (poh->x + poh->cx >= poh->x + cxThis) &&
  805. (poh->y + poh->cy >= poh->y + cyThis),
  806. "poh must properly fit requested rectangle");
  807. // Finally, we can subdivide to get our requested rectangle:
  808. if (!bFreeRightAndBottomSpace(ppdev, poh, cxThis, cyThis, FALSE))
  809. {
  810. poh = NULL; // Fail this call
  811. }
  812. // Free our temporary rectangles, if there are any:
  813. pohFree(ppdev, pohTop);
  814. pohFree(ppdev, pohLeft);
  815. return(poh);
  816. }
  817. }
  818. }
  819. // There was no free rectangle that completely contains the requested
  820. // rectangle:
  821. return(NULL);
  822. }
  823. /******************************Public*Routine******************************\
  824. * OH* pohMakeRoomAnywhere
  825. *
  826. * Allocates space for an off-screen rectangle. It will attempt to find
  827. * the smallest available free rectangle, and will allocate the block out
  828. * of its upper-left corner. The remaining two rectangles will be placed
  829. * on the available free space list.
  830. *
  831. * If the rectangle would have been large enough to fit into off-screen
  832. * memory, but there is not enough available free space, we will boot
  833. * bitmaps out of off-screen and into DIBs until there is enough room.
  834. *
  835. \**************************************************************************/
  836. OH* pohMakeRoomAnywhere(
  837. PDEV* ppdev,
  838. LONG cxThis, // Width of rectangle to be allocated
  839. LONG cyThis, // Height of rectangle to be allocated
  840. FLONG floh) // May have FLOH_ONLY_IF_ROOM set
  841. {
  842. ULONG cxcyThis; // Width and height search key
  843. OH* pohThis; // Points to found available rectangle we'll use
  844. GLINT_DECL;
  845. ASSERTDD((cxThis > 0) && (cyThis > 0), "Illegal allocation size");
  846. // Increase the width to get the proper alignment (thus ensuring that all
  847. // allocations will be properly aligned):
  848. cxThis = (cxThis + (HEAP_X_ALIGNMENT_P3[ppdev->cPelSize] - 1)) &
  849. ~(HEAP_X_ALIGNMENT_P3[ppdev->cPelSize] - 1);
  850. // We can't succeed if the requested rectangle is larger than the
  851. // largest possible available rectangle:
  852. if ((cxThis > ppdev->heap.cxBounds) || (cyThis > ppdev->heap.cyBounds))
  853. {
  854. DISPDBG((WRNLVL, "Can't allocate (%d x %d) from (%d x %d)!",
  855. cxThis, cyThis, ppdev->heap.cxBounds, ppdev->heap.cyBounds));
  856. return(NULL);
  857. }
  858. // Find the first available rectangle the same size
  859. // or larger than the requested one:
  860. cxcyThis = CXCY(cxThis, cyThis);
  861. pohThis = GetFreeNode(ppdev, cxThis, cyThis);
  862. if(pohThis == NULL)
  863. {
  864. DISPDBG((WRNLVL, "pohMakeRoomAnywhere: "
  865. "error, GetFreeNode() returned NULL"));
  866. return(NULL);
  867. }
  868. ASSERTDD(pohThis->ohState == OH_FREE, "Non-free node in free list(9)");
  869. if (pohThis->cxcy == CXCY_SENTINEL)
  870. {
  871. // There was no space large enough...
  872. if (floh & FLOH_ONLY_IF_ROOM)
  873. {
  874. return(NULL);
  875. }
  876. DISPDBG((DBGLVL, "> Making room for %li x %li allocation...",
  877. cxThis, cyThis));
  878. // We couldn't find an available rectangle that was big enough
  879. // to fit our request. So throw things out of the heap until we
  880. // have room, oldest allocations first:
  881. do {
  882. // (Least-recently created)
  883. pohThis = ppdev->heap.ohDiscardable.pohPrev;
  884. if (pohThis == &ppdev->heap.ohDiscardable)
  885. {
  886. return(NULL);
  887. }
  888. ASSERTDD(pohThis != &ppdev->heap.ohDiscardable,
  889. "Ran out of discardable entries -- Max not set correctly");
  890. ASSERTDD(pohThis->ohState == OH_DISCARDABLE,
  891. "Non-discardable node in discardable list");
  892. // We can safely exit here if we have to:
  893. pohThis = pohMoveOffscreenDfbToDib(ppdev, pohThis);
  894. if (pohThis == NULL)
  895. {
  896. return(NULL);
  897. }
  898. } while ((pohThis->cx < cxThis) || (pohThis->cy < cyThis));
  899. }
  900. if ((pohThis->cxReserved) && (floh & (FLOH_RESERVE | FLOH_MAKE_PERMANENT)))
  901. {
  902. // We can't reserve this rectangle, or make it permanent, if it's
  903. // already been reserved. So throw absolutely everything out and
  904. // search the free list.
  905. //
  906. // NOTE: This is extremely painful! A better approach would be to
  907. // keep separate 'cxMax' and 'cyMax' variables kept for free
  908. // rectangles that are not reserved (cxMax and cyMax
  909. // currently include reserved free rectangles).
  910. if (!bDiscardEverythingInRectangle(ppdev, 0, 0,
  911. ppdev->cxMemory, ppdev->cyMemory))
  912. {
  913. return(NULL);
  914. }
  915. pohThis = &ppdev->heap.ohFree;
  916. do {
  917. pohThis = pohThis->pohNext;
  918. if (pohThis == &ppdev->heap.ohFree)
  919. {
  920. return(NULL);
  921. }
  922. } // the free list isn't ordered if the heap is DX managed
  923. while ((ppdev->flStatus & STAT_LINEAR_HEAP) == 0 &&
  924. ((pohThis->cxReserved) ||
  925. (pohThis->cx < cxThis) ||
  926. (pohThis->cy < cyThis)));
  927. }
  928. if((ppdev->flStatus & STAT_LINEAR_HEAP) == 0)
  929. {
  930. if (!bFreeRightAndBottomSpace(ppdev, pohThis, cxThis, cyThis, FALSE))
  931. {
  932. return(NULL);
  933. }
  934. }
  935. return(pohThis);
  936. }
  937. /******************************Public*Routine******************************\
  938. * BOOL bOhCommit
  939. *
  940. * If 'bCommit' is TRUE, converts a 'reserved' allocation to 'permanent,'
  941. * moving from off-screen memory any discardable allocations that may have
  942. * been using the space.
  943. *
  944. * If 'bCommit' is FALSE, converts a 'permanent' allocation to 'reserved,'
  945. * allowing the space to be used by discardable allocations.
  946. *
  947. \**************************************************************************/
  948. BOOL bOhCommit(
  949. PDEV* ppdev,
  950. OH* poh,
  951. BOOL bCommit)
  952. {
  953. BOOL bRet;
  954. LONG cx;
  955. LONG cy;
  956. ULONG cxcy;
  957. OH* pohRoot;
  958. OH* pohNext;
  959. OH* pohPrev;
  960. bRet = FALSE; // Assume failure
  961. if (poh == NULL)
  962. {
  963. return(bRet);
  964. }
  965. if ((bCommit) && (poh->cxReserved))
  966. {
  967. if (bDiscardEverythingInRectangle(ppdev, poh->x, poh->y,
  968. poh->cxReserved, poh->cyReserved))
  969. {
  970. DISPDBG((DBGLVL, "Commited %li x %li at (%li, %li)",
  971. poh->cx, poh->cy, poh->x, poh->y));
  972. poh->ohState = OH_PERMANENT;
  973. // Remove this node from the free list:
  974. poh->pohPrev->pohNext = poh->pohNext;
  975. poh->pohNext->pohPrev = poh->pohPrev;
  976. // Now insert the node at the head of the permanent list:
  977. pohRoot = &ppdev->heap.ohPermanent;
  978. poh->pohNext = pohRoot->pohNext;
  979. poh->pohPrev = pohRoot;
  980. pohRoot->pohNext->pohPrev = poh;
  981. pohRoot->pohNext = poh;
  982. bRet = TRUE;
  983. }
  984. }
  985. else if ((!bCommit) && (poh->ohState == OH_PERMANENT))
  986. {
  987. DISPDBG((DBGLVL, "Decommited %li x %li at (%li, %li)",
  988. poh->cx, poh->cy, poh->x, poh->y));
  989. poh->ohState = OH_FREE;
  990. poh->cxReserved = poh->cx;
  991. poh->cyReserved = poh->cy;
  992. // Remove this node from the permanent list:
  993. poh->pohPrev->pohNext = poh->pohNext;
  994. poh->pohNext->pohPrev = poh->pohPrev;
  995. // Now insert the node, in order, into the free list:
  996. cxcy = poh->cxcy;
  997. pohNext = ppdev->heap.ohFree.pohNext;
  998. while (pohNext->cxcy < cxcy)
  999. {
  1000. pohNext = pohNext->pohNext;
  1001. }
  1002. pohPrev = pohNext->pohPrev;
  1003. pohPrev->pohNext = poh;
  1004. pohNext->pohPrev = poh;
  1005. poh->pohPrev = pohPrev;
  1006. poh->pohNext = pohNext;
  1007. bRet = TRUE;
  1008. }
  1009. // Recalculate the biggest rectangle available for allocation:
  1010. vCalculateMaximumNonPermanent(ppdev);
  1011. return(bRet);
  1012. }
  1013. /******************************Public*Routine******************************\
  1014. * OH* pohMoveOffscreenDfbToDib
  1015. *
  1016. * Converts the DFB from being off-screen to being a DIB.
  1017. *
  1018. * Note: The caller does NOT have to call 'pohFree' on 'poh' after making
  1019. * this call.
  1020. *
  1021. * Returns: NULL if the function failed (due to a memory allocation).
  1022. * Otherwise, it returns a pointer to the coalesced off-screen heap
  1023. * node that has been made available for subsequent allocations
  1024. * (useful when trying to free enough memory to make a new
  1025. * allocation).
  1026. \**************************************************************************/
  1027. OH* pohMoveOffscreenDfbToDib(
  1028. PDEV* ppdev,
  1029. OH* poh)
  1030. {
  1031. DSURF *pdsurf;
  1032. HBITMAP hbmDib;
  1033. SURFOBJ *pso;
  1034. GLINT_DECL;
  1035. DISPDBG((DBGLVL, "Throwing out poh %p -- %li x %li at (%li, %li)!",
  1036. poh, poh->cx, poh->cy, poh->x, poh->y));
  1037. pdsurf = poh->pdsurf;
  1038. ASSERTDD((poh->x != 0) || (poh->y != 0 || poh->bDXManaged),
  1039. "Can't make the visible screen into a DIB");
  1040. ASSERTDD((pdsurf->dt & DT_DIB) == 0,
  1041. "Can't make a DIB into even more of a DIB");
  1042. hbmDib = EngCreateBitmap(pdsurf->sizl, 0, ppdev->iBitmapFormat,
  1043. BMF_TOPDOWN, NULL);
  1044. if (hbmDib)
  1045. {
  1046. if (EngAssociateSurface((HSURF) hbmDib, ppdev->hdevEng, 0))
  1047. {
  1048. pso = EngLockSurface((HSURF) hbmDib);
  1049. if (pso != NULL)
  1050. {
  1051. UploadDFBToDIB(ppdev, pso, pdsurf);
  1052. // delete the screen DIB. Recreate it when
  1053. // we change the DIB back to a DFB
  1054. vDeleteScreenDIBFromOH(poh);
  1055. pdsurf->dt = DT_DIB;
  1056. pdsurf->pso = pso;
  1057. pdsurf->poh = NULL;
  1058. // Don't even bother checking to see if this DIB should
  1059. // be put back into off-screen memory until the next
  1060. // heap 'free' occurs:
  1061. pdsurf->iUniq = ppdev->iHeapUniq;
  1062. pdsurf->cBlt = 0;
  1063. // Remove this node from the off-screen DFB list, and free
  1064. // it. 'pohFree' will never return NULL:
  1065. return(pohFree(ppdev, poh));
  1066. }
  1067. }
  1068. // Fail case:
  1069. EngDeleteSurface((HSURF) hbmDib);
  1070. }
  1071. return(NULL);
  1072. }
  1073. /******************************Public*Routine******************************\
  1074. * BOOL bMoveEverythingFromOffscreenToDibs
  1075. *
  1076. * This function is used when we're about to enter full-screen mode, which
  1077. * would wipe all our off-screen bitmaps. GDI can ask us to draw on
  1078. * device bitmaps even when we're in full-screen mode, and we do NOT have
  1079. * the option of stalling the call until we switch out of full-screen.
  1080. * We have no choice but to move all the off-screen DFBs to DIBs.
  1081. *
  1082. * Returns TRUE if all DSURFs have been successfully moved.
  1083. *
  1084. \**************************************************************************/
  1085. BOOL bMoveAllDfbsFromOffscreenToDibs(
  1086. PDEV* ppdev)
  1087. {
  1088. // Throw out any discardable bitmaps over the entire surface:
  1089. return(bDiscardEverythingInRectangle(ppdev, 0, 0,
  1090. ppdev->cxMemory, ppdev->cyMemory));
  1091. }
  1092. /******************************Public*Routine******************************\
  1093. * OH* pohAllocate
  1094. *
  1095. * Allocates a rectangle in off-screen memory.
  1096. *
  1097. * Types:
  1098. *
  1099. * FLOH_RESERVE
  1100. *
  1101. * Reserves an off-screen rectangle. The space may still be used by
  1102. * discardable bitmaps until the rectangle is committed via 'bOhCommit'.
  1103. *
  1104. * FLOH_MAKE_PERMANENT
  1105. *
  1106. * Allocates an off-screen rectangle that can never be booted
  1107. * of the heap. It's the caller's responsibility to manage
  1108. * the rectangle, which includes what to do with the memory in
  1109. * DrvAssertMode when the display is changed to full-screen
  1110. * mode.
  1111. *
  1112. * Default
  1113. *
  1114. * Allocates a 'discardable' off-screen rectangle for a DFB that may
  1115. * be kicked out of off-screen if the space is needed.
  1116. *
  1117. * Options:
  1118. *
  1119. * FLOH_ONLY_IF_ROOM
  1120. *
  1121. * Allocates an off-screen rectangle only if there is free space
  1122. * available -- i.e., no discardable rectangles will be moved out of
  1123. * off-screen to make room.
  1124. *
  1125. * Default
  1126. *
  1127. * May move discardable rectangles out of off-screen to make room.
  1128. *
  1129. * Arguments:
  1130. *
  1131. * pptl
  1132. *
  1133. * If NULL, the rectangle will be allocated anywhere in un-used offscreen
  1134. * memory.
  1135. *
  1136. * If non-NULL, is a requested position for the rectangle.
  1137. *
  1138. * NOTE: The heap will quickly fragment if arbitrary positions are
  1139. * requested. This position option works best if there is only
  1140. * one specific rectangle ever requested, or if the allocations
  1141. * are always wider than they are high.
  1142. *
  1143. \**************************************************************************/
  1144. OH* pohAllocate(
  1145. PDEV* ppdev,
  1146. POINTL* pptl, // Optional requested position of rectangle
  1147. LONG cxThis, // Width of rectangle to be allocated
  1148. LONG cyThis, // Height of rectangle to be allocated
  1149. FLOH floh) // Allocation flags
  1150. {
  1151. OH* pohThis; // Points to found available rectangle we'll use
  1152. OH* pohRoot; // Point to root of list where we'll insert node
  1153. ULONG cxcy;
  1154. OH* pohNext;
  1155. OH* pohPrev;
  1156. ASSERTDD((floh & (FLOH_RESERVE | FLOH_MAKE_PERMANENT))
  1157. != (FLOH_RESERVE | FLOH_MAKE_PERMANENT),
  1158. "Illegal flags -- can't set both "
  1159. "FLOH_RESERVE and FLOH_MAKE_PERMANENT");
  1160. DISPDBG((DBGLVL, "pohAllocate: size %d %d", cxThis, cyThis));
  1161. if (pptl == NULL)
  1162. {
  1163. pohThis = pohMakeRoomAnywhere(ppdev, cxThis, cyThis, floh);
  1164. if (pohThis == NULL)
  1165. {
  1166. DISPDBG((DBGLVL, "Can't allocate %li x %li with flags %li",
  1167. cxThis, cyThis, floh));
  1168. }
  1169. }
  1170. else
  1171. {
  1172. pohThis = pohMakeRoomAtLocation(ppdev, pptl, cxThis, cyThis, floh);
  1173. if (pohThis == NULL)
  1174. {
  1175. DISPDBG((DBGLVL, "Can't allocate %li x %li at %li, "
  1176. "%li with flags %li",
  1177. cxThis, cyThis, pptl->x, pptl->y, floh));
  1178. }
  1179. }
  1180. if (pohThis == NULL)
  1181. {
  1182. return(NULL);
  1183. }
  1184. // Calculate the effective start address for this bitmap in off-
  1185. // screen memory:
  1186. if(pohThis->bDXManaged)
  1187. {
  1188. // in the linear coordinate system:
  1189. // pixOffset == offset of DFB from the start of the FB
  1190. // y == scanline offset from pixOffset (always 0)
  1191. // x == pixel offset from pixOffset+y*lDelta
  1192. // (always the pixel offset from the nearest dword aligned pixel)
  1193. pohThis->pvScan0 = ppdev->pjScreen +
  1194. ( ( pohThis->pixOffset +
  1195. pohThis->y * pohThis->lPixDelta +
  1196. pohThis->x)
  1197. << ppdev->cPelSize );
  1198. }
  1199. else
  1200. {
  1201. // in the rectangular coordinate system, for non-PX/RX chips:
  1202. // pixOffset == value of y expressed in pixels from the start of FB
  1203. // y == pixOffset / lDelta (lDelta is always cxMemory)
  1204. // x == pixel offset to DFB from the beginning of its scanline.
  1205. // For PX/RX chips pixOffset is always 0, y is the number of scanlines
  1206. // to the DFB from the start of the FB
  1207. pohThis->pvScan0 = ppdev->pjScreen +
  1208. ( ( pohThis->y * pohThis->lPixDelta +
  1209. pohThis->x)
  1210. << ppdev->cPelSize );
  1211. }
  1212. // The caller is responsible for setting this field:
  1213. pohThis->pdsurf = NULL;
  1214. // Our 'reserve' logic expects the node to have 'free' status:
  1215. ASSERTDD(pohThis->ohState == OH_FREE, "Node not free after making room");
  1216. ASSERTDD(((floh & (FLOH_RESERVE | FLOH_MAKE_PERMANENT)) == 0) ||
  1217. (pohThis->cxReserved == 0),
  1218. "Can't reserve a rectangle that's already reserved");
  1219. if (floh & FLOH_RESERVE)
  1220. {
  1221. ASSERTDD((ppdev->flStatus & STAT_LINEAR_HEAP) == FALSE,
  1222. "pohAllocate() - can't reserve when the heap is DX managed");
  1223. // A non-zero value for 'cxReserved' means it's reserved:
  1224. pohThis->cxReserved = pohThis->cx;
  1225. pohThis->cyReserved = pohThis->cy;
  1226. // Remove this node from its place in the free list:
  1227. pohThis->pohPrev->pohNext = pohThis->pohNext;
  1228. pohThis->pohNext->pohPrev = pohThis->pohPrev;
  1229. // Now insert the node, in order, back into the free list:
  1230. cxcy = pohThis->cxcy;
  1231. pohNext = ppdev->heap.ohFree.pohNext;
  1232. while (pohNext->cxcy < cxcy)
  1233. {
  1234. pohNext = pohNext->pohNext;
  1235. }
  1236. pohPrev = pohNext->pohPrev;
  1237. pohPrev->pohNext = pohThis;
  1238. pohNext->pohPrev = pohThis;
  1239. pohThis->pohPrev = pohPrev;
  1240. pohThis->pohNext = pohNext;
  1241. }
  1242. else
  1243. {
  1244. // Remove this node from the free list:
  1245. pohThis->pohPrev->pohNext = pohThis->pohNext;
  1246. pohThis->pohNext->pohPrev = pohThis->pohPrev;
  1247. if (floh & FLOH_MAKE_PERMANENT)
  1248. {
  1249. // Change status of node and insert into permanent list:
  1250. pohThis->ohState = OH_PERMANENT;
  1251. pohRoot = &ppdev->heap.ohPermanent;
  1252. // Calculate the new maximum size rectangle available
  1253. // for allocation:
  1254. vCalculateMaximumNonPermanent(ppdev);
  1255. }
  1256. else
  1257. {
  1258. // Change status of node and insert into discardable list:
  1259. pohThis->ohState = OH_DISCARDABLE;
  1260. pohRoot = &ppdev->heap.ohDiscardable;
  1261. }
  1262. // Now insert the node at the head of the appropriate list:
  1263. pohThis->pohNext = pohRoot->pohNext;
  1264. pohThis->pohPrev = pohRoot;
  1265. pohRoot->pohNext->pohPrev = pohThis;
  1266. pohRoot->pohNext = pohThis;
  1267. }
  1268. DISPDBG((DBGLVL, " Allocated (%li x %li) at (%li, %li) with flags %li",
  1269. cxThis, cyThis, pohThis->x, pohThis->y, floh));
  1270. return(pohThis);
  1271. }
  1272. /******************************Public*Routine******************************\
  1273. * OH* pohFree
  1274. *
  1275. * Frees an off-screen heap allocation. The free space will be combined
  1276. * with any adjacent free spaces to avoid segmentation of the 2-d heap.
  1277. *
  1278. * Note: A key idea here is that the data structure for the upper-left-
  1279. * most node must be kept at the same physical CPU memory so that
  1280. * adjacency links are kept correctly (when two free spaces are
  1281. * merged, the lower or right node can be freed).
  1282. *
  1283. \**************************************************************************/
  1284. OH* pohFree(
  1285. PDEV* ppdev,
  1286. OH* poh)
  1287. {
  1288. ULONG cxcy;
  1289. OH* pohBeside;
  1290. OH* pohNext;
  1291. OH* pohPrev;
  1292. OHSTATE oldState;
  1293. if (poh == NULL)
  1294. {
  1295. DISPDBG((WRNLVL, "pohFree: passed in NULL poh"));
  1296. return(NULL);
  1297. }
  1298. DISPDBG((DBGLVL, "Freeing poh %p -- %li x %li at (%li, %li)",
  1299. poh, poh->cx, poh->cy, poh->x, poh->y));
  1300. oldState = poh->ohState;
  1301. if (oldState != OH_DISCARDABLE)
  1302. {
  1303. // We can remove the 'reserved' status unless we are merely
  1304. // deleting a discardable rectangle that was temporarily
  1305. // placed in a reserve rectangle:
  1306. poh->cxReserved = 0;
  1307. poh->cyReserved = 0;
  1308. }
  1309. // Update the uniqueness to show that space has been freed, so that
  1310. // we may decide to see if some DIBs can be moved back into off-screen
  1311. // memory:
  1312. ppdev->iHeapUniq++;
  1313. if(poh->bDXManaged)
  1314. {
  1315. #if WNT_DDRAW
  1316. DISPDBG((DBGLVL, "pohFree: calling DX free for item %p on heap %p",
  1317. (VOID *)poh->fpMem, poh->pvmHeap));
  1318. if(poh->pvmHeap == NULL)
  1319. {
  1320. DISPDBG((ERRLVL,"pohFree: poh %p -- linear DFB is invalid!", poh));
  1321. }
  1322. else
  1323. {
  1324. _DX_LIN_FreeLinearMemory(poh->pvmHeap, (ULONG)(poh->fpMem) );
  1325. poh->pvmHeap = NULL;
  1326. poh->fpMem = 0;
  1327. #if 1 //azntst for MP leak
  1328. // Remove this node from whatever list it's in:
  1329. poh->pohNext->pohPrev = poh->pohPrev;
  1330. poh->pohPrev->pohNext = poh->pohNext;
  1331. // Add the node the the list of free nodes
  1332. vOhFreeNode(ppdev, poh);
  1333. // Set the current state as FREE
  1334. poh->ohState = OH_FREE;
  1335. return(poh); // with DX managing it, we can return now.
  1336. #endif
  1337. }
  1338. #endif // WNT_DDRAW
  1339. goto MergeComplete; //azntst Now a NOP
  1340. }
  1341. MergeLoop:
  1342. // Try merging with the right sibling:
  1343. pohBeside = poh->pohRight;
  1344. if ((poh->cxReserved != poh->cx) &&
  1345. (pohBeside->ohState == OH_FREE) &&
  1346. (pohBeside->cy == poh->cy) &&
  1347. (pohBeside->pohUp == poh->pohUp) &&
  1348. (pohBeside->pohDown == poh->pohDown) &&
  1349. (pohBeside->pohRight->pohLeft != pohBeside))
  1350. {
  1351. // Add the right rectangle to ours:
  1352. poh->cx += pohBeside->cx;
  1353. poh->pohRight = pohBeside->pohRight;
  1354. // Remove 'pohBeside' from the free list and free it:
  1355. pohBeside->pohNext->pohPrev = pohBeside->pohPrev;
  1356. pohBeside->pohPrev->pohNext = pohBeside->pohNext;
  1357. vOhFreeNode(ppdev, pohBeside);
  1358. goto MergeLoop;
  1359. }
  1360. // Try merging with the lower sibling:
  1361. pohBeside = poh->pohDown;
  1362. if ((poh->cyReserved != poh->cy) &&
  1363. (pohBeside->ohState == OH_FREE) &&
  1364. (pohBeside->cx == poh->cx) &&
  1365. (pohBeside->pohLeft == poh->pohLeft) &&
  1366. (pohBeside->pohRight == poh->pohRight) &&
  1367. (pohBeside->pohDown->pohUp != pohBeside))
  1368. {
  1369. poh->cy += pohBeside->cy;
  1370. poh->pohDown = pohBeside->pohDown;
  1371. pohBeside->pohNext->pohPrev = pohBeside->pohPrev;
  1372. pohBeside->pohPrev->pohNext = pohBeside->pohNext;
  1373. vOhFreeNode(ppdev, pohBeside);
  1374. goto MergeLoop;
  1375. }
  1376. // Don't do any more merge this rectangle into anything to the
  1377. // top or to the left if it's reserved:
  1378. if (!poh->cxReserved)
  1379. {
  1380. // Try merging with the left sibling:
  1381. pohBeside = poh->pohLeft;
  1382. if ((pohBeside->cxReserved != pohBeside->cx) &&
  1383. (pohBeside->ohState == OH_FREE) &&
  1384. (pohBeside->cy == poh->cy) &&
  1385. (pohBeside->pohUp == poh->pohUp) &&
  1386. (pohBeside->pohDown == poh->pohDown) &&
  1387. (pohBeside->pohRight == poh) &&
  1388. (poh->pohRight->pohLeft != poh))
  1389. {
  1390. // We add our rectangle to the one to the left:
  1391. pohBeside->cx += poh->cx;
  1392. pohBeside->pohRight = poh->pohRight;
  1393. // Remove 'poh' from whatever list it was in (if we were
  1394. // asked to free a 'permanent' node, it will have been in
  1395. // the permanent list) and free it:
  1396. poh->pohNext->pohPrev = poh->pohPrev;
  1397. poh->pohPrev->pohNext = poh->pohNext;
  1398. vOhFreeNode(ppdev, poh);
  1399. poh = pohBeside;
  1400. goto MergeLoop;
  1401. }
  1402. // Try merging with the upper sibling:
  1403. pohBeside = poh->pohUp;
  1404. if ((pohBeside->cyReserved != pohBeside->cy) &&
  1405. (pohBeside->ohState == OH_FREE) &&
  1406. (pohBeside->cx == poh->cx) &&
  1407. (pohBeside->pohLeft == poh->pohLeft) &&
  1408. (pohBeside->pohRight == poh->pohRight) &&
  1409. (pohBeside->pohDown == poh) &&
  1410. (poh->pohDown->pohUp != poh))
  1411. {
  1412. pohBeside->cy += poh->cy;
  1413. pohBeside->pohDown = poh->pohDown;
  1414. poh->pohNext->pohPrev = poh->pohPrev;
  1415. poh->pohPrev->pohNext = poh->pohNext;
  1416. vOhFreeNode(ppdev, poh);
  1417. poh = pohBeside;
  1418. goto MergeLoop;
  1419. }
  1420. }
  1421. MergeComplete:
  1422. // Remove this node from whatever list it's in:
  1423. poh->pohNext->pohPrev = poh->pohPrev;
  1424. poh->pohPrev->pohNext = poh->pohNext;
  1425. cxcy = CXCY(poh->cx, poh->cy);
  1426. // Insert the node, in order, into the free list:
  1427. // NB. DX managed DFBs don't need to go in any order -
  1428. // they are organised by DirectX instead
  1429. pohNext = ppdev->heap.ohFree.pohNext;
  1430. if(!poh->bDXManaged)
  1431. {
  1432. while (pohNext->cxcy < cxcy)
  1433. {
  1434. pohNext = pohNext->pohNext;
  1435. }
  1436. }
  1437. pohPrev = pohNext->pohPrev;
  1438. pohPrev->pohNext = poh;
  1439. pohNext->pohPrev = poh;
  1440. poh->pohPrev = pohPrev;
  1441. poh->pohNext = pohNext;
  1442. poh->cxcy = cxcy;
  1443. poh->ohState = OH_FREE;
  1444. if (oldState == OH_PERMANENT)
  1445. {
  1446. // Removing the permanent entry means that we may be able to
  1447. // enlarge the maximum possible rectangle we can allow:
  1448. vCalculateMaximumNonPermanent(ppdev);
  1449. }
  1450. // Return the node pointer for the new and improved available rectangle:
  1451. return(poh);
  1452. }
  1453. /******************************Public*Routine******************************\
  1454. * BOOL bCreateScreenDIBForOH
  1455. *
  1456. * Given an OH create a surface for the bitmap which is accessible by GDI.
  1457. * So if we can't handle any drawing using GLINT we can get GDI to draw
  1458. * driectly to the screen. This is possible because we map the screen in
  1459. * fully and linearly. We can use this for the screen and off-screen bitmaps.
  1460. *
  1461. * Returns: FALSE if we didn't create the surface, TRUE if we did.
  1462. *
  1463. \**************************************************************************/
  1464. BOOL
  1465. bCreateScreenDIBForOH(PPDEV ppdev, OH *poh, ULONG hooks)
  1466. {
  1467. DSURF *pdsurf = poh->pdsurf;
  1468. UCHAR *pvBits = poh->pvScan0;
  1469. LONG lDelta = poh->lPixDelta << ppdev->cPelSize;
  1470. HBITMAP hbmDib;
  1471. SURFOBJ *pso;
  1472. DISPDBG((DBGLVL, "bCreateScreenDIBForOH: poh at 0x%x, pdsurf at 0x%x, "
  1473. "pvBits 0x%x", poh, pdsurf, pvBits));
  1474. hbmDib = EngCreateBitmap(pdsurf->sizl,
  1475. (ULONG)lDelta,
  1476. (ULONG)(ppdev->iBitmapFormat),
  1477. (FLONG)(((lDelta > 0) ? BMF_TOPDOWN : 0)),
  1478. (PVOID)pvBits);
  1479. if (hbmDib)
  1480. {
  1481. // set HOOK_SYNCHRONIZE so that GDI will call DrvSynchronize before
  1482. // drawing on this surface. This means we can call Eng anytime safe
  1483. // in the knowledge that DrvSynchronize will sync for us.
  1484. //
  1485. if (EngAssociateSurface((HSURF)hbmDib, ppdev->hdevEng, hooks))
  1486. {
  1487. // NB: use the temporary pso so we don't overwrite pdsurf->pso
  1488. // if we fail
  1489. if (pso = EngLockSurface((HSURF)hbmDib))
  1490. {
  1491. pdsurf->pso = pso;
  1492. DISPDBG((DBGLVL, "created surface 0x%x", pso));
  1493. return(TRUE);
  1494. }
  1495. }
  1496. EngDeleteSurface((HSURF)hbmDib);
  1497. }
  1498. DISPDBG((DBGLVL, "bCreateScreenDIBForOH failed"));
  1499. return(FALSE);
  1500. }
  1501. /******************************Public*Routine******************************\
  1502. * BOOL vDeleteScreenDIBFromOH
  1503. *
  1504. * Given an OH delete any screen DIB surface associated with it. We choose to
  1505. * do a lazy creation of GDI accessible bitmaps for DFBs. So there may not be
  1506. * any surface to delete.
  1507. *
  1508. * Returns:
  1509. *
  1510. \**************************************************************************/
  1511. VOID
  1512. vDeleteScreenDIBFromOH(OH *poh)
  1513. {
  1514. DSURF *pdsurf = poh->pdsurf;
  1515. SURFOBJ *pso;
  1516. HSURF hsurf;
  1517. DISPDBG((DBGLVL, "vDeleteScreenDIBFromOH called"));
  1518. if (!(pso = pdsurf->pso))
  1519. {
  1520. DISPDBG((DBGLVL, "no surface to delete"));
  1521. return;
  1522. }
  1523. hsurf = pso->hsurf; // can't dereference pso when unlocked
  1524. EngUnlockSurface(pso);
  1525. EngDeleteSurface(hsurf); // pdsurf->pso can now be reassigned
  1526. // to a memory DIB
  1527. DISPDBG((DBGLVL, "surface 0x%x deleted", pso));
  1528. }
  1529. /******************************Public*Routine******************************\
  1530. * BOOL bMoveDibToOffscreenDfbIfRoom
  1531. *
  1532. * Converts the DIB DFB to an off-screen DFB, if there's room for it in
  1533. * off-screen memory.
  1534. *
  1535. * Returns: FALSE if there wasn't room, TRUE if successfully moved.
  1536. *
  1537. \**************************************************************************/
  1538. BOOL bMoveDibToOffscreenDfbIfRoom(
  1539. PDEV* ppdev,
  1540. DSURF* pdsurf)
  1541. {
  1542. OH* poh;
  1543. SURFOBJ* pso;
  1544. HSURF hsurf;
  1545. LONG cy;
  1546. ASSERTDD(pdsurf->dt & DT_DIB,
  1547. "Can't move a bitmap off-screen when it's already off-screen");
  1548. // If we're in full-screen mode, we can't move anything to off-screen
  1549. // memory:
  1550. if (!ppdev->bEnabled || !(ppdev->flStatus & STAT_DEV_BITMAPS))
  1551. {
  1552. return(FALSE);
  1553. }
  1554. // XXX
  1555. //
  1556. // for the GeoTwin all off-screen bitmaps must start on an even scanline.
  1557. // This is so that even coordinates always map to the same chip.
  1558. cy = pdsurf->sizl.cy;
  1559. if (ppdev->flCaps & CAPS_SPLIT_FRAMEBUFFER)
  1560. {
  1561. cy = (cy + 1) & ~1;
  1562. DISPDBG((DBGLVL, "move: sizl.cy evened up to %d for GeoTwin", cy));
  1563. }
  1564. poh = pohAllocate(ppdev, NULL, pdsurf->sizl.cx, cy,
  1565. FLOH_ONLY_IF_ROOM);
  1566. if (poh == NULL)
  1567. {
  1568. // There wasn't any free room.
  1569. return(FALSE);
  1570. }
  1571. // Update the data structures to reflect the new off-screen node:
  1572. pso = pdsurf->pso;
  1573. poh->pdsurf = pdsurf;
  1574. pdsurf->poh = poh;
  1575. // recreate the screen DIB. Do it here so that if we fail we can zap poh and
  1576. // leave the bitmap as a memory DIB.
  1577. if (!bCreateScreenDIBForOH(ppdev, poh, HOOK_SYNCHRONIZE))
  1578. {
  1579. DISPDBG((DBGLVL, "bCreateScreenDIBForOH failed"));
  1580. goto ReturnFail;
  1581. }
  1582. pdsurf->dt = DT_SCREEN;
  1583. pdsurf->bOffScreen = TRUE;
  1584. DownloadDIBToDFB(ppdev, pso, pdsurf);
  1585. // Now free the DIB. Get the hsurf from the SURFOBJ before we unlock
  1586. // it (it's not legal to dereference psoDib when it's unlocked):
  1587. hsurf = pso->hsurf;
  1588. EngUnlockSurface(pso);
  1589. EngDeleteSurface(hsurf);
  1590. return(TRUE);
  1591. ReturnFail:
  1592. pohFree(ppdev, poh);
  1593. DISPDBG((DBGLVL, "bMoveDibToOffscreenDfbIfRoom failed"));
  1594. return(FALSE);
  1595. }
  1596. /******************************Public*Routine******************************\
  1597. * HBITMAP DrvCreateDeviceBitmap
  1598. *
  1599. * Function called by GDI to create a device-format-bitmap (DFB). We will
  1600. * always try to allocate the bitmap in off-screen; if we can't, we simply
  1601. * fail the call and GDI will create and manage the bitmap itself.
  1602. *
  1603. * Note: We do not have to zero the bitmap bits. GDI will automatically
  1604. * call us via DrvBitBlt to zero the bits (which is a security
  1605. * consideration).
  1606. *
  1607. \**************************************************************************/
  1608. HBITMAP DrvCreateDeviceBitmap(
  1609. DHPDEV dhpdev,
  1610. SIZEL sizl,
  1611. ULONG iFormat)
  1612. {
  1613. PDEV* ppdev = (PDEV*) dhpdev;
  1614. OH* poh;
  1615. DSURF* pdsurf;
  1616. HBITMAP hbmDevice;
  1617. FLONG flHooks;
  1618. LONG cy = sizl.cy;
  1619. LONG cx = sizl.cx;
  1620. GLINT_DECL;
  1621. // If we're in full-screen mode, we hardly have any off-screen memory
  1622. // in which to allocate a DFB. LATER: We could still allocate an
  1623. // OH node and put the bitmap on the DIB DFB list for later promotion.
  1624. // Also check that off-screen DFBs are configured.
  1625. if (!ppdev->bEnabled || !(ppdev->flStatus & STAT_DEV_BITMAPS))
  1626. {
  1627. return(0);
  1628. }
  1629. // We only support device bitmaps that are the same colour depth
  1630. // as our display.
  1631. //
  1632. // Actually, those are the only kind GDI will ever call us with,
  1633. // but we may as well check. Note that this implies you'll never
  1634. // get a crack at 1bpp bitmaps.
  1635. if (iFormat != ppdev->iBitmapFormat)
  1636. {
  1637. DISPDBG((DBGLVL, "DrvCreateDeviceBitmap(): can't create bitmap of "
  1638. "format %d size(%d,%d), only bitmaps of format %d "
  1639. "supported!", iFormat, cx, cy, ppdev->iBitmapFormat));
  1640. return(0);
  1641. }
  1642. // We don't want anything 8x8 or smaller -- they're typically brush
  1643. // patterns which we don't particularly want to stash in off-screen
  1644. // memory:
  1645. if ((cx <= 8) && (cy <= 8))
  1646. {
  1647. return(0);
  1648. }
  1649. // XXX
  1650. //
  1651. // for the GeoTwin all off-screen bitmaps must start on an even scanline.
  1652. // This is so that even coordinates always map to the same chip.
  1653. if (ppdev->flCaps & CAPS_SPLIT_FRAMEBUFFER)
  1654. {
  1655. cy = (cy + 1) & ~1;
  1656. DISPDBG((DBGLVL, "create: sizl.cy evened up to %d for GeoTwin", cy));
  1657. }
  1658. if(ppdev->pohImageDownloadArea)
  1659. {
  1660. DISPDBG((DBGLVL, "DrvCreateDeviceBitmap: discarding image download "
  1661. "scratch area"));
  1662. pohFree(ppdev, ppdev->pohImageDownloadArea);
  1663. ppdev->pohImageDownloadArea = NULL;
  1664. ppdev->cbImageDownloadArea = 0;
  1665. }
  1666. poh = pohAllocate(ppdev, NULL, cx, cy, 0);
  1667. if (poh != NULL)
  1668. {
  1669. pdsurf = ENGALLOCMEM(FL_ZERO_MEMORY, sizeof(DSURF), ALLOC_TAG_GDI(E));
  1670. if (pdsurf != NULL)
  1671. {
  1672. hbmDevice = EngCreateDeviceBitmap((DHSURF) pdsurf, sizl, iFormat);
  1673. if (hbmDevice != NULL)
  1674. {
  1675. flHooks = ppdev->flHooks;
  1676. #if SYNCHRONIZEACCESS_WORKS && (_WIN32_WINNT < 0x500)
  1677. {
  1678. // Setting the SYNCHRONIZEACCESS flag tells GDI that we
  1679. // want all drawing to the bitmaps to be synchronized (GDI
  1680. // is multi-threaded and by default does not synchronize
  1681. // device bitmap drawing -- it would be a Bad Thing for us
  1682. // to have multiple threads using the accelerator at the
  1683. // same time):
  1684. flHooks |= HOOK_SYNCHRONIZEACCESS;
  1685. }
  1686. #endif // SYNCHRONIZEACCESS_WORKS && (_WIN32_WINNT < 0x500)
  1687. // It's a device-managed surface; make sure we don't set
  1688. // HOOK_SYNCHRONIZE, otherwise we may confuse GDI:
  1689. flHooks &= ~HOOK_SYNCHRONIZE;
  1690. if (EngAssociateSurface((HSURF) hbmDevice, ppdev->hdevEng,
  1691. flHooks))
  1692. {
  1693. pdsurf->dt = DT_SCREEN;
  1694. pdsurf->bOffScreen = TRUE;
  1695. pdsurf->poh = poh;
  1696. pdsurf->sizl = sizl;
  1697. pdsurf->ppdev = ppdev;
  1698. poh->pdsurf = pdsurf;
  1699. // create the GDI accessible screen bitmap
  1700. if (bCreateScreenDIBForOH(ppdev, poh, HOOK_SYNCHRONIZE))
  1701. {
  1702. DISPDBG((DBGLVL, "DFB created at (%d,%d), w %d, h %d",
  1703. poh->x, poh->y, poh->cx, poh->cy));
  1704. return(hbmDevice);
  1705. }
  1706. EngDeleteSurface((HSURF) hbmDevice);
  1707. // Once association is done, EngDeleteSurface
  1708. // callback driver's DrvDeleteDeviceBitmap,
  1709. // then pdsurf and poh are freed there, so that
  1710. // we don't need to free it here.
  1711. }
  1712. else
  1713. {
  1714. EngDeleteSurface((HSURF) hbmDevice);
  1715. ENGFREEMEM(pdsurf);
  1716. pohFree(ppdev, poh);
  1717. }
  1718. }
  1719. else
  1720. {
  1721. ENGFREEMEM(pdsurf);
  1722. pohFree(ppdev, poh);
  1723. }
  1724. }
  1725. else
  1726. {
  1727. pohFree(ppdev, poh);
  1728. }
  1729. }
  1730. return(0);
  1731. }
  1732. /******************************Public*Routine******************************\
  1733. * VOID DrvDeleteDeviceBitmap
  1734. *
  1735. * Deletes a DFB.
  1736. *
  1737. \**************************************************************************/
  1738. VOID DrvDeleteDeviceBitmap(
  1739. DHSURF dhsurf)
  1740. {
  1741. DSURF* pdsurf;
  1742. PDEV* ppdev;
  1743. SURFOBJ* psoDib;
  1744. HSURF hsurfDib;
  1745. pdsurf = (DSURF*) dhsurf;
  1746. ppdev = pdsurf->ppdev;
  1747. if ((pdsurf->dt & DT_DIB) ||
  1748. (pdsurf->dt & DT_DIRECTDRAW))
  1749. {
  1750. psoDib = pdsurf->pso;
  1751. // Get the hsurf from the SURFOBJ before we unlock it (it's not
  1752. // legal to dereference psoDib when it's unlocked):
  1753. hsurfDib = psoDib->hsurf;
  1754. EngUnlockSurface(psoDib);
  1755. EngDeleteSurface(hsurfDib);
  1756. }
  1757. else if (pdsurf->dt & DT_SCREEN)
  1758. {
  1759. vDeleteScreenDIBFromOH(pdsurf->poh);
  1760. pohFree(ppdev, pdsurf->poh);
  1761. }
  1762. ENGFREEMEM(pdsurf);
  1763. }
  1764. /******************************Public*Routine******************************\
  1765. * BOOL bAssertModeOffscreenHeap
  1766. *
  1767. * This function is called whenever we switch in or out of full-screen
  1768. * mode. We have to convert all the off-screen bitmaps to DIBs when
  1769. * we switch to full-screen (because we may be asked to draw on them even
  1770. * when in full-screen, and the mode switch would probably nuke the video
  1771. * memory contents anyway).
  1772. *
  1773. \**************************************************************************/
  1774. BOOL bAssertModeOffscreenHeap(
  1775. PDEV* ppdev,
  1776. BOOL bEnable)
  1777. {
  1778. BOOL b;
  1779. b = TRUE;
  1780. if (!bEnable)
  1781. {
  1782. b = bMoveAllDfbsFromOffscreenToDibs(ppdev);
  1783. }
  1784. return(b);
  1785. }
  1786. /******************************Public*Routine******************************\
  1787. * VOID vDisableOffscreenHeap
  1788. *
  1789. * Frees any resources allocated by the off-screen heap.
  1790. *
  1791. \**************************************************************************/
  1792. VOID vDisableOffscreenHeap(
  1793. PDEV* ppdev)
  1794. {
  1795. OHALLOC* poha;
  1796. OHALLOC* pohaNext;
  1797. SURFOBJ* psoPunt;
  1798. HSURF hsurf;
  1799. psoPunt = ppdev->psoPunt;
  1800. if (psoPunt != NULL)
  1801. {
  1802. hsurf = psoPunt->hsurf;
  1803. EngUnlockSurface(psoPunt);
  1804. EngDeleteSurface(hsurf);
  1805. }
  1806. psoPunt = ppdev->psoPunt2;
  1807. if (psoPunt != NULL)
  1808. {
  1809. hsurf = psoPunt->hsurf;
  1810. EngUnlockSurface(psoPunt);
  1811. EngDeleteSurface(hsurf);
  1812. }
  1813. poha = ppdev->heap.pohaChain;
  1814. while (poha != NULL)
  1815. {
  1816. pohaNext = poha->pohaNext; // Grab the next pointer before it's freed
  1817. ENGFREEMEM(poha);
  1818. poha = pohaNext;
  1819. }
  1820. // the linear heap, if enabled, must be disabled now
  1821. ppdev->flStatus &= ~STAT_LINEAR_HEAP;
  1822. }
  1823. /******************************Public*Routine******************************\
  1824. * BOOL bEnableOffscreenHeap
  1825. *
  1826. * Initializes the off-screen heap using all available video memory,
  1827. * accounting for the portion taken by the visible screen.
  1828. *
  1829. * Input: ppdev->cxScreen
  1830. * ppdev->cyScreen
  1831. * ppdev->cxMemory
  1832. * ppdev->cyMemory
  1833. *
  1834. \**************************************************************************/
  1835. BOOL bEnableOffscreenHeap(
  1836. PDEV* ppdev)
  1837. {
  1838. OH* poh;
  1839. SIZEL sizl;
  1840. HSURF hsurf;
  1841. POINTL ptlScreen;
  1842. LONG virtualcxMemory;
  1843. GLINT_DECL;
  1844. virtualcxMemory = ppdev->cxMemory;
  1845. DISPDBG((DBGLVL, "Screen: %li x %li Memory: %li x %li, "
  1846. "virtualcxMem %li x %li", ppdev->cxScreen,
  1847. ppdev->cyScreen, ppdev->cxMemory, ppdev->cyMemory,
  1848. virtualcxMemory));
  1849. ASSERTDD((ppdev->cxScreen <= virtualcxMemory) &&
  1850. (ppdev->cyScreen <= ppdev->cyMemory),
  1851. "Memory must not have smaller dimensions than visible screen!");
  1852. ppdev->heap.pohaChain = NULL;
  1853. ppdev->heap.pohFreeList = NULL;
  1854. // Initialize the available list, which will be a circular
  1855. // doubly-linked list kept in ascending 'cxcy' order, with a
  1856. // 'sentinel' at the end of the list:
  1857. poh = pohNewNode(ppdev);
  1858. if (poh == NULL)
  1859. {
  1860. goto ReturnFalse;
  1861. }
  1862. // The first node describes the entire video memory size:
  1863. poh->pohNext = &ppdev->heap.ohFree;
  1864. poh->pohPrev = &ppdev->heap.ohFree;
  1865. poh->ohState = OH_FREE;
  1866. poh->x = 0;
  1867. poh->y = 0;
  1868. poh->lPixDelta = ppdev->cxMemory;
  1869. poh->cx = virtualcxMemory;
  1870. poh->cy = ppdev->cyMemory;
  1871. poh->cxcy = CXCY(virtualcxMemory, ppdev->cyMemory);
  1872. poh->pohLeft = &ppdev->heap.ohFree;
  1873. poh->pohUp = &ppdev->heap.ohFree;
  1874. poh->pohRight = &ppdev->heap.ohFree;
  1875. poh->pohDown = &ppdev->heap.ohFree;
  1876. poh->pvScan0 = ppdev->pjScreen;
  1877. poh->pixOffset = 0;
  1878. // The second node is our free list sentinel:
  1879. ppdev->heap.ohFree.pohNext = poh;
  1880. ppdev->heap.ohFree.pohPrev = poh;
  1881. ppdev->heap.ohFree.cxcy = CXCY_SENTINEL;
  1882. ppdev->heap.ohFree.cx = 0x7fffffff;
  1883. ppdev->heap.ohFree.cy = 0x7fffffff;
  1884. ppdev->heap.ohFree.ohState = OH_FREE;
  1885. // Initialize the discardable list, which will be a circular
  1886. // doubly-linked list kept in order, with a sentinel at the end.
  1887. // This node is also used for the screen-surface, for its offset:
  1888. ppdev->heap.ohDiscardable.pohNext = &ppdev->heap.ohDiscardable;
  1889. ppdev->heap.ohDiscardable.pohPrev = &ppdev->heap.ohDiscardable;
  1890. ppdev->heap.ohDiscardable.ohState = OH_DISCARDABLE;
  1891. // Initialize the permanent list, which will be a circular
  1892. // doubly-linked list kept in order, with a sentinel at the end.
  1893. ppdev->heap.ohPermanent.pohNext = &ppdev->heap.ohPermanent;
  1894. ppdev->heap.ohPermanent.pohPrev = &ppdev->heap.ohPermanent;
  1895. ppdev->heap.ohPermanent.ohState = OH_PERMANENT;
  1896. // For the moment, make the max really big so that the first
  1897. // allocation we're about to do will succeed:
  1898. ppdev->heap.cxMax = 0x7fffffff;
  1899. ppdev->heap.cyMax = 0x7fffffff;
  1900. #if (_WIN32_WINNT >= 0x500)
  1901. if(ppdev->flStatus & ENABLE_LINEAR_HEAP)
  1902. {
  1903. // in Windows 2000 we use the DX linear heap for DFBs.
  1904. // NB. the DX heaps aren't initialized until after the display
  1905. // driver has initialized, therefore
  1906. // we use the old rectangular heap for 2D cache allocation.
  1907. ppdev->heap.pvmLinearHeap = NULL;
  1908. ppdev->heap.cLinearHeaps = 0;
  1909. }
  1910. #endif //(_WIN32_WINNT >= 0x500)
  1911. ptlScreen.x = 0;
  1912. ptlScreen.y = 0;
  1913. // Finally, reserve the upper-left corner for the screen. We can
  1914. // actually throw away 'poh' because we'll never need it again
  1915. // (not even for disabling the off-screen heap since everything is
  1916. // freed using OHALLOCs):
  1917. poh = pohAllocate(ppdev, &ptlScreen, ppdev->cxScreen, ppdev->cyScreen,
  1918. FLOH_MAKE_PERMANENT);
  1919. ASSERTDD((poh != NULL) && (poh->x == 0) && (poh->y == 0) &&
  1920. (poh->cx >= ppdev->cxScreen) && (poh->cy >= ppdev->cyScreen),
  1921. "Screen allocation messed up");
  1922. // Remember it so that we can associate the screen SURFOBJ with this
  1923. // poh:
  1924. ppdev->pohScreen = poh;
  1925. // Allocate a 'punt' SURFOBJ we'll use when the device-bitmap is in
  1926. // off-screen memory, but we want GDI to draw to it directly as an
  1927. // engine-managed surface:
  1928. sizl.cx = virtualcxMemory;
  1929. sizl.cy = ppdev->cyMemory;
  1930. // We want to create it with exactly the same capabilities
  1931. // as our primary surface. We will override the 'lDelta' and 'pvScan0'
  1932. // fields later:
  1933. // We do NOT want to hook any of the drawing functions. Once we
  1934. // send this surface into the engine, we don't want the driver to
  1935. // get called with it again. Otherwise we could get into a situation
  1936. // where both the source and dest SURFOBJs for a blt were marked as DIBs.
  1937. hsurf = (HSURF) EngCreateBitmap(sizl,
  1938. 0xbadf00d,
  1939. ppdev->iBitmapFormat,
  1940. BMF_TOPDOWN,
  1941. (VOID*) 0xbadf00d);
  1942. if ((hsurf == 0) ||
  1943. (!EngAssociateSurface(hsurf, ppdev->hdevEng, 0)) ||
  1944. (!(ppdev->psoPunt = EngLockSurface(hsurf))))
  1945. {
  1946. DISPDBG((DBGLVL, "Failed punt surface creation"));
  1947. EngDeleteSurface(hsurf);
  1948. goto ReturnFalse;
  1949. }
  1950. // We need another for doing DrvBitBlt and DrvCopyBits when both
  1951. // surfaces are off-screen bitmaps:
  1952. hsurf = (HSURF) EngCreateBitmap(sizl,
  1953. 0xbadf00d,
  1954. ppdev->iBitmapFormat,
  1955. BMF_TOPDOWN,
  1956. (VOID*) 0xbadf00d);
  1957. if ((hsurf == 0) ||
  1958. (!EngAssociateSurface(hsurf, ppdev->hdevEng, 0)) ||
  1959. (!(ppdev->psoPunt2 = EngLockSurface(hsurf))))
  1960. {
  1961. DISPDBG((DBGLVL, "Failed punt surface creation"));
  1962. EngDeleteSurface(hsurf);
  1963. goto ReturnFalse;
  1964. }
  1965. DISPDBG((DBGLVL, "Passed bEnableOffscreenHeap"));
  1966. // enable off-screen bitmaps by if configured
  1967. if (ppdev->flStatus & ENABLE_DEV_BITMAPS)
  1968. {
  1969. ppdev->flStatus |= STAT_DEV_BITMAPS;
  1970. }
  1971. if (poh != NULL)
  1972. {
  1973. return(TRUE);
  1974. }
  1975. ReturnFalse:
  1976. DISPDBG((DBGLVL, "Failed bEnableOffscreenHeap"));
  1977. return(FALSE);
  1978. }
  1979. /******************************Public*Routine******************************\
  1980. * BOOL vDisable2DOffscreenMemory
  1981. *
  1982. * 3D apps want to use the offscreen memory. Prevent 2D from using it.
  1983. \**************************************************************************/
  1984. BOOL bDisable2DOffscreenMemory(PDEV* ppdev)
  1985. {
  1986. GLINT_DECL;
  1987. if (ppdev->Disable2DCount++ > 0)
  1988. {
  1989. return(TRUE);
  1990. }
  1991. if (ppdev->flStatus & STAT_DEV_BITMAPS)
  1992. {
  1993. if (!bMoveAllDfbsFromOffscreenToDibs(ppdev))
  1994. {
  1995. DISPDBG((DBGLVL, "bDisable2DOffscreenMemory failed"));
  1996. return FALSE;
  1997. }
  1998. ppdev->flStatus &= ~STAT_DEV_BITMAPS;
  1999. }
  2000. return TRUE;
  2001. }
  2002. /******************************Public*Routine******************************\
  2003. * VOID vEnable2DOffscreenMemory
  2004. *
  2005. * 3D apps no longer need offscreen memory. Use it for 2D instead.
  2006. \**************************************************************************/
  2007. VOID vEnable2DOffscreenMemory(PDEV *ppdev)
  2008. {
  2009. GLINT_DECL;
  2010. if (--ppdev->Disable2DCount > 0)
  2011. {
  2012. return;
  2013. }
  2014. if (ppdev->flStatus & ENABLE_DEV_BITMAPS)
  2015. {
  2016. ppdev->flStatus |= STAT_DEV_BITMAPS;
  2017. }
  2018. }
  2019. #if !defined(_WIN64) && WNT_DDRAW
  2020. /******************************Public*Routine******************************\
  2021. * VOID vSurfUsed
  2022. *
  2023. * Notify the heap manager that this surface is touched and it should be
  2024. * moved to the end of DdFreeDriverMemory's priority queue
  2025. \**************************************************************************/
  2026. VOID vSurfUsed(SURFOBJ *psoSurf)
  2027. {
  2028. DSURF* pSurf;
  2029. OH* pohSurf;
  2030. OH* pohHead;
  2031. // When psoSurf is the original source surface, it can be NULL
  2032. if (! psoSurf)
  2033. {
  2034. return;
  2035. }
  2036. // Cast the dhsurf back to the Perm3 GDI surface pointer
  2037. pSurf = (DSURF *)psoSurf->dhsurf;
  2038. // If the surface is a DIB managed by the driver, it shoulf be ignored
  2039. if ((! pSurf) || (pSurf->dt & (DT_DIB | DT_DIRECTDRAW)))
  2040. {
  2041. return;
  2042. }
  2043. // Get the heap node pointer for the surface
  2044. pohSurf = pSurf->poh;
  2045. // Only surface in the discardable chain should be considered
  2046. if ((! pSurf->bOffScreen) || (pohSurf->ohState != OH_DISCARDABLE))
  2047. {
  2048. return;
  2049. }
  2050. // Get the head of the discardable surface chain
  2051. pohHead = &pSurf->ppdev->heap.ohDiscardable;
  2052. // It is quite possible that the surface is already at the end of the queue
  2053. if (pohSurf->pohNext == pohHead)
  2054. {
  2055. return;
  2056. }
  2057. // Remove the surf the priority queue
  2058. pohSurf->pohPrev->pohNext = pohSurf->pohNext;
  2059. pohSurf->pohNext->pohPrev = pohSurf->pohPrev;
  2060. // Link the surf into the priority queue at the end
  2061. pohSurf->pohPrev = pohHead->pohPrev;
  2062. pohSurf->pohNext = pohHead;
  2063. pohSurf->pohPrev->pohNext = pohSurf;
  2064. pohHead->pohPrev = pohSurf;
  2065. }
  2066. /******************************Callback*Routine****************************\
  2067. * DWORD DdFreeDriverMemory
  2068. *
  2069. * This function called by DirectDraw when it's running low on memory in
  2070. * our heap. You only need to implement this function if you use the
  2071. * DirectDraw 'HeapVidMemAllocAligned' function in your driver, and you
  2072. * can boot those allocations out of memory to make room for DirectDraw.
  2073. *
  2074. * We implement this function in the P3 driver because we have DirectDraw
  2075. * entirely manage our off-screen heap, and we use HeapVidMemAllocAligned
  2076. * to put GDI device-bitmaps in off-screen memory. DirectDraw applications
  2077. * have a higher priority for getting stuff into video memory, though, and
  2078. * so this function is used to boot those GDI surfaces out of memory in
  2079. * order to make room for DirectDraw.
  2080. *
  2081. \**************************************************************************/
  2082. DWORD CALLBACK
  2083. DdFreeDriverMemory(PDD_FREEDRIVERMEMORYDATA lpFreeDriverMemory)
  2084. {
  2085. PPDEV ppdev;
  2086. OH* pohSurf;
  2087. DISPDBG((DBGLVL, "DdFreeDriverMemory is called"));
  2088. // Set the return value in case no VM is available
  2089. lpFreeDriverMemory->ddRVal = DDERR_OUTOFMEMORY;
  2090. // Get the head of discardable surface queue
  2091. ppdev = (PPDEV)lpFreeDriverMemory->lpDD->dhpdev;
  2092. pohSurf = ppdev->heap.ohDiscardable.pohNext;
  2093. while (pohSurf != &ppdev->heap.ohDiscardable)
  2094. {
  2095. if (! pohSurf->bDXManaged)
  2096. {
  2097. pohSurf = pohSurf->pohNext;
  2098. continue;
  2099. }
  2100. // Try to demote this VM bitmap to SM
  2101. if (pohMoveOffscreenDfbToDib(ppdev, pohSurf))
  2102. {
  2103. lpFreeDriverMemory->ddRVal = DD_OK;
  2104. }
  2105. break;
  2106. }
  2107. return (DDHAL_DRIVER_HANDLED);
  2108. }
  2109. /******************************Callback*Routine****************************\
  2110. * DdSetExclusiveMode
  2111. *
  2112. * This function is called by DirectDraw when we switch from the GDI surface,
  2113. * to DirectDraw exclusive mode, e.g. to run a game in fullcreen mode.
  2114. * You only need to implement this function when you are using the
  2115. * 'HeapVidMemAllocAligned' function and allocate memory for Device Bitmaps
  2116. * and DirectDraw surfaces from the same heap.
  2117. *
  2118. * We use this call to disable GDI DeviceBitMaps when we are running in
  2119. * DirectDraw exclusive mode. Otherwise a DD app gets confused if both GDI and
  2120. * DirectDraw allocate memory from the same heap.
  2121. *
  2122. *
  2123. \**************************************************************************/
  2124. DWORD CALLBACK
  2125. DdSetExclusiveMode(PDD_SETEXCLUSIVEMODEDATA lpSetExclusiveMode)
  2126. {
  2127. DISPDBG((DBGLVL, "DdSetExclusiveMode is called"));
  2128. if (lpSetExclusiveMode->dwEnterExcl)
  2129. {
  2130. // Remove all GDI device bitmaps from video memory here
  2131. // and make sure they will not be promoted to videomemory
  2132. // until we leave exclusive mode.
  2133. bMoveAllDfbsFromOffscreenToDibs(
  2134. (PDEV*)lpSetExclusiveMode->lpDD->dhpdev);
  2135. }
  2136. lpSetExclusiveMode->ddRVal = DD_OK;
  2137. return (DDHAL_DRIVER_HANDLED);
  2138. }
  2139. /******************************Callback*Routine****************************\
  2140. * DWORD DdFlipToGDISurface
  2141. *
  2142. * This function is called by DirectDraw when it flips to the surface on which
  2143. * GDI can write to.
  2144. \**************************************************************************/
  2145. #if DX7_STEREO
  2146. #define __VIDEO_STEREOENABLE 0x800
  2147. #endif
  2148. DWORD CALLBACK
  2149. DdFlipToGDISurface(PDD_FLIPTOGDISURFACEDATA lpFlipToGDISurface)
  2150. {
  2151. PDEV* ppdev = (PDEV *)lpFlipToGDISurface->lpDD->dhpdev;
  2152. GLINT_DECL;
  2153. DISPDBG((DBGLVL, "DdFlipToGDISurface is called"));
  2154. lpFlipToGDISurface->ddRVal = DD_OK;
  2155. #if DX7_STEREO
  2156. READ_GLINT_CTRL_REG(VideoControl, dwVideoControl);
  2157. WRITE_GLINT_CTRL_REG(VideoControl,
  2158. (dwVideoControl & (~__VIDEO_STEREOENABLE)));
  2159. #endif
  2160. //
  2161. // Return NOTHANDLED, so that the ddraw runtime takes
  2162. // care that we flip back to the primary...
  2163. //
  2164. return (DDHAL_DRIVER_NOTHANDLED);
  2165. }
  2166. #endif
  2167. /*****************************Public*Routine*******************************\
  2168. *
  2169. * HBITMAP DrvDeriveSurface
  2170. *
  2171. * This function derives and creates a GDI surface from the specified
  2172. * DirectDraw surface.
  2173. *
  2174. * Parameters
  2175. * pDirectDraw-----Points to a DD_DIRECTDRAW_GLOBAL structure that describes
  2176. * the DirectDraw object.
  2177. * pSurface--------Points to a DD_SURFACE_LOCAL structure that describes the
  2178. * DirectDraw surface around which to wrap a GDI surface.
  2179. *
  2180. * Return Value
  2181. * DrvDeriveSurface returns a handle to the created GDI surface upon success.
  2182. * It returns NULL if the call fails or if the driver cannot accelerate GDI
  2183. * drawing to the specified DirectDraw surface.
  2184. *
  2185. * Comments
  2186. * DrvDeriveSurface allows the driver to create a GDI surface around a
  2187. * DirectDraw video memory or AGP surface object in order to allow accelerated
  2188. * GDI drawing to the surface. If the driver does not hook this call, all GDI
  2189. * drawing to DirectDraw surfaces is done in software using the DIB engine.
  2190. *
  2191. * GDI calls DrvDeriveSurface with RGB surfaces only.
  2192. *
  2193. * The driver should call DrvCreateDeviceBitmap to create a GDI surface of the
  2194. * same size and format as that of the DirectDraw surface. Space for the
  2195. * actual pixels need not be allocated since it already exists.
  2196. *
  2197. \**************************************************************************/
  2198. HBITMAP
  2199. DrvDeriveSurface(DD_DIRECTDRAW_GLOBAL* pDirectDraw,
  2200. DD_SURFACE_LOCAL* pSurface)
  2201. {
  2202. PDEV* ppdev;
  2203. DSURF* pdsurf;
  2204. HBITMAP hbmDevice;
  2205. DD_SURFACE_GLOBAL* pSurfaceGlobal;
  2206. SIZEL sizl;
  2207. ppdev = (PDEV*)pDirectDraw->dhpdev;
  2208. pSurfaceGlobal = pSurface->lpGbl;
  2209. // Only accel. primary surface.
  2210. if (pSurface->ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE)
  2211. {
  2212. pdsurf = (DSURF*)ENGALLOCMEM(FL_ZERO_MEMORY, sizeof(DSURF), ALLOC_TAG_GDI(E));
  2213. if (pdsurf != NULL)
  2214. {
  2215. sizl.cx = pSurfaceGlobal->wWidth;
  2216. sizl.cy = pSurfaceGlobal->wHeight;
  2217. hbmDevice = EngCreateDeviceBitmap((DHSURF)pdsurf,
  2218. sizl,
  2219. ppdev->iBitmapFormat);
  2220. if ((hbmDevice != NULL) &&
  2221. (EngAssociateSurface((HSURF)hbmDevice, ppdev->hdevEng, ppdev->flHooks)))
  2222. {
  2223. PVOID pvScan0 = ppdev->pjScreen + pSurfaceGlobal->fpVidMem;
  2224. HBITMAP hbmDib = EngCreateBitmap(
  2225. sizl,
  2226. (ULONG) pSurfaceGlobal->lPitch,
  2227. (ULONG)(ppdev->iBitmapFormat),
  2228. (FLONG)(((pSurfaceGlobal->lPitch > 0) ? BMF_TOPDOWN : 0)),
  2229. (PVOID) pvScan0);
  2230. if ((hbmDib != NULL) &&
  2231. (EngAssociateSurface((HSURF)hbmDib, ppdev->hdevEng, HOOK_SYNCHRONIZE)))
  2232. {
  2233. pdsurf->dt = DT_SCREEN | DT_DIRECTDRAW;
  2234. pdsurf->bOffScreen = FALSE;
  2235. pdsurf->poh = ppdev->pohScreen;
  2236. pdsurf->sizl = sizl;
  2237. pdsurf->ppdev = ppdev;
  2238. if (pdsurf->pso = EngLockSurface((HSURF)hbmDib))
  2239. {
  2240. return (hbmDevice);
  2241. }
  2242. }
  2243. if (hbmDib)
  2244. {
  2245. EngDeleteSurface((HSURF)hbmDib);
  2246. }
  2247. }
  2248. if (hbmDevice)
  2249. {
  2250. EngDeleteSurface((HSURF)hbmDevice);
  2251. }
  2252. ENGFREEMEM(pdsurf);
  2253. }
  2254. }
  2255. return(0);
  2256. } // DrvDeriveSurface()