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