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/ganesh/GrBackendSurface.h"
13 #include "include/gpu/ganesh/GrTypes.h"
14 #include "include/gpu/MutableTextureState.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 default:
53 return SkTextureCompressionType::kNone;
54 }
55 }
56
bytesPerBlock() const57 size_t bytesPerBlock() const override {
58 return skgpu::VkFormatBytesPerBlock(fFormat);
59 }
60
stencilBits() const61 int stencilBits() const override {
62 return skgpu::VkFormatStencilBits(fFormat);
63 }
64
channelMask() const65 uint32_t channelMask() const override {
66 return skgpu::VkFormatChannels(fFormat);
67 }
68
desc() const69 GrColorFormatDesc desc() const override {
70 return GrVkFormatDesc(fFormat);
71 }
72
equal(const GrBackendFormatData * that) const73 bool equal(const GrBackendFormatData* that) const override {
74 SkASSERT(!that || that->type() == GrBackendApi::kVulkan);
75 if (auto otherVk = static_cast<const GrVkBackendFormatData*>(that)) {
76 return fFormat == otherVk->fFormat &&
77 fYcbcrConversionInfo == otherVk->fYcbcrConversionInfo;
78 }
79 return false;
80 }
81
toString() const82 std::string toString() const override {
83 #if defined(SK_DEBUG) || defined(GPU_TEST_UTILS)
84 return skgpu::VkFormatToStr(fFormat);
85 #else
86 return "";
87 #endif
88 }
89
copyTo(AnyFormatData & formatData) const90 void copyTo(AnyFormatData& formatData) const override {
91 formatData.emplace<GrVkBackendFormatData>(fFormat, fYcbcrConversionInfo);
92 }
93
makeTexture2D()94 void makeTexture2D() override {
95 // If we have a ycbcr we remove it from the backend format and set the VkFormat to
96 // R8G8B8A8_UNORM
97 if (fYcbcrConversionInfo.isValid()) {
98 fYcbcrConversionInfo = skgpu::VulkanYcbcrConversionInfo();
99 fFormat = VK_FORMAT_R8G8B8A8_UNORM;
100 }
101 }
102
103 #if defined(SK_DEBUG)
type() const104 GrBackendApi type() const override { return GrBackendApi::kVulkan; }
105 #endif
106
107 VkFormat fFormat;
108 skgpu::VulkanYcbcrConversionInfo fYcbcrConversionInfo;
109 };
110
get_and_cast_data(const GrBackendFormat & format)111 static const GrVkBackendFormatData* get_and_cast_data(const GrBackendFormat& format) {
112 auto data = GrBackendSurfacePriv::GetBackendData(format);
113 SkASSERT(!data || data->type() == GrBackendApi::kVulkan);
114 return static_cast<const GrVkBackendFormatData*>(data);
115 }
116
117 namespace GrBackendFormats {
118
MakeVk(VkFormat format,bool willUseDRMFormatModifiers)119 GrBackendFormat MakeVk(VkFormat format, bool willUseDRMFormatModifiers) {
120 return GrBackendSurfacePriv::MakeGrBackendFormat(
121 GrTextureType::k2D,
122 GrBackendApi::kVulkan,
123 GrVkBackendFormatData(format, skgpu::VulkanYcbcrConversionInfo{}));
124 }
125
MakeVk(const skgpu::VulkanYcbcrConversionInfo & ycbcrInfo,bool willUseDRMFormatModifiers)126 GrBackendFormat MakeVk(const skgpu::VulkanYcbcrConversionInfo& ycbcrInfo,
127 bool willUseDRMFormatModifiers) {
128 SkASSERT(ycbcrInfo.isValid());
129 GrTextureType textureType =
130 ((ycbcrInfo.isValid() && ycbcrInfo.fExternalFormat) || willUseDRMFormatModifiers)
131 ? GrTextureType::kExternal
132 : GrTextureType::k2D;
133 return GrBackendSurfacePriv::MakeGrBackendFormat(
134 textureType,
135 GrBackendApi::kVulkan,
136 GrVkBackendFormatData(ycbcrInfo.fFormat, ycbcrInfo));
137 }
138
AsVkFormat(const GrBackendFormat & format,VkFormat * vkFormat)139 bool AsVkFormat(const GrBackendFormat& format, VkFormat* vkFormat) {
140 SkASSERT(vkFormat);
141 if (format.isValid() && format.backend() == GrBackendApi::kVulkan) {
142 const GrVkBackendFormatData* data = get_and_cast_data(format);
143 SkASSERT(data);
144 *vkFormat = data->asVkFormat();
145 return true;
146 }
147 return false;
148 }
149
GetVkYcbcrConversionInfo(const GrBackendFormat & format)150 const skgpu::VulkanYcbcrConversionInfo* GetVkYcbcrConversionInfo(const GrBackendFormat& format) {
151 if (format.isValid() && format.backend() == GrBackendApi::kVulkan) {
152 const GrVkBackendFormatData* data = get_and_cast_data(format);
153 SkASSERT(data);
154 return data->getYcbcrConversionInfo();
155 }
156 return nullptr;
157 }
158
159 } // namespace GrBackendFormats
160
161
162 class GrVkBackendTextureData final : public GrBackendTextureData {
163 public:
GrVkBackendTextureData(const GrVkImageInfo & info,sk_sp<skgpu::MutableTextureState> mutableState=nullptr)164 GrVkBackendTextureData(const GrVkImageInfo& info,
165 sk_sp<skgpu::MutableTextureState> mutableState = nullptr)
166 : fVkInfo(info) {
167 if (mutableState) {
168 fMutableState = std::move(mutableState);
169 } else {
170 fMutableState =
171 sk_make_sp<skgpu::MutableTextureState>(skgpu::MutableTextureStates::MakeVulkan(
172 info.fImageLayout, info.fCurrentQueueFamily));
173 }
174 }
175
info() const176 const GrVkImageInfo& info() const { return fVkInfo; }
177
getMutableState() const178 sk_sp<skgpu::MutableTextureState> getMutableState() const override {
179 return fMutableState;
180 }
setMutableState(const skgpu::MutableTextureState & state)181 void setMutableState(const skgpu::MutableTextureState& state) override {
182 fMutableState->set(state);
183 }
184
mutableState()185 skgpu::MutableTextureState* mutableState() { return fMutableState.get(); }
mutableState() const186 const skgpu::MutableTextureState* mutableState() const { return fMutableState.get(); }
187
188 private:
copyTo(AnyTextureData & textureData) const189 void copyTo(AnyTextureData& textureData) const override {
190 textureData.emplace<GrVkBackendTextureData>(fVkInfo, fMutableState);
191 }
192
isProtected() const193 bool isProtected() const override { return fVkInfo.fProtected == skgpu::Protected::kYes; }
194
equal(const GrBackendTextureData * that) const195 bool equal(const GrBackendTextureData* that) const override {
196 SkASSERT(!that || that->type() == GrBackendApi::kVulkan);
197 if (auto otherVk = static_cast<const GrVkBackendTextureData*>(that)) {
198 // For our tests when checking equality we are assuming both backendTexture objects will
199 // be using the same mutable state object.
200 if (fMutableState != otherVk->fMutableState) {
201 return false;
202 }
203 return GrVkImageInfoWithMutableState(fVkInfo, fMutableState.get()) ==
204 GrVkImageInfoWithMutableState(otherVk->fVkInfo, fMutableState.get());
205 }
206 return false;
207 }
208
isSameTexture(const GrBackendTextureData * that) const209 bool isSameTexture(const GrBackendTextureData* that) const override {
210 SkASSERT(!that || that->type() == GrBackendApi::kVulkan);
211 if (auto otherVk = static_cast<const GrVkBackendTextureData*>(that)) {
212 return fVkInfo.fImage == otherVk->fVkInfo.fImage;
213 }
214 return false;
215
216 }
217
getBackendFormat() const218 GrBackendFormat getBackendFormat() const override {
219 auto info = GrVkImageInfoWithMutableState(fVkInfo, fMutableState.get());
220 bool usesDRMModifier = info.fImageTiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT;
221 if (info.fYcbcrConversionInfo.isValid()) {
222 SkASSERT(info.fFormat == info.fYcbcrConversionInfo.fFormat);
223 return GrBackendFormats::MakeVk(info.fYcbcrConversionInfo, usesDRMModifier);
224 }
225 return GrBackendFormats::MakeVk(info.fFormat, usesDRMModifier);
226 }
227
228 #if defined(SK_DEBUG)
type() const229 GrBackendApi type() const override { return GrBackendApi::kVulkan; }
230 #endif
231
232 GrVkImageInfo fVkInfo;
233 sk_sp<skgpu::MutableTextureState> fMutableState;
234 };
235
get_and_cast_data(const GrBackendTexture & texture)236 static const GrVkBackendTextureData* get_and_cast_data(const GrBackendTexture& texture) {
237 auto data = GrBackendSurfacePriv::GetBackendData(texture);
238 SkASSERT(!data || data->type() == GrBackendApi::kVulkan);
239 return static_cast<const GrVkBackendTextureData*>(data);
240 }
241
get_and_cast_data(GrBackendTexture * texture)242 static GrVkBackendTextureData* get_and_cast_data(GrBackendTexture* texture) {
243 auto data = GrBackendSurfacePriv::GetBackendData(texture);
244 SkASSERT(!data || data->type() == GrBackendApi::kVulkan);
245 return static_cast<GrVkBackendTextureData*>(data);
246 }
247
vk_image_info_to_texture_type(const GrVkImageInfo & info)248 static GrTextureType vk_image_info_to_texture_type(const GrVkImageInfo& info) {
249 if ((info.fYcbcrConversionInfo.isValid() && info.fYcbcrConversionInfo.fExternalFormat != 0) ||
250 info.fImageTiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT) {
251 return GrTextureType::kExternal;
252 }
253 return GrTextureType::k2D;
254 }
255
256 static const VkImageUsageFlags kDefaultUsageFlags =
257 VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
258
259 static const VkImageUsageFlags kDefaultRTUsageFlags =
260 kDefaultUsageFlags | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
261
262 // We don't know if the backend texture is made renderable or not, so we default the usage flags
263 // to include color attachment as well.
264 static const VkImageUsageFlags kDefaultTexRTUsageFlags =
265 kDefaultUsageFlags | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
266
apply_default_usage_flags(const GrVkImageInfo & info,VkImageUsageFlags defaultFlags)267 static GrVkImageInfo apply_default_usage_flags(const GrVkImageInfo& info,
268 VkImageUsageFlags defaultFlags) {
269 if (info.fImageUsageFlags == 0) {
270 GrVkImageInfo newInfo = info;
271 newInfo.fImageUsageFlags = defaultFlags;
272 return newInfo;
273 }
274 return info;
275 }
276
277 namespace GrBackendTextures {
278
MakeVk(int width,int height,const GrVkImageInfo & vkInfo,std::string_view label)279 GrBackendTexture MakeVk(int width,
280 int height,
281 const GrVkImageInfo& vkInfo,
282 std::string_view label) {
283 return GrBackendSurfacePriv::MakeGrBackendTexture(
284 width,
285 height,
286 label,
287 skgpu::Mipmapped(vkInfo.fLevelCount > 1),
288 GrBackendApi::kVulkan,
289 vk_image_info_to_texture_type(vkInfo),
290 GrVkBackendTextureData(apply_default_usage_flags(vkInfo, kDefaultTexRTUsageFlags)));
291 }
292
MakeVk(int width,int height,const GrVkImageInfo & vkInfo,sk_sp<skgpu::MutableTextureState> mutableState)293 GrBackendTexture MakeVk(int width,
294 int height,
295 const GrVkImageInfo& vkInfo,
296 sk_sp<skgpu::MutableTextureState> mutableState) {
297 return GrBackendSurfacePriv::MakeGrBackendTexture(
298 width,
299 height,
300 /*label=*/{},
301 skgpu::Mipmapped(vkInfo.fLevelCount > 1),
302 GrBackendApi::kVulkan,
303 vk_image_info_to_texture_type(vkInfo),
304 GrVkBackendTextureData(apply_default_usage_flags(vkInfo, kDefaultTexRTUsageFlags),
305 std::move(mutableState)));
306 }
307
GetVkImageInfo(const GrBackendTexture & tex,GrVkImageInfo * outInfo)308 bool GetVkImageInfo(const GrBackendTexture& tex, GrVkImageInfo* outInfo) {
309 if (!tex.isValid() || tex.backend() != GrBackendApi::kVulkan) {
310 return false;
311 }
312 const GrVkBackendTextureData* data = get_and_cast_data(tex);
313 SkASSERT(data);
314 *outInfo = GrVkImageInfoWithMutableState(data->info(), data->mutableState());
315 return true;
316 }
317
SetVkImageLayout(GrBackendTexture * tex,VkImageLayout layout)318 void SetVkImageLayout(GrBackendTexture* tex, VkImageLayout layout) {
319 if (tex && tex->isValid() && tex->backend() == GrBackendApi::kVulkan) {
320 GrVkBackendTextureData* data = get_and_cast_data(tex);
321 SkASSERT(data);
322 skgpu::MutableTextureStates::SetVkImageLayout(data->mutableState(), layout);
323 }
324 }
325
326 } // namespace GrBackendTextures
327
328
329 class GrVkBackendRenderTargetData final : public GrBackendRenderTargetData {
330 public:
GrVkBackendRenderTargetData(const GrVkImageInfo & info,sk_sp<skgpu::MutableTextureState> mutableState=nullptr)331 GrVkBackendRenderTargetData(const GrVkImageInfo& info,
332 sk_sp<skgpu::MutableTextureState> mutableState = nullptr)
333 : fVkInfo(info) {
334 if (mutableState) {
335 fMutableState = std::move(mutableState);
336 } else {
337 fMutableState =
338 sk_make_sp<skgpu::MutableTextureState>(skgpu::MutableTextureStates::MakeVulkan(
339 info.fImageLayout, info.fCurrentQueueFamily));
340 }
341 }
342
info() const343 const GrVkImageInfo& info() const { return fVkInfo; }
344
getMutableState() const345 sk_sp<skgpu::MutableTextureState> getMutableState() const override {
346 return fMutableState;
347 }
setMutableState(const skgpu::MutableTextureState & state)348 void setMutableState(const skgpu::MutableTextureState& state) override {
349 fMutableState->set(state);
350 }
351
mutableState()352 skgpu::MutableTextureState* mutableState() { return fMutableState.get(); }
mutableState() const353 const skgpu::MutableTextureState* mutableState() const { return fMutableState.get(); }
354
355 private:
getBackendFormat() const356 GrBackendFormat getBackendFormat() const override {
357 auto info = GrVkImageInfoWithMutableState(fVkInfo, fMutableState.get());
358 if (info.fYcbcrConversionInfo.isValid()) {
359 SkASSERT(info.fFormat == info.fYcbcrConversionInfo.fFormat);
360 return GrBackendFormats::MakeVk(info.fYcbcrConversionInfo);
361 }
362 return GrBackendFormats::MakeVk(info.fFormat);
363 }
364
isProtected() const365 bool isProtected() const override { return fVkInfo.fProtected == skgpu::Protected::kYes; }
366
equal(const GrBackendRenderTargetData * that) const367 bool equal(const GrBackendRenderTargetData* that) const override {
368 SkASSERT(!that || that->type() == GrBackendApi::kVulkan);
369 if (auto otherVk = static_cast<const GrVkBackendRenderTargetData*>(that)) {
370 // For our tests when checking equality we are assuming both objects will be using the
371 // same mutable state object.
372 if (fMutableState != otherVk->fMutableState) {
373 return false;
374 }
375 return GrVkImageInfoWithMutableState(fVkInfo, fMutableState.get()) ==
376 GrVkImageInfoWithMutableState(otherVk->fVkInfo, fMutableState.get());
377 }
378 return false;
379 }
380
copyTo(AnyRenderTargetData & rtData) const381 void copyTo(AnyRenderTargetData& rtData) const override {
382 rtData.emplace<GrVkBackendRenderTargetData>(fVkInfo, fMutableState);
383 }
384
385 #if defined(SK_DEBUG)
type() const386 GrBackendApi type() const override { return GrBackendApi::kVulkan; }
387 #endif
388
389 GrVkImageInfo fVkInfo;
390 sk_sp<skgpu::MutableTextureState> fMutableState;
391 };
392
get_and_cast_data(const GrBackendRenderTarget & rt)393 static const GrVkBackendRenderTargetData* get_and_cast_data(const GrBackendRenderTarget& rt) {
394 auto data = GrBackendSurfacePriv::GetBackendData(rt);
395 SkASSERT(!data || data->type() == GrBackendApi::kVulkan);
396 return static_cast<const GrVkBackendRenderTargetData*>(data);
397 }
398
get_and_cast_data(GrBackendRenderTarget * rt)399 static GrVkBackendRenderTargetData* get_and_cast_data(GrBackendRenderTarget* rt) {
400 auto data = GrBackendSurfacePriv::GetBackendData(rt);
401 SkASSERT(!data || data->type() == GrBackendApi::kVulkan);
402 return static_cast<GrVkBackendRenderTargetData*>(data);
403 }
404
405 namespace GrBackendRenderTargets {
406
MakeVk(int width,int height,const GrVkImageInfo & vkInfo)407 GrBackendRenderTarget MakeVk(int width, int height, const GrVkImageInfo& vkInfo) {
408 return GrBackendSurfacePriv::MakeGrBackendRenderTarget(
409 width,
410 height,
411 std::max(1U, vkInfo.fSampleCount),
412 /*stencilBits=*/0,
413 GrBackendApi::kVulkan,
414 /*framebufferOnly=*/false,
415 GrVkBackendRenderTargetData(apply_default_usage_flags(vkInfo, kDefaultRTUsageFlags)));
416 }
417
MakeVk(int width,int height,const GrVkImageInfo & vkInfo,sk_sp<skgpu::MutableTextureState> mutableState)418 GrBackendRenderTarget MakeVk(int width,
419 int height,
420 const GrVkImageInfo& vkInfo,
421 sk_sp<skgpu::MutableTextureState> mutableState) {
422 return GrBackendSurfacePriv::MakeGrBackendRenderTarget(
423 width,
424 height,
425 std::max(1U, vkInfo.fSampleCount),
426 /*stencilBits=*/0,
427 GrBackendApi::kVulkan,
428 /*framebufferOnly=*/false,
429 GrVkBackendRenderTargetData(apply_default_usage_flags(vkInfo, kDefaultRTUsageFlags),
430 std::move(mutableState)));
431 }
432
GetVkImageInfo(const GrBackendRenderTarget & rt,GrVkImageInfo * outInfo)433 bool GetVkImageInfo(const GrBackendRenderTarget& rt, GrVkImageInfo* outInfo) {
434 if (!rt.isValid() || rt.backend() != GrBackendApi::kVulkan) {
435 return false;
436 }
437 const GrVkBackendRenderTargetData* data = get_and_cast_data(rt);
438 SkASSERT(data);
439 *outInfo = GrVkImageInfoWithMutableState(data->info(), data->mutableState());
440 return true;
441 }
442
SetVkImageLayout(GrBackendRenderTarget * rt,VkImageLayout layout)443 void SetVkImageLayout(GrBackendRenderTarget* rt, VkImageLayout layout) {
444 if (rt && rt->isValid() && rt->backend() == GrBackendApi::kVulkan) {
445 GrVkBackendRenderTargetData* data = get_and_cast_data(rt);
446 skgpu::MutableTextureStates::SetVkImageLayout(data->mutableState(), layout);
447 }
448 }
449
450 } // namespace GrBackendRenderTargets
451