1398 lines
41 KiB
C
1398 lines
41 KiB
C
/******************************************************************************\
|
||
*
|
||
* $Workfile: heap.c $
|
||
*
|
||
* This module contains the routines for a 2-d heap. It is used primarily
|
||
* for allocating space for device-format-bitmaps in off-screen memory.
|
||
*
|
||
* Off-screen bitmaps are a big deal on NT because:
|
||
*
|
||
* 1) It reduces the working set. Any bitmap stored in off-screen
|
||
* memory is a bitmap that isn't taking up space in main memory.
|
||
*
|
||
* 2) There is a speed win by using the accelerator hardware for
|
||
* drawing, in place of NT's GDI code. NT's GDI is written entirely
|
||
* in 'C++' and perhaps isn't as fast as it could be.
|
||
*
|
||
* 3) It leads naturally to nifty tricks that can take advantage of
|
||
* the hardware, such as MaskBlt support and cheap double buffering
|
||
* for OpenGL.
|
||
*
|
||
* The heap algorithm employed herein attempts to solve an unsolvable
|
||
* problem: the problem of keeping arbitrary sized bitmaps as packed as
|
||
* possible in a 2-d space, when the bitmaps can come and go at random.
|
||
*
|
||
* This problem is due entirely to the nature of the hardware for which this
|
||
* driver is written: the hardware treats everything as 2-d quantities. If
|
||
* the hardware bitmap pitch could be changed so that the bitmaps could be
|
||
* packed linearly in memory, the problem would be infinitely easier (it is
|
||
* much easier to track the memory, and the accelerator can be used to re-pack
|
||
* the heap to avoid segmentation).
|
||
*
|
||
* If your hardware can treat bitmaps as one dimensional quantities (as can
|
||
* the XGA and ATI), by all means please implement a new off-screen heap.
|
||
*
|
||
* When the heap gets full, old allocations will automatically be punted
|
||
* from off-screen and copied to DIBs, which we'll let GDI draw on.
|
||
*
|
||
* Note that this heap manages reverse-L shape off-screen memory
|
||
* configurations (where the scan pitch is longer than the visible screen,
|
||
* such as happens at 800x600 when the scan length must be a multiple of
|
||
* 1024).
|
||
*
|
||
* NOTE: All heap operations must be done under some sort of synchronization,
|
||
* whether it's controlled by GDI or explicitly by the driver. All
|
||
* the routines in this module assume that they have exclusive access
|
||
* to the heap data structures; multiple threads partying in here at
|
||
* the same time would be a Bad Thing. (By default, GDI does NOT
|
||
* synchronize drawing on device-created bitmaps.)
|
||
*
|
||
* Copyright (c) 1993-1995 Microsoft Corporation
|
||
* Copyright (c) 1996 Cirrus Logic, Inc.
|
||
*
|
||
* $Log: S:/projects/drivers/ntsrc/display/heap.c_v $
|
||
*
|
||
* Rev 1.3 Apr 03 1997 15:38:54 unknown
|
||
*
|
||
*
|
||
* Rev 1.2 28 Mar 1997 16:08:50 PLCHU
|
||
*
|
||
*
|
||
* Rev 1.1 Oct 10 1996 15:37:42 unknown
|
||
*
|
||
*
|
||
* Rev 1.8 12 Aug 1996 17:11:22 frido
|
||
* hp#1 - Commented new heap stuff.
|
||
* hp#2 - Keep enough memory for WinBench bitmap.
|
||
*
|
||
* Rev 1.7 12 Aug 1996 16:53:30 frido
|
||
* Added NT 3.5x/4.0 auto detection.
|
||
*
|
||
* Rev 1.6 23 Jul 1996 17:48:38 frido
|
||
* Removed creation of small device bitmaps.
|
||
* Never reject the WinBench bitmap!
|
||
*
|
||
* Rev 1.5 16 Jul 1996 18:55:52 frido
|
||
* Changed splitting of new block to cause less fragmentation.
|
||
*
|
||
* pat04: 12-20-96 : Supported NT3.51 software cursor with panning scrolling
|
||
* pat08: 04-01-97 : SW cursor problem due to code merge. Frido had turned
|
||
* of allocation of small device bitmaps for optimization,
|
||
* --- winnt to return a null ptr to a color bitmap mask.
|
||
*
|
||
\******************************************************************************/
|
||
|
||
#include "precomp.h"
|
||
|
||
#define OH_ALLOC_SIZE 4000 // Do all memory allocations in 4k chunks
|
||
#define OH_QUANTUM 8 // The minimum dimension of an allocation
|
||
#define CXCY_SENTINEL 0x7fffffff // The sentinel at the end of the available
|
||
// list has this very large 'cxcy' value
|
||
|
||
// This macro results in the available list being maintained with a
|
||
// cx-major, cy-minor sort:
|
||
|
||
#define CXCY(cx, cy) (((cx) << 16) | (cy))
|
||
|
||
#if DBG
|
||
BOOL gbEnableDFB = TRUE;
|
||
#endif
|
||
|
||
/******************************Public*Routine******************************\
|
||
* OH* pohNewNode
|
||
*
|
||
* Allocates a basic memory unit in which we'll pack our data structures.
|
||
*
|
||
* Since we'll have a lot of OH nodes, most of which we will be
|
||
* occasionally traversing, we do our own memory allocation scheme to
|
||
* keep them densely packed in memory.
|
||
*
|
||
* It would be the worst possible thing for the working set to simply
|
||
* call EngAllocMem(sizeof(OH)) every time we needed a new node. There
|
||
* would be no locality; OH nodes would get scattered throughout memory,
|
||
* and as we traversed the available list for one of our allocations,
|
||
* it would be far more likely that we would hit a hard page fault.
|
||
\**************************************************************************/
|
||
|
||
OH* pohNewNode(
|
||
PDEV* ppdev)
|
||
{
|
||
LONG i;
|
||
LONG cOhs;
|
||
OHALLOC* poha;
|
||
OH* poh;
|
||
|
||
if (ppdev->heap.pohFreeList == NULL)
|
||
{
|
||
// We zero-init to initialize all the OH flags, and to help in
|
||
// debugging (we can afford to do this since we'll be doing this
|
||
// very infrequently):
|
||
|
||
poha = ALLOC(OH_ALLOC_SIZE);
|
||
if (poha == NULL)
|
||
return(NULL);
|
||
|
||
// Insert this OHALLOC at the begining of the OHALLOC chain:
|
||
|
||
poha->pohaNext = ppdev->heap.pohaChain;
|
||
ppdev->heap.pohaChain = poha;
|
||
|
||
// This has a '+ 1' because OHALLOC includes an extra OH in its
|
||
// structure declaration:
|
||
|
||
cOhs = (OH_ALLOC_SIZE - sizeof(OHALLOC)) / sizeof(OH) + 1;
|
||
|
||
// The big OHALLOC allocation is simply a container for a bunch of
|
||
// OH data structures in an array. The new OH data structures are
|
||
// linked together and added to the OH free list:
|
||
|
||
poh = &poha->aoh[0];
|
||
for (i = cOhs - 1; i != 0; i--)
|
||
{
|
||
poh->pohNext = poh + 1;
|
||
poh = poh + 1;
|
||
}
|
||
|
||
poh->pohNext = NULL;
|
||
ppdev->heap.pohFreeList = &poha->aoh[0];
|
||
}
|
||
|
||
poh = ppdev->heap.pohFreeList;
|
||
ppdev->heap.pohFreeList = poh->pohNext;
|
||
|
||
return(poh);
|
||
}
|
||
|
||
/******************************Public*Routine******************************\
|
||
* VOID vOhFreeNode
|
||
*
|
||
* Frees our basic data structure allocation unit by adding it to a free
|
||
* list.
|
||
*
|
||
\**************************************************************************/
|
||
|
||
VOID vOhFreeNode(
|
||
PDEV* ppdev,
|
||
OH* poh)
|
||
{
|
||
if (poh == NULL)
|
||
return;
|
||
|
||
poh->pohNext = ppdev->heap.pohFreeList;
|
||
ppdev->heap.pohFreeList = poh;
|
||
poh->ofl = 0;
|
||
}
|
||
|
||
/******************************Public*Routine******************************\
|
||
* OH* pohFree
|
||
*
|
||
* Frees an off-screen heap allocation. The free space will be combined
|
||
* with any adjacent free spaces to avoid segmentation of the 2-d heap.
|
||
*
|
||
* Note: A key idea here is that the data structure for the upper-left-
|
||
* most node must be kept at the same physical CPU memory so that
|
||
* adjacency links are kept correctly (when two free spaces are
|
||
* merged, the lower or right node can be freed).
|
||
*
|
||
\**************************************************************************/
|
||
|
||
OH* pohFree(
|
||
PDEV* ppdev,
|
||
OH* poh)
|
||
{
|
||
ULONG cxcy;
|
||
OH* pohBeside;
|
||
OH* pohNext;
|
||
OH* pohPrev;
|
||
#if 1 //hp#1
|
||
BOOL bUpdate;
|
||
#endif
|
||
|
||
if (poh == NULL)
|
||
return(NULL);
|
||
|
||
#if 1 //hp#1
|
||
bUpdate = (poh->ofl & OFL_PERMANENT) != 0;
|
||
#endif
|
||
|
||
DISPDBG((4, "Freeing %d x %d at (%d, %d)", poh->cx, poh->cy, poh->x,
|
||
poh->y));
|
||
|
||
#if DEBUG_HEAP
|
||
{
|
||
RECTL rclBitmap;
|
||
RBRUSH_COLOR rbc;
|
||
LONG xOffset;
|
||
LONG yOffset;
|
||
LONG xyOffset;
|
||
|
||
rclBitmap.left = poh->x;
|
||
rclBitmap.top = poh->y;
|
||
rclBitmap.right = poh->x + poh->cx;
|
||
rclBitmap.bottom = poh->y + poh->cy;
|
||
|
||
xOffset = ppdev->xOffset;
|
||
yOffset = ppdev->yOffset;
|
||
xyOffset = ppdev->xyOffset;
|
||
|
||
ppdev->xOffset = 0;
|
||
ppdev->yOffset = 0;
|
||
ppdev->xyOffset = 0;
|
||
|
||
ppdev->pfnFillSolid(ppdev, 1, &rclBitmap, 0x0, rbc, NULL);
|
||
|
||
ppdev->xOffset = xOffset;
|
||
ppdev->yOffset = yOffset;
|
||
ppdev->xyOffset = xyOffset;
|
||
}
|
||
#endif
|
||
|
||
// Update the uniqueness to show that space has been freed, so that
|
||
// we may decide to see if some DIBs can be moved back into off-screen
|
||
// memory:
|
||
|
||
ppdev->iHeapUniq++;
|
||
|
||
MergeLoop:
|
||
|
||
#if 0 //hp#1
|
||
ASSERTDD(!(poh->ofl & OFL_PERMANENT), "Can't free permanents for now");
|
||
#endif
|
||
|
||
// Try merging with the right sibling:
|
||
|
||
pohBeside = poh->pohRight;
|
||
if ((pohBeside->ofl & OFL_AVAILABLE) &&
|
||
(pohBeside->cy == poh->cy) &&
|
||
(pohBeside->pohUp == poh->pohUp) &&
|
||
(pohBeside->pohDown == poh->pohDown) &&
|
||
(pohBeside->pohRight->pohLeft != pohBeside))
|
||
{
|
||
// Add the right rectangle to ours:
|
||
|
||
poh->cx += pohBeside->cx;
|
||
poh->pohRight = pohBeside->pohRight;
|
||
|
||
// Remove 'pohBeside' from the ??? list and free it:
|
||
|
||
pohBeside->pohNext->pohPrev = pohBeside->pohPrev;
|
||
pohBeside->pohPrev->pohNext = pohBeside->pohNext;
|
||
|
||
vOhFreeNode(ppdev, pohBeside);
|
||
goto MergeLoop;
|
||
}
|
||
|
||
// Try merging with the lower sibling:
|
||
|
||
pohBeside = poh->pohDown;
|
||
if ((pohBeside->ofl & OFL_AVAILABLE) &&
|
||
(pohBeside->cx == poh->cx) &&
|
||
(pohBeside->pohLeft == poh->pohLeft) &&
|
||
(pohBeside->pohRight == poh->pohRight) &&
|
||
(pohBeside->pohDown->pohUp != pohBeside))
|
||
{
|
||
poh->cy += pohBeside->cy;
|
||
poh->pohDown = pohBeside->pohDown;
|
||
|
||
pohBeside->pohNext->pohPrev = pohBeside->pohPrev;
|
||
pohBeside->pohPrev->pohNext = pohBeside->pohNext;
|
||
|
||
vOhFreeNode(ppdev, pohBeside);
|
||
goto MergeLoop;
|
||
}
|
||
|
||
// Try merging with the left sibling:
|
||
|
||
pohBeside = poh->pohLeft;
|
||
if ((pohBeside->ofl & OFL_AVAILABLE) &&
|
||
(pohBeside->cy == poh->cy) &&
|
||
(pohBeside->pohUp == poh->pohUp) &&
|
||
(pohBeside->pohDown == poh->pohDown) &&
|
||
(pohBeside->pohRight == poh) &&
|
||
(poh->pohRight->pohLeft != poh))
|
||
{
|
||
// We add our rectangle to the one to the left:
|
||
|
||
pohBeside->cx += poh->cx;
|
||
pohBeside->pohRight = poh->pohRight;
|
||
|
||
// Remove 'poh' from the ??? list and free it:
|
||
|
||
poh->pohNext->pohPrev = poh->pohPrev;
|
||
poh->pohPrev->pohNext = poh->pohNext;
|
||
|
||
vOhFreeNode(ppdev, poh);
|
||
|
||
poh = pohBeside;
|
||
goto MergeLoop;
|
||
}
|
||
|
||
// Try merging with the upper sibling:
|
||
|
||
pohBeside = poh->pohUp;
|
||
if ((pohBeside->ofl & OFL_AVAILABLE) &&
|
||
(pohBeside->cx == poh->cx) &&
|
||
(pohBeside->pohLeft == poh->pohLeft) &&
|
||
(pohBeside->pohRight == poh->pohRight) &&
|
||
(pohBeside->pohDown == poh) &&
|
||
(poh->pohDown->pohUp != poh))
|
||
{
|
||
pohBeside->cy += poh->cy;
|
||
pohBeside->pohDown = poh->pohDown;
|
||
|
||
poh->pohNext->pohPrev = poh->pohPrev;
|
||
poh->pohPrev->pohNext = poh->pohNext;
|
||
|
||
vOhFreeNode(ppdev, poh);
|
||
|
||
poh = pohBeside;
|
||
goto MergeLoop;
|
||
}
|
||
|
||
// Remove the node from the ???list if it was in use (we wouldn't
|
||
// want to do this for a OFL_PERMANENT node that had been freed):
|
||
|
||
poh->pohNext->pohPrev = poh->pohPrev;
|
||
poh->pohPrev->pohNext = poh->pohNext;
|
||
|
||
cxcy = CXCY(poh->cx, poh->cy);
|
||
|
||
// Insert the node into the available list:
|
||
|
||
pohNext = ppdev->heap.ohAvailable.pohNext;
|
||
while (pohNext->cxcy < cxcy)
|
||
{
|
||
pohNext = pohNext->pohNext;
|
||
}
|
||
pohPrev = pohNext->pohPrev;
|
||
|
||
pohPrev->pohNext = poh;
|
||
pohNext->pohPrev = poh;
|
||
poh->pohPrev = pohPrev;
|
||
poh->pohNext = pohNext;
|
||
poh->ofl = OFL_AVAILABLE;
|
||
poh->cxcy = cxcy;
|
||
|
||
#if 1 //hp#1
|
||
if (bUpdate)
|
||
{
|
||
vCalculateMaximum(ppdev);
|
||
}
|
||
#endif
|
||
|
||
// Return the node pointer for the new and improved available rectangle:
|
||
return(poh);
|
||
}
|
||
|
||
/******************************Public*Routine******************************\
|
||
* OH* pohAllocate
|
||
*
|
||
* Allocates space for an off-screen rectangle. It will attempt to find
|
||
* the smallest available free rectangle, and will allocate the block out
|
||
* of its upper-left corner. The remaining two rectangles will be placed
|
||
* on the available free space list.
|
||
*
|
||
* If the rectangle would have been large enough to fit into off-screen
|
||
* memory, but there is not enough available free space, we will boot
|
||
* bitmaps out of off-screen and into DIBs until there is enough room.
|
||
*
|
||
\**************************************************************************/
|
||
|
||
OH* pohAllocate(
|
||
PDEV* ppdev,
|
||
LONG cxThis, // Width of rectangle to be allocated
|
||
LONG cyThis, // Height of rectangle to be allocated
|
||
FLOH floh) // Allocation flags
|
||
{
|
||
ULONG cxcyThis; // Width and height search key
|
||
OH* pohThis; // Points to found available rectangle we'll use
|
||
ULONG cxcy; // Temporary versions
|
||
OH* pohNext;
|
||
OH* pohPrev;
|
||
|
||
LONG cxRem;
|
||
LONG cyRem;
|
||
|
||
OH* pohBelow;
|
||
LONG cxBelow;
|
||
LONG cyBelow;
|
||
|
||
OH* pohBeside;
|
||
LONG cxBeside;
|
||
LONG cyBeside;
|
||
|
||
DISPDBG((4, "Allocating %d x %d...", cxThis, cyThis));
|
||
|
||
ASSERTDD((cxThis > 0) && (cyThis > 0), "Illegal allocation size");
|
||
|
||
// Increase the width to get the proper alignment (thus ensuring that all
|
||
// allocations will be properly aligned):
|
||
|
||
cxThis = (cxThis + (HEAP_X_ALIGNMENT - 1)) & ~(HEAP_X_ALIGNMENT - 1);
|
||
|
||
// We can't succeed if the requested rectangle is larger than the
|
||
// largest possible available rectangle:
|
||
|
||
if ((cxThis > ppdev->heap.cxMax) || (cyThis > ppdev->heap.cyMax))
|
||
{
|
||
#if 1 //hp#2
|
||
if ((cxThis != 400) && (cyThis != 90))
|
||
#endif
|
||
{
|
||
DISPDBG((4, "Failing pohAllocate... rectangle is larger than max allowed"));
|
||
DISPDBG((4, "max = (%d,%d)", ppdev->heap.cxMax, ppdev->heap.cyMax));
|
||
DISPDBG((4, "req = (%d,%d)", cxThis, cyThis));
|
||
return(NULL);
|
||
}
|
||
}
|
||
|
||
// Find the first available rectangle the same size or larger than
|
||
// the requested one:
|
||
|
||
cxcyThis = CXCY(cxThis, cyThis);
|
||
pohThis = ppdev->heap.ohAvailable.pohNext;
|
||
while (pohThis->cxcy < cxcyThis)
|
||
{
|
||
pohThis = pohThis->pohNext;
|
||
}
|
||
|
||
while (pohThis->cy < cyThis)
|
||
{
|
||
pohThis = pohThis->pohNext;
|
||
}
|
||
|
||
if (pohThis->cxcy == CXCY_SENTINEL)
|
||
{
|
||
// There was no space large enough...
|
||
|
||
if (floh & FLOH_ONLY_IF_ROOM)
|
||
{
|
||
DISPDBG((4, "Failing pohAllocate... no space large enough"));
|
||
DISPDBG((4, "req = (%d,%d)", cxThis, cyThis));
|
||
return(NULL);
|
||
}
|
||
|
||
// We couldn't find an available rectangle that was big enough
|
||
// to fit our request. So throw things out of the heap until we
|
||
// have room:
|
||
|
||
do {
|
||
pohThis = ppdev->heap.ohDfb.pohPrev; // Least-recently blitted
|
||
|
||
ASSERTDD(pohThis != &ppdev->heap.ohDfb, "Ran out of in-use entries");
|
||
|
||
#if 1 //hp#1
|
||
while (pohThis->ofl == OFL_PERMANENT)
|
||
{
|
||
pohThis = pohThis->pohPrev;
|
||
if (pohThis == &ppdev->heap.ohDfb)
|
||
{
|
||
DISPDBG((4, "Failing pohAllocate... not enough memory"));
|
||
DISPDBG((4, "req = (%d,%d)", cxThis, cyThis));
|
||
return(NULL);
|
||
}
|
||
}
|
||
#endif
|
||
// We can safely exit here if we have to:
|
||
|
||
pohThis = pohMoveOffscreenDfbToDib(ppdev, pohThis);
|
||
if (pohThis == NULL)
|
||
{
|
||
DISPDBG((4, "Failing pohAllocate... failed to eject a dfb"));
|
||
DISPDBG((4, "req = (%d,%d)", cxThis, cyThis));
|
||
return(NULL);
|
||
}
|
||
|
||
} while ((pohThis->cx < cxThis) || (pohThis->cy < cyThis));
|
||
}
|
||
|
||
// We've now found an available rectangle that is the same size or
|
||
// bigger than our requested rectangle. We're going to use the
|
||
// upper-left corner of our found rectangle, and divide the unused
|
||
// remainder into two rectangles which will go on the available
|
||
// list.
|
||
|
||
// Compute the width of the unused rectangle to the right, and the
|
||
// height of the unused rectangle below:
|
||
|
||
cyRem = pohThis->cy - cyThis;
|
||
cxRem = pohThis->cx - cxThis;
|
||
|
||
// Given finite area, we wish to find the two rectangles that are
|
||
// most square -- i.e., the arrangement that gives two rectangles
|
||
// with the least perimiter:
|
||
|
||
cyBelow = cyRem;
|
||
cxBeside = cxRem;
|
||
|
||
#if 1 //hp#1
|
||
if ((cxRem <= cyRem) || (pohThis->cx >= ppdev->cxScreen))
|
||
#else
|
||
if (cxRem <= cyRem)
|
||
#endif
|
||
{
|
||
cxBelow = cxThis + cxRem;
|
||
cyBeside = cyThis;
|
||
}
|
||
else
|
||
{
|
||
cxBelow = cxThis;
|
||
cyBeside = cyThis + cyRem;
|
||
}
|
||
|
||
// We only make new available rectangles of the unused right and bottom
|
||
// portions if they're greater in dimension than OH_QUANTUM (it hardly
|
||
// makes sense to do the book-work to keep around a 2-pixel wide
|
||
// available space, for example):
|
||
|
||
pohBeside = NULL;
|
||
if (cxBeside >= OH_QUANTUM)
|
||
{
|
||
pohBeside = pohNewNode(ppdev);
|
||
if (pohBeside == NULL)
|
||
return(NULL);
|
||
}
|
||
|
||
pohBelow = NULL;
|
||
if (cyBelow >= OH_QUANTUM)
|
||
{
|
||
pohBelow = pohNewNode(ppdev);
|
||
if (pohBelow == NULL)
|
||
{
|
||
vOhFreeNode(ppdev, pohBeside);
|
||
return(NULL);
|
||
}
|
||
|
||
// Insert this rectangle into the available list (which is
|
||
// sorted on ascending cxcy):
|
||
|
||
cxcy = CXCY(cxBelow, cyBelow);
|
||
pohNext = ppdev->heap.ohAvailable.pohNext;
|
||
while (pohNext->cxcy < cxcy)
|
||
{
|
||
pohNext = pohNext->pohNext;
|
||
}
|
||
pohPrev = pohNext->pohPrev;
|
||
|
||
pohPrev->pohNext = pohBelow;
|
||
pohNext->pohPrev = pohBelow;
|
||
pohBelow->pohPrev = pohPrev;
|
||
pohBelow->pohNext = pohNext;
|
||
|
||
// Now update the adjacency information:
|
||
|
||
pohBelow->pohLeft = pohThis->pohLeft;
|
||
pohBelow->pohUp = pohThis;
|
||
pohBelow->pohRight = pohThis->pohRight;
|
||
pohBelow->pohDown = pohThis->pohDown;
|
||
|
||
// Update the rest of the new node information:
|
||
|
||
pohBelow->cxcy = cxcy;
|
||
pohBelow->ofl = OFL_AVAILABLE;
|
||
|
||
pohBelow->x = pohThis->x;
|
||
pohBelow->y = pohThis->y + cyThis;
|
||
pohBelow->xy = PELS_TO_BYTES(pohBelow->x)
|
||
+ (pohBelow->y * ppdev->lDelta);
|
||
|
||
pohBelow->cx = cxBelow;
|
||
pohBelow->cy = cyBelow;
|
||
|
||
// Modify the current node to reflect the changes we've made:
|
||
|
||
pohThis->cy = cyThis;
|
||
}
|
||
|
||
if (cxBeside >= OH_QUANTUM)
|
||
{
|
||
// Insert this rectangle into the available list (which is
|
||
// sorted on ascending cxcy):
|
||
|
||
cxcy = CXCY(cxBeside, cyBeside);
|
||
pohNext = ppdev->heap.ohAvailable.pohNext;
|
||
while (pohNext->cxcy < cxcy)
|
||
{
|
||
pohNext = pohNext->pohNext;
|
||
}
|
||
pohPrev = pohNext->pohPrev;
|
||
|
||
pohPrev->pohNext = pohBeside;
|
||
pohNext->pohPrev = pohBeside;
|
||
pohBeside->pohPrev = pohPrev;
|
||
pohBeside->pohNext = pohNext;
|
||
|
||
// Now update the adjacency information:
|
||
|
||
pohBeside->pohUp = pohThis->pohUp;
|
||
pohBeside->pohLeft = pohThis;
|
||
pohBeside->pohDown = pohThis->pohDown;
|
||
pohBeside->pohRight = pohThis->pohRight;
|
||
|
||
// Update the rest of the new node information:
|
||
|
||
pohBeside->cxcy = cxcy;
|
||
pohBeside->ofl = OFL_AVAILABLE;
|
||
|
||
pohBeside->x = pohThis->x + cxThis;
|
||
pohBeside->y = pohThis->y;
|
||
pohBeside->xy = PELS_TO_BYTES(pohBeside->x)
|
||
+ (pohBeside->y * ppdev->lDelta);
|
||
|
||
pohBeside->cx = cxBeside;
|
||
pohBeside->cy = cyBeside;
|
||
|
||
// Modify the current node to reflect the changes we've made:
|
||
|
||
pohThis->cx = cxThis;
|
||
}
|
||
|
||
if (pohBelow != NULL)
|
||
{
|
||
pohThis->pohDown = pohBelow;
|
||
if ((pohBeside != NULL) && (cyBeside == pohThis->cy))
|
||
pohBeside->pohDown = pohBelow;
|
||
}
|
||
if (pohBeside != NULL)
|
||
{
|
||
pohThis->pohRight = pohBeside;
|
||
if ((pohBelow != NULL) && (cxBelow == pohThis->cx))
|
||
pohBelow->pohRight = pohBeside;
|
||
}
|
||
|
||
pohThis->ofl = OFL_INUSE;
|
||
pohThis->cxcy = CXCY(pohThis->cx, pohThis->cy);
|
||
pohThis->pdsurf = NULL; // Caller is responsible for setting this field
|
||
|
||
// Remove this from the available list:
|
||
|
||
pohThis->pohPrev->pohNext = pohThis->pohNext;
|
||
pohThis->pohNext->pohPrev = pohThis->pohPrev;
|
||
|
||
// Now insert this at the head of the DFB list:
|
||
|
||
pohThis->pohNext = ppdev->heap.ohDfb.pohNext;
|
||
pohThis->pohPrev = &ppdev->heap.ohDfb;
|
||
ppdev->heap.ohDfb.pohNext->pohPrev = pohThis;
|
||
ppdev->heap.ohDfb.pohNext = pohThis;
|
||
|
||
DISPDBG((4, " Allocated at (%d, %d)", pohThis->x, pohThis->y));
|
||
|
||
// Calculate the effective start address for this bitmap in off-
|
||
// screen memory:
|
||
|
||
pohThis->pvScan0 = ppdev->pjScreen + (pohThis->y * ppdev->lDelta)
|
||
+ PELS_TO_BYTES(pohThis->x);
|
||
return(pohThis);
|
||
}
|
||
|
||
/******************************Public*Routine******************************\
|
||
* VOID vCalculateMaxmimum
|
||
*
|
||
* Traverses the list of in-use and available rectangles to find the one
|
||
* with the maximal area.
|
||
*
|
||
\**************************************************************************/
|
||
VOID vCalculateMaximum(
|
||
PDEV* ppdev)
|
||
{
|
||
OH* poh;
|
||
OH* pohSentinel;
|
||
LONG lArea;
|
||
LONG lMaxArea;
|
||
LONG cxMax;
|
||
LONG cyMax;
|
||
LONG i;
|
||
|
||
lMaxArea = 0;
|
||
cxMax = 0;
|
||
cyMax = 0;
|
||
|
||
// First time through, loop through the list of available rectangles:
|
||
|
||
pohSentinel = &ppdev->heap.ohAvailable;
|
||
|
||
for (i = 2; i != 0; i--)
|
||
{
|
||
for (poh = pohSentinel->pohNext; poh != pohSentinel; poh = poh->pohNext)
|
||
{
|
||
#if 1 //hp#1
|
||
if (poh->ofl & OFL_PERMANENT)
|
||
{
|
||
continue;
|
||
}
|
||
#else
|
||
ASSERTDD(!(poh->ofl & OFL_PERMANENT),
|
||
"Permanent in available/DFB chain?");
|
||
#endif
|
||
|
||
// We don't have worry about this multiply overflowing
|
||
// because we are dealing in physical screen coordinates,
|
||
// which will probably never be more than 15 bits:
|
||
|
||
lArea = poh->cx * poh->cy;
|
||
if (lArea > lMaxArea)
|
||
{
|
||
cxMax = poh->cx;
|
||
cyMax = poh->cy;
|
||
lMaxArea = lArea;
|
||
}
|
||
}
|
||
|
||
// Second time through, loop through the list of in-use rectangles:
|
||
|
||
pohSentinel = &ppdev->heap.ohDfb;
|
||
}
|
||
|
||
// All that we are interested in is the dimensions of the rectangle
|
||
// that has the largest possible available area (and remember that
|
||
// there might not be any possible available area):
|
||
|
||
ppdev->heap.cxMax = cxMax;
|
||
ppdev->heap.cyMax = cyMax;
|
||
|
||
DISPDBG((1, "Maximum heap: %d x %d", cxMax, cyMax));
|
||
}
|
||
|
||
/******************************Public*Routine******************************\
|
||
* OH* pohAllocatePermanent
|
||
*
|
||
* Allocates an off-screen rectangle that can never be booted of the heap.
|
||
* It's the caller's responsibility to manage the rectangle, which includes
|
||
* what to do with the memory in DrvAssertMode when the display is changed
|
||
* to full-screen mode.
|
||
*
|
||
\**************************************************************************/
|
||
|
||
OH* pohAllocatePermanent(
|
||
PDEV* ppdev,
|
||
LONG cx,
|
||
LONG cy)
|
||
{
|
||
OH* poh;
|
||
|
||
poh = pohAllocate(ppdev, cx, cy, 0);
|
||
if (poh != NULL)
|
||
{
|
||
// Mark the rectangle as permanent:
|
||
|
||
poh->ofl = OFL_PERMANENT;
|
||
|
||
#if 0 //hp#1
|
||
// Remove the node from the most-recently blitted list:
|
||
|
||
poh->pohPrev->pohNext = poh->pohNext;
|
||
poh->pohNext->pohPrev = poh->pohPrev;
|
||
poh->pohPrev = NULL;
|
||
poh->pohNext = NULL;
|
||
#endif
|
||
|
||
// Now calculate the new maximum size rectangle available in the
|
||
// heap:
|
||
vCalculateMaximum(ppdev);
|
||
}
|
||
|
||
return(poh);
|
||
}
|
||
|
||
/******************************Public*Routine******************************\
|
||
* BOOL bMoveDibToOffscreenDfbIfRoom
|
||
*
|
||
* Converts the DIB DFB to an off-screen DFB, if there's room for it in
|
||
* off-screen memory.
|
||
*
|
||
* Returns: FALSE if there wasn't room, TRUE if successfully moved.
|
||
*
|
||
\**************************************************************************/
|
||
|
||
BOOL bMoveDibToOffscreenDfbIfRoom(
|
||
PDEV* ppdev,
|
||
DSURF* pdsurf)
|
||
{
|
||
OH* poh;
|
||
SURFOBJ* pso;
|
||
RECTL rclDst;
|
||
POINTL ptlSrc;
|
||
HSURF hsurf;
|
||
|
||
ASSERTDD(pdsurf->dt == DT_DIB,
|
||
"Can't move a bitmap off-screen when it's already off-screen");
|
||
|
||
DISPDBG((4, "Trying to reload %d x %d surface", pdsurf->sizl.cx,
|
||
pdsurf->sizl.cy));
|
||
|
||
// If we're in full-screen mode, we can't move anything to off-screen
|
||
// memory:
|
||
|
||
if (!ppdev->bEnabled)
|
||
return(FALSE);
|
||
|
||
poh = pohAllocate(ppdev, pdsurf->sizl.cx, pdsurf->sizl.cy,
|
||
FLOH_ONLY_IF_ROOM);
|
||
if (poh == NULL)
|
||
{
|
||
// There wasn't any free room.
|
||
|
||
return(FALSE);
|
||
}
|
||
|
||
// 'pdsurf->sizl' is the actual bitmap dimension, not 'poh->cx' or
|
||
// 'poh->cy'.
|
||
|
||
rclDst.left = poh->x;
|
||
rclDst.top = poh->y;
|
||
rclDst.right = rclDst.left + pdsurf->sizl.cx;
|
||
rclDst.bottom = rclDst.top + pdsurf->sizl.cy;
|
||
|
||
ptlSrc.x = 0;
|
||
ptlSrc.y = 0;
|
||
|
||
ppdev->pfnPutBits(ppdev, pdsurf->pso, &rclDst, &ptlSrc);
|
||
|
||
// Update the data structures to reflect the new off-screen node:
|
||
|
||
pso = pdsurf->pso;
|
||
pdsurf->dt = DT_SCREEN;
|
||
pdsurf->poh = poh;
|
||
poh->pdsurf = pdsurf;
|
||
|
||
// Now free the DIB. Get the hsurf from the SURFOBJ before we unlock
|
||
// it (it's not legal to dereference psoDib when it's unlocked):
|
||
|
||
hsurf = pso->hsurf;
|
||
EngUnlockSurface(pso);
|
||
EngDeleteSurface(hsurf);
|
||
|
||
return(TRUE);
|
||
}
|
||
|
||
/******************************Public*Routine******************************\
|
||
* OH* pohMoveOffscreenDfbToDib
|
||
*
|
||
* Converts the DFB from being off-screen to being a DIB.
|
||
*
|
||
* Note: The caller does NOT have to call 'pohFree' on 'poh' after making
|
||
* this call.
|
||
*
|
||
* Returns: NULL if the function failed (due to a memory allocation).
|
||
* Otherwise, it returns a pointer to the coalesced off-screen heap
|
||
* node that has been made available for subsequent allocations
|
||
* (useful when trying to free enough memory to make a new
|
||
* allocation).
|
||
\**************************************************************************/
|
||
|
||
OH* pohMoveOffscreenDfbToDib(
|
||
PDEV* ppdev,
|
||
OH* poh)
|
||
{
|
||
DSURF* pdsurf;
|
||
HBITMAP hbmDib;
|
||
SURFOBJ* pso;
|
||
RECTL rclDst;
|
||
POINTL ptlSrc;
|
||
|
||
DISPDBG((4, "Throwing out %li x %li at (%li, %li)!",
|
||
poh->cx, poh->cy, poh->x, poh->y));
|
||
|
||
#if 1 //hp#1
|
||
if (poh->ofl & OFL_PERMANENT)
|
||
{
|
||
return(NULL);
|
||
}
|
||
#endif
|
||
|
||
pdsurf = poh->pdsurf;
|
||
|
||
ASSERTDD((poh->x != 0) || (poh->y != 0),
|
||
"Can't make the visible screen into a DIB");
|
||
ASSERTDD(pdsurf->dt != DT_DIB,
|
||
"Can't make a DIB into even more of a DIB");
|
||
|
||
hbmDib = EngCreateBitmap(pdsurf->sizl, 0, ppdev->iBitmapFormat,
|
||
BMF_TOPDOWN, NULL);
|
||
if (hbmDib)
|
||
{
|
||
if (EngAssociateSurface((HSURF) hbmDib, ppdev->hdevEng, 0))
|
||
{
|
||
pso = EngLockSurface((HSURF) hbmDib);
|
||
if (pso != NULL)
|
||
{
|
||
rclDst.left = 0;
|
||
rclDst.top = 0;
|
||
rclDst.right = pdsurf->sizl.cx;
|
||
rclDst.bottom = pdsurf->sizl.cy;
|
||
|
||
ptlSrc.x = poh->x;
|
||
ptlSrc.y = poh->y;
|
||
|
||
ppdev->pfnGetBits(ppdev, pso, &rclDst, &ptlSrc);
|
||
|
||
pdsurf->dt = DT_DIB;
|
||
pdsurf->pso = pso;
|
||
|
||
// Don't even bother checking to see if this DIB should
|
||
// be put back into off-screen memory until the next
|
||
// heap 'free' occurs:
|
||
|
||
pdsurf->iUniq = ppdev->iHeapUniq;
|
||
pdsurf->cBlt = 0;
|
||
|
||
// Remove this node from the off-screen DFB list, and free
|
||
// it. 'pohFree' will never return NULL:
|
||
|
||
return(pohFree(ppdev, poh));
|
||
}
|
||
}
|
||
|
||
// Fail case:
|
||
|
||
EngDeleteSurface((HSURF) hbmDib);
|
||
}
|
||
|
||
return(NULL);
|
||
}
|
||
|
||
/******************************Public*Routine******************************\
|
||
* BOOL bMoveEverythingFromOffscreenToDibs
|
||
*
|
||
* This function is used when we're about to enter full-screen mode, which
|
||
* would wipe all our off-screen bitmaps. GDI can ask us to draw on
|
||
* device bitmaps even when we're in full-screen mode, and we do NOT have
|
||
* the option of stalling the call until we switch out of full-screen.
|
||
* We have no choice but to move all the off-screen DFBs to DIBs.
|
||
*
|
||
* Returns TRUE if all DSURFs have been successfully moved.
|
||
*
|
||
\**************************************************************************/
|
||
|
||
BOOL bMoveAllDfbsFromOffscreenToDibs(
|
||
PDEV* ppdev)
|
||
{
|
||
OH* poh;
|
||
OH* pohNext;
|
||
BOOL bRet;
|
||
|
||
bRet = TRUE;
|
||
poh = ppdev->heap.ohDfb.pohNext;
|
||
while (poh != &ppdev->heap.ohDfb)
|
||
{
|
||
pohNext = poh->pohNext;
|
||
|
||
// If something's already a DIB, we shouldn't try to make it even
|
||
// more of a DIB:
|
||
|
||
#if 1 //hp#1
|
||
if (!(poh->ofl & OFL_PERMANENT) && (poh->pdsurf->dt == DT_SCREEN))
|
||
#else
|
||
if (poh->pdsurf->dt == DT_SCREEN)
|
||
#endif
|
||
{
|
||
if (!pohMoveOffscreenDfbToDib(ppdev, poh))
|
||
bRet = FALSE;
|
||
}
|
||
|
||
poh = pohNext;
|
||
}
|
||
|
||
return(bRet);
|
||
}
|
||
|
||
/******************************Public*Routine******************************\
|
||
* HBITMAP DrvCreateDeviceBitmap
|
||
*
|
||
* Function called by GDI to create a device-format-bitmap (DFB). We will
|
||
* always try to allocate the bitmap in off-screen; if we can't, we simply
|
||
* fail the call and GDI will create and manage the bitmap itself.
|
||
*
|
||
* Note: We do not have to zero the bitmap bits. GDI will automatically
|
||
* call us via DrvBitBlt to zero the bits (which is a security
|
||
* consideration).
|
||
*
|
||
\**************************************************************************/
|
||
|
||
HBITMAP DrvCreateDeviceBitmap(
|
||
DHPDEV dhpdev,
|
||
SIZEL sizl,
|
||
ULONG iFormat)
|
||
{
|
||
PDEV* ppdev;
|
||
OH* poh;
|
||
DSURF* pdsurf;
|
||
HBITMAP hbmDevice;
|
||
|
||
ppdev = (PDEV*) dhpdev;
|
||
|
||
// If we're in full-screen mode, we hardly have any off-screen memory
|
||
// in which to allocate a DFB. LATER: We could still allocate an
|
||
// OH node and put the bitmap on the DIB DFB list for later promotion.
|
||
|
||
if (!ppdev->bEnabled)
|
||
return(0);
|
||
|
||
#if DBG
|
||
if(!gbEnableDFB)
|
||
return(0);
|
||
#endif
|
||
|
||
#if (_WIN32_WINNT >= 0x0400) //#pat08
|
||
|
||
#if 1 //hp#2
|
||
if ((sizl.cx < 20) || ((sizl.cx >= 32) && (sizl.cx < 100)))
|
||
{
|
||
return(0);
|
||
}
|
||
#endif
|
||
//pat08 begin
|
||
#else
|
||
if ((ppdev->ulChipID != CL7541_ID) && (ppdev->ulChipID == CL7543_ID) &&
|
||
(ppdev->ulChipID != CL7542_ID) && (ppdev->ulChipID == CL7548_ID) &&
|
||
(ppdev->ulChipID != CL7555_ID) && (ppdev->ulChipID == CL7556_ID))
|
||
{
|
||
#if 1 //hp#2
|
||
if ((sizl.cx < 20) || ((sizl.cx >= 32) && (sizl.cx < 100)))
|
||
{
|
||
return(0);
|
||
}
|
||
#endif
|
||
}
|
||
#endif
|
||
//pat08 end
|
||
|
||
// We only support device bitmaps that are the same colour depth
|
||
// as our display.
|
||
//
|
||
// Actually, those are the only kind GDI will ever call us with,
|
||
// but we may as well check. Note that this implies you'll never
|
||
// get a crack at 1bpp bitmaps.
|
||
|
||
if (iFormat != ppdev->iBitmapFormat)
|
||
return(0);
|
||
|
||
// We don't want anything 8x8 or smaller -- they're typically brush
|
||
// patterns which we don't particularly want to stash in off-screen
|
||
// memory:
|
||
|
||
if ((sizl.cx <= 8) && (sizl.cy <= 8))
|
||
return(0);
|
||
|
||
poh = pohAllocate(ppdev, sizl.cx, sizl.cy, 0);
|
||
if (poh != NULL)
|
||
{
|
||
pdsurf = ALLOC(sizeof(DSURF));
|
||
if (pdsurf != NULL)
|
||
{
|
||
hbmDevice = EngCreateDeviceBitmap((DHSURF) pdsurf, sizl, iFormat);
|
||
if (hbmDevice != NULL)
|
||
{
|
||
if (EngAssociateSurface((HSURF) hbmDevice, ppdev->hdevEng,
|
||
ppdev->flHooks))
|
||
{
|
||
pdsurf->dt = DT_SCREEN;
|
||
pdsurf->poh = poh;
|
||
pdsurf->sizl = sizl;
|
||
pdsurf->ppdev = ppdev;
|
||
poh->pdsurf = pdsurf;
|
||
|
||
return(hbmDevice);
|
||
}
|
||
|
||
EngDeleteSurface((HSURF) hbmDevice);
|
||
}
|
||
FREE(pdsurf);
|
||
}
|
||
pohFree(ppdev, poh);
|
||
}
|
||
|
||
return(0);
|
||
}
|
||
|
||
/******************************Public*Routine******************************\
|
||
* VOID DrvDeleteDeviceBitmap
|
||
*
|
||
* Deletes a DFB.
|
||
*
|
||
\**************************************************************************/
|
||
|
||
VOID DrvDeleteDeviceBitmap(
|
||
DHSURF dhsurf)
|
||
{
|
||
DSURF* pdsurf;
|
||
PDEV* ppdev;
|
||
SURFOBJ* psoDib;
|
||
HSURF hsurfDib;
|
||
|
||
pdsurf = (DSURF*) dhsurf;
|
||
ppdev = pdsurf->ppdev;
|
||
|
||
if (pdsurf->dt == DT_SCREEN)
|
||
{
|
||
pohFree(ppdev, pdsurf->poh);
|
||
}
|
||
else
|
||
{
|
||
ASSERTDD(pdsurf->dt == DT_DIB, "Expected DIB type");
|
||
|
||
psoDib = pdsurf->pso;
|
||
|
||
// Get the hsurf from the SURFOBJ before we unlock it (it's not
|
||
// legal to dereference psoDib when it's unlocked):
|
||
|
||
hsurfDib = psoDib->hsurf;
|
||
EngUnlockSurface(psoDib);
|
||
EngDeleteSurface(hsurfDib);
|
||
}
|
||
|
||
FREE(pdsurf);
|
||
}
|
||
|
||
/******************************Public*Routine******************************\
|
||
* BOOL bAssertModeOffscreenHeap
|
||
*
|
||
* This function is called whenever we switch in or out of full-screen
|
||
* mode. We have to convert all the off-screen bitmaps to DIBs when
|
||
* we switch to full-screen (because we may be asked to draw on them even
|
||
* when in full-screen, and the mode switch would probably nuke the video
|
||
* memory contents anyway).
|
||
*
|
||
\**************************************************************************/
|
||
|
||
BOOL bAssertModeOffscreenHeap(
|
||
PDEV* ppdev,
|
||
BOOL bEnable)
|
||
{
|
||
BOOL b;
|
||
|
||
b = TRUE;
|
||
|
||
if (!bEnable)
|
||
{
|
||
b = bMoveAllDfbsFromOffscreenToDibs(ppdev);
|
||
}
|
||
|
||
return(b);
|
||
}
|
||
|
||
/******************************Public*Routine******************************\
|
||
* VOID vDisableOffscreenHeap
|
||
*
|
||
* Frees any resources allocated by the off-screen heap.
|
||
*
|
||
\**************************************************************************/
|
||
|
||
VOID vDisableOffscreenHeap(
|
||
PDEV* ppdev)
|
||
{
|
||
OHALLOC* poha;
|
||
OHALLOC* pohaNext;
|
||
SURFOBJ* psoPunt;
|
||
HSURF hsurf;
|
||
|
||
psoPunt = ppdev->psoPunt;
|
||
if (psoPunt != NULL)
|
||
{
|
||
hsurf = psoPunt->hsurf;
|
||
EngUnlockSurface(psoPunt);
|
||
EngDeleteSurface(hsurf);
|
||
}
|
||
|
||
psoPunt = ppdev->psoPunt2;
|
||
if (psoPunt != NULL)
|
||
{
|
||
hsurf = psoPunt->hsurf;
|
||
EngUnlockSurface(psoPunt);
|
||
EngDeleteSurface(hsurf);
|
||
}
|
||
|
||
poha = ppdev->heap.pohaChain;
|
||
while (poha != NULL)
|
||
{
|
||
pohaNext = poha->pohaNext; // Grab the next pointer before it's freed
|
||
FREE(poha);
|
||
poha = pohaNext;
|
||
}
|
||
}
|
||
|
||
/******************************Public*Routine******************************\
|
||
* BOOL bEnableOffscreenHeap
|
||
*
|
||
* Initializes the off-screen heap using all available video memory,
|
||
* accounting for the portion taken by the visible screen.
|
||
*
|
||
* Input: ppdev->cxScreen
|
||
* ppdev->cyScreen
|
||
* ppdev->cxMemory
|
||
* ppdev->cyMemory
|
||
*
|
||
\**************************************************************************/
|
||
|
||
BOOL bEnableOffscreenHeap(
|
||
PDEV* ppdev)
|
||
{
|
||
OH* poh;
|
||
SIZEL sizl;
|
||
HSURF hsurf;
|
||
static onetimealloc = 0; //pat04
|
||
FLONG flPuntSurfaceHooks = ppdev->flHooks & ~HOOK_SYNCHRONIZE;
|
||
|
||
DISPDBG((5, "Screen: %li x %li Memory: %li x %li",
|
||
ppdev->cxScreen, ppdev->cyScreen, ppdev->cxMemory, ppdev->cyMemory));
|
||
|
||
ppdev->heap.pohaChain = NULL;
|
||
ppdev->heap.pohFreeList = NULL;
|
||
|
||
// Initialize the available list, which will be a circular
|
||
// doubly-linked list kept in ascending 'cxcy' order, with a
|
||
// 'sentinel' at the end of the list:
|
||
|
||
poh = pohNewNode(ppdev);
|
||
if (poh == NULL)
|
||
goto ReturnFalse;
|
||
|
||
// The first node describes the entire video memory size:
|
||
|
||
poh->pohNext = &ppdev->heap.ohAvailable;
|
||
poh->pohPrev = &ppdev->heap.ohAvailable;
|
||
poh->ofl = OFL_AVAILABLE;
|
||
poh->x = 0;
|
||
poh->y = 0;
|
||
poh->xy = 0;
|
||
poh->cx = ppdev->cxMemory;
|
||
poh->cy = ppdev->cyMemory;
|
||
poh->cxcy = CXCY(ppdev->cxMemory, ppdev->cyMemory);
|
||
poh->pohLeft = &ppdev->heap.ohAvailable;
|
||
poh->pohUp = &ppdev->heap.ohAvailable;
|
||
poh->pohRight = &ppdev->heap.ohAvailable;
|
||
poh->pohDown = &ppdev->heap.ohAvailable;
|
||
poh->pvScan0 = ppdev->pjScreen;
|
||
|
||
// The second node is our available list sentinel:
|
||
|
||
ppdev->heap.ohAvailable.pohNext = poh;
|
||
ppdev->heap.ohAvailable.pohPrev = poh;
|
||
ppdev->heap.ohAvailable.cxcy = CXCY_SENTINEL;
|
||
ppdev->heap.ohAvailable.cx = 0x7fffffff;
|
||
ppdev->heap.ohAvailable.cy = 0x7fffffff;
|
||
ppdev->heap.ohAvailable.ofl = OFL_PERMANENT;
|
||
ppdev->heap.ohDfb.pohLeft = NULL;
|
||
ppdev->heap.ohDfb.pohUp = NULL;
|
||
ppdev->heap.ohDfb.pohRight = NULL;
|
||
ppdev->heap.ohDfb.pohDown = NULL;
|
||
|
||
// Initialize the most-recently-blitted DFB list, which will be
|
||
// a circular doubly-linked list kept in order, with a sentinel at
|
||
// the end. This node is also used for the screen-surface, for its
|
||
// offset:
|
||
|
||
ppdev->heap.ohDfb.pohNext = &ppdev->heap.ohDfb;
|
||
ppdev->heap.ohDfb.pohPrev = &ppdev->heap.ohDfb;
|
||
ppdev->heap.ohDfb.ofl = OFL_PERMANENT;
|
||
|
||
// For the moment, make the max really big so that the first
|
||
// allocation we're about to do will succeed:
|
||
|
||
ppdev->heap.cxMax = 0x7fffffff;
|
||
ppdev->heap.cyMax = 0x7fffffff;
|
||
|
||
// Reserve the upper-left corner for the screen.
|
||
|
||
poh = pohAllocatePermanent(ppdev, ppdev->cxScreen, ppdev->cyScreen);
|
||
|
||
ppdev->pohScreen = poh;
|
||
|
||
ASSERTDD((poh != NULL) && (poh->x == 0) && (poh->y == 0),
|
||
"We assumed allocator would use the upper-left corner");
|
||
|
||
// Allocate a 'punt' SURFOBJ we'll use when the device-bitmap is in
|
||
// off-screen memory, but we want GDI to draw to it directly as an
|
||
// engine-managed surface:
|
||
|
||
sizl.cx = ppdev->cxMemory;
|
||
sizl.cy = ppdev->cyMemory;
|
||
|
||
// We want to create it with exactly the same hooks, capabilities,
|
||
// and screen delta as our primary surface:
|
||
|
||
hsurf = (HSURF) EngCreateBitmap(sizl,
|
||
ppdev->lDelta,
|
||
ppdev->iBitmapFormat,
|
||
BMF_TOPDOWN,
|
||
ppdev->pjScreen);
|
||
|
||
if ((hsurf == 0) ||
|
||
(!EngAssociateSurface(hsurf, ppdev->hdevEng, flPuntSurfaceHooks)) ||
|
||
(!(ppdev->psoPunt = EngLockSurface(hsurf))))
|
||
{
|
||
DISPDBG((0, "Failed punt surface creation"));
|
||
|
||
EngDeleteSurface(hsurf);
|
||
goto ReturnFalse;
|
||
}
|
||
|
||
// We need another for doing DrvBitBlt and DrvCopyBits when both
|
||
// surfaces are off-screen bitmaps:
|
||
|
||
hsurf = (HSURF) EngCreateBitmap(sizl,
|
||
ppdev->lDelta,
|
||
ppdev->iBitmapFormat,
|
||
BMF_TOPDOWN,
|
||
ppdev->pjScreen);
|
||
|
||
if ((hsurf == 0) ||
|
||
(!EngAssociateSurface(hsurf, ppdev->hdevEng, flPuntSurfaceHooks)) ||
|
||
(!(ppdev->psoPunt2 = EngLockSurface(hsurf))))
|
||
{
|
||
DISPDBG((0, "Failed punt surface creation"));
|
||
|
||
EngDeleteSurface(hsurf);
|
||
goto ReturnFalse;
|
||
}
|
||
|
||
DISPDBG((5, "Passed bEnableOffscreenHeap"));
|
||
|
||
// pat04 : for NT 3.51 S/W cursor, begin
|
||
#if (_WIN32_WINNT < 0x0400)
|
||
#ifdef PANNING_SCROLL
|
||
|
||
if ((ppdev->ulChipID == CL7541_ID) || (ppdev->ulChipID == CL7543_ID) ||
|
||
(ppdev->ulChipID == CL7542_ID) || (ppdev->ulChipID == CL7548_ID) ||
|
||
(ppdev->ulChipID == CL7555_ID) || (ppdev->ulChipID == CL7556_ID))
|
||
{
|
||
if (poh != NULL) {
|
||
if (onetimealloc == 0)
|
||
{
|
||
onetimealloc = 1;
|
||
ppdev->pjPointerAndCMask =
|
||
pohAllocatePermanent(ppdev, 32 * ppdev->cBpp, 32);
|
||
ppdev->pjCBackground =
|
||
pohAllocatePermanent (ppdev, 32 * ppdev->cBpp, 32);
|
||
ppdev->pjPointerCBitmap =
|
||
pohAllocatePermanent (ppdev, 32 * ppdev->cBpp, 32);
|
||
}
|
||
|
||
return(TRUE);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (poh != NULL)
|
||
return(TRUE);
|
||
}
|
||
#else //myf-pat
|
||
if (poh != NULL)
|
||
return(TRUE);
|
||
#endif //myf-pat
|
||
#else // NT4.0 code
|
||
//pat04, end
|
||
if (poh != NULL)
|
||
return(TRUE);
|
||
#endif //pat04
|
||
|
||
|
||
ReturnFalse:
|
||
|
||
DISPDBG((0, "Failed bEnableOffscreenHeap"));
|
||
|
||
return(FALSE);
|
||
}
|
||
|