Starting rework for GPU driven UI rendering

main
noah metz 2024-10-18 14:26:41 -06:00
parent d04f7769ee
commit 6129e9c5b9
10 changed files with 347 additions and 669 deletions

@ -92,8 +92,8 @@ VkResult init_vulkan(
VkResult draw_frame( VkResult draw_frame(
RenderContext* context, RenderContext* context,
UIContext* ui_context, UIContextStorage* ui_context,
UILayer* ui_layers, UILayerStorage* ui_layers,
uint32_t ui_layer_count); uint32_t ui_layer_count);
VkResult create_transfer_buffer( VkResult create_transfer_buffer(

@ -19,20 +19,16 @@ typedef struct GraphicsPipelineStruct {
VkPipeline pipeline; VkPipeline pipeline;
} GraphicsPipeline; } GraphicsPipeline;
typedef struct ColoredRectStruct { typedef struct UIRectStruct {
vec3 pos; vec3 pos;
uint32_t padding0; float pad0;
vec2 size; vec2 size;
vec4 color; vec4 color;
} ColoredRect; } UIRect;
typedef struct UIUniformStruct {
mat4 screen;
} UIUniform;
typedef struct StringStruct { typedef struct StringStruct {
vec3 pos; vec3 pos;
uint32_t padding0; float pad0;
vec4 color; vec4 color;
float size; float size;
uint32_t offset; uint32_t offset;
@ -46,27 +42,26 @@ typedef struct DrawCommandStruct {
uint32_t first_instance; uint32_t first_instance;
} DrawCommand; } DrawCommand;
typedef struct StringPointersStruct { typedef struct DispatchCommandStruct {
VkDeviceAddress strings; uint32_t x;
VkDeviceAddress codes; uint32_t y;
VkDeviceAddress characters; uint32_t z;
VkDeviceAddress draw; } DispatchCommand;
} StringPointers;
typedef struct CharacterStruct { typedef struct CharacterStruct {
vec3 pos; vec3 pos;
uint32_t padding0; float pad0;
vec4 color; vec4 color;
float size; float size;
uint32_t code; uint32_t code;
} Character; } Character;
typedef struct FontUniformStruct { typedef struct FontStruct {
uint32_t num_symbols; uint32_t num_symbols;
uint32_t width; uint32_t width;
uint32_t height; uint32_t height;
VkDeviceAddress symbol_list; VkDeviceAddress symbol_list;
} FontUniform; } Font;
typedef struct SymbolInfoStruct { typedef struct SymbolInfoStruct {
int32_t top; int32_t top;
@ -76,17 +71,15 @@ typedef struct SymbolInfoStruct {
uint32_t advance; uint32_t advance;
} SymbolInfo; } SymbolInfo;
typedef struct FontStruct { typedef struct FontStorageStruct {
VmaAllocation symbol_memory; VmaAllocation symbol_memory;
VmaAllocation uniform_memory;
VmaAllocation image_memory; VmaAllocation image_memory;
VkBuffer symbols; VkBuffer symbols;
VkBuffer uniform; VkImage image;
VkImage image; VkImageView view;
VkImageView view; VkSampler sampler;
VkSampler sampler; uint32_t index;
VkDescriptorSet set; } FontStorage;
} Font;
typedef struct TextPointersMemoryStruct { typedef struct TextPointersMemoryStruct {
VmaAllocation pointers_memory; VmaAllocation pointers_memory;
@ -102,46 +95,72 @@ typedef struct TextPointersMemoryStruct {
VkBuffer characters_buffer; VkBuffer characters_buffer;
} TextPointersMemory; } TextPointersMemory;
typedef struct UIlayerStorageStruct {
VkBuffer strings;
VkBuffer chars;
VkBuffer codes;
VkBuffer rects;
VkBuffer layer;
VmaAllocation strings_memory;
VmaAllocation rects_memory;
VmaAllocation chars_memory;
VmaAllocation codes_memory;
VmaAllocation layer_memory;
VkDeviceAddress address;
} UILayerStorage;
typedef struct UILayerStruct { typedef struct UILayerStruct {
VkDeviceAddress colored_rects; VkDeviceAddress rects;
uint32_t colored_rect_count; uint32_t rect_count;
VkBuffer string_draw; VkDeviceAddress strings;
VkBuffer chars; uint32_t font_index;
VkDeviceAddress string_pointers;
uint32_t string_count; DrawCommand draw_chars;
uint32_t chars_count; DrawCommand draw_rects;
Font font; DispatchCommand dispatch_strings;
} UILayer; } UILayer;
typedef struct UIContextStruct { typedef struct UIContextStruct {
VkBuffer ui_descriptor_buffer; mat4 screen;
VmaAllocation ui_descriptor_memory; VkDeviceAddress font_infos;
VkDescriptorSetLayout ui_descriptor_layout;
VkDescriptorPool ui_descriptor_pool;
VkDescriptorSet ui_descriptor_set;
VkDescriptorPool font_pool;
VkDescriptorSetLayout font_layout;
GraphicsPipeline ui_pipeline_rect;
GraphicsPipeline ui_pipeline_text;
ComputePipeline ui_compute_text;
} UIContext; } UIContext;
VkResult init_pipelines( typedef struct UIContextStorageStruct {
VkDeviceAddress address;
VkBuffer context;
VmaAllocation context_memory;
VkBuffer font_infos;
VmaAllocation font_infos_memory;
VkDescriptorSet font_samplers;
VkDescriptorSet font_textures;
VkDescriptorSetLayout font_samplers_layout;
VkDescriptorSetLayout font_textures_layout;
VkDescriptorPool fonts_pool;
GraphicsPipeline rect_pipeline;
GraphicsPipeline char_pipeline;
ComputePipeline string_pipeline;
} UIContextStorage;
VkResult create_ui_context(
VkDevice device, VkDevice device,
VmaAllocator allocator, VmaAllocator allocator,
VkExtent2D swapchain_extent,
vec2 window_scale,
VkRenderPass render_pass, VkRenderPass render_pass,
UIContext* context); UIContextStorage* memory);
VkResult load_font( VkResult load_font(
VkDevice device, VkDevice device,
VmaAllocator allocator, VmaAllocator allocator,
VkDescriptorSetLayout layout, VkBuffer font_infos,
VkDescriptorPool pool, VkDescriptorSet font_samplers,
VkDescriptorSet font_textures,
uint32_t last_index,
VkCommandPool transfer_pool, VkCommandPool transfer_pool,
Queue transfer_queue, Queue transfer_queue,
FT_Library library, FT_Library library,
@ -149,16 +168,16 @@ VkResult load_font(
uint32_t size, uint32_t size,
VkBool32 antialias, VkBool32 antialias,
uint32_t** charmap, uint32_t** charmap,
Font* descriptor); FontStorage* memory);
VkResult create_text_pointers( VkResult create_layer(
uint32_t max_strings, uint32_t max_strings,
uint32_t max_characters, uint32_t max_characters,
uint32_t max_rects,
VkDevice device, VkDevice device,
VmaAllocator allocator, VmaAllocator allocator,
VkCommandPool transfer_pool, VkCommandPool transfer_pool,
Queue transfer_queue, Queue transfer_queue,
TextPointersMemory* memory, UILayerStorage* memory,
VkDeviceAddress* address); VkDeviceAddress* address);
#endif #endif

@ -1,10 +1,6 @@
#version 450 #version 450
#extension GL_EXT_buffer_reference : require #extension GL_EXT_buffer_reference : require
layout(set = 0, binding = 0) uniform UIUniform {
mat4 screen;
} ubo;
struct Rect { struct Rect {
vec3 pos; vec3 pos;
vec2 size; vec2 size;
@ -15,7 +11,12 @@ layout(std430, buffer_reference) readonly buffer RectList {
Rect r[]; Rect r[];
}; };
layout(std430, buffer_reference) readonly buffer ScreenInfo {
mat4 bounds;
};
layout(std430, push_constant) uniform PushConstant { layout(std430, push_constant) uniform PushConstant {
ScreenInfo screen;
RectList rects; RectList rects;
} pc; } pc;
@ -32,7 +33,7 @@ const vec2 square[6] = {
void main() { void main() {
Rect rect = pc.rects.r[gl_InstanceIndex]; Rect rect = pc.rects.r[gl_InstanceIndex];
gl_Position = ubo.screen * vec4(vec3(square[gl_VertexIndex] * rect.size, 0.0) + rect.pos.xyz, 1.0); gl_Position = pc.screen.bounds * vec4(vec3(square[gl_VertexIndex] * rect.size, 0.0) + rect.pos.xyz, 1.0);
fragColor = rect.color; fragColor = rect.color;
} }

@ -1,7 +1,7 @@
#version 450 #version 450
#extension GL_EXT_buffer_reference : require #extension GL_EXT_buffer_reference : require
struct Symbol { layout(buffer_reference, std430) buffer Symbol {
int top; int top;
uint left; uint left;
uint width; uint width;
@ -9,14 +9,14 @@ struct Symbol {
uint advance; uint advance;
}; };
struct Character { layout(buffer_reference, std430) buffer Character {
vec3 pos; vec3 pos;
vec4 color; vec4 color;
float size; float size;
uint code; uint code;
}; };
struct String { layout(buffer_reference, std430) buffer String {
vec3 pos; vec3 pos;
vec4 color; vec4 color;
float size; float size;
@ -40,12 +40,12 @@ layout(buffer_reference, std430) readonly buffer Strings{
String strings[]; String strings[];
}; };
layout(set = 0, binding = 0) uniform Font { layout(buffer_reference, std430) readonly buffer Font {
uint num_symbols; uint num_symbols;
uint width; uint width;
uint height; uint height;
SymbolList symbol_list; SymbolList symbol_list;
} font; };
layout(buffer_reference, std430) buffer DrawCommand { layout(buffer_reference, std430) buffer DrawCommand {
uint vertex_count; uint vertex_count;
@ -61,7 +61,17 @@ layout(buffer_reference, std430) readonly buffer Pointers {
DrawCommand draw; DrawCommand draw;
}; };
layout(buffer_reference, std430) readonly buffer FontList {
Font fonts[];
};
layout(buffer_reference, std430) readonly buffer UIContext {
mat4 screen;
FontList fonts;
};
layout(std430, push_constant) uniform Push { layout(std430, push_constant) uniform Push {
UIContext ui;
Pointers pointers; Pointers pointers;
} push; } push;
@ -70,6 +80,7 @@ layout(local_size_x = 1) in;
void main() { void main() {
uint gID = gl_GlobalInvocationID.x; uint gID = gl_GlobalInvocationID.x;
String string = push.pointers.strings.strings[gID]; String string = push.pointers.strings.strings[gID];
Font font = push.ui.fonts.fonts[0];
uint buffer_pos = atomicAdd(push.pointers.draw.instance_count, string.len); uint buffer_pos = atomicAdd(push.pointers.draw.instance_count, string.len);
float x = 0; float x = 0;

@ -1,6 +1,8 @@
#version 450 #version 450
#extension GL_EXT_nonuniform_qualifier : enable
layout(set = 1, binding = 1) uniform sampler2DArray font; layout(set = 0, binding = 0) uniform sampler font_samplers[];
layout(set = 1, binding = 0) uniform texture2DArray font_textures[];
layout(location = 0) in vec4 fragColor; layout(location = 0) in vec4 fragColor;
layout(location = 1) in vec2 fragUV; layout(location = 1) in vec2 fragUV;
@ -9,6 +11,6 @@ layout(location = 2) flat in uint code;
layout(location = 0) out vec4 outColor; layout(location = 0) out vec4 outColor;
void main() { void main() {
outColor = fragColor * texture(font, vec3(fragUV, code)); outColor = fragColor * texture(sampler2DArray(font_textures[0], font_samplers[0]), vec3(fragUV, code));
} }

@ -1,7 +1,7 @@
#version 450 #version 450
#extension GL_EXT_buffer_reference : require #extension GL_EXT_buffer_reference : require
struct Symbol { layout(buffer_reference, std430) buffer Symbol {
int top; int top;
uint left; uint left;
uint width; uint width;
@ -9,7 +9,7 @@ struct Symbol {
uint advance; uint advance;
}; };
struct Character { layout(buffer_reference, std430) buffer Character {
vec3 pos; vec3 pos;
vec4 color; vec4 color;
float size; float size;
@ -24,23 +24,30 @@ layout(buffer_reference, std430) readonly buffer CharacterList{
Character characters[]; Character characters[];
}; };
layout(set = 0, binding = 0) uniform UIUniform { layout(buffer_reference, std430) readonly buffer Font {
mat4 screen;
} ubo;
layout(set = 1, binding = 0) uniform Font {
uint num_symbols; uint num_symbols;
uint width; uint width;
uint height; uint height;
SymbolList symbol_list; SymbolList symbol_list;
} font; };
layout(buffer_reference, std430) readonly buffer Pointers { layout(buffer_reference, std430) readonly buffer Pointers {
uint padding[4]; uint padding[4];
CharacterList characters; CharacterList characters;
};
layout(buffer_reference, std430) readonly buffer FontList {
Font fonts[];
};
layout(buffer_reference, std430) readonly buffer UIContext {
mat4 screen;
FontList fonts;
}; };
layout(std430, push_constant) uniform Push { layout(std430, push_constant) uniform Push {
UIContext ui;
Pointers pointers; Pointers pointers;
} push; } push;
@ -59,6 +66,7 @@ const vec2 square[6] = {
void main() { void main() {
Character character = push.pointers.characters.characters[gl_InstanceIndex]; Character character = push.pointers.characters.characters[gl_InstanceIndex];
Font font = push.ui.fonts.fonts[0];
Symbol symbol = font.symbol_list.symbols[character.code]; Symbol symbol = font.symbol_list.symbols[character.code];
float fragU = square[gl_VertexIndex].x * symbol.width/font.width; float fragU = square[gl_VertexIndex].x * symbol.width/font.width;
@ -68,7 +76,7 @@ void main() {
fragUV = vec2(fragU, fragV); fragUV = vec2(fragU, fragV);
fragColor = character.color; fragColor = character.color;
gl_Position = ubo.screen * vec4(vec3(x, y, 0.0) + character.pos, 1.0); gl_Position = push.ui.screen * vec4(vec3(x, y, 0.0) + character.pos, 1.0);
code = character.code; code = character.code;
} }

@ -10,168 +10,42 @@
VkResult render_thread(GLFWwindow* window, RenderContext* render_context) { VkResult render_thread(GLFWwindow* window, RenderContext* render_context) {
VkResult result; VkResult result;
UIContext ui_context; UIContextStorage ui;
VkBuffer colored_rect_buffer;
VmaAllocation colored_rect_memory;
result = init_pipelines(render_context->device, render_context->allocator, render_context->swapchain_extent, render_context->window_scale, render_context->render_pass, &ui_context);
if(result != VK_SUCCESS) {
return result;
}
FT_Library library; FT_Library library;
if(FT_Init_FreeType(&library) != FT_Err_Ok) { FontStorage font;
return VK_ERROR_UNKNOWN;
}
Font test_font;
uint32_t* charmap; uint32_t* charmap;
result = load_font(render_context->device, render_context->allocator, ui_context.font_layout, ui_context.font_pool, render_context->transfer_pool, render_context->transfer_queue, library, "test.ttf", 16, VK_TRUE, &charmap, &test_font); VkBuffer temp_buffer;
if(result != VK_SUCCESS) { VmaAllocation temp_memory;
return result; void* mapped;
} UILayerStorage layer = {};
VkBufferCreateInfo colored_rect_buffer_info = {
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
.size = 3*sizeof(ColoredRect),
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
};
VmaAllocationCreateInfo colored_rect_memory_info = {
.usage = VMA_MEMORY_USAGE_CPU_TO_GPU,
};
result = vmaCreateBuffer(render_context->allocator, &colored_rect_buffer_info, &colored_rect_memory_info, &colored_rect_buffer, &colored_rect_memory, NULL); result = create_ui_context(render_context->device, render_context->allocator, render_context->render_pass, &ui);
if(result != VK_SUCCESS) { if(result != VK_SUCCESS) {
return result; return result;
} }
ColoredRect* colored_rects; if(FT_Init_FreeType(&library) != FT_Err_Ok) {
return VK_ERROR_UNKNOWN;
result = vmaMapMemory(render_context->allocator, colored_rect_memory, (void**)&colored_rects);
if(result != VK_SUCCESS) {
return result;
} }
colored_rects[0].pos[0] = 0.0; result = load_font(render_context->device, render_context->allocator, ui.font_infos, ui.font_samplers, ui.font_textures, 0, render_context->transfer_pool, render_context->transfer_queue, library, "test.ttf", 16, VK_TRUE, &charmap, &font);
colored_rects[0].pos[1] = 0.0;
colored_rects[0].pos[2] = 0.5;
colored_rects[0].size[0] = 100.0;
colored_rects[0].size[1] = 100.0;
colored_rects[0].color[0] = 1.0;
colored_rects[0].color[1] = 0.0;
colored_rects[0].color[2] = 0.0;
colored_rects[0].color[3] = 1.0;
colored_rects[1].pos[0] = 0.0;
colored_rects[1].pos[1] = 100.0;
colored_rects[1].pos[2] = 0.5;
colored_rects[1].size[0] = 100.0;
colored_rects[1].size[1] = 100.0;
colored_rects[1].color[0] = 0.0;
colored_rects[1].color[1] = 0.0;
colored_rects[1].color[2] = 1.0;
colored_rects[1].color[3] = 1.0;
colored_rects[2].pos[0] = 100.0;
colored_rects[2].pos[1] = 0.0;
colored_rects[2].pos[2] = 0.5;
colored_rects[2].size[0] = 100.0;
colored_rects[2].size[1] = 100.0;
colored_rects[2].color[0] = 0.0;
colored_rects[2].color[1] = 1.0;
colored_rects[2].color[2] = 0.0;
colored_rects[2].color[3] = 1.0;
vmaUnmapMemory(render_context->allocator, colored_rect_memory);
TextPointersMemory text_pointers;
VkDeviceAddress text_pointers_address;
result = create_text_pointers(2, 100, render_context->device, render_context->allocator, render_context->transfer_pool, render_context->transfer_queue, &text_pointers, &text_pointers_address);
if(result != VK_SUCCESS) { if(result != VK_SUCCESS) {
return result; return result;
} }
VkBuffer temp_buffer;
VmaAllocation temp_memory;
void* mapped;
result = create_transfer_buffer(2*sizeof(String) + 100*sizeof(uint32_t), render_context->allocator, &temp_buffer, &temp_memory, (void**)&mapped); result = create_transfer_buffer(2*sizeof(String) + 100*sizeof(uint32_t), render_context->allocator, &temp_buffer, &temp_memory, (void**)&mapped);
if(result != VK_SUCCESS) { if(result != VK_SUCCESS) {
return result; return result;
} }
String* mapped_strings = (String*)mapped;
mapped_strings[0].pos[0] = 0;
mapped_strings[0].pos[1] = 200.0;
mapped_strings[0].pos[2] = 0.2;
mapped_strings[0].color[0] = 1.0;
mapped_strings[0].color[1] = 1.0;
mapped_strings[0].color[2] = 1.0;
mapped_strings[0].color[3] = 1.0;
mapped_strings[0].size = 50.0;
mapped_strings[0].length = 50;
mapped_strings[0].offset = 0;
mapped_strings[1].pos[0] = 0;
mapped_strings[1].pos[1] = 225.0;
mapped_strings[1].pos[2] = 0.3;
mapped_strings[1].color[0] = 1.0;
mapped_strings[1].color[1] = 1.0;
mapped_strings[1].color[2] = 1.0;
mapped_strings[1].color[3] = 1.0;
mapped_strings[1].size = 50.0;
mapped_strings[1].length = 50;
mapped_strings[1].offset = 50;
uint32* mapped_codes = (uint32_t*)(mapped + 2*sizeof(String));
for(uint32_t i = 0; i < 100; i++) {
mapped_codes[i] = i;
}
VkCommandBuffer command_buffer = command_begin_single(render_context->device, render_context->transfer_pool);
VkBufferCopy copy_string = {
.size = 2*sizeof(String),
.srcOffset = 0,
};
vkCmdCopyBuffer(command_buffer, temp_buffer, text_pointers.strings_buffer, 1, &copy_string);
VkBufferCopy copy_codes = {
.size = 100*sizeof(uint32_t),
.srcOffset = 2*sizeof(String),
};
vkCmdCopyBuffer(command_buffer, temp_buffer, text_pointers.codes_buffer, 1, &copy_codes);
result = command_end_single(render_context->device, command_buffer, render_context->transfer_pool, render_context->transfer_queue);
if(result != VK_SUCCESS) {
return result;
}
vkQueueWaitIdle(render_context->transfer_queue.handle); vkQueueWaitIdle(render_context->transfer_queue.handle);
vmaUnmapMemory(render_context->allocator, temp_memory); vmaUnmapMemory(render_context->allocator, temp_memory);
vmaDestroyBuffer(render_context->allocator, temp_buffer, temp_memory); vmaDestroyBuffer(render_context->allocator, temp_buffer, temp_memory);
VkBufferDeviceAddressInfo colored_rect_address_info = {
.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO,
.buffer = colored_rect_buffer,
};
UILayer test_layer = {
.colored_rects = vkGetBufferDeviceAddress(render_context->device, &colored_rect_address_info),
.colored_rect_count = 3,
.font = test_font,
.chars = text_pointers.characters_buffer,
.string_count = 2,
.chars_count = 100,
.string_pointers = text_pointers_address,
.string_draw = text_pointers.draw_buffer,
};
while(glfwWindowShouldClose(window) == 0) { while(glfwWindowShouldClose(window) == 0) {
glfwPollEvents(); glfwPollEvents();
result = draw_frame(render_context, &ui_context, &test_layer, 1); result = draw_frame(render_context, &ui, &layer, 1);
if(result != VK_SUCCESS) { if(result != VK_SUCCESS) {
fprintf(stderr, "draw_frame error: %s\n", string_VkResult(result)); fprintf(stderr, "draw_frame error: %s\n", string_VkResult(result));
return result; return result;

@ -344,6 +344,7 @@ VkResult create_logical_device(VkPhysicalDevice physical_device, VkSurfaceKHR su
VkPhysicalDeviceVulkan12Features features_12 = { VkPhysicalDeviceVulkan12Features features_12 = {
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES, .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES,
.bufferDeviceAddress = VK_TRUE, .bufferDeviceAddress = VK_TRUE,
.runtimeDescriptorArray = VK_TRUE,
.descriptorIndexing = VK_TRUE, .descriptorIndexing = VK_TRUE,
.descriptorBindingPartiallyBound = VK_TRUE, .descriptorBindingPartiallyBound = VK_TRUE,
.descriptorBindingVariableDescriptorCount = VK_TRUE, .descriptorBindingVariableDescriptorCount = VK_TRUE,
@ -976,7 +977,7 @@ VkResult init_vulkan(GLFWwindow* window, RenderContext* context) {
return VK_SUCCESS; return VK_SUCCESS;
} }
VkResult draw_frame(RenderContext* context, UIContext* ui_context, UILayer* ui_layers, uint32_t ui_layer_count) { VkResult draw_frame(RenderContext* context, UIContextStorage* ui_context, UILayerStorage* ui_layers, uint32_t ui_layer_count) {
VkResult result; VkResult result;
result = vkWaitForFences(context->device, 1, &context->in_flight_fences[context->current_frame], VK_TRUE, UINT64_MAX); result = vkWaitForFences(context->device, 1, &context->in_flight_fences[context->current_frame], VK_TRUE, UINT64_MAX);
@ -996,7 +997,6 @@ VkResult draw_frame(RenderContext* context, UIContext* ui_context, UILayer* ui_l
return result; return result;
} }
result = vkResetCommandBuffer(command_buffer, 0); result = vkResetCommandBuffer(command_buffer, 0);
if(result != VK_SUCCESS) { if(result != VK_SUCCESS) {
return result; return result;
@ -1035,82 +1035,32 @@ VkResult draw_frame(RenderContext* context, UIContext* ui_context, UILayer* ui_l
.pClearValues = clear_values, .pClearValues = clear_values,
}; };
// UI strings compute pass VkDeviceAddress push[2] = {ui_context->address, 0};
vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, ui_context->ui_compute_text.pipeline);
for(uint32_t i = 0; i < ui_layer_count; i ++) { // Compute Pass
if(ui_layers[i].string_count > 0) { vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, ui_context->string_pipeline.pipeline);
VkBufferMemoryBarrier draw_barrier = { for(uint32_t i = 0; i < ui_layer_count; i++) {
.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, push[1] = ui_layers[i].address;
.size = sizeof(DrawCommand), vkCmdPushConstants(command_buffer, ui_context->string_pipeline.layout, VK_SHADER_STAGE_COMPUTE_BIT, 0, 16, push);
.buffer = ui_layers[i].string_draw, vkCmdDispatchIndirect(command_buffer, ui_layers[i].layer, offsetof(UILayer, dispatch_strings));
.srcAccessMask = VK_ACCESS_INDIRECT_COMMAND_READ_BIT,
.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
};
vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT, VK_PIPELINE_STAGE_2_ALL_TRANSFER_BIT, VK_DEPENDENCY_BY_REGION_BIT, 0, NULL, 1, &draw_barrier, 0, NULL);
vkCmdFillBuffer(command_buffer, ui_layers[i].string_draw, offsetof(DrawCommand, instance_count), sizeof(uint32_t), 0);
VkBufferMemoryBarrier clear_barrier = {
.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
.size = sizeof(uint32_t),
.offset = offsetof(DrawCommand, instance_count),
.buffer = ui_layers[i].string_draw,
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
};
vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_2_ALL_TRANSFER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_DEPENDENCY_BY_REGION_BIT, 0, NULL, 1, &clear_barrier, 0, NULL);
vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, ui_context->ui_compute_text.layout, 0, 1, &ui_layers[i].font.set, 0, NULL);
vkCmdPushConstants(command_buffer, ui_context->ui_pipeline_text.layout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_COMPUTE_BIT, 0, 8, &ui_layers[i].string_pointers);
vkCmdDispatch(command_buffer, ui_layers[i].string_count, 1, 1);
VkBufferMemoryBarrier character_compute_barrier = {
.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
.size = ui_layers[i].chars_count,
.buffer = ui_layers[i].chars,
.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT,
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT,
};
VkBufferMemoryBarrier draw_compute_barrier = {
.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
.size = sizeof(DrawCommand),
.buffer = ui_layers[i].string_draw,
.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT,
.dstAccessMask = VK_ACCESS_INDIRECT_COMMAND_READ_BIT,
};
vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT, VK_DEPENDENCY_BY_REGION_BIT, 0, NULL, 1, &character_compute_barrier, 0, NULL);
vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT, VK_DEPENDENCY_BY_REGION_BIT, 0, NULL, 1, &draw_compute_barrier, 0, NULL);
}
} }
// Render Pass // Render Pass
vkCmdBeginRenderPass(command_buffer, &render_pass_begin, VK_SUBPASS_CONTENTS_INLINE); vkCmdBeginRenderPass(command_buffer, &render_pass_begin, VK_SUBPASS_CONTENTS_INLINE);
// World subpass // World subpass
vkCmdNextSubpass(command_buffer, VK_SUBPASS_CONTENTS_INLINE); vkCmdNextSubpass(command_buffer, VK_SUBPASS_CONTENTS_INLINE);
// UI subpass // UI subpass
vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, ui_context->rect_pipeline.layout, 0, 1, &ui_context->font_samplers, 0, NULL);
// Draw UI colored rects //////////////////////////////// vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, ui_context->rect_pipeline.layout, 1, 1, &ui_context->font_textures, 0, NULL);
vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, ui_context->ui_pipeline_rect.pipeline);
vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, ui_context->ui_pipeline_rect.layout, 0, 1, &ui_context->ui_descriptor_set, 0, NULL);
for(uint32_t i = 0; i < ui_layer_count; i++) {
if(ui_layers[i].colored_rect_count > 0) {
vkCmdPushConstants(command_buffer, ui_context->ui_pipeline_rect.layout, VK_SHADER_STAGE_VERTEX_BIT, 0, 8, &ui_layers[i].colored_rects);
vkCmdDraw(command_buffer, 6, ui_layers[i].colored_rect_count, 0, 0);
}
}
/////////////////////////////////////////////////////////
// Draw UI text /////////////////////////////////////////
vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, ui_context->ui_pipeline_text.pipeline);
vkCmdBindDescriptorSets(command_buffer, 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++) { for(uint32_t i = 0; i < ui_layer_count; i++) {
if(ui_layers[i].string_count > 0) { push[1] = ui_layers[i].address;
// Bind Font Descriptor vkCmdPushConstants(command_buffer, ui_context->rect_pipeline.layout, VK_SHADER_STAGE_VERTEX_BIT, 0, 16, push);
vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, ui_context->ui_pipeline_text.layout, 1, 1, &ui_layers[i].font.set, 0, NULL); vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, ui_context->rect_pipeline.pipeline);
// Push pointers vkCmdDrawIndirect(command_buffer, ui_layers[i].layer, offsetof(UILayer, draw_rects), 1, 0);
vkCmdPushConstants(command_buffer, ui_context->ui_pipeline_text.layout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_COMPUTE_BIT, 0, 8, &ui_layers[i].string_pointers); vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, ui_context->char_pipeline.pipeline);
vkCmdDrawIndirect(command_buffer, ui_layers[i].string_draw, 0, 1, sizeof(DrawCommand)); vkCmdDrawIndirect(command_buffer, ui_layers[i].layer, offsetof(UILayer, draw_chars), 1, 0);
}
} }
/////////////////////////////////////////////////////////
vkCmdEndRenderPass(command_buffer); vkCmdEndRenderPass(command_buffer);

@ -53,14 +53,33 @@ VkShaderModule load_shader_file(const char* path, VkDevice device) {
VkResult create_ui_pipeline( VkResult create_ui_pipeline(
VkDevice device, VkDevice device,
VkRenderPass render_pass, VkRenderPass render_pass,
VkDescriptorSetLayout font_samplers_layout,
VkDescriptorSetLayout font_textures_layout,
VkPipelineShaderStageCreateInfo* shader_stages, VkPipelineShaderStageCreateInfo* shader_stages,
uint32_t shader_stage_count, uint32_t shader_stage_count,
VkPipelineVertexInputStateCreateInfo input_info, VkPipelineVertexInputStateCreateInfo input_info,
VkPipelineLayoutCreateInfo layout_info,
VkPipelineInputAssemblyStateCreateInfo input_assembly_info, VkPipelineInputAssemblyStateCreateInfo input_assembly_info,
GraphicsPipeline* pipeline) { GraphicsPipeline* pipeline) {
VkResult result; VkResult result;
VkPushConstantRange push_constants[] = {
{
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT,
.size = 16,
.offset = 0,
},
};
VkDescriptorSetLayout set_layouts[] = {font_samplers_layout, font_textures_layout};
VkPipelineLayoutCreateInfo layout_info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
.pushConstantRangeCount = sizeof(push_constants)/sizeof(VkPushConstantRange),
.pPushConstantRanges = push_constants,
.setLayoutCount = sizeof(set_layouts)/sizeof(VkDescriptorSetLayout),
.pSetLayouts = set_layouts,
};
result = vkCreatePipelineLayout(device, &layout_info, 0, &pipeline->layout); result = vkCreatePipelineLayout(device, &layout_info, 0, &pipeline->layout);
if(result != VK_SUCCESS) { if(result != VK_SUCCESS) {
return result; return result;
@ -176,12 +195,12 @@ VkResult create_ui_pipeline(
return VK_SUCCESS; return VK_SUCCESS;
} }
VkResult create_ui_colored_rect_pipeline(VkDevice device, VkRenderPass render_pass, VkDescriptorSetLayout ui_descriptor_layout, GraphicsPipeline* pipeline) { VkResult create_ui_rect_pipeline(VkDevice device, VkRenderPass render_pass, VkDescriptorSetLayout font_samplers_layout, VkDescriptorSetLayout font_textures_layout, GraphicsPipeline* pipeline) {
VkShaderModule vert_shader = load_shader_file("shader_src/ui_colored_rect.vert.spv", device); VkShaderModule vert_shader = load_shader_file("shader_src/ui_rect.vert.spv", device);
if(vert_shader == VK_NULL_HANDLE) { if(vert_shader == VK_NULL_HANDLE) {
return VK_ERROR_UNKNOWN; return VK_ERROR_UNKNOWN;
} }
VkShaderModule frag_shader = load_shader_file("shader_src/ui_colored_rect.frag.spv", device); VkShaderModule frag_shader = load_shader_file("shader_src/ui_rect.frag.spv", device);
if(frag_shader == VK_NULL_HANDLE) { if(frag_shader == VK_NULL_HANDLE) {
return VK_ERROR_UNKNOWN; return VK_ERROR_UNKNOWN;
} }
@ -210,26 +229,13 @@ VkResult create_ui_colored_rect_pipeline(VkDevice device, VkRenderPass render_pa
.vertexAttributeDescriptionCount = sizeof(attributes)/sizeof(VkVertexInputAttributeDescription), .vertexAttributeDescriptionCount = sizeof(attributes)/sizeof(VkVertexInputAttributeDescription),
}; };
VkPushConstantRange push_constant = {
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
.size = 8,
};
VkPipelineLayoutCreateInfo layout_info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
.setLayoutCount = 1,
.pSetLayouts = &ui_descriptor_layout,
.pPushConstantRanges = &push_constant,
.pushConstantRangeCount = 1,
};
VkPipelineInputAssemblyStateCreateInfo input_assembly_info = { VkPipelineInputAssemblyStateCreateInfo input_assembly_info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
.primitiveRestartEnable = VK_FALSE, .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); VkResult result = create_ui_pipeline(device, render_pass, font_samplers_layout, font_textures_layout, shader_stages, sizeof(shader_stages)/sizeof(VkPipelineShaderStageCreateInfo), input_info, input_assembly_info, pipeline);
if(result != VK_SUCCESS) { if(result != VK_SUCCESS) {
return result; return result;
} }
@ -237,7 +243,7 @@ VkResult create_ui_colored_rect_pipeline(VkDevice device, VkRenderPass render_pa
return VK_SUCCESS; return VK_SUCCESS;
} }
VkResult create_ui_text_pipeline(VkDevice device, VkRenderPass render_pass, VkDescriptorSetLayout ui_descriptor_layout, VkDescriptorSetLayout font_layout, GraphicsPipeline* pipeline, ComputePipeline* compute) { VkResult create_ui_text_pipeline(VkDevice device, VkRenderPass render_pass, VkDescriptorSetLayout font_samplers_layout, VkDescriptorSetLayout font_textures_layout, GraphicsPipeline* pipeline, ComputePipeline* compute) {
VkResult result; VkResult result;
VkShaderModule compute_shader = load_shader_file("shader_src/ui_text.comp.spv", device); VkShaderModule compute_shader = load_shader_file("shader_src/ui_text.comp.spv", device);
if(compute_shader == VK_NULL_HANDLE) { if(compute_shader == VK_NULL_HANDLE) {
@ -252,18 +258,14 @@ VkResult create_ui_text_pipeline(VkDevice device, VkRenderPass render_pass, VkDe
}; };
VkPushConstantRange push_constant = { VkPushConstantRange push_constant = {
.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT | VK_SHADER_STAGE_VERTEX_BIT, .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
.size = 8, .size = 16,
}; };
VkDescriptorSetLayout compute_descriptors[] = {font_layout};
VkPipelineLayoutCreateInfo compute_layout_info = { VkPipelineLayoutCreateInfo compute_layout_info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
.pushConstantRangeCount = 1, .pushConstantRangeCount = 1,
.pPushConstantRanges = &push_constant, .pPushConstantRanges = &push_constant,
.setLayoutCount = sizeof(compute_descriptors)/sizeof(VkDescriptorSetLayout),
.pSetLayouts = compute_descriptors,
}; };
result = vkCreatePipelineLayout(device, &compute_layout_info, NULL, &compute->layout); result = vkCreatePipelineLayout(device, &compute_layout_info, NULL, &compute->layout);
@ -320,23 +322,13 @@ VkResult create_ui_text_pipeline(VkDevice device, VkRenderPass render_pass, VkDe
.vertexAttributeDescriptionCount = sizeof(attributes)/sizeof(VkVertexInputAttributeDescription), .vertexAttributeDescriptionCount = sizeof(attributes)/sizeof(VkVertexInputAttributeDescription),
}; };
VkDescriptorSetLayout all_layouts[] = {ui_descriptor_layout, font_layout};
VkPipelineLayoutCreateInfo layout_info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
.setLayoutCount = sizeof(all_layouts)/sizeof(VkDescriptorSetLayout),
.pSetLayouts = all_layouts,
.pPushConstantRanges = &push_constant,
.pushConstantRangeCount = 1,
};
VkPipelineInputAssemblyStateCreateInfo input_assembly_info = { VkPipelineInputAssemblyStateCreateInfo input_assembly_info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
.primitiveRestartEnable = VK_FALSE, .primitiveRestartEnable = VK_FALSE,
}; };
result = create_ui_pipeline(device, render_pass, shader_stages, sizeof(shader_stages)/sizeof(VkPipelineShaderStageCreateInfo), input_info, layout_info, input_assembly_info, pipeline); result = create_ui_pipeline(device, render_pass, font_samplers_layout, font_textures_layout, shader_stages, sizeof(shader_stages)/sizeof(VkPipelineShaderStageCreateInfo), input_info, input_assembly_info, pipeline);
if(result != VK_SUCCESS) { if(result != VK_SUCCESS) {
return result; return result;
} }
@ -344,219 +336,36 @@ VkResult create_ui_text_pipeline(VkDevice device, VkRenderPass render_pass, VkDe
return VK_SUCCESS; return VK_SUCCESS;
} }
VkResult create_font_descriptor_pools(VkDevice device, uint32_t max_sets, VkDescriptorPool* font_pool, VkDescriptorSetLayout* font_layout) { VkResult create_layer(
VkResult result;
VkDescriptorPoolSize font_pool_sizes[] = {
{
.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
.descriptorCount = 1,
},
{
.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
.descriptorCount = 1,
},
};
VkDescriptorPoolCreateInfo font_pool_info = {
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
.pPoolSizes = font_pool_sizes,
.poolSizeCount = sizeof(font_pool_sizes)/sizeof(VkDescriptorPoolSize),
.maxSets = max_sets,
};
result = vkCreateDescriptorPool(device, &font_pool_info, NULL, font_pool);
if(result != VK_SUCCESS) {
return result;
}
VkDescriptorSetLayoutBinding font_descriptor_bindings[] = {
{
.binding = 0,
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
.descriptorCount = 1,
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_COMPUTE_BIT,
},
{
.binding = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
.descriptorCount = 1,
.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
},
};
VkDescriptorSetLayoutCreateInfo font_descriptor_info = {
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
.pBindings = font_descriptor_bindings,
.bindingCount = sizeof(font_descriptor_bindings)/sizeof(VkDescriptorSetLayoutBinding),
};
result = vkCreateDescriptorSetLayout(device, &font_descriptor_info, NULL, font_layout);
if(result != VK_SUCCESS) {
return result;
}
return VK_SUCCESS;
}
VkResult create_text_pointers(
uint32_t max_strings, uint32_t max_strings,
uint32_t max_characters, uint32_t max_characters,
uint32_t max_rects,
VkDevice device, VkDevice device,
VmaAllocator allocator, VmaAllocator allocator,
VkCommandPool transfer_pool, VkCommandPool transfer_pool,
Queue transfer_queue, Queue transfer_queue,
TextPointersMemory* memory, UILayerStorage* memory,
VkDeviceAddress* address) { VkDeviceAddress* address) {
VkResult result; VkResult result;
VmaAllocationCreateInfo memory_info = {
.usage = VMA_MEMORY_USAGE_GPU_ONLY,
};
VkBufferCreateInfo pointers_info = {
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.size = sizeof(StringPointers),
.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
};
result = vmaCreateBuffer(allocator, &pointers_info, &memory_info, &memory->pointers_buffer, &memory->pointers_memory, NULL);
if(result != VK_SUCCESS) {
return result;
}
VkBufferCreateInfo draw_info = {
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.size = sizeof(DrawCommand),
.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
};
result = vmaCreateBuffer(allocator, &draw_info, &memory_info, &memory->draw_buffer, &memory->draw_memory, NULL);
if(result != VK_SUCCESS) {
return result;
}
VkBufferCreateInfo strings_info = {
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.size = max_strings*sizeof(String),
.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
};
result = vmaCreateBuffer(allocator, &strings_info, &memory_info, &memory->strings_buffer, &memory->strings_memory, NULL);
if(result != VK_SUCCESS) {
return result;
}
VkBufferCreateInfo codes_info = {
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.size = max_characters*sizeof(DrawCommand),
.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
};
result = vmaCreateBuffer(allocator, &codes_info, &memory_info, &memory->codes_buffer, &memory->codes_memory, NULL);
if(result != VK_SUCCESS) {
return result;
}
VkBufferCreateInfo characters_info = {
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.size = max_characters*sizeof(DrawCommand),
.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
};
result = vmaCreateBuffer(allocator, &characters_info, &memory_info, &memory->characters_buffer, &memory->characters_memory, NULL);
if(result != VK_SUCCESS) {
return result;
}
VkBufferDeviceAddressInfo pointers_address = {
.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO,
.buffer = memory->pointers_buffer,
};
VkBufferDeviceAddressInfo strings_address = {
.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO,
.buffer = memory->strings_buffer,
};
VkBufferDeviceAddressInfo codes_address = {
.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO,
.buffer = memory->codes_buffer,
};
VkBufferDeviceAddressInfo characters_address = {
.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO,
.buffer = memory->characters_buffer,
};
VkBufferDeviceAddressInfo draw_address = {
.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO,
.buffer = memory->draw_buffer,
};
VkBuffer temp_buffer;
VmaAllocation temp_memory;
VkBufferCreateInfo temp_buffer_info = {
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
.size = sizeof(StringPointers) +
sizeof(DrawCommand),
};
VmaAllocationCreateInfo temp_memory_info = {
.usage = VMA_MEMORY_USAGE_CPU_TO_GPU,
};
result = vmaCreateBuffer(allocator, &temp_buffer_info, &temp_memory_info, &temp_buffer, &temp_memory, NULL);
if(result != VK_SUCCESS) {
return result;
}
void* mapped;
result = vmaMapMemory(allocator, temp_memory, &mapped);
if(result != VK_SUCCESS) {
return result;
}
DrawCommand draw = {
.vertex_count = 6,
};
memcpy(mapped + 0, &draw, sizeof(DrawCommand));
StringPointers pointers = {
.strings = vkGetBufferDeviceAddress(device, &strings_address),
.codes = vkGetBufferDeviceAddress(device, &codes_address),
.characters = vkGetBufferDeviceAddress(device, &characters_address),
.draw = vkGetBufferDeviceAddress(device, &draw_address),
};
memcpy(mapped + sizeof(DrawCommand), &pointers, sizeof(StringPointers));
vmaUnmapMemory(allocator, temp_memory);
VkCommandBuffer command_buffer = command_begin_single(device, transfer_pool);
VkBufferCopy copy_draw = {
.size = sizeof(DrawCommand),
.srcOffset = 0,
};
vkCmdCopyBuffer(command_buffer, temp_buffer, memory->draw_buffer, 1, &copy_draw);
VkBufferCopy copy_pointers = {
.size = sizeof(StringPointers),
.srcOffset = sizeof(DrawCommand),
};
vkCmdCopyBuffer(command_buffer, temp_buffer, memory->pointers_buffer, 1, &copy_pointers);
result = command_end_single(device, command_buffer, transfer_pool, transfer_queue);
if(result != VK_SUCCESS) {
return result;
}
vmaDestroyBuffer(allocator, temp_buffer, temp_memory);
*address = vkGetBufferDeviceAddress(device, &pointers_address);
return VK_SUCCESS; return VK_SUCCESS;
} }
VkResult load_font(VkDevice device, VmaAllocator allocator, VkDescriptorSetLayout layout, VkDescriptorPool pool,VkCommandPool transfer_pool, Queue transfer_queue, FT_Library library, const char* ttf_file, uint32_t size, VkBool32 antialias, uint32_t** charmap, Font* descriptor) { VkResult load_font(
VkDevice device,
VmaAllocator allocator,
VkBuffer font_infos,
VkDescriptorSet font_samplers,
VkDescriptorSet font_textures,
uint32_t index,
VkCommandPool transfer_pool,
Queue transfer_queue,
FT_Library library,
const char* ttf_file,
uint32_t size,
VkBool32 antialias,
uint32_t** charmap,
FontStorage* memory) {
FT_Face face; FT_Face face;
int error; int error;
@ -572,7 +381,7 @@ VkResult load_font(VkDevice device, VmaAllocator allocator, VkDescriptorSetLayou
uint32_t* tmp_charmap = malloc(sizeof(uint32_t)*face->num_glyphs); uint32_t* tmp_charmap = malloc(sizeof(uint32_t)*face->num_glyphs);
SymbolInfo* symbols = malloc(sizeof(SymbolInfo)*face->num_glyphs); SymbolInfo* symbols = malloc(sizeof(SymbolInfo)*face->num_glyphs);
FontUniform uniform; Font info;
uint32_t glyph_index; uint32_t glyph_index;
uint32_t max_height = 0; uint32_t max_height = 0;
@ -607,9 +416,9 @@ VkResult load_font(VkDevice device, VmaAllocator allocator, VkDescriptorSetLayou
c = FT_Get_Next_Char(face, c, &glyph_index); c = FT_Get_Next_Char(face, c, &glyph_index);
} }
uniform.width = max_width; info.width = max_width;
uniform.height = max_height; info.height = max_height;
uniform.num_symbols = symbol_count; info.num_symbols = symbol_count;
uint32_t image_size = max_width*max_height*sizeof(uint32_t); uint32_t image_size = max_width*max_height*sizeof(uint32_t);
uint32_t* images = malloc(image_size*symbol_count); uint32_t* images = malloc(image_size*symbol_count);
memset(images, 0x00, image_size*symbol_count); memset(images, 0x00, image_size*symbol_count);
@ -636,53 +445,29 @@ VkResult load_font(VkDevice device, VmaAllocator allocator, VkDescriptorSetLayou
} }
VkResult result; 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 = { VkBufferCreateInfo symbol_buffer_info = {
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_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, .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, .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
.size = sizeof(SymbolInfo)*uniform.num_symbols, .size = sizeof(SymbolInfo)*info.num_symbols,
}; };
VmaAllocationCreateInfo symbol_memory_info = { VmaAllocationCreateInfo symbol_memory_info = {
.usage = VMA_MEMORY_USAGE_GPU_ONLY, .usage = VMA_MEMORY_USAGE_GPU_ONLY,
}; };
result = vmaCreateBuffer(allocator, &symbol_buffer_info, &symbol_memory_info, &descriptor->symbols, &descriptor->symbol_memory, NULL); result = vmaCreateBuffer(allocator, &symbol_buffer_info, &symbol_memory_info, &memory->symbols, &memory->symbol_memory, NULL);
if(result != VK_SUCCESS) { if(result != VK_SUCCESS) {
return result; return result;
} }
VkBufferCreateInfo uniform_buffer_info = {
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | 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 = { VkImageCreateInfo image_info = {
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
.sharingMode = VK_SHARING_MODE_EXCLUSIVE, .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, .usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
.extent.depth = 1, .extent.depth = 1,
.extent.width = uniform.width, .extent.width = info.width,
.extent.height = uniform.height, .extent.height = info.height,
.mipLevels = 1, .mipLevels = 1,
.arrayLayers = uniform.num_symbols, .arrayLayers = info.num_symbols,
.format = VK_FORMAT_R8G8B8A8_SRGB, .format = VK_FORMAT_R8G8B8A8_SRGB,
.tiling = VK_IMAGE_TILING_OPTIMAL, .tiling = VK_IMAGE_TILING_OPTIMAL,
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
@ -694,7 +479,7 @@ VkResult load_font(VkDevice device, VmaAllocator allocator, VkDescriptorSetLayou
.usage = VMA_MEMORY_USAGE_GPU_ONLY, .usage = VMA_MEMORY_USAGE_GPU_ONLY,
}; };
result = vmaCreateImage(allocator, &image_info, &image_memory_info, &descriptor->image, &descriptor->image_memory, NULL); result = vmaCreateImage(allocator, &image_info, &image_memory_info, &memory->image, &memory->image_memory, NULL);
if(result != VK_SUCCESS) { if(result != VK_SUCCESS) {
return result; return result;
} }
@ -703,7 +488,7 @@ VkResult load_font(VkDevice device, VmaAllocator allocator, VkDescriptorSetLayou
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT, .usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
.sharingMode = VK_SHARING_MODE_EXCLUSIVE, .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
.size = sizeof(FontUniform) + image_size*uniform.num_symbols + sizeof(SymbolInfo)*uniform.num_symbols, .size = sizeof(Font) + image_size*info.num_symbols + sizeof(SymbolInfo)*info.num_symbols,
}; };
VmaAllocationCreateInfo staging_memory_info = { VmaAllocationCreateInfo staging_memory_info = {
@ -722,66 +507,66 @@ VkResult load_font(VkDevice device, VmaAllocator allocator, VkDescriptorSetLayou
if(result != VK_SUCCESS) { if(result != VK_SUCCESS) {
return result; return result;
} }
memcpy(mapped_staging + image_size*uniform.num_symbols + sizeof(FontUniform), symbols, sizeof(SymbolInfo)*uniform.num_symbols); memcpy(mapped_staging + image_size*info.num_symbols + sizeof(Font), symbols, sizeof(SymbolInfo)*info.num_symbols);
VkBufferDeviceAddressInfo address_info = { VkBufferDeviceAddressInfo address_info = {
.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO, .sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO,
.buffer = descriptor->symbols, .buffer = memory->symbols,
}; };
uniform.symbol_list = vkGetBufferDeviceAddress(device, &address_info); info.symbol_list = vkGetBufferDeviceAddress(device, &address_info);
memcpy(mapped_staging + image_size*uniform.num_symbols, &uniform, sizeof(FontUniform)); memcpy(mapped_staging + image_size*info.num_symbols, &info, sizeof(Font));
memcpy(mapped_staging, images, image_size*uniform.num_symbols); memcpy(mapped_staging, images, image_size*info.num_symbols);
vmaUnmapMemory(allocator, staging_memory); vmaUnmapMemory(allocator, staging_memory);
free(images); free(images);
free(symbols); free(symbols);
VkCommandBuffer command_buffer = command_begin_single(device, transfer_pool); VkCommandBuffer command_buffer = command_begin_single(device, transfer_pool);
VkBufferCopy uniform_copy_info = { VkBufferCopy info_copy = {
.size = sizeof(FontUniform), .size = sizeof(Font),
.srcOffset = image_size*uniform.num_symbols, .srcOffset = image_size*info.num_symbols,
.dstOffset = 0, .dstOffset = index*sizeof(Font),
}; };
vkCmdCopyBuffer(command_buffer, staging_buffer, descriptor->uniform, 1, &uniform_copy_info); vkCmdCopyBuffer(command_buffer, staging_buffer, font_infos, 1, &info_copy);
VkBufferCopy symbol_copy_info = { VkBufferCopy symbol_copy = {
.size = sizeof(SymbolInfo)*uniform.num_symbols, .size = sizeof(SymbolInfo)*info.num_symbols,
.srcOffset = image_size*uniform.num_symbols + sizeof(FontUniform), .srcOffset = image_size*info.num_symbols + sizeof(Font),
.dstOffset = 0, .dstOffset = 0,
}; };
vkCmdCopyBuffer(command_buffer, staging_buffer, descriptor->symbols, 1, &symbol_copy_info); vkCmdCopyBuffer(command_buffer, staging_buffer, memory->symbols, 1, &symbol_copy);
VkImageMemoryBarrier first_barrier = { VkImageMemoryBarrier first_barrier = {
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.image = descriptor->image, .image = memory->image,
.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED, .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, .newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, .subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.subresourceRange.levelCount = 1, .subresourceRange.levelCount = 1,
.subresourceRange.layerCount = uniform.num_symbols, .subresourceRange.layerCount = info.num_symbols,
.srcAccessMask = 0, .srcAccessMask = 0,
.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, .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); 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 = { VkBufferImageCopy image_copy = {
.imageSubresource.layerCount = uniform.num_symbols, .imageSubresource.layerCount = info.num_symbols,
.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, .imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.imageExtent = image_info.extent, .imageExtent = image_info.extent,
}; };
vkCmdCopyBufferToImage(command_buffer, staging_buffer, descriptor->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &image_copy); vkCmdCopyBufferToImage(command_buffer, staging_buffer, memory->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &image_copy);
VkImageMemoryBarrier second_barrier = { VkImageMemoryBarrier second_barrier = {
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.image = descriptor->image, .image = memory->image,
.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, .newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, .subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.subresourceRange.levelCount = 1, .subresourceRange.levelCount = 1,
.subresourceRange.layerCount = uniform.num_symbols, .subresourceRange.layerCount = info.num_symbols,
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT, .dstAccessMask = VK_ACCESS_SHADER_READ_BIT,
}; };
@ -795,18 +580,18 @@ VkResult load_font(VkDevice device, VmaAllocator allocator, VkDescriptorSetLayou
VkImageViewCreateInfo view_info = { VkImageViewCreateInfo view_info = {
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
.image = descriptor->image, .image = memory->image,
.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY, .viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY,
.format = VK_FORMAT_R8G8B8A8_SRGB, .format = VK_FORMAT_R8G8B8A8_SRGB,
.subresourceRange = { .subresourceRange = {
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.layerCount = uniform.num_symbols, .layerCount = info.num_symbols,
.baseMipLevel = 0, .baseMipLevel = 0,
.levelCount = 1, .levelCount = 1,
.baseArrayLayer = 0, .baseArrayLayer = 0,
}, },
}; };
result = vkCreateImageView(device, &view_info, NULL, &descriptor->view); result = vkCreateImageView(device, &view_info, NULL, &memory->view);
if(result != VK_SUCCESS) { if(result != VK_SUCCESS) {
return result; return result;
} }
@ -819,171 +604,199 @@ VkResult load_font(VkDevice device, VmaAllocator allocator, VkDescriptorSetLayou
.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT, .addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT,
.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT, .addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT,
}; };
result = vkCreateSampler(device, &sampler_info, NULL, &descriptor->sampler); result = vkCreateSampler(device, &sampler_info, NULL, &memory->sampler);
if(result != VK_SUCCESS) { if(result != VK_SUCCESS) {
return result; return result;
} }
VkDescriptorBufferInfo desc_uniform_info = { VkDescriptorImageInfo desc_sampler_info = {
.offset = 0, .sampler = memory->sampler,
.range = sizeof(FontUniform),
.buffer = descriptor->uniform,
}; };
VkDescriptorImageInfo desc_image_info = { VkDescriptorImageInfo desc_texture_info = {
.sampler = descriptor->sampler,
.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
.imageView = descriptor->view, .imageView = memory->view,
}; };
VkWriteDescriptorSet descriptor_writes[] = { VkWriteDescriptorSet descriptor_writes[] = {
{ {
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.dstSet = descriptor->set, .dstSet = font_textures,
.dstBinding = 0, .dstBinding = 0,
.dstArrayElement = 0, .dstArrayElement = index,
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
.descriptorCount = 1, .descriptorCount = 1,
.pBufferInfo = &desc_uniform_info, .pImageInfo = &desc_texture_info,
}, },
{ {
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.dstSet = descriptor->set, .dstSet = font_samplers,
.dstBinding = 1, .dstBinding = 0,
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, .dstArrayElement = index,
.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER,
.descriptorCount = 1, .descriptorCount = 1,
.pImageInfo = &desc_image_info, .pImageInfo = &desc_sampler_info,
} },
}; };
vkUpdateDescriptorSets(device, 2, descriptor_writes, 0, NULL); vkUpdateDescriptorSets(device, sizeof(descriptor_writes)/sizeof(VkWriteDescriptorSet), descriptor_writes, 0, NULL);
return VK_SUCCESS; return VK_SUCCESS;
} }
VkResult create_ui_descriptor_set(VkDevice device, VmaAllocator allocator, VkExtent2D swapchain_extent, vec2 window_scale, VkDescriptorSetLayout* ui_descriptor_layout, VkDescriptorPool* ui_descriptor_pool, VkDescriptorSet* ui_descriptor_set, VmaAllocation* ui_descriptor_memory, VkBuffer* ui_descriptor_buffer) { VkResult create_ui_descriptor(VkDevice device, VmaAllocator allocator, uint32_t max_fonts, VkBuffer* font_infos, VmaAllocation* font_infos_memory, VkDescriptorSet* font_samplers, VkDescriptorSet* font_textures, VkDescriptorSetLayout* font_sampler_layout, VkDescriptorSetLayout* font_texture_layout, VkDescriptorPool* font_pool) {
VkDescriptorSetLayoutBinding ui_descriptor_bindings[] = { VkBufferCreateInfo font_infos_buffer = {
{ .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.binding = 0, .size = sizeof(Font)*max_fonts,
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, .usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
.descriptorCount = 1,
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
}
}; };
VkDescriptorSetLayoutCreateInfo ui_descriptor_info = { VmaAllocationCreateInfo font_infos_memory_info = {
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, .usage = VMA_MEMORY_USAGE_GPU_ONLY,
.pBindings = ui_descriptor_bindings,
.bindingCount = sizeof(ui_descriptor_bindings)/sizeof(VkDescriptorSetLayoutBinding),
}; };
VkResult result; VkResult result;
result = vkCreateDescriptorSetLayout(device, &ui_descriptor_info, NULL, ui_descriptor_layout); result = vmaCreateBuffer(allocator, &font_infos_buffer, &font_infos_memory_info, font_infos, font_infos_memory, NULL);
if(result != VK_SUCCESS) { if(result != VK_SUCCESS) {
return result; return result;
} }
VkDescriptorPoolSize pool_size = { VkDescriptorSetLayoutBinding font_sampler_bindings[] = {
.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, {
.descriptorCount = 1, .binding = 0,
.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER,
.descriptorCount = max_fonts,
.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
},
}; };
VkDescriptorPoolCreateInfo ui_pool_info = { VkDescriptorBindingFlags bindless_flags[] = {
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT | VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT | VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT,
.pPoolSizes = &pool_size,
.poolSizeCount = 1,
.maxSets = 1,
}; };
result = vkCreateDescriptorPool(device, &ui_pool_info, NULL, ui_descriptor_pool); VkDescriptorSetLayoutBindingFlagsCreateInfo font_sampler_bindings_info = {
if(result != VK_SUCCESS) { .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO,
return result; .bindingCount = sizeof(font_sampler_bindings)/sizeof(VkDescriptorSetLayoutBinding),
} .pBindingFlags = bindless_flags,
};
VkDescriptorSetAllocateInfo ui_descriptor_allocate_info = { VkDescriptorSetLayoutCreateInfo font_sampler_info = {
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
.pSetLayouts = ui_descriptor_layout, .pBindings = font_sampler_bindings,
.descriptorSetCount = 1, .bindingCount = sizeof(font_sampler_bindings)/sizeof(VkDescriptorSetLayoutBinding),
.descriptorPool = *ui_descriptor_pool, .flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT,
.pNext = &font_sampler_bindings_info,
}; };
result = vkAllocateDescriptorSets(device, &ui_descriptor_allocate_info, ui_descriptor_set);
result = vkCreateDescriptorSetLayout(device, &font_sampler_info, NULL, font_sampler_layout);
if(result != VK_SUCCESS) { if(result != VK_SUCCESS) {
return result; return result;
} }
VkBufferCreateInfo ui_uniform_buffer_info = { VkDescriptorSetLayoutBinding font_texture_bindings[] = {
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, {
.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, .binding = 0,
.size = sizeof(UIUniform), .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
.sharingMode = VK_SHARING_MODE_EXCLUSIVE, .descriptorCount = max_fonts,
.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
},
}; };
VmaAllocationCreateInfo ui_uniform_memory_info = { VkDescriptorSetLayoutBindingFlagsCreateInfo font_texture_bindings_info = {
.usage = VMA_MEMORY_USAGE_CPU_TO_GPU, .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO,
.bindingCount = sizeof(font_texture_bindings)/sizeof(VkDescriptorSetLayoutBinding),
.pBindingFlags = bindless_flags,
}; };
result = vmaCreateBuffer(allocator, &ui_uniform_buffer_info, &ui_uniform_memory_info, ui_descriptor_buffer, ui_descriptor_memory, NULL); VkDescriptorSetLayoutCreateInfo font_texture_info = {
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
.pBindings = font_texture_bindings,
.bindingCount = sizeof(font_texture_bindings)/sizeof(VkDescriptorSetLayoutBinding),
.flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT,
.pNext = &font_texture_bindings_info,
};
result = vkCreateDescriptorSetLayout(device, &font_texture_info, NULL, font_texture_layout);
if(result != VK_SUCCESS) { if(result != VK_SUCCESS) {
return result; return result;
} }
void* mapped; VkDescriptorPoolSize font_pool_sizes[] = {
result = vmaMapMemory(allocator, *ui_descriptor_memory, &mapped); {
.type = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
.descriptorCount = max_fonts,
},
{
.type = VK_DESCRIPTOR_TYPE_SAMPLER,
.descriptorCount = max_fonts,
},
};
VkDescriptorPoolCreateInfo font_pool_info = {
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
.pPoolSizes = font_pool_sizes,
.poolSizeCount = 2,
.maxSets = 2,
.flags = VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT,
};
result = vkCreateDescriptorPool(device, &font_pool_info, NULL, font_pool);
if(result != VK_SUCCESS) { if(result != VK_SUCCESS) {
return result; return result;
} }
UIUniform ui_uniform;
vec3 screen_offset = {-1.0, -1.0, 0.0};
vec3 screen_scale = {1.0/(float)swapchain_extent.width*window_scale[0], 1.0/(float)swapchain_extent.height*window_scale[1], 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 = { uint32_t max_font_binding = max_fonts - 1;
.offset = 0, VkDescriptorSetVariableDescriptorCountAllocateInfo count_info = {
.range = sizeof(ui_uniform), .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO,
.buffer = *ui_descriptor_buffer, .descriptorSetCount = 1,
.pDescriptorCounts = &max_font_binding,
}; };
VkWriteDescriptorSet ui_uniform_write = { VkDescriptorSetAllocateInfo allocate_font_samplers = {
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
.dstSet = *ui_descriptor_set, .pSetLayouts = font_sampler_layout,
.dstBinding = 0, .descriptorSetCount = 1,
.dstArrayElement = 0, .descriptorPool = *font_pool,
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, .pNext = &count_info,
.descriptorCount = 1,
.pBufferInfo = &ui_uniform_info,
}; };
vkUpdateDescriptorSets(device, 1, &ui_uniform_write, 0, NULL); VkDescriptorSetAllocateInfo allocate_font_textures = {
return VK_SUCCESS; .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
} .pSetLayouts = font_texture_layout,
.descriptorSetCount = 1,
VkResult init_pipelines(VkDevice device, VmaAllocator allocator, VkExtent2D swapchain_extent, vec2 window_scale, VkRenderPass render_pass, UIContext* context) { .descriptorPool = *font_pool,
.pNext = &count_info,
};
VkResult result; result = vkAllocateDescriptorSets(device, &allocate_font_samplers, font_samplers);
result = create_ui_descriptor_set(device, allocator, swapchain_extent, window_scale, &context->ui_descriptor_layout, &context->ui_descriptor_pool, &context->ui_descriptor_set, &context->ui_descriptor_memory, &context->ui_descriptor_buffer);
if(result != VK_SUCCESS) { if(result != VK_SUCCESS) {
return result; return result;
} }
result = create_ui_colored_rect_pipeline(device, render_pass, context->ui_descriptor_layout, &context->ui_pipeline_rect); result = vkAllocateDescriptorSets(device, &allocate_font_textures, font_textures);
if(result != VK_SUCCESS) { if(result != VK_SUCCESS) {
return result; return result;
} }
result = create_font_descriptor_pools(device, 10, &context->font_pool, &context->font_layout); return VK_SUCCESS;
}
VkResult create_ui_context(VkDevice device, VmaAllocator allocator, VkRenderPass render_pass, UIContextStorage* memory) {
VkResult result;
result = create_ui_descriptor(device, allocator, 10, &memory->font_infos, &memory->font_infos_memory, &memory->font_samplers, &memory->font_textures, &memory->font_samplers_layout, &memory->font_textures_layout, &memory->fonts_pool);
if(result != VK_SUCCESS) { if(result != VK_SUCCESS) {
return result; return result;
} }
result = create_ui_text_pipeline(device, render_pass, context->ui_descriptor_layout, context->font_layout, &context->ui_pipeline_text, &context->ui_compute_text); result = create_ui_rect_pipeline(device, render_pass, memory->font_samplers_layout, memory->font_textures_layout, &memory->rect_pipeline);
if(result != VK_SUCCESS) { if(result != VK_SUCCESS) {
return result; return result;
} }
result = create_ui_text_pipeline(device, render_pass, memory->font_samplers_layout, memory->font_textures_layout, &memory->char_pipeline, &memory->string_pipeline);
if(result != VK_SUCCESS) {
return result;
}
return VK_SUCCESS; return VK_SUCCESS;
} }