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.
420 lines
13 KiB
420 lines
13 KiB
/******************************Module*Header**********************************\
|
|
*
|
|
* *******************
|
|
* * D3D SAMPLE CODE *
|
|
* *******************
|
|
*
|
|
* Module Name: d3dstrct.c
|
|
*
|
|
* Content: Internal D3D structure management.
|
|
*
|
|
* Copyright (c) 1994-1999 3Dlabs Inc. Ltd. All rights reserved.
|
|
* Copyright (c) 1995-2003 Microsoft Corporation. All rights reserved.
|
|
\*****************************************************************************/
|
|
#include "glint.h"
|
|
#include "d3dstrct.h"
|
|
|
|
//----------------------------------------------------------------------------
|
|
// This file provides a centralized place where we manage ans use internal
|
|
// data structures for the driver. This way, we can change the data structure
|
|
// or its management without affecting the rest of the code.
|
|
//----------------------------------------------------------------------------
|
|
|
|
//----------------------------------------------------------------------------
|
|
//********************** A R R A Y S T R U C T U R E *********************
|
|
//----------------------------------------------------------------------------
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// PA_CreateArray
|
|
//
|
|
// Creates an array of pointers.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
PointerArray*
|
|
PA_CreateArray()
|
|
{
|
|
PointerArray* pNewArray;
|
|
|
|
pNewArray = HEAP_ALLOC(HEAP_ZERO_MEMORY,
|
|
sizeof(PointerArray),
|
|
ALLOC_TAG_DX(5));
|
|
|
|
if (!pNewArray)
|
|
{
|
|
DISPDBG((ERRLVL,"ERROR: PointerArray allocation failed"));
|
|
return NULL;
|
|
}
|
|
|
|
// Explicit initialization
|
|
pNewArray->pPointers = NULL;
|
|
pNewArray->dwNumPointers = 0;
|
|
pNewArray->pfnDestroyCallback = NULL;
|
|
|
|
return pNewArray;
|
|
} // PA_CreateArray
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// PA_SetDataDestroyCallback
|
|
//
|
|
// Records the data pointer destroy callback.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
void
|
|
PA_SetDataDestroyCallback(
|
|
PointerArray* pArray,
|
|
PA_DestroyCB DestroyCallback)
|
|
{
|
|
pArray->pfnDestroyCallback = DestroyCallback;
|
|
|
|
} // PA_SetDataDestroyCallback
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// PA_DestroyArray
|
|
//
|
|
// Destroys all the pointers in the array. Optionally calls a callback with
|
|
// each pointer to allow clients to free objects associated with the pointer
|
|
//-----------------------------------------------------------------------------
|
|
BOOL
|
|
PA_DestroyArray(PointerArray* pArray, VOID *pExtra)
|
|
{
|
|
if (pArray != NULL)
|
|
{
|
|
if (pArray->pPointers != NULL)
|
|
{
|
|
DWORD dwCount;
|
|
|
|
// If there is a registered destroy callback, call it for every
|
|
// non-null data pointer
|
|
if (pArray->pfnDestroyCallback != NULL)
|
|
{
|
|
for (dwCount = 0; dwCount < pArray->dwNumPointers; dwCount++)
|
|
{
|
|
if (pArray->pPointers[dwCount] != 0)
|
|
{
|
|
// Call the data destroy callback
|
|
pArray->pfnDestroyCallback(
|
|
pArray,
|
|
(void*)pArray->pPointers[dwCount],
|
|
pExtra);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Free the Array of Pointers
|
|
HEAP_FREE(pArray->pPointers);
|
|
pArray->pPointers = NULL;
|
|
}
|
|
|
|
// Free the pointer array
|
|
HEAP_FREE(pArray);
|
|
}
|
|
|
|
return TRUE;
|
|
} // PA_DestroyArray
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// PA_GetEntry
|
|
//
|
|
// Look up the Pointer in the array an return it
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
void*
|
|
PA_GetEntry(PointerArray* pArray, DWORD dwNum)
|
|
{
|
|
ASSERTDD((pArray != NULL), "ERROR: Bad Pointer array!");
|
|
|
|
if ((pArray->dwNumPointers == 0) ||
|
|
(dwNum > (pArray->dwNumPointers - 1)) )
|
|
{
|
|
// We will be getting called frequently by D3DCreateSurfaceEx for
|
|
// handles which might not be initialized so this will be hit often
|
|
DISPDBG((DBGLVL,"PA_GetEntry: Ptr outside of range (usually OK)"));
|
|
return NULL;
|
|
}
|
|
|
|
return (void*)pArray->pPointers[dwNum];
|
|
} // PA_GetEntry
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// PA_SetEntry
|
|
//
|
|
// Sets an entry in the array of pointers. If the entry is larger than
|
|
// the array, the array is grown to accomodate it. Returns FALSE if we
|
|
// fail to set the data for any reason (mainly out of memory).
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
BOOL
|
|
PA_SetEntry(
|
|
PointerArray* pArray,
|
|
DWORD dwNum,
|
|
void* pData)
|
|
{
|
|
ASSERTDD(pArray != NULL, "Bad pointer array");
|
|
|
|
if ( (dwNum + 1 ) > pArray->dwNumPointers )
|
|
{
|
|
ULONG_PTR* pNewArray;
|
|
DWORD dwNewArrayLength, dwNewArraySize;
|
|
|
|
//
|
|
// The array either already exists and has to be grown in size
|
|
// or doesnt exist at all
|
|
//
|
|
|
|
DISPDBG((DBGLVL, "Expanding/creating pointer array"));
|
|
|
|
dwNewArrayLength = (dwNum * 2) + 1; // Tunable heuristic
|
|
// ask for double of the space
|
|
// needed for the new element
|
|
dwNewArraySize = dwNewArrayLength * sizeof(ULONG_PTR);
|
|
pNewArray = (ULONG_PTR*)HEAP_ALLOC(HEAP_ZERO_MEMORY,
|
|
dwNewArraySize,
|
|
ALLOC_TAG_DX(7));
|
|
if (pNewArray == NULL)
|
|
{
|
|
DISPDBG((DBGLVL,"ERROR: Failed to allocate new Pointer array!!"));
|
|
return FALSE;
|
|
}
|
|
|
|
if (pArray->pPointers != NULL)
|
|
{
|
|
// We had an old valid array before this, so we need to transfer
|
|
// old array elements into the new array and destroy the old array
|
|
memcpy( pNewArray,
|
|
pArray->pPointers,
|
|
(pArray->dwNumPointers * sizeof(ULONG_PTR)) );
|
|
|
|
HEAP_FREE(pArray->pPointers);
|
|
|
|
}
|
|
|
|
// Update our pointer to the array and its size info
|
|
pArray->pPointers = pNewArray;
|
|
pArray->dwNumPointers = dwNewArrayLength;
|
|
}
|
|
|
|
pArray->pPointers[dwNum] = (ULONG_PTR)pData;
|
|
|
|
return TRUE;
|
|
|
|
} // PA_SetEntry
|
|
|
|
//----------------------------------------------------------------------------
|
|
//********************** H A S H S T R U C T U R E *********************
|
|
//----------------------------------------------------------------------------
|
|
|
|
// Manages a hash table
|
|
// Each slot contains front and back pointers, a handle, and an app-specific
|
|
// data pointer. Entries are the things that the clients add/remove
|
|
// Slots are the internal data chunks that are managed as part of the hash table
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// HT_CreateHashTable
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
HashTable*
|
|
HT_CreateHashTable()
|
|
{
|
|
HashTable* pHashTable;
|
|
|
|
DISPDBG((DBGLVL,"In HT_CreateHashTable"));
|
|
|
|
pHashTable = (HashTable*)HEAP_ALLOC(HEAP_ZERO_MEMORY,
|
|
sizeof(HashTable),
|
|
ALLOC_TAG_DX(8));
|
|
if (pHashTable == NULL)
|
|
{
|
|
DISPDBG((DBGLVL,"Hash table alloc failed!"));
|
|
return NULL;
|
|
}
|
|
|
|
return pHashTable;
|
|
} // HT_CreateHashTable
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// HT_SetDataDestroyCallback
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
void
|
|
HT_SetDataDestroyCallback(
|
|
HashTable* pHashTable,
|
|
DataDestroyCB DestroyCallback)
|
|
{
|
|
DISPDBG((DBGLVL,"In HT_SetDataDestroyCallback"));
|
|
ASSERTDD(pHashTable != NULL,"ERROR: HashTable passed in is not valid!");
|
|
|
|
pHashTable->pfnDestroyCallback = DestroyCallback;
|
|
} // HT_SetDataDestroyCallback
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// HT_ClearEntriesHashTable
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
void
|
|
HT_ClearEntriesHashTable(HashTable* pHashTable, VOID* pExtra)
|
|
{
|
|
int i;
|
|
HashSlot* pHashSlot = NULL;
|
|
|
|
DISPDBG((DBGLVL,"In HT_ClearEntriesHashTable"));
|
|
|
|
ASSERTDD(pHashTable != NULL,"ERROR: HashTable passed in is not valid!");
|
|
|
|
for (i = 0; i < HASH_SIZE; i++)
|
|
{
|
|
while (pHashSlot = pHashTable->Slots[i])
|
|
{
|
|
HT_RemoveEntry(pHashTable, pHashSlot->dwHandle, pExtra);
|
|
}
|
|
|
|
pHashTable->Slots[i] = NULL;
|
|
}
|
|
|
|
} // HT_ClearEntriesHashTable
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// HT_DestroyHashTable
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
void
|
|
HT_DestroyHashTable(HashTable* pHashTable, VOID* pExtra)
|
|
{
|
|
|
|
HT_ClearEntriesHashTable(pHashTable, pExtra);
|
|
|
|
HEAP_FREE(pHashTable);
|
|
|
|
} // HT_DestroyHashTable
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// vBOOL HT_AddEntry
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
BOOL HT_AddEntry(HashTable* pTable, ULONG_PTR dwHandle, void* pData)
|
|
{
|
|
HashSlot* pHashSlot = NULL;
|
|
|
|
DISPDBG((DBGLVL,"In HT_AddEntry"));
|
|
ASSERTDD(pTable != NULL,"ERROR: HashTable passed in is not valid!");
|
|
|
|
pHashSlot = HEAP_ALLOC(HEAP_ZERO_MEMORY,
|
|
sizeof(HashSlot),
|
|
ALLOC_TAG_DX(9));
|
|
|
|
if (pHashSlot == NULL)
|
|
{
|
|
DISPDBG((ERRLVL,"Hash entry alloc failed!"));
|
|
return FALSE;
|
|
}
|
|
|
|
// Sew this new entry into the hash table
|
|
if (pTable->Slots[HT_HASH_OF(dwHandle)])
|
|
{
|
|
pTable->Slots[HT_HASH_OF(dwHandle)]->pPrev = pHashSlot;
|
|
}
|
|
|
|
// Carry on a next pointer
|
|
pHashSlot->pNext = pTable->Slots[HT_HASH_OF(dwHandle)];
|
|
pHashSlot->pPrev = NULL;
|
|
|
|
// Remember the app-supplied data and the handle
|
|
pHashSlot->pData = pData;
|
|
pHashSlot->dwHandle = dwHandle;
|
|
|
|
// hash table refers to this one now.
|
|
pTable->Slots[HT_HASH_OF(dwHandle)] = pHashSlot;
|
|
|
|
return TRUE;
|
|
} // HT_AddEntry
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// BOOL HT_RemoveEntry
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
BOOL HT_RemoveEntry(HashTable* pTable, ULONG_PTR dwHandle, VOID *pExtra)
|
|
{
|
|
HashSlot* pSlot = HT_GetSlotFromHandle(pTable, dwHandle);
|
|
|
|
DISPDBG((DBGLVL,"In HT_RemoveEntry"));
|
|
ASSERTDD(pTable != NULL,"ERROR: HashTable passed in is not valid!");
|
|
|
|
if (pSlot == NULL)
|
|
{
|
|
DISPDBG((WRNLVL,"WARNING: Hash entry does not exist"));
|
|
return FALSE;
|
|
}
|
|
|
|
// Mark the entry as gone from the hash table if it is at the front
|
|
if (pTable->Slots[HT_HASH_OF(dwHandle)]->dwHandle == pSlot->dwHandle)
|
|
{
|
|
pTable->Slots[HT_HASH_OF(dwHandle)] =
|
|
pTable->Slots[HT_HASH_OF(dwHandle)]->pNext;
|
|
}
|
|
|
|
// and sew the list back together.
|
|
if (pSlot->pPrev)
|
|
{
|
|
pSlot->pPrev->pNext = pSlot->pNext;
|
|
}
|
|
|
|
if (pSlot->pNext)
|
|
{
|
|
pSlot->pNext->pPrev = pSlot->pPrev;
|
|
}
|
|
|
|
// If the destroy data callback is setup, call it.
|
|
if ((pSlot->pData != NULL) && (pTable->pfnDestroyCallback))
|
|
{
|
|
DISPDBG((WRNLVL,"Calling DestroyCallback for undestroyed data"));
|
|
pTable->pfnDestroyCallback(pTable, pSlot->pData, pExtra);
|
|
}
|
|
|
|
// Free the memory associated with the slot
|
|
HEAP_FREE(pSlot);
|
|
|
|
return TRUE;
|
|
} // HT_RemoveEntry
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// BOOL HT_SwapEntries
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
BOOL HT_SwapEntries(HashTable* pTable, DWORD dwHandle1, DWORD dwHandle2)
|
|
{
|
|
HashSlot* pEntry1;
|
|
HashSlot* pEntry2;
|
|
void* pDataTemp;
|
|
|
|
ASSERTDD(pTable != NULL,"ERROR: HashTable passed in is not valid!");
|
|
|
|
pEntry1 = HT_GetSlotFromHandle(pTable, dwHandle1);
|
|
pEntry2 = HT_GetSlotFromHandle(pTable, dwHandle2);
|
|
|
|
// The handle remains the same, the pointers to the actual data are swapped
|
|
if (pEntry1 && pEntry2)
|
|
{
|
|
pDataTemp = pEntry1->pData;
|
|
pEntry1->pData = pEntry2->pData;
|
|
pEntry2->pData = pDataTemp;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
DISPDBG((ERRLVL,"ERROR: Swapped entries are invalid!"));
|
|
|
|
return FALSE;
|
|
} // HT_SwapEntries
|