Moved to homebrew clang, added gpu memory management functions\n
parent
8bba0f1c26
commit
82166a8181
@ -0,0 +1,54 @@
|
||||
#ifndef GPU_MEM_H
|
||||
#define GPU_MEM_H
|
||||
|
||||
#include <vulkan/vulkan_core.h>
|
||||
#include <stdio.h>
|
||||
|
||||
typedef struct GPUMemoryTypeStruct {
|
||||
VkMemoryPropertyFlags flags;
|
||||
uint32_t index;
|
||||
} GPUMemoryType;
|
||||
|
||||
typedef struct GPUMemoryChunkStruct {
|
||||
VkDeviceSize size;
|
||||
VkDeviceSize offset;
|
||||
struct GPUMemoryChunkStruct* next;
|
||||
} GPUMemoryChunk;
|
||||
|
||||
typedef struct GPUPageStruct {
|
||||
VkDeviceMemory memory;
|
||||
VkDeviceSize size;
|
||||
GPUMemoryType type;
|
||||
|
||||
GPUMemoryChunk* free;
|
||||
GPUMemoryChunk* allocated;
|
||||
|
||||
} GPUPage;
|
||||
|
||||
typedef struct GPUBufferStruct {
|
||||
GPUPage* page;
|
||||
GPUMemoryChunk* memory;
|
||||
VkBuffer handle;
|
||||
} GPUBuffer;
|
||||
|
||||
typedef struct GPUImageStruct {
|
||||
GPUPage* page;
|
||||
GPUMemoryChunk* memory;
|
||||
VkImage handle;
|
||||
} GPUImage;
|
||||
|
||||
GPUMemoryType pick_memory(VkPhysicalDeviceMemoryProperties memories, uint32_t filter, VkMemoryPropertyFlags include, VkMemoryPropertyFlags exclude);
|
||||
|
||||
VkResult gpu_page_allocate(VkDevice device, VkPhysicalDeviceMemoryProperties memories, VkDeviceSize size, uint32_t filter, VkMemoryPropertyFlags include, VkMemoryPropertyFlags exclude, GPUPage** handle);
|
||||
void gpu_page_free(VkDevice device, GPUPage* page);
|
||||
VkResult gpu_buffer_malloc(VkDevice device, GPUPage* page, VkDeviceSize size, VkBufferUsageFlags usage, GPUBuffer* buffer);
|
||||
VkResult gpu_image_malloc(VkDevice device, GPUPage* page, VkImageCreateInfo* info, GPUImage* image);
|
||||
void gpu_buffer_free(VkDevice device, GPUBuffer buffer);
|
||||
|
||||
void gpu_free(GPUPage* page, GPUMemoryChunk* memory);
|
||||
|
||||
|
||||
void fprintchunks(FILE* out, GPUMemoryChunk* start);
|
||||
|
||||
|
||||
#endif
|
@ -0,0 +1,320 @@
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <gpu_mem.h>
|
||||
|
||||
GPUMemoryType pick_memory(VkPhysicalDeviceMemoryProperties memories, uint32_t filter, VkMemoryPropertyFlags include, VkMemoryPropertyFlags exclude) {
|
||||
for(uint32_t i = 0; i < memories.memoryTypeCount; i++){
|
||||
if((filter & (1 << i))
|
||||
&& ((include & memories.memoryTypes[i].propertyFlags) == include)
|
||||
&& ((exclude & memories.memoryTypes[i].propertyFlags) == 0)) {
|
||||
GPUMemoryType ret = {
|
||||
.flags = memories.memoryTypes[i].propertyFlags,
|
||||
.index = i,
|
||||
};
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
GPUMemoryType err = {
|
||||
.flags = 0,
|
||||
.index = 0xFFFFFFFF,
|
||||
};
|
||||
return err;
|
||||
}
|
||||
|
||||
VkResult gpu_page_allocate(VkDevice device, VkPhysicalDeviceMemoryProperties memories, VkDeviceSize size, uint32_t filter, VkMemoryPropertyFlags include, VkMemoryPropertyFlags exclude, GPUPage** handle) {
|
||||
if(handle == NULL) {
|
||||
return VK_ERROR_VALIDATION_FAILED_EXT;
|
||||
}
|
||||
|
||||
GPUPage* output = malloc(sizeof(GPUPage));
|
||||
if(output == NULL) {
|
||||
return VK_ERROR_OUT_OF_HOST_MEMORY;
|
||||
}
|
||||
|
||||
GPUMemoryChunk* initial_chunk = malloc(sizeof(GPUMemoryChunk));
|
||||
if(initial_chunk == 0) {
|
||||
return VK_ERROR_OUT_OF_HOST_MEMORY;
|
||||
}
|
||||
|
||||
initial_chunk->size = size;
|
||||
initial_chunk->offset = 0;
|
||||
initial_chunk->next = NULL;
|
||||
|
||||
GPUMemoryType memory_type = pick_memory(memories, filter, include, exclude);
|
||||
if(memory_type.index == 0xFFFFFFFF) {
|
||||
return VK_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
VkMemoryAllocateInfo allocate_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
|
||||
.allocationSize = size,
|
||||
.memoryTypeIndex = memory_type.index,
|
||||
.pNext = NULL,
|
||||
};
|
||||
|
||||
VkDeviceMemory memory = VK_NULL_HANDLE;
|
||||
VkResult result = vkAllocateMemory(device, &allocate_info, 0, &memory);
|
||||
if(result != VK_SUCCESS) {
|
||||
return result;
|
||||
}
|
||||
|
||||
output->memory = memory;
|
||||
output->size = size;
|
||||
output->type = memory_type;
|
||||
output->free = initial_chunk;
|
||||
output->allocated = NULL;
|
||||
|
||||
*handle = output;
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
void gpu_page_free(VkDevice device, GPUPage* page) {
|
||||
if(page == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
GPUMemoryChunk* cur = page->free;
|
||||
while(cur != NULL) {
|
||||
GPUMemoryChunk* last = cur;
|
||||
cur = cur->next;
|
||||
free(last);
|
||||
}
|
||||
|
||||
vkFreeMemory(device, page->memory, 0);
|
||||
free(page);
|
||||
}
|
||||
|
||||
void gpu_add_allocation(GPUPage* page, GPUMemoryChunk* allocation, VkDeviceSize size, GPUMemoryChunk* prev, GPUMemoryChunk* cur) {
|
||||
if(page->allocated == NULL) {
|
||||
page->allocated = allocation;
|
||||
} else {
|
||||
GPUMemoryChunk* alloc_cur = page->allocated;
|
||||
while(alloc_cur->next != NULL) {
|
||||
alloc_cur = alloc_cur->next;
|
||||
}
|
||||
alloc_cur->next = allocation;
|
||||
}
|
||||
|
||||
if(cur->size == size && prev == NULL) {
|
||||
free(cur);
|
||||
page->free = NULL;
|
||||
} else if(cur->size == size && prev != NULL) {
|
||||
prev->next = cur->next;
|
||||
free(cur);
|
||||
} else if(cur->size > size) {
|
||||
cur->offset += size;
|
||||
cur->size -= size;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
VkResult gpu_new_allocation(GPUPage* page, GPUMemoryChunk** prev, GPUMemoryChunk** cur, GPUMemoryChunk** allocation, VkDeviceSize size) {
|
||||
if(prev == NULL || cur == NULL || allocation == NULL) {
|
||||
return VK_ERROR_VALIDATION_FAILED_EXT;
|
||||
}
|
||||
|
||||
*cur = page->free;
|
||||
*prev = NULL;
|
||||
|
||||
|
||||
// Find a chunk
|
||||
while(*cur != NULL) {
|
||||
if((*cur)->size >= size) {
|
||||
break;
|
||||
}
|
||||
*prev = *cur;
|
||||
*cur = (*cur)->next;
|
||||
}
|
||||
|
||||
if(*cur == NULL) {
|
||||
return VK_ERROR_OUT_OF_DEVICE_MEMORY;
|
||||
}
|
||||
|
||||
*allocation = malloc(sizeof(GPUMemoryChunk));
|
||||
if(*allocation == NULL) {
|
||||
return VK_ERROR_OUT_OF_HOST_MEMORY;
|
||||
}
|
||||
|
||||
|
||||
(*allocation)->next = NULL;
|
||||
(*allocation)->size = size;
|
||||
(*allocation)->offset = (*cur)->offset;
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
VkResult gpu_image_malloc(VkDevice device, GPUPage* page, VkImageCreateInfo* info, GPUImage* image) {
|
||||
if(image == NULL || info == NULL || page == NULL) {
|
||||
return VK_ERROR_VALIDATION_FAILED_EXT;
|
||||
}
|
||||
|
||||
VkResult result = vkCreateImage(device, info, 0, &image->handle);
|
||||
if(result != VK_SUCCESS) {
|
||||
return result;
|
||||
}
|
||||
|
||||
VkMemoryRequirements requirements;
|
||||
vkGetImageMemoryRequirements(device, image->handle, &requirements);
|
||||
|
||||
GPUMemoryChunk* cur;
|
||||
GPUMemoryChunk* prev;
|
||||
GPUMemoryChunk* allocation;
|
||||
|
||||
result = gpu_new_allocation(page, &prev, &cur, &allocation, requirements.size);
|
||||
if(result != VK_SUCCESS) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result = vkBindImageMemory(device, image->handle, page->memory, cur->offset);
|
||||
if(result != VK_SUCCESS) {
|
||||
return result;
|
||||
}
|
||||
|
||||
image->page = page;
|
||||
image->memory = allocation;
|
||||
|
||||
gpu_add_allocation(page, allocation, requirements.size, prev, cur);
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
VkResult gpu_buffer_malloc(VkDevice device, GPUPage* page, VkDeviceSize size, VkBufferUsageFlags usage, GPUBuffer* buffer) {
|
||||
if(buffer == NULL || page == NULL) {
|
||||
return VK_ERROR_VALIDATION_FAILED_EXT;
|
||||
}
|
||||
|
||||
VkBufferCreateInfo buffer_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
|
||||
.size = size,
|
||||
.usage = usage,
|
||||
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
||||
};
|
||||
|
||||
VkResult result = vkCreateBuffer(device, &buffer_info, 0, &buffer->handle);
|
||||
if(result != VK_SUCCESS) {
|
||||
return result;
|
||||
}
|
||||
|
||||
GPUMemoryChunk* cur;
|
||||
GPUMemoryChunk* prev;
|
||||
GPUMemoryChunk* allocation;
|
||||
|
||||
result = gpu_new_allocation(page, &prev, &cur, &allocation, size);
|
||||
if(result != VK_SUCCESS) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result = vkBindBufferMemory(device, buffer->handle, page->memory, cur->offset);
|
||||
if(result != VK_SUCCESS) {
|
||||
return result;
|
||||
}
|
||||
|
||||
buffer->page = page;
|
||||
buffer->memory = allocation;
|
||||
|
||||
gpu_add_allocation(page, allocation, size, prev, cur);
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
void gpu_buffer_free(VkDevice device, GPUBuffer buffer) {
|
||||
vkDestroyBuffer(device, buffer.handle, 0);
|
||||
gpu_free(buffer.page, buffer.memory);
|
||||
}
|
||||
|
||||
void gpu_free(GPUPage* page, GPUMemoryChunk* memory) {
|
||||
|
||||
if(memory == page->allocated) {
|
||||
page->allocated = memory->next;
|
||||
} else {
|
||||
GPUMemoryChunk* cur = page->allocated;
|
||||
while(cur->next != NULL) {
|
||||
if(cur->next == memory) {
|
||||
cur->next = memory->next;
|
||||
break;
|
||||
}
|
||||
cur = cur->next;
|
||||
}
|
||||
if(cur == NULL) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
memory->next = NULL;
|
||||
|
||||
GPUMemoryChunk* free_cur = page->free;
|
||||
GPUMemoryChunk* free_prev = NULL;
|
||||
while(free_cur != NULL) {
|
||||
if(free_cur->offset > memory->offset) {
|
||||
break;
|
||||
}
|
||||
free_prev = free_cur;
|
||||
free_cur = free_cur->next;
|
||||
}
|
||||
if(free_cur == NULL && free_prev == NULL) {
|
||||
page->free = memory;
|
||||
} else {
|
||||
bool left_cont = false;
|
||||
if (free_prev != NULL) {
|
||||
left_cont = ((free_prev->offset + free_prev->size) == memory->offset);
|
||||
}
|
||||
bool right_cont = false;
|
||||
if (free_cur != NULL) {
|
||||
right_cont = ((memory->offset + memory->size) == free_cur->offset);
|
||||
}
|
||||
|
||||
fprintf(stderr, "l: %d, r: %d\n", left_cont, right_cont);
|
||||
|
||||
if(left_cont && right_cont) {
|
||||
free_prev->next = free_cur->next;
|
||||
free_prev->size += free_cur->size;
|
||||
free_prev->size += memory->size;
|
||||
|
||||
free(free_cur);
|
||||
free(memory);
|
||||
} else if(!left_cont && right_cont) {
|
||||
free_cur->offset -= memory->size;
|
||||
free_cur->size += memory->size;
|
||||
free(memory);
|
||||
} else if(left_cont && !right_cont) {
|
||||
free_prev->size += memory->size;
|
||||
free(memory);
|
||||
} else if(!left_cont && !right_cont) {
|
||||
if(free_cur == NULL) {
|
||||
memory->next = NULL;
|
||||
} else {
|
||||
memory->next = free_cur->next;
|
||||
}
|
||||
|
||||
if(free_prev == NULL) {
|
||||
memory->next = page->free;
|
||||
page->free = memory;
|
||||
} else {
|
||||
free_prev->next = memory;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void fprintchunks(FILE* out, GPUMemoryChunk* start) {
|
||||
if(start == NULL) {
|
||||
fprintf(out, "Chunks: {}\n");
|
||||
return;
|
||||
}
|
||||
|
||||
fprintf(out, "Chunks: {");
|
||||
GPUMemoryChunk* cur = start;
|
||||
while(cur != NULL) {
|
||||
if(cur->next == NULL) {
|
||||
fprintf(out, "%llu@%llu}", cur->size, cur->offset);
|
||||
} else {
|
||||
fprintf(out, "%llu@%llu, ", cur->size, cur->offset);
|
||||
}
|
||||
cur = cur->next;
|
||||
}
|
||||
fprintf(out, "\n");
|
||||
}
|
Loading…
Reference in New Issue