Flutter Engine
The Flutter Engine
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
6
7#include <algorithm>
8
12
13namespace impeller {
14
15static constexpr const char* kInstanceLayer = "ImpellerInstance";
16
17CapabilitiesVK::CapabilitiesVK(bool enable_validations,
18 bool fatal_missing_validations) {
19 auto extensions = vk::enumerateInstanceExtensionProperties();
20 auto layers = vk::enumerateInstanceLayerProperties();
21
22 if (extensions.result != vk::Result::eSuccess ||
23 layers.result != vk::Result::eSuccess) {
24 return;
25 }
26
27 for (const auto& ext : extensions.value) {
28 exts_[kInstanceLayer].insert(ext.extensionName);
29 }
30
31 for (const auto& layer : layers.value) {
32 const std::string layer_name = layer.layerName;
33 auto layer_exts = vk::enumerateInstanceExtensionProperties(layer_name);
34 if (layer_exts.result != vk::Result::eSuccess) {
35 return;
36 }
37 for (const auto& layer_ext : layer_exts.value) {
38 exts_[layer_name].insert(layer_ext.extensionName);
39 }
40 }
41
42 validations_enabled_ =
43 enable_validations && HasLayer("VK_LAYER_KHRONOS_validation");
44 if (enable_validations && !validations_enabled_) {
46 << "Requested Impeller context creation with validations but the "
47 "validation layers could not be found. Expect no Vulkan validation "
48 "checks!";
49 if (fatal_missing_validations) {
50 FML_LOG(FATAL) << "Validation missing. Exiting.";
51 }
52 }
53 if (validations_enabled_) {
54 FML_LOG(INFO) << "Vulkan validations are enabled.";
55 }
56 is_valid_ = true;
57}
58
60
62 return is_valid_;
63}
64
66 return validations_enabled_;
67}
68
69std::optional<std::vector<std::string>> CapabilitiesVK::GetEnabledLayers()
70 const {
71 std::vector<std::string> required;
72
73 if (validations_enabled_) {
74 // The presence of this layer is already checked in the ctor.
75 required.push_back("VK_LAYER_KHRONOS_validation");
76 }
77
78 return required;
79}
80
81std::optional<std::vector<std::string>>
83 std::vector<std::string> required;
84
85 if (!HasExtension("VK_KHR_surface")) {
86 // Swapchain support is required and this is a dependency of
87 // VK_KHR_swapchain.
88 VALIDATION_LOG << "Could not find the surface extension.";
89 return std::nullopt;
90 }
91 required.push_back("VK_KHR_surface");
92
93 auto has_wsi = false;
94 if (HasExtension("VK_MVK_macos_surface")) {
95 required.push_back("VK_MVK_macos_surface");
96 has_wsi = true;
97 }
98
99 if (HasExtension("VK_EXT_metal_surface")) {
100 required.push_back("VK_EXT_metal_surface");
101 has_wsi = true;
102 }
103
104 if (HasExtension("VK_KHR_portability_enumeration")) {
105 required.push_back("VK_KHR_portability_enumeration");
106 has_wsi = true;
107 }
108
109 if (HasExtension("VK_KHR_win32_surface")) {
110 required.push_back("VK_KHR_win32_surface");
111 has_wsi = true;
112 }
113
114 if (HasExtension("VK_KHR_android_surface")) {
115 required.push_back("VK_KHR_android_surface");
116 has_wsi = true;
117 }
118
119 if (HasExtension("VK_KHR_xcb_surface")) {
120 required.push_back("VK_KHR_xcb_surface");
121 has_wsi = true;
122 }
123
124 if (HasExtension("VK_KHR_xlib_surface")) {
125 required.push_back("VK_KHR_xlib_surface");
126 has_wsi = true;
127 }
128
129 if (HasExtension("VK_KHR_wayland_surface")) {
130 required.push_back("VK_KHR_wayland_surface");
131 has_wsi = true;
132 }
133
134 if (!has_wsi) {
135 // Don't really care which WSI extension there is as long there is at least
136 // one.
137 VALIDATION_LOG << "Could not find a WSI extension.";
138 return std::nullopt;
139 }
140
141 if (validations_enabled_) {
142 if (!HasExtension("VK_EXT_debug_utils")) {
143 VALIDATION_LOG << "Requested validations but could not find the "
144 "VK_EXT_debug_utils extension.";
145 return std::nullopt;
146 }
147 required.push_back("VK_EXT_debug_utils");
148
149 if (HasExtension("VK_EXT_validation_features")) {
150 // It's valid to not have `VK_EXT_validation_features` available. That's
151 // the case when using AGI as a frame debugger.
152 required.push_back("VK_EXT_validation_features");
153 }
154 }
155
156 return required;
157}
158
160 switch (ext) {
164 return "Unknown";
165 }
167}
168
170 switch (ext) {
173 return "VK_ANDROID_external_memory_android_hardware_buffer";
191 return "Unknown";
192 }
194}
195
197 switch (ext) {
201 return "VK_KHR_portability_subset";
203 return "Unknown";
204 }
206}
207
208template <class T>
209static bool IterateExtensions(const std::function<bool(T)>& it) {
210 if (!it) {
211 return false;
212 }
213 for (size_t i = 0; i < static_cast<uint32_t>(T::kLast); i++) {
214 if (!it(static_cast<T>(i))) {
215 return false;
216 }
217 }
218 return true;
219}
220
221static std::optional<std::set<std::string>> GetSupportedDeviceExtensions(
222 const vk::PhysicalDevice& physical_device) {
223 auto device_extensions = physical_device.enumerateDeviceExtensionProperties();
224 if (device_extensions.result != vk::Result::eSuccess) {
225 return std::nullopt;
226 }
227
228 std::set<std::string> exts;
229 for (const auto& device_extension : device_extensions.value) {
230 exts.insert(device_extension.extensionName);
231 };
232
233 return exts;
234}
235
236std::optional<std::vector<std::string>>
238 const vk::PhysicalDevice& physical_device) const {
240
241 if (!exts.has_value()) {
242 return std::nullopt;
243 }
244
245 std::vector<std::string> enabled;
246
247 auto for_each_common_extension = [&](RequiredCommonDeviceExtensionVK ext) {
248 auto name = GetExtensionName(ext);
249 if (exts->find(name) == exts->end()) {
250 VALIDATION_LOG << "Device does not support required extension: " << name;
251 return false;
252 }
253 enabled.push_back(name);
254 return true;
255 };
256
257 auto for_each_android_extension = [&](RequiredAndroidDeviceExtensionVK ext) {
258#ifdef FML_OS_ANDROID
259 auto name = GetExtensionName(ext);
260 if (exts->find(name) == exts->end()) {
261 VALIDATION_LOG << "Device does not support required Android extension: "
262 << name;
263 return false;
264 }
265 enabled.push_back(name);
266#endif // FML_OS_ANDROID
267 return true;
268 };
269
270 auto for_each_optional_extension = [&](OptionalDeviceExtensionVK ext) {
271 auto name = GetExtensionName(ext);
272 if (exts->find(name) != exts->end()) {
273 enabled.push_back(name);
274 }
275 return true;
276 };
277
278 const auto iterate_extensions =
279 IterateExtensions<RequiredCommonDeviceExtensionVK>(
280 for_each_common_extension) &&
281 IterateExtensions<RequiredAndroidDeviceExtensionVK>(
282 for_each_android_extension) &&
283 IterateExtensions<OptionalDeviceExtensionVK>(for_each_optional_extension);
284
285 if (!iterate_extensions) {
286 VALIDATION_LOG << "Device not suitable since required extensions are not "
287 "supported.";
288 return std::nullopt;
289 }
290
291 return enabled;
292}
293
294static bool HasSuitableColorFormat(const vk::PhysicalDevice& device,
296 const auto props = device.getFormatProperties(format);
297 // This needs to be more comprehensive.
298 return !!(props.optimalTilingFeatures &
299 vk::FormatFeatureFlagBits::eColorAttachment);
300}
301
302static bool HasSuitableDepthStencilFormat(const vk::PhysicalDevice& device,
304 const auto props = device.getFormatProperties(format);
305 return !!(props.optimalTilingFeatures &
306 vk::FormatFeatureFlagBits::eDepthStencilAttachment);
307}
308
310 const vk::PhysicalDevice& device) {
311 const auto has_color_format =
312 HasSuitableColorFormat(device, vk::Format::eR8G8B8A8Unorm);
313 const auto has_stencil_format =
314 HasSuitableDepthStencilFormat(device, vk::Format::eD32SfloatS8Uint) ||
315 HasSuitableDepthStencilFormat(device, vk::Format::eD24UnormS8Uint);
316 return has_color_format && has_stencil_format;
317}
318
319static bool HasRequiredProperties(const vk::PhysicalDevice& physical_device) {
320 auto properties = physical_device.getProperties();
321 if (!(properties.limits.framebufferColorSampleCounts &
322 (vk::SampleCountFlagBits::e1 | vk::SampleCountFlagBits::e4))) {
323 return false;
324 }
325 return true;
326}
327
328static bool HasRequiredQueues(const vk::PhysicalDevice& physical_device) {
329 auto queue_flags = vk::QueueFlags{};
330 for (const auto& queue : physical_device.getQueueFamilyProperties()) {
331 if (queue.queueCount == 0) {
332 continue;
333 }
334 queue_flags |= queue.queueFlags;
335 }
336 return static_cast<VkQueueFlags>(queue_flags &
337 (vk::QueueFlagBits::eGraphics |
338 vk::QueueFlagBits::eCompute |
339 vk::QueueFlagBits::eTransfer));
340}
341
342template <class ExtensionEnum>
343static bool IsExtensionInList(const std::vector<std::string>& list,
344 ExtensionEnum ext) {
345 const std::string name = GetExtensionName(ext);
346 return std::find(list.begin(), list.end(), name) != list.end();
347}
348
349std::optional<CapabilitiesVK::PhysicalDeviceFeatures>
351 const vk::PhysicalDevice& device) const {
353 VALIDATION_LOG << "Device doesn't support the required formats.";
354 return std::nullopt;
355 }
356
358 VALIDATION_LOG << "Device doesn't support the required properties.";
359 return std::nullopt;
360 }
361
363 VALIDATION_LOG << "Device doesn't support the required queues.";
364 return std::nullopt;
365 }
366
367 const auto enabled_extensions = GetEnabledDeviceExtensions(device);
368 if (!enabled_extensions.has_value()) {
369 VALIDATION_LOG << "Device doesn't support the required queues.";
370 return std::nullopt;
371 }
372
373 PhysicalDeviceFeatures supported_chain;
374 device.getFeatures2(&supported_chain.get());
375
376 PhysicalDeviceFeatures required_chain;
377
378 // Base features.
379 {
380 auto& required = required_chain.get().features;
381 const auto& supported = supported_chain.get().features;
382
383 // We require this for enabling wireframes in the playground. But its not
384 // necessarily a big deal if we don't have this feature.
385 required.fillModeNonSolid = supported.fillModeNonSolid;
386 }
387 // VK_KHR_sampler_ycbcr_conversion features.
389 enabled_extensions.value(),
391 auto& required =
392 required_chain
393 .get<vk::PhysicalDeviceSamplerYcbcrConversionFeaturesKHR>();
394 const auto& supported =
395 supported_chain
396 .get<vk::PhysicalDeviceSamplerYcbcrConversionFeaturesKHR>();
397
398 required.samplerYcbcrConversion = supported.samplerYcbcrConversion;
399 }
400
401 // Vulkan 1.1
402 {
403 auto& required =
404 required_chain.get<vk::PhysicalDevice16BitStorageFeatures>();
405 const auto& supported =
406 supported_chain.get<vk::PhysicalDevice16BitStorageFeatures>();
407
408 required.uniformAndStorageBuffer16BitAccess =
409 supported.uniformAndStorageBuffer16BitAccess;
410 }
411
412 return required_chain;
413}
414
415bool CapabilitiesVK::HasLayer(const std::string& layer) const {
416 for (const auto& [found_layer, exts] : exts_) {
417 if (found_layer == layer) {
418 return true;
419 }
420 }
421 return false;
422}
423
424bool CapabilitiesVK::HasExtension(const std::string& ext) const {
425 for (const auto& [layer, exts] : exts_) {
426 if (exts.find(ext) != exts.end()) {
427 return true;
428 }
429 }
430 return false;
431}
432
434 default_color_format_ = pixel_format;
435}
436
437bool CapabilitiesVK::SetPhysicalDevice(const vk::PhysicalDevice& device) {
438 if (HasSuitableColorFormat(device, vk::Format::eR8G8B8A8Unorm)) {
439 default_color_format_ = PixelFormat::kR8G8B8A8UNormInt;
440 } else {
441 default_color_format_ = PixelFormat::kUnknown;
442 }
443
444 if (HasSuitableDepthStencilFormat(device, vk::Format::eD32SfloatS8Uint)) {
445 default_depth_stencil_format_ = PixelFormat::kD32FloatS8UInt;
447 vk::Format::eD24UnormS8Uint)) {
448 default_depth_stencil_format_ = PixelFormat::kD24UnormS8Uint;
449 } else {
450 default_depth_stencil_format_ = PixelFormat::kUnknown;
451 }
452
453 if (HasSuitableDepthStencilFormat(device, vk::Format::eS8Uint)) {
454 default_stencil_format_ = PixelFormat::kS8UInt;
455 } else if (default_depth_stencil_format_ != PixelFormat::kUnknown) {
456 default_stencil_format_ = default_depth_stencil_format_;
457 }
458
459 device_properties_ = device.getProperties();
460
461 auto physical_properties_2 =
462 device.getProperties2<vk::PhysicalDeviceProperties2,
463 vk::PhysicalDeviceSubgroupProperties>();
464
465 // Currently shaders only want access to arithmetic subgroup features.
466 // If that changes this needs to get updated, and so does Metal (which right
467 // now assumes it from compile time flags based on the MSL target version).
468
469 supports_compute_subgroups_ =
470 !!(physical_properties_2.get<vk::PhysicalDeviceSubgroupProperties>()
471 .supportedOperations &
472 vk::SubgroupFeatureFlagBits::eArithmetic);
473
474 {
475 // Query texture support.
476 // TODO(jonahwilliams):
477 // https://github.com/flutter/flutter/issues/129784
478 vk::PhysicalDeviceMemoryProperties memory_properties;
479 device.getMemoryProperties(&memory_properties);
480
481 for (auto i = 0u; i < memory_properties.memoryTypeCount; i++) {
482 if (memory_properties.memoryTypes[i].propertyFlags &
483 vk::MemoryPropertyFlagBits::eLazilyAllocated) {
484 supports_device_transient_textures_ = true;
485 }
486 }
487 }
488
489 // Determine the optional device extensions this physical device supports.
490 {
491 required_common_device_extensions_.clear();
492 required_android_device_extensions_.clear();
493 optional_device_extensions_.clear();
495 if (!exts.has_value()) {
496 return false;
497 }
498 IterateExtensions<RequiredCommonDeviceExtensionVK>([&](auto ext) -> bool {
499 auto ext_name = GetExtensionName(ext);
500 if (exts->find(ext_name) != exts->end()) {
501 required_common_device_extensions_.insert(ext);
502 }
503 return true;
504 });
505 IterateExtensions<RequiredAndroidDeviceExtensionVK>([&](auto ext) -> bool {
506 auto ext_name = GetExtensionName(ext);
507 if (exts->find(ext_name) != exts->end()) {
508 required_android_device_extensions_.insert(ext);
509 }
510 return true;
511 });
512 IterateExtensions<OptionalDeviceExtensionVK>([&](auto ext) -> bool {
513 auto ext_name = GetExtensionName(ext);
514 if (exts->find(ext_name) != exts->end()) {
515 optional_device_extensions_.insert(ext);
516 }
517 return true;
518 });
519 }
520
521 return true;
522}
523
524// |Capabilities|
526 return true;
527}
528
529// |Capabilities|
531 return false;
532}
533
534// |Capabilities|
536 return true;
537}
538
539// |Capabilities|
541 return true;
542}
543
544// |Capabilities|
546 return true;
547}
548
549// |Capabilities|
551 // Vulkan 1.1 requires support for compute.
552 return true;
553}
554
555// |Capabilities|
557 // Set by |SetPhysicalDevice|.
558 return supports_compute_subgroups_;
559}
560
561// |Capabilities|
563 return false;
564}
565
567 return true;
568}
569
570// |Capabilities|
572 return supports_device_transient_textures_;
573}
574
575// |Capabilities|
577 return default_color_format_;
578}
579
580// |Capabilities|
582 return default_stencil_format_;
583}
584
585// |Capabilities|
587 return default_depth_stencil_format_;
588}
589
590const vk::PhysicalDeviceProperties&
592 return device_properties_;
593}
594
597}
598
600 return required_common_device_extensions_.find(ext) !=
601 required_common_device_extensions_.end();
602}
603
605 return required_android_device_extensions_.find(ext) !=
606 required_android_device_extensions_.end();
607}
608
610 return optional_device_extensions_.find(ext) !=
611 optional_device_extensions_.end();
612}
613
614} // namespace impeller
float e1
int find(T *array, int N, T item)
bool SupportsDeviceTransientTextures() const override
Whether the context backend supports allocating StorageMode::kDeviceTransient (aka "memoryless") text...
std::optional< std::vector< std::string > > GetEnabledInstanceExtensions() const
bool AreValidationsEnabled() const
bool SupportsSSBO() const override
Whether the context backend supports binding Shader Storage Buffer Objects (SSBOs) to pipelines.
bool SupportsFramebufferFetch() const override
Whether the context backend is able to support pipelines with shaders that read from the framebuffer ...
CapabilitiesVK(bool enable_validations, bool fatal_missing_validations=false)
vk::StructureChain< vk::PhysicalDeviceFeatures2, vk::PhysicalDeviceSamplerYcbcrConversionFeaturesKHR, vk::PhysicalDevice16BitStorageFeatures > PhysicalDeviceFeatures
bool SupportsOffscreenMSAA() const override
Whether the context backend supports attaching offscreen MSAA color/stencil textures.
bool SupportsCompute() const override
Whether the context backend supports ComputePass.
bool HasExtension(RequiredCommonDeviceExtensionVK ext) const
void SetOffscreenFormat(PixelFormat pixel_format) const
PixelFormat GetDefaultStencilFormat() const override
Returns a supported PixelFormat for textures that store stencil information. May include a depth chan...
bool SetPhysicalDevice(const vk::PhysicalDevice &physical_device)
bool SupportsComputeSubgroups() const override
Whether the context backend supports configuring ComputePass command subgroups.
PixelFormat GetDefaultDepthStencilFormat() const override
Returns a supported PixelFormat for textures that store both a stencil and depth component....
bool SupportsTextureToTextureBlits() const override
Whether the context backend supports blitting from one texture region to another texture region (via ...
std::optional< std::vector< std::string > > GetEnabledDeviceExtensions(const vk::PhysicalDevice &physical_device) const
bool SupportsReadFromResolve() const override
Whether the context backend supports binding the current RenderPass attachments. This is supported if...
bool SupportsDecalSamplerAddressMode() const override
Whether the context backend supports SamplerAddressMode::Decal.
std::optional< std::vector< std::string > > GetEnabledLayers() const
PixelFormat GetDefaultGlyphAtlasFormat() const override
Returns the default pixel format for the alpha bitmap glyph atlas.
PixelFormat GetDefaultColorFormat() const override
Returns a supported PixelFormat for textures that store 4-channel colors (red/green/blue/alpha).
const vk::PhysicalDeviceProperties & GetPhysicalDeviceProperties() const
bool SupportsImplicitResolvingMSAA() const override
Whether the context backend supports multisampled rendering to the on-screen surface without requirin...
std::optional< PhysicalDeviceFeatures > GetEnabledDeviceFeatures(const vk::PhysicalDevice &physical_device) const
VkPhysicalDevice physical_device
Definition: main.cc:51
VkDevice device
Definition: main.cc:53
VkQueue queue
Definition: main.cc:55
#define FATAL(error)
uint32_t uint32_t * format
#define FML_LOG(severity)
Definition: logging.h:82
#define FML_UNREACHABLE()
Definition: logging.h:109
Dart_NativeFunction function
Definition: fuchsia.cc:51
DEF_SWITCHES_START aot vmservice shared library name
Definition: switches.h:32
static bool IterateExtensions(const std::function< bool(T)> &it)
static const char * GetExtensionName(RequiredCommonDeviceExtensionVK ext)
static bool PhysicalDeviceSupportsRequiredFormats(const vk::PhysicalDevice &device)
static bool HasRequiredProperties(const vk::PhysicalDevice &physical_device)
static bool IsExtensionInList(const std::vector< std::string > &list, ExtensionEnum ext)
static bool HasSuitableColorFormat(const vk::PhysicalDevice &device, vk::Format format)
RequiredAndroidDeviceExtensionVK
A device extension available on all Android platforms. Without the presence of these extensions on An...
PixelFormat
The Pixel formats supported by Impeller. The naming convention denotes the usage of the component,...
Definition: formats.h:99
static std::optional< std::set< std::string > > GetSupportedDeviceExtensions(const vk::PhysicalDevice &physical_device)
static bool HasSuitableDepthStencilFormat(const vk::PhysicalDevice &device, vk::Format format)
RequiredCommonDeviceExtensionVK
A device extension available on all platforms. Without the presence of these extensions,...
static constexpr const char * kInstanceLayer
OptionalDeviceExtensionVK
A device extension enabled if available. Subsystems cannot assume availability and must check if thes...
static bool HasRequiredQueues(const vk::PhysicalDevice &physical_device)
def Format(template, **parameters)
Definition: emitter.py:13
#define T
Definition: precompiler.cc:65
#define ERROR(message)
Definition: elf_loader.cc:260
#define VALIDATION_LOG
Definition: validation.h:73
VkFlags VkQueueFlags
Definition: vulkan_core.h:2425
#define VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME
Definition: vulkan_core.h:9443
#define VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME
Definition: vulkan_core.h:8788
#define VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME
Definition: vulkan_core.h:8800
#define VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME
Definition: vulkan_core.h:8708
#define VK_EXT_PIPELINE_CREATION_FEEDBACK_EXTENSION_NAME
#define VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME
#define VK_KHR_EXTERNAL_FENCE_EXTENSION_NAME
Definition: vulkan_core.h:9051
#define VK_KHR_SWAPCHAIN_EXTENSION_NAME
Definition: vulkan_core.h:7707
#define VK_KHR_EXTERNAL_FENCE_FD_EXTENSION_NAME
Definition: vulkan_core.h:9063
#define VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME
Definition: vulkan_core.h:9374