summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoromnisci3nce <omniscient.oce@gmail.com>2024-04-28 09:14:22 +1000
committeromnisci3nce <omniscient.oce@gmail.com>2024-04-28 09:14:22 +1000
commit411520b240446f878a27c5d89812000774cc3c15 (patch)
tree989f442fdffcc85e45f665f8f22102fe6f6bae19
parentefea29ed9059303a5bb609ba0ce79c20ba894a23 (diff)
getting vulkan working on windows
-rw-r--r--examples/main_loop/ex_main_loop.c2
-rw-r--r--src/defines.h3
-rw-r--r--src/maths/maths.h1
-rw-r--r--src/maths/primitives.c261
-rw-r--r--src/renderer/archive/old_backend_vulkan.c1990
-rw-r--r--src/renderer/backends/backend_dx11.h4
-rw-r--r--src/renderer/backends/backend_vulkan.c1990
-rw-r--r--src/renderer/backends/backend_vulkan.h (renamed from src/renderer/cleanroom/backend_vulkan.h)3
-rw-r--r--src/renderer/cleanroom/backend_vulkan.c65
-rw-r--r--src/renderer/cleanroom/types.h60
-rw-r--r--src/renderer/immediate.c (renamed from src/renderer/cleanroom/immediate.c)2
-rw-r--r--src/renderer/immediate.h (renamed from src/renderer/cleanroom/immediate.h)0
-rw-r--r--src/renderer/ral.h10
-rw-r--r--src/renderer/ral_types.h46
-rw-r--r--src/renderer/render.c4
-rw-r--r--src/renderer/render.h4
-rw-r--r--src/renderer/render_types.h2
-rw-r--r--src/systems/screenspace.h2
-rw-r--r--xmake.lua14
19 files changed, 2246 insertions, 2217 deletions
diff --git a/examples/main_loop/ex_main_loop.c b/examples/main_loop/ex_main_loop.c
index 4e1f6a9..4e31313 100644
--- a/examples/main_loop/ex_main_loop.c
+++ b/examples/main_loop/ex_main_loop.c
@@ -26,6 +26,8 @@ int main() {
// insert work here
render_frame_end(&core->renderer);
+ glfwSwapBuffers(core->renderer.window);
+ glfwPollEvents();
}
return 0;
diff --git a/src/defines.h b/src/defines.h
index 54f2dd5..ec526e0 100644
--- a/src/defines.h
+++ b/src/defines.h
@@ -71,7 +71,8 @@ Renderer backend defines:
#endif
#if defined(CEL_PLATFORM_WINDOWS)
-#define CEL_REND_BACKEND_DX11 1
+// #define CEL_REND_BACKEND_DX11 1
+#define CEL_REND_BACKEND_VULKAN 1
#endif
#if defined(CEL_PLATFORM_MAC)
diff --git a/src/maths/maths.h b/src/maths/maths.h
index ad33981..88a5215 100644
--- a/src/maths/maths.h
+++ b/src/maths/maths.h
@@ -53,6 +53,7 @@ static inline void print_vec3(vec3 v) { printf("{ x: %f, y: %f, z: %f )\n", v.x,
// TODO: Dimension 2
static inline vec2 vec2_create(f32 x, f32 y) { return (vec2){ x, y }; }
+static inline vec2 vec2_div(vec2 a, f32 s) { return (vec2){ a.x / s, a.y / s }; }
// TODO: Dimension 4
static inline vec4 vec4_create(f32 x, f32 y, f32 z, f32 w) { return (vec4){ x, y, z, w }; }
diff --git a/src/maths/primitives.c b/src/maths/primitives.c
index 55ff5fc..310fc98 100644
--- a/src/maths/primitives.c
+++ b/src/maths/primitives.c
@@ -1,4 +1,5 @@
#include "primitives.h"
+#include "maths.h"
// vertices
f32 plane_vertex_positions[] = {
@@ -13,9 +14,9 @@ geometry_data geo_create_plane(f32x2 extents) {
vertex_format format = VERTEX_STATIC_3D;
vertex_darray* vertices = vertex_darray_new(4);
- vertex_darray_push(vertices, (vertex){ .static_3d = { .position = } });
+ // vertex_darray_push(vertices, (vertex){ .static_3d = { .position = } });
- return (geometry_data) { .format = format, .vertices =.has_indices = true, }
+ // return (geometry_data) { .format = format, .vertices =.has_indices = true, }
}
// OLD
@@ -33,130 +34,132 @@ static mesh prim_cube_mesh_create() {
mesh cube = { 0 };
cube.vertices = vertex_darray_new(36);
- // back faces
- vertex_darray_push(
- cube.vertices,
- (vertex){ .position = BACK_BOT_LEFT, .normal = VEC3_NEG_Z, .uv = (vec2){ 0, 1 } });
- vertex_darray_push(
- cube.vertices,
- (vertex){ .position = BACK_TOP_LEFT, .normal = VEC3_NEG_Z, .uv = (vec2){ 0, 0 } });
- vertex_darray_push(
- cube.vertices,
- (vertex){ .position = BACK_TOP_RIGHT, .normal = VEC3_NEG_Z, .uv = (vec2){ 1, 0 } });
- vertex_darray_push(
- cube.vertices,
- (vertex){ .position = BACK_TOP_RIGHT, .normal = VEC3_NEG_Z, .uv = (vec2){ 1, 0 } });
- vertex_darray_push(
- cube.vertices,
- (vertex){ .position = BACK_BOT_RIGHT, .normal = VEC3_NEG_Z, .uv = (vec2){ 1, 1 } });
- vertex_darray_push(
- cube.vertices,
- (vertex){ .position = BACK_BOT_LEFT, .normal = VEC3_NEG_Z, .uv = (vec2){ 0, 1 } });
-
- // front faces
- vertex_darray_push(
- cube.vertices,
- (vertex){ .position = FRONT_BOT_LEFT, .normal = VEC3_Z, .uv = (vec2){ 0, 1 } });
- vertex_darray_push(
- cube.vertices,
- (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_Z, .uv = (vec2){ 1, 0 } });
- vertex_darray_push(
- cube.vertices,
- (vertex){ .position = FRONT_TOP_LEFT, .normal = VEC3_Z, .uv = (vec2){ 0, 0 } });
- vertex_darray_push(
- cube.vertices,
- (vertex){ .position = FRONT_BOT_LEFT, .normal = VEC3_Z, .uv = (vec2){ 0, 1 } });
- vertex_darray_push(
- cube.vertices,
- (vertex){ .position = FRONT_BOT_RIGHT, .normal = VEC3_Z, .uv = (vec2){ 1, 1 } });
- vertex_darray_push(
- cube.vertices,
- (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_Z, .uv = (vec2){ 1, 0 } });
-
- // top faces
- vertex_darray_push(cube.vertices,
- (vertex){ .position = BACK_TOP_LEFT, .normal = VEC3_Y, .uv = (vec2){ 0, 0 } });
- vertex_darray_push(
- cube.vertices,
- (vertex){ .position = FRONT_TOP_LEFT, .normal = VEC3_Y, .uv = (vec2){ 0, 1 } });
- vertex_darray_push(
- cube.vertices,
- (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_Y, .uv = (vec2){ 1, 1 } });
- vertex_darray_push(cube.vertices,
- (vertex){ .position = BACK_TOP_LEFT, .normal = VEC3_Y, .uv = (vec2){ 0, 0 } });
- vertex_darray_push(
- cube.vertices,
- (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_Y, .uv = (vec2){ 1, 1 } });
- vertex_darray_push(
- cube.vertices,
- (vertex){ .position = BACK_TOP_RIGHT, .normal = VEC3_Y, .uv = (vec2){ 1, 0 } });
-
- // bottom faces
- vertex_darray_push(
- cube.vertices,
- (vertex){ .position = BACK_BOT_LEFT, .normal = VEC3_NEG_Y, .uv = (vec2){ 0 } });
- vertex_darray_push(
- cube.vertices,
- (vertex){ .position = FRONT_BOT_RIGHT, .normal = VEC3_NEG_Y, .uv = (vec2){ 0 } });
- vertex_darray_push(
- cube.vertices,
- (vertex){ .position = FRONT_BOT_LEFT, .normal = VEC3_NEG_Y, .uv = (vec2){ 0 } });
- vertex_darray_push(
- cube.vertices,
- (vertex){ .position = BACK_BOT_LEFT, .normal = VEC3_NEG_Y, .uv = (vec2){ 0 } });
- vertex_darray_push(
- cube.vertices,
- (vertex){ .position = BACK_BOT_RIGHT, .normal = VEC3_NEG_Y, .uv = (vec2){ 0 } });
- vertex_darray_push(
- cube.vertices,
- (vertex){ .position = FRONT_BOT_RIGHT, .normal = VEC3_NEG_Y, .uv = (vec2){ 0 } });
-
- // right faces
- vertex_darray_push(
- cube.vertices,
- (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_X, .uv = (vec2){ 0, 0 } });
- vertex_darray_push(
- cube.vertices,
- (vertex){ .position = BACK_BOT_RIGHT, .normal = VEC3_X, .uv = (vec2){ 1, 1 } });
- vertex_darray_push(
- cube.vertices,
- (vertex){ .position = BACK_TOP_RIGHT, .normal = VEC3_X, .uv = (vec2){ 1, 0 } });
- vertex_darray_push(
- cube.vertices,
- (vertex){ .position = BACK_BOT_RIGHT, .normal = VEC3_X, .uv = (vec2){ 1, 1 } });
- vertex_darray_push(
- cube.vertices,
- (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_X, .uv = (vec2){ 0, 0 } });
- vertex_darray_push(
- cube.vertices,
- (vertex){ .position = FRONT_BOT_RIGHT, .normal = VEC3_X, .uv = (vec2){ 0, 1 } });
-
- // left faces
- vertex_darray_push(
- cube.vertices,
- (vertex){ .position = FRONT_TOP_LEFT, .normal = VEC3_NEG_X, .uv = (vec2){ 0 } });
- vertex_darray_push(
- cube.vertices,
- (vertex){ .position = BACK_TOP_LEFT, .normal = VEC3_NEG_X, .uv = (vec2){ 0 } });
- vertex_darray_push(
- cube.vertices,
- (vertex){ .position = BACK_BOT_LEFT, .normal = VEC3_NEG_X, .uv = (vec2){ 0 } });
- vertex_darray_push(
- cube.vertices,
- (vertex){ .position = BACK_BOT_LEFT, .normal = VEC3_NEG_X, .uv = (vec2){ 0 } });
- vertex_darray_push(
- cube.vertices,
- (vertex){ .position = FRONT_BOT_LEFT, .normal = VEC3_NEG_X, .uv = (vec2){ 0 } });
- vertex_darray_push(
- cube.vertices,
- (vertex){ .position = FRONT_TOP_LEFT, .normal = VEC3_NEG_X, .uv = (vec2){ 0 } });
-
- cube.indices_len = cube.vertices->len;
- cube.indices = malloc(sizeof(u32) * cube.indices_len);
-
- for (u32 i = 0; i < cube.indices_len; i++) {
- cube.indices[i] = i;
- }
+ // // back faces
+ // vertex_darray_push(
+ // cube.vertices,
+ // (vertex){ .position = BACK_BOT_LEFT, .normal = VEC3_NEG_Z, .uv = (vec2){ 0, 1 } });
+ // vertex_darray_push(
+ // cube.vertices,
+ // (vertex){ .position = BACK_TOP_LEFT, .normal = VEC3_NEG_Z, .uv = (vec2){ 0, 0 } });
+ // vertex_darray_push(
+ // cube.vertices,
+ // (vertex){ .position = BACK_TOP_RIGHT, .normal = VEC3_NEG_Z, .uv = (vec2){ 1, 0 } });
+ // vertex_darray_push(
+ // cube.vertices,
+ // (vertex){ .position = BACK_TOP_RIGHT, .normal = VEC3_NEG_Z, .uv = (vec2){ 1, 0 } });
+ // vertex_darray_push(
+ // cube.vertices,
+ // (vertex){ .position = BACK_BOT_RIGHT, .normal = VEC3_NEG_Z, .uv = (vec2){ 1, 1 } });
+ // vertex_darray_push(
+ // cube.vertices,
+ // (vertex){ .position = BACK_BOT_LEFT, .normal = VEC3_NEG_Z, .uv = (vec2){ 0, 1 } });
+
+ // // front faces
+ // vertex_darray_push(
+ // cube.vertices,
+ // (vertex){ .position = FRONT_BOT_LEFT, .normal = VEC3_Z, .uv = (vec2){ 0, 1 } });
+ // vertex_darray_push(
+ // cube.vertices,
+ // (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_Z, .uv = (vec2){ 1, 0 } });
+ // vertex_darray_push(
+ // cube.vertices,
+ // (vertex){ .position = FRONT_TOP_LEFT, .normal = VEC3_Z, .uv = (vec2){ 0, 0 } });
+ // vertex_darray_push(
+ // cube.vertices,
+ // (vertex){ .position = FRONT_BOT_LEFT, .normal = VEC3_Z, .uv = (vec2){ 0, 1 } });
+ // vertex_darray_push(
+ // cube.vertices,
+ // (vertex){ .position = FRONT_BOT_RIGHT, .normal = VEC3_Z, .uv = (vec2){ 1, 1 } });
+ // vertex_darray_push(
+ // cube.vertices,
+ // (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_Z, .uv = (vec2){ 1, 0 } });
+
+ // // top faces
+ // vertex_darray_push(cube.vertices,
+ // (vertex){ .position = BACK_TOP_LEFT, .normal = VEC3_Y, .uv = (vec2){ 0, 0
+ // } });
+ // vertex_darray_push(
+ // cube.vertices,
+ // (vertex){ .position = FRONT_TOP_LEFT, .normal = VEC3_Y, .uv = (vec2){ 0, 1 } });
+ // vertex_darray_push(
+ // cube.vertices,
+ // (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_Y, .uv = (vec2){ 1, 1 } });
+ // vertex_darray_push(cube.vertices,
+ // (vertex){ .position = BACK_TOP_LEFT, .normal = VEC3_Y, .uv = (vec2){ 0, 0
+ // } });
+ // vertex_darray_push(
+ // cube.vertices,
+ // (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_Y, .uv = (vec2){ 1, 1 } });
+ // vertex_darray_push(
+ // cube.vertices,
+ // (vertex){ .position = BACK_TOP_RIGHT, .normal = VEC3_Y, .uv = (vec2){ 1, 0 } });
+
+ // // bottom faces
+ // vertex_darray_push(
+ // cube.vertices,
+ // (vertex){ .position = BACK_BOT_LEFT, .normal = VEC3_NEG_Y, .uv = (vec2){ 0 } });
+ // vertex_darray_push(
+ // cube.vertices,
+ // (vertex){ .position = FRONT_BOT_RIGHT, .normal = VEC3_NEG_Y, .uv = (vec2){ 0 } });
+ // vertex_darray_push(
+ // cube.vertices,
+ // (vertex){ .position = FRONT_BOT_LEFT, .normal = VEC3_NEG_Y, .uv = (vec2){ 0 } });
+ // vertex_darray_push(
+ // cube.vertices,
+ // (vertex){ .position = BACK_BOT_LEFT, .normal = VEC3_NEG_Y, .uv = (vec2){ 0 } });
+ // vertex_darray_push(
+ // cube.vertices,
+ // (vertex){ .position = BACK_BOT_RIGHT, .normal = VEC3_NEG_Y, .uv = (vec2){ 0 } });
+ // vertex_darray_push(
+ // cube.vertices,
+ // (vertex){ .position = FRONT_BOT_RIGHT, .normal = VEC3_NEG_Y, .uv = (vec2){ 0 } });
+
+ // // right faces
+ // vertex_darray_push(
+ // cube.vertices,
+ // (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_X, .uv = (vec2){ 0, 0 } });
+ // vertex_darray_push(
+ // cube.vertices,
+ // (vertex){ .position = BACK_BOT_RIGHT, .normal = VEC3_X, .uv = (vec2){ 1, 1 } });
+ // vertex_darray_push(
+ // cube.vertices,
+ // (vertex){ .position = BACK_TOP_RIGHT, .normal = VEC3_X, .uv = (vec2){ 1, 0 } });
+ // vertex_darray_push(
+ // cube.vertices,
+ // (vertex){ .position = BACK_BOT_RIGHT, .normal = VEC3_X, .uv = (vec2){ 1, 1 } });
+ // vertex_darray_push(
+ // cube.vertices,
+ // (vertex){ .position = FRONT_TOP_RIGHT, .normal = VEC3_X, .uv = (vec2){ 0, 0 } });
+ // vertex_darray_push(
+ // cube.vertices,
+ // (vertex){ .position = FRONT_BOT_RIGHT, .normal = VEC3_X, .uv = (vec2){ 0, 1 } });
+
+ // // left faces
+ // vertex_darray_push(
+ // cube.vertices,
+ // (vertex){ .position = FRONT_TOP_LEFT, .normal = VEC3_NEG_X, .uv = (vec2){ 0 } });
+ // vertex_darray_push(
+ // cube.vertices,
+ // (vertex){ .position = BACK_TOP_LEFT, .normal = VEC3_NEG_X, .uv = (vec2){ 0 } });
+ // vertex_darray_push(
+ // cube.vertices,
+ // (vertex){ .position = BACK_BOT_LEFT, .normal = VEC3_NEG_X, .uv = (vec2){ 0 } });
+ // vertex_darray_push(
+ // cube.vertices,
+ // (vertex){ .position = BACK_BOT_LEFT, .normal = VEC3_NEG_X, .uv = (vec2){ 0 } });
+ // vertex_darray_push(
+ // cube.vertices,
+ // (vertex){ .position = FRONT_BOT_LEFT, .normal = VEC3_NEG_X, .uv = (vec2){ 0 } });
+ // vertex_darray_push(
+ // cube.vertices,
+ // (vertex){ .position = FRONT_TOP_LEFT, .normal = VEC3_NEG_X, .uv = (vec2){ 0 } });
+
+ // cube.indices_len = cube.vertices->len;
+ // cube.indices = malloc(sizeof(u32) * cube.indices_len);
+
+ // for (u32 i = 0; i < cube.indices_len; i++) {
+ // cube.indices[i] = i;
+ // }
cube.has_indices = true;
@@ -174,4 +177,10 @@ static model_handle prim_cube_new(core* core) {
u32 index = (u32)model_darray_len(core->models);
model_darray_push_copy(core->models, &model);
return (model_handle){ .raw = index };
+}
+
+// --- Spheres
+
+geometry_data geo_create_uvsphere(f32 radius, f32 north_south_lines, f32 east_west_lines) {
+ // TODO
} \ No newline at end of file
diff --git a/src/renderer/archive/old_backend_vulkan.c b/src/renderer/archive/old_backend_vulkan.c
new file mode 100644
index 0000000..a18ca70
--- /dev/null
+++ b/src/renderer/archive/old_backend_vulkan.c
@@ -0,0 +1,1990 @@
+#include "camera.h"
+#include "primitives.h"
+#define CDEBUG
+#define CEL_REND_BACKEND_VULKAN 1
+#if CEL_REND_BACKEND_VULKAN
+// ^ Temporary
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+#include <vk_platform.h>
+#include <vulkan.h>
+#include <vulkan_core.h>
+#include "colours.h"
+#include "str.h"
+
+#include "darray.h"
+#include "defines.h"
+#include "file.h"
+#include "log.h"
+#include "maths.h"
+#include "maths_types.h"
+#include "render_backend.h"
+#include "render_types.h"
+// #include "vulkan_helpers.h"
+
+#include <stdlib.h>
+
+#define SCR_WIDTH 1000
+#define SCR_HEIGHT 1000
+
+#include <glad/glad.h>
+
+#include <glfw3.h>
+
+KITC_DECL_TYPED_ARRAY(VkLayerProperties)
+
+typedef struct vulkan_device {
+ VkPhysicalDevice physical_device;
+ VkDevice logical_device;
+ vulkan_swapchain_support_info swapchain_support;
+ i32 graphics_queue_index;
+ i32 present_queue_index;
+ i32 compute_queue_index;
+ i32 transfer_queue_index;
+ VkQueue graphics_queue;
+ VkQueue present_queue;
+ VkQueue compute_queue;
+ VkQueue transfer_queue;
+ VkCommandPool gfx_command_pool;
+ VkPhysicalDeviceProperties properties;
+ VkPhysicalDeviceFeatures features;
+ VkPhysicalDeviceMemoryProperties memory;
+ VkFormat depth_format;
+} vulkan_device;
+
+typedef struct vulkan_image {
+ VkImage handle;
+ VkDeviceMemory memory;
+ VkImageView view;
+ u32 width;
+ u32 height;
+} vulkan_image;
+
+typedef struct vulkan_texture_data {
+ vulkan_image image;
+ VkSampler sampler;
+} vulkan_texture_data;
+
+typedef enum vulkan_renderpass_state {
+ READY,
+ RECORDING,
+ IN_RENDER_PASS,
+ RECORDING_ENDING,
+ SUBMITTED,
+ NOT_ALLOCATED
+} vulkan_renderpass_state;
+
+typedef struct vulkan_renderpass {
+ VkRenderPass handle;
+ vec4 render_area;
+ vec4 clear_colour;
+ f32 depth;
+ u32 stencil;
+ vulkan_renderpass_state state;
+} vulkan_renderpass;
+
+typedef struct vulkan_framebuffer {
+ VkFramebuffer handle;
+ u32 attachment_count;
+ VkImageView* attachments;
+ vulkan_renderpass* renderpass;
+} vulkan_framebuffer;
+
+KITC_DECL_TYPED_ARRAY(vulkan_framebuffer)
+
+typedef struct vulkan_swapchain {
+ VkSurfaceFormatKHR image_format;
+ u8 max_frames_in_flight;
+ VkSwapchainKHR handle;
+ u32 image_count;
+ VkImage* images;
+ VkImageView* views;
+ vulkan_image depth_attachment;
+ vulkan_framebuffer_darray* framebuffers;
+} vulkan_swapchain;
+
+// overengineered
+typedef enum vulkan_command_buffer_state {
+ COMMAND_BUFFER_STATE_READY,
+ COMMAND_BUFFER_STATE_IN_RENDER_PASS,
+ COMMAND_BUFFER_STATE_RECORDING,
+ COMMAND_BUFFER_STATE_RECORDING_ENDED,
+ COMMAND_BUFFER_STATE_SUBMITTED,
+ COMMAND_BUFFER_STATE_NOT_ALLOCATED,
+} vulkan_command_buffer_state;
+
+typedef struct vulkan_command_buffer {
+ VkCommandBuffer handle;
+ vulkan_command_buffer_state state;
+} vulkan_command_buffer;
+
+KITC_DECL_TYPED_ARRAY(vulkan_command_buffer)
+
+typedef struct vulkan_fence {
+ VkFence handle;
+ bool is_signaled;
+} vulkan_fence;
+
+typedef struct vulkan_shader_stage {
+ VkShaderModuleCreateInfo create_info;
+ VkShaderModule handle;
+ VkPipelineShaderStageCreateInfo stage_create_info;
+} vulkan_shader_stage;
+
+typedef struct vulkan_pipeline {
+ VkPipeline handle;
+ VkPipelineLayout layout;
+} vulkan_pipeline;
+
+typedef struct global_object_uniform {
+ mat4 projection; // 64 bytes
+ mat4 view; // 64 bytes
+ f32 padding[32];
+} global_object_uniform;
+
+typedef struct object_uniform {
+ vec4 diffuse_colour;
+ vec4 v_reserved0;
+ vec4 v_reserved1;
+ vec4 v_reserved2;
+} object_uniform;
+
+#define MAX_OBJECT_COUNT 1024
+#define VULKAN_OBJECT_SHADER_DESCRIPTOR_COUNT 1
+
+typedef struct geometry_render_data {
+ u32 id;
+ mat4 model;
+ texture* textures[16];
+} geometry_render_data;
+
+typedef struct vulkan_buffer {
+ u64 total_size;
+ VkBuffer handle;
+ VkBufferUsageFlagBits usage;
+ bool is_locked;
+ VkDeviceMemory memory;
+ i32 memory_index;
+ u32 memory_property_flags;
+} vulkan_buffer;
+
+#define SHADER_STAGE_COUNT 2
+
+typedef struct vulkan_shader {
+ // vertex, fragment
+ vulkan_shader_stage stages[SHADER_STAGE_COUNT];
+ vulkan_pipeline pipeline;
+
+ // descriptors
+ VkDescriptorPool descriptor_pool;
+ VkDescriptorSetLayout descriptor_set_layout;
+ VkDescriptorSet descriptor_sets[3]; // one for each in-flight frame
+
+ vulkan_buffer global_uniforms_buffer;
+
+ // Data that's global for all objects drawn
+ global_object_uniform global_ubo;
+ object_uniform object_ubo;
+ vulkan_texture_data* texture_data;
+} vulkan_shader;
+
+typedef struct vulkan_context {
+ VkInstance instance;
+ VkAllocationCallbacks* allocator;
+ VkSurfaceKHR surface;
+ vulkan_device device;
+ u32 framebuffer_width;
+ u32 framebuffer_height;
+ vulkan_swapchain swapchain;
+ vulkan_renderpass main_renderpass;
+ vulkan_buffer object_vertex_buffer;
+ vulkan_buffer object_index_buffer;
+ u64 geometry_vertex_offset;
+ u64 geometry_index_offset;
+
+ vulkan_command_buffer_darray* gfx_command_buffers;
+
+ VkSemaphore* image_available_semaphores;
+ VkSemaphore* queue_complete_semaphores;
+ u32 in_flight_fence_count;
+ vulkan_fence* in_flight_fences;
+ vulkan_fence** images_in_flight;
+
+ u32 image_index;
+ u32 current_frame;
+
+ vulkan_shader object_shader;
+
+ // TODO: swapchain recreation
+
+#if defined(DEBUG)
+ VkDebugUtilsMessengerEXT vk_debugger;
+#endif
+} vulkan_context;
+
+static vulkan_context context;
+
+static i32 find_memory_index(vulkan_context* context, u32 type_filter, u32 property_flags) {
+ VkPhysicalDeviceMemoryProperties memory_properties;
+ vkGetPhysicalDeviceMemoryProperties(context->device.physical_device, &memory_properties);
+
+ for (u32 i = 0; i < memory_properties.memoryTypeCount; ++i) {
+ // Check each memory type to see if its bit is set to 1.
+ if (type_filter & (1 << i) &&
+ (memory_properties.memoryTypes[i].propertyFlags & property_flags) == property_flags) {
+ return i;
+ }
+ }
+
+ WARN("Unable to find suitable memory type!");
+ return -1;
+}
+
+/** @brief Internal backend state */
+typedef struct vulkan_state {
+} vulkan_state;
+
+typedef struct vertex_pos {
+ vec3 pos;
+ vec3 normal;
+} vertex_pos;
+
+// pipeline stuff
+bool vulkan_graphics_pipeline_create(vulkan_context* context, vulkan_renderpass* renderpass,
+ u32 attribute_count,
+ VkVertexInputAttributeDescription* attributes,
+ u32 descriptor_set_layout_count,
+ VkDescriptorSetLayout* descriptor_set_layouts, u32 stage_count,
+ VkPipelineShaderStageCreateInfo* stages, VkViewport viewport,
+ VkRect2D scissor, bool is_wireframe,
+ vulkan_pipeline* out_pipeline) {
+ VkPipelineViewportStateCreateInfo viewport_state = {
+ VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO
+ };
+ viewport_state.viewportCount = 1;
+ viewport_state.pViewports = &viewport;
+ viewport_state.scissorCount = 1;
+ viewport_state.pScissors = &scissor;
+
+ // Rasterizer
+ VkPipelineRasterizationStateCreateInfo rasterizer_create_info = {
+ VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO
+ };
+ rasterizer_create_info.depthClampEnable = VK_FALSE;
+ rasterizer_create_info.rasterizerDiscardEnable = VK_FALSE;
+ rasterizer_create_info.polygonMode = is_wireframe ? VK_POLYGON_MODE_LINE : VK_POLYGON_MODE_FILL;
+ rasterizer_create_info.lineWidth = 1.0f;
+ rasterizer_create_info.cullMode = VK_CULL_MODE_BACK_BIT;
+ rasterizer_create_info.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
+ rasterizer_create_info.depthBiasEnable = VK_FALSE;
+ rasterizer_create_info.depthBiasConstantFactor = 0.0;
+ rasterizer_create_info.depthBiasClamp = 0.0;
+ rasterizer_create_info.depthBiasSlopeFactor = 0.0;
+
+ // Multisampling
+ VkPipelineMultisampleStateCreateInfo ms_create_info = {
+ VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO
+ };
+ ms_create_info.sampleShadingEnable = VK_FALSE;
+ ms_create_info.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
+ ms_create_info.minSampleShading = 1.0;
+ ms_create_info.pSampleMask = 0;
+ ms_create_info.alphaToCoverageEnable = VK_FALSE;
+ ms_create_info.alphaToOneEnable = VK_FALSE;
+
+ // Depth and stencil testing
+ VkPipelineDepthStencilStateCreateInfo depth_stencil = {
+ VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO
+ };
+ depth_stencil.depthTestEnable = VK_TRUE;
+ depth_stencil.depthWriteEnable = VK_TRUE;
+ depth_stencil.depthCompareOp = VK_COMPARE_OP_LESS;
+ depth_stencil.depthBoundsTestEnable = VK_FALSE;
+ depth_stencil.stencilTestEnable = VK_FALSE;
+ depth_stencil.pNext = 0;
+
+ VkPipelineColorBlendAttachmentState color_blend_attachment_state;
+ color_blend_attachment_state.blendEnable = VK_TRUE;
+ color_blend_attachment_state.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
+ color_blend_attachment_state.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
+ color_blend_attachment_state.colorBlendOp = VK_BLEND_OP_ADD;
+ color_blend_attachment_state.srcAlphaBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
+ color_blend_attachment_state.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
+ color_blend_attachment_state.alphaBlendOp = VK_BLEND_OP_ADD;
+ color_blend_attachment_state.colorWriteMask = VK_COLOR_COMPONENT_R_BIT |
+ VK_COLOR_COMPONENT_G_BIT |
+ VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
+
+ VkPipelineColorBlendStateCreateInfo color_blend = {
+ VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO
+ };
+ color_blend.logicOpEnable = VK_FALSE;
+ color_blend.logicOp = VK_LOGIC_OP_COPY;
+ color_blend.attachmentCount = 1;
+ color_blend.pAttachments = &color_blend_attachment_state;
+
+ const u32 dynamic_state_count = 3;
+ VkDynamicState dynamic_states[3] = {
+ VK_DYNAMIC_STATE_VIEWPORT,
+ VK_DYNAMIC_STATE_SCISSOR,
+ VK_DYNAMIC_STATE_LINE_WIDTH,
+ };
+
+ VkPipelineDynamicStateCreateInfo dynamic_state = {
+ VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO
+ };
+ dynamic_state.dynamicStateCount = dynamic_state_count;
+ dynamic_state.pDynamicStates = dynamic_states;
+
+ // Vertex input
+ VkVertexInputBindingDescription binding_desc;
+ binding_desc.binding = 0;
+ binding_desc.stride = sizeof(vertex);
+ binding_desc.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
+
+ VkPipelineVertexInputStateCreateInfo vertex_input_info = {
+ VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO
+ };
+ vertex_input_info.vertexBindingDescriptionCount = 1;
+ vertex_input_info.pVertexBindingDescriptions = &binding_desc;
+ vertex_input_info.vertexAttributeDescriptionCount = attribute_count;
+ vertex_input_info.pVertexAttributeDescriptions = attributes;
+
+ VkPipelineInputAssemblyStateCreateInfo input_assembly = {
+ VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO
+ };
+ input_assembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
+ input_assembly.primitiveRestartEnable = VK_FALSE;
+
+ VkPipelineLayoutCreateInfo pipeline_layout_create_info = {
+ VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO
+ };
+
+ // Pushconstants
+ VkPushConstantRange push_constant;
+ push_constant.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
+ push_constant.offset = sizeof(mat4) * 0;
+ push_constant.size = sizeof(mat4) * 2;
+
+ pipeline_layout_create_info.pushConstantRangeCount = 1;
+ pipeline_layout_create_info.pPushConstantRanges = &push_constant;
+
+ pipeline_layout_create_info.setLayoutCount = descriptor_set_layout_count;
+ pipeline_layout_create_info.pSetLayouts = descriptor_set_layouts;
+
+ vkCreatePipelineLayout(context->device.logical_device, &pipeline_layout_create_info,
+ context->allocator, &out_pipeline->layout);
+
+ VkGraphicsPipelineCreateInfo pipeline_create_info = {
+ VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO
+ };
+ pipeline_create_info.stageCount = stage_count;
+ pipeline_create_info.pStages = stages;
+ pipeline_create_info.pVertexInputState = &vertex_input_info;
+ pipeline_create_info.pInputAssemblyState = &input_assembly;
+
+ pipeline_create_info.pViewportState = &viewport_state;
+ pipeline_create_info.pRasterizationState = &rasterizer_create_info;
+ pipeline_create_info.pMultisampleState = &ms_create_info;
+ pipeline_create_info.pDepthStencilState = &depth_stencil;
+ pipeline_create_info.pColorBlendState = &color_blend;
+ pipeline_create_info.pDynamicState = &dynamic_state;
+ pipeline_create_info.pTessellationState = 0;
+
+ pipeline_create_info.layout = out_pipeline->layout;
+
+ pipeline_create_info.renderPass = renderpass->handle;
+ pipeline_create_info.subpass = 0;
+ pipeline_create_info.basePipelineHandle = VK_NULL_HANDLE;
+ pipeline_create_info.basePipelineIndex = -1;
+
+ VkResult result =
+ vkCreateGraphicsPipelines(context->device.logical_device, VK_NULL_HANDLE, 1,
+ &pipeline_create_info, context->allocator, &out_pipeline->handle);
+ if (result != VK_SUCCESS) {
+ FATAL("graphics pipeline creation failed. its fked mate");
+ ERROR_EXIT("Doomed");
+ }
+
+ return true;
+}
+
+void vulkan_pipeline_bind(vulkan_command_buffer* command_buffer, VkPipelineBindPoint bind_point,
+ vulkan_pipeline* pipeline) {
+ vkCmdBindPipeline(command_buffer->handle, bind_point, pipeline->handle);
+}
+
+void vulkan_buffer_bind(vulkan_context* context, vulkan_buffer* buffer, u64 offset) {
+ vkBindBufferMemory(context->device.logical_device, buffer->handle, buffer->memory, offset);
+}
+
+bool vulkan_buffer_create(vulkan_context* context, u64 size, VkBufferUsageFlagBits usage,
+ u32 memory_property_flags, bool bind_on_create,
+ vulkan_buffer* out_buffer) {
+ memset(out_buffer, 0, sizeof(vulkan_buffer));
+ out_buffer->total_size = size;
+ out_buffer->usage = usage;
+ out_buffer->memory_property_flags = memory_property_flags;
+
+ VkBufferCreateInfo buffer_info = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
+ buffer_info.size = size;
+ buffer_info.usage = usage;
+ buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
+
+ vkCreateBuffer(context->device.logical_device, &buffer_info, context->allocator,
+ &out_buffer->handle);
+
+ VkMemoryRequirements requirements;
+ vkGetBufferMemoryRequirements(context->device.logical_device, out_buffer->handle, &requirements);
+ out_buffer->memory_index =
+ find_memory_index(context, requirements.memoryTypeBits, out_buffer->memory_property_flags);
+
+ // Allocate
+ VkMemoryAllocateInfo allocate_info = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
+ allocate_info.allocationSize = requirements.size;
+ allocate_info.memoryTypeIndex = (u32)out_buffer->memory_index;
+
+ vkAllocateMemory(context->device.logical_device, &allocate_info, context->allocator,
+ &out_buffer->memory);
+
+ if (bind_on_create) {
+ vulkan_buffer_bind(context, out_buffer, 0);
+ }
+
+ DEBUG("Created buffer.");
+
+ return true;
+}
+
+// lock and unlock?
+
+void* vulkan_buffer_lock_memory(vulkan_context* context, vulkan_buffer* buffer, u64 offset,
+ u64 size, u32 flags) {
+ void* data;
+ vkMapMemory(context->device.logical_device, buffer->memory, offset, size, flags, &data);
+ return data;
+}
+void* vulkan_buffer_unlock_memory(vulkan_context* context, vulkan_buffer* buffer) {
+ vkUnmapMemory(context->device.logical_device, buffer->memory);
+}
+
+void vulkan_buffer_load_data(vulkan_context* context, vulkan_buffer* buffer, u64 offset, u64 size,
+ u32 flags, const void* data) {
+ void* data_ptr = 0;
+ VK_CHECK(
+ vkMapMemory(context->device.logical_device, buffer->memory, offset, size, flags, &data_ptr));
+ memcpy(data_ptr, data, size);
+ vkUnmapMemory(context->device.logical_device, buffer->memory);
+}
+
+// TODO: destroy
+
+bool create_shader_module(vulkan_context* context, const char* filename, const char* type_str,
+ VkShaderStageFlagBits flag, u32 stage_index,
+ vulkan_shader_stage* shader_stages) {
+ memset(&shader_stages[stage_index].create_info, 0, sizeof(VkShaderModuleCreateInfo));
+ memset(&shader_stages[stage_index].stage_create_info, 0, sizeof(VkPipelineShaderStageCreateInfo));
+
+ shader_stages[stage_index].create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
+
+ // todo: file input
+ FileData file_contents = load_spv_file(filename);
+
+ shader_stages[stage_index].create_info.codeSize = file_contents.size;
+ shader_stages[stage_index].create_info.pCode = (u32*)file_contents.data;
+
+ vkCreateShaderModule(context->device.logical_device, &shader_stages[stage_index].create_info,
+ context->allocator, &shader_stages[stage_index].handle);
+
+ shader_stages[stage_index].stage_create_info.sType =
+ VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
+ shader_stages[stage_index].stage_create_info.stage = flag;
+ shader_stages[stage_index].stage_create_info.module = shader_stages[stage_index].handle;
+ shader_stages[stage_index].stage_create_info.pName = "main";
+
+ free(file_contents.data);
+
+ // TODO: Descriptors
+
+ return true;
+}
+
+bool vulkan_object_shader_create(vulkan_context* context, vulkan_shader* out_shader) {
+ char stage_type_strs[SHADER_STAGE_COUNT][5] = { "vert", "frag" };
+ char stage_filenames[SHADER_STAGE_COUNT][256] = { "build/linux/x86_64/debug/object.vert.spv",
+ "build/linux/x86_64/debug/object.frag.spv" };
+ VkShaderStageFlagBits stage_types[SHADER_STAGE_COUNT] = { VK_SHADER_STAGE_VERTEX_BIT,
+ VK_SHADER_STAGE_FRAGMENT_BIT };
+ for (u8 i = 0; i < SHADER_STAGE_COUNT; i++) {
+ DEBUG("Loading %s", stage_filenames[i]);
+ create_shader_module(context, stage_filenames[i], stage_type_strs[i], stage_types[i], i,
+ out_shader->stages);
+ }
+
+ // descriptors
+ VkDescriptorSetLayoutBinding global_ubo_layout_binding;
+ global_ubo_layout_binding.binding = 0;
+ global_ubo_layout_binding.descriptorCount = 1;
+ global_ubo_layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
+ global_ubo_layout_binding.pImmutableSamplers = 0;
+ global_ubo_layout_binding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
+
+ VkDescriptorSetLayoutBinding sampler_layout_binding;
+ sampler_layout_binding.binding = 1;
+ sampler_layout_binding.descriptorCount = 1;
+ sampler_layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
+ sampler_layout_binding.pImmutableSamplers = 0;
+ sampler_layout_binding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
+
+ VkDescriptorSetLayoutCreateInfo global_layout_info = {
+ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO
+ };
+
+ VkDescriptorSetLayoutBinding bindings[2] = { global_ubo_layout_binding, sampler_layout_binding };
+
+ global_layout_info.bindingCount = 2;
+ global_layout_info.pBindings = bindings;
+
+ VK_CHECK(vkCreateDescriptorSetLayout(context->device.logical_device, &global_layout_info,
+ context->allocator, &out_shader->descriptor_set_layout));
+
+ VkDescriptorPoolSize global_pool_size;
+ global_pool_size.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
+ global_pool_size.descriptorCount = 3;
+
+ VkDescriptorPoolSize sampler_pool_size;
+ sampler_pool_size.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
+ sampler_pool_size.descriptorCount = 3;
+
+ VkDescriptorPoolSize pool_sizes[2] = { global_pool_size, sampler_pool_size };
+
+ VkDescriptorPoolCreateInfo pool_info = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO };
+ pool_info.poolSizeCount = 2;
+ pool_info.pPoolSizes = pool_sizes;
+ pool_info.maxSets = 3;
+
+ VK_CHECK(vkCreateDescriptorPool(context->device.logical_device, &pool_info, context->allocator,
+ &out_shader->descriptor_pool));
+
+ // Pipeline creation
+ VkViewport viewport;
+ viewport.x = 0;
+ viewport.y = 0;
+ viewport.width = (f32)context->framebuffer_width;
+ viewport.height = (f32)context->framebuffer_height;
+ viewport.minDepth = 0.0;
+ viewport.maxDepth = 1.0;
+
+ VkRect2D scissor;
+ scissor.offset.x = scissor.offset.y = 0;
+ scissor.extent.width = context->framebuffer_width;
+ scissor.extent.height = context->framebuffer_height;
+
+ // Attributes
+ u32 offset = 0;
+ const i32 attribute_count = 3;
+ VkVertexInputAttributeDescription attribute_descs[3];
+ // Position
+ VkFormat formats[3] = { VK_FORMAT_R32G32B32_SFLOAT, VK_FORMAT_R32G32B32_SFLOAT,
+ VK_FORMAT_R32G32_SFLOAT };
+
+ u64 sizes[3] = { sizeof(vec3), sizeof(vec3), sizeof(vec2) };
+
+ for (u32 i = 0; i < attribute_count; i++) {
+ attribute_descs[i].binding = 0;
+ attribute_descs[i].location = i;
+ attribute_descs[i].format = formats[i];
+ attribute_descs[i].offset = offset;
+ offset += sizes[i];
+ }
+
+ // Descriptor set layouts
+ VkDescriptorSetLayout layouts[1] = { out_shader->descriptor_set_layout };
+
+ // Stages
+ VkPipelineShaderStageCreateInfo stage_create_infos[SHADER_STAGE_COUNT];
+ memset(stage_create_infos, 0, sizeof(stage_create_infos));
+ for (u32 i = 0; i < SHADER_STAGE_COUNT; i++) {
+ stage_create_infos[i].sType = out_shader->stages[i].stage_create_info.sType;
+ stage_create_infos[i] = out_shader->stages[i].stage_create_info;
+ }
+
+ vulkan_graphics_pipeline_create(
+ context, &context->main_renderpass, attribute_count, attribute_descs, 1, layouts,
+ SHADER_STAGE_COUNT, stage_create_infos, viewport, scissor, false, &out_shader->pipeline);
+ INFO("Graphics pipeline created!");
+
+ // Uniform buffer
+ if (!vulkan_buffer_create(context, sizeof(global_object_uniform),
+ VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
+ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
+ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
+ VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
+ true, &out_shader->global_uniforms_buffer)) {
+ ERROR("Couldnt create uniforms buffer");
+ return false;
+ }
+
+ VkDescriptorSetLayout global_layouts[3] = {
+ out_shader->descriptor_set_layout,
+ out_shader->descriptor_set_layout,
+ out_shader->descriptor_set_layout,
+ };
+
+ VkDescriptorSetAllocateInfo alloc_info = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO };
+ alloc_info.descriptorPool = out_shader->descriptor_pool;
+ alloc_info.descriptorSetCount = 3;
+ alloc_info.pSetLayouts = global_layouts;
+ VK_CHECK(vkAllocateDescriptorSets(context->device.logical_device, &alloc_info,
+ out_shader->descriptor_sets));
+
+ return true;
+}
+void vulkan_object_shader_destroy(vulkan_context* context, vulkan_shader* shader) {}
+void vulkan_object_shader_use(vulkan_context* context, vulkan_shader* shader) {
+ u32 image_index = context->image_index;
+ vulkan_pipeline_bind(&context->gfx_command_buffers->data[image_index],
+ VK_PIPELINE_BIND_POINT_GRAPHICS, &shader->pipeline);
+}
+void vulkan_object_shader_update_global_state(vulkan_context* context, vulkan_shader* shader) {
+ u32 image_index = context->image_index;
+ VkCommandBuffer cmd_buffer = context->gfx_command_buffers->data[image_index].handle;
+ VkDescriptorSet global_descriptors = shader->descriptor_sets[image_index];
+
+ u32 range = sizeof(global_object_uniform);
+ u64 offset = 0;
+
+ // copy data to buffer
+ vulkan_buffer_load_data(context, &shader->global_uniforms_buffer, offset, range, 0,
+ &shader->global_ubo);
+
+ VkDescriptorBufferInfo buffer_info;
+ buffer_info.buffer = shader->global_uniforms_buffer.handle;
+ buffer_info.offset = offset;
+ buffer_info.range = range;
+
+ VkDescriptorImageInfo image_info;
+ image_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+ image_info.imageView = shader->texture_data->image.view;
+ image_info.sampler = shader->texture_data->sampler;
+
+ VkWriteDescriptorSet uniform_write = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET };
+ uniform_write.dstSet = shader->descriptor_sets[image_index];
+ uniform_write.dstBinding = 0;
+ uniform_write.dstArrayElement = 0;
+ uniform_write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
+ uniform_write.descriptorCount = 1;
+ uniform_write.pBufferInfo = &buffer_info;
+
+ VkWriteDescriptorSet texture_write = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET };
+ texture_write.dstSet = shader->descriptor_sets[image_index];
+ texture_write.dstBinding = 1;
+ texture_write.dstArrayElement = 0;
+ texture_write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
+ texture_write.descriptorCount = 1;
+ texture_write.pImageInfo = &image_info;
+
+ VkWriteDescriptorSet writes[2] = { uniform_write, texture_write };
+
+ vkUpdateDescriptorSets(context->device.logical_device, 2, writes, 0, 0);
+
+ vkCmdBindDescriptorSets(cmd_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, shader->pipeline.layout, 0,
+ 1, &global_descriptors, 0, 0);
+}
+
+void vulkan_object_shader_update_object(vulkan_context* context, vulkan_shader* shader,
+ mat4 model) {
+ u32 image_index = context->image_index;
+ VkCommandBuffer cmd_buffer = context->gfx_command_buffers->data[image_index].handle;
+ // vulkan_command_buffer* cmd_buffer = &context->gfx_command_buffers->data[context.image_index];
+
+ vkCmdPushConstants(cmd_buffer, shader->pipeline.layout, VK_SHADER_STAGE_VERTEX_BIT, 0,
+ sizeof(mat4), &model);
+
+ // vulkan_object_shader_use(context, &context->object_shader);
+ VkDeviceSize offsets[1] = { 0 };
+ vkCmdBindVertexBuffers(cmd_buffer, 0, 1, &context->object_vertex_buffer.handle,
+ (VkDeviceSize*)offsets);
+
+ vkCmdBindIndexBuffer(cmd_buffer, context->object_index_buffer.handle, 0, VK_INDEX_TYPE_UINT32);
+
+ vkCmdDrawIndexed(cmd_buffer, 36, 1, 0, 0, 0);
+ // vkCmdDraw(cmd_buffer, 36, 1, 0, 0);
+}
+
+bool select_physical_device(vulkan_context* ctx) {
+ u32 physical_device_count = 0;
+ VK_CHECK(vkEnumeratePhysicalDevices(ctx->instance, &physical_device_count, 0));
+ if (physical_device_count == 0) {
+ FATAL("No devices that support vulkan were found");
+ return false;
+ }
+ TRACE("Number of devices found %d", physical_device_count);
+
+ VkPhysicalDevice physical_devices[physical_device_count];
+ VK_CHECK(vkEnumeratePhysicalDevices(ctx->instance, &physical_device_count, physical_devices));
+
+ for (u32 i = 0; i < physical_device_count; i++) {
+ VkPhysicalDeviceProperties properties;
+ vkGetPhysicalDeviceProperties(physical_devices[i], &properties);
+
+ VkPhysicalDeviceFeatures features;
+ vkGetPhysicalDeviceFeatures(physical_devices[i], &features);
+
+ VkPhysicalDeviceMemoryProperties memory;
+ vkGetPhysicalDeviceMemoryProperties(physical_devices[i], &memory);
+
+ vulkan_physical_device_requirements requirements = {};
+ requirements.graphics = true;
+ requirements.present = true;
+ requirements.compute = true;
+ requirements.transfer = true;
+
+ requirements.sampler_anistropy = true;
+ requirements.discrete_gpu = true;
+ requirements.device_ext_names[0] = str8lit(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
+ requirements.device_ext_name_count = 1;
+
+ vulkan_physical_device_queue_family_info queue_info = {};
+
+ bool result = physical_device_meets_requirements(physical_devices[i], ctx->surface, &properties,
+ &features, &requirements, &queue_info,
+ &ctx->device.swapchain_support);
+
+ if (result) {
+ INFO("GPU Driver version: %d.%d.%d", VK_VERSION_MAJOR(properties.driverVersion),
+ VK_VERSION_MINOR(properties.driverVersion), VK_VERSION_PATCH(properties.driverVersion));
+
+ INFO("Vulkan API version: %d.%d.%d", VK_VERSION_MAJOR(properties.apiVersion),
+ VK_VERSION_MINOR(properties.apiVersion), VK_VERSION_PATCH(properties.apiVersion));
+
+ // TODO: print gpu memory information -
+ // https://youtu.be/6Kj3O2Ov1RU?si=pXfP5NvXXcXjJsrG&t=2439
+
+ ctx->device.physical_device = physical_devices[i];
+ ctx->device.graphics_queue_index = queue_info.graphics_family_index;
+ ctx->device.present_queue_index = queue_info.present_family_index;
+ ctx->device.compute_queue_index = queue_info.compute_family_index;
+ ctx->device.transfer_queue_index = queue_info.transfer_family_index;
+ ctx->device.properties = properties;
+ ctx->device.features = features;
+ ctx->device.memory = memory;
+ break;
+ }
+ }
+
+ if (!ctx->device.physical_device) {
+ ERROR("No suitable physical devices were found :(");
+ return false;
+ }
+
+ INFO("Physical device selected: %s\n", ctx->device.properties.deviceName);
+ return true;
+}
+
+bool vulkan_device_create(vulkan_context* context) {
+ // Physical device - NOTE: mutates the context directly
+ if (!select_physical_device(context)) {
+ return false;
+ }
+
+// Logical device - NOTE: mutates the context directly
+
+// queues
+#define VULKAN_QUEUES_COUNT 2
+ const char* queue_names[VULKAN_QUEUES_COUNT] = {
+ "GRAPHICS",
+ "TRANSFER",
+ };
+ i32 indices[VULKAN_QUEUES_COUNT] = {
+ context->device.graphics_queue_index,
+ context->device.transfer_queue_index,
+ };
+ f32 prio_one = 1.0;
+ VkDeviceQueueCreateInfo queue_create_info[2]; // HACK: make 2 queues, graphics and transfer
+ // graphics
+ queue_create_info[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
+ queue_create_info[0].queueFamilyIndex = 0;
+ queue_create_info[0].queueCount = 1;
+ queue_create_info[0].flags = 0;
+ queue_create_info[0].pNext = 0;
+ queue_create_info[0].pQueuePriorities = &prio_one;
+ // transfer
+ queue_create_info[1].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
+ queue_create_info[1].queueFamilyIndex = 1;
+ queue_create_info[1].queueCount = 1;
+ queue_create_info[1].flags = 0;
+ queue_create_info[1].pNext = 0;
+ queue_create_info[1].pQueuePriorities = &prio_one;
+
+ // for (int i = 0; i < 2; i++) {
+ // TRACE("Configure %s queue", queue_names[i]);
+ // queue_create_info[i].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
+ // queue_create_info[i].queueFamilyIndex = indices[i];
+ // queue_create_info[i].queueCount = 1; // make just one of them
+ // queue_create_info[i].flags = 0;
+ // queue_create_info[i].pNext = 0;
+ // f32 priority = 1.0;
+ // queue_create_info[i].pQueuePriorities = &priority;
+ // }
+
+ // features
+ VkPhysicalDeviceFeatures device_features = {};
+ device_features.samplerAnisotropy = VK_TRUE; // request anistrophy
+
+ // device itself
+ VkDeviceCreateInfo device_create_info = { VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO };
+ device_create_info.queueCreateInfoCount = VULKAN_QUEUES_COUNT;
+ device_create_info.pQueueCreateInfos = queue_create_info;
+ device_create_info.pEnabledFeatures = &device_features;
+ device_create_info.enabledExtensionCount = 1;
+ const char* extension_names = VK_KHR_SWAPCHAIN_EXTENSION_NAME;
+ device_create_info.ppEnabledExtensionNames = &extension_names;
+
+ // deprecated
+ device_create_info.enabledLayerCount = 0;
+ device_create_info.ppEnabledLayerNames = 0;
+
+ VkResult result = vkCreateDevice(context->device.physical_device, &device_create_info,
+ context->allocator, &context->device.logical_device);
+ if (result != VK_SUCCESS) {
+ printf("error creating logical device with status %u\n", result);
+ ERROR_EXIT("Bye bye");
+ }
+ INFO("Logical device created");
+
+ // get queues
+ vkGetDeviceQueue(context->device.logical_device, context->device.graphics_queue_index, 0,
+ &context->device.graphics_queue);
+ // vkGetDeviceQueue(context->device.logical_device, context->device.present_queue_index, 0,
+ // &context->device.present_queue);
+ // vkGetDeviceQueue(context->device.logical_device, context->device.compute_queue_index, 0,
+ // &context->device.compute_queue);
+ vkGetDeviceQueue(context->device.logical_device, context->device.transfer_queue_index, 0,
+ &context->device.transfer_queue);
+
+ // create command pool for graphics queue
+ VkCommandPoolCreateInfo pool_create_info = { VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO };
+ pool_create_info.queueFamilyIndex = context->device.graphics_queue_index;
+ pool_create_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
+ vkCreateCommandPool(context->device.logical_device, &pool_create_info, context->allocator,
+ &context->device.gfx_command_pool);
+ INFO("Created Command Pool")
+
+ return true;
+}
+void vulkan_device_destroy(vulkan_context* context) {
+ context->device.physical_device = 0; // release
+ // TODO: reset other memory
+}
+
+bool vulkan_device_detect_depth_format(vulkan_device* device) {
+ const size_t n_candidates = 3;
+ VkFormat candidates[3] = { VK_FORMAT_D32_SFLOAT, VK_FORMAT_D32_SFLOAT_S8_UINT,
+ VK_FORMAT_D24_UNORM_S8_UINT };
+ u32 flags = VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT;
+ for (u64 i = 0; i < n_candidates; i++) {
+ VkFormatProperties properties;
+ vkGetPhysicalDeviceFormatProperties(device->physical_device, candidates[i], &properties);
+
+ if ((properties.linearTilingFeatures & flags) == flags) {
+ device->depth_format = candidates[i];
+ return true;
+ }
+ if ((properties.optimalTilingFeatures & flags) == flags) {
+ device->depth_format = candidates[i];
+ return true;
+ }
+ }
+ return false;
+}
+
+void vulkan_image_view_create(vulkan_context* context, VkFormat format, vulkan_image* image,
+ VkImageAspectFlags aspect_flags) {
+ VkImageViewCreateInfo view_create_info = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };
+ view_create_info.image = image->handle;
+ view_create_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
+ view_create_info.format = format;
+ view_create_info.subresourceRange.aspectMask = aspect_flags;
+
+ view_create_info.subresourceRange.baseMipLevel = 0;
+ view_create_info.subresourceRange.levelCount = 1;
+ view_create_info.subresourceRange.baseArrayLayer = 0;
+ view_create_info.subresourceRange.layerCount = 1;
+
+ vkCreateImageView(context->device.logical_device, &view_create_info, context->allocator,
+ &image->view);
+}
+
+void vulkan_image_transition_layout(vulkan_context* context, vulkan_command_buffer* command_buffer,
+ vulkan_image* image, VkFormat format, VkImageLayout old_layout,
+ VkImageLayout new_layout) {
+ VkImageMemoryBarrier barrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER };
+ void vulkan_image_transition_layout(
+ vulkan_context * context, vulkan_command_buffer * command_buffer, vulkan_image * image,
+ VkFormat format, VkImageLayout old_layout, VkImageLayout new_layout) {
+ VkImageMemoryBarrier barrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER };
+ barrier.oldLayout = old_layout;
+ barrier.newLayout = new_layout;
+ barrier.srcQueueFamilyIndex = context->device.graphics_queue_index;
+ barrier.dstQueueFamilyIndex = context->device.graphics_queue_index;
+ barrier.image = image->handle;
+ barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+ barrier.subresourceRange.baseMipLevel = 0;
+ barrier.subresourceRange.levelCount = 1;
+ barrier.subresourceRange.baseArrayLayer = 0;
+ barrier.subresourceRange.layerCount = 1;
+ barrier.srcAccessMask = 0;
+ barrier.dstAccessMask = 0;
+
+ VkPipelineStageFlags source_stage;
+ VkPipelineStageFlags dest_stage;
+
+ if (old_layout == VK_IMAGE_LAYOUT_UNDEFINED &&
+ new_layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
+ barrier.srcAccessMask = 0;
+ barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
+
+ source_stage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
+ dest_stage = VK_PIPELINE_STAGE_TRANSFER_BIT;
+
+ } else if (old_layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL &&
+ new_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
+ barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
+ barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
+ source_stage = VK_PIPELINE_STAGE_TRANSFER_BIT;
+ dest_stage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
+ } else {
+ FATAL("Unsupported image layout transition");
+ return;
+ }
+
+ vkCmdPipelineBarrier(command_buffer->handle, source_stage, dest_stage, 0, 0, 0, 0, 0, 1,
+ &barrier);
+ }
+
+ void vulkan_image_copy_from_buffer(vulkan_image * image, VkBuffer buffer,
+ vulkan_command_buffer * command_buffer) {
+ VkBufferImageCopy region;
+ region.bufferOffset = 0;
+ region.bufferRowLength = 0;
+ region.bufferImageHeight = 0;
+ region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+ region.imageSubresource.mipLevel = 0;
+ region.imageSubresource.baseArrayLayer = 0;
+ region.imageSubresource.layerCount = 1;
+ printf("Image details width: %d height %d\n", image->width, image->height);
+ region.imageOffset.x = 0;
+ region.imageOffset.y = 0;
+ region.imageOffset.z = 0;
+ region.imageExtent.width = image->width;
+ region.imageExtent.height = image->height;
+ region.imageExtent.depth = 1;
+
+ vkCmdCopyBufferToImage(command_buffer->handle, buffer, image->handle,
+ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
+ }
+
+ void vulkan_image_create(vulkan_context * context, VkImageType image_type, u32 width, u32 height,
+ VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage,
+ VkMemoryPropertyFlags memory_flags, bool create_view,
+ VkImageAspectFlags aspect_flags, vulkan_image* out_image) {
+ // copy params
+ out_image->width = width;
+ out_image->height = height;
+
+ // create info
+ VkImageCreateInfo image_create_info = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };
+ image_create_info.imageType = image_type;
+ image_create_info.extent.width = width;
+ image_create_info.extent.height = height;
+ image_create_info.extent.depth = 1;
+ image_create_info.mipLevels = 1;
+ image_create_info.arrayLayers = 1;
+ image_create_info.format = format;
+ image_create_info.tiling = tiling;
+ image_create_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+ image_create_info.usage = usage;
+ image_create_info.samples = VK_SAMPLE_COUNT_1_BIT;
+ image_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
+
+ VK_CHECK(vkCreateImage(context->device.logical_device, &image_create_info, context->allocator,
+ &out_image->handle));
+
+ VkMemoryRequirements memory_reqs;
+ vkGetImageMemoryRequirements(context->device.logical_device, out_image->handle, &memory_reqs);
+
+ i32 memory_type = -1;
+ VkPhysicalDeviceMemoryProperties memory_properties;
+ vkGetPhysicalDeviceMemoryProperties(context->device.physical_device, &memory_properties);
+
+ for (u32 i = 0; i < memory_properties.memoryTypeCount; i++) {
+ // typefilter = memoryTypeBits , prop filter = memory_flags
+ if (memory_reqs.memoryTypeBits & (1 << i) &&
+ (memory_properties.memoryTypes[i].propertyFlags & memory_flags)) {
+ memory_type = i;
+ break;
+ }
+ }
+
+ if (memory_type < 0) {
+ ERROR_EXIT("couldnt find a suitable memory type for the image");
+ }
+
+ // allocate memory
+ VkMemoryAllocateInfo memory_allocate_info = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
+ memory_allocate_info.allocationSize = memory_reqs.size;
+ memory_allocate_info.memoryTypeIndex = memory_type;
+ vkAllocateMemory(context->device.logical_device, &memory_allocate_info, context->allocator,
+ &out_image->memory);
+
+ // bind memory
+ // TODO: maybe bind context->device.logical_device to device at the top of the functions?
+ vkBindImageMemory(context->device.logical_device, out_image->handle, out_image->memory, 0);
+
+ if (create_view) {
+ out_image->view = 0;
+ vulkan_image_view_create(context, format, out_image, aspect_flags);
+ }
+ }
+
+ // TODO: vulkan_image_destroy
+
+ void vulkan_framebuffer_create(vulkan_context * context, vulkan_renderpass * renderpass,
+ u32 width, u32 height, u32 attachment_count,
+ VkImageView * attachments, vulkan_framebuffer * out_framebuffer) {
+ out_framebuffer->attachments = malloc(sizeof(VkImageView) * attachment_count);
+ for (u32 i = 0; i < attachment_count; i++) {
+ out_framebuffer->attachments[i] = attachments[i];
+ }
+ out_framebuffer->attachment_count = attachment_count;
+ out_framebuffer->renderpass = renderpass;
+
+ VkFramebufferCreateInfo framebuffer_create_info = {
+ VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO
+ }; // TODO
+
+ framebuffer_create_info.renderPass = renderpass->handle;
+ framebuffer_create_info.attachmentCount = attachment_count;
+ framebuffer_create_info.pAttachments = out_framebuffer->attachments;
+ framebuffer_create_info.width = width;
+ framebuffer_create_info.height = height;
+ framebuffer_create_info.layers = 1;
+
+ vkCreateFramebuffer(context->device.logical_device, &framebuffer_create_info,
+ context->allocator, &out_framebuffer->handle);
+ }
+
+ // TODO: vulkan_framebuffer_destroy
+
+ void vulkan_command_buffer_allocate(vulkan_context * context, VkCommandPool pool, bool is_primary,
+ vulkan_command_buffer* out_command_buffer) {
+ VkCommandBufferAllocateInfo allocate_info = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO };
+ allocate_info.commandPool = pool;
+ allocate_info.level =
+ is_primary ? VK_COMMAND_BUFFER_LEVEL_PRIMARY : VK_COMMAND_BUFFER_LEVEL_SECONDARY;
+ allocate_info.commandBufferCount = 1;
+ allocate_info.pNext = 0;
+
+ out_command_buffer->state = COMMAND_BUFFER_STATE_NOT_ALLOCATED;
+ vkAllocateCommandBuffers(context->device.logical_device, &allocate_info,
+ &out_command_buffer->handle);
+ out_command_buffer->state = COMMAND_BUFFER_STATE_READY;
+ }
+
+ void vulkan_command_buffer_free(vulkan_context * context, VkCommandPool pool,
+ vulkan_command_buffer * out_command_buffer) {
+ // TODO: implement freeing
+ }
+
+ void vulkan_command_buffer_begin(vulkan_command_buffer * command_buffer, bool is_single_use,
+ bool is_renderpass_continue, bool is_simultaneous_use) {
+ VkCommandBufferBeginInfo begin_info = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
+ begin_info.flags = 0;
+ if (is_single_use) {
+ begin_info.flags |= VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
+ }
+ // TODO: RENDER_PASS_CONTINUE_BIT & SIMULTANEOUS_USE_BIT
+
+ begin_info.pNext = 0;
+ begin_info.pInheritanceInfo = 0;
+ vkBeginCommandBuffer(command_buffer->handle, &begin_info);
+
+ command_buffer->state = COMMAND_BUFFER_STATE_RECORDING;
+ }
+
+ void vulkan_command_buffer_end(vulkan_command_buffer * command_buffer) {
+ VK_CHECK(vkEndCommandBuffer(command_buffer->handle));
+ command_buffer->state = COMMAND_BUFFER_STATE_RECORDING_ENDED;
+ }
+ void vulkan_command_buffer_update_submitted(vulkan_command_buffer * command_buffer) {
+ command_buffer->state = COMMAND_BUFFER_STATE_SUBMITTED;
+ }
+ void vulkan_command_buffer_reset(vulkan_command_buffer * command_buffer) {
+ command_buffer->state = COMMAND_BUFFER_STATE_READY;
+ }
+
+ void vulkan_command_buffer_allocate_and_begin_oneshot(
+ vulkan_context * context, VkCommandPool pool, vulkan_command_buffer * out_command_buffer) {
+ vulkan_command_buffer_allocate(context, pool, true, out_command_buffer);
+ vulkan_command_buffer_begin(out_command_buffer, true, false, false);
+ }
+
+ void vulkan_command_buffer_end_oneshot(vulkan_context * context, VkCommandPool pool,
+ vulkan_command_buffer * command_buffer, VkQueue queue) {
+ vulkan_command_buffer_end(command_buffer);
+
+ // submit to queue
+ VkSubmitInfo submit_info = { VK_STRUCTURE_TYPE_SUBMIT_INFO };
+ submit_info.commandBufferCount = 1;
+ submit_info.pCommandBuffers = &command_buffer->handle;
+ VK_CHECK(vkQueueSubmit(queue, 1, &submit_info, 0));
+ // wait for it to finish
+ VK_CHECK(vkQueueWaitIdle(queue));
+
+ vulkan_command_buffer_free(context, pool, command_buffer);
+ }
+
+ void vulkan_buffer_copy_to(vulkan_context * context, VkCommandPool pool, VkFence fence,
+ VkQueue queue, VkBuffer source, u64 source_offset, VkBuffer dest,
+ u64 dest_offset, u64 size) {
+ vkQueueWaitIdle(queue);
+
+ vulkan_command_buffer temp_cmd_buf;
+ vulkan_command_buffer_allocate_and_begin_oneshot(context, pool, &temp_cmd_buf);
+
+ VkBufferCopy copy_region;
+ copy_region.srcOffset = source_offset;
+ copy_region.dstOffset = dest_offset;
+ copy_region.size = size;
+
+ vkCmdCopyBuffer(temp_cmd_buf.handle, source, dest, 1, &copy_region);
+
+ vulkan_command_buffer_end_oneshot(context, pool, &temp_cmd_buf, queue);
+ }
+
+ void vulkan_swapchain_create(vulkan_context * context, u32 width, u32 height,
+ vulkan_swapchain * out_swapchain) {
+ VkExtent2D swapchain_extent = { width, height };
+ out_swapchain->max_frames_in_flight = 2; // support triple buffering
+
+ // find a format
+ bool found;
+ for (u32 i = 0; i < context->device.swapchain_support.format_count; i++) {
+ VkSurfaceFormatKHR format = context->device.swapchain_support.formats[i];
+ if (format.format == VK_FORMAT_B8G8R8A8_UNORM &&
+ format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
+ out_swapchain->image_format = format;
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ out_swapchain->image_format = context->device.swapchain_support.formats[0];
+ }
+
+ VkPresentModeKHR present_mode = VK_PRESENT_MODE_FIFO_KHR; // guaranteed to be implemented
+ // TODO: look for mailbox - https://youtu.be/jWKVb_QdSNM?si=bHcd3sEf-M0x3QwH&t=1687
+
+ // TODO: requery swapchain support
+
+ u32 image_count = context->device.swapchain_support.capabilities.minImageCount;
+
+ VkSwapchainCreateInfoKHR swapchain_create_info = {
+ VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR
+ };
+ swapchain_create_info.surface = context->surface;
+ swapchain_create_info.minImageCount = image_count;
+ swapchain_create_info.imageFormat = out_swapchain->image_format.format;
+ swapchain_create_info.imageColorSpace = out_swapchain->image_format.colorSpace;
+ DEBUG("Image extent %d %d\n", swapchain_extent.width, swapchain_extent.height);
+ swapchain_create_info.imageExtent = swapchain_extent;
+ swapchain_create_info.imageArrayLayers = 1;
+ swapchain_create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
+ swapchain_create_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
+ swapchain_create_info.queueFamilyIndexCount = 0;
+ swapchain_create_info.pQueueFamilyIndices = 0;
+
+ swapchain_create_info.preTransform =
+ context->device.swapchain_support.capabilities.currentTransform;
+ swapchain_create_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
+ swapchain_create_info.presentMode = present_mode;
+ swapchain_create_info.clipped = VK_TRUE;
+ swapchain_create_info.oldSwapchain = 0;
+
+ TRACE("Create swapchain");
+ VK_CHECK(vkCreateSwapchainKHR(context->device.logical_device, &swapchain_create_info,
+ context->allocator, &out_swapchain->handle));
+
+ context->current_frame = 0;
+
+ // images
+ out_swapchain->image_count = 0;
+ vkGetSwapchainImagesKHR(context->device.logical_device, out_swapchain->handle,
+ &out_swapchain->image_count, 0);
+
+ if (!out_swapchain->images) {
+ out_swapchain->images = (VkImage*)malloc(sizeof(VkImage) * out_swapchain->image_count);
+ }
+ if (!out_swapchain->views) {
+ out_swapchain->views = (VkImageView*)malloc(sizeof(VkImage) * out_swapchain->image_count);
+ }
+ VK_CHECK(vkGetSwapchainImagesKHR(context->device.logical_device, out_swapchain->handle,
+ &out_swapchain->image_count, out_swapchain->images));
+
+ // views
+ for (int i = 0; i < out_swapchain->image_count; i++) {
+ VkImageViewCreateInfo view_info = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };
+ view_info.image = out_swapchain->images[i];
+ view_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
+ view_info.format = out_swapchain->image_format.format;
+ view_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+ view_info.subresourceRange.baseMipLevel = 0;
+ view_info.subresourceRange.levelCount = 1;
+ view_info.subresourceRange.baseArrayLayer = 0;
+ view_info.subresourceRange.layerCount = 1;
+
+ VK_CHECK(vkCreateImageView(context->device.logical_device, &view_info, context->allocator,
+ &out_swapchain->views[i]));
+ }
+
+ // depth attachment
+ if (!vulkan_device_detect_depth_format(&context->device)) {
+ ERROR_EXIT("Failed to find a supported depth format");
+ }
+ vulkan_image_create(context, VK_IMAGE_TYPE_2D, swapchain_extent.width, swapchain_extent.height,
+ context->device.depth_format, VK_IMAGE_TILING_OPTIMAL,
+ VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
+ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, true, VK_IMAGE_ASPECT_DEPTH_BIT,
+ &out_swapchain->depth_attachment);
+ INFO("Depth attachment created");
+
+ INFO("Swapchain created successfully");
+ }
+
+ // TODO: swapchain destroy
+ void vulkan_swapchain_recreate(vulkan_context * context, u32 width, u32 height,
+ vulkan_swapchain * swapchain) {
+ // TODO
+ }
+ bool vulkan_swapchain_acquire_next_image_index(
+ vulkan_context * context, vulkan_swapchain * swapchain, u64 timeout_ns,
+ VkSemaphore image_available_semaphore, VkFence fence, u32 * out_image_index) {
+ VkResult result =
+ vkAcquireNextImageKHR(context->device.logical_device, swapchain->handle, timeout_ns,
+ image_available_semaphore, fence, out_image_index);
+
+ if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) {
+ FATAL("Failed to acquire swapchain image");
+ return false;
+ }
+
+ return true;
+ }
+
+ void vulkan_swapchain_present(vulkan_context * context, vulkan_swapchain * swapchain,
+ VkQueue graphics_queue, VkQueue present_queue,
+ VkSemaphore render_complete_semaphore, u32 present_image_index) {
+ // return image to swapchain for presentation
+ VkPresentInfoKHR present_info = { VK_STRUCTURE_TYPE_PRESENT_INFO_KHR };
+ present_info.waitSemaphoreCount = 1;
+ present_info.pWaitSemaphores = &render_complete_semaphore;
+ present_info.swapchainCount = 1;
+ present_info.pSwapchains = &swapchain->handle;
+ present_info.pImageIndices = &present_image_index;
+ present_info.pResults = 0;
+
+ VkResult result = vkQueuePresentKHR(present_queue, &present_info);
+ if (result != VK_SUCCESS) {
+ if (result == VK_SUBOPTIMAL_KHR) {
+ // WARN("Swapchain suboptimal - maybe resize needed?");
+ } else {
+ FATAL("Failed to present swapchain iamge");
+ }
+ }
+
+ // advance the current frame
+ context->current_frame = (context->current_frame + 1) % swapchain->max_frames_in_flight;
+ }
+
+ void vulkan_renderpass_create(vulkan_context * context, vulkan_renderpass * out_renderpass,
+ vec4 render_area, vec4 clear_colour, f32 depth, u32 stencil) {
+ out_renderpass->render_area = render_area;
+ out_renderpass->clear_colour = clear_colour;
+ out_renderpass->depth = depth;
+ out_renderpass->stencil = stencil;
+
+ // main subpass
+ VkSubpassDescription subpass = {};
+ subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
+
+ // attachments
+ u32 attachment_desc_count = 2;
+ VkAttachmentDescription attachment_descriptions[2];
+
+ // Colour attachment
+ VkAttachmentDescription color_attachment;
+ color_attachment.format = context->swapchain.image_format.format;
+ color_attachment.samples = VK_SAMPLE_COUNT_1_BIT;
+ color_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
+ color_attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
+ color_attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+ color_attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
+ color_attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+ color_attachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
+ color_attachment.flags = 0;
+
+ attachment_descriptions[0] = color_attachment;
+
+ VkAttachmentReference color_attachment_reference;
+ color_attachment_reference.attachment = 0;
+ color_attachment_reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+
+ subpass.colorAttachmentCount = 1;
+ subpass.pColorAttachments = &color_attachment_reference;
+
+ // Depth attachment
+ VkAttachmentDescription depth_attachment;
+ depth_attachment.format = context->device.depth_format;
+ depth_attachment.samples = VK_SAMPLE_COUNT_1_BIT;
+ depth_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
+ depth_attachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
+ depth_attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+ depth_attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
+ depth_attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+ depth_attachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
+ depth_attachment.flags = 0;
+
+ attachment_descriptions[1] = depth_attachment;
+
+ VkAttachmentReference depth_attachment_reference;
+ depth_attachment_reference.attachment = 1;
+ depth_attachment_reference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
+
+ subpass.pDepthStencilAttachment = &depth_attachment_reference;
+
+ // TODO: other attachment styles
+
+ subpass.inputAttachmentCount = 0;
+ subpass.pInputAttachments = 0;
+ subpass.pResolveAttachments = 0;
+ subpass.preserveAttachmentCount = 0;
+ subpass.preserveAttachmentCount = 0;
+
+ // renderpass dependencies
+ VkSubpassDependency dependency;
+ dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
+ dependency.dstSubpass = 0;
+ dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
+ dependency.srcAccessMask = 0;
+ dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
+ dependency.dstAccessMask =
+ VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
+ dependency.dependencyFlags = 0;
+
+ VkRenderPassCreateInfo render_pass_create_info = { VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO };
+ render_pass_create_info.attachmentCount = attachment_desc_count;
+ render_pass_create_info.pAttachments = attachment_descriptions;
+ render_pass_create_info.subpassCount = 1;
+ render_pass_create_info.pSubpasses = &subpass;
+ render_pass_create_info.dependencyCount = 1;
+ render_pass_create_info.pDependencies = &dependency;
+ render_pass_create_info.pNext = 0;
+ render_pass_create_info.flags = 0;
+
+ VK_CHECK(vkCreateRenderPass(context->device.logical_device, &render_pass_create_info,
+ context->allocator, &out_renderpass->handle));
+ }
+
+ // TODO: renderpass destroy
+
+ void vulkan_renderpass_begin(vulkan_command_buffer * command_buffer,
+ vulkan_renderpass * renderpass, VkFramebuffer framebuffer) {
+ VkRenderPassBeginInfo begin_info = { VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO };
+ begin_info.renderPass = renderpass->handle;
+ begin_info.framebuffer = framebuffer;
+ begin_info.renderArea.offset.x = renderpass->render_area.x;
+ begin_info.renderArea.offset.y = renderpass->render_area.y;
+ begin_info.renderArea.extent.width = renderpass->render_area.z;
+ begin_info.renderArea.extent.height = renderpass->render_area.w;
+
+ VkClearValue clear_values[2];
+ memset(&clear_values, 0, sizeof(VkClearValue) * 2);
+ clear_values[0].color.float32[0] = renderpass->clear_colour.x;
+ clear_values[0].color.float32[1] = renderpass->clear_colour.y;
+ clear_values[0].color.float32[2] = renderpass->clear_colour.z;
+ clear_values[0].color.float32[3] = renderpass->clear_colour.w;
+ clear_values[1].depthStencil.depth = renderpass->depth;
+ clear_values[1].depthStencil.stencil = renderpass->stencil;
+
+ begin_info.clearValueCount = 2;
+ begin_info.pClearValues = clear_values;
+
+ vkCmdBeginRenderPass(command_buffer->handle, &begin_info, VK_SUBPASS_CONTENTS_INLINE);
+ command_buffer->state = COMMAND_BUFFER_STATE_IN_RENDER_PASS;
+ }
+
+ void vulkan_renderpass_end(vulkan_command_buffer * command_buffer,
+ vulkan_renderpass * renderpass) {
+ vkCmdEndRenderPass(command_buffer->handle);
+ command_buffer->state = COMMAND_BUFFER_STATE_RECORDING;
+ }
+
+ bool create_buffers(vulkan_context * context) {
+ VkMemoryPropertyFlagBits mem_prop_flags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
+
+ const u64 vertex_buffer_size = sizeof(vertex_pos) * 1024 * 1024;
+ if (!vulkan_buffer_create(context, vertex_buffer_size,
+ VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT |
+ VK_BUFFER_USAGE_TRANSFER_DST_BIT,
+ mem_prop_flags, true, &context->object_vertex_buffer)) {
+ ERROR("couldnt create vertex buffer");
+ return false;
+ }
+
+ context->geometry_vertex_offset = 0;
+
+ const u64 index1_buffer_size = sizeof(u32) * 1024 * 1024;
+ if (!vulkan_buffer_create(context, index1_buffer_size,
+ VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT |
+ VK_BUFFER_USAGE_TRANSFER_DST_BIT,
+ mem_prop_flags, true, &context->object_index_buffer)) {
+ ERROR("couldnt create vertex buffer");
+ return false;
+ }
+ context->geometry_index_offset = 0;
+
+ return true;
+ }
+
+ void create_command_buffers(renderer * ren) {
+ if (!context.gfx_command_buffers) {
+ context.gfx_command_buffers = vulkan_command_buffer_darray_new(context.swapchain.image_count);
+ }
+
+ for (u32 i = 0; i < context.swapchain.image_count; i++) {
+ vulkan_command_buffer_allocate(&context, context.device.gfx_command_pool, true,
+ &context.gfx_command_buffers->data[i]);
+ }
+ }
+
+ void upload_data_range(vulkan_context * context, VkCommandPool pool, VkFence fence, VkQueue queue,
+ vulkan_buffer * buffer, u64 offset, u64 size, void* data) {
+ VkBufferUsageFlags flags =
+ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
+ vulkan_buffer staging;
+ vulkan_buffer_create(context, size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, flags, true, &staging);
+ // load data into staging buffer
+ printf("Size: %ld\n", size);
+ vulkan_buffer_load_data(context, &staging, 0, size, 0, data);
+
+ // copy
+ vulkan_buffer_copy_to(context, pool, fence, queue, staging.handle, 0, buffer->handle, offset,
+ size);
+
+ vkDestroyBuffer(context->device.logical_device, staging.handle, context->allocator);
+ }
+
+ void regenerate_framebuffers(renderer * ren, vulkan_swapchain * swapchain,
+ vulkan_renderpass * renderpass) {
+ for (u32 i = 0; i < swapchain->image_count; i++) {
+ u32 attachment_count = 2; // one for depth, one for colour
+
+ VkImageView attachments[2] = { swapchain->views[i], swapchain->depth_attachment.view };
+
+ vulkan_framebuffer_create(&context, renderpass, context.framebuffer_width,
+ context.framebuffer_height, 2, attachments,
+ &swapchain->framebuffers->data[i]);
+ }
+ }
+
+ void vulkan_fence_create(vulkan_context * context, bool create_signaled,
+ vulkan_fence* out_fence) {
+ out_fence->is_signaled = create_signaled;
+ VkFenceCreateInfo fence_create_info = { VK_STRUCTURE_TYPE_FENCE_CREATE_INFO };
+ if (out_fence->is_signaled) {
+ fence_create_info.flags = VK_FENCE_CREATE_SIGNALED_BIT;
+ }
+
+ vkCreateFence(context->device.logical_device, &fence_create_info, context->allocator,
+ &out_fence->handle);
+ }
+
+ // TODO: vulkan_fence_destroy
+
+ bool vulkan_fence_wait(vulkan_context * context, vulkan_fence * fence, u64 timeout_ns) {
+ if (!fence->is_signaled) {
+ VkResult result =
+ vkWaitForFences(context->device.logical_device, 1, &fence->handle, true, timeout_ns);
+ switch (result) {
+ case VK_SUCCESS:
+ fence->is_signaled = true;
+ return true;
+ case VK_TIMEOUT:
+ WARN("vk_fence_wait - Timed out");
+ break;
+ default:
+ ERROR("vk_fence_wait - Unhanlded error type");
+ break;
+ }
+ } else {
+ return true;
+ }
+
+ return false;
+ }
+ void vulkan_fence_reset(vulkan_context * context, vulkan_fence * fence) {
+ if (fence->is_signaled) {
+ vkResetFences(context->device.logical_device, 1, &fence->handle);
+ fence->is_signaled = false;
+ }
+ }
+
+ bool gfx_backend_init(renderer * ren) {
+ INFO("loading Vulkan backend");
+
+ vulkan_state* internal = malloc(sizeof(vulkan_state));
+ ren->backend_state = (void*)internal;
+
+ context.allocator = 0; // TODO: custom allocator
+
+ context.framebuffer_width = SCR_WIDTH;
+ context.framebuffer_height = SCR_HEIGHT;
+
+ // Setup Vulkan instance
+ VkApplicationInfo app_info = { VK_STRUCTURE_TYPE_APPLICATION_INFO };
+ app_info.apiVersion = VK_API_VERSION_1_3;
+ app_info.pApplicationName = ren->config.window_name;
+ app_info.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
+ app_info.pEngineName = "Celeritas Engine";
+ app_info.engineVersion = VK_MAKE_VERSION(1, 0, 0);
+
+ VkInstanceCreateInfo create_info = { VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO };
+ create_info.pApplicationInfo = &app_info;
+
+ cstr_darray* required_extensions = cstr_darray_new(2);
+ cstr_darray_push(required_extensions, VK_KHR_SURFACE_EXTENSION_NAME);
+
+ plat_get_required_extension_names(required_extensions);
+
+#if defined(CDEBUG)
+ cstr_darray_push(required_extensions, VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
+
+ DEBUG("Required extensions:");
+ for (u32 i = 0; i < cstr_darray_len(required_extensions); i++) {
+ DEBUG(" %s", required_extensions->data[i]);
+ }
+#endif
+
+ create_info.enabledExtensionCount = cstr_darray_len(required_extensions);
+ create_info.ppEnabledExtensionNames = required_extensions->data;
+
+ // Validation layers
+ create_info.enabledLayerCount = 0;
+ create_info.ppEnabledLayerNames = 0;
+#if defined(CDEBUG)
+ INFO("Validation layers enabled");
+ cstr_darray* desired_validation_layers = cstr_darray_new(1);
+ cstr_darray_push(desired_validation_layers, "VK_LAYER_KHRONOS_validation");
+
+ u32 n_available_layers = 0;
+ VK_CHECK(vkEnumerateInstanceLayerProperties(&n_available_layers, 0));
+ TRACE("%d available layers", n_available_layers);
+ VkLayerProperties_darray* available_layers = VkLayerProperties_darray_new(n_available_layers);
+ VK_CHECK(vkEnumerateInstanceLayerProperties(&n_available_layers, available_layers->data));
+
+ for (int i = 0; i < cstr_darray_len(desired_validation_layers); i++) {
+ // look through layers to make sure we can find the ones we want
+ bool found = false;
+ for (int j = 0; j < n_available_layers; j++) {
+ if (str8_equals(str8_cstr_view(desired_validation_layers->data[i]),
+ str8_cstr_view(available_layers->data[j].layerName))) {
+ found = true;
+ TRACE("Found layer %s", desired_validation_layers->data[i]);
+ break;
+ }
+ }
+
+ if (!found) {
+ FATAL("Required validation is missing %s", desired_validation_layers->data[i]);
+ return false;
+ }
+ }
+ INFO("All validation layers are present");
+ create_info.enabledLayerCount = cstr_darray_len(desired_validation_layers);
+ create_info.ppEnabledLayerNames = desired_validation_layers->data;
+#endif
+
+ VkResult result = vkCreateInstance(&create_info, NULL, &context.instance);
+ if (result != VK_SUCCESS) {
+ ERROR("vkCreateInstance failed with result: %u", result);
+ return false;
+ }
+
+ // Debugger
+#if defined(CDEBUG)
+ DEBUG("Creating Vulkan debugger")
+ u32 log_severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT |
+ VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT;
+ VkDebugUtilsMessengerCreateInfoEXT debug_create_info = {
+ VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT
+ };
+ debug_create_info.messageSeverity = log_severity;
+ debug_create_info.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
+ VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT |
+ VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT;
+ debug_create_info.pfnUserCallback = vk_debug_callback;
+
+ PFN_vkCreateDebugUtilsMessengerEXT func =
+ (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(context.instance,
+ "vkCreateDebugUtilsMessengerEXT");
+ assert(func);
+ VK_CHECK(func(context.instance, &debug_create_info, context.allocator, &context.vk_debugger));
+ DEBUG("Vulkan debugger created");
+
+#endif
+
+ // Surface creation
+ DEBUG("Create SurfaceKHR")
+ VkSurfaceKHR surface;
+ VK_CHECK(glfwCreateWindowSurface(context.instance, ren->window, NULL, &surface));
+ context.surface = surface;
+ DEBUG("Vulkan surface created")
+
+ // Device creation
+ if (!vulkan_device_create(&context)) {
+ FATAL("device creation failed");
+ return false;
+ }
+
+ // Swapchain creation
+ vulkan_swapchain_create(&context, SCR_WIDTH, SCR_HEIGHT, &context.swapchain);
+
+ // Renderpass creation
+ vulkan_renderpass_create(&context, &context.main_renderpass,
+ vec4(0, 0, context.framebuffer_width, context.framebuffer_height),
+ rgba_to_vec4(COLOUR_SEA_GREEN), 1.0, 0);
+
+ // Framebiffers creation
+ context.swapchain.framebuffers = vulkan_framebuffer_darray_new(context.swapchain.image_count);
+ regenerate_framebuffers(ren, &context.swapchain, &context.main_renderpass);
+ INFO("Framebuffers created");
+
+ // Command buffers creation
+ create_command_buffers(ren);
+ INFO("Command buffers created");
+
+ // Sync objects
+ context.image_available_semaphores =
+ calloc(context.swapchain.max_frames_in_flight, sizeof(VkSemaphore));
+ context.queue_complete_semaphores =
+ calloc(context.swapchain.max_frames_in_flight, sizeof(VkSemaphore));
+ context.in_flight_fences = calloc(context.swapchain.max_frames_in_flight, sizeof(vulkan_fence));
+
+ for (u8 i = 0; i < context.swapchain.max_frames_in_flight; i++) {
+ VkSemaphoreCreateInfo semaphore_create_info = { VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO };
+ vkCreateSemaphore(context.device.logical_device, &semaphore_create_info, context.allocator,
+ &context.image_available_semaphores[i]);
+ vkCreateSemaphore(context.device.logical_device, &semaphore_create_info, context.allocator,
+ &context.queue_complete_semaphores[i]);
+
+ // create the fence in a signaled state
+ vulkan_fence_create(&context, true, &context.in_flight_fences[i]);
+ }
+
+ context.images_in_flight =
+ malloc(sizeof(vulkan_fence*) * context.swapchain.max_frames_in_flight);
+ for (u8 i = 0; i < context.swapchain.max_frames_in_flight; i++) {
+ context.images_in_flight[i] = 0;
+ }
+ INFO("Sync objects created");
+
+ // Shader modules
+ vulkan_object_shader_create(&context, &context.object_shader);
+ INFO("Compiled shader modules")
+
+ create_buffers(&context);
+ INFO("Created buffers");
+
+ // TODO: temporary test code
+
+ mesh cube = prim_cube_mesh_create();
+
+ vertex* verts = malloc(sizeof(vertex) * cube.vertices->len);
+
+ f32 scale = 3.0;
+ for (size_t i = 0; i < cube.vertices->len; i++) {
+ verts[i].position = vec3_mult(cube.vertices->data[i].position, scale);
+ verts[i].normal = cube.vertices->data[i].normal;
+ verts[i].uv = cube.vertices->data[i].uv;
+ }
+
+ // const f32 s = 1.0;
+ // const u32 vert_count = 4;
+ // vertex_pos verts[4] = { 0 };
+
+ // verts[0].pos.x = -0.5 * s;
+ // verts[0].pos.y = -0.5 * s;
+
+ // verts[1].pos.x = 0.5 * s;
+ // verts[1].pos.y = 0.5 * s;
+
+ // verts[2].pos.x = -0.5 * s;
+ // verts[2].pos.y = 0.5 * s;
+
+ // verts[3].pos.x = 0.5 * s;
+ // verts[3].pos.y = -0.5 * s;
+
+ // const u32 index_count = 6;
+ // u32 indices[6] = { 0, 1, 2, 0, 3, 1 };
+
+ upload_data_range(&context, context.device.gfx_command_pool, 0, context.device.graphics_queue,
+ &context.object_vertex_buffer, 0, sizeof(vertex) * cube.vertices->len, verts);
+ TRACE("Uploaded vertex data");
+ upload_data_range(&context, context.device.gfx_command_pool, 0, context.device.graphics_queue,
+ &context.object_index_buffer, 0, sizeof(u32) * cube.indices_len,
+ cube.indices);
+ TRACE("Uploaded index data");
+ vertex_darray_free(cube.vertices);
+ free(cube.indices);
+
+ // upload texture
+
+ // --- End test code
+
+ INFO("Vulkan renderer initialisation succeeded");
+ return true;
+ }
+
+ void gfx_backend_shutdown(renderer * ren) {
+ DEBUG("Destroying Vulkan debugger");
+ if (context.vk_debugger) {
+ PFN_vkDestroyDebugUtilsMessengerEXT func =
+ (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr(
+ context.instance, "vkDestroyDebugUtilsMessengerEXT");
+ func(context.instance, context.vk_debugger, context.allocator);
+ }
+
+ DEBUG("Destroying Vulkan instance...");
+ vkDestroyInstance(context.instance, context.allocator);
+ }
+
+ void backend_begin_frame(renderer * ren, f32 delta_time) {
+ vulkan_device* device = &context.device;
+
+ // TODO: resize gubbins
+
+ if (!vulkan_fence_wait(&context, &context.in_flight_fences[context.current_frame],
+ UINT64_MAX)) {
+ WARN("In-flight fence wait failure");
+ }
+
+ if (!vulkan_swapchain_acquire_next_image_index(
+ &context, &context.swapchain, UINT64_MAX,
+ context.image_available_semaphores[context.current_frame], 0, &context.image_index)) {
+ WARN("couldnt acquire swapchain next image");
+ }
+
+ vulkan_command_buffer* command_buffer = &context.gfx_command_buffers->data[context.image_index];
+ vulkan_command_buffer_reset(command_buffer);
+ vulkan_command_buffer_begin(command_buffer, false, false, false);
+
+ VkViewport viewport;
+ viewport.x = 0.0;
+ viewport.y = 0;
+ viewport.width = (f32)context.framebuffer_width;
+ viewport.height = (f32)context.framebuffer_height;
+ viewport.minDepth = 0.0;
+ viewport.maxDepth = 1.0;
+
+ VkRect2D scissor;
+ scissor.offset.x = scissor.offset.y = 0;
+ scissor.extent.width = context.framebuffer_width;
+ scissor.extent.height = context.framebuffer_height;
+
+ vkCmdSetViewport(command_buffer->handle, 0, 1, &viewport);
+ vkCmdSetScissor(command_buffer->handle, 0, 1, &scissor);
+
+ context.main_renderpass.render_area.z = context.framebuffer_width;
+ context.main_renderpass.render_area.w = context.framebuffer_height;
+
+ vulkan_renderpass_begin(command_buffer, &context.main_renderpass,
+ context.swapchain.framebuffers->data[context.image_index].handle);
+ }
+
+ void texture_data_upload(texture * tex) {
+ printf("Texture name %s\n", tex->name);
+ tex->backend_data = malloc(sizeof(vulkan_texture_data));
+ vulkan_texture_data* data = (vulkan_texture_data*)tex->backend_data;
+ printf("Texture (%s) details: \n width %d\n height %d\n channel count %d\n", tex->name,
+ tex->width, tex->height, tex->channel_count);
+ VkDeviceSize image_size = tex->width * tex->height * max(tex->channel_count, 4);
+
+ TRACE("Creating buffer of size %ld", image_size);
+
+ VkFormat image_format = VK_FORMAT_R8G8B8A8_SRGB;
+
+ VkBufferUsageFlags usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
+ VkMemoryPropertyFlags memory_prop_flags =
+ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
+ vulkan_buffer staging;
+ vulkan_buffer_create(&context, image_size, usage, memory_prop_flags, true, &staging);
+ DEBUG("Uploading image data");
+ vulkan_buffer_load_data(&context, &staging, 0, image_size, 0, tex->image_data);
+ INFO("Loaded iamge data!");
+
+ vulkan_image_create(
+ &context, VK_IMAGE_TYPE_2D, tex->width, tex->height, image_format, VK_IMAGE_TILING_OPTIMAL,
+ VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
+ VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
+ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, true, VK_IMAGE_ASPECT_COLOR_BIT, &data->image);
+
+ vulkan_command_buffer temp_buffer;
+ vulkan_command_buffer_allocate_and_begin_oneshot(&context, context.device.gfx_command_pool,
+ &temp_buffer);
+
+ vulkan_image_transition_layout(&context, &temp_buffer, &data->image, image_format,
+ VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
+
+ vulkan_image_copy_from_buffer(&data->image, staging.handle, &temp_buffer);
+
+ vulkan_image_transition_layout(&context, &temp_buffer, &data->image, image_format,
+ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
+
+ vulkan_command_buffer_end_oneshot(&context, context.device.gfx_command_pool, &temp_buffer,
+ context.device.graphics_queue);
+
+ VkSamplerCreateInfo sampler_info = { VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO };
+ sampler_info.magFilter = VK_FILTER_LINEAR;
+ sampler_info.minFilter = VK_FILTER_LINEAR;
+ sampler_info.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
+ sampler_info.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
+ sampler_info.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
+ sampler_info.anisotropyEnable = VK_TRUE;
+ sampler_info.maxAnisotropy = 16;
+ sampler_info.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK;
+ sampler_info.unnormalizedCoordinates = VK_FALSE;
+ sampler_info.compareEnable = VK_FALSE;
+ sampler_info.compareOp = VK_COMPARE_OP_ALWAYS;
+ sampler_info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
+ sampler_info.mipLodBias = 0.0;
+ sampler_info.minLod = 0.0;
+ sampler_info.maxLod = 0.0;
+
+ VkResult res = vkCreateSampler(context.device.logical_device, &sampler_info, context.allocator,
+ &data->sampler);
+ if (res != VK_SUCCESS) {
+ ERROR("Error creating texture sampler for image %s", tex->name);
+ return;
+ }
+
+ tex->image_data = (void*)data;
+ }
+
+ // TODO: destroy texture
+
+ void backend_end_frame(renderer * ren, f32 delta_time) {
+ vulkan_command_buffer* command_buffer = &context.gfx_command_buffers->data[context.image_index];
+
+ vulkan_renderpass_end(command_buffer, &context.main_renderpass);
+
+ vulkan_command_buffer_end(command_buffer);
+
+ // TODO: wait on fence - https://youtu.be/hRL71D1f3pU?si=nLJx-ZsemDBeQiQ1&t=1037
+
+ context.images_in_flight[context.image_index] =
+ &context.in_flight_fences[context.current_frame];
+
+ vulkan_fence_reset(&context, &context.in_flight_fences[context.current_frame]);
+
+ VkSubmitInfo submit_info = { VK_STRUCTURE_TYPE_SUBMIT_INFO };
+ submit_info.commandBufferCount = 1;
+ submit_info.pCommandBuffers = &command_buffer->handle;
+ submit_info.signalSemaphoreCount = 1;
+ submit_info.pSignalSemaphores = &context.queue_complete_semaphores[context.current_frame];
+ submit_info.waitSemaphoreCount = 1;
+ submit_info.pWaitSemaphores = &context.image_available_semaphores[context.current_frame];
+
+ VkPipelineStageFlags flags[1] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
+ submit_info.pWaitDstStageMask = flags;
+
+ VkResult result = vkQueueSubmit(context.device.graphics_queue, 1, &submit_info,
+ context.in_flight_fences[context.current_frame].handle);
+
+ if (result != VK_SUCCESS) {
+ ERROR("queue submission failed. fark.");
+ }
+
+ vulkan_command_buffer_update_submitted(command_buffer);
+
+ vulkan_swapchain_present(
+ &context, &context.swapchain, context.device.graphics_queue, context.device.graphics_queue,
+ context.queue_complete_semaphores[context.current_frame], context.image_index);
+ }
+
+ void gfx_backend_draw_frame(renderer * ren, camera * cam, mat4 model, texture * tex) {
+ backend_begin_frame(ren, 16.0);
+
+ mat4 proj;
+ mat4 view;
+
+ camera_view_projection(cam, SCR_HEIGHT, SCR_WIDTH, &view, &proj);
+
+ context.object_shader.texture_data = (vulkan_texture_data*)tex->image_data;
+ gfx_backend_update_global_state(proj, view, cam->position, vec4(1.0, 1.0, 1.0, 1.0), 0);
+
+ vulkan_object_shader_update_object(&context, &context.object_shader, model);
+
+ backend_end_frame(ren, 16.0);
+ }
+
+ void gfx_backend_update_global_state(mat4 projection, mat4 view, vec3 view_pos,
+ vec4 ambient_colour, i32 mode) {
+ vulkan_object_shader_use(&context, &context.object_shader);
+
+ vulkan_object_shader_update_global_state(&context, &context.object_shader);
+ context.object_shader.global_ubo.projection = projection;
+ context.object_shader.global_ubo.view = view;
+ // TODO: other UBO properties
+ }
+
+ void clear_screen(vec3 colour) {}
+
+ void bind_texture(shader s, texture * tex, u32 slot) {}
+ void bind_mesh_vertex_buffer(void* backend, mesh* mesh) {}
+ void draw_primitives(cel_primitive_topology primitive, u32 start_index, u32 count) {}
+
+ shader shader_create_separate(const char* vert_shader, const char* frag_shader) {}
+ void set_shader(shader s) {}
+
+ void uniform_vec3f(u32 program_id, const char* uniform_name, vec3* value) {}
+ void uniform_f32(u32 program_id, const char* uniform_name, f32 value) {}
+ void uniform_i32(u32 program_id, const char* uniform_name, i32 value) {}
+ void uniform_mat4f(u32 program_id, const char* uniform_name, mat4* value) {}
+
+ VKAPI_ATTR VkBool32 VKAPI_CALL vk_debug_callback(
+ VkDebugUtilsMessageSeverityFlagBitsEXT severity, VkDebugUtilsMessageTypeFlagsEXT flags,
+ const VkDebugUtilsMessengerCallbackDataEXT* callback_data, void* user_data) {
+ switch (severity) {
+ default:
+ case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT:
+ ERROR("%s", callback_data->pMessage);
+ break;
+ case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT:
+ WARN("%s", callback_data->pMessage);
+ break;
+ case VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT:
+ INFO("%s", callback_data->pMessage);
+ break;
+ case VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT:
+ TRACE("%s", callback_data->pMessage);
+ break;
+ }
+ return VK_FALSE;
+ }
+
+#endif \ No newline at end of file
diff --git a/src/renderer/backends/backend_dx11.h b/src/renderer/backends/backend_dx11.h
index 163ca97..e076659 100644
--- a/src/renderer/backends/backend_dx11.h
+++ b/src/renderer/backends/backend_dx11.h
@@ -1,4 +1,7 @@
#pragma once
+#include <d3d11.h>
+#include <d3dcompiler.h>
+
#include "ral.h"
#define GPU_SWAPCHAIN_IMG_COUNT 2
@@ -6,6 +9,7 @@
typedef struct gpu_swapchain {
} gpu_swapchain;
typedef struct gpu_device {
+
// VkPhysicalDevice physical_device;
// VkDevice logical_device;
// VkPhysicalDeviceProperties properties;
diff --git a/src/renderer/backends/backend_vulkan.c b/src/renderer/backends/backend_vulkan.c
index 75b0439..b66aeca 100644
--- a/src/renderer/backends/backend_vulkan.c
+++ b/src/renderer/backends/backend_vulkan.c
@@ -1,841 +1,44 @@
-#include "camera.h"
-#include "primitives.h"
-#define CDEBUG
-// #define CEL_PLATFORM_LINUX
-#if CEL_REND_BACKEND_VULKAN
-// ^ Temporary
-
-#include <assert.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <string.h>
#include <vulkan/vk_platform.h>
#include <vulkan/vulkan.h>
#include <vulkan/vulkan_core.h>
-#include "colours.h"
-#include "str.h"
-#include "darray.h"
+#include "backend_vulkan.h"
+
#include "defines.h"
-#include "file.h"
#include "log.h"
-#include "maths.h"
-#include "maths_types.h"
-#include "render_backend.h"
-#include "render_types.h"
-#include "vulkan_helpers.h"
-
-#include <stdlib.h>
-
-#define SCR_WIDTH 1000
-#define SCR_HEIGHT 1000
-
-#include <glad/glad.h>
-
-#include <glfw3.h>
-
-KITC_DECL_TYPED_ARRAY(VkLayerProperties)
-
-typedef struct vulkan_device {
- VkPhysicalDevice physical_device;
- VkDevice logical_device;
- vulkan_swapchain_support_info swapchain_support;
- i32 graphics_queue_index;
- i32 present_queue_index;
- i32 compute_queue_index;
- i32 transfer_queue_index;
- VkQueue graphics_queue;
- VkQueue present_queue;
- VkQueue compute_queue;
- VkQueue transfer_queue;
- VkCommandPool gfx_command_pool;
- VkPhysicalDeviceProperties properties;
- VkPhysicalDeviceFeatures features;
- VkPhysicalDeviceMemoryProperties memory;
- VkFormat depth_format;
-} vulkan_device;
-
-typedef struct vulkan_image {
- VkImage handle;
- VkDeviceMemory memory;
- VkImageView view;
- u32 width;
- u32 height;
-} vulkan_image;
-
-typedef struct vulkan_texture_data {
- vulkan_image image;
- VkSampler sampler;
-} vulkan_texture_data;
-
-typedef enum vulkan_renderpass_state {
- READY,
- RECORDING,
- IN_RENDER_PASS,
- RECORDING_ENDING,
- SUBMITTED,
- NOT_ALLOCATED
-} vulkan_renderpass_state;
-
-typedef struct vulkan_renderpass {
- VkRenderPass handle;
- vec4 render_area;
- vec4 clear_colour;
- f32 depth;
- u32 stencil;
- vulkan_renderpass_state state;
-} vulkan_renderpass;
-
-typedef struct vulkan_framebuffer {
- VkFramebuffer handle;
- u32 attachment_count;
- VkImageView* attachments;
- vulkan_renderpass* renderpass;
-} vulkan_framebuffer;
-
-KITC_DECL_TYPED_ARRAY(vulkan_framebuffer)
-
-typedef struct vulkan_swapchain {
- VkSurfaceFormatKHR image_format;
- u8 max_frames_in_flight;
- VkSwapchainKHR handle;
- u32 image_count;
- VkImage* images;
- VkImageView* views;
- vulkan_image depth_attachment;
- vulkan_framebuffer_darray* framebuffers;
-} vulkan_swapchain;
-
-// overengineered
-typedef enum vulkan_command_buffer_state {
- COMMAND_BUFFER_STATE_READY,
- COMMAND_BUFFER_STATE_IN_RENDER_PASS,
- COMMAND_BUFFER_STATE_RECORDING,
- COMMAND_BUFFER_STATE_RECORDING_ENDED,
- COMMAND_BUFFER_STATE_SUBMITTED,
- COMMAND_BUFFER_STATE_NOT_ALLOCATED,
-} vulkan_command_buffer_state;
-
-typedef struct vulkan_command_buffer {
- VkCommandBuffer handle;
- vulkan_command_buffer_state state;
-} vulkan_command_buffer;
-
-KITC_DECL_TYPED_ARRAY(vulkan_command_buffer)
-
-typedef struct vulkan_fence {
- VkFence handle;
- bool is_signaled;
-} vulkan_fence;
-
-typedef struct vulkan_shader_stage {
- VkShaderModuleCreateInfo create_info;
- VkShaderModule handle;
- VkPipelineShaderStageCreateInfo stage_create_info;
-} vulkan_shader_stage;
-
-typedef struct vulkan_pipeline {
- VkPipeline handle;
- VkPipelineLayout layout;
-} vulkan_pipeline;
-
-typedef struct global_object_uniform {
- mat4 projection; // 64 bytes
- mat4 view; // 64 bytes
- f32 padding[32];
-} global_object_uniform;
-
-typedef struct object_uniform {
- vec4 diffuse_colour;
- vec4 v_reserved0;
- vec4 v_reserved1;
- vec4 v_reserved2;
-} object_uniform;
-
-#define MAX_OBJECT_COUNT 1024
-#define VULKAN_OBJECT_SHADER_DESCRIPTOR_COUNT 1
-
-typedef struct geometry_render_data {
- u32 id;
- mat4 model;
- texture* textures[16];
-} geometry_render_data;
-
-typedef struct vulkan_buffer {
- u64 total_size;
- VkBuffer handle;
- VkBufferUsageFlagBits usage;
- bool is_locked;
- VkDeviceMemory memory;
- i32 memory_index;
- u32 memory_property_flags;
-} vulkan_buffer;
+#include "ral.h"
+#include "ral_types.h"
-#define SHADER_STAGE_COUNT 2
-
-typedef struct vulkan_shader {
- // vertex, fragment
- vulkan_shader_stage stages[SHADER_STAGE_COUNT];
- vulkan_pipeline pipeline;
-
- // descriptors
- VkDescriptorPool descriptor_pool;
- VkDescriptorSetLayout descriptor_set_layout;
- VkDescriptorSet descriptor_sets[3]; // one for each in-flight frame
-
- vulkan_buffer global_uniforms_buffer;
-
- // Data that's global for all objects drawn
- global_object_uniform global_ubo;
- object_uniform object_ubo;
- vulkan_texture_data* texture_data;
-} vulkan_shader;
+#define VULKAN_QUEUES_COUNT 2
+const char* queue_names[VULKAN_QUEUES_COUNT] = { "GRAPHICS", "TRANSFER" };
typedef struct vulkan_context {
- VkInstance instance;
+ gpu_device device;
VkAllocationCallbacks* allocator;
- VkSurfaceKHR surface;
- vulkan_device device;
- u32 framebuffer_width;
- u32 framebuffer_height;
- vulkan_swapchain swapchain;
- vulkan_renderpass main_renderpass;
- vulkan_buffer object_vertex_buffer;
- vulkan_buffer object_index_buffer;
- u64 geometry_vertex_offset;
- u64 geometry_index_offset;
-
- vulkan_command_buffer_darray* gfx_command_buffers;
- VkSemaphore* image_available_semaphores;
- VkSemaphore* queue_complete_semaphores;
- u32 in_flight_fence_count;
- vulkan_fence* in_flight_fences;
- vulkan_fence** images_in_flight;
-
- u32 image_index;
- u32 current_frame;
-
- vulkan_shader object_shader;
-
- // TODO: swapchain recreation
+ VkInstance instance;
-#if defined(DEBUG)
- VkDebugUtilsMessengerEXT vk_debugger;
-#endif
} vulkan_context;
static vulkan_context context;
-static i32 find_memory_index(vulkan_context* context, u32 type_filter, u32 property_flags) {
- VkPhysicalDeviceMemoryProperties memory_properties;
- vkGetPhysicalDeviceMemoryProperties(context->device.physical_device, &memory_properties);
-
- for (u32 i = 0; i < memory_properties.memoryTypeCount; ++i) {
- // Check each memory type to see if its bit is set to 1.
- if (type_filter & (1 << i) &&
- (memory_properties.memoryTypes[i].propertyFlags & property_flags) == property_flags) {
- return i;
- }
- }
-
- WARN("Unable to find suitable memory type!");
- return -1;
-}
-
-/** @brief Internal backend state */
-typedef struct vulkan_state {
-} vulkan_state;
-
-typedef struct vertex_pos {
- vec3 pos;
- vec3 normal;
-} vertex_pos;
-
-// pipeline stuff
-bool vulkan_graphics_pipeline_create(vulkan_context* context, vulkan_renderpass* renderpass,
- u32 attribute_count,
- VkVertexInputAttributeDescription* attributes,
- u32 descriptor_set_layout_count,
- VkDescriptorSetLayout* descriptor_set_layouts, u32 stage_count,
- VkPipelineShaderStageCreateInfo* stages, VkViewport viewport,
- VkRect2D scissor, bool is_wireframe,
- vulkan_pipeline* out_pipeline) {
- VkPipelineViewportStateCreateInfo viewport_state = {
- VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO
- };
- viewport_state.viewportCount = 1;
- viewport_state.pViewports = &viewport;
- viewport_state.scissorCount = 1;
- viewport_state.pScissors = &scissor;
-
- // Rasterizer
- VkPipelineRasterizationStateCreateInfo rasterizer_create_info = {
- VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO
- };
- rasterizer_create_info.depthClampEnable = VK_FALSE;
- rasterizer_create_info.rasterizerDiscardEnable = VK_FALSE;
- rasterizer_create_info.polygonMode = is_wireframe ? VK_POLYGON_MODE_LINE : VK_POLYGON_MODE_FILL;
- rasterizer_create_info.lineWidth = 1.0f;
- rasterizer_create_info.cullMode = VK_CULL_MODE_BACK_BIT;
- rasterizer_create_info.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
- rasterizer_create_info.depthBiasEnable = VK_FALSE;
- rasterizer_create_info.depthBiasConstantFactor = 0.0;
- rasterizer_create_info.depthBiasClamp = 0.0;
- rasterizer_create_info.depthBiasSlopeFactor = 0.0;
-
- // Multisampling
- VkPipelineMultisampleStateCreateInfo ms_create_info = {
- VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO
- };
- ms_create_info.sampleShadingEnable = VK_FALSE;
- ms_create_info.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
- ms_create_info.minSampleShading = 1.0;
- ms_create_info.pSampleMask = 0;
- ms_create_info.alphaToCoverageEnable = VK_FALSE;
- ms_create_info.alphaToOneEnable = VK_FALSE;
-
- // Depth and stencil testing
- VkPipelineDepthStencilStateCreateInfo depth_stencil = {
- VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO
- };
- depth_stencil.depthTestEnable = VK_TRUE;
- depth_stencil.depthWriteEnable = VK_TRUE;
- depth_stencil.depthCompareOp = VK_COMPARE_OP_LESS;
- depth_stencil.depthBoundsTestEnable = VK_FALSE;
- depth_stencil.stencilTestEnable = VK_FALSE;
- depth_stencil.pNext = 0;
-
- VkPipelineColorBlendAttachmentState color_blend_attachment_state;
- color_blend_attachment_state.blendEnable = VK_TRUE;
- color_blend_attachment_state.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
- color_blend_attachment_state.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
- color_blend_attachment_state.colorBlendOp = VK_BLEND_OP_ADD;
- color_blend_attachment_state.srcAlphaBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
- color_blend_attachment_state.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
- color_blend_attachment_state.alphaBlendOp = VK_BLEND_OP_ADD;
- color_blend_attachment_state.colorWriteMask = VK_COLOR_COMPONENT_R_BIT |
- VK_COLOR_COMPONENT_G_BIT |
- VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
-
- VkPipelineColorBlendStateCreateInfo color_blend = {
- VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO
- };
- color_blend.logicOpEnable = VK_FALSE;
- color_blend.logicOp = VK_LOGIC_OP_COPY;
- color_blend.attachmentCount = 1;
- color_blend.pAttachments = &color_blend_attachment_state;
-
- const u32 dynamic_state_count = 3;
- VkDynamicState dynamic_states[3] = {
- VK_DYNAMIC_STATE_VIEWPORT,
- VK_DYNAMIC_STATE_SCISSOR,
- VK_DYNAMIC_STATE_LINE_WIDTH,
- };
-
- VkPipelineDynamicStateCreateInfo dynamic_state = {
- VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO
- };
- dynamic_state.dynamicStateCount = dynamic_state_count;
- dynamic_state.pDynamicStates = dynamic_states;
-
- // Vertex input
- VkVertexInputBindingDescription binding_desc;
- binding_desc.binding = 0;
- binding_desc.stride = sizeof(vertex);
- binding_desc.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
-
- VkPipelineVertexInputStateCreateInfo vertex_input_info = {
- VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO
- };
- vertex_input_info.vertexBindingDescriptionCount = 1;
- vertex_input_info.pVertexBindingDescriptions = &binding_desc;
- vertex_input_info.vertexAttributeDescriptionCount = attribute_count;
- vertex_input_info.pVertexAttributeDescriptions = attributes;
-
- VkPipelineInputAssemblyStateCreateInfo input_assembly = {
- VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO
- };
- input_assembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
- input_assembly.primitiveRestartEnable = VK_FALSE;
-
- VkPipelineLayoutCreateInfo pipeline_layout_create_info = {
- VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO
- };
-
- // Pushconstants
- VkPushConstantRange push_constant;
- push_constant.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
- push_constant.offset = sizeof(mat4) * 0;
- push_constant.size = sizeof(mat4) * 2;
-
- pipeline_layout_create_info.pushConstantRangeCount = 1;
- pipeline_layout_create_info.pPushConstantRanges = &push_constant;
-
- pipeline_layout_create_info.setLayoutCount = descriptor_set_layout_count;
- pipeline_layout_create_info.pSetLayouts = descriptor_set_layouts;
-
- vkCreatePipelineLayout(context->device.logical_device, &pipeline_layout_create_info,
- context->allocator, &out_pipeline->layout);
-
- VkGraphicsPipelineCreateInfo pipeline_create_info = {
- VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO
- };
- pipeline_create_info.stageCount = stage_count;
- pipeline_create_info.pStages = stages;
- pipeline_create_info.pVertexInputState = &vertex_input_info;
- pipeline_create_info.pInputAssemblyState = &input_assembly;
-
- pipeline_create_info.pViewportState = &viewport_state;
- pipeline_create_info.pRasterizationState = &rasterizer_create_info;
- pipeline_create_info.pMultisampleState = &ms_create_info;
- pipeline_create_info.pDepthStencilState = &depth_stencil;
- pipeline_create_info.pColorBlendState = &color_blend;
- pipeline_create_info.pDynamicState = &dynamic_state;
- pipeline_create_info.pTessellationState = 0;
-
- pipeline_create_info.layout = out_pipeline->layout;
-
- pipeline_create_info.renderPass = renderpass->handle;
- pipeline_create_info.subpass = 0;
- pipeline_create_info.basePipelineHandle = VK_NULL_HANDLE;
- pipeline_create_info.basePipelineIndex = -1;
-
- VkResult result =
- vkCreateGraphicsPipelines(context->device.logical_device, VK_NULL_HANDLE, 1,
- &pipeline_create_info, context->allocator, &out_pipeline->handle);
- if (result != VK_SUCCESS) {
- FATAL("graphics pipeline creation failed. its fked mate");
- ERROR_EXIT("Doomed");
- }
-
- return true;
-}
-
-void vulkan_pipeline_bind(vulkan_command_buffer* command_buffer, VkPipelineBindPoint bind_point,
- vulkan_pipeline* pipeline) {
- vkCmdBindPipeline(command_buffer->handle, bind_point, pipeline->handle);
-}
-
-void vulkan_buffer_bind(vulkan_context* context, vulkan_buffer* buffer, u64 offset) {
- vkBindBufferMemory(context->device.logical_device, buffer->handle, buffer->memory, offset);
-}
-
-bool vulkan_buffer_create(vulkan_context* context, u64 size, VkBufferUsageFlagBits usage,
- u32 memory_property_flags, bool bind_on_create,
- vulkan_buffer* out_buffer) {
- memset(out_buffer, 0, sizeof(vulkan_buffer));
- out_buffer->total_size = size;
- out_buffer->usage = usage;
- out_buffer->memory_property_flags = memory_property_flags;
-
- VkBufferCreateInfo buffer_info = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
- buffer_info.size = size;
- buffer_info.usage = usage;
- buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
-
- vkCreateBuffer(context->device.logical_device, &buffer_info, context->allocator,
- &out_buffer->handle);
-
- VkMemoryRequirements requirements;
- vkGetBufferMemoryRequirements(context->device.logical_device, out_buffer->handle, &requirements);
- out_buffer->memory_index =
- find_memory_index(context, requirements.memoryTypeBits, out_buffer->memory_property_flags);
-
- // Allocate
- VkMemoryAllocateInfo allocate_info = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
- allocate_info.allocationSize = requirements.size;
- allocate_info.memoryTypeIndex = (u32)out_buffer->memory_index;
-
- vkAllocateMemory(context->device.logical_device, &allocate_info, context->allocator,
- &out_buffer->memory);
-
- if (bind_on_create) {
- vulkan_buffer_bind(context, out_buffer, 0);
- }
-
- DEBUG("Created buffer.");
-
- return true;
-}
-
-// lock and unlock?
-
-void* vulkan_buffer_lock_memory(vulkan_context* context, vulkan_buffer* buffer, u64 offset,
- u64 size, u32 flags) {
- void* data;
- vkMapMemory(context->device.logical_device, buffer->memory, offset, size, flags, &data);
- return data;
-}
-void* vulkan_buffer_unlock_memory(vulkan_context* context, vulkan_buffer* buffer) {
- vkUnmapMemory(context->device.logical_device, buffer->memory);
-}
-
-void vulkan_buffer_load_data(vulkan_context* context, vulkan_buffer* buffer, u64 offset, u64 size,
- u32 flags, const void* data) {
- void* data_ptr = 0;
- VK_CHECK(
- vkMapMemory(context->device.logical_device, buffer->memory, offset, size, flags, &data_ptr));
- memcpy(data_ptr, data, size);
- vkUnmapMemory(context->device.logical_device, buffer->memory);
-}
-
-// TODO: destroy
-
-bool create_shader_module(vulkan_context* context, const char* filename, const char* type_str,
- VkShaderStageFlagBits flag, u32 stage_index,
- vulkan_shader_stage* shader_stages) {
- memset(&shader_stages[stage_index].create_info, 0, sizeof(VkShaderModuleCreateInfo));
- memset(&shader_stages[stage_index].stage_create_info, 0, sizeof(VkPipelineShaderStageCreateInfo));
-
- shader_stages[stage_index].create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
-
- // todo: file input
- FileData file_contents = load_spv_file(filename);
-
- shader_stages[stage_index].create_info.codeSize = file_contents.size;
- shader_stages[stage_index].create_info.pCode = (u32*)file_contents.data;
-
- vkCreateShaderModule(context->device.logical_device, &shader_stages[stage_index].create_info,
- context->allocator, &shader_stages[stage_index].handle);
-
- shader_stages[stage_index].stage_create_info.sType =
- VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
- shader_stages[stage_index].stage_create_info.stage = flag;
- shader_stages[stage_index].stage_create_info.module = shader_stages[stage_index].handle;
- shader_stages[stage_index].stage_create_info.pName = "main";
-
- free(file_contents.data);
-
- // TODO: Descriptors
-
- return true;
-}
-
-bool vulkan_object_shader_create(vulkan_context* context, vulkan_shader* out_shader) {
- char stage_type_strs[SHADER_STAGE_COUNT][5] = { "vert", "frag" };
- char stage_filenames[SHADER_STAGE_COUNT][256] = { "build/linux/x86_64/debug/object.vert.spv",
- "build/linux/x86_64/debug/object.frag.spv" };
- VkShaderStageFlagBits stage_types[SHADER_STAGE_COUNT] = { VK_SHADER_STAGE_VERTEX_BIT,
- VK_SHADER_STAGE_FRAGMENT_BIT };
- for (u8 i = 0; i < SHADER_STAGE_COUNT; i++) {
- DEBUG("Loading %s", stage_filenames[i]);
- create_shader_module(context, stage_filenames[i], stage_type_strs[i], stage_types[i], i,
- out_shader->stages);
- }
-
- // descriptors
- VkDescriptorSetLayoutBinding global_ubo_layout_binding;
- global_ubo_layout_binding.binding = 0;
- global_ubo_layout_binding.descriptorCount = 1;
- global_ubo_layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
- global_ubo_layout_binding.pImmutableSamplers = 0;
- global_ubo_layout_binding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
+static bool select_physical_device(gpu_device* out_device) {}
- VkDescriptorSetLayoutBinding sampler_layout_binding;
- sampler_layout_binding.binding = 1;
- sampler_layout_binding.descriptorCount = 1;
- sampler_layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
- sampler_layout_binding.pImmutableSamplers = 0;
- sampler_layout_binding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
-
- VkDescriptorSetLayoutCreateInfo global_layout_info = {
- VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO
- };
-
- VkDescriptorSetLayoutBinding bindings[2] = { global_ubo_layout_binding, sampler_layout_binding };
-
- global_layout_info.bindingCount = 2;
- global_layout_info.pBindings = bindings;
-
- VK_CHECK(vkCreateDescriptorSetLayout(context->device.logical_device, &global_layout_info,
- context->allocator, &out_shader->descriptor_set_layout));
-
- VkDescriptorPoolSize global_pool_size;
- global_pool_size.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
- global_pool_size.descriptorCount = 3;
-
- VkDescriptorPoolSize sampler_pool_size;
- sampler_pool_size.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
- sampler_pool_size.descriptorCount = 3;
-
- VkDescriptorPoolSize pool_sizes[2] = { global_pool_size, sampler_pool_size };
-
- VkDescriptorPoolCreateInfo pool_info = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO };
- pool_info.poolSizeCount = 2;
- pool_info.pPoolSizes = pool_sizes;
- pool_info.maxSets = 3;
-
- VK_CHECK(vkCreateDescriptorPool(context->device.logical_device, &pool_info, context->allocator,
- &out_shader->descriptor_pool));
-
- // Pipeline creation
- VkViewport viewport;
- viewport.x = 0;
- viewport.y = 0;
- viewport.width = (f32)context->framebuffer_width;
- viewport.height = (f32)context->framebuffer_height;
- viewport.minDepth = 0.0;
- viewport.maxDepth = 1.0;
-
- VkRect2D scissor;
- scissor.offset.x = scissor.offset.y = 0;
- scissor.extent.width = context->framebuffer_width;
- scissor.extent.height = context->framebuffer_height;
-
- // Attributes
- u32 offset = 0;
- const i32 attribute_count = 3;
- VkVertexInputAttributeDescription attribute_descs[3];
- // Position
- VkFormat formats[3] = { VK_FORMAT_R32G32B32_SFLOAT, VK_FORMAT_R32G32B32_SFLOAT,
- VK_FORMAT_R32G32_SFLOAT };
-
- u64 sizes[3] = { sizeof(vec3), sizeof(vec3), sizeof(vec2) };
-
- for (u32 i = 0; i < attribute_count; i++) {
- attribute_descs[i].binding = 0;
- attribute_descs[i].location = i;
- attribute_descs[i].format = formats[i];
- attribute_descs[i].offset = offset;
- offset += sizes[i];
- }
-
- // Descriptor set layouts
- VkDescriptorSetLayout layouts[1] = { out_shader->descriptor_set_layout };
-
- // Stages
- VkPipelineShaderStageCreateInfo stage_create_infos[SHADER_STAGE_COUNT];
- memset(stage_create_infos, 0, sizeof(stage_create_infos));
- for (u32 i = 0; i < SHADER_STAGE_COUNT; i++) {
- stage_create_infos[i].sType = out_shader->stages[i].stage_create_info.sType;
- stage_create_infos[i] = out_shader->stages[i].stage_create_info;
- }
-
- vulkan_graphics_pipeline_create(
- context, &context->main_renderpass, attribute_count, attribute_descs, 1, layouts,
- SHADER_STAGE_COUNT, stage_create_infos, viewport, scissor, false, &out_shader->pipeline);
- INFO("Graphics pipeline created!");
-
- // Uniform buffer
- if (!vulkan_buffer_create(context, sizeof(global_object_uniform),
- VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
- VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
- VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
- VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
- true, &out_shader->global_uniforms_buffer)) {
- ERROR("Couldnt create uniforms buffer");
- return false;
- }
-
- VkDescriptorSetLayout global_layouts[3] = {
- out_shader->descriptor_set_layout,
- out_shader->descriptor_set_layout,
- out_shader->descriptor_set_layout,
- };
-
- VkDescriptorSetAllocateInfo alloc_info = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO };
- alloc_info.descriptorPool = out_shader->descriptor_pool;
- alloc_info.descriptorSetCount = 3;
- alloc_info.pSetLayouts = global_layouts;
- VK_CHECK(vkAllocateDescriptorSets(context->device.logical_device, &alloc_info,
- out_shader->descriptor_sets));
-
- return true;
-}
-void vulkan_object_shader_destroy(vulkan_context* context, vulkan_shader* shader) {}
-void vulkan_object_shader_use(vulkan_context* context, vulkan_shader* shader) {
- u32 image_index = context->image_index;
- vulkan_pipeline_bind(&context->gfx_command_buffers->data[image_index],
- VK_PIPELINE_BIND_POINT_GRAPHICS, &shader->pipeline);
-}
-void vulkan_object_shader_update_global_state(vulkan_context* context, vulkan_shader* shader) {
- u32 image_index = context->image_index;
- VkCommandBuffer cmd_buffer = context->gfx_command_buffers->data[image_index].handle;
- VkDescriptorSet global_descriptors = shader->descriptor_sets[image_index];
-
- u32 range = sizeof(global_object_uniform);
- u64 offset = 0;
-
- // copy data to buffer
- vulkan_buffer_load_data(context, &shader->global_uniforms_buffer, offset, range, 0,
- &shader->global_ubo);
-
- VkDescriptorBufferInfo buffer_info;
- buffer_info.buffer = shader->global_uniforms_buffer.handle;
- buffer_info.offset = offset;
- buffer_info.range = range;
-
- VkDescriptorImageInfo image_info;
- image_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
- image_info.imageView = shader->texture_data->image.view;
- image_info.sampler = shader->texture_data->sampler;
-
- VkWriteDescriptorSet uniform_write = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET };
- uniform_write.dstSet = shader->descriptor_sets[image_index];
- uniform_write.dstBinding = 0;
- uniform_write.dstArrayElement = 0;
- uniform_write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
- uniform_write.descriptorCount = 1;
- uniform_write.pBufferInfo = &buffer_info;
-
- VkWriteDescriptorSet texture_write = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET };
- texture_write.dstSet = shader->descriptor_sets[image_index];
- texture_write.dstBinding = 1;
- texture_write.dstArrayElement = 0;
- texture_write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
- texture_write.descriptorCount = 1;
- texture_write.pImageInfo = &image_info;
-
- VkWriteDescriptorSet writes[2] = { uniform_write, texture_write };
-
- vkUpdateDescriptorSets(context->device.logical_device, 2, writes, 0, 0);
-
- vkCmdBindDescriptorSets(cmd_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, shader->pipeline.layout, 0,
- 1, &global_descriptors, 0, 0);
-}
-
-void vulkan_object_shader_update_object(vulkan_context* context, vulkan_shader* shader,
- mat4 model) {
- u32 image_index = context->image_index;
- VkCommandBuffer cmd_buffer = context->gfx_command_buffers->data[image_index].handle;
- // vulkan_command_buffer* cmd_buffer = &context->gfx_command_buffers->data[context.image_index];
-
- vkCmdPushConstants(cmd_buffer, shader->pipeline.layout, VK_SHADER_STAGE_VERTEX_BIT, 0,
- sizeof(mat4), &model);
-
- // vulkan_object_shader_use(context, &context->object_shader);
- VkDeviceSize offsets[1] = { 0 };
- vkCmdBindVertexBuffers(cmd_buffer, 0, 1, &context->object_vertex_buffer.handle,
- (VkDeviceSize*)offsets);
-
- vkCmdBindIndexBuffer(cmd_buffer, context->object_index_buffer.handle, 0, VK_INDEX_TYPE_UINT32);
-
- vkCmdDrawIndexed(cmd_buffer, 36, 1, 0, 0, 0);
- // vkCmdDraw(cmd_buffer, 36, 1, 0, 0);
-}
-
-bool select_physical_device(vulkan_context* ctx) {
- u32 physical_device_count = 0;
- VK_CHECK(vkEnumeratePhysicalDevices(ctx->instance, &physical_device_count, 0));
- if (physical_device_count == 0) {
- FATAL("No devices that support vulkan were found");
- return false;
- }
- TRACE("Number of devices found %d", physical_device_count);
-
- VkPhysicalDevice physical_devices[physical_device_count];
- VK_CHECK(vkEnumeratePhysicalDevices(ctx->instance, &physical_device_count, physical_devices));
-
- for (u32 i = 0; i < physical_device_count; i++) {
- VkPhysicalDeviceProperties properties;
- vkGetPhysicalDeviceProperties(physical_devices[i], &properties);
-
- VkPhysicalDeviceFeatures features;
- vkGetPhysicalDeviceFeatures(physical_devices[i], &features);
-
- VkPhysicalDeviceMemoryProperties memory;
- vkGetPhysicalDeviceMemoryProperties(physical_devices[i], &memory);
-
- vulkan_physical_device_requirements requirements = {};
- requirements.graphics = true;
- requirements.present = true;
- requirements.compute = true;
- requirements.transfer = true;
-
- requirements.sampler_anistropy = true;
- requirements.discrete_gpu = true;
- requirements.device_ext_names[0] = str8lit(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
- requirements.device_ext_name_count = 1;
-
- vulkan_physical_device_queue_family_info queue_info = {};
-
- bool result = physical_device_meets_requirements(physical_devices[i], ctx->surface, &properties,
- &features, &requirements, &queue_info,
- &ctx->device.swapchain_support);
-
- if (result) {
- INFO("GPU Driver version: %d.%d.%d", VK_VERSION_MAJOR(properties.driverVersion),
- VK_VERSION_MINOR(properties.driverVersion), VK_VERSION_PATCH(properties.driverVersion));
-
- INFO("Vulkan API version: %d.%d.%d", VK_VERSION_MAJOR(properties.apiVersion),
- VK_VERSION_MINOR(properties.apiVersion), VK_VERSION_PATCH(properties.apiVersion));
-
- // TODO: print gpu memory information -
- // https://youtu.be/6Kj3O2Ov1RU?si=pXfP5NvXXcXjJsrG&t=2439
-
- ctx->device.physical_device = physical_devices[i];
- ctx->device.graphics_queue_index = queue_info.graphics_family_index;
- ctx->device.present_queue_index = queue_info.present_family_index;
- ctx->device.compute_queue_index = queue_info.compute_family_index;
- ctx->device.transfer_queue_index = queue_info.transfer_family_index;
- ctx->device.properties = properties;
- ctx->device.features = features;
- ctx->device.memory = memory;
- break;
- }
- }
-
- if (!ctx->device.physical_device) {
- ERROR("No suitable physical devices were found :(");
- return false;
- }
-
- INFO("Physical device selected: %s\n", ctx->device.properties.deviceName);
- return true;
-}
-
-bool vulkan_device_create(vulkan_context* context) {
- // Physical device - NOTE: mutates the context directly
- if (!select_physical_device(context)) {
- return false;
- }
-
-// Logical device - NOTE: mutates the context directly
-
-// queues
-#define VULKAN_QUEUES_COUNT 2
- const char* queue_names[VULKAN_QUEUES_COUNT] = {
- "GRAPHICS",
- "TRANSFER",
- };
- i32 indices[VULKAN_QUEUES_COUNT] = {
- context->device.graphics_queue_index,
- context->device.transfer_queue_index,
- };
- f32 prio_one = 1.0;
- VkDeviceQueueCreateInfo queue_create_info[2]; // HACK: make 2 queues, graphics and transfer
- // graphics
- queue_create_info[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
- queue_create_info[0].queueFamilyIndex = 0;
- queue_create_info[0].queueCount = 1;
- queue_create_info[0].flags = 0;
- queue_create_info[0].pNext = 0;
- queue_create_info[0].pQueuePriorities = &prio_one;
- // transfer
- queue_create_info[1].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
- queue_create_info[1].queueFamilyIndex = 1;
- queue_create_info[1].queueCount = 1;
- queue_create_info[1].flags = 0;
- queue_create_info[1].pNext = 0;
- queue_create_info[1].pQueuePriorities = &prio_one;
-
- // for (int i = 0; i < 2; i++) {
- // TRACE("Configure %s queue", queue_names[i]);
- // queue_create_info[i].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
- // queue_create_info[i].queueFamilyIndex = indices[i];
- // queue_create_info[i].queueCount = 1; // make just one of them
- // queue_create_info[i].flags = 0;
- // queue_create_info[i].pNext = 0;
- // f32 priority = 1.0;
- // queue_create_info[i].pQueuePriorities = &priority;
+gpu_device gpu_device_create() {
+ gpu_device device = { 0 };
+ // Physical device
+ // if (!select_physical_device()) {
+ // return false;
// }
+ INFO("Physical device selected");
- // features
+ // Features
VkPhysicalDeviceFeatures device_features = {};
device_features.samplerAnisotropy = VK_TRUE; // request anistrophy
- // device itself
+ // Logical device
+ VkDeviceQueueCreateInfo queue_create_info[2];
+ //..
VkDeviceCreateInfo device_create_info = { VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO };
device_create_info.queueCreateInfoCount = VULKAN_QUEUES_COUNT;
device_create_info.pQueueCreateInfos = queue_create_info;
@@ -844,1147 +47,38 @@ bool vulkan_device_create(vulkan_context* context) {
const char* extension_names = VK_KHR_SWAPCHAIN_EXTENSION_NAME;
device_create_info.ppEnabledExtensionNames = &extension_names;
- // deprecated
- device_create_info.enabledLayerCount = 0;
- device_create_info.ppEnabledLayerNames = 0;
-
- VkResult result = vkCreateDevice(context->device.physical_device, &device_create_info,
- context->allocator, &context->device.logical_device);
+ VkResult result = vkCreateDevice(device.physical_device, &device_create_info, context.allocator,
+ &device.logical_device);
if (result != VK_SUCCESS) {
- printf("error creating logical device with status %u\n", result);
- ERROR_EXIT("Bye bye");
+ FATAL("Error creating logical device with status %u\n", result);
+ exit(1);
}
INFO("Logical device created");
- // get queues
- vkGetDeviceQueue(context->device.logical_device, context->device.graphics_queue_index, 0,
- &context->device.graphics_queue);
- // vkGetDeviceQueue(context->device.logical_device, context->device.present_queue_index, 0,
- // &context->device.present_queue);
- // vkGetDeviceQueue(context->device.logical_device, context->device.compute_queue_index, 0,
- // &context->device.compute_queue);
- vkGetDeviceQueue(context->device.logical_device, context->device.transfer_queue_index, 0,
- &context->device.transfer_queue);
+ // Queues
- // create command pool for graphics queue
- VkCommandPoolCreateInfo pool_create_info = { VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO };
- pool_create_info.queueFamilyIndex = context->device.graphics_queue_index;
- pool_create_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
- vkCreateCommandPool(context->device.logical_device, &pool_create_info, context->allocator,
- &context->device.gfx_command_pool);
- INFO("Created Command Pool")
+ // Create the command pool
- return true;
+ context.device = device;
+ return device;
}
-void vulkan_device_destroy(vulkan_context* context) {
- context->device.physical_device = 0; // release
- // TODO: reset other memory
-}
-
-bool vulkan_device_detect_depth_format(vulkan_device* device) {
- const size_t n_candidates = 3;
- VkFormat candidates[3] = { VK_FORMAT_D32_SFLOAT, VK_FORMAT_D32_SFLOAT_S8_UINT,
- VK_FORMAT_D24_UNORM_S8_UINT };
- u32 flags = VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT;
- for (u64 i = 0; i < n_candidates; i++) {
- VkFormatProperties properties;
- vkGetPhysicalDeviceFormatProperties(device->physical_device, candidates[i], &properties);
- if ((properties.linearTilingFeatures & flags) == flags) {
- device->depth_format = candidates[i];
- return true;
- }
- if ((properties.optimalTilingFeatures & flags) == flags) {
- device->depth_format = candidates[i];
- return true;
- }
- }
- return false;
+gpu_renderpass* gpu_renderpass_create() {
+ // Allocate it
+ // sets everything up
+ // return pointer to it
}
-void vulkan_image_view_create(vulkan_context* context, VkFormat format, vulkan_image* image,
- VkImageAspectFlags aspect_flags) {
- VkImageViewCreateInfo view_create_info = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };
- view_create_info.image = image->handle;
- view_create_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
- view_create_info.format = format;
- view_create_info.subresourceRange.aspectMask = aspect_flags;
-
- view_create_info.subresourceRange.baseMipLevel = 0;
- view_create_info.subresourceRange.levelCount = 1;
- view_create_info.subresourceRange.baseArrayLayer = 0;
- view_create_info.subresourceRange.layerCount = 1;
-
- vkCreateImageView(context->device.logical_device, &view_create_info, context->allocator,
- &image->view);
+void encode_set_pipeline(gpu_cmd_encoder* encoder, gpu_pipeline* pipeline) {
+ // VK_PIPELINE_BIND_POINT_GRAPHICS, &shader->pipeline);
+ // if (kind == PIPELINE_GRAPHICS) {
+ // // ...
+ // } else {
+ // // ...
+ // }
}
-void vulkan_image_transition_layout(vulkan_context* context, vulkan_command_buffer* command_buffer,
- vulkan_image* image, VkFormat format, VkImageLayout old_layout,
- VkImageLayout new_layout) {
- VkImageMemoryBarrier barrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER };
- void vulkan_image_transition_layout(
- vulkan_context * context, vulkan_command_buffer * command_buffer, vulkan_image * image,
- VkFormat format, VkImageLayout old_layout, VkImageLayout new_layout) {
- VkImageMemoryBarrier barrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER };
- barrier.oldLayout = old_layout;
- barrier.newLayout = new_layout;
- barrier.srcQueueFamilyIndex = context->device.graphics_queue_index;
- barrier.dstQueueFamilyIndex = context->device.graphics_queue_index;
- barrier.image = image->handle;
- barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
- barrier.subresourceRange.baseMipLevel = 0;
- barrier.subresourceRange.levelCount = 1;
- barrier.subresourceRange.baseArrayLayer = 0;
- barrier.subresourceRange.layerCount = 1;
- barrier.srcAccessMask = 0;
- barrier.dstAccessMask = 0;
-
- VkPipelineStageFlags source_stage;
- VkPipelineStageFlags dest_stage;
-
- if (old_layout == VK_IMAGE_LAYOUT_UNDEFINED &&
- new_layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
- barrier.srcAccessMask = 0;
- barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
-
- source_stage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
- dest_stage = VK_PIPELINE_STAGE_TRANSFER_BIT;
-
- } else if (old_layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL &&
- new_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
- barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
- barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
- source_stage = VK_PIPELINE_STAGE_TRANSFER_BIT;
- dest_stage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
- } else {
- FATAL("Unsupported image layout transition");
- return;
- }
-
- vkCmdPipelineBarrier(command_buffer->handle, source_stage, dest_stage, 0, 0, 0, 0, 0, 1,
- &barrier);
- }
-
- void vulkan_image_copy_from_buffer(vulkan_image * image, VkBuffer buffer,
- vulkan_command_buffer * command_buffer) {
- VkBufferImageCopy region;
- region.bufferOffset = 0;
- region.bufferRowLength = 0;
- region.bufferImageHeight = 0;
- region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
- region.imageSubresource.mipLevel = 0;
- region.imageSubresource.baseArrayLayer = 0;
- region.imageSubresource.layerCount = 1;
- printf("Image details width: %d height %d\n", image->width, image->height);
- region.imageOffset.x = 0;
- region.imageOffset.y = 0;
- region.imageOffset.z = 0;
- region.imageExtent.width = image->width;
- region.imageExtent.height = image->height;
- region.imageExtent.depth = 1;
-
- vkCmdCopyBufferToImage(command_buffer->handle, buffer, image->handle,
- VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
- }
-
- void vulkan_image_create(vulkan_context * context, VkImageType image_type, u32 width, u32 height,
- VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage,
- VkMemoryPropertyFlags memory_flags, bool create_view,
- VkImageAspectFlags aspect_flags, vulkan_image* out_image) {
- // copy params
- out_image->width = width;
- out_image->height = height;
-
- // create info
- VkImageCreateInfo image_create_info = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };
- image_create_info.imageType = image_type;
- image_create_info.extent.width = width;
- image_create_info.extent.height = height;
- image_create_info.extent.depth = 1;
- image_create_info.mipLevels = 1;
- image_create_info.arrayLayers = 1;
- image_create_info.format = format;
- image_create_info.tiling = tiling;
- image_create_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
- image_create_info.usage = usage;
- image_create_info.samples = VK_SAMPLE_COUNT_1_BIT;
- image_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
-
- VK_CHECK(vkCreateImage(context->device.logical_device, &image_create_info, context->allocator,
- &out_image->handle));
-
- VkMemoryRequirements memory_reqs;
- vkGetImageMemoryRequirements(context->device.logical_device, out_image->handle, &memory_reqs);
-
- i32 memory_type = -1;
- VkPhysicalDeviceMemoryProperties memory_properties;
- vkGetPhysicalDeviceMemoryProperties(context->device.physical_device, &memory_properties);
-
- for (u32 i = 0; i < memory_properties.memoryTypeCount; i++) {
- // typefilter = memoryTypeBits , prop filter = memory_flags
- if (memory_reqs.memoryTypeBits & (1 << i) &&
- (memory_properties.memoryTypes[i].propertyFlags & memory_flags)) {
- memory_type = i;
- break;
- }
- }
-
- if (memory_type < 0) {
- ERROR_EXIT("couldnt find a suitable memory type for the image");
- }
-
- // allocate memory
- VkMemoryAllocateInfo memory_allocate_info = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
- memory_allocate_info.allocationSize = memory_reqs.size;
- memory_allocate_info.memoryTypeIndex = memory_type;
- vkAllocateMemory(context->device.logical_device, &memory_allocate_info, context->allocator,
- &out_image->memory);
-
- // bind memory
- // TODO: maybe bind context->device.logical_device to device at the top of the functions?
- vkBindImageMemory(context->device.logical_device, out_image->handle, out_image->memory, 0);
-
- if (create_view) {
- out_image->view = 0;
- vulkan_image_view_create(context, format, out_image, aspect_flags);
- }
- }
-
- // TODO: vulkan_image_destroy
-
- void vulkan_framebuffer_create(vulkan_context * context, vulkan_renderpass * renderpass,
- u32 width, u32 height, u32 attachment_count,
- VkImageView * attachments, vulkan_framebuffer * out_framebuffer) {
- out_framebuffer->attachments = malloc(sizeof(VkImageView) * attachment_count);
- for (u32 i = 0; i < attachment_count; i++) {
- out_framebuffer->attachments[i] = attachments[i];
- }
- out_framebuffer->attachment_count = attachment_count;
- out_framebuffer->renderpass = renderpass;
-
- VkFramebufferCreateInfo framebuffer_create_info = {
- VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO
- }; // TODO
-
- framebuffer_create_info.renderPass = renderpass->handle;
- framebuffer_create_info.attachmentCount = attachment_count;
- framebuffer_create_info.pAttachments = out_framebuffer->attachments;
- framebuffer_create_info.width = width;
- framebuffer_create_info.height = height;
- framebuffer_create_info.layers = 1;
-
- vkCreateFramebuffer(context->device.logical_device, &framebuffer_create_info,
- context->allocator, &out_framebuffer->handle);
- }
-
- // TODO: vulkan_framebuffer_destroy
-
- void vulkan_command_buffer_allocate(vulkan_context * context, VkCommandPool pool, bool is_primary,
- vulkan_command_buffer* out_command_buffer) {
- VkCommandBufferAllocateInfo allocate_info = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO };
- allocate_info.commandPool = pool;
- allocate_info.level =
- is_primary ? VK_COMMAND_BUFFER_LEVEL_PRIMARY : VK_COMMAND_BUFFER_LEVEL_SECONDARY;
- allocate_info.commandBufferCount = 1;
- allocate_info.pNext = 0;
-
- out_command_buffer->state = COMMAND_BUFFER_STATE_NOT_ALLOCATED;
- vkAllocateCommandBuffers(context->device.logical_device, &allocate_info,
- &out_command_buffer->handle);
- out_command_buffer->state = COMMAND_BUFFER_STATE_READY;
- }
-
- void vulkan_command_buffer_free(vulkan_context * context, VkCommandPool pool,
- vulkan_command_buffer * out_command_buffer) {
- // TODO: implement freeing
- }
-
- void vulkan_command_buffer_begin(vulkan_command_buffer * command_buffer, bool is_single_use,
- bool is_renderpass_continue, bool is_simultaneous_use) {
- VkCommandBufferBeginInfo begin_info = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
- begin_info.flags = 0;
- if (is_single_use) {
- begin_info.flags |= VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
- }
- // TODO: RENDER_PASS_CONTINUE_BIT & SIMULTANEOUS_USE_BIT
-
- begin_info.pNext = 0;
- begin_info.pInheritanceInfo = 0;
- vkBeginCommandBuffer(command_buffer->handle, &begin_info);
-
- command_buffer->state = COMMAND_BUFFER_STATE_RECORDING;
- }
-
- void vulkan_command_buffer_end(vulkan_command_buffer * command_buffer) {
- VK_CHECK(vkEndCommandBuffer(command_buffer->handle));
- command_buffer->state = COMMAND_BUFFER_STATE_RECORDING_ENDED;
- }
- void vulkan_command_buffer_update_submitted(vulkan_command_buffer * command_buffer) {
- command_buffer->state = COMMAND_BUFFER_STATE_SUBMITTED;
- }
- void vulkan_command_buffer_reset(vulkan_command_buffer * command_buffer) {
- command_buffer->state = COMMAND_BUFFER_STATE_READY;
- }
-
- void vulkan_command_buffer_allocate_and_begin_oneshot(
- vulkan_context * context, VkCommandPool pool, vulkan_command_buffer * out_command_buffer) {
- vulkan_command_buffer_allocate(context, pool, true, out_command_buffer);
- vulkan_command_buffer_begin(out_command_buffer, true, false, false);
- }
-
- void vulkan_command_buffer_end_oneshot(vulkan_context * context, VkCommandPool pool,
- vulkan_command_buffer * command_buffer, VkQueue queue) {
- vulkan_command_buffer_end(command_buffer);
-
- // submit to queue
- VkSubmitInfo submit_info = { VK_STRUCTURE_TYPE_SUBMIT_INFO };
- submit_info.commandBufferCount = 1;
- submit_info.pCommandBuffers = &command_buffer->handle;
- VK_CHECK(vkQueueSubmit(queue, 1, &submit_info, 0));
- // wait for it to finish
- VK_CHECK(vkQueueWaitIdle(queue));
-
- vulkan_command_buffer_free(context, pool, command_buffer);
- }
-
- void vulkan_buffer_copy_to(vulkan_context * context, VkCommandPool pool, VkFence fence,
- VkQueue queue, VkBuffer source, u64 source_offset, VkBuffer dest,
- u64 dest_offset, u64 size) {
- vkQueueWaitIdle(queue);
-
- vulkan_command_buffer temp_cmd_buf;
- vulkan_command_buffer_allocate_and_begin_oneshot(context, pool, &temp_cmd_buf);
-
- VkBufferCopy copy_region;
- copy_region.srcOffset = source_offset;
- copy_region.dstOffset = dest_offset;
- copy_region.size = size;
-
- vkCmdCopyBuffer(temp_cmd_buf.handle, source, dest, 1, &copy_region);
-
- vulkan_command_buffer_end_oneshot(context, pool, &temp_cmd_buf, queue);
- }
-
- void vulkan_swapchain_create(vulkan_context * context, u32 width, u32 height,
- vulkan_swapchain * out_swapchain) {
- VkExtent2D swapchain_extent = { width, height };
- out_swapchain->max_frames_in_flight = 2; // support triple buffering
-
- // find a format
- bool found;
- for (u32 i = 0; i < context->device.swapchain_support.format_count; i++) {
- VkSurfaceFormatKHR format = context->device.swapchain_support.formats[i];
- if (format.format == VK_FORMAT_B8G8R8A8_UNORM &&
- format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
- out_swapchain->image_format = format;
- found = true;
- break;
- }
- }
- if (!found) {
- out_swapchain->image_format = context->device.swapchain_support.formats[0];
- }
-
- VkPresentModeKHR present_mode = VK_PRESENT_MODE_FIFO_KHR; // guaranteed to be implemented
- // TODO: look for mailbox - https://youtu.be/jWKVb_QdSNM?si=bHcd3sEf-M0x3QwH&t=1687
-
- // TODO: requery swapchain support
-
- u32 image_count = context->device.swapchain_support.capabilities.minImageCount;
-
- VkSwapchainCreateInfoKHR swapchain_create_info = {
- VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR
- };
- swapchain_create_info.surface = context->surface;
- swapchain_create_info.minImageCount = image_count;
- swapchain_create_info.imageFormat = out_swapchain->image_format.format;
- swapchain_create_info.imageColorSpace = out_swapchain->image_format.colorSpace;
- DEBUG("Image extent %d %d\n", swapchain_extent.width, swapchain_extent.height);
- swapchain_create_info.imageExtent = swapchain_extent;
- swapchain_create_info.imageArrayLayers = 1;
- swapchain_create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
- swapchain_create_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
- swapchain_create_info.queueFamilyIndexCount = 0;
- swapchain_create_info.pQueueFamilyIndices = 0;
-
- swapchain_create_info.preTransform =
- context->device.swapchain_support.capabilities.currentTransform;
- swapchain_create_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
- swapchain_create_info.presentMode = present_mode;
- swapchain_create_info.clipped = VK_TRUE;
- swapchain_create_info.oldSwapchain = 0;
-
- TRACE("Create swapchain");
- VK_CHECK(vkCreateSwapchainKHR(context->device.logical_device, &swapchain_create_info,
- context->allocator, &out_swapchain->handle));
-
- context->current_frame = 0;
-
- // images
- out_swapchain->image_count = 0;
- vkGetSwapchainImagesKHR(context->device.logical_device, out_swapchain->handle,
- &out_swapchain->image_count, 0);
-
- if (!out_swapchain->images) {
- out_swapchain->images = (VkImage*)malloc(sizeof(VkImage) * out_swapchain->image_count);
- }
- if (!out_swapchain->views) {
- out_swapchain->views = (VkImageView*)malloc(sizeof(VkImage) * out_swapchain->image_count);
- }
- VK_CHECK(vkGetSwapchainImagesKHR(context->device.logical_device, out_swapchain->handle,
- &out_swapchain->image_count, out_swapchain->images));
-
- // views
- for (int i = 0; i < out_swapchain->image_count; i++) {
- VkImageViewCreateInfo view_info = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };
- view_info.image = out_swapchain->images[i];
- view_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
- view_info.format = out_swapchain->image_format.format;
- view_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
- view_info.subresourceRange.baseMipLevel = 0;
- view_info.subresourceRange.levelCount = 1;
- view_info.subresourceRange.baseArrayLayer = 0;
- view_info.subresourceRange.layerCount = 1;
-
- VK_CHECK(vkCreateImageView(context->device.logical_device, &view_info, context->allocator,
- &out_swapchain->views[i]));
- }
-
- // depth attachment
- if (!vulkan_device_detect_depth_format(&context->device)) {
- ERROR_EXIT("Failed to find a supported depth format");
- }
- vulkan_image_create(context, VK_IMAGE_TYPE_2D, swapchain_extent.width, swapchain_extent.height,
- context->device.depth_format, VK_IMAGE_TILING_OPTIMAL,
- VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
- VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, true, VK_IMAGE_ASPECT_DEPTH_BIT,
- &out_swapchain->depth_attachment);
- INFO("Depth attachment created");
-
- INFO("Swapchain created successfully");
- }
-
- // TODO: swapchain destroy
- void vulkan_swapchain_recreate(vulkan_context * context, u32 width, u32 height,
- vulkan_swapchain * swapchain) {
- // TODO
- }
- bool vulkan_swapchain_acquire_next_image_index(
- vulkan_context * context, vulkan_swapchain * swapchain, u64 timeout_ns,
- VkSemaphore image_available_semaphore, VkFence fence, u32 * out_image_index) {
- VkResult result =
- vkAcquireNextImageKHR(context->device.logical_device, swapchain->handle, timeout_ns,
- image_available_semaphore, fence, out_image_index);
-
- if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) {
- FATAL("Failed to acquire swapchain image");
- return false;
- }
-
- return true;
- }
-
- void vulkan_swapchain_present(vulkan_context * context, vulkan_swapchain * swapchain,
- VkQueue graphics_queue, VkQueue present_queue,
- VkSemaphore render_complete_semaphore, u32 present_image_index) {
- // return image to swapchain for presentation
- VkPresentInfoKHR present_info = { VK_STRUCTURE_TYPE_PRESENT_INFO_KHR };
- present_info.waitSemaphoreCount = 1;
- present_info.pWaitSemaphores = &render_complete_semaphore;
- present_info.swapchainCount = 1;
- present_info.pSwapchains = &swapchain->handle;
- present_info.pImageIndices = &present_image_index;
- present_info.pResults = 0;
-
- VkResult result = vkQueuePresentKHR(present_queue, &present_info);
- if (result != VK_SUCCESS) {
- if (result == VK_SUBOPTIMAL_KHR) {
- // WARN("Swapchain suboptimal - maybe resize needed?");
- } else {
- FATAL("Failed to present swapchain iamge");
- }
- }
-
- // advance the current frame
- context->current_frame = (context->current_frame + 1) % swapchain->max_frames_in_flight;
- }
-
- void vulkan_renderpass_create(vulkan_context * context, vulkan_renderpass * out_renderpass,
- vec4 render_area, vec4 clear_colour, f32 depth, u32 stencil) {
- out_renderpass->render_area = render_area;
- out_renderpass->clear_colour = clear_colour;
- out_renderpass->depth = depth;
- out_renderpass->stencil = stencil;
-
- // main subpass
- VkSubpassDescription subpass = {};
- subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
-
- // attachments
- u32 attachment_desc_count = 2;
- VkAttachmentDescription attachment_descriptions[2];
-
- // Colour attachment
- VkAttachmentDescription color_attachment;
- color_attachment.format = context->swapchain.image_format.format;
- color_attachment.samples = VK_SAMPLE_COUNT_1_BIT;
- color_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
- color_attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
- color_attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
- color_attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
- color_attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
- color_attachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
- color_attachment.flags = 0;
-
- attachment_descriptions[0] = color_attachment;
-
- VkAttachmentReference color_attachment_reference;
- color_attachment_reference.attachment = 0;
- color_attachment_reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
-
- subpass.colorAttachmentCount = 1;
- subpass.pColorAttachments = &color_attachment_reference;
-
- // Depth attachment
- VkAttachmentDescription depth_attachment;
- depth_attachment.format = context->device.depth_format;
- depth_attachment.samples = VK_SAMPLE_COUNT_1_BIT;
- depth_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
- depth_attachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
- depth_attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
- depth_attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
- depth_attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
- depth_attachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
- depth_attachment.flags = 0;
-
- attachment_descriptions[1] = depth_attachment;
-
- VkAttachmentReference depth_attachment_reference;
- depth_attachment_reference.attachment = 1;
- depth_attachment_reference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
-
- subpass.pDepthStencilAttachment = &depth_attachment_reference;
-
- // TODO: other attachment styles
-
- subpass.inputAttachmentCount = 0;
- subpass.pInputAttachments = 0;
- subpass.pResolveAttachments = 0;
- subpass.preserveAttachmentCount = 0;
- subpass.preserveAttachmentCount = 0;
-
- // renderpass dependencies
- VkSubpassDependency dependency;
- dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
- dependency.dstSubpass = 0;
- dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
- dependency.srcAccessMask = 0;
- dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
- dependency.dstAccessMask =
- VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
- dependency.dependencyFlags = 0;
-
- VkRenderPassCreateInfo render_pass_create_info = { VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO };
- render_pass_create_info.attachmentCount = attachment_desc_count;
- render_pass_create_info.pAttachments = attachment_descriptions;
- render_pass_create_info.subpassCount = 1;
- render_pass_create_info.pSubpasses = &subpass;
- render_pass_create_info.dependencyCount = 1;
- render_pass_create_info.pDependencies = &dependency;
- render_pass_create_info.pNext = 0;
- render_pass_create_info.flags = 0;
-
- VK_CHECK(vkCreateRenderPass(context->device.logical_device, &render_pass_create_info,
- context->allocator, &out_renderpass->handle));
- }
-
- // TODO: renderpass destroy
-
- void vulkan_renderpass_begin(vulkan_command_buffer * command_buffer,
- vulkan_renderpass * renderpass, VkFramebuffer framebuffer) {
- VkRenderPassBeginInfo begin_info = { VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO };
- begin_info.renderPass = renderpass->handle;
- begin_info.framebuffer = framebuffer;
- begin_info.renderArea.offset.x = renderpass->render_area.x;
- begin_info.renderArea.offset.y = renderpass->render_area.y;
- begin_info.renderArea.extent.width = renderpass->render_area.z;
- begin_info.renderArea.extent.height = renderpass->render_area.w;
-
- VkClearValue clear_values[2];
- memset(&clear_values, 0, sizeof(VkClearValue) * 2);
- clear_values[0].color.float32[0] = renderpass->clear_colour.x;
- clear_values[0].color.float32[1] = renderpass->clear_colour.y;
- clear_values[0].color.float32[2] = renderpass->clear_colour.z;
- clear_values[0].color.float32[3] = renderpass->clear_colour.w;
- clear_values[1].depthStencil.depth = renderpass->depth;
- clear_values[1].depthStencil.stencil = renderpass->stencil;
-
- begin_info.clearValueCount = 2;
- begin_info.pClearValues = clear_values;
-
- vkCmdBeginRenderPass(command_buffer->handle, &begin_info, VK_SUBPASS_CONTENTS_INLINE);
- command_buffer->state = COMMAND_BUFFER_STATE_IN_RENDER_PASS;
- }
-
- void vulkan_renderpass_end(vulkan_command_buffer * command_buffer,
- vulkan_renderpass * renderpass) {
- vkCmdEndRenderPass(command_buffer->handle);
- command_buffer->state = COMMAND_BUFFER_STATE_RECORDING;
- }
-
- bool create_buffers(vulkan_context * context) {
- VkMemoryPropertyFlagBits mem_prop_flags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
-
- const u64 vertex_buffer_size = sizeof(vertex_pos) * 1024 * 1024;
- if (!vulkan_buffer_create(context, vertex_buffer_size,
- VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT |
- VK_BUFFER_USAGE_TRANSFER_DST_BIT,
- mem_prop_flags, true, &context->object_vertex_buffer)) {
- ERROR("couldnt create vertex buffer");
- return false;
- }
-
- context->geometry_vertex_offset = 0;
-
- const u64 index1_buffer_size = sizeof(u32) * 1024 * 1024;
- if (!vulkan_buffer_create(context, index1_buffer_size,
- VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT |
- VK_BUFFER_USAGE_TRANSFER_DST_BIT,
- mem_prop_flags, true, &context->object_index_buffer)) {
- ERROR("couldnt create vertex buffer");
- return false;
- }
- context->geometry_index_offset = 0;
-
- return true;
- }
-
- void create_command_buffers(renderer * ren) {
- if (!context.gfx_command_buffers) {
- context.gfx_command_buffers = vulkan_command_buffer_darray_new(context.swapchain.image_count);
- }
-
- for (u32 i = 0; i < context.swapchain.image_count; i++) {
- vulkan_command_buffer_allocate(&context, context.device.gfx_command_pool, true,
- &context.gfx_command_buffers->data[i]);
- }
- }
-
- void upload_data_range(vulkan_context * context, VkCommandPool pool, VkFence fence, VkQueue queue,
- vulkan_buffer * buffer, u64 offset, u64 size, void* data) {
- VkBufferUsageFlags flags =
- VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
- vulkan_buffer staging;
- vulkan_buffer_create(context, size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, flags, true, &staging);
- // load data into staging buffer
- printf("Size: %ld\n", size);
- vulkan_buffer_load_data(context, &staging, 0, size, 0, data);
-
- // copy
- vulkan_buffer_copy_to(context, pool, fence, queue, staging.handle, 0, buffer->handle, offset,
- size);
-
- vkDestroyBuffer(context->device.logical_device, staging.handle, context->allocator);
- }
-
- void regenerate_framebuffers(renderer * ren, vulkan_swapchain * swapchain,
- vulkan_renderpass * renderpass) {
- for (u32 i = 0; i < swapchain->image_count; i++) {
- u32 attachment_count = 2; // one for depth, one for colour
-
- VkImageView attachments[2] = { swapchain->views[i], swapchain->depth_attachment.view };
-
- vulkan_framebuffer_create(&context, renderpass, context.framebuffer_width,
- context.framebuffer_height, 2, attachments,
- &swapchain->framebuffers->data[i]);
- }
- }
-
- void vulkan_fence_create(vulkan_context * context, bool create_signaled,
- vulkan_fence* out_fence) {
- out_fence->is_signaled = create_signaled;
- VkFenceCreateInfo fence_create_info = { VK_STRUCTURE_TYPE_FENCE_CREATE_INFO };
- if (out_fence->is_signaled) {
- fence_create_info.flags = VK_FENCE_CREATE_SIGNALED_BIT;
- }
-
- vkCreateFence(context->device.logical_device, &fence_create_info, context->allocator,
- &out_fence->handle);
- }
-
- // TODO: vulkan_fence_destroy
-
- bool vulkan_fence_wait(vulkan_context * context, vulkan_fence * fence, u64 timeout_ns) {
- if (!fence->is_signaled) {
- VkResult result =
- vkWaitForFences(context->device.logical_device, 1, &fence->handle, true, timeout_ns);
- switch (result) {
- case VK_SUCCESS:
- fence->is_signaled = true;
- return true;
- case VK_TIMEOUT:
- WARN("vk_fence_wait - Timed out");
- break;
- default:
- ERROR("vk_fence_wait - Unhanlded error type");
- break;
- }
- } else {
- return true;
- }
-
- return false;
- }
- void vulkan_fence_reset(vulkan_context * context, vulkan_fence * fence) {
- if (fence->is_signaled) {
- vkResetFences(context->device.logical_device, 1, &fence->handle);
- fence->is_signaled = false;
- }
- }
-
- bool gfx_backend_init(renderer * ren) {
- INFO("loading Vulkan backend");
-
- vulkan_state* internal = malloc(sizeof(vulkan_state));
- ren->backend_state = (void*)internal;
-
- context.allocator = 0; // TODO: custom allocator
-
- context.framebuffer_width = SCR_WIDTH;
- context.framebuffer_height = SCR_HEIGHT;
-
- // Setup Vulkan instance
- VkApplicationInfo app_info = { VK_STRUCTURE_TYPE_APPLICATION_INFO };
- app_info.apiVersion = VK_API_VERSION_1_3;
- app_info.pApplicationName = ren->config.window_name;
- app_info.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
- app_info.pEngineName = "Celeritas Engine";
- app_info.engineVersion = VK_MAKE_VERSION(1, 0, 0);
-
- VkInstanceCreateInfo create_info = { VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO };
- create_info.pApplicationInfo = &app_info;
-
- cstr_darray* required_extensions = cstr_darray_new(2);
- cstr_darray_push(required_extensions, VK_KHR_SURFACE_EXTENSION_NAME);
-
- plat_get_required_extension_names(required_extensions);
-
-#if defined(CDEBUG)
- cstr_darray_push(required_extensions, VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
-
- DEBUG("Required extensions:");
- for (u32 i = 0; i < cstr_darray_len(required_extensions); i++) {
- DEBUG(" %s", required_extensions->data[i]);
- }
-#endif
-
- create_info.enabledExtensionCount = cstr_darray_len(required_extensions);
- create_info.ppEnabledExtensionNames = required_extensions->data;
-
- // Validation layers
- create_info.enabledLayerCount = 0;
- create_info.ppEnabledLayerNames = 0;
-#if defined(CDEBUG)
- INFO("Validation layers enabled");
- cstr_darray* desired_validation_layers = cstr_darray_new(1);
- cstr_darray_push(desired_validation_layers, "VK_LAYER_KHRONOS_validation");
-
- u32 n_available_layers = 0;
- VK_CHECK(vkEnumerateInstanceLayerProperties(&n_available_layers, 0));
- TRACE("%d available layers", n_available_layers);
- VkLayerProperties_darray* available_layers = VkLayerProperties_darray_new(n_available_layers);
- VK_CHECK(vkEnumerateInstanceLayerProperties(&n_available_layers, available_layers->data));
-
- for (int i = 0; i < cstr_darray_len(desired_validation_layers); i++) {
- // look through layers to make sure we can find the ones we want
- bool found = false;
- for (int j = 0; j < n_available_layers; j++) {
- if (str8_equals(str8_cstr_view(desired_validation_layers->data[i]),
- str8_cstr_view(available_layers->data[j].layerName))) {
- found = true;
- TRACE("Found layer %s", desired_validation_layers->data[i]);
- break;
- }
- }
-
- if (!found) {
- FATAL("Required validation is missing %s", desired_validation_layers->data[i]);
- return false;
- }
- }
- INFO("All validation layers are present");
- create_info.enabledLayerCount = cstr_darray_len(desired_validation_layers);
- create_info.ppEnabledLayerNames = desired_validation_layers->data;
-#endif
-
- VkResult result = vkCreateInstance(&create_info, NULL, &context.instance);
- if (result != VK_SUCCESS) {
- ERROR("vkCreateInstance failed with result: %u", result);
- return false;
- }
-
- // Debugger
-#if defined(CDEBUG)
- DEBUG("Creating Vulkan debugger")
- u32 log_severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT |
- VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT;
- VkDebugUtilsMessengerCreateInfoEXT debug_create_info = {
- VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT
- };
- debug_create_info.messageSeverity = log_severity;
- debug_create_info.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
- VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT |
- VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT;
- debug_create_info.pfnUserCallback = vk_debug_callback;
-
- PFN_vkCreateDebugUtilsMessengerEXT func =
- (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(context.instance,
- "vkCreateDebugUtilsMessengerEXT");
- assert(func);
- VK_CHECK(func(context.instance, &debug_create_info, context.allocator, &context.vk_debugger));
- DEBUG("Vulkan debugger created");
-
-#endif
-
- // Surface creation
- DEBUG("Create SurfaceKHR")
- VkSurfaceKHR surface;
- VK_CHECK(glfwCreateWindowSurface(context.instance, ren->window, NULL, &surface));
- context.surface = surface;
- DEBUG("Vulkan surface created")
-
- // Device creation
- if (!vulkan_device_create(&context)) {
- FATAL("device creation failed");
- return false;
- }
-
- // Swapchain creation
- vulkan_swapchain_create(&context, SCR_WIDTH, SCR_HEIGHT, &context.swapchain);
-
- // Renderpass creation
- vulkan_renderpass_create(&context, &context.main_renderpass,
- vec4(0, 0, context.framebuffer_width, context.framebuffer_height),
- rgba_to_vec4(COLOUR_SEA_GREEN), 1.0, 0);
-
- // Framebiffers creation
- context.swapchain.framebuffers = vulkan_framebuffer_darray_new(context.swapchain.image_count);
- regenerate_framebuffers(ren, &context.swapchain, &context.main_renderpass);
- INFO("Framebuffers created");
-
- // Command buffers creation
- create_command_buffers(ren);
- INFO("Command buffers created");
-
- // Sync objects
- context.image_available_semaphores =
- calloc(context.swapchain.max_frames_in_flight, sizeof(VkSemaphore));
- context.queue_complete_semaphores =
- calloc(context.swapchain.max_frames_in_flight, sizeof(VkSemaphore));
- context.in_flight_fences = calloc(context.swapchain.max_frames_in_flight, sizeof(vulkan_fence));
-
- for (u8 i = 0; i < context.swapchain.max_frames_in_flight; i++) {
- VkSemaphoreCreateInfo semaphore_create_info = { VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO };
- vkCreateSemaphore(context.device.logical_device, &semaphore_create_info, context.allocator,
- &context.image_available_semaphores[i]);
- vkCreateSemaphore(context.device.logical_device, &semaphore_create_info, context.allocator,
- &context.queue_complete_semaphores[i]);
-
- // create the fence in a signaled state
- vulkan_fence_create(&context, true, &context.in_flight_fences[i]);
- }
-
- context.images_in_flight =
- malloc(sizeof(vulkan_fence*) * context.swapchain.max_frames_in_flight);
- for (u8 i = 0; i < context.swapchain.max_frames_in_flight; i++) {
- context.images_in_flight[i] = 0;
- }
- INFO("Sync objects created");
-
- // Shader modules
- vulkan_object_shader_create(&context, &context.object_shader);
- INFO("Compiled shader modules")
-
- create_buffers(&context);
- INFO("Created buffers");
-
- // TODO: temporary test code
-
- mesh cube = prim_cube_mesh_create();
-
- vertex* verts = malloc(sizeof(vertex) * cube.vertices->len);
-
- f32 scale = 3.0;
- for (size_t i = 0; i < cube.vertices->len; i++) {
- verts[i].position = vec3_mult(cube.vertices->data[i].position, scale);
- verts[i].normal = cube.vertices->data[i].normal;
- verts[i].uv = cube.vertices->data[i].uv;
- }
-
- // const f32 s = 1.0;
- // const u32 vert_count = 4;
- // vertex_pos verts[4] = { 0 };
-
- // verts[0].pos.x = -0.5 * s;
- // verts[0].pos.y = -0.5 * s;
-
- // verts[1].pos.x = 0.5 * s;
- // verts[1].pos.y = 0.5 * s;
-
- // verts[2].pos.x = -0.5 * s;
- // verts[2].pos.y = 0.5 * s;
-
- // verts[3].pos.x = 0.5 * s;
- // verts[3].pos.y = -0.5 * s;
-
- // const u32 index_count = 6;
- // u32 indices[6] = { 0, 1, 2, 0, 3, 1 };
-
- upload_data_range(&context, context.device.gfx_command_pool, 0, context.device.graphics_queue,
- &context.object_vertex_buffer, 0, sizeof(vertex) * cube.vertices->len, verts);
- TRACE("Uploaded vertex data");
- upload_data_range(&context, context.device.gfx_command_pool, 0, context.device.graphics_queue,
- &context.object_index_buffer, 0, sizeof(u32) * cube.indices_len,
- cube.indices);
- TRACE("Uploaded index data");
- vertex_darray_free(cube.vertices);
- free(cube.indices);
-
- // upload texture
-
- // --- End test code
-
- INFO("Vulkan renderer initialisation succeeded");
- return true;
- }
-
- void gfx_backend_shutdown(renderer * ren) {
- DEBUG("Destroying Vulkan debugger");
- if (context.vk_debugger) {
- PFN_vkDestroyDebugUtilsMessengerEXT func =
- (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr(
- context.instance, "vkDestroyDebugUtilsMessengerEXT");
- func(context.instance, context.vk_debugger, context.allocator);
- }
-
- DEBUG("Destroying Vulkan instance...");
- vkDestroyInstance(context.instance, context.allocator);
- }
-
- void backend_begin_frame(renderer * ren, f32 delta_time) {
- vulkan_device* device = &context.device;
-
- // TODO: resize gubbins
-
- if (!vulkan_fence_wait(&context, &context.in_flight_fences[context.current_frame],
- UINT64_MAX)) {
- WARN("In-flight fence wait failure");
- }
-
- if (!vulkan_swapchain_acquire_next_image_index(
- &context, &context.swapchain, UINT64_MAX,
- context.image_available_semaphores[context.current_frame], 0, &context.image_index)) {
- WARN("couldnt acquire swapchain next image");
- }
-
- vulkan_command_buffer* command_buffer = &context.gfx_command_buffers->data[context.image_index];
- vulkan_command_buffer_reset(command_buffer);
- vulkan_command_buffer_begin(command_buffer, false, false, false);
-
- VkViewport viewport;
- viewport.x = 0.0;
- viewport.y = 0;
- viewport.width = (f32)context.framebuffer_width;
- viewport.height = (f32)context.framebuffer_height;
- viewport.minDepth = 0.0;
- viewport.maxDepth = 1.0;
-
- VkRect2D scissor;
- scissor.offset.x = scissor.offset.y = 0;
- scissor.extent.width = context.framebuffer_width;
- scissor.extent.height = context.framebuffer_height;
-
- vkCmdSetViewport(command_buffer->handle, 0, 1, &viewport);
- vkCmdSetScissor(command_buffer->handle, 0, 1, &scissor);
-
- context.main_renderpass.render_area.z = context.framebuffer_width;
- context.main_renderpass.render_area.w = context.framebuffer_height;
-
- vulkan_renderpass_begin(command_buffer, &context.main_renderpass,
- context.swapchain.framebuffers->data[context.image_index].handle);
- }
-
- void texture_data_upload(texture * tex) {
- printf("Texture name %s\n", tex->name);
- tex->backend_data = malloc(sizeof(vulkan_texture_data));
- vulkan_texture_data* data = (vulkan_texture_data*)tex->backend_data;
- printf("Texture (%s) details: \n width %d\n height %d\n channel count %d\n", tex->name,
- tex->width, tex->height, tex->channel_count);
- VkDeviceSize image_size = tex->width * tex->height * max(tex->channel_count, 4);
-
- TRACE("Creating buffer of size %ld", image_size);
-
- VkFormat image_format = VK_FORMAT_R8G8B8A8_SRGB;
-
- VkBufferUsageFlags usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
- VkMemoryPropertyFlags memory_prop_flags =
- VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
- vulkan_buffer staging;
- vulkan_buffer_create(&context, image_size, usage, memory_prop_flags, true, &staging);
- DEBUG("Uploading image data");
- vulkan_buffer_load_data(&context, &staging, 0, image_size, 0, tex->image_data);
- INFO("Loaded iamge data!");
-
- vulkan_image_create(
- &context, VK_IMAGE_TYPE_2D, tex->width, tex->height, image_format, VK_IMAGE_TILING_OPTIMAL,
- VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
- VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
- VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, true, VK_IMAGE_ASPECT_COLOR_BIT, &data->image);
-
- vulkan_command_buffer temp_buffer;
- vulkan_command_buffer_allocate_and_begin_oneshot(&context, context.device.gfx_command_pool,
- &temp_buffer);
-
- vulkan_image_transition_layout(&context, &temp_buffer, &data->image, image_format,
- VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
-
- vulkan_image_copy_from_buffer(&data->image, staging.handle, &temp_buffer);
-
- vulkan_image_transition_layout(&context, &temp_buffer, &data->image, image_format,
- VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
- VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
-
- vulkan_command_buffer_end_oneshot(&context, context.device.gfx_command_pool, &temp_buffer,
- context.device.graphics_queue);
-
- VkSamplerCreateInfo sampler_info = { VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO };
- sampler_info.magFilter = VK_FILTER_LINEAR;
- sampler_info.minFilter = VK_FILTER_LINEAR;
- sampler_info.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
- sampler_info.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
- sampler_info.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
- sampler_info.anisotropyEnable = VK_TRUE;
- sampler_info.maxAnisotropy = 16;
- sampler_info.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK;
- sampler_info.unnormalizedCoordinates = VK_FALSE;
- sampler_info.compareEnable = VK_FALSE;
- sampler_info.compareOp = VK_COMPARE_OP_ALWAYS;
- sampler_info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
- sampler_info.mipLodBias = 0.0;
- sampler_info.minLod = 0.0;
- sampler_info.maxLod = 0.0;
-
- VkResult res = vkCreateSampler(context.device.logical_device, &sampler_info, context.allocator,
- &data->sampler);
- if (res != VK_SUCCESS) {
- ERROR("Error creating texture sampler for image %s", tex->name);
- return;
- }
-
- tex->image_data = (void*)data;
- }
-
- // TODO: destroy texture
-
- void backend_end_frame(renderer * ren, f32 delta_time) {
- vulkan_command_buffer* command_buffer = &context.gfx_command_buffers->data[context.image_index];
-
- vulkan_renderpass_end(command_buffer, &context.main_renderpass);
-
- vulkan_command_buffer_end(command_buffer);
-
- // TODO: wait on fence - https://youtu.be/hRL71D1f3pU?si=nLJx-ZsemDBeQiQ1&t=1037
-
- context.images_in_flight[context.image_index] =
- &context.in_flight_fences[context.current_frame];
-
- vulkan_fence_reset(&context, &context.in_flight_fences[context.current_frame]);
-
- VkSubmitInfo submit_info = { VK_STRUCTURE_TYPE_SUBMIT_INFO };
- submit_info.commandBufferCount = 1;
- submit_info.pCommandBuffers = &command_buffer->handle;
- submit_info.signalSemaphoreCount = 1;
- submit_info.pSignalSemaphores = &context.queue_complete_semaphores[context.current_frame];
- submit_info.waitSemaphoreCount = 1;
- submit_info.pWaitSemaphores = &context.image_available_semaphores[context.current_frame];
-
- VkPipelineStageFlags flags[1] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
- submit_info.pWaitDstStageMask = flags;
-
- VkResult result = vkQueueSubmit(context.device.graphics_queue, 1, &submit_info,
- context.in_flight_fences[context.current_frame].handle);
-
- if (result != VK_SUCCESS) {
- ERROR("queue submission failed. fark.");
- }
-
- vulkan_command_buffer_update_submitted(command_buffer);
-
- vulkan_swapchain_present(
- &context, &context.swapchain, context.device.graphics_queue, context.device.graphics_queue,
- context.queue_complete_semaphores[context.current_frame], context.image_index);
- }
-
- void gfx_backend_draw_frame(renderer * ren, camera * cam, mat4 model, texture * tex) {
- backend_begin_frame(ren, 16.0);
-
- mat4 proj;
- mat4 view;
-
- camera_view_projection(cam, SCR_HEIGHT, SCR_WIDTH, &view, &proj);
-
- context.object_shader.texture_data = (vulkan_texture_data*)tex->image_data;
- gfx_backend_update_global_state(proj, view, cam->position, vec4(1.0, 1.0, 1.0, 1.0), 0);
-
- vulkan_object_shader_update_object(&context, &context.object_shader, model);
-
- backend_end_frame(ren, 16.0);
- }
-
- void gfx_backend_update_global_state(mat4 projection, mat4 view, vec3 view_pos,
- vec4 ambient_colour, i32 mode) {
- vulkan_object_shader_use(&context, &context.object_shader);
-
- vulkan_object_shader_update_global_state(&context, &context.object_shader);
- context.object_shader.global_ubo.projection = projection;
- context.object_shader.global_ubo.view = view;
- // TODO: other UBO properties
- }
-
- void clear_screen(vec3 colour) {}
-
- void bind_texture(shader s, texture * tex, u32 slot) {}
- void bind_mesh_vertex_buffer(void* backend, mesh* mesh) {}
- void draw_primitives(cel_primitive_topology primitive, u32 start_index, u32 count) {}
-
- shader shader_create_separate(const char* vert_shader, const char* frag_shader) {}
- void set_shader(shader s) {}
-
- void uniform_vec3f(u32 program_id, const char* uniform_name, vec3* value) {}
- void uniform_f32(u32 program_id, const char* uniform_name, f32 value) {}
- void uniform_i32(u32 program_id, const char* uniform_name, i32 value) {}
- void uniform_mat4f(u32 program_id, const char* uniform_name, mat4* value) {}
-
- VKAPI_ATTR VkBool32 VKAPI_CALL vk_debug_callback(
- VkDebugUtilsMessageSeverityFlagBitsEXT severity, VkDebugUtilsMessageTypeFlagsEXT flags,
- const VkDebugUtilsMessengerCallbackDataEXT* callback_data, void* user_data) {
- switch (severity) {
- default:
- case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT:
- ERROR("%s", callback_data->pMessage);
- break;
- case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT:
- WARN("%s", callback_data->pMessage);
- break;
- case VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT:
- INFO("%s", callback_data->pMessage);
- break;
- case VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT:
- TRACE("%s", callback_data->pMessage);
- break;
- }
- return VK_FALSE;
- }
-
-#endif \ No newline at end of file
+// --- Drawing
+inline void encode_draw_indexed(gpu_cmd_encoder* encoder, u64 index_count) {
+ vkCmdDrawIndexed(encoder->cmd_buffer, index_count, 1, 0, 0, 0);
+} \ No newline at end of file
diff --git a/src/renderer/cleanroom/backend_vulkan.h b/src/renderer/backends/backend_vulkan.h
index c8d5777..05f043e 100644
--- a/src/renderer/cleanroom/backend_vulkan.h
+++ b/src/renderer/backends/backend_vulkan.h
@@ -1,5 +1,5 @@
#pragma once
-#include "cleanroom/ral.h"
+#include "defines.h"
#define GPU_SWAPCHAIN_IMG_COUNT 2
@@ -20,7 +20,6 @@ typedef struct gpu_pipeline {
typedef struct gpu_renderpass {
VkRenderPass vk_handle;
VkFramebuffer framebuffers[GPU_SWAPCHAIN_IMG_COUNT];
- u32
} gpu_renderpass;
typedef struct gpu_cmd_encoder {
diff --git a/src/renderer/cleanroom/backend_vulkan.c b/src/renderer/cleanroom/backend_vulkan.c
deleted file mode 100644
index 71a09f3..0000000
--- a/src/renderer/cleanroom/backend_vulkan.c
+++ /dev/null
@@ -1,65 +0,0 @@
-#include <stdlib.h>
-#include "ral.h"
-#include "types.h"
-// #include "render_types.h"
-
-#define VULKAN_QUEUES_COUNT 2
-const char* queue_names[VULKAN_QUEUES_COUNT] = { "GRAPHICS", "TRANSFER" };
-
-typedef struct gpu_device {
-} gpu_device;
-
-typedef struct vulkan_context {
- gpu_device device;
-
- VkInstance instance;
-
-} vulkan_context;
-
-static vulkan_context context;
-
-static bool select_physical_device(gpu_device* out_device) {}
-
-bool gpu_device_create(gpu_device* out_device) {
- // Physical device
- if (!select_physical_device(out_device)) {
- return false;
- }
- INFO("Physical device selected");
-
- // Logical device
- VkDeviceQueueCreateInfo queue_create_info[2];
- //..
- VkDeviceCreateInfo device_create_info = { VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO };
-
- VkResult result = vkCreateDevice();
- if (result != VK_SUCCESS) {
- FATAL("Error creating logical device with status %u\n", result);
- exit(1);
- }
- INFO("Logical device created");
-
- // Queues
-
- // Create the command pool
-}
-
-gpu_renderpass* gpu_renderpass_create() {
- // Allocate it
- // sets everything up
- // return pointer to it
-}
-
-void encode_set_pipeline(gpu_cmd_encoder* encoder, pipeline_type kind, gpu_pipeline* pipeline) {
- // VK_PIPELINE_BIND_POINT_GRAPHICS, &shader->pipeline);
- if (kind == PIPELINE_GRAPHICS) {
- // ...
- } else {
- // ...
- }
-}
-
-// --- Drawing
-inline void encode_draw_indexed(gpu_cmd_encoder* encoder, u64 index_count) {
- vkCmdDrawIndexed(encoder->cmd_buffer, index_count, 1, 0, 0, 0);
-} \ No newline at end of file
diff --git a/src/renderer/cleanroom/types.h b/src/renderer/cleanroom/types.h
index 0a28b1c..7360ebe 100644
--- a/src/renderer/cleanroom/types.h
+++ b/src/renderer/cleanroom/types.h
@@ -4,63 +4,3 @@
#include "maths_types.h"
#include "str.h"
#include "render_types.h"
-
-// typedef struct transform_hierarchy {
-// } transform_hierarchy;
-
-
-/*
- - render_types.h
- - ral_types.h
- - ral.h
- - render.h ?
-*/
-
-/* render_types */
-typedef struct model pbr_material;
-typedef struct model bp_material; // blinn-phong
-
-
-// ? How to tie together materials and shaders
-
-// Three registers
-// 1. low level graphics api calls "ral"
-// 2. higher level render calls
-// 3. simplified immediate mode API
-
-// 3 - you don't need to know how the renderer works at all
-// 2 - you need to know how the overall renderer is designed
-// 1 - you need to understand graphics API specifics
-
-/* ral.h */
-
-// command buffer gubbins
-
-/* --- Backends */
-
-// struct vulkan_backend {
-// gpu_pipeline static_opaque_pipeline;
-// gpu_pipeline skinned_opaque_pipeline;
-// };
-
-/* --- Renderer layer */
-/* render.h */
-
-
-// Drawing
-
-// void draw_mesh(gpu_cmd_encoder* encoder, mesh* mesh) {
-// encode_set_vertex_buffer(encoder, mesh->vertex_buffer);
-// encode_set_index_buffer(encoder, mesh->index_buffer);
-// encode_draw_indexed(encoder, mesh->index_count)
-// // vkCmdDrawIndexed
-// }
-
-// void draw_scene(arena* frame, model_darray* models, renderer* ren, camera* camera,
-// transform_hierarchy* tfh, scene* scene) {
-// // set the pipeline first
-// encode_set_pipeline()
-// // in open this sets the shader
-// // in vulkan it sets the whole pipeline
-
-// } \ No newline at end of file
diff --git a/src/renderer/cleanroom/immediate.c b/src/renderer/immediate.c
index 8e4bf7e..e76d102 100644
--- a/src/renderer/cleanroom/immediate.c
+++ b/src/renderer/immediate.c
@@ -1,8 +1,8 @@
#include "immediate.h"
#include "maths.h"
#include "primitives.h"
+#include "ral_types.h"
#include "render.h"
-#include "types.h"
void imm_draw_sphere(vec3 pos, f32 radius, vec4 colour) {
// Create the vertices
diff --git a/src/renderer/cleanroom/immediate.h b/src/renderer/immediate.h
index 6d93c53..6d93c53 100644
--- a/src/renderer/cleanroom/immediate.h
+++ b/src/renderer/immediate.h
diff --git a/src/renderer/ral.h b/src/renderer/ral.h
index fd83e76..fb77f0a 100644
--- a/src/renderer/ral.h
+++ b/src/renderer/ral.h
@@ -23,10 +23,10 @@ typedef struct gpu_renderpass gpu_renderpass;
typedef struct gpu_cmd_encoder gpu_cmd_encoder; // Recording
typedef struct gpu_cmd_buffer gpu_cmd_buffer; // Ready for submission
-enum pipeline_kind {
- GRAPHICS,
- COMPUTE,
-};
+typedef enum pipeline_kind {
+ PIPELINE_GRAPHICS,
+ PIPELINE_COMPUTE,
+} pipeline_kind;
typedef struct shader_desc {
const char* debug_name;
@@ -40,7 +40,7 @@ struct pipeline_desc {
};
// lifecycle functions
-gpu_device* gpu_device_create();
+gpu_device gpu_device_create();
void gpu_device_destroy();
gpu_renderpass* gpu_renderpass_create();
diff --git a/src/renderer/ral_types.h b/src/renderer/ral_types.h
index 9b1ef62..a20e600 100644
--- a/src/renderer/ral_types.h
+++ b/src/renderer/ral_types.h
@@ -90,4 +90,48 @@ typedef union vertex {
KITC_DECL_TYPED_ARRAY(vertex)
KITC_DECL_TYPED_ARRAY(u32)
#define TYPED_VERTEX_ARRAY
-#endif \ No newline at end of file
+#endif
+
+// ? How to tie together materials and shaders
+
+// Three registers
+// 1. low level graphics api calls "ral"
+// 2. higher level render calls
+// 3. simplified immediate mode API
+
+// 3 - you don't need to know how the renderer works at all
+// 2 - you need to know how the overall renderer is designed
+// 1 - you need to understand graphics API specifics
+
+/* ral.h */
+
+// command buffer gubbins
+
+/* --- Backends */
+
+// struct vulkan_backend {
+// gpu_pipeline static_opaque_pipeline;
+// gpu_pipeline skinned_opaque_pipeline;
+// };
+
+/* --- Renderer layer */
+/* render.h */
+
+
+// Drawing
+
+// void draw_mesh(gpu_cmd_encoder* encoder, mesh* mesh) {
+// encode_set_vertex_buffer(encoder, mesh->vertex_buffer);
+// encode_set_index_buffer(encoder, mesh->index_buffer);
+// encode_draw_indexed(encoder, mesh->index_count)
+// // vkCmdDrawIndexed
+// }
+
+// void draw_scene(arena* frame, model_darray* models, renderer* ren, camera* camera,
+// transform_hierarchy* tfh, scene* scene) {
+// // set the pipeline first
+// encode_set_pipeline()
+// // in open this sets the shader
+// // in vulkan it sets the whole pipeline
+
+// } \ No newline at end of file
diff --git a/src/renderer/render.c b/src/renderer/render.c
index d6b77c0..034585a 100644
--- a/src/renderer/render.c
+++ b/src/renderer/render.c
@@ -52,4 +52,6 @@ void render_frame_begin(renderer* ren) {}
void render_frame_end(renderer* ren) {}
void render_frame_draw(renderer* ren) {}
-void gfx_backend_draw_frame(renderer* ren, camera* camera, mat4 model, texture* tex) {} \ No newline at end of file
+void gfx_backend_draw_frame(renderer* ren, camera* camera, mat4 model, texture* tex) {}
+
+void geo_set_vertex_colours(geometry_data* geo, vec4 colour) {} \ No newline at end of file
diff --git a/src/renderer/render.h b/src/renderer/render.h
index 0aeeac2..a5a5928 100644
--- a/src/renderer/render.h
+++ b/src/renderer/render.h
@@ -40,4 +40,6 @@ void shader_hot_reload(const char* filepath);
// models and meshes are implemented **in terms of the above**
mesh mesh_create(geometry_data* geometry);
-model_handle model_load(const char* debug_name, const char* filepath); \ No newline at end of file
+model_handle model_load(const char* debug_name, const char* filepath);
+
+void geo_set_vertex_colours(geometry_data* geo, vec4 colour); \ No newline at end of file
diff --git a/src/renderer/render_types.h b/src/renderer/render_types.h
index bc9692f..5faefad 100644
--- a/src/renderer/render_types.h
+++ b/src/renderer/render_types.h
@@ -41,8 +41,6 @@ typedef struct geometry_data {
vec3 colour; /** Optional: set vertex colours */
} geometry_data;
-void geo_set_vertex_colours(geometry_data* geo, vec4 colour);
-
typedef struct mesh {
buffer_handle vertex_buffer;
buffer_handle index_buffer;
diff --git a/src/systems/screenspace.h b/src/systems/screenspace.h
index f513148..5f0c579 100644
--- a/src/systems/screenspace.h
+++ b/src/systems/screenspace.h
@@ -25,7 +25,7 @@ struct draw_circle {
/** @brief Tagged union that represents a UI shape to be drawn. */
typedef struct draw_cmd {
- enum { RECT, CIRCLE } draw_cmd_type;
+ enum { DRAW_RECT, CIRCLE } draw_cmd_type;
union {
struct draw_rect rect;
struct draw_circle circle;
diff --git a/xmake.lua b/xmake.lua
index 0fc042c..6fee04a 100644
--- a/xmake.lua
+++ b/xmake.lua
@@ -1,6 +1,6 @@
set_project("celeritas")
set_version("0.1.0")
-set_config("cc", "clang")
+set_config("cc", "clang-cl")
add_rules("mode.debug", "mode.release") -- we have two modes: debug & release
@@ -25,6 +25,8 @@ if is_plat("linux") then
elseif is_plat("windows") then
add_defines("CEL_PLATFORM_WINDOWS")
add_syslinks("user32", "gdi32", "kernel32", "shell32")
+ add_requires("vulkansdk", {system=true})
+
-- add_links("pthreadVC2-w64")
elseif is_plat("macosx") then
add_defines("CEL_PLATFORM_MAC")
@@ -55,6 +57,7 @@ local core_sources = {
"deps/glad/src/glad.c",
"src/*.c",
-- "src/logos/*.c",
+ "src/maths/*.c",
"src/platform/*.c",
"src/renderer/*.c",
"src/renderer/backends/*.c",
@@ -84,6 +87,8 @@ rule("compile_glsl_frag_shaders")
end)
-- TODO: Metal shaders compilation
+--
+
-- common configuration for both static and shared libraries
target("core_config")
set_kind("static") -- kind is required but you can ignore it since it's just for common settings
@@ -100,7 +105,6 @@ target("core_config")
add_includedirs("src/platform/", {public = true})
add_includedirs("src/renderer/", {public = true})
add_includedirs("src/renderer/backends/", {public = true})
- -- add_includedirs("src/renderer/cleanroom/", {public = true})
add_includedirs("src/resources/", {public = true})
add_includedirs("src/std/", {public = true})
add_includedirs("src/std/containers", {public = true})
@@ -111,6 +115,11 @@ target("core_config")
-- add_files("assets/shaders/object.vert")
-- add_files("assets/shaders/object.frag")
-- add_files("assets/shaders/*.frag")
+ if is_plat("windows") then
+ add_includedirs("$(env VULKAN_SDK)/Include", {public = true})
+ add_linkdirs("$(env VULKAN_SDK)/Lib", {public = true})
+ add_links("vulkan-1")
+ end
set_default(false) -- prevents standalone building of this target
target("core_static")
@@ -132,7 +141,6 @@ target("core_shared")
if is_plat("windows") then
add_links("msvcrt", "legacy_stdio_definitions") -- for release builds
add_links("msvcrtd", "legacy_stdio_definitions") -- for debug builds
- -- add_links("pthreadVC2-w64")
end
target("main_loop")