Move back to C

I'm insane and as such I have moved to C AGAIN! Without any reason.
This commit is contained in:
Piotr Krygier committed 2023-08-14 13:48:29 +02:00
1 parent bf31b96a2e
commit 3d538eaa2c
43 files changed
+2645 -2649

No files matched your search

+748
View File
@@ -0,0 +1,748 @@
#include "vulkan_pipeline.h"
#include "locale_vulkan.h"
#include "utilities/file_utils.h"
#include "utilities/logger.h"
#include "vulkan_errors.h"
#include "mesh_controller.h"
#include "vulkan/vulkan.h"
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#define SHADER_MODULES_COUNT 2U
enum shader_stage_t
{
VERTEX,
FRAGMENTS
};
#define IMAGE_FORMAT VK_FORMAT_B8G8R8A8_SRGB;
uint32_t g_swapchain_images_count = 0U;
VkImage* g_swapchain_images = NULL;
VkShaderModule g_shader_modules[SHADER_MODULES_COUNT];
const char* g_shader_paths[] = {
/* TODO: When changing to release and install, move those files*/
"../graphics/shaders/shader.vert.num",
"../graphics/shaders/shader.frag.num",
};
VkShaderModule create_shader_module(const char* binary_data, size_t data_size);
static uint8_t create_swapchain();
static uint8_t create_swapchain_image_views();
static uint8_t create_render_pass();
static uint8_t create_descriptor_set_layout();
static uint8_t create_pipeline_layout();
static uint8_t create_graphics_pipeline();
static uint8_t create_framebuffers();
static uint8_t fill_shader_stages(VkPipelineShaderStageCreateInfo* shader_stages);
static void fill_dynamic_pipeline_state_info(VkPipelineDynamicStateCreateInfo* dynamic_state);
static void free_dynamic_pipeline_state_info(VkPipelineDynamicStateCreateInfo* dynamic_state);
static void fill_vertex_input_info(VkPipelineVertexInputStateCreateInfo* vertex_input_info);
static void free_vertex_input_info(VkPipelineVertexInputStateCreateInfo* vertex_input_info);
static void fill_input_assembly_info(VkPipelineInputAssemblyStateCreateInfo* input_assembly);
static void fill_viewport_state_info(VkPipelineViewportStateCreateInfo* viewport_state);
static void free_viewport_state_info(VkPipelineViewportStateCreateInfo* viewport_state);
static void fill_rasterization_info(VkPipelineRasterizationStateCreateInfo* rasterizer);
static void fill_multisampling_state_info(VkPipelineMultisampleStateCreateInfo* multisampling);
static void fill_color_blend_state_info(VkPipelineColorBlendStateCreateInfo* color_blending);
static void free_color_blend_info(VkPipelineColorBlendStateCreateInfo* color_blending);
static VkVertexInputBindingDescription get_binding_description()
{
VkVertexInputBindingDescription binding_description;
binding_description.binding = 0;
binding_description.stride = sizeof(struct rse_vertex_t);
binding_description.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
return binding_description;
}
static VkVertexInputAttributeDescription* get_attribute_descriptions()
{
static VkVertexInputAttributeDescription attributeDescriptions[2];
attributeDescriptions[0].binding = 0;
attributeDescriptions[0].location = 0; /* inPosition in shader.vert */
attributeDescriptions[0].format = VK_FORMAT_R32G32B32_SFLOAT;
attributeDescriptions[0].offset = offsetof(struct rse_vertex_t, pos);
attributeDescriptions[1].binding = 0;
attributeDescriptions[1].location = 1; /* inColor in shader.vert */
attributeDescriptions[1].format = VK_FORMAT_R32G32B32_SFLOAT;
attributeDescriptions[1].offset = offsetof(struct rse_vertex_t, color);
return attributeDescriptions;
}
/**
* @brief Creates shader module
*
* @param binary_data Shader compiled code
* @return std::optional<VkShaderModule> Handle to compiled shader module or nullopt
*/
VkShaderModule create_shader_module(const char* binary_data, size_t data_size)
{
VkShaderModule shader_module;
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);
if (VK_SUCCESS != vkCreateShaderModule(g_vulkan_state.device, &create_info, NULL, &shader_module)) {
LOGF(vulkan_error_messages[VULKAN_SHADER_UNABLE_TO_CREATE_SHADER]);
// TODO: Add error handling
return shader_module;
}
return shader_module;
}
/**
* @brief Create a Swapchain
*
* @return uint8_t VULKAN_ERROR_NO_ERROR on success. Possible errors:
* VULKAN_ERROR_SWAPCHAIN_CREATION_FAILED
*/
uint8_t create_swapchain()
{
VkSwapchainCreateInfoKHR create_info;
VkSurfaceCapabilitiesKHR physical_device_surface_capabilities;
VkBool32 surfaceSupported;
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(g_vulkan_state.physical_device,
g_vulkan_state.surface,
&physical_device_surface_capabilities);
/* Store extent in global variable, for later use */
g_vulkan_state.swapchain_extent = physical_device_surface_capabilities.currentExtent;
/* Check if device supports surface for presentation */
vkGetPhysicalDeviceSurfaceSupportKHR(g_vulkan_state.physical_device,
g_vulkan_state.queue_family_indices[0],
g_vulkan_state.surface,
&surfaceSupported);
create_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
create_info.pNext = NULL;
create_info.flags = 0U;
create_info.surface = g_vulkan_state.surface;
create_info.minImageCount = SWAP_BUFFER_COUNT + 1;
create_info.imageFormat = IMAGE_FORMAT; /* TODO: Check for supported formats */
create_info.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; /* TODO: Check for supported color space */
create_info.imageExtent = g_vulkan_state.swapchain_extent;
create_info.imageArrayLayers = 1U; /* For non-stereoscopic-3D applications, this value is 1. */
create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; /* TODO: Probably change later? Dunno */
create_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; /* Using only one queue family, so this is ok */
create_info.queueFamilyIndexCount = 1U;
create_info.pQueueFamilyIndices = g_vulkan_state.queue_family_indices;
create_info.preTransform = physical_device_surface_capabilities.currentTransform;
create_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
create_info.presentMode = VK_PRESENT_MODE_FIFO_KHR; /* TODO: Choose present mode from VkPresentModeKHR */
create_info.clipped = VK_TRUE;
create_info.oldSwapchain = VK_NULL_HANDLE;
if (VK_SUCCESS != vkCreateSwapchainKHR(g_vulkan_state.device, &create_info, NULL, &g_vulkan_state.swapchain)) {
LOGF(vulkan_error_messages[VULKAN_SWAPCHAIN_CREATION_FAILED]);
return VULKAN_ERROR_SWAPCHAIN_CREATION_FAILED;
}
/* Obtain swapchain images */
vkGetSwapchainImagesKHR(g_vulkan_state.device, g_vulkan_state.swapchain, &g_swapchain_images_count, NULL);
g_swapchain_images = (VkImage*)malloc(sizeof(VkImage) * g_swapchain_images_count);
vkGetSwapchainImagesKHR(g_vulkan_state.device, g_vulkan_state.swapchain, &g_swapchain_images_count, g_swapchain_images);
return VULKAN_ERROR_NO_ERROR;
}
/**
* @brief Create a Swapchain Image Views
*
* @return uint8_t VULKAN_ERROR_NO_ERROR on success. Possible errors:
*/
uint8_t create_swapchain_image_views()
{
g_vulkan_state.swapchain_image_views = malloc(sizeof(VkImageView) * g_swapchain_images_count);
for (size_t i = 0; i < g_swapchain_images_count; i++) {
VkImageViewCreateInfo create_info;
create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
create_info.pNext = NULL;
create_info.flags = 0U;
create_info.image = g_swapchain_images[i];
create_info.viewType = VK_IMAGE_VIEW_TYPE_2D; /* 2D Texture */
create_info.format = VK_FORMAT_B8G8R8A8_SRGB;
create_info.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
create_info.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
create_info.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
create_info.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
create_info.subresourceRange.baseMipLevel = 0U;
create_info.subresourceRange.levelCount = 1U;
create_info.subresourceRange.baseArrayLayer = 0U;
create_info.subresourceRange.layerCount = 1U;
if (VK_SUCCESS != vkCreateImageView(g_vulkan_state.device, &create_info, NULL, &g_vulkan_state.swapchain_image_views[i])) {
LOGF(vulkan_error_messages[VULKAN_SWAPCHAIN_IMVIEW_CREATION_FAILED]);
return VULKAN_ERROR_SWAPCHAIN_IMVIEW_CREATION_FAILED;
}
}
return VULKAN_ERROR_NO_ERROR;
}
/**
* @brief Create a Render Pass
*
* @return uint8_t VULKAN_ERROR_NO_ERROR on success. Possible errors:
* VULKAN_ERROR_RENDERPASS_CREATION_FAILED
*/
uint8_t create_render_pass()
{
VkAttachmentDescription color_attachment = {};
VkAttachmentReference color_attachment_ref = {};
VkSubpassDescription subpass = {};
VkRenderPassCreateInfo renderpass_info = {};
color_attachment.flags = 0U;
color_attachment.format = IMAGE_FORMAT;
color_attachment.samples = VK_SAMPLE_COUNT_1_BIT;
color_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
color_attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
color_attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
color_attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
color_attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
color_attachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
color_attachment_ref.attachment = 0;
color_attachment_ref.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpass.colorAttachmentCount = 1;
subpass.pColorAttachments = &color_attachment_ref;
renderpass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
renderpass_info.attachmentCount = 1;
renderpass_info.pAttachments = &color_attachment;
renderpass_info.subpassCount = 1;
renderpass_info.pSubpasses = &subpass;
if (VK_SUCCESS != vkCreateRenderPass(g_vulkan_state.device, &renderpass_info, NULL, &g_vulkan_state.render_pass)) {
LOGF(vulkan_error_messages[VULKAN_RENDERPASS_CREATION_FAILED]);
return VULKAN_ERROR_RENDERPASS_CREATION_FAILED;
}
return VULKAN_ERROR_NO_ERROR;
}
/**
* @brief Create a Descriptor Set Layout
*
* @return uint8_t VULKAN_ERROR_NO_ERROR on success. Possible errors:
*/
uint8_t create_descriptor_set_layout()
{
VkDescriptorSetLayoutCreateInfo layout_info = {};
VkDescriptorSetLayoutBinding ubo_layout_binding = {};
ubo_layout_binding.binding = 0;
ubo_layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
ubo_layout_binding.descriptorCount = 1;
ubo_layout_binding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
ubo_layout_binding.pImmutableSamplers = NULL;
layout_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
layout_info.pNext = NULL;
layout_info.flags = 0U;
layout_info.bindingCount = 1U;
layout_info.pBindings = &ubo_layout_binding;
if (vkCreateDescriptorSetLayout(g_vulkan_state.device, &layout_info, NULL, &g_vulkan_state.descriptor_set_layout) != VK_SUCCESS) {
LOGF(vulkan_error_messages[VULKAN_DESCRIPTORSETLAYOUT_CREATION_FAILED]);
return VULKAN_ERROR_DESCRIPTORSETLAYOUT_CREATION_FAILED;
}
return VULKAN_ERROR_NO_ERROR;
}
/**
* @brief Create a Pipeline Layout
*
* @return uint8_t VULKAN_ERROR_NO_ERROR on success. Possible errors:
* VULKAN_ERROR_PIPELINE_LAYOUT_CREATION_FAILED
*/
uint8_t create_pipeline_layout()
{
VkPipelineLayoutCreateInfo create_info = {};
create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
create_info.pNext = NULL;
create_info.flags = 0U;
create_info.setLayoutCount = 1U;
create_info.pSetLayouts = &g_vulkan_state.descriptor_set_layout;
create_info.pushConstantRangeCount = 0U;
create_info.pPushConstantRanges = NULL;
if (VK_SUCCESS != vkCreatePipelineLayout(g_vulkan_state.device, &create_info, NULL, &g_vulkan_state.pipeline_layout)) {
LOGF(vulkan_error_messages[VULKAN_PIPELAYOUT_CREATION_FAILED]);
return VULKAN_ERROR_PIPELINE_LAYOUT_CREATION_FAILED;
}
return VULKAN_ERROR_NO_ERROR;
}
/**
* @brief Create Graphics Pipeline
*
* @return uint8_t VULKAN_ERROR_NO_ERROR on success. Possible errors:
* VULKAN_ERROR_GRAPHICSPIPELINE_CREATION_FAILED
*/
uint8_t create_graphics_pipeline()
{
uint8_t status = VULKAN_ERROR_NO_ERROR;
VkPipelineShaderStageCreateInfo shader_stages[SHADER_MODULES_COUNT];
VkPipelineVertexInputStateCreateInfo vertex_input_info = {};
VkPipelineInputAssemblyStateCreateInfo input_assembly = {};
VkPipelineViewportStateCreateInfo viewport_state = {};
VkPipelineRasterizationStateCreateInfo rasterizer = {};
VkPipelineMultisampleStateCreateInfo multisampling = {};
VkPipelineColorBlendStateCreateInfo color_blending = {};
VkPipelineDynamicStateCreateInfo dynamic_state = {};
STATUS_CHECK(fill_shader_stages(shader_stages));
fill_vertex_input_info(&vertex_input_info);
fill_input_assembly_info(&input_assembly);
fill_viewport_state_info(&viewport_state);
fill_rasterization_info(&rasterizer);
fill_multisampling_state_info(&multisampling);
fill_color_blend_state_info(&color_blending);
fill_dynamic_pipeline_state_info(&dynamic_state);
VkGraphicsPipelineCreateInfo pipelineInfo = {};
pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
pipelineInfo.pNext = NULL;
pipelineInfo.flags = 0U;
pipelineInfo.stageCount = SHADER_MODULES_COUNT;
pipelineInfo.pStages = shader_stages;
pipelineInfo.pVertexInputState = &vertex_input_info;
pipelineInfo.pInputAssemblyState = &input_assembly;
pipelineInfo.pTessellationState = NULL;
pipelineInfo.pViewportState = &viewport_state;
pipelineInfo.pRasterizationState = &rasterizer;
pipelineInfo.pMultisampleState = &multisampling;
pipelineInfo.pDepthStencilState = NULL;
pipelineInfo.pColorBlendState = &color_blending;
pipelineInfo.pDynamicState = &dynamic_state;
pipelineInfo.layout = g_vulkan_state.pipeline_layout;
pipelineInfo.renderPass = g_vulkan_state.render_pass;
pipelineInfo.subpass = 0;
pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
pipelineInfo.basePipelineIndex = -1;
if (VK_SUCCESS !=
vkCreateGraphicsPipelines(g_vulkan_state.device, VK_NULL_HANDLE, 1, &pipelineInfo, NULL, &g_vulkan_state.graphics_pipeline)) {
LOGF(vulkan_error_messages[VULKAN_GRAPHICSPIPELINE_CREATION_FAILED]);
status = VULKAN_ERROR_GRAPHICSPIPELINE_CREATION_FAILED;
}
free_dynamic_pipeline_state_info(&dynamic_state);
free_color_blend_info(&color_blending);
free_viewport_state_info(&viewport_state);
free_vertex_input_info(&vertex_input_info);
return status;
}
/**
* @brief Create Frambuffers
*
* @return uint8_t VULKAN_ERROR_NO_ERROR on success. Possible errors:
*/
uint8_t create_framebuffers()
{
g_vulkan_state.swapchain_framebuffers = malloc(sizeof(VkFramebuffer) * g_swapchain_images_count);
for (size_t i = 0; i < g_swapchain_images_count; i++) {
VkImageView attachments[] = {g_vulkan_state.swapchain_image_views[i]};
VkFramebufferCreateInfo framebufferInfo = {};
framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
framebufferInfo.renderPass = g_vulkan_state.render_pass;
framebufferInfo.attachmentCount = 1;
framebufferInfo.pAttachments = attachments;
framebufferInfo.width = g_vulkan_state.swapchain_extent.width;
framebufferInfo.height = g_vulkan_state.swapchain_extent.height;
framebufferInfo.layers = 1;
if (vkCreateFramebuffer(g_vulkan_state.device, &framebufferInfo, NULL, &g_vulkan_state.swapchain_framebuffers[i]) != VK_SUCCESS) {
LOGF(vulkan_error_messages[VULKAN_FRAMEBUFFERS_CREATION_FAILED]);
return VULKAN_ERROR_FRAMEBUFFERS_CREATION_FAILED;
}
}
return VULKAN_ERROR_NO_ERROR;
}
/**
* @brief Recreate swapchain
*
*/
void recreate_swapchain()
{
cleanup_swapchain();
create_swapchain();
create_swapchain_image_views();
create_framebuffers();
}
/**
* @brief Cleanup swapchain
*
*/
void cleanup_swapchain()
{
size_t i;
vkDeviceWaitIdle(g_vulkan_state.device);
for (i = 0; i < g_swapchain_images_count; i++) {
vkDestroyFramebuffer(g_vulkan_state.device, g_vulkan_state.swapchain_framebuffers[i], NULL);
}
for (i = 0; i < g_swapchain_images_count; i++) {
vkDestroyImageView(g_vulkan_state.device, g_vulkan_state.swapchain_image_views[i], NULL);
}
vkDestroySwapchainKHR(g_vulkan_state.device, g_vulkan_state.swapchain, NULL);
}
/**
* @brief Creates shader stages from hardcoded shader paths. Changes input
*
* @param shader_stages Empty vector, that will be filled with data
* @return uint8_t VULKAN_ERROR_NO_ERROR on success. Possible errors:
* VULKAN_ERROR_SHADER_FILE_OPEN_FAILED
* VULKAN_ERROR_SHADER_CREATION_FAILED
*/
static uint8_t fill_shader_stages(VkPipelineShaderStageCreateInfo* shader_stages)
{
char* buffer;
size_t buffer_size;
VkShaderModule vertex_shader_module;
VkShaderModule fragments_shader_module;
VkPipelineShaderStageCreateInfo vert_shader_stage_info = {};
VkPipelineShaderStageCreateInfo frag_shader_stage_info = {};
read_file(g_shader_paths[VERTEX], &buffer_size, NULL);
buffer = malloc(buffer_size);
read_file(g_shader_paths[VERTEX], &buffer_size, buffer);
vertex_shader_module = create_shader_module(buffer, buffer_size);
free(buffer);
read_file(g_shader_paths[FRAGMENTS], &buffer_size, NULL);
buffer = malloc(buffer_size);
read_file(g_shader_paths[FRAGMENTS], &buffer_size, buffer);
fragments_shader_module = create_shader_module(buffer, buffer_size);
free(buffer);
//TODO: Shader creation might have failed. Add error handling
/* Vertex Shader Pipeline Stage */
vert_shader_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
vert_shader_stage_info.pNext = NULL;
vert_shader_stage_info.flags = 0U;
vert_shader_stage_info.stage = VK_SHADER_STAGE_VERTEX_BIT;
vert_shader_stage_info.module = vertex_shader_module;
vert_shader_stage_info.pName = "main"; /* Entry point function */
vert_shader_stage_info.pSpecializationInfo = NULL; /* Specialization in a SPIR-V module */
/* Fragments Shader Pipeline Stage */
frag_shader_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
frag_shader_stage_info.pNext = NULL;
frag_shader_stage_info.flags = 0U;
frag_shader_stage_info.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
frag_shader_stage_info.module = fragments_shader_module;
frag_shader_stage_info.pName = "main"; /* Entry point function */
frag_shader_stage_info.pSpecializationInfo = NULL; /* Specialization in a SPIR-V module */
shader_stages[VERTEX] = vert_shader_stage_info;
shader_stages[FRAGMENTS] = frag_shader_stage_info;
memcpy(&g_shader_modules[0], &vertex_shader_module, sizeof(VkShaderModule));
memcpy(&g_shader_modules[1], &fragments_shader_module, sizeof(VkShaderModule));
return VULKAN_ERROR_NO_ERROR;
}
/**
* @brief Fill dynamic pipeline state info
*
* @param dynamic_state structure to be filled
*/
void fill_dynamic_pipeline_state_info(VkPipelineDynamicStateCreateInfo* dynamic_state)
{
VkDynamicState* dynamic_states;
/*
* Select pipeline stages that will be set dynamically. Those that are selected are ignored in
* pipeline create structures. I'll list ignored members of structs, that will be ignored due to the
* settings and also functions, that will need to be called to set specific state.
*/
dynamic_states = malloc(sizeof(VkDynamicState) * 2);
dynamic_states[0] = VK_DYNAMIC_STATE_VIEWPORT; /* VkPipelineViewportStateCreateInfo:pViewport; vkCmdSetViewport() */
dynamic_states[1] = VK_DYNAMIC_STATE_SCISSOR; /* VkPipelineViewportStateCreateInfo:pScissors; vkCmdSetScissors() */
dynamic_state->sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
dynamic_state->pNext = NULL;
dynamic_state->flags = 0U;
dynamic_state->dynamicStateCount = 2U;
/* dynamic_state is constructed localy. To avoid creation of VkPipelineDynamicStateCreateInfo structure in
* main pipeline construction function, we have to do a little memory trickery here and allocate memory for
* dynamic state pointer manually. We must also free this memory later */
dynamic_state->pDynamicStates = dynamic_states;
}
/**
* @brief Release allocated dynamic pipeline state info
*
* @param dynamic_state structure to be freed
*/
void free_dynamic_pipeline_state_info(VkPipelineDynamicStateCreateInfo* dynamic_state)
{
free((VkDynamicState*)dynamic_state->pDynamicStates);
}
/**
* @brief Fill vertex input info
*
* @param vertex_input_info structure to be filled
*/
void fill_vertex_input_info(VkPipelineVertexInputStateCreateInfo* vertex_input_info)
{
VkVertexInputBindingDescription vertex_binding_description = get_binding_description();
VkVertexInputAttributeDescription* vertex_attribute_descriptions = get_attribute_descriptions();
VkVertexInputBindingDescription* bindingDescriptions = malloc(sizeof(VkVertexInputBindingDescription) * 2);
VkVertexInputAttributeDescription* attributeDescriptions = malloc(sizeof(VkVertexInputAttributeDescription) * 5);
bindingDescriptions[0] = vertex_binding_description;
bindingDescriptions[1].binding = 1;
bindingDescriptions[1].stride = sizeof(struct rse_instance_data_t); //TODO: change
bindingDescriptions[1].inputRate = VK_VERTEX_INPUT_RATE_INSTANCE;
memcpy(attributeDescriptions, vertex_attribute_descriptions, sizeof(VkVertexInputAttributeDescription) * 2);
attributeDescriptions[2].binding = 1;
attributeDescriptions[2].location = 2;
attributeDescriptions[2].format = VK_FORMAT_R32G32B32_SFLOAT;
attributeDescriptions[2].offset = offsetof(struct rse_instance_data_t, pos);
attributeDescriptions[3].binding = 1;
attributeDescriptions[3].location = 3;
attributeDescriptions[3].format = VK_FORMAT_R32G32B32_SFLOAT;
attributeDescriptions[3].offset = offsetof(struct rse_instance_data_t, rot);
attributeDescriptions[4].binding = 1;
attributeDescriptions[4].location = 4;
attributeDescriptions[4].format = VK_FORMAT_R32_SFLOAT;
attributeDescriptions[4].offset = offsetof(struct rse_instance_data_t, scale);
// ************************
vertex_input_info->sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
vertex_input_info->pNext = NULL;
vertex_input_info->flags = 0U;
vertex_input_info->vertexBindingDescriptionCount = 2U;
vertex_input_info->pVertexBindingDescriptions = bindingDescriptions;
vertex_input_info->vertexAttributeDescriptionCount = 5U;
vertex_input_info->pVertexAttributeDescriptions = attributeDescriptions;
}
/**
* @brief Free allocated vertex input info
*
* @param vertex_input_info structure to be freed
*/
void free_vertex_input_info(VkPipelineVertexInputStateCreateInfo* vertex_input_info)
{
free((VkVertexInputBindingDescription*)vertex_input_info->pVertexBindingDescriptions);
free((VkVertexInputAttributeDescription*)vertex_input_info->pVertexAttributeDescriptions);
}
/**
* @brief Fill input assembly info
*
* @param input_assembly structure to be filled
*/
void fill_input_assembly_info(VkPipelineInputAssemblyStateCreateInfo* input_assembly)
{
input_assembly->sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
input_assembly->pNext = NULL;
input_assembly->flags = 0U;
input_assembly->topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; // TODO: Change to _STRIP
input_assembly->primitiveRestartEnable = VK_FALSE; /* If I want to break lines during _STRIP,
* I must set this to VK_TRUE */
}
/**
* @brief Fill viewport state info
*
* @param viewport_state structure to be filled
*/
void fill_viewport_state_info(VkPipelineViewportStateCreateInfo* viewport_state)
{
VkViewport* viewport = malloc(sizeof(VkViewport));
VkRect2D* scissor = malloc(sizeof(VkRect2D));
viewport->x = 0.0f;
viewport->y = 0.0f;
viewport->width = (float)(g_vulkan_state.swapchain_extent.width);
viewport->height = (float)(g_vulkan_state.swapchain_extent.height);
viewport->minDepth = 0.0f;
viewport->maxDepth = 1.0f;
/* Setting Scissors to fill entire window*/
scissor->offset.x = 0;
scissor->offset.y = 0;
scissor->extent = g_vulkan_state.swapchain_extent;
viewport_state->sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
viewport_state->viewportCount = 1;
viewport_state->pViewports = viewport;
viewport_state->scissorCount = 1;
viewport_state->pScissors = scissor;
}
/**
* @brief Free allocated viewport state input info
*
* @param viewport_state structure to be freed
*/
void free_viewport_state_info(VkPipelineViewportStateCreateInfo* viewport_state)
{
free((VkViewport*)viewport_state->pViewports);
free((VkRect2D*)viewport_state->pScissors);
}
/**
* @brief Fill rasteriation info
*
* @param rasterizer
*/
void fill_rasterization_info(VkPipelineRasterizationStateCreateInfo* rasterizer)
{
rasterizer->sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
rasterizer->pNext = NULL;
rasterizer->flags = 0U;
rasterizer->depthClampEnable = VK_FALSE; /* VK_TRUE to play with shadow maps */
rasterizer->rasterizerDiscardEnable = VK_FALSE; /* Disable/Enable output to framebuffer*/
rasterizer->polygonMode = VK_POLYGON_MODE_FILL;
rasterizer->cullMode = VK_CULL_MODE_BACK_BIT;
rasterizer->frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
rasterizer->depthBiasEnable = VK_FALSE;
rasterizer->depthBiasConstantFactor = 0.0f;
rasterizer->depthBiasClamp = 0.0f;
rasterizer->depthBiasSlopeFactor = 0.0f;
rasterizer->lineWidth = 1.0f;
}
/**
* @brief Fill multisampling state info
*
* @param multisampling structure to be filled
*/
void fill_multisampling_state_info(VkPipelineMultisampleStateCreateInfo* multisampling)
{
multisampling->sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
multisampling->pNext = NULL;
multisampling->flags = 0U;
multisampling->rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
multisampling->sampleShadingEnable = VK_FALSE;
multisampling->minSampleShading = 1.0f;
multisampling->pSampleMask = NULL;
multisampling->alphaToCoverageEnable = VK_FALSE;
multisampling->alphaToOneEnable = VK_FALSE;
}
/**
* @brief Fill color blend state info
*
* @param color_blending structure to be filled
*/
void fill_color_blend_state_info(VkPipelineColorBlendStateCreateInfo* color_blending)
{
VkPipelineColorBlendAttachmentState* color_blend_attachment = malloc(sizeof(VkPipelineColorBlendAttachmentState));
color_blend_attachment->blendEnable = VK_FALSE;
color_blend_attachment->srcColorBlendFactor = VK_BLEND_FACTOR_ONE;
color_blend_attachment->dstColorBlendFactor = VK_BLEND_FACTOR_ZERO;
color_blend_attachment->colorBlendOp = VK_BLEND_OP_ADD;
color_blend_attachment->srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
color_blend_attachment->dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
color_blend_attachment->alphaBlendOp = VK_BLEND_OP_ADD;
color_blend_attachment->colorWriteMask =
VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
color_blending->sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
color_blending->pNext = NULL;
color_blending->flags = 0U;
color_blending->logicOpEnable = VK_FALSE;
color_blending->logicOp = VK_LOGIC_OP_COPY;
color_blending->attachmentCount = 1U;
color_blending->pAttachments = color_blend_attachment;
color_blending->blendConstants[0] = 0.0f;
color_blending->blendConstants[1] = 0.0f;
color_blending->blendConstants[2] = 0.0f;
color_blending->blendConstants[3] = 0.0f;
}
/**
* @brief Free allocated color blend state info
*
* @param color_blending Structure to be freed
*/
void free_color_blend_info(VkPipelineColorBlendStateCreateInfo* color_blending)
{
free((VkPipelineColorBlendAttachmentState*)color_blending->pAttachments);
}
uint8_t create_pipeline()
{
uint8_t status = VULKAN_ERROR_NO_ERROR;
STATUS_CHECK(create_swapchain());
STATUS_CHECK(create_swapchain_image_views());
STATUS_CHECK(create_render_pass());
STATUS_CHECK(create_descriptor_set_layout());
STATUS_CHECK(create_pipeline_layout());
STATUS_CHECK(create_graphics_pipeline());
STATUS_CHECK(create_framebuffers());
return status;
}
void destroy_pipeline()
{
vkDestroyPipeline(g_vulkan_state.device, g_vulkan_state.graphics_pipeline, NULL);
vkDestroyPipelineLayout(g_vulkan_state.device, g_vulkan_state.pipeline_layout, NULL);
vkDestroyRenderPass(g_vulkan_state.device, g_vulkan_state.render_pass, NULL);
for (size_t i = 0; i < SHADER_MODULES_COUNT; i++) {
vkDestroyShaderModule(g_vulkan_state.device, g_shader_modules[i], NULL);
}
}