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