| // Copyright 2013 The Flutter Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #define FML_USED_ON_EMBEDDER |
| |
| #include <cstring> |
| #include <string> |
| #include <utility> |
| #include <vector> |
| |
| #include "embedder.h" |
| #include "embedder_engine.h" |
| #include "flutter/fml/synchronization/count_down_latch.h" |
| #include "flutter/shell/platform/embedder/tests/embedder_config_builder.h" |
| #include "flutter/shell/platform/embedder/tests/embedder_test.h" |
| #include "flutter/shell/platform/embedder/tests/embedder_test_context_vulkan.h" |
| #include "flutter/shell/platform/embedder/tests/embedder_unittests_util.h" |
| #include "flutter/testing/testing.h" |
| |
| // CREATE_NATIVE_ENTRY is leaky by design |
| // NOLINTBEGIN(clang-analyzer-core.StackAddressEscape) |
| |
| namespace flutter { |
| namespace testing { |
| |
| using EmbedderTest = testing::EmbedderTest; |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // Notice: Other Vulkan unit tests exist in embedder_gl_unittests.cc. |
| // See https://github.com/flutter/flutter/issues/134322 |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| namespace { |
| |
| struct VulkanProcInfo { |
| decltype(vkGetInstanceProcAddr)* get_instance_proc_addr = nullptr; |
| decltype(vkGetDeviceProcAddr)* get_device_proc_addr = nullptr; |
| decltype(vkQueueSubmit)* queue_submit_proc_addr = nullptr; |
| bool did_call_queue_submit = false; |
| }; |
| |
| static_assert(std::is_trivially_destructible_v<VulkanProcInfo>); |
| |
| VulkanProcInfo g_vulkan_proc_info; |
| |
| VkResult QueueSubmit(VkQueue queue, |
| uint32_t submitCount, |
| const VkSubmitInfo* pSubmits, |
| VkFence fence) { |
| FML_DCHECK(g_vulkan_proc_info.queue_submit_proc_addr != nullptr); |
| g_vulkan_proc_info.did_call_queue_submit = true; |
| return g_vulkan_proc_info.queue_submit_proc_addr(queue, submitCount, pSubmits, |
| fence); |
| } |
| |
| template <size_t N> |
| int StrcmpFixed(const char* str1, const char (&str2)[N]) { |
| return strncmp(str1, str2, N - 1); |
| } |
| |
| PFN_vkVoidFunction GetDeviceProcAddr(VkDevice device, const char* pName) { |
| FML_DCHECK(g_vulkan_proc_info.get_device_proc_addr != nullptr); |
| if (StrcmpFixed(pName, "vkQueueSubmit") == 0) { |
| g_vulkan_proc_info.queue_submit_proc_addr = |
| reinterpret_cast<decltype(vkQueueSubmit)*>( |
| g_vulkan_proc_info.get_device_proc_addr(device, pName)); |
| return reinterpret_cast<PFN_vkVoidFunction>(QueueSubmit); |
| } |
| return g_vulkan_proc_info.get_device_proc_addr(device, pName); |
| } |
| |
| PFN_vkVoidFunction GetInstanceProcAddr(VkInstance instance, const char* pName) { |
| FML_DCHECK(g_vulkan_proc_info.get_instance_proc_addr != nullptr); |
| if (StrcmpFixed(pName, "vkGetDeviceProcAddr") == 0) { |
| g_vulkan_proc_info.get_device_proc_addr = |
| reinterpret_cast<decltype(vkGetDeviceProcAddr)*>( |
| g_vulkan_proc_info.get_instance_proc_addr(instance, pName)); |
| return reinterpret_cast<PFN_vkVoidFunction>(GetDeviceProcAddr); |
| } |
| return g_vulkan_proc_info.get_instance_proc_addr(instance, pName); |
| } |
| |
| template <typename T, typename U> |
| struct CheckSameSignature : std::false_type {}; |
| |
| template <typename Ret, typename... Args> |
| struct CheckSameSignature<Ret(Args...), Ret(Args...)> : std::true_type {}; |
| |
| static_assert(CheckSameSignature<decltype(GetInstanceProcAddr), |
| decltype(vkGetInstanceProcAddr)>::value); |
| static_assert(CheckSameSignature<decltype(GetDeviceProcAddr), |
| decltype(vkGetDeviceProcAddr)>::value); |
| static_assert( |
| CheckSameSignature<decltype(QueueSubmit), decltype(vkQueueSubmit)>::value); |
| } // namespace |
| |
| TEST_F(EmbedderTest, CanSwapOutVulkanCalls) { |
| auto& context = GetEmbedderContext(EmbedderTestContextType::kVulkanContext); |
| fml::AutoResetWaitableEvent latch; |
| context.AddIsolateCreateCallback([&latch]() { latch.Signal(); }); |
| EmbedderConfigBuilder builder(context); |
| builder.SetVulkanRendererConfig( |
| SkISize::Make(1024, 1024), |
| [](void* user_data, FlutterVulkanInstanceHandle instance, |
| const char* name) -> void* { |
| if (StrcmpFixed(name, "vkGetInstanceProcAddr") == 0) { |
| g_vulkan_proc_info.get_instance_proc_addr = |
| reinterpret_cast<decltype(vkGetInstanceProcAddr)*>( |
| EmbedderTestContextVulkan::InstanceProcAddr(user_data, |
| instance, name)); |
| return reinterpret_cast<void*>(GetInstanceProcAddr); |
| } |
| return EmbedderTestContextVulkan::InstanceProcAddr(user_data, instance, |
| name); |
| }); |
| auto engine = builder.LaunchEngine(); |
| ASSERT_TRUE(engine.is_valid()); |
| // Wait for the root isolate to launch. |
| latch.Wait(); |
| engine.reset(); |
| EXPECT_TRUE(g_vulkan_proc_info.did_call_queue_submit); |
| } |
| |
| } // namespace testing |
| } // namespace flutter |
| |
| // NOLINTEND(clang-analyzer-core.StackAddressEscape) |