Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
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
187
189 switch (ext) {
193 return "VK_KHR_portability_subset";
195 return "Unknown";
196 }
198}
199
200template <class T>
201static bool IterateExtensions(const std::function<bool(T)>& it) {
202 if (!it) {
203 return false;
204 }
205 for (size_t i = 0; i < static_cast<uint32_t>(T::kLast); i++) {
206 if (!it(static_cast<T>(i))) {
207 return false;
208 }
209 }
210 return true;
211}
212
213static std::optional<std::set<std::string>> GetSupportedDeviceExtensions(
214 const vk::PhysicalDevice& physical_device) {
215 auto device_extensions = physical_device.enumerateDeviceExtensionProperties();
216 if (device_extensions.result != vk::Result::eSuccess) {
217 return std::nullopt;
218 }
219
220 std::set<std::string> exts;
221 for (const auto& device_extension : device_extensions.value) {
222 exts.insert(device_extension.extensionName);
223 };
224
225 return exts;
226}
227
228std::optional<std::vector<std::string>>
230 const vk::PhysicalDevice& physical_device) const {
232
233 if (!exts.has_value()) {
234 return std::nullopt;
235 }
236
237 std::vector<std::string> enabled;
238
239 auto for_each_common_extension = [&](RequiredCommonDeviceExtensionVK ext) {
240 auto name = GetExtensionName(ext);
241 if (exts->find(name) == exts->end()) {
242 VALIDATION_LOG << "Device does not support required extension: " << name;
243 return false;
244 }
245 enabled.push_back(name);
246 return true;
247 };
248
249 auto for_each_android_extension = [&](RequiredAndroidDeviceExtensionVK ext) {
250#ifdef FML_OS_ANDROID
251 auto name = GetExtensionName(ext);
252 if (exts->find(name) == exts->end()) {
253 VALIDATION_LOG << "Device does not support required Android extension: "
254 << name;
255 return false;
256 }
257 enabled.push_back(name);
258#endif // FML_OS_ANDROID
259 return true;
260 };
261
262 auto for_each_optional_extension = [&](OptionalDeviceExtensionVK ext) {
263 auto name = GetExtensionName(ext);
264 if (exts->find(name) != exts->end()) {
265 enabled.push_back(name);
266 }
267 return true;
268 };
269
270 const auto iterate_extensions =
271 IterateExtensions<RequiredCommonDeviceExtensionVK>(
272 for_each_common_extension) &&
273 IterateExtensions<RequiredAndroidDeviceExtensionVK>(
274 for_each_android_extension) &&
275 IterateExtensions<OptionalDeviceExtensionVK>(for_each_optional_extension);
276
277 if (!iterate_extensions) {
278 VALIDATION_LOG << "Device not suitable since required extensions are not "
279 "supported.";
280 return std::nullopt;
281 }
282
283 return enabled;
284}
285
286static bool HasSuitableColorFormat(const vk::PhysicalDevice& device,
287 vk::Format format) {
288 const auto props = device.getFormatProperties(format);
289 // This needs to be more comprehensive.
290 return !!(props.optimalTilingFeatures &
291 vk::FormatFeatureFlagBits::eColorAttachment);
292}
293
294static bool HasSuitableDepthStencilFormat(const vk::PhysicalDevice& device,
295 vk::Format format) {
296 const auto props = device.getFormatProperties(format);
297 return !!(props.optimalTilingFeatures &
298 vk::FormatFeatureFlagBits::eDepthStencilAttachment);
299}
300
302 const vk::PhysicalDevice& device) {
303 const auto has_color_format =
304 HasSuitableColorFormat(device, vk::Format::eR8G8B8A8Unorm);
305 const auto has_stencil_format =
306 HasSuitableDepthStencilFormat(device, vk::Format::eD32SfloatS8Uint) ||
307 HasSuitableDepthStencilFormat(device, vk::Format::eD24UnormS8Uint);
308 return has_color_format && has_stencil_format;
309}
310
311static bool HasRequiredProperties(const vk::PhysicalDevice& physical_device) {
312 auto properties = physical_device.getProperties();
313 if (!(properties.limits.framebufferColorSampleCounts &
314 (vk::SampleCountFlagBits::e1 | vk::SampleCountFlagBits::e4))) {
315 return false;
316 }
317 return true;
318}
319
320static bool HasRequiredQueues(const vk::PhysicalDevice& physical_device) {
321 auto queue_flags = vk::QueueFlags{};
322 for (const auto& queue : physical_device.getQueueFamilyProperties()) {
323 if (queue.queueCount == 0) {
324 continue;
325 }
326 queue_flags |= queue.queueFlags;
327 }
328 return static_cast<VkQueueFlags>(queue_flags &
329 (vk::QueueFlagBits::eGraphics |
330 vk::QueueFlagBits::eCompute |
331 vk::QueueFlagBits::eTransfer));
332}
333
334template <class ExtensionEnum>
335static bool IsExtensionInList(const std::vector<std::string>& list,
336 ExtensionEnum ext) {
337 const std::string name = GetExtensionName(ext);
338 return std::find(list.begin(), list.end(), name) != list.end();
339}
340
341std::optional<CapabilitiesVK::PhysicalDeviceFeatures>
343 const vk::PhysicalDevice& device) const {
345 VALIDATION_LOG << "Device doesn't support the required formats.";
346 return std::nullopt;
347 }
348
350 VALIDATION_LOG << "Device doesn't support the required properties.";
351 return std::nullopt;
352 }
353
355 VALIDATION_LOG << "Device doesn't support the required queues.";
356 return std::nullopt;
357 }
358
359 const auto enabled_extensions = GetEnabledDeviceExtensions(device);
360 if (!enabled_extensions.has_value()) {
361 VALIDATION_LOG << "Device doesn't support the required queues.";
362 return std::nullopt;
363 }
364
365 PhysicalDeviceFeatures supported_chain;
366 device.getFeatures2(&supported_chain.get());
367
368 PhysicalDeviceFeatures required_chain;
369
370 // Base features.
371 {
372 auto& required = required_chain.get().features;
373 const auto& supported = supported_chain.get().features;
374
375 // We require this for enabling wireframes in the playground. But its not
376 // necessarily a big deal if we don't have this feature.
377 required.fillModeNonSolid = supported.fillModeNonSolid;
378 }
379 // VK_KHR_sampler_ycbcr_conversion features.
381 enabled_extensions.value(),
383 auto& required =
384 required_chain
385 .get<vk::PhysicalDeviceSamplerYcbcrConversionFeaturesKHR>();
386 const auto& supported =
387 supported_chain
388 .get<vk::PhysicalDeviceSamplerYcbcrConversionFeaturesKHR>();
389
390 required.samplerYcbcrConversion = supported.samplerYcbcrConversion;
391 }
392
393 // Vulkan 1.1
394 {
395 auto& required =
396 required_chain.get<vk::PhysicalDevice16BitStorageFeatures>();
397 const auto& supported =
398 supported_chain.get<vk::PhysicalDevice16BitStorageFeatures>();
399
400 required.uniformAndStorageBuffer16BitAccess =
401 supported.uniformAndStorageBuffer16BitAccess;
402 }
403
404 return required_chain;
405}
406
407bool CapabilitiesVK::HasLayer(const std::string& layer) const {
408 for (const auto& [found_layer, exts] : exts_) {
409 if (found_layer == layer) {
410 return true;
411 }
412 }
413 return false;
414}
415
416bool CapabilitiesVK::HasExtension(const std::string& ext) const {
417 for (const auto& [layer, exts] : exts_) {
418 if (exts.find(ext) != exts.end()) {
419 return true;
420 }
421 }
422 return false;
423}
424
426 default_color_format_ = pixel_format;
427}
428
429bool CapabilitiesVK::SetPhysicalDevice(const vk::PhysicalDevice& device) {
430 if (HasSuitableColorFormat(device, vk::Format::eR8G8B8A8Unorm)) {
431 default_color_format_ = PixelFormat::kR8G8B8A8UNormInt;
432 } else {
433 default_color_format_ = PixelFormat::kUnknown;
434 }
435
436 if (HasSuitableDepthStencilFormat(device, vk::Format::eD32SfloatS8Uint)) {
437 default_depth_stencil_format_ = PixelFormat::kD32FloatS8UInt;
439 vk::Format::eD24UnormS8Uint)) {
440 default_depth_stencil_format_ = PixelFormat::kD24UnormS8Uint;
441 } else {
442 default_depth_stencil_format_ = PixelFormat::kUnknown;
443 }
444
445 if (HasSuitableDepthStencilFormat(device, vk::Format::eS8Uint)) {
446 default_stencil_format_ = PixelFormat::kS8UInt;
447 } else if (default_depth_stencil_format_ != PixelFormat::kUnknown) {
448 default_stencil_format_ = default_depth_stencil_format_;
449 }
450
451 device_properties_ = device.getProperties();
452
453 auto physical_properties_2 =
454 device.getProperties2<vk::PhysicalDeviceProperties2,
455 vk::PhysicalDeviceSubgroupProperties>();
456
457 // Currently shaders only want access to arithmetic subgroup features.
458 // If that changes this needs to get updated, and so does Metal (which right
459 // now assumes it from compile time flags based on the MSL target version).
460
461 supports_compute_subgroups_ =
462 !!(physical_properties_2.get<vk::PhysicalDeviceSubgroupProperties>()
463 .supportedOperations &
464 vk::SubgroupFeatureFlagBits::eArithmetic);
465
466 {
467 // Query texture support.
468 // TODO(jonahwilliams):
469 // https://github.com/flutter/flutter/issues/129784
470 vk::PhysicalDeviceMemoryProperties memory_properties;
471 device.getMemoryProperties(&memory_properties);
472
473 for (auto i = 0u; i < memory_properties.memoryTypeCount; i++) {
474 if (memory_properties.memoryTypes[i].propertyFlags &
475 vk::MemoryPropertyFlagBits::eLazilyAllocated) {
476 supports_device_transient_textures_ = true;
477 }
478 }
479 }
480
481 // Determine the optional device extensions this physical device supports.
482 {
483 required_common_device_extensions_.clear();
484 required_android_device_extensions_.clear();
485 optional_device_extensions_.clear();
487 if (!exts.has_value()) {
488 return false;
489 }
490 IterateExtensions<RequiredCommonDeviceExtensionVK>([&](auto ext) -> bool {
491 auto ext_name = GetExtensionName(ext);
492 if (exts->find(ext_name) != exts->end()) {
493 required_common_device_extensions_.insert(ext);
494 }
495 return true;
496 });
497 IterateExtensions<RequiredAndroidDeviceExtensionVK>([&](auto ext) -> bool {
498 auto ext_name = GetExtensionName(ext);
499 if (exts->find(ext_name) != exts->end()) {
500 required_android_device_extensions_.insert(ext);
501 }
502 return true;
503 });
504 IterateExtensions<OptionalDeviceExtensionVK>([&](auto ext) -> bool {
505 auto ext_name = GetExtensionName(ext);
506 if (exts->find(ext_name) != exts->end()) {
507 optional_device_extensions_.insert(ext);
508 }
509 return true;
510 });
511 }
512
513 return true;
514}
515
516// |Capabilities|
518 return true;
519}
520
521// |Capabilities|
523 return false;
524}
525
526// |Capabilities|
528 return true;
529}
530
531// |Capabilities|
533 return true;
534}
535
536// |Capabilities|
538 return true;
539}
540
541// |Capabilities|
543 return true;
544}
545
546// |Capabilities|
548 // Vulkan 1.1 requires support for compute.
549 return true;
550}
551
552// |Capabilities|
554 // Set by |SetPhysicalDevice|.
555 return supports_compute_subgroups_;
556}
557
558// |Capabilities|
560 return false;
561}
562
564 return true;
565}
566
567// |Capabilities|
569 return supports_device_transient_textures_;
570}
571
572// |Capabilities|
574 return default_color_format_;
575}
576
577// |Capabilities|
579 return default_stencil_format_;
580}
581
582// |Capabilities|
584 return default_depth_stencil_format_;
585}
586
587const vk::PhysicalDeviceProperties&
589 return device_properties_;
590}
591
595
597 return required_common_device_extensions_.find(ext) !=
598 required_common_device_extensions_.end();
599}
600
602 return required_android_device_extensions_.find(ext) !=
603 required_android_device_extensions_.end();
604}
605
607 return optional_device_extensions_.find(ext) !=
608 optional_device_extensions_.end();
609}
610
611} // namespace impeller
bool SupportsDeviceTransientTextures() const override
Whether the context backend supports allocating StorageMode::kDeviceTransient (aka "memoryless") text...
std::optional< std::vector< std::string > > GetEnabledInstanceExtensions() 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 SupportsBufferToTextureBlits() const override
Whether the context backend supports blitting from a given DeviceBuffer view to a texture region (via...
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
const char * name
Definition fuchsia.cc:50
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:100
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)
#define T
#define ERROR(message)
#define VALIDATION_LOG
Definition validation.h:73
VkFlags VkQueueFlags
#define VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME
#define VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME
#define VK_EXT_PIPELINE_CREATION_FEEDBACK_EXTENSION_NAME
#define VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME
#define VK_KHR_SWAPCHAIN_EXTENSION_NAME
#define VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME