Replace dedicated offscreen command buffer and complicated synchronization with single command buffer and sync via sub pass dependencies

Code cleanup
This commit is contained in:
Sascha Willems 2019-04-01 20:22:28 +02:00
parent 84b1c30714
commit b1c2529032

View file

@ -22,7 +22,6 @@
#include "VulkanBuffer.hpp" #include "VulkanBuffer.hpp"
#include "VulkanModel.hpp" #include "VulkanModel.hpp"
#define VERTEX_BUFFER_BIND_ID 0
#define ENABLE_VALIDATION false #define ENABLE_VALIDATION false
// 16 bits of depth is enough for such a small scene // 16 bits of depth is enough for such a small scene
@ -75,12 +74,6 @@ public:
std::vector<std::string> sceneNames; std::vector<std::string> sceneNames;
int32_t sceneIndex = 0; int32_t sceneIndex = 0;
struct {
VkPipelineVertexInputStateCreateInfo inputState;
std::vector<VkVertexInputBindingDescription> bindingDescriptions;
std::vector<VkVertexInputAttributeDescription> attributeDescriptions;
} vertices;
struct { struct {
vks::Buffer scene; vks::Buffer scene;
vks::Buffer offscreen; vks::Buffer offscreen;
@ -137,9 +130,6 @@ public:
VkRenderPass renderPass; VkRenderPass renderPass;
VkSampler depthSampler; VkSampler depthSampler;
VkDescriptorImageInfo descriptor; VkDescriptorImageInfo descriptor;
VkCommandBuffer commandBuffer = VK_NULL_HANDLE;
// Semaphore used to synchronize between offscreen and final scene render pass
VkSemaphore semaphore = VK_NULL_HANDLE;
} offscreenPass; } offscreenPass;
VulkanExample() : VulkanExampleBase(ENABLE_VALIDATION) VulkanExample() : VulkanExampleBase(ENABLE_VALIDATION)
@ -188,9 +178,6 @@ public:
uniformBuffers.offscreen.destroy(); uniformBuffers.offscreen.destroy();
uniformBuffers.scene.destroy(); uniformBuffers.scene.destroy();
uniformBuffers.debug.destroy(); uniformBuffers.debug.destroy();
vkFreeCommandBuffers(device, cmdPool, 1, &offscreenPass.commandBuffer);
vkDestroySemaphore(device, offscreenPass.semaphore, nullptr);
} }
// Set up a separate render pass for the offscreen frame buffer // Set up a separate render pass for the offscreen frame buffer
@ -221,17 +208,17 @@ public:
dependencies[0].srcSubpass = VK_SUBPASS_EXTERNAL; dependencies[0].srcSubpass = VK_SUBPASS_EXTERNAL;
dependencies[0].dstSubpass = 0; dependencies[0].dstSubpass = 0;
dependencies[0].srcStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; dependencies[0].srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
dependencies[0].dstStageMask = VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; dependencies[0].dstStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
dependencies[0].srcAccessMask = 0; dependencies[0].srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
dependencies[0].dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; dependencies[0].dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
dependencies[0].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT; dependencies[0].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
dependencies[1].srcSubpass = 0; dependencies[1].srcSubpass = 0;
dependencies[1].dstSubpass = VK_SUBPASS_EXTERNAL; dependencies[1].dstSubpass = VK_SUBPASS_EXTERNAL;
dependencies[1].srcStageMask = VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; dependencies[1].srcStageMask = VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
dependencies[1].dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; dependencies[1].dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
dependencies[1].srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; dependencies[1].srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
dependencies[1].dstAccessMask = VK_ACCESS_SHADER_READ_BIT; dependencies[1].dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
dependencies[1].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT; dependencies[1].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
@ -319,104 +306,92 @@ public:
VK_CHECK_RESULT(vkCreateFramebuffer(device, &fbufCreateInfo, nullptr, &offscreenPass.frameBuffer)); VK_CHECK_RESULT(vkCreateFramebuffer(device, &fbufCreateInfo, nullptr, &offscreenPass.frameBuffer));
} }
void buildOffscreenCommandBuffer()
{
if (offscreenPass.commandBuffer == VK_NULL_HANDLE)
{
offscreenPass.commandBuffer = VulkanExampleBase::createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, false);
}
if (offscreenPass.semaphore == VK_NULL_HANDLE)
{
// Create a semaphore used to synchronize offscreen rendering and usage
VkSemaphoreCreateInfo semaphoreCreateInfo = vks::initializers::semaphoreCreateInfo();
VK_CHECK_RESULT(vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &offscreenPass.semaphore));
}
VkCommandBufferBeginInfo cmdBufInfo = vks::initializers::commandBufferBeginInfo();
VkClearValue clearValues[1];
clearValues[0].depthStencil = { 1.0f, 0 };
VkRenderPassBeginInfo renderPassBeginInfo = vks::initializers::renderPassBeginInfo();
renderPassBeginInfo.renderPass = offscreenPass.renderPass;
renderPassBeginInfo.framebuffer = offscreenPass.frameBuffer;
renderPassBeginInfo.renderArea.offset.x = 0;
renderPassBeginInfo.renderArea.offset.y = 0;
renderPassBeginInfo.renderArea.extent.width = offscreenPass.width;
renderPassBeginInfo.renderArea.extent.height = offscreenPass.height;
renderPassBeginInfo.clearValueCount = 2;
renderPassBeginInfo.pClearValues = clearValues;
VK_CHECK_RESULT(vkBeginCommandBuffer(offscreenPass.commandBuffer, &cmdBufInfo));
VkViewport viewport = vks::initializers::viewport((float)offscreenPass.width, (float)offscreenPass.height, 0.0f, 1.0f);
vkCmdSetViewport(offscreenPass.commandBuffer, 0, 1, &viewport);
VkRect2D scissor = vks::initializers::rect2D(offscreenPass.width, offscreenPass.height, 0, 0);
vkCmdSetScissor(offscreenPass.commandBuffer, 0, 1, &scissor);
// Set depth bias (aka "Polygon offset")
// Required to avoid shadow mapping artefacts
vkCmdSetDepthBias(
offscreenPass.commandBuffer,
depthBiasConstant,
0.0f,
depthBiasSlope);
vkCmdBeginRenderPass(offscreenPass.commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
vkCmdBindPipeline(offscreenPass.commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.offscreen);
vkCmdBindDescriptorSets(offscreenPass.commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayouts.offscreen, 0, 1, &descriptorSets.offscreen, 0, NULL);
VkDeviceSize offsets[1] = { 0 };
vkCmdBindVertexBuffers(offscreenPass.commandBuffer, VERTEX_BUFFER_BIND_ID, 1, &scenes[sceneIndex].vertices.buffer, offsets);
vkCmdBindIndexBuffer(offscreenPass.commandBuffer, scenes[sceneIndex].indices.buffer, 0, VK_INDEX_TYPE_UINT32);
vkCmdDrawIndexed(offscreenPass.commandBuffer, scenes[sceneIndex].indexCount, 1, 0, 0, 0);
vkCmdEndRenderPass(offscreenPass.commandBuffer);
VK_CHECK_RESULT(vkEndCommandBuffer(offscreenPass.commandBuffer));
}
void buildCommandBuffers() void buildCommandBuffers()
{ {
VkCommandBufferBeginInfo cmdBufInfo = vks::initializers::commandBufferBeginInfo(); VkCommandBufferBeginInfo cmdBufInfo = vks::initializers::commandBufferBeginInfo();
VkClearValue clearValues[2]; VkClearValue clearValues[2];
VkViewport viewport;
VkRect2D scissor;
VkDeviceSize offsets[1] = { 0 };
for (int32_t i = 0; i < drawCmdBuffers.size(); ++i)
{
VK_CHECK_RESULT(vkBeginCommandBuffer(drawCmdBuffers[i], &cmdBufInfo));
/*
First render pass: Generate shadow map by rendering the scene from light's POV
*/
{
clearValues[0].depthStencil = { 1.0f, 0 };
VkRenderPassBeginInfo renderPassBeginInfo = vks::initializers::renderPassBeginInfo();
renderPassBeginInfo.renderPass = offscreenPass.renderPass;
renderPassBeginInfo.framebuffer = offscreenPass.frameBuffer;
renderPassBeginInfo.renderArea.extent.width = offscreenPass.width;
renderPassBeginInfo.renderArea.extent.height = offscreenPass.height;
renderPassBeginInfo.clearValueCount = 1;
renderPassBeginInfo.pClearValues = clearValues;
vkCmdBeginRenderPass(drawCmdBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
viewport = vks::initializers::viewport((float)offscreenPass.width, (float)offscreenPass.height, 0.0f, 1.0f);
vkCmdSetViewport(drawCmdBuffers[i], 0, 1, &viewport);
scissor = vks::initializers::rect2D(offscreenPass.width, offscreenPass.height, 0, 0);
vkCmdSetScissor(drawCmdBuffers[i], 0, 1, &scissor);
// Set depth bias (aka "Polygon offset")
// Required to avoid shadow mapping artefacts
vkCmdSetDepthBias(
drawCmdBuffers[i],
depthBiasConstant,
0.0f,
depthBiasSlope);
vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.offscreen);
vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayouts.offscreen, 0, 1, &descriptorSets.offscreen, 0, NULL);
vkCmdBindVertexBuffers(drawCmdBuffers[i], 0, 1, &scenes[sceneIndex].vertices.buffer, offsets);
vkCmdBindIndexBuffer(drawCmdBuffers[i], scenes[sceneIndex].indices.buffer, 0, VK_INDEX_TYPE_UINT32);
vkCmdDrawIndexed(drawCmdBuffers[i], scenes[sceneIndex].indexCount, 1, 0, 0, 0);
vkCmdEndRenderPass(drawCmdBuffers[i]);
}
/*
Note: Explicit synchronization is not required between the render pass, as this is done implicit via sub pass dependencies
*/
/*
Second pass: Scene rendering with applied shadow map
*/
{
clearValues[0].color = defaultClearColor; clearValues[0].color = defaultClearColor;
clearValues[1].depthStencil = { 1.0f, 0 }; clearValues[1].depthStencil = { 1.0f, 0 };
VkRenderPassBeginInfo renderPassBeginInfo = vks::initializers::renderPassBeginInfo(); VkRenderPassBeginInfo renderPassBeginInfo = vks::initializers::renderPassBeginInfo();
renderPassBeginInfo.renderPass = renderPass; renderPassBeginInfo.renderPass = renderPass;
renderPassBeginInfo.renderArea.offset.x = 0; renderPassBeginInfo.framebuffer = frameBuffers[i];
renderPassBeginInfo.renderArea.offset.y = 0;
renderPassBeginInfo.renderArea.extent.width = width; renderPassBeginInfo.renderArea.extent.width = width;
renderPassBeginInfo.renderArea.extent.height = height; renderPassBeginInfo.renderArea.extent.height = height;
renderPassBeginInfo.clearValueCount = 2; renderPassBeginInfo.clearValueCount = 2;
renderPassBeginInfo.pClearValues = clearValues; renderPassBeginInfo.pClearValues = clearValues;
for (int32_t i = 0; i < drawCmdBuffers.size(); ++i)
{
// Set target frame buffer
renderPassBeginInfo.framebuffer = frameBuffers[i];
VK_CHECK_RESULT(vkBeginCommandBuffer(drawCmdBuffers[i], &cmdBufInfo));
vkCmdBeginRenderPass(drawCmdBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); vkCmdBeginRenderPass(drawCmdBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
VkViewport viewport = vks::initializers::viewport((float)width, (float)height, 0.0f, 1.0f); viewport = vks::initializers::viewport((float)width, (float)height, 0.0f, 1.0f);
vkCmdSetViewport(drawCmdBuffers[i], 0, 1, &viewport); vkCmdSetViewport(drawCmdBuffers[i], 0, 1, &viewport);
VkRect2D scissor = vks::initializers::rect2D(width, height, 0, 0); scissor = vks::initializers::rect2D(width, height, 0, 0);
vkCmdSetScissor(drawCmdBuffers[i], 0, 1, &scissor); vkCmdSetScissor(drawCmdBuffers[i], 0, 1, &scissor);
VkDeviceSize offsets[1] = { 0 };
// Visualize shadow map // Visualize shadow map
if (displayShadowMap) { if (displayShadowMap) {
vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayouts.quad, 0, 1, &descriptorSet, 0, NULL); vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayouts.quad, 0, 1, &descriptorSet, 0, NULL);
vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.quad); vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.quad);
vkCmdBindVertexBuffers(drawCmdBuffers[i], VERTEX_BUFFER_BIND_ID, 1, &models.quad.vertices.buffer, offsets); vkCmdBindVertexBuffers(drawCmdBuffers[i], 0, 1, &models.quad.vertices.buffer, offsets);
vkCmdBindIndexBuffer(drawCmdBuffers[i], models.quad.indices.buffer, 0, VK_INDEX_TYPE_UINT32); vkCmdBindIndexBuffer(drawCmdBuffers[i], models.quad.indices.buffer, 0, VK_INDEX_TYPE_UINT32);
vkCmdDrawIndexed(drawCmdBuffers[i], models.quad.indexCount, 1, 0, 0, 0); vkCmdDrawIndexed(drawCmdBuffers[i], models.quad.indexCount, 1, 0, 0, 0);
} }
@ -425,13 +400,14 @@ public:
vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayouts.quad, 0, 1, &descriptorSets.scene, 0, NULL); vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayouts.quad, 0, 1, &descriptorSets.scene, 0, NULL);
vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, (filterPCF) ? pipelines.sceneShadowPCF : pipelines.sceneShadow); vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, (filterPCF) ? pipelines.sceneShadowPCF : pipelines.sceneShadow);
vkCmdBindVertexBuffers(drawCmdBuffers[i], VERTEX_BUFFER_BIND_ID, 1, &scenes[sceneIndex].vertices.buffer, offsets); vkCmdBindVertexBuffers(drawCmdBuffers[i], 0, 1, &scenes[sceneIndex].vertices.buffer, offsets);
vkCmdBindIndexBuffer(drawCmdBuffers[i], scenes[sceneIndex].indices.buffer, 0, VK_INDEX_TYPE_UINT32); vkCmdBindIndexBuffer(drawCmdBuffers[i], scenes[sceneIndex].indices.buffer, 0, VK_INDEX_TYPE_UINT32);
vkCmdDrawIndexed(drawCmdBuffers[i], scenes[sceneIndex].indexCount, 1, 0, 0, 0); vkCmdDrawIndexed(drawCmdBuffers[i], scenes[sceneIndex].indexCount, 1, 0, 0, 0);
drawUI(drawCmdBuffers[i]); drawUI(drawCmdBuffers[i]);
vkCmdEndRenderPass(drawCmdBuffers[i]); vkCmdEndRenderPass(drawCmdBuffers[i]);
}
VK_CHECK_RESULT(vkEndCommandBuffer(drawCmdBuffers[i])); VK_CHECK_RESULT(vkEndCommandBuffer(drawCmdBuffers[i]));
} }
@ -488,59 +464,10 @@ public:
models.quad.device = device; models.quad.device = device;
} }
void setupVertexDescriptions()
{
// Binding description
vertices.bindingDescriptions.resize(1);
vertices.bindingDescriptions[0] =
vks::initializers::vertexInputBindingDescription(
VERTEX_BUFFER_BIND_ID,
vertexLayout.stride(),
VK_VERTEX_INPUT_RATE_VERTEX);
// Attribute descriptions
vertices.attributeDescriptions.resize(4);
// Location 0 : Position
vertices.attributeDescriptions[0] =
vks::initializers::vertexInputAttributeDescription(
VERTEX_BUFFER_BIND_ID,
0,
VK_FORMAT_R32G32B32_SFLOAT,
0);
// Location 1 : Texture coordinates
vertices.attributeDescriptions[1] =
vks::initializers::vertexInputAttributeDescription(
VERTEX_BUFFER_BIND_ID,
1,
VK_FORMAT_R32G32_SFLOAT,
sizeof(float) * 3);
// Location 2 : Color
vertices.attributeDescriptions[2] =
vks::initializers::vertexInputAttributeDescription(
VERTEX_BUFFER_BIND_ID,
2,
VK_FORMAT_R32G32B32_SFLOAT,
sizeof(float) * 5);
// Location 3 : Normal
vertices.attributeDescriptions[3] =
vks::initializers::vertexInputAttributeDescription(
VERTEX_BUFFER_BIND_ID,
3,
VK_FORMAT_R32G32B32_SFLOAT,
sizeof(float) * 8);
vertices.inputState = vks::initializers::pipelineVertexInputStateCreateInfo();
vertices.inputState.vertexBindingDescriptionCount = vertices.bindingDescriptions.size();
vertices.inputState.pVertexBindingDescriptions = vertices.bindingDescriptions.data();
vertices.inputState.vertexAttributeDescriptionCount = vertices.attributeDescriptions.size();
vertices.inputState.pVertexAttributeDescriptions = vertices.attributeDescriptions.data();
}
void setupDescriptorPool() void setupDescriptorPool()
{ {
// Example uses three ubos and two image samplers // Example uses three ubos and two image samplers
std::vector<VkDescriptorPoolSize> poolSizes = std::vector<VkDescriptorPoolSize> poolSizes = {
{
vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 6), vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 6),
vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 4) vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 4)
}; };
@ -557,32 +484,23 @@ public:
void setupDescriptorSetLayout() void setupDescriptorSetLayout()
{ {
// Textured quad pipeline layout // Textured quad pipeline layout
std::vector<VkDescriptorSetLayoutBinding> setLayoutBindings = std::vector<VkDescriptorSetLayoutBinding> setLayoutBindings = {
{
// Binding 0 : Vertex shader uniform buffer // Binding 0 : Vertex shader uniform buffer
vks::initializers::descriptorSetLayoutBinding( vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_VERTEX_BIT, 0),
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
VK_SHADER_STAGE_VERTEX_BIT,
0),
// Binding 1 : Fragment shader image sampler // Binding 1 : Fragment shader image sampler
vks::initializers::descriptorSetLayoutBinding( vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT, 1)
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
VK_SHADER_STAGE_FRAGMENT_BIT,
1)
}; };
VkDescriptorSetLayoutCreateInfo descriptorLayout = VkDescriptorSetLayoutCreateInfo descriptorLayout =
vks::initializers::descriptorSetLayoutCreateInfo( vks::initializers::descriptorSetLayoutCreateInfo(
setLayoutBindings.data(), setLayoutBindings.data(),
setLayoutBindings.size()); setLayoutBindings.size());
VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorLayout, nullptr, &descriptorSetLayout)); VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorLayout, nullptr, &descriptorSetLayout));
VkPipelineLayoutCreateInfo pPipelineLayoutCreateInfo = VkPipelineLayoutCreateInfo pPipelineLayoutCreateInfo =
vks::initializers::pipelineLayoutCreateInfo( vks::initializers::pipelineLayoutCreateInfo(
&descriptorSetLayout, &descriptorSetLayout,
1); 1);
VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pPipelineLayoutCreateInfo, nullptr, &pipelineLayouts.quad)); VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pPipelineLayoutCreateInfo, nullptr, &pipelineLayouts.quad));
// Offscreen pipeline layout // Offscreen pipeline layout
@ -611,19 +529,10 @@ public:
writeDescriptorSets = { 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, &uniformBuffers.debug.descriptor),
descriptorSet,
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
0,
&uniformBuffers.debug.descriptor),
// Binding 1 : Fragment shader texture sampler // Binding 1 : Fragment shader texture sampler
vks::initializers::writeDescriptorSet( vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, &texDescriptor)
descriptorSet,
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
1,
&texDescriptor)
}; };
vkUpdateDescriptorSets(device, writeDescriptorSets.size(), writeDescriptorSets.data(), 0, NULL); vkUpdateDescriptorSets(device, writeDescriptorSets.size(), writeDescriptorSets.data(), 0, NULL);
// Offscreen // Offscreen
@ -631,11 +540,7 @@ public:
writeDescriptorSets = { writeDescriptorSets = {
// Binding 0 : Vertex shader uniform buffer // Binding 0 : Vertex shader uniform buffer
vks::initializers::writeDescriptorSet( vks::initializers::writeDescriptorSet(descriptorSets.offscreen, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0, &uniformBuffers.offscreen.descriptor),
descriptorSets.offscreen,
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
0,
&uniformBuffers.offscreen.descriptor),
}; };
vkUpdateDescriptorSets(device, writeDescriptorSets.size(), writeDescriptorSets.data(), 0, NULL); vkUpdateDescriptorSets(device, writeDescriptorSets.size(), writeDescriptorSets.data(), 0, NULL);
@ -648,102 +553,66 @@ public:
writeDescriptorSets = { writeDescriptorSets = {
// Binding 0 : Vertex shader uniform buffer // Binding 0 : Vertex shader uniform buffer
vks::initializers::writeDescriptorSet( vks::initializers::writeDescriptorSet(descriptorSets.scene, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0, &uniformBuffers.scene.descriptor),
descriptorSets.scene,
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
0,
&uniformBuffers.scene.descriptor),
// Binding 1 : Fragment shader shadow sampler // Binding 1 : Fragment shader shadow sampler
vks::initializers::writeDescriptorSet( vks::initializers::writeDescriptorSet(descriptorSets.scene, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, &texDescriptor)
descriptorSets.scene,
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
1,
&texDescriptor)
}; };
vkUpdateDescriptorSets(device, writeDescriptorSets.size(), writeDescriptorSets.data(), 0, NULL); vkUpdateDescriptorSets(device, writeDescriptorSets.size(), writeDescriptorSets.data(), 0, NULL);
} }
void preparePipelines() void preparePipelines()
{ {
VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCI = vks::initializers::pipelineInputAssemblyStateCreateInfo(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, 0, VK_FALSE);
vks::initializers::pipelineInputAssemblyStateCreateInfo( VkPipelineRasterizationStateCreateInfo rasterizationStateCI = vks::initializers::pipelineRasterizationStateCreateInfo(VK_POLYGON_MODE_FILL, VK_CULL_MODE_BACK_BIT, VK_FRONT_FACE_CLOCKWISE, 0);
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, VkPipelineColorBlendAttachmentState blendAttachmentState = vks::initializers::pipelineColorBlendAttachmentState(0xf, VK_FALSE);
0, VkPipelineColorBlendStateCreateInfo colorBlendStateCI = vks::initializers::pipelineColorBlendStateCreateInfo(1, &blendAttachmentState);
VK_FALSE); VkPipelineDepthStencilStateCreateInfo depthStencilStateCI = vks::initializers::pipelineDepthStencilStateCreateInfo(VK_TRUE, VK_TRUE, VK_COMPARE_OP_LESS_OR_EQUAL);
VkPipelineViewportStateCreateInfo viewportStateCI = vks::initializers::pipelineViewportStateCreateInfo(1, 1, 0);
VkPipelineRasterizationStateCreateInfo rasterizationState = VkPipelineMultisampleStateCreateInfo multisampleStateCI = vks::initializers::pipelineMultisampleStateCreateInfo(VK_SAMPLE_COUNT_1_BIT, 0);
vks::initializers::pipelineRasterizationStateCreateInfo( std::vector<VkDynamicState> dynamicStateEnables = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR };
VK_POLYGON_MODE_FILL, VkPipelineDynamicStateCreateInfo dynamicStateCI = vks::initializers::pipelineDynamicStateCreateInfo(dynamicStateEnables.data(), dynamicStateEnables.size(), 0);
VK_CULL_MODE_BACK_BIT,
VK_FRONT_FACE_CLOCKWISE,
0);
VkPipelineColorBlendAttachmentState blendAttachmentState =
vks::initializers::pipelineColorBlendAttachmentState(
0xf,
VK_FALSE);
VkPipelineColorBlendStateCreateInfo colorBlendState =
vks::initializers::pipelineColorBlendStateCreateInfo(
1,
&blendAttachmentState);
VkPipelineDepthStencilStateCreateInfo depthStencilState =
vks::initializers::pipelineDepthStencilStateCreateInfo(
VK_TRUE,
VK_TRUE,
VK_COMPARE_OP_LESS_OR_EQUAL);
VkPipelineViewportStateCreateInfo viewportState =
vks::initializers::pipelineViewportStateCreateInfo(1, 1, 0);
VkPipelineMultisampleStateCreateInfo multisampleState =
vks::initializers::pipelineMultisampleStateCreateInfo(
VK_SAMPLE_COUNT_1_BIT,
0);
std::vector<VkDynamicState> dynamicStateEnables = {
VK_DYNAMIC_STATE_VIEWPORT,
VK_DYNAMIC_STATE_SCISSOR
};
VkPipelineDynamicStateCreateInfo dynamicState =
vks::initializers::pipelineDynamicStateCreateInfo(
dynamicStateEnables.data(),
dynamicStateEnables.size(),
0);
std::array<VkPipelineShaderStageCreateInfo, 2> shaderStages; std::array<VkPipelineShaderStageCreateInfo, 2> shaderStages;
VkGraphicsPipelineCreateInfo pipelineCreateInfo = VkGraphicsPipelineCreateInfo pipelineCI = vks::initializers::pipelineCreateInfo(pipelineLayouts.quad, renderPass, 0);
vks::initializers::pipelineCreateInfo(
pipelineLayouts.quad,
renderPass,
0);
pipelineCreateInfo.pInputAssemblyState = &inputAssemblyState; pipelineCI.pInputAssemblyState = &inputAssemblyStateCI;
pipelineCreateInfo.pRasterizationState = &rasterizationState; pipelineCI.pRasterizationState = &rasterizationStateCI;
pipelineCreateInfo.pColorBlendState = &colorBlendState; pipelineCI.pColorBlendState = &colorBlendStateCI;
pipelineCreateInfo.pMultisampleState = &multisampleState; pipelineCI.pMultisampleState = &multisampleStateCI;
pipelineCreateInfo.pViewportState = &viewportState; pipelineCI.pViewportState = &viewportStateCI;
pipelineCreateInfo.pDepthStencilState = &depthStencilState; pipelineCI.pDepthStencilState = &depthStencilStateCI;
pipelineCreateInfo.pDynamicState = &dynamicState; pipelineCI.pDynamicState = &dynamicStateCI;
pipelineCreateInfo.stageCount = shaderStages.size(); pipelineCI.stageCount = shaderStages.size();
pipelineCreateInfo.pStages = shaderStages.data(); pipelineCI.pStages = shaderStages.data();
// Shadow mapping debug quad display // Shadow mapping debug quad display
rasterizationState.cullMode = VK_CULL_MODE_NONE; rasterizationStateCI.cullMode = VK_CULL_MODE_NONE;
shaderStages[0] = loadShader(getAssetPath() + "shaders/shadowmapping/quad.vert.spv", VK_SHADER_STAGE_VERTEX_BIT); shaderStages[0] = loadShader(getAssetPath() + "shaders/shadowmapping/quad.vert.spv", VK_SHADER_STAGE_VERTEX_BIT);
shaderStages[1] = loadShader(getAssetPath() + "shaders/shadowmapping/quad.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT); shaderStages[1] = loadShader(getAssetPath() + "shaders/shadowmapping/quad.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT);
// Empty vertex input state // Empty vertex input state
VkPipelineVertexInputStateCreateInfo emptyInputState = vks::initializers::pipelineVertexInputStateCreateInfo(); VkPipelineVertexInputStateCreateInfo emptyInputState = vks::initializers::pipelineVertexInputStateCreateInfo();
pipelineCreateInfo.pVertexInputState = &emptyInputState; pipelineCI.pVertexInputState = &emptyInputState;
VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipelines.quad)); VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &pipelines.quad));
pipelineCreateInfo.pVertexInputState = &vertices.inputState; // Vertex bindings and attributes
std::vector<VkVertexInputBindingDescription> vertexInputBindings = {
vks::initializers::vertexInputBindingDescription(0, vertexLayout.stride(), VK_VERTEX_INPUT_RATE_VERTEX),
};
std::vector<VkVertexInputAttributeDescription> vertexInputAttributes = {
vks::initializers::vertexInputAttributeDescription(0, 0, VK_FORMAT_R32G32B32_SFLOAT, 0), // Position
vks::initializers::vertexInputAttributeDescription(0, 1, VK_FORMAT_R32G32_SFLOAT, sizeof(float) * 3), // Texture coordinates
vks::initializers::vertexInputAttributeDescription(0, 2, VK_FORMAT_R32G32B32_SFLOAT, sizeof(float) * 5), // Color
vks::initializers::vertexInputAttributeDescription(0, 3, VK_FORMAT_R32G32B32_SFLOAT, sizeof(float) * 8), // Normal
};
VkPipelineVertexInputStateCreateInfo vertexInputState = vks::initializers::pipelineVertexInputStateCreateInfo();
vertexInputState.vertexBindingDescriptionCount = static_cast<uint32_t>(vertexInputBindings.size());
vertexInputState.pVertexBindingDescriptions = vertexInputBindings.data();
vertexInputState.vertexAttributeDescriptionCount = static_cast<uint32_t>(vertexInputAttributes.size());
vertexInputState.pVertexAttributeDescriptions = vertexInputAttributes.data();
pipelineCI.pVertexInputState = &vertexInputState;
// Scene rendering with shadows applied // Scene rendering with shadows applied
rasterizationState.cullMode = VK_CULL_MODE_BACK_BIT; rasterizationStateCI.cullMode = VK_CULL_MODE_BACK_BIT;
shaderStages[0] = loadShader(getAssetPath() + "shaders/shadowmapping/scene.vert.spv", VK_SHADER_STAGE_VERTEX_BIT); shaderStages[0] = loadShader(getAssetPath() + "shaders/shadowmapping/scene.vert.spv", VK_SHADER_STAGE_VERTEX_BIT);
shaderStages[1] = loadShader(getAssetPath() + "shaders/shadowmapping/scene.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT); shaderStages[1] = loadShader(getAssetPath() + "shaders/shadowmapping/scene.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT);
// Use specialization constants to select between horizontal and vertical blur // Use specialization constants to select between horizontal and vertical blur
@ -752,31 +621,31 @@ public:
VkSpecializationInfo specializationInfo = vks::initializers::specializationInfo(1, &specializationMapEntry, sizeof(uint32_t), &enablePCF); VkSpecializationInfo specializationInfo = vks::initializers::specializationInfo(1, &specializationMapEntry, sizeof(uint32_t), &enablePCF);
shaderStages[1].pSpecializationInfo = &specializationInfo; shaderStages[1].pSpecializationInfo = &specializationInfo;
// No filtering // No filtering
VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipelines.sceneShadow)); VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &pipelines.sceneShadow));
// PCF filtering // PCF filtering
enablePCF = 1; enablePCF = 1;
VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipelines.sceneShadowPCF)); VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &pipelines.sceneShadowPCF));
// Offscreen pipeline (vertex shader only) // Offscreen pipeline (vertex shader only)
shaderStages[0] = loadShader(getAssetPath() + "shaders/shadowmapping/offscreen.vert.spv", VK_SHADER_STAGE_VERTEX_BIT); shaderStages[0] = loadShader(getAssetPath() + "shaders/shadowmapping/offscreen.vert.spv", VK_SHADER_STAGE_VERTEX_BIT);
pipelineCreateInfo.stageCount = 1; pipelineCI.stageCount = 1;
// No blend attachment states (no color attachments used) // No blend attachment states (no color attachments used)
colorBlendState.attachmentCount = 0; colorBlendStateCI.attachmentCount = 0;
// Cull front faces // Cull front faces
depthStencilState.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL; depthStencilStateCI.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL;
// Enable depth bias // Enable depth bias
rasterizationState.depthBiasEnable = VK_TRUE; rasterizationStateCI.depthBiasEnable = VK_TRUE;
// Add depth bias to dynamic state, so we can change it at runtime // Add depth bias to dynamic state, so we can change it at runtime
dynamicStateEnables.push_back(VK_DYNAMIC_STATE_DEPTH_BIAS); dynamicStateEnables.push_back(VK_DYNAMIC_STATE_DEPTH_BIAS);
dynamicState = dynamicStateCI =
vks::initializers::pipelineDynamicStateCreateInfo( vks::initializers::pipelineDynamicStateCreateInfo(
dynamicStateEnables.data(), dynamicStateEnables.data(),
dynamicStateEnables.size(), dynamicStateEnables.size(),
0); 0);
pipelineCreateInfo.layout = pipelineLayouts.offscreen; pipelineCI.layout = pipelineLayouts.offscreen;
pipelineCreateInfo.renderPass = offscreenPass.renderPass; pipelineCI.renderPass = offscreenPass.renderPass;
VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipelines.offscreen)); VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &pipelines.offscreen));
} }
// Prepare and initialize uniform buffer containing shader uniforms // Prepare and initialize uniform buffer containing shader uniforms
@ -864,30 +733,11 @@ public:
{ {
VulkanExampleBase::prepareFrame(); VulkanExampleBase::prepareFrame();
// The scene render command buffer has to wait for the offscreen rendering (and transfer) to be finished before using the shadow map // Command buffer to be sumitted to the queue
// Therefore we synchronize using an additional semaphore
// Offscreen rendering
// Wait for swap chain presentation to finish
submitInfo.pWaitSemaphores = &semaphores.presentComplete;
// Signal ready with offscreen semaphore
submitInfo.pSignalSemaphores = &offscreenPass.semaphore;
// Submit work
submitInfo.commandBufferCount = 1; submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &offscreenPass.commandBuffer;
VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE));
// Scene rendering
// Wait for offscreen semaphore
submitInfo.pWaitSemaphores = &offscreenPass.semaphore;;
// Signal ready with render complete semaphpre
submitInfo.pSignalSemaphores = &semaphores.renderComplete;
// Submit work
submitInfo.pCommandBuffers = &drawCmdBuffers[currentBuffer]; submitInfo.pCommandBuffers = &drawCmdBuffers[currentBuffer];
// Submit to queue
VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE)); VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE));
VulkanExampleBase::submitFrame(); VulkanExampleBase::submitFrame();
@ -899,14 +749,12 @@ public:
loadAssets(); loadAssets();
generateQuad(); generateQuad();
prepareOffscreenFramebuffer(); prepareOffscreenFramebuffer();
setupVertexDescriptions();
prepareUniformBuffers(); prepareUniformBuffers();
setupDescriptorSetLayout(); setupDescriptorSetLayout();
preparePipelines(); preparePipelines();
setupDescriptorPool(); setupDescriptorPool();
setupDescriptorSets(); setupDescriptorSets();
buildCommandBuffers(); buildCommandBuffers();
buildOffscreenCommandBuffer();
prepared = true; prepared = true;
} }
@ -915,7 +763,7 @@ public:
if (!prepared) if (!prepared)
return; return;
draw(); draw();
if (!paused) if (!paused || camera.updated)
{ {
updateLight(); updateLight();
updateUniformBufferOffscreen(); updateUniformBufferOffscreen();
@ -923,18 +771,11 @@ public:
} }
} }
virtual void viewChanged()
{
updateUniformBufferOffscreen();
updateUniformBuffers();
}
virtual void OnUpdateUIOverlay(vks::UIOverlay *overlay) virtual void OnUpdateUIOverlay(vks::UIOverlay *overlay)
{ {
if (overlay->header("Settings")) { if (overlay->header("Settings")) {
if (overlay->comboBox("Scenes", &sceneIndex, sceneNames)) { if (overlay->comboBox("Scenes", &sceneIndex, sceneNames)) {
buildCommandBuffers(); buildCommandBuffers();
buildOffscreenCommandBuffer();
} }
if (overlay->checkBox("Display shadow render target", &displayShadowMap)) { if (overlay->checkBox("Display shadow render target", &displayShadowMap)) {
buildCommandBuffers(); buildCommandBuffers();