diff options
author | Omniscient <17525998+omnisci3nce@users.noreply.github.com> | 2024-03-30 23:15:36 +1100 |
---|---|---|
committer | Omniscient <17525998+omnisci3nce@users.noreply.github.com> | 2024-03-30 23:15:36 +1100 |
commit | f26f084958550cd01b9e4e4b098551520a4c6852 (patch) | |
tree | 1b835288f94461ba86aca8cff723d3364556db52 | |
parent | b4cb698d177ada97c976eab059eabedd433abfd0 (diff) | |
parent | c20740ecbb008afbe93c7fa1eb35851cedc6eb42 (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.vert | 20 | ||||
-rw-r--r-- | assets/shaders/triangle.vert | 6 | ||||
-rw-r--r-- | examples/input/ex_input.c | 111 | ||||
-rw-r--r-- | examples/main_loop/ex_main_loop.c | 7 | ||||
-rw-r--r-- | src/core.c | 17 | ||||
-rw-r--r-- | src/core.h | 1 | ||||
-rw-r--r-- | src/maths/maths.h | 3 | ||||
-rw-r--r-- | src/renderer/backends/backend_vulkan.c | 662 | ||||
-rw-r--r-- | src/renderer/backends/vulkan/vulkan_glossary.md | 18 | ||||
-rw-r--r-- | src/renderer/render.c | 6 | ||||
-rw-r--r-- | src/renderer/render_backend.h | 5 | ||||
-rw-r--r-- | src/systems/input.c | 19 | ||||
-rw-r--r-- | src/systems/keys.h | 15 | ||||
-rw-r--r-- | xmake.lua | 22 |
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 @@ -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 @@ -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, ©_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 @@ -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") |