// 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 "VkFramebuffer.hpp" #include "VkImageView.hpp" #include "VkRenderPass.hpp" #include "VkStringify.hpp" #include #include namespace vk { Framebuffer::Framebuffer(const VkFramebufferCreateInfo *pCreateInfo, void *mem) : attachments(reinterpret_cast(mem)) , extent{ pCreateInfo->width, pCreateInfo->height, pCreateInfo->layers } { const VkBaseInStructure *curInfo = reinterpret_cast(pCreateInfo->pNext); const VkFramebufferAttachmentsCreateInfo *attachmentsCreateInfo = nullptr; while(curInfo) { switch(curInfo->sType) { case VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENTS_CREATE_INFO: attachmentsCreateInfo = reinterpret_cast(curInfo); break; default: LOG_TRAP("pFramebufferCreateInfo->pNext->sType = %s", vk::Stringify(curInfo->sType).c_str()); break; } curInfo = curInfo->pNext; } if(pCreateInfo->flags & VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT) { // If flags includes VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT, the pNext chain **must** // include a VkFramebufferAttachmentsCreateInfo. ASSERT(attachmentsCreateInfo != nullptr); attachmentCount = attachmentsCreateInfo->attachmentImageInfoCount; for(uint32_t i = 0; i < attachmentCount; i++) { attachments[i] = nullptr; } } else { attachmentCount = pCreateInfo->attachmentCount; for(uint32_t i = 0; i < attachmentCount; i++) { attachments[i] = vk::Cast(pCreateInfo->pAttachments[i]); } } } void Framebuffer::destroy(const VkAllocationCallbacks *pAllocator) { vk::deallocate(attachments, pAllocator); } void Framebuffer::clear(const RenderPass *renderPass, uint32_t clearValueCount, const VkClearValue *pClearValues, const VkRect2D &renderArea) { ASSERT(attachmentCount == renderPass->getAttachmentCount()); const uint32_t count = std::min(clearValueCount, attachmentCount); for(uint32_t i = 0; i < count; i++) { const VkAttachmentDescription attachment = renderPass->getAttachment(i); VkImageAspectFlags aspectMask = Format(attachment.format).getAspects(); if(attachment.loadOp != VK_ATTACHMENT_LOAD_OP_CLEAR) aspectMask &= VK_IMAGE_ASPECT_STENCIL_BIT; if(attachment.stencilLoadOp != VK_ATTACHMENT_LOAD_OP_CLEAR) aspectMask &= ~VK_IMAGE_ASPECT_STENCIL_BIT; if(!aspectMask || !renderPass->isAttachmentUsed(i)) { continue; } if(renderPass->isMultiView()) { attachments[i]->clearWithLayerMask(pClearValues[i], aspectMask, renderArea, renderPass->getAttachmentViewMask(i)); } else { attachments[i]->clear(pClearValues[i], aspectMask, renderArea); } } } void Framebuffer::clearAttachment(const RenderPass *renderPass, uint32_t subpassIndex, const VkClearAttachment &attachment, const VkClearRect &rect) { VkSubpassDescription subpass = renderPass->getSubpass(subpassIndex); if(attachment.aspectMask == VK_IMAGE_ASPECT_COLOR_BIT) { ASSERT(attachment.colorAttachment < subpass.colorAttachmentCount); uint32_t attachmentIndex = subpass.pColorAttachments[attachment.colorAttachment].attachment; if(attachmentIndex != VK_ATTACHMENT_UNUSED) { ASSERT(attachmentIndex < attachmentCount); ImageView *imageView = attachments[attachmentIndex]; if(renderPass->isMultiView()) { imageView->clearWithLayerMask(attachment.clearValue, attachment.aspectMask, rect.rect, renderPass->getViewMask(subpassIndex)); } else { imageView->clear(attachment.clearValue, attachment.aspectMask, rect); } } } else if(attachment.aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { uint32_t attachmentIndex = subpass.pDepthStencilAttachment->attachment; if(attachmentIndex != VK_ATTACHMENT_UNUSED) { ASSERT(attachmentIndex < attachmentCount); ImageView *imageView = attachments[attachmentIndex]; if(renderPass->isMultiView()) { imageView->clearWithLayerMask(attachment.clearValue, attachment.aspectMask, rect.rect, renderPass->getViewMask(subpassIndex)); } else { imageView->clear(attachment.clearValue, attachment.aspectMask, rect); } } } } void Framebuffer::setAttachment(ImageView *imageView, uint32_t index) { ASSERT(index < attachmentCount); ASSERT(attachments[index] == nullptr); attachments[index] = imageView; } ImageView *Framebuffer::getAttachment(uint32_t index) const { return attachments[index]; } void Framebuffer::resolve(const RenderPass *renderPass, uint32_t subpassIndex) { auto const &subpass = renderPass->getSubpass(subpassIndex); if(subpass.pResolveAttachments) { for(uint32_t i = 0; i < subpass.colorAttachmentCount; i++) { uint32_t resolveAttachment = subpass.pResolveAttachments[i].attachment; if(resolveAttachment != VK_ATTACHMENT_UNUSED) { ImageView *imageView = attachments[subpass.pColorAttachments[i].attachment]; if(renderPass->isMultiView()) { imageView->resolveWithLayerMask(attachments[resolveAttachment], renderPass->getViewMask(subpassIndex)); } else { imageView->resolve(attachments[resolveAttachment]); } } } } if(renderPass->hasDepthStencilResolve() && subpass.pDepthStencilAttachment != nullptr) { VkSubpassDescriptionDepthStencilResolve dsResolve = renderPass->getSubpassDepthStencilResolve(subpassIndex); uint32_t depthStencilAttachment = subpass.pDepthStencilAttachment->attachment; if(depthStencilAttachment != VK_ATTACHMENT_UNUSED) { ImageView *imageView = attachments[depthStencilAttachment]; imageView->resolveDepthStencil(attachments[dsResolve.pDepthStencilResolveAttachment->attachment], dsResolve); } } } size_t Framebuffer::ComputeRequiredAllocationSize(const VkFramebufferCreateInfo *pCreateInfo) { const VkBaseInStructure *curInfo = reinterpret_cast(pCreateInfo->pNext); const VkFramebufferAttachmentsCreateInfo *attachmentsInfo = nullptr; while(curInfo) { switch(curInfo->sType) { case VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENTS_CREATE_INFO: attachmentsInfo = reinterpret_cast(curInfo); break; default: LOG_TRAP("pFramebufferCreateInfo->pNext->sType = %s", vk::Stringify(curInfo->sType).c_str()); break; } curInfo = curInfo->pNext; } if(pCreateInfo->flags & VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT) { ASSERT(attachmentsInfo != nullptr); return attachmentsInfo->attachmentImageInfoCount * sizeof(void *); } else { return pCreateInfo->attachmentCount * sizeof(void *); } } } // namespace vk