905 lines
29 KiB
C
905 lines
29 KiB
C
#include "pipeline.h"
|
|
#include "cglm/affine.h"
|
|
#include "cglm/mat4.h"
|
|
#include "command.h"
|
|
#include "stdio.h"
|
|
#include "stdlib.h"
|
|
#include "string.h"
|
|
#include "vk_mem_alloc.h"
|
|
#include "vulkan/vulkan_core.h"
|
|
|
|
VkShaderModule load_shader_file(const char* path, VkDevice device) {
|
|
FILE* file;
|
|
file = fopen(path, "rb");
|
|
if(file == 0) {
|
|
return VK_NULL_HANDLE;
|
|
}
|
|
|
|
int result = fseek(file, 0, SEEK_END);
|
|
if(result != 0) {
|
|
return VK_NULL_HANDLE;
|
|
}
|
|
|
|
long buffer_size = ftell(file);
|
|
|
|
result = fseek(file, 0, SEEK_SET);
|
|
if(result != 0) {
|
|
return VK_NULL_HANDLE;
|
|
}
|
|
|
|
char * buffer = malloc(buffer_size);
|
|
if(buffer == 0) {
|
|
return VK_NULL_HANDLE;
|
|
}
|
|
|
|
size_t read = fread(buffer, 1, buffer_size, file);
|
|
|
|
VkShaderModuleCreateInfo shader_info = {
|
|
.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
|
|
.codeSize = read,
|
|
.pCode = (uint32_t*)buffer,
|
|
};
|
|
|
|
VkShaderModule shader;
|
|
result = vkCreateShaderModule(device, &shader_info, 0, &shader);
|
|
free(buffer);
|
|
if(result != VK_SUCCESS) {
|
|
return VK_NULL_HANDLE;
|
|
}
|
|
|
|
return shader;
|
|
}
|
|
|
|
VkResult create_ui_pipeline(
|
|
VkDevice device,
|
|
VkRenderPass render_pass,
|
|
VkPipelineShaderStageCreateInfo* shader_stages,
|
|
uint32_t shader_stage_count,
|
|
VkPipelineVertexInputStateCreateInfo input_info,
|
|
VkPipelineLayoutCreateInfo layout_info,
|
|
VkPipelineInputAssemblyStateCreateInfo input_assembly_info,
|
|
GraphicsPipeline* pipeline) {
|
|
VkResult result;
|
|
|
|
result = vkCreatePipelineLayout(device, &layout_info, 0, &pipeline->layout);
|
|
if(result != VK_SUCCESS) {
|
|
return result;
|
|
}
|
|
|
|
VkViewport viewport = {
|
|
.x = 0.0f,
|
|
.y = 0.0f,
|
|
.width = (float)(100),
|
|
.height = (float)(100),
|
|
.minDepth = 0.0f,
|
|
.maxDepth = 1.0f,
|
|
};
|
|
|
|
VkRect2D scissor = {
|
|
.offset = {
|
|
.x = 0,
|
|
.y = 0,
|
|
},
|
|
.extent = {
|
|
.width = 100,
|
|
.height = 100,
|
|
},
|
|
};
|
|
|
|
VkPipelineViewportStateCreateInfo viewport_state = {
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
|
|
.viewportCount = 1,
|
|
.pViewports = &viewport,
|
|
.scissorCount = 1,
|
|
.pScissors = &scissor,
|
|
};
|
|
|
|
VkPipelineRasterizationStateCreateInfo raster_info = {
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
|
|
.depthClampEnable = VK_FALSE,
|
|
.rasterizerDiscardEnable = VK_FALSE,
|
|
.polygonMode = VK_POLYGON_MODE_FILL,
|
|
.lineWidth = 1.0f,
|
|
.cullMode = VK_CULL_MODE_BACK_BIT,
|
|
.frontFace = VK_FRONT_FACE_CLOCKWISE,
|
|
.depthBiasEnable = VK_FALSE,
|
|
.depthBiasConstantFactor = 0.0f,
|
|
.depthBiasClamp = 0.0f,
|
|
.depthBiasSlopeFactor = 0.0f,
|
|
};
|
|
|
|
VkPipelineMultisampleStateCreateInfo multisample_info = {
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
|
|
.sampleShadingEnable = VK_FALSE,
|
|
.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT,
|
|
.minSampleShading = 1.0f,
|
|
.pSampleMask = 0,
|
|
.alphaToCoverageEnable = VK_FALSE,
|
|
.alphaToOneEnable = VK_FALSE,
|
|
};
|
|
|
|
VkPipelineDepthStencilStateCreateInfo depth_info = {
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
|
|
.depthTestEnable = VK_TRUE,
|
|
.depthWriteEnable = VK_TRUE,
|
|
.depthCompareOp = VK_COMPARE_OP_LESS,
|
|
.depthBoundsTestEnable = VK_FALSE,
|
|
.maxDepthBounds = 1.0f,
|
|
.minDepthBounds = 0.0f,
|
|
.stencilTestEnable = VK_FALSE,
|
|
.front = {},
|
|
.back = {},
|
|
};
|
|
|
|
VkPipelineColorBlendAttachmentState color_blend_attachment = {
|
|
.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
|
|
.blendEnable = VK_TRUE,
|
|
.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA,
|
|
.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
|
|
.colorBlendOp = VK_BLEND_OP_ADD,
|
|
.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE,
|
|
.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
|
|
.alphaBlendOp = VK_BLEND_OP_ADD,
|
|
};
|
|
|
|
VkPipelineColorBlendStateCreateInfo color_blend_info = {
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
|
|
.logicOpEnable = VK_FALSE,
|
|
.logicOp = VK_LOGIC_OP_COPY,
|
|
.attachmentCount = 1,
|
|
.pAttachments = &color_blend_attachment,
|
|
.blendConstants[0] = 0.0f,
|
|
.blendConstants[1] = 0.0f,
|
|
.blendConstants[2] = 0.0f,
|
|
.blendConstants[3] = 0.0f,
|
|
};
|
|
|
|
VkDynamicState dynamic_states[] = {
|
|
VK_DYNAMIC_STATE_VIEWPORT,
|
|
VK_DYNAMIC_STATE_SCISSOR,
|
|
};
|
|
|
|
uint32_t dynamic_state_count = sizeof(dynamic_states)/sizeof(VkDynamicState);
|
|
|
|
VkPipelineDynamicStateCreateInfo dynamic_info = {
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
|
|
.dynamicStateCount = dynamic_state_count,
|
|
.pDynamicStates = dynamic_states,
|
|
};
|
|
|
|
VkGraphicsPipelineCreateInfo draw_pipeline_info = {
|
|
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
|
.stageCount = shader_stage_count,
|
|
.pStages = shader_stages,
|
|
.pVertexInputState = &input_info,
|
|
.pInputAssemblyState = &input_assembly_info,
|
|
.pViewportState = &viewport_state,
|
|
.pRasterizationState = &raster_info,
|
|
.pColorBlendState = &color_blend_info,
|
|
.pDynamicState = &dynamic_info,
|
|
.pDepthStencilState = &depth_info,
|
|
.pMultisampleState = &multisample_info,
|
|
.layout = pipeline->layout,
|
|
.renderPass = render_pass,
|
|
.subpass = 0,
|
|
.basePipelineHandle = VK_NULL_HANDLE,
|
|
.basePipelineIndex = -1,
|
|
};
|
|
|
|
result = vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &draw_pipeline_info, 0, &pipeline->pipeline);
|
|
if(result != VK_SUCCESS) {
|
|
return result;
|
|
}
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
VkResult create_ui_colored_rect_pipeline(VkDevice device, VkRenderPass render_pass, VkDescriptorSetLayout ui_descriptor_layout, GraphicsPipeline* pipeline) {
|
|
VkShaderModule vert_shader = load_shader_file("shader_src/ui_colored_rect.vert.spv", device);
|
|
if(vert_shader == VK_NULL_HANDLE) {
|
|
return VK_ERROR_UNKNOWN;
|
|
}
|
|
VkShaderModule frag_shader = load_shader_file("shader_src/ui_colored_rect.frag.spv", device);
|
|
if(frag_shader == VK_NULL_HANDLE) {
|
|
return VK_ERROR_UNKNOWN;
|
|
}
|
|
VkPipelineShaderStageCreateInfo shader_stages[] = {
|
|
{
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
|
.stage = VK_SHADER_STAGE_VERTEX_BIT,
|
|
.module = vert_shader,
|
|
.pName = "main",
|
|
},
|
|
{
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
|
.stage = VK_SHADER_STAGE_FRAGMENT_BIT,
|
|
.module = frag_shader,
|
|
.pName = "main",
|
|
},
|
|
};
|
|
|
|
VkVertexInputBindingDescription bindings[] = {
|
|
{
|
|
.binding = 0,
|
|
.stride = sizeof(vec2),
|
|
.inputRate = VK_VERTEX_INPUT_RATE_VERTEX,
|
|
},
|
|
{
|
|
.binding = 1,
|
|
.stride = sizeof(ColoredRect),
|
|
.inputRate = VK_VERTEX_INPUT_RATE_INSTANCE,
|
|
},
|
|
};
|
|
|
|
VkVertexInputAttributeDescription attributes[] = {
|
|
{
|
|
.binding = 0,
|
|
.location = 0,
|
|
.format = VK_FORMAT_R32G32_SFLOAT,
|
|
.offset = 0,
|
|
},
|
|
{
|
|
.binding = 1,
|
|
.location = 1,
|
|
.format = VK_FORMAT_R32G32B32_SFLOAT,
|
|
.offset = offsetof(ColoredRect, pos),
|
|
},
|
|
{
|
|
.binding = 1,
|
|
.location = 2,
|
|
.format = VK_FORMAT_R32G32_SFLOAT,
|
|
.offset = offsetof(ColoredRect, size),
|
|
},
|
|
{
|
|
.binding = 1,
|
|
.location = 3,
|
|
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
|
|
.offset = offsetof(ColoredRect, color),
|
|
},
|
|
};
|
|
|
|
VkPipelineVertexInputStateCreateInfo input_info = {
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
|
|
.pVertexBindingDescriptions = bindings,
|
|
.vertexBindingDescriptionCount = sizeof(bindings)/sizeof(VkVertexInputBindingDescription),
|
|
.pVertexAttributeDescriptions = attributes,
|
|
.vertexAttributeDescriptionCount = sizeof(attributes)/sizeof(VkVertexInputAttributeDescription),
|
|
};
|
|
|
|
VkPipelineLayoutCreateInfo layout_info = {
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
|
|
.setLayoutCount = 1,
|
|
.pSetLayouts = &ui_descriptor_layout,
|
|
};
|
|
|
|
VkPipelineInputAssemblyStateCreateInfo input_assembly_info = {
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
|
|
.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
|
|
.primitiveRestartEnable = VK_FALSE,
|
|
};
|
|
|
|
VkResult result = create_ui_pipeline(device, render_pass, shader_stages, sizeof(shader_stages)/sizeof(VkPipelineShaderStageCreateInfo), input_info, layout_info, input_assembly_info, pipeline);
|
|
if(result != VK_SUCCESS) {
|
|
return result;
|
|
}
|
|
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
VkResult create_ui_text_pipeline(VkDevice device, VkRenderPass render_pass, VkDescriptorSetLayout ui_descriptor_layout, VkDescriptorSetLayout text_layout, GraphicsPipeline* pipeline) {
|
|
VkShaderModule vert_shader = load_shader_file("shader_src/ui_text.vert.spv", device);
|
|
if(vert_shader == VK_NULL_HANDLE) {
|
|
return VK_ERROR_UNKNOWN;
|
|
}
|
|
VkShaderModule frag_shader = load_shader_file("shader_src/ui_text.frag.spv", device);
|
|
if(frag_shader == VK_NULL_HANDLE) {
|
|
return VK_ERROR_UNKNOWN;
|
|
}
|
|
|
|
// TODO: add a compute stage before the shader stages that sets up the draw buffer and commands for the characters based off of strings + positions
|
|
// 1. Reserve a buffer for array of draw command params + Char on the GPU
|
|
// 2. Reserve a buffer for Text on the GPU
|
|
VkPipelineShaderStageCreateInfo shader_stages[] = {
|
|
{
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
|
.stage = VK_SHADER_STAGE_VERTEX_BIT,
|
|
.module = vert_shader,
|
|
.pName = "main",
|
|
},
|
|
{
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
|
.stage = VK_SHADER_STAGE_FRAGMENT_BIT,
|
|
.module = frag_shader,
|
|
.pName = "main",
|
|
},
|
|
};
|
|
|
|
VkVertexInputBindingDescription bindings[] = {
|
|
{
|
|
.binding = 0,
|
|
.stride = sizeof(vec2),
|
|
.inputRate = VK_VERTEX_INPUT_RATE_VERTEX,
|
|
},
|
|
{
|
|
.binding = 1,
|
|
.stride = sizeof(Char),
|
|
.inputRate = VK_VERTEX_INPUT_RATE_INSTANCE,
|
|
}
|
|
};
|
|
VkVertexInputAttributeDescription attributes[] = {
|
|
{
|
|
.binding = 0,
|
|
.location = 0,
|
|
.format = VK_FORMAT_R32G32_SFLOAT,
|
|
.offset = 0,
|
|
},
|
|
{
|
|
.binding = 1,
|
|
.location = 1,
|
|
.format = VK_FORMAT_R32G32B32_SFLOAT,
|
|
.offset = offsetof(Char, pos),
|
|
},
|
|
{
|
|
.binding = 1,
|
|
.location = 2,
|
|
.format = VK_FORMAT_R32G32_SFLOAT,
|
|
.offset = offsetof(Char, size),
|
|
},
|
|
{
|
|
.binding = 1,
|
|
.location = 3,
|
|
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
|
|
.offset = offsetof(Char, color),
|
|
},
|
|
{
|
|
.binding = 1,
|
|
.location = 4,
|
|
.format = VK_FORMAT_R32_UINT,
|
|
.offset = offsetof(Char, code),
|
|
},
|
|
};
|
|
|
|
VkPipelineVertexInputStateCreateInfo input_info = {
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
|
|
.pVertexBindingDescriptions = bindings,
|
|
.vertexBindingDescriptionCount = sizeof(bindings)/sizeof(VkVertexInputBindingDescription),
|
|
.pVertexAttributeDescriptions = attributes,
|
|
.vertexAttributeDescriptionCount = sizeof(attributes)/sizeof(VkVertexInputAttributeDescription),
|
|
};
|
|
|
|
VkDescriptorSetLayout all_layouts[] = {ui_descriptor_layout, text_layout};
|
|
VkPipelineLayoutCreateInfo layout_info = {
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
|
|
.setLayoutCount = sizeof(all_layouts)/sizeof(VkDescriptorSetLayout),
|
|
.pSetLayouts = all_layouts,
|
|
};
|
|
|
|
VkPipelineInputAssemblyStateCreateInfo input_assembly_info = {
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
|
|
.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
|
|
.primitiveRestartEnable = VK_FALSE,
|
|
};
|
|
|
|
VkResult result = create_ui_pipeline(device, render_pass, shader_stages, sizeof(shader_stages)/sizeof(VkPipelineShaderStageCreateInfo), input_info, layout_info, input_assembly_info, pipeline);
|
|
if(result != VK_SUCCESS) {
|
|
return result;
|
|
}
|
|
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
VkResult create_text_descriptor_pool(VkDevice device, uint32_t max_sets, VkDescriptorPool* pool, VkDescriptorSetLayout* text_descriptor_layout) {
|
|
VkResult result;
|
|
VkDescriptorPoolSize pool_sizes[] = {
|
|
{
|
|
.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
|
.descriptorCount = 1,
|
|
},
|
|
{
|
|
.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
|
.descriptorCount = 1,
|
|
}
|
|
};
|
|
|
|
VkDescriptorPoolCreateInfo pool_info = {
|
|
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
|
|
.pPoolSizes = pool_sizes,
|
|
.poolSizeCount = sizeof(pool_sizes)/sizeof(VkDescriptorPoolSize),
|
|
.maxSets = max_sets,
|
|
};
|
|
|
|
result = vkCreateDescriptorPool(device, &pool_info, NULL, pool);
|
|
if(result != VK_SUCCESS) {
|
|
return result;
|
|
}
|
|
|
|
VkDescriptorSetLayoutBinding text_descriptor_bindings[] = {
|
|
{
|
|
.binding = 0,
|
|
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
|
.descriptorCount = 1,
|
|
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
|
|
},
|
|
{
|
|
.binding = 1,
|
|
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
|
.descriptorCount = 1,
|
|
.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
|
|
}
|
|
};
|
|
|
|
VkDescriptorSetLayoutCreateInfo text_descriptor_info = {
|
|
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
|
|
.pBindings = text_descriptor_bindings,
|
|
.bindingCount = sizeof(text_descriptor_bindings)/sizeof(VkDescriptorSetLayoutBinding),
|
|
};
|
|
|
|
result = vkCreateDescriptorSetLayout(device, &text_descriptor_info, NULL, text_descriptor_layout);
|
|
if(result != VK_SUCCESS) {
|
|
return result;
|
|
}
|
|
|
|
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
VkResult create_text_descriptor(VkDevice device, VmaAllocator allocator, VkDescriptorSetLayout layout, VkDescriptorPool pool, FontData* font, SymbolInfo* symbols, uint32_t* atlas, VkCommandPool transfer_pool, Queue transfer_queue, FontDescriptor* descriptor) {
|
|
VkResult result;
|
|
VkDescriptorSetAllocateInfo set_allocate_info = {
|
|
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
|
|
.pSetLayouts = &layout,
|
|
.descriptorSetCount = 1,
|
|
.descriptorPool = pool,
|
|
};
|
|
|
|
result = vkAllocateDescriptorSets(device, &set_allocate_info, &descriptor->set);
|
|
if(result != VK_SUCCESS) {
|
|
return result;
|
|
}
|
|
|
|
VkBufferCreateInfo symbol_buffer_info = {
|
|
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
|
|
.usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
|
|
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
|
.size = sizeof(SymbolInfo)*font->info.num_symbols,
|
|
};
|
|
VmaAllocationCreateInfo symbol_memory_info = {
|
|
.usage = VMA_MEMORY_USAGE_GPU_ONLY,
|
|
};
|
|
result = vmaCreateBuffer(allocator, &symbol_buffer_info, &symbol_memory_info, &descriptor->symbols, &descriptor->symbol_memory, NULL);
|
|
if(result != VK_SUCCESS) {
|
|
return result;
|
|
}
|
|
|
|
VkBufferCreateInfo uniform_buffer_info = {
|
|
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
|
|
.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
|
|
.size = sizeof(FontUniform),
|
|
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
|
};
|
|
|
|
VmaAllocationCreateInfo uniform_memory_info = {
|
|
.usage = VMA_MEMORY_USAGE_GPU_ONLY,
|
|
};
|
|
|
|
result = vmaCreateBuffer(allocator, &uniform_buffer_info, &uniform_memory_info, &descriptor->uniform, &descriptor->uniform_memory, NULL);
|
|
VkImageCreateInfo image_info = {
|
|
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
|
|
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
|
.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
|
|
.extent.depth = 1,
|
|
.extent.width = font->info.width,
|
|
.extent.height = font->info.height,
|
|
.mipLevels = 1,
|
|
.arrayLayers = 1,
|
|
.format = VK_FORMAT_R8G8B8A8_SRGB,
|
|
.tiling = VK_IMAGE_TILING_OPTIMAL,
|
|
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
|
|
.samples = VK_SAMPLE_COUNT_1_BIT,
|
|
};
|
|
|
|
VmaAllocationCreateInfo image_memory_info = {
|
|
.usage = VMA_MEMORY_USAGE_GPU_ONLY,
|
|
};
|
|
|
|
result = vmaCreateImage(allocator, &image_info, &image_memory_info, &descriptor->image, &descriptor->image_memory, NULL);
|
|
if(result != VK_SUCCESS) {
|
|
return result;
|
|
}
|
|
|
|
uint32_t image_size = sizeof(uint32_t)*font->info.width*font->info.height;
|
|
VkBufferCreateInfo staging_info = {
|
|
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
|
|
.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
|
|
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
|
.size = sizeof(FontUniform) + image_size + sizeof(SymbolInfo)*font->info.num_symbols,
|
|
};
|
|
|
|
VmaAllocationCreateInfo staging_memory_info = {
|
|
.usage = VMA_MEMORY_USAGE_CPU_TO_GPU,
|
|
};
|
|
|
|
VkBuffer staging_buffer;
|
|
VmaAllocation staging_memory;
|
|
result = vmaCreateBuffer(allocator, &staging_info, &staging_memory_info, &staging_buffer, &staging_memory, NULL);
|
|
if(result != VK_SUCCESS) {
|
|
return result;
|
|
}
|
|
|
|
void* mapped_staging;
|
|
result = vmaMapMemory(allocator, staging_memory, &mapped_staging);
|
|
if(result != VK_SUCCESS) {
|
|
return result;
|
|
}
|
|
memcpy(mapped_staging + image_size + sizeof(FontUniform), symbols, sizeof(SymbolInfo)*font->info.num_symbols);
|
|
VkBufferDeviceAddressInfo address_info = {
|
|
.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO,
|
|
.buffer = descriptor->symbols,
|
|
};
|
|
font->info.symbol_list = vkGetBufferDeviceAddress(device, &address_info);
|
|
memcpy(mapped_staging + image_size, &font->info, sizeof(FontUniform));
|
|
memcpy(mapped_staging, atlas, image_size);
|
|
vmaUnmapMemory(allocator, staging_memory);
|
|
|
|
VkCommandBuffer command_buffer = command_begin_single(device, transfer_pool);
|
|
|
|
VkBufferCopy uniform_copy_info = {
|
|
.size = sizeof(FontUniform),
|
|
.srcOffset = image_size,
|
|
.dstOffset = 0,
|
|
};
|
|
vkCmdCopyBuffer(command_buffer, staging_buffer, descriptor->uniform, 1, &uniform_copy_info);
|
|
|
|
VkBufferCopy symbol_copy_info = {
|
|
.size = sizeof(SymbolInfo)*font->info.num_symbols,
|
|
.srcOffset = image_size + sizeof(FontUniform),
|
|
.dstOffset = 0,
|
|
};
|
|
vkCmdCopyBuffer(command_buffer, staging_buffer, descriptor->symbols, 1, &symbol_copy_info);
|
|
|
|
VkImageMemoryBarrier first_barrier = {
|
|
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
|
.image = descriptor->image,
|
|
.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
|
|
.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
|
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
|
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
|
.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
|
.subresourceRange.levelCount = 1,
|
|
.subresourceRange.layerCount = 1,
|
|
.srcAccessMask = 0,
|
|
.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
|
};
|
|
vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 1, &first_barrier);
|
|
|
|
VkBufferImageCopy image_copy = {
|
|
.imageSubresource.layerCount = 1,
|
|
.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
|
.imageExtent = image_info.extent,
|
|
};
|
|
vkCmdCopyBufferToImage(command_buffer, staging_buffer, descriptor->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &image_copy);
|
|
|
|
VkImageMemoryBarrier second_barrier = {
|
|
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
|
.image = descriptor->image,
|
|
.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
|
.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
|
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
|
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
|
.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
|
.subresourceRange.levelCount = 1,
|
|
.subresourceRange.layerCount = 1,
|
|
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
|
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT,
|
|
};
|
|
vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &second_barrier);
|
|
|
|
result = command_end_single(device, command_buffer, transfer_pool, transfer_queue);
|
|
if(result != VK_SUCCESS) {
|
|
return result;
|
|
}
|
|
vmaDestroyBuffer(allocator, staging_buffer, staging_memory);
|
|
|
|
VkImageViewCreateInfo view_info = {
|
|
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
|
|
.image = descriptor->image,
|
|
.viewType = VK_IMAGE_VIEW_TYPE_2D,
|
|
.format = VK_FORMAT_R8G8B8A8_SRGB,
|
|
.subresourceRange = {
|
|
.layerCount = 1,
|
|
.baseMipLevel = 0,
|
|
.levelCount = 1,
|
|
.baseArrayLayer = 0,
|
|
},
|
|
};
|
|
result = vkCreateImageView(device, &view_info, NULL, &descriptor->view);
|
|
if(result != VK_SUCCESS) {
|
|
return result;
|
|
}
|
|
|
|
VkSamplerCreateInfo sampler_info = {
|
|
.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
|
|
.magFilter = VK_FILTER_NEAREST,
|
|
.minFilter = VK_FILTER_LINEAR,
|
|
.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT,
|
|
.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT,
|
|
.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT,
|
|
};
|
|
result = vkCreateSampler(device, &sampler_info, NULL, &descriptor->sampler);
|
|
if(result != VK_SUCCESS) {
|
|
return result;
|
|
}
|
|
|
|
VkDescriptorBufferInfo desc_uniform_info = {
|
|
.offset = 0,
|
|
.range = sizeof(FontUniform),
|
|
.buffer = descriptor->uniform,
|
|
};
|
|
|
|
VkDescriptorImageInfo desc_image_info = {
|
|
.sampler = descriptor->sampler,
|
|
.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
|
.imageView = descriptor->view,
|
|
};
|
|
|
|
VkWriteDescriptorSet descriptor_writes[] = {
|
|
{
|
|
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
|
.dstSet = descriptor->set,
|
|
.dstBinding = 0,
|
|
.dstArrayElement = 0,
|
|
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
|
.descriptorCount = 1,
|
|
.pBufferInfo = &desc_uniform_info,
|
|
},
|
|
{
|
|
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
|
.dstSet = descriptor->set,
|
|
.dstBinding = 1,
|
|
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
|
.descriptorCount = 1,
|
|
.pImageInfo = &desc_image_info,
|
|
}
|
|
};
|
|
|
|
vkUpdateDescriptorSets(device, 2, descriptor_writes, 0, NULL);
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
VkResult create_ui_descriptor_set(VkDevice device, VmaAllocator allocator, VkExtent2D swapchain_extent, VkDescriptorSetLayout* ui_descriptor_layout, VkDescriptorPool* ui_descriptor_pool, VkDescriptorSet* ui_descriptor_set, VmaAllocation* ui_descriptor_memory, VkBuffer* ui_descriptor_buffer) {
|
|
VkDescriptorSetLayoutBinding ui_descriptor_bindings[] = {
|
|
{
|
|
.binding = 0,
|
|
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
|
.descriptorCount = 1,
|
|
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
|
|
}
|
|
};
|
|
|
|
VkDescriptorSetLayoutCreateInfo ui_descriptor_info = {
|
|
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
|
|
.pBindings = ui_descriptor_bindings,
|
|
.bindingCount = sizeof(ui_descriptor_bindings)/sizeof(VkDescriptorSetLayoutBinding),
|
|
};
|
|
|
|
VkResult result;
|
|
result = vkCreateDescriptorSetLayout(device, &ui_descriptor_info, NULL, ui_descriptor_layout);
|
|
if(result != VK_SUCCESS) {
|
|
return result;
|
|
}
|
|
|
|
VkDescriptorPoolSize pool_size = {
|
|
.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
|
.descriptorCount = 1,
|
|
};
|
|
|
|
VkDescriptorPoolCreateInfo ui_pool_info = {
|
|
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
|
|
.pPoolSizes = &pool_size,
|
|
.poolSizeCount = 1,
|
|
.maxSets = 1,
|
|
};
|
|
|
|
result = vkCreateDescriptorPool(device, &ui_pool_info, NULL, ui_descriptor_pool);
|
|
if(result != VK_SUCCESS) {
|
|
return result;
|
|
}
|
|
|
|
VkDescriptorSetAllocateInfo ui_descriptor_allocate_info = {
|
|
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
|
|
.pSetLayouts = ui_descriptor_layout,
|
|
.descriptorSetCount = 1,
|
|
.descriptorPool = *ui_descriptor_pool,
|
|
};
|
|
|
|
result = vkAllocateDescriptorSets(device, &ui_descriptor_allocate_info, ui_descriptor_set);
|
|
if(result != VK_SUCCESS) {
|
|
return result;
|
|
}
|
|
|
|
VkBufferCreateInfo ui_uniform_buffer_info = {
|
|
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
|
|
.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
|
|
.size = sizeof(UIUniform),
|
|
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
|
};
|
|
|
|
VmaAllocationCreateInfo ui_uniform_memory_info = {
|
|
.usage = VMA_MEMORY_USAGE_CPU_TO_GPU,
|
|
};
|
|
|
|
result = vmaCreateBuffer(allocator, &ui_uniform_buffer_info, &ui_uniform_memory_info, ui_descriptor_buffer, ui_descriptor_memory, NULL);
|
|
if(result != VK_SUCCESS) {
|
|
return result;
|
|
}
|
|
|
|
void* mapped;
|
|
result = vmaMapMemory(allocator, *ui_descriptor_memory, &mapped);
|
|
if(result != VK_SUCCESS) {
|
|
return result;
|
|
}
|
|
UIUniform ui_uniform;
|
|
vec3 screen_offset = {-1.0, -1.0, 0.0};
|
|
vec3 screen_scale = {1.0/(float)swapchain_extent.width, 1.0/(float)swapchain_extent.height, 1.0};
|
|
glm_mat4_identity(ui_uniform.screen);
|
|
glm_translate(ui_uniform.screen, screen_offset);
|
|
glm_scale(ui_uniform.screen, screen_scale);
|
|
memcpy(mapped, &ui_uniform, sizeof(ui_uniform));
|
|
vmaUnmapMemory(allocator, *ui_descriptor_memory);
|
|
|
|
VkDescriptorBufferInfo ui_uniform_info = {
|
|
.offset = 0,
|
|
.range = sizeof(ui_uniform),
|
|
.buffer = *ui_descriptor_buffer,
|
|
};
|
|
|
|
VkWriteDescriptorSet ui_uniform_write = {
|
|
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
|
.dstSet = *ui_descriptor_set,
|
|
.dstBinding = 0,
|
|
.dstArrayElement = 0,
|
|
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
|
.descriptorCount = 1,
|
|
.pBufferInfo = &ui_uniform_info,
|
|
};
|
|
|
|
vkUpdateDescriptorSets(device, 1, &ui_uniform_write, 0, NULL);
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
VkResult create_ui_rect_buffer(VkDevice device, Queue transfer_queue, VkCommandPool transfer_pool, VmaAllocator allocator, struct RectBuffer* rect) {
|
|
|
|
uint32_t vertex_buffer_size = 4 * sizeof(vec2);
|
|
uint32_t index_buffer_size = 6 * sizeof(uint32_t);
|
|
|
|
// Create temp buffer
|
|
VkBufferCreateInfo temp_buffer_info = {
|
|
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
|
|
.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
|
|
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
|
.size = vertex_buffer_size + index_buffer_size,
|
|
};
|
|
|
|
VmaAllocationCreateInfo temp_allocation_info = {
|
|
.usage = VMA_MEMORY_USAGE_CPU_TO_GPU,
|
|
};
|
|
|
|
VkBuffer temp_buffer;
|
|
VmaAllocation temp_buffer_memory;
|
|
VkResult result;
|
|
|
|
result = vmaCreateBuffer(allocator, &temp_buffer_info, &temp_allocation_info, &temp_buffer, &temp_buffer_memory, NULL);
|
|
if(result != VK_SUCCESS) {
|
|
return result;
|
|
}
|
|
|
|
// Create buffers
|
|
VmaAllocationCreateInfo allocation_info = {
|
|
.usage = VMA_MEMORY_USAGE_GPU_ONLY,
|
|
};
|
|
|
|
VkBufferCreateInfo vertex_buffer_info = {
|
|
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
|
|
.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
|
|
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
|
.size = vertex_buffer_size,
|
|
};
|
|
|
|
result = vmaCreateBuffer(allocator, &vertex_buffer_info, &allocation_info, &rect->vertex, &rect->vertex_memory, NULL);
|
|
if(result != VK_SUCCESS) {
|
|
return result;
|
|
}
|
|
|
|
VkBufferCreateInfo index_buffer_info = {
|
|
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
|
|
.usage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
|
|
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
|
.size = index_buffer_size,
|
|
};
|
|
|
|
result = vmaCreateBuffer(allocator, &index_buffer_info, &allocation_info, &rect->index, &rect->index_memory, NULL);
|
|
if(result != VK_SUCCESS) {
|
|
return result;
|
|
}
|
|
|
|
void* mapped;
|
|
result = vmaMapMemory(allocator, temp_buffer_memory, &mapped);
|
|
if(result != VK_SUCCESS) {
|
|
return result;
|
|
}
|
|
|
|
vec2* mapped_vertex = (vec2*)mapped;
|
|
mapped_vertex[0][0] = 0.0f;
|
|
mapped_vertex[0][1] = 0.0f;
|
|
mapped_vertex[1][0] = 1.0f;
|
|
mapped_vertex[1][1] = 0.0f;
|
|
mapped_vertex[2][0] = 0.0f;
|
|
mapped_vertex[2][1] = 1.0f;
|
|
mapped_vertex[3][0] = 1.0f;
|
|
mapped_vertex[3][1] = 1.0f;
|
|
|
|
uint32_t* mapped_index = (uint32_t*)(mapped + vertex_buffer_size);
|
|
mapped_index[0] = 0;
|
|
mapped_index[1] = 1;
|
|
mapped_index[2] = 2;
|
|
mapped_index[3] = 1;
|
|
mapped_index[4] = 3;
|
|
mapped_index[5] = 2;
|
|
|
|
vmaUnmapMemory(allocator, temp_buffer_memory);
|
|
|
|
VkCommandBuffer copy_buffer = command_begin_single(device, transfer_pool);
|
|
VkBufferCopy vertex_copy_region = {
|
|
.size = vertex_buffer_size,
|
|
.dstOffset = 0,
|
|
.srcOffset = 0,
|
|
};
|
|
vkCmdCopyBuffer(copy_buffer, temp_buffer, rect->vertex, 1, &vertex_copy_region);
|
|
|
|
VkBufferCopy index_copy_region = {
|
|
.size = index_buffer_size,
|
|
.dstOffset = 0,
|
|
.srcOffset = vertex_buffer_size,
|
|
};
|
|
vkCmdCopyBuffer(copy_buffer, temp_buffer, rect->index, 1, &index_copy_region);
|
|
|
|
result = command_end_single(device, copy_buffer, transfer_pool, transfer_queue);
|
|
if(result != VK_SUCCESS) {
|
|
return result;
|
|
}
|
|
|
|
vmaDestroyBuffer(allocator, temp_buffer, temp_buffer_memory);
|
|
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
VkResult init_pipelines(VkDevice device, VmaAllocator allocator, VkExtent2D swapchain_extent, VkRenderPass render_pass, Queue transfer_queue, VkCommandPool transfer_pool, UIContext* context) {
|
|
|
|
VkResult result;
|
|
result = create_ui_descriptor_set(device, allocator, swapchain_extent, &context->ui_descriptor_layout, &context->ui_descriptor_pool, &context->ui_descriptor_set, &context->ui_descriptor_memory, &context->ui_descriptor_buffer);
|
|
if(result != VK_SUCCESS) {
|
|
return result;
|
|
}
|
|
|
|
result = create_ui_rect_buffer(device, transfer_queue, transfer_pool, allocator, &context->ui_rect);
|
|
if(result != VK_SUCCESS) {
|
|
return result;
|
|
}
|
|
|
|
result = create_ui_colored_rect_pipeline(device, render_pass, context->ui_descriptor_layout, &context->ui_pipeline_rect);
|
|
if(result != VK_SUCCESS) {
|
|
return result;
|
|
}
|
|
|
|
result = create_text_descriptor_pool(device, 10, &context->font_pool, &context->font_layout);
|
|
if(result != VK_SUCCESS) {
|
|
return result;
|
|
}
|
|
|
|
result = create_ui_text_pipeline(device, render_pass, context->ui_descriptor_layout, context->font_layout, &context->ui_pipeline_text);
|
|
if(result != VK_SUCCESS) {
|
|
return result;
|
|
}
|
|
|
|
return VK_SUCCESS;
|
|
}
|