Move back to C
I'm insane and as such I have moved to C AGAIN! Without any reason.
This commit is contained in:
1 parent
bf31b96a2e
commit
3d538eaa2c
43 files changed
+2645
-2649
No files matched your search
@@ -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);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user