diff --git a/src/main.c b/src/main.c index a997216..1a9a773 100644 --- a/src/main.c +++ b/src/main.c @@ -2355,6 +2355,215 @@ Material create_texture_mesh_material(VkDevice device, VkExtent2D extent, VkRend return create_material(device, extent, render_pass, 2, shader_stages, scene_ubo_layout, texture_layout, textured_mesh_type, max_frames_in_flight, object_descriptor_mappings); } +typedef struct MemoryChunkStruct { + VkDeviceMemory memory; + VkDeviceSize free; +} MemoryChunk; + +VkResult allocate_memory_chunk(uint32_t memory_type, VkDevice device, VkDeviceSize size, MemoryChunk* allocated) { + if(allocated == NULL) { + return VK_ERROR_UNKNOWN; + } + + VkMemoryAllocateInfo allocate_info = { + .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, + .memoryTypeIndex = memory_type, + .allocationSize = size, + }; + + VkResult result = vkAllocateMemory(device, &allocate_info, 0, &allocated->memory); + if(result != VK_SUCCESS) { + return result; + } + + allocated->free = size; + + return VK_SUCCESS; +} + +VkResult create_image(MemoryChunk* memory, VkDevice device, VkDeviceSize offset, VkImageType type, VkFormat format, VkExtent3D extent, VkImageUsageFlags usage, VkImage* image) { + if(image == NULL) { + return VK_ERROR_UNKNOWN; + } else if (*image != VK_NULL_HANDLE) { + return VK_ERROR_UNKNOWN; + } else if (memory == NULL) { + return VK_ERROR_UNKNOWN; + } + + VkImageCreateInfo image_info = { + .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, + .imageType = type, + .extent = extent, + .mipLevels = 1, + .arrayLayers = 1, + .format = format, + .tiling = VK_IMAGE_TILING_OPTIMAL, + .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, + .usage = usage, + .sharingMode = VK_SHARING_MODE_EXCLUSIVE, + .samples = VK_SAMPLE_COUNT_1_BIT, + .flags = 0, + }; + + VkResult result = vkCreateImage(device, &image_info, 0, image); + if(result != VK_SUCCESS) { + return result; + } + + result = vkBindImageMemory(device, *image, memory->memory, offset); + if(result != VK_SUCCESS) { + vkDestroyImage(device, *image, 0); + *image = VK_NULL_HANDLE; + return result; + } + + VkMemoryRequirements memory_requirements; + vkGetImageMemoryRequirements(device, *image, &memory_requirements); + + memory->free -= memory_requirements.size; + + return VK_SUCCESS; +} + +VkResult create_buffer(MemoryChunk* memory, VkDevice device, VkDeviceSize offset, VkDeviceSize size, VkBufferUsageFlags usage, VkBuffer* buffer) { + if(buffer == NULL) { + return VK_ERROR_UNKNOWN; + } else if (*buffer != VK_NULL_HANDLE) { + return VK_ERROR_UNKNOWN; + } else if (memory == NULL) { + return VK_ERROR_UNKNOWN; + } else if (memory->free < size) { + return VK_ERROR_UNKNOWN; + } + + 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); + if(result != VK_SUCCESS) { + return result; + } + + VkMemoryRequirements memory_requirements; + vkGetBufferMemoryRequirements(device, *buffer, &memory_requirements); + + result = vkBindBufferMemory(device, *buffer, memory->memory, offset); + if(result != VK_SUCCESS) { + vkDestroyBuffer(device, *buffer, 0); + *buffer = VK_NULL_HANDLE; + return result; + } + + memory->free -= size; + return VK_SUCCESS; +} + +VkResult create_buffers(MemoryChunk* memory, VkDevice device, VkDeviceSize offset, VkDeviceSize size, VkBufferUsageFlags usage, VkBuffer** buffers, uint32_t count) { + if(buffers == NULL) { + return VK_ERROR_UNKNOWN; + } else if(*buffers == NULL) { + return VK_ERROR_UNKNOWN; + } + + *buffers = malloc(sizeof(VkBuffer)*count); + if(*buffers == NULL) { + return VK_ERROR_OUT_OF_HOST_MEMORY; + } + + for(uint32_t i = 0; i < count; i++) { + VkResult result = create_buffer(memory, device, offset + (i*size), size, usage, &(*buffers)[i]); + if(result != VK_SUCCESS) { + for(uint32_t j = 0; j < i; j++) { + vkDestroyBuffer(device, *buffers[j], 0); + } + free(buffers); + return result; + } + } + + return VK_SUCCESS; +} + +VkResult command_copy_to_image(VkDevice device, VkBuffer staging_buffer, VkDeviceMemory staging_memory, VkImage destination, void* data, VkExtent3D size, VkDeviceSize stride, VkCommandPool pool, VkQueue queue) { + VkDeviceSize data_size = size.height * size.width * stride; + + void* mapped_ptr = NULL; + VkResult result = vkMapMemory(device, staging_memory, 0, data_size, 0, &mapped_ptr); + if(result != VK_SUCCESS) { + vkDestroyBuffer(device, staging_buffer, 0); + return result; + } + + memcpy(mapped_ptr, data, data_size); + + vkUnmapMemory(device, staging_memory); + + VkCommandBuffer command_buffer = command_begin_single(device, pool); + if(command_buffer == VK_NULL_HANDLE) { + vkDestroyBuffer(device, staging_buffer, 0); + return VK_ERROR_UNKNOWN; + } + + VkBufferImageCopy region = { + .bufferOffset = 0, + .bufferRowLength = 0, + .bufferImageHeight = 0, + .imageSubresource = { + .baseArrayLayer = 0, + .layerCount = 1, + .mipLevel = 0, + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + }, + .imageOffset = { + .x = 0, + .y = 0, + .z = 0, + }, + .imageExtent = size, + }; + + vkCmdCopyBufferToImage(command_buffer, staging_buffer, destination, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); + + result = command_end_single(device, command_buffer, pool, queue); + vkDestroyBuffer(device, staging_buffer, 0); + return result; +} + +VkResult command_copy_to_buffer(VkDevice device, VkBuffer staging_buffer, VkDeviceMemory staging_memory, VkBuffer destination, void* data, VkDeviceSize size, VkDeviceSize offset, VkCommandPool pool, VkQueue queue) { + void* mapped_ptr = NULL; + VkResult result = vkMapMemory(device, staging_memory, 0, size, 0, &mapped_ptr); + if(result != VK_SUCCESS) { + vkDestroyBuffer(device, staging_buffer, 0); + return result; + } + + memcpy(mapped_ptr, data, size); + + vkUnmapMemory(device, staging_memory); + + VkCommandBuffer command_buffer = command_begin_single(device, pool); + if(command_buffer == VK_NULL_HANDLE) { + vkDestroyBuffer(device, staging_buffer, 0); + return VK_ERROR_UNKNOWN; + } + + VkBufferCopy region = { + .srcOffset = 0, + .dstOffset = offset, + .size = size, + }; + + vkCmdCopyBuffer(command_buffer, staging_buffer, destination, 1, ®ion); + + result = command_end_single(device, command_buffer, pool, queue); + vkDestroyBuffer(device, staging_buffer, 0); + return result; +} + VulkanContext* init_vulkan(GLFWwindow* window, uint32_t max_frames_in_flight) { VulkanContext* context = (VulkanContext*)malloc(sizeof(VulkanContext));