Flutter Engine
The Flutter Engine
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
27#include "src/sksl/SkSLUtil.h"
28
29#ifdef SK_BUILD_FOR_ANDROID
30#include <sys/system_properties.h>
31#endif
32
33namespace skgpu::graphite {
34
36 const skgpu::VulkanInterface* vkInterface,
37 VkPhysicalDevice physDev,
38 uint32_t physicalDeviceVersion,
39 const VkPhysicalDeviceFeatures2* features,
41 Protected isProtected)
42 : Caps() {
43 this->init(contextOptions, vkInterface, physDev, physicalDeviceVersion, features, extensions,
44 isProtected);
45}
46
48
49void VulkanCaps::init(const ContextOptions& contextOptions,
50 const skgpu::VulkanInterface* vkInterface,
51 VkPhysicalDevice physDev,
52 uint32_t physicalDeviceVersion,
53 const VkPhysicalDeviceFeatures2* features,
55 Protected isProtected) {
56 VkPhysicalDeviceProperties physDevProperties;
57 VULKAN_CALL(vkInterface, GetPhysicalDeviceProperties(physDev, &physDevProperties));
58
59#if defined(GRAPHITE_TEST_UTILS)
60 this->setDeviceName(physDevProperties.deviceName);
61#endif
62
63 // Graphite requires Vulkan version 1.1 or later, which always has protected support.
64 if (isProtected == Protected::kYes) {
65 fProtectedSupport = true;
66 fShouldAlwaysUseDedicatedImageMemory = true;
67 }
68
69 fPhysicalDeviceMemoryProperties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2;
70 fPhysicalDeviceMemoryProperties2.pNext = nullptr;
71 VULKAN_CALL(vkInterface,
72 GetPhysicalDeviceMemoryProperties2(physDev, &fPhysicalDeviceMemoryProperties2));
73
74 // We could actually query and get a max size for each config, however maxImageDimension2D will
75 // give the minimum max size across all configs. So for simplicity we will use that for now.
76 fMaxTextureSize = std::min(physDevProperties.limits.maxImageDimension2D, (uint32_t)INT_MAX);
77
81
83 // TODO(skia:14639): We cannot use std430 layout for SSBOs until SkSL gracefully handles
84 // implicit array stride.
88
89 VkPhysicalDeviceMemoryProperties deviceMemoryProperties;
90 VULKAN_CALL(vkInterface, GetPhysicalDeviceMemoryProperties(physDev, &deviceMemoryProperties));
91 fSupportsMemorylessAttachments = false;
94 // If we have a protected context we can only use memoryless images if they also support
95 // being protected. With current devices we don't actually expect this combination to be
96 // supported, but this at least covers us for future devices that may allow it.
97 requiredLazyFlags |= VK_MEMORY_PROPERTY_PROTECTED_BIT;
98 }
99 for (uint32_t i = 0; i < deviceMemoryProperties.memoryTypeCount; ++i) {
100 if (deviceMemoryProperties.memoryTypes[i].propertyFlags & requiredLazyFlags) {
101 fSupportsMemorylessAttachments = true;
102 }
103 }
104
105#ifdef SK_BUILD_FOR_UNIX
106 if (kNvidia_VkVendor == physDevProperties.vendorID) {
107 // On NVIDIA linux we see a big perf regression when not using dedicated image allocations.
108 fShouldAlwaysUseDedicatedImageMemory = true;
109 }
110#endif
111
112 if (physDevProperties.vendorID == kNvidia_VkVendor ||
113 physDevProperties.vendorID == kAMD_VkVendor) {
114 // On discrete GPUs, it can be faster to read gpu-only memory compared to memory that is
115 // also mappable on the host.
116 fGpuOnlyBuffersMorePerformant = true;
117
118 // On discrete GPUs we try to use special DEVICE_LOCAL and HOST_VISIBLE memory for our
119 // cpu write, gpu read buffers. This memory is not ideal to be kept persistently mapped.
120 // Some discrete GPUs do not expose this special memory, however we still disable
121 // persistently mapped buffers for all of them since most GPUs with updated drivers do
122 // expose it. If this becomes an issue we can try to be more fine grained.
123 fShouldPersistentlyMapCpuToGpuBuffers = false;
124 }
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 fShaderCaps->fFloatBufferArrayName = "fsGradientBuffer";
161
162 // Note that format table initialization should be performed at the end of this method to ensure
163 // all capability determinations are completed prior to populating the format tables.
164 this->initFormatTable(vkInterface, physDev, physDevProperties);
165 this->initDepthStencilFormatTable(vkInterface, physDev, physDevProperties);
166
167 this->finishInitialization(contextOptions);
168}
169
170void VulkanCaps::applyDriverCorrectnessWorkarounds(const VkPhysicalDeviceProperties& properties) {
171 // By default, we initialize the Android API version to 0 since we consider certain things
172 // "fixed" only once above a certain version. This way, we default to enabling the workarounds.
173 int androidAPIVersion = 0;
174#if defined(SK_BUILD_FOR_ANDROID)
175 char androidAPIVersionStr[PROP_VALUE_MAX];
176 int strLength = __system_property_get("ro.build.version.sdk", androidAPIVersionStr);
177 // Defaults to zero since most checks care if it is greater than a specific value. So this will
178 // just default to it being less.
179 androidAPIVersion = (strLength == 0) ? 0 : atoi(androidAPIVersionStr);
180#endif
181
182 // On Mali galaxy s7 we see lots of rendering issues when we suballocate VkImages.
183 if (kARM_VkVendor == properties.vendorID && androidAPIVersion <= 28) {
184 fShouldAlwaysUseDedicatedImageMemory = true;
185 }
186}
187
188// These are all the valid VkFormats that we support in Skia. They are roughly ordered from most
189// frequently used to least to improve look up times in arrays.
190static constexpr VkFormat kVkFormats[] = {
213};
214// These are all the valid depth/stencil formats that we support in Skia.
215static constexpr VkFormat kDepthStencilVkFormats[] = {
221};
222
224 Mipmapped mipmapped,
225 Protected isProtected,
226 Renderable isRenderable) const {
227 VkFormat format = this->getFormatFromColorType(ct);
228 const FormatInfo& formatInfo = this->getFormatInfo(format);
229 static constexpr int defaultSampleCount = 1;
230 if ((isProtected == Protected::kYes && !this->protectedSupport()) ||
231 !formatInfo.isTexturable(VK_IMAGE_TILING_OPTIMAL) ||
233 !formatInfo.isRenderable(VK_IMAGE_TILING_OPTIMAL, defaultSampleCount)) ) {
234 return {};
235 }
236
238 info.fSampleCount = defaultSampleCount;
239 info.fMipmapped = mipmapped;
240 info.fFlags = (isProtected == Protected::kYes) ? VK_IMAGE_CREATE_PROTECTED_BIT : 0;
241 info.fFormat = format;
242 info.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
243 info.fImageUsageFlags = VK_IMAGE_USAGE_SAMPLED_BIT |
247 // We make all renderable images support being used as input attachment
248 info.fImageUsageFlags = info.fImageUsageFlags |
251 }
252 info.fSharingMode = VK_SHARING_MODE_EXCLUSIVE;
253 info.fAspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
254
255 return info;
256}
257
259 Mipmapped mipmapped) const {
261 if (!textureInfo.getVulkanTextureInfo(&info)) {
262 return {};
263 }
264
265 info.fSampleCount = 1;
266 info.fMipmapped = mipmapped;
267 info.fFlags = (textureInfo.fProtected == Protected::kYes) ? VK_IMAGE_CREATE_PROTECTED_BIT : 0;
268 info.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
271 info.fSharingMode = VK_SHARING_MODE_EXCLUSIVE;
272
273 return info;
274}
275
276namespace {
277VkFormat format_from_compression(SkTextureCompressionType compression) {
278 switch (compression) {
285 default:
286 return VK_FORMAT_UNDEFINED;
287 }
288}
289}
290
292 Mipmapped mipmapped,
293 Protected isProtected) const {
294 VkFormat format = format_from_compression(compression);
295 const FormatInfo& formatInfo = this->getFormatInfo(format);
296 static constexpr int defaultSampleCount = 1;
297 if ((isProtected == Protected::kYes && !this->protectedSupport()) ||
298 !formatInfo.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
299 return {};
300 }
301
303 info.fSampleCount = defaultSampleCount;
304 info.fMipmapped = mipmapped;
305 info.fFlags = (isProtected == Protected::kYes) ? VK_IMAGE_CREATE_PROTECTED_BIT : 0;
306 info.fFormat = format;
307 info.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
308 info.fImageUsageFlags = VK_IMAGE_USAGE_SAMPLED_BIT |
311 info.fSharingMode = VK_SHARING_MODE_EXCLUSIVE;
312 info.fAspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
313
314 return info;
315}
316
318 Discardable discardable) const {
319 if (fDefaultMSAASamples <= 1) {
320 return {};
321 }
322
323 const VkFormat singleSpecFormat = singleSampledInfo.vulkanTextureSpec().fFormat;
324 const FormatInfo& formatInfo = this->getFormatInfo(singleSpecFormat);
325 if ((singleSampledInfo.isProtected() == Protected::kYes && !this->protectedSupport()) ||
326 !formatInfo.isRenderable(VK_IMAGE_TILING_OPTIMAL, fDefaultMSAASamples)) {
327 return {};
328 }
329
331 info.fSampleCount = fDefaultMSAASamples;
332 info.fMipmapped = Mipmapped::kNo;
333 info.fFlags = (singleSampledInfo.isProtected() == Protected::kYes) ?
335 info.fFormat = singleSpecFormat;
336 info.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
337
338 /**
339 * Graphite, unlike ganesh, does not require a dedicated MSAA attachment on every surface.
340 * MSAA textures now get resolved within the scope of a render pass, which can be done simply
341 * with the color attachment usage flag. So we no longer require transfer src/dst usage flags.
342 */
344 if (discardable == Discardable::kYes && fSupportsMemorylessAttachments) {
346 }
347
348 info.fImageUsageFlags = flags;
349 info.fSharingMode = VK_SHARING_MODE_EXCLUSIVE;
350 info.fAspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
351
352 return info;
353}
354
356 uint32_t sampleCount,
357 Protected isProtected) const {
358 VkFormat format = this->getFormatFromDepthStencilFlags(flags);
359 const DepthStencilFormatInfo& formatInfo = this->getDepthStencilFormatInfo(format);
360 if ( (isProtected == Protected::kYes && !this->protectedSupport()) ||
361 !formatInfo.isDepthStencilSupported(formatInfo.fFormatProperties.optimalTilingFeatures) ||
362 !formatInfo.fSupportedSampleCounts.isSampleCountSupported(sampleCount)) {
363 return {};
364 }
365
367 info.fSampleCount = sampleCount;
368 info.fMipmapped = Mipmapped::kNo;
369 info.fFlags = (isProtected == Protected::kYes) ? VK_IMAGE_CREATE_PROTECTED_BIT : 0;
370 info.fFormat = format;
371 info.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
372 // TODO: Passing in a discardable flag to this method, and if true, add the TRANSIENT bit.
374 info.fSharingMode = VK_SHARING_MODE_EXCLUSIVE;
375 info.fAspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
376
377 return info;
378}
379
381 VkFormat format = this->getFormatFromColorType(colorType);
382 const FormatInfo& formatInfo = this->getFormatInfo(format);
383 if (!formatInfo.isTexturable(VK_IMAGE_TILING_OPTIMAL) ||
384 !formatInfo.isStorage(VK_IMAGE_TILING_OPTIMAL)) {
385 return {};
386 }
387
389 info.fSampleCount = 1;
390 info.fMipmapped = Mipmapped::kNo;
391 info.fFlags = 0;
392 info.fFormat = format;
393 info.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
394 // Storage textures are currently always sampleable from a shader
395 info.fImageUsageFlags = VK_IMAGE_USAGE_STORAGE_BIT |
398 info.fSharingMode = VK_SHARING_MODE_EXCLUSIVE;
399 info.fAspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
400
401 return info;
402}
403
404uint32_t VulkanCaps::channelMask(const TextureInfo& textureInfo) const {
405 return skgpu::VkFormatChannels(textureInfo.vulkanTextureSpec().fFormat);
406}
407
408void VulkanCaps::initFormatTable(const skgpu::VulkanInterface* interface,
409 VkPhysicalDevice physDev,
410 const VkPhysicalDeviceProperties& properties) {
411 static_assert(std::size(kVkFormats) == VulkanCaps::kNumVkFormats,
412 "Size of VkFormats array must match static value in header");
413
414 std::fill_n(fColorTypeToFormatTable, kSkColorTypeCnt, VK_FORMAT_UNDEFINED);
415
416 // Go through all the formats and init their support surface and data ColorTypes.
417 // Format: VK_FORMAT_R8G8B8A8_UNORM
418 {
420 auto& info = this->getFormatInfo(format);
421 info.init(interface, physDev, properties, format);
422 if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
423 info.fColorTypeInfoCount = 2;
424 info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
425 int ctIdx = 0;
426 // Format: VK_FORMAT_R8G8B8A8_UNORM, Surface: kRGBA_8888
427 {
429 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
430 ctInfo.fColorType = ct;
431 ctInfo.fTransferColorType = ct;
433 }
434 // Format: VK_FORMAT_R8G8B8A8_UNORM, Surface: kRGB_888x
435 {
437 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
438 ctInfo.fColorType = ct;
439 ctInfo.fTransferColorType = ct;
440 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag;
441 ctInfo.fReadSwizzle = skgpu::Swizzle::RGB1();
442 }
443 }
444 }
445
446 // Format: VK_FORMAT_R8_UNORM
447 {
449 auto& info = this->getFormatInfo(format);
450 info.init(interface, physDev, properties, format);
451 if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
452 info.fColorTypeInfoCount = 3;
453 info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
454 int ctIdx = 0;
455 // Format: VK_FORMAT_R8_UNORM, Surface: kR_8
456 {
458 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
459 ctInfo.fColorType = ct;
460 ctInfo.fTransferColorType = ct;
462 }
463 // Format: VK_FORMAT_R8_UNORM, Surface: kAlpha_8
464 {
466 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
467 ctInfo.fColorType = ct;
468 ctInfo.fTransferColorType = ct;
470 ctInfo.fReadSwizzle = skgpu::Swizzle("000r");
471 ctInfo.fWriteSwizzle = skgpu::Swizzle("a000");
472 }
473 // Format: VK_FORMAT_R8_UNORM, Surface: kGray_8
474 {
476 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
477 ctInfo.fColorType = ct;
478 ctInfo.fTransferColorType = ct;
479 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag;
480 ctInfo.fReadSwizzle = skgpu::Swizzle("rrr1");
481 }
482 }
483 }
484
485 // Format: VK_FORMAT_B8G8R8A8_UNORM
486 {
488 auto& info = this->getFormatInfo(format);
489 info.init(interface, physDev, properties, format);
490 if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
491 info.fColorTypeInfoCount = 1;
492 info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
493 int ctIdx = 0;
494 // Format: VK_FORMAT_B8G8R8A8_UNORM, Surface: kBGRA_8888
495 {
497 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
498 ctInfo.fColorType = ct;
499 ctInfo.fTransferColorType = ct;
501 }
502 }
503 }
504 // Format: VK_FORMAT_R5G6B5_UNORM_PACK16
505 {
507 auto& info = this->getFormatInfo(format);
508 info.init(interface, physDev, properties, format);
509 if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
510 info.fColorTypeInfoCount = 1;
511 info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
512 int ctIdx = 0;
513 // Format: VK_FORMAT_R5G6B5_UNORM_PACK16, Surface: kRGB_565_SkColorType
514 {
516 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
517 ctInfo.fColorType = ct;
518 ctInfo.fTransferColorType = ct;
520 }
521 }
522 }
523 // Format: VK_FORMAT_R16G16B16A16_SFLOAT
524 {
526 auto& info = this->getFormatInfo(format);
527 info.init(interface, physDev, properties, format);
528 if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
529 info.fColorTypeInfoCount = 2;
530 info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
531 int ctIdx = 0;
532 // Format: VK_FORMAT_R16G16B16A16_SFLOAT, Surface: SkColorType::kRGBA_F16_SkColorType
533 {
535 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
536 ctInfo.fColorType = ct;
537 ctInfo.fTransferColorType = ct;
539 }
540 }
541 }
542 // Format: VK_FORMAT_R16_SFLOAT
543 {
545 auto& info = this->getFormatInfo(format);
546 info.init(interface, physDev, properties, format);
547 if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
548 info.fColorTypeInfoCount = 1;
549 info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
550 int ctIdx = 0;
551 // Format: VK_FORMAT_R16_SFLOAT, Surface: kAlpha_F16
552 {
554 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
555 ctInfo.fColorType = ct;
556 ctInfo.fTransferColorType = ct;
558 ctInfo.fReadSwizzle = skgpu::Swizzle("000r");
559 ctInfo.fWriteSwizzle = skgpu::Swizzle("a000");
560 }
561 }
562 }
563 // Format: VK_FORMAT_R8G8B8_UNORM
564 {
566 auto& info = this->getFormatInfo(format);
567 info.init(interface, physDev, properties, format);
568 if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
569 info.fColorTypeInfoCount = 1;
570 info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
571 int ctIdx = 0;
572 // Format: VK_FORMAT_R8G8B8_UNORM, Surface: kRGB_888x
573 {
575 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
576 ctInfo.fColorType = ct;
577 // This SkColorType is a lie, but we don't have a kRGB_888_SkColorType. The Vulkan
578 // format is 3 bpp so we must manualy convert to/from this and kRGB_888x when doing
579 // transfers. We signal this need for manual conversions in the
580 // supportedRead/WriteColorType calls.
581 ctInfo.fTransferColorType = SkColorType::kRGB_888x_SkColorType;
583 }
584 }
585 }
586 // Format: VK_FORMAT_R8G8_UNORM
587 {
589 auto& info = this->getFormatInfo(format);
590 info.init(interface, physDev, properties, format);
591 if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
592 info.fColorTypeInfoCount = 1;
593 info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
594 int ctIdx = 0;
595 // Format: VK_FORMAT_R8G8_UNORM, Surface: kR8G8_unorm
596 {
598 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
599 ctInfo.fColorType = ct;
600 ctInfo.fTransferColorType = ct;
602 }
603 }
604 }
605 // Format: VK_FORMAT_A2B10G10R10_UNORM_PACK32
606 {
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_A2B10G10R10_UNORM_PACK32, Surface: kRGBA_1010102
615 {
617 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
618 ctInfo.fColorType = ct;
619 ctInfo.fTransferColorType = ct;
621 }
622 }
623 }
624 // Format: VK_FORMAT_A2R10G10B10_UNORM_PACK32
625 {
627 auto& info = this->getFormatInfo(format);
628 info.init(interface, physDev, properties, format);
629 if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
630 info.fColorTypeInfoCount = 1;
631 info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
632 int ctIdx = 0;
633 // Format: VK_FORMAT_A2R10G10B10_UNORM_PACK32, Surface: kBGRA_1010102
634 {
636 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
637 ctInfo.fColorType = ct;
638 ctInfo.fTransferColorType = ct;
640 }
641 }
642 }
643 // Format: VK_FORMAT_B4G4R4A4_UNORM_PACK16
644 {
646 auto& info = this->getFormatInfo(format);
647 info.init(interface, physDev, properties, format);
648 if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
649 info.fColorTypeInfoCount = 1;
650 info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
651 int ctIdx = 0;
652 // Format: VK_FORMAT_B4G4R4A4_UNORM_PACK16, Surface: kARGB_4444_SkColorType
653 {
655 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
656 ctInfo.fColorType = ct;
657 ctInfo.fTransferColorType = ct;
659 ctInfo.fReadSwizzle = skgpu::Swizzle::BGRA();
660 ctInfo.fWriteSwizzle = skgpu::Swizzle::BGRA();
661 }
662 }
663 }
664
665 // Format: VK_FORMAT_R4G4B4A4_UNORM_PACK16
666 {
668 auto& info = this->getFormatInfo(format);
669 info.init(interface, physDev, properties, format);
670 if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
671 info.fColorTypeInfoCount = 1;
672 info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
673 int ctIdx = 0;
674 // Format: VK_FORMAT_R4G4B4A4_UNORM_PACK16, Surface: kARGB_4444_SkColorType
675 {
677 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
678 ctInfo.fColorType = ct;
679 ctInfo.fTransferColorType = ct;
681 }
682 }
683 }
684 // Format: VK_FORMAT_R8G8B8A8_SRGB
685 {
687 auto& info = this->getFormatInfo(format);
688 info.init(interface, physDev, properties, format);
689 if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
690 info.fColorTypeInfoCount = 1;
691 info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
692 int ctIdx = 0;
693 // Format: VK_FORMAT_R8G8B8A8_SRGB, Surface: kRGBA_8888_SRGB
694 {
696 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
697 ctInfo.fColorType = ct;
698 ctInfo.fTransferColorType = ct;
700 }
701 }
702 }
703 // Format: VK_FORMAT_R16_UNORM
704 {
706 auto& info = this->getFormatInfo(format);
707 info.init(interface, physDev, properties, format);
708 if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
709 info.fColorTypeInfoCount = 1;
710 info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
711 int ctIdx = 0;
712 // Format: VK_FORMAT_R16_UNORM, Surface: kAlpha_16
713 {
715 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
716 ctInfo.fColorType = ct;
717 ctInfo.fTransferColorType = ct;
719 ctInfo.fReadSwizzle = skgpu::Swizzle("000r");
720 ctInfo.fWriteSwizzle = skgpu::Swizzle("a000");
721 }
722 }
723 }
724 // Format: VK_FORMAT_R16G16_UNORM
725 {
727 auto& info = this->getFormatInfo(format);
728 info.init(interface, physDev, properties, format);
729 if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
730 info.fColorTypeInfoCount = 1;
731 info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
732 int ctIdx = 0;
733 // Format: VK_FORMAT_R16G16_UNORM, Surface: kRG_1616
734 {
736 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
737 ctInfo.fColorType = ct;
738 ctInfo.fTransferColorType = ct;
740 }
741 }
742 }
743 // Format: VK_FORMAT_R16G16B16A16_UNORM
744 {
746 auto& info = this->getFormatInfo(format);
747 info.init(interface, physDev, properties, format);
748 if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
749 info.fColorTypeInfoCount = 1;
750 info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
751 int ctIdx = 0;
752 // Format: VK_FORMAT_R16G16B16A16_UNORM, Surface: kRGBA_16161616
753 {
755 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
756 ctInfo.fColorType = ct;
757 ctInfo.fTransferColorType = ct;
759 }
760 }
761 }
762 // Format: VK_FORMAT_R16G16_SFLOAT
763 {
765 auto& info = this->getFormatInfo(format);
766 info.init(interface, physDev, properties, format);
767 if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
768 info.fColorTypeInfoCount = 1;
769 info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
770 int ctIdx = 0;
771 // Format: VK_FORMAT_R16G16_SFLOAT, Surface: kRG_F16
772 {
774 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
775 ctInfo.fColorType = ct;
776 ctInfo.fTransferColorType = ct;
778 }
779 }
780 }
781 // Format: VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM
782 {
784 auto& info = this->getFormatInfo(format);
785 if (fSupportsYcbcrConversion) {
786 info.init(interface, physDev, properties, format);
787 }
788 if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
789 info.fColorTypeInfoCount = 1;
790 info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
791 int ctIdx = 0;
792 // Format: VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM, Surface: kRGB_888x
793 {
795 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
796 ctInfo.fColorType = ct;
797 ctInfo.fTransferColorType = ct;
798 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag;
799 }
800 SkDEBUGCODE(info.fIsWrappedOnly = true;)
801 }
802 }
803 // Format: VK_FORMAT_G8_B8R8_2PLANE_420_UNORM
804 {
806 auto& info = this->getFormatInfo(format);
807 if (fSupportsYcbcrConversion) {
808 info.init(interface, physDev, properties, format);
809 }
810 if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
811 info.fColorTypeInfoCount = 1;
812 info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
813 int ctIdx = 0;
814 // Format: VK_FORMAT_G8_B8R8_2PLANE_420_UNORM, Surface: kRGB_888x
815 {
817 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
818 ctInfo.fColorType = ct;
819 ctInfo.fTransferColorType = ct;
820 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag;
821 }
822 SkDEBUGCODE(info.fIsWrappedOnly = true;)
823 }
824 }
825 // Format: VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK
826 {
828 auto& info = this->getFormatInfo(format);
829 info.init(interface, physDev, properties, format);
830 if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
831 info.fColorTypeInfoCount = 1;
832 info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
833 int ctIdx = 0;
834 // Format: VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK, Surface: kRGB_888x
835 {
837 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
838 ctInfo.fColorType = ct;
839 ctInfo.fTransferColorType = ct;
840 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag;
841 }
842 }
843 }
844
845 // Format: VK_FORMAT_BC1_RGB_UNORM_BLOCK
846 {
848 auto& info = this->getFormatInfo(format);
849 info.init(interface, physDev, properties, format);
850 if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
851 info.fColorTypeInfoCount = 1;
852 info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
853 int ctIdx = 0;
854 // Format: VK_FORMAT_BC1_RGB_UNORM_BLOCK, Surface: kRGB_888x
855 {
857 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
858 ctInfo.fColorType = ct;
859 ctInfo.fTransferColorType = ct;
860 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag;
861 }
862 }
863 }
864
865 // Format: VK_FORMAT_BC1_RGBA_UNORM_BLOCK
866 {
868 auto& info = this->getFormatInfo(format);
869 info.init(interface, physDev, properties, format);
870 if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
871 info.fColorTypeInfoCount = 1;
872 info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
873 int ctIdx = 0;
874 // Format: VK_FORMAT_BC1_RGBA_UNORM_BLOCK, Surface: kRGB_888x
875 {
877 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
878 ctInfo.fColorType = ct;
879 ctInfo.fTransferColorType = ct;
880 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag;
881 }
882 }
883 }
884
885 ////////////////////////////////////////////////////////////////////////////
886 // Map SkColorType (used for creating Surfaces) to VkFormats. The order in which the formats are
887 // passed into the setColorType function indicates the priority in selecting which format we use
888 // for a given SkColorType.
889 typedef SkColorType ct;
890
891 this->setColorType(ct::kAlpha_8_SkColorType, { VK_FORMAT_R8_UNORM });
899 this->setColorType(ct::kR8G8_unorm_SkColorType, { VK_FORMAT_R8G8_UNORM });
903 this->setColorType(ct::kGray_8_SkColorType, { VK_FORMAT_R8_UNORM });
904 this->setColorType(ct::kA16_float_SkColorType, { VK_FORMAT_R16_SFLOAT });
906 this->setColorType(ct::kA16_unorm_SkColorType, { VK_FORMAT_R16_UNORM });
910}
911
912namespace {
913void set_ds_flags_to_format(VkFormat& slot, VkFormat format) {
914 if (slot == VK_FORMAT_UNDEFINED) {
915 slot = format;
916 }
917}
918} // namespace
919
920void VulkanCaps::initDepthStencilFormatTable(const skgpu::VulkanInterface* interface,
921 VkPhysicalDevice physDev,
922 const VkPhysicalDeviceProperties& properties) {
923 static_assert(std::size(kDepthStencilVkFormats) == VulkanCaps::kNumDepthStencilVkFormats,
924 "Size of DepthStencilVkFormats array must match static value in header");
925
926 using DSFlags = SkEnumBitMask<DepthStencilFlags>;
927 constexpr DSFlags stencilFlags = DepthStencilFlags::kStencil;
928 constexpr DSFlags depthFlags = DepthStencilFlags::kDepth;
929 constexpr DSFlags dsFlags = DepthStencilFlags::kDepthStencil;
930
931 std::fill_n(fDepthStencilFlagsToFormatTable, kNumDepthStencilFlags, VK_FORMAT_UNDEFINED);
932 // Format: VK_FORMAT_S8_UINT
933 {
935 auto& info = this->getDepthStencilFormatInfo(format);
936 info.init(interface, physDev, properties, format);
937 if (info.fFormatProperties.optimalTilingFeatures &
939 set_ds_flags_to_format(fDepthStencilFlagsToFormatTable[stencilFlags.value()], format);
940 }
941 }
942 // Format: VK_FORMAT_D16_UNORM
943 {
944 // Qualcomm drivers will report OUT_OF_HOST_MEMORY when binding memory to a VkImage with
945 // D16_UNORM in a protected context. Using D32_SFLOAT succeeds, so clearly it's not actually
946 // out of memory. D16_UNORM appears to function correctly in unprotected contexts.
947 const bool disableD16InProtected = this->protectedSupport() &&
948 kQualcomm_VkVendor == properties.vendorID;
949 if (!disableD16InProtected) {
951 auto& info = this->getDepthStencilFormatInfo(format);
952 info.init(interface, physDev, properties, format);
953 if (info.fFormatProperties.optimalTilingFeatures &
955 set_ds_flags_to_format(fDepthStencilFlagsToFormatTable[depthFlags.value()], format);
956 }
957 }
958 }
959 // Format: VK_FORMAT_D32_SFLOAT
960 {
962 auto& info = this->getDepthStencilFormatInfo(format);
963 info.init(interface, physDev, properties, format);
964 if (info.fFormatProperties.optimalTilingFeatures &
966 set_ds_flags_to_format(fDepthStencilFlagsToFormatTable[depthFlags.value()], format);
967 }
968 }
969 // Format: VK_FORMAT_D24_UNORM_S8_UINT
970 {
972 auto& info = this->getDepthStencilFormatInfo(format);
973 info.init(interface, physDev, properties, format);
974 if (info.fFormatProperties.optimalTilingFeatures &
976 set_ds_flags_to_format(fDepthStencilFlagsToFormatTable[stencilFlags.value()], format);
977 set_ds_flags_to_format(fDepthStencilFlagsToFormatTable[depthFlags.value()], format);
978 set_ds_flags_to_format(fDepthStencilFlagsToFormatTable[dsFlags.value()], format);
979 }
980 }
981 // Format: VK_FORMAT_D32_SFLOAT_S8_UINT
982 {
984 auto& info = this->getDepthStencilFormatInfo(format);
985 info.init(interface, physDev, properties, format);
986 if (info.fFormatProperties.optimalTilingFeatures &
988 set_ds_flags_to_format(fDepthStencilFlagsToFormatTable[stencilFlags.value()], format);
989 set_ds_flags_to_format(fDepthStencilFlagsToFormatTable[depthFlags.value()], format);
990 set_ds_flags_to_format(fDepthStencilFlagsToFormatTable[dsFlags.value()], format);
991 }
992 }
993}
994
995void VulkanCaps::SupportedSampleCounts::initSampleCounts(const skgpu::VulkanInterface* interface,
996 VkPhysicalDevice physDev,
997 const VkPhysicalDeviceProperties& physProps,
1000 VkImageFormatProperties properties;
1001
1003 // VULKAN_CALL_RESULT requires a VulkanSharedContext for tracking DEVICE_LOST, but VulkanCaps
1004 // are initialized before a VulkanSharedContext is available. The _NOCHECK variant only requires
1005 // a VulkanInterface, so we can use that and log failures manually.
1007 result,
1008 GetPhysicalDeviceImageFormatProperties(physDev,
1009 format,
1012 usage,
1013 0, // createFlags
1014 &properties));
1015 if (result != VK_SUCCESS) {
1016 SKGPU_LOG_W("Vulkan call GetPhysicalDeviceImageFormatProperties failed: %d", result);
1017 return;
1018 }
1019
1022 fSampleCounts.push_back(1);
1023 }
1024 if (kImagination_VkVendor == physProps.vendorID) {
1025 // MSAA does not work on imagination
1026 return;
1027 }
1028 if (kIntel_VkVendor == physProps.vendorID) {
1029 // MSAA doesn't work well on Intel GPUs chromium:527565, chromium:983926
1030 return;
1031 }
1033 fSampleCounts.push_back(2);
1034 }
1036 fSampleCounts.push_back(4);
1037 }
1039 fSampleCounts.push_back(8);
1040 }
1042 fSampleCounts.push_back(16);
1043 }
1044 // Standard sample locations are not defined for more than 16 samples, and we don't need more
1045 // than 16. Omit 32 and 64.
1046}
1047
1048bool VulkanCaps::SupportedSampleCounts::isSampleCountSupported(int requestedCount) const {
1049 requestedCount = std::max(1, requestedCount);
1050 for (int i = 0; i < fSampleCounts.size(); i++) {
1051 if (fSampleCounts[i] == requestedCount) {
1052 return true;
1053 } else if (requestedCount < fSampleCounts[i]) {
1054 return false;
1055 }
1056 }
1057 return false;
1058}
1059
1060
1061namespace {
1062bool is_texturable(VkFormatFeatureFlags flags) {
1065}
1066
1067bool is_renderable(VkFormatFeatureFlags flags) {
1069}
1070
1071bool is_storage(VkFormatFeatureFlags flags) {
1073}
1074
1075bool is_transfer_src(VkFormatFeatureFlags flags) {
1077}
1078
1079bool is_transfer_dst(VkFormatFeatureFlags flags) {
1081}
1082}
1083
1085 VkPhysicalDevice physDev,
1086 const VkPhysicalDeviceProperties& properties,
1087 VkFormat format) {
1088 memset(&fFormatProperties, 0, sizeof(VkFormatProperties));
1089 VULKAN_CALL(interface, GetPhysicalDeviceFormatProperties(physDev, format, &fFormatProperties));
1090
1091 if (is_renderable(fFormatProperties.optimalTilingFeatures)) {
1092 // We make all renderable images support being used as input attachment
1098 this->fSupportedSampleCounts.initSampleCounts(interface, physDev, properties, format,
1099 usageFlags);
1100 }
1101}
1102
1103bool VulkanCaps::FormatInfo::isTexturable(VkImageTiling imageTiling) const {
1104 switch (imageTiling) {
1106 return is_texturable(fFormatProperties.optimalTilingFeatures);
1108 return is_texturable(fFormatProperties.linearTilingFeatures);
1109 default:
1110 return false;
1111 }
1113}
1114
1115bool VulkanCaps::FormatInfo::isRenderable(VkImageTiling imageTiling,
1116 uint32_t sampleCount) const {
1117 if (!fSupportedSampleCounts.isSampleCountSupported(sampleCount)) {
1118 return false;
1119 }
1120 switch (imageTiling) {
1122 return is_renderable(fFormatProperties.optimalTilingFeatures);
1124 return is_renderable(fFormatProperties.linearTilingFeatures);
1125 default:
1126 return false;
1127 }
1129}
1130
1131bool VulkanCaps::FormatInfo::isStorage(VkImageTiling imageTiling) const {
1132 switch (imageTiling) {
1134 return is_storage(fFormatProperties.optimalTilingFeatures);
1136 return is_storage(fFormatProperties.linearTilingFeatures);
1137 default:
1138 return false;
1139 }
1141}
1142
1143bool VulkanCaps::FormatInfo::isTransferSrc(VkImageTiling imageTiling) const {
1144 switch (imageTiling) {
1146 return is_transfer_src(fFormatProperties.optimalTilingFeatures);
1148 return is_transfer_src(fFormatProperties.linearTilingFeatures);
1149 default:
1150 return false;
1151 }
1153}
1154
1155bool VulkanCaps::FormatInfo::isTransferDst(VkImageTiling imageTiling) const {
1156 switch (imageTiling) {
1158 return is_transfer_dst(fFormatProperties.optimalTilingFeatures);
1160 return is_transfer_dst(fFormatProperties.linearTilingFeatures);
1161 default:
1162 return false;
1163 }
1165}
1166
1167void VulkanCaps::setColorType(SkColorType colorType, std::initializer_list<VkFormat> formats) {
1168 int idx = static_cast<int>(colorType);
1169 for (auto it = formats.begin(); it != formats.end(); ++it) {
1170 const auto& info = this->getFormatInfo(*it);
1171 for (int i = 0; i < info.fColorTypeInfoCount; ++i) {
1172 if (info.fColorTypeInfos[i].fColorType == colorType) {
1173 fColorTypeToFormatTable[idx] = *it;
1174 return;
1175 }
1176 }
1177 }
1178}
1179
1180VkFormat VulkanCaps::getFormatFromColorType(SkColorType colorType) const {
1181 int idx = static_cast<int>(colorType);
1182 return fColorTypeToFormatTable[idx];
1183}
1184
1185VulkanCaps::FormatInfo& VulkanCaps::getFormatInfo(VkFormat format) {
1186 static_assert(std::size(kVkFormats) == VulkanCaps::kNumVkFormats,
1187 "Size of VkFormats array must match static value in header");
1188 for (size_t i = 0; i < std::size(kVkFormats); ++i) {
1189 if (kVkFormats[i] == format) {
1190 return fFormatTable[i];
1191 }
1192 }
1193 static FormatInfo kInvalidFormat;
1194 return kInvalidFormat;
1195}
1196
1197const VulkanCaps::FormatInfo& VulkanCaps::getFormatInfo(VkFormat format) const {
1198 VulkanCaps* nonConstThis = const_cast<VulkanCaps*>(this);
1199 return nonConstThis->getFormatInfo(format);
1200}
1201
1203 VkPhysicalDevice physDev,
1204 const VkPhysicalDeviceProperties& properties,
1205 VkFormat format) {
1206 memset(&fFormatProperties, 0, sizeof(VkFormatProperties));
1207 VULKAN_CALL(interface, GetPhysicalDeviceFormatProperties(physDev, format, &fFormatProperties));
1208
1209 if (this->isDepthStencilSupported(fFormatProperties.optimalTilingFeatures)) {
1211 fSupportedSampleCounts.initSampleCounts(interface, physDev, properties, format, usageFlags);
1212 }
1213}
1214
1215bool VulkanCaps::DepthStencilFormatInfo::isDepthStencilSupported(VkFormatFeatureFlags flags) const {
1217}
1218
1219VkFormat VulkanCaps::getFormatFromDepthStencilFlags(const SkEnumBitMask<DepthStencilFlags>& flags)
1220 const {
1221 return fDepthStencilFlagsToFormatTable[flags.value()];
1222}
1223
1224VulkanCaps::DepthStencilFormatInfo& VulkanCaps::getDepthStencilFormatInfo(VkFormat format) {
1225 static_assert(std::size(kDepthStencilVkFormats) == VulkanCaps::kNumDepthStencilVkFormats,
1226 "Size of VkFormats array must match static value in header");
1227 for (size_t i = 0; i < std::size(kDepthStencilVkFormats); ++i) {
1228 if (kVkFormats[i] == format) {
1229 return fDepthStencilFormatTable[i];
1230 }
1231 }
1232 static DepthStencilFormatInfo kInvalidFormat;
1233 return kInvalidFormat;
1234}
1235
1236const VulkanCaps::DepthStencilFormatInfo& VulkanCaps::getDepthStencilFormatInfo(VkFormat format)
1237 const {
1238 VulkanCaps* nonConstThis = const_cast<VulkanCaps*>(this);
1239 return nonConstThis->getDepthStencilFormatInfo(format);
1240}
1241
1242const Caps::ColorTypeInfo* VulkanCaps::getColorTypeInfo(SkColorType ct,
1243 const TextureInfo& textureInfo) const {
1244 VkFormat vkFormat = textureInfo.vulkanTextureSpec().fFormat;
1245 if (vkFormat == VK_FORMAT_UNDEFINED) {
1246 // If VkFormat is undefined but there is a valid YCbCr conversion associated with the
1247 // texture, then we know we are using an external format and can return color type
1248 // info representative of external format color information.
1249 return textureInfo.vulkanTextureSpec().fYcbcrConversionInfo.isValid()
1250 ? &fExternalFormatColorTypeInfo
1251 : nullptr;
1252 }
1253
1254 const FormatInfo& info = this->getFormatInfo(vkFormat);
1255 for (int i = 0; i < info.fColorTypeInfoCount; ++i) {
1256 const ColorTypeInfo& ctInfo = info.fColorTypeInfos[i];
1257 if (ctInfo.fColorType == ct) {
1258 return &ctInfo;
1259 }
1260 }
1261
1262 return nullptr;
1263}
1264
1265bool VulkanCaps::onIsTexturable(const TextureInfo& texInfo) const {
1266 VulkanTextureInfo vkInfo;
1267 if (!texInfo.getVulkanTextureInfo(&vkInfo)) {
1268 return false;
1269 }
1270
1271 // All images using external formats are required to be able to be sampled per Vulkan spec.
1272 // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkAndroidHardwareBufferFormatPropertiesANDROID.html#_description
1273 if (vkInfo.fFormat == VK_FORMAT_UNDEFINED && vkInfo.fYcbcrConversionInfo.isValid()) {
1274 return true;
1275 }
1276
1277 // Otherwise, we are working with a known format and can simply reference the format table info.
1278 const FormatInfo& info = this->getFormatInfo(vkInfo.fFormat);
1279 return info.isTexturable(vkInfo.fImageTiling);
1280}
1281
1282bool VulkanCaps::isRenderable(const TextureInfo& texInfo) const {
1283 VulkanTextureInfo vkInfo;
1284 if (!texInfo.getVulkanTextureInfo(&vkInfo)) {
1285 return false;
1286 }
1287
1288 const FormatInfo& info = this->getFormatInfo(vkInfo.fFormat);
1289 return info.isRenderable(vkInfo.fImageTiling, texInfo.numSamples());
1290}
1291
1292bool VulkanCaps::isStorage(const TextureInfo& texInfo) const {
1293 VulkanTextureInfo vkInfo;
1294 if (!texInfo.getVulkanTextureInfo(&vkInfo)) {
1295 return false;
1296 }
1297
1298 const FormatInfo& info = this->getFormatInfo(vkInfo.fFormat);
1299 return info.isStorage(vkInfo.fImageTiling);
1300}
1301
1303 const FormatInfo& info = this->getFormatInfo(vkInfo.fFormat);
1304 return info.isTransferSrc(vkInfo.fImageTiling);
1305}
1306
1308 const FormatInfo& info = this->getFormatInfo(vkInfo.fFormat);
1309 return info.isTransferDst(vkInfo.fImageTiling);
1310}
1311
1312bool VulkanCaps::supportsWritePixels(const TextureInfo& texInfo) const {
1313 VulkanTextureInfo vkInfo;
1314 if (!texInfo.getVulkanTextureInfo(&vkInfo)) {
1315 return false;
1316 }
1317
1318 // Can't write if it needs a YCbCr sampler
1319 if (VkFormatNeedsYcbcrSampler(vkInfo.fFormat)) {
1320 return false;
1321 }
1322
1323 if (vkInfo.fSampleCount > 1) {
1324 return false;
1325 }
1326
1328 return false;
1329 }
1330
1331 return true;
1332}
1333
1334bool VulkanCaps::supportsReadPixels(const TextureInfo& texInfo) const {
1335 if (texInfo.isProtected() == Protected::kYes) {
1336 return false;
1337 }
1338
1339 VulkanTextureInfo vkInfo;
1340 if (!texInfo.getVulkanTextureInfo(&vkInfo)) {
1341 return false;
1342 }
1343
1344 // Can't read if it needs a YCbCr sampler
1345 if (VkFormatNeedsYcbcrSampler(vkInfo.fFormat)) {
1346 return false;
1347 }
1348
1349 if (VkFormatIsCompressed(vkInfo.fFormat)) {
1350 return false;
1351 }
1352
1353 if (vkInfo.fSampleCount > 1) {
1354 return false;
1355 }
1356
1357 if (!SkToBool(vkInfo.fImageUsageFlags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT)) {
1358 return false;
1359 }
1360
1361 return true;
1362}
1363
1364std::pair<SkColorType, bool /*isRGBFormat*/> VulkanCaps::supportedWritePixelsColorType(
1365 SkColorType dstColorType,
1366 const TextureInfo& dstTextureInfo,
1367 SkColorType srcColorType) const {
1368 VulkanTextureInfo vkInfo;
1369 if (!dstTextureInfo.getVulkanTextureInfo(&vkInfo)) {
1370 return {kUnknown_SkColorType, false};
1371 }
1372
1373 // Can't write to YCbCr formats
1374 // TODO: Can't write to external formats, either
1375 if (VkFormatNeedsYcbcrSampler(vkInfo.fFormat)) {
1376 return {kUnknown_SkColorType, false};
1377 }
1378
1379 const FormatInfo& info = this->getFormatInfo(vkInfo.fFormat);
1380 for (int i = 0; i < info.fColorTypeInfoCount; ++i) {
1381 const auto& ctInfo = info.fColorTypeInfos[i];
1382 if (ctInfo.fColorType == dstColorType) {
1383 return {ctInfo.fTransferColorType, vkInfo.fFormat == VK_FORMAT_R8G8B8_UNORM};
1384 }
1385 }
1386
1387 return {kUnknown_SkColorType, false};
1388}
1389
1390std::pair<SkColorType, bool /*isRGBFormat*/> VulkanCaps::supportedReadPixelsColorType(
1391 SkColorType srcColorType,
1392 const TextureInfo& srcTextureInfo,
1393 SkColorType dstColorType) const {
1394 VulkanTextureInfo vkInfo;
1395 if (!srcTextureInfo.getVulkanTextureInfo(&vkInfo)) {
1396 return {kUnknown_SkColorType, false};
1397 }
1398
1399 // Can't read from YCbCr formats
1400 // TODO: external formats?
1401 if (VkFormatNeedsYcbcrSampler(vkInfo.fFormat)) {
1402 return {kUnknown_SkColorType, false};
1403 }
1404
1405 // TODO: handle compressed formats
1406 if (VkFormatIsCompressed(vkInfo.fFormat)) {
1407 SkASSERT(this->isTexturable(vkInfo));
1408 return {kUnknown_SkColorType, false};
1409 }
1410
1411 const FormatInfo& info = this->getFormatInfo(vkInfo.fFormat);
1412 for (int i = 0; i < info.fColorTypeInfoCount; ++i) {
1413 const auto& ctInfo = info.fColorTypeInfos[i];
1414 if (ctInfo.fColorType == srcColorType) {
1415 return {ctInfo.fTransferColorType, vkInfo.fFormat == VK_FORMAT_R8G8B8_UNORM};
1416 }
1417 }
1418
1419 return {kUnknown_SkColorType, false};
1420}
1421
1423 const RenderPassDesc& renderPassDesc) const {
1424 UniqueKey pipelineKey;
1425 {
1428
1429 VulkanRenderPass::VulkanRenderPassMetaData rpMetaData {renderPassDesc};
1430
1431 // Reserve 3 uint32s for the render step id, paint id, and write swizzle.
1432 static constexpr int kUint32sNeededForPipelineInfo = 3;
1433 // The uint32s needed for a RenderPass is variable number, so consult rpMetaData to
1434 // determine how many to reserve.
1435 UniqueKey::Builder builder(&pipelineKey,
1437 kUint32sNeededForPipelineInfo + rpMetaData.fUint32DataCnt,
1438 "GraphicsPipeline");
1439
1440 int idx = 0;
1441 // Add GraphicsPipelineDesc information
1442 builder[idx++] = pipelineDesc.renderStepID();
1443 builder[idx++] = pipelineDesc.paintParamsID().asUInt();
1444 // Add RenderPass info relevant for pipeline creation that's not captured in RenderPass keys
1445 builder[idx++] = renderPassDesc.fWriteSwizzle.asKey();
1446 // Add RenderPassDesc information
1447 VulkanRenderPass::AddRenderPassInfoToKey(rpMetaData, builder, idx, /*compatibleOnly=*/true);
1448
1449 builder.finish();
1450 }
1451
1452 return pipelineKey;
1453}
1454
1456 GraphiteResourceKey samplerKey;
1457 const SkSpan<const uint32_t>& samplerData = samplerDesc.asSpan();
1458 static const ResourceType kSamplerType = GraphiteResourceKey::GenerateResourceType();
1459 // Non-format ycbcr and sampler information are guaranteed to fit within one uint32, so the size
1460 // of the returned span accurately captures the quantity of uint32s needed whether the sampler
1461 // is immutable or not.
1462 GraphiteResourceKey::Builder builder(&samplerKey, kSamplerType, samplerData.size(),
1464
1465 for (size_t i = 0; i < samplerData.size(); i++) {
1466 builder[i] = samplerData[i];
1467 }
1468
1469 builder.finish();
1470 return samplerKey;
1471}
1472
1474 const TextureInfo& info,
1476 Shareable shareable,
1477 GraphiteResourceKey* key) const {
1478 SkASSERT(!dimensions.isEmpty());
1479
1480 const VulkanTextureSpec& vkSpec = info.vulkanTextureSpec();
1481 // We expect that the VkFormat enum is at most a 32-bit value.
1482 static_assert(VK_FORMAT_MAX_ENUM == 0x7FFFFFFF);
1483 // We should either be using a known VkFormat or have a valid ycbcr conversion.
1485
1486 uint32_t format = static_cast<uint32_t>(vkSpec.fFormat);
1487 uint32_t samples = SamplesToKey(info.numSamples());
1488 // We don't have to key the number of mip levels because it is inherit in the combination of
1489 // isMipped and dimensions.
1490 bool isMipped = info.mipmapped() == Mipmapped::kYes;
1491 Protected isProtected = info.isProtected();
1492
1493 // Confirm all the below parts of the key can fit in a single uint32_t. The sum of the shift
1494 // amounts in the asserts must be less than or equal to 32. vkSpec.fFlags will go into its
1495 // own 32-bit block.
1496 SkASSERT(samples < (1u << 3)); // sample key is first 3 bits
1497 SkASSERT(static_cast<uint32_t>(isMipped) < (1u << 1)); // isMapped is 4th bit
1498 SkASSERT(static_cast<uint32_t>(isProtected) < (1u << 1)); // isProtected is 5th bit
1499 SkASSERT(vkSpec.fImageTiling < (1u << 1)); // imageTiling is 6th bit
1500 SkASSERT(vkSpec.fSharingMode < (1u << 1)); // sharingMode is 7th bit
1501 SkASSERT(vkSpec.fAspectMask < (1u << 11)); // aspectMask is bits 8 - 19
1502 SkASSERT(vkSpec.fImageUsageFlags < (1u << 12)); // imageUsageFlags are bits 20-32
1503
1504 // We need two uint32_ts for dimensions, 1 for format, and 2 for the rest of the information.
1505 static constexpr int kNum32DataCntNoYcbcr = 2 + 1 + 2;
1506 int num32DataCnt = kNum32DataCntNoYcbcr;
1507
1508 // If a texture w/ an external format is being used, that information must also be appended.
1509 const VulkanYcbcrConversionInfo& ycbcrInfo = info.vulkanTextureSpec().fYcbcrConversionInfo;
1510 num32DataCnt += ycbcrPackaging::numInt32sNeeded(ycbcrInfo);
1511
1512 GraphiteResourceKey::Builder builder(key, type, num32DataCnt, shareable);
1513
1514 int i = 0;
1515 builder[i++] = dimensions.width();
1516 builder[i++] = dimensions.height();
1517
1518 if (ycbcrInfo.isValid()) {
1519 SkASSERT(ycbcrInfo.fFormat != VK_FORMAT_UNDEFINED || ycbcrInfo.fExternalFormat != 0);
1520 bool useExternalFormat = ycbcrInfo.fFormat == VK_FORMAT_UNDEFINED;
1522 if (useExternalFormat) {
1523 builder[i++] = (uint32_t)ycbcrInfo.fExternalFormat;
1524 builder[i++] = (uint32_t)(ycbcrInfo.fExternalFormat >> 32);
1525 } else {
1526 builder[i++] = ycbcrInfo.fFormat;
1527 }
1528 } else {
1529 builder[i++] = format;
1530 }
1531
1532 builder[i++] = (static_cast<uint32_t>(vkSpec.fFlags));
1533 builder[i++] = (samples << 0 ) |
1534 (static_cast<uint32_t>(isMipped) << 3 ) |
1535 (static_cast<uint32_t>(isProtected) << 4 ) |
1536 (static_cast<uint32_t>(vkSpec.fImageTiling) << 5 ) |
1537 (static_cast<uint32_t>(vkSpec.fSharingMode) << 6 ) |
1538 (static_cast<uint32_t>(vkSpec.fAspectMask) << 7 ) |
1539 (static_cast<uint32_t>(vkSpec.fImageUsageFlags) << 19);
1540 SkASSERT(i == num32DataCnt);
1541}
1542
1544 if (proxy) {
1545 const skgpu::VulkanYcbcrConversionInfo& ycbcrConversionInfo =
1546 proxy->textureInfo().vulkanTextureSpec().fYcbcrConversionInfo;
1547
1548 if (ycbcrConversionInfo.isValid()) {
1549 ImmutableSamplerInfo immutableSamplerInfo;
1550 // ycbcrConversionInfo's fFormat being VK_FORMAT_UNDEFINED indicates we are using an
1551 // external format rather than a known VkFormat.
1552 immutableSamplerInfo.fFormat = ycbcrConversionInfo.fFormat == VK_FORMAT_UNDEFINED
1553 ? ycbcrConversionInfo.fExternalFormat
1554 : ycbcrConversionInfo.fFormat;
1555 immutableSamplerInfo.fNonFormatYcbcrConversionInfo =
1556 ycbcrPackaging::nonFormatInfoAsUInt32(ycbcrConversionInfo);
1557 return immutableSamplerInfo;
1558 }
1559 }
1560
1561 // If the proxy is null or the YCbCr conversion for that proxy is invalid, then return a
1562 // default ImmutableSamplerInfo struct.
1563 return {};
1564}
1565
1566} // 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
static SkColorType colorType(AImageDecoder *decoder, const AImageDecoderHeaderInfo *headerInfo)
SkTextureCompressionType
SkDEBUGCODE(SK_SPI) SkThreadID SkGetThreadID()
static constexpr bool SkToBool(const T &x)
Definition: SkTo.h:35
#define VULKAN_CALL(IFACE, X)
#define VULKAN_CALL_RESULT_NOCHECK(IFACE, RESULT, X)
GLenum type
constexpr size_t size() const
Definition: SkSpan_impl.h:95
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()
Definition: ResourceKey.cpp:27
size_t fRequiredStorageBufferAlignment
Definition: Caps.h:359
bool fSupportsAHardwareBufferImages
Definition: Caps.h:376
size_t fRequiredUniformBufferAlignment
Definition: Caps.h:358
bool isTexturable(const TextureInfo &) const
Definition: Caps.cpp:66
bool protectedSupport() const
Definition: Caps.h:226
std::unique_ptr< SkSL::ShaderCaps > fShaderCaps
Definition: Caps.h:363
static uint32_t SamplesToKey(uint32_t numSamples)
Definition: Caps.h:314
bool fProtectedSupport
Definition: Caps.h:366
void finishInitialization(const ContextOptions &)
Definition: Caps.cpp:29
size_t fRequiredTransferBufferAlignment
Definition: Caps.h:360
ResourceBindingRequirements fResourceBindingReqs
Definition: Caps.h:383
int fDefaultMSAASamples
Definition: Caps.h:357
UniquePaintParamsID paintParamsID() const
uint32_t numSamples() const
Definition: TextureInfo.h:78
Protected isProtected() const
Definition: TextureInfo.h:80
const TextureInfo & textureInfo() const
Definition: TextureProxy.h:38
TextureInfo getDefaultDepthStencilTextureInfo(SkEnumBitMask< DepthStencilFlags >, uint32_t sampleCount, Protected) const override
Definition: VulkanCaps.cpp:355
ImmutableSamplerInfo getImmutableSamplerInfo(const TextureProxy *proxy) const override
void buildKeyForTexture(SkISize dimensions, const TextureInfo &, ResourceType, Shareable, GraphiteResourceKey *) const override
TextureInfo getTextureInfoForSampledCopy(const TextureInfo &textureInfo, Mipmapped mipmapped) const override
Definition: VulkanCaps.cpp:258
UniqueKey makeGraphicsPipelineKey(const GraphicsPipelineDesc &, const RenderPassDesc &) const override
GraphiteResourceKey makeSamplerKey(const SamplerDesc &) const override
bool isStorage(const TextureInfo &) const override
bool isRenderable(const TextureInfo &) const override
TextureInfo getDefaultSampledTextureInfo(SkColorType, Mipmapped mipmapped, Protected, Renderable) const override
Definition: VulkanCaps.cpp:223
bool isTransferSrc(const VulkanTextureInfo &) const
bool isTransferDst(const VulkanTextureInfo &) const
TextureInfo getDefaultCompressedTextureInfo(SkTextureCompressionType, Mipmapped mipmapped, Protected) const override
Definition: VulkanCaps.cpp:291
TextureInfo getDefaultMSAATextureInfo(const TextureInfo &singleSampledInfo, Discardable discardable) const override
Definition: VulkanCaps.cpp:317
uint32_t channelMask(const TextureInfo &) const override
Definition: VulkanCaps.cpp:404
TextureInfo getDefaultStorageTextureInfo(SkColorType) const override
Definition: VulkanCaps.cpp:380
VulkanCaps(const ContextOptions &, const skgpu::VulkanInterface *, VkPhysicalDevice, uint32_t physicalDeviceVersion, const VkPhysicalDeviceFeatures2 *, const skgpu::VulkanExtensions *, Protected)
Definition: VulkanCaps.cpp:35
static void AddRenderPassInfoToKey(VulkanRenderPassMetaData &rpMetaData, ResourceKey::Builder &builder, int &builderIdx, bool compatibleOnly)
FlutterSemanticsFlag flags
GAsyncResult * result
uint32_t uint32_t * format
static float max(float r, float g, float b)
Definition: hsl.cpp:49
static float min(float r, float g, float b)
Definition: hsl.cpp:48
static bool init()
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
int numInt32sNeeded(const VulkanYcbcrConversionInfo &conversionInfo)
uint32_t nonFormatInfoAsUInt32(const VulkanYcbcrConversionInfo &conversionInfo)
static constexpr VkFormat kDepthStencilVkFormats[]
Definition: VulkanCaps.cpp:215
static constexpr VkFormat kVkFormats[]
Definition: VulkanCaps.cpp:190
uint32_t ResourceType
static const skgpu::UniqueKey::Domain kGraphicsPipelineDomain
Definition: MtlCaps.mm:895
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)
Definition: SkSize.h:16
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
Definition: vulkan_core.h:3022
VkMemoryPropertyFlags propertyFlags
Definition: vulkan_core.h:3043
uint32_t maxUniformBufferRange
Definition: vulkan_core.h:3112
VkDeviceSize minStorageBufferOffsetAlignment
Definition: vulkan_core.h:3175
VkDeviceSize minUniformBufferOffsetAlignment
Definition: vulkan_core.h:3174
uint32_t maxVertexInputAttributes
Definition: vulkan_core.h:3135
VkMemoryType memoryTypes[VK_MAX_MEMORY_TYPES]
Definition: vulkan_core.h:3216
char deviceName[VK_MAX_PHYSICAL_DEVICE_NAME_SIZE]
Definition: vulkan_core.h:3235
VkPhysicalDeviceLimits limits
Definition: vulkan_core.h:3237
SkSpan< const uint32_t > asSpan() const
VulkanYcbcrConversionInfo fYcbcrConversionInfo
#define VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME
VkFlags VkMemoryPropertyFlags
Definition: vulkan_core.h:2410
VkFlags VkSampleCountFlags
Definition: vulkan_core.h:2349
@ VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT
Definition: vulkan_core.h:2271
@ VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT
Definition: vulkan_core.h:2267
@ VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT
Definition: vulkan_core.h:2268
@ VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT
Definition: vulkan_core.h:2260
@ VK_FORMAT_FEATURE_TRANSFER_DST_BIT
Definition: vulkan_core.h:2273
@ VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT
Definition: vulkan_core.h:2259
@ VK_FORMAT_FEATURE_TRANSFER_SRC_BIT
Definition: vulkan_core.h:2272
@ VK_SHARING_MODE_EXCLUSIVE
Definition: vulkan_core.h:1813
@ VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT
Definition: vulkan_core.h:2403
@ VK_MEMORY_PROPERTY_PROTECTED_BIT
Definition: vulkan_core.h:2404
VkFlags VkImageUsageFlags
Definition: vulkan_core.h:2382
@ VK_IMAGE_CREATE_PROTECTED_BIT
Definition: vulkan_core.h:2320
VkImageTiling
Definition: vulkan_core.h:1766
@ VK_IMAGE_TILING_OPTIMAL
Definition: vulkan_core.h:1767
@ VK_IMAGE_TILING_LINEAR
Definition: vulkan_core.h:1768
@ VK_IMAGE_ASPECT_COLOR_BIT
Definition: vulkan_core.h:2238
@ VK_IMAGE_USAGE_TRANSFER_DST_BIT
Definition: vulkan_core.h:2353
@ VK_IMAGE_USAGE_SAMPLED_BIT
Definition: vulkan_core.h:2354
@ VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT
Definition: vulkan_core.h:2357
@ VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT
Definition: vulkan_core.h:2359
@ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT
Definition: vulkan_core.h:2356
@ VK_IMAGE_USAGE_TRANSFER_SRC_BIT
Definition: vulkan_core.h:2352
@ VK_IMAGE_USAGE_STORAGE_BIT
Definition: vulkan_core.h:2355
@ VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT
Definition: vulkan_core.h:2358
@ VK_SAMPLE_COUNT_8_BIT
Definition: vulkan_core.h:2343
@ VK_SAMPLE_COUNT_2_BIT
Definition: vulkan_core.h:2341
@ VK_SAMPLE_COUNT_1_BIT
Definition: vulkan_core.h:2340
@ VK_SAMPLE_COUNT_4_BIT
Definition: vulkan_core.h:2342
@ VK_SAMPLE_COUNT_16_BIT
Definition: vulkan_core.h:2344
VkFlags VkFormatFeatureFlags
Definition: vulkan_core.h:2307
@ VK_IMAGE_TYPE_2D
Definition: vulkan_core.h:1775
#define VK_EXT_DEVICE_FAULT_EXTENSION_NAME
VkResult
Definition: vulkan_core.h:140
@ VK_SUCCESS
Definition: vulkan_core.h:141
VkFormat
Definition: vulkan_core.h:1458
@ VK_FORMAT_R16G16B16A16_UNORM
Definition: vulkan_core.h:1550
@ VK_FORMAT_R8G8B8A8_SRGB
Definition: vulkan_core.h:1502
@ VK_FORMAT_R8G8B8_UNORM
Definition: vulkan_core.h:1482
@ VK_FORMAT_D24_UNORM_S8_UINT
Definition: vulkan_core.h:1588
@ VK_FORMAT_D32_SFLOAT
Definition: vulkan_core.h:1585
@ VK_FORMAT_B8G8R8A8_UNORM
Definition: vulkan_core.h:1503
@ VK_FORMAT_R16G16_SFLOAT
Definition: vulkan_core.h:1542
@ VK_FORMAT_B4G4R4A4_UNORM_PACK16
Definition: vulkan_core.h:1462
@ VK_FORMAT_R16_SFLOAT
Definition: vulkan_core.h:1535
@ VK_FORMAT_R8G8_UNORM
Definition: vulkan_core.h:1475
@ VK_FORMAT_S8_UINT
Definition: vulkan_core.h:1586
@ VK_FORMAT_R8_UNORM
Definition: vulkan_core.h:1468
@ VK_FORMAT_R5G6B5_UNORM_PACK16
Definition: vulkan_core.h:1463
@ VK_FORMAT_R4G4B4A4_UNORM_PACK16
Definition: vulkan_core.h:1461
@ VK_FORMAT_A2B10G10R10_UNORM_PACK32
Definition: vulkan_core.h:1523
@ VK_FORMAT_R8G8B8A8_UNORM
Definition: vulkan_core.h:1496
@ VK_FORMAT_UNDEFINED
Definition: vulkan_core.h:1459
@ VK_FORMAT_BC1_RGB_UNORM_BLOCK
Definition: vulkan_core.h:1590
@ VK_FORMAT_R16_UNORM
Definition: vulkan_core.h:1529
@ VK_FORMAT_D16_UNORM
Definition: vulkan_core.h:1583
@ VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM
Definition: vulkan_core.h:1646
@ VK_FORMAT_R16G16B16A16_SFLOAT
Definition: vulkan_core.h:1556
@ VK_FORMAT_R16G16_UNORM
Definition: vulkan_core.h:1536
@ VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK
Definition: vulkan_core.h:1606
@ VK_FORMAT_A2R10G10B10_UNORM_PACK32
Definition: vulkan_core.h:1517
@ VK_FORMAT_BC1_RGBA_UNORM_BLOCK
Definition: vulkan_core.h:1592
@ VK_FORMAT_G8_B8R8_2PLANE_420_UNORM
Definition: vulkan_core.h:1647
@ VK_FORMAT_D32_SFLOAT_S8_UINT
Definition: vulkan_core.h:1589
@ VK_FORMAT_MAX_ENUM
Definition: vulkan_core.h:1763
@ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES
Definition: vulkan_core.h:296
@ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2
Definition: vulkan_core.h:277