/* SPDX-License-Identifier:BSD-3-Clause */ #include "pipeline.h" #include "../../core/log.h" #include #include 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); }