1 /*
2  * Copyright 2015 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 
9 #include "src/gpu/vk/GrVkTexture.h"
10 
11 #include "src/gpu/GrTexture.h"
12 #include "src/gpu/vk/GrVkDescriptorSet.h"
13 #include "src/gpu/vk/GrVkGpu.h"
14 #include "src/gpu/vk/GrVkImageView.h"
15 #include "src/gpu/vk/GrVkTextureRenderTarget.h"
16 #include "src/gpu/vk/GrVkUtil.h"
17 
18 #include "include/gpu/vk/GrVkTypes.h"
19 
20 #define VK_CALL(GPU, X) GR_VK_CALL(GPU->vkInterface(), X)
21 
22 // Because this class is virtually derived from GrSurface we must explicitly call its constructor.
GrVkTexture(GrVkGpu* gpu, SkBudgeted budgeted, SkISize dimensions, sk_sp<GrVkImage> texture, GrMipmapStatus mipmapStatus)23 GrVkTexture::GrVkTexture(GrVkGpu* gpu,
24                          SkBudgeted budgeted,
25                          SkISize dimensions,
26                          sk_sp<GrVkImage> texture,
27                          GrMipmapStatus mipmapStatus)
28         : GrSurface(gpu, dimensions,
29                     texture->isProtected() ? GrProtected::kYes : GrProtected::kNo)
30         , GrTexture(gpu, dimensions,
31                     texture->isProtected() ? GrProtected::kYes : GrProtected::kNo,
32                     GrTextureType::k2D, mipmapStatus)
33         , fTexture(std::move(texture))
34         , fDescSetCache(kMaxCachedDescSets) {
35     SkASSERT((GrMipmapStatus::kNotAllocated == mipmapStatus) == (1 == fTexture->mipLevels()));
36     // We don't support creating external GrVkTextures
37     SkASSERT(!fTexture->ycbcrConversionInfo().isValid() ||
38              !fTexture->ycbcrConversionInfo().fExternalFormat);
39     SkASSERT(SkToBool(fTexture->vkUsageFlags() & VK_IMAGE_USAGE_SAMPLED_BIT));
40 #ifdef SKIA_OHOS
41     if (fTexture->GetBudgeted() == SkBudgeted::kYes) {
42         this->registerWithCache(SkBudgeted::kNo);
43     } else {
44         this->registerWithCache(budgeted);
45     }
46 #else
47     this->registerWithCache(budgeted);
48 #endif
49     if (GrVkFormatIsCompressed(fTexture->imageFormat())) {
50         this->setReadOnly();
51     }
52 }
53 
GrVkTexture(GrVkGpu* gpu, SkISize dimensions, sk_sp<GrVkImage> texture, GrMipmapStatus mipmapStatus, GrWrapCacheable cacheable, GrIOType ioType, bool isExternal)54 GrVkTexture::GrVkTexture(GrVkGpu* gpu, SkISize dimensions,
55                          sk_sp<GrVkImage> texture, GrMipmapStatus mipmapStatus,
56                          GrWrapCacheable cacheable, GrIOType ioType, bool isExternal)
57         : GrSurface(gpu, dimensions, texture->isProtected() ? GrProtected::kYes : GrProtected::kNo)
58         , GrTexture(gpu, dimensions, texture->isProtected() ? GrProtected::kYes : GrProtected::kNo,
59                     isExternal ? GrTextureType::kExternal : GrTextureType::k2D, mipmapStatus)
60         , fTexture(std::move(texture))
61         , fDescSetCache(kMaxCachedDescSets) {
62     SkASSERT((GrMipmapStatus::kNotAllocated == mipmapStatus) == (1 == fTexture->mipLevels()));
63     SkASSERT(SkToBool(fTexture->vkUsageFlags() & VK_IMAGE_USAGE_SAMPLED_BIT));
64     if (ioType == kRead_GrIOType) {
65         this->setReadOnly();
66     }
67     this->registerWithCacheWrapped(cacheable);
68 }
69 
70 // Because this class is virtually derived from GrSurface we must explicitly call its constructor.
GrVkTexture(GrVkGpu* gpu, SkISize dimensions, sk_sp<GrVkImage> texture, GrMipmapStatus mipmapStatus)71 GrVkTexture::GrVkTexture(GrVkGpu* gpu,
72                          SkISize dimensions,
73                          sk_sp<GrVkImage> texture,
74                          GrMipmapStatus mipmapStatus)
75         : GrSurface(gpu, dimensions, texture->isProtected() ? GrProtected::kYes : GrProtected::kNo)
76         , GrTexture(gpu, dimensions, texture->isProtected() ? GrProtected::kYes : GrProtected::kNo,
77                     GrTextureType::k2D, mipmapStatus)
78         , fTexture(std::move(texture))
79         , fDescSetCache(kMaxCachedDescSets) {
80     SkASSERT((GrMipmapStatus::kNotAllocated == mipmapStatus) == (1 == fTexture->mipLevels()));
81     // Since this ctor is only called from GrVkTextureRenderTarget, we can't have a ycbcr conversion
82     // since we don't support that on render targets.
83     SkASSERT(!fTexture->ycbcrConversionInfo().isValid());
84     SkASSERT(SkToBool(fTexture->vkUsageFlags() & VK_IMAGE_USAGE_SAMPLED_BIT));
85 }
86 
MakeNewTexture(GrVkGpu* gpu, SkBudgeted budgeted, SkISize dimensions, VkFormat format, uint32_t mipLevels, GrProtected isProtected, GrMipmapStatus mipmapStatus)87 sk_sp<GrVkTexture> GrVkTexture::MakeNewTexture(GrVkGpu* gpu, SkBudgeted budgeted,
88                                                SkISize dimensions,
89                                                VkFormat format, uint32_t mipLevels,
90                                                GrProtected isProtected,
91                                                GrMipmapStatus mipmapStatus) {
92     sk_sp<GrVkImage> texture = GrVkImage::MakeTexture(
93             gpu, dimensions, format, mipLevels, GrRenderable::kNo, /*numSamples=*/1, budgeted,
94             isProtected);
95 
96     if (!texture) {
97         return nullptr;
98     }
99     return sk_sp<GrVkTexture>(new GrVkTexture(gpu, budgeted, dimensions, std::move(texture),
100                                               mipmapStatus));
101 }
102 
MakeWrappedTexture( GrVkGpu* gpu, SkISize dimensions, GrWrapOwnership wrapOwnership, GrWrapCacheable cacheable, GrIOType ioType, const GrVkImageInfo& info, sk_sp<GrBackendSurfaceMutableStateImpl> mutableState)103 sk_sp<GrVkTexture> GrVkTexture::MakeWrappedTexture(
104         GrVkGpu* gpu, SkISize dimensions, GrWrapOwnership wrapOwnership, GrWrapCacheable cacheable,
105         GrIOType ioType, const GrVkImageInfo& info,
106         sk_sp<GrBackendSurfaceMutableStateImpl> mutableState) {
107     // Adopted textures require both image and allocation because we're responsible for freeing
108     SkASSERT(VK_NULL_HANDLE != info.fImage &&
109              (kBorrow_GrWrapOwnership == wrapOwnership || VK_NULL_HANDLE != info.fAlloc.fMemory));
110 
111     sk_sp<GrVkImage> texture = GrVkImage::MakeWrapped(gpu,
112                                                       dimensions,
113                                                       info,
114                                                       std::move(mutableState),
115                                                       GrAttachment::UsageFlags::kTexture,
116                                                       wrapOwnership,
117                                                       cacheable);
118     if (!texture) {
119         return nullptr;
120     }
121 
122     GrMipmapStatus mipmapStatus = info.fLevelCount > 1 ? GrMipmapStatus::kValid
123                                                        : GrMipmapStatus::kNotAllocated;
124 
125     bool isExternal = info.fYcbcrConversionInfo.isValid() &&
126                       (info.fYcbcrConversionInfo.fExternalFormat != 0);
127     isExternal |= (info.fImageTiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT);
128     return sk_sp<GrVkTexture>(new GrVkTexture(gpu, dimensions, std::move(texture), mipmapStatus,
129                                               cacheable, ioType, isExternal));
130 }
131 
~GrVkTexture()132 GrVkTexture::~GrVkTexture() {
133     // either release or abandon should have been called by the owner of this object.
134     SkASSERT(!fTexture);
135 }
136 
onRelease()137 void GrVkTexture::onRelease() {
138     fTexture.reset();
139 
140     fDescSetCache.reset();
141 
142     GrTexture::onRelease();
143 }
144 
145 struct GrVkTexture::DescriptorCacheEntry {
DescriptorCacheEntryGrVkTexture::DescriptorCacheEntry146     DescriptorCacheEntry(const GrVkDescriptorSet* fDescSet, GrVkGpu* gpu)
147             : fDescriptorSet(fDescSet), fGpu(gpu) {}
~DescriptorCacheEntryGrVkTexture::DescriptorCacheEntry148     ~DescriptorCacheEntry() {
149         if (fDescriptorSet) {
150             fDescriptorSet->recycle();
151         }
152     }
153 
154     const GrVkDescriptorSet* fDescriptorSet;
155     GrVkGpu* fGpu;
156 };
157 
onAbandon()158 void GrVkTexture::onAbandon() {
159     fTexture.reset();
160 
161     fDescSetCache.reset();
162 
163     GrTexture::onAbandon();
164 }
165 
getBackendTexture() const166 GrBackendTexture GrVkTexture::getBackendTexture() const {
167     return GrBackendTexture(fTexture->width(), fTexture->height(), fTexture->vkImageInfo(),
168                             fTexture->getMutableState());
169 }
170 
getVkGpu() const171 GrVkGpu* GrVkTexture::getVkGpu() const {
172     SkASSERT(!this->wasDestroyed());
173     return static_cast<GrVkGpu*>(this->getGpu());
174 }
175 
textureView()176 const GrVkImageView* GrVkTexture::textureView() { return fTexture->textureView(); }
177 
cachedSingleDescSet(GrSamplerState state)178 const GrVkDescriptorSet* GrVkTexture::cachedSingleDescSet(GrSamplerState state) {
179     if (std::unique_ptr<DescriptorCacheEntry>* e = fDescSetCache.find(state)) {
180         return (*e)->fDescriptorSet;
181     }
182     return nullptr;
183 }
184 
addDescriptorSetToCache(const GrVkDescriptorSet* descSet, GrSamplerState state)185 void GrVkTexture::addDescriptorSetToCache(const GrVkDescriptorSet* descSet, GrSamplerState state) {
186     SkASSERT(!fDescSetCache.find(state));
187     descSet->ref();
188     fDescSetCache.insert(state, std::make_unique<DescriptorCacheEntry>(descSet, this->getVkGpu()));
189 }
190 
dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const191 void GrVkTexture::dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const {
192     size_t size = GrSurface::ComputeSize(this->backendFormat(), this->dimensions(), 1,
193                                          this->mipmapped());
194     SkString resourceName = this->getResourceName();
195     resourceName.append("/texture");
196     this->dumpMemoryStatisticsPriv(traceMemoryDump, resourceName, "Texture", size);
197 }
198