| 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 exts = std::set(embedder_device_extensions_.begin(),
273 embedder_device_extensions_.end());
274 }
275
276 std::vector<std::string> enabled;
277
278 auto for_each_common_extension = [&](RequiredCommonDeviceExtensionVK ext) {
279 auto name = GetExtensionName(ext);
280 if (exts.find(name) == exts.end()) {
281 VALIDATION_LOG << "Device does not support required extension: " << name;
282 return false;
283 }
284 enabled.push_back(name);
285 return true;
286 };
287
288 auto for_each_android_extension = [&](RequiredAndroidDeviceExtensionVK ext) {
289 #ifdef FML_OS_ANDROID
290 auto name = GetExtensionName(ext);
291 if (exts.find(name) == exts.end()) {
292 VALIDATION_LOG << "Device does not support required Android extension: "
293 << name;
294 return false;
295 }
296 enabled.push_back(name);
297 #endif // FML_OS_ANDROID
298 return true;
299 };
300
301 auto for_each_optional_android_extension =
302 [&](OptionalAndroidDeviceExtensionVK ext) {
303 #ifdef FML_OS_ANDROID
304 auto name = GetExtensionName(ext);
305 if (exts.find(name) != exts.end()) {
306 enabled.push_back(name);
307 }
308 #endif // FML_OS_ANDROID
309 return true;
310 };
311
312 auto for_each_optional_extension = [&](OptionalDeviceExtensionVK ext) {
313 auto name = GetExtensionName(ext);
314 if (exts.find(name) != exts.end()) {
315 enabled.push_back(name);
316 }
317 return true;
318 };
319
320 const auto iterate_extensions =
321 IterateExtensions<RequiredCommonDeviceExtensionVK>(
322 for_each_common_extension) &&
323 IterateExtensions<RequiredAndroidDeviceExtensionVK>(
324 for_each_android_extension) &&
325 IterateExtensions<OptionalDeviceExtensionVK>(
326 for_each_optional_extension) &&
327 IterateExtensions<OptionalAndroidDeviceExtensionVK>(
328 for_each_optional_android_extension);
329
330 if (!iterate_extensions) {
331 VALIDATION_LOG << "Device not suitable since required extensions are not "
332 "supported.";
333 return std::nullopt;
334 }
335
336 return enabled;
337 }
338
339 static bool HasSuitableColorFormat(const vk::PhysicalDevice& device,
340 vk::Format format) {
341 const auto props = device.getFormatProperties(format);
342 // This needs to be more comprehensive.
343 return !!(props.optimalTilingFeatures &
344 vk::FormatFeatureFlagBits::eColorAttachment);
345 }
346
347 static bool HasSuitableDepthStencilFormat(const vk::PhysicalDevice& device,
348 vk::Format format) {
349 const auto props = device.getFormatProperties(format);
350 return !!(props.optimalTilingFeatures &
351 vk::FormatFeatureFlagBits::eDepthStencilAttachment);
352 }
353
354 static bool PhysicalDeviceSupportsRequiredFormats(
355 const vk::PhysicalDevice& device) {
356 const auto has_color_format =
357 HasSuitableColorFormat(device, vk::Format::eR8G8B8A8Unorm);
358 const auto has_stencil_format =
359 HasSuitableDepthStencilFormat(device, vk::Format::eD32SfloatS8Uint) ||
360 HasSuitableDepthStencilFormat(device, vk::Format::eD24UnormS8Uint);
361 return has_color_format && has_stencil_format;
362 }
363
364 static bool HasRequiredProperties(const vk::PhysicalDevice& physical_device) {
365 auto properties = physical_device.getProperties();
366 if (!(properties.limits.framebufferColorSampleCounts &
367 (vk::SampleCountFlagBits::e1 | vk::SampleCountFlagBits::e4))) {
368 return false;
369 }
370 return true;
371 }
372
373 static bool HasRequiredQueues(const vk::PhysicalDevice& physical_device) {
374 auto queue_flags = vk::QueueFlags{};
375 for (const auto& queue : physical_device.getQueueFamilyProperties()) {
376 if (queue.queueCount == 0) {
377 continue;
378 }
379 queue_flags |= queue.queueFlags;
380 }
381 return static_cast<VkQueueFlags>(queue_flags &
382 (vk::QueueFlagBits::eGraphics |
383 vk::QueueFlagBits::eCompute |
384 vk::QueueFlagBits::eTransfer));
385 }
386
387 template <class ExtensionEnum>
388 static bool IsExtensionInList(const std::vector<std::string>& list,
389 ExtensionEnum ext) {
390 const std::string name = GetExtensionName(ext);
391 return std::find(list.begin(), list.end(), name) != list.end();
392 }
393
394 std::optional<CapabilitiesVK::PhysicalDeviceFeatures>
395 CapabilitiesVK::GetEnabledDeviceFeatures(
396 const vk::PhysicalDevice& device) const {
397 if (!PhysicalDeviceSupportsRequiredFormats(device)) {
398 VALIDATION_LOG << "Device doesn't support the required formats.";
399 return std::nullopt;
400 }
401
402 if (!HasRequiredProperties(device)) {
403 VALIDATION_LOG << "Device doesn't support the required properties.";
404 return std::nullopt;
405 }
406
407 if (!HasRequiredQueues(device)) {
408 VALIDATION_LOG << "Device doesn't support the required queues.";
409 return std::nullopt;
410 }
411
412 const auto enabled_extensions = GetEnabledDeviceExtensions(device);
413 if (!enabled_extensions.has_value()) {
414 VALIDATION_LOG << "Device doesn't support the required queues.";
415 return std::nullopt;
416 }
417
418 PhysicalDeviceFeatures supported_chain;
419
420 // Swiftshader seems to be fussy about just this structure even being in the
421 // chain. Just unlink it if its not supported. We already perform an
422 // extensions check on the other side when reading.
423 if (!IsExtensionInList(
424 enabled_extensions.value(),
425 OptionalDeviceExtensionVK::kEXTImageCompressionControl)) {
426 supported_chain
427 .unlink<vk::PhysicalDeviceImageCompressionControlFeaturesEXT>();
428 }
429
430 device.getFeatures2(&supported_chain.get());
431
432 PhysicalDeviceFeatures required_chain;
433
434 // Base features.
435 {
436 auto& required = required_chain.get().features;
437 const auto& supported = supported_chain.get().features;
438
439 // We require this for enabling wireframes in the playground. But its not
440 // necessarily a big deal if we don't have this feature.
441 required.fillModeNonSolid = supported.fillModeNonSolid;
442 }
443 // VK_KHR_sampler_ycbcr_conversion features.
444 if (IsExtensionInList(
445 enabled_extensions.value(),
446 RequiredAndroidDeviceExtensionVK::kKHRSamplerYcbcrConversion)) {
447 auto& required =
448 required_chain
449 .get<vk::PhysicalDeviceSamplerYcbcrConversionFeaturesKHR>();
450 const auto& supported =
451 supported_chain
452 .get<vk::PhysicalDeviceSamplerYcbcrConversionFeaturesKHR>();
453
454 required.samplerYcbcrConversion = supported.samplerYcbcrConversion;
455 }
456
457 // VK_EXT_image_compression_control
458 if (IsExtensionInList(
459 enabled_extensions.value(),
460 OptionalDeviceExtensionVK::kEXTImageCompressionControl)) {
461 auto& required =
462 required_chain
463 .get<vk::PhysicalDeviceImageCompressionControlFeaturesEXT>();
464 const auto& supported =
465 supported_chain
466 .get<vk::PhysicalDeviceImageCompressionControlFeaturesEXT>();
467
468 required.imageCompressionControl = supported.imageCompressionControl;
469 } else {
470 required_chain
471 .unlink<vk::PhysicalDeviceImageCompressionControlFeaturesEXT>();
472 }
473
474 // Vulkan 1.1
475 {
476 auto& required =
477 required_chain.get<vk::PhysicalDevice16BitStorageFeatures>();
478 const auto& supported =
479 supported_chain.get<vk::PhysicalDevice16BitStorageFeatures>();
480
481 required.uniformAndStorageBuffer16BitAccess =
482 supported.uniformAndStorageBuffer16BitAccess;
483 }
484
485 return required_chain;
486 }
487
488 bool CapabilitiesVK::HasLayer(const std::string& layer) const {
489 for (const auto& [found_layer, exts] : exts_) {
490 if (found_layer == layer) {
491 return true;
492 }
493 }
494 return false;
495 }
496
497 bool CapabilitiesVK::HasExtension(const std::string& ext) const {
498 for (const auto& [layer, exts] : exts_) {
499 if (exts.find(ext) != exts.end()) {
500 return true;
501 }
502 }
503 return false;
504 }
505
506 bool CapabilitiesVK::SupportsPrimitiveRestart() const {
507 return has_primitive_restart_;
508 }
509
510 void CapabilitiesVK::SetOffscreenFormat(PixelFormat pixel_format) const {
511 default_color_format_ = pixel_format;
512 }
513
514 bool CapabilitiesVK::SetPhysicalDevice(
515 const vk::PhysicalDevice& device,
516 const PhysicalDeviceFeatures& enabled_features) {
517 if (HasSuitableColorFormat(device, vk::Format::eR8G8B8A8Unorm)) {
518 default_color_format_ = PixelFormat::kR8G8B8A8UNormInt;
519 } else {
520 default_color_format_ = PixelFormat::kUnknown;
521 }
522
523 if (HasSuitableDepthStencilFormat(device, vk::Format::eD32SfloatS8Uint)) {
524 default_depth_stencil_format_ = PixelFormat::kD32FloatS8UInt;
525 } else if (HasSuitableDepthStencilFormat(device,
526 vk::Format::eD24UnormS8Uint)) {
527 default_depth_stencil_format_ = PixelFormat::kD24UnormS8Uint;
528 } else {
529 default_depth_stencil_format_ = PixelFormat::kUnknown;
530 }
531
532 if (HasSuitableDepthStencilFormat(device, vk::Format::eS8Uint)) {
533 default_stencil_format_ = PixelFormat::kS8UInt;
534 } else if (default_depth_stencil_format_ != PixelFormat::kUnknown) {
535 default_stencil_format_ = default_depth_stencil_format_;
536 }
537
538 physical_device_ = device;
539 device_properties_ = device.getProperties();
540
541 auto physical_properties_2 =
542 device.getProperties2<vk::PhysicalDeviceProperties2,
543 vk::PhysicalDeviceSubgroupProperties>();
544
545 // Currently shaders only want access to arithmetic subgroup features.
546 // If that changes this needs to get updated, and so does Metal (which right
547 // now assumes it from compile time flags based on the MSL target version).
548
549 supports_compute_subgroups_ =
550 !!(physical_properties_2.get<vk::PhysicalDeviceSubgroupProperties>()
551 .supportedOperations &
552 vk::SubgroupFeatureFlagBits::eArithmetic);
553
554 {
555 // Query texture support.
556 // TODO(129784): Add a capability check for expected memory types.
557 vk::PhysicalDeviceMemoryProperties memory_properties;
558 device.getMemoryProperties(&memory_properties);
559
560 for (auto i = 0u; i < memory_properties.memoryTypeCount; i++) {
561 if (memory_properties.memoryTypes[i].propertyFlags &
562 vk::MemoryPropertyFlagBits::eLazilyAllocated) {
563 supports_device_transient_textures_ = true;
564 }
565 }
566 }
567
568 // Determine the optional device extensions this physical device supports.
569 {
570 required_common_device_extensions_.clear();
571 required_android_device_extensions_.clear();
572 optional_device_extensions_.clear();
573 optional_android_device_extensions_.clear();
574
575 std::set<std::string> exts;
576 if (!use_embedder_extensions_) {
577 auto maybe_exts = GetSupportedDeviceExtensions(device);
578 if (!maybe_exts.has_value()) {
579 return false;
580 }
581 exts = maybe_exts.value();
582 } else {
583 exts = std::set(embedder_device_extensions_.begin(),
584 embedder_device_extensions_.end());
585 }
586
587 IterateExtensions<RequiredCommonDeviceExtensionVK>([&](auto ext) -> bool {
588 auto ext_name = GetExtensionName(ext);
589 if (exts.find(ext_name) != exts.end()) {
590 required_common_device_extensions_.insert(ext);
591 }
592 return true;
593 });
594 IterateExtensions<RequiredAndroidDeviceExtensionVK>([&](auto ext) -> bool {
595 auto ext_name = GetExtensionName(ext);
596 if (exts.find(ext_name) != exts.end()) {
597 required_android_device_extensions_.insert(ext);
598 }
599 return true;
600 });
601 IterateExtensions<OptionalDeviceExtensionVK>([&](auto ext) -> bool {
602 auto ext_name = GetExtensionName(ext);
603 if (exts.find(ext_name) != exts.end()) {
604 optional_device_extensions_.insert(ext);
605 }
606 return true;
607 });
608 IterateExtensions<OptionalAndroidDeviceExtensionVK>(
609 [&](OptionalAndroidDeviceExtensionVK ext) {
610 auto name = GetExtensionName(ext);
611 if (exts.find(name) != exts.end()) {
612 optional_android_device_extensions_.insert(ext);
613 }
614 return true;
615 });
616 }
617
618 supports_texture_fixed_rate_compression_ =
619 enabled_features
620 .isLinked<vk::PhysicalDeviceImageCompressionControlFeaturesEXT>() &&
621 enabled_features
622 .get<vk::PhysicalDeviceImageCompressionControlFeaturesEXT>()
623 .imageCompressionControl;
624
625 max_render_pass_attachment_size_ =
626 ISize{device_properties_.limits.maxFramebufferWidth,
627 device_properties_.limits.maxFramebufferHeight};
628
629 // Molten, Vulkan on Metal, cannot support triangle fans because Metal doesn't
630 // support triangle fans.
631 // See VUID-VkPipelineInputAssemblyStateCreateInfo-triangleFans-04452.
632 has_triangle_fans_ =
633 !HasExtension(OptionalDeviceExtensionVK::kVKKHRPortabilitySubset);
634
635 // External Fence/Semaphore for AHB swapchain
636 if (HasExtension(OptionalAndroidDeviceExtensionVK::kKHRExternalFenceFd) &&
637 HasExtension(OptionalAndroidDeviceExtensionVK::kKHRExternalFence) &&
638 HasExtension(OptionalAndroidDeviceExtensionVK::kKHRExternalSemaphore) &&
639 HasExtension(OptionalAndroidDeviceExtensionVK::kKHRExternalSemaphoreFd)) {
640 supports_external_fence_and_semaphore_ = true;
641 }
642
643 return true;
644 }
645
646 // |Capabilities|
647 bool CapabilitiesVK::SupportsOffscreenMSAA() const {
648 return true;
649 }
650
651 // |Capabilities|
652 bool CapabilitiesVK::SupportsImplicitResolvingMSAA() const {
653 return false;
654 }
655
656 // |Capabilities|
657 bool CapabilitiesVK::SupportsSSBO() const {
658 return true;
659 }
660
661 // |Capabilities|
662 bool CapabilitiesVK::SupportsTextureToTextureBlits() const {
663 return true;
664 }
665
666 // |Capabilities|
667 bool CapabilitiesVK::SupportsFramebufferFetch() const {
668 return has_framebuffer_fetch_;
669 }
670
671 // |Capabilities|
672 bool CapabilitiesVK::SupportsCompute() const {
673 // Vulkan 1.1 requires support for compute.
674 return true;
675 }
676
677 // |Capabilities|
678 bool CapabilitiesVK::SupportsComputeSubgroups() const {
679 // Set by |SetPhysicalDevice|.
680 return supports_compute_subgroups_;
681 }
682
683 // |Capabilities|
684 bool CapabilitiesVK::SupportsReadFromResolve() const {
685 return false;
686 }
687
688 bool CapabilitiesVK::SupportsDecalSamplerAddressMode() const {
689 return true;
690 }
691
692 // |Capabilities|
693 bool CapabilitiesVK::SupportsDeviceTransientTextures() const {
694 return supports_device_transient_textures_;
695 }
696
697 // |Capabilities|
698 PixelFormat CapabilitiesVK::GetDefaultColorFormat() const {
699 return default_color_format_;
700 }
701
702 // |Capabilities|
703 PixelFormat CapabilitiesVK::GetDefaultStencilFormat() const {
704 return default_stencil_format_;
705 }
706
707 // |Capabilities|
708 PixelFormat CapabilitiesVK::GetDefaultDepthStencilFormat() const {
709 return default_depth_stencil_format_;
710 }
711
712 const vk::PhysicalDeviceProperties&
713 CapabilitiesVK::GetPhysicalDeviceProperties() const {
714 return device_properties_;
715 }
716
717 PixelFormat CapabilitiesVK::GetDefaultGlyphAtlasFormat() const {
718 return PixelFormat::kR8UNormInt;
719 }
720
721 bool CapabilitiesVK::HasExtension(RequiredCommonDeviceExtensionVK ext) const {
722 return required_common_device_extensions_.find(ext) !=
723 required_common_device_extensions_.end();
724 }
725
726 bool CapabilitiesVK::HasExtension(RequiredAndroidDeviceExtensionVK ext) const {
727 return required_android_device_extensions_.find(ext) !=
728 required_android_device_extensions_.end();
729 }
730
731 bool CapabilitiesVK::HasExtension(OptionalDeviceExtensionVK ext) const {
732 return optional_device_extensions_.find(ext) !=
733 optional_device_extensions_.end();
734 }
735
736 bool CapabilitiesVK::HasExtension(OptionalAndroidDeviceExtensionVK ext) const {
737 return optional_android_device_extensions_.find(ext) !=
738 optional_android_device_extensions_.end();
739 }
740
741 bool CapabilitiesVK::SupportsTextureFixedRateCompression() const {
742 return supports_texture_fixed_rate_compression_;
743 }
744
745 std::optional<vk::ImageCompressionFixedRateFlagBitsEXT>
746 CapabilitiesVK::GetSupportedFRCRate(CompressionType compression_type,
747 const FRCFormatDescriptor& desc) const {
748 if (compression_type != CompressionType::kLossy) {
749 return std::nullopt;
750 }
751 if (!supports_texture_fixed_rate_compression_) {
752 return std::nullopt;
753 }
754 // There are opportunities to hash and cache the FRCFormatDescriptor if
755 // needed.
756 vk::StructureChain<vk::PhysicalDeviceImageFormatInfo2,
757 vk::ImageCompressionControlEXT>
758 format_chain;
759
760 auto& format_info = format_chain.get();
761
762 format_info.format = desc.format;
763 format_info.type = desc.type;
764 format_info.tiling = desc.tiling;
765 format_info.usage = desc.usage;
766 format_info.flags = desc.flags;
767
768 const auto kIdealFRCRate = vk::ImageCompressionFixedRateFlagBitsEXT::e4Bpc;
769
770 std::array<vk::ImageCompressionFixedRateFlagsEXT, 1u> rates = {kIdealFRCRate};
771
772 auto& compression = format_chain.get<vk::ImageCompressionControlEXT>();
773 compression.flags = vk::ImageCompressionFlagBitsEXT::eFixedRateExplicit;
774 compression.compressionControlPlaneCount = rates.size();
775 compression.pFixedRateFlags = rates.data();
776
777 const auto [result, supported] = physical_device_.getImageFormatProperties2<
778 vk::ImageFormatProperties2, vk::ImageCompressionPropertiesEXT>(
779 format_chain.get());
780
781 if (result != vk::Result::eSuccess ||
782 !supported.isLinked<vk::ImageCompressionPropertiesEXT>()) {
783 return std::nullopt;
784 }
785
786 const auto& compression_props =
787 supported.get<vk::ImageCompressionPropertiesEXT>();
788
789 if ((compression_props.imageCompressionFlags &
790 vk::ImageCompressionFlagBitsEXT::eFixedRateExplicit) &&
791 (compression_props.imageCompressionFixedRateFlags & kIdealFRCRate)) {
792 return kIdealFRCRate;
793 }
794
795 return std::nullopt;
796 }
797
798 bool CapabilitiesVK::SupportsTriangleFan() const {
799 return has_triangle_fans_;
800 }
801
802 ISize CapabilitiesVK::GetMaximumRenderPassAttachmentSize() const {
803 return max_render_pass_attachment_size_;
804 }
805
806 void CapabilitiesVK::ApplyWorkarounds(const WorkaroundsVK& workarounds) {
807 has_primitive_restart_ = !workarounds.slow_primitive_restart_performance;
808 has_framebuffer_fetch_ = !workarounds.input_attachment_self_dependency_broken;
809 }
810
811 bool CapabilitiesVK::SupportsExternalSemaphoreExtensions() const {
812 return supports_external_fence_and_semaphore_;
813 }
814
815 bool CapabilitiesVK::SupportsExtendedRangeFormats() const {
816 return false;
817 }
818
819 } // 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:798
impeller::CapabilitiesVK::SupportsDeviceTransientTextures
bool SupportsDeviceTransientTextures() const override
Whether the context backend supports allocating StorageMode::kDeviceTransient (aka "memoryless") text...
Definition: capabilities_vk.cc:693
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:514
impeller::CapabilitiesVK::GetMaximumRenderPassAttachmentSize
ISize GetMaximumRenderPassAttachmentSize() const override
Return the maximum size of a render pass attachment.
Definition: capabilities_vk.cc:802
impeller::CapabilitiesVK::SupportsSSBO
bool SupportsSSBO() const override
Whether the context backend supports binding Shader Storage Buffer Objects (SSBOs) to pipelines.
Definition: capabilities_vk.cc:657
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:667
impeller::CapabilitiesVK::SupportsExternalSemaphoreExtensions
bool SupportsExternalSemaphoreExtensions() const
Definition: capabilities_vk.cc:811
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:647
impeller::CapabilitiesVK::SupportsCompute
bool SupportsCompute() const override
Whether the context backend supports ComputePass.
Definition: capabilities_vk.cc:672
impeller::CapabilitiesVK::HasExtension
bool HasExtension(RequiredCommonDeviceExtensionVK ext) const
Definition: capabilities_vk.cc:721
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:746
impeller::CapabilitiesVK::SetOffscreenFormat
void SetOffscreenFormat(PixelFormat pixel_format) const
Definition: capabilities_vk.cc:510
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:703
impeller::CapabilitiesVK::ApplyWorkarounds
void ApplyWorkarounds(const WorkaroundsVK &workarounds)
Update capabilities for the given set of workarounds.
Definition: capabilities_vk.cc:806
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:678
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:708
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:662
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:684
impeller::CapabilitiesVK::SupportsDecalSamplerAddressMode
bool SupportsDecalSamplerAddressMode() const override
Whether the context backend supports SamplerAddressMode::Decal.
Definition: capabilities_vk.cc:688
impeller::CapabilitiesVK::SupportsPrimitiveRestart
bool SupportsPrimitiveRestart() const override
Whether primitive restart is supported.
Definition: capabilities_vk.cc:506
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:741
impeller::CapabilitiesVK::GetDefaultGlyphAtlasFormat
PixelFormat GetDefaultGlyphAtlasFormat() const override
Returns the default pixel format for the alpha bitmap glyph atlas.
Definition: capabilities_vk.cc:717
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:698
impeller::CapabilitiesVK::GetPhysicalDeviceProperties
const vk::PhysicalDeviceProperties & GetPhysicalDeviceProperties() const
Definition: capabilities_vk.cc:713
impeller::CapabilitiesVK::SupportsExtendedRangeFormats
bool SupportsExtendedRangeFormats() const override
Whether the XR formats are supported on this device.
Definition: capabilities_vk.cc:815
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:652
impeller::CapabilitiesVK::GetEnabledDeviceFeatures
std::optional< PhysicalDeviceFeatures > GetEnabledDeviceFeatures(const vk::PhysicalDevice &physical_device) const
Definition: capabilities_vk.cc:395
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:354
impeller::HasRequiredProperties
static bool HasRequiredProperties(const vk::PhysicalDevice &physical_device)
Definition: capabilities_vk.cc:364
impeller::IsExtensionInList
static bool IsExtensionInList(const std::vector< std::string > &list, ExtensionEnum ext)
Definition: capabilities_vk.cc:388
impeller::HasSuitableColorFormat
static bool HasSuitableColorFormat(const vk::PhysicalDevice &device, vk::Format format)
Definition: capabilities_vk.cc:339
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:347
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:373
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