From cb5bd093ecd25a7f0550b54c6a65450ef7b13bd9 Mon Sep 17 00:00:00 2001 From: saschawillems Date: Sat, 13 Aug 2016 15:41:36 +0200 Subject: [PATCH] Fold layout transitions into subpass (Refs #155), refactoring of offscreen render pass --- data/shaders/radialblur/colorpass.vert | 5 +- data/shaders/radialblur/colorpass.vert.spv | Bin 1236 -> 1188 bytes data/shaders/radialblur/radialblur.frag | 5 +- data/shaders/radialblur/radialblur.frag.spv | Bin 2456 -> 2496 bytes offscreen/offscreen.cpp | 11 +- radialblur/radialblur.cpp | 498 +++++++------------- 6 files changed, 188 insertions(+), 331 deletions(-) diff --git a/data/shaders/radialblur/colorpass.vert b/data/shaders/radialblur/colorpass.vert index 05c9cd4e..abd9082e 100644 --- a/data/shaders/radialblur/colorpass.vert +++ b/data/shaders/radialblur/colorpass.vert @@ -10,7 +10,6 @@ layout (binding = 0) uniform UBO { mat4 projection; mat4 model; - vec4 glowColor; } ubo; layout (location = 0) out vec3 outColor; @@ -22,8 +21,6 @@ out gl_PerVertex void main() { - { - outColor = inColor; - } + outColor = inColor; gl_Position = ubo.projection * ubo.model * inPos; } diff --git a/data/shaders/radialblur/colorpass.vert.spv b/data/shaders/radialblur/colorpass.vert.spv index 3778d638bce584247b73341f77ce1bb181d1a7a2..2cce8d4a03dfa0df427edc81911c4295cfd4933e 100644 GIT binary patch delta 33 mcmcb@xrB2=0^{Tg#xt8En4}oFSr|kZ7#M^>cyl9jFe3n;R0nVX delta 77 zcmZ3&d4+RB0;4D!0~><~0|NsS5U1zlmpkX@$Ngj>6-JX*e?)lnPh zbDWJBKwlfNR$V5;L@Dbxh*xcI7psk|onxCUZT57?)-Uo-v;QbOxockr_T{409Q4o} z&R~1JTh{gwatm17C!D=9gZg;c>+W{{Mv*n2ys?I#Z$AP2l0JiMJ?hTsIPkkkq;j~( zvnBICr@x%NPJY%bHwkL7A9BXE?%}-Z=1q2YBjr5+D?dXFw@UdCF~&Kkfw_;MyF+r? zr_s$TCk}J-xsngzC>t<^tnS_6FX_kde;$K=#(E(-$z6)Nz4JSbZr**RHmKzQvhhr;1j+U?C-oaS^s z`oGO-Jo!}5X=J}MSme(Dxu-FxeIA}~@p#+`V+->e|2iRE4 zIrT?-1=!Pr+^TZwcb(I^&82>W)0pb%9k-D~*s7#F_tAC%{lDdOhkT!Psk>`(>3$tK zgq_L--ezoj=BLl!Fk_tFo#ga?iS?*EWB+Fi>nDeFdp%rE(7;e-8rrR zdzk9_0@*uhUU!i7kx%nlMSgZ(U&6_!S*#&@SNw fyN+xx%$IuDK$f?M-rE4)mA9q`k^7hbb{D~aI=`~> literal 2456 zcmZ9MeQ%Rx6o+pp>xL*V@+P9#F%=b@69=LbW{0d(r<=?<6t#KSo^;jHE?t)x|C%u- z{^fV^EBK*|nwWT9PoHB7cXM*i`JI>hyxdPK2dBnUI>2utHPi5%NC(kVI+CgdZ!E7Z zPwx)4rf09s=y5bv3P*j8rSWtKEvtEL zyZKJm&jxvOcRSn4`_0~i@AA#T?xQ}K+TB*OlXY8rSu1bOUY*&=Hos3}WE#D94CF9( z^zqL+YwaKN1X4*)f~_yC&`q_FQPUv*VWYh@*j5hQe!!RVc58c3;NykAbq{kcboTmd zn^`9(W}>h;i4ohNpLbhktqh^RcF*;Cl~xMSbUy*BO}oIJy$jzhs?oQamejL{JDt3Ly9_CCllArni~X$iKfZ*;`aDxZM*I+S z4r10Gm@^QY7{Tma%sk;|jM#CgQO@4j2HEWSBIF6({=#nW7c_FT+s~-Ky8hOu-M+&A zBw5Te$(`1vd(VI&RhQ)Twn3%3K5Dsy61iVNw$|u%x|Bz2zYb8S zySxsiv{OIFmwX3F?10e73H?0#T?E(9e2vma%$ceCW<1*0;l2%Lpmyfc=V@Q@h`yZ&aJTt1H|06cm0hA{+Z#nfGO6G2fsy``%uKtoafYaj%v5&t=?Y zbYsQC=L)iS|5W~RL}KIMPX&sF$akVpG0T)W)6+{HD>9KUmy zZ~jJ!`7Qi|kNTUCxr|k|Ki~aL$o}REdAQ44B_8?b(aj$_dLLOVcC>&jR)>Beulv6Z znMa#*68ivhmqS~ncxPhXvk3nX@;iwceuV4{)s6oc@@>YxmXY-lk9~cD{P?~;1rv{5 ztRNdJzCmq%hpUkHYx6#_&miB7aq4$VOy77l3^E8rfOghhm1`Ad5Rgwidth = width; - tex->height = height; - - VkImageCreateInfo imageCreateInfo = vkTools::initializers::imageCreateInfo(); - imageCreateInfo.imageType = VK_IMAGE_TYPE_2D; - imageCreateInfo.format = format; - imageCreateInfo.extent = { width, height, 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_UNDEFINED; - // 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 = vulkanDevice->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_UNDEFINED, - tex->imageLayout); - - // Create sampler - VkSamplerCreateInfo sampler = vkTools::initializers::samplerCreateInfo(); - sampler.magFilter = TEX_FILTER; - sampler.minFilter = TEX_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 = 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)); - - VulkanExampleBase::flushCommandBuffer(cmdBuffer, queue, true); + vkFreeCommandBuffers(device, cmdPool, 1, &offscreenPass.commandBuffer); + vkDestroySemaphore(device, offscreenPass.semaphore, nullptr); } // Setup the offscreen framebuffer for rendering the blurred scene - // The color attachment of this framebuffer will then be used - // to sample frame in the fragment shader of the final pass - void prepareOffscreenFramebuffer() + // The color attachment of this framebuffer will then be used to sample frame in the fragment shader of the final pass + void prepareOffscreen() { - offScreenFrameBuf.width = FB_DIM; - offScreenFrameBuf.height = FB_DIM; - - VkFormat fbColorFormat = FB_COLOR_FORMAT; + offscreenPass.width = FB_DIM; + offscreenPass.height = FB_DIM; // Find a suitable depth format VkFormat fbDepthFormat; @@ -270,9 +182,9 @@ public: // Color attachment VkImageCreateInfo image = vkTools::initializers::imageCreateInfo(); image.imageType = VK_IMAGE_TYPE_2D; - image.format = fbColorFormat; - image.extent.width = offScreenFrameBuf.width; - image.extent.height = offScreenFrameBuf.height; + image.format = FB_COLOR_FORMAT; + image.extent.width = offscreenPass.width; + image.extent.height = offscreenPass.height; image.extent.depth = 1; image.mipLevels = 1; image.arrayLayers = 1; @@ -284,58 +196,51 @@ public: VkMemoryAllocateInfo memAlloc = vkTools::initializers::memoryAllocateInfo(); VkMemoryRequirements memReqs; + VK_CHECK_RESULT(vkCreateImage(device, &image, nullptr, &offscreenPass.color.image)); + vkGetImageMemoryRequirements(device, offscreenPass.color.image, &memReqs); + memAlloc.allocationSize = memReqs.size; + memAlloc.memoryTypeIndex = vulkanDevice->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + VK_CHECK_RESULT(vkAllocateMemory(device, &memAlloc, nullptr, &offscreenPass.color.mem)); + VK_CHECK_RESULT(vkBindImageMemory(device, offscreenPass.color.image, offscreenPass.color.mem, 0)); + VkImageViewCreateInfo colorImageView = vkTools::initializers::imageViewCreateInfo(); colorImageView.viewType = VK_IMAGE_VIEW_TYPE_2D; - colorImageView.format = fbColorFormat; + colorImageView.format = FB_COLOR_FORMAT; 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; + colorImageView.image = offscreenPass.color.image; + VK_CHECK_RESULT(vkCreateImageView(device, &colorImageView, nullptr, &offscreenPass.color.view)); - VK_CHECK_RESULT(vkCreateImage(device, &image, nullptr, &offScreenFrameBuf.color.image)); - vkGetImageMemoryRequirements(device, offScreenFrameBuf.color.image, &memReqs); - memAlloc.allocationSize = memReqs.size; - memAlloc.memoryTypeIndex = vulkanDevice->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - VK_CHECK_RESULT(vkAllocateMemory(device, &memAlloc, nullptr, &offScreenFrameBuf.color.mem)); - VK_CHECK_RESULT(vkBindImageMemory(device, offScreenFrameBuf.color.image, offScreenFrameBuf.color.mem, 0)); - - // Get a primary command buffer for submitting image layout transitions for the framebuffer attachments - VkCommandBuffer layoutCmd = VulkanExampleBase::createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true); - - // Set the initial layout to shader read instead of attachment - // This is done as the render loop does the actualy image layout transitions - vkTools::setImageLayout( - layoutCmd, - offScreenFrameBuf.color.image, - VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - - colorImageView.image = offScreenFrameBuf.color.image; - VK_CHECK_RESULT(vkCreateImageView(device, &colorImageView, nullptr, &offScreenFrameBuf.color.view)); - - // Create sampler to sample from to collor attachment - // Used to sample in the fragment shader for final rendering - VkSamplerCreateInfo sampler = vkTools::initializers::samplerCreateInfo(); - sampler.magFilter = VK_FILTER_LINEAR; - sampler.minFilter = VK_FILTER_LINEAR; - 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.minLod = 0.0f; - sampler.maxLod = 1.0f; - sampler.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; - VK_CHECK_RESULT(vkCreateSampler(device, &sampler, nullptr, &offScreenFrameBuf.colorSampler)); + // Create sampler to sample from the attachment in the fragment shader + VkSamplerCreateInfo samplerInfo = vkTools::initializers::samplerCreateInfo(); + samplerInfo.magFilter = VK_FILTER_LINEAR; + samplerInfo.minFilter = VK_FILTER_LINEAR; + samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; + samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + samplerInfo.addressModeV = samplerInfo.addressModeU; + samplerInfo.addressModeW = samplerInfo.addressModeU; + samplerInfo.mipLodBias = 0.0f; + samplerInfo.maxAnisotropy = 0; + samplerInfo.minLod = 0.0f; + samplerInfo.maxLod = 1.0f; + samplerInfo.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; + VK_CHECK_RESULT(vkCreateSampler(device, &samplerInfo, nullptr, &offscreenPass.sampler)); // Depth stencil attachment image.format = fbDepthFormat; image.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + VK_CHECK_RESULT(vkCreateImage(device, &image, nullptr, &offscreenPass.depth.image)); + vkGetImageMemoryRequirements(device, offscreenPass.depth.image, &memReqs); + memAlloc.allocationSize = memReqs.size; + memAlloc.memoryTypeIndex = vulkanDevice->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + VK_CHECK_RESULT(vkAllocateMemory(device, &memAlloc, nullptr, &offscreenPass.depth.mem)); + VK_CHECK_RESULT(vkBindImageMemory(device, offscreenPass.depth.image, offscreenPass.depth.mem, 0)); + VkImageViewCreateInfo depthStencilView = vkTools::initializers::imageViewCreateInfo(); depthStencilView.viewType = VK_IMAGE_VIEW_TYPE_2D; depthStencilView.format = fbDepthFormat; @@ -346,52 +251,103 @@ public: depthStencilView.subresourceRange.levelCount = 1; depthStencilView.subresourceRange.baseArrayLayer = 0; depthStencilView.subresourceRange.layerCount = 1; + depthStencilView.image = offscreenPass.depth.image; + VK_CHECK_RESULT(vkCreateImageView(device, &depthStencilView, nullptr, &offscreenPass.depth.view)); - VK_CHECK_RESULT(vkCreateImage(device, &image, nullptr, &offScreenFrameBuf.depth.image)); - vkGetImageMemoryRequirements(device, offScreenFrameBuf.depth.image, &memReqs); - memAlloc.allocationSize = memReqs.size; - memAlloc.memoryTypeIndex = vulkanDevice->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - VK_CHECK_RESULT(vkAllocateMemory(device, &memAlloc, nullptr, &offScreenFrameBuf.depth.mem)); - VK_CHECK_RESULT(vkBindImageMemory(device, offScreenFrameBuf.depth.image, offScreenFrameBuf.depth.mem, 0)); + // Create a separate render pass for the offscreen rendering as it may differ from the one used for scene rendering - vkTools::setImageLayout( - layoutCmd, - offScreenFrameBuf.depth.image, - VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, - VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); + std::array attchmentDescriptions = {}; + // Color attachment + attchmentDescriptions[0].format = FB_COLOR_FORMAT; + attchmentDescriptions[0].samples = VK_SAMPLE_COUNT_1_BIT; + attchmentDescriptions[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + attchmentDescriptions[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE; + attchmentDescriptions[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + attchmentDescriptions[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + attchmentDescriptions[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + attchmentDescriptions[0].finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + // Depth attachment + attchmentDescriptions[1].format = fbDepthFormat; + attchmentDescriptions[1].samples = VK_SAMPLE_COUNT_1_BIT; + attchmentDescriptions[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + attchmentDescriptions[1].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + attchmentDescriptions[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + attchmentDescriptions[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + attchmentDescriptions[1].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + attchmentDescriptions[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - // Submit the command buffer to apply the image memory barrier - VulkanExampleBase::flushCommandBuffer(layoutCmd, queue, true); + VkAttachmentReference colorReference = { 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL }; + VkAttachmentReference depthReference = { 1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL }; - depthStencilView.image = offScreenFrameBuf.depth.image; - VK_CHECK_RESULT(vkCreateImageView(device, &depthStencilView, nullptr, &offScreenFrameBuf.depth.view)); + VkSubpassDescription subpassDescription = {}; + subpassDescription.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpassDescription.colorAttachmentCount = 1; + subpassDescription.pColorAttachments = &colorReference; + subpassDescription.pDepthStencilAttachment = &depthReference; + + // Use subpass dependencies for layout transitions + std::array dependencies; + + dependencies[0].srcSubpass = VK_SUBPASS_EXTERNAL; + dependencies[0].dstSubpass = 0; + dependencies[0].srcStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; + dependencies[0].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + dependencies[0].srcAccessMask = VK_ACCESS_MEMORY_READ_BIT; + dependencies[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + dependencies[0].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT; + + dependencies[1].srcSubpass = 0; + dependencies[1].dstSubpass = VK_SUBPASS_EXTERNAL; + dependencies[1].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + dependencies[1].dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; + dependencies[1].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + dependencies[1].dstAccessMask = VK_ACCESS_MEMORY_READ_BIT; + dependencies[1].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT; + + // Create the actual renderpass + VkRenderPassCreateInfo renderPassInfo = {}; + renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + renderPassInfo.attachmentCount = static_cast(attchmentDescriptions.size()); + renderPassInfo.pAttachments = attchmentDescriptions.data(); + renderPassInfo.subpassCount = 1; + renderPassInfo.pSubpasses = &subpassDescription; + renderPassInfo.dependencyCount = static_cast(dependencies.size()); + renderPassInfo.pDependencies = dependencies.data(); + + VK_CHECK_RESULT(vkCreateRenderPass(device, &renderPassInfo, nullptr, &offscreenPass.renderPass)); VkImageView attachments[2]; - attachments[0] = offScreenFrameBuf.color.view; - attachments[1] = offScreenFrameBuf.depth.view; + attachments[0] = offscreenPass.color.view; + attachments[1] = offscreenPass.depth.view; VkFramebufferCreateInfo fbufCreateInfo = vkTools::initializers::framebufferCreateInfo(); - fbufCreateInfo.renderPass = renderPass; + fbufCreateInfo.renderPass = offscreenPass.renderPass; fbufCreateInfo.attachmentCount = 2; fbufCreateInfo.pAttachments = attachments; - fbufCreateInfo.width = offScreenFrameBuf.width; - fbufCreateInfo.height = offScreenFrameBuf.height; + fbufCreateInfo.width = offscreenPass.width; + fbufCreateInfo.height = offscreenPass.height; fbufCreateInfo.layers = 1; - VK_CHECK_RESULT(vkCreateFramebuffer(device, &fbufCreateInfo, nullptr, &offScreenFrameBuf.frameBuffer)); + + VK_CHECK_RESULT(vkCreateFramebuffer(device, &fbufCreateInfo, nullptr, &offscreenPass.frameBuffer)); + + // Fill a descriptor for later use in a descriptor set + offscreenPass.descriptor.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + offscreenPass.descriptor.imageView = offscreenPass.color.view; + offscreenPass.descriptor.sampler = offscreenPass.sampler; } // Sets up the command buffer that renders the scene to the offscreen frame buffer void buildOffscreenCommandBuffer() { - if (offScreenCmdBuffer == VK_NULL_HANDLE) + if (offscreenPass.commandBuffer == VK_NULL_HANDLE) { - offScreenCmdBuffer = VulkanExampleBase::createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, false); + offscreenPass.commandBuffer = VulkanExampleBase::createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, false); + } + if (offscreenPass.semaphore == VK_NULL_HANDLE) + { + VkSemaphoreCreateInfo semaphoreCreateInfo = vkTools::initializers::semaphoreCreateInfo(); + VK_CHECK_RESULT(vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &offscreenPass.semaphore)); } - - // Create a semaphore used to synchronize offscreen rendering and usage - VkSemaphoreCreateInfo semaphoreCreateInfo = vkTools::initializers::semaphoreCreateInfo(); - VK_CHECK_RESULT(vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &offscreenSemaphore)); VkCommandBufferBeginInfo cmdBufInfo = vkTools::initializers::commandBufferBeginInfo(); @@ -400,50 +356,34 @@ public: 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.renderPass = offscreenPass.renderPass; + renderPassBeginInfo.framebuffer = offscreenPass.frameBuffer; + renderPassBeginInfo.renderArea.extent.width = offscreenPass.width; + renderPassBeginInfo.renderArea.extent.height = offscreenPass.height; renderPassBeginInfo.clearValueCount = 2; renderPassBeginInfo.pClearValues = clearValues; - VK_CHECK_RESULT(vkBeginCommandBuffer(offScreenCmdBuffer, &cmdBufInfo)); + VK_CHECK_RESULT(vkBeginCommandBuffer(offscreenPass.commandBuffer, &cmdBufInfo)); - // Change back layout of the color attachment after sampling in the fragment shader - vkTools::setImageLayout( - offScreenCmdBuffer, - offScreenFrameBuf.color.image, - VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + VkViewport viewport = vkTools::initializers::viewport((float)offscreenPass.width, (float)offscreenPass.height, 0.0f, 1.0f); + vkCmdSetViewport(offscreenPass.commandBuffer, 0, 1, &viewport); - 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(offscreenPass.width, offscreenPass.height, 0, 0); + vkCmdSetScissor(offscreenPass.commandBuffer, 0, 1, &scissor); - VkRect2D scissor = vkTools::initializers::rect2D(offScreenFrameBuf.width, offScreenFrameBuf.height, 0, 0); - vkCmdSetScissor(offScreenCmdBuffer, 0, 1, &scissor); + vkCmdBeginRenderPass(offscreenPass.commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); - vkCmdBeginRenderPass(offScreenCmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); - - vkCmdBindDescriptorSets(offScreenCmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayouts.scene, 0, 1, &descriptorSets.scene, 0, NULL); - vkCmdBindPipeline(offScreenCmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.colorPass); + vkCmdBindDescriptorSets(offscreenPass.commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayouts.scene, 0, 1, &descriptorSets.scene, 0, NULL); + vkCmdBindPipeline(offscreenPass.commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.colorPass); VkDeviceSize offsets[1] = { 0 }; - vkCmdBindVertexBuffers(offScreenCmdBuffer, VERTEX_BUFFER_BIND_ID, 1, &meshes.example.vertices.buf, offsets); - vkCmdBindIndexBuffer(offScreenCmdBuffer, meshes.example.indices.buf, 0, VK_INDEX_TYPE_UINT32); - vkCmdDrawIndexed(offScreenCmdBuffer, meshes.example.indexCount, 1, 0, 0, 0); + vkCmdBindVertexBuffers(offscreenPass.commandBuffer, VERTEX_BUFFER_BIND_ID, 1, &meshes.example.vertices.buf, offsets); + vkCmdBindIndexBuffer(offscreenPass.commandBuffer, meshes.example.indices.buf, 0, VK_INDEX_TYPE_UINT32); + vkCmdDrawIndexed(offscreenPass.commandBuffer, meshes.example.indexCount, 1, 0, 0, 0); - vkCmdEndRenderPass(offScreenCmdBuffer); + vkCmdEndRenderPass(offscreenPass.commandBuffer); - // Change layout of the color attachment for sampling in the fragment shader - vkTools::setImageLayout( - offScreenCmdBuffer, - offScreenFrameBuf.color.image, - VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - - VK_CHECK_RESULT(vkEndCommandBuffer(offScreenCmdBuffer)); + VK_CHECK_RESULT(vkEndCommandBuffer(offscreenPass.commandBuffer)); } void reBuildCommandBuffers() @@ -514,7 +454,7 @@ public: } } - void loadMeshes() + void loadAssets() { loadMesh(getAssetPath() + "models/glowsphere.dae", &meshes.example, vertexLayout, 0.05f); } @@ -675,13 +615,6 @@ public: VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &descriptorSets.quad)); - // Image descriptor for the offscreen color attachment image - VkDescriptorImageInfo texDescriptor = - vkTools::initializers::descriptorImageInfo( - offScreenFrameBuf.colorSampler, - offScreenFrameBuf.color.view, - VK_IMAGE_LAYOUT_GENERAL); - std::vector writeDescriptorSets = { // Binding 0 : Vertex shader uniform buffer @@ -695,7 +628,7 @@ public: descriptorSets.quad, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, - &texDescriptor), + &offscreenPass.descriptor), // Binding 2 : Fragment shader uniform buffer vkTools::initializers::writeDescriptorSet( descriptorSets.quad, @@ -803,7 +736,6 @@ public: 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.radialBlur)); // No blending (for debug display) @@ -813,17 +745,16 @@ public: // Phong pass shaderStages[0] = loadShader(getAssetPath() + "shaders/radialblur/phongpass.vert.spv", VK_SHADER_STAGE_VERTEX_BIT); shaderStages[1] = loadShader(getAssetPath() + "shaders/radialblur/phongpass.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT); - pipelineCreateInfo.layout = pipelineLayouts.scene; blendAttachmentState.blendEnable = VK_FALSE; depthStencilState.depthWriteEnable = VK_TRUE; - VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipelines.phongPass)); // Color only pass (offscreen blur base) shaderStages[0] = loadShader(getAssetPath() + "shaders/radialblur/colorpass.vert.spv", VK_SHADER_STAGE_VERTEX_BIT); shaderStages[1] = loadShader(getAssetPath() + "shaders/radialblur/colorpass.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT); - + pipelineCreateInfo.renderPass = offscreenPass.renderPass; + pipelineCreateInfo.layout = pipelineLayouts.radialBlur; VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipelines.colorPass)); } @@ -905,33 +836,22 @@ public: { VulkanExampleBase::prepareFrame(); - // The scene render command buffer has to wait for the offscreen - // rendering to be finished before we can use the framebuffer - // color image for sampling during final rendering - // To ensure this we use a dedicated offscreen synchronization - // semaphore that will be signaled when offscreen renderin - // has been finished - // This is necessary as an implementation may start both - // command buffers at the same time, there is no guarantee - // that command buffers will be executed in the order they - // have been submitted by the application - // Offscreen rendering // Wait for swap chain presentation to finish submitInfo.pWaitSemaphores = &semaphores.presentComplete; // Signal ready with offscreen semaphore - submitInfo.pSignalSemaphores = &offscreenSemaphore; + submitInfo.pSignalSemaphores = &offscreenPass.semaphore; // Submit work submitInfo.commandBufferCount = 1; - submitInfo.pCommandBuffers = &offScreenCmdBuffer; + submitInfo.pCommandBuffers = &offscreenPass.commandBuffer; VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE)); // Scene rendering // Wait for offscreen semaphore - submitInfo.pWaitSemaphores = &offscreenSemaphore; + submitInfo.pWaitSemaphores = &offscreenPass.semaphore; // Signal ready with render complete semaphpre submitInfo.pSignalSemaphores = &semaphores.renderComplete; @@ -945,9 +865,9 @@ public: void prepare() { VulkanExampleBase::prepare(); + loadAssets(); generateQuad(); - loadMeshes(); - prepareOffscreenFramebuffer(); + prepareOffscreen(); setupVertexDescriptions(); prepareUniformBuffers(); setupDescriptorSetLayout(); @@ -976,6 +896,19 @@ public: updateUniformBuffersScreen(); } + void toggleBlur() + { + blur = !blur; + updateUniformBuffersScene(); + reBuildCommandBuffers(); + } + + void toggleTextureDisplay() + { + displayTexture = !displayTexture; + reBuildCommandBuffers(); + } + virtual void keyPressed(uint32_t keyCode) { switch (keyCode) @@ -1001,79 +934,6 @@ public: textOverlay->addText("Press \"T\" to display offscreen texture", 5.0f, 105.0f, VulkanTextOverlay::alignLeft); #endif } - - void toggleBlur() - { - blur = !blur; - updateUniformBuffersScene(); - reBuildCommandBuffers(); - } - - void toggleTextureDisplay() - { - displayTexture = !displayTexture; - reBuildCommandBuffers(); - } - }; -VulkanExample *vulkanExample; - -#if defined(_WIN32) -LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - if (vulkanExample != NULL) - { - vulkanExample->handleMessages(hWnd, uMsg, wParam, lParam); - } - return (DefWindowProc(hWnd, uMsg, wParam, lParam)); -} -#elif defined(__linux__) && !defined(__ANDROID__) -static void handleEvent(const xcb_generic_event_t *event) -{ - if (vulkanExample != NULL) - { - vulkanExample->handleEvent(event); - } -} -#endif - -// Main entry point -#if defined(_WIN32) -// Windows entry point -int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR pCmdLine, int nCmdShow) -#elif defined(__ANDROID__) -// Android entry point -void android_main(android_app* state) -#elif defined(__linux__) -// Linux entry point -int main(const int argc, const char *argv[]) -#endif -{ -#if defined(__ANDROID__) - // Removing this may cause the compiler to omit the main entry point - // which would make the application crash at start - app_dummy(); -#endif - vulkanExample = new VulkanExample(); -#if defined(_WIN32) - vulkanExample->setupWindow(hInstance, WndProc); -#elif defined(__ANDROID__) - // Attach vulkan example to global android application state - state->userData = vulkanExample; - state->onAppCmd = VulkanExample::handleAppCommand; - state->onInputEvent = VulkanExample::handleAppInput; - vulkanExample->androidApp = state; -#elif defined(__linux__) - vulkanExample->setupWindow(); -#endif -#if !defined(__ANDROID__) - vulkanExample->initSwapchain(); - vulkanExample->prepare(); -#endif - vulkanExample->renderLoop(); - delete(vulkanExample); -#if !defined(__ANDROID__) - return 0; -#endif -} +VULKAN_EXAMPLE_MAIN()