// Copyright 2018 The SwiftShader Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "VkRenderPass.hpp" #include "VkStringify.hpp" #include namespace { template size_t ComputeRequiredAllocationSizeT(const T *pCreateInfo) { size_t attachmentSize = pCreateInfo->attachmentCount * sizeof(VkAttachmentDescription) + pCreateInfo->attachmentCount * sizeof(int) // first use + pCreateInfo->attachmentCount * sizeof(uint32_t); // union of subpass view masks, per attachment size_t subpassesSize = 0; for(uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) { const auto &subpass = pCreateInfo->pSubpasses[i]; uint32_t nbAttachments = subpass.inputAttachmentCount + subpass.colorAttachmentCount; if(subpass.pResolveAttachments) { nbAttachments += subpass.colorAttachmentCount; } if(subpass.pDepthStencilAttachment) { nbAttachments += 1; } subpassesSize += sizeof(VkSubpassDescription) + sizeof(VkAttachmentReference) * nbAttachments + sizeof(uint32_t) * subpass.preserveAttachmentCount + sizeof(uint32_t); // view mask } size_t dependenciesSize = pCreateInfo->dependencyCount * sizeof(VkSubpassDependency); return attachmentSize + subpassesSize + dependenciesSize; } template void CopySubpasses(VkSubpassDescription *dst, const T *src, uint32_t count) { for(uint32_t i = 0; i < count; ++i) { dst[i].flags = src[i].flags; dst[i].pipelineBindPoint = src[i].pipelineBindPoint; dst[i].inputAttachmentCount = src[i].inputAttachmentCount; dst[i].pInputAttachments = nullptr; dst[i].colorAttachmentCount = src[i].colorAttachmentCount; dst[i].pColorAttachments = nullptr; dst[i].pResolveAttachments = nullptr; dst[i].pDepthStencilAttachment = nullptr; dst[i].preserveAttachmentCount = src[i].preserveAttachmentCount; dst[i].pPreserveAttachments = nullptr; } } template void CopyAttachmentDescriptions(VkAttachmentDescription *dst, const T *src, uint32_t count) { for(uint32_t i = 0; i < count; ++i) { dst[i].flags = src[i].flags; dst[i].format = src[i].format; dst[i].samples = src[i].samples; dst[i].loadOp = src[i].loadOp; dst[i].storeOp = src[i].storeOp; dst[i].stencilLoadOp = src[i].stencilLoadOp; dst[i].stencilStoreOp = src[i].stencilStoreOp; dst[i].initialLayout = src[i].initialLayout; dst[i].finalLayout = src[i].finalLayout; } } template void CopyAttachmentReferences(VkAttachmentReference *dst, const T *src, uint32_t count) { for(uint32_t i = 0; i < count; ++i) { dst[i].attachment = src[i].attachment; dst[i].layout = src[i].layout; } } template void CopySubpassDependencies(VkSubpassDependency *dst, const T *src, uint32_t count) { for(uint32_t i = 0; i < count; ++i) { dst[i].srcSubpass = src[i].srcSubpass; dst[i].dstSubpass = src[i].dstSubpass; dst[i].srcStageMask = src[i].srcStageMask; dst[i].dstStageMask = src[i].dstStageMask; dst[i].srcAccessMask = src[i].srcAccessMask; dst[i].dstAccessMask = src[i].dstAccessMask; dst[i].dependencyFlags = src[i].dependencyFlags; } } bool GetViewMasks(const VkRenderPassCreateInfo *pCreateInfo, uint32_t *masks) { return false; } bool GetViewMasks(const VkRenderPassCreateInfo2KHR *pCreateInfo, uint32_t *masks) { for(uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) { masks[i] = pCreateInfo->pSubpasses[i].viewMask; } return true; } } // namespace namespace vk { RenderPass::RenderPass(const VkRenderPassCreateInfo *pCreateInfo, void *mem) : attachmentCount(pCreateInfo->attachmentCount) , subpassCount(pCreateInfo->subpassCount) , dependencyCount(pCreateInfo->dependencyCount) { init(pCreateInfo, &mem); } RenderPass::RenderPass(const VkRenderPassCreateInfo2KHR *pCreateInfo, void *mem) : attachmentCount(pCreateInfo->attachmentCount) , subpassCount(pCreateInfo->subpassCount) , dependencyCount(pCreateInfo->dependencyCount) { init(pCreateInfo, &mem); // Note: the init function above ignores: // - pCorrelatedViewMasks: This provides a potential performance optimization // - VkAttachmentReference2::aspectMask : This specifies which aspects may be used // - VkSubpassDependency2::viewOffset : This is the same as VkRenderPassMultiviewCreateInfo::pViewOffsets, which is currently ignored // - Any pNext pointer in VkRenderPassCreateInfo2KHR's internal structures char *hostMemory = reinterpret_cast(mem); // Handle the extensions in each subpass for(uint32_t i = 0; i < subpassCount; i++) { auto const &subpass = pCreateInfo->pSubpasses[i]; const VkBaseInStructure *extension = reinterpret_cast(subpass.pNext); while(extension) { switch(extension->sType) { case VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE: { const auto *ext = reinterpret_cast(extension); // If any subpass includes depthStencilResolve, allocate a DSR struct for each subpass // This allows us to index into subpassDepthStencilResolves using the subpass index. if(ext->pDepthStencilResolveAttachment != nullptr && ext->pDepthStencilResolveAttachment->attachment != VK_ATTACHMENT_UNUSED) { if(subpassDepthStencilResolves == nullptr) { subpassDepthStencilResolves = reinterpret_cast(hostMemory); hostMemory += subpassCount * sizeof(VkSubpassDescriptionDepthStencilResolve); for(uint32_t subpass = 0; subpass < subpassCount; subpass++) { subpassDepthStencilResolves[subpass].sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE; subpassDepthStencilResolves[subpass].pNext = nullptr; subpassDepthStencilResolves[subpass].depthResolveMode = VK_RESOLVE_MODE_NONE; subpassDepthStencilResolves[subpass].stencilResolveMode = VK_RESOLVE_MODE_NONE; subpassDepthStencilResolves[subpass].pDepthStencilResolveAttachment = nullptr; } } VkAttachmentReference2 *reference = reinterpret_cast(hostMemory); hostMemory += sizeof(VkAttachmentReference2); subpassDepthStencilResolves[i].depthResolveMode = ext->depthResolveMode; subpassDepthStencilResolves[i].stencilResolveMode = ext->stencilResolveMode; reference->pNext = nullptr; reference->sType = ext->pDepthStencilResolveAttachment->sType; reference->attachment = ext->pDepthStencilResolveAttachment->attachment; reference->layout = ext->pDepthStencilResolveAttachment->layout; reference->aspectMask = ext->pDepthStencilResolveAttachment->aspectMask; subpassDepthStencilResolves[i].pDepthStencilResolveAttachment = reinterpret_cast(reference); MarkFirstUse(reference->attachment, i); } } break; default: LOG_TRAP("VkRenderPassCreateInfo2KHR->subpass[%d]->pNext sType: %s", i, vk::Stringify(extension->sType).c_str()); break; } extension = extension->pNext; } } } template void RenderPass::init(const T *pCreateInfo, void **mem) { char *hostMemory = reinterpret_cast(*mem); // subpassCount must be greater than 0 ASSERT(pCreateInfo->subpassCount > 0); size_t subpassesSize = pCreateInfo->subpassCount * sizeof(VkSubpassDescription); subpasses = reinterpret_cast(hostMemory); CopySubpasses(subpasses, pCreateInfo->pSubpasses, pCreateInfo->subpassCount); hostMemory += subpassesSize; uint32_t *masks = reinterpret_cast(hostMemory); hostMemory += subpassCount * sizeof(uint32_t); if(attachmentCount > 0) { size_t attachmentSize = pCreateInfo->attachmentCount * sizeof(VkAttachmentDescription); attachments = reinterpret_cast(hostMemory); CopyAttachmentDescriptions(attachments, pCreateInfo->pAttachments, pCreateInfo->attachmentCount); hostMemory += attachmentSize; size_t firstUseSize = pCreateInfo->attachmentCount * sizeof(int); attachmentFirstUse = reinterpret_cast(hostMemory); hostMemory += firstUseSize; attachmentViewMasks = reinterpret_cast(hostMemory); hostMemory += pCreateInfo->attachmentCount * sizeof(uint32_t); for(auto i = 0u; i < pCreateInfo->attachmentCount; i++) { attachmentFirstUse[i] = -1; attachmentViewMasks[i] = 0; } } const VkBaseInStructure *extensionCreateInfo = reinterpret_cast(pCreateInfo->pNext); while(extensionCreateInfo) { switch(extensionCreateInfo->sType) { case VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO: { // Renderpass uses multiview if this structure is present AND some subpass specifies // a nonzero view mask auto const *multiviewCreateInfo = reinterpret_cast(extensionCreateInfo); for(auto i = 0u; i < pCreateInfo->subpassCount; i++) { masks[i] = multiviewCreateInfo->pViewMasks[i]; // This is now a multiview renderpass, so make the masks available if(masks[i]) { viewMasks = masks; } } break; } default: WARN("pCreateInfo->pNext sType = %s", vk::Stringify(extensionCreateInfo->sType).c_str()); break; } extensionCreateInfo = extensionCreateInfo->pNext; } if(!viewMasks && (GetViewMasks(pCreateInfo, masks))) { for(auto i = 0u; i < pCreateInfo->subpassCount; i++) { if(masks[i]) { viewMasks = masks; } } } // Deep copy subpasses for(uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) { const auto &subpass = pCreateInfo->pSubpasses[i]; if(subpass.inputAttachmentCount > 0) { size_t inputAttachmentsSize = subpass.inputAttachmentCount * sizeof(VkAttachmentReference); subpasses[i].pInputAttachments = reinterpret_cast(hostMemory); CopyAttachmentReferences(const_cast(subpasses[i].pInputAttachments), pCreateInfo->pSubpasses[i].pInputAttachments, subpass.inputAttachmentCount); hostMemory += inputAttachmentsSize; for(auto j = 0u; j < subpasses[i].inputAttachmentCount; j++) { if(subpass.pInputAttachments[j].attachment != VK_ATTACHMENT_UNUSED) MarkFirstUse(subpass.pInputAttachments[j].attachment, i); } } if(subpass.colorAttachmentCount > 0) { size_t colorAttachmentsSize = subpass.colorAttachmentCount * sizeof(VkAttachmentReference); subpasses[i].pColorAttachments = reinterpret_cast(hostMemory); CopyAttachmentReferences(const_cast(subpasses[i].pColorAttachments), subpass.pColorAttachments, subpass.colorAttachmentCount); hostMemory += colorAttachmentsSize; if(subpass.pResolveAttachments) { subpasses[i].pResolveAttachments = reinterpret_cast(hostMemory); CopyAttachmentReferences(const_cast(subpasses[i].pResolveAttachments), subpass.pResolveAttachments, subpass.colorAttachmentCount); hostMemory += colorAttachmentsSize; } for(auto j = 0u; j < subpasses[i].colorAttachmentCount; j++) { if(subpass.pColorAttachments[j].attachment != VK_ATTACHMENT_UNUSED) MarkFirstUse(subpass.pColorAttachments[j].attachment, i); if(subpass.pResolveAttachments && subpass.pResolveAttachments[j].attachment != VK_ATTACHMENT_UNUSED) MarkFirstUse(subpass.pResolveAttachments[j].attachment, i); } } if(subpass.pDepthStencilAttachment) { subpasses[i].pDepthStencilAttachment = reinterpret_cast(hostMemory); CopyAttachmentReferences(const_cast(subpasses[i].pDepthStencilAttachment), subpass.pDepthStencilAttachment, 1); hostMemory += sizeof(VkAttachmentReference); if(subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) MarkFirstUse(subpass.pDepthStencilAttachment->attachment, i); } if(subpass.preserveAttachmentCount > 0) { size_t preserveAttachmentSize = subpass.preserveAttachmentCount * sizeof(uint32_t); subpasses[i].pPreserveAttachments = reinterpret_cast(hostMemory); for(uint32_t j = 0u; j < subpass.preserveAttachmentCount; j++) { const_cast(subpasses[i].pPreserveAttachments)[j] = pCreateInfo->pSubpasses[i].pPreserveAttachments[j]; } hostMemory += preserveAttachmentSize; for(auto j = 0u; j < subpasses[i].preserveAttachmentCount; j++) { if(subpass.pPreserveAttachments[j] != VK_ATTACHMENT_UNUSED) MarkFirstUse(subpass.pPreserveAttachments[j], i); } } } if(pCreateInfo->dependencyCount > 0) { dependencies = reinterpret_cast(hostMemory); CopySubpassDependencies(dependencies, pCreateInfo->pDependencies, pCreateInfo->dependencyCount); hostMemory += dependencyCount * sizeof(VkSubpassDependency); } *mem = hostMemory; } void RenderPass::destroy(const VkAllocationCallbacks *pAllocator) { vk::deallocate(subpasses, pAllocator); // attachments and dependencies are in the same allocation } size_t RenderPass::ComputeRequiredAllocationSize(const VkRenderPassCreateInfo *pCreateInfo) { return ComputeRequiredAllocationSizeT(pCreateInfo); } size_t RenderPass::ComputeRequiredAllocationSize(const VkRenderPassCreateInfo2KHR *pCreateInfo) { size_t requiredMemory = ComputeRequiredAllocationSizeT(pCreateInfo); // Calculate the memory required to handle depth stencil resolves bool usesDSR = false; for(uint32_t i = 0; i < pCreateInfo->subpassCount; i++) { auto const &subpass = pCreateInfo->pSubpasses[i]; const VkBaseInStructure *extension = reinterpret_cast(subpass.pNext); while(extension) { switch(extension->sType) { case VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE: { const auto *ext = reinterpret_cast(extension); if(ext->pDepthStencilResolveAttachment != nullptr && ext->pDepthStencilResolveAttachment->attachment != VK_ATTACHMENT_UNUSED) { if(!usesDSR) { // If any subpass uses DSR, then allocate a VkSubpassDescriptionDepthStencilResolve // for all subpasses. This allows us to index into our DSR structs using the subpass index. requiredMemory += sizeof(VkSubpassDescriptionDepthStencilResolve) * pCreateInfo->subpassCount; usesDSR = true; } // For each subpass that actually uses DSR, allocate a VkAttachmentReference2. requiredMemory += sizeof(VkAttachmentReference2); } } break; default: LOG_TRAP("VkRenderPassCreateInfo2KHR->subpass[%d]->pNext sType: %s", i, vk::Stringify(extension->sType).c_str()); break; } extension = extension->pNext; } } return requiredMemory; } void RenderPass::getRenderAreaGranularity(VkExtent2D *pGranularity) const { pGranularity->width = 1; pGranularity->height = 1; } void RenderPass::MarkFirstUse(int attachment, int subpass) { // FIXME: we may not actually need to track attachmentFirstUse if we're going to eagerly // clear attachments at the start of the renderpass; can use attachmentViewMasks always instead. if(attachmentFirstUse[attachment] == -1) attachmentFirstUse[attachment] = subpass; if(isMultiView()) attachmentViewMasks[attachment] |= viewMasks[subpass]; } } // namespace vk