• 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/core/SkTextureCompressionType.h"
11 #include "include/gpu/graphite/ContextOptions.h"
12 #include "include/gpu/graphite/TextureInfo.h"
13 #include "include/gpu/graphite/vk/VulkanGraphiteTypes.h"
14 #include "include/gpu/vk/VulkanExtensions.h"
15 #include "include/gpu/vk/VulkanTypes.h"
16 #include "src/gpu/graphite/ContextUtils.h"
17 #include "src/gpu/graphite/GraphicsPipelineDesc.h"
18 #include "src/gpu/graphite/GraphiteResourceKey.h"
19 #include "src/gpu/graphite/RenderPassDesc.h"
20 #include "src/gpu/graphite/RendererProvider.h"
21 #include "src/gpu/graphite/RuntimeEffectDictionary.h"
22 #include "src/gpu/graphite/vk/VulkanGraphiteUtilsPriv.h"
23 #include "src/gpu/graphite/vk/VulkanRenderPass.h"
24 #include "src/gpu/graphite/vk/VulkanSharedContext.h"
25 #include "src/gpu/graphite/vk/VulkanYcbcrConversion.h"
26 #include "src/gpu/vk/VulkanUtilsPriv.h"
27 
28 #ifdef SK_BUILD_FOR_ANDROID
29 #include <sys/system_properties.h>
30 #endif
31 
32 namespace skgpu::graphite {
33 
VulkanCaps(const ContextOptions & contextOptions,const skgpu::VulkanInterface * vkInterface,VkPhysicalDevice physDev,uint32_t physicalDeviceVersion,const VkPhysicalDeviceFeatures2 * features,const skgpu::VulkanExtensions * extensions,Protected isProtected)34 VulkanCaps::VulkanCaps(const ContextOptions& contextOptions,
35                        const skgpu::VulkanInterface* vkInterface,
36                        VkPhysicalDevice physDev,
37                        uint32_t physicalDeviceVersion,
38                        const VkPhysicalDeviceFeatures2* features,
39                        const skgpu::VulkanExtensions* extensions,
40                        Protected isProtected)
41         : Caps() {
42     this->init(contextOptions, vkInterface, physDev, physicalDeviceVersion, features, extensions,
43                isProtected);
44 }
45 
~VulkanCaps()46 VulkanCaps::~VulkanCaps() {}
47 
init(const ContextOptions & contextOptions,const skgpu::VulkanInterface * vkInterface,VkPhysicalDevice physDev,uint32_t physicalDeviceVersion,const VkPhysicalDeviceFeatures2 * features,const skgpu::VulkanExtensions * extensions,Protected isProtected)48 void VulkanCaps::init(const ContextOptions& contextOptions,
49                       const skgpu::VulkanInterface* vkInterface,
50                       VkPhysicalDevice physDev,
51                       uint32_t physicalDeviceVersion,
52                       const VkPhysicalDeviceFeatures2* features,
53                       const skgpu::VulkanExtensions* extensions,
54                       Protected isProtected) {
55     VkPhysicalDeviceProperties physDevProperties;
56     VULKAN_CALL(vkInterface, GetPhysicalDeviceProperties(physDev, &physDevProperties));
57 
58 #if defined(GRAPHITE_TEST_UTILS)
59     this->setDeviceName(physDevProperties.deviceName);
60 #endif
61 
62     // Graphite requires Vulkan version 1.1 or later, which always has protected support.
63     if (isProtected == Protected::kYes) {
64         fProtectedSupport = true;
65         fShouldAlwaysUseDedicatedImageMemory = true;
66     }
67 
68     fPhysicalDeviceMemoryProperties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2;
69     fPhysicalDeviceMemoryProperties2.pNext = nullptr;
70     VULKAN_CALL(vkInterface,
71                 GetPhysicalDeviceMemoryProperties2(physDev, &fPhysicalDeviceMemoryProperties2));
72 
73     // We could actually query and get a max size for each config, however maxImageDimension2D will
74     // give the minimum max size across all configs. So for simplicity we will use that for now.
75     fMaxTextureSize = std::min(physDevProperties.limits.maxImageDimension2D, (uint32_t)INT_MAX);
76 
77     fRequiredUniformBufferAlignment = physDevProperties.limits.minUniformBufferOffsetAlignment;
78     fRequiredStorageBufferAlignment =  physDevProperties.limits.minStorageBufferOffsetAlignment;
79     fRequiredTransferBufferAlignment = 4;
80 
81     fResourceBindingReqs.fUniformBufferLayout = Layout::kStd140;
82     // TODO(skia:14639): We cannot use std430 layout for SSBOs until SkSL gracefully handles
83     // implicit array stride.
84     fResourceBindingReqs.fStorageBufferLayout = Layout::kStd140;
85     fResourceBindingReqs.fSeparateTextureAndSamplerBinding = false;
86     fResourceBindingReqs.fDistinctIndexRanges = false;
87 
88     VkPhysicalDeviceMemoryProperties deviceMemoryProperties;
89     VULKAN_CALL(vkInterface, GetPhysicalDeviceMemoryProperties(physDev, &deviceMemoryProperties));
90     fSupportsMemorylessAttachments = false;
91     VkMemoryPropertyFlags requiredLazyFlags = VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT;
92     if (fProtectedSupport) {
93         // If we have a protected context we can only use memoryless images if they also support
94         // being protected. With current devices we don't actually expect this combination to be
95         // supported, but this at least covers us for future devices that may allow it.
96         requiredLazyFlags |= VK_MEMORY_PROPERTY_PROTECTED_BIT;
97     }
98     for (uint32_t i = 0; i < deviceMemoryProperties.memoryTypeCount; ++i) {
99         if (deviceMemoryProperties.memoryTypes[i].propertyFlags & requiredLazyFlags) {
100             fSupportsMemorylessAttachments = true;
101         }
102     }
103 
104 #ifdef SK_BUILD_FOR_UNIX
105     if (kNvidia_VkVendor == physDevProperties.vendorID) {
106         // On NVIDIA linux we see a big perf regression when not using dedicated image allocations.
107         fShouldAlwaysUseDedicatedImageMemory = true;
108     }
109 #endif
110 
111     if (physDevProperties.vendorID == kNvidia_VkVendor ||
112         physDevProperties.vendorID == kAMD_VkVendor) {
113         // On discrete GPUs, it can be faster to read gpu-only memory compared to memory that is
114         // also mappable on the host.
115         fGpuOnlyBuffersMorePerformant = true;
116 
117         // On discrete GPUs we try to use special DEVICE_LOCAL and HOST_VISIBLE memory for our
118         // cpu write, gpu read buffers. This memory is not ideal to be kept persistently mapped.
119         // Some discrete GPUs do not expose this special memory, however we still disable
120         // persistently mapped buffers for all of them since most GPUs with updated drivers do
121         // expose it. If this becomes an issue we can try to be more fine grained.
122         fShouldPersistentlyMapCpuToGpuBuffers = false;
123     }
124 
125     if (!contextOptions.fDisableDriverCorrectnessWorkarounds) {
126         this->applyDriverCorrectnessWorkarounds(physDevProperties);
127     }
128 
129     if (physDevProperties.vendorID == kAMD_VkVendor) {
130         // AMD advertises support for MAX_UINT vertex attributes but in reality only supports 32.
131         fMaxVertexAttributes = 32;
132     } else {
133         fMaxVertexAttributes = physDevProperties.limits.maxVertexInputAttributes;
134     }
135     fMaxUniformBufferRange = physDevProperties.limits.maxUniformBufferRange;
136 
137 #ifdef SK_BUILD_FOR_ANDROID
138     if (extensions->hasExtension(
139             VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME, 2)) {
140         fSupportsAHardwareBufferImages = true;
141     }
142 #endif
143 
144     // Determine whether the client enabled certain physical device features.
145     if (features) {
146         auto ycbcrFeatures =
147                 skgpu::GetExtensionFeatureStruct<VkPhysicalDeviceSamplerYcbcrConversionFeatures>(
148                         *features,
149                         VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES);
150         if (ycbcrFeatures && ycbcrFeatures->samplerYcbcrConversion) {
151             fSupportsYcbcrConversion = true;
152         }
153     }
154 
155     if (extensions->hasExtension(VK_EXT_DEVICE_FAULT_EXTENSION_NAME, 1)) {
156         fSupportsDeviceFaultInfo = true;
157     }
158 
159     // Note that format table initialization should be performed at the end of this method to ensure
160     // all capability determinations are completed prior to populating the format tables.
161     this->initFormatTable(vkInterface, physDev, physDevProperties);
162     this->initDepthStencilFormatTable(vkInterface, physDev, physDevProperties);
163 
164     this->finishInitialization(contextOptions);
165 }
166 
applyDriverCorrectnessWorkarounds(const VkPhysicalDeviceProperties & properties)167 void VulkanCaps::applyDriverCorrectnessWorkarounds(const VkPhysicalDeviceProperties& properties) {
168     // By default, we initialize the Android API version to 0 since we consider certain things
169     // "fixed" only once above a certain version. This way, we default to enabling the workarounds.
170     int androidAPIVersion = 0;
171 #if defined(SK_BUILD_FOR_ANDROID)
172     char androidAPIVersionStr[PROP_VALUE_MAX];
173     int strLength = __system_property_get("ro.build.version.sdk", androidAPIVersionStr);
174     // Defaults to zero since most checks care if it is greater than a specific value. So this will
175     // just default to it being less.
176     androidAPIVersion = (strLength == 0) ? 0 : atoi(androidAPIVersionStr);
177 #endif
178 
179     // On Mali galaxy s7 we see lots of rendering issues when we suballocate VkImages.
180     if (kARM_VkVendor == properties.vendorID && androidAPIVersion <= 28) {
181         fShouldAlwaysUseDedicatedImageMemory = true;
182     }
183 }
184 
185 // These are all the valid VkFormats that we support in Skia. They are roughly ordered from most
186 // frequently used to least to improve look up times in arrays.
187 static constexpr VkFormat kVkFormats[] = {
188     VK_FORMAT_R8G8B8A8_UNORM,
189     VK_FORMAT_R8_UNORM,
190     VK_FORMAT_B8G8R8A8_UNORM,
191     VK_FORMAT_R5G6B5_UNORM_PACK16,
192     VK_FORMAT_R16G16B16A16_SFLOAT,
193     VK_FORMAT_R16_SFLOAT,
194     VK_FORMAT_R8G8B8_UNORM,
195     VK_FORMAT_R8G8_UNORM,
196     VK_FORMAT_A2B10G10R10_UNORM_PACK32,
197     VK_FORMAT_A2R10G10B10_UNORM_PACK32,
198     VK_FORMAT_B4G4R4A4_UNORM_PACK16,
199     VK_FORMAT_R4G4B4A4_UNORM_PACK16,
200     VK_FORMAT_R8G8B8A8_SRGB,
201     VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK,
202     VK_FORMAT_BC1_RGB_UNORM_BLOCK,
203     VK_FORMAT_BC1_RGBA_UNORM_BLOCK,
204     VK_FORMAT_R16_UNORM,
205     VK_FORMAT_R16G16_UNORM,
206     VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM,
207     VK_FORMAT_G8_B8R8_2PLANE_420_UNORM,
208     VK_FORMAT_R16G16B16A16_UNORM,
209     VK_FORMAT_R16G16_SFLOAT,
210 };
211 // These are all the valid depth/stencil formats that we support in Skia.
212 static constexpr VkFormat kDepthStencilVkFormats[] = {
213     VK_FORMAT_S8_UINT,
214     VK_FORMAT_D16_UNORM,
215     VK_FORMAT_D32_SFLOAT,
216     VK_FORMAT_D24_UNORM_S8_UINT,
217     VK_FORMAT_D32_SFLOAT_S8_UINT,
218 };
219 
getDefaultSampledTextureInfo(SkColorType ct,Mipmapped mipmapped,Protected isProtected,Renderable isRenderable) const220 TextureInfo VulkanCaps::getDefaultSampledTextureInfo(SkColorType ct,
221                                                      Mipmapped mipmapped,
222                                                      Protected isProtected,
223                                                      Renderable isRenderable) const {
224     VkFormat format = this->getFormatFromColorType(ct);
225     const FormatInfo& formatInfo = this->getFormatInfo(format);
226     static constexpr int defaultSampleCount = 1;
227     if ((isProtected == Protected::kYes && !this->protectedSupport()) ||
228         !formatInfo.isTexturable(VK_IMAGE_TILING_OPTIMAL) ||
229         (isRenderable == Renderable::kYes &&
230          !formatInfo.isRenderable(VK_IMAGE_TILING_OPTIMAL, defaultSampleCount)) ) {
231         return {};
232     }
233 
234     VulkanTextureInfo info;
235     info.fSampleCount = defaultSampleCount;
236     info.fMipmapped = mipmapped;
237     info.fFlags = (isProtected == Protected::kYes) ? VK_IMAGE_CREATE_PROTECTED_BIT : 0;
238     info.fFormat = format;
239     info.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
240     info.fImageUsageFlags = VK_IMAGE_USAGE_SAMPLED_BIT |
241                             VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
242                             VK_IMAGE_USAGE_TRANSFER_DST_BIT;
243     if (isRenderable == Renderable::kYes) {
244         // We make all renderable images support being used as input attachment
245         info.fImageUsageFlags = info.fImageUsageFlags |
246                                 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
247                                 VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
248     }
249     info.fSharingMode = VK_SHARING_MODE_EXCLUSIVE;
250     info.fAspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
251 
252     return info;
253 }
254 
getTextureInfoForSampledCopy(const TextureInfo & textureInfo,Mipmapped mipmapped) const255 TextureInfo VulkanCaps::getTextureInfoForSampledCopy(const TextureInfo& textureInfo,
256                                                      Mipmapped mipmapped) const {
257     VulkanTextureInfo info;
258     if (!textureInfo.getVulkanTextureInfo(&info)) {
259         return {};
260     }
261 
262     info.fSampleCount = 1;
263     info.fMipmapped = mipmapped;
264     info.fFlags = (textureInfo.fProtected == Protected::kYes) ? VK_IMAGE_CREATE_PROTECTED_BIT : 0;
265     info.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
266     info.fImageUsageFlags = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
267                             VK_IMAGE_USAGE_TRANSFER_DST_BIT;
268     info.fSharingMode = VK_SHARING_MODE_EXCLUSIVE;
269 
270     return info;
271 }
272 
273 namespace {
format_from_compression(SkTextureCompressionType compression)274 VkFormat format_from_compression(SkTextureCompressionType compression) {
275     switch (compression) {
276         case SkTextureCompressionType::kETC2_RGB8_UNORM:
277             return VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK;
278         case SkTextureCompressionType::kBC1_RGB8_UNORM:
279             return VK_FORMAT_BC1_RGB_UNORM_BLOCK;
280         case SkTextureCompressionType::kBC1_RGBA8_UNORM:
281             return VK_FORMAT_BC1_RGBA_UNORM_BLOCK;
282         default:
283             return VK_FORMAT_UNDEFINED;
284     }
285 }
286 }
287 
getDefaultCompressedTextureInfo(SkTextureCompressionType compression,Mipmapped mipmapped,Protected isProtected) const288 TextureInfo VulkanCaps::getDefaultCompressedTextureInfo(SkTextureCompressionType compression,
289                                                         Mipmapped mipmapped,
290                                                         Protected isProtected) const {
291     VkFormat format = format_from_compression(compression);
292     const FormatInfo& formatInfo = this->getFormatInfo(format);
293     static constexpr int defaultSampleCount = 1;
294     if ((isProtected == Protected::kYes && !this->protectedSupport()) ||
295         !formatInfo.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
296         return {};
297     }
298 
299     VulkanTextureInfo info;
300     info.fSampleCount = defaultSampleCount;
301     info.fMipmapped = mipmapped;
302     info.fFlags = (isProtected == Protected::kYes) ? VK_IMAGE_CREATE_PROTECTED_BIT : 0;
303     info.fFormat = format;
304     info.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
305     info.fImageUsageFlags = VK_IMAGE_USAGE_SAMPLED_BIT |
306                             VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
307                             VK_IMAGE_USAGE_TRANSFER_DST_BIT;
308     info.fSharingMode = VK_SHARING_MODE_EXCLUSIVE;
309     info.fAspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
310 
311     return info;
312 }
313 
getDefaultMSAATextureInfo(const TextureInfo & singleSampledInfo,Discardable discardable) const314 TextureInfo VulkanCaps::getDefaultMSAATextureInfo(const TextureInfo& singleSampledInfo,
315                                                   Discardable discardable) const {
316     if (fDefaultMSAASamples <= 1) {
317         return {};
318     }
319 
320     const VkFormat singleSpecFormat = singleSampledInfo.vulkanTextureSpec().fFormat;
321     const FormatInfo& formatInfo = this->getFormatInfo(singleSpecFormat);
322     if ((singleSampledInfo.isProtected() == Protected::kYes && !this->protectedSupport()) ||
323         !formatInfo.isRenderable(VK_IMAGE_TILING_OPTIMAL, fDefaultMSAASamples)) {
324         return {};
325     }
326 
327     VulkanTextureInfo info;
328     info.fSampleCount = fDefaultMSAASamples;
329     info.fMipmapped = Mipmapped::kNo;
330     info.fFlags = (singleSampledInfo.isProtected() == Protected::kYes) ?
331         VK_IMAGE_CREATE_PROTECTED_BIT : 0;
332     info.fFormat = singleSpecFormat;
333     info.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
334 
335     /**
336      * Graphite, unlike ganesh, does not require a dedicated MSAA attachment on every surface.
337      * MSAA textures now get resolved within the scope of a render pass, which can be done simply
338      * with the color attachment usage flag. So we no longer require transfer src/dst usage flags.
339     */
340     VkImageUsageFlags flags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
341     if (discardable == Discardable::kYes && fSupportsMemorylessAttachments) {
342         flags = flags | VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT;
343     }
344 
345     info.fImageUsageFlags = flags;
346     info.fSharingMode = VK_SHARING_MODE_EXCLUSIVE;
347     info.fAspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
348 
349     return info;
350 }
351 
getDefaultDepthStencilTextureInfo(SkEnumBitMask<DepthStencilFlags> flags,uint32_t sampleCount,Protected isProtected) const352 TextureInfo VulkanCaps::getDefaultDepthStencilTextureInfo(SkEnumBitMask<DepthStencilFlags> flags,
353                                                           uint32_t sampleCount,
354                                                           Protected isProtected) const {
355     VkFormat format = this->getFormatFromDepthStencilFlags(flags);
356     const DepthStencilFormatInfo& formatInfo = this->getDepthStencilFormatInfo(format);
357     if ( (isProtected == Protected::kYes && !this->protectedSupport()) ||
358          !formatInfo.isDepthStencilSupported(formatInfo.fFormatProperties.optimalTilingFeatures) ||
359          !formatInfo.fSupportedSampleCounts.isSampleCountSupported(sampleCount)) {
360         return {};
361     }
362 
363     VulkanTextureInfo info;
364     info.fSampleCount = sampleCount;
365     info.fMipmapped = Mipmapped::kNo;
366     info.fFlags = (isProtected == Protected::kYes) ? VK_IMAGE_CREATE_PROTECTED_BIT : 0;
367     info.fFormat = format;
368     info.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
369     // TODO: Passing in a discardable flag to this method, and if true, add the TRANSIENT bit.
370     info.fImageUsageFlags = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
371     info.fSharingMode = VK_SHARING_MODE_EXCLUSIVE;
372     info.fAspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
373 
374     return info;
375 }
376 
getDefaultStorageTextureInfo(SkColorType colorType) const377 TextureInfo VulkanCaps::getDefaultStorageTextureInfo(SkColorType colorType) const {
378     VkFormat format = this->getFormatFromColorType(colorType);
379     const FormatInfo& formatInfo = this->getFormatInfo(format);
380     if (!formatInfo.isTexturable(VK_IMAGE_TILING_OPTIMAL) ||
381         !formatInfo.isStorage(VK_IMAGE_TILING_OPTIMAL)) {
382         return {};
383     }
384 
385     VulkanTextureInfo info;
386     info.fSampleCount = 1;
387     info.fMipmapped = Mipmapped::kNo;
388     info.fFlags = 0;
389     info.fFormat = format;
390     info.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
391     // Storage textures are currently always sampleable from a shader
392     info.fImageUsageFlags = VK_IMAGE_USAGE_STORAGE_BIT |
393                             VK_IMAGE_USAGE_SAMPLED_BIT |
394                             VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
395     info.fSharingMode = VK_SHARING_MODE_EXCLUSIVE;
396     info.fAspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
397 
398     return info;
399 }
400 
channelMask(const TextureInfo & textureInfo) const401 uint32_t VulkanCaps::channelMask(const TextureInfo& textureInfo) const {
402     return skgpu::VkFormatChannels(textureInfo.vulkanTextureSpec().fFormat);
403 }
404 
initFormatTable(const skgpu::VulkanInterface * interface,VkPhysicalDevice physDev,const VkPhysicalDeviceProperties & properties)405 void VulkanCaps::initFormatTable(const skgpu::VulkanInterface* interface,
406                                  VkPhysicalDevice physDev,
407                                  const VkPhysicalDeviceProperties& properties) {
408     static_assert(std::size(kVkFormats) == VulkanCaps::kNumVkFormats,
409                   "Size of VkFormats array must match static value in header");
410 
411     std::fill_n(fColorTypeToFormatTable, kSkColorTypeCnt, VK_FORMAT_UNDEFINED);
412 
413     // Go through all the formats and init their support surface and data ColorTypes.
414     // Format: VK_FORMAT_R8G8B8A8_UNORM
415     {
416         constexpr VkFormat format = VK_FORMAT_R8G8B8A8_UNORM;
417         auto& info = this->getFormatInfo(format);
418         info.init(interface, physDev, properties, format);
419          if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
420             info.fColorTypeInfoCount = 2;
421             info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
422             int ctIdx = 0;
423             // Format: VK_FORMAT_R8G8B8A8_UNORM, Surface: kRGBA_8888
424             {
425                 constexpr SkColorType ct = SkColorType::kRGBA_8888_SkColorType;
426                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
427                 ctInfo.fColorType = ct;
428                 ctInfo.fTransferColorType = ct;
429                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
430             }
431             // Format: VK_FORMAT_R8G8B8A8_UNORM, Surface: kRGB_888x
432             {
433                 constexpr SkColorType ct = SkColorType::kRGB_888x_SkColorType;
434                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
435                 ctInfo.fColorType = ct;
436                 ctInfo.fTransferColorType = ct;
437                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag;
438                 ctInfo.fReadSwizzle = skgpu::Swizzle::RGB1();
439             }
440         }
441     }
442 
443     // Format: VK_FORMAT_R8_UNORM
444     {
445         constexpr VkFormat format = VK_FORMAT_R8_UNORM;
446         auto& info = this->getFormatInfo(format);
447         info.init(interface, physDev, properties, format);
448          if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
449             info.fColorTypeInfoCount = 3;
450             info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
451             int ctIdx = 0;
452             // Format: VK_FORMAT_R8_UNORM, Surface: kR_8
453             {
454                 constexpr SkColorType ct = SkColorType::kR8_unorm_SkColorType;
455                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
456                 ctInfo.fColorType = ct;
457                 ctInfo.fTransferColorType = ct;
458                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
459             }
460             // Format: VK_FORMAT_R8_UNORM, Surface: kAlpha_8
461             {
462                 constexpr SkColorType ct = SkColorType::kAlpha_8_SkColorType;
463                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
464                 ctInfo.fColorType = ct;
465                 ctInfo.fTransferColorType = ct;
466                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
467                 ctInfo.fReadSwizzle = skgpu::Swizzle("000r");
468                 ctInfo.fWriteSwizzle = skgpu::Swizzle("a000");
469             }
470             // Format: VK_FORMAT_R8_UNORM, Surface: kGray_8
471             {
472                 constexpr SkColorType ct = SkColorType::kGray_8_SkColorType;
473                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
474                 ctInfo.fColorType = ct;
475                 ctInfo.fTransferColorType = ct;
476                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag;
477                 ctInfo.fReadSwizzle = skgpu::Swizzle("rrr1");
478             }
479         }
480     }
481 
482     // Format: VK_FORMAT_B8G8R8A8_UNORM
483     {
484         constexpr VkFormat format = VK_FORMAT_B8G8R8A8_UNORM;
485         auto& info = this->getFormatInfo(format);
486         info.init(interface, physDev, properties, format);
487          if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
488             info.fColorTypeInfoCount = 1;
489             info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
490             int ctIdx = 0;
491             // Format: VK_FORMAT_B8G8R8A8_UNORM, Surface: kBGRA_8888
492             {
493                 constexpr SkColorType ct = SkColorType::kBGRA_8888_SkColorType;
494                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
495                 ctInfo.fColorType = ct;
496                 ctInfo.fTransferColorType = ct;
497                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
498             }
499         }
500     }
501     // Format: VK_FORMAT_R5G6B5_UNORM_PACK16
502     {
503         constexpr VkFormat format = VK_FORMAT_R5G6B5_UNORM_PACK16;
504         auto& info = this->getFormatInfo(format);
505         info.init(interface, physDev, properties, format);
506          if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
507             info.fColorTypeInfoCount = 1;
508             info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
509             int ctIdx = 0;
510             // Format: VK_FORMAT_R5G6B5_UNORM_PACK16, Surface: kRGB_565_SkColorType
511             {
512                 constexpr SkColorType ct = SkColorType::kRGB_565_SkColorType;
513                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
514                 ctInfo.fColorType = ct;
515                 ctInfo.fTransferColorType = ct;
516                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
517             }
518         }
519     }
520     // Format: VK_FORMAT_R16G16B16A16_SFLOAT
521     {
522         constexpr VkFormat format = VK_FORMAT_R16G16B16A16_SFLOAT;
523         auto& info = this->getFormatInfo(format);
524         info.init(interface, physDev, properties, format);
525          if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
526             info.fColorTypeInfoCount = 2;
527             info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
528             int ctIdx = 0;
529             // Format: VK_FORMAT_R16G16B16A16_SFLOAT, Surface: SkColorType::kRGBA_F16_SkColorType
530             {
531                 constexpr SkColorType ct = SkColorType::kRGBA_F16_SkColorType;
532                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
533                 ctInfo.fColorType = ct;
534                 ctInfo.fTransferColorType = ct;
535                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
536             }
537         }
538     }
539     // Format: VK_FORMAT_R16_SFLOAT
540     {
541         constexpr VkFormat format = VK_FORMAT_R16_SFLOAT;
542         auto& info = this->getFormatInfo(format);
543         info.init(interface, physDev, properties, format);
544          if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
545             info.fColorTypeInfoCount = 1;
546             info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
547             int ctIdx = 0;
548             // Format: VK_FORMAT_R16_SFLOAT, Surface: kAlpha_F16
549             {
550                 constexpr SkColorType ct = SkColorType::kA16_float_SkColorType;
551                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
552                 ctInfo.fColorType = ct;
553                 ctInfo.fTransferColorType = ct;
554                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
555                 ctInfo.fReadSwizzle = skgpu::Swizzle("000r");
556                 ctInfo.fWriteSwizzle = skgpu::Swizzle("a000");
557             }
558         }
559     }
560     // Format: VK_FORMAT_R8G8B8_UNORM
561     {
562         constexpr VkFormat format = VK_FORMAT_R8G8B8_UNORM;
563         auto& info = this->getFormatInfo(format);
564         info.init(interface, physDev, properties, format);
565          if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
566             info.fColorTypeInfoCount = 1;
567             info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
568             int ctIdx = 0;
569             // Format: VK_FORMAT_R8G8B8_UNORM, Surface: kRGB_888x
570             {
571                 constexpr SkColorType ct = SkColorType::kRGB_888x_SkColorType;
572                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
573                 ctInfo.fColorType = ct;
574                 // This SkColorType is a lie, but we don't have a kRGB_888_SkColorType. The Vulkan
575                 // format is 3 bpp so we must manualy convert to/from this and kRGB_888x when doing
576                 // transfers. We signal this need for manual conversions in the
577                 // supportedRead/WriteColorType calls.
578                 ctInfo.fTransferColorType = SkColorType::kRGB_888x_SkColorType;
579                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
580             }
581         }
582     }
583     // Format: VK_FORMAT_R8G8_UNORM
584     {
585         constexpr VkFormat format = VK_FORMAT_R8G8_UNORM;
586         auto& info = this->getFormatInfo(format);
587         info.init(interface, physDev, properties, format);
588          if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
589             info.fColorTypeInfoCount = 1;
590             info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
591             int ctIdx = 0;
592             // Format: VK_FORMAT_R8G8_UNORM, Surface: kR8G8_unorm
593             {
594                 constexpr SkColorType ct = SkColorType::kR8G8_unorm_SkColorType;
595                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
596                 ctInfo.fColorType = ct;
597                 ctInfo.fTransferColorType = ct;
598                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
599             }
600         }
601     }
602     // Format: VK_FORMAT_A2B10G10R10_UNORM_PACK32
603     {
604         constexpr VkFormat format = VK_FORMAT_A2B10G10R10_UNORM_PACK32;
605         auto& info = this->getFormatInfo(format);
606         info.init(interface, physDev, properties, format);
607          if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
608             info.fColorTypeInfoCount = 1;
609             info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
610             int ctIdx = 0;
611             // Format: VK_FORMAT_A2B10G10R10_UNORM_PACK32, Surface: kRGBA_1010102
612             {
613                 constexpr SkColorType ct = SkColorType::kRGBA_1010102_SkColorType;
614                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
615                 ctInfo.fColorType = ct;
616                 ctInfo.fTransferColorType = ct;
617                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
618             }
619         }
620     }
621     // Format: VK_FORMAT_A2R10G10B10_UNORM_PACK32
622     {
623         constexpr VkFormat format = VK_FORMAT_A2R10G10B10_UNORM_PACK32;
624         auto& info = this->getFormatInfo(format);
625         info.init(interface, physDev, properties, format);
626          if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
627             info.fColorTypeInfoCount = 1;
628             info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
629             int ctIdx = 0;
630             // Format: VK_FORMAT_A2R10G10B10_UNORM_PACK32, Surface: kBGRA_1010102
631             {
632                 constexpr SkColorType ct = SkColorType::kBGRA_1010102_SkColorType;
633                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
634                 ctInfo.fColorType = ct;
635                 ctInfo.fTransferColorType = ct;
636                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
637             }
638         }
639     }
640     // Format: VK_FORMAT_B4G4R4A4_UNORM_PACK16
641     {
642         constexpr VkFormat format = VK_FORMAT_B4G4R4A4_UNORM_PACK16;
643         auto& info = this->getFormatInfo(format);
644         info.init(interface, physDev, properties, format);
645          if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
646             info.fColorTypeInfoCount = 1;
647             info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
648             int ctIdx = 0;
649             // Format: VK_FORMAT_B4G4R4A4_UNORM_PACK16, Surface: kARGB_4444_SkColorType
650             {
651                 constexpr SkColorType ct = SkColorType::kARGB_4444_SkColorType;
652                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
653                 ctInfo.fColorType = ct;
654                 ctInfo.fTransferColorType = ct;
655                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
656                 ctInfo.fReadSwizzle = skgpu::Swizzle::BGRA();
657                 ctInfo.fWriteSwizzle = skgpu::Swizzle::BGRA();
658             }
659         }
660     }
661 
662     // Format: VK_FORMAT_R4G4B4A4_UNORM_PACK16
663     {
664         constexpr VkFormat format = VK_FORMAT_R4G4B4A4_UNORM_PACK16;
665         auto& info = this->getFormatInfo(format);
666         info.init(interface, physDev, properties, format);
667          if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
668             info.fColorTypeInfoCount = 1;
669             info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
670             int ctIdx = 0;
671             // Format: VK_FORMAT_R4G4B4A4_UNORM_PACK16, Surface: kARGB_4444_SkColorType
672             {
673                 constexpr SkColorType ct = SkColorType::kARGB_4444_SkColorType;
674                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
675                 ctInfo.fColorType = ct;
676                 ctInfo.fTransferColorType = ct;
677                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
678             }
679         }
680     }
681     // Format: VK_FORMAT_R8G8B8A8_SRGB
682     {
683         constexpr VkFormat format = VK_FORMAT_R8G8B8A8_SRGB;
684         auto& info = this->getFormatInfo(format);
685         info.init(interface, physDev, properties, format);
686          if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
687             info.fColorTypeInfoCount = 1;
688             info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
689             int ctIdx = 0;
690             // Format: VK_FORMAT_R8G8B8A8_SRGB, Surface: kRGBA_8888_SRGB
691             {
692                 constexpr SkColorType ct = SkColorType::kSRGBA_8888_SkColorType;
693                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
694                 ctInfo.fColorType = ct;
695                 ctInfo.fTransferColorType = ct;
696                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
697             }
698         }
699     }
700     // Format: VK_FORMAT_R16_UNORM
701     {
702         constexpr VkFormat format = VK_FORMAT_R16_UNORM;
703         auto& info = this->getFormatInfo(format);
704         info.init(interface, physDev, properties, format);
705          if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
706             info.fColorTypeInfoCount = 1;
707             info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
708             int ctIdx = 0;
709             // Format: VK_FORMAT_R16_UNORM, Surface: kAlpha_16
710             {
711                 constexpr SkColorType ct = SkColorType::kA16_unorm_SkColorType;
712                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
713                 ctInfo.fColorType = ct;
714                 ctInfo.fTransferColorType = ct;
715                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
716                 ctInfo.fReadSwizzle = skgpu::Swizzle("000r");
717                 ctInfo.fWriteSwizzle = skgpu::Swizzle("a000");
718             }
719         }
720     }
721     // Format: VK_FORMAT_R16G16_UNORM
722     {
723         constexpr VkFormat format = VK_FORMAT_R16G16_UNORM;
724         auto& info = this->getFormatInfo(format);
725         info.init(interface, physDev, properties, format);
726          if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
727             info.fColorTypeInfoCount = 1;
728             info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
729             int ctIdx = 0;
730             // Format: VK_FORMAT_R16G16_UNORM, Surface: kRG_1616
731             {
732                 constexpr SkColorType ct = SkColorType::kR16G16_unorm_SkColorType;
733                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
734                 ctInfo.fColorType = ct;
735                 ctInfo.fTransferColorType = ct;
736                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
737             }
738         }
739     }
740     // Format: VK_FORMAT_R16G16B16A16_UNORM
741     {
742         constexpr VkFormat format = VK_FORMAT_R16G16B16A16_UNORM;
743         auto& info = this->getFormatInfo(format);
744         info.init(interface, physDev, properties, format);
745          if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
746             info.fColorTypeInfoCount = 1;
747             info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
748             int ctIdx = 0;
749             // Format: VK_FORMAT_R16G16B16A16_UNORM, Surface: kRGBA_16161616
750             {
751                 constexpr SkColorType ct = SkColorType::kR16G16B16A16_unorm_SkColorType;
752                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
753                 ctInfo.fColorType = ct;
754                 ctInfo.fTransferColorType = ct;
755                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
756             }
757         }
758     }
759     // Format: VK_FORMAT_R16G16_SFLOAT
760     {
761         constexpr VkFormat format = VK_FORMAT_R16G16_SFLOAT;
762         auto& info = this->getFormatInfo(format);
763         info.init(interface, physDev, properties, format);
764          if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
765             info.fColorTypeInfoCount = 1;
766             info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
767             int ctIdx = 0;
768             // Format: VK_FORMAT_R16G16_SFLOAT, Surface: kRG_F16
769             {
770                 constexpr SkColorType ct = SkColorType::kR16G16_float_SkColorType;
771                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
772                 ctInfo.fColorType = ct;
773                 ctInfo.fTransferColorType = ct;
774                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
775             }
776         }
777     }
778     // Format: VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM
779     {
780         constexpr VkFormat format = VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM;
781         auto& info = this->getFormatInfo(format);
782         if (fSupportsYcbcrConversion) {
783             info.init(interface, physDev, properties, format);
784         }
785         if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
786             info.fColorTypeInfoCount = 1;
787             info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
788             int ctIdx = 0;
789             // Format: VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM, Surface: kRGB_888x
790             {
791                 constexpr SkColorType ct = SkColorType::kRGB_888x_SkColorType;
792                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
793                 ctInfo.fColorType = ct;
794                 ctInfo.fTransferColorType = ct;
795                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag;
796             }
797             SkDEBUGCODE(info.fIsWrappedOnly = true;)
798         }
799     }
800     // Format: VK_FORMAT_G8_B8R8_2PLANE_420_UNORM
801     {
802         constexpr VkFormat format = VK_FORMAT_G8_B8R8_2PLANE_420_UNORM;
803         auto& info = this->getFormatInfo(format);
804         if (fSupportsYcbcrConversion) {
805             info.init(interface, physDev, properties, format);
806         }
807         if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
808             info.fColorTypeInfoCount = 1;
809             info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
810             int ctIdx = 0;
811             // Format: VK_FORMAT_G8_B8R8_2PLANE_420_UNORM, Surface: kRGB_888x
812             {
813                 constexpr SkColorType ct = SkColorType::kRGB_888x_SkColorType;
814                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
815                 ctInfo.fColorType = ct;
816                 ctInfo.fTransferColorType = ct;
817                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag;
818             }
819             SkDEBUGCODE(info.fIsWrappedOnly = true;)
820         }
821     }
822     // Format: VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK
823     {
824         constexpr VkFormat format = VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK;
825         auto& info = this->getFormatInfo(format);
826         info.init(interface, physDev, properties, format);
827         if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
828             info.fColorTypeInfoCount = 1;
829             info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
830             int ctIdx = 0;
831             // Format: VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK, Surface: kRGB_888x
832             {
833                 constexpr SkColorType ct = SkColorType::kRGB_888x_SkColorType;
834                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
835                 ctInfo.fColorType = ct;
836                 ctInfo.fTransferColorType = ct;
837                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag;
838             }
839         }
840     }
841 
842     // Format: VK_FORMAT_BC1_RGB_UNORM_BLOCK
843     {
844         constexpr VkFormat format = VK_FORMAT_BC1_RGB_UNORM_BLOCK;
845         auto& info = this->getFormatInfo(format);
846         info.init(interface, physDev, properties, format);
847         if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
848             info.fColorTypeInfoCount = 1;
849             info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
850             int ctIdx = 0;
851             // Format: VK_FORMAT_BC1_RGB_UNORM_BLOCK, Surface: kRGB_888x
852             {
853                 constexpr SkColorType ct = SkColorType::kRGB_888x_SkColorType;
854                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
855                 ctInfo.fColorType = ct;
856                 ctInfo.fTransferColorType = ct;
857                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag;
858             }
859         }
860     }
861 
862     // Format: VK_FORMAT_BC1_RGBA_UNORM_BLOCK
863     {
864         constexpr VkFormat format = VK_FORMAT_BC1_RGBA_UNORM_BLOCK;
865         auto& info = this->getFormatInfo(format);
866         info.init(interface, physDev, properties, format);
867         if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
868             info.fColorTypeInfoCount = 1;
869             info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
870             int ctIdx = 0;
871             // Format: VK_FORMAT_BC1_RGBA_UNORM_BLOCK, Surface: kRGB_888x
872             {
873                 constexpr SkColorType ct = SkColorType::kRGBA_8888_SkColorType;
874                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
875                 ctInfo.fColorType = ct;
876                 ctInfo.fTransferColorType = ct;
877                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag;
878             }
879         }
880     }
881 
882     ////////////////////////////////////////////////////////////////////////////
883     // Map SkColorType (used for creating Surfaces) to VkFormats. The order in which the formats are
884     // passed into the setColorType function indicates the priority in selecting which format we use
885     // for a given SkColorType.
886     typedef SkColorType ct;
887 
888     this->setColorType(ct::kAlpha_8_SkColorType,            { VK_FORMAT_R8_UNORM });
889     this->setColorType(ct::kRGB_565_SkColorType,            { VK_FORMAT_R5G6B5_UNORM_PACK16 });
890     this->setColorType(ct::kARGB_4444_SkColorType,          { VK_FORMAT_R4G4B4A4_UNORM_PACK16,
891                                                               VK_FORMAT_B4G4R4A4_UNORM_PACK16 });
892     this->setColorType(ct::kRGBA_8888_SkColorType,          { VK_FORMAT_R8G8B8A8_UNORM });
893     this->setColorType(ct::kSRGBA_8888_SkColorType,         { VK_FORMAT_R8G8B8A8_SRGB });
894     this->setColorType(ct::kRGB_888x_SkColorType,           { VK_FORMAT_R8G8B8_UNORM,
895                                                               VK_FORMAT_R8G8B8A8_UNORM });
896     this->setColorType(ct::kR8G8_unorm_SkColorType,         { VK_FORMAT_R8G8_UNORM });
897     this->setColorType(ct::kBGRA_8888_SkColorType,          { VK_FORMAT_B8G8R8A8_UNORM });
898     this->setColorType(ct::kRGBA_1010102_SkColorType,       { VK_FORMAT_A2B10G10R10_UNORM_PACK32 });
899     this->setColorType(ct::kBGRA_1010102_SkColorType,       { VK_FORMAT_A2R10G10B10_UNORM_PACK32 });
900     this->setColorType(ct::kGray_8_SkColorType,             { VK_FORMAT_R8_UNORM });
901     this->setColorType(ct::kA16_float_SkColorType,          { VK_FORMAT_R16_SFLOAT });
902     this->setColorType(ct::kRGBA_F16_SkColorType,           { VK_FORMAT_R16G16B16A16_SFLOAT });
903     this->setColorType(ct::kA16_unorm_SkColorType,          { VK_FORMAT_R16_UNORM });
904     this->setColorType(ct::kR16G16_unorm_SkColorType,       { VK_FORMAT_R16G16_UNORM });
905     this->setColorType(ct::kR16G16B16A16_unorm_SkColorType, { VK_FORMAT_R16G16B16A16_UNORM });
906     this->setColorType(ct::kR16G16_float_SkColorType,       { VK_FORMAT_R16G16_SFLOAT });
907 }
908 
909 namespace {
set_ds_flags_to_format(VkFormat & slot,VkFormat format)910 void set_ds_flags_to_format(VkFormat& slot, VkFormat format) {
911     if (slot == VK_FORMAT_UNDEFINED) {
912         slot = format;
913     }
914 }
915 } // namespace
916 
initDepthStencilFormatTable(const skgpu::VulkanInterface * interface,VkPhysicalDevice physDev,const VkPhysicalDeviceProperties & properties)917 void VulkanCaps::initDepthStencilFormatTable(const skgpu::VulkanInterface* interface,
918                                              VkPhysicalDevice physDev,
919                                              const VkPhysicalDeviceProperties& properties) {
920     static_assert(std::size(kDepthStencilVkFormats) == VulkanCaps::kNumDepthStencilVkFormats,
921                   "Size of DepthStencilVkFormats array must match static value in header");
922 
923     using DSFlags = SkEnumBitMask<DepthStencilFlags>;
924     constexpr DSFlags stencilFlags = DepthStencilFlags::kStencil;
925     constexpr DSFlags depthFlags = DepthStencilFlags::kDepth;
926     constexpr DSFlags dsFlags = DepthStencilFlags::kDepthStencil;
927 
928     std::fill_n(fDepthStencilFlagsToFormatTable, kNumDepthStencilFlags, VK_FORMAT_UNDEFINED);
929     // Format: VK_FORMAT_S8_UINT
930     {
931         constexpr VkFormat format = VK_FORMAT_S8_UINT;
932         auto& info = this->getDepthStencilFormatInfo(format);
933         info.init(interface, physDev, properties, format);
934         if (info.fFormatProperties.optimalTilingFeatures &
935             VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) {
936             set_ds_flags_to_format(fDepthStencilFlagsToFormatTable[stencilFlags.value()], format);
937         }
938     }
939     // Format: VK_FORMAT_D16_UNORM
940     {
941         // Qualcomm drivers will report OUT_OF_HOST_MEMORY when binding memory to a VkImage with
942         // D16_UNORM in a protected context. Using D32_SFLOAT succeeds, so clearly it's not actually
943         // out of memory. D16_UNORM appears to function correctly in unprotected contexts.
944         const bool disableD16InProtected = this->protectedSupport() &&
945                                            kQualcomm_VkVendor == properties.vendorID;
946         if (!disableD16InProtected) {
947             constexpr VkFormat format = VK_FORMAT_D16_UNORM;
948             auto& info = this->getDepthStencilFormatInfo(format);
949             info.init(interface, physDev, properties, format);
950             if (info.fFormatProperties.optimalTilingFeatures &
951                 VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) {
952                 set_ds_flags_to_format(fDepthStencilFlagsToFormatTable[depthFlags.value()], format);
953             }
954         }
955     }
956     // Format: VK_FORMAT_D32_SFLOAT
957     {
958         constexpr VkFormat format = VK_FORMAT_D32_SFLOAT;
959         auto& info = this->getDepthStencilFormatInfo(format);
960         info.init(interface, physDev, properties, format);
961         if (info.fFormatProperties.optimalTilingFeatures &
962             VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) {
963             set_ds_flags_to_format(fDepthStencilFlagsToFormatTable[depthFlags.value()], format);
964         }
965     }
966     // Format: VK_FORMAT_D24_UNORM_S8_UINT
967     {
968         constexpr VkFormat format = VK_FORMAT_D24_UNORM_S8_UINT;
969         auto& info = this->getDepthStencilFormatInfo(format);
970         info.init(interface, physDev, properties, format);
971         if (info.fFormatProperties.optimalTilingFeatures &
972             VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) {
973             set_ds_flags_to_format(fDepthStencilFlagsToFormatTable[stencilFlags.value()], format);
974             set_ds_flags_to_format(fDepthStencilFlagsToFormatTable[depthFlags.value()], format);
975             set_ds_flags_to_format(fDepthStencilFlagsToFormatTable[dsFlags.value()], format);
976         }
977     }
978     // Format: VK_FORMAT_D32_SFLOAT_S8_UINT
979     {
980         constexpr VkFormat format = VK_FORMAT_D32_SFLOAT_S8_UINT;
981         auto& info = this->getDepthStencilFormatInfo(format);
982         info.init(interface, physDev, properties, format);
983         if (info.fFormatProperties.optimalTilingFeatures &
984             VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) {
985             set_ds_flags_to_format(fDepthStencilFlagsToFormatTable[stencilFlags.value()], format);
986             set_ds_flags_to_format(fDepthStencilFlagsToFormatTable[depthFlags.value()], format);
987             set_ds_flags_to_format(fDepthStencilFlagsToFormatTable[dsFlags.value()], format);
988         }
989     }
990 }
991 
initSampleCounts(const skgpu::VulkanInterface * interface,VkPhysicalDevice physDev,const VkPhysicalDeviceProperties & physProps,VkFormat format,VkImageUsageFlags usage)992 void VulkanCaps::SupportedSampleCounts::initSampleCounts(const skgpu::VulkanInterface* interface,
993         VkPhysicalDevice physDev,
994         const VkPhysicalDeviceProperties& physProps,
995         VkFormat format,
996         VkImageUsageFlags usage) {
997     VkImageFormatProperties properties;
998 
999     VkResult result;
1000     // VULKAN_CALL_RESULT requires a VulkanSharedContext for tracking DEVICE_LOST, but VulkanCaps
1001     // are initialized before a VulkanSharedContext is available. The _NOCHECK variant only requires
1002     // a VulkanInterface, so we can use that and log failures manually.
1003     VULKAN_CALL_RESULT_NOCHECK(interface,
1004                                result,
1005                                GetPhysicalDeviceImageFormatProperties(physDev,
1006                                                                       format,
1007                                                                       VK_IMAGE_TYPE_2D,
1008                                                                       VK_IMAGE_TILING_OPTIMAL,
1009                                                                       usage,
1010                                                                       0,  // createFlags
1011                                                                       &properties));
1012     if (result != VK_SUCCESS) {
1013         SKGPU_LOG_W("Vulkan call GetPhysicalDeviceImageFormatProperties failed: %d", result);
1014         return;
1015     }
1016 
1017     VkSampleCountFlags flags = properties.sampleCounts;
1018     if (flags & VK_SAMPLE_COUNT_1_BIT) {
1019         fSampleCounts.push_back(1);
1020     }
1021     if (kImagination_VkVendor == physProps.vendorID) {
1022         // MSAA does not work on imagination
1023         return;
1024     }
1025     if (kIntel_VkVendor == physProps.vendorID) {
1026         // MSAA doesn't work well on Intel GPUs chromium:527565, chromium:983926
1027         return;
1028     }
1029     if (flags & VK_SAMPLE_COUNT_2_BIT) {
1030         fSampleCounts.push_back(2);
1031     }
1032     if (flags & VK_SAMPLE_COUNT_4_BIT) {
1033         fSampleCounts.push_back(4);
1034     }
1035     if (flags & VK_SAMPLE_COUNT_8_BIT) {
1036         fSampleCounts.push_back(8);
1037     }
1038     if (flags & VK_SAMPLE_COUNT_16_BIT) {
1039         fSampleCounts.push_back(16);
1040     }
1041     // Standard sample locations are not defined for more than 16 samples, and we don't need more
1042     // than 16. Omit 32 and 64.
1043 }
1044 
isSampleCountSupported(int requestedCount) const1045 bool VulkanCaps::SupportedSampleCounts::isSampleCountSupported(int requestedCount) const {
1046     requestedCount = std::max(1, requestedCount);
1047     for (int i = 0; i < fSampleCounts.size(); i++) {
1048         if (fSampleCounts[i] == requestedCount) {
1049             return true;
1050         } else if (requestedCount < fSampleCounts[i]) {
1051             return false;
1052         }
1053     }
1054     return false;
1055 }
1056 
1057 
1058 namespace {
is_texturable(VkFormatFeatureFlags flags)1059 bool is_texturable(VkFormatFeatureFlags flags) {
1060     return SkToBool(VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT & flags) &&
1061            SkToBool(VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT & flags);
1062 }
1063 
is_renderable(VkFormatFeatureFlags flags)1064 bool is_renderable(VkFormatFeatureFlags flags) {
1065     return SkToBool(VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT & flags);
1066 }
1067 
is_storage(VkFormatFeatureFlags flags)1068 bool is_storage(VkFormatFeatureFlags flags) {
1069     return SkToBool(VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT & flags);
1070 }
1071 
is_transfer_src(VkFormatFeatureFlags flags)1072 bool is_transfer_src(VkFormatFeatureFlags flags) {
1073     return SkToBool(VK_FORMAT_FEATURE_TRANSFER_SRC_BIT & flags);
1074 }
1075 
is_transfer_dst(VkFormatFeatureFlags flags)1076 bool is_transfer_dst(VkFormatFeatureFlags flags) {
1077     return SkToBool(VK_FORMAT_FEATURE_TRANSFER_DST_BIT & flags);
1078 }
1079 }
1080 
init(const skgpu::VulkanInterface * interface,VkPhysicalDevice physDev,const VkPhysicalDeviceProperties & properties,VkFormat format)1081 void VulkanCaps::FormatInfo::init(const skgpu::VulkanInterface* interface,
1082                                   VkPhysicalDevice physDev,
1083                                   const VkPhysicalDeviceProperties& properties,
1084                                   VkFormat format) {
1085     memset(&fFormatProperties, 0, sizeof(VkFormatProperties));
1086     VULKAN_CALL(interface, GetPhysicalDeviceFormatProperties(physDev, format, &fFormatProperties));
1087 
1088     if (is_renderable(fFormatProperties.optimalTilingFeatures)) {
1089         // We make all renderable images support being used as input attachment
1090         VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
1091                                        VK_IMAGE_USAGE_TRANSFER_DST_BIT |
1092                                        VK_IMAGE_USAGE_SAMPLED_BIT |
1093                                        VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
1094                                        VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
1095         this->fSupportedSampleCounts.initSampleCounts(interface, physDev, properties, format,
1096                                                       usageFlags);
1097     }
1098 }
1099 
isTexturable(VkImageTiling imageTiling) const1100 bool VulkanCaps::FormatInfo::isTexturable(VkImageTiling imageTiling) const {
1101     switch (imageTiling) {
1102         case VK_IMAGE_TILING_OPTIMAL:
1103             return is_texturable(fFormatProperties.optimalTilingFeatures);
1104         case VK_IMAGE_TILING_LINEAR:
1105             return is_texturable(fFormatProperties.linearTilingFeatures);
1106         default:
1107             return false;
1108     }
1109     SkUNREACHABLE;
1110 }
1111 
isRenderable(VkImageTiling imageTiling,uint32_t sampleCount) const1112 bool VulkanCaps::FormatInfo::isRenderable(VkImageTiling imageTiling,
1113                                           uint32_t sampleCount) const {
1114     if (!fSupportedSampleCounts.isSampleCountSupported(sampleCount)) {
1115         return false;
1116     }
1117     switch (imageTiling) {
1118         case VK_IMAGE_TILING_OPTIMAL:
1119             return is_renderable(fFormatProperties.optimalTilingFeatures);
1120         case VK_IMAGE_TILING_LINEAR:
1121             return is_renderable(fFormatProperties.linearTilingFeatures);
1122         default:
1123             return false;
1124     }
1125     SkUNREACHABLE;
1126 }
1127 
isStorage(VkImageTiling imageTiling) const1128 bool VulkanCaps::FormatInfo::isStorage(VkImageTiling imageTiling) const {
1129     switch (imageTiling) {
1130         case VK_IMAGE_TILING_OPTIMAL:
1131             return is_storage(fFormatProperties.optimalTilingFeatures);
1132         case VK_IMAGE_TILING_LINEAR:
1133             return is_storage(fFormatProperties.linearTilingFeatures);
1134         default:
1135             return false;
1136     }
1137     SkUNREACHABLE;
1138 }
1139 
isTransferSrc(VkImageTiling imageTiling) const1140 bool VulkanCaps::FormatInfo::isTransferSrc(VkImageTiling imageTiling) const {
1141     switch (imageTiling) {
1142         case VK_IMAGE_TILING_OPTIMAL:
1143             return is_transfer_src(fFormatProperties.optimalTilingFeatures);
1144         case VK_IMAGE_TILING_LINEAR:
1145             return is_transfer_src(fFormatProperties.linearTilingFeatures);
1146         default:
1147             return false;
1148     }
1149     SkUNREACHABLE;
1150 }
1151 
isTransferDst(VkImageTiling imageTiling) const1152 bool VulkanCaps::FormatInfo::isTransferDst(VkImageTiling imageTiling) const {
1153     switch (imageTiling) {
1154         case VK_IMAGE_TILING_OPTIMAL:
1155             return is_transfer_dst(fFormatProperties.optimalTilingFeatures);
1156         case VK_IMAGE_TILING_LINEAR:
1157             return is_transfer_dst(fFormatProperties.linearTilingFeatures);
1158         default:
1159             return false;
1160     }
1161     SkUNREACHABLE;
1162 }
1163 
setColorType(SkColorType colorType,std::initializer_list<VkFormat> formats)1164 void VulkanCaps::setColorType(SkColorType colorType, std::initializer_list<VkFormat> formats) {
1165     int idx = static_cast<int>(colorType);
1166     for (auto it = formats.begin(); it != formats.end(); ++it) {
1167         const auto& info = this->getFormatInfo(*it);
1168         for (int i = 0; i < info.fColorTypeInfoCount; ++i) {
1169             if (info.fColorTypeInfos[i].fColorType == colorType) {
1170                 fColorTypeToFormatTable[idx] = *it;
1171                 return;
1172             }
1173         }
1174     }
1175 }
1176 
getFormatFromColorType(SkColorType colorType) const1177 VkFormat VulkanCaps::getFormatFromColorType(SkColorType colorType) const {
1178     int idx = static_cast<int>(colorType);
1179     return fColorTypeToFormatTable[idx];
1180 }
1181 
getFormatInfo(VkFormat format)1182 VulkanCaps::FormatInfo& VulkanCaps::getFormatInfo(VkFormat format) {
1183     static_assert(std::size(kVkFormats) == VulkanCaps::kNumVkFormats,
1184                   "Size of VkFormats array must match static value in header");
1185     for (size_t i = 0; i < std::size(kVkFormats); ++i) {
1186         if (kVkFormats[i] == format) {
1187             return fFormatTable[i];
1188         }
1189     }
1190     static FormatInfo kInvalidFormat;
1191     return kInvalidFormat;
1192 }
1193 
getFormatInfo(VkFormat format) const1194 const VulkanCaps::FormatInfo& VulkanCaps::getFormatInfo(VkFormat format) const {
1195     VulkanCaps* nonConstThis = const_cast<VulkanCaps*>(this);
1196     return nonConstThis->getFormatInfo(format);
1197 }
1198 
init(const skgpu::VulkanInterface * interface,VkPhysicalDevice physDev,const VkPhysicalDeviceProperties & properties,VkFormat format)1199 void VulkanCaps::DepthStencilFormatInfo::init(const skgpu::VulkanInterface* interface,
1200                                              VkPhysicalDevice physDev,
1201                                              const VkPhysicalDeviceProperties& properties,
1202                                              VkFormat format) {
1203     memset(&fFormatProperties, 0, sizeof(VkFormatProperties));
1204     VULKAN_CALL(interface, GetPhysicalDeviceFormatProperties(physDev, format, &fFormatProperties));
1205 
1206     if (this->isDepthStencilSupported(fFormatProperties.optimalTilingFeatures)) {
1207         VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
1208         fSupportedSampleCounts.initSampleCounts(interface, physDev, properties, format, usageFlags);
1209     }
1210 }
1211 
isDepthStencilSupported(VkFormatFeatureFlags flags) const1212 bool VulkanCaps::DepthStencilFormatInfo::isDepthStencilSupported(VkFormatFeatureFlags flags) const {
1213     return SkToBool(VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT & flags);
1214 }
1215 
getFormatFromDepthStencilFlags(const SkEnumBitMask<DepthStencilFlags> & flags) const1216 VkFormat VulkanCaps::getFormatFromDepthStencilFlags(const SkEnumBitMask<DepthStencilFlags>& flags)
1217         const {
1218     return fDepthStencilFlagsToFormatTable[flags.value()];
1219 }
1220 
getDepthStencilFormatInfo(VkFormat format)1221 VulkanCaps::DepthStencilFormatInfo& VulkanCaps::getDepthStencilFormatInfo(VkFormat format) {
1222     static_assert(std::size(kDepthStencilVkFormats) == VulkanCaps::kNumDepthStencilVkFormats,
1223                   "Size of VkFormats array must match static value in header");
1224     for (size_t i = 0; i < std::size(kDepthStencilVkFormats); ++i) {
1225         if (kVkFormats[i] == format) {
1226             return fDepthStencilFormatTable[i];
1227         }
1228     }
1229     static DepthStencilFormatInfo kInvalidFormat;
1230     return kInvalidFormat;
1231 }
1232 
getDepthStencilFormatInfo(VkFormat format) const1233 const VulkanCaps::DepthStencilFormatInfo& VulkanCaps::getDepthStencilFormatInfo(VkFormat format)
1234         const {
1235     VulkanCaps* nonConstThis = const_cast<VulkanCaps*>(this);
1236     return nonConstThis->getDepthStencilFormatInfo(format);
1237 }
1238 
getColorTypeInfo(SkColorType ct,const TextureInfo & textureInfo) const1239 const Caps::ColorTypeInfo* VulkanCaps::getColorTypeInfo(SkColorType ct,
1240                                                         const TextureInfo& textureInfo) const {
1241     VkFormat vkFormat = textureInfo.vulkanTextureSpec().fFormat;
1242     if (vkFormat == VK_FORMAT_UNDEFINED) {
1243         // If VkFormat is undefined but there is a valid YCbCr conversion associated with the
1244         // texture, then we know we are using an external format and can return color type
1245         // info representative of external format color information.
1246         return textureInfo.vulkanTextureSpec().fYcbcrConversionInfo.isValid()
1247                 ? &fExternalFormatColorTypeInfo
1248                 : nullptr;
1249     }
1250 
1251     const FormatInfo& info = this->getFormatInfo(vkFormat);
1252     for (int i = 0; i < info.fColorTypeInfoCount; ++i) {
1253         const ColorTypeInfo& ctInfo = info.fColorTypeInfos[i];
1254         if (ctInfo.fColorType == ct) {
1255             return &ctInfo;
1256         }
1257     }
1258 
1259     return nullptr;
1260 }
1261 
onIsTexturable(const TextureInfo & texInfo) const1262 bool VulkanCaps::onIsTexturable(const TextureInfo& texInfo) const {
1263     VulkanTextureInfo vkInfo;
1264     if (!texInfo.getVulkanTextureInfo(&vkInfo)) {
1265         return false;
1266     }
1267 
1268     // All images using external formats are required to be able to be sampled per Vulkan spec.
1269     // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkAndroidHardwareBufferFormatPropertiesANDROID.html#_description
1270     if (vkInfo.fFormat == VK_FORMAT_UNDEFINED && vkInfo.fYcbcrConversionInfo.isValid()) {
1271         return true;
1272     }
1273 
1274     // Otherwise, we are working with a known format and can simply reference the format table info.
1275     const FormatInfo& info = this->getFormatInfo(vkInfo.fFormat);
1276     return info.isTexturable(vkInfo.fImageTiling);
1277 }
1278 
isRenderable(const TextureInfo & texInfo) const1279 bool VulkanCaps::isRenderable(const TextureInfo& texInfo) const {
1280     VulkanTextureInfo vkInfo;
1281     if (!texInfo.getVulkanTextureInfo(&vkInfo)) {
1282         return false;
1283     }
1284 
1285     const FormatInfo& info = this->getFormatInfo(vkInfo.fFormat);
1286     return info.isRenderable(vkInfo.fImageTiling, texInfo.numSamples());
1287 }
1288 
isStorage(const TextureInfo & texInfo) const1289 bool VulkanCaps::isStorage(const TextureInfo& texInfo) const {
1290     VulkanTextureInfo vkInfo;
1291     if (!texInfo.getVulkanTextureInfo(&vkInfo)) {
1292         return false;
1293     }
1294 
1295     const FormatInfo& info = this->getFormatInfo(vkInfo.fFormat);
1296     return info.isStorage(vkInfo.fImageTiling);
1297 }
1298 
isTransferSrc(const VulkanTextureInfo & vkInfo) const1299 bool VulkanCaps::isTransferSrc(const VulkanTextureInfo& vkInfo) const {
1300     const FormatInfo& info = this->getFormatInfo(vkInfo.fFormat);
1301     return info.isTransferSrc(vkInfo.fImageTiling);
1302 }
1303 
isTransferDst(const VulkanTextureInfo & vkInfo) const1304 bool VulkanCaps::isTransferDst(const VulkanTextureInfo& vkInfo) const {
1305     const FormatInfo& info = this->getFormatInfo(vkInfo.fFormat);
1306     return info.isTransferDst(vkInfo.fImageTiling);
1307 }
1308 
supportsWritePixels(const TextureInfo & texInfo) const1309 bool VulkanCaps::supportsWritePixels(const TextureInfo& texInfo) const {
1310     VulkanTextureInfo vkInfo;
1311     if (!texInfo.getVulkanTextureInfo(&vkInfo)) {
1312         return false;
1313     }
1314 
1315     // Can't write if it needs a YCbCr sampler
1316     if (VkFormatNeedsYcbcrSampler(vkInfo.fFormat)) {
1317         return false;
1318     }
1319 
1320     if (vkInfo.fSampleCount > 1) {
1321         return false;
1322     }
1323 
1324     if (!SkToBool(vkInfo.fImageUsageFlags & VK_IMAGE_USAGE_TRANSFER_DST_BIT)) {
1325         return false;
1326     }
1327 
1328     return true;
1329 }
1330 
supportsReadPixels(const TextureInfo & texInfo) const1331 bool VulkanCaps::supportsReadPixels(const TextureInfo& texInfo) const {
1332     if (texInfo.isProtected() == Protected::kYes) {
1333         return false;
1334     }
1335 
1336     VulkanTextureInfo vkInfo;
1337     if (!texInfo.getVulkanTextureInfo(&vkInfo)) {
1338         return false;
1339     }
1340 
1341     // Can't read if it needs a YCbCr sampler
1342     if (VkFormatNeedsYcbcrSampler(vkInfo.fFormat)) {
1343         return false;
1344     }
1345 
1346     if (VkFormatIsCompressed(vkInfo.fFormat)) {
1347         return false;
1348     }
1349 
1350     if (vkInfo.fSampleCount > 1) {
1351         return false;
1352     }
1353 
1354     if (!SkToBool(vkInfo.fImageUsageFlags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT)) {
1355         return false;
1356     }
1357 
1358     return true;
1359 }
1360 
supportedWritePixelsColorType(SkColorType dstColorType,const TextureInfo & dstTextureInfo,SkColorType srcColorType) const1361 std::pair<SkColorType, bool /*isRGBFormat*/> VulkanCaps::supportedWritePixelsColorType(
1362         SkColorType dstColorType,
1363         const TextureInfo& dstTextureInfo,
1364         SkColorType srcColorType) const {
1365     VulkanTextureInfo vkInfo;
1366     if (!dstTextureInfo.getVulkanTextureInfo(&vkInfo)) {
1367         return {kUnknown_SkColorType, false};
1368     }
1369 
1370     // Can't write to YCbCr formats
1371     // TODO: Can't write to external formats, either
1372     if (VkFormatNeedsYcbcrSampler(vkInfo.fFormat)) {
1373         return {kUnknown_SkColorType, false};
1374     }
1375 
1376     const FormatInfo& info = this->getFormatInfo(vkInfo.fFormat);
1377     for (int i = 0; i < info.fColorTypeInfoCount; ++i) {
1378         const auto& ctInfo = info.fColorTypeInfos[i];
1379         if (ctInfo.fColorType == dstColorType) {
1380             return {ctInfo.fTransferColorType, vkInfo.fFormat == VK_FORMAT_R8G8B8_UNORM};
1381         }
1382     }
1383 
1384     return {kUnknown_SkColorType, false};
1385 }
1386 
supportedReadPixelsColorType(SkColorType srcColorType,const TextureInfo & srcTextureInfo,SkColorType dstColorType) const1387 std::pair<SkColorType, bool /*isRGBFormat*/> VulkanCaps::supportedReadPixelsColorType(
1388         SkColorType srcColorType,
1389         const TextureInfo& srcTextureInfo,
1390         SkColorType dstColorType) const {
1391     VulkanTextureInfo vkInfo;
1392     if (!srcTextureInfo.getVulkanTextureInfo(&vkInfo)) {
1393         return {kUnknown_SkColorType, false};
1394     }
1395 
1396     // Can't read from YCbCr formats
1397     // TODO: external formats?
1398     if (VkFormatNeedsYcbcrSampler(vkInfo.fFormat)) {
1399         return {kUnknown_SkColorType, false};
1400     }
1401 
1402     // TODO: handle compressed formats
1403     if (VkFormatIsCompressed(vkInfo.fFormat)) {
1404         SkASSERT(this->isTexturable(vkInfo));
1405         return {kUnknown_SkColorType, false};
1406     }
1407 
1408     const FormatInfo& info = this->getFormatInfo(vkInfo.fFormat);
1409     for (int i = 0; i < info.fColorTypeInfoCount; ++i) {
1410         const auto& ctInfo = info.fColorTypeInfos[i];
1411         if (ctInfo.fColorType == srcColorType) {
1412             return {ctInfo.fTransferColorType, vkInfo.fFormat == VK_FORMAT_R8G8B8_UNORM};
1413         }
1414     }
1415 
1416     return {kUnknown_SkColorType, false};
1417 }
1418 
makeGraphicsPipelineKey(const GraphicsPipelineDesc & pipelineDesc,const RenderPassDesc & renderPassDesc) const1419 UniqueKey VulkanCaps::makeGraphicsPipelineKey(const GraphicsPipelineDesc& pipelineDesc,
1420                                               const RenderPassDesc& renderPassDesc) const {
1421     UniqueKey pipelineKey;
1422     {
1423         static const skgpu::UniqueKey::Domain kGraphicsPipelineDomain =
1424             UniqueKey::GenerateDomain();
1425 
1426         VulkanRenderPass::VulkanRenderPassMetaData rpMetaData {renderPassDesc};
1427 
1428         // Reserve 3 uint32s for the render step id, paint id, and write swizzle.
1429         static constexpr int kUint32sNeededForPipelineInfo = 3;
1430         // The uint32s needed for a RenderPass is variable number, so consult rpMetaData to
1431         // determine how many to reserve.
1432         UniqueKey::Builder builder(&pipelineKey,
1433                                    kGraphicsPipelineDomain,
1434                                    kUint32sNeededForPipelineInfo + rpMetaData.fUint32DataCnt,
1435                                    "GraphicsPipeline");
1436 
1437         int idx = 0;
1438         // Add GraphicsPipelineDesc information
1439         builder[idx++] = pipelineDesc.renderStepID();
1440         builder[idx++] = pipelineDesc.paintParamsID().asUInt();
1441         // Add RenderPass info relevant for pipeline creation that's not captured in RenderPass keys
1442         builder[idx++] = renderPassDesc.fWriteSwizzle.asKey();
1443         // Add RenderPassDesc information
1444         VulkanRenderPass::AddRenderPassInfoToKey(rpMetaData, builder, idx, /*compatibleOnly=*/true);
1445 
1446         builder.finish();
1447     }
1448 
1449     return pipelineKey;
1450 }
1451 
makeSamplerKey(const SamplerDesc & samplerDesc) const1452 GraphiteResourceKey VulkanCaps::makeSamplerKey(const SamplerDesc& samplerDesc) const {
1453     GraphiteResourceKey samplerKey;
1454     // Non-zero conversion information means the sampler utilizes a ycbcr conversion.
1455     uint32_t nonFormatYcbcrInfo =
1456             (uint32_t)(samplerDesc.desc() >> SamplerDesc::kImmutableSamplerInfoShift);
1457     bool usesYcbcrConversion = nonFormatYcbcrInfo != 0;
1458 
1459     int uint32Quantity = 1;
1460     bool usesExternalFormat = false;
1461     if (usesYcbcrConversion) {
1462         // If using a YCbCr conversion, check nonFormatYcbcrInfo to see if we are using an external
1463         // format and update uint32Quantity accordingly.
1464         usesExternalFormat = static_cast<bool>(
1465                 ((nonFormatYcbcrInfo & ycbcrPackaging::kUseExternalFormatMask) >>
1466                         ycbcrPackaging::kUsesExternalFormatShift));
1467         // Reassign uint32Quantity. This is an assignment instead of an additive operation because
1468         // non-format ycbcr information and sampler information cam be fit into just one int32.
1469         uint32Quantity = usesExternalFormat ? ycbcrPackaging::kInt32sNeededExternalFormat
1470                                             : ycbcrPackaging::kInt32sNeededKnownFormat;
1471     }
1472     static const ResourceType kSamplerType = GraphiteResourceKey::GenerateResourceType();
1473     GraphiteResourceKey::Builder builder(&samplerKey, kSamplerType, uint32Quantity,
1474                                          Shareable::kYes);
1475     int i = 0;
1476     builder[i++] = samplerDesc.desc();
1477     if (usesYcbcrConversion) {
1478         if (usesExternalFormat) {
1479             builder[i++] = samplerDesc.externalFormatMSBs();
1480         }
1481         builder[i++] = samplerDesc.format();
1482     }
1483     SkASSERT(i == uint32Quantity);
1484 
1485     builder.finish();
1486     return samplerKey;
1487 }
1488 
buildKeyForTexture(SkISize dimensions,const TextureInfo & info,ResourceType type,Shareable shareable,GraphiteResourceKey * key) const1489 void VulkanCaps::buildKeyForTexture(SkISize dimensions,
1490                                     const TextureInfo& info,
1491                                     ResourceType type,
1492                                     Shareable shareable,
1493                                     GraphiteResourceKey* key) const {
1494     SkASSERT(!dimensions.isEmpty());
1495 
1496     const VulkanTextureSpec& vkSpec = info.vulkanTextureSpec();
1497     // We expect that the VkFormat enum is at most a 32-bit value.
1498     static_assert(VK_FORMAT_MAX_ENUM == 0x7FFFFFFF);
1499     // We should either be using a known VkFormat or have a valid ycbcr conversion.
1500     SkASSERT(vkSpec.fFormat != VK_FORMAT_UNDEFINED || vkSpec.fYcbcrConversionInfo.isValid());
1501 
1502     uint32_t format = static_cast<uint32_t>(vkSpec.fFormat);
1503     uint32_t samples = SamplesToKey(info.numSamples());
1504     // We don't have to key the number of mip levels because it is inherit in the combination of
1505     // isMipped and dimensions.
1506     bool isMipped = info.mipmapped() == Mipmapped::kYes;
1507     Protected isProtected = info.isProtected();
1508 
1509     // Confirm all the below parts of the key can fit in a single uint32_t. The sum of the shift
1510     // amounts in the asserts must be less than or equal to 32. vkSpec.fFlags will go into its
1511     // own 32-bit block.
1512     SkASSERT(samples                            < (1u << 3));  // sample key is first 3 bits
1513     SkASSERT(static_cast<uint32_t>(isMipped)    < (1u << 1));  // isMapped is 4th bit
1514     SkASSERT(static_cast<uint32_t>(isProtected) < (1u << 1));  // isProtected is 5th bit
1515     SkASSERT(vkSpec.fImageTiling                < (1u << 1));  // imageTiling is 6th bit
1516     SkASSERT(vkSpec.fSharingMode                < (1u << 1));  // sharingMode is 7th bit
1517     SkASSERT(vkSpec.fAspectMask                 < (1u << 11)); // aspectMask is bits 8 - 19
1518     SkASSERT(vkSpec.fImageUsageFlags            < (1u << 12)); // imageUsageFlags are bits 20-32
1519 
1520     // We need two uint32_ts for dimensions, 1 for format, and 2 for the rest of the information.
1521     static constexpr int kNum32DataCntNoYcbcr =  2 + 1 + 2;
1522     int num32DataCnt = kNum32DataCntNoYcbcr;
1523 
1524     // If a texture w/ an external format is being used, that information must also be appended.
1525     const VulkanYcbcrConversionInfo& ycbcrInfo = info.vulkanTextureSpec().fYcbcrConversionInfo;
1526     num32DataCnt += ycbcrPackaging::numInt32sNeeded(ycbcrInfo);
1527 
1528     GraphiteResourceKey::Builder builder(key, type, num32DataCnt, shareable);
1529 
1530     int i = 0;
1531     builder[i++] = dimensions.width();
1532     builder[i++] = dimensions.height();
1533 
1534     if (ycbcrInfo.isValid()) {
1535         SkASSERT(ycbcrInfo.fFormat != VK_FORMAT_UNDEFINED || ycbcrInfo.fExternalFormat != 0);
1536         bool useExternalFormat = ycbcrInfo.fFormat == VK_FORMAT_UNDEFINED;
1537         builder[i++] = ycbcrPackaging::nonFormatInfoAsUInt32(ycbcrInfo);
1538         if (useExternalFormat) {
1539             builder[i++] = (uint32_t)ycbcrInfo.fExternalFormat;
1540             builder[i++] = (uint32_t)(ycbcrInfo.fExternalFormat >> 32);
1541         } else {
1542             builder[i++] =  ycbcrInfo.fFormat;
1543         }
1544     } else {
1545         builder[i++] = format;
1546     }
1547 
1548     builder[i++] = (static_cast<uint32_t>(vkSpec.fFlags));
1549     builder[i++] = (samples                                            << 0 ) |
1550                    (static_cast<uint32_t>(isMipped)                    << 3 ) |
1551                    (static_cast<uint32_t>(isProtected)                 << 4 ) |
1552                    (static_cast<uint32_t>(vkSpec.fImageTiling)         << 5 ) |
1553                    (static_cast<uint32_t>(vkSpec.fSharingMode)         << 6 ) |
1554                    (static_cast<uint32_t>(vkSpec.fAspectMask)          << 7 ) |
1555                    (static_cast<uint32_t>(vkSpec.fImageUsageFlags)     << 19);
1556     SkASSERT(i == num32DataCnt);
1557 }
1558 
getImmutableSamplerInfo(sk_sp<TextureProxy> proxy) const1559 ImmutableSamplerInfo VulkanCaps::getImmutableSamplerInfo(sk_sp<TextureProxy> proxy) const {
1560     if (proxy) {
1561         const skgpu::VulkanYcbcrConversionInfo& ycbcrConversionInfo =
1562                 proxy->textureInfo().vulkanTextureSpec().fYcbcrConversionInfo;
1563 
1564         if (ycbcrConversionInfo.isValid()) {
1565             ImmutableSamplerInfo immutableSamplerInfo;
1566             // ycbcrConversionInfo's fFormat being VK_FORMAT_UNDEFINED indicates we are using an
1567             // external format rather than a known VkFormat.
1568             immutableSamplerInfo.fFormat = ycbcrConversionInfo.fFormat == VK_FORMAT_UNDEFINED
1569                     ? ycbcrConversionInfo.fExternalFormat
1570                     : ycbcrConversionInfo.fFormat;
1571             immutableSamplerInfo.fNonFormatYcbcrConversionInfo =
1572                     ycbcrPackaging::nonFormatInfoAsUInt32(ycbcrConversionInfo);
1573             return immutableSamplerInfo;
1574         }
1575     }
1576 
1577     // If the proxy is null or the YCbCr conversion for that proxy is invalid, then return a
1578     // default ImmutableSamplerInfo struct.
1579     return {};
1580 }
1581 
1582 } // namespace skgpu::graphite
1583