summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOmniscient <17525998+omnisci3nce@users.noreply.github.com>2024-03-30 23:15:36 +1100
committerOmniscient <17525998+omnisci3nce@users.noreply.github.com>2024-03-30 23:15:36 +1100
commitf26f084958550cd01b9e4e4b098551520a4c6852 (patch)
tree1b835288f94461ba86aca8cff723d3364556db52
parentb4cb698d177ada97c976eab059eabedd433abfd0 (diff)
parentc20740ecbb008afbe93c7fa1eb35851cedc6eb42 (diff)
Merge branch 'cel-60-scaffold-vulkan' into cleanroom-vulkan
-rw-r--r--assets/shaders/object.frag (renamed from assets/shaders/triangle.frag)0
-rw-r--r--assets/shaders/object.vert20
-rw-r--r--assets/shaders/triangle.vert6
-rw-r--r--examples/input/ex_input.c111
-rw-r--r--examples/main_loop/ex_main_loop.c7
-rw-r--r--src/core.c17
-rw-r--r--src/core.h1
-rw-r--r--src/maths/maths.h3
-rw-r--r--src/renderer/backends/backend_vulkan.c662
-rw-r--r--src/renderer/backends/vulkan/vulkan_glossary.md18
-rw-r--r--src/renderer/render.c6
-rw-r--r--src/renderer/render_backend.h5
-rw-r--r--src/systems/input.c19
-rw-r--r--src/systems/keys.h15
-rw-r--r--xmake.lua22
15 files changed, 851 insertions, 61 deletions
diff --git a/assets/shaders/triangle.frag b/assets/shaders/object.frag
index 44c1eb3..44c1eb3 100644
--- a/assets/shaders/triangle.frag
+++ b/assets/shaders/object.frag
diff --git a/assets/shaders/object.vert b/assets/shaders/object.vert
new file mode 100644
index 0000000..a5097d4
--- /dev/null
+++ b/assets/shaders/object.vert
@@ -0,0 +1,20 @@
+#version 450
+#extension GL_ARB_separate_shader_objects : enable
+
+layout(location = 0) in vec3 in_position;
+
+layout(set = 0, binding = 0) uniform global_object_uniform {
+ mat4 projection;
+ mat4 view;
+}
+global_ubo;
+
+layout(push_constant) uniform push_constants {
+ mat4 model; // 64 bytes
+}
+u_push_constants;
+
+void main() {
+ gl_Position =
+ global_ubo.projection * global_ubo.view * u_push_constants.model * vec4(in_position, 1.0);
+} \ No newline at end of file
diff --git a/assets/shaders/triangle.vert b/assets/shaders/triangle.vert
deleted file mode 100644
index f253d9b..0000000
--- a/assets/shaders/triangle.vert
+++ /dev/null
@@ -1,6 +0,0 @@
-#version 450
-#extension GL_ARB_separate_shader_objects : enable
-
-layout(location = 0) in vec3 in_position;
-
-void main() { gl_Position = vec4(in_position, 1.0); } \ No newline at end of file
diff --git a/examples/input/ex_input.c b/examples/input/ex_input.c
new file mode 100644
index 0000000..7ead3ec
--- /dev/null
+++ b/examples/input/ex_input.c
@@ -0,0 +1,111 @@
+#include <glfw3.h>
+
+#include "camera.h"
+#include "core.h"
+#include "input.h"
+#include "keys.h"
+#include "maths.h"
+#include "maths_types.h"
+#include "render.h"
+#include "render_backend.h"
+
+typedef struct game_state {
+ camera camera;
+ vec3 camera_euler;
+ bool first_mouse_update; // so the camera doesnt lurch when you run the first process_camera_rotation
+} game_state;
+
+void update_camera_rotation(input_state* input, game_state* game, camera* cam);
+
+int main() {
+ core* core = core_bringup();
+
+ game_state game = {
+ .camera = camera_create(vec3_create(0, 0, 30), vec3_create(0, 0, -1), VEC3_Y, deg_to_rad(45.0)),
+ .camera_euler = vec3_create(90, 0, 0),
+ .first_mouse_update = true,
+ };
+
+ printf("Starting look direction: ");
+ print_vec3(game.camera.front);
+
+ // Main loop
+ const f32 camera_speed = 0.4;
+
+ while (!should_exit(core)) {
+ input_update(&core->input);
+
+ vec3 translation = VEC3_ZERO;
+ if (key_is_pressed(KEYCODE_W) || key_is_pressed(KEYCODE_KEY_UP)) {
+ printf("Move Forwards\n");
+ translation = vec3_mult(game.camera.front, camera_speed);
+ } else if (key_is_pressed(KEYCODE_S) || key_is_pressed(KEYCODE_KEY_DOWN)) {
+ printf("Move Backwards\n");
+ translation = vec3_mult(game.camera.front, -camera_speed);
+ } else if (key_is_pressed(KEYCODE_A) || key_is_pressed(KEYCODE_KEY_LEFT)) {
+ printf("Move Left\n");
+ vec3 lateral = vec3_normalise(vec3_cross(game.camera.front, game.camera.up));
+ translation = vec3_mult(lateral, -camera_speed);
+ } else if (key_is_pressed(KEYCODE_D) || key_is_pressed(KEYCODE_KEY_RIGHT)) {
+ printf("Move Right\n");
+ vec3 lateral = vec3_normalise(vec3_cross(game.camera.front, game.camera.up));
+ translation = vec3_mult(lateral, camera_speed);
+ }
+ game.camera.position = vec3_add(game.camera.position, translation);
+ update_camera_rotation(&core->input, &game, &game.camera);
+
+ // UNUSED: threadpool_process_results(&core->threadpool, 1);
+
+ render_frame_begin(&core->renderer);
+
+ mat4 model = mat4_translation(VEC3_ZERO);
+
+ gfx_backend_draw_frame(&core->renderer, &game.camera, model);
+
+ render_frame_end(&core->renderer);
+ }
+
+ core_shutdown(core);
+
+ return 0;
+}
+
+void update_camera_rotation(input_state* input, game_state* game, camera* cam) {
+ float xoffset = -input->mouse.x_delta; // xpos - lastX;
+ float yoffset = -input->mouse.y_delta; // reversed since y-coordinates go from bottom to top
+ if (game->first_mouse_update) {
+ xoffset = 0.0;
+ yoffset = 0.0;
+ game->first_mouse_update = false;
+ }
+
+ float sensitivity = 0.1f; // change this value to your liking
+ xoffset *= sensitivity;
+ yoffset *= sensitivity;
+
+ // x = yaw
+ game->camera_euler.x += xoffset;
+ // y = pitch
+ game->camera_euler.y += yoffset;
+ // we dont update roll
+
+ f32 yaw = game->camera_euler.x;
+ f32 pitch = game->camera_euler.y;
+
+ // make sure that when pitch is out of bounds, screen doesn't get flipped
+ if (game->camera_euler.y > 89.0f) game->camera_euler.y = 89.0f;
+ if (game->camera_euler.y < -89.0f) game->camera_euler.y = -89.0f;
+
+ vec3 front = cam->front;
+ front.x = cos(deg_to_rad(yaw) * cos(deg_to_rad(pitch)));
+ front.y = sin(deg_to_rad(pitch));
+ front.z = sin(deg_to_rad(yaw)) * cos(deg_to_rad(pitch));
+
+ front = vec3_normalise(front);
+ // save it back
+ cam->front.x = front.x;
+ cam->front.y = front.y;
+ // roll is static
+
+ print_vec3(cam->front);
+}
diff --git a/examples/main_loop/ex_main_loop.c b/examples/main_loop/ex_main_loop.c
index 728290f..25dbf4a 100644
--- a/examples/main_loop/ex_main_loop.c
+++ b/examples/main_loop/ex_main_loop.c
@@ -1,6 +1,7 @@
#include <glfw3.h>
#include "core.h"
+#include "maths.h"
#include "render.h"
#include "render_backend.h"
@@ -14,7 +15,11 @@ int main() {
render_frame_begin(&core->renderer);
- gfx_backend_draw_frame(&core->renderer);
+ static f32 x = 0.0;
+ x += 0.01;
+ mat4 model = mat4_translation(vec3(x, 0, 0));
+
+ gfx_backend_draw_frame(&core->renderer, model);
// insert work here
diff --git a/src/core.c b/src/core.c
index 024b2d7..0db8962 100644
--- a/src/core.c
+++ b/src/core.c
@@ -2,13 +2,16 @@
#include <stdlib.h>
+#include "glfw3.h"
+#include "input.h"
+#include "keys.h"
#include "log.h"
#include "render.h"
#include "render_types.h"
#include "threadpool.h"
-#define SCR_WIDTH 1080
-#define SCR_HEIGHT 800
+#define SCR_WIDTH 1000
+#define SCR_HEIGHT 1000
core* core_bringup() {
INFO("Initiate Core bringup");
@@ -49,3 +52,13 @@ core* core_bringup() {
return c;
}
+
+void core_shutdown(core* core) {
+ // threadpool_destroy(&core->threadpool);
+ input_system_shutdown(&core->input);
+ renderer_shutdown(&core->renderer);
+}
+
+bool should_exit(core* core) {
+ return key_just_released(KEYCODE_ESCAPE) || glfwWindowShouldClose(core->renderer.window);
+} \ No newline at end of file
diff --git a/src/core.h b/src/core.h
index f54631e..05e3aed 100644
--- a/src/core.h
+++ b/src/core.h
@@ -20,5 +20,6 @@ typedef struct core {
// --- Lifecycle
core* core_bringup();
void core_shutdown(core* core);
+bool should_exit(core* core);
void core_input_update(core* core);
diff --git a/src/maths/maths.h b/src/maths/maths.h
index db63072..41fbdfc 100644
--- a/src/maths/maths.h
+++ b/src/maths/maths.h
@@ -9,6 +9,7 @@
#pragma once
#include <math.h>
+#include <stdio.h>
#include "maths_types.h"
// --- Helpers
@@ -48,6 +49,8 @@ static inline vec3 vec3_cross(vec3 a, vec3 b) {
#define VEC3_Z ((vec3){ .x = 0.0, .y = 0.0, .z = 1.0 })
#define VEC3_NEG_Z ((vec3){ .x = 0.0, .y = 0.0, .z = -1.0 })
+static inline void print_vec3(vec3 v) { printf("{ x: %f, y: %f, z: %f )\n", v.x, v.y, v.z); }
+
// TODO: Dimension 2
static inline vec2 vec2_create(f32 x, f32 y) { return (vec2){ x, y }; }
diff --git a/src/renderer/backends/backend_vulkan.c b/src/renderer/backends/backend_vulkan.c
index d78d4d2..43ea658 100644
--- a/src/renderer/backends/backend_vulkan.c
+++ b/src/renderer/backends/backend_vulkan.c
@@ -1,12 +1,17 @@
+#include "camera.h"
+#define CDEBUG
+#define CEL_PLATFORM_LINUX
+// ^ Temporary
+
+#include <assert.h>
+#include <stdatomic.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
-#include "colours.h"
-#define CEL_PLATFORM_LINUX
-#include <assert.h>
#include <vulkan/vk_platform.h>
#include <vulkan/vulkan.h>
#include <vulkan/vulkan_core.h>
+#include "colours.h"
#include "str.h"
#include "darray.h"
@@ -21,8 +26,8 @@
#include <stdlib.h>
-#define SCR_WIDTH 1080
-#define SCR_HEIGHT 800
+#define SCR_WIDTH 1000
+#define SCR_HEIGHT 1000
#if CEL_REND_BACKEND_VULKAN
@@ -129,12 +134,38 @@ typedef struct vulkan_pipeline {
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 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;
} vulkan_shader;
typedef struct vulkan_context {
@@ -146,6 +177,11 @@ typedef struct vulkan_context {
u32 framebuffer_height;
vulkan_swapchain swapchain;
vulkan_renderpass main_renderpass;
+ vulkan_buffer object_vertex_buffer;
+ vulkan_buffer object_index_buffer;
+ u64 geometry_vertex_offset;
+ u64 geometry_index_offset;
+
vulkan_command_buffer_darray* gfx_command_buffers;
VkSemaphore* image_available_semaphores;
@@ -168,16 +204,257 @@ typedef struct vulkan_context {
static vulkan_context context;
+static i32 find_memory_index(vulkan_context* context, u32 type_filter, u32 property_flags) {
+ VkPhysicalDeviceMemoryProperties memory_properties;
+ vkGetPhysicalDeviceMemoryProperties(context->device.physical_device, &memory_properties);
+
+ for (u32 i = 0; i < memory_properties.memoryTypeCount; ++i) {
+ // Check each memory type to see if its bit is set to 1.
+ if (type_filter & (1 << i) &&
+ (memory_properties.memoryTypes[i].propertyFlags & property_flags) == property_flags) {
+ return i;
+ }
+ }
+
+ WARN("Unable to find suitable memory type!");
+ return -1;
+}
+
/** @brief Internal backend state */
typedef struct vulkan_state {
} vulkan_state;
+typedef struct vertex_pos {
+ vec3 pos;
+} vertex_pos;
+
// pipeline stuff
bool vulkan_graphics_pipeline_create(vulkan_context* context, vulkan_renderpass* renderpass,
u32 attribute_count,
VkVertexInputAttributeDescription* attributes,
- // ... https://youtu.be/OmPmftW7Kjg?si=qn_777v_ppHKzswK&t=568
-) {}
+ u32 descriptor_set_layout_count,
+ VkDescriptorSetLayout* descriptor_set_layouts, u32 stage_count,
+ VkPipelineShaderStageCreateInfo* stages, VkViewport viewport,
+ VkRect2D scissor, bool is_wireframe,
+ vulkan_pipeline* out_pipeline) {
+ VkPipelineViewportStateCreateInfo viewport_state = {
+ VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO
+ };
+ viewport_state.viewportCount = 1;
+ viewport_state.pViewports = &viewport;
+ viewport_state.scissorCount = 1;
+ viewport_state.pScissors = &scissor;
+
+ // Rasterizer
+ VkPipelineRasterizationStateCreateInfo rasterizer_create_info = {
+ VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO
+ };
+ rasterizer_create_info.depthClampEnable = VK_FALSE;
+ rasterizer_create_info.rasterizerDiscardEnable = VK_FALSE;
+ rasterizer_create_info.polygonMode = is_wireframe ? VK_POLYGON_MODE_LINE : VK_POLYGON_MODE_FILL;
+ rasterizer_create_info.lineWidth = 1.0f;
+ rasterizer_create_info.cullMode = VK_CULL_MODE_BACK_BIT;
+ rasterizer_create_info.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
+ rasterizer_create_info.depthBiasEnable = VK_FALSE;
+ rasterizer_create_info.depthBiasConstantFactor = 0.0;
+ rasterizer_create_info.depthBiasClamp = 0.0;
+ rasterizer_create_info.depthBiasSlopeFactor = 0.0;
+
+ // Multisampling
+ VkPipelineMultisampleStateCreateInfo ms_create_info = {
+ VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO
+ };
+ ms_create_info.sampleShadingEnable = VK_FALSE;
+ ms_create_info.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
+ ms_create_info.minSampleShading = 1.0;
+ ms_create_info.pSampleMask = 0;
+ ms_create_info.alphaToCoverageEnable = VK_FALSE;
+ ms_create_info.alphaToOneEnable = VK_FALSE;
+
+ // Depth and stencil testing
+ VkPipelineDepthStencilStateCreateInfo depth_stencil = {
+ VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO
+ };
+ depth_stencil.depthTestEnable = VK_TRUE;
+ depth_stencil.depthWriteEnable = VK_TRUE;
+ depth_stencil.depthCompareOp = VK_COMPARE_OP_LESS;
+ depth_stencil.depthBoundsTestEnable = VK_FALSE;
+ depth_stencil.stencilTestEnable = VK_FALSE;
+ depth_stencil.pNext = 0;
+
+ VkPipelineColorBlendAttachmentState color_blend_attachment_state;
+ color_blend_attachment_state.blendEnable = VK_TRUE;
+ color_blend_attachment_state.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
+ color_blend_attachment_state.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
+ color_blend_attachment_state.colorBlendOp = VK_BLEND_OP_ADD;
+ color_blend_attachment_state.srcAlphaBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
+ color_blend_attachment_state.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
+ color_blend_attachment_state.alphaBlendOp = VK_BLEND_OP_ADD;
+ color_blend_attachment_state.colorWriteMask = VK_COLOR_COMPONENT_R_BIT |
+ VK_COLOR_COMPONENT_G_BIT |
+ VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
+
+ VkPipelineColorBlendStateCreateInfo color_blend = {
+ VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO
+ };
+ color_blend.logicOpEnable = VK_FALSE;
+ color_blend.logicOp = VK_LOGIC_OP_COPY;
+ color_blend.attachmentCount = 1;
+ color_blend.pAttachments = &color_blend_attachment_state;
+
+ const u32 dynamic_state_count = 3;
+ VkDynamicState dynamic_states[3] = {
+ VK_DYNAMIC_STATE_VIEWPORT,
+ VK_DYNAMIC_STATE_SCISSOR,
+ VK_DYNAMIC_STATE_LINE_WIDTH,
+ };
+
+ VkPipelineDynamicStateCreateInfo dynamic_state = {
+ VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO
+ };
+ dynamic_state.dynamicStateCount = dynamic_state_count;
+ dynamic_state.pDynamicStates = dynamic_states;
+
+ // Vertex input
+ VkVertexInputBindingDescription binding_desc;
+ binding_desc.binding = 0;
+ binding_desc.stride = sizeof(vertex_pos);
+ binding_desc.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
+
+ VkPipelineVertexInputStateCreateInfo vertex_input_info = {
+ VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO
+ };
+ vertex_input_info.vertexBindingDescriptionCount = 1;
+ vertex_input_info.pVertexBindingDescriptions = &binding_desc;
+ vertex_input_info.vertexAttributeDescriptionCount = attribute_count;
+ vertex_input_info.pVertexAttributeDescriptions = attributes;
+
+ VkPipelineInputAssemblyStateCreateInfo input_assembly = {
+ VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO
+ };
+ input_assembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
+ input_assembly.primitiveRestartEnable = VK_FALSE;
+
+ VkPipelineLayoutCreateInfo pipeline_layout_create_info = {
+ VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO
+ };
+
+ // 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);
+ }
+
+ 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,
@@ -211,8 +488,8 @@ bool create_shader_module(vulkan_context* context, const char* filename, const c
bool vulkan_object_shader_create(vulkan_context* context, vulkan_shader* out_shader) {
char stage_type_strs[SHADER_STAGE_COUNT][5] = { "vert", "frag" };
- char stage_filenames[SHADER_STAGE_COUNT][256] = { "build/linux/x86_64/debug/triangle.vert.spv",
- "build/linux/x86_64/debug/triangle.frag.spv" };
+ char stage_filenames[SHADER_STAGE_COUNT][256] = { "build/linux/x86_64/debug/object.vert.spv",
+ "build/linux/x86_64/debug/object.frag.spv" };
VkShaderStageFlagBits stage_types[SHADER_STAGE_COUNT] = { VK_SHADER_STAGE_VERTEX_BIT,
VK_SHADER_STAGE_FRAGMENT_BIT };
for (u8 i = 0; i < SHADER_STAGE_COUNT; i++) {
@@ -220,9 +497,164 @@ bool vulkan_object_shader_create(vulkan_context* context, vulkan_shader* out_sha
create_shader_module(context, stage_filenames[i], stage_type_strs[i], stage_types[i], i,
out_shader->stages);
}
+
+ // descriptors
+ VkDescriptorSetLayoutBinding global_ubo_layout_binding;
+ global_ubo_layout_binding.binding = 0;
+ global_ubo_layout_binding.descriptorCount = 1;
+ global_ubo_layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
+ global_ubo_layout_binding.pImmutableSamplers = 0;
+ global_ubo_layout_binding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
+
+ VkDescriptorSetLayoutCreateInfo global_layout_info = {
+ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO
+ };
+ global_layout_info.bindingCount = 1;
+ global_layout_info.pBindings = &global_ubo_layout_binding;
+
+ VK_CHECK(vkCreateDescriptorSetLayout(context->device.logical_device, &global_layout_info,
+ context->allocator, &out_shader->descriptor_set_layout));
+
+ VkDescriptorPoolSize global_pool_size;
+ global_pool_size.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
+ global_pool_size.descriptorCount = 3;
+
+ VkDescriptorPoolCreateInfo pool_info = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO };
+ pool_info.poolSizeCount = 1;
+ pool_info.pPoolSizes = &global_pool_size;
+ pool_info.maxSets = 3;
+
+ VK_CHECK(vkCreateDescriptorPool(context->device.logical_device, &pool_info, context->allocator,
+ &out_shader->descriptor_pool));
+
+ // Pipeline creation
+ VkViewport viewport;
+ viewport.x = 0;
+ viewport.y = (f32)context->framebuffer_height;
+ viewport.width = (f32)context->framebuffer_width;
+ viewport.height = -(f32)context->framebuffer_height;
+ viewport.minDepth = 0.0;
+ viewport.maxDepth = 1.0;
+
+ VkRect2D scissor;
+ scissor.offset.x = scissor.offset.y = 0;
+ scissor.extent.width = context->framebuffer_width;
+ scissor.extent.height = context->framebuffer_height;
+
+ // Attributes
+ u32 offset = 0;
+ const i32 attribute_count = 1;
+ VkVertexInputAttributeDescription attribute_descs[1];
+ // Position
+ VkFormat formats[1] = { VK_FORMAT_R32G32B32_SFLOAT };
+
+ u64 sizes[1] = { sizeof(vec3) };
+
+ for (u32 i = 0; i < attribute_count; i++) {
+ attribute_descs[i].binding = 0;
+ attribute_descs[i].location = i;
+ attribute_descs[i].format = formats[i];
+ attribute_descs[i].offset = offset;
+ offset += sizes[i];
+ }
+
+ // 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) {}
+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;
+
+ VkWriteDescriptorSet descriptor_write = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET };
+ descriptor_write.dstSet = shader->descriptor_sets[image_index];
+ descriptor_write.dstBinding = 0;
+ descriptor_write.dstArrayElement = 0;
+ descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
+ descriptor_write.descriptorCount = 1;
+ descriptor_write.pBufferInfo = &buffer_info;
+
+ vkUpdateDescriptorSets(context->device.logical_device, 1, &descriptor_write, 0, 0);
+
+ vkCmdBindDescriptorSets(cmd_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, shader->pipeline.layout, 0,
+ 1, &global_descriptors, 0, 0);
+}
+
+void vulkan_object_shader_update_object(vulkan_context* context, vulkan_shader* shader,
+ mat4 model) {
+ u32 image_index = context->image_index;
+ VkCommandBuffer cmd_buffer = context->gfx_command_buffers->data[image_index].handle;
+ // vulkan_command_buffer* cmd_buffer = &context->gfx_command_buffers->data[context.image_index];
+
+ vkCmdPushConstants(cmd_buffer, shader->pipeline.layout, VK_SHADER_STAGE_VERTEX_BIT, 0,
+ sizeof(mat4), &model);
+
+ // vulkan_object_shader_use(context, &context->object_shader);
+ VkDeviceSize offsets[1] = { 0 };
+ vkCmdBindVertexBuffers(cmd_buffer, 0, 1, &context->object_vertex_buffer.handle,
+ (VkDeviceSize*)offsets);
+
+ vkCmdBindIndexBuffer(cmd_buffer, context->object_index_buffer.handle, 0, VK_INDEX_TYPE_UINT32);
+
+ vkCmdDrawIndexed(cmd_buffer, 6, 1, 0, 0, 0);
+}
bool select_physical_device(vulkan_context* ctx) {
u32 physical_device_count = 0;
@@ -303,26 +735,42 @@ bool vulkan_device_create(vulkan_context* context) {
// Logical device - NOTE: mutates the context directly
// queues
-#define VULKAN_QUEUES_COUNT 3
- const char* queue_names[VULKAN_QUEUES_COUNT] = { "GRAPHICS", "PRESENT",
- // "COMPUTE",
- "TRANSFER" };
- i32 indices[VULKAN_QUEUES_COUNT] = { context->device.graphics_queue_index,
- context->device.present_queue_index,
- // context->device.compute_queue_index,
- context->device.transfer_queue_index };
- VkDeviceQueueCreateInfo
- queue_create_info[VULKAN_QUEUES_COUNT]; // one for each of graphics,present,compute,transfer
- for (int i = 0; i < VULKAN_QUEUES_COUNT; i++) {
- TRACE("Configure %s queue", queue_names[i]);
- queue_create_info[i].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
- queue_create_info[i].queueFamilyIndex = indices[i];
- queue_create_info[i].queueCount = 1; // make just one of them
- queue_create_info[i].flags = 0;
- queue_create_info[i].pNext = 0;
- f32 priority = 1.0;
- queue_create_info[i].pQueuePriorities = &priority;
- }
+#define VULKAN_QUEUES_COUNT 2
+ const char* queue_names[VULKAN_QUEUES_COUNT] = {
+ "GRAPHICS",
+ "TRANSFER",
+ };
+ i32 indices[VULKAN_QUEUES_COUNT] = {
+ context->device.graphics_queue_index,
+ context->device.transfer_queue_index,
+ };
+ f32 prio_one = 1.0;
+ VkDeviceQueueCreateInfo queue_create_info[2]; // HACK: make 2 queues, graphics and transfer
+ // graphics
+ queue_create_info[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
+ queue_create_info[0].queueFamilyIndex = 0;
+ queue_create_info[0].queueCount = 1;
+ queue_create_info[0].flags = 0;
+ queue_create_info[0].pNext = 0;
+ queue_create_info[0].pQueuePriorities = &prio_one;
+ // transfer
+ queue_create_info[1].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
+ queue_create_info[1].queueFamilyIndex = 1;
+ queue_create_info[1].queueCount = 1;
+ queue_create_info[1].flags = 0;
+ queue_create_info[1].pNext = 0;
+ queue_create_info[1].pQueuePriorities = &prio_one;
+
+ // for (int i = 0; i < 2; i++) {
+ // TRACE("Configure %s queue", queue_names[i]);
+ // queue_create_info[i].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
+ // queue_create_info[i].queueFamilyIndex = indices[i];
+ // queue_create_info[i].queueCount = 1; // make just one of them
+ // queue_create_info[i].flags = 0;
+ // queue_create_info[i].pNext = 0;
+ // f32 priority = 1.0;
+ // queue_create_info[i].pQueuePriorities = &priority;
+ // }
// features
VkPhysicalDeviceFeatures device_features = {};
@@ -352,10 +800,10 @@ bool vulkan_device_create(vulkan_context* context) {
// get queues
vkGetDeviceQueue(context->device.logical_device, context->device.graphics_queue_index, 0,
&context->device.graphics_queue);
- vkGetDeviceQueue(context->device.logical_device, context->device.present_queue_index, 0,
- &context->device.present_queue);
- vkGetDeviceQueue(context->device.logical_device, context->device.compute_queue_index, 0,
- &context->device.compute_queue);
+ // vkGetDeviceQueue(context->device.logical_device, context->device.present_queue_index, 0,
+ // &context->device.present_queue);
+ // vkGetDeviceQueue(context->device.logical_device, context->device.compute_queue_index, 0,
+ // &context->device.compute_queue);
vkGetDeviceQueue(context->device.logical_device, context->device.transfer_queue_index, 0,
&context->device.transfer_queue);
@@ -572,6 +1020,24 @@ void vulkan_command_buffer_end_oneshot(vulkan_context* context, VkCommandPool po
vulkan_command_buffer_free(context, pool, command_buffer);
}
+void vulkan_buffer_copy_to(vulkan_context* context, VkCommandPool pool, VkFence fence,
+ VkQueue queue, VkBuffer source, u64 source_offset, VkBuffer dest,
+ u64 dest_offset, u64 size) {
+ vkQueueWaitIdle(queue);
+
+ vulkan_command_buffer temp_cmd_buf;
+ vulkan_command_buffer_allocate_and_begin_oneshot(context, pool, &temp_cmd_buf);
+
+ VkBufferCopy copy_region;
+ copy_region.srcOffset = source_offset;
+ copy_region.dstOffset = dest_offset;
+ copy_region.size = size;
+
+ vkCmdCopyBuffer(temp_cmd_buf.handle, source, dest, 1, &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 };
@@ -597,13 +1063,14 @@ void vulkan_swapchain_create(vulkan_context* context, u32 width, u32 height,
// TODO: requery swapchain support
- u32 image_count = context->device.swapchain_support.capabilities.minImageCount + 1;
+ u32 image_count = context->device.swapchain_support.capabilities.minImageCount;
VkSwapchainCreateInfoKHR swapchain_create_info = { VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR };
swapchain_create_info.surface = context->surface;
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;
@@ -703,7 +1170,11 @@ void vulkan_swapchain_present(vulkan_context* context, vulkan_swapchain* swapcha
VkResult result = vkQueuePresentKHR(present_queue, &present_info);
if (result != VK_SUCCESS) {
- FATAL("Failed to present swapchain iamge");
+ if (result == VK_SUBOPTIMAL_KHR) {
+ // WARN("Swapchain suboptimal - maybe resize needed?");
+ } else {
+ FATAL("Failed to present swapchain iamge");
+ }
}
// advance the current frame
@@ -832,6 +1303,33 @@ void vulkan_renderpass_end(vulkan_command_buffer* command_buffer, vulkan_renderp
command_buffer->state = COMMAND_BUFFER_STATE_RECORDING;
}
+bool create_buffers(vulkan_context* context) {
+ VkMemoryPropertyFlagBits mem_prop_flags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
+
+ const u64 vertex_buffer_size = sizeof(vertex_pos) * 1024 * 1024;
+ if (!vulkan_buffer_create(context, vertex_buffer_size,
+ VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT |
+ VK_BUFFER_USAGE_TRANSFER_DST_BIT,
+ mem_prop_flags, true, &context->object_vertex_buffer)) {
+ ERROR("couldnt create vertex buffer");
+ return false;
+ }
+
+ context->geometry_vertex_offset = 0;
+
+ const u64 index1_buffer_size = sizeof(u32) * 1024 * 1024;
+ if (!vulkan_buffer_create(context, index1_buffer_size,
+ VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT |
+ VK_BUFFER_USAGE_TRANSFER_DST_BIT,
+ mem_prop_flags, true, &context->object_index_buffer)) {
+ ERROR("couldnt create vertex buffer");
+ return false;
+ }
+ context->geometry_index_offset = 0;
+
+ return true;
+}
+
void create_command_buffers(renderer* ren) {
if (!context.gfx_command_buffers) {
context.gfx_command_buffers = vulkan_command_buffer_darray_new(context.swapchain.image_count);
@@ -843,6 +1341,25 @@ void create_command_buffers(renderer* ren) {
}
}
+void upload_data_range(vulkan_context* context, VkCommandPool pool, VkFence fence, VkQueue queue,
+ vulkan_buffer* buffer, u64 offset, u64 size, void* data) {
+ VkBufferUsageFlags flags =
+ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
+ vulkan_buffer staging;
+ vulkan_buffer_create(context, size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, flags, true, &staging);
+ TRACE("HERE");
+ // load data into staging buffer
+ printf("Size: %ld\n", size);
+ vulkan_buffer_load_data(context, &staging, 0, size, 0, data);
+ TRACE("here");
+
+ // copy
+ vulkan_buffer_copy_to(context, pool, fence, queue, staging.handle, 0, buffer->handle, offset,
+ size);
+
+ vkDestroyBuffer(context->device.logical_device, staging.handle, context->allocator);
+}
+
void regenerate_framebuffers(renderer* ren, vulkan_swapchain* swapchain,
vulkan_renderpass* renderpass) {
for (u32 i = 0; i < swapchain->image_count; i++) {
@@ -924,7 +1441,7 @@ bool gfx_backend_init(renderer* ren) {
plat_get_required_extension_names(required_extensions);
-#if defined(DEBUG)
+#if defined(CDEBUG)
cstr_darray_push(required_extensions, VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
DEBUG("Required extensions:");
@@ -939,7 +1456,7 @@ bool gfx_backend_init(renderer* ren) {
// Validation layers
create_info.enabledLayerCount = 0;
create_info.ppEnabledLayerNames = 0;
-#if defined(DEBUG)
+#if defined(CDEBUG)
INFO("Validation layers enabled");
cstr_darray* desired_validation_layers = cstr_darray_new(1);
cstr_darray_push(desired_validation_layers, "VK_LAYER_KHRONOS_validation");
@@ -979,7 +1496,7 @@ bool gfx_backend_init(renderer* ren) {
}
// Debugger
-#if defined(DEBUG)
+#if defined(CDEBUG)
DEBUG("Creating Vulkan debugger")
u32 log_severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT;
@@ -1059,6 +1576,38 @@ bool gfx_backend_init(renderer* ren) {
vulkan_object_shader_create(&context, &context.object_shader);
INFO("Compiled shader modules")
+ create_buffers(&context);
+ INFO("Created buffers");
+
+ // TODO: temporary test code
+ const u32 vert_count = 4;
+ vertex_pos verts[4] = { 0 };
+
+ const f32 s = 10.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_pos) * vert_count, verts);
+ TRACE("Uploaded vertex data");
+ upload_data_range(&context, context.device.gfx_command_pool, 0, context.device.graphics_queue,
+ &context.object_index_buffer, 0, sizeof(u32) * index_count, indices);
+ TRACE("Uploaded index data");
+ // --- End test code
+
INFO("Vulkan renderer initialisation succeeded");
return true;
}
@@ -1116,6 +1665,19 @@ void backend_begin_frame(renderer* ren, f32 delta_time) {
vulkan_renderpass_begin(command_buffer, &context.main_renderpass,
context.swapchain.framebuffers->data[context.image_index].handle);
+
+ // TODO: temp test code
+ // vulkan_object_shader_use(&context, &context.object_shader);
+
+ // VkDeviceSize offsets[1] = { 0 };
+ // vkCmdBindVertexBuffers(command_buffer->handle, 0, 1, &context.object_vertex_buffer.handle,
+ // (VkDeviceSize*)offsets);
+
+ // vkCmdBindIndexBuffer(command_buffer->handle, context.object_index_buffer.handle, 0,
+ // VK_INDEX_TYPE_UINT32);
+
+ // vkCmdDrawIndexed(command_buffer->handle, 6, 1, 0, 0, 0);
+ // --- End temp test code
}
void backend_end_frame(renderer* ren, f32 delta_time) {
@@ -1152,16 +1714,34 @@ void backend_end_frame(renderer* ren, f32 delta_time) {
vulkan_command_buffer_update_submitted(command_buffer);
vulkan_swapchain_present(
- &context, &context.swapchain, context.device.graphics_queue, context.device.present_queue,
+ &context, &context.swapchain, context.device.graphics_queue, context.device.graphics_queue,
context.queue_complete_semaphores[context.current_frame], context.image_index);
}
-void gfx_backend_draw_frame(renderer* ren) {
+void gfx_backend_draw_frame(renderer* ren, camera* cam, mat4 model) {
backend_begin_frame(ren, 16.0);
+ mat4 proj;
+ mat4 view;
+
+ camera_view_projection(cam, SCR_HEIGHT, SCR_WIDTH, &view, &proj);
+
+ gfx_backend_update_global_state(proj, view, VEC3_ZERO, vec4(1.0, 1.0, 1.0, 1.0), 0);
+ vulkan_object_shader_update_object(&context, &context.object_shader, model);
+
backend_end_frame(ren, 16.0);
}
+void gfx_backend_update_global_state(mat4 projection, mat4 view, vec3 view_pos, vec4 ambient_colour,
+ i32 mode) {
+ vulkan_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) {}
diff --git a/src/renderer/backends/vulkan/vulkan_glossary.md b/src/renderer/backends/vulkan/vulkan_glossary.md
new file mode 100644
index 0000000..4214f9d
--- /dev/null
+++ b/src/renderer/backends/vulkan/vulkan_glossary.md
@@ -0,0 +1,18 @@
+# Vulkan Glossary
+
+*from https://vkguide.dev/docs/introduction/vulkan_execution/*
+
+- **VkInstance**: The Vulkan context, used to access drivers.
+- **VkPhysicalDevice**: A GPU. Used to query physical GPU details, like features, capabilities, memory size, etc.
+- **VkDevice**: The “logical” GPU context that you actually execute things on.
+- **VkBuffer**: A chunk of GPU visible memory.
+- **VkImage**: A texture you can write to and read from.
+- **VkPipeline**: Holds the state of the gpu needed to draw. For example: shaders, rasterization options, depth settings.
+- **VkRenderPass**: Holds information about the images you are rendering into. All drawing commands have to be done inside a renderpass. Only used in legacy vkguide.
+- **VkFrameBuffer**: Holds the target images for a renderpass. Only used in legacy vkguide.
+- **VkCommandBuffer**: Encodes GPU commands. All execution that is performed on the GPU itself (not in the driver) has to be encoded in a VkCommandBuffer.
+- **VkQueue**: Execution “port” for commands. GPUs will have a set of queues with different properties. Some allow only graphics commands, others only allow memory commands, etc. Command buffers are executed by submitting them into a queue, which will copy the rendering commands onto the GPU for execution.
+- **VkDescriptorSet**: Holds the binding information that connects shader inputs to data such as VkBuffer resources and VkImage textures. Think of it as a set of gpu-side pointers that you bind once.
+- **VkSwapchainKHR**: Holds the images for the screen. It allows you to render things into a visible window. The KHR suffix shows that it comes from an extension, which in this case is VK_KHR_swapchain.
+- **VkSemaphore**: Synchronizes GPU to GPU execution of commands. Used for syncing multiple command buffer submissions one after another.
+- **VkFence**: Synchronizes GPU to CPU execution of commands. Used to know if a command buffer has finished being executed on the GPU.
diff --git a/src/renderer/render.c b/src/renderer/render.c
index 45762d4..54b63b6 100644
--- a/src/renderer/render.c
+++ b/src/renderer/render.c
@@ -17,8 +17,8 @@
// FIXME: get rid of these and store dynamic screen realestate
// in renderer
-#define SCR_WIDTH 1080
-#define SCR_HEIGHT 800
+#define SCR_WIDTH 1000
+#define SCR_HEIGHT 1000
material DEFAULT_MATERIAL = { 0 };
@@ -61,6 +61,8 @@ bool renderer_init(renderer* ren) {
return true;
}
+void renderer_shutdown(renderer* ren) {}
+
void render_frame_begin(renderer* ren) {
vec3 color = ren->config.clear_colour;
clear_screen(color);
diff --git a/src/renderer/render_backend.h b/src/renderer/render_backend.h
index 041f412..ea84b27 100644
--- a/src/renderer/render_backend.h
+++ b/src/renderer/render_backend.h
@@ -3,6 +3,7 @@
*/
#pragma once
+#include "camera.h"
#include "maths_types.h"
#include "render_types.h"
@@ -12,7 +13,9 @@
bool gfx_backend_init(renderer* ren);
void gfx_backend_shutdown(renderer* ren);
-void gfx_backend_draw_frame(renderer* ren);
+void gfx_backend_draw_frame(renderer* ren, camera* camera, mat4 model);
+void gfx_backend_update_global_state(mat4 projection, mat4 view, vec3 view_pos, vec4 ambient_colour,
+ i32 mode);
void clear_screen(vec3 colour);
diff --git a/src/systems/input.c b/src/systems/input.c
index 292d438..fc62db8 100644
--- a/src/systems/input.c
+++ b/src/systems/input.c
@@ -1,11 +1,17 @@
#include "input.h"
+#include <assert.h>
#include <glfw3.h>
+#include <string.h>
#include "log.h"
+static input_state *g_input; // Use a global to simplify caller code
+
bool input_system_init(input_state *input, GLFWwindow *window) {
INFO("Input init");
+ memset(input, 0, sizeof(input_state));
+
input->window = window;
// Set everything to false. Could just set memory to zero but where's the fun in that
for (int i = 0; i < KEYCODE_MAX; i++) {
@@ -14,9 +20,16 @@ bool input_system_init(input_state *input, GLFWwindow *window) {
input->just_released_keys[i] = false;
}
+ g_input = input;
+
+ assert(input->mouse.x_delta == 0);
+ assert(input->mouse.y_delta == 0);
+
return true;
}
+void input_system_shutdown(input_state *input) {}
+
void input_update(input_state *input) {
// --- update keyboard input
@@ -75,3 +88,9 @@ void input_update(input_state *input) {
input->mouse = new_mouse_state;
}
+
+bool key_is_pressed(keycode key) { return g_input->depressed_keys[key]; }
+
+bool key_just_pressed(keycode key) { return g_input->just_pressed_keys[key]; }
+
+bool key_just_released(keycode key) { return g_input->just_released_keys[key]; } \ No newline at end of file
diff --git a/src/systems/keys.h b/src/systems/keys.h
index 090bb49..a76e101 100644
--- a/src/systems/keys.h
+++ b/src/systems/keys.h
@@ -2,5 +2,18 @@
typedef enum keycode {
// TODO: add all keycodes
- KEYCODE_MAX
+ KEYCODE_SPACE = 32,
+ KEYCODE_A = 65,
+ KEYCODE_D = 68,
+ KEYCODE_S = 83,
+ KEYCODE_W = 87,
+ KEYCODE_ESCAPE = 256,
+ KEYCODE_ENTER = 257,
+ KEYCODE_TAB = 258,
+ KEYCODE_BACKSPACE = 259,
+ KEYCODE_KEY_RIGHT = 262,
+ KEYCODE_KEY_LEFT = 263,
+ KEYCODE_KEY_DOWN = 264,
+ KEYCODE_KEY_UP = 265,
+ KEYCODE_MAX = 348
} keycode; \ No newline at end of file
diff --git a/xmake.lua b/xmake.lua
index 5457ccb..29c1de0 100644
--- a/xmake.lua
+++ b/xmake.lua
@@ -14,6 +14,7 @@ add_cflags("-Wall", "-Wextra", "-Wundef", "-Wdouble-promotion")
if is_mode("debug") then
add_cflags("-g") -- Add debug symbols in debug mode
+ add_defines("CDEBUG")
elseif is_mode("release") then
add_defines("CRELEASE")
end
@@ -68,18 +69,18 @@ rule("compile_glsl_vert_shaders")
on_buildcmd_file(function (target, batchcmds, sourcefile, opt)
local targetfile = path.join(target:targetdir(), path.basename(sourcefile) .. ".vert.spv")
- print("Compiling shader: %s", sourcefile)
+ print("Compiling shader: %s to %s", sourcefile, targetfile)
batchcmds:vrunv('glslc', {sourcefile, "-o", targetfile})
- batchcmds:add_depfiles(sourcefile)
+ -- batchcmds:add_depfiles(sourcefile)
end)
rule("compile_glsl_frag_shaders")
set_extensions(".frag")
on_buildcmd_file(function (target, batchcmds, sourcefile, opt)
local targetfile = path.join(target:targetdir(), path.basename(sourcefile) .. ".frag.spv")
- print("Compiling shader: %s", sourcefile)
+ print("Compiling shader: %s to %s", sourcefile, targetfile)
batchcmds:vrunv('glslc', {sourcefile, "-o", targetfile})
- batchcmds:add_depfiles(sourcefile)
+ -- batchcmds:add_depfiles(sourcefile)
end)
-- TODO: Metal shaders compilation
@@ -103,11 +104,11 @@ target("core_config")
add_includedirs("src/std/", {public = true})
add_includedirs("src/std/containers", {public = true})
add_includedirs("src/systems/", {public = true})
+ add_files("src/empty.c") -- for some reason we need this on Mac so it doesnt call 'ar' with no files and error
add_rules("compile_glsl_vert_shaders")
add_rules("compile_glsl_frag_shaders")
- add_files("src/empty.c") -- for some reason we need this on Mac so it doesnt call 'ar' with no files and error
- add_files("assets/shaders/triangle.vert")
- add_files("assets/shaders/triangle.frag")
+ add_files("assets/shaders/object.vert")
+ add_files("assets/shaders/object.frag")
-- add_files("assets/shaders/*.frag")
set_default(false) -- prevents standalone building of this target
@@ -143,6 +144,13 @@ target("obj")
add_files("examples/obj_loading/ex_obj_loading.c")
set_rundir("$(projectdir)")
+target("input")
+ set_kind("binary")
+ set_group("examples")
+ add_deps("core_static")
+ add_files("examples/input/ex_input.c")
+ set_rundir("$(projectdir)")
+
target("demo")
set_kind("binary")
set_group("examples")