diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 624b03125d78b9b7a1591d5830d8281979549f73..a4d2a2a79102b21fce504411bf473db54b351aa2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,4 +1,5 @@ target_sources(${PROJECT_NAME} PRIVATE + GraphicsPipeline.cpp main.cpp Renderer.cpp Swapchain.cpp diff --git a/src/GraphicsPipeline.cpp b/src/GraphicsPipeline.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6fd8f68bc661ed532b0afcb290150c5cfa8aba65 --- /dev/null +++ b/src/GraphicsPipeline.cpp @@ -0,0 +1,128 @@ +#include "GraphicsPipeline.hpp" + +[[nodiscard]] +static auto + load_shader_module(const vk::Device t_device, const std::filesystem::path& t_filepath) + -> vk::UniqueShaderModule +{ + std::ifstream file{ t_filepath, std::ios::binary | std::ios::in | std::ios::ate }; + + const std::streamsize file_size = file.tellg(); + if (file_size == -1) { + throw std::runtime_error{ + std::format("Failed to open file: {}", t_filepath.generic_string()) + }; + } + + std::vector<char> buffer(static_cast<size_t>(file_size)); + + file.seekg(0, std::ios::beg); + file.read(buffer.data(), file_size); + file.close(); + + const vk::ShaderModuleCreateInfo create_info{ + .codeSize = static_cast<size_t>(file_size), + .pCode = reinterpret_cast<uint32_t*>(buffer.data()) + }; + + return t_device.createShaderModuleUnique(create_info); +} + +auto create_pipeline_layout(const vk::Device device) -> vk::UniquePipelineLayout +{ + constexpr static vk::PipelineLayoutCreateInfo create_info{}; + + return device.createPipelineLayoutUnique(create_info); +} + +auto build_graphics_pipeline( + const vk::Device device, + const vk::PipelineLayout layout, + const vk::RenderPass render_pass +) -> vk::UniquePipeline +{ + const vk::UniqueShaderModule vertex_shader{ + load_shader_module(device, "shaders/triangle.frag") + }; + const vk::UniqueShaderModule fragment_shader{ + load_shader_module(device, "shaders/triangle.frag") + }; + const std::array shader_stages{ + vk::PipelineShaderStageCreateInfo{ .stage = vk::ShaderStageFlagBits::eVertex, + .module = vertex_shader.get(), + .pName = "main" }, + vk::PipelineShaderStageCreateInfo{ .stage = vk::ShaderStageFlagBits::eFragment, + .module = fragment_shader.get(), + .pName = "main" } + }; + + constexpr static vk::PipelineVertexInputStateCreateInfo + vertex_input_state_create_info{}; + + constexpr static vk::PipelineInputAssemblyStateCreateInfo + input_assembly_state_create_info{ + .topology = vk::PrimitiveTopology::eTriangleList, + }; + + constexpr static vk::PipelineViewportStateCreateInfo viewport_state_create_info{ + .viewportCount = 1, + .scissorCount = 1, + }; + + constexpr static vk::PipelineRasterizationStateCreateInfo + rasterization_state_create_info{ + .polygonMode = vk::PolygonMode::eFill, + .cullMode = vk::CullModeFlagBits::eBack, + .frontFace = vk::FrontFace::eCounterClockwise, + .lineWidth = 1.f, + }; + + constexpr static vk::PipelineMultisampleStateCreateInfo multisample_state_create_info{ + .rasterizationSamples = vk::SampleCountFlagBits::e1, + }; + + constexpr static vk::PipelineDepthStencilStateCreateInfo + depth_stencil_state_create_info{ + .depthTestEnable = true, + .depthWriteEnable = true, + .depthCompareOp = vk::CompareOp::eLess, + .depthBoundsTestEnable = false, + .stencilTestEnable = false, + }; + + constexpr static vk::PipelineColorBlendAttachmentState color_blend_attachment_state{ + .blendEnable = vk::False, + .colorWriteMask = vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG + | vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA, + }; + constexpr static vk::PipelineColorBlendStateCreateInfo color_blend_state_create_info{ + .attachmentCount = 1, + .pAttachments = &color_blend_attachment_state, + }; + + constexpr static std::array dynamic_states{ + vk::DynamicState::eViewport, + vk::DynamicState::eScissor, + }; + constexpr static vk::PipelineDynamicStateCreateInfo dynamic_state_create_info{ + .dynamicStateCount = static_cast<uint32_t>(dynamic_states.size()), + .pDynamicStates = dynamic_states.data(), + }; + + const vk::GraphicsPipelineCreateInfo create_info{ + .stageCount = static_cast<uint32_t>(shader_stages.size()), + .pStages = shader_stages.data(), + .pVertexInputState = &vertex_input_state_create_info, + .pInputAssemblyState = &input_assembly_state_create_info, + .pViewportState = &viewport_state_create_info, + .pRasterizationState = &rasterization_state_create_info, + .pMultisampleState = &multisample_state_create_info, + .pDepthStencilState = &depth_stencil_state_create_info, + .pColorBlendState = &color_blend_state_create_info, + .pDynamicState = &dynamic_state_create_info, + .layout = layout, + .renderPass = render_pass, + }; + + return device.createGraphicsPipelineUnique(nullptr, create_info).value; +} diff --git a/src/GraphicsPipeline.hpp b/src/GraphicsPipeline.hpp new file mode 100644 index 0000000000000000000000000000000000000000..9e33271de6486d29c98ed5bb90423cb43a427e72 --- /dev/null +++ b/src/GraphicsPipeline.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include <vulkan/vulkan.hpp> + +[[nodiscard]] +auto create_pipeline_layout(vk::Device) -> vk::UniquePipelineLayout; + +[[nodiscard]] +auto build_graphics_pipeline( + vk::Device device, + vk::PipelineLayout layout, + vk::RenderPass render_pass +) -> vk::UniquePipeline; diff --git a/src/Renderer.cpp b/src/Renderer.cpp index 9b34c28d3a3697541e2cf8ba41023272a8bbe782..9896107d41a0be9b08364f9b5be02a85d61c3aca 100644 --- a/src/Renderer.cpp +++ b/src/Renderer.cpp @@ -135,6 +135,57 @@ static auto return physical_device.createDeviceUnique(device_create_info); } +[[nodiscard]] +static auto create_render_pass(const vk::Format color_format, const vk::Device device) + -> vk::UniqueRenderPass +{ + const vk::AttachmentDescription color_attachment_description{ + .format = color_format, + .samples = vk::SampleCountFlagBits::e1, + .loadOp = vk::AttachmentLoadOp::eClear, + .storeOp = vk::AttachmentStoreOp::eStore, + .stencilLoadOp = vk::AttachmentLoadOp::eDontCare, + .stencilStoreOp = vk::AttachmentStoreOp::eDontCare, + .initialLayout = vk::ImageLayout::eUndefined, + .finalLayout = vk::ImageLayout::ePresentSrcKHR, + }; + + const std::array attachment_descriptions{ + color_attachment_description, + }; + + constexpr static vk::AttachmentReference color_attachment_reference{ + .attachment = 0, + .layout = vk::ImageLayout::eColorAttachmentOptimal, + }; + + const vk::SubpassDescription subpass_description{ + .pipelineBindPoint = vk::PipelineBindPoint::eGraphics, + .colorAttachmentCount = 1, + .pColorAttachments = &color_attachment_reference, + }; + + constexpr static vk::SubpassDependency subpass_dependency{ + .srcSubpass = VK_SUBPASS_EXTERNAL, + .dstSubpass = 0, + .srcStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput, + .dstStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput, + .srcAccessMask = vk::AccessFlagBits::eNone, + .dstAccessMask = vk::AccessFlagBits::eColorAttachmentWrite, + }; + + const vk::RenderPassCreateInfo render_pass_create_info{ + .attachmentCount = static_cast<uint32_t>(attachment_descriptions.size()), + .pAttachments = attachment_descriptions.data(), + .subpassCount = 1, + .pSubpasses = &subpass_description, + .dependencyCount = 1, + .pDependencies = &subpass_dependency, + }; + + return device.createRenderPassUnique(render_pass_create_info); +} + Renderer::Renderer(const Window& window) : m_instance{ create_instance() }, m_surface{ window.create_vulkan_surface(m_instance.get()) }, @@ -150,5 +201,6 @@ Renderer::Renderer(const Window& window) m_queue_family_index, m_device.get(), window.framebuffer_size() - ) } + ) }, + m_render_pass{ create_render_pass(m_swapchain->format(), m_device.get()) } {} diff --git a/src/Renderer.hpp b/src/Renderer.hpp index 3f4c0c104b2af50f35851414f85f55b7c942dcee..7d2cc0740804ab97b816f1d20aef673932ec4783 100644 --- a/src/Renderer.hpp +++ b/src/Renderer.hpp @@ -12,13 +12,15 @@ public: explicit Renderer(const Window& window); private: - vk::UniqueInstance m_instance; + vk::UniqueInstance m_instance; vk::UniqueSurfaceKHR m_surface; - + vk::PhysicalDevice m_physical_device; uint32_t m_queue_family_index; vk::UniqueDevice m_device; vk::Queue m_queue; std::optional<Swapchain> m_swapchain; + + vk::UniqueRenderPass m_render_pass; };