|
|
|
@ -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));
|
|
|
|
|
|
|
|
|
|