diff --git a/base/vulkanframebuffer.hpp b/base/vulkanframebuffer.hpp index 86a00e1f..26c59dfa 100644 --- a/base/vulkanframebuffer.hpp +++ b/base/vulkanframebuffer.hpp @@ -27,6 +27,8 @@ namespace vk VkImageView view; VkFormat format; VkImageSubresourceRange subresourceRange; + VkAttachmentDescription description; + VkImageLayout initialLayout; /** * @brief Returns true if the attachment has a depth component @@ -59,6 +61,15 @@ namespace vk }; return std::find(formats.begin(), formats.end(), format) != std::end(formats); } + + /** + * @brief Returns true if the attachment is a depth and/or stencil attachment + */ + bool isDepthStencil() + { + return(hasDepth() || hasStencil()); + } + }; /** @@ -69,10 +80,7 @@ namespace vk uint32_t width, height; uint32_t layerCount; VkFormat format; - // todo: could be derived from format VkImageUsageFlags usage; - // todo: rename - bool sample; }; /** @@ -101,19 +109,20 @@ namespace vk } /** - * Destroy and free resources used for the framebuffer and all of it's attachments + * Destroy and free Vulkan resources used for the framebuffer and all of it's attachments */ - void FreeResources(VkDevice device) + ~Framebuffer() { + assert(vulkanDevice); for (auto attachment : attachments) { - vkDestroyImage(device, attachment.image, nullptr); - vkDestroyImageView(device, attachment.view, nullptr); - vkFreeMemory(device, attachment.memory, nullptr); + vkDestroyImage(vulkanDevice->device, attachment.image, nullptr); + vkDestroyImageView(vulkanDevice->device, attachment.view, nullptr); + vkFreeMemory(vulkanDevice->device, attachment.memory, nullptr); } - vkDestroySampler(device, sampler, nullptr); - vkDestroyRenderPass(device, renderPass, nullptr); - vkDestroyFramebuffer(device, framebuffer, nullptr); + vkDestroySampler(vulkanDevice->device, sampler, nullptr); + vkDestroyRenderPass(vulkanDevice->device, renderPass, nullptr); + vkDestroyFramebuffer(vulkanDevice->device, framebuffer, nullptr); } /** @@ -134,12 +143,16 @@ namespace vk VkImageLayout imageLayout; // Select aspect mask and layout depending on usage + + // Color attachment if (createinfo.usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) { aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - imageLayout = createinfo.sample ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + attachment.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + imageLayout = (createinfo.usage & VK_IMAGE_USAGE_SAMPLED_BIT) ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; } + // Depth (and/or stencil) attachment if (createinfo.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { if (attachment.hasDepth()) @@ -150,7 +163,8 @@ namespace vk { aspectMask = aspectMask | VK_IMAGE_ASPECT_STENCIL_BIT; } - imageLayout = createinfo.sample ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + attachment.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + imageLayout = (createinfo.usage & VK_IMAGE_USAGE_SAMPLED_BIT) ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; } assert(aspectMask > 0); @@ -202,9 +216,135 @@ namespace vk imageView.image = attachment.image; VK_CHECK_RESULT(vkCreateImageView(vulkanDevice->device, &imageView, nullptr, &attachment.view)); + // Fill attachment description + attachment.description = {}; + attachment.description.samples = VK_SAMPLE_COUNT_1_BIT; + attachment.description.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + attachment.description.storeOp = (createinfo.usage & VK_IMAGE_USAGE_SAMPLED_BIT) ? VK_ATTACHMENT_STORE_OP_STORE : VK_ATTACHMENT_STORE_OP_DONT_CARE; + attachment.description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + attachment.description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + attachment.description.format = createinfo.format; + if (attachment.hasDepth() || attachment.hasStencil()) + { + attachment.description.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + attachment.description.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + } + else + { + attachment.description.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + attachment.description.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + } + attachments.push_back(attachment); return static_cast(attachments.size() - 1); } + + /** + * Creates a default sampler for sampling from any of the framebuffer attachments + * Applications are free to create their own samplers for different use cases + * + * @param magFilter Magnification filter for lookups + * @param minFilter Minification filter for lookups + * @param adressMode Adressing mode for the U,V and W coordinates + * + * @return VkResult for the sampler creation + */ + VkResult createSampler(VkFilter magFilter, VkFilter minFilter, VkSamplerAddressMode adressMode) + { + VkSamplerCreateInfo samplerInfo = vkTools::initializers::samplerCreateInfo(); + samplerInfo.magFilter = magFilter; + samplerInfo.minFilter = minFilter; + samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; + samplerInfo.addressModeU = adressMode; + samplerInfo.addressModeV = adressMode; + samplerInfo.addressModeW = adressMode; + samplerInfo.mipLodBias = 0.0f; + samplerInfo.maxAnisotropy = 0; + samplerInfo.minLod = 0.0f; + samplerInfo.maxLod = 1.0f; + samplerInfo.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; + return vkCreateSampler(vulkanDevice->device, &samplerInfo, nullptr, &sampler); + } + + /** + * Creates a default render pass setup with one sub pass + * + * @return VK_SUCCESS if all resources have been created successfully + */ + VkResult createRenderPass() + { + std::vector attachmentDescriptions; + for (auto& attachment : attachments) + { + attachmentDescriptions.push_back(attachment.description); + }; + + // Collect attachment references + std::vector colorReferences; + VkAttachmentReference depthReference = {}; + bool hasDepth = false; + bool hasColor = false; + + uint32_t attachmentIndex = 0; + + for (auto& attachment : attachments) + { + if (attachment.isDepthStencil()) + { + // Only one depth attachment allowed + assert(!hasDepth); + depthReference.attachment = attachmentIndex; + depthReference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + hasDepth = true; + } + else + { + colorReferences.push_back({ attachmentIndex, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL }); + hasColor = true; + } + attachmentIndex++; + }; + + // Default render pass setup uses only one subpass + VkSubpassDescription subpass = {}; + subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + if (hasColor) + { + subpass.pColorAttachments = colorReferences.data(); + subpass.colorAttachmentCount = static_cast(colorReferences.size()); + } + if (hasDepth) + { + subpass.pDepthStencilAttachment = &depthReference; + } + + // Create render pass + VkRenderPassCreateInfo renderPassInfo = {}; + renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + renderPassInfo.pAttachments = attachmentDescriptions.data(); + renderPassInfo.attachmentCount = static_cast(attachmentDescriptions.size()); + renderPassInfo.subpassCount = 1; + renderPassInfo.pSubpasses = &subpass; + VK_CHECK_RESULT(vkCreateRenderPass(vulkanDevice->device, &renderPassInfo, nullptr, &renderPass)); + + std::vector attachmentViews; + for (auto attachment : attachments) + { + attachmentViews.push_back(attachment.view); + } + + VkFramebufferCreateInfo framebufferInfo = {}; + framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; + framebufferInfo.renderPass = renderPass; + framebufferInfo.pAttachments = attachmentViews.data(); + framebufferInfo.attachmentCount = static_cast(attachmentViews.size()); + framebufferInfo.width = width; + framebufferInfo.height = height; + framebufferInfo.layers = 1; + VK_CHECK_RESULT(vkCreateFramebuffer(vulkanDevice->device, &framebufferInfo, nullptr, &framebuffer)); + + return VK_SUCCESS; + } }; } \ No newline at end of file