/* * Copyright 2015 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "GrVkRenderPass.h" #include "GrProcessor.h" #include "GrVkFramebuffer.h" #include "GrVkGpu.h" #include "GrVkRenderTarget.h" #include "GrVkUtil.h" typedef GrVkRenderPass::AttachmentsDescriptor::AttachmentDesc AttachmentDesc; void setup_vk_attachment_description(VkAttachmentDescription* attachment, const AttachmentDesc& desc, VkImageLayout layout) { attachment->flags = 0; attachment->format = desc.fFormat; SkAssertResult(GrSampleCountToVkSampleCount(desc.fSamples, &attachment->samples)); switch (layout) { case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: attachment->loadOp = desc.fLoadStoreOps.fLoadOp; attachment->storeOp = desc.fLoadStoreOps.fStoreOp; attachment->stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; attachment->stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; break; case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: attachment->loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; attachment->storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; attachment->stencilLoadOp = desc.fLoadStoreOps.fLoadOp; attachment->stencilStoreOp = desc.fLoadStoreOps.fStoreOp; break; default: SK_ABORT("Unexpected attachment layout"); } attachment->initialLayout = layout; attachment->finalLayout = layout; } void GrVkRenderPass::initSimple(const GrVkGpu* gpu, const GrVkRenderTarget& target) { static const GrVkRenderPass::LoadStoreOps kBasicLoadStoreOps(VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE); this->init(gpu, target, kBasicLoadStoreOps, kBasicLoadStoreOps); } void GrVkRenderPass::init(const GrVkGpu* gpu, const LoadStoreOps& colorOp, const LoadStoreOps& stencilOp) { uint32_t numAttachments = fAttachmentsDescriptor.fAttachmentCount; // Attachment descriptions to be set on the render pass SkTArray attachments(numAttachments); attachments.reset(numAttachments); memset(attachments.begin(), 0, numAttachments * sizeof(VkAttachmentDescription)); // Refs to attachments on the render pass (as described by teh VkAttachmentDescription above), // that are used by the subpass. VkAttachmentReference colorRef; VkAttachmentReference stencilRef; uint32_t currentAttachment = 0; // Go through each of the attachment types (color, stencil) and set the necessary // on the various Vk structs. VkSubpassDescription subpassDesc; memset(&subpassDesc, 0, sizeof(VkSubpassDescription)); subpassDesc.flags = 0; subpassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; subpassDesc.inputAttachmentCount = 0; subpassDesc.pInputAttachments = nullptr; subpassDesc.pResolveAttachments = nullptr; if (fAttachmentFlags & kColor_AttachmentFlag) { // set up color attachment fAttachmentsDescriptor.fColor.fLoadStoreOps = colorOp; setup_vk_attachment_description(&attachments[currentAttachment], fAttachmentsDescriptor.fColor, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); // setup subpass use of attachment colorRef.attachment = currentAttachment++; colorRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; subpassDesc.colorAttachmentCount = 1; if (VK_ATTACHMENT_LOAD_OP_CLEAR == colorOp.fLoadOp) { fClearValueCount = colorRef.attachment + 1; } } else { // I don't think there should ever be a time where we don't have a color attachment SkASSERT(false); colorRef.attachment = VK_ATTACHMENT_UNUSED; colorRef.layout = VK_IMAGE_LAYOUT_UNDEFINED; subpassDesc.colorAttachmentCount = 0; } subpassDesc.pColorAttachments = &colorRef; if (fAttachmentFlags & kStencil_AttachmentFlag) { // set up stencil attachment fAttachmentsDescriptor.fStencil.fLoadStoreOps = stencilOp; setup_vk_attachment_description(&attachments[currentAttachment], fAttachmentsDescriptor.fStencil, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); // setup subpass use of attachment stencilRef.attachment = currentAttachment++; stencilRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; if (VK_ATTACHMENT_LOAD_OP_CLEAR == stencilOp.fLoadOp) { fClearValueCount = SkTMax(fClearValueCount, stencilRef.attachment + 1); } } else { stencilRef.attachment = VK_ATTACHMENT_UNUSED; stencilRef.layout = VK_IMAGE_LAYOUT_UNDEFINED; } subpassDesc.pDepthStencilAttachment = &stencilRef; subpassDesc.preserveAttachmentCount = 0; subpassDesc.pPreserveAttachments = nullptr; SkASSERT(numAttachments == currentAttachment); // Create the VkRenderPass compatible with the attachment descriptions above VkRenderPassCreateInfo createInfo; memset(&createInfo, 0, sizeof(VkRenderPassCreateInfo)); createInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; createInfo.pNext = nullptr; createInfo.flags = 0; createInfo.attachmentCount = numAttachments; createInfo.pAttachments = attachments.begin(); createInfo.subpassCount = 1; createInfo.pSubpasses = &subpassDesc; createInfo.dependencyCount = 0; createInfo.pDependencies = nullptr; GR_VK_CALL_ERRCHECK(gpu->vkInterface(), CreateRenderPass(gpu->device(), &createInfo, nullptr, &fRenderPass)); // Get granularity for this render pass GR_VK_CALL(gpu->vkInterface(), GetRenderAreaGranularity(gpu->device(), fRenderPass, &fGranularity)); } void GrVkRenderPass::init(const GrVkGpu* gpu, const GrVkRenderPass& compatibleRenderPass, const LoadStoreOps& colorOp, const LoadStoreOps& stencilOp) { fAttachmentFlags = compatibleRenderPass.fAttachmentFlags; fAttachmentsDescriptor = compatibleRenderPass.fAttachmentsDescriptor; this->init(gpu, colorOp, stencilOp); } void GrVkRenderPass::init(const GrVkGpu* gpu, const GrVkRenderTarget& target, const LoadStoreOps& colorOp, const LoadStoreOps& stencilOp) { // Get attachment information from render target. This includes which attachments the render // target has (color, stencil) and the attachments format and sample count. target.getAttachmentsDescriptor(&fAttachmentsDescriptor, &fAttachmentFlags); this->init(gpu, colorOp, stencilOp); } void GrVkRenderPass::freeGPUData(GrVkGpu* gpu) const { if (!(fAttachmentFlags & kExternal_AttachmentFlag)) { GR_VK_CALL(gpu->vkInterface(), DestroyRenderPass(gpu->device(), fRenderPass, nullptr)); } } bool GrVkRenderPass::colorAttachmentIndex(uint32_t* index) const { *index = fColorAttachmentIndex; if ((fAttachmentFlags & kColor_AttachmentFlag) || (fAttachmentFlags & kExternal_AttachmentFlag)) { return true; } return false; } // Works under the assumption that stencil attachment will always be after the color and resolve // attachment. bool GrVkRenderPass::stencilAttachmentIndex(uint32_t* index) const { *index = 0; if (fAttachmentFlags & kColor_AttachmentFlag) { ++(*index); } if (fAttachmentFlags & kStencil_AttachmentFlag) { return true; } return false; } bool GrVkRenderPass::isCompatible(const AttachmentsDescriptor& desc, const AttachmentFlags& flags) const { SkASSERT(!(fAttachmentFlags & kExternal_AttachmentFlag)); if (flags != fAttachmentFlags) { return false; } if (fAttachmentFlags & kColor_AttachmentFlag) { if (!fAttachmentsDescriptor.fColor.isCompatible(desc.fColor)) { return false; } } if (fAttachmentFlags & kStencil_AttachmentFlag) { if (!fAttachmentsDescriptor.fStencil.isCompatible(desc.fStencil)) { return false; } } return true; } bool GrVkRenderPass::isCompatible(const GrVkRenderTarget& target) const { SkASSERT(!(fAttachmentFlags & kExternal_AttachmentFlag)); AttachmentsDescriptor desc; AttachmentFlags flags; target.getAttachmentsDescriptor(&desc, &flags); return this->isCompatible(desc, flags); } bool GrVkRenderPass::isCompatible(const GrVkRenderPass& renderPass) const { SkASSERT(!(fAttachmentFlags & kExternal_AttachmentFlag)); return this->isCompatible(renderPass.fAttachmentsDescriptor, renderPass.fAttachmentFlags); } bool GrVkRenderPass::isCompatibleExternalRP(VkRenderPass renderPass) const { SkASSERT(fAttachmentFlags & kExternal_AttachmentFlag); return fRenderPass == renderPass; } bool GrVkRenderPass::equalLoadStoreOps(const LoadStoreOps& colorOps, const LoadStoreOps& stencilOps) const { SkASSERT(!(fAttachmentFlags & kExternal_AttachmentFlag)); if (fAttachmentFlags & kColor_AttachmentFlag) { if (fAttachmentsDescriptor.fColor.fLoadStoreOps != colorOps) { return false; } } if (fAttachmentFlags & kStencil_AttachmentFlag) { if (fAttachmentsDescriptor.fStencil.fLoadStoreOps != stencilOps) { return false; } } return true; } void GrVkRenderPass::genKey(GrProcessorKeyBuilder* b) const { b->add32(fAttachmentFlags); if (fAttachmentFlags & kColor_AttachmentFlag) { b->add32(fAttachmentsDescriptor.fColor.fFormat); b->add32(fAttachmentsDescriptor.fColor.fSamples); } if (fAttachmentFlags & kStencil_AttachmentFlag) { b->add32(fAttachmentsDescriptor.fStencil.fFormat); b->add32(fAttachmentsDescriptor.fStencil.fSamples); } if (fAttachmentFlags & kExternal_AttachmentFlag) { SkASSERT(!(fAttachmentFlags & ~kExternal_AttachmentFlag)); uint64_t handle = (uint64_t)fRenderPass; b->add32((uint32_t)handle); b->add32((uint32_t)(handle>>32)); } }