Started UI text pipeline with 4x4 test font

main
noah metz 2024-10-13 22:18:37 -06:00
parent dc6e44ef99
commit ea72e53c93
6 changed files with 415 additions and 33 deletions

@ -16,6 +16,4 @@ VkResult command_end_single(VkDevice device, VkCommandBuffer command_buffer, VkC
VkResult command_transition_image_layout(VkDevice device, VkCommandPool transfer_pool, Queue transfer_queue, VkImageLayout old_layout, VkImageLayout new_layout, VkImage image, VkAccessFlags src_mask, VkAccessFlags dst_mask, VkPipelineStageFlags source, VkPipelineStageFlags dest, uint32_t source_family, uint32_t dest_family, VkImageAspectFlags aspect_flags);
VkResult command_transition_image_layout(VkDevice device, VkCommandPool transfer_pool, Queue transfer_queue, VkImageLayout old_layout, VkImageLayout new_layout, VkImage image, VkAccessFlags src_mask, VkAccessFlags dst_mask, VkPipelineStageFlags source, VkPipelineStageFlags dest, uint32_t source_family, uint32_t dest_family, VkImageAspectFlags aspect_flags);
#endif

@ -21,6 +21,19 @@ typedef struct UIUniformStruct {
mat4 screen;
} UIUniform;
typedef struct TextStruct {
vec3 pos;
vec2 size;
vec4 color;
uint32_t code;
} Text;
typedef struct FontUniformStruct {
vec2 size;
uint32_t columns;
uint32_t start;
} FontUniform;
typedef struct UILayerStruct {
VkBuffer colored_rects;
uint32_t colored_rect_count;
@ -34,6 +47,12 @@ typedef struct UILayerStruct {
VkDescriptorSet text_descriptor;
} UILayer;
typedef struct FontDataStruct {
FontUniform info;
uint32_t rows;
vec4* data;
} FontData;
struct RectBuffer {
VkBuffer vertex;
VkBuffer index;
@ -49,6 +68,17 @@ typedef struct UIContextStruct {
VkDescriptorPool ui_descriptor_pool;
VkDescriptorSet ui_descriptor_set;
VkDescriptorPool font_pool;
VkDescriptorSetLayout font_layout;
VmaAllocation test_font_uniform_memory;
VmaAllocation test_font_image_memory;
VkBuffer test_font_uniform;
VkImage test_font_image;
VkImageView test_font_view;
VkSampler test_font_sampler;
VkDescriptorSet test_font_set;
struct RectBuffer ui_rect;
GraphicsPipeline ui_pipeline_rect;
GraphicsPipeline ui_pipeline_text;

@ -0,0 +1,14 @@
#version 450
layout(set = 1, binding = 1) uniform sampler2D font;
layout(location = 0) in vec4 fragColor;
layout(location = 1) in vec2 fragUV;
layout(location = 0) out vec4 outColor;
void main() {
outColor = vec4(fragUV, 0.0, 1.0);
//;fragColor * texture(font, fragUV);
}

@ -0,0 +1,27 @@
#version 450
layout(set = 0, binding = 0) uniform UIUniform {
mat4 screen;
} ubo;
layout(set = 1, binding = 0) uniform FontUniform {
vec2 font_size;
uint columns;
uint start;
} font;
layout(location = 0) in vec2 inVertexPosition;
layout(location = 1) in vec3 inPosition;
layout(location = 2) in vec2 inSize;
layout(location = 3) in vec4 inColor;
layout(location = 4) in uint code;
layout(location = 0) out vec4 fragColor;
layout(location = 1) out vec2 fragUV;
void main() {
gl_Position = ubo.screen * vec4(vec3(inVertexPosition * inSize, 0.0) + inPosition, 1.0);
fragUV = inVertexPosition;
fragColor = inColor;
}

@ -77,28 +77,3 @@ VkResult command_transition_image_layout(VkDevice device, VkCommandPool transfer
return command_end_single(device, command_buffer, transfer_pool, transfer_queue);
}
VkResult command_copy_buffer_to_image(VkDevice device, VkCommandPool transfer_pool, Queue 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, &region);
return command_end_single(device, command_buffer, transfer_pool, transfer_queue);
}

@ -1,6 +1,7 @@
#include "pipeline.h"
#include "cglm/affine.h"
#include "cglm/mat4.h"
#include "command.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
@ -194,7 +195,13 @@ VkResult create_ui_pipeline(
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,
@ -278,9 +285,15 @@ VkPipelineVertexInputStateCreateInfo input_info = {
return VK_SUCCESS;
}
VkResult create_ui_text_pipeline(VkDevice device, VkRenderPass render_pass, VkDescriptorSetLayout ui_descriptor_layout, GraphicsPipeline* pipeline) {
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;
}
VkPipelineShaderStageCreateInfo shader_stages[] = {
{
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
@ -296,8 +309,50 @@ VkResult create_ui_text_pipeline(VkDevice device, VkRenderPass render_pass, VkDe
},
};
VkVertexInputBindingDescription bindings[] = {};
VkVertexInputAttributeDescription attributes[] = {};
VkVertexInputBindingDescription bindings[] = {
{
.binding = 0,
.stride = sizeof(vec2),
.inputRate = VK_VERTEX_INPUT_RATE_VERTEX,
},
{
.binding = 1,
.stride = sizeof(Text),
.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(Text, pos),
},
{
.binding = 1,
.location = 2,
.format = VK_FORMAT_R32G32_SFLOAT,
.offset = offsetof(Text, size),
},
{
.binding = 1,
.location = 3,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = offsetof(Text, color),
},
{
.binding = 1,
.location = 4,
.format = VK_FORMAT_R32_UINT,
.offset = offsetof(Text, code),
},
};
VkPipelineVertexInputStateCreateInfo input_info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
@ -307,7 +362,7 @@ VkResult create_ui_text_pipeline(VkDevice device, VkRenderPass render_pass, VkDe
.vertexAttributeDescriptionCount = sizeof(attributes)/sizeof(VkVertexInputAttributeDescription),
};
VkDescriptorSetLayout all_layouts[] = {ui_descriptor_layout};
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),
@ -328,6 +383,257 @@ VkResult create_ui_text_pipeline(VkDevice device, VkRenderPass render_pass, VkDe
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, VkCommandPool transfer_pool, Queue transfer_queue, VmaAllocation* uniform_memory, VkBuffer* uniform, VmaAllocation* image_memory, VkImage* image, VkImageView* view, VkSampler* sampler, VkDescriptorSet* set) {
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, set);
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, uniform, 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.size[0]*font->info.columns,
.extent.height = font->info.size[1]*font->rows,
.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, image, image_memory, NULL);
if(result != VK_SUCCESS) {
return result;
}
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) + 4*image_info.extent.width*image_info.extent.height,
};
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, &font->info, sizeof(FontUniform));
memcpy(mapped_staging + sizeof(FontUniform), font->data, 4*font->rows*font->info.columns);
vmaUnmapMemory(allocator, staging_memory);
VkCommandBuffer command_buffer = command_begin_single(device, transfer_pool);
VkBufferCopy copy_info = {
.size = sizeof(FontUniform),
.srcOffset = 0,
.dstOffset = 0,
};
vkCmdCopyBuffer(command_buffer, staging_buffer, *uniform, 1, &copy_info);
VkImageMemoryBarrier first_barrier = {
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.image = *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,
.bufferOffset = sizeof(FontUniform),
};
vkCmdCopyBufferToImage(command_buffer, staging_buffer, *image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &image_copy);
VkImageMemoryBarrier second_barrier = {
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.image = *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 = *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, 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, sampler);
if(result != VK_SUCCESS) {
return result;
}
VkDescriptorBufferInfo desc_uniform_info = {
.offset = 0,
.range = sizeof(FontUniform),
.buffer = *uniform,
};
VkDescriptorImageInfo desc_image_info = {
.sampler = *sampler,
.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
.imageView = *view,
};
VkWriteDescriptorSet descriptor_writes[] = {
{
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.dstSet = *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 = *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[] = {
{
@ -395,7 +701,7 @@ VkResult create_ui_descriptor_set(VkDevice device, VmaAllocator allocator, VkExt
return result;
}
void * mapped;
void* mapped;
result = vmaMapMemory(allocator, *ui_descriptor_memory, &mapped);
if(result != VK_SUCCESS) {
return result;
@ -535,6 +841,13 @@ VkResult create_ui_rect_buffer(VkDevice device, Queue transfer_queue, VkCommandP
return VK_SUCCESS;
}
#define WHITE {1.0f, 1.0f, 1.0f, 1.0f}
#define CLEAR {0.0f, 0.0f, 0.0f, 0.0f}
vec4 test_font_data[] = {
WHITE, WHITE, CLEAR, WHITE,
CLEAR, CLEAR, WHITE, CLEAR,
};
VkResult init_pipelines(VkDevice device, VmaAllocator allocator, VkExtent2D swapchain_extent, VkRenderPass render_pass, Queue transfer_queue, VkCommandPool transfer_pool, UIContext* context) {
VkResult result;
@ -543,12 +856,37 @@ VkResult init_pipelines(VkDevice device, VmaAllocator allocator, VkExtent2D swap
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_ui_rect_buffer(device, transfer_queue, transfer_pool, allocator, &context->ui_rect);
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;
}
FontData test_font = {
.info = {
.size = {4, 4},
.start = 0,
.columns = 2,
},
.rows = 1,
.data = test_font_data,
};
result = create_text_descriptor(device, allocator, context->font_layout, context->font_pool, &test_font, transfer_pool, transfer_queue, &context->test_font_uniform_memory, &context->test_font_uniform, &context->test_font_image_memory, &context->test_font_image, &context->test_font_view, &context->test_font_sampler, &context->test_font_set);
if(result != VK_SUCCESS) {
return result;
}