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