Create and use render pipeline with shaders
This commit is contained in:
parent
7127555dea
commit
e8cd239a6b
|
@ -8,22 +8,26 @@ std::vector<VkShaderModule> ShaderLoader::loadShaders(
|
||||||
for (int i = 0; i < shaderFilenameCount; ++i) {
|
for (int i = 0; i < shaderFilenameCount; ++i) {
|
||||||
std::ifstream shaderFile(shaderFilenames[i],
|
std::ifstream shaderFile(shaderFilenames[i],
|
||||||
std::ios::ate | std::ios::binary);
|
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
|
// std::ios::ate starts at the end of file => position is the file size
|
||||||
const std::fpos<mbstate_t> &fileSize = shaderFile.tellg();
|
const std::fpos<mbstate_t> &fileSize = shaderFile.tellg();
|
||||||
std::vector<char> buffer(fileSize);
|
std::vector<uint32_t> buffer((fileSize / sizeof(uint32_t)) + 1);
|
||||||
shaderFile.seekg(0);
|
shaderFile.seekg(0);
|
||||||
shaderFile.read(buffer.data(), fileSize);
|
shaderFile.read(reinterpret_cast<char *>(buffer.data()), fileSize);
|
||||||
shaderFile.close();
|
shaderFile.close();
|
||||||
|
|
||||||
VkShaderModuleCreateInfo createInfo{};
|
VkShaderModuleCreateInfo createInfo{};
|
||||||
createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
|
createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
|
||||||
createInfo.codeSize = buffer.size();
|
createInfo.codeSize = fileSize;
|
||||||
createInfo.pCode = reinterpret_cast<const uint32_t *>(buffer.data());
|
createInfo.pCode = buffer.data();
|
||||||
VkShaderModule shaderModule;
|
VkShaderModule shaderModule;
|
||||||
VkResult result = deviceFunctions->vkCreateShaderModule(
|
VkResult result = deviceFunctions->vkCreateShaderModule(
|
||||||
device, &createInfo, nullptr, &shaderModule);
|
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);
|
loadedShaders.push_back(shaderModule);
|
||||||
}
|
}
|
||||||
return loadedShaders;
|
return loadedShaders;
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
class ShaderLoader {
|
class ShaderLoader {
|
||||||
private:
|
private:
|
||||||
std::vector<VkShaderModule> loadedShaders;
|
std::vector<VkShaderModule> loadedShaders{};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ShaderLoader() = default;
|
ShaderLoader() = default;
|
||||||
|
|
|
@ -1,11 +1,33 @@
|
||||||
#include "VulkanRenderer.h"
|
#include "VulkanRenderer.h"
|
||||||
#include <complex>
|
#include <complex>
|
||||||
|
|
||||||
VulkanRenderer::VulkanRenderer(QVulkanWindow *w)
|
VulkanRenderer::VulkanRenderer(QVulkanWindow *w) : m_window(w) {}
|
||||||
: m_window(w), m_devFuncs(nullptr) {}
|
|
||||||
|
|
||||||
void VulkanRenderer::initResources() {
|
void VulkanRenderer::initResources() {
|
||||||
|
VkResult result;
|
||||||
m_devFuncs = m_window->vulkanInstance()->deviceFunctions(m_window->device());
|
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 =
|
auto shaders =
|
||||||
std::array<std::string, 2>{"shaders/vert.spv", "shaders/frag.spv"};
|
std::array<std::string, 2>{"shaders/vert.spv", "shaders/frag.spv"};
|
||||||
auto loadedShaders =
|
auto loadedShaders =
|
||||||
|
@ -22,66 +44,102 @@ void VulkanRenderer::initResources() {
|
||||||
fragShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
|
fragShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||||
fragShaderStageInfo.module = loadedShaders[1];
|
fragShaderStageInfo.module = loadedShaders[1];
|
||||||
fragShaderStageInfo.pName = "main";
|
fragShaderStageInfo.pName = "main";
|
||||||
|
std::array<VkPipelineShaderStageCreateInfo, 2> 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<VkImage>(m_window->swapChainImageCount());
|
|
||||||
// m_swapChainImageViews =
|
|
||||||
// std::vector<VkImageView>(m_window->swapChainImageCount());
|
|
||||||
// m_framebuffers =
|
|
||||||
// std::vector<VkFramebuffer>(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() {
|
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);
|
m_shaderLoader.destroyShaders(m_window->device(), m_devFuncs);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanRenderer::startNextFrame() {
|
void VulkanRenderer::startNextFrame() {
|
||||||
VkCommandBuffer cmdBuf = m_window->currentCommandBuffer();
|
VkCommandBuffer cmdBuf = m_window->currentCommandBuffer();
|
||||||
|
|
||||||
// make a clear-color from frame number. This will flash with a 120*pi frame
|
VkClearDepthStencilValue clearDS = {1, 0};
|
||||||
// period.
|
std::array<VkClearValue, 3> clearValue{};
|
||||||
VkClearValue clearValue;
|
|
||||||
float flash = std::abs(std::sin(static_cast<float>(m_frameNumber) / 120.f));
|
float flash = std::abs(std::sin(static_cast<float>(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.
|
VkRenderPassBeginInfo rpInfo{};
|
||||||
// We will use the clear color from above, and the framebuffer of the index
|
|
||||||
// the swapchain gave us
|
|
||||||
VkRenderPassBeginInfo rpInfo = {};
|
|
||||||
rpInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
rpInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
||||||
rpInfo.pNext = nullptr;
|
rpInfo.pNext = nullptr;
|
||||||
|
|
||||||
|
@ -90,20 +148,31 @@ void VulkanRenderer::startNextFrame() {
|
||||||
rpInfo.renderArea.offset.y = 0;
|
rpInfo.renderArea.offset.y = 0;
|
||||||
rpInfo.renderArea.extent.width = m_window->width();
|
rpInfo.renderArea.extent.width = m_window->width();
|
||||||
rpInfo.renderArea.extent.height = m_window->height();
|
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();
|
rpInfo.framebuffer = m_window->currentFramebuffer();
|
||||||
|
|
||||||
// connect clear values
|
|
||||||
rpInfo.clearValueCount = 1;
|
|
||||||
rpInfo.pClearValues = &clearValue;
|
|
||||||
|
|
||||||
m_devFuncs->vkCmdBeginRenderPass(cmdBuf, &rpInfo, VK_SUBPASS_CONTENTS_INLINE);
|
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);
|
const QSize renderTargetSize = m_window->swapChainImageSize();
|
||||||
++m_frameNumber;
|
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_window->frameReady();
|
||||||
|
++m_frameNumber;
|
||||||
m_window->requestUpdate();
|
m_window->requestUpdate();
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,9 +16,11 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QVulkanWindow *m_window;
|
QVulkanWindow *m_window;
|
||||||
QVulkanDeviceFunctions *m_devFuncs;
|
QVulkanDeviceFunctions *m_devFuncs{};
|
||||||
unsigned long m_frameNumber{0UL};
|
unsigned long m_frameNumber{0UL};
|
||||||
ShaderLoader m_shaderLoader;
|
ShaderLoader m_shaderLoader{};
|
||||||
|
VkPipelineLayout m_pipelineLayout{};
|
||||||
|
VkPipeline m_graphicsPipeline{};
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // VULKANCPPSETUP_VULKANRENDERER_H
|
#endif // VULKANCPPSETUP_VULKANRENDERER_H
|
||||||
|
|
|
@ -6,9 +6,8 @@ static const int KEY_ESCAPE = 16777216;
|
||||||
|
|
||||||
void VulkanWindow::keyPressEvent(QKeyEvent *event) {
|
void VulkanWindow::keyPressEvent(QKeyEvent *event) {
|
||||||
QWindow::keyPressEvent(event);
|
QWindow::keyPressEvent(event);
|
||||||
qDebug() << "text" << event->text()
|
qDebug() << "text" << event->text() << "key" << event->key() << "modifiers"
|
||||||
<< "key" << event->key()
|
<< event->modifiers();
|
||||||
<< "modifiers" << event->modifiers();
|
|
||||||
if (event->matches(QKeySequence::Quit) || event->key() == KEY_ESCAPE) {
|
if (event->matches(QKeySequence::Quit) || event->key() == KEY_ESCAPE) {
|
||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,18 +5,16 @@
|
||||||
#ifndef VULKANCPPSETUP_VULKANWINDOW_H
|
#ifndef VULKANCPPSETUP_VULKANWINDOW_H
|
||||||
#define VULKANCPPSETUP_VULKANWINDOW_H
|
#define VULKANCPPSETUP_VULKANWINDOW_H
|
||||||
|
|
||||||
|
#include <QVulkanWindow>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <qevent.h>
|
#include <qevent.h>
|
||||||
#include <QVulkanWindow>
|
|
||||||
|
|
||||||
class VulkanWindow : public QVulkanWindow
|
class VulkanWindow : public QVulkanWindow {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
QVulkanWindowRenderer *createRenderer() override;
|
QVulkanWindowRenderer *createRenderer() override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void keyPressEvent(QKeyEvent *event) override;
|
void keyPressEvent(QKeyEvent *event) override;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // VULKANCPPSETUP_VULKANWINDOW_H
|
#endif // VULKANCPPSETUP_VULKANWINDOW_H
|
||||||
|
|
Loading…
Reference in a new issue