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