Add shaders and shader loading
This commit is contained in:
parent
2ec08561f1
commit
7127555dea
|
@ -1,4 +1,4 @@
|
||||||
cmake_minimum_required(VERSION 3.22)
|
cmake_minimum_required(VERSION 3.21)
|
||||||
project(VulkanCppSetup)
|
project(VulkanCppSetup)
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 20)
|
set(CMAKE_CXX_STANDARD 20)
|
||||||
|
@ -6,6 +6,6 @@ set(CMAKE_CXX_STANDARD 20)
|
||||||
find_package(Vulkan REQUIRED)
|
find_package(Vulkan REQUIRED)
|
||||||
find_package(Qt5 COMPONENTS Gui REQUIRED)
|
find_package(Qt5 COMPONENTS Gui REQUIRED)
|
||||||
|
|
||||||
add_executable(VulkanCppSetup src/main.cpp src/VulkanWindow.cpp src/VulkanRenderer.cpp)
|
add_executable(VulkanCppSetup src/main.cpp src/VulkanWindow.cpp src/VulkanRenderer.cpp src/ShaderLoader.cpp)
|
||||||
#include_directories(VulkanCppSetup ${Vulkan_INCLUDE_DIRS} ${Qt5_INCLUDE_DIRS})
|
#include_directories(VulkanCppSetup ${Vulkan_INCLUDE_DIRS} ${Qt5_INCLUDE_DIRS})
|
||||||
target_link_libraries(VulkanCppSetup ${Vulkan_LIBRARIES} Qt5::Gui)
|
target_link_libraries(VulkanCppSetup ${Vulkan_LIBRARIES} Qt5::Gui)
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
# Vulkan Renderer
|
# Vulkan Renderer
|
||||||
|
|
||||||
|
Created with Qt 5 and the help of <https://vulkan-tutorial.com>
|
||||||
|
and <https://vkguide.dev/> and <https://doc.qt.io/qt-5/>.
|
||||||
|
|
||||||
## Building
|
## Building
|
||||||
|
|
||||||
Needs cmake 3.22+, C++20 compiler, Qt 5.10+
|
Needs cmake 3.21+, C++20 compiler, Qt 5.10+
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
|
|
9
make_shaders.sh
Executable file
9
make_shaders.sh
Executable file
|
@ -0,0 +1,9 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
DIR="$(realpath $(dirname $0))"
|
||||||
|
cd "${DIR}/shaders"
|
||||||
|
|
||||||
|
# needs Vulkan SDK
|
||||||
|
glslc shader.vert -o vert.spv
|
||||||
|
glslc shader.frag -o frag.spv
|
||||||
|
|
BIN
shaders/frag.spv
Normal file
BIN
shaders/frag.spv
Normal file
Binary file not shown.
9
shaders/shader.frag
Normal file
9
shaders/shader.frag
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
#version 450
|
||||||
|
|
||||||
|
layout(location = 0) in vec3 fragColor;
|
||||||
|
|
||||||
|
layout(location = 0) out vec4 outColor;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
outColor = vec4(fragColor, 1.0);
|
||||||
|
}
|
20
shaders/shader.vert
Normal file
20
shaders/shader.vert
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
#version 450
|
||||||
|
|
||||||
|
layout(location = 0) out vec3 fragColor;
|
||||||
|
|
||||||
|
vec2 positions[3] = vec2[](
|
||||||
|
vec2(0.0, -0.5),
|
||||||
|
vec2(0.5, 0.5),
|
||||||
|
vec2(-0.5, 0.5)
|
||||||
|
);
|
||||||
|
|
||||||
|
vec3 colors[3] = vec3[](
|
||||||
|
vec3(1.0, 0.0, 0.0),
|
||||||
|
vec3(0.0, 1.0, 0.0),
|
||||||
|
vec3(0.0, 0.0, 1.0)
|
||||||
|
);
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0);
|
||||||
|
fragColor = colors[gl_VertexIndex];
|
||||||
|
}
|
BIN
shaders/vert.spv
Normal file
BIN
shaders/vert.spv
Normal file
Binary file not shown.
37
src/ShaderLoader.cpp
Normal file
37
src/ShaderLoader.cpp
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
#include "ShaderLoader.h"
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
std::vector<VkShaderModule> ShaderLoader::loadShaders(
|
||||||
|
VkDevice device, QVulkanDeviceFunctions *deviceFunctions,
|
||||||
|
std::string const *shaderFilenames, std::size_t shaderFilenameCount) {
|
||||||
|
loadedShaders.reserve(loadedShaders.size() + shaderFilenameCount);
|
||||||
|
for (int i = 0; i < shaderFilenameCount; ++i) {
|
||||||
|
std::ifstream shaderFile(shaderFilenames[i],
|
||||||
|
std::ios::ate | std::ios::binary);
|
||||||
|
assert(shaderFile.is_open());
|
||||||
|
// std::ios::ate starts at the end of file => position is the file size
|
||||||
|
const std::fpos<mbstate_t> &fileSize = shaderFile.tellg();
|
||||||
|
std::vector<char> buffer(fileSize);
|
||||||
|
shaderFile.seekg(0);
|
||||||
|
shaderFile.read(buffer.data(), fileSize);
|
||||||
|
shaderFile.close();
|
||||||
|
|
||||||
|
VkShaderModuleCreateInfo createInfo{};
|
||||||
|
createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
|
||||||
|
createInfo.codeSize = buffer.size();
|
||||||
|
createInfo.pCode = reinterpret_cast<const uint32_t *>(buffer.data());
|
||||||
|
VkShaderModule shaderModule;
|
||||||
|
VkResult result = deviceFunctions->vkCreateShaderModule(
|
||||||
|
device, &createInfo, nullptr, &shaderModule);
|
||||||
|
assert(result == VK_SUCCESS);
|
||||||
|
loadedShaders.push_back(shaderModule);
|
||||||
|
}
|
||||||
|
return loadedShaders;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShaderLoader::destroyShaders(VkDevice device,
|
||||||
|
QVulkanDeviceFunctions *devFuncs) {
|
||||||
|
for (auto &shaderModule : loadedShaders) {
|
||||||
|
devFuncs->vkDestroyShaderModule(device, shaderModule, nullptr);
|
||||||
|
}
|
||||||
|
}
|
34
src/ShaderLoader.h
Normal file
34
src/ShaderLoader.h
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
#ifndef VULKANCPPSETUP_SHADERLOADER_H
|
||||||
|
#define VULKANCPPSETUP_SHADERLOADER_H
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <qvulkanfunctions.h>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <vulkan/vulkan_core.h>
|
||||||
|
|
||||||
|
class ShaderLoader {
|
||||||
|
private:
|
||||||
|
std::vector<VkShaderModule> loadedShaders;
|
||||||
|
|
||||||
|
public:
|
||||||
|
ShaderLoader() = default;
|
||||||
|
~ShaderLoader() = default;
|
||||||
|
|
||||||
|
std::vector<VkShaderModule>
|
||||||
|
loadShaders(VkDevice device, QVulkanDeviceFunctions *deviceFunctions,
|
||||||
|
std::string const *shaderFilenames,
|
||||||
|
std::size_t shaderFilenameCount);
|
||||||
|
|
||||||
|
template <std::size_t amount>
|
||||||
|
std::vector<VkShaderModule>
|
||||||
|
loadShaders(VkDevice device, QVulkanDeviceFunctions *deviceFunctions,
|
||||||
|
const std::array<std::string, amount> &shaderFilenames) {
|
||||||
|
return loadShaders(device, deviceFunctions, shaderFilenames.data(),
|
||||||
|
shaderFilenames.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroyShaders(VkDevice device, QVulkanDeviceFunctions *devFuncs);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // VULKANCPPSETUP_SHADERLOADER_H
|
|
@ -1,21 +1,109 @@
|
||||||
#include "VulkanRenderer.h"
|
#include "VulkanRenderer.h"
|
||||||
|
#include <complex>
|
||||||
|
|
||||||
VulkanRenderer::VulkanRenderer(QVulkanWindow *w)
|
VulkanRenderer::VulkanRenderer(QVulkanWindow *w)
|
||||||
: m_window(w), m_devFuncs(nullptr) {}
|
: m_window(w), m_devFuncs(nullptr) {}
|
||||||
|
|
||||||
void VulkanRenderer::initResources() {
|
void VulkanRenderer::initResources() {
|
||||||
m_devFuncs =
|
m_devFuncs = m_window->vulkanInstance()->deviceFunctions(m_window->device());
|
||||||
m_window->vulkanInstance()->deviceFunctions(m_window->device());
|
auto shaders =
|
||||||
|
std::array<std::string, 2>{"shaders/vert.spv", "shaders/frag.spv"};
|
||||||
|
auto loadedShaders =
|
||||||
|
m_shaderLoader.loadShaders(m_window->device(), m_devFuncs, shaders);
|
||||||
|
VkPipelineShaderStageCreateInfo vertShaderStageInfo{};
|
||||||
|
vertShaderStageInfo.sType =
|
||||||
|
VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||||
|
vertShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;
|
||||||
|
vertShaderStageInfo.module = loadedShaders[0];
|
||||||
|
vertShaderStageInfo.pName = "main";
|
||||||
|
VkPipelineShaderStageCreateInfo fragShaderStageInfo{};
|
||||||
|
fragShaderStageInfo.sType =
|
||||||
|
VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||||
|
fragShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||||
|
fragShaderStageInfo.module = loadedShaders[1];
|
||||||
|
fragShaderStageInfo.pName = "main";
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanRenderer::initSwapChainResources() {}
|
//void VulkanRenderer::initSwapChainResources() {
|
||||||
void VulkanRenderer::releaseSwapChainResources() {}
|
// qDebug() << "initSwapChainResources";
|
||||||
void VulkanRenderer::releaseResources() {}
|
// 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() {
|
||||||
|
m_shaderLoader.destroyShaders(m_window->device(), m_devFuncs);
|
||||||
|
}
|
||||||
|
|
||||||
void VulkanRenderer::startNextFrame() {
|
void VulkanRenderer::startNextFrame() {
|
||||||
VkCommandBuffer cmdBuf = m_window->currentCommandBuffer();
|
VkCommandBuffer cmdBuf = m_window->currentCommandBuffer();
|
||||||
|
|
||||||
// m_devFuncs->vkCmdBeginRenderPass(…);
|
// make a clear-color from frame number. This will flash with a 120*pi frame
|
||||||
|
// period.
|
||||||
|
VkClearValue clearValue;
|
||||||
|
float flash = std::abs(std::sin(static_cast<float>(m_frameNumber) / 120.f));
|
||||||
|
clearValue.color = {{0.0f, 0.0f, flash, 1.0f}};
|
||||||
|
|
||||||
|
// start the main renderpass.
|
||||||
|
// 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.pNext = nullptr;
|
||||||
|
|
||||||
|
rpInfo.renderPass = m_window->defaultRenderPass();
|
||||||
|
rpInfo.renderArea.offset.x = 0;
|
||||||
|
rpInfo.renderArea.offset.y = 0;
|
||||||
|
rpInfo.renderArea.extent.width = m_window->width();
|
||||||
|
rpInfo.renderArea.extent.height = m_window->height();
|
||||||
|
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;
|
||||||
m_window->frameReady();
|
m_window->frameReady();
|
||||||
|
m_window->requestUpdate();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#ifndef VULKANCPPSETUP_VULKANRENDERER_H
|
#ifndef VULKANCPPSETUP_VULKANRENDERER_H
|
||||||
#define VULKANCPPSETUP_VULKANRENDERER_H
|
#define VULKANCPPSETUP_VULKANRENDERER_H
|
||||||
|
|
||||||
|
#include "ShaderLoader.h"
|
||||||
#include <QVulkanWindowRenderer>
|
#include <QVulkanWindowRenderer>
|
||||||
#include <qvulkanfunctions.h>
|
#include <qvulkanfunctions.h>
|
||||||
|
|
||||||
|
@ -9,8 +10,6 @@ public:
|
||||||
explicit VulkanRenderer(QVulkanWindow *w);
|
explicit VulkanRenderer(QVulkanWindow *w);
|
||||||
|
|
||||||
void initResources() override;
|
void initResources() override;
|
||||||
void initSwapChainResources() override;
|
|
||||||
void releaseSwapChainResources() override;
|
|
||||||
void releaseResources() override;
|
void releaseResources() override;
|
||||||
|
|
||||||
void startNextFrame() override;
|
void startNextFrame() override;
|
||||||
|
@ -18,6 +17,8 @@ public:
|
||||||
private:
|
private:
|
||||||
QVulkanWindow *m_window;
|
QVulkanWindow *m_window;
|
||||||
QVulkanDeviceFunctions *m_devFuncs;
|
QVulkanDeviceFunctions *m_devFuncs;
|
||||||
|
unsigned long m_frameNumber{0UL};
|
||||||
|
ShaderLoader m_shaderLoader;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // VULKANCPPSETUP_VULKANRENDERER_H
|
#endif // VULKANCPPSETUP_VULKANRENDERER_H
|
||||||
|
|
|
@ -8,9 +8,10 @@ int main(int argc, char **argv) {
|
||||||
QVulkanInstance inst;
|
QVulkanInstance inst;
|
||||||
QByteArrayList layers{"VK_LAYER_LUNARG_standard_validation"};
|
QByteArrayList layers{"VK_LAYER_LUNARG_standard_validation"};
|
||||||
inst.setLayers(layers);
|
inst.setLayers(layers);
|
||||||
if (!inst.create())
|
if (!inst.create()) {
|
||||||
|
qFatal("Could not create Vulkan instance %d", inst.errorCode());
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
VulkanWindow window{};
|
VulkanWindow window{};
|
||||||
window.setVulkanInstance(&inst);
|
window.setVulkanInstance(&inst);
|
||||||
window.resize(800, 600);
|
window.resize(800, 600);
|
||||||
|
|
Loading…
Reference in a new issue