diff options
-rw-r--r-- | examples/triangle/ex_triangle.c | 39 | ||||
-rw-r--r-- | src/renderer/backends/backend_dx11.h | 3 | ||||
-rw-r--r-- | src/renderer/backends/backend_vulkan.c | 142 | ||||
-rw-r--r-- | src/renderer/backends/backend_vulkan.h | 11 | ||||
-rw-r--r-- | src/renderer/backends/vulkan_helpers.h | 7 | ||||
-rw-r--r-- | src/renderer/bind_group_layouts.h | 30 | ||||
-rw-r--r-- | src/renderer/ral.h | 22 | ||||
-rw-r--r-- | src/renderer/ral_types.h | 6 | ||||
-rw-r--r-- | src/renderer/render.h | 1 | ||||
-rw-r--r-- | src/renderer/render_types.h | 5 | ||||
-rw-r--r-- | src/renderer/renderpasses.h | 31 |
11 files changed, 274 insertions, 23 deletions
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 <glfw3.h> +#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 <vulkan/vulkan_core.h> #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 |