| Flutter Impeller |

capabilities_vk.cc
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "impeller/renderer/backend/vulkan/capabilities_vk.h"
6
7 #include <algorithm>
8 #include <array>
9
10 #include "impeller/base/validation.h"
11 #include "impeller/core/formats.h"
12 #include "impeller/renderer/backend/vulkan/vk.h"
13 #include "impeller/renderer/backend/vulkan/workarounds_vk.h"
14
15 // vulkan.hpp generates some clang-tidy warnings.
16 // NOLINTBEGIN(clang-analyzer-security.PointerSub)
17
18 namespace impeller {
19
20 static constexpr const char* kInstanceLayer = "ImpellerInstance";
21
22 CapabilitiesVK::CapabilitiesVK(bool enable_validations,
23 bool fatal_missing_validations,
24 bool use_embedder_extensions,
25 std::vector<std::string> instance_extensions,
26 std::vector<std::string> device_extensions)
27 : use_embedder_extensions_(use_embedder_extensions),
28 embedder_instance_extensions_(std::move(instance_extensions)),
29 embedder_device_extensions_(std::move(device_extensions)) {
30 if (!use_embedder_extensions_) {
31 auto extensions = vk::enumerateInstanceExtensionProperties();
32 auto layers = vk::enumerateInstanceLayerProperties();
33
34 if (extensions.result != vk::Result::eSuccess ||
35 layers.result != vk::Result::eSuccess) {
36 return;
37 }
38
39 for (const auto& ext : extensions.value) {
40 exts_[kInstanceLayer].insert(ext.extensionName);
41 }
42
43 for (const auto& layer : layers.value) {
44 const std::string layer_name = layer.layerName;
45 auto layer_exts = vk::enumerateInstanceExtensionProperties(layer_name);
46 if (layer_exts.result != vk::Result::eSuccess) {
47 return;
48 }
49 for (const auto& layer_ext : layer_exts.value) {
50 exts_[layer_name].insert(layer_ext.extensionName);
51 }
52 }
53 } else {
54 for (const auto& ext : embedder_instance_extensions_) {
55 exts_[kInstanceLayer].insert(ext);
56 }
57 }
58
59 validations_enabled_ =
60 enable_validations && HasLayer("VK_LAYER_KHRONOS_validation");
61 if (enable_validations && !validations_enabled_) {
62 FML_LOG(ERROR)
63 << "Requested Impeller context creation with validations but the "
64 "validation layers could not be found. Expect no Vulkan validation "
65 "checks!";
66 if (fatal_missing_validations) {
67 FML_LOG(FATAL) << "Validation missing. Exiting.";
68 }
69 }
70 if (validations_enabled_) {
71 FML_LOG(INFO) << "Vulkan validations are enabled.";
72 }
73 is_valid_ = true;
74 }
75
76 CapabilitiesVK::~CapabilitiesVK() = default;
77
78 bool CapabilitiesVK::IsValid() const {
79 return is_valid_;
80 }
81
82 bool CapabilitiesVK::AreValidationsEnabled() const {
83 return validations_enabled_;
84 }
85
86 std::optional<std::vector<std::string>> CapabilitiesVK::GetEnabledLayers()
87 const {
88 std::vector<std::string> required;
89
90 if (validations_enabled_) {
91 // The presence of this layer is already checked in the ctor.
92 required.push_back("VK_LAYER_KHRONOS_validation");
93 }
94
95 return required;
96 }
97
98 std::optional<std::vector<std::string>>
99 CapabilitiesVK::GetEnabledInstanceExtensions() const {
100 std::vector<std::string> required;
101
102 if (!HasExtension("VK_KHR_surface")) {
103 // Swapchain support is required and this is a dependency of
104 // VK_KHR_swapchain.
105 VALIDATION_LOG << "Could not find the surface extension.";
106 return std::nullopt;
107 }
108 required.push_back("VK_KHR_surface");
109
110 auto has_wsi = false;
111 if (HasExtension("VK_MVK_macos_surface")) {
112 required.push_back("VK_MVK_macos_surface");
113 has_wsi = true;
114 }
115
116 if (HasExtension("VK_EXT_metal_surface")) {
117 required.push_back("VK_EXT_metal_surface");
118 has_wsi = true;
119 }
120
121 if (HasExtension("VK_KHR_portability_enumeration")) {
122 required.push_back("VK_KHR_portability_enumeration");
123 has_wsi = true;
124 }
125
126 if (HasExtension("VK_KHR_win32_surface")) {
127 required.push_back("VK_KHR_win32_surface");
128 has_wsi = true;
129 }
130
131 if (HasExtension("VK_KHR_android_surface")) {
132 required.push_back("VK_KHR_android_surface");
133 has_wsi = true;
134 }
135
136 if (HasExtension("VK_KHR_xcb_surface")) {
137 required.push_back("VK_KHR_xcb_surface");
138 has_wsi = true;
139 }
140
141 if (HasExtension("VK_KHR_xlib_surface")) {
142 required.push_back("VK_KHR_xlib_surface");
143 has_wsi = true;
144 }
145
146 if (HasExtension("VK_KHR_wayland_surface")) {
147 required.push_back("VK_KHR_wayland_surface");
148 has_wsi = true;
149 }
150
151 if (!has_wsi) {
152 // Don't really care which WSI extension there is as long there is at least
153 // one.
154 VALIDATION_LOG << "Could not find a WSI extension.";
155 return std::nullopt;
156 }
157
158 if (validations_enabled_) {
159 if (!HasExtension("VK_EXT_debug_utils")) {
160 VALIDATION_LOG << "Requested validations but could not find the "
161 "VK_EXT_debug_utils extension.";
162 return std::nullopt;
163 }
164 required.push_back("VK_EXT_debug_utils");
165
166 if (HasExtension("VK_EXT_validation_features")) {
167 // It's valid to not have `VK_EXT_validation_features` available. That's
168 // the case when using AGI as a frame debugger.
169 required.push_back("VK_EXT_validation_features");
170 }
171 }
172
173 return required;
174 }
175
176 static const char* GetExtensionName(RequiredCommonDeviceExtensionVK ext) {
177 switch (ext) {
178 case RequiredCommonDeviceExtensionVK::kKHRSwapchain:
179 return VK_KHR_SWAPCHAIN_EXTENSION_NAME;
180 case RequiredCommonDeviceExtensionVK::kLast:
181 return "Unknown";
182 }
183 FML_UNREACHABLE();
184 }
185
186 static const char* GetExtensionName(RequiredAndroidDeviceExtensionVK ext) {
187 switch (ext) {
188 case RequiredAndroidDeviceExtensionVK::
189 kANDROIDExternalMemoryAndroidHardwareBuffer:
190 return "VK_ANDROID_external_memory_android_hardware_buffer";
191 case RequiredAndroidDeviceExtensionVK::kKHRSamplerYcbcrConversion:
192 return VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME;
193 case RequiredAndroidDeviceExtensionVK::kKHRExternalMemory:
194 return VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME;
195 case RequiredAndroidDeviceExtensionVK::kEXTQueueFamilyForeign:
196 return VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME;
197 case RequiredAndroidDeviceExtensionVK::kKHRDedicatedAllocation:
198 return VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME;
199 case RequiredAndroidDeviceExtensionVK::kLast:
200 return "Unknown";
201 }
202 FML_UNREACHABLE();
203 }
204
205 static const char* GetExtensionName(OptionalAndroidDeviceExtensionVK ext) {
206 switch (ext) {
207 case OptionalAndroidDeviceExtensionVK::kKHRExternalFenceFd:
208 return VK_KHR_EXTERNAL_FENCE_FD_EXTENSION_NAME;
209 case OptionalAndroidDeviceExtensionVK::kKHRExternalFence:
210 return VK_KHR_EXTERNAL_FENCE_EXTENSION_NAME;
211 case OptionalAndroidDeviceExtensionVK::kKHRExternalSemaphoreFd:
212 return VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME;
213 case OptionalAndroidDeviceExtensionVK::kKHRExternalSemaphore:
214 return VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME;
215 case OptionalAndroidDeviceExtensionVK::kLast:
216 return "Unknown";
217 }
218 }
219
220 static const char* GetExtensionName(OptionalDeviceExtensionVK ext) {
221 switch (ext) {
222 case OptionalDeviceExtensionVK::kEXTPipelineCreationFeedback:
223 return VK_EXT_PIPELINE_CREATION_FEEDBACK_EXTENSION_NAME;
224 case OptionalDeviceExtensionVK::kVKKHRPortabilitySubset:
225 return "VK_KHR_portability_subset";
226 case OptionalDeviceExtensionVK::kEXTImageCompressionControl:
227 return VK_EXT_IMAGE_COMPRESSION_CONTROL_EXTENSION_NAME;
228 case OptionalDeviceExtensionVK::kLast:
229 return "Unknown";
230 }
231 FML_UNREACHABLE();
232 }
233
234 template <class T>
235 static bool IterateExtensions(const std::function<bool(T)>& it) {
236 if (!it) {
237 return false;
238 }
239 for (size_t i = 0; i < static_cast<uint32_t>(T::kLast); i++) {
240 if (!it(static_cast<T>(i))) {
241 return false;
242 }
243 }
244 return true;
245 }
246
247 static std::optional<std::set<std::string>> GetSupportedDeviceExtensions(
248 const vk::PhysicalDevice& physical_device) {
249 auto device_extensions = physical_device.enumerateDeviceExtensionProperties();
250 if (device_extensions.result != vk::Result::eSuccess) {
251 return std::nullopt;
252 }
253
254 std::set<std::string> exts;
255 for (const auto& device_extension : device_extensions.value) {
256 exts.insert(device_extension.extensionName);
257 };
258
259 return exts;
260 }
261
262 std::optional<std::vector<std::string>>
263 CapabilitiesVK::GetEnabledDeviceExtensions(
264 const vk::PhysicalDevice& physical_device) const {
265 std::set<std::string> exts;
266
267 if (!use_embedder_extensions_) {
268 auto maybe_exts = GetSupportedDeviceExtensions(physical_device);
269
270 if (!maybe_exts.has_value()) {
271 return std::nullopt;
272 }
273 exts = maybe_exts.value();
274 } else {
275 for (const auto& ext : embedder_device_extensions_) {
276 exts.insert(ext);
277 }
278 }
279
280 std::vector<std::string> enabled;
281
282 auto for_each_common_extension = [&](RequiredCommonDeviceExtensionVK ext) {
283 auto name = GetExtensionName(ext);
284 if (exts.find(name) == exts.end()) {
285 VALIDATION_LOG << "Device does not support required extension: " << name;
286 return false;
287 }
288 enabled.push_back(name);
289 return true;
290 };
291
292 auto for_each_android_extension = [&](RequiredAndroidDeviceExtensionVK ext) {
293 #ifdef FML_OS_ANDROID
294 auto name = GetExtensionName(ext);
295 if (exts.find(name) == exts.end()) {
296 VALIDATION_LOG << "Device does not support required Android extension: "
297 << name;
298 return false;
299 }
300 enabled.push_back(name);
301 #endif // FML_OS_ANDROID
302 return true;
303 };
304
305 auto for_each_optional_android_extension =
306 [&](OptionalAndroidDeviceExtensionVK ext) {
307 #ifdef FML_OS_ANDROID
308 auto name = GetExtensionName(ext);
309 if (exts.find(name) != exts.end()) {
310 enabled.push_back(name);
311 }
312 #endif // FML_OS_ANDROID
313 return true;
314 };
315
316 auto for_each_optional_extension = [&](OptionalDeviceExtensionVK ext) {
317 auto name = GetExtensionName(ext);
318 if (exts.find(name) != exts.end()) {
319 enabled.push_back(name);
320 }
321 return true;
322 };
323
324 const auto iterate_extensions =
325 IterateExtensions<RequiredCommonDeviceExtensionVK>(
326 for_each_common_extension) &&
327 IterateExtensions<RequiredAndroidDeviceExtensionVK>(
328 for_each_android_extension) &&
329 IterateExtensions<OptionalDeviceExtensionVK>(
330 for_each_optional_extension) &&
331 IterateExtensions<OptionalAndroidDeviceExtensionVK>(
332 for_each_optional_android_extension);
333
334 if (!iterate_extensions) {
335 VALIDATION_LOG << "Device not suitable since required extensions are not "
336 "supported.";
337 return std::nullopt;
338 }
339
340 return enabled;
341 }
342
343 static bool HasSuitableColorFormat(const vk::PhysicalDevice& device,
344 vk::Format format) {
345 const auto props = device.getFormatProperties(format);
346 // This needs to be more comprehensive.
347 return !!(props.optimalTilingFeatures &
348 vk::FormatFeatureFlagBits::eColorAttachment);
349 }
350
351 static bool HasSuitableDepthStencilFormat(const vk::PhysicalDevice& device,
352 vk::Format format) {
353 const auto props = device.getFormatProperties(format);
354 return !!(props.optimalTilingFeatures &
355 vk::FormatFeatureFlagBits::eDepthStencilAttachment);
356 }
357
358 static bool PhysicalDeviceSupportsRequiredFormats(
359 const vk::PhysicalDevice& device) {
360 const auto has_color_format =
361 HasSuitableColorFormat(device, vk::Format::eR8G8B8A8Unorm);
362 const auto has_stencil_format =
363 HasSuitableDepthStencilFormat(device, vk::Format::eD32SfloatS8Uint) ||
364 HasSuitableDepthStencilFormat(device, vk::Format::eD24UnormS8Uint);
365 return has_color_format && has_stencil_format;
366 }
367
368 static bool HasRequiredProperties(const vk::PhysicalDevice& physical_device) {
369 auto properties = physical_device.getProperties();
370 if (!(properties.limits.framebufferColorSampleCounts &
371 (vk::SampleCountFlagBits::e1 | vk::SampleCountFlagBits::e4))) {
372 return false;
373 }
374 return true;
375 }
376
377 static bool HasRequiredQueues(const vk::PhysicalDevice& physical_device) {
378 auto queue_flags = vk::QueueFlags{};
379 for (const auto& queue : physical_device.getQueueFamilyProperties()) {
380 if (queue.queueCount == 0) {
381 continue;
382 }
383 queue_flags |= queue.queueFlags;
384 }
385 return static_cast<VkQueueFlags>(queue_flags &
386 (vk::QueueFlagBits::eGraphics |
387 vk::QueueFlagBits::eCompute |
388 vk::QueueFlagBits::eTransfer));
389 }
390
391 template <class ExtensionEnum>
392 static bool IsExtensionInList(const std::vector<std::string>& list,
393 ExtensionEnum ext) {
394 const std::string name = GetExtensionName(ext);
395 return std::find(list.begin(), list.end(), name) != list.end();
396 }
397
398 std::optional<CapabilitiesVK::PhysicalDeviceFeatures>
399 CapabilitiesVK::GetEnabledDeviceFeatures(
400 const vk::PhysicalDevice& device) const {
401 if (!PhysicalDeviceSupportsRequiredFormats(device)) {
402 VALIDATION_LOG << "Device doesn't support the required formats.";
403 return std::nullopt;
404 }
405
406 if (!HasRequiredProperties(device)) {
407 VALIDATION_LOG << "Device doesn't support the required properties.";
408 return std::nullopt;
409 }
410
411 if (!HasRequiredQueues(device)) {
412 VALIDATION_LOG << "Device doesn't support the required queues.";
413 return std::nullopt;
414 }
415
416 const auto enabled_extensions = GetEnabledDeviceExtensions(device);
417 if (!enabled_extensions.has_value()) {
418 VALIDATION_LOG << "Device doesn't support the required queues.";
419 return std::nullopt;
420 }
421
422 PhysicalDeviceFeatures supported_chain;
423
424 // Swiftshader seems to be fussy about just this structure even being in the
425 // chain. Just unlink it if its not supported. We already perform an
426 // extensions check on the other side when reading.
427 if (!IsExtensionInList(
428 enabled_extensions.value(),
429 OptionalDeviceExtensionVK::kEXTImageCompressionControl)) {
430 supported_chain
431 .unlink<vk::PhysicalDeviceImageCompressionControlFeaturesEXT>();
432 }
433
434 device.getFeatures2(&supported_chain.get());
435
436 PhysicalDeviceFeatures required_chain;
437
438 // Base features.
439 {
440 auto& required = required_chain.get().features;
441 const auto& supported = supported_chain.get().features;
442
443 // We require this for enabling wireframes in the playground. But its not
444 // necessarily a big deal if we don't have this feature.
445 required.fillModeNonSolid = supported.fillModeNonSolid;
446 }
447 // VK_KHR_sampler_ycbcr_conversion features.
448 if (IsExtensionInList(
449 enabled_extensions.value(),
450 RequiredAndroidDeviceExtensionVK::kKHRSamplerYcbcrConversion)) {
451 auto& required =
452 required_chain
453 .get<vk::PhysicalDeviceSamplerYcbcrConversionFeaturesKHR>();
454 const auto& supported =
455 supported_chain
456 .get<vk::PhysicalDeviceSamplerYcbcrConversionFeaturesKHR>();
457
458 required.samplerYcbcrConversion = supported.samplerYcbcrConversion;
459 }
460
461 // VK_EXT_image_compression_control
462 if (IsExtensionInList(
463 enabled_extensions.value(),
464 OptionalDeviceExtensionVK::kEXTImageCompressionControl)) {
465 auto& required =
466 required_chain
467 .get<vk::PhysicalDeviceImageCompressionControlFeaturesEXT>();
468 const auto& supported =
469 supported_chain
470 .get<vk::PhysicalDeviceImageCompressionControlFeaturesEXT>();
471
472 required.imageCompressionControl = supported.imageCompressionControl;
473 } else {
474 required_chain
475 .unlink<vk::PhysicalDeviceImageCompressionControlFeaturesEXT>();
476 }
477
478 // Vulkan 1.1
479 {
480 auto& required =
481 required_chain.get<vk::PhysicalDevice16BitStorageFeatures>();
482 const auto& supported =
483 supported_chain.get<vk::PhysicalDevice16BitStorageFeatures>();
484
485 required.uniformAndStorageBuffer16BitAccess =
486 supported.uniformAndStorageBuffer16BitAccess;
487 }
488
489 return required_chain;
490 }
491
492 bool CapabilitiesVK::HasLayer(const std::string& layer) const {
493 for (const auto& [found_layer, exts] : exts_) {
494 if (found_layer == layer) {
495 return true;
496 }
497 }
498 return false;
499 }
500
501 bool CapabilitiesVK::HasExtension(const std::string& ext) const {
502 for (const auto& [layer, exts] : exts_) {
503 if (exts.find(ext) != exts.end()) {
504 return true;
505 }
506 }
507 return false;
508 }
509
510 bool CapabilitiesVK::SupportsPrimitiveRestart() const {
511 return has_primitive_restart_;
512 }
513
514 void CapabilitiesVK::SetOffscreenFormat(PixelFormat pixel_format) const {
515 default_color_format_ = pixel_format;
516 }
517
518 bool CapabilitiesVK::SetPhysicalDevice(
519 const vk::PhysicalDevice& device,
520 const PhysicalDeviceFeatures& enabled_features) {
521 if (HasSuitableColorFormat(device, vk::Format::eR8G8B8A8Unorm)) {
522 default_color_format_ = PixelFormat::kR8G8B8A8UNormInt;
523 } else {
524 default_color_format_ = PixelFormat::kUnknown;
525 }
526
527 if (HasSuitableDepthStencilFormat(device, vk::Format::eD24UnormS8Uint)) {
528 default_depth_stencil_format_ = PixelFormat::kD24UnormS8Uint;
529 } else if (HasSuitableDepthStencilFormat(device,
530 vk::Format::eD32SfloatS8Uint)) {
531 default_depth_stencil_format_ = PixelFormat::kD32FloatS8UInt;
532 } else {
533 default_depth_stencil_format_ = PixelFormat::kUnknown;
534 }
535
536 if (HasSuitableDepthStencilFormat(device, vk::Format::eS8Uint)) {
537 default_stencil_format_ = PixelFormat::kS8UInt;
538 } else if (default_depth_stencil_format_ != PixelFormat::kUnknown) {
539 default_stencil_format_ = default_depth_stencil_format_;
540 }
541
542 physical_device_ = device;
543 device_properties_ = device.getProperties();
544
545 auto physical_properties_2 =
546 device.getProperties2<vk::PhysicalDeviceProperties2,
547 vk::PhysicalDeviceSubgroupProperties>();
548
549 // Currently shaders only want access to arithmetic subgroup features.
550 // If that changes this needs to get updated, and so does Metal (which right
551 // now assumes it from compile time flags based on the MSL target version).
552
553 supports_compute_subgroups_ =
554 !!(physical_properties_2.get<vk::PhysicalDeviceSubgroupProperties>()
555 .supportedOperations &
556 vk::SubgroupFeatureFlagBits::eArithmetic);
557
558 {
559 // Query texture support.
560 // TODO(129784): Add a capability check for expected memory types.
561 vk::PhysicalDeviceMemoryProperties memory_properties;
562 device.getMemoryProperties(&memory_properties);
563
564 for (auto i = 0u; i < memory_properties.memoryTypeCount; i++) {
565 if (memory_properties.memoryTypes[i].propertyFlags &
566 vk::MemoryPropertyFlagBits::eLazilyAllocated) {
567 supports_device_transient_textures_ = true;
568 }
569 }
570 }
571
572 // Determine the optional device extensions this physical device supports.
573 {
574 required_common_device_extensions_.clear();
575 required_android_device_extensions_.clear();
576 optional_device_extensions_.clear();
577 optional_android_device_extensions_.clear();
578
579 std::set<std::string> exts;
580 if (!use_embedder_extensions_) {
581 auto maybe_exts = GetSupportedDeviceExtensions(device);
582 if (!maybe_exts.has_value()) {
583 return false;
584 }
585 exts = maybe_exts.value();
586 } else {
587 for (const auto& ext : embedder_device_extensions_) {
588 exts.insert(ext);
589 }
590 }
591
592 IterateExtensions<RequiredCommonDeviceExtensionVK>([&](auto ext) -> bool {
593 auto ext_name = GetExtensionName(ext);
594 if (exts.find(ext_name) != exts.end()) {
595 required_common_device_extensions_.insert(ext);
596 }
597 return true;
598 });
599 IterateExtensions<RequiredAndroidDeviceExtensionVK>([&](auto ext) -> bool {
600 auto ext_name = GetExtensionName(ext);
601 if (exts.find(ext_name) != exts.end()) {
602 required_android_device_extensions_.insert(ext);
603 }
604 return true;
605 });
606 IterateExtensions<OptionalDeviceExtensionVK>([&](auto ext) -> bool {
607 auto ext_name = GetExtensionName(ext);
608 if (exts.find(ext_name) != exts.end()) {
609 optional_device_extensions_.insert(ext);
610 }
611 return true;
612 });
613 IterateExtensions<OptionalAndroidDeviceExtensionVK>(
614 [&](OptionalAndroidDeviceExtensionVK ext) {
615 auto name = GetExtensionName(ext);
616 if (exts.find(name) != exts.end()) {
617 optional_android_device_extensions_.insert(ext);
618 }
619 return true;
620 });
621 }
622
623 supports_texture_fixed_rate_compression_ =
624 enabled_features
625 .isLinked<vk::PhysicalDeviceImageCompressionControlFeaturesEXT>() &&
626 enabled_features
627 .get<vk::PhysicalDeviceImageCompressionControlFeaturesEXT>()
628 .imageCompressionControl;
629
630 max_render_pass_attachment_size_ =
631 ISize{device_properties_.limits.maxFramebufferWidth,
632 device_properties_.limits.maxFramebufferHeight};
633
634 // Molten, Vulkan on Metal, cannot support triangle fans because Metal doesn't
635 // support triangle fans.
636 // See VUID-VkPipelineInputAssemblyStateCreateInfo-triangleFans-04452.
637 has_triangle_fans_ =
638 !HasExtension(OptionalDeviceExtensionVK::kVKKHRPortabilitySubset);
639
640 // External Fence/Semaphore for AHB swapchain
641 if (HasExtension(OptionalAndroidDeviceExtensionVK::kKHRExternalFenceFd) &&
642 HasExtension(OptionalAndroidDeviceExtensionVK::kKHRExternalFence) &&
643 HasExtension(OptionalAndroidDeviceExtensionVK::kKHRExternalSemaphore) &&
644 HasExtension(OptionalAndroidDeviceExtensionVK::kKHRExternalSemaphoreFd)) {
645 supports_external_fence_and_semaphore_ = true;
646 }
647
648 minimum_uniform_alignment_ =
649 device_properties_.limits.minUniformBufferOffsetAlignment;
650
651 return true;
652 }
653
654 // |Capabilities|
655 bool CapabilitiesVK::SupportsOffscreenMSAA() const {
656 return true;
657 }
658
659 // |Capabilities|
660 bool CapabilitiesVK::SupportsImplicitResolvingMSAA() const {
661 return false;
662 }
663
664 // |Capabilities|
665 bool CapabilitiesVK::SupportsSSBO() const {
666 return true;
667 }
668
669 // |Capabilities|
670 bool CapabilitiesVK::SupportsTextureToTextureBlits() const {
671 return true;
672 }
673
674 // |Capabilities|
675 bool CapabilitiesVK::SupportsFramebufferFetch() const {
676 return has_framebuffer_fetch_;
677 }
678
679 // |Capabilities|
680 bool CapabilitiesVK::SupportsCompute() const {
681 // Vulkan 1.1 requires support for compute.
682 return true;
683 }
684
685 // |Capabilities|
686 bool CapabilitiesVK::SupportsComputeSubgroups() const {
687 // Set by |SetPhysicalDevice|.
688 return supports_compute_subgroups_;
689 }
690
691 // |Capabilities|
692 bool CapabilitiesVK::SupportsReadFromResolve() const {
693 return false;
694 }
695
696 bool CapabilitiesVK::SupportsDecalSamplerAddressMode() const {
697 return true;
698 }
699
700 // |Capabilities|
701 bool CapabilitiesVK::SupportsDeviceTransientTextures() const {
702 return supports_device_transient_textures_;
703 }
704
705 // |Capabilities|
706 PixelFormat CapabilitiesVK::GetDefaultColorFormat() const {
707 return default_color_format_;
708 }
709
710 // |Capabilities|
711 PixelFormat CapabilitiesVK::GetDefaultStencilFormat() const {
712 return default_stencil_format_;
713 }
714
715 // |Capabilities|
716 PixelFormat CapabilitiesVK::GetDefaultDepthStencilFormat() const {
717 return default_depth_stencil_format_;
718 }
719
720 const vk::PhysicalDeviceProperties&
721 CapabilitiesVK::GetPhysicalDeviceProperties() const {
722 return device_properties_;
723 }
724
725 PixelFormat CapabilitiesVK::GetDefaultGlyphAtlasFormat() const {
726 return PixelFormat::kR8UNormInt;
727 }
728
729 size_t CapabilitiesVK::GetMinimumUniformAlignment() const {
730 return minimum_uniform_alignment_;
731 }
732
733 bool CapabilitiesVK::NeedsPartitionedHostBuffer() const {
734 return false;
735 }
736
737 bool CapabilitiesVK::HasExtension(RequiredCommonDeviceExtensionVK ext) const {
738 return required_common_device_extensions_.find(ext) !=
739 required_common_device_extensions_.end();
740 }
741
742 bool CapabilitiesVK::HasExtension(RequiredAndroidDeviceExtensionVK ext) const {
743 return required_android_device_extensions_.find(ext) !=
744 required_android_device_extensions_.end();
745 }
746
747 bool CapabilitiesVK::HasExtension(OptionalDeviceExtensionVK ext) const {
748 return optional_device_extensions_.find(ext) !=
749 optional_device_extensions_.end();
750 }
751
752 bool CapabilitiesVK::HasExtension(OptionalAndroidDeviceExtensionVK ext) const {
753 return optional_android_device_extensions_.find(ext) !=
754 optional_android_device_extensions_.end();
755 }
756
757 bool CapabilitiesVK::SupportsTextureFixedRateCompression() const {
758 return supports_texture_fixed_rate_compression_;
759 }
760
761 std::optional<vk::ImageCompressionFixedRateFlagBitsEXT>
762 CapabilitiesVK::GetSupportedFRCRate(CompressionType compression_type,
763 const FRCFormatDescriptor& desc) const {
764 if (compression_type != CompressionType::kLossy) {
765 return std::nullopt;
766 }
767 if (!supports_texture_fixed_rate_compression_) {
768 return std::nullopt;
769 }
770 // There are opportunities to hash and cache the FRCFormatDescriptor if
771 // needed.
772 vk::StructureChain<vk::PhysicalDeviceImageFormatInfo2,
773 vk::ImageCompressionControlEXT>
774 format_chain;
775
776 auto& format_info = format_chain.get();
777
778 format_info.format = desc.format;
779 format_info.type = desc.type;
780 format_info.tiling = desc.tiling;
781 format_info.usage = desc.usage;
782 format_info.flags = desc.flags;
783
784 const auto kIdealFRCRate = vk::ImageCompressionFixedRateFlagBitsEXT::e4Bpc;
785
786 std::array<vk::ImageCompressionFixedRateFlagsEXT, 1u> rates = {kIdealFRCRate};
787
788 auto& compression = format_chain.get<vk::ImageCompressionControlEXT>();
789 compression.flags = vk::ImageCompressionFlagBitsEXT::eFixedRateExplicit;
790 compression.compressionControlPlaneCount = rates.size();
791 compression.pFixedRateFlags = rates.data();
792
793 const auto [result, supported] = physical_device_.getImageFormatProperties2<
794 vk::ImageFormatProperties2, vk::ImageCompressionPropertiesEXT>(
795 format_chain.get());
796
797 if (result != vk::Result::eSuccess ||
798 !supported.isLinked<vk::ImageCompressionPropertiesEXT>()) {
799 return std::nullopt;
800 }
801
802 const auto& compression_props =
803 supported.get<vk::ImageCompressionPropertiesEXT>();
804
805 if ((compression_props.imageCompressionFlags &
806 vk::ImageCompressionFlagBitsEXT::eFixedRateExplicit) &&
807 (compression_props.imageCompressionFixedRateFlags & kIdealFRCRate)) {
808 return kIdealFRCRate;
809 }
810
811 return std::nullopt;
812 }
813
814 bool CapabilitiesVK::SupportsTriangleFan() const {
815 return has_triangle_fans_;
816 }
817
818 ISize CapabilitiesVK::GetMaximumRenderPassAttachmentSize() const {
819 return max_render_pass_attachment_size_;
820 }
821
822 void CapabilitiesVK::ApplyWorkarounds(const WorkaroundsVK& workarounds) {
823 has_primitive_restart_ = !workarounds.slow_primitive_restart_performance;
824 has_framebuffer_fetch_ = !workarounds.input_attachment_self_dependency_broken;
825 }
826
827 bool CapabilitiesVK::SupportsExternalSemaphoreExtensions() const {
828 return supports_external_fence_and_semaphore_;
829 }
830
831 bool CapabilitiesVK::SupportsExtendedRangeFormats() const {
832 return false;
833 }
834
835 } // namespace impeller
836
837 // NOLINTEND(clang-analyzer-security.PointerSub)
capabilities_vk.h
impeller::CapabilitiesVK::SupportsTriangleFan
bool SupportsTriangleFan() const override
Whether the primitive type TriangleFan is supported by the backend.
Definition: capabilities_vk.cc:814
impeller::CapabilitiesVK::GetMinimumUniformAlignment
size_t GetMinimumUniformAlignment() const override
The minimum alignment of uniform value offsets in bytes.
Definition: capabilities_vk.cc:729
impeller::CapabilitiesVK::SupportsDeviceTransientTextures
bool SupportsDeviceTransientTextures() const override
Whether the context backend supports allocating StorageMode::kDeviceTransient (aka "memoryless") text...
Definition: capabilities_vk.cc:701
impeller::CapabilitiesVK::GetEnabledInstanceExtensions
std::optional< std::vector< std::string > > GetEnabledInstanceExtensions() const
Definition: capabilities_vk.cc:99
impeller::CapabilitiesVK::AreValidationsEnabled
bool AreValidationsEnabled() const
Definition: capabilities_vk.cc:82
impeller::CapabilitiesVK::SetPhysicalDevice
bool SetPhysicalDevice(const vk::PhysicalDevice &physical_device, const PhysicalDeviceFeatures &enabled_features)
Definition: capabilities_vk.cc:518
impeller::CapabilitiesVK::GetMaximumRenderPassAttachmentSize
ISize GetMaximumRenderPassAttachmentSize() const override
Return the maximum size of a render pass attachment.
Definition: capabilities_vk.cc:818
impeller::CapabilitiesVK::SupportsSSBO
bool SupportsSSBO() const override
Whether the context backend supports binding Shader Storage Buffer Objects (SSBOs) to pipelines.
Definition: capabilities_vk.cc:665
impeller::CapabilitiesVK::SupportsFramebufferFetch
bool SupportsFramebufferFetch() const override
Whether the context backend is able to support pipelines with shaders that read from the framebuffer ...
Definition: capabilities_vk.cc:675
impeller::CapabilitiesVK::SupportsExternalSemaphoreExtensions
bool SupportsExternalSemaphoreExtensions() const
Definition: capabilities_vk.cc:827
impeller::CapabilitiesVK::CapabilitiesVK
CapabilitiesVK(bool enable_validations, bool fatal_missing_validations=false, bool use_embedder_extensions=false, std::vector< std::string > instance_extensions={}, std::vector< std::string > device_extensions={})
Definition: capabilities_vk.cc:22
impeller::CapabilitiesVK::~CapabilitiesVK
~CapabilitiesVK()
impeller::CapabilitiesVK::SupportsOffscreenMSAA
bool SupportsOffscreenMSAA() const override
Whether the context backend supports attaching offscreen MSAA color/stencil textures.
Definition: capabilities_vk.cc:655
impeller::CapabilitiesVK::SupportsCompute
bool SupportsCompute() const override
Whether the context backend supports ComputePass.
Definition: capabilities_vk.cc:680
impeller::CapabilitiesVK::HasExtension
bool HasExtension(RequiredCommonDeviceExtensionVK ext) const
Definition: capabilities_vk.cc:737
impeller::CapabilitiesVK::GetSupportedFRCRate
std::optional< vk::ImageCompressionFixedRateFlagBitsEXT > GetSupportedFRCRate(CompressionType compression_type, const FRCFormatDescriptor &desc) const
Get the fixed compression rate supported by the context for the given format and usage.
Definition: capabilities_vk.cc:762
impeller::CapabilitiesVK::SetOffscreenFormat
void SetOffscreenFormat(PixelFormat pixel_format) const
Definition: capabilities_vk.cc:514
impeller::CapabilitiesVK::GetDefaultStencilFormat
PixelFormat GetDefaultStencilFormat() const override
Returns a supported PixelFormat for textures that store stencil information. May include a depth chan...
Definition: capabilities_vk.cc:711
impeller::CapabilitiesVK::ApplyWorkarounds
void ApplyWorkarounds(const WorkaroundsVK &workarounds)
Update capabilities for the given set of workarounds.
Definition: capabilities_vk.cc:822
impeller::CapabilitiesVK::IsValid
bool IsValid() const
Definition: capabilities_vk.cc:78
impeller::CapabilitiesVK::PhysicalDeviceFeatures
vk::StructureChain< vk::PhysicalDeviceFeatures2, vk::PhysicalDeviceSamplerYcbcrConversionFeaturesKHR, vk::PhysicalDevice16BitStorageFeatures, vk::PhysicalDeviceImageCompressionControlFeaturesEXT > PhysicalDeviceFeatures
Definition: capabilities_vk.h:214
impeller::CapabilitiesVK::SupportsComputeSubgroups
bool SupportsComputeSubgroups() const override
Whether the context backend supports configuring ComputePass command subgroups.
Definition: capabilities_vk.cc:686
impeller::CapabilitiesVK::GetDefaultDepthStencilFormat
PixelFormat GetDefaultDepthStencilFormat() const override
Returns a supported PixelFormat for textures that store both a stencil and depth component....
Definition: capabilities_vk.cc:716
impeller::CapabilitiesVK::SupportsTextureToTextureBlits
bool SupportsTextureToTextureBlits() const override
Whether the context backend supports blitting from one texture region to another texture region (via ...
Definition: capabilities_vk.cc:670
impeller::CapabilitiesVK::GetEnabledDeviceExtensions
std::optional< std::vector< std::string > > GetEnabledDeviceExtensions(const vk::PhysicalDevice &physical_device) const
Definition: capabilities_vk.cc:263
impeller::CapabilitiesVK::SupportsReadFromResolve
bool SupportsReadFromResolve() const override
Whether the context backend supports binding the current RenderPass attachments. This is supported if...
Definition: capabilities_vk.cc:692
impeller::CapabilitiesVK::SupportsDecalSamplerAddressMode
bool SupportsDecalSamplerAddressMode() const override
Whether the context backend supports SamplerAddressMode::Decal.
Definition: capabilities_vk.cc:696
impeller::CapabilitiesVK::SupportsPrimitiveRestart
bool SupportsPrimitiveRestart() const override
Whether primitive restart is supported.
Definition: capabilities_vk.cc:510
impeller::CapabilitiesVK::GetEnabledLayers
std::optional< std::vector< std::string > > GetEnabledLayers() const
Definition: capabilities_vk.cc:86
impeller::CapabilitiesVK::SupportsTextureFixedRateCompression
bool SupportsTextureFixedRateCompression() const
Definition: capabilities_vk.cc:757
impeller::CapabilitiesVK::NeedsPartitionedHostBuffer
bool NeedsPartitionedHostBuffer() const override
Whether the host buffer should use separate device buffers for indexes from other data.
Definition: capabilities_vk.cc:733
impeller::CapabilitiesVK::GetDefaultGlyphAtlasFormat
PixelFormat GetDefaultGlyphAtlasFormat() const override
Returns the default pixel format for the alpha bitmap glyph atlas.
Definition: capabilities_vk.cc:725
impeller::CapabilitiesVK::GetDefaultColorFormat
PixelFormat GetDefaultColorFormat() const override
Returns a supported PixelFormat for textures that store 4-channel colors (red/green/blue/alpha).
Definition: capabilities_vk.cc:706
impeller::CapabilitiesVK::GetPhysicalDeviceProperties
const vk::PhysicalDeviceProperties & GetPhysicalDeviceProperties() const
Definition: capabilities_vk.cc:721
impeller::CapabilitiesVK::SupportsExtendedRangeFormats
bool SupportsExtendedRangeFormats() const override
Whether the XR formats are supported on this device.
Definition: capabilities_vk.cc:831
impeller::CapabilitiesVK::SupportsImplicitResolvingMSAA
bool SupportsImplicitResolvingMSAA() const override
Whether the context backend supports multisampled rendering to the on-screen surface without requirin...
Definition: capabilities_vk.cc:660
impeller::CapabilitiesVK::GetEnabledDeviceFeatures
std::optional< PhysicalDeviceFeatures > GetEnabledDeviceFeatures(const vk::PhysicalDevice &physical_device) const
Definition: capabilities_vk.cc:399
formats.h
e1
Vector3 e1
Definition: line_contents.cc:107
impeller
Definition: allocation.cc:12
impeller::IterateExtensions
static bool IterateExtensions(const std::function< bool(T)> &it)
Definition: capabilities_vk.cc:235
impeller::GetSupportedDeviceExtensions
static std::optional< std::set< std::string > > GetSupportedDeviceExtensions(const vk::PhysicalDevice &physical_device)
Definition: capabilities_vk.cc:247
impeller::PhysicalDeviceSupportsRequiredFormats
static bool PhysicalDeviceSupportsRequiredFormats(const vk::PhysicalDevice &device)
Definition: capabilities_vk.cc:358
impeller::HasRequiredProperties
static bool HasRequiredProperties(const vk::PhysicalDevice &physical_device)
Definition: capabilities_vk.cc:368
impeller::IsExtensionInList
static bool IsExtensionInList(const std::vector< std::string > &list, ExtensionEnum ext)
Definition: capabilities_vk.cc:392
impeller::HasSuitableColorFormat
static bool HasSuitableColorFormat(const vk::PhysicalDevice &device, vk::Format format)
Definition: capabilities_vk.cc:343
impeller::RequiredAndroidDeviceExtensionVK
RequiredAndroidDeviceExtensionVK
A device extension available on all Android platforms. Without the presence of these extensions on An...
Definition: capabilities_vk.h:48
impeller::RequiredAndroidDeviceExtensionVK::kKHRExternalMemory
@ kKHRExternalMemory
impeller::RequiredAndroidDeviceExtensionVK::kKHRSamplerYcbcrConversion
@ kKHRSamplerYcbcrConversion
impeller::RequiredAndroidDeviceExtensionVK::kKHRDedicatedAllocation
@ kKHRDedicatedAllocation
impeller::RequiredAndroidDeviceExtensionVK::kLast
@ kLast
impeller::RequiredAndroidDeviceExtensionVK::kEXTQueueFamilyForeign
@ kEXTQueueFamilyForeign
impeller::RequiredAndroidDeviceExtensionVK::kANDROIDExternalMemoryAndroidHardwareBuffer
@ kANDROIDExternalMemoryAndroidHardwareBuffer
impeller::PixelFormat
PixelFormat
The Pixel formats supported by Impeller. The naming convention denotes the usage of the component,...
Definition: formats.h:99
impeller::PixelFormat::kD24UnormS8Uint
@ kD24UnormS8Uint
impeller::PixelFormat::kR8UNormInt
@ kR8UNormInt
impeller::PixelFormat::kUnknown
@ kUnknown
impeller::PixelFormat::kS8UInt
@ kS8UInt
impeller::PixelFormat::kD32FloatS8UInt
@ kD32FloatS8UInt
impeller::PixelFormat::kR8G8B8A8UNormInt
@ kR8G8B8A8UNormInt
impeller::HasSuitableDepthStencilFormat
static bool HasSuitableDepthStencilFormat(const vk::PhysicalDevice &device, vk::Format format)
Definition: capabilities_vk.cc:351
impeller::RequiredCommonDeviceExtensionVK
RequiredCommonDeviceExtensionVK
A device extension available on all platforms. Without the presence of these extensions,...
Definition: capabilities_vk.h:29
impeller::RequiredCommonDeviceExtensionVK::kKHRSwapchain
@ kKHRSwapchain
impeller::RequiredCommonDeviceExtensionVK::kLast
@ kLast
impeller::OptionalAndroidDeviceExtensionVK
OptionalAndroidDeviceExtensionVK
A device extension available on some Android platforms.
Definition: capabilities_vk.h:93
impeller::OptionalAndroidDeviceExtensionVK::kKHRExternalFenceFd
@ kKHRExternalFenceFd
impeller::OptionalAndroidDeviceExtensionVK::kKHRExternalSemaphore
@ kKHRExternalSemaphore
impeller::OptionalAndroidDeviceExtensionVK::kKHRExternalFence
@ kKHRExternalFence
impeller::OptionalAndroidDeviceExtensionVK::kKHRExternalSemaphoreFd
@ kKHRExternalSemaphoreFd
impeller::OptionalAndroidDeviceExtensionVK::kLast
@ kLast
impeller::GetExtensionName
static const char * GetExtensionName(RequiredCommonDeviceExtensionVK ext)
Definition: capabilities_vk.cc:176
impeller::kInstanceLayer
static constexpr const char * kInstanceLayer
Definition: capabilities_vk.cc:20
impeller::CompressionType
CompressionType
Additional compression to apply to a texture. This value is ignored on platforms which do not support...
Definition: texture_descriptor.h:19
impeller::CompressionType::kLossy
@ kLossy
impeller::OptionalDeviceExtensionVK
OptionalDeviceExtensionVK
A device extension enabled if available. Subsystems cannot assume availability and must check if thes...
Definition: capabilities_vk.h:131
impeller::OptionalDeviceExtensionVK::kEXTImageCompressionControl
@ kEXTImageCompressionControl
impeller::OptionalDeviceExtensionVK::kLast
@ kLast
impeller::OptionalDeviceExtensionVK::kVKKHRPortabilitySubset
@ kVKKHRPortabilitySubset
impeller::OptionalDeviceExtensionVK::kEXTPipelineCreationFeedback
@ kEXTPipelineCreationFeedback
impeller::HasRequiredQueues
static bool HasRequiredQueues(const vk::PhysicalDevice &physical_device)
Definition: capabilities_vk.cc:377
std
Definition: comparable.h:95
impeller::FRCFormatDescriptor
A pixel format and usage that is sufficient to check if images of that format and usage are suitable ...
Definition: capabilities_vk.h:162
impeller::FRCFormatDescriptor::tiling
vk::ImageTiling tiling
Definition: capabilities_vk.h:165
impeller::FRCFormatDescriptor::usage
vk::ImageUsageFlags usage
Definition: capabilities_vk.h:166
impeller::FRCFormatDescriptor::flags
vk::ImageCreateFlags flags
Definition: capabilities_vk.h:167
impeller::FRCFormatDescriptor::type
vk::ImageType type
Definition: capabilities_vk.h:164
impeller::FRCFormatDescriptor::format
vk::Format format
Definition: capabilities_vk.h:163
impeller::TSize
Definition: size.h:25
impeller::WorkaroundsVK
A non-exhaustive set of driver specific workarounds.
Definition: workarounds_vk.h:13
impeller::WorkaroundsVK::slow_primitive_restart_performance
bool slow_primitive_restart_performance
Definition: workarounds_vk.h:18
impeller::WorkaroundsVK::input_attachment_self_dependency_broken
bool input_attachment_self_dependency_broken
Definition: workarounds_vk.h:30
validation.h
VALIDATION_LOG
#define VALIDATION_LOG
Definition: validation.h:91
vk.h
workarounds_vk.h