• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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