diff options
-rw-r--r-- | examples/cube/ex_cube.c | 62 | ||||
-rw-r--r-- | examples/triangle/ex_triangle.c | 2 | ||||
-rw-r--r-- | src/renderer/backends/backend_vulkan.c | 116 | ||||
-rw-r--r-- | src/renderer/backends/backend_vulkan.h | 21 | ||||
-rw-r--r-- | src/renderer/ral.h | 13 | ||||
-rw-r--r-- | src/renderer/ral_types.h | 15 | ||||
-rw-r--r-- | src/renderer/render.h | 2 | ||||
-rw-r--r-- | xmake.lua | 7 |
8 files changed, 199 insertions, 39 deletions
diff --git a/examples/cube/ex_cube.c b/examples/cube/ex_cube.c index 71b7917..699cf55 100644 --- a/examples/cube/ex_cube.c +++ b/examples/cube/ex_cube.c @@ -13,6 +13,14 @@ extern core g_core; +const custom_vertex vertices[] = { + (custom_vertex){ .pos = vec2(-0.5, 0.5), .color = vec3(0.0, 0.0, 1.0) }, + (custom_vertex){ .pos = vec2(0.5, 0.5), .color = vec3(0.0, 1.0, 0.0) }, + (custom_vertex){ .pos = vec2(0.5, -0.5), .color = vec3(1.0, 0.0, 0.0) }, + (custom_vertex){ .pos = vec2(-0.5, -0.5), .color = vec3(1.0, 1.0, 1.0) }, +}; +const u16 indices[] = { 0, 1, 2, 2, 3, 0 }; + // Define the shader data typedef struct mvp_uniforms { mat4 model; @@ -23,33 +31,15 @@ typedef struct mvp_uniforms { shader_data_layout mvp_uniforms_layout(void* data) { mvp_uniforms* d = (mvp_uniforms*)data; bool has_data = data != NULL; - - shader_binding b1 = { - .label = "model", - .type = SHADER_BINDING_BYTES, - .stores_data = has_data, - .data = {.bytes = { .size = sizeof(mat4) }} - }; - shader_binding b2 = { - .label = "view", - .type = SHADER_BINDING_BYTES, - .stores_data = has_data, - .data = {.bytes = { .size = sizeof(mat4) }} - }; - shader_binding b3 = { - .label = "projection", - .type = SHADER_BINDING_BYTES, - .stores_data = has_data, - .data = {.bytes = { .size = sizeof(mat4) }} - }; + + shader_binding b1 = { .label = "mvp_uniforms", + .type = SHADER_BINDING_BYTES, + .stores_data = has_data, + .data = { .bytes = { .size = sizeof(mvp_uniforms) } } }; if (has_data) { - b1.data.bytes.data = &d->model; - b2.data.bytes.data = &d->view; - b3.data.bytes.data = &d->projection; + b1.data.bytes.data = d; } - return (shader_data_layout ){.name = "mvp_uniforms", .bindings = { - b1, b2, b3 - }}; + return (shader_data_layout){ .name = "global_ubo", .bindings = { b1 } }; } int main() { @@ -58,18 +48,7 @@ int main() { DEBUG("render capacity %d", g_core.default_scene.renderables->capacity); - shader_data_layout mvp_layout = mvp_uniforms_layout(NULL); - - mvp_uniforms mvp_data = { - .model = mat4_ident(), - .view = mat4_ident(), - .projection = mat4_ident() - }; - - shader_data mvp_uniforms_data = { - .data = &mvp_data, - .shader_data_get_layout = &mvp_uniforms_layout - }; + shader_data mvp_uniforms_data = { .data = NULL, .shader_data_get_layout = &mvp_uniforms_layout }; gpu_renderpass_desc pass_description = {}; gpu_renderpass* renderpass = gpu_renderpass_create(&pass_description); @@ -84,6 +63,8 @@ int main() { struct graphics_pipeline_desc pipeline_description = { .debug_name = "Basic Pipeline", + .data_layouts = { mvp_uniforms_data }, + .data_layouts_count = 1, .vs = { .debug_name = "Triangle Vertex Shader", .filepath = vert_path, .code = vertex_shader.contents, @@ -121,6 +102,13 @@ int main() { encode_bind_pipeline(enc, PIPELINE_GRAPHICS, gfx_pipeline); encode_set_default_settings(enc); + /* shader_data_layout mvp_layout = mvp_uniforms_layout(NULL); */ + + mvp_uniforms mvp_data = { .model = mat4_ident(), + .view = mat4_ident(), + .projection = mat4_ident() }; + mvp_uniforms_data.data = &mvp_data; + // Record draw calls encode_set_vertex_buffer(enc, triangle_vert_buf); encode_set_index_buffer(enc, triangle_index_buf); diff --git a/examples/triangle/ex_triangle.c b/examples/triangle/ex_triangle.c index c6f0e54..5d8f0cf 100644 --- a/examples/triangle/ex_triangle.c +++ b/examples/triangle/ex_triangle.c @@ -11,6 +11,7 @@ #include "ral.h" #include "ral_types.h" #include "render.h" +#include "render_types.h" extern core g_core; @@ -53,6 +54,7 @@ int main() { }; gpu_pipeline* gfx_pipeline = gpu_graphics_pipeline_create(pipeline_description); + // Load triangle vertex and index data buffer_handle triangle_vert_buf = gpu_buffer_create(sizeof(vertices), CEL_BUFFER_VERTEX, CEL_BUFFER_FLAG_GPU, vertices); diff --git a/src/renderer/backends/backend_vulkan.c b/src/renderer/backends/backend_vulkan.c index dbae96e..c145c1a 100644 --- a/src/renderer/backends/backend_vulkan.c +++ b/src/renderer/backends/backend_vulkan.c @@ -25,8 +25,9 @@ // TEMP #define SCREEN_WIDTH 1000 #define SCREEN_HEIGHT 1000 -#define MAX_FRAMES_IN_FLIGHT 2 #define VULKAN_QUEUES_COUNT 2 +#define MAX_DESCRIPTOR_SETS 100 + const char* queue_names[VULKAN_QUEUES_COUNT] = { "GRAPHICS", "TRANSFER" }; typedef struct vulkan_context { @@ -78,6 +79,7 @@ queue_family_indices find_queue_families(VkPhysicalDevice device); bool create_logical_device(gpu_device* out_device); void create_swapchain_framebuffers(); void create_sync_objects(); +void create_descriptor_pools(); VkShaderModule create_shader_module(str8 spirv); @@ -494,6 +496,83 @@ gpu_pipeline* gpu_graphics_pipeline_create(struct graphics_pipeline_desc descrip dynamic_state.dynamicStateCount = DYNAMIC_STATE_COUNT; dynamic_state.pDynamicStates = dynamic_states; + // Descriptor Set layouts + + VkDescriptorSetLayout* desc_set_layouts = + malloc(description.data_layouts_count * sizeof(VkDescriptorSetLayout)); + pipeline->desc_set_layouts = desc_set_layouts; + pipeline->desc_set_layouts_count = description.data_layouts_count; + pipeline->uniform_pointers = + malloc(description.data_layouts_count * sizeof(desc_set_uniform_buffer)); + + for (u32 i = 0; i < description.data_layouts_count; i++) { + shader_data_layout sdl = description.data_layouts[i].shader_data_get_layout(NULL); + + // NOTE: is using VLA generally ok? + VkDescriptorSetLayoutBinding desc_set_bindings[description.data_layouts_count]; + + // Bindings + for (u32 j = 0; j < sdl.bindings_count; j++) { + desc_set_bindings[j].binding = j; + desc_set_bindings[j].descriptorCount = 1; + switch (sdl.bindings[j].type) { + case SHADER_BINDING_BUFFER: + case SHADER_BINDING_BYTES: + desc_set_bindings[j].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + + u64 buffer_size = sdl.bindings[j].data.bytes.size; + VkDeviceSize uniform_buf_size = buffer_size; + // TODO: Create backing buffer + + VkBuffer buffers[MAX_FRAMES_IN_FLIGHT]; + VkDeviceMemory uniform_buf_memorys[MAX_FRAMES_IN_FLIGHT]; + void* uniform_buf_mem_mappings[MAX_FRAMES_IN_FLIGHT]; + // void* s? + for (size_t frame_i = 0; frame_i < MAX_FRAMES_IN_FLIGHT; frame_i++) { + buffer_handle uniform_buf_handle = + gpu_buffer_create(buffer_size, CEL_BUFFER_UNIFORM, CEL_BUFFER_FLAG_CPU, NULL); + buffers[frame_i] = context.buffers[uniform_buf_handle.raw].handle; + vkMapMemory(context.device->logical_device, uniform_buf_memorys[frame_i], 0, + uniform_buf_size, 0, &uniform_buf_mem_mappings[frame_i]); + } + + desc_set_uniform_buffer uniform_data; + memcpy(&uniform_data.buffers, &buffers, sizeof(buffers)); + memcpy(&uniform_data.uniform_buf_memorys, &uniform_buf_memorys, + sizeof(uniform_buf_memorys)); + memcpy(&uniform_data.uniform_buf_mem_mappings, &uniform_buf_mem_mappings, + sizeof(uniform_buf_mem_mappings)); + uniform_data.size = buffer_size; + + pipeline->uniform_pointers[j] = uniform_data; + + break; + default: + ERROR_EXIT("Unimplemented binding type!! in backend_vulkan"); + } + switch (sdl.bindings[j].vis) { + case VISIBILITY_VERTEX: + desc_set_bindings[j].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; + break; + case VISIBILITY_FRAGMENT: + desc_set_bindings[j].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + break; + case VISIBILITY_COMPUTE: + WARN("Compute is not implemented yet"); + break; + } + } + + VkDescriptorSetLayoutCreateInfo desc_set_layout_info = { + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO + }; + desc_set_layout_info.bindingCount = sdl.bindings_count; + desc_set_layout_info.pBindings = desc_set_bindings; + + VK_CHECK(vkCreateDescriptorSetLayout(context.device->logical_device, &desc_set_layout_info, + context.allocator, &desc_set_layouts[i])); + } + // Layout VkPipelineLayoutCreateInfo pipeline_layout_create_info = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO @@ -652,6 +731,18 @@ gpu_cmd_encoder gpu_cmd_encoder_create() { VK_CHECK(vkAllocateCommandBuffers(context.device->logical_device, &allocate_info, &encoder.cmd_buffer);); + VkDescriptorPoolSize uniform_pool_size; + uniform_pool_size.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + uniform_pool_size.descriptorCount = MAX_FRAMES_IN_FLIGHT * MAX_DESCRIPTOR_SETS; + + VkDescriptorPoolCreateInfo pool_info = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO }; + pool_info.poolSizeCount = 1; + pool_info.pPoolSizes = &uniform_pool_size; + pool_info.maxSets = 10000; + + VK_CHECK(vkCreateDescriptorPool(context.device->logical_device, &pool_info, context.allocator, + &encoder.descriptor_pool)); + return encoder; } void gpu_cmd_encoder_destroy(gpu_cmd_encoder* encoder) { @@ -698,7 +789,27 @@ gpu_cmd_buffer gpu_cmd_encoder_finish(gpu_cmd_encoder* encoder) { // --- Binding void encode_bind_pipeline(gpu_cmd_encoder* encoder, pipeline_kind kind, gpu_pipeline* pipeline) { vkCmdBindPipeline(encoder->cmd_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->handle); + encoder->pipeline = pipeline; +} + +void encode_bind_shader_data(gpu_cmd_encoder* encoder, u32 group, shader_data* data) { + assert(data->data != NULL); + + // Update the local buffer + desc_set_uniform_buffer ubo = encoder->pipeline->uniform_pointers[group]; + memcpy(ubo.uniform_buf_mem_mappings[context.current_frame], data->data, ubo.size); + + VkDescriptorSetAllocateInfo alloc_info = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO }; + alloc_info.descriptorPool =encoder->descriptor_pool; + alloc_info.descriptorSetCount = 1; + alloc_info.pSetLayouts = &encoder->pipeline->desc_set_layouts[group]; + + VkDescriptorSet sets[1]; + VK_CHECK(vkAllocateDescriptorSets(context.device->logical_device, &alloc_info, + sets)); + } + void encode_set_vertex_buffer(gpu_cmd_encoder* encoder, buffer_handle buf) { gpu_buffer buffer = context.buffers[buf.raw]; VkBuffer vbs[] = { buffer.handle }; @@ -970,6 +1081,9 @@ VkShaderModule create_shader_module(str8 spirv) { return shader_module; } + +void create_descriptor_pools() {} + void create_swapchain_framebuffers() { WARN("Recreating framebuffers..."); u32 image_count = context.swapchain->image_count; diff --git a/src/renderer/backends/backend_vulkan.h b/src/renderer/backends/backend_vulkan.h index 0b0a492..7bdf821 100644 --- a/src/renderer/backends/backend_vulkan.h +++ b/src/renderer/backends/backend_vulkan.h @@ -7,6 +7,7 @@ #include "ral.h" // #include "vulkan_helpers.h" +#define MAX_FRAMES_IN_FLIGHT 2 #define GPU_SWAPCHAIN_IMG_COUNT 2 /* @@ -59,9 +60,26 @@ typedef struct gpu_pipeline_layout { VkPipelineLayout handle; } gpu_pipeline_layout; +typedef struct desc_set_uniform_buffer { + VkBuffer buffers[MAX_FRAMES_IN_FLIGHT]; + VkDeviceMemory uniform_buf_memorys[MAX_FRAMES_IN_FLIGHT]; + void* uniform_buf_mem_mappings[MAX_FRAMES_IN_FLIGHT]; + size_t size; +} desc_set_uniform_buffer; + typedef struct gpu_pipeline { VkPipeline handle; VkPipelineLayout layout_handle; + + // Descriptor gubbins + shader_data data_layouts[MAX_SHADER_DATA_LAYOUTS]; + u32 data_layouts_count; + + VkDescriptorSetLayout* desc_set_layouts; + // Based on group, we know which data to load + desc_set_uniform_buffer* uniform_pointers; + u32 desc_set_layouts_count; + } gpu_pipeline; typedef struct gpu_renderpass { @@ -71,6 +89,8 @@ typedef struct gpu_renderpass { typedef struct gpu_cmd_encoder { VkCommandBuffer cmd_buffer; + VkDescriptorPool descriptor_pool; + gpu_pipeline* pipeline; } gpu_cmd_encoder; typedef struct gpu_cmd_buffer { @@ -82,3 +102,4 @@ typedef struct gpu_buffer { VkDeviceMemory memory; u64 size; } gpu_buffer; + diff --git a/src/renderer/ral.h b/src/renderer/ral.h index 38a653d..0df23ea 100644 --- a/src/renderer/ral.h +++ b/src/renderer/ral.h @@ -30,6 +30,8 @@ typedef struct gpu_cmd_encoder gpu_cmd_encoder; // Recording typedef struct gpu_cmd_buffer gpu_cmd_buffer; // Ready for submission typedef struct gpu_buffer gpu_buffer; +#define MAX_SHADER_DATA_LAYOUTS 5 + /** @brief A*/ // typedef struct gpu_bind_group @@ -54,6 +56,17 @@ struct graphics_pipeline_desc { const char* debug_name; shader_desc vs; /** @brief Vertex shader stage */ shader_desc fs; /** @brief Fragment shader stage */ + + /* shader_data_layout data_layouts[MAX_SHADER_DATA_LAYOUTS]; */ + /* u32 data_layouts_count; */ + + // Roughly equivalent to a descriptor set layout each. each layout can have multiple bindings + // examples: + // - uniform buffer reprensenting view projection matrix + // - texture for shadow map ? + shader_data data_layouts[MAX_SHADER_DATA_LAYOUTS]; + u32 data_layouts_count; + // gpu_pipeline_layout* layout; gpu_renderpass* renderpass; diff --git a/src/renderer/ral_types.h b/src/renderer/ral_types.h index 230afc3..e7863a9 100644 --- a/src/renderer/ral_types.h +++ b/src/renderer/ral_types.h @@ -59,6 +59,7 @@ typedef enum gpu_buffer_type { CEL_BUFFER_DEFAULT, // on Vulkan this would be a storage buffer? CEL_BUFFER_VERTEX, CEL_BUFFER_INDEX, + CEL_BUFFER_UNIFORM, CEL_BUFFER_COUNT } gpu_buffer_type; @@ -75,6 +76,7 @@ typedef enum vertex_format { VERTEX_SPRITE, VERTEX_SKINNED, VERTEX_COLOURED_STATIC_3D, + VERTEX_RAW_POS_COLOUR, VERTEX_COUNT } vertex_format; @@ -106,6 +108,11 @@ typedef union vertex { vec3 normal; vec4 colour; } coloured_static_3d; /** @brief vertex format used for debugging */ + + struct { + vec2 position; + vec3 colour; + } raw_pos_colour; } vertex; #ifndef TYPED_VERTEX_ARRAY @@ -136,6 +143,12 @@ typedef enum vertex_attrib_type { ATTR_I32x4, } vertex_attrib_type; +typedef enum shader_visibility { + VISIBILITY_VERTEX = 1 << 0, + VISIBILITY_FRAGMENT = 1 << 1 , + VISIBILITY_COMPUTE = 1 << 2, +} shader_visibility; + typedef enum shader_binding_type { SHADER_BINDING_BUFFER, SHADER_BINDING_TEXTURE, @@ -146,6 +159,7 @@ typedef enum shader_binding_type { typedef struct shader_binding { const char* label; shader_binding_type type; + shader_visibility vis; bool stores_data; /** @brief if this is true then the shader binding has references to live data, if false then its just being used to describe a layout and .data should be zeroed */ @@ -168,6 +182,7 @@ typedef struct shader_binding { typedef struct shader_data_layout { char* name; shader_binding bindings[MAX_LAYOUT_BINDINGS]; + u32 bindings_count; } shader_data_layout; typedef struct shader_data { diff --git a/src/renderer/render.h b/src/renderer/render.h index e6dd8b8..c690e80 100644 --- a/src/renderer/render.h +++ b/src/renderer/render.h @@ -43,4 +43,4 @@ mesh mesh_create(geometry_data* geometry); model_handle model_load(const char* debug_name, const char* filepath); -void geo_set_vertex_colours(geometry_data* geo, vec4 colour);
\ No newline at end of file +void geo_set_vertex_colours(geometry_data* geo, vec4 colour); @@ -157,6 +157,13 @@ target("tri") add_files("examples/triangle/ex_triangle.c") set_rundir("$(projectdir)") +target("cube") + set_kind("binary") + set_group("examples") + add_deps("core_static") + add_files("examples/cube/ex_cube.c") + set_rundir("$(projectdir)") + -- target("std") -- set_kind("binary") -- set_group("examples") |