[WIP] Refactor project
There are many problems with the way the current version is provided and maintained. This commit or series of commits will fix this.
This commit is contained in:
1 parent
f5ab5f3f27
commit
173a82b9d1
63 files changed
+2663
-2239
No files matched your search
@@ -0,0 +1,859 @@
|
||||
/**
|
||||
* @file pipeline_builder.c
|
||||
* @author Piotr Krygier (everyonecancode@gmail.com)
|
||||
* @brief
|
||||
* @version 0.1
|
||||
* @date 2024-03-01
|
||||
*
|
||||
* @copyright Copyright (c) 2024
|
||||
*
|
||||
*/
|
||||
|
||||
#include "pipeline_builder.h"
|
||||
|
||||
#include "utilities/commons.h"
|
||||
#include "utilities/errors_common.h"
|
||||
#include "utilities/file_utils.h"
|
||||
#include "utilities/linked_list.h"
|
||||
#include "utilities/localization.h"
|
||||
#include "vulkan/vulkan_core.h"
|
||||
#include "vulkan_errors.h"
|
||||
#include "vulkan_image.h"
|
||||
|
||||
#define MAX_BINDLESS_RESOURCES 1000
|
||||
|
||||
/**
|
||||
* @brief Creates shader module
|
||||
*
|
||||
* @param binary_data Shader compiled code
|
||||
* @return rse_err_t RSE_ERROR_NO_ERROR on success
|
||||
*/
|
||||
static rse_err_t create_shader_module(struct graphics_context_t* context,
|
||||
struct pipeline_t* pipeline,
|
||||
const char* binary_data, size_t data_size)
|
||||
{
|
||||
VkShaderModuleCreateInfo create_info = {};
|
||||
|
||||
create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
|
||||
create_info.pNext = NULL;
|
||||
create_info.flags = 0U;
|
||||
create_info.codeSize = data_size;
|
||||
create_info.pCode = (const uint32_t*)(binary_data);
|
||||
|
||||
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))) {
|
||||
LOGF(_("Failed to create a shader\n"));
|
||||
return VULKAN_ERROR_SHADER_CREATION_FAILED;
|
||||
}
|
||||
|
||||
return RSE_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
static rse_err_t pipeline_add_input_assembly(struct pipeline_t* pipeline)
|
||||
{
|
||||
/* For now input assebly is hardcoded */
|
||||
pipeline->input_assembly.sType =
|
||||
VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
|
||||
pipeline->input_assembly.pNext = NULL;
|
||||
pipeline->input_assembly.flags = 0U;
|
||||
pipeline->input_assembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
||||
pipeline->input_assembly.primitiveRestartEnable = VK_FALSE;
|
||||
|
||||
return RSE_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
static rse_err_t pipeline_add_viewport_state(struct pipeline_t* pipeline)
|
||||
{
|
||||
/* For now viewport is hardcoded */
|
||||
pipeline->viewport_state.sType =
|
||||
VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
|
||||
pipeline->viewport_state.pNext = NULL;
|
||||
pipeline->viewport_state.flags = 0U;
|
||||
pipeline->viewport_state.viewportCount = 1U;
|
||||
pipeline->viewport_state.pViewports =
|
||||
NULL; /* This is set during rendering */
|
||||
pipeline->viewport_state.scissorCount = 1U;
|
||||
pipeline->viewport_state.pScissors =
|
||||
NULL; /* This is set during rendering */
|
||||
|
||||
if (pipeline->viewport_state.pViewports == NULL ||
|
||||
pipeline->viewport_state.viewportCount == 0U) {
|
||||
RSE_STACK_PUSH(pipeline->required_dynamic_states,
|
||||
VK_DYNAMIC_STATE_VIEWPORT);
|
||||
}
|
||||
|
||||
if (pipeline->viewport_state.pScissors == NULL ||
|
||||
pipeline->viewport_state.scissorCount == 0U) {
|
||||
RSE_STACK_PUSH(pipeline->required_dynamic_states,
|
||||
VK_DYNAMIC_STATE_SCISSOR);
|
||||
}
|
||||
|
||||
return RSE_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
static rse_err_t pipeline_add_rasterizer(struct pipeline_t* pipeline)
|
||||
{
|
||||
/* For now rasterizer is hardcoded */
|
||||
pipeline->rasterizer.sType =
|
||||
VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
|
||||
pipeline->rasterizer.pNext = NULL;
|
||||
pipeline->rasterizer.flags = 0U;
|
||||
pipeline->rasterizer.depthClampEnable =
|
||||
VK_FALSE; /* VK_TRUE to play with shadow maps */
|
||||
pipeline->rasterizer.rasterizerDiscardEnable =
|
||||
VK_FALSE; /* Disable/Enable output to framebuffer*/
|
||||
pipeline->rasterizer.polygonMode = VK_POLYGON_MODE_FILL;
|
||||
pipeline->rasterizer.cullMode = VK_CULL_MODE_BACK_BIT;
|
||||
pipeline->rasterizer.frontFace = VK_FRONT_FACE_CLOCKWISE;
|
||||
pipeline->rasterizer.depthBiasEnable = VK_FALSE;
|
||||
pipeline->rasterizer.depthBiasConstantFactor = 0.0f;
|
||||
pipeline->rasterizer.depthBiasClamp = 0.0f;
|
||||
pipeline->rasterizer.depthBiasSlopeFactor = 0.0f;
|
||||
pipeline->rasterizer.lineWidth = 1.0f;
|
||||
|
||||
return RSE_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
static rse_err_t pipeline_add_multisampling(struct pipeline_t* pipeline)
|
||||
{
|
||||
/* For now multisampling is hardcoded */
|
||||
pipeline->multisampling.sType =
|
||||
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.sampleShadingEnable = VK_FALSE;
|
||||
pipeline->multisampling.minSampleShading = 1.0f;
|
||||
pipeline->multisampling.pSampleMask = NULL;
|
||||
pipeline->multisampling.alphaToCoverageEnable = VK_FALSE;
|
||||
pipeline->multisampling.alphaToOneEnable = VK_FALSE;
|
||||
|
||||
return RSE_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
static rse_err_t pipeline_add_color_blending(struct pipeline_t* pipeline)
|
||||
{
|
||||
/* For now color blending is hardcoded */
|
||||
pipeline->color_blend_attachment.colorWriteMask =
|
||||
VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
|
||||
VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
|
||||
pipeline->color_blend_attachment.blendEnable = VK_TRUE;
|
||||
pipeline->color_blend_attachment.srcColorBlendFactor =
|
||||
VK_BLEND_FACTOR_SRC_ALPHA;
|
||||
pipeline->color_blend_attachment.dstColorBlendFactor =
|
||||
VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
|
||||
pipeline->color_blend_attachment.colorBlendOp = VK_BLEND_OP_ADD;
|
||||
pipeline->color_blend_attachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
|
||||
pipeline->color_blend_attachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
|
||||
pipeline->color_blend_attachment.alphaBlendOp = VK_BLEND_OP_ADD;
|
||||
|
||||
pipeline->color_blending.sType =
|
||||
VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
|
||||
pipeline->color_blending.pNext = NULL;
|
||||
pipeline->color_blending.flags = 0U;
|
||||
pipeline->color_blending.logicOpEnable = VK_FALSE;
|
||||
pipeline->color_blending.logicOp = VK_LOGIC_OP_COPY;
|
||||
pipeline->color_blending.attachmentCount = 1U;
|
||||
pipeline->color_blending.pAttachments = &pipeline->color_blend_attachment;
|
||||
pipeline->color_blending.blendConstants[0] = 0.0f;
|
||||
pipeline->color_blending.blendConstants[1] = 0.0f;
|
||||
pipeline->color_blending.blendConstants[2] = 0.0f;
|
||||
pipeline->color_blending.blendConstants[3] = 0.0f;
|
||||
|
||||
return RSE_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
static rse_err_t pipeline_add_depth_stencil(struct pipeline_t* pipeline)
|
||||
{
|
||||
/* For now depth stencil is hardcoded */
|
||||
pipeline->depth_stencil.sType =
|
||||
VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
|
||||
pipeline->depth_stencil.pNext = NULL;
|
||||
pipeline->depth_stencil.flags = 0U;
|
||||
pipeline->depth_stencil.depthTestEnable = VK_TRUE;
|
||||
pipeline->depth_stencil.depthWriteEnable = VK_TRUE;
|
||||
pipeline->depth_stencil.depthCompareOp = VK_COMPARE_OP_LESS;
|
||||
pipeline->depth_stencil.depthBoundsTestEnable = VK_FALSE;
|
||||
pipeline->depth_stencil.stencilTestEnable = VK_FALSE;
|
||||
pipeline->depth_stencil.minDepthBounds = 0.0f;
|
||||
pipeline->depth_stencil.maxDepthBounds = 1.0f;
|
||||
|
||||
return RSE_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Create a Pipeline Layout
|
||||
*
|
||||
* @return rse_err_t RSE_ERROR_NO_ERROR on success. Possible errors:
|
||||
* VULKAN_ERROR_PIPELINE_LAYOUT_CREATION_FAILED
|
||||
*/
|
||||
static rse_err_t create_pipeline_layout(struct graphics_context_t* context)
|
||||
{
|
||||
VkPipelineLayoutCreateInfo create_info = {};
|
||||
create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
|
||||
create_info.pNext = NULL;
|
||||
create_info.flags = 0U;
|
||||
create_info.setLayoutCount =
|
||||
context->pipelines_data.descriptor_set_layouts_count;
|
||||
create_info.pSetLayouts = context->pipelines_data.descriptor_set_layouts;
|
||||
create_info.pushConstantRangeCount = 0U;
|
||||
create_info.pPushConstantRanges = NULL;
|
||||
|
||||
if (VK_SUCCESS !=
|
||||
vkCreatePipelineLayout(context->device, &create_info, NULL,
|
||||
&context->pipelines_data.pipeline_layout)) {
|
||||
LOGF(_("Failed to create pipeline layout\n"));
|
||||
return VULKAN_ERROR_PIPELINE_LAYOUT_CREATION_FAILED;
|
||||
}
|
||||
|
||||
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
|
||||
* used by pipeline builder.
|
||||
*
|
||||
* @param[in/out] pipelines List of pipelines to clean up
|
||||
*/
|
||||
static void pipeline_builder_cleanup(struct pipeline_infos_list_t* pipelines)
|
||||
{
|
||||
size_t pipeline_count = RSE_LINKED_LIST_SIZE(pipelines);
|
||||
VkVertexInputBindingDescription* vertex_bindings = NULL;
|
||||
VkVertexInputAttributeDescription* shader_attributes = NULL;
|
||||
VkDynamicState* dynamic_states = NULL;
|
||||
|
||||
for (size_t i = 0; i < pipeline_count; i++) {
|
||||
VkGraphicsPipelineCreateInfo* pipeline_info =
|
||||
&RSE_LINKED_LIST_FRONT(pipelines);
|
||||
if (pipeline_info != NULL) {
|
||||
vertex_bindings =
|
||||
(VkVertexInputBindingDescription*)pipeline_info
|
||||
->pVertexInputState->pVertexBindingDescriptions;
|
||||
|
||||
shader_attributes =
|
||||
(VkVertexInputAttributeDescription*)pipeline_info
|
||||
->pVertexInputState->pVertexAttributeDescriptions;
|
||||
|
||||
dynamic_states =
|
||||
(VkDynamicState*)pipeline_info->pDynamicState->pDynamicStates;
|
||||
|
||||
rse_free(vertex_bindings);
|
||||
rse_free(shader_attributes);
|
||||
rse_free(dynamic_states);
|
||||
}
|
||||
RSE_LINKED_LIST_POP_FRONT(pipelines);
|
||||
}
|
||||
|
||||
if (RSE_LINKED_LIST_IS_EMPTY(pipelines) == 0) {
|
||||
LOGF(_("Failed to clean up pipelines\n"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
if (dynamic_state >= VK_DYNAMIC_STATE_MAX_ENUM) {
|
||||
LOGF(_("Invalid dynamic state in pipeline\n"));
|
||||
return VULKAN_ERROR_PIPELINE_INVALID_DYNAMIC_STATE;
|
||||
}
|
||||
|
||||
RSE_LINKED_LIST_PUSH_FRONT(pipeline->dynamic_states, dynamic_state);
|
||||
|
||||
return RSE_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
rse_err_t pipeline_builder_init(struct pipeline_t* pipeline)
|
||||
{
|
||||
rse_err_t status = RSE_ERROR_NO_ERROR;
|
||||
|
||||
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));
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
rse_err_t pipeline_add_shader_stage(struct graphics_context_t* context,
|
||||
struct pipeline_t* pipeline,
|
||||
const char* shader_path,
|
||||
const VkShaderStageFlagBits shader_stage)
|
||||
{
|
||||
size_t i = 0;
|
||||
rse_err_t status = RSE_ERROR_NO_ERROR;
|
||||
char* buffer = NULL;
|
||||
size_t buffer_size = 0U;
|
||||
|
||||
/* Check if we have enough space for new shader stages */
|
||||
if (pipeline->shader_stages_count + 1 > MAX_SHADER_STAGES) {
|
||||
LOGF(_("Too many shader stages in pipeline\n"));
|
||||
return VULKAN_ERROR_PIPELINE_TOO_MANY_SHADER_STAGES;
|
||||
}
|
||||
|
||||
i = pipeline->shader_stages_count++;
|
||||
|
||||
/* Check if shader module is valid */
|
||||
if (shader_stage >= VK_SHADER_STAGE_FLAG_BITS_MAX_ENUM) {
|
||||
LOGF(_("Invalid shader stage in pipeline\n"));
|
||||
return VULKAN_ERROR_PIPELINE_INVALID_SHADER_STAGE;
|
||||
}
|
||||
|
||||
/* Read shader file */
|
||||
read_file(shader_path, &buffer_size, NULL);
|
||||
rse_malloc(buffer, buffer_size);
|
||||
read_file(shader_path, &buffer_size, buffer);
|
||||
|
||||
STATUS_CHECK(create_shader_module(context, pipeline, buffer, buffer_size));
|
||||
free(buffer);
|
||||
|
||||
pipeline->shader_stages[i].sType =
|
||||
VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||
pipeline->shader_stages[i].pNext = NULL;
|
||||
pipeline->shader_stages[i].flags = 0U;
|
||||
pipeline->shader_stages[i].stage = shader_stage;
|
||||
pipeline->shader_stages[i].module = RSE_LINKED_LIST_FRONT(
|
||||
context->shader_modules); /* This is automatically updated during
|
||||
shader module creation */
|
||||
pipeline->shader_stages[i].pName = "main";
|
||||
pipeline->shader_stages[i].pSpecializationInfo = NULL;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
rse_err_t pipeline_add_vertex_input_binding(struct pipeline_t* pipeline,
|
||||
const uint8_t binding,
|
||||
const uint8_t stride,
|
||||
const VkVertexInputRate input_rate)
|
||||
{
|
||||
VkVertexInputBindingDescription binding_pipeline_description = {};
|
||||
if (input_rate >= VK_VERTEX_INPUT_RATE_MAX_ENUM) {
|
||||
LOGF(_("Invalid vertex input rate\n"));
|
||||
return VULKAN_ERROR_PIPELINE_INVALID_VERTEX_INPUT_RATE;
|
||||
}
|
||||
|
||||
binding_pipeline_description.binding = binding;
|
||||
binding_pipeline_description.stride = stride;
|
||||
binding_pipeline_description.inputRate = input_rate;
|
||||
|
||||
RSE_LINKED_LIST_PUSH_FRONT(pipeline->vertex_bindings,
|
||||
binding_pipeline_description);
|
||||
return RSE_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
rse_err_t pipeline_add_vertex_input_attribute(struct pipeline_t* pipeline,
|
||||
const uint8_t binding,
|
||||
const uint8_t location,
|
||||
const VkFormat format,
|
||||
const uint8_t offset)
|
||||
{
|
||||
VkVertexInputAttributeDescription attribute_description = {};
|
||||
if (binding >= 16U) {
|
||||
LOGF(_("Invalid binding in pipeline attribute description\n"));
|
||||
return VULKAN_ERROR_PIPELINE_INVALID_BINDING;
|
||||
}
|
||||
if (format >= VK_FORMAT_MAX_ENUM) {
|
||||
LOGF(_("Invalid format in pipeline attribute description\n"));
|
||||
return VULKAN_ERROR_PIPELINE_INVALID_FORMAT;
|
||||
}
|
||||
|
||||
attribute_description.binding = binding;
|
||||
attribute_description.location = location;
|
||||
attribute_description.format = format;
|
||||
attribute_description.offset = offset;
|
||||
|
||||
RSE_LINKED_LIST_PUSH_FRONT(pipeline->shader_attributes,
|
||||
attribute_description);
|
||||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
|
||||
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)
|
||||
{
|
||||
rse_err_t status = RSE_ERROR_NO_ERROR;
|
||||
size_t pipelines_count = RSE_LINKED_LIST_SIZE(pipelines);
|
||||
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);
|
||||
|
||||
rse_malloc(pipeline_infos,
|
||||
sizeof(VkGraphicsPipelineCreateInfo) * pipelines_count);
|
||||
|
||||
RSE_LINKED_LIST_TO_ARRAY(pipelines, pipeline_infos);
|
||||
|
||||
if (VK_SUCCESS !=
|
||||
vkCreateGraphicsPipelines(context->device, VK_NULL_HANDLE,
|
||||
pipelines_count, pipeline_infos, NULL,
|
||||
context->pipelines_data.pipelines)) {
|
||||
LOGF(_("Failed to create graphics pipelines\n"));
|
||||
status = VULKAN_ERROR_GRAPHICSPIPELINE_CREATION_FAILED;
|
||||
}
|
||||
|
||||
rse_free(pipeline_infos);
|
||||
pipeline_builder_cleanup(pipelines);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
rse_err_t add_pipeline(const struct graphics_context_t* context,
|
||||
struct pipeline_t* pipeline,
|
||||
struct pipeline_infos_list_t* pipelines)
|
||||
{
|
||||
/* Check for send and required dynamic states */
|
||||
rse_err_t status = RSE_ERROR_NO_ERROR;
|
||||
VkGraphicsPipelineCreateInfo pipeline_info = {};
|
||||
|
||||
size_t vertex_bindings_count = 0U;
|
||||
VkVertexInputBindingDescription* vertex_bindings = NULL;
|
||||
|
||||
size_t shader_attributes_count = 0U;
|
||||
VkVertexInputAttributeDescription* shader_attributes = NULL;
|
||||
|
||||
size_t dynamic_states_count = 0U;
|
||||
VkDynamicState* dynamic_states = NULL;
|
||||
|
||||
uint8_t dynamic_state_found = 0;
|
||||
while (RSE_STACK_IS_EMPTY(pipeline->required_dynamic_states) == 0) {
|
||||
dynamic_state_found = 0;
|
||||
VkDynamicState dynamic_state =
|
||||
RSE_STACK_POP(pipeline->required_dynamic_states);
|
||||
RSE_LINKED_LIST_FOREACH(pipeline->dynamic_states, dynamic_state_ptr)
|
||||
{
|
||||
if (dynamic_state_ptr->data == dynamic_state) {
|
||||
dynamic_state_found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (dynamic_state_found == 0) {
|
||||
LOGF(_("Missing dynamic state in pipeline\n"));
|
||||
return VULKAN_ERROR_PIPELINE_MISSING_DYNAMIC_STATE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for shader modules */
|
||||
if (RSE_LINKED_LIST_IS_EMPTY(context->shader_modules) == 1) {
|
||||
LOGF(_("Missing shader modules in pipeline\n"));
|
||||
return VULKAN_ERROR_PIPELINE_MISSING_SHADER_MODULES;
|
||||
}
|
||||
|
||||
/* Check for required shader stages */
|
||||
if (pipeline->shader_stages_count == 0) {
|
||||
LOGF(
|
||||
_("Missing shader stages in pipeline. There must be at least "
|
||||
"one.\n"));
|
||||
return VULKAN_ERROR_PIPELINE_MISSING_SHADER_STAGES;
|
||||
}
|
||||
|
||||
/* Check for required vertex bindings */
|
||||
if (pipeline->vertex_bindings == NULL) {
|
||||
LOGF(_("Missing vertex bindings in pipeline\n"));
|
||||
return VULKAN_ERROR_PIPELINE_MISSING_VERTEX_BINDINGS;
|
||||
}
|
||||
|
||||
/* Check for required shader attributes */
|
||||
if (pipeline->shader_attributes == NULL) {
|
||||
LOGF(_("Missing shader attributes in pipeline\n"));
|
||||
return VULKAN_ERROR_PIPELINE_MISSING_SHADER_ATTRIBUTES;
|
||||
}
|
||||
|
||||
/* Convert linked list to array */
|
||||
vertex_bindings_count =
|
||||
RSE_LINKED_LIST_TO_ARRAY(pipeline->vertex_bindings, vertex_bindings);
|
||||
shader_attributes_count = RSE_LINKED_LIST_TO_ARRAY(
|
||||
pipeline->shader_attributes, shader_attributes);
|
||||
dynamic_states_count =
|
||||
RSE_LINKED_LIST_TO_ARRAY(pipeline->dynamic_states, dynamic_states);
|
||||
|
||||
/* Build constant pipeline. TODO: Some parts may be customizable */
|
||||
pipeline_add_input_assembly(pipeline);
|
||||
pipeline_add_viewport_state(pipeline);
|
||||
pipeline_add_rasterizer(pipeline);
|
||||
pipeline_add_multisampling(pipeline);
|
||||
pipeline_add_color_blending(pipeline);
|
||||
pipeline_add_depth_stencil(pipeline);
|
||||
|
||||
pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
|
||||
pipeline_info.pNext = NULL;
|
||||
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,
|
||||
};
|
||||
pipeline_info.pInputAssemblyState = &pipeline->input_assembly;
|
||||
pipeline_info.pTessellationState = NULL;
|
||||
pipeline_info.pViewportState = &pipeline->viewport_state;
|
||||
pipeline_info.pRasterizationState = &pipeline->rasterizer;
|
||||
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,
|
||||
};
|
||||
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;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
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,
|
||||
context->pipelines_data.pipelines[i], NULL);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < context->pipelines_data.descriptor_set_layouts_count; i++) {
|
||||
if (context->pipelines_data.descriptor_set_layouts[i] !=
|
||||
VK_NULL_HANDLE) {
|
||||
vkDestroyDescriptorSetLayout(
|
||||
context->device,
|
||||
context->pipelines_data.descriptor_set_layouts[i], NULL);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
RSE_LINKED_LIST_POP_FRONT(context->shader_modules);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user