diff options
author | omnisci3nce <omniscient.oce@gmail.com> | 2024-04-28 11:02:21 +1000 |
---|---|---|
committer | omnisci3nce <omniscient.oce@gmail.com> | 2024-04-28 11:02:27 +1000 |
commit | 5e382c2095bc4891e2952ba87609f2796f2248ad (patch) | |
tree | b3a87539ec5e31083b5d9fd83e19b54bf6f59696 | |
parent | 411520b240446f878a27c5d89812000774cc3c15 (diff) |
start porting vulkan code to new RAL
-rw-r--r-- | examples/triangle/ex_triangle.c | 34 | ||||
-rw-r--r-- | src/log.h | 12 | ||||
-rw-r--r-- | src/renderer/backends/backend_vulkan.c | 143 | ||||
-rw-r--r-- | src/renderer/backends/backend_vulkan.h | 11 | ||||
-rw-r--r-- | src/renderer/ral.h | 31 | ||||
-rw-r--r-- | src/renderer/ral_types.h | 14 | ||||
-rw-r--r-- | src/renderer/render.c | 25 | ||||
-rw-r--r-- | src/renderer/render_types.h | 5 | ||||
-rw-r--r-- | src/std/buf.h | 17 | ||||
-rw-r--r-- | xmake.lua | 11 |
10 files changed, 267 insertions, 36 deletions
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 <glfw3.h> + +#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; +} @@ -38,19 +38,19 @@ void logger_shutdown(); void log_output(log_level level, const char* message, ...); -#define FATAL(message, ...) log_output(LOG_LEVEL_FATAL, message, ##__VA_ARGS__); -#define ERROR(message, ...) log_output(LOG_LEVEL_ERROR, message, ##__VA_ARGS__); -#define WARN(message, ...) log_output(LOG_LEVEL_WARN, message, ##__VA_ARGS__); -#define INFO(message, ...) log_output(LOG_LEVEL_INFO, message, ##__VA_ARGS__); +#define FATAL(message, ...) log_output(LOG_LEVEL_FATAL, message, ##__VA_ARGS__) +#define ERROR(message, ...) log_output(LOG_LEVEL_ERROR, message, ##__VA_ARGS__) +#define WARN(message, ...) log_output(LOG_LEVEL_WARN, message, ##__VA_ARGS__) +#define INFO(message, ...) log_output(LOG_LEVEL_INFO, message, ##__VA_ARGS__) #if LOG_DEBUG_ENABLED == 1 -#define DEBUG(message, ...) log_output(LOG_LEVEL_DEBUG, message, ##__VA_ARGS__); +#define DEBUG(message, ...) log_output(LOG_LEVEL_DEBUG, message, ##__VA_ARGS__) #else #define DEBUG(message, ...) #endif #if LOG_TRACE_ENABLED == 1 -#define TRACE(message, ...) log_output(LOG_LEVEL_TRACE, message, ##__VA_ARGS__); +#define TRACE(message, ...) log_output(LOG_LEVEL_TRACE, message, ##__VA_ARGS__) #else #define TRACE(message, ...) #endif
\ No newline at end of file diff --git a/src/renderer/backends/backend_vulkan.c b/src/renderer/backends/backend_vulkan.c index b66aeca..2502dd2 100644 --- a/src/renderer/backends/backend_vulkan.c +++ b/src/renderer/backends/backend_vulkan.c @@ -1,39 +1,109 @@ +#include <glfw3.h> +#include <stdlib.h> #include <vulkan/vk_platform.h> #include <vulkan/vulkan.h> #include <vulkan/vulkan_core.h> #include "backend_vulkan.h" +#include "mem.h" +#include "vulkan_helpers.h" #include "defines.h" #include "log.h" #include "ral.h" #include "ral_types.h" +// TEMP +#define SCREEN_WIDTH 1000 +#define SCREEN_HEIGHT 1000 + #define VULKAN_QUEUES_COUNT 2 const char* queue_names[VULKAN_QUEUES_COUNT] = { "GRAPHICS", "TRANSFER" }; typedef struct vulkan_context { - gpu_device device; + VkInstance instance; VkAllocationCallbacks* allocator; + VkSurfaceKHR surface; - VkInstance instance; + arena temp_arena; + gpu_device* device; + gpu_swapchain* swapchain; + u32 screen_width; + u32 screen_height; } vulkan_context; static vulkan_context context; -static bool select_physical_device(gpu_device* out_device) {} +// --- Function forward declarations + +/** @brief Enumerates and selects the most appropriate graphics device */ +bool select_physical_device(gpu_device* out_device); +/** @brief Helper function for creating array of all extensions we want */ +cstr_darray* get_all_extensions(); + +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; + + // Create an allocator + size_t temp_arena_size = 1024 * 1024; + arena_create(malloc(temp_arena_size), temp_arena_size); + + // Setup Vulkan instance + VkApplicationInfo app_info = { VK_STRUCTURE_TYPE_APPLICATION_INFO }; + app_info.apiVersion = VK_API_VERSION_1_3; + app_info.pApplicationName = window_name; + app_info.applicationVersion = VK_MAKE_VERSION(1, 0, 0); + app_info.pEngineName = "Celeritas Engine"; + app_info.engineVersion = VK_MAKE_VERSION(1, 0, 0); + + VkInstanceCreateInfo create_info = { VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO }; + create_info.pApplicationInfo = &app_info; + + // Extensions + // FIXME: Use my own extension choices + // cstr_darray* required_extensions = cstr_darray_new(2); + // cstr_darray_push(required_extensions, VK_KHR_SURFACE_EXTENSION_NAME); + // create_info.enabledExtensionCount = cstr_darray_len(required_extensions); + // create_info.ppEnabledExtensionNames = required_extensions->data; + uint32_t count; + const char** extensions = glfwGetRequiredInstanceExtensions(&count); + create_info.enabledExtensionCount = count; + create_info.ppEnabledExtensionNames = extensions; + + // TODO: Validation layers + create_info.enabledLayerCount = 0; + create_info.ppEnabledLayerNames = NULL; + + VkResult result = vkCreateInstance(&create_info, NULL, &context.instance); + if (result != VK_SUCCESS) { + ERROR("vkCreateInstance failed with result: %u", result); + return false; + } + TRACE("Vulkan Instance created"); + + // Surface creation + VkSurfaceKHR surface; + VK_CHECK(glfwCreateWindowSurface(context.instance, window, NULL, &surface)); + context.surface = surface; + TRACE("Vulkan Surface created"); -gpu_device gpu_device_create() { - gpu_device device = { 0 }; + return true; +} + +void gpu_backend_shutdown() { arena_free_storage(&context.temp_arena); } + +bool gpu_device_create(gpu_device* out_device) { // Physical device - // if (!select_physical_device()) { - // return false; - // } - INFO("Physical device selected"); + if (!select_physical_device(out_device)) { + return false; + } + TRACE("Physical device selected"); // Features - VkPhysicalDeviceFeatures device_features = {}; + VkPhysicalDeviceFeatures device_features = { 0 }; device_features.samplerAnisotropy = VK_TRUE; // request anistrophy // Logical device @@ -47,20 +117,59 @@ gpu_device gpu_device_create() { const char* extension_names = VK_KHR_SWAPCHAIN_EXTENSION_NAME; device_create_info.ppEnabledExtensionNames = &extension_names; - VkResult result = vkCreateDevice(device.physical_device, &device_create_info, context.allocator, - &device.logical_device); + VkResult result = vkCreateDevice(out_device->physical_device, &device_create_info, + context.allocator, &out_device->logical_device); if (result != VK_SUCCESS) { FATAL("Error creating logical device with status %u\n", result); exit(1); } - INFO("Logical device created"); + TRACE("Logical device created"); // Queues // Create the command pool - context.device = device; - return device; + return true; +} + +bool gpu_swapchain_create(gpu_swapchain* out_swapchain) { + VkExtent2D swapchain_extent = { context.screen_width, context.screen_height }; + + // find a format + + VkPresentModeKHR present_mode = VK_PRESENT_MODE_FIFO_KHR; // guaranteed to be implemented + + VkSwapchainCreateInfoKHR swapchain_create_info = { VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR }; + + // swapchain_create_info.minImageCount = + + VK_CHECK(vkCreateSwapchainKHR(context.device->logical_device, &swapchain_create_info, + context.allocator, &out_swapchain->handle)); + TRACE("Vulkan Swapchain created"); +} + +gpu_pipeline* gpu_graphics_pipeline_create(struct graphics_pipeline_desc description) { + VkViewport viewport = { .x = 0, + .y = 0, + .width = (f32)context.screen_width, + .height = (f32)context.screen_height, + .minDepth = 0.0, + .maxDepth = 1.0 }; + 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 + }; + viewport_state.viewportCount = 1; + viewport_state.pViewports = &viewport; + viewport_state.scissorCount = 1; + viewport_state.pScissors = &scissor; } gpu_renderpass* gpu_renderpass_create() { @@ -81,4 +190,6 @@ void encode_set_pipeline(gpu_cmd_encoder* encoder, gpu_pipeline* pipeline) { // --- Drawing inline void encode_draw_indexed(gpu_cmd_encoder* encoder, u64 index_count) { vkCmdDrawIndexed(encoder->cmd_buffer, index_count, 1, 0, 0, 0); -}
\ No newline at end of file +} + +bool select_physical_device(gpu_device* out_device) {}
\ No newline at end of file diff --git a/src/renderer/backends/backend_vulkan.h b/src/renderer/backends/backend_vulkan.h index 05f043e..dfe6a0f 100644 --- a/src/renderer/backends/backend_vulkan.h +++ b/src/renderer/backends/backend_vulkan.h @@ -1,9 +1,20 @@ #pragma once +#include <vulkan/vk_platform.h> +#include <vulkan/vulkan.h> +#include <vulkan/vulkan_core.h> + #include "defines.h" #define GPU_SWAPCHAIN_IMG_COUNT 2 +/* +Conventions: + - Place the 'handle' as the first field of a struct + - Vulkan specific data goes at the top, followed by our internal data +*/ + typedef struct gpu_swapchain { + VkSwapchainKHR handle; } gpu_swapchain; typedef struct gpu_device { // In Vulkan we store both physical and logical device here diff --git a/src/renderer/ral.h b/src/renderer/ral.h index fb77f0a..014c31e 100644 --- a/src/renderer/ral.h +++ b/src/renderer/ral.h @@ -14,6 +14,11 @@ #include "ral_types.h" #include "defines.h" #include "str.h" +#include "buf.h" + +// Unrelated forward declares +typedef struct arena arena; +struct GLFWwindow; // Forward declare structs typedef struct gpu_swapchain gpu_swapchain; @@ -34,21 +39,28 @@ typedef struct shader_desc { str8 glsl; // contents } shader_desc; -struct pipeline_desc { +struct graphics_pipeline_desc { shader_desc vs; /** @brief Vertex shader stage */ shader_desc fs; /** @brief Fragment shader stage */ }; -// lifecycle functions -gpu_device gpu_device_create(); +// --- Lifecycle functions + +bool gpu_backend_init(const char* window_name, struct GLFWwindow* window); +void gpu_backend_shutdown(); + +bool gpu_device_create(gpu_device* out_device); void gpu_device_destroy(); gpu_renderpass* gpu_renderpass_create(); void gpu_renderpass_destroy(gpu_renderpass* pass); -gpu_pipeline* gpu_pipeline_create(enum pipeline_kind kind, struct pipeline_desc description); +gpu_pipeline* gpu_graphics_pipeline_create(struct graphics_pipeline_desc description); void gpu_pipeline_destroy(gpu_pipeline* pipeline); +bool gpu_swapchain_create(gpu_swapchain* out_swapchain); +void gpu_swapchain_destroy(); + void gpu_cmd_encoder_begin(); void gpu_cmd_encoder_begin_render(); void gpu_cmd_encoder_begin_compute(); @@ -58,6 +70,10 @@ void encode_buffer_copy(gpu_cmd_encoder* encoder, buffer_handle src, u64 src_off buffer_handle dst, u64 dst_offset, u64 copy_size); void encode_clear_buffer(gpu_cmd_encoder* encoder, buffer_handle buf); void encode_set_pipeline(gpu_cmd_encoder* encoder, gpu_pipeline* pipeline); + +/** @brief Upload CPU-side data as array of bytes to a GPU buffer */ +void buffer_upload_bytes(buffer_handle gpu_buf, bytebuffer cpu_buf, u64 offset, u64 size); + // render pass void encode_set_vertex_buffer(gpu_cmd_encoder* encoder, buffer_handle buf); void encode_set_index_buffer(gpu_cmd_encoder* encoder, buffer_handle buf); @@ -84,4 +100,9 @@ void gpu_texture_destroy(); void gpu_texture_upload(); // Samplers -void gpu_sampler_create();
\ No newline at end of file +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 diff --git a/src/renderer/ral_types.h b/src/renderer/ral_types.h index a20e600..73b41f1 100644 --- a/src/renderer/ral_types.h +++ b/src/renderer/ral_types.h @@ -50,9 +50,9 @@ typedef enum gpu_texture_format { /** @brief Texture Description - used by texture creation functions */ typedef struct texture_desc { - // gpu_texture_type tex_type; - // gpu_texture_format format; - // u32x2 extents; + gpu_texture_type tex_type; + gpu_texture_format format; + u32x2 extents; } texture_desc; typedef enum vertex_format { @@ -65,7 +65,6 @@ typedef enum vertex_format { typedef union vertex { struct { vec3 position; - vec4 colour; vec2 tex_coords; vec3 normal; } static_3d; /** @brief standard vertex format for static geometry in 3D */ @@ -84,6 +83,13 @@ typedef union vertex { vec4i bone_ids; // Integer vector for bone IDs vec4 bone_weights; // Weight of each bone's influence } skinned_3d; /** @brief vertex format for skeletal (animated) geometry in 3D */ + + struct { + vec3 position; + vec2 tex_coords; + vec3 normal; + vec4 colour; + } coloured_static_3d; /** @brief vertex format used for debugging */ } vertex; #ifndef TYPED_VERTEX_ARRAY diff --git a/src/renderer/render.c b/src/renderer/render.c index 034585a..799cba7 100644 --- a/src/renderer/render.c +++ b/src/renderer/render.c @@ -1,6 +1,12 @@ #include "render.h" #include <glfw3.h> #include "camera.h" +#include "log.h" +#include "ral.h" + +/** @brief Creates the pipelines built into Celeritas such as rendering static opaque geometry, + debug visualisations, immediate mode UI, etc */ +void default_pipelines_init(renderer* ren); bool renderer_init(renderer* ren) { // INFO("Renderer init"); @@ -29,12 +35,20 @@ bool renderer_init(renderer* ren) { glfwMakeContextCurrent(ren->window); + DEBUG("Start backend init"); + + gpu_backend_init("Celeritas Engine - Vulkan", window); + gpu_device_create(&ren->device); // TODO: handle errors + gpu_swapchain_create(&ren->swapchain); + // DEBUG("init graphics api backend"); // if (!gfx_backend_init(ren)) { // FATAL("Couldnt load graphics api backend"); // return false; // } + default_pipelines_init(ren); + // ren->blinn_phong = // shader_create_separate("assets/shaders/blinn_phong.vert", // "assets/shaders/blinn_phong.frag"); @@ -46,7 +60,16 @@ bool renderer_init(renderer* ren) { return true; } -void renderer_shutdown(renderer* ren) {} +void renderer_shutdown(renderer* ren) { + // gpu_device_destroy(ren->device); +} + +void default_pipelines_init(renderer* ren) { + // Static opaque geometry + // graphics_pipeline_desc gfx = { + // }; + // ren->static_opaque_pipeline = gpu_graphics_pipeline_create(); +} void render_frame_begin(renderer* ren) {} void render_frame_end(renderer* ren) {} diff --git a/src/renderer/render_types.h b/src/renderer/render_types.h index 5faefad..6ef2461 100644 --- a/src/renderer/render_types.h +++ b/src/renderer/render_types.h @@ -29,8 +29,9 @@ typedef struct renderer { struct GLFWwindow* window; void* backend_context; renderer_config config; - gpu_device* device; - gpu_pipeline* static_opaque_pipeline; + gpu_device device; + gpu_swapchain swapchain; + gpu_pipeline static_opaque_pipeline; } renderer; typedef struct geometry_data { diff --git a/src/std/buf.h b/src/std/buf.h new file mode 100644 index 0000000..b0f8b85 --- /dev/null +++ b/src/std/buf.h @@ -0,0 +1,17 @@ +/** + * @file buf.h + * @author your name (you@domain.com) + * @brief + * @version 0.1 + * @date 2024-04-28 + * + * @copyright Copyright (c) 2024 + * + */ +#pragma once +#include "defines.h" + +typedef struct bytebuffer { + u8* buf; + size_t size; +} bytebuffer; @@ -143,11 +143,18 @@ target("core_shared") add_links("msvcrtd", "legacy_stdio_definitions") -- for debug builds end -target("main_loop") +-- target("main_loop") +-- set_kind("binary") +-- set_group("examples") +-- add_deps("core_static") +-- add_files("examples/main_loop/ex_main_loop.c") +-- set_rundir("$(projectdir)") + +target("tri") set_kind("binary") set_group("examples") add_deps("core_static") - add_files("examples/main_loop/ex_main_loop.c") + add_files("examples/triangle/ex_triangle.c") set_rundir("$(projectdir)") -- target("std") |