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