|
|
|
@ -52,6 +52,17 @@ typedef struct AllocatedBufferStruct {
|
|
|
|
|
VkDeviceMemory memory;
|
|
|
|
|
} AllocatedBuffer;
|
|
|
|
|
|
|
|
|
|
typedef struct AllocatedImageStruct {
|
|
|
|
|
VkImage image;
|
|
|
|
|
VkDeviceMemory memory;
|
|
|
|
|
} AllocatedImage;
|
|
|
|
|
|
|
|
|
|
typedef struct TextureStruct {
|
|
|
|
|
AllocatedImage image;
|
|
|
|
|
VkImageView view;
|
|
|
|
|
VkSampler sampler;
|
|
|
|
|
} Texture;
|
|
|
|
|
|
|
|
|
|
typedef struct MeshStruct {
|
|
|
|
|
uint32_t vertex_count;
|
|
|
|
|
AllocatedBuffer vertex_buffer;
|
|
|
|
@ -546,7 +557,9 @@ VkDevice create_logical_device(VkPhysicalDevice physical_device, QueueIndices qu
|
|
|
|
|
queue_create_info[i].pQueuePriorities = &default_queue_priority;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VkPhysicalDeviceFeatures device_features = {};
|
|
|
|
|
VkPhysicalDeviceFeatures device_features = {
|
|
|
|
|
.samplerAnisotropy = VK_TRUE,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
VkDeviceCreateInfo device_create_info = {};
|
|
|
|
|
device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
|
|
|
|
@ -883,6 +896,60 @@ uint32_t find_memory_type(VkPhysicalDevice physical_device, uint32_t type_filter
|
|
|
|
|
return 0xFFFFFFFF;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AllocatedImage allocate_image(VkPhysicalDevice physical_device, VkDevice device, VkImageType type, VkFormat format, VkExtent3D size, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, VkSampleCountFlagBits samples) {
|
|
|
|
|
VkImageCreateInfo image_info = {
|
|
|
|
|
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
|
|
|
|
|
.imageType = type,
|
|
|
|
|
.extent = size,
|
|
|
|
|
.mipLevels = 1,
|
|
|
|
|
.arrayLayers = 1,
|
|
|
|
|
.format = format,
|
|
|
|
|
.tiling = VK_IMAGE_TILING_OPTIMAL,
|
|
|
|
|
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
|
|
|
|
|
.usage = usage,
|
|
|
|
|
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
|
|
|
|
.samples = samples,
|
|
|
|
|
.flags = 0,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
AllocatedImage allocated = {
|
|
|
|
|
.memory = VK_NULL_HANDLE,
|
|
|
|
|
.image = VK_NULL_HANDLE,
|
|
|
|
|
};
|
|
|
|
|
VkResult result = vkCreateImage(device, &image_info, 0, &allocated.image);
|
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
|
return allocated;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VkMemoryRequirements memory_requirements;
|
|
|
|
|
vkGetImageMemoryRequirements(device, allocated.image, &memory_requirements);
|
|
|
|
|
|
|
|
|
|
VkMemoryAllocateInfo memory_info = {
|
|
|
|
|
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
|
|
|
|
|
.allocationSize = memory_requirements.size,
|
|
|
|
|
.memoryTypeIndex = find_memory_type(physical_device, memory_requirements.memoryTypeBits, properties),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
result = vkAllocateMemory(device, &memory_info, 0, &allocated.memory);
|
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
|
vkDestroyImage(device, allocated.image, 0);
|
|
|
|
|
allocated.image = VK_NULL_HANDLE;
|
|
|
|
|
return allocated;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
result = vkBindImageMemory(device, allocated.image, allocated.memory, 0);
|
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
|
vkFreeMemory(device, allocated.memory, 0);
|
|
|
|
|
vkDestroyImage(device, allocated.image, 0);
|
|
|
|
|
allocated.memory = VK_NULL_HANDLE;
|
|
|
|
|
allocated.image = VK_NULL_HANDLE;
|
|
|
|
|
|
|
|
|
|
return allocated;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return allocated;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AllocatedBuffer allocate_buffer(VkPhysicalDevice physical_device, VkDevice device, VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties) {
|
|
|
|
|
AllocatedBuffer ret = {};
|
|
|
|
|
ret.memory = VK_NULL_HANDLE;
|
|
|
|
@ -934,6 +1001,11 @@ void deallocate_buffer(VkDevice device, AllocatedBuffer buffer) {
|
|
|
|
|
vkFreeMemory(device, buffer.memory, 0);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
void deallocate_image(VkDevice device, AllocatedImage image) {
|
|
|
|
|
vkDestroyImage(device, image.image, 0);
|
|
|
|
|
vkFreeMemory(device, image.memory, 0);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
AllocatedBuffer* allocate_buffers(VkPhysicalDevice physical_device, VkDevice device, VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, uint32_t count) {
|
|
|
|
|
AllocatedBuffer* buffers = malloc(sizeof(AllocatedBuffer)*count);
|
|
|
|
|
if(buffers == 0) {
|
|
|
|
@ -955,7 +1027,7 @@ AllocatedBuffer* allocate_buffers(VkPhysicalDevice physical_device, VkDevice dev
|
|
|
|
|
return buffers;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VkResult command_copy_buffers(VkDevice device, VkCommandPool transfer_pool, VkQueue transfer_queue, VkBuffer source, VkBuffer dest, VkDeviceSize size) {
|
|
|
|
|
VkCommandBuffer command_begin_single(VkDevice device, VkCommandPool transfer_pool) {
|
|
|
|
|
VkCommandBufferAllocateInfo command_info = {};
|
|
|
|
|
command_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
|
|
|
|
command_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
|
|
|
@ -965,7 +1037,7 @@ VkResult command_copy_buffers(VkDevice device, VkCommandPool transfer_pool, VkQu
|
|
|
|
|
VkCommandBuffer command_buffer;
|
|
|
|
|
VkResult result = vkAllocateCommandBuffers(device, &command_info, &command_buffer);
|
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
|
return result;
|
|
|
|
|
return VK_NULL_HANDLE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VkCommandBufferBeginInfo begin_info = {};
|
|
|
|
@ -975,41 +1047,96 @@ VkResult command_copy_buffers(VkDevice device, VkCommandPool transfer_pool, VkQu
|
|
|
|
|
result = vkBeginCommandBuffer(command_buffer, &begin_info);
|
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
|
vkFreeCommandBuffers(device, transfer_pool, 1, &command_buffer);
|
|
|
|
|
return result;
|
|
|
|
|
return VK_NULL_HANDLE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VkBufferCopy copy_region = {};
|
|
|
|
|
copy_region.srcOffset = 0;
|
|
|
|
|
copy_region.dstOffset = 0;
|
|
|
|
|
copy_region.size = size;
|
|
|
|
|
|
|
|
|
|
vkCmdCopyBuffer(command_buffer, source, dest, 1, ©_region);
|
|
|
|
|
result = vkEndCommandBuffer(command_buffer);
|
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
|
vkFreeCommandBuffers(device, transfer_pool, 1, &command_buffer);
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
return command_buffer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VkResult command_end_single(VkDevice device, VkCommandBuffer command_buffer, VkCommandPool transfer_pool, VkQueue transfer_queue) {
|
|
|
|
|
VkSubmitInfo submit_info = {};
|
|
|
|
|
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
|
|
|
|
submit_info.commandBufferCount = 1;
|
|
|
|
|
submit_info.pCommandBuffers = &command_buffer;
|
|
|
|
|
|
|
|
|
|
result = vkQueueSubmit(transfer_queue, 1, &submit_info, 0);
|
|
|
|
|
VkResult result = vkQueueSubmit(transfer_queue, 1, &submit_info, 0);
|
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
|
vkFreeCommandBuffers(device, transfer_pool, 1, &command_buffer);
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
result = vkQueueWaitIdle(transfer_queue);
|
|
|
|
|
vkFreeCommandBuffers(device, transfer_pool, 1, &command_buffer);
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VkResult command_copy_buffers(VkDevice device, VkCommandPool transfer_pool, VkQueue transfer_queue, VkBuffer source, VkBuffer dest, VkDeviceSize size) {
|
|
|
|
|
VkCommandBuffer command_buffer = command_begin_single(device, transfer_pool);
|
|
|
|
|
|
|
|
|
|
VkBufferCopy copy_region = {};
|
|
|
|
|
copy_region.srcOffset = 0;
|
|
|
|
|
copy_region.dstOffset = 0;
|
|
|
|
|
copy_region.size = size;
|
|
|
|
|
|
|
|
|
|
vkCmdCopyBuffer(command_buffer, source, dest, 1, ©_region);
|
|
|
|
|
VkResult result = vkEndCommandBuffer(command_buffer);
|
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
|
vkFreeCommandBuffers(device, transfer_pool, 1, &command_buffer);
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vkFreeCommandBuffers(device, transfer_pool, 1, &command_buffer);
|
|
|
|
|
return command_end_single(device, command_buffer, transfer_pool, transfer_queue);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return VK_SUCCESS;
|
|
|
|
|
VkResult command_transition_image_layout(VkDevice device, VkCommandPool transfer_pool, VkQueue transfer_queue, VkImageLayout old_layout, VkImageLayout new_layout, VkImage image) {
|
|
|
|
|
VkCommandBuffer command_buffer = command_begin_single(device, transfer_pool);
|
|
|
|
|
|
|
|
|
|
VkImageMemoryBarrier barrier = {
|
|
|
|
|
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
|
|
|
|
.oldLayout = old_layout,
|
|
|
|
|
.newLayout = new_layout,
|
|
|
|
|
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
|
|
|
|
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
|
|
|
|
.image = image,
|
|
|
|
|
.subresourceRange = {
|
|
|
|
|
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
|
|
|
|
.levelCount = 1,
|
|
|
|
|
.layerCount = 1,
|
|
|
|
|
.baseMipLevel = 0,
|
|
|
|
|
.baseArrayLayer = 0,
|
|
|
|
|
},
|
|
|
|
|
.srcAccessMask = 0,
|
|
|
|
|
.dstAccessMask = 0,
|
|
|
|
|
};
|
|
|
|
|
vkCmdPipelineBarrier(command_buffer, 0, 0, 0, 0, 0, 0, 0, 1, &barrier);
|
|
|
|
|
|
|
|
|
|
return command_end_single(device, command_buffer, transfer_pool, transfer_queue);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VkResult command_copy_buffer_to_image(VkDevice device, VkCommandPool transfer_pool, VkQueue transfer_queue, VkExtent3D image_size, VkBuffer source, VkImage dest) {
|
|
|
|
|
VkCommandBuffer command_buffer = command_begin_single(device, transfer_pool);
|
|
|
|
|
|
|
|
|
|
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 = image_size,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
vkCmdCopyBufferToImage(command_buffer, source, dest, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion);
|
|
|
|
|
|
|
|
|
|
return command_end_single(device, command_buffer, transfer_pool, transfer_queue);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AllocatedBuffer create_populated_buffer(VkPhysicalDevice physical_device, VkDevice device, void* data, VkDeviceSize size, VkCommandPool transfer_pool, VkQueue transfer_queue, VkBufferUsageFlags usage) {
|
|
|
|
@ -1050,6 +1177,118 @@ AllocatedBuffer create_populated_buffer(VkPhysicalDevice physical_device, VkDevi
|
|
|
|
|
return vertex_buffer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Texture load_texture(VkPhysicalDevice physical_device, VkDevice device, VkCommandPool transfer_pool, VkQueue transfer_queue, VkExtent2D size, uint32_t stride, VkFormat format, void* image_data){
|
|
|
|
|
Texture ret = {
|
|
|
|
|
.image.image = VK_NULL_HANDLE,
|
|
|
|
|
.image.memory = VK_NULL_HANDLE,
|
|
|
|
|
.view = VK_NULL_HANDLE,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
uint32_t image_size = size.width * size.height * stride;
|
|
|
|
|
AllocatedBuffer staging = allocate_buffer(physical_device, device, image_size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
|
|
|
|
|
if(staging.memory == VK_NULL_HANDLE) {
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void* staging_ptr;
|
|
|
|
|
VkResult result = vkMapMemory(device, staging.memory, 0, image_size, 0, &staging_ptr);
|
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
|
deallocate_buffer(device, staging);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
memcpy(staging_ptr, image_data, image_size);
|
|
|
|
|
|
|
|
|
|
vkUnmapMemory(device, staging.memory);
|
|
|
|
|
|
|
|
|
|
VkExtent3D full_extent = {
|
|
|
|
|
.width = size.width,
|
|
|
|
|
.height = size.height,
|
|
|
|
|
.depth = 1,
|
|
|
|
|
};
|
|
|
|
|
AllocatedImage image = allocate_image(physical_device, device, VK_IMAGE_TYPE_2D, format, full_extent, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, VK_SAMPLE_COUNT_1_BIT);
|
|
|
|
|
if(image.memory == VK_NULL_HANDLE) {
|
|
|
|
|
deallocate_buffer(device, staging);
|
|
|
|
|
deallocate_image(device, image);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
result = command_transition_image_layout(device, transfer_pool, transfer_queue, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, image.image);
|
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
|
deallocate_buffer(device, staging);
|
|
|
|
|
deallocate_image(device, image);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
result = command_copy_buffer_to_image(device, transfer_pool, transfer_queue, full_extent, staging.buffer, image.image);
|
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
|
deallocate_buffer(device, staging);
|
|
|
|
|
deallocate_image(device, image);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
VkImageView view;
|
|
|
|
|
VkImageViewCreateInfo view_info = {
|
|
|
|
|
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
|
|
|
|
|
.image = image.image,
|
|
|
|
|
.viewType = VK_IMAGE_VIEW_TYPE_2D,
|
|
|
|
|
.components = {
|
|
|
|
|
.a = VK_COMPONENT_SWIZZLE_IDENTITY,
|
|
|
|
|
.b = VK_COMPONENT_SWIZZLE_IDENTITY,
|
|
|
|
|
.g = VK_COMPONENT_SWIZZLE_IDENTITY,
|
|
|
|
|
.r = VK_COMPONENT_SWIZZLE_IDENTITY,
|
|
|
|
|
},
|
|
|
|
|
.format = format,
|
|
|
|
|
.subresourceRange = {
|
|
|
|
|
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
|
|
|
|
.layerCount = 1,
|
|
|
|
|
.levelCount = 1,
|
|
|
|
|
.baseArrayLayer = 0,
|
|
|
|
|
.baseMipLevel = 0,
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
result = vkCreateImageView(device, &view_info, 0, &view);
|
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
|
deallocate_buffer(device, staging);
|
|
|
|
|
deallocate_image(device, image);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VkSampler sampler;
|
|
|
|
|
VkSamplerCreateInfo sampler_info = {
|
|
|
|
|
.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
|
|
|
|
|
.magFilter = VK_FILTER_NEAREST,
|
|
|
|
|
.minFilter = VK_FILTER_NEAREST,
|
|
|
|
|
.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT,
|
|
|
|
|
.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT,
|
|
|
|
|
.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT,
|
|
|
|
|
.anisotropyEnable = VK_TRUE,
|
|
|
|
|
.maxAnisotropy = 2,
|
|
|
|
|
.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK,
|
|
|
|
|
.unnormalizedCoordinates = VK_FALSE,
|
|
|
|
|
.compareEnable = VK_FALSE,
|
|
|
|
|
.compareOp = VK_COMPARE_OP_ALWAYS,
|
|
|
|
|
.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR,
|
|
|
|
|
.mipLodBias = 0.0f,
|
|
|
|
|
.minLod = 0.0f,
|
|
|
|
|
.maxLod = 0.0f,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
result = vkCreateSampler(device, &sampler_info, 0, &sampler);
|
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
|
deallocate_buffer(device, staging);
|
|
|
|
|
deallocate_image(device, image);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ret.image = image;
|
|
|
|
|
ret.view = view;
|
|
|
|
|
ret.sampler = sampler;
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VkPipeline create_graphics_pipeline(
|
|
|
|
|
VkDevice device,
|
|
|
|
|
VkExtent2D extent,
|
|
|
|
|