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