xref: /aosp_15_r20/external/skia/src/gpu/ganesh/vk/GrVkBackendSurface.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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