From 5e382c2095bc4891e2952ba87609f2796f2248ad Mon Sep 17 00:00:00 2001 From: omnisci3nce Date: Sun, 28 Apr 2024 11:02:21 +1000 Subject: start porting vulkan code to new RAL --- examples/triangle/ex_triangle.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 examples/triangle/ex_triangle.c (limited to 'examples/triangle') diff --git a/examples/triangle/ex_triangle.c b/examples/triangle/ex_triangle.c new file mode 100644 index 0000000..4e31313 --- /dev/null +++ b/examples/triangle/ex_triangle.c @@ -0,0 +1,34 @@ +#include + +#include "camera.h" +#include "core.h" +#include "maths.h" +#include "render.h" + +int main() { + core* core = core_bringup(); + + camera camera = camera_create(vec3_create(0, 0, 20), VEC3_NEG_Z, VEC3_Y, deg_to_rad(45.0)); + + // Main loop + while (!glfwWindowShouldClose(core->renderer.window)) { + input_update(&core->input); + // threadpool_process_results(&core->threadpool, 1); + + render_frame_begin(&core->renderer); + + static f32 x = 0.0; + x += 0.01; + mat4 model = mat4_translation(vec3(x, 0, 0)); + + gfx_backend_draw_frame(&core->renderer, &camera, model, NULL); + + // insert work here + + render_frame_end(&core->renderer); + glfwSwapBuffers(core->renderer.window); + glfwPollEvents(); + } + + return 0; +} -- cgit v1.2.3-70-g09d2 From 24e2e5f0b8675d498c188f221ea0a309d5911206 Mon Sep 17 00:00:00 2001 From: omnisci3nce Date: Sun, 28 Apr 2024 21:52:10 +1000 Subject: start on pipeline layout, pipeline, renderpass --- examples/triangle/ex_triangle.c | 39 +++++++-- src/renderer/backends/backend_dx11.h | 3 +- src/renderer/backends/backend_vulkan.c | 142 ++++++++++++++++++++++++++++++--- src/renderer/backends/backend_vulkan.h | 11 ++- src/renderer/backends/vulkan_helpers.h | 7 +- src/renderer/bind_group_layouts.h | 30 +++++++ src/renderer/ral.h | 22 ++++- src/renderer/ral_types.h | 6 ++ src/renderer/render.h | 1 + src/renderer/render_types.h | 5 +- src/renderer/renderpasses.h | 31 +++++++ 11 files changed, 274 insertions(+), 23 deletions(-) create mode 100644 src/renderer/bind_group_layouts.h create mode 100644 src/renderer/renderpasses.h (limited to 'examples/triangle') diff --git a/examples/triangle/ex_triangle.c b/examples/triangle/ex_triangle.c index 4e31313..9b993c1 100644 --- a/examples/triangle/ex_triangle.c +++ b/examples/triangle/ex_triangle.c @@ -1,27 +1,52 @@ #include +#include "backend_vulkan.h" #include "camera.h" #include "core.h" +#include "file.h" +#include "log.h" #include "maths.h" +#include "mem.h" +#include "ral.h" #include "render.h" +// Example setting up a renderer + int main() { core* core = core_bringup(); + arena scratch = arena_create(malloc(1024 * 1024), 1024 * 1024); + + gpu_renderpass_desc pass_description = {}; + gpu_renderpass* renderpass = gpu_renderpass_create(&pass_description); - camera camera = camera_create(vec3_create(0, 0, 20), VEC3_NEG_Z, VEC3_Y, deg_to_rad(45.0)); + str8_opt vertex_shader = str8_from_file(&scratch, str8lit("assets/shaders/triangle.vert")); + str8_opt fragment_shader = str8_from_file(&scratch, str8lit("assets/shaders/triangle.frag")); + if (!vertex_shader.has_value || !fragment_shader.has_value) { + ERROR_EXIT("Failed to load shaders from disk") + } + + struct graphics_pipeline_desc pipeline_description = { + .debug_name = "Basic Pipeline", + .vs = { .debug_name = "Triangle Vertex Shader", + .filepath = str8lit("assets/shaders/triangle.vert"), + .glsl = vertex_shader.contents }, + .fs = { .debug_name = "Triangle Fragment Shader", + .filepath = str8lit("assets/shaders/triangle.frag"), + .glsl = fragment_shader.contents }, + .renderpass = renderpass, + .wireframe = false, + .depth_test = false + }; + gpu_pipeline* gfx_pipeline = gpu_graphics_pipeline_create(pipeline_description); // Main loop - while (!glfwWindowShouldClose(core->renderer.window)) { + while (!should_exit(core)) { input_update(&core->input); - // threadpool_process_results(&core->threadpool, 1); render_frame_begin(&core->renderer); - static f32 x = 0.0; + static f64 x = 0.0; x += 0.01; - mat4 model = mat4_translation(vec3(x, 0, 0)); - - gfx_backend_draw_frame(&core->renderer, &camera, model, NULL); // insert work here diff --git a/src/renderer/backends/backend_dx11.h b/src/renderer/backends/backend_dx11.h index e076659..8e3a513 100644 --- a/src/renderer/backends/backend_dx11.h +++ b/src/renderer/backends/backend_dx11.h @@ -6,8 +6,7 @@ #define GPU_SWAPCHAIN_IMG_COUNT 2 -typedef struct gpu_swapchain { -} gpu_swapchain; +// typedef struct gpu_swapchain gpu_swapchain; typedef struct gpu_device { // VkPhysicalDevice physical_device; diff --git a/src/renderer/backends/backend_vulkan.c b/src/renderer/backends/backend_vulkan.c index 2502dd2..ae857a0 100644 --- a/src/renderer/backends/backend_vulkan.c +++ b/src/renderer/backends/backend_vulkan.c @@ -141,7 +141,7 @@ bool gpu_swapchain_create(gpu_swapchain* out_swapchain) { VkSwapchainCreateInfoKHR swapchain_create_info = { VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR }; - // swapchain_create_info.minImageCount = + // swapchain_create_info.minImageCount = VK_CHECK(vkCreateSwapchainKHR(context.device->logical_device, &swapchain_create_info, context.allocator, &out_swapchain->handle)); @@ -149,6 +149,11 @@ bool gpu_swapchain_create(gpu_swapchain* out_swapchain) { } gpu_pipeline* gpu_graphics_pipeline_create(struct graphics_pipeline_desc description) { + // Allocate + gpu_pipeline_layout* layout = malloc(sizeof(gpu_pipeline_layout)); + gpu_pipeline* pipeline = malloc(sizeof(gpu_pipeline)); + + // Viewport VkViewport viewport = { .x = 0, .y = 0, .width = (f32)context.screen_width, @@ -158,11 +163,6 @@ gpu_pipeline* gpu_graphics_pipeline_create(struct graphics_pipeline_desc descrip VkRect2D scissor = { .offset = { .x = 0, .y = 0 }, .extent = { .width = context.screen_width, .height = context.screen_height } }; - - // TODO: Attributes - - // TODO: layouts - VkPipelineViewportStateCreateInfo viewport_state = { VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO }; @@ -170,12 +170,136 @@ gpu_pipeline* gpu_graphics_pipeline_create(struct graphics_pipeline_desc descrip viewport_state.pViewports = &viewport; viewport_state.scissorCount = 1; viewport_state.pScissors = &scissor; + + // Rasterizer + VkPipelineRasterizationStateCreateInfo rasterizer_create_info = { + VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO + }; + rasterizer_create_info.depthClampEnable = VK_FALSE; + rasterizer_create_info.rasterizerDiscardEnable = VK_FALSE; + rasterizer_create_info.polygonMode = + description.wireframe ? VK_POLYGON_MODE_LINE : VK_POLYGON_MODE_FILL; + rasterizer_create_info.lineWidth = 1.0f; + rasterizer_create_info.cullMode = VK_CULL_MODE_BACK_BIT; + rasterizer_create_info.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; + rasterizer_create_info.depthBiasEnable = VK_FALSE; + rasterizer_create_info.depthBiasConstantFactor = 0.0; + rasterizer_create_info.depthBiasClamp = 0.0; + rasterizer_create_info.depthBiasSlopeFactor = 0.0; + + // Multisampling + VkPipelineMultisampleStateCreateInfo ms_create_info = { + VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO + }; + ms_create_info.sampleShadingEnable = VK_FALSE; + ms_create_info.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; + ms_create_info.minSampleShading = 1.0; + ms_create_info.pSampleMask = 0; + ms_create_info.alphaToCoverageEnable = VK_FALSE; + ms_create_info.alphaToOneEnable = VK_FALSE; + + // Depth and stencil testing + VkPipelineDepthStencilStateCreateInfo depth_stencil = { + VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO + }; + depth_stencil.depthTestEnable = description.depth_test ? VK_TRUE : VK_FALSE; + depth_stencil.depthWriteEnable = description.depth_test ? VK_TRUE : VK_FALSE; + depth_stencil.depthCompareOp = VK_COMPARE_OP_LESS; + depth_stencil.depthBoundsTestEnable = VK_FALSE; + depth_stencil.stencilTestEnable = VK_FALSE; + depth_stencil.pNext = 0; + + // TODO: Blending + + // TODO: Vertex Input + + // TODO: Attributes + + // TODO: layouts + VkPipelineLayoutCreateInfo pipeline_layout_create_info = { + VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO + }; + pipeline_layout_create_info.setLayoutCount = 0; + pipeline_layout_create_info.pSetLayouts = NULL; + pipeline_layout_create_info.pushConstantRangeCount = 0; + pipeline_layout_create_info.pPushConstantRanges = NULL; + VK_CHECK(vkCreatePipelineLayout(context.device->logical_device, &pipeline_layout_create_info, + context.allocator, &layout->handle)); + pipeline->layout_handle = layout->handle; // keep a copy of the layout on the pipeline object + + VkGraphicsPipelineCreateInfo pipeline_create_info = { + VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO + }; + // pipeline_create_info.stageCount = stage_count; + // pipeline_create_info.pStages = stages; + // pipeline_create_info.pVertexInputState = &vertex_input_info; + // pipeline_create_info.pInputAssemblyState = &input_assembly; + + // pipeline_create_info.pViewportState = &viewport_state; + // pipeline_create_info.pRasterizationState = &rasterizer_create_info; + // pipeline_create_info.pMultisampleState = &ms_create_info; + // pipeline_create_info.pDepthStencilState = &depth_stencil; + // pipeline_create_info.pColorBlendState = &color_blend; + // pipeline_create_info.pDynamicState = &dynamic_state; + // pipeline_create_info.pTessellationState = 0; + + // pipeline_create_info.layout = out_pipeline->layout; + + // pipeline_create_info.renderPass = renderpass->handle; + // pipeline_create_info.subpass = 0; + // pipeline_create_info.basePipelineHandle = VK_NULL_HANDLE; + // pipeline_create_info.basePipelineIndex = -1; + + VkResult result = + vkCreateGraphicsPipelines(context.device->logical_device, VK_NULL_HANDLE, 1, + &pipeline_create_info, context.allocator, &pipeline->handle); + if (result != VK_SUCCESS) { + FATAL("graphics pipeline creation failed. its fked mate"); + ERROR_EXIT("Doomed"); + } + + return pipeline; } -gpu_renderpass* gpu_renderpass_create() { - // Allocate it +gpu_renderpass* gpu_renderpass_create(const gpu_renderpass_desc* description) { + // TEMP: allocate with malloc. in the future we will have a pool allocator on the context + gpu_renderpass* renderpass = malloc(sizeof(gpu_renderpass)); + + // Colour attachment + VkAttachmentDescription color_attachment; + // color_attachment.format = context->swapchain.image_format.format; + color_attachment.samples = VK_SAMPLE_COUNT_1_BIT; + color_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + color_attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + color_attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + color_attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + color_attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + color_attachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + color_attachment.flags = 0; + + // attachment_descriptions[0] = color_attachment; + + VkAttachmentReference color_attachment_reference; + color_attachment_reference.attachment = 0; + color_attachment_reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + // subpass.colorAttachmentCount = 1; + // subpass.pColorAttachments = &color_attachment_reference; + + // TODO: Depth attachment + + // main subpass + VkSubpassDescription subpass = { 0 }; + subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpass.colorAttachmentCount = 1; + subpass.pColorAttachments = &color_attachment_reference; + // sets everything up - // return pointer to it + + // Finally, create the RenderPass + VkRenderPassCreateInfo render_pass_create_info = { VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO }; + + return renderpass; } void encode_set_pipeline(gpu_cmd_encoder* encoder, gpu_pipeline* pipeline) { diff --git a/src/renderer/backends/backend_vulkan.h b/src/renderer/backends/backend_vulkan.h index dfe6a0f..9802311 100644 --- a/src/renderer/backends/backend_vulkan.h +++ b/src/renderer/backends/backend_vulkan.h @@ -4,6 +4,7 @@ #include #include "defines.h" +#include "ral.h" #define GPU_SWAPCHAIN_IMG_COUNT 2 @@ -16,6 +17,7 @@ Conventions: typedef struct gpu_swapchain { VkSwapchainKHR handle; } gpu_swapchain; + typedef struct gpu_device { // In Vulkan we store both physical and logical device here VkPhysicalDevice physical_device; @@ -25,11 +27,18 @@ typedef struct gpu_device { VkPhysicalDeviceMemoryProperties memory; VkCommandPool pool; } gpu_device; + +typedef struct gpu_pipeline_layout { + VkPipelineLayout handle; +} gpu_pipeline_layout; + typedef struct gpu_pipeline { + VkPipeline handle; + VkPipelineLayout layout_handle; } gpu_pipeline; typedef struct gpu_renderpass { - VkRenderPass vk_handle; + VkRenderPass handle; VkFramebuffer framebuffers[GPU_SWAPCHAIN_IMG_COUNT]; } gpu_renderpass; diff --git a/src/renderer/backends/vulkan_helpers.h b/src/renderer/backends/vulkan_helpers.h index 3465aed..4bd02f1 100644 --- a/src/renderer/backends/vulkan_helpers.h +++ b/src/renderer/backends/vulkan_helpers.h @@ -21,7 +21,12 @@ static void plat_get_required_extension_names(cstr_darray* extensions) { // TODO(omni): port to using internal assert functions #define VK_CHECK(vulkan_expr) \ - { assert(vulkan_expr == VK_SUCCESS); } + do { \ + VkResult res = vulkan_expr; \ + if (res != VK_SUCCESS) { \ + ERROR_EXIT("Vulkan error: %u", res); \ + } \ + } while (0) // TODO: typedef struct vk_debugger {} vk_debugger; diff --git a/src/renderer/bind_group_layouts.h b/src/renderer/bind_group_layouts.h new file mode 100644 index 0000000..d163fab --- /dev/null +++ b/src/renderer/bind_group_layouts.h @@ -0,0 +1,30 @@ +/** + * @file bind_group_layouts.h + * @author your name (you@domain.com) + * @brief Common bindgroups (descriptor set layouts) + * @version 0.1 + * @date 2024-04-28 + * + * @copyright Copyright (c) 2024 + * + */ +#pragma once +#include "defines.h" +#include "maths_types.h" + +// Three major sets + +// 1. Scene / Global +typedef struct bg_globals { + f32 total_time; + f32 delta_time; + mat4 view; + mat4 projection; +} bg_globals; + +// 2. Material (once per object) + +// 3. Per draw call +typedef struct bg_model { + mat4 model; +} bg_model; diff --git a/src/renderer/ral.h b/src/renderer/ral.h index 6c165c9..8e49dbe 100644 --- a/src/renderer/ral.h +++ b/src/renderer/ral.h @@ -23,11 +23,20 @@ struct GLFWwindow; // Forward declare structs typedef struct gpu_swapchain gpu_swapchain; typedef struct gpu_device gpu_device; +typedef struct gpu_pipeline_layout gpu_pipeline_layout; typedef struct gpu_pipeline gpu_pipeline; typedef struct gpu_renderpass gpu_renderpass; typedef struct gpu_cmd_encoder gpu_cmd_encoder; // Recording typedef struct gpu_cmd_buffer gpu_cmd_buffer; // Ready for submission +/** @brief A*/ +// typedef struct gpu_bind_group + +// Pools +typedef struct gpu_backend_pools { + // pools for each gpu structure +} gpu_backend_pools; + typedef enum pipeline_kind { PIPELINE_GRAPHICS, PIPELINE_COMPUTE, @@ -40,10 +49,20 @@ typedef struct shader_desc { } shader_desc; struct graphics_pipeline_desc { + const char* debug_name; shader_desc vs; /** @brief Vertex shader stage */ shader_desc fs; /** @brief Fragment shader stage */ + // gpu_pipeline_layout* layout; + gpu_renderpass* renderpass; + + bool wireframe; + bool depth_test; }; +typedef struct gpu_renderpass_desc { + +} gpu_renderpass_desc; + // --- Lifecycle functions bool gpu_backend_init(const char* window_name, struct GLFWwindow* window); @@ -52,7 +71,7 @@ void gpu_backend_shutdown(); bool gpu_device_create(gpu_device* out_device); void gpu_device_destroy(); -gpu_renderpass* gpu_renderpass_create(); +gpu_renderpass* gpu_renderpass_create(const gpu_renderpass_desc* description); void gpu_renderpass_destroy(gpu_renderpass* pass); gpu_pipeline* gpu_graphics_pipeline_create(struct graphics_pipeline_desc description); @@ -75,6 +94,7 @@ void encode_set_pipeline(gpu_cmd_encoder* encoder, gpu_pipeline* pipeline); void buffer_upload_bytes(buffer_handle gpu_buf, bytebuffer cpu_buf, u64 offset, u64 size); // render pass +void encode_bind_pipeline(gpu_cmd_encoder* encoder, pipeline_kind kind, gpu_pipeline* pipeline); void encode_set_vertex_buffer(gpu_cmd_encoder* encoder, buffer_handle buf); void encode_set_index_buffer(gpu_cmd_encoder* encoder, buffer_handle buf); void encode_set_bind_group(); // TODO diff --git a/src/renderer/ral_types.h b/src/renderer/ral_types.h index 5f41b55..0b1c02e 100644 --- a/src/renderer/ral_types.h +++ b/src/renderer/ral_types.h @@ -99,6 +99,12 @@ KITC_DECL_TYPED_ARRAY(u32) #define TYPED_VERTEX_ARRAY #endif +typedef enum gpu_cull_mode { + CULL_BACK_FACE, + CULL_FRONT_FACE, + CULL_COUNT +} gpu_cull_mode; + // ? How to tie together materials and shaders // Three registers diff --git a/src/renderer/render.h b/src/renderer/render.h index a5a5928..a9370e0 100644 --- a/src/renderer/render.h +++ b/src/renderer/render.h @@ -17,6 +17,7 @@ bool renderer_init(renderer* ren); void renderer_shutdown(renderer* ren); void render_frame_begin(renderer* ren); +void render_frame_update_globals(renderer* ren); void render_frame_end(renderer* ren); void render_frame_draw(renderer* ren); diff --git a/src/renderer/render_types.h b/src/renderer/render_types.h index 6ef2461..4866ef4 100644 --- a/src/renderer/render_types.h +++ b/src/renderer/render_types.h @@ -13,7 +13,8 @@ #include "ral_types.h" #include "ral.h" #if defined(CEL_PLATFORM_WINDOWS) -#include "backend_dx11.h" +// #include "backend_dx11.h" +#include "backend_vulkan.h" #endif struct GLFWwindow; @@ -36,7 +37,7 @@ typedef struct renderer { typedef struct geometry_data { vertex_format format; - vertex_darray* vertices; // TODO: make it not a pointe + vertex_darray* vertices; // TODO: make it not a pointer bool has_indices; u32_darray indices; vec3 colour; /** Optional: set vertex colours */ diff --git a/src/renderer/renderpasses.h b/src/renderer/renderpasses.h new file mode 100644 index 0000000..67badaa --- /dev/null +++ b/src/renderer/renderpasses.h @@ -0,0 +1,31 @@ +/** + * @file renderpasses.h + * @author your name (you@domain.com) + * @brief Built-in renderpasses to the engine + * @version 0.1 + * @date 2024-04-28 + * + * @copyright Copyright (c) 2024 + * + */ +#pragma once +#include "maths_types.h" +#include "ral.h" +#include "render.h" + +// Shadowmap pass +// Blinn-phong pass +// Unlit pass +// Debug visualisations pass + +typedef struct render_entity { + model* model; + transform tf; +} render_entity; + +// Don't need to pass in *anything*. +gpu_renderpass* renderpass_blinn_phong_create(); +void renderpass_blinn_phong_execute(gpu_renderpass* pass, render_entity* entities, size_t entity_count); + +gpu_renderpass* renderpass_shadows_create(); +void renderpass_shadows_execute(gpu_renderpass* pass, render_entity* entities, size_t entity_count); \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 1c27e3c4d42b79e38feb56974f66a2caf3f5a53d Mon Sep 17 00:00:00 2001 From: Omniscient <17525998+omnisci3nce@users.noreply.github.com> Date: Sat, 4 May 2024 22:28:07 +1000 Subject: set up most of basic pipeline state --- examples/triangle/ex_triangle.c | 16 ++-- src/renderer/backends/backend_vulkan.c | 163 +++++++++++++++++++++++++-------- src/renderer/backends/vulkan_helpers.h | 2 +- src/renderer/ral.h | 3 +- 4 files changed, 140 insertions(+), 44 deletions(-) (limited to 'examples/triangle') diff --git a/examples/triangle/ex_triangle.c b/examples/triangle/ex_triangle.c index 9b993c1..bdb2d70 100644 --- a/examples/triangle/ex_triangle.c +++ b/examples/triangle/ex_triangle.c @@ -19,8 +19,10 @@ int main() { gpu_renderpass_desc pass_description = {}; gpu_renderpass* renderpass = gpu_renderpass_create(&pass_description); - str8_opt vertex_shader = str8_from_file(&scratch, str8lit("assets/shaders/triangle.vert")); - str8_opt fragment_shader = str8_from_file(&scratch, str8lit("assets/shaders/triangle.frag")); + str8 vert_path = str8lit("build/linux/x86_64/debug/triangle.vert.spv"); + str8 frag_path = str8lit("build/linux/x86_64/debug/triangle.frag.spv"); + str8_opt vertex_shader = str8_from_file(&scratch, vert_path); + str8_opt fragment_shader = str8_from_file(&scratch, frag_path); if (!vertex_shader.has_value || !fragment_shader.has_value) { ERROR_EXIT("Failed to load shaders from disk") } @@ -28,11 +30,13 @@ int main() { struct graphics_pipeline_desc pipeline_description = { .debug_name = "Basic Pipeline", .vs = { .debug_name = "Triangle Vertex Shader", - .filepath = str8lit("assets/shaders/triangle.vert"), - .glsl = vertex_shader.contents }, + .filepath = vert_path, + .code = vertex_shader.contents, + .is_spirv = true }, .fs = { .debug_name = "Triangle Fragment Shader", - .filepath = str8lit("assets/shaders/triangle.frag"), - .glsl = fragment_shader.contents }, + .filepath = frag_path, + .code = fragment_shader.contents, + .is_spirv = true }, .renderpass = renderpass, .wireframe = false, .depth_test = false diff --git a/src/renderer/backends/backend_vulkan.c b/src/renderer/backends/backend_vulkan.c index 45bb0e7..5a01303 100644 --- a/src/renderer/backends/backend_vulkan.c +++ b/src/renderer/backends/backend_vulkan.c @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -8,9 +9,11 @@ #include "backend_vulkan.h" #include "maths_types.h" #include "mem.h" +#include "str.h" #include "vulkan_helpers.h" #include "defines.h" +#include "file.h" #include "log.h" #include "ral.h" #include "utils.h" @@ -51,6 +54,8 @@ queue_family_indices find_queue_families(VkPhysicalDevice device); bool create_logical_device(gpu_device* out_device); +VkShaderModule create_shader_module(str8 spirv); + /** @brief Helper function for creating array of all extensions we want */ cstr_darray* get_all_extensions(); @@ -192,6 +197,8 @@ bool gpu_device_create(gpu_device* out_device) { } bool gpu_swapchain_create(gpu_swapchain* out_swapchain) { + context.swapchain = out_swapchain; + out_swapchain->swapchain_arena = arena_create(malloc(1024), 1024); vulkan_swapchain_support_info swapchain_support = context.swapchain_support; @@ -262,7 +269,7 @@ bool gpu_swapchain_create(gpu_swapchain* out_swapchain) { void gpu_swapchain_destroy(gpu_swapchain* swapchain) { arena_free_storage(&swapchain->swapchain_arena); - vkDestroySwapchainKHR(context.device, swapchain->handle, context.allocator); + vkDestroySwapchainKHR(context.device->logical_device, swapchain->handle, context.allocator); } gpu_pipeline* gpu_graphics_pipeline_create(struct graphics_pipeline_desc description) { @@ -270,16 +277,55 @@ gpu_pipeline* gpu_graphics_pipeline_create(struct graphics_pipeline_desc descrip gpu_pipeline_layout* layout = malloc(sizeof(gpu_pipeline_layout)); gpu_pipeline* pipeline = malloc(sizeof(gpu_pipeline)); + // Shaders + VkShaderModule vertex_shader = create_shader_module(description.vs.code); + VkShaderModule fragment_shader = create_shader_module(description.fs.code); + + // Vertex + VkPipelineShaderStageCreateInfo vert_shader_stage_info = { + VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO + }; + vert_shader_stage_info.stage = VK_SHADER_STAGE_VERTEX_BIT; + vert_shader_stage_info.module = vertex_shader; + vert_shader_stage_info.pName = "main"; + // Fragment + VkPipelineShaderStageCreateInfo frag_shader_stage_info = { + VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO + }; + frag_shader_stage_info.stage = VK_SHADER_STAGE_FRAGMENT_BIT; + frag_shader_stage_info.module = fragment_shader; + frag_shader_stage_info.pName = "main"; + + VkPipelineShaderStageCreateInfo shader_stages[2] = { vert_shader_stage_info, + frag_shader_stage_info }; + + // Vertex Input + + // TODO: Attributes + + VkPipelineVertexInputStateCreateInfo vertex_input_info = { + VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO + }; + vertex_input_info.vertexBindingDescriptionCount = 0; + vertex_input_info.pVertexBindingDescriptions = NULL; + vertex_input_info.vertexAttributeDescriptionCount = 0; + vertex_input_info.pVertexAttributeDescriptions = NULL; + + // Input Assembly + VkPipelineInputAssemblyStateCreateInfo input_assembly = { + VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO + }; + input_assembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + input_assembly.primitiveRestartEnable = VK_FALSE; + // Viewport VkViewport viewport = { .x = 0, .y = 0, - .width = (f32)context.screen_width, - .height = (f32)context.screen_height, + .width = (f32)context.swapchain->extent.width, + .height = (f32)context.swapchain->extent.height, .minDepth = 0.0, .maxDepth = 1.0 }; - VkRect2D scissor = { .offset = { .x = 0, .y = 0 }, - .extent = { .width = context.screen_width, - .height = context.screen_height } }; + VkRect2D scissor = { .offset = { .x = 0, .y = 0 }, .extent = context.swapchain->extent }; VkPipelineViewportStateCreateInfo viewport_state = { VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO }; @@ -315,24 +361,52 @@ gpu_pipeline* gpu_graphics_pipeline_create(struct graphics_pipeline_desc descrip ms_create_info.alphaToCoverageEnable = VK_FALSE; ms_create_info.alphaToOneEnable = VK_FALSE; - // Depth and stencil testing - VkPipelineDepthStencilStateCreateInfo depth_stencil = { - VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO + // TODO: Depth and stencil testing + // VkPipelineDepthStencilStateCreateInfo depth_stencil = { + // VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO + // }; + // depth_stencil.depthTestEnable = description.depth_test ? VK_TRUE : VK_FALSE; + // depth_stencil.depthWriteEnable = description.depth_test ? VK_TRUE : VK_FALSE; + // depth_stencil.depthCompareOp = VK_COMPARE_OP_LESS; + // depth_stencil.depthBoundsTestEnable = VK_FALSE; + // depth_stencil.stencilTestEnable = VK_FALSE; + // depth_stencil.pNext = 0; + + // Blending + VkPipelineColorBlendAttachmentState color_blend_attachment_state; + color_blend_attachment_state.blendEnable = VK_TRUE; + color_blend_attachment_state.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; + color_blend_attachment_state.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + color_blend_attachment_state.colorBlendOp = VK_BLEND_OP_ADD; + color_blend_attachment_state.srcAlphaBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; + color_blend_attachment_state.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + color_blend_attachment_state.alphaBlendOp = VK_BLEND_OP_ADD; + color_blend_attachment_state.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | + VK_COLOR_COMPONENT_G_BIT | + VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + + VkPipelineColorBlendStateCreateInfo color_blend = { + VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO + }; + color_blend.logicOpEnable = VK_FALSE; + color_blend.logicOp = VK_LOGIC_OP_COPY; + color_blend.attachmentCount = 1; + color_blend.pAttachments = &color_blend_attachment_state; + +// Dynamic state +#define DYNAMIC_STATE_COUNT 2 + VkDynamicState dynamic_states[DYNAMIC_STATE_COUNT] = { + VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_SCISSOR, }; - depth_stencil.depthTestEnable = description.depth_test ? VK_TRUE : VK_FALSE; - depth_stencil.depthWriteEnable = description.depth_test ? VK_TRUE : VK_FALSE; - depth_stencil.depthCompareOp = VK_COMPARE_OP_LESS; - depth_stencil.depthBoundsTestEnable = VK_FALSE; - depth_stencil.stencilTestEnable = VK_FALSE; - depth_stencil.pNext = 0; - - // TODO: Blending - - // TODO: Vertex Input - // TODO: Attributes + VkPipelineDynamicStateCreateInfo dynamic_state = { + VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO + }; + dynamic_state.dynamicStateCount = DYNAMIC_STATE_COUNT; + dynamic_state.pDynamicStates = dynamic_states; - // TODO: layouts + // Layout VkPipelineLayoutCreateInfo pipeline_layout_create_info = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO }; @@ -347,25 +421,26 @@ gpu_pipeline* gpu_graphics_pipeline_create(struct graphics_pipeline_desc descrip VkGraphicsPipelineCreateInfo pipeline_create_info = { VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO }; - // pipeline_create_info.stageCount = stage_count; - // pipeline_create_info.pStages = stages; - // pipeline_create_info.pVertexInputState = &vertex_input_info; - // pipeline_create_info.pInputAssemblyState = &input_assembly; - // pipeline_create_info.pViewportState = &viewport_state; - // pipeline_create_info.pRasterizationState = &rasterizer_create_info; - // pipeline_create_info.pMultisampleState = &ms_create_info; - // pipeline_create_info.pDepthStencilState = &depth_stencil; - // pipeline_create_info.pColorBlendState = &color_blend; - // pipeline_create_info.pDynamicState = &dynamic_state; - // pipeline_create_info.pTessellationState = 0; + pipeline_create_info.stageCount = 2; + pipeline_create_info.pStages = shader_stages; + pipeline_create_info.pVertexInputState = &vertex_input_info; + pipeline_create_info.pInputAssemblyState = &input_assembly; - // pipeline_create_info.layout = out_pipeline->layout; + pipeline_create_info.pViewportState = &viewport_state; + pipeline_create_info.pRasterizationState = &rasterizer_create_info; + pipeline_create_info.pMultisampleState = &ms_create_info; + pipeline_create_info.pDepthStencilState = NULL; // &depth_stencil; + pipeline_create_info.pColorBlendState = &color_blend; + pipeline_create_info.pDynamicState = &dynamic_state; + pipeline_create_info.pTessellationState = 0; + + pipeline_create_info.layout = layout->handle; // pipeline_create_info.renderPass = renderpass->handle; - // pipeline_create_info.subpass = 0; - // pipeline_create_info.basePipelineHandle = VK_NULL_HANDLE; - // pipeline_create_info.basePipelineIndex = -1; + pipeline_create_info.subpass = 0; + pipeline_create_info.basePipelineHandle = VK_NULL_HANDLE; + pipeline_create_info.basePipelineIndex = -1; VkResult result = vkCreateGraphicsPipelines(context.device->logical_device, VK_NULL_HANDLE, 1, @@ -375,6 +450,10 @@ gpu_pipeline* gpu_graphics_pipeline_create(struct graphics_pipeline_desc descrip ERROR_EXIT("Doomed"); } + // once the pipeline has been created we can destroy these + vkDestroyShaderModule(context.device->logical_device, vertex_shader, context.allocator); + vkDestroyShaderModule(context.device->logical_device, fragment_shader, context.allocator); + return pipeline; } @@ -576,4 +655,16 @@ bool create_logical_device(gpu_device* out_device) { &context.device->present_queue); return true; +} + +VkShaderModule create_shader_module(str8 spirv) { + VkShaderModuleCreateInfo create_info = { VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO }; + create_info.codeSize = spirv.len; + create_info.pCode = (uint32_t*)spirv.buf; + + VkShaderModule shader_module; + VK_CHECK(vkCreateShaderModule(context.device->logical_device, &create_info, context.allocator, + &shader_module)); + + return shader_module; } \ No newline at end of file diff --git a/src/renderer/backends/vulkan_helpers.h b/src/renderer/backends/vulkan_helpers.h index 55d8846..aa43c62 100644 --- a/src/renderer/backends/vulkan_helpers.h +++ b/src/renderer/backends/vulkan_helpers.h @@ -81,7 +81,7 @@ static void vulkan_device_query_swapchain_support(VkPhysicalDevice device, VkSur static VkSurfaceFormatKHR choose_swapchain_format( vulkan_swapchain_support_info* swapchain_support) { - assert(swapchain_support->format_count > 0); + assert(swapchain_support->format_count > 0); // find a format for (u32 i = 0; i < swapchain_support->format_count; i++) { VkSurfaceFormatKHR format = swapchain_support->formats[i]; diff --git a/src/renderer/ral.h b/src/renderer/ral.h index f202e51..15c66ef 100644 --- a/src/renderer/ral.h +++ b/src/renderer/ral.h @@ -45,7 +45,8 @@ typedef enum pipeline_kind { typedef struct shader_desc { const char* debug_name; str8 filepath; // where it came from - str8 glsl; // contents + str8 code; // Either GLSL or SPIRV bytecode + bool is_spirv; } shader_desc; struct graphics_pipeline_desc { -- cgit v1.2.3-70-g09d2 From 945f84d0a1201b60dc470331d38ff6c1853a1149 Mon Sep 17 00:00:00 2001 From: Omniscient <17525998+omnisci3nce@users.noreply.github.com> Date: Tue, 7 May 2024 10:51:37 +1000 Subject: framebuffers, and create commandbuffer --- examples/triangle/ex_triangle.c | 2 + src/renderer/backends/backend_vulkan.c | 92 ++++++++++++++++++++++++++++++++-- src/renderer/backends/backend_vulkan.h | 3 ++ src/renderer/ral.h | 5 +- 4 files changed, 97 insertions(+), 5 deletions(-) (limited to 'examples/triangle') diff --git a/examples/triangle/ex_triangle.c b/examples/triangle/ex_triangle.c index bdb2d70..1b6fc96 100644 --- a/examples/triangle/ex_triangle.c +++ b/examples/triangle/ex_triangle.c @@ -59,5 +59,7 @@ int main() { glfwPollEvents(); } + gpu_backend_shutdown(); + return 0; } diff --git a/src/renderer/backends/backend_vulkan.c b/src/renderer/backends/backend_vulkan.c index 5a01303..1b192dd 100644 --- a/src/renderer/backends/backend_vulkan.c +++ b/src/renderer/backends/backend_vulkan.c @@ -34,6 +34,11 @@ typedef struct vulkan_context { arena temp_arena; gpu_device* device; gpu_swapchain* swapchain; + u32 framebuffer_count; + VkFramebuffer* + swapchain_framebuffers; // TODO: Move this data into the swapchain as its own struct + + gpu_cmd_encoder main_cmd_buf; u32 screen_width; u32 screen_height; @@ -171,9 +176,11 @@ bool gpu_backend_init(const char* window_name, GLFWwindow* window) { } void gpu_backend_shutdown() { - arena_free_storage(&context.temp_arena); + gpu_swapchain_destroy(context.swapchain); + vkDestroySurfaceKHR(context.instance, context.surface, context.allocator); vkDestroyInstance(context.instance, context.allocator); + arena_free_storage(&context.temp_arena); } bool gpu_device_create(gpu_device* out_device) { @@ -191,6 +198,12 @@ bool gpu_device_create(gpu_device* out_device) { create_logical_device(out_device); // Create the command pool + VkCommandPoolCreateInfo pool_create_info = { VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO }; + pool_create_info.queueFamilyIndex = out_device->queue_family_indicies.graphics_family_index; + pool_create_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + vkCreateCommandPool(out_device->logical_device, &pool_create_info, context.allocator, + &out_device->pool); + TRACE("Command Pool created"); arena_rewind(savept); // Free any temp data return true; @@ -268,6 +281,10 @@ bool gpu_swapchain_create(gpu_swapchain* out_swapchain) { } void gpu_swapchain_destroy(gpu_swapchain* swapchain) { + for (u32 i = 0; i < swapchain->image_count; i++) { + vkDestroyImageView(context.device->logical_device, swapchain->image_views[i], + context.allocator); + } arena_free_storage(&swapchain->swapchain_arena); vkDestroySwapchainKHR(context.device->logical_device, swapchain->handle, context.allocator); } @@ -437,7 +454,7 @@ gpu_pipeline* gpu_graphics_pipeline_create(struct graphics_pipeline_desc descrip pipeline_create_info.layout = layout->handle; - // pipeline_create_info.renderPass = renderpass->handle; + pipeline_create_info.renderPass = description.renderpass->handle; pipeline_create_info.subpass = 0; pipeline_create_info.basePipelineHandle = VK_NULL_HANDLE; pipeline_create_info.basePipelineIndex = -1; @@ -454,6 +471,31 @@ gpu_pipeline* gpu_graphics_pipeline_create(struct graphics_pipeline_desc descrip vkDestroyShaderModule(context.device->logical_device, vertex_shader, context.allocator); vkDestroyShaderModule(context.device->logical_device, fragment_shader, context.allocator); + // Framebuffers + u32 image_count = context.swapchain->image_count; + context.swapchain_framebuffers = + arena_alloc(&context.swapchain->swapchain_arena, image_count * sizeof(VkFramebuffer)); + for (u32 i = 0; i < image_count; i++) { + VkImageView attachments[1] = { context.swapchain->image_views[i] }; + + VkFramebufferCreateInfo framebuffer_create_info = { VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO }; + framebuffer_create_info.attachmentCount = 1; + framebuffer_create_info.pAttachments = attachments; + + framebuffer_create_info.renderPass = description.renderpass->handle; + framebuffer_create_info.width = context.swapchain->extent.width; + framebuffer_create_info.height = context.swapchain->extent.height; + framebuffer_create_info.layers = 1; + + vkCreateFramebuffer(context.device->logical_device, &framebuffer_create_info, context.allocator, + &context.swapchain_framebuffers[i]); + } + TRACE("Swapchain Framebuffers created"); + + context.main_cmd_buf = gpu_cmd_encoder_create(); + TRACE("main Command Buffer created"); + + TRACE("Graphics pipeline created"); return pipeline; } @@ -463,7 +505,7 @@ gpu_renderpass* gpu_renderpass_create(const gpu_renderpass_desc* description) { // Colour attachment VkAttachmentDescription color_attachment; - // color_attachment.format = context->swapchain.image_format.format; + color_attachment.format = context.swapchain->image_format.format; color_attachment.samples = VK_SAMPLE_COUNT_1_BIT; color_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; color_attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; @@ -491,9 +533,30 @@ gpu_renderpass* gpu_renderpass_create(const gpu_renderpass_desc* description) { subpass.pColorAttachments = &color_attachment_reference; // sets everything up + // renderpass dependencies + VkSubpassDependency dependency; + dependency.srcSubpass = VK_SUBPASS_EXTERNAL; + dependency.dstSubpass = 0; + dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + dependency.srcAccessMask = 0; + dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + dependency.dstAccessMask = + VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + dependency.dependencyFlags = 0; // Finally, create the RenderPass VkRenderPassCreateInfo render_pass_create_info = { VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO }; + render_pass_create_info.attachmentCount = 1; + render_pass_create_info.pAttachments = &color_attachment; + render_pass_create_info.subpassCount = 1; + render_pass_create_info.pSubpasses = &subpass; + render_pass_create_info.dependencyCount = 1; + render_pass_create_info.pDependencies = &dependency; + render_pass_create_info.flags = 0; + render_pass_create_info.pNext = 0; + + VK_CHECK(vkCreateRenderPass(context.device->logical_device, &render_pass_create_info, + context.allocator, &renderpass->handle)); return renderpass; } @@ -507,6 +570,29 @@ void encode_set_pipeline(gpu_cmd_encoder* encoder, gpu_pipeline* pipeline) { // } } +gpu_cmd_encoder gpu_cmd_encoder_create() { + // gpu_cmd_encoder* encoder = malloc(sizeof(gpu_cmd_encoder)); // TODO: fix leaking mem + gpu_cmd_encoder encoder = { 0 }; + + VkCommandBufferAllocateInfo allocate_info = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO }; + allocate_info.commandPool = context.device->pool; + allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + allocate_info.commandBufferCount = 1; + allocate_info.pNext = NULL; + + VK_CHECK(vkAllocateCommandBuffers(context.device->logical_device, &allocate_info, + &encoder.cmd_buffer);); + + return encoder; +} + +void gpu_cmd_encoder_begin(gpu_cmd_encoder encoder) { + VkCommandBufferBeginInfo begin_info = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO }; + VK_CHECK(vkBeginCommandBuffer(encoder.cmd_buffer, &begin_info)); +} + +void gpu_cmd_encoder_begin_render(gpu_renderpass* renderpass) {} + // --- Drawing inline void encode_draw_indexed(gpu_cmd_encoder* encoder, u64 index_count) { vkCmdDrawIndexed(encoder->cmd_buffer, index_count, 1, 0, 0, 0); diff --git a/src/renderer/backends/backend_vulkan.h b/src/renderer/backends/backend_vulkan.h index 9c85683..842355e 100644 --- a/src/renderer/backends/backend_vulkan.h +++ b/src/renderer/backends/backend_vulkan.h @@ -26,6 +26,9 @@ typedef struct queue_family_indices { bool has_transfer; } queue_family_indices; +// typedef struct vulkan_framebuffer { +// } vulkan_framebuffer; + typedef struct gpu_swapchain { VkSwapchainKHR handle; arena swapchain_arena; diff --git a/src/renderer/ral.h b/src/renderer/ral.h index 15c66ef..b09e1ae 100644 --- a/src/renderer/ral.h +++ b/src/renderer/ral.h @@ -80,8 +80,9 @@ void gpu_pipeline_destroy(gpu_pipeline* pipeline); bool gpu_swapchain_create(gpu_swapchain* out_swapchain); void gpu_swapchain_destroy(gpu_swapchain* swapchain); -void gpu_cmd_encoder_begin(); -void gpu_cmd_encoder_begin_render(); +gpu_cmd_encoder gpu_cmd_encoder_create(); +void gpu_cmd_encoder_begin(gpu_cmd_encoder encoder); +void gpu_cmd_encoder_begin_render(gpu_renderpass* renderpass); void gpu_cmd_encoder_begin_compute(); /* Actual commands that we can encode */ -- cgit v1.2.3-70-g09d2 From f05ce66a8e6fd0742a8314661a8dc871a5a2c0c3 Mon Sep 17 00:00:00 2001 From: Omniscient <17525998+omnisci3nce@users.noreply.github.com> Date: Wed, 8 May 2024 10:37:18 +1000 Subject: finishing submission + presentation for triangle example --- examples/triangle/ex_triangle.c | 19 ++++- src/renderer/backends/backend_vulkan.c | 138 ++++++++++++++++++++++++++++++++- src/renderer/backends/backend_vulkan.h | 8 +- src/renderer/ral.h | 15 +++- 4 files changed, 172 insertions(+), 8 deletions(-) (limited to 'examples/triangle') diff --git a/examples/triangle/ex_triangle.c b/examples/triangle/ex_triangle.c index 1b6fc96..50f135a 100644 --- a/examples/triangle/ex_triangle.c +++ b/examples/triangle/ex_triangle.c @@ -52,7 +52,24 @@ int main() { static f64 x = 0.0; x += 0.01; - // insert work here + gpu_backend_begin_frame(); + gpu_cmd_encoder* enc = gpu_get_default_cmd_encoder(); + // begin recording + gpu_cmd_encoder_begin(*enc); + gpu_cmd_encoder_begin_render(enc, renderpass); + encode_bind_pipeline(enc, PIPELINE_GRAPHICS, gfx_pipeline); + encode_set_default_settings(enc); + + // Record draw calls + gpu_temp_draw(); + + // End recording + gpu_cmd_encoder_end_render(enc); + + gpu_cmd_buffer buf = gpu_cmd_encoder_finish(enc); + gpu_queue_submit(&buf); + // Submit + gpu_backend_end_frame(); render_frame_end(&core->renderer); glfwSwapBuffers(core->renderer.window); diff --git a/src/renderer/backends/backend_vulkan.c b/src/renderer/backends/backend_vulkan.c index 1b192dd..7140d45 100644 --- a/src/renderer/backends/backend_vulkan.c +++ b/src/renderer/backends/backend_vulkan.c @@ -39,6 +39,10 @@ typedef struct vulkan_context { swapchain_framebuffers; // TODO: Move this data into the swapchain as its own struct gpu_cmd_encoder main_cmd_buf; + u32 current_img_index; + VkSemaphore image_available_semaphore; + VkSemaphore render_finished_semaphore; + VkFence in_flight_fence; u32 screen_width; u32 screen_height; @@ -59,6 +63,8 @@ queue_family_indices find_queue_families(VkPhysicalDevice device); bool create_logical_device(gpu_device* out_device); +void create_sync_objects(); + VkShaderModule create_shader_module(str8 spirv); /** @brief Helper function for creating array of all extensions we want */ @@ -68,6 +74,7 @@ bool gpu_backend_init(const char* window_name, GLFWwindow* window) { context.allocator = 0; // TODO: use an allocator context.screen_width = SCREEN_WIDTH; context.screen_height = SCREEN_HEIGHT; + context.current_img_index = 0; // Create an allocator size_t temp_arena_size = 1024 * 1024; @@ -205,6 +212,10 @@ bool gpu_device_create(gpu_device* out_device) { &out_device->pool); TRACE("Command Pool created"); + // Synchronisation objects + create_sync_objects(); + TRACE("Synchronisation primitives created"); + arena_rewind(savept); // Free any temp data return true; } @@ -487,8 +498,8 @@ gpu_pipeline* gpu_graphics_pipeline_create(struct graphics_pipeline_desc descrip framebuffer_create_info.height = context.swapchain->extent.height; framebuffer_create_info.layers = 1; - vkCreateFramebuffer(context.device->logical_device, &framebuffer_create_info, context.allocator, - &context.swapchain_framebuffers[i]); + VK_CHECK(vkCreateFramebuffer(context.device->logical_device, &framebuffer_create_info, + context.allocator, &context.swapchain_framebuffers[i])); } TRACE("Swapchain Framebuffers created"); @@ -498,6 +509,7 @@ gpu_pipeline* gpu_graphics_pipeline_create(struct graphics_pipeline_desc descrip TRACE("Graphics pipeline created"); return pipeline; } +gpu_cmd_encoder* gpu_get_default_cmd_encoder() { return &context.main_cmd_buf; } gpu_renderpass* gpu_renderpass_create(const gpu_renderpass_desc* description) { // TEMP: allocate with malloc. in the future we will have a pool allocator on the context @@ -591,9 +603,116 @@ void gpu_cmd_encoder_begin(gpu_cmd_encoder encoder) { VK_CHECK(vkBeginCommandBuffer(encoder.cmd_buffer, &begin_info)); } -void gpu_cmd_encoder_begin_render(gpu_renderpass* renderpass) {} +void gpu_cmd_encoder_begin_render(gpu_cmd_encoder* encoder, gpu_renderpass* renderpass) { + VkRenderPassBeginInfo begin_info = { VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO }; + begin_info.renderPass = renderpass->handle; + begin_info.framebuffer = context.swapchain_framebuffers[context.current_img_index]; + begin_info.renderArea.offset = (VkOffset2D){ 0, 0 }; + begin_info.renderArea.extent = context.swapchain->extent; + + // VkClearValue clear_values[2]; + VkClearValue clear_color = { { { 0.0f, 0.0f, 0.0f, 1.0f } } }; + // clear_values[1].depthStencil.depth = renderpass->depth; + // clear_values[1].depthStencil.stencil = renderpass->stencil; + + begin_info.clearValueCount = 1; + begin_info.pClearValues = &clear_color; + + vkCmdBeginRenderPass(encoder->cmd_buffer, &begin_info, VK_SUBPASS_CONTENTS_INLINE); + // command_buffer->state = COMMAND_BUFFER_STATE_IN_RENDER_PASS; +} + +void gpu_cmd_encoder_end_render(gpu_cmd_encoder* encoder) { + vkCmdEndRenderPass(encoder->cmd_buffer); +} + +gpu_cmd_buffer gpu_cmd_encoder_finish(gpu_cmd_encoder* encoder) { + vkEndCommandBuffer(encoder->cmd_buffer); + // TEMP: submit + return (gpu_cmd_buffer){ .cmd_buffer = encoder->cmd_buffer }; +} + +// --- 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); +} + +// TEMP +void encode_set_default_settings(gpu_cmd_encoder* encoder) { + VkViewport viewport = { 0 }; + viewport.x = 0.0f; + viewport.y = 0.0f; + viewport.width = context.swapchain->extent.width; + viewport.height = context.swapchain->extent.height; + viewport.minDepth = 0.0f; + viewport.maxDepth = 1.0f; + vkCmdSetViewport(encoder->cmd_buffer, 0, 1, &viewport); + + VkRect2D scissor = { 0 }; + scissor.offset = (VkOffset2D){ 0, 0 }; + scissor.extent = context.swapchain->extent; + vkCmdSetScissor(encoder->cmd_buffer, 0, 1, &scissor); +} // --- Drawing + +void gpu_backend_begin_frame() { + TRACE("gpu_backend_begin_frame"); + vkWaitForFences(context.device->logical_device, 1, &context.in_flight_fence, VK_TRUE, UINT64_MAX); + vkResetFences(context.device->logical_device, 1, &context.in_flight_fence); + + u32 image_index; + vkAcquireNextImageKHR(context.device->logical_device, context.swapchain->handle, UINT64_MAX, + context.image_available_semaphore, VK_NULL_HANDLE, &image_index); + context.current_img_index = image_index; + DEBUG("Current image_index = %d", image_index); + vkResetCommandBuffer(context.main_cmd_buf.cmd_buffer, 0); +} + +void gpu_temp_draw() { + gpu_cmd_encoder* encoder = &context.main_cmd_buf; + + vkCmdDraw(encoder->cmd_buffer, 3, 1, 0, 0); +} + +void gpu_backend_end_frame() { + VkPresentInfoKHR present_info = { VK_STRUCTURE_TYPE_PRESENT_INFO_KHR }; + present_info.waitSemaphoreCount = 1; + present_info.pWaitSemaphores = &context.render_finished_semaphore; + + VkSwapchainKHR swapchains[] = { context.swapchain->handle }; + present_info.swapchainCount = 1; + present_info.pSwapchains = swapchains; + present_info.pImageIndices = &context.current_img_index; + + vkQueuePresentKHR(context.device->present_queue, &present_info); + vkDeviceWaitIdle(context.device->logical_device); +} + +// TODO: Move into better order in file +void gpu_queue_submit(gpu_cmd_buffer* buffer) { + VkSubmitInfo submit_info = { VK_STRUCTURE_TYPE_SUBMIT_INFO }; + + // Specify semaphore to wait on + VkSemaphore wait_semaphores[] = { context.image_available_semaphore }; + VkPipelineStageFlags wait_stages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT }; + + submit_info.waitSemaphoreCount = 1; + submit_info.pWaitSemaphores = wait_semaphores; + submit_info.pWaitDstStageMask = wait_stages; + + // Specify semaphore to signal when finished executing buffer + VkSemaphore signal_semaphores[] = { context.render_finished_semaphore }; + submit_info.signalSemaphoreCount = 1; + submit_info.pSignalSemaphores = signal_semaphores; + + submit_info.commandBufferCount = 1; + submit_info.pCommandBuffers = &buffer->cmd_buffer; + + VK_CHECK( + vkQueueSubmit(context.device->graphics_queue, 1, &submit_info, context.in_flight_fence);); +} + inline void encode_draw_indexed(gpu_cmd_encoder* encoder, u64 index_count) { vkCmdDrawIndexed(encoder->cmd_buffer, index_count, 1, 0, 0, 0); } @@ -753,4 +872,17 @@ VkShaderModule create_shader_module(str8 spirv) { &shader_module)); return shader_module; +} + +void create_sync_objects() { + VkSemaphoreCreateInfo semaphore_info = { VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO }; + VK_CHECK(vkCreateSemaphore(context.device->logical_device, &semaphore_info, context.allocator, + &context.image_available_semaphore);); + VK_CHECK(vkCreateSemaphore(context.device->logical_device, &semaphore_info, context.allocator, + &context.render_finished_semaphore);); + + VkFenceCreateInfo fence_info = { VK_STRUCTURE_TYPE_FENCE_CREATE_INFO }; + fence_info.flags = VK_FENCE_CREATE_SIGNALED_BIT; + VK_CHECK(vkCreateFence(context.device->logical_device, &fence_info, context.allocator, + &context.in_flight_fence)); } \ No newline at end of file diff --git a/src/renderer/backends/backend_vulkan.h b/src/renderer/backends/backend_vulkan.h index 842355e..330ba18 100644 --- a/src/renderer/backends/backend_vulkan.h +++ b/src/renderer/backends/backend_vulkan.h @@ -66,9 +66,13 @@ typedef struct gpu_pipeline { typedef struct gpu_renderpass { VkRenderPass handle; - VkFramebuffer framebuffers[GPU_SWAPCHAIN_IMG_COUNT]; + // TODO: Where to store framebuffers? VkFramebuffer framebuffers[GPU_SWAPCHAIN_IMG_COUNT]; } gpu_renderpass; typedef struct gpu_cmd_encoder { VkCommandBuffer cmd_buffer; -} gpu_cmd_encoder; \ No newline at end of file +} gpu_cmd_encoder; + +typedef struct gpu_cmd_buffer { + VkCommandBuffer cmd_buffer; +} gpu_cmd_buffer; \ No newline at end of file diff --git a/src/renderer/ral.h b/src/renderer/ral.h index b09e1ae..416370f 100644 --- a/src/renderer/ral.h +++ b/src/renderer/ral.h @@ -68,6 +68,10 @@ typedef struct gpu_renderpass_desc { bool gpu_backend_init(const char* window_name, struct GLFWwindow* window); void gpu_backend_shutdown(); +// TEMP +void gpu_backend_begin_frame(); +void gpu_backend_end_frame(); + bool gpu_device_create(gpu_device* out_device); void gpu_device_destroy(); @@ -82,8 +86,10 @@ void gpu_swapchain_destroy(gpu_swapchain* swapchain); gpu_cmd_encoder gpu_cmd_encoder_create(); void gpu_cmd_encoder_begin(gpu_cmd_encoder encoder); -void gpu_cmd_encoder_begin_render(gpu_renderpass* renderpass); +void gpu_cmd_encoder_begin_render(gpu_cmd_encoder* encoder, gpu_renderpass* renderpass); +void gpu_cmd_encoder_end_render(gpu_cmd_encoder* encoder); void gpu_cmd_encoder_begin_compute(); +gpu_cmd_encoder* gpu_get_default_cmd_encoder(); /* Actual commands that we can encode */ void encode_buffer_copy(gpu_cmd_encoder* encoder, buffer_handle src, u64 src_offset, @@ -96,6 +102,7 @@ void buffer_upload_bytes(buffer_handle gpu_buf, bytebuffer cpu_buf, u64 offset, // render pass void encode_bind_pipeline(gpu_cmd_encoder* encoder, pipeline_kind kind, gpu_pipeline* pipeline); +void encode_set_default_settings(gpu_cmd_encoder* encoder); void encode_set_vertex_buffer(gpu_cmd_encoder* encoder, buffer_handle buf); void encode_set_index_buffer(gpu_cmd_encoder* encoder, buffer_handle buf); void encode_set_bind_group(); // TODO @@ -126,4 +133,8 @@ void gpu_sampler_create(); // --- Vertex formats bytebuffer vertices_as_bytebuffer(arena* a, vertex_format format, vertex_darray* vertices); -// TODO: Bindgroup texture samplers / shader resources \ No newline at end of file +// TODO: Bindgroup texture samplers / shader resources + +// TEMP + +void gpu_temp_draw(); \ No newline at end of file -- cgit v1.2.3-70-g09d2 From f1b48b0bbbebb92b9600dac41848304b82f0b3dd Mon Sep 17 00:00:00 2001 From: Omniscient <17525998+omnisci3nce@users.noreply.github.com> Date: Wed, 8 May 2024 11:56:25 +1000 Subject: we are so triangle --- assets/shaders/triangle.vert | 2 +- examples/triangle/ex_triangle.c | 4 +-- src/renderer/backends/backend_vulkan.c | 48 ++++++++++++++++++---------------- 3 files changed, 29 insertions(+), 25 deletions(-) (limited to 'examples/triangle') diff --git a/assets/shaders/triangle.vert b/assets/shaders/triangle.vert index e160d39..ee3675d 100644 --- a/assets/shaders/triangle.vert +++ b/assets/shaders/triangle.vert @@ -1,6 +1,6 @@ #version 450 -vec2 positions[3] = vec2[](vec2(0.0, -0.5), vec2(0.5, 0.5), vec2(-0.5, 0.5)); +vec2 positions[3] = vec2[](vec2(-0.5, 0.5), vec2(0.5, 0.5), vec2(0.0, -0.5)); vec3 colors[3] = vec3[](vec3(1.0, 0.0, 0.0), vec3(0.0, 1.0, 0.0), vec3(0.0, 0.0, 1.0)); diff --git a/examples/triangle/ex_triangle.c b/examples/triangle/ex_triangle.c index 50f135a..4aa9e96 100644 --- a/examples/triangle/ex_triangle.c +++ b/examples/triangle/ex_triangle.c @@ -45,6 +45,7 @@ int main() { // Main loop while (!should_exit(core)) { + glfwPollEvents(); input_update(&core->input); render_frame_begin(&core->renderer); @@ -72,8 +73,7 @@ int main() { gpu_backend_end_frame(); render_frame_end(&core->renderer); - glfwSwapBuffers(core->renderer.window); - glfwPollEvents(); + // glfwSwapBuffers(core->renderer.window); } gpu_backend_shutdown(); diff --git a/src/renderer/backends/backend_vulkan.c b/src/renderer/backends/backend_vulkan.c index 7140d45..e693da3 100644 --- a/src/renderer/backends/backend_vulkan.c +++ b/src/renderer/backends/backend_vulkan.c @@ -261,15 +261,16 @@ bool gpu_swapchain_create(gpu_swapchain* out_swapchain) { TRACE("Vulkan Swapchain created"); // Retrieve Images - out_swapchain->images = - arena_alloc(&out_swapchain->swapchain_arena, image_count * sizeof(VkImage)); + // out_swapchain->images = + // arena_alloc(&out_swapchain->swapchain_arena, image_count * sizeof(VkImage)); + out_swapchain->images = malloc(image_count * sizeof(VkImage)); VK_CHECK(vkGetSwapchainImagesKHR(context.device->logical_device, out_swapchain->handle, &image_count, out_swapchain->images)); // Create ImageViews // TODO: Move this to a separate function - out_swapchain->image_views = - arena_alloc(&out_swapchain->swapchain_arena, image_count * sizeof(VkImageView)); + out_swapchain->image_views = malloc(image_count * sizeof(VkImageView)); + // arena_alloc(&out_swapchain->swapchain_arena, image_count * sizeof(VkImageView)); for (u32 i = 0; i < image_count; i++) { VkImageViewCreateInfo view_create_info = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO }; view_create_info.image = out_swapchain->images[i]; @@ -306,6 +307,8 @@ gpu_pipeline* gpu_graphics_pipeline_create(struct graphics_pipeline_desc descrip gpu_pipeline* pipeline = malloc(sizeof(gpu_pipeline)); // Shaders + printf("Vertex shader: %s\n", description.vs.filepath.buf); + printf("Fragment shader: %s\n", description.fs.filepath.buf); VkShaderModule vertex_shader = create_shader_module(description.vs.code); VkShaderModule fragment_shader = create_shader_module(description.fs.code); @@ -358,9 +361,9 @@ gpu_pipeline* gpu_graphics_pipeline_create(struct graphics_pipeline_desc descrip VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO }; viewport_state.viewportCount = 1; - viewport_state.pViewports = &viewport; + // viewport_state.pViewports = &viewport; viewport_state.scissorCount = 1; - viewport_state.pScissors = &scissor; + // viewport_state.pScissors = &scissor; // Rasterizer VkPipelineRasterizationStateCreateInfo rasterizer_create_info = { @@ -402,13 +405,13 @@ gpu_pipeline* gpu_graphics_pipeline_create(struct graphics_pipeline_desc descrip // Blending VkPipelineColorBlendAttachmentState color_blend_attachment_state; - color_blend_attachment_state.blendEnable = VK_TRUE; - color_blend_attachment_state.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; - color_blend_attachment_state.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; - color_blend_attachment_state.colorBlendOp = VK_BLEND_OP_ADD; - color_blend_attachment_state.srcAlphaBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; - color_blend_attachment_state.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; - color_blend_attachment_state.alphaBlendOp = VK_BLEND_OP_ADD; + color_blend_attachment_state.blendEnable = VK_FALSE; + // color_blend_attachment_state.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; + // color_blend_attachment_state.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + // color_blend_attachment_state.colorBlendOp = VK_BLEND_OP_ADD; + // color_blend_attachment_state.srcAlphaBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; + // color_blend_attachment_state.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + // color_blend_attachment_state.alphaBlendOp = VK_BLEND_OP_ADD; color_blend_attachment_state.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; @@ -606,12 +609,13 @@ void gpu_cmd_encoder_begin(gpu_cmd_encoder encoder) { void gpu_cmd_encoder_begin_render(gpu_cmd_encoder* encoder, gpu_renderpass* renderpass) { VkRenderPassBeginInfo begin_info = { VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO }; begin_info.renderPass = renderpass->handle; + printf("Current img: %d\n", context.current_img_index); begin_info.framebuffer = context.swapchain_framebuffers[context.current_img_index]; begin_info.renderArea.offset = (VkOffset2D){ 0, 0 }; begin_info.renderArea.extent = context.swapchain->extent; // VkClearValue clear_values[2]; - VkClearValue clear_color = { { { 0.0f, 0.0f, 0.0f, 1.0f } } }; + VkClearValue clear_color = { { { 0.2f, 0.2f, 0.2f, 1.0f } } }; // clear_values[1].depthStencil.depth = renderpass->depth; // clear_values[1].depthStencil.stencil = renderpass->stencil; @@ -657,21 +661,22 @@ void encode_set_default_settings(gpu_cmd_encoder* encoder) { // --- Drawing void gpu_backend_begin_frame() { - TRACE("gpu_backend_begin_frame"); + // TRACE("gpu_backend_begin_frame"); vkWaitForFences(context.device->logical_device, 1, &context.in_flight_fence, VK_TRUE, UINT64_MAX); vkResetFences(context.device->logical_device, 1, &context.in_flight_fence); u32 image_index; - vkAcquireNextImageKHR(context.device->logical_device, context.swapchain->handle, UINT64_MAX, - context.image_available_semaphore, VK_NULL_HANDLE, &image_index); + VK_CHECK(vkAcquireNextImageKHR(context.device->logical_device, context.swapchain->handle, + UINT64_MAX, context.image_available_semaphore, VK_NULL_HANDLE, + &image_index)); context.current_img_index = image_index; - DEBUG("Current image_index = %d", image_index); - vkResetCommandBuffer(context.main_cmd_buf.cmd_buffer, 0); + printf("Current img: %d\n", context.current_img_index); + VK_CHECK(vkResetCommandBuffer(context.main_cmd_buf.cmd_buffer, 0)); } void gpu_temp_draw() { gpu_cmd_encoder* encoder = &context.main_cmd_buf; - + TRACE("Draw call"); vkCmdDraw(encoder->cmd_buffer, 3, 1, 0, 0); } @@ -709,8 +714,7 @@ void gpu_queue_submit(gpu_cmd_buffer* buffer) { submit_info.commandBufferCount = 1; submit_info.pCommandBuffers = &buffer->cmd_buffer; - VK_CHECK( - vkQueueSubmit(context.device->graphics_queue, 1, &submit_info, context.in_flight_fence);); + VK_CHECK(vkQueueSubmit(context.device->graphics_queue, 1, &submit_info, context.in_flight_fence)); } inline void encode_draw_indexed(gpu_cmd_encoder* encoder, u64 index_count) { -- cgit v1.2.3-70-g09d2 From 5e0f5662ae65d268db1bf1bc53c773ef9cba33ea Mon Sep 17 00:00:00 2001 From: Omniscient <17525998+omnisci3nce@users.noreply.github.com> Date: Thu, 9 May 2024 10:55:13 +1000 Subject: frames in flight. recreate swapchain still has a few validation errors --- examples/triangle/ex_triangle.c | 2 +- src/renderer/backends/backend_vulkan.c | 178 ++++++++++++++++++++++----------- src/renderer/render.c | 6 +- 3 files changed, 126 insertions(+), 60 deletions(-) (limited to 'examples/triangle') diff --git a/examples/triangle/ex_triangle.c b/examples/triangle/ex_triangle.c index 4aa9e96..1f7ef5e 100644 --- a/examples/triangle/ex_triangle.c +++ b/examples/triangle/ex_triangle.c @@ -76,7 +76,7 @@ int main() { // glfwSwapBuffers(core->renderer.window); } - gpu_backend_shutdown(); + renderer_shutdown(&core->renderer); return 0; } diff --git a/src/renderer/backends/backend_vulkan.c b/src/renderer/backends/backend_vulkan.c index e693da3..50f9662 100644 --- a/src/renderer/backends/backend_vulkan.c +++ b/src/renderer/backends/backend_vulkan.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -21,7 +22,7 @@ // TEMP #define SCREEN_WIDTH 1000 #define SCREEN_HEIGHT 1000 - +#define MAX_FRAMES_IN_FLIGHT 2 #define VULKAN_QUEUES_COUNT 2 const char* queue_names[VULKAN_QUEUES_COUNT] = { "GRAPHICS", "TRANSFER" }; @@ -38,11 +39,15 @@ typedef struct vulkan_context { VkFramebuffer* swapchain_framebuffers; // TODO: Move this data into the swapchain as its own struct - gpu_cmd_encoder main_cmd_buf; u32 current_img_index; - VkSemaphore image_available_semaphore; - VkSemaphore render_finished_semaphore; - VkFence in_flight_fence; + u32 current_frame; // super important + gpu_cmd_encoder main_cmd_bufs[MAX_FRAMES_IN_FLIGHT]; + VkSemaphore image_available_semaphores[MAX_FRAMES_IN_FLIGHT]; + VkSemaphore render_finished_semaphores[MAX_FRAMES_IN_FLIGHT]; + VkFence in_flight_fences[MAX_FRAMES_IN_FLIGHT]; + + // HACK + VkRenderPass main_renderpass; u32 screen_width; u32 screen_height; @@ -62,7 +67,7 @@ bool is_physical_device_suitable(VkPhysicalDevice device); queue_family_indices find_queue_families(VkPhysicalDevice device); bool create_logical_device(gpu_device* out_device); - +void create_swapchain_framebuffers(); void create_sync_objects(); VkShaderModule create_shader_module(str8 spirv); @@ -71,10 +76,12 @@ VkShaderModule create_shader_module(str8 spirv); cstr_darray* get_all_extensions(); bool gpu_backend_init(const char* window_name, GLFWwindow* window) { + memset(&context, 0, sizeof(vulkan_context)); context.allocator = 0; // TODO: use an allocator context.screen_width = SCREEN_WIDTH; context.screen_height = SCREEN_HEIGHT; context.current_img_index = 0; + context.current_frame = 0; // Create an allocator size_t temp_arena_size = 1024 * 1024; @@ -224,6 +231,9 @@ bool gpu_swapchain_create(gpu_swapchain* out_swapchain) { context.swapchain = out_swapchain; out_swapchain->swapchain_arena = arena_create(malloc(1024), 1024); + + vulkan_device_query_swapchain_support(context.device->physical_device, context.surface, + &context.swapchain_support); vulkan_swapchain_support_info swapchain_support = context.swapchain_support; // TODO: custom swapchain extents VkExtent2D swapchain_extent = { width, height }; @@ -293,6 +303,11 @@ bool gpu_swapchain_create(gpu_swapchain* out_swapchain) { } void gpu_swapchain_destroy(gpu_swapchain* swapchain) { + // Destroy Framebuffers + for (u32 i = 0; i < swapchain->image_count; i++) { + vkDestroyFramebuffer(context.device->logical_device, context.swapchain_framebuffers[i], + context.allocator); + } for (u32 i = 0; i < swapchain->image_count; i++) { vkDestroyImageView(context.device->logical_device, swapchain->image_views[i], context.allocator); @@ -301,6 +316,15 @@ void gpu_swapchain_destroy(gpu_swapchain* swapchain) { vkDestroySwapchainKHR(context.device->logical_device, swapchain->handle, context.allocator); } +static void recreate_swapchain(gpu_swapchain* swapchain) { + DEBUG("Recreating swapchain..."); + vkDeviceWaitIdle(context.device->logical_device); + + gpu_swapchain_destroy(swapchain); + gpu_swapchain_create(swapchain); + create_swapchain_framebuffers(); +} + gpu_pipeline* gpu_graphics_pipeline_create(struct graphics_pipeline_desc description) { // Allocate gpu_pipeline_layout* layout = malloc(sizeof(gpu_pipeline_layout)); @@ -406,12 +430,12 @@ gpu_pipeline* gpu_graphics_pipeline_create(struct graphics_pipeline_desc descrip // Blending VkPipelineColorBlendAttachmentState color_blend_attachment_state; color_blend_attachment_state.blendEnable = VK_FALSE; - // color_blend_attachment_state.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; - // color_blend_attachment_state.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; - // color_blend_attachment_state.colorBlendOp = VK_BLEND_OP_ADD; - // color_blend_attachment_state.srcAlphaBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; - // color_blend_attachment_state.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; - // color_blend_attachment_state.alphaBlendOp = VK_BLEND_OP_ADD; + color_blend_attachment_state.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; + color_blend_attachment_state.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + color_blend_attachment_state.colorBlendOp = VK_BLEND_OP_ADD; + color_blend_attachment_state.srcAlphaBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; + color_blend_attachment_state.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + color_blend_attachment_state.alphaBlendOp = VK_BLEND_OP_ADD; color_blend_attachment_state.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; @@ -486,33 +510,27 @@ gpu_pipeline* gpu_graphics_pipeline_create(struct graphics_pipeline_desc descrip vkDestroyShaderModule(context.device->logical_device, fragment_shader, context.allocator); // Framebuffers - u32 image_count = context.swapchain->image_count; - context.swapchain_framebuffers = - arena_alloc(&context.swapchain->swapchain_arena, image_count * sizeof(VkFramebuffer)); - for (u32 i = 0; i < image_count; i++) { - VkImageView attachments[1] = { context.swapchain->image_views[i] }; - - VkFramebufferCreateInfo framebuffer_create_info = { VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO }; - framebuffer_create_info.attachmentCount = 1; - framebuffer_create_info.pAttachments = attachments; - - framebuffer_create_info.renderPass = description.renderpass->handle; - framebuffer_create_info.width = context.swapchain->extent.width; - framebuffer_create_info.height = context.swapchain->extent.height; - framebuffer_create_info.layers = 1; - - VK_CHECK(vkCreateFramebuffer(context.device->logical_device, &framebuffer_create_info, - context.allocator, &context.swapchain_framebuffers[i])); - } + create_swapchain_framebuffers(); TRACE("Swapchain Framebuffers created"); - context.main_cmd_buf = gpu_cmd_encoder_create(); + for (u32 frame_i = 0; frame_i < MAX_FRAMES_IN_FLIGHT; frame_i++) { + context.main_cmd_bufs[frame_i] = gpu_cmd_encoder_create(); + } TRACE("main Command Buffer created"); TRACE("Graphics pipeline created"); return pipeline; } -gpu_cmd_encoder* gpu_get_default_cmd_encoder() { return &context.main_cmd_buf; } + +void gpu_pipeline_destroy(gpu_pipeline* pipeline) { + vkDestroyPipeline(context.device->logical_device, pipeline->handle, context.allocator); + vkDestroyPipelineLayout(context.device->logical_device, pipeline->layout_handle, + context.allocator); +} + +gpu_cmd_encoder* gpu_get_default_cmd_encoder() { + return &context.main_cmd_bufs[context.current_frame]; +} gpu_renderpass* gpu_renderpass_create(const gpu_renderpass_desc* description) { // TEMP: allocate with malloc. in the future we will have a pool allocator on the context @@ -573,6 +591,9 @@ gpu_renderpass* gpu_renderpass_create(const gpu_renderpass_desc* description) { VK_CHECK(vkCreateRenderPass(context.device->logical_device, &render_pass_create_info, context.allocator, &renderpass->handle)); + // HACK + context.main_renderpass = renderpass->handle; + return renderpass; } @@ -609,13 +630,14 @@ void gpu_cmd_encoder_begin(gpu_cmd_encoder encoder) { void gpu_cmd_encoder_begin_render(gpu_cmd_encoder* encoder, gpu_renderpass* renderpass) { VkRenderPassBeginInfo begin_info = { VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO }; begin_info.renderPass = renderpass->handle; - printf("Current img: %d\n", context.current_img_index); + /* printf("Current img: %d Current frame %d\n", context.current_img_index, context.current_frame); + */ begin_info.framebuffer = context.swapchain_framebuffers[context.current_img_index]; begin_info.renderArea.offset = (VkOffset2D){ 0, 0 }; begin_info.renderArea.extent = context.swapchain->extent; // VkClearValue clear_values[2]; - VkClearValue clear_color = { { { 0.2f, 0.2f, 0.2f, 1.0f } } }; + VkClearValue clear_color = { { { 0.02f, 0.02f, 0.02f, 1.0f } } }; // clear_values[1].depthStencil.depth = renderpass->depth; // clear_values[1].depthStencil.stencil = renderpass->stencil; @@ -661,37 +683,53 @@ void encode_set_default_settings(gpu_cmd_encoder* encoder) { // --- Drawing void gpu_backend_begin_frame() { + u32 current_frame = context.current_frame; // TRACE("gpu_backend_begin_frame"); - vkWaitForFences(context.device->logical_device, 1, &context.in_flight_fence, VK_TRUE, UINT64_MAX); - vkResetFences(context.device->logical_device, 1, &context.in_flight_fence); + vkWaitForFences(context.device->logical_device, 1, &context.in_flight_fences[current_frame], + VK_TRUE, UINT64_MAX); + vkResetFences(context.device->logical_device, 1, &context.in_flight_fences[current_frame]); u32 image_index; - VK_CHECK(vkAcquireNextImageKHR(context.device->logical_device, context.swapchain->handle, - UINT64_MAX, context.image_available_semaphore, VK_NULL_HANDLE, - &image_index)); + VkResult result = vkAcquireNextImageKHR( + context.device->logical_device, context.swapchain->handle, UINT64_MAX, + context.image_available_semaphores[current_frame], VK_NULL_HANDLE, &image_index); + if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) { + recreate_swapchain(context.swapchain); + return; + } else if (result != VK_SUCCESS) { + ERROR_EXIT("failed to acquire swapchain image"); + } + context.current_img_index = image_index; - printf("Current img: %d\n", context.current_img_index); - VK_CHECK(vkResetCommandBuffer(context.main_cmd_buf.cmd_buffer, 0)); + /* printf("Current img: %d\n", context.current_img_index); */ + VK_CHECK(vkResetCommandBuffer(context.main_cmd_bufs[current_frame].cmd_buffer, 0)); } void gpu_temp_draw() { - gpu_cmd_encoder* encoder = &context.main_cmd_buf; - TRACE("Draw call"); + gpu_cmd_encoder* encoder = gpu_get_default_cmd_encoder(); // &context.main_cmd_buf; vkCmdDraw(encoder->cmd_buffer, 3, 1, 0, 0); } void gpu_backend_end_frame() { VkPresentInfoKHR present_info = { VK_STRUCTURE_TYPE_PRESENT_INFO_KHR }; present_info.waitSemaphoreCount = 1; - present_info.pWaitSemaphores = &context.render_finished_semaphore; + present_info.pWaitSemaphores = &context.render_finished_semaphores[context.current_frame]; VkSwapchainKHR swapchains[] = { context.swapchain->handle }; present_info.swapchainCount = 1; present_info.pSwapchains = swapchains; present_info.pImageIndices = &context.current_img_index; - vkQueuePresentKHR(context.device->present_queue, &present_info); - vkDeviceWaitIdle(context.device->logical_device); + VkResult result = vkQueuePresentKHR(context.device->present_queue, &present_info); + if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) { + recreate_swapchain(context.swapchain); + return; + } else if (result != VK_SUCCESS) { + ERROR_EXIT("failed to present swapchain image"); + } + context.current_frame = (context.current_frame + 1) % MAX_FRAMES_IN_FLIGHT; + + /* vkDeviceWaitIdle(context.device->logical_device); */ } // TODO: Move into better order in file @@ -699,7 +737,7 @@ void gpu_queue_submit(gpu_cmd_buffer* buffer) { VkSubmitInfo submit_info = { VK_STRUCTURE_TYPE_SUBMIT_INFO }; // Specify semaphore to wait on - VkSemaphore wait_semaphores[] = { context.image_available_semaphore }; + VkSemaphore wait_semaphores[] = { context.image_available_semaphores[context.current_frame] }; VkPipelineStageFlags wait_stages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT }; submit_info.waitSemaphoreCount = 1; @@ -707,14 +745,15 @@ void gpu_queue_submit(gpu_cmd_buffer* buffer) { submit_info.pWaitDstStageMask = wait_stages; // Specify semaphore to signal when finished executing buffer - VkSemaphore signal_semaphores[] = { context.render_finished_semaphore }; + VkSemaphore signal_semaphores[] = { context.render_finished_semaphores[context.current_frame] }; submit_info.signalSemaphoreCount = 1; submit_info.pSignalSemaphores = signal_semaphores; submit_info.commandBufferCount = 1; submit_info.pCommandBuffers = &buffer->cmd_buffer; - VK_CHECK(vkQueueSubmit(context.device->graphics_queue, 1, &submit_info, context.in_flight_fence)); + VK_CHECK(vkQueueSubmit(context.device->graphics_queue, 1, &submit_info, + context.in_flight_fences[context.current_frame])); } inline void encode_draw_indexed(gpu_cmd_encoder* encoder, u64 index_count) { @@ -878,15 +917,40 @@ VkShaderModule create_shader_module(str8 spirv) { return shader_module; } +void create_swapchain_framebuffers() { + u32 image_count = context.swapchain->image_count; + context.swapchain_framebuffers = + arena_alloc(&context.swapchain->swapchain_arena, image_count * sizeof(VkFramebuffer)); + for (u32 i = 0; i < image_count; i++) { + VkImageView attachments[1] = { context.swapchain->image_views[i] }; + + VkFramebufferCreateInfo framebuffer_create_info = { VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO }; + framebuffer_create_info.attachmentCount = 1; + framebuffer_create_info.pAttachments = attachments; + + framebuffer_create_info.renderPass = + context.main_renderpass; // TODO: description.renderpass->handle; + framebuffer_create_info.width = context.swapchain->extent.width; + framebuffer_create_info.height = context.swapchain->extent.height; + framebuffer_create_info.layers = 1; + + VK_CHECK(vkCreateFramebuffer(context.device->logical_device, &framebuffer_create_info, + context.allocator, &context.swapchain_framebuffers[i])); + } +} + void create_sync_objects() { VkSemaphoreCreateInfo semaphore_info = { VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO }; - VK_CHECK(vkCreateSemaphore(context.device->logical_device, &semaphore_info, context.allocator, - &context.image_available_semaphore);); - VK_CHECK(vkCreateSemaphore(context.device->logical_device, &semaphore_info, context.allocator, - &context.render_finished_semaphore);); - VkFenceCreateInfo fence_info = { VK_STRUCTURE_TYPE_FENCE_CREATE_INFO }; fence_info.flags = VK_FENCE_CREATE_SIGNALED_BIT; - VK_CHECK(vkCreateFence(context.device->logical_device, &fence_info, context.allocator, - &context.in_flight_fence)); -} \ No newline at end of file + + for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + VK_CHECK(vkCreateSemaphore(context.device->logical_device, &semaphore_info, context.allocator, + &context.image_available_semaphores[i]);); + VK_CHECK(vkCreateSemaphore(context.device->logical_device, &semaphore_info, context.allocator, + &context.render_finished_semaphores[i]);); + + VK_CHECK(vkCreateFence(context.device->logical_device, &fence_info, context.allocator, + &context.in_flight_fences[i])); + } +} diff --git a/src/renderer/render.c b/src/renderer/render.c index 799cba7..f73578e 100644 --- a/src/renderer/render.c +++ b/src/renderer/render.c @@ -61,7 +61,9 @@ bool renderer_init(renderer* ren) { return true; } void renderer_shutdown(renderer* ren) { - // gpu_device_destroy(ren->device); + gpu_swapchain_destroy(&ren->swapchain); + gpu_pipeline_destroy(&ren->static_opaque_pipeline); + gpu_backend_shutdown(); } void default_pipelines_init(renderer* ren) { @@ -77,4 +79,4 @@ void render_frame_draw(renderer* ren) {} void gfx_backend_draw_frame(renderer* ren, camera* camera, mat4 model, texture* tex) {} -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) {} -- cgit v1.2.3-70-g09d2 From 3a0557d98ba311b031ad53ceb8fc6025013f65dc Mon Sep 17 00:00:00 2001 From: Omniscient <17525998+omnisci3nce@users.noreply.github.com> Date: Thu, 9 May 2024 18:03:03 +1000 Subject: fix some validation errors --- examples/triangle/ex_triangle.c | 4 +++- src/core.c | 4 ++-- src/renderer/backends/backend_vulkan.c | 29 +++++++++++++++++++++++------ src/renderer/ral.h | 4 ++-- 4 files changed, 30 insertions(+), 11 deletions(-) (limited to 'examples/triangle') diff --git a/examples/triangle/ex_triangle.c b/examples/triangle/ex_triangle.c index 1f7ef5e..3a9b7db 100644 --- a/examples/triangle/ex_triangle.c +++ b/examples/triangle/ex_triangle.c @@ -53,7 +53,9 @@ int main() { static f64 x = 0.0; x += 0.01; - gpu_backend_begin_frame(); + if (!gpu_backend_begin_frame()) { + continue; + } gpu_cmd_encoder* enc = gpu_get_default_cmd_encoder(); // begin recording gpu_cmd_encoder_begin(*enc); diff --git a/src/core.c b/src/core.c index a853637..cd6ff88 100644 --- a/src/core.c +++ b/src/core.c @@ -57,8 +57,8 @@ core* core_bringup() { #include "input.h" #include "render.h" -bool should_window_close(core *core) { glfwWindowShouldClose(core->renderer.window); } -void core_input_update(core *core) { input_update(&core->input); } +bool should_window_close(core* core) { glfwWindowShouldClose(core->renderer.window); } +void core_input_update(core* core) { input_update(&core->input); } void core_frame_begin(core* core) { render_frame_begin(&core->renderer); } void core_frame_end(core* core) { render_frame_end(&core->renderer); } diff --git a/src/renderer/backends/backend_vulkan.c b/src/renderer/backends/backend_vulkan.c index 50f9662..5390f1f 100644 --- a/src/renderer/backends/backend_vulkan.c +++ b/src/renderer/backends/backend_vulkan.c @@ -51,6 +51,8 @@ typedef struct vulkan_context { u32 screen_width; u32 screen_height; + bool is_resizing; + GLFWwindow* window; VkDebugUtilsMessengerEXT vk_debugger; } vulkan_context; @@ -80,6 +82,7 @@ bool gpu_backend_init(const char* window_name, GLFWwindow* window) { context.allocator = 0; // TODO: use an allocator context.screen_width = SCREEN_WIDTH; context.screen_height = SCREEN_HEIGHT; + context.window = window; context.current_img_index = 0; context.current_frame = 0; @@ -304,7 +307,9 @@ bool gpu_swapchain_create(gpu_swapchain* out_swapchain) { void gpu_swapchain_destroy(gpu_swapchain* swapchain) { // Destroy Framebuffers + DEBUG("Image count %d", swapchain->image_count); for (u32 i = 0; i < swapchain->image_count; i++) { + DEBUG("Framebuffer handle %d", context.swapchain_framebuffers[i]); vkDestroyFramebuffer(context.device->logical_device, context.swapchain_framebuffers[i], context.allocator); } @@ -312,11 +317,18 @@ void gpu_swapchain_destroy(gpu_swapchain* swapchain) { vkDestroyImageView(context.device->logical_device, swapchain->image_views[i], context.allocator); } - arena_free_storage(&swapchain->swapchain_arena); + arena_free_all(&swapchain->swapchain_arena); vkDestroySwapchainKHR(context.device->logical_device, swapchain->handle, context.allocator); + TRACE("Vulkan Swapchain destroyed"); } static void recreate_swapchain(gpu_swapchain* swapchain) { + int width = 0, height = 0; + glfwGetFramebufferSize(context.window, &width, &height); + while (width == 0 || height == 0) { + glfwGetFramebufferSize(context.window, &width, &height); + glfwWaitEvents(); + } DEBUG("Recreating swapchain..."); vkDeviceWaitIdle(context.device->logical_device); @@ -682,27 +694,30 @@ void encode_set_default_settings(gpu_cmd_encoder* encoder) { // --- Drawing -void gpu_backend_begin_frame() { +bool gpu_backend_begin_frame() { u32 current_frame = context.current_frame; - // TRACE("gpu_backend_begin_frame"); vkWaitForFences(context.device->logical_device, 1, &context.in_flight_fences[current_frame], VK_TRUE, UINT64_MAX); - vkResetFences(context.device->logical_device, 1, &context.in_flight_fences[current_frame]); u32 image_index; VkResult result = vkAcquireNextImageKHR( context.device->logical_device, context.swapchain->handle, UINT64_MAX, context.image_available_semaphores[current_frame], VK_NULL_HANDLE, &image_index); - if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) { + if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || context.is_resizing) { + ERROR("Acquire next image failure. recreate swapchain"); + context.is_resizing = false; recreate_swapchain(context.swapchain); - return; + return false; } else if (result != VK_SUCCESS) { ERROR_EXIT("failed to acquire swapchain image"); } + vkResetFences(context.device->logical_device, 1, &context.in_flight_fences[current_frame]); + context.current_img_index = image_index; /* printf("Current img: %d\n", context.current_img_index); */ VK_CHECK(vkResetCommandBuffer(context.main_cmd_bufs[current_frame].cmd_buffer, 0)); + return true; } void gpu_temp_draw() { @@ -722,6 +737,7 @@ void gpu_backend_end_frame() { VkResult result = vkQueuePresentKHR(context.device->present_queue, &present_info); if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) { + ERROR("Queue present error. recreate swapchain"); recreate_swapchain(context.swapchain); return; } else if (result != VK_SUCCESS) { @@ -918,6 +934,7 @@ VkShaderModule create_shader_module(str8 spirv) { } void create_swapchain_framebuffers() { + WARN("Recreating framebuffers..."); u32 image_count = context.swapchain->image_count; context.swapchain_framebuffers = arena_alloc(&context.swapchain->swapchain_arena, image_count * sizeof(VkFramebuffer)); diff --git a/src/renderer/ral.h b/src/renderer/ral.h index 416370f..ec9793e 100644 --- a/src/renderer/ral.h +++ b/src/renderer/ral.h @@ -69,7 +69,7 @@ bool gpu_backend_init(const char* window_name, struct GLFWwindow* window); void gpu_backend_shutdown(); // TEMP -void gpu_backend_begin_frame(); +bool gpu_backend_begin_frame(); void gpu_backend_end_frame(); bool gpu_device_create(gpu_device* out_device); @@ -137,4 +137,4 @@ bytebuffer vertices_as_bytebuffer(arena* a, vertex_format format, vertex_darray* // TEMP -void gpu_temp_draw(); \ No newline at end of file +void gpu_temp_draw(); -- cgit v1.2.3-70-g09d2 From f7944239b793d1d5c49336856965d3a793f99316 Mon Sep 17 00:00:00 2001 From: Omniscient <17525998+omnisci3nce@users.noreply.github.com> Date: Fri, 10 May 2024 13:24:05 +1000 Subject: make core a static and add a default scene to it --- examples/triangle/ex_triangle.c | 14 ++++++---- src/core.c | 35 +++++++++++------------ src/core.h | 16 +++++++---- src/maths/maths_types.h | 3 +- src/renderer/archive/render_types.h | 30 ++++++++++---------- src/renderer/render_types.h | 33 ++++++++++++++++++---- src/scene.c | 56 +++++++++++++++++++++++++++++++++++++ src/scene.h | 42 ++++++++++++++++++++-------- 8 files changed, 165 insertions(+), 64 deletions(-) create mode 100644 src/scene.c (limited to 'examples/triangle') diff --git a/examples/triangle/ex_triangle.c b/examples/triangle/ex_triangle.c index 3a9b7db..97d6484 100644 --- a/examples/triangle/ex_triangle.c +++ b/examples/triangle/ex_triangle.c @@ -12,8 +12,10 @@ // Example setting up a renderer +extern core g_core; + int main() { - core* core = core_bringup(); + core_bringup(); arena scratch = arena_create(malloc(1024 * 1024), 1024 * 1024); gpu_renderpass_desc pass_description = {}; @@ -44,11 +46,11 @@ int main() { gpu_pipeline* gfx_pipeline = gpu_graphics_pipeline_create(pipeline_description); // Main loop - while (!should_exit(core)) { + while (!should_exit(&g_core)) { glfwPollEvents(); - input_update(&core->input); + input_update(&g_core.input); - render_frame_begin(&core->renderer); + render_frame_begin(&g_core.renderer); static f64 x = 0.0; x += 0.01; @@ -74,11 +76,11 @@ int main() { // Submit gpu_backend_end_frame(); - render_frame_end(&core->renderer); + render_frame_end(&g_core.renderer); // glfwSwapBuffers(core->renderer.window); } - renderer_shutdown(&core->renderer); + renderer_shutdown(&g_core.renderer); return 0; } diff --git a/src/core.c b/src/core.c index cd6ff88..3596e01 100644 --- a/src/core.c +++ b/src/core.c @@ -13,25 +13,28 @@ #define SCR_WIDTH 1000 #define SCR_HEIGHT 1000 -core* core_bringup() { +core g_core; /** @brief global `core` that other files can use */ + +inline core* get_global_core() { return &g_core; } + +void core_bringup() { INFO("Initiate Core bringup"); - core* c = malloc(sizeof(core)); renderer_config conf = { .window_name = { "Celeritas Engine Core" }, .scr_width = SCR_WIDTH, .scr_height = SCR_HEIGHT, .clear_colour = (vec3){ .08, .08, .1 } }; - c->renderer.config = conf; - c->renderer.backend_context = NULL; + g_core.renderer.config = conf; + g_core.renderer.backend_context = NULL; // threadpool_create(&c->threadpool, 6, 256); // threadpool_set_ctx(&c->threadpool, c); // Gives the threadpool access to the core // initialise all subsystems - if (!renderer_init(&c->renderer)) { + if (!renderer_init(&g_core.renderer)) { // FATAL("Failed to start renderer"); ERROR_EXIT("Failed to start renderer\n"); } - if (!input_system_init(&c->input, c->renderer.window)) { + if (!input_system_init(&g_core.input, g_core.renderer.window)) { // the input system needs the glfw window which is created by the renderer // hence the order here is important FATAL("Failed to start input system"); @@ -48,26 +51,22 @@ core* core_bringup() { } */ - c->models = model_darray_new(10); - - return c; + g_core.models = model_darray_new(10); } #include -#include "input.h" -#include "render.h" bool should_window_close(core* core) { glfwWindowShouldClose(core->renderer.window); } -void core_input_update(core* core) { input_update(&core->input); } +void core_input_update() { input_update(&g_core.input); } void core_frame_begin(core* core) { render_frame_begin(&core->renderer); } void core_frame_end(core* core) { render_frame_end(&core->renderer); } -void core_shutdown(core* core) { +void core_shutdown() { // threadpool_destroy(&core->threadpool); - input_system_shutdown(&core->input); - renderer_shutdown(&core->renderer); + input_system_shutdown(&g_core.input); + renderer_shutdown(&g_core.renderer); } -bool should_exit(core* core) { - return key_just_released(KEYCODE_ESCAPE) || glfwWindowShouldClose(core->renderer.window); -} \ No newline at end of file +bool should_exit() { + return key_just_released(KEYCODE_ESCAPE) || glfwWindowShouldClose(g_core.renderer.window); +} diff --git a/src/core.h b/src/core.h index a122448..ec8cde9 100644 --- a/src/core.h +++ b/src/core.h @@ -1,9 +1,8 @@ #pragma once -#include "defines.h" #include "input.h" -#include "ral.h" #include "screenspace.h" +#include "scene.h" #include "terrain.h" #include "text.h" // #include "threadpool.h" @@ -19,12 +18,17 @@ typedef struct core { terrain_state terrain; screenspace_state screenspace; // data storage + scene default_scene; model_darray* models; } core; +core* get_global_core(); + // --- Lifecycle -core* core_bringup(); -void core_shutdown(core* core); -bool should_exit(core* core); -void core_input_update(core* core); +/** @brief Throws error if the core cannot be instantiated */ +void core_bringup(); +void core_shutdown(); +bool should_exit(); + +void core_input_update(); diff --git a/src/maths/maths_types.h b/src/maths/maths_types.h index aa86eb0..5ef09db 100644 --- a/src/maths/maths_types.h +++ b/src/maths/maths_types.h @@ -61,6 +61,7 @@ typedef struct transform { f32 scale; bool is_dirty; } transform; +typedef transform transform3d; typedef struct vec4i { i32 x, y, z, w; @@ -99,4 +100,4 @@ typedef struct vec2 f32x2; #define f32x2(x, y) ((f32x2){ x, y }) typedef struct vec3 f32x3; -#define f32x3(x, y, z) ((f32x3){ x, y, z }) \ No newline at end of file +#define f32x3(x, y, z) ((f32x3){ x, y, z }) diff --git a/src/renderer/archive/render_types.h b/src/renderer/archive/render_types.h index 13a6651..f5ea986 100644 --- a/src/renderer/archive/render_types.h +++ b/src/renderer/archive/render_types.h @@ -94,20 +94,20 @@ KITC_DECL_TYPED_ARRAY(animation_clip) // creates "material_darray" #endif // // lights -// typedef struct point_light { -// vec3 position; -// f32 constant, linear, quadratic; -// vec3 ambient; -// vec3 diffuse; -// vec3 specular; -// } point_light; - -// typedef struct directional_light { -// vec3 direction; -// vec3 ambient; -// vec3 diffuse; -// vec3 specular; -// } directional_light; +typedef struct point_light { + vec3 position; + f32 constant, linear, quadratic; + vec3 ambient; + vec3 diffuse; + vec3 specular; +} point_light; + +typedef struct directional_light { + vec3 direction; + vec3 ambient; + vec3 diffuse; + vec3 specular; +} directional_light; // void point_light_upload_uniforms(shader shader, point_light *light, char index); // void dir_light_upload_uniforms(shader shader, directional_light *light); @@ -207,4 +207,4 @@ typedef struct model { // // typedef enum pipeline_kind { // // GRAPHICS, // // COMPUTE, -// // } pipeline_kind; \ No newline at end of file +// // } pipeline_kind; diff --git a/src/renderer/render_types.h b/src/renderer/render_types.h index 08b9e94..3763967 100644 --- a/src/renderer/render_types.h +++ b/src/renderer/render_types.h @@ -116,10 +116,31 @@ KITC_DECL_TYPED_ARRAY(animation_clip) /** @brief Describes all the data required for the renderer to start executing draws */ typedef struct render_entity { - buffer_handle index_buffer; - u32 index_count; - u32 index_offset; - buffer_handle vertex_buffer; - material* material; + /* buffer_handle index_buffer; */ + /* u32 index_count; */ + /* u32 index_offset; */ + /* buffer_handle vertex_buffer; */ + model_handle model; transform tf; -} render_entity; \ No newline at end of file +} render_entity; + +#ifndef TYPED_RENDER_ENTITY_ARRAY +KITC_DECL_TYPED_ARRAY(render_entity) +#define TYPED_RENDER_ENTITY_ARRAY +#endif + +// --- Lights +typedef struct point_light { + vec3 position; + f32 constant, linear, quadratic; + vec3 ambient; + vec3 diffuse; + vec3 specular; +} point_light; + +typedef struct directional_light { + vec3 direction; + vec3 ambient; + vec3 diffuse; + vec3 specular; +} directional_light; diff --git a/src/scene.c b/src/scene.c new file mode 100644 index 0000000..d9fea05 --- /dev/null +++ b/src/scene.c @@ -0,0 +1,56 @@ +#include "scene.h" +#include "core.h" +#include "log.h" +#include "maths.h" +#include "render_types.h" + +extern core g_core; + +void scene_init(scene *s) { + memset(s, 0, sizeof(scene)); + s->renderables = render_entity_darray_new(10); + // default camera position - moved slightly along Z axis looking at 0,0,0 + vec3 cam_pos = vec3_create(0, 0, -5); + s->camera = camera_create(cam_pos, vec3_negate(cam_pos), VEC3_Y, deg_to_rad(45.0)); +} +void scene_free(scene *s) { render_entity_darray_free(s->renderables); } + +void scene_set_dir_light(directional_light light) { g_core.default_scene.dir_light = light; } +void scene_add_point_light(point_light light) { + scene s = g_core.default_scene; + if (s.point_lights_count == 4) { + WARN("Already 4 point lights, we can't add more."); + } else { + s.point_lights[s.point_lights_count] = light; + s.point_lights_count++; + } +} +void scene_add_model(model_handle model, transform3d transform) { + render_entity renderable = { .model = model, .tf = transform }; + render_entity_darray_push(g_core.default_scene.renderables, renderable); +} + +bool scene_remove_model(model_handle model) { + scene s = g_core.default_scene; + for (u32 i = 0; i <= s.renderables->len; i++) { + if (s.renderables->data[i].model.raw == model.raw) { + // TODO: add remove function to darray + } + } + return true; +} + +void scene_set_model_transform(model_handle model, transform3d new_transform) { + scene s = g_core.default_scene; + for (u32 i = 0; i <= s.renderables->len; i++) { + if (s.renderables->data[i].model.raw == model.raw) { + s.renderables->data[i].tf = new_transform; + } + } +} + +void scene_set_camera(vec3 pos, vec3 front) { + scene s = g_core.default_scene; + s.camera.position = pos; + s.camera.front = front; +} diff --git a/src/scene.h b/src/scene.h index 6cac061..5399ab7 100644 --- a/src/scene.h +++ b/src/scene.h @@ -8,23 +8,41 @@ * @copyright Copyright (c) 2024 * */ +#pragma once +#include "camera.h" #include "defines.h" -#include "types.h" +#include "render_types.h" +#include "maths_types.h" typedef struct scene { - // directional_light dir_light; - // point_light point_lights[4]; - // size_t n_point_lights; + // camera + camera camera; + // lights + directional_light dir_light; + point_light point_lights[4]; + size_t point_lights_count; + // geometry + render_entity_darray* renderables; + // TODO: tree - transform_hierarchy } scene; -bool scene_add_directional_light(scene* s /* TODO */); -bool scene_add_point_light(scene* s /* TODO */); +void scene_init(scene* s); +void scene_free(scene* s); -// There can only be one heightmap terrain at a time right now. -bool scene_add_heightmap(scene* s /* TODO */); -bool scene_delete_heightmap(scene* s); +// Simplified API - no scene pointer; gets and sets global scene -bool scene_add_model(scene* s, model_handle model); -void scene_remove_model(scene* s, model_handle model); +// Add/Remove objects from the scene +void scene_set_dir_light(directional_light light); +void scene_add_point_light(point_light light); +void scene_add_model(model_handle model, transform3d transform); +bool scene_remove_model(model_handle model); -// TODO: functions to load and save scenes from disk \ No newline at end of file +// Getter & Setters +void scene_set_model_transform(model_handle model, transform3d new_transform); +void scene_set_camera(vec3 pos, vec3 front); + +/* // There can only be one heightmap terrain at a time right now. */ +/* bool scene_add_heightmap(scene* s /\* TODO *\/); */ +/* bool scene_delete_heightmap(scene* s); */ + +// TODO: functions to load and save scenes from disk -- cgit v1.2.3-70-g09d2 From 78275161e08df050d3439f16ef88de8e421c6f8b Mon Sep 17 00:00:00 2001 From: Omniscient <17525998+omnisci3nce@users.noreply.github.com> Date: Fri, 10 May 2024 13:36:03 +1000 Subject: initiate scene when bringing up core --- examples/triangle/ex_triangle.c | 2 ++ src/core.c | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'examples/triangle') diff --git a/examples/triangle/ex_triangle.c b/examples/triangle/ex_triangle.c index 97d6484..7b8a1d0 100644 --- a/examples/triangle/ex_triangle.c +++ b/examples/triangle/ex_triangle.c @@ -18,6 +18,8 @@ int main() { core_bringup(); arena scratch = arena_create(malloc(1024 * 1024), 1024 * 1024); + DEBUG("render capacity %d", g_core.default_scene.renderables->capacity); + gpu_renderpass_desc pass_description = {}; gpu_renderpass* renderpass = gpu_renderpass_create(&pass_description); diff --git a/src/core.c b/src/core.c index 3596e01..17424b3 100644 --- a/src/core.c +++ b/src/core.c @@ -8,6 +8,7 @@ #include "log.h" #include "render.h" #include "render_types.h" +#include "scene.h" // #include "threadpool.h" #define SCR_WIDTH 1000 @@ -51,7 +52,8 @@ void core_bringup() { } */ - g_core.models = model_darray_new(10); + INFO("Creating default scene"); + scene_init(&g_core.default_scene); } #include -- cgit v1.2.3-70-g09d2 From eedd332680dbdd367197616658903f00252f5a9c Mon Sep 17 00:00:00 2001 From: Omniscient <17525998+omnisci3nce@users.noreply.github.com> Date: Sat, 11 May 2024 00:22:13 +1000 Subject: upload data using staging buffer. use vertex buffer data --- assets/shaders/triangle.vert | 11 ++- examples/triangle/ex_triangle.c | 23 ++++- src/core.c | 9 +- src/core.h | 2 +- src/maths/maths.h | 5 +- src/renderer/backends/backend_vulkan.c | 170 +++++++++++++++++++++++++++++++-- src/renderer/backends/backend_vulkan.h | 8 +- src/renderer/ral.h | 7 +- src/renderer/ral_types.h | 22 ++++- src/renderer/render.c | 43 ++++----- src/scene.h | 2 +- 11 files changed, 250 insertions(+), 52 deletions(-) (limited to 'examples/triangle') diff --git a/assets/shaders/triangle.vert b/assets/shaders/triangle.vert index ee3675d..b8c8f63 100644 --- a/assets/shaders/triangle.vert +++ b/assets/shaders/triangle.vert @@ -1,12 +1,13 @@ #version 450 -vec2 positions[3] = vec2[](vec2(-0.5, 0.5), vec2(0.5, 0.5), vec2(0.0, -0.5)); - -vec3 colors[3] = vec3[](vec3(1.0, 0.0, 0.0), vec3(0.0, 1.0, 0.0), vec3(0.0, 0.0, 1.0)); +layout(location = 0) in vec2 inPos; +layout(location = 1) in vec3 inColor; +// layout(location = 1) in vec3 inNormal; +// layout(location = 2) in vec2 inTexCoords; layout(location = 0) out vec3 fragColor; void main() { - gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0); - fragColor = colors[gl_VertexIndex]; + gl_Position = vec4(inPos, 0.0, 1.0); + fragColor = inColor; } diff --git a/examples/triangle/ex_triangle.c b/examples/triangle/ex_triangle.c index 7b8a1d0..c4f90f2 100644 --- a/examples/triangle/ex_triangle.c +++ b/examples/triangle/ex_triangle.c @@ -1,6 +1,7 @@ #include #include "backend_vulkan.h" +#include "buf.h" #include "camera.h" #include "core.h" #include "file.h" @@ -8,12 +9,20 @@ #include "maths.h" #include "mem.h" #include "ral.h" +#include "ral_types.h" #include "render.h" // Example setting up a renderer 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.0, -0.5), .color = vec3(1.0, 0.0, 0.0) }, +}; +_Static_assert(sizeof(vertices) == (5 * 3 * sizeof(float)), ""); + int main() { core_bringup(); arena scratch = arena_create(malloc(1024 * 1024), 1024 * 1024); @@ -47,12 +56,19 @@ int main() { }; gpu_pipeline* gfx_pipeline = gpu_graphics_pipeline_create(pipeline_description); + buffer_handle triangle_vert_buf = gpu_buffer_create( + 3 * sizeof(custom_vertex), CEL_BUFFER_VERTEX, CEL_BUFFER_FLAG_GPU, + vertices); // gpu_buffer_create(3 * sizeof(custom_vertex), CEL_BUFFER_VERTEX); + /* buffer_upload_bytes(triangle_vert_buf, (bytebuffer){ .buf = vertices, .size = sizeof(vertices) + * }, */ + /* 0, sizeof(vertices)); */ + // Main loop while (!should_exit(&g_core)) { glfwPollEvents(); input_update(&g_core.input); - render_frame_begin(&g_core.renderer); + // render_frame_begin(&g_core.renderer); static f64 x = 0.0; x += 0.01; @@ -68,7 +84,8 @@ int main() { encode_set_default_settings(enc); // Record draw calls - gpu_temp_draw(); + encode_set_vertex_buffer(enc, triangle_vert_buf); + gpu_temp_draw(3); // End recording gpu_cmd_encoder_end_render(enc); @@ -78,7 +95,7 @@ int main() { // Submit gpu_backend_end_frame(); - render_frame_end(&g_core.renderer); + // render_frame_end(&g_core.renderer); // glfwSwapBuffers(core->renderer.window); } diff --git a/src/core.c b/src/core.c index 26e7613..84c9cae 100644 --- a/src/core.c +++ b/src/core.c @@ -59,9 +59,7 @@ void core_bringup() { #include /* bool should_window_close(core* core) { glfwWindowShouldClose(core->renderer.window); } */ -void core_input_update() { - input_update(&g_core.input); -} +void core_input_update() { input_update(&g_core.input); } void core_frame_begin(core* core) { render_frame_begin(&core->renderer); } void core_frame_end(core* core) { render_frame_end(&core->renderer); } @@ -76,7 +74,8 @@ bool should_exit() { } void frame_begin() { - glfwPollEvents(); - render_frame_begin(&g_core.renderer); } + glfwPollEvents(); + render_frame_begin(&g_core.renderer); +} void frame_draw() {} void frame_end() { render_frame_end(&g_core.renderer); } diff --git a/src/core.h b/src/core.h index db711d0..1031868 100644 --- a/src/core.h +++ b/src/core.h @@ -1,8 +1,8 @@ #pragma once #include "input.h" -#include "screenspace.h" #include "scene.h" +#include "screenspace.h" #include "terrain.h" #include "text.h" // #include "threadpool.h" diff --git a/src/maths/maths.h b/src/maths/maths.h index 88a5215..217f2e0 100644 --- a/src/maths/maths.h +++ b/src/maths/maths.h @@ -21,7 +21,7 @@ // Dimension 3 static inline vec3 vec3_create(f32 x, f32 y, f32 z) { return (vec3){ x, y, z }; } -#define vec3(x, y, z) (vec3_create(x, y, z)) +#define vec3(x, y, z) ((vec3){ x, y, z }) static inline vec3 vec3_add(vec3 a, vec3 b) { return (vec3){ a.x + b.x, a.y + b.y, a.z + b.z }; } static inline vec3 vec3_sub(vec3 a, vec3 b) { return (vec3){ a.x - b.x, a.y - b.y, a.z - b.z }; } static inline vec3 vec3_mult(vec3 a, f32 s) { return (vec3){ a.x * s, a.y * s, a.z * s }; } @@ -53,6 +53,7 @@ static inline void print_vec3(vec3 v) { printf("{ x: %f, y: %f, z: %f )\n", v.x, // TODO: Dimension 2 static inline vec2 vec2_create(f32 x, f32 y) { return (vec2){ x, y }; } +#define vec2(x, y) ((vec2){ x, y }) static inline vec2 vec2_div(vec2 a, f32 s) { return (vec2){ a.x / s, a.y / s }; } // TODO: Dimension 4 @@ -320,4 +321,4 @@ static inline mat4 transform_to_mat(transform *tf) { _Static_assert(alignof(vec3) == 4, "vec3 is 4 byte aligned"); _Static_assert(sizeof(vec3) == 12, "vec3 is 12 bytes so has no padding"); -_Static_assert(alignof(vec4) == 4, "vec4 is 4 byte aligned"); \ No newline at end of file +_Static_assert(alignof(vec4) == 4, "vec4 is 4 byte aligned"); diff --git a/src/renderer/backends/backend_vulkan.c b/src/renderer/backends/backend_vulkan.c index 5390f1f..e30d3c1 100644 --- a/src/renderer/backends/backend_vulkan.c +++ b/src/renderer/backends/backend_vulkan.c @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -8,8 +9,10 @@ #include #include "backend_vulkan.h" +#include "buf.h" #include "maths_types.h" #include "mem.h" +#include "ral_types.h" #include "str.h" #include "vulkan_helpers.h" @@ -54,6 +57,10 @@ typedef struct vulkan_context { bool is_resizing; GLFWwindow* window; + // Storage + gpu_buffer buffers[1024]; + size_t buffer_count; + VkDebugUtilsMessengerEXT vk_debugger; } vulkan_context; @@ -366,17 +373,31 @@ gpu_pipeline* gpu_graphics_pipeline_create(struct graphics_pipeline_desc descrip VkPipelineShaderStageCreateInfo shader_stages[2] = { vert_shader_stage_info, frag_shader_stage_info }; - // Vertex Input - // TODO: Attributes + VkVertexInputAttributeDescription attribute_descs[2]; + attribute_descs[0].binding = 0; + attribute_descs[0].location = 0; + attribute_descs[0].format = VK_FORMAT_R32G32_SFLOAT; + attribute_descs[0].offset = offsetof(custom_vertex, pos); + + attribute_descs[1].binding = 0; + attribute_descs[1].location = 1; + attribute_descs[1].format = VK_FORMAT_R32G32B32_SFLOAT; + attribute_descs[1].offset = offsetof(custom_vertex, color); + + // Vertex input + VkVertexInputBindingDescription binding_desc; + binding_desc.binding = 0; + binding_desc.stride = sizeof(custom_vertex); + binding_desc.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; VkPipelineVertexInputStateCreateInfo vertex_input_info = { VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO }; - vertex_input_info.vertexBindingDescriptionCount = 0; - vertex_input_info.pVertexBindingDescriptions = NULL; - vertex_input_info.vertexAttributeDescriptionCount = 0; - vertex_input_info.pVertexAttributeDescriptions = NULL; + vertex_input_info.vertexBindingDescriptionCount = 1; + vertex_input_info.pVertexBindingDescriptions = &binding_desc; + vertex_input_info.vertexAttributeDescriptionCount = 2; + vertex_input_info.pVertexAttributeDescriptions = attribute_descs; // Input Assembly VkPipelineInputAssemblyStateCreateInfo input_assembly = { @@ -633,6 +654,10 @@ gpu_cmd_encoder gpu_cmd_encoder_create() { return encoder; } +void gpu_cmd_encoder_destroy(gpu_cmd_encoder* encoder) { + vkFreeCommandBuffers(context.device->logical_device, context.device->pool, 1, + &encoder->cmd_buffer); +} void gpu_cmd_encoder_begin(gpu_cmd_encoder encoder) { VkCommandBufferBeginInfo begin_info = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO }; @@ -674,6 +699,12 @@ gpu_cmd_buffer gpu_cmd_encoder_finish(gpu_cmd_encoder* encoder) { 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); } +void encode_set_vertex_buffer(gpu_cmd_encoder* encoder, buffer_handle buf) { + gpu_buffer buffer = context.buffers[buf.raw]; + VkBuffer vbs[] = { buffer.handle }; + VkDeviceSize offsets[] = { 0 }; + vkCmdBindVertexBuffers(encoder->cmd_buffer, 0, 1, vbs, offsets); +} // TEMP void encode_set_default_settings(gpu_cmd_encoder* encoder) { @@ -720,9 +751,9 @@ bool gpu_backend_begin_frame() { return true; } -void gpu_temp_draw() { +void gpu_temp_draw(size_t n_verts) { gpu_cmd_encoder* encoder = gpu_get_default_cmd_encoder(); // &context.main_cmd_buf; - vkCmdDraw(encoder->cmd_buffer, 3, 1, 0, 0); + vkCmdDraw(encoder->cmd_buffer, n_verts, 1, 0, 0); } void gpu_backend_end_frame() { @@ -971,3 +1002,126 @@ void create_sync_objects() { &context.in_flight_fences[i])); } } + +static i32 find_memory_index(u32 type_filter, u32 property_flags) { + VkPhysicalDeviceMemoryProperties memory_properties; + vkGetPhysicalDeviceMemoryProperties(context.device->physical_device, &memory_properties); + + for (u32 i = 0; i < memory_properties.memoryTypeCount; ++i) { + // Check each memory type to see if its bit is set to 1. + if (type_filter & (1 << i) && + (memory_properties.memoryTypes[i].propertyFlags & property_flags) == property_flags) { + return i; + } + } + + WARN("Unable to find suitable memory type!"); + return -1; +} + +buffer_handle gpu_buffer_create(u64 size, gpu_buffer_type buf_type, gpu_buffer_flags flags, + const void* data) { + VkBufferCreateInfo buffer_info = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; + buffer_info.size = size; + buffer_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; + + switch (buf_type) { + case CEL_BUFFER_DEFAULT: + buffer_info.usage |= VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; + break; + case CEL_BUFFER_VERTEX: + buffer_info.usage |= VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; + break; + case CEL_BUFFER_COUNT: + WARN("Incorrect gpu_buffer_type provided. using default"); + break; + } + + buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + + // "allocating" the cpu-side buffer struct + gpu_buffer buffer; + buffer.size = size; + buffer_handle handle = { .raw = (u32)context.buffer_count }; + + VK_CHECK(vkCreateBuffer(context.device->logical_device, &buffer_info, context.allocator, + &buffer.handle)); + + VkMemoryRequirements requirements; + vkGetBufferMemoryRequirements(context.device->logical_device, buffer.handle, &requirements); + + // Just make them always need all of them for now + i32 memory_index = + find_memory_index(requirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | + VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); + + // Allocate the actual VRAM + VkMemoryAllocateInfo allocate_info = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO }; + allocate_info.allocationSize = requirements.size; + allocate_info.memoryTypeIndex = (u32)memory_index; + + vkAllocateMemory(context.device->logical_device, &allocate_info, context.allocator, + &buffer.memory); + vkBindBufferMemory(context.device->logical_device, buffer.handle, buffer.memory, 0); + + /* Now there are two options: + * 1. create CPU-accessible memory -> map memory -> memcpy -> unmap + * 2. use a staging buffer thats CPU-accessible and copy its contents to a + * GPU-only buffer + */ + + context.buffers[context.buffer_count] = buffer; + context.buffer_count++; + + if (data) { + if (flags & CEL_BUFFER_FLAG_CPU) { + buffer_upload_bytes(handle, (bytebuffer){ .buf = (u8*)data, .size = size }, 0, size); + } else if (flags & CEL_BUFFER_FLAG_GPU) { + TRACE("Uploading data to buffer using staging buffer"); + buffer_handle staging = + gpu_buffer_create(size, CEL_BUFFER_DEFAULT, CEL_BUFFER_FLAG_CPU, data); + gpu_cmd_encoder temp_encoder = gpu_cmd_encoder_create(); + gpu_cmd_encoder_begin(temp_encoder); + encode_buffer_copy(&temp_encoder, handle, 0, staging, 0, size); + gpu_cmd_buffer copy_cmd_buffer = gpu_cmd_encoder_finish(&temp_encoder); + + VkSubmitInfo submit_info = { VK_STRUCTURE_TYPE_SUBMIT_INFO }; + submit_info.commandBufferCount = 1; + submit_info.pCommandBuffers = &temp_encoder.cmd_buffer; + vkQueueSubmit(context.device->graphics_queue, 1, &submit_info, VK_NULL_HANDLE); + + vkQueueWaitIdle(context.device->graphics_queue); + gpu_cmd_encoder_destroy(&temp_encoder); + gpu_buffer_destroy(staging); + } + } + + return handle; +} + +void gpu_buffer_destroy(buffer_handle buffer) { + gpu_buffer b = context.buffers[buffer.raw]; + vkDestroyBuffer(context.device->logical_device, b.handle, context.allocator); + vkFreeMemory(context.device->logical_device, b.memory, context.allocator); +} + +// Upload data to a +void buffer_upload_bytes(buffer_handle gpu_buf, bytebuffer cpu_buf, u64 offset, u64 size) { + gpu_buffer buffer = context.buffers[gpu_buf.raw]; + void* data_ptr; + vkMapMemory(context.device->logical_device, buffer.memory, 0, size, 0, &data_ptr); + memcpy(data_ptr, cpu_buf.buf, size); + vkUnmapMemory(context.device->logical_device, buffer.memory); +} + +void encode_buffer_copy(gpu_cmd_encoder* encoder, buffer_handle src, u64 src_offset, + buffer_handle dst, u64 dst_offset, u64 copy_size) { + VkBufferCopy copy_region; + copy_region.srcOffset = src_offset; + copy_region.dstOffset = dst_offset; + copy_region.size = copy_size; + + vkCmdCopyBuffer(encoder->cmd_buffer, context.buffers[src.raw].handle, + context.buffers[dst.raw].handle, 1, ©_region); +} diff --git a/src/renderer/backends/backend_vulkan.h b/src/renderer/backends/backend_vulkan.h index 330ba18..0b0a492 100644 --- a/src/renderer/backends/backend_vulkan.h +++ b/src/renderer/backends/backend_vulkan.h @@ -75,4 +75,10 @@ typedef struct gpu_cmd_encoder { typedef struct gpu_cmd_buffer { VkCommandBuffer cmd_buffer; -} gpu_cmd_buffer; \ No newline at end of file +} gpu_cmd_buffer; + +typedef struct gpu_buffer { + VkBuffer handle; + VkDeviceMemory memory; + u64 size; +} gpu_buffer; diff --git a/src/renderer/ral.h b/src/renderer/ral.h index ec9793e..2fb0166 100644 --- a/src/renderer/ral.h +++ b/src/renderer/ral.h @@ -28,6 +28,7 @@ typedef struct gpu_pipeline gpu_pipeline; typedef struct gpu_renderpass gpu_renderpass; 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; /** @brief A*/ // typedef struct gpu_bind_group @@ -85,6 +86,7 @@ bool gpu_swapchain_create(gpu_swapchain* out_swapchain); void gpu_swapchain_destroy(gpu_swapchain* swapchain); gpu_cmd_encoder gpu_cmd_encoder_create(); +void gpu_cmd_encoder_destroy(gpu_cmd_encoder* encoder); void gpu_cmd_encoder_begin(gpu_cmd_encoder encoder); void gpu_cmd_encoder_begin_render(gpu_cmd_encoder* encoder, gpu_renderpass* renderpass); void gpu_cmd_encoder_end_render(gpu_cmd_encoder* encoder); @@ -117,7 +119,8 @@ gpu_cmd_buffer gpu_cmd_encoder_finish(gpu_cmd_encoder* encoder); void gpu_queue_submit(gpu_cmd_buffer* buffer); // Buffers -void gpu_buffer_create(u64 size); +buffer_handle gpu_buffer_create(u64 size, gpu_buffer_type buf_type, gpu_buffer_flags flags, + const void* data); void gpu_buffer_destroy(buffer_handle buffer); void gpu_buffer_upload(); void gpu_buffer_bind(buffer_handle buffer); @@ -137,4 +140,4 @@ bytebuffer vertices_as_bytebuffer(arena* a, vertex_format format, vertex_darray* // TEMP -void gpu_temp_draw(); +void gpu_temp_draw(size_t n_verts); diff --git a/src/renderer/ral_types.h b/src/renderer/ral_types.h index ae54b53..7dd254e 100644 --- a/src/renderer/ral_types.h +++ b/src/renderer/ral_types.h @@ -55,6 +55,20 @@ typedef struct texture_desc { u32x2 extents; } texture_desc; +typedef enum gpu_buffer_type { + CEL_BUFFER_DEFAULT, // on Vulkan this would be a storage buffer? + CEL_BUFFER_VERTEX, + CEL_BUFFER_COUNT +} gpu_buffer_type; + +typedef enum gpu_buffer_flag { + CEL_BUFFER_FLAG_CPU = 1 << 0, + CEL_BUFFER_FLAG_GPU = 1 << 1, + CEL_BUFFER_FLAG_STORAGE = 1 << 2, + CEL_BUFFER_FLAG_COUNT +} gpu_buffer_flag; +typedef u32 gpu_buffer_flags; + typedef enum vertex_format { VERTEX_STATIC_3D, VERTEX_SPRITE, @@ -99,6 +113,12 @@ KITC_DECL_TYPED_ARRAY(u32) #define TYPED_VERTEX_ARRAY #endif +// TEMP +typedef struct custom_vertex { + vec2 pos; + vec3 color; +} custom_vertex; + typedef enum gpu_cull_mode { CULL_BACK_FACE, CULL_FRONT_FACE, CULL_COUNT } gpu_cull_mode; // ? How to tie together materials and shaders @@ -110,4 +130,4 @@ typedef enum gpu_cull_mode { CULL_BACK_FACE, CULL_FRONT_FACE, CULL_COUNT } gpu_c // 3 - you don't need to know how the renderer works at all // 2 - you need to know how the overall renderer is designed -// 1 - you need to understand graphics API specifics \ No newline at end of file +// 1 - you need to understand graphics API specifics diff --git a/src/renderer/render.c b/src/renderer/render.c index 10589e5..9f5b21a 100644 --- a/src/renderer/render.c +++ b/src/renderer/render.c @@ -55,7 +55,7 @@ bool renderer_init(renderer* ren) { // default_material_init(); // Create default rendering pipeline - default_pipelines_init(ren); + /* default_pipelines_init(ren); */ return true; } @@ -67,9 +67,6 @@ void renderer_shutdown(renderer* ren) { void default_pipelines_init(renderer* ren) { // Static opaque geometry - // graphics_pipeline_desc gfx = { - // }; - // ren->static_opaque_pipeline = gpu_graphics_pipeline_create(); arena scratch = arena_create(malloc(1024 * 1024), 1024 * 1024); gpu_renderpass_desc pass_description = {}; @@ -77,8 +74,8 @@ void default_pipelines_init(renderer* ren) { ren->default_renderpass = *renderpass; - str8 vert_path = str8lit("celeritas-core/build/linux/x86_64/debug/triangle.vert.spv"); - str8 frag_path = str8lit("celeritas-core/build/linux/x86_64/debug/triangle.frag.spv"); + str8 vert_path = str8lit("build/linux/x86_64/debug/triangle.vert.spv"); + str8 frag_path = str8lit("build/linux/x86_64/debug/triangle.frag.spv"); str8_opt vertex_shader = str8_from_file(&scratch, vert_path); str8_opt fragment_shader = str8_from_file(&scratch, frag_path); if (!vertex_shader.has_value || !fragment_shader.has_value) { @@ -104,28 +101,28 @@ void default_pipelines_init(renderer* ren) { } void render_frame_begin(renderer* ren) { - ren->frame_aborted = false; - if (!gpu_backend_begin_frame()) { - ren->frame_aborted = true; - return; - } - gpu_cmd_encoder* enc = gpu_get_default_cmd_encoder(); - // begin recording - gpu_cmd_encoder_begin(*enc); - gpu_cmd_encoder_begin_render(enc, &ren->default_renderpass); - encode_bind_pipeline(enc, PIPELINE_GRAPHICS, &ren->static_opaque_pipeline); - encode_set_default_settings(enc); + ren->frame_aborted = false; + if (!gpu_backend_begin_frame()) { + ren->frame_aborted = true; + return; + } + gpu_cmd_encoder* enc = gpu_get_default_cmd_encoder(); + // begin recording + gpu_cmd_encoder_begin(*enc); + gpu_cmd_encoder_begin_render(enc, &ren->default_renderpass); + encode_bind_pipeline(enc, PIPELINE_GRAPHICS, &ren->static_opaque_pipeline); + encode_set_default_settings(enc); } void render_frame_end(renderer* ren) { if (ren->frame_aborted) { return; } - gpu_temp_draw(); - gpu_cmd_encoder* enc = gpu_get_default_cmd_encoder(); - gpu_cmd_encoder_end_render(enc); - gpu_cmd_buffer buf = gpu_cmd_encoder_finish(enc); - gpu_queue_submit(&buf); - gpu_backend_end_frame(); + gpu_temp_draw(3); + gpu_cmd_encoder* enc = gpu_get_default_cmd_encoder(); + gpu_cmd_encoder_end_render(enc); + gpu_cmd_buffer buf = gpu_cmd_encoder_finish(enc); + gpu_queue_submit(&buf); + gpu_backend_end_frame(); } void render_frame_draw(renderer* ren) {} diff --git a/src/scene.h b/src/scene.h index 5399ab7..24429b3 100644 --- a/src/scene.h +++ b/src/scene.h @@ -11,8 +11,8 @@ #pragma once #include "camera.h" #include "defines.h" -#include "render_types.h" #include "maths_types.h" +#include "render_types.h" typedef struct scene { // camera -- cgit v1.2.3-70-g09d2 From fa6b939d49398a11d76080029204e7462b22914e Mon Sep 17 00:00:00 2001 From: Omniscient <17525998+omnisci3nce@users.noreply.github.com> Date: Sat, 11 May 2024 00:49:47 +1000 Subject: draw with indexes --- examples/triangle/ex_triangle.c | 19 ++++++++++--------- src/renderer/backends/backend_vulkan.c | 28 +++++++++++++++++++++++----- src/renderer/ral_types.h | 1 + 3 files changed, 34 insertions(+), 14 deletions(-) (limited to 'examples/triangle') diff --git a/examples/triangle/ex_triangle.c b/examples/triangle/ex_triangle.c index c4f90f2..dc82156 100644 --- a/examples/triangle/ex_triangle.c +++ b/examples/triangle/ex_triangle.c @@ -19,9 +19,10 @@ 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.0, -0.5), .color = vec3(1.0, 0.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) }, }; -_Static_assert(sizeof(vertices) == (5 * 3 * sizeof(float)), ""); +const u16 indices[] = { 0, 1, 2, 2, 3, 0 }; int main() { core_bringup(); @@ -56,12 +57,11 @@ int main() { }; gpu_pipeline* gfx_pipeline = gpu_graphics_pipeline_create(pipeline_description); - buffer_handle triangle_vert_buf = gpu_buffer_create( - 3 * sizeof(custom_vertex), CEL_BUFFER_VERTEX, CEL_BUFFER_FLAG_GPU, - vertices); // gpu_buffer_create(3 * sizeof(custom_vertex), CEL_BUFFER_VERTEX); - /* buffer_upload_bytes(triangle_vert_buf, (bytebuffer){ .buf = vertices, .size = sizeof(vertices) - * }, */ - /* 0, sizeof(vertices)); */ + buffer_handle triangle_vert_buf = + gpu_buffer_create(sizeof(vertices), CEL_BUFFER_VERTEX, CEL_BUFFER_FLAG_GPU, vertices); + + buffer_handle triangle_index_buf = + gpu_buffer_create(sizeof(indices), CEL_BUFFER_INDEX, CEL_BUFFER_FLAG_GPU, indices); // Main loop while (!should_exit(&g_core)) { @@ -85,7 +85,8 @@ int main() { // Record draw calls encode_set_vertex_buffer(enc, triangle_vert_buf); - gpu_temp_draw(3); + encode_set_index_buffer(enc, triangle_index_buf); + gpu_temp_draw(6); // End recording gpu_cmd_encoder_end_render(enc); diff --git a/src/renderer/backends/backend_vulkan.c b/src/renderer/backends/backend_vulkan.c index e30d3c1..dbae96e 100644 --- a/src/renderer/backends/backend_vulkan.c +++ b/src/renderer/backends/backend_vulkan.c @@ -706,6 +706,11 @@ void encode_set_vertex_buffer(gpu_cmd_encoder* encoder, buffer_handle buf) { vkCmdBindVertexBuffers(encoder->cmd_buffer, 0, 1, vbs, offsets); } +void encode_set_index_buffer(gpu_cmd_encoder* encoder, buffer_handle buf) { + gpu_buffer buffer = context.buffers[buf.raw]; + vkCmdBindIndexBuffer(encoder->cmd_buffer, buffer.handle, 0, VK_INDEX_TYPE_UINT16); +} + // TEMP void encode_set_default_settings(gpu_cmd_encoder* encoder) { VkViewport viewport = { 0 }; @@ -751,9 +756,10 @@ bool gpu_backend_begin_frame() { return true; } -void gpu_temp_draw(size_t n_verts) { +void gpu_temp_draw(size_t n_indices) { gpu_cmd_encoder* encoder = gpu_get_default_cmd_encoder(); // &context.main_cmd_buf; - vkCmdDraw(encoder->cmd_buffer, n_verts, 1, 0, 0); + /* vkCmdDraw(encoder->cmd_buffer, n_verts, 1, 0, 0); */ + vkCmdDrawIndexed(encoder->cmd_buffer, n_indices, 1, 0, 0, 0); } void gpu_backend_end_frame() { @@ -1032,6 +1038,9 @@ buffer_handle gpu_buffer_create(u64 size, gpu_buffer_type buf_type, gpu_buffer_f case CEL_BUFFER_VERTEX: buffer_info.usage |= VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; break; + case CEL_BUFFER_INDEX: + buffer_info.usage |= VK_BUFFER_USAGE_INDEX_BUFFER_BIT; + break; case CEL_BUFFER_COUNT: WARN("Incorrect gpu_buffer_type provided. using default"); break; @@ -1075,15 +1084,22 @@ buffer_handle gpu_buffer_create(u64 size, gpu_buffer_type buf_type, gpu_buffer_f context.buffer_count++; if (data) { + TRACE("Upload data as part of buffer creation"); if (flags & CEL_BUFFER_FLAG_CPU) { + // map memory -> copy data in -> unmap memory buffer_upload_bytes(handle, (bytebuffer){ .buf = (u8*)data, .size = size }, 0, size); } else if (flags & CEL_BUFFER_FLAG_GPU) { TRACE("Uploading data to buffer using staging buffer"); - buffer_handle staging = - gpu_buffer_create(size, CEL_BUFFER_DEFAULT, CEL_BUFFER_FLAG_CPU, data); + // Create a staging buffer + buffer_handle staging = gpu_buffer_create(size, buf_type, CEL_BUFFER_FLAG_CPU, NULL); + + // Copy data into it + buffer_upload_bytes(staging, (bytebuffer){ .buf = (u8*)data, .size = size }, 0, size); + + // Enqueue a copy from the staging buffer into the DEVICE_LOCAL buffer gpu_cmd_encoder temp_encoder = gpu_cmd_encoder_create(); gpu_cmd_encoder_begin(temp_encoder); - encode_buffer_copy(&temp_encoder, handle, 0, staging, 0, size); + encode_buffer_copy(&temp_encoder, staging, 0, handle, 0, size); gpu_cmd_buffer copy_cmd_buffer = gpu_cmd_encoder_finish(&temp_encoder); VkSubmitInfo submit_info = { VK_STRUCTURE_TYPE_SUBMIT_INFO }; @@ -1091,6 +1107,7 @@ buffer_handle gpu_buffer_create(u64 size, gpu_buffer_type buf_type, gpu_buffer_f submit_info.pCommandBuffers = &temp_encoder.cmd_buffer; vkQueueSubmit(context.device->graphics_queue, 1, &submit_info, VK_NULL_HANDLE); + // Cleanup vkQueueWaitIdle(context.device->graphics_queue); gpu_cmd_encoder_destroy(&temp_encoder); gpu_buffer_destroy(staging); @@ -1111,6 +1128,7 @@ void buffer_upload_bytes(buffer_handle gpu_buf, bytebuffer cpu_buf, u64 offset, gpu_buffer buffer = context.buffers[gpu_buf.raw]; void* data_ptr; vkMapMemory(context.device->logical_device, buffer.memory, 0, size, 0, &data_ptr); + DEBUG("Uploading %d bytes to buffer", size); memcpy(data_ptr, cpu_buf.buf, size); vkUnmapMemory(context.device->logical_device, buffer.memory); } diff --git a/src/renderer/ral_types.h b/src/renderer/ral_types.h index 7dd254e..2fa8258 100644 --- a/src/renderer/ral_types.h +++ b/src/renderer/ral_types.h @@ -58,6 +58,7 @@ typedef struct texture_desc { typedef enum gpu_buffer_type { CEL_BUFFER_DEFAULT, // on Vulkan this would be a storage buffer? CEL_BUFFER_VERTEX, + CEL_BUFFER_INDEX, CEL_BUFFER_COUNT } gpu_buffer_type; -- cgit v1.2.3-70-g09d2 From 08d7e23fd5ed95953822a72ba11d4b6cd96b2846 Mon Sep 17 00:00:00 2001 From: omniscient <17525998+omnisci3nce@users.noreply.github.com> Date: Sat, 11 May 2024 17:30:58 +1000 Subject: prototyping shader data --- examples/cube/ex_cube.c | 145 ++++++++++++++++++++++++++++++++++++++++ examples/triangle/ex_triangle.c | 22 ++---- src/renderer/ral.h | 1 + src/renderer/ral_types.h | 61 +++++++++++++++++ src/systems/input.c | 1 + 5 files changed, 213 insertions(+), 17 deletions(-) create mode 100644 examples/cube/ex_cube.c (limited to 'examples/triangle') diff --git a/examples/cube/ex_cube.c b/examples/cube/ex_cube.c new file mode 100644 index 0000000..71b7917 --- /dev/null +++ b/examples/cube/ex_cube.c @@ -0,0 +1,145 @@ +#include + +#include "buf.h" +#include "camera.h" +#include "core.h" +#include "file.h" +#include "log.h" +#include "maths.h" +#include "mem.h" +#include "ral.h" +#include "ral_types.h" +#include "render.h" + +extern core g_core; + +// Define the shader data +typedef struct mvp_uniforms { + mat4 model; + mat4 view; + mat4 projection; +} 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) }} + }; + if (has_data) { + b1.data.bytes.data = &d->model; + b2.data.bytes.data = &d->view; + b3.data.bytes.data = &d->projection; + } + return (shader_data_layout ){.name = "mvp_uniforms", .bindings = { + b1, b2, b3 + }}; +} + +int main() { + core_bringup(); + arena scratch = arena_create(malloc(1024 * 1024), 1024 * 1024); + + 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 + }; + + gpu_renderpass_desc pass_description = {}; + gpu_renderpass* renderpass = gpu_renderpass_create(&pass_description); + + str8 vert_path = str8lit("build/linux/x86_64/debug/triangle.vert.spv"); + str8 frag_path = str8lit("build/linux/x86_64/debug/triangle.frag.spv"); + str8_opt vertex_shader = str8_from_file(&scratch, vert_path); + str8_opt fragment_shader = str8_from_file(&scratch, frag_path); + if (!vertex_shader.has_value || !fragment_shader.has_value) { + ERROR_EXIT("Failed to load shaders from disk") + } + + struct graphics_pipeline_desc pipeline_description = { + .debug_name = "Basic Pipeline", + .vs = { .debug_name = "Triangle Vertex Shader", + .filepath = vert_path, + .code = vertex_shader.contents, + .is_spirv = true }, + .fs = { .debug_name = "Triangle Fragment Shader", + .filepath = frag_path, + .code = fragment_shader.contents, + .is_spirv = true }, + .renderpass = renderpass, + .wireframe = false, + .depth_test = false + }; + gpu_pipeline* gfx_pipeline = gpu_graphics_pipeline_create(pipeline_description); + + buffer_handle triangle_vert_buf = + gpu_buffer_create(sizeof(vertices), CEL_BUFFER_VERTEX, CEL_BUFFER_FLAG_GPU, vertices); + + buffer_handle triangle_index_buf = + gpu_buffer_create(sizeof(indices), CEL_BUFFER_INDEX, CEL_BUFFER_FLAG_GPU, indices); + + // Main loop + while (!should_exit(&g_core)) { + glfwPollEvents(); + input_update(&g_core.input); + + // render_frame_begin(&g_core.renderer); + + if (!gpu_backend_begin_frame()) { + continue; + } + gpu_cmd_encoder* enc = gpu_get_default_cmd_encoder(); + // begin recording + gpu_cmd_encoder_begin(*enc); + gpu_cmd_encoder_begin_render(enc, renderpass); + encode_bind_pipeline(enc, PIPELINE_GRAPHICS, gfx_pipeline); + encode_set_default_settings(enc); + + // Record draw calls + encode_set_vertex_buffer(enc, triangle_vert_buf); + encode_set_index_buffer(enc, triangle_index_buf); + encode_bind_shader_data(enc, 0, &mvp_uniforms_data); + gpu_temp_draw(6); + + // End recording + gpu_cmd_encoder_end_render(enc); + + gpu_cmd_buffer buf = gpu_cmd_encoder_finish(enc); + gpu_queue_submit(&buf); + // Submit + gpu_backend_end_frame(); + + // render_frame_end(&g_core.renderer); + // glfwSwapBuffers(core->renderer.window); + } + + renderer_shutdown(&g_core.renderer); + + return 0; +} diff --git a/examples/triangle/ex_triangle.c b/examples/triangle/ex_triangle.c index dc82156..c6f0e54 100644 --- a/examples/triangle/ex_triangle.c +++ b/examples/triangle/ex_triangle.c @@ -12,8 +12,6 @@ #include "ral_types.h" #include "render.h" -// Example setting up a renderer - extern core g_core; const custom_vertex vertices[] = { @@ -28,8 +26,6 @@ int main() { core_bringup(); arena scratch = arena_create(malloc(1024 * 1024), 1024 * 1024); - DEBUG("render capacity %d", g_core.default_scene.renderables->capacity); - gpu_renderpass_desc pass_description = {}; gpu_renderpass* renderpass = gpu_renderpass_create(&pass_description); @@ -65,19 +61,13 @@ int main() { // Main loop while (!should_exit(&g_core)) { - glfwPollEvents(); input_update(&g_core.input); - // render_frame_begin(&g_core.renderer); - - static f64 x = 0.0; - x += 0.01; - if (!gpu_backend_begin_frame()) { continue; } gpu_cmd_encoder* enc = gpu_get_default_cmd_encoder(); - // begin recording + // Begin recording gpu_cmd_encoder_begin(*enc); gpu_cmd_encoder_begin_render(enc, renderpass); encode_bind_pipeline(enc, PIPELINE_GRAPHICS, gfx_pipeline); @@ -86,18 +76,16 @@ int main() { // Record draw calls encode_set_vertex_buffer(enc, triangle_vert_buf); encode_set_index_buffer(enc, triangle_index_buf); - gpu_temp_draw(6); + encode_draw_indexed(enc, 6); // End recording gpu_cmd_encoder_end_render(enc); - gpu_cmd_buffer buf = gpu_cmd_encoder_finish(enc); - gpu_queue_submit(&buf); + gpu_cmd_buffer buf = gpu_cmd_encoder_finish( + enc); // Command buffer is no longer recording and is ready to submit // Submit + gpu_queue_submit(&buf); gpu_backend_end_frame(); - - // render_frame_end(&g_core.renderer); - // glfwSwapBuffers(core->renderer.window); } renderer_shutdown(&g_core.renderer); diff --git a/src/renderer/ral.h b/src/renderer/ral.h index 2fb0166..38a653d 100644 --- a/src/renderer/ral.h +++ b/src/renderer/ral.h @@ -104,6 +104,7 @@ void buffer_upload_bytes(buffer_handle gpu_buf, bytebuffer cpu_buf, u64 offset, // render pass void encode_bind_pipeline(gpu_cmd_encoder* encoder, pipeline_kind kind, gpu_pipeline* pipeline); +void encode_bind_shader_data(gpu_cmd_encoder* encoder, u32 group, shader_data* data); void encode_set_default_settings(gpu_cmd_encoder* encoder); void encode_set_vertex_buffer(gpu_cmd_encoder* encoder, buffer_handle buf); void encode_set_index_buffer(gpu_cmd_encoder* encoder, buffer_handle buf); diff --git a/src/renderer/ral_types.h b/src/renderer/ral_types.h index 2fa8258..230afc3 100644 --- a/src/renderer/ral_types.h +++ b/src/renderer/ral_types.h @@ -120,6 +120,67 @@ typedef struct custom_vertex { vec3 color; } custom_vertex; +// Vertex attributes +typedef enum vertex_attrib_type { + ATTR_F32, + ATTR_F32x2, + ATTR_F32x3, + ATTR_F32x4, + ATTR_U32, + ATTR_U32x2, + ATTR_U32x3, + ATTR_U32x4, + ATTR_I32, + ATTR_I32x2, + ATTR_I32x3, + ATTR_I32x4, +} vertex_attrib_type; + +typedef enum shader_binding_type { + SHADER_BINDING_BUFFER, + SHADER_BINDING_TEXTURE, + SHADER_BINDING_BYTES, + SHADER_BINDING_COUNT +} shader_binding_type; + +typedef struct shader_binding { + const char* label; + shader_binding_type type; + 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 */ + union { + struct { + buffer_handle handle; + } buffer; + struct { + void* data; + size_t size; + } bytes; + } data; +} shader_binding; + +#define MAX_LAYOUT_BINDINGS 8 + +/** @brief A list of bindings that describe what data a shader / pipeline expects + @note This roughly correlates to a descriptor set layout in Vulkan +*/ +typedef struct shader_data_layout { + char* name; + shader_binding bindings[MAX_LAYOUT_BINDINGS]; +} shader_data_layout; + +typedef struct shader_data { + shader_data_layout (*shader_data_get_layout)(void* data); + void* data; +} shader_data; + +/* + Usage: + 1. When we create the pipeline, we must call a function that return a layout without .data fields + 2. When binding +*/ + typedef enum gpu_cull_mode { CULL_BACK_FACE, CULL_FRONT_FACE, CULL_COUNT } gpu_cull_mode; // ? How to tie together materials and shaders diff --git a/src/systems/input.c b/src/systems/input.c index 5df1159..0c8f768 100644 --- a/src/systems/input.c +++ b/src/systems/input.c @@ -32,6 +32,7 @@ bool input_system_init(input_state *input, GLFWwindow *window) { void input_system_shutdown(input_state *input) {} void input_update(input_state *input) { + glfwPollEvents(); // --- update keyboard input // if we go from un-pressed -> pressed, set as "just pressed" -- cgit v1.2.3-70-g09d2 From 677ab09b0dc3b6d9c872b732f8e31543fa2d11bb Mon Sep 17 00:00:00 2001 From: Omniscient <17525998+omnisci3nce@users.noreply.github.com> Date: Sat, 11 May 2024 22:06:55 +1000 Subject: WIP: shader data --- examples/cube/ex_cube.c | 62 +++++++----------- examples/triangle/ex_triangle.c | 2 + src/renderer/backends/backend_vulkan.c | 116 ++++++++++++++++++++++++++++++++- src/renderer/backends/backend_vulkan.h | 21 ++++++ src/renderer/ral.h | 13 ++++ src/renderer/ral_types.h | 15 +++++ src/renderer/render.h | 2 +- xmake.lua | 7 ++ 8 files changed, 199 insertions(+), 39 deletions(-) (limited to 'examples/triangle') 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); diff --git a/xmake.lua b/xmake.lua index 882535d..7ebd63d 100644 --- a/xmake.lua +++ b/xmake.lua @@ -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") -- cgit v1.2.3-70-g09d2 From d79a8aa200bd64b14b85d2ec0c207601ba5c7922 Mon Sep 17 00:00:00 2001 From: Omniscient Date: Sat, 18 May 2024 23:53:11 +1000 Subject: working on image creation --- assets/shaders/triangle.vert | 2 - examples/cube/ex_cube.c | 5 + examples/triangle/ex_triangle.c | 18 ++- src/renderer/backends/backend_vulkan.c | 224 ++++++++++++++++++++++++++++----- src/renderer/backends/backend_vulkan.h | 8 ++ src/renderer/ral.c | 21 ---- src/renderer/ral.h | 7 ++ src/renderer/ral_types.h | 3 - src/renderer/render.c | 44 ++++++- src/renderer/render.h | 16 ++- src/renderer/render_types.h | 15 +-- 11 files changed, 289 insertions(+), 74 deletions(-) (limited to 'examples/triangle') diff --git a/assets/shaders/triangle.vert b/assets/shaders/triangle.vert index b8c8f63..8030561 100644 --- a/assets/shaders/triangle.vert +++ b/assets/shaders/triangle.vert @@ -2,8 +2,6 @@ layout(location = 0) in vec2 inPos; layout(location = 1) in vec3 inColor; -// layout(location = 1) in vec3 inNormal; -// layout(location = 2) in vec2 inTexCoords; layout(location = 0) out vec3 fragColor; diff --git a/examples/cube/ex_cube.c b/examples/cube/ex_cube.c index 7c7831d..264bf71 100644 --- a/examples/cube/ex_cube.c +++ b/examples/cube/ex_cube.c @@ -86,9 +86,14 @@ int main() { }; gpu_pipeline* gfx_pipeline = gpu_graphics_pipeline_create(pipeline_description); + // Geometry geometry_data cube_data = geo_create_cuboid(f32x3(1, 1, 1)); mesh cube = mesh_create(&cube_data, false); + // Texture + texture_data tex_data = texture_data_load("assets/textures/texture.jpg", false); + texture_handle texture = texture_data_upload(tex_data, true); + // Main loop while (!should_exit(&g_core)) { input_update(&g_core.input); diff --git a/examples/triangle/ex_triangle.c b/examples/triangle/ex_triangle.c index 5d8f0cf..886637a 100644 --- a/examples/triangle/ex_triangle.c +++ b/examples/triangle/ex_triangle.c @@ -16,17 +16,22 @@ extern core g_core; const custom_vertex vertices[] = { + (custom_vertex){ .pos = vec2(-0.5, -0.5), .color = vec3(1.0, 1.0, 1.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(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 }; +const u32 indices[] = { 2, 1, 0, 1, 2, 3}; int main() { core_bringup(); arena scratch = arena_create(malloc(1024 * 1024), 1024 * 1024); + vertex_description vertex_input = {0}; + vertex_input.debug_label = "Hello"; + vertex_desc_add(&vertex_input, "inPos", ATTR_F32x2); + vertex_desc_add(&vertex_input, "inColor", ATTR_F32x3); + gpu_renderpass_desc pass_description = {}; gpu_renderpass* renderpass = gpu_renderpass_create(&pass_description); @@ -40,6 +45,9 @@ int main() { struct graphics_pipeline_desc pipeline_description = { .debug_name = "Basic Pipeline", + .vertex_desc = vertex_input, + // .data_layouts = {0}, + // .data_layouts_count = 0, .vs = { .debug_name = "Triangle Vertex Shader", .filepath = vert_path, .code = vertex_shader.contents, @@ -56,13 +64,13 @@ int main() { // Load triangle vertex and index data buffer_handle triangle_vert_buf = - gpu_buffer_create(sizeof(vertices), CEL_BUFFER_VERTEX, CEL_BUFFER_FLAG_GPU, vertices); + gpu_buffer_create(4 * sizeof(vertex) , CEL_BUFFER_VERTEX, CEL_BUFFER_FLAG_GPU, vertices); buffer_handle triangle_index_buf = gpu_buffer_create(sizeof(indices), CEL_BUFFER_INDEX, CEL_BUFFER_FLAG_GPU, indices); // Main loop - while (!should_exit(&g_core)) { + while (!should_exit()) { input_update(&g_core.input); if (!gpu_backend_begin_frame()) { diff --git a/src/renderer/backends/backend_vulkan.c b/src/renderer/backends/backend_vulkan.c index 2dc11b5..208aef0 100644 --- a/src/renderer/backends/backend_vulkan.c +++ b/src/renderer/backends/backend_vulkan.c @@ -414,37 +414,39 @@ gpu_pipeline* gpu_graphics_pipeline_create(struct graphics_pipeline_desc descrip VkPipelineShaderStageCreateInfo shader_stages[2] = { vert_shader_stage_info, frag_shader_stage_info }; - // TODO: Attributes - VkVertexInputAttributeDescription attribute_descs[2] = { 0 }; - /* u32 offset = 0; */ - /* for (u32 i = 0; i < description.vertex_desc.attributes_count; i++) { */ - /* attribute_descs[i].binding = 0; */ - /* attribute_descs[i].location = i; */ - /* attribute_descs[i].format = format_from_vertex_attr(description.vertex_desc.attributes[i]); - */ - /* attribute_descs[i].offset = offset; */ - /* size_t this_offset = vertex_attrib_size(description.vertex_desc.attributes[i]); */ - /* printf("offset total %d this attr %ld\n", offset, this_offset); */ - /* printf("sizeof vertex %ld\n", sizeof(vertex)); */ - /* printf("%d \n", offsetof(vertex, static_3d)); */ - /* offset += this_offset; */ - /* } */ - printf("Vertex attributes\n"); - attribute_descs[0].binding = 0; - attribute_descs[0].location = 0; - attribute_descs[0].format = VK_FORMAT_R32G32B32_SFLOAT; - attribute_descs[0].offset = 0; // offsetof(custom_vertex, pos); - - attribute_descs[1].binding = 0; - attribute_descs[1].location = 1; - attribute_descs[1].format = VK_FORMAT_R32G32B32_SFLOAT; - attribute_descs[1].offset = 12; // offsetof(custom_vertex, color); + // Attributes + u32 attr_count = description.vertex_desc.attributes_count; + printf("N attributes %d\n", attr_count); + VkVertexInputAttributeDescription attribute_descs[attr_count]; + memset(attribute_descs, 0, attr_count * sizeof(VkVertexInputAttributeDescription)); + u32 offset = 0; + for (u32 i = 0; i < description.vertex_desc.attributes_count; i++) { + attribute_descs[i].binding = 0; + attribute_descs[i].location = i; + attribute_descs[i].format = format_from_vertex_attr(description.vertex_desc.attributes[i]); + attribute_descs[i].offset = offset; + size_t this_offset = vertex_attrib_size(description.vertex_desc.attributes[i]); + printf("offset total %d this attr %ld\n", offset, this_offset); + printf("sizeof vertex %ld\n", sizeof(vertex)); + /* printf("%d \n", offsetof(vertex, static_3d)); */ + offset += this_offset; + } + /* printf("Vertex attributes\n"); */ + /* attribute_descs[0].binding = 0; */ + /* attribute_descs[0].location = 0; */ + /* attribute_descs[0].format = VK_FORMAT_R32G32B32_SFLOAT; */ + /* attribute_descs[0].offset = 0; // offsetof(custom_vertex, pos); */ + + /* attribute_descs[1].binding = 0; */ + /* attribute_descs[1].location = 1; */ + /* attribute_descs[1].format = VK_FORMAT_R32G32B32_SFLOAT; */ + /* attribute_descs[1].offset = 12; // offsetof(custom_vertex, color); */ // Vertex input // TODO: Generate this from descroiption now VkVertexInputBindingDescription binding_desc; binding_desc.binding = 0; - binding_desc.stride = sizeof(vertex); // description.vertex_desc.stride; + binding_desc.stride = description.vertex_desc.stride; binding_desc.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; VkPipelineVertexInputStateCreateInfo vertex_input_info = { @@ -453,7 +455,7 @@ gpu_pipeline* gpu_graphics_pipeline_create(struct graphics_pipeline_desc descrip vertex_input_info.vertexBindingDescriptionCount = 1; vertex_input_info.pVertexBindingDescriptions = &binding_desc; vertex_input_info.vertexAttributeDescriptionCount = - 2; // description.vertex_desc.attributes_count; + attr_count; // description.vertex_desc.attributes_count; vertex_input_info.pVertexAttributeDescriptions = attribute_descs; // Input Assembly @@ -558,10 +560,15 @@ gpu_pipeline* gpu_graphics_pipeline_create(struct graphics_pipeline_desc descrip malloc(description.data_layouts_count * sizeof(VkDescriptorSetLayout)); pipeline->desc_set_layouts = desc_set_layouts; pipeline->desc_set_layouts_count = description.data_layouts_count; + if (description.data_layouts_count > 0) { pipeline->uniform_pointers = malloc(description.data_layouts_count * sizeof(desc_set_uniform_buffer)); + } else { + pipeline->uniform_pointers = NULL; + } // assert(description.data_layouts_count == 1); + printf("data layouts %d\n", description.data_layouts_count); for (u32 i = 0; i < description.data_layouts_count; i++) { shader_data_layout sdl = description.data_layouts[i].shader_data_get_layout(NULL); @@ -1343,15 +1350,15 @@ buffer_handle gpu_buffer_create(u64 size, gpu_buffer_type buf_type, gpu_buffer_f void gpu_buffer_destroy(buffer_handle buffer) { gpu_buffer* b = - buffer_pool_get(&context.resource_pools->buffers, buffer); // context.buffers[buffer.raw]; + buffer_pool_get(&context.resource_pools->buffers, buffer); vkDestroyBuffer(context.device->logical_device, b->handle, context.allocator); vkFreeMemory(context.device->logical_device, b->memory, context.allocator); + buffer_pool_dealloc(&context.resource_pools->buffers, buffer); } // Upload data to a void buffer_upload_bytes(buffer_handle gpu_buf, bytebuffer cpu_buf, u64 offset, u64 size) { gpu_buffer* buffer = buffer_pool_get(&context.resource_pools->buffers, gpu_buf); - /* gpu_buffer buffer = context.buffers[gpu_buf.raw]; */ void* data_ptr; vkMapMemory(context.device->logical_device, buffer->memory, 0, size, 0, &data_ptr); DEBUG("Uploading %d bytes to buffer", size); @@ -1371,6 +1378,80 @@ void encode_buffer_copy(gpu_cmd_encoder* encoder, buffer_handle src, u64 src_off vkCmdCopyBuffer(encoder->cmd_buffer, src_buf->handle, dst_buf->handle, 1, ©_region); } +// one-shot command buffers +VkCommandBuffer vulkan_command_buffer_create_oneshot() { + VkCommandBufferAllocateInfo alloc_info = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO }; + alloc_info.commandPool = context.device->pool; + alloc_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + alloc_info.commandBufferCount = 1; + alloc_info.pNext = 0; + + VkCommandBuffer cmd_buffer; + vkAllocateCommandBuffers(context.device->logical_device, &alloc_info, &cmd_buffer); + + VkCommandBufferBeginInfo begin_info = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO }; + begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + + vkBeginCommandBuffer(cmd_buffer, &begin_info); + + return cmd_buffer; +} + +void vulkan_command_buffer_finish_oneshot(VkCommandBuffer cmd_buffer) { + VK_CHECK(vkEndCommandBuffer(cmd_buffer)); + + // submit to queue + VkSubmitInfo submit_info = { VK_STRUCTURE_TYPE_SUBMIT_INFO }; + submit_info.commandBufferCount = 1; + submit_info.pCommandBuffers = &cmd_buffer; + VK_CHECK(vkQueueSubmit(context.device->graphics_queue, 1, &submit_info, 0)); + VK_CHECK(vkQueueWaitIdle(context.device->graphics_queue)); + + vkFreeCommandBuffers(context.device->logical_device, context.device->pool, 1, &cmd_buffer); +} + +void copy_buffer_to_buffer_oneshot(buffer_handle src, u64 src_offset, buffer_handle dst, + u64 dst_offset, u64 copy_size) { + VkBufferCopy copy_region; + copy_region.srcOffset = src_offset; + copy_region.dstOffset = dst_offset; + copy_region.size = copy_size; + + gpu_buffer* src_buf = buffer_pool_get(&context.resource_pools->buffers, src); + gpu_buffer* dst_buf = buffer_pool_get(&context.resource_pools->buffers, dst); + VkCommandBuffer temp_cmd_buffer = vulkan_command_buffer_create_oneshot(); + vkCmdCopyBuffer(temp_cmd_buffer, src_buf->handle, dst_buf->handle, 1, ©_region); + vulkan_command_buffer_finish_oneshot(temp_cmd_buffer); +} + +void copy_buffer_to_image_oneshot(buffer_handle src, texture_handle dst) { + gpu_buffer* src_buf = buffer_pool_get(&context.resource_pools->buffers, src); + gpu_texture* dst_tex = texture_pool_get(&context.resource_pools->textures, dst); + + VkCommandBuffer temp_cmd_buffer = vulkan_command_buffer_create_oneshot(); + + VkBufferImageCopy region; + region.bufferOffset = 0; + region.bufferRowLength = 0; + region.bufferImageHeight = 0; + region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + region.imageSubresource.mipLevel = 0; + region.imageSubresource.baseArrayLayer = 0; + region.imageSubresource.layerCount = 1; + printf("Image details width: %d height %d\n", dst_tex->desc.extents.x, dst_tex->desc.extents.y); + region.imageOffset.x = 0; + region.imageOffset.y = 0; + region.imageOffset.z = 0; + region.imageExtent.width = dst_tex->desc.extents.x; + region.imageExtent.height = dst_tex->desc.extents.y; + region.imageExtent.depth = 1; + + vkCmdCopyBufferToImage(temp_cmd_buffer, src_buf->handle, dst_tex->handle, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); + + vulkan_command_buffer_finish_oneshot(temp_cmd_buffer); +} + texture_handle gpu_texture_create(texture_desc desc, const void* data) { VkDeviceSize image_size = desc.extents.x * desc.extents.y * 4; @@ -1380,6 +1461,91 @@ texture_handle gpu_texture_create(texture_desc desc, const void* data) { gpu_buffer_create(image_size, CEL_BUFFER_DEFAULT, CEL_BUFFER_FLAG_CPU, NULL); // Copy data into it buffer_upload_bytes(staging, (bytebuffer){ .buf = (u8*)data, .size = image_size }, 0, image_size); + + VkImage image; + VkDeviceMemory image_memory; + + VkImageCreateInfo image_create_info = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO }; + image_create_info.imageType = VK_IMAGE_TYPE_2D; + image_create_info.extent.width = desc.extents.x; + image_create_info.extent.height = desc.extents.y; + image_create_info.extent.depth = 1; + image_create_info.mipLevels = 1; + image_create_info.arrayLayers = 1; + image_create_info.format = VK_FORMAT_R8G8B8A8_SRGB; + image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL; + image_create_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + image_create_info.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; + image_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + image_create_info.samples = VK_SAMPLE_COUNT_1_BIT; + + VK_CHECK( + vkCreateImage(context.device->logical_device, &image_create_info, context.allocator, &image)); + + VkMemoryRequirements memory_reqs; + vkGetImageMemoryRequirements(context.device->logical_device, image, &memory_reqs); + + VkMemoryAllocateInfo alloc_info = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO }; + alloc_info.allocationSize = memory_reqs.size; + alloc_info.memoryTypeIndex = + find_memory_index(memory_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + vkAllocateMemory(context.device->logical_device, &alloc_info, context.allocator, &image_memory); + + vkBindImageMemory(context.device->logical_device, image, image_memory, 0); + +gpu_buffer_destroy(staging); + + texture_handle handle; + gpu_texture* texture = texture_pool_alloc(&context.resource_pools->textures, &handle); + texture->handle = image; + texture->memory = image_memory; + texture->size = image_size; + return handle; +} + +void vulkan_transition_image_layout(gpu_texture* texture, VkFormat format, VkImageLayout old_layout, + VkImageLayout new_layout) { + VkCommandBuffer temp_cmd_buffer = vulkan_command_buffer_create_oneshot(); + + VkImageMemoryBarrier barrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER }; + barrier.oldLayout = old_layout; + barrier.newLayout = new_layout; + barrier.srcQueueFamilyIndex = context.device->queue_family_indicies.graphics_family_index; + barrier.dstQueueFamilyIndex = context.device->queue_family_indicies.graphics_family_index; + barrier.image = texture->handle; + barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + barrier.subresourceRange.baseMipLevel = 0; + barrier.subresourceRange.levelCount = 1; + barrier.subresourceRange.baseArrayLayer = 0; + barrier.subresourceRange.layerCount = 1; + barrier.srcAccessMask = 0; // TODO + barrier.dstAccessMask = 0; // TODO + + VkPipelineStageFlags source_stage; + VkPipelineStageFlags dest_stage; + + if (old_layout == VK_IMAGE_LAYOUT_UNDEFINED && + new_layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) { + barrier.srcAccessMask = 0; + barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + + source_stage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; + dest_stage = VK_PIPELINE_STAGE_TRANSFER_BIT; + + } else if (old_layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && + new_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) { + barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + source_stage = VK_PIPELINE_STAGE_TRANSFER_BIT; + dest_stage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + } else { + FATAL("Unsupported image layout transition"); + return; + } + + vkCmdPipelineBarrier(temp_cmd_buffer, source_stage, dest_stage, 0, 0, 0, 0, 0, 1, &barrier); + + vulkan_command_buffer_finish_oneshot(temp_cmd_buffer); } size_t vertex_attrib_size(vertex_attrib_type attr) { diff --git a/src/renderer/backends/backend_vulkan.h b/src/renderer/backends/backend_vulkan.h index 77b9f94..1e36ca3 100644 --- a/src/renderer/backends/backend_vulkan.h +++ b/src/renderer/backends/backend_vulkan.h @@ -6,6 +6,7 @@ #include "defines.h" #include "mem.h" #include "ral.h" +#include "ral_types.h" #define MAX_FRAMES_IN_FLIGHT 2 #define GPU_SWAPCHAIN_IMG_COUNT 2 @@ -102,3 +103,10 @@ typedef struct gpu_buffer { VkDeviceMemory memory; u64 size; } gpu_buffer; + +typedef struct gpu_texture { + VkImage handle; + VkDeviceMemory memory; + u64 size; + texture_desc desc; +} gpu_texture; diff --git a/src/renderer/ral.c b/src/renderer/ral.c index 6a417dd..304017d 100644 --- a/src/renderer/ral.c +++ b/src/renderer/ral.c @@ -1,22 +1 @@ #include "ral.h" - -/* typedef struct foo { */ -/* u32 a; */ -/* f32 b; */ -/* char c; */ -/* } foo; */ - -/* TYPED_POOL(gpu_buffer, buffer); */ - -/* typedef struct buffer_handle { */ -/* u32 raw; */ -/* } buffer_handle; */ - -/* typedef struct gpu_buffer gpu_buffer; */ -/* TYPED_POOL(gpu_buffer, buffer); */ -/* TYPED_POOL(gpu_texture, texture); */ - -/* struct resource_pools { */ -/* buffer_pool buffers; */ -/* texture_pool textures; */ -/* }; */ diff --git a/src/renderer/ral.h b/src/renderer/ral.h index da9eb93..48be83a 100644 --- a/src/renderer/ral.h +++ b/src/renderer/ral.h @@ -30,6 +30,7 @@ typedef struct gpu_renderpass gpu_renderpass; 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; +typedef struct gpu_texture gpu_texture; #define MAX_SHADER_DATA_LAYOUTS 5 #define MAX_BUFFERS 256 @@ -174,3 +175,9 @@ struct resource_pools { // Must be implemented by backends void resource_pools_init(arena* a, struct resource_pools* res_pools); + +void copy_buffer_to_buffer_oneshot(buffer_handle src, u64 src_offset, buffer_handle dst, u64 dst_offset, + u64 copy_size); +void copy_buffer_to_image_oneshot(buffer_handle src, texture_handle dst); + +// --- Helpers diff --git a/src/renderer/ral_types.h b/src/renderer/ral_types.h index 5d4e88a..fc8bb8b 100644 --- a/src/renderer/ral_types.h +++ b/src/renderer/ral_types.h @@ -66,9 +66,6 @@ typedef struct texture_desc { u32x2 extents; } texture_desc; -typedef struct gpu_texture { -} gpu_texture; - typedef enum gpu_buffer_type { CEL_BUFFER_DEFAULT, // on Vulkan this would be a storage buffer? CEL_BUFFER_VERTEX, diff --git a/src/renderer/render.c b/src/renderer/render.c index b06620b..fc45093 100644 --- a/src/renderer/render.c +++ b/src/renderer/render.c @@ -1,11 +1,15 @@ -#include "render.h" #include +#include "maths_types.h" +#define STB_IMAGE_IMPLEMENTATION +#include + #include "camera.h" #include "file.h" #include "log.h" #include "mem.h" #include "ral.h" #include "ral_types.h" +#include "render.h" /** @brief Creates the pipelines built into Celeritas such as rendering static opaque geometry, debug visualisations, immediate mode UI, etc */ @@ -194,3 +198,41 @@ mesh mesh_create(geometry_data* geometry, bool free_on_upload) { return m; } + +// --- Textures + +texture_data texture_data_load(const char* path, bool invert_y) { + TRACE("Load texture %s", path); + + // load the file data + int width, height, num_channels; + stbi_set_flip_vertically_on_load(invert_y); + +#pragma GCC diagnostic ignored "-Wpointer-sign" + char* data = stbi_load(path, &width, &height, &num_channels, 0); // STBI_rgb_alpha); + if (data) { + DEBUG("loaded texture: %s", path); + } else { + WARN("failed to load texture"); + } + + unsigned int channel_type; + if (num_channels == 4) { + channel_type = GL_RGBA; + } else { + channel_type = GL_RGB; + } + texture_desc desc = { .extents = { width, height }, + .format = CEL_TEXTURE_FORMAT_8_8_8_8_RGBA_UNORM, + .tex_type = CEL_TEXTURE_TYPE_2D }; + + return (texture_data){ .description = desc, .image_data = data }; +} + +texture_handle texture_data_upload(texture_data data, bool free_on_upload) { + texture_handle handle = gpu_texture_create(data.description, data.image_data); + if (free_on_upload) { + stbi_image_free(data.image_data); + } + return handle; +} diff --git a/src/renderer/render.h b/src/renderer/render.h index 5657fc1..9a7ff2f 100644 --- a/src/renderer/render.h +++ b/src/renderer/render.h @@ -34,9 +34,17 @@ typedef struct render_ctx { texture_handle texture_create(const char* debug_name, texture_desc description, const u8* data); // Frontend Resources -// TODO: void texture_data_upload(texture_handle texture); -void texture_data_upload(texture* tex); -texture texture_data_load(const char* path, bool invert_y); +texture_data texture_data_load(const char* path, bool invert_y); + +/** + * @brief + * + * @param data + * @param free_on_upload frees the CPU-side pixel data stored in `data` + * @return texture_handle + */ +texture_handle texture_data_upload(texture_data data, bool free_on_upload); + buffer_handle buffer_create(const char* debug_name, u64 size); bool buffer_destroy(buffer_handle buffer); sampler_handle sampler_create(); @@ -49,7 +57,7 @@ void shader_hot_reload(const char* filepath); * @brief Creates buffers and returns a struct that holds handles to our resources * * @param geometry - * @param free_on_upload frees the CPU-side vertex/index data stored in geometry_data when we + * @param free_on_upload frees the CPU-side vertex/index data stored in `geometry` when we successfully upload that data to the GPU-side buffer * @return mesh */ diff --git a/src/renderer/render_types.h b/src/renderer/render_types.h index bd9ef3c..c6aec8e 100644 --- a/src/renderer/render_types.h +++ b/src/renderer/render_types.h @@ -69,16 +69,13 @@ typedef struct model { u32 mesh_count; } model; -typedef struct texture { - u32 texture_id; - char name[256]; +typedef struct texture {} texture; + +typedef struct texture_data { + texture_desc description; void* image_data; - void* backend_data; - u32 width; - u32 height; - u8 channel_count; - u32 channel_type; -} texture; +} texture_data; + typedef struct blinn_phong_material { char name[256]; -- cgit v1.2.3-70-g09d2 From b1b2d988e8f2fa3b0f63ff3aeb02849497433647 Mon Sep 17 00:00:00 2001 From: Omniscient Date: Sun, 19 May 2024 00:01:50 +1000 Subject: cube compiles again --- examples/cube/ex_cube.c | 2 +- examples/triangle/ex_triangle.c | 2 +- src/renderer/backends/backend_vulkan.c | 2 +- src/renderer/ral_types.h | 1 + src/renderer/render.c | 2 +- 5 files changed, 5 insertions(+), 4 deletions(-) (limited to 'examples/triangle') diff --git a/examples/cube/ex_cube.c b/examples/cube/ex_cube.c index 264bf71..346dd10 100644 --- a/examples/cube/ex_cube.c +++ b/examples/cube/ex_cube.c @@ -48,7 +48,7 @@ int main() { vec3 camera_front = vec3_normalise(vec3_negate(camera_pos)); camera cam = camera_create(camera_pos, camera_front, VEC3_Y, deg_to_rad(45.0)); - vertex_description vertex_input; + vertex_description vertex_input = {.use_full_vertex_size = true}; vertex_input.debug_label = "Standard Static 3D Vertex Format"; vertex_desc_add(&vertex_input, "inPosition", ATTR_F32x3); vertex_desc_add(&vertex_input, "inNormal", ATTR_F32x3); diff --git a/examples/triangle/ex_triangle.c b/examples/triangle/ex_triangle.c index 886637a..69c29ac 100644 --- a/examples/triangle/ex_triangle.c +++ b/examples/triangle/ex_triangle.c @@ -27,7 +27,7 @@ int main() { core_bringup(); arena scratch = arena_create(malloc(1024 * 1024), 1024 * 1024); - vertex_description vertex_input = {0}; + vertex_description vertex_input = {.use_full_vertex_size=false}; vertex_input.debug_label = "Hello"; vertex_desc_add(&vertex_input, "inPos", ATTR_F32x2); vertex_desc_add(&vertex_input, "inColor", ATTR_F32x3); diff --git a/src/renderer/backends/backend_vulkan.c b/src/renderer/backends/backend_vulkan.c index 208aef0..ae49cc3 100644 --- a/src/renderer/backends/backend_vulkan.c +++ b/src/renderer/backends/backend_vulkan.c @@ -446,7 +446,7 @@ gpu_pipeline* gpu_graphics_pipeline_create(struct graphics_pipeline_desc descrip // TODO: Generate this from descroiption now VkVertexInputBindingDescription binding_desc; binding_desc.binding = 0; - binding_desc.stride = description.vertex_desc.stride; + binding_desc.stride = description.vertex_desc.use_full_vertex_size ? sizeof(vertex) : description.vertex_desc.stride; binding_desc.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; VkPipelineVertexInputStateCreateInfo vertex_input_info = { diff --git a/src/renderer/ral_types.h b/src/renderer/ral_types.h index fc8bb8b..8339625 100644 --- a/src/renderer/ral_types.h +++ b/src/renderer/ral_types.h @@ -160,6 +160,7 @@ typedef struct vertex_description { vertex_attrib_type attributes[MAX_VERTEX_ATTRIBUTES]; u32 attributes_count; size_t stride; + bool use_full_vertex_size; } vertex_description; // --- Shaders & Bindings diff --git a/src/renderer/render.c b/src/renderer/render.c index fc45093..9f9a97c 100644 --- a/src/renderer/render.c +++ b/src/renderer/render.c @@ -209,7 +209,7 @@ texture_data texture_data_load(const char* path, bool invert_y) { stbi_set_flip_vertically_on_load(invert_y); #pragma GCC diagnostic ignored "-Wpointer-sign" - char* data = stbi_load(path, &width, &height, &num_channels, 0); // STBI_rgb_alpha); + char* data = stbi_load(path, &width, &height, &num_channels, STBI_rgb_alpha); if (data) { DEBUG("loaded texture: %s", path); } else { -- cgit v1.2.3-70-g09d2 From ebee348781e68e61f97c31411512dc0aabab7acb Mon Sep 17 00:00:00 2001 From: Omniscient Date: Sun, 19 May 2024 00:04:31 +1000 Subject: chore: fmt --- examples/cube/ex_cube.c | 2 +- examples/triangle/ex_triangle.c | 6 +++--- src/renderer/backends/backend_vulkan.c | 15 ++++++++------- src/renderer/ral.h | 4 ++-- src/renderer/render.h | 10 +++++----- src/renderer/render_types.h | 4 ++-- src/scene.h | 8 ++++---- 7 files changed, 25 insertions(+), 24 deletions(-) (limited to 'examples/triangle') diff --git a/examples/cube/ex_cube.c b/examples/cube/ex_cube.c index 346dd10..80a4e26 100644 --- a/examples/cube/ex_cube.c +++ b/examples/cube/ex_cube.c @@ -48,7 +48,7 @@ int main() { vec3 camera_front = vec3_normalise(vec3_negate(camera_pos)); camera cam = camera_create(camera_pos, camera_front, VEC3_Y, deg_to_rad(45.0)); - vertex_description vertex_input = {.use_full_vertex_size = true}; + vertex_description vertex_input = { .use_full_vertex_size = true }; vertex_input.debug_label = "Standard Static 3D Vertex Format"; vertex_desc_add(&vertex_input, "inPosition", ATTR_F32x3); vertex_desc_add(&vertex_input, "inNormal", ATTR_F32x3); diff --git a/examples/triangle/ex_triangle.c b/examples/triangle/ex_triangle.c index 69c29ac..d57e224 100644 --- a/examples/triangle/ex_triangle.c +++ b/examples/triangle/ex_triangle.c @@ -21,13 +21,13 @@ 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) }, }; -const u32 indices[] = { 2, 1, 0, 1, 2, 3}; +const u32 indices[] = { 2, 1, 0, 1, 2, 3 }; int main() { core_bringup(); arena scratch = arena_create(malloc(1024 * 1024), 1024 * 1024); - vertex_description vertex_input = {.use_full_vertex_size=false}; + vertex_description vertex_input = { .use_full_vertex_size = false }; vertex_input.debug_label = "Hello"; vertex_desc_add(&vertex_input, "inPos", ATTR_F32x2); vertex_desc_add(&vertex_input, "inColor", ATTR_F32x3); @@ -64,7 +64,7 @@ int main() { // Load triangle vertex and index data buffer_handle triangle_vert_buf = - gpu_buffer_create(4 * sizeof(vertex) , CEL_BUFFER_VERTEX, CEL_BUFFER_FLAG_GPU, vertices); + gpu_buffer_create(4 * sizeof(vertex), CEL_BUFFER_VERTEX, CEL_BUFFER_FLAG_GPU, vertices); buffer_handle triangle_index_buf = gpu_buffer_create(sizeof(indices), CEL_BUFFER_INDEX, CEL_BUFFER_FLAG_GPU, indices); diff --git a/src/renderer/backends/backend_vulkan.c b/src/renderer/backends/backend_vulkan.c index ae49cc3..33e0860 100644 --- a/src/renderer/backends/backend_vulkan.c +++ b/src/renderer/backends/backend_vulkan.c @@ -425,7 +425,7 @@ gpu_pipeline* gpu_graphics_pipeline_create(struct graphics_pipeline_desc descrip attribute_descs[i].location = i; attribute_descs[i].format = format_from_vertex_attr(description.vertex_desc.attributes[i]); attribute_descs[i].offset = offset; - size_t this_offset = vertex_attrib_size(description.vertex_desc.attributes[i]); + size_t this_offset = vertex_attrib_size(description.vertex_desc.attributes[i]); printf("offset total %d this attr %ld\n", offset, this_offset); printf("sizeof vertex %ld\n", sizeof(vertex)); /* printf("%d \n", offsetof(vertex, static_3d)); */ @@ -446,7 +446,9 @@ gpu_pipeline* gpu_graphics_pipeline_create(struct graphics_pipeline_desc descrip // TODO: Generate this from descroiption now VkVertexInputBindingDescription binding_desc; binding_desc.binding = 0; - binding_desc.stride = description.vertex_desc.use_full_vertex_size ? sizeof(vertex) : description.vertex_desc.stride; + binding_desc.stride = description.vertex_desc.use_full_vertex_size + ? sizeof(vertex) + : description.vertex_desc.stride; binding_desc.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; VkPipelineVertexInputStateCreateInfo vertex_input_info = { @@ -561,8 +563,8 @@ gpu_pipeline* gpu_graphics_pipeline_create(struct graphics_pipeline_desc descrip pipeline->desc_set_layouts = desc_set_layouts; pipeline->desc_set_layouts_count = description.data_layouts_count; if (description.data_layouts_count > 0) { - pipeline->uniform_pointers = - malloc(description.data_layouts_count * sizeof(desc_set_uniform_buffer)); + pipeline->uniform_pointers = + malloc(description.data_layouts_count * sizeof(desc_set_uniform_buffer)); } else { pipeline->uniform_pointers = NULL; } @@ -1349,8 +1351,7 @@ buffer_handle gpu_buffer_create(u64 size, gpu_buffer_type buf_type, gpu_buffer_f } void gpu_buffer_destroy(buffer_handle buffer) { - gpu_buffer* b = - buffer_pool_get(&context.resource_pools->buffers, buffer); + gpu_buffer* b = buffer_pool_get(&context.resource_pools->buffers, buffer); vkDestroyBuffer(context.device->logical_device, b->handle, context.allocator); vkFreeMemory(context.device->logical_device, b->memory, context.allocator); buffer_pool_dealloc(&context.resource_pools->buffers, buffer); @@ -1493,7 +1494,7 @@ texture_handle gpu_texture_create(texture_desc desc, const void* data) { vkBindImageMemory(context.device->logical_device, image, image_memory, 0); -gpu_buffer_destroy(staging); + gpu_buffer_destroy(staging); texture_handle handle; gpu_texture* texture = texture_pool_alloc(&context.resource_pools->textures, &handle); diff --git a/src/renderer/ral.h b/src/renderer/ral.h index 48be83a..a82a2ba 100644 --- a/src/renderer/ral.h +++ b/src/renderer/ral.h @@ -176,8 +176,8 @@ struct resource_pools { // Must be implemented by backends void resource_pools_init(arena* a, struct resource_pools* res_pools); -void copy_buffer_to_buffer_oneshot(buffer_handle src, u64 src_offset, buffer_handle dst, u64 dst_offset, - u64 copy_size); +void copy_buffer_to_buffer_oneshot(buffer_handle src, u64 src_offset, buffer_handle dst, + u64 dst_offset, u64 copy_size); void copy_buffer_to_image_oneshot(buffer_handle src, texture_handle dst); // --- Helpers diff --git a/src/renderer/render.h b/src/renderer/render.h index 9a7ff2f..c193ff9 100644 --- a/src/renderer/render.h +++ b/src/renderer/render.h @@ -37,11 +37,11 @@ texture_handle texture_create(const char* debug_name, texture_desc description, texture_data texture_data_load(const char* path, bool invert_y); /** - * @brief - * - * @param data - * @param free_on_upload frees the CPU-side pixel data stored in `data` - * @return texture_handle + * @brief + * + * @param data + * @param free_on_upload frees the CPU-side pixel data stored in `data` + * @return texture_handle */ texture_handle texture_data_upload(texture_data data, bool free_on_upload); diff --git a/src/renderer/render_types.h b/src/renderer/render_types.h index c6aec8e..cc5fd93 100644 --- a/src/renderer/render_types.h +++ b/src/renderer/render_types.h @@ -69,14 +69,14 @@ typedef struct model { u32 mesh_count; } model; -typedef struct texture {} texture; +typedef struct texture { +} texture; typedef struct texture_data { texture_desc description; void* image_data; } texture_data; - typedef struct blinn_phong_material { char name[256]; texture diffuse_texture; diff --git a/src/scene.h b/src/scene.h index 5a85e2e..5ac7542 100644 --- a/src/scene.h +++ b/src/scene.h @@ -32,10 +32,10 @@ void scene_free(scene* s); // Simplified API - no scene pointer; gets and sets global scene // Add/Remove objects from the scene - /* vec3 direction; */ - /* vec3 ambient; */ - /* vec3 diffuse; */ - /* vec3 specular; */ +/* vec3 direction; */ +/* vec3 ambient; */ +/* vec3 diffuse; */ +/* vec3 specular; */ void scene_set_dir_light(directional_light light); void _scene_set_dir_light(vec3 ambient, vec3 diffuse, vec3 specular, vec3 direction); -- cgit v1.2.3-70-g09d2