diff --git a/offscreen/offscreen.cpp b/offscreen/offscreen.cpp index c52a3876..51565375 100644 --- a/offscreen/offscreen.cpp +++ b/offscreen/offscreen.cpp @@ -113,8 +113,7 @@ public: int32_t width, height; VkFramebuffer frameBuffer; FrameBufferAttachment color, depth; - // Texture target for offscreen framebuffer - vkTools::VulkanTexture textureTarget; + VkSampler colorSampler; } offScreenFrameBuf; VkCommandBuffer offScreenCmdBuffer = VK_NULL_HANDLE; @@ -141,8 +140,8 @@ public: // Note : Inherited destructor cleans up resources stored in base class // Textures - textureLoader->destroyTexture(offScreenFrameBuf.textureTarget); textureLoader->destroyTexture(textures.colorMap); + vkDestroySampler(device, offScreenFrameBuf.colorSampler, nullptr); // Frame buffer @@ -184,91 +183,9 @@ public: vkDestroySemaphore(device, offscreenSemaphore, nullptr); } - // Preapre an empty texture as the blit target from - // the offscreen framebuffer - void prepareTextureTarget(uint32_t width, uint32_t height, VkFormat format) - { - // Get device properties for the requested texture format - VkFormatProperties formatProperties; - vkGetPhysicalDeviceFormatProperties(physicalDevice, 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); - - // Prepare blit target texture - offScreenFrameBuf.textureTarget.width = width; - offScreenFrameBuf.textureTarget.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; - // 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; - imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED; - - VkMemoryAllocateInfo memAllocInfo = vkTools::initializers::memoryAllocateInfo(); - VkMemoryRequirements memReqs; - - VK_CHECK_RESULT(vkCreateImage(device, &imageCreateInfo, nullptr, &offScreenFrameBuf.textureTarget.image)); - vkGetImageMemoryRequirements(device, offScreenFrameBuf.textureTarget.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.textureTarget.deviceMemory)); - VK_CHECK_RESULT(vkBindImageMemory(device, offScreenFrameBuf.textureTarget.image, offScreenFrameBuf.textureTarget.deviceMemory, 0)); - - // Get a primary command buffer for submitting image layout transition - VkCommandBuffer layoutCmd = VulkanExampleBase::createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true); - - // Image memory barrier - // Set initial layout for the offscreen texture transfer destination - // Will be transformed while updating the texture - offScreenFrameBuf.textureTarget.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - vkTools::setImageLayout( - layoutCmd, - offScreenFrameBuf.textureTarget.image, - VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_PREINITIALIZED, - offScreenFrameBuf.textureTarget.imageLayout); - - // Submit the command buffer to apply the image memory barrier - VulkanExampleBase::flushCommandBuffer(layoutCmd, queue, true); - - // 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, &offScreenFrameBuf.textureTarget.sampler)); - - // Create image view - VkImageViewCreateInfo view = {}; - view.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - view.pNext = NULL; - 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 = offScreenFrameBuf.textureTarget.image; - VK_CHECK_RESULT(vkCreateImageView(device, &view, nullptr, &offScreenFrameBuf.textureTarget.view)); - } - - // Prepare a new framebuffer for offscreen rendering - // The contents of this framebuffer are then - // blitted to our render target + // Setup the offscreen framebuffer for rendering the mirrored scene + // The color attachment of this framebuffer will then be used + // to sample frame in the fragment shader of the final pass void prepareOffscreenFramebuffer() { offScreenFrameBuf.width = FB_DIM; @@ -292,9 +209,8 @@ public: 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; + // We will sample directly from the color attachment + image.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; VkMemoryAllocateInfo memAlloc = vkTools::initializers::memoryAllocateInfo(); VkMemoryRequirements memReqs; @@ -302,7 +218,6 @@ public: VkImageViewCreateInfo colorImageView = vkTools::initializers::imageViewCreateInfo(); colorImageView.viewType = VK_IMAGE_VIEW_TYPE_2D; colorImageView.format = fbColorFormat; - colorImageView.flags = 0; colorImageView.subresourceRange = {}; colorImageView.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; colorImageView.subresourceRange.baseMipLevel = 0; @@ -320,16 +235,34 @@ public: // 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_COLOR_ATTACHMENT_OPTIMAL); + 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)); + // Depth stencil attachment image.format = fbDepthFormat; image.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; @@ -408,6 +341,14 @@ public: VK_CHECK_RESULT(vkBeginCommandBuffer(offScreenCmdBuffer, &cmdBufInfo)); + // Change back layout of the color attachment after sampling in the fragment shader + vkTools::setImageLayout( + offScreenCmdBuffer, + offScreenFrameBuf.color.image, + VK_IMAGE_ASPECT_DEPTH_BIT, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + vkCmdBeginRenderPass(offScreenCmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); VkViewport viewport = vkTools::initializers::viewport((float)offScreenFrameBuf.width, (float)offScreenFrameBuf.height, 0.0f, 1.0f); @@ -427,74 +368,12 @@ public: vkCmdEndRenderPass(offScreenCmdBuffer); - // Make sure color writes to the framebuffer are finished before using it as transfer source + // 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_ASPECT_DEPTH_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); - - // Transform texture target to transfer source - 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 textuer 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)); @@ -744,11 +623,11 @@ public: VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &descriptorSets.mirror)); - // Image descriptor for the offscreen mirror texture + // Image descriptor for the offscreen mirror color attachment image VkDescriptorImageInfo texDescriptorMirror = vkTools::initializers::descriptorImageInfo( - offScreenFrameBuf.textureTarget.sampler, - offScreenFrameBuf.textureTarget.view, + offScreenFrameBuf.colorSampler, + offScreenFrameBuf.color.view, VK_IMAGE_LAYOUT_GENERAL); // Image descriptor for the color map @@ -789,7 +668,7 @@ public: { // Binding 0 : Vertex shader uniform buffer vkTools::initializers::writeDescriptorSet( - descriptorSets.debugQuad, + descriptorSets.debugQuad, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0, &uniformData.vsDebugQuad.descriptor), @@ -827,7 +706,7 @@ public: { // Binding 0 : Vertex shader uniform buffer vkTools::initializers::writeDescriptorSet( - descriptorSets.offscreen, + descriptorSets.offscreen, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0, &uniformData.vsOffScreen.descriptor) @@ -1081,14 +960,13 @@ public: loadTextures(); generateQuad(); loadMeshes(); + prepareOffscreenFramebuffer(); setupVertexDescriptions(); prepareUniformBuffers(); - prepareTextureTarget(TEX_DIM, TEX_DIM, TEX_FORMAT); setupDescriptorSetLayout(); preparePipelines(); setupDescriptorPool(); setupDescriptorSet(); - prepareOffscreenFramebuffer(); buildCommandBuffers(); buildOffscreenCommandBuffer(); prepared = true; diff --git a/shadowmapping/shadowmapping.cpp b/shadowmapping/shadowmapping.cpp index 898ee0fa..288ebebd 100644 --- a/shadowmapping/shadowmapping.cpp +++ b/shadowmapping/shadowmapping.cpp @@ -155,6 +155,7 @@ public: // Note : Inherited destructor cleans up resources stored in base class // Frame buffer + vkDestroySampler(device, offScreenFrameBuf.depthSampler, nullptr); // Color attachment vkDestroyImageView(device, offScreenFrameBuf.color.view, nullptr); @@ -329,7 +330,7 @@ public: VK_CHECK_RESULT(vkBindImageMemory(device, offScreenFrameBuf.depth.image, offScreenFrameBuf.depth.mem, 0)); // Set the initial layout to shader read instead of attachment - // This is done as teh render loop does the actualy image layout transitions + // This is done as the render loop does the actualy image layout transitions vkTools::setImageLayout( layoutCmd, offScreenFrameBuf.depth.image, @@ -439,7 +440,7 @@ public: vkCmdEndRenderPass(offScreenCmdBuffer); - // Change back layout of the depth attachment after sampling in the fragment shader + // Change layout of the depth attachment for sampling in the fragment shader vkTools::setImageLayout( offScreenCmdBuffer, offScreenFrameBuf.depth.image,