From f07e87a86e386ba0f65c5a1e962b6a90cfe26ced Mon Sep 17 00:00:00 2001 From: Omniscient <17525998+omnisci3nce@users.noreply.github.com> Date: Sat, 30 Mar 2024 17:42:15 +1100 Subject: uniform with descriptor set. fix image_index being 4 when expoected to be 3 --- assets/shaders/object.frag | 6 + assets/shaders/object.vert | 12 ++ assets/shaders/triangle.frag | 10 -- assets/shaders/triangle.vert | 11 -- examples/main_loop/ex_main_loop.c | 1 + src/renderer/backends/backend_vulkan.c | 293 +++++++++++++++++++++++---------- src/renderer/render_backend.h | 1 + xmake.lua | 10 +- 8 files changed, 233 insertions(+), 111 deletions(-) create mode 100644 assets/shaders/object.frag create mode 100644 assets/shaders/object.vert delete mode 100644 assets/shaders/triangle.frag delete mode 100644 assets/shaders/triangle.vert diff --git a/assets/shaders/object.frag b/assets/shaders/object.frag new file mode 100644 index 0000000..44c1eb3 --- /dev/null +++ b/assets/shaders/object.frag @@ -0,0 +1,6 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(location = 0) out vec4 out_colour; + +void main() { out_colour = vec4(1.0); } \ No newline at end of file diff --git a/assets/shaders/object.vert b/assets/shaders/object.vert new file mode 100644 index 0000000..9aaefed --- /dev/null +++ b/assets/shaders/object.vert @@ -0,0 +1,12 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(location = 0) in vec3 in_position; + +layout(set = 0, binding = 0) uniform global_object_uniform { + mat4 projection; + mat4 view; +} +global_ubo; + +void main() { gl_Position = global_ubo.projection * global_ubo.view * vec4(in_position, 1.0); } \ No newline at end of file diff --git a/assets/shaders/triangle.frag b/assets/shaders/triangle.frag deleted file mode 100644 index 8455d04..0000000 --- a/assets/shaders/triangle.frag +++ /dev/null @@ -1,10 +0,0 @@ -#version 450 -#extension GL_ARB_separate_shader_objects : enable - -layout(location = 0) in vec3 in_position; - -layout(location = 0) out vec4 out_colour; - -void main() { - out_colour = vec4(in_position.r + 0.5, in_position.g + 0.5, in_position.b + 0.5, 1.0); -} \ No newline at end of file diff --git a/assets/shaders/triangle.vert b/assets/shaders/triangle.vert deleted file mode 100644 index e34112d..0000000 --- a/assets/shaders/triangle.vert +++ /dev/null @@ -1,11 +0,0 @@ -#version 450 -#extension GL_ARB_separate_shader_objects : enable - -layout(location = 0) in vec3 in_position; - -layout(location = 0) out vec3 out_position; - -void main() { - gl_Position = vec4(in_position, 1.0); - out_position = in_position; -} \ No newline at end of file diff --git a/examples/main_loop/ex_main_loop.c b/examples/main_loop/ex_main_loop.c index 728290f..9a6f98c 100644 --- a/examples/main_loop/ex_main_loop.c +++ b/examples/main_loop/ex_main_loop.c @@ -1,6 +1,7 @@ #include #include "core.h" +#include "maths.h" #include "render.h" #include "render_backend.h" diff --git a/src/renderer/backends/backend_vulkan.c b/src/renderer/backends/backend_vulkan.c index 3e5137e..759da2f 100644 --- a/src/renderer/backends/backend_vulkan.c +++ b/src/renderer/backends/backend_vulkan.c @@ -133,13 +133,11 @@ typedef struct vulkan_pipeline { VkPipelineLayout layout; } vulkan_pipeline; -#define SHADER_STAGE_COUNT 2 - -typedef struct vulkan_shader { - // vertex, fragment - vulkan_shader_stage stages[SHADER_STAGE_COUNT]; - vulkan_pipeline pipeline; -} vulkan_shader; +typedef struct global_object_uniform { + mat4 projection; // 64 bytes + mat4 view; // 64 bytes + f32 padding[32]; +} global_object_uniform; typedef struct vulkan_buffer { u64 total_size; @@ -151,6 +149,24 @@ typedef struct vulkan_buffer { u32 memory_property_flags; } vulkan_buffer; +#define SHADER_STAGE_COUNT 2 + +typedef struct vulkan_shader { + // vertex, fragment + vulkan_shader_stage stages[SHADER_STAGE_COUNT]; + vulkan_pipeline pipeline; + + // descriptors + VkDescriptorPool descriptor_pool; + VkDescriptorSetLayout descriptor_set_layout; + VkDescriptorSet descriptor_sets[3]; // one for each in-flight frame + + vulkan_buffer global_uniforms_buffer; + + // Data that's global for all objects drawn + global_object_uniform global_ubo; +} vulkan_shader; + typedef struct vulkan_context { VkInstance instance; VkAllocationCallbacks* allocator; @@ -366,6 +382,69 @@ void vulkan_pipeline_bind(vulkan_command_buffer* command_buffer, VkPipelineBindP vkCmdBindPipeline(command_buffer->handle, bind_point, pipeline->handle); } +void vulkan_buffer_bind(vulkan_context* context, vulkan_buffer* buffer, u64 offset) { + vkBindBufferMemory(context->device.logical_device, buffer->handle, buffer->memory, offset); +} + +bool vulkan_buffer_create(vulkan_context* context, u64 size, VkBufferUsageFlagBits usage, + u32 memory_property_flags, bool bind_on_create, + vulkan_buffer* out_buffer) { + memset(out_buffer, 0, sizeof(vulkan_buffer)); + out_buffer->total_size = size; + out_buffer->usage = usage; + out_buffer->memory_property_flags = memory_property_flags; + + VkBufferCreateInfo buffer_info = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; + buffer_info.size = size; + buffer_info.usage = usage; + buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + + vkCreateBuffer(context->device.logical_device, &buffer_info, context->allocator, + &out_buffer->handle); + + VkMemoryRequirements requirements; + vkGetBufferMemoryRequirements(context->device.logical_device, out_buffer->handle, &requirements); + out_buffer->memory_index = + find_memory_index(context, requirements.memoryTypeBits, out_buffer->memory_property_flags); + + // Allocate + VkMemoryAllocateInfo allocate_info = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO }; + allocate_info.allocationSize = requirements.size; + allocate_info.memoryTypeIndex = (u32)out_buffer->memory_index; + + vkAllocateMemory(context->device.logical_device, &allocate_info, context->allocator, + &out_buffer->memory); + + if (bind_on_create) { + vulkan_buffer_bind(context, out_buffer, 0); + } + + return true; +} + +// lock and unlock? + +void* vulkan_buffer_lock_memory(vulkan_context* context, vulkan_buffer* buffer, u64 offset, + u64 size, u32 flags) { + void* data; + vkMapMemory(context->device.logical_device, buffer->memory, offset, size, flags, &data); + return data; +} +void* vulkan_buffer_unlock_memory(vulkan_context* context, vulkan_buffer* buffer) { + vkUnmapMemory(context->device.logical_device, buffer->memory); +} + +void vulkan_buffer_load_data(vulkan_context* context, vulkan_buffer* buffer, u64 offset, u64 size, + u32 flags, const void* data) { + void* data_ptr = 0; + VK_CHECK( + vkMapMemory(context->device.logical_device, buffer->memory, offset, size, flags, &data_ptr)); + memcpy(data_ptr, data, size); + vkUnmapMemory(context->device.logical_device, buffer->memory); +} + +// TODO: destroy + bool create_shader_module(vulkan_context* context, const char* filename, const char* type_str, VkShaderStageFlagBits flag, u32 stage_index, vulkan_shader_stage* shader_stages) { @@ -398,8 +477,8 @@ bool create_shader_module(vulkan_context* context, const char* filename, const c bool vulkan_object_shader_create(vulkan_context* context, vulkan_shader* out_shader) { char stage_type_strs[SHADER_STAGE_COUNT][5] = { "vert", "frag" }; - char stage_filenames[SHADER_STAGE_COUNT][256] = { "build/linux/x86_64/debug/triangle.vert.spv", - "build/linux/x86_64/debug/triangle.frag.spv" }; + char stage_filenames[SHADER_STAGE_COUNT][256] = { "build/linux/x86_64/debug/object.vert.spv", + "build/linux/x86_64/debug/object.frag.spv" }; VkShaderStageFlagBits stage_types[SHADER_STAGE_COUNT] = { VK_SHADER_STAGE_VERTEX_BIT, VK_SHADER_STAGE_FRAGMENT_BIT }; for (u8 i = 0; i < SHADER_STAGE_COUNT; i++) { @@ -408,7 +487,34 @@ bool vulkan_object_shader_create(vulkan_context* context, vulkan_shader* out_sha out_shader->stages); } - // TODO: descriptors + // descriptors + VkDescriptorSetLayoutBinding global_ubo_layout_binding; + global_ubo_layout_binding.binding = 0; + global_ubo_layout_binding.descriptorCount = 1; + global_ubo_layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + global_ubo_layout_binding.pImmutableSamplers = 0; + global_ubo_layout_binding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; + + VkDescriptorSetLayoutCreateInfo global_layout_info = { + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO + }; + global_layout_info.bindingCount = 1; + global_layout_info.pBindings = &global_ubo_layout_binding; + + VK_CHECK(vkCreateDescriptorSetLayout(context->device.logical_device, &global_layout_info, + context->allocator, &out_shader->descriptor_set_layout)); + + VkDescriptorPoolSize global_pool_size; + global_pool_size.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + global_pool_size.descriptorCount = 3; + + VkDescriptorPoolCreateInfo pool_info = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO }; + pool_info.poolSizeCount = 1; + pool_info.pPoolSizes = &global_pool_size; + pool_info.maxSets = 3; + + VK_CHECK(vkCreateDescriptorPool(context->device.logical_device, &pool_info, context->allocator, + &out_shader->descriptor_pool)); // Pipeline creation VkViewport viewport; @@ -441,7 +547,8 @@ bool vulkan_object_shader_create(vulkan_context* context, vulkan_shader* out_sha offset += sizes[i]; } - // TODO: Descriptor set + // Descriptor set layouts + VkDescriptorSetLayout layouts[1] = { out_shader->descriptor_set_layout }; // Stages VkPipelineShaderStageCreateInfo stage_create_infos[SHADER_STAGE_COUNT]; @@ -451,11 +558,35 @@ bool vulkan_object_shader_create(vulkan_context* context, vulkan_shader* out_sha stage_create_infos[i] = out_shader->stages[i].stage_create_info; } - vulkan_graphics_pipeline_create(context, &context->main_renderpass, attribute_count, - attribute_descs, 0, 0, SHADER_STAGE_COUNT, stage_create_infos, - viewport, scissor, false, &out_shader->pipeline); + vulkan_graphics_pipeline_create( + context, &context->main_renderpass, attribute_count, attribute_descs, 1, layouts, + SHADER_STAGE_COUNT, stage_create_infos, viewport, scissor, false, &out_shader->pipeline); INFO("Graphics pipeline created!"); + // Uniform buffer + if (!vulkan_buffer_create(context, sizeof(global_object_uniform), + VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | + VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, + true, &out_shader->global_uniforms_buffer)) { + ERROR("Couldnt create uniforms buffer"); + return false; + } + + VkDescriptorSetLayout global_layouts[3] = { + out_shader->descriptor_set_layout, + out_shader->descriptor_set_layout, + out_shader->descriptor_set_layout, + }; + + VkDescriptorSetAllocateInfo alloc_info = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO }; + alloc_info.descriptorPool = out_shader->descriptor_pool; + alloc_info.descriptorSetCount = 3; + alloc_info.pSetLayouts = global_layouts; + VK_CHECK(vkAllocateDescriptorSets(context->device.logical_device, &alloc_info, + out_shader->descriptor_sets)); + return true; } void vulkan_object_shader_destroy(vulkan_context* context, vulkan_shader* shader) {} @@ -464,6 +595,36 @@ void vulkan_object_shader_use(vulkan_context* context, vulkan_shader* shader) { vulkan_pipeline_bind(&context->gfx_command_buffers->data[image_index], VK_PIPELINE_BIND_POINT_GRAPHICS, &shader->pipeline); } +void vulkan_object_shader_update_global_state(vulkan_context* context, vulkan_shader* shader) { + u32 image_index = context->image_index; + VkCommandBuffer cmd_buffer = context->gfx_command_buffers->data[image_index].handle; + VkDescriptorSet global_descriptors = shader->descriptor_sets[image_index]; + + vkCmdBindDescriptorSets(cmd_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, shader->pipeline.layout, 0, + 1, &global_descriptors, 0, 0); + + u32 range = sizeof(global_object_uniform); + u64 offset = 0; + + // copy data to buffer + vulkan_buffer_load_data(context, &shader->global_uniforms_buffer, offset, range, 0, + &shader->global_ubo); + + VkDescriptorBufferInfo buffer_info; + buffer_info.buffer = shader->global_uniforms_buffer.handle; + buffer_info.offset = offset; + buffer_info.range = range; + + VkWriteDescriptorSet descriptor_write = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET }; + descriptor_write.dstSet = shader->descriptor_sets[image_index]; + descriptor_write.dstBinding = 0; + descriptor_write.dstArrayElement = 0; + descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + descriptor_write.descriptorCount = 1; + descriptor_write.pBufferInfo = &buffer_info; + + vkUpdateDescriptorSets(context->device.logical_device, 1, &descriptor_write, 0, 0); +} bool select_physical_device(vulkan_context* ctx) { u32 physical_device_count = 0; @@ -734,69 +895,6 @@ void vulkan_image_create(vulkan_context* context, VkImageType image_type, u32 wi // TODO: vulkan_image_destroy -void vulkan_buffer_bind(vulkan_context* context, vulkan_buffer* buffer, u64 offset) { - vkBindBufferMemory(context->device.logical_device, buffer->handle, buffer->memory, offset); -} - -bool vulkan_buffer_create(vulkan_context* context, u64 size, VkBufferUsageFlagBits usage, - u32 memory_property_flags, bool bind_on_create, - vulkan_buffer* out_buffer) { - memset(out_buffer, 0, sizeof(vulkan_buffer)); - out_buffer->total_size = size; - out_buffer->usage = usage; - out_buffer->memory_property_flags = memory_property_flags; - - VkBufferCreateInfo buffer_info = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; - buffer_info.size = size; - buffer_info.usage = usage; - buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - - vkCreateBuffer(context->device.logical_device, &buffer_info, context->allocator, - &out_buffer->handle); - - VkMemoryRequirements requirements; - vkGetBufferMemoryRequirements(context->device.logical_device, out_buffer->handle, &requirements); - out_buffer->memory_index = - find_memory_index(context, requirements.memoryTypeBits, out_buffer->memory_property_flags); - - // Allocate - VkMemoryAllocateInfo allocate_info = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO }; - allocate_info.allocationSize = requirements.size; - allocate_info.memoryTypeIndex = (u32)out_buffer->memory_index; - - vkAllocateMemory(context->device.logical_device, &allocate_info, context->allocator, - &out_buffer->memory); - - if (bind_on_create) { - vulkan_buffer_bind(context, out_buffer, 0); - } - - return true; -} - -// lock and unlock? - -void* vulkan_buffer_lock_memory(vulkan_context* context, vulkan_buffer* buffer, u64 offset, - u64 size, u32 flags) { - void* data; - vkMapMemory(context->device.logical_device, buffer->memory, offset, size, flags, &data); - return data; -} -void* vulkan_buffer_unlock_memory(vulkan_context* context, vulkan_buffer* buffer) { - vkUnmapMemory(context->device.logical_device, buffer->memory); -} - -void vulkan_buffer_load_data(vulkan_context* context, vulkan_buffer* buffer, u64 offset, u64 size, - u32 flags, const void* data) { - void* data_ptr = 0; - VK_CHECK( - vkMapMemory(context->device.logical_device, buffer->memory, offset, size, flags, &data_ptr)); - memcpy(data_ptr, data, size); - vkUnmapMemory(context->device.logical_device, buffer->memory); -} - -// TODO: destroy - void vulkan_framebuffer_create(vulkan_context* context, vulkan_renderpass* renderpass, u32 width, u32 height, u32 attachment_count, VkImageView* attachments, vulkan_framebuffer* out_framebuffer) { @@ -935,7 +1033,7 @@ void vulkan_swapchain_create(vulkan_context* context, u32 width, u32 height, // TODO: requery swapchain support - u32 image_count = context->device.swapchain_support.capabilities.minImageCount + 1; + u32 image_count = context->device.swapchain_support.capabilities.minImageCount; VkSwapchainCreateInfoKHR swapchain_create_info = { VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR }; swapchain_create_info.surface = context->surface; @@ -1537,16 +1635,16 @@ void backend_begin_frame(renderer* ren, f32 delta_time) { context.swapchain.framebuffers->data[context.image_index].handle); // TODO: temp test code - vulkan_object_shader_use(&context, &context.object_shader); + // vulkan_object_shader_use(&context, &context.object_shader); - VkDeviceSize offsets[1] = { 0 }; - vkCmdBindVertexBuffers(command_buffer->handle, 0, 1, &context.object_vertex_buffer.handle, - (VkDeviceSize*)offsets); + // VkDeviceSize offsets[1] = { 0 }; + // vkCmdBindVertexBuffers(command_buffer->handle, 0, 1, &context.object_vertex_buffer.handle, + // (VkDeviceSize*)offsets); - vkCmdBindIndexBuffer(command_buffer->handle, context.object_index_buffer.handle, 0, - VK_INDEX_TYPE_UINT32); + // vkCmdBindIndexBuffer(command_buffer->handle, context.object_index_buffer.handle, 0, + // VK_INDEX_TYPE_UINT32); - vkCmdDrawIndexed(command_buffer->handle, 6, 1, 0, 0, 0); + // vkCmdDrawIndexed(command_buffer->handle, 6, 1, 0, 0, 0); // --- End temp test code } @@ -1591,9 +1689,34 @@ void backend_end_frame(renderer* ren, f32 delta_time) { void gfx_backend_draw_frame(renderer* ren) { backend_begin_frame(ren, 16.0); + gfx_backend_update_global_state(mat4_ident(), mat4_ident(), VEC3_ZERO, vec4(1.0, 1.0, 1.0, 1.0), + 0); + backend_end_frame(ren, 16.0); } +void gfx_backend_update_global_state(mat4 projection, mat4 view, vec3 view_pos, vec4 ambient_colour, + i32 mode) { + vulkan_command_buffer* cmd_buffer = &context.gfx_command_buffers->data[context.image_index]; + vulkan_object_shader_use(&context, &context.object_shader); + + vulkan_object_shader_update_global_state(&context, &context.object_shader); + context.object_shader.global_ubo.projection = projection; + context.object_shader.global_ubo.view = view; + // TODO: other UBO properties + + // vulkan_object_shader_use(&context, &context.object_shader); + + VkDeviceSize offsets[1] = { 0 }; + vkCmdBindVertexBuffers(cmd_buffer->handle, 0, 1, &context.object_vertex_buffer.handle, + (VkDeviceSize*)offsets); + + vkCmdBindIndexBuffer(cmd_buffer->handle, context.object_index_buffer.handle, 0, + VK_INDEX_TYPE_UINT32); + + vkCmdDrawIndexed(cmd_buffer->handle, 6, 1, 0, 0, 0); +} + void clear_screen(vec3 colour) {} void bind_texture(shader s, texture* tex, u32 slot) {} diff --git a/src/renderer/render_backend.h b/src/renderer/render_backend.h index 041f412..69d14d8 100644 --- a/src/renderer/render_backend.h +++ b/src/renderer/render_backend.h @@ -13,6 +13,7 @@ bool gfx_backend_init(renderer* ren); void gfx_backend_shutdown(renderer* ren); void gfx_backend_draw_frame(renderer* ren); +void gfx_backend_update_global_state(mat4 projection, mat4 view, vec3 view_pos, vec4 ambient_colour, i32 mode); void clear_screen(vec3 colour); diff --git a/xmake.lua b/xmake.lua index 3005713..cb6d98a 100644 --- a/xmake.lua +++ b/xmake.lua @@ -69,7 +69,7 @@ rule("compile_glsl_vert_shaders") on_buildcmd_file(function (target, batchcmds, sourcefile, opt) local targetfile = path.join(target:targetdir(), path.basename(sourcefile) .. ".vert.spv") - print("Compiling shader: %s", sourcefile) + print("Compiling shader: %s to %s", sourcefile, targetfile) batchcmds:vrunv('glslc', {sourcefile, "-o", targetfile}) batchcmds:add_depfiles(sourcefile) end) @@ -78,7 +78,7 @@ rule("compile_glsl_frag_shaders") on_buildcmd_file(function (target, batchcmds, sourcefile, opt) local targetfile = path.join(target:targetdir(), path.basename(sourcefile) .. ".frag.spv") - print("Compiling shader: %s", sourcefile) + print("Compiling shader: %s to %s", sourcefile, targetfile) batchcmds:vrunv('glslc', {sourcefile, "-o", targetfile}) batchcmds:add_depfiles(sourcefile) end) @@ -104,11 +104,11 @@ target("core_config") add_includedirs("src/std/", {public = true}) add_includedirs("src/std/containers", {public = true}) add_includedirs("src/systems/", {public = true}) + add_files("src/empty.c") -- for some reason we need this on Mac so it doesnt call 'ar' with no files and error add_rules("compile_glsl_vert_shaders") add_rules("compile_glsl_frag_shaders") - add_files("src/empty.c") -- for some reason we need this on Mac so it doesnt call 'ar' with no files and error - add_files("assets/shaders/triangle.vert") - add_files("assets/shaders/triangle.frag") + add_files("assets/shaders/object.vert") + add_files("assets/shaders/object.frag") -- add_files("assets/shaders/*.frag") set_default(false) -- prevents standalone building of this target -- cgit v1.2.3-70-g09d2