diff --git a/client/include/command.h b/client/include/command.h index 42ca07b..88a79e0 100644 --- a/client/include/command.h +++ b/client/include/command.h @@ -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 diff --git a/client/include/pipeline.h b/client/include/pipeline.h index f5743a8..237f4f0 100644 --- a/client/include/pipeline.h +++ b/client/include/pipeline.h @@ -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; diff --git a/client/shader_src/ui_text.frag b/client/shader_src/ui_text.frag new file mode 100644 index 0000000..9955e64 --- /dev/null +++ b/client/shader_src/ui_text.frag @@ -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); +} + diff --git a/client/shader_src/ui_text.vert b/client/shader_src/ui_text.vert new file mode 100644 index 0000000..1cabe9f --- /dev/null +++ b/client/shader_src/ui_text.vert @@ -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; +} + diff --git a/client/src/command.c b/client/src/command.c index 7332dfc..73f9986 100644 --- a/client/src/command.c +++ b/client/src/command.c @@ -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, ®ion); - - return command_end_single(device, command_buffer, transfer_pool, transfer_queue); -} diff --git a/client/src/pipeline.c b/client/src/pipeline.c index 2a651dd..d0b1650 100644 --- a/client/src/pipeline.c +++ b/client/src/pipeline.c @@ -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, ©_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; }