topaz/rendering/vk/pipeline.c

198 lines
5.4 KiB
C

/* SPDX-License-Identifier:BSD-3-Clause */
#include "pipeline.h"
#include "../../core/log.h"
#include <stdlib.h>
#include <stdio.h>
static u8 *read_file(const char *path, usize *size)
{
FILE *file = fopen(path, "rb");
if (!file) {
return NULL;
}
fseek(file, 0, SEEK_END);
*size = ftell(file);
fseek(file, 0, SEEK_SET);
u8 *data = malloc(*size);
fread(data, 1, *size, file);
fclose(file);
return data;
}
static VkShaderModule create_shader_module(VkDevice device, u8 *code, usize size)
{
VkShaderModuleCreateInfo create_info = {
.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
.codeSize = size,
.pCode = (u32 *)code
};
VkShaderModule module;
if (vkCreateShaderModule(device, &create_info, NULL, &module) != VK_SUCCESS) {
fatal("Can't create shader module.\n");
}
return module;
}
void vk_pipeline_init(struct renderer_context *context)
{
usize vert_size, frag_size;
u8 *vert_code = read_file("assets/shaders/quad.vert.spv", &vert_size);
u8 *frag_code = read_file("assets/shaders/quad.frag.spv", &frag_size);
if (!vert_code || !frag_code) {
fatal("Can't read shader files.\n");
}
VkShaderModule vert_module = create_shader_module(context->device, vert_code, vert_size);
VkShaderModule frag_module = create_shader_module(context->device, frag_code, frag_size);
free(vert_code);
free(frag_code);
VkPipelineShaderStageCreateInfo shader_stages[] = {
{
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
.stage = VK_SHADER_STAGE_VERTEX_BIT,
.module = vert_module,
.pName = "main"
},
{
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
.stage = VK_SHADER_STAGE_FRAGMENT_BIT,
.module = frag_module,
.pName = "main"
}
};
VkVertexInputBindingDescription binding = {
.binding = 0,
.stride = sizeof(f32) * 5,
.inputRate = VK_VERTEX_INPUT_RATE_VERTEX
};
VkVertexInputAttributeDescription attributes[] = {
{
.binding = 0,
.location = 0,
.format = VK_FORMAT_R32G32_SFLOAT,
.offset = 0
},
{
.binding = 0,
.location = 1,
.format = VK_FORMAT_R32G32B32_SFLOAT,
.offset = sizeof(f32) * 2
}
};
VkPipelineVertexInputStateCreateInfo vertex_input = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
.vertexBindingDescriptionCount = 1,
.pVertexBindingDescriptions = &binding,
.vertexAttributeDescriptionCount = 2,
.pVertexAttributeDescriptions = attributes
};
VkPipelineInputAssemblyStateCreateInfo input_assembly = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
.primitiveRestartEnable = VK_FALSE
};
VkViewport viewport = {
.x = 0.0f,
.y = 0.0f,
.width = (f32)context->swapchain.extent.width,
.height = (f32)context->swapchain.extent.height,
.minDepth = 0.0f,
.maxDepth = 1.0f
};
VkRect2D scissor = {
.offset = { 0, 0 },
.extent = context->swapchain.extent
};
VkPipelineViewportStateCreateInfo viewport_state = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
.viewportCount = 1,
.pViewports = &viewport,
.scissorCount = 1,
.pScissors = &scissor
};
VkPipelineRasterizationStateCreateInfo rasterizer = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
.depthClampEnable = VK_FALSE,
.rasterizerDiscardEnable = VK_FALSE,
.polygonMode = VK_POLYGON_MODE_FILL,
.lineWidth = 1.0f,
.cullMode = VK_CULL_MODE_BACK_BIT,
.frontFace = VK_FRONT_FACE_CLOCKWISE,
.depthBiasEnable = VK_FALSE
};
VkPipelineMultisampleStateCreateInfo multisampling = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
.sampleShadingEnable = VK_FALSE,
.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT
};
VkPipelineColorBlendAttachmentState blend_attachment = {
.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
.blendEnable = VK_FALSE
};
VkPipelineColorBlendStateCreateInfo color_blend = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
.logicOpEnable = VK_FALSE,
.attachmentCount = 1,
.pAttachments = &blend_attachment
};
VkPipelineLayoutCreateInfo layout_info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
.setLayoutCount = 0,
.pushConstantRangeCount = 0
};
if (vkCreatePipelineLayout(context->device, &layout_info, NULL, &context->pipeline_layout) != VK_SUCCESS) {
fatal("Can't create pipeline layout.\n");
}
VkGraphicsPipelineCreateInfo pipeline_info = {
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
.stageCount = 2,
.pStages = shader_stages,
.pVertexInputState = &vertex_input,
.pInputAssemblyState = &input_assembly,
.pViewportState = &viewport_state,
.pRasterizationState = &rasterizer,
.pMultisampleState = &multisampling,
.pColorBlendState = &color_blend,
.layout = context->pipeline_layout,
.renderPass = context->render_pass,
.subpass = 0
};
if (vkCreateGraphicsPipelines(context->device, VK_NULL_HANDLE, 1, &pipeline_info, NULL, &context->pipeline) != VK_SUCCESS) {
fatal("Can't create graphics pipeline.\n");
}
vkDestroyShaderModule(context->device, vert_module, NULL);
vkDestroyShaderModule(context->device, frag_module, NULL);
log_info("Graphics pipeline created.\n");
}
void vk_pipeline_deinit(struct renderer_context *context)
{
vkDestroyPipeline(context->device, context->pipeline, NULL);
vkDestroyPipelineLayout(context->device, context->pipeline_layout, NULL);
}