From 7d8d503cb458f8addeaa20f61696814cefc2328d Mon Sep 17 00:00:00 2001 From: omniscient <17525998+omnisci3nce@users.noreply.github.com> Date: Fri, 22 Mar 2024 08:29:58 +1100 Subject: misc comments + cleanup --- src/renderer/render.c | 2 +- src/renderer/render.h | 14 ++++++++++++++ src/renderer/render_backend.h | 4 +++- src/renderer/render_types.h | 2 +- 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/renderer/render.c b/src/renderer/render.c index 7884db6..8e67fa6 100644 --- a/src/renderer/render.c +++ b/src/renderer/render.c @@ -38,7 +38,7 @@ bool renderer_init(renderer* ren) { GLFWwindow* window = glfwCreateWindow(ren->config.scr_width, ren->config.scr_height, ren->config.window_name, NULL, NULL); if (window == NULL) { - printf("Failed to create GLFW window\n"); + ERROR("Failed to create GLFW window\n"); glfwTerminate(); return false; } diff --git a/src/renderer/render.h b/src/renderer/render.h index 10702e3..3a06972 100644 --- a/src/renderer/render.h +++ b/src/renderer/render.h @@ -1,3 +1,13 @@ +/** + * @file render.h + * @author your name (you@domain.com) + * @brief Renderer frontend + * @version 0.1 + * @date 2024-03-21 + * + * @copyright Copyright (c) 2024 + * + */ #pragma once #include "camera.h" @@ -10,6 +20,10 @@ bool renderer_init(renderer* ren); /** @brief shutdown the render system frontend */ void renderer_shutdown(renderer* ren); +void renderer_on_resize(renderer *ren); + +struct render_packet; + // --- Frame void render_frame_begin(renderer* ren); diff --git a/src/renderer/render_backend.h b/src/renderer/render_backend.h index 7e1c16c..9644f07 100644 --- a/src/renderer/render_backend.h +++ b/src/renderer/render_backend.h @@ -1,5 +1,5 @@ /** - * @brief + * @brief Renderer backend */ #pragma once @@ -7,6 +7,8 @@ #include "render_types.h" /// --- Lifecycle + +/** @brief Initialise the graphics API backend */ bool gfx_backend_init(renderer* ren); void gfx_backend_shutdown(renderer* ren); diff --git a/src/renderer/render_types.h b/src/renderer/render_types.h index 483e392..02eac6f 100644 --- a/src/renderer/render_types.h +++ b/src/renderer/render_types.h @@ -36,7 +36,7 @@ typedef struct renderer_config { typedef struct renderer { struct GLFWwindow *window; /** Currently all platforms use GLFW*/ - void *backend_state; /** Graphics API-specific state */ + void* backend_state; /** Graphics API-specific state */ renderer_config config; // shaders shader blinn_phong; -- cgit v1.2.3-70-g09d2 From 4fa2db8e3dbcca107af1b6bb027cbcb752199705 Mon Sep 17 00:00:00 2001 From: omniscient <17525998+omnisci3nce@users.noreply.github.com> Date: Fri, 22 Mar 2024 21:09:04 +1100 Subject: swap PCs --- src/renderer/backends/backend_vulkan.c | 23 ++++++++++++++++++++++- src/renderer/render.h | 1 + 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/renderer/backends/backend_vulkan.c b/src/renderer/backends/backend_vulkan.c index 6347e27..bf2234d 100644 --- a/src/renderer/backends/backend_vulkan.c +++ b/src/renderer/backends/backend_vulkan.c @@ -1 +1,22 @@ -// #FUTURE \ No newline at end of file +#define CEL_PLATFORM_LINUX + +#include "defines.h" +#include "file.h" +#include "log.h" +#include "maths_types.h" +#include "render_types.h" + +#include + +#if CEL_REND_BACKEND_VULKAN + +#include + +#include + +typedef struct vulkan_context vulkan_context; +static vulkan_context context; + +/** @brief Internal backend state */ +typedef struct vulkan_state { +} vulkan_state; \ No newline at end of file diff --git a/src/renderer/render.h b/src/renderer/render.h index 3a06972..db74acc 100644 --- a/src/renderer/render.h +++ b/src/renderer/render.h @@ -28,6 +28,7 @@ struct render_packet; void render_frame_begin(renderer* ren); void render_frame_end(renderer* ren); +void render_frame_draw(renderer* ren); // --- models meshes void model_upload_meshes(renderer* ren, model* model); -- cgit v1.2.3-70-g09d2 From df80f2cf0b851b527f715ebfe385dc4930a61512 Mon Sep 17 00:00:00 2001 From: omnisci3nce <17525998+omnisci3nce@users.noreply.github.com> Date: Sat, 23 Mar 2024 12:19:52 +1100 Subject: required extensions and validation layers --- src/core.h | 1 + src/defines.h | 4 +- src/renderer/backends/backend_vulkan.c | 116 ++++++++++++++++++++++++++++++++- src/renderer/backends/vulkan_helpers.h | 19 ++++++ src/renderer/render.h | 17 +---- src/renderer/render_backend.h | 9 +++ src/renderer/render_types.h | 6 +- src/std/containers/darray.h | 44 +++++++------ xmake.lua | 2 +- 9 files changed, 177 insertions(+), 41 deletions(-) create mode 100644 src/renderer/backends/vulkan_helpers.h diff --git a/src/core.h b/src/core.h index 1b3e28b..f54631e 100644 --- a/src/core.h +++ b/src/core.h @@ -8,6 +8,7 @@ #include "threadpool.h" typedef struct core { + // TODO: Add application name renderer renderer; threadpool threadpool; input_state input; diff --git a/src/defines.h b/src/defines.h index 52aa7b0..4459e1a 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) || defined(CEL_PLATFORM_WINDOWS) -#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_MAC) diff --git a/src/renderer/backends/backend_vulkan.c b/src/renderer/backends/backend_vulkan.c index bf2234d..c21dfc2 100644 --- a/src/renderer/backends/backend_vulkan.c +++ b/src/renderer/backends/backend_vulkan.c @@ -1,10 +1,14 @@ +#include "str.h" #define CEL_PLATFORM_LINUX +#include "darray.h" #include "defines.h" #include "file.h" #include "log.h" #include "maths_types.h" +#include "render_backend.h" #include "render_types.h" +#include "vulkan_helpers.h" #include @@ -13,10 +17,118 @@ #include #include +#include +#include + +typedef struct vulkan_context { + VkInstance instance; + VkAllocationCallbacks* allocator; +} vulkan_context; -typedef struct vulkan_context vulkan_context; static vulkan_context context; /** @brief Internal backend state */ typedef struct vulkan_state { -} vulkan_state; \ No newline at end of file +} vulkan_state; + +KITC_DECL_TYPED_ARRAY(VkLayerProperties) + +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 + + // 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(DEBUG) + 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(DEBUG) + 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; + } + + INFO("Vulkan renderer initialisation succeeded"); + return true; +} + +void gfx_backend_shutdown(renderer* ren) {} + +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) {} + +#endif \ No newline at end of file diff --git a/src/renderer/backends/vulkan_helpers.h b/src/renderer/backends/vulkan_helpers.h new file mode 100644 index 0000000..058ea91 --- /dev/null +++ b/src/renderer/backends/vulkan_helpers.h @@ -0,0 +1,19 @@ +#pragma once + +#include +#include + +#include "darray.h" +#include "defines.h" + +DECL_TYPED_ARRAY(const char*, cstr) + +static void plat_get_required_extension_names(cstr_darray* extensions) { +#ifdef CEL_PLATFORM_LINUX + cstr_darray_push(extensions, "VK_KHR_xcb_surface"); +#endif +} + +// TODO(omni): port to using internal assert functions +#define VK_CHECK(vulkan_expr) \ + { assert(vulkan_expr == VK_SUCCESS); } \ No newline at end of file diff --git a/src/renderer/render.h b/src/renderer/render.h index db74acc..6cd9701 100644 --- a/src/renderer/render.h +++ b/src/renderer/render.h @@ -4,9 +4,9 @@ * @brief Renderer frontend * @version 0.1 * @date 2024-03-21 - * + * * @copyright Copyright (c) 2024 - * + * */ #pragma once @@ -20,7 +20,7 @@ bool renderer_init(renderer* ren); /** @brief shutdown the render system frontend */ void renderer_shutdown(renderer* ren); -void renderer_on_resize(renderer *ren); +void renderer_on_resize(renderer* ren); struct render_packet; @@ -38,14 +38,3 @@ void draw_mesh(renderer* ren, mesh* mesh, transform tf, material* mat, mat4* vie // --- texture texture_data_load(const char* path, bool invert_y); // #frontend void texture_data_upload(texture* tex); // #backend - -// --- Uniforms - -/** @brief upload a vec3 of f32 to a uniform */ -void uniform_vec3f(u32 program_id, const char* uniform_name, vec3* value); -/** @brief upload a single f32 to a uniform */ -void uniform_f32(u32 program_id, const char* uniform_name, f32 value); -/** @brief upload a integer to a uniform */ -void uniform_i32(u32 program_id, const char* uniform_name, i32 value); -/** @brief upload a mat4 of f32 to a uniform */ -void uniform_mat4f(u32 program_id, const char* uniform_name, mat4* value); \ No newline at end of file diff --git a/src/renderer/render_backend.h b/src/renderer/render_backend.h index 9644f07..8c351c6 100644 --- a/src/renderer/render_backend.h +++ b/src/renderer/render_backend.h @@ -22,3 +22,12 @@ shader shader_create_separate(const char* vert_shader, const char* frag_shader); void set_shader(shader s); // --- Uniforms + +/** @brief upload a vec3 of f32 to a uniform */ +void uniform_vec3f(u32 program_id, const char* uniform_name, vec3* value); +/** @brief upload a single f32 to a uniform */ +void uniform_f32(u32 program_id, const char* uniform_name, f32 value); +/** @brief upload a integer to a uniform */ +void uniform_i32(u32 program_id, const char* uniform_name, i32 value); +/** @brief upload a mat4 of f32 to a uniform */ +void uniform_mat4f(u32 program_id, const char* uniform_name, mat4* value); \ No newline at end of file diff --git a/src/renderer/render_types.h b/src/renderer/render_types.h index 02eac6f..7bb6e60 100644 --- a/src/renderer/render_types.h +++ b/src/renderer/render_types.h @@ -34,9 +34,13 @@ typedef struct renderer_config { 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 */ + void *backend_state; /** Graphics API-specific state */ renderer_config config; // shaders shader blinn_phong; diff --git a/src/std/containers/darray.h b/src/std/containers/darray.h index 25bf846..8eb00cb 100644 --- a/src/std/containers/darray.h +++ b/src/std/containers/darray.h @@ -39,15 +39,17 @@ /* } else {\ */ /* }\ */ -#define KITC_DECL_TYPED_ARRAY(T) \ - typedef typed_array(T) T##_darray; \ - typedef typed_array_iterator(T) T##_darray_iter; \ +#define KITC_DECL_TYPED_ARRAY(T) DECL_TYPED_ARRAY(T, T) + +#define DECL_TYPED_ARRAY(T, Type) \ + typedef typed_array(T) Type##_darray; \ + typedef typed_array_iterator(Type) Type##_darray_iter; \ \ /* Create a new one growable array */ \ - PREFIX T##_darray *T##_darray_new(size_t starting_capacity) { \ - T##_darray *d; \ + PREFIX Type##_darray *Type##_darray_new(size_t starting_capacity) { \ + Type##_darray *d; \ T *data; \ - d = malloc(sizeof(T##_darray)); \ + d = malloc(sizeof(Type##_darray)); \ data = malloc(starting_capacity * sizeof(T)); \ \ d->len = 0; \ @@ -57,14 +59,14 @@ return d; \ } \ \ - PREFIX void T##_darray_free(T##_darray *d) { \ + PREFIX void Type##_darray_free(Type##_darray *d) { \ if (d != NULL) { \ free(d->data); \ free(d); \ } \ } \ \ - PREFIX T *T##_darray_resize(T##_darray *d, size_t capacity) { \ + PREFIX T *Type##_darray_resize(Type##_darray *d, size_t capacity) { \ /* resize the internal data block */ \ T *new_data = realloc(d->data, sizeof(T) * capacity); \ /* TODO: handle OOM error */ \ @@ -74,22 +76,22 @@ return new_data; \ } \ \ - PREFIX void T##_darray_push(T##_darray *d, T value) { \ + PREFIX void Type##_darray_push(Type##_darray *d, T value) { \ if (d->len >= d->capacity) { \ size_t new_capacity = \ d->capacity > 0 ? d->capacity * DARRAY_RESIZE_FACTOR : DARRAY_DEFAULT_CAPACITY; \ - T *resized = T##_darray_resize(d, new_capacity); \ + T *resized = Type##_darray_resize(d, new_capacity); \ } \ \ d->data[d->len] = value; \ d->len += 1; \ } \ \ - PREFIX void T##_darray_push_copy(T##_darray *d, const T *value) { \ + PREFIX void Type##_darray_push_copy(Type##_darray *d, const T *value) { \ if (d->len >= d->capacity) { \ size_t new_capacity = \ d->capacity > 0 ? d->capacity * DARRAY_RESIZE_FACTOR : DARRAY_DEFAULT_CAPACITY; \ - T *resized = T##_darray_resize(d, new_capacity); \ + T *resized = Type##_darray_resize(d, new_capacity); \ } \ \ T *place = d->data + d->len; \ @@ -97,18 +99,18 @@ memcpy(place, value, sizeof(T)); \ } \ \ - PREFIX void T##_darray_pop(T##_darray *d, T *dest) { \ + PREFIX void Type##_darray_pop(Type##_darray *d, T *dest) { \ T *item = d->data + (d->len - 1); \ d->len -= 1; \ memcpy(dest, item, sizeof(T)); \ } \ \ - PREFIX void T##_darray_ins(T##_darray *d, const T *value, size_t index) { \ + PREFIX void Type##_darray_ins(Type##_darray *d, const T *value, size_t index) { \ /* check if requires resize */ \ if (d->len + 1 > d->capacity) { \ size_t new_capacity = \ d->capacity > 0 ? d->capacity * DARRAY_RESIZE_FACTOR : DARRAY_DEFAULT_CAPACITY; \ - T *resized = T##_darray_resize(d, new_capacity); \ + T *resized = Type##_darray_resize(d, new_capacity); \ } \ \ /* shift existing data after index */ \ @@ -122,14 +124,14 @@ memcpy(insert_dest, value, sizeof(T)); \ } \ \ - PREFIX void T##_darray_clear(T##_darray *d) { \ + PREFIX void Type##_darray_clear(Type##_darray *d) { \ d->len = 0; \ memset(d->data, 0, d->capacity * sizeof(T)); \ } \ \ - PREFIX size_t T##_darray_len(T##_darray *d) { return d->len; } \ + PREFIX size_t Type##_darray_len(Type##_darray *d) { return d->len; } \ \ - PREFIX void T##_darray_print(T##_darray *d) { \ + PREFIX void Type##_darray_print(Type##_darray *d) { \ printf("len: %zu ", d->len); \ printf("capacity: %zu\n", d->capacity); \ for (int i = 0; i < d->len; i++) { \ @@ -137,14 +139,14 @@ } \ } \ \ - PREFIX T##_darray_iter T##_darray_iter_new(T##_darray *d) { \ - T##_darray_iter iterator; \ + PREFIX Type##_darray_iter Type##_darray_iter_new(Type##_darray *d) { \ + Type##_darray_iter iterator; \ iterator.array = d; \ iterator.current_idx = 0; \ return iterator; \ } \ \ - PREFIX void *T##_darray_iter_next(T##_darray_iter *iterator) { \ + PREFIX void *Type##_darray_iter_next(Type##_darray_iter *iterator) { \ if (iterator->current_idx < iterator->array->len) { \ return &iterator->array->data[iterator->current_idx++]; \ } else { \ diff --git a/xmake.lua b/xmake.lua index 611b537..386f3bb 100644 --- a/xmake.lua +++ b/xmake.lua @@ -22,7 +22,7 @@ end -- Platform defines and system packages if is_plat("linux") then add_defines("CEL_PLATFORM_LINUX") - add_syslinks("dl", "X11", "pthread") + add_syslinks("vulkan", "dl", "X11", "pthread") elseif is_plat("windows") then add_defines("CEL_PLATFORM_WINDOWS") elseif is_plat("macosx") then -- cgit v1.2.3-70-g09d2 From 411992fad179c4e45d044cd3dab86dc460ce15ac Mon Sep 17 00:00:00 2001 From: omnisci3nce <17525998+omnisci3nce@users.noreply.github.com> Date: Sat, 23 Mar 2024 17:53:42 +1100 Subject: vk debugger and physical device selection omg. --- src/renderer/backends/backend_vulkan.c | 176 ++++++++++++++++++++++++++++++++- src/renderer/backends/vulkan_helpers.h | 149 +++++++++++++++++++++++++++- src/renderer/render.c | 6 +- 3 files changed, 325 insertions(+), 6 deletions(-) diff --git a/src/renderer/backends/backend_vulkan.c b/src/renderer/backends/backend_vulkan.c index c21dfc2..481792a 100644 --- a/src/renderer/backends/backend_vulkan.c +++ b/src/renderer/backends/backend_vulkan.c @@ -1,5 +1,9 @@ -#include "str.h" #define CEL_PLATFORM_LINUX +#include +#include +#include +#include +#include "str.h" #include "darray.h" #include "defines.h" @@ -17,12 +21,29 @@ #include #include -#include -#include + +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; + VkPhysicalDeviceProperties properties; + VkPhysicalDeviceFeatures features; + VkPhysicalDeviceMemoryProperties memory; +} vulkan_device; typedef struct vulkan_context { VkInstance instance; VkAllocationCallbacks* allocator; + VkSurfaceKHR surface; + vulkan_device device; + +#if defined(DEBUG) + VkDebugUtilsMessengerEXT vk_debugger; +#endif } vulkan_context; static vulkan_context context; @@ -33,6 +54,85 @@ typedef struct vulkan_state { KITC_DECL_TYPED_ARRAY(VkLayerProperties) +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* ctx) { + if (!select_physical_device(ctx)) { + return false; + } + + return true; +} +void vulkan_device_destroy(vulkan_context* ctx) {} + bool gfx_backend_init(renderer* ren) { INFO("loading Vulkan backend"); @@ -111,11 +211,58 @@ bool gfx_backend_init(renderer* ren) { return false; } + // Debugger +#if defined(DEBUG) + 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; + } + INFO("Vulkan renderer initialisation succeeded"); return true; } -void gfx_backend_shutdown(renderer* ren) {} +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 clear_screen(vec3 colour) {} @@ -131,4 +278,25 @@ 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(callback_data.pMessage); + break; + case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT: + WARN(callback_data.pMessage); + break; + case VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT: + INFO(callback_data.pMessage); + break; + case VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT: + TRACE(callback_data.pMessage); + break; + } + return VK_FALSE; +} + #endif \ No newline at end of file diff --git a/src/renderer/backends/vulkan_helpers.h b/src/renderer/backends/vulkan_helpers.h index 058ea91..8f4d48a 100644 --- a/src/renderer/backends/vulkan_helpers.h +++ b/src/renderer/backends/vulkan_helpers.h @@ -2,9 +2,14 @@ #include #include +#include #include "darray.h" #include "defines.h" +#include "log.h" +#include "str.h" + +#define VULKAN_PHYS_DEVICE_MAX_EXTENSION_NAMES 36 DECL_TYPED_ARRAY(const char*, cstr) @@ -16,4 +21,146 @@ static void plat_get_required_extension_names(cstr_darray* extensions) { // TODO(omni): port to using internal assert functions #define VK_CHECK(vulkan_expr) \ - { assert(vulkan_expr == VK_SUCCESS); } \ No newline at end of file + { assert(vulkan_expr == VK_SUCCESS); } + +// TODO: typedef struct vk_debugger {} vk_debugger; + +typedef struct vulkan_physical_device_requirements { + bool graphics; + bool present; + bool compute; + bool transfer; + str8 device_ext_names[VULKAN_PHYS_DEVICE_MAX_EXTENSION_NAMES]; + size_t device_ext_name_count; + bool sampler_anistropy; + 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 { + VkSurfaceCapabilitiesKHR capabilities; + VkSurfaceFormatKHR formats[VULKAN_MAX_DEFAULT]; + u32 format_count; + VkPresentModeKHR present_modes[VULKAN_MAX_DEFAULT]; + u32 mode_count; +} vulkan_swapchain_support_info; + +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) { + // TODO: add VK_CHECK to these calls! + + // Surface capabilities + vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, surface, &out_support_info->capabilities); + + // Surface formats + vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &out_support_info->format_count, + 0); // Get number of formats + if (out_support_info->format_count > 0) { + vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &out_support_info->format_count, + out_support_info->formats); + } + + // Present Modes + vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &out_support_info->mode_count, + 0); // Get number of formats + if (out_support_info->mode_count > 0) { + vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &out_support_info->mode_count, + out_support_info->present_modes); + } +} + +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; +} \ No newline at end of file diff --git a/src/renderer/render.c b/src/renderer/render.c index 8e67fa6..45762d4 100644 --- a/src/renderer/render.c +++ b/src/renderer/render.c @@ -28,11 +28,14 @@ bool renderer_init(renderer* ren) { // NOTE: all platforms use GLFW at the moment but thats subject to change glfwInit(); - DEBUG("init graphics api (OpenGL) backend"); +#if defined(CEL_REND_BACKEND_OPENGL) glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); +#elif defined(CEL_REND_BACKEND_VULKAN) + glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); +#endif // glfw window creation GLFWwindow* window = glfwCreateWindow(ren->config.scr_width, ren->config.scr_height, @@ -46,6 +49,7 @@ bool renderer_init(renderer* ren) { glfwMakeContextCurrent(ren->window); + DEBUG("init graphics api backend"); if (!gfx_backend_init(ren)) { FATAL("Couldnt load graphics api backend"); return false; -- cgit v1.2.3-70-g09d2 From b1e9a0f5e8731226d6dde11a5aabe002fa1a6a7d Mon Sep 17 00:00:00 2001 From: omnisci3nce <17525998+omnisci3nce@users.noreply.github.com> Date: Sat, 23 Mar 2024 21:40:56 +1100 Subject: fix vulkan debug callback --- src/renderer/backends/vulkan_helpers.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/renderer/backends/vulkan_helpers.h b/src/renderer/backends/vulkan_helpers.h index 8f4d48a..3465aed 100644 --- a/src/renderer/backends/vulkan_helpers.h +++ b/src/renderer/backends/vulkan_helpers.h @@ -55,7 +55,7 @@ typedef struct vulkan_swapchain_support_info { VKAPI_ATTR VkBool32 VKAPI_CALL vk_debug_callback( VkDebugUtilsMessageSeverityFlagBitsEXT severity, VkDebugUtilsMessageTypeFlagsEXT flags, - const VkDebugUtilsMessengerCallbackDataEXT callback_data, void* user_data); + const VkDebugUtilsMessengerCallbackDataEXT* callback_data, void* user_data); void vulkan_device_query_swapchain_support(VkPhysicalDevice device, VkSurfaceKHR surface, vulkan_swapchain_support_info* out_support_info) { -- cgit v1.2.3-70-g09d2 From 81ea3b4ebb0163570a3f113701840772c55fb11a Mon Sep 17 00:00:00 2001 From: omnisci3nce <17525998+omnisci3nce@users.noreply.github.com> Date: Sat, 23 Mar 2024 21:47:01 +1100 Subject: temporarily ignore compute queue need to understand the family queue indexes more, as it was complaining about present and compute both having index 2 --- src/renderer/backends/backend_vulkan.c | 85 ++++++++++++++++++++++++++++++---- 1 file changed, 77 insertions(+), 8 deletions(-) diff --git a/src/renderer/backends/backend_vulkan.c b/src/renderer/backends/backend_vulkan.c index 481792a..c17637f 100644 --- a/src/renderer/backends/backend_vulkan.c +++ b/src/renderer/backends/backend_vulkan.c @@ -30,6 +30,10 @@ typedef struct vulkan_device { i32 present_queue_index; i32 compute_queue_index; i32 transfer_queue_index; + VkQueue graphics_queue; + VkQueue present_queue; + VkQueue compute_queue; + VkQueue transfer_queue; VkPhysicalDeviceProperties properties; VkPhysicalDeviceFeatures features; VkPhysicalDeviceMemoryProperties memory; @@ -124,14 +128,79 @@ bool select_physical_device(vulkan_context* ctx) { return true; } -bool vulkan_device_create(vulkan_context* ctx) { - if (!select_physical_device(ctx)) { +bool vulkan_device_create(vulkan_context* context) { + // Physical device - NOTE: mutates the context directly + if (!select_physical_device(context)) { return false; } + TRACE("HERE"); + +// Logical device - NOTE: mutates the context directly + +// queues +#define VULKAN_QUEUES_COUNT 3 + const char* queue_names[VULKAN_QUEUES_COUNT] = { "GRAPHICS", "PRESENT", + // "COMPUTE", + "TRANSFER" }; + i32 indices[VULKAN_QUEUES_COUNT] = { context->device.graphics_queue_index, + context->device.present_queue_index, + // context->device.compute_queue_index, + context->device.transfer_queue_index }; + VkDeviceQueueCreateInfo + queue_create_info[VULKAN_QUEUES_COUNT]; // one for each of graphics,present,compute,transfer + for (int i = 0; i < VULKAN_QUEUES_COUNT; 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); + return true; } -void vulkan_device_destroy(vulkan_context* ctx) {} +void vulkan_device_destroy(vulkan_context* context) { + context->device.physical_device = 0; // release + // TODO: reset other memory +} bool gfx_backend_init(renderer* ren) { INFO("loading Vulkan backend"); @@ -280,20 +349,20 @@ 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) { + const VkDebugUtilsMessengerCallbackDataEXT* callback_data, void* user_data) { switch (severity) { default: case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT: - ERROR(callback_data.pMessage); + ERROR("%s", callback_data->pMessage); break; case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT: - WARN(callback_data.pMessage); + WARN("%s", callback_data->pMessage); break; case VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT: - INFO(callback_data.pMessage); + INFO("%s", callback_data->pMessage); break; case VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT: - TRACE(callback_data.pMessage); + TRACE("%s", callback_data->pMessage); break; } return VK_FALSE; -- cgit v1.2.3-70-g09d2 From 014c833c5b2a5fda31164ba71ab51fba868c1d86 Mon Sep 17 00:00:00 2001 From: omnisci3nce <17525998+omnisci3nce@users.noreply.github.com> Date: Sun, 24 Mar 2024 09:57:21 +1100 Subject: creating swapchain --- src/renderer/backends/backend_vulkan.c | 145 +++++++++++++++++++++++++++++++-- 1 file changed, 139 insertions(+), 6 deletions(-) diff --git a/src/renderer/backends/backend_vulkan.c b/src/renderer/backends/backend_vulkan.c index c17637f..1f1f6f7 100644 --- a/src/renderer/backends/backend_vulkan.c +++ b/src/renderer/backends/backend_vulkan.c @@ -1,3 +1,4 @@ +#include #define CEL_PLATFORM_LINUX #include #include @@ -39,11 +40,25 @@ typedef struct vulkan_device { VkPhysicalDeviceMemoryProperties memory; } vulkan_device; +typedef struct vulkan_swapchain { + VkSurfaceFormatKHR image_format; + u8 max_frames_in_flight; + VkSwapchainKHR handle; + u32 image_count; + VkImage* images; + VkImageView* views; +} vulkan_swapchain; + typedef struct vulkan_context { VkInstance instance; VkAllocationCallbacks* allocator; VkSurfaceKHR surface; vulkan_device device; + vulkan_swapchain swapchain; + u32 image_index; + u32 current_frame; + + // TODO: swapchain recreation #if defined(DEBUG) VkDebugUtilsMessengerEXT vk_debugger; @@ -134,18 +149,16 @@ bool vulkan_device_create(vulkan_context* context) { return false; } - TRACE("HERE"); - // Logical device - NOTE: mutates the context directly // queues #define VULKAN_QUEUES_COUNT 3 - const char* queue_names[VULKAN_QUEUES_COUNT] = { "GRAPHICS", "PRESENT", - // "COMPUTE", - "TRANSFER" }; + const char* queue_names[VULKAN_QUEUES_COUNT] = { "GRAPHICS", "PRESENT", + // "COMPUTE", + "TRANSFER" }; i32 indices[VULKAN_QUEUES_COUNT] = { context->device.graphics_queue_index, context->device.present_queue_index, - // context->device.compute_queue_index, + // context->device.compute_queue_index, context->device.transfer_queue_index }; VkDeviceQueueCreateInfo queue_create_info[VULKAN_QUEUES_COUNT]; // one for each of graphics,present,compute,transfer @@ -202,6 +215,126 @@ void vulkan_device_destroy(vulkan_context* context) { // TODO: reset other memory } +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 + 1; + + 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; + 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; + + 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.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])); + } +} + +// 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) { + FATAL("Failed to present swapchain iamge"); + } +} + bool gfx_backend_init(renderer* ren) { INFO("loading Vulkan backend"); -- cgit v1.2.3-70-g09d2 From 8b9094ff517126ed102b79425e5fe4c67c589e47 Mon Sep 17 00:00:00 2001 From: omnisci3nce <17525998+omnisci3nce@users.noreply.github.com> Date: Sun, 24 Mar 2024 15:50:47 +1100 Subject: swapchain creation and main renderpass --- src/maths/maths.h | 2 + src/renderer/backends/backend_vulkan.c | 294 ++++++++++++++++++++++++++++++++- src/std/containers/darray.h | 4 + 3 files changed, 298 insertions(+), 2 deletions(-) diff --git a/src/maths/maths.h b/src/maths/maths.h index d832739..6816415 100644 --- a/src/maths/maths.h +++ b/src/maths/maths.h @@ -52,6 +52,8 @@ static inline vec3 vec3_cross(vec3 a, vec3 b) { static inline vec2 vec2_create(f32 x, f32 y) { return (vec2){ x, y }; } // TODO: Dimension 4 +static inline vec4 vec4_create(f32 x, f32 y, f32 z, f32 w) { return (vec4){ x, y, z, w }; } +#define vec4(x, y, z, w) (vec4_create(x, y, z, w)) #define VEC4_ZERO ((vec4){ .x = 0.0, .y = 0.0, .z = 0.0, .w = 0.0 }) // --- Quaternion Implementations diff --git a/src/renderer/backends/backend_vulkan.c b/src/renderer/backends/backend_vulkan.c index 1f1f6f7..ba12696 100644 --- a/src/renderer/backends/backend_vulkan.c +++ b/src/renderer/backends/backend_vulkan.c @@ -1,4 +1,5 @@ #include +#include #define CEL_PLATFORM_LINUX #include #include @@ -10,6 +11,7 @@ #include "defines.h" #include "file.h" #include "log.h" +#include "maths.h" #include "maths_types.h" #include "render_backend.h" #include "render_types.h" @@ -17,6 +19,9 @@ #include +#define SCR_WIDTH 1080 +#define SCR_HEIGHT 800 + #if CEL_REND_BACKEND_VULKAN #include @@ -38,8 +43,35 @@ typedef struct vulkan_device { 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 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_swapchain { VkSurfaceFormatKHR image_format; u8 max_frames_in_flight; @@ -47,14 +79,29 @@ typedef struct vulkan_swapchain { u32 image_count; VkImage* images; VkImageView* views; + vulkan_image depth_attachment; } vulkan_swapchain; +typedef enum vulkan_command_buffer_state { + COMMAND_BUFFER_STATE_READY, + COMMAND_BUFFER_STATE_IN_RENDER_PASS, + COMMAND_BUFFER_STATE_RECORDING, +} vulkan_command_buffer_state; + +typedef struct vulkan_command_buffer { + VkCommandBuffer handle; + vulkan_command_buffer_state state; +} vulkan_command_buffer; + 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; u32 image_index; u32 current_frame; @@ -215,6 +262,109 @@ void vulkan_device_destroy(vulkan_context* context) { // 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_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 = 4; + 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; + + 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_swapchain_create(vulkan_context* context, u32 width, u32 height, vulkan_swapchain* out_swapchain) { VkExtent2D swapchain_extent = { width, height }; @@ -261,8 +411,9 @@ void vulkan_swapchain_create(vulkan_context* context, u32 width, u32 height, swapchain_create_info.clipped = VK_TRUE; swapchain_create_info.oldSwapchain = 0; - vkCreateSwapchainKHR(context->device.logical_device, &swapchain_create_info, context->allocator, - &out_swapchain->handle); + TRACE("Create swapchain"); + VK_CHECK(vkCreateSwapchainKHR(context->device.logical_device, &swapchain_create_info, + context->allocator, &out_swapchain->handle)); context->current_frame = 0; @@ -285,6 +436,7 @@ void vulkan_swapchain_create(vulkan_context* context, u32 width, u32 height, 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; @@ -294,6 +446,19 @@ void vulkan_swapchain_create(vulkan_context* context, u32 width, u32 height, 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 @@ -335,6 +500,123 @@ void vulkan_swapchain_present(vulkan_context* context, vulkan_swapchain* swapcha } } +void vulkan_renderpass_create(vulkan_context* context, vulkan_renderpass* out_renderpass, + vec4 render_area, vec4 clear_colour, f32 depth, u32 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 gfx_backend_init(renderer* ren) { INFO("loading Vulkan backend"); @@ -449,6 +731,14 @@ bool gfx_backend_init(renderer* ren) { 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), + vec4(0.0, 0.0, 0.2, 1.0), 1.0, 0); + INFO("Vulkan renderer initialisation succeeded"); return true; } diff --git a/src/std/containers/darray.h b/src/std/containers/darray.h index 8eb00cb..45d92e2 100644 --- a/src/std/containers/darray.h +++ b/src/std/containers/darray.h @@ -5,6 +5,10 @@ */ // COPIED FROM KITC WITH SOME MINOR ADJUSTMENTS +/* TODO: + - a 'find' function that takes a predicate (maybe wrap with a macro so we dont have to define a new function?) +*/ + #ifndef KITC_TYPED_ARRAY_H #define KITC_TYPED_ARRAY_H -- cgit v1.2.3-70-g09d2 From ce14deef131d3f4e11af6a1817fa1b786201ea12 Mon Sep 17 00:00:00 2001 From: omnisci3nce <17525998+omnisci3nce@users.noreply.github.com> Date: Sun, 24 Mar 2024 21:46:48 +1100 Subject: command pool and allocate command buffers --- src/renderer/backends/backend_vulkan.c | 102 ++++++++++++++++++++++++++++++++- 1 file changed, 100 insertions(+), 2 deletions(-) diff --git a/src/renderer/backends/backend_vulkan.c b/src/renderer/backends/backend_vulkan.c index ba12696..f6fc505 100644 --- a/src/renderer/backends/backend_vulkan.c +++ b/src/renderer/backends/backend_vulkan.c @@ -28,6 +28,8 @@ #include +KITC_DECL_TYPED_ARRAY(VkLayerProperties) + typedef struct vulkan_device { VkPhysicalDevice physical_device; VkDevice logical_device; @@ -40,6 +42,7 @@ typedef struct vulkan_device { VkQueue present_queue; VkQueue compute_queue; VkQueue transfer_queue; + VkCommandPool gfx_command_pool; VkPhysicalDeviceProperties properties; VkPhysicalDeviceFeatures features; VkPhysicalDeviceMemoryProperties memory; @@ -86,6 +89,9 @@ 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 { @@ -93,6 +99,8 @@ typedef struct vulkan_command_buffer { vulkan_command_buffer_state state; } vulkan_command_buffer; +KITC_DECL_TYPED_ARRAY(vulkan_command_buffer) + typedef struct vulkan_context { VkInstance instance; VkAllocationCallbacks* allocator; @@ -102,6 +110,8 @@ typedef struct vulkan_context { u32 framebuffer_height; vulkan_swapchain swapchain; vulkan_renderpass main_renderpass; + vulkan_command_buffer_darray* gfx_command_buffers; + u32 image_index; u32 current_frame; @@ -118,8 +128,6 @@ static vulkan_context context; typedef struct vulkan_state { } vulkan_state; -KITC_DECL_TYPED_ARRAY(VkLayerProperties) - bool select_physical_device(vulkan_context* ctx) { u32 physical_device_count = 0; VK_CHECK(vkEnumeratePhysicalDevices(ctx->instance, &physical_device_count, 0)); @@ -255,6 +263,14 @@ bool vulkan_device_create(vulkan_context* context) { 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) { @@ -365,6 +381,74 @@ void vulkan_image_create(vulkan_context* context, VkImageType image_type, u32 wi // TODO: vulkan_image_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_swapchain_create(vulkan_context* context, u32 width, u32 height, vulkan_swapchain* out_swapchain) { VkExtent2D swapchain_extent = { width, height }; @@ -617,6 +701,17 @@ void vulkan_renderpass_end(vulkan_command_buffer* command_buffer, vulkan_renderp command_buffer->state = COMMAND_BUFFER_STATE_RECORDING; } +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]); + } +} + bool gfx_backend_init(renderer* ren) { INFO("loading Vulkan backend"); @@ -739,6 +834,9 @@ bool gfx_backend_init(renderer* ren) { vec4(0, 0, context.framebuffer_width, context.framebuffer_height), vec4(0.0, 0.0, 0.2, 1.0), 1.0, 0); + // Command buffers creation + create_command_buffers(ren); + INFO("Vulkan renderer initialisation succeeded"); return true; } -- cgit v1.2.3-70-g09d2 From 98ed693b25ba383e5f5fe9f9edcde58f0aafb471 Mon Sep 17 00:00:00 2001 From: omnisci3nce <17525998+omnisci3nce@users.noreply.github.com> Date: Sun, 24 Mar 2024 21:54:16 +1100 Subject: wip: framebuffer struct --- src/renderer/backends/backend_vulkan.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/renderer/backends/backend_vulkan.c b/src/renderer/backends/backend_vulkan.c index f6fc505..88cc87b 100644 --- a/src/renderer/backends/backend_vulkan.c +++ b/src/renderer/backends/backend_vulkan.c @@ -122,6 +122,10 @@ typedef struct vulkan_context { #endif } vulkan_context; +typedef struct vulkan_framebuffer { + // TODO: struct members +} vulkan_framebuffer; + static vulkan_context context; /** @brief Internal backend state */ -- cgit v1.2.3-70-g09d2 From e847ee50647a35b1c9b3d5d7661417be2517f373 Mon Sep 17 00:00:00 2001 From: omniscient <17525998+omnisci3nce@users.noreply.github.com> Date: Mon, 25 Mar 2024 17:49:12 +1100 Subject: wip: framebuffer creation --- src/renderer/backends/backend_vulkan.c | 62 +++++++++++++++++++++++++++++++--- 1 file changed, 58 insertions(+), 4 deletions(-) diff --git a/src/renderer/backends/backend_vulkan.c b/src/renderer/backends/backend_vulkan.c index 88cc87b..6e80861 100644 --- a/src/renderer/backends/backend_vulkan.c +++ b/src/renderer/backends/backend_vulkan.c @@ -75,6 +75,15 @@ typedef struct vulkan_renderpass { 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; @@ -83,6 +92,7 @@ typedef struct vulkan_swapchain { VkImage* images; VkImageView* views; vulkan_image depth_attachment; + vulkan_framebuffer_darray* framebuffers; } vulkan_swapchain; typedef enum vulkan_command_buffer_state { @@ -122,10 +132,6 @@ typedef struct vulkan_context { #endif } vulkan_context; -typedef struct vulkan_framebuffer { - // TODO: struct members -} vulkan_framebuffer; - static vulkan_context context; /** @brief Internal backend state */ @@ -385,6 +391,36 @@ void vulkan_image_create(vulkan_context* context, VkImageType image_type, u32 wi // 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 = {}; // TODO + + framebuffer_create_info.renderPass = renderpass->handle; + // TODO: fill out info - https://youtu.be/Is6CwlsaCFE?si=86ZGxU7S8licijCD&t=252 + + 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 }; @@ -716,6 +752,20 @@ void create_command_buffers(renderer* ren) { } } +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 + }; + + vulkan_framebuffer_create(context, + renderpass, context.framebuffer_width, context.framebuffer_height, 2, attachments, swapchain->framebuffers->data[i]); + } +} + bool gfx_backend_init(renderer* ren) { INFO("loading Vulkan backend"); @@ -838,6 +888,10 @@ bool gfx_backend_init(renderer* ren) { vec4(0, 0, context.framebuffer_width, context.framebuffer_height), vec4(0.0, 0.0, 0.2, 1.0), 1.0, 0); + // Framebiffers creation + context.swapchain.framebuffers = vulkan_framebuffer_darray_new(context.swapchain.image_count); + regenerate_framebuffers(ren, &context.swapchain, &context.main_renderpass); + // Command buffers creation create_command_buffers(ren); -- cgit v1.2.3-70-g09d2 From d3e977d6461738ca19d427f99a428b9fa537a26c Mon Sep 17 00:00:00 2001 From: omniscient <17525998+omnisci3nce@users.noreply.github.com> Date: Mon, 25 Mar 2024 17:49:23 +1100 Subject: chore: format --- src/renderer/backends/backend_vulkan.c | 36 ++++++++++++---------------------- 1 file changed, 13 insertions(+), 23 deletions(-) diff --git a/src/renderer/backends/backend_vulkan.c b/src/renderer/backends/backend_vulkan.c index 6e80861..407053a 100644 --- a/src/renderer/backends/backend_vulkan.c +++ b/src/renderer/backends/backend_vulkan.c @@ -391,14 +391,9 @@ void vulkan_image_create(vulkan_context* context, VkImageType image_type, u32 wi // 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 -) { +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]; @@ -406,17 +401,13 @@ void vulkan_framebuffer_create( out_framebuffer->attachment_count = attachment_count; out_framebuffer->renderpass = renderpass; - VkFramebufferCreateInfo framebuffer_create_info = {}; // TODO + VkFramebufferCreateInfo framebuffer_create_info = {}; // TODO framebuffer_create_info.renderPass = renderpass->handle; // TODO: fill out info - https://youtu.be/Is6CwlsaCFE?si=86ZGxU7S8licijCD&t=252 - vkCreateFramebuffer( - context->device.logical_device, - &framebuffer_create_info, - context->allocator, - &out_framebuffer->handle - ); + vkCreateFramebuffer(context->device.logical_device, &framebuffer_create_info, context->allocator, + &out_framebuffer->handle); } // TODO: vulkan_framebuffer_destroy @@ -752,17 +743,16 @@ void create_command_buffers(renderer* ren) { } } -void regenerate_framebuffers(renderer* ren, vulkan_swapchain* swapchain, vulkan_renderpass* renderpass) { +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 + u32 attachment_count = 2; // one for depth, one for colour - VkImageView attachments[2] = { - swapchain->views[i], - swapchain->depth_attachment - }; + VkImageView attachments[2] = { swapchain->views[i], swapchain->depth_attachment }; - vulkan_framebuffer_create(context, - renderpass, context.framebuffer_width, context.framebuffer_height, 2, attachments, swapchain->framebuffers->data[i]); + vulkan_framebuffer_create(context, renderpass, context.framebuffer_width, + context.framebuffer_height, 2, attachments, + swapchain->framebuffers->data[i]); } } -- cgit v1.2.3-70-g09d2 From 8752fe1132f0fb19a7ac90dd257417a088e32100 Mon Sep 17 00:00:00 2001 From: omnisci3nce <17525998+omnisci3nce@users.noreply.github.com> Date: Mon, 25 Mar 2024 20:43:37 +1100 Subject: sync objects --- src/renderer/backends/backend_vulkan.c | 103 +++++++++++++++++++++++++++++++-- 1 file changed, 97 insertions(+), 6 deletions(-) diff --git a/src/renderer/backends/backend_vulkan.c b/src/renderer/backends/backend_vulkan.c index 407053a..81a08e2 100644 --- a/src/renderer/backends/backend_vulkan.c +++ b/src/renderer/backends/backend_vulkan.c @@ -111,6 +111,11 @@ typedef struct vulkan_command_buffer { KITC_DECL_TYPED_ARRAY(vulkan_command_buffer) +typedef struct vulkan_fence { + VkFence handle; + bool is_signaled; +} vulkan_fence; + typedef struct vulkan_context { VkInstance instance; VkAllocationCallbacks* allocator; @@ -122,6 +127,12 @@ typedef struct vulkan_context { vulkan_renderpass main_renderpass; 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; @@ -394,17 +405,23 @@ void vulkan_image_create(vulkan_context* context, VkImageType image_type, u32 wi 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); + 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 = {}; // TODO + VkFramebufferCreateInfo framebuffer_create_info = { + VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO + }; // TODO framebuffer_create_info.renderPass = renderpass->handle; - // TODO: fill out info - https://youtu.be/Is6CwlsaCFE?si=86ZGxU7S8licijCD&t=252 + 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); @@ -613,6 +630,9 @@ void vulkan_swapchain_present(vulkan_context* context, vulkan_swapchain* swapcha if (result != VK_SUCCESS) { 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, @@ -748,11 +768,52 @@ void regenerate_framebuffers(renderer* ren, vulkan_swapchain* swapchain, 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 }; + VkImageView attachments[2] = { swapchain->views[i], swapchain->depth_attachment.view }; - vulkan_framebuffer_create(context, renderpass, context.framebuffer_width, + vulkan_framebuffer_create(&context, renderpass, context.framebuffer_width, context.framebuffer_height, 2, attachments, - swapchain->framebuffers->data[i]); + &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; } } @@ -764,6 +825,9 @@ bool gfx_backend_init(renderer* ren) { 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; @@ -881,9 +945,36 @@ bool gfx_backend_init(renderer* ren) { // 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 = + malloc(sizeof(VkSemaphore) * context.swapchain.max_frames_in_flight); + context.queue_complete_semaphores = + malloc(sizeof(VkSemaphore) * context.swapchain.max_frames_in_flight); + context.in_flight_fences = malloc(sizeof(vulkan_fence) * context.swapchain.max_frames_in_flight); + + 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"); INFO("Vulkan renderer initialisation succeeded"); return true; -- cgit v1.2.3-70-g09d2 From 9e120a48438c793e8f23fab000189d4af1068eee Mon Sep 17 00:00:00 2001 From: omnisci3nce <17525998+omnisci3nce@users.noreply.github.com> Date: Mon, 25 Mar 2024 23:29:18 +1100 Subject: clearing the screen with a clear color! --- examples/main_loop/ex_main_loop.c | 3 + src/colours.h | 2 + src/renderer/backends/backend_vulkan.c | 101 +++++++++++++++++++++++++++++++-- src/renderer/render_backend.h | 2 + 4 files changed, 104 insertions(+), 4 deletions(-) diff --git a/examples/main_loop/ex_main_loop.c b/examples/main_loop/ex_main_loop.c index 3b2354a..728290f 100644 --- a/examples/main_loop/ex_main_loop.c +++ b/examples/main_loop/ex_main_loop.c @@ -2,6 +2,7 @@ #include "core.h" #include "render.h" +#include "render_backend.h" int main() { core* core = core_bringup(); @@ -13,6 +14,8 @@ int main() { render_frame_begin(&core->renderer); + gfx_backend_draw_frame(&core->renderer); + // insert work here render_frame_end(&core->renderer); diff --git a/src/colours.h b/src/colours.h index bbd9476..fa5f54b 100644 --- a/src/colours.h +++ b/src/colours.h @@ -12,6 +12,8 @@ typedef struct rgba { #define COLOUR_SEA_GREEN ((rgba){ 0.18, 0.77, 0.71, 1.0 }) #define COLOUR_WHITE ((rgba){ 1.0, 1.0, 1.0, 1.0 }) +#define rgba_to_vec4(color) (vec4(color.r, color.g, color.b, color.a)) + // Thanks ChatGPT #define STONE_50 ((rgba){ 0.980, 0.980, 0.976, 1.0 }) #define STONE_100 ((rgba){ 0.961, 0.961, 0.957, 1.0 }) diff --git a/src/renderer/backends/backend_vulkan.c b/src/renderer/backends/backend_vulkan.c index 81a08e2..4b7314c 100644 --- a/src/renderer/backends/backend_vulkan.c +++ b/src/renderer/backends/backend_vulkan.c @@ -1,5 +1,7 @@ #include +#include #include +#include "colours.h" #define CEL_PLATFORM_LINUX #include #include @@ -637,6 +639,11 @@ void vulkan_swapchain_present(vulkan_context* context, vulkan_swapchain* swapcha 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; @@ -940,7 +947,7 @@ bool gfx_backend_init(renderer* ren) { // Renderpass creation vulkan_renderpass_create(&context, &context.main_renderpass, vec4(0, 0, context.framebuffer_width, context.framebuffer_height), - vec4(0.0, 0.0, 0.2, 1.0), 1.0, 0); + rgba_to_vec4(COLOUR_SEA_GREEN), 1.0, 0); // Framebiffers creation context.swapchain.framebuffers = vulkan_framebuffer_darray_new(context.swapchain.image_count); @@ -953,10 +960,10 @@ bool gfx_backend_init(renderer* ren) { // Sync objects context.image_available_semaphores = - malloc(sizeof(VkSemaphore) * context.swapchain.max_frames_in_flight); + calloc(context.swapchain.max_frames_in_flight, sizeof(VkSemaphore)); context.queue_complete_semaphores = - malloc(sizeof(VkSemaphore) * context.swapchain.max_frames_in_flight); - context.in_flight_fences = malloc(sizeof(vulkan_fence) * context.swapchain.max_frames_in_flight); + 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 }; @@ -993,6 +1000,92 @@ void gfx_backend_shutdown(renderer* ren) { 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 = (f32)context.framebuffer_height; + 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 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.present_queue, + context.queue_complete_semaphores[context.current_frame], context.image_index); +} + +void gfx_backend_draw_frame(renderer* ren) { + backend_begin_frame(ren, 16.0); + + backend_end_frame(ren, 16.0); +} + void clear_screen(vec3 colour) {} void bind_texture(shader s, texture* tex, u32 slot) {} diff --git a/src/renderer/render_backend.h b/src/renderer/render_backend.h index 8c351c6..041f412 100644 --- a/src/renderer/render_backend.h +++ b/src/renderer/render_backend.h @@ -12,6 +12,8 @@ bool gfx_backend_init(renderer* ren); void gfx_backend_shutdown(renderer* ren); +void gfx_backend_draw_frame(renderer* ren); + void clear_screen(vec3 colour); void bind_texture(shader s, texture* tex, u32 slot); -- cgit v1.2.3-70-g09d2 From 90248a622203da205916ac89a1ac144d363cf37d Mon Sep 17 00:00:00 2001 From: omnisci3nce <17525998+omnisci3nce@users.noreply.github.com> Date: Tue, 26 Mar 2024 22:30:26 +1100 Subject: compile shader to spirv in build. start adding shader module code --- assets/shaders/blinn_phong.vert | 11 ++++++--- src/renderer/backends/backend_vulkan.c | 45 +++++++++++++++++++++++++++++++++- xmake.lua | 14 +++++++++++ 3 files changed, 65 insertions(+), 5 deletions(-) diff --git a/assets/shaders/blinn_phong.vert b/assets/shaders/blinn_phong.vert index 6028178..041c3d1 100644 --- a/assets/shaders/blinn_phong.vert +++ b/assets/shaders/blinn_phong.vert @@ -4,10 +4,13 @@ layout (location = 0) in vec3 inPos; layout (location = 1) in vec3 inNormal; layout (location = 2) in vec2 inTexCoords; -uniform mat4 model; -uniform mat4 view; -uniform mat4 projection; -uniform mat4 lightSpaceMatrix; +// Uniform block +layout (std140, binding = 0) uniform MatrixBlock { + mat4 model; + mat4 view; + mat4 projection; + mat4 lightSpaceMatrix; +}; // Output out VS_OUT { diff --git a/src/renderer/backends/backend_vulkan.c b/src/renderer/backends/backend_vulkan.c index 4b7314c..2b6bcd5 100644 --- a/src/renderer/backends/backend_vulkan.c +++ b/src/renderer/backends/backend_vulkan.c @@ -151,6 +151,48 @@ static vulkan_context context; typedef struct vulkan_state { } vulkan_state; +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; + +#define SHADER_STAGE_COUNT 2 + +typedef struct vulkan_shader { + // vertex, fragment + vulkan_shader_stage stages[SHADER_STAGE_COUNT]; + vulkan_pipeline pipeline; +} vulkan_shader; + +bool create_shader_module(vulkan_context* context, const char* filename, const char* type_str, + VkShaderStageFlagBits flag, u32 stage_index, + vulkan_shader_stage* shader_stages) { + // char file_name[512]; + + memset(&shader_stages[stage_index].create_info, 0, sizeof(VkShaderModuleCreateInfo)); + shader_stages[stage_index].create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; + + // todo: file input +} + +bool vulkan_object_shader_create(vulkan_context* context, vulkan_shader* out_shader) { + char stage_type_strs[SHADER_STAGE_COUNT][5] = { "vert", "frag" }; + 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++) { + create_shader_module(context, "build/linux/x86_64/debug/blinn_phong.vert.spv", + stage_type_strs[i], stage_types[i], i, out_shader->stages); + } +} +void vulkan_object_shader_destroy(vulkan_context* context, vulkan_shader* shader) {} +void vulkan_object_shader_use(vulkan_context* context, vulkan_shader* shader) {} + bool select_physical_device(vulkan_context* ctx) { u32 physical_device_count = 0; VK_CHECK(vkEnumeratePhysicalDevices(ctx->instance, &physical_device_count, 0)); @@ -980,9 +1022,10 @@ bool gfx_backend_init(renderer* ren) { for (u8 i = 0; i < context.swapchain.max_frames_in_flight; i++) { context.images_in_flight[i] = 0; } - INFO("Sync objects created"); + // Shader modules + INFO("Vulkan renderer initialisation succeeded"); return true; } diff --git a/xmake.lua b/xmake.lua index 386f3bb..32e5ba4 100644 --- a/xmake.lua +++ b/xmake.lua @@ -63,6 +63,17 @@ local core_sources = { "src/systems/*.c", } +rule("compile_glsl_shaders") + set_extensions(".vert") + on_buildcmd_file(function (target, batchcmds, sourcefile, opt) + local targetfile = path.join(target:targetdir(), path.basename(sourcefile) .. ".vert.spv") + + print("Compiling shader: %s", sourcefile) + batchcmds:vrunv('glslc', {sourcefile, "-o", targetfile}) + batchcmds:add_depfiles(sourcefile) +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 @@ -83,7 +94,10 @@ target("core_config") add_includedirs("src/std/", {public = true}) add_includedirs("src/std/containers", {public = true}) add_includedirs("src/systems/", {public = true}) + add_rules("compile_glsl_shaders") add_files("src/empty.c") -- for some reason we need this on Mac so it doesnt call 'ar' with no files and error + add_files("assets/shaders/*.vert") + -- add_files("assets/shaders/*.frag") set_default(false) -- prevents standalone building of this target target("core_static") -- cgit v1.2.3-70-g09d2 From 80cdd4f2b1c2a3355926b59a85e14100b3daa7b7 Mon Sep 17 00:00:00 2001 From: omnisci3nce <17525998+omnisci3nce@users.noreply.github.com> Date: Wed, 27 Mar 2024 21:05:04 +1100 Subject: simple shaders for testing --- assets/shaders/triangle.frag | 8 ++++++++ assets/shaders/triangle.vert | 8 ++++++++ src/renderer/backends/backend_vulkan.c | 24 ++++++++++++++++++++++-- xmake.lua | 17 ++++++++++++++--- 4 files changed, 52 insertions(+), 5 deletions(-) create mode 100644 assets/shaders/triangle.frag create mode 100644 assets/shaders/triangle.vert diff --git a/assets/shaders/triangle.frag b/assets/shaders/triangle.frag new file mode 100644 index 0000000..d26e5c4 --- /dev/null +++ b/assets/shaders/triangle.frag @@ -0,0 +1,8 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(location = 0) out vec4 out_colour; + +void main() { + out_colour = vec4(1.0); +} \ No newline at end of file diff --git a/assets/shaders/triangle.vert b/assets/shaders/triangle.vert new file mode 100644 index 0000000..0518c62 --- /dev/null +++ b/assets/shaders/triangle.vert @@ -0,0 +1,8 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(location = 0) in vec3 in_position; + +void main() { + gl_Position = vec4(in_position, 1.0); +} \ No newline at end of file diff --git a/src/renderer/backends/backend_vulkan.c b/src/renderer/backends/backend_vulkan.c index 2b6bcd5..863cd65 100644 --- a/src/renderer/backends/backend_vulkan.c +++ b/src/renderer/backends/backend_vulkan.c @@ -176,9 +176,29 @@ bool create_shader_module(vulkan_context* context, const char* filename, const c // char file_name[512]; 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 + const char* file_contents = string_from_file(filename); + + u64 bytes = strlen(file_contents); + shader_stages[stage_index].create_info.codeSize = bytes; + shader_stages[stage_index].create_info.pCode = (u32*)file_contents; + + 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); + + return true; } bool vulkan_object_shader_create(vulkan_context* context, vulkan_shader* out_shader) { @@ -186,8 +206,8 @@ bool vulkan_object_shader_create(vulkan_context* context, vulkan_shader* out_sha 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++) { - create_shader_module(context, "build/linux/x86_64/debug/blinn_phong.vert.spv", - stage_type_strs[i], stage_types[i], i, out_shader->stages); + create_shader_module(context, "build/linux/x86_64/debug/triangle.vert.spv", stage_type_strs[i], + stage_types[i], i, out_shader->stages); } } void vulkan_object_shader_destroy(vulkan_context* context, vulkan_shader* shader) {} diff --git a/xmake.lua b/xmake.lua index 32e5ba4..5457ccb 100644 --- a/xmake.lua +++ b/xmake.lua @@ -63,7 +63,7 @@ local core_sources = { "src/systems/*.c", } -rule("compile_glsl_shaders") +rule("compile_glsl_vert_shaders") set_extensions(".vert") on_buildcmd_file(function (target, batchcmds, sourcefile, opt) local targetfile = path.join(target:targetdir(), path.basename(sourcefile) .. ".vert.spv") @@ -72,6 +72,15 @@ rule("compile_glsl_shaders") batchcmds:vrunv('glslc', {sourcefile, "-o", targetfile}) batchcmds:add_depfiles(sourcefile) end) +rule("compile_glsl_frag_shaders") + set_extensions(".frag") + on_buildcmd_file(function (target, batchcmds, sourcefile, opt) + local targetfile = path.join(target:targetdir(), path.basename(sourcefile) .. ".frag.spv") + + print("Compiling shader: %s", sourcefile) + batchcmds:vrunv('glslc', {sourcefile, "-o", targetfile}) + batchcmds:add_depfiles(sourcefile) +end) -- TODO: Metal shaders compilation -- common configuration for both static and shared libraries @@ -94,9 +103,11 @@ target("core_config") add_includedirs("src/std/", {public = true}) add_includedirs("src/std/containers", {public = true}) add_includedirs("src/systems/", {public = true}) - add_rules("compile_glsl_shaders") + add_rules("compile_glsl_vert_shaders") + add_rules("compile_glsl_frag_shaders") add_files("src/empty.c") -- for some reason we need this on Mac so it doesnt call 'ar' with no files and error - add_files("assets/shaders/*.vert") + add_files("assets/shaders/triangle.vert") + add_files("assets/shaders/triangle.frag") -- add_files("assets/shaders/*.frag") set_default(false) -- prevents standalone building of this target -- cgit v1.2.3-70-g09d2 From ff907c6ffa7ed0a7c6ce938b40a6c223dd0a3b9d Mon Sep 17 00:00:00 2001 From: omnisci3nce <17525998+omnisci3nce@users.noreply.github.com> Date: Wed, 27 Mar 2024 22:09:03 +1100 Subject: start going through Kohi episode 26 --- src/platform/file.c | 30 +++++++++++++++ src/platform/file.h | 9 ++++- src/renderer/backends/backend_vulkan.c | 68 +++++++++++++++++++++------------- 3 files changed, 81 insertions(+), 26 deletions(-) diff --git a/src/platform/file.c b/src/platform/file.c index ec9259a..ac5014d 100644 --- a/src/platform/file.c +++ b/src/platform/file.c @@ -61,3 +61,33 @@ str8_opt str8_from_file(arena *a, str8 path) { return result; } + +FileData load_spv_file(const char *path) { + FILE *f = fopen(path, "rb"); + if (f == NULL) { + perror("Error opening file"); + return (FileData){NULL, 0}; + } + + fseek(f, 0, SEEK_END); + long fsize = ftell(f); + rewind(f); + + char *data = (char *)malloc(fsize); + if (data == NULL) { + perror("Memory allocation failed"); + fclose(f); + return (FileData){NULL, 0}; + } + + size_t bytesRead = fread(data, 1, fsize, f); + if (bytesRead < fsize) { + perror("Failed to read the entire file"); + free(data); + fclose(f); + return (FileData){NULL, 0}; + } + + fclose(f); + return (FileData){data, bytesRead}; +} \ No newline at end of file diff --git a/src/platform/file.h b/src/platform/file.h index 8bb22c8..83d1317 100644 --- a/src/platform/file.h +++ b/src/platform/file.h @@ -16,4 +16,11 @@ typedef struct str8_opt { const char* string_from_file(const char* path); -str8_opt str8_from_file(arena* a, str8 path); \ No newline at end of file +str8_opt str8_from_file(arena* a, str8 path); + +typedef struct { + char *data; + size_t size; +} FileData; + +FileData load_spv_file(const char *path); \ No newline at end of file diff --git a/src/renderer/backends/backend_vulkan.c b/src/renderer/backends/backend_vulkan.c index 863cd65..c57da9d 100644 --- a/src/renderer/backends/backend_vulkan.c +++ b/src/renderer/backends/backend_vulkan.c @@ -118,6 +118,25 @@ typedef struct vulkan_fence { 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; + +#define SHADER_STAGE_COUNT 2 + +typedef struct vulkan_shader { + // vertex, fragment + vulkan_shader_stage stages[SHADER_STAGE_COUNT]; + vulkan_pipeline pipeline; +} vulkan_shader; + typedef struct vulkan_context { VkInstance instance; VkAllocationCallbacks* allocator; @@ -138,6 +157,8 @@ typedef struct vulkan_context { u32 image_index; u32 current_frame; + vulkan_shader object_shader; + // TODO: swapchain recreation #if defined(DEBUG) @@ -151,29 +172,20 @@ static vulkan_context context; typedef struct vulkan_state { } vulkan_state; -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; +// pipeline stuff +bool vulkan_graphics_pipeline_create( + vulkan_context* context, + vulkan_renderpass* renderpass, + u32 attribute_count, + VkVertexInputAttributeDescription* attributes, + // ... https://youtu.be/OmPmftW7Kjg?si=qn_777v_ppHKzswK&t=568 +) { -#define SHADER_STAGE_COUNT 2 - -typedef struct vulkan_shader { - // vertex, fragment - vulkan_shader_stage stages[SHADER_STAGE_COUNT]; - vulkan_pipeline pipeline; -} vulkan_shader; +} bool create_shader_module(vulkan_context* context, const char* filename, const char* type_str, VkShaderStageFlagBits flag, u32 stage_index, vulkan_shader_stage* shader_stages) { - // char file_name[512]; memset(&shader_stages[stage_index].create_info, 0, sizeof(VkShaderModuleCreateInfo)); memset(&shader_stages[stage_index].stage_create_info, 0, sizeof(VkPipelineShaderStageCreateInfo)); @@ -181,11 +193,10 @@ bool create_shader_module(vulkan_context* context, const char* filename, const c shader_stages[stage_index].create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; // todo: file input - const char* file_contents = string_from_file(filename); + FileData file_contents = load_spv_file(filename); - u64 bytes = strlen(file_contents); - shader_stages[stage_index].create_info.codeSize = bytes; - shader_stages[stage_index].create_info.pCode = (u32*)file_contents; + 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); @@ -196,18 +207,23 @@ bool create_shader_module(vulkan_context* context, const char* filename, const c 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); + 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/triangle.vert.spv", + "build/linux/x86_64/debug/triangle.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++) { - create_shader_module(context, "build/linux/x86_64/debug/triangle.vert.spv", stage_type_strs[i], - stage_types[i], i, out_shader->stages); + DEBUG("Loading %s", stage_filenames[i]); + create_shader_module(context, stage_filenames[i], stage_type_strs[i], stage_types[i], i, + out_shader->stages); } } void vulkan_object_shader_destroy(vulkan_context* context, vulkan_shader* shader) {} @@ -1045,6 +1061,8 @@ bool gfx_backend_init(renderer* ren) { INFO("Sync objects created"); // Shader modules + vulkan_object_shader_create(&context, &context.object_shader); + INFO("Compiled shader modules") INFO("Vulkan renderer initialisation succeeded"); return true; -- cgit v1.2.3-70-g09d2 From fe83372519e3ae8dd88ecfb4c67d484a1a5f13af Mon Sep 17 00:00:00 2001 From: omniscient <17525998+omnisci3nce@users.noreply.github.com> Date: Wed, 27 Mar 2024 23:07:16 +1100 Subject: brainsforming refined layout for renderer --- assets/shaders/triangle.frag | 4 +-- assets/shaders/triangle.vert | 4 +-- src/maths/maths.h | 6 ++++ src/platform/file.c | 50 +++++++++++++-------------- src/platform/file.h | 6 ++-- src/renderer/backends/backend_vulkan.c | 15 +++----- src/renderer/cleanroom/README.md | 1 + src/renderer/cleanroom/types.h | 63 ++++++++++++++++++++++++++++++++++ src/renderer/render_types.h | 3 +- src/std/containers/darray.h | 3 +- 10 files changed, 109 insertions(+), 46 deletions(-) create mode 100644 src/renderer/cleanroom/README.md create mode 100644 src/renderer/cleanroom/types.h diff --git a/assets/shaders/triangle.frag b/assets/shaders/triangle.frag index d26e5c4..44c1eb3 100644 --- a/assets/shaders/triangle.frag +++ b/assets/shaders/triangle.frag @@ -3,6 +3,4 @@ layout(location = 0) out vec4 out_colour; -void main() { - out_colour = vec4(1.0); -} \ No newline at end of file +void main() { out_colour = vec4(1.0); } \ No newline at end of file diff --git a/assets/shaders/triangle.vert b/assets/shaders/triangle.vert index 0518c62..f253d9b 100644 --- a/assets/shaders/triangle.vert +++ b/assets/shaders/triangle.vert @@ -3,6 +3,4 @@ layout(location = 0) in vec3 in_position; -void main() { - gl_Position = vec4(in_position, 1.0); -} \ No newline at end of file +void main() { gl_Position = vec4(in_position, 1.0); } \ No newline at end of file diff --git a/src/maths/maths.h b/src/maths/maths.h index 6816415..db63072 100644 --- a/src/maths/maths.h +++ b/src/maths/maths.h @@ -236,3 +236,9 @@ typedef struct u32x3 { }; } 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 diff --git a/src/platform/file.c b/src/platform/file.c index ac5014d..6030620 100644 --- a/src/platform/file.c +++ b/src/platform/file.c @@ -63,31 +63,31 @@ str8_opt str8_from_file(arena *a, str8 path) { } FileData load_spv_file(const char *path) { - FILE *f = fopen(path, "rb"); - if (f == NULL) { - perror("Error opening file"); - return (FileData){NULL, 0}; - } - - fseek(f, 0, SEEK_END); - long fsize = ftell(f); - rewind(f); - - char *data = (char *)malloc(fsize); - if (data == NULL) { - perror("Memory allocation failed"); - fclose(f); - return (FileData){NULL, 0}; - } - - size_t bytesRead = fread(data, 1, fsize, f); - if (bytesRead < fsize) { - perror("Failed to read the entire file"); - free(data); - fclose(f); - return (FileData){NULL, 0}; - } + FILE *f = fopen(path, "rb"); + if (f == NULL) { + perror("Error opening file"); + return (FileData){ NULL, 0 }; + } + + fseek(f, 0, SEEK_END); + long fsize = ftell(f); + rewind(f); + char *data = (char *)malloc(fsize); + if (data == NULL) { + perror("Memory allocation failed"); fclose(f); - return (FileData){data, bytesRead}; + return (FileData){ NULL, 0 }; + } + + size_t bytesRead = fread(data, 1, fsize, f); + if (bytesRead < fsize) { + perror("Failed to read the entire file"); + free(data); + fclose(f); + return (FileData){ NULL, 0 }; + } + + fclose(f); + return (FileData){ data, bytesRead }; } \ No newline at end of file diff --git a/src/platform/file.h b/src/platform/file.h index 83d1317..a8aa8ea 100644 --- a/src/platform/file.h +++ b/src/platform/file.h @@ -19,8 +19,8 @@ const char* string_from_file(const char* path); str8_opt str8_from_file(arena* a, str8 path); typedef struct { - char *data; - size_t size; + char* data; + size_t size; } FileData; -FileData load_spv_file(const char *path); \ No newline at end of file +FileData load_spv_file(const char* path); \ No newline at end of file diff --git a/src/renderer/backends/backend_vulkan.c b/src/renderer/backends/backend_vulkan.c index c57da9d..d78d4d2 100644 --- a/src/renderer/backends/backend_vulkan.c +++ b/src/renderer/backends/backend_vulkan.c @@ -173,20 +173,15 @@ typedef struct vulkan_state { } vulkan_state; // pipeline stuff -bool vulkan_graphics_pipeline_create( - vulkan_context* context, - vulkan_renderpass* renderpass, - u32 attribute_count, - VkVertexInputAttributeDescription* attributes, - // ... https://youtu.be/OmPmftW7Kjg?si=qn_777v_ppHKzswK&t=568 -) { - -} +bool vulkan_graphics_pipeline_create(vulkan_context* context, vulkan_renderpass* renderpass, + u32 attribute_count, + VkVertexInputAttributeDescription* attributes, + // ... https://youtu.be/OmPmftW7Kjg?si=qn_777v_ppHKzswK&t=568 +) {} 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)); diff --git a/src/renderer/cleanroom/README.md b/src/renderer/cleanroom/README.md new file mode 100644 index 0000000..d510f16 --- /dev/null +++ b/src/renderer/cleanroom/README.md @@ -0,0 +1 @@ +# Cleanroom / Re-jig of the renderer structure \ No newline at end of file diff --git a/src/renderer/cleanroom/types.h b/src/renderer/cleanroom/types.h new file mode 100644 index 0000000..cd51fca --- /dev/null +++ b/src/renderer/cleanroom/types.h @@ -0,0 +1,63 @@ +#pragma once +#include "defines.h" + +typedef int texture_handle; +typedef int buffer_handle; +typedef int model_handle; + +/** @brief Texture Description - used by texture creation functions */ +typedef struct texture_desc { + // gpu_texture_type tex_type; + // gpu_texture_format format; + // u32x2 extents; +} texture_desc; + +/* + - render_types.h + - ral_types.h + - ral.h + - render.h ? +*/ + +/* render_types */ +typedef struct mesh mesh; +typedef struct model model; +typedef struct model pbr_material; +typedef struct model bp_material; // blinn-phong + +// Three registers +// 1. low level graphics api calls "ral" +// 2. higher level render calls +// 3. simplified immediate mode API + +/* render.h */ +// frontend -- these can be called from say a loop in an example, or via FFI +texture_handle texture_create(const char* debug_name, texture_desc description); +void texture_data_upload(texture_handle texture); +buffer_handle buffer_create(const char* debug_name, u64 size); + +// models and meshes are implemented **in terms of the above** +mesh mesh_create(); +model_handle model_load(const char* filepath); + +/* ral.h */ +// backend -- these are not seen by the higher-level code +void gpu_texture_init(); +void gpu_texture_upload(); +void gpu_buffer_init(); +void gpu_buffer_upload(); + +// command buffer gubbins + +// 3. SIMA (simplified immediate mode api) +// - dont need to worry about uploading mesh data +void debug_draw_cuboid(); +void debug_draw_sphere(); +void debug_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/render_types.h b/src/renderer/render_types.h index 7bb6e60..2cc321c 100644 --- a/src/renderer/render_types.h +++ b/src/renderer/render_types.h @@ -8,6 +8,7 @@ #pragma once #include "darray.h" +#include "maths.h" #include "maths_types.h" #include "str.h" @@ -178,4 +179,4 @@ typedef enum gpu_texture_format { TEXTURE_FORMAT_8_8_8_8_RGBA_UNORM, TEXTURE_FORMAT_DEPTH_DEFAULT, TEXTURE_FORMAT_COUNT -} gpu_texture_format; +} gpu_texture_format; \ No newline at end of file diff --git a/src/std/containers/darray.h b/src/std/containers/darray.h index 45d92e2..b15d269 100644 --- a/src/std/containers/darray.h +++ b/src/std/containers/darray.h @@ -6,7 +6,8 @@ // COPIED FROM KITC WITH SOME MINOR ADJUSTMENTS /* TODO: - - a 'find' function that takes a predicate (maybe wrap with a macro so we dont have to define a new function?) + - a 'find' function that takes a predicate (maybe wrap with a macro so we dont have to define a + new function?) */ #ifndef KITC_TYPED_ARRAY_H -- cgit v1.2.3-70-g09d2 From be985fa4363816817344f9236efe33997f86e945 Mon Sep 17 00:00:00 2001 From: omniscient <17525998+omnisci3nce@users.noreply.github.com> Date: Thu, 28 Mar 2024 19:58:58 +1100 Subject: more api --- src/renderer/cleanroom/types.h | 86 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 82 insertions(+), 4 deletions(-) diff --git a/src/renderer/cleanroom/types.h b/src/renderer/cleanroom/types.h index cd51fca..94ec85c 100644 --- a/src/renderer/cleanroom/types.h +++ b/src/renderer/cleanroom/types.h @@ -1,5 +1,7 @@ #pragma once +#include "darray.h" #include "defines.h" +#include "str.h" typedef int texture_handle; typedef int buffer_handle; @@ -19,12 +21,82 @@ typedef struct texture_desc { - render.h ? */ +// gpu types +typedef enum gpu_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 { + CEL_TEXTURE_TYPE_2D, + CEL_TEXTURE_TYPE_3D, + CEL_TEXTURE_TYPE_2D_ARRAY, + CEL_TEXTURE_TYPE_CUBE_MAP, + CEL_TEXTURE_TYPE_COUNT +} gpu_texture_type; + +typedef enum gpu_texture_format { + CEL_TEXTURE_FORMAT_8_8_8_8_RGBA_UNORM, + CEL_TEXTURE_FORMAT_DEPTH_DEFAULT, + CEL_TEXTURE_FORMAT_COUNT +} gpu_texture_format; + /* render_types */ typedef struct mesh mesh; typedef struct model model; typedef struct model pbr_material; 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 union vertex { + struct { + vec3 position; + vec4 colour; + vec2 tex_coords; + vec3 normal; + } static_3d; /** @brief standard vertex format for static geometry in 3D */ + + struct { + vec2 position; + vec4 colour; + vec2 tex_coords; + } sprite; + + // TODO: animated 3d +} vertex; + +KITC_DECL_TYPED_ARRAY(vertex) + +typedef struct geometry_data { + vertex_format format; + vertex_darray vertices; +} geometry_data; + +typedef struct mesh { + buffer_handle vertex_buffer; + buffer_handle index_buffer; + u32 index_count; + bool has_indices; + geometry_data* vertices; // NULL means it has been freed +} mesh; + +typedef struct model { + str8 debug_name; + mesh* meshes; + u32 mesh_count; +} model; + // Three registers // 1. low level graphics api calls "ral" // 2. higher level render calls @@ -32,7 +104,8 @@ typedef struct model bp_material; // blinn-phong /* render.h */ // frontend -- these can be called from say a loop in an example, or via FFI -texture_handle texture_create(const char* debug_name, texture_desc description); +texture_handle texture_create(const char* debug_name, texture_desc description, const u8* data); + void texture_data_upload(texture_handle texture); buffer_handle buffer_create(const char* debug_name, u64 size); @@ -42,6 +115,10 @@ model_handle model_load(const char* filepath); /* ral.h */ // backend -- these are not seen by the higher-level code +typedef struct gpu_swapchain gpu_swapchain; +typedef struct gpu_device gpu_device; +typedef struct gpu_pipeline gpu_pipeline; + void gpu_texture_init(); void gpu_texture_upload(); void gpu_buffer_init(); @@ -51,9 +128,10 @@ void gpu_buffer_upload(); // 3. SIMA (simplified immediate mode api) // - dont need to worry about uploading mesh data -void debug_draw_cuboid(); -void debug_draw_sphere(); -void debug_draw_camera_frustum(); +// - very useful for debugging +void imm_draw_cuboid(); +void imm_draw_sphere(); +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) { -- cgit v1.2.3-70-g09d2 From b4cb698d177ada97c976eab059eabedd433abfd0 Mon Sep 17 00:00:00 2001 From: omniscient <17525998+omnisci3nce@users.noreply.github.com> Date: Thu, 28 Mar 2024 21:54:22 +1100 Subject: sphere args --- src/renderer/cleanroom/types.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/renderer/cleanroom/types.h b/src/renderer/cleanroom/types.h index 94ec85c..23f2348 100644 --- a/src/renderer/cleanroom/types.h +++ b/src/renderer/cleanroom/types.h @@ -130,7 +130,7 @@ void gpu_buffer_upload(); // - dont need to worry about uploading mesh data // - very useful for debugging void imm_draw_cuboid(); -void imm_draw_sphere(); +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 -- cgit v1.2.3-70-g09d2 From 765a6d0f36a9f16189efc449bde815a6c0938584 Mon Sep 17 00:00:00 2001 From: omnisci3nce <17525998+omnisci3nce@users.noreply.github.com> Date: Fri, 29 Mar 2024 21:11:02 +1100 Subject: triangle --- assets/shaders/triangle.frag | 4 +- assets/shaders/triangle.vert | 3 + src/core.c | 4 +- src/platform/file.c | 50 ++-- src/renderer/backends/backend_vulkan.c | 439 +++++++++++++++++++++++++++++++-- src/renderer/render.c | 4 +- xmake.lua | 1 + 7 files changed, 458 insertions(+), 47 deletions(-) diff --git a/assets/shaders/triangle.frag b/assets/shaders/triangle.frag index d26e5c4..dd6d148 100644 --- a/assets/shaders/triangle.frag +++ b/assets/shaders/triangle.frag @@ -1,8 +1,10 @@ #version 450 #extension GL_ARB_separate_shader_objects : enable +layout(location = 0) in vec3 in_position; + layout(location = 0) out vec4 out_colour; void main() { - out_colour = vec4(1.0); + out_colour = vec4(in_position.r + 0.5, in_position.g + 0.5, in_position.b + 0.5, 1.0); } \ No newline at end of file diff --git a/assets/shaders/triangle.vert b/assets/shaders/triangle.vert index 0518c62..3dcf931 100644 --- a/assets/shaders/triangle.vert +++ b/assets/shaders/triangle.vert @@ -3,6 +3,9 @@ layout(location = 0) in vec3 in_position; +layout(location = 0) out vec3 out_position; + void main() { gl_Position = vec4(in_position, 1.0); + out_position = in_position; } \ No newline at end of file diff --git a/src/core.c b/src/core.c index 024b2d7..a0dc3b6 100644 --- a/src/core.c +++ b/src/core.c @@ -7,8 +7,8 @@ #include "render_types.h" #include "threadpool.h" -#define SCR_WIDTH 1080 -#define SCR_HEIGHT 800 +#define SCR_WIDTH 2160 +#define SCR_HEIGHT 1080 core* core_bringup() { INFO("Initiate Core bringup"); diff --git a/src/platform/file.c b/src/platform/file.c index ac5014d..6030620 100644 --- a/src/platform/file.c +++ b/src/platform/file.c @@ -63,31 +63,31 @@ str8_opt str8_from_file(arena *a, str8 path) { } FileData load_spv_file(const char *path) { - FILE *f = fopen(path, "rb"); - if (f == NULL) { - perror("Error opening file"); - return (FileData){NULL, 0}; - } - - fseek(f, 0, SEEK_END); - long fsize = ftell(f); - rewind(f); - - char *data = (char *)malloc(fsize); - if (data == NULL) { - perror("Memory allocation failed"); - fclose(f); - return (FileData){NULL, 0}; - } - - size_t bytesRead = fread(data, 1, fsize, f); - if (bytesRead < fsize) { - perror("Failed to read the entire file"); - free(data); - fclose(f); - return (FileData){NULL, 0}; - } + FILE *f = fopen(path, "rb"); + if (f == NULL) { + perror("Error opening file"); + return (FileData){ NULL, 0 }; + } + + fseek(f, 0, SEEK_END); + long fsize = ftell(f); + rewind(f); + char *data = (char *)malloc(fsize); + if (data == NULL) { + perror("Memory allocation failed"); fclose(f); - return (FileData){data, bytesRead}; + return (FileData){ NULL, 0 }; + } + + size_t bytesRead = fread(data, 1, fsize, f); + if (bytesRead < fsize) { + perror("Failed to read the entire file"); + free(data); + fclose(f); + return (FileData){ NULL, 0 }; + } + + fclose(f); + return (FileData){ data, bytesRead }; } \ No newline at end of file diff --git a/src/renderer/backends/backend_vulkan.c b/src/renderer/backends/backend_vulkan.c index c57da9d..ac64429 100644 --- a/src/renderer/backends/backend_vulkan.c +++ b/src/renderer/backends/backend_vulkan.c @@ -1,12 +1,16 @@ +#define CDEBUG +#define CEL_PLATFORM_LINUX +// ^ Temporary + +#include +#include #include #include #include -#include "colours.h" -#define CEL_PLATFORM_LINUX -#include #include #include #include +#include "colours.h" #include "str.h" #include "darray.h" @@ -21,8 +25,8 @@ #include -#define SCR_WIDTH 1080 -#define SCR_HEIGHT 800 +#define SCR_WIDTH 2160 +#define SCR_HEIGHT 1080 #if CEL_REND_BACKEND_VULKAN @@ -137,6 +141,16 @@ typedef struct vulkan_shader { vulkan_pipeline pipeline; } vulkan_shader; +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; + typedef struct vulkan_context { VkInstance instance; VkAllocationCallbacks* allocator; @@ -146,6 +160,11 @@ typedef struct vulkan_context { 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; @@ -168,25 +187,188 @@ typedef struct 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; +} vertex_pos; + // pipeline stuff -bool vulkan_graphics_pipeline_create( - vulkan_context* context, - vulkan_renderpass* renderpass, - u32 attribute_count, - VkVertexInputAttributeDescription* attributes, - // ... https://youtu.be/OmPmftW7Kjg?si=qn_777v_ppHKzswK&t=568 -) { +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_pos); + 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 + }; + 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); } 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)); @@ -225,9 +407,63 @@ bool vulkan_object_shader_create(vulkan_context* context, vulkan_shader* out_sha create_shader_module(context, stage_filenames[i], stage_type_strs[i], stage_types[i], i, out_shader->stages); } + + // TODO: descriptors + + // Pipeline creation + VkViewport viewport; + viewport.x = 0; + viewport.y = (f32)context->framebuffer_height; + 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 = 1; + VkVertexInputAttributeDescription attribute_descs[1]; + // Position + VkFormat formats[1] = { VK_FORMAT_R32G32B32_SFLOAT }; + + u64 sizes[1] = { sizeof(vec3) }; + + 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]; + } + + // TODO: Descriptor set + + // 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, 0, 0, SHADER_STAGE_COUNT, stage_create_infos, + viewport, scissor, false, &out_shader->pipeline); + INFO("Graphics pipeline created!"); + + return true; } void vulkan_object_shader_destroy(vulkan_context* context, vulkan_shader* shader) {} -void vulkan_object_shader_use(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); +} bool select_physical_device(vulkan_context* ctx) { u32 physical_device_count = 0; @@ -482,6 +718,68 @@ void vulkan_image_create(vulkan_context* context, VkImageType image_type, u32 wi // TODO: vulkan_image_destroy +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); + } + + 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 + void vulkan_framebuffer_create(vulkan_context* context, vulkan_renderpass* renderpass, u32 width, u32 height, u32 attachment_count, VkImageView* attachments, vulkan_framebuffer* out_framebuffer) { @@ -577,6 +875,24 @@ void vulkan_command_buffer_end_oneshot(vulkan_context* context, VkCommandPool po 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 }; @@ -837,6 +1153,33 @@ void vulkan_renderpass_end(vulkan_command_buffer* command_buffer, vulkan_renderp 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); @@ -848,6 +1191,25 @@ void create_command_buffers(renderer* ren) { } } +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); + TRACE("HERE"); + // load data into staging buffer + printf("Size: %ld\n", size); + vulkan_buffer_load_data(context, &staging, 0, size, 0, data); + TRACE("here"); + + // 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++) { @@ -929,7 +1291,7 @@ bool gfx_backend_init(renderer* ren) { plat_get_required_extension_names(required_extensions); -#if defined(DEBUG) +#if defined(CDEBUG) cstr_darray_push(required_extensions, VK_EXT_DEBUG_UTILS_EXTENSION_NAME); DEBUG("Required extensions:"); @@ -944,7 +1306,7 @@ bool gfx_backend_init(renderer* ren) { // Validation layers create_info.enabledLayerCount = 0; create_info.ppEnabledLayerNames = 0; -#if defined(DEBUG) +#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"); @@ -984,7 +1346,7 @@ bool gfx_backend_init(renderer* ren) { } // Debugger -#if defined(DEBUG) +#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; @@ -1064,6 +1426,36 @@ bool gfx_backend_init(renderer* ren) { vulkan_object_shader_create(&context, &context.object_shader); INFO("Compiled shader modules") + create_buffers(&context); + INFO("Created buffers"); + + // TODO: temporary test code + const u32 vert_count = 4; + vertex_pos verts[4] = { 0 }; + + verts[0].pos.x = 0.0; + verts[0].pos.y = -0.5; + + verts[1].pos.x = 0.5; + verts[1].pos.y = 0.5; + + verts[2].pos.x = 0.0; + verts[2].pos.y = 0.5; + + verts[3].pos.x = 0.5; + verts[3].pos.y = -0.5; + + 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_pos) * vert_count, 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) * index_count, indices); + TRACE("Uploaded index data"); + // --- End test code + INFO("Vulkan renderer initialisation succeeded"); return true; } @@ -1121,6 +1513,19 @@ void backend_begin_frame(renderer* ren, f32 delta_time) { vulkan_renderpass_begin(command_buffer, &context.main_renderpass, context.swapchain.framebuffers->data[context.image_index].handle); + + // TODO: temp test code + vulkan_object_shader_use(&context, &context.object_shader); + + VkDeviceSize offsets[1] = { 0 }; + vkCmdBindVertexBuffers(command_buffer->handle, 0, 1, &context.object_vertex_buffer.handle, + (VkDeviceSize*)offsets); + + vkCmdBindIndexBuffer(command_buffer->handle, context.object_index_buffer.handle, 0, + VK_INDEX_TYPE_UINT32); + + vkCmdDrawIndexed(command_buffer->handle, 6, 1, 0, 0, 0); + // --- End temp test code } void backend_end_frame(renderer* ren, f32 delta_time) { diff --git a/src/renderer/render.c b/src/renderer/render.c index 45762d4..de1a775 100644 --- a/src/renderer/render.c +++ b/src/renderer/render.c @@ -17,8 +17,8 @@ // FIXME: get rid of these and store dynamic screen realestate // in renderer -#define SCR_WIDTH 1080 -#define SCR_HEIGHT 800 +#define SCR_WIDTH 2160 +#define SCR_HEIGHT 1080 material DEFAULT_MATERIAL = { 0 }; diff --git a/xmake.lua b/xmake.lua index 5457ccb..3005713 100644 --- a/xmake.lua +++ b/xmake.lua @@ -14,6 +14,7 @@ add_cflags("-Wall", "-Wextra", "-Wundef", "-Wdouble-promotion") if is_mode("debug") then add_cflags("-g") -- Add debug symbols in debug mode + add_defines("CDEBUG") elseif is_mode("release") then add_defines("CRELEASE") end -- cgit v1.2.3-70-g09d2 From 57185c5e59e92775dd45b3e2966debb4ce5641e9 Mon Sep 17 00:00:00 2001 From: Omniscient <17525998+omnisci3nce@users.noreply.github.com> Date: Sat, 30 Mar 2024 10:52:10 +1100 Subject: get it working on other PC. hacky code in place --- src/renderer/backends/backend_vulkan.c | 80 ++++++++++++++++++++++------------ src/renderer/render.c | 4 +- 2 files changed, 53 insertions(+), 31 deletions(-) diff --git a/src/renderer/backends/backend_vulkan.c b/src/renderer/backends/backend_vulkan.c index ac64429..3e5137e 100644 --- a/src/renderer/backends/backend_vulkan.c +++ b/src/renderer/backends/backend_vulkan.c @@ -25,8 +25,8 @@ #include -#define SCR_WIDTH 2160 -#define SCR_HEIGHT 1080 +#define SCR_WIDTH 1000 +#define SCR_HEIGHT 1000 #if CEL_REND_BACKEND_VULKAN @@ -544,26 +544,42 @@ bool vulkan_device_create(vulkan_context* context) { // Logical device - NOTE: mutates the context directly // queues -#define VULKAN_QUEUES_COUNT 3 - const char* queue_names[VULKAN_QUEUES_COUNT] = { "GRAPHICS", "PRESENT", - // "COMPUTE", - "TRANSFER" }; - i32 indices[VULKAN_QUEUES_COUNT] = { context->device.graphics_queue_index, - context->device.present_queue_index, - // context->device.compute_queue_index, - context->device.transfer_queue_index }; - VkDeviceQueueCreateInfo - queue_create_info[VULKAN_QUEUES_COUNT]; // one for each of graphics,present,compute,transfer - for (int i = 0; i < VULKAN_QUEUES_COUNT; 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; - } +#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 = {}; @@ -593,10 +609,10 @@ bool vulkan_device_create(vulkan_context* context) { // 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.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); @@ -773,7 +789,8 @@ void* vulkan_buffer_unlock_memory(vulkan_context* context, vulkan_buffer* buffer 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)); + 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); } @@ -925,6 +942,7 @@ void vulkan_swapchain_create(vulkan_context* context, u32 width, u32 height, 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 extend %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; @@ -1024,7 +1042,11 @@ void vulkan_swapchain_present(vulkan_context* context, vulkan_swapchain* swapcha VkResult result = vkQueuePresentKHR(present_queue, &present_info); if (result != VK_SUCCESS) { - FATAL("Failed to present swapchain iamge"); + if (result == VK_SUBOPTIMAL_KHR) { + // WARN("Swapchain suboptimal - maybe resize needed?"); + } else { + FATAL("Failed to present swapchain iamge"); + } } // advance the current frame @@ -1562,7 +1584,7 @@ void backend_end_frame(renderer* ren, f32 delta_time) { vulkan_command_buffer_update_submitted(command_buffer); vulkan_swapchain_present( - &context, &context.swapchain, context.device.graphics_queue, context.device.present_queue, + &context, &context.swapchain, context.device.graphics_queue, context.device.graphics_queue, context.queue_complete_semaphores[context.current_frame], context.image_index); } diff --git a/src/renderer/render.c b/src/renderer/render.c index de1a775..74b98cf 100644 --- a/src/renderer/render.c +++ b/src/renderer/render.c @@ -17,8 +17,8 @@ // FIXME: get rid of these and store dynamic screen realestate // in renderer -#define SCR_WIDTH 2160 -#define SCR_HEIGHT 1080 +#define SCR_WIDTH 1000 +#define SCR_HEIGHT 1000 material DEFAULT_MATERIAL = { 0 }; -- cgit v1.2.3-70-g09d2 From c5176c9c001c7d32cc2c658e09be8a4b5237685b Mon Sep 17 00:00:00 2001 From: Omniscient <17525998+omnisci3nce@users.noreply.github.com> Date: Sat, 30 Mar 2024 10:52:15 +1100 Subject: chore format lint --- assets/shaders/triangle.frag | 2 +- assets/shaders/triangle.vert | 4 ++-- src/core.c | 4 ++-- src/platform/file.h | 6 +++--- src/std/containers/darray.h | 3 ++- 5 files changed, 10 insertions(+), 9 deletions(-) diff --git a/assets/shaders/triangle.frag b/assets/shaders/triangle.frag index dd6d148..8455d04 100644 --- a/assets/shaders/triangle.frag +++ b/assets/shaders/triangle.frag @@ -6,5 +6,5 @@ layout(location = 0) in vec3 in_position; layout(location = 0) out vec4 out_colour; void main() { - out_colour = vec4(in_position.r + 0.5, in_position.g + 0.5, in_position.b + 0.5, 1.0); + out_colour = vec4(in_position.r + 0.5, in_position.g + 0.5, in_position.b + 0.5, 1.0); } \ No newline at end of file diff --git a/assets/shaders/triangle.vert b/assets/shaders/triangle.vert index 3dcf931..e34112d 100644 --- a/assets/shaders/triangle.vert +++ b/assets/shaders/triangle.vert @@ -6,6 +6,6 @@ layout(location = 0) in vec3 in_position; layout(location = 0) out vec3 out_position; void main() { - gl_Position = vec4(in_position, 1.0); - out_position = in_position; + gl_Position = vec4(in_position, 1.0); + out_position = in_position; } \ No newline at end of file diff --git a/src/core.c b/src/core.c index a0dc3b6..4b3bd1b 100644 --- a/src/core.c +++ b/src/core.c @@ -7,8 +7,8 @@ #include "render_types.h" #include "threadpool.h" -#define SCR_WIDTH 2160 -#define SCR_HEIGHT 1080 +#define SCR_WIDTH 1000 +#define SCR_HEIGHT 1000 core* core_bringup() { INFO("Initiate Core bringup"); diff --git a/src/platform/file.h b/src/platform/file.h index 83d1317..a8aa8ea 100644 --- a/src/platform/file.h +++ b/src/platform/file.h @@ -19,8 +19,8 @@ const char* string_from_file(const char* path); str8_opt str8_from_file(arena* a, str8 path); typedef struct { - char *data; - size_t size; + char* data; + size_t size; } FileData; -FileData load_spv_file(const char *path); \ No newline at end of file +FileData load_spv_file(const char* path); \ No newline at end of file diff --git a/src/std/containers/darray.h b/src/std/containers/darray.h index 45d92e2..b15d269 100644 --- a/src/std/containers/darray.h +++ b/src/std/containers/darray.h @@ -6,7 +6,8 @@ // COPIED FROM KITC WITH SOME MINOR ADJUSTMENTS /* TODO: - - a 'find' function that takes a predicate (maybe wrap with a macro so we dont have to define a new function?) + - a 'find' function that takes a predicate (maybe wrap with a macro so we dont have to define a + new function?) */ #ifndef KITC_TYPED_ARRAY_H -- cgit v1.2.3-70-g09d2 From f07e87a86e386ba0f65c5a1e962b6a90cfe26ced Mon Sep 17 00:00:00 2001 From: Omniscient <17525998+omnisci3nce@users.noreply.github.com> Date: Sat, 30 Mar 2024 17:42:15 +1100 Subject: uniform with descriptor set. fix image_index being 4 when expoected to be 3 --- assets/shaders/object.frag | 6 + assets/shaders/object.vert | 12 ++ assets/shaders/triangle.frag | 10 -- assets/shaders/triangle.vert | 11 -- examples/main_loop/ex_main_loop.c | 1 + src/renderer/backends/backend_vulkan.c | 293 +++++++++++++++++++++++---------- src/renderer/render_backend.h | 1 + xmake.lua | 10 +- 8 files changed, 233 insertions(+), 111 deletions(-) create mode 100644 assets/shaders/object.frag create mode 100644 assets/shaders/object.vert delete mode 100644 assets/shaders/triangle.frag delete mode 100644 assets/shaders/triangle.vert diff --git a/assets/shaders/object.frag b/assets/shaders/object.frag new file mode 100644 index 0000000..44c1eb3 --- /dev/null +++ b/assets/shaders/object.frag @@ -0,0 +1,6 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(location = 0) out vec4 out_colour; + +void main() { out_colour = vec4(1.0); } \ No newline at end of file diff --git a/assets/shaders/object.vert b/assets/shaders/object.vert new file mode 100644 index 0000000..9aaefed --- /dev/null +++ b/assets/shaders/object.vert @@ -0,0 +1,12 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(location = 0) in vec3 in_position; + +layout(set = 0, binding = 0) uniform global_object_uniform { + mat4 projection; + mat4 view; +} +global_ubo; + +void main() { gl_Position = global_ubo.projection * global_ubo.view * vec4(in_position, 1.0); } \ No newline at end of file diff --git a/assets/shaders/triangle.frag b/assets/shaders/triangle.frag deleted file mode 100644 index 8455d04..0000000 --- a/assets/shaders/triangle.frag +++ /dev/null @@ -1,10 +0,0 @@ -#version 450 -#extension GL_ARB_separate_shader_objects : enable - -layout(location = 0) in vec3 in_position; - -layout(location = 0) out vec4 out_colour; - -void main() { - out_colour = vec4(in_position.r + 0.5, in_position.g + 0.5, in_position.b + 0.5, 1.0); -} \ No newline at end of file diff --git a/assets/shaders/triangle.vert b/assets/shaders/triangle.vert deleted file mode 100644 index e34112d..0000000 --- a/assets/shaders/triangle.vert +++ /dev/null @@ -1,11 +0,0 @@ -#version 450 -#extension GL_ARB_separate_shader_objects : enable - -layout(location = 0) in vec3 in_position; - -layout(location = 0) out vec3 out_position; - -void main() { - gl_Position = vec4(in_position, 1.0); - out_position = in_position; -} \ No newline at end of file diff --git a/examples/main_loop/ex_main_loop.c b/examples/main_loop/ex_main_loop.c index 728290f..9a6f98c 100644 --- a/examples/main_loop/ex_main_loop.c +++ b/examples/main_loop/ex_main_loop.c @@ -1,6 +1,7 @@ #include #include "core.h" +#include "maths.h" #include "render.h" #include "render_backend.h" diff --git a/src/renderer/backends/backend_vulkan.c b/src/renderer/backends/backend_vulkan.c index 3e5137e..759da2f 100644 --- a/src/renderer/backends/backend_vulkan.c +++ b/src/renderer/backends/backend_vulkan.c @@ -133,13 +133,11 @@ typedef struct vulkan_pipeline { VkPipelineLayout layout; } vulkan_pipeline; -#define SHADER_STAGE_COUNT 2 - -typedef struct vulkan_shader { - // vertex, fragment - vulkan_shader_stage stages[SHADER_STAGE_COUNT]; - vulkan_pipeline pipeline; -} vulkan_shader; +typedef struct global_object_uniform { + mat4 projection; // 64 bytes + mat4 view; // 64 bytes + f32 padding[32]; +} global_object_uniform; typedef struct vulkan_buffer { u64 total_size; @@ -151,6 +149,24 @@ typedef struct vulkan_buffer { 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; +} vulkan_shader; + typedef struct vulkan_context { VkInstance instance; VkAllocationCallbacks* allocator; @@ -366,6 +382,69 @@ void vulkan_pipeline_bind(vulkan_command_buffer* command_buffer, VkPipelineBindP 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); + } + + 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) { @@ -398,8 +477,8 @@ bool create_shader_module(vulkan_context* context, const char* filename, const c 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/triangle.vert.spv", - "build/linux/x86_64/debug/triangle.frag.spv" }; + 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++) { @@ -408,7 +487,34 @@ bool vulkan_object_shader_create(vulkan_context* context, vulkan_shader* out_sha out_shader->stages); } - // TODO: descriptors + // 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; + + VkDescriptorSetLayoutCreateInfo global_layout_info = { + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO + }; + global_layout_info.bindingCount = 1; + global_layout_info.pBindings = &global_ubo_layout_binding; + + 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; + + VkDescriptorPoolCreateInfo pool_info = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO }; + pool_info.poolSizeCount = 1; + pool_info.pPoolSizes = &global_pool_size; + pool_info.maxSets = 3; + + VK_CHECK(vkCreateDescriptorPool(context->device.logical_device, &pool_info, context->allocator, + &out_shader->descriptor_pool)); // Pipeline creation VkViewport viewport; @@ -441,7 +547,8 @@ bool vulkan_object_shader_create(vulkan_context* context, vulkan_shader* out_sha offset += sizes[i]; } - // TODO: Descriptor set + // Descriptor set layouts + VkDescriptorSetLayout layouts[1] = { out_shader->descriptor_set_layout }; // Stages VkPipelineShaderStageCreateInfo stage_create_infos[SHADER_STAGE_COUNT]; @@ -451,11 +558,35 @@ bool vulkan_object_shader_create(vulkan_context* context, vulkan_shader* out_sha stage_create_infos[i] = out_shader->stages[i].stage_create_info; } - vulkan_graphics_pipeline_create(context, &context->main_renderpass, attribute_count, - attribute_descs, 0, 0, SHADER_STAGE_COUNT, stage_create_infos, - viewport, scissor, false, &out_shader->pipeline); + 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) {} @@ -464,6 +595,36 @@ void vulkan_object_shader_use(vulkan_context* context, vulkan_shader* shader) { 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]; + + vkCmdBindDescriptorSets(cmd_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, shader->pipeline.layout, 0, + 1, &global_descriptors, 0, 0); + + 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; + + VkWriteDescriptorSet descriptor_write = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET }; + descriptor_write.dstSet = shader->descriptor_sets[image_index]; + descriptor_write.dstBinding = 0; + descriptor_write.dstArrayElement = 0; + descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + descriptor_write.descriptorCount = 1; + descriptor_write.pBufferInfo = &buffer_info; + + vkUpdateDescriptorSets(context->device.logical_device, 1, &descriptor_write, 0, 0); +} bool select_physical_device(vulkan_context* ctx) { u32 physical_device_count = 0; @@ -734,69 +895,6 @@ void vulkan_image_create(vulkan_context* context, VkImageType image_type, u32 wi // TODO: vulkan_image_destroy -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); - } - - 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 - void vulkan_framebuffer_create(vulkan_context* context, vulkan_renderpass* renderpass, u32 width, u32 height, u32 attachment_count, VkImageView* attachments, vulkan_framebuffer* out_framebuffer) { @@ -935,7 +1033,7 @@ void vulkan_swapchain_create(vulkan_context* context, u32 width, u32 height, // TODO: requery swapchain support - u32 image_count = context->device.swapchain_support.capabilities.minImageCount + 1; + 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; @@ -1537,16 +1635,16 @@ void backend_begin_frame(renderer* ren, f32 delta_time) { context.swapchain.framebuffers->data[context.image_index].handle); // TODO: temp test code - vulkan_object_shader_use(&context, &context.object_shader); + // vulkan_object_shader_use(&context, &context.object_shader); - VkDeviceSize offsets[1] = { 0 }; - vkCmdBindVertexBuffers(command_buffer->handle, 0, 1, &context.object_vertex_buffer.handle, - (VkDeviceSize*)offsets); + // VkDeviceSize offsets[1] = { 0 }; + // vkCmdBindVertexBuffers(command_buffer->handle, 0, 1, &context.object_vertex_buffer.handle, + // (VkDeviceSize*)offsets); - vkCmdBindIndexBuffer(command_buffer->handle, context.object_index_buffer.handle, 0, - VK_INDEX_TYPE_UINT32); + // vkCmdBindIndexBuffer(command_buffer->handle, context.object_index_buffer.handle, 0, + // VK_INDEX_TYPE_UINT32); - vkCmdDrawIndexed(command_buffer->handle, 6, 1, 0, 0, 0); + // vkCmdDrawIndexed(command_buffer->handle, 6, 1, 0, 0, 0); // --- End temp test code } @@ -1591,9 +1689,34 @@ void backend_end_frame(renderer* ren, f32 delta_time) { void gfx_backend_draw_frame(renderer* ren) { backend_begin_frame(ren, 16.0); + gfx_backend_update_global_state(mat4_ident(), mat4_ident(), VEC3_ZERO, vec4(1.0, 1.0, 1.0, 1.0), + 0); + 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_command_buffer* cmd_buffer = &context.gfx_command_buffers->data[context.image_index]; + 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 + + // vulkan_object_shader_use(&context, &context.object_shader); + + VkDeviceSize offsets[1] = { 0 }; + vkCmdBindVertexBuffers(cmd_buffer->handle, 0, 1, &context.object_vertex_buffer.handle, + (VkDeviceSize*)offsets); + + vkCmdBindIndexBuffer(cmd_buffer->handle, context.object_index_buffer.handle, 0, + VK_INDEX_TYPE_UINT32); + + vkCmdDrawIndexed(cmd_buffer->handle, 6, 1, 0, 0, 0); +} + void clear_screen(vec3 colour) {} void bind_texture(shader s, texture* tex, u32 slot) {} diff --git a/src/renderer/render_backend.h b/src/renderer/render_backend.h index 041f412..69d14d8 100644 --- a/src/renderer/render_backend.h +++ b/src/renderer/render_backend.h @@ -13,6 +13,7 @@ bool gfx_backend_init(renderer* ren); void gfx_backend_shutdown(renderer* ren); void gfx_backend_draw_frame(renderer* ren); +void gfx_backend_update_global_state(mat4 projection, mat4 view, vec3 view_pos, vec4 ambient_colour, i32 mode); void clear_screen(vec3 colour); diff --git a/xmake.lua b/xmake.lua index 3005713..cb6d98a 100644 --- a/xmake.lua +++ b/xmake.lua @@ -69,7 +69,7 @@ rule("compile_glsl_vert_shaders") on_buildcmd_file(function (target, batchcmds, sourcefile, opt) local targetfile = path.join(target:targetdir(), path.basename(sourcefile) .. ".vert.spv") - print("Compiling shader: %s", sourcefile) + print("Compiling shader: %s to %s", sourcefile, targetfile) batchcmds:vrunv('glslc', {sourcefile, "-o", targetfile}) batchcmds:add_depfiles(sourcefile) end) @@ -78,7 +78,7 @@ rule("compile_glsl_frag_shaders") on_buildcmd_file(function (target, batchcmds, sourcefile, opt) local targetfile = path.join(target:targetdir(), path.basename(sourcefile) .. ".frag.spv") - print("Compiling shader: %s", sourcefile) + print("Compiling shader: %s to %s", sourcefile, targetfile) batchcmds:vrunv('glslc', {sourcefile, "-o", targetfile}) batchcmds:add_depfiles(sourcefile) end) @@ -104,11 +104,11 @@ target("core_config") add_includedirs("src/std/", {public = true}) add_includedirs("src/std/containers", {public = true}) add_includedirs("src/systems/", {public = true}) + add_files("src/empty.c") -- for some reason we need this on Mac so it doesnt call 'ar' with no files and error add_rules("compile_glsl_vert_shaders") add_rules("compile_glsl_frag_shaders") - add_files("src/empty.c") -- for some reason we need this on Mac so it doesnt call 'ar' with no files and error - add_files("assets/shaders/triangle.vert") - add_files("assets/shaders/triangle.frag") + add_files("assets/shaders/object.vert") + add_files("assets/shaders/object.frag") -- add_files("assets/shaders/*.frag") set_default(false) -- prevents standalone building of this target -- cgit v1.2.3-70-g09d2 From 16237e6499f47d963df35c0f0c4649900ec98d84 Mon Sep 17 00:00:00 2001 From: Omniscient <17525998+omnisci3nce@users.noreply.github.com> Date: Sat, 30 Mar 2024 17:49:36 +1100 Subject: square boi recedes into the distance. --- src/renderer/backends/backend_vulkan.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/src/renderer/backends/backend_vulkan.c b/src/renderer/backends/backend_vulkan.c index 759da2f..7be5918 100644 --- a/src/renderer/backends/backend_vulkan.c +++ b/src/renderer/backends/backend_vulkan.c @@ -1040,7 +1040,7 @@ void vulkan_swapchain_create(vulkan_context* context, u32 width, u32 height, 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 extend %d %d\n", swapchain_extent.width, swapchain_extent.height); + 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; @@ -1553,17 +1553,19 @@ bool gfx_backend_init(renderer* ren) { const u32 vert_count = 4; vertex_pos verts[4] = { 0 }; - verts[0].pos.x = 0.0; - verts[0].pos.y = -0.5; + const f32 s = 10.0; - verts[1].pos.x = 0.5; - verts[1].pos.y = 0.5; + verts[0].pos.x = 0.0 * s; + verts[0].pos.y = -0.5 * s; - verts[2].pos.x = 0.0; - verts[2].pos.y = 0.5; + verts[1].pos.x = 0.5 * s; + verts[1].pos.y = 0.5 * s; - verts[3].pos.x = 0.5; - verts[3].pos.y = -0.5; + verts[2].pos.x = 0.0 * 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 }; @@ -1689,8 +1691,12 @@ void backend_end_frame(renderer* ren, f32 delta_time) { void gfx_backend_draw_frame(renderer* ren) { backend_begin_frame(ren, 16.0); - gfx_backend_update_global_state(mat4_ident(), mat4_ident(), VEC3_ZERO, vec4(1.0, 1.0, 1.0, 1.0), - 0); + static f32 z = -1.0; + z -= 0.2; + mat4 proj = mat4_perspective(deg_to_rad(45.0), 1000 / 1000.0, 0.1, 1000.0); + mat4 view = mat4_translation(vec3(0, 0, z)); + + gfx_backend_update_global_state(proj, view, VEC3_ZERO, vec4(1.0, 1.0, 1.0, 1.0), 0); backend_end_frame(ren, 16.0); } -- cgit v1.2.3-70-g09d2 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 --- assets/shaders/object.vert | 10 ++- examples/input/ex_input.c | 113 +++++++++++++++++++++++++++++++++ examples/main_loop/ex_main_loop.c | 6 +- src/core.c | 13 ++++ src/core.h | 1 + src/maths/maths.h | 5 ++ src/renderer/backends/backend_vulkan.c | 63 +++++++++++------- src/renderer/render.c | 2 + src/renderer/render_backend.h | 6 +- src/systems/input.c | 19 ++++++ src/systems/keys.h | 15 ++++- xmake.lua | 11 +++- 12 files changed, 235 insertions(+), 29 deletions(-) create mode 100644 examples/input/ex_input.c diff --git a/assets/shaders/object.vert b/assets/shaders/object.vert index 9aaefed..a5097d4 100644 --- a/assets/shaders/object.vert +++ b/assets/shaders/object.vert @@ -9,4 +9,12 @@ layout(set = 0, binding = 0) uniform global_object_uniform { } global_ubo; -void main() { gl_Position = global_ubo.projection * global_ubo.view * vec4(in_position, 1.0); } \ No newline at end of file +layout(push_constant) uniform push_constants { + mat4 model; // 64 bytes +} +u_push_constants; + +void main() { + gl_Position = + global_ubo.projection * global_ubo.view * u_push_constants.model * vec4(in_position, 1.0); +} \ No newline at end of file diff --git a/examples/input/ex_input.c b/examples/input/ex_input.c new file mode 100644 index 0000000..d3d1fbd --- /dev/null +++ b/examples/input/ex_input.c @@ -0,0 +1,113 @@ +#include + +#include "camera.h" +#include "core.h" +#include "input.h" +#include "keys.h" +#include "maths.h" +#include "maths_types.h" +#include "render.h" +#include "render_backend.h" + +typedef struct game_state { + camera camera; + vec3 camera_euler; + bool first_mouse_update; +} game_state; + +void update_camera_rotation(input_state* input, game_state* game, camera* cam); + +int main() { + core* core = core_bringup(); + + game_state game = { + .camera = camera_create(vec3_create(0, 0, 30), vec3_create(0, 0, -1), VEC3_Y, deg_to_rad(45.0)), + .camera_euler = vec3_create(90, 0, 0), + .first_mouse_update = true, + }; + + printf("Starting look direction: "); + print_vec3(game.camera.front); + + // Main loop + const f32 camera_speed = 0.4; + + while (!should_exit(core)) { + input_update(&core->input); + + vec3 translation = VEC3_ZERO; + if (key_is_pressed(KEYCODE_W) || key_is_pressed(KEYCODE_KEY_UP)) { + printf("Move Forwards\n"); + translation = vec3_mult(game.camera.front, camera_speed); + } else if (key_is_pressed(KEYCODE_S) || key_is_pressed(KEYCODE_KEY_DOWN)) { + printf("Move Backwards\n"); + translation = vec3_mult(game.camera.front, -camera_speed); + } else if (key_is_pressed(KEYCODE_A) || key_is_pressed(KEYCODE_KEY_LEFT)) { + printf("Move Left\n"); + vec3 lateral = vec3_normalise(vec3_cross(game.camera.front, game.camera.up)); + translation = vec3_mult(lateral, -camera_speed); + } else if (key_is_pressed(KEYCODE_D) || key_is_pressed(KEYCODE_KEY_RIGHT)) { + printf("Move Right\n"); + vec3 lateral = vec3_normalise(vec3_cross(game.camera.front, game.camera.up)); + translation = vec3_mult(lateral, camera_speed); + } + game.camera.position = vec3_add(game.camera.position, translation); + update_camera_rotation(&core->input, &game, &game.camera); + + // UNUSED: threadpool_process_results(&core->threadpool, 1); + + render_frame_begin(&core->renderer); + + mat4 model = mat4_translation(VEC3_ZERO); + + gfx_backend_draw_frame(&core->renderer, &game.camera, model); + + render_frame_end(&core->renderer); + } + + core_shutdown(core); + + return 0; +} + +void update_camera_rotation(input_state* input, game_state* game, camera* cam) { + float xoffset = -input->mouse.x_delta; // xpos - lastX; + float yoffset = -input->mouse.y_delta; // reversed since y-coordinates go from bottom to top + if (game->first_mouse_update) { + xoffset = 0.0; + yoffset = 0.0; + game->first_mouse_update = false; + } + + printf("x offset: %f y offset %f\n", xoffset, yoffset); + + float sensitivity = 0.1f; // change this value to your liking + xoffset *= sensitivity; + yoffset *= sensitivity; + + // x = yaw + game->camera_euler.x += xoffset; + // y = pitch + game->camera_euler.y += yoffset; + // we dont update roll + + f32 yaw = game->camera_euler.x; + f32 pitch = game->camera_euler.y; + + // make sure that when pitch is out of bounds, screen doesn't get flipped + if (game->camera_euler.y > 89.0f) game->camera_euler.y = 89.0f; + if (game->camera_euler.y < -89.0f) game->camera_euler.y = -89.0f; + + vec3 front = cam->front; + front.x = cos(deg_to_rad(yaw) * cos(deg_to_rad(pitch))); + front.y = sin(deg_to_rad(pitch)); + front.z = sin(deg_to_rad(yaw)) * cos(deg_to_rad(pitch)); + + front = vec3_normalise(front); + // save it back + cam->front.x = front.x; + cam->front.y = front.y; + // cam->front.z = front.z; + + print_vec3(cam->front); +} diff --git a/examples/main_loop/ex_main_loop.c b/examples/main_loop/ex_main_loop.c index 9a6f98c..25dbf4a 100644 --- a/examples/main_loop/ex_main_loop.c +++ b/examples/main_loop/ex_main_loop.c @@ -15,7 +15,11 @@ int main() { render_frame_begin(&core->renderer); - gfx_backend_draw_frame(&core->renderer); + static f32 x = 0.0; + x += 0.01; + mat4 model = mat4_translation(vec3(x, 0, 0)); + + gfx_backend_draw_frame(&core->renderer, model); // insert work here diff --git a/src/core.c b/src/core.c index 4b3bd1b..0db8962 100644 --- a/src/core.c +++ b/src/core.c @@ -2,6 +2,9 @@ #include +#include "glfw3.h" +#include "input.h" +#include "keys.h" #include "log.h" #include "render.h" #include "render_types.h" @@ -49,3 +52,13 @@ core* core_bringup() { return c; } + +void core_shutdown(core* core) { + // threadpool_destroy(&core->threadpool); + input_system_shutdown(&core->input); + renderer_shutdown(&core->renderer); +} + +bool should_exit(core* core) { + return key_just_released(KEYCODE_ESCAPE) || glfwWindowShouldClose(core->renderer.window); +} \ No newline at end of file diff --git a/src/core.h b/src/core.h index f54631e..05e3aed 100644 --- a/src/core.h +++ b/src/core.h @@ -20,5 +20,6 @@ typedef struct core { // --- Lifecycle core* core_bringup(); void core_shutdown(core* core); +bool should_exit(core* core); void core_input_update(core* core); diff --git a/src/maths/maths.h b/src/maths/maths.h index 6816415..baa75e9 100644 --- a/src/maths/maths.h +++ b/src/maths/maths.h @@ -9,6 +9,7 @@ #pragma once #include +#include #include "maths_types.h" // --- Helpers @@ -48,6 +49,10 @@ static inline vec3 vec3_cross(vec3 a, vec3 b) { #define VEC3_Z ((vec3){ .x = 0.0, .y = 0.0, .z = 1.0 }) #define VEC3_NEG_Z ((vec3){ .x = 0.0, .y = 0.0, .z = -1.0 }) +static inline void print_vec3(vec3 v) { + printf("{ x: %f, y: %f, z: %f )\n", v.x, v.y, v.z); +} + // TODO: Dimension 2 static inline vec2 vec2_create(f32 x, f32 y) { return (vec2){ x, y }; } diff --git a/src/renderer/backends/backend_vulkan.c b/src/renderer/backends/backend_vulkan.c index 7be5918..43ea658 100644 --- a/src/renderer/backends/backend_vulkan.c +++ b/src/renderer/backends/backend_vulkan.c @@ -1,3 +1,4 @@ +#include "camera.h" #define CDEBUG #define CEL_PLATFORM_LINUX // ^ Temporary @@ -337,6 +338,16 @@ bool vulkan_graphics_pipeline_create(vulkan_context* context, vulkan_renderpass* 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; @@ -600,9 +611,6 @@ void vulkan_object_shader_update_global_state(vulkan_context* context, vulkan_sh VkCommandBuffer cmd_buffer = context->gfx_command_buffers->data[image_index].handle; VkDescriptorSet global_descriptors = shader->descriptor_sets[image_index]; - vkCmdBindDescriptorSets(cmd_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, shader->pipeline.layout, 0, - 1, &global_descriptors, 0, 0); - u32 range = sizeof(global_object_uniform); u64 offset = 0; @@ -624,6 +632,28 @@ void vulkan_object_shader_update_global_state(vulkan_context* context, vulkan_sh descriptor_write.pBufferInfo = &buffer_info; vkUpdateDescriptorSets(context->device.logical_device, 1, &descriptor_write, 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, 6, 1, 0, 0, 0); } bool select_physical_device(vulkan_context* ctx) { @@ -1555,13 +1585,13 @@ bool gfx_backend_init(renderer* ren) { const f32 s = 10.0; - verts[0].pos.x = 0.0 * s; + 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.0 * s; + verts[2].pos.x = -0.5 * s; verts[2].pos.y = 0.5 * s; verts[3].pos.x = 0.5 * s; @@ -1688,39 +1718,28 @@ void backend_end_frame(renderer* ren, f32 delta_time) { context.queue_complete_semaphores[context.current_frame], context.image_index); } -void gfx_backend_draw_frame(renderer* ren) { +void gfx_backend_draw_frame(renderer* ren, camera* cam, mat4 model) { backend_begin_frame(ren, 16.0); - static f32 z = -1.0; - z -= 0.2; - mat4 proj = mat4_perspective(deg_to_rad(45.0), 1000 / 1000.0, 0.1, 1000.0); - mat4 view = mat4_translation(vec3(0, 0, z)); + mat4 proj; + mat4 view; + + camera_view_projection(cam, SCR_HEIGHT, SCR_WIDTH, &view, &proj); gfx_backend_update_global_state(proj, view, VEC3_ZERO, 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_command_buffer* cmd_buffer = &context.gfx_command_buffers->data[context.image_index]; 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 - - // vulkan_object_shader_use(&context, &context.object_shader); - - VkDeviceSize offsets[1] = { 0 }; - vkCmdBindVertexBuffers(cmd_buffer->handle, 0, 1, &context.object_vertex_buffer.handle, - (VkDeviceSize*)offsets); - - vkCmdBindIndexBuffer(cmd_buffer->handle, context.object_index_buffer.handle, 0, - VK_INDEX_TYPE_UINT32); - - vkCmdDrawIndexed(cmd_buffer->handle, 6, 1, 0, 0, 0); } void clear_screen(vec3 colour) {} diff --git a/src/renderer/render.c b/src/renderer/render.c index 74b98cf..54b63b6 100644 --- a/src/renderer/render.c +++ b/src/renderer/render.c @@ -61,6 +61,8 @@ bool renderer_init(renderer* ren) { return true; } +void renderer_shutdown(renderer* ren) {} + void render_frame_begin(renderer* ren) { vec3 color = ren->config.clear_colour; clear_screen(color); diff --git a/src/renderer/render_backend.h b/src/renderer/render_backend.h index 69d14d8..ea84b27 100644 --- a/src/renderer/render_backend.h +++ b/src/renderer/render_backend.h @@ -3,6 +3,7 @@ */ #pragma once +#include "camera.h" #include "maths_types.h" #include "render_types.h" @@ -12,8 +13,9 @@ bool gfx_backend_init(renderer* ren); void gfx_backend_shutdown(renderer* ren); -void gfx_backend_draw_frame(renderer* ren); -void gfx_backend_update_global_state(mat4 projection, mat4 view, vec3 view_pos, vec4 ambient_colour, i32 mode); +void gfx_backend_draw_frame(renderer* ren, camera* camera, mat4 model); +void gfx_backend_update_global_state(mat4 projection, mat4 view, vec3 view_pos, vec4 ambient_colour, + i32 mode); void clear_screen(vec3 colour); 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 diff --git a/xmake.lua b/xmake.lua index cb6d98a..29c1de0 100644 --- a/xmake.lua +++ b/xmake.lua @@ -71,7 +71,7 @@ rule("compile_glsl_vert_shaders") print("Compiling shader: %s to %s", sourcefile, targetfile) batchcmds:vrunv('glslc', {sourcefile, "-o", targetfile}) - batchcmds:add_depfiles(sourcefile) + -- batchcmds:add_depfiles(sourcefile) end) rule("compile_glsl_frag_shaders") set_extensions(".frag") @@ -80,7 +80,7 @@ rule("compile_glsl_frag_shaders") print("Compiling shader: %s to %s", sourcefile, targetfile) batchcmds:vrunv('glslc', {sourcefile, "-o", targetfile}) - batchcmds:add_depfiles(sourcefile) + -- batchcmds:add_depfiles(sourcefile) end) -- TODO: Metal shaders compilation @@ -144,6 +144,13 @@ target("obj") add_files("examples/obj_loading/ex_obj_loading.c") set_rundir("$(projectdir)") +target("input") + set_kind("binary") + set_group("examples") + add_deps("core_static") + add_files("examples/input/ex_input.c") + set_rundir("$(projectdir)") + target("demo") set_kind("binary") set_group("examples") -- cgit v1.2.3-70-g09d2 From 2c55e9a73ae1321c14f5186ecc75ac949ad19bbd Mon Sep 17 00:00:00 2001 From: Omniscient <17525998+omnisci3nce@users.noreply.github.com> Date: Sat, 30 Mar 2024 21:46:10 +1100 Subject: chore: format --- examples/input/ex_input.c | 4 +--- src/maths/maths.h | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/examples/input/ex_input.c b/examples/input/ex_input.c index d3d1fbd..4bbf76a 100644 --- a/examples/input/ex_input.c +++ b/examples/input/ex_input.c @@ -79,8 +79,6 @@ void update_camera_rotation(input_state* input, game_state* game, camera* cam) { game->first_mouse_update = false; } - printf("x offset: %f y offset %f\n", xoffset, yoffset); - float sensitivity = 0.1f; // change this value to your liking xoffset *= sensitivity; yoffset *= sensitivity; @@ -107,7 +105,7 @@ void update_camera_rotation(input_state* input, game_state* game, camera* cam) { // save it back cam->front.x = front.x; cam->front.y = front.y; - // cam->front.z = front.z; + // roll is static print_vec3(cam->front); } diff --git a/src/maths/maths.h b/src/maths/maths.h index baa75e9..6fbdfdf 100644 --- a/src/maths/maths.h +++ b/src/maths/maths.h @@ -49,9 +49,7 @@ static inline vec3 vec3_cross(vec3 a, vec3 b) { #define VEC3_Z ((vec3){ .x = 0.0, .y = 0.0, .z = 1.0 }) #define VEC3_NEG_Z ((vec3){ .x = 0.0, .y = 0.0, .z = -1.0 }) -static inline void print_vec3(vec3 v) { - printf("{ x: %f, y: %f, z: %f )\n", v.x, v.y, v.z); -} +static inline void print_vec3(vec3 v) { printf("{ x: %f, y: %f, z: %f )\n", v.x, v.y, v.z); } // TODO: Dimension 2 static inline vec2 vec2_create(f32 x, f32 y) { return (vec2){ x, y }; } -- cgit v1.2.3-70-g09d2 From c20740ecbb008afbe93c7fa1eb35851cedc6eb42 Mon Sep 17 00:00:00 2001 From: Omniscient <17525998+omnisci3nce@users.noreply.github.com> Date: Sat, 30 Mar 2024 23:14:39 +1100 Subject: vulkan glossary --- examples/input/ex_input.c | 2 +- src/renderer/backends/vulkan/vulkan_glossary.md | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 src/renderer/backends/vulkan/vulkan_glossary.md diff --git a/examples/input/ex_input.c b/examples/input/ex_input.c index 4bbf76a..7ead3ec 100644 --- a/examples/input/ex_input.c +++ b/examples/input/ex_input.c @@ -12,7 +12,7 @@ typedef struct game_state { camera camera; vec3 camera_euler; - bool first_mouse_update; + bool first_mouse_update; // so the camera doesnt lurch when you run the first process_camera_rotation } game_state; void update_camera_rotation(input_state* input, game_state* game, camera* cam); diff --git a/src/renderer/backends/vulkan/vulkan_glossary.md b/src/renderer/backends/vulkan/vulkan_glossary.md new file mode 100644 index 0000000..4214f9d --- /dev/null +++ b/src/renderer/backends/vulkan/vulkan_glossary.md @@ -0,0 +1,18 @@ +# Vulkan Glossary + +*from https://vkguide.dev/docs/introduction/vulkan_execution/* + +- **VkInstance**: The Vulkan context, used to access drivers. +- **VkPhysicalDevice**: A GPU. Used to query physical GPU details, like features, capabilities, memory size, etc. +- **VkDevice**: The “logical” GPU context that you actually execute things on. +- **VkBuffer**: A chunk of GPU visible memory. +- **VkImage**: A texture you can write to and read from. +- **VkPipeline**: Holds the state of the gpu needed to draw. For example: shaders, rasterization options, depth settings. +- **VkRenderPass**: Holds information about the images you are rendering into. All drawing commands have to be done inside a renderpass. Only used in legacy vkguide. +- **VkFrameBuffer**: Holds the target images for a renderpass. Only used in legacy vkguide. +- **VkCommandBuffer**: Encodes GPU commands. All execution that is performed on the GPU itself (not in the driver) has to be encoded in a VkCommandBuffer. +- **VkQueue**: Execution “port” for commands. GPUs will have a set of queues with different properties. Some allow only graphics commands, others only allow memory commands, etc. Command buffers are executed by submitting them into a queue, which will copy the rendering commands onto the GPU for execution. +- **VkDescriptorSet**: Holds the binding information that connects shader inputs to data such as VkBuffer resources and VkImage textures. Think of it as a set of gpu-side pointers that you bind once. +- **VkSwapchainKHR**: Holds the images for the screen. It allows you to render things into a visible window. The KHR suffix shows that it comes from an extension, which in this case is VK_KHR_swapchain. +- **VkSemaphore**: Synchronizes GPU to GPU execution of commands. Used for syncing multiple command buffer submissions one after another. +- **VkFence**: Synchronizes GPU to CPU execution of commands. Used to know if a command buffer has finished being executed on the GPU. -- cgit v1.2.3-70-g09d2 From b638fd776253fa0cb841175e3e134df4587101b6 Mon Sep 17 00:00:00 2001 From: Omniscient <17525998+omnisci3nce@users.noreply.github.com> Date: Sat, 30 Mar 2024 23:16:53 +1100 Subject: fix main loop example --- examples/input/ex_input.c | 3 ++- examples/main_loop/ex_main_loop.c | 5 ++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/examples/input/ex_input.c b/examples/input/ex_input.c index 7ead3ec..0e72c16 100644 --- a/examples/input/ex_input.c +++ b/examples/input/ex_input.c @@ -12,7 +12,8 @@ typedef struct game_state { camera camera; vec3 camera_euler; - bool first_mouse_update; // so the camera doesnt lurch when you run the first process_camera_rotation + bool first_mouse_update; // so the camera doesnt lurch when you run the first + // process_camera_rotation } game_state; void update_camera_rotation(input_state* input, game_state* game, camera* cam); diff --git a/examples/main_loop/ex_main_loop.c b/examples/main_loop/ex_main_loop.c index 25dbf4a..31514bf 100644 --- a/examples/main_loop/ex_main_loop.c +++ b/examples/main_loop/ex_main_loop.c @@ -1,5 +1,6 @@ #include +#include "camera.h" #include "core.h" #include "maths.h" #include "render.h" @@ -8,6 +9,8 @@ int main() { core* core = core_bringup(); + camera camera = camera_create(vec3_create(0, 0, 20), VEC3_NEG_Z, VEC3_Y, deg_to_rad(45.0)); + // Main loop while (!glfwWindowShouldClose(core->renderer.window)) { input_update(&core->input); @@ -19,7 +22,7 @@ int main() { x += 0.01; mat4 model = mat4_translation(vec3(x, 0, 0)); - gfx_backend_draw_frame(&core->renderer, model); + gfx_backend_draw_frame(&core->renderer, &camera, model); // insert work here -- cgit v1.2.3-70-g09d2 From c4bf1916fe219324e14384fc938e767daeab26c9 Mon Sep 17 00:00:00 2001 From: Omniscient <17525998+omnisci3nce@users.noreply.github.com> Date: Sun, 31 Mar 2024 00:48:11 +1100 Subject: working on cube (hardcoded) --- assets/shaders/object.frag | 5 ++- assets/shaders/object.vert | 10 ++++- examples/gltf_loading/ex_gltf_loading.c | 0 examples/input/ex_input.c | 10 ++++- src/maths/maths.h | 19 ++++++++++ src/maths/primitives.h | 67 +++++++++++++++++++++++++++++++++ src/renderer/backends/backend_vulkan.c | 62 ++++++++++++++++++------------ src/renderer/cleanroom/types.h | 7 +++- 8 files changed, 149 insertions(+), 31 deletions(-) create mode 100644 examples/gltf_loading/ex_gltf_loading.c create mode 100644 src/maths/primitives.h diff --git a/assets/shaders/object.frag b/assets/shaders/object.frag index 44c1eb3..11b33e1 100644 --- a/assets/shaders/object.frag +++ b/assets/shaders/object.frag @@ -1,6 +1,9 @@ #version 450 #extension GL_ARB_separate_shader_objects : enable +layout(location = 0) in vec3 in_normal; +layout(location = 1) in vec3 in_position; + layout(location = 0) out vec4 out_colour; -void main() { out_colour = vec4(1.0); } \ No newline at end of file +void main() { out_colour = vec4(in_normal, 1.0); } \ No newline at end of file diff --git a/assets/shaders/object.vert b/assets/shaders/object.vert index a5097d4..a7237bb 100644 --- a/assets/shaders/object.vert +++ b/assets/shaders/object.vert @@ -2,6 +2,10 @@ #extension GL_ARB_separate_shader_objects : enable layout(location = 0) in vec3 in_position; +layout(location = 1) in vec3 in_normal; + +layout(location = 0) out vec3 out_normal; +layout(location = 1) out vec3 out_position; layout(set = 0, binding = 0) uniform global_object_uniform { mat4 projection; @@ -15,6 +19,8 @@ layout(push_constant) uniform push_constants { u_push_constants; void main() { - gl_Position = - global_ubo.projection * global_ubo.view * u_push_constants.model * vec4(in_position, 1.0); + out_position = in_position; + gl_Position = global_ubo.projection * global_ubo.view * u_push_constants.model * + vec4(in_position.x, in_position.y, in_position.z, 1.0); + out_normal = in_normal; // forward normal vectors } \ No newline at end of file diff --git a/examples/gltf_loading/ex_gltf_loading.c b/examples/gltf_loading/ex_gltf_loading.c new file mode 100644 index 0000000..e69de29 diff --git a/examples/input/ex_input.c b/examples/input/ex_input.c index 0e72c16..f102fad 100644 --- a/examples/input/ex_input.c +++ b/examples/input/ex_input.c @@ -6,8 +6,10 @@ #include "keys.h" #include "maths.h" #include "maths_types.h" +#include "primitives.h" #include "render.h" #include "render_backend.h" +#include "render_types.h" typedef struct game_state { camera camera; @@ -21,12 +23,15 @@ void update_camera_rotation(input_state* input, game_state* game, camera* cam); int main() { core* core = core_bringup(); + vec3 cam_pos = vec3_create(-15, 20.0, 13); game_state game = { - .camera = camera_create(vec3_create(0, 0, 30), vec3_create(0, 0, -1), VEC3_Y, deg_to_rad(45.0)), + .camera = camera_create(cam_pos, vec3_negate(cam_pos), VEC3_Y, deg_to_rad(45.0)), .camera_euler = vec3_create(90, 0, 0), .first_mouse_update = true, }; + // model_handle cube_handle = prim_cube_new(core); + printf("Starting look direction: "); print_vec3(game.camera.front); @@ -53,12 +58,13 @@ int main() { translation = vec3_mult(lateral, camera_speed); } game.camera.position = vec3_add(game.camera.position, translation); - update_camera_rotation(&core->input, &game, &game.camera); + // update_camera_rotation(&core->input, &game, &game.camera); // UNUSED: threadpool_process_results(&core->threadpool, 1); render_frame_begin(&core->renderer); + // model cube = core->models->data[cube_handle.raw]; mat4 model = mat4_translation(VEC3_ZERO); gfx_backend_draw_frame(&core->renderer, &game.camera, model); diff --git a/src/maths/maths.h b/src/maths/maths.h index 41fbdfc..9206c5c 100644 --- a/src/maths/maths.h +++ b/src/maths/maths.h @@ -132,6 +132,24 @@ static inline mat4 mat4_mult(mat4 lhs, mat4 rhs) { return out_matrix; } +#if defined(CEL_REND_BACKEND_VULKAN) +/** @brief Creates a perspective projection matrix compatible with Vulkan */ +static inline mat4 mat4_perspective(f32 fov_radians, f32 aspect_ratio, f32 near_clip, f32 far_clip) { + // near_clip *= -1.0; + // far_clip *= -1.0; + + f32 half_tan_fov = tanf(fov_radians * 0.5f); + mat4 out_matrix = { .data = { 0 } }; + + out_matrix.data[0] = 1.0f / (aspect_ratio * half_tan_fov); + out_matrix.data[5] = -1.0f / half_tan_fov; // Flip Y-axis for Vulkan + out_matrix.data[10] = -((far_clip + near_clip) / (far_clip - near_clip)); + out_matrix.data[11] = -1.0f; + out_matrix.data[14] = -((2.0f * far_clip * near_clip) / (far_clip - near_clip)); + + return out_matrix; +} +#else /** @brief Creates a perspective projection matrix */ static inline mat4 mat4_perspective(f32 fov_radians, f32 aspect_ratio, f32 near_clip, f32 far_clip) { @@ -144,6 +162,7 @@ static inline mat4 mat4_perspective(f32 fov_radians, f32 aspect_ratio, f32 near_ out_matrix.data[14] = -((2.0f * far_clip * near_clip) / (far_clip - near_clip)); return out_matrix; } +#endif /** @brief Creates an orthographic projection matrix */ static inline mat4 mat4_orthographic(f32 left, f32 right, f32 bottom, f32 top, f32 near_clip, diff --git a/src/maths/primitives.h b/src/maths/primitives.h new file mode 100644 index 0000000..60d36da --- /dev/null +++ b/src/maths/primitives.h @@ -0,0 +1,67 @@ +#pragma once + +#include +#include "core.h" +#include "render_types.h" + +static float cube_vertices[] = { + // positions // normals // texture coords + -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.5f, -0.5f, -0.5f, 0.0f, + 0.0f, -1.0f, 1.0f, 0.0f, 0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f, + 0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f, -0.5f, 0.5f, -0.5f, 0.0f, + 0.0f, -1.0f, 0.0f, 1.0f, -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, + + -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.5f, -0.5f, 0.5f, 0.0f, + 0.0f, 1.0f, 1.0f, 0.0f, 0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, + 0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, -0.5f, 0.5f, 0.5f, 0.0f, + 0.0f, 1.0f, 0.0f, 1.0f, -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, + + -0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, -0.5f, 0.5f, -0.5f, -1.0f, + 0.0f, 0.0f, 1.0f, 1.0f, -0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, + -0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, -0.5f, -0.5f, 0.5f, -1.0f, + 0.0f, 0.0f, 0.0f, 0.0f, -0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, + + 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.5f, 0.5f, -0.5f, 1.0f, + 0.0f, 0.0f, 1.0f, 1.0f, 0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, + 0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.5f, -0.5f, 0.5f, 1.0f, + 0.0f, 0.0f, 0.0f, 0.0f, 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, + + -0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.5f, -0.5f, -0.5f, 0.0f, + -1.0f, 0.0f, 1.0f, 1.0f, 0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, + 0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, -0.5f, -0.5f, 0.5f, 0.0f, + -1.0f, 0.0f, 0.0f, 0.0f, -0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, + + -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.5f, 0.5f, -0.5f, 0.0f, + 1.0f, 0.0f, 1.0f, 1.0f, 0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, + 0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, -0.5f, 0.5f, 0.5f, 0.0f, + 1.0f, 0.0f, 0.0f, 0.0f, -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f +}; + +static mesh prim_cube_mesh_create() { + mesh cube = { 0 }; + cube.vertices = vertex_darray_new(36); + + for (int i = 0; i < 36; i++) { + vertex vert = { .position = vec3_create(cube_vertices[(i * 8) + 0], cube_vertices[(i * 8) + 1], + cube_vertices[(i * 8) + 2]), + .normal = vec3_create(cube_vertices[(i * 8) + 3], cube_vertices[(i * 8) + 4], + cube_vertices[(i * 8) + 5]), + .uv = (vec2){ .x = cube_vertices[(i * 8) + 6], + .y = cube_vertices[(i * 8) + 7] } }; + vertex_darray_push(cube.vertices, vert); + } + 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/renderer/backends/backend_vulkan.c b/src/renderer/backends/backend_vulkan.c index 43ea658..f83b271 100644 --- a/src/renderer/backends/backend_vulkan.c +++ b/src/renderer/backends/backend_vulkan.c @@ -1,4 +1,5 @@ #include "camera.h" +#include "primitives.h" #define CDEBUG #define CEL_PLATFORM_LINUX // ^ Temporary @@ -226,6 +227,7 @@ typedef struct vulkan_state { typedef struct vertex_pos { vec3 pos; + vec3 normal; } vertex_pos; // pipeline stuff @@ -530,9 +532,9 @@ bool vulkan_object_shader_create(vulkan_context* context, vulkan_shader* out_sha // Pipeline creation VkViewport viewport; viewport.x = 0; - viewport.y = (f32)context->framebuffer_height; + viewport.y = 0; viewport.width = (f32)context->framebuffer_width; - viewport.height = -(f32)context->framebuffer_height; + viewport.height = (f32)context->framebuffer_height; viewport.minDepth = 0.0; viewport.maxDepth = 1.0; @@ -543,12 +545,12 @@ bool vulkan_object_shader_create(vulkan_context* context, vulkan_shader* out_sha // Attributes u32 offset = 0; - const i32 attribute_count = 1; - VkVertexInputAttributeDescription attribute_descs[1]; + const i32 attribute_count = 2; + VkVertexInputAttributeDescription attribute_descs[2]; // Position - VkFormat formats[1] = { VK_FORMAT_R32G32B32_SFLOAT }; + VkFormat formats[2] = { VK_FORMAT_R32G32B32_SFLOAT, VK_FORMAT_R32G32B32_SFLOAT }; - u64 sizes[1] = { sizeof(vec3) }; + u64 sizes[2] = { sizeof(vec3), sizeof(vec3) }; for (u32 i = 0; i < attribute_count; i++) { attribute_descs[i].binding = 0; @@ -651,9 +653,10 @@ void vulkan_object_shader_update_object(vulkan_context* context, vulkan_shader* 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); + // vkCmdBindIndexBuffer(cmd_buffer, context->object_index_buffer.handle, 0, VK_INDEX_TYPE_UINT32); - vkCmdDrawIndexed(cmd_buffer, 6, 1, 0, 0, 0); + // vkCmdDrawIndexed(cmd_buffer, 6, 1, 0, 0, 0); + vkCmdDraw(cmd_buffer, 36, 1, 0, 0); } bool select_physical_device(vulkan_context* ctx) { @@ -1580,22 +1583,33 @@ bool gfx_backend_init(renderer* ren) { INFO("Created buffers"); // TODO: temporary test code - const u32 vert_count = 4; - vertex_pos verts[4] = { 0 }; - const f32 s = 10.0; + mesh cube = prim_cube_mesh_create(); - verts[0].pos.x = -0.5 * s; - verts[0].pos.y = -0.5 * s; + const u32 vert_count = 36; + // vertex_pos verts[4] = { 0 }; - verts[1].pos.x = 0.5 * s; - verts[1].pos.y = 0.5 * s; + vertex_pos verts[36] = { 0 }; - verts[2].pos.x = -0.5 * s; - verts[2].pos.y = 0.5 * s; + f32 scale = 3.0; + for (size_t i = 0; i < 36; i++) { + verts[i].pos = vec3_mult(cube.vertices->data[i].position, scale); + verts[i].normal = cube.vertices->data[i].normal; + } + + // const f32 s = 10.0; + + // verts[0].pos.x = -0.5 * s; + // verts[0].pos.y = -0.5 * s; - verts[3].pos.x = 0.5 * s; - verts[3].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 }; @@ -1603,9 +1617,9 @@ bool gfx_backend_init(renderer* ren) { upload_data_range(&context, context.device.gfx_command_pool, 0, context.device.graphics_queue, &context.object_vertex_buffer, 0, sizeof(vertex_pos) * vert_count, 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) * index_count, indices); - TRACE("Uploaded index data"); + // upload_data_range(&context, context.device.gfx_command_pool, 0, context.device.graphics_queue, + // &context.object_index_buffer, 0, sizeof(u32) * index_count, indices); + // TRACE("Uploaded index data"); // --- End test code INFO("Vulkan renderer initialisation succeeded"); @@ -1646,9 +1660,9 @@ void backend_begin_frame(renderer* ren, f32 delta_time) { VkViewport viewport; viewport.x = 0.0; - viewport.y = (f32)context.framebuffer_height; + viewport.y = 0.0; viewport.width = (f32)context.framebuffer_width; - viewport.height = -(f32)context.framebuffer_height; + viewport.height = (f32)context.framebuffer_height; viewport.minDepth = 0.0; viewport.maxDepth = 1.0; diff --git a/src/renderer/cleanroom/types.h b/src/renderer/cleanroom/types.h index 23f2348..0a26120 100644 --- a/src/renderer/cleanroom/types.h +++ b/src/renderer/cleanroom/types.h @@ -77,10 +77,12 @@ typedef union vertex { } vertex; KITC_DECL_TYPED_ARRAY(vertex) +KITC_DECL_TYPED_ARRAY(u32) typedef struct geometry_data { vertex_format format; vertex_darray vertices; + u32_darray indices; } geometry_data; typedef struct mesh { @@ -110,7 +112,7 @@ void texture_data_upload(texture_handle texture); buffer_handle buffer_create(const char* debug_name, u64 size); // models and meshes are implemented **in terms of the above** -mesh mesh_create(); +mesh mesh_create(geometry_data* geometry); model_handle model_load(const char* filepath); /* ral.h */ @@ -123,10 +125,11 @@ void gpu_texture_init(); void gpu_texture_upload(); void gpu_buffer_init(); void gpu_buffer_upload(); +void gpu_buffer_bind(); // command buffer gubbins -// 3. SIMA (simplified immediate mode api) +// 3. SIMA (simplified immediate mode api) / render.h // - dont need to worry about uploading mesh data // - very useful for debugging void imm_draw_cuboid(); -- cgit v1.2.3-70-g09d2 From 6463c6c1090644438d8449f7ae1a152a4a196123 Mon Sep 17 00:00:00 2001 From: omniscient <17525998+omnisci3nce@users.noreply.github.com> Date: Sun, 31 Mar 2024 02:34:19 +1100 Subject: more api design --- src/maths/maths.h | 23 ++++----- src/maths/maths_types.h | 6 ++- src/maths/primitives.h | 2 +- src/renderer/backends/backend_vulkan.c | 1 + src/renderer/cleanroom/types.h | 88 +++++++++++++++++++++++++++------- 5 files changed, 91 insertions(+), 29 deletions(-) diff --git a/src/maths/maths.h b/src/maths/maths.h index 9206c5c..6fa2f9b 100644 --- a/src/maths/maths.h +++ b/src/maths/maths.h @@ -134,20 +134,21 @@ static inline mat4 mat4_mult(mat4 lhs, mat4 rhs) { #if defined(CEL_REND_BACKEND_VULKAN) /** @brief Creates a perspective projection matrix compatible with Vulkan */ -static inline mat4 mat4_perspective(f32 fov_radians, f32 aspect_ratio, f32 near_clip, f32 far_clip) { - // near_clip *= -1.0; - // far_clip *= -1.0; - - f32 half_tan_fov = tanf(fov_radians * 0.5f); - mat4 out_matrix = { .data = { 0 } }; - - out_matrix.data[0] = 1.0f / (aspect_ratio * half_tan_fov); - out_matrix.data[5] = -1.0f / half_tan_fov; // Flip Y-axis for Vulkan - out_matrix.data[10] = -((far_clip + near_clip) / (far_clip - near_clip)); +static inline mat4 mat4_perspective(f32 fov_radians, f32 aspect_ratio, f32 near_clip, + f32 far_clip) { + // near_clip *= -1.0; + // far_clip *= -1.0; + + f32 half_tan_fov = tanf(fov_radians * 0.5f); + mat4 out_matrix = { .data = { 0 } }; + + out_matrix.data[0] = 1.0f / (aspect_ratio * half_tan_fov); + out_matrix.data[5] = -1.0f / half_tan_fov; // Flip Y-axis for Vulkan + out_matrix.data[10] = -((far_clip + near_clip) / (far_clip - near_clip)); out_matrix.data[11] = -1.0f; out_matrix.data[14] = -((2.0f * far_clip * near_clip) / (far_clip - near_clip)); - return out_matrix; + return out_matrix; } #else /** @brief Creates a perspective projection matrix */ diff --git a/src/maths/maths_types.h b/src/maths/maths_types.h index ba741b9..6d38fc7 100644 --- a/src/maths/maths_types.h +++ b/src/maths/maths_types.h @@ -60,4 +60,8 @@ typedef struct transform { quat rotation; f32 scale; bool is_dirty; -} transform; \ No newline at end of file +} transform; + +typedef struct vec4i { + i32 x, y, z, w; +} vec4i; \ No newline at end of file diff --git a/src/maths/primitives.h b/src/maths/primitives.h index 60d36da..fd798c1 100644 --- a/src/maths/primitives.h +++ b/src/maths/primitives.h @@ -55,7 +55,7 @@ static mesh prim_cube_mesh_create() { /** @brief create a new model with the shape of a cube */ static model_handle prim_cube_new(core* core) { - model model = { 0 }; + model model = { 0 }; mesh cube = prim_cube_mesh_create(); mesh_darray_push(model.meshes, cube); diff --git a/src/renderer/backends/backend_vulkan.c b/src/renderer/backends/backend_vulkan.c index f83b271..1657594 100644 --- a/src/renderer/backends/backend_vulkan.c +++ b/src/renderer/backends/backend_vulkan.c @@ -103,6 +103,7 @@ typedef struct vulkan_swapchain { vulkan_framebuffer_darray* framebuffers; } vulkan_swapchain; +// overengineered typedef enum vulkan_command_buffer_state { COMMAND_BUFFER_STATE_READY, COMMAND_BUFFER_STATE_IN_RENDER_PASS, diff --git a/src/renderer/cleanroom/types.h b/src/renderer/cleanroom/types.h index 0a26120..3f62cab 100644 --- a/src/renderer/cleanroom/types.h +++ b/src/renderer/cleanroom/types.h @@ -1,6 +1,7 @@ #pragma once #include "darray.h" #include "defines.h" +#include "maths_types.h" #include "str.h" typedef int texture_handle; @@ -14,9 +15,9 @@ typedef struct texture_desc { // u32x2 extents; } texture_desc; -/* +/* - render_types.h - - ral_types.h + - ral_types.h - ral.h - render.h ? */ @@ -49,15 +50,11 @@ typedef enum gpu_texture_format { typedef struct mesh mesh; typedef struct model model; typedef struct model pbr_material; -typedef struct model bp_material; // blinn-phong +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_COUNT } vertex_format; typedef union vertex { struct { @@ -73,7 +70,14 @@ typedef union vertex { vec2 tex_coords; } sprite; - // TODO: animated 3d + struct { + vec3 position; + vec4 colour; + vec2 tex_coords; + vec3 normal; + vec4i bone_ids; // Integer vector for bone IDs + vec4 bone_weights; // Weight of each bone's influence + } animated_3d; /** @brief vertex format for skeletal (animated) geometry in 3D */ } vertex; KITC_DECL_TYPED_ARRAY(vertex) @@ -90,42 +94,93 @@ typedef struct mesh { buffer_handle index_buffer; u32 index_count; bool has_indices; - geometry_data* vertices; // NULL means it has been freed + geometry_data* vertices; // NULL means it has been freed } mesh; +/* Hot reloading: +C side - reload_model(): + - load model from disk using existing loader + - remove from transform graph so it isnt tried to be drawn + - + +*/ + typedef struct model { str8 debug_name; mesh* meshes; u32 mesh_count; } model; +// ? 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 + /* render.h */ // frontend -- these can be called from say a loop in an example, or via FFI texture_handle texture_create(const char* debug_name, texture_desc description, const u8* data); void texture_data_upload(texture_handle texture); buffer_handle buffer_create(const char* debug_name, u64 size); +bool buffer_destroy(buffer_handle buffer); // models and meshes are implemented **in terms of the above** mesh mesh_create(geometry_data* geometry); -model_handle model_load(const char* filepath); +model_handle model_load(const char* debug_name, const char* filepath); /* ral.h */ + +enum pipeline_type { + GRAPHICS, + COMPUTE, +} pipeline_type; + // backend -- these are not seen by the higher-level code typedef struct gpu_swapchain gpu_swapchain; typedef struct gpu_device gpu_device; typedef struct gpu_pipeline gpu_pipeline; +typedef struct gpu_cmd_encoder gpu_cmd_encoder; +typedef struct gpu_cmd_buffer gpu_cmd_buffer; // Ready for submission -void gpu_texture_init(); -void gpu_texture_upload(); -void gpu_buffer_init(); +void gpu_cmd_encoder_begin(); +void gpu_cmd_encoder_begin_render(); +void gpu_cmd_encoder_begin_compute(); + +/* Actual commands that we can encode */ +void encode_buffer_copy(gpu_cmd_encoder* encoder, buffer_handle src, u64 src_offset, + buffer_handle dst, u64 dst_offset, u64 copy_size); +void encode_clear_buffer(gpu_cmd_encoder* encoder, buffer_handle buf); +// render pass +void encode_set_vertex_buffer(gpu_cmd_encoder* encoder, buffer_handle buf); +void encode_set_index_buffer(gpu_cmd_encoder* encoder, buffer_handle buf); +void encode_draw_indexed(gpu_cmd_encoder* encoder, u64 index_count, u64* indices); + +// FUTURE: compute passes + +/** @brief Finish recording and return a command buffer that can be submitted to a queue */ +gpu_cmd_buffer gpu_cmd_encoder_finish(gpu_cmd_encoder* encoder); + +void gpu_queue_submit(gpu_cmd_buffer* buffer); + +// Buffers +void gpu_buffer_create(u64 size); +void gpu_buffer_destroy(buffer_handle buffer); void gpu_buffer_upload(); -void gpu_buffer_bind(); +void gpu_buffer_bind(buffer_handle buffer); + +// Textures +void gpu_texture_create(); +void gpu_texture_destroy(); +void gpu_texture_upload(); + +// Samplers +void gpu_sampler_create(); // command buffer gubbins @@ -135,7 +190,8 @@ void gpu_buffer_bind(); 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); // tracks internally whether the model is loaded static void imm_draw_model(const char* model_filepath) { // check that model is loaded -- cgit v1.2.3-70-g09d2 From a56349f682862f065c5e5af6183643fcb1f19617 Mon Sep 17 00:00:00 2001 From: Omniscient <17525998+omnisci3nce@users.noreply.github.com> Date: Sun, 31 Mar 2024 15:35:04 +1100 Subject: redo cube primitive vertex and normals --- examples/input/ex_input.c | 18 ++-- src/maths/maths.h | 42 ++++++++- src/maths/primitives.h | 160 ++++++++++++++++++++++++--------- src/renderer/backends/backend_vulkan.c | 46 ++++++---- 4 files changed, 196 insertions(+), 70 deletions(-) diff --git a/examples/input/ex_input.c b/examples/input/ex_input.c index f102fad..3101968 100644 --- a/examples/input/ex_input.c +++ b/examples/input/ex_input.c @@ -23,20 +23,19 @@ void update_camera_rotation(input_state* input, game_state* game, camera* cam); int main() { core* core = core_bringup(); - vec3 cam_pos = vec3_create(-15, 20.0, 13); + vec3 cam_pos = vec3_create(5, 5, 5); game_state game = { .camera = camera_create(cam_pos, vec3_negate(cam_pos), VEC3_Y, deg_to_rad(45.0)), .camera_euler = vec3_create(90, 0, 0), .first_mouse_update = true, }; - // model_handle cube_handle = prim_cube_new(core); - printf("Starting look direction: "); print_vec3(game.camera.front); // Main loop - const f32 camera_speed = 0.4; + const f32 camera_lateral_speed = 0.2; + const f32 camera_zoom_speed = 0.15; while (!should_exit(core)) { input_update(&core->input); @@ -44,18 +43,18 @@ int main() { vec3 translation = VEC3_ZERO; if (key_is_pressed(KEYCODE_W) || key_is_pressed(KEYCODE_KEY_UP)) { printf("Move Forwards\n"); - translation = vec3_mult(game.camera.front, camera_speed); + translation = vec3_mult(game.camera.front, camera_zoom_speed); } else if (key_is_pressed(KEYCODE_S) || key_is_pressed(KEYCODE_KEY_DOWN)) { printf("Move Backwards\n"); - translation = vec3_mult(game.camera.front, -camera_speed); + translation = vec3_mult(game.camera.front, -camera_zoom_speed); } else if (key_is_pressed(KEYCODE_A) || key_is_pressed(KEYCODE_KEY_LEFT)) { printf("Move Left\n"); vec3 lateral = vec3_normalise(vec3_cross(game.camera.front, game.camera.up)); - translation = vec3_mult(lateral, -camera_speed); + translation = vec3_mult(lateral, -camera_lateral_speed); } else if (key_is_pressed(KEYCODE_D) || key_is_pressed(KEYCODE_KEY_RIGHT)) { printf("Move Right\n"); vec3 lateral = vec3_normalise(vec3_cross(game.camera.front, game.camera.up)); - translation = vec3_mult(lateral, camera_speed); + translation = vec3_mult(lateral, camera_lateral_speed); } game.camera.position = vec3_add(game.camera.position, translation); // update_camera_rotation(&core->input, &game, &game.camera); @@ -64,7 +63,6 @@ int main() { render_frame_begin(&core->renderer); - // model cube = core->models->data[cube_handle.raw]; mat4 model = mat4_translation(VEC3_ZERO); gfx_backend_draw_frame(&core->renderer, &game.camera, model); @@ -86,7 +84,7 @@ void update_camera_rotation(input_state* input, game_state* game, camera* cam) { game->first_mouse_update = false; } - float sensitivity = 0.1f; // change this value to your liking + float sensitivity = 0.2f; // change this value to your liking xoffset *= sensitivity; yoffset *= sensitivity; diff --git a/src/maths/maths.h b/src/maths/maths.h index 6fa2f9b..1432581 100644 --- a/src/maths/maths.h +++ b/src/maths/maths.h @@ -132,6 +132,27 @@ static inline mat4 mat4_mult(mat4 lhs, mat4 rhs) { return out_matrix; } +static mat4 mat4_transposed(mat4 matrix) { + mat4 out_matrix = mat4_ident(); + out_matrix.data[0] = matrix.data[0]; + out_matrix.data[1] = matrix.data[4]; + out_matrix.data[2] = matrix.data[8]; + out_matrix.data[3] = matrix.data[12]; + out_matrix.data[4] = matrix.data[1]; + out_matrix.data[5] = matrix.data[5]; + out_matrix.data[6] = matrix.data[9]; + out_matrix.data[7] = matrix.data[13]; + out_matrix.data[8] = matrix.data[2]; + out_matrix.data[9] = matrix.data[6]; + out_matrix.data[10] = matrix.data[10]; + out_matrix.data[11] = matrix.data[14]; + out_matrix.data[12] = matrix.data[3]; + out_matrix.data[13] = matrix.data[7]; + out_matrix.data[14] = matrix.data[11]; + out_matrix.data[15] = matrix.data[15]; + return out_matrix; +} + #if defined(CEL_REND_BACKEND_VULKAN) /** @brief Creates a perspective projection matrix compatible with Vulkan */ static inline mat4 mat4_perspective(f32 fov_radians, f32 aspect_ratio, f32 near_clip, @@ -143,12 +164,31 @@ static inline mat4 mat4_perspective(f32 fov_radians, f32 aspect_ratio, f32 near_ mat4 out_matrix = { .data = { 0 } }; out_matrix.data[0] = 1.0f / (aspect_ratio * half_tan_fov); - out_matrix.data[5] = -1.0f / half_tan_fov; // Flip Y-axis for Vulkan + out_matrix.data[5] = 1.0f / half_tan_fov; // Flip Y-axis for Vulkan out_matrix.data[10] = -((far_clip + near_clip) / (far_clip - near_clip)); out_matrix.data[11] = -1.0f; out_matrix.data[14] = -((2.0f * far_clip * near_clip) / (far_clip - near_clip)); + // float half_tan_fov = tanf(fov_radians * 0.5); + // float k = far_clip / (far_clip - near_clip); + + // out_matrix.data[0] = 1.0f / (aspect_ratio * half_tan_fov); + // out_matrix.data[5] = 1.0f / half_tan_fov; + // out_matrix.data[10] = k; + // out_matrix.data[11] = -1.0; + // out_matrix.data[14] = -1.0 * near_clip * k; + + // f32 half_tan_fov = tan(fov_radians * 0.5f); + // out_matrix.data[0] = 1.0f / (aspect_ratio * half_tan_fov); + // out_matrix.data[5] = 1.0f / half_tan_fov; + // out_matrix.data[10] = -((far_clip + near_clip) / (far_clip - near_clip)); + // out_matrix.data[11] = -1.0f; + // out_matrix.data[14] = + // -((2.0f * far_clip * near_clip) / (far_clip - near_clip)); + // return out_matrix; + return out_matrix; + // return mat4_transposed(out_matrix); } #else /** @brief Creates a perspective projection matrix */ diff --git a/src/maths/primitives.h b/src/maths/primitives.h index fd798c1..77dbbae 100644 --- a/src/maths/primitives.h +++ b/src/maths/primitives.h @@ -1,55 +1,135 @@ #pragma once #include +#include #include "core.h" +#include "maths.h" #include "render_types.h" -static float cube_vertices[] = { - // positions // normals // texture coords - -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.5f, -0.5f, -0.5f, 0.0f, - 0.0f, -1.0f, 1.0f, 0.0f, 0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f, - 0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f, -0.5f, 0.5f, -0.5f, 0.0f, - 0.0f, -1.0f, 0.0f, 1.0f, -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, - - -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.5f, -0.5f, 0.5f, 0.0f, - 0.0f, 1.0f, 1.0f, 0.0f, 0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, - 0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, -0.5f, 0.5f, 0.5f, 0.0f, - 0.0f, 1.0f, 0.0f, 1.0f, -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, - - -0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, -0.5f, 0.5f, -0.5f, -1.0f, - 0.0f, 0.0f, 1.0f, 1.0f, -0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, - -0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, -0.5f, -0.5f, 0.5f, -1.0f, - 0.0f, 0.0f, 0.0f, 0.0f, -0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, - - 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.5f, 0.5f, -0.5f, 1.0f, - 0.0f, 0.0f, 1.0f, 1.0f, 0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, - 0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.5f, -0.5f, 0.5f, 1.0f, - 0.0f, 0.0f, 0.0f, 0.0f, 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, - - -0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.5f, -0.5f, -0.5f, 0.0f, - -1.0f, 0.0f, 1.0f, 1.0f, 0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, - 0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, -0.5f, -0.5f, 0.5f, 0.0f, - -1.0f, 0.0f, 0.0f, 0.0f, -0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, - - -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.5f, 0.5f, -0.5f, 0.0f, - 1.0f, 0.0f, 1.0f, 1.0f, 0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, - 0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, -0.5f, 0.5f, 0.5f, 0.0f, - 1.0f, 0.0f, 0.0f, 0.0f, -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f -}; +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); - for (int i = 0; i < 36; i++) { - vertex vert = { .position = vec3_create(cube_vertices[(i * 8) + 0], cube_vertices[(i * 8) + 1], - cube_vertices[(i * 8) + 2]), - .normal = vec3_create(cube_vertices[(i * 8) + 3], cube_vertices[(i * 8) + 4], - cube_vertices[(i * 8) + 5]), - .uv = (vec2){ .x = cube_vertices[(i * 8) + 6], - .y = cube_vertices[(i * 8) + 7] } }; - vertex_darray_push(cube.vertices, vert); + // back faces + vertex_darray_push( + cube.vertices, + (vertex){ .position = BACK_BOT_LEFT, .normal = VEC3_NEG_Z, .uv = (vec2){ 0 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = BACK_TOP_LEFT, .normal = VEC3_NEG_Z, .uv = (vec2){ 0 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = BACK_TOP_LEFT, .normal = VEC3_NEG_Z, .uv = (vec2){ 0 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = BACK_TOP_RIGHT, .normal = VEC3_NEG_Z, .uv = (vec2){ 0 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = BACK_BOT_RIGHT, .normal = VEC3_NEG_Z, .uv = (vec2){ 0 } }); + vertex_darray_push( + cube.vertices, + (vertex){ .position = BACK_BOT_LEFT, .normal = VEC3_NEG_Z, .uv = (vec2){ 0 } }); + + // front faces + vertex_darray_push(cube.vertices, + (vertex){ .position = FRONT_BOT_LEFT, .normal = VEC3_Z, .uv = (vec2){ 0 } }); + vertex_darray_push(cube.vertices, + (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_Z, .uv = (vec2){ 0 } }); + vertex_darray_push(cube.vertices, + (vertex){ .position = FRONT_TOP_LEFT, .normal = VEC3_Z, .uv = (vec2){ 0 } }); + vertex_darray_push(cube.vertices, + (vertex){ .position = FRONT_BOT_LEFT, .normal = VEC3_Z, .uv = (vec2){ 0 } }); + vertex_darray_push(cube.vertices, + (vertex){ .position = FRONT_BOT_RIGHT, .normal = VEC3_Z, .uv = (vec2){ 0 } }); + vertex_darray_push(cube.vertices, + (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_Z, .uv = (vec2){ 0 } }); + + // top faces + vertex_darray_push(cube.vertices, + (vertex){ .position = BACK_TOP_LEFT, .normal = VEC3_Y, .uv = (vec2){ 0 } }); + vertex_darray_push(cube.vertices, + (vertex){ .position = FRONT_TOP_LEFT, .normal = VEC3_Y, .uv = (vec2){ 0 } }); + vertex_darray_push(cube.vertices, + (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_Y, .uv = (vec2){ 0 } }); + vertex_darray_push(cube.vertices, + (vertex){ .position = BACK_TOP_LEFT, .normal = VEC3_Y, .uv = (vec2){ 0 } }); + vertex_darray_push(cube.vertices, + (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_Y, .uv = (vec2){ 0 } }); + vertex_darray_push(cube.vertices, + (vertex){ .position = BACK_TOP_RIGHT, .normal = VEC3_Y, .uv = (vec2){ 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 } }); + vertex_darray_push(cube.vertices, + (vertex){ .position = BACK_BOT_RIGHT, .normal = VEC3_X, .uv = (vec2){ 0 } }); + vertex_darray_push(cube.vertices, + (vertex){ .position = BACK_TOP_RIGHT, .normal = VEC3_X, .uv = (vec2){ 0 } }); + vertex_darray_push(cube.vertices, + (vertex){ .position = BACK_BOT_RIGHT, .normal = VEC3_X, .uv = (vec2){ 0 } }); + vertex_darray_push(cube.vertices, + (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_X, .uv = (vec2){ 0 } }); + vertex_darray_push(cube.vertices, + (vertex){ .position = FRONT_BOT_RIGHT, .normal = VEC3_X, .uv = (vec2){ 0 } }); + + // 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; } diff --git a/src/renderer/backends/backend_vulkan.c b/src/renderer/backends/backend_vulkan.c index 1657594..97e0a44 100644 --- a/src/renderer/backends/backend_vulkan.c +++ b/src/renderer/backends/backend_vulkan.c @@ -654,10 +654,10 @@ void vulkan_object_shader_update_object(vulkan_context* context, vulkan_shader* 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); + vkCmdBindIndexBuffer(cmd_buffer, context->object_index_buffer.handle, 0, VK_INDEX_TYPE_UINT32); - // vkCmdDrawIndexed(cmd_buffer, 6, 1, 0, 0, 0); - vkCmdDraw(cmd_buffer, 36, 1, 0, 0); + vkCmdDrawIndexed(cmd_buffer, 36, 1, 0, 0, 0); + // vkCmdDraw(cmd_buffer, 36, 1, 0, 0); } bool select_physical_device(vulkan_context* ctx) { @@ -1351,11 +1351,9 @@ void upload_data_range(vulkan_context* context, VkCommandPool pool, VkFence fenc 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); - TRACE("HERE"); // load data into staging buffer printf("Size: %ld\n", size); vulkan_buffer_load_data(context, &staging, 0, size, 0, data); - TRACE("here"); // copy vulkan_buffer_copy_to(context, pool, fence, queue, staging.handle, 0, buffer->handle, offset, @@ -1587,18 +1585,19 @@ bool gfx_backend_init(renderer* ren) { mesh cube = prim_cube_mesh_create(); - const u32 vert_count = 36; - // vertex_pos verts[4] = { 0 }; + // const u32 vert_count = 36; - vertex_pos verts[36] = { 0 }; + vertex_pos* verts = malloc(sizeof(vertex_pos) * cube.vertices->len); f32 scale = 3.0; - for (size_t i = 0; i < 36; i++) { + for (size_t i = 0; i < cube.vertices->len; i++) { verts[i].pos = vec3_mult(cube.vertices->data[i].position, scale); verts[i].normal = cube.vertices->data[i].normal; } - // const f32 s = 10.0; + // 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; @@ -1612,15 +1611,16 @@ bool gfx_backend_init(renderer* ren) { // 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 }; + // 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_pos) * vert_count, verts); + &context.object_vertex_buffer, 0, sizeof(vertex_pos) * 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) * index_count, indices); - // TRACE("Uploaded index 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"); // --- End test code INFO("Vulkan renderer initialisation succeeded"); @@ -1661,9 +1661,9 @@ void backend_begin_frame(renderer* ren, f32 delta_time) { VkViewport viewport; viewport.x = 0.0; - viewport.y = 0.0; + viewport.y = (f32)context.framebuffer_height; viewport.width = (f32)context.framebuffer_width; - viewport.height = (f32)context.framebuffer_height; + viewport.height = -(f32)context.framebuffer_height; viewport.minDepth = 0.0; viewport.maxDepth = 1.0; @@ -1741,7 +1741,15 @@ void gfx_backend_draw_frame(renderer* ren, camera* cam, mat4 model) { camera_view_projection(cam, SCR_HEIGHT, SCR_WIDTH, &view, &proj); - gfx_backend_update_global_state(proj, view, VEC3_ZERO, vec4(1.0, 1.0, 1.0, 1.0), 0); + // proj = mat4_perspective(deg_to_rad(45.0), (f32)SCR_WIDTH / SCR_HEIGHT, 0.1, 100.0); + + // proj.data[5] *= -1.0; + + // vec3 pos = vec3_create(2, 2, 2); + // vec3 up = VEC3_Y; + // view = mat4_look_at(pos, VEC3_ZERO, up); + + 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); -- cgit v1.2.3-70-g09d2 From 1b4c27d514423c9e27a93742b8c8e9eb9f588e27 Mon Sep 17 00:00:00 2001 From: Omniscient <17525998+omnisci3nce@users.noreply.github.com> Date: Sun, 31 Mar 2024 15:43:08 +1100 Subject: fix discrepancy between opengl and vulkan --- assets/shaders/blinn_phong.vert | 11 ++++------- src/maths/maths.h | 24 +----------------------- src/renderer/backends/backend_vulkan.c | 17 ++++------------- 3 files changed, 9 insertions(+), 43 deletions(-) diff --git a/assets/shaders/blinn_phong.vert b/assets/shaders/blinn_phong.vert index 041c3d1..6028178 100644 --- a/assets/shaders/blinn_phong.vert +++ b/assets/shaders/blinn_phong.vert @@ -4,13 +4,10 @@ layout (location = 0) in vec3 inPos; layout (location = 1) in vec3 inNormal; layout (location = 2) in vec2 inTexCoords; -// Uniform block -layout (std140, binding = 0) uniform MatrixBlock { - mat4 model; - mat4 view; - mat4 projection; - mat4 lightSpaceMatrix; -}; +uniform mat4 model; +uniform mat4 view; +uniform mat4 projection; +uniform mat4 lightSpaceMatrix; // Output out VS_OUT { diff --git a/src/maths/maths.h b/src/maths/maths.h index 1432581..c9bcaad 100644 --- a/src/maths/maths.h +++ b/src/maths/maths.h @@ -157,38 +157,16 @@ static mat4 mat4_transposed(mat4 matrix) { /** @brief Creates a perspective projection matrix compatible with Vulkan */ static inline mat4 mat4_perspective(f32 fov_radians, f32 aspect_ratio, f32 near_clip, f32 far_clip) { - // near_clip *= -1.0; - // far_clip *= -1.0; - f32 half_tan_fov = tanf(fov_radians * 0.5f); mat4 out_matrix = { .data = { 0 } }; out_matrix.data[0] = 1.0f / (aspect_ratio * half_tan_fov); - out_matrix.data[5] = 1.0f / half_tan_fov; // Flip Y-axis for Vulkan + out_matrix.data[5] = -1.0f / half_tan_fov; // Flip Y-axis for Vulkan out_matrix.data[10] = -((far_clip + near_clip) / (far_clip - near_clip)); out_matrix.data[11] = -1.0f; out_matrix.data[14] = -((2.0f * far_clip * near_clip) / (far_clip - near_clip)); - // float half_tan_fov = tanf(fov_radians * 0.5); - // float k = far_clip / (far_clip - near_clip); - - // out_matrix.data[0] = 1.0f / (aspect_ratio * half_tan_fov); - // out_matrix.data[5] = 1.0f / half_tan_fov; - // out_matrix.data[10] = k; - // out_matrix.data[11] = -1.0; - // out_matrix.data[14] = -1.0 * near_clip * k; - - // f32 half_tan_fov = tan(fov_radians * 0.5f); - // out_matrix.data[0] = 1.0f / (aspect_ratio * half_tan_fov); - // out_matrix.data[5] = 1.0f / half_tan_fov; - // out_matrix.data[10] = -((far_clip + near_clip) / (far_clip - near_clip)); - // out_matrix.data[11] = -1.0f; - // out_matrix.data[14] = - // -((2.0f * far_clip * near_clip) / (far_clip - near_clip)); - // return out_matrix; - return out_matrix; - // return mat4_transposed(out_matrix); } #else /** @brief Creates a perspective projection matrix */ diff --git a/src/renderer/backends/backend_vulkan.c b/src/renderer/backends/backend_vulkan.c index 97e0a44..d149e15 100644 --- a/src/renderer/backends/backend_vulkan.c +++ b/src/renderer/backends/backend_vulkan.c @@ -1,7 +1,8 @@ #include "camera.h" #include "primitives.h" #define CDEBUG -#define CEL_PLATFORM_LINUX +// #define CEL_PLATFORM_LINUX +#if CEL_REND_BACKEND_VULKAN // ^ Temporary #include @@ -30,8 +31,6 @@ #define SCR_WIDTH 1000 #define SCR_HEIGHT 1000 -#if CEL_REND_BACKEND_VULKAN - #include #include @@ -1661,9 +1660,9 @@ void backend_begin_frame(renderer* ren, f32 delta_time) { VkViewport viewport; viewport.x = 0.0; - viewport.y = (f32)context.framebuffer_height; + viewport.y = 0; viewport.width = (f32)context.framebuffer_width; - viewport.height = -(f32)context.framebuffer_height; + viewport.height = (f32)context.framebuffer_height; viewport.minDepth = 0.0; viewport.maxDepth = 1.0; @@ -1741,14 +1740,6 @@ void gfx_backend_draw_frame(renderer* ren, camera* cam, mat4 model) { camera_view_projection(cam, SCR_HEIGHT, SCR_WIDTH, &view, &proj); - // proj = mat4_perspective(deg_to_rad(45.0), (f32)SCR_WIDTH / SCR_HEIGHT, 0.1, 100.0); - - // proj.data[5] *= -1.0; - - // vec3 pos = vec3_create(2, 2, 2); - // vec3 up = VEC3_Y; - // view = mat4_look_at(pos, VEC3_ZERO, up); - 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); -- cgit v1.2.3-70-g09d2 From b771fc06a4339f466c0864ad896d5a96aee7e35d Mon Sep 17 00:00:00 2001 From: Omniscient <17525998+omnisci3nce@users.noreply.github.com> Date: Sun, 31 Mar 2024 22:08:05 +1100 Subject: adding image creation for textures --- src/maths/primitives.h | 24 +++--- src/renderer/backends/backend_opengl.c | 23 ++++++ src/renderer/backends/backend_vulkan.c | 134 +++++++++++++++++++++++++++++---- src/renderer/render.c | 23 ------ src/renderer/render.h | 1 - src/renderer/render_backend.h | 1 + src/renderer/render_types.h | 3 +- 7 files changed, 159 insertions(+), 50 deletions(-) diff --git a/src/maths/primitives.h b/src/maths/primitives.h index 77dbbae..4fb6b4d 100644 --- a/src/maths/primitives.h +++ b/src/maths/primitives.h @@ -22,36 +22,36 @@ static mesh prim_cube_mesh_create() { // back faces vertex_darray_push( cube.vertices, - (vertex){ .position = BACK_BOT_LEFT, .normal = VEC3_NEG_Z, .uv = (vec2){ 0 } }); + (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 } }); + (vertex){ .position = BACK_TOP_LEFT, .normal = VEC3_NEG_Z, .uv = (vec2){ 0, 0 } }); vertex_darray_push( cube.vertices, - (vertex){ .position = BACK_TOP_LEFT, .normal = VEC3_NEG_Z, .uv = (vec2){ 0 } }); + (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){ 0 } }); + (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){ 0 } }); + (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 } }); + (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 } }); + (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){ 0 } }); + (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 } }); + (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 } }); + (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){ 0 } }); + (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){ 0 } }); + (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_Z, .uv = (vec2){ 1, 0 } }); // top faces vertex_darray_push(cube.vertices, diff --git a/src/renderer/backends/backend_opengl.c b/src/renderer/backends/backend_opengl.c index ea6cb00..a9f7482 100644 --- a/src/renderer/backends/backend_opengl.c +++ b/src/renderer/backends/backend_opengl.c @@ -60,6 +60,29 @@ void clear_screen(vec3 colour) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } +void texture_data_upload(texture* tex) { + printf("Texture name %s\n", tex->name); + TRACE("Upload texture data"); + u32 texture_id; + glGenTextures(1, &texture_id); + glBindTexture(GL_TEXTURE_2D, texture_id); + tex->texture_id = texture_id; + + // set the texture wrapping parameters + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, + GL_REPEAT); // set texture wrapping to GL_REPEAT (default wrapping method) + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + // set texture filtering parameters + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tex->width, tex->height, 0, tex->channel_type, + GL_UNSIGNED_BYTE, tex->image_data); + glGenerateMipmap(GL_TEXTURE_2D); + DEBUG("Freeing texture image data after uploading to GPU"); + // stbi_image_free(tex->image_data); // data is on gpu now so we dont need it around +} + void bind_texture(shader s, texture *tex, u32 slot) { // printf("bind texture slot %d with texture id %d \n", slot, tex->texture_id); glActiveTexture(GL_TEXTURE0 + slot); diff --git a/src/renderer/backends/backend_vulkan.c b/src/renderer/backends/backend_vulkan.c index d149e15..9d0ef51 100644 --- a/src/renderer/backends/backend_vulkan.c +++ b/src/renderer/backends/backend_vulkan.c @@ -6,7 +6,6 @@ // ^ Temporary #include -#include #include #include #include @@ -64,6 +63,11 @@ typedef struct vulkan_image { u32 height; } vulkan_image; +typedef struct vulkan_texture_data { + vulkan_image image; + VkSampler sampler; +} vulkan_texture_data; + typedef enum vulkan_renderpass_state { READY, RECORDING, @@ -863,6 +867,67 @@ 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}; + 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_TOP_OF_PIPE_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.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + region.imageSubresource.mipLevel = 0; + region.imageSubresource.baseArrayLayer = 0; + region.imageSubresource.layerCount = 1; + 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, @@ -1584,8 +1649,6 @@ bool gfx_backend_init(renderer* ren) { mesh cube = prim_cube_mesh_create(); - // const u32 vert_count = 36; - vertex_pos* verts = malloc(sizeof(vertex_pos) * cube.vertices->len); f32 scale = 3.0; @@ -1620,6 +1683,8 @@ bool gfx_backend_init(renderer* ren) { 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 INFO("Vulkan renderer initialisation succeeded"); @@ -1679,21 +1744,64 @@ void backend_begin_frame(renderer* ren, f32 delta_time) { vulkan_renderpass_begin(command_buffer, &context.main_renderpass, context.swapchain.framebuffers->data[context.image_index].handle); +} - // TODO: temp test code - // vulkan_object_shader_use(&context, &context.object_shader); - - // VkDeviceSize offsets[1] = { 0 }; - // vkCmdBindVertexBuffers(command_buffer->handle, 0, 1, &context.object_vertex_buffer.handle, - // (VkDeviceSize*)offsets); +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; + VkDeviceSize image_size = tex->width * tex->height * tex->channel_count; - // vkCmdBindIndexBuffer(command_buffer->handle, context.object_index_buffer.handle, 0, - // VK_INDEX_TYPE_UINT32); + VkFormat image_format = VK_FORMAT_R8G8B8A8_SNORM; - // vkCmdDrawIndexed(command_buffer->handle, 6, 1, 0, 0, 0); - // --- End temp test code + 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); + 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_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 + void backend_end_frame(renderer* ren, f32 delta_time) { vulkan_command_buffer* command_buffer = &context.gfx_command_buffers->data[context.image_index]; diff --git a/src/renderer/render.c b/src/renderer/render.c index 54b63b6..9dc47c2 100644 --- a/src/renderer/render.c +++ b/src/renderer/render.c @@ -247,29 +247,6 @@ texture texture_data_load(const char* path, bool invert_y) { .image_data = data }; } -void texture_data_upload(texture* tex) { - printf("Texture name %s\n", tex->name); - TRACE("Upload texture data"); - u32 texture_id; - glGenTextures(1, &texture_id); - glBindTexture(GL_TEXTURE_2D, texture_id); - tex->texture_id = texture_id; - - // set the texture wrapping parameters - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, - GL_REPEAT); // set texture wrapping to GL_REPEAT (default wrapping method) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - // set texture filtering parameters - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tex->width, tex->height, 0, tex->channel_type, - GL_UNSIGNED_BYTE, tex->image_data); - glGenerateMipmap(GL_TEXTURE_2D); - DEBUG("Freeing texture image data after uploading to GPU"); - // stbi_image_free(tex->image_data); // data is on gpu now so we dont need it around -} - void dir_light_upload_uniforms(shader shader, directional_light* light) { uniform_vec3f(shader.program_id, "dirLight.direction", &light->direction); uniform_vec3f(shader.program_id, "dirLight.ambient", &light->ambient); diff --git a/src/renderer/render.h b/src/renderer/render.h index 6cd9701..b6dad00 100644 --- a/src/renderer/render.h +++ b/src/renderer/render.h @@ -37,4 +37,3 @@ void draw_mesh(renderer* ren, mesh* mesh, transform tf, material* mat, mat4* vie // --- texture texture_data_load(const char* path, bool invert_y); // #frontend -void texture_data_upload(texture* tex); // #backend diff --git a/src/renderer/render_backend.h b/src/renderer/render_backend.h index ea84b27..af62f9f 100644 --- a/src/renderer/render_backend.h +++ b/src/renderer/render_backend.h @@ -19,6 +19,7 @@ void gfx_backend_update_global_state(mat4 projection, mat4 view, vec3 view_pos, void clear_screen(vec3 colour); +void texture_data_upload(texture* tex); 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); diff --git a/src/renderer/render_types.h b/src/renderer/render_types.h index 2cc321c..80e1372 100644 --- a/src/renderer/render_types.h +++ b/src/renderer/render_types.h @@ -52,7 +52,8 @@ typedef struct renderer { typedef struct texture { u32 texture_id; char name[MAX_TEXTURE_NAME_LEN]; - void *image_data; + void* image_data; + void* backend_data; u32 width; u32 height; u8 channel_count; -- cgit v1.2.3-70-g09d2 From fb3e055ff500e530e9ec46317441688bf4d07e13 Mon Sep 17 00:00:00 2001 From: Omniscient <17525998+omnisci3nce@users.noreply.github.com> Date: Mon, 1 Apr 2024 01:57:11 +1100 Subject: image / textures ! --- assets/shaders/object.frag | 14 ++- assets/shaders/object.vert | 11 +- examples/input/ex_input.c | 6 +- src/colours.h | 48 +++++++++ src/maths/primitives.h | 24 ++--- src/renderer/backends/backend_opengl.c | 2 +- src/renderer/backends/backend_vulkan.c | 191 +++++++++++++++++++++++---------- src/renderer/render.c | 2 +- src/renderer/render_backend.h | 2 +- 9 files changed, 219 insertions(+), 81 deletions(-) diff --git a/assets/shaders/object.frag b/assets/shaders/object.frag index 11b33e1..8466c1d 100644 --- a/assets/shaders/object.frag +++ b/assets/shaders/object.frag @@ -1,9 +1,15 @@ #version 450 #extension GL_ARB_separate_shader_objects : enable -layout(location = 0) in vec3 in_normal; -layout(location = 1) in vec3 in_position; +layout(location = 0) in vec3 in_position; +layout(location = 1) in vec3 in_normal; +layout(location = 2) in vec2 in_tex_coord; -layout(location = 0) out vec4 out_colour; +layout(binding = 1) uniform sampler2D texSampler; -void main() { out_colour = vec4(in_normal, 1.0); } \ No newline at end of file +layout(location = 0) out vec4 out_color; + +void main() { + // out_color = vec4(1.0); + out_color = texture(texSampler, in_tex_coord); +} \ No newline at end of file diff --git a/assets/shaders/object.vert b/assets/shaders/object.vert index a7237bb..23c0ffb 100644 --- a/assets/shaders/object.vert +++ b/assets/shaders/object.vert @@ -3,9 +3,11 @@ layout(location = 0) in vec3 in_position; layout(location = 1) in vec3 in_normal; +layout(location = 2) in vec2 in_tex_coord; -layout(location = 0) out vec3 out_normal; -layout(location = 1) out vec3 out_position; +layout(location = 0) out vec3 out_position; +layout(location = 1) out vec3 out_normal; +layout(location = 2) out vec2 out_tex_coord; layout(set = 0, binding = 0) uniform global_object_uniform { mat4 projection; @@ -19,8 +21,9 @@ layout(push_constant) uniform push_constants { u_push_constants; void main() { - out_position = in_position; gl_Position = global_ubo.projection * global_ubo.view * u_push_constants.model * vec4(in_position.x, in_position.y, in_position.z, 1.0); - out_normal = in_normal; // forward normal vectors + out_position = in_position; + out_normal = in_normal; + out_tex_coord = in_tex_coord; } \ No newline at end of file diff --git a/examples/input/ex_input.c b/examples/input/ex_input.c index 3101968..576b364 100644 --- a/examples/input/ex_input.c +++ b/examples/input/ex_input.c @@ -30,6 +30,10 @@ int main() { .first_mouse_update = true, }; + // load a texture + texture tex = texture_data_load("assets/models/obj/cube/container.jpg", false); + texture_data_upload(&tex); + printf("Starting look direction: "); print_vec3(game.camera.front); @@ -65,7 +69,7 @@ int main() { mat4 model = mat4_translation(VEC3_ZERO); - gfx_backend_draw_frame(&core->renderer, &game.camera, model); + gfx_backend_draw_frame(&core->renderer, &game.camera, model, &tex); render_frame_end(&core->renderer); } diff --git a/src/colours.h b/src/colours.h index fa5f54b..a981c6c 100644 --- a/src/colours.h +++ b/src/colours.h @@ -38,3 +38,51 @@ typedef struct rgba { #define CYAN_800 ((rgba){ 0.082, 0.369, 0.459, 1.0 }) #define CYAN_900 ((rgba){ 0.086, 0.306, 0.388, 1.0 }) #define CYAN_950 ((rgba){ 0.033, 0.200, 0.263, 1.0 }) + +#define GRAY_50 ((rgba){ 0.976, 0.980, 0.984, 1.0 }) +#define GRAY_100 ((rgba){ 0.953, 0.957, 0.965, 1.0 }) +#define GRAY_200 ((rgba){ 0.898, 0.906, 0.922, 1.0 }) +#define GRAY_300 ((rgba){ 0.820, 0.835, 0.859, 1.0 }) +#define GRAY_400 ((rgba){ 0.612, 0.639, 0.686, 1.0 }) +#define GRAY_500 ((rgba){ 0.420, 0.447, 0.502, 1.0 }) +#define GRAY_600 ((rgba){ 0.294, 0.333, 0.388, 1.0 }) +#define GRAY_700 ((rgba){ 0.216, 0.255, 0.318, 1.0 }) +#define GRAY_800 ((rgba){ 0.122, 0.161, 0.216, 1.0 }) +#define GRAY_900 ((rgba){ 0.067, 0.094, 0.153, 1.0 }) +#define GRAY_950 ((rgba){ 0.012, 0.027, 0.071, 1.0 }) + +#define RED_50 ((rgba){ 0.996, 0.949, 0.949, 1.0 }) +#define RED_100 ((rgba){ 0.996, 0.886, 0.886, 1.0 }) +#define RED_200 ((rgba){ 0.996, 0.792, 0.792, 1.0 }) +#define RED_300 ((rgba){ 0.988, 0.647, 0.647, 1.0 }) +#define RED_400 ((rgba){ 0.973, 0.443, 0.443, 1.0 }) +#define RED_500 ((rgba){ 0.937, 0.267, 0.267, 1.0 }) +#define RED_600 ((rgba){ 0.863, 0.149, 0.149, 1.0 }) +#define RED_700 ((rgba){ 0.725, 0.110, 0.110, 1.0 }) +#define RED_800 ((rgba){ 0.600, 0.106, 0.106, 1.0 }) +#define RED_900 ((rgba){ 0.498, 0.114, 0.114, 1.0 }) +#define RED_950 ((rgba){ 0.271, 0.039, 0.039, 1.0 }) + +#define ORANGE_50 ((rgba){ 1.000, 0.969, 0.929, 1.0 }) +#define ORANGE_100 ((rgba){ 1.000, 0.929, 0.835, 1.0 }) +#define ORANGE_200 ((rgba){ 0.996, 0.843, 0.667, 1.0 }) +#define ORANGE_300 ((rgba){ 0.992, 0.729, 0.455, 1.0 }) +#define ORANGE_400 ((rgba){ 0.984, 0.573, 0.235, 1.0 }) +#define ORANGE_500 ((rgba){ 0.976, 0.451, 0.086, 1.0 }) +#define ORANGE_600 ((rgba){ 0.918, 0.345, 0.047, 1.0 }) +#define ORANGE_700 ((rgba){ 0.761, 0.255, 0.047, 1.0 }) +#define ORANGE_800 ((rgba){ 0.604, 0.204, 0.071, 1.0 }) +#define ORANGE_900 ((rgba){ 0.486, 0.176, 0.071, 1.0 }) +#define ORANGE_950 ((rgba){ 0.263, 0.078, 0.027, 1.0 }) + +#define AMBER_50 ((rgba){ 1.000, 0.984, 0.922, 1.0 }) +#define AMBER_100 ((rgba){ 0.996, 0.953, 0.780, 1.0 }) +#define AMBER_200 ((rgba){ 0.992, 0.902, 0.541, 1.0 }) +#define AMBER_300 ((rgba){ 0.988, 0.827, 0.302, 1.0 }) +#define AMBER_400 ((rgba){ 0.984, 0.749, 0.141, 1.0 }) +#define AMBER_500 ((rgba){ 0.961, 0.620, 0.043, 1.0 }) +#define AMBER_600 ((rgba){ 0.851, 0.467, 0.024, 1.0 }) +#define AMBER_700 ((rgba){ 0.706, 0.325, 0.035, 1.0 }) +#define AMBER_800 ((rgba){ 0.573, 0.251, 0.055, 1.0 }) +#define AMBER_900 ((rgba){ 0.471, 0.208, 0.059, 1.0 }) +#define AMBER_950 ((rgba){ 0.271, 0.102, 0.012, 1.0 }) diff --git a/src/maths/primitives.h b/src/maths/primitives.h index 4fb6b4d..b7fefa0 100644 --- a/src/maths/primitives.h +++ b/src/maths/primitives.h @@ -55,17 +55,17 @@ static mesh prim_cube_mesh_create() { // top faces vertex_darray_push(cube.vertices, - (vertex){ .position = BACK_TOP_LEFT, .normal = VEC3_Y, .uv = (vec2){ 0 } }); + (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 } }); + (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){ 0 } }); + (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 } }); + (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){ 0 } }); + (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){ 0 } }); + (vertex){ .position = BACK_TOP_RIGHT, .normal = VEC3_Y, .uv = (vec2){ 1, 0 } }); // bottom faces vertex_darray_push( @@ -89,17 +89,17 @@ static mesh prim_cube_mesh_create() { // right faces vertex_darray_push(cube.vertices, - (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_X, .uv = (vec2){ 0 } }); + (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){ 0 } }); + (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){ 0 } }); + (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){ 0 } }); + (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 } }); + (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 } }); + (vertex){ .position = FRONT_BOT_RIGHT, .normal = VEC3_X, .uv = (vec2){ 0, 1 } }); // left faces vertex_darray_push( diff --git a/src/renderer/backends/backend_opengl.c b/src/renderer/backends/backend_opengl.c index a9f7482..e3a4fb6 100644 --- a/src/renderer/backends/backend_opengl.c +++ b/src/renderer/backends/backend_opengl.c @@ -60,7 +60,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..e0b0e4e 100644 --- a/src/renderer/backends/backend_vulkan.c +++ b/src/renderer/backends/backend_vulkan.c @@ -145,6 +145,22 @@ typedef struct global_object_uniform { 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; @@ -171,6 +187,8 @@ typedef struct vulkan_shader { // 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 { @@ -324,7 +342,7 @@ bool vulkan_graphics_pipeline_create(vulkan_context* context, vulkan_renderpass* // Vertex input VkVertexInputBindingDescription binding_desc; binding_desc.binding = 0; - binding_desc.stride = sizeof(vertex_pos); + binding_desc.stride = sizeof(vertex); binding_desc.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; VkPipelineVertexInputStateCreateInfo vertex_input_info = { @@ -436,6 +454,8 @@ bool vulkan_buffer_create(vulkan_context* context, u64 size, VkBufferUsageFlagBi vulkan_buffer_bind(context, out_buffer, 0); } + DEBUG("Created buffer."); + return true; } @@ -512,11 +532,21 @@ bool vulkan_object_shader_create(vulkan_context* context, vulkan_shader* out_sha 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 }; - global_layout_info.bindingCount = 1; - global_layout_info.pBindings = &global_ubo_layout_binding; + + 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)); @@ -525,9 +555,15 @@ bool vulkan_object_shader_create(vulkan_context* context, vulkan_shader* out_sha 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 = 1; - pool_info.pPoolSizes = &global_pool_size; + pool_info.poolSizeCount = 2; + pool_info.pPoolSizes = pool_sizes; pool_info.maxSets = 3; VK_CHECK(vkCreateDescriptorPool(context->device.logical_device, &pool_info, context->allocator, @@ -549,12 +585,13 @@ bool vulkan_object_shader_create(vulkan_context* context, vulkan_shader* out_sha // Attributes u32 offset = 0; - const i32 attribute_count = 2; - VkVertexInputAttributeDescription attribute_descs[2]; + const i32 attribute_count = 3; + VkVertexInputAttributeDescription attribute_descs[3]; // Position - VkFormat formats[2] = { VK_FORMAT_R32G32B32_SFLOAT, VK_FORMAT_R32G32B32_SFLOAT }; + VkFormat formats[3] = { VK_FORMAT_R32G32B32_SFLOAT, VK_FORMAT_R32G32B32_SFLOAT, + VK_FORMAT_R32G32_SFLOAT }; - u64 sizes[2] = { sizeof(vec3), sizeof(vec3) }; + u64 sizes[3] = { sizeof(vec3), sizeof(vec3), sizeof(vec2) }; for (u32 i = 0; i < attribute_count; i++) { attribute_descs[i].binding = 0; @@ -629,15 +666,30 @@ void vulkan_object_shader_update_global_state(vulkan_context* context, vulkan_sh buffer_info.offset = offset; buffer_info.range = range; - VkWriteDescriptorSet descriptor_write = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET }; - descriptor_write.dstSet = shader->descriptor_sets[image_index]; - descriptor_write.dstBinding = 0; - descriptor_write.dstArrayElement = 0; - descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - descriptor_write.descriptorCount = 1; - descriptor_write.pBufferInfo = &buffer_info; + 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; - vkUpdateDescriptorSets(context->device.logical_device, 1, &descriptor_write, 0, 0); + 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); @@ -867,15 +919,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 +939,16 @@ 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) { + 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; @@ -907,25 +958,30 @@ 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.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); + 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, @@ -942,7 +998,7 @@ void vulkan_image_create(vulkan_context* context, VkImageType image_type, u32 wi image_create_info.extent.width = width; image_create_info.extent.height = height; image_create_info.extent.depth = 1; - image_create_info.mipLevels = 4; + image_create_info.mipLevels = 1; image_create_info.arrayLayers = 1; image_create_info.format = format; image_create_info.tiling = tiling; @@ -951,8 +1007,8 @@ void vulkan_image_create(vulkan_context* context, VkImageType image_type, u32 wi image_create_info.samples = VK_SAMPLE_COUNT_1_BIT; image_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - vkCreateImage(context->device.logical_device, &image_create_info, context->allocator, - &out_image->handle); + 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); @@ -1649,12 +1705,13 @@ bool gfx_backend_init(renderer* ren) { mesh cube = prim_cube_mesh_create(); - vertex_pos* verts = malloc(sizeof(vertex_pos) * cube.vertices->len); + vertex* verts = malloc(sizeof(vertex) * cube.vertices->len); f32 scale = 3.0; for (size_t i = 0; i < cube.vertices->len; i++) { - verts[i].pos = vec3_mult(cube.vertices->data[i].position, scale); + 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; @@ -1677,14 +1734,16 @@ bool gfx_backend_init(renderer* ren) { // 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_pos) * cube.vertices->len, - verts); + &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"); @@ -1750,32 +1809,46 @@ 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; - VkDeviceSize image_size = tex->width * tex->height * tex->channel_count; + 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); - VkFormat image_format = VK_FORMAT_R8G8B8A8_SNORM; + 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; + 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_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 +1865,14 @@ 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; } - + + tex->image_data = (void*)data; } // TODO: destroy texture @@ -1840,7 +1915,7 @@ void backend_end_frame(renderer* ren, f32 delta_time) { context.queue_complete_semaphores[context.current_frame], context.image_index); } -void gfx_backend_draw_frame(renderer* ren, camera* cam, mat4 model) { +void gfx_backend_draw_frame(renderer* ren, camera* cam, mat4 model, texture* tex) { backend_begin_frame(ren, 16.0); mat4 proj; @@ -1848,7 +1923,9 @@ void gfx_backend_draw_frame(renderer* ren, camera* cam, mat4 model) { 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); diff --git a/src/renderer/render.c b/src/renderer/render.c index 9dc47c2..ebade4f 100644 --- a/src/renderer/render.c +++ b/src/renderer/render.c @@ -224,7 +224,7 @@ texture texture_data_load(const char* path, bool invert_y) { stbi_set_flip_vertically_on_load(invert_y); #pragma GCC diagnostic ignored "-Wpointer-sign" - char* data = stbi_load(path, &width, &height, &num_channels, 0); + char* data = stbi_load(path, &width, &height, &num_channels, STBI_rgb_alpha); if (data) { DEBUG("loaded texture: %s", path); } else { diff --git a/src/renderer/render_backend.h b/src/renderer/render_backend.h index af62f9f..da30bcc 100644 --- a/src/renderer/render_backend.h +++ b/src/renderer/render_backend.h @@ -13,7 +13,7 @@ bool gfx_backend_init(renderer* ren); void gfx_backend_shutdown(renderer* ren); -void gfx_backend_draw_frame(renderer* ren, camera* camera, mat4 model); +void gfx_backend_draw_frame(renderer* ren, camera* camera, mat4 model, texture* tex); void gfx_backend_update_global_state(mat4 projection, mat4 view, vec3 view_pos, vec4 ambient_colour, i32 mode); -- cgit v1.2.3-70-g09d2 From 6a95b047998c0e0dcfdf60d17cf2cd0bd0bfee12 Mon Sep 17 00:00:00 2001 From: omnisci3nce <17525998+omnisci3nce@users.noreply.github.com> Date: Wed, 3 Apr 2024 19:54:57 +1100 Subject: make set explicit --- assets/shaders/object.frag | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/shaders/object.frag b/assets/shaders/object.frag index 8466c1d..fa50fcf 100644 --- a/assets/shaders/object.frag +++ b/assets/shaders/object.frag @@ -5,7 +5,7 @@ layout(location = 0) in vec3 in_position; layout(location = 1) in vec3 in_normal; layout(location = 2) in vec2 in_tex_coord; -layout(binding = 1) uniform sampler2D texSampler; +layout(set = 0, binding = 1) uniform sampler2D texSampler; layout(location = 0) out vec4 out_color; -- cgit v1.2.3-70-g09d2