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