Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1397 lines
41 KiB

  1. /******************************************************************************\
  2. *
  3. * $Workfile: heap.c $
  4. *
  5. * This module contains the routines for a 2-d heap. It is used primarily
  6. * for allocating space for device-format-bitmaps in off-screen memory.
  7. *
  8. * Off-screen bitmaps are a big deal on NT because:
  9. *
  10. * 1) It reduces the working set. Any bitmap stored in off-screen
  11. * memory is a bitmap that isn't taking up space in main memory.
  12. *
  13. * 2) There is a speed win by using the accelerator hardware for
  14. * drawing, in place of NT's GDI code. NT's GDI is written entirely
  15. * in 'C++' and perhaps isn't as fast as it could be.
  16. *
  17. * 3) It leads naturally to nifty tricks that can take advantage of
  18. * the hardware, such as MaskBlt support and cheap double buffering
  19. * for OpenGL.
  20. *
  21. * The heap algorithm employed herein attempts to solve an unsolvable
  22. * problem: the problem of keeping arbitrary sized bitmaps as packed as
  23. * possible in a 2-d space, when the bitmaps can come and go at random.
  24. *
  25. * This problem is due entirely to the nature of the hardware for which this
  26. * driver is written: the hardware treats everything as 2-d quantities. If
  27. * the hardware bitmap pitch could be changed so that the bitmaps could be
  28. * packed linearly in memory, the problem would be infinitely easier (it is
  29. * much easier to track the memory, and the accelerator can be used to re-pack
  30. * the heap to avoid segmentation).
  31. *
  32. * If your hardware can treat bitmaps as one dimensional quantities (as can
  33. * the XGA and ATI), by all means please implement a new off-screen heap.
  34. *
  35. * When the heap gets full, old allocations will automatically be punted
  36. * from off-screen and copied to DIBs, which we'll let GDI draw on.
  37. *
  38. * Note that this heap manages reverse-L shape off-screen memory
  39. * configurations (where the scan pitch is longer than the visible screen,
  40. * such as happens at 800x600 when the scan length must be a multiple of
  41. * 1024).
  42. *
  43. * NOTE: All heap operations must be done under some sort of synchronization,
  44. * whether it's controlled by GDI or explicitly by the driver. All
  45. * the routines in this module assume that they have exclusive access
  46. * to the heap data structures; multiple threads partying in here at
  47. * the same time would be a Bad Thing. (By default, GDI does NOT
  48. * synchronize drawing on device-created bitmaps.)
  49. *
  50. * Copyright (c) 1993-1995 Microsoft Corporation
  51. * Copyright (c) 1996 Cirrus Logic, Inc.
  52. *
  53. * $Log: S:/projects/drivers/ntsrc/display/heap.c_v $
  54. *
  55. * Rev 1.3 Apr 03 1997 15:38:54 unknown
  56. *
  57. *
  58. * Rev 1.2 28 Mar 1997 16:08:50 PLCHU
  59. *
  60. *
  61. * Rev 1.1 Oct 10 1996 15:37:42 unknown
  62. *
  63. *
  64. * Rev 1.8 12 Aug 1996 17:11:22 frido
  65. * hp#1 - Commented new heap stuff.
  66. * hp#2 - Keep enough memory for WinBench bitmap.
  67. *
  68. * Rev 1.7 12 Aug 1996 16:53:30 frido
  69. * Added NT 3.5x/4.0 auto detection.
  70. *
  71. * Rev 1.6 23 Jul 1996 17:48:38 frido
  72. * Removed creation of small device bitmaps.
  73. * Never reject the WinBench bitmap!
  74. *
  75. * Rev 1.5 16 Jul 1996 18:55:52 frido
  76. * Changed splitting of new block to cause less fragmentation.
  77. *
  78. * pat04: 12-20-96 : Supported NT3.51 software cursor with panning scrolling
  79. * pat08: 04-01-97 : SW cursor problem due to code merge. Frido had turned
  80. * of allocation of small device bitmaps for optimization,
  81. * --- winnt to return a null ptr to a color bitmap mask.
  82. *
  83. \******************************************************************************/
  84. #include "precomp.h"
  85. #define OH_ALLOC_SIZE 4000 // Do all memory allocations in 4k chunks
  86. #define OH_QUANTUM 8 // The minimum dimension of an allocation
  87. #define CXCY_SENTINEL 0x7fffffff // The sentinel at the end of the available
  88. // list has this very large 'cxcy' value
  89. // This macro results in the available list being maintained with a
  90. // cx-major, cy-minor sort:
  91. #define CXCY(cx, cy) (((cx) << 16) | (cy))
  92. #if DBG
  93. BOOL gbEnableDFB = TRUE;
  94. #endif
  95. /******************************Public*Routine******************************\
  96. * OH* pohNewNode
  97. *
  98. * Allocates a basic memory unit in which we'll pack our data structures.
  99. *
  100. * Since we'll have a lot of OH nodes, most of which we will be
  101. * occasionally traversing, we do our own memory allocation scheme to
  102. * keep them densely packed in memory.
  103. *
  104. * It would be the worst possible thing for the working set to simply
  105. * call EngAllocMem(sizeof(OH)) every time we needed a new node. There
  106. * would be no locality; OH nodes would get scattered throughout memory,
  107. * and as we traversed the available list for one of our allocations,
  108. * it would be far more likely that we would hit a hard page fault.
  109. \**************************************************************************/
  110. OH* pohNewNode(
  111. PDEV* ppdev)
  112. {
  113. LONG i;
  114. LONG cOhs;
  115. OHALLOC* poha;
  116. OH* poh;
  117. if (ppdev->heap.pohFreeList == NULL)
  118. {
  119. // We zero-init to initialize all the OH flags, and to help in
  120. // debugging (we can afford to do this since we'll be doing this
  121. // very infrequently):
  122. poha = ALLOC(OH_ALLOC_SIZE);
  123. if (poha == NULL)
  124. return(NULL);
  125. // Insert this OHALLOC at the begining of the OHALLOC chain:
  126. poha->pohaNext = ppdev->heap.pohaChain;
  127. ppdev->heap.pohaChain = poha;
  128. // This has a '+ 1' because OHALLOC includes an extra OH in its
  129. // structure declaration:
  130. cOhs = (OH_ALLOC_SIZE - sizeof(OHALLOC)) / sizeof(OH) + 1;
  131. // The big OHALLOC allocation is simply a container for a bunch of
  132. // OH data structures in an array. The new OH data structures are
  133. // linked together and added to the OH free list:
  134. poh = &poha->aoh[0];
  135. for (i = cOhs - 1; i != 0; i--)
  136. {
  137. poh->pohNext = poh + 1;
  138. poh = poh + 1;
  139. }
  140. poh->pohNext = NULL;
  141. ppdev->heap.pohFreeList = &poha->aoh[0];
  142. }
  143. poh = ppdev->heap.pohFreeList;
  144. ppdev->heap.pohFreeList = poh->pohNext;
  145. return(poh);
  146. }
  147. /******************************Public*Routine******************************\
  148. * VOID vOhFreeNode
  149. *
  150. * Frees our basic data structure allocation unit by adding it to a free
  151. * list.
  152. *
  153. \**************************************************************************/
  154. VOID vOhFreeNode(
  155. PDEV* ppdev,
  156. OH* poh)
  157. {
  158. if (poh == NULL)
  159. return;
  160. poh->pohNext = ppdev->heap.pohFreeList;
  161. ppdev->heap.pohFreeList = poh;
  162. poh->ofl = 0;
  163. }
  164. /******************************Public*Routine******************************\
  165. * OH* pohFree
  166. *
  167. * Frees an off-screen heap allocation. The free space will be combined
  168. * with any adjacent free spaces to avoid segmentation of the 2-d heap.
  169. *
  170. * Note: A key idea here is that the data structure for the upper-left-
  171. * most node must be kept at the same physical CPU memory so that
  172. * adjacency links are kept correctly (when two free spaces are
  173. * merged, the lower or right node can be freed).
  174. *
  175. \**************************************************************************/
  176. OH* pohFree(
  177. PDEV* ppdev,
  178. OH* poh)
  179. {
  180. ULONG cxcy;
  181. OH* pohBeside;
  182. OH* pohNext;
  183. OH* pohPrev;
  184. #if 1 //hp#1
  185. BOOL bUpdate;
  186. #endif
  187. if (poh == NULL)
  188. return(NULL);
  189. #if 1 //hp#1
  190. bUpdate = (poh->ofl & OFL_PERMANENT) != 0;
  191. #endif
  192. DISPDBG((4, "Freeing %d x %d at (%d, %d)", poh->cx, poh->cy, poh->x,
  193. poh->y));
  194. #if DEBUG_HEAP
  195. {
  196. RECTL rclBitmap;
  197. RBRUSH_COLOR rbc;
  198. LONG xOffset;
  199. LONG yOffset;
  200. LONG xyOffset;
  201. rclBitmap.left = poh->x;
  202. rclBitmap.top = poh->y;
  203. rclBitmap.right = poh->x + poh->cx;
  204. rclBitmap.bottom = poh->y + poh->cy;
  205. xOffset = ppdev->xOffset;
  206. yOffset = ppdev->yOffset;
  207. xyOffset = ppdev->xyOffset;
  208. ppdev->xOffset = 0;
  209. ppdev->yOffset = 0;
  210. ppdev->xyOffset = 0;
  211. ppdev->pfnFillSolid(ppdev, 1, &rclBitmap, 0x0, rbc, NULL);
  212. ppdev->xOffset = xOffset;
  213. ppdev->yOffset = yOffset;
  214. ppdev->xyOffset = xyOffset;
  215. }
  216. #endif
  217. // Update the uniqueness to show that space has been freed, so that
  218. // we may decide to see if some DIBs can be moved back into off-screen
  219. // memory:
  220. ppdev->iHeapUniq++;
  221. MergeLoop:
  222. #if 0 //hp#1
  223. ASSERTDD(!(poh->ofl & OFL_PERMANENT), "Can't free permanents for now");
  224. #endif
  225. // Try merging with the right sibling:
  226. pohBeside = poh->pohRight;
  227. if ((pohBeside->ofl & OFL_AVAILABLE) &&
  228. (pohBeside->cy == poh->cy) &&
  229. (pohBeside->pohUp == poh->pohUp) &&
  230. (pohBeside->pohDown == poh->pohDown) &&
  231. (pohBeside->pohRight->pohLeft != pohBeside))
  232. {
  233. // Add the right rectangle to ours:
  234. poh->cx += pohBeside->cx;
  235. poh->pohRight = pohBeside->pohRight;
  236. // Remove 'pohBeside' from the ??? list and free it:
  237. pohBeside->pohNext->pohPrev = pohBeside->pohPrev;
  238. pohBeside->pohPrev->pohNext = pohBeside->pohNext;
  239. vOhFreeNode(ppdev, pohBeside);
  240. goto MergeLoop;
  241. }
  242. // Try merging with the lower sibling:
  243. pohBeside = poh->pohDown;
  244. if ((pohBeside->ofl & OFL_AVAILABLE) &&
  245. (pohBeside->cx == poh->cx) &&
  246. (pohBeside->pohLeft == poh->pohLeft) &&
  247. (pohBeside->pohRight == poh->pohRight) &&
  248. (pohBeside->pohDown->pohUp != pohBeside))
  249. {
  250. poh->cy += pohBeside->cy;
  251. poh->pohDown = pohBeside->pohDown;
  252. pohBeside->pohNext->pohPrev = pohBeside->pohPrev;
  253. pohBeside->pohPrev->pohNext = pohBeside->pohNext;
  254. vOhFreeNode(ppdev, pohBeside);
  255. goto MergeLoop;
  256. }
  257. // Try merging with the left sibling:
  258. pohBeside = poh->pohLeft;
  259. if ((pohBeside->ofl & OFL_AVAILABLE) &&
  260. (pohBeside->cy == poh->cy) &&
  261. (pohBeside->pohUp == poh->pohUp) &&
  262. (pohBeside->pohDown == poh->pohDown) &&
  263. (pohBeside->pohRight == poh) &&
  264. (poh->pohRight->pohLeft != poh))
  265. {
  266. // We add our rectangle to the one to the left:
  267. pohBeside->cx += poh->cx;
  268. pohBeside->pohRight = poh->pohRight;
  269. // Remove 'poh' from the ??? list and free it:
  270. poh->pohNext->pohPrev = poh->pohPrev;
  271. poh->pohPrev->pohNext = poh->pohNext;
  272. vOhFreeNode(ppdev, poh);
  273. poh = pohBeside;
  274. goto MergeLoop;
  275. }
  276. // Try merging with the upper sibling:
  277. pohBeside = poh->pohUp;
  278. if ((pohBeside->ofl & OFL_AVAILABLE) &&
  279. (pohBeside->cx == poh->cx) &&
  280. (pohBeside->pohLeft == poh->pohLeft) &&
  281. (pohBeside->pohRight == poh->pohRight) &&
  282. (pohBeside->pohDown == poh) &&
  283. (poh->pohDown->pohUp != poh))
  284. {
  285. pohBeside->cy += poh->cy;
  286. pohBeside->pohDown = poh->pohDown;
  287. poh->pohNext->pohPrev = poh->pohPrev;
  288. poh->pohPrev->pohNext = poh->pohNext;
  289. vOhFreeNode(ppdev, poh);
  290. poh = pohBeside;
  291. goto MergeLoop;
  292. }
  293. // Remove the node from the ???list if it was in use (we wouldn't
  294. // want to do this for a OFL_PERMANENT node that had been freed):
  295. poh->pohNext->pohPrev = poh->pohPrev;
  296. poh->pohPrev->pohNext = poh->pohNext;
  297. cxcy = CXCY(poh->cx, poh->cy);
  298. // Insert the node into the available list:
  299. pohNext = ppdev->heap.ohAvailable.pohNext;
  300. while (pohNext->cxcy < cxcy)
  301. {
  302. pohNext = pohNext->pohNext;
  303. }
  304. pohPrev = pohNext->pohPrev;
  305. pohPrev->pohNext = poh;
  306. pohNext->pohPrev = poh;
  307. poh->pohPrev = pohPrev;
  308. poh->pohNext = pohNext;
  309. poh->ofl = OFL_AVAILABLE;
  310. poh->cxcy = cxcy;
  311. #if 1 //hp#1
  312. if (bUpdate)
  313. {
  314. vCalculateMaximum(ppdev);
  315. }
  316. #endif
  317. // Return the node pointer for the new and improved available rectangle:
  318. return(poh);
  319. }
  320. /******************************Public*Routine******************************\
  321. * OH* pohAllocate
  322. *
  323. * Allocates space for an off-screen rectangle. It will attempt to find
  324. * the smallest available free rectangle, and will allocate the block out
  325. * of its upper-left corner. The remaining two rectangles will be placed
  326. * on the available free space list.
  327. *
  328. * If the rectangle would have been large enough to fit into off-screen
  329. * memory, but there is not enough available free space, we will boot
  330. * bitmaps out of off-screen and into DIBs until there is enough room.
  331. *
  332. \**************************************************************************/
  333. OH* pohAllocate(
  334. PDEV* ppdev,
  335. LONG cxThis, // Width of rectangle to be allocated
  336. LONG cyThis, // Height of rectangle to be allocated
  337. FLOH floh) // Allocation flags
  338. {
  339. ULONG cxcyThis; // Width and height search key
  340. OH* pohThis; // Points to found available rectangle we'll use
  341. ULONG cxcy; // Temporary versions
  342. OH* pohNext;
  343. OH* pohPrev;
  344. LONG cxRem;
  345. LONG cyRem;
  346. OH* pohBelow;
  347. LONG cxBelow;
  348. LONG cyBelow;
  349. OH* pohBeside;
  350. LONG cxBeside;
  351. LONG cyBeside;
  352. DISPDBG((4, "Allocating %d x %d...", cxThis, cyThis));
  353. ASSERTDD((cxThis > 0) && (cyThis > 0), "Illegal allocation size");
  354. // Increase the width to get the proper alignment (thus ensuring that all
  355. // allocations will be properly aligned):
  356. cxThis = (cxThis + (HEAP_X_ALIGNMENT - 1)) & ~(HEAP_X_ALIGNMENT - 1);
  357. // We can't succeed if the requested rectangle is larger than the
  358. // largest possible available rectangle:
  359. if ((cxThis > ppdev->heap.cxMax) || (cyThis > ppdev->heap.cyMax))
  360. {
  361. #if 1 //hp#2
  362. if ((cxThis != 400) && (cyThis != 90))
  363. #endif
  364. {
  365. DISPDBG((4, "Failing pohAllocate... rectangle is larger than max allowed"));
  366. DISPDBG((4, "max = (%d,%d)", ppdev->heap.cxMax, ppdev->heap.cyMax));
  367. DISPDBG((4, "req = (%d,%d)", cxThis, cyThis));
  368. return(NULL);
  369. }
  370. }
  371. // Find the first available rectangle the same size or larger than
  372. // the requested one:
  373. cxcyThis = CXCY(cxThis, cyThis);
  374. pohThis = ppdev->heap.ohAvailable.pohNext;
  375. while (pohThis->cxcy < cxcyThis)
  376. {
  377. pohThis = pohThis->pohNext;
  378. }
  379. while (pohThis->cy < cyThis)
  380. {
  381. pohThis = pohThis->pohNext;
  382. }
  383. if (pohThis->cxcy == CXCY_SENTINEL)
  384. {
  385. // There was no space large enough...
  386. if (floh & FLOH_ONLY_IF_ROOM)
  387. {
  388. DISPDBG((4, "Failing pohAllocate... no space large enough"));
  389. DISPDBG((4, "req = (%d,%d)", cxThis, cyThis));
  390. return(NULL);
  391. }
  392. // We couldn't find an available rectangle that was big enough
  393. // to fit our request. So throw things out of the heap until we
  394. // have room:
  395. do {
  396. pohThis = ppdev->heap.ohDfb.pohPrev; // Least-recently blitted
  397. ASSERTDD(pohThis != &ppdev->heap.ohDfb, "Ran out of in-use entries");
  398. #if 1 //hp#1
  399. while (pohThis->ofl == OFL_PERMANENT)
  400. {
  401. pohThis = pohThis->pohPrev;
  402. if (pohThis == &ppdev->heap.ohDfb)
  403. {
  404. DISPDBG((4, "Failing pohAllocate... not enough memory"));
  405. DISPDBG((4, "req = (%d,%d)", cxThis, cyThis));
  406. return(NULL);
  407. }
  408. }
  409. #endif
  410. // We can safely exit here if we have to:
  411. pohThis = pohMoveOffscreenDfbToDib(ppdev, pohThis);
  412. if (pohThis == NULL)
  413. {
  414. DISPDBG((4, "Failing pohAllocate... failed to eject a dfb"));
  415. DISPDBG((4, "req = (%d,%d)", cxThis, cyThis));
  416. return(NULL);
  417. }
  418. } while ((pohThis->cx < cxThis) || (pohThis->cy < cyThis));
  419. }
  420. // We've now found an available rectangle that is the same size or
  421. // bigger than our requested rectangle. We're going to use the
  422. // upper-left corner of our found rectangle, and divide the unused
  423. // remainder into two rectangles which will go on the available
  424. // list.
  425. // Compute the width of the unused rectangle to the right, and the
  426. // height of the unused rectangle below:
  427. cyRem = pohThis->cy - cyThis;
  428. cxRem = pohThis->cx - cxThis;
  429. // Given finite area, we wish to find the two rectangles that are
  430. // most square -- i.e., the arrangement that gives two rectangles
  431. // with the least perimiter:
  432. cyBelow = cyRem;
  433. cxBeside = cxRem;
  434. #if 1 //hp#1
  435. if ((cxRem <= cyRem) || (pohThis->cx >= ppdev->cxScreen))
  436. #else
  437. if (cxRem <= cyRem)
  438. #endif
  439. {
  440. cxBelow = cxThis + cxRem;
  441. cyBeside = cyThis;
  442. }
  443. else
  444. {
  445. cxBelow = cxThis;
  446. cyBeside = cyThis + cyRem;
  447. }
  448. // We only make new available rectangles of the unused right and bottom
  449. // portions if they're greater in dimension than OH_QUANTUM (it hardly
  450. // makes sense to do the book-work to keep around a 2-pixel wide
  451. // available space, for example):
  452. pohBeside = NULL;
  453. if (cxBeside >= OH_QUANTUM)
  454. {
  455. pohBeside = pohNewNode(ppdev);
  456. if (pohBeside == NULL)
  457. return(NULL);
  458. }
  459. pohBelow = NULL;
  460. if (cyBelow >= OH_QUANTUM)
  461. {
  462. pohBelow = pohNewNode(ppdev);
  463. if (pohBelow == NULL)
  464. {
  465. vOhFreeNode(ppdev, pohBeside);
  466. return(NULL);
  467. }
  468. // Insert this rectangle into the available list (which is
  469. // sorted on ascending cxcy):
  470. cxcy = CXCY(cxBelow, cyBelow);
  471. pohNext = ppdev->heap.ohAvailable.pohNext;
  472. while (pohNext->cxcy < cxcy)
  473. {
  474. pohNext = pohNext->pohNext;
  475. }
  476. pohPrev = pohNext->pohPrev;
  477. pohPrev->pohNext = pohBelow;
  478. pohNext->pohPrev = pohBelow;
  479. pohBelow->pohPrev = pohPrev;
  480. pohBelow->pohNext = pohNext;
  481. // Now update the adjacency information:
  482. pohBelow->pohLeft = pohThis->pohLeft;
  483. pohBelow->pohUp = pohThis;
  484. pohBelow->pohRight = pohThis->pohRight;
  485. pohBelow->pohDown = pohThis->pohDown;
  486. // Update the rest of the new node information:
  487. pohBelow->cxcy = cxcy;
  488. pohBelow->ofl = OFL_AVAILABLE;
  489. pohBelow->x = pohThis->x;
  490. pohBelow->y = pohThis->y + cyThis;
  491. pohBelow->xy = PELS_TO_BYTES(pohBelow->x)
  492. + (pohBelow->y * ppdev->lDelta);
  493. pohBelow->cx = cxBelow;
  494. pohBelow->cy = cyBelow;
  495. // Modify the current node to reflect the changes we've made:
  496. pohThis->cy = cyThis;
  497. }
  498. if (cxBeside >= OH_QUANTUM)
  499. {
  500. // Insert this rectangle into the available list (which is
  501. // sorted on ascending cxcy):
  502. cxcy = CXCY(cxBeside, cyBeside);
  503. pohNext = ppdev->heap.ohAvailable.pohNext;
  504. while (pohNext->cxcy < cxcy)
  505. {
  506. pohNext = pohNext->pohNext;
  507. }
  508. pohPrev = pohNext->pohPrev;
  509. pohPrev->pohNext = pohBeside;
  510. pohNext->pohPrev = pohBeside;
  511. pohBeside->pohPrev = pohPrev;
  512. pohBeside->pohNext = pohNext;
  513. // Now update the adjacency information:
  514. pohBeside->pohUp = pohThis->pohUp;
  515. pohBeside->pohLeft = pohThis;
  516. pohBeside->pohDown = pohThis->pohDown;
  517. pohBeside->pohRight = pohThis->pohRight;
  518. // Update the rest of the new node information:
  519. pohBeside->cxcy = cxcy;
  520. pohBeside->ofl = OFL_AVAILABLE;
  521. pohBeside->x = pohThis->x + cxThis;
  522. pohBeside->y = pohThis->y;
  523. pohBeside->xy = PELS_TO_BYTES(pohBeside->x)
  524. + (pohBeside->y * ppdev->lDelta);
  525. pohBeside->cx = cxBeside;
  526. pohBeside->cy = cyBeside;
  527. // Modify the current node to reflect the changes we've made:
  528. pohThis->cx = cxThis;
  529. }
  530. if (pohBelow != NULL)
  531. {
  532. pohThis->pohDown = pohBelow;
  533. if ((pohBeside != NULL) && (cyBeside == pohThis->cy))
  534. pohBeside->pohDown = pohBelow;
  535. }
  536. if (pohBeside != NULL)
  537. {
  538. pohThis->pohRight = pohBeside;
  539. if ((pohBelow != NULL) && (cxBelow == pohThis->cx))
  540. pohBelow->pohRight = pohBeside;
  541. }
  542. pohThis->ofl = OFL_INUSE;
  543. pohThis->cxcy = CXCY(pohThis->cx, pohThis->cy);
  544. pohThis->pdsurf = NULL; // Caller is responsible for setting this field
  545. // Remove this from the available list:
  546. pohThis->pohPrev->pohNext = pohThis->pohNext;
  547. pohThis->pohNext->pohPrev = pohThis->pohPrev;
  548. // Now insert this at the head of the DFB list:
  549. pohThis->pohNext = ppdev->heap.ohDfb.pohNext;
  550. pohThis->pohPrev = &ppdev->heap.ohDfb;
  551. ppdev->heap.ohDfb.pohNext->pohPrev = pohThis;
  552. ppdev->heap.ohDfb.pohNext = pohThis;
  553. DISPDBG((4, " Allocated at (%d, %d)", pohThis->x, pohThis->y));
  554. // Calculate the effective start address for this bitmap in off-
  555. // screen memory:
  556. pohThis->pvScan0 = ppdev->pjScreen + (pohThis->y * ppdev->lDelta)
  557. + PELS_TO_BYTES(pohThis->x);
  558. return(pohThis);
  559. }
  560. /******************************Public*Routine******************************\
  561. * VOID vCalculateMaxmimum
  562. *
  563. * Traverses the list of in-use and available rectangles to find the one
  564. * with the maximal area.
  565. *
  566. \**************************************************************************/
  567. VOID vCalculateMaximum(
  568. PDEV* ppdev)
  569. {
  570. OH* poh;
  571. OH* pohSentinel;
  572. LONG lArea;
  573. LONG lMaxArea;
  574. LONG cxMax;
  575. LONG cyMax;
  576. LONG i;
  577. lMaxArea = 0;
  578. cxMax = 0;
  579. cyMax = 0;
  580. // First time through, loop through the list of available rectangles:
  581. pohSentinel = &ppdev->heap.ohAvailable;
  582. for (i = 2; i != 0; i--)
  583. {
  584. for (poh = pohSentinel->pohNext; poh != pohSentinel; poh = poh->pohNext)
  585. {
  586. #if 1 //hp#1
  587. if (poh->ofl & OFL_PERMANENT)
  588. {
  589. continue;
  590. }
  591. #else
  592. ASSERTDD(!(poh->ofl & OFL_PERMANENT),
  593. "Permanent in available/DFB chain?");
  594. #endif
  595. // We don't have worry about this multiply overflowing
  596. // because we are dealing in physical screen coordinates,
  597. // which will probably never be more than 15 bits:
  598. lArea = poh->cx * poh->cy;
  599. if (lArea > lMaxArea)
  600. {
  601. cxMax = poh->cx;
  602. cyMax = poh->cy;
  603. lMaxArea = lArea;
  604. }
  605. }
  606. // Second time through, loop through the list of in-use rectangles:
  607. pohSentinel = &ppdev->heap.ohDfb;
  608. }
  609. // All that we are interested in is the dimensions of the rectangle
  610. // that has the largest possible available area (and remember that
  611. // there might not be any possible available area):
  612. ppdev->heap.cxMax = cxMax;
  613. ppdev->heap.cyMax = cyMax;
  614. DISPDBG((1, "Maximum heap: %d x %d", cxMax, cyMax));
  615. }
  616. /******************************Public*Routine******************************\
  617. * OH* pohAllocatePermanent
  618. *
  619. * Allocates an off-screen rectangle that can never be booted of the heap.
  620. * It's the caller's responsibility to manage the rectangle, which includes
  621. * what to do with the memory in DrvAssertMode when the display is changed
  622. * to full-screen mode.
  623. *
  624. \**************************************************************************/
  625. OH* pohAllocatePermanent(
  626. PDEV* ppdev,
  627. LONG cx,
  628. LONG cy)
  629. {
  630. OH* poh;
  631. poh = pohAllocate(ppdev, cx, cy, 0);
  632. if (poh != NULL)
  633. {
  634. // Mark the rectangle as permanent:
  635. poh->ofl = OFL_PERMANENT;
  636. #if 0 //hp#1
  637. // Remove the node from the most-recently blitted list:
  638. poh->pohPrev->pohNext = poh->pohNext;
  639. poh->pohNext->pohPrev = poh->pohPrev;
  640. poh->pohPrev = NULL;
  641. poh->pohNext = NULL;
  642. #endif
  643. // Now calculate the new maximum size rectangle available in the
  644. // heap:
  645. vCalculateMaximum(ppdev);
  646. }
  647. return(poh);
  648. }
  649. /******************************Public*Routine******************************\
  650. * BOOL bMoveDibToOffscreenDfbIfRoom
  651. *
  652. * Converts the DIB DFB to an off-screen DFB, if there's room for it in
  653. * off-screen memory.
  654. *
  655. * Returns: FALSE if there wasn't room, TRUE if successfully moved.
  656. *
  657. \**************************************************************************/
  658. BOOL bMoveDibToOffscreenDfbIfRoom(
  659. PDEV* ppdev,
  660. DSURF* pdsurf)
  661. {
  662. OH* poh;
  663. SURFOBJ* pso;
  664. RECTL rclDst;
  665. POINTL ptlSrc;
  666. HSURF hsurf;
  667. ASSERTDD(pdsurf->dt == DT_DIB,
  668. "Can't move a bitmap off-screen when it's already off-screen");
  669. DISPDBG((4, "Trying to reload %d x %d surface", pdsurf->sizl.cx,
  670. pdsurf->sizl.cy));
  671. // If we're in full-screen mode, we can't move anything to off-screen
  672. // memory:
  673. if (!ppdev->bEnabled)
  674. return(FALSE);
  675. poh = pohAllocate(ppdev, pdsurf->sizl.cx, pdsurf->sizl.cy,
  676. FLOH_ONLY_IF_ROOM);
  677. if (poh == NULL)
  678. {
  679. // There wasn't any free room.
  680. return(FALSE);
  681. }
  682. // 'pdsurf->sizl' is the actual bitmap dimension, not 'poh->cx' or
  683. // 'poh->cy'.
  684. rclDst.left = poh->x;
  685. rclDst.top = poh->y;
  686. rclDst.right = rclDst.left + pdsurf->sizl.cx;
  687. rclDst.bottom = rclDst.top + pdsurf->sizl.cy;
  688. ptlSrc.x = 0;
  689. ptlSrc.y = 0;
  690. ppdev->pfnPutBits(ppdev, pdsurf->pso, &rclDst, &ptlSrc);
  691. // Update the data structures to reflect the new off-screen node:
  692. pso = pdsurf->pso;
  693. pdsurf->dt = DT_SCREEN;
  694. pdsurf->poh = poh;
  695. poh->pdsurf = pdsurf;
  696. // Now free the DIB. Get the hsurf from the SURFOBJ before we unlock
  697. // it (it's not legal to dereference psoDib when it's unlocked):
  698. hsurf = pso->hsurf;
  699. EngUnlockSurface(pso);
  700. EngDeleteSurface(hsurf);
  701. return(TRUE);
  702. }
  703. /******************************Public*Routine******************************\
  704. * OH* pohMoveOffscreenDfbToDib
  705. *
  706. * Converts the DFB from being off-screen to being a DIB.
  707. *
  708. * Note: The caller does NOT have to call 'pohFree' on 'poh' after making
  709. * this call.
  710. *
  711. * Returns: NULL if the function failed (due to a memory allocation).
  712. * Otherwise, it returns a pointer to the coalesced off-screen heap
  713. * node that has been made available for subsequent allocations
  714. * (useful when trying to free enough memory to make a new
  715. * allocation).
  716. \**************************************************************************/
  717. OH* pohMoveOffscreenDfbToDib(
  718. PDEV* ppdev,
  719. OH* poh)
  720. {
  721. DSURF* pdsurf;
  722. HBITMAP hbmDib;
  723. SURFOBJ* pso;
  724. RECTL rclDst;
  725. POINTL ptlSrc;
  726. DISPDBG((4, "Throwing out %li x %li at (%li, %li)!",
  727. poh->cx, poh->cy, poh->x, poh->y));
  728. #if 1 //hp#1
  729. if (poh->ofl & OFL_PERMANENT)
  730. {
  731. return(NULL);
  732. }
  733. #endif
  734. pdsurf = poh->pdsurf;
  735. ASSERTDD((poh->x != 0) || (poh->y != 0),
  736. "Can't make the visible screen into a DIB");
  737. ASSERTDD(pdsurf->dt != DT_DIB,
  738. "Can't make a DIB into even more of a DIB");
  739. hbmDib = EngCreateBitmap(pdsurf->sizl, 0, ppdev->iBitmapFormat,
  740. BMF_TOPDOWN, NULL);
  741. if (hbmDib)
  742. {
  743. if (EngAssociateSurface((HSURF) hbmDib, ppdev->hdevEng, 0))
  744. {
  745. pso = EngLockSurface((HSURF) hbmDib);
  746. if (pso != NULL)
  747. {
  748. rclDst.left = 0;
  749. rclDst.top = 0;
  750. rclDst.right = pdsurf->sizl.cx;
  751. rclDst.bottom = pdsurf->sizl.cy;
  752. ptlSrc.x = poh->x;
  753. ptlSrc.y = poh->y;
  754. ppdev->pfnGetBits(ppdev, pso, &rclDst, &ptlSrc);
  755. pdsurf->dt = DT_DIB;
  756. pdsurf->pso = pso;
  757. // Don't even bother checking to see if this DIB should
  758. // be put back into off-screen memory until the next
  759. // heap 'free' occurs:
  760. pdsurf->iUniq = ppdev->iHeapUniq;
  761. pdsurf->cBlt = 0;
  762. // Remove this node from the off-screen DFB list, and free
  763. // it. 'pohFree' will never return NULL:
  764. return(pohFree(ppdev, poh));
  765. }
  766. }
  767. // Fail case:
  768. EngDeleteSurface((HSURF) hbmDib);
  769. }
  770. return(NULL);
  771. }
  772. /******************************Public*Routine******************************\
  773. * BOOL bMoveEverythingFromOffscreenToDibs
  774. *
  775. * This function is used when we're about to enter full-screen mode, which
  776. * would wipe all our off-screen bitmaps. GDI can ask us to draw on
  777. * device bitmaps even when we're in full-screen mode, and we do NOT have
  778. * the option of stalling the call until we switch out of full-screen.
  779. * We have no choice but to move all the off-screen DFBs to DIBs.
  780. *
  781. * Returns TRUE if all DSURFs have been successfully moved.
  782. *
  783. \**************************************************************************/
  784. BOOL bMoveAllDfbsFromOffscreenToDibs(
  785. PDEV* ppdev)
  786. {
  787. OH* poh;
  788. OH* pohNext;
  789. BOOL bRet;
  790. bRet = TRUE;
  791. poh = ppdev->heap.ohDfb.pohNext;
  792. while (poh != &ppdev->heap.ohDfb)
  793. {
  794. pohNext = poh->pohNext;
  795. // If something's already a DIB, we shouldn't try to make it even
  796. // more of a DIB:
  797. #if 1 //hp#1
  798. if (!(poh->ofl & OFL_PERMANENT) && (poh->pdsurf->dt == DT_SCREEN))
  799. #else
  800. if (poh->pdsurf->dt == DT_SCREEN)
  801. #endif
  802. {
  803. if (!pohMoveOffscreenDfbToDib(ppdev, poh))
  804. bRet = FALSE;
  805. }
  806. poh = pohNext;
  807. }
  808. return(bRet);
  809. }
  810. /******************************Public*Routine******************************\
  811. * HBITMAP DrvCreateDeviceBitmap
  812. *
  813. * Function called by GDI to create a device-format-bitmap (DFB). We will
  814. * always try to allocate the bitmap in off-screen; if we can't, we simply
  815. * fail the call and GDI will create and manage the bitmap itself.
  816. *
  817. * Note: We do not have to zero the bitmap bits. GDI will automatically
  818. * call us via DrvBitBlt to zero the bits (which is a security
  819. * consideration).
  820. *
  821. \**************************************************************************/
  822. HBITMAP DrvCreateDeviceBitmap(
  823. DHPDEV dhpdev,
  824. SIZEL sizl,
  825. ULONG iFormat)
  826. {
  827. PDEV* ppdev;
  828. OH* poh;
  829. DSURF* pdsurf;
  830. HBITMAP hbmDevice;
  831. ppdev = (PDEV*) dhpdev;
  832. // If we're in full-screen mode, we hardly have any off-screen memory
  833. // in which to allocate a DFB. LATER: We could still allocate an
  834. // OH node and put the bitmap on the DIB DFB list for later promotion.
  835. if (!ppdev->bEnabled)
  836. return(0);
  837. #if DBG
  838. if(!gbEnableDFB)
  839. return(0);
  840. #endif
  841. #if (_WIN32_WINNT >= 0x0400) //#pat08
  842. #if 1 //hp#2
  843. if ((sizl.cx < 20) || ((sizl.cx >= 32) && (sizl.cx < 100)))
  844. {
  845. return(0);
  846. }
  847. #endif
  848. //pat08 begin
  849. #else
  850. if ((ppdev->ulChipID != CL7541_ID) && (ppdev->ulChipID == CL7543_ID) &&
  851. (ppdev->ulChipID != CL7542_ID) && (ppdev->ulChipID == CL7548_ID) &&
  852. (ppdev->ulChipID != CL7555_ID) && (ppdev->ulChipID == CL7556_ID))
  853. {
  854. #if 1 //hp#2
  855. if ((sizl.cx < 20) || ((sizl.cx >= 32) && (sizl.cx < 100)))
  856. {
  857. return(0);
  858. }
  859. #endif
  860. }
  861. #endif
  862. //pat08 end
  863. // We only support device bitmaps that are the same colour depth
  864. // as our display.
  865. //
  866. // Actually, those are the only kind GDI will ever call us with,
  867. // but we may as well check. Note that this implies you'll never
  868. // get a crack at 1bpp bitmaps.
  869. if (iFormat != ppdev->iBitmapFormat)
  870. return(0);
  871. // We don't want anything 8x8 or smaller -- they're typically brush
  872. // patterns which we don't particularly want to stash in off-screen
  873. // memory:
  874. if ((sizl.cx <= 8) && (sizl.cy <= 8))
  875. return(0);
  876. poh = pohAllocate(ppdev, sizl.cx, sizl.cy, 0);
  877. if (poh != NULL)
  878. {
  879. pdsurf = ALLOC(sizeof(DSURF));
  880. if (pdsurf != NULL)
  881. {
  882. hbmDevice = EngCreateDeviceBitmap((DHSURF) pdsurf, sizl, iFormat);
  883. if (hbmDevice != NULL)
  884. {
  885. if (EngAssociateSurface((HSURF) hbmDevice, ppdev->hdevEng,
  886. ppdev->flHooks))
  887. {
  888. pdsurf->dt = DT_SCREEN;
  889. pdsurf->poh = poh;
  890. pdsurf->sizl = sizl;
  891. pdsurf->ppdev = ppdev;
  892. poh->pdsurf = pdsurf;
  893. return(hbmDevice);
  894. }
  895. EngDeleteSurface((HSURF) hbmDevice);
  896. }
  897. FREE(pdsurf);
  898. }
  899. pohFree(ppdev, poh);
  900. }
  901. return(0);
  902. }
  903. /******************************Public*Routine******************************\
  904. * VOID DrvDeleteDeviceBitmap
  905. *
  906. * Deletes a DFB.
  907. *
  908. \**************************************************************************/
  909. VOID DrvDeleteDeviceBitmap(
  910. DHSURF dhsurf)
  911. {
  912. DSURF* pdsurf;
  913. PDEV* ppdev;
  914. SURFOBJ* psoDib;
  915. HSURF hsurfDib;
  916. pdsurf = (DSURF*) dhsurf;
  917. ppdev = pdsurf->ppdev;
  918. if (pdsurf->dt == DT_SCREEN)
  919. {
  920. pohFree(ppdev, pdsurf->poh);
  921. }
  922. else
  923. {
  924. ASSERTDD(pdsurf->dt == DT_DIB, "Expected DIB type");
  925. psoDib = pdsurf->pso;
  926. // Get the hsurf from the SURFOBJ before we unlock it (it's not
  927. // legal to dereference psoDib when it's unlocked):
  928. hsurfDib = psoDib->hsurf;
  929. EngUnlockSurface(psoDib);
  930. EngDeleteSurface(hsurfDib);
  931. }
  932. FREE(pdsurf);
  933. }
  934. /******************************Public*Routine******************************\
  935. * BOOL bAssertModeOffscreenHeap
  936. *
  937. * This function is called whenever we switch in or out of full-screen
  938. * mode. We have to convert all the off-screen bitmaps to DIBs when
  939. * we switch to full-screen (because we may be asked to draw on them even
  940. * when in full-screen, and the mode switch would probably nuke the video
  941. * memory contents anyway).
  942. *
  943. \**************************************************************************/
  944. BOOL bAssertModeOffscreenHeap(
  945. PDEV* ppdev,
  946. BOOL bEnable)
  947. {
  948. BOOL b;
  949. b = TRUE;
  950. if (!bEnable)
  951. {
  952. b = bMoveAllDfbsFromOffscreenToDibs(ppdev);
  953. }
  954. return(b);
  955. }
  956. /******************************Public*Routine******************************\
  957. * VOID vDisableOffscreenHeap
  958. *
  959. * Frees any resources allocated by the off-screen heap.
  960. *
  961. \**************************************************************************/
  962. VOID vDisableOffscreenHeap(
  963. PDEV* ppdev)
  964. {
  965. OHALLOC* poha;
  966. OHALLOC* pohaNext;
  967. SURFOBJ* psoPunt;
  968. HSURF hsurf;
  969. psoPunt = ppdev->psoPunt;
  970. if (psoPunt != NULL)
  971. {
  972. hsurf = psoPunt->hsurf;
  973. EngUnlockSurface(psoPunt);
  974. EngDeleteSurface(hsurf);
  975. }
  976. psoPunt = ppdev->psoPunt2;
  977. if (psoPunt != NULL)
  978. {
  979. hsurf = psoPunt->hsurf;
  980. EngUnlockSurface(psoPunt);
  981. EngDeleteSurface(hsurf);
  982. }
  983. poha = ppdev->heap.pohaChain;
  984. while (poha != NULL)
  985. {
  986. pohaNext = poha->pohaNext; // Grab the next pointer before it's freed
  987. FREE(poha);
  988. poha = pohaNext;
  989. }
  990. }
  991. /******************************Public*Routine******************************\
  992. * BOOL bEnableOffscreenHeap
  993. *
  994. * Initializes the off-screen heap using all available video memory,
  995. * accounting for the portion taken by the visible screen.
  996. *
  997. * Input: ppdev->cxScreen
  998. * ppdev->cyScreen
  999. * ppdev->cxMemory
  1000. * ppdev->cyMemory
  1001. *
  1002. \**************************************************************************/
  1003. BOOL bEnableOffscreenHeap(
  1004. PDEV* ppdev)
  1005. {
  1006. OH* poh;
  1007. SIZEL sizl;
  1008. HSURF hsurf;
  1009. static onetimealloc = 0; //pat04
  1010. FLONG flPuntSurfaceHooks = ppdev->flHooks & ~HOOK_SYNCHRONIZE;
  1011. DISPDBG((5, "Screen: %li x %li Memory: %li x %li",
  1012. ppdev->cxScreen, ppdev->cyScreen, ppdev->cxMemory, ppdev->cyMemory));
  1013. ppdev->heap.pohaChain = NULL;
  1014. ppdev->heap.pohFreeList = NULL;
  1015. // Initialize the available list, which will be a circular
  1016. // doubly-linked list kept in ascending 'cxcy' order, with a
  1017. // 'sentinel' at the end of the list:
  1018. poh = pohNewNode(ppdev);
  1019. if (poh == NULL)
  1020. goto ReturnFalse;
  1021. // The first node describes the entire video memory size:
  1022. poh->pohNext = &ppdev->heap.ohAvailable;
  1023. poh->pohPrev = &ppdev->heap.ohAvailable;
  1024. poh->ofl = OFL_AVAILABLE;
  1025. poh->x = 0;
  1026. poh->y = 0;
  1027. poh->xy = 0;
  1028. poh->cx = ppdev->cxMemory;
  1029. poh->cy = ppdev->cyMemory;
  1030. poh->cxcy = CXCY(ppdev->cxMemory, ppdev->cyMemory);
  1031. poh->pohLeft = &ppdev->heap.ohAvailable;
  1032. poh->pohUp = &ppdev->heap.ohAvailable;
  1033. poh->pohRight = &ppdev->heap.ohAvailable;
  1034. poh->pohDown = &ppdev->heap.ohAvailable;
  1035. poh->pvScan0 = ppdev->pjScreen;
  1036. // The second node is our available list sentinel:
  1037. ppdev->heap.ohAvailable.pohNext = poh;
  1038. ppdev->heap.ohAvailable.pohPrev = poh;
  1039. ppdev->heap.ohAvailable.cxcy = CXCY_SENTINEL;
  1040. ppdev->heap.ohAvailable.cx = 0x7fffffff;
  1041. ppdev->heap.ohAvailable.cy = 0x7fffffff;
  1042. ppdev->heap.ohAvailable.ofl = OFL_PERMANENT;
  1043. ppdev->heap.ohDfb.pohLeft = NULL;
  1044. ppdev->heap.ohDfb.pohUp = NULL;
  1045. ppdev->heap.ohDfb.pohRight = NULL;
  1046. ppdev->heap.ohDfb.pohDown = NULL;
  1047. // Initialize the most-recently-blitted DFB list, which will be
  1048. // a circular doubly-linked list kept in order, with a sentinel at
  1049. // the end. This node is also used for the screen-surface, for its
  1050. // offset:
  1051. ppdev->heap.ohDfb.pohNext = &ppdev->heap.ohDfb;
  1052. ppdev->heap.ohDfb.pohPrev = &ppdev->heap.ohDfb;
  1053. ppdev->heap.ohDfb.ofl = OFL_PERMANENT;
  1054. // For the moment, make the max really big so that the first
  1055. // allocation we're about to do will succeed:
  1056. ppdev->heap.cxMax = 0x7fffffff;
  1057. ppdev->heap.cyMax = 0x7fffffff;
  1058. // Reserve the upper-left corner for the screen.
  1059. poh = pohAllocatePermanent(ppdev, ppdev->cxScreen, ppdev->cyScreen);
  1060. ppdev->pohScreen = poh;
  1061. ASSERTDD((poh != NULL) && (poh->x == 0) && (poh->y == 0),
  1062. "We assumed allocator would use the upper-left corner");
  1063. // Allocate a 'punt' SURFOBJ we'll use when the device-bitmap is in
  1064. // off-screen memory, but we want GDI to draw to it directly as an
  1065. // engine-managed surface:
  1066. sizl.cx = ppdev->cxMemory;
  1067. sizl.cy = ppdev->cyMemory;
  1068. // We want to create it with exactly the same hooks, capabilities,
  1069. // and screen delta as our primary surface:
  1070. hsurf = (HSURF) EngCreateBitmap(sizl,
  1071. ppdev->lDelta,
  1072. ppdev->iBitmapFormat,
  1073. BMF_TOPDOWN,
  1074. ppdev->pjScreen);
  1075. if ((hsurf == 0) ||
  1076. (!EngAssociateSurface(hsurf, ppdev->hdevEng, flPuntSurfaceHooks)) ||
  1077. (!(ppdev->psoPunt = EngLockSurface(hsurf))))
  1078. {
  1079. DISPDBG((0, "Failed punt surface creation"));
  1080. EngDeleteSurface(hsurf);
  1081. goto ReturnFalse;
  1082. }
  1083. // We need another for doing DrvBitBlt and DrvCopyBits when both
  1084. // surfaces are off-screen bitmaps:
  1085. hsurf = (HSURF) EngCreateBitmap(sizl,
  1086. ppdev->lDelta,
  1087. ppdev->iBitmapFormat,
  1088. BMF_TOPDOWN,
  1089. ppdev->pjScreen);
  1090. if ((hsurf == 0) ||
  1091. (!EngAssociateSurface(hsurf, ppdev->hdevEng, flPuntSurfaceHooks)) ||
  1092. (!(ppdev->psoPunt2 = EngLockSurface(hsurf))))
  1093. {
  1094. DISPDBG((0, "Failed punt surface creation"));
  1095. EngDeleteSurface(hsurf);
  1096. goto ReturnFalse;
  1097. }
  1098. DISPDBG((5, "Passed bEnableOffscreenHeap"));
  1099. // pat04 : for NT 3.51 S/W cursor, begin
  1100. #if (_WIN32_WINNT < 0x0400)
  1101. #ifdef PANNING_SCROLL
  1102. if ((ppdev->ulChipID == CL7541_ID) || (ppdev->ulChipID == CL7543_ID) ||
  1103. (ppdev->ulChipID == CL7542_ID) || (ppdev->ulChipID == CL7548_ID) ||
  1104. (ppdev->ulChipID == CL7555_ID) || (ppdev->ulChipID == CL7556_ID))
  1105. {
  1106. if (poh != NULL) {
  1107. if (onetimealloc == 0)
  1108. {
  1109. onetimealloc = 1;
  1110. ppdev->pjPointerAndCMask =
  1111. pohAllocatePermanent(ppdev, 32 * ppdev->cBpp, 32);
  1112. ppdev->pjCBackground =
  1113. pohAllocatePermanent (ppdev, 32 * ppdev->cBpp, 32);
  1114. ppdev->pjPointerCBitmap =
  1115. pohAllocatePermanent (ppdev, 32 * ppdev->cBpp, 32);
  1116. }
  1117. return(TRUE);
  1118. }
  1119. }
  1120. else
  1121. {
  1122. if (poh != NULL)
  1123. return(TRUE);
  1124. }
  1125. #else //myf-pat
  1126. if (poh != NULL)
  1127. return(TRUE);
  1128. #endif //myf-pat
  1129. #else // NT4.0 code
  1130. //pat04, end
  1131. if (poh != NULL)
  1132. return(TRUE);
  1133. #endif //pat04
  1134. ReturnFalse:
  1135. DISPDBG((0, "Failed bEnableOffscreenHeap"));
  1136. return(FALSE);
  1137. }
  1138.