Got basic text pipeline working, want to minimize the amount of data transfered to GPU so that strings don't repeat so much data

main
noah metz 2024-10-14 01:00:10 -06:00
parent ea72e53c93
commit 74e1a05790
6 changed files with 140 additions and 69 deletions

@ -30,10 +30,26 @@ typedef struct TextStruct {
typedef struct FontUniformStruct {
vec2 size;
uint32_t columns;
uint32_t cols;
uint32_t rows;
uint32_t start;
} FontUniform;
typedef struct FontDataStruct {
FontUniform info;
uint32_t* data;
} FontData;
typedef struct FontDescriptorStruct {
VmaAllocation uniform_memory;
VmaAllocation image_memory;
VkBuffer uniform;
VkImage image;
VkImageView view;
VkSampler sampler;
VkDescriptorSet set;
} FontDescriptor;
typedef struct UILayerStruct {
VkBuffer colored_rects;
uint32_t colored_rect_count;
@ -44,15 +60,9 @@ typedef struct UILayerStruct {
VkBuffer texts;
uint32_t text_count;
VkDescriptorSet text_descriptor;
FontDescriptor font;
} UILayer;
typedef struct FontDataStruct {
FontUniform info;
uint32_t rows;
vec4* data;
} FontData;
struct RectBuffer {
VkBuffer vertex;
VkBuffer index;
@ -71,14 +81,6 @@ typedef struct UIContextStruct {
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;
@ -86,4 +88,6 @@ typedef struct UIContextStruct {
VkResult init_pipelines(VkDevice device, VmaAllocator allocator, VkExtent2D swapchain_extent, VkRenderPass render_pass, Queue transfer_queue, VkCommandPool transfer_pool, UIContext* context);
VkResult create_text_descriptor(VkDevice device, VmaAllocator allocator, VkDescriptorSetLayout layout, VkDescriptorPool pool, FontData* font, VkCommandPool transfer_pool, Queue transfer_queue, FontDescriptor* descriptor);
#endif

@ -8,7 +8,6 @@ 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);
outColor = fragColor * texture(font, fragUV);
}

@ -5,8 +5,9 @@ layout(set = 0, binding = 0) uniform UIUniform {
} ubo;
layout(set = 1, binding = 0) uniform FontUniform {
vec2 font_size;
uint columns;
vec2 size;
uint cols;
uint rows;
uint start;
} font;
@ -20,8 +21,10 @@ 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;
float row = floor(code/font.cols);
float col = code - row*font.cols;
fragUV = (vec2(col, row) + inVertexPosition) / vec2(font.cols, font.rows);
fragColor = inColor;
gl_Position = ubo.screen * vec4(vec3(inVertexPosition * inSize, 0.0) + inPosition, 1.0);
}

@ -12,17 +12,42 @@ ColoredRect colored_rect(float width, float height, float r, float g, float b, f
return rect;
}
const uint32_t WHITE = 0xFFFFFFFF;
const uint32_t CLEAR = 0x00000000;
uint32_t test_font_data[] = {
WHITE, WHITE, CLEAR, WHITE,
CLEAR, CLEAR, WHITE, CLEAR,
};
VkResult render_thread(GLFWwindow* window, RenderContext* render_context) {
VkResult result;
UIContext ui_context;
VkBuffer colored_rect_buffer;
VkBuffer text_buffer;
VmaAllocation colored_rect_memory;
VmaAllocation text_memory;
result = init_pipelines(render_context->device, render_context->allocator, render_context->swapchain_extent, render_context->world_render_pass, render_context->transfer_queue, render_context->transfer_pool, &ui_context);
if(result != VK_SUCCESS) {
return result;
}
FontData test_font = {
.info = {
.size = {2, 2},
.start = 0,
.cols = 2,
.rows = 1,
},
.data = test_font_data,
};
FontDescriptor test_font_descriptor;
result = create_text_descriptor(render_context->device, render_context->allocator, ui_context.font_layout, ui_context.font_pool, &test_font, render_context->transfer_pool, render_context->transfer_queue, &test_font_descriptor);
if(result != VK_SUCCESS) {
return result;
}
VkBufferCreateInfo colored_rect_buffer_info = {
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
@ -52,9 +77,58 @@ VkResult render_thread(GLFWwindow* window, RenderContext* render_context) {
vmaUnmapMemory(render_context->allocator, colored_rect_memory);
VkBufferCreateInfo text_buffer_info = {
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
.size = 2*sizeof(Text),
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
};
VmaAllocationCreateInfo text_memory_info = {
.usage = VMA_MEMORY_USAGE_CPU_TO_GPU,
};
result = vmaCreateBuffer(render_context->allocator, &text_buffer_info, &text_memory_info, &text_buffer, &text_memory, NULL);
if(result != VK_SUCCESS) {
return result;
}
Text* text;
result = vmaMapMemory(render_context->allocator, text_memory, (void**)&text);
if(result != VK_SUCCESS) {
return result;
}
text[0].size[0] = 200.0f;
text[0].size[1] = 200.0f;
text[0].color[0] = 1.0f;
text[0].color[1] = 1.0f;
text[0].color[2] = 1.0f;
text[0].color[3] = 1.0f;
text[0].pos[0] = 200.0f;
text[0].pos[1] = 200.0f;
text[0].code = 0;
text[1].size[0] = 200.0f;
text[1].size[1] = 200.0f;
text[1].color[0] = 1.0f;
text[1].color[1] = 1.0f;
text[1].color[2] = 1.0f;
text[1].color[3] = 1.0f;
text[1].pos[0] = 400.0f;
text[1].pos[1] = 200.0f;
text[1].code = 1;
vmaUnmapMemory(render_context->allocator, text_memory);
UILayer test_layer = {
.colored_rects = colored_rect_buffer,
.colored_rect_count = 3,
.font = test_font_descriptor,
.text_count = 2,
.texts = text_buffer,
};
while(glfwWindowShouldClose(window) == 0) {

@ -438,7 +438,7 @@ VkResult create_text_descriptor_pool(VkDevice device, uint32_t max_sets, VkDescr
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 create_text_descriptor(VkDevice device, VmaAllocator allocator, VkDescriptorSetLayout layout, VkDescriptorPool pool, FontData* font, VkCommandPool transfer_pool, Queue transfer_queue, FontDescriptor* descriptor) {
VkResult result;
VkDescriptorSetAllocateInfo set_allocate_info = {
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
@ -447,7 +447,7 @@ VkResult create_text_descriptor(VkDevice device, VmaAllocator allocator, VkDescr
.descriptorPool = pool,
};
result = vkAllocateDescriptorSets(device, &set_allocate_info, set);
result = vkAllocateDescriptorSets(device, &set_allocate_info, &descriptor->set);
if(result != VK_SUCCESS) {
return result;
}
@ -463,14 +463,14 @@ VkResult create_text_descriptor(VkDevice device, VmaAllocator allocator, VkDescr
.usage = VMA_MEMORY_USAGE_GPU_ONLY,
};
result = vmaCreateBuffer(allocator, &uniform_buffer_info, &uniform_memory_info, uniform, uniform_memory, NULL);
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.size[0]*font->info.columns,
.extent.height = font->info.size[1]*font->rows,
.extent.width = font->info.size[0]*font->info.cols,
.extent.height = font->info.size[1]*font->info.rows,
.mipLevels = 1,
.arrayLayers = 1,
.format = VK_FORMAT_R8G8B8A8_SRGB,
@ -483,16 +483,17 @@ VkResult create_text_descriptor(VkDevice device, VmaAllocator allocator, VkDescr
.usage = VMA_MEMORY_USAGE_GPU_ONLY,
};
result = vmaCreateImage(allocator, &image_info, &image_memory_info, image, image_memory, NULL);
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.rows*font->info.size[0]*font->info.cols*font->info.size[1];
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,
.size = sizeof(FontUniform) + image_size,
};
VmaAllocationCreateInfo staging_memory_info = {
@ -511,22 +512,22 @@ VkResult create_text_descriptor(VkDevice device, VmaAllocator allocator, VkDescr
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);
memcpy(mapped_staging + image_size, &font->info, sizeof(FontUniform));
memcpy(mapped_staging, font->data, image_size);
vmaUnmapMemory(allocator, staging_memory);
VkCommandBuffer command_buffer = command_begin_single(device, transfer_pool);
VkBufferCopy copy_info = {
.size = sizeof(FontUniform),
.srcOffset = 0,
.srcOffset = image_size,
.dstOffset = 0,
};
vkCmdCopyBuffer(command_buffer, staging_buffer, *uniform, 1, &copy_info);
vkCmdCopyBuffer(command_buffer, staging_buffer, descriptor->uniform, 1, &copy_info);
VkImageMemoryBarrier first_barrier = {
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.image = *image,
.image = descriptor->image,
.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
@ -543,13 +544,12 @@ VkResult create_text_descriptor(VkDevice device, VmaAllocator allocator, VkDescr
.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);
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 = *image,
.image = descriptor->image,
.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
@ -570,7 +570,7 @@ VkResult create_text_descriptor(VkDevice device, VmaAllocator allocator, VkDescr
VkImageViewCreateInfo view_info = {
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
.image = *image,
.image = descriptor->image,
.viewType = VK_IMAGE_VIEW_TYPE_2D,
.format = VK_FORMAT_R8G8B8A8_SRGB,
.subresourceRange = {
@ -580,7 +580,7 @@ VkResult create_text_descriptor(VkDevice device, VmaAllocator allocator, VkDescr
.baseArrayLayer = 0,
},
};
result = vkCreateImageView(device, &view_info, NULL, view);
result = vkCreateImageView(device, &view_info, NULL, &descriptor->view);
if(result != VK_SUCCESS) {
return result;
}
@ -593,7 +593,7 @@ VkResult create_text_descriptor(VkDevice device, VmaAllocator allocator, VkDescr
.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT,
.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT,
};
result = vkCreateSampler(device, &sampler_info, NULL, sampler);
result = vkCreateSampler(device, &sampler_info, NULL, &descriptor->sampler);
if(result != VK_SUCCESS) {
return result;
}
@ -601,19 +601,19 @@ VkResult create_text_descriptor(VkDevice device, VmaAllocator allocator, VkDescr
VkDescriptorBufferInfo desc_uniform_info = {
.offset = 0,
.range = sizeof(FontUniform),
.buffer = *uniform,
.buffer = descriptor->uniform,
};
VkDescriptorImageInfo desc_image_info = {
.sampler = *sampler,
.sampler = descriptor->sampler,
.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
.imageView = *view,
.imageView = descriptor->view,
};
VkWriteDescriptorSet descriptor_writes[] = {
{
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.dstSet = *set,
.dstSet = descriptor->set,
.dstBinding = 0,
.dstArrayElement = 0,
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
@ -622,7 +622,7 @@ VkResult create_text_descriptor(VkDevice device, VmaAllocator allocator, VkDescr
},
{
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.dstSet = *set,
.dstSet = descriptor->set,
.dstBinding = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
.descriptorCount = 1,
@ -841,13 +841,6 @@ 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;
@ -876,20 +869,5 @@ VkResult init_pipelines(VkDevice device, VmaAllocator allocator, VkExtent2D swap
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;
}
return VK_SUCCESS;
}

@ -1016,8 +1016,21 @@ VkResult draw_frame(RenderContext* context, UIContext* ui_context, UILayer* ui_l
vkCmdBindIndexBuffer(context->swapchain_command_buffers[context->current_frame], ui_context->ui_rect.index, 0, VK_INDEX_TYPE_UINT32);
for(uint32_t i = 0; i < ui_layer_count; i++) {
vkCmdBindVertexBuffers(context->swapchain_command_buffers[context->current_frame], 1, 1, &ui_layers[i].colored_rects, &offset);
vkCmdDrawIndexed(context->swapchain_command_buffers[context->current_frame], 6, ui_layers[i].colored_rect_count, 0, 0, 0);
if(ui_layers[i].colored_rect_count > 0) {
vkCmdBindVertexBuffers(context->swapchain_command_buffers[context->current_frame], 1, 1, &ui_layers[i].colored_rects, &offset);
vkCmdDrawIndexed(context->swapchain_command_buffers[context->current_frame], 6, ui_layers[i].colored_rect_count, 0, 0, 0);
}
}
/////////////////////////////////////////////////////////
// Draw UI text /////////////////////////////////////////
vkCmdBindPipeline(context->swapchain_command_buffers[context->current_frame], VK_PIPELINE_BIND_POINT_GRAPHICS, ui_context->ui_pipeline_text.pipeline);
vkCmdBindDescriptorSets(context->swapchain_command_buffers[context->current_frame], VK_PIPELINE_BIND_POINT_GRAPHICS, ui_context->ui_pipeline_text.layout, 0, 1, &ui_context->ui_descriptor_set, 0, NULL);
for(uint32_t i = 0; i < ui_layer_count; i++) {
if(ui_layers[i].text_count > 0) {
vkCmdBindDescriptorSets(context->swapchain_command_buffers[context->current_frame], VK_PIPELINE_BIND_POINT_GRAPHICS, ui_context->ui_pipeline_text.layout, 1, 1, &ui_layers[i].font.set, 0, NULL);
vkCmdBindVertexBuffers(context->swapchain_command_buffers[context->current_frame], 1, 1, &ui_layers[i].texts, &offset);
vkCmdDrawIndexed(context->swapchain_command_buffers[context->current_frame], 6, ui_layers[i].text_count, 0, 0, 0);
}
}
/////////////////////////////////////////////////////////