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 this->registerWithCache(budgeted);
53 if (skgpu::VkFormatIsCompressed(fTexture->imageFormat())) {
54 this->setReadOnly();
55 }
56 }
57
GrVkTexture(GrVkGpu * gpu,SkISize dimensions,sk_sp<GrVkImage> texture,GrMipmapStatus mipmapStatus,GrWrapCacheable cacheable,GrIOType ioType,bool isExternal,std::string_view label)58 GrVkTexture::GrVkTexture(GrVkGpu* gpu,
59 SkISize dimensions,
60 sk_sp<GrVkImage> texture,
61 GrMipmapStatus mipmapStatus,
62 GrWrapCacheable cacheable,
63 GrIOType ioType,
64 bool isExternal,
65 std::string_view label)
66 : GrSurface(gpu,
67 dimensions,
68 texture->isProtected() ? GrProtected::kYes : GrProtected::kNo,
69 label)
70 , GrTexture(gpu,
71 dimensions,
72 texture->isProtected() ? GrProtected::kYes : GrProtected::kNo,
73 isExternal ? GrTextureType::kExternal : GrTextureType::k2D,
74 mipmapStatus,
75 label)
76 , fTexture(std::move(texture))
77 , fDescSetCache(kMaxCachedDescSets) {
78 SkASSERT((GrMipmapStatus::kNotAllocated == mipmapStatus) == (1 == fTexture->mipLevels()));
79 SkASSERT(SkToBool(fTexture->vkUsageFlags() & VK_IMAGE_USAGE_SAMPLED_BIT));
80 if (ioType == kRead_GrIOType) {
81 this->setReadOnly();
82 }
83 this->registerWithCacheWrapped(cacheable);
84 }
85
86 // 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)87 GrVkTexture::GrVkTexture(GrVkGpu* gpu,
88 SkISize dimensions,
89 sk_sp<GrVkImage> texture,
90 GrMipmapStatus mipmapStatus,
91 std::string_view label)
92 : GrSurface(gpu,
93 dimensions,
94 texture->isProtected() ? GrProtected::kYes : GrProtected::kNo,
95 label)
96 , GrTexture(gpu,
97 dimensions,
98 texture->isProtected() ? GrProtected::kYes : GrProtected::kNo,
99 GrTextureType::k2D,
100 mipmapStatus,
101 label)
102 , fTexture(std::move(texture))
103 , fDescSetCache(kMaxCachedDescSets) {
104 SkASSERT((GrMipmapStatus::kNotAllocated == mipmapStatus) == (1 == fTexture->mipLevels()));
105 // Since this ctor is only called from GrVkTextureRenderTarget, we can't have a ycbcr conversion
106 // since we don't support that on render targets.
107 SkASSERT(!fTexture->ycbcrConversionInfo().isValid());
108 SkASSERT(SkToBool(fTexture->vkUsageFlags() & VK_IMAGE_USAGE_SAMPLED_BIT));
109 }
110
MakeNewTexture(GrVkGpu * gpu,skgpu::Budgeted budgeted,SkISize dimensions,VkFormat format,uint32_t mipLevels,GrProtected isProtected,GrMipmapStatus mipmapStatus,std::string_view label)111 sk_sp<GrVkTexture> GrVkTexture::MakeNewTexture(GrVkGpu* gpu,
112 skgpu::Budgeted budgeted,
113 SkISize dimensions,
114 VkFormat format,
115 uint32_t mipLevels,
116 GrProtected isProtected,
117 GrMipmapStatus mipmapStatus,
118 std::string_view label) {
119 sk_sp<GrVkImage> texture = GrVkImage::MakeTexture(
120 gpu, dimensions, format, mipLevels, GrRenderable::kNo, /*numSamples=*/1, budgeted,
121 isProtected);
122
123 if (!texture) {
124 return nullptr;
125 }
126 return sk_sp<GrVkTexture>(new GrVkTexture(
127 gpu, budgeted, dimensions, std::move(texture), mipmapStatus, label));
128 }
129
MakeWrappedTexture(GrVkGpu * gpu,SkISize dimensions,GrWrapOwnership wrapOwnership,GrWrapCacheable cacheable,GrIOType ioType,const GrVkImageInfo & info,sk_sp<skgpu::MutableTextureState> mutableState)130 sk_sp<GrVkTexture> GrVkTexture::MakeWrappedTexture(
131 GrVkGpu* gpu, SkISize dimensions, GrWrapOwnership wrapOwnership, GrWrapCacheable cacheable,
132 GrIOType ioType, const GrVkImageInfo& info,
133 sk_sp<skgpu::MutableTextureState> mutableState) {
134 // Adopted textures require both image and allocation because we're responsible for freeing
135 SkASSERT(VK_NULL_HANDLE != info.fImage &&
136 (kBorrow_GrWrapOwnership == wrapOwnership || VK_NULL_HANDLE != info.fAlloc.fMemory));
137
138 sk_sp<GrVkImage> texture = GrVkImage::MakeWrapped(gpu,
139 dimensions,
140 info,
141 std::move(mutableState),
142 GrAttachment::UsageFlags::kTexture,
143 wrapOwnership,
144 cacheable,
145 "VkImage_MakeWrappedTexture");
146 if (!texture) {
147 return nullptr;
148 }
149
150 GrMipmapStatus mipmapStatus = info.fLevelCount > 1 ? GrMipmapStatus::kValid
151 : GrMipmapStatus::kNotAllocated;
152
153 bool isExternal = info.fYcbcrConversionInfo.isValid() &&
154 (info.fYcbcrConversionInfo.fExternalFormat != 0);
155 isExternal |= (info.fImageTiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT);
156 return sk_sp<GrVkTexture>(new GrVkTexture(gpu,
157 dimensions,
158 std::move(texture),
159 mipmapStatus,
160 cacheable,
161 ioType,
162 isExternal,
163 /*label=*/"Vk_MakeWrappedTexture"));
164 }
165
~GrVkTexture()166 GrVkTexture::~GrVkTexture() {
167 // either release or abandon should have been called by the owner of this object.
168 SkASSERT(!fTexture);
169 }
170
onRelease()171 void GrVkTexture::onRelease() {
172 fTexture.reset();
173
174 fDescSetCache.reset();
175
176 GrTexture::onRelease();
177 }
178
179 struct GrVkTexture::DescriptorCacheEntry {
DescriptorCacheEntryGrVkTexture::DescriptorCacheEntry180 DescriptorCacheEntry(const GrVkDescriptorSet* fDescSet, GrVkGpu* gpu)
181 : fDescriptorSet(fDescSet), fGpu(gpu) {}
~DescriptorCacheEntryGrVkTexture::DescriptorCacheEntry182 ~DescriptorCacheEntry() {
183 if (fDescriptorSet) {
184 fDescriptorSet->recycle();
185 }
186 }
187
188 const GrVkDescriptorSet* fDescriptorSet;
189 GrVkGpu* fGpu;
190 };
191
onAbandon()192 void GrVkTexture::onAbandon() {
193 fTexture.reset();
194
195 fDescSetCache.reset();
196
197 GrTexture::onAbandon();
198 }
199
getBackendTexture() const200 GrBackendTexture GrVkTexture::getBackendTexture() const {
201 return GrBackendTextures::MakeVk(fTexture->width(),
202 fTexture->height(),
203 fTexture->vkImageInfo(),
204 fTexture->getMutableState());
205 }
206
getVkGpu() const207 GrVkGpu* GrVkTexture::getVkGpu() const {
208 SkASSERT(!this->wasDestroyed());
209 return static_cast<GrVkGpu*>(this->getGpu());
210 }
211
textureView()212 const GrVkImageView* GrVkTexture::textureView() { return fTexture->textureView(); }
213
cachedSingleDescSet(GrSamplerState state)214 const GrVkDescriptorSet* GrVkTexture::cachedSingleDescSet(GrSamplerState state) {
215 if (std::unique_ptr<DescriptorCacheEntry>* e = fDescSetCache.find(state)) {
216 return (*e)->fDescriptorSet;
217 }
218 return nullptr;
219 }
220
addDescriptorSetToCache(const GrVkDescriptorSet * descSet,GrSamplerState state)221 void GrVkTexture::addDescriptorSetToCache(const GrVkDescriptorSet* descSet, GrSamplerState state) {
222 SkASSERT(!fDescSetCache.find(state));
223 descSet->ref();
224 fDescSetCache.insert(state, std::make_unique<DescriptorCacheEntry>(descSet, this->getVkGpu()));
225 }
226