From e8cd239a6b6db8224a788d95703b514512e6d9d0 Mon Sep 17 00:00:00 2001 From: Benedikt Ziemons Date: Tue, 18 Jan 2022 23:33:20 +0100 Subject: [PATCH] Create and use render pipeline with shaders --- src/ShaderLoader.cpp | 16 ++-- src/ShaderLoader.h | 2 +- src/VulkanRenderer.cpp | 191 ++++++++++++++++++++++++++++------------- src/VulkanRenderer.h | 6 +- src/VulkanWindow.cpp | 5 +- src/VulkanWindow.h | 12 ++- 6 files changed, 152 insertions(+), 80 deletions(-) diff --git a/src/ShaderLoader.cpp b/src/ShaderLoader.cpp index 6be2db1..7e45ab7 100644 --- a/src/ShaderLoader.cpp +++ b/src/ShaderLoader.cpp @@ -8,22 +8,26 @@ std::vector ShaderLoader::loadShaders( for (int i = 0; i < shaderFilenameCount; ++i) { std::ifstream shaderFile(shaderFilenames[i], std::ios::ate | std::ios::binary); - assert(shaderFile.is_open()); + if (!shaderFile.is_open()) { + qFatal("Could not open shader file %s", shaderFilenames[i].c_str()); + } // std::ios::ate starts at the end of file => position is the file size const std::fpos &fileSize = shaderFile.tellg(); - std::vector buffer(fileSize); + std::vector buffer((fileSize / sizeof(uint32_t)) + 1); shaderFile.seekg(0); - shaderFile.read(buffer.data(), fileSize); + shaderFile.read(reinterpret_cast(buffer.data()), fileSize); shaderFile.close(); VkShaderModuleCreateInfo createInfo{}; createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; - createInfo.codeSize = buffer.size(); - createInfo.pCode = reinterpret_cast(buffer.data()); + createInfo.codeSize = fileSize; + createInfo.pCode = buffer.data(); VkShaderModule shaderModule; VkResult result = deviceFunctions->vkCreateShaderModule( device, &createInfo, nullptr, &shaderModule); - assert(result == VK_SUCCESS); + if (result != VK_SUCCESS) { + qFatal("Could not create shader module: code %d", result); + } loadedShaders.push_back(shaderModule); } return loadedShaders; diff --git a/src/ShaderLoader.h b/src/ShaderLoader.h index 03288c6..08d5381 100644 --- a/src/ShaderLoader.h +++ b/src/ShaderLoader.h @@ -9,7 +9,7 @@ class ShaderLoader { private: - std::vector loadedShaders; + std::vector loadedShaders{}; public: ShaderLoader() = default; diff --git a/src/VulkanRenderer.cpp b/src/VulkanRenderer.cpp index 1a0aaab..c139b6b 100644 --- a/src/VulkanRenderer.cpp +++ b/src/VulkanRenderer.cpp @@ -1,11 +1,33 @@ #include "VulkanRenderer.h" #include -VulkanRenderer::VulkanRenderer(QVulkanWindow *w) - : m_window(w), m_devFuncs(nullptr) {} +VulkanRenderer::VulkanRenderer(QVulkanWindow *w) : m_window(w) {} void VulkanRenderer::initResources() { + VkResult result; m_devFuncs = m_window->vulkanInstance()->deviceFunctions(m_window->device()); + + VkPipelineLayoutCreateInfo pipelineLayoutInfo{}; + pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + pipelineLayoutInfo.setLayoutCount = 0; // Optional + pipelineLayoutInfo.pSetLayouts = nullptr; // Optional + pipelineLayoutInfo.pushConstantRangeCount = 0; // Optional + pipelineLayoutInfo.pPushConstantRanges = nullptr; // Optional + + result = m_devFuncs->vkCreatePipelineLayout( + m_window->device(), &pipelineLayoutInfo, nullptr, &m_pipelineLayout); + if (result != VK_SUCCESS) { + qFatal("Failed to create pipeline layout, code: %d", result); + } + + VkPipelineVertexInputStateCreateInfo vertexInputInfo{}; + vertexInputInfo.sType = + VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; + vertexInputInfo.vertexBindingDescriptionCount = 0; + vertexInputInfo.pVertexBindingDescriptions = nullptr; // Optional + vertexInputInfo.vertexAttributeDescriptionCount = 0; + vertexInputInfo.pVertexAttributeDescriptions = nullptr; // Optional + auto shaders = std::array{"shaders/vert.spv", "shaders/frag.spv"}; auto loadedShaders = @@ -22,66 +44,102 @@ void VulkanRenderer::initResources() { fragShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT; fragShaderStageInfo.module = loadedShaders[1]; fragShaderStageInfo.pName = "main"; + std::array shaderStages{ + vertShaderStageInfo, fragShaderStageInfo}; + VkGraphicsPipelineCreateInfo pipelineInfo{}; + pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + pipelineInfo.stageCount = shaderStages.size(); + pipelineInfo.pStages = shaderStages.data(); + pipelineInfo.pVertexInputState = &vertexInputInfo; + + VkPipelineInputAssemblyStateCreateInfo ia; + memset(&ia, 0, sizeof(ia)); + ia.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; + ia.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + pipelineInfo.pInputAssemblyState = &ia; + + VkPipelineViewportStateCreateInfo vp; + memset(&vp, 0, sizeof(vp)); + vp.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; + vp.viewportCount = 1; + vp.scissorCount = 1; + pipelineInfo.pViewportState = &vp; + + VkPipelineRasterizationStateCreateInfo rs; + memset(&rs, 0, sizeof(rs)); + rs.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; + rs.polygonMode = VK_POLYGON_MODE_FILL; + // rs.cullMode = VK_CULL_MODE_BACK_BIT; + rs.cullMode = VK_CULL_MODE_NONE; + rs.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; + rs.lineWidth = 1.0f; + pipelineInfo.pRasterizationState = &rs; + + VkPipelineMultisampleStateCreateInfo ms; + memset(&ms, 0, sizeof(ms)); + ms.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; + ms.rasterizationSamples = m_window->sampleCountFlagBits(); + pipelineInfo.pMultisampleState = &ms; + + VkPipelineDepthStencilStateCreateInfo ds; + memset(&ds, 0, sizeof(ds)); + ds.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; + ds.depthTestEnable = VK_FALSE; + ds.depthWriteEnable = VK_TRUE; + ds.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL; + pipelineInfo.pDepthStencilState = &ds; + + VkPipelineColorBlendStateCreateInfo cb; + memset(&cb, 0, sizeof(cb)); + cb.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; + VkPipelineColorBlendAttachmentState att; + memset(&att, 0, sizeof(att)); + att.colorWriteMask = 0xF; + cb.attachmentCount = 1; + cb.pAttachments = &att; + pipelineInfo.pColorBlendState = &cb; + + VkDynamicState dynamicStates[] = {VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_SCISSOR}; + VkPipelineDynamicStateCreateInfo dyn; + memset(&dyn, 0, sizeof(dyn)); + dyn.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; + dyn.dynamicStateCount = sizeof(dynamicStates) / sizeof(VkDynamicState); + dyn.pDynamicStates = dynamicStates; + pipelineInfo.pDynamicState = &dyn; + + pipelineInfo.layout = m_pipelineLayout; + pipelineInfo.renderPass = m_window->defaultRenderPass(); + pipelineInfo.basePipelineHandle = VK_NULL_HANDLE; // Optional + pipelineInfo.basePipelineIndex = -1; // Optional + + result = m_devFuncs->vkCreateGraphicsPipelines( + m_window->device(), VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, + &m_graphicsPipeline); + if (result != VK_SUCCESS) { + qFatal("Failed to create graphics pipeline: code %d", result); + } } -//void VulkanRenderer::initSwapChainResources() { - // qDebug() << "initSwapChainResources"; - // VkFramebufferCreateInfo framebufferInfo = {}; - // framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; - // framebufferInfo.pNext = nullptr; - // framebufferInfo.renderPass = m_renderPass; - // framebufferInfo.attachmentCount = 1; - // framebufferInfo.width = m_window->width(); - // framebufferInfo.height = m_window->height(); - // framebufferInfo.layers = 1; - // - // m_swapChainImages = std::vector(m_window->swapChainImageCount()); - // m_swapChainImageViews = - // std::vector(m_window->swapChainImageCount()); - // m_framebuffers = - // std::vector(m_window->swapChainImageCount()); for (int i = - // 0; i < m_window->swapChainImageCount(); ++i) { - // m_swapChainImages[i] = m_window->swapChainImage(i); - // m_swapChainImageViews[i] = m_window->swapChainImageView(i); - // - // framebufferInfo.pAttachments = &m_swapChainImageViews[i]; - // VkResult vkResult = m_devFuncs->vkCreateFramebuffer( - // m_window->device(), &framebufferInfo, nullptr, &m_framebuffers[i]); - // assert(vkResult == VK_SUCCESS); - // } -//} - -//void VulkanRenderer::releaseSwapChainResources() { - // destruction of swap chain image views are handled in Qt framework - // for (auto& imageView : m_swapChainImageViews) { - // m_devFuncs->vkDestroyImageView(m_window->device(), imageView, nullptr); - // } - // for (auto &framebuffer : m_framebuffers) { - // m_devFuncs->vkDestroyFramebuffer(m_window->device(), framebuffer, - // nullptr); - // } - // destruction of the default render pass is handled in Qt framework - // m_devFuncs->vkDestroyRenderPass(m_window->device(), m_renderPass, - // nullptr); -//} - void VulkanRenderer::releaseResources() { + m_devFuncs->vkDestroyPipeline(m_window->device(), m_graphicsPipeline, + nullptr); + m_devFuncs->vkDestroyPipelineLayout(m_window->device(), m_pipelineLayout, + nullptr); m_shaderLoader.destroyShaders(m_window->device(), m_devFuncs); } void VulkanRenderer::startNextFrame() { VkCommandBuffer cmdBuf = m_window->currentCommandBuffer(); - // make a clear-color from frame number. This will flash with a 120*pi frame - // period. - VkClearValue clearValue; + VkClearDepthStencilValue clearDS = {1, 0}; + std::array clearValue{}; float flash = std::abs(std::sin(static_cast(m_frameNumber) / 120.f)); - clearValue.color = {{0.0f, 0.0f, flash, 1.0f}}; + clearValue[0].color = {{0.0f, 0.0f, flash, 1.0f}}; + clearValue[1].depthStencil = clearDS; + clearValue[2].color = clearValue[0].color; - // start the main renderpass. - // We will use the clear color from above, and the framebuffer of the index - // the swapchain gave us - VkRenderPassBeginInfo rpInfo = {}; + VkRenderPassBeginInfo rpInfo{}; rpInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; rpInfo.pNext = nullptr; @@ -90,20 +148,31 @@ void VulkanRenderer::startNextFrame() { rpInfo.renderArea.offset.y = 0; rpInfo.renderArea.extent.width = m_window->width(); rpInfo.renderArea.extent.height = m_window->height(); + rpInfo.clearValueCount = + m_window->sampleCountFlagBits() > VK_SAMPLE_COUNT_1_BIT ? 3 : 2; + rpInfo.pClearValues = clearValue.data(); rpInfo.framebuffer = m_window->currentFramebuffer(); - // connect clear values - rpInfo.clearValueCount = 1; - rpInfo.pClearValues = &clearValue; - m_devFuncs->vkCmdBeginRenderPass(cmdBuf, &rpInfo, VK_SUBPASS_CONTENTS_INLINE); - // int imageIndex = m_window->currentSwapChainImageIndex(); - // uint32_t swapchainImageIndex; - // VK_CHECK(vkAcquireNextImageKHR(_device, _swapchain, 1000000000, - // _presentSemaphore, nullptr, &swapchainImageIndex)); - // m_devFuncs->vkCmdEndRenderPass(cmdBuf); - ++m_frameNumber; + const QSize renderTargetSize = m_window->swapChainImageSize(); + VkViewport viewport = { + 0, 0, float(renderTargetSize.width()), float(renderTargetSize.height()), + 0, 1}; + m_devFuncs->vkCmdSetViewport(cmdBuf, 0, 1, &viewport); + + VkRect2D scissor = {{0, 0}, + {uint32_t(renderTargetSize.width()), + uint32_t(renderTargetSize.height())}}; + m_devFuncs->vkCmdSetScissor(cmdBuf, 0, 1, &scissor); + + m_devFuncs->vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, + m_graphicsPipeline); + + m_devFuncs->vkCmdDraw(cmdBuf, 3, 1, 0, 0); + + m_devFuncs->vkCmdEndRenderPass(cmdBuf); m_window->frameReady(); + ++m_frameNumber; m_window->requestUpdate(); } diff --git a/src/VulkanRenderer.h b/src/VulkanRenderer.h index 4040701..45bf2b9 100644 --- a/src/VulkanRenderer.h +++ b/src/VulkanRenderer.h @@ -16,9 +16,11 @@ public: private: QVulkanWindow *m_window; - QVulkanDeviceFunctions *m_devFuncs; + QVulkanDeviceFunctions *m_devFuncs{}; unsigned long m_frameNumber{0UL}; - ShaderLoader m_shaderLoader; + ShaderLoader m_shaderLoader{}; + VkPipelineLayout m_pipelineLayout{}; + VkPipeline m_graphicsPipeline{}; }; #endif // VULKANCPPSETUP_VULKANRENDERER_H diff --git a/src/VulkanWindow.cpp b/src/VulkanWindow.cpp index 52abf89..e55d189 100644 --- a/src/VulkanWindow.cpp +++ b/src/VulkanWindow.cpp @@ -6,9 +6,8 @@ static const int KEY_ESCAPE = 16777216; void VulkanWindow::keyPressEvent(QKeyEvent *event) { QWindow::keyPressEvent(event); - qDebug() << "text" << event->text() - << "key" << event->key() - << "modifiers" << event->modifiers(); + qDebug() << "text" << event->text() << "key" << event->key() << "modifiers" + << event->modifiers(); if (event->matches(QKeySequence::Quit) || event->key() == KEY_ESCAPE) { close(); } diff --git a/src/VulkanWindow.h b/src/VulkanWindow.h index c515314..84adc2b 100644 --- a/src/VulkanWindow.h +++ b/src/VulkanWindow.h @@ -5,18 +5,16 @@ #ifndef VULKANCPPSETUP_VULKANWINDOW_H #define VULKANCPPSETUP_VULKANWINDOW_H +#include #include #include -#include -class VulkanWindow : public QVulkanWindow -{ +class VulkanWindow : public QVulkanWindow { public: - QVulkanWindowRenderer *createRenderer() override; + QVulkanWindowRenderer *createRenderer() override; protected: - void keyPressEvent(QKeyEvent* event) override; - + void keyPressEvent(QKeyEvent *event) override; }; -#endif //VULKANCPPSETUP_VULKANWINDOW_H +#endif // VULKANCPPSETUP_VULKANWINDOW_H