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