From 9ace87aca3a16789c96a2d180452fc863c2dce6e Mon Sep 17 00:00:00 2001 From: saschawillems Date: Thu, 26 May 2016 13:58:38 +0200 Subject: [PATCH] Added post processing pass --- data/shaders/debugmarker/colorpass.frag | 13 + data/shaders/debugmarker/colorpass.frag.spv | Bin 0 -> 520 bytes data/shaders/debugmarker/colorpass.vert | 28 ++ data/shaders/debugmarker/colorpass.vert.spv | Bin 0 -> 1188 bytes data/shaders/debugmarker/generate-spirv.bat | 8 +- data/shaders/debugmarker/mesh.frag.spv | Bin 1828 -> 0 bytes .../debugmarker/{mesh.frag => phongpass.frag} | 9 +- data/shaders/debugmarker/phongpass.frag.spv | Bin 0 -> 2300 bytes .../debugmarker/{mesh.vert => phongpass.vert} | 0 .../{mesh.vert.spv => phongpass.vert.spv} | Bin data/shaders/debugmarker/postprocess.frag | 42 ++ data/shaders/debugmarker/postprocess.frag.spv | Bin 0 -> 3184 bytes data/shaders/debugmarker/postprocess.vert | 17 + data/shaders/debugmarker/postprocess.vert.spv | Bin 0 -> 1064 bytes debugmarker/debugmarker.cpp | 436 ++++++++++++++++-- 15 files changed, 510 insertions(+), 43 deletions(-) create mode 100644 data/shaders/debugmarker/colorpass.frag create mode 100644 data/shaders/debugmarker/colorpass.frag.spv create mode 100644 data/shaders/debugmarker/colorpass.vert create mode 100644 data/shaders/debugmarker/colorpass.vert.spv delete mode 100644 data/shaders/debugmarker/mesh.frag.spv rename data/shaders/debugmarker/{mesh.frag => phongpass.frag} (65%) create mode 100644 data/shaders/debugmarker/phongpass.frag.spv rename data/shaders/debugmarker/{mesh.vert => phongpass.vert} (100%) rename data/shaders/debugmarker/{mesh.vert.spv => phongpass.vert.spv} (100%) create mode 100644 data/shaders/debugmarker/postprocess.frag create mode 100644 data/shaders/debugmarker/postprocess.frag.spv create mode 100644 data/shaders/debugmarker/postprocess.vert create mode 100644 data/shaders/debugmarker/postprocess.vert.spv diff --git a/data/shaders/debugmarker/colorpass.frag b/data/shaders/debugmarker/colorpass.frag new file mode 100644 index 00000000..b23b0129 --- /dev/null +++ b/data/shaders/debugmarker/colorpass.frag @@ -0,0 +1,13 @@ +#version 450 + +#extension GL_ARB_separate_shader_objects : enable +#extension GL_ARB_shading_language_420pack : enable + +layout (location = 0) in vec3 inColor; + +layout (location = 0) out vec4 outFragColor; + +void main() +{ + outFragColor.rgb = inColor; +} \ No newline at end of file diff --git a/data/shaders/debugmarker/colorpass.frag.spv b/data/shaders/debugmarker/colorpass.frag.spv new file mode 100644 index 0000000000000000000000000000000000000000..7fad085dbc6b361978c60ddb7364518ed34fb629 GIT binary patch literal 520 zcmY+A-Acni6oilc*J@i4^iC??mm*aPqM(Ag2?+WCVQoW<)}$oq3;I;v2+p@{K{uS7 zo!QwllhkYHZL=Lc9UIts9a>G;tZOabgYYFBmDPMSxg4YDS=|fK^sQ|Tb?Vcl83((n zebqoZco}F{*Hp7FU1~@XgwfseeN@IvSGX#U$~QNUizt76k7rf+U!$WmOQMC#l9fy1 zXmT-Ly4i;{HR-Q!Q+e^uSJh+Tl81be7lK|#o-|uiflpv|%AppR^DRD7QnH@;)aLic z+PB0FRVUK(O{b9G@Gdt1 literal 0 HcmV?d00001 diff --git a/data/shaders/debugmarker/colorpass.vert b/data/shaders/debugmarker/colorpass.vert new file mode 100644 index 00000000..f842fec1 --- /dev/null +++ b/data/shaders/debugmarker/colorpass.vert @@ -0,0 +1,28 @@ +#version 450 + +#extension GL_ARB_separate_shader_objects : enable +#extension GL_ARB_shading_language_420pack : enable + +layout (location = 0) in vec4 inPos; +layout (location = 3) in vec3 inColor; + +layout (binding = 0) uniform UBO +{ + mat4 projection; + mat4 model; +} ubo; + +layout (location = 0) out vec3 outColor; + +out gl_PerVertex +{ + vec4 gl_Position; +}; + +void main() +{ + { + outColor = inColor; + } + gl_Position = ubo.projection * ubo.model * inPos; +} diff --git a/data/shaders/debugmarker/colorpass.vert.spv b/data/shaders/debugmarker/colorpass.vert.spv new file mode 100644 index 0000000000000000000000000000000000000000..9e254ace61f32b6a71dcbdcad66cf171349688a6 GIT binary patch literal 1188 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 literal 0 HcmV?d00001 diff --git a/data/shaders/debugmarker/postprocess.vert b/data/shaders/debugmarker/postprocess.vert new file mode 100644 index 00000000..e1a60b60 --- /dev/null +++ b/data/shaders/debugmarker/postprocess.vert @@ -0,0 +1,17 @@ +#version 450 + +#extension GL_ARB_separate_shader_objects : enable +#extension GL_ARB_shading_language_420pack : enable + +layout (location = 0) out vec2 outUV; + +out gl_PerVertex +{ + vec4 gl_Position; +}; + +void main() +{ + outUV = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2); + gl_Position = vec4(outUV * vec2(2.0f, 2.0f) + vec2(-1.0f, -1.0f), 0.0f, 1.0f); +} \ No newline at end of file diff --git a/data/shaders/debugmarker/postprocess.vert.spv b/data/shaders/debugmarker/postprocess.vert.spv new file mode 100644 index 0000000000000000000000000000000000000000..a67317a06d4caff6670f287e31dddbbfbc10dd40 GIT binary patch literal 1064 zcmZ9JOHbQC6orR`q)^Hu<<(N4=2cp#5UK!Gs-T5UK*}N%!PatP65vH6>Mg+z(FA=rTDx(pu8o^lzQ{N4AsLtG%#k zuQL5jrq^vJ`y{IDvOy`UHI2Rd!wjji~B88uuU8 zKkH2DNT!WxUzX+xsrb?_;K_|t_@LA9<<@Bx zr{hhebKK>%fS%VG)}A`~nGx;L9-kQ%N3W|c_a76egTAHdcuO>D@_kZ3`{VN8I}P7{ zJ8f2bbbQ*E#%v1$I+1H1v`6a_>Z*=EivqcP!&7|RRt-G-B=DZRA+y2Bzf*;;!aW+3 BO5*?k literal 0 HcmV?d00001 diff --git a/debugmarker/debugmarker.cpp b/debugmarker/debugmarker.cpp index 2af6093e..46994eb9 100644 --- a/debugmarker/debugmarker.cpp +++ b/debugmarker/debugmarker.cpp @@ -23,6 +23,11 @@ #define VERTEX_BUFFER_BIND_ID 0 #define ENABLE_VALIDATION false +// Offscreen properties +#define OFFSCREEN_DIM 256 +#define OFFSCREEN_FORMAT VK_FORMAT_R8G8B8A8_UNORM +#define OFFSCREEN_FILTER VK_FILTER_LINEAR; + // Setup and functions for the VK_EXT_debug_marker_extension // Extension spec can be found at https://github.com/KhronosGroup/Vulkan-Docs/blob/1.0-VK_EXT_debug_marker/doc/specs/vulkan/appendices/VK_EXT_debug_marker.txt // Note that the extension will only be present if run from an offline debugging application @@ -153,10 +158,7 @@ class VulkanExample : public VulkanExampleBase { public: bool wireframe = false; - - struct { - vkTools::VulkanTexture colorMap; - } textures; + bool glow = true; struct { VkPipelineVertexInputStateCreateInfo inputState; @@ -177,14 +179,35 @@ public: } uboVS; struct { - VkPipeline solid; + VkPipeline phong; + VkPipeline color; VkPipeline wireframe; + VkPipeline postprocess; } pipelines; VkPipelineLayout pipelineLayout; - VkDescriptorSet descriptorSet; VkDescriptorSetLayout descriptorSetLayout; + struct { + VkDescriptorSet scene; + VkDescriptorSet fullscreen; + } descriptorSets; + + // Framebuffer for offscreen rendering + struct FrameBufferAttachment { + VkImage image; + VkDeviceMemory mem; + VkImageView view; + }; + struct FrameBuffer { + int32_t width, height; + VkFramebuffer frameBuffer; + FrameBufferAttachment color, depth; + vkTools::VulkanTexture textureTarget; + } offScreenFrameBuf; + + VkCommandBuffer offScreenCmdBuffer = VK_NULL_HANDLE; + VulkanExample() : VulkanExampleBase(ENABLE_VALIDATION) { zoom = -8.5f; @@ -200,7 +223,9 @@ public: { // Clean up used Vulkan resources // Note : Inherited destructor cleans up resources stored in base class - vkDestroyPipeline(device, pipelines.solid, nullptr); + vkDestroyPipeline(device, pipelines.phong, nullptr); + vkDestroyPipeline(device, pipelines.color, nullptr); + vkDestroyPipeline(device, pipelines.wireframe, nullptr); vkDestroyPipelineLayout(device, pipelineLayout, nullptr); vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr); @@ -211,11 +236,299 @@ public: vkDestroyBuffer(device, scene.indices.buf, nullptr); vkFreeMemory(device, scene.indices.mem, nullptr); - textureLoader->destroyTexture(textures.colorMap); - vkTools::destroyUniformData(device, &uniformData.vsScene); } + // Prepare a texture target and framebuffer for offscreen rendering + void prepareOffscreen() + { + VkCommandBuffer cmdBuffer = VulkanExampleBase::createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true); + + VkFormatProperties formatProperties; + + // Get device properites for the requested texture format + vkGetPhysicalDeviceFormatProperties(physicalDevice, OFFSCREEN_FORMAT, &formatProperties); + // Check if blit destination is supported for the requested format + // Only try for optimal tiling, linear tiling usually won't support blit as destination anyway + assert(formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_BLIT_DST_BIT); + + // Texture target + + vkTools::VulkanTexture *tex = &offScreenFrameBuf.textureTarget; + + // Prepare blit target texture + tex->width = OFFSCREEN_DIM; + tex->height = OFFSCREEN_DIM; + + VkImageCreateInfo imageCreateInfo = vkTools::initializers::imageCreateInfo(); + imageCreateInfo.imageType = VK_IMAGE_TYPE_2D; + imageCreateInfo.format = OFFSCREEN_FORMAT; + imageCreateInfo.extent = { OFFSCREEN_DIM, OFFSCREEN_DIM, 1 }; + imageCreateInfo.mipLevels = 1; + imageCreateInfo.arrayLayers = 1; + imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT; + imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; + imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED; + // Texture will be sampled in a shader and is also the blit destination + imageCreateInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; + + VkMemoryAllocateInfo memAllocInfo = vkTools::initializers::memoryAllocateInfo(); + VkMemoryRequirements memReqs; + + VK_CHECK_RESULT(vkCreateImage(device, &imageCreateInfo, nullptr, &tex->image)); + vkGetImageMemoryRequirements(device, tex->image, &memReqs); + memAllocInfo.allocationSize = memReqs.size; + memAllocInfo.memoryTypeIndex = getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + VK_CHECK_RESULT(vkAllocateMemory(device, &memAllocInfo, nullptr, &(tex->deviceMemory))); + VK_CHECK_RESULT(vkBindImageMemory(device, tex->image, tex->deviceMemory, 0)); + + // Transform image layout to transfer destination + tex->imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + vkTools::setImageLayout( + cmdBuffer, + tex->image, + VK_IMAGE_ASPECT_COLOR_BIT, + VK_IMAGE_LAYOUT_PREINITIALIZED, + tex->imageLayout); + + // Create sampler + VkSamplerCreateInfo sampler = vkTools::initializers::samplerCreateInfo(); + sampler.magFilter = OFFSCREEN_FILTER; + sampler.minFilter = OFFSCREEN_FILTER; + sampler.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; + sampler.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + sampler.addressModeV = sampler.addressModeU; + sampler.addressModeW = sampler.addressModeU; + sampler.mipLodBias = 0.0f; + sampler.maxAnisotropy = 0; + sampler.compareOp = VK_COMPARE_OP_NEVER; + sampler.minLod = 0.0f; + sampler.maxLod = 0.0f; + sampler.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; + VK_CHECK_RESULT(vkCreateSampler(device, &sampler, nullptr, &tex->sampler)); + + // Create image view + VkImageViewCreateInfo view = vkTools::initializers::imageViewCreateInfo(); + view.image = VK_NULL_HANDLE; + view.viewType = VK_IMAGE_VIEW_TYPE_2D; + view.format = OFFSCREEN_FORMAT; + view.components = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A }; + view.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }; + view.image = tex->image; + VK_CHECK_RESULT(vkCreateImageView(device, &view, nullptr, &tex->view)); + + // Frame buffer + offScreenFrameBuf.width = OFFSCREEN_DIM; + offScreenFrameBuf.height = OFFSCREEN_DIM; + + // Find a suitable depth format + VkFormat fbDepthFormat; + VkBool32 validDepthFormat = vkTools::getSupportedDepthFormat(physicalDevice, &fbDepthFormat); + assert(validDepthFormat); + + // Color attachment + VkImageCreateInfo image = vkTools::initializers::imageCreateInfo(); + image.imageType = VK_IMAGE_TYPE_2D; + image.format = OFFSCREEN_FORMAT; + image.extent.width = offScreenFrameBuf.width; + image.extent.height = offScreenFrameBuf.height; + image.extent.depth = 1; + image.mipLevels = 1; + image.arrayLayers = 1; + image.samples = VK_SAMPLE_COUNT_1_BIT; + image.tiling = VK_IMAGE_TILING_OPTIMAL; + // Image of the framebuffer is blit source + image.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + image.flags = 0; + + VkImageViewCreateInfo colorImageView = vkTools::initializers::imageViewCreateInfo(); + colorImageView.viewType = VK_IMAGE_VIEW_TYPE_2D; + colorImageView.format = OFFSCREEN_FORMAT; + colorImageView.flags = 0; + colorImageView.subresourceRange = {}; + colorImageView.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + colorImageView.subresourceRange.baseMipLevel = 0; + colorImageView.subresourceRange.levelCount = 1; + colorImageView.subresourceRange.baseArrayLayer = 0; + colorImageView.subresourceRange.layerCount = 1; + + VK_CHECK_RESULT(vkCreateImage(device, &image, nullptr, &offScreenFrameBuf.color.image)); + vkGetImageMemoryRequirements(device, offScreenFrameBuf.color.image, &memReqs); + memAllocInfo.allocationSize = memReqs.size; + memAllocInfo.memoryTypeIndex = getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + VK_CHECK_RESULT(vkAllocateMemory(device, &memAllocInfo, nullptr, &offScreenFrameBuf.color.mem)); + VK_CHECK_RESULT(vkBindImageMemory(device, offScreenFrameBuf.color.image, offScreenFrameBuf.color.mem, 0)); + + vkTools::setImageLayout( + cmdBuffer, + offScreenFrameBuf.color.image, + VK_IMAGE_ASPECT_COLOR_BIT, + VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + + colorImageView.image = offScreenFrameBuf.color.image; + VK_CHECK_RESULT(vkCreateImageView(device, &colorImageView, nullptr, &offScreenFrameBuf.color.view)); + + // Depth stencil attachment + image.format = fbDepthFormat; + image.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + + VkImageViewCreateInfo depthStencilView = vkTools::initializers::imageViewCreateInfo(); + depthStencilView.viewType = VK_IMAGE_VIEW_TYPE_2D; + depthStencilView.format = fbDepthFormat; + depthStencilView.flags = 0; + depthStencilView.subresourceRange = {}; + depthStencilView.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; + depthStencilView.subresourceRange.baseMipLevel = 0; + depthStencilView.subresourceRange.levelCount = 1; + depthStencilView.subresourceRange.baseArrayLayer = 0; + depthStencilView.subresourceRange.layerCount = 1; + + VK_CHECK_RESULT(vkCreateImage(device, &image, nullptr, &offScreenFrameBuf.depth.image)); + vkGetImageMemoryRequirements(device, offScreenFrameBuf.depth.image, &memReqs); + memAllocInfo.allocationSize = memReqs.size; + memAllocInfo.memoryTypeIndex = getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + VK_CHECK_RESULT(vkAllocateMemory(device, &memAllocInfo, nullptr, &offScreenFrameBuf.depth.mem)); + VK_CHECK_RESULT(vkBindImageMemory(device, offScreenFrameBuf.depth.image, offScreenFrameBuf.depth.mem, 0)); + + vkTools::setImageLayout( + cmdBuffer, + offScreenFrameBuf.depth.image, + VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, + VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); + + depthStencilView.image = offScreenFrameBuf.depth.image; + VK_CHECK_RESULT(vkCreateImageView(device, &depthStencilView, nullptr, &offScreenFrameBuf.depth.view)); + + VkImageView attachments[2]; + attachments[0] = offScreenFrameBuf.color.view; + attachments[1] = offScreenFrameBuf.depth.view; + + VkFramebufferCreateInfo fbufCreateInfo = vkTools::initializers::framebufferCreateInfo(); + fbufCreateInfo.renderPass = renderPass; + fbufCreateInfo.attachmentCount = 2; + fbufCreateInfo.pAttachments = attachments; + fbufCreateInfo.width = offScreenFrameBuf.width; + fbufCreateInfo.height = offScreenFrameBuf.height; + fbufCreateInfo.layers = 1; + VK_CHECK_RESULT(vkCreateFramebuffer(device, &fbufCreateInfo, nullptr, &offScreenFrameBuf.frameBuffer)); + + VulkanExampleBase::flushCommandBuffer(cmdBuffer, queue, true); + + // Command buffer for offscreen rendering + offScreenCmdBuffer = VulkanExampleBase::createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, false); + } + + // Command buffer for rendering color only scene for glow + void buildOffscreenCommandBuffer() + { + VkCommandBufferBeginInfo cmdBufInfo = vkTools::initializers::commandBufferBeginInfo(); + + VkClearValue clearValues[2]; + clearValues[0].color = { { 0.0f, 0.0f, 0.0f, 0.0f } }; + clearValues[1].depthStencil = { 1.0f, 0 }; + + VkRenderPassBeginInfo renderPassBeginInfo = vkTools::initializers::renderPassBeginInfo(); + renderPassBeginInfo.renderPass = renderPass; + renderPassBeginInfo.framebuffer = offScreenFrameBuf.frameBuffer; + renderPassBeginInfo.renderArea.extent.width = offScreenFrameBuf.width; + renderPassBeginInfo.renderArea.extent.height = offScreenFrameBuf.height; + renderPassBeginInfo.clearValueCount = 2; + renderPassBeginInfo.pClearValues = clearValues; + + VK_CHECK_RESULT(vkBeginCommandBuffer(offScreenCmdBuffer, &cmdBufInfo)); + + VkViewport viewport = vkTools::initializers::viewport((float)offScreenFrameBuf.width, (float)offScreenFrameBuf.height, 0.0f, 1.0f); + vkCmdSetViewport(offScreenCmdBuffer, 0, 1, &viewport); + + VkRect2D scissor = vkTools::initializers::rect2D(offScreenFrameBuf.width, offScreenFrameBuf.height, 0, 0); + vkCmdSetScissor(offScreenCmdBuffer, 0, 1, &scissor); + + vkCmdBeginRenderPass(offScreenCmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); + + vkCmdBindDescriptorSets(offScreenCmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSets.scene, 0, NULL); + vkCmdBindPipeline(offScreenCmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.color); + + // Draw glow scene + sceneGlow.draw(offScreenCmdBuffer); + + vkCmdEndRenderPass(offScreenCmdBuffer); + + // Make sure color writes to the framebuffer are finished before using it as transfer source + vkTools::setImageLayout( + offScreenCmdBuffer, + offScreenFrameBuf.color.image, + VK_IMAGE_ASPECT_COLOR_BIT, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); + + // Transform texture target to transfer destination + vkTools::setImageLayout( + offScreenCmdBuffer, + offScreenFrameBuf.textureTarget.image, + VK_IMAGE_ASPECT_COLOR_BIT, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + + // Blit offscreen color buffer to our texture target + VkImageBlit imgBlit; + + imgBlit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + imgBlit.srcSubresource.mipLevel = 0; + imgBlit.srcSubresource.baseArrayLayer = 0; + imgBlit.srcSubresource.layerCount = 1; + + imgBlit.srcOffsets[0] = { 0, 0, 0 }; + imgBlit.srcOffsets[1].x = offScreenFrameBuf.width; + imgBlit.srcOffsets[1].y = offScreenFrameBuf.height; + imgBlit.srcOffsets[1].z = 1; + + imgBlit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + imgBlit.dstSubresource.mipLevel = 0; + imgBlit.dstSubresource.baseArrayLayer = 0; + imgBlit.dstSubresource.layerCount = 1; + + imgBlit.dstOffsets[0] = { 0, 0, 0 }; + imgBlit.dstOffsets[1].x = offScreenFrameBuf.textureTarget.width; + imgBlit.dstOffsets[1].y = offScreenFrameBuf.textureTarget.height; + imgBlit.dstOffsets[1].z = 1; + + // Blit from framebuffer image to texture image + // vkCmdBlitImage does scaling and (if necessary and possible) also does format conversions + vkCmdBlitImage( + offScreenCmdBuffer, + offScreenFrameBuf.color.image, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + offScreenFrameBuf.textureTarget.image, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + 1, + &imgBlit, + VK_FILTER_LINEAR + ); + + // Transform framebuffer color attachment back + vkTools::setImageLayout( + offScreenCmdBuffer, + offScreenFrameBuf.color.image, + VK_IMAGE_ASPECT_COLOR_BIT, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + + // Transform texture target back to shader read + // Makes sure that writes to the texture are finished before + // it's accessed in the shader + vkTools::setImageLayout( + offScreenCmdBuffer, + offScreenFrameBuf.textureTarget.image, + VK_IMAGE_ASPECT_COLOR_BIT, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + + VK_CHECK_RESULT(vkEndCommandBuffer(offScreenCmdBuffer)); + } + // Load a model file as separate meshes into a scene void loadModel(std::string filename, Scene *scene) { @@ -374,12 +687,7 @@ public: for (size_t i = 0; i < names.size(); i++) { scene.meshes[i].name = names[i]; - } - // Glow - std::vector namesGlow = { "emeralds", "mushroom stems", "blue mushroom caps", "chest fittings" }; - for (size_t i = 0; i < namesGlow.size(); i++) - { - sceneGlow.meshes[i].name = namesGlow[i]; + sceneGlow.meshes[i].name = names[i]; } // Name the buffers for debugging @@ -391,14 +699,6 @@ public: DebugReportExt::setObjectName(device, (uint64_t)sceneGlow.indices.buf, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, "Glow index buffer"); } - void loadTextures() - { - textureLoader->loadTexture( - getAssetPath() + "models/voyager/voyager.ktx", - VK_FORMAT_BC3_UNORM_BLOCK, - &textures.colorMap); - } - void reBuildCommandBuffers() { if (!checkCommandBuffers()) @@ -444,14 +744,14 @@ public: VkRect2D scissor = vkTools::initializers::rect2D(wireframe ? width / 2 : width, height, 0, 0); vkCmdSetScissor(drawCmdBuffers[i], 0, 1, &scissor); - 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, &descriptorSets.scene, 0, NULL); // Solid rendering // Start a new debug marker region DebugReportExt::beginDebugMarkerRegion(drawCmdBuffers[i], "Solid draw", glm::vec4(1.0f, 0.0f, 0.0f, 0.0f)); - vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.solid); + vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.phong); scene.draw(drawCmdBuffers[i]); DebugReportExt::endDebugMarkerRegion(drawCmdBuffers[i]); @@ -471,6 +771,19 @@ public: DebugReportExt::endDebugMarkerRegion(drawCmdBuffers[i]); } + // Post processing + if (glow) + { + DebugReportExt::beginDebugMarkerRegion(drawCmdBuffers[i], "Post processing", glm::vec4(1.0f, 0.0f, 0.0f, 0.0f)); + + vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.postprocess); + // Full screen quad is generated by the vertex shaders, so we reuse four vertices (for four invocations) from current vertex buffer + vkCmdDraw(drawCmdBuffers[i], 4, 1, 0, 0); + + DebugReportExt::endDebugMarkerRegion(drawCmdBuffers[i]); + } + + vkCmdEndRenderPass(drawCmdBuffers[i]); // End current debug marker region @@ -586,25 +899,25 @@ public: &descriptorSetLayout, 1); - VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &descriptorSet)); + VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &descriptorSets.scene)); VkDescriptorImageInfo texDescriptor = vkTools::initializers::descriptorImageInfo( - textures.colorMap.sampler, - textures.colorMap.view, + offScreenFrameBuf.textureTarget.sampler, + offScreenFrameBuf.textureTarget.view, VK_IMAGE_LAYOUT_GENERAL); std::vector writeDescriptorSets = { // Binding 0 : Vertex shader uniform buffer vkTools::initializers::writeDescriptorSet( - descriptorSet, + descriptorSets.scene, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0, &uniformData.vsScene.descriptor), // Binding 1 : Color map vkTools::initializers::writeDescriptorSet( - descriptorSet, + descriptorSets.scene, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, &texDescriptor) @@ -662,12 +975,12 @@ public: dynamicStateEnables.size(), 0); - // Solid rendering pipeline + // Phong lighting pipeline // Load shaders std::array shaderStages; - shaderStages[0] = loadShader(getAssetPath() + "shaders/debugmarker/mesh.vert.spv", VK_SHADER_STAGE_VERTEX_BIT); - shaderStages[1] = loadShader(getAssetPath() + "shaders/debugmarker/mesh.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT); + shaderStages[0] = loadShader(getAssetPath() + "shaders/debugmarker/phongpass.vert.spv", VK_SHADER_STAGE_VERTEX_BIT); + shaderStages[1] = loadShader(getAssetPath() + "shaders/debugmarker/phongpass.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT); // Name shader moduels for debugging DebugReportExt::setObjectName(device, (uint64_t)shaderModules[0], VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT, "Mesh rendering vertex shader"); @@ -690,7 +1003,13 @@ public: pipelineCreateInfo.stageCount = shaderStages.size(); pipelineCreateInfo.pStages = shaderStages.data(); - VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipelines.solid)); + VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipelines.phong)); + + // Color only pipeline + shaderStages[0] = loadShader(getAssetPath() + "shaders/debugmarker/colorpass.vert.spv", VK_SHADER_STAGE_VERTEX_BIT); + shaderStages[1] = loadShader(getAssetPath() + "shaders/debugmarker/colorpass.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT); + + VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipelines.color)); // Wire frame rendering pipeline rasterizationState.polygonMode = VK_POLYGON_MODE_LINE; @@ -698,9 +1017,32 @@ public: VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipelines.wireframe)); + // Post processing effect + shaderStages[0] = loadShader(getAssetPath() + "shaders/debugmarker/postprocess.vert.spv", VK_SHADER_STAGE_VERTEX_BIT); + shaderStages[1] = loadShader(getAssetPath() + "shaders/debugmarker/postprocess.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT); + + depthStencilState.depthTestEnable = VK_FALSE; + depthStencilState.depthWriteEnable = VK_FALSE; + + rasterizationState.polygonMode = VK_POLYGON_MODE_FILL; + rasterizationState.cullMode = VK_CULL_MODE_NONE; + + blendAttachmentState.colorWriteMask = 0xF; + blendAttachmentState.blendEnable = VK_TRUE; + blendAttachmentState.colorBlendOp = VK_BLEND_OP_ADD; + blendAttachmentState.srcColorBlendFactor = VK_BLEND_FACTOR_ONE; + blendAttachmentState.dstColorBlendFactor = VK_BLEND_FACTOR_ONE; + blendAttachmentState.alphaBlendOp = VK_BLEND_OP_ADD; + blendAttachmentState.srcAlphaBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; + blendAttachmentState.dstAlphaBlendFactor = VK_BLEND_FACTOR_DST_ALPHA; + + VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipelines.postprocess)); + // Name pipelines for debugging - DebugReportExt::setObjectName(device, (uint64_t)pipelines.solid, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT, "Solid rendering pipeline"); + DebugReportExt::setObjectName(device, (uint64_t)pipelines.phong, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT, "Phong lighting pipeline"); + DebugReportExt::setObjectName(device, (uint64_t)pipelines.color, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT, "Color only pipeline"); DebugReportExt::setObjectName(device, (uint64_t)pipelines.wireframe, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT, "Wireframe rendering pipeline"); + DebugReportExt::setObjectName(device, (uint64_t)pipelines.postprocess, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT, "Post processing pipeline"); } // Prepare and initialize uniform buffer containing shader uniforms @@ -742,8 +1084,18 @@ public: { VulkanExampleBase::prepareFrame(); - submitInfo.commandBufferCount = 1; - submitInfo.pCommandBuffers = &drawCmdBuffers[currentBuffer]; + std::vector submitCmdBuffers; + + // Submit offscreen rendering command buffer + // todo : use event to ensure that offscreen result is finished bfore render command buffer is started + if (glow) + { + submitCmdBuffers.push_back(offScreenCmdBuffer); + } + submitCmdBuffers.push_back(drawCmdBuffers[currentBuffer]); + + submitInfo.commandBufferCount = submitCmdBuffers.size(); + submitInfo.pCommandBuffers = submitCmdBuffers.data(); VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE)); VulkanExampleBase::submitFrame(); @@ -753,8 +1105,8 @@ public: { VulkanExampleBase::prepare(); DebugReportExt::setupDebugMarkers(device); - loadTextures(); loadScene(); + prepareOffscreen(); setupVertexDescriptions(); prepareUniformBuffers(); setupDescriptorSetLayout(); @@ -762,6 +1114,7 @@ public: setupDescriptorPool(); setupDescriptorSet(); buildCommandBuffers(); + buildOffscreenCommandBuffer(); updateTextOverlay(); prepared = true; } @@ -783,10 +1136,15 @@ public: switch (keyCode) { case 0x57: - case GAMEPAD_BUTTON_A: + case GAMEPAD_BUTTON_X: wireframe = !wireframe; reBuildCommandBuffers(); break; + case 0x47: + case GAMEPAD_BUTTON_A: + glow = !glow; + reBuildCommandBuffers(); + break; } }