MF_API MFVertexBuffer *MFVertex_CreateVertexBuffer(const MFVertexDeclaration *pVertexFormat, int numVerts, MFVertexBufferType type, void *pVertexBufferMemory, const char *pName) { int nameLen = pName ? MFString_Length(pName) + 1 : 0; MFVertexBuffer *pVB; if(type == MFVBType_Scratch) pVB = (MFVertexBuffer*)MFRenderer_AllocateScratchMemory(sizeof(MFVertexBuffer) + nameLen); else pVB = (MFVertexBuffer*)MFHeap_Alloc(sizeof(MFVertexBuffer) + nameLen); MFZeroMemory(pVB, sizeof(MFVertexBuffer)); if(pName) pName = MFString_Copy((char*)&pVB[1], pName); pVB->pVertexDeclatation = pVertexFormat; pVB->bufferType = type; pVB->numVerts = numVerts; if(!MFVertex_CreateVertexBufferPlatformSpecific(pVB, pVertexBufferMemory)) { if(type != MFVBType_Scratch) MFHeap_Free(pVB); return NULL; } if(type == MFVBType_Scratch) { // add to a scratch list that will be cleaned up later... pVB->pNextScratchBuffer = gpScratchBufferList; gpScratchBufferList = pVB; } else MFResource_AddResource(pVB, MFRT_VertexBuffer, (uint32)(MFUtil_HashPointer(pVB) & 0xFFFFFFFF), pName); return pVB; }
static MFAllocHeader *GetAllocHeader(const void *pMemory) { int hash = MFUtil_HashPointer(pMemory) % MFHeap_AllocTableLength; MFHeap_AllocItem *pI = gpAllocTable[hash]; while(pI && pI->pMemory != pMemory) pI = pI->pNext; if(!pI) return NULL; return &pI->header; }
static MFAllocHeader *AddAlloc(void *pMemory, size_t bytes, const char *pDesc) { if(numFree == 0) ExpandAllocTable(); MFHeap_AllocItem *pAlloc = gppFreeList[--numFree]; pAlloc->pMemory = pMemory; int hash = MFUtil_HashPointer(pMemory) % MFHeap_AllocTableLength; pAlloc->pNext = gpAllocTable[hash]; gpAllocTable[hash] = pAlloc; return &pAlloc->header; }
MFInitStatus MFHeap_InitModule() { MFCALLSTACK; MFDebug_Assert(MFThread_GetMutexSizePlatformSpecific() <= sizeof(gMutexBuffer), "Mutex buffer too small!"); MFThread_InitMutexPlatformSpecific((MFMutex)gMutexBuffer, "MFHeap alloc mutex"); gAllocMutex = (MFMutex)gMutexBuffer; // any heap tracking allocations should be made in the debug space MFHeap *pOld = MFHeap_SetActiveHeap(MFHeap_GetDebugHeap()); #if defined(_USE_TRACKING_HASH_TABLE) // set up the memory tracking hash table // note: this is slightly complicated due to the chicken and egg nature // of making the first allocation for the pool its self ;) static const int numAllocHeaders = 1024; // uint32 bytes = (sizeof(MFHeap_AllocItem) + sizeof(void**)) * numAllocHeaders; // void *pPoolMemory = MFHeap_Alloc(bytes); // gAllocHeaderPool.Init(sizeof(MFHeap_AllocItem), numAllocHeaders, 1024, pPoolMemory, bytes); gAllocHeaderPool.Init(sizeof(MFHeap_AllocItem), numAllocHeaders, 1024); MFZeroMemory(gpAllocTable, sizeof(gpAllocTable)); // artificially add an entry for the pool its self... MFHeap_AllocItem *pHeader = (MFHeap_AllocItem*)gAllocHeaderPool.Alloc(); pHeader->header.pHeap = &gExternalHeap; pHeader->header.size = bytes; pHeader->header.pFile = __FILE__; pHeader->header.line = (uint16)__LINE__; pHeader->header.alignment = 4; pHeader->pMemory = pPoolMemory; pHeader->pNext = NULL; gpAllocTable[MFUtil_HashPointer(pPoolMemory) % MFHeap_AllocTableLength] = pHeader; #endif #if defined(_USE_ALLOC_TRACKER) gAllocList.Init(sizeof(void*), 1024, 1024); gPoolInitialised = true; #endif // restore the active heap MFHeap_SetActiveHeap(pOld); // init the heap MFHeap_InitModulePlatformSpecific(); return MFAIC_Succeeded; }
MF_API MFIndexBuffer *MFVertex_CreateIndexBuffer(int numIndices, uint16 *pIndexBufferMemory, const char *pName) { int nameLen = pName ? MFString_Length(pName) + 1 : 0; MFIndexBuffer *pIB = (MFIndexBuffer*)MFHeap_AllocAndZero(sizeof(MFIndexBuffer) + nameLen); if(pName) pName = MFString_Copy((char*)&pIB[1], pName); pIB->numIndices = numIndices; if(!MFVertex_CreateIndexBufferPlatformSpecific(pIB, pIndexBufferMemory)) { MFHeap_Free(pIB); return NULL; } MFResource_AddResource(pIB, MFRT_IndexBuffer, (uint32)(MFUtil_HashPointer(pIB) & 0xFFFFFFFF), pName); return pIB; }
static void FreeAlloc(void *pMemory) { int hash = MFUtil_HashPointer(pMemory) % MFHeap_AllocTableLength; MFDebug_Assert(gpAllocTable[hash], "No allocation record! O_O"); if(gpAllocTable[hash]->pMemory == pMemory) { gppFreeList[numFree++] = gpAllocTable[hash]; gpAllocTable[hash] = gpAllocTable[hash]->pNext; } else { MFHeap_AllocItem *pI = gpAllocTable[hash]; while(pI->pNext && pI->pNext->pMemory != pMemory) pI = pI->pNext; MFDebug_Assert(pI->pNext, "No allocation record! O_O"); gppFreeList[numFree++] = pI->pNext; pI->pNext = pI->pNext->pNext; } }
MF_API void MFHeap_Free(void *pMem) { MFCALLSTACK; if(!pMem) { MFDebug_Warn(3, "Attemptd to Free 'NULL' pointer."); return; } MFAllocHeader *pHeader = &((MFAllocHeader*)pMem)[-1]; MFDebug_Assert(MFHeap_ValidateMemory(pMem), MFStr("Memory corruption detected!!\n%s(%d)", pHeader->pFile, pHeader->line)); MFThread_LockMutex(gAllocMutex); MFHeap *pHeap = pHeader->pHeap; if(pHeap->heapType != MFHT_Debug) { #if defined(_USE_TRACKING_HASH_TABLE) int hash = MFUtil_HashPointer(pMem) % MFHeap_AllocTableLength; MFHeap_AllocItem *pT = gpAllocTable[hash]; if(pT) { if(pT->pMemory == pMem) { gpAllocTable[hash] = pT->pNext; gAllocHeaderPool.Free(pT); } else { while(pT->pNext && pT->pNext->pMemory != pMem) pT = pT->pNext; if(pT->pNext) { MFHeap_AllocItem *pTN = pT->pNext; pT->pNext = pTN->pNext; gAllocHeaderPool.Free(pTN); } } } #endif #if defined(_USE_ALLOC_TRACKER) if(gPoolInitialised) { int numAllocs = gAllocList.GetNumAllocated(); for(int a=0; a<numAllocs; ++a) { void **ppAlloc = (void**)gAllocList.GetItem(a); if(*ppAlloc == pMem) { gAllocList.Free(ppAlloc); break; } } } #endif } #if !defined(_RETAIL) int pad = 0; while(pad < (int)sizeof(MFAllocHeader)) pad += heapAlignment; size_t extra = pad + sizeof(MFAllocHeader) + MFHeap_MungwallBytes; pHeap->totalAllocated -= pHeader->size + extra; pHeap->totalWaste -= extra; --pHeap->allocCount; // MFDebug_Log(2, MFStr("Free: %08X, %d bytes - %s:(%d)", pMem, pHeader->size, pHeader->pFile, (int)pHeader->line)); #endif MFHeap *pAllocHeap = pHeader->pHeap; MFCopyMemory((char*)pMem + pHeader->size, "freefreefreefree", MFHeap_MungwallBytes); MFCopyMemory((char*)pMem - 8, "freefreefreefree", MFHeap_MungwallBytes); MFMemSet(pMem, 0xFE, pHeader->size); pAllocHeap->pCallbacks->pFree((char*)pMem - pHeader->alignment, pAllocHeap->pHeapData); MFThread_ReleaseMutex(gAllocMutex); }
MF_API void *MFHeap_AllocInternal(size_t bytes, MFHeap *pHeap) { MFCALLSTACK; MFHeap *pAllocHeap = pOverrideHeap ? pOverrideHeap : (pHeap ? pHeap : pActiveHeap); int pad = 0; while(pad < (int)sizeof(MFAllocHeader)) pad += heapAlignment; size_t allocExtra = pad + sizeof(MFAllocHeader) + MFHeap_MungwallBytes; size_t allocBytes = bytes + allocExtra; MFThread_LockMutex(gAllocMutex); char *pMemory = (char*)pAllocHeap->pCallbacks->pMalloc(allocBytes, pAllocHeap->pHeapData); MFDebug_Assert(pMemory, "Failed to allocate memory!"); if(pMemory) { int alignment = (int)(MFALIGN(pMemory + sizeof(MFAllocHeader), heapAlignment) - (uintp)pMemory); pMemory += alignment; MFAllocHeader *pHeader = &((MFAllocHeader*)pMemory)[-1]; pHeader->alignment = (uint16)alignment; pHeader->pHeap = pAllocHeap; pHeader->size = (uint32)bytes; pHeader->pFile = gpMFHeap_TrackerFile; pHeader->line = (uint16)gMFHeap_TrackerLine; #if defined(USE_PRE_MUNGWALL) MFCopyMemory(pHeader->llawgnum, gLlawgnum, MFHeap_MungwallBytes); #endif if(pAllocHeap->heapType != MFHT_Debug) { #if defined(_USE_TRACKING_HASH_TABLE) MFHeap_AllocItem *pAlloc = (MFHeap_AllocItem*)gAllocHeaderPool.Alloc(); pAlloc->header.alignment = (uint16)alignment; pAlloc->header.pHeap = pAllocHeap; pAlloc->header.size = (uint32)bytes; pAlloc->header.pFile = gpMFHeap_TrackerFile; pAlloc->header.line = (uint16)gMFHeap_TrackerLine; pAlloc->pMemory = pMemory; int hash = MFUtil_HashPointer(pMemory) % MFHeap_AllocTableLength; pAlloc->pNext = gpAllocTable[hash]; gpAllocTable[hash] = pAlloc; #endif #if defined(_USE_ALLOC_TRACKER) if(gPoolInitialised) *(void**)gAllocList.Alloc() = pMemory; #endif } #if !defined(_RETAIL) MFCopyMemory(pMemory + bytes, gMungwall, MFHeap_MungwallBytes); pAllocHeap->totalAllocated += allocBytes; pAllocHeap->totalWaste += allocExtra; ++pAllocHeap->allocCount; // MFDebug_Log(2, MFStr("Alloc: %08X(%08X), %d bytes - %s:(%d)", pMemory, pMemory - pHeader->alignment, bytes, gpMFHeap_TrackerFile, gMFHeap_TrackerLine)); #endif } MFThread_ReleaseMutex(gAllocMutex); return (void*)pMemory; }