diff --git a/CMakeLists.txt b/CMakeLists.txt index a93af8f9..9b24ce46 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,8 @@ project("RedScarfEngine" DESCRIPTION "Vulkan based 3D engine" LANGUAGES C CXX) -set(CMAKE_C_STANDARD 23) +set(CMAKE_C_STANDARD 11) +set(CMAKE_CXX_STANDARD 17) set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) diff --git a/cmake/FindFreeType.cmake b/cmake/FindFreeType.cmake index 5cf6ff55..884415d9 100644 --- a/cmake/FindFreeType.cmake +++ b/cmake/FindFreeType.cmake @@ -1,11 +1,11 @@ -set(FREE_TYPE_DIR "${PROJECT_SOURCE_DIR}/third_party/freetype/") +set(FREE_TYPE_DIR "/usr/") find_library( freetype NAMES freetype - HINTS ${FREE_TYPE_DIR}/build/ + HINTS ${FREE_TYPE_DIR}/lib/x86_64-linux-gnu ) -set(FreeType_INCLUDE_DIR "${FREE_TYPE_DIR}/include/") +set(FreeType_INCLUDE_DIR "${FREE_TYPE_DIR}/include/freetype2/") diff --git a/cmake/Findstb.cmake b/cmake/Findstb.cmake index 9dfae165..9350b9ac 100644 --- a/cmake/Findstb.cmake +++ b/cmake/Findstb.cmake @@ -1,3 +1,3 @@ -set(STB_DIR "${PROJECT_SOURCE_DIR}/third_party/stb/") +set(STB_DIR "/usr/include") set(stb_INCLUDE_DIR "${STB_DIR}/") \ No newline at end of file diff --git a/cmake/FindCmock.cmake b/cmake_to_remove/FindCmock.cmake similarity index 100% rename from cmake/FindCmock.cmake rename to cmake_to_remove/FindCmock.cmake diff --git a/cmake/FindCriterion.cmake b/cmake_to_remove/FindCriterion.cmake similarity index 100% rename from cmake/FindCriterion.cmake rename to cmake_to_remove/FindCriterion.cmake diff --git a/cmake/FindPackageHandleStandardArgs.cmake b/cmake_to_remove/FindPackageHandleStandardArgs.cmake similarity index 100% rename from cmake/FindPackageHandleStandardArgs.cmake rename to cmake_to_remove/FindPackageHandleStandardArgs.cmake diff --git a/cmake/FindPackageMessage.cmake b/cmake_to_remove/FindPackageMessage.cmake similarity index 100% rename from cmake/FindPackageMessage.cmake rename to cmake_to_remove/FindPackageMessage.cmake diff --git a/cmake/FindVulkan.cmake b/cmake_to_remove/FindVulkan.cmake similarity index 100% rename from cmake/FindVulkan.cmake rename to cmake_to_remove/FindVulkan.cmake diff --git a/cmake/Findglfw3.cmake b/cmake_to_remove/Findglfw3.cmake similarity index 100% rename from cmake/Findglfw3.cmake rename to cmake_to_remove/Findglfw3.cmake diff --git a/cmake/Findvma.cmake b/cmake_to_remove/Findvma.cmake similarity index 100% rename from cmake/Findvma.cmake rename to cmake_to_remove/Findvma.cmake diff --git a/graphics/CMakeLists.txt b/graphics/CMakeLists.txt index f205d663..65cf16ca 100644 --- a/graphics/CMakeLists.txt +++ b/graphics/CMakeLists.txt @@ -1,7 +1,6 @@ find_package(Vulkan REQUIRED) -find_package(vma REQUIRED) +find_package(VulkanMemoryAllocator CONFIG REQUIRED) find_package(glfw3 REQUIRED) -find_package(stb REQUIRED) find_package(FreeType REQUIRED) find_package(Vulkan COMPONENTS glslc) @@ -19,7 +18,6 @@ function(compile_shader) add_custom_command( OUTPUT ${source}.${arg_FORMAT} DEPENDS ${source} - DEPFILE ${source}.d COMMAND ${glslc_executable} -o ${source}.${arg_FORMAT} @@ -57,21 +55,23 @@ target_sources(graphics PRIVATE src/vma_port.cpp src/window.c src/vulkan_base.c -src/vulkan_pipeline.c src/vulkan_commands.c src/vulkan_buffers.c -src/vulkan_descriptors.c src/rse_graphics.c src/math.c src/mesh_controller.c src/vulkan_commons.c src/vulkan_image.c +src/vulkan_render_pass.c +src/vulkan_swapchain.c src/text_renderer.c +src/pipeline_builder.c +src/descriptor_builder.c ) -target_link_libraries(graphics PRIVATE +target_link_libraries(graphics PUBLIC utilities ${Vulkan_LIBRARIES} - ${glfw} + glfw ${freetype} ) diff --git a/graphics/rse_graphics.h b/graphics/rse_graphics.h index 54a9023b..899de480 100644 --- a/graphics/rse_graphics.h +++ b/graphics/rse_graphics.h @@ -12,7 +12,7 @@ struct rse_graphics_context_t; * @param context Graphics context handle. Must be NULL! * @return rse_err_t RSE_ERROR_NO_ERROR on success */ -rse_err_t rse_graphics_init(struct rse_graphics_context_t* context); +rse_err_t rse_graphics_init(struct rse_graphics_context_t** context); /** * @brief Runs graphics engine. This has to be called after all objects are added to the scene diff --git a/graphics/src/descriptor_builder.c b/graphics/src/descriptor_builder.c new file mode 100644 index 00000000..e6405b8b --- /dev/null +++ b/graphics/src/descriptor_builder.c @@ -0,0 +1,228 @@ +/** + * @file descriptor_builder.c + * @author Piotr Krygier (everyonecancode@gmail.com) + * @brief + * @version 0.1 + * @date 2025-03-14 + * + * @copyright Copyright (c) 2025 + * + */ + +#include "descriptor_builder.h" + +#include + +#include "src/graphics_context.h" +#include "utilities/commons.h" +#include "utilities/errors_common.h" +#include "utilities/linked_list.h" +#include "utilities/localization.h" +#include "utilities/logger.h" +#include "vulkan/vulkan_core.h" +#include "vulkan_errors.h" + +RSE_LINKED_LIST_DEFINE(descriptor_set_layout_list_t, + VkDescriptorSetLayoutBinding); + +struct descriptor_t +{ + uint32_t binding; + VkDescriptorType type; + uint32_t descriptors_count; + VkShaderStageFlags shader_stages; + VkSampler immutable_sampler; +}; +RSE_LINKED_LIST_DEFINE(descriptors_list_t, struct descriptor_t); + +/* FIXME: When new descriptors are introduced to Vulkan, this enum has to be + * updated */ +enum descriptor_type_id_t +{ + DESCRIPTOR_TYPE_SAMPLER_ID, + DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER_ID, + DESCRIPTOR_TYPE_SAMPLED_IMAGE_ID, + DESCRIPTOR_TYPE_STORAGE_IMAGE_ID, + DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER_ID, + DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER_ID, + DESCRIPTOR_TYPE_UNIFORM_BUFFER_ID, + DESCRIPTOR_TYPE_STORAGE_BUFFER_ID, + DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC_ID, + DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC_ID, + DESCRIPTOR_TYPE_INPUT_ATTACHMENT_ID, + DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_ID, + DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR_ID, + DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV_ID, + DESCRIPTOR_TYPE_SAMPLE_WEIGHT_IMAGE_QCOM_ID, + DESCRIPTOR_TYPE_BLOCK_MATCH_IMAGE_QCOM_ID, + DESCRIPTOR_TYPE_MUTABLE_EXT_ID, + DESCRIPTOR_TYPE_ID_MAX_ENUM, +}; + +struct descriptors_data_t +{ + VkDescriptorPool pool; + VkDescriptorSet set; + struct descriptor_set_layout_list_t layouts_list; +}; + +rse_err_t descriptor_add(struct descriptors_list_t* descriptors_list, + uint32_t binding, VkDescriptorType type, + uint32_t descriptors_count, + VkShaderStageFlags shader_stages, VkSampler sampler) +{ + struct descriptor_t descriptor = {.binding = binding, + .type = type, + .descriptors_count = descriptors_count, + .shader_stages = shader_stages, + .immutable_sampler = sampler}; + + RSE_LINKED_LIST_PUSH_BACK(descriptors_list, descriptor); + + return RSE_ERROR_NO_ERROR; +} + +rse_err_t descriptors_build(struct graphics_context_t* context, + struct descriptors_list_t* descriptors) +{ + VkDescriptorPoolCreateInfo pool_create_info = {}; + VkDescriptorPoolCreateFlags pool_create_flags = 0U; + VkDescriptorPool descriptor_pool = VK_NULL_HANDLE; + VkDescriptorPoolSize pool_sizes[DESCRIPTOR_TYPE_ID_MAX_ENUM] = {}; + VkDescriptorPoolSize requested_pool_sizes[DESCRIPTOR_TYPE_ID_MAX_ENUM] = {}; + uint32_t pool_max_sets = 0; + size_t pool_size_count = 0U; + size_t iterator = 0U; + + if (NULL == context) { + LOGF(_("Provided NULL context\n")); + + return RSE_ERROR_NULL_POINTER; + } + + RSE_LINKED_LIST_FOREACH(descriptors, descriptor) + { + switch (descriptor->data.type) { + case VK_DESCRIPTOR_TYPE_SAMPLER: + pool_sizes[DESCRIPTOR_TYPE_SAMPLER_ID].type = + VK_DESCRIPTOR_TYPE_SAMPLER; + pool_sizes[DESCRIPTOR_TYPE_SAMPLER_ID].descriptorCount++; + break; + case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: + pool_sizes[DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER_ID].type = + VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + pool_sizes[DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER_ID] + .descriptorCount++; + break; + case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: + pool_sizes[DESCRIPTOR_TYPE_SAMPLED_IMAGE_ID].type = + VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; + pool_sizes[DESCRIPTOR_TYPE_SAMPLED_IMAGE_ID].descriptorCount++; + break; + case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: + pool_sizes[DESCRIPTOR_TYPE_STORAGE_IMAGE_ID].type = + VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + pool_sizes[DESCRIPTOR_TYPE_STORAGE_IMAGE_ID].descriptorCount++; + break; + case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER: + pool_sizes[DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER_ID].type = + VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER; + pool_sizes[DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER_ID] + .descriptorCount++; + break; + case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: + pool_sizes[DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER_ID].type = + VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER; + pool_sizes[DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER_ID] + .descriptorCount++; + break; + case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: + pool_sizes[DESCRIPTOR_TYPE_UNIFORM_BUFFER_ID].type = + VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + pool_sizes[DESCRIPTOR_TYPE_UNIFORM_BUFFER_ID].descriptorCount++; + break; + case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER: + pool_sizes[DESCRIPTOR_TYPE_STORAGE_BUFFER_ID].type = + VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + pool_sizes[DESCRIPTOR_TYPE_STORAGE_BUFFER_ID].descriptorCount++; + break; + case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC: + pool_sizes[DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC_ID].type = + VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; + pool_sizes[DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC_ID] + .descriptorCount++; + break; + case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: + pool_sizes[DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC_ID].type = + VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC; + pool_sizes[DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC_ID] + .descriptorCount++; + break; + case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: + pool_sizes[DESCRIPTOR_TYPE_INPUT_ATTACHMENT_ID].type = + VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT; + pool_sizes[DESCRIPTOR_TYPE_INPUT_ATTACHMENT_ID] + .descriptorCount++; + break; + case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK: + pool_sizes[DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_ID].type = + VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK; + pool_sizes[DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_ID] + .descriptorCount++; + break; + case VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR: + pool_sizes[DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR_ID].type = + VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR; + pool_sizes[DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR_ID] + .descriptorCount++; + break; + case VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV: + pool_sizes[DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV_ID].type = + VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV; + pool_sizes[DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV_ID] + .descriptorCount++; + break; + case VK_DESCRIPTOR_TYPE_SAMPLE_WEIGHT_IMAGE_QCOM: + pool_sizes[DESCRIPTOR_TYPE_SAMPLE_WEIGHT_IMAGE_QCOM_ID].type = + VK_DESCRIPTOR_TYPE_SAMPLE_WEIGHT_IMAGE_QCOM; + pool_sizes[DESCRIPTOR_TYPE_SAMPLE_WEIGHT_IMAGE_QCOM_ID] + .descriptorCount++; + break; + case VK_DESCRIPTOR_TYPE_BLOCK_MATCH_IMAGE_QCOM: + pool_sizes[DESCRIPTOR_TYPE_BLOCK_MATCH_IMAGE_QCOM_ID].type = + VK_DESCRIPTOR_TYPE_BLOCK_MATCH_IMAGE_QCOM; + pool_sizes[DESCRIPTOR_TYPE_BLOCK_MATCH_IMAGE_QCOM_ID] + .descriptorCount++; + break; + case VK_DESCRIPTOR_TYPE_MUTABLE_EXT: + pool_sizes[DESCRIPTOR_TYPE_MUTABLE_EXT_ID].type = + VK_DESCRIPTOR_TYPE_MUTABLE_EXT; + pool_sizes[DESCRIPTOR_TYPE_MUTABLE_EXT_ID].descriptorCount++; + default: + LOGF(_("Invalid descriptor type provided\n")); + return VULKAN_ERROR_UNKNOWN_DESCRIPTOR_TYPE; + } + } + + /* Allocate pool based on layout */ + /* create array of required descriptors */ + for (iterator = 0U; iterator < DESCRIPTOR_TYPE_ID_MAX_ENUM; ++iterator) { + if (pool_sizes[iterator].descriptorCount > 0) { + requested_pool_sizes[pool_size_count].type = + pool_sizes[iterator].type; + requested_pool_sizes[pool_size_count].descriptorCount = + pool_sizes[iterator].descriptorCount; + pool_size_count++; + } + } + + pool_create_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; + pool_create_info.pNext = NULL; + pool_create_info.flags = pool_create_flags; + pool_create_info.maxSets = + 0; // FIXME: Calculate number of sets based on layout + pool_create_info.poolSizeCount = pool_size_count; + pool_create_info.pPoolSizes = requested_pool_sizes; + + return RSE_ERROR_NO_ERROR; +} diff --git a/graphics/src/descriptor_builder.h b/graphics/src/descriptor_builder.h new file mode 100644 index 00000000..e86d598d --- /dev/null +++ b/graphics/src/descriptor_builder.h @@ -0,0 +1,17 @@ +/** + * @file descriptor_builder.h + * @author Piotr Krygier (everyonecancode@gmail.com) + * @brief + * @version 0.1 + * @date 2024-03-01 + * + * @copyright Copyright (c) 2024 + * + */ + +#ifndef DESCRIPTOR_BUILDER_H +#define DESCRIPTOR_BUILDER_H + +struct descriptors_list_t; + +#endif // !DESCRIPTOR_BUILDER_H diff --git a/graphics/src/graphics_context.h b/graphics/src/graphics_context.h index 20e97566..e82c0dfb 100644 --- a/graphics/src/graphics_context.h +++ b/graphics/src/graphics_context.h @@ -33,6 +33,7 @@ #define MAX_DESCRIPTOR_SETS 16 #define MAX_PIPELINE_COUNT 16 +#define MAX_DESCRIPTOR_POOLS_COUNT (16) RSE_LINKED_LIST_DEFINE(shader_module_list_t, VkShaderModule); @@ -91,7 +92,6 @@ struct pipeline_internal_t size_t descriptor_set_layouts_count; VkPipeline pipelines[MAX_PIPELINE_COUNT]; VkPipelineLayout pipeline_layout; - VkDescriptorSetLayout descriptor_set_layouts[MAX_DESCRIPTOR_SETS]; }; struct graphics_context_t diff --git a/graphics/src/pipeline_builder.c b/graphics/src/pipeline_builder.c index 75e81063..94c878f6 100644 --- a/graphics/src/pipeline_builder.c +++ b/graphics/src/pipeline_builder.c @@ -11,6 +11,10 @@ #include "pipeline_builder.h" +#include +#include + +#include "src/graphics_context.h" #include "utilities/commons.h" #include "utilities/errors_common.h" #include "utilities/file_utils.h" @@ -22,6 +26,40 @@ #define MAX_BINDLESS_RESOURCES 1000 +RSE_LINKED_LIST_DEFINE(vertex_binding_list_t, VkVertexInputBindingDescription); +RSE_LINKED_LIST_DEFINE(shader_attribute_list_t, + VkVertexInputAttributeDescription); +RSE_LINKED_LIST_DEFINE(dynamic_state_list_t, VkDynamicState); +RSE_LINKED_LIST_DEFINE(pipeline_infos_list_t, VkGraphicsPipelineCreateInfo); + +RSE_STACK_DEFINE(required_dynamic_states_t, VkDynamicState, 16U); + + +struct pipeline_t { + VkPipeline pipeline; + uint8_t id; + /* Shader stages */ + size_t shader_stages_count; + VkPipelineShaderStageCreateInfo shader_stages[MAX_SHADER_STAGES]; + /* Input assembly */ + VkPipelineInputAssemblyStateCreateInfo input_assembly; + /* Viewport state */ + VkPipelineViewportStateCreateInfo viewport_state; + /* Rasterizer */ + VkPipelineRasterizationStateCreateInfo rasterizer; + /* Multisampling */ + VkPipelineMultisampleStateCreateInfo multisampling; + /* Color blending */ + VkPipelineColorBlendAttachmentState color_blend_attachment; + VkPipelineColorBlendStateCreateInfo color_blending; + /* Depth stencil */ + VkPipelineDepthStencilStateCreateInfo depth_stencil; + struct vertex_binding_list_t* vertex_bindings; + struct shader_attribute_list_t* shader_attributes; + struct dynamic_state_list_t* dynamic_states; + struct required_dynamic_states_t required_dynamic_states; +}; + /** * @brief Creates shader module * @@ -42,9 +80,9 @@ static rse_err_t create_shader_module(struct graphics_context_t* context, RSE_LINKED_LIST_PUSH_FRONT(context->shader_modules, (VkShaderModule){0}); - if (VK_SUCCESS != vkCreateShaderModule( - context->device, &create_info, NULL, - &RSE_LINKED_LIST_FRONT(context->shader_modules))) { + if (VK_SUCCESS != + vkCreateShaderModule(context->device, &create_info, NULL, + &RSE_LINKED_LIST_FRONT(context->shader_modules))) { LOGF(_("Failed to create a shader\n")); return VULKAN_ERROR_SHADER_CREATION_FAILED; } @@ -124,7 +162,7 @@ static rse_err_t pipeline_add_multisampling(struct pipeline_t* pipeline) VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; pipeline->multisampling.pNext = NULL; pipeline->multisampling.flags = 0U; - pipeline->multisampling.rasterizationSamples = VK_SAMPLE_COUNT_16_BIT; + pipeline->multisampling.rasterizationSamples = VK_SAMPLE_COUNT_8_BIT; pipeline->multisampling.sampleShadingEnable = VK_FALSE; pipeline->multisampling.minSampleShading = 1.0f; pipeline->multisampling.pSampleMask = NULL; @@ -212,104 +250,6 @@ static rse_err_t create_pipeline_layout(struct graphics_context_t* context) return RSE_ERROR_NO_ERROR; } -/** - * @brief Create a Render Pass - * - * @return rse_err_t RSE_ERROR_NO_ERROR on success. Possible errors: - * VULKAN_ERROR_RENDERPASS_CREATION_FAILED - */ -static rse_err_t create_render_pass(struct graphics_context_t* context) -{ - rse_err_t status = RSE_ERROR_NO_ERROR; - VkAttachmentDescription attachments[3] = {}; - VkAttachmentDescription color_attachment = {}; - VkAttachmentReference color_attachment_ref = {}; - VkAttachmentDescription color_attachment_resolve = {}; - VkAttachmentReference color_attachment_resolve_ref = {}; - VkSubpassDescription subpass = {}; - VkRenderPassCreateInfo renderpass_info = {}; - VkAttachmentDescription depth_attachment = {}; - VkAttachmentReference depth_attachment_ref = {}; - VkSubpassDependency dependency = {}; - - STATUS_CHECK(find_depth_format(context, &depth_attachment.format)); - - depth_attachment.samples = VK_SAMPLE_COUNT_16_BIT; - depth_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - depth_attachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - depth_attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - depth_attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - depth_attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - depth_attachment.finalLayout = - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - - depth_attachment_ref.attachment = 1; - depth_attachment_ref.layout = - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - - color_attachment.flags = 0U; - color_attachment.format = IMAGE_FORMAT; - color_attachment.samples = VK_SAMPLE_COUNT_16_BIT; - color_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - color_attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; - color_attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - color_attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - color_attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - color_attachment.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - - color_attachment_ref.attachment = 0; - color_attachment_ref.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - - color_attachment_resolve.format = IMAGE_FORMAT; - color_attachment_resolve.samples = VK_SAMPLE_COUNT_1_BIT; - color_attachment_resolve.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - color_attachment_resolve.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - color_attachment_resolve.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - color_attachment_resolve.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - color_attachment_resolve.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - color_attachment_resolve.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; - - color_attachment_resolve_ref.attachment = 2; - color_attachment_resolve_ref.layout = - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - - subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - subpass.colorAttachmentCount = 1; - subpass.pColorAttachments = &color_attachment_ref; - subpass.pDepthStencilAttachment = &depth_attachment_ref; - subpass.pResolveAttachments = &color_attachment_resolve_ref; - - attachments[0] = color_attachment; - attachments[1] = depth_attachment; - attachments[2] = color_attachment_resolve; - - dependency.srcSubpass = VK_SUBPASS_EXTERNAL; - dependency.dstSubpass = 0; - dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | - VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT; - dependency.srcAccessMask = 0; - dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | - VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT; - dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | - VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; - - renderpass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; - renderpass_info.attachmentCount = 3; - renderpass_info.pAttachments = attachments; - renderpass_info.subpassCount = 1; - renderpass_info.pSubpasses = &subpass; - renderpass_info.dependencyCount = 1; - renderpass_info.pDependencies = &dependency; - - if (VK_SUCCESS != vkCreateRenderPass(context->device, &renderpass_info, - NULL, &context->render_pass)) { - LOGF(_("Failed to create render pass\n")); - return VULKAN_ERROR_RENDERPASS_CREATION_FAILED; - } - - return RSE_ERROR_NO_ERROR; -} - /** * @brief Clean up pipeline builder. This function should be called after all * pipelines are built and no more pipelines are needed. It frees all resources @@ -339,6 +279,10 @@ static void pipeline_builder_cleanup(struct pipeline_infos_list_t* pipelines) dynamic_states = (VkDynamicState*)pipeline_info->pDynamicState->pDynamicStates; + rse_free((VkPipelineVertexInputStateCreateInfo*) + pipeline_info->pVertexInputState); + rse_free((VkPipelineDynamicStateCreateInfo*) + pipeline_info->pDynamicState); rse_free(vertex_bindings); rse_free(shader_attributes); rse_free(dynamic_states); @@ -351,140 +295,6 @@ static void pipeline_builder_cleanup(struct pipeline_infos_list_t* pipelines) } } -/** - * @brief Create a Descriptor Pool - * - * @return rse_err_t RSE_ERROR_NO_ERROR on success. Possible errors: - * VULKAN_ERROR_DESCRIPTOR_POOL_CREATION_FAILED - */ -static rse_err_t create_descriptor_pool(struct graphics_context_t* context, struct binding_info_t* binding_infos, size_t binding_count) -{ - VkDescriptorPoolSize pool_sizes[2] = {}; - VkDescriptorPoolCreateInfo pool_info = {}; - - pool_sizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - pool_sizes[0].descriptorCount = (uint32_t)(SWAP_BUFFER_COUNT); - - pool_sizes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - pool_sizes[1].descriptorCount = MAX_BINDLESS_RESOURCES; - - pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; - pool_info.poolSizeCount = 1; - pool_info.pPoolSizes = &pool_sizes[0]; - - pool_info.maxSets = (uint32_t)(SWAP_BUFFER_COUNT); - if (vkCreateDescriptorPool(context->device, &pool_info, NULL, - &context->descriptor_pool) != VK_SUCCESS) { - LOGF(_("Failed to create descriptor pool\n")); - return VULKAN_ERROR_DESCRIPTOR_POOL_CREATION_FAILED; - } - - pool_info.flags = VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT_EXT; - pool_info.maxSets = MAX_BINDLESS_RESOURCES * 2; - pool_info.pPoolSizes = &pool_sizes[1]; - - if (vkCreateDescriptorPool(context->device, &pool_info, NULL, - &context->descriptor_pool_bindless) != - VK_SUCCESS) { - LOGF(_("Failed to create descriptor pool\n")); - return VULKAN_ERROR_DESCRIPTOR_POOL_CREATION_FAILED; - } - - return RSE_ERROR_NO_ERROR; -} - -/** - * @brief Create a Descriptor Sets - * - * @return rse_err_t RSE_ERROR_NO_ERROR on success. Possible errors: - * VULKAN_ERROR_DESCRIPTOR_SETS_ALLOCATION_FAILED */ -static rse_err_t create_descriptor_sets(struct graphics_context_t* context) -{ - uint32_t max_binding = MAX_BINDLESS_RESOURCES - 1; - VkDescriptorSetLayout layouts[SWAP_BUFFER_COUNT] = { - context->descriptor_set_layout, context->descriptor_set_layout}; - VkDescriptorSetLayout layouts_bindless[SWAP_BUFFER_COUNT] = { - context->descriptor_set_layout_bindless, - context->descriptor_set_layout_bindless}; - VkDescriptorSetAllocateInfo allocInfo = {}; - VkDescriptorSetAllocateInfo allocInfo_bindless = {}; - VkDescriptorSetVariableDescriptorCountAllocateInfoEXT count_info = {}; - - count_info.sType = - VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO_EXT; - count_info.descriptorSetCount = 1; - count_info.pDescriptorCounts = &max_binding; - - allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; - allocInfo.descriptorPool = context->descriptor_pool; - allocInfo.descriptorSetCount = (uint32_t)(SWAP_BUFFER_COUNT); - allocInfo.pSetLayouts = layouts; - - allocInfo_bindless = allocInfo; - allocInfo_bindless.descriptorPool = context->descriptor_pool_bindless; - allocInfo_bindless.pSetLayouts = layouts_bindless; - allocInfo_bindless.pNext = &count_info; - allocInfo_bindless.descriptorSetCount = 1; - - if (vkAllocateDescriptorSets(context->device, &allocInfo, - context->descriptor_sets) != VK_SUCCESS) { - LOGF(_("Failed to allocate descriptor sets\n")); - return VULKAN_ERROR_DESCRIPTOR_SETS_ALLOCATION_FAILED; - } - - if (vkAllocateDescriptorSets(context->device, &allocInfo_bindless, - &context->descriptor_sets_bindless) != - VK_SUCCESS) { - LOGF(_("Failed to allocate descriptor sets\n")); - return VULKAN_ERROR_DESCRIPTOR_SETS_ALLOCATION_FAILED; - } - - for (size_t i = 0; i < SWAP_BUFFER_COUNT; i++) { - VkDescriptorBufferInfo buffer_info = {}; - VkWriteDescriptorSet descriptor_writes[2] = {}; - VkDescriptorImageInfo image_infos[RSE_MAX_IMAGE_COUNT] = {}; - size_t image_iterator = 0U; - size_t image_info_iterator = 0U; - - buffer_info.buffer = context->uniform_buffers[i].buffer; - buffer_info.offset = 0; - buffer_info.range = sizeof(struct uniform_buffer_object_t); - - for (image_iterator = 0U; image_iterator < RSE_MAX_IMAGE_COUNT; - ++image_iterator) { - if (image_exists(context, image_iterator)) { - image_infos[image_info_iterator].imageLayout = - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - image_infos[image_info_iterator].imageView = - context->swapchain_image_views[image_iterator]; - image_infos[image_info_iterator].sampler = context->sampler; - image_info_iterator++; - } - } - - descriptor_writes[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - descriptor_writes[0].dstSet = context->descriptor_sets[i]; - descriptor_writes[0].dstBinding = 0; - descriptor_writes[0].dstArrayElement = 0; - descriptor_writes[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - descriptor_writes[0].descriptorCount = 1; - descriptor_writes[0].pBufferInfo = &buffer_info; - - descriptor_writes[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - descriptor_writes[1].dstSet = context->descriptor_sets_bindless; - descriptor_writes[1].dstBinding = 1; - descriptor_writes[1].dstArrayElement = 0; - descriptor_writes[1].descriptorType = - VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - descriptor_writes[1].descriptorCount = image_info_iterator; - descriptor_writes[1].pImageInfo = image_infos; - - vkUpdateDescriptorSets(context->device, 2, descriptor_writes, 0, NULL); - } - - return RSE_ERROR_NO_ERROR; -} - rse_err_t pipeline_add_dynamic_state(struct pipeline_t* pipeline, VkDynamicState dynamic_state) { @@ -498,19 +308,21 @@ rse_err_t pipeline_add_dynamic_state(struct pipeline_t* pipeline, return RSE_ERROR_NO_ERROR; } -rse_err_t pipeline_builder_init(struct pipeline_t* pipeline) +rse_err_t pipeline_builder_init(struct pipeline_t** pipeline) { rse_err_t status = RSE_ERROR_NO_ERROR; + struct pipeline_t* pipeline_ptr = NULL; - if (pipeline != NULL) { + if (*pipeline != NULL) { LOGF( _("Pipeline is not NULL. This function will initialize everything " "for you, no need for manual allocation\n")); return VULKAN_ERROR_PIPELINE_ALREADY_INITIALIZED; } - rse_malloc(pipeline, sizeof(struct pipeline_t)); - rse_memset(pipeline, 0, sizeof(struct pipeline_t)); + rse_malloc(pipeline_ptr, sizeof(struct pipeline_t)); + rse_memset(pipeline_ptr, 0, sizeof(struct pipeline_t)); + *pipeline = pipeline_ptr; return status; } @@ -608,95 +420,31 @@ rse_err_t pipeline_add_vertex_input_attribute(struct pipeline_t* pipeline, return RSE_ERROR_NO_ERROR; } -rse_err_t pipeline_add_descriptor_layout(struct graphics_context_t* context, - struct binding_info_t* binding_infos, - size_t binding_count, - size_t* descriptor_set_index) +rse_err_t pipelines_build(struct graphics_context_t* context, + struct pipeline_infos_list_t* pipelines_infos_list) { - VkDescriptorSetLayoutCreateInfo layout_info = {}; - VkDescriptorSetLayoutBinding* bindings = NULL; - VkDescriptorSetLayoutBindingFlagsCreateInfoEXT extended_info = {0}; - VkDescriptorBindingFlags bindless_flags = - VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT_EXT | - VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT_EXT | - VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT; + assert(NULL != context); + assert(NULL != pipelines_infos_list); - if (binding_count == 0) { - LOGF(_("No bindings in descriptor set layout\n")); - return VULKAN_ERROR_DESCRIPTORSETLAYOUT_NO_BINDINGS; - } - - if (context->pipelines_data.descriptor_set_layouts_count + 1 > - MAX_DESCRIPTOR_SETS) { - LOGF(_("Too many descriptor sets\n")); - return VULKAN_ERROR_DESCRIPTORSETLAYOUT_TOO_MANY; - } - - rse_malloc(bindings, sizeof(VkDescriptorSetLayoutBinding) * binding_count); - - for (size_t i = 0; i < binding_count; i++) { - bindings[i].binding = binding_infos[i].binding; - bindings[i].descriptorType = binding_infos[i].descriptor_type; - bindings[i].descriptorCount = 1; - bindings[i].stageFlags = binding_infos[i].stage_flags; - bindings[i].pImmutableSamplers = NULL; - - if (bindings[i].descriptorType == - VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) { - bindings[i].pImmutableSamplers = NULL; - bindings[i].descriptorCount = MAX_BINDLESS_RESOURCES; - - extended_info.sType = - VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO_EXT; - extended_info.bindingCount++; - extended_info.pBindingFlags = &bindless_flags; - - layout_info.pNext = &extended_info; - layout_info.flags = - VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT_EXT; - } - } - - layout_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; - layout_info.bindingCount = (uint32_t)binding_count; - layout_info.pBindings = bindings; - - if (vkCreateDescriptorSetLayout( - context->device, &layout_info, NULL, - &context->pipelines_data.descriptor_set_layouts - [context->pipelines_data.descriptor_set_layouts_count]) != - VK_SUCCESS) { - LOGF(_("Failed to create descriptor set layout\n")); - return VULKAN_ERROR_DESCRIPTORSETLAYOUT_CREATION_FAILED; - } - - *descriptor_set_index = - context->pipelines_data.descriptor_set_layouts_count; - context->pipelines_data.descriptor_set_layouts_count++; - - rse_free(bindings); - - return RSE_ERROR_NO_ERROR; -} - - -rse_err_t build_pipelines(struct graphics_context_t* context, - struct pipeline_infos_list_t* pipelines) -{ + size_t i = 0U; rse_err_t status = RSE_ERROR_NO_ERROR; - size_t pipelines_count = RSE_LINKED_LIST_SIZE(pipelines); + size_t pipelines_count = RSE_LINKED_LIST_SIZE(pipelines_infos_list); VkGraphicsPipelineCreateInfo* pipeline_infos = NULL; context->pipelines_data.pipelines_count = pipelines_count; - create_pipeline_layout(context); - create_render_pass(context); - create_descriptor_pool(context, NULL, 0); + STATUS_CHECK(create_pipeline_layout(context)); rse_malloc(pipeline_infos, sizeof(VkGraphicsPipelineCreateInfo) * pipelines_count); - RSE_LINKED_LIST_TO_ARRAY(pipelines, pipeline_infos); + RSE_LINKED_LIST_TO_ARRAY(pipelines_infos_list, pipeline_infos); + + /* FIXME: layout is created to late. Maybe move it somewhere else so we + * don't need this loop? */ + for (i = 0; i < pipelines_count; ++i) { + pipeline_infos[i].layout = context->pipelines_data.pipeline_layout; + } if (VK_SUCCESS != vkCreateGraphicsPipelines(context->device, VK_NULL_HANDLE, @@ -707,14 +455,14 @@ rse_err_t build_pipelines(struct graphics_context_t* context, } rse_free(pipeline_infos); - pipeline_builder_cleanup(pipelines); + pipeline_builder_cleanup(pipelines_infos_list); return status; } rse_err_t add_pipeline(const struct graphics_context_t* context, struct pipeline_t* pipeline, - struct pipeline_infos_list_t* pipelines) + struct pipeline_infos_list_t** pipelines_infos) { /* Check for send and required dynamic states */ rse_err_t status = RSE_ERROR_NO_ERROR; @@ -722,14 +470,17 @@ rse_err_t add_pipeline(const struct graphics_context_t* context, size_t vertex_bindings_count = 0U; VkVertexInputBindingDescription* vertex_bindings = NULL; + VkPipelineVertexInputStateCreateInfo* vertex_bindings_ci = NULL; size_t shader_attributes_count = 0U; VkVertexInputAttributeDescription* shader_attributes = NULL; size_t dynamic_states_count = 0U; VkDynamicState* dynamic_states = NULL; + VkPipelineDynamicStateCreateInfo* dynamic_states_ci = NULL; uint8_t dynamic_state_found = 0; + while (RSE_STACK_IS_EMPTY(pipeline->required_dynamic_states) == 0) { dynamic_state_found = 0; VkDynamicState dynamic_state = @@ -794,15 +545,20 @@ rse_err_t add_pipeline(const struct graphics_context_t* context, pipeline_info.flags = 0U; pipeline_info.stageCount = pipeline->shader_stages_count; pipeline_info.pStages = pipeline->shader_stages; - pipeline_info.pVertexInputState = &(VkPipelineVertexInputStateCreateInfo){ - .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, - .pNext = NULL, - .flags = 0U, - .vertexBindingDescriptionCount = vertex_bindings_count, - .pVertexBindingDescriptions = vertex_bindings, - .vertexAttributeDescriptionCount = shader_attributes_count, - .pVertexAttributeDescriptions = shader_attributes, - }; + + rse_malloc(vertex_bindings_ci, + sizeof(VkPipelineVertexInputStateCreateInfo)); + vertex_bindings_ci->sType = + VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; + vertex_bindings_ci->pNext = NULL; + vertex_bindings_ci->flags = 0U; + vertex_bindings_ci->vertexBindingDescriptionCount = vertex_bindings_count; + vertex_bindings_ci->pVertexBindingDescriptions = vertex_bindings; + vertex_bindings_ci->vertexAttributeDescriptionCount = + shader_attributes_count; + vertex_bindings_ci->pVertexAttributeDescriptions = shader_attributes; + pipeline_info.pVertexInputState = vertex_bindings_ci; + pipeline_info.pInputAssemblyState = &pipeline->input_assembly; pipeline_info.pTessellationState = NULL; pipeline_info.pViewportState = &pipeline->viewport_state; @@ -810,19 +566,23 @@ rse_err_t add_pipeline(const struct graphics_context_t* context, pipeline_info.pMultisampleState = &pipeline->multisampling; pipeline_info.pDepthStencilState = &pipeline->depth_stencil; pipeline_info.pColorBlendState = &pipeline->color_blending; - pipeline_info.pDynamicState = &(VkPipelineDynamicStateCreateInfo){ - .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, - .pNext = NULL, - .flags = 0U, - .dynamicStateCount = dynamic_states_count, - .pDynamicStates = dynamic_states, - }; + + rse_malloc(dynamic_states_ci, sizeof(VkPipelineDynamicStateCreateInfo)); + dynamic_states_ci->sType = + VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; + dynamic_states_ci->pNext = NULL; + dynamic_states_ci->flags = 0U; + dynamic_states_ci->dynamicStateCount = dynamic_states_count; + dynamic_states_ci->pDynamicStates = dynamic_states; + pipeline_info.pDynamicState = dynamic_states_ci; + pipeline_info.layout = context->pipelines_data.pipeline_layout; pipeline_info.renderPass = context->render_pass; pipeline_info.subpass = 0; pipeline_info.basePipelineHandle = VK_NULL_HANDLE; // TODO: Add possiblity do derive from another pipeline pipeline_info.basePipelineIndex = -1; + RSE_LINKED_LIST_PUSH_BACK(*pipelines_infos, pipeline_info); return status; } @@ -831,7 +591,7 @@ void destroy_pipelines(struct graphics_context_t* context) { size_t i = 0; size_t shader_modules_count = RSE_LINKED_LIST_SIZE(context->shader_modules); - vkDestroyRenderPass(context->device, context->render_pass, NULL); + for (i = 0; i < context->pipelines_data.pipelines_count; i++) { if (context->pipelines_data.pipelines[i] != VK_NULL_HANDLE) { vkDestroyPipeline(context->device, @@ -851,8 +611,8 @@ void destroy_pipelines(struct graphics_context_t* context) for (i = 0; i < shader_modules_count; i++) { if (RSE_LINKED_LIST_FRONT(context->shader_modules) != VK_NULL_HANDLE) { vkDestroyShaderModule( - context->device, - RSE_LINKED_LIST_FRONT(context->shader_modules), NULL); + context->device, RSE_LINKED_LIST_FRONT(context->shader_modules), + NULL); } RSE_LINKED_LIST_POP_FRONT(context->shader_modules); } diff --git a/graphics/src/pipeline_builder.h b/graphics/src/pipeline_builder.h index f656cb67..2a2589d1 100644 --- a/graphics/src/pipeline_builder.h +++ b/graphics/src/pipeline_builder.h @@ -13,6 +13,7 @@ #define PIPELINE_BUILDER_H #include +#include #include "graphics_context.h" #include "utilities/commons.h" #include "utilities/linked_list.h" @@ -20,45 +21,8 @@ #define MAX_SHADER_STAGES 12U -RSE_LINKED_LIST_DEFINE(vertex_bindinlist_t, VkVertexInputBindingDescription); -RSE_LINKED_LIST_DEFINE(shader_attribute_list_t, - VkVertexInputAttributeDescription); -RSE_LINKED_LIST_DEFINE(dynamic_state_list_t, VkDynamicState); -RSE_LINKED_LIST_DEFINE(pipeline_infos_list_t, VkGraphicsPipelineCreateInfo); - -RSE_STACK_DEFINE(required_dynamic_states_t, VkDynamicState, 16U); - - -struct binding_info_t { - uint32_t binding; - VkDescriptorType descriptor_type; - VkShaderStageFlags stage_flags; -}; - -struct pipeline_t { - VkPipeline pipeline; - uint8_t id; - /* Shader stages */ - size_t shader_stages_count; - VkPipelineShaderStageCreateInfo shader_stages[MAX_SHADER_STAGES]; - /* Input assembly */ - VkPipelineInputAssemblyStateCreateInfo input_assembly; - /* Viewport state */ - VkPipelineViewportStateCreateInfo viewport_state; - /* Rasterizer */ - VkPipelineRasterizationStateCreateInfo rasterizer; - /* Multisampling */ - VkPipelineMultisampleStateCreateInfo multisampling; - /* Color blending */ - VkPipelineColorBlendAttachmentState color_blend_attachment; - VkPipelineColorBlendStateCreateInfo color_blending; - /* Depth stencil */ - VkPipelineDepthStencilStateCreateInfo depth_stencil; - struct vertex_bindinlist_t* vertex_bindings; - struct shader_attribute_list_t* shader_attributes; - struct dynamic_state_list_t* dynamic_states; - struct required_dynamic_states_t required_dynamic_states; -}; +struct pipeline_t; +struct pipeline_infos_list_t; /** * @brief Initialize pipeline builder @@ -66,7 +30,7 @@ struct pipeline_t { * @param[out] pipeline Pipeline to initialize. Must be NULL * @return RSE_SUCCESS on success, error code otherwise */ -rse_err_t pipeline_builder_init(struct pipeline_t* pipeline); +rse_err_t pipeline_builder_init(struct pipeline_t** pipeline); /** * @brief Add shader stages to pipeline @@ -115,6 +79,18 @@ rse_err_t pipeline_add_vertex_input_attribute(struct pipeline_t* pipeline, const */ rse_err_t pipeline_add_dynamic_state(struct pipeline_t* pipeline, const VkDynamicState dynamic_state); +/** + * @brief Add descriptor pool + * + * @param[in] context Graphics context handle + * @param[in] pipeline Pipeline to add descriptor pool to + * @param[in] descriptor_type Type of descriptors to be stored in this pool. + * @return RSE_SUCCESS on success, error code otherwise + */ +rse_err_t pipeline_add_descriptor_pool(struct graphics_context_t* context, + struct pipeline_t* pipeline, + enum VkDescriptorType descriptor_type); + /** * @brief Add required dynamic state to pipeline * @@ -136,7 +112,7 @@ rse_err_t pipeline_add_descriptor_layout(struct graphics_context_t* context, * @param[in] pipeline Pipelines list to build * @return RSE_SUCCESS on success, error code otherwise */ -rse_err_t build_pipelines(struct graphics_context_t* context, +rse_err_t pipelines_build(struct graphics_context_t* context, struct pipeline_infos_list_t* pipelines); /** @@ -144,10 +120,10 @@ rse_err_t build_pipelines(struct graphics_context_t* context, * * @param[in] context Graphics context handle * @param[in] pipeline Pipeline to add - * @param[out] pipelines List of pipelines + * @param[out] pipeline_info List of pipelines infos, where new info should be added * @return RSE_SUCCESS on success, error code otherwise */ -rse_err_t add_pipeline(const struct graphics_context_t* context, struct pipeline_t* pipeline, struct pipeline_infos_list_t* pipelines); +rse_err_t add_pipeline(const struct graphics_context_t* context, struct pipeline_t* pipeline, struct pipeline_infos_list_t** pipelines); /** * @brief Destroy all pipelines diff --git a/graphics/src/rse_graphics.c b/graphics/src/rse_graphics.c index 385685b2..b217956c 100644 --- a/graphics/src/rse_graphics.c +++ b/graphics/src/rse_graphics.c @@ -17,20 +17,23 @@ struct rse_graphics_context_t { struct graphics_context_t* context; }; -rse_err_t rse_graphics_init(struct rse_graphics_context_t* context) +rse_err_t rse_graphics_init(struct rse_graphics_context_t** context) { rse_err_t status = RSE_ERROR_NO_ERROR; - if (context != NULL) { + struct rse_graphics_context_t* ctx_ptr = NULL; + + if (*context != NULL) { LOGF(_("Graphics already initialized!\n")); return RSE_ERROR_ALREADY_INITIALIZED; } - rse_malloc(context, sizeof(struct rse_graphics_context_t)); - rse_malloc(context->context, sizeof(struct graphics_context_t)); - rse_memset(context->context, 0, sizeof(struct graphics_context_t)); + rse_malloc(*context, sizeof(struct rse_graphics_context_t)); + ctx_ptr = *context; + rse_malloc(ctx_ptr->context, sizeof(struct graphics_context_t)); + rse_memset(ctx_ptr->context, 0, sizeof(struct graphics_context_t)); - STATUS_CHECK(window_init(context->context->window_handle, &context->context->is_framebuffer_resized)); - STATUS_CHECK(init_vulkan(context->context)); + STATUS_CHECK(window_init(&ctx_ptr->context->window_handle, &ctx_ptr->context->is_framebuffer_resized)); + STATUS_CHECK(init_vulkan(ctx_ptr->context)); return status; } @@ -94,19 +97,21 @@ void rse_graphics_test_function(struct rse_graphics_context_t* rse_context) // print_text("Hello World!", (struct vec3_t){-1.0f, 0.0f, 0.9f}, 0.3f); /* Initialize pipeline */ - pipeline_builder_init(pipeline); + pipeline_builder_init(&pipeline); + pipeline_add_shader_stage(context, pipeline, "../graphics/shaders/shader.vert.num", VK_SHADER_STAGE_VERTEX_BIT); pipeline_add_shader_stage(context, pipeline, "../graphics/shaders/solid_objects.frag.num", VK_SHADER_STAGE_FRAGMENT_BIT); pipeline_add_vertex_input_binding(pipeline, 0, sizeof(struct vertex_t), VK_VERTEX_INPUT_RATE_VERTEX); + pipeline_add_vertex_input_binding(pipeline, 1, sizeof(struct vertex_t), VK_VERTEX_INPUT_RATE_INSTANCE); pipeline_add_vertex_input_attribute(pipeline, 0, 0, VK_FORMAT_R32G32B32_SFLOAT, offsetof(struct vertex_t, pos)); - pipeline_add_vertex_input_attribute(pipeline, 1, 0, VK_FORMAT_R32G32B32_SFLOAT, offsetof(struct vertex_t, color)); - pipeline_add_vertex_input_attribute(pipeline, 2, 0, VK_FORMAT_R32G32_SFLOAT, offsetof(struct vertex_t, tex_coords)); - pipeline_add_vertex_input_attribute(pipeline, 3, 1, VK_FORMAT_R32G32B32_SFLOAT, offsetof(struct instance_data_t, pos)); - pipeline_add_vertex_input_attribute(pipeline, 4, 1, VK_FORMAT_R32G32B32_SFLOAT, offsetof(struct instance_data_t, rot)); - pipeline_add_vertex_input_attribute(pipeline, 5, 1, VK_FORMAT_R32_SFLOAT, offsetof(struct instance_data_t, scale)); - pipeline_add_vertex_input_attribute(pipeline, 6, 1, VK_FORMAT_R32_SFLOAT, offsetof(struct instance_data_t, texture_id)); + pipeline_add_vertex_input_attribute(pipeline, 0, 1, VK_FORMAT_R32G32B32_SFLOAT, offsetof(struct vertex_t, color)); + pipeline_add_vertex_input_attribute(pipeline, 0, 2, VK_FORMAT_R32G32_SFLOAT, offsetof(struct vertex_t, tex_coords)); + pipeline_add_vertex_input_attribute(pipeline, 1, 3, VK_FORMAT_R32G32B32_SFLOAT, offsetof(struct instance_data_t, pos)); + pipeline_add_vertex_input_attribute(pipeline, 1, 4, VK_FORMAT_R32G32B32_SFLOAT, offsetof(struct instance_data_t, rot)); + pipeline_add_vertex_input_attribute(pipeline, 1, 5, VK_FORMAT_R32_SFLOAT, offsetof(struct instance_data_t, scale)); + pipeline_add_vertex_input_attribute(pipeline, 1, 6, VK_FORMAT_R32_UINT, offsetof(struct instance_data_t, texture_id)); pipeline_add_dynamic_state(pipeline, VK_DYNAMIC_STATE_VIEWPORT); pipeline_add_dynamic_state(pipeline, VK_DYNAMIC_STATE_SCISSOR); @@ -119,10 +124,13 @@ void rse_graphics_test_function(struct rse_graphics_context_t* rse_context) binding_infos[1].descriptor_type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; binding_infos[1].stage_flags = VK_SHADER_STAGE_FRAGMENT_BIT; + pipeline_add_descriptor_pool(context, pipeline, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER); + pipeline_add_descriptor_pool(context, pipeline, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER); + pipeline_add_descriptor_layout(context, &binding_infos[0], 1, &ubo_index); pipeline_add_descriptor_layout(context, &binding_infos[1], 1, &sampler_index); - add_pipeline(context, pipeline, pipeline_infos); + add_pipeline(context, pipeline, &pipeline_infos); build_pipelines(context, pipeline_infos); @@ -135,8 +143,7 @@ rse_err_t rse_graphics_run(struct rse_graphics_context_t* rse_context) rse_err_t status = RSE_ERROR_NO_ERROR; struct graphics_context_t* context = rse_context->context; - STATUS_CHECK(init_vulkan(context)); - + STATUS_CHECK(run_vulkan(context)); STATUS_CHECK(window_loop(context)); deinit_vulkan(context); diff --git a/graphics/src/text_renderer.c b/graphics/src/text_renderer.c index 07ae79f9..a44d22e7 100644 --- a/graphics/src/text_renderer.c +++ b/graphics/src/text_renderer.c @@ -3,7 +3,6 @@ #include #include "freetype/fttypes.h" -#include "locale_fonts.h" #include "font_errors.h" #include "src/mesh_controller.h" #include "src/math.h" @@ -11,6 +10,7 @@ #include "utilities/logger.h" #include "utilities/commons.h" #include "utilities/errors_common.h" +#include "utilities/localization.h" #include "vulkan_image.h" #include "vulkan/vulkan_core.h" @@ -52,7 +52,7 @@ rse_err_t fonts_initialize() } -rse_err_t fonts_load_from_file(const char* file_path) +rse_err_t fonts_load_from_file(struct graphics_context_t* context, const char* file_path) { rse_err_t status = RSE_ERROR_NO_ERROR; FT_Error error; @@ -110,9 +110,9 @@ rse_err_t fonts_load_from_file(const char* file_path) {g_fonts_data[iter].bearing_x, g_fonts_data[iter].height, 0.0f}, {1.0f, 1.0f, 1.0f}, {0.0f, 1.0f} }; - g_fonts_data[iter].mesh_id = create_mesh(font_vertices, font_indices, 8, 6); + g_fonts_data[iter].mesh_id = create_mesh(context, font_vertices, font_indices, 8, 6); - STATUS_CHECK(load_texture_from_bitmat(face->glyph->bitmap.buffer, + STATUS_CHECK(load_texture_from_bitmat(context, face->glyph->bitmap.buffer, face->glyph->bitmap.width, face->glyph->bitmap.rows, &g_fonts_data[iter].texture_id, VK_FORMAT_R8_SRGB)); @@ -121,7 +121,7 @@ rse_err_t fonts_load_from_file(const char* file_path) return status; } -rse_err_t print_text(const char* text, struct vec3_t position, float font_size) +rse_err_t print_text(struct graphics_context_t* context, const char* text, struct vec3_t position, float font_size) { rse_err_t status = RSE_ERROR_NO_ERROR; size_t iter = 0U; @@ -140,7 +140,7 @@ rse_err_t print_text(const char* text, struct vec3_t position, float font_size) x_pos = position.x + advance - (g_fonts_data[charactet_code].bearing_x * scale); y_pos = position.y - (g_fonts_data[charactet_code].bearing_y * scale); - create_mesh_instance(g_fonts_data[charactet_code].mesh_id, (struct instance_data_t){ + create_mesh_instance(context, g_fonts_data[charactet_code].mesh_id, (struct instance_data_t){ {x_pos, y_pos, 0.0f}, {0.0f, 0.0f, math_deg_to_radians(0.0f)}, FONT_SCALING * font_size, diff --git a/graphics/src/text_renderer.h b/graphics/src/text_renderer.h index 2cb4187c..524bc95f 100644 --- a/graphics/src/text_renderer.h +++ b/graphics/src/text_renderer.h @@ -15,10 +15,11 @@ #define TEXT_RENDERER_H #include "utilities/commons.h" +#include "graphics_context.h" #include "math.h" rse_err_t fonts_initialize(void); -rse_err_t fonts_load_from_file(const char* file_path); -rse_err_t print_text(const char* text, struct vec3_t position, float font_size); +rse_err_t fonts_load_from_file(struct graphics_context_t* context, const char* file_path); +rse_err_t print_text(struct graphics_context_t* context, const char* text, struct vec3_t position, float font_size); #endif // !TEXT_RENDERER_H_ diff --git a/graphics/src/vulkan_base.c b/graphics/src/vulkan_base.c index e36d67c9..3a41b59e 100644 --- a/graphics/src/vulkan_base.c +++ b/graphics/src/vulkan_base.c @@ -1,5 +1,5 @@ /** - * @file vulkanBase.cpp + * @file vulkanBase.cp * @author Piotr Krygier (everyonecancode@gmail.com) * @brief Base configuration for Vulkan API * @version 0.1 @@ -27,6 +27,7 @@ #include "vk_mem_alloc.h" // #pragma GCC diagnostic pop +#include "utilities/commons.h" #include "utilities/errors_common.h" #include "utilities/logger.h" #include "vulkan/vulkan_core.h" @@ -35,8 +36,10 @@ #include "vulkan_commons.h" #include "vulkan_commands.h" #include "vulkan_buffers.h" -#include "vulkan_descriptors.h" #include "vulkan_image.h" +#include "vulkan_render_pass.h" +#include "vulkan_swapchain.h" +#include "pipeline_builder.h" #include #include @@ -558,9 +561,11 @@ rse_err_t init_vulkan(struct graphics_context_t* context) STATUS_CHECK(pick_physical_device(context->instance, &context->physical_device)); STATUS_CHECK(create_device(context)); STATUS_CHECK(create_memory_allocator(context)); + STATUS_CHECK(create_render_pass(context)); STATUS_CHECK(init_commands(context)); STATUS_CHECK(create_buffers(context)); STATUS_CHECK(init_vulkan_images(context)); + STATUS_CHECK(create_swapchain_and_framebuffers(context)); return status; } @@ -569,7 +574,6 @@ rse_err_t run_vulkan(struct graphics_context_t* context) { rse_err_t status = RSE_ERROR_NO_ERROR; - STATUS_CHECK(create_descriptors(context)); STATUS_CHECK(create_sync_objects(context)); init_time(); @@ -596,7 +600,7 @@ rse_err_t draw_frame(struct graphics_context_t* context) VK_NULL_HANDLE, &image_index); if (result == VK_ERROR_OUT_OF_DATE_KHR) { - recreate_swapchain(); + recreate_swapchain(context); return RSE_ERROR_NO_ERROR; } else if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) { LOGF(_("Failed to acquire swapchain image\n")); @@ -646,7 +650,7 @@ rse_err_t draw_frame(struct graphics_context_t* context) if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || context->is_framebuffer_resized) { context->is_framebuffer_resized = false; - recreate_swapchain(); + recreate_swapchain(context); } else if (result != VK_SUCCESS) { LOGF(_("Failed to submit draw command buffer!\n")); return VULKAN_ERROR_DRAW_FAILED; @@ -659,8 +663,6 @@ rse_err_t draw_frame(struct graphics_context_t* context) void deinit_vulkan(struct graphics_context_t* context) { - cleanup_swapchain(); - destroy_descriptors(); destroy_buffers(context); for (size_t i = 0; i < SWAP_BUFFER_COUNT; ++i) { vkDestroySemaphore(context->device, context->image_available_semaphores[i], NULL); @@ -668,11 +670,13 @@ void deinit_vulkan(struct graphics_context_t* context) vkDestroyFence(context->device, context->in_flight_fences[i], NULL); } - destroy_textures(); + destroy_textures(context); destroy_commands(context); - destroy_pipeline(); + destroy_render_pass(context); + cleanup_swapchain(context); + destroy_pipelines(context); vmaDestroyAllocator(context->allocator); vkDestroyDevice(context->device, NULL); diff --git a/graphics/src/vulkan_buffers.c b/graphics/src/vulkan_buffers.c index ee3d624f..61cd5e80 100644 --- a/graphics/src/vulkan_buffers.c +++ b/graphics/src/vulkan_buffers.c @@ -3,6 +3,7 @@ #include "src/graphics_context.h" #include "src/vulkan_commons.h" #include "utilities/commons.h" +#include "utilities/linked_list.h" #include "vulkan_errors.h" #include "utilities/logger.h" #include "utilities/localization.h" @@ -321,8 +322,7 @@ rse_err_t update_mesh_instances(struct graphics_context_t* context, uint16_t mes rse_err_t record_command_buffer(struct graphics_context_t* context, uint32_t image_index) { VkCommandBuffer command_buffer = context->command_buffers[context->current_frame]; - VkDescriptorSet descriptor_sets[] = {context->descriptor_sets[context->current_frame], - context->descriptor_sets_bindless}; + VkDescriptorSet* descriptor_sets = NULL; VkCommandBufferBeginInfo begin_info = {}; VkRenderPassBeginInfo render_pass_info = {}; VkViewport viewport = {}; @@ -331,6 +331,9 @@ rse_err_t record_command_buffer(struct graphics_context_t* context, uint32_t ima VkClearValue clear_values[2] = {}; //For color and depth stencil size_t i = 0U; + + RSE_LINKED_LIST_TO_ARRAY(context->pipelines_data.descriptor_sets, descriptor_sets); + clear_values[0].color.float32[0] = 0.0f; clear_values[0].color.float32[1] = 0.0f; clear_values[0].color.float32[2] = 0.0f; @@ -357,7 +360,8 @@ rse_err_t record_command_buffer(struct graphics_context_t* context, uint32_t ima render_pass_info.pClearValues = clear_values; vkCmdBeginRenderPass(command_buffer, &render_pass_info, VK_SUBPASS_CONTENTS_INLINE); - vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, context->graphics_pipeline); + /* TODO: Iterate over pipelines, do NOT hardocde 0 here */ + vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, context->pipelines_data.pipelines[0]); viewport.x = 0.0f; viewport.y = 0.0f; @@ -374,7 +378,7 @@ rse_err_t record_command_buffer(struct graphics_context_t* context, uint32_t ima vkCmdBindVertexBuffers(command_buffer, 0, 1, &context->vertex_buffer.buffer, offsets); vkCmdBindIndexBuffer(command_buffer, context->index_buffer.buffer, 0, VK_INDEX_TYPE_UINT16); - vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, context->pipeline_layout, 0, 2, + vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, context->pipelines_data.pipeline_layout, 0, 2, descriptor_sets, 0, NULL); for (i = 0; i < MAX_MESH_NUMBER; ++i) { diff --git a/graphics/src/vulkan_errors.h b/graphics/src/vulkan_errors.h index 7cecea8f..56fd5937 100644 --- a/graphics/src/vulkan_errors.h +++ b/graphics/src/vulkan_errors.h @@ -56,6 +56,7 @@ enum vulkan_error_t VULKAN_ERROR_PIPELINE_MISSING_SHADER_MODULES, VULKAN_ERROR_DRAW_FAILED, VULKAN_ERROR_PIPELINE_ALREADY_INITIALIZED, + VULKAN_ERROR_UNKNOWN_DESCRIPTOR_TYPE, }; #endif diff --git a/graphics/src/vulkan_image.c b/graphics/src/vulkan_image.c index f81005f1..0b63413c 100644 --- a/graphics/src/vulkan_image.c +++ b/graphics/src/vulkan_image.c @@ -2,7 +2,6 @@ #include -#include "src/vulkan_pipeline.h" #include "utilities/commons.h" #include "utilities/errors_common.h" #include "utilities/file_utils.h" @@ -18,8 +17,7 @@ #include #include -#include "stb_image.h" -#include "vma/vk_mem_alloc.h" +#include "stb/stb_image.h" #define IMAGE_TAKEN 1U #define IMAGE_FREE 0U @@ -190,7 +188,7 @@ rse_err_t create_color_resource(struct graphics_context_t* context) create_image(context, &context->color_image, physical_device_surface_capabilities.currentExtent.width, physical_device_surface_capabilities.currentExtent.height, - color_format, VK_SAMPLE_COUNT_16_BIT, + color_format, VK_SAMPLE_COUNT_8_BIT, VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, 0U)); @@ -215,7 +213,7 @@ rse_err_t create_depth_resources(struct graphics_context_t* context) create_image(context, &context->depth_image, physical_device_surface_capabilities.currentExtent.width, physical_device_surface_capabilities.currentExtent.height, - depth_format, VK_SAMPLE_COUNT_16_BIT, + depth_format, VK_SAMPLE_COUNT_8_BIT, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, 0U)); STATUS_CHECK(create_image_view(context, &context->depth_image, depth_format, VK_IMAGE_ASPECT_DEPTH_BIT)); @@ -349,7 +347,7 @@ static rse_err_t create_textured_image(struct graphics_context_t* context, STATUS_CHECK(create_image( context, free_texture_image, width, height, format, - VK_SAMPLE_COUNT_1_BIT, + VK_SAMPLE_COUNT_8_BIT, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT)); diff --git a/graphics/src/vulkan_render_pass.c b/graphics/src/vulkan_render_pass.c new file mode 100644 index 00000000..4cfcf6cd --- /dev/null +++ b/graphics/src/vulkan_render_pass.c @@ -0,0 +1,115 @@ +/** + * @file vulkan_render_pass.c + * @author Piotr Krygier (piotrkrygier@everyonecancode.xyz) + * @brief + * @version 0.1 + * @date 20-02-2025 + * + * @copyright Copyright (c) 2025 + * + */ + +#include "vulkan_render_pass.h" + +#include "vulkan_image.h" +#include "vulkan_errors.h" +#include "utilities/errors_common.h" +#include "utilities/logger.h" +#include "utilities/localization.h" + +rse_err_t create_render_pass(struct graphics_context_t* context) +{ + rse_err_t status = RSE_ERROR_NO_ERROR; + VkAttachmentDescription attachments[3] = {}; + VkAttachmentDescription color_attachment = {}; + VkAttachmentReference color_attachment_ref = {}; + VkAttachmentDescription color_attachment_resolve = {}; + VkAttachmentReference color_attachment_resolve_ref = {}; + VkSubpassDescription subpass = {}; + VkRenderPassCreateInfo renderpass_info = {}; + VkAttachmentDescription depth_attachment = {}; + VkAttachmentReference depth_attachment_ref = {}; + VkSubpassDependency dependency = {}; + + STATUS_CHECK(find_depth_format(context, &depth_attachment.format)); + + depth_attachment.samples = VK_SAMPLE_COUNT_8_BIT; + depth_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + depth_attachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + depth_attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + depth_attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + depth_attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + depth_attachment.finalLayout = + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + + depth_attachment_ref.attachment = 1; + depth_attachment_ref.layout = + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + + color_attachment.flags = 0U; + color_attachment.format = IMAGE_FORMAT; + color_attachment.samples = VK_SAMPLE_COUNT_8_BIT; + color_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + color_attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + color_attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + color_attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + color_attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + color_attachment.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + color_attachment_ref.attachment = 0; + color_attachment_ref.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + color_attachment_resolve.format = IMAGE_FORMAT; + color_attachment_resolve.samples = VK_SAMPLE_COUNT_1_BIT; + color_attachment_resolve.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + color_attachment_resolve.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + color_attachment_resolve.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + color_attachment_resolve.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + color_attachment_resolve.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + color_attachment_resolve.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + + color_attachment_resolve_ref.attachment = 2; + color_attachment_resolve_ref.layout = + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpass.colorAttachmentCount = 1; + subpass.pColorAttachments = &color_attachment_ref; + subpass.pDepthStencilAttachment = &depth_attachment_ref; + subpass.pResolveAttachments = &color_attachment_resolve_ref; + + attachments[0] = color_attachment; + attachments[1] = depth_attachment; + attachments[2] = color_attachment_resolve; + + dependency.srcSubpass = VK_SUBPASS_EXTERNAL; + dependency.dstSubpass = 0; + dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | + VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT; + dependency.srcAccessMask = 0; + dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | + VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT; + dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; + + renderpass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + renderpass_info.attachmentCount = 3; + renderpass_info.pAttachments = attachments; + renderpass_info.subpassCount = 1; + renderpass_info.pSubpasses = &subpass; + renderpass_info.dependencyCount = 1; + renderpass_info.pDependencies = &dependency; + + if (VK_SUCCESS != vkCreateRenderPass(context->device, &renderpass_info, + NULL, &context->render_pass)) { + LOGF(_("Failed to create render pass\n")); + return VULKAN_ERROR_RENDERPASS_CREATION_FAILED; + } + + return RSE_ERROR_NO_ERROR; +} + +void destroy_render_pass(struct graphics_context_t* context) +{ + vkDestroyRenderPass(context->device, context->render_pass, NULL); +} \ No newline at end of file diff --git a/graphics/src/vulkan_render_pass.h b/graphics/src/vulkan_render_pass.h new file mode 100644 index 00000000..e9d9fdc8 --- /dev/null +++ b/graphics/src/vulkan_render_pass.h @@ -0,0 +1,33 @@ +/** + * @file vulkan_render_pass.h + * @author Piotr Krygier (piotrkrygier@everyonecancode.xyz) + * @brief + * @version 0.1 + * @date 20-02-2025 + * + * @copyright Copyright (c) 2025 + * + */ + +#ifndef VULKAN_RENDER_PASS_H_ +#define VULKAN_RENDER_PASS_H_ + +#include "utilities/commons.h" +#include "graphics_context.h" + +/** + * @brief Create a render pass + * + * @param context Graphics context + * @return rse_err_t RSE_ERROR_NO_ERROR on success + */ +rse_err_t create_render_pass(struct graphics_context_t* context); + +/** + * @brief Destroy render pass + * + * @param context Graphics context + */ +void destroy_render_pass(struct graphics_context_t* context); + +#endif /* VULKAN_RENDER_PASS_H_ */ \ No newline at end of file diff --git a/graphics/src/vulkan_swapchain.h b/graphics/src/vulkan_swapchain.h index c22a045a..794a95d9 100644 --- a/graphics/src/vulkan_swapchain.h +++ b/graphics/src/vulkan_swapchain.h @@ -16,4 +16,12 @@ void cleanup_swapchain(struct graphics_context_t* context); */ void recreate_swapchain(struct graphics_context_t* context); +/** + * @brief Create a swapchain and framebuffers object + * + * @param context graphical context + * @return rse_err_t RSE_ERROR_NO_ERROR on success + */ +rse_err_t create_swapchain_and_framebuffers(struct graphics_context_t* context); + #endif /* VULKAN_SWAPCHAIN_H */ diff --git a/graphics/src/window.c b/graphics/src/window.c index 24542ccc..f118c5ec 100644 --- a/graphics/src/window.c +++ b/graphics/src/window.c @@ -61,7 +61,7 @@ static void framebuffer_resized_callback(GLFWwindow* window, int width, int heig } -rse_err_t window_init(GLFWwindow* window_handle, bool* is_framebuffer_resized) +rse_err_t window_init(GLFWwindow** window_handle, bool* is_framebuffer_resized) { /* Initiliaze GLFW AP */ if (GLFW_TRUE != glfwInit()) @@ -83,16 +83,16 @@ rse_err_t window_init(GLFWwindow* window_handle, bool* is_framebuffer_resized) /* Create window */ glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); - window_handle = glfwCreateWindow(640, 480, "RedScarfEngine", NULL, NULL); + *window_handle = glfwCreateWindow(640, 480, "RedScarfEngine", NULL, NULL); - if (NULL == window_handle) { + if (NULL == *window_handle) { LOGF(_("Window context creation failed\n")); return WINDOW_ERROR_WINDOW_NOT_CREATED; } - glfwSetKeyCallback(window_handle, key_callback); - glfwSetFramebufferSizeCallback(window_handle, framebuffer_resized_callback); - glfwSetWindowUserPointer(window_handle, is_framebuffer_resized); + glfwSetKeyCallback(*window_handle, key_callback); + glfwSetFramebufferSizeCallback(*window_handle, framebuffer_resized_callback); + glfwSetWindowUserPointer(*window_handle, is_framebuffer_resized); return RSE_ERROR_NO_ERROR; } diff --git a/graphics/src/window.h b/graphics/src/window.h index 0216e463..2529d9c1 100644 --- a/graphics/src/window.h +++ b/graphics/src/window.h @@ -30,7 +30,7 @@ * WINDOW_WINDOW_NOT_CREATED * */ -rse_err_t window_init(GLFWwindow* window_handle, bool* is_framebuffer_resized); +rse_err_t window_init(GLFWwindow** window_handle, bool* is_framebuffer_resized); /** * @brief Main window loop diff --git a/red_scarf_engine/src/main.c b/red_scarf_engine/src/main.c index 637d7422..cbbbc0da 100644 --- a/red_scarf_engine/src/main.c +++ b/red_scarf_engine/src/main.c @@ -1,16 +1,17 @@ -#include "graphics/graphics.h" #include "graphics/rse_graphics.h" #include "utilities/task.h" +#include "utilities/errors_common.h" int main(int argc, char** argv) { + rse_err_t status = RSE_ERROR_NO_ERROR; thread_t graphics_task; struct rse_graphics_context_t* context = NULL; (void)argc; (void)argv; - rse_graphics_init(context); + STATUS_CHECK(rse_graphics_init(&context)); rse_graphics_test_function(context); create_task(&graphics_task, (thread_worker_t)rse_graphics_run, context); diff --git a/utilities/errors_common.h b/utilities/errors_common.h index c5244455..0d09426d 100644 --- a/utilities/errors_common.h +++ b/utilities/errors_common.h @@ -23,6 +23,7 @@ enum common_error_t { RSE_ERROR_NO_ERROR = RSE_COMMON_MODULE_ID, + RSE_ERROR_NULL_POINTER, RSE_ERROR_ALREADY_INITIALIZED, RSE_COMMON_ERROR_MALLLOC_FAILED, }; diff --git a/utilities/linked_list.h b/utilities/linked_list.h index fd5b4e06..946369d0 100644 --- a/utilities/linked_list.h +++ b/utilities/linked_list.h @@ -86,7 +86,7 @@ } #define RSE_LINKED_LIST_IS_EMPTY(list) \ - list == NULL + (list == NULL) #define RSE_LINKED_LIST_SIZE(list) \ ({ \ diff --git a/utilities/src/file_utils.c b/utilities/src/file_utils.c index d594676a..fab141bc 100644 --- a/utilities/src/file_utils.c +++ b/utilities/src/file_utils.c @@ -1,4 +1,4 @@ -#include "file_utils.h" +#include "utilities/file_utils.h" #include #include diff --git a/utilities/src/logger.c b/utilities/src/logger.c index c9bb2ed1..c5bf0847 100644 --- a/utilities/src/logger.c +++ b/utilities/src/logger.c @@ -1,4 +1,4 @@ -#include "logger.h" +#include "utilities/logger.h" #include "stdarg.h" const char* log_levels[] = { diff --git a/utilities/src/task_linux.c b/utilities/src/task_linux.c index 60e09c9b..d15781a4 100644 --- a/utilities/src/task_linux.c +++ b/utilities/src/task_linux.c @@ -1,4 +1,4 @@ -#include "task.h" +#include "utilities/task.h" uint8_t create_task(thread_t* thread_id, thread_worker_t callback, void* args) { diff --git a/utilities/stack.h b/utilities/stack.h index 4ffcec68..85dac1b8 100644 --- a/utilities/stack.h +++ b/utilities/stack.h @@ -28,18 +28,18 @@ stack.data[stack.top] #define RSE_STACK_IS_EMPTY(stack) \ - stack.top == -1 + (stack.top == -1) #define RSE_STACK_IS_FULL(stack, size) \ - stack.top == size - 1 + (stack.top == size - 1) #define RSE_STACK_INIT(stack) \ - stack.top = -1 + (stack.top = -1) #define RSE_STACK_SIZE(stack) \ - stack.top + 1 + (stack.top + 1) #define RSE_STACK_CLEAR(stack) \ - stack.top = -1 + (stack.top = -1) #endif // STACK_H