Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

336 lines
8.7 KiB

/*
* Copyright (c) 1993 Digital Equipment Corporation
*
* Module Name: offscrn.c
*
* This module contains routines to manage off-screen memory in the TGA
* frame buffer. It was stolen from FFBPIXMAP.C.
*
* Next-fit storage allocation mechanism
*
* Algorithm stolen from Knuth V1, p 437,
* with suggested modifications from Exercise 2.5.6.
*
* free list is kept in tga address order
* ppdev->pFreeList is a pointer to first free element
* ppdev->pRover is a pointer into free list
* ppdev->pAllocated points to list of allocated elements
*
* History:
*
* 29-Nov-1993 Barry Tannenbaum
* Original adaptation
*
* 08-Jun-1994 Bob Seitsinger
* Modify the initial values for the low-order 4k of the frame buffer
* to reserve the first 8 bytes for offscreen blit copies. Remember that
* blits scr->scr code 'may' have to adjust the destination address down
* by 8 bytes (quadword alignment) if the source alignment adjustment is
* greater than the destination alignment adjustment - which will most
* likely be the case if the destination is the very first frame buffer
* address.
*
* 14-Jul-1994 Bob Seitsinger
* Add code in vTgaOffScreenInit to handle 24 plane boards.
*
*/
#include "driver.h"
/*
* EnQueue
*
* This routine adds a node to a doubly linked list after a specified node.
* If the previous node is NULL, the node is simply points to itself.
*/
static __inline void EnQueue (OffScreen *prev, OffScreen *p)
{
if (NULL == prev)
{
p->prev = p;
p->next = p;
}
else
{
p->next = prev->next;
prev->next = p;
p->prev = prev;
p->next->prev = p;
}
}
/*
* DeQueue
*
* This routine removes a node from a doubly linked list and updates a pointer
* to the start of the list.
*/
static __inline OffScreen *DeQueue (OffScreen *p, OffScreen **ptr)
{
if (*ptr == p) // Update the pointer
{
if (p->next == p)
*ptr = NULL;
else
*ptr = p->next;
}
p->prev->next = p->next; // Remove the element
p->next->prev = p->prev;
return p;
}
/*
* vTgaOffScreenInit
*
* This routine initializes the off-screen memory management routines
*/
VOID vTgaOffScreenInit (PPDEV ppdev)
{
OffScreen *p;
// Allocate block for chunk of memory before the start of on-screen memory
p = EngAllocMem (FL_ZERO_MEMORY, sizeof(OffScreen), ALLOC_TAG);
if (NULL == p)
return;
// We need to 'reserve' the low-order 8 bytes of the frame buffer for
// blit copy mode copies, as well as the high-order 8 bytes for the
// 'on-screen' portion of the frame buffer.
//
// Additionally, 24-plane systems need to reserve the first 2k of
// the frame buffer. This is used by NT for cursors.
if (8 == ppdev->ulBitCount)
{
p->addr = ppdev->pjVideoMemory + 8;
p->bytes = (ppdev->pjFrameBuffer - ppdev->pjVideoMemory) - 16;
}
else
{
p->addr = ppdev->pjVideoMemory + (2048 + 8);
p->bytes = (ppdev->pjFrameBuffer - ppdev->pjVideoMemory) - (2048 + 16);
}
DISPDBG ((1, "TGA.DLL!vTgaOffScreenInit - pjVideoMemory [%x], pjFrameBuffer [%x]\n",
ppdev->pjVideoMemory, ppdev->pjFrameBuffer));
DISPDBG ((1, "TGA.DLL!vTgaOffScreenInit - ulFrameBufferLen [%x], lScreenStride [%x], cyScreen [%x]\n",
ppdev->ulFrameBufferLen, ppdev->lScreenStride, ppdev->cyScreen));
DISPDBG ((1, "TGA.DLL!vTgaOffScreenInit - p: addr [%x], bytes [0x%x]\n",
p->addr, p->bytes));
ppdev->pFreeList = ppdev->pRover = p;
EnQueue (NULL, p);
// Allocate block for chunk of memory after on-screen memory
p = EngAllocMem (FL_ZERO_MEMORY, sizeof(OffScreen), ALLOC_TAG);
if (NULL == p)
return;
p->addr = ppdev->pjFrameBuffer + (ppdev->lScreenStride * ppdev->cyScreen);
p->bytes = ppdev->ulFrameBufferLen - (ppdev->lScreenStride * ppdev->cyScreen);
DISPDBG ((1, "TGA.DLL!vTgaOffScreenInit - p: addr [%x], bytes [0x%x]\n",
p->addr, p->bytes));
EnQueue (ppdev->pRover, p);
}
/*
* pTgaOffScreenMalloc
*
* This routine allocates off-screen memory. If a suitable chunk can't be
* allocated a null pointer is returned. Otherwise, a pointer to an OffScreen
* data structure is returned
*/
OffScreen *pTgaOffScreenMalloc (PPDEV ppdev, ULONG bytes, ULONG priority)
{
OffScreen *p, *q, *start;
// If there's nothing available, bail out now. pRover is invalid if
// there's nothing on the free list
if (NULL == ppdev->pFreeList)
return NULL;
start = p = ppdev->pRover->next;
// Search for a block large enough. If we wrap back to the beginning,
// bail out
while (p->bytes < bytes)
{
p = p->next;
if (p == start)
return NULL;
}
// If we found a chunk of exactly the right size, simply remove the chunk
// from the free list and return the pointer to the OffScreen
if (p->bytes == bytes)
{
ppdev->pRover = p->prev;
DeQueue (p, &ppdev->pFreeList);
EnQueue (ppdev->pAllocated, p);
if (NULL == ppdev->pAllocated)
ppdev->pAllocated = p;
return p;
}
// We have to split a chunk. Create a new OffScreen element to return and
// adjust the fragment we're leaving behind appropriately
ppdev->pRover = q = p;
p = EngAllocMem (FL_ZERO_MEMORY, sizeof(OffScreen), ALLOC_TAG);
EnQueue (ppdev->pAllocated, p);
if (NULL == ppdev->pAllocated)
ppdev->pAllocated = p;
p->addr = q->addr;
p->bytes = bytes;
q->addr += bytes;
q->bytes -= bytes;
return p;
}
/*
* vTgaOffScreenFree
*
* This routine returns a block of memory to the free list
*/
VOID vTgaOffScreenFree (PPDEV ppdev, OffScreen *returned)
{
OffScreen *p, *q;
// Make sure the the element is not locked
if (returned->locked)
{
DISPDBG ((0, "vTgaOffScreenFree - Attempt to free locked block of memory\n"));
return;
}
// Remove the OffScreen element from the list of allocated elements
DeQueue (returned, &ppdev->pAllocated);
// If the free list is empty, simply add this element
if (NULL == ppdev->pFreeList)
{
EnQueue (NULL, returned);
ppdev->pFreeList = ppdev->pRover = returned;
return;
}
// Search for the right place. The list is kept sorted by address in the
// TGA framebuffer
p = ppdev->pFreeList;
while (p->addr < returned->addr)
{
p = p->next;
if (p == ppdev->pFreeList)
break;
}
q = p->prev;
// Free memory goes somewhere between q->addr and p->addr.
// It may be immediately after q->addr, or immediately before p->addr,
// or both. Merge abutting blocks appropriately.
// New free space immediately before p->addr?
if (p->addr == returned->addr + returned->bytes)
{
if (q->addr + q->bytes == returned->addr) // Free space also abuts q,
{ // merge all three spaces
q->bytes += returned->bytes + p->bytes;
q->next = p->next;
DeQueue (p, &ppdev->pFreeList);
EngFreeMem (p);
EngFreeMem (returned);
}
else
{ // Just merge free space with p
p->bytes += returned->bytes;
p->addr -= returned->bytes;
EngFreeMem (returned);
}
}
else
{
if (q->addr + q->bytes == returned->addr)
{ // new block abuts q, merge
q->bytes += returned->bytes;
EngFreeMem (returned);
}
else
{ // does not abut either q or p
EnQueue (q, returned);
if (returned->addr < ppdev->pFreeList->addr)
ppdev->pFreeList = returned;
}
}
ppdev->pRover = q; // Start search here next time
}
// Free all the memory for the offscreen data structures
//
// This works for a linked list that is standard (i.e.
// does not curl back itself) or circular (i.e. does curl
// back on itself)
//static
VOID vTgaOffScreenFreeAll_ (OffScreen *ptr)
{
OffScreen *p, *q;
p = q = ptr;
while (NULL != p)
{
p = p->next;
EngFreeMem (q);
// We've come back to the beginning so no more
if (p == ptr)
break;
q = p;
}
ptr = NULL;
}
VOID vTgaOffScreenFreeAll (PPDEV ppdev)
{
// Free up the data structure memory for the Free list
vTgaOffScreenFreeAll_ (ppdev->pFreeList);
// Free up the data structure memory for the Allocated list
vTgaOffScreenFreeAll_ (ppdev->pAllocated);
ppdev->pRover = NULL;
}