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 #include "src/gpu/ganesh/vk/GrVkTexture.h"
9
10 #include "include/core/SkSize.h"
11 #include "include/gpu/GpuTypes.h"
12 #include "include/gpu/MutableTextureState.h"
13 #include "include/gpu/ganesh/vk/GrVkTypes.h"
14 #include "include/gpu/vk/VulkanTypes.h"
15 #include "include/private/base/SkAssert.h"
16 #include "include/private/base/SkTo.h"
17 #include "src/gpu/ganesh/GrAttachment.h"
18 #include "src/gpu/ganesh/GrSurface.h"
19 #include "src/gpu/ganesh/GrTexture.h"
20 #include "src/gpu/ganesh/vk/GrVkBackendSurfacePriv.h"
21 #include "src/gpu/ganesh/vk/GrVkDescriptorSet.h"
22 #include "src/gpu/ganesh/vk/GrVkGpu.h"
23 #include "src/gpu/ganesh/vk/GrVkUtil.h"
24 #include "src/gpu/vk/VulkanUtilsPriv.h"
25
26 #define VK_CALL(GPU, X) GR_VK_CALL(GPU->vkInterface(), X)
27
28 // Because this class is virtually derived from GrSurface we must explicitly call its constructor.
GrVkTexture(GrVkGpu * gpu,skgpu::Budgeted budgeted,SkISize dimensions,sk_sp<GrVkImage> texture,GrMipmapStatus mipmapStatus,std::string_view label)29 GrVkTexture::GrVkTexture(GrVkGpu* gpu,
30 skgpu::Budgeted budgeted,
31 SkISize dimensions,
32 sk_sp<GrVkImage> texture,
33 GrMipmapStatus mipmapStatus,
34 std::string_view label)
35 : GrSurface(gpu,
36 dimensions,
37 texture->isProtected() ? GrProtected::kYes : GrProtected::kNo,
38 label)
39 , GrTexture(gpu,
40 dimensions,
41 texture->isProtected() ? GrProtected::kYes : GrProtected::kNo,
42 GrTextureType::k2D,
43 mipmapStatus,
44 label)
45 , fTexture(std::move(texture))
46 , fDescSetCache(kMaxCachedDescSets) {
47 SkASSERT((GrMipmapStatus::kNotAllocated == mipmapStatus) == (1 == fTexture->mipLevels()));
48 // We don't support creating external GrVkTextures
49 SkASSERT(!fTexture->ycbcrConversionInfo().isValid() ||
50 !fTexture->ycbcrConversionInfo().fExternalFormat);
51 SkASSERT(SkToBool(fTexture->vkUsageFlags() & VK_IMAGE_USAGE_SAMPLED_BIT));
52 #ifdef SKIA_OHOS
53 if (fTexture->GetBudgeted() == skgpu::Budgeted::kYes) {
54 this->registerWithCache(skgpu::Budgeted::kNo);
55 } else {
56 this->registerWithCache(budgeted);
57 }
58 #else
59 this->registerWithCache(budgeted);
60 #endif
61 if (skgpu::VkFormatIsCompressed(fTexture->imageFormat())) {
62 this->setReadOnly();
63 }
64 }
65
GrVkTexture(GrVkGpu * gpu,SkISize dimensions,sk_sp<GrVkImage> texture,GrMipmapStatus mipmapStatus,GrWrapCacheable cacheable,GrIOType ioType,bool isExternal,std::string_view label)66 GrVkTexture::GrVkTexture(GrVkGpu* gpu,
67 SkISize dimensions,
68 sk_sp<GrVkImage> texture,
69 GrMipmapStatus mipmapStatus,
70 GrWrapCacheable cacheable,
71 GrIOType ioType,
72 bool isExternal,
73 std::string_view label)
74 : GrSurface(gpu,
75 dimensions,
76 texture->isProtected() ? GrProtected::kYes : GrProtected::kNo,
77 label)
78 , GrTexture(gpu,
79 dimensions,
80 texture->isProtected() ? GrProtected::kYes : GrProtected::kNo,
81 isExternal ? GrTextureType::kExternal : GrTextureType::k2D,
82 mipmapStatus,
83 label)
84 , fTexture(std::move(texture))
85 , fDescSetCache(kMaxCachedDescSets) {
86 SkASSERT((GrMipmapStatus::kNotAllocated == mipmapStatus) == (1 == fTexture->mipLevels()));
87 SkASSERT(SkToBool(fTexture->vkUsageFlags() & VK_IMAGE_USAGE_SAMPLED_BIT));
88 if (ioType == kRead_GrIOType) {
89 this->setReadOnly();
90 }
91 this->registerWithCacheWrapped(cacheable);
92 }
93
94 // 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,std::string_view label)95 GrVkTexture::GrVkTexture(GrVkGpu* gpu,
96 SkISize dimensions,
97 sk_sp<GrVkImage> texture,
98 GrMipmapStatus mipmapStatus,
99 std::string_view label)
100 : GrSurface(gpu,
101 dimensions,
102 texture->isProtected() ? GrProtected::kYes : GrProtected::kNo,
103 label)
104 , GrTexture(gpu,
105 dimensions,
106 texture->isProtected() ? GrProtected::kYes : GrProtected::kNo,
107 GrTextureType::k2D,
108 mipmapStatus,
109 label)
110 , fTexture(std::move(texture))
111 , fDescSetCache(kMaxCachedDescSets) {
112 SkASSERT((GrMipmapStatus::kNotAllocated == mipmapStatus) == (1 == fTexture->mipLevels()));
113 // Since this ctor is only called from GrVkTextureRenderTarget, we can't have a ycbcr conversion
114 // since we don't support that on render targets.
115 SkASSERT(!fTexture->ycbcrConversionInfo().isValid());
116 SkASSERT(SkToBool(fTexture->vkUsageFlags() & VK_IMAGE_USAGE_SAMPLED_BIT));
117 }
118
MakeNewTexture(GrVkGpu * gpu,skgpu::Budgeted budgeted,SkISize dimensions,VkFormat format,uint32_t mipLevels,GrProtected isProtected,GrMipmapStatus mipmapStatus,std::string_view label)119 sk_sp<GrVkTexture> GrVkTexture::MakeNewTexture(GrVkGpu* gpu,
120 skgpu::Budgeted budgeted,
121 SkISize dimensions,
122 VkFormat format,
123 uint32_t mipLevels,
124 GrProtected isProtected,
125 GrMipmapStatus mipmapStatus,
126 std::string_view label) {
127 sk_sp<GrVkImage> texture = GrVkImage::MakeTexture(
128 gpu, dimensions, format, mipLevels, GrRenderable::kNo, /*numSamples=*/1, budgeted,
129 isProtected);
130
131 if (!texture) {
132 return nullptr;
133 }
134 return sk_sp<GrVkTexture>(new GrVkTexture(
135 gpu, budgeted, dimensions, std::move(texture), mipmapStatus, label));
136 }
137
MakeWrappedTexture(GrVkGpu * gpu,SkISize dimensions,GrWrapOwnership wrapOwnership,GrWrapCacheable cacheable,GrIOType ioType,const GrVkImageInfo & info,sk_sp<skgpu::MutableTextureState> mutableState)138 sk_sp<GrVkTexture> GrVkTexture::MakeWrappedTexture(
139 GrVkGpu* gpu, SkISize dimensions, GrWrapOwnership wrapOwnership, GrWrapCacheable cacheable,
140 GrIOType ioType, const GrVkImageInfo& info,
141 sk_sp<skgpu::MutableTextureState> mutableState) {
142 // Adopted textures require both image and allocation because we're responsible for freeing
143 SkASSERT(VK_NULL_HANDLE != info.fImage &&
144 (kBorrow_GrWrapOwnership == wrapOwnership || VK_NULL_HANDLE != info.fAlloc.fMemory));
145
146 sk_sp<GrVkImage> texture = GrVkImage::MakeWrapped(gpu,
147 dimensions,
148 info,
149 std::move(mutableState),
150 GrAttachment::UsageFlags::kTexture,
151 wrapOwnership,
152 cacheable,
153 "VkImage_MakeWrappedTexture");
154 if (!texture) {
155 return nullptr;
156 }
157
158 GrMipmapStatus mipmapStatus = info.fLevelCount > 1 ? GrMipmapStatus::kValid
159 : GrMipmapStatus::kNotAllocated;
160
161 bool isExternal = info.fYcbcrConversionInfo.isValid() &&
162 (info.fYcbcrConversionInfo.fExternalFormat != 0);
163 isExternal |= (info.fImageTiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT);
164 return sk_sp<GrVkTexture>(new GrVkTexture(gpu,
165 dimensions,
166 std::move(texture),
167 mipmapStatus,
168 cacheable,
169 ioType,
170 isExternal,
171 /*label=*/"Vk_MakeWrappedTexture"));
172 }
173
~GrVkTexture()174 GrVkTexture::~GrVkTexture() {
175 // either release or abandon should have been called by the owner of this object.
176 SkASSERT(!fTexture);
177 }
178
onRelease()179 void GrVkTexture::onRelease() {
180 fTexture.reset();
181
182 fDescSetCache.reset();
183
184 GrTexture::onRelease();
185 }
186
187 struct GrVkTexture::DescriptorCacheEntry {
DescriptorCacheEntryGrVkTexture::DescriptorCacheEntry188 DescriptorCacheEntry(const GrVkDescriptorSet* fDescSet, GrVkGpu* gpu)
189 : fDescriptorSet(fDescSet), fGpu(gpu) {}
~DescriptorCacheEntryGrVkTexture::DescriptorCacheEntry190 ~DescriptorCacheEntry() {
191 if (fDescriptorSet) {
192 fDescriptorSet->recycle();
193 }
194 }
195
196 const GrVkDescriptorSet* fDescriptorSet;
197 GrVkGpu* fGpu;
198 };
199
onAbandon()200 void GrVkTexture::onAbandon() {
201 fTexture.reset();
202
203 fDescSetCache.reset();
204
205 GrTexture::onAbandon();
206 }
207
getBackendTexture() const208 GrBackendTexture GrVkTexture::getBackendTexture() const {
209 return GrBackendTextures::MakeVk(fTexture->width(),
210 fTexture->height(),
211 fTexture->vkImageInfo(),
212 fTexture->getMutableState());
213 }
214
getVkGpu() const215 GrVkGpu* GrVkTexture::getVkGpu() const {
216 SkASSERT(!this->wasDestroyed());
217 return static_cast<GrVkGpu*>(this->getGpu());
218 }
219
textureView()220 const GrVkImageView* GrVkTexture::textureView() { return fTexture->textureView(); }
221
cachedSingleDescSet(GrSamplerState state)222 const GrVkDescriptorSet* GrVkTexture::cachedSingleDescSet(GrSamplerState state) {
223 if (std::unique_ptr<DescriptorCacheEntry>* e = fDescSetCache.find(state)) {
224 return (*e)->fDescriptorSet;
225 }
226 return nullptr;
227 }
228
addDescriptorSetToCache(const GrVkDescriptorSet * descSet,GrSamplerState state)229 void GrVkTexture::addDescriptorSetToCache(const GrVkDescriptorSet* descSet, GrSamplerState state) {
230 SkASSERT(!fDescSetCache.find(state));
231 descSet->ref();
232 fDescSetCache.insert(state, std::make_unique<DescriptorCacheEntry>(descSet, this->getVkGpu()));
233 }
234
dumpMemoryStatistics(SkTraceMemoryDump * traceMemoryDump) const235 void GrVkTexture::dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const {
236 size_t size = GrSurface::ComputeSize(this->backendFormat(), this->dimensions(), 1,
237 this->mipmapped());
238 SkString resourceName = this->getResourceName();
239 resourceName.append("/texture");
240 if (fTexture->isBorrowed() && !fTexture->isRealAlloc()) {
241 this->dumpMemoryStatisticsPriv(traceMemoryDump, resourceName, "External Texture", size);
242 } else {
243 this->dumpMemoryStatisticsPriv(traceMemoryDump, resourceName, "Texture", size);
244 }
245 }
246
247 #ifdef SKIA_DFX_FOR_RECORD_VKIMAGE
updateNodeId(uint64_t nodeId)248 void GrVkTexture::updateNodeId(uint64_t nodeId) {
249 if (fTexture != nullptr) {
250 fTexture->updateNodeId(nodeId);
251 }
252 }
253 #endif
254