Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
VulkanCaps.cpp
Go to the documentation of this file.
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
9
25
26#ifdef SK_BUILD_FOR_ANDROID
27#include <sys/system_properties.h>
28#endif
29
30namespace skgpu::graphite {
31
33 const skgpu::VulkanInterface* vkInterface,
34 VkPhysicalDevice physDev,
35 uint32_t physicalDeviceVersion,
36 const VkPhysicalDeviceFeatures2* features,
37 const skgpu::VulkanExtensions* extensions,
38 Protected isProtected)
39 : Caps() {
40 this->init(contextOptions, vkInterface, physDev, physicalDeviceVersion, features, extensions,
41 isProtected);
42}
43
45
46void VulkanCaps::init(const ContextOptions& contextOptions,
47 const skgpu::VulkanInterface* vkInterface,
48 VkPhysicalDevice physDev,
49 uint32_t physicalDeviceVersion,
50 const VkPhysicalDeviceFeatures2* features,
51 const skgpu::VulkanExtensions* extensions,
52 Protected isProtected) {
53 VkPhysicalDeviceProperties physDevProperties;
54 VULKAN_CALL(vkInterface, GetPhysicalDeviceProperties(physDev, &physDevProperties));
55
56#if defined(GRAPHITE_TEST_UTILS)
57 this->setDeviceName(physDevProperties.deviceName);
58#endif
59
60 // Graphite requires Vulkan version 1.1 or later, which always has protected support.
61 if (isProtected == Protected::kYes) {
62 fProtectedSupport = true;
63 fShouldAlwaysUseDedicatedImageMemory = true;
64 }
65
66 fPhysicalDeviceMemoryProperties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2;
67 fPhysicalDeviceMemoryProperties2.pNext = nullptr;
68 VULKAN_CALL(vkInterface,
69 GetPhysicalDeviceMemoryProperties2(physDev, &fPhysicalDeviceMemoryProperties2));
70
71 // We could actually query and get a max size for each config, however maxImageDimension2D will
72 // give the minimum max size across all configs. So for simplicity we will use that for now.
73 fMaxTextureSize = std::min(physDevProperties.limits.maxImageDimension2D, (uint32_t)INT_MAX);
74
78
80 // TODO(skia:14639): We cannot use std430 layout for SSBOs until SkSL gracefully handles
81 // implicit array stride.
85
86 VkPhysicalDeviceMemoryProperties deviceMemoryProperties;
87 VULKAN_CALL(vkInterface, GetPhysicalDeviceMemoryProperties(physDev, &deviceMemoryProperties));
88 fSupportsMemorylessAttachments = false;
91 // If we have a protected context we can only use memoryless images if they also support
92 // being protected. With current devices we don't actually expect this combination to be
93 // supported, but this at least covers us for future devices that may allow it.
94 requiredLazyFlags |= VK_MEMORY_PROPERTY_PROTECTED_BIT;
95 }
96 for (uint32_t i = 0; i < deviceMemoryProperties.memoryTypeCount; ++i) {
97 if (deviceMemoryProperties.memoryTypes[i].propertyFlags & requiredLazyFlags) {
98 fSupportsMemorylessAttachments = true;
99 }
100 }
101
102#ifdef SK_BUILD_FOR_UNIX
103 if (kNvidia_VkVendor == physDevProperties.vendorID) {
104 // On NVIDIA linux we see a big perf regression when not using dedicated image allocations.
105 fShouldAlwaysUseDedicatedImageMemory = true;
106 }
107#endif
108
109 if (physDevProperties.vendorID == kNvidia_VkVendor ||
110 physDevProperties.vendorID == kAMD_VkVendor) {
111 // On discrete GPUs, it can be faster to read gpu-only memory compared to memory that is
112 // also mappable on the host.
113 fGpuOnlyBuffersMorePerformant = true;
114
115 // On discrete GPUs we try to use special DEVICE_LOCAL and HOST_VISIBLE memory for our
116 // cpu write, gpu read buffers. This memory is not ideal to be kept persistently mapped.
117 // Some discrete GPUs do not expose this special memory, however we still disable
118 // persistently mapped buffers for all of them since most GPUs with updated drivers do
119 // expose it. If this becomes an issue we can try to be more fine grained.
120 fShouldPersistentlyMapCpuToGpuBuffers = false;
121 }
122
123 this->initFormatTable(vkInterface, physDev, physDevProperties);
124 this->initDepthStencilFormatTable(vkInterface, physDev, physDevProperties);
125
126 if (!contextOptions.fDisableDriverCorrectnessWorkarounds) {
127 this->applyDriverCorrectnessWorkarounds(physDevProperties);
128 }
129
130 if (physDevProperties.vendorID == kAMD_VkVendor) {
131 // AMD advertises support for MAX_UINT vertex attributes but in reality only supports 32.
132 fMaxVertexAttributes = 32;
133 } else {
134 fMaxVertexAttributes = physDevProperties.limits.maxVertexInputAttributes;
135 }
136 fMaxUniformBufferRange = physDevProperties.limits.maxUniformBufferRange;
137
138#ifdef SK_BUILD_FOR_ANDROID
139 if (extensions->hasExtension(
142 }
143#endif
144
145 // Determine whether the client enabled certain physical device features.
146 if (features) {
147 auto ycbcrFeatures =
148 skgpu::GetExtensionFeatureStruct<VkPhysicalDeviceSamplerYcbcrConversionFeatures>(
149 *features,
151 if (ycbcrFeatures && ycbcrFeatures->samplerYcbcrConversion) {
152 fSupportsYcbcrConversion = true;
153 }
154 }
155
156 if (extensions->hasExtension(VK_EXT_DEVICE_FAULT_EXTENSION_NAME, 1)) {
157 fSupportsDeviceFaultInfo = true;
158 }
159
160 this->finishInitialization(contextOptions);
161}
162
163void VulkanCaps::applyDriverCorrectnessWorkarounds(const VkPhysicalDeviceProperties& properties) {
164 // By default, we initialize the Android API version to 0 since we consider certain things
165 // "fixed" only once above a certain version. This way, we default to enabling the workarounds.
166 int androidAPIVersion = 0;
167#if defined(SK_BUILD_FOR_ANDROID)
168 char androidAPIVersionStr[PROP_VALUE_MAX];
169 int strLength = __system_property_get("ro.build.version.sdk", androidAPIVersionStr);
170 // Defaults to zero since most checks care if it is greater than a specific value. So this will
171 // just default to it being less.
172 androidAPIVersion = (strLength == 0) ? 0 : atoi(androidAPIVersionStr);
173#endif
174
175 // On Mali galaxy s7 we see lots of rendering issues when we suballocate VkImages.
176 if (kARM_VkVendor == properties.vendorID && androidAPIVersion <= 28) {
177 fShouldAlwaysUseDedicatedImageMemory = true;
178 }
179}
180
181// These are all the valid VkFormats that we support in Skia. They are roughly ordered from most
182// frequently used to least to improve look up times in arrays.
207// These are all the valid depth/stencil formats that we support in Skia.
213
215 Mipmapped mipmapped,
216 Protected isProtected,
217 Renderable isRenderable) const {
218 VkFormat format = this->getFormatFromColorType(ct);
219 const FormatInfo& formatInfo = this->getFormatInfo(format);
220 static constexpr int defaultSampleCount = 1;
221 if ((isProtected == Protected::kYes && !this->protectedSupport()) ||
222 !formatInfo.isTexturable(VK_IMAGE_TILING_OPTIMAL) ||
223 (isRenderable == Renderable::kYes &&
224 !formatInfo.isRenderable(VK_IMAGE_TILING_OPTIMAL, defaultSampleCount)) ) {
225 return {};
226 }
227
229 info.fSampleCount = defaultSampleCount;
230 info.fMipmapped = mipmapped;
231 info.fFlags = (isProtected == Protected::kYes) ? VK_IMAGE_CREATE_PROTECTED_BIT : 0;
232 info.fFormat = format;
233 info.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
234 info.fImageUsageFlags = VK_IMAGE_USAGE_SAMPLED_BIT |
237 if (isRenderable == Renderable::kYes) {
238 // We make all renderable images support being used as input attachment
239 info.fImageUsageFlags = info.fImageUsageFlags |
242 }
243 info.fSharingMode = VK_SHARING_MODE_EXCLUSIVE;
244 info.fAspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
245
246 return info;
247}
248
250 Mipmapped mipmapped) const {
252 if (!textureInfo.getVulkanTextureInfo(&info)) {
253 return {};
254 }
255
256 info.fSampleCount = 1;
257 info.fMipmapped = mipmapped;
258 info.fFlags = (textureInfo.fProtected == Protected::kYes) ? VK_IMAGE_CREATE_PROTECTED_BIT : 0;
259 info.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
262 info.fSharingMode = VK_SHARING_MODE_EXCLUSIVE;
263
264 return info;
265}
266
267namespace {
268VkFormat format_from_compression(SkTextureCompressionType compression) {
269 switch (compression) {
276 default:
277 return VK_FORMAT_UNDEFINED;
278 }
279}
280}
281
283 Mipmapped mipmapped,
284 Protected isProtected) const {
285 VkFormat format = format_from_compression(compression);
286 const FormatInfo& formatInfo = this->getFormatInfo(format);
287 static constexpr int defaultSampleCount = 1;
288 if ((isProtected == Protected::kYes && !this->protectedSupport()) ||
289 !formatInfo.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
290 return {};
291 }
292
294 info.fSampleCount = defaultSampleCount;
295 info.fMipmapped = mipmapped;
296 info.fFlags = (isProtected == Protected::kYes) ? VK_IMAGE_CREATE_PROTECTED_BIT : 0;
297 info.fFormat = format;
298 info.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
299 info.fImageUsageFlags = VK_IMAGE_USAGE_SAMPLED_BIT |
302 info.fSharingMode = VK_SHARING_MODE_EXCLUSIVE;
303 info.fAspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
304
305 return info;
306}
307
309 Discardable discardable) const {
310 if (fDefaultMSAASamples <= 1) {
311 return {};
312 }
313
314 const VkFormat singleSpecFormat = singleSampledInfo.vulkanTextureSpec().fFormat;
315 const FormatInfo& formatInfo = this->getFormatInfo(singleSpecFormat);
316 if ((singleSampledInfo.isProtected() == Protected::kYes && !this->protectedSupport()) ||
317 !formatInfo.isRenderable(VK_IMAGE_TILING_OPTIMAL, fDefaultMSAASamples)) {
318 return {};
319 }
320
323 info.fMipmapped = Mipmapped::kNo;
324 info.fFlags = (singleSampledInfo.isProtected() == Protected::kYes) ?
326 info.fFormat = singleSpecFormat;
327 info.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
328
329 /**
330 * Graphite, unlike ganesh, does not require a dedicated MSAA attachment on every surface.
331 * MSAA textures now get resolved within the scope of a render pass, which can be done simply
332 * with the color attachment usage flag. So we no longer require transfer src/dst usage flags.
333 */
335 if (discardable == Discardable::kYes && fSupportsMemorylessAttachments) {
337 }
338
339 info.fImageUsageFlags = flags;
340 info.fSharingMode = VK_SHARING_MODE_EXCLUSIVE;
341 info.fAspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
342
343 return info;
344}
345
347 uint32_t sampleCount,
348 Protected isProtected) const {
349 VkFormat format = this->getFormatFromDepthStencilFlags(flags);
350 const DepthStencilFormatInfo& formatInfo = this->getDepthStencilFormatInfo(format);
351 if ( (isProtected == Protected::kYes && !this->protectedSupport()) ||
352 !formatInfo.isDepthStencilSupported(formatInfo.fFormatProperties.optimalTilingFeatures) ||
353 !formatInfo.fSupportedSampleCounts.isSampleCountSupported(sampleCount)) {
354 return {};
355 }
356
358 info.fSampleCount = sampleCount;
359 info.fMipmapped = Mipmapped::kNo;
360 info.fFlags = (isProtected == Protected::kYes) ? VK_IMAGE_CREATE_PROTECTED_BIT : 0;
361 info.fFormat = format;
362 info.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
363 // TODO: Passing in a discardable flag to this method, and if true, add the TRANSIENT bit.
365 info.fSharingMode = VK_SHARING_MODE_EXCLUSIVE;
366 info.fAspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
367
368 return info;
369}
370
372 VkFormat format = this->getFormatFromColorType(colorType);
373 const FormatInfo& formatInfo = this->getFormatInfo(format);
374 if (!formatInfo.isTexturable(VK_IMAGE_TILING_OPTIMAL) ||
375 !formatInfo.isStorage(VK_IMAGE_TILING_OPTIMAL)) {
376 return {};
377 }
378
380 info.fSampleCount = 1;
381 info.fMipmapped = Mipmapped::kNo;
382 info.fFlags = 0;
383 info.fFormat = format;
384 info.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
385 // Storage textures are currently always sampleable from a shader
386 info.fImageUsageFlags = VK_IMAGE_USAGE_STORAGE_BIT |
389 info.fSharingMode = VK_SHARING_MODE_EXCLUSIVE;
390 info.fAspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
391
392 return info;
393}
394
395uint32_t VulkanCaps::channelMask(const TextureInfo& textureInfo) const {
396 return skgpu::VkFormatChannels(textureInfo.vulkanTextureSpec().fFormat);
397}
398
399void VulkanCaps::initFormatTable(const skgpu::VulkanInterface* interface,
400 VkPhysicalDevice physDev,
401 const VkPhysicalDeviceProperties& properties) {
402 static_assert(std::size(kVkFormats) == VulkanCaps::kNumVkFormats,
403 "Size of VkFormats array must match static value in header");
404
405 std::fill_n(fColorTypeToFormatTable, kSkColorTypeCnt, VK_FORMAT_UNDEFINED);
406
407 // Go through all the formats and init their support surface and data ColorTypes.
408 // Format: VK_FORMAT_R8G8B8A8_UNORM
409 {
411 auto& info = this->getFormatInfo(format);
412 info.init(interface, physDev, properties, format);
413 if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
414 info.fColorTypeInfoCount = 2;
415 info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
416 int ctIdx = 0;
417 // Format: VK_FORMAT_R8G8B8A8_UNORM, Surface: kRGBA_8888
418 {
420 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
421 ctInfo.fColorType = ct;
422 ctInfo.fTransferColorType = ct;
423 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
424 }
425 // Format: VK_FORMAT_R8G8B8A8_UNORM, Surface: kRGB_888x
426 {
428 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
429 ctInfo.fColorType = ct;
430 ctInfo.fTransferColorType = ct;
431 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag;
432 ctInfo.fReadSwizzle = skgpu::Swizzle::RGB1();
433 }
434 }
435 }
436
437 // Format: VK_FORMAT_R8_UNORM
438 {
440 auto& info = this->getFormatInfo(format);
441 info.init(interface, physDev, properties, format);
442 if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
443 info.fColorTypeInfoCount = 3;
444 info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
445 int ctIdx = 0;
446 // Format: VK_FORMAT_R8_UNORM, Surface: kR_8
447 {
449 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
450 ctInfo.fColorType = ct;
451 ctInfo.fTransferColorType = ct;
452 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
453 }
454 // Format: VK_FORMAT_R8_UNORM, Surface: kAlpha_8
455 {
457 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
458 ctInfo.fColorType = ct;
459 ctInfo.fTransferColorType = ct;
460 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
461 ctInfo.fReadSwizzle = skgpu::Swizzle("000r");
462 ctInfo.fWriteSwizzle = skgpu::Swizzle("a000");
463 }
464 // Format: VK_FORMAT_R8_UNORM, Surface: kGray_8
465 {
467 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
468 ctInfo.fColorType = ct;
469 ctInfo.fTransferColorType = ct;
470 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag;
471 ctInfo.fReadSwizzle = skgpu::Swizzle("rrr1");
472 }
473 }
474 }
475
476 // Format: VK_FORMAT_B8G8R8A8_UNORM
477 {
479 auto& info = this->getFormatInfo(format);
480 info.init(interface, physDev, properties, format);
481 if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
482 info.fColorTypeInfoCount = 1;
483 info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
484 int ctIdx = 0;
485 // Format: VK_FORMAT_B8G8R8A8_UNORM, Surface: kBGRA_8888
486 {
488 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
489 ctInfo.fColorType = ct;
490 ctInfo.fTransferColorType = ct;
491 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
492 }
493 }
494 }
495 // Format: VK_FORMAT_R5G6B5_UNORM_PACK16
496 {
498 auto& info = this->getFormatInfo(format);
499 info.init(interface, physDev, properties, format);
500 if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
501 info.fColorTypeInfoCount = 1;
502 info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
503 int ctIdx = 0;
504 // Format: VK_FORMAT_R5G6B5_UNORM_PACK16, Surface: kRGB_565_SkColorType
505 {
507 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
508 ctInfo.fColorType = ct;
509 ctInfo.fTransferColorType = ct;
510 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
511 }
512 }
513 }
514 // Format: VK_FORMAT_R16G16B16A16_SFLOAT
515 {
517 auto& info = this->getFormatInfo(format);
518 info.init(interface, physDev, properties, format);
519 if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
520 info.fColorTypeInfoCount = 2;
521 info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
522 int ctIdx = 0;
523 // Format: VK_FORMAT_R16G16B16A16_SFLOAT, Surface: SkColorType::kRGBA_F16_SkColorType
524 {
526 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
527 ctInfo.fColorType = ct;
528 ctInfo.fTransferColorType = ct;
529 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
530 }
531 }
532 }
533 // Format: VK_FORMAT_R16_SFLOAT
534 {
536 auto& info = this->getFormatInfo(format);
537 info.init(interface, physDev, properties, format);
538 if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
539 info.fColorTypeInfoCount = 1;
540 info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
541 int ctIdx = 0;
542 // Format: VK_FORMAT_R16_SFLOAT, Surface: kAlpha_F16
543 {
545 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
546 ctInfo.fColorType = ct;
547 ctInfo.fTransferColorType = ct;
548 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
549 ctInfo.fReadSwizzle = skgpu::Swizzle("000r");
550 ctInfo.fWriteSwizzle = skgpu::Swizzle("a000");
551 }
552 }
553 }
554 // Format: VK_FORMAT_R8G8B8_UNORM
555 {
557 auto& info = this->getFormatInfo(format);
558 info.init(interface, physDev, properties, format);
559 if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
560 info.fColorTypeInfoCount = 1;
561 info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
562 int ctIdx = 0;
563 // Format: VK_FORMAT_R8G8B8_UNORM, Surface: kRGB_888x
564 {
566 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
567 ctInfo.fColorType = ct;
568 // This SkColorType is a lie, but we don't have a kRGB_888_SkColorType. The Vulkan
569 // format is 3 bpp so we must manualy convert to/from this and kRGB_888x when doing
570 // transfers. We signal this need for manual conversions in the
571 // supportedRead/WriteColorType calls.
572 ctInfo.fTransferColorType = SkColorType::kRGB_888x_SkColorType;
573 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
574 }
575 }
576 }
577 // Format: VK_FORMAT_R8G8_UNORM
578 {
580 auto& info = this->getFormatInfo(format);
581 info.init(interface, physDev, properties, format);
582 if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
583 info.fColorTypeInfoCount = 1;
584 info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
585 int ctIdx = 0;
586 // Format: VK_FORMAT_R8G8_UNORM, Surface: kR8G8_unorm
587 {
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 }
595 }
596 // Format: VK_FORMAT_A2B10G10R10_UNORM_PACK32
597 {
599 auto& info = this->getFormatInfo(format);
600 info.init(interface, physDev, properties, format);
601 if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
602 info.fColorTypeInfoCount = 1;
603 info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
604 int ctIdx = 0;
605 // Format: VK_FORMAT_A2B10G10R10_UNORM_PACK32, Surface: kRGBA_1010102
606 {
608 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
609 ctInfo.fColorType = ct;
610 ctInfo.fTransferColorType = ct;
611 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
612 }
613 }
614 }
615 // Format: VK_FORMAT_A2R10G10B10_UNORM_PACK32
616 {
618 auto& info = this->getFormatInfo(format);
619 info.init(interface, physDev, properties, format);
620 if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
621 info.fColorTypeInfoCount = 1;
622 info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
623 int ctIdx = 0;
624 // Format: VK_FORMAT_A2R10G10B10_UNORM_PACK32, Surface: kBGRA_1010102
625 {
627 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
628 ctInfo.fColorType = ct;
629 ctInfo.fTransferColorType = ct;
630 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
631 }
632 }
633 }
634 // Format: VK_FORMAT_B4G4R4A4_UNORM_PACK16
635 {
637 auto& info = this->getFormatInfo(format);
638 info.init(interface, physDev, properties, format);
639 if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
640 info.fColorTypeInfoCount = 1;
641 info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
642 int ctIdx = 0;
643 // Format: VK_FORMAT_B4G4R4A4_UNORM_PACK16, Surface: kARGB_4444_SkColorType
644 {
646 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
647 ctInfo.fColorType = ct;
648 ctInfo.fTransferColorType = ct;
649 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
650 ctInfo.fReadSwizzle = skgpu::Swizzle::BGRA();
651 ctInfo.fWriteSwizzle = skgpu::Swizzle::BGRA();
652 }
653 }
654 }
655
656 // Format: VK_FORMAT_R4G4B4A4_UNORM_PACK16
657 {
659 auto& info = this->getFormatInfo(format);
660 info.init(interface, physDev, properties, format);
661 if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
662 info.fColorTypeInfoCount = 1;
663 info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
664 int ctIdx = 0;
665 // Format: VK_FORMAT_R4G4B4A4_UNORM_PACK16, Surface: kARGB_4444_SkColorType
666 {
668 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
669 ctInfo.fColorType = ct;
670 ctInfo.fTransferColorType = ct;
671 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
672 }
673 }
674 }
675 // Format: VK_FORMAT_R8G8B8A8_SRGB
676 {
678 auto& info = this->getFormatInfo(format);
679 info.init(interface, physDev, properties, format);
680 if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
681 info.fColorTypeInfoCount = 1;
682 info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
683 int ctIdx = 0;
684 // Format: VK_FORMAT_R8G8B8A8_SRGB, Surface: kRGBA_8888_SRGB
685 {
687 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
688 ctInfo.fColorType = ct;
689 ctInfo.fTransferColorType = ct;
690 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
691 }
692 }
693 }
694 // Format: VK_FORMAT_R16_UNORM
695 {
697 auto& info = this->getFormatInfo(format);
698 info.init(interface, physDev, properties, format);
699 if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
700 info.fColorTypeInfoCount = 1;
701 info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
702 int ctIdx = 0;
703 // Format: VK_FORMAT_R16_UNORM, Surface: kAlpha_16
704 {
706 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
707 ctInfo.fColorType = ct;
708 ctInfo.fTransferColorType = ct;
709 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
710 ctInfo.fReadSwizzle = skgpu::Swizzle("000r");
711 ctInfo.fWriteSwizzle = skgpu::Swizzle("a000");
712 }
713 }
714 }
715 // Format: VK_FORMAT_R16G16_UNORM
716 {
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_R16G16_UNORM, Surface: kRG_1616
725 {
727 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
728 ctInfo.fColorType = ct;
729 ctInfo.fTransferColorType = ct;
730 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
731 }
732 }
733 }
734 // Format: VK_FORMAT_R16G16B16A16_UNORM
735 {
737 auto& info = this->getFormatInfo(format);
738 info.init(interface, physDev, properties, format);
739 if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
740 info.fColorTypeInfoCount = 1;
741 info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
742 int ctIdx = 0;
743 // Format: VK_FORMAT_R16G16B16A16_UNORM, Surface: kRGBA_16161616
744 {
746 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
747 ctInfo.fColorType = ct;
748 ctInfo.fTransferColorType = ct;
749 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
750 }
751 }
752 }
753 // Format: VK_FORMAT_R16G16_SFLOAT
754 {
756 auto& info = this->getFormatInfo(format);
757 info.init(interface, physDev, properties, format);
758 if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
759 info.fColorTypeInfoCount = 1;
760 info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
761 int ctIdx = 0;
762 // Format: VK_FORMAT_R16G16_SFLOAT, Surface: kRG_F16
763 {
765 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
766 ctInfo.fColorType = ct;
767 ctInfo.fTransferColorType = ct;
768 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
769 }
770 }
771 }
772 // Format: VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM
773 {
775 auto& info = this->getFormatInfo(format);
776 if (fSupportsYcbcrConversion) {
777 info.init(interface, physDev, properties, format);
778 }
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_G8_B8_R8_3PLANE_420_UNORM, Surface: kRGB_888x
784 {
786 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
787 ctInfo.fColorType = ct;
788 ctInfo.fTransferColorType = ct;
789 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag;
790 }
791 SkDEBUGCODE(info.fIsWrappedOnly = true;)
792 }
793 }
794 // Format: VK_FORMAT_G8_B8R8_2PLANE_420_UNORM
795 {
797 auto& info = this->getFormatInfo(format);
798 if (fSupportsYcbcrConversion) {
799 info.init(interface, physDev, properties, format);
800 }
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_G8_B8R8_2PLANE_420_UNORM, Surface: kRGB_888x
806 {
808 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
809 ctInfo.fColorType = ct;
810 ctInfo.fTransferColorType = ct;
811 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag;
812 }
813 SkDEBUGCODE(info.fIsWrappedOnly = true;)
814 }
815 }
816 // Format: VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK
817 {
819 auto& info = this->getFormatInfo(format);
820 info.init(interface, physDev, properties, format);
821 if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
822 info.fColorTypeInfoCount = 1;
823 info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
824 int ctIdx = 0;
825 // Format: VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK, Surface: kRGB_888x
826 {
828 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
829 ctInfo.fColorType = ct;
830 ctInfo.fTransferColorType = ct;
831 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag;
832 }
833 }
834 }
835
836 // Format: VK_FORMAT_BC1_RGB_UNORM_BLOCK
837 {
839 auto& info = this->getFormatInfo(format);
840 info.init(interface, physDev, properties, format);
841 if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
842 info.fColorTypeInfoCount = 1;
843 info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
844 int ctIdx = 0;
845 // Format: VK_FORMAT_BC1_RGB_UNORM_BLOCK, Surface: kRGB_888x
846 {
848 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
849 ctInfo.fColorType = ct;
850 ctInfo.fTransferColorType = ct;
851 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag;
852 }
853 }
854 }
855
856 // Format: VK_FORMAT_BC1_RGBA_UNORM_BLOCK
857 {
859 auto& info = this->getFormatInfo(format);
860 info.init(interface, physDev, properties, format);
861 if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
862 info.fColorTypeInfoCount = 1;
863 info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
864 int ctIdx = 0;
865 // Format: VK_FORMAT_BC1_RGBA_UNORM_BLOCK, Surface: kRGB_888x
866 {
868 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
869 ctInfo.fColorType = ct;
870 ctInfo.fTransferColorType = ct;
871 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag;
872 }
873 }
874 }
875
876 ////////////////////////////////////////////////////////////////////////////
877 // Map SkColorType (used for creating Surfaces) to VkFormats. The order in which the formats are
878 // passed into the setColorType function indicates the priority in selecting which format we use
879 // for a given SkColorType.
880 typedef SkColorType ct;
881
882 this->setColorType(ct::kAlpha_8_SkColorType, { VK_FORMAT_R8_UNORM });
883 this->setColorType(ct::kRGB_565_SkColorType, { VK_FORMAT_R5G6B5_UNORM_PACK16 });
884 this->setColorType(ct::kARGB_4444_SkColorType, { VK_FORMAT_R4G4B4A4_UNORM_PACK16,
886 this->setColorType(ct::kRGBA_8888_SkColorType, { VK_FORMAT_R8G8B8A8_UNORM });
887 this->setColorType(ct::kSRGBA_8888_SkColorType, { VK_FORMAT_R8G8B8A8_SRGB });
888 this->setColorType(ct::kRGB_888x_SkColorType, { VK_FORMAT_R8G8B8_UNORM,
890 this->setColorType(ct::kR8G8_unorm_SkColorType, { VK_FORMAT_R8G8_UNORM });
891 this->setColorType(ct::kBGRA_8888_SkColorType, { VK_FORMAT_B8G8R8A8_UNORM });
892 this->setColorType(ct::kRGBA_1010102_SkColorType, { VK_FORMAT_A2B10G10R10_UNORM_PACK32 });
893 this->setColorType(ct::kBGRA_1010102_SkColorType, { VK_FORMAT_A2R10G10B10_UNORM_PACK32 });
894 this->setColorType(ct::kGray_8_SkColorType, { VK_FORMAT_R8_UNORM });
895 this->setColorType(ct::kA16_float_SkColorType, { VK_FORMAT_R16_SFLOAT });
896 this->setColorType(ct::kRGBA_F16_SkColorType, { VK_FORMAT_R16G16B16A16_SFLOAT });
897 this->setColorType(ct::kA16_unorm_SkColorType, { VK_FORMAT_R16_UNORM });
898 this->setColorType(ct::kR16G16_unorm_SkColorType, { VK_FORMAT_R16G16_UNORM });
899 this->setColorType(ct::kR16G16B16A16_unorm_SkColorType, { VK_FORMAT_R16G16B16A16_UNORM });
900 this->setColorType(ct::kR16G16_float_SkColorType, { VK_FORMAT_R16G16_SFLOAT });
901}
902
903namespace {
904void set_ds_flags_to_format(VkFormat& slot, VkFormat format) {
905 if (slot == VK_FORMAT_UNDEFINED) {
906 slot = format;
907 }
908}
909} // namespace
910
911void VulkanCaps::initDepthStencilFormatTable(const skgpu::VulkanInterface* interface,
912 VkPhysicalDevice physDev,
913 const VkPhysicalDeviceProperties& properties) {
914 static_assert(std::size(kDepthStencilVkFormats) == VulkanCaps::kNumDepthStencilVkFormats,
915 "Size of DepthStencilVkFormats array must match static value in header");
916
917 using DSFlags = SkEnumBitMask<DepthStencilFlags>;
918 constexpr DSFlags stencilFlags = DepthStencilFlags::kStencil;
919 constexpr DSFlags depthFlags = DepthStencilFlags::kDepth;
920 constexpr DSFlags dsFlags = DepthStencilFlags::kDepthStencil;
921
922 std::fill_n(fDepthStencilFlagsToFormatTable, kNumDepthStencilFlags, VK_FORMAT_UNDEFINED);
923 // Format: VK_FORMAT_S8_UINT
924 {
926 auto& info = this->getDepthStencilFormatInfo(format);
927 info.init(interface, physDev, properties, format);
928 if (info.fFormatProperties.optimalTilingFeatures &
930 set_ds_flags_to_format(fDepthStencilFlagsToFormatTable[stencilFlags.value()], format);
931 }
932 }
933 // Format: VK_FORMAT_D24_UNORM_S8_UINT
934 {
936 auto& info = this->getDepthStencilFormatInfo(format);
937 info.init(interface, physDev, properties, format);
938 if (info.fFormatProperties.optimalTilingFeatures &
940 set_ds_flags_to_format(fDepthStencilFlagsToFormatTable[stencilFlags.value()], format);
941 set_ds_flags_to_format(fDepthStencilFlagsToFormatTable[depthFlags.value()], format);
942 set_ds_flags_to_format(fDepthStencilFlagsToFormatTable[dsFlags.value()], format);
943 }
944 }
945 // Format: VK_FORMAT_D32_SFLOAT_S8_UINT
946 {
948 auto& info = this->getDepthStencilFormatInfo(format);
949 info.init(interface, physDev, properties, format);
950 if (info.fFormatProperties.optimalTilingFeatures &
952 set_ds_flags_to_format(fDepthStencilFlagsToFormatTable[stencilFlags.value()], format);
953 set_ds_flags_to_format(fDepthStencilFlagsToFormatTable[depthFlags.value()], format);
954 set_ds_flags_to_format(fDepthStencilFlagsToFormatTable[dsFlags.value()], format);
955 }
956 }
957}
958
959void VulkanCaps::SupportedSampleCounts::initSampleCounts(const skgpu::VulkanInterface* interface,
960 VkPhysicalDevice physDev,
961 const VkPhysicalDeviceProperties& physProps,
964 VkImageFormatProperties properties;
965
967 // VULKAN_CALL_RESULT requires a VulkanSharedContext for tracking DEVICE_LOST, but VulkanCaps
968 // are initialized before a VulkanSharedContext is available. The _NOCHECK variant only requires
969 // a VulkanInterface, so we can use that and log failures manually.
971 result,
972 GetPhysicalDeviceImageFormatProperties(physDev,
973 format,
976 usage,
977 0, // createFlags
978 &properties));
979 if (result != VK_SUCCESS) {
980 SKGPU_LOG_W("Vulkan call GetPhysicalDeviceImageFormatProperties failed: %d", result);
981 return;
982 }
983
986 fSampleCounts.push_back(1);
987 }
988 if (kImagination_VkVendor == physProps.vendorID) {
989 // MSAA does not work on imagination
990 return;
991 }
992 if (kIntel_VkVendor == physProps.vendorID) {
993 // MSAA doesn't work well on Intel GPUs chromium:527565, chromium:983926
994 return;
995 }
997 fSampleCounts.push_back(2);
998 }
1000 fSampleCounts.push_back(4);
1001 }
1003 fSampleCounts.push_back(8);
1004 }
1006 fSampleCounts.push_back(16);
1007 }
1008 // Standard sample locations are not defined for more than 16 samples, and we don't need more
1009 // than 16. Omit 32 and 64.
1010}
1011
1012bool VulkanCaps::SupportedSampleCounts::isSampleCountSupported(int requestedCount) const {
1013 requestedCount = std::max(1, requestedCount);
1014 for (int i = 0; i < fSampleCounts.size(); i++) {
1015 if (fSampleCounts[i] == requestedCount) {
1016 return true;
1017 } else if (requestedCount < fSampleCounts[i]) {
1018 return false;
1019 }
1020 }
1021 return false;
1022}
1023
1024
1025namespace {
1026bool is_texturable(VkFormatFeatureFlags flags) {
1029}
1030
1031bool is_renderable(VkFormatFeatureFlags flags) {
1033}
1034
1035bool is_storage(VkFormatFeatureFlags flags) {
1037}
1038
1039bool is_transfer_src(VkFormatFeatureFlags flags) {
1041}
1042
1043bool is_transfer_dst(VkFormatFeatureFlags flags) {
1045}
1046}
1047
1048void VulkanCaps::FormatInfo::init(const skgpu::VulkanInterface* interface,
1049 VkPhysicalDevice physDev,
1050 const VkPhysicalDeviceProperties& properties,
1051 VkFormat format) {
1052 memset(&fFormatProperties, 0, sizeof(VkFormatProperties));
1053 VULKAN_CALL(interface, GetPhysicalDeviceFormatProperties(physDev, format, &fFormatProperties));
1054
1055 if (is_renderable(fFormatProperties.optimalTilingFeatures)) {
1056 // We make all renderable images support being used as input attachment
1062 this->fSupportedSampleCounts.initSampleCounts(interface, physDev, properties, format,
1063 usageFlags);
1064 }
1065}
1066
1067bool VulkanCaps::FormatInfo::isTexturable(VkImageTiling imageTiling) const {
1068 switch (imageTiling) {
1070 return is_texturable(fFormatProperties.optimalTilingFeatures);
1072 return is_texturable(fFormatProperties.linearTilingFeatures);
1073 default:
1074 return false;
1075 }
1077}
1078
1079bool VulkanCaps::FormatInfo::isRenderable(VkImageTiling imageTiling,
1080 uint32_t sampleCount) const {
1081 if (!fSupportedSampleCounts.isSampleCountSupported(sampleCount)) {
1082 return false;
1083 }
1084 switch (imageTiling) {
1086 return is_renderable(fFormatProperties.optimalTilingFeatures);
1088 return is_renderable(fFormatProperties.linearTilingFeatures);
1089 default:
1090 return false;
1091 }
1093}
1094
1095bool VulkanCaps::FormatInfo::isStorage(VkImageTiling imageTiling) const {
1096 switch (imageTiling) {
1098 return is_storage(fFormatProperties.optimalTilingFeatures);
1100 return is_storage(fFormatProperties.linearTilingFeatures);
1101 default:
1102 return false;
1103 }
1105}
1106
1107bool VulkanCaps::FormatInfo::isTransferSrc(VkImageTiling imageTiling) const {
1108 switch (imageTiling) {
1110 return is_transfer_src(fFormatProperties.optimalTilingFeatures);
1112 return is_transfer_src(fFormatProperties.linearTilingFeatures);
1113 default:
1114 return false;
1115 }
1117}
1118
1119bool VulkanCaps::FormatInfo::isTransferDst(VkImageTiling imageTiling) const {
1120 switch (imageTiling) {
1122 return is_transfer_dst(fFormatProperties.optimalTilingFeatures);
1124 return is_transfer_dst(fFormatProperties.linearTilingFeatures);
1125 default:
1126 return false;
1127 }
1129}
1130
1131void VulkanCaps::setColorType(SkColorType colorType, std::initializer_list<VkFormat> formats) {
1132 int idx = static_cast<int>(colorType);
1133 for (auto it = formats.begin(); it != formats.end(); ++it) {
1134 const auto& info = this->getFormatInfo(*it);
1135 for (int i = 0; i < info.fColorTypeInfoCount; ++i) {
1136 if (info.fColorTypeInfos[i].fColorType == colorType) {
1137 fColorTypeToFormatTable[idx] = *it;
1138 return;
1139 }
1140 }
1141 }
1142}
1143
1144VkFormat VulkanCaps::getFormatFromColorType(SkColorType colorType) const {
1145 int idx = static_cast<int>(colorType);
1146 return fColorTypeToFormatTable[idx];
1147}
1148
1149VulkanCaps::FormatInfo& VulkanCaps::getFormatInfo(VkFormat format) {
1150 static_assert(std::size(kVkFormats) == VulkanCaps::kNumVkFormats,
1151 "Size of VkFormats array must match static value in header");
1152 for (size_t i = 0; i < std::size(kVkFormats); ++i) {
1153 if (kVkFormats[i] == format) {
1154 return fFormatTable[i];
1155 }
1156 }
1157 static FormatInfo kInvalidFormat;
1158 return kInvalidFormat;
1159}
1160
1161const VulkanCaps::FormatInfo& VulkanCaps::getFormatInfo(VkFormat format) const {
1162 VulkanCaps* nonConstThis = const_cast<VulkanCaps*>(this);
1163 return nonConstThis->getFormatInfo(format);
1164}
1165
1166void VulkanCaps::DepthStencilFormatInfo::init(const skgpu::VulkanInterface* interface,
1167 VkPhysicalDevice physDev,
1168 const VkPhysicalDeviceProperties& properties,
1169 VkFormat format) {
1170 memset(&fFormatProperties, 0, sizeof(VkFormatProperties));
1171 VULKAN_CALL(interface, GetPhysicalDeviceFormatProperties(physDev, format, &fFormatProperties));
1172
1173 if (this->isDepthStencilSupported(fFormatProperties.optimalTilingFeatures)) {
1175 fSupportedSampleCounts.initSampleCounts(interface, physDev, properties, format, usageFlags);
1176 }
1177}
1178
1179bool VulkanCaps::DepthStencilFormatInfo::isDepthStencilSupported(VkFormatFeatureFlags flags) const {
1181}
1182
1183VkFormat VulkanCaps::getFormatFromDepthStencilFlags(const SkEnumBitMask<DepthStencilFlags>& flags)
1184 const {
1185 return fDepthStencilFlagsToFormatTable[flags.value()];
1186}
1187
1188VulkanCaps::DepthStencilFormatInfo& VulkanCaps::getDepthStencilFormatInfo(VkFormat format) {
1189 static_assert(std::size(kDepthStencilVkFormats) == VulkanCaps::kNumDepthStencilVkFormats,
1190 "Size of VkFormats array must match static value in header");
1191 for (size_t i = 0; i < std::size(kDepthStencilVkFormats); ++i) {
1192 if (kVkFormats[i] == format) {
1193 return fDepthStencilFormatTable[i];
1194 }
1195 }
1196 static DepthStencilFormatInfo kInvalidFormat;
1197 return kInvalidFormat;
1198}
1199
1200const VulkanCaps::DepthStencilFormatInfo& VulkanCaps::getDepthStencilFormatInfo(VkFormat format)
1201 const {
1202 VulkanCaps* nonConstThis = const_cast<VulkanCaps*>(this);
1203 return nonConstThis->getDepthStencilFormatInfo(format);
1204}
1205
1207 const TextureInfo& textureInfo) const {
1208 VkFormat vkFormat = textureInfo.vulkanTextureSpec().fFormat;
1209 if (vkFormat == VK_FORMAT_UNDEFINED) {
1210 return nullptr;
1211 }
1212
1213 const FormatInfo& info = this->getFormatInfo(vkFormat);
1214 for (int i = 0; i < info.fColorTypeInfoCount; ++i) {
1215 const ColorTypeInfo& ctInfo = info.fColorTypeInfos[i];
1216 if (ctInfo.fColorType == ct) {
1217 return &ctInfo;
1218 }
1219 }
1220
1221 return nullptr;
1222}
1223
1224bool VulkanCaps::onIsTexturable(const TextureInfo& texInfo) const {
1225 VulkanTextureInfo vkInfo;
1226 if (!texInfo.getVulkanTextureInfo(&vkInfo)) {
1227 return false;
1228 }
1229
1230 // TODO:
1231 // Once we support external formats with associated YCbCr conversion info, check for that
1232 // and return true here because we can always texture from an external format.
1233
1234 const FormatInfo& info = this->getFormatInfo(vkInfo.fFormat);
1235 return info.isTexturable(vkInfo.fImageTiling);
1236}
1237
1238
1239bool VulkanCaps::isRenderable(const TextureInfo& texInfo) const {
1240 VulkanTextureInfo vkInfo;
1241 if (!texInfo.getVulkanTextureInfo(&vkInfo)) {
1242 return false;
1243 }
1244
1245 const FormatInfo& info = this->getFormatInfo(vkInfo.fFormat);
1246 return info.isRenderable(vkInfo.fImageTiling, texInfo.numSamples());
1247}
1248
1249bool VulkanCaps::isStorage(const TextureInfo& texInfo) const {
1250 VulkanTextureInfo vkInfo;
1251 if (!texInfo.getVulkanTextureInfo(&vkInfo)) {
1252 return false;
1253 }
1254
1255 const FormatInfo& info = this->getFormatInfo(vkInfo.fFormat);
1256 return info.isStorage(vkInfo.fImageTiling);
1257}
1258
1260 const FormatInfo& info = this->getFormatInfo(vkInfo.fFormat);
1261 return info.isTransferSrc(vkInfo.fImageTiling);
1262}
1263
1265 const FormatInfo& info = this->getFormatInfo(vkInfo.fFormat);
1266 return info.isTransferDst(vkInfo.fImageTiling);
1267}
1268
1270 VulkanTextureInfo vkInfo;
1271 if (!texInfo.getVulkanTextureInfo(&vkInfo)) {
1272 return false;
1273 }
1274
1275 // Can't write if it needs a YCbCr sampler
1276 if (VkFormatNeedsYcbcrSampler(vkInfo.fFormat)) {
1277 return false;
1278 }
1279
1280 if (vkInfo.fSampleCount > 1) {
1281 return false;
1282 }
1283
1285 return false;
1286 }
1287
1288 return true;
1289}
1290
1292 if (texInfo.isProtected() == Protected::kYes) {
1293 return false;
1294 }
1295
1296 VulkanTextureInfo vkInfo;
1297 if (!texInfo.getVulkanTextureInfo(&vkInfo)) {
1298 return false;
1299 }
1300
1301 // Can't read if it needs a YCbCr sampler
1302 if (VkFormatNeedsYcbcrSampler(vkInfo.fFormat)) {
1303 return false;
1304 }
1305
1306 if (VkFormatIsCompressed(vkInfo.fFormat)) {
1307 return false;
1308 }
1309
1310 if (vkInfo.fSampleCount > 1) {
1311 return false;
1312 }
1313
1315 return false;
1316 }
1317
1318 return true;
1319}
1320
1322 SkColorType dstColorType,
1323 const TextureInfo& dstTextureInfo,
1324 SkColorType srcColorType) const {
1325 VulkanTextureInfo vkInfo;
1326 if (!dstTextureInfo.getVulkanTextureInfo(&vkInfo)) {
1327 return {kUnknown_SkColorType, false};
1328 }
1329
1330 // Can't write to YCbCr formats
1331 // TODO: Can't write to external formats, either
1332 if (VkFormatNeedsYcbcrSampler(vkInfo.fFormat)) {
1333 return {kUnknown_SkColorType, false};
1334 }
1335
1336 const FormatInfo& info = this->getFormatInfo(vkInfo.fFormat);
1337 for (int i = 0; i < info.fColorTypeInfoCount; ++i) {
1338 const auto& ctInfo = info.fColorTypeInfos[i];
1339 if (ctInfo.fColorType == dstColorType) {
1340 return {ctInfo.fTransferColorType, vkInfo.fFormat == VK_FORMAT_R8G8B8_UNORM};
1341 }
1342 }
1343
1344 return {kUnknown_SkColorType, false};
1345}
1346
1348 SkColorType srcColorType,
1349 const TextureInfo& srcTextureInfo,
1350 SkColorType dstColorType) const {
1351 VulkanTextureInfo vkInfo;
1352 if (!srcTextureInfo.getVulkanTextureInfo(&vkInfo)) {
1353 return {kUnknown_SkColorType, false};
1354 }
1355
1356 // Can't read from YCbCr formats
1357 // TODO: external formats?
1358 if (VkFormatNeedsYcbcrSampler(vkInfo.fFormat)) {
1359 return {kUnknown_SkColorType, false};
1360 }
1361
1362 // TODO: handle compressed formats
1363 if (VkFormatIsCompressed(vkInfo.fFormat)) {
1364 SkASSERT(this->isTexturable(vkInfo));
1365 return {kUnknown_SkColorType, false};
1366 }
1367
1368 const FormatInfo& info = this->getFormatInfo(vkInfo.fFormat);
1369 for (int i = 0; i < info.fColorTypeInfoCount; ++i) {
1370 const auto& ctInfo = info.fColorTypeInfos[i];
1371 if (ctInfo.fColorType == srcColorType) {
1372 return {ctInfo.fTransferColorType, vkInfo.fFormat == VK_FORMAT_R8G8B8_UNORM};
1373 }
1374 }
1375
1376 return {kUnknown_SkColorType, false};
1377}
1378
1380 const RenderPassDesc& renderPassDesc) const {
1381 UniqueKey pipelineKey;
1382 {
1385
1386 VulkanRenderPass::VulkanRenderPassMetaData rpMetaData {renderPassDesc};
1387
1388 // Reserve 3 uint32s for the render step id, paint id, and write swizzle.
1389 static constexpr int kUint32sNeededForPipelineInfo = 3;
1390 // The uint32s needed for a RenderPass is variable number, so consult rpMetaData to
1391 // determine how many to reserve.
1392 UniqueKey::Builder builder(&pipelineKey,
1394 kUint32sNeededForPipelineInfo + rpMetaData.fUint32DataCnt,
1395 "GraphicsPipeline");
1396
1397 int idx = 0;
1398 // Add GraphicsPipelineDesc information
1399 builder[idx++] = pipelineDesc.renderStepID();
1400 builder[idx++] = pipelineDesc.paintParamsID().asUInt();
1401 // Add RenderPass info relevant for pipeline creation that's not captured in RenderPass keys
1402 builder[idx++] = renderPassDesc.fWriteSwizzle.asKey();
1403 // Add RenderPassDesc information
1404 VulkanRenderPass::AddRenderPassInfoToKey(rpMetaData, builder, idx, /*compatibleOnly=*/true);
1405
1406 builder.finish();
1407 }
1408
1409 return pipelineKey;
1410}
1411
1413 GraphiteResourceKey samplerKey;
1415 GraphiteResourceKey::Builder builder(&samplerKey, kType, 1, Shareable::kYes);
1416
1417 // TODO(b/311392779): When needed, add YCbCr info to the sampler key.
1418
1419 builder[0] = samplerDesc.desc();
1420 builder.finish();
1421 return samplerKey;
1422}
1423
1425 const TextureInfo& info,
1427 Shareable shareable,
1428 GraphiteResourceKey* key) const {
1429 const VulkanTextureSpec& vkSpec = info.vulkanTextureSpec();
1430
1431 SkASSERT(!dimensions.isEmpty());
1432
1433 // We expect that the VkFormat enum is at most a 32-bit value.
1434 static_assert(VK_FORMAT_MAX_ENUM == 0x7FFFFFFF);
1436 uint32_t formatKey = static_cast<uint32_t>(vkSpec.fFormat);
1437
1438 uint32_t samplesKey = SamplesToKey(info.numSamples());
1439 // We don't have to key the number of mip levels because it is inherit in the combination of
1440 // isMipped and dimensions.
1441 bool isMipped = info.mipmapped() == Mipmapped::kYes;
1442 Protected isProtected = info.isProtected();
1443
1444 // Confirm all the below parts of the key can fit in a single uint32_t. The sum of the shift
1445 // amounts in the asserts must be less than or equal to 32. vkSpec.fFlags will go into its
1446 // own 32-bit block.
1447 SkASSERT(samplesKey < (1u << 3)); // sample key is first 3 bits
1448 SkASSERT(static_cast<uint32_t>(isMipped) < (1u << 1)); // isMapped is 4th bit
1449 SkASSERT(static_cast<uint32_t>(isProtected) < (1u << 1)); // isProtected is 5th bit
1450 SkASSERT(vkSpec.fImageTiling < (1u << 1)); // imageTiling is 6th bit
1451 SkASSERT(vkSpec.fSharingMode < (1u << 1)); // sharingMode is 7th bit
1452 SkASSERT(vkSpec.fAspectMask < (1u << 11)); // aspectMask is bits 8 - 19
1453 SkASSERT(vkSpec.fImageUsageFlags < (1u << 12)); // imageUsageFlags are bits 20-32
1454
1455 // We need two uint32_ts for dimensions, 1 for format, and 2 for the rest of the key.
1456 static int kNum32DataCnt = 2 + 1 + 2;
1457
1458 GraphiteResourceKey::Builder builder(key, type, kNum32DataCnt, shareable);
1459
1460 builder[0] = dimensions.width();
1461 builder[1] = dimensions.height();
1462 builder[2] = formatKey;
1463 builder[3] = (static_cast<uint32_t>(vkSpec.fFlags));
1464 builder[4] = (samplesKey << 0) |
1465 (static_cast<uint32_t>(isMipped) << 3) |
1466 (static_cast<uint32_t>(isProtected) << 4) |
1467 (static_cast<uint32_t>(vkSpec.fImageTiling) << 5) |
1468 (static_cast<uint32_t>(vkSpec.fSharingMode) << 6) |
1469 (static_cast<uint32_t>(vkSpec.fAspectMask) << 7) |
1470 (static_cast<uint32_t>(vkSpec.fImageUsageFlags) << 19);
1471}
1472
1473} // namespace skgpu::graphite
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition DM.cpp:213
#define SKGPU_LOG_W(fmt,...)
Definition Log.h:40
#define SkUNREACHABLE
Definition SkAssert.h:135
#define SkASSERT(cond)
Definition SkAssert.h:116
SkColorType
Definition SkColorType.h:19
@ kR16G16B16A16_unorm_SkColorType
pixel with a little endian uint16_t for red, green, blue
Definition SkColorType.h:50
@ kR8_unorm_SkColorType
Definition SkColorType.h:54
@ kARGB_4444_SkColorType
pixel with 4 bits for alpha, red, green, blue; in 16-bit word
Definition SkColorType.h:23
@ kR8G8_unorm_SkColorType
pixel with a uint8_t for red and green
Definition SkColorType.h:43
@ kBGRA_8888_SkColorType
pixel with 8 bits for blue, green, red, alpha; in 32-bit word
Definition SkColorType.h:26
@ kA16_unorm_SkColorType
pixel with a little endian uint16_t for alpha
Definition SkColorType.h:48
@ kRGBA_F16_SkColorType
pixel with half floats for red, green, blue, alpha;
Definition SkColorType.h:38
@ kAlpha_8_SkColorType
pixel with alpha in 8-bit byte
Definition SkColorType.h:21
@ kSRGBA_8888_SkColorType
Definition SkColorType.h:53
@ kGray_8_SkColorType
pixel with grayscale level in 8-bit byte
Definition SkColorType.h:35
@ kRGB_565_SkColorType
pixel with 5 bits red, 6 bits green, 5 bits blue, in 16-bit word
Definition SkColorType.h:22
@ kRGBA_8888_SkColorType
pixel with 8 bits for red, green, blue, alpha; in 32-bit word
Definition SkColorType.h:24
@ kRGB_888x_SkColorType
pixel with 8 bits each for red, green, blue; in 32-bit word
Definition SkColorType.h:25
@ kBGRA_1010102_SkColorType
10 bits for blue, green, red; 2 bits for alpha; in 32-bit word
Definition SkColorType.h:28
@ kA16_float_SkColorType
pixel with a half float for alpha
Definition SkColorType.h:45
@ kRGBA_1010102_SkColorType
10 bits for red, green, blue; 2 bits for alpha; in 32-bit word
Definition SkColorType.h:27
@ kR16G16_unorm_SkColorType
pixel with a little endian uint16_t for red and green
Definition SkColorType.h:49
@ kUnknown_SkColorType
uninitialized
Definition SkColorType.h:20
@ kR16G16_float_SkColorType
pixel with a half float for red and green
Definition SkColorType.h:46
static constexpr int kSkColorTypeCnt
Definition SkColorType.h:68
#define SkDEBUGCODE(...)
Definition SkDebug.h:23
static SkColorType colorType(AImageDecoder *decoder, const AImageDecoderHeaderInfo *headerInfo)
static constexpr bool SkToBool(const T &x)
Definition SkTo.h:35
#define VULKAN_CALL(IFACE, X)
#define VULKAN_CALL_RESULT_NOCHECK(IFACE, RESULT, X)
constexpr uint16_t asKey() const
Definition Swizzle.h:43
static constexpr Swizzle BGRA()
Definition Swizzle.h:67
static constexpr Swizzle RGB1()
Definition Swizzle.h:69
static Domain GenerateDomain()
size_t fRequiredStorageBufferAlignment
Definition Caps.h:342
bool fSupportsAHardwareBufferImages
Definition Caps.h:359
size_t fRequiredUniformBufferAlignment
Definition Caps.h:341
bool isTexturable(const TextureInfo &) const
Definition Caps.cpp:65
bool protectedSupport() const
Definition Caps.h:219
static uint32_t SamplesToKey(uint32_t numSamples)
Definition Caps.h:305
void finishInitialization(const ContextOptions &)
Definition Caps.cpp:29
size_t fRequiredTransferBufferAlignment
Definition Caps.h:343
ResourceBindingRequirements fResourceBindingReqs
Definition Caps.h:366
UniquePaintParamsID paintParamsID() const
uint32_t numSamples() const
Definition TextureInfo.h:78
Protected isProtected() const
Definition TextureInfo.h:80
TextureInfo getDefaultDepthStencilTextureInfo(SkEnumBitMask< DepthStencilFlags >, uint32_t sampleCount, Protected) const override
const ColorTypeInfo * getColorTypeInfo(SkColorType, const TextureInfo &) const override
std::pair< SkColorType, bool > supportedWritePixelsColorType(SkColorType dstColorType, const TextureInfo &dstTextureInfo, SkColorType srcColorType) const override
void buildKeyForTexture(SkISize dimensions, const TextureInfo &, ResourceType, Shareable, GraphiteResourceKey *) const override
TextureInfo getTextureInfoForSampledCopy(const TextureInfo &textureInfo, Mipmapped mipmapped) const override
UniqueKey makeGraphicsPipelineKey(const GraphicsPipelineDesc &, const RenderPassDesc &) const override
GraphiteResourceKey makeSamplerKey(const SamplerDesc &) const override
bool isStorage(const TextureInfo &) const override
bool supportsWritePixels(const TextureInfo &) const override
bool isRenderable(const TextureInfo &) const override
TextureInfo getDefaultSampledTextureInfo(SkColorType, Mipmapped mipmapped, Protected, Renderable) const override
bool isTransferSrc(const VulkanTextureInfo &) const
bool supportsReadPixels(const TextureInfo &) const override
bool isTransferDst(const VulkanTextureInfo &) const
TextureInfo getDefaultCompressedTextureInfo(SkTextureCompressionType, Mipmapped mipmapped, Protected) const override
TextureInfo getDefaultMSAATextureInfo(const TextureInfo &singleSampledInfo, Discardable discardable) const override
bool onIsTexturable(const TextureInfo &) const override
uint32_t channelMask(const TextureInfo &) const override
std::pair< SkColorType, bool > supportedReadPixelsColorType(SkColorType srcColorType, const TextureInfo &srcTextureInfo, SkColorType dstColorType) const override
TextureInfo getDefaultStorageTextureInfo(SkColorType) const override
VulkanCaps(const ContextOptions &, const skgpu::VulkanInterface *, VkPhysicalDevice, uint32_t physicalDeviceVersion, const VkPhysicalDeviceFeatures2 *, const skgpu::VulkanExtensions *, Protected)
static void AddRenderPassInfoToKey(VulkanRenderPassMetaData &rpMetaData, ResourceKey::Builder &builder, int &builderIdx, bool compatibleOnly)
FlutterSemanticsFlag flags
GAsyncResult * result
uint32_t uint32_t * format
static constexpr VkFormat kDepthStencilVkFormats[]
static constexpr VkFormat kVkFormats[]
uint32_t ResourceType
static const skgpu::UniqueKey::Domain kGraphicsPipelineDomain
Definition MtlCaps.mm:959
static constexpr uint32_t VkFormatChannels(VkFormat vkFormat)
static constexpr bool VkFormatNeedsYcbcrSampler(VkFormat format)
static constexpr bool VkFormatIsCompressed(VkFormat vkFormat)
Renderable
Definition GpuTypes.h:69
Mipmapped
Definition GpuTypes.h:53
Protected
Definition GpuTypes.h:61
static void usage(char *argv0)
bool isEmpty() const
Definition SkSize.h:31
constexpr int32_t width() const
Definition SkSize.h:36
constexpr int32_t height() const
Definition SkSize.h:37
VkSampleCountFlags sampleCounts
VkMemoryPropertyFlags propertyFlags
VkDeviceSize minStorageBufferOffsetAlignment
VkDeviceSize minUniformBufferOffsetAlignment
uint32_t maxVertexInputAttributes
VkMemoryType memoryTypes[VK_MAX_MEMORY_TYPES]
char deviceName[VK_MAX_PHYSICAL_DEVICE_NAME_SIZE]
VkPhysicalDeviceLimits limits
#define VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME
VkFlags VkMemoryPropertyFlags
VkFlags VkSampleCountFlags
@ VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT
@ VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT
@ VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT
@ VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT
@ VK_FORMAT_FEATURE_TRANSFER_DST_BIT
@ VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT
@ VK_FORMAT_FEATURE_TRANSFER_SRC_BIT
@ VK_SHARING_MODE_EXCLUSIVE
@ VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT
@ VK_MEMORY_PROPERTY_PROTECTED_BIT
VkFlags VkImageUsageFlags
@ VK_IMAGE_CREATE_PROTECTED_BIT
VkImageTiling
@ VK_IMAGE_TILING_OPTIMAL
@ VK_IMAGE_TILING_LINEAR
@ VK_IMAGE_ASPECT_COLOR_BIT
@ VK_IMAGE_USAGE_TRANSFER_DST_BIT
@ VK_IMAGE_USAGE_SAMPLED_BIT
@ VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT
@ VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT
@ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT
@ VK_IMAGE_USAGE_TRANSFER_SRC_BIT
@ VK_IMAGE_USAGE_STORAGE_BIT
@ VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT
@ VK_SAMPLE_COUNT_8_BIT
@ VK_SAMPLE_COUNT_2_BIT
@ VK_SAMPLE_COUNT_1_BIT
@ VK_SAMPLE_COUNT_4_BIT
@ VK_SAMPLE_COUNT_16_BIT
VkFlags VkFormatFeatureFlags
@ VK_IMAGE_TYPE_2D
#define VK_EXT_DEVICE_FAULT_EXTENSION_NAME
VkResult
@ VK_SUCCESS
VkFormat
@ VK_FORMAT_R16G16B16A16_UNORM
@ VK_FORMAT_R8G8B8A8_SRGB
@ VK_FORMAT_R8G8B8_UNORM
@ VK_FORMAT_D24_UNORM_S8_UINT
@ VK_FORMAT_B8G8R8A8_UNORM
@ VK_FORMAT_R16G16_SFLOAT
@ VK_FORMAT_B4G4R4A4_UNORM_PACK16
@ VK_FORMAT_R16_SFLOAT
@ VK_FORMAT_R8G8_UNORM
@ VK_FORMAT_S8_UINT
@ VK_FORMAT_R8_UNORM
@ VK_FORMAT_R5G6B5_UNORM_PACK16
@ VK_FORMAT_R4G4B4A4_UNORM_PACK16
@ VK_FORMAT_A2B10G10R10_UNORM_PACK32
@ VK_FORMAT_R8G8B8A8_UNORM
@ VK_FORMAT_UNDEFINED
@ VK_FORMAT_BC1_RGB_UNORM_BLOCK
@ VK_FORMAT_R16_UNORM
@ VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM
@ VK_FORMAT_R16G16B16A16_SFLOAT
@ VK_FORMAT_R16G16_UNORM
@ VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK
@ VK_FORMAT_A2R10G10B10_UNORM_PACK32
@ VK_FORMAT_BC1_RGBA_UNORM_BLOCK
@ VK_FORMAT_G8_B8R8_2PLANE_420_UNORM
@ VK_FORMAT_D32_SFLOAT_S8_UINT
@ VK_FORMAT_MAX_ENUM
@ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES
@ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2