diff --git a/client/Makefile b/client/Makefile index 1670b4d..39d8c70 100644 --- a/client/Makefile +++ b/client/Makefile @@ -10,11 +10,13 @@ SOURCES = src/main.c src/render.c src/vma.cpp src/pipeline.c src/command.c src/s OBJECTS = $(addsuffix .o, $(basename $(SOURCES))) VERT_SPV = $(addsuffix .vert.spv, $(basename $(wildcard shader_src/*.vert))) FRAG_SPV = $(addsuffix .frag.spv, $(basename $(wildcard shader_src/*.frag))) +COMP_SPV = $(addsuffix .comp.spv, $(basename $(wildcard shader_src/*.comp))) +SPV_FILES = $(VERT_SPV) $(FRAG_SPV) $(COMP_SPV) export MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS=1 .PHONY: all -all: roleplay $(VERT_SPV) $(FRAG_SPV) +all: roleplay $(SPV_FILES) roleplay: $(OBJECTS) $(CPP) $(CFLAGS) $(LDFLAGS) -o $@ $^ @@ -28,8 +30,7 @@ roleplay: $(OBJECTS) .PHONY: clean clean_compdb clean: - rm -f $(FRAG_SPV) - rm -f $(VERT_SPV) + rm -f $(SPV_FILES) rm -f $(OBJECTS) rm -f roleplay rm -rf roleplay.dSYM @@ -38,18 +39,20 @@ clean_compdb: rm -rf .compdb rm compile_commands.json -run: roleplay $(VERT_SPV) $(FRAG_SPV) +run: roleplay $(SPV_FILES) ./roleplay roleplay.dSYM: roleplay $(DSYM) roleplay -debug: roleplay roleplay.dSYM $(VERT_SPV) $(FRAG_SPV) +debug: roleplay roleplay.dSYM $(SPV_FILES) $(GDB) roleplay - %.vert.spv: %.vert glslangValidator -V -o $@ $< %.frag.spv: %.frag glslangValidator -V -o $@ $< + +%.comp.spv: %.comp + glslangValidator -V -o $@ $< diff --git a/client/include/pipeline.h b/client/include/pipeline.h index 9093173..3fc34c0 100644 --- a/client/include/pipeline.h +++ b/client/include/pipeline.h @@ -34,6 +34,12 @@ typedef struct TextStruct { uint32_t offset; } Text; +typedef struct TextPointersStruct { + VkDeviceAddress strings; + VkDeviceAddress codes; + VkDeviceAddress characters; +} TextPointers; + typedef struct CharStruct { vec3 pos; vec4 color; diff --git a/client/include/render.h b/client/include/render.h index d9d1bbf..d3cf54e 100644 --- a/client/include/render.h +++ b/client/include/render.h @@ -71,8 +71,7 @@ typedef struct RenderContextStruct { VkCommandPool graphics_pool; VkCommandPool transfer_pool; - VkRenderPass world_render_pass; - VkRenderPass ui_render_pass; + VkRenderPass render_pass; VkCommandBuffer* swapchain_command_buffers; diff --git a/client/shader_src/ui_text.comp b/client/shader_src/ui_text.comp new file mode 100644 index 0000000..5578177 --- /dev/null +++ b/client/shader_src/ui_text.comp @@ -0,0 +1,64 @@ +#version 450 +#extension GL_EXT_buffer_reference : require + +struct Symbol { + uint x; + uint top; + uint width; +}; + +struct Character { + vec3 pos; + vec4 color; + float size; + uint code; +}; + +struct String { + vec3 pos; + vec4 color; + float size; + uint offset; + uint length; +}; + +layout(buffer_reference, std430) readonly buffer SymbolList{ + Symbol symbols[]; +}; + +layout(buffer_reference, std430) writeonly buffer CharacterList{ + Character characters[]; +}; + +layout(buffer_reference, std430) readonly buffer Characters{ + uint codes[]; +}; + +layout(buffer_reference, std430) readonly buffer Strings{ + String strings[]; +}; + +layout(set = 0, binding = 0) uniform UIUniform { + mat4 screen; +} ubo; + +layout(set = 1, binding = 0) uniform Font { + uint num_symbols; + uint width; + uint height; + uint space_width; + SymbolList symbol_list; +} font; + +layout(buffer_reference, std430) readonly buffer Pointers { + Strings strings; + Characters codes; + CharacterList characters; +}; + +layout(std430, push_constant) uniform Push { + Pointers pointers; +} push; + +void main() { +} diff --git a/client/shader_src/ui_text.vert b/client/shader_src/ui_text.vert index 4b604f6..218a930 100644 --- a/client/shader_src/ui_text.vert +++ b/client/shader_src/ui_text.vert @@ -26,7 +26,7 @@ layout(set = 0, binding = 0) uniform UIUniform { mat4 screen; } ubo; -layout(set = 1, binding = 0) uniform FontUniform { +layout(set = 1, binding = 0) uniform Font { uint num_symbols; uint width; uint height; @@ -34,8 +34,13 @@ layout(set = 1, binding = 0) uniform FontUniform { SymbolList symbol_list; } font; -layout(std430, push_constant) uniform Push { +layout(buffer_reference, std430) readonly buffer Pointers { + uint padding[4]; CharacterList characters; +}; + +layout(std430, push_constant) uniform Push { + Pointers pointers; } push; layout(location = 0) in vec2 inVertexPosition; @@ -44,7 +49,7 @@ layout(location = 0) out vec4 fragColor; layout(location = 1) out vec2 fragUV; void main() { - Character character = push.characters.characters[gl_InstanceIndex]; + Character character = push.pointers.characters.characters[gl_InstanceIndex]; Symbol symbol = font.symbol_list.symbols[character.code]; float fragU = (inVertexPosition.x*symbol.width + symbol.x) / font.width; diff --git a/client/src/main.c b/client/src/main.c index 5d0b939..44b5c5c 100644 --- a/client/src/main.c +++ b/client/src/main.c @@ -106,7 +106,7 @@ VkResult render_thread(GLFWwindow* window, RenderContext* render_context) { 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); + result = init_pipelines(render_context->device, render_context->allocator, render_context->swapchain_extent, render_context->render_pass, render_context->transfer_queue, render_context->transfer_pool, &ui_context); if(result != VK_SUCCESS) { return result; } @@ -197,10 +197,42 @@ VkResult render_thread(GLFWwindow* window, RenderContext* render_context) { vmaUnmapMemory(render_context->allocator, text_memory); + VkBuffer text_pointer_buffer; + VmaAllocation text_pointer_memory; + + VkBufferCreateInfo text_pointer_buffer_info = { + .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, + .usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, + .size = sizeof(TextPointers), + .sharingMode = VK_SHARING_MODE_EXCLUSIVE, + }; + + VmaAllocationCreateInfo text_pointer_memory_info = { + .usage = VMA_MEMORY_USAGE_CPU_TO_GPU, + }; + + result = vmaCreateBuffer(render_context->allocator, &text_pointer_buffer_info, &text_pointer_memory_info, &text_pointer_buffer, &text_pointer_memory, NULL); + if(result != VK_SUCCESS) { + return result; + } + + TextPointers* pointers; + + result = vmaMapMemory(render_context->allocator, text_pointer_memory, (void**)&pointers); + if(result != VK_SUCCESS) { + return result; + } VkBufferDeviceAddressInfo test_address_info = { .sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO, .buffer = text_buffer, }; + pointers->characters = vkGetBufferDeviceAddress(render_context->device, &test_address_info); + vmaUnmapMemory(render_context->allocator, text_pointer_memory); + + VkBufferDeviceAddressInfo pointers_address_info = { + .sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO, + .buffer = text_pointer_buffer, + }; UILayer test_layer = { .colored_rects = colored_rect_buffer, @@ -209,7 +241,7 @@ VkResult render_thread(GLFWwindow* window, RenderContext* render_context) { .font = test_font_descriptor, .text_count = 2, .texts = text_buffer, - .texts_address = vkGetBufferDeviceAddress(render_context->device, &test_address_info), + .texts_address = vkGetBufferDeviceAddress(render_context->device, &pointers_address_info), }; while(glfwWindowShouldClose(window) == 0) { diff --git a/client/src/pipeline.c b/client/src/pipeline.c index 27053c6..0844b2e 100644 --- a/client/src/pipeline.c +++ b/client/src/pipeline.c @@ -286,6 +286,46 @@ VkPipelineVertexInputStateCreateInfo input_info = { } VkResult create_ui_text_pipeline(VkDevice device, VkRenderPass render_pass, VkDescriptorSetLayout ui_descriptor_layout, VkDescriptorSetLayout font_layout, GraphicsPipeline* pipeline, ComputePipeline* compute) { + VkResult result; + VkShaderModule compute_shader = load_shader_file("shader_src/ui_text.comp.spv", device); + if(compute_shader == VK_NULL_HANDLE) { + return VK_ERROR_UNKNOWN; + } + + VkPipelineShaderStageCreateInfo compute_shader_stage = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + .stage = VK_SHADER_STAGE_COMPUTE_BIT, + .pName = "main", + .module = compute_shader, + }; + + VkPushConstantRange push_constant = { + .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT | VK_SHADER_STAGE_VERTEX_BIT, + .size = 8, + }; + + VkPipelineLayoutCreateInfo compute_layout_info = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, + .pushConstantRangeCount = 1, + .pPushConstantRanges = &push_constant, + }; + + result = vkCreatePipelineLayout(device, &compute_layout_info, NULL, &compute->layout); + if(result != VK_SUCCESS) { + return result; + } + + VkComputePipelineCreateInfo compute_pipeline_info = { + .sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, + .layout = compute->layout, + .stage = compute_shader_stage, + }; + + result = vkCreateComputePipelines(device, VK_NULL_HANDLE, 1, &compute_pipeline_info, NULL, &compute->pipeline); + if(result != VK_SUCCESS) { + return result; + } + VkShaderModule vert_shader = load_shader_file("shader_src/ui_text.vert.spv", device); if(vert_shader == VK_NULL_HANDLE) { return VK_ERROR_UNKNOWN; @@ -339,11 +379,6 @@ VkResult create_ui_text_pipeline(VkDevice device, VkRenderPass render_pass, VkDe VkDescriptorSetLayout all_layouts[] = {ui_descriptor_layout, font_layout}; - VkPushConstantRange push_constant = { - .size = 8, - .stageFlags = VK_SHADER_STAGE_VERTEX_BIT, - }; - VkPipelineLayoutCreateInfo layout_info = { .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, .setLayoutCount = sizeof(all_layouts)/sizeof(VkDescriptorSetLayout), @@ -358,7 +393,7 @@ VkResult create_ui_text_pipeline(VkDevice device, VkRenderPass render_pass, VkDe .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); + result = create_ui_pipeline(device, render_pass, shader_stages, sizeof(shader_stages)/sizeof(VkPipelineShaderStageCreateInfo), input_info, layout_info, input_assembly_info, pipeline); if(result != VK_SUCCESS) { return result; } diff --git a/client/src/render.c b/client/src/render.c index a24da3e..ef5c9bd 100644 --- a/client/src/render.c +++ b/client/src/render.c @@ -27,6 +27,10 @@ const char * instance_extensions[] = { uint32_t instance_extension_count = sizeof(instance_extensions) / sizeof(const char *); const char * device_extensions[] = { +#ifdef __APPLE__ + "VK_KHR_portability_subset", +#endif + VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME, VK_KHR_SWAPCHAIN_EXTENSION_NAME, VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME, }; @@ -125,8 +129,6 @@ VkResult create_instance(VkInstance* instance) { .flags = VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR, }; - - VkResult result = vkCreateInstance(&instance_info, 0, instance); if(result != VK_SUCCESS) { return result; @@ -575,17 +577,17 @@ VkResult find_depth_format(VkPhysicalDevice physical_device, VkImageTiling tilin return VK_ERROR_UNKNOWN; } -VkResult create_render_pass(VkDevice device, VkSurfaceFormatKHR format, VkFormat depth_format, VkRenderPass* render_pass, VkImageLayout initial_layout, VkImageLayout final_layout, VkAttachmentLoadOp color_load_op) { +VkResult create_render_pass(VkDevice device, VkSurfaceFormatKHR format, VkFormat depth_format, VkRenderPass* render_pass) { VkAttachmentDescription attachments[] = { { .format = format.format, .samples = VK_SAMPLE_COUNT_1_BIT, - .loadOp = color_load_op, + .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, .storeOp = VK_ATTACHMENT_STORE_OP_STORE, .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, .stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE, - .initialLayout = initial_layout, - .finalLayout = final_layout, + .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, + .finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, }, { .format = depth_format, @@ -619,6 +621,12 @@ VkResult create_render_pass(VkDevice device, VkSurfaceFormatKHR format, VkFormat .pColorAttachments = color_attachment_refs, .pDepthStencilAttachment = &depth_attachment_ref, }, + { + .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS, + .colorAttachmentCount = sizeof(color_attachment_refs)/sizeof(VkAttachmentReference), + .pColorAttachments = color_attachment_refs, + .pDepthStencilAttachment = &depth_attachment_ref, + }, }; // This basically says "make sure nothing else is writing to the depth_stencil or the color attachment during the pipeline @@ -631,6 +639,15 @@ VkResult create_render_pass(VkDevice device, VkSurfaceFormatKHR format, VkFormat .dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT, .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, .dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT, + }, + { + .srcSubpass = 0, + .dstSubpass = 1, + .srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT, + .srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, + .dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT, + .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, + .dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT, } }; @@ -931,12 +948,7 @@ VkResult init_vulkan(GLFWwindow* window, RenderContext* context) { return result; } - result = create_render_pass(context->device, context->swapchain_format, context->depth_format, &context->world_render_pass, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, VK_ATTACHMENT_LOAD_OP_CLEAR); - if(result != VK_SUCCESS) { - return result; - } - - result = create_render_pass(context->device, context->swapchain_format, context->depth_format, &context->ui_render_pass, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, VK_ATTACHMENT_LOAD_OP_LOAD); + result = create_render_pass(context->device, context->swapchain_format, context->depth_format, &context->render_pass); if(result != VK_SUCCESS) { return result; } @@ -946,7 +958,7 @@ VkResult init_vulkan(GLFWwindow* window, RenderContext* context) { return result; } - result = create_swapchain_framebuffers(context->device, context->swapchain_image_count, context->swapchain_image_views, context->depth_image_view, context->world_render_pass, context->swapchain_extent, &context->swapchain_framebuffers); + result = create_swapchain_framebuffers(context->device, context->swapchain_image_count, context->swapchain_image_views, context->depth_image_view, context->render_pass, context->swapchain_extent, &context->swapchain_framebuffers); if(result != VK_SUCCESS) { return result; } @@ -1005,30 +1017,20 @@ VkResult draw_frame(RenderContext* context, UIContext* ui_context, UILayer* ui_l VkClearValue clear_values[2] = {{.color={{0.0f, 0.0f, 0.0f, 1.0f}}}, {.depthStencil={1.0f, 0.0f}}}; VkDeviceSize offset = 0; - // World Render Pass - VkRenderPassBeginInfo world_render_pass_begin = { + VkRenderPassBeginInfo render_pass_begin = { .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, - .renderPass = context->world_render_pass, + .renderPass = context->render_pass, .framebuffer = context->swapchain_framebuffers[image_index], .renderArea.offset = {0, 0}, .renderArea.extent = context->swapchain_extent, .clearValueCount = 2, .pClearValues = clear_values, }; - vkCmdBeginRenderPass(command_buffer, &world_render_pass_begin, VK_SUBPASS_CONTENTS_INLINE); - vkCmdEndRenderPass(command_buffer); + vkCmdBeginRenderPass(command_buffer, &render_pass_begin, VK_SUBPASS_CONTENTS_INLINE); + // World subpass - // UI Render Pass - VkRenderPassBeginInfo ui_render_pass_begin = { - .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, - .renderPass = context->ui_render_pass, - .framebuffer = context->swapchain_framebuffers[image_index], - .renderArea.offset = {0, 0}, - .renderArea.extent = context->swapchain_extent, - .clearValueCount = 2, - .pClearValues = clear_values, - }; - vkCmdBeginRenderPass(command_buffer, &ui_render_pass_begin, VK_SUBPASS_CONTENTS_INLINE); + vkCmdNextSubpass(command_buffer, VK_SUBPASS_CONTENTS_INLINE); + // UI subpass // Draw UI colored rects //////////////////////////////// vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, ui_context->ui_pipeline_rect.pipeline); @@ -1044,12 +1046,15 @@ VkResult draw_frame(RenderContext* context, UIContext* ui_context, UILayer* ui_l } ///////////////////////////////////////////////////////// // Draw UI text ///////////////////////////////////////// + vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, ui_context->ui_compute_text.pipeline); 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++) { if(ui_layers[i].text_count > 0) { + // Bind Font Descriptor vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, ui_context->ui_pipeline_text.layout, 1, 1, &ui_layers[i].font.set, 0, NULL); - vkCmdPushConstants(command_buffer, ui_context->ui_pipeline_text.layout, VK_SHADER_STAGE_VERTEX_BIT, 0, 8, &ui_layers[i].texts_address); + // Push pointers + vkCmdPushConstants(command_buffer, ui_context->ui_pipeline_text.layout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_COMPUTE_BIT, 0, 8, &ui_layers[i].texts_address); vkCmdDrawIndexed(command_buffer, 6, ui_layers[i].text_count, 0, 0, 0); } }