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