From f7b91c2eae24ecb7a20b638246fb849d6c63615a Mon Sep 17 00:00:00 2001 From: Omniscient <17525998+omnisci3nce@users.noreply.github.com> Date: Sat, 30 Mar 2024 21:39:31 +1100 Subject: start adding mouse input processing --- src/systems/input.c | 19 +++++++++++++++++++ src/systems/keys.h | 15 ++++++++++++++- 2 files changed, 33 insertions(+), 1 deletion(-) (limited to 'src/systems') diff --git a/src/systems/input.c b/src/systems/input.c index 292d438..fc62db8 100644 --- a/src/systems/input.c +++ b/src/systems/input.c @@ -1,11 +1,17 @@ #include "input.h" +#include #include +#include #include "log.h" +static input_state *g_input; // Use a global to simplify caller code + bool input_system_init(input_state *input, GLFWwindow *window) { INFO("Input init"); + memset(input, 0, sizeof(input_state)); + input->window = window; // Set everything to false. Could just set memory to zero but where's the fun in that for (int i = 0; i < KEYCODE_MAX; i++) { @@ -14,9 +20,16 @@ bool input_system_init(input_state *input, GLFWwindow *window) { input->just_released_keys[i] = false; } + g_input = input; + + assert(input->mouse.x_delta == 0); + assert(input->mouse.y_delta == 0); + return true; } +void input_system_shutdown(input_state *input) {} + void input_update(input_state *input) { // --- update keyboard input @@ -75,3 +88,9 @@ void input_update(input_state *input) { input->mouse = new_mouse_state; } + +bool key_is_pressed(keycode key) { return g_input->depressed_keys[key]; } + +bool key_just_pressed(keycode key) { return g_input->just_pressed_keys[key]; } + +bool key_just_released(keycode key) { return g_input->just_released_keys[key]; } \ No newline at end of file diff --git a/src/systems/keys.h b/src/systems/keys.h index 090bb49..a76e101 100644 --- a/src/systems/keys.h +++ b/src/systems/keys.h @@ -2,5 +2,18 @@ typedef enum keycode { // TODO: add all keycodes - KEYCODE_MAX + KEYCODE_SPACE = 32, + KEYCODE_A = 65, + KEYCODE_D = 68, + KEYCODE_S = 83, + KEYCODE_W = 87, + KEYCODE_ESCAPE = 256, + KEYCODE_ENTER = 257, + KEYCODE_TAB = 258, + KEYCODE_BACKSPACE = 259, + KEYCODE_KEY_RIGHT = 262, + KEYCODE_KEY_LEFT = 263, + KEYCODE_KEY_DOWN = 264, + KEYCODE_KEY_UP = 265, + KEYCODE_MAX = 348 } keycode; \ No newline at end of file -- cgit v1.2.3-70-g09d2 From fd582eeebe716dac85531d2dda8cee2c06b8ddf9 Mon Sep 17 00:00:00 2001 From: Omniscient Date: Tue, 23 Apr 2024 21:20:52 +1000 Subject: start spitballing physics --- src/defines.h | 2 +- src/logos/jobs.h | 3 +++ src/systems/physics.c | 1 + src/systems/physics.h | 19 +++++++++++++++++++ 4 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 src/logos/jobs.h create mode 100644 src/systems/physics.c create mode 100644 src/systems/physics.h (limited to 'src/systems') diff --git a/src/defines.h b/src/defines.h index 52aa7b0..7698e98 100644 --- a/src/defines.h +++ b/src/defines.h @@ -1,6 +1,6 @@ /** * @file defines.h - * @brief + * @brief Typedefs for common integer/floating point types and very basic macros * @date 2024-02-24 * @copyright Copyright (c) 2024 */ diff --git a/src/logos/jobs.h b/src/logos/jobs.h new file mode 100644 index 0000000..cc2c8fa --- /dev/null +++ b/src/logos/jobs.h @@ -0,0 +1,3 @@ +/** + * Common jobs that get run +*/ \ No newline at end of file diff --git a/src/systems/physics.c b/src/systems/physics.c new file mode 100644 index 0000000..299c0c1 --- /dev/null +++ b/src/systems/physics.c @@ -0,0 +1 @@ +#include "physics.h" \ No newline at end of file diff --git a/src/systems/physics.h b/src/systems/physics.h new file mode 100644 index 0000000..17fc746 --- /dev/null +++ b/src/systems/physics.h @@ -0,0 +1,19 @@ +#pragma once + +#include "maths_types.h" + +// 'system' means that it gets called per frame + +typedef struct physics_settings { + f32 gravity_strength; +} physics_settings; + +typedef struct physics_world { + physics_settings settings; +} physics_world; + +physics_world physics_init(physics_settings settings); +void physics_shutdown(physics_world* phys_world); + +/** @brief perform one or more simulation steps */ +void physics_system_update(physics_world* phys_world, f64 deltatime); \ No newline at end of file -- cgit v1.2.3-70-g09d2 From f8375e4587612d6a582eb053be5a67694a59993d Mon Sep 17 00:00:00 2001 From: Omniscient Date: Thu, 25 Apr 2024 10:58:39 +1000 Subject: phys collider --- src/systems/physics.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'src/systems') diff --git a/src/systems/physics.h b/src/systems/physics.h index 17fc746..5c96c6e 100644 --- a/src/systems/physics.h +++ b/src/systems/physics.h @@ -8,6 +8,20 @@ typedef struct physics_settings { f32 gravity_strength; } physics_settings; +enum collider_type { + cuboid_collider, + sphere_collider, +}; + +/** @brief generic collider structure */ +typedef struct physics_collider { + u64 id; // ? Replace with handle? + enum collider_type shape; + transform transform; + u8 layer; + bool on_ground; +} physics_collider; + typedef struct physics_world { physics_settings settings; } physics_world; -- cgit v1.2.3-70-g09d2 From d6837defc03e431517f6616ec8e49a8eb3643011 Mon Sep 17 00:00:00 2001 From: omniscient <17525998+omnisci3nce@users.noreply.github.com> Date: Sat, 27 Apr 2024 12:00:37 +1000 Subject: Start moving more files to using ral.h --- examples/transforms/ex_transforms.c | 2 +- src/core.h | 3 +- src/renderer/backends/backend_opengl.c | 6 +- src/renderer/backends/backend_vulkan.c | 62 +++--- src/renderer/cleanroom/backend_vulkan.c | 16 +- src/renderer/cleanroom/ral.h | 23 +- src/renderer/cleanroom/renderer.c | 6 +- src/renderer/cleanroom/renderer.h | 6 +- src/renderer/cleanroom/types.h | 24 +- src/renderer/render_types.h | 378 ++++++++++++++++---------------- src/resources/gltf.c | 3 +- src/systems/screenspace.h | 2 +- src/systems/text.h | 4 +- src/transform_hierarchy.c | 2 +- src/transform_hierarchy.h | 1 + 15 files changed, 277 insertions(+), 261 deletions(-) (limited to 'src/systems') diff --git a/examples/transforms/ex_transforms.c b/examples/transforms/ex_transforms.c index 689c49d..fc225b4 100644 --- a/examples/transforms/ex_transforms.c +++ b/examples/transforms/ex_transforms.c @@ -5,7 +5,7 @@ #include "maths_types.h" #include "mem.h" #include "render.h" -#include "render_types.h" +// #include "render_types.h" #include "transform_hierarchy.h" const vec3 pointlight_positions[4] = { diff --git a/src/core.h b/src/core.h index 05e3aed..68bf957 100644 --- a/src/core.h +++ b/src/core.h @@ -2,7 +2,8 @@ #include "defines.h" #include "input.h" -#include "render_types.h" +#include "ral.h" +// #include "render_types.h" #include "screenspace.h" #include "text.h" #include "threadpool.h" diff --git a/src/renderer/backends/backend_opengl.c b/src/renderer/backends/backend_opengl.c index a9f7482..ffeb051 100644 --- a/src/renderer/backends/backend_opengl.c +++ b/src/renderer/backends/backend_opengl.c @@ -5,7 +5,9 @@ #include "file.h" #include "log.h" #include "maths_types.h" -#include "render_types.h" +// #include "render_types.h" +#include "cleanroom/types.h" +#include "ral.h" #if CEL_REND_BACKEND_OPENGL @@ -60,7 +62,7 @@ void clear_screen(vec3 colour) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } -void texture_data_upload(texture* tex) { +void texture_data_upload(texture *tex) { printf("Texture name %s\n", tex->name); TRACE("Upload texture data"); u32 texture_id; diff --git a/src/renderer/backends/backend_vulkan.c b/src/renderer/backends/backend_vulkan.c index 9d0ef51..4a4b09e 100644 --- a/src/renderer/backends/backend_vulkan.c +++ b/src/renderer/backends/backend_vulkan.c @@ -867,15 +867,10 @@ void vulkan_image_view_create(vulkan_context* context, VkFormat format, vulkan_i &image->view); } -void vulkan_image_transition_layout( - vulkan_context* context, - vulkan_command_buffer* command_buffer, - vulkan_image* image, - VkFormat format, - VkImageLayout old_layout, - VkImageLayout new_layout -) { - VkImageMemoryBarrier barrier = {VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER}; +void vulkan_image_transition_layout(vulkan_context* context, vulkan_command_buffer* command_buffer, + vulkan_image* image, VkFormat format, VkImageLayout old_layout, + VkImageLayout new_layout) { + VkImageMemoryBarrier barrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER }; barrier.oldLayout = old_layout; barrier.newLayout = new_layout; barrier.srcQueueFamilyIndex = context->device.graphics_queue_index; @@ -892,12 +887,14 @@ void vulkan_image_transition_layout( VkPipelineStageFlags source_stage; VkPipelineStageFlags dest_stage; - if (old_layout == VK_IMAGE_LAYOUT_UNDEFINED && new_layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) { + 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_TOP_OF_PIPE_BIT; - } else if (old_layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && new_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) { + } 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; @@ -907,14 +904,12 @@ void vulkan_image_transition_layout( return; } - vkCmdPipelineBarrier(command_buffer->handle, source_stage, dest_stage, 0, 0, 0, 0, 0, 1, &barrier); + vkCmdPipelineBarrier(command_buffer->handle, source_stage, dest_stage, 0, 0, 0, 0, 0, 1, + &barrier); } -void vulkan_image_copy_from_buffer( - vulkan_image* image, - VkBuffer buffer, - vulkan_command_buffer* command_buffer -) { +void vulkan_image_copy_from_buffer(vulkan_image* image, VkBuffer buffer, + vulkan_command_buffer* command_buffer) { VkBufferImageCopy region; region.bufferOffset = 0; region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; @@ -925,7 +920,8 @@ void vulkan_image_copy_from_buffer( region.imageExtent.height = image->height; region.imageExtent.depth = 1; - vkCmdCopyBufferToImage(command_buffer->handle, buffer, image->handle, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); + vkCmdCopyBufferToImage(command_buffer->handle, buffer, image->handle, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); } void vulkan_image_create(vulkan_context* context, VkImageType image_type, u32 width, u32 height, @@ -1755,27 +1751,35 @@ void texture_data_upload(texture* tex) { VkFormat image_format = VK_FORMAT_R8G8B8A8_SNORM; VkBufferUsageFlags usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; - VkMemoryPropertyFlags memory_prop_flags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; + VkMemoryPropertyFlags memory_prop_flags = + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; vulkan_buffer staging; vulkan_buffer_create(&context, image_size, usage, memory_prop_flags, true, &staging); vulkan_buffer_load_data(&context, &staging, 0, image_size, 0, tex->image_data); - vulkan_image_create(&context, VK_IMAGE_TYPE_2D, tex->width, tex->height, image_format, VK_IMAGE_TILING_OPTIMAL, - VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT - , VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, true, VK_IMAGE_ASPECT_COLOR_BIT, &data->image); + vulkan_image_create( + &context, VK_IMAGE_TYPE_2D, tex->width, tex->height, image_format, VK_IMAGE_TILING_OPTIMAL, + VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | + VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, true, VK_IMAGE_ASPECT_COLOR_BIT, &data->image); vulkan_command_buffer temp_buffer; - vulkan_command_buffer_allocate_and_begin_oneshot(&context, context.device.gfx_command_pool, &temp_buffer); + vulkan_command_buffer_allocate_and_begin_oneshot(&context, context.device.gfx_command_pool, + &temp_buffer); - vulkan_image_transition_layout(&context, &temp_buffer, &data->image, image_format, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + vulkan_image_transition_layout(&context, &temp_buffer, &data->image, image_format, + VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); vulkan_image_copy_from_buffer(&data->image, staging.handle, &temp_buffer); - vulkan_image_transition_layout(&context, &temp_buffer, &data->image, image_format, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + vulkan_image_transition_layout(&context, &temp_buffer, &data->image, image_format, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - vulkan_command_buffer_end_oneshot(&context, context.device.gfx_command_pool, &temp_buffer, context.device.graphics_queue); + vulkan_command_buffer_end_oneshot(&context, context.device.gfx_command_pool, &temp_buffer, + context.device.graphics_queue); - VkSamplerCreateInfo sampler_info = {VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; + VkSamplerCreateInfo sampler_info = { VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO }; sampler_info.magFilter = VK_FILTER_LINEAR; sampler_info.minFilter = VK_FILTER_LINEAR; sampler_info.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; @@ -1792,12 +1796,12 @@ void texture_data_upload(texture* tex) { sampler_info.minLod = 0.0; sampler_info.maxLod = 0.0; - VkResult res = vkCreateSampler(context.device.logical_device, &sampler_info, context.allocator, &data->sampler); + VkResult res = vkCreateSampler(context.device.logical_device, &sampler_info, context.allocator, + &data->sampler); if (res != VK_SUCCESS) { ERROR("Error creating texture sampler for image %s", tex->name); return; } - } // TODO: destroy texture diff --git a/src/renderer/cleanroom/backend_vulkan.c b/src/renderer/cleanroom/backend_vulkan.c index 2838f20..71a09f3 100644 --- a/src/renderer/cleanroom/backend_vulkan.c +++ b/src/renderer/cleanroom/backend_vulkan.c @@ -1,16 +1,17 @@ #include #include "ral.h" #include "types.h" -#include "render_types.h" +// #include "render_types.h" #define VULKAN_QUEUES_COUNT 2 -const char* queue_names[VULKAN_QUEUES_COUNT] = { - "GRAPHICS", "TRANSFER" -}; +const char* queue_names[VULKAN_QUEUES_COUNT] = { "GRAPHICS", "TRANSFER" }; + +typedef struct gpu_device { +} gpu_device; typedef struct vulkan_context { gpu_device device; - + VkInstance instance; } vulkan_context; @@ -41,7 +42,6 @@ bool gpu_device_create(gpu_device* out_device) { // Queues // Create the command pool - } gpu_renderpass* gpu_renderpass_create() { @@ -51,8 +51,8 @@ gpu_renderpass* gpu_renderpass_create() { } void encode_set_pipeline(gpu_cmd_encoder* encoder, pipeline_type kind, gpu_pipeline* pipeline) { -// VK_PIPELINE_BIND_POINT_GRAPHICS, &shader->pipeline); - if (kind== PIPELINE_GRAPHICS) { + // VK_PIPELINE_BIND_POINT_GRAPHICS, &shader->pipeline); + if (kind == PIPELINE_GRAPHICS) { // ... } else { // ... diff --git a/src/renderer/cleanroom/ral.h b/src/renderer/cleanroom/ral.h index 8f7c8a4..a1e9929 100644 --- a/src/renderer/cleanroom/ral.h +++ b/src/renderer/cleanroom/ral.h @@ -14,12 +14,6 @@ #include "cleanroom/types.h" #include "defines.h" -// TODO: Replace with handle defines -typedef int buffer_handle; -typedef int texture_handle; -typedef int sampler_handle; -typedef int model_handle; - // Forward declare structs typedef struct gpu_swapchain gpu_swapchain; typedef struct gpu_device gpu_device; @@ -28,6 +22,21 @@ 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 +enum pipeline_kind { + GRAPHICS, + COMPUTE, +} pipeline_kind; + +typedef struct shader_desc { + const char* debug_name; + str8 filepath; // where it came from + str8 glsl; // contents +} shader_desc; + +struct pipeline_desc { + shader_desc vs; /** @brief Vertex shader stage */ + shader_desc fs; /** @brief Fragment shader stage */ +}; // lifecycle functions gpu_device* gpu_device_create(); @@ -36,7 +45,7 @@ void gpu_device_destroy(); gpu_renderpass* gpu_renderpass_create(); void gpu_renderpass_destroy(gpu_renderpass* pass); -gpu_pipeline* gpu_pipeline_create(pipeline_kind kind); +gpu_pipeline* gpu_pipeline_create(enum pipeline_kind kind, struct pipeline_desc description); void gpu_pipeline_destroy(gpu_pipeline* pipeline); void gpu_cmd_encoder_begin(); diff --git a/src/renderer/cleanroom/renderer.c b/src/renderer/cleanroom/renderer.c index 65c09de..a874664 100644 --- a/src/renderer/cleanroom/renderer.c +++ b/src/renderer/cleanroom/renderer.c @@ -1,6 +1,4 @@ -#include "render_types.h" #include "defines.h" +#include "render_types.h" -bool renderer_init() { - -} \ No newline at end of file +bool renderer_init() {} \ No newline at end of file diff --git a/src/renderer/cleanroom/renderer.h b/src/renderer/cleanroom/renderer.h index 7d56fe2..8012b49 100644 --- a/src/renderer/cleanroom/renderer.h +++ b/src/renderer/cleanroom/renderer.h @@ -7,4 +7,8 @@ typedef struct renderer2 { void* backend_state; gpu_device* device; gpu_pipeline* static_opaque_pipeline; -} renderer2; \ No newline at end of file +} renderer2; + +// mesh +// model +// material \ No newline at end of file diff --git a/src/renderer/cleanroom/types.h b/src/renderer/cleanroom/types.h index a37e0e6..98c2e21 100644 --- a/src/renderer/cleanroom/types.h +++ b/src/renderer/cleanroom/types.h @@ -4,11 +4,11 @@ #include "maths_types.h" #include "str.h" -// TODO: Replace with handle defines -typedef int buffer_handle; -typedef int texture_handle; -typedef int sampler_handle; -typedef int model_handle; +CORE_DEFINE_HANDLE(buffer_handle); +CORE_DEFINE_HANDLE(texture_handle); +CORE_DEFINE_HANDLE(sampler_handle); +CORE_DEFINE_HANDLE(shader_handle); +CORE_DEFINE_HANDLE(model_handle); typedef struct transform_hierarchy {} transform_hierarchy; @@ -56,7 +56,7 @@ typedef struct model bp_material; // blinn-phong #include "maths_types.h" -typedef enum vertex_format { VERTEX_STATIC_3D, VERTEX_SPRITE, VERTEX_COUNT } vertex_format; +typedef enum vertex_format { VERTEX_STATIC_3D, VERTEX_SPRITE, VERTEX_SKINNED, VERTEX_COUNT } vertex_format; typedef union vertex { struct { @@ -70,7 +70,7 @@ typedef union vertex { vec2 position; vec4 colour; vec2 tex_coords; - } sprite; + } sprite; /** @brief vertex format for 2D sprites or quads */ struct { vec3 position; @@ -79,7 +79,7 @@ typedef union vertex { vec3 normal; 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 */ + } skinned_3d; /** @brief vertex format for skeletal (animated) geometry in 3D */ } vertex; KITC_DECL_TYPED_ARRAY(vertex) @@ -88,6 +88,7 @@ KITC_DECL_TYPED_ARRAY(u32) typedef struct geometry_data { vertex_format format; vertex_darray vertices; + bool has_indices; u32_darray indices; } geometry_data; @@ -107,6 +108,7 @@ C side - reload_model(): */ +// TODO: move to some sort of render layer (not inside the abstraction layer) typedef struct model { str8 debug_name; mesh* meshes; @@ -126,12 +128,6 @@ typedef struct model { /* ral.h */ -// enum pipeline_type { -// GRAPHICS, -// COMPUTE, -// } pipeline_type; - - // command buffer gubbins diff --git a/src/renderer/render_types.h b/src/renderer/render_types.h index 6252dee..af20999 100644 --- a/src/renderer/render_types.h +++ b/src/renderer/render_types.h @@ -1,189 +1,189 @@ -/** - * @file render_types.h - * @author Omniscient - * @brief Type definitions for the majority of data required by the renderer system - * @date 2024-02-24 - * - */ -#pragma once - -#include "darray.h" -#include "maths.h" -#include "maths_types.h" -#include "str.h" - -struct GLFWwindow; - -#define MAX_MATERIAL_NAME_LEN 256 -#define MAX_TEXTURE_NAME_LEN 256 - -#ifndef RESOURCE_HANDLE_DEFS -CORE_DEFINE_HANDLE(model_handle); -#define ABSENT_MODEL_HANDLE 999999999 -CORE_DEFINE_HANDLE(texture_handle); -#define RESOURCE_HANDLE_DEFS -#endif - -/* @brief Opaque wrapper around a shader program */ -typedef struct shader { - u32 program_id; -} shader; - -/** @brief configuration passed to the renderer at init time */ -typedef struct renderer_config { - char window_name[256]; - u32 scr_width, scr_height; - vec3 clear_colour; /** colour that the screen gets cleared to every frame */ -} renderer_config; - -typedef struct frame_stats { - u64 last_time; -} frame_stats; - -typedef struct renderer { - struct GLFWwindow *window; /** Currently all platforms use GLFW*/ - void *backend_state; /** Graphics API-specific state */ - renderer_config config; - // shaders - shader blinn_phong; -} renderer; - -// --- Lighting & Materials - -typedef struct texture { - u32 texture_id; - char name[MAX_TEXTURE_NAME_LEN]; - void* image_data; - void* backend_data; - u32 width; - u32 height; - u8 channel_count; - u32 channel_type; -} texture; - -typedef struct blinn_phong_material { - char name[MAX_MATERIAL_NAME_LEN]; - texture diffuse_texture; - char diffuse_tex_path[256]; - texture specular_texture; - char specular_tex_path[256]; - vec3 ambient_colour; - vec3 diffuse; - vec3 specular; - f32 spec_exponent; - bool is_loaded; - bool is_uploaded; -} blinn_phong_material; -typedef blinn_phong_material material; // when we start using PBR, this will no longer be the case - -// the default blinn-phong material. MUST be initialised with the function below -extern material DEFAULT_MATERIAL; -void default_material_init(); - -#ifndef TYPED_MATERIAL_ARRAY -KITC_DECL_TYPED_ARRAY(material) // creates "material_darray" -#define TYPED_MATERIAL_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; - -void point_light_upload_uniforms(shader shader, point_light *light, char index); -void dir_light_upload_uniforms(shader shader, directional_light *light); - -// --- Models & Meshes - -/** @brief Vertex format for a static mesh */ -typedef struct vertex { - vec3 position; - vec3 normal; - vec2 uv; -} vertex; - -#ifndef TYPED_VERTEX_ARRAY -KITC_DECL_TYPED_ARRAY(vertex) // creates "vertex_darray" -#define TYPED_VERTEX_ARRAY -#endif - -typedef struct mesh { - vertex_darray *vertices; - u32 vertex_size; /** size in bytes of each vertex including necessary padding */ - bool has_indices; - u32 *indices; - u32 indices_len; - size_t material_index; - u32 vbo, vao; /** OpenGL data. TODO: dont leak OpenGL details */ -} mesh; - -#ifndef TYPED_MESH_ARRAY -KITC_DECL_TYPED_ARRAY(mesh) // creates "mesh_darray" -#define TYPED_MESH_ARRAY -#endif - -typedef struct model { - str8 name; - mesh_darray *meshes; - aabb_3d bbox; - material_darray *materials; - bool is_loaded; - bool is_uploaded; -} model; - -#ifndef TYPED_MODEL_ARRAY -KITC_DECL_TYPED_ARRAY(model) // creates "model_darray" -#define TYPED_MODEL_ARRAY -#endif - -// --- Scene - -// NOTE: This struct won't stay like this for a long time. It's somewhat temporary -// in order to get a basic scene working without putting burden on the caller of -// draw_model() -typedef struct scene { - directional_light dir_light; - point_light point_lights[4]; - size_t n_point_lights; -} scene; - -// --- Graphics API related - -typedef enum cel_primitive_topology { - CEL_PRIMITIVE_TOPOLOGY_POINT, - CEL_PRIMITIVE_TOPOLOGY_LINE, - CEL_PRIMITIVE_TOPOLOGY_LINE_STRIP, - CEL_PRIMITIVE_TOPOLOGY_TRIANGLE, - CEL_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, - CEL_PRIMITIVE_TOPOLOGY_COUNT -} cel_primitive_topology; - -typedef enum gpu_texture_type { - TEXTURE_TYPE_2D, - TEXTURE_TYPE_3D, - TEXTURE_TYPE_2D_ARRAY, - TEXTURE_TYPE_CUBE_MAP, - TEXTURE_TYPE_COUNT -} gpu_texture_type; - -typedef enum gpu_texture_format { - TEXTURE_FORMAT_8_8_8_8_RGBA_UNORM, - TEXTURE_FORMAT_DEPTH_DEFAULT, - TEXTURE_FORMAT_COUNT -} gpu_texture_format; - -typedef enum pipeline_kind { - GRAPHICS, - COMPUTE, -} pipeline_kind; \ No newline at end of file +// /** +// * @file render_types.h +// * @author Omniscient +// * @brief Type definitions for the majority of data required by the renderer system +// * @date 2024-02-24 +// * +// */ +// #pragma once + +// #include "darray.h" +// #include "maths.h" +// #include "maths_types.h" +// #include "str.h" + +// struct GLFWwindow; + +// #define MAX_MATERIAL_NAME_LEN 256 +// #define MAX_TEXTURE_NAME_LEN 256 + +// #ifndef RESOURCE_HANDLE_DEFS +// // CORE_DEFINE_HANDLE(model_handle); +// #define ABSENT_MODEL_HANDLE 999999999 +// // CORE_DEFINE_HANDLE(texture_handle); +// #define RESOURCE_HANDLE_DEFS +// #endif + +// /* @brief Opaque wrapper around a shader program */ +// typedef struct shader { +// u32 program_id; +// } shader; + +// /** @brief configuration passed to the renderer at init time */ +// typedef struct renderer_config { +// char window_name[256]; +// u32 scr_width, scr_height; +// vec3 clear_colour; /** colour that the screen gets cleared to every frame */ +// } renderer_config; + +// typedef struct frame_stats { +// u64 last_time; +// } frame_stats; + +// typedef struct renderer { +// struct GLFWwindow *window; /** Currently all platforms use GLFW*/ +// void *backend_state; /** Graphics API-specific state */ +// renderer_config config; +// // shaders +// shader blinn_phong; +// } renderer; + +// // --- Lighting & Materials + +// typedef struct texture { +// u32 texture_id; +// char name[MAX_TEXTURE_NAME_LEN]; +// void* image_data; +// void* backend_data; +// u32 width; +// u32 height; +// u8 channel_count; +// u32 channel_type; +// } texture; + +// typedef struct blinn_phong_material { +// char name[MAX_MATERIAL_NAME_LEN]; +// texture diffuse_texture; +// char diffuse_tex_path[256]; +// texture specular_texture; +// char specular_tex_path[256]; +// vec3 ambient_colour; +// vec3 diffuse; +// vec3 specular; +// f32 spec_exponent; +// bool is_loaded; +// bool is_uploaded; +// } blinn_phong_material; +// typedef blinn_phong_material material; // when we start using PBR, this will no longer be the case + +// // the default blinn-phong material. MUST be initialised with the function below +// extern material DEFAULT_MATERIAL; +// void default_material_init(); + +// #ifndef TYPED_MATERIAL_ARRAY +// KITC_DECL_TYPED_ARRAY(material) // creates "material_darray" +// #define TYPED_MATERIAL_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; + +// void point_light_upload_uniforms(shader shader, point_light *light, char index); +// void dir_light_upload_uniforms(shader shader, directional_light *light); + +// // --- Models & Meshes + +// /** @brief Vertex format for a static mesh */ +// typedef struct vertex { +// vec3 position; +// vec3 normal; +// vec2 uv; +// } vertex; + +// #ifndef TYPED_VERTEX_ARRAY +// KITC_DECL_TYPED_ARRAY(vertex) // creates "vertex_darray" +// #define TYPED_VERTEX_ARRAY +// #endif + +// typedef struct mesh { +// vertex_darray *vertices; +// u32 vertex_size; /** size in bytes of each vertex including necessary padding */ +// bool has_indices; +// u32 *indices; +// u32 indices_len; +// size_t material_index; +// u32 vbo, vao; /** OpenGL data. TODO: dont leak OpenGL details */ +// } mesh; + +// #ifndef TYPED_MESH_ARRAY +// KITC_DECL_TYPED_ARRAY(mesh) // creates "mesh_darray" +// #define TYPED_MESH_ARRAY +// #endif + +// typedef struct model { +// str8 name; +// mesh_darray *meshes; +// aabb_3d bbox; +// material_darray *materials; +// bool is_loaded; +// bool is_uploaded; +// } model; + +// #ifndef TYPED_MODEL_ARRAY +// KITC_DECL_TYPED_ARRAY(model) // creates "model_darray" +// #define TYPED_MODEL_ARRAY +// #endif + +// // --- Scene + +// // NOTE: This struct won't stay like this for a long time. It's somewhat temporary +// // in order to get a basic scene working without putting burden on the caller of +// // draw_model() +// typedef struct scene { +// directional_light dir_light; +// point_light point_lights[4]; +// size_t n_point_lights; +// } scene; + +// // --- Graphics API related + +// // typedef enum cel_primitive_topology { +// // CEL_PRIMITIVE_TOPOLOGY_POINT, +// // CEL_PRIMITIVE_TOPOLOGY_LINE, +// // CEL_PRIMITIVE_TOPOLOGY_LINE_STRIP, +// // CEL_PRIMITIVE_TOPOLOGY_TRIANGLE, +// // CEL_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, +// // CEL_PRIMITIVE_TOPOLOGY_COUNT +// // } cel_primitive_topology; + +// // typedef enum gpu_texture_type { +// // TEXTURE_TYPE_2D, +// // TEXTURE_TYPE_3D, +// // TEXTURE_TYPE_2D_ARRAY, +// // TEXTURE_TYPE_CUBE_MAP, +// // TEXTURE_TYPE_COUNT +// // } gpu_texture_type; + +// // typedef enum gpu_texture_format { +// // TEXTURE_FORMAT_8_8_8_8_RGBA_UNORM, +// // TEXTURE_FORMAT_DEPTH_DEFAULT, +// // TEXTURE_FORMAT_COUNT +// // } gpu_texture_format; + +// // typedef enum pipeline_kind { +// // GRAPHICS, +// // COMPUTE, +// // } pipeline_kind; \ No newline at end of file diff --git a/src/resources/gltf.c b/src/resources/gltf.c index b269fcd..f4e11f2 100644 --- a/src/resources/gltf.c +++ b/src/resources/gltf.c @@ -8,12 +8,11 @@ #include "log.h" #include "path.h" #include "render.h" -#include "render_types.h" +// #include "render_types.h" #include "str.h" #define CGLTF_IMPLEMENTATION #include -// TODO: Port code from old repo struct face { cgltf_uint indices[3]; diff --git a/src/systems/screenspace.h b/src/systems/screenspace.h index 2250847..f513148 100644 --- a/src/systems/screenspace.h +++ b/src/systems/screenspace.h @@ -37,7 +37,7 @@ KITC_DECL_TYPED_ARRAY(draw_cmd) typedef struct screenspace_state { u32 rect_vbo; u32 rect_vao; - shader rect_shader; + // shader rect_shader; draw_cmd_darray* draw_cmd_buf; } screenspace_state; diff --git a/src/systems/text.h b/src/systems/text.h index 19248a6..4fac0b8 100644 --- a/src/systems/text.h +++ b/src/systems/text.h @@ -5,9 +5,11 @@ #include +#include "cleanroom/types.h" #include "darray.h" #include "defines.h" #include "render_types.h" +#include "ral.h" struct core; @@ -29,7 +31,7 @@ KITC_DECL_TYPED_ARRAY(draw_text_packet) typedef struct text_system_state { font default_font; - shader glyph_shader; + shader_handle glyph_shader; u32 glyph_vbo; u32 glyph_vao; draw_text_packet_darray *draw_cmd_buf; diff --git a/src/transform_hierarchy.c b/src/transform_hierarchy.c index f1c859a..2f2ff01 100644 --- a/src/transform_hierarchy.c +++ b/src/transform_hierarchy.c @@ -11,7 +11,7 @@ #include "log.h" #include "maths.h" #include "maths_types.h" -#include "render_types.h" +// #include "render_types.h" struct transform_hierarchy { transform_node root; diff --git a/src/transform_hierarchy.h b/src/transform_hierarchy.h index af77ee1..d77b846 100644 --- a/src/transform_hierarchy.h +++ b/src/transform_hierarchy.h @@ -5,6 +5,7 @@ #include "maths_types.h" #include "render_types.h" +#include "ral.h" #define MAX_TF_NODE_CHILDREN \ 32 /** TEMP: Make it simpler to manage children in `transform_node`s */ -- cgit v1.2.3-70-g09d2 From 4e6897aa8c8769a556ad58081eba5a90226e551d Mon Sep 17 00:00:00 2001 From: omnisci3nce Date: Sat, 27 Apr 2024 15:37:52 +1000 Subject: wip --- src/defines.h | 6 +- src/logos/README.md | 6 ++ src/maths/maths.h | 25 +---- src/maths/maths_types.h | 33 ++++++- src/maths/primitives.c | 187 +++++++++++++++++++++++++++++++++++ src/maths/primitives.h | 162 ++---------------------------- src/renderer/backends/backend_dx11.c | 3 + src/systems/terrain.c | 0 src/systems/terrain.h | 10 ++ 9 files changed, 250 insertions(+), 182 deletions(-) create mode 100644 src/logos/README.md create mode 100644 src/maths/primitives.c create mode 100644 src/renderer/backends/backend_dx11.c create mode 100644 src/systems/terrain.c create mode 100644 src/systems/terrain.h (limited to 'src/systems') diff --git a/src/defines.h b/src/defines.h index 8cd4f98..54f2dd5 100644 --- a/src/defines.h +++ b/src/defines.h @@ -65,11 +65,15 @@ Renderer backend defines: */ // Platform will inform renderer backend (unless user overrides) -#if defined(CEL_PLATFORM_LINUX) || defined(CEL_PLATFORM_WINDOWS) +#if defined(CEL_PLATFORM_LINUX) #define CEL_REND_BACKEND_OPENGL 1 // #define CEL_REND_BACKEND_VULKAN 1 #endif +#if defined(CEL_PLATFORM_WINDOWS) +#define CEL_REND_BACKEND_DX11 1 +#endif + #if defined(CEL_PLATFORM_MAC) // #define CEL_REND_BACKEND_METAL 1 #define CEL_REND_BACKEND_OPENGL 1 diff --git a/src/logos/README.md b/src/logos/README.md new file mode 100644 index 0000000..25b7bef --- /dev/null +++ b/src/logos/README.md @@ -0,0 +1,6 @@ +# Logos + +Logos is the namespace for threadpool & job system code. This is not a 'system' as it is underlying core unit of the engine. + +Threadpool currently gets initialised at core bringup with a set number of threads and results are processed once per frame +on the main thread. This is subject to change but multithreading is not the highest priority right now. \ No newline at end of file diff --git a/src/maths/maths.h b/src/maths/maths.h index e0d39d7..ad33981 100644 --- a/src/maths/maths.h +++ b/src/maths/maths.h @@ -319,27 +319,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"); - -// --- Some other types -typedef struct u32x3 { - union { - struct { - u32 x; - u32 y; - u32 z; - }; - struct { - u32 r; - u32 g; - u32 b; - }; - }; -} u32x3; -#define u32x3(x, y, z) ((u32x3){ x, y, z }) - -typedef struct u32x2 { - u32 x; - u32 y; -} u32x2; -#define u32x2(x, y) ((u32x3){ x, y }) \ No newline at end of file +_Static_assert(alignof(vec4) == 4, "vec4 is 4 byte aligned"); \ No newline at end of file diff --git a/src/maths/maths_types.h b/src/maths/maths_types.h index 53cac55..aa86eb0 100644 --- a/src/maths/maths_types.h +++ b/src/maths/maths_types.h @@ -68,4 +68,35 @@ typedef struct vec4i { typedef struct vec4u { u32 x, y, z, w; -} vec4u; \ No newline at end of file +} vec4u; + +// --- Some other types +typedef struct u32x3 { + union { + struct { + u32 x; + u32 y; + u32 z; + }; + struct { + u32 r; + u32 g; + u32 b; + }; + }; +} u32x3; +#define u32x3(x, y, z) ((u32x3){ x, y, z }) + +typedef struct u32x2 { + u32 x; + u32 y; +} u32x2; +#define u32x2(x, y) ((u32x3){ x, y }) + +// Type aliass + +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 diff --git a/src/maths/primitives.c b/src/maths/primitives.c new file mode 100644 index 0000000..42c51ea --- /dev/null +++ b/src/maths/primitives.c @@ -0,0 +1,187 @@ +#include "primitives.h" + +// vertices +f32 plane_vertex_positions[] = { + // triangle 1 + -0.5, 0, -0.5, -0.5, 0, 0.5, 0.5, 0, -0.5, + // triangle 2 + 0.5, 0, -0.5, -0.5, 0, 0.5, 0.5, 0, 0.5 +}; + +geometry_data geo_create_plane(f32x2 extents) { + f32x2 half_extents = vec2_div(extents, 2.0); + vertex_format format = VERTEX_STATIC_3D; + vertex_darray* vertices = vertex_darray_new(4); + + vertex_darray_push( + vertices, + (vertex) {.static_3d = { + .position = + }} + ); + + return (geometry_data) { + .format = format, + .vertices = + .has_indices = true, + } +} + + +// OLD + +static const vec3 BACK_BOT_LEFT = (vec3){ 0, 0, 0 }; +static const vec3 BACK_BOT_RIGHT = (vec3){ 1, 0, 0 }; +static const vec3 BACK_TOP_LEFT = (vec3){ 0, 1, 0 }; +static const vec3 BACK_TOP_RIGHT = (vec3){ 1, 1, 0 }; +static const vec3 FRONT_BOT_LEFT = (vec3){ 0, 0, 1 }; +static const vec3 FRONT_BOT_RIGHT = (vec3){ 1, 0, 1 }; +static const vec3 FRONT_TOP_LEFT = (vec3){ 0, 1, 1 }; +static const vec3 FRONT_TOP_RIGHT = (vec3){ 1, 1, 1 }; + +static mesh prim_cube_mesh_create() { + mesh cube = { 0 }; + cube.vertices = vertex_darray_new(36); + + // back faces + vertex_darray_push( + cube.vertices, + (vertex){ .position = BACK_BOT_LEFT, .normal = VEC3_NEG_Z, .uv = (vec2){ 0, 1 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = BACK_TOP_LEFT, .normal = VEC3_NEG_Z, .uv = (vec2){ 0, 0 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = BACK_TOP_RIGHT, .normal = VEC3_NEG_Z, .uv = (vec2){ 1, 0 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = BACK_TOP_RIGHT, .normal = VEC3_NEG_Z, .uv = (vec2){ 1, 0 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = BACK_BOT_RIGHT, .normal = VEC3_NEG_Z, .uv = (vec2){ 1, 1 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = BACK_BOT_LEFT, .normal = VEC3_NEG_Z, .uv = (vec2){ 0, 1 } }); + + // front faces + vertex_darray_push( + cube.vertices, + (vertex){ .position = FRONT_BOT_LEFT, .normal = VEC3_Z, .uv = (vec2){ 0, 1 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_Z, .uv = (vec2){ 1, 0 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = FRONT_TOP_LEFT, .normal = VEC3_Z, .uv = (vec2){ 0, 0 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = FRONT_BOT_LEFT, .normal = VEC3_Z, .uv = (vec2){ 0, 1 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = FRONT_BOT_RIGHT, .normal = VEC3_Z, .uv = (vec2){ 1, 1 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_Z, .uv = (vec2){ 1, 0 } }); + + // top faces + vertex_darray_push(cube.vertices, + (vertex){ .position = BACK_TOP_LEFT, .normal = VEC3_Y, .uv = (vec2){ 0, 0 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = FRONT_TOP_LEFT, .normal = VEC3_Y, .uv = (vec2){ 0, 1 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_Y, .uv = (vec2){ 1, 1 } }); + vertex_darray_push(cube.vertices, + (vertex){ .position = BACK_TOP_LEFT, .normal = VEC3_Y, .uv = (vec2){ 0, 0 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_Y, .uv = (vec2){ 1, 1 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = BACK_TOP_RIGHT, .normal = VEC3_Y, .uv = (vec2){ 1, 0 } }); + + // bottom faces + vertex_darray_push( + cube.vertices, + (vertex){ .position = BACK_BOT_LEFT, .normal = VEC3_NEG_Y, .uv = (vec2){ 0 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = FRONT_BOT_RIGHT, .normal = VEC3_NEG_Y, .uv = (vec2){ 0 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = FRONT_BOT_LEFT, .normal = VEC3_NEG_Y, .uv = (vec2){ 0 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = BACK_BOT_LEFT, .normal = VEC3_NEG_Y, .uv = (vec2){ 0 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = BACK_BOT_RIGHT, .normal = VEC3_NEG_Y, .uv = (vec2){ 0 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = FRONT_BOT_RIGHT, .normal = VEC3_NEG_Y, .uv = (vec2){ 0 } }); + + // right faces + vertex_darray_push( + cube.vertices, + (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_X, .uv = (vec2){ 0, 0 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = BACK_BOT_RIGHT, .normal = VEC3_X, .uv = (vec2){ 1, 1 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = BACK_TOP_RIGHT, .normal = VEC3_X, .uv = (vec2){ 1, 0 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = BACK_BOT_RIGHT, .normal = VEC3_X, .uv = (vec2){ 1, 1 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_X, .uv = (vec2){ 0, 0 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = FRONT_BOT_RIGHT, .normal = VEC3_X, .uv = (vec2){ 0, 1 } }); + + // left faces + vertex_darray_push( + cube.vertices, + (vertex){ .position = FRONT_TOP_LEFT, .normal = VEC3_NEG_X, .uv = (vec2){ 0 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = BACK_TOP_LEFT, .normal = VEC3_NEG_X, .uv = (vec2){ 0 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = BACK_BOT_LEFT, .normal = VEC3_NEG_X, .uv = (vec2){ 0 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = BACK_BOT_LEFT, .normal = VEC3_NEG_X, .uv = (vec2){ 0 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = FRONT_BOT_LEFT, .normal = VEC3_NEG_X, .uv = (vec2){ 0 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = FRONT_TOP_LEFT, .normal = VEC3_NEG_X, .uv = (vec2){ 0 } }); + + cube.indices_len = cube.vertices->len; + cube.indices = malloc(sizeof(u32) * cube.indices_len); + + for (u32 i = 0; i < cube.indices_len; i++) { + cube.indices[i] = i; + } + + cube.has_indices = true; + + return cube; +} + +/** @brief create a new model with the shape of a cube */ +static model_handle prim_cube_new(core* core) { + model model = { 0 }; + mesh cube = prim_cube_mesh_create(); + + mesh_darray_push(model.meshes, cube); + assert(mesh_darray_len(model.meshes) == 1); + + u32 index = (u32)model_darray_len(core->models); + model_darray_push_copy(core->models, &model); + return (model_handle){ .raw = index }; +} \ No newline at end of file diff --git a/src/maths/primitives.h b/src/maths/primitives.h index ed52c8c..3e0cc5f 100644 --- a/src/maths/primitives.h +++ b/src/maths/primitives.h @@ -3,161 +3,11 @@ #include #include #include "core.h" -#include "maths.h" +#include "maths_types.h" #include "render_types.h" -static const vec3 BACK_BOT_LEFT = (vec3){ 0, 0, 0 }; -static const vec3 BACK_BOT_RIGHT = (vec3){ 1, 0, 0 }; -static const vec3 BACK_TOP_LEFT = (vec3){ 0, 1, 0 }; -static const vec3 BACK_TOP_RIGHT = (vec3){ 1, 1, 0 }; -static const vec3 FRONT_BOT_LEFT = (vec3){ 0, 0, 1 }; -static const vec3 FRONT_BOT_RIGHT = (vec3){ 1, 0, 1 }; -static const vec3 FRONT_TOP_LEFT = (vec3){ 0, 1, 1 }; -static const vec3 FRONT_TOP_RIGHT = (vec3){ 1, 1, 1 }; - -static mesh prim_cube_mesh_create() { - mesh cube = { 0 }; - cube.vertices = vertex_darray_new(36); - - // back faces - vertex_darray_push( - cube.vertices, - (vertex){ .position = BACK_BOT_LEFT, .normal = VEC3_NEG_Z, .uv = (vec2){ 0, 1 } }); - vertex_darray_push( - cube.vertices, - (vertex){ .position = BACK_TOP_LEFT, .normal = VEC3_NEG_Z, .uv = (vec2){ 0, 0 } }); - vertex_darray_push( - cube.vertices, - (vertex){ .position = BACK_TOP_RIGHT, .normal = VEC3_NEG_Z, .uv = (vec2){ 1, 0 } }); - vertex_darray_push( - cube.vertices, - (vertex){ .position = BACK_TOP_RIGHT, .normal = VEC3_NEG_Z, .uv = (vec2){ 1, 0 } }); - vertex_darray_push( - cube.vertices, - (vertex){ .position = BACK_BOT_RIGHT, .normal = VEC3_NEG_Z, .uv = (vec2){ 1, 1 } }); - vertex_darray_push( - cube.vertices, - (vertex){ .position = BACK_BOT_LEFT, .normal = VEC3_NEG_Z, .uv = (vec2){ 0, 1 } }); - - // front faces - vertex_darray_push( - cube.vertices, - (vertex){ .position = FRONT_BOT_LEFT, .normal = VEC3_Z, .uv = (vec2){ 0, 1 } }); - vertex_darray_push( - cube.vertices, - (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_Z, .uv = (vec2){ 1, 0 } }); - vertex_darray_push( - cube.vertices, - (vertex){ .position = FRONT_TOP_LEFT, .normal = VEC3_Z, .uv = (vec2){ 0, 0 } }); - vertex_darray_push( - cube.vertices, - (vertex){ .position = FRONT_BOT_LEFT, .normal = VEC3_Z, .uv = (vec2){ 0, 1 } }); - vertex_darray_push( - cube.vertices, - (vertex){ .position = FRONT_BOT_RIGHT, .normal = VEC3_Z, .uv = (vec2){ 1, 1 } }); - vertex_darray_push( - cube.vertices, - (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_Z, .uv = (vec2){ 1, 0 } }); - - // top faces - vertex_darray_push(cube.vertices, - (vertex){ .position = BACK_TOP_LEFT, .normal = VEC3_Y, .uv = (vec2){ 0, 0 } }); - vertex_darray_push( - cube.vertices, - (vertex){ .position = FRONT_TOP_LEFT, .normal = VEC3_Y, .uv = (vec2){ 0, 1 } }); - vertex_darray_push( - cube.vertices, - (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_Y, .uv = (vec2){ 1, 1 } }); - vertex_darray_push(cube.vertices, - (vertex){ .position = BACK_TOP_LEFT, .normal = VEC3_Y, .uv = (vec2){ 0, 0 } }); - vertex_darray_push( - cube.vertices, - (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_Y, .uv = (vec2){ 1, 1 } }); - vertex_darray_push( - cube.vertices, - (vertex){ .position = BACK_TOP_RIGHT, .normal = VEC3_Y, .uv = (vec2){ 1, 0 } }); - - // bottom faces - vertex_darray_push( - cube.vertices, - (vertex){ .position = BACK_BOT_LEFT, .normal = VEC3_NEG_Y, .uv = (vec2){ 0 } }); - vertex_darray_push( - cube.vertices, - (vertex){ .position = FRONT_BOT_RIGHT, .normal = VEC3_NEG_Y, .uv = (vec2){ 0 } }); - vertex_darray_push( - cube.vertices, - (vertex){ .position = FRONT_BOT_LEFT, .normal = VEC3_NEG_Y, .uv = (vec2){ 0 } }); - vertex_darray_push( - cube.vertices, - (vertex){ .position = BACK_BOT_LEFT, .normal = VEC3_NEG_Y, .uv = (vec2){ 0 } }); - vertex_darray_push( - cube.vertices, - (vertex){ .position = BACK_BOT_RIGHT, .normal = VEC3_NEG_Y, .uv = (vec2){ 0 } }); - vertex_darray_push( - cube.vertices, - (vertex){ .position = FRONT_BOT_RIGHT, .normal = VEC3_NEG_Y, .uv = (vec2){ 0 } }); - - // right faces - vertex_darray_push( - cube.vertices, - (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_X, .uv = (vec2){ 0, 0 } }); - vertex_darray_push( - cube.vertices, - (vertex){ .position = BACK_BOT_RIGHT, .normal = VEC3_X, .uv = (vec2){ 1, 1 } }); - vertex_darray_push( - cube.vertices, - (vertex){ .position = BACK_TOP_RIGHT, .normal = VEC3_X, .uv = (vec2){ 1, 0 } }); - vertex_darray_push( - cube.vertices, - (vertex){ .position = BACK_BOT_RIGHT, .normal = VEC3_X, .uv = (vec2){ 1, 1 } }); - vertex_darray_push( - cube.vertices, - (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_X, .uv = (vec2){ 0, 0 } }); - vertex_darray_push( - cube.vertices, - (vertex){ .position = FRONT_BOT_RIGHT, .normal = VEC3_X, .uv = (vec2){ 0, 1 } }); - - // left faces - vertex_darray_push( - cube.vertices, - (vertex){ .position = FRONT_TOP_LEFT, .normal = VEC3_NEG_X, .uv = (vec2){ 0 } }); - vertex_darray_push( - cube.vertices, - (vertex){ .position = BACK_TOP_LEFT, .normal = VEC3_NEG_X, .uv = (vec2){ 0 } }); - vertex_darray_push( - cube.vertices, - (vertex){ .position = BACK_BOT_LEFT, .normal = VEC3_NEG_X, .uv = (vec2){ 0 } }); - vertex_darray_push( - cube.vertices, - (vertex){ .position = BACK_BOT_LEFT, .normal = VEC3_NEG_X, .uv = (vec2){ 0 } }); - vertex_darray_push( - cube.vertices, - (vertex){ .position = FRONT_BOT_LEFT, .normal = VEC3_NEG_X, .uv = (vec2){ 0 } }); - vertex_darray_push( - cube.vertices, - (vertex){ .position = FRONT_TOP_LEFT, .normal = VEC3_NEG_X, .uv = (vec2){ 0 } }); - - cube.indices_len = cube.vertices->len; - cube.indices = malloc(sizeof(u32) * cube.indices_len); - - for (u32 i = 0; i < cube.indices_len; i++) { - cube.indices[i] = i; - } - - cube.has_indices = true; - - return cube; -} - -/** @brief create a new model with the shape of a cube */ -static model_handle prim_cube_new(core* core) { - model model = { 0 }; - mesh cube = prim_cube_mesh_create(); - - mesh_darray_push(model.meshes, cube); - assert(mesh_darray_len(model.meshes) == 1); - - u32 index = (u32)model_darray_len(core->models); - model_darray_push_copy(core->models, &model); - return (model_handle){ .raw = index }; -} \ No newline at end of file +geometry_data geo_create_plane(f32x2 extents); +geometry_data geo_create_cuboid(f32x3 extents); +geometry_data geo_create_cylinder(f32 radius, f32 height, u32 resolution); +geometry_data geo_create_uvsphere(f32 radius, f32 north_south_lines, f32 east_west_lines); +geometry_data geo_create_icosphere(f32 radius, f32 n_subdivisions); \ No newline at end of file diff --git a/src/renderer/backends/backend_dx11.c b/src/renderer/backends/backend_dx11.c new file mode 100644 index 0000000..d991f03 --- /dev/null +++ b/src/renderer/backends/backend_dx11.c @@ -0,0 +1,3 @@ +#if CEL_REND_BACKEND_DX11 + +#endif \ No newline at end of file diff --git a/src/systems/terrain.c b/src/systems/terrain.c new file mode 100644 index 0000000..e69de29 diff --git a/src/systems/terrain.h b/src/systems/terrain.h new file mode 100644 index 0000000..fa2d3b3 --- /dev/null +++ b/src/systems/terrain.h @@ -0,0 +1,10 @@ +/** + * @file terrain.h + * @author your name (you@domain.com) + * @brief + * @version 0.1 + * @date 2024-04-27 + * + * @copyright Copyright (c) 2024 + * + */ -- cgit v1.2.3-70-g09d2 From c72440f89cfabe0c7752f9105cfc244a79016965 Mon Sep 17 00:00:00 2001 From: omniscient <17525998+omnisci3nce@users.noreply.github.com> Date: Sat, 27 Apr 2024 15:58:03 +1000 Subject: expanding desired containers --- src/core.h | 8 +- src/renderer/backends/backend_vulkan.c | 1813 ++++++++++++++++---------------- src/std/containers/graphs.h | 15 + src/std/containers/hashset.h | 10 + src/std/containers/hashtable.h | 10 + src/systems/terrain.h | 9 + 6 files changed, 960 insertions(+), 905 deletions(-) create mode 100644 src/std/containers/graphs.h create mode 100644 src/std/containers/hashset.h create mode 100644 src/std/containers/hashtable.h (limited to 'src/systems') diff --git a/src/core.h b/src/core.h index 68bf957..dd5a695 100644 --- a/src/core.h +++ b/src/core.h @@ -3,18 +3,22 @@ #include "defines.h" #include "input.h" #include "ral.h" -// #include "render_types.h" +#include "terrain.h" #include "screenspace.h" #include "text.h" #include "threadpool.h" typedef struct core { - // TODO: Add application name + const char* app_name; + // foundations renderer renderer; threadpool threadpool; + // systems input_state input; text_system_state text; + terrain_state terrain; screenspace_state screenspace; + // data storage model_darray* models; } core; diff --git a/src/renderer/backends/backend_vulkan.c b/src/renderer/backends/backend_vulkan.c index 4d3a14e..75b0439 100644 --- a/src/renderer/backends/backend_vulkan.c +++ b/src/renderer/backends/backend_vulkan.c @@ -923,1061 +923,1068 @@ void vulkan_image_transition_layout(vulkan_context* context, vulkan_command_buff vulkan_image* image, VkFormat format, VkImageLayout old_layout, VkImageLayout new_layout) { VkImageMemoryBarrier barrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER }; -void vulkan_image_transition_layout(vulkan_context* context, vulkan_command_buffer* command_buffer, - vulkan_image* image, VkFormat format, VkImageLayout old_layout, - VkImageLayout new_layout) { - VkImageMemoryBarrier barrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER }; - barrier.oldLayout = old_layout; - barrier.newLayout = new_layout; - barrier.srcQueueFamilyIndex = context->device.graphics_queue_index; - barrier.dstQueueFamilyIndex = context->device.graphics_queue_index; - barrier.image = image->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; - barrier.dstAccessMask = 0; - - VkPipelineStageFlags source_stage; - VkPipelineStageFlags dest_stage; - - if (old_layout == VK_IMAGE_LAYOUT_UNDEFINED && - new_layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) { + void vulkan_image_transition_layout( + vulkan_context * context, vulkan_command_buffer * command_buffer, vulkan_image * image, + VkFormat format, VkImageLayout old_layout, VkImageLayout new_layout) { + VkImageMemoryBarrier barrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER }; + barrier.oldLayout = old_layout; + barrier.newLayout = new_layout; + barrier.srcQueueFamilyIndex = context->device.graphics_queue_index; + barrier.dstQueueFamilyIndex = context->device.graphics_queue_index; + barrier.image = image->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; - 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; - } + barrier.dstAccessMask = 0; - vkCmdPipelineBarrier(command_buffer->handle, source_stage, dest_stage, 0, 0, 0, 0, 0, 1, - &barrier); -} + VkPipelineStageFlags source_stage; + VkPipelineStageFlags dest_stage; -void vulkan_image_copy_from_buffer(vulkan_image* image, VkBuffer buffer, - vulkan_command_buffer* command_buffer) { - 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", image->width, image->height); - region.imageOffset.x = 0; - region.imageOffset.y = 0; - region.imageOffset.z = 0; - region.imageExtent.width = image->width; - region.imageExtent.height = image->height; - region.imageExtent.depth = 1; - - vkCmdCopyBufferToImage(command_buffer->handle, buffer, image->handle, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); -} + 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; -void vulkan_image_create(vulkan_context* context, VkImageType image_type, u32 width, u32 height, - VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, - VkMemoryPropertyFlags memory_flags, bool create_view, - VkImageAspectFlags aspect_flags, vulkan_image* out_image) { - // copy params - out_image->width = width; - out_image->height = height; - - // create info - VkImageCreateInfo image_create_info = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO }; - image_create_info.imageType = image_type; - image_create_info.extent.width = width; - image_create_info.extent.height = height; - image_create_info.extent.depth = 1; - image_create_info.mipLevels = 1; - image_create_info.arrayLayers = 1; - image_create_info.format = format; - image_create_info.tiling = tiling; - image_create_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - image_create_info.usage = usage; - image_create_info.samples = VK_SAMPLE_COUNT_1_BIT; - image_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - - VK_CHECK(vkCreateImage(context->device.logical_device, &image_create_info, context->allocator, - &out_image->handle)); - - VkMemoryRequirements memory_reqs; - vkGetImageMemoryRequirements(context->device.logical_device, out_image->handle, &memory_reqs); - - i32 memory_type = -1; - VkPhysicalDeviceMemoryProperties memory_properties; - vkGetPhysicalDeviceMemoryProperties(context->device.physical_device, &memory_properties); + source_stage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; + dest_stage = VK_PIPELINE_STAGE_TRANSFER_BIT; - for (u32 i = 0; i < memory_properties.memoryTypeCount; i++) { - // typefilter = memoryTypeBits , prop filter = memory_flags - if (memory_reqs.memoryTypeBits & (1 << i) && - (memory_properties.memoryTypes[i].propertyFlags & memory_flags)) { - memory_type = i; - break; + } 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(command_buffer->handle, source_stage, dest_stage, 0, 0, 0, 0, 0, 1, + &barrier); } - if (memory_type < 0) { - ERROR_EXIT("couldnt find a suitable memory type for the image"); + void vulkan_image_copy_from_buffer(vulkan_image * image, VkBuffer buffer, + vulkan_command_buffer * command_buffer) { + 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", image->width, image->height); + region.imageOffset.x = 0; + region.imageOffset.y = 0; + region.imageOffset.z = 0; + region.imageExtent.width = image->width; + region.imageExtent.height = image->height; + region.imageExtent.depth = 1; + + vkCmdCopyBufferToImage(command_buffer->handle, buffer, image->handle, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); } - // allocate memory - VkMemoryAllocateInfo memory_allocate_info = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO }; - memory_allocate_info.allocationSize = memory_reqs.size; - memory_allocate_info.memoryTypeIndex = memory_type; - vkAllocateMemory(context->device.logical_device, &memory_allocate_info, context->allocator, - &out_image->memory); + void vulkan_image_create(vulkan_context * context, VkImageType image_type, u32 width, u32 height, + VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, + VkMemoryPropertyFlags memory_flags, bool create_view, + VkImageAspectFlags aspect_flags, vulkan_image* out_image) { + // copy params + out_image->width = width; + out_image->height = height; + + // create info + VkImageCreateInfo image_create_info = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO }; + image_create_info.imageType = image_type; + image_create_info.extent.width = width; + image_create_info.extent.height = height; + image_create_info.extent.depth = 1; + image_create_info.mipLevels = 1; + image_create_info.arrayLayers = 1; + image_create_info.format = format; + image_create_info.tiling = tiling; + image_create_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + image_create_info.usage = usage; + image_create_info.samples = VK_SAMPLE_COUNT_1_BIT; + image_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + + VK_CHECK(vkCreateImage(context->device.logical_device, &image_create_info, context->allocator, + &out_image->handle)); + + VkMemoryRequirements memory_reqs; + vkGetImageMemoryRequirements(context->device.logical_device, out_image->handle, &memory_reqs); + + i32 memory_type = -1; + VkPhysicalDeviceMemoryProperties memory_properties; + vkGetPhysicalDeviceMemoryProperties(context->device.physical_device, &memory_properties); + + for (u32 i = 0; i < memory_properties.memoryTypeCount; i++) { + // typefilter = memoryTypeBits , prop filter = memory_flags + if (memory_reqs.memoryTypeBits & (1 << i) && + (memory_properties.memoryTypes[i].propertyFlags & memory_flags)) { + memory_type = i; + break; + } + } - // bind memory - // TODO: maybe bind context->device.logical_device to device at the top of the functions? - vkBindImageMemory(context->device.logical_device, out_image->handle, out_image->memory, 0); + if (memory_type < 0) { + ERROR_EXIT("couldnt find a suitable memory type for the image"); + } - if (create_view) { - out_image->view = 0; - vulkan_image_view_create(context, format, out_image, aspect_flags); - } -} + // allocate memory + VkMemoryAllocateInfo memory_allocate_info = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO }; + memory_allocate_info.allocationSize = memory_reqs.size; + memory_allocate_info.memoryTypeIndex = memory_type; + vkAllocateMemory(context->device.logical_device, &memory_allocate_info, context->allocator, + &out_image->memory); -// TODO: vulkan_image_destroy + // bind memory + // TODO: maybe bind context->device.logical_device to device at the top of the functions? + vkBindImageMemory(context->device.logical_device, out_image->handle, out_image->memory, 0); -void vulkan_framebuffer_create(vulkan_context* context, vulkan_renderpass* renderpass, u32 width, - u32 height, u32 attachment_count, VkImageView* attachments, - vulkan_framebuffer* out_framebuffer) { - out_framebuffer->attachments = malloc(sizeof(VkImageView) * attachment_count); - for (u32 i = 0; i < attachment_count; i++) { - out_framebuffer->attachments[i] = attachments[i]; + if (create_view) { + out_image->view = 0; + vulkan_image_view_create(context, format, out_image, aspect_flags); + } } - out_framebuffer->attachment_count = attachment_count; - out_framebuffer->renderpass = renderpass; - - VkFramebufferCreateInfo framebuffer_create_info = { - VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO - }; // TODO - - framebuffer_create_info.renderPass = renderpass->handle; - framebuffer_create_info.attachmentCount = attachment_count; - framebuffer_create_info.pAttachments = out_framebuffer->attachments; - framebuffer_create_info.width = width; - framebuffer_create_info.height = height; - framebuffer_create_info.layers = 1; - - vkCreateFramebuffer(context->device.logical_device, &framebuffer_create_info, context->allocator, - &out_framebuffer->handle); -} -// TODO: vulkan_framebuffer_destroy - -void vulkan_command_buffer_allocate(vulkan_context* context, VkCommandPool pool, bool is_primary, - vulkan_command_buffer* out_command_buffer) { - VkCommandBufferAllocateInfo allocate_info = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO }; - allocate_info.commandPool = pool; - allocate_info.level = - is_primary ? VK_COMMAND_BUFFER_LEVEL_PRIMARY : VK_COMMAND_BUFFER_LEVEL_SECONDARY; - allocate_info.commandBufferCount = 1; - allocate_info.pNext = 0; - - out_command_buffer->state = COMMAND_BUFFER_STATE_NOT_ALLOCATED; - vkAllocateCommandBuffers(context->device.logical_device, &allocate_info, - &out_command_buffer->handle); - out_command_buffer->state = COMMAND_BUFFER_STATE_READY; -} + // TODO: vulkan_image_destroy -void vulkan_command_buffer_free(vulkan_context* context, VkCommandPool pool, - vulkan_command_buffer* out_command_buffer) { - // TODO: implement freeing -} + void vulkan_framebuffer_create(vulkan_context * context, vulkan_renderpass * renderpass, + u32 width, u32 height, u32 attachment_count, + VkImageView * attachments, vulkan_framebuffer * out_framebuffer) { + out_framebuffer->attachments = malloc(sizeof(VkImageView) * attachment_count); + for (u32 i = 0; i < attachment_count; i++) { + out_framebuffer->attachments[i] = attachments[i]; + } + out_framebuffer->attachment_count = attachment_count; + out_framebuffer->renderpass = renderpass; + + VkFramebufferCreateInfo framebuffer_create_info = { + VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO + }; // TODO + + framebuffer_create_info.renderPass = renderpass->handle; + framebuffer_create_info.attachmentCount = attachment_count; + framebuffer_create_info.pAttachments = out_framebuffer->attachments; + framebuffer_create_info.width = width; + framebuffer_create_info.height = height; + framebuffer_create_info.layers = 1; + + vkCreateFramebuffer(context->device.logical_device, &framebuffer_create_info, + context->allocator, &out_framebuffer->handle); + } -void vulkan_command_buffer_begin(vulkan_command_buffer* command_buffer, bool is_single_use, - bool is_renderpass_continue, bool is_simultaneous_use) { - VkCommandBufferBeginInfo begin_info = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO }; - begin_info.flags = 0; - if (is_single_use) { - begin_info.flags |= VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + // TODO: vulkan_framebuffer_destroy + + void vulkan_command_buffer_allocate(vulkan_context * context, VkCommandPool pool, bool is_primary, + vulkan_command_buffer* out_command_buffer) { + VkCommandBufferAllocateInfo allocate_info = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO }; + allocate_info.commandPool = pool; + allocate_info.level = + is_primary ? VK_COMMAND_BUFFER_LEVEL_PRIMARY : VK_COMMAND_BUFFER_LEVEL_SECONDARY; + allocate_info.commandBufferCount = 1; + allocate_info.pNext = 0; + + out_command_buffer->state = COMMAND_BUFFER_STATE_NOT_ALLOCATED; + vkAllocateCommandBuffers(context->device.logical_device, &allocate_info, + &out_command_buffer->handle); + out_command_buffer->state = COMMAND_BUFFER_STATE_READY; } - // TODO: RENDER_PASS_CONTINUE_BIT & SIMULTANEOUS_USE_BIT - begin_info.pNext = 0; - begin_info.pInheritanceInfo = 0; - vkBeginCommandBuffer(command_buffer->handle, &begin_info); + void vulkan_command_buffer_free(vulkan_context * context, VkCommandPool pool, + vulkan_command_buffer * out_command_buffer) { + // TODO: implement freeing + } - command_buffer->state = COMMAND_BUFFER_STATE_RECORDING; -} + void vulkan_command_buffer_begin(vulkan_command_buffer * command_buffer, bool is_single_use, + bool is_renderpass_continue, bool is_simultaneous_use) { + VkCommandBufferBeginInfo begin_info = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO }; + begin_info.flags = 0; + if (is_single_use) { + begin_info.flags |= VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + } + // TODO: RENDER_PASS_CONTINUE_BIT & SIMULTANEOUS_USE_BIT -void vulkan_command_buffer_end(vulkan_command_buffer* command_buffer) { - VK_CHECK(vkEndCommandBuffer(command_buffer->handle)); - command_buffer->state = COMMAND_BUFFER_STATE_RECORDING_ENDED; -} -void vulkan_command_buffer_update_submitted(vulkan_command_buffer* command_buffer) { - command_buffer->state = COMMAND_BUFFER_STATE_SUBMITTED; -} -void vulkan_command_buffer_reset(vulkan_command_buffer* command_buffer) { - command_buffer->state = COMMAND_BUFFER_STATE_READY; -} + begin_info.pNext = 0; + begin_info.pInheritanceInfo = 0; + vkBeginCommandBuffer(command_buffer->handle, &begin_info); -void vulkan_command_buffer_allocate_and_begin_oneshot(vulkan_context* context, VkCommandPool pool, - vulkan_command_buffer* out_command_buffer) { - vulkan_command_buffer_allocate(context, pool, true, out_command_buffer); - vulkan_command_buffer_begin(out_command_buffer, true, false, false); -} + command_buffer->state = COMMAND_BUFFER_STATE_RECORDING; + } -void vulkan_command_buffer_end_oneshot(vulkan_context* context, VkCommandPool pool, - vulkan_command_buffer* command_buffer, VkQueue queue) { - vulkan_command_buffer_end(command_buffer); + void vulkan_command_buffer_end(vulkan_command_buffer * command_buffer) { + VK_CHECK(vkEndCommandBuffer(command_buffer->handle)); + command_buffer->state = COMMAND_BUFFER_STATE_RECORDING_ENDED; + } + void vulkan_command_buffer_update_submitted(vulkan_command_buffer * command_buffer) { + command_buffer->state = COMMAND_BUFFER_STATE_SUBMITTED; + } + void vulkan_command_buffer_reset(vulkan_command_buffer * command_buffer) { + command_buffer->state = COMMAND_BUFFER_STATE_READY; + } - // submit to queue - VkSubmitInfo submit_info = { VK_STRUCTURE_TYPE_SUBMIT_INFO }; - submit_info.commandBufferCount = 1; - submit_info.pCommandBuffers = &command_buffer->handle; - VK_CHECK(vkQueueSubmit(queue, 1, &submit_info, 0)); - // wait for it to finish - VK_CHECK(vkQueueWaitIdle(queue)); + void vulkan_command_buffer_allocate_and_begin_oneshot( + vulkan_context * context, VkCommandPool pool, vulkan_command_buffer * out_command_buffer) { + vulkan_command_buffer_allocate(context, pool, true, out_command_buffer); + vulkan_command_buffer_begin(out_command_buffer, true, false, false); + } - vulkan_command_buffer_free(context, pool, command_buffer); -} + void vulkan_command_buffer_end_oneshot(vulkan_context * context, VkCommandPool pool, + vulkan_command_buffer * command_buffer, VkQueue queue) { + vulkan_command_buffer_end(command_buffer); -void vulkan_buffer_copy_to(vulkan_context* context, VkCommandPool pool, VkFence fence, - VkQueue queue, VkBuffer source, u64 source_offset, VkBuffer dest, - u64 dest_offset, u64 size) { - vkQueueWaitIdle(queue); + // submit to queue + VkSubmitInfo submit_info = { VK_STRUCTURE_TYPE_SUBMIT_INFO }; + submit_info.commandBufferCount = 1; + submit_info.pCommandBuffers = &command_buffer->handle; + VK_CHECK(vkQueueSubmit(queue, 1, &submit_info, 0)); + // wait for it to finish + VK_CHECK(vkQueueWaitIdle(queue)); - vulkan_command_buffer temp_cmd_buf; - vulkan_command_buffer_allocate_and_begin_oneshot(context, pool, &temp_cmd_buf); + vulkan_command_buffer_free(context, pool, command_buffer); + } - VkBufferCopy copy_region; - copy_region.srcOffset = source_offset; - copy_region.dstOffset = dest_offset; - copy_region.size = size; + void vulkan_buffer_copy_to(vulkan_context * context, VkCommandPool pool, VkFence fence, + VkQueue queue, VkBuffer source, u64 source_offset, VkBuffer dest, + u64 dest_offset, u64 size) { + vkQueueWaitIdle(queue); - vkCmdCopyBuffer(temp_cmd_buf.handle, source, dest, 1, ©_region); + vulkan_command_buffer temp_cmd_buf; + vulkan_command_buffer_allocate_and_begin_oneshot(context, pool, &temp_cmd_buf); - vulkan_command_buffer_end_oneshot(context, pool, &temp_cmd_buf, queue); -} + VkBufferCopy copy_region; + copy_region.srcOffset = source_offset; + copy_region.dstOffset = dest_offset; + copy_region.size = size; -void vulkan_swapchain_create(vulkan_context* context, u32 width, u32 height, - vulkan_swapchain* out_swapchain) { - VkExtent2D swapchain_extent = { width, height }; - out_swapchain->max_frames_in_flight = 2; // support triple buffering - - // find a format - bool found; - for (u32 i = 0; i < context->device.swapchain_support.format_count; i++) { - VkSurfaceFormatKHR format = context->device.swapchain_support.formats[i]; - if (format.format == VK_FORMAT_B8G8R8A8_UNORM && - format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { - out_swapchain->image_format = format; - found = true; - break; - } - } - if (!found) { - out_swapchain->image_format = context->device.swapchain_support.formats[0]; - } + vkCmdCopyBuffer(temp_cmd_buf.handle, source, dest, 1, ©_region); - VkPresentModeKHR present_mode = VK_PRESENT_MODE_FIFO_KHR; // guaranteed to be implemented - // TODO: look for mailbox - https://youtu.be/jWKVb_QdSNM?si=bHcd3sEf-M0x3QwH&t=1687 - - // TODO: requery swapchain support - - u32 image_count = context->device.swapchain_support.capabilities.minImageCount; - - VkSwapchainCreateInfoKHR swapchain_create_info = { VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR }; - swapchain_create_info.surface = context->surface; - swapchain_create_info.minImageCount = image_count; - swapchain_create_info.imageFormat = out_swapchain->image_format.format; - swapchain_create_info.imageColorSpace = out_swapchain->image_format.colorSpace; - DEBUG("Image extent %d %d\n", swapchain_extent.width, swapchain_extent.height); - swapchain_create_info.imageExtent = swapchain_extent; - swapchain_create_info.imageArrayLayers = 1; - swapchain_create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; - swapchain_create_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; - swapchain_create_info.queueFamilyIndexCount = 0; - swapchain_create_info.pQueueFamilyIndices = 0; - - swapchain_create_info.preTransform = - context->device.swapchain_support.capabilities.currentTransform; - swapchain_create_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; - swapchain_create_info.presentMode = present_mode; - swapchain_create_info.clipped = VK_TRUE; - swapchain_create_info.oldSwapchain = 0; - - TRACE("Create swapchain"); - VK_CHECK(vkCreateSwapchainKHR(context->device.logical_device, &swapchain_create_info, - context->allocator, &out_swapchain->handle)); - - context->current_frame = 0; - - // images - out_swapchain->image_count = 0; - vkGetSwapchainImagesKHR(context->device.logical_device, out_swapchain->handle, - &out_swapchain->image_count, 0); - - if (!out_swapchain->images) { - out_swapchain->images = (VkImage*)malloc(sizeof(VkImage) * out_swapchain->image_count); - } - if (!out_swapchain->views) { - out_swapchain->views = (VkImageView*)malloc(sizeof(VkImage) * out_swapchain->image_count); + vulkan_command_buffer_end_oneshot(context, pool, &temp_cmd_buf, queue); } - VK_CHECK(vkGetSwapchainImagesKHR(context->device.logical_device, out_swapchain->handle, - &out_swapchain->image_count, out_swapchain->images)); - - // views - for (int i = 0; i < out_swapchain->image_count; i++) { - VkImageViewCreateInfo view_info = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO }; - view_info.image = out_swapchain->images[i]; - view_info.viewType = VK_IMAGE_VIEW_TYPE_2D; - view_info.format = out_swapchain->image_format.format; - view_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - view_info.subresourceRange.baseMipLevel = 0; - view_info.subresourceRange.levelCount = 1; - view_info.subresourceRange.baseArrayLayer = 0; - view_info.subresourceRange.layerCount = 1; - - VK_CHECK(vkCreateImageView(context->device.logical_device, &view_info, context->allocator, - &out_swapchain->views[i])); + + void vulkan_swapchain_create(vulkan_context * context, u32 width, u32 height, + vulkan_swapchain * out_swapchain) { + VkExtent2D swapchain_extent = { width, height }; + out_swapchain->max_frames_in_flight = 2; // support triple buffering + + // find a format + bool found; + for (u32 i = 0; i < context->device.swapchain_support.format_count; i++) { + VkSurfaceFormatKHR format = context->device.swapchain_support.formats[i]; + if (format.format == VK_FORMAT_B8G8R8A8_UNORM && + format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { + out_swapchain->image_format = format; + found = true; + break; + } + } + if (!found) { + out_swapchain->image_format = context->device.swapchain_support.formats[0]; + } + + VkPresentModeKHR present_mode = VK_PRESENT_MODE_FIFO_KHR; // guaranteed to be implemented + // TODO: look for mailbox - https://youtu.be/jWKVb_QdSNM?si=bHcd3sEf-M0x3QwH&t=1687 + + // TODO: requery swapchain support + + u32 image_count = context->device.swapchain_support.capabilities.minImageCount; + + VkSwapchainCreateInfoKHR swapchain_create_info = { + VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR + }; + swapchain_create_info.surface = context->surface; + swapchain_create_info.minImageCount = image_count; + swapchain_create_info.imageFormat = out_swapchain->image_format.format; + swapchain_create_info.imageColorSpace = out_swapchain->image_format.colorSpace; + DEBUG("Image extent %d %d\n", swapchain_extent.width, swapchain_extent.height); + swapchain_create_info.imageExtent = swapchain_extent; + swapchain_create_info.imageArrayLayers = 1; + swapchain_create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + swapchain_create_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; + swapchain_create_info.queueFamilyIndexCount = 0; + swapchain_create_info.pQueueFamilyIndices = 0; + + swapchain_create_info.preTransform = + context->device.swapchain_support.capabilities.currentTransform; + swapchain_create_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; + swapchain_create_info.presentMode = present_mode; + swapchain_create_info.clipped = VK_TRUE; + swapchain_create_info.oldSwapchain = 0; + + TRACE("Create swapchain"); + VK_CHECK(vkCreateSwapchainKHR(context->device.logical_device, &swapchain_create_info, + context->allocator, &out_swapchain->handle)); + + context->current_frame = 0; + + // images + out_swapchain->image_count = 0; + vkGetSwapchainImagesKHR(context->device.logical_device, out_swapchain->handle, + &out_swapchain->image_count, 0); + + if (!out_swapchain->images) { + out_swapchain->images = (VkImage*)malloc(sizeof(VkImage) * out_swapchain->image_count); + } + if (!out_swapchain->views) { + out_swapchain->views = (VkImageView*)malloc(sizeof(VkImage) * out_swapchain->image_count); + } + VK_CHECK(vkGetSwapchainImagesKHR(context->device.logical_device, out_swapchain->handle, + &out_swapchain->image_count, out_swapchain->images)); + + // views + for (int i = 0; i < out_swapchain->image_count; i++) { + VkImageViewCreateInfo view_info = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO }; + view_info.image = out_swapchain->images[i]; + view_info.viewType = VK_IMAGE_VIEW_TYPE_2D; + view_info.format = out_swapchain->image_format.format; + view_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + view_info.subresourceRange.baseMipLevel = 0; + view_info.subresourceRange.levelCount = 1; + view_info.subresourceRange.baseArrayLayer = 0; + view_info.subresourceRange.layerCount = 1; + + VK_CHECK(vkCreateImageView(context->device.logical_device, &view_info, context->allocator, + &out_swapchain->views[i])); + } + + // depth attachment + if (!vulkan_device_detect_depth_format(&context->device)) { + ERROR_EXIT("Failed to find a supported depth format"); + } + vulkan_image_create(context, VK_IMAGE_TYPE_2D, swapchain_extent.width, swapchain_extent.height, + context->device.depth_format, VK_IMAGE_TILING_OPTIMAL, + VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, true, VK_IMAGE_ASPECT_DEPTH_BIT, + &out_swapchain->depth_attachment); + INFO("Depth attachment created"); + + INFO("Swapchain created successfully"); } - // depth attachment - if (!vulkan_device_detect_depth_format(&context->device)) { - ERROR_EXIT("Failed to find a supported depth format"); + // TODO: swapchain destroy + void vulkan_swapchain_recreate(vulkan_context * context, u32 width, u32 height, + vulkan_swapchain * swapchain) { + // TODO } - vulkan_image_create(context, VK_IMAGE_TYPE_2D, swapchain_extent.width, swapchain_extent.height, - context->device.depth_format, VK_IMAGE_TILING_OPTIMAL, - VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, true, VK_IMAGE_ASPECT_DEPTH_BIT, - &out_swapchain->depth_attachment); - INFO("Depth attachment created"); - - INFO("Swapchain created successfully"); -} + bool vulkan_swapchain_acquire_next_image_index( + vulkan_context * context, vulkan_swapchain * swapchain, u64 timeout_ns, + VkSemaphore image_available_semaphore, VkFence fence, u32 * out_image_index) { + VkResult result = + vkAcquireNextImageKHR(context->device.logical_device, swapchain->handle, timeout_ns, + image_available_semaphore, fence, out_image_index); -// TODO: swapchain destroy -void vulkan_swapchain_recreate(vulkan_context* context, u32 width, u32 height, - vulkan_swapchain* swapchain) { - // TODO -} -bool vulkan_swapchain_acquire_next_image_index(vulkan_context* context, vulkan_swapchain* swapchain, - u64 timeout_ns, - VkSemaphore image_available_semaphore, VkFence fence, - u32* out_image_index) { - VkResult result = - vkAcquireNextImageKHR(context->device.logical_device, swapchain->handle, timeout_ns, - image_available_semaphore, fence, out_image_index); + if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) { + FATAL("Failed to acquire swapchain image"); + return false; + } - if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) { - FATAL("Failed to acquire swapchain image"); - return false; + return true; } - return true; -} - -void vulkan_swapchain_present(vulkan_context* context, vulkan_swapchain* swapchain, - VkQueue graphics_queue, VkQueue present_queue, - VkSemaphore render_complete_semaphore, u32 present_image_index) { - // return image to swapchain for presentation - VkPresentInfoKHR present_info = { VK_STRUCTURE_TYPE_PRESENT_INFO_KHR }; - present_info.waitSemaphoreCount = 1; - present_info.pWaitSemaphores = &render_complete_semaphore; - present_info.swapchainCount = 1; - present_info.pSwapchains = &swapchain->handle; - present_info.pImageIndices = &present_image_index; - present_info.pResults = 0; - - VkResult result = vkQueuePresentKHR(present_queue, &present_info); - if (result != VK_SUCCESS) { - if (result == VK_SUBOPTIMAL_KHR) { - // WARN("Swapchain suboptimal - maybe resize needed?"); - } else { - FATAL("Failed to present swapchain iamge"); + void vulkan_swapchain_present(vulkan_context * context, vulkan_swapchain * swapchain, + VkQueue graphics_queue, VkQueue present_queue, + VkSemaphore render_complete_semaphore, u32 present_image_index) { + // return image to swapchain for presentation + VkPresentInfoKHR present_info = { VK_STRUCTURE_TYPE_PRESENT_INFO_KHR }; + present_info.waitSemaphoreCount = 1; + present_info.pWaitSemaphores = &render_complete_semaphore; + present_info.swapchainCount = 1; + present_info.pSwapchains = &swapchain->handle; + present_info.pImageIndices = &present_image_index; + present_info.pResults = 0; + + VkResult result = vkQueuePresentKHR(present_queue, &present_info); + if (result != VK_SUCCESS) { + if (result == VK_SUBOPTIMAL_KHR) { + // WARN("Swapchain suboptimal - maybe resize needed?"); + } else { + FATAL("Failed to present swapchain iamge"); + } } + + // advance the current frame + context->current_frame = (context->current_frame + 1) % swapchain->max_frames_in_flight; } - // advance the current frame - context->current_frame = (context->current_frame + 1) % swapchain->max_frames_in_flight; -} + void vulkan_renderpass_create(vulkan_context * context, vulkan_renderpass * out_renderpass, + vec4 render_area, vec4 clear_colour, f32 depth, u32 stencil) { + out_renderpass->render_area = render_area; + out_renderpass->clear_colour = clear_colour; + out_renderpass->depth = depth; + out_renderpass->stencil = stencil; + + // main subpass + VkSubpassDescription subpass = {}; + subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + + // attachments + u32 attachment_desc_count = 2; + VkAttachmentDescription attachment_descriptions[2]; + + // 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; + + // Depth attachment + VkAttachmentDescription depth_attachment; + depth_attachment.format = context->device.depth_format; + depth_attachment.samples = VK_SAMPLE_COUNT_1_BIT; + depth_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + depth_attachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + depth_attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + depth_attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + depth_attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + depth_attachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + depth_attachment.flags = 0; + + attachment_descriptions[1] = depth_attachment; + + VkAttachmentReference depth_attachment_reference; + depth_attachment_reference.attachment = 1; + depth_attachment_reference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + + subpass.pDepthStencilAttachment = &depth_attachment_reference; + + // TODO: other attachment styles + + subpass.inputAttachmentCount = 0; + subpass.pInputAttachments = 0; + subpass.pResolveAttachments = 0; + subpass.preserveAttachmentCount = 0; + subpass.preserveAttachmentCount = 0; + + // 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; + + VkRenderPassCreateInfo render_pass_create_info = { VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO }; + render_pass_create_info.attachmentCount = attachment_desc_count; + render_pass_create_info.pAttachments = attachment_descriptions; + 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.pNext = 0; + render_pass_create_info.flags = 0; + + VK_CHECK(vkCreateRenderPass(context->device.logical_device, &render_pass_create_info, + context->allocator, &out_renderpass->handle)); + } -void vulkan_renderpass_create(vulkan_context* context, vulkan_renderpass* out_renderpass, - vec4 render_area, vec4 clear_colour, f32 depth, u32 stencil) { - out_renderpass->render_area = render_area; - out_renderpass->clear_colour = clear_colour; - out_renderpass->depth = depth; - out_renderpass->stencil = stencil; - - // main subpass - VkSubpassDescription subpass = {}; - subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - - // attachments - u32 attachment_desc_count = 2; - VkAttachmentDescription attachment_descriptions[2]; - - // 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; - - // Depth attachment - VkAttachmentDescription depth_attachment; - depth_attachment.format = context->device.depth_format; - depth_attachment.samples = VK_SAMPLE_COUNT_1_BIT; - depth_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - depth_attachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - depth_attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - depth_attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - depth_attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - depth_attachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - depth_attachment.flags = 0; - - attachment_descriptions[1] = depth_attachment; - - VkAttachmentReference depth_attachment_reference; - depth_attachment_reference.attachment = 1; - depth_attachment_reference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - - subpass.pDepthStencilAttachment = &depth_attachment_reference; - - // TODO: other attachment styles - - subpass.inputAttachmentCount = 0; - subpass.pInputAttachments = 0; - subpass.pResolveAttachments = 0; - subpass.preserveAttachmentCount = 0; - subpass.preserveAttachmentCount = 0; - - // 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; - - VkRenderPassCreateInfo render_pass_create_info = { VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO }; - render_pass_create_info.attachmentCount = attachment_desc_count; - render_pass_create_info.pAttachments = attachment_descriptions; - 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.pNext = 0; - render_pass_create_info.flags = 0; - - VK_CHECK(vkCreateRenderPass(context->device.logical_device, &render_pass_create_info, - context->allocator, &out_renderpass->handle)); -} + // TODO: renderpass destroy + + void vulkan_renderpass_begin(vulkan_command_buffer * command_buffer, + vulkan_renderpass * renderpass, VkFramebuffer framebuffer) { + VkRenderPassBeginInfo begin_info = { VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO }; + begin_info.renderPass = renderpass->handle; + begin_info.framebuffer = framebuffer; + begin_info.renderArea.offset.x = renderpass->render_area.x; + begin_info.renderArea.offset.y = renderpass->render_area.y; + begin_info.renderArea.extent.width = renderpass->render_area.z; + begin_info.renderArea.extent.height = renderpass->render_area.w; + + VkClearValue clear_values[2]; + memset(&clear_values, 0, sizeof(VkClearValue) * 2); + clear_values[0].color.float32[0] = renderpass->clear_colour.x; + clear_values[0].color.float32[1] = renderpass->clear_colour.y; + clear_values[0].color.float32[2] = renderpass->clear_colour.z; + clear_values[0].color.float32[3] = renderpass->clear_colour.w; + clear_values[1].depthStencil.depth = renderpass->depth; + clear_values[1].depthStencil.stencil = renderpass->stencil; + + begin_info.clearValueCount = 2; + begin_info.pClearValues = clear_values; + + vkCmdBeginRenderPass(command_buffer->handle, &begin_info, VK_SUBPASS_CONTENTS_INLINE); + command_buffer->state = COMMAND_BUFFER_STATE_IN_RENDER_PASS; + } -// TODO: renderpass destroy - -void vulkan_renderpass_begin(vulkan_command_buffer* command_buffer, vulkan_renderpass* renderpass, - VkFramebuffer framebuffer) { - VkRenderPassBeginInfo begin_info = { VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO }; - begin_info.renderPass = renderpass->handle; - begin_info.framebuffer = framebuffer; - begin_info.renderArea.offset.x = renderpass->render_area.x; - begin_info.renderArea.offset.y = renderpass->render_area.y; - begin_info.renderArea.extent.width = renderpass->render_area.z; - begin_info.renderArea.extent.height = renderpass->render_area.w; - - VkClearValue clear_values[2]; - memset(&clear_values, 0, sizeof(VkClearValue) * 2); - clear_values[0].color.float32[0] = renderpass->clear_colour.x; - clear_values[0].color.float32[1] = renderpass->clear_colour.y; - clear_values[0].color.float32[2] = renderpass->clear_colour.z; - clear_values[0].color.float32[3] = renderpass->clear_colour.w; - clear_values[1].depthStencil.depth = renderpass->depth; - clear_values[1].depthStencil.stencil = renderpass->stencil; - - begin_info.clearValueCount = 2; - begin_info.pClearValues = clear_values; - - vkCmdBeginRenderPass(command_buffer->handle, &begin_info, VK_SUBPASS_CONTENTS_INLINE); - command_buffer->state = COMMAND_BUFFER_STATE_IN_RENDER_PASS; -} + void vulkan_renderpass_end(vulkan_command_buffer * command_buffer, + vulkan_renderpass * renderpass) { + vkCmdEndRenderPass(command_buffer->handle); + command_buffer->state = COMMAND_BUFFER_STATE_RECORDING; + } -void vulkan_renderpass_end(vulkan_command_buffer* command_buffer, vulkan_renderpass* renderpass) { - vkCmdEndRenderPass(command_buffer->handle); - command_buffer->state = COMMAND_BUFFER_STATE_RECORDING; -} + bool create_buffers(vulkan_context * context) { + VkMemoryPropertyFlagBits mem_prop_flags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; -bool create_buffers(vulkan_context* context) { - VkMemoryPropertyFlagBits mem_prop_flags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + const u64 vertex_buffer_size = sizeof(vertex_pos) * 1024 * 1024; + if (!vulkan_buffer_create(context, vertex_buffer_size, + VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | + VK_BUFFER_USAGE_TRANSFER_DST_BIT, + mem_prop_flags, true, &context->object_vertex_buffer)) { + ERROR("couldnt create vertex buffer"); + return false; + } - const u64 vertex_buffer_size = sizeof(vertex_pos) * 1024 * 1024; - if (!vulkan_buffer_create(context, vertex_buffer_size, - VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | - VK_BUFFER_USAGE_TRANSFER_DST_BIT, - mem_prop_flags, true, &context->object_vertex_buffer)) { - ERROR("couldnt create vertex buffer"); - return false; - } + context->geometry_vertex_offset = 0; - context->geometry_vertex_offset = 0; + const u64 index1_buffer_size = sizeof(u32) * 1024 * 1024; + if (!vulkan_buffer_create(context, index1_buffer_size, + VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | + VK_BUFFER_USAGE_TRANSFER_DST_BIT, + mem_prop_flags, true, &context->object_index_buffer)) { + ERROR("couldnt create vertex buffer"); + return false; + } + context->geometry_index_offset = 0; - const u64 index1_buffer_size = sizeof(u32) * 1024 * 1024; - if (!vulkan_buffer_create(context, index1_buffer_size, - VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | - VK_BUFFER_USAGE_TRANSFER_DST_BIT, - mem_prop_flags, true, &context->object_index_buffer)) { - ERROR("couldnt create vertex buffer"); - return false; + return true; } - context->geometry_index_offset = 0; - return true; -} + void create_command_buffers(renderer * ren) { + if (!context.gfx_command_buffers) { + context.gfx_command_buffers = vulkan_command_buffer_darray_new(context.swapchain.image_count); + } -void create_command_buffers(renderer* ren) { - if (!context.gfx_command_buffers) { - context.gfx_command_buffers = vulkan_command_buffer_darray_new(context.swapchain.image_count); + for (u32 i = 0; i < context.swapchain.image_count; i++) { + vulkan_command_buffer_allocate(&context, context.device.gfx_command_pool, true, + &context.gfx_command_buffers->data[i]); + } } - for (u32 i = 0; i < context.swapchain.image_count; i++) { - vulkan_command_buffer_allocate(&context, context.device.gfx_command_pool, true, - &context.gfx_command_buffers->data[i]); + void upload_data_range(vulkan_context * context, VkCommandPool pool, VkFence fence, VkQueue queue, + vulkan_buffer * buffer, u64 offset, u64 size, void* data) { + VkBufferUsageFlags flags = + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; + vulkan_buffer staging; + vulkan_buffer_create(context, size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, flags, true, &staging); + // load data into staging buffer + printf("Size: %ld\n", size); + vulkan_buffer_load_data(context, &staging, 0, size, 0, data); + + // copy + vulkan_buffer_copy_to(context, pool, fence, queue, staging.handle, 0, buffer->handle, offset, + size); + + vkDestroyBuffer(context->device.logical_device, staging.handle, context->allocator); } -} -void upload_data_range(vulkan_context* context, VkCommandPool pool, VkFence fence, VkQueue queue, - vulkan_buffer* buffer, u64 offset, u64 size, void* data) { - VkBufferUsageFlags flags = - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; - vulkan_buffer staging; - vulkan_buffer_create(context, size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, flags, true, &staging); - // load data into staging buffer - printf("Size: %ld\n", size); - vulkan_buffer_load_data(context, &staging, 0, size, 0, data); - - // copy - vulkan_buffer_copy_to(context, pool, fence, queue, staging.handle, 0, buffer->handle, offset, - size); - - vkDestroyBuffer(context->device.logical_device, staging.handle, context->allocator); -} - -void regenerate_framebuffers(renderer* ren, vulkan_swapchain* swapchain, - vulkan_renderpass* renderpass) { - for (u32 i = 0; i < swapchain->image_count; i++) { - u32 attachment_count = 2; // one for depth, one for colour - - VkImageView attachments[2] = { swapchain->views[i], swapchain->depth_attachment.view }; + void regenerate_framebuffers(renderer * ren, vulkan_swapchain * swapchain, + vulkan_renderpass * renderpass) { + for (u32 i = 0; i < swapchain->image_count; i++) { + u32 attachment_count = 2; // one for depth, one for colour - vulkan_framebuffer_create(&context, renderpass, context.framebuffer_width, - context.framebuffer_height, 2, attachments, - &swapchain->framebuffers->data[i]); - } -} + VkImageView attachments[2] = { swapchain->views[i], swapchain->depth_attachment.view }; -void vulkan_fence_create(vulkan_context* context, bool create_signaled, vulkan_fence* out_fence) { - out_fence->is_signaled = create_signaled; - VkFenceCreateInfo fence_create_info = { VK_STRUCTURE_TYPE_FENCE_CREATE_INFO }; - if (out_fence->is_signaled) { - fence_create_info.flags = VK_FENCE_CREATE_SIGNALED_BIT; + vulkan_framebuffer_create(&context, renderpass, context.framebuffer_width, + context.framebuffer_height, 2, attachments, + &swapchain->framebuffers->data[i]); + } } - vkCreateFence(context->device.logical_device, &fence_create_info, context->allocator, - &out_fence->handle); -} + void vulkan_fence_create(vulkan_context * context, bool create_signaled, + vulkan_fence* out_fence) { + out_fence->is_signaled = create_signaled; + VkFenceCreateInfo fence_create_info = { VK_STRUCTURE_TYPE_FENCE_CREATE_INFO }; + if (out_fence->is_signaled) { + fence_create_info.flags = VK_FENCE_CREATE_SIGNALED_BIT; + } -// TODO: vulkan_fence_destroy + vkCreateFence(context->device.logical_device, &fence_create_info, context->allocator, + &out_fence->handle); + } -bool vulkan_fence_wait(vulkan_context* context, vulkan_fence* fence, u64 timeout_ns) { - if (!fence->is_signaled) { - VkResult result = - vkWaitForFences(context->device.logical_device, 1, &fence->handle, true, timeout_ns); - switch (result) { - case VK_SUCCESS: - fence->is_signaled = true; - return true; - case VK_TIMEOUT: - WARN("vk_fence_wait - Timed out"); - break; - default: - ERROR("vk_fence_wait - Unhanlded error type"); - break; + // TODO: vulkan_fence_destroy + + bool vulkan_fence_wait(vulkan_context * context, vulkan_fence * fence, u64 timeout_ns) { + if (!fence->is_signaled) { + VkResult result = + vkWaitForFences(context->device.logical_device, 1, &fence->handle, true, timeout_ns); + switch (result) { + case VK_SUCCESS: + fence->is_signaled = true; + return true; + case VK_TIMEOUT: + WARN("vk_fence_wait - Timed out"); + break; + default: + ERROR("vk_fence_wait - Unhanlded error type"); + break; + } + } else { + return true; } - } else { - return true; - } - return false; -} -void vulkan_fence_reset(vulkan_context* context, vulkan_fence* fence) { - if (fence->is_signaled) { - vkResetFences(context->device.logical_device, 1, &fence->handle); - fence->is_signaled = false; + return false; + } + void vulkan_fence_reset(vulkan_context * context, vulkan_fence * fence) { + if (fence->is_signaled) { + vkResetFences(context->device.logical_device, 1, &fence->handle); + fence->is_signaled = false; + } } -} -bool gfx_backend_init(renderer* ren) { - INFO("loading Vulkan backend"); + bool gfx_backend_init(renderer * ren) { + INFO("loading Vulkan backend"); - vulkan_state* internal = malloc(sizeof(vulkan_state)); - ren->backend_state = (void*)internal; + vulkan_state* internal = malloc(sizeof(vulkan_state)); + ren->backend_state = (void*)internal; - context.allocator = 0; // TODO: custom allocator + context.allocator = 0; // TODO: custom allocator - context.framebuffer_width = SCR_WIDTH; - context.framebuffer_height = SCR_HEIGHT; + context.framebuffer_width = SCR_WIDTH; + context.framebuffer_height = SCR_HEIGHT; - // Setup Vulkan instance - VkApplicationInfo app_info = { VK_STRUCTURE_TYPE_APPLICATION_INFO }; - app_info.apiVersion = VK_API_VERSION_1_3; - app_info.pApplicationName = ren->config.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); + // Setup Vulkan instance + VkApplicationInfo app_info = { VK_STRUCTURE_TYPE_APPLICATION_INFO }; + app_info.apiVersion = VK_API_VERSION_1_3; + app_info.pApplicationName = ren->config.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; + VkInstanceCreateInfo create_info = { VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO }; + create_info.pApplicationInfo = &app_info; - cstr_darray* required_extensions = cstr_darray_new(2); - cstr_darray_push(required_extensions, VK_KHR_SURFACE_EXTENSION_NAME); + cstr_darray* required_extensions = cstr_darray_new(2); + cstr_darray_push(required_extensions, VK_KHR_SURFACE_EXTENSION_NAME); - plat_get_required_extension_names(required_extensions); + plat_get_required_extension_names(required_extensions); #if defined(CDEBUG) - cstr_darray_push(required_extensions, VK_EXT_DEBUG_UTILS_EXTENSION_NAME); + cstr_darray_push(required_extensions, VK_EXT_DEBUG_UTILS_EXTENSION_NAME); - DEBUG("Required extensions:"); - for (u32 i = 0; i < cstr_darray_len(required_extensions); i++) { - DEBUG(" %s", required_extensions->data[i]); - } + DEBUG("Required extensions:"); + for (u32 i = 0; i < cstr_darray_len(required_extensions); i++) { + DEBUG(" %s", required_extensions->data[i]); + } #endif - create_info.enabledExtensionCount = cstr_darray_len(required_extensions); - create_info.ppEnabledExtensionNames = required_extensions->data; + create_info.enabledExtensionCount = cstr_darray_len(required_extensions); + create_info.ppEnabledExtensionNames = required_extensions->data; - // Validation layers - create_info.enabledLayerCount = 0; - create_info.ppEnabledLayerNames = 0; + // Validation layers + create_info.enabledLayerCount = 0; + create_info.ppEnabledLayerNames = 0; #if defined(CDEBUG) - INFO("Validation layers enabled"); - cstr_darray* desired_validation_layers = cstr_darray_new(1); - cstr_darray_push(desired_validation_layers, "VK_LAYER_KHRONOS_validation"); - - u32 n_available_layers = 0; - VK_CHECK(vkEnumerateInstanceLayerProperties(&n_available_layers, 0)); - TRACE("%d available layers", n_available_layers); - VkLayerProperties_darray* available_layers = VkLayerProperties_darray_new(n_available_layers); - VK_CHECK(vkEnumerateInstanceLayerProperties(&n_available_layers, available_layers->data)); - - for (int i = 0; i < cstr_darray_len(desired_validation_layers); i++) { - // look through layers to make sure we can find the ones we want - bool found = false; - for (int j = 0; j < n_available_layers; j++) { - if (str8_equals(str8_cstr_view(desired_validation_layers->data[i]), - str8_cstr_view(available_layers->data[j].layerName))) { - found = true; - TRACE("Found layer %s", desired_validation_layers->data[i]); - break; + INFO("Validation layers enabled"); + cstr_darray* desired_validation_layers = cstr_darray_new(1); + cstr_darray_push(desired_validation_layers, "VK_LAYER_KHRONOS_validation"); + + u32 n_available_layers = 0; + VK_CHECK(vkEnumerateInstanceLayerProperties(&n_available_layers, 0)); + TRACE("%d available layers", n_available_layers); + VkLayerProperties_darray* available_layers = VkLayerProperties_darray_new(n_available_layers); + VK_CHECK(vkEnumerateInstanceLayerProperties(&n_available_layers, available_layers->data)); + + for (int i = 0; i < cstr_darray_len(desired_validation_layers); i++) { + // look through layers to make sure we can find the ones we want + bool found = false; + for (int j = 0; j < n_available_layers; j++) { + if (str8_equals(str8_cstr_view(desired_validation_layers->data[i]), + str8_cstr_view(available_layers->data[j].layerName))) { + found = true; + TRACE("Found layer %s", desired_validation_layers->data[i]); + break; + } } - } - if (!found) { - FATAL("Required validation is missing %s", desired_validation_layers->data[i]); - return false; + if (!found) { + FATAL("Required validation is missing %s", desired_validation_layers->data[i]); + return false; + } } - } - INFO("All validation layers are present"); - create_info.enabledLayerCount = cstr_darray_len(desired_validation_layers); - create_info.ppEnabledLayerNames = desired_validation_layers->data; + INFO("All validation layers are present"); + create_info.enabledLayerCount = cstr_darray_len(desired_validation_layers); + create_info.ppEnabledLayerNames = desired_validation_layers->data; #endif - VkResult result = vkCreateInstance(&create_info, NULL, &context.instance); - if (result != VK_SUCCESS) { - ERROR("vkCreateInstance failed with result: %u", result); - return false; - } + VkResult result = vkCreateInstance(&create_info, NULL, &context.instance); + if (result != VK_SUCCESS) { + ERROR("vkCreateInstance failed with result: %u", result); + return false; + } - // Debugger + // Debugger #if defined(CDEBUG) - DEBUG("Creating Vulkan debugger") - u32 log_severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT; - VkDebugUtilsMessengerCreateInfoEXT debug_create_info = { - VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT - }; - debug_create_info.messageSeverity = log_severity; - debug_create_info.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT; - debug_create_info.pfnUserCallback = vk_debug_callback; - - PFN_vkCreateDebugUtilsMessengerEXT func = - (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(context.instance, - "vkCreateDebugUtilsMessengerEXT"); - assert(func); - VK_CHECK(func(context.instance, &debug_create_info, context.allocator, &context.vk_debugger)); - DEBUG("Vulkan debugger created"); + DEBUG("Creating Vulkan debugger") + u32 log_severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT; + VkDebugUtilsMessengerCreateInfoEXT debug_create_info = { + VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT + }; + debug_create_info.messageSeverity = log_severity; + debug_create_info.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT; + debug_create_info.pfnUserCallback = vk_debug_callback; + + PFN_vkCreateDebugUtilsMessengerEXT func = + (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(context.instance, + "vkCreateDebugUtilsMessengerEXT"); + assert(func); + VK_CHECK(func(context.instance, &debug_create_info, context.allocator, &context.vk_debugger)); + DEBUG("Vulkan debugger created"); #endif - // Surface creation - DEBUG("Create SurfaceKHR") - VkSurfaceKHR surface; - VK_CHECK(glfwCreateWindowSurface(context.instance, ren->window, NULL, &surface)); - context.surface = surface; - DEBUG("Vulkan surface created") + // Surface creation + DEBUG("Create SurfaceKHR") + VkSurfaceKHR surface; + VK_CHECK(glfwCreateWindowSurface(context.instance, ren->window, NULL, &surface)); + context.surface = surface; + DEBUG("Vulkan surface created") - // Device creation - if (!vulkan_device_create(&context)) { - FATAL("device creation failed"); - return false; - } - - // Swapchain creation - vulkan_swapchain_create(&context, SCR_WIDTH, SCR_HEIGHT, &context.swapchain); - - // Renderpass creation - vulkan_renderpass_create(&context, &context.main_renderpass, - vec4(0, 0, context.framebuffer_width, context.framebuffer_height), - rgba_to_vec4(COLOUR_SEA_GREEN), 1.0, 0); - - // Framebiffers creation - context.swapchain.framebuffers = vulkan_framebuffer_darray_new(context.swapchain.image_count); - regenerate_framebuffers(ren, &context.swapchain, &context.main_renderpass); - INFO("Framebuffers created"); - - // Command buffers creation - create_command_buffers(ren); - INFO("Command buffers created"); - - // Sync objects - context.image_available_semaphores = - calloc(context.swapchain.max_frames_in_flight, sizeof(VkSemaphore)); - context.queue_complete_semaphores = - calloc(context.swapchain.max_frames_in_flight, sizeof(VkSemaphore)); - context.in_flight_fences = calloc(context.swapchain.max_frames_in_flight, sizeof(vulkan_fence)); - - for (u8 i = 0; i < context.swapchain.max_frames_in_flight; i++) { - VkSemaphoreCreateInfo semaphore_create_info = { VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO }; - vkCreateSemaphore(context.device.logical_device, &semaphore_create_info, context.allocator, - &context.image_available_semaphores[i]); - vkCreateSemaphore(context.device.logical_device, &semaphore_create_info, context.allocator, - &context.queue_complete_semaphores[i]); - - // create the fence in a signaled state - vulkan_fence_create(&context, true, &context.in_flight_fences[i]); - } + // Device creation + if (!vulkan_device_create(&context)) { + FATAL("device creation failed"); + return false; + } - context.images_in_flight = malloc(sizeof(vulkan_fence*) * context.swapchain.max_frames_in_flight); - for (u8 i = 0; i < context.swapchain.max_frames_in_flight; i++) { - context.images_in_flight[i] = 0; - } - INFO("Sync objects created"); + // Swapchain creation + vulkan_swapchain_create(&context, SCR_WIDTH, SCR_HEIGHT, &context.swapchain); + + // Renderpass creation + vulkan_renderpass_create(&context, &context.main_renderpass, + vec4(0, 0, context.framebuffer_width, context.framebuffer_height), + rgba_to_vec4(COLOUR_SEA_GREEN), 1.0, 0); + + // Framebiffers creation + context.swapchain.framebuffers = vulkan_framebuffer_darray_new(context.swapchain.image_count); + regenerate_framebuffers(ren, &context.swapchain, &context.main_renderpass); + INFO("Framebuffers created"); + + // Command buffers creation + create_command_buffers(ren); + INFO("Command buffers created"); + + // Sync objects + context.image_available_semaphores = + calloc(context.swapchain.max_frames_in_flight, sizeof(VkSemaphore)); + context.queue_complete_semaphores = + calloc(context.swapchain.max_frames_in_flight, sizeof(VkSemaphore)); + context.in_flight_fences = calloc(context.swapchain.max_frames_in_flight, sizeof(vulkan_fence)); + + for (u8 i = 0; i < context.swapchain.max_frames_in_flight; i++) { + VkSemaphoreCreateInfo semaphore_create_info = { VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO }; + vkCreateSemaphore(context.device.logical_device, &semaphore_create_info, context.allocator, + &context.image_available_semaphores[i]); + vkCreateSemaphore(context.device.logical_device, &semaphore_create_info, context.allocator, + &context.queue_complete_semaphores[i]); + + // create the fence in a signaled state + vulkan_fence_create(&context, true, &context.in_flight_fences[i]); + } - // Shader modules - vulkan_object_shader_create(&context, &context.object_shader); - INFO("Compiled shader modules") + context.images_in_flight = + malloc(sizeof(vulkan_fence*) * context.swapchain.max_frames_in_flight); + for (u8 i = 0; i < context.swapchain.max_frames_in_flight; i++) { + context.images_in_flight[i] = 0; + } + INFO("Sync objects created"); - create_buffers(&context); - INFO("Created buffers"); + // Shader modules + vulkan_object_shader_create(&context, &context.object_shader); + INFO("Compiled shader modules") - // TODO: temporary test code + create_buffers(&context); + INFO("Created buffers"); - mesh cube = prim_cube_mesh_create(); + // TODO: temporary test code - vertex* verts = malloc(sizeof(vertex) * cube.vertices->len); + mesh cube = prim_cube_mesh_create(); - f32 scale = 3.0; - for (size_t i = 0; i < cube.vertices->len; i++) { - verts[i].position = vec3_mult(cube.vertices->data[i].position, scale); - verts[i].normal = cube.vertices->data[i].normal; - verts[i].uv = cube.vertices->data[i].uv; - } + vertex* verts = malloc(sizeof(vertex) * cube.vertices->len); - // const f32 s = 1.0; - // const u32 vert_count = 4; - // vertex_pos verts[4] = { 0 }; + f32 scale = 3.0; + for (size_t i = 0; i < cube.vertices->len; i++) { + verts[i].position = vec3_mult(cube.vertices->data[i].position, scale); + verts[i].normal = cube.vertices->data[i].normal; + verts[i].uv = cube.vertices->data[i].uv; + } - // verts[0].pos.x = -0.5 * s; - // verts[0].pos.y = -0.5 * s; + // const f32 s = 1.0; + // const u32 vert_count = 4; + // vertex_pos verts[4] = { 0 }; - // verts[1].pos.x = 0.5 * s; - // verts[1].pos.y = 0.5 * s; + // verts[0].pos.x = -0.5 * s; + // verts[0].pos.y = -0.5 * s; - // verts[2].pos.x = -0.5 * s; - // verts[2].pos.y = 0.5 * s; + // verts[1].pos.x = 0.5 * s; + // verts[1].pos.y = 0.5 * s; - // verts[3].pos.x = 0.5 * s; - // verts[3].pos.y = -0.5 * s; + // verts[2].pos.x = -0.5 * s; + // verts[2].pos.y = 0.5 * s; - // const u32 index_count = 6; - // u32 indices[6] = { 0, 1, 2, 0, 3, 1 }; + // verts[3].pos.x = 0.5 * s; + // verts[3].pos.y = -0.5 * s; - upload_data_range(&context, context.device.gfx_command_pool, 0, context.device.graphics_queue, - &context.object_vertex_buffer, 0, sizeof(vertex) * cube.vertices->len, verts); - TRACE("Uploaded vertex data"); - upload_data_range(&context, context.device.gfx_command_pool, 0, context.device.graphics_queue, - &context.object_index_buffer, 0, sizeof(u32) * cube.indices_len, cube.indices); - TRACE("Uploaded index data"); - vertex_darray_free(cube.vertices); - free(cube.indices); + // const u32 index_count = 6; + // u32 indices[6] = { 0, 1, 2, 0, 3, 1 }; - // upload texture + upload_data_range(&context, context.device.gfx_command_pool, 0, context.device.graphics_queue, + &context.object_vertex_buffer, 0, sizeof(vertex) * cube.vertices->len, verts); + TRACE("Uploaded vertex data"); + upload_data_range(&context, context.device.gfx_command_pool, 0, context.device.graphics_queue, + &context.object_index_buffer, 0, sizeof(u32) * cube.indices_len, + cube.indices); + TRACE("Uploaded index data"); + vertex_darray_free(cube.vertices); + free(cube.indices); - // --- End test code + // upload texture - INFO("Vulkan renderer initialisation succeeded"); - return true; -} + // --- End test code -void gfx_backend_shutdown(renderer* ren) { - DEBUG("Destroying Vulkan debugger"); - if (context.vk_debugger) { - PFN_vkDestroyDebugUtilsMessengerEXT func = - (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr( - context.instance, "vkDestroyDebugUtilsMessengerEXT"); - func(context.instance, context.vk_debugger, context.allocator); + INFO("Vulkan renderer initialisation succeeded"); + return true; } - DEBUG("Destroying Vulkan instance..."); - vkDestroyInstance(context.instance, context.allocator); -} + void gfx_backend_shutdown(renderer * ren) { + DEBUG("Destroying Vulkan debugger"); + if (context.vk_debugger) { + PFN_vkDestroyDebugUtilsMessengerEXT func = + (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr( + context.instance, "vkDestroyDebugUtilsMessengerEXT"); + func(context.instance, context.vk_debugger, context.allocator); + } -void backend_begin_frame(renderer* ren, f32 delta_time) { - vulkan_device* device = &context.device; + DEBUG("Destroying Vulkan instance..."); + vkDestroyInstance(context.instance, context.allocator); + } - // TODO: resize gubbins + void backend_begin_frame(renderer * ren, f32 delta_time) { + vulkan_device* device = &context.device; - if (!vulkan_fence_wait(&context, &context.in_flight_fences[context.current_frame], UINT64_MAX)) { - WARN("In-flight fence wait failure"); - } + // TODO: resize gubbins - if (!vulkan_swapchain_acquire_next_image_index( - &context, &context.swapchain, UINT64_MAX, - context.image_available_semaphores[context.current_frame], 0, &context.image_index)) { - WARN("couldnt acquire swapchain next image"); - } + if (!vulkan_fence_wait(&context, &context.in_flight_fences[context.current_frame], + UINT64_MAX)) { + WARN("In-flight fence wait failure"); + } - vulkan_command_buffer* command_buffer = &context.gfx_command_buffers->data[context.image_index]; - vulkan_command_buffer_reset(command_buffer); - vulkan_command_buffer_begin(command_buffer, false, false, false); + if (!vulkan_swapchain_acquire_next_image_index( + &context, &context.swapchain, UINT64_MAX, + context.image_available_semaphores[context.current_frame], 0, &context.image_index)) { + WARN("couldnt acquire swapchain next image"); + } - VkViewport viewport; - viewport.x = 0.0; - viewport.y = 0; - viewport.width = (f32)context.framebuffer_width; - viewport.height = (f32)context.framebuffer_height; - viewport.minDepth = 0.0; - viewport.maxDepth = 1.0; + vulkan_command_buffer* command_buffer = &context.gfx_command_buffers->data[context.image_index]; + vulkan_command_buffer_reset(command_buffer); + vulkan_command_buffer_begin(command_buffer, false, false, false); - VkRect2D scissor; - scissor.offset.x = scissor.offset.y = 0; - scissor.extent.width = context.framebuffer_width; - scissor.extent.height = context.framebuffer_height; + VkViewport viewport; + viewport.x = 0.0; + viewport.y = 0; + viewport.width = (f32)context.framebuffer_width; + viewport.height = (f32)context.framebuffer_height; + viewport.minDepth = 0.0; + viewport.maxDepth = 1.0; - vkCmdSetViewport(command_buffer->handle, 0, 1, &viewport); - vkCmdSetScissor(command_buffer->handle, 0, 1, &scissor); + VkRect2D scissor; + scissor.offset.x = scissor.offset.y = 0; + scissor.extent.width = context.framebuffer_width; + scissor.extent.height = context.framebuffer_height; - context.main_renderpass.render_area.z = context.framebuffer_width; - context.main_renderpass.render_area.w = context.framebuffer_height; + vkCmdSetViewport(command_buffer->handle, 0, 1, &viewport); + vkCmdSetScissor(command_buffer->handle, 0, 1, &scissor); - vulkan_renderpass_begin(command_buffer, &context.main_renderpass, - context.swapchain.framebuffers->data[context.image_index].handle); -} + context.main_renderpass.render_area.z = context.framebuffer_width; + context.main_renderpass.render_area.w = context.framebuffer_height; -void texture_data_upload(texture* tex) { - printf("Texture name %s\n", tex->name); - tex->backend_data = malloc(sizeof(vulkan_texture_data)); - vulkan_texture_data* data = (vulkan_texture_data*)tex->backend_data; - printf("Texture (%s) details: \n width %d\n height %d\n channel count %d\n", tex->name, - tex->width, tex->height, tex->channel_count); - VkDeviceSize image_size = tex->width * tex->height * max(tex->channel_count, 4); - - TRACE("Creating buffer of size %ld", image_size); - - VkFormat image_format = VK_FORMAT_R8G8B8A8_SRGB; - - VkBufferUsageFlags usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; - VkMemoryPropertyFlags memory_prop_flags = - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; - vulkan_buffer staging; - vulkan_buffer_create(&context, image_size, usage, memory_prop_flags, true, &staging); - DEBUG("Uploading image data"); - vulkan_buffer_load_data(&context, &staging, 0, image_size, 0, tex->image_data); - INFO("Loaded iamge data!"); - - vulkan_image_create( - &context, VK_IMAGE_TYPE_2D, tex->width, tex->height, image_format, VK_IMAGE_TILING_OPTIMAL, - VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | - VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, true, VK_IMAGE_ASPECT_COLOR_BIT, &data->image); - - vulkan_command_buffer temp_buffer; - vulkan_command_buffer_allocate_and_begin_oneshot(&context, context.device.gfx_command_pool, - &temp_buffer); - - vulkan_image_transition_layout(&context, &temp_buffer, &data->image, image_format, - VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); - - vulkan_image_copy_from_buffer(&data->image, staging.handle, &temp_buffer); - - vulkan_image_transition_layout(&context, &temp_buffer, &data->image, image_format, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - - vulkan_command_buffer_end_oneshot(&context, context.device.gfx_command_pool, &temp_buffer, - context.device.graphics_queue); - - VkSamplerCreateInfo sampler_info = { VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO }; - sampler_info.magFilter = VK_FILTER_LINEAR; - sampler_info.minFilter = VK_FILTER_LINEAR; - sampler_info.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; - sampler_info.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT; - sampler_info.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; - sampler_info.anisotropyEnable = VK_TRUE; - sampler_info.maxAnisotropy = 16; - sampler_info.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK; - sampler_info.unnormalizedCoordinates = VK_FALSE; - sampler_info.compareEnable = VK_FALSE; - sampler_info.compareOp = VK_COMPARE_OP_ALWAYS; - sampler_info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; - sampler_info.mipLodBias = 0.0; - sampler_info.minLod = 0.0; - sampler_info.maxLod = 0.0; - - VkResult res = vkCreateSampler(context.device.logical_device, &sampler_info, context.allocator, - &data->sampler); - if (res != VK_SUCCESS) { - ERROR("Error creating texture sampler for image %s", tex->name); - return; + vulkan_renderpass_begin(command_buffer, &context.main_renderpass, + context.swapchain.framebuffers->data[context.image_index].handle); } - tex->image_data = (void*)data; -} + void texture_data_upload(texture * tex) { + printf("Texture name %s\n", tex->name); + tex->backend_data = malloc(sizeof(vulkan_texture_data)); + vulkan_texture_data* data = (vulkan_texture_data*)tex->backend_data; + printf("Texture (%s) details: \n width %d\n height %d\n channel count %d\n", tex->name, + tex->width, tex->height, tex->channel_count); + VkDeviceSize image_size = tex->width * tex->height * max(tex->channel_count, 4); + + TRACE("Creating buffer of size %ld", image_size); + + VkFormat image_format = VK_FORMAT_R8G8B8A8_SRGB; + + VkBufferUsageFlags usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + VkMemoryPropertyFlags memory_prop_flags = + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; + vulkan_buffer staging; + vulkan_buffer_create(&context, image_size, usage, memory_prop_flags, true, &staging); + DEBUG("Uploading image data"); + vulkan_buffer_load_data(&context, &staging, 0, image_size, 0, tex->image_data); + INFO("Loaded iamge data!"); + + vulkan_image_create( + &context, VK_IMAGE_TYPE_2D, tex->width, tex->height, image_format, VK_IMAGE_TILING_OPTIMAL, + VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | + VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, true, VK_IMAGE_ASPECT_COLOR_BIT, &data->image); + + vulkan_command_buffer temp_buffer; + vulkan_command_buffer_allocate_and_begin_oneshot(&context, context.device.gfx_command_pool, + &temp_buffer); + + vulkan_image_transition_layout(&context, &temp_buffer, &data->image, image_format, + VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + + vulkan_image_copy_from_buffer(&data->image, staging.handle, &temp_buffer); + + vulkan_image_transition_layout(&context, &temp_buffer, &data->image, image_format, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + + vulkan_command_buffer_end_oneshot(&context, context.device.gfx_command_pool, &temp_buffer, + context.device.graphics_queue); + + VkSamplerCreateInfo sampler_info = { VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO }; + sampler_info.magFilter = VK_FILTER_LINEAR; + sampler_info.minFilter = VK_FILTER_LINEAR; + sampler_info.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; + sampler_info.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT; + sampler_info.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; + sampler_info.anisotropyEnable = VK_TRUE; + sampler_info.maxAnisotropy = 16; + sampler_info.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK; + sampler_info.unnormalizedCoordinates = VK_FALSE; + sampler_info.compareEnable = VK_FALSE; + sampler_info.compareOp = VK_COMPARE_OP_ALWAYS; + sampler_info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; + sampler_info.mipLodBias = 0.0; + sampler_info.minLod = 0.0; + sampler_info.maxLod = 0.0; + + VkResult res = vkCreateSampler(context.device.logical_device, &sampler_info, context.allocator, + &data->sampler); + if (res != VK_SUCCESS) { + ERROR("Error creating texture sampler for image %s", tex->name); + return; + } -// TODO: destroy texture + tex->image_data = (void*)data; + } -void backend_end_frame(renderer* ren, f32 delta_time) { - vulkan_command_buffer* command_buffer = &context.gfx_command_buffers->data[context.image_index]; + // TODO: destroy texture - vulkan_renderpass_end(command_buffer, &context.main_renderpass); + void backend_end_frame(renderer * ren, f32 delta_time) { + vulkan_command_buffer* command_buffer = &context.gfx_command_buffers->data[context.image_index]; - vulkan_command_buffer_end(command_buffer); + vulkan_renderpass_end(command_buffer, &context.main_renderpass); - // TODO: wait on fence - https://youtu.be/hRL71D1f3pU?si=nLJx-ZsemDBeQiQ1&t=1037 + vulkan_command_buffer_end(command_buffer); - context.images_in_flight[context.image_index] = &context.in_flight_fences[context.current_frame]; + // TODO: wait on fence - https://youtu.be/hRL71D1f3pU?si=nLJx-ZsemDBeQiQ1&t=1037 - vulkan_fence_reset(&context, &context.in_flight_fences[context.current_frame]); + context.images_in_flight[context.image_index] = + &context.in_flight_fences[context.current_frame]; - VkSubmitInfo submit_info = { VK_STRUCTURE_TYPE_SUBMIT_INFO }; - submit_info.commandBufferCount = 1; - submit_info.pCommandBuffers = &command_buffer->handle; - submit_info.signalSemaphoreCount = 1; - submit_info.pSignalSemaphores = &context.queue_complete_semaphores[context.current_frame]; - submit_info.waitSemaphoreCount = 1; - submit_info.pWaitSemaphores = &context.image_available_semaphores[context.current_frame]; + vulkan_fence_reset(&context, &context.in_flight_fences[context.current_frame]); - VkPipelineStageFlags flags[1] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT }; - submit_info.pWaitDstStageMask = flags; + VkSubmitInfo submit_info = { VK_STRUCTURE_TYPE_SUBMIT_INFO }; + submit_info.commandBufferCount = 1; + submit_info.pCommandBuffers = &command_buffer->handle; + submit_info.signalSemaphoreCount = 1; + submit_info.pSignalSemaphores = &context.queue_complete_semaphores[context.current_frame]; + submit_info.waitSemaphoreCount = 1; + submit_info.pWaitSemaphores = &context.image_available_semaphores[context.current_frame]; - VkResult result = vkQueueSubmit(context.device.graphics_queue, 1, &submit_info, - context.in_flight_fences[context.current_frame].handle); + VkPipelineStageFlags flags[1] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT }; + submit_info.pWaitDstStageMask = flags; - if (result != VK_SUCCESS) { - ERROR("queue submission failed. fark."); - } + VkResult result = vkQueueSubmit(context.device.graphics_queue, 1, &submit_info, + context.in_flight_fences[context.current_frame].handle); - vulkan_command_buffer_update_submitted(command_buffer); + if (result != VK_SUCCESS) { + ERROR("queue submission failed. fark."); + } - vulkan_swapchain_present( - &context, &context.swapchain, context.device.graphics_queue, context.device.graphics_queue, - context.queue_complete_semaphores[context.current_frame], context.image_index); -} + vulkan_command_buffer_update_submitted(command_buffer); -void gfx_backend_draw_frame(renderer* ren, camera* cam, mat4 model, texture* tex) { - backend_begin_frame(ren, 16.0); + vulkan_swapchain_present( + &context, &context.swapchain, context.device.graphics_queue, context.device.graphics_queue, + context.queue_complete_semaphores[context.current_frame], context.image_index); + } - mat4 proj; - mat4 view; + void gfx_backend_draw_frame(renderer * ren, camera * cam, mat4 model, texture * tex) { + backend_begin_frame(ren, 16.0); - camera_view_projection(cam, SCR_HEIGHT, SCR_WIDTH, &view, &proj); + mat4 proj; + mat4 view; - context.object_shader.texture_data = (vulkan_texture_data*)tex->image_data; - gfx_backend_update_global_state(proj, view, cam->position, vec4(1.0, 1.0, 1.0, 1.0), 0); + camera_view_projection(cam, SCR_HEIGHT, SCR_WIDTH, &view, &proj); - vulkan_object_shader_update_object(&context, &context.object_shader, model); + context.object_shader.texture_data = (vulkan_texture_data*)tex->image_data; + gfx_backend_update_global_state(proj, view, cam->position, vec4(1.0, 1.0, 1.0, 1.0), 0); - backend_end_frame(ren, 16.0); -} + vulkan_object_shader_update_object(&context, &context.object_shader, model); -void gfx_backend_update_global_state(mat4 projection, mat4 view, vec3 view_pos, vec4 ambient_colour, - i32 mode) { - vulkan_object_shader_use(&context, &context.object_shader); + backend_end_frame(ren, 16.0); + } - vulkan_object_shader_update_global_state(&context, &context.object_shader); - context.object_shader.global_ubo.projection = projection; - context.object_shader.global_ubo.view = view; - // TODO: other UBO properties -} + void gfx_backend_update_global_state(mat4 projection, mat4 view, vec3 view_pos, + vec4 ambient_colour, i32 mode) { + vulkan_object_shader_use(&context, &context.object_shader); -void clear_screen(vec3 colour) {} + vulkan_object_shader_update_global_state(&context, &context.object_shader); + context.object_shader.global_ubo.projection = projection; + context.object_shader.global_ubo.view = view; + // TODO: other UBO properties + } -void bind_texture(shader s, texture* tex, u32 slot) {} -void bind_mesh_vertex_buffer(void* backend, mesh* mesh) {} -void draw_primitives(cel_primitive_topology primitive, u32 start_index, u32 count) {} + void clear_screen(vec3 colour) {} -shader shader_create_separate(const char* vert_shader, const char* frag_shader) {} -void set_shader(shader s) {} + void bind_texture(shader s, texture * tex, u32 slot) {} + void bind_mesh_vertex_buffer(void* backend, mesh* mesh) {} + void draw_primitives(cel_primitive_topology primitive, u32 start_index, u32 count) {} -void uniform_vec3f(u32 program_id, const char* uniform_name, vec3* value) {} -void uniform_f32(u32 program_id, const char* uniform_name, f32 value) {} -void uniform_i32(u32 program_id, const char* uniform_name, i32 value) {} -void uniform_mat4f(u32 program_id, const char* uniform_name, mat4* value) {} + shader shader_create_separate(const char* vert_shader, const char* frag_shader) {} + void set_shader(shader s) {} -VKAPI_ATTR VkBool32 VKAPI_CALL vk_debug_callback( - VkDebugUtilsMessageSeverityFlagBitsEXT severity, VkDebugUtilsMessageTypeFlagsEXT flags, - const VkDebugUtilsMessengerCallbackDataEXT* callback_data, void* user_data) { - switch (severity) { - default: - case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT: - ERROR("%s", callback_data->pMessage); - break; - case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT: - WARN("%s", callback_data->pMessage); - break; - case VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT: - INFO("%s", callback_data->pMessage); - break; - case VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT: - TRACE("%s", callback_data->pMessage); - break; + void uniform_vec3f(u32 program_id, const char* uniform_name, vec3* value) {} + void uniform_f32(u32 program_id, const char* uniform_name, f32 value) {} + void uniform_i32(u32 program_id, const char* uniform_name, i32 value) {} + void uniform_mat4f(u32 program_id, const char* uniform_name, mat4* value) {} + + VKAPI_ATTR VkBool32 VKAPI_CALL vk_debug_callback( + VkDebugUtilsMessageSeverityFlagBitsEXT severity, VkDebugUtilsMessageTypeFlagsEXT flags, + const VkDebugUtilsMessengerCallbackDataEXT* callback_data, void* user_data) { + switch (severity) { + default: + case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT: + ERROR("%s", callback_data->pMessage); + break; + case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT: + WARN("%s", callback_data->pMessage); + break; + case VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT: + INFO("%s", callback_data->pMessage); + break; + case VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT: + TRACE("%s", callback_data->pMessage); + break; + } + return VK_FALSE; } - return VK_FALSE; -} #endif \ No newline at end of file diff --git a/src/std/containers/graphs.h b/src/std/containers/graphs.h new file mode 100644 index 0000000..47399e9 --- /dev/null +++ b/src/std/containers/graphs.h @@ -0,0 +1,15 @@ +/** + * @file graphs.h + * @author your name (you@domain.com) + * @brief + * @version 0.1 + * @date 2024-04-27 + * + * @copyright Copyright (c) 2024 + * + */ + + +// Adjacency list backed graphs + +// Matrix backed graphs (not as useful) \ No newline at end of file diff --git a/src/std/containers/hashset.h b/src/std/containers/hashset.h new file mode 100644 index 0000000..f8e7073 --- /dev/null +++ b/src/std/containers/hashset.h @@ -0,0 +1,10 @@ +/** + * @file hashset.h + * @author your name (you@domain.com) + * @brief + * @version 0.1 + * @date 2024-04-27 + * + * @copyright Copyright (c) 2024 + * + */ \ No newline at end of file diff --git a/src/std/containers/hashtable.h b/src/std/containers/hashtable.h new file mode 100644 index 0000000..c93dc19 --- /dev/null +++ b/src/std/containers/hashtable.h @@ -0,0 +1,10 @@ +/** + * @file hashtable.h + * @author your name (you@domain.com) + * @brief + * @version 0.1 + * @date 2024-04-27 + * + * @copyright Copyright (c) 2024 + * + */ \ No newline at end of file diff --git a/src/systems/terrain.h b/src/systems/terrain.h index fa2d3b3..96875d9 100644 --- a/src/systems/terrain.h +++ b/src/systems/terrain.h @@ -8,3 +8,12 @@ * @copyright Copyright (c) 2024 * */ + +#include "defines.h" + +typedef struct terrain_state { + +} terrain_state; + +bool terrain_system_init(terrain_state* state); +void terrain_system_shutdown(terrain_state* state); \ No newline at end of file -- cgit v1.2.3-70-g09d2 From fc35df8e999521b8be7c44800f4ff4665df3254a Mon Sep 17 00:00:00 2001 From: omniscient <17525998+omnisci3nce@users.noreply.github.com> Date: Sat, 27 Apr 2024 16:35:11 +1000 Subject: heightmap function signatures --- src/core.h | 2 +- src/logos/jobs.h | 4 ++-- src/maths/primitives.c | 16 +++----------- src/platform/mutex.c | 2 +- src/platform/mutex.h | 12 ++++++----- src/platform/thread.h | 6 +++--- src/renderer/cleanroom/backend_vulkan.h | 7 ++++--- src/renderer/cleanroom/ral.h | 12 +++++------ src/renderer/cleanroom/renderer.h | 2 +- src/renderer/cleanroom/types.h | 13 ++++++++---- src/renderer/render_types.h | 3 ++- src/std/containers/graphs.h | 7 +++---- src/std/containers/hashset.h | 6 +++--- src/std/containers/hashtable.h | 6 +++--- src/systems/physics.h | 2 +- src/systems/terrain.h | 37 ++++++++++++++++++++++++++++----- src/systems/text.h | 2 +- src/transform_hierarchy.h | 2 +- 18 files changed, 83 insertions(+), 58 deletions(-) (limited to 'src/systems') diff --git a/src/core.h b/src/core.h index dd5a695..be88c53 100644 --- a/src/core.h +++ b/src/core.h @@ -3,8 +3,8 @@ #include "defines.h" #include "input.h" #include "ral.h" -#include "terrain.h" #include "screenspace.h" +#include "terrain.h" #include "text.h" #include "threadpool.h" diff --git a/src/logos/jobs.h b/src/logos/jobs.h index cc2c8fa..ef4eed7 100644 --- a/src/logos/jobs.h +++ b/src/logos/jobs.h @@ -1,3 +1,3 @@ /** - * Common jobs that get run -*/ \ No newline at end of file + * Common jobs that get run + */ \ No newline at end of file diff --git a/src/maths/primitives.c b/src/maths/primitives.c index 42c51ea..55ff5fc 100644 --- a/src/maths/primitives.c +++ b/src/maths/primitives.c @@ -13,20 +13,10 @@ geometry_data geo_create_plane(f32x2 extents) { vertex_format format = VERTEX_STATIC_3D; vertex_darray* vertices = vertex_darray_new(4); - vertex_darray_push( - vertices, - (vertex) {.static_3d = { - .position = - }} - ); - - return (geometry_data) { - .format = format, - .vertices = - .has_indices = true, - } -} + vertex_darray_push(vertices, (vertex){ .static_3d = { .position = } }); + return (geometry_data) { .format = format, .vertices =.has_indices = true, } +} // OLD diff --git a/src/platform/mutex.c b/src/platform/mutex.c index 9735483..2aeb825 100644 --- a/src/platform/mutex.c +++ b/src/platform/mutex.c @@ -4,6 +4,6 @@ // TODO: implement in terms of pthreads #endif -#if defined (CEL_PLATFORM_WINDOWS) +#if defined(CEL_PLATFORM_WINDOWS) // TODO: implement using win32 api #endif \ No newline at end of file diff --git a/src/platform/mutex.h b/src/platform/mutex.h index 0552ea2..a0a4208 100644 --- a/src/platform/mutex.h +++ b/src/platform/mutex.h @@ -1,12 +1,12 @@ /** * @file mutex.h * @author your name (you@domain.com) - * @brief + * @brief * @version 0.1 * @date 2024-04-27 - * + * * @copyright Copyright (c) 2024 - * + * */ #include @@ -16,10 +16,12 @@ cel_mutex mutex_create(); void mutex_destroy(cel_mutex* mutex); -/** @brief Blocks until the mutex can be acquired. if returns false then an error occurred and can be checked (TODO) */ +/** @brief Blocks until the mutex can be acquired. if returns false then an error occurred and can + * be checked (TODO) */ bool mutex_lock(cel_mutex* mutex); -/** @brief Tries to acquire the mutex like `mutex_lock` but returns immediately if the mutex has already been locked */ +/** @brief Tries to acquire the mutex like `mutex_lock` but returns immediately if the mutex has + * already been locked */ bool mutex_try_lock(cel_mutex* mutex); /** @brief Releases a mutex. If it is already unlocked then does nothing */ diff --git a/src/platform/thread.h b/src/platform/thread.h index a3560cb..af07d3f 100644 --- a/src/platform/thread.h +++ b/src/platform/thread.h @@ -1,12 +1,12 @@ /** * @file thread.h * @author your name (you@domain.com) - * @brief + * @brief * @version 0.1 * @date 2024-04-27 - * + * * @copyright Copyright (c) 2024 - * + * */ typedef struct cel_thread cel_thread; diff --git a/src/renderer/cleanroom/backend_vulkan.h b/src/renderer/cleanroom/backend_vulkan.h index 6798b13..c8d5777 100644 --- a/src/renderer/cleanroom/backend_vulkan.h +++ b/src/renderer/cleanroom/backend_vulkan.h @@ -3,7 +3,8 @@ #define GPU_SWAPCHAIN_IMG_COUNT 2 -typedef struct gpu_swapchain {} gpu_swapchain; +typedef struct gpu_swapchain { +} gpu_swapchain; typedef struct gpu_device { // In Vulkan we store both physical and logical device here VkPhysicalDevice physical_device; @@ -13,7 +14,8 @@ typedef struct gpu_device { VkPhysicalDeviceMemoryProperties memory; VkCommandPool pool; } gpu_device; -typedef struct gpu_pipeline {} gpu_pipeline; +typedef struct gpu_pipeline { +} gpu_pipeline; typedef struct gpu_renderpass { VkRenderPass vk_handle; @@ -21,7 +23,6 @@ typedef struct gpu_renderpass { u32 } gpu_renderpass; - typedef struct gpu_cmd_encoder { VkCommandBuffer cmd_buffer; } gpu_cmd_encoder; \ No newline at end of file diff --git a/src/renderer/cleanroom/ral.h b/src/renderer/cleanroom/ral.h index a1e9929..15eb027 100644 --- a/src/renderer/cleanroom/ral.h +++ b/src/renderer/cleanroom/ral.h @@ -5,9 +5,9 @@ * @details API that a graphics backend *must* implement * @version 0.1 * @date 2024-03-31 - * + * * @copyright Copyright (c) 2024 - * + * */ #pragma once @@ -19,8 +19,8 @@ typedef struct gpu_swapchain gpu_swapchain; typedef struct gpu_device gpu_device; 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_cmd_encoder gpu_cmd_encoder; // Recording +typedef struct gpu_cmd_buffer gpu_cmd_buffer; // Ready for submission enum pipeline_kind { GRAPHICS, @@ -29,8 +29,8 @@ enum pipeline_kind { typedef struct shader_desc { const char* debug_name; - str8 filepath; // where it came from - str8 glsl; // contents + str8 filepath; // where it came from + str8 glsl; // contents } shader_desc; struct pipeline_desc { diff --git a/src/renderer/cleanroom/renderer.h b/src/renderer/cleanroom/renderer.h index 8012b49..ff342b0 100644 --- a/src/renderer/cleanroom/renderer.h +++ b/src/renderer/cleanroom/renderer.h @@ -1,7 +1,7 @@ #pragma once -#include "cleanroom/ral.h" #include "cleanroom/backend_vulkan.h" +#include "cleanroom/ral.h" typedef struct renderer2 { void* backend_state; diff --git a/src/renderer/cleanroom/types.h b/src/renderer/cleanroom/types.h index 98c2e21..b18b5b8 100644 --- a/src/renderer/cleanroom/types.h +++ b/src/renderer/cleanroom/types.h @@ -10,7 +10,8 @@ CORE_DEFINE_HANDLE(sampler_handle); CORE_DEFINE_HANDLE(shader_handle); CORE_DEFINE_HANDLE(model_handle); -typedef struct transform_hierarchy {} transform_hierarchy; +typedef struct transform_hierarchy { +} transform_hierarchy; /** @brief Texture Description - used by texture creation functions */ typedef struct texture_desc { @@ -56,7 +57,12 @@ typedef struct model bp_material; // blinn-phong #include "maths_types.h" -typedef enum vertex_format { VERTEX_STATIC_3D, VERTEX_SPRITE, VERTEX_SKINNED, VERTEX_COUNT } vertex_format; +typedef enum vertex_format { + VERTEX_STATIC_3D, + VERTEX_SPRITE, + VERTEX_SKINNED, + VERTEX_COUNT +} vertex_format; typedef union vertex { struct { @@ -79,7 +85,7 @@ typedef union vertex { vec3 normal; 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 */ + } skinned_3d; /** @brief vertex format for skeletal (animated) geometry in 3D */ } vertex; KITC_DECL_TYPED_ARRAY(vertex) @@ -128,7 +134,6 @@ typedef struct model { /* ral.h */ - // command buffer gubbins /* --- Backends */ diff --git a/src/renderer/render_types.h b/src/renderer/render_types.h index 387ac81..3bce88f 100644 --- a/src/renderer/render_types.h +++ b/src/renderer/render_types.h @@ -76,7 +76,8 @@ typedef struct texture { // bool is_loaded; // bool is_uploaded; // } blinn_phong_material; -// typedef blinn_phong_material material; // when we start using PBR, this will no longer be the case +// typedef blinn_phong_material material; // when we start using PBR, this will no longer be the +// case // // the default blinn-phong material. MUST be initialised with the function below // extern material DEFAULT_MATERIAL; diff --git a/src/std/containers/graphs.h b/src/std/containers/graphs.h index 47399e9..5dbec97 100644 --- a/src/std/containers/graphs.h +++ b/src/std/containers/graphs.h @@ -1,15 +1,14 @@ /** * @file graphs.h * @author your name (you@domain.com) - * @brief + * @brief * @version 0.1 * @date 2024-04-27 - * + * * @copyright Copyright (c) 2024 - * + * */ - // Adjacency list backed graphs // Matrix backed graphs (not as useful) \ No newline at end of file diff --git a/src/std/containers/hashset.h b/src/std/containers/hashset.h index f8e7073..d153fd2 100644 --- a/src/std/containers/hashset.h +++ b/src/std/containers/hashset.h @@ -1,10 +1,10 @@ /** * @file hashset.h * @author your name (you@domain.com) - * @brief + * @brief * @version 0.1 * @date 2024-04-27 - * + * * @copyright Copyright (c) 2024 - * + * */ \ No newline at end of file diff --git a/src/std/containers/hashtable.h b/src/std/containers/hashtable.h index c93dc19..f5d98e7 100644 --- a/src/std/containers/hashtable.h +++ b/src/std/containers/hashtable.h @@ -1,10 +1,10 @@ /** * @file hashtable.h * @author your name (you@domain.com) - * @brief + * @brief * @version 0.1 * @date 2024-04-27 - * + * * @copyright Copyright (c) 2024 - * + * */ \ No newline at end of file diff --git a/src/systems/physics.h b/src/systems/physics.h index 5c96c6e..61d2008 100644 --- a/src/systems/physics.h +++ b/src/systems/physics.h @@ -15,7 +15,7 @@ enum collider_type { /** @brief generic collider structure */ typedef struct physics_collider { - u64 id; // ? Replace with handle? + u64 id; // ? Replace with handle? enum collider_type shape; transform transform; u8 layer; diff --git a/src/systems/terrain.h b/src/systems/terrain.h index 96875d9..6558202 100644 --- a/src/systems/terrain.h +++ b/src/systems/terrain.h @@ -1,19 +1,46 @@ /** * @file terrain.h * @author your name (you@domain.com) - * @brief + * @brief * @version 0.1 * @date 2024-04-27 - * + * * @copyright Copyright (c) 2024 - * + * */ +/* +Future: + - Chunked terrain + - Dynamic LOD +*/ + +#include "cleanroom/types.h" #include "defines.h" +#include "maths_types.h" +#include "mem.h" typedef struct terrain_state { - } terrain_state; +typedef struct heightmap { + u32x2 size; + void* image_data; +} heightmap; + bool terrain_system_init(terrain_state* state); -void terrain_system_shutdown(terrain_state* state); \ No newline at end of file +void terrain_system_shutdown(terrain_state* state); +void terrain_system_render_hmap(renderer* rend, terrain_state* state); + +heightmap heightmap_from_image(const char* filepath); +heightmap heightmap_from_perlin(/* TODO: perlin noise generation parameters */); + +/** @brief Get the height (the Y component) for a vertex at a particular coordinate in the heightmap + */ +f32 heightmap_height_at_xz(heightmap* hmap, f32 x, f32 z); + +/** @brief Calculate the normal vector of a vertex at a particular coordinate in the heightmap */ +vec3 heightmap_normal_at_xz(heightmap* hmap, f32 x, f32 z); + +/** @brief Generate the `geometry_data` for a heightmap ready to be uploaded to the GPU */ +geometry_data geo_heightmap(arena* a, heightmap heightmap); \ No newline at end of file diff --git a/src/systems/text.h b/src/systems/text.h index 4fac0b8..dc396f0 100644 --- a/src/systems/text.h +++ b/src/systems/text.h @@ -8,8 +8,8 @@ #include "cleanroom/types.h" #include "darray.h" #include "defines.h" -#include "render_types.h" #include "ral.h" +#include "render_types.h" struct core; diff --git a/src/transform_hierarchy.h b/src/transform_hierarchy.h index d77b846..0921c19 100644 --- a/src/transform_hierarchy.h +++ b/src/transform_hierarchy.h @@ -4,8 +4,8 @@ #pragma once #include "maths_types.h" -#include "render_types.h" #include "ral.h" +#include "render_types.h" #define MAX_TF_NODE_CHILDREN \ 32 /** TEMP: Make it simpler to manage children in `transform_node`s */ -- cgit v1.2.3-70-g09d2 From 93c8d40b39fe55a626e66d412450fb4cca1f993b Mon Sep 17 00:00:00 2001 From: omniscient <17525998+omnisci3nce@users.noreply.github.com> Date: Sat, 27 Apr 2024 17:07:03 +1000 Subject: scene thoughts --- src/camera.h | 9 ++++++++- src/renderer/cleanroom/immediate.c | 18 ++++++++++++++++++ src/renderer/cleanroom/immediate.h | 20 ++++++++++++++++++++ src/renderer/cleanroom/simda.h | 18 ------------------ src/renderer/cleanroom/types.h | 3 +++ src/scene.h | 30 ++++++++++++++++++++++++++++++ src/systems/physics.h | 8 ++++++++ src/systems/terrain.h | 18 +++++++++++++----- 8 files changed, 100 insertions(+), 24 deletions(-) create mode 100644 src/renderer/cleanroom/immediate.c create mode 100644 src/renderer/cleanroom/immediate.h delete mode 100644 src/renderer/cleanroom/simda.h create mode 100644 src/scene.h (limited to 'src/systems') diff --git a/src/camera.h b/src/camera.h index f7bc6eb..ec867c5 100644 --- a/src/camera.h +++ b/src/camera.h @@ -24,4 +24,11 @@ camera camera_create(vec3 pos, vec3 front, vec3 up, f32 fov); /** @brief get a 4x4 transform matrix for the view and perspective projection */ void camera_view_projection(camera *c, f32 screen_height, f32 screen_width, mat4 *out_view, - mat4 *out_proj); \ No newline at end of file + mat4 *out_proj); + +// TODO: Basic reusable camera controls +/* +Right click + move = pan +Left click = orbit camera +WASD = forward/backward/left/right +*/ \ No newline at end of file diff --git a/src/renderer/cleanroom/immediate.c b/src/renderer/cleanroom/immediate.c new file mode 100644 index 0000000..8e4bf7e --- /dev/null +++ b/src/renderer/cleanroom/immediate.c @@ -0,0 +1,18 @@ +#include "immediate.h" +#include "maths.h" +#include "primitives.h" +#include "render.h" +#include "types.h" + +void imm_draw_sphere(vec3 pos, f32 radius, vec4 colour) { + // Create the vertices + geometry_data geometry = geo_create_uvsphere(radius, 16, 16); + geo_set_vertex_colours(&geometry, colour); + + // Upload to GPU + mat4 model = mat4_translation(pos); + + // Set pipeline + + // Draw +} \ No newline at end of file diff --git a/src/renderer/cleanroom/immediate.h b/src/renderer/cleanroom/immediate.h new file mode 100644 index 0000000..6d93c53 --- /dev/null +++ b/src/renderer/cleanroom/immediate.h @@ -0,0 +1,20 @@ +#pragma once + +#include "geometry.h" +#include "maths_types.h" + +// 3. SIMA (simplified immediate mode api) / render.h +// - dont need to worry about uploading mesh data +// - very useful for debugging +void imm_draw_cuboid(vec3 pos, quat rotation, f32x3 extents, vec4 colour); +void imm_draw_sphere(vec3 pos, f32 radius, vec4 colour); +void imm_draw_camera_frustum(); + +// static void imm_draw_model( +// const char* model_filepath); // tracks internally whether the model is loaded + +// static void imm_draw_model(const char* model_filepath) { + // check that model is loaded + // if not loaded, load model and upload to gpu - LRU cache for models + // else submit draw call +// } \ No newline at end of file diff --git a/src/renderer/cleanroom/simda.h b/src/renderer/cleanroom/simda.h deleted file mode 100644 index d0b4794..0000000 --- a/src/renderer/cleanroom/simda.h +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -#include "maths_types.h" - -// 3. SIMA (simplified immediate mode api) / render.h -// - dont need to worry about uploading mesh data -// - very useful for debugging -void imm_draw_cuboid(); -void imm_draw_sphere(vec3 pos, f32 radius, vec4 colour); -void imm_draw_camera_frustum(); -static void imm_draw_model( - const char* model_filepath); // tracks internally whether the model is loaded - -static void imm_draw_model(const char* model_filepath) { - // check that model is loaded - // if not loaded, load model and upload to gpu - LRU cache for models - // else submit draw call -} \ No newline at end of file diff --git a/src/renderer/cleanroom/types.h b/src/renderer/cleanroom/types.h index b18b5b8..7a6cfbd 100644 --- a/src/renderer/cleanroom/types.h +++ b/src/renderer/cleanroom/types.h @@ -96,8 +96,11 @@ typedef struct geometry_data { vertex_darray vertices; bool has_indices; u32_darray indices; + vec3 colour; /** Optional: set vertex colours */ } geometry_data; +void geo_set_vertex_colours(geometry_data* geo, vec4 colour); + typedef struct mesh { buffer_handle vertex_buffer; buffer_handle index_buffer; diff --git a/src/scene.h b/src/scene.h new file mode 100644 index 0000000..2cc4d8a --- /dev/null +++ b/src/scene.h @@ -0,0 +1,30 @@ +/** + * @file scene.h + * @author your name (you@domain.com) + * @brief + * @version 0.1 + * @date 2024-04-27 + * + * @copyright Copyright (c) 2024 + * + */ +#include "defines.h" +#include "types.h" + +typedef struct scene { + // directional_light dir_light; + // point_light point_lights[4]; + // size_t n_point_lights; +} scene; + +bool scene_add_directional_light(scene* s /* TODO */); +bool scene_add_point_light(scene* s /* TODO */); + +// 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); + +bool scene_add_model(scene *s, model_handle model); +void scene_remove_model(scene *s, model_handle model); + +// TODO: functions to load and save scenes from disk \ No newline at end of file diff --git a/src/systems/physics.h b/src/systems/physics.h index 61d2008..7239ab5 100644 --- a/src/systems/physics.h +++ b/src/systems/physics.h @@ -1,5 +1,6 @@ #pragma once +#include "geometry.h" #include "maths_types.h" // 'system' means that it gets called per frame @@ -17,11 +18,18 @@ enum collider_type { typedef struct physics_collider { u64 id; // ? Replace with handle? enum collider_type shape; + union collider_data { + cuboid cuboid; + sphere sphere; + } geometry; transform transform; u8 layer; bool on_ground; } physics_collider; +// What else do I need? +// intersection methods + typedef struct physics_world { physics_settings settings; } physics_world; diff --git a/src/systems/terrain.h b/src/systems/terrain.h index 6558202..3d6f1c1 100644 --- a/src/systems/terrain.h +++ b/src/systems/terrain.h @@ -20,19 +20,23 @@ Future: #include "maths_types.h" #include "mem.h" -typedef struct terrain_state { -} terrain_state; - typedef struct heightmap { + str8 filepath; u32x2 size; void* image_data; + bool is_uploaded; } heightmap; +typedef struct terrain_state { + arena terrain_allocator; + heightmap* heightmap; // NULL = no heightmap +} terrain_state; + bool terrain_system_init(terrain_state* state); void terrain_system_shutdown(terrain_state* state); void terrain_system_render_hmap(renderer* rend, terrain_state* state); -heightmap heightmap_from_image(const char* filepath); +heightmap heightmap_from_image(str8 filepath); heightmap heightmap_from_perlin(/* TODO: perlin noise generation parameters */); /** @brief Get the height (the Y component) for a vertex at a particular coordinate in the heightmap @@ -43,4 +47,8 @@ f32 heightmap_height_at_xz(heightmap* hmap, f32 x, f32 z); vec3 heightmap_normal_at_xz(heightmap* hmap, f32 x, f32 z); /** @brief Generate the `geometry_data` for a heightmap ready to be uploaded to the GPU */ -geometry_data geo_heightmap(arena* a, heightmap heightmap); \ No newline at end of file +geometry_data geo_heightmap(arena* a, heightmap heightmap); + +// somewhere there will be an easy way to add a heightmap + +// scene_add_heightmap \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 411520b240446f878a27c5d89812000774cc3c15 Mon Sep 17 00:00:00 2001 From: omnisci3nce Date: Sun, 28 Apr 2024 09:14:22 +1000 Subject: getting vulkan working on windows --- examples/main_loop/ex_main_loop.c | 2 + src/defines.h | 3 +- src/maths/maths.h | 1 + src/maths/primitives.c | 261 ++-- src/renderer/archive/old_backend_vulkan.c | 1990 +++++++++++++++++++++++++++++ src/renderer/backends/backend_dx11.h | 4 + src/renderer/backends/backend_vulkan.c | 1990 +---------------------------- src/renderer/backends/backend_vulkan.h | 27 + src/renderer/cleanroom/backend_vulkan.c | 65 - src/renderer/cleanroom/backend_vulkan.h | 28 - src/renderer/cleanroom/immediate.c | 18 - src/renderer/cleanroom/immediate.h | 20 - src/renderer/cleanroom/types.h | 60 - src/renderer/immediate.c | 18 + src/renderer/immediate.h | 20 + src/renderer/ral.h | 10 +- src/renderer/ral_types.h | 46 +- src/renderer/render.c | 4 +- src/renderer/render.h | 4 +- src/renderer/render_types.h | 2 - src/systems/screenspace.h | 2 +- xmake.lua | 14 +- 22 files changed, 2309 insertions(+), 2280 deletions(-) create mode 100644 src/renderer/archive/old_backend_vulkan.c create mode 100644 src/renderer/backends/backend_vulkan.h delete mode 100644 src/renderer/cleanroom/backend_vulkan.c delete mode 100644 src/renderer/cleanroom/backend_vulkan.h delete mode 100644 src/renderer/cleanroom/immediate.c delete mode 100644 src/renderer/cleanroom/immediate.h create mode 100644 src/renderer/immediate.c create mode 100644 src/renderer/immediate.h (limited to 'src/systems') diff --git a/examples/main_loop/ex_main_loop.c b/examples/main_loop/ex_main_loop.c index 4e1f6a9..4e31313 100644 --- a/examples/main_loop/ex_main_loop.c +++ b/examples/main_loop/ex_main_loop.c @@ -26,6 +26,8 @@ int main() { // insert work here render_frame_end(&core->renderer); + glfwSwapBuffers(core->renderer.window); + glfwPollEvents(); } return 0; diff --git a/src/defines.h b/src/defines.h index 54f2dd5..ec526e0 100644 --- a/src/defines.h +++ b/src/defines.h @@ -71,7 +71,8 @@ Renderer backend defines: #endif #if defined(CEL_PLATFORM_WINDOWS) -#define CEL_REND_BACKEND_DX11 1 +// #define CEL_REND_BACKEND_DX11 1 +#define CEL_REND_BACKEND_VULKAN 1 #endif #if defined(CEL_PLATFORM_MAC) diff --git a/src/maths/maths.h b/src/maths/maths.h index ad33981..88a5215 100644 --- a/src/maths/maths.h +++ b/src/maths/maths.h @@ -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 }; } +static inline vec2 vec2_div(vec2 a, f32 s) { return (vec2){ a.x / s, a.y / s }; } // TODO: Dimension 4 static inline vec4 vec4_create(f32 x, f32 y, f32 z, f32 w) { return (vec4){ x, y, z, w }; } diff --git a/src/maths/primitives.c b/src/maths/primitives.c index 55ff5fc..310fc98 100644 --- a/src/maths/primitives.c +++ b/src/maths/primitives.c @@ -1,4 +1,5 @@ #include "primitives.h" +#include "maths.h" // vertices f32 plane_vertex_positions[] = { @@ -13,9 +14,9 @@ geometry_data geo_create_plane(f32x2 extents) { vertex_format format = VERTEX_STATIC_3D; vertex_darray* vertices = vertex_darray_new(4); - vertex_darray_push(vertices, (vertex){ .static_3d = { .position = } }); + // vertex_darray_push(vertices, (vertex){ .static_3d = { .position = } }); - return (geometry_data) { .format = format, .vertices =.has_indices = true, } + // return (geometry_data) { .format = format, .vertices =.has_indices = true, } } // OLD @@ -33,130 +34,132 @@ static mesh prim_cube_mesh_create() { mesh cube = { 0 }; cube.vertices = vertex_darray_new(36); - // back faces - vertex_darray_push( - cube.vertices, - (vertex){ .position = BACK_BOT_LEFT, .normal = VEC3_NEG_Z, .uv = (vec2){ 0, 1 } }); - vertex_darray_push( - cube.vertices, - (vertex){ .position = BACK_TOP_LEFT, .normal = VEC3_NEG_Z, .uv = (vec2){ 0, 0 } }); - vertex_darray_push( - cube.vertices, - (vertex){ .position = BACK_TOP_RIGHT, .normal = VEC3_NEG_Z, .uv = (vec2){ 1, 0 } }); - vertex_darray_push( - cube.vertices, - (vertex){ .position = BACK_TOP_RIGHT, .normal = VEC3_NEG_Z, .uv = (vec2){ 1, 0 } }); - vertex_darray_push( - cube.vertices, - (vertex){ .position = BACK_BOT_RIGHT, .normal = VEC3_NEG_Z, .uv = (vec2){ 1, 1 } }); - vertex_darray_push( - cube.vertices, - (vertex){ .position = BACK_BOT_LEFT, .normal = VEC3_NEG_Z, .uv = (vec2){ 0, 1 } }); - - // front faces - vertex_darray_push( - cube.vertices, - (vertex){ .position = FRONT_BOT_LEFT, .normal = VEC3_Z, .uv = (vec2){ 0, 1 } }); - vertex_darray_push( - cube.vertices, - (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_Z, .uv = (vec2){ 1, 0 } }); - vertex_darray_push( - cube.vertices, - (vertex){ .position = FRONT_TOP_LEFT, .normal = VEC3_Z, .uv = (vec2){ 0, 0 } }); - vertex_darray_push( - cube.vertices, - (vertex){ .position = FRONT_BOT_LEFT, .normal = VEC3_Z, .uv = (vec2){ 0, 1 } }); - vertex_darray_push( - cube.vertices, - (vertex){ .position = FRONT_BOT_RIGHT, .normal = VEC3_Z, .uv = (vec2){ 1, 1 } }); - vertex_darray_push( - cube.vertices, - (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_Z, .uv = (vec2){ 1, 0 } }); - - // top faces - vertex_darray_push(cube.vertices, - (vertex){ .position = BACK_TOP_LEFT, .normal = VEC3_Y, .uv = (vec2){ 0, 0 } }); - vertex_darray_push( - cube.vertices, - (vertex){ .position = FRONT_TOP_LEFT, .normal = VEC3_Y, .uv = (vec2){ 0, 1 } }); - vertex_darray_push( - cube.vertices, - (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_Y, .uv = (vec2){ 1, 1 } }); - vertex_darray_push(cube.vertices, - (vertex){ .position = BACK_TOP_LEFT, .normal = VEC3_Y, .uv = (vec2){ 0, 0 } }); - vertex_darray_push( - cube.vertices, - (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_Y, .uv = (vec2){ 1, 1 } }); - vertex_darray_push( - cube.vertices, - (vertex){ .position = BACK_TOP_RIGHT, .normal = VEC3_Y, .uv = (vec2){ 1, 0 } }); - - // bottom faces - vertex_darray_push( - cube.vertices, - (vertex){ .position = BACK_BOT_LEFT, .normal = VEC3_NEG_Y, .uv = (vec2){ 0 } }); - vertex_darray_push( - cube.vertices, - (vertex){ .position = FRONT_BOT_RIGHT, .normal = VEC3_NEG_Y, .uv = (vec2){ 0 } }); - vertex_darray_push( - cube.vertices, - (vertex){ .position = FRONT_BOT_LEFT, .normal = VEC3_NEG_Y, .uv = (vec2){ 0 } }); - vertex_darray_push( - cube.vertices, - (vertex){ .position = BACK_BOT_LEFT, .normal = VEC3_NEG_Y, .uv = (vec2){ 0 } }); - vertex_darray_push( - cube.vertices, - (vertex){ .position = BACK_BOT_RIGHT, .normal = VEC3_NEG_Y, .uv = (vec2){ 0 } }); - vertex_darray_push( - cube.vertices, - (vertex){ .position = FRONT_BOT_RIGHT, .normal = VEC3_NEG_Y, .uv = (vec2){ 0 } }); - - // right faces - vertex_darray_push( - cube.vertices, - (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_X, .uv = (vec2){ 0, 0 } }); - vertex_darray_push( - cube.vertices, - (vertex){ .position = BACK_BOT_RIGHT, .normal = VEC3_X, .uv = (vec2){ 1, 1 } }); - vertex_darray_push( - cube.vertices, - (vertex){ .position = BACK_TOP_RIGHT, .normal = VEC3_X, .uv = (vec2){ 1, 0 } }); - vertex_darray_push( - cube.vertices, - (vertex){ .position = BACK_BOT_RIGHT, .normal = VEC3_X, .uv = (vec2){ 1, 1 } }); - vertex_darray_push( - cube.vertices, - (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_X, .uv = (vec2){ 0, 0 } }); - vertex_darray_push( - cube.vertices, - (vertex){ .position = FRONT_BOT_RIGHT, .normal = VEC3_X, .uv = (vec2){ 0, 1 } }); - - // left faces - vertex_darray_push( - cube.vertices, - (vertex){ .position = FRONT_TOP_LEFT, .normal = VEC3_NEG_X, .uv = (vec2){ 0 } }); - vertex_darray_push( - cube.vertices, - (vertex){ .position = BACK_TOP_LEFT, .normal = VEC3_NEG_X, .uv = (vec2){ 0 } }); - vertex_darray_push( - cube.vertices, - (vertex){ .position = BACK_BOT_LEFT, .normal = VEC3_NEG_X, .uv = (vec2){ 0 } }); - vertex_darray_push( - cube.vertices, - (vertex){ .position = BACK_BOT_LEFT, .normal = VEC3_NEG_X, .uv = (vec2){ 0 } }); - vertex_darray_push( - cube.vertices, - (vertex){ .position = FRONT_BOT_LEFT, .normal = VEC3_NEG_X, .uv = (vec2){ 0 } }); - vertex_darray_push( - cube.vertices, - (vertex){ .position = FRONT_TOP_LEFT, .normal = VEC3_NEG_X, .uv = (vec2){ 0 } }); - - cube.indices_len = cube.vertices->len; - cube.indices = malloc(sizeof(u32) * cube.indices_len); - - for (u32 i = 0; i < cube.indices_len; i++) { - cube.indices[i] = i; - } + // // back faces + // vertex_darray_push( + // cube.vertices, + // (vertex){ .position = BACK_BOT_LEFT, .normal = VEC3_NEG_Z, .uv = (vec2){ 0, 1 } }); + // vertex_darray_push( + // cube.vertices, + // (vertex){ .position = BACK_TOP_LEFT, .normal = VEC3_NEG_Z, .uv = (vec2){ 0, 0 } }); + // vertex_darray_push( + // cube.vertices, + // (vertex){ .position = BACK_TOP_RIGHT, .normal = VEC3_NEG_Z, .uv = (vec2){ 1, 0 } }); + // vertex_darray_push( + // cube.vertices, + // (vertex){ .position = BACK_TOP_RIGHT, .normal = VEC3_NEG_Z, .uv = (vec2){ 1, 0 } }); + // vertex_darray_push( + // cube.vertices, + // (vertex){ .position = BACK_BOT_RIGHT, .normal = VEC3_NEG_Z, .uv = (vec2){ 1, 1 } }); + // vertex_darray_push( + // cube.vertices, + // (vertex){ .position = BACK_BOT_LEFT, .normal = VEC3_NEG_Z, .uv = (vec2){ 0, 1 } }); + + // // front faces + // vertex_darray_push( + // cube.vertices, + // (vertex){ .position = FRONT_BOT_LEFT, .normal = VEC3_Z, .uv = (vec2){ 0, 1 } }); + // vertex_darray_push( + // cube.vertices, + // (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_Z, .uv = (vec2){ 1, 0 } }); + // vertex_darray_push( + // cube.vertices, + // (vertex){ .position = FRONT_TOP_LEFT, .normal = VEC3_Z, .uv = (vec2){ 0, 0 } }); + // vertex_darray_push( + // cube.vertices, + // (vertex){ .position = FRONT_BOT_LEFT, .normal = VEC3_Z, .uv = (vec2){ 0, 1 } }); + // vertex_darray_push( + // cube.vertices, + // (vertex){ .position = FRONT_BOT_RIGHT, .normal = VEC3_Z, .uv = (vec2){ 1, 1 } }); + // vertex_darray_push( + // cube.vertices, + // (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_Z, .uv = (vec2){ 1, 0 } }); + + // // top faces + // vertex_darray_push(cube.vertices, + // (vertex){ .position = BACK_TOP_LEFT, .normal = VEC3_Y, .uv = (vec2){ 0, 0 + // } }); + // vertex_darray_push( + // cube.vertices, + // (vertex){ .position = FRONT_TOP_LEFT, .normal = VEC3_Y, .uv = (vec2){ 0, 1 } }); + // vertex_darray_push( + // cube.vertices, + // (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_Y, .uv = (vec2){ 1, 1 } }); + // vertex_darray_push(cube.vertices, + // (vertex){ .position = BACK_TOP_LEFT, .normal = VEC3_Y, .uv = (vec2){ 0, 0 + // } }); + // vertex_darray_push( + // cube.vertices, + // (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_Y, .uv = (vec2){ 1, 1 } }); + // vertex_darray_push( + // cube.vertices, + // (vertex){ .position = BACK_TOP_RIGHT, .normal = VEC3_Y, .uv = (vec2){ 1, 0 } }); + + // // bottom faces + // vertex_darray_push( + // cube.vertices, + // (vertex){ .position = BACK_BOT_LEFT, .normal = VEC3_NEG_Y, .uv = (vec2){ 0 } }); + // vertex_darray_push( + // cube.vertices, + // (vertex){ .position = FRONT_BOT_RIGHT, .normal = VEC3_NEG_Y, .uv = (vec2){ 0 } }); + // vertex_darray_push( + // cube.vertices, + // (vertex){ .position = FRONT_BOT_LEFT, .normal = VEC3_NEG_Y, .uv = (vec2){ 0 } }); + // vertex_darray_push( + // cube.vertices, + // (vertex){ .position = BACK_BOT_LEFT, .normal = VEC3_NEG_Y, .uv = (vec2){ 0 } }); + // vertex_darray_push( + // cube.vertices, + // (vertex){ .position = BACK_BOT_RIGHT, .normal = VEC3_NEG_Y, .uv = (vec2){ 0 } }); + // vertex_darray_push( + // cube.vertices, + // (vertex){ .position = FRONT_BOT_RIGHT, .normal = VEC3_NEG_Y, .uv = (vec2){ 0 } }); + + // // right faces + // vertex_darray_push( + // cube.vertices, + // (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_X, .uv = (vec2){ 0, 0 } }); + // vertex_darray_push( + // cube.vertices, + // (vertex){ .position = BACK_BOT_RIGHT, .normal = VEC3_X, .uv = (vec2){ 1, 1 } }); + // vertex_darray_push( + // cube.vertices, + // (vertex){ .position = BACK_TOP_RIGHT, .normal = VEC3_X, .uv = (vec2){ 1, 0 } }); + // vertex_darray_push( + // cube.vertices, + // (vertex){ .position = BACK_BOT_RIGHT, .normal = VEC3_X, .uv = (vec2){ 1, 1 } }); + // vertex_darray_push( + // cube.vertices, + // (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_X, .uv = (vec2){ 0, 0 } }); + // vertex_darray_push( + // cube.vertices, + // (vertex){ .position = FRONT_BOT_RIGHT, .normal = VEC3_X, .uv = (vec2){ 0, 1 } }); + + // // left faces + // vertex_darray_push( + // cube.vertices, + // (vertex){ .position = FRONT_TOP_LEFT, .normal = VEC3_NEG_X, .uv = (vec2){ 0 } }); + // vertex_darray_push( + // cube.vertices, + // (vertex){ .position = BACK_TOP_LEFT, .normal = VEC3_NEG_X, .uv = (vec2){ 0 } }); + // vertex_darray_push( + // cube.vertices, + // (vertex){ .position = BACK_BOT_LEFT, .normal = VEC3_NEG_X, .uv = (vec2){ 0 } }); + // vertex_darray_push( + // cube.vertices, + // (vertex){ .position = BACK_BOT_LEFT, .normal = VEC3_NEG_X, .uv = (vec2){ 0 } }); + // vertex_darray_push( + // cube.vertices, + // (vertex){ .position = FRONT_BOT_LEFT, .normal = VEC3_NEG_X, .uv = (vec2){ 0 } }); + // vertex_darray_push( + // cube.vertices, + // (vertex){ .position = FRONT_TOP_LEFT, .normal = VEC3_NEG_X, .uv = (vec2){ 0 } }); + + // cube.indices_len = cube.vertices->len; + // cube.indices = malloc(sizeof(u32) * cube.indices_len); + + // for (u32 i = 0; i < cube.indices_len; i++) { + // cube.indices[i] = i; + // } cube.has_indices = true; @@ -174,4 +177,10 @@ static model_handle prim_cube_new(core* core) { u32 index = (u32)model_darray_len(core->models); model_darray_push_copy(core->models, &model); return (model_handle){ .raw = index }; +} + +// --- Spheres + +geometry_data geo_create_uvsphere(f32 radius, f32 north_south_lines, f32 east_west_lines) { + // TODO } \ No newline at end of file diff --git a/src/renderer/archive/old_backend_vulkan.c b/src/renderer/archive/old_backend_vulkan.c new file mode 100644 index 0000000..a18ca70 --- /dev/null +++ b/src/renderer/archive/old_backend_vulkan.c @@ -0,0 +1,1990 @@ +#include "camera.h" +#include "primitives.h" +#define CDEBUG +#define CEL_REND_BACKEND_VULKAN 1 +#if CEL_REND_BACKEND_VULKAN +// ^ Temporary + +#include +#include +#include +#include +#include +#include +#include +#include "colours.h" +#include "str.h" + +#include "darray.h" +#include "defines.h" +#include "file.h" +#include "log.h" +#include "maths.h" +#include "maths_types.h" +#include "render_backend.h" +#include "render_types.h" +// #include "vulkan_helpers.h" + +#include + +#define SCR_WIDTH 1000 +#define SCR_HEIGHT 1000 + +#include + +#include + +KITC_DECL_TYPED_ARRAY(VkLayerProperties) + +typedef struct vulkan_device { + VkPhysicalDevice physical_device; + VkDevice logical_device; + vulkan_swapchain_support_info swapchain_support; + i32 graphics_queue_index; + i32 present_queue_index; + i32 compute_queue_index; + i32 transfer_queue_index; + VkQueue graphics_queue; + VkQueue present_queue; + VkQueue compute_queue; + VkQueue transfer_queue; + VkCommandPool gfx_command_pool; + VkPhysicalDeviceProperties properties; + VkPhysicalDeviceFeatures features; + VkPhysicalDeviceMemoryProperties memory; + VkFormat depth_format; +} vulkan_device; + +typedef struct vulkan_image { + VkImage handle; + VkDeviceMemory memory; + VkImageView view; + u32 width; + u32 height; +} vulkan_image; + +typedef struct vulkan_texture_data { + vulkan_image image; + VkSampler sampler; +} vulkan_texture_data; + +typedef enum vulkan_renderpass_state { + READY, + RECORDING, + IN_RENDER_PASS, + RECORDING_ENDING, + SUBMITTED, + NOT_ALLOCATED +} vulkan_renderpass_state; + +typedef struct vulkan_renderpass { + VkRenderPass handle; + vec4 render_area; + vec4 clear_colour; + f32 depth; + u32 stencil; + vulkan_renderpass_state state; +} vulkan_renderpass; + +typedef struct vulkan_framebuffer { + VkFramebuffer handle; + u32 attachment_count; + VkImageView* attachments; + vulkan_renderpass* renderpass; +} vulkan_framebuffer; + +KITC_DECL_TYPED_ARRAY(vulkan_framebuffer) + +typedef struct vulkan_swapchain { + VkSurfaceFormatKHR image_format; + u8 max_frames_in_flight; + VkSwapchainKHR handle; + u32 image_count; + VkImage* images; + VkImageView* views; + vulkan_image depth_attachment; + vulkan_framebuffer_darray* framebuffers; +} vulkan_swapchain; + +// overengineered +typedef enum vulkan_command_buffer_state { + COMMAND_BUFFER_STATE_READY, + COMMAND_BUFFER_STATE_IN_RENDER_PASS, + COMMAND_BUFFER_STATE_RECORDING, + COMMAND_BUFFER_STATE_RECORDING_ENDED, + COMMAND_BUFFER_STATE_SUBMITTED, + COMMAND_BUFFER_STATE_NOT_ALLOCATED, +} vulkan_command_buffer_state; + +typedef struct vulkan_command_buffer { + VkCommandBuffer handle; + vulkan_command_buffer_state state; +} vulkan_command_buffer; + +KITC_DECL_TYPED_ARRAY(vulkan_command_buffer) + +typedef struct vulkan_fence { + VkFence handle; + bool is_signaled; +} vulkan_fence; + +typedef struct vulkan_shader_stage { + VkShaderModuleCreateInfo create_info; + VkShaderModule handle; + VkPipelineShaderStageCreateInfo stage_create_info; +} vulkan_shader_stage; + +typedef struct vulkan_pipeline { + VkPipeline handle; + VkPipelineLayout layout; +} vulkan_pipeline; + +typedef struct global_object_uniform { + mat4 projection; // 64 bytes + mat4 view; // 64 bytes + f32 padding[32]; +} global_object_uniform; + +typedef struct object_uniform { + vec4 diffuse_colour; + vec4 v_reserved0; + vec4 v_reserved1; + vec4 v_reserved2; +} object_uniform; + +#define MAX_OBJECT_COUNT 1024 +#define VULKAN_OBJECT_SHADER_DESCRIPTOR_COUNT 1 + +typedef struct geometry_render_data { + u32 id; + mat4 model; + texture* textures[16]; +} geometry_render_data; + +typedef struct vulkan_buffer { + u64 total_size; + VkBuffer handle; + VkBufferUsageFlagBits usage; + bool is_locked; + VkDeviceMemory memory; + i32 memory_index; + u32 memory_property_flags; +} vulkan_buffer; + +#define SHADER_STAGE_COUNT 2 + +typedef struct vulkan_shader { + // vertex, fragment + vulkan_shader_stage stages[SHADER_STAGE_COUNT]; + vulkan_pipeline pipeline; + + // descriptors + VkDescriptorPool descriptor_pool; + VkDescriptorSetLayout descriptor_set_layout; + VkDescriptorSet descriptor_sets[3]; // one for each in-flight frame + + vulkan_buffer global_uniforms_buffer; + + // Data that's global for all objects drawn + global_object_uniform global_ubo; + object_uniform object_ubo; + vulkan_texture_data* texture_data; +} vulkan_shader; + +typedef struct vulkan_context { + VkInstance instance; + VkAllocationCallbacks* allocator; + VkSurfaceKHR surface; + vulkan_device device; + u32 framebuffer_width; + u32 framebuffer_height; + vulkan_swapchain swapchain; + vulkan_renderpass main_renderpass; + vulkan_buffer object_vertex_buffer; + vulkan_buffer object_index_buffer; + u64 geometry_vertex_offset; + u64 geometry_index_offset; + + vulkan_command_buffer_darray* gfx_command_buffers; + + VkSemaphore* image_available_semaphores; + VkSemaphore* queue_complete_semaphores; + u32 in_flight_fence_count; + vulkan_fence* in_flight_fences; + vulkan_fence** images_in_flight; + + u32 image_index; + u32 current_frame; + + vulkan_shader object_shader; + + // TODO: swapchain recreation + +#if defined(DEBUG) + VkDebugUtilsMessengerEXT vk_debugger; +#endif +} vulkan_context; + +static vulkan_context context; + +static i32 find_memory_index(vulkan_context* context, 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; +} + +/** @brief Internal backend state */ +typedef struct vulkan_state { +} vulkan_state; + +typedef struct vertex_pos { + vec3 pos; + vec3 normal; +} vertex_pos; + +// pipeline stuff +bool vulkan_graphics_pipeline_create(vulkan_context* context, vulkan_renderpass* renderpass, + u32 attribute_count, + VkVertexInputAttributeDescription* attributes, + u32 descriptor_set_layout_count, + VkDescriptorSetLayout* descriptor_set_layouts, u32 stage_count, + VkPipelineShaderStageCreateInfo* stages, VkViewport viewport, + VkRect2D scissor, bool is_wireframe, + vulkan_pipeline* out_pipeline) { + 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; + + // 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 = is_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 = VK_TRUE; + depth_stencil.depthWriteEnable = VK_TRUE; + depth_stencil.depthCompareOp = VK_COMPARE_OP_LESS; + depth_stencil.depthBoundsTestEnable = VK_FALSE; + depth_stencil.stencilTestEnable = VK_FALSE; + depth_stencil.pNext = 0; + + 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; + + const u32 dynamic_state_count = 3; + VkDynamicState dynamic_states[3] = { + VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_SCISSOR, + VK_DYNAMIC_STATE_LINE_WIDTH, + }; + + VkPipelineDynamicStateCreateInfo dynamic_state = { + VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO + }; + dynamic_state.dynamicStateCount = dynamic_state_count; + dynamic_state.pDynamicStates = dynamic_states; + + // Vertex input + VkVertexInputBindingDescription binding_desc; + binding_desc.binding = 0; + binding_desc.stride = sizeof(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 = 1; + vertex_input_info.pVertexBindingDescriptions = &binding_desc; + vertex_input_info.vertexAttributeDescriptionCount = attribute_count; + vertex_input_info.pVertexAttributeDescriptions = attributes; + + 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; + + VkPipelineLayoutCreateInfo pipeline_layout_create_info = { + VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO + }; + + // Pushconstants + VkPushConstantRange push_constant; + push_constant.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; + push_constant.offset = sizeof(mat4) * 0; + push_constant.size = sizeof(mat4) * 2; + + pipeline_layout_create_info.pushConstantRangeCount = 1; + pipeline_layout_create_info.pPushConstantRanges = &push_constant; + + pipeline_layout_create_info.setLayoutCount = descriptor_set_layout_count; + pipeline_layout_create_info.pSetLayouts = descriptor_set_layouts; + + vkCreatePipelineLayout(context->device.logical_device, &pipeline_layout_create_info, + context->allocator, &out_pipeline->layout); + + 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, &out_pipeline->handle); + if (result != VK_SUCCESS) { + FATAL("graphics pipeline creation failed. its fked mate"); + ERROR_EXIT("Doomed"); + } + + return true; +} + +void vulkan_pipeline_bind(vulkan_command_buffer* command_buffer, VkPipelineBindPoint bind_point, + vulkan_pipeline* pipeline) { + vkCmdBindPipeline(command_buffer->handle, bind_point, pipeline->handle); +} + +void vulkan_buffer_bind(vulkan_context* context, vulkan_buffer* buffer, u64 offset) { + vkBindBufferMemory(context->device.logical_device, buffer->handle, buffer->memory, offset); +} + +bool vulkan_buffer_create(vulkan_context* context, u64 size, VkBufferUsageFlagBits usage, + u32 memory_property_flags, bool bind_on_create, + vulkan_buffer* out_buffer) { + memset(out_buffer, 0, sizeof(vulkan_buffer)); + out_buffer->total_size = size; + out_buffer->usage = usage; + out_buffer->memory_property_flags = memory_property_flags; + + VkBufferCreateInfo buffer_info = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; + buffer_info.size = size; + buffer_info.usage = usage; + buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + + vkCreateBuffer(context->device.logical_device, &buffer_info, context->allocator, + &out_buffer->handle); + + VkMemoryRequirements requirements; + vkGetBufferMemoryRequirements(context->device.logical_device, out_buffer->handle, &requirements); + out_buffer->memory_index = + find_memory_index(context, requirements.memoryTypeBits, out_buffer->memory_property_flags); + + // Allocate + VkMemoryAllocateInfo allocate_info = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO }; + allocate_info.allocationSize = requirements.size; + allocate_info.memoryTypeIndex = (u32)out_buffer->memory_index; + + vkAllocateMemory(context->device.logical_device, &allocate_info, context->allocator, + &out_buffer->memory); + + if (bind_on_create) { + vulkan_buffer_bind(context, out_buffer, 0); + } + + DEBUG("Created buffer."); + + return true; +} + +// lock and unlock? + +void* vulkan_buffer_lock_memory(vulkan_context* context, vulkan_buffer* buffer, u64 offset, + u64 size, u32 flags) { + void* data; + vkMapMemory(context->device.logical_device, buffer->memory, offset, size, flags, &data); + return data; +} +void* vulkan_buffer_unlock_memory(vulkan_context* context, vulkan_buffer* buffer) { + vkUnmapMemory(context->device.logical_device, buffer->memory); +} + +void vulkan_buffer_load_data(vulkan_context* context, vulkan_buffer* buffer, u64 offset, u64 size, + u32 flags, const void* data) { + void* data_ptr = 0; + VK_CHECK( + vkMapMemory(context->device.logical_device, buffer->memory, offset, size, flags, &data_ptr)); + memcpy(data_ptr, data, size); + vkUnmapMemory(context->device.logical_device, buffer->memory); +} + +// TODO: destroy + +bool create_shader_module(vulkan_context* context, const char* filename, const char* type_str, + VkShaderStageFlagBits flag, u32 stage_index, + vulkan_shader_stage* shader_stages) { + memset(&shader_stages[stage_index].create_info, 0, sizeof(VkShaderModuleCreateInfo)); + memset(&shader_stages[stage_index].stage_create_info, 0, sizeof(VkPipelineShaderStageCreateInfo)); + + shader_stages[stage_index].create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; + + // todo: file input + FileData file_contents = load_spv_file(filename); + + shader_stages[stage_index].create_info.codeSize = file_contents.size; + shader_stages[stage_index].create_info.pCode = (u32*)file_contents.data; + + vkCreateShaderModule(context->device.logical_device, &shader_stages[stage_index].create_info, + context->allocator, &shader_stages[stage_index].handle); + + shader_stages[stage_index].stage_create_info.sType = + VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + shader_stages[stage_index].stage_create_info.stage = flag; + shader_stages[stage_index].stage_create_info.module = shader_stages[stage_index].handle; + shader_stages[stage_index].stage_create_info.pName = "main"; + + free(file_contents.data); + + // TODO: Descriptors + + return true; +} + +bool vulkan_object_shader_create(vulkan_context* context, vulkan_shader* out_shader) { + char stage_type_strs[SHADER_STAGE_COUNT][5] = { "vert", "frag" }; + char stage_filenames[SHADER_STAGE_COUNT][256] = { "build/linux/x86_64/debug/object.vert.spv", + "build/linux/x86_64/debug/object.frag.spv" }; + VkShaderStageFlagBits stage_types[SHADER_STAGE_COUNT] = { VK_SHADER_STAGE_VERTEX_BIT, + VK_SHADER_STAGE_FRAGMENT_BIT }; + for (u8 i = 0; i < SHADER_STAGE_COUNT; i++) { + DEBUG("Loading %s", stage_filenames[i]); + create_shader_module(context, stage_filenames[i], stage_type_strs[i], stage_types[i], i, + out_shader->stages); + } + + // descriptors + VkDescriptorSetLayoutBinding global_ubo_layout_binding; + global_ubo_layout_binding.binding = 0; + global_ubo_layout_binding.descriptorCount = 1; + global_ubo_layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + global_ubo_layout_binding.pImmutableSamplers = 0; + global_ubo_layout_binding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; + + VkDescriptorSetLayoutBinding sampler_layout_binding; + sampler_layout_binding.binding = 1; + sampler_layout_binding.descriptorCount = 1; + sampler_layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + sampler_layout_binding.pImmutableSamplers = 0; + sampler_layout_binding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + + VkDescriptorSetLayoutCreateInfo global_layout_info = { + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO + }; + + VkDescriptorSetLayoutBinding bindings[2] = { global_ubo_layout_binding, sampler_layout_binding }; + + global_layout_info.bindingCount = 2; + global_layout_info.pBindings = bindings; + + VK_CHECK(vkCreateDescriptorSetLayout(context->device.logical_device, &global_layout_info, + context->allocator, &out_shader->descriptor_set_layout)); + + VkDescriptorPoolSize global_pool_size; + global_pool_size.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + global_pool_size.descriptorCount = 3; + + VkDescriptorPoolSize sampler_pool_size; + sampler_pool_size.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + sampler_pool_size.descriptorCount = 3; + + VkDescriptorPoolSize pool_sizes[2] = { global_pool_size, sampler_pool_size }; + + VkDescriptorPoolCreateInfo pool_info = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO }; + pool_info.poolSizeCount = 2; + pool_info.pPoolSizes = pool_sizes; + pool_info.maxSets = 3; + + VK_CHECK(vkCreateDescriptorPool(context->device.logical_device, &pool_info, context->allocator, + &out_shader->descriptor_pool)); + + // Pipeline creation + VkViewport viewport; + viewport.x = 0; + viewport.y = 0; + viewport.width = (f32)context->framebuffer_width; + viewport.height = (f32)context->framebuffer_height; + viewport.minDepth = 0.0; + viewport.maxDepth = 1.0; + + VkRect2D scissor; + scissor.offset.x = scissor.offset.y = 0; + scissor.extent.width = context->framebuffer_width; + scissor.extent.height = context->framebuffer_height; + + // Attributes + u32 offset = 0; + const i32 attribute_count = 3; + VkVertexInputAttributeDescription attribute_descs[3]; + // Position + VkFormat formats[3] = { VK_FORMAT_R32G32B32_SFLOAT, VK_FORMAT_R32G32B32_SFLOAT, + VK_FORMAT_R32G32_SFLOAT }; + + u64 sizes[3] = { sizeof(vec3), sizeof(vec3), sizeof(vec2) }; + + for (u32 i = 0; i < attribute_count; i++) { + attribute_descs[i].binding = 0; + attribute_descs[i].location = i; + attribute_descs[i].format = formats[i]; + attribute_descs[i].offset = offset; + offset += sizes[i]; + } + + // Descriptor set layouts + VkDescriptorSetLayout layouts[1] = { out_shader->descriptor_set_layout }; + + // Stages + VkPipelineShaderStageCreateInfo stage_create_infos[SHADER_STAGE_COUNT]; + memset(stage_create_infos, 0, sizeof(stage_create_infos)); + for (u32 i = 0; i < SHADER_STAGE_COUNT; i++) { + stage_create_infos[i].sType = out_shader->stages[i].stage_create_info.sType; + stage_create_infos[i] = out_shader->stages[i].stage_create_info; + } + + vulkan_graphics_pipeline_create( + context, &context->main_renderpass, attribute_count, attribute_descs, 1, layouts, + SHADER_STAGE_COUNT, stage_create_infos, viewport, scissor, false, &out_shader->pipeline); + INFO("Graphics pipeline created!"); + + // Uniform buffer + if (!vulkan_buffer_create(context, sizeof(global_object_uniform), + VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | + VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, + true, &out_shader->global_uniforms_buffer)) { + ERROR("Couldnt create uniforms buffer"); + return false; + } + + VkDescriptorSetLayout global_layouts[3] = { + out_shader->descriptor_set_layout, + out_shader->descriptor_set_layout, + out_shader->descriptor_set_layout, + }; + + VkDescriptorSetAllocateInfo alloc_info = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO }; + alloc_info.descriptorPool = out_shader->descriptor_pool; + alloc_info.descriptorSetCount = 3; + alloc_info.pSetLayouts = global_layouts; + VK_CHECK(vkAllocateDescriptorSets(context->device.logical_device, &alloc_info, + out_shader->descriptor_sets)); + + return true; +} +void vulkan_object_shader_destroy(vulkan_context* context, vulkan_shader* shader) {} +void vulkan_object_shader_use(vulkan_context* context, vulkan_shader* shader) { + u32 image_index = context->image_index; + vulkan_pipeline_bind(&context->gfx_command_buffers->data[image_index], + VK_PIPELINE_BIND_POINT_GRAPHICS, &shader->pipeline); +} +void vulkan_object_shader_update_global_state(vulkan_context* context, vulkan_shader* shader) { + u32 image_index = context->image_index; + VkCommandBuffer cmd_buffer = context->gfx_command_buffers->data[image_index].handle; + VkDescriptorSet global_descriptors = shader->descriptor_sets[image_index]; + + u32 range = sizeof(global_object_uniform); + u64 offset = 0; + + // copy data to buffer + vulkan_buffer_load_data(context, &shader->global_uniforms_buffer, offset, range, 0, + &shader->global_ubo); + + VkDescriptorBufferInfo buffer_info; + buffer_info.buffer = shader->global_uniforms_buffer.handle; + buffer_info.offset = offset; + buffer_info.range = range; + + VkDescriptorImageInfo image_info; + image_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + image_info.imageView = shader->texture_data->image.view; + image_info.sampler = shader->texture_data->sampler; + + VkWriteDescriptorSet uniform_write = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET }; + uniform_write.dstSet = shader->descriptor_sets[image_index]; + uniform_write.dstBinding = 0; + uniform_write.dstArrayElement = 0; + uniform_write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + uniform_write.descriptorCount = 1; + uniform_write.pBufferInfo = &buffer_info; + + VkWriteDescriptorSet texture_write = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET }; + texture_write.dstSet = shader->descriptor_sets[image_index]; + texture_write.dstBinding = 1; + texture_write.dstArrayElement = 0; + texture_write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + texture_write.descriptorCount = 1; + texture_write.pImageInfo = &image_info; + + VkWriteDescriptorSet writes[2] = { uniform_write, texture_write }; + + vkUpdateDescriptorSets(context->device.logical_device, 2, writes, 0, 0); + + vkCmdBindDescriptorSets(cmd_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, shader->pipeline.layout, 0, + 1, &global_descriptors, 0, 0); +} + +void vulkan_object_shader_update_object(vulkan_context* context, vulkan_shader* shader, + mat4 model) { + u32 image_index = context->image_index; + VkCommandBuffer cmd_buffer = context->gfx_command_buffers->data[image_index].handle; + // vulkan_command_buffer* cmd_buffer = &context->gfx_command_buffers->data[context.image_index]; + + vkCmdPushConstants(cmd_buffer, shader->pipeline.layout, VK_SHADER_STAGE_VERTEX_BIT, 0, + sizeof(mat4), &model); + + // vulkan_object_shader_use(context, &context->object_shader); + VkDeviceSize offsets[1] = { 0 }; + vkCmdBindVertexBuffers(cmd_buffer, 0, 1, &context->object_vertex_buffer.handle, + (VkDeviceSize*)offsets); + + vkCmdBindIndexBuffer(cmd_buffer, context->object_index_buffer.handle, 0, VK_INDEX_TYPE_UINT32); + + vkCmdDrawIndexed(cmd_buffer, 36, 1, 0, 0, 0); + // vkCmdDraw(cmd_buffer, 36, 1, 0, 0); +} + +bool select_physical_device(vulkan_context* ctx) { + u32 physical_device_count = 0; + VK_CHECK(vkEnumeratePhysicalDevices(ctx->instance, &physical_device_count, 0)); + if (physical_device_count == 0) { + FATAL("No devices that support vulkan were found"); + return false; + } + TRACE("Number of devices found %d", physical_device_count); + + VkPhysicalDevice physical_devices[physical_device_count]; + VK_CHECK(vkEnumeratePhysicalDevices(ctx->instance, &physical_device_count, physical_devices)); + + for (u32 i = 0; i < physical_device_count; i++) { + VkPhysicalDeviceProperties properties; + vkGetPhysicalDeviceProperties(physical_devices[i], &properties); + + VkPhysicalDeviceFeatures features; + vkGetPhysicalDeviceFeatures(physical_devices[i], &features); + + VkPhysicalDeviceMemoryProperties memory; + vkGetPhysicalDeviceMemoryProperties(physical_devices[i], &memory); + + vulkan_physical_device_requirements requirements = {}; + requirements.graphics = true; + requirements.present = true; + requirements.compute = true; + requirements.transfer = true; + + requirements.sampler_anistropy = true; + requirements.discrete_gpu = true; + requirements.device_ext_names[0] = str8lit(VK_KHR_SWAPCHAIN_EXTENSION_NAME); + requirements.device_ext_name_count = 1; + + vulkan_physical_device_queue_family_info queue_info = {}; + + bool result = physical_device_meets_requirements(physical_devices[i], ctx->surface, &properties, + &features, &requirements, &queue_info, + &ctx->device.swapchain_support); + + if (result) { + INFO("GPU Driver version: %d.%d.%d", VK_VERSION_MAJOR(properties.driverVersion), + VK_VERSION_MINOR(properties.driverVersion), VK_VERSION_PATCH(properties.driverVersion)); + + INFO("Vulkan API version: %d.%d.%d", VK_VERSION_MAJOR(properties.apiVersion), + VK_VERSION_MINOR(properties.apiVersion), VK_VERSION_PATCH(properties.apiVersion)); + + // TODO: print gpu memory information - + // https://youtu.be/6Kj3O2Ov1RU?si=pXfP5NvXXcXjJsrG&t=2439 + + ctx->device.physical_device = physical_devices[i]; + ctx->device.graphics_queue_index = queue_info.graphics_family_index; + ctx->device.present_queue_index = queue_info.present_family_index; + ctx->device.compute_queue_index = queue_info.compute_family_index; + ctx->device.transfer_queue_index = queue_info.transfer_family_index; + ctx->device.properties = properties; + ctx->device.features = features; + ctx->device.memory = memory; + break; + } + } + + if (!ctx->device.physical_device) { + ERROR("No suitable physical devices were found :("); + return false; + } + + INFO("Physical device selected: %s\n", ctx->device.properties.deviceName); + return true; +} + +bool vulkan_device_create(vulkan_context* context) { + // Physical device - NOTE: mutates the context directly + if (!select_physical_device(context)) { + return false; + } + +// Logical device - NOTE: mutates the context directly + +// queues +#define VULKAN_QUEUES_COUNT 2 + const char* queue_names[VULKAN_QUEUES_COUNT] = { + "GRAPHICS", + "TRANSFER", + }; + i32 indices[VULKAN_QUEUES_COUNT] = { + context->device.graphics_queue_index, + context->device.transfer_queue_index, + }; + f32 prio_one = 1.0; + VkDeviceQueueCreateInfo queue_create_info[2]; // HACK: make 2 queues, graphics and transfer + // graphics + queue_create_info[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + queue_create_info[0].queueFamilyIndex = 0; + queue_create_info[0].queueCount = 1; + queue_create_info[0].flags = 0; + queue_create_info[0].pNext = 0; + queue_create_info[0].pQueuePriorities = &prio_one; + // transfer + queue_create_info[1].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + queue_create_info[1].queueFamilyIndex = 1; + queue_create_info[1].queueCount = 1; + queue_create_info[1].flags = 0; + queue_create_info[1].pNext = 0; + queue_create_info[1].pQueuePriorities = &prio_one; + + // for (int i = 0; i < 2; i++) { + // TRACE("Configure %s queue", queue_names[i]); + // queue_create_info[i].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + // queue_create_info[i].queueFamilyIndex = indices[i]; + // queue_create_info[i].queueCount = 1; // make just one of them + // queue_create_info[i].flags = 0; + // queue_create_info[i].pNext = 0; + // f32 priority = 1.0; + // queue_create_info[i].pQueuePriorities = &priority; + // } + + // features + VkPhysicalDeviceFeatures device_features = {}; + device_features.samplerAnisotropy = VK_TRUE; // request anistrophy + + // device itself + VkDeviceCreateInfo device_create_info = { VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO }; + device_create_info.queueCreateInfoCount = VULKAN_QUEUES_COUNT; + device_create_info.pQueueCreateInfos = queue_create_info; + device_create_info.pEnabledFeatures = &device_features; + device_create_info.enabledExtensionCount = 1; + const char* extension_names = VK_KHR_SWAPCHAIN_EXTENSION_NAME; + device_create_info.ppEnabledExtensionNames = &extension_names; + + // deprecated + device_create_info.enabledLayerCount = 0; + device_create_info.ppEnabledLayerNames = 0; + + VkResult result = vkCreateDevice(context->device.physical_device, &device_create_info, + context->allocator, &context->device.logical_device); + if (result != VK_SUCCESS) { + printf("error creating logical device with status %u\n", result); + ERROR_EXIT("Bye bye"); + } + INFO("Logical device created"); + + // get queues + vkGetDeviceQueue(context->device.logical_device, context->device.graphics_queue_index, 0, + &context->device.graphics_queue); + // vkGetDeviceQueue(context->device.logical_device, context->device.present_queue_index, 0, + // &context->device.present_queue); + // vkGetDeviceQueue(context->device.logical_device, context->device.compute_queue_index, 0, + // &context->device.compute_queue); + vkGetDeviceQueue(context->device.logical_device, context->device.transfer_queue_index, 0, + &context->device.transfer_queue); + + // create command pool for graphics queue + VkCommandPoolCreateInfo pool_create_info = { VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO }; + pool_create_info.queueFamilyIndex = context->device.graphics_queue_index; + pool_create_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + vkCreateCommandPool(context->device.logical_device, &pool_create_info, context->allocator, + &context->device.gfx_command_pool); + INFO("Created Command Pool") + + return true; +} +void vulkan_device_destroy(vulkan_context* context) { + context->device.physical_device = 0; // release + // TODO: reset other memory +} + +bool vulkan_device_detect_depth_format(vulkan_device* device) { + const size_t n_candidates = 3; + VkFormat candidates[3] = { VK_FORMAT_D32_SFLOAT, VK_FORMAT_D32_SFLOAT_S8_UINT, + VK_FORMAT_D24_UNORM_S8_UINT }; + u32 flags = VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT; + for (u64 i = 0; i < n_candidates; i++) { + VkFormatProperties properties; + vkGetPhysicalDeviceFormatProperties(device->physical_device, candidates[i], &properties); + + if ((properties.linearTilingFeatures & flags) == flags) { + device->depth_format = candidates[i]; + return true; + } + if ((properties.optimalTilingFeatures & flags) == flags) { + device->depth_format = candidates[i]; + return true; + } + } + return false; +} + +void vulkan_image_view_create(vulkan_context* context, VkFormat format, vulkan_image* image, + VkImageAspectFlags aspect_flags) { + VkImageViewCreateInfo view_create_info = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO }; + view_create_info.image = image->handle; + view_create_info.viewType = VK_IMAGE_VIEW_TYPE_2D; + view_create_info.format = format; + view_create_info.subresourceRange.aspectMask = aspect_flags; + + view_create_info.subresourceRange.baseMipLevel = 0; + view_create_info.subresourceRange.levelCount = 1; + view_create_info.subresourceRange.baseArrayLayer = 0; + view_create_info.subresourceRange.layerCount = 1; + + vkCreateImageView(context->device.logical_device, &view_create_info, context->allocator, + &image->view); +} + +void vulkan_image_transition_layout(vulkan_context* context, vulkan_command_buffer* command_buffer, + vulkan_image* image, VkFormat format, VkImageLayout old_layout, + VkImageLayout new_layout) { + VkImageMemoryBarrier barrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER }; + void vulkan_image_transition_layout( + vulkan_context * context, vulkan_command_buffer * command_buffer, vulkan_image * image, + VkFormat format, VkImageLayout old_layout, VkImageLayout new_layout) { + VkImageMemoryBarrier barrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER }; + barrier.oldLayout = old_layout; + barrier.newLayout = new_layout; + barrier.srcQueueFamilyIndex = context->device.graphics_queue_index; + barrier.dstQueueFamilyIndex = context->device.graphics_queue_index; + barrier.image = image->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; + barrier.dstAccessMask = 0; + + 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(command_buffer->handle, source_stage, dest_stage, 0, 0, 0, 0, 0, 1, + &barrier); + } + + void vulkan_image_copy_from_buffer(vulkan_image * image, VkBuffer buffer, + vulkan_command_buffer * command_buffer) { + 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", image->width, image->height); + region.imageOffset.x = 0; + region.imageOffset.y = 0; + region.imageOffset.z = 0; + region.imageExtent.width = image->width; + region.imageExtent.height = image->height; + region.imageExtent.depth = 1; + + vkCmdCopyBufferToImage(command_buffer->handle, buffer, image->handle, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); + } + + void vulkan_image_create(vulkan_context * context, VkImageType image_type, u32 width, u32 height, + VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, + VkMemoryPropertyFlags memory_flags, bool create_view, + VkImageAspectFlags aspect_flags, vulkan_image* out_image) { + // copy params + out_image->width = width; + out_image->height = height; + + // create info + VkImageCreateInfo image_create_info = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO }; + image_create_info.imageType = image_type; + image_create_info.extent.width = width; + image_create_info.extent.height = height; + image_create_info.extent.depth = 1; + image_create_info.mipLevels = 1; + image_create_info.arrayLayers = 1; + image_create_info.format = format; + image_create_info.tiling = tiling; + image_create_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + image_create_info.usage = usage; + image_create_info.samples = VK_SAMPLE_COUNT_1_BIT; + image_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + + VK_CHECK(vkCreateImage(context->device.logical_device, &image_create_info, context->allocator, + &out_image->handle)); + + VkMemoryRequirements memory_reqs; + vkGetImageMemoryRequirements(context->device.logical_device, out_image->handle, &memory_reqs); + + i32 memory_type = -1; + VkPhysicalDeviceMemoryProperties memory_properties; + vkGetPhysicalDeviceMemoryProperties(context->device.physical_device, &memory_properties); + + for (u32 i = 0; i < memory_properties.memoryTypeCount; i++) { + // typefilter = memoryTypeBits , prop filter = memory_flags + if (memory_reqs.memoryTypeBits & (1 << i) && + (memory_properties.memoryTypes[i].propertyFlags & memory_flags)) { + memory_type = i; + break; + } + } + + if (memory_type < 0) { + ERROR_EXIT("couldnt find a suitable memory type for the image"); + } + + // allocate memory + VkMemoryAllocateInfo memory_allocate_info = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO }; + memory_allocate_info.allocationSize = memory_reqs.size; + memory_allocate_info.memoryTypeIndex = memory_type; + vkAllocateMemory(context->device.logical_device, &memory_allocate_info, context->allocator, + &out_image->memory); + + // bind memory + // TODO: maybe bind context->device.logical_device to device at the top of the functions? + vkBindImageMemory(context->device.logical_device, out_image->handle, out_image->memory, 0); + + if (create_view) { + out_image->view = 0; + vulkan_image_view_create(context, format, out_image, aspect_flags); + } + } + + // TODO: vulkan_image_destroy + + void vulkan_framebuffer_create(vulkan_context * context, vulkan_renderpass * renderpass, + u32 width, u32 height, u32 attachment_count, + VkImageView * attachments, vulkan_framebuffer * out_framebuffer) { + out_framebuffer->attachments = malloc(sizeof(VkImageView) * attachment_count); + for (u32 i = 0; i < attachment_count; i++) { + out_framebuffer->attachments[i] = attachments[i]; + } + out_framebuffer->attachment_count = attachment_count; + out_framebuffer->renderpass = renderpass; + + VkFramebufferCreateInfo framebuffer_create_info = { + VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO + }; // TODO + + framebuffer_create_info.renderPass = renderpass->handle; + framebuffer_create_info.attachmentCount = attachment_count; + framebuffer_create_info.pAttachments = out_framebuffer->attachments; + framebuffer_create_info.width = width; + framebuffer_create_info.height = height; + framebuffer_create_info.layers = 1; + + vkCreateFramebuffer(context->device.logical_device, &framebuffer_create_info, + context->allocator, &out_framebuffer->handle); + } + + // TODO: vulkan_framebuffer_destroy + + void vulkan_command_buffer_allocate(vulkan_context * context, VkCommandPool pool, bool is_primary, + vulkan_command_buffer* out_command_buffer) { + VkCommandBufferAllocateInfo allocate_info = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO }; + allocate_info.commandPool = pool; + allocate_info.level = + is_primary ? VK_COMMAND_BUFFER_LEVEL_PRIMARY : VK_COMMAND_BUFFER_LEVEL_SECONDARY; + allocate_info.commandBufferCount = 1; + allocate_info.pNext = 0; + + out_command_buffer->state = COMMAND_BUFFER_STATE_NOT_ALLOCATED; + vkAllocateCommandBuffers(context->device.logical_device, &allocate_info, + &out_command_buffer->handle); + out_command_buffer->state = COMMAND_BUFFER_STATE_READY; + } + + void vulkan_command_buffer_free(vulkan_context * context, VkCommandPool pool, + vulkan_command_buffer * out_command_buffer) { + // TODO: implement freeing + } + + void vulkan_command_buffer_begin(vulkan_command_buffer * command_buffer, bool is_single_use, + bool is_renderpass_continue, bool is_simultaneous_use) { + VkCommandBufferBeginInfo begin_info = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO }; + begin_info.flags = 0; + if (is_single_use) { + begin_info.flags |= VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + } + // TODO: RENDER_PASS_CONTINUE_BIT & SIMULTANEOUS_USE_BIT + + begin_info.pNext = 0; + begin_info.pInheritanceInfo = 0; + vkBeginCommandBuffer(command_buffer->handle, &begin_info); + + command_buffer->state = COMMAND_BUFFER_STATE_RECORDING; + } + + void vulkan_command_buffer_end(vulkan_command_buffer * command_buffer) { + VK_CHECK(vkEndCommandBuffer(command_buffer->handle)); + command_buffer->state = COMMAND_BUFFER_STATE_RECORDING_ENDED; + } + void vulkan_command_buffer_update_submitted(vulkan_command_buffer * command_buffer) { + command_buffer->state = COMMAND_BUFFER_STATE_SUBMITTED; + } + void vulkan_command_buffer_reset(vulkan_command_buffer * command_buffer) { + command_buffer->state = COMMAND_BUFFER_STATE_READY; + } + + void vulkan_command_buffer_allocate_and_begin_oneshot( + vulkan_context * context, VkCommandPool pool, vulkan_command_buffer * out_command_buffer) { + vulkan_command_buffer_allocate(context, pool, true, out_command_buffer); + vulkan_command_buffer_begin(out_command_buffer, true, false, false); + } + + void vulkan_command_buffer_end_oneshot(vulkan_context * context, VkCommandPool pool, + vulkan_command_buffer * command_buffer, VkQueue queue) { + vulkan_command_buffer_end(command_buffer); + + // submit to queue + VkSubmitInfo submit_info = { VK_STRUCTURE_TYPE_SUBMIT_INFO }; + submit_info.commandBufferCount = 1; + submit_info.pCommandBuffers = &command_buffer->handle; + VK_CHECK(vkQueueSubmit(queue, 1, &submit_info, 0)); + // wait for it to finish + VK_CHECK(vkQueueWaitIdle(queue)); + + vulkan_command_buffer_free(context, pool, command_buffer); + } + + void vulkan_buffer_copy_to(vulkan_context * context, VkCommandPool pool, VkFence fence, + VkQueue queue, VkBuffer source, u64 source_offset, VkBuffer dest, + u64 dest_offset, u64 size) { + vkQueueWaitIdle(queue); + + vulkan_command_buffer temp_cmd_buf; + vulkan_command_buffer_allocate_and_begin_oneshot(context, pool, &temp_cmd_buf); + + VkBufferCopy copy_region; + copy_region.srcOffset = source_offset; + copy_region.dstOffset = dest_offset; + copy_region.size = size; + + vkCmdCopyBuffer(temp_cmd_buf.handle, source, dest, 1, ©_region); + + vulkan_command_buffer_end_oneshot(context, pool, &temp_cmd_buf, queue); + } + + void vulkan_swapchain_create(vulkan_context * context, u32 width, u32 height, + vulkan_swapchain * out_swapchain) { + VkExtent2D swapchain_extent = { width, height }; + out_swapchain->max_frames_in_flight = 2; // support triple buffering + + // find a format + bool found; + for (u32 i = 0; i < context->device.swapchain_support.format_count; i++) { + VkSurfaceFormatKHR format = context->device.swapchain_support.formats[i]; + if (format.format == VK_FORMAT_B8G8R8A8_UNORM && + format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { + out_swapchain->image_format = format; + found = true; + break; + } + } + if (!found) { + out_swapchain->image_format = context->device.swapchain_support.formats[0]; + } + + VkPresentModeKHR present_mode = VK_PRESENT_MODE_FIFO_KHR; // guaranteed to be implemented + // TODO: look for mailbox - https://youtu.be/jWKVb_QdSNM?si=bHcd3sEf-M0x3QwH&t=1687 + + // TODO: requery swapchain support + + u32 image_count = context->device.swapchain_support.capabilities.minImageCount; + + VkSwapchainCreateInfoKHR swapchain_create_info = { + VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR + }; + swapchain_create_info.surface = context->surface; + swapchain_create_info.minImageCount = image_count; + swapchain_create_info.imageFormat = out_swapchain->image_format.format; + swapchain_create_info.imageColorSpace = out_swapchain->image_format.colorSpace; + DEBUG("Image extent %d %d\n", swapchain_extent.width, swapchain_extent.height); + swapchain_create_info.imageExtent = swapchain_extent; + swapchain_create_info.imageArrayLayers = 1; + swapchain_create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + swapchain_create_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; + swapchain_create_info.queueFamilyIndexCount = 0; + swapchain_create_info.pQueueFamilyIndices = 0; + + swapchain_create_info.preTransform = + context->device.swapchain_support.capabilities.currentTransform; + swapchain_create_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; + swapchain_create_info.presentMode = present_mode; + swapchain_create_info.clipped = VK_TRUE; + swapchain_create_info.oldSwapchain = 0; + + TRACE("Create swapchain"); + VK_CHECK(vkCreateSwapchainKHR(context->device.logical_device, &swapchain_create_info, + context->allocator, &out_swapchain->handle)); + + context->current_frame = 0; + + // images + out_swapchain->image_count = 0; + vkGetSwapchainImagesKHR(context->device.logical_device, out_swapchain->handle, + &out_swapchain->image_count, 0); + + if (!out_swapchain->images) { + out_swapchain->images = (VkImage*)malloc(sizeof(VkImage) * out_swapchain->image_count); + } + if (!out_swapchain->views) { + out_swapchain->views = (VkImageView*)malloc(sizeof(VkImage) * out_swapchain->image_count); + } + VK_CHECK(vkGetSwapchainImagesKHR(context->device.logical_device, out_swapchain->handle, + &out_swapchain->image_count, out_swapchain->images)); + + // views + for (int i = 0; i < out_swapchain->image_count; i++) { + VkImageViewCreateInfo view_info = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO }; + view_info.image = out_swapchain->images[i]; + view_info.viewType = VK_IMAGE_VIEW_TYPE_2D; + view_info.format = out_swapchain->image_format.format; + view_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + view_info.subresourceRange.baseMipLevel = 0; + view_info.subresourceRange.levelCount = 1; + view_info.subresourceRange.baseArrayLayer = 0; + view_info.subresourceRange.layerCount = 1; + + VK_CHECK(vkCreateImageView(context->device.logical_device, &view_info, context->allocator, + &out_swapchain->views[i])); + } + + // depth attachment + if (!vulkan_device_detect_depth_format(&context->device)) { + ERROR_EXIT("Failed to find a supported depth format"); + } + vulkan_image_create(context, VK_IMAGE_TYPE_2D, swapchain_extent.width, swapchain_extent.height, + context->device.depth_format, VK_IMAGE_TILING_OPTIMAL, + VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, true, VK_IMAGE_ASPECT_DEPTH_BIT, + &out_swapchain->depth_attachment); + INFO("Depth attachment created"); + + INFO("Swapchain created successfully"); + } + + // TODO: swapchain destroy + void vulkan_swapchain_recreate(vulkan_context * context, u32 width, u32 height, + vulkan_swapchain * swapchain) { + // TODO + } + bool vulkan_swapchain_acquire_next_image_index( + vulkan_context * context, vulkan_swapchain * swapchain, u64 timeout_ns, + VkSemaphore image_available_semaphore, VkFence fence, u32 * out_image_index) { + VkResult result = + vkAcquireNextImageKHR(context->device.logical_device, swapchain->handle, timeout_ns, + image_available_semaphore, fence, out_image_index); + + if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) { + FATAL("Failed to acquire swapchain image"); + return false; + } + + return true; + } + + void vulkan_swapchain_present(vulkan_context * context, vulkan_swapchain * swapchain, + VkQueue graphics_queue, VkQueue present_queue, + VkSemaphore render_complete_semaphore, u32 present_image_index) { + // return image to swapchain for presentation + VkPresentInfoKHR present_info = { VK_STRUCTURE_TYPE_PRESENT_INFO_KHR }; + present_info.waitSemaphoreCount = 1; + present_info.pWaitSemaphores = &render_complete_semaphore; + present_info.swapchainCount = 1; + present_info.pSwapchains = &swapchain->handle; + present_info.pImageIndices = &present_image_index; + present_info.pResults = 0; + + VkResult result = vkQueuePresentKHR(present_queue, &present_info); + if (result != VK_SUCCESS) { + if (result == VK_SUBOPTIMAL_KHR) { + // WARN("Swapchain suboptimal - maybe resize needed?"); + } else { + FATAL("Failed to present swapchain iamge"); + } + } + + // advance the current frame + context->current_frame = (context->current_frame + 1) % swapchain->max_frames_in_flight; + } + + void vulkan_renderpass_create(vulkan_context * context, vulkan_renderpass * out_renderpass, + vec4 render_area, vec4 clear_colour, f32 depth, u32 stencil) { + out_renderpass->render_area = render_area; + out_renderpass->clear_colour = clear_colour; + out_renderpass->depth = depth; + out_renderpass->stencil = stencil; + + // main subpass + VkSubpassDescription subpass = {}; + subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + + // attachments + u32 attachment_desc_count = 2; + VkAttachmentDescription attachment_descriptions[2]; + + // 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; + + // Depth attachment + VkAttachmentDescription depth_attachment; + depth_attachment.format = context->device.depth_format; + depth_attachment.samples = VK_SAMPLE_COUNT_1_BIT; + depth_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + depth_attachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + depth_attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + depth_attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + depth_attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + depth_attachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + depth_attachment.flags = 0; + + attachment_descriptions[1] = depth_attachment; + + VkAttachmentReference depth_attachment_reference; + depth_attachment_reference.attachment = 1; + depth_attachment_reference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + + subpass.pDepthStencilAttachment = &depth_attachment_reference; + + // TODO: other attachment styles + + subpass.inputAttachmentCount = 0; + subpass.pInputAttachments = 0; + subpass.pResolveAttachments = 0; + subpass.preserveAttachmentCount = 0; + subpass.preserveAttachmentCount = 0; + + // 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; + + VkRenderPassCreateInfo render_pass_create_info = { VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO }; + render_pass_create_info.attachmentCount = attachment_desc_count; + render_pass_create_info.pAttachments = attachment_descriptions; + 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.pNext = 0; + render_pass_create_info.flags = 0; + + VK_CHECK(vkCreateRenderPass(context->device.logical_device, &render_pass_create_info, + context->allocator, &out_renderpass->handle)); + } + + // TODO: renderpass destroy + + void vulkan_renderpass_begin(vulkan_command_buffer * command_buffer, + vulkan_renderpass * renderpass, VkFramebuffer framebuffer) { + VkRenderPassBeginInfo begin_info = { VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO }; + begin_info.renderPass = renderpass->handle; + begin_info.framebuffer = framebuffer; + begin_info.renderArea.offset.x = renderpass->render_area.x; + begin_info.renderArea.offset.y = renderpass->render_area.y; + begin_info.renderArea.extent.width = renderpass->render_area.z; + begin_info.renderArea.extent.height = renderpass->render_area.w; + + VkClearValue clear_values[2]; + memset(&clear_values, 0, sizeof(VkClearValue) * 2); + clear_values[0].color.float32[0] = renderpass->clear_colour.x; + clear_values[0].color.float32[1] = renderpass->clear_colour.y; + clear_values[0].color.float32[2] = renderpass->clear_colour.z; + clear_values[0].color.float32[3] = renderpass->clear_colour.w; + clear_values[1].depthStencil.depth = renderpass->depth; + clear_values[1].depthStencil.stencil = renderpass->stencil; + + begin_info.clearValueCount = 2; + begin_info.pClearValues = clear_values; + + vkCmdBeginRenderPass(command_buffer->handle, &begin_info, VK_SUBPASS_CONTENTS_INLINE); + command_buffer->state = COMMAND_BUFFER_STATE_IN_RENDER_PASS; + } + + void vulkan_renderpass_end(vulkan_command_buffer * command_buffer, + vulkan_renderpass * renderpass) { + vkCmdEndRenderPass(command_buffer->handle); + command_buffer->state = COMMAND_BUFFER_STATE_RECORDING; + } + + bool create_buffers(vulkan_context * context) { + VkMemoryPropertyFlagBits mem_prop_flags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + + const u64 vertex_buffer_size = sizeof(vertex_pos) * 1024 * 1024; + if (!vulkan_buffer_create(context, vertex_buffer_size, + VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | + VK_BUFFER_USAGE_TRANSFER_DST_BIT, + mem_prop_flags, true, &context->object_vertex_buffer)) { + ERROR("couldnt create vertex buffer"); + return false; + } + + context->geometry_vertex_offset = 0; + + const u64 index1_buffer_size = sizeof(u32) * 1024 * 1024; + if (!vulkan_buffer_create(context, index1_buffer_size, + VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | + VK_BUFFER_USAGE_TRANSFER_DST_BIT, + mem_prop_flags, true, &context->object_index_buffer)) { + ERROR("couldnt create vertex buffer"); + return false; + } + context->geometry_index_offset = 0; + + return true; + } + + void create_command_buffers(renderer * ren) { + if (!context.gfx_command_buffers) { + context.gfx_command_buffers = vulkan_command_buffer_darray_new(context.swapchain.image_count); + } + + for (u32 i = 0; i < context.swapchain.image_count; i++) { + vulkan_command_buffer_allocate(&context, context.device.gfx_command_pool, true, + &context.gfx_command_buffers->data[i]); + } + } + + void upload_data_range(vulkan_context * context, VkCommandPool pool, VkFence fence, VkQueue queue, + vulkan_buffer * buffer, u64 offset, u64 size, void* data) { + VkBufferUsageFlags flags = + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; + vulkan_buffer staging; + vulkan_buffer_create(context, size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, flags, true, &staging); + // load data into staging buffer + printf("Size: %ld\n", size); + vulkan_buffer_load_data(context, &staging, 0, size, 0, data); + + // copy + vulkan_buffer_copy_to(context, pool, fence, queue, staging.handle, 0, buffer->handle, offset, + size); + + vkDestroyBuffer(context->device.logical_device, staging.handle, context->allocator); + } + + void regenerate_framebuffers(renderer * ren, vulkan_swapchain * swapchain, + vulkan_renderpass * renderpass) { + for (u32 i = 0; i < swapchain->image_count; i++) { + u32 attachment_count = 2; // one for depth, one for colour + + VkImageView attachments[2] = { swapchain->views[i], swapchain->depth_attachment.view }; + + vulkan_framebuffer_create(&context, renderpass, context.framebuffer_width, + context.framebuffer_height, 2, attachments, + &swapchain->framebuffers->data[i]); + } + } + + void vulkan_fence_create(vulkan_context * context, bool create_signaled, + vulkan_fence* out_fence) { + out_fence->is_signaled = create_signaled; + VkFenceCreateInfo fence_create_info = { VK_STRUCTURE_TYPE_FENCE_CREATE_INFO }; + if (out_fence->is_signaled) { + fence_create_info.flags = VK_FENCE_CREATE_SIGNALED_BIT; + } + + vkCreateFence(context->device.logical_device, &fence_create_info, context->allocator, + &out_fence->handle); + } + + // TODO: vulkan_fence_destroy + + bool vulkan_fence_wait(vulkan_context * context, vulkan_fence * fence, u64 timeout_ns) { + if (!fence->is_signaled) { + VkResult result = + vkWaitForFences(context->device.logical_device, 1, &fence->handle, true, timeout_ns); + switch (result) { + case VK_SUCCESS: + fence->is_signaled = true; + return true; + case VK_TIMEOUT: + WARN("vk_fence_wait - Timed out"); + break; + default: + ERROR("vk_fence_wait - Unhanlded error type"); + break; + } + } else { + return true; + } + + return false; + } + void vulkan_fence_reset(vulkan_context * context, vulkan_fence * fence) { + if (fence->is_signaled) { + vkResetFences(context->device.logical_device, 1, &fence->handle); + fence->is_signaled = false; + } + } + + bool gfx_backend_init(renderer * ren) { + INFO("loading Vulkan backend"); + + vulkan_state* internal = malloc(sizeof(vulkan_state)); + ren->backend_state = (void*)internal; + + context.allocator = 0; // TODO: custom allocator + + context.framebuffer_width = SCR_WIDTH; + context.framebuffer_height = SCR_HEIGHT; + + // Setup Vulkan instance + VkApplicationInfo app_info = { VK_STRUCTURE_TYPE_APPLICATION_INFO }; + app_info.apiVersion = VK_API_VERSION_1_3; + app_info.pApplicationName = ren->config.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; + + cstr_darray* required_extensions = cstr_darray_new(2); + cstr_darray_push(required_extensions, VK_KHR_SURFACE_EXTENSION_NAME); + + plat_get_required_extension_names(required_extensions); + +#if defined(CDEBUG) + cstr_darray_push(required_extensions, VK_EXT_DEBUG_UTILS_EXTENSION_NAME); + + DEBUG("Required extensions:"); + for (u32 i = 0; i < cstr_darray_len(required_extensions); i++) { + DEBUG(" %s", required_extensions->data[i]); + } +#endif + + create_info.enabledExtensionCount = cstr_darray_len(required_extensions); + create_info.ppEnabledExtensionNames = required_extensions->data; + + // Validation layers + create_info.enabledLayerCount = 0; + create_info.ppEnabledLayerNames = 0; +#if defined(CDEBUG) + INFO("Validation layers enabled"); + cstr_darray* desired_validation_layers = cstr_darray_new(1); + cstr_darray_push(desired_validation_layers, "VK_LAYER_KHRONOS_validation"); + + u32 n_available_layers = 0; + VK_CHECK(vkEnumerateInstanceLayerProperties(&n_available_layers, 0)); + TRACE("%d available layers", n_available_layers); + VkLayerProperties_darray* available_layers = VkLayerProperties_darray_new(n_available_layers); + VK_CHECK(vkEnumerateInstanceLayerProperties(&n_available_layers, available_layers->data)); + + for (int i = 0; i < cstr_darray_len(desired_validation_layers); i++) { + // look through layers to make sure we can find the ones we want + bool found = false; + for (int j = 0; j < n_available_layers; j++) { + if (str8_equals(str8_cstr_view(desired_validation_layers->data[i]), + str8_cstr_view(available_layers->data[j].layerName))) { + found = true; + TRACE("Found layer %s", desired_validation_layers->data[i]); + break; + } + } + + if (!found) { + FATAL("Required validation is missing %s", desired_validation_layers->data[i]); + return false; + } + } + INFO("All validation layers are present"); + create_info.enabledLayerCount = cstr_darray_len(desired_validation_layers); + create_info.ppEnabledLayerNames = desired_validation_layers->data; +#endif + + VkResult result = vkCreateInstance(&create_info, NULL, &context.instance); + if (result != VK_SUCCESS) { + ERROR("vkCreateInstance failed with result: %u", result); + return false; + } + + // Debugger +#if defined(CDEBUG) + DEBUG("Creating Vulkan debugger") + u32 log_severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT; + VkDebugUtilsMessengerCreateInfoEXT debug_create_info = { + VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT + }; + debug_create_info.messageSeverity = log_severity; + debug_create_info.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT; + debug_create_info.pfnUserCallback = vk_debug_callback; + + PFN_vkCreateDebugUtilsMessengerEXT func = + (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(context.instance, + "vkCreateDebugUtilsMessengerEXT"); + assert(func); + VK_CHECK(func(context.instance, &debug_create_info, context.allocator, &context.vk_debugger)); + DEBUG("Vulkan debugger created"); + +#endif + + // Surface creation + DEBUG("Create SurfaceKHR") + VkSurfaceKHR surface; + VK_CHECK(glfwCreateWindowSurface(context.instance, ren->window, NULL, &surface)); + context.surface = surface; + DEBUG("Vulkan surface created") + + // Device creation + if (!vulkan_device_create(&context)) { + FATAL("device creation failed"); + return false; + } + + // Swapchain creation + vulkan_swapchain_create(&context, SCR_WIDTH, SCR_HEIGHT, &context.swapchain); + + // Renderpass creation + vulkan_renderpass_create(&context, &context.main_renderpass, + vec4(0, 0, context.framebuffer_width, context.framebuffer_height), + rgba_to_vec4(COLOUR_SEA_GREEN), 1.0, 0); + + // Framebiffers creation + context.swapchain.framebuffers = vulkan_framebuffer_darray_new(context.swapchain.image_count); + regenerate_framebuffers(ren, &context.swapchain, &context.main_renderpass); + INFO("Framebuffers created"); + + // Command buffers creation + create_command_buffers(ren); + INFO("Command buffers created"); + + // Sync objects + context.image_available_semaphores = + calloc(context.swapchain.max_frames_in_flight, sizeof(VkSemaphore)); + context.queue_complete_semaphores = + calloc(context.swapchain.max_frames_in_flight, sizeof(VkSemaphore)); + context.in_flight_fences = calloc(context.swapchain.max_frames_in_flight, sizeof(vulkan_fence)); + + for (u8 i = 0; i < context.swapchain.max_frames_in_flight; i++) { + VkSemaphoreCreateInfo semaphore_create_info = { VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO }; + vkCreateSemaphore(context.device.logical_device, &semaphore_create_info, context.allocator, + &context.image_available_semaphores[i]); + vkCreateSemaphore(context.device.logical_device, &semaphore_create_info, context.allocator, + &context.queue_complete_semaphores[i]); + + // create the fence in a signaled state + vulkan_fence_create(&context, true, &context.in_flight_fences[i]); + } + + context.images_in_flight = + malloc(sizeof(vulkan_fence*) * context.swapchain.max_frames_in_flight); + for (u8 i = 0; i < context.swapchain.max_frames_in_flight; i++) { + context.images_in_flight[i] = 0; + } + INFO("Sync objects created"); + + // Shader modules + vulkan_object_shader_create(&context, &context.object_shader); + INFO("Compiled shader modules") + + create_buffers(&context); + INFO("Created buffers"); + + // TODO: temporary test code + + mesh cube = prim_cube_mesh_create(); + + vertex* verts = malloc(sizeof(vertex) * cube.vertices->len); + + f32 scale = 3.0; + for (size_t i = 0; i < cube.vertices->len; i++) { + verts[i].position = vec3_mult(cube.vertices->data[i].position, scale); + verts[i].normal = cube.vertices->data[i].normal; + verts[i].uv = cube.vertices->data[i].uv; + } + + // const f32 s = 1.0; + // const u32 vert_count = 4; + // vertex_pos verts[4] = { 0 }; + + // verts[0].pos.x = -0.5 * s; + // verts[0].pos.y = -0.5 * s; + + // verts[1].pos.x = 0.5 * s; + // verts[1].pos.y = 0.5 * s; + + // verts[2].pos.x = -0.5 * s; + // verts[2].pos.y = 0.5 * s; + + // verts[3].pos.x = 0.5 * s; + // verts[3].pos.y = -0.5 * s; + + // const u32 index_count = 6; + // u32 indices[6] = { 0, 1, 2, 0, 3, 1 }; + + upload_data_range(&context, context.device.gfx_command_pool, 0, context.device.graphics_queue, + &context.object_vertex_buffer, 0, sizeof(vertex) * cube.vertices->len, verts); + TRACE("Uploaded vertex data"); + upload_data_range(&context, context.device.gfx_command_pool, 0, context.device.graphics_queue, + &context.object_index_buffer, 0, sizeof(u32) * cube.indices_len, + cube.indices); + TRACE("Uploaded index data"); + vertex_darray_free(cube.vertices); + free(cube.indices); + + // upload texture + + // --- End test code + + INFO("Vulkan renderer initialisation succeeded"); + return true; + } + + void gfx_backend_shutdown(renderer * ren) { + DEBUG("Destroying Vulkan debugger"); + if (context.vk_debugger) { + PFN_vkDestroyDebugUtilsMessengerEXT func = + (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr( + context.instance, "vkDestroyDebugUtilsMessengerEXT"); + func(context.instance, context.vk_debugger, context.allocator); + } + + DEBUG("Destroying Vulkan instance..."); + vkDestroyInstance(context.instance, context.allocator); + } + + void backend_begin_frame(renderer * ren, f32 delta_time) { + vulkan_device* device = &context.device; + + // TODO: resize gubbins + + if (!vulkan_fence_wait(&context, &context.in_flight_fences[context.current_frame], + UINT64_MAX)) { + WARN("In-flight fence wait failure"); + } + + if (!vulkan_swapchain_acquire_next_image_index( + &context, &context.swapchain, UINT64_MAX, + context.image_available_semaphores[context.current_frame], 0, &context.image_index)) { + WARN("couldnt acquire swapchain next image"); + } + + vulkan_command_buffer* command_buffer = &context.gfx_command_buffers->data[context.image_index]; + vulkan_command_buffer_reset(command_buffer); + vulkan_command_buffer_begin(command_buffer, false, false, false); + + VkViewport viewport; + viewport.x = 0.0; + viewport.y = 0; + viewport.width = (f32)context.framebuffer_width; + viewport.height = (f32)context.framebuffer_height; + viewport.minDepth = 0.0; + viewport.maxDepth = 1.0; + + VkRect2D scissor; + scissor.offset.x = scissor.offset.y = 0; + scissor.extent.width = context.framebuffer_width; + scissor.extent.height = context.framebuffer_height; + + vkCmdSetViewport(command_buffer->handle, 0, 1, &viewport); + vkCmdSetScissor(command_buffer->handle, 0, 1, &scissor); + + context.main_renderpass.render_area.z = context.framebuffer_width; + context.main_renderpass.render_area.w = context.framebuffer_height; + + vulkan_renderpass_begin(command_buffer, &context.main_renderpass, + context.swapchain.framebuffers->data[context.image_index].handle); + } + + void texture_data_upload(texture * tex) { + printf("Texture name %s\n", tex->name); + tex->backend_data = malloc(sizeof(vulkan_texture_data)); + vulkan_texture_data* data = (vulkan_texture_data*)tex->backend_data; + printf("Texture (%s) details: \n width %d\n height %d\n channel count %d\n", tex->name, + tex->width, tex->height, tex->channel_count); + VkDeviceSize image_size = tex->width * tex->height * max(tex->channel_count, 4); + + TRACE("Creating buffer of size %ld", image_size); + + VkFormat image_format = VK_FORMAT_R8G8B8A8_SRGB; + + VkBufferUsageFlags usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + VkMemoryPropertyFlags memory_prop_flags = + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; + vulkan_buffer staging; + vulkan_buffer_create(&context, image_size, usage, memory_prop_flags, true, &staging); + DEBUG("Uploading image data"); + vulkan_buffer_load_data(&context, &staging, 0, image_size, 0, tex->image_data); + INFO("Loaded iamge data!"); + + vulkan_image_create( + &context, VK_IMAGE_TYPE_2D, tex->width, tex->height, image_format, VK_IMAGE_TILING_OPTIMAL, + VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | + VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, true, VK_IMAGE_ASPECT_COLOR_BIT, &data->image); + + vulkan_command_buffer temp_buffer; + vulkan_command_buffer_allocate_and_begin_oneshot(&context, context.device.gfx_command_pool, + &temp_buffer); + + vulkan_image_transition_layout(&context, &temp_buffer, &data->image, image_format, + VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + + vulkan_image_copy_from_buffer(&data->image, staging.handle, &temp_buffer); + + vulkan_image_transition_layout(&context, &temp_buffer, &data->image, image_format, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + + vulkan_command_buffer_end_oneshot(&context, context.device.gfx_command_pool, &temp_buffer, + context.device.graphics_queue); + + VkSamplerCreateInfo sampler_info = { VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO }; + sampler_info.magFilter = VK_FILTER_LINEAR; + sampler_info.minFilter = VK_FILTER_LINEAR; + sampler_info.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; + sampler_info.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT; + sampler_info.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; + sampler_info.anisotropyEnable = VK_TRUE; + sampler_info.maxAnisotropy = 16; + sampler_info.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK; + sampler_info.unnormalizedCoordinates = VK_FALSE; + sampler_info.compareEnable = VK_FALSE; + sampler_info.compareOp = VK_COMPARE_OP_ALWAYS; + sampler_info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; + sampler_info.mipLodBias = 0.0; + sampler_info.minLod = 0.0; + sampler_info.maxLod = 0.0; + + VkResult res = vkCreateSampler(context.device.logical_device, &sampler_info, context.allocator, + &data->sampler); + if (res != VK_SUCCESS) { + ERROR("Error creating texture sampler for image %s", tex->name); + return; + } + + tex->image_data = (void*)data; + } + + // TODO: destroy texture + + void backend_end_frame(renderer * ren, f32 delta_time) { + vulkan_command_buffer* command_buffer = &context.gfx_command_buffers->data[context.image_index]; + + vulkan_renderpass_end(command_buffer, &context.main_renderpass); + + vulkan_command_buffer_end(command_buffer); + + // TODO: wait on fence - https://youtu.be/hRL71D1f3pU?si=nLJx-ZsemDBeQiQ1&t=1037 + + context.images_in_flight[context.image_index] = + &context.in_flight_fences[context.current_frame]; + + vulkan_fence_reset(&context, &context.in_flight_fences[context.current_frame]); + + VkSubmitInfo submit_info = { VK_STRUCTURE_TYPE_SUBMIT_INFO }; + submit_info.commandBufferCount = 1; + submit_info.pCommandBuffers = &command_buffer->handle; + submit_info.signalSemaphoreCount = 1; + submit_info.pSignalSemaphores = &context.queue_complete_semaphores[context.current_frame]; + submit_info.waitSemaphoreCount = 1; + submit_info.pWaitSemaphores = &context.image_available_semaphores[context.current_frame]; + + VkPipelineStageFlags flags[1] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT }; + submit_info.pWaitDstStageMask = flags; + + VkResult result = vkQueueSubmit(context.device.graphics_queue, 1, &submit_info, + context.in_flight_fences[context.current_frame].handle); + + if (result != VK_SUCCESS) { + ERROR("queue submission failed. fark."); + } + + vulkan_command_buffer_update_submitted(command_buffer); + + vulkan_swapchain_present( + &context, &context.swapchain, context.device.graphics_queue, context.device.graphics_queue, + context.queue_complete_semaphores[context.current_frame], context.image_index); + } + + void gfx_backend_draw_frame(renderer * ren, camera * cam, mat4 model, texture * tex) { + backend_begin_frame(ren, 16.0); + + mat4 proj; + mat4 view; + + camera_view_projection(cam, SCR_HEIGHT, SCR_WIDTH, &view, &proj); + + context.object_shader.texture_data = (vulkan_texture_data*)tex->image_data; + gfx_backend_update_global_state(proj, view, cam->position, vec4(1.0, 1.0, 1.0, 1.0), 0); + + vulkan_object_shader_update_object(&context, &context.object_shader, model); + + backend_end_frame(ren, 16.0); + } + + void gfx_backend_update_global_state(mat4 projection, mat4 view, vec3 view_pos, + vec4 ambient_colour, i32 mode) { + vulkan_object_shader_use(&context, &context.object_shader); + + vulkan_object_shader_update_global_state(&context, &context.object_shader); + context.object_shader.global_ubo.projection = projection; + context.object_shader.global_ubo.view = view; + // TODO: other UBO properties + } + + void clear_screen(vec3 colour) {} + + void bind_texture(shader s, texture * tex, u32 slot) {} + void bind_mesh_vertex_buffer(void* backend, mesh* mesh) {} + void draw_primitives(cel_primitive_topology primitive, u32 start_index, u32 count) {} + + shader shader_create_separate(const char* vert_shader, const char* frag_shader) {} + void set_shader(shader s) {} + + void uniform_vec3f(u32 program_id, const char* uniform_name, vec3* value) {} + void uniform_f32(u32 program_id, const char* uniform_name, f32 value) {} + void uniform_i32(u32 program_id, const char* uniform_name, i32 value) {} + void uniform_mat4f(u32 program_id, const char* uniform_name, mat4* value) {} + + VKAPI_ATTR VkBool32 VKAPI_CALL vk_debug_callback( + VkDebugUtilsMessageSeverityFlagBitsEXT severity, VkDebugUtilsMessageTypeFlagsEXT flags, + const VkDebugUtilsMessengerCallbackDataEXT* callback_data, void* user_data) { + switch (severity) { + default: + case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT: + ERROR("%s", callback_data->pMessage); + break; + case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT: + WARN("%s", callback_data->pMessage); + break; + case VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT: + INFO("%s", callback_data->pMessage); + break; + case VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT: + TRACE("%s", callback_data->pMessage); + break; + } + return VK_FALSE; + } + +#endif \ No newline at end of file diff --git a/src/renderer/backends/backend_dx11.h b/src/renderer/backends/backend_dx11.h index 163ca97..e076659 100644 --- a/src/renderer/backends/backend_dx11.h +++ b/src/renderer/backends/backend_dx11.h @@ -1,4 +1,7 @@ #pragma once +#include +#include + #include "ral.h" #define GPU_SWAPCHAIN_IMG_COUNT 2 @@ -6,6 +9,7 @@ typedef struct gpu_swapchain { } gpu_swapchain; typedef struct gpu_device { + // VkPhysicalDevice physical_device; // VkDevice logical_device; // VkPhysicalDeviceProperties properties; diff --git a/src/renderer/backends/backend_vulkan.c b/src/renderer/backends/backend_vulkan.c index 75b0439..b66aeca 100644 --- a/src/renderer/backends/backend_vulkan.c +++ b/src/renderer/backends/backend_vulkan.c @@ -1,841 +1,44 @@ -#include "camera.h" -#include "primitives.h" -#define CDEBUG -// #define CEL_PLATFORM_LINUX -#if CEL_REND_BACKEND_VULKAN -// ^ Temporary - -#include -#include -#include -#include #include #include #include -#include "colours.h" -#include "str.h" -#include "darray.h" +#include "backend_vulkan.h" + #include "defines.h" -#include "file.h" #include "log.h" -#include "maths.h" -#include "maths_types.h" -#include "render_backend.h" -#include "render_types.h" -#include "vulkan_helpers.h" - -#include - -#define SCR_WIDTH 1000 -#define SCR_HEIGHT 1000 - -#include - -#include - -KITC_DECL_TYPED_ARRAY(VkLayerProperties) - -typedef struct vulkan_device { - VkPhysicalDevice physical_device; - VkDevice logical_device; - vulkan_swapchain_support_info swapchain_support; - i32 graphics_queue_index; - i32 present_queue_index; - i32 compute_queue_index; - i32 transfer_queue_index; - VkQueue graphics_queue; - VkQueue present_queue; - VkQueue compute_queue; - VkQueue transfer_queue; - VkCommandPool gfx_command_pool; - VkPhysicalDeviceProperties properties; - VkPhysicalDeviceFeatures features; - VkPhysicalDeviceMemoryProperties memory; - VkFormat depth_format; -} vulkan_device; - -typedef struct vulkan_image { - VkImage handle; - VkDeviceMemory memory; - VkImageView view; - u32 width; - u32 height; -} vulkan_image; - -typedef struct vulkan_texture_data { - vulkan_image image; - VkSampler sampler; -} vulkan_texture_data; - -typedef enum vulkan_renderpass_state { - READY, - RECORDING, - IN_RENDER_PASS, - RECORDING_ENDING, - SUBMITTED, - NOT_ALLOCATED -} vulkan_renderpass_state; - -typedef struct vulkan_renderpass { - VkRenderPass handle; - vec4 render_area; - vec4 clear_colour; - f32 depth; - u32 stencil; - vulkan_renderpass_state state; -} vulkan_renderpass; - -typedef struct vulkan_framebuffer { - VkFramebuffer handle; - u32 attachment_count; - VkImageView* attachments; - vulkan_renderpass* renderpass; -} vulkan_framebuffer; - -KITC_DECL_TYPED_ARRAY(vulkan_framebuffer) - -typedef struct vulkan_swapchain { - VkSurfaceFormatKHR image_format; - u8 max_frames_in_flight; - VkSwapchainKHR handle; - u32 image_count; - VkImage* images; - VkImageView* views; - vulkan_image depth_attachment; - vulkan_framebuffer_darray* framebuffers; -} vulkan_swapchain; - -// overengineered -typedef enum vulkan_command_buffer_state { - COMMAND_BUFFER_STATE_READY, - COMMAND_BUFFER_STATE_IN_RENDER_PASS, - COMMAND_BUFFER_STATE_RECORDING, - COMMAND_BUFFER_STATE_RECORDING_ENDED, - COMMAND_BUFFER_STATE_SUBMITTED, - COMMAND_BUFFER_STATE_NOT_ALLOCATED, -} vulkan_command_buffer_state; - -typedef struct vulkan_command_buffer { - VkCommandBuffer handle; - vulkan_command_buffer_state state; -} vulkan_command_buffer; - -KITC_DECL_TYPED_ARRAY(vulkan_command_buffer) - -typedef struct vulkan_fence { - VkFence handle; - bool is_signaled; -} vulkan_fence; - -typedef struct vulkan_shader_stage { - VkShaderModuleCreateInfo create_info; - VkShaderModule handle; - VkPipelineShaderStageCreateInfo stage_create_info; -} vulkan_shader_stage; - -typedef struct vulkan_pipeline { - VkPipeline handle; - VkPipelineLayout layout; -} vulkan_pipeline; - -typedef struct global_object_uniform { - mat4 projection; // 64 bytes - mat4 view; // 64 bytes - f32 padding[32]; -} global_object_uniform; - -typedef struct object_uniform { - vec4 diffuse_colour; - vec4 v_reserved0; - vec4 v_reserved1; - vec4 v_reserved2; -} object_uniform; - -#define MAX_OBJECT_COUNT 1024 -#define VULKAN_OBJECT_SHADER_DESCRIPTOR_COUNT 1 - -typedef struct geometry_render_data { - u32 id; - mat4 model; - texture* textures[16]; -} geometry_render_data; - -typedef struct vulkan_buffer { - u64 total_size; - VkBuffer handle; - VkBufferUsageFlagBits usage; - bool is_locked; - VkDeviceMemory memory; - i32 memory_index; - u32 memory_property_flags; -} vulkan_buffer; +#include "ral.h" +#include "ral_types.h" -#define SHADER_STAGE_COUNT 2 - -typedef struct vulkan_shader { - // vertex, fragment - vulkan_shader_stage stages[SHADER_STAGE_COUNT]; - vulkan_pipeline pipeline; - - // descriptors - VkDescriptorPool descriptor_pool; - VkDescriptorSetLayout descriptor_set_layout; - VkDescriptorSet descriptor_sets[3]; // one for each in-flight frame - - vulkan_buffer global_uniforms_buffer; - - // Data that's global for all objects drawn - global_object_uniform global_ubo; - object_uniform object_ubo; - vulkan_texture_data* texture_data; -} vulkan_shader; +#define VULKAN_QUEUES_COUNT 2 +const char* queue_names[VULKAN_QUEUES_COUNT] = { "GRAPHICS", "TRANSFER" }; typedef struct vulkan_context { - VkInstance instance; + gpu_device device; VkAllocationCallbacks* allocator; - VkSurfaceKHR surface; - vulkan_device device; - u32 framebuffer_width; - u32 framebuffer_height; - vulkan_swapchain swapchain; - vulkan_renderpass main_renderpass; - vulkan_buffer object_vertex_buffer; - vulkan_buffer object_index_buffer; - u64 geometry_vertex_offset; - u64 geometry_index_offset; - - vulkan_command_buffer_darray* gfx_command_buffers; - VkSemaphore* image_available_semaphores; - VkSemaphore* queue_complete_semaphores; - u32 in_flight_fence_count; - vulkan_fence* in_flight_fences; - vulkan_fence** images_in_flight; - - u32 image_index; - u32 current_frame; - - vulkan_shader object_shader; - - // TODO: swapchain recreation + VkInstance instance; -#if defined(DEBUG) - VkDebugUtilsMessengerEXT vk_debugger; -#endif } vulkan_context; static vulkan_context context; -static i32 find_memory_index(vulkan_context* context, 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; -} - -/** @brief Internal backend state */ -typedef struct vulkan_state { -} vulkan_state; - -typedef struct vertex_pos { - vec3 pos; - vec3 normal; -} vertex_pos; - -// pipeline stuff -bool vulkan_graphics_pipeline_create(vulkan_context* context, vulkan_renderpass* renderpass, - u32 attribute_count, - VkVertexInputAttributeDescription* attributes, - u32 descriptor_set_layout_count, - VkDescriptorSetLayout* descriptor_set_layouts, u32 stage_count, - VkPipelineShaderStageCreateInfo* stages, VkViewport viewport, - VkRect2D scissor, bool is_wireframe, - vulkan_pipeline* out_pipeline) { - 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; - - // 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 = is_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 = VK_TRUE; - depth_stencil.depthWriteEnable = VK_TRUE; - depth_stencil.depthCompareOp = VK_COMPARE_OP_LESS; - depth_stencil.depthBoundsTestEnable = VK_FALSE; - depth_stencil.stencilTestEnable = VK_FALSE; - depth_stencil.pNext = 0; - - 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; - - const u32 dynamic_state_count = 3; - VkDynamicState dynamic_states[3] = { - VK_DYNAMIC_STATE_VIEWPORT, - VK_DYNAMIC_STATE_SCISSOR, - VK_DYNAMIC_STATE_LINE_WIDTH, - }; - - VkPipelineDynamicStateCreateInfo dynamic_state = { - VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO - }; - dynamic_state.dynamicStateCount = dynamic_state_count; - dynamic_state.pDynamicStates = dynamic_states; - - // Vertex input - VkVertexInputBindingDescription binding_desc; - binding_desc.binding = 0; - binding_desc.stride = sizeof(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 = 1; - vertex_input_info.pVertexBindingDescriptions = &binding_desc; - vertex_input_info.vertexAttributeDescriptionCount = attribute_count; - vertex_input_info.pVertexAttributeDescriptions = attributes; - - 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; - - VkPipelineLayoutCreateInfo pipeline_layout_create_info = { - VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO - }; - - // Pushconstants - VkPushConstantRange push_constant; - push_constant.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; - push_constant.offset = sizeof(mat4) * 0; - push_constant.size = sizeof(mat4) * 2; - - pipeline_layout_create_info.pushConstantRangeCount = 1; - pipeline_layout_create_info.pPushConstantRanges = &push_constant; - - pipeline_layout_create_info.setLayoutCount = descriptor_set_layout_count; - pipeline_layout_create_info.pSetLayouts = descriptor_set_layouts; - - vkCreatePipelineLayout(context->device.logical_device, &pipeline_layout_create_info, - context->allocator, &out_pipeline->layout); - - 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, &out_pipeline->handle); - if (result != VK_SUCCESS) { - FATAL("graphics pipeline creation failed. its fked mate"); - ERROR_EXIT("Doomed"); - } - - return true; -} - -void vulkan_pipeline_bind(vulkan_command_buffer* command_buffer, VkPipelineBindPoint bind_point, - vulkan_pipeline* pipeline) { - vkCmdBindPipeline(command_buffer->handle, bind_point, pipeline->handle); -} - -void vulkan_buffer_bind(vulkan_context* context, vulkan_buffer* buffer, u64 offset) { - vkBindBufferMemory(context->device.logical_device, buffer->handle, buffer->memory, offset); -} - -bool vulkan_buffer_create(vulkan_context* context, u64 size, VkBufferUsageFlagBits usage, - u32 memory_property_flags, bool bind_on_create, - vulkan_buffer* out_buffer) { - memset(out_buffer, 0, sizeof(vulkan_buffer)); - out_buffer->total_size = size; - out_buffer->usage = usage; - out_buffer->memory_property_flags = memory_property_flags; - - VkBufferCreateInfo buffer_info = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; - buffer_info.size = size; - buffer_info.usage = usage; - buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - - vkCreateBuffer(context->device.logical_device, &buffer_info, context->allocator, - &out_buffer->handle); - - VkMemoryRequirements requirements; - vkGetBufferMemoryRequirements(context->device.logical_device, out_buffer->handle, &requirements); - out_buffer->memory_index = - find_memory_index(context, requirements.memoryTypeBits, out_buffer->memory_property_flags); - - // Allocate - VkMemoryAllocateInfo allocate_info = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO }; - allocate_info.allocationSize = requirements.size; - allocate_info.memoryTypeIndex = (u32)out_buffer->memory_index; - - vkAllocateMemory(context->device.logical_device, &allocate_info, context->allocator, - &out_buffer->memory); - - if (bind_on_create) { - vulkan_buffer_bind(context, out_buffer, 0); - } - - DEBUG("Created buffer."); - - return true; -} - -// lock and unlock? - -void* vulkan_buffer_lock_memory(vulkan_context* context, vulkan_buffer* buffer, u64 offset, - u64 size, u32 flags) { - void* data; - vkMapMemory(context->device.logical_device, buffer->memory, offset, size, flags, &data); - return data; -} -void* vulkan_buffer_unlock_memory(vulkan_context* context, vulkan_buffer* buffer) { - vkUnmapMemory(context->device.logical_device, buffer->memory); -} - -void vulkan_buffer_load_data(vulkan_context* context, vulkan_buffer* buffer, u64 offset, u64 size, - u32 flags, const void* data) { - void* data_ptr = 0; - VK_CHECK( - vkMapMemory(context->device.logical_device, buffer->memory, offset, size, flags, &data_ptr)); - memcpy(data_ptr, data, size); - vkUnmapMemory(context->device.logical_device, buffer->memory); -} - -// TODO: destroy - -bool create_shader_module(vulkan_context* context, const char* filename, const char* type_str, - VkShaderStageFlagBits flag, u32 stage_index, - vulkan_shader_stage* shader_stages) { - memset(&shader_stages[stage_index].create_info, 0, sizeof(VkShaderModuleCreateInfo)); - memset(&shader_stages[stage_index].stage_create_info, 0, sizeof(VkPipelineShaderStageCreateInfo)); - - shader_stages[stage_index].create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; - - // todo: file input - FileData file_contents = load_spv_file(filename); - - shader_stages[stage_index].create_info.codeSize = file_contents.size; - shader_stages[stage_index].create_info.pCode = (u32*)file_contents.data; - - vkCreateShaderModule(context->device.logical_device, &shader_stages[stage_index].create_info, - context->allocator, &shader_stages[stage_index].handle); - - shader_stages[stage_index].stage_create_info.sType = - VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - shader_stages[stage_index].stage_create_info.stage = flag; - shader_stages[stage_index].stage_create_info.module = shader_stages[stage_index].handle; - shader_stages[stage_index].stage_create_info.pName = "main"; - - free(file_contents.data); - - // TODO: Descriptors - - return true; -} - -bool vulkan_object_shader_create(vulkan_context* context, vulkan_shader* out_shader) { - char stage_type_strs[SHADER_STAGE_COUNT][5] = { "vert", "frag" }; - char stage_filenames[SHADER_STAGE_COUNT][256] = { "build/linux/x86_64/debug/object.vert.spv", - "build/linux/x86_64/debug/object.frag.spv" }; - VkShaderStageFlagBits stage_types[SHADER_STAGE_COUNT] = { VK_SHADER_STAGE_VERTEX_BIT, - VK_SHADER_STAGE_FRAGMENT_BIT }; - for (u8 i = 0; i < SHADER_STAGE_COUNT; i++) { - DEBUG("Loading %s", stage_filenames[i]); - create_shader_module(context, stage_filenames[i], stage_type_strs[i], stage_types[i], i, - out_shader->stages); - } - - // descriptors - VkDescriptorSetLayoutBinding global_ubo_layout_binding; - global_ubo_layout_binding.binding = 0; - global_ubo_layout_binding.descriptorCount = 1; - global_ubo_layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - global_ubo_layout_binding.pImmutableSamplers = 0; - global_ubo_layout_binding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; +static bool select_physical_device(gpu_device* out_device) {} - VkDescriptorSetLayoutBinding sampler_layout_binding; - sampler_layout_binding.binding = 1; - sampler_layout_binding.descriptorCount = 1; - sampler_layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - sampler_layout_binding.pImmutableSamplers = 0; - sampler_layout_binding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; - - VkDescriptorSetLayoutCreateInfo global_layout_info = { - VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO - }; - - VkDescriptorSetLayoutBinding bindings[2] = { global_ubo_layout_binding, sampler_layout_binding }; - - global_layout_info.bindingCount = 2; - global_layout_info.pBindings = bindings; - - VK_CHECK(vkCreateDescriptorSetLayout(context->device.logical_device, &global_layout_info, - context->allocator, &out_shader->descriptor_set_layout)); - - VkDescriptorPoolSize global_pool_size; - global_pool_size.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - global_pool_size.descriptorCount = 3; - - VkDescriptorPoolSize sampler_pool_size; - sampler_pool_size.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - sampler_pool_size.descriptorCount = 3; - - VkDescriptorPoolSize pool_sizes[2] = { global_pool_size, sampler_pool_size }; - - VkDescriptorPoolCreateInfo pool_info = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO }; - pool_info.poolSizeCount = 2; - pool_info.pPoolSizes = pool_sizes; - pool_info.maxSets = 3; - - VK_CHECK(vkCreateDescriptorPool(context->device.logical_device, &pool_info, context->allocator, - &out_shader->descriptor_pool)); - - // Pipeline creation - VkViewport viewport; - viewport.x = 0; - viewport.y = 0; - viewport.width = (f32)context->framebuffer_width; - viewport.height = (f32)context->framebuffer_height; - viewport.minDepth = 0.0; - viewport.maxDepth = 1.0; - - VkRect2D scissor; - scissor.offset.x = scissor.offset.y = 0; - scissor.extent.width = context->framebuffer_width; - scissor.extent.height = context->framebuffer_height; - - // Attributes - u32 offset = 0; - const i32 attribute_count = 3; - VkVertexInputAttributeDescription attribute_descs[3]; - // Position - VkFormat formats[3] = { VK_FORMAT_R32G32B32_SFLOAT, VK_FORMAT_R32G32B32_SFLOAT, - VK_FORMAT_R32G32_SFLOAT }; - - u64 sizes[3] = { sizeof(vec3), sizeof(vec3), sizeof(vec2) }; - - for (u32 i = 0; i < attribute_count; i++) { - attribute_descs[i].binding = 0; - attribute_descs[i].location = i; - attribute_descs[i].format = formats[i]; - attribute_descs[i].offset = offset; - offset += sizes[i]; - } - - // Descriptor set layouts - VkDescriptorSetLayout layouts[1] = { out_shader->descriptor_set_layout }; - - // Stages - VkPipelineShaderStageCreateInfo stage_create_infos[SHADER_STAGE_COUNT]; - memset(stage_create_infos, 0, sizeof(stage_create_infos)); - for (u32 i = 0; i < SHADER_STAGE_COUNT; i++) { - stage_create_infos[i].sType = out_shader->stages[i].stage_create_info.sType; - stage_create_infos[i] = out_shader->stages[i].stage_create_info; - } - - vulkan_graphics_pipeline_create( - context, &context->main_renderpass, attribute_count, attribute_descs, 1, layouts, - SHADER_STAGE_COUNT, stage_create_infos, viewport, scissor, false, &out_shader->pipeline); - INFO("Graphics pipeline created!"); - - // Uniform buffer - if (!vulkan_buffer_create(context, sizeof(global_object_uniform), - VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | - VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, - true, &out_shader->global_uniforms_buffer)) { - ERROR("Couldnt create uniforms buffer"); - return false; - } - - VkDescriptorSetLayout global_layouts[3] = { - out_shader->descriptor_set_layout, - out_shader->descriptor_set_layout, - out_shader->descriptor_set_layout, - }; - - VkDescriptorSetAllocateInfo alloc_info = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO }; - alloc_info.descriptorPool = out_shader->descriptor_pool; - alloc_info.descriptorSetCount = 3; - alloc_info.pSetLayouts = global_layouts; - VK_CHECK(vkAllocateDescriptorSets(context->device.logical_device, &alloc_info, - out_shader->descriptor_sets)); - - return true; -} -void vulkan_object_shader_destroy(vulkan_context* context, vulkan_shader* shader) {} -void vulkan_object_shader_use(vulkan_context* context, vulkan_shader* shader) { - u32 image_index = context->image_index; - vulkan_pipeline_bind(&context->gfx_command_buffers->data[image_index], - VK_PIPELINE_BIND_POINT_GRAPHICS, &shader->pipeline); -} -void vulkan_object_shader_update_global_state(vulkan_context* context, vulkan_shader* shader) { - u32 image_index = context->image_index; - VkCommandBuffer cmd_buffer = context->gfx_command_buffers->data[image_index].handle; - VkDescriptorSet global_descriptors = shader->descriptor_sets[image_index]; - - u32 range = sizeof(global_object_uniform); - u64 offset = 0; - - // copy data to buffer - vulkan_buffer_load_data(context, &shader->global_uniforms_buffer, offset, range, 0, - &shader->global_ubo); - - VkDescriptorBufferInfo buffer_info; - buffer_info.buffer = shader->global_uniforms_buffer.handle; - buffer_info.offset = offset; - buffer_info.range = range; - - VkDescriptorImageInfo image_info; - image_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - image_info.imageView = shader->texture_data->image.view; - image_info.sampler = shader->texture_data->sampler; - - VkWriteDescriptorSet uniform_write = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET }; - uniform_write.dstSet = shader->descriptor_sets[image_index]; - uniform_write.dstBinding = 0; - uniform_write.dstArrayElement = 0; - uniform_write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - uniform_write.descriptorCount = 1; - uniform_write.pBufferInfo = &buffer_info; - - VkWriteDescriptorSet texture_write = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET }; - texture_write.dstSet = shader->descriptor_sets[image_index]; - texture_write.dstBinding = 1; - texture_write.dstArrayElement = 0; - texture_write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - texture_write.descriptorCount = 1; - texture_write.pImageInfo = &image_info; - - VkWriteDescriptorSet writes[2] = { uniform_write, texture_write }; - - vkUpdateDescriptorSets(context->device.logical_device, 2, writes, 0, 0); - - vkCmdBindDescriptorSets(cmd_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, shader->pipeline.layout, 0, - 1, &global_descriptors, 0, 0); -} - -void vulkan_object_shader_update_object(vulkan_context* context, vulkan_shader* shader, - mat4 model) { - u32 image_index = context->image_index; - VkCommandBuffer cmd_buffer = context->gfx_command_buffers->data[image_index].handle; - // vulkan_command_buffer* cmd_buffer = &context->gfx_command_buffers->data[context.image_index]; - - vkCmdPushConstants(cmd_buffer, shader->pipeline.layout, VK_SHADER_STAGE_VERTEX_BIT, 0, - sizeof(mat4), &model); - - // vulkan_object_shader_use(context, &context->object_shader); - VkDeviceSize offsets[1] = { 0 }; - vkCmdBindVertexBuffers(cmd_buffer, 0, 1, &context->object_vertex_buffer.handle, - (VkDeviceSize*)offsets); - - vkCmdBindIndexBuffer(cmd_buffer, context->object_index_buffer.handle, 0, VK_INDEX_TYPE_UINT32); - - vkCmdDrawIndexed(cmd_buffer, 36, 1, 0, 0, 0); - // vkCmdDraw(cmd_buffer, 36, 1, 0, 0); -} - -bool select_physical_device(vulkan_context* ctx) { - u32 physical_device_count = 0; - VK_CHECK(vkEnumeratePhysicalDevices(ctx->instance, &physical_device_count, 0)); - if (physical_device_count == 0) { - FATAL("No devices that support vulkan were found"); - return false; - } - TRACE("Number of devices found %d", physical_device_count); - - VkPhysicalDevice physical_devices[physical_device_count]; - VK_CHECK(vkEnumeratePhysicalDevices(ctx->instance, &physical_device_count, physical_devices)); - - for (u32 i = 0; i < physical_device_count; i++) { - VkPhysicalDeviceProperties properties; - vkGetPhysicalDeviceProperties(physical_devices[i], &properties); - - VkPhysicalDeviceFeatures features; - vkGetPhysicalDeviceFeatures(physical_devices[i], &features); - - VkPhysicalDeviceMemoryProperties memory; - vkGetPhysicalDeviceMemoryProperties(physical_devices[i], &memory); - - vulkan_physical_device_requirements requirements = {}; - requirements.graphics = true; - requirements.present = true; - requirements.compute = true; - requirements.transfer = true; - - requirements.sampler_anistropy = true; - requirements.discrete_gpu = true; - requirements.device_ext_names[0] = str8lit(VK_KHR_SWAPCHAIN_EXTENSION_NAME); - requirements.device_ext_name_count = 1; - - vulkan_physical_device_queue_family_info queue_info = {}; - - bool result = physical_device_meets_requirements(physical_devices[i], ctx->surface, &properties, - &features, &requirements, &queue_info, - &ctx->device.swapchain_support); - - if (result) { - INFO("GPU Driver version: %d.%d.%d", VK_VERSION_MAJOR(properties.driverVersion), - VK_VERSION_MINOR(properties.driverVersion), VK_VERSION_PATCH(properties.driverVersion)); - - INFO("Vulkan API version: %d.%d.%d", VK_VERSION_MAJOR(properties.apiVersion), - VK_VERSION_MINOR(properties.apiVersion), VK_VERSION_PATCH(properties.apiVersion)); - - // TODO: print gpu memory information - - // https://youtu.be/6Kj3O2Ov1RU?si=pXfP5NvXXcXjJsrG&t=2439 - - ctx->device.physical_device = physical_devices[i]; - ctx->device.graphics_queue_index = queue_info.graphics_family_index; - ctx->device.present_queue_index = queue_info.present_family_index; - ctx->device.compute_queue_index = queue_info.compute_family_index; - ctx->device.transfer_queue_index = queue_info.transfer_family_index; - ctx->device.properties = properties; - ctx->device.features = features; - ctx->device.memory = memory; - break; - } - } - - if (!ctx->device.physical_device) { - ERROR("No suitable physical devices were found :("); - return false; - } - - INFO("Physical device selected: %s\n", ctx->device.properties.deviceName); - return true; -} - -bool vulkan_device_create(vulkan_context* context) { - // Physical device - NOTE: mutates the context directly - if (!select_physical_device(context)) { - return false; - } - -// Logical device - NOTE: mutates the context directly - -// queues -#define VULKAN_QUEUES_COUNT 2 - const char* queue_names[VULKAN_QUEUES_COUNT] = { - "GRAPHICS", - "TRANSFER", - }; - i32 indices[VULKAN_QUEUES_COUNT] = { - context->device.graphics_queue_index, - context->device.transfer_queue_index, - }; - f32 prio_one = 1.0; - VkDeviceQueueCreateInfo queue_create_info[2]; // HACK: make 2 queues, graphics and transfer - // graphics - queue_create_info[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; - queue_create_info[0].queueFamilyIndex = 0; - queue_create_info[0].queueCount = 1; - queue_create_info[0].flags = 0; - queue_create_info[0].pNext = 0; - queue_create_info[0].pQueuePriorities = &prio_one; - // transfer - queue_create_info[1].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; - queue_create_info[1].queueFamilyIndex = 1; - queue_create_info[1].queueCount = 1; - queue_create_info[1].flags = 0; - queue_create_info[1].pNext = 0; - queue_create_info[1].pQueuePriorities = &prio_one; - - // for (int i = 0; i < 2; i++) { - // TRACE("Configure %s queue", queue_names[i]); - // queue_create_info[i].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; - // queue_create_info[i].queueFamilyIndex = indices[i]; - // queue_create_info[i].queueCount = 1; // make just one of them - // queue_create_info[i].flags = 0; - // queue_create_info[i].pNext = 0; - // f32 priority = 1.0; - // queue_create_info[i].pQueuePriorities = &priority; +gpu_device gpu_device_create() { + gpu_device device = { 0 }; + // Physical device + // if (!select_physical_device()) { + // return false; // } + INFO("Physical device selected"); - // features + // Features VkPhysicalDeviceFeatures device_features = {}; device_features.samplerAnisotropy = VK_TRUE; // request anistrophy - // device itself + // Logical device + VkDeviceQueueCreateInfo queue_create_info[2]; + //.. VkDeviceCreateInfo device_create_info = { VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO }; device_create_info.queueCreateInfoCount = VULKAN_QUEUES_COUNT; device_create_info.pQueueCreateInfos = queue_create_info; @@ -844,1147 +47,38 @@ bool vulkan_device_create(vulkan_context* context) { const char* extension_names = VK_KHR_SWAPCHAIN_EXTENSION_NAME; device_create_info.ppEnabledExtensionNames = &extension_names; - // deprecated - device_create_info.enabledLayerCount = 0; - device_create_info.ppEnabledLayerNames = 0; - - VkResult result = vkCreateDevice(context->device.physical_device, &device_create_info, - context->allocator, &context->device.logical_device); + VkResult result = vkCreateDevice(device.physical_device, &device_create_info, context.allocator, + &device.logical_device); if (result != VK_SUCCESS) { - printf("error creating logical device with status %u\n", result); - ERROR_EXIT("Bye bye"); + FATAL("Error creating logical device with status %u\n", result); + exit(1); } INFO("Logical device created"); - // get queues - vkGetDeviceQueue(context->device.logical_device, context->device.graphics_queue_index, 0, - &context->device.graphics_queue); - // vkGetDeviceQueue(context->device.logical_device, context->device.present_queue_index, 0, - // &context->device.present_queue); - // vkGetDeviceQueue(context->device.logical_device, context->device.compute_queue_index, 0, - // &context->device.compute_queue); - vkGetDeviceQueue(context->device.logical_device, context->device.transfer_queue_index, 0, - &context->device.transfer_queue); + // Queues - // create command pool for graphics queue - VkCommandPoolCreateInfo pool_create_info = { VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO }; - pool_create_info.queueFamilyIndex = context->device.graphics_queue_index; - pool_create_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; - vkCreateCommandPool(context->device.logical_device, &pool_create_info, context->allocator, - &context->device.gfx_command_pool); - INFO("Created Command Pool") + // Create the command pool - return true; + context.device = device; + return device; } -void vulkan_device_destroy(vulkan_context* context) { - context->device.physical_device = 0; // release - // TODO: reset other memory -} - -bool vulkan_device_detect_depth_format(vulkan_device* device) { - const size_t n_candidates = 3; - VkFormat candidates[3] = { VK_FORMAT_D32_SFLOAT, VK_FORMAT_D32_SFLOAT_S8_UINT, - VK_FORMAT_D24_UNORM_S8_UINT }; - u32 flags = VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT; - for (u64 i = 0; i < n_candidates; i++) { - VkFormatProperties properties; - vkGetPhysicalDeviceFormatProperties(device->physical_device, candidates[i], &properties); - if ((properties.linearTilingFeatures & flags) == flags) { - device->depth_format = candidates[i]; - return true; - } - if ((properties.optimalTilingFeatures & flags) == flags) { - device->depth_format = candidates[i]; - return true; - } - } - return false; +gpu_renderpass* gpu_renderpass_create() { + // Allocate it + // sets everything up + // return pointer to it } -void vulkan_image_view_create(vulkan_context* context, VkFormat format, vulkan_image* image, - VkImageAspectFlags aspect_flags) { - VkImageViewCreateInfo view_create_info = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO }; - view_create_info.image = image->handle; - view_create_info.viewType = VK_IMAGE_VIEW_TYPE_2D; - view_create_info.format = format; - view_create_info.subresourceRange.aspectMask = aspect_flags; - - view_create_info.subresourceRange.baseMipLevel = 0; - view_create_info.subresourceRange.levelCount = 1; - view_create_info.subresourceRange.baseArrayLayer = 0; - view_create_info.subresourceRange.layerCount = 1; - - vkCreateImageView(context->device.logical_device, &view_create_info, context->allocator, - &image->view); +void encode_set_pipeline(gpu_cmd_encoder* encoder, gpu_pipeline* pipeline) { + // VK_PIPELINE_BIND_POINT_GRAPHICS, &shader->pipeline); + // if (kind == PIPELINE_GRAPHICS) { + // // ... + // } else { + // // ... + // } } -void vulkan_image_transition_layout(vulkan_context* context, vulkan_command_buffer* command_buffer, - vulkan_image* image, VkFormat format, VkImageLayout old_layout, - VkImageLayout new_layout) { - VkImageMemoryBarrier barrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER }; - void vulkan_image_transition_layout( - vulkan_context * context, vulkan_command_buffer * command_buffer, vulkan_image * image, - VkFormat format, VkImageLayout old_layout, VkImageLayout new_layout) { - VkImageMemoryBarrier barrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER }; - barrier.oldLayout = old_layout; - barrier.newLayout = new_layout; - barrier.srcQueueFamilyIndex = context->device.graphics_queue_index; - barrier.dstQueueFamilyIndex = context->device.graphics_queue_index; - barrier.image = image->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; - barrier.dstAccessMask = 0; - - 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(command_buffer->handle, source_stage, dest_stage, 0, 0, 0, 0, 0, 1, - &barrier); - } - - void vulkan_image_copy_from_buffer(vulkan_image * image, VkBuffer buffer, - vulkan_command_buffer * command_buffer) { - 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", image->width, image->height); - region.imageOffset.x = 0; - region.imageOffset.y = 0; - region.imageOffset.z = 0; - region.imageExtent.width = image->width; - region.imageExtent.height = image->height; - region.imageExtent.depth = 1; - - vkCmdCopyBufferToImage(command_buffer->handle, buffer, image->handle, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); - } - - void vulkan_image_create(vulkan_context * context, VkImageType image_type, u32 width, u32 height, - VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, - VkMemoryPropertyFlags memory_flags, bool create_view, - VkImageAspectFlags aspect_flags, vulkan_image* out_image) { - // copy params - out_image->width = width; - out_image->height = height; - - // create info - VkImageCreateInfo image_create_info = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO }; - image_create_info.imageType = image_type; - image_create_info.extent.width = width; - image_create_info.extent.height = height; - image_create_info.extent.depth = 1; - image_create_info.mipLevels = 1; - image_create_info.arrayLayers = 1; - image_create_info.format = format; - image_create_info.tiling = tiling; - image_create_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - image_create_info.usage = usage; - image_create_info.samples = VK_SAMPLE_COUNT_1_BIT; - image_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - - VK_CHECK(vkCreateImage(context->device.logical_device, &image_create_info, context->allocator, - &out_image->handle)); - - VkMemoryRequirements memory_reqs; - vkGetImageMemoryRequirements(context->device.logical_device, out_image->handle, &memory_reqs); - - i32 memory_type = -1; - VkPhysicalDeviceMemoryProperties memory_properties; - vkGetPhysicalDeviceMemoryProperties(context->device.physical_device, &memory_properties); - - for (u32 i = 0; i < memory_properties.memoryTypeCount; i++) { - // typefilter = memoryTypeBits , prop filter = memory_flags - if (memory_reqs.memoryTypeBits & (1 << i) && - (memory_properties.memoryTypes[i].propertyFlags & memory_flags)) { - memory_type = i; - break; - } - } - - if (memory_type < 0) { - ERROR_EXIT("couldnt find a suitable memory type for the image"); - } - - // allocate memory - VkMemoryAllocateInfo memory_allocate_info = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO }; - memory_allocate_info.allocationSize = memory_reqs.size; - memory_allocate_info.memoryTypeIndex = memory_type; - vkAllocateMemory(context->device.logical_device, &memory_allocate_info, context->allocator, - &out_image->memory); - - // bind memory - // TODO: maybe bind context->device.logical_device to device at the top of the functions? - vkBindImageMemory(context->device.logical_device, out_image->handle, out_image->memory, 0); - - if (create_view) { - out_image->view = 0; - vulkan_image_view_create(context, format, out_image, aspect_flags); - } - } - - // TODO: vulkan_image_destroy - - void vulkan_framebuffer_create(vulkan_context * context, vulkan_renderpass * renderpass, - u32 width, u32 height, u32 attachment_count, - VkImageView * attachments, vulkan_framebuffer * out_framebuffer) { - out_framebuffer->attachments = malloc(sizeof(VkImageView) * attachment_count); - for (u32 i = 0; i < attachment_count; i++) { - out_framebuffer->attachments[i] = attachments[i]; - } - out_framebuffer->attachment_count = attachment_count; - out_framebuffer->renderpass = renderpass; - - VkFramebufferCreateInfo framebuffer_create_info = { - VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO - }; // TODO - - framebuffer_create_info.renderPass = renderpass->handle; - framebuffer_create_info.attachmentCount = attachment_count; - framebuffer_create_info.pAttachments = out_framebuffer->attachments; - framebuffer_create_info.width = width; - framebuffer_create_info.height = height; - framebuffer_create_info.layers = 1; - - vkCreateFramebuffer(context->device.logical_device, &framebuffer_create_info, - context->allocator, &out_framebuffer->handle); - } - - // TODO: vulkan_framebuffer_destroy - - void vulkan_command_buffer_allocate(vulkan_context * context, VkCommandPool pool, bool is_primary, - vulkan_command_buffer* out_command_buffer) { - VkCommandBufferAllocateInfo allocate_info = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO }; - allocate_info.commandPool = pool; - allocate_info.level = - is_primary ? VK_COMMAND_BUFFER_LEVEL_PRIMARY : VK_COMMAND_BUFFER_LEVEL_SECONDARY; - allocate_info.commandBufferCount = 1; - allocate_info.pNext = 0; - - out_command_buffer->state = COMMAND_BUFFER_STATE_NOT_ALLOCATED; - vkAllocateCommandBuffers(context->device.logical_device, &allocate_info, - &out_command_buffer->handle); - out_command_buffer->state = COMMAND_BUFFER_STATE_READY; - } - - void vulkan_command_buffer_free(vulkan_context * context, VkCommandPool pool, - vulkan_command_buffer * out_command_buffer) { - // TODO: implement freeing - } - - void vulkan_command_buffer_begin(vulkan_command_buffer * command_buffer, bool is_single_use, - bool is_renderpass_continue, bool is_simultaneous_use) { - VkCommandBufferBeginInfo begin_info = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO }; - begin_info.flags = 0; - if (is_single_use) { - begin_info.flags |= VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; - } - // TODO: RENDER_PASS_CONTINUE_BIT & SIMULTANEOUS_USE_BIT - - begin_info.pNext = 0; - begin_info.pInheritanceInfo = 0; - vkBeginCommandBuffer(command_buffer->handle, &begin_info); - - command_buffer->state = COMMAND_BUFFER_STATE_RECORDING; - } - - void vulkan_command_buffer_end(vulkan_command_buffer * command_buffer) { - VK_CHECK(vkEndCommandBuffer(command_buffer->handle)); - command_buffer->state = COMMAND_BUFFER_STATE_RECORDING_ENDED; - } - void vulkan_command_buffer_update_submitted(vulkan_command_buffer * command_buffer) { - command_buffer->state = COMMAND_BUFFER_STATE_SUBMITTED; - } - void vulkan_command_buffer_reset(vulkan_command_buffer * command_buffer) { - command_buffer->state = COMMAND_BUFFER_STATE_READY; - } - - void vulkan_command_buffer_allocate_and_begin_oneshot( - vulkan_context * context, VkCommandPool pool, vulkan_command_buffer * out_command_buffer) { - vulkan_command_buffer_allocate(context, pool, true, out_command_buffer); - vulkan_command_buffer_begin(out_command_buffer, true, false, false); - } - - void vulkan_command_buffer_end_oneshot(vulkan_context * context, VkCommandPool pool, - vulkan_command_buffer * command_buffer, VkQueue queue) { - vulkan_command_buffer_end(command_buffer); - - // submit to queue - VkSubmitInfo submit_info = { VK_STRUCTURE_TYPE_SUBMIT_INFO }; - submit_info.commandBufferCount = 1; - submit_info.pCommandBuffers = &command_buffer->handle; - VK_CHECK(vkQueueSubmit(queue, 1, &submit_info, 0)); - // wait for it to finish - VK_CHECK(vkQueueWaitIdle(queue)); - - vulkan_command_buffer_free(context, pool, command_buffer); - } - - void vulkan_buffer_copy_to(vulkan_context * context, VkCommandPool pool, VkFence fence, - VkQueue queue, VkBuffer source, u64 source_offset, VkBuffer dest, - u64 dest_offset, u64 size) { - vkQueueWaitIdle(queue); - - vulkan_command_buffer temp_cmd_buf; - vulkan_command_buffer_allocate_and_begin_oneshot(context, pool, &temp_cmd_buf); - - VkBufferCopy copy_region; - copy_region.srcOffset = source_offset; - copy_region.dstOffset = dest_offset; - copy_region.size = size; - - vkCmdCopyBuffer(temp_cmd_buf.handle, source, dest, 1, ©_region); - - vulkan_command_buffer_end_oneshot(context, pool, &temp_cmd_buf, queue); - } - - void vulkan_swapchain_create(vulkan_context * context, u32 width, u32 height, - vulkan_swapchain * out_swapchain) { - VkExtent2D swapchain_extent = { width, height }; - out_swapchain->max_frames_in_flight = 2; // support triple buffering - - // find a format - bool found; - for (u32 i = 0; i < context->device.swapchain_support.format_count; i++) { - VkSurfaceFormatKHR format = context->device.swapchain_support.formats[i]; - if (format.format == VK_FORMAT_B8G8R8A8_UNORM && - format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { - out_swapchain->image_format = format; - found = true; - break; - } - } - if (!found) { - out_swapchain->image_format = context->device.swapchain_support.formats[0]; - } - - VkPresentModeKHR present_mode = VK_PRESENT_MODE_FIFO_KHR; // guaranteed to be implemented - // TODO: look for mailbox - https://youtu.be/jWKVb_QdSNM?si=bHcd3sEf-M0x3QwH&t=1687 - - // TODO: requery swapchain support - - u32 image_count = context->device.swapchain_support.capabilities.minImageCount; - - VkSwapchainCreateInfoKHR swapchain_create_info = { - VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR - }; - swapchain_create_info.surface = context->surface; - swapchain_create_info.minImageCount = image_count; - swapchain_create_info.imageFormat = out_swapchain->image_format.format; - swapchain_create_info.imageColorSpace = out_swapchain->image_format.colorSpace; - DEBUG("Image extent %d %d\n", swapchain_extent.width, swapchain_extent.height); - swapchain_create_info.imageExtent = swapchain_extent; - swapchain_create_info.imageArrayLayers = 1; - swapchain_create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; - swapchain_create_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; - swapchain_create_info.queueFamilyIndexCount = 0; - swapchain_create_info.pQueueFamilyIndices = 0; - - swapchain_create_info.preTransform = - context->device.swapchain_support.capabilities.currentTransform; - swapchain_create_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; - swapchain_create_info.presentMode = present_mode; - swapchain_create_info.clipped = VK_TRUE; - swapchain_create_info.oldSwapchain = 0; - - TRACE("Create swapchain"); - VK_CHECK(vkCreateSwapchainKHR(context->device.logical_device, &swapchain_create_info, - context->allocator, &out_swapchain->handle)); - - context->current_frame = 0; - - // images - out_swapchain->image_count = 0; - vkGetSwapchainImagesKHR(context->device.logical_device, out_swapchain->handle, - &out_swapchain->image_count, 0); - - if (!out_swapchain->images) { - out_swapchain->images = (VkImage*)malloc(sizeof(VkImage) * out_swapchain->image_count); - } - if (!out_swapchain->views) { - out_swapchain->views = (VkImageView*)malloc(sizeof(VkImage) * out_swapchain->image_count); - } - VK_CHECK(vkGetSwapchainImagesKHR(context->device.logical_device, out_swapchain->handle, - &out_swapchain->image_count, out_swapchain->images)); - - // views - for (int i = 0; i < out_swapchain->image_count; i++) { - VkImageViewCreateInfo view_info = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO }; - view_info.image = out_swapchain->images[i]; - view_info.viewType = VK_IMAGE_VIEW_TYPE_2D; - view_info.format = out_swapchain->image_format.format; - view_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - view_info.subresourceRange.baseMipLevel = 0; - view_info.subresourceRange.levelCount = 1; - view_info.subresourceRange.baseArrayLayer = 0; - view_info.subresourceRange.layerCount = 1; - - VK_CHECK(vkCreateImageView(context->device.logical_device, &view_info, context->allocator, - &out_swapchain->views[i])); - } - - // depth attachment - if (!vulkan_device_detect_depth_format(&context->device)) { - ERROR_EXIT("Failed to find a supported depth format"); - } - vulkan_image_create(context, VK_IMAGE_TYPE_2D, swapchain_extent.width, swapchain_extent.height, - context->device.depth_format, VK_IMAGE_TILING_OPTIMAL, - VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, true, VK_IMAGE_ASPECT_DEPTH_BIT, - &out_swapchain->depth_attachment); - INFO("Depth attachment created"); - - INFO("Swapchain created successfully"); - } - - // TODO: swapchain destroy - void vulkan_swapchain_recreate(vulkan_context * context, u32 width, u32 height, - vulkan_swapchain * swapchain) { - // TODO - } - bool vulkan_swapchain_acquire_next_image_index( - vulkan_context * context, vulkan_swapchain * swapchain, u64 timeout_ns, - VkSemaphore image_available_semaphore, VkFence fence, u32 * out_image_index) { - VkResult result = - vkAcquireNextImageKHR(context->device.logical_device, swapchain->handle, timeout_ns, - image_available_semaphore, fence, out_image_index); - - if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) { - FATAL("Failed to acquire swapchain image"); - return false; - } - - return true; - } - - void vulkan_swapchain_present(vulkan_context * context, vulkan_swapchain * swapchain, - VkQueue graphics_queue, VkQueue present_queue, - VkSemaphore render_complete_semaphore, u32 present_image_index) { - // return image to swapchain for presentation - VkPresentInfoKHR present_info = { VK_STRUCTURE_TYPE_PRESENT_INFO_KHR }; - present_info.waitSemaphoreCount = 1; - present_info.pWaitSemaphores = &render_complete_semaphore; - present_info.swapchainCount = 1; - present_info.pSwapchains = &swapchain->handle; - present_info.pImageIndices = &present_image_index; - present_info.pResults = 0; - - VkResult result = vkQueuePresentKHR(present_queue, &present_info); - if (result != VK_SUCCESS) { - if (result == VK_SUBOPTIMAL_KHR) { - // WARN("Swapchain suboptimal - maybe resize needed?"); - } else { - FATAL("Failed to present swapchain iamge"); - } - } - - // advance the current frame - context->current_frame = (context->current_frame + 1) % swapchain->max_frames_in_flight; - } - - void vulkan_renderpass_create(vulkan_context * context, vulkan_renderpass * out_renderpass, - vec4 render_area, vec4 clear_colour, f32 depth, u32 stencil) { - out_renderpass->render_area = render_area; - out_renderpass->clear_colour = clear_colour; - out_renderpass->depth = depth; - out_renderpass->stencil = stencil; - - // main subpass - VkSubpassDescription subpass = {}; - subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - - // attachments - u32 attachment_desc_count = 2; - VkAttachmentDescription attachment_descriptions[2]; - - // 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; - - // Depth attachment - VkAttachmentDescription depth_attachment; - depth_attachment.format = context->device.depth_format; - depth_attachment.samples = VK_SAMPLE_COUNT_1_BIT; - depth_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - depth_attachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - depth_attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - depth_attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - depth_attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - depth_attachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - depth_attachment.flags = 0; - - attachment_descriptions[1] = depth_attachment; - - VkAttachmentReference depth_attachment_reference; - depth_attachment_reference.attachment = 1; - depth_attachment_reference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - - subpass.pDepthStencilAttachment = &depth_attachment_reference; - - // TODO: other attachment styles - - subpass.inputAttachmentCount = 0; - subpass.pInputAttachments = 0; - subpass.pResolveAttachments = 0; - subpass.preserveAttachmentCount = 0; - subpass.preserveAttachmentCount = 0; - - // 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; - - VkRenderPassCreateInfo render_pass_create_info = { VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO }; - render_pass_create_info.attachmentCount = attachment_desc_count; - render_pass_create_info.pAttachments = attachment_descriptions; - 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.pNext = 0; - render_pass_create_info.flags = 0; - - VK_CHECK(vkCreateRenderPass(context->device.logical_device, &render_pass_create_info, - context->allocator, &out_renderpass->handle)); - } - - // TODO: renderpass destroy - - void vulkan_renderpass_begin(vulkan_command_buffer * command_buffer, - vulkan_renderpass * renderpass, VkFramebuffer framebuffer) { - VkRenderPassBeginInfo begin_info = { VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO }; - begin_info.renderPass = renderpass->handle; - begin_info.framebuffer = framebuffer; - begin_info.renderArea.offset.x = renderpass->render_area.x; - begin_info.renderArea.offset.y = renderpass->render_area.y; - begin_info.renderArea.extent.width = renderpass->render_area.z; - begin_info.renderArea.extent.height = renderpass->render_area.w; - - VkClearValue clear_values[2]; - memset(&clear_values, 0, sizeof(VkClearValue) * 2); - clear_values[0].color.float32[0] = renderpass->clear_colour.x; - clear_values[0].color.float32[1] = renderpass->clear_colour.y; - clear_values[0].color.float32[2] = renderpass->clear_colour.z; - clear_values[0].color.float32[3] = renderpass->clear_colour.w; - clear_values[1].depthStencil.depth = renderpass->depth; - clear_values[1].depthStencil.stencil = renderpass->stencil; - - begin_info.clearValueCount = 2; - begin_info.pClearValues = clear_values; - - vkCmdBeginRenderPass(command_buffer->handle, &begin_info, VK_SUBPASS_CONTENTS_INLINE); - command_buffer->state = COMMAND_BUFFER_STATE_IN_RENDER_PASS; - } - - void vulkan_renderpass_end(vulkan_command_buffer * command_buffer, - vulkan_renderpass * renderpass) { - vkCmdEndRenderPass(command_buffer->handle); - command_buffer->state = COMMAND_BUFFER_STATE_RECORDING; - } - - bool create_buffers(vulkan_context * context) { - VkMemoryPropertyFlagBits mem_prop_flags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; - - const u64 vertex_buffer_size = sizeof(vertex_pos) * 1024 * 1024; - if (!vulkan_buffer_create(context, vertex_buffer_size, - VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | - VK_BUFFER_USAGE_TRANSFER_DST_BIT, - mem_prop_flags, true, &context->object_vertex_buffer)) { - ERROR("couldnt create vertex buffer"); - return false; - } - - context->geometry_vertex_offset = 0; - - const u64 index1_buffer_size = sizeof(u32) * 1024 * 1024; - if (!vulkan_buffer_create(context, index1_buffer_size, - VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | - VK_BUFFER_USAGE_TRANSFER_DST_BIT, - mem_prop_flags, true, &context->object_index_buffer)) { - ERROR("couldnt create vertex buffer"); - return false; - } - context->geometry_index_offset = 0; - - return true; - } - - void create_command_buffers(renderer * ren) { - if (!context.gfx_command_buffers) { - context.gfx_command_buffers = vulkan_command_buffer_darray_new(context.swapchain.image_count); - } - - for (u32 i = 0; i < context.swapchain.image_count; i++) { - vulkan_command_buffer_allocate(&context, context.device.gfx_command_pool, true, - &context.gfx_command_buffers->data[i]); - } - } - - void upload_data_range(vulkan_context * context, VkCommandPool pool, VkFence fence, VkQueue queue, - vulkan_buffer * buffer, u64 offset, u64 size, void* data) { - VkBufferUsageFlags flags = - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; - vulkan_buffer staging; - vulkan_buffer_create(context, size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, flags, true, &staging); - // load data into staging buffer - printf("Size: %ld\n", size); - vulkan_buffer_load_data(context, &staging, 0, size, 0, data); - - // copy - vulkan_buffer_copy_to(context, pool, fence, queue, staging.handle, 0, buffer->handle, offset, - size); - - vkDestroyBuffer(context->device.logical_device, staging.handle, context->allocator); - } - - void regenerate_framebuffers(renderer * ren, vulkan_swapchain * swapchain, - vulkan_renderpass * renderpass) { - for (u32 i = 0; i < swapchain->image_count; i++) { - u32 attachment_count = 2; // one for depth, one for colour - - VkImageView attachments[2] = { swapchain->views[i], swapchain->depth_attachment.view }; - - vulkan_framebuffer_create(&context, renderpass, context.framebuffer_width, - context.framebuffer_height, 2, attachments, - &swapchain->framebuffers->data[i]); - } - } - - void vulkan_fence_create(vulkan_context * context, bool create_signaled, - vulkan_fence* out_fence) { - out_fence->is_signaled = create_signaled; - VkFenceCreateInfo fence_create_info = { VK_STRUCTURE_TYPE_FENCE_CREATE_INFO }; - if (out_fence->is_signaled) { - fence_create_info.flags = VK_FENCE_CREATE_SIGNALED_BIT; - } - - vkCreateFence(context->device.logical_device, &fence_create_info, context->allocator, - &out_fence->handle); - } - - // TODO: vulkan_fence_destroy - - bool vulkan_fence_wait(vulkan_context * context, vulkan_fence * fence, u64 timeout_ns) { - if (!fence->is_signaled) { - VkResult result = - vkWaitForFences(context->device.logical_device, 1, &fence->handle, true, timeout_ns); - switch (result) { - case VK_SUCCESS: - fence->is_signaled = true; - return true; - case VK_TIMEOUT: - WARN("vk_fence_wait - Timed out"); - break; - default: - ERROR("vk_fence_wait - Unhanlded error type"); - break; - } - } else { - return true; - } - - return false; - } - void vulkan_fence_reset(vulkan_context * context, vulkan_fence * fence) { - if (fence->is_signaled) { - vkResetFences(context->device.logical_device, 1, &fence->handle); - fence->is_signaled = false; - } - } - - bool gfx_backend_init(renderer * ren) { - INFO("loading Vulkan backend"); - - vulkan_state* internal = malloc(sizeof(vulkan_state)); - ren->backend_state = (void*)internal; - - context.allocator = 0; // TODO: custom allocator - - context.framebuffer_width = SCR_WIDTH; - context.framebuffer_height = SCR_HEIGHT; - - // Setup Vulkan instance - VkApplicationInfo app_info = { VK_STRUCTURE_TYPE_APPLICATION_INFO }; - app_info.apiVersion = VK_API_VERSION_1_3; - app_info.pApplicationName = ren->config.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; - - cstr_darray* required_extensions = cstr_darray_new(2); - cstr_darray_push(required_extensions, VK_KHR_SURFACE_EXTENSION_NAME); - - plat_get_required_extension_names(required_extensions); - -#if defined(CDEBUG) - cstr_darray_push(required_extensions, VK_EXT_DEBUG_UTILS_EXTENSION_NAME); - - DEBUG("Required extensions:"); - for (u32 i = 0; i < cstr_darray_len(required_extensions); i++) { - DEBUG(" %s", required_extensions->data[i]); - } -#endif - - create_info.enabledExtensionCount = cstr_darray_len(required_extensions); - create_info.ppEnabledExtensionNames = required_extensions->data; - - // Validation layers - create_info.enabledLayerCount = 0; - create_info.ppEnabledLayerNames = 0; -#if defined(CDEBUG) - INFO("Validation layers enabled"); - cstr_darray* desired_validation_layers = cstr_darray_new(1); - cstr_darray_push(desired_validation_layers, "VK_LAYER_KHRONOS_validation"); - - u32 n_available_layers = 0; - VK_CHECK(vkEnumerateInstanceLayerProperties(&n_available_layers, 0)); - TRACE("%d available layers", n_available_layers); - VkLayerProperties_darray* available_layers = VkLayerProperties_darray_new(n_available_layers); - VK_CHECK(vkEnumerateInstanceLayerProperties(&n_available_layers, available_layers->data)); - - for (int i = 0; i < cstr_darray_len(desired_validation_layers); i++) { - // look through layers to make sure we can find the ones we want - bool found = false; - for (int j = 0; j < n_available_layers; j++) { - if (str8_equals(str8_cstr_view(desired_validation_layers->data[i]), - str8_cstr_view(available_layers->data[j].layerName))) { - found = true; - TRACE("Found layer %s", desired_validation_layers->data[i]); - break; - } - } - - if (!found) { - FATAL("Required validation is missing %s", desired_validation_layers->data[i]); - return false; - } - } - INFO("All validation layers are present"); - create_info.enabledLayerCount = cstr_darray_len(desired_validation_layers); - create_info.ppEnabledLayerNames = desired_validation_layers->data; -#endif - - VkResult result = vkCreateInstance(&create_info, NULL, &context.instance); - if (result != VK_SUCCESS) { - ERROR("vkCreateInstance failed with result: %u", result); - return false; - } - - // Debugger -#if defined(CDEBUG) - DEBUG("Creating Vulkan debugger") - u32 log_severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT; - VkDebugUtilsMessengerCreateInfoEXT debug_create_info = { - VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT - }; - debug_create_info.messageSeverity = log_severity; - debug_create_info.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT; - debug_create_info.pfnUserCallback = vk_debug_callback; - - PFN_vkCreateDebugUtilsMessengerEXT func = - (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(context.instance, - "vkCreateDebugUtilsMessengerEXT"); - assert(func); - VK_CHECK(func(context.instance, &debug_create_info, context.allocator, &context.vk_debugger)); - DEBUG("Vulkan debugger created"); - -#endif - - // Surface creation - DEBUG("Create SurfaceKHR") - VkSurfaceKHR surface; - VK_CHECK(glfwCreateWindowSurface(context.instance, ren->window, NULL, &surface)); - context.surface = surface; - DEBUG("Vulkan surface created") - - // Device creation - if (!vulkan_device_create(&context)) { - FATAL("device creation failed"); - return false; - } - - // Swapchain creation - vulkan_swapchain_create(&context, SCR_WIDTH, SCR_HEIGHT, &context.swapchain); - - // Renderpass creation - vulkan_renderpass_create(&context, &context.main_renderpass, - vec4(0, 0, context.framebuffer_width, context.framebuffer_height), - rgba_to_vec4(COLOUR_SEA_GREEN), 1.0, 0); - - // Framebiffers creation - context.swapchain.framebuffers = vulkan_framebuffer_darray_new(context.swapchain.image_count); - regenerate_framebuffers(ren, &context.swapchain, &context.main_renderpass); - INFO("Framebuffers created"); - - // Command buffers creation - create_command_buffers(ren); - INFO("Command buffers created"); - - // Sync objects - context.image_available_semaphores = - calloc(context.swapchain.max_frames_in_flight, sizeof(VkSemaphore)); - context.queue_complete_semaphores = - calloc(context.swapchain.max_frames_in_flight, sizeof(VkSemaphore)); - context.in_flight_fences = calloc(context.swapchain.max_frames_in_flight, sizeof(vulkan_fence)); - - for (u8 i = 0; i < context.swapchain.max_frames_in_flight; i++) { - VkSemaphoreCreateInfo semaphore_create_info = { VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO }; - vkCreateSemaphore(context.device.logical_device, &semaphore_create_info, context.allocator, - &context.image_available_semaphores[i]); - vkCreateSemaphore(context.device.logical_device, &semaphore_create_info, context.allocator, - &context.queue_complete_semaphores[i]); - - // create the fence in a signaled state - vulkan_fence_create(&context, true, &context.in_flight_fences[i]); - } - - context.images_in_flight = - malloc(sizeof(vulkan_fence*) * context.swapchain.max_frames_in_flight); - for (u8 i = 0; i < context.swapchain.max_frames_in_flight; i++) { - context.images_in_flight[i] = 0; - } - INFO("Sync objects created"); - - // Shader modules - vulkan_object_shader_create(&context, &context.object_shader); - INFO("Compiled shader modules") - - create_buffers(&context); - INFO("Created buffers"); - - // TODO: temporary test code - - mesh cube = prim_cube_mesh_create(); - - vertex* verts = malloc(sizeof(vertex) * cube.vertices->len); - - f32 scale = 3.0; - for (size_t i = 0; i < cube.vertices->len; i++) { - verts[i].position = vec3_mult(cube.vertices->data[i].position, scale); - verts[i].normal = cube.vertices->data[i].normal; - verts[i].uv = cube.vertices->data[i].uv; - } - - // const f32 s = 1.0; - // const u32 vert_count = 4; - // vertex_pos verts[4] = { 0 }; - - // verts[0].pos.x = -0.5 * s; - // verts[0].pos.y = -0.5 * s; - - // verts[1].pos.x = 0.5 * s; - // verts[1].pos.y = 0.5 * s; - - // verts[2].pos.x = -0.5 * s; - // verts[2].pos.y = 0.5 * s; - - // verts[3].pos.x = 0.5 * s; - // verts[3].pos.y = -0.5 * s; - - // const u32 index_count = 6; - // u32 indices[6] = { 0, 1, 2, 0, 3, 1 }; - - upload_data_range(&context, context.device.gfx_command_pool, 0, context.device.graphics_queue, - &context.object_vertex_buffer, 0, sizeof(vertex) * cube.vertices->len, verts); - TRACE("Uploaded vertex data"); - upload_data_range(&context, context.device.gfx_command_pool, 0, context.device.graphics_queue, - &context.object_index_buffer, 0, sizeof(u32) * cube.indices_len, - cube.indices); - TRACE("Uploaded index data"); - vertex_darray_free(cube.vertices); - free(cube.indices); - - // upload texture - - // --- End test code - - INFO("Vulkan renderer initialisation succeeded"); - return true; - } - - void gfx_backend_shutdown(renderer * ren) { - DEBUG("Destroying Vulkan debugger"); - if (context.vk_debugger) { - PFN_vkDestroyDebugUtilsMessengerEXT func = - (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr( - context.instance, "vkDestroyDebugUtilsMessengerEXT"); - func(context.instance, context.vk_debugger, context.allocator); - } - - DEBUG("Destroying Vulkan instance..."); - vkDestroyInstance(context.instance, context.allocator); - } - - void backend_begin_frame(renderer * ren, f32 delta_time) { - vulkan_device* device = &context.device; - - // TODO: resize gubbins - - if (!vulkan_fence_wait(&context, &context.in_flight_fences[context.current_frame], - UINT64_MAX)) { - WARN("In-flight fence wait failure"); - } - - if (!vulkan_swapchain_acquire_next_image_index( - &context, &context.swapchain, UINT64_MAX, - context.image_available_semaphores[context.current_frame], 0, &context.image_index)) { - WARN("couldnt acquire swapchain next image"); - } - - vulkan_command_buffer* command_buffer = &context.gfx_command_buffers->data[context.image_index]; - vulkan_command_buffer_reset(command_buffer); - vulkan_command_buffer_begin(command_buffer, false, false, false); - - VkViewport viewport; - viewport.x = 0.0; - viewport.y = 0; - viewport.width = (f32)context.framebuffer_width; - viewport.height = (f32)context.framebuffer_height; - viewport.minDepth = 0.0; - viewport.maxDepth = 1.0; - - VkRect2D scissor; - scissor.offset.x = scissor.offset.y = 0; - scissor.extent.width = context.framebuffer_width; - scissor.extent.height = context.framebuffer_height; - - vkCmdSetViewport(command_buffer->handle, 0, 1, &viewport); - vkCmdSetScissor(command_buffer->handle, 0, 1, &scissor); - - context.main_renderpass.render_area.z = context.framebuffer_width; - context.main_renderpass.render_area.w = context.framebuffer_height; - - vulkan_renderpass_begin(command_buffer, &context.main_renderpass, - context.swapchain.framebuffers->data[context.image_index].handle); - } - - void texture_data_upload(texture * tex) { - printf("Texture name %s\n", tex->name); - tex->backend_data = malloc(sizeof(vulkan_texture_data)); - vulkan_texture_data* data = (vulkan_texture_data*)tex->backend_data; - printf("Texture (%s) details: \n width %d\n height %d\n channel count %d\n", tex->name, - tex->width, tex->height, tex->channel_count); - VkDeviceSize image_size = tex->width * tex->height * max(tex->channel_count, 4); - - TRACE("Creating buffer of size %ld", image_size); - - VkFormat image_format = VK_FORMAT_R8G8B8A8_SRGB; - - VkBufferUsageFlags usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; - VkMemoryPropertyFlags memory_prop_flags = - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; - vulkan_buffer staging; - vulkan_buffer_create(&context, image_size, usage, memory_prop_flags, true, &staging); - DEBUG("Uploading image data"); - vulkan_buffer_load_data(&context, &staging, 0, image_size, 0, tex->image_data); - INFO("Loaded iamge data!"); - - vulkan_image_create( - &context, VK_IMAGE_TYPE_2D, tex->width, tex->height, image_format, VK_IMAGE_TILING_OPTIMAL, - VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | - VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, true, VK_IMAGE_ASPECT_COLOR_BIT, &data->image); - - vulkan_command_buffer temp_buffer; - vulkan_command_buffer_allocate_and_begin_oneshot(&context, context.device.gfx_command_pool, - &temp_buffer); - - vulkan_image_transition_layout(&context, &temp_buffer, &data->image, image_format, - VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); - - vulkan_image_copy_from_buffer(&data->image, staging.handle, &temp_buffer); - - vulkan_image_transition_layout(&context, &temp_buffer, &data->image, image_format, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - - vulkan_command_buffer_end_oneshot(&context, context.device.gfx_command_pool, &temp_buffer, - context.device.graphics_queue); - - VkSamplerCreateInfo sampler_info = { VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO }; - sampler_info.magFilter = VK_FILTER_LINEAR; - sampler_info.minFilter = VK_FILTER_LINEAR; - sampler_info.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; - sampler_info.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT; - sampler_info.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; - sampler_info.anisotropyEnable = VK_TRUE; - sampler_info.maxAnisotropy = 16; - sampler_info.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK; - sampler_info.unnormalizedCoordinates = VK_FALSE; - sampler_info.compareEnable = VK_FALSE; - sampler_info.compareOp = VK_COMPARE_OP_ALWAYS; - sampler_info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; - sampler_info.mipLodBias = 0.0; - sampler_info.minLod = 0.0; - sampler_info.maxLod = 0.0; - - VkResult res = vkCreateSampler(context.device.logical_device, &sampler_info, context.allocator, - &data->sampler); - if (res != VK_SUCCESS) { - ERROR("Error creating texture sampler for image %s", tex->name); - return; - } - - tex->image_data = (void*)data; - } - - // TODO: destroy texture - - void backend_end_frame(renderer * ren, f32 delta_time) { - vulkan_command_buffer* command_buffer = &context.gfx_command_buffers->data[context.image_index]; - - vulkan_renderpass_end(command_buffer, &context.main_renderpass); - - vulkan_command_buffer_end(command_buffer); - - // TODO: wait on fence - https://youtu.be/hRL71D1f3pU?si=nLJx-ZsemDBeQiQ1&t=1037 - - context.images_in_flight[context.image_index] = - &context.in_flight_fences[context.current_frame]; - - vulkan_fence_reset(&context, &context.in_flight_fences[context.current_frame]); - - VkSubmitInfo submit_info = { VK_STRUCTURE_TYPE_SUBMIT_INFO }; - submit_info.commandBufferCount = 1; - submit_info.pCommandBuffers = &command_buffer->handle; - submit_info.signalSemaphoreCount = 1; - submit_info.pSignalSemaphores = &context.queue_complete_semaphores[context.current_frame]; - submit_info.waitSemaphoreCount = 1; - submit_info.pWaitSemaphores = &context.image_available_semaphores[context.current_frame]; - - VkPipelineStageFlags flags[1] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT }; - submit_info.pWaitDstStageMask = flags; - - VkResult result = vkQueueSubmit(context.device.graphics_queue, 1, &submit_info, - context.in_flight_fences[context.current_frame].handle); - - if (result != VK_SUCCESS) { - ERROR("queue submission failed. fark."); - } - - vulkan_command_buffer_update_submitted(command_buffer); - - vulkan_swapchain_present( - &context, &context.swapchain, context.device.graphics_queue, context.device.graphics_queue, - context.queue_complete_semaphores[context.current_frame], context.image_index); - } - - void gfx_backend_draw_frame(renderer * ren, camera * cam, mat4 model, texture * tex) { - backend_begin_frame(ren, 16.0); - - mat4 proj; - mat4 view; - - camera_view_projection(cam, SCR_HEIGHT, SCR_WIDTH, &view, &proj); - - context.object_shader.texture_data = (vulkan_texture_data*)tex->image_data; - gfx_backend_update_global_state(proj, view, cam->position, vec4(1.0, 1.0, 1.0, 1.0), 0); - - vulkan_object_shader_update_object(&context, &context.object_shader, model); - - backend_end_frame(ren, 16.0); - } - - void gfx_backend_update_global_state(mat4 projection, mat4 view, vec3 view_pos, - vec4 ambient_colour, i32 mode) { - vulkan_object_shader_use(&context, &context.object_shader); - - vulkan_object_shader_update_global_state(&context, &context.object_shader); - context.object_shader.global_ubo.projection = projection; - context.object_shader.global_ubo.view = view; - // TODO: other UBO properties - } - - void clear_screen(vec3 colour) {} - - void bind_texture(shader s, texture * tex, u32 slot) {} - void bind_mesh_vertex_buffer(void* backend, mesh* mesh) {} - void draw_primitives(cel_primitive_topology primitive, u32 start_index, u32 count) {} - - shader shader_create_separate(const char* vert_shader, const char* frag_shader) {} - void set_shader(shader s) {} - - void uniform_vec3f(u32 program_id, const char* uniform_name, vec3* value) {} - void uniform_f32(u32 program_id, const char* uniform_name, f32 value) {} - void uniform_i32(u32 program_id, const char* uniform_name, i32 value) {} - void uniform_mat4f(u32 program_id, const char* uniform_name, mat4* value) {} - - VKAPI_ATTR VkBool32 VKAPI_CALL vk_debug_callback( - VkDebugUtilsMessageSeverityFlagBitsEXT severity, VkDebugUtilsMessageTypeFlagsEXT flags, - const VkDebugUtilsMessengerCallbackDataEXT* callback_data, void* user_data) { - switch (severity) { - default: - case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT: - ERROR("%s", callback_data->pMessage); - break; - case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT: - WARN("%s", callback_data->pMessage); - break; - case VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT: - INFO("%s", callback_data->pMessage); - break; - case VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT: - TRACE("%s", callback_data->pMessage); - break; - } - return VK_FALSE; - } - -#endif \ No newline at end of file +// --- 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 diff --git a/src/renderer/backends/backend_vulkan.h b/src/renderer/backends/backend_vulkan.h new file mode 100644 index 0000000..05f043e --- /dev/null +++ b/src/renderer/backends/backend_vulkan.h @@ -0,0 +1,27 @@ +#pragma once +#include "defines.h" + +#define GPU_SWAPCHAIN_IMG_COUNT 2 + +typedef struct gpu_swapchain { +} gpu_swapchain; +typedef struct gpu_device { + // In Vulkan we store both physical and logical device here + VkPhysicalDevice physical_device; + VkDevice logical_device; + VkPhysicalDeviceProperties properties; + VkPhysicalDeviceFeatures features; + VkPhysicalDeviceMemoryProperties memory; + VkCommandPool pool; +} gpu_device; +typedef struct gpu_pipeline { +} gpu_pipeline; + +typedef struct gpu_renderpass { + VkRenderPass vk_handle; + 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 diff --git a/src/renderer/cleanroom/backend_vulkan.c b/src/renderer/cleanroom/backend_vulkan.c deleted file mode 100644 index 71a09f3..0000000 --- a/src/renderer/cleanroom/backend_vulkan.c +++ /dev/null @@ -1,65 +0,0 @@ -#include -#include "ral.h" -#include "types.h" -// #include "render_types.h" - -#define VULKAN_QUEUES_COUNT 2 -const char* queue_names[VULKAN_QUEUES_COUNT] = { "GRAPHICS", "TRANSFER" }; - -typedef struct gpu_device { -} gpu_device; - -typedef struct vulkan_context { - gpu_device device; - - VkInstance instance; - -} vulkan_context; - -static vulkan_context context; - -static bool select_physical_device(gpu_device* out_device) {} - -bool gpu_device_create(gpu_device* out_device) { - // Physical device - if (!select_physical_device(out_device)) { - return false; - } - INFO("Physical device selected"); - - // Logical device - VkDeviceQueueCreateInfo queue_create_info[2]; - //.. - VkDeviceCreateInfo device_create_info = { VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO }; - - VkResult result = vkCreateDevice(); - if (result != VK_SUCCESS) { - FATAL("Error creating logical device with status %u\n", result); - exit(1); - } - INFO("Logical device created"); - - // Queues - - // Create the command pool -} - -gpu_renderpass* gpu_renderpass_create() { - // Allocate it - // sets everything up - // return pointer to it -} - -void encode_set_pipeline(gpu_cmd_encoder* encoder, pipeline_type kind, gpu_pipeline* pipeline) { - // VK_PIPELINE_BIND_POINT_GRAPHICS, &shader->pipeline); - if (kind == PIPELINE_GRAPHICS) { - // ... - } else { - // ... - } -} - -// --- 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 diff --git a/src/renderer/cleanroom/backend_vulkan.h b/src/renderer/cleanroom/backend_vulkan.h deleted file mode 100644 index c8d5777..0000000 --- a/src/renderer/cleanroom/backend_vulkan.h +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once -#include "cleanroom/ral.h" - -#define GPU_SWAPCHAIN_IMG_COUNT 2 - -typedef struct gpu_swapchain { -} gpu_swapchain; -typedef struct gpu_device { - // In Vulkan we store both physical and logical device here - VkPhysicalDevice physical_device; - VkDevice logical_device; - VkPhysicalDeviceProperties properties; - VkPhysicalDeviceFeatures features; - VkPhysicalDeviceMemoryProperties memory; - VkCommandPool pool; -} gpu_device; -typedef struct gpu_pipeline { -} gpu_pipeline; - -typedef struct gpu_renderpass { - VkRenderPass vk_handle; - VkFramebuffer framebuffers[GPU_SWAPCHAIN_IMG_COUNT]; - u32 -} gpu_renderpass; - -typedef struct gpu_cmd_encoder { - VkCommandBuffer cmd_buffer; -} gpu_cmd_encoder; \ No newline at end of file diff --git a/src/renderer/cleanroom/immediate.c b/src/renderer/cleanroom/immediate.c deleted file mode 100644 index 8e4bf7e..0000000 --- a/src/renderer/cleanroom/immediate.c +++ /dev/null @@ -1,18 +0,0 @@ -#include "immediate.h" -#include "maths.h" -#include "primitives.h" -#include "render.h" -#include "types.h" - -void imm_draw_sphere(vec3 pos, f32 radius, vec4 colour) { - // Create the vertices - geometry_data geometry = geo_create_uvsphere(radius, 16, 16); - geo_set_vertex_colours(&geometry, colour); - - // Upload to GPU - mat4 model = mat4_translation(pos); - - // Set pipeline - - // Draw -} \ No newline at end of file diff --git a/src/renderer/cleanroom/immediate.h b/src/renderer/cleanroom/immediate.h deleted file mode 100644 index 6d93c53..0000000 --- a/src/renderer/cleanroom/immediate.h +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once - -#include "geometry.h" -#include "maths_types.h" - -// 3. SIMA (simplified immediate mode api) / render.h -// - dont need to worry about uploading mesh data -// - very useful for debugging -void imm_draw_cuboid(vec3 pos, quat rotation, f32x3 extents, vec4 colour); -void imm_draw_sphere(vec3 pos, f32 radius, vec4 colour); -void imm_draw_camera_frustum(); - -// static void imm_draw_model( -// const char* model_filepath); // tracks internally whether the model is loaded - -// static void imm_draw_model(const char* model_filepath) { - // check that model is loaded - // if not loaded, load model and upload to gpu - LRU cache for models - // else submit draw call -// } \ No newline at end of file diff --git a/src/renderer/cleanroom/types.h b/src/renderer/cleanroom/types.h index 0a28b1c..7360ebe 100644 --- a/src/renderer/cleanroom/types.h +++ b/src/renderer/cleanroom/types.h @@ -4,63 +4,3 @@ #include "maths_types.h" #include "str.h" #include "render_types.h" - -// typedef struct transform_hierarchy { -// } transform_hierarchy; - - -/* - - render_types.h - - ral_types.h - - ral.h - - render.h ? -*/ - -/* render_types */ -typedef struct model pbr_material; -typedef struct model bp_material; // blinn-phong - - -// ? How to tie together materials and shaders - -// Three registers -// 1. low level graphics api calls "ral" -// 2. higher level render calls -// 3. simplified immediate mode API - -// 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 - -/* ral.h */ - -// command buffer gubbins - -/* --- Backends */ - -// struct vulkan_backend { -// gpu_pipeline static_opaque_pipeline; -// gpu_pipeline skinned_opaque_pipeline; -// }; - -/* --- Renderer layer */ -/* render.h */ - - -// Drawing - -// void draw_mesh(gpu_cmd_encoder* encoder, mesh* mesh) { -// encode_set_vertex_buffer(encoder, mesh->vertex_buffer); -// encode_set_index_buffer(encoder, mesh->index_buffer); -// encode_draw_indexed(encoder, mesh->index_count) -// // vkCmdDrawIndexed -// } - -// void draw_scene(arena* frame, model_darray* models, renderer* ren, camera* camera, -// transform_hierarchy* tfh, scene* scene) { -// // set the pipeline first -// encode_set_pipeline() -// // in open this sets the shader -// // in vulkan it sets the whole pipeline - -// } \ No newline at end of file diff --git a/src/renderer/immediate.c b/src/renderer/immediate.c new file mode 100644 index 0000000..e76d102 --- /dev/null +++ b/src/renderer/immediate.c @@ -0,0 +1,18 @@ +#include "immediate.h" +#include "maths.h" +#include "primitives.h" +#include "ral_types.h" +#include "render.h" + +void imm_draw_sphere(vec3 pos, f32 radius, vec4 colour) { + // Create the vertices + geometry_data geometry = geo_create_uvsphere(radius, 16, 16); + geo_set_vertex_colours(&geometry, colour); + + // Upload to GPU + mat4 model = mat4_translation(pos); + + // Set pipeline + + // Draw +} \ No newline at end of file diff --git a/src/renderer/immediate.h b/src/renderer/immediate.h new file mode 100644 index 0000000..6d93c53 --- /dev/null +++ b/src/renderer/immediate.h @@ -0,0 +1,20 @@ +#pragma once + +#include "geometry.h" +#include "maths_types.h" + +// 3. SIMA (simplified immediate mode api) / render.h +// - dont need to worry about uploading mesh data +// - very useful for debugging +void imm_draw_cuboid(vec3 pos, quat rotation, f32x3 extents, vec4 colour); +void imm_draw_sphere(vec3 pos, f32 radius, vec4 colour); +void imm_draw_camera_frustum(); + +// static void imm_draw_model( +// const char* model_filepath); // tracks internally whether the model is loaded + +// static void imm_draw_model(const char* model_filepath) { + // check that model is loaded + // if not loaded, load model and upload to gpu - LRU cache for models + // else submit draw call +// } \ No newline at end of file diff --git a/src/renderer/ral.h b/src/renderer/ral.h index fd83e76..fb77f0a 100644 --- a/src/renderer/ral.h +++ b/src/renderer/ral.h @@ -23,10 +23,10 @@ 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 -enum pipeline_kind { - GRAPHICS, - COMPUTE, -}; +typedef enum pipeline_kind { + PIPELINE_GRAPHICS, + PIPELINE_COMPUTE, +} pipeline_kind; typedef struct shader_desc { const char* debug_name; @@ -40,7 +40,7 @@ struct pipeline_desc { }; // lifecycle functions -gpu_device* gpu_device_create(); +gpu_device gpu_device_create(); void gpu_device_destroy(); gpu_renderpass* gpu_renderpass_create(); diff --git a/src/renderer/ral_types.h b/src/renderer/ral_types.h index 9b1ef62..a20e600 100644 --- a/src/renderer/ral_types.h +++ b/src/renderer/ral_types.h @@ -90,4 +90,48 @@ typedef union vertex { KITC_DECL_TYPED_ARRAY(vertex) KITC_DECL_TYPED_ARRAY(u32) #define TYPED_VERTEX_ARRAY -#endif \ No newline at end of file +#endif + +// ? How to tie together materials and shaders + +// Three registers +// 1. low level graphics api calls "ral" +// 2. higher level render calls +// 3. simplified immediate mode API + +// 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 + +/* ral.h */ + +// command buffer gubbins + +/* --- Backends */ + +// struct vulkan_backend { +// gpu_pipeline static_opaque_pipeline; +// gpu_pipeline skinned_opaque_pipeline; +// }; + +/* --- Renderer layer */ +/* render.h */ + + +// Drawing + +// void draw_mesh(gpu_cmd_encoder* encoder, mesh* mesh) { +// encode_set_vertex_buffer(encoder, mesh->vertex_buffer); +// encode_set_index_buffer(encoder, mesh->index_buffer); +// encode_draw_indexed(encoder, mesh->index_count) +// // vkCmdDrawIndexed +// } + +// void draw_scene(arena* frame, model_darray* models, renderer* ren, camera* camera, +// transform_hierarchy* tfh, scene* scene) { +// // set the pipeline first +// encode_set_pipeline() +// // in open this sets the shader +// // in vulkan it sets the whole pipeline + +// } \ No newline at end of file diff --git a/src/renderer/render.c b/src/renderer/render.c index d6b77c0..034585a 100644 --- a/src/renderer/render.c +++ b/src/renderer/render.c @@ -52,4 +52,6 @@ void render_frame_begin(renderer* ren) {} void render_frame_end(renderer* ren) {} void render_frame_draw(renderer* ren) {} -void gfx_backend_draw_frame(renderer* ren, camera* camera, mat4 model, texture* tex) {} \ No newline at end of file +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 diff --git a/src/renderer/render.h b/src/renderer/render.h index 0aeeac2..a5a5928 100644 --- a/src/renderer/render.h +++ b/src/renderer/render.h @@ -40,4 +40,6 @@ void shader_hot_reload(const char* filepath); // models and meshes are implemented **in terms of the above** mesh mesh_create(geometry_data* geometry); -model_handle model_load(const char* debug_name, const char* filepath); \ No newline at end of file +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 diff --git a/src/renderer/render_types.h b/src/renderer/render_types.h index bc9692f..5faefad 100644 --- a/src/renderer/render_types.h +++ b/src/renderer/render_types.h @@ -41,8 +41,6 @@ typedef struct geometry_data { vec3 colour; /** Optional: set vertex colours */ } geometry_data; -void geo_set_vertex_colours(geometry_data* geo, vec4 colour); - typedef struct mesh { buffer_handle vertex_buffer; buffer_handle index_buffer; diff --git a/src/systems/screenspace.h b/src/systems/screenspace.h index f513148..5f0c579 100644 --- a/src/systems/screenspace.h +++ b/src/systems/screenspace.h @@ -25,7 +25,7 @@ struct draw_circle { /** @brief Tagged union that represents a UI shape to be drawn. */ typedef struct draw_cmd { - enum { RECT, CIRCLE } draw_cmd_type; + enum { DRAW_RECT, CIRCLE } draw_cmd_type; union { struct draw_rect rect; struct draw_circle circle; diff --git a/xmake.lua b/xmake.lua index 0fc042c..6fee04a 100644 --- a/xmake.lua +++ b/xmake.lua @@ -1,6 +1,6 @@ set_project("celeritas") set_version("0.1.0") -set_config("cc", "clang") +set_config("cc", "clang-cl") add_rules("mode.debug", "mode.release") -- we have two modes: debug & release @@ -25,6 +25,8 @@ if is_plat("linux") then elseif is_plat("windows") then add_defines("CEL_PLATFORM_WINDOWS") add_syslinks("user32", "gdi32", "kernel32", "shell32") + add_requires("vulkansdk", {system=true}) + -- add_links("pthreadVC2-w64") elseif is_plat("macosx") then add_defines("CEL_PLATFORM_MAC") @@ -55,6 +57,7 @@ local core_sources = { "deps/glad/src/glad.c", "src/*.c", -- "src/logos/*.c", + "src/maths/*.c", "src/platform/*.c", "src/renderer/*.c", "src/renderer/backends/*.c", @@ -84,6 +87,8 @@ rule("compile_glsl_frag_shaders") end) -- TODO: Metal shaders compilation +-- + -- common configuration for both static and shared libraries target("core_config") set_kind("static") -- kind is required but you can ignore it since it's just for common settings @@ -100,7 +105,6 @@ target("core_config") add_includedirs("src/platform/", {public = true}) add_includedirs("src/renderer/", {public = true}) add_includedirs("src/renderer/backends/", {public = true}) - -- add_includedirs("src/renderer/cleanroom/", {public = true}) add_includedirs("src/resources/", {public = true}) add_includedirs("src/std/", {public = true}) add_includedirs("src/std/containers", {public = true}) @@ -111,6 +115,11 @@ target("core_config") -- add_files("assets/shaders/object.vert") -- add_files("assets/shaders/object.frag") -- add_files("assets/shaders/*.frag") + if is_plat("windows") then + add_includedirs("$(env VULKAN_SDK)/Include", {public = true}) + add_linkdirs("$(env VULKAN_SDK)/Lib", {public = true}) + add_links("vulkan-1") + end set_default(false) -- prevents standalone building of this target target("core_static") @@ -132,7 +141,6 @@ target("core_shared") if is_plat("windows") then add_links("msvcrt", "legacy_stdio_definitions") -- for release builds add_links("msvcrtd", "legacy_stdio_definitions") -- for debug builds - -- add_links("pthreadVC2-w64") end target("main_loop") -- cgit v1.2.3-70-g09d2 From aed7d1b7ac340c19656059c9cbd94aff40952f83 Mon Sep 17 00:00:00 2001 From: Omniscient <17525998+omnisci3nce@users.noreply.github.com> Date: Fri, 3 May 2024 21:37:51 +1000 Subject: create logical device --- src/defines.h | 4 +- src/renderer/backends/backend_dx11.h | 1 - src/renderer/backends/backend_vulkan.c | 237 +++++++++++++++++++++++++++++---- src/renderer/backends/vulkan_helpers.h | 42 +++++- src/renderer/bind_group_layouts.h | 4 +- src/renderer/cleanroom/types.h | 2 +- src/renderer/immediate.h | 6 +- src/renderer/ral.h | 7 +- src/renderer/ral_types.h | 14 +- src/renderer/render.h | 2 +- src/renderer/render_types.h | 16 +-- src/renderer/renderpasses.h | 7 +- src/scene.h | 10 +- src/std/buf.h | 6 +- src/std/mem.c | 9 +- src/std/mem.h | 7 + src/systems/terrain.h | 2 +- xmake.lua | 2 +- 18 files changed, 299 insertions(+), 79 deletions(-) (limited to 'src/systems') diff --git a/src/defines.h b/src/defines.h index ec526e0..4b6f8c7 100644 --- a/src/defines.h +++ b/src/defines.h @@ -66,8 +66,8 @@ Renderer backend defines: // Platform will inform renderer backend (unless user overrides) #if defined(CEL_PLATFORM_LINUX) -#define CEL_REND_BACKEND_OPENGL 1 -// #define CEL_REND_BACKEND_VULKAN 1 +// #define CEL_REND_BACKEND_OPENGL 1 +#define CEL_REND_BACKEND_VULKAN 1 #endif #if defined(CEL_PLATFORM_WINDOWS) diff --git a/src/renderer/backends/backend_dx11.h b/src/renderer/backends/backend_dx11.h index 8e3a513..53738aa 100644 --- a/src/renderer/backends/backend_dx11.h +++ b/src/renderer/backends/backend_dx11.h @@ -8,7 +8,6 @@ // typedef struct gpu_swapchain gpu_swapchain; typedef struct gpu_device { - // VkPhysicalDevice physical_device; // VkDevice logical_device; // VkPhysicalDeviceProperties properties; diff --git a/src/renderer/backends/backend_vulkan.c b/src/renderer/backends/backend_vulkan.c index ae857a0..c21a6b9 100644 --- a/src/renderer/backends/backend_vulkan.c +++ b/src/renderer/backends/backend_vulkan.c @@ -5,6 +5,7 @@ #include #include "backend_vulkan.h" +#include "maths_types.h" #include "mem.h" #include "vulkan_helpers.h" @@ -31,6 +32,8 @@ typedef struct vulkan_context { u32 screen_width; u32 screen_height; + + VkDebugUtilsMessengerEXT vk_debugger; } vulkan_context; static vulkan_context context; @@ -39,6 +42,13 @@ static vulkan_context context; /** @brief Enumerates and selects the most appropriate graphics device */ bool select_physical_device(gpu_device* out_device); + +bool is_physical_device_suitable(VkPhysicalDevice device); + +queue_family_indices find_queue_families(VkPhysicalDevice device); + +bool create_logical_device(gpu_device* out_device); + /** @brief Helper function for creating array of all extensions we want */ cstr_darray* get_all_extensions(); @@ -49,7 +59,7 @@ bool gpu_backend_init(const char* window_name, GLFWwindow* window) { // Create an allocator size_t temp_arena_size = 1024 * 1024; - arena_create(malloc(temp_arena_size), temp_arena_size); + context.temp_arena = arena_create(malloc(temp_arena_size), temp_arena_size); // Setup Vulkan instance VkApplicationInfo app_info = { VK_STRUCTURE_TYPE_APPLICATION_INFO }; @@ -63,20 +73,61 @@ bool gpu_backend_init(const char* window_name, GLFWwindow* window) { create_info.pApplicationInfo = &app_info; // Extensions - // FIXME: Use my own extension choices - // cstr_darray* required_extensions = cstr_darray_new(2); + 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; + for (u32 i = 0; i < count; i++) { + cstr_darray_push(required_extensions, extensions[i]); + } + + cstr_darray_push(required_extensions, VK_EXT_DEBUG_UTILS_EXTENSION_NAME); + + DEBUG("Required extensions:"); + for (u32 i = 0; i < cstr_darray_len(required_extensions); i++) { + DEBUG(" %s", required_extensions->data[i]); + } + + create_info.enabledExtensionCount = cstr_darray_len(required_extensions); + create_info.ppEnabledExtensionNames = required_extensions->data; // TODO: Validation layers create_info.enabledLayerCount = 0; create_info.ppEnabledLayerNames = NULL; + INFO("Validation layers enabled"); + cstr_darray* desired_validation_layers = cstr_darray_new(1); + cstr_darray_push(desired_validation_layers, "VK_LAYER_KHRONOS_validation"); + + u32 n_available_layers = 0; + VK_CHECK(vkEnumerateInstanceLayerProperties(&n_available_layers, 0)); + TRACE("%d available layers", n_available_layers); + VkLayerProperties* available_layers = + arena_alloc(&context.temp_arena, n_available_layers * sizeof(VkLayerProperties)); + VK_CHECK(vkEnumerateInstanceLayerProperties(&n_available_layers, available_layers)); + + for (int i = 0; i < cstr_darray_len(desired_validation_layers); i++) { + // look through layers to make sure we can find the ones we want + bool found = false; + for (int j = 0; j < n_available_layers; j++) { + if (str8_equals(str8_cstr_view(desired_validation_layers->data[i]), + str8_cstr_view(available_layers[j].layerName))) { + found = true; + TRACE("Found layer %s", desired_validation_layers->data[i]); + break; + } + } + + if (!found) { + FATAL("Required validation is missing %s", desired_validation_layers->data[i]); + return false; + } + } + INFO("All validation layers are present"); + create_info.enabledLayerCount = cstr_darray_len(desired_validation_layers); + create_info.ppEnabledLayerNames = desired_validation_layers->data; + VkResult result = vkCreateInstance(&create_info, NULL, &context.instance); if (result != VK_SUCCESS) { ERROR("vkCreateInstance failed with result: %u", result); @@ -84,6 +135,25 @@ bool gpu_backend_init(const char* window_name, GLFWwindow* window) { } TRACE("Vulkan Instance created"); + DEBUG("Creating Vulkan debugger"); + u32 log_severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT; + VkDebugUtilsMessengerCreateInfoEXT debug_create_info = { + VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT + }; + debug_create_info.messageSeverity = log_severity; + debug_create_info.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT; + debug_create_info.pfnUserCallback = vk_debug_callback; + + PFN_vkCreateDebugUtilsMessengerEXT func = + (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(context.instance, + "vkCreateDebugUtilsMessengerEXT"); + assert(func); + VK_CHECK(func(context.instance, &debug_create_info, context.allocator, &context.vk_debugger)); + DEBUG("Vulkan Debugger created"); + // Surface creation VkSurfaceKHR surface; VK_CHECK(glfwCreateWindowSurface(context.instance, window, NULL, &surface)); @@ -96,39 +166,43 @@ bool gpu_backend_init(const char* window_name, GLFWwindow* window) { void gpu_backend_shutdown() { arena_free_storage(&context.temp_arena); } bool gpu_device_create(gpu_device* out_device) { + // First things first store this poitner from the renderer + context.device = out_device; + + arena_save savept = arena_savepoint(&context.temp_arena); // Physical device if (!select_physical_device(out_device)) { return false; } TRACE("Physical device selected"); - // Features - VkPhysicalDeviceFeatures device_features = { 0 }; - device_features.samplerAnisotropy = VK_TRUE; // request anistrophy - // Logical device - VkDeviceQueueCreateInfo queue_create_info[2]; - //.. - VkDeviceCreateInfo device_create_info = { VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO }; - device_create_info.queueCreateInfoCount = VULKAN_QUEUES_COUNT; - device_create_info.pQueueCreateInfos = queue_create_info; - device_create_info.pEnabledFeatures = &device_features; - device_create_info.enabledExtensionCount = 1; - const char* extension_names = VK_KHR_SWAPCHAIN_EXTENSION_NAME; - device_create_info.ppEnabledExtensionNames = &extension_names; - - 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); - } - TRACE("Logical device created"); + create_logical_device(out_device); + // VkDeviceQueueCreateInfo queue_create_info = {}; + + // queue_family_indices indices = find_queue_families(context.device->physical_device); + // //.. + // VkDeviceCreateInfo device_create_info = { VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO }; + // device_create_info.queueCreateInfoCount = VULKAN_QUEUES_COUNT; + // device_create_info.pQueueCreateInfos = queue_create_info; + // device_create_info.pEnabledFeatures = &device_features; + // device_create_info.enabledExtensionCount = 1; + // const char* extension_names = VK_KHR_SWAPCHAIN_EXTENSION_NAME; + // device_create_info.ppEnabledExtensionNames = &extension_names; + + // 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); + // } + // TRACE("Logical device created"); // Queues // Create the command pool + arena_rewind(savept); // Free any temp data return true; } @@ -316,4 +390,109 @@ inline void encode_draw_indexed(gpu_cmd_encoder* encoder, u64 index_count) { vkCmdDrawIndexed(encoder->cmd_buffer, index_count, 1, 0, 0, 0); } -bool select_physical_device(gpu_device* out_device) {} \ No newline at end of file +bool select_physical_device(gpu_device* out_device) { + u32 physical_device_count = 0; + VK_CHECK(vkEnumeratePhysicalDevices(context.instance, &physical_device_count, 0)); + if (physical_device_count == 0) { + FATAL("No devices that support vulkan were found"); + return false; + } + TRACE("Number of devices found %d", physical_device_count); + + VkPhysicalDevice* physical_devices = + arena_alloc(&context.temp_arena, physical_device_count * sizeof(VkPhysicalDevice)); + VK_CHECK(vkEnumeratePhysicalDevices(context.instance, &physical_device_count, physical_devices)); + + bool found = false; + for (u32 device_i = 0; device_i < physical_device_count; device_i++) { + if (is_physical_device_suitable(physical_devices[device_i])) { + out_device->physical_device = physical_devices[device_i]; + found = true; + break; + } + } + + if (!found) { + FATAL("Couldn't find a suitable physical device"); + return false; + } + + return true; +} + +bool is_physical_device_suitable(VkPhysicalDevice device) { + VkPhysicalDeviceProperties properties; + vkGetPhysicalDeviceProperties(device, &properties); + + VkPhysicalDeviceFeatures features; + vkGetPhysicalDeviceFeatures(device, &features); + + VkPhysicalDeviceMemoryProperties memory; + vkGetPhysicalDeviceMemoryProperties(device, &memory); + + // TODO: Check against these device properties + + queue_family_indices indices = find_queue_families(device); + + return indices.has_graphics; +} + +queue_family_indices find_queue_families(VkPhysicalDevice device) { + queue_family_indices indices = { 0 }; + + u32 queue_family_count = 0; + vkGetPhysicalDeviceQueueFamilyProperties(device, &queue_family_count, 0); + + VkQueueFamilyProperties* queue_families = + arena_alloc(&context.temp_arena, queue_family_count * sizeof(VkQueueFamilyProperties)); + vkGetPhysicalDeviceQueueFamilyProperties(device, &queue_family_count, queue_families); + + for (u32 queue_i = 0; queue_i < queue_family_count; queue_i++) { + // Graphics queue + if (queue_families[queue_i].queueFlags & VK_QUEUE_GRAPHICS_BIT) { + indices.graphics_queue_index = queue_i; + indices.has_graphics = true; + } + } + + return indices; +} + +bool create_logical_device(gpu_device* out_device) { + queue_family_indices indices = find_queue_families(out_device->physical_device); + + f32 prio_one = 1.0; + VkDeviceQueueCreateInfo queue_create_info = { VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO }; + queue_create_info.queueFamilyIndex = indices.graphics_queue_index; + queue_create_info.queueCount = 1; + queue_create_info.pQueuePriorities = &prio_one; + queue_create_info.flags = 0; + queue_create_info.pNext = 0; + + // Features + VkPhysicalDeviceFeatures device_features = { 0 }; + device_features.samplerAnisotropy = VK_TRUE; // request anistrophy + + // Device itself + VkDeviceCreateInfo device_create_info = { VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO }; + device_create_info.queueCreateInfoCount = 1; + device_create_info.pQueueCreateInfos = &queue_create_info; + device_create_info.pEnabledFeatures = &device_features; + device_create_info.enabledExtensionCount = 1; + const char* extension_names = VK_KHR_SWAPCHAIN_EXTENSION_NAME; + device_create_info.ppEnabledExtensionNames = &extension_names; + + // deprecated + device_create_info.enabledLayerCount = 0; + device_create_info.ppEnabledLayerNames = 0; + + VkResult result = vkCreateDevice(context.device->physical_device, &device_create_info, + context.allocator, &context.device->logical_device); + if (result != VK_SUCCESS) { + printf("error creating logical device with status %u\n", result); + ERROR_EXIT("Unable to create vulkan logical device. Exiting.."); + } + TRACE("Logical device created"); + + return true; +} \ No newline at end of file diff --git a/src/renderer/backends/vulkan_helpers.h b/src/renderer/backends/vulkan_helpers.h index 4bd02f1..baff4e7 100644 --- a/src/renderer/backends/vulkan_helpers.h +++ b/src/renderer/backends/vulkan_helpers.h @@ -20,16 +20,27 @@ static void plat_get_required_extension_names(cstr_darray* extensions) { } // TODO(omni): port to using internal assert functions -#define VK_CHECK(vulkan_expr) \ - do { \ - VkResult res = vulkan_expr; \ - if (res != VK_SUCCESS) { \ +#define VK_CHECK(vulkan_expr) \ + do { \ + VkResult res = vulkan_expr; \ + if (res != VK_SUCCESS) { \ ERROR_EXIT("Vulkan error: %u", res); \ - } \ + } \ } while (0) // TODO: typedef struct vk_debugger {} vk_debugger; +typedef struct queue_family_indices { + u32 graphics_queue_index; + u32 present_queue_index; + u32 compute_queue_index; + u32 transfer_queue_index; + bool has_graphics; + bool has_present; + bool has_compute; + bool has_transfer; +} queue_family_indices; + typedef struct vulkan_physical_device_requirements { bool graphics; bool present; @@ -168,4 +179,25 @@ static bool physical_device_meets_requirements( } return false; +} + +VKAPI_ATTR VkBool32 VKAPI_CALL vk_debug_callback( + VkDebugUtilsMessageSeverityFlagBitsEXT severity, VkDebugUtilsMessageTypeFlagsEXT flags, + const VkDebugUtilsMessengerCallbackDataEXT* callback_data, void* user_data) { + switch (severity) { + default: + case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT: + ERROR("%s", callback_data->pMessage); + break; + case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT: + WARN("%s", callback_data->pMessage); + break; + case VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT: + INFO("%s", callback_data->pMessage); + break; + case VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT: + TRACE("%s", callback_data->pMessage); + break; + } + return VK_FALSE; } \ No newline at end of file diff --git a/src/renderer/bind_group_layouts.h b/src/renderer/bind_group_layouts.h index d163fab..d2571ef 100644 --- a/src/renderer/bind_group_layouts.h +++ b/src/renderer/bind_group_layouts.h @@ -4,9 +4,9 @@ * @brief Common bindgroups (descriptor set layouts) * @version 0.1 * @date 2024-04-28 - * + * * @copyright Copyright (c) 2024 - * + * */ #pragma once #include "defines.h" diff --git a/src/renderer/cleanroom/types.h b/src/renderer/cleanroom/types.h index 7360ebe..6686be5 100644 --- a/src/renderer/cleanroom/types.h +++ b/src/renderer/cleanroom/types.h @@ -2,5 +2,5 @@ #include "darray.h" #include "defines.h" #include "maths_types.h" -#include "str.h" #include "render_types.h" +#include "str.h" diff --git a/src/renderer/immediate.h b/src/renderer/immediate.h index 6d93c53..b9d7c61 100644 --- a/src/renderer/immediate.h +++ b/src/renderer/immediate.h @@ -14,7 +14,7 @@ void imm_draw_camera_frustum(); // const char* model_filepath); // tracks internally whether the model is loaded // static void imm_draw_model(const char* model_filepath) { - // check that model is loaded - // if not loaded, load model and upload to gpu - LRU cache for models - // else submit draw call +// check that model is loaded +// if not loaded, load model and upload to gpu - LRU cache for models +// else submit draw call // } \ No newline at end of file diff --git a/src/renderer/ral.h b/src/renderer/ral.h index 8e49dbe..7c143f2 100644 --- a/src/renderer/ral.h +++ b/src/renderer/ral.h @@ -11,10 +11,10 @@ */ #pragma once -#include "ral_types.h" +#include "buf.h" #include "defines.h" +#include "ral_types.h" #include "str.h" -#include "buf.h" // Unrelated forward declares typedef struct arena arena; @@ -60,7 +60,6 @@ struct graphics_pipeline_desc { }; typedef struct gpu_renderpass_desc { - } gpu_renderpass_desc; // --- Lifecycle functions @@ -97,7 +96,7 @@ void buffer_upload_bytes(buffer_handle gpu_buf, bytebuffer cpu_buf, u64 offset, 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 +void encode_set_bind_group(); // TODO void encode_draw(gpu_cmd_encoder* encoder); void encode_draw_indexed(gpu_cmd_encoder* encoder, u64 index_count); diff --git a/src/renderer/ral_types.h b/src/renderer/ral_types.h index d6c5865..ae54b53 100644 --- a/src/renderer/ral_types.h +++ b/src/renderer/ral_types.h @@ -1,18 +1,18 @@ /** * @file ral_types.h * @author your name (you@domain.com) - * @brief + * @brief * @version 0.1 * @date 2024-04-27 - * + * * @copyright Copyright (c) 2024 - * + * */ #pragma once +#include "darray.h" #include "defines.h" #include "maths_types.h" -#include "darray.h" #ifndef RENDERER_TYPED_HANDLES CORE_DEFINE_HANDLE(buffer_handle); @@ -99,11 +99,7 @@ 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; +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/renderer/render.h b/src/renderer/render.h index a9370e0..e6dd8b8 100644 --- a/src/renderer/render.h +++ b/src/renderer/render.h @@ -10,8 +10,8 @@ */ #pragma once -#include "render_types.h" #include "ral_types.h" +#include "render_types.h" bool renderer_init(renderer* ren); void renderer_shutdown(renderer* ren); diff --git a/src/renderer/render_types.h b/src/renderer/render_types.h index 4866ef4..a5c0c1a 100644 --- a/src/renderer/render_types.h +++ b/src/renderer/render_types.h @@ -1,21 +1,21 @@ /** * @file render_types.h * @author your name (you@domain.com) - * @brief + * @brief * @version 0.1 * @date 2024-04-27 - * + * * @copyright Copyright (c) 2024 - * + * */ #pragma once -#include "ral_types.h" #include "ral.h" +#include "ral_types.h" #if defined(CEL_PLATFORM_WINDOWS) // #include "backend_dx11.h" -#include "backend_vulkan.h" #endif +#include "backend_vulkan.h" struct GLFWwindow; @@ -37,7 +37,7 @@ typedef struct renderer { typedef struct geometry_data { vertex_format format; - vertex_darray* vertices; // TODO: make it not a pointer + vertex_darray* vertices; // TODO: make it not a pointer bool has_indices; u32_darray indices; vec3 colour; /** Optional: set vertex colours */ @@ -66,8 +66,8 @@ typedef struct model { typedef struct texture { u32 texture_id; char name[256]; - void *image_data; - void *backend_data; + void* image_data; + void* backend_data; u32 width; u32 height; u8 channel_count; diff --git a/src/renderer/renderpasses.h b/src/renderer/renderpasses.h index 67badaa..91970d8 100644 --- a/src/renderer/renderpasses.h +++ b/src/renderer/renderpasses.h @@ -4,9 +4,9 @@ * @brief Built-in renderpasses to the engine * @version 0.1 * @date 2024-04-28 - * + * * @copyright Copyright (c) 2024 - * + * */ #pragma once #include "maths_types.h" @@ -25,7 +25,8 @@ typedef struct 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); +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 diff --git a/src/scene.h b/src/scene.h index 2cc4d8a..6cac061 100644 --- a/src/scene.h +++ b/src/scene.h @@ -1,12 +1,12 @@ /** * @file scene.h * @author your name (you@domain.com) - * @brief + * @brief * @version 0.1 * @date 2024-04-27 - * + * * @copyright Copyright (c) 2024 - * + * */ #include "defines.h" #include "types.h" @@ -24,7 +24,7 @@ bool scene_add_point_light(scene* s /* TODO */); bool scene_add_heightmap(scene* s /* TODO */); bool scene_delete_heightmap(scene* s); -bool scene_add_model(scene *s, model_handle model); -void scene_remove_model(scene *s, model_handle model); +bool scene_add_model(scene* s, model_handle model); +void scene_remove_model(scene* s, model_handle model); // TODO: functions to load and save scenes from disk \ No newline at end of file diff --git a/src/std/buf.h b/src/std/buf.h index b0f8b85..de093ec 100644 --- a/src/std/buf.h +++ b/src/std/buf.h @@ -1,12 +1,12 @@ /** * @file buf.h * @author your name (you@domain.com) - * @brief + * @brief * @version 0.1 * @date 2024-04-28 - * + * * @copyright Copyright (c) 2024 - * + * */ #pragma once #include "defines.h" diff --git a/src/std/mem.c b/src/std/mem.c index 5468898..4886d72 100644 --- a/src/std/mem.c +++ b/src/std/mem.c @@ -31,4 +31,11 @@ void arena_free_all(arena* a) { a->curr = a->begin; // pop everything at once and reset to the start. } -void arena_free_storage(arena* a) { free(a->begin); } \ No newline at end of file +void arena_free_storage(arena* a) { free(a->begin); } + +arena_save arena_savepoint(arena* a) { + arena_save savept = { .arena = a, .savepoint = a->curr }; + return savept; +} + +void arena_rewind(arena_save savepoint) { savepoint.arena->curr = savepoint.savepoint; } \ No newline at end of file diff --git a/src/std/mem.h b/src/std/mem.h index 2f92894..bbfb852 100644 --- a/src/std/mem.h +++ b/src/std/mem.h @@ -18,9 +18,16 @@ typedef struct arena { char* end; } arena; +typedef struct arena_save { + arena* arena; + char* savepoint; +} arena_save; + arena arena_create(void* backing_buffer, size_t capacity); void* arena_alloc(arena* a, size_t size); void* arena_alloc_align(arena* a, size_t size, size_t align); void arena_free_all(arena* a); void arena_free_storage(arena* a); +arena_save arena_savepoint(arena* a); +void arena_rewind(arena_save savepoint); // TODO: arena_resize \ No newline at end of file diff --git a/src/systems/terrain.h b/src/systems/terrain.h index 3d6f1c1..a8bff17 100644 --- a/src/systems/terrain.h +++ b/src/systems/terrain.h @@ -29,7 +29,7 @@ typedef struct heightmap { typedef struct terrain_state { arena terrain_allocator; - heightmap* heightmap; // NULL = no heightmap + heightmap* heightmap; // NULL = no heightmap } terrain_state; bool terrain_system_init(terrain_state* state); diff --git a/xmake.lua b/xmake.lua index ab6a7a6..949dd76 100644 --- a/xmake.lua +++ b/xmake.lua @@ -1,6 +1,6 @@ set_project("celeritas") set_version("0.1.0") -set_config("cc", "clang-cl") +set_config("cc", "gcc") add_rules("mode.debug", "mode.release") -- we have two modes: debug & release -- cgit v1.2.3-70-g09d2 From 8c714a082e4b8069b6f1c29e83e09f406f1c965a Mon Sep 17 00:00:00 2001 From: Omniscient <17525998+omnisci3nce@users.noreply.github.com> Date: Sat, 4 May 2024 11:15:49 +1000 Subject: delete cleanroom --- src/renderer/cleanroom/README.md | 1 - src/renderer/cleanroom/renderer.c | 4 ---- src/renderer/cleanroom/renderer.h | 14 -------------- src/renderer/cleanroom/types.h | 6 ------ src/systems/terrain.h | 3 ++- 5 files changed, 2 insertions(+), 26 deletions(-) delete mode 100644 src/renderer/cleanroom/README.md delete mode 100644 src/renderer/cleanroom/renderer.c delete mode 100644 src/renderer/cleanroom/renderer.h delete mode 100644 src/renderer/cleanroom/types.h (limited to 'src/systems') diff --git a/src/renderer/cleanroom/README.md b/src/renderer/cleanroom/README.md deleted file mode 100644 index d510f16..0000000 --- a/src/renderer/cleanroom/README.md +++ /dev/null @@ -1 +0,0 @@ -# Cleanroom / Re-jig of the renderer structure \ No newline at end of file diff --git a/src/renderer/cleanroom/renderer.c b/src/renderer/cleanroom/renderer.c deleted file mode 100644 index a874664..0000000 --- a/src/renderer/cleanroom/renderer.c +++ /dev/null @@ -1,4 +0,0 @@ -#include "defines.h" -#include "render_types.h" - -bool renderer_init() {} \ No newline at end of file diff --git a/src/renderer/cleanroom/renderer.h b/src/renderer/cleanroom/renderer.h deleted file mode 100644 index ff342b0..0000000 --- a/src/renderer/cleanroom/renderer.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -#include "cleanroom/backend_vulkan.h" -#include "cleanroom/ral.h" - -typedef struct renderer2 { - void* backend_state; - gpu_device* device; - gpu_pipeline* static_opaque_pipeline; -} renderer2; - -// mesh -// model -// material \ No newline at end of file diff --git a/src/renderer/cleanroom/types.h b/src/renderer/cleanroom/types.h deleted file mode 100644 index 6686be5..0000000 --- a/src/renderer/cleanroom/types.h +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once -#include "darray.h" -#include "defines.h" -#include "maths_types.h" -#include "render_types.h" -#include "str.h" diff --git a/src/systems/terrain.h b/src/systems/terrain.h index a8bff17..745ca22 100644 --- a/src/systems/terrain.h +++ b/src/systems/terrain.h @@ -15,10 +15,11 @@ Future: - Dynamic LOD */ -#include "cleanroom/types.h" #include "defines.h" #include "maths_types.h" #include "mem.h" +#include "str.h" +#include "render_types.h" typedef struct heightmap { str8 filepath; -- cgit v1.2.3-70-g09d2 From 74fd8a8424aeaccfaf7985f4ad2129fd54ae9fba Mon Sep 17 00:00:00 2001 From: Omniscient <17525998+omnisci3nce@users.noreply.github.com> Date: Sat, 4 May 2024 13:02:31 +1000 Subject: swapchain support --- src/renderer/backends/backend_opengl.c | 2 - src/renderer/backends/backend_vulkan.c | 22 ++++- src/renderer/backends/vulkan_helpers.h | 173 ++++++++++++++++----------------- src/systems/text.h | 1 - 4 files changed, 104 insertions(+), 94 deletions(-) (limited to 'src/systems') diff --git a/src/renderer/backends/backend_opengl.c b/src/renderer/backends/backend_opengl.c index 7fc277f..4cd97b5 100644 --- a/src/renderer/backends/backend_opengl.c +++ b/src/renderer/backends/backend_opengl.c @@ -6,8 +6,6 @@ #include "file.h" #include "log.h" #include "maths_types.h" -// #include "render_types.h" -#include "cleanroom/types.h" #include "ral.h" #if CEL_REND_BACKEND_OPENGL diff --git a/src/renderer/backends/backend_vulkan.c b/src/renderer/backends/backend_vulkan.c index 900b592..08e62bf 100644 --- a/src/renderer/backends/backend_vulkan.c +++ b/src/renderer/backends/backend_vulkan.c @@ -26,6 +26,7 @@ typedef struct vulkan_context { VkInstance instance; VkAllocationCallbacks* allocator; VkSurfaceKHR surface; + vulkan_swapchain_support_info swapchain_support; arena temp_arena; gpu_device* device; @@ -181,6 +182,9 @@ bool gpu_device_create(gpu_device* out_device) { } TRACE("Physical device selected"); + // vulkan_device_query_swapchain_support(out_device->physical_device, context.surface, + // &context.swapchain_support); + // Logical device create_logical_device(out_device); // VkDeviceQueueCreateInfo queue_create_info = {}; @@ -432,6 +436,10 @@ bool select_physical_device(gpu_device* out_device) { return false; } + vkGetPhysicalDeviceProperties(out_device->physical_device, &out_device->properties); + vkGetPhysicalDeviceFeatures(out_device->physical_device, &out_device->features); + vkGetPhysicalDeviceMemoryProperties(out_device->physical_device, &out_device->memory); + return true; } @@ -449,7 +457,10 @@ bool is_physical_device_suitable(VkPhysicalDevice device) { queue_family_indices indices = find_queue_families(device); - return indices.has_graphics && indices.has_present; + vulkan_device_query_swapchain_support(device, context.surface, &context.swapchain_support); + + return indices.has_graphics && indices.has_present && context.swapchain_support.mode_count > 0 && + context.swapchain_support.format_count > 0; } queue_family_indices find_queue_families(VkPhysicalDevice device) { @@ -480,8 +491,17 @@ queue_family_indices find_queue_families(VkPhysicalDevice device) { return indices; } +const char* bool_str(bool input) { return input ? "True" : "False"; } + bool create_logical_device(gpu_device* out_device) { queue_family_indices indices = find_queue_families(out_device->physical_device); + INFO(" %s | %s | %s | %s | %s", bool_str(indices.has_graphics), bool_str(indices.has_present), + bool_str(indices.has_compute), bool_str(indices.has_transfer), + out_device->properties.deviceName); + TRACE("Graphics Family queue index: %d", indices.graphics_family_index); + TRACE("Present Family queue index: %d", indices.present_family_index); + TRACE("Compute Family queue index: %d", indices.compute_family_index); + TRACE("Transfer Family queue index: %d", indices.transfer_family_index); // Queues f32 prio_one = 1.0; diff --git a/src/renderer/backends/vulkan_helpers.h b/src/renderer/backends/vulkan_helpers.h index d91b4a9..03ee814 100644 --- a/src/renderer/backends/vulkan_helpers.h +++ b/src/renderer/backends/vulkan_helpers.h @@ -40,13 +40,6 @@ typedef struct vulkan_physical_device_requirements { bool discrete_gpu; } vulkan_physical_device_requirements; -typedef struct vulkan_physical_device_queue_family_info { - u32 graphics_family_index; - u32 present_family_index; - u32 compute_family_index; - u32 transfer_family_index; -} vulkan_physical_device_queue_family_info; - #define VULKAN_MAX_DEFAULT 32 typedef struct vulkan_swapchain_support_info { @@ -85,89 +78,89 @@ void vulkan_device_query_swapchain_support(VkPhysicalDevice device, VkSurfaceKHR } } -static bool physical_device_meets_requirements( - VkPhysicalDevice device, VkSurfaceKHR surface, const VkPhysicalDeviceProperties* properties, - const VkPhysicalDeviceFeatures* features, - const vulkan_physical_device_requirements* requirements, - vulkan_physical_device_queue_family_info* out_queue_info, - vulkan_swapchain_support_info* out_swapchain_support) { - // TODO: pass in an arena - - out_queue_info->graphics_family_index = -1; - out_queue_info->present_family_index = -1; - out_queue_info->compute_family_index = -1; - out_queue_info->transfer_family_index = -1; - - if (requirements->discrete_gpu) { - if (properties->deviceType != VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) { - TRACE("Device is not a physical GPU. Skipping."); - return false; - } - } - - u32 queue_family_count = 0; - vkGetPhysicalDeviceQueueFamilyProperties(device, &queue_family_count, 0); - VkQueueFamilyProperties queue_families[queue_family_count]; - vkGetPhysicalDeviceQueueFamilyProperties(device, &queue_family_count, queue_families); - - INFO("Graphics | Present | Compute | Transfer | Name"); - u8 min_transfer_score = 255; - for (u32 i = 0; i < queue_family_count; i++) { - u8 current_transfer_score = 0; - - // Graphics queue - if (queue_families[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) { - out_queue_info->graphics_family_index = i; - current_transfer_score++; - } - - // Compute queue - if (queue_families[i].queueFlags & VK_QUEUE_COMPUTE_BIT) { - out_queue_info->compute_family_index = i; - current_transfer_score++; - } - - // Transfer queue - if (queue_families[i].queueFlags & VK_QUEUE_TRANSFER_BIT) { - // always take the lowest score transfer index - if (current_transfer_score <= min_transfer_score) { - min_transfer_score = current_transfer_score; - out_queue_info->transfer_family_index = i; - } - } - - // Present Queue - VkBool32 supports_present = VK_FALSE; - vkGetPhysicalDeviceSurfaceSupportKHR(device, i, surface, &supports_present); - if (supports_present) { - out_queue_info->present_family_index = i; - } - } - - INFO(" %d | %d | %d | %d | %s", - out_queue_info->graphics_family_index != -1, out_queue_info->present_family_index != -1, - out_queue_info->compute_family_index != -1, out_queue_info->transfer_family_index != -1, - properties->deviceName); - TRACE("Graphics Family queue index: %d", out_queue_info->graphics_family_index); - TRACE("Present Family queue index: %d", out_queue_info->present_family_index); - TRACE("Compute Family queue index: %d", out_queue_info->compute_family_index); - TRACE("Transfer Family queue index: %d", out_queue_info->transfer_family_index); - - if ((!requirements->graphics || - (requirements->graphics && out_queue_info->graphics_family_index != -1))) { - INFO("Physical device meets our requirements! Proceed."); - - vulkan_device_query_swapchain_support( - device, surface, out_swapchain_support - - // TODO: error handling i.e. format count = 0 or present mode = 0 - - ); - return true; - } - - return false; -} +// static bool physical_device_meets_requirements( +// VkPhysicalDevice device, VkSurfaceKHR surface, const VkPhysicalDeviceProperties* properties, +// const VkPhysicalDeviceFeatures* features, +// const vulkan_physical_device_requirements* requirements, +// vulkan_physical_device_queue_family_info* out_queue_info, +// vulkan_swapchain_support_info* out_swapchain_support) { +// // TODO: pass in an arena + +// out_queue_info->graphics_family_index = -1; +// out_queue_info->present_family_index = -1; +// out_queue_info->compute_family_index = -1; +// out_queue_info->transfer_family_index = -1; + +// if (requirements->discrete_gpu) { +// if (properties->deviceType != VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) { +// TRACE("Device is not a physical GPU. Skipping."); +// return false; +// } +// } + +// u32 queue_family_count = 0; +// vkGetPhysicalDeviceQueueFamilyProperties(device, &queue_family_count, 0); +// VkQueueFamilyProperties queue_families[queue_family_count]; +// vkGetPhysicalDeviceQueueFamilyProperties(device, &queue_family_count, queue_families); + +// INFO("Graphics | Present | Compute | Transfer | Name"); +// u8 min_transfer_score = 255; +// for (u32 i = 0; i < queue_family_count; i++) { +// u8 current_transfer_score = 0; + +// // Graphics queue +// if (queue_families[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) { +// out_queue_info->graphics_family_index = i; +// current_transfer_score++; +// } + +// // Compute queue +// if (queue_families[i].queueFlags & VK_QUEUE_COMPUTE_BIT) { +// out_queue_info->compute_family_index = i; +// current_transfer_score++; +// } + +// // Transfer queue +// if (queue_families[i].queueFlags & VK_QUEUE_TRANSFER_BIT) { +// // always take the lowest score transfer index +// if (current_transfer_score <= min_transfer_score) { +// min_transfer_score = current_transfer_score; +// out_queue_info->transfer_family_index = i; +// } +// } + +// // Present Queue +// VkBool32 supports_present = VK_FALSE; +// vkGetPhysicalDeviceSurfaceSupportKHR(device, i, surface, &supports_present); +// if (supports_present) { +// out_queue_info->present_family_index = i; +// } +// } + +// INFO(" %d | %d | %d | %d | %s", +// out_queue_info->graphics_family_index != -1, out_queue_info->present_family_index != -1, +// out_queue_info->compute_family_index != -1, out_queue_info->transfer_family_index != -1, +// properties->deviceName); +// TRACE("Graphics Family queue index: %d", out_queue_info->graphics_family_index); +// TRACE("Present Family queue index: %d", out_queue_info->present_family_index); +// TRACE("Compute Family queue index: %d", out_queue_info->compute_family_index); +// TRACE("Transfer Family queue index: %d", out_queue_info->transfer_family_index); + +// if ((!requirements->graphics || +// (requirements->graphics && out_queue_info->graphics_family_index != -1))) { +// INFO("Physical device meets our requirements! Proceed."); + +// vulkan_device_query_swapchain_support( +// device, surface, out_swapchain_support + +// // TODO: error handling i.e. format count = 0 or present mode = 0 + +// ); +// return true; +// } + +// return false; +// } VKAPI_ATTR VkBool32 VKAPI_CALL vk_debug_callback( VkDebugUtilsMessageSeverityFlagBitsEXT severity, VkDebugUtilsMessageTypeFlagsEXT flags, diff --git a/src/systems/text.h b/src/systems/text.h index dc396f0..f40cfd6 100644 --- a/src/systems/text.h +++ b/src/systems/text.h @@ -5,7 +5,6 @@ #include -#include "cleanroom/types.h" #include "darray.h" #include "defines.h" #include "ral.h" -- cgit v1.2.3-70-g09d2 From a51ef12d8583522ee229a0195a4132652f0f9cd8 Mon Sep 17 00:00:00 2001 From: Omniscient <17525998+omnisci3nce@users.noreply.github.com> Date: Sat, 4 May 2024 15:47:54 +1000 Subject: finish swapchain creation --- assets/shaders/triangle.frag | 0 assets/shaders/triangle.vert | 0 src/renderer/backends/backend_vulkan.c | 74 +++++++++++++++++----------------- src/renderer/backends/backend_vulkan.h | 6 +++ src/renderer/backends/vulkan_helpers.h | 19 ++++++++- src/renderer/ral.h | 2 +- src/std/utils.h | 4 ++ src/systems/terrain.h | 2 +- 8 files changed, 66 insertions(+), 41 deletions(-) create mode 100644 assets/shaders/triangle.frag create mode 100644 assets/shaders/triangle.vert create mode 100644 src/std/utils.h (limited to 'src/systems') diff --git a/assets/shaders/triangle.frag b/assets/shaders/triangle.frag new file mode 100644 index 0000000..e69de29 diff --git a/assets/shaders/triangle.vert b/assets/shaders/triangle.vert new file mode 100644 index 0000000..e69de29 diff --git a/src/renderer/backends/backend_vulkan.c b/src/renderer/backends/backend_vulkan.c index 08e62bf..028cde8 100644 --- a/src/renderer/backends/backend_vulkan.c +++ b/src/renderer/backends/backend_vulkan.c @@ -13,7 +13,7 @@ #include "defines.h" #include "log.h" #include "ral.h" -#include "ral_types.h" +#include "utils.h" // TEMP #define SCREEN_WIDTH 1000 @@ -182,32 +182,8 @@ bool gpu_device_create(gpu_device* out_device) { } TRACE("Physical device selected"); - // vulkan_device_query_swapchain_support(out_device->physical_device, context.surface, - // &context.swapchain_support); - - // Logical device + // Logical device & Queues create_logical_device(out_device); - // VkDeviceQueueCreateInfo queue_create_info = {}; - - // queue_family_indices indices = find_queue_families(context.device->physical_device); - // //.. - // VkDeviceCreateInfo device_create_info = { VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO }; - // device_create_info.queueCreateInfoCount = VULKAN_QUEUES_COUNT; - // device_create_info.pQueueCreateInfos = queue_create_info; - // device_create_info.pEnabledFeatures = &device_features; - // device_create_info.enabledExtensionCount = 1; - // const char* extension_names = VK_KHR_SWAPCHAIN_EXTENSION_NAME; - // device_create_info.ppEnabledExtensionNames = &extension_names; - - // 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); - // } - // TRACE("Logical device created"); - - // Queues // Create the command pool @@ -216,29 +192,55 @@ bool gpu_device_create(gpu_device* out_device) { } bool gpu_swapchain_create(gpu_swapchain* out_swapchain) { - VkExtent2D swapchain_extent = { context.screen_width, context.screen_height }; + out_swapchain->swapchain_arena = arena_create(malloc(1024), 1024); + vulkan_swapchain_support_info swapchain_support = context.swapchain_support; - // find a format + // TODO: custom swapchain extents VkExtent2D swapchain_extent = { width, height }; + VkSurfaceFormatKHR image_format = choose_swapchain_format(&swapchain_support); + out_swapchain->image_format = image_format; VkPresentModeKHR present_mode = VK_PRESENT_MODE_FIFO_KHR; // guaranteed to be implemented + out_swapchain->present_mode = present_mode; + + u32 image_count = swapchain_support.capabilities.minImageCount + 1; + out_swapchain->image_count = image_count; VkSwapchainCreateInfoKHR swapchain_create_info = { VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR }; swapchain_create_info.surface = context.surface; - swapchain_create_info.minImageCount = 2; - // TODO: image_ fields + swapchain_create_info.minImageCount = image_count; + swapchain_create_info.imageFormat = image_format.format; + swapchain_create_info.imageColorSpace = image_format.colorSpace; + swapchain_create_info.imageExtent = swapchain_support.capabilities.currentExtent; + swapchain_create_info.imageArrayLayers = 1; + swapchain_create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + swapchain_create_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; swapchain_create_info.queueFamilyIndexCount = 0; - swapchain_create_info.pQueueFamilyIndices = 0; + swapchain_create_info.pQueueFamilyIndices = NULL; - // TODO: preTransform + swapchain_create_info.preTransform = swapchain_support.capabilities.currentTransform; swapchain_create_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; swapchain_create_info.presentMode = present_mode; - swapchain_create_info.clipped = VK_TRUE; - swapchain_create_info.oldSwapchain = 0; + swapchain_create_info.oldSwapchain = VK_NULL_HANDLE; + + out_swapchain->extent = swapchain_support.capabilities.currentExtent; VK_CHECK(vkCreateSwapchainKHR(context.device->logical_device, &swapchain_create_info, context.allocator, &out_swapchain->handle)); TRACE("Vulkan Swapchain created"); + + // Retrieve Images + out_swapchain->images = + arena_alloc(&out_swapchain->swapchain_arena, image_count * sizeof(VkImage)); + VK_CHECK(vkGetSwapchainImagesKHR(context.device->logical_device, out_swapchain->handle, + &image_count, out_swapchain->images)); + + return true; +} + +void gpu_swapchain_destroy(gpu_swapchain* swapchain) { + arena_free_storage(&swapchain->swapchain_arena); + vkDestroySwapchainKHR(context.device, swapchain->handle, context.allocator); } gpu_pipeline* gpu_graphics_pipeline_create(struct graphics_pipeline_desc description) { @@ -482,7 +484,7 @@ queue_family_indices find_queue_families(VkPhysicalDevice device) { VkBool32 present_support = false; vkGetPhysicalDeviceSurfaceSupportKHR(device, q_fam_i, context.surface, &present_support); - if (present_support) { + if (present_support && !indices.has_present) { indices.present_family_index = q_fam_i; indices.has_present = true; } @@ -491,8 +493,6 @@ queue_family_indices find_queue_families(VkPhysicalDevice device) { return indices; } -const char* bool_str(bool input) { return input ? "True" : "False"; } - bool create_logical_device(gpu_device* out_device) { queue_family_indices indices = find_queue_families(out_device->physical_device); INFO(" %s | %s | %s | %s | %s", bool_str(indices.has_graphics), bool_str(indices.has_present), diff --git a/src/renderer/backends/backend_vulkan.h b/src/renderer/backends/backend_vulkan.h index 8c6b772..0114d7a 100644 --- a/src/renderer/backends/backend_vulkan.h +++ b/src/renderer/backends/backend_vulkan.h @@ -28,6 +28,12 @@ typedef struct queue_family_indices { typedef struct gpu_swapchain { VkSwapchainKHR handle; + arena swapchain_arena; + VkExtent2D extent; + VkSurfaceFormatKHR image_format; + VkPresentModeKHR present_mode; + VkImage* images; + u32 image_count; } gpu_swapchain; typedef struct gpu_device { diff --git a/src/renderer/backends/vulkan_helpers.h b/src/renderer/backends/vulkan_helpers.h index 03ee814..55d8846 100644 --- a/src/renderer/backends/vulkan_helpers.h +++ b/src/renderer/backends/vulkan_helpers.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include @@ -54,8 +55,8 @@ VKAPI_ATTR VkBool32 VKAPI_CALL vk_debug_callback( VkDebugUtilsMessageSeverityFlagBitsEXT severity, VkDebugUtilsMessageTypeFlagsEXT flags, const VkDebugUtilsMessengerCallbackDataEXT* callback_data, void* user_data); -void vulkan_device_query_swapchain_support(VkPhysicalDevice device, VkSurfaceKHR surface, - vulkan_swapchain_support_info* out_support_info) { +static void vulkan_device_query_swapchain_support(VkPhysicalDevice device, VkSurfaceKHR surface, + vulkan_swapchain_support_info* out_support_info) { // TODO: add VK_CHECK to these calls! // Surface capabilities @@ -78,6 +79,20 @@ void vulkan_device_query_swapchain_support(VkPhysicalDevice device, VkSurfaceKHR } } +static VkSurfaceFormatKHR choose_swapchain_format( + vulkan_swapchain_support_info* swapchain_support) { + 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]; + if (format.format == VK_FORMAT_B8G8R8A8_SRGB && + format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { + return format; + } + } + return swapchain_support->formats[0]; +} + // static bool physical_device_meets_requirements( // VkPhysicalDevice device, VkSurfaceKHR surface, const VkPhysicalDeviceProperties* properties, // const VkPhysicalDeviceFeatures* features, diff --git a/src/renderer/ral.h b/src/renderer/ral.h index 7c143f2..f202e51 100644 --- a/src/renderer/ral.h +++ b/src/renderer/ral.h @@ -77,7 +77,7 @@ gpu_pipeline* gpu_graphics_pipeline_create(struct graphics_pipeline_desc descrip void gpu_pipeline_destroy(gpu_pipeline* pipeline); bool gpu_swapchain_create(gpu_swapchain* out_swapchain); -void gpu_swapchain_destroy(); +void gpu_swapchain_destroy(gpu_swapchain* swapchain); void gpu_cmd_encoder_begin(); void gpu_cmd_encoder_begin_render(); diff --git a/src/std/utils.h b/src/std/utils.h new file mode 100644 index 0000000..c9827a3 --- /dev/null +++ b/src/std/utils.h @@ -0,0 +1,4 @@ +#pragma once +#include + +const char* bool_str(bool input) { return input ? "True" : "False"; } \ No newline at end of file diff --git a/src/systems/terrain.h b/src/systems/terrain.h index 745ca22..bfd90b5 100644 --- a/src/systems/terrain.h +++ b/src/systems/terrain.h @@ -18,8 +18,8 @@ Future: #include "defines.h" #include "maths_types.h" #include "mem.h" -#include "str.h" #include "render_types.h" +#include "str.h" typedef struct heightmap { str8 filepath; -- cgit v1.2.3-70-g09d2 From 53fe85a463c9c68ec75fa4efb496d1ff864a929e Mon Sep 17 00:00:00 2001 From: Omniscient <17525998+omnisci3nce@users.noreply.github.com> Date: Fri, 10 May 2024 15:44:28 +1000 Subject: add bindings friendly functions --- include/celeritas.h | 8 +++-- src/core.c | 6 +++- src/core.h | 4 +++ src/renderer/render.c | 76 ++++++++++++++++++++++++++++++++++++++------- src/renderer/render_types.h | 2 ++ src/systems/input.c | 1 + 6 files changed, 81 insertions(+), 16 deletions(-) (limited to 'src/systems') diff --git a/include/celeritas.h b/include/celeritas.h index 425436c..9ba741b 100644 --- a/include/celeritas.h +++ b/include/celeritas.h @@ -33,9 +33,9 @@ void core_bringup(); void core_shutdown(); bool should_window_close(); -void render_frame_begin(); -void render_frame_draw(); -void render_frame_end(); +void frame_begin(); +void frame_draw(); +void frame_end(); // Assets model_handle model_load(const char* filepath); @@ -47,6 +47,8 @@ typedef struct render_entity { transform3d transform; } render_entity; +void render_frame_begin(); + // Scene typedef struct directional_light {} directional_light; typedef struct point_light {} point_light; diff --git a/src/core.c b/src/core.c index 17424b3..ffd72a5 100644 --- a/src/core.c +++ b/src/core.c @@ -58,7 +58,7 @@ void core_bringup() { #include -bool should_window_close(core* core) { glfwWindowShouldClose(core->renderer.window); } +/* bool should_window_close(core* core) { glfwWindowShouldClose(core->renderer.window); } */ 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); } @@ -72,3 +72,7 @@ void core_shutdown() { bool should_exit() { return key_just_released(KEYCODE_ESCAPE) || glfwWindowShouldClose(g_core.renderer.window); } + +void frame_begin() { 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 ec8cde9..db711d0 100644 --- a/src/core.h +++ b/src/core.h @@ -31,4 +31,8 @@ void core_bringup(); void core_shutdown(); bool should_exit(); +void frame_begin(); +void frame_draw(); +void frame_end(); + void core_input_update(); diff --git a/src/renderer/render.c b/src/renderer/render.c index f73578e..10589e5 100644 --- a/src/renderer/render.c +++ b/src/renderer/render.c @@ -1,6 +1,7 @@ #include "render.h" #include #include "camera.h" +#include "file.h" #include "log.h" #include "ral.h" @@ -35,20 +36,15 @@ bool renderer_init(renderer* ren) { glfwMakeContextCurrent(ren->window); - DEBUG("Start backend init"); + DEBUG("Start gpu backend init"); - gpu_backend_init("Celeritas Engine - Vulkan", window); + if (!gpu_backend_init("Celeritas Engine - Vulkan", window)) { + FATAL("Couldnt load graphics api backend"); + return false; + } 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"); @@ -58,6 +54,9 @@ bool renderer_init(renderer* ren) { // default_material_init(); + // Create default rendering pipeline + default_pipelines_init(ren); + return true; } void renderer_shutdown(renderer* ren) { @@ -71,10 +70,63 @@ void default_pipelines_init(renderer* ren) { // 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 = {}; + gpu_renderpass* renderpass = gpu_renderpass_create(&pass_description); + + 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_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); + ren->static_opaque_pipeline = *gfx_pipeline; } -void render_frame_begin(renderer* ren) {} -void render_frame_end(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); +} +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(); +} void render_frame_draw(renderer* ren) {} void gfx_backend_draw_frame(renderer* ren, camera* camera, mat4 model, texture* tex) {} diff --git a/src/renderer/render_types.h b/src/renderer/render_types.h index 3763967..06a8415 100644 --- a/src/renderer/render_types.h +++ b/src/renderer/render_types.h @@ -32,7 +32,9 @@ typedef struct renderer { renderer_config config; gpu_device device; gpu_swapchain swapchain; + gpu_renderpass default_renderpass; gpu_pipeline static_opaque_pipeline; + bool frame_aborted; } renderer; typedef struct geometry_data { diff --git a/src/systems/input.c b/src/systems/input.c index fc62db8..5df1159 100644 --- a/src/systems/input.c +++ b/src/systems/input.c @@ -25,6 +25,7 @@ bool input_system_init(input_state *input, GLFWwindow *window) { assert(input->mouse.x_delta == 0); assert(input->mouse.y_delta == 0); + INFO("Finish input init"); return true; } -- 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 'src/systems') 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 634f22e2b6d538fc5a45da2b1b23af631f6f8703 Mon Sep 17 00:00:00 2001 From: omniscient <17525998+omnisci3nce@users.noreply.github.com> Date: Sun, 12 May 2024 15:07:57 +1000 Subject: more restructuring --- examples/cube/ex_cube.c | 5 + src/maths/primitives.c | 265 +++++++++++++++++---------------- src/physics/broadphase.h | 10 ++ src/physics/collision.h | 30 ++++ src/physics/narrowphase.h | 10 ++ src/physics/physics.c | 1 + src/physics/physics.h | 23 +++ src/renderer/backends/backend_vulkan.c | 7 +- src/renderer/backends/metal/README.md | 1 + src/renderer/backends/opengl/README.md | 1 + src/renderer/backends/vulkan/README.md | 1 + src/renderer/ral.h | 4 + src/renderer/ral_types.h | 32 +++- src/renderer/render.h | 2 + src/renderer/standard_vertex_types.c | 11 ++ src/systems/physics.c | 1 - src/systems/physics.h | 41 ----- xmake.lua | 2 + 18 files changed, 274 insertions(+), 173 deletions(-) create mode 100644 src/physics/broadphase.h create mode 100644 src/physics/collision.h create mode 100644 src/physics/narrowphase.h create mode 100644 src/physics/physics.c create mode 100644 src/physics/physics.h create mode 100644 src/renderer/backends/metal/README.md create mode 100644 src/renderer/backends/opengl/README.md create mode 100644 src/renderer/backends/vulkan/README.md create mode 100644 src/renderer/standard_vertex_types.c delete mode 100644 src/systems/physics.c delete mode 100644 src/systems/physics.h (limited to 'src/systems') diff --git a/examples/cube/ex_cube.c b/examples/cube/ex_cube.c index 712485c..a115fe3 100644 --- a/examples/cube/ex_cube.c +++ b/examples/cube/ex_cube.c @@ -52,6 +52,10 @@ int main() { DEBUG("render capacity %d", g_core.default_scene.renderables->capacity); + vertex_description vertex_input = {0}; + vertex_desc_add(&vertex_input, "inPosition", ATTR_F32x2); + vertex_desc_add(&vertex_input, "inColor", ATTR_F32x3); + shader_data mvp_uniforms_data = { .data = NULL, .shader_data_get_layout = &mvp_uniforms_layout }; gpu_renderpass_desc pass_description = {}; @@ -67,6 +71,7 @@ int main() { struct graphics_pipeline_desc pipeline_description = { .debug_name = "Basic Pipeline", + .vertex_desc = vertex_input, .data_layouts = { mvp_uniforms_data }, .data_layouts_count = 1, .vs = { .debug_name = "Triangle Vertex Shader", diff --git a/src/maths/primitives.c b/src/maths/primitives.c index 310fc98..459a535 100644 --- a/src/maths/primitives.c +++ b/src/maths/primitives.c @@ -1,5 +1,6 @@ #include "primitives.h" #include "maths.h" +#include "ral_types.h" // vertices f32 plane_vertex_positions[] = { @@ -30,136 +31,148 @@ static const vec3 FRONT_BOT_RIGHT = (vec3){ 1, 0, 1 }; static const vec3 FRONT_TOP_LEFT = (vec3){ 0, 1, 1 }; static const vec3 FRONT_TOP_RIGHT = (vec3){ 1, 1, 1 }; +#define VERT_3D(arr, pos, norm, uv) \ + { \ + vertex v = { + .static_3d = { \ + .position = pos, \ + .normal = norm, \ + .tex_coords = uv \ + }}; \ + vertex_darray_push(arr, v); \ + } + static mesh prim_cube_mesh_create() { mesh cube = { 0 }; cube.vertices = vertex_darray_new(36); - // // back faces - // vertex_darray_push( - // cube.vertices, - // (vertex){ .position = BACK_BOT_LEFT, .normal = VEC3_NEG_Z, .uv = (vec2){ 0, 1 } }); - // vertex_darray_push( - // cube.vertices, - // (vertex){ .position = BACK_TOP_LEFT, .normal = VEC3_NEG_Z, .uv = (vec2){ 0, 0 } }); - // vertex_darray_push( - // cube.vertices, - // (vertex){ .position = BACK_TOP_RIGHT, .normal = VEC3_NEG_Z, .uv = (vec2){ 1, 0 } }); - // vertex_darray_push( - // cube.vertices, - // (vertex){ .position = BACK_TOP_RIGHT, .normal = VEC3_NEG_Z, .uv = (vec2){ 1, 0 } }); - // vertex_darray_push( - // cube.vertices, - // (vertex){ .position = BACK_BOT_RIGHT, .normal = VEC3_NEG_Z, .uv = (vec2){ 1, 1 } }); - // vertex_darray_push( - // cube.vertices, - // (vertex){ .position = BACK_BOT_LEFT, .normal = VEC3_NEG_Z, .uv = (vec2){ 0, 1 } }); - - // // front faces - // vertex_darray_push( - // cube.vertices, - // (vertex){ .position = FRONT_BOT_LEFT, .normal = VEC3_Z, .uv = (vec2){ 0, 1 } }); - // vertex_darray_push( - // cube.vertices, - // (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_Z, .uv = (vec2){ 1, 0 } }); - // vertex_darray_push( - // cube.vertices, - // (vertex){ .position = FRONT_TOP_LEFT, .normal = VEC3_Z, .uv = (vec2){ 0, 0 } }); - // vertex_darray_push( - // cube.vertices, - // (vertex){ .position = FRONT_BOT_LEFT, .normal = VEC3_Z, .uv = (vec2){ 0, 1 } }); - // vertex_darray_push( - // cube.vertices, - // (vertex){ .position = FRONT_BOT_RIGHT, .normal = VEC3_Z, .uv = (vec2){ 1, 1 } }); - // vertex_darray_push( - // cube.vertices, - // (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_Z, .uv = (vec2){ 1, 0 } }); - - // // top faces - // vertex_darray_push(cube.vertices, - // (vertex){ .position = BACK_TOP_LEFT, .normal = VEC3_Y, .uv = (vec2){ 0, 0 - // } }); - // vertex_darray_push( - // cube.vertices, - // (vertex){ .position = FRONT_TOP_LEFT, .normal = VEC3_Y, .uv = (vec2){ 0, 1 } }); - // vertex_darray_push( - // cube.vertices, - // (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_Y, .uv = (vec2){ 1, 1 } }); - // vertex_darray_push(cube.vertices, - // (vertex){ .position = BACK_TOP_LEFT, .normal = VEC3_Y, .uv = (vec2){ 0, 0 - // } }); - // vertex_darray_push( - // cube.vertices, - // (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_Y, .uv = (vec2){ 1, 1 } }); - // vertex_darray_push( - // cube.vertices, - // (vertex){ .position = BACK_TOP_RIGHT, .normal = VEC3_Y, .uv = (vec2){ 1, 0 } }); - - // // bottom faces - // vertex_darray_push( - // cube.vertices, - // (vertex){ .position = BACK_BOT_LEFT, .normal = VEC3_NEG_Y, .uv = (vec2){ 0 } }); - // vertex_darray_push( - // cube.vertices, - // (vertex){ .position = FRONT_BOT_RIGHT, .normal = VEC3_NEG_Y, .uv = (vec2){ 0 } }); - // vertex_darray_push( - // cube.vertices, - // (vertex){ .position = FRONT_BOT_LEFT, .normal = VEC3_NEG_Y, .uv = (vec2){ 0 } }); - // vertex_darray_push( - // cube.vertices, - // (vertex){ .position = BACK_BOT_LEFT, .normal = VEC3_NEG_Y, .uv = (vec2){ 0 } }); - // vertex_darray_push( - // cube.vertices, - // (vertex){ .position = BACK_BOT_RIGHT, .normal = VEC3_NEG_Y, .uv = (vec2){ 0 } }); - // vertex_darray_push( - // cube.vertices, - // (vertex){ .position = FRONT_BOT_RIGHT, .normal = VEC3_NEG_Y, .uv = (vec2){ 0 } }); - - // // right faces - // vertex_darray_push( - // cube.vertices, - // (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_X, .uv = (vec2){ 0, 0 } }); - // vertex_darray_push( - // cube.vertices, - // (vertex){ .position = BACK_BOT_RIGHT, .normal = VEC3_X, .uv = (vec2){ 1, 1 } }); - // vertex_darray_push( - // cube.vertices, - // (vertex){ .position = BACK_TOP_RIGHT, .normal = VEC3_X, .uv = (vec2){ 1, 0 } }); - // vertex_darray_push( - // cube.vertices, - // (vertex){ .position = BACK_BOT_RIGHT, .normal = VEC3_X, .uv = (vec2){ 1, 1 } }); - // vertex_darray_push( - // cube.vertices, - // (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_X, .uv = (vec2){ 0, 0 } }); - // vertex_darray_push( - // cube.vertices, - // (vertex){ .position = FRONT_BOT_RIGHT, .normal = VEC3_X, .uv = (vec2){ 0, 1 } }); - - // // left faces - // vertex_darray_push( - // cube.vertices, - // (vertex){ .position = FRONT_TOP_LEFT, .normal = VEC3_NEG_X, .uv = (vec2){ 0 } }); - // vertex_darray_push( - // cube.vertices, - // (vertex){ .position = BACK_TOP_LEFT, .normal = VEC3_NEG_X, .uv = (vec2){ 0 } }); - // vertex_darray_push( - // cube.vertices, - // (vertex){ .position = BACK_BOT_LEFT, .normal = VEC3_NEG_X, .uv = (vec2){ 0 } }); - // vertex_darray_push( - // cube.vertices, - // (vertex){ .position = BACK_BOT_LEFT, .normal = VEC3_NEG_X, .uv = (vec2){ 0 } }); - // vertex_darray_push( - // cube.vertices, - // (vertex){ .position = FRONT_BOT_LEFT, .normal = VEC3_NEG_X, .uv = (vec2){ 0 } }); - // vertex_darray_push( - // cube.vertices, - // (vertex){ .position = FRONT_TOP_LEFT, .normal = VEC3_NEG_X, .uv = (vec2){ 0 } }); - - // cube.indices_len = cube.vertices->len; - // cube.indices = malloc(sizeof(u32) * cube.indices_len); - - // for (u32 i = 0; i < cube.indices_len; i++) { - // cube.indices[i] = i; - // } + // back faces + VERT_3D(cube.vertices, BACK_BOT_LEFT, VEC3_NEG_Z, (vec2){ 0, 1 })) + // vertex_darray_push( + // cube.vertices, + // (vertex){ .position = BACK_BOT_LEFT, .normal = VEC3_NEG_Z, .uv = (vec2){ 0, 1 } }); + // vertex_darray_push( + // cube.vertices, + // (vertex){ .position = BACK_TOP_LEFT, .normal = VEC3_NEG_Z, .uv = (vec2){ 0, 0 } }); + // vertex_darray_push( + // cube.vertices, + // (vertex){ .position = BACK_TOP_RIGHT, .normal = VEC3_NEG_Z, .uv = (vec2){ 1, 0 } }); + // vertex_darray_push( + // cube.vertices, + // (vertex){ .position = BACK_TOP_RIGHT, .normal = VEC3_NEG_Z, .uv = (vec2){ 1, 0 } }); + // vertex_darray_push( + // cube.vertices, + // (vertex){ .position = BACK_BOT_RIGHT, .normal = VEC3_NEG_Z, .uv = (vec2){ 1, 1 } }); + // vertex_darray_push( + // cube.vertices, + // (vertex){ .position = BACK_BOT_LEFT, .normal = VEC3_NEG_Z, .uv = (vec2){ 0, 1 } }); + + // front faces + vertex_darray_push( + cube.vertices, + (vertex){ .position = FRONT_BOT_LEFT, .normal = VEC3_Z, .uv = (vec2){ 0, 1 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_Z, .uv = (vec2){ 1, 0 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = FRONT_TOP_LEFT, .normal = VEC3_Z, .uv = (vec2){ 0, 0 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = FRONT_BOT_LEFT, .normal = VEC3_Z, .uv = (vec2){ 0, 1 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = FRONT_BOT_RIGHT, .normal = VEC3_Z, .uv = (vec2){ 1, 1 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_Z, .uv = (vec2){ 1, 0 } }); + + // top faces + vertex_darray_push(cube.vertices, + (vertex){ .position = BACK_TOP_LEFT, .normal = VEC3_Y, .uv = (vec2){ 0, 0 + } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = FRONT_TOP_LEFT, .normal = VEC3_Y, .uv = (vec2){ 0, 1 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_Y, .uv = (vec2){ 1, 1 } }); + vertex_darray_push(cube.vertices, + (vertex){ .position = BACK_TOP_LEFT, .normal = VEC3_Y, .uv = (vec2){ 0, 0 + } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_Y, .uv = (vec2){ 1, 1 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = BACK_TOP_RIGHT, .normal = VEC3_Y, .uv = (vec2){ 1, 0 } }); + + // bottom faces + vertex_darray_push( + cube.vertices, + (vertex){ .position = BACK_BOT_LEFT, .normal = VEC3_NEG_Y, .uv = (vec2){ 0 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = FRONT_BOT_RIGHT, .normal = VEC3_NEG_Y, .uv = (vec2){ 0 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = FRONT_BOT_LEFT, .normal = VEC3_NEG_Y, .uv = (vec2){ 0 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = BACK_BOT_LEFT, .normal = VEC3_NEG_Y, .uv = (vec2){ 0 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = BACK_BOT_RIGHT, .normal = VEC3_NEG_Y, .uv = (vec2){ 0 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = FRONT_BOT_RIGHT, .normal = VEC3_NEG_Y, .uv = (vec2){ 0 } }); + + // right faces + vertex_darray_push( + cube.vertices, + (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_X, .uv = (vec2){ 0, 0 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = BACK_BOT_RIGHT, .normal = VEC3_X, .uv = (vec2){ 1, 1 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = BACK_TOP_RIGHT, .normal = VEC3_X, .uv = (vec2){ 1, 0 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = BACK_BOT_RIGHT, .normal = VEC3_X, .uv = (vec2){ 1, 1 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_X, .uv = (vec2){ 0, 0 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = FRONT_BOT_RIGHT, .normal = VEC3_X, .uv = (vec2){ 0, 1 } }); + + // left faces + vertex_darray_push( + cube.vertices, + (vertex){ .position = FRONT_TOP_LEFT, .normal = VEC3_NEG_X, .uv = (vec2){ 0 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = BACK_TOP_LEFT, .normal = VEC3_NEG_X, .uv = (vec2){ 0 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = BACK_BOT_LEFT, .normal = VEC3_NEG_X, .uv = (vec2){ 0 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = BACK_BOT_LEFT, .normal = VEC3_NEG_X, .uv = (vec2){ 0 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = FRONT_BOT_LEFT, .normal = VEC3_NEG_X, .uv = (vec2){ 0 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = FRONT_TOP_LEFT, .normal = VEC3_NEG_X, .uv = (vec2){ 0 } }); + + cube.indices_len = cube.vertices->len; + cube.indices = malloc(sizeof(u32) * cube.indices_len); + + for (u32 i = 0; i < cube.indices_len; i++) { + cube.indices[i] = i; + } cube.has_indices = true; diff --git a/src/physics/broadphase.h b/src/physics/broadphase.h new file mode 100644 index 0000000..43b57f6 --- /dev/null +++ b/src/physics/broadphase.h @@ -0,0 +1,10 @@ +/** + * @file broadphase.h + * @author your name (you@domain.com) + * @brief + * @version 0.1 + * @date 2024-05-12 + * + * @copyright Copyright (c) 2024 + * + */ \ No newline at end of file diff --git a/src/physics/collision.h b/src/physics/collision.h new file mode 100644 index 0000000..3b65b1b --- /dev/null +++ b/src/physics/collision.h @@ -0,0 +1,30 @@ +/** + * @file collision.h + * @author your name (you@domain.com) + * @brief + * @version 0.1 + * @date 2024-05-12 + * + * @copyright Copyright (c) 2024 + * + */ +#pragma once +#include "geometry.h" + + enum collider_type { + cuboid_collider, + sphere_collider, +}; + +/** @brief generic collider structure */ +typedef struct physics_collider { + u64 id; // ? Replace with handle? + enum collider_type shape; + union collider_data { + cuboid cuboid; + sphere sphere; + } geometry; + transform transform; + u8 layer; + bool on_ground; +} physics_collider; \ No newline at end of file diff --git a/src/physics/narrowphase.h b/src/physics/narrowphase.h new file mode 100644 index 0000000..501c690 --- /dev/null +++ b/src/physics/narrowphase.h @@ -0,0 +1,10 @@ +/** + * @file narrowphase.h + * @author your name (you@domain.com) + * @brief + * @version 0.1 + * @date 2024-05-12 + * + * @copyright Copyright (c) 2024 + * + */ \ No newline at end of file diff --git a/src/physics/physics.c b/src/physics/physics.c new file mode 100644 index 0000000..299c0c1 --- /dev/null +++ b/src/physics/physics.c @@ -0,0 +1 @@ +#include "physics.h" \ No newline at end of file diff --git a/src/physics/physics.h b/src/physics/physics.h new file mode 100644 index 0000000..e0e3b89 --- /dev/null +++ b/src/physics/physics.h @@ -0,0 +1,23 @@ +#pragma once + +#include "geometry.h" +#include "maths_types.h" + +// 'system' means that it gets called per frame + +typedef struct physics_settings { + f32 gravity_strength; +} physics_settings; + +// What else do I need? +// intersection methods + +typedef struct physics_world { + physics_settings settings; +} physics_world; + +physics_world physics_init(physics_settings settings); +void physics_shutdown(physics_world* phys_world); + +/** @brief perform one or more simulation steps */ +void physics_system_update(physics_world* phys_world, f64 deltatime); \ No newline at end of file diff --git a/src/renderer/backends/backend_vulkan.c b/src/renderer/backends/backend_vulkan.c index a845ebf..f83ef84 100644 --- a/src/renderer/backends/backend_vulkan.c +++ b/src/renderer/backends/backend_vulkan.c @@ -393,6 +393,7 @@ gpu_pipeline* gpu_graphics_pipeline_create(struct graphics_pipeline_desc descrip attribute_descs[1].offset = offsetof(custom_vertex, color); // Vertex input + // TODO: Generate this from descroiption now VkVertexInputBindingDescription binding_desc; binding_desc.binding = 0; binding_desc.stride = sizeof(custom_vertex); @@ -819,9 +820,9 @@ void encode_bind_shader_data(gpu_cmd_encoder* encoder, u32 group, shader_data* d alloc_info.pSetLayouts = &encoder->pipeline->desc_set_layouts[group]; VkDescriptorSet sets[1]; - /* VK_CHECK( */ - vkAllocateDescriptorSets(context.device->logical_device, &alloc_info, sets); - /* ); */ + VK_CHECK( + vkAllocateDescriptorSets(context.device->logical_device, &alloc_info, sets) + ); VkDescriptorSet_darray_push(context.free_set_queue, sets[0]); shader_data_layout sdl = data->shader_data_get_layout(NULL); diff --git a/src/renderer/backends/metal/README.md b/src/renderer/backends/metal/README.md new file mode 100644 index 0000000..f87f5c1 --- /dev/null +++ b/src/renderer/backends/metal/README.md @@ -0,0 +1 @@ +# TODO \ No newline at end of file diff --git a/src/renderer/backends/opengl/README.md b/src/renderer/backends/opengl/README.md new file mode 100644 index 0000000..f87f5c1 --- /dev/null +++ b/src/renderer/backends/opengl/README.md @@ -0,0 +1 @@ +# TODO \ No newline at end of file diff --git a/src/renderer/backends/vulkan/README.md b/src/renderer/backends/vulkan/README.md new file mode 100644 index 0000000..220ed64 --- /dev/null +++ b/src/renderer/backends/vulkan/README.md @@ -0,0 +1 @@ +# Vulkan Backend Overview \ No newline at end of file diff --git a/src/renderer/ral.h b/src/renderer/ral.h index 0df23ea..30d5413 100644 --- a/src/renderer/ral.h +++ b/src/renderer/ral.h @@ -54,6 +54,7 @@ typedef struct shader_desc { struct graphics_pipeline_desc { const char* debug_name; + vertex_description vertex_desc; shader_desc vs; /** @brief Vertex shader stage */ shader_desc fs; /** @brief Fragment shader stage */ @@ -150,8 +151,11 @@ void gpu_sampler_create(); // --- Vertex formats bytebuffer vertices_as_bytebuffer(arena* a, vertex_format format, vertex_darray* vertices); +void vertex_desc_add(vertex_description* builder, const char* name, vertex_attrib_type type); + // TODO: Bindgroup texture samplers / shader resources // TEMP void gpu_temp_draw(size_t n_verts); + diff --git a/src/renderer/ral_types.h b/src/renderer/ral_types.h index e7863a9..48695ea 100644 --- a/src/renderer/ral_types.h +++ b/src/renderer/ral_types.h @@ -1,7 +1,7 @@ /** * @file ral_types.h * @author your name (you@domain.com) - * @brief + * @brief Struct and enum definitions for RAL * @version 0.1 * @date 2024-04-27 * @@ -14,6 +14,8 @@ #include "defines.h" #include "maths_types.h" +#define MAX_VERTEX_ATTRIBUTES 16 + #ifndef RENDERER_TYPED_HANDLES CORE_DEFINE_HANDLE(buffer_handle); CORE_DEFINE_HANDLE(texture_handle); @@ -143,19 +145,45 @@ typedef enum vertex_attrib_type { ATTR_I32x4, } vertex_attrib_type; +typedef struct vertex_description { + char* debug_label; + const char* attr_names[MAX_VERTEX_ATTRIBUTES]; + vertex_attrib_type attributes[MAX_VERTEX_ATTRIBUTES]; + size_t stride; +} vertex_description; + +// --- Shaders & Bindings + typedef enum shader_visibility { VISIBILITY_VERTEX = 1 << 0, VISIBILITY_FRAGMENT = 1 << 1 , VISIBILITY_COMPUTE = 1 << 2, } shader_visibility; +/** @brief Describes the kind of binding a `shader_binding` is for. This changes how we create backing data for it. */ typedef enum shader_binding_type { + /** + * @brief Binds a buffer to a shader + * @note Vulkan: Becomes a Storage Buffer + */ SHADER_BINDING_BUFFER, + SHADER_BINDING_BUFFER_ARRAY, SHADER_BINDING_TEXTURE, + SHADER_BINDING_TEXTURE_ARRAY, + SHADER_BINDING_SAMPLER, + /** + * @brief Binds raw data to a shader + * @note Vulkan: Becomes a Uniform Buffer + */ SHADER_BINDING_BYTES, + // TODO: Acceleration Structure SHADER_BINDING_COUNT } shader_binding_type; +// pub trait ShaderBindable: Clone + Copy { +// fn bind_to(&self, context: &mut PipelineContext, index: u32); +// } + typedef struct shader_binding { const char* label; shader_binding_type type; @@ -171,7 +199,7 @@ typedef struct shader_binding { void* data; size_t size; } bytes; - } data; + } data; /** @brief */ } shader_binding; #define MAX_LAYOUT_BINDINGS 8 diff --git a/src/renderer/render.h b/src/renderer/render.h index c690e80..4477121 100644 --- a/src/renderer/render.h +++ b/src/renderer/render.h @@ -44,3 +44,5 @@ 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); + +vertex_description static_3d_vertex_description(); \ No newline at end of file diff --git a/src/renderer/standard_vertex_types.c b/src/renderer/standard_vertex_types.c new file mode 100644 index 0000000..4973bf0 --- /dev/null +++ b/src/renderer/standard_vertex_types.c @@ -0,0 +1,11 @@ +#include "ral.h" +#include "ral_types.h" +#include "render.h" + +vertex_description static_3d_vertex_description() { + vertex_description builder = { .debug_label = "vertex" }; + vertex_desc_add(&builder, "position", ATTR_F32x3); + vertex_desc_add(&builder, "normal", ATTR_F32x3); + vertex_desc_add(&builder, "texCoords", ATTR_F32x2); + return builder; +} \ No newline at end of file diff --git a/src/systems/physics.c b/src/systems/physics.c deleted file mode 100644 index 299c0c1..0000000 --- a/src/systems/physics.c +++ /dev/null @@ -1 +0,0 @@ -#include "physics.h" \ No newline at end of file diff --git a/src/systems/physics.h b/src/systems/physics.h deleted file mode 100644 index 7239ab5..0000000 --- a/src/systems/physics.h +++ /dev/null @@ -1,41 +0,0 @@ -#pragma once - -#include "geometry.h" -#include "maths_types.h" - -// 'system' means that it gets called per frame - -typedef struct physics_settings { - f32 gravity_strength; -} physics_settings; - -enum collider_type { - cuboid_collider, - sphere_collider, -}; - -/** @brief generic collider structure */ -typedef struct physics_collider { - u64 id; // ? Replace with handle? - enum collider_type shape; - union collider_data { - cuboid cuboid; - sphere sphere; - } geometry; - transform transform; - u8 layer; - bool on_ground; -} physics_collider; - -// What else do I need? -// intersection methods - -typedef struct physics_world { - physics_settings settings; -} physics_world; - -physics_world physics_init(physics_settings settings); -void physics_shutdown(physics_world* phys_world); - -/** @brief perform one or more simulation steps */ -void physics_system_update(physics_world* phys_world, f64 deltatime); \ No newline at end of file diff --git a/xmake.lua b/xmake.lua index f1b648b..1d576c7 100644 --- a/xmake.lua +++ b/xmake.lua @@ -59,6 +59,7 @@ local core_sources = { -- "src/logos/*.c", "src/maths/*.c", "src/platform/*.c", + "src/physics/*.c", "src/renderer/*.c", "src/renderer/backends/*.c", "src/resources/*.c", @@ -103,6 +104,7 @@ target("core_config") -- add_includedirs("src/logos/", {public = true}) add_includedirs("src/maths/", {public = true}) add_includedirs("src/platform/", {public = true}) + add_includedirs("src/physics/", {public = true}) add_includedirs("src/renderer/", {public = true}) add_includedirs("src/renderer/backends/", {public = true}) add_includedirs("src/resources/", {public = true}) -- cgit v1.2.3-70-g09d2