/******************************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