From 5744e7a13c6d3d3e1b61246e0e5d58f477f2cfc7 Mon Sep 17 00:00:00 2001 From: Anish Bhobe Date: Mon, 1 Jul 2024 19:53:06 +0200 Subject: [PATCH] Trivial Pipeline object. --- aster/CMakeLists.txt | 6 +- aster/pipeline.cpp | 21 +++ aster/pipeline.h | 20 +++ triangle/triangle.cpp | 329 ++++++++++++++++++++++-------------------- 4 files changed, 218 insertions(+), 158 deletions(-) create mode 100644 aster/pipeline.cpp create mode 100644 aster/pipeline.h diff --git a/aster/CMakeLists.txt b/aster/CMakeLists.txt index 2ba28a1..5e30339 100644 --- a/aster/CMakeLists.txt +++ b/aster/CMakeLists.txt @@ -19,7 +19,8 @@ set(HEADER_FILES window.h physical_device.h device.h - swapchain.h) + swapchain.h + "pipeline.h") set(SOURCE_FILES logger.cpp @@ -28,7 +29,8 @@ set(SOURCE_FILES window.cpp physical_device.cpp device.cpp - swapchain.cpp) + swapchain.cpp + pipeline.cpp) add_library(aster_core STATIC ${SOURCE_FILES} ${HEADER_FILES}) set_property(TARGET aster_core PROPERTY CXX_STANDARD 20) diff --git a/aster/pipeline.cpp b/aster/pipeline.cpp new file mode 100644 index 0000000..a6ca175 --- /dev/null +++ b/aster/pipeline.cpp @@ -0,0 +1,21 @@ +// ============================================= +// Aster: pipeline.cpp +// Copyright (c) 2020-2024 Anish Bhobe +// ============================================= + +#include "pipeline.h" + +#include "device.h" + +Pipeline::Pipeline(const Device *device, vk::PipelineLayout layout, vk::Pipeline pipeline) + : m_Device(device) + , m_Layout(layout) + , m_Pipeline(pipeline) +{ +} + +Pipeline::~Pipeline() +{ + m_Device->m_Device.destroy(m_Pipeline, nullptr); + m_Device->m_Device.destroy(m_Layout, nullptr); +} \ No newline at end of file diff --git a/aster/pipeline.h b/aster/pipeline.h new file mode 100644 index 0000000..4376ed8 --- /dev/null +++ b/aster/pipeline.h @@ -0,0 +1,20 @@ +// ============================================= +// Aster: pipeline.h +// Copyright (c) 2020-2024 Anish Bhobe +// ============================================= + +#pragma once + +#include "global.h" + +struct Device; + +struct Pipeline +{ + const Device *m_Device; + vk::PipelineLayout m_Layout; + vk::Pipeline m_Pipeline; + + Pipeline(const Device *device, vk::PipelineLayout layout, vk::Pipeline pipeline); + ~Pipeline(); +}; \ No newline at end of file diff --git a/triangle/triangle.cpp b/triangle/triangle.cpp index 555c7cd..0aa7068 100644 --- a/triangle/triangle.cpp +++ b/triangle/triangle.cpp @@ -6,6 +6,7 @@ #include "aster/window.h" #include "aster/global.h" +#include "aster/pipeline.h" #include "aster/swapchain.h" #include @@ -39,10 +40,13 @@ struct Shader vk::ShaderStageFlags m_Stage; }; +Pipeline +CreatePipeline(const Device *device, const Swapchain *swapchain, cstr vertexShaderFile, cstr fragmentShaderFile); + int main(int, char **) { - MIN_LOG_LEVEL(Logger::LogType::eVerbose); + MIN_LOG_LEVEL(Logger::LogType::eInfo); GlfwContext glfwContext = {}; Context context = {"Aster", VERSION}; @@ -61,125 +65,12 @@ main(int, char **) Swapchain swapchain = {&window, &device, "Primary Chain"}; - auto vertexShaderModule = CreateShader(&device, "shader/triangle.vs.hlsl.spv"); - auto fragmentShaderModule = CreateShader(&device, "shader/white.frag.glsl.spv"); + auto vertexShaderFile = "shader/triangle.vs.hlsl.spv"; + auto fragmentShaderFile = "shader/white.frag.glsl.spv"; - eastl::array shaderStages = {{ - { - .stage = vk::ShaderStageFlagBits::eVertex, - .module = vertexShaderModule, - .pName = "main", - }, - { - .stage = vk::ShaderStageFlagBits::eFragment, - .module = fragmentShaderModule, - .pName = "main", - }, - }}; - - vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo = { - .setLayoutCount = 0, - .pSetLayouts = nullptr, - .pushConstantRangeCount = 0, - .pPushConstantRanges = nullptr, - }; - vk::PipelineLayout pipelineLayout; - vk::Result result = device.m_Device.createPipelineLayout(&pipelineLayoutCreateInfo, nullptr, &pipelineLayout); - ERROR_IF(Failed(result), "Could not create a pipeline layout. Cause: {}", result) THEN_ABORT(result); - device.SetName(pipelineLayout, "Triangle Layout"); - - vk::PipelineVertexInputStateCreateInfo vertexInputStateCreateInfo = { - .vertexBindingDescriptionCount = 0, - .pVertexBindingDescriptions = nullptr, - .vertexAttributeDescriptionCount = 0, - .pVertexAttributeDescriptions = nullptr, - }; - vk::PipelineInputAssemblyStateCreateInfo inputAssemblyStateCreateInfo = { - .topology = vk::PrimitiveTopology::eTriangleList, - .primitiveRestartEnable = vk::False, - }; - - vk::PipelineViewportStateCreateInfo viewportStateCreateInfo = { - .viewportCount = 1, - .scissorCount = 1, - }; - - vk::PipelineRasterizationStateCreateInfo rasterizationStateCreateInfo = { - .depthClampEnable = vk::False, - .rasterizerDiscardEnable = vk::False, - .polygonMode = vk::PolygonMode::eFill, - .cullMode = vk::CullModeFlagBits::eNone, - .frontFace = vk::FrontFace::eCounterClockwise, - .depthBiasEnable = vk::False, - .lineWidth = 1.0, - }; - vk::PipelineMultisampleStateCreateInfo multisampleStateCreateInfo = { - .rasterizationSamples = vk::SampleCountFlagBits::e1, - .sampleShadingEnable = vk::False, - }; - vk::PipelineDepthStencilStateCreateInfo depthStencilStateCreateInfo = { - .depthTestEnable = vk::False, - .depthWriteEnable = vk::False, - }; - vk::PipelineColorBlendAttachmentState colorBlendAttachmentState = { - .blendEnable = vk::False, - .srcColorBlendFactor = vk::BlendFactor::eSrcColor, - .dstColorBlendFactor = vk::BlendFactor::eOneMinusSrcColor, - .colorBlendOp = vk::BlendOp::eAdd, - .srcAlphaBlendFactor = vk::BlendFactor::eSrcAlpha, - .dstAlphaBlendFactor = vk::BlendFactor::eOneMinusSrcAlpha, - .alphaBlendOp = vk::BlendOp::eAdd, - .colorWriteMask = vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG | - vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA, - }; - vk::PipelineColorBlendStateCreateInfo colorBlendStateCreateInfo = { - .logicOpEnable = vk::False, - .attachmentCount = 1, - .pAttachments = &colorBlendAttachmentState, - }; - - eastl::array dynamicStates = { - vk::DynamicState::eScissor, - vk::DynamicState::eViewport, - }; - - vk::PipelineDynamicStateCreateInfo dynamicStateCreateInfo = { - .dynamicStateCount = Cast(dynamicStates.size()), - .pDynamicStates = dynamicStates.data(), - }; - - vk::PipelineRenderingCreateInfo renderingCreateInfo = { - .viewMask = 0, - .colorAttachmentCount = 1, - .pColorAttachmentFormats = &swapchain.m_Format, - }; - - vk::GraphicsPipelineCreateInfo pipelineCreateInfo = { - .pNext = &renderingCreateInfo, - .stageCount = Cast(shaderStages.size()), - .pStages = shaderStages.data(), - .pVertexInputState = &vertexInputStateCreateInfo, - .pInputAssemblyState = &inputAssemblyStateCreateInfo, - .pViewportState = &viewportStateCreateInfo, - .pRasterizationState = &rasterizationStateCreateInfo, - .pMultisampleState = &multisampleStateCreateInfo, - .pDepthStencilState = &depthStencilStateCreateInfo, - .pColorBlendState = &colorBlendStateCreateInfo, - .pDynamicState = &dynamicStateCreateInfo, - .layout = pipelineLayout, - }; - vk::Pipeline pipeline; - result = device.m_Device.createGraphicsPipelines(nullptr, 1, &pipelineCreateInfo, nullptr, &pipeline); - ERROR_IF(Failed(result), "Could not create a graphics pipeline. Cause: {}", result) THEN_ABORT(result); - device.SetName(pipelineLayout, "Triangle Pipeline"); - - // Frames - eastl::fixed_vector frames; - for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i) - { - frames.emplace_back(&device, queueAllocation.m_Family, i); - } + Pipeline pipeline = CreatePipeline(&device, &swapchain, vertexShaderFile, fragmentShaderFile); + // Persistent variables vk::Viewport viewport = { .x = 0, .y = Cast(swapchain.m_Extent.height), @@ -194,12 +85,48 @@ main(int, char **) .extent = swapchain.m_Extent, }; + vk::ImageMemoryBarrier topOfThePipeBarrier = { + .oldLayout = vk::ImageLayout::eUndefined, + .newLayout = vk::ImageLayout::eColorAttachmentOptimal, + .srcQueueFamilyIndex = queueAllocation.m_Family, + .dstQueueFamilyIndex = queueAllocation.m_Family, + .subresourceRange = + { + .aspectMask = vk::ImageAspectFlagBits::eColor, + .baseMipLevel = 0, + .levelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1, + }, + }; + vk::ImageMemoryBarrier renderToPresentBarrier = { + .oldLayout = vk::ImageLayout::eColorAttachmentOptimal, + .newLayout = vk::ImageLayout::ePresentSrcKHR, + .srcQueueFamilyIndex = queueAllocation.m_Family, + .dstQueueFamilyIndex = queueAllocation.m_Family, + .subresourceRange = + { + .aspectMask = vk::ImageAspectFlagBits::eColor, + .baseMipLevel = 0, + .levelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1, + }, + }; + + // Frames + eastl::fixed_vector frames; + for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i) + { + frames.emplace_back(&device, queueAllocation.m_Family, i); + } + u32 frameIndex = 0; while (window.Poll()) { Frame *currentFrame = &frames[frameIndex]; - result = device.m_Device.waitForFences(1, ¤tFrame->m_FrameAvailableFence, vk::True, MaxValue); + auto result = device.m_Device.waitForFences(1, ¤tFrame->m_FrameAvailableFence, vk::True, MaxValue); ERROR_IF(Failed(result), "Waiting for fence {} failed. Cause: {}", frameIndex, result) THEN_ABORT(result); @@ -237,36 +164,8 @@ main(int, char **) vk::Image currentImage = swapchain.m_Images[imageIndex]; vk::CommandBuffer cmd = currentFrame->AllocateCommandBuffer(); - vk::ImageMemoryBarrier topOfThePipeBarrier = { - .oldLayout = vk::ImageLayout::eUndefined, - .newLayout = vk::ImageLayout::eColorAttachmentOptimal, - .srcQueueFamilyIndex = queueAllocation.m_Family, - .dstQueueFamilyIndex = queueAllocation.m_Family, - .image = currentImage, - .subresourceRange = - { - .aspectMask = vk::ImageAspectFlagBits::eColor, - .baseMipLevel = 0, - .levelCount = 1, - .baseArrayLayer = 0, - .layerCount = 1, - }, - }; - vk::ImageMemoryBarrier renderToPresentBarrier = { - .oldLayout = vk::ImageLayout::eColorAttachmentOptimal, - .newLayout = vk::ImageLayout::ePresentSrcKHR, - .srcQueueFamilyIndex = queueAllocation.m_Family, - .dstQueueFamilyIndex = queueAllocation.m_Family, - .image = currentImage, - .subresourceRange = - { - .aspectMask = vk::ImageAspectFlagBits::eColor, - .baseMipLevel = 0, - .levelCount = 1, - .baseArrayLayer = 0, - .layerCount = 1, - }, - }; + topOfThePipeBarrier.image = currentImage; + renderToPresentBarrier.image = currentImage; vk::CommandBufferBeginInfo beginInfo = {.flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit}; result = cmd.begin(&beginInfo); @@ -297,7 +196,7 @@ main(int, char **) cmd.setViewport(0, 1, &viewport); cmd.setScissor(0, 1, &scissor); - cmd.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline); + cmd.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline.m_Pipeline); cmd.draw(3, 1, 0, 0); cmd.endRendering(); @@ -353,14 +252,9 @@ main(int, char **) frameIndex = (frameIndex + 1) % MAX_FRAMES_IN_FLIGHT; } - result = device.m_Device.waitIdle(); + auto result = device.m_Device.waitIdle(); ERROR_IF(Failed(result), "Wait idle failed. Cause: {}", result); - device.m_Device.destroy(pipeline, nullptr); - device.m_Device.destroy(pipelineLayout, nullptr); - device.m_Device.destroy(vertexShaderModule, nullptr); - device.m_Device.destroy(fragmentShaderModule, nullptr); - return 0; } @@ -399,6 +293,7 @@ FindAppropriateQueueAllocation(const PhysicalDevice *physicalDevice) ERROR("No suitable queue family on the GPU.") THEN_ABORT(vk::Result::eErrorUnknown); } + eastl::optional> ReadFile(cstr fileName) { @@ -467,6 +362,128 @@ Frame::AllocateCommandBuffer() const return commandBuffer; } +Pipeline +CreatePipeline(const Device *device, const Swapchain *swapchain, cstr vertexShaderFile, cstr fragmentShaderFile) +{ + // Pipeline Setup + auto vertexShaderModule = CreateShader(device, vertexShaderFile); + auto fragmentShaderModule = CreateShader(device, fragmentShaderFile); + + eastl::array shaderStages = {{ + { + .stage = vk::ShaderStageFlagBits::eVertex, + .module = vertexShaderModule, + .pName = "main", + }, + { + .stage = vk::ShaderStageFlagBits::eFragment, + .module = fragmentShaderModule, + .pName = "main", + }, + }}; + + vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo = { + .setLayoutCount = 0, + .pSetLayouts = nullptr, + .pushConstantRangeCount = 0, + .pPushConstantRanges = nullptr, + }; + vk::PipelineLayout pipelineLayout; + vk::Result result = device->m_Device.createPipelineLayout(&pipelineLayoutCreateInfo, nullptr, &pipelineLayout); + ERROR_IF(Failed(result), "Could not create a pipeline layout. Cause: {}", result) THEN_ABORT(result); + device->SetName(pipelineLayout, "Triangle Layout"); + + vk::PipelineVertexInputStateCreateInfo vertexInputStateCreateInfo = { + .vertexBindingDescriptionCount = 0, + .pVertexBindingDescriptions = nullptr, + .vertexAttributeDescriptionCount = 0, + .pVertexAttributeDescriptions = nullptr, + }; + vk::PipelineInputAssemblyStateCreateInfo inputAssemblyStateCreateInfo = { + .topology = vk::PrimitiveTopology::eTriangleList, + .primitiveRestartEnable = vk::False, + }; + + vk::PipelineViewportStateCreateInfo viewportStateCreateInfo = { + .viewportCount = 1, + .scissorCount = 1, + }; + + vk::PipelineRasterizationStateCreateInfo rasterizationStateCreateInfo = { + .depthClampEnable = vk::False, + .rasterizerDiscardEnable = vk::False, + .polygonMode = vk::PolygonMode::eFill, + .cullMode = vk::CullModeFlagBits::eNone, + .frontFace = vk::FrontFace::eCounterClockwise, + .depthBiasEnable = vk::False, + .lineWidth = 1.0, + }; + vk::PipelineMultisampleStateCreateInfo multisampleStateCreateInfo = { + .rasterizationSamples = vk::SampleCountFlagBits::e1, + .sampleShadingEnable = vk::False, + }; + vk::PipelineDepthStencilStateCreateInfo depthStencilStateCreateInfo = { + .depthTestEnable = vk::False, + .depthWriteEnable = vk::False, + }; + vk::PipelineColorBlendAttachmentState colorBlendAttachmentState = { + .blendEnable = vk::False, + .srcColorBlendFactor = vk::BlendFactor::eSrcColor, + .dstColorBlendFactor = vk::BlendFactor::eOneMinusSrcColor, + .colorBlendOp = vk::BlendOp::eAdd, + .srcAlphaBlendFactor = vk::BlendFactor::eSrcAlpha, + .dstAlphaBlendFactor = vk::BlendFactor::eOneMinusSrcAlpha, + .alphaBlendOp = vk::BlendOp::eAdd, + .colorWriteMask = vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG | + vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA, + }; + vk::PipelineColorBlendStateCreateInfo colorBlendStateCreateInfo = { + .logicOpEnable = vk::False, + .attachmentCount = 1, + .pAttachments = &colorBlendAttachmentState, + }; + + eastl::array dynamicStates = { + vk::DynamicState::eScissor, + vk::DynamicState::eViewport, + }; + + vk::PipelineDynamicStateCreateInfo dynamicStateCreateInfo = { + .dynamicStateCount = Cast(dynamicStates.size()), + .pDynamicStates = dynamicStates.data(), + }; + + vk::PipelineRenderingCreateInfo renderingCreateInfo = { + .viewMask = 0, + .colorAttachmentCount = 1, + .pColorAttachmentFormats = &swapchain->m_Format, + }; + + vk::GraphicsPipelineCreateInfo pipelineCreateInfo = { + .pNext = &renderingCreateInfo, + .stageCount = Cast(shaderStages.size()), + .pStages = shaderStages.data(), + .pVertexInputState = &vertexInputStateCreateInfo, + .pInputAssemblyState = &inputAssemblyStateCreateInfo, + .pViewportState = &viewportStateCreateInfo, + .pRasterizationState = &rasterizationStateCreateInfo, + .pMultisampleState = &multisampleStateCreateInfo, + .pDepthStencilState = &depthStencilStateCreateInfo, + .pColorBlendState = &colorBlendStateCreateInfo, + .pDynamicState = &dynamicStateCreateInfo, + .layout = pipelineLayout, + }; + vk::Pipeline pipeline; + result = device->m_Device.createGraphicsPipelines(nullptr, 1, &pipelineCreateInfo, nullptr, &pipeline); + ERROR_IF(Failed(result), "Could not create a graphics pipeline. Cause: {}", result) + THEN_ABORT(result); + device->SetName(pipeline, "Triangle Pipeline"); + + device->m_Device.destroy(vertexShaderModule, nullptr); + device->m_Device.destroy(fragmentShaderModule, nullptr); + + return {device, pipelineLayout, pipeline}; +} vk::ShaderModule CreateShader(const Device *device, cstr shaderFile)