/* * 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 "GrVkRenderTarget.h" #include "GrRenderTargetPriv.h" #include "GrVkCommandBuffer.h" #include "GrVkFramebuffer.h" #include "GrVkGpu.h" #include "GrVkImageView.h" #include "GrVkResourceProvider.h" #include "GrVkUtil.h" #include "vk/GrVkTypes.h" #define VK_CALL(GPU, X) GR_VK_CALL(GPU->vkInterface(), X) // We're virtually derived from GrSurface (via GrRenderTarget) so its // constructor must be explicitly called. GrVkRenderTarget::GrVkRenderTarget(GrVkGpu* gpu, SkBudgeted budgeted, const GrSurfaceDesc& desc, const GrVkImageInfo& info, const GrVkImageInfo& msaaInfo, const GrVkImageView* colorAttachmentView, const GrVkImageView* resolveAttachmentView, GrVkImage::Wrapped wrapped) : GrSurface(gpu, desc) , GrVkImage(info, wrapped) // for the moment we only support 1:1 color to stencil , GrRenderTarget(gpu, desc) , fColorAttachmentView(colorAttachmentView) , fMSAAImage(new GrVkImage(msaaInfo, GrVkImage::kNot_Wrapped)) , fResolveAttachmentView(resolveAttachmentView) , fFramebuffer(nullptr) , fCachedSimpleRenderPass(nullptr) { SkASSERT(desc.fSampleCnt); this->createFramebuffer(gpu); this->registerWithCache(budgeted); } // We're virtually derived from GrSurface (via GrRenderTarget) so its // constructor must be explicitly called. GrVkRenderTarget::GrVkRenderTarget(GrVkGpu* gpu, const GrSurfaceDesc& desc, const GrVkImageInfo& info, const GrVkImageInfo& msaaInfo, const GrVkImageView* colorAttachmentView, const GrVkImageView* resolveAttachmentView, GrVkImage::Wrapped wrapped) : GrSurface(gpu, desc) , GrVkImage(info, wrapped) // for the moment we only support 1:1 color to stencil , GrRenderTarget(gpu, desc) , fColorAttachmentView(colorAttachmentView) , fMSAAImage(new GrVkImage(msaaInfo, GrVkImage::kNot_Wrapped)) , fResolveAttachmentView(resolveAttachmentView) , fFramebuffer(nullptr) , fCachedSimpleRenderPass(nullptr) { SkASSERT(desc.fSampleCnt); this->createFramebuffer(gpu); } // We're virtually derived from GrSurface (via GrRenderTarget) so its // constructor must be explicitly called. GrVkRenderTarget::GrVkRenderTarget(GrVkGpu* gpu, SkBudgeted budgeted, const GrSurfaceDesc& desc, const GrVkImageInfo& info, const GrVkImageView* colorAttachmentView, GrVkImage::Wrapped wrapped) : GrSurface(gpu, desc) , GrVkImage(info, wrapped) , GrRenderTarget(gpu, desc) , fColorAttachmentView(colorAttachmentView) , fMSAAImage(nullptr) , fResolveAttachmentView(nullptr) , fFramebuffer(nullptr) , fCachedSimpleRenderPass(nullptr) { SkASSERT(!desc.fSampleCnt); this->createFramebuffer(gpu); this->registerWithCache(budgeted); } // We're virtually derived from GrSurface (via GrRenderTarget) so its // constructor must be explicitly called. GrVkRenderTarget::GrVkRenderTarget(GrVkGpu* gpu, const GrSurfaceDesc& desc, const GrVkImageInfo& info, const GrVkImageView* colorAttachmentView, GrVkImage::Wrapped wrapped) : GrSurface(gpu, desc) , GrVkImage(info, wrapped) , GrRenderTarget(gpu, desc) , fColorAttachmentView(colorAttachmentView) , fMSAAImage(nullptr) , fResolveAttachmentView(nullptr) , fFramebuffer(nullptr) , fCachedSimpleRenderPass(nullptr) { SkASSERT(!desc.fSampleCnt); this->createFramebuffer(gpu); } GrVkRenderTarget* GrVkRenderTarget::Create(GrVkGpu* gpu, SkBudgeted budgeted, const GrSurfaceDesc& desc, const GrVkImageInfo& info, GrVkImage::Wrapped wrapped) { SkASSERT(1 == info.fLevelCount); VkFormat pixelFormat; GrPixelConfigToVkFormat(desc.fConfig, &pixelFormat); VkImage colorImage; // create msaa surface if necessary GrVkImageInfo msInfo; const GrVkImageView* resolveAttachmentView = nullptr; if (desc.fSampleCnt) { GrVkImage::ImageDesc msImageDesc; msImageDesc.fImageType = VK_IMAGE_TYPE_2D; msImageDesc.fFormat = pixelFormat; msImageDesc.fWidth = desc.fWidth; msImageDesc.fHeight = desc.fHeight; msImageDesc.fLevels = 1; msImageDesc.fSamples = desc.fSampleCnt; msImageDesc.fImageTiling = VK_IMAGE_TILING_OPTIMAL; msImageDesc.fUsageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; msImageDesc.fMemProps = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; if (!GrVkImage::InitImageInfo(gpu, msImageDesc, &msInfo)) { return nullptr; } // Set color attachment image colorImage = msInfo.fImage; // Create Resolve attachment view resolveAttachmentView = GrVkImageView::Create(gpu, info.fImage, pixelFormat, GrVkImageView::kColor_Type, 1); if (!resolveAttachmentView) { GrVkImage::DestroyImageInfo(gpu, &msInfo); return nullptr; } } else { // Set color attachment image colorImage = info.fImage; } // Get color attachment view const GrVkImageView* colorAttachmentView = GrVkImageView::Create(gpu, colorImage, pixelFormat, GrVkImageView::kColor_Type, 1); if (!colorAttachmentView) { if (desc.fSampleCnt) { resolveAttachmentView->unref(gpu); GrVkImage::DestroyImageInfo(gpu, &msInfo); } return nullptr; } GrVkRenderTarget* texRT; if (desc.fSampleCnt) { texRT = new GrVkRenderTarget(gpu, budgeted, desc, info, msInfo, colorAttachmentView, resolveAttachmentView, wrapped); } else { texRT = new GrVkRenderTarget(gpu, budgeted, desc, info, colorAttachmentView, wrapped); } return texRT; } GrVkRenderTarget* GrVkRenderTarget::CreateNewRenderTarget(GrVkGpu* gpu, SkBudgeted budgeted, const GrSurfaceDesc& desc, const GrVkImage::ImageDesc& imageDesc) { SkASSERT(imageDesc.fUsageFlags & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT); GrVkImageInfo info; if (!GrVkImage::InitImageInfo(gpu, imageDesc, &info)) { return nullptr; } GrVkRenderTarget* rt = GrVkRenderTarget::Create(gpu, budgeted, desc, info, GrVkImage::kNot_Wrapped); if (!rt) { GrVkImage::DestroyImageInfo(gpu, &info); } return rt; } sk_sp<GrVkRenderTarget> GrVkRenderTarget::MakeWrappedRenderTarget(GrVkGpu* gpu, const GrSurfaceDesc& desc, const GrVkImageInfo* info) { SkASSERT(info); SkASSERT(VK_NULL_HANDLE != info->fImage); return sk_sp<GrVkRenderTarget>( GrVkRenderTarget::Create(gpu, SkBudgeted::kNo, desc, *info, GrVkImage::kBorrowed_Wrapped)); } bool GrVkRenderTarget::completeStencilAttachment() { this->createFramebuffer(this->getVkGpu()); return true; } void GrVkRenderTarget::createFramebuffer(GrVkGpu* gpu) { if (fFramebuffer) { fFramebuffer->unref(gpu); } if (fCachedSimpleRenderPass) { fCachedSimpleRenderPass->unref(gpu); } // Vulkan requires us to create a compatible renderpass before we can create our framebuffer, // so we use this to get a (cached) basic renderpass, only for creation. fCachedSimpleRenderPass = gpu->resourceProvider().findCompatibleRenderPass(*this, &fCompatibleRPHandle); // Stencil attachment view is stored in the base RT stencil attachment const GrVkImageView* stencilView = this->stencilAttachmentView(); fFramebuffer = GrVkFramebuffer::Create(gpu, this->width(), this->height(), fCachedSimpleRenderPass, fColorAttachmentView, stencilView); SkASSERT(fFramebuffer); } void GrVkRenderTarget::getAttachmentsDescriptor( GrVkRenderPass::AttachmentsDescriptor* desc, GrVkRenderPass::AttachmentFlags* attachmentFlags) const { int colorSamples = this->numColorSamples(); VkFormat colorFormat; GrPixelConfigToVkFormat(this->config(), &colorFormat); desc->fColor.fFormat = colorFormat; desc->fColor.fSamples = colorSamples ? colorSamples : 1; *attachmentFlags = GrVkRenderPass::kColor_AttachmentFlag; uint32_t attachmentCount = 1; const GrStencilAttachment* stencil = this->renderTargetPriv().getStencilAttachment(); if (stencil) { const GrVkStencilAttachment* vkStencil = static_cast<const GrVkStencilAttachment*>(stencil); desc->fStencil.fFormat = vkStencil->vkFormat(); desc->fStencil.fSamples = vkStencil->numSamples() ? vkStencil->numSamples() : 1; // Currently in vulkan stencil and color attachments must all have same number of samples SkASSERT(desc->fColor.fSamples == desc->fStencil.fSamples); *attachmentFlags |= GrVkRenderPass::kStencil_AttachmentFlag; ++attachmentCount; } desc->fAttachmentCount = attachmentCount; } GrVkRenderTarget::~GrVkRenderTarget() { // either release or abandon should have been called by the owner of this object. SkASSERT(!fMSAAImage); SkASSERT(!fResolveAttachmentView); SkASSERT(!fColorAttachmentView); SkASSERT(!fFramebuffer); SkASSERT(!fCachedSimpleRenderPass); } void GrVkRenderTarget::addResources(GrVkCommandBuffer& commandBuffer) const { commandBuffer.addResource(this->framebuffer()); commandBuffer.addResource(this->colorAttachmentView()); commandBuffer.addResource(this->msaaImageResource() ? this->msaaImageResource() : this->resource()); if (this->stencilImageResource()) { commandBuffer.addResource(this->stencilImageResource()); commandBuffer.addResource(this->stencilAttachmentView()); } } void GrVkRenderTarget::releaseInternalObjects() { GrVkGpu* gpu = this->getVkGpu(); if (fMSAAImage) { fMSAAImage->releaseImage(gpu); fMSAAImage = nullptr; } if (fResolveAttachmentView) { fResolveAttachmentView->unref(gpu); fResolveAttachmentView = nullptr; } if (fColorAttachmentView) { fColorAttachmentView->unref(gpu); fColorAttachmentView = nullptr; } if (fFramebuffer) { fFramebuffer->unref(gpu); fFramebuffer = nullptr; } if (fCachedSimpleRenderPass) { fCachedSimpleRenderPass->unref(gpu); fCachedSimpleRenderPass = nullptr; } } void GrVkRenderTarget::abandonInternalObjects() { if (fMSAAImage) { fMSAAImage->abandonImage(); fMSAAImage = nullptr; } if (fResolveAttachmentView) { fResolveAttachmentView->unrefAndAbandon(); fResolveAttachmentView = nullptr; } if (fColorAttachmentView) { fColorAttachmentView->unrefAndAbandon(); fColorAttachmentView = nullptr; } if (fFramebuffer) { fFramebuffer->unrefAndAbandon(); fFramebuffer = nullptr; } if (fCachedSimpleRenderPass) { fCachedSimpleRenderPass->unrefAndAbandon(); fCachedSimpleRenderPass = nullptr; } } void GrVkRenderTarget::onRelease() { this->releaseInternalObjects(); this->releaseImage(this->getVkGpu()); GrRenderTarget::onRelease(); } void GrVkRenderTarget::onAbandon() { this->abandonInternalObjects(); this->abandonImage(); GrRenderTarget::onAbandon(); } GrBackendObject GrVkRenderTarget::getRenderTargetHandle() const { // If the render target is multisampled, we currently return the ImageInfo for the resolved // image. If we only wrap the msaa target (currently not implemented) we should return a handle // to that instead. return (GrBackendObject)&fInfo; } const GrVkResource* GrVkRenderTarget::stencilImageResource() const { const GrStencilAttachment* stencil = this->renderTargetPriv().getStencilAttachment(); if (stencil) { const GrVkStencilAttachment* vkStencil = static_cast<const GrVkStencilAttachment*>(stencil); return vkStencil->imageResource(); } return nullptr; } const GrVkImageView* GrVkRenderTarget::stencilAttachmentView() const { const GrStencilAttachment* stencil = this->renderTargetPriv().getStencilAttachment(); if (stencil) { const GrVkStencilAttachment* vkStencil = static_cast<const GrVkStencilAttachment*>(stencil); return vkStencil->stencilView(); } return nullptr; } GrVkGpu* GrVkRenderTarget::getVkGpu() const { SkASSERT(!this->wasDestroyed()); return static_cast<GrVkGpu*>(this->getGpu()); }