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