diff --git a/impeller/renderer/backend/vulkan/capabilities_vk.cc b/impeller/renderer/backend/vulkan/capabilities_vk.cc index ad72a03fde6a5..08c220521af46 100644 --- a/impeller/renderer/backend/vulkan/capabilities_vk.cc +++ b/impeller/renderer/backend/vulkan/capabilities_vk.cc @@ -167,6 +167,22 @@ static const char* GetExtensionName(RequiredCommonDeviceExtensionVK ext) { FML_UNREACHABLE(); } +static const char* GetExtensionName(OptionalAndroidDeviceExtensionVK ext) { + switch (ext) { + case OptionalAndroidDeviceExtensionVK::kKHRExternalFenceFd: + return VK_KHR_EXTERNAL_FENCE_FD_EXTENSION_NAME; + case OptionalAndroidDeviceExtensionVK::kKHRExternalFence: + return VK_KHR_EXTERNAL_FENCE_EXTENSION_NAME; + case OptionalAndroidDeviceExtensionVK::kKHRExternalSemaphoreFd: + return VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME; + case OptionalAndroidDeviceExtensionVK::kKHRExternalSemaphore: + return VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME; + case OptionalAndroidDeviceExtensionVK::kLast: + return "Unknown"; + } + FML_UNREACHABLE(); +} + static const char* GetExtensionName(RequiredAndroidDeviceExtensionVK ext) { switch (ext) { case RequiredAndroidDeviceExtensionVK:: @@ -180,14 +196,6 @@ static const char* GetExtensionName(RequiredAndroidDeviceExtensionVK ext) { return VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME; case RequiredAndroidDeviceExtensionVK::kKHRDedicatedAllocation: return VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME; - case RequiredAndroidDeviceExtensionVK::kKHRExternalFenceFd: - return VK_KHR_EXTERNAL_FENCE_FD_EXTENSION_NAME; - case RequiredAndroidDeviceExtensionVK::kKHRExternalFence: - return VK_KHR_EXTERNAL_FENCE_EXTENSION_NAME; - case RequiredAndroidDeviceExtensionVK::kKHRExternalSemaphoreFd: - return VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME; - case RequiredAndroidDeviceExtensionVK::kKHRExternalSemaphore: - return VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME; case RequiredAndroidDeviceExtensionVK::kLast: return "Unknown"; } @@ -278,12 +286,24 @@ CapabilitiesVK::GetEnabledDeviceExtensions( return true; }; + auto for_each_optional_android_extension = + [&](OptionalAndroidDeviceExtensionVK ext) { + auto name = GetExtensionName(ext); + if (exts->find(name) != exts->end()) { + enabled.push_back(name); + } + return true; + }; + const auto iterate_extensions = IterateExtensions( for_each_common_extension) && IterateExtensions( for_each_android_extension) && - IterateExtensions(for_each_optional_extension); + IterateExtensions( + for_each_optional_extension) && + IterateExtensions( + for_each_optional_android_extension); if (!iterate_extensions) { VALIDATION_LOG << "Device not suitable since required extensions are not " @@ -549,6 +569,13 @@ bool CapabilitiesVK::SetPhysicalDevice( } return true; }); + IterateExtensions([&](auto ext) -> bool { + auto ext_name = GetExtensionName(ext); + if (exts->find(ext_name) != exts->end()) { + optional_android_device_extensions_.insert(ext); + } + return true; + }); } supports_texture_fixed_rate_compression_ = @@ -651,6 +678,11 @@ bool CapabilitiesVK::HasExtension(OptionalDeviceExtensionVK ext) const { optional_device_extensions_.end(); } +bool CapabilitiesVK::HasExtension(OptionalAndroidDeviceExtensionVK ext) const { + return optional_android_device_extensions_.find(ext) != + optional_android_device_extensions_.end(); +} + bool CapabilitiesVK::SupportsTextureFixedRateCompression() const { return supports_texture_fixed_rate_compression_; } diff --git a/impeller/renderer/backend/vulkan/capabilities_vk.h b/impeller/renderer/backend/vulkan/capabilities_vk.h index 1024f2f822218..6a3b914f9aaec 100644 --- a/impeller/renderer/backend/vulkan/capabilities_vk.h +++ b/impeller/renderer/backend/vulkan/capabilities_vk.h @@ -80,33 +80,6 @@ enum class RequiredAndroidDeviceExtensionVK : uint32_t { /// kKHRDedicatedAllocation, - //---------------------------------------------------------------------------- - /// For exporting file descriptors from fences to interact with platform APIs. - /// - /// https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_external_fence_fd.html - /// - kKHRExternalFenceFd, - - //---------------------------------------------------------------------------- - /// Dependency of kKHRExternalFenceFd. - /// - /// https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_external_fence.html - /// - kKHRExternalFence, - - //---------------------------------------------------------------------------- - /// For importing sync file descriptors as semaphores so the GPU can wait for - /// semaphore to be signaled. - /// - /// https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_external_semaphore_fd.html - kKHRExternalSemaphoreFd, - - //---------------------------------------------------------------------------- - /// Dependency of kKHRExternalSemaphoreFd - /// - /// https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_external_semaphore.html - kKHRExternalSemaphore, - kLast, }; @@ -143,6 +116,46 @@ enum class OptionalDeviceExtensionVK : uint32_t { kLast, }; +//------------------------------------------------------------------------------ +/// @brief A device extensions that may be available on Android platforms. +/// Without the presence of these extensions on Android, certain +/// features cannot be used, like AHB swapchains. +/// +/// Platform agnostic code can still check if these Android +/// extensions are present. +/// +enum class OptionalAndroidDeviceExtensionVK : uint32_t { + + //---------------------------------------------------------------------------- + /// For exporting file descriptors from fences to interact with platform APIs. + /// + /// https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_external_fence_fd.html + /// + kKHRExternalFenceFd, + + //---------------------------------------------------------------------------- + /// Dependency of kKHRExternalFenceFd. + /// + /// https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_external_fence.html + /// + kKHRExternalFence, + + //---------------------------------------------------------------------------- + /// For importing sync file descriptors as semaphores so the GPU can wait for + /// semaphore to be signaled. + /// + /// https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_external_semaphore_fd.html + kKHRExternalSemaphoreFd, + + //---------------------------------------------------------------------------- + /// Dependency of kKHRExternalSemaphoreFd + /// + /// https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_external_semaphore.html + kKHRExternalSemaphore, + + kLast, +}; + //------------------------------------------------------------------------------ /// @brief A pixel format and usage that is sufficient to check if images /// of that format and usage are suitable for use with fixed-rate @@ -182,6 +195,8 @@ class CapabilitiesVK final : public Capabilities, bool HasExtension(RequiredAndroidDeviceExtensionVK ext) const; + bool HasExtension(OptionalAndroidDeviceExtensionVK ext) const; + bool HasExtension(OptionalDeviceExtensionVK ext) const; std::optional> GetEnabledLayers() const; @@ -276,6 +291,8 @@ class CapabilitiesVK final : public Capabilities, std::set required_android_device_extensions_; std::set optional_device_extensions_; + std::set + optional_android_device_extensions_; mutable PixelFormat default_color_format_ = PixelFormat::kUnknown; PixelFormat default_stencil_format_ = PixelFormat::kUnknown; PixelFormat default_depth_stencil_format_ = PixelFormat::kUnknown; diff --git a/impeller/renderer/backend/vulkan/context_vk.cc b/impeller/renderer/backend/vulkan/context_vk.cc index 0a0973ba0ad01..d43a91f52bf78 100644 --- a/impeller/renderer/backend/vulkan/context_vk.cc +++ b/impeller/renderer/backend/vulkan/context_vk.cc @@ -626,4 +626,16 @@ const std::unique_ptr& ContextVK::GetDriverInfo() const { return driver_info_; } +bool ContextVK::SupportsAHBSwapchain() const { + const CapabilitiesVK& caps = CapabilitiesVK::Cast(*device_capabilities_); + return caps.HasExtension( + OptionalAndroidDeviceExtensionVK::kKHRExternalFence) && + caps.HasExtension( + OptionalAndroidDeviceExtensionVK::kKHRExternalFenceFd) && + caps.HasExtension( + OptionalAndroidDeviceExtensionVK::kKHRExternalSemaphore) && + caps.HasExtension( + OptionalAndroidDeviceExtensionVK::kKHRExternalSemaphoreFd); +} + } // namespace impeller diff --git a/impeller/renderer/backend/vulkan/context_vk.h b/impeller/renderer/backend/vulkan/context_vk.h index 22909582ee204..a708f8309143b 100644 --- a/impeller/renderer/backend/vulkan/context_vk.h +++ b/impeller/renderer/backend/vulkan/context_vk.h @@ -102,6 +102,10 @@ class ContextVK final : public Context, // |Context| void Shutdown() override; + /// @brief Whether the Vulkan context has sufficient capabilities to support + /// Android Hardware Buffer swapchains. + bool SupportsAHBSwapchain() const; + void SetOffscreenFormat(PixelFormat pixel_format); template diff --git a/impeller/renderer/backend/vulkan/context_vk_unittests.cc b/impeller/renderer/backend/vulkan/context_vk_unittests.cc index 1cfe8d15ddd86..d2cd10321ceb8 100644 --- a/impeller/renderer/backend/vulkan/context_vk_unittests.cc +++ b/impeller/renderer/backend/vulkan/context_vk_unittests.cc @@ -241,5 +241,24 @@ TEST(ContextVKTest, HasDefaultColorFormat) { ASSERT_NE(capabilites_vk->GetDefaultColorFormat(), PixelFormat::kUnknown); } +TEST(ContextVKTest, ChecksOptionalDeviceExtensionsForAndroid) { + auto context = MockVulkanContextBuilder().Build(); + ASSERT_NE(context, nullptr); + + EXPECT_FALSE(context->SupportsAHBSwapchain()); + + context = MockVulkanContextBuilder() + .SetDeviceExtensions({ + VK_KHR_EXTERNAL_FENCE_FD_EXTENSION_NAME, // + VK_KHR_EXTERNAL_FENCE_EXTENSION_NAME, // + VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME, // + VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME // + }) + .Build(); + ASSERT_NE(context, nullptr); + + EXPECT_TRUE(context->SupportsAHBSwapchain()); +} + } // namespace testing } // namespace impeller diff --git a/impeller/renderer/backend/vulkan/swapchain/khr/khr_swapchain_impl_vk.cc b/impeller/renderer/backend/vulkan/swapchain/khr/khr_swapchain_impl_vk.cc index 8be88832bb470..359cdb4de048a 100644 --- a/impeller/renderer/backend/vulkan/swapchain/khr/khr_swapchain_impl_vk.cc +++ b/impeller/renderer/backend/vulkan/swapchain/khr/khr_swapchain_impl_vk.cc @@ -20,11 +20,6 @@ namespace impeller { static constexpr size_t kMaxFramesInFlight = 3u; -// Number of frames to poll for orientation changes. For example `1u` means -// that the orientation will be polled every frame, while `2u` means that the -// orientation will be polled every other frame. -static constexpr size_t kPollFramesForOrientation = 1u; - struct KHRFrameSynchronizerVK { vk::UniqueFence acquire; vk::UniqueSemaphore render_ready; @@ -335,10 +330,10 @@ KHRSwapchainImplVK::AcquireResult KHRSwapchainImplVK::AcquireNextDrawable() { /// Get the next image index. /// auto [acq_result, index] = context.GetDevice().acquireNextImageKHR( - *swapchain_, // swapchain - 1'000'000'000, // timeout (ns) 1000ms - *sync->render_ready, // signal semaphore - nullptr // fence + *swapchain_, // swapchain + std::numeric_limits::max(), // timeout (ns) + *sync->render_ready, // signal semaphore + nullptr // fence ); switch (acq_result) { diff --git a/impeller/renderer/backend/vulkan/swapchain/swapchain_vk.cc b/impeller/renderer/backend/vulkan/swapchain/swapchain_vk.cc index 534c1f8b22e83..341fadd379248 100644 --- a/impeller/renderer/backend/vulkan/swapchain/swapchain_vk.cc +++ b/impeller/renderer/backend/vulkan/swapchain/swapchain_vk.cc @@ -59,7 +59,8 @@ std::shared_ptr SwapchainVK::Create( const auto emulator = ContextVK::Cast(*context).GetDriverInfo()->IsEmulator(); // Try AHB swapchains first. - if (!emulator && AHBSwapchainVK::IsAvailableOnPlatform()) { + if (!emulator && ContextVK::Cast(*context).SupportsAHBSwapchain() && + AHBSwapchainVK::IsAvailableOnPlatform()) { auto ahb_swapchain = std::shared_ptr(new AHBSwapchainVK( context, // window.GetHandle(), // diff --git a/impeller/renderer/backend/vulkan/test/mock_vulkan.cc b/impeller/renderer/backend/vulkan/test/mock_vulkan.cc index c18a569315863..c77ef3587682a 100644 --- a/impeller/renderer/backend/vulkan/test/mock_vulkan.cc +++ b/impeller/renderer/backend/vulkan/test/mock_vulkan.cc @@ -191,16 +191,23 @@ void vkGetPhysicalDeviceQueueFamilyProperties( } } +static thread_local std::vector g_device_extensions; + VkResult vkEnumerateDeviceExtensionProperties( VkPhysicalDevice physicalDevice, const char* pLayerName, uint32_t* pPropertyCount, VkExtensionProperties* pProperties) { if (!pProperties) { - *pPropertyCount = 1; + *pPropertyCount = g_device_extensions.size(); } else { - strcpy(pProperties[0].extensionName, "VK_KHR_swapchain"); - pProperties[0].specVersion = 0; + uint32_t count = 0; + for (const std::string& ext : g_device_extensions) { + strncpy(pProperties[count].extensionName, ext.c_str(), + sizeof(VkExtensionProperties::extensionName)); + pProperties[count].specVersion = 0; + count++; + } } return VK_SUCCESS; } @@ -916,7 +923,11 @@ std::shared_ptr MockVulkanContextBuilder::Build() { if (settings_callback_) { settings_callback_(settings); } + if (device_extensions_.empty()) { + device_extensions_.push_back("VK_KHR_swapchain"); + } g_instance_extensions = instance_extensions_; + g_device_extensions = device_extensions_; g_instance_layers = instance_layers_; g_format_properties_callback = format_properties_callback_; std::shared_ptr result = ContextVK::Create(std::move(settings)); diff --git a/impeller/renderer/backend/vulkan/test/mock_vulkan.h b/impeller/renderer/backend/vulkan/test/mock_vulkan.h index 3febfe3bc7ff7..67142da767b1d 100644 --- a/impeller/renderer/backend/vulkan/test/mock_vulkan.h +++ b/impeller/renderer/backend/vulkan/test/mock_vulkan.h @@ -83,6 +83,13 @@ class MockVulkanContextBuilder { return *this; } + MockVulkanContextBuilder& SetDeviceExtensions( + const std::vector& device_extensions) { + device_extensions_ = device_extensions; + device_extensions_.push_back("VK_KHR_swapchain"); + return *this; + } + MockVulkanContextBuilder& SetInstanceLayers( const std::vector& instance_layers) { instance_layers_ = instance_layers; @@ -103,6 +110,7 @@ class MockVulkanContextBuilder { private: std::function settings_callback_; std::vector instance_extensions_; + std::vector device_extensions_; std::vector instance_layers_; std::function