• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2022 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 
8 #include "src/gpu/graphite/vk/VulkanCaps.h"
9 
10 #include "include/gpu/graphite/ContextOptions.h"
11 #include "include/gpu/graphite/TextureInfo.h"
12 #include "include/gpu/graphite/vk/VulkanGraphiteTypes.h"
13 #include "include/gpu/vk/VulkanExtensions.h"
14 #include "src/gpu/ganesh/TestFormatColorTypeCombination.h"
15 #include "src/gpu/graphite/vk/VulkanGraphiteUtilsPriv.h"
16 
17 #ifdef SK_BUILD_FOR_ANDROID
18 #include <sys/system_properties.h>
19 #endif
20 
21 namespace skgpu::graphite {
22 
VulkanCaps(const skgpu::VulkanInterface * vkInterface,VkPhysicalDevice physDev,uint32_t physicalDeviceVersion,const skgpu::VulkanExtensions * extensions,const ContextOptions & contextOptions)23 VulkanCaps::VulkanCaps(const skgpu::VulkanInterface* vkInterface,
24                        VkPhysicalDevice physDev,
25                        uint32_t physicalDeviceVersion,
26                        const skgpu::VulkanExtensions* extensions,
27                        const ContextOptions& contextOptions)
28         : Caps() {
29     this->init(vkInterface, physDev, physicalDeviceVersion, extensions, contextOptions);
30 }
31 
~VulkanCaps()32 VulkanCaps::~VulkanCaps() {}
33 
init(const skgpu::VulkanInterface * vkInterface,VkPhysicalDevice physDev,uint32_t physicalDeviceVersion,const skgpu::VulkanExtensions * extensions,const ContextOptions & contextOptions)34 void VulkanCaps::init(const skgpu::VulkanInterface* vkInterface,
35                       VkPhysicalDevice physDev,
36                       uint32_t physicalDeviceVersion,
37                       const skgpu::VulkanExtensions* extensions,
38                       const ContextOptions& contextOptions) {
39     VkPhysicalDeviceProperties physDevProperties;
40     VULKAN_CALL(vkInterface, GetPhysicalDeviceProperties(physDev, &physDevProperties));
41 
42     // Graphite requires Vulkan version 1.1 or later, which has protected support.
43     fProtectedSupport = true;
44 
45     // Enable the use of memoryless attachments for tiler GPUs (ARM Mali and Qualcomm Adreno).
46     if (physDevProperties.vendorID == kARM_VkVendor ||
47         physDevProperties.vendorID == kQualcomm_VkVendor) {
48         fSupportsMemorylessAttachments = true;
49     }
50 
51 #ifdef SK_BUILD_FOR_UNIX
52     if (kNvidia_VkVendor == physDevProperties.vendorID) {
53         // On NVIDIA linux we see a big perf regression when not using dedicated image allocations.
54         fShouldAlwaysUseDedicatedImageMemory = true;
55     }
56 #endif
57 
58     if (physDevProperties.vendorID == kNvidia_VkVendor ||
59         physDevProperties.vendorID == kAMD_VkVendor) {
60         // On discrete GPUs, it can be faster to read gpu-only memory compared to memory that is
61         // also mappable on the host.
62         fGpuOnlyBuffersMorePerformant = true;
63 
64         // On discrete GPUs we try to use special DEVICE_LOCAL and HOST_VISIBLE memory for our
65         // cpu write, gpu read buffers. This memory is not ideal to be kept persistently mapped.
66         // Some discrete GPUs do not expose this special memory, however we still disable
67         // persistently mapped buffers for all of them since most GPUs with updated drivers do
68         // expose it. If this becomes an issue we can try to be more fine grained.
69         fShouldPersistentlyMapCpuToGpuBuffers = false;
70     }
71 
72     this->initFormatTable(vkInterface, physDev, physDevProperties);
73     this->initDepthStencilFormatTable(vkInterface, physDev, physDevProperties);
74 
75     if (!contextOptions.fDisableDriverCorrectnessWorkarounds) {
76         this->applyDriverCorrectnessWorkarounds(physDevProperties);
77     }
78 }
79 
applyDriverCorrectnessWorkarounds(const VkPhysicalDeviceProperties & properties)80 void VulkanCaps::applyDriverCorrectnessWorkarounds(const VkPhysicalDeviceProperties& properties) {
81     // By default, we initialize the Android API version to 0 since we consider certain things
82     // "fixed" only once above a certain version. This way, we default to enabling the workarounds.
83     int androidAPIVersion = 0;
84 #if defined(SK_BUILD_FOR_ANDROID)
85     char androidAPIVersionStr[PROP_VALUE_MAX];
86     int strLength = __system_property_get("ro.build.version.sdk", androidAPIVersionStr);
87     // Defaults to zero since most checks care if it is greater than a specific value. So this will
88     // just default to it being less.
89     androidAPIVersion = (strLength == 0) ? 0 : atoi(androidAPIVersionStr);
90 #endif
91 
92     // On Mali galaxy s7 we see lots of rendering issues when we suballocate VkImages.
93     if (kARM_VkVendor == properties.vendorID && androidAPIVersion <= 28) {
94         fShouldAlwaysUseDedicatedImageMemory = true;
95     }
96 }
97 
98 // These are all the valid VkFormats that we support in Skia. They are roughly ordered from most
99 // frequently used to least to improve look up times in arrays.
100 static constexpr VkFormat kVkFormats[] = {
101     VK_FORMAT_R8G8B8A8_UNORM,
102     VK_FORMAT_R8_UNORM,
103     VK_FORMAT_B8G8R8A8_UNORM,
104     VK_FORMAT_R5G6B5_UNORM_PACK16,
105     VK_FORMAT_R16G16B16A16_SFLOAT,
106     VK_FORMAT_R16_SFLOAT,
107     VK_FORMAT_R8G8B8_UNORM,
108     VK_FORMAT_R8G8_UNORM,
109     VK_FORMAT_A2B10G10R10_UNORM_PACK32,
110     VK_FORMAT_A2R10G10B10_UNORM_PACK32,
111     VK_FORMAT_B4G4R4A4_UNORM_PACK16,
112     VK_FORMAT_R4G4B4A4_UNORM_PACK16,
113     VK_FORMAT_R8G8B8A8_SRGB,
114     VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK,
115     VK_FORMAT_BC1_RGB_UNORM_BLOCK,
116     VK_FORMAT_BC1_RGBA_UNORM_BLOCK,
117     VK_FORMAT_R16_UNORM,
118     VK_FORMAT_R16G16_UNORM,
119     VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM,
120     VK_FORMAT_G8_B8R8_2PLANE_420_UNORM,
121     VK_FORMAT_R16G16B16A16_UNORM,
122     VK_FORMAT_R16G16_SFLOAT,
123 };
124 // These are all the valid depth/stencil formats that we support in Skia.
125 static constexpr VkFormat kDepthStencilVkFormats[] = {
126     VK_FORMAT_S8_UINT,
127     VK_FORMAT_D24_UNORM_S8_UINT,
128     VK_FORMAT_D32_SFLOAT_S8_UINT,
129 };
130 
getDefaultSampledTextureInfo(SkColorType ct,Mipmapped mipmapped,Protected isProtected,Renderable isRenderable) const131 TextureInfo VulkanCaps::getDefaultSampledTextureInfo(SkColorType ct,
132                                                      Mipmapped mipmapped,
133                                                      Protected isProtected,
134                                                      Renderable isRenderable) const {
135     VkFormat format = this->getFormatFromColorType(ct);
136     const FormatInfo& formatInfo = this->getFormatInfo(format);
137     static constexpr int defaultSampleCount = 1;
138     if ((isProtected == Protected::kYes && !this->protectedSupport()) ||
139         !formatInfo.isTexturable(VK_IMAGE_TILING_OPTIMAL) ||
140         (isRenderable == Renderable::kYes &&
141          !formatInfo.isRenderable(VK_IMAGE_TILING_OPTIMAL, defaultSampleCount)) ) {
142         return {};
143     }
144 
145     VulkanTextureInfo info;
146     info.fSampleCount = defaultSampleCount;
147     info.fMipmapped = mipmapped;
148     info.fFlags = (isProtected == Protected::kYes) ? VK_IMAGE_CREATE_PROTECTED_BIT : 0;
149     info.fFormat = format;
150     info.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
151     info.fImageUsageFlags = VK_IMAGE_USAGE_SAMPLED_BIT |
152                             VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
153                             VK_IMAGE_USAGE_TRANSFER_DST_BIT;
154     if (isRenderable == Renderable::kYes) {
155         info.fImageUsageFlags = info.fImageUsageFlags | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
156     }
157     info.fSharingMode = VK_SHARING_MODE_EXCLUSIVE;
158     info.fAspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
159 
160     return info;
161 }
162 
getDefaultMSAATextureInfo(const TextureInfo & singleSampledInfo,Discardable discardable) const163 TextureInfo VulkanCaps::getDefaultMSAATextureInfo(const TextureInfo& singleSampledInfo,
164                                                   Discardable discardable) const {
165     const VkFormat singleSpecFormat = singleSampledInfo.vulkanTextureSpec().fFormat;
166     const FormatInfo& formatInfo = this->getFormatInfo(singleSpecFormat);
167     if ((singleSampledInfo.isProtected() == Protected::kYes && !this->protectedSupport()) ||
168         !formatInfo.isRenderable(VK_IMAGE_TILING_OPTIMAL, this->defaultMSAASamples())) {
169         return {};
170     }
171 
172     VulkanTextureInfo info;
173     info.fSampleCount = this->defaultMSAASamples();
174     info.fMipmapped = Mipmapped::kNo;
175     info.fFlags = (singleSampledInfo.isProtected() == Protected::kYes) ?
176         VK_IMAGE_CREATE_PROTECTED_BIT : 0;
177     info.fFormat = singleSpecFormat;
178     info.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
179 
180     /**
181      * Graphite, unlike ganesh, does not require a dedicated MSAA attachment on every surface.
182      * MSAA textures now get resolved within the scope of a render pass, which can be done simply
183      * with the color attachment usage flag. So we no longer require transfer src/dst usage flags.
184     */
185     VkImageUsageFlags flags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
186     if (discardable == Discardable::kYes && fSupportsMemorylessAttachments) {
187         flags = flags | VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT;
188     }
189 
190     info.fImageUsageFlags = flags;
191     info.fSharingMode = VK_SHARING_MODE_EXCLUSIVE;
192     info.fAspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
193 
194     return info;
195 }
196 
getDefaultDepthStencilTextureInfo(SkEnumBitMask<DepthStencilFlags> flags,uint32_t sampleCount,Protected isProtected) const197 TextureInfo VulkanCaps::getDefaultDepthStencilTextureInfo(SkEnumBitMask<DepthStencilFlags> flags,
198                                                           uint32_t sampleCount,
199                                                           Protected isProtected) const {
200     VkFormat format = getFormatFromDepthStencilFlags(flags);
201     const DepthStencilFormatInfo& formatInfo = this->getDepthStencilFormatInfo(format);
202     if ( (isProtected == Protected::kYes && !this->protectedSupport()) ||
203          !formatInfo.isDepthStencilSupported(formatInfo.fFormatProperties.optimalTilingFeatures) ||
204          !formatInfo.fSupportedSampleCounts.isSampleCountSupported(sampleCount)) {
205         return {};
206     }
207 
208     VulkanTextureInfo info;
209     info.fSampleCount = sampleCount;
210     info.fMipmapped = Mipmapped::kNo;
211     info.fFlags = (isProtected == Protected::kYes) ? VK_IMAGE_CREATE_PROTECTED_BIT : 0;
212     info.fFormat = format;
213     info.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
214     // TODO: Passing in a discardable flag to this method, and if true, add the TRANSIENT bit.
215     info.fImageUsageFlags = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
216     info.fSharingMode = VK_SHARING_MODE_EXCLUSIVE;
217     info.fAspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
218 
219     return info;
220 }
221 
initFormatTable(const skgpu::VulkanInterface * interface,VkPhysicalDevice physDev,const VkPhysicalDeviceProperties & properties)222 void VulkanCaps::initFormatTable(const skgpu::VulkanInterface* interface,
223                                  VkPhysicalDevice physDev,
224                                  const VkPhysicalDeviceProperties& properties) {
225     static_assert(std::size(kVkFormats) == VulkanCaps::kNumVkFormats,
226                   "Size of VkFormats array must match static value in header");
227 
228     std::fill_n(fColorTypeToFormatTable, kSkColorTypeCnt, VK_FORMAT_UNDEFINED);
229 
230     // Go through all the formats and init their support surface and data ColorTypes.
231     // Format: VK_FORMAT_R8G8B8A8_UNORM
232     {
233         constexpr VkFormat format = VK_FORMAT_R8G8B8A8_UNORM;
234         auto& info = this->getFormatInfo(format);
235         info.init(interface, physDev, properties, format);
236          if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
237             info.fColorTypeInfoCount = 2;
238             info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
239             int ctIdx = 0;
240             // Format: VK_FORMAT_R8G8B8A8_UNORM, Surface: kRGBA_8888
241             {
242                 constexpr SkColorType ct = SkColorType::kRGBA_8888_SkColorType;
243                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
244                 ctInfo.fColorType = ct;
245                 ctInfo.fTransferColorType = ct;
246                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
247             }
248             // Format: VK_FORMAT_R8G8B8A8_UNORM, Surface: kRGB_888x
249             {
250                 constexpr SkColorType ct = SkColorType::kRGB_888x_SkColorType;
251                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
252                 ctInfo.fColorType = ct;
253                 ctInfo.fTransferColorType = ct;
254                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag;
255                 ctInfo.fReadSwizzle = skgpu::Swizzle::RGB1();
256             }
257         }
258     }
259 
260     // Format: VK_FORMAT_R8_UNORM
261     {
262         constexpr VkFormat format = VK_FORMAT_R8_UNORM;
263         auto& info = this->getFormatInfo(format);
264         info.init(interface, physDev, properties, format);
265          if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
266             info.fColorTypeInfoCount = 3;
267             info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
268             int ctIdx = 0;
269             // Format: VK_FORMAT_R8_UNORM, Surface: kR_8
270             {
271                 constexpr SkColorType ct = SkColorType::kR8_unorm_SkColorType;
272                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
273                 ctInfo.fColorType = ct;
274                 ctInfo.fTransferColorType = ct;
275                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
276             }
277             // Format: VK_FORMAT_R8_UNORM, Surface: kAlpha_8
278             {
279                 constexpr SkColorType ct = SkColorType::kAlpha_8_SkColorType;
280                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
281                 ctInfo.fColorType = ct;
282                 ctInfo.fTransferColorType = ct;
283                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
284                 ctInfo.fReadSwizzle = skgpu::Swizzle("000r");
285                 ctInfo.fWriteSwizzle = skgpu::Swizzle("a000");
286             }
287             // Format: VK_FORMAT_R8_UNORM, Surface: kGray_8
288             {
289                 constexpr SkColorType ct = SkColorType::kGray_8_SkColorType;
290                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
291                 ctInfo.fColorType = ct;
292                 ctInfo.fTransferColorType = ct;
293                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag;
294                 ctInfo.fReadSwizzle = skgpu::Swizzle("rrr1");
295             }
296         }
297     }
298 
299     // Format: VK_FORMAT_B8G8R8A8_UNORM
300     {
301         constexpr VkFormat format = VK_FORMAT_B8G8R8A8_UNORM;
302         auto& info = this->getFormatInfo(format);
303         info.init(interface, physDev, properties, format);
304          if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
305             info.fColorTypeInfoCount = 1;
306             info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
307             int ctIdx = 0;
308             // Format: VK_FORMAT_B8G8R8A8_UNORM, Surface: kBGRA_8888
309             {
310                 constexpr SkColorType ct = SkColorType::kBGRA_8888_SkColorType;
311                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
312                 ctInfo.fColorType = ct;
313                 ctInfo.fTransferColorType = ct;
314                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
315             }
316         }
317     }
318     // Format: VK_FORMAT_R5G6B5_UNORM_PACK16
319     {
320         constexpr VkFormat format = VK_FORMAT_R5G6B5_UNORM_PACK16;
321         auto& info = this->getFormatInfo(format);
322         info.init(interface, physDev, properties, format);
323          if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
324             info.fColorTypeInfoCount = 1;
325             info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
326             int ctIdx = 0;
327             // Format: VK_FORMAT_R5G6B5_UNORM_PACK16, Surface: kRGB_565_SkColorType
328             {
329                 constexpr SkColorType ct = SkColorType::kRGB_565_SkColorType;
330                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
331                 ctInfo.fColorType = ct;
332                 ctInfo.fTransferColorType = ct;
333                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
334             }
335         }
336     }
337     // Format: VK_FORMAT_R16G16B16A16_SFLOAT
338     {
339         constexpr VkFormat format = VK_FORMAT_R16G16B16A16_SFLOAT;
340         auto& info = this->getFormatInfo(format);
341         info.init(interface, physDev, properties, format);
342          if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
343             info.fColorTypeInfoCount = 2;
344             info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
345             int ctIdx = 0;
346             // Format: VK_FORMAT_R16G16B16A16_SFLOAT, Surface: SkColorType::kRGBA_F16_SkColorType
347             {
348                 constexpr SkColorType ct = SkColorType::kRGBA_F16_SkColorType;
349                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
350                 ctInfo.fColorType = ct;
351                 ctInfo.fTransferColorType = ct;
352                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
353             }
354         }
355     }
356     // Format: VK_FORMAT_R16_SFLOAT
357     {
358         constexpr VkFormat format = VK_FORMAT_R16_SFLOAT;
359         auto& info = this->getFormatInfo(format);
360         info.init(interface, physDev, properties, format);
361          if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
362             info.fColorTypeInfoCount = 1;
363             info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
364             int ctIdx = 0;
365             // Format: VK_FORMAT_R16_SFLOAT, Surface: kAlpha_F16
366             {
367                 constexpr SkColorType ct = SkColorType::kA16_float_SkColorType;
368                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
369                 ctInfo.fColorType = ct;
370                 ctInfo.fTransferColorType = ct;
371                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
372                 ctInfo.fReadSwizzle = skgpu::Swizzle("000r");
373                 ctInfo.fWriteSwizzle = skgpu::Swizzle("a000");
374             }
375         }
376     }
377     // Format: VK_FORMAT_R8G8B8_UNORM
378     {
379         constexpr VkFormat format = VK_FORMAT_R8G8B8_UNORM;
380         auto& info = this->getFormatInfo(format);
381         info.init(interface, physDev, properties, format);
382          if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
383             info.fColorTypeInfoCount = 1;
384             info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
385             int ctIdx = 0;
386             // Format: VK_FORMAT_R8G8B8_UNORM, Surface: kRGB_888x
387             {
388                 constexpr SkColorType ct = SkColorType::kRGB_888x_SkColorType;
389                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
390                 ctInfo.fColorType = ct;
391                 // The Vulkan format is 3 bpp so we must convert to/from that when transferring.
392                 ctInfo.fTransferColorType = SkColorType::kRGB_888x_SkColorType;
393                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
394             }
395         }
396     }
397     // Format: VK_FORMAT_R8G8_UNORM
398     {
399         constexpr VkFormat format = VK_FORMAT_R8G8_UNORM;
400         auto& info = this->getFormatInfo(format);
401         info.init(interface, physDev, properties, format);
402          if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
403             info.fColorTypeInfoCount = 1;
404             info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
405             int ctIdx = 0;
406             // Format: VK_FORMAT_R8G8_UNORM, Surface: kR8G8_unorm
407             {
408                 constexpr SkColorType ct = SkColorType::kR8G8_unorm_SkColorType;
409                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
410                 ctInfo.fColorType = ct;
411                 ctInfo.fTransferColorType = ct;
412                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
413             }
414         }
415     }
416     // Format: VK_FORMAT_A2B10G10R10_UNORM_PACK32
417     {
418         constexpr VkFormat format = VK_FORMAT_A2B10G10R10_UNORM_PACK32;
419         auto& info = this->getFormatInfo(format);
420         info.init(interface, physDev, properties, format);
421          if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
422             info.fColorTypeInfoCount = 1;
423             info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
424             int ctIdx = 0;
425             // Format: VK_FORMAT_A2B10G10R10_UNORM_PACK32, Surface: kRGBA_1010102
426             {
427                 constexpr SkColorType ct = SkColorType::kRGBA_1010102_SkColorType;
428                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
429                 ctInfo.fColorType = ct;
430                 ctInfo.fTransferColorType = ct;
431                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
432             }
433         }
434     }
435     // Format: VK_FORMAT_A2R10G10B10_UNORM_PACK32
436     {
437         constexpr VkFormat format = VK_FORMAT_A2R10G10B10_UNORM_PACK32;
438         auto& info = this->getFormatInfo(format);
439         info.init(interface, physDev, properties, format);
440          if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
441             info.fColorTypeInfoCount = 1;
442             info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
443             int ctIdx = 0;
444             // Format: VK_FORMAT_A2R10G10B10_UNORM_PACK32, Surface: kBGRA_1010102
445             {
446                 constexpr SkColorType ct = SkColorType::kBGRA_1010102_SkColorType;
447                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
448                 ctInfo.fColorType = ct;
449                 ctInfo.fTransferColorType = ct;
450                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
451             }
452         }
453     }
454     // Format: VK_FORMAT_B4G4R4A4_UNORM_PACK16
455     {
456         constexpr VkFormat format = VK_FORMAT_B4G4R4A4_UNORM_PACK16;
457         auto& info = this->getFormatInfo(format);
458         info.init(interface, physDev, properties, format);
459          if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
460             info.fColorTypeInfoCount = 1;
461             info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
462             int ctIdx = 0;
463             // Format: VK_FORMAT_B4G4R4A4_UNORM_PACK16, Surface: kARGB_4444_SkColorType
464             {
465                 constexpr SkColorType ct = SkColorType::kARGB_4444_SkColorType;
466                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
467                 ctInfo.fColorType = ct;
468                 ctInfo.fTransferColorType = ct;
469                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
470                 ctInfo.fReadSwizzle = skgpu::Swizzle::BGRA();
471                 ctInfo.fWriteSwizzle = skgpu::Swizzle::BGRA();
472             }
473         }
474     }
475 
476     // Format: VK_FORMAT_R4G4B4A4_UNORM_PACK16
477     {
478         constexpr VkFormat format = VK_FORMAT_R4G4B4A4_UNORM_PACK16;
479         auto& info = this->getFormatInfo(format);
480         info.init(interface, physDev, properties, format);
481          if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
482             info.fColorTypeInfoCount = 1;
483             info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
484             int ctIdx = 0;
485             // Format: VK_FORMAT_R4G4B4A4_UNORM_PACK16, Surface: kARGB_4444_SkColorType
486             {
487                 constexpr SkColorType ct = SkColorType::kARGB_4444_SkColorType;
488                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
489                 ctInfo.fColorType = ct;
490                 ctInfo.fTransferColorType = ct;
491                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
492             }
493         }
494     }
495     // Format: VK_FORMAT_R8G8B8A8_SRGB
496     {
497         constexpr VkFormat format = VK_FORMAT_R8G8B8A8_SRGB;
498         auto& info = this->getFormatInfo(format);
499         info.init(interface, physDev, properties, format);
500          if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
501             info.fColorTypeInfoCount = 1;
502             info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
503             int ctIdx = 0;
504             // Format: VK_FORMAT_R8G8B8A8_SRGB, Surface: kRGBA_8888_SRGB
505             {
506                 constexpr SkColorType ct = SkColorType::kSRGBA_8888_SkColorType;
507                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
508                 ctInfo.fColorType = ct;
509                 ctInfo.fTransferColorType = ct;
510                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
511             }
512         }
513     }
514     // Format: VK_FORMAT_R16_UNORM
515     {
516         constexpr VkFormat format = VK_FORMAT_R16_UNORM;
517         auto& info = this->getFormatInfo(format);
518         info.init(interface, physDev, properties, format);
519          if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
520             info.fColorTypeInfoCount = 1;
521             info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
522             int ctIdx = 0;
523             // Format: VK_FORMAT_R16_UNORM, Surface: kAlpha_16
524             {
525                 constexpr SkColorType ct = SkColorType::kA16_unorm_SkColorType;
526                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
527                 ctInfo.fColorType = ct;
528                 ctInfo.fTransferColorType = ct;
529                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
530                 ctInfo.fReadSwizzle = skgpu::Swizzle("000r");
531                 ctInfo.fWriteSwizzle = skgpu::Swizzle("a000");
532             }
533         }
534     }
535     // Format: VK_FORMAT_R16G16_UNORM
536     {
537         constexpr VkFormat format = VK_FORMAT_R16G16_UNORM;
538         auto& info = this->getFormatInfo(format);
539         info.init(interface, physDev, properties, format);
540          if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
541             info.fColorTypeInfoCount = 1;
542             info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
543             int ctIdx = 0;
544             // Format: VK_FORMAT_R16G16_UNORM, Surface: kRG_1616
545             {
546                 constexpr SkColorType ct = SkColorType::kR16G16_unorm_SkColorType;
547                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
548                 ctInfo.fColorType = ct;
549                 ctInfo.fTransferColorType = ct;
550                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
551             }
552         }
553     }
554     // Format: VK_FORMAT_R16G16B16A16_UNORM
555     {
556         constexpr VkFormat format = VK_FORMAT_R16G16B16A16_UNORM;
557         auto& info = this->getFormatInfo(format);
558         info.init(interface, physDev, properties, format);
559          if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
560             info.fColorTypeInfoCount = 1;
561             info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
562             int ctIdx = 0;
563             // Format: VK_FORMAT_R16G16B16A16_UNORM, Surface: kRGBA_16161616
564             {
565                 constexpr SkColorType ct = SkColorType::kR16G16B16A16_unorm_SkColorType;
566                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
567                 ctInfo.fColorType = ct;
568                 ctInfo.fTransferColorType = ct;
569                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
570             }
571         }
572     }
573     // Format: VK_FORMAT_R16G16_SFLOAT
574     {
575         constexpr VkFormat format = VK_FORMAT_R16G16_SFLOAT;
576         auto& info = this->getFormatInfo(format);
577         info.init(interface, physDev, properties, format);
578          if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
579             info.fColorTypeInfoCount = 1;
580             info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
581             int ctIdx = 0;
582             // Format: VK_FORMAT_R16G16_SFLOAT, Surface: kRG_F16
583             {
584                 constexpr SkColorType ct = SkColorType::kR16G16_float_SkColorType;
585                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
586                 ctInfo.fColorType = ct;
587                 ctInfo.fTransferColorType = ct;
588                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
589             }
590         }
591     }
592     // Format: VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM
593     {
594         constexpr VkFormat format = VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM;
595         auto& info = this->getFormatInfo(format);
596         if (fSupportsYcbcrConversion) {
597             info.init(interface, physDev, properties, format);
598             SkDEBUGCODE(info.fIsWrappedOnly = true;)
599         }
600          if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
601             info.fColorTypeInfoCount = 1;
602             info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
603             int ctIdx = 0;
604             // Format: VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM, Surface: kRGB_888x
605             {
606                 constexpr SkColorType ct = SkColorType::kRGB_888x_SkColorType;
607                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
608                 ctInfo.fColorType = ct;
609                 ctInfo.fTransferColorType = ct;
610                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag;
611             }
612         }
613     }
614     // Format: VK_FORMAT_G8_B8R8_2PLANE_420_UNORM
615     {
616         constexpr VkFormat format = VK_FORMAT_G8_B8R8_2PLANE_420_UNORM;
617         auto& info = this->getFormatInfo(format);
618         if (fSupportsYcbcrConversion) {
619             info.init(interface, physDev, properties, format);
620             SkDEBUGCODE(info.fIsWrappedOnly = true;)
621         }
622          if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
623             info.fColorTypeInfoCount = 1;
624             info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
625             int ctIdx = 0;
626             // Format: VK_FORMAT_G8_B8R8_2PLANE_420_UNORM, Surface: kRGB_888x
627             {
628                 constexpr SkColorType ct = SkColorType::kRGB_888x_SkColorType;
629                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
630                 ctInfo.fColorType = ct;
631                 ctInfo.fTransferColorType = ct;
632                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag;
633             }
634         }
635     }
636     // Format: VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK
637     {
638         constexpr VkFormat format = VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK;
639         auto& info = this->getFormatInfo(format);
640         info.init(interface, physDev, properties, format);
641         // Setting this to texel block size
642         // No supported SkColorType.
643     }
644 
645     // Format: VK_FORMAT_BC1_RGB_UNORM_BLOCK
646     {
647         constexpr VkFormat format = VK_FORMAT_BC1_RGB_UNORM_BLOCK;
648         auto& info = this->getFormatInfo(format);
649         info.init(interface, physDev, properties, format);
650         // Setting this to texel block size
651         // No supported SkColorType.
652     }
653 
654     // Format: VK_FORMAT_BC1_RGBA_UNORM_BLOCK
655     {
656         constexpr VkFormat format = VK_FORMAT_BC1_RGBA_UNORM_BLOCK;
657         auto& info = this->getFormatInfo(format);
658         info.init(interface, physDev, properties, format);
659         // Setting this to texel block size
660         // No supported SkColorType.
661     }
662 
663     ////////////////////////////////////////////////////////////////////////////
664     // Map SkColorType (used for creating Surfaces) to VkFormats. The order in which the formats are
665     // passed into the setColorType function indicates the priority in selecting which format we use
666     // for a given SkColorType.
667     typedef SkColorType ct;
668 
669     this->setColorType(ct::kAlpha_8_SkColorType,            { VK_FORMAT_R8_UNORM });
670     this->setColorType(ct::kRGB_565_SkColorType,            { VK_FORMAT_R5G6B5_UNORM_PACK16 });
671     this->setColorType(ct::kARGB_4444_SkColorType,          { VK_FORMAT_R4G4B4A4_UNORM_PACK16,
672                                                               VK_FORMAT_B4G4R4A4_UNORM_PACK16 });
673     this->setColorType(ct::kRGBA_8888_SkColorType,          { VK_FORMAT_R8G8B8A8_UNORM });
674     this->setColorType(ct::kSRGBA_8888_SkColorType,         { VK_FORMAT_R8G8B8A8_SRGB });
675     this->setColorType(ct::kRGB_888x_SkColorType,           { VK_FORMAT_R8G8B8_UNORM,
676                                                               VK_FORMAT_R8G8B8A8_UNORM });
677     this->setColorType(ct::kR8G8_unorm_SkColorType,         { VK_FORMAT_R8G8_UNORM });
678     this->setColorType(ct::kBGRA_8888_SkColorType,          { VK_FORMAT_B8G8R8A8_UNORM });
679     this->setColorType(ct::kRGBA_1010102_SkColorType,       { VK_FORMAT_A2B10G10R10_UNORM_PACK32 });
680     this->setColorType(ct::kBGRA_1010102_SkColorType,       { VK_FORMAT_A2R10G10B10_UNORM_PACK32 });
681     this->setColorType(ct::kGray_8_SkColorType,             { VK_FORMAT_R8_UNORM });
682     this->setColorType(ct::kA16_float_SkColorType,          { VK_FORMAT_R16_SFLOAT });
683     this->setColorType(ct::kRGBA_F16_SkColorType,           { VK_FORMAT_R16G16B16A16_SFLOAT });
684     this->setColorType(ct::kA16_unorm_SkColorType,          { VK_FORMAT_R16_UNORM });
685     this->setColorType(ct::kR16G16_unorm_SkColorType,       { VK_FORMAT_R16G16_UNORM });
686     this->setColorType(ct::kR16G16B16A16_unorm_SkColorType, { VK_FORMAT_R16G16B16A16_UNORM });
687     this->setColorType(ct::kR16G16_float_SkColorType,       { VK_FORMAT_R16G16_SFLOAT });
688 }
689 
initDepthStencilFormatTable(const skgpu::VulkanInterface * interface,VkPhysicalDevice physDev,const VkPhysicalDeviceProperties & properties)690 void VulkanCaps::initDepthStencilFormatTable(const skgpu::VulkanInterface* interface,
691                                              VkPhysicalDevice physDev,
692                                              const VkPhysicalDeviceProperties& properties) {
693     static_assert(std::size(kDepthStencilVkFormats) == VulkanCaps::kNumDepthStencilVkFormats,
694                   "Size of DepthStencilVkFormats array must match static value in header");
695 
696     std::fill_n(fDepthStencilFlagsToFormatTable, kNumDepthStencilFlags, VK_FORMAT_UNDEFINED);
697     // Format: VK_FORMAT_S8_UINT
698     {
699         constexpr VkFormat format = VK_FORMAT_S8_UINT;
700         auto& info = this->getDepthStencilFormatInfo(format);
701         info.init(interface, physDev, properties, format);
702     }
703     // Format: VK_FORMAT_D24_UNORM_S8_UINT
704     {
705         constexpr VkFormat format = VK_FORMAT_D24_UNORM_S8_UINT;
706         auto& info = this->getDepthStencilFormatInfo(format);
707         info.init(interface, physDev, properties, format);
708     }
709     // Format: VK_FORMAT_D32_SFLOAT_S8_UINT
710     {
711         constexpr VkFormat format = VK_FORMAT_D32_SFLOAT_S8_UINT;
712         auto& info = this->getDepthStencilFormatInfo(format);
713         info.init(interface, physDev, properties, format);
714     }
715 }
716 
initSampleCounts(const skgpu::VulkanInterface * interface,VkPhysicalDevice physDev,const VkPhysicalDeviceProperties & physProps,VkFormat format,VkImageUsageFlags usage)717 void VulkanCaps::SupportedSampleCounts::initSampleCounts(const skgpu::VulkanInterface* interface,
718         VkPhysicalDevice physDev,
719         const VkPhysicalDeviceProperties& physProps,
720         VkFormat format,
721         VkImageUsageFlags usage) {
722     VkImageFormatProperties properties;
723 
724     VkResult result;
725     VULKAN_CALL_RESULT(interface, result,
726                        GetPhysicalDeviceImageFormatProperties(physDev,
727                                                               format,
728                                                               VK_IMAGE_TYPE_2D,
729                                                               VK_IMAGE_TILING_OPTIMAL,
730                                                               usage,
731                                                               0,  // createFlags
732                                                               &properties));
733     if (result != VK_SUCCESS) {
734         SKGPU_LOG_W("Vulkan call GetPhysicalDeviceImageFormatProperties failed");
735         return;
736     }
737 
738     VkSampleCountFlags flags = properties.sampleCounts;
739     if (flags & VK_SAMPLE_COUNT_1_BIT) {
740         fSampleCounts.push_back(1);
741     }
742     if (kImagination_VkVendor == physProps.vendorID) {
743         // MSAA does not work on imagination
744         return;
745     }
746     if (kIntel_VkVendor == physProps.vendorID) {
747         // MSAA doesn't work well on Intel GPUs chromium:527565, chromium:983926
748         return;
749     }
750     if (flags & VK_SAMPLE_COUNT_2_BIT) {
751         fSampleCounts.push_back(2);
752     }
753     if (flags & VK_SAMPLE_COUNT_4_BIT) {
754         fSampleCounts.push_back(4);
755     }
756     if (flags & VK_SAMPLE_COUNT_8_BIT) {
757         fSampleCounts.push_back(8);
758     }
759     if (flags & VK_SAMPLE_COUNT_16_BIT) {
760         fSampleCounts.push_back(16);
761     }
762     // Standard sample locations are not defined for more than 16 samples, and we don't need more
763     // than 16. Omit 32 and 64.
764 }
765 
isSampleCountSupported(int requestedCount) const766 bool VulkanCaps::SupportedSampleCounts::isSampleCountSupported(int requestedCount) const {
767     requestedCount = std::max(1, requestedCount);
768     for (int i = 0; i < fSampleCounts.size(); i++) {
769         if (fSampleCounts[i] == requestedCount) {
770             return true;
771         } else if (requestedCount < fSampleCounts[i]) {
772             return false;
773         }
774     }
775     return false;
776 }
777 
init(const skgpu::VulkanInterface * interface,VkPhysicalDevice physDev,const VkPhysicalDeviceProperties & properties,VkFormat format)778 void VulkanCaps::FormatInfo::init(const skgpu::VulkanInterface* interface,
779                                   VkPhysicalDevice physDev,
780                                   const VkPhysicalDeviceProperties& properties,
781                                   VkFormat format) {
782     memset(&fFormatProperties, 0, sizeof(VkFormatProperties));
783     VULKAN_CALL(interface, GetPhysicalDeviceFormatProperties(physDev, format, &fFormatProperties));
784 
785     if (this->isRenderable(fFormatProperties.optimalTilingFeatures)) {
786         VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
787                                        VK_IMAGE_USAGE_TRANSFER_DST_BIT |
788                                        VK_IMAGE_USAGE_SAMPLED_BIT |
789                                        VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
790         this->fSupportedSampleCounts.initSampleCounts(interface, physDev, properties, format,
791                                                       usageFlags);
792     }
793 }
794 
isTexturable(VkImageTiling imageTiling) const795 bool VulkanCaps::FormatInfo::isTexturable(VkImageTiling imageTiling) const {
796     switch (imageTiling) {
797         case VK_IMAGE_TILING_OPTIMAL:
798             return this->isTexturable(fFormatProperties.optimalTilingFeatures);
799         case VK_IMAGE_TILING_LINEAR:
800             return this->isTexturable(fFormatProperties.linearTilingFeatures);
801         default:
802             return false;
803     }
804     SkUNREACHABLE;
805 }
806 
isRenderable(VkImageTiling imageTiling,uint32_t sampleCount) const807 bool VulkanCaps::FormatInfo::isRenderable(VkImageTiling imageTiling,
808                                           uint32_t sampleCount) const {
809     if (!fSupportedSampleCounts.isSampleCountSupported(sampleCount)) {
810         return false;
811     }
812     switch (imageTiling) {
813         case VK_IMAGE_TILING_OPTIMAL:
814             return this->isRenderable(fFormatProperties.optimalTilingFeatures);
815         case VK_IMAGE_TILING_LINEAR:
816             return this->isRenderable(fFormatProperties.linearTilingFeatures);
817         default:
818             return false;
819     }
820     SkUNREACHABLE;
821 }
822 
isTexturable(VkFormatFeatureFlags flags) const823 bool VulkanCaps::FormatInfo::isTexturable(VkFormatFeatureFlags flags) const {
824     return SkToBool(VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT & flags) &&
825            SkToBool(VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT & flags);
826 }
827 
isRenderable(VkFormatFeatureFlags flags) const828 bool VulkanCaps::FormatInfo::isRenderable(VkFormatFeatureFlags flags) const {
829     return SkToBool(VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT & flags);
830 }
831 
setColorType(SkColorType colorType,std::initializer_list<VkFormat> formats)832 void VulkanCaps::setColorType(SkColorType colorType, std::initializer_list<VkFormat> formats) {
833 #ifdef SK_DEBUG
834     // If any format's FormatInfo claims support for the passed-in colorType, ensure that format is
835     // included in the provided formats list.
836     for (size_t i = 0; i < kNumVkFormats; ++i) {
837         const auto& formatInfo = fFormatTable[i];
838         for (int j = 0; j < formatInfo.fColorTypeInfoCount; ++j) {
839             const auto& ctInfo = formatInfo.fColorTypeInfos[j];
840             if (ctInfo.fColorType == colorType && !formatInfo.fIsWrappedOnly) {
841                 bool found = false;
842                 for (auto it = formats.begin(); it != formats.end(); ++it) {
843                     if (kVkFormats[i] == *it) {
844                         found = true;
845                     }
846                 }
847                 SkASSERT(found);
848             }
849         }
850     }
851 #endif
852     int idx = static_cast<int>(colorType);
853     for (auto it = formats.begin(); it != formats.end(); ++it) {
854         const auto& info = this->getFormatInfo(*it);
855         for (int i = 0; i < info.fColorTypeInfoCount; ++i) {
856             if (info.fColorTypeInfos[i].fColorType == colorType) {
857                 fColorTypeToFormatTable[idx] = *it;
858                 return;
859             }
860         }
861     }
862 }
863 
getFormatFromColorType(SkColorType colorType) const864 VkFormat VulkanCaps::getFormatFromColorType(SkColorType colorType) const {
865     int idx = static_cast<int>(colorType);
866     return fColorTypeToFormatTable[idx];
867 }
868 
getFormatInfo(VkFormat format)869 VulkanCaps::FormatInfo& VulkanCaps::getFormatInfo(VkFormat format) {
870     static_assert(std::size(kVkFormats) == VulkanCaps::kNumVkFormats,
871                   "Size of VkFormats array must match static value in header");
872     for (size_t i = 0; i < std::size(kVkFormats); ++i) {
873         if (kVkFormats[i] == format) {
874             return fFormatTable[i];
875         }
876     }
877     static FormatInfo kInvalidFormat;
878     return kInvalidFormat;
879 }
880 
getFormatInfo(VkFormat format) const881 const VulkanCaps::FormatInfo& VulkanCaps::getFormatInfo(VkFormat format) const {
882     VulkanCaps* nonConstThis = const_cast<VulkanCaps*>(this);
883     return nonConstThis->getFormatInfo(format);
884 }
885 
init(const skgpu::VulkanInterface * interface,VkPhysicalDevice physDev,const VkPhysicalDeviceProperties & properties,VkFormat format)886 void VulkanCaps::DepthStencilFormatInfo::init(const skgpu::VulkanInterface* interface,
887                                              VkPhysicalDevice physDev,
888                                              const VkPhysicalDeviceProperties& properties,
889                                              VkFormat format) {
890     memset(&fFormatProperties, 0, sizeof(VkFormatProperties));
891     VULKAN_CALL(interface, GetPhysicalDeviceFormatProperties(physDev, format, &fFormatProperties));
892 
893     VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
894     fSupportedSampleCounts.initSampleCounts(interface, physDev, properties, format, usageFlags);
895 }
896 
isDepthStencilSupported(VkFormatFeatureFlags flags) const897 bool VulkanCaps::DepthStencilFormatInfo::isDepthStencilSupported(VkFormatFeatureFlags flags) const {
898     return SkToBool(VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT & flags);
899 }
900 
getFormatFromDepthStencilFlags(const SkEnumBitMask<DepthStencilFlags> & flags) const901 VkFormat VulkanCaps::getFormatFromDepthStencilFlags(const SkEnumBitMask<DepthStencilFlags>& flags)
902         const {
903     int idx = static_cast<int>(flags);
904     return fDepthStencilFlagsToFormatTable[idx];
905 }
906 
getDepthStencilFormatInfo(VkFormat format)907 VulkanCaps::DepthStencilFormatInfo& VulkanCaps::getDepthStencilFormatInfo(VkFormat format) {
908     static_assert(std::size(kDepthStencilVkFormats) == VulkanCaps::kNumDepthStencilVkFormats,
909                   "Size of VkFormats array must match static value in header");
910     for (size_t i = 0; i < std::size(kDepthStencilVkFormats); ++i) {
911         if (kVkFormats[i] == format) {
912             return fDepthStencilFormatTable[i];
913         }
914     }
915     static DepthStencilFormatInfo kInvalidFormat;
916     return kInvalidFormat;
917 }
918 
getDepthStencilFormatInfo(VkFormat format) const919 const VulkanCaps::DepthStencilFormatInfo& VulkanCaps::getDepthStencilFormatInfo(VkFormat format)
920         const {
921     VulkanCaps* nonConstThis = const_cast<VulkanCaps*>(this);
922     return nonConstThis->getDepthStencilFormatInfo(format);
923 }
924 } // namespace skgpu::graphite
925 
926