1 /*
2 * Copyright 2022 Google LLC
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/graphite/vk/VulkanCaps.h"
9
10 #include "include/core/SkTextureCompressionType.h"
11 #include "include/gpu/graphite/ContextOptions.h"
12 #include "include/gpu/graphite/TextureInfo.h"
13 #include "include/gpu/graphite/vk/VulkanGraphiteTypes.h"
14 #include "include/gpu/vk/VulkanExtensions.h"
15 #include "include/gpu/vk/VulkanTypes.h"
16 #include "src/gpu/graphite/ContextUtils.h"
17 #include "src/gpu/graphite/GraphicsPipelineDesc.h"
18 #include "src/gpu/graphite/GraphiteResourceKey.h"
19 #include "src/gpu/graphite/RenderPassDesc.h"
20 #include "src/gpu/graphite/RendererProvider.h"
21 #include "src/gpu/graphite/RuntimeEffectDictionary.h"
22 #include "src/gpu/graphite/vk/VulkanGraphiteUtilsPriv.h"
23 #include "src/gpu/graphite/vk/VulkanRenderPass.h"
24 #include "src/gpu/graphite/vk/VulkanSharedContext.h"
25 #include "src/gpu/graphite/vk/VulkanYcbcrConversion.h"
26 #include "src/gpu/vk/VulkanUtilsPriv.h"
27
28 #ifdef SK_BUILD_FOR_ANDROID
29 #include <sys/system_properties.h>
30 #endif
31
32 namespace skgpu::graphite {
33
VulkanCaps(const ContextOptions & contextOptions,const skgpu::VulkanInterface * vkInterface,VkPhysicalDevice physDev,uint32_t physicalDeviceVersion,const VkPhysicalDeviceFeatures2 * features,const skgpu::VulkanExtensions * extensions,Protected isProtected)34 VulkanCaps::VulkanCaps(const ContextOptions& contextOptions,
35 const skgpu::VulkanInterface* vkInterface,
36 VkPhysicalDevice physDev,
37 uint32_t physicalDeviceVersion,
38 const VkPhysicalDeviceFeatures2* features,
39 const skgpu::VulkanExtensions* extensions,
40 Protected isProtected)
41 : Caps() {
42 this->init(contextOptions, vkInterface, physDev, physicalDeviceVersion, features, extensions,
43 isProtected);
44 }
45
~VulkanCaps()46 VulkanCaps::~VulkanCaps() {}
47
init(const ContextOptions & contextOptions,const skgpu::VulkanInterface * vkInterface,VkPhysicalDevice physDev,uint32_t physicalDeviceVersion,const VkPhysicalDeviceFeatures2 * features,const skgpu::VulkanExtensions * extensions,Protected isProtected)48 void VulkanCaps::init(const ContextOptions& contextOptions,
49 const skgpu::VulkanInterface* vkInterface,
50 VkPhysicalDevice physDev,
51 uint32_t physicalDeviceVersion,
52 const VkPhysicalDeviceFeatures2* features,
53 const skgpu::VulkanExtensions* extensions,
54 Protected isProtected) {
55 VkPhysicalDeviceProperties physDevProperties;
56 VULKAN_CALL(vkInterface, GetPhysicalDeviceProperties(physDev, &physDevProperties));
57
58 #if defined(GRAPHITE_TEST_UTILS)
59 this->setDeviceName(physDevProperties.deviceName);
60 #endif
61
62 // Graphite requires Vulkan version 1.1 or later, which always has protected support.
63 if (isProtected == Protected::kYes) {
64 fProtectedSupport = true;
65 fShouldAlwaysUseDedicatedImageMemory = true;
66 }
67
68 fPhysicalDeviceMemoryProperties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2;
69 fPhysicalDeviceMemoryProperties2.pNext = nullptr;
70 VULKAN_CALL(vkInterface,
71 GetPhysicalDeviceMemoryProperties2(physDev, &fPhysicalDeviceMemoryProperties2));
72
73 // We could actually query and get a max size for each config, however maxImageDimension2D will
74 // give the minimum max size across all configs. So for simplicity we will use that for now.
75 fMaxTextureSize = std::min(physDevProperties.limits.maxImageDimension2D, (uint32_t)INT_MAX);
76
77 fRequiredUniformBufferAlignment = physDevProperties.limits.minUniformBufferOffsetAlignment;
78 fRequiredStorageBufferAlignment = physDevProperties.limits.minStorageBufferOffsetAlignment;
79 fRequiredTransferBufferAlignment = 4;
80
81 fResourceBindingReqs.fUniformBufferLayout = Layout::kStd140;
82 // TODO(skia:14639): We cannot use std430 layout for SSBOs until SkSL gracefully handles
83 // implicit array stride.
84 fResourceBindingReqs.fStorageBufferLayout = Layout::kStd140;
85 fResourceBindingReqs.fSeparateTextureAndSamplerBinding = false;
86 fResourceBindingReqs.fDistinctIndexRanges = false;
87
88 VkPhysicalDeviceMemoryProperties deviceMemoryProperties;
89 VULKAN_CALL(vkInterface, GetPhysicalDeviceMemoryProperties(physDev, &deviceMemoryProperties));
90 fSupportsMemorylessAttachments = false;
91 VkMemoryPropertyFlags requiredLazyFlags = VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT;
92 if (fProtectedSupport) {
93 // If we have a protected context we can only use memoryless images if they also support
94 // being protected. With current devices we don't actually expect this combination to be
95 // supported, but this at least covers us for future devices that may allow it.
96 requiredLazyFlags |= VK_MEMORY_PROPERTY_PROTECTED_BIT;
97 }
98 for (uint32_t i = 0; i < deviceMemoryProperties.memoryTypeCount; ++i) {
99 if (deviceMemoryProperties.memoryTypes[i].propertyFlags & requiredLazyFlags) {
100 fSupportsMemorylessAttachments = true;
101 }
102 }
103
104 #ifdef SK_BUILD_FOR_UNIX
105 if (kNvidia_VkVendor == physDevProperties.vendorID) {
106 // On NVIDIA linux we see a big perf regression when not using dedicated image allocations.
107 fShouldAlwaysUseDedicatedImageMemory = true;
108 }
109 #endif
110
111 if (physDevProperties.vendorID == kNvidia_VkVendor ||
112 physDevProperties.vendorID == kAMD_VkVendor) {
113 // On discrete GPUs, it can be faster to read gpu-only memory compared to memory that is
114 // also mappable on the host.
115 fGpuOnlyBuffersMorePerformant = true;
116
117 // On discrete GPUs we try to use special DEVICE_LOCAL and HOST_VISIBLE memory for our
118 // cpu write, gpu read buffers. This memory is not ideal to be kept persistently mapped.
119 // Some discrete GPUs do not expose this special memory, however we still disable
120 // persistently mapped buffers for all of them since most GPUs with updated drivers do
121 // expose it. If this becomes an issue we can try to be more fine grained.
122 fShouldPersistentlyMapCpuToGpuBuffers = false;
123 }
124
125 if (!contextOptions.fDisableDriverCorrectnessWorkarounds) {
126 this->applyDriverCorrectnessWorkarounds(physDevProperties);
127 }
128
129 if (physDevProperties.vendorID == kAMD_VkVendor) {
130 // AMD advertises support for MAX_UINT vertex attributes but in reality only supports 32.
131 fMaxVertexAttributes = 32;
132 } else {
133 fMaxVertexAttributes = physDevProperties.limits.maxVertexInputAttributes;
134 }
135 fMaxUniformBufferRange = physDevProperties.limits.maxUniformBufferRange;
136
137 #ifdef SK_BUILD_FOR_ANDROID
138 if (extensions->hasExtension(
139 VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME, 2)) {
140 fSupportsAHardwareBufferImages = true;
141 }
142 #endif
143
144 // Determine whether the client enabled certain physical device features.
145 if (features) {
146 auto ycbcrFeatures =
147 skgpu::GetExtensionFeatureStruct<VkPhysicalDeviceSamplerYcbcrConversionFeatures>(
148 *features,
149 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES);
150 if (ycbcrFeatures && ycbcrFeatures->samplerYcbcrConversion) {
151 fSupportsYcbcrConversion = true;
152 }
153 }
154
155 if (extensions->hasExtension(VK_EXT_DEVICE_FAULT_EXTENSION_NAME, 1)) {
156 fSupportsDeviceFaultInfo = true;
157 }
158
159 // Note that format table initialization should be performed at the end of this method to ensure
160 // all capability determinations are completed prior to populating the format tables.
161 this->initFormatTable(vkInterface, physDev, physDevProperties);
162 this->initDepthStencilFormatTable(vkInterface, physDev, physDevProperties);
163
164 this->finishInitialization(contextOptions);
165 }
166
applyDriverCorrectnessWorkarounds(const VkPhysicalDeviceProperties & properties)167 void VulkanCaps::applyDriverCorrectnessWorkarounds(const VkPhysicalDeviceProperties& properties) {
168 // By default, we initialize the Android API version to 0 since we consider certain things
169 // "fixed" only once above a certain version. This way, we default to enabling the workarounds.
170 int androidAPIVersion = 0;
171 #if defined(SK_BUILD_FOR_ANDROID)
172 char androidAPIVersionStr[PROP_VALUE_MAX];
173 int strLength = __system_property_get("ro.build.version.sdk", androidAPIVersionStr);
174 // Defaults to zero since most checks care if it is greater than a specific value. So this will
175 // just default to it being less.
176 androidAPIVersion = (strLength == 0) ? 0 : atoi(androidAPIVersionStr);
177 #endif
178
179 // On Mali galaxy s7 we see lots of rendering issues when we suballocate VkImages.
180 if (kARM_VkVendor == properties.vendorID && androidAPIVersion <= 28) {
181 fShouldAlwaysUseDedicatedImageMemory = true;
182 }
183 }
184
185 // These are all the valid VkFormats that we support in Skia. They are roughly ordered from most
186 // frequently used to least to improve look up times in arrays.
187 static constexpr VkFormat kVkFormats[] = {
188 VK_FORMAT_R8G8B8A8_UNORM,
189 VK_FORMAT_R8_UNORM,
190 VK_FORMAT_B8G8R8A8_UNORM,
191 VK_FORMAT_R5G6B5_UNORM_PACK16,
192 VK_FORMAT_R16G16B16A16_SFLOAT,
193 VK_FORMAT_R16_SFLOAT,
194 VK_FORMAT_R8G8B8_UNORM,
195 VK_FORMAT_R8G8_UNORM,
196 VK_FORMAT_A2B10G10R10_UNORM_PACK32,
197 VK_FORMAT_A2R10G10B10_UNORM_PACK32,
198 VK_FORMAT_B4G4R4A4_UNORM_PACK16,
199 VK_FORMAT_R4G4B4A4_UNORM_PACK16,
200 VK_FORMAT_R8G8B8A8_SRGB,
201 VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK,
202 VK_FORMAT_BC1_RGB_UNORM_BLOCK,
203 VK_FORMAT_BC1_RGBA_UNORM_BLOCK,
204 VK_FORMAT_R16_UNORM,
205 VK_FORMAT_R16G16_UNORM,
206 VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM,
207 VK_FORMAT_G8_B8R8_2PLANE_420_UNORM,
208 VK_FORMAT_R16G16B16A16_UNORM,
209 VK_FORMAT_R16G16_SFLOAT,
210 };
211 // These are all the valid depth/stencil formats that we support in Skia.
212 static constexpr VkFormat kDepthStencilVkFormats[] = {
213 VK_FORMAT_S8_UINT,
214 VK_FORMAT_D16_UNORM,
215 VK_FORMAT_D32_SFLOAT,
216 VK_FORMAT_D24_UNORM_S8_UINT,
217 VK_FORMAT_D32_SFLOAT_S8_UINT,
218 };
219
getDefaultSampledTextureInfo(SkColorType ct,Mipmapped mipmapped,Protected isProtected,Renderable isRenderable) const220 TextureInfo VulkanCaps::getDefaultSampledTextureInfo(SkColorType ct,
221 Mipmapped mipmapped,
222 Protected isProtected,
223 Renderable isRenderable) const {
224 VkFormat format = this->getFormatFromColorType(ct);
225 const FormatInfo& formatInfo = this->getFormatInfo(format);
226 static constexpr int defaultSampleCount = 1;
227 if ((isProtected == Protected::kYes && !this->protectedSupport()) ||
228 !formatInfo.isTexturable(VK_IMAGE_TILING_OPTIMAL) ||
229 (isRenderable == Renderable::kYes &&
230 !formatInfo.isRenderable(VK_IMAGE_TILING_OPTIMAL, defaultSampleCount)) ) {
231 return {};
232 }
233
234 VulkanTextureInfo info;
235 info.fSampleCount = defaultSampleCount;
236 info.fMipmapped = mipmapped;
237 info.fFlags = (isProtected == Protected::kYes) ? VK_IMAGE_CREATE_PROTECTED_BIT : 0;
238 info.fFormat = format;
239 info.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
240 info.fImageUsageFlags = VK_IMAGE_USAGE_SAMPLED_BIT |
241 VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
242 VK_IMAGE_USAGE_TRANSFER_DST_BIT;
243 if (isRenderable == Renderable::kYes) {
244 // We make all renderable images support being used as input attachment
245 info.fImageUsageFlags = info.fImageUsageFlags |
246 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
247 VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
248 }
249 info.fSharingMode = VK_SHARING_MODE_EXCLUSIVE;
250 info.fAspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
251
252 return info;
253 }
254
getTextureInfoForSampledCopy(const TextureInfo & textureInfo,Mipmapped mipmapped) const255 TextureInfo VulkanCaps::getTextureInfoForSampledCopy(const TextureInfo& textureInfo,
256 Mipmapped mipmapped) const {
257 VulkanTextureInfo info;
258 if (!textureInfo.getVulkanTextureInfo(&info)) {
259 return {};
260 }
261
262 info.fSampleCount = 1;
263 info.fMipmapped = mipmapped;
264 info.fFlags = (textureInfo.fProtected == Protected::kYes) ? VK_IMAGE_CREATE_PROTECTED_BIT : 0;
265 info.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
266 info.fImageUsageFlags = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
267 VK_IMAGE_USAGE_TRANSFER_DST_BIT;
268 info.fSharingMode = VK_SHARING_MODE_EXCLUSIVE;
269
270 return info;
271 }
272
273 namespace {
format_from_compression(SkTextureCompressionType compression)274 VkFormat format_from_compression(SkTextureCompressionType compression) {
275 switch (compression) {
276 case SkTextureCompressionType::kETC2_RGB8_UNORM:
277 return VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK;
278 case SkTextureCompressionType::kBC1_RGB8_UNORM:
279 return VK_FORMAT_BC1_RGB_UNORM_BLOCK;
280 case SkTextureCompressionType::kBC1_RGBA8_UNORM:
281 return VK_FORMAT_BC1_RGBA_UNORM_BLOCK;
282 default:
283 return VK_FORMAT_UNDEFINED;
284 }
285 }
286 }
287
getDefaultCompressedTextureInfo(SkTextureCompressionType compression,Mipmapped mipmapped,Protected isProtected) const288 TextureInfo VulkanCaps::getDefaultCompressedTextureInfo(SkTextureCompressionType compression,
289 Mipmapped mipmapped,
290 Protected isProtected) const {
291 VkFormat format = format_from_compression(compression);
292 const FormatInfo& formatInfo = this->getFormatInfo(format);
293 static constexpr int defaultSampleCount = 1;
294 if ((isProtected == Protected::kYes && !this->protectedSupport()) ||
295 !formatInfo.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
296 return {};
297 }
298
299 VulkanTextureInfo info;
300 info.fSampleCount = defaultSampleCount;
301 info.fMipmapped = mipmapped;
302 info.fFlags = (isProtected == Protected::kYes) ? VK_IMAGE_CREATE_PROTECTED_BIT : 0;
303 info.fFormat = format;
304 info.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
305 info.fImageUsageFlags = VK_IMAGE_USAGE_SAMPLED_BIT |
306 VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
307 VK_IMAGE_USAGE_TRANSFER_DST_BIT;
308 info.fSharingMode = VK_SHARING_MODE_EXCLUSIVE;
309 info.fAspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
310
311 return info;
312 }
313
getDefaultMSAATextureInfo(const TextureInfo & singleSampledInfo,Discardable discardable) const314 TextureInfo VulkanCaps::getDefaultMSAATextureInfo(const TextureInfo& singleSampledInfo,
315 Discardable discardable) const {
316 if (fDefaultMSAASamples <= 1) {
317 return {};
318 }
319
320 const VkFormat singleSpecFormat = singleSampledInfo.vulkanTextureSpec().fFormat;
321 const FormatInfo& formatInfo = this->getFormatInfo(singleSpecFormat);
322 if ((singleSampledInfo.isProtected() == Protected::kYes && !this->protectedSupport()) ||
323 !formatInfo.isRenderable(VK_IMAGE_TILING_OPTIMAL, fDefaultMSAASamples)) {
324 return {};
325 }
326
327 VulkanTextureInfo info;
328 info.fSampleCount = fDefaultMSAASamples;
329 info.fMipmapped = Mipmapped::kNo;
330 info.fFlags = (singleSampledInfo.isProtected() == Protected::kYes) ?
331 VK_IMAGE_CREATE_PROTECTED_BIT : 0;
332 info.fFormat = singleSpecFormat;
333 info.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
334
335 /**
336 * Graphite, unlike ganesh, does not require a dedicated MSAA attachment on every surface.
337 * MSAA textures now get resolved within the scope of a render pass, which can be done simply
338 * with the color attachment usage flag. So we no longer require transfer src/dst usage flags.
339 */
340 VkImageUsageFlags flags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
341 if (discardable == Discardable::kYes && fSupportsMemorylessAttachments) {
342 flags = flags | VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT;
343 }
344
345 info.fImageUsageFlags = flags;
346 info.fSharingMode = VK_SHARING_MODE_EXCLUSIVE;
347 info.fAspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
348
349 return info;
350 }
351
getDefaultDepthStencilTextureInfo(SkEnumBitMask<DepthStencilFlags> flags,uint32_t sampleCount,Protected isProtected) const352 TextureInfo VulkanCaps::getDefaultDepthStencilTextureInfo(SkEnumBitMask<DepthStencilFlags> flags,
353 uint32_t sampleCount,
354 Protected isProtected) const {
355 VkFormat format = this->getFormatFromDepthStencilFlags(flags);
356 const DepthStencilFormatInfo& formatInfo = this->getDepthStencilFormatInfo(format);
357 if ( (isProtected == Protected::kYes && !this->protectedSupport()) ||
358 !formatInfo.isDepthStencilSupported(formatInfo.fFormatProperties.optimalTilingFeatures) ||
359 !formatInfo.fSupportedSampleCounts.isSampleCountSupported(sampleCount)) {
360 return {};
361 }
362
363 VulkanTextureInfo info;
364 info.fSampleCount = sampleCount;
365 info.fMipmapped = Mipmapped::kNo;
366 info.fFlags = (isProtected == Protected::kYes) ? VK_IMAGE_CREATE_PROTECTED_BIT : 0;
367 info.fFormat = format;
368 info.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
369 // TODO: Passing in a discardable flag to this method, and if true, add the TRANSIENT bit.
370 info.fImageUsageFlags = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
371 info.fSharingMode = VK_SHARING_MODE_EXCLUSIVE;
372 info.fAspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
373
374 return info;
375 }
376
getDefaultStorageTextureInfo(SkColorType colorType) const377 TextureInfo VulkanCaps::getDefaultStorageTextureInfo(SkColorType colorType) const {
378 VkFormat format = this->getFormatFromColorType(colorType);
379 const FormatInfo& formatInfo = this->getFormatInfo(format);
380 if (!formatInfo.isTexturable(VK_IMAGE_TILING_OPTIMAL) ||
381 !formatInfo.isStorage(VK_IMAGE_TILING_OPTIMAL)) {
382 return {};
383 }
384
385 VulkanTextureInfo info;
386 info.fSampleCount = 1;
387 info.fMipmapped = Mipmapped::kNo;
388 info.fFlags = 0;
389 info.fFormat = format;
390 info.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
391 // Storage textures are currently always sampleable from a shader
392 info.fImageUsageFlags = VK_IMAGE_USAGE_STORAGE_BIT |
393 VK_IMAGE_USAGE_SAMPLED_BIT |
394 VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
395 info.fSharingMode = VK_SHARING_MODE_EXCLUSIVE;
396 info.fAspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
397
398 return info;
399 }
400
channelMask(const TextureInfo & textureInfo) const401 uint32_t VulkanCaps::channelMask(const TextureInfo& textureInfo) const {
402 return skgpu::VkFormatChannels(textureInfo.vulkanTextureSpec().fFormat);
403 }
404
initFormatTable(const skgpu::VulkanInterface * interface,VkPhysicalDevice physDev,const VkPhysicalDeviceProperties & properties)405 void VulkanCaps::initFormatTable(const skgpu::VulkanInterface* interface,
406 VkPhysicalDevice physDev,
407 const VkPhysicalDeviceProperties& properties) {
408 static_assert(std::size(kVkFormats) == VulkanCaps::kNumVkFormats,
409 "Size of VkFormats array must match static value in header");
410
411 std::fill_n(fColorTypeToFormatTable, kSkColorTypeCnt, VK_FORMAT_UNDEFINED);
412
413 // Go through all the formats and init their support surface and data ColorTypes.
414 // Format: VK_FORMAT_R8G8B8A8_UNORM
415 {
416 constexpr VkFormat format = VK_FORMAT_R8G8B8A8_UNORM;
417 auto& info = this->getFormatInfo(format);
418 info.init(interface, physDev, properties, format);
419 if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
420 info.fColorTypeInfoCount = 2;
421 info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
422 int ctIdx = 0;
423 // Format: VK_FORMAT_R8G8B8A8_UNORM, Surface: kRGBA_8888
424 {
425 constexpr SkColorType ct = SkColorType::kRGBA_8888_SkColorType;
426 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
427 ctInfo.fColorType = ct;
428 ctInfo.fTransferColorType = ct;
429 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
430 }
431 // Format: VK_FORMAT_R8G8B8A8_UNORM, Surface: kRGB_888x
432 {
433 constexpr SkColorType ct = SkColorType::kRGB_888x_SkColorType;
434 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
435 ctInfo.fColorType = ct;
436 ctInfo.fTransferColorType = ct;
437 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag;
438 ctInfo.fReadSwizzle = skgpu::Swizzle::RGB1();
439 }
440 }
441 }
442
443 // Format: VK_FORMAT_R8_UNORM
444 {
445 constexpr VkFormat format = VK_FORMAT_R8_UNORM;
446 auto& info = this->getFormatInfo(format);
447 info.init(interface, physDev, properties, format);
448 if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
449 info.fColorTypeInfoCount = 3;
450 info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
451 int ctIdx = 0;
452 // Format: VK_FORMAT_R8_UNORM, Surface: kR_8
453 {
454 constexpr SkColorType ct = SkColorType::kR8_unorm_SkColorType;
455 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
456 ctInfo.fColorType = ct;
457 ctInfo.fTransferColorType = ct;
458 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
459 }
460 // Format: VK_FORMAT_R8_UNORM, Surface: kAlpha_8
461 {
462 constexpr SkColorType ct = SkColorType::kAlpha_8_SkColorType;
463 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
464 ctInfo.fColorType = ct;
465 ctInfo.fTransferColorType = ct;
466 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
467 ctInfo.fReadSwizzle = skgpu::Swizzle("000r");
468 ctInfo.fWriteSwizzle = skgpu::Swizzle("a000");
469 }
470 // Format: VK_FORMAT_R8_UNORM, Surface: kGray_8
471 {
472 constexpr SkColorType ct = SkColorType::kGray_8_SkColorType;
473 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
474 ctInfo.fColorType = ct;
475 ctInfo.fTransferColorType = ct;
476 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag;
477 ctInfo.fReadSwizzle = skgpu::Swizzle("rrr1");
478 }
479 }
480 }
481
482 // Format: VK_FORMAT_B8G8R8A8_UNORM
483 {
484 constexpr VkFormat format = VK_FORMAT_B8G8R8A8_UNORM;
485 auto& info = this->getFormatInfo(format);
486 info.init(interface, physDev, properties, format);
487 if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
488 info.fColorTypeInfoCount = 1;
489 info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
490 int ctIdx = 0;
491 // Format: VK_FORMAT_B8G8R8A8_UNORM, Surface: kBGRA_8888
492 {
493 constexpr SkColorType ct = SkColorType::kBGRA_8888_SkColorType;
494 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
495 ctInfo.fColorType = ct;
496 ctInfo.fTransferColorType = ct;
497 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
498 }
499 }
500 }
501 // Format: VK_FORMAT_R5G6B5_UNORM_PACK16
502 {
503 constexpr VkFormat format = VK_FORMAT_R5G6B5_UNORM_PACK16;
504 auto& info = this->getFormatInfo(format);
505 info.init(interface, physDev, properties, format);
506 if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
507 info.fColorTypeInfoCount = 1;
508 info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
509 int ctIdx = 0;
510 // Format: VK_FORMAT_R5G6B5_UNORM_PACK16, Surface: kRGB_565_SkColorType
511 {
512 constexpr SkColorType ct = SkColorType::kRGB_565_SkColorType;
513 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
514 ctInfo.fColorType = ct;
515 ctInfo.fTransferColorType = ct;
516 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
517 }
518 }
519 }
520 // Format: VK_FORMAT_R16G16B16A16_SFLOAT
521 {
522 constexpr VkFormat format = VK_FORMAT_R16G16B16A16_SFLOAT;
523 auto& info = this->getFormatInfo(format);
524 info.init(interface, physDev, properties, format);
525 if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
526 info.fColorTypeInfoCount = 2;
527 info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
528 int ctIdx = 0;
529 // Format: VK_FORMAT_R16G16B16A16_SFLOAT, Surface: SkColorType::kRGBA_F16_SkColorType
530 {
531 constexpr SkColorType ct = SkColorType::kRGBA_F16_SkColorType;
532 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
533 ctInfo.fColorType = ct;
534 ctInfo.fTransferColorType = ct;
535 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
536 }
537 }
538 }
539 // Format: VK_FORMAT_R16_SFLOAT
540 {
541 constexpr VkFormat format = VK_FORMAT_R16_SFLOAT;
542 auto& info = this->getFormatInfo(format);
543 info.init(interface, physDev, properties, format);
544 if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
545 info.fColorTypeInfoCount = 1;
546 info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
547 int ctIdx = 0;
548 // Format: VK_FORMAT_R16_SFLOAT, Surface: kAlpha_F16
549 {
550 constexpr SkColorType ct = SkColorType::kA16_float_SkColorType;
551 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
552 ctInfo.fColorType = ct;
553 ctInfo.fTransferColorType = ct;
554 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
555 ctInfo.fReadSwizzle = skgpu::Swizzle("000r");
556 ctInfo.fWriteSwizzle = skgpu::Swizzle("a000");
557 }
558 }
559 }
560 // Format: VK_FORMAT_R8G8B8_UNORM
561 {
562 constexpr VkFormat format = VK_FORMAT_R8G8B8_UNORM;
563 auto& info = this->getFormatInfo(format);
564 info.init(interface, physDev, properties, format);
565 if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
566 info.fColorTypeInfoCount = 1;
567 info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
568 int ctIdx = 0;
569 // Format: VK_FORMAT_R8G8B8_UNORM, Surface: kRGB_888x
570 {
571 constexpr SkColorType ct = SkColorType::kRGB_888x_SkColorType;
572 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
573 ctInfo.fColorType = ct;
574 // This SkColorType is a lie, but we don't have a kRGB_888_SkColorType. The Vulkan
575 // format is 3 bpp so we must manualy convert to/from this and kRGB_888x when doing
576 // transfers. We signal this need for manual conversions in the
577 // supportedRead/WriteColorType calls.
578 ctInfo.fTransferColorType = SkColorType::kRGB_888x_SkColorType;
579 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
580 }
581 }
582 }
583 // Format: VK_FORMAT_R8G8_UNORM
584 {
585 constexpr VkFormat format = VK_FORMAT_R8G8_UNORM;
586 auto& info = this->getFormatInfo(format);
587 info.init(interface, physDev, properties, format);
588 if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
589 info.fColorTypeInfoCount = 1;
590 info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
591 int ctIdx = 0;
592 // Format: VK_FORMAT_R8G8_UNORM, Surface: kR8G8_unorm
593 {
594 constexpr SkColorType ct = SkColorType::kR8G8_unorm_SkColorType;
595 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
596 ctInfo.fColorType = ct;
597 ctInfo.fTransferColorType = ct;
598 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
599 }
600 }
601 }
602 // Format: VK_FORMAT_A2B10G10R10_UNORM_PACK32
603 {
604 constexpr VkFormat format = VK_FORMAT_A2B10G10R10_UNORM_PACK32;
605 auto& info = this->getFormatInfo(format);
606 info.init(interface, physDev, properties, format);
607 if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
608 info.fColorTypeInfoCount = 1;
609 info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
610 int ctIdx = 0;
611 // Format: VK_FORMAT_A2B10G10R10_UNORM_PACK32, Surface: kRGBA_1010102
612 {
613 constexpr SkColorType ct = SkColorType::kRGBA_1010102_SkColorType;
614 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
615 ctInfo.fColorType = ct;
616 ctInfo.fTransferColorType = ct;
617 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
618 }
619 }
620 }
621 // Format: VK_FORMAT_A2R10G10B10_UNORM_PACK32
622 {
623 constexpr VkFormat format = VK_FORMAT_A2R10G10B10_UNORM_PACK32;
624 auto& info = this->getFormatInfo(format);
625 info.init(interface, physDev, properties, format);
626 if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
627 info.fColorTypeInfoCount = 1;
628 info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
629 int ctIdx = 0;
630 // Format: VK_FORMAT_A2R10G10B10_UNORM_PACK32, Surface: kBGRA_1010102
631 {
632 constexpr SkColorType ct = SkColorType::kBGRA_1010102_SkColorType;
633 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
634 ctInfo.fColorType = ct;
635 ctInfo.fTransferColorType = ct;
636 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
637 }
638 }
639 }
640 // Format: VK_FORMAT_B4G4R4A4_UNORM_PACK16
641 {
642 constexpr VkFormat format = VK_FORMAT_B4G4R4A4_UNORM_PACK16;
643 auto& info = this->getFormatInfo(format);
644 info.init(interface, physDev, properties, format);
645 if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
646 info.fColorTypeInfoCount = 1;
647 info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
648 int ctIdx = 0;
649 // Format: VK_FORMAT_B4G4R4A4_UNORM_PACK16, Surface: kARGB_4444_SkColorType
650 {
651 constexpr SkColorType ct = SkColorType::kARGB_4444_SkColorType;
652 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
653 ctInfo.fColorType = ct;
654 ctInfo.fTransferColorType = ct;
655 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
656 ctInfo.fReadSwizzle = skgpu::Swizzle::BGRA();
657 ctInfo.fWriteSwizzle = skgpu::Swizzle::BGRA();
658 }
659 }
660 }
661
662 // Format: VK_FORMAT_R4G4B4A4_UNORM_PACK16
663 {
664 constexpr VkFormat format = VK_FORMAT_R4G4B4A4_UNORM_PACK16;
665 auto& info = this->getFormatInfo(format);
666 info.init(interface, physDev, properties, format);
667 if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
668 info.fColorTypeInfoCount = 1;
669 info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
670 int ctIdx = 0;
671 // Format: VK_FORMAT_R4G4B4A4_UNORM_PACK16, Surface: kARGB_4444_SkColorType
672 {
673 constexpr SkColorType ct = SkColorType::kARGB_4444_SkColorType;
674 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
675 ctInfo.fColorType = ct;
676 ctInfo.fTransferColorType = ct;
677 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
678 }
679 }
680 }
681 // Format: VK_FORMAT_R8G8B8A8_SRGB
682 {
683 constexpr VkFormat format = VK_FORMAT_R8G8B8A8_SRGB;
684 auto& info = this->getFormatInfo(format);
685 info.init(interface, physDev, properties, format);
686 if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
687 info.fColorTypeInfoCount = 1;
688 info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
689 int ctIdx = 0;
690 // Format: VK_FORMAT_R8G8B8A8_SRGB, Surface: kRGBA_8888_SRGB
691 {
692 constexpr SkColorType ct = SkColorType::kSRGBA_8888_SkColorType;
693 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
694 ctInfo.fColorType = ct;
695 ctInfo.fTransferColorType = ct;
696 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
697 }
698 }
699 }
700 // Format: VK_FORMAT_R16_UNORM
701 {
702 constexpr VkFormat format = VK_FORMAT_R16_UNORM;
703 auto& info = this->getFormatInfo(format);
704 info.init(interface, physDev, properties, format);
705 if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
706 info.fColorTypeInfoCount = 1;
707 info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
708 int ctIdx = 0;
709 // Format: VK_FORMAT_R16_UNORM, Surface: kAlpha_16
710 {
711 constexpr SkColorType ct = SkColorType::kA16_unorm_SkColorType;
712 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
713 ctInfo.fColorType = ct;
714 ctInfo.fTransferColorType = ct;
715 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
716 ctInfo.fReadSwizzle = skgpu::Swizzle("000r");
717 ctInfo.fWriteSwizzle = skgpu::Swizzle("a000");
718 }
719 }
720 }
721 // Format: VK_FORMAT_R16G16_UNORM
722 {
723 constexpr VkFormat format = VK_FORMAT_R16G16_UNORM;
724 auto& info = this->getFormatInfo(format);
725 info.init(interface, physDev, properties, format);
726 if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
727 info.fColorTypeInfoCount = 1;
728 info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
729 int ctIdx = 0;
730 // Format: VK_FORMAT_R16G16_UNORM, Surface: kRG_1616
731 {
732 constexpr SkColorType ct = SkColorType::kR16G16_unorm_SkColorType;
733 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
734 ctInfo.fColorType = ct;
735 ctInfo.fTransferColorType = ct;
736 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
737 }
738 }
739 }
740 // Format: VK_FORMAT_R16G16B16A16_UNORM
741 {
742 constexpr VkFormat format = VK_FORMAT_R16G16B16A16_UNORM;
743 auto& info = this->getFormatInfo(format);
744 info.init(interface, physDev, properties, format);
745 if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
746 info.fColorTypeInfoCount = 1;
747 info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
748 int ctIdx = 0;
749 // Format: VK_FORMAT_R16G16B16A16_UNORM, Surface: kRGBA_16161616
750 {
751 constexpr SkColorType ct = SkColorType::kR16G16B16A16_unorm_SkColorType;
752 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
753 ctInfo.fColorType = ct;
754 ctInfo.fTransferColorType = ct;
755 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
756 }
757 }
758 }
759 // Format: VK_FORMAT_R16G16_SFLOAT
760 {
761 constexpr VkFormat format = VK_FORMAT_R16G16_SFLOAT;
762 auto& info = this->getFormatInfo(format);
763 info.init(interface, physDev, properties, format);
764 if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
765 info.fColorTypeInfoCount = 1;
766 info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
767 int ctIdx = 0;
768 // Format: VK_FORMAT_R16G16_SFLOAT, Surface: kRG_F16
769 {
770 constexpr SkColorType ct = SkColorType::kR16G16_float_SkColorType;
771 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
772 ctInfo.fColorType = ct;
773 ctInfo.fTransferColorType = ct;
774 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag | ColorTypeInfo::kRenderable_Flag;
775 }
776 }
777 }
778 // Format: VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM
779 {
780 constexpr VkFormat format = VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM;
781 auto& info = this->getFormatInfo(format);
782 if (fSupportsYcbcrConversion) {
783 info.init(interface, physDev, properties, format);
784 }
785 if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
786 info.fColorTypeInfoCount = 1;
787 info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
788 int ctIdx = 0;
789 // Format: VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM, Surface: kRGB_888x
790 {
791 constexpr SkColorType ct = SkColorType::kRGB_888x_SkColorType;
792 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
793 ctInfo.fColorType = ct;
794 ctInfo.fTransferColorType = ct;
795 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag;
796 }
797 SkDEBUGCODE(info.fIsWrappedOnly = true;)
798 }
799 }
800 // Format: VK_FORMAT_G8_B8R8_2PLANE_420_UNORM
801 {
802 constexpr VkFormat format = VK_FORMAT_G8_B8R8_2PLANE_420_UNORM;
803 auto& info = this->getFormatInfo(format);
804 if (fSupportsYcbcrConversion) {
805 info.init(interface, physDev, properties, format);
806 }
807 if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
808 info.fColorTypeInfoCount = 1;
809 info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
810 int ctIdx = 0;
811 // Format: VK_FORMAT_G8_B8R8_2PLANE_420_UNORM, Surface: kRGB_888x
812 {
813 constexpr SkColorType ct = SkColorType::kRGB_888x_SkColorType;
814 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
815 ctInfo.fColorType = ct;
816 ctInfo.fTransferColorType = ct;
817 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag;
818 }
819 SkDEBUGCODE(info.fIsWrappedOnly = true;)
820 }
821 }
822 // Format: VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK
823 {
824 constexpr VkFormat format = VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK;
825 auto& info = this->getFormatInfo(format);
826 info.init(interface, physDev, properties, format);
827 if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
828 info.fColorTypeInfoCount = 1;
829 info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
830 int ctIdx = 0;
831 // Format: VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK, Surface: kRGB_888x
832 {
833 constexpr SkColorType ct = SkColorType::kRGB_888x_SkColorType;
834 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
835 ctInfo.fColorType = ct;
836 ctInfo.fTransferColorType = ct;
837 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag;
838 }
839 }
840 }
841
842 // Format: VK_FORMAT_BC1_RGB_UNORM_BLOCK
843 {
844 constexpr VkFormat format = VK_FORMAT_BC1_RGB_UNORM_BLOCK;
845 auto& info = this->getFormatInfo(format);
846 info.init(interface, physDev, properties, format);
847 if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
848 info.fColorTypeInfoCount = 1;
849 info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
850 int ctIdx = 0;
851 // Format: VK_FORMAT_BC1_RGB_UNORM_BLOCK, Surface: kRGB_888x
852 {
853 constexpr SkColorType ct = SkColorType::kRGB_888x_SkColorType;
854 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
855 ctInfo.fColorType = ct;
856 ctInfo.fTransferColorType = ct;
857 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag;
858 }
859 }
860 }
861
862 // Format: VK_FORMAT_BC1_RGBA_UNORM_BLOCK
863 {
864 constexpr VkFormat format = VK_FORMAT_BC1_RGBA_UNORM_BLOCK;
865 auto& info = this->getFormatInfo(format);
866 info.init(interface, physDev, properties, format);
867 if (info.isTexturable(VK_IMAGE_TILING_OPTIMAL)) {
868 info.fColorTypeInfoCount = 1;
869 info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
870 int ctIdx = 0;
871 // Format: VK_FORMAT_BC1_RGBA_UNORM_BLOCK, Surface: kRGB_888x
872 {
873 constexpr SkColorType ct = SkColorType::kRGBA_8888_SkColorType;
874 auto& ctInfo = info.fColorTypeInfos[ctIdx++];
875 ctInfo.fColorType = ct;
876 ctInfo.fTransferColorType = ct;
877 ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag;
878 }
879 }
880 }
881
882 ////////////////////////////////////////////////////////////////////////////
883 // Map SkColorType (used for creating Surfaces) to VkFormats. The order in which the formats are
884 // passed into the setColorType function indicates the priority in selecting which format we use
885 // for a given SkColorType.
886 typedef SkColorType ct;
887
888 this->setColorType(ct::kAlpha_8_SkColorType, { VK_FORMAT_R8_UNORM });
889 this->setColorType(ct::kRGB_565_SkColorType, { VK_FORMAT_R5G6B5_UNORM_PACK16 });
890 this->setColorType(ct::kARGB_4444_SkColorType, { VK_FORMAT_R4G4B4A4_UNORM_PACK16,
891 VK_FORMAT_B4G4R4A4_UNORM_PACK16 });
892 this->setColorType(ct::kRGBA_8888_SkColorType, { VK_FORMAT_R8G8B8A8_UNORM });
893 this->setColorType(ct::kSRGBA_8888_SkColorType, { VK_FORMAT_R8G8B8A8_SRGB });
894 this->setColorType(ct::kRGB_888x_SkColorType, { VK_FORMAT_R8G8B8_UNORM,
895 VK_FORMAT_R8G8B8A8_UNORM });
896 this->setColorType(ct::kR8G8_unorm_SkColorType, { VK_FORMAT_R8G8_UNORM });
897 this->setColorType(ct::kBGRA_8888_SkColorType, { VK_FORMAT_B8G8R8A8_UNORM });
898 this->setColorType(ct::kRGBA_1010102_SkColorType, { VK_FORMAT_A2B10G10R10_UNORM_PACK32 });
899 this->setColorType(ct::kBGRA_1010102_SkColorType, { VK_FORMAT_A2R10G10B10_UNORM_PACK32 });
900 this->setColorType(ct::kGray_8_SkColorType, { VK_FORMAT_R8_UNORM });
901 this->setColorType(ct::kA16_float_SkColorType, { VK_FORMAT_R16_SFLOAT });
902 this->setColorType(ct::kRGBA_F16_SkColorType, { VK_FORMAT_R16G16B16A16_SFLOAT });
903 this->setColorType(ct::kA16_unorm_SkColorType, { VK_FORMAT_R16_UNORM });
904 this->setColorType(ct::kR16G16_unorm_SkColorType, { VK_FORMAT_R16G16_UNORM });
905 this->setColorType(ct::kR16G16B16A16_unorm_SkColorType, { VK_FORMAT_R16G16B16A16_UNORM });
906 this->setColorType(ct::kR16G16_float_SkColorType, { VK_FORMAT_R16G16_SFLOAT });
907 }
908
909 namespace {
set_ds_flags_to_format(VkFormat & slot,VkFormat format)910 void set_ds_flags_to_format(VkFormat& slot, VkFormat format) {
911 if (slot == VK_FORMAT_UNDEFINED) {
912 slot = format;
913 }
914 }
915 } // namespace
916
initDepthStencilFormatTable(const skgpu::VulkanInterface * interface,VkPhysicalDevice physDev,const VkPhysicalDeviceProperties & properties)917 void VulkanCaps::initDepthStencilFormatTable(const skgpu::VulkanInterface* interface,
918 VkPhysicalDevice physDev,
919 const VkPhysicalDeviceProperties& properties) {
920 static_assert(std::size(kDepthStencilVkFormats) == VulkanCaps::kNumDepthStencilVkFormats,
921 "Size of DepthStencilVkFormats array must match static value in header");
922
923 using DSFlags = SkEnumBitMask<DepthStencilFlags>;
924 constexpr DSFlags stencilFlags = DepthStencilFlags::kStencil;
925 constexpr DSFlags depthFlags = DepthStencilFlags::kDepth;
926 constexpr DSFlags dsFlags = DepthStencilFlags::kDepthStencil;
927
928 std::fill_n(fDepthStencilFlagsToFormatTable, kNumDepthStencilFlags, VK_FORMAT_UNDEFINED);
929 // Format: VK_FORMAT_S8_UINT
930 {
931 constexpr VkFormat format = VK_FORMAT_S8_UINT;
932 auto& info = this->getDepthStencilFormatInfo(format);
933 info.init(interface, physDev, properties, format);
934 if (info.fFormatProperties.optimalTilingFeatures &
935 VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) {
936 set_ds_flags_to_format(fDepthStencilFlagsToFormatTable[stencilFlags.value()], format);
937 }
938 }
939 // Format: VK_FORMAT_D16_UNORM
940 {
941 // Qualcomm drivers will report OUT_OF_HOST_MEMORY when binding memory to a VkImage with
942 // D16_UNORM in a protected context. Using D32_SFLOAT succeeds, so clearly it's not actually
943 // out of memory. D16_UNORM appears to function correctly in unprotected contexts.
944 const bool disableD16InProtected = this->protectedSupport() &&
945 kQualcomm_VkVendor == properties.vendorID;
946 if (!disableD16InProtected) {
947 constexpr VkFormat format = VK_FORMAT_D16_UNORM;
948 auto& info = this->getDepthStencilFormatInfo(format);
949 info.init(interface, physDev, properties, format);
950 if (info.fFormatProperties.optimalTilingFeatures &
951 VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) {
952 set_ds_flags_to_format(fDepthStencilFlagsToFormatTable[depthFlags.value()], format);
953 }
954 }
955 }
956 // Format: VK_FORMAT_D32_SFLOAT
957 {
958 constexpr VkFormat format = VK_FORMAT_D32_SFLOAT;
959 auto& info = this->getDepthStencilFormatInfo(format);
960 info.init(interface, physDev, properties, format);
961 if (info.fFormatProperties.optimalTilingFeatures &
962 VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) {
963 set_ds_flags_to_format(fDepthStencilFlagsToFormatTable[depthFlags.value()], format);
964 }
965 }
966 // Format: VK_FORMAT_D24_UNORM_S8_UINT
967 {
968 constexpr VkFormat format = VK_FORMAT_D24_UNORM_S8_UINT;
969 auto& info = this->getDepthStencilFormatInfo(format);
970 info.init(interface, physDev, properties, format);
971 if (info.fFormatProperties.optimalTilingFeatures &
972 VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) {
973 set_ds_flags_to_format(fDepthStencilFlagsToFormatTable[stencilFlags.value()], format);
974 set_ds_flags_to_format(fDepthStencilFlagsToFormatTable[depthFlags.value()], format);
975 set_ds_flags_to_format(fDepthStencilFlagsToFormatTable[dsFlags.value()], format);
976 }
977 }
978 // Format: VK_FORMAT_D32_SFLOAT_S8_UINT
979 {
980 constexpr VkFormat format = VK_FORMAT_D32_SFLOAT_S8_UINT;
981 auto& info = this->getDepthStencilFormatInfo(format);
982 info.init(interface, physDev, properties, format);
983 if (info.fFormatProperties.optimalTilingFeatures &
984 VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) {
985 set_ds_flags_to_format(fDepthStencilFlagsToFormatTable[stencilFlags.value()], format);
986 set_ds_flags_to_format(fDepthStencilFlagsToFormatTable[depthFlags.value()], format);
987 set_ds_flags_to_format(fDepthStencilFlagsToFormatTable[dsFlags.value()], format);
988 }
989 }
990 }
991
initSampleCounts(const skgpu::VulkanInterface * interface,VkPhysicalDevice physDev,const VkPhysicalDeviceProperties & physProps,VkFormat format,VkImageUsageFlags usage)992 void VulkanCaps::SupportedSampleCounts::initSampleCounts(const skgpu::VulkanInterface* interface,
993 VkPhysicalDevice physDev,
994 const VkPhysicalDeviceProperties& physProps,
995 VkFormat format,
996 VkImageUsageFlags usage) {
997 VkImageFormatProperties properties;
998
999 VkResult result;
1000 // VULKAN_CALL_RESULT requires a VulkanSharedContext for tracking DEVICE_LOST, but VulkanCaps
1001 // are initialized before a VulkanSharedContext is available. The _NOCHECK variant only requires
1002 // a VulkanInterface, so we can use that and log failures manually.
1003 VULKAN_CALL_RESULT_NOCHECK(interface,
1004 result,
1005 GetPhysicalDeviceImageFormatProperties(physDev,
1006 format,
1007 VK_IMAGE_TYPE_2D,
1008 VK_IMAGE_TILING_OPTIMAL,
1009 usage,
1010 0, // createFlags
1011 &properties));
1012 if (result != VK_SUCCESS) {
1013 SKGPU_LOG_W("Vulkan call GetPhysicalDeviceImageFormatProperties failed: %d", result);
1014 return;
1015 }
1016
1017 VkSampleCountFlags flags = properties.sampleCounts;
1018 if (flags & VK_SAMPLE_COUNT_1_BIT) {
1019 fSampleCounts.push_back(1);
1020 }
1021 if (kImagination_VkVendor == physProps.vendorID) {
1022 // MSAA does not work on imagination
1023 return;
1024 }
1025 if (kIntel_VkVendor == physProps.vendorID) {
1026 // MSAA doesn't work well on Intel GPUs chromium:527565, chromium:983926
1027 return;
1028 }
1029 if (flags & VK_SAMPLE_COUNT_2_BIT) {
1030 fSampleCounts.push_back(2);
1031 }
1032 if (flags & VK_SAMPLE_COUNT_4_BIT) {
1033 fSampleCounts.push_back(4);
1034 }
1035 if (flags & VK_SAMPLE_COUNT_8_BIT) {
1036 fSampleCounts.push_back(8);
1037 }
1038 if (flags & VK_SAMPLE_COUNT_16_BIT) {
1039 fSampleCounts.push_back(16);
1040 }
1041 // Standard sample locations are not defined for more than 16 samples, and we don't need more
1042 // than 16. Omit 32 and 64.
1043 }
1044
isSampleCountSupported(int requestedCount) const1045 bool VulkanCaps::SupportedSampleCounts::isSampleCountSupported(int requestedCount) const {
1046 requestedCount = std::max(1, requestedCount);
1047 for (int i = 0; i < fSampleCounts.size(); i++) {
1048 if (fSampleCounts[i] == requestedCount) {
1049 return true;
1050 } else if (requestedCount < fSampleCounts[i]) {
1051 return false;
1052 }
1053 }
1054 return false;
1055 }
1056
1057
1058 namespace {
is_texturable(VkFormatFeatureFlags flags)1059 bool is_texturable(VkFormatFeatureFlags flags) {
1060 return SkToBool(VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT & flags) &&
1061 SkToBool(VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT & flags);
1062 }
1063
is_renderable(VkFormatFeatureFlags flags)1064 bool is_renderable(VkFormatFeatureFlags flags) {
1065 return SkToBool(VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT & flags);
1066 }
1067
is_storage(VkFormatFeatureFlags flags)1068 bool is_storage(VkFormatFeatureFlags flags) {
1069 return SkToBool(VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT & flags);
1070 }
1071
is_transfer_src(VkFormatFeatureFlags flags)1072 bool is_transfer_src(VkFormatFeatureFlags flags) {
1073 return SkToBool(VK_FORMAT_FEATURE_TRANSFER_SRC_BIT & flags);
1074 }
1075
is_transfer_dst(VkFormatFeatureFlags flags)1076 bool is_transfer_dst(VkFormatFeatureFlags flags) {
1077 return SkToBool(VK_FORMAT_FEATURE_TRANSFER_DST_BIT & flags);
1078 }
1079 }
1080
init(const skgpu::VulkanInterface * interface,VkPhysicalDevice physDev,const VkPhysicalDeviceProperties & properties,VkFormat format)1081 void VulkanCaps::FormatInfo::init(const skgpu::VulkanInterface* interface,
1082 VkPhysicalDevice physDev,
1083 const VkPhysicalDeviceProperties& properties,
1084 VkFormat format) {
1085 memset(&fFormatProperties, 0, sizeof(VkFormatProperties));
1086 VULKAN_CALL(interface, GetPhysicalDeviceFormatProperties(physDev, format, &fFormatProperties));
1087
1088 if (is_renderable(fFormatProperties.optimalTilingFeatures)) {
1089 // We make all renderable images support being used as input attachment
1090 VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
1091 VK_IMAGE_USAGE_TRANSFER_DST_BIT |
1092 VK_IMAGE_USAGE_SAMPLED_BIT |
1093 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
1094 VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
1095 this->fSupportedSampleCounts.initSampleCounts(interface, physDev, properties, format,
1096 usageFlags);
1097 }
1098 }
1099
isTexturable(VkImageTiling imageTiling) const1100 bool VulkanCaps::FormatInfo::isTexturable(VkImageTiling imageTiling) const {
1101 switch (imageTiling) {
1102 case VK_IMAGE_TILING_OPTIMAL:
1103 return is_texturable(fFormatProperties.optimalTilingFeatures);
1104 case VK_IMAGE_TILING_LINEAR:
1105 return is_texturable(fFormatProperties.linearTilingFeatures);
1106 default:
1107 return false;
1108 }
1109 SkUNREACHABLE;
1110 }
1111
isRenderable(VkImageTiling imageTiling,uint32_t sampleCount) const1112 bool VulkanCaps::FormatInfo::isRenderable(VkImageTiling imageTiling,
1113 uint32_t sampleCount) const {
1114 if (!fSupportedSampleCounts.isSampleCountSupported(sampleCount)) {
1115 return false;
1116 }
1117 switch (imageTiling) {
1118 case VK_IMAGE_TILING_OPTIMAL:
1119 return is_renderable(fFormatProperties.optimalTilingFeatures);
1120 case VK_IMAGE_TILING_LINEAR:
1121 return is_renderable(fFormatProperties.linearTilingFeatures);
1122 default:
1123 return false;
1124 }
1125 SkUNREACHABLE;
1126 }
1127
isStorage(VkImageTiling imageTiling) const1128 bool VulkanCaps::FormatInfo::isStorage(VkImageTiling imageTiling) const {
1129 switch (imageTiling) {
1130 case VK_IMAGE_TILING_OPTIMAL:
1131 return is_storage(fFormatProperties.optimalTilingFeatures);
1132 case VK_IMAGE_TILING_LINEAR:
1133 return is_storage(fFormatProperties.linearTilingFeatures);
1134 default:
1135 return false;
1136 }
1137 SkUNREACHABLE;
1138 }
1139
isTransferSrc(VkImageTiling imageTiling) const1140 bool VulkanCaps::FormatInfo::isTransferSrc(VkImageTiling imageTiling) const {
1141 switch (imageTiling) {
1142 case VK_IMAGE_TILING_OPTIMAL:
1143 return is_transfer_src(fFormatProperties.optimalTilingFeatures);
1144 case VK_IMAGE_TILING_LINEAR:
1145 return is_transfer_src(fFormatProperties.linearTilingFeatures);
1146 default:
1147 return false;
1148 }
1149 SkUNREACHABLE;
1150 }
1151
isTransferDst(VkImageTiling imageTiling) const1152 bool VulkanCaps::FormatInfo::isTransferDst(VkImageTiling imageTiling) const {
1153 switch (imageTiling) {
1154 case VK_IMAGE_TILING_OPTIMAL:
1155 return is_transfer_dst(fFormatProperties.optimalTilingFeatures);
1156 case VK_IMAGE_TILING_LINEAR:
1157 return is_transfer_dst(fFormatProperties.linearTilingFeatures);
1158 default:
1159 return false;
1160 }
1161 SkUNREACHABLE;
1162 }
1163
setColorType(SkColorType colorType,std::initializer_list<VkFormat> formats)1164 void VulkanCaps::setColorType(SkColorType colorType, std::initializer_list<VkFormat> formats) {
1165 int idx = static_cast<int>(colorType);
1166 for (auto it = formats.begin(); it != formats.end(); ++it) {
1167 const auto& info = this->getFormatInfo(*it);
1168 for (int i = 0; i < info.fColorTypeInfoCount; ++i) {
1169 if (info.fColorTypeInfos[i].fColorType == colorType) {
1170 fColorTypeToFormatTable[idx] = *it;
1171 return;
1172 }
1173 }
1174 }
1175 }
1176
getFormatFromColorType(SkColorType colorType) const1177 VkFormat VulkanCaps::getFormatFromColorType(SkColorType colorType) const {
1178 int idx = static_cast<int>(colorType);
1179 return fColorTypeToFormatTable[idx];
1180 }
1181
getFormatInfo(VkFormat format)1182 VulkanCaps::FormatInfo& VulkanCaps::getFormatInfo(VkFormat format) {
1183 static_assert(std::size(kVkFormats) == VulkanCaps::kNumVkFormats,
1184 "Size of VkFormats array must match static value in header");
1185 for (size_t i = 0; i < std::size(kVkFormats); ++i) {
1186 if (kVkFormats[i] == format) {
1187 return fFormatTable[i];
1188 }
1189 }
1190 static FormatInfo kInvalidFormat;
1191 return kInvalidFormat;
1192 }
1193
getFormatInfo(VkFormat format) const1194 const VulkanCaps::FormatInfo& VulkanCaps::getFormatInfo(VkFormat format) const {
1195 VulkanCaps* nonConstThis = const_cast<VulkanCaps*>(this);
1196 return nonConstThis->getFormatInfo(format);
1197 }
1198
init(const skgpu::VulkanInterface * interface,VkPhysicalDevice physDev,const VkPhysicalDeviceProperties & properties,VkFormat format)1199 void VulkanCaps::DepthStencilFormatInfo::init(const skgpu::VulkanInterface* interface,
1200 VkPhysicalDevice physDev,
1201 const VkPhysicalDeviceProperties& properties,
1202 VkFormat format) {
1203 memset(&fFormatProperties, 0, sizeof(VkFormatProperties));
1204 VULKAN_CALL(interface, GetPhysicalDeviceFormatProperties(physDev, format, &fFormatProperties));
1205
1206 if (this->isDepthStencilSupported(fFormatProperties.optimalTilingFeatures)) {
1207 VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
1208 fSupportedSampleCounts.initSampleCounts(interface, physDev, properties, format, usageFlags);
1209 }
1210 }
1211
isDepthStencilSupported(VkFormatFeatureFlags flags) const1212 bool VulkanCaps::DepthStencilFormatInfo::isDepthStencilSupported(VkFormatFeatureFlags flags) const {
1213 return SkToBool(VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT & flags);
1214 }
1215
getFormatFromDepthStencilFlags(const SkEnumBitMask<DepthStencilFlags> & flags) const1216 VkFormat VulkanCaps::getFormatFromDepthStencilFlags(const SkEnumBitMask<DepthStencilFlags>& flags)
1217 const {
1218 return fDepthStencilFlagsToFormatTable[flags.value()];
1219 }
1220
getDepthStencilFormatInfo(VkFormat format)1221 VulkanCaps::DepthStencilFormatInfo& VulkanCaps::getDepthStencilFormatInfo(VkFormat format) {
1222 static_assert(std::size(kDepthStencilVkFormats) == VulkanCaps::kNumDepthStencilVkFormats,
1223 "Size of VkFormats array must match static value in header");
1224 for (size_t i = 0; i < std::size(kDepthStencilVkFormats); ++i) {
1225 if (kVkFormats[i] == format) {
1226 return fDepthStencilFormatTable[i];
1227 }
1228 }
1229 static DepthStencilFormatInfo kInvalidFormat;
1230 return kInvalidFormat;
1231 }
1232
getDepthStencilFormatInfo(VkFormat format) const1233 const VulkanCaps::DepthStencilFormatInfo& VulkanCaps::getDepthStencilFormatInfo(VkFormat format)
1234 const {
1235 VulkanCaps* nonConstThis = const_cast<VulkanCaps*>(this);
1236 return nonConstThis->getDepthStencilFormatInfo(format);
1237 }
1238
getColorTypeInfo(SkColorType ct,const TextureInfo & textureInfo) const1239 const Caps::ColorTypeInfo* VulkanCaps::getColorTypeInfo(SkColorType ct,
1240 const TextureInfo& textureInfo) const {
1241 VkFormat vkFormat = textureInfo.vulkanTextureSpec().fFormat;
1242 if (vkFormat == VK_FORMAT_UNDEFINED) {
1243 // If VkFormat is undefined but there is a valid YCbCr conversion associated with the
1244 // texture, then we know we are using an external format and can return color type
1245 // info representative of external format color information.
1246 return textureInfo.vulkanTextureSpec().fYcbcrConversionInfo.isValid()
1247 ? &fExternalFormatColorTypeInfo
1248 : nullptr;
1249 }
1250
1251 const FormatInfo& info = this->getFormatInfo(vkFormat);
1252 for (int i = 0; i < info.fColorTypeInfoCount; ++i) {
1253 const ColorTypeInfo& ctInfo = info.fColorTypeInfos[i];
1254 if (ctInfo.fColorType == ct) {
1255 return &ctInfo;
1256 }
1257 }
1258
1259 return nullptr;
1260 }
1261
onIsTexturable(const TextureInfo & texInfo) const1262 bool VulkanCaps::onIsTexturable(const TextureInfo& texInfo) const {
1263 VulkanTextureInfo vkInfo;
1264 if (!texInfo.getVulkanTextureInfo(&vkInfo)) {
1265 return false;
1266 }
1267
1268 // All images using external formats are required to be able to be sampled per Vulkan spec.
1269 // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkAndroidHardwareBufferFormatPropertiesANDROID.html#_description
1270 if (vkInfo.fFormat == VK_FORMAT_UNDEFINED && vkInfo.fYcbcrConversionInfo.isValid()) {
1271 return true;
1272 }
1273
1274 // Otherwise, we are working with a known format and can simply reference the format table info.
1275 const FormatInfo& info = this->getFormatInfo(vkInfo.fFormat);
1276 return info.isTexturable(vkInfo.fImageTiling);
1277 }
1278
isRenderable(const TextureInfo & texInfo) const1279 bool VulkanCaps::isRenderable(const TextureInfo& texInfo) const {
1280 VulkanTextureInfo vkInfo;
1281 if (!texInfo.getVulkanTextureInfo(&vkInfo)) {
1282 return false;
1283 }
1284
1285 const FormatInfo& info = this->getFormatInfo(vkInfo.fFormat);
1286 return info.isRenderable(vkInfo.fImageTiling, texInfo.numSamples());
1287 }
1288
isStorage(const TextureInfo & texInfo) const1289 bool VulkanCaps::isStorage(const TextureInfo& texInfo) const {
1290 VulkanTextureInfo vkInfo;
1291 if (!texInfo.getVulkanTextureInfo(&vkInfo)) {
1292 return false;
1293 }
1294
1295 const FormatInfo& info = this->getFormatInfo(vkInfo.fFormat);
1296 return info.isStorage(vkInfo.fImageTiling);
1297 }
1298
isTransferSrc(const VulkanTextureInfo & vkInfo) const1299 bool VulkanCaps::isTransferSrc(const VulkanTextureInfo& vkInfo) const {
1300 const FormatInfo& info = this->getFormatInfo(vkInfo.fFormat);
1301 return info.isTransferSrc(vkInfo.fImageTiling);
1302 }
1303
isTransferDst(const VulkanTextureInfo & vkInfo) const1304 bool VulkanCaps::isTransferDst(const VulkanTextureInfo& vkInfo) const {
1305 const FormatInfo& info = this->getFormatInfo(vkInfo.fFormat);
1306 return info.isTransferDst(vkInfo.fImageTiling);
1307 }
1308
supportsWritePixels(const TextureInfo & texInfo) const1309 bool VulkanCaps::supportsWritePixels(const TextureInfo& texInfo) const {
1310 VulkanTextureInfo vkInfo;
1311 if (!texInfo.getVulkanTextureInfo(&vkInfo)) {
1312 return false;
1313 }
1314
1315 // Can't write if it needs a YCbCr sampler
1316 if (VkFormatNeedsYcbcrSampler(vkInfo.fFormat)) {
1317 return false;
1318 }
1319
1320 if (vkInfo.fSampleCount > 1) {
1321 return false;
1322 }
1323
1324 if (!SkToBool(vkInfo.fImageUsageFlags & VK_IMAGE_USAGE_TRANSFER_DST_BIT)) {
1325 return false;
1326 }
1327
1328 return true;
1329 }
1330
supportsReadPixels(const TextureInfo & texInfo) const1331 bool VulkanCaps::supportsReadPixels(const TextureInfo& texInfo) const {
1332 if (texInfo.isProtected() == Protected::kYes) {
1333 return false;
1334 }
1335
1336 VulkanTextureInfo vkInfo;
1337 if (!texInfo.getVulkanTextureInfo(&vkInfo)) {
1338 return false;
1339 }
1340
1341 // Can't read if it needs a YCbCr sampler
1342 if (VkFormatNeedsYcbcrSampler(vkInfo.fFormat)) {
1343 return false;
1344 }
1345
1346 if (VkFormatIsCompressed(vkInfo.fFormat)) {
1347 return false;
1348 }
1349
1350 if (vkInfo.fSampleCount > 1) {
1351 return false;
1352 }
1353
1354 if (!SkToBool(vkInfo.fImageUsageFlags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT)) {
1355 return false;
1356 }
1357
1358 return true;
1359 }
1360
supportedWritePixelsColorType(SkColorType dstColorType,const TextureInfo & dstTextureInfo,SkColorType srcColorType) const1361 std::pair<SkColorType, bool /*isRGBFormat*/> VulkanCaps::supportedWritePixelsColorType(
1362 SkColorType dstColorType,
1363 const TextureInfo& dstTextureInfo,
1364 SkColorType srcColorType) const {
1365 VulkanTextureInfo vkInfo;
1366 if (!dstTextureInfo.getVulkanTextureInfo(&vkInfo)) {
1367 return {kUnknown_SkColorType, false};
1368 }
1369
1370 // Can't write to YCbCr formats
1371 // TODO: Can't write to external formats, either
1372 if (VkFormatNeedsYcbcrSampler(vkInfo.fFormat)) {
1373 return {kUnknown_SkColorType, false};
1374 }
1375
1376 const FormatInfo& info = this->getFormatInfo(vkInfo.fFormat);
1377 for (int i = 0; i < info.fColorTypeInfoCount; ++i) {
1378 const auto& ctInfo = info.fColorTypeInfos[i];
1379 if (ctInfo.fColorType == dstColorType) {
1380 return {ctInfo.fTransferColorType, vkInfo.fFormat == VK_FORMAT_R8G8B8_UNORM};
1381 }
1382 }
1383
1384 return {kUnknown_SkColorType, false};
1385 }
1386
supportedReadPixelsColorType(SkColorType srcColorType,const TextureInfo & srcTextureInfo,SkColorType dstColorType) const1387 std::pair<SkColorType, bool /*isRGBFormat*/> VulkanCaps::supportedReadPixelsColorType(
1388 SkColorType srcColorType,
1389 const TextureInfo& srcTextureInfo,
1390 SkColorType dstColorType) const {
1391 VulkanTextureInfo vkInfo;
1392 if (!srcTextureInfo.getVulkanTextureInfo(&vkInfo)) {
1393 return {kUnknown_SkColorType, false};
1394 }
1395
1396 // Can't read from YCbCr formats
1397 // TODO: external formats?
1398 if (VkFormatNeedsYcbcrSampler(vkInfo.fFormat)) {
1399 return {kUnknown_SkColorType, false};
1400 }
1401
1402 // TODO: handle compressed formats
1403 if (VkFormatIsCompressed(vkInfo.fFormat)) {
1404 SkASSERT(this->isTexturable(vkInfo));
1405 return {kUnknown_SkColorType, false};
1406 }
1407
1408 const FormatInfo& info = this->getFormatInfo(vkInfo.fFormat);
1409 for (int i = 0; i < info.fColorTypeInfoCount; ++i) {
1410 const auto& ctInfo = info.fColorTypeInfos[i];
1411 if (ctInfo.fColorType == srcColorType) {
1412 return {ctInfo.fTransferColorType, vkInfo.fFormat == VK_FORMAT_R8G8B8_UNORM};
1413 }
1414 }
1415
1416 return {kUnknown_SkColorType, false};
1417 }
1418
makeGraphicsPipelineKey(const GraphicsPipelineDesc & pipelineDesc,const RenderPassDesc & renderPassDesc) const1419 UniqueKey VulkanCaps::makeGraphicsPipelineKey(const GraphicsPipelineDesc& pipelineDesc,
1420 const RenderPassDesc& renderPassDesc) const {
1421 UniqueKey pipelineKey;
1422 {
1423 static const skgpu::UniqueKey::Domain kGraphicsPipelineDomain =
1424 UniqueKey::GenerateDomain();
1425
1426 VulkanRenderPass::VulkanRenderPassMetaData rpMetaData {renderPassDesc};
1427
1428 // Reserve 3 uint32s for the render step id, paint id, and write swizzle.
1429 static constexpr int kUint32sNeededForPipelineInfo = 3;
1430 // The uint32s needed for a RenderPass is variable number, so consult rpMetaData to
1431 // determine how many to reserve.
1432 UniqueKey::Builder builder(&pipelineKey,
1433 kGraphicsPipelineDomain,
1434 kUint32sNeededForPipelineInfo + rpMetaData.fUint32DataCnt,
1435 "GraphicsPipeline");
1436
1437 int idx = 0;
1438 // Add GraphicsPipelineDesc information
1439 builder[idx++] = pipelineDesc.renderStepID();
1440 builder[idx++] = pipelineDesc.paintParamsID().asUInt();
1441 // Add RenderPass info relevant for pipeline creation that's not captured in RenderPass keys
1442 builder[idx++] = renderPassDesc.fWriteSwizzle.asKey();
1443 // Add RenderPassDesc information
1444 VulkanRenderPass::AddRenderPassInfoToKey(rpMetaData, builder, idx, /*compatibleOnly=*/true);
1445
1446 builder.finish();
1447 }
1448
1449 return pipelineKey;
1450 }
1451
makeSamplerKey(const SamplerDesc & samplerDesc) const1452 GraphiteResourceKey VulkanCaps::makeSamplerKey(const SamplerDesc& samplerDesc) const {
1453 GraphiteResourceKey samplerKey;
1454 // Non-zero conversion information means the sampler utilizes a ycbcr conversion.
1455 uint32_t nonFormatYcbcrInfo =
1456 (uint32_t)(samplerDesc.desc() >> SamplerDesc::kImmutableSamplerInfoShift);
1457 bool usesYcbcrConversion = nonFormatYcbcrInfo != 0;
1458
1459 int uint32Quantity = 1;
1460 bool usesExternalFormat = false;
1461 if (usesYcbcrConversion) {
1462 // If using a YCbCr conversion, check nonFormatYcbcrInfo to see if we are using an external
1463 // format and update uint32Quantity accordingly.
1464 usesExternalFormat = static_cast<bool>(
1465 ((nonFormatYcbcrInfo & ycbcrPackaging::kUseExternalFormatMask) >>
1466 ycbcrPackaging::kUsesExternalFormatShift));
1467 // Reassign uint32Quantity. This is an assignment instead of an additive operation because
1468 // non-format ycbcr information and sampler information cam be fit into just one int32.
1469 uint32Quantity = usesExternalFormat ? ycbcrPackaging::kInt32sNeededExternalFormat
1470 : ycbcrPackaging::kInt32sNeededKnownFormat;
1471 }
1472 static const ResourceType kSamplerType = GraphiteResourceKey::GenerateResourceType();
1473 GraphiteResourceKey::Builder builder(&samplerKey, kSamplerType, uint32Quantity,
1474 Shareable::kYes);
1475 int i = 0;
1476 builder[i++] = samplerDesc.desc();
1477 if (usesYcbcrConversion) {
1478 if (usesExternalFormat) {
1479 builder[i++] = samplerDesc.externalFormatMSBs();
1480 }
1481 builder[i++] = samplerDesc.format();
1482 }
1483 SkASSERT(i == uint32Quantity);
1484
1485 builder.finish();
1486 return samplerKey;
1487 }
1488
buildKeyForTexture(SkISize dimensions,const TextureInfo & info,ResourceType type,Shareable shareable,GraphiteResourceKey * key) const1489 void VulkanCaps::buildKeyForTexture(SkISize dimensions,
1490 const TextureInfo& info,
1491 ResourceType type,
1492 Shareable shareable,
1493 GraphiteResourceKey* key) const {
1494 SkASSERT(!dimensions.isEmpty());
1495
1496 const VulkanTextureSpec& vkSpec = info.vulkanTextureSpec();
1497 // We expect that the VkFormat enum is at most a 32-bit value.
1498 static_assert(VK_FORMAT_MAX_ENUM == 0x7FFFFFFF);
1499 // We should either be using a known VkFormat or have a valid ycbcr conversion.
1500 SkASSERT(vkSpec.fFormat != VK_FORMAT_UNDEFINED || vkSpec.fYcbcrConversionInfo.isValid());
1501
1502 uint32_t format = static_cast<uint32_t>(vkSpec.fFormat);
1503 uint32_t samples = SamplesToKey(info.numSamples());
1504 // We don't have to key the number of mip levels because it is inherit in the combination of
1505 // isMipped and dimensions.
1506 bool isMipped = info.mipmapped() == Mipmapped::kYes;
1507 Protected isProtected = info.isProtected();
1508
1509 // Confirm all the below parts of the key can fit in a single uint32_t. The sum of the shift
1510 // amounts in the asserts must be less than or equal to 32. vkSpec.fFlags will go into its
1511 // own 32-bit block.
1512 SkASSERT(samples < (1u << 3)); // sample key is first 3 bits
1513 SkASSERT(static_cast<uint32_t>(isMipped) < (1u << 1)); // isMapped is 4th bit
1514 SkASSERT(static_cast<uint32_t>(isProtected) < (1u << 1)); // isProtected is 5th bit
1515 SkASSERT(vkSpec.fImageTiling < (1u << 1)); // imageTiling is 6th bit
1516 SkASSERT(vkSpec.fSharingMode < (1u << 1)); // sharingMode is 7th bit
1517 SkASSERT(vkSpec.fAspectMask < (1u << 11)); // aspectMask is bits 8 - 19
1518 SkASSERT(vkSpec.fImageUsageFlags < (1u << 12)); // imageUsageFlags are bits 20-32
1519
1520 // We need two uint32_ts for dimensions, 1 for format, and 2 for the rest of the information.
1521 static constexpr int kNum32DataCntNoYcbcr = 2 + 1 + 2;
1522 int num32DataCnt = kNum32DataCntNoYcbcr;
1523
1524 // If a texture w/ an external format is being used, that information must also be appended.
1525 const VulkanYcbcrConversionInfo& ycbcrInfo = info.vulkanTextureSpec().fYcbcrConversionInfo;
1526 num32DataCnt += ycbcrPackaging::numInt32sNeeded(ycbcrInfo);
1527
1528 GraphiteResourceKey::Builder builder(key, type, num32DataCnt, shareable);
1529
1530 int i = 0;
1531 builder[i++] = dimensions.width();
1532 builder[i++] = dimensions.height();
1533
1534 if (ycbcrInfo.isValid()) {
1535 SkASSERT(ycbcrInfo.fFormat != VK_FORMAT_UNDEFINED || ycbcrInfo.fExternalFormat != 0);
1536 bool useExternalFormat = ycbcrInfo.fFormat == VK_FORMAT_UNDEFINED;
1537 builder[i++] = ycbcrPackaging::nonFormatInfoAsUInt32(ycbcrInfo);
1538 if (useExternalFormat) {
1539 builder[i++] = (uint32_t)ycbcrInfo.fExternalFormat;
1540 builder[i++] = (uint32_t)(ycbcrInfo.fExternalFormat >> 32);
1541 } else {
1542 builder[i++] = ycbcrInfo.fFormat;
1543 }
1544 } else {
1545 builder[i++] = format;
1546 }
1547
1548 builder[i++] = (static_cast<uint32_t>(vkSpec.fFlags));
1549 builder[i++] = (samples << 0 ) |
1550 (static_cast<uint32_t>(isMipped) << 3 ) |
1551 (static_cast<uint32_t>(isProtected) << 4 ) |
1552 (static_cast<uint32_t>(vkSpec.fImageTiling) << 5 ) |
1553 (static_cast<uint32_t>(vkSpec.fSharingMode) << 6 ) |
1554 (static_cast<uint32_t>(vkSpec.fAspectMask) << 7 ) |
1555 (static_cast<uint32_t>(vkSpec.fImageUsageFlags) << 19);
1556 SkASSERT(i == num32DataCnt);
1557 }
1558
getImmutableSamplerInfo(sk_sp<TextureProxy> proxy) const1559 ImmutableSamplerInfo VulkanCaps::getImmutableSamplerInfo(sk_sp<TextureProxy> proxy) const {
1560 if (proxy) {
1561 const skgpu::VulkanYcbcrConversionInfo& ycbcrConversionInfo =
1562 proxy->textureInfo().vulkanTextureSpec().fYcbcrConversionInfo;
1563
1564 if (ycbcrConversionInfo.isValid()) {
1565 ImmutableSamplerInfo immutableSamplerInfo;
1566 // ycbcrConversionInfo's fFormat being VK_FORMAT_UNDEFINED indicates we are using an
1567 // external format rather than a known VkFormat.
1568 immutableSamplerInfo.fFormat = ycbcrConversionInfo.fFormat == VK_FORMAT_UNDEFINED
1569 ? ycbcrConversionInfo.fExternalFormat
1570 : ycbcrConversionInfo.fFormat;
1571 immutableSamplerInfo.fNonFormatYcbcrConversionInfo =
1572 ycbcrPackaging::nonFormatInfoAsUInt32(ycbcrConversionInfo);
1573 return immutableSamplerInfo;
1574 }
1575 }
1576
1577 // If the proxy is null or the YCbCr conversion for that proxy is invalid, then return a
1578 // default ImmutableSamplerInfo struct.
1579 return {};
1580 }
1581
1582 } // namespace skgpu::graphite
1583