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.
667 lines
24 KiB
667 lines
24 KiB
/******************************Module*Header*******************************\
|
|
*
|
|
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
* !! !!
|
|
* !! WARNING: NOT DDK SAMPLE CODE !!
|
|
* !! !!
|
|
* !! This source code is provided for completeness only and should not be !!
|
|
* !! used as sample code for display driver development. Only those sources !!
|
|
* !! marked as sample code for a given driver component should be used for !!
|
|
* !! development purposes. !!
|
|
* !! !!
|
|
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
*
|
|
* Module Name: linalloc.c
|
|
*
|
|
* Content: Videomemory linear allocator
|
|
*
|
|
* Copyright (c) 1995-2003 Microsoft Corporation
|
|
\**************************************************************************/
|
|
|
|
#include "glint.h"
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// This module implements video memory allocation. It isn't a great
|
|
// allocator (though it IS robust), but mainly it shows how to hook
|
|
// up your own if you need/wish to.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// In linalloc.h we define MEMORY_MAP_SIZE and LinearAllocatorInfo
|
|
// which are key for our implementation
|
|
|
|
// This define allows allocations to search more efficiently for free
|
|
// memory. If you want to keep things simple you can turn it off
|
|
// and things will still work fine.
|
|
#define ALLOC_OPTIMIZE 1
|
|
|
|
// Total number of chunks per element of our memory map array
|
|
// (which is of DWORD type , therefore we use sizeof(DWORD) )
|
|
#define CHUNKS_PER_ELEM (sizeof(DWORD)*8)
|
|
|
|
// Memory to be managed will be subdivided in "memory chunks". Each memory
|
|
// chunk status will be signaled by a bit in the memory map by being turned
|
|
// on or off.
|
|
#define TOTAL_MEM_CHUNKS (MEMORY_MAP_SIZE * CHUNKS_PER_ELEM)
|
|
|
|
// Macros to set, clear and test the value of a given chunk bit without
|
|
// worrying about the structure internals.
|
|
#define CHUNKNUM_BIT(chunk_num) \
|
|
(1 << ((chunk_num) % CHUNKS_PER_ELEM))
|
|
|
|
#define CHUNKNUM_ELEM(mmap, chunk_num) \
|
|
mmap[ (chunk_num) / CHUNKS_PER_ELEM ]
|
|
|
|
#define SET_MEM_CHUNK(mmap, chunk_num) \
|
|
CHUNKNUM_ELEM(mmap, chunk_num) |= CHUNKNUM_BIT(chunk_num)
|
|
|
|
#define CLR_MEM_CHUNK(mmap, chunk_num) \
|
|
CHUNKNUM_ELEM(mmap, chunk_num) &= ~CHUNKNUM_BIT(chunk_num)
|
|
|
|
#define MEM_CHUNK_VAL(mmap, chunk_num) \
|
|
((CHUNKNUM_ELEM(mmap, chunk_num) & CHUNKNUM_BIT(chunk_num)) > 0 ? 1 : 0)
|
|
|
|
// Macros that do the mapping between real (heap) memory pointers and the
|
|
// chunking indices.
|
|
#define MEM_BYTES_TO_CHUNKS(pAlloc, dwBytes) \
|
|
( (dwBytes) / pAlloc->dwMemPerChunk + \
|
|
( ((dwBytes) % pAlloc->dwMemPerChunk)? 1 : 0 ) \
|
|
)
|
|
|
|
#define CHUNK_NUM_TO_PTR(pAlloc, num) \
|
|
( (num) * pAlloc->dwMemPerChunk + pAlloc->dwMemStart )
|
|
|
|
#define MEM_PTR_TO_CHUNK_NUM(pAlloc, ptr) \
|
|
MEM_BYTES_TO_CHUNKS(pAlloc, ((ptr) - pAlloc->dwMemStart) )
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// __LIN_AlignPtr
|
|
//
|
|
// Return an aligned pointer
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
DWORD
|
|
__LIN_AlignPtr(DWORD pointer, DWORD alignment)
|
|
{
|
|
ULONG ulExtraBytes;
|
|
|
|
ulExtraBytes = pointer % alignment;
|
|
|
|
if (ulExtraBytes == 0)
|
|
{
|
|
ulExtraBytes = alignment;
|
|
}
|
|
|
|
// add enough to pointer so that its new value % alignment is == 0
|
|
return (pointer + alignment - ulExtraBytes);
|
|
} // __LIN_AlignPtr
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// __LIN_CalcMaxChunks
|
|
//
|
|
// Calculate the number of chunks in the heap
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
void
|
|
__LIN_CalcMaxChunks(LinearAllocatorInfo* pAlloc)
|
|
{
|
|
DWORD n, dwSizeHeap;
|
|
|
|
// Compute how many chunks we'll need and what size of heap each
|
|
// chunk will control for this linear allocator.
|
|
dwSizeHeap = pAlloc->dwMemEnd - pAlloc->dwMemStart;
|
|
|
|
// We will need dwMemPerChunk * dwMaxChunks to be >= dwSizeHeap.
|
|
// We also want dwMaxChunks to be as close to TOTAL_MEM_CHUNKS and
|
|
// we would like (though its not necessary) dwMemPerChunk to be as 2^N.
|
|
// (and making them at least 16 bytes makes life easier for
|
|
// the alignment requirements we have in this driver).
|
|
|
|
for(n = 4; n < 32; n++)
|
|
{
|
|
// our current choice of heap size each chunk will control
|
|
pAlloc->dwMemPerChunk = 1 << n; // 2^N
|
|
|
|
// how many chunks do we need for such case?
|
|
pAlloc->dwMaxChunks = dwSizeHeap / pAlloc->dwMemPerChunk;
|
|
if (dwSizeHeap % pAlloc->dwMemPerChunk != 0)
|
|
{
|
|
pAlloc->dwMaxChunks++;
|
|
}
|
|
|
|
// can we accept this result to fit in our data structure?
|
|
if (pAlloc->dwMaxChunks <= TOTAL_MEM_CHUNKS)
|
|
{
|
|
// We have as finely grained chunks as we can without
|
|
// exceeding our self imposed limits.
|
|
break;
|
|
}
|
|
}
|
|
|
|
// 1 << n is the size of 1 chunk which is 1k on P3 with 256MB video memory
|
|
ASSERTDD((n < 32), "__LIN_CalcMaxChunks : Wrong heap size");
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// __LIN_ReInitWhenNeeded
|
|
//
|
|
// Reinitialize heap allocater if needed. This is important only for
|
|
// the Win9x driver which can signal us from the 16bit side in a mode
|
|
// change that it needs the heap to be reinitialized completely. (It will
|
|
// do this by simple setting bResetLinAllocator to TRUE).
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
void
|
|
__LIN_ReInitWhenNeeded(LinearAllocatorInfo* pAlloc)
|
|
{
|
|
#ifdef W95_DDRAW
|
|
if (pAlloc)
|
|
{
|
|
if (pAlloc->bResetLinAllocator)
|
|
{
|
|
// Clean all previous allocation data in the memory map
|
|
if (pAlloc->pMMap)
|
|
{
|
|
memset(pAlloc->pMMap, 0, sizeof(MemoryMap));
|
|
}
|
|
|
|
// Clean all previous lenght data in the memory map
|
|
if (pAlloc->pLenMap)
|
|
{
|
|
memset(pAlloc->pLenMap, 0, sizeof(MemoryMap));
|
|
}
|
|
|
|
// Recalculate max chunks due to change of heap's size
|
|
__LIN_CalcMaxChunks(pAlloc);
|
|
}
|
|
|
|
// reinitialization completed
|
|
pAlloc->bResetLinAllocator = FALSE;
|
|
}
|
|
#endif // W95_DDRAW
|
|
} // __LIN_ReInitWhenNeeded
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// _DX_LIN_InitialiseHeapManager
|
|
//
|
|
// Creates the heap manager. This code is fairly common to this
|
|
// sample app and the dd allocator as it will stand. The operations
|
|
// it performs will be in perm3dd and/or mini, though the shared heap
|
|
// memory can be allocated from 16 and 32 bit land.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
BOOL
|
|
_DX_LIN_InitialiseHeapManager(LinearAllocatorInfo* pAlloc,
|
|
DWORD dwMemStart,
|
|
DWORD dwMemEnd)
|
|
{
|
|
DWORD n;
|
|
|
|
// Reinitialize heap allocater if needed
|
|
__LIN_ReInitWhenNeeded(pAlloc);
|
|
|
|
pAlloc->dwMemStart = dwMemStart;
|
|
pAlloc->dwMemEnd = dwMemEnd;
|
|
pAlloc->bResetLinAllocator = FALSE;
|
|
|
|
// Get memory for the allocator's memory map
|
|
pAlloc->pMMap = (MemoryMap*)HEAP_ALLOC(HEAP_ZERO_MEMORY,
|
|
sizeof(MemoryMap),
|
|
ALLOC_TAG_DX(G));
|
|
if(pAlloc->pMMap == NULL)
|
|
{
|
|
// Out of memory
|
|
return FALSE;
|
|
}
|
|
|
|
// Clear the memory map
|
|
memset(pAlloc->pMMap, 0, sizeof(MemoryMap));
|
|
|
|
// Calculate the maximum number of chunks
|
|
__LIN_CalcMaxChunks(pAlloc);
|
|
|
|
// Get memory for the allocator's lenght memory map. We'll keep here
|
|
// a map of 0's and 1's where 1 will indicate where the current
|
|
// allocated block ends. That way we won't need to keep any binding
|
|
// between the allocated addresses and the size of each one in order
|
|
// to do the right thing when we are asked to free the memory
|
|
pAlloc->pLenMap = (MemoryMap*)HEAP_ALLOC(HEAP_ZERO_MEMORY,
|
|
sizeof(MemoryMap),
|
|
ALLOC_TAG_DX(H));
|
|
if(pAlloc->pLenMap == NULL)
|
|
{
|
|
// Couln't allocate the lenght map, deallocate the memory map
|
|
HEAP_FREE(pAlloc->pMMap);
|
|
pAlloc->pMMap = NULL;
|
|
|
|
// Out of memory
|
|
return FALSE;
|
|
}
|
|
|
|
// Clear the lenghts memory map
|
|
memset(pAlloc->pLenMap, 0xFF, sizeof(MemoryMap));
|
|
|
|
return TRUE;
|
|
|
|
} // _DX_LIN_InitialiseHeapManager
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// _DX_LIN_UnInitialiseHeapManager(pLinearAllocatorInfo pAlloc)
|
|
//
|
|
// Frees the heap manager. This code is fairly common to this
|
|
// sample app and the dd allocator as it will stand. The operations
|
|
// it performs will be in p3r3dx and/or mini, though the shared heap
|
|
// memory can be allocated from 16 and 32 bit land.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
void _DX_LIN_UnInitialiseHeapManager(LinearAllocatorInfo* pAlloc)
|
|
{
|
|
__LIN_ReInitWhenNeeded(pAlloc);
|
|
|
|
// Destroy/Clean all previous allocation data
|
|
if (pAlloc)
|
|
{
|
|
if(pAlloc->pMMap)
|
|
{
|
|
HEAP_FREE(pAlloc->pMMap);
|
|
pAlloc->pMMap = NULL;
|
|
}
|
|
|
|
if(pAlloc->pLenMap)
|
|
{
|
|
HEAP_FREE(pAlloc->pLenMap);
|
|
pAlloc->pLenMap = NULL;
|
|
}
|
|
}
|
|
|
|
} // _DX_LIN_UnInitialiseHeapManager
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// _DX_LIN_AllocateLinearMemory
|
|
//
|
|
// This is the allocation interface to the allocator. It gives an
|
|
// application the opportunity to allocate a linear chunk of memory
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
DWORD
|
|
_DX_LIN_AllocateLinearMemory(
|
|
pLinearAllocatorInfo pAlloc,
|
|
LPMEMREQUEST lpMemReq)
|
|
{
|
|
INT i;
|
|
DWORD dwBytes,
|
|
dwCurrStartChunk,
|
|
dwCurrEndChunk,
|
|
dwNumContChunksFound,
|
|
dwContChunksNeeded;
|
|
#if ALLOC_OPTIMIZE
|
|
// Each block is CHUNKS_PER_ELE chuncks
|
|
DWORD dwStartLastBlock;
|
|
#endif
|
|
|
|
// Reinitialize heap allocater if needed
|
|
__LIN_ReInitWhenNeeded(pAlloc);
|
|
|
|
// Validate the passed data
|
|
if ((lpMemReq == NULL) ||
|
|
(lpMemReq->dwSize != sizeof(P3_MEMREQUEST)))
|
|
{
|
|
DISPDBG((ERRLVL,"ERROR: NULL lpMemReq passed!"));
|
|
return GLDD_INVALIDARGS;
|
|
}
|
|
|
|
if ((!pAlloc) ||
|
|
(pAlloc->pMMap == NULL) ||
|
|
(pAlloc->pLenMap == NULL) )
|
|
{
|
|
DISPDBG((ERRLVL,"ERROR: invalid pAlloc passed!"));
|
|
return GLDD_INVALIDARGS;
|
|
}
|
|
|
|
// Always ensure that alignment is a DWORD (or DWORD multiple)
|
|
if (lpMemReq->dwAlign < 4)
|
|
{
|
|
lpMemReq->dwAlign = 4;
|
|
}
|
|
|
|
while ((lpMemReq->dwAlign % 4) != 0)
|
|
{
|
|
lpMemReq->dwAlign++;
|
|
}
|
|
|
|
// Always align memory requests to a minimum of a 4 byte boundary
|
|
dwBytes = __LIN_AlignPtr(lpMemReq->dwBytes, lpMemReq->dwAlign);
|
|
if (dwBytes == 0)
|
|
{
|
|
DISPDBG((WRNLVL,"ERROR: Requested 0 Bytes!"));
|
|
return GLDD_INVALIDARGS;
|
|
}
|
|
|
|
// Determine how many chunks of memory we'll need to allocate
|
|
dwContChunksNeeded = MEM_BYTES_TO_CHUNKS(pAlloc, dwBytes);
|
|
|
|
// We don't check if we were called with MEM3DL_FIRST_FIT since
|
|
// that's the only thing we know how to do right now. We decide
|
|
// whether we'll search from back to front or viceversa. We will
|
|
// scan the memory map in the chosen direction looking for a "hole"
|
|
// large enough for the current request.
|
|
if (lpMemReq->dwFlags & MEM3DL_BACK)
|
|
{
|
|
// We will examine the MemoryMap from the end towards the front
|
|
// looking out for a suitable space with the required number of
|
|
// chunks we need
|
|
dwCurrEndChunk = 0;
|
|
dwNumContChunksFound = 0;
|
|
for ( i = pAlloc->dwMaxChunks - 1; i >= 0 ; i--)
|
|
{
|
|
#if ALLOC_OPTIMIZE
|
|
// we are about to start testing a specific DWORD in
|
|
// the memory map (going from the end to the start)
|
|
if (( i % 32) == 31)
|
|
{
|
|
// If the whole DWORD is 0xFFFFFFFF (meaning all chunks are
|
|
// already allocated) then we can & should skip it altogheter
|
|
while ((i >= 0) &&
|
|
(CHUNKNUM_ELEM((*pAlloc->pMMap), i) == 0xFFFFFFFF))
|
|
{
|
|
// Search needs to be restarted
|
|
dwNumContChunksFound = 0;
|
|
|
|
i -= 32;
|
|
}
|
|
|
|
// If the whole DWORD is 0x00000000 (meaning none of the
|
|
// chunks is yet allocated) then we could grab all
|
|
while ((i >= 0) &&
|
|
(CHUNKNUM_ELEM((*pAlloc->pMMap), i) == 0x00000000) &&
|
|
!(dwNumContChunksFound >= dwContChunksNeeded))
|
|
{
|
|
if (dwNumContChunksFound == 0)
|
|
{
|
|
dwCurrEndChunk = i;
|
|
}
|
|
i -= 32;
|
|
dwNumContChunksFound += 32;
|
|
}
|
|
|
|
if (dwNumContChunksFound >= dwContChunksNeeded)
|
|
{
|
|
// We've found a suitable place! Figure out where it starts
|
|
dwCurrStartChunk = dwCurrEndChunk - dwContChunksNeeded + 1;
|
|
break;
|
|
}
|
|
else if(!(i >= 0))
|
|
{
|
|
break; // finished examining all memory, break loop here
|
|
}
|
|
}
|
|
#endif // ALLOC_OPTIMIZE
|
|
if (MEM_CHUNK_VAL((*pAlloc->pMMap), i ) == 0)
|
|
{
|
|
if (dwNumContChunksFound == 0)
|
|
{
|
|
// our count so far of contigous chunks is zero,
|
|
// meaning that were just starting to find free
|
|
// chunks. We need to remember where this block
|
|
// is ending
|
|
dwCurrEndChunk = i;
|
|
}
|
|
dwNumContChunksFound++;
|
|
}
|
|
else
|
|
{
|
|
// This chunk is being used and we haven't found a suitable
|
|
// set of chunks, so reset our count of contigous chunks
|
|
// found so far
|
|
dwNumContChunksFound = 0;
|
|
}
|
|
|
|
if (dwNumContChunksFound >= dwContChunksNeeded)
|
|
{
|
|
// We've found a suitable place! Figure out where it starts.
|
|
dwCurrStartChunk = dwCurrEndChunk - dwContChunksNeeded + 1;
|
|
break; // break loop here
|
|
}
|
|
}
|
|
}
|
|
else // even if no flags are set lets allocate at the heaps front
|
|
{
|
|
// We will examine the MemoryMap from the front towards the end
|
|
// looking out for a suitable space with the required number of
|
|
// chunks we need
|
|
dwCurrStartChunk = 0;
|
|
dwNumContChunksFound = 0;
|
|
|
|
#if ALLOC_OPTIMIZE
|
|
// At the end of the heap there might be a region smaller than
|
|
// CHUNKS_PER_ELEM(32) of chunks, and optimized search of 32
|
|
// chunk free blocks should be disabled in that region.
|
|
dwStartLastBlock = (pAlloc->dwMaxChunks / CHUNKS_PER_ELEM) *
|
|
CHUNKS_PER_ELEM;
|
|
#endif
|
|
|
|
for ( i = 0 ; i < (INT)pAlloc->dwMaxChunks ; i++)
|
|
{
|
|
#if ALLOC_OPTIMIZE
|
|
|
|
// we are about to start testing a specific
|
|
// DWORD in the memory map.
|
|
if (( i % 32) == 0)
|
|
{
|
|
// If the whole DWORD is 0xFFFFFFFF (meaning all chunks are
|
|
// already allocated) then we can & should skip it altogheter
|
|
while ((i < (INT)dwStartLastBlock) &&
|
|
(CHUNKNUM_ELEM((*pAlloc->pMMap), i) == 0xFFFFFFFF))
|
|
{
|
|
// Search needs to be restarted
|
|
dwNumContChunksFound = 0;
|
|
|
|
i += 32;
|
|
}
|
|
|
|
// If the whole DWORD is 0x00000000 (meaning none of the
|
|
// chunks is yet allocated) then we could grab all
|
|
while ((i < (INT)dwStartLastBlock) &&
|
|
(CHUNKNUM_ELEM((*pAlloc->pMMap), i) == 0x00000000) &&
|
|
!(dwNumContChunksFound >= dwContChunksNeeded))
|
|
{
|
|
if (dwNumContChunksFound == 0)
|
|
{
|
|
dwCurrStartChunk = i;
|
|
}
|
|
i += 32;
|
|
dwNumContChunksFound += 32;
|
|
}
|
|
|
|
if (dwNumContChunksFound >= dwContChunksNeeded)
|
|
{
|
|
break; // We've found a suitable place! Break loop here
|
|
}
|
|
else if(!(i < (INT)pAlloc->dwMaxChunks))
|
|
{
|
|
break; // finished examining all memory, break loop here
|
|
}
|
|
|
|
}
|
|
#endif // ALLOC_OPTIMIZE
|
|
if (MEM_CHUNK_VAL((*pAlloc->pMMap), i) == 0)
|
|
{
|
|
if (dwNumContChunksFound == 0)
|
|
{
|
|
// our count so far of contigous chunks is zero,
|
|
// meaning that were just starting to find free
|
|
// chunks. We need to remember where this block
|
|
// is starting
|
|
dwCurrStartChunk = i;
|
|
}
|
|
dwNumContChunksFound++;
|
|
}
|
|
else
|
|
{
|
|
// This chunk is being used and we haven't found a suitable
|
|
// set of chunks, so reset our count of contigous chunks
|
|
// found so far
|
|
dwNumContChunksFound = 0;
|
|
}
|
|
|
|
if (dwNumContChunksFound >= dwContChunksNeeded)
|
|
{
|
|
// We've found a suitable place!
|
|
break; // break loop here
|
|
}
|
|
}
|
|
}
|
|
|
|
// If we found a suitable place lets allocate in it
|
|
if (dwNumContChunksFound >= dwContChunksNeeded)
|
|
{
|
|
// Fill in the return pointer (properly aligned)
|
|
lpMemReq->pMem = __LIN_AlignPtr(CHUNK_NUM_TO_PTR(pAlloc,
|
|
dwCurrStartChunk),
|
|
lpMemReq->dwAlign);
|
|
|
|
for (i = dwCurrStartChunk ;
|
|
i < (INT)(dwCurrStartChunk + dwContChunksNeeded);
|
|
i++)
|
|
{
|
|
// Set up the bits in the memory map to indicate those
|
|
// addresses are being used.
|
|
SET_MEM_CHUNK((*pAlloc->pMMap), i);
|
|
|
|
// Clear the bits in the lenght memory map to indicate that
|
|
// the alloacted block doesn't end here.
|
|
CLR_MEM_CHUNK((*pAlloc->pLenMap), i);
|
|
}
|
|
|
|
// Now set the last bit of the lenght map in order to indicate
|
|
// end-of-allocated-block
|
|
SET_MEM_CHUNK((*pAlloc->pLenMap),
|
|
dwCurrStartChunk + dwContChunksNeeded - 1);
|
|
|
|
return GLDD_SUCCESS;
|
|
}
|
|
|
|
return GLDD_NOMEM;
|
|
|
|
} // _DX_LIN_AllocateLinearMemory
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// _DX_LIN_FreeLinearMemory
|
|
//
|
|
// This is the interface to memory freeing.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
DWORD
|
|
_DX_LIN_FreeLinearMemory(
|
|
pLinearAllocatorInfo pAlloc,
|
|
DWORD VidPointer)
|
|
{
|
|
// Reinitialize heap allocater if needed
|
|
__LIN_ReInitWhenNeeded(pAlloc);
|
|
|
|
if (pAlloc && pAlloc->pMMap && pAlloc->pLenMap)
|
|
{
|
|
DWORD i, dwFirstChunk;
|
|
BOOL bLast = FALSE;
|
|
|
|
// Now compute the starting chunk for this VidMem ptr
|
|
dwFirstChunk = MEM_PTR_TO_CHUNK_NUM(pAlloc, VidPointer);
|
|
|
|
// Clear the relevant bits in the memory map until the
|
|
// lenght map indicates we've reached the end of the allocated
|
|
// block
|
|
|
|
i = dwFirstChunk;
|
|
|
|
while ((!bLast) && (i <= pAlloc->dwMaxChunks))
|
|
{
|
|
// First check if this is the end of the block
|
|
bLast = MEM_CHUNK_VAL((*pAlloc->pLenMap), i );
|
|
|
|
// Now "delete" it (even if its the end of the block)
|
|
CLR_MEM_CHUNK((*pAlloc->pMMap), i);
|
|
|
|
// Set the bits in the lenght memory map for future
|
|
// allocations.
|
|
SET_MEM_CHUNK((*pAlloc->pLenMap), i);
|
|
|
|
i++;
|
|
}
|
|
|
|
return GLDD_SUCCESS;
|
|
}
|
|
|
|
return GLDD_NOMEM;
|
|
|
|
} // _DX_LIN_FreeLinearMemory
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// _DX_LIN_GetFreeMemInHeap
|
|
//
|
|
// Scans the memory map and reports the memory that is available in it.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
DWORD
|
|
_DX_LIN_GetFreeMemInHeap(
|
|
pLinearAllocatorInfo pAlloc)
|
|
{
|
|
DWORD dwTotalFreeMem = 0;
|
|
DWORD dwLargestBlock = 0;
|
|
DWORD dwTempSize = 0;
|
|
DWORD i;
|
|
|
|
// Reinitialize heap allocater if needed
|
|
__LIN_ReInitWhenNeeded(pAlloc);
|
|
|
|
// Make sure the linear allocator & memory map are valid
|
|
if (pAlloc && pAlloc->pMMap)
|
|
{
|
|
for (i = 0; i < pAlloc->dwMaxChunks ; i++)
|
|
{
|
|
// Check if chunk is free or in use
|
|
if (MEM_CHUNK_VAL((*pAlloc->pMMap), i) == 0)
|
|
{
|
|
// Keep track of total free memory
|
|
dwTotalFreeMem++;
|
|
|
|
// Keep track of largest single memory area
|
|
dwTempSize++;
|
|
if (dwTempSize > dwLargestBlock)
|
|
{
|
|
dwLargestBlock = dwTempSize;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dwTempSize = 0;
|
|
}
|
|
}
|
|
|
|
// There is a minimum amount for an allocation to succeed since we have
|
|
// to pad these/ surfaces out to 32x32, so a 32bpp surface requires at
|
|
// least 4K free.
|
|
//@@BEGIN_DDKSPLIT
|
|
// If we say that we have 1.5K free, then we'll fail TDDRAW WHQL test. Ouch!
|
|
//@@END_DDKSPLIT
|
|
if (dwLargestBlock * pAlloc->dwMemPerChunk >= 4096)
|
|
{
|
|
return dwTotalFreeMem * pAlloc->dwMemPerChunk;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
|
|
} // _DX_LIN_GetFreeMemInHeap
|
|
|