xref: /aosp_15_r20/external/skia/src/gpu/ganesh/vk/GrVkCaps.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2015 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "src/gpu/ganesh/vk/GrVkCaps.h"
9 
10 #include "include/core/SkRect.h"
11 #include "include/core/SkSize.h"
12 #include "include/core/SkTextureCompressionType.h"
13 #include "include/core/SkTypes.h"
14 #include "include/gpu/GpuTypes.h"
15 #include "include/gpu/ganesh/GrBackendSurface.h"
16 #include "include/gpu/ganesh/GrContextOptions.h"
17 #include "include/gpu/ganesh/vk/GrVkBackendSurface.h"
18 #include "include/gpu/vk/VulkanExtensions.h"
19 #include "include/gpu/vk/VulkanTypes.h"
20 #include "src/core/SkCompressedDataUtils.h"
21 #include "src/gpu/KeyBuilder.h"
22 #include "src/gpu/ganesh/GrBackendUtils.h"
23 #include "src/gpu/ganesh/GrPipeline.h"
24 #include "src/gpu/ganesh/GrProgramDesc.h"
25 #include "src/gpu/ganesh/GrProgramInfo.h"
26 #include "src/gpu/ganesh/GrRenderTarget.h"
27 #include "src/gpu/ganesh/GrRenderTargetProxy.h"
28 #include "src/gpu/ganesh/GrShaderCaps.h"
29 #include "src/gpu/ganesh/GrStencilSettings.h"
30 #include "src/gpu/ganesh/GrSurface.h"
31 #include "src/gpu/ganesh/GrSurfaceProxy.h"
32 #include "src/gpu/ganesh/GrXferProcessor.h"
33 #include "src/gpu/ganesh/TestFormatColorTypeCombination.h"
34 #include "src/gpu/ganesh/vk/GrVkGpu.h"
35 #include "src/gpu/ganesh/vk/GrVkImage.h"
36 #include "src/gpu/ganesh/vk/GrVkRenderPass.h"
37 #include "src/gpu/ganesh/vk/GrVkRenderTarget.h"
38 #include "src/gpu/ganesh/vk/GrVkSampler.h"
39 #include "src/gpu/ganesh/vk/GrVkTexture.h"
40 #include "src/gpu/ganesh/vk/GrVkUniformHandler.h"
41 #include "src/gpu/ganesh/vk/GrVkUtil.h"
42 #include "src/gpu/vk/VulkanUtilsPriv.h"
43 
44 #include <limits.h>
45 #include <algorithm>
46 #include <array>
47 #include <cstring>
48 #include <memory>
49 
50 #ifdef SK_BUILD_FOR_ANDROID
51 #include <sys/system_properties.h>
52 #endif
53 
GrVkCaps(const GrContextOptions & contextOptions,const skgpu::VulkanInterface * vkInterface,VkPhysicalDevice physDev,const VkPhysicalDeviceFeatures2 & features,uint32_t instanceVersion,uint32_t physicalDeviceVersion,const skgpu::VulkanExtensions & extensions,GrProtected isProtected)54 GrVkCaps::GrVkCaps(const GrContextOptions& contextOptions,
55                    const skgpu::VulkanInterface* vkInterface,
56                    VkPhysicalDevice physDev,
57                    const VkPhysicalDeviceFeatures2& features,
58                    uint32_t instanceVersion,
59                    uint32_t physicalDeviceVersion,
60                    const skgpu::VulkanExtensions& extensions,
61                    GrProtected isProtected)
62         : INHERITED(contextOptions) {
63     /**************************************************************************
64      * GrCaps fields
65      **************************************************************************/
66     fMipmapSupport = true;   // always available in Vulkan
67     fAnisoSupport = true;   // always available in Vulkan
68     fNPOTTextureTileSupport = true;  // always available in Vulkan
69     fReuseScratchTextures = true; //TODO: figure this out
70     fGpuTracingSupport = false; //TODO: figure this out
71     fOversizedStencilSupport = false; //TODO: figure this out
72     fDrawInstancedSupport = true;
73 
74     fSemaphoreSupport = true;   // always available in Vulkan
75     fBackendSemaphoreSupport = true;
76     fFinishedProcAsyncCallbackSupport = true;
77     fCrossContextTextureSupport = true;
78     fHalfFloatVertexAttributeSupport = true;
79 
80     // We always copy in/out of a transfer buffer so it's trivial to support row bytes.
81     fReadPixelsRowBytesSupport = true;
82     fWritePixelsRowBytesSupport = true;
83 
84     fTransferFromBufferToTextureSupport = true;
85     fTransferFromSurfaceToBufferSupport = true;
86     fTransferFromBufferToBufferSupport  = true;
87 
88     fMaxRenderTargetSize = 4096; // minimum required by spec
89     fMaxTextureSize = 4096; // minimum required by spec
90 
91     fDynamicStateArrayGeometryProcessorTextureSupport = true;
92 
93     fTextureBarrierSupport = true;
94 
95     fShaderCaps = std::make_unique<GrShaderCaps>();
96 
97     this->init(contextOptions, vkInterface, physDev, features, physicalDeviceVersion, extensions,
98                isProtected);
99 }
100 
101 namespace {
102 /**
103  * This comes from section 37.1.6 of the Vulkan spec. Format is
104  * (<bits>|<tag>)_<block_size>_<texels_per_block>.
105  */
106 enum class FormatCompatibilityClass {
107     k8_1_1,
108     k16_2_1,
109     k24_3_1,
110     k32_4_1,
111     k64_8_1,
112     k10x6_64_6_1,
113     kBC1_RGB_8_16_1,
114     kBC1_RGBA_8_16,
115     kETC2_RGB_8_16,
116 };
117 }  // anonymous namespace
118 
format_compatibility_class(VkFormat format)119 static FormatCompatibilityClass format_compatibility_class(VkFormat format) {
120     switch (format) {
121         case VK_FORMAT_B8G8R8A8_UNORM:
122         case VK_FORMAT_R8G8B8A8_UNORM:
123         case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
124         case VK_FORMAT_A2R10G10B10_UNORM_PACK32:
125         case VK_FORMAT_R8G8B8A8_SRGB:
126         case VK_FORMAT_R16G16_UNORM:
127         case VK_FORMAT_R16G16_SFLOAT:
128             return FormatCompatibilityClass::k32_4_1;
129 
130         case VK_FORMAT_R8_UNORM:
131             return FormatCompatibilityClass::k8_1_1;
132 
133         case VK_FORMAT_R5G6B5_UNORM_PACK16:
134         case VK_FORMAT_B5G6R5_UNORM_PACK16:
135         case VK_FORMAT_R16_SFLOAT:
136         case VK_FORMAT_R8G8_UNORM:
137         case VK_FORMAT_B4G4R4A4_UNORM_PACK16:
138         case VK_FORMAT_R4G4B4A4_UNORM_PACK16:
139         case VK_FORMAT_R16_UNORM:
140             return FormatCompatibilityClass::k16_2_1;
141 
142         case VK_FORMAT_R16G16B16A16_SFLOAT:
143         case VK_FORMAT_R16G16B16A16_UNORM:
144             return FormatCompatibilityClass::k64_8_1;
145 
146         case VK_FORMAT_R8G8B8_UNORM:
147             return FormatCompatibilityClass::k24_3_1;
148 
149         case VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16:
150             return FormatCompatibilityClass::k10x6_64_6_1;
151 
152         case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK:
153             return FormatCompatibilityClass::kETC2_RGB_8_16;
154 
155         case VK_FORMAT_BC1_RGB_UNORM_BLOCK:
156             return FormatCompatibilityClass::kBC1_RGB_8_16_1;
157 
158         case VK_FORMAT_BC1_RGBA_UNORM_BLOCK:
159             return FormatCompatibilityClass::kBC1_RGBA_8_16;
160 
161         default:
162             SK_ABORT("Unsupported VkFormat");
163     }
164 }
165 
canCopyImage(VkFormat dstFormat,int dstSampleCnt,bool dstHasYcbcr,VkFormat srcFormat,int srcSampleCnt,bool srcHasYcbcr) const166 bool GrVkCaps::canCopyImage(VkFormat dstFormat, int dstSampleCnt, bool dstHasYcbcr,
167                             VkFormat srcFormat, int srcSampleCnt, bool srcHasYcbcr) const {
168     if ((dstSampleCnt > 1 || srcSampleCnt > 1) && dstSampleCnt != srcSampleCnt) {
169         return false;
170     }
171 
172     if (dstHasYcbcr || srcHasYcbcr) {
173         return false;
174     }
175 
176     // We require that all Vulkan GrSurfaces have been created with transfer_dst and transfer_src
177     // as image usage flags.
178     return format_compatibility_class(srcFormat) == format_compatibility_class(dstFormat);
179 }
180 
canCopyAsBlit(VkFormat dstFormat,int dstSampleCnt,bool dstIsLinear,bool dstHasYcbcr,VkFormat srcFormat,int srcSampleCnt,bool srcIsLinear,bool srcHasYcbcr) const181 bool GrVkCaps::canCopyAsBlit(VkFormat dstFormat, int dstSampleCnt, bool dstIsLinear,
182                              bool dstHasYcbcr, VkFormat srcFormat, int srcSampleCnt,
183                              bool srcIsLinear, bool srcHasYcbcr) const {
184     // We require that all vulkan GrSurfaces have been created with transfer_dst and transfer_src
185     // as image usage flags.
186     if (!this->formatCanBeDstofBlit(dstFormat, dstIsLinear) ||
187         !this->formatCanBeSrcofBlit(srcFormat, srcIsLinear)) {
188         return false;
189     }
190 
191     // We cannot blit images that are multisampled. Will need to figure out if we can blit the
192     // resolved msaa though.
193     if (dstSampleCnt > 1 || srcSampleCnt > 1) {
194         return false;
195     }
196 
197     if (dstHasYcbcr || srcHasYcbcr) {
198         return false;
199     }
200 
201     return true;
202 }
203 
canCopyAsResolve(VkFormat dstFormat,int dstSampleCnt,bool dstHasYcbcr,VkFormat srcFormat,int srcSampleCnt,bool srcHasYcbcr) const204 bool GrVkCaps::canCopyAsResolve(VkFormat dstFormat, int dstSampleCnt, bool dstHasYcbcr,
205                                 VkFormat srcFormat, int srcSampleCnt, bool srcHasYcbcr) const {
206     // The src surface must be multisampled.
207     if (srcSampleCnt <= 1) {
208         return false;
209     }
210 
211     // The dst must not be multisampled.
212     if (dstSampleCnt > 1) {
213         return false;
214     }
215 
216     // Surfaces must have the same format.
217     if (srcFormat != dstFormat) {
218         return false;
219     }
220 
221     if (dstHasYcbcr || srcHasYcbcr) {
222         return false;
223     }
224 
225     return true;
226 }
227 
onCanCopySurface(const GrSurfaceProxy * dst,const SkIRect & dstRect,const GrSurfaceProxy * src,const SkIRect & srcRect) const228 bool GrVkCaps::onCanCopySurface(const GrSurfaceProxy* dst, const SkIRect& dstRect,
229                                 const GrSurfaceProxy* src, const SkIRect& srcRect) const {
230     if (src->isProtected() == GrProtected::kYes && dst->isProtected() != GrProtected::kYes) {
231         return false;
232     }
233 
234     // TODO: Figure out a way to track if we've wrapped a linear texture in a proxy (e.g.
235     // PromiseImage which won't get instantiated right away. Does this need a similar thing like the
236     // tracking of external or rectangle textures in GL? For now we don't create linear textures
237     // internally, and I don't believe anyone is wrapping them.
238     bool srcIsLinear = false;
239     bool dstIsLinear = false;
240 
241     int dstSampleCnt = 0;
242     int srcSampleCnt = 0;
243     if (const GrRenderTargetProxy* rtProxy = dst->asRenderTargetProxy()) {
244         // Copying to or from render targets that wrap a secondary command buffer is not allowed
245         // since they would require us to know the VkImage, which we don't have, as well as need us
246         // to stop and start the VkRenderPass which we don't have access to.
247         if (rtProxy->wrapsVkSecondaryCB()) {
248             return false;
249         }
250         if (this->preferDiscardableMSAAAttachment() && dst->asTextureProxy() &&
251             rtProxy->supportsVkInputAttachment()) {
252             dstSampleCnt = 1;
253         } else {
254             dstSampleCnt = rtProxy->numSamples();
255         }
256     }
257     if (const GrRenderTargetProxy* rtProxy = src->asRenderTargetProxy()) {
258         // Copying to or from render targets that wrap a secondary command buffer is not allowed
259         // since they would require us to know the VkImage, which we don't have, as well as need us
260         // to stop and start the VkRenderPass which we don't have access to.
261         if (rtProxy->wrapsVkSecondaryCB()) {
262             return false;
263         }
264         if (this->preferDiscardableMSAAAttachment() && src->asTextureProxy() &&
265             rtProxy->supportsVkInputAttachment()) {
266             srcSampleCnt = 1;
267         } else {
268             srcSampleCnt = rtProxy->numSamples();
269         }
270     }
271     SkASSERT((dstSampleCnt > 0) == SkToBool(dst->asRenderTargetProxy()));
272     SkASSERT((srcSampleCnt > 0) == SkToBool(src->asRenderTargetProxy()));
273 
274     bool dstHasYcbcr = false;
275     if (auto ycbcr = GrBackendFormats::GetVkYcbcrConversionInfo(dst->backendFormat())) {
276         if (ycbcr->isValid()) {
277             dstHasYcbcr = true;
278         }
279     }
280 
281     bool srcHasYcbcr = false;
282     if (auto ycbcr = GrBackendFormats::GetVkYcbcrConversionInfo(src->backendFormat())) {
283         if (ycbcr->isValid()) {
284             srcHasYcbcr = true;
285         }
286     }
287 
288     VkFormat dstFormat, srcFormat;
289     SkAssertResult(GrBackendFormats::AsVkFormat(dst->backendFormat(), &dstFormat));
290     SkAssertResult(GrBackendFormats::AsVkFormat(src->backendFormat(), &srcFormat));
291 
292     // Only blits support scaling, but since we've already clamped the src and dst rects,
293     // the dimensions of the scaled blit aren't important to know if it's allowed.
294     const bool copyScales = srcRect.size() != dstRect.size();
295     if (!copyScales && (this->canCopyImage(dstFormat, dstSampleCnt, dstHasYcbcr,
296                                            srcFormat, srcSampleCnt, srcHasYcbcr) ||
297                         this->canCopyAsResolve(dstFormat, dstSampleCnt, dstHasYcbcr,
298                                                srcFormat, srcSampleCnt, srcHasYcbcr))) {
299         return true;
300     }
301     return this->canCopyAsBlit(dstFormat, dstSampleCnt, dstIsLinear, dstHasYcbcr,
302                                srcFormat, srcSampleCnt, srcIsLinear, srcHasYcbcr);
303 
304 }
305 
init(const GrContextOptions & contextOptions,const skgpu::VulkanInterface * vkInterface,VkPhysicalDevice physDev,const VkPhysicalDeviceFeatures2 & features,uint32_t physicalDeviceVersion,const skgpu::VulkanExtensions & extensions,GrProtected isProtected)306 void GrVkCaps::init(const GrContextOptions& contextOptions,
307                     const skgpu::VulkanInterface* vkInterface,
308                     VkPhysicalDevice physDev,
309                     const VkPhysicalDeviceFeatures2& features,
310                     uint32_t physicalDeviceVersion,
311                     const skgpu::VulkanExtensions& extensions,
312                     GrProtected isProtected) {
313     VkPhysicalDeviceProperties properties;
314     GR_VK_CALL(vkInterface, GetPhysicalDeviceProperties(physDev, &properties));
315 
316 #if defined(GPU_TEST_UTILS)
317     this->setDeviceName(properties.deviceName);
318 #endif
319 
320     VkPhysicalDeviceMemoryProperties memoryProperties;
321     GR_VK_CALL(vkInterface, GetPhysicalDeviceMemoryProperties(physDev, &memoryProperties));
322 
323     SkASSERT(physicalDeviceVersion <= properties.apiVersion);
324 
325     if (extensions.hasExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME, 1)) {
326         fSupportsSwapchain = true;
327     }
328 
329     if (physicalDeviceVersion >= VK_MAKE_VERSION(1, 1, 0) ||
330         extensions.hasExtension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, 1)) {
331         fSupportsPhysicalDeviceProperties2 = true;
332     }
333 
334     if (physicalDeviceVersion >= VK_MAKE_VERSION(1, 1, 0) ||
335         extensions.hasExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME, 1)) {
336         fSupportsMemoryRequirements2 = true;
337     }
338 
339     if (physicalDeviceVersion >= VK_MAKE_VERSION(1, 1, 0) ||
340         extensions.hasExtension(VK_KHR_BIND_MEMORY_2_EXTENSION_NAME, 1)) {
341         fSupportsBindMemory2 = true;
342     }
343 
344     if (physicalDeviceVersion >= VK_MAKE_VERSION(1, 1, 0) ||
345         extensions.hasExtension(VK_KHR_MAINTENANCE1_EXTENSION_NAME, 1)) {
346         fSupportsMaintenance1 = true;
347     }
348 
349     if (physicalDeviceVersion >= VK_MAKE_VERSION(1, 1, 0) ||
350         extensions.hasExtension(VK_KHR_MAINTENANCE2_EXTENSION_NAME, 1)) {
351         fSupportsMaintenance2 = true;
352     }
353 
354     if (physicalDeviceVersion >= VK_MAKE_VERSION(1, 1, 0) ||
355         extensions.hasExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME, 1)) {
356         fSupportsMaintenance3 = true;
357     }
358 
359     if (physicalDeviceVersion >= VK_MAKE_VERSION(1, 1, 0) ||
360         (extensions.hasExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME, 1) &&
361          this->supportsMemoryRequirements2())) {
362         fSupportsDedicatedAllocation = true;
363     }
364 
365     if (physicalDeviceVersion >= VK_MAKE_VERSION(1, 1, 0) ||
366         (extensions.hasExtension(VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME, 1) &&
367          this->supportsPhysicalDeviceProperties2() &&
368          extensions.hasExtension(VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME, 1) &&
369          this->supportsDedicatedAllocation())) {
370         fSupportsExternalMemory = true;
371     }
372 
373 #ifdef SK_BUILD_FOR_ANDROID
374     // Currently Adreno devices are not supporting the QUEUE_FAMILY_FOREIGN_EXTENSION, so until they
375     // do we don't explicitly require it here even the spec says it is required.
376     if (extensions.hasExtension(
377             VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME, 2) &&
378        /* extensions.hasExtension(VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME, 1) &&*/
379         this->supportsExternalMemory() &&
380         this->supportsBindMemory2()) {
381         fSupportsAndroidHWBExternalMemory = true;
382         fSupportsAHardwareBufferImages = true;
383     }
384 #endif
385 
386     auto ycbcrFeatures = skgpu::GetExtensionFeatureStruct<
387             VkPhysicalDeviceSamplerYcbcrConversionFeatures>(
388                     features,
389                     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES);
390     if (ycbcrFeatures && ycbcrFeatures->samplerYcbcrConversion &&
391         (physicalDeviceVersion >= VK_MAKE_VERSION(1, 1, 0) ||
392          (extensions.hasExtension(VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME, 1) &&
393           this->supportsMaintenance1() && this->supportsBindMemory2() &&
394           this->supportsMemoryRequirements2() && this->supportsPhysicalDeviceProperties2()))) {
395         fSupportsYcbcrConversion = true;
396     }
397 
398     // We always push back the default skgpu::VulkanYcbcrConversionInfo so that the case of no
399     // conversion will return a key of 0.
400     fYcbcrInfos.push_back(skgpu::VulkanYcbcrConversionInfo());
401 
402     if ((isProtected == GrProtected::kYes) &&
403         (physicalDeviceVersion >= VK_MAKE_VERSION(1, 1, 0))) {
404         fSupportsProtectedContent = true;
405         fAvoidUpdateBuffers = true;
406         fShouldAlwaysUseDedicatedImageMemory = true;
407     }
408 
409     if (extensions.hasExtension(VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME, 1)) {
410         fSupportsDRMFormatModifiers = true;
411     }
412 
413     if (extensions.hasExtension(VK_EXT_DEVICE_FAULT_EXTENSION_NAME, 1)) {
414         fSupportsDeviceFaultInfo = true;
415     }
416 
417     if (extensions.hasExtension(VK_EXT_FRAME_BOUNDARY_EXTENSION_NAME, 1)) {
418         fSupportsFrameBoundary = true;
419     }
420 
421     fMaxInputAttachmentDescriptors = properties.limits.maxDescriptorSetInputAttachments;
422 
423     fMaxSamplerAnisotropy = properties.limits.maxSamplerAnisotropy;
424 
425     // On desktop GPUs we have found that this does not provide much benefit. The perf results show
426     // a mix of regressions, some improvements, and lots of no changes. Thus it is not worth
427     // enabling this (especially with the rendering artifacts) on desktop.
428     //
429     // On Adreno devices we were expecting to see perf gains. But instead there were actually a lot
430     // of perf regressions and only a few perf wins. This needs some follow up with qualcomm since
431     // we do expect this to be a big win on tilers.
432     //
433     // On ARM devices we are seeing an average perf win of around 50%-60% across the board.
434     if (kARM_VkVendor == properties.vendorID) {
435         // We currently don't see any Vulkan devices that expose a memory type that supports
436         // both lazy allocated and protected memory. So for simplicity we just disable the
437         // use of memoryless attachments when using protected memory. In the future, if we ever
438         // do see devices that support both, we can look through the device's memory types here
439         // and see if any support both flags.
440         fPreferDiscardableMSAAAttachment = !fSupportsProtectedContent;
441         fSupportsMemorylessAttachments = !fSupportsProtectedContent;
442     }
443 
444     this->initGrCaps(vkInterface, physDev, properties, memoryProperties, features, extensions);
445     this->initShaderCaps(properties, features);
446 
447     if (kQualcomm_VkVendor == properties.vendorID) {
448         // A "clear" load for atlases runs faster on QC than a "discard" load followed by a
449         // scissored clear.
450         // On NVIDIA and Intel, the discard load followed by clear is faster.
451         // TODO: Evaluate on ARM, Imagination, and ATI.
452         fPreferFullscreenClears = true;
453     }
454 
455     if (properties.vendorID == kNvidia_VkVendor || properties.vendorID == kAMD_VkVendor) {
456         // On discrete GPUs it can be faster to read gpu only memory compared to memory that is also
457         // mappable on the host.
458         fGpuOnlyBuffersMorePerformant = true;
459 
460         // On discrete GPUs we try to use special DEVICE_LOCAL and HOST_VISIBLE memory for our
461         // cpu write, gpu read buffers. This memory is not ideal to be kept persistently mapped.
462         // Some discrete GPUs do not expose this special memory, however we still disable
463         // persistently mapped buffers for all of them since most GPUs with updated drivers do
464         // expose it. If this becomes an issue we can try to be more fine grained.
465         fShouldPersistentlyMapCpuToGpuBuffers = false;
466     }
467 
468     if (kQualcomm_VkVendor == properties.vendorID) {
469         // On Qualcomm it looks like using vkCmdUpdateBuffer is slower than using a transfer buffer
470         // even for small sizes.
471         fAvoidUpdateBuffers = true;
472     }
473 
474     fNativeDrawIndirectSupport = features.features.drawIndirectFirstInstance;
475     if (properties.vendorID == kQualcomm_VkVendor) {
476         // Indirect draws seem slow on QC. Disable until we can investigate. http://skbug.com/11139
477         fNativeDrawIndirectSupport = false;
478     }
479 
480     if (fNativeDrawIndirectSupport) {
481         fMaxDrawIndirectDrawCount = properties.limits.maxDrawIndirectCount;
482         SkASSERT(fMaxDrawIndirectDrawCount == 1 || features.features.multiDrawIndirect);
483     }
484 
485 #ifdef SK_BUILD_FOR_UNIX
486     if (kNvidia_VkVendor == properties.vendorID) {
487         // On nvidia linux we see a big perf regression when not using dedicated image allocations.
488         fShouldAlwaysUseDedicatedImageMemory = true;
489     }
490 #endif
491 
492     this->initFormatTable(contextOptions, vkInterface, physDev, properties, features, extensions);
493     this->initStencilFormat(vkInterface, physDev);
494 
495     if (contextOptions.fMaxCachedVulkanSecondaryCommandBuffers >= 0) {
496         fMaxPerPoolCachedSecondaryCommandBuffers =
497                 contextOptions.fMaxCachedVulkanSecondaryCommandBuffers;
498     }
499 
500     if (!contextOptions.fDisableDriverCorrectnessWorkarounds) {
501         this->applyDriverCorrectnessWorkarounds(properties);
502     }
503 
504     this->finishInitialization(contextOptions);
505 }
506 
applyDriverCorrectnessWorkarounds(const VkPhysicalDeviceProperties & properties)507 void GrVkCaps::applyDriverCorrectnessWorkarounds(const VkPhysicalDeviceProperties& properties) {
508 #if defined(SK_BUILD_FOR_WIN)
509     if (kNvidia_VkVendor == properties.vendorID || kIntel_VkVendor == properties.vendorID) {
510         fMustSyncCommandBuffersWithQueue = true;
511     }
512 #elif defined(SK_BUILD_FOR_ANDROID)
513     if (kImagination_VkVendor == properties.vendorID) {
514         fMustSyncCommandBuffersWithQueue = true;
515     }
516 #endif
517 
518     // Defaults to zero since all our workaround checks that use this consider things "fixed" once
519     // above a certain api level. So this will just default to it being less which will enable
520     // workarounds.
521     int androidAPIVersion = 0;
522 #if defined(SK_BUILD_FOR_ANDROID)
523     char androidAPIVersionStr[PROP_VALUE_MAX];
524     int strLength = __system_property_get("ro.build.version.sdk", androidAPIVersionStr);
525     // Defaults to zero since most checks care if it is greater than a specific value. So this will
526     // just default to it being less.
527     androidAPIVersion = (strLength == 0) ? 0 : atoi(androidAPIVersionStr);
528 #endif
529 
530     // Protected memory features have problems in Android P and earlier.
531     if (fSupportsProtectedContent && (kQualcomm_VkVendor == properties.vendorID)) {
532         if (androidAPIVersion <= 28) {
533             fSupportsProtectedContent = false;
534         }
535     }
536 
537     // On Mali galaxy s7 we see lots of rendering issues when we suballocate VkImages.
538     if (kARM_VkVendor == properties.vendorID && androidAPIVersion <= 28) {
539         fShouldAlwaysUseDedicatedImageMemory = true;
540     }
541 
542     // On Mali galaxy s7 and s9 we see lots of rendering issues with image filters dropping out when
543     // using only primary command buffers. We also see issues on the P30 running android 28.
544     if (kARM_VkVendor == properties.vendorID && androidAPIVersion <= 28) {
545         fPreferPrimaryOverSecondaryCommandBuffers = false;
546         // If we are using secondary command buffers our code isn't setup to insert barriers into
547         // the secondary cb so we need to disable support for them.
548         fTextureBarrierSupport = false;
549         fBlendEquationSupport = kBasic_BlendEquationSupport;
550     }
551 
552     // We've seen numerous driver bugs on qualcomm devices running on android P (api 28) or earlier
553     // when trying to using discardable msaa attachments and loading from resolve. So we disable the
554     // feature for those devices.
555     if (properties.vendorID == kQualcomm_VkVendor && androidAPIVersion <= 28) {
556         fPreferDiscardableMSAAAttachment = false;
557         fSupportsDiscardableMSAAForDMSAA = false;
558     }
559 
560     // On the Mali G76 and T880, the Perlin noise code needs to aggressively snap to multiples
561     // of 1/255 to avoid artifacts in the double table lookup.
562     if (kARM_VkVendor == properties.vendorID) {
563         fShaderCaps->fPerlinNoiseRoundingFix = true;
564     }
565 
566     // On various devices, when calling vkCmdClearAttachments on a primary command buffer, it
567     // corrupts the bound buffers on the command buffer. As a workaround we invalidate our knowledge
568     // of bound buffers so that we will rebind them on the next draw.
569     if (kQualcomm_VkVendor == properties.vendorID || kAMD_VkVendor == properties.vendorID) {
570         fMustInvalidatePrimaryCmdBufferStateAfterClearAttachments = true;
571     }
572 
573     // On Qualcomm and Arm the gpu resolves an area larger than the render pass bounds when using
574     // discardable msaa attachments. This causes the resolve to resolve uninitialized data from the
575     // msaa image into the resolve image.
576     // This also occurs on swiftshader: b/303705884
577     if (properties.vendorID == kQualcomm_VkVendor ||
578         properties.vendorID == kARM_VkVendor ||
579         (properties.vendorID == kGoogle_VkVendor &&
580          properties.deviceID == kSwiftshader_DeviceID)) {
581         fMustLoadFullImageWithDiscardableMSAA = true;
582     }
583 
584     // There seems to be bug in swiftshader when we reuse scratch buffers for uploads. We end up
585     // with very slight pixel diffs. For example:
586     // (https://ci.chromium.org/ui/p/chromium/builders/try/linux-rel/1585128/overview).
587     // Since swiftshader is only really used for testing, to try and make things more stable we
588     // disable the reuse of buffers.
589     if (properties.vendorID == kGoogle_VkVendor && properties.deviceID == kSwiftshader_DeviceID) {
590         fReuseScratchBuffers = false;
591     }
592 
593     ////////////////////////////////////////////////////////////////////////////
594     // GrCaps workarounds
595     ////////////////////////////////////////////////////////////////////////////
596 
597     if (kARM_VkVendor == properties.vendorID) {
598         fAvoidWritePixelsFastPath = true; // bugs.skia.org/8064
599     }
600 
601     // AMD advertises support for MAX_UINT vertex input attributes, but in reality only supports 32.
602     if (kAMD_VkVendor == properties.vendorID) {
603         fMaxVertexAttributes = std::min(fMaxVertexAttributes, 32);
604     }
605 
606     // Adreno devices fail when trying to read the dest using an input attachment and texture
607     // barriers.
608     if (kQualcomm_VkVendor == properties.vendorID) {
609         fTextureBarrierSupport = false;
610     }
611 
612 #ifdef SK_BUILD_FOR_WIN
613     // Gen 12 Intel devices running on windows has issues using barriers for dst reads. This is seen
614     // when running the unit tests SkRuntimeEffect_Blender_GPU and DMSAA_aa_dst_read_after_dmsaa.
615     //
616     // Additionally, as of 2023-01-19 the latest driver compatible with Intel Iris Graphics 540
617     // (9th gen Skylake microarchitecture) produce SkRuntimeEffect_Blender and DMSAA deltas that
618     // are unacceptable and break our tests. The drivers in question are version 31.0.101.2115 and
619     // can be downloaded from
620     // https://www.intel.com/content/www/us/en/download/762755/intel-6th-10th-gen-processor-graphics-windows.html.
621     // This is likely due to bugs in the driver. As a temporary workaround, we disable texture
622     // barrier support in Skylake and newer generations (i.e. 9th gen or newer).
623     if (kIntel_VkVendor == properties.vendorID &&
624         GetIntelGen(GetIntelGPUType(properties.deviceID)) >= 9) {
625         fTextureBarrierSupport = false;
626     }
627 #endif
628 
629     // On ARM indirect draws are broken on Android 9 and earlier. This was tested on a P30 and
630     // Mate 20x running android 9.
631     if (properties.vendorID == kARM_VkVendor && androidAPIVersion <= 28) {
632         fNativeDrawIndirectSupport = false;
633     }
634 
635     ////////////////////////////////////////////////////////////////////////////
636     // GrShaderCaps workarounds
637     ////////////////////////////////////////////////////////////////////////////
638 
639     if (kImagination_VkVendor == properties.vendorID) {
640         fShaderCaps->fAtan2ImplementedAsAtanYOverX = true;
641     }
642 
643     // ARM GPUs calculate `matrix * vector` in SPIR-V at full precision, even when the inputs are
644     // RelaxedPrecision. Rewriting the multiply as a sum of vector*scalar fixes this. (skia:11769)
645     if (kARM_VkVendor == properties.vendorID) {
646         fShaderCaps->fRewriteMatrixVectorMultiply = true;
647     }
648 }
649 
initGrCaps(const skgpu::VulkanInterface * vkInterface,VkPhysicalDevice physDev,const VkPhysicalDeviceProperties & properties,const VkPhysicalDeviceMemoryProperties & memoryProperties,const VkPhysicalDeviceFeatures2 & features,const skgpu::VulkanExtensions & extensions)650 void GrVkCaps::initGrCaps(const skgpu::VulkanInterface* vkInterface,
651                           VkPhysicalDevice physDev,
652                           const VkPhysicalDeviceProperties& properties,
653                           const VkPhysicalDeviceMemoryProperties& memoryProperties,
654                           const VkPhysicalDeviceFeatures2& features,
655                           const skgpu::VulkanExtensions& extensions) {
656     // So GPUs, like AMD, are reporting MAX_INT support vertex attributes. In general, there is no
657     // need for us ever to support that amount, and it makes tests which tests all the vertex
658     // attribs timeout looping over that many. For now, we'll cap this at 64 max and can raise it if
659     // we ever find that need.
660     static const uint32_t kMaxVertexAttributes = 64;
661     fMaxVertexAttributes = std::min(properties.limits.maxVertexInputAttributes,
662                                     kMaxVertexAttributes);
663 
664     // GrCaps::fSampleLocationsSupport refers to the ability to *query* the sample locations (not
665     // program them). For now we just set this to true if the device uses standard locations, and
666     // return the standard locations back when queried.
667     if (properties.limits.standardSampleLocations) {
668         fSampleLocationsSupport = true;
669     }
670 
671     if (extensions.hasExtension(VK_EXT_CONSERVATIVE_RASTERIZATION_EXTENSION_NAME, 1)) {
672         fConservativeRasterSupport = true;
673     }
674 
675     fWireframeSupport = true;
676 
677     // We could actually query and get a max size for each config, however maxImageDimension2D will
678     // give the minimum max size across all configs. So for simplicity we will use that for now.
679     fMaxRenderTargetSize = std::min(properties.limits.maxImageDimension2D, (uint32_t)INT_MAX);
680     fMaxTextureSize = std::min(properties.limits.maxImageDimension2D, (uint32_t)INT_MAX);
681 
682     // TODO: check if RT's larger than 4k incur a performance cost on ARM.
683     fMaxPreferredRenderTargetSize = fMaxRenderTargetSize;
684 
685     fMaxPushConstantsSize = std::min(properties.limits.maxPushConstantsSize, (uint32_t)INT_MAX);
686 
687     // Assuming since we will always map in the end to upload the data we might as well just map
688     // from the get go. There is no hard data to suggest this is faster or slower.
689     fBufferMapThreshold = 0;
690 
691     fMapBufferFlags = kCanMap_MapFlag | kSubset_MapFlag | kAsyncRead_MapFlag;
692 
693     fOversizedStencilSupport = true;
694 
695     if (extensions.hasExtension(VK_EXT_BLEND_OPERATION_ADVANCED_EXTENSION_NAME, 2) &&
696         this->supportsPhysicalDeviceProperties2()) {
697 
698         VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT blendProps;
699         blendProps.sType =
700                 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_PROPERTIES_EXT;
701         blendProps.pNext = nullptr;
702 
703         VkPhysicalDeviceProperties2 props;
704         props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
705         props.pNext = &blendProps;
706 
707         GR_VK_CALL(vkInterface, GetPhysicalDeviceProperties2(physDev, &props));
708 
709         if (blendProps.advancedBlendAllOperations == VK_TRUE) {
710             fShaderCaps->fAdvBlendEqInteraction = GrShaderCaps::kAutomatic_AdvBlendEqInteraction;
711 
712             auto blendFeatures = skgpu::GetExtensionFeatureStruct<
713                     VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT>(
714                             features,
715                             VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_FEATURES_EXT
716                     );
717             if (blendFeatures && blendFeatures->advancedBlendCoherentOperations == VK_TRUE) {
718                 fBlendEquationSupport = kAdvancedCoherent_BlendEquationSupport;
719             } else {
720                 fBlendEquationSupport = kAdvanced_BlendEquationSupport;
721             }
722         }
723     }
724 
725     if (kARM_VkVendor == properties.vendorID) {
726         fShouldCollapseSrcOverToSrcWhenAble = true;
727     }
728 }
729 
initShaderCaps(const VkPhysicalDeviceProperties & properties,const VkPhysicalDeviceFeatures2 & features)730 void GrVkCaps::initShaderCaps(const VkPhysicalDeviceProperties& properties,
731                               const VkPhysicalDeviceFeatures2& features) {
732     GrShaderCaps* shaderCaps = fShaderCaps.get();
733     shaderCaps->fVersionDeclString = "#version 330\n";
734 
735     // Ganesh + Vulkan always emits `sk_Clockwise` to avoid some Adreno rendering errors.
736     shaderCaps->fMustDeclareFragmentFrontFacing = true;
737 
738     // Vulkan is based off ES 3.0 so the following should all be supported
739     shaderCaps->fUsesPrecisionModifiers = true;
740     shaderCaps->fFlatInterpolationSupport = true;
741     // Flat interpolation appears to be slow on Qualcomm GPUs. This was tested in GL and is assumed
742     // to be true with Vulkan as well.
743     shaderCaps->fPreferFlatInterpolation = kQualcomm_VkVendor != properties.vendorID;
744 
745     shaderCaps->fSampleMaskSupport = true;
746 
747     shaderCaps->fShaderDerivativeSupport = true;
748     shaderCaps->fExplicitTextureLodSupport = true;
749 
750     shaderCaps->fDualSourceBlendingSupport = features.features.dualSrcBlend;
751 
752     shaderCaps->fIntegerSupport = true;
753     shaderCaps->fNonsquareMatrixSupport = true;
754     shaderCaps->fInverseHyperbolicSupport = true;
755     shaderCaps->fVertexIDSupport = true;
756     shaderCaps->fInfinitySupport = true;
757     shaderCaps->fNonconstantArrayIndexSupport = true;
758     shaderCaps->fBitManipulationSupport = true;
759 
760     // Assume the minimum precisions mandated by the SPIR-V spec.
761     shaderCaps->fFloatIs32Bits = true;
762     shaderCaps->fHalfIs32Bits = false;
763 
764     shaderCaps->fMaxFragmentSamplers = std::min(
765                                        std::min(properties.limits.maxPerStageDescriptorSampledImages,
766                                               properties.limits.maxPerStageDescriptorSamplers),
767                                               (uint32_t)INT_MAX);
768 }
769 
stencil_format_supported(const skgpu::VulkanInterface * interface,VkPhysicalDevice physDev,VkFormat format)770 bool stencil_format_supported(const skgpu::VulkanInterface* interface,
771                               VkPhysicalDevice physDev,
772                               VkFormat format) {
773     VkFormatProperties props;
774     memset(&props, 0, sizeof(VkFormatProperties));
775     GR_VK_CALL(interface, GetPhysicalDeviceFormatProperties(physDev, format, &props));
776     return SkToBool(VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT & props.optimalTilingFeatures);
777 }
778 
initStencilFormat(const skgpu::VulkanInterface * interface,VkPhysicalDevice physDev)779 void GrVkCaps::initStencilFormat(const skgpu::VulkanInterface* interface,
780                                  VkPhysicalDevice physDev) {
781     if (stencil_format_supported(interface, physDev, VK_FORMAT_S8_UINT)) {
782         fPreferredStencilFormat = VK_FORMAT_S8_UINT;
783     } else if (stencil_format_supported(interface, physDev, VK_FORMAT_D24_UNORM_S8_UINT)) {
784         fPreferredStencilFormat = VK_FORMAT_D24_UNORM_S8_UINT;
785     } else {
786         SkASSERT(stencil_format_supported(interface, physDev, VK_FORMAT_D32_SFLOAT_S8_UINT));
787         fPreferredStencilFormat = VK_FORMAT_D32_SFLOAT_S8_UINT;
788     }
789 }
790 
format_is_srgb(VkFormat format)791 static bool format_is_srgb(VkFormat format) {
792     SkASSERT(GrVkFormatIsSupported(format));
793 
794     switch (format) {
795         case VK_FORMAT_R8G8B8A8_SRGB:
796             return true;
797         default:
798             return false;
799     }
800 }
801 
802 // These are all the valid VkFormats that we support in Skia. They are roughly ordered from most
803 // frequently used to least to improve look up times in arrays.
804 static constexpr VkFormat kVkFormats[] = {
805     VK_FORMAT_R8G8B8A8_UNORM,
806     VK_FORMAT_R8_UNORM,
807     VK_FORMAT_B8G8R8A8_UNORM,
808     VK_FORMAT_R5G6B5_UNORM_PACK16,
809     VK_FORMAT_B5G6R5_UNORM_PACK16,
810     VK_FORMAT_R16G16B16A16_SFLOAT,
811     VK_FORMAT_R16_SFLOAT,
812     VK_FORMAT_R8G8B8_UNORM,
813     VK_FORMAT_R8G8_UNORM,
814     VK_FORMAT_A2B10G10R10_UNORM_PACK32,
815     VK_FORMAT_A2R10G10B10_UNORM_PACK32,
816     VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16,
817     VK_FORMAT_B4G4R4A4_UNORM_PACK16,
818     VK_FORMAT_R4G4B4A4_UNORM_PACK16,
819     VK_FORMAT_R8G8B8A8_SRGB,
820     VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK,
821     VK_FORMAT_BC1_RGB_UNORM_BLOCK,
822     VK_FORMAT_BC1_RGBA_UNORM_BLOCK,
823     VK_FORMAT_R16_UNORM,
824     VK_FORMAT_R16G16_UNORM,
825     VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM,
826     VK_FORMAT_G8_B8R8_2PLANE_420_UNORM,
827     VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16,
828     VK_FORMAT_R16G16B16A16_UNORM,
829     VK_FORMAT_R16G16_SFLOAT,
830 };
831 
setColorType(GrColorType colorType,std::initializer_list<VkFormat> formats)832 void GrVkCaps::setColorType(GrColorType colorType, std::initializer_list<VkFormat> formats) {
833 #ifdef SK_DEBUG
834     for (size_t i = 0; i < kNumVkFormats; ++i) {
835         const auto& formatInfo = fFormatTable[i];
836         for (int j = 0; j < formatInfo.fColorTypeInfoCount; ++j) {
837             const auto& ctInfo = formatInfo.fColorTypeInfos[j];
838             if (ctInfo.fColorType == colorType &&
839                 !SkToBool(ctInfo.fFlags & ColorTypeInfo::kWrappedOnly_Flag)) {
840                 bool found = false;
841                 for (auto it = formats.begin(); it != formats.end(); ++it) {
842                     if (kVkFormats[i] == *it) {
843                         found = true;
844                     }
845                 }
846                 SkASSERT(found);
847             }
848         }
849     }
850 #endif
851     int idx = static_cast<int>(colorType);
852     for (auto it = formats.begin(); it != formats.end(); ++it) {
853         const auto& info = this->getFormatInfo(*it);
854         for (int i = 0; i < info.fColorTypeInfoCount; ++i) {
855             if (info.fColorTypeInfos[i].fColorType == colorType) {
856                 fColorTypeToFormatTable[idx] = *it;
857                 return;
858             }
859         }
860     }
861 }
862 
getFormatInfo(VkFormat format) const863 const GrVkCaps::FormatInfo& GrVkCaps::getFormatInfo(VkFormat format) const {
864     GrVkCaps* nonConstThis = const_cast<GrVkCaps*>(this);
865     return nonConstThis->getFormatInfo(format);
866 }
867 
getFormatInfo(VkFormat format)868 GrVkCaps::FormatInfo& GrVkCaps::getFormatInfo(VkFormat format) {
869     static_assert(std::size(kVkFormats) == GrVkCaps::kNumVkFormats,
870                   "Size of VkFormats array must match static value in header");
871     for (size_t i = 0; i < std::size(kVkFormats); ++i) {
872         if (kVkFormats[i] == format) {
873             return fFormatTable[i];
874         }
875     }
876     static FormatInfo kInvalidFormat;
877     return kInvalidFormat;
878 }
879 
initFormatTable(const GrContextOptions & contextOptions,const skgpu::VulkanInterface * interface,VkPhysicalDevice physDev,const VkPhysicalDeviceProperties & properties,const VkPhysicalDeviceFeatures2 & features,const skgpu::VulkanExtensions & extensions)880 void GrVkCaps::initFormatTable(const GrContextOptions& contextOptions,
881                                const skgpu::VulkanInterface* interface,
882                                VkPhysicalDevice physDev,
883                                const VkPhysicalDeviceProperties& properties,
884                                const VkPhysicalDeviceFeatures2& features,
885                                const skgpu::VulkanExtensions& extensions) {
886     static_assert(std::size(kVkFormats) == GrVkCaps::kNumVkFormats,
887                   "Size of VkFormats array must match static value in header");
888 
889     std::fill_n(fColorTypeToFormatTable, kGrColorTypeCnt, VK_FORMAT_UNDEFINED);
890 
891     // Go through all the formats and init their support surface and data GrColorTypes.
892     // Format: VK_FORMAT_R8G8B8A8_UNORM
893     {
894         constexpr VkFormat format = VK_FORMAT_R8G8B8A8_UNORM;
895         auto& info = this->getFormatInfo(format);
896         info.init(contextOptions, interface, physDev, properties, format);
897         if (SkToBool(info.fOptimalFlags & FormatInfo::kTexturable_Flag)) {
898             info.fColorTypeInfoCount = 2;
899             info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
900             int ctIdx = 0;
901             // Format: VK_FORMAT_R8G8B8A8_UNORM, Surface: kRGBA_8888
902             {
903                 constexpr GrColorType ct = GrColorType::kRGBA_8888;
904                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
905                 ctInfo.fColorType = ct;
906                 ctInfo.fTransferColorType = ct;
907                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
908             }
909             // Format: VK_FORMAT_R8G8B8A8_UNORM, Surface: kRGB_888x
910             {
911                 constexpr GrColorType ct = GrColorType::kRGB_888x;
912                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
913                 ctInfo.fColorType = ct;
914                 ctInfo.fTransferColorType = ct;
915                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag;
916                 ctInfo.fReadSwizzle = skgpu::Swizzle::RGB1();
917             }
918         }
919     }
920 
921     // Format: VK_FORMAT_R8_UNORM
922     {
923         constexpr VkFormat format = VK_FORMAT_R8_UNORM;
924         auto& info = this->getFormatInfo(format);
925         info.init(contextOptions, interface, physDev, properties, format);
926         if (SkToBool(info.fOptimalFlags & FormatInfo::kTexturable_Flag)) {
927             info.fColorTypeInfoCount = 3;
928             info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
929             int ctIdx = 0;
930             // Format: VK_FORMAT_R8_UNORM, Surface: kR_8
931             {
932                 constexpr GrColorType ct = GrColorType::kR_8;
933                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
934                 ctInfo.fColorType = ct;
935                 ctInfo.fTransferColorType = ct;
936                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
937             }
938             // Format: VK_FORMAT_R8_UNORM, Surface: kAlpha_8
939             {
940                 constexpr GrColorType ct = GrColorType::kAlpha_8;
941                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
942                 ctInfo.fColorType = ct;
943                 ctInfo.fTransferColorType = ct;
944                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
945                 ctInfo.fReadSwizzle = skgpu::Swizzle("000r");
946                 ctInfo.fWriteSwizzle = skgpu::Swizzle("a000");
947             }
948             // Format: VK_FORMAT_R8_UNORM, Surface: kGray_8
949             {
950                 constexpr GrColorType ct = GrColorType::kGray_8;
951                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
952                 ctInfo.fColorType = ct;
953                 ctInfo.fTransferColorType = ct;
954                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag;
955                 ctInfo.fReadSwizzle = skgpu::Swizzle("rrr1");
956             }
957         }
958     }
959     // Format: VK_FORMAT_B8G8R8A8_UNORM
960     {
961         constexpr VkFormat format = VK_FORMAT_B8G8R8A8_UNORM;
962         auto& info = this->getFormatInfo(format);
963         info.init(contextOptions, interface, physDev, properties, format);
964         if (SkToBool(info.fOptimalFlags & FormatInfo::kTexturable_Flag)) {
965             info.fColorTypeInfoCount = 2;
966             info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
967             int ctIdx = 0;
968             // Format: VK_FORMAT_B8G8R8A8_UNORM, Surface: kBGRA_8888
969             {
970                 constexpr GrColorType ct = GrColorType::kBGRA_8888;
971                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
972                 ctInfo.fColorType = ct;
973                 ctInfo.fTransferColorType = ct;
974                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
975             }
976             // Format: VK_FORMAT_B8G8R8A8_UNORM, Surface: kRGB_888x
977             // TODO: add and use kBGR_888X instead
978             {
979                 constexpr GrColorType ct = GrColorType::kRGB_888x;
980                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
981                 ctInfo.fColorType = ct;
982                 ctInfo.fTransferColorType = GrColorType::kBGRA_8888;
983                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag;
984                 ctInfo.fReadSwizzle = skgpu::Swizzle::RGB1();
985             }
986         }
987     }
988     // Format: VK_FORMAT_R5G6B5_UNORM_PACK16
989     {
990         constexpr VkFormat format = VK_FORMAT_R5G6B5_UNORM_PACK16;
991         auto& info = this->getFormatInfo(format);
992         info.init(contextOptions, interface, physDev, properties, format);
993         if (SkToBool(info.fOptimalFlags & FormatInfo::kTexturable_Flag)) {
994             info.fColorTypeInfoCount = 1;
995             info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
996             int ctIdx = 0;
997             // Format: VK_FORMAT_R5G6B5_UNORM_PACK16, Surface: kBGR_565
998             {
999                 constexpr GrColorType ct = GrColorType::kBGR_565;
1000                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
1001                 ctInfo.fColorType = ct;
1002                 ctInfo.fTransferColorType = ct;
1003                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
1004             }
1005         }
1006     }
1007     // Format: VK_FORMAT_B5G6R5_UNORM_PACK16
1008     {
1009         constexpr VkFormat format = VK_FORMAT_B5G6R5_UNORM_PACK16;
1010         auto& info = this->getFormatInfo(format);
1011         info.init(contextOptions, interface, physDev, properties, format);
1012         if (SkToBool(info.fOptimalFlags & FormatInfo::kTexturable_Flag)) {
1013             info.fColorTypeInfoCount = 2;
1014             info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
1015             int ctIdx = 0;
1016             // Format: VK_FORMAT_B5G6R5_UNORM_PACK16, Surface: kRGB_565
1017             {
1018                 constexpr GrColorType ct = GrColorType::kRGB_565;
1019                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
1020                 ctInfo.fColorType = ct;
1021                 ctInfo.fTransferColorType = ct;
1022                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
1023             }
1024             // Format: VK_FORMAT_B5G6R5_UNORM_PACK16, Surface: kBGR_565
1025             // We need this because there is no kBGR_565_SkColorType.
1026             {
1027                 constexpr GrColorType ct = GrColorType::kBGR_565;
1028                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
1029                 ctInfo.fColorType = ct;
1030                 ctInfo.fTransferColorType = GrColorType::kRGB_565;
1031                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag;
1032             }
1033         }
1034     }
1035     // Format: VK_FORMAT_R16G16B16A16_SFLOAT
1036     {
1037         constexpr VkFormat format = VK_FORMAT_R16G16B16A16_SFLOAT;
1038         auto& info = this->getFormatInfo(format);
1039         info.init(contextOptions, interface, physDev, properties, format);
1040         if (SkToBool(info.fOptimalFlags & FormatInfo::kTexturable_Flag)) {
1041             info.fColorTypeInfoCount = 3;
1042             info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
1043             int ctIdx = 0;
1044             // Format: VK_FORMAT_R16G16B16A16_SFLOAT, Surface: GrColorType::kRGBA_F16
1045             {
1046                 constexpr GrColorType ct = GrColorType::kRGBA_F16;
1047                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
1048                 ctInfo.fColorType = ct;
1049                 ctInfo.fTransferColorType = ct;
1050                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
1051             }
1052             // Format: VK_FORMAT_R16G16B16A16_SFLOAT, Surface: GrColorType::kRGBA_F16_Clamped
1053             {
1054                 constexpr GrColorType ct = GrColorType::kRGBA_F16_Clamped;
1055                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
1056                 ctInfo.fColorType = ct;
1057                 ctInfo.fTransferColorType = ct;
1058                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
1059             }
1060             // Format: VK_FORMAT_R16G16B16A16_SFLOAT, Surface: GrColorType::kRGB_F16F16F16x
1061             {
1062                 constexpr GrColorType ct = GrColorType::kRGB_F16F16F16x;
1063                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
1064                 ctInfo.fColorType = ct;
1065                 ctInfo.fTransferColorType = ct;
1066                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag;
1067                 ctInfo.fReadSwizzle = skgpu::Swizzle::RGB1();
1068             }
1069         }
1070     }
1071     // Format: VK_FORMAT_R16_SFLOAT
1072     {
1073         constexpr VkFormat format = VK_FORMAT_R16_SFLOAT;
1074         auto& info = this->getFormatInfo(format);
1075         info.init(contextOptions, interface, physDev, properties, format);
1076         if (SkToBool(info.fOptimalFlags & FormatInfo::kTexturable_Flag)) {
1077             info.fColorTypeInfoCount = 1;
1078             info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
1079             int ctIdx = 0;
1080             // Format: VK_FORMAT_R16_SFLOAT, Surface: kAlpha_F16
1081             {
1082                 constexpr GrColorType ct = GrColorType::kAlpha_F16;
1083                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
1084                 ctInfo.fColorType = ct;
1085                 ctInfo.fTransferColorType = ct;
1086                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
1087                 ctInfo.fReadSwizzle = skgpu::Swizzle("000r");
1088                 ctInfo.fWriteSwizzle = skgpu::Swizzle("a000");
1089             }
1090         }
1091     }
1092     // Format: VK_FORMAT_R8G8B8_UNORM
1093     {
1094         constexpr VkFormat format = VK_FORMAT_R8G8B8_UNORM;
1095         auto& info = this->getFormatInfo(format);
1096         info.init(contextOptions, interface, physDev, properties, format);
1097         if (SkToBool(info.fOptimalFlags & FormatInfo::kTexturable_Flag)) {
1098             info.fColorTypeInfoCount = 1;
1099             info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
1100             int ctIdx = 0;
1101             // Format: VK_FORMAT_R8G8B8_UNORM, Surface: kRGB_888x
1102             {
1103                 constexpr GrColorType ct = GrColorType::kRGB_888x;
1104                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
1105                 ctInfo.fColorType = ct;
1106                 // The Vulkan format is 3 bpp so we must convert to/from that when transferring.
1107                 ctInfo.fTransferColorType = GrColorType::kRGB_888;
1108                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
1109             }
1110         }
1111     }
1112     // Format: VK_FORMAT_R8G8_UNORM
1113     {
1114         constexpr VkFormat format = VK_FORMAT_R8G8_UNORM;
1115         auto& info = this->getFormatInfo(format);
1116         info.init(contextOptions, interface, physDev, properties, format);
1117         if (SkToBool(info.fOptimalFlags & FormatInfo::kTexturable_Flag)) {
1118             info.fColorTypeInfoCount = 1;
1119             info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
1120             int ctIdx = 0;
1121             // Format: VK_FORMAT_R8G8_UNORM, Surface: kRG_88
1122             {
1123                 constexpr GrColorType ct = GrColorType::kRG_88;
1124                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
1125                 ctInfo.fColorType = ct;
1126                 ctInfo.fTransferColorType = ct;
1127                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
1128             }
1129         }
1130     }
1131     // Format: VK_FORMAT_A2B10G10R10_UNORM_PACK32
1132     {
1133         constexpr VkFormat format = VK_FORMAT_A2B10G10R10_UNORM_PACK32;
1134         auto& info = this->getFormatInfo(format);
1135         info.init(contextOptions, interface, physDev, properties, format);
1136         if (SkToBool(info.fOptimalFlags & FormatInfo::kTexturable_Flag)) {
1137             info.fColorTypeInfoCount = 2;
1138             info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
1139             int ctIdx = 0;
1140             // Format: VK_FORMAT_A2B10G10R10_UNORM_PACK32, Surface: kRGBA_1010102
1141             {
1142                 constexpr GrColorType ct = GrColorType::kRGBA_1010102;
1143                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
1144                 ctInfo.fColorType = ct;
1145                 ctInfo.fTransferColorType = ct;
1146                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
1147             }
1148             // Format: VK_FORMAT_A2B10G10R10_UNORM_PACK32, Surface: kRGB_101010x
1149             {
1150                 constexpr GrColorType ct = GrColorType::kRGB_101010x;
1151                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
1152                 ctInfo.fColorType = ct;
1153                 ctInfo.fTransferColorType = ct;
1154                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag;
1155                 ctInfo.fReadSwizzle = skgpu::Swizzle::RGB1();
1156             }
1157         }
1158     }
1159     // Format: VK_FORMAT_A2R10G10B10_UNORM_PACK32
1160     {
1161         constexpr VkFormat format = VK_FORMAT_A2R10G10B10_UNORM_PACK32;
1162         auto& info = this->getFormatInfo(format);
1163         info.init(contextOptions, interface, physDev, properties, format);
1164         if (SkToBool(info.fOptimalFlags & FormatInfo::kTexturable_Flag)) {
1165             info.fColorTypeInfoCount = 1;
1166             info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
1167             int ctIdx = 0;
1168             // Format: VK_FORMAT_A2R10G10B10_UNORM_PACK32, Surface: kBGRA_1010102
1169             {
1170                 constexpr GrColorType ct = GrColorType::kBGRA_1010102;
1171                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
1172                 ctInfo.fColorType = ct;
1173                 ctInfo.fTransferColorType = ct;
1174                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
1175             }
1176         }
1177     }
1178 
1179     bool supportsRGBA10x6 = false;
1180     if (extensions.hasExtension(VK_EXT_RGBA10X6_FORMATS_EXTENSION_NAME, 1)) {
1181         auto rgba10x6Feature =
1182                 skgpu::GetExtensionFeatureStruct<VkPhysicalDeviceRGBA10X6FormatsFeaturesEXT>(
1183                         features, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RGBA10X6_FORMATS_FEATURES_EXT);
1184         // Technically without this extension and exabled feature we could still use this format to
1185         // sample with a ycbcr sampler. But for simplicity until we have clients requesting that, we
1186         // limit the use of this format to cases where we have the extension supported.
1187         supportsRGBA10x6 = rgba10x6Feature  && rgba10x6Feature->formatRgba10x6WithoutYCbCrSampler;
1188     }
1189 
1190     // Format: VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16
1191     if (supportsRGBA10x6) {
1192         constexpr VkFormat format = VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16;
1193         auto& info = this->getFormatInfo(format);
1194         info.init(contextOptions, interface, physDev, properties, format);
1195         if (SkToBool(info.fOptimalFlags & FormatInfo::kTexturable_Flag)) {
1196             info.fColorTypeInfoCount = 1;
1197             info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
1198             int ctIdx = 0;
1199             // Format: VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16, Surface: kRGBA_10x6
1200             {
1201                 constexpr GrColorType ct = GrColorType::kRGBA_10x6;
1202                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
1203                 ctInfo.fColorType = ct;
1204                 ctInfo.fTransferColorType = ct;
1205                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
1206             }
1207         }
1208     }
1209 
1210     // Format: VK_FORMAT_B4G4R4A4_UNORM_PACK16
1211     {
1212         constexpr VkFormat format = VK_FORMAT_B4G4R4A4_UNORM_PACK16;
1213         auto& info = this->getFormatInfo(format);
1214         info.init(contextOptions, interface, physDev, properties, format);
1215         if (SkToBool(info.fOptimalFlags & FormatInfo::kTexturable_Flag)) {
1216             info.fColorTypeInfoCount = 1;
1217             info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
1218             int ctIdx = 0;
1219             // Format: VK_FORMAT_B4G4R4A4_UNORM_PACK16, Surface: kABGR_4444
1220             {
1221                 constexpr GrColorType ct = GrColorType::kABGR_4444;
1222                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
1223                 ctInfo.fColorType = ct;
1224                 ctInfo.fTransferColorType = ct;
1225                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
1226                 ctInfo.fReadSwizzle = skgpu::Swizzle::BGRA();
1227                 ctInfo.fWriteSwizzle = skgpu::Swizzle::BGRA();
1228             }
1229         }
1230     }
1231 
1232     // Format: VK_FORMAT_R4G4B4A4_UNORM_PACK16
1233     {
1234         constexpr VkFormat format = VK_FORMAT_R4G4B4A4_UNORM_PACK16;
1235         auto& info = this->getFormatInfo(format);
1236         info.init(contextOptions, interface, physDev, properties, format);
1237         if (SkToBool(info.fOptimalFlags & FormatInfo::kTexturable_Flag)) {
1238             info.fColorTypeInfoCount = 1;
1239             info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
1240             int ctIdx = 0;
1241             // Format: VK_FORMAT_R4G4B4A4_UNORM_PACK16, Surface: kABGR_4444
1242             {
1243                 constexpr GrColorType ct = GrColorType::kABGR_4444;
1244                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
1245                 ctInfo.fColorType = ct;
1246                 ctInfo.fTransferColorType = ct;
1247                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
1248             }
1249         }
1250     }
1251     // Format: VK_FORMAT_R8G8B8A8_SRGB
1252     {
1253         constexpr VkFormat format = VK_FORMAT_R8G8B8A8_SRGB;
1254         auto& info = this->getFormatInfo(format);
1255         info.init(contextOptions, interface, physDev, properties, format);
1256         if (SkToBool(info.fOptimalFlags & FormatInfo::kTexturable_Flag)) {
1257             info.fColorTypeInfoCount = 1;
1258             info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
1259             int ctIdx = 0;
1260             // Format: VK_FORMAT_R8G8B8A8_SRGB, Surface: kRGBA_8888_SRGB
1261             {
1262                 constexpr GrColorType ct = GrColorType::kRGBA_8888_SRGB;
1263                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
1264                 ctInfo.fColorType = ct;
1265                 ctInfo.fTransferColorType = ct;
1266                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
1267             }
1268         }
1269     }
1270     // Format: VK_FORMAT_R16_UNORM
1271     {
1272         constexpr VkFormat format = VK_FORMAT_R16_UNORM;
1273         auto& info = this->getFormatInfo(format);
1274         info.init(contextOptions, interface, physDev, properties, format);
1275         if (SkToBool(info.fOptimalFlags & FormatInfo::kTexturable_Flag)) {
1276             info.fColorTypeInfoCount = 1;
1277             info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
1278             int ctIdx = 0;
1279             // Format: VK_FORMAT_R16_UNORM, Surface: kAlpha_16
1280             {
1281                 constexpr GrColorType ct = GrColorType::kAlpha_16;
1282                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
1283                 ctInfo.fColorType = ct;
1284                 ctInfo.fTransferColorType = ct;
1285                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
1286                 ctInfo.fReadSwizzle = skgpu::Swizzle("000r");
1287                 ctInfo.fWriteSwizzle = skgpu::Swizzle("a000");
1288             }
1289         }
1290     }
1291     // Format: VK_FORMAT_R16G16_UNORM
1292     {
1293         constexpr VkFormat format = VK_FORMAT_R16G16_UNORM;
1294         auto& info = this->getFormatInfo(format);
1295         info.init(contextOptions, interface, physDev, properties, format);
1296         if (SkToBool(info.fOptimalFlags & FormatInfo::kTexturable_Flag)) {
1297             info.fColorTypeInfoCount = 1;
1298             info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
1299             int ctIdx = 0;
1300             // Format: VK_FORMAT_R16G16_UNORM, Surface: kRG_1616
1301             {
1302                 constexpr GrColorType ct = GrColorType::kRG_1616;
1303                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
1304                 ctInfo.fColorType = ct;
1305                 ctInfo.fTransferColorType = ct;
1306                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
1307             }
1308         }
1309     }
1310     // Format: VK_FORMAT_R16G16B16A16_UNORM
1311     {
1312         constexpr VkFormat format = VK_FORMAT_R16G16B16A16_UNORM;
1313         auto& info = this->getFormatInfo(format);
1314         info.init(contextOptions, interface, physDev, properties, format);
1315         if (SkToBool(info.fOptimalFlags & FormatInfo::kTexturable_Flag)) {
1316             info.fColorTypeInfoCount = 1;
1317             info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
1318             int ctIdx = 0;
1319             // Format: VK_FORMAT_R16G16B16A16_UNORM, Surface: kRGBA_16161616
1320             {
1321                 constexpr GrColorType ct = GrColorType::kRGBA_16161616;
1322                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
1323                 ctInfo.fColorType = ct;
1324                 ctInfo.fTransferColorType = ct;
1325                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
1326             }
1327         }
1328     }
1329     // Format: VK_FORMAT_R16G16_SFLOAT
1330     {
1331         constexpr VkFormat format = VK_FORMAT_R16G16_SFLOAT;
1332         auto& info = this->getFormatInfo(format);
1333         info.init(contextOptions, interface, physDev, properties, format);
1334         if (SkToBool(info.fOptimalFlags & FormatInfo::kTexturable_Flag)) {
1335             info.fColorTypeInfoCount = 1;
1336             info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
1337             int ctIdx = 0;
1338             // Format: VK_FORMAT_R16G16_SFLOAT, Surface: kRG_F16
1339             {
1340                 constexpr GrColorType ct = GrColorType::kRG_F16;
1341                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
1342                 ctInfo.fColorType = ct;
1343                 ctInfo.fTransferColorType = ct;
1344                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
1345             }
1346         }
1347     }
1348     // Format: VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM
1349     {
1350         constexpr VkFormat format = VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM;
1351         auto& info = this->getFormatInfo(format);
1352         if (fSupportsYcbcrConversion) {
1353             info.init(contextOptions, interface, physDev, properties, format);
1354         }
1355         if (SkToBool(info.fOptimalFlags & FormatInfo::kTexturable_Flag)) {
1356             info.fColorTypeInfoCount = 1;
1357             info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
1358             int ctIdx = 0;
1359             // Format: VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM, Surface: kRGB_888x
1360             {
1361                 constexpr GrColorType ct = GrColorType::kRGB_888x;
1362                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
1363                 ctInfo.fColorType = ct;
1364                 ctInfo.fTransferColorType = ct;
1365                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kWrappedOnly_Flag;
1366             }
1367         }
1368     }
1369     // Format: VK_FORMAT_G8_B8R8_2PLANE_420_UNORM
1370     {
1371         constexpr VkFormat format = VK_FORMAT_G8_B8R8_2PLANE_420_UNORM;
1372         auto& info = this->getFormatInfo(format);
1373         if (fSupportsYcbcrConversion) {
1374             info.init(contextOptions, interface, physDev, properties, format);
1375         }
1376         if (SkToBool(info.fOptimalFlags & FormatInfo::kTexturable_Flag)) {
1377             info.fColorTypeInfoCount = 1;
1378             info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
1379             int ctIdx = 0;
1380             // Format: VK_FORMAT_G8_B8R8_2PLANE_420_UNORM, Surface: kRGB_888x
1381             {
1382                 constexpr GrColorType ct = GrColorType::kRGB_888x;
1383                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
1384                 ctInfo.fColorType = ct;
1385                 ctInfo.fTransferColorType = ct;
1386                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kWrappedOnly_Flag;
1387             }
1388         }
1389     }
1390     // Format: VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16
1391     {
1392         constexpr VkFormat format = VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16;
1393         auto& info = this->getFormatInfo(format);
1394         if (fSupportsYcbcrConversion) {
1395             info.init(contextOptions, interface, physDev, properties, format);
1396         }
1397         if (SkToBool(info.fOptimalFlags & FormatInfo::kTexturable_Flag)) {
1398             info.fColorTypeInfoCount = 1;
1399             info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
1400             int ctIdx = 0;
1401             // Format: VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16, Surface: kRGBA_1010102
1402             {
1403                 constexpr GrColorType ct = GrColorType::kRGBA_1010102;
1404                 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
1405                 ctInfo.fColorType = ct;
1406                 ctInfo.fTransferColorType = ct;
1407                 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kWrappedOnly_Flag;
1408             }
1409         }
1410     }
1411     // Format: VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK
1412     {
1413         constexpr VkFormat format = VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK;
1414         auto& info = this->getFormatInfo(format);
1415         info.init(contextOptions, interface, physDev, properties, format);
1416         // Setting this to texel block size
1417         // No supported GrColorTypes.
1418     }
1419 
1420     // Format: VK_FORMAT_BC1_RGB_UNORM_BLOCK
1421     {
1422         constexpr VkFormat format = VK_FORMAT_BC1_RGB_UNORM_BLOCK;
1423         auto& info = this->getFormatInfo(format);
1424         info.init(contextOptions, interface, physDev, properties, format);
1425         // Setting this to texel block size
1426         // No supported GrColorTypes.
1427     }
1428 
1429     // Format: VK_FORMAT_BC1_RGBA_UNORM_BLOCK
1430     {
1431         constexpr VkFormat format = VK_FORMAT_BC1_RGBA_UNORM_BLOCK;
1432         auto& info = this->getFormatInfo(format);
1433         info.init(contextOptions, interface, physDev, properties, format);
1434         // Setting this to texel block size
1435         // No supported GrColorTypes.
1436     }
1437 
1438     ////////////////////////////////////////////////////////////////////////////
1439     // Map GrColorTypes (used for creating GrSurfaces) to VkFormats. The order in which the formats
1440     // are passed into the setColorType function indicates the priority in selecting which format
1441     // we use for a given GrcolorType.
1442 
1443     this->setColorType(GrColorType::kAlpha_8,          { VK_FORMAT_R8_UNORM });
1444     this->setColorType(GrColorType::kBGR_565,          { VK_FORMAT_R5G6B5_UNORM_PACK16,
1445                                                          VK_FORMAT_B5G6R5_UNORM_PACK16 });
1446     this->setColorType(GrColorType::kRGB_565,          { VK_FORMAT_B5G6R5_UNORM_PACK16 });
1447     this->setColorType(GrColorType::kABGR_4444,        { VK_FORMAT_R4G4B4A4_UNORM_PACK16,
1448                                                          VK_FORMAT_B4G4R4A4_UNORM_PACK16 });
1449     this->setColorType(GrColorType::kRGBA_8888,        { VK_FORMAT_R8G8B8A8_UNORM });
1450     this->setColorType(GrColorType::kRGBA_8888_SRGB,   { VK_FORMAT_R8G8B8A8_SRGB });
1451     this->setColorType(GrColorType::kRGB_888x,         { VK_FORMAT_R8G8B8_UNORM,
1452                                                          VK_FORMAT_R8G8B8A8_UNORM,
1453                                                          VK_FORMAT_B8G8R8A8_UNORM, });
1454     this->setColorType(GrColorType::kRG_88,            { VK_FORMAT_R8G8_UNORM });
1455     this->setColorType(GrColorType::kBGRA_8888,        { VK_FORMAT_B8G8R8A8_UNORM });
1456     this->setColorType(GrColorType::kRGBA_1010102,     { VK_FORMAT_A2B10G10R10_UNORM_PACK32 });
1457     this->setColorType(GrColorType::kBGRA_1010102,     { VK_FORMAT_A2R10G10B10_UNORM_PACK32 });
1458     this->setColorType(GrColorType::kRGB_101010x,      { VK_FORMAT_A2B10G10R10_UNORM_PACK32 });
1459     this->setColorType(GrColorType::kGray_8,           { VK_FORMAT_R8_UNORM });
1460     this->setColorType(GrColorType::kAlpha_F16,        { VK_FORMAT_R16_SFLOAT });
1461     this->setColorType(GrColorType::kRGBA_F16,         { VK_FORMAT_R16G16B16A16_SFLOAT });
1462     this->setColorType(GrColorType::kRGBA_F16_Clamped, { VK_FORMAT_R16G16B16A16_SFLOAT });
1463     this->setColorType(GrColorType::kRGB_F16F16F16x,   { VK_FORMAT_R16G16B16A16_SFLOAT});
1464     this->setColorType(GrColorType::kAlpha_16,         { VK_FORMAT_R16_UNORM });
1465     this->setColorType(GrColorType::kRG_1616,          { VK_FORMAT_R16G16_UNORM });
1466     this->setColorType(GrColorType::kRGBA_16161616,    { VK_FORMAT_R16G16B16A16_UNORM });
1467     this->setColorType(GrColorType::kRG_F16,           { VK_FORMAT_R16G16_SFLOAT });
1468 }
1469 
InitFormatFlags(VkFormatFeatureFlags vkFlags,uint16_t * flags)1470 void GrVkCaps::FormatInfo::InitFormatFlags(VkFormatFeatureFlags vkFlags, uint16_t* flags) {
1471     if (SkToBool(VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT & vkFlags) &&
1472         SkToBool(VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT & vkFlags)) {
1473         *flags = *flags | kTexturable_Flag;
1474 
1475         // Ganesh assumes that all renderable surfaces are also texturable
1476         if (SkToBool(VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT & vkFlags)) {
1477             *flags = *flags | kRenderable_Flag;
1478         }
1479     }
1480     // TODO: For Vk w/ VK_KHR_maintenance1 extension support, check
1481     //  VK_FORMAT_FEATURE_TRANSFER_[SRC|DST]_BIT_KHR explicitly to set copy flags
1482     //  Can do similar check for VK_KHR_sampler_ycbcr_conversion added bits
1483 
1484     if (SkToBool(VK_FORMAT_FEATURE_BLIT_SRC_BIT & vkFlags)) {
1485         *flags = *flags | kBlitSrc_Flag;
1486     }
1487 
1488     if (SkToBool(VK_FORMAT_FEATURE_BLIT_DST_BIT & vkFlags)) {
1489         *flags = *flags | kBlitDst_Flag;
1490     }
1491 }
1492 
initSampleCounts(const GrContextOptions & contextOptions,const skgpu::VulkanInterface * interface,VkPhysicalDevice physDev,const VkPhysicalDeviceProperties & physProps,VkFormat format)1493 void GrVkCaps::FormatInfo::initSampleCounts(const GrContextOptions& contextOptions,
1494                                             const skgpu::VulkanInterface* interface,
1495                                             VkPhysicalDevice physDev,
1496                                             const VkPhysicalDeviceProperties& physProps,
1497                                             VkFormat format) {
1498     VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
1499                               VK_IMAGE_USAGE_TRANSFER_DST_BIT |
1500                               VK_IMAGE_USAGE_SAMPLED_BIT |
1501                               VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
1502     VkImageFormatProperties properties;
1503     GR_VK_CALL(interface, GetPhysicalDeviceImageFormatProperties(physDev,
1504                                                                  format,
1505                                                                  VK_IMAGE_TYPE_2D,
1506                                                                  VK_IMAGE_TILING_OPTIMAL,
1507                                                                  usage,
1508                                                                  0,  // createFlags
1509                                                                  &properties));
1510     VkSampleCountFlags flags = properties.sampleCounts;
1511     if (flags & VK_SAMPLE_COUNT_1_BIT) {
1512         fColorSampleCounts.push_back(1);
1513     }
1514     if (kImagination_VkVendor == physProps.vendorID) {
1515         // MSAA does not work on imagination
1516         return;
1517     }
1518     if (kIntel_VkVendor == physProps.vendorID) {
1519         if (GetIntelGen(GetIntelGPUType(physProps.deviceID)) < 12 ||
1520             !contextOptions.fAllowMSAAOnNewIntel) {
1521             // MSAA doesn't work well on Intel GPUs chromium:527565, chromium:983926
1522             return;
1523         }
1524     }
1525     if (flags & VK_SAMPLE_COUNT_2_BIT) {
1526         fColorSampleCounts.push_back(2);
1527     }
1528     if (flags & VK_SAMPLE_COUNT_4_BIT) {
1529         fColorSampleCounts.push_back(4);
1530     }
1531     if (flags & VK_SAMPLE_COUNT_8_BIT) {
1532         fColorSampleCounts.push_back(8);
1533     }
1534     if (flags & VK_SAMPLE_COUNT_16_BIT) {
1535         fColorSampleCounts.push_back(16);
1536     }
1537     // Standard sample locations are not defined for more than 16 samples, and we don't need more
1538     // than 16. Omit 32 and 64.
1539 }
1540 
init(const GrContextOptions & contextOptions,const skgpu::VulkanInterface * interface,VkPhysicalDevice physDev,const VkPhysicalDeviceProperties & properties,VkFormat format)1541 void GrVkCaps::FormatInfo::init(const GrContextOptions& contextOptions,
1542                                 const skgpu::VulkanInterface* interface,
1543                                 VkPhysicalDevice physDev,
1544                                 const VkPhysicalDeviceProperties& properties,
1545                                 VkFormat format) {
1546     VkFormatProperties props;
1547     memset(&props, 0, sizeof(VkFormatProperties));
1548     GR_VK_CALL(interface, GetPhysicalDeviceFormatProperties(physDev, format, &props));
1549     InitFormatFlags(props.linearTilingFeatures, &fLinearFlags);
1550     InitFormatFlags(props.optimalTilingFeatures, &fOptimalFlags);
1551     if (fOptimalFlags & kRenderable_Flag) {
1552         this->initSampleCounts(contextOptions, interface, physDev, properties, format);
1553     }
1554 }
1555 
1556 // For many checks in caps, we need to know whether the GrBackendFormat is external or not. If it is
1557 // external the VkFormat will be VK_NULL_HANDLE which is not handled by our various format
1558 // capability checks.
backend_format_is_external(const GrBackendFormat & format)1559 static bool backend_format_is_external(const GrBackendFormat& format) {
1560     const skgpu::VulkanYcbcrConversionInfo* ycbcrInfo =
1561             GrBackendFormats::GetVkYcbcrConversionInfo(format);
1562     SkASSERT(ycbcrInfo);
1563 
1564     // All external formats have a valid ycbcrInfo used for sampling and a non zero external format.
1565     if (ycbcrInfo->isValid() && ycbcrInfo->fExternalFormat != 0) {
1566 #ifdef SK_DEBUG
1567         VkFormat vkFormat;
1568         SkAssertResult(GrBackendFormats::AsVkFormat(format, &vkFormat));
1569         SkASSERT(vkFormat == VK_FORMAT_UNDEFINED);
1570 #endif
1571         return true;
1572     }
1573     return false;
1574 }
1575 
isFormatSRGB(const GrBackendFormat & format) const1576 bool GrVkCaps::isFormatSRGB(const GrBackendFormat& format) const {
1577     VkFormat vkFormat;
1578     if (!GrBackendFormats::AsVkFormat(format, &vkFormat)) {
1579         return false;
1580     }
1581     if (backend_format_is_external(format)) {
1582         return false;
1583     }
1584 
1585     return format_is_srgb(vkFormat);
1586 }
1587 
isFormatTexturable(const GrBackendFormat & format,GrTextureType) const1588 bool GrVkCaps::isFormatTexturable(const GrBackendFormat& format, GrTextureType) const {
1589     VkFormat vkFormat;
1590     if (!GrBackendFormats::AsVkFormat(format, &vkFormat)) {
1591         return false;
1592     }
1593     if (backend_format_is_external(format)) {
1594         // We can always texture from an external format (assuming we have the ycbcr conversion
1595         // info which we require to be passed in).
1596         return true;
1597     }
1598     return this->isVkFormatTexturable(vkFormat);
1599 }
1600 
isVkFormatTexturable(VkFormat format) const1601 bool GrVkCaps::isVkFormatTexturable(VkFormat format) const {
1602     const FormatInfo& info = this->getFormatInfo(format);
1603     return SkToBool(FormatInfo::kTexturable_Flag & info.fOptimalFlags);
1604 }
1605 
isFormatAsColorTypeRenderable(GrColorType ct,const GrBackendFormat & format,int sampleCount) const1606 bool GrVkCaps::isFormatAsColorTypeRenderable(GrColorType ct, const GrBackendFormat& format,
1607                                              int sampleCount) const {
1608     if (!this->isFormatRenderable(format, sampleCount)) {
1609         return false;
1610     }
1611     VkFormat vkFormat;
1612     if (!GrBackendFormats::AsVkFormat(format, &vkFormat)) {
1613         return false;
1614     }
1615     const auto& info = this->getFormatInfo(vkFormat);
1616     if (!SkToBool(info.colorTypeFlags(ct) & ColorTypeInfo::kRenderable_Flag)) {
1617         return false;
1618     }
1619     return true;
1620 }
1621 
isFormatRenderable(const GrBackendFormat & format,int sampleCount) const1622 bool GrVkCaps::isFormatRenderable(const GrBackendFormat& format, int sampleCount) const {
1623     VkFormat vkFormat;
1624     if (!GrBackendFormats::AsVkFormat(format, &vkFormat)) {
1625         return false;
1626     }
1627     return this->isFormatRenderable(vkFormat, sampleCount);
1628 }
1629 
isFormatRenderable(VkFormat format,int sampleCount) const1630 bool GrVkCaps::isFormatRenderable(VkFormat format, int sampleCount) const {
1631     return sampleCount <= this->maxRenderTargetSampleCount(format);
1632 }
1633 
getRenderTargetSampleCount(int requestedCount,const GrBackendFormat & format) const1634 int GrVkCaps::getRenderTargetSampleCount(int requestedCount,
1635                                          const GrBackendFormat& format) const {
1636     VkFormat vkFormat;
1637     if (!GrBackendFormats::AsVkFormat(format, &vkFormat)) {
1638         return 0;
1639     }
1640 
1641     return this->getRenderTargetSampleCount(requestedCount, vkFormat);
1642 }
1643 
getRenderTargetSampleCount(int requestedCount,VkFormat format) const1644 int GrVkCaps::getRenderTargetSampleCount(int requestedCount, VkFormat format) const {
1645     requestedCount = std::max(1, requestedCount);
1646 
1647     const FormatInfo& info = this->getFormatInfo(format);
1648 
1649     int count = info.fColorSampleCounts.size();
1650 
1651     if (!count) {
1652         return 0;
1653     }
1654 
1655     if (1 == requestedCount) {
1656         SkASSERT(!info.fColorSampleCounts.empty() && info.fColorSampleCounts[0] == 1);
1657         return 1;
1658     }
1659 
1660     for (int i = 0; i < count; ++i) {
1661         if (info.fColorSampleCounts[i] >= requestedCount) {
1662             return info.fColorSampleCounts[i];
1663         }
1664     }
1665     return 0;
1666 }
1667 
maxRenderTargetSampleCount(const GrBackendFormat & format) const1668 int GrVkCaps::maxRenderTargetSampleCount(const GrBackendFormat& format) const {
1669     VkFormat vkFormat;
1670     if (!GrBackendFormats::AsVkFormat(format, &vkFormat)) {
1671         return 0;
1672     }
1673     return this->maxRenderTargetSampleCount(vkFormat);
1674 }
1675 
maxRenderTargetSampleCount(VkFormat format) const1676 int GrVkCaps::maxRenderTargetSampleCount(VkFormat format) const {
1677     const FormatInfo& info = this->getFormatInfo(format);
1678 
1679     const auto& table = info.fColorSampleCounts;
1680     if (table.empty()) {
1681         return 0;
1682     }
1683     return table[table.size() - 1];
1684 }
1685 
align_to_4(size_t v)1686 static inline size_t align_to_4(size_t v) {
1687     switch (v & 0b11) {
1688         // v is already a multiple of 4.
1689         case 0:     return v;
1690         // v is a multiple of 2 but not 4.
1691         case 2:     return 2 * v;
1692         // v is not a multiple of 2.
1693         default:    return 4 * v;
1694     }
1695 }
1696 
supportedWritePixelsColorType(GrColorType surfaceColorType,const GrBackendFormat & surfaceFormat,GrColorType srcColorType) const1697 GrCaps::SupportedWrite GrVkCaps::supportedWritePixelsColorType(GrColorType surfaceColorType,
1698                                                                const GrBackendFormat& surfaceFormat,
1699                                                                GrColorType srcColorType) const {
1700     VkFormat vkFormat;
1701     if (!GrBackendFormats::AsVkFormat(surfaceFormat, &vkFormat)) {
1702         return {GrColorType::kUnknown, 0};
1703     }
1704 
1705     // We don't support the ability to upload to external formats or formats that require a ycbcr
1706     // sampler. In general these types of formats are only used for sampling in a shader.
1707     if (backend_format_is_external(surfaceFormat) || skgpu::VkFormatNeedsYcbcrSampler(vkFormat)) {
1708         return {GrColorType::kUnknown, 0};
1709     }
1710 
1711     // The VkBufferImageCopy bufferOffset field must be both a multiple of 4 and of a single texel.
1712     size_t offsetAlignment = align_to_4(skgpu::VkFormatBytesPerBlock(vkFormat));
1713 
1714     const auto& info = this->getFormatInfo(vkFormat);
1715     for (int i = 0; i < info.fColorTypeInfoCount; ++i) {
1716         const auto& ctInfo = info.fColorTypeInfos[i];
1717         if (ctInfo.fColorType == surfaceColorType) {
1718             return {ctInfo.fTransferColorType, offsetAlignment};
1719         }
1720     }
1721     return {GrColorType::kUnknown, 0};
1722 }
1723 
surfaceSupportsReadPixels(const GrSurface * surface) const1724 GrCaps::SurfaceReadPixelsSupport GrVkCaps::surfaceSupportsReadPixels(
1725         const GrSurface* surface) const {
1726     if (surface->isProtected()) {
1727         return SurfaceReadPixelsSupport::kUnsupported;
1728     }
1729     if (auto tex = static_cast<const GrVkTexture*>(surface->asTexture())) {
1730         auto texImage = tex->textureImage();
1731         if (!texImage) {
1732             return SurfaceReadPixelsSupport::kUnsupported;
1733         }
1734         // We can't directly read from a VkImage that has a ycbcr sampler.
1735         if (texImage->ycbcrConversionInfo().isValid()) {
1736             return SurfaceReadPixelsSupport::kCopyToTexture2D;
1737         }
1738         // We can't directly read from a compressed format
1739         if (skgpu::VkFormatIsCompressed(texImage->imageFormat())) {
1740             return SurfaceReadPixelsSupport::kCopyToTexture2D;
1741         }
1742         return SurfaceReadPixelsSupport::kSupported;
1743     } else if (auto rt = surface->asRenderTarget()) {
1744         if (rt->numSamples() > 1) {
1745             return SurfaceReadPixelsSupport::kCopyToTexture2D;
1746         }
1747         return SurfaceReadPixelsSupport::kSupported;
1748     }
1749     return SurfaceReadPixelsSupport::kUnsupported;
1750 }
1751 
transferColorType(VkFormat vkFormat,GrColorType surfaceColorType) const1752 GrColorType GrVkCaps::transferColorType(VkFormat vkFormat, GrColorType surfaceColorType) const {
1753     const auto& info = this->getFormatInfo(vkFormat);
1754     for (int i = 0; i < info.fColorTypeInfoCount; ++i) {
1755         if (info.fColorTypeInfos[i].fColorType == surfaceColorType) {
1756             return info.fColorTypeInfos[i].fTransferColorType;
1757         }
1758     }
1759     return GrColorType::kUnknown;
1760 }
1761 
onSurfaceSupportsWritePixels(const GrSurface * surface) const1762 bool GrVkCaps::onSurfaceSupportsWritePixels(const GrSurface* surface) const {
1763     if (auto rt = surface->asRenderTarget()) {
1764         return rt->numSamples() <= 1 && SkToBool(surface->asTexture());
1765     }
1766     // We can't write to a texture that has a ycbcr sampler.
1767     if (auto tex = static_cast<const GrVkTexture*>(surface->asTexture())) {
1768         auto texImage = tex->textureImage();
1769         if (!texImage) {
1770             return false;
1771         }
1772         // We can't directly read from a VkImage that has a ycbcr sampler.
1773         if (texImage->ycbcrConversionInfo().isValid()) {
1774             return false;
1775         }
1776     }
1777     return true;
1778 }
1779 
onAreColorTypeAndFormatCompatible(GrColorType ct,const GrBackendFormat & format) const1780 bool GrVkCaps::onAreColorTypeAndFormatCompatible(GrColorType ct,
1781                                                  const GrBackendFormat& format) const {
1782     VkFormat vkFormat;
1783     if (!GrBackendFormats::AsVkFormat(format, &vkFormat)) {
1784         return false;
1785     }
1786     const skgpu::VulkanYcbcrConversionInfo* ycbcrInfo =
1787             GrBackendFormats::GetVkYcbcrConversionInfo(format);
1788     SkASSERT(ycbcrInfo);
1789 
1790     if (ycbcrInfo->isValid() && !skgpu::VkFormatNeedsYcbcrSampler(vkFormat)) {
1791         // Format may be undefined for external images, which are required to have YCbCr conversion.
1792         if (VK_FORMAT_UNDEFINED == vkFormat && ycbcrInfo->fExternalFormat != 0) {
1793             return true;
1794         }
1795         return false;
1796     }
1797 
1798     const auto& info = this->getFormatInfo(vkFormat);
1799     for (int i = 0; i < info.fColorTypeInfoCount; ++i) {
1800         if (info.fColorTypeInfos[i].fColorType == ct) {
1801             return true;
1802         }
1803     }
1804     return false;
1805 }
1806 
onGetDefaultBackendFormat(GrColorType ct) const1807 GrBackendFormat GrVkCaps::onGetDefaultBackendFormat(GrColorType ct) const {
1808     VkFormat format = this->getFormatFromColorType(ct);
1809     if (format == VK_FORMAT_UNDEFINED) {
1810         return {};
1811     }
1812     return GrBackendFormats::MakeVk(format);
1813 }
1814 
onSupportsDynamicMSAA(const GrRenderTargetProxy * rtProxy) const1815 bool GrVkCaps::onSupportsDynamicMSAA(const GrRenderTargetProxy* rtProxy) const {
1816     // We must be able to use the rtProxy as an input attachment to load into the discardable msaa
1817     // attachment. Also the rtProxy should have a sample count of 1 so that it can be used as a
1818     // resolve attachment.
1819     return this->supportsDiscardableMSAAForDMSAA() &&
1820            rtProxy->supportsVkInputAttachment() &&
1821            rtProxy->numSamples() == 1;
1822 }
1823 
renderTargetSupportsDiscardableMSAA(const GrVkRenderTarget * rt) const1824 bool GrVkCaps::renderTargetSupportsDiscardableMSAA(const GrVkRenderTarget* rt) const {
1825     return rt->resolveAttachment() &&
1826            rt->resolveAttachment()->supportsInputAttachmentUsage() &&
1827            ((rt->numSamples() > 1 && this->preferDiscardableMSAAAttachment()) ||
1828             (rt->numSamples() == 1 && this->supportsDiscardableMSAAForDMSAA()));
1829 }
1830 
programInfoWillUseDiscardableMSAA(const GrProgramInfo & programInfo) const1831 bool GrVkCaps::programInfoWillUseDiscardableMSAA(const GrProgramInfo& programInfo) const {
1832     return programInfo.targetHasVkResolveAttachmentWithInput() &&
1833            programInfo.numSamples() > 1 &&
1834            ((programInfo.targetsNumSamples() > 1 && this->preferDiscardableMSAAAttachment()) ||
1835             (programInfo.targetsNumSamples() == 1 && this->supportsDiscardableMSAAForDMSAA()));
1836 }
1837 
getBackendFormatFromCompressionType(SkTextureCompressionType compressionType) const1838 GrBackendFormat GrVkCaps::getBackendFormatFromCompressionType(
1839         SkTextureCompressionType compressionType) const {
1840     switch (compressionType) {
1841         case SkTextureCompressionType::kNone:
1842             return {};
1843         case SkTextureCompressionType::kETC2_RGB8_UNORM:
1844             if (this->isVkFormatTexturable(VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK)) {
1845                 return GrBackendFormats::MakeVk(VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK);
1846             }
1847             return {};
1848         case SkTextureCompressionType::kBC1_RGB8_UNORM:
1849             if (this->isVkFormatTexturable(VK_FORMAT_BC1_RGB_UNORM_BLOCK)) {
1850                 return GrBackendFormats::MakeVk(VK_FORMAT_BC1_RGB_UNORM_BLOCK);
1851             }
1852             return {};
1853         case SkTextureCompressionType::kBC1_RGBA8_UNORM:
1854             if (this->isVkFormatTexturable(VK_FORMAT_BC1_RGBA_UNORM_BLOCK)) {
1855                 return GrBackendFormats::MakeVk(VK_FORMAT_BC1_RGBA_UNORM_BLOCK);
1856             }
1857             return {};
1858     }
1859 
1860     SkUNREACHABLE;
1861 }
1862 
onGetReadSwizzle(const GrBackendFormat & format,GrColorType colorType) const1863 skgpu::Swizzle GrVkCaps::onGetReadSwizzle(const GrBackendFormat& format,
1864                                           GrColorType colorType) const {
1865     VkFormat vkFormat;
1866     SkAssertResult(GrBackendFormats::AsVkFormat(format, &vkFormat));
1867     const skgpu::VulkanYcbcrConversionInfo* ycbcrInfo =
1868             GrBackendFormats::GetVkYcbcrConversionInfo(format);
1869     SkASSERT(ycbcrInfo);
1870     if (ycbcrInfo->isValid() && ycbcrInfo->fExternalFormat != 0) {
1871         // We allow these to work with any color type and never swizzle. See
1872         // onAreColorTypeAndFormatCompatible.
1873         return skgpu::Swizzle{"rgba"};
1874     }
1875 
1876     const auto& info = this->getFormatInfo(vkFormat);
1877     for (int i = 0; i < info.fColorTypeInfoCount; ++i) {
1878         const auto& ctInfo = info.fColorTypeInfos[i];
1879         if (ctInfo.fColorType == colorType) {
1880             return ctInfo.fReadSwizzle;
1881         }
1882     }
1883     SkDEBUGFAILF("Illegal color type (%d) and format (%d) combination.",
1884                  (int)colorType, (int)vkFormat);
1885     return {};
1886 }
1887 
getWriteSwizzle(const GrBackendFormat & format,GrColorType colorType) const1888 skgpu::Swizzle GrVkCaps::getWriteSwizzle(const GrBackendFormat& format,
1889                                          GrColorType colorType) const {
1890     VkFormat vkFormat;
1891     SkAssertResult(GrBackendFormats::AsVkFormat(format, &vkFormat));
1892     const auto& info = this->getFormatInfo(vkFormat);
1893     for (int i = 0; i < info.fColorTypeInfoCount; ++i) {
1894         const auto& ctInfo = info.fColorTypeInfos[i];
1895         if (ctInfo.fColorType == colorType) {
1896             return ctInfo.fWriteSwizzle;
1897         }
1898     }
1899     SkDEBUGFAILF("Illegal color type (%d) and format (%d) combination.",
1900                  (int)colorType, (int)vkFormat);
1901     return {};
1902 }
1903 
onGetDstSampleFlagsForProxy(const GrRenderTargetProxy * rt) const1904 GrDstSampleFlags GrVkCaps::onGetDstSampleFlagsForProxy(const GrRenderTargetProxy* rt) const {
1905     bool isMSAAWithResolve = rt->numSamples() > 1 && rt->asTextureProxy();
1906     // TODO: Currently if we have an msaa rt with a resolve, the supportsVkInputAttachment call
1907     // references whether the resolve is supported as an input attachment. We need to add a check to
1908     // allow checking the color attachment (msaa or not) supports input attachment specifically.
1909     if (!isMSAAWithResolve && rt->supportsVkInputAttachment()) {
1910         return GrDstSampleFlags::kRequiresTextureBarrier | GrDstSampleFlags::kAsInputAttachment;
1911     }
1912     return GrDstSampleFlags::kNone;
1913 }
1914 
computeFormatKey(const GrBackendFormat & format) const1915 uint64_t GrVkCaps::computeFormatKey(const GrBackendFormat& format) const {
1916     VkFormat vkFormat;
1917     SkAssertResult(GrBackendFormats::AsVkFormat(format, &vkFormat));
1918 
1919 #ifdef SK_DEBUG
1920     // We should never be trying to compute a key for an external format
1921     const skgpu::VulkanYcbcrConversionInfo* ycbcrInfo =
1922             GrBackendFormats::GetVkYcbcrConversionInfo(format);
1923     SkASSERT(ycbcrInfo);
1924     SkASSERT(!ycbcrInfo->isValid() || ycbcrInfo->fExternalFormat == 0);
1925 #endif
1926 
1927     // A VkFormat has a size of 64 bits.
1928     return (uint64_t)vkFormat;
1929 }
1930 
onSupportedReadPixelsColorType(GrColorType srcColorType,const GrBackendFormat & srcBackendFormat,GrColorType dstColorType) const1931 GrCaps::SupportedRead GrVkCaps::onSupportedReadPixelsColorType(
1932         GrColorType srcColorType, const GrBackendFormat& srcBackendFormat,
1933         GrColorType dstColorType) const {
1934     VkFormat vkFormat;
1935     if (!GrBackendFormats::AsVkFormat(srcBackendFormat, &vkFormat)) {
1936         return {GrColorType::kUnknown, 0};
1937     }
1938 
1939     if (skgpu::VkFormatNeedsYcbcrSampler(vkFormat)) {
1940         return {GrColorType::kUnknown, 0};
1941     }
1942 
1943     SkTextureCompressionType compression = GrBackendFormatToCompressionType(srcBackendFormat);
1944     if (compression != SkTextureCompressionType::kNone) {
1945         return { SkTextureCompressionTypeIsOpaque(compression) ? GrColorType::kRGB_888x
1946                                                         : GrColorType::kRGBA_8888, 0 };
1947     }
1948 
1949     // The VkBufferImageCopy bufferOffset field must be both a multiple of 4 and of a single texel.
1950     size_t offsetAlignment = align_to_4(skgpu::VkFormatBytesPerBlock(vkFormat));
1951 
1952     const auto& info = this->getFormatInfo(vkFormat);
1953     for (int i = 0; i < info.fColorTypeInfoCount; ++i) {
1954         const auto& ctInfo = info.fColorTypeInfos[i];
1955         if (ctInfo.fColorType == srcColorType) {
1956             return {ctInfo.fTransferColorType, offsetAlignment};
1957         }
1958     }
1959     return {GrColorType::kUnknown, 0};
1960 }
1961 
getFragmentUniformBinding() const1962 int GrVkCaps::getFragmentUniformBinding() const {
1963     return GrVkUniformHandler::kUniformBinding;
1964 }
1965 
getFragmentUniformSet() const1966 int GrVkCaps::getFragmentUniformSet() const {
1967     return GrVkUniformHandler::kUniformBufferDescSet;
1968 }
1969 
addExtraSamplerKey(skgpu::KeyBuilder * b,GrSamplerState samplerState,const GrBackendFormat & format) const1970 void GrVkCaps::addExtraSamplerKey(skgpu::KeyBuilder* b,
1971                                   GrSamplerState samplerState,
1972                                   const GrBackendFormat& format) const {
1973     const skgpu::VulkanYcbcrConversionInfo* ycbcrInfo =
1974             GrBackendFormats::GetVkYcbcrConversionInfo(format);
1975     if (!ycbcrInfo) {
1976         return;
1977     }
1978 
1979     GrVkSampler::Key key = GrVkSampler::GenerateKey(samplerState, *ycbcrInfo);
1980 
1981     constexpr size_t numInts = (sizeof(key) + 3) / 4;
1982     uint32_t tmp[numInts];
1983     memcpy(tmp, &key, sizeof(key));
1984 
1985     for (size_t i = 0; i < numInts; ++i) {
1986         b->add32(tmp[i]);
1987     }
1988 }
1989 
1990 /**
1991  * For Vulkan we want to cache the entire VkPipeline for reuse of draws. The Desc here holds all
1992  * the information needed to differentiate one pipeline from another.
1993  *
1994  * The GrProgramDesc contains all the information need to create the actual shaders for the
1995  * pipeline.
1996  *
1997  * For Vulkan we need to add to the GrProgramDesc to include the rest of the state on the
1998  * pipline. This includes stencil settings, blending information, render pass format, draw face
1999  * information, and primitive type. Note that some state is set dynamically on the pipeline for
2000  * each draw  and thus is not included in this descriptor. This includes the viewport, scissor,
2001  * and blend constant.
2002  */
makeDesc(GrRenderTarget * rt,const GrProgramInfo & programInfo,ProgramDescOverrideFlags overrideFlags) const2003 GrProgramDesc GrVkCaps::makeDesc(GrRenderTarget* rt,
2004                                  const GrProgramInfo& programInfo,
2005                                  ProgramDescOverrideFlags overrideFlags) const {
2006     GrProgramDesc desc;
2007     GrProgramDesc::Build(&desc, programInfo, *this);
2008 
2009     skgpu::KeyBuilder b(desc.key());
2010 
2011     // This will become part of the sheared off key used to persistently cache
2012     // the SPIRV code. It needs to be added right after the base key so that,
2013     // when the base-key is sheared off, the shearing code can include it in the
2014     // reduced key (c.f. the +4s in the SkData::MakeWithCopy calls in
2015     // GrVkPipelineStateBuilder.cpp).
2016     b.add32(GrVkGpu::kShader_PersistentCacheKeyType);
2017 
2018     GrVkRenderPass::SelfDependencyFlags selfDepFlags = GrVkRenderPass::SelfDependencyFlags::kNone;
2019     if (programInfo.renderPassBarriers() & GrXferBarrierFlags::kBlend) {
2020         selfDepFlags |= GrVkRenderPass::SelfDependencyFlags::kForNonCoherentAdvBlend;
2021     }
2022     if (programInfo.renderPassBarriers() & GrXferBarrierFlags::kTexture) {
2023         selfDepFlags |= GrVkRenderPass::SelfDependencyFlags::kForInputAttachment;
2024     }
2025 
2026     bool needsResolve = this->programInfoWillUseDiscardableMSAA(programInfo);
2027 
2028     bool forceLoadFromResolve =
2029             overrideFlags & GrCaps::ProgramDescOverrideFlags::kVulkanHasResolveLoadSubpass;
2030     SkASSERT(!forceLoadFromResolve || needsResolve);
2031 
2032     GrVkRenderPass::LoadFromResolve loadFromResolve = GrVkRenderPass::LoadFromResolve::kNo;
2033     if (needsResolve && (programInfo.colorLoadOp() == GrLoadOp::kLoad || forceLoadFromResolve)) {
2034         loadFromResolve = GrVkRenderPass::LoadFromResolve::kLoad;
2035     }
2036 
2037     if (rt) {
2038         GrVkRenderTarget* vkRT = (GrVkRenderTarget*) rt;
2039 
2040         SkASSERT(!needsResolve || (vkRT->resolveAttachment() &&
2041                                    vkRT->resolveAttachment()->supportsInputAttachmentUsage()));
2042 
2043         bool needsStencil = programInfo.needsStencil() || programInfo.isStencilEnabled();
2044         // TODO: support failure in getSimpleRenderPass
2045         auto rp = vkRT->getSimpleRenderPass(needsResolve, needsStencil, selfDepFlags,
2046                                             loadFromResolve);
2047         SkASSERT(rp);
2048         rp->genKey(&b);
2049 
2050 #ifdef SK_DEBUG
2051         if (!rp->isExternal()) {
2052             // This is to ensure ReconstructAttachmentsDescriptor keeps matching
2053             // getSimpleRenderPass' result
2054             GrVkRenderPass::AttachmentsDescriptor attachmentsDescriptor;
2055             GrVkRenderPass::AttachmentFlags attachmentFlags;
2056             GrVkRenderTarget::ReconstructAttachmentsDescriptor(*this, programInfo,
2057                                                                &attachmentsDescriptor,
2058                                                                &attachmentFlags);
2059             SkASSERT(rp->isCompatible(attachmentsDescriptor, attachmentFlags, selfDepFlags,
2060                                       loadFromResolve));
2061         }
2062 #endif
2063     } else {
2064         GrVkRenderPass::AttachmentsDescriptor attachmentsDescriptor;
2065         GrVkRenderPass::AttachmentFlags attachmentFlags;
2066         GrVkRenderTarget::ReconstructAttachmentsDescriptor(*this, programInfo,
2067                                                            &attachmentsDescriptor,
2068                                                            &attachmentFlags);
2069 
2070         // kExternal_AttachmentFlag is only set for wrapped secondary command buffers - which
2071         // will always go through the above 'rt' path (i.e., we can always pass 0 as the final
2072         // parameter to GenKey).
2073         GrVkRenderPass::GenKey(&b, attachmentFlags, attachmentsDescriptor, selfDepFlags,
2074                                loadFromResolve, 0);
2075     }
2076 
2077     GrStencilSettings stencil = programInfo.nonGLStencilSettings();
2078     stencil.genKey(&b, true);
2079 
2080     programInfo.pipeline().genKey(&b, *this);
2081     b.add32(programInfo.numSamples());
2082 
2083     // Vulkan requires the full primitive type as part of its key
2084     b.add32(programInfo.primitiveTypeKey());
2085 
2086     b.flush();
2087     return desc;
2088 }
2089 
getExtraSurfaceFlagsForDeferredRT() const2090 GrInternalSurfaceFlags GrVkCaps::getExtraSurfaceFlagsForDeferredRT() const {
2091     // We always create vulkan RT with the input attachment flag;
2092     return GrInternalSurfaceFlags::kVkRTSupportsInputAttachment;
2093 }
2094 
getPushConstantStageFlags() const2095 VkShaderStageFlags GrVkCaps::getPushConstantStageFlags() const {
2096     VkShaderStageFlags stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT;
2097     return stageFlags;
2098 }
2099 
2100 template <size_t N>
intel_deviceID_present(const std::array<uint32_t,N> & array,uint32_t deviceID)2101 static bool intel_deviceID_present(const std::array<uint32_t, N>& array, uint32_t deviceID) {
2102     return std::find(array.begin(), array.end(), deviceID) != array.end();
2103 }
2104 
2105 
GetIntelGPUType(uint32_t deviceID)2106 GrVkCaps::IntelGPUType GrVkCaps::GetIntelGPUType(uint32_t deviceID) {
2107     // Some common Intel GPU models, currently we cover SKL/ICL/RKL/TGL/ADL
2108     // Referenced from the following Mesa source files:
2109     // https://github.com/mesa3d/mesa/blob/master/include/pci_ids/i965_pci_ids.h
2110     // https://github.com/mesa3d/mesa/blob/master/include/pci_ids/iris_pci_ids.h
2111     static constexpr std::array<uint32_t, 25> kSkyLakeIDs = {
2112         {0x1902, 0x1906, 0x190A, 0x190B, 0x190E, 0x1912, 0x1913,
2113          0x1915, 0x1916, 0x1917, 0x191A, 0x191B, 0x191D, 0x191E,
2114          0x1921, 0x1923, 0x1926, 0x1927, 0x192A, 0x192B, 0x192D,
2115          0x1932, 0x193A, 0x193B, 0x193D}};
2116     static constexpr std::array<uint32_t, 14> kIceLakeIDs = {
2117         {0x8A50, 0x8A51, 0x8A52, 0x8A53, 0x8A54, 0x8A56, 0x8A57,
2118          0x8A58, 0x8A59, 0x8A5A, 0x8A5B, 0x8A5C, 0x8A5D, 0x8A71}};
2119     static constexpr  std::array<uint32_t, 5> kRocketLakeIDs = {
2120         {0x4c8a, 0x4c8b, 0x4c8c, 0x4c90, 0x4c9a}};
2121     static constexpr  std::array<uint32_t, 11> kTigerLakeIDs = {
2122         {0x9A40, 0x9A49, 0x9A59, 0x9A60, 0x9A68, 0x9A70,
2123          0x9A78, 0x9AC0, 0x9AC9, 0x9AD9, 0x9AF8}};
2124     static constexpr  std::array<uint32_t, 10> kAlderLakeIDs = {
2125         {0x4680, 0x4681, 0x4682, 0x4683, 0x4690,
2126          0x4691, 0x4692, 0x4693, 0x4698, 0x4699}};
2127 
2128     if (intel_deviceID_present(kSkyLakeIDs, deviceID)) {
2129         return IntelGPUType::kSkyLake;
2130     }
2131     if (intel_deviceID_present(kIceLakeIDs, deviceID)) {
2132         return IntelGPUType::kIceLake;
2133     }
2134     if (intel_deviceID_present(kRocketLakeIDs, deviceID)) {
2135         return IntelGPUType::kRocketLake;
2136     }
2137     if (intel_deviceID_present(kTigerLakeIDs, deviceID)) {
2138         return IntelGPUType::kTigerLake;
2139     }
2140     if (intel_deviceID_present(kAlderLakeIDs, deviceID)) {
2141         return IntelGPUType::kAlderLake;
2142     }
2143     return IntelGPUType::kOther;
2144 }
2145 
2146 #if defined(GPU_TEST_UTILS)
getTestingCombinations() const2147 std::vector<GrTest::TestFormatColorTypeCombination> GrVkCaps::getTestingCombinations() const {
2148     std::vector<GrTest::TestFormatColorTypeCombination> combos = {
2149         { GrColorType::kAlpha_8,          GrBackendFormats::MakeVk(VK_FORMAT_R8_UNORM)            },
2150         { GrColorType::kBGR_565,          GrBackendFormats::MakeVk(VK_FORMAT_R5G6B5_UNORM_PACK16) },
2151         { GrColorType::kRGB_565,          GrBackendFormats::MakeVk(VK_FORMAT_B5G6R5_UNORM_PACK16) },
2152         { GrColorType::kABGR_4444,       GrBackendFormats::MakeVk(VK_FORMAT_R4G4B4A4_UNORM_PACK16)},
2153         { GrColorType::kABGR_4444,       GrBackendFormats::MakeVk(VK_FORMAT_B4G4R4A4_UNORM_PACK16)},
2154         { GrColorType::kRGBA_8888,        GrBackendFormats::MakeVk(VK_FORMAT_R8G8B8A8_UNORM)      },
2155         { GrColorType::kRGBA_8888_SRGB,   GrBackendFormats::MakeVk(VK_FORMAT_R8G8B8A8_SRGB)       },
2156         { GrColorType::kRGB_888x,         GrBackendFormats::MakeVk(VK_FORMAT_R8G8B8A8_UNORM)      },
2157         { GrColorType::kRGB_888x,         GrBackendFormats::MakeVk(VK_FORMAT_B8G8R8A8_UNORM)      },
2158         { GrColorType::kRGB_888x,         GrBackendFormats::MakeVk(VK_FORMAT_R8G8B8_UNORM)        },
2159         { GrColorType::kRG_88,            GrBackendFormats::MakeVk(VK_FORMAT_R8G8_UNORM)          },
2160         { GrColorType::kBGRA_8888,        GrBackendFormats::MakeVk(VK_FORMAT_B8G8R8A8_UNORM)      },
2161         { GrColorType::kRGBA_1010102, GrBackendFormats::MakeVk(VK_FORMAT_A2B10G10R10_UNORM_PACK32)},
2162         { GrColorType::kBGRA_1010102, GrBackendFormats::MakeVk(VK_FORMAT_A2R10G10B10_UNORM_PACK32)},
2163         { GrColorType::kRGB_101010x, GrBackendFormats::MakeVk(VK_FORMAT_A2B10G10R10_UNORM_PACK32)},
2164         { GrColorType::kRGBA_10x6,
2165           GrBackendFormats::MakeVk(VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16)},
2166         { GrColorType::kGray_8,           GrBackendFormats::MakeVk(VK_FORMAT_R8_UNORM)            },
2167         { GrColorType::kAlpha_F16,        GrBackendFormats::MakeVk(VK_FORMAT_R16_SFLOAT)          },
2168         { GrColorType::kRGBA_F16,         GrBackendFormats::MakeVk(VK_FORMAT_R16G16B16A16_SFLOAT) },
2169         { GrColorType::kRGBA_F16_Clamped, GrBackendFormats::MakeVk(VK_FORMAT_R16G16B16A16_SFLOAT) },
2170         { GrColorType::kRGB_F16F16F16x,   GrBackendFormats::MakeVk(VK_FORMAT_R16G16B16A16_SFLOAT) },
2171         { GrColorType::kAlpha_16,         GrBackendFormats::MakeVk(VK_FORMAT_R16_UNORM)           },
2172         { GrColorType::kRG_1616,          GrBackendFormats::MakeVk(VK_FORMAT_R16G16_UNORM)        },
2173         { GrColorType::kRGBA_16161616,    GrBackendFormats::MakeVk(VK_FORMAT_R16G16B16A16_UNORM)  },
2174         { GrColorType::kRG_F16,           GrBackendFormats::MakeVk(VK_FORMAT_R16G16_SFLOAT)       },
2175         // These two compressed formats both have an effective colorType of kRGB_888x
2176         { GrColorType::kRGB_888x,      GrBackendFormats::MakeVk(VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK)},
2177         { GrColorType::kRGB_888x,         GrBackendFormats::MakeVk(VK_FORMAT_BC1_RGB_UNORM_BLOCK) },
2178         { GrColorType::kRGBA_8888,        GrBackendFormats::MakeVk(VK_FORMAT_BC1_RGBA_UNORM_BLOCK)},
2179     };
2180 
2181     return combos;
2182 }
2183 #endif
2184