19 bool fatal_missing_validations) {
20 auto extensions = vk::enumerateInstanceExtensionProperties();
21 auto layers = vk::enumerateInstanceLayerProperties();
23 if (extensions.result != vk::Result::eSuccess ||
24 layers.result != vk::Result::eSuccess) {
28 for (
const auto& ext : extensions.value) {
32 for (
const auto& layer : layers.value) {
33 const std::string layer_name = layer.layerName;
34 auto layer_exts = vk::enumerateInstanceExtensionProperties(layer_name);
35 if (layer_exts.result != vk::Result::eSuccess) {
38 for (
const auto& layer_ext : layer_exts.value) {
39 exts_[layer_name].insert(layer_ext.extensionName);
43 validations_enabled_ =
44 enable_validations && HasLayer(
"VK_LAYER_KHRONOS_validation");
45 if (enable_validations && !validations_enabled_) {
47 <<
"Requested Impeller context creation with validations but the "
48 "validation layers could not be found. Expect no Vulkan validation "
50 if (fatal_missing_validations) {
51 FML_LOG(FATAL) <<
"Validation missing. Exiting.";
54 if (validations_enabled_) {
55 FML_LOG(INFO) <<
"Vulkan validations are enabled.";
67 return validations_enabled_;
72 std::vector<std::string> required;
74 if (validations_enabled_) {
76 required.push_back(
"VK_LAYER_KHRONOS_validation");
82 std::optional<std::vector<std::string>>
84 std::vector<std::string> required;
92 required.push_back(
"VK_KHR_surface");
96 required.push_back(
"VK_MVK_macos_surface");
101 required.push_back(
"VK_EXT_metal_surface");
106 required.push_back(
"VK_KHR_portability_enumeration");
111 required.push_back(
"VK_KHR_win32_surface");
116 required.push_back(
"VK_KHR_android_surface");
121 required.push_back(
"VK_KHR_xcb_surface");
126 required.push_back(
"VK_KHR_xlib_surface");
131 required.push_back(
"VK_KHR_wayland_surface");
142 if (validations_enabled_) {
145 "VK_EXT_debug_utils extension.";
148 required.push_back(
"VK_EXT_debug_utils");
153 required.push_back(
"VK_EXT_validation_features");
163 return VK_KHR_SWAPCHAIN_EXTENSION_NAME;
174 return "VK_ANDROID_external_memory_android_hardware_buffer";
176 return VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME;
178 return VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME;
180 return VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME;
182 return VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME;
184 return VK_KHR_EXTERNAL_FENCE_FD_EXTENSION_NAME;
186 return VK_KHR_EXTERNAL_FENCE_EXTENSION_NAME;
188 return VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME;
190 return VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME;
200 return VK_EXT_PIPELINE_CREATION_FEEDBACK_EXTENSION_NAME;
202 return "VK_KHR_portability_subset";
204 return VK_EXT_IMAGE_COMPRESSION_CONTROL_EXTENSION_NAME;
216 for (
size_t i = 0; i < static_cast<uint32_t>(T::kLast); i++) {
217 if (!it(
static_cast<T
>(i))) {
225 const vk::PhysicalDevice& physical_device) {
226 auto device_extensions = physical_device.enumerateDeviceExtensionProperties();
227 if (device_extensions.result != vk::Result::eSuccess) {
231 std::set<std::string> exts;
232 for (
const auto& device_extension : device_extensions.value) {
233 exts.insert(device_extension.extensionName);
239 std::optional<std::vector<std::string>>
241 const vk::PhysicalDevice& physical_device)
const {
244 if (!exts.has_value()) {
248 std::vector<std::string> enabled;
252 if (exts->find(name) == exts->end()) {
253 VALIDATION_LOG <<
"Device does not support required extension: " << name;
256 enabled.push_back(name);
261 #ifdef FML_OS_ANDROID
263 if (exts->find(name) == exts->end()) {
264 VALIDATION_LOG <<
"Device does not support required Android extension: "
268 enabled.push_back(name);
269 #endif // FML_OS_ANDROID
275 if (exts->find(name) != exts->end()) {
276 enabled.push_back(name);
281 const auto iterate_extensions =
282 IterateExtensions<RequiredCommonDeviceExtensionVK>(
283 for_each_common_extension) &&
284 IterateExtensions<RequiredAndroidDeviceExtensionVK>(
285 for_each_android_extension) &&
286 IterateExtensions<OptionalDeviceExtensionVK>(for_each_optional_extension);
288 if (!iterate_extensions) {
289 VALIDATION_LOG <<
"Device not suitable since required extensions are not "
299 const auto props = device.getFormatProperties(format);
301 return !!(props.optimalTilingFeatures &
302 vk::FormatFeatureFlagBits::eColorAttachment);
307 const auto props = device.getFormatProperties(format);
308 return !!(props.optimalTilingFeatures &
309 vk::FormatFeatureFlagBits::eDepthStencilAttachment);
313 const vk::PhysicalDevice& device) {
314 const auto has_color_format =
316 const auto has_stencil_format =
319 return has_color_format && has_stencil_format;
323 auto properties = physical_device.getProperties();
324 if (!(properties.limits.framebufferColorSampleCounts &
325 (vk::SampleCountFlagBits::e1 | vk::SampleCountFlagBits::e4))) {
332 auto queue_flags = vk::QueueFlags{};
333 for (
const auto& queue : physical_device.getQueueFamilyProperties()) {
334 if (queue.queueCount == 0) {
337 queue_flags |= queue.queueFlags;
339 return static_cast<VkQueueFlags
>(queue_flags &
340 (vk::QueueFlagBits::eGraphics |
341 vk::QueueFlagBits::eCompute |
342 vk::QueueFlagBits::eTransfer));
345 template <
class ExtensionEnum>
349 return std::find(list.begin(), list.end(), name) != list.end();
352 std::optional<CapabilitiesVK::PhysicalDeviceFeatures>
354 const vk::PhysicalDevice& device)
const {
361 VALIDATION_LOG <<
"Device doesn't support the required properties.";
371 if (!enabled_extensions.has_value()) {
382 enabled_extensions.value(),
385 .unlink<vk::PhysicalDeviceImageCompressionControlFeaturesEXT>();
388 device.getFeatures2(&supported_chain.get());
394 auto& required = required_chain.get().features;
395 const auto& supported = supported_chain.get().features;
399 required.fillModeNonSolid = supported.fillModeNonSolid;
403 enabled_extensions.value(),
407 .get<vk::PhysicalDeviceSamplerYcbcrConversionFeaturesKHR>();
408 const auto& supported =
410 .get<vk::PhysicalDeviceSamplerYcbcrConversionFeaturesKHR>();
412 required.samplerYcbcrConversion = supported.samplerYcbcrConversion;
417 enabled_extensions.value(),
421 .get<vk::PhysicalDeviceImageCompressionControlFeaturesEXT>();
422 const auto& supported =
424 .get<vk::PhysicalDeviceImageCompressionControlFeaturesEXT>();
426 required.imageCompressionControl = supported.imageCompressionControl;
429 .unlink<vk::PhysicalDeviceImageCompressionControlFeaturesEXT>();
435 required_chain.get<vk::PhysicalDevice16BitStorageFeatures>();
436 const auto& supported =
437 supported_chain.get<vk::PhysicalDevice16BitStorageFeatures>();
439 required.uniformAndStorageBuffer16BitAccess =
440 supported.uniformAndStorageBuffer16BitAccess;
443 return required_chain;
446 bool CapabilitiesVK::HasLayer(
const std::string& layer)
const {
447 for (
const auto& [found_layer, exts] : exts_) {
448 if (found_layer == layer) {
456 for (
const auto& [layer, exts] : exts_) {
457 if (exts.find(ext) != exts.end()) {
465 default_color_format_ = pixel_format;
469 const vk::PhysicalDevice& device,
480 vk::Format::eD24UnormS8Uint)) {
489 default_stencil_format_ = default_depth_stencil_format_;
492 physical_device_ = device;
493 device_properties_ = device.getProperties();
495 auto physical_properties_2 =
496 device.getProperties2<vk::PhysicalDeviceProperties2,
497 vk::PhysicalDeviceSubgroupProperties>();
503 supports_compute_subgroups_ =
504 !!(physical_properties_2.get<vk::PhysicalDeviceSubgroupProperties>()
505 .supportedOperations &
506 vk::SubgroupFeatureFlagBits::eArithmetic);
511 vk::PhysicalDeviceMemoryProperties memory_properties;
512 device.getMemoryProperties(&memory_properties);
514 for (
auto i = 0u; i < memory_properties.memoryTypeCount; i++) {
515 if (memory_properties.memoryTypes[i].propertyFlags &
516 vk::MemoryPropertyFlagBits::eLazilyAllocated) {
517 supports_device_transient_textures_ =
true;
524 required_common_device_extensions_.clear();
525 required_android_device_extensions_.clear();
526 optional_device_extensions_.clear();
528 if (!exts.has_value()) {
531 IterateExtensions<RequiredCommonDeviceExtensionVK>([&](
auto ext) ->
bool {
533 if (exts->find(ext_name) != exts->end()) {
534 required_common_device_extensions_.insert(ext);
538 IterateExtensions<RequiredAndroidDeviceExtensionVK>([&](
auto ext) ->
bool {
540 if (exts->find(ext_name) != exts->end()) {
541 required_android_device_extensions_.insert(ext);
545 IterateExtensions<OptionalDeviceExtensionVK>([&](
auto ext) ->
bool {
547 if (exts->find(ext_name) != exts->end()) {
548 optional_device_extensions_.insert(ext);
554 supports_texture_fixed_rate_compression_ =
556 .isLinked<vk::PhysicalDeviceImageCompressionControlFeaturesEXT>() &&
558 .get<vk::PhysicalDeviceImageCompressionControlFeaturesEXT>()
559 .imageCompressionControl;
561 max_render_pass_attachment_size_ =
562 ISize{device_properties_.limits.maxFramebufferWidth,
563 device_properties_.limits.maxFramebufferHeight};
602 return supports_compute_subgroups_;
616 return supports_device_transient_textures_;
621 return default_color_format_;
626 return default_stencil_format_;
631 return default_depth_stencil_format_;
634 const vk::PhysicalDeviceProperties&
636 return device_properties_;
644 return required_common_device_extensions_.find(ext) !=
645 required_common_device_extensions_.end();
649 return required_android_device_extensions_.find(ext) !=
650 required_android_device_extensions_.end();
654 return optional_device_extensions_.find(ext) !=
655 optional_device_extensions_.end();
659 return supports_texture_fixed_rate_compression_;
662 std::optional<vk::ImageCompressionFixedRateFlagBitsEXT>
668 if (!supports_texture_fixed_rate_compression_) {
673 vk::StructureChain<vk::PhysicalDeviceImageFormatInfo2,
674 vk::ImageCompressionControlEXT>
677 auto& format_info = format_chain.get();
679 format_info.format = desc.
format;
680 format_info.type = desc.
type;
681 format_info.tiling = desc.
tiling;
682 format_info.usage = desc.
usage;
683 format_info.flags = desc.
flags;
685 const auto kIdealFRCRate = vk::ImageCompressionFixedRateFlagBitsEXT::e4Bpc;
687 std::array<vk::ImageCompressionFixedRateFlagsEXT, 1u> rates = {kIdealFRCRate};
689 auto& compression = format_chain.get<vk::ImageCompressionControlEXT>();
690 compression.flags = vk::ImageCompressionFlagBitsEXT::eFixedRateExplicit;
691 compression.compressionControlPlaneCount = rates.size();
692 compression.pFixedRateFlags = rates.data();
694 const auto [result, supported] = physical_device_.getImageFormatProperties2<
695 vk::ImageFormatProperties2, vk::ImageCompressionPropertiesEXT>(
698 if (result != vk::Result::eSuccess ||
699 !supported.isLinked<vk::ImageCompressionPropertiesEXT>()) {
703 const auto& compression_props =
704 supported.get<vk::ImageCompressionPropertiesEXT>();
706 if ((compression_props.imageCompressionFlags &
707 vk::ImageCompressionFlagBitsEXT::eFixedRateExplicit) &&
708 (compression_props.imageCompressionFixedRateFlags & kIdealFRCRate)) {
709 return kIdealFRCRate;
720 return max_render_pass_attachment_size_;