Ich implementiert meine eigenen VkAllocatorCallback mit Plain C malloc()/realloc()/free(). Es ist eine naive Implementierung und ignoriert den Alignment-Parameter vollständig. Unter Berücksichtigung, dass malloc in 64-Bit-Betriebssystem immer Zeiger mit 16 (!) Bytes Ausrichtung, die ziemlich große Ausrichtung ist, das wäre kein Problem in meinen Tests. Siehe Reference.
Aus Gründen der Vollständigkeit der Informationen ist eine 16-Byte-Ausrichtung auch 8/4/2 Byte ausgerichtet.
Mein Code ist folgende:
/**
* PFN_vkAllocationFunction implementation
*/
void* allocationFunction(void* pUserData, size_t size, size_t alignment, VkSystemAllocationScope allocationScope){
printf("pAllocator's allocationFunction: <%s>, size: %u, alignment: %u, allocationScope: %d",
(USER_TYPE)pUserData, size, alignment, allocationScope);
// the allocation itself - ignore alignment, for while
void* ptr = malloc(size);//_aligned_malloc(size, alignment);
memset(ptr, 0, size);
printf(", return ptr* : 0x%p \n", ptr);
return ptr;
}
/**
* The PFN_vkFreeFunction implementation
*/
void freeFunction(void* pUserData, void* pMemory){
printf("pAllocator's freeFunction: <%s> ptr: 0x%p\n",
(USER_TYPE)pUserData, pMemory);
// now, the free operation !
free(pMemory);
}
/**
* The PFN_vkReallocationFunction implementation
*/
void* reallocationFunction(void* pUserData, void* pOriginal, size_t size, size_t alignment, VkSystemAllocationScope allocationScope){
printf("pAllocator's REallocationFunction: <%s>, size %u, alignment %u, allocationScope %d \n",
(USER_TYPE)pUserData, size, alignment, allocationScope);
return realloc(pOriginal, size);
}
/**
* PFN_vkInternalAllocationNotification implementation
*/
void internalAllocationNotification(void* pUserData, size_t size, VkInternalAllocationType allocationType, VkSystemAllocationScope allocationScope){
printf("pAllocator's internalAllocationNotification: <%s>, size %uz, alignment %uz, allocationType %uz, allocationScope %s \n",
(USER_TYPE)pUserData,
size,
allocationType,
allocationScope);
}
/**
* PFN_vkInternalFreeNotification implementation
**/
void internalFreeNotification(void* pUserData, size_t size, VkInternalAllocationType allocationType, VkSystemAllocationScope allocationScope){
printf("pAllocator's internalFreeNotification: <%s>, size %uz, alignment %uz, allocationType %d, allocationScope %s \n",
(USER_TYPE)pUserData, size, allocationType, allocationScope);
}
/**
* Create Pallocator
* @param info - String for tracking Allocator usage
*/
static VkAllocationCallbacks* createPAllocator(const char* info){
VkAllocationCallbacks* m_allocator = (VkAllocationCallbacks*)malloc(sizeof(VkAllocationCallbacks));
memset(m_allocator, 0, sizeof(VkAllocationCallbacks));
m_allocator->pUserData = (void*)info;
m_allocator->pfnAllocation = (PFN_vkAllocationFunction)(&allocationFunction);
m_allocator->pfnReallocation = (PFN_vkReallocationFunction)(&reallocationFunction);
m_allocator->pfnFree = (PFN_vkFreeFunction)&freeFunction;
m_allocator->pfnInternalAllocation = (PFN_vkInternalAllocationNotification)&internalAllocationNotification;
m_allocator->pfnInternalFree = (PFN_vkInternalFreeNotification)&internalFreeNotification;
// storePAllocator(m_allocator);
return m_allocator;
}
`
Ich benutzte das Cube.c Beispiel aus VulkanSDK, meinen Code und Annahmen zu testen.Modifizierte Versionen finden Sie hier GitHub
Eine Probe des Ausgangs:
pAllocator's allocationFunction: <Device>, size: 800, alignment: 8, allocationScope: 1, return ptr* : 0x00000000061ECE40
pAllocator's allocationFunction: <RenderPass>, size: 128, alignment: 8, allocationScope: 1, return ptr* : 0x000000000623FAB0
pAllocator's allocationFunction: <ShaderModule>, size: 96, alignment: 8, allocationScope: 1, return ptr* : 0x00000000061F2C30
pAllocator's allocationFunction: <ShaderModule>, size: 96, alignment: 8, allocationScope: 1, return ptr* : 0x00000000061F8790
pAllocator's allocationFunction: <PipelineCache>, size: 152, alignment: 8, allocationScope: 1, return ptr* : 0x00000000061F2590
pAllocator's allocationFunction: <Device>, size: 424, alignment: 8, allocationScope: 1, return ptr* : 0x00000000061F8EB0
pAllocator's freeFunction: <ShaderModule> ptr: 0x00000000061F8790
pAllocator's freeFunction: <ShaderModule> ptr: 0x00000000061F2C30
pAllocator's allocationFunction: <Device>, size: 3448, alignment: 8, allocationScope: 1, return ptr* : 0x000000000624D260
pAllocator's allocationFunction: <Device>, size: 3448, alignment: 8, allocationScope: 1, return ptr* : 0x0000000006249A80
Schlussfolgerungen:
der Benutzer implementiert PFN_vkAllocationFunction, PFN_vkReallocationFunction, PFN_vkFreeFunction wirklich tut malloc/realoc/freien Betrieb in Namen von Vulkan. Nicht sicher, ob sie ALLE Zuordnungen durchführen, da Vulkan wählen kann, um einige Teile selbst zuzuteilen/freizugeben.
Die von meinen Implementierungen zur Verfügung gestellte Ausgabe zeigt, dass die typische Ausrichtung angefordert 8 Bytes ist, in meinem Win 7-64/NVidia. Dies zeigt, dass es Platz für Optimierungen gibt, wie zum Beispiel ein gut gemanagter Speicher, in dem Sie einen großen Teil des Speichers belegen und für Ihre Vulkan-App (einen Speicherpool) unterteilen. Es Mai * reduziert Speicherverbrauch (denke 8 Bytes vor und bis zu 8 Bytes nach jedem zugewiesenen Block). Es kann auch schneller sein, wie malloc() Anruf länger dauern kann als ein direkter Zeiger auf Ihren eigenen Speicherpool bereits allokiert.
Zumindest mit meinen aktuellen Vulkan-Treiber, die PFN_vkInternalAllocationNotification und PFN_vkInternalFreeNotification nicht ausgeführt. Vielleicht ein Fehler in meinen NVidia-Treibern. Ich werde später meine AMD einchecken.
Der * pUserData wird verwendet, um Informationen und/oder Management zu debuggen. Tatsächlich können Sie damit ein C++ - Objekt übergeben und dort alle erforderlichen Performance-Jobs abspielen. Es ist eine Art offensichtliche Information, aber Sie können sie für jeden Anruf oder jedes VkCreateXXX-Objekt ändern.
Sie können einen einzelnen und generischen VkAllocatorCallBack-Allokator für alle Anwendungen verwenden, aber ich denke, dass die Verwendung eines benutzerdefinierten Allokators zu besseren Ergebnissen führen kann. I mein Test, VkSemaphore Erstellung zeigt ein typisches Muster auf intensive Allok/frei von kleinen Chunks (72 Bytes), die mit der Wiederverwendung eines zuvor Chunk im Speicher adressiert werden können, in einem angepassten Allokator. malloc()/free() verwendet bereits Speicher, wenn es möglich ist, ist aber verlockend, versuchen Sie, unseren eigenen Speichermanager zu verwenden, zumindest für kurzlebige kleine Speicherblöcke.
Die Speicherausrichtung ist möglicherweise ein Problem bei der Implementierung von VkAllocationCallback (es ist keine _aligned_realoc-Funktion verfügbar, sondern nur _aligned_malloc und _aligned_free). Aber nur wenn Vulkan alignments größer als mallocs Standard anfordert (8 Bytes für x86, 16 für AMD64, etc. müssen ARM defaults überprüfen). Aber bis jetzt fragt seens Vulkan tatsächlich Speicher mit niedriger Ausrichtung als malloc() Standard, mindestens auf 64bit OS.
letzter Gedanke:
Sie können glücklich leben, bis das Ende der Zeit nur alle VkAllocatorCallback * pAllocator Einstellung, die Sie als NULL finden;) Möglicherweise Vulkan-Standard allocator bereits funktioniert das alles besser als sich selbst.
ABER ...
Ein Höhepunkt Vulkan Vorteile waren der Entwickler allem unter Kontrolle gebracht werden würde, einschließlich Speicher-Management.Khronos presentation, slide 6
"* Fehlt mir hier etwas? *" Warum glauben Sie, dass diese Gründe nicht ausreichen, um die Funktion zu rechtfertigen? –
Meinst du "Ja, das ist alles! Gehen Sie voran, implementieren Sie es genau so, wie Sie es geschrieben haben"? Oder "Hey, Dummkopf, lies die f * specs und halt den Mund!" –
Mein Punkt ist mehr, dass Ihre Frage darauf hindeutet, dass diese Gründe nicht ausreichen, um Rückrufe zu erlauben. –