1 /*
2 * Copyright 2023 Google LLC
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 #include "include/gpu/ganesh/vk/GrVkBackendSurface.h"
8
9 #include "include/core/SkRefCnt.h"
10 #include "include/core/SkTextureCompressionType.h"
11 #include "include/gpu/GpuTypes.h"
12 #include "include/gpu/GrBackendSurface.h"
13 #include "include/gpu/GrTypes.h"
14 #include "include/gpu/MutableTextureState.h"
15 #include "include/gpu/vk/GrVkTypes.h"
16 #include "include/gpu/vk/VulkanMutableTextureState.h"
17 #include "include/private/base/SkAssert.h"
18 #include "include/private/base/SkTo.h"
19 #include "include/private/gpu/ganesh/GrTypesPriv.h"
20 #include "src/gpu/ganesh/GrBackendSurfacePriv.h"
21 #include "src/gpu/ganesh/vk/GrVkTypesPriv.h"
22 #include "src/gpu/ganesh/vk/GrVkUtil.h"
23 #include "src/gpu/vk/VulkanMutableTextureStatePriv.h"
24 #include "src/gpu/vk/VulkanUtilsPriv.h"
25
26 #include <algorithm>
27 #include <cstddef>
28 #include <cstdint>
29 #include <string>
30
31 class GrVkBackendFormatData final : public GrBackendFormatData {
32 public:
GrVkBackendFormatData(VkFormat format,const GrVkYcbcrConversionInfo & ycbcrInfo)33 GrVkBackendFormatData(VkFormat format, const GrVkYcbcrConversionInfo& ycbcrInfo)
34 : fFormat(format), fYcbcrConversionInfo(ycbcrInfo) {}
35
asVkFormat() const36 VkFormat asVkFormat() const { return fFormat; }
getYcbcrConversionInfo() const37 const GrVkYcbcrConversionInfo* getYcbcrConversionInfo() const { return &fYcbcrConversionInfo; }
38
39 private:
compressionType() const40 SkTextureCompressionType compressionType() const override {
41 switch (fFormat) {
42 case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK:
43 return SkTextureCompressionType::kETC2_RGB8_UNORM;
44 case VK_FORMAT_BC1_RGB_UNORM_BLOCK:
45 return SkTextureCompressionType::kBC1_RGB8_UNORM;
46 case VK_FORMAT_BC1_RGBA_UNORM_BLOCK:
47 return SkTextureCompressionType::kBC1_RGBA8_UNORM;
48 default:
49 return SkTextureCompressionType::kNone;
50 }
51 }
52
bytesPerBlock() const53 size_t bytesPerBlock() const override {
54 return skgpu::VkFormatBytesPerBlock(fFormat);
55 }
56
stencilBits() const57 int stencilBits() const override {
58 return skgpu::VkFormatStencilBits(fFormat);
59 }
60
channelMask() const61 uint32_t channelMask() const override {
62 return skgpu::VkFormatChannels(fFormat);
63 }
64
desc() const65 GrColorFormatDesc desc() const override {
66 return GrVkFormatDesc(fFormat);
67 }
68
equal(const GrBackendFormatData * that) const69 bool equal(const GrBackendFormatData* that) const override {
70 SkASSERT(!that || that->type() == GrBackendApi::kVulkan);
71 if (auto otherVk = static_cast<const GrVkBackendFormatData*>(that)) {
72 return fFormat == otherVk->fFormat &&
73 fYcbcrConversionInfo == otherVk->fYcbcrConversionInfo;
74 }
75 return false;
76 }
77
toString() const78 std::string toString() const override {
79 #if defined(SK_DEBUG) || GR_TEST_UTILS
80 return skgpu::VkFormatToStr(fFormat);
81 #else
82 return "";
83 #endif
84 }
85
copyTo(AnyFormatData & formatData) const86 void copyTo(AnyFormatData& formatData) const override {
87 formatData.emplace<GrVkBackendFormatData>(fFormat, fYcbcrConversionInfo);
88 }
89
makeTexture2D()90 void makeTexture2D() override {
91 // If we have a ycbcr we remove it from the backend format and set the VkFormat to
92 // R8G8B8A8_UNORM
93 if (fYcbcrConversionInfo.isValid()) {
94 fYcbcrConversionInfo = GrVkYcbcrConversionInfo();
95 fFormat = VK_FORMAT_R8G8B8A8_UNORM;
96 }
97 }
98
99 #if defined(SK_DEBUG)
type() const100 GrBackendApi type() const override { return GrBackendApi::kVulkan; }
101 #endif
102
103 VkFormat fFormat;
104 GrVkYcbcrConversionInfo fYcbcrConversionInfo;
105 };
106
get_and_cast_data(const GrBackendFormat & format)107 static const GrVkBackendFormatData* get_and_cast_data(const GrBackendFormat& format) {
108 auto data = GrBackendSurfacePriv::GetBackendData(format);
109 SkASSERT(!data || data->type() == GrBackendApi::kVulkan);
110 return static_cast<const GrVkBackendFormatData*>(data);
111 }
112
113 namespace GrBackendFormats {
114
MakeVk(VkFormat format,bool willUseDRMFormatModifiers)115 GrBackendFormat MakeVk(VkFormat format, bool willUseDRMFormatModifiers) {
116 return GrBackendSurfacePriv::MakeGrBackendFormat(
117 GrTextureType::k2D,
118 GrBackendApi::kVulkan,
119 GrVkBackendFormatData(format, GrVkYcbcrConversionInfo{}));
120 }
121
MakeVk(const GrVkYcbcrConversionInfo & ycbcrInfo,bool willUseDRMFormatModifiers)122 GrBackendFormat MakeVk(const GrVkYcbcrConversionInfo& ycbcrInfo, bool willUseDRMFormatModifiers) {
123 SkASSERT(ycbcrInfo.isValid());
124 GrTextureType textureType =
125 ((ycbcrInfo.isValid() && ycbcrInfo.fExternalFormat) || willUseDRMFormatModifiers)
126 ? GrTextureType::kExternal
127 : GrTextureType::k2D;
128 return GrBackendSurfacePriv::MakeGrBackendFormat(
129 textureType,
130 GrBackendApi::kVulkan,
131 GrVkBackendFormatData(ycbcrInfo.fFormat, ycbcrInfo));
132 }
133
AsVkFormat(const GrBackendFormat & format,VkFormat * vkFormat)134 bool AsVkFormat(const GrBackendFormat& format, VkFormat* vkFormat) {
135 SkASSERT(vkFormat);
136 if (format.isValid() && format.backend() == GrBackendApi::kVulkan) {
137 const GrVkBackendFormatData* data = get_and_cast_data(format);
138 SkASSERT(data);
139 *vkFormat = data->asVkFormat();
140 return true;
141 }
142 return false;
143 }
144
GetVkYcbcrConversionInfo(const GrBackendFormat & format)145 const GrVkYcbcrConversionInfo* GetVkYcbcrConversionInfo(const GrBackendFormat& format) {
146 if (format.isValid() && format.backend() == GrBackendApi::kVulkan) {
147 const GrVkBackendFormatData* data = get_and_cast_data(format);
148 SkASSERT(data);
149 return data->getYcbcrConversionInfo();
150 }
151 return nullptr;
152 }
153
154 } // namespace GrBackendFormats
155
156
157 class GrVkBackendTextureData final : public GrBackendTextureData {
158 public:
GrVkBackendTextureData(const GrVkImageInfo & info,sk_sp<skgpu::MutableTextureState> mutableState=nullptr)159 GrVkBackendTextureData(const GrVkImageInfo& info,
160 sk_sp<skgpu::MutableTextureState> mutableState = nullptr)
161 : fVkInfo(info) {
162 if (mutableState) {
163 fMutableState = std::move(mutableState);
164 } else {
165 fMutableState =
166 sk_make_sp<skgpu::MutableTextureState>(skgpu::MutableTextureStates::MakeVulkan(
167 info.fImageLayout, info.fCurrentQueueFamily));
168 }
169 }
170
info() const171 const GrVkImageInfo& info() const { return fVkInfo; }
172
getMutableState() const173 sk_sp<skgpu::MutableTextureState> getMutableState() const override {
174 return fMutableState;
175 }
setMutableState(const skgpu::MutableTextureState & state)176 void setMutableState(const skgpu::MutableTextureState& state) override {
177 fMutableState->set(state);
178 }
179
mutableState()180 skgpu::MutableTextureState* mutableState() { return fMutableState.get(); }
mutableState() const181 const skgpu::MutableTextureState* mutableState() const { return fMutableState.get(); }
182
183 private:
copyTo(AnyTextureData & textureData) const184 void copyTo(AnyTextureData& textureData) const override {
185 textureData.emplace<GrVkBackendTextureData>(fVkInfo, fMutableState);
186 }
187
isProtected() const188 bool isProtected() const override { return fVkInfo.fProtected == skgpu::Protected::kYes; }
189
equal(const GrBackendTextureData * that) const190 bool equal(const GrBackendTextureData* that) const override {
191 SkASSERT(!that || that->type() == GrBackendApi::kVulkan);
192 if (auto otherVk = static_cast<const GrVkBackendTextureData*>(that)) {
193 // For our tests when checking equality we are assuming both backendTexture objects will
194 // be using the same mutable state object.
195 if (fMutableState != otherVk->fMutableState) {
196 return false;
197 }
198 return GrVkImageInfoWithMutableState(fVkInfo, fMutableState.get()) ==
199 GrVkImageInfoWithMutableState(otherVk->fVkInfo, fMutableState.get());
200 }
201 return false;
202 }
203
isSameTexture(const GrBackendTextureData * that) const204 bool isSameTexture(const GrBackendTextureData* that) const override {
205 SkASSERT(!that || that->type() == GrBackendApi::kVulkan);
206 if (auto otherVk = static_cast<const GrVkBackendTextureData*>(that)) {
207 return fVkInfo.fImage == otherVk->fVkInfo.fImage;
208 }
209 return false;
210
211 }
212
getBackendFormat() const213 GrBackendFormat getBackendFormat() const override {
214 auto info = GrVkImageInfoWithMutableState(fVkInfo, fMutableState.get());
215 bool usesDRMModifier = info.fImageTiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT;
216 if (info.fYcbcrConversionInfo.isValid()) {
217 SkASSERT(info.fFormat == info.fYcbcrConversionInfo.fFormat);
218 return GrBackendFormats::MakeVk(info.fYcbcrConversionInfo, usesDRMModifier);
219 }
220 return GrBackendFormats::MakeVk(info.fFormat, usesDRMModifier);
221 }
222
223 #if defined(SK_DEBUG)
type() const224 GrBackendApi type() const override { return GrBackendApi::kVulkan; }
225 #endif
226
227 GrVkImageInfo fVkInfo;
228 sk_sp<skgpu::MutableTextureState> fMutableState;
229 };
230
get_and_cast_data(const GrBackendTexture & texture)231 static const GrVkBackendTextureData* get_and_cast_data(const GrBackendTexture& texture) {
232 auto data = GrBackendSurfacePriv::GetBackendData(texture);
233 SkASSERT(!data || data->type() == GrBackendApi::kVulkan);
234 return static_cast<const GrVkBackendTextureData*>(data);
235 }
236
get_and_cast_data(GrBackendTexture * texture)237 static GrVkBackendTextureData* get_and_cast_data(GrBackendTexture* texture) {
238 auto data = GrBackendSurfacePriv::GetBackendData(texture);
239 SkASSERT(!data || data->type() == GrBackendApi::kVulkan);
240 return static_cast<GrVkBackendTextureData*>(data);
241 }
242
vk_image_info_to_texture_type(const GrVkImageInfo & info)243 static GrTextureType vk_image_info_to_texture_type(const GrVkImageInfo& info) {
244 if ((info.fYcbcrConversionInfo.isValid() && info.fYcbcrConversionInfo.fExternalFormat != 0) ||
245 info.fImageTiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT) {
246 return GrTextureType::kExternal;
247 }
248 return GrTextureType::k2D;
249 }
250
251 static const VkImageUsageFlags kDefaultUsageFlags =
252 VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
253
254 static const VkImageUsageFlags kDefaultRTUsageFlags =
255 kDefaultUsageFlags | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
256
257 // We don't know if the backend texture is made renderable or not, so we default the usage flags
258 // to include color attachment as well.
259 static const VkImageUsageFlags kDefaultTexRTUsageFlags =
260 kDefaultUsageFlags | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
261
apply_default_usage_flags(const GrVkImageInfo & info,VkImageUsageFlags defaultFlags)262 static GrVkImageInfo apply_default_usage_flags(const GrVkImageInfo& info,
263 VkImageUsageFlags defaultFlags) {
264 if (info.fImageUsageFlags == 0) {
265 GrVkImageInfo newInfo = info;
266 newInfo.fImageUsageFlags = defaultFlags;
267 return newInfo;
268 }
269 return info;
270 }
271
272 namespace GrBackendTextures {
273
MakeVk(int width,int height,const GrVkImageInfo & vkInfo,std::string_view label)274 GrBackendTexture MakeVk(int width,
275 int height,
276 const GrVkImageInfo& vkInfo,
277 std::string_view label) {
278 return GrBackendSurfacePriv::MakeGrBackendTexture(
279 width,
280 height,
281 label,
282 skgpu::Mipmapped(vkInfo.fLevelCount > 1),
283 GrBackendApi::kVulkan,
284 vk_image_info_to_texture_type(vkInfo),
285 GrVkBackendTextureData(apply_default_usage_flags(vkInfo, kDefaultTexRTUsageFlags)));
286 }
287
MakeVk(int width,int height,const GrVkImageInfo & vkInfo,sk_sp<skgpu::MutableTextureState> mutableState)288 GrBackendTexture MakeVk(int width,
289 int height,
290 const GrVkImageInfo& vkInfo,
291 sk_sp<skgpu::MutableTextureState> mutableState) {
292 return GrBackendSurfacePriv::MakeGrBackendTexture(
293 width,
294 height,
295 /*label=*/{},
296 skgpu::Mipmapped(vkInfo.fLevelCount > 1),
297 GrBackendApi::kVulkan,
298 vk_image_info_to_texture_type(vkInfo),
299 GrVkBackendTextureData(apply_default_usage_flags(vkInfo, kDefaultTexRTUsageFlags),
300 std::move(mutableState)));
301 }
302
GetVkImageInfo(const GrBackendTexture & tex,GrVkImageInfo * outInfo)303 bool GetVkImageInfo(const GrBackendTexture& tex, GrVkImageInfo* outInfo) {
304 if (!tex.isValid() || tex.backend() != GrBackendApi::kVulkan) {
305 return false;
306 }
307 const GrVkBackendTextureData* data = get_and_cast_data(tex);
308 SkASSERT(data);
309 *outInfo = GrVkImageInfoWithMutableState(data->info(), data->mutableState());
310 return true;
311 }
312
SetVkImageLayout(GrBackendTexture * tex,VkImageLayout layout)313 void SetVkImageLayout(GrBackendTexture* tex, VkImageLayout layout) {
314 if (tex && tex->isValid() && tex->backend() == GrBackendApi::kVulkan) {
315 GrVkBackendTextureData* data = get_and_cast_data(tex);
316 SkASSERT(data);
317 skgpu::MutableTextureStates::SetVkImageLayout(data->mutableState(), layout);
318 }
319 }
320
321 } // namespace GrBackendTextures
322
323
324 class GrVkBackendRenderTargetData final : public GrBackendRenderTargetData {
325 public:
GrVkBackendRenderTargetData(const GrVkImageInfo & info,sk_sp<skgpu::MutableTextureState> mutableState=nullptr)326 GrVkBackendRenderTargetData(const GrVkImageInfo& info,
327 sk_sp<skgpu::MutableTextureState> mutableState = nullptr)
328 : fVkInfo(info) {
329 if (mutableState) {
330 fMutableState = std::move(mutableState);
331 } else {
332 fMutableState =
333 sk_make_sp<skgpu::MutableTextureState>(skgpu::MutableTextureStates::MakeVulkan(
334 info.fImageLayout, info.fCurrentQueueFamily));
335 }
336 }
337
info() const338 const GrVkImageInfo& info() const { return fVkInfo; }
339
getMutableState() const340 sk_sp<skgpu::MutableTextureState> getMutableState() const override {
341 return fMutableState;
342 }
setMutableState(const skgpu::MutableTextureState & state)343 void setMutableState(const skgpu::MutableTextureState& state) override {
344 fMutableState->set(state);
345 }
346
mutableState()347 skgpu::MutableTextureState* mutableState() { return fMutableState.get(); }
mutableState() const348 const skgpu::MutableTextureState* mutableState() const { return fMutableState.get(); }
349
350 private:
getBackendFormat() const351 GrBackendFormat getBackendFormat() const override {
352 auto info = GrVkImageInfoWithMutableState(fVkInfo, fMutableState.get());
353 if (info.fYcbcrConversionInfo.isValid()) {
354 SkASSERT(info.fFormat == info.fYcbcrConversionInfo.fFormat);
355 return GrBackendFormats::MakeVk(info.fYcbcrConversionInfo);
356 }
357 return GrBackendFormats::MakeVk(info.fFormat);
358 }
359
isProtected() const360 bool isProtected() const override { return fVkInfo.fProtected == skgpu::Protected::kYes; }
361
equal(const GrBackendRenderTargetData * that) const362 bool equal(const GrBackendRenderTargetData* that) const override {
363 SkASSERT(!that || that->type() == GrBackendApi::kVulkan);
364 if (auto otherVk = static_cast<const GrVkBackendRenderTargetData*>(that)) {
365 // For our tests when checking equality we are assuming both objects will be using the
366 // same mutable state object.
367 if (fMutableState != otherVk->fMutableState) {
368 return false;
369 }
370 return GrVkImageInfoWithMutableState(fVkInfo, fMutableState.get()) ==
371 GrVkImageInfoWithMutableState(otherVk->fVkInfo, fMutableState.get());
372 }
373 return false;
374 }
375
copyTo(AnyRenderTargetData & rtData) const376 void copyTo(AnyRenderTargetData& rtData) const override {
377 rtData.emplace<GrVkBackendRenderTargetData>(fVkInfo, fMutableState);
378 }
379
380 #if defined(SK_DEBUG)
type() const381 GrBackendApi type() const override { return GrBackendApi::kVulkan; }
382 #endif
383
384 GrVkImageInfo fVkInfo;
385 sk_sp<skgpu::MutableTextureState> fMutableState;
386 };
387
get_and_cast_data(const GrBackendRenderTarget & rt)388 static const GrVkBackendRenderTargetData* get_and_cast_data(const GrBackendRenderTarget& rt) {
389 auto data = GrBackendSurfacePriv::GetBackendData(rt);
390 SkASSERT(!data || data->type() == GrBackendApi::kVulkan);
391 return static_cast<const GrVkBackendRenderTargetData*>(data);
392 }
393
get_and_cast_data(GrBackendRenderTarget * rt)394 static GrVkBackendRenderTargetData* get_and_cast_data(GrBackendRenderTarget* rt) {
395 auto data = GrBackendSurfacePriv::GetBackendData(rt);
396 SkASSERT(!data || data->type() == GrBackendApi::kVulkan);
397 return static_cast<GrVkBackendRenderTargetData*>(data);
398 }
399
400 namespace GrBackendRenderTargets {
401
MakeVk(int width,int height,const GrVkImageInfo & vkInfo)402 GrBackendRenderTarget MakeVk(int width, int height, const GrVkImageInfo& vkInfo) {
403 return GrBackendSurfacePriv::MakeGrBackendRenderTarget(
404 width,
405 height,
406 std::max(1U, vkInfo.fSampleCount),
407 /*stencilBits=*/0,
408 GrBackendApi::kVulkan,
409 /*framebufferOnly=*/false,
410 GrVkBackendRenderTargetData(apply_default_usage_flags(vkInfo, kDefaultRTUsageFlags)));
411 }
412
MakeVk(int width,int height,const GrVkImageInfo & vkInfo,sk_sp<skgpu::MutableTextureState> mutableState)413 GrBackendRenderTarget MakeVk(int width,
414 int height,
415 const GrVkImageInfo& vkInfo,
416 sk_sp<skgpu::MutableTextureState> mutableState) {
417 return GrBackendSurfacePriv::MakeGrBackendRenderTarget(
418 width,
419 height,
420 std::max(1U, vkInfo.fSampleCount),
421 /*stencilBits=*/0,
422 GrBackendApi::kVulkan,
423 /*framebufferOnly=*/false,
424 GrVkBackendRenderTargetData(apply_default_usage_flags(vkInfo, kDefaultRTUsageFlags),
425 std::move(mutableState)));
426 }
427
GetVkImageInfo(const GrBackendRenderTarget & rt,GrVkImageInfo * outInfo)428 bool GetVkImageInfo(const GrBackendRenderTarget& rt, GrVkImageInfo* outInfo) {
429 if (!rt.isValid() || rt.backend() != GrBackendApi::kVulkan) {
430 return false;
431 }
432 const GrVkBackendRenderTargetData* data = get_and_cast_data(rt);
433 SkASSERT(data);
434 *outInfo = GrVkImageInfoWithMutableState(data->info(), data->mutableState());
435 return true;
436 }
437
SetVkImageLayout(GrBackendRenderTarget * rt,VkImageLayout layout)438 void SetVkImageLayout(GrBackendRenderTarget* rt, VkImageLayout layout) {
439 if (rt && rt->isValid() && rt->backend() == GrBackendApi::kVulkan) {
440 GrVkBackendRenderTargetData* data = get_and_cast_data(rt);
441 skgpu::MutableTextureStates::SetVkImageLayout(data->mutableState(), layout);
442 }
443 }
444
445 } // namespace GrBackendRenderTargets
446