/* * 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 "src/gpu/vk/GrVkAttachment.h" #include "src/gpu/vk/GrVkDescriptorSet.h" #include "src/gpu/vk/GrVkGpu.h" #include "src/gpu/vk/GrVkImage.h" #include "src/gpu/vk/GrVkImageView.h" #include "src/gpu/vk/GrVkUtil.h" #define VK_CALL(GPU, X) GR_VK_CALL(GPU->vkInterface(), X) GrVkAttachment::GrVkAttachment(GrVkGpu* gpu, SkISize dimensions, UsageFlags supportedUsages, const GrVkImageInfo& info, sk_sp mutableState, sk_sp framebufferView, sk_sp textureView, SkBudgeted budgeted) : GrAttachment(gpu, dimensions, supportedUsages, info.fSampleCount, GrMipmapped::kNo, info.fProtected) , GrVkImage(gpu, info, std::move(mutableState), GrBackendObjectOwnership::kOwned) , fFramebufferView(std::move(framebufferView)) , fTextureView(std::move(textureView)) { this->registerWithCache(budgeted); } GrVkAttachment::GrVkAttachment(GrVkGpu* gpu, SkISize dimensions, UsageFlags supportedUsages, const GrVkImageInfo& info, sk_sp mutableState, sk_sp framebufferView, sk_sp textureView, GrBackendObjectOwnership ownership, GrWrapCacheable cacheable, bool forSecondaryCB) : GrAttachment(gpu, dimensions, supportedUsages, info.fSampleCount, GrMipmapped::kNo, info.fProtected) , GrVkImage(gpu, info, std::move(mutableState), ownership, forSecondaryCB) , fFramebufferView(std::move(framebufferView)) , fTextureView(std::move(textureView)) { this->registerWithCacheWrapped(cacheable); } sk_sp GrVkAttachment::MakeStencil(GrVkGpu* gpu, SkISize dimensions, int sampleCnt, VkFormat format) { VkImageUsageFlags vkUsageFlags = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; return GrVkAttachment::Make(gpu, dimensions, UsageFlags::kStencilAttachment, sampleCnt, format, /*mipLevels=*/1, vkUsageFlags, GrProtected::kNo, SkBudgeted::kYes); } sk_sp GrVkAttachment::MakeMSAA(GrVkGpu* gpu, SkISize dimensions, int numSamples, VkFormat format, GrProtected isProtected) { SkASSERT(numSamples > 1); VkImageUsageFlags vkUsageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; return GrVkAttachment::Make(gpu, dimensions, UsageFlags::kColorAttachment, numSamples, format, /*mipLevels=*/1, vkUsageFlags, isProtected, SkBudgeted::kYes); } sk_sp GrVkAttachment::MakeTexture(GrVkGpu* gpu, SkISize dimensions, VkFormat format, uint32_t mipLevels, GrRenderable renderable, int numSamples, SkBudgeted budgeted, GrProtected isProtected) { UsageFlags usageFlags = UsageFlags::kTexture; VkImageUsageFlags vkUsageFlags = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; if (renderable == GrRenderable::kYes) { usageFlags |= UsageFlags::kColorAttachment; vkUsageFlags |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; // We always make our render targets support being used as input attachments vkUsageFlags |= VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT; } return GrVkAttachment::Make(gpu, dimensions, usageFlags, numSamples, format, mipLevels, vkUsageFlags, isProtected, budgeted); } static bool make_views(GrVkGpu* gpu, const GrVkImageInfo& info, GrAttachment::UsageFlags attachmentUsages, sk_sp* framebufferView, sk_sp* textureView) { GrVkImageView::Type viewType; if (attachmentUsages & GrAttachment::UsageFlags::kStencilAttachment) { // If we have stencil usage then we shouldn't have any other usages SkASSERT(attachmentUsages == GrAttachment::UsageFlags::kStencilAttachment); viewType = GrVkImageView::kStencil_Type; } else { viewType = GrVkImageView::kColor_Type; } if (SkToBool(attachmentUsages & GrAttachment::UsageFlags::kStencilAttachment) || SkToBool(attachmentUsages & GrAttachment::UsageFlags::kColorAttachment)) { // Attachments can only have a mip level of 1 *framebufferView = GrVkImageView::Make(gpu, info.fImage, info.fFormat, viewType, 1, info.fYcbcrConversionInfo); if (!*framebufferView) { return false; } } if (attachmentUsages & GrAttachment::UsageFlags::kTexture) { *textureView = GrVkImageView::Make(gpu, info.fImage, info.fFormat, viewType, info.fLevelCount, info.fYcbcrConversionInfo); if (!*textureView) { return false; } } return true; } sk_sp GrVkAttachment::Make(GrVkGpu* gpu, SkISize dimensions, UsageFlags attachmentUsages, int sampleCnt, VkFormat format, uint32_t mipLevels, VkImageUsageFlags vkUsageFlags, GrProtected isProtected, SkBudgeted budgeted) { GrVkImage::ImageDesc imageDesc; imageDesc.fImageType = VK_IMAGE_TYPE_2D; imageDesc.fFormat = format; imageDesc.fWidth = dimensions.width(); imageDesc.fHeight = dimensions.height(); imageDesc.fLevels = mipLevels; imageDesc.fSamples = sampleCnt; imageDesc.fImageTiling = VK_IMAGE_TILING_OPTIMAL; imageDesc.fUsageFlags = vkUsageFlags; imageDesc.fIsProtected = isProtected; GrVkImageInfo info; if (!GrVkImage::InitImageInfo(gpu, imageDesc, &info)) { return nullptr; } sk_sp framebufferView; sk_sp textureView; if (!make_views(gpu, info, attachmentUsages, &framebufferView, &textureView)) { GrVkImage::DestroyImageInfo(gpu, &info); return nullptr; } sk_sp mutableState( new GrBackendSurfaceMutableStateImpl(info.fImageLayout, info.fCurrentQueueFamily)); return sk_sp(new GrVkAttachment(gpu, dimensions, attachmentUsages, info, std::move(mutableState), std::move(framebufferView), std::move(textureView), budgeted)); } sk_sp GrVkAttachment::MakeWrapped( GrVkGpu* gpu, SkISize dimensions, const GrVkImageInfo& info, sk_sp mutableState, UsageFlags attachmentUsages, GrWrapOwnership ownership, GrWrapCacheable cacheable, bool forSecondaryCB) { sk_sp framebufferView; sk_sp textureView; if (!forSecondaryCB) { if (!make_views(gpu, info, attachmentUsages, &framebufferView, &textureView)) { return nullptr; } } GrBackendObjectOwnership backendOwnership = kBorrow_GrWrapOwnership == ownership ? GrBackendObjectOwnership::kBorrowed : GrBackendObjectOwnership::kOwned; return sk_sp(new GrVkAttachment(gpu, dimensions, attachmentUsages, info, std::move(mutableState), std::move(framebufferView), std::move(textureView), backendOwnership, cacheable, forSecondaryCB)); } static void write_input_desc_set(GrVkGpu* gpu, VkImageView view, VkImageLayout layout, VkDescriptorSet descSet) { VkDescriptorImageInfo imageInfo; memset(&imageInfo, 0, sizeof(VkDescriptorImageInfo)); imageInfo.sampler = VK_NULL_HANDLE; imageInfo.imageView = view; imageInfo.imageLayout = layout; VkWriteDescriptorSet writeInfo; memset(&writeInfo, 0, sizeof(VkWriteDescriptorSet)); writeInfo.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; writeInfo.pNext = nullptr; writeInfo.dstSet = descSet; writeInfo.dstBinding = GrVkUniformHandler::kInputBinding; writeInfo.dstArrayElement = 0; writeInfo.descriptorCount = 1; writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT; writeInfo.pImageInfo = &imageInfo; writeInfo.pBufferInfo = nullptr; writeInfo.pTexelBufferView = nullptr; GR_VK_CALL(gpu->vkInterface(), UpdateDescriptorSets(gpu->device(), 1, &writeInfo, 0, nullptr)); } gr_rp < const GrVkDescriptorSet> GrVkAttachment::inputDescSetForBlending(GrVkGpu* gpu) { if (!this->supportsInputAttachmentUsage()) { return nullptr; } if (fCachedBlendingInputDescSet) { return fCachedBlendingInputDescSet; } fCachedBlendingInputDescSet.reset(gpu->resourceProvider().getInputDescriptorSet()); if (!fCachedBlendingInputDescSet) { return nullptr; } write_input_desc_set(gpu, this->framebufferView()->imageView(), VK_IMAGE_LAYOUT_GENERAL, *fCachedBlendingInputDescSet->descriptorSet()); return fCachedBlendingInputDescSet; } gr_rp GrVkAttachment::inputDescSetForMSAALoad(GrVkGpu* gpu) { if (!this->supportsInputAttachmentUsage()) { return nullptr; } if (fCachedMSAALoadInputDescSet) { return fCachedMSAALoadInputDescSet; } fCachedMSAALoadInputDescSet.reset(gpu->resourceProvider().getInputDescriptorSet()); if (!fCachedMSAALoadInputDescSet) { return nullptr; } write_input_desc_set(gpu, this->framebufferView()->imageView(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, *fCachedMSAALoadInputDescSet->descriptorSet()); return fCachedMSAALoadInputDescSet; } GrVkAttachment::~GrVkAttachment() { // should have been released or abandoned first SkASSERT(!fFramebufferView); SkASSERT(!fTextureView); } void GrVkAttachment::release() { this->releaseImage(); fFramebufferView.reset(); fTextureView.reset(); fCachedBlendingInputDescSet.reset(); fCachedMSAALoadInputDescSet.reset(); } void GrVkAttachment::onRelease() { this->release(); GrAttachment::onRelease(); } void GrVkAttachment::onAbandon() { this->release(); GrAttachment::onAbandon(); } GrVkGpu* GrVkAttachment::getVkGpu() const { SkASSERT(!this->wasDestroyed()); return static_cast(this->getGpu()); }