Code cleanup, comments

This commit is contained in:
Sascha Willems 2024-01-07 20:39:36 +01:00
parent 06439511e4
commit 1970dcbb0f

View file

@ -1,5 +1,7 @@
/* /*
* Vulkan Example - Using different pipelines in one single renderpass * Vulkan Example - Using different pipelines in a single renderpass
*
* This sample shows how to setup multiple graphics pipelines and how to use them for drawing objects with differring visuals
* *
* Copyright (C) 2016-2023 by Sascha Willems - www.saschawillems.de * Copyright (C) 2016-2023 by Sascha Willems - www.saschawillems.de
* *
@ -14,23 +16,21 @@ class VulkanExample: public VulkanExampleBase
public: public:
vkglTF::Model scene; vkglTF::Model scene;
vks::Buffer uniformBuffer; struct UniformData {
// Same uniform buffer layout as shader
struct UBOVS {
glm::mat4 projection; glm::mat4 projection;
glm::mat4 modelView; glm::mat4 modelView;
glm::vec4 lightPos = glm::vec4(0.0f, 2.0f, 1.0f, 0.0f); glm::vec4 lightPos{ 0.0f, 2.0f, 1.0f, 0.0f };
} uboVS; } uniformData;
vks::Buffer uniformBuffer;
VkPipelineLayout pipelineLayout; VkPipelineLayout pipelineLayout{ VK_NULL_HANDLE };
VkDescriptorSet descriptorSet; VkDescriptorSet descriptorSet{ VK_NULL_HANDLE };
VkDescriptorSetLayout descriptorSetLayout; VkDescriptorSetLayout descriptorSetLayout{ VK_NULL_HANDLE };
struct { struct {
VkPipeline phong; VkPipeline phong{ VK_NULL_HANDLE };
VkPipeline wireframe; VkPipeline wireframe{ VK_NULL_HANDLE };
VkPipeline toon; VkPipeline toon{ VK_NULL_HANDLE };
} pipelines; } pipelines;
VulkanExample() : VulkanExampleBase() VulkanExample() : VulkanExampleBase()
@ -45,19 +45,19 @@ public:
~VulkanExample() ~VulkanExample()
{ {
// Clean up used Vulkan resources if (device) {
// Note : Inherited destructor cleans up resources stored in base class vkDestroyPipeline(device, pipelines.phong, nullptr);
vkDestroyPipeline(device, pipelines.phong, nullptr); if (enabledFeatures.fillModeNonSolid)
if (enabledFeatures.fillModeNonSolid) {
{ vkDestroyPipeline(device, pipelines.wireframe, nullptr);
vkDestroyPipeline(device, pipelines.wireframe, nullptr); }
vkDestroyPipeline(device, pipelines.toon, nullptr);
vkDestroyPipelineLayout(device, pipelineLayout, nullptr);
vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr);
uniformBuffer.destroy();
} }
vkDestroyPipeline(device, pipelines.toon, nullptr);
vkDestroyPipelineLayout(device, pipelineLayout, nullptr);
vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr);
uniformBuffer.destroy();
} }
// Enable physical device features required for this example // Enable physical device features required for this example
@ -93,7 +93,6 @@ public:
for (int32_t i = 0; i < drawCmdBuffers.size(); ++i) for (int32_t i = 0; i < drawCmdBuffers.size(); ++i)
{ {
// Set target frame buffer
renderPassBeginInfo.framebuffer = frameBuffers[i]; renderPassBeginInfo.framebuffer = frameBuffers[i];
VK_CHECK_RESULT(vkBeginCommandBuffer(drawCmdBuffers[i], &cmdBufInfo)); VK_CHECK_RESULT(vkBeginCommandBuffer(drawCmdBuffers[i], &cmdBufInfo));
@ -109,14 +108,14 @@ public:
vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSet, 0, NULL); vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSet, 0, NULL);
scene.bindBuffers(drawCmdBuffers[i]); scene.bindBuffers(drawCmdBuffers[i]);
// Left : Solid colored // Left : Render the scene using the solid colored pipeline with phong shading
viewport.width = (float)width / 3.0f; viewport.width = (float)width / 3.0f;
vkCmdSetViewport(drawCmdBuffers[i], 0, 1, &viewport); vkCmdSetViewport(drawCmdBuffers[i], 0, 1, &viewport);
vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.phong); vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.phong);
vkCmdSetLineWidth(drawCmdBuffers[i], 1.0f); vkCmdSetLineWidth(drawCmdBuffers[i], 1.0f);
scene.draw(drawCmdBuffers[i]); scene.draw(drawCmdBuffers[i]);
// Center : Toon // Center : Render the scene using a toon style pipeline
viewport.x = (float)width / 3.0f; viewport.x = (float)width / 3.0f;
vkCmdSetViewport(drawCmdBuffers[i], 0, 1, &viewport); vkCmdSetViewport(drawCmdBuffers[i], 0, 1, &viewport);
vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.toon); vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.toon);
@ -126,9 +125,8 @@ public:
} }
scene.draw(drawCmdBuffers[i]); scene.draw(drawCmdBuffers[i]);
if (enabledFeatures.fillModeNonSolid) // Right : Render the scene as wireframe (if that feature is supported by the implementation)
{ if (enabledFeatures.fillModeNonSolid) {
// Right : Wireframe
viewport.x = (float)width / 3.0f + (float)width / 3.0f; viewport.x = (float)width / 3.0f + (float)width / 3.0f;
vkCmdSetViewport(drawCmdBuffers[i], 0, 1, &viewport); vkCmdSetViewport(drawCmdBuffers[i], 0, 1, &viewport);
vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.wireframe); vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.wireframe);
@ -149,58 +147,43 @@ public:
scene.loadFromFile(getAssetPath() + "models/treasure_smooth.gltf", vulkanDevice, queue, glTFLoadingFlags); scene.loadFromFile(getAssetPath() + "models/treasure_smooth.gltf", vulkanDevice, queue, glTFLoadingFlags);
} }
void setupDescriptorPool() void setupDescriptors()
{ {
std::vector<VkDescriptorPoolSize> poolSizes = // Pool
{ std::vector<VkDescriptorPoolSize> poolSizes = {
vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1) vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1)
}; };
VkDescriptorPoolCreateInfo descriptorPoolInfo = vks::initializers::descriptorPoolCreateInfo(poolSizes, 2);
VkDescriptorPoolCreateInfo descriptorPoolInfo =
vks::initializers::descriptorPoolCreateInfo(poolSizes, 2);
VK_CHECK_RESULT(vkCreateDescriptorPool(device, &descriptorPoolInfo, nullptr, &descriptorPool)); VK_CHECK_RESULT(vkCreateDescriptorPool(device, &descriptorPoolInfo, nullptr, &descriptorPool));
}
void setupDescriptorSetLayout() // Layout
{ std::vector<VkDescriptorSetLayoutBinding> setLayoutBindings = {
std::vector<VkDescriptorSetLayoutBinding> setLayoutBindings =
{
// Binding 0 : Vertex shader uniform buffer // Binding 0 : Vertex shader uniform buffer
vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_VERTEX_BIT, 0) vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_VERTEX_BIT, 0)
}; };
VkDescriptorSetLayoutCreateInfo descriptorLayout = vks::initializers::descriptorSetLayoutCreateInfo(setLayoutBindings); VkDescriptorSetLayoutCreateInfo descriptorLayout = vks::initializers::descriptorSetLayoutCreateInfo(setLayoutBindings);
VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorLayout, nullptr, &descriptorSetLayout)); VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorLayout, nullptr, &descriptorSetLayout));
VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = vks::initializers::pipelineLayoutCreateInfo(&descriptorSetLayout, 1); // Set
VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCreateInfo, nullptr, &pipelineLayout)); VkDescriptorSetAllocateInfo allocInfo = vks::initializers::descriptorSetAllocateInfo(descriptorPool, &descriptorSetLayout, 1);
}
void setupDescriptorSet()
{
VkDescriptorSetAllocateInfo allocInfo =
vks::initializers::descriptorSetAllocateInfo(
descriptorPool,
&descriptorSetLayout,
1);
VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &descriptorSet)); VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &descriptorSet));
std::vector<VkWriteDescriptorSet> writeDescriptorSets = std::vector<VkWriteDescriptorSet> writeDescriptorSets = {
{
// Binding 0 : Vertex shader uniform buffer // Binding 0 : Vertex shader uniform buffer
vks::initializers::writeDescriptorSet( vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0, &uniformBuffer.descriptor)
descriptorSet,
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
0,
&uniformBuffer.descriptor)
}; };
vkUpdateDescriptorSets(device, static_cast<uint32_t>(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, nullptr); vkUpdateDescriptorSets(device, static_cast<uint32_t>(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, nullptr);
} }
void preparePipelines() void preparePipelines()
{ {
// Layout
VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = vks::initializers::pipelineLayoutCreateInfo(&descriptorSetLayout, 1);
VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCreateInfo, nullptr, &pipelineLayout));
// Pipelines
// Most state is shared between all pipelines
VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = vks::initializers::pipelineInputAssemblyStateCreateInfo(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, 0, VK_FALSE); VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = vks::initializers::pipelineInputAssemblyStateCreateInfo(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, 0, VK_FALSE);
VkPipelineRasterizationStateCreateInfo rasterizationState = vks::initializers::pipelineRasterizationStateCreateInfo(VK_POLYGON_MODE_FILL, VK_CULL_MODE_BACK_BIT, VK_FRONT_FACE_COUNTER_CLOCKWISE, 0); VkPipelineRasterizationStateCreateInfo rasterizationState = vks::initializers::pipelineRasterizationStateCreateInfo(VK_POLYGON_MODE_FILL, VK_CULL_MODE_BACK_BIT, VK_FRONT_FACE_COUNTER_CLOCKWISE, 0);
VkPipelineColorBlendAttachmentState blendAttachmentState = vks::initializers::pipelineColorBlendAttachmentState(0xf, VK_FALSE); VkPipelineColorBlendAttachmentState blendAttachmentState = vks::initializers::pipelineColorBlendAttachmentState(0xf, VK_FALSE);
@ -224,7 +207,7 @@ public:
pipelineCI.pStages = shaderStages.data(); pipelineCI.pStages = shaderStages.data();
pipelineCI.pVertexInputState = vkglTF::Vertex::getPipelineVertexInputState({vkglTF::VertexComponent::Position, vkglTF::VertexComponent::Normal, vkglTF::VertexComponent::Color}); pipelineCI.pVertexInputState = vkglTF::Vertex::getPipelineVertexInputState({vkglTF::VertexComponent::Position, vkglTF::VertexComponent::Normal, vkglTF::VertexComponent::Color});
// Create the graphics pipeline state objects // Create the different pipelines used in this sample
// We are using this pipeline as the base for the other pipelines (derivatives) // We are using this pipeline as the base for the other pipelines (derivatives)
// Pipeline derivatives can be used for pipelines that share most of their state // Pipeline derivatives can be used for pipelines that share most of their state
@ -253,8 +236,7 @@ public:
// Pipeline for wire frame rendering // Pipeline for wire frame rendering
// Non solid rendering is not a mandatory Vulkan feature // Non solid rendering is not a mandatory Vulkan feature
if (enabledFeatures.fillModeNonSolid) if (enabledFeatures.fillModeNonSolid) {
{
rasterizationState.polygonMode = VK_POLYGON_MODE_LINE; rasterizationState.polygonMode = VK_POLYGON_MODE_LINE;
shaderStages[0] = loadShader(getShadersPath() + "pipelines/wireframe.vert.spv", VK_SHADER_STAGE_VERTEX_BIT); shaderStages[0] = loadShader(getShadersPath() + "pipelines/wireframe.vert.spv", VK_SHADER_STAGE_VERTEX_BIT);
shaderStages[1] = loadShader(getShadersPath() + "pipelines/wireframe.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT); shaderStages[1] = loadShader(getShadersPath() + "pipelines/wireframe.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT);
@ -266,34 +248,16 @@ public:
void prepareUniformBuffers() void prepareUniformBuffers()
{ {
// Create the vertex shader uniform buffer block // Create the vertex shader uniform buffer block
VK_CHECK_RESULT(vulkanDevice->createBuffer( VK_CHECK_RESULT(vulkanDevice->createBuffer(VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &uniformBuffer, sizeof(UniformData)));
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
&uniformBuffer,
sizeof(uboVS)));
// Map persistent // Map persistent
VK_CHECK_RESULT(uniformBuffer.map()); VK_CHECK_RESULT(uniformBuffer.map());
updateUniformBuffers();
} }
void updateUniformBuffers() void updateUniformBuffers()
{ {
uboVS.projection = camera.matrices.perspective; uniformData.projection = camera.matrices.perspective;
uboVS.modelView = camera.matrices.view; uniformData.modelView = camera.matrices.view;
memcpy(uniformBuffer.mapped, &uboVS, sizeof(uboVS)); memcpy(uniformBuffer.mapped, &uniformData, sizeof(UniformData));
}
void draw()
{
VulkanExampleBase::prepareFrame();
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &drawCmdBuffers[currentBuffer];
VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE));
VulkanExampleBase::submitFrame();
} }
void prepare() void prepare()
@ -301,28 +265,29 @@ public:
VulkanExampleBase::prepare(); VulkanExampleBase::prepare();
loadAssets(); loadAssets();
prepareUniformBuffers(); prepareUniformBuffers();
setupDescriptorSetLayout(); setupDescriptors();
preparePipelines(); preparePipelines();
setupDescriptorPool();
setupDescriptorSet();
buildCommandBuffers(); buildCommandBuffers();
prepared = true; prepared = true;
} }
void draw()
{
VulkanExampleBase::prepareFrame();
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &drawCmdBuffers[currentBuffer];
VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE));
VulkanExampleBase::submitFrame();
}
virtual void render() virtual void render()
{ {
if (!prepared) if (!prepared)
return; return;
draw(); // Override the base sample camera setup, since we use three viewports
if (camera.updated) {
updateUniformBuffers();
}
}
virtual void viewChanged()
{
camera.setPerspective(60.0f, (float)(width / 3.0f) / (float)height, 0.1f, 256.0f); camera.setPerspective(60.0f, (float)(width / 3.0f) / (float)height, 0.1f, 256.0f);
updateUniformBuffers(); updateUniformBuffers();
draw();
} }
virtual void OnUpdateUIOverlay(vks::UIOverlay *overlay) virtual void OnUpdateUIOverlay(vks::UIOverlay *overlay)