/* * 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/ganesh/vk/GrVkTexture.h" #include "include/core/SkSize.h" #include "include/gpu/GpuTypes.h" #include "include/gpu/MutableTextureState.h" #include "include/gpu/ganesh/vk/GrVkTypes.h" #include "include/gpu/vk/VulkanTypes.h" #include "include/private/base/SkAssert.h" #include "include/private/base/SkTo.h" #include "src/gpu/ganesh/GrAttachment.h" #include "src/gpu/ganesh/GrSurface.h" #include "src/gpu/ganesh/GrTexture.h" #include "src/gpu/ganesh/vk/GrVkBackendSurfacePriv.h" #include "src/gpu/ganesh/vk/GrVkDescriptorSet.h" #include "src/gpu/ganesh/vk/GrVkGpu.h" #include "src/gpu/ganesh/vk/GrVkUtil.h" #include "src/gpu/vk/VulkanUtilsPriv.h" #define VK_CALL(GPU, X) GR_VK_CALL(GPU->vkInterface(), X) // Because this class is virtually derived from GrSurface we must explicitly call its constructor. GrVkTexture::GrVkTexture(GrVkGpu* gpu, skgpu::Budgeted budgeted, SkISize dimensions, sk_sp texture, GrMipmapStatus mipmapStatus, std::string_view label) : GrSurface(gpu, dimensions, texture->isProtected() ? GrProtected::kYes : GrProtected::kNo, label) , GrTexture(gpu, dimensions, texture->isProtected() ? GrProtected::kYes : GrProtected::kNo, GrTextureType::k2D, mipmapStatus, label) , fTexture(std::move(texture)) , fDescSetCache(kMaxCachedDescSets) { SkASSERT((GrMipmapStatus::kNotAllocated == mipmapStatus) == (1 == fTexture->mipLevels())); // We don't support creating external GrVkTextures SkASSERT(!fTexture->ycbcrConversionInfo().isValid() || !fTexture->ycbcrConversionInfo().fExternalFormat); SkASSERT(SkToBool(fTexture->vkUsageFlags() & VK_IMAGE_USAGE_SAMPLED_BIT)); this->registerWithCache(budgeted); if (skgpu::VkFormatIsCompressed(fTexture->imageFormat())) { this->setReadOnly(); } } GrVkTexture::GrVkTexture(GrVkGpu* gpu, SkISize dimensions, sk_sp texture, GrMipmapStatus mipmapStatus, GrWrapCacheable cacheable, GrIOType ioType, bool isExternal, std::string_view label) : GrSurface(gpu, dimensions, texture->isProtected() ? GrProtected::kYes : GrProtected::kNo, label) , GrTexture(gpu, dimensions, texture->isProtected() ? GrProtected::kYes : GrProtected::kNo, isExternal ? GrTextureType::kExternal : GrTextureType::k2D, mipmapStatus, label) , fTexture(std::move(texture)) , fDescSetCache(kMaxCachedDescSets) { SkASSERT((GrMipmapStatus::kNotAllocated == mipmapStatus) == (1 == fTexture->mipLevels())); SkASSERT(SkToBool(fTexture->vkUsageFlags() & VK_IMAGE_USAGE_SAMPLED_BIT)); if (ioType == kRead_GrIOType) { this->setReadOnly(); } this->registerWithCacheWrapped(cacheable); } // Because this class is virtually derived from GrSurface we must explicitly call its constructor. GrVkTexture::GrVkTexture(GrVkGpu* gpu, SkISize dimensions, sk_sp texture, GrMipmapStatus mipmapStatus, std::string_view label) : GrSurface(gpu, dimensions, texture->isProtected() ? GrProtected::kYes : GrProtected::kNo, label) , GrTexture(gpu, dimensions, texture->isProtected() ? GrProtected::kYes : GrProtected::kNo, GrTextureType::k2D, mipmapStatus, label) , fTexture(std::move(texture)) , fDescSetCache(kMaxCachedDescSets) { SkASSERT((GrMipmapStatus::kNotAllocated == mipmapStatus) == (1 == fTexture->mipLevels())); // Since this ctor is only called from GrVkTextureRenderTarget, we can't have a ycbcr conversion // since we don't support that on render targets. SkASSERT(!fTexture->ycbcrConversionInfo().isValid()); SkASSERT(SkToBool(fTexture->vkUsageFlags() & VK_IMAGE_USAGE_SAMPLED_BIT)); } sk_sp GrVkTexture::MakeNewTexture(GrVkGpu* gpu, skgpu::Budgeted budgeted, SkISize dimensions, VkFormat format, uint32_t mipLevels, GrProtected isProtected, GrMipmapStatus mipmapStatus, std::string_view label) { sk_sp texture = GrVkImage::MakeTexture( gpu, dimensions, format, mipLevels, GrRenderable::kNo, /*numSamples=*/1, budgeted, isProtected); if (!texture) { return nullptr; } return sk_sp(new GrVkTexture( gpu, budgeted, dimensions, std::move(texture), mipmapStatus, label)); } sk_sp GrVkTexture::MakeWrappedTexture( GrVkGpu* gpu, SkISize dimensions, GrWrapOwnership wrapOwnership, GrWrapCacheable cacheable, GrIOType ioType, const GrVkImageInfo& info, sk_sp mutableState) { // Adopted textures require both image and allocation because we're responsible for freeing SkASSERT(VK_NULL_HANDLE != info.fImage && (kBorrow_GrWrapOwnership == wrapOwnership || VK_NULL_HANDLE != info.fAlloc.fMemory)); sk_sp texture = GrVkImage::MakeWrapped(gpu, dimensions, info, std::move(mutableState), GrAttachment::UsageFlags::kTexture, wrapOwnership, cacheable, "VkImage_MakeWrappedTexture"); if (!texture) { return nullptr; } GrMipmapStatus mipmapStatus = info.fLevelCount > 1 ? GrMipmapStatus::kValid : GrMipmapStatus::kNotAllocated; bool isExternal = info.fYcbcrConversionInfo.isValid() && (info.fYcbcrConversionInfo.fExternalFormat != 0); isExternal |= (info.fImageTiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT); return sk_sp(new GrVkTexture(gpu, dimensions, std::move(texture), mipmapStatus, cacheable, ioType, isExternal, /*label=*/"Vk_MakeWrappedTexture")); } GrVkTexture::~GrVkTexture() { // either release or abandon should have been called by the owner of this object. SkASSERT(!fTexture); } void GrVkTexture::onRelease() { fTexture.reset(); fDescSetCache.reset(); GrTexture::onRelease(); } struct GrVkTexture::DescriptorCacheEntry { DescriptorCacheEntry(const GrVkDescriptorSet* fDescSet, GrVkGpu* gpu) : fDescriptorSet(fDescSet), fGpu(gpu) {} ~DescriptorCacheEntry() { if (fDescriptorSet) { fDescriptorSet->recycle(); } } const GrVkDescriptorSet* fDescriptorSet; GrVkGpu* fGpu; }; void GrVkTexture::onAbandon() { fTexture.reset(); fDescSetCache.reset(); GrTexture::onAbandon(); } GrBackendTexture GrVkTexture::getBackendTexture() const { return GrBackendTextures::MakeVk(fTexture->width(), fTexture->height(), fTexture->vkImageInfo(), fTexture->getMutableState()); } GrVkGpu* GrVkTexture::getVkGpu() const { SkASSERT(!this->wasDestroyed()); return static_cast(this->getGpu()); } const GrVkImageView* GrVkTexture::textureView() { return fTexture->textureView(); } const GrVkDescriptorSet* GrVkTexture::cachedSingleDescSet(GrSamplerState state) { if (std::unique_ptr* e = fDescSetCache.find(state)) { return (*e)->fDescriptorSet; } return nullptr; } void GrVkTexture::addDescriptorSetToCache(const GrVkDescriptorSet* descSet, GrSamplerState state) { SkASSERT(!fDescSetCache.find(state)); descSet->ref(); fDescSetCache.insert(state, std::make_unique(descSet, this->getVkGpu())); }