5 #include "flutter/fml/synchronization/waitable_event.h"
6 #include "flutter/testing/testing.h"
11 #include "impeller/renderer/backend/vulkan/test/mock_vulkan.h"
12 #include "vulkan/vulkan_core.h"
17 TEST(ContextVKTest, CommonHardwareConcurrencyConfigurations) {
30 TEST(ContextVKTest, DeletesCommandPools) {
31 std::weak_ptr<ContextVK> weak_context;
32 std::weak_ptr<CommandPoolVK> weak_pool;
34 std::shared_ptr<ContextVK> context = MockVulkanContextBuilder().Build();
35 auto const pool = context->GetCommandPoolRecycler()->Get();
37 weak_context = context;
38 ASSERT_TRUE(weak_pool.lock());
39 ASSERT_TRUE(weak_context.lock());
41 ASSERT_FALSE(weak_pool.lock());
42 ASSERT_FALSE(weak_context.lock());
45 TEST(ContextVKTest, DeletesCommandPoolsOnAllThreads) {
46 std::weak_ptr<ContextVK> weak_context;
47 std::weak_ptr<CommandPoolVK> weak_pool_main;
49 std::shared_ptr<ContextVK> context = MockVulkanContextBuilder().Build();
50 weak_pool_main = context->GetCommandPoolRecycler()->Get();
51 weak_context = context;
52 ASSERT_TRUE(weak_pool_main.lock());
53 ASSERT_TRUE(weak_context.lock());
56 fml::AutoResetWaitableEvent latch1, latch2;
57 std::weak_ptr<CommandPoolVK> weak_pool_thread;
58 std::thread thread([&]() {
59 weak_pool_thread = context->GetCommandPoolRecycler()->Get();
67 ASSERT_FALSE(weak_pool_main.lock());
68 ASSERT_FALSE(weak_context.lock());
73 ASSERT_FALSE(weak_pool_thread.lock());
76 TEST(ContextVKTest, ThreadLocalCleanupDeletesCommandPool) {
77 std::shared_ptr<ContextVK> context = MockVulkanContextBuilder().Build();
79 fml::AutoResetWaitableEvent latch1, latch2;
80 std::weak_ptr<CommandPoolVK> weak_pool;
81 std::thread thread([&]() {
82 weak_pool = context->GetCommandPoolRecycler()->Get();
83 context->DisposeThreadLocalCachedResources();
89 ASSERT_FALSE(weak_pool.lock());
95 TEST(ContextVKTest, DeletePipelineAfterContext) {
96 std::shared_ptr<Pipeline<PipelineDescriptor>> pipeline;
97 std::shared_ptr<std::vector<std::string>> functions;
99 std::shared_ptr<ContextVK> context = MockVulkanContextBuilder().Build();
103 context->GetPipelineLibrary()->GetPipeline(pipeline_desc);
104 pipeline = pipeline_future.
Get();
105 ASSERT_TRUE(pipeline);
106 functions = GetMockVulkanFunctions(context->GetDevice());
107 ASSERT_TRUE(std::find(functions->begin(), functions->end(),
108 "vkCreateGraphicsPipelines") != functions->end());
110 ASSERT_TRUE(std::find(functions->begin(), functions->end(),
111 "vkDestroyDevice") != functions->end());
114 TEST(ContextVKTest, DeleteShaderFunctionAfterContext) {
115 std::shared_ptr<const ShaderFunction> shader_function;
116 std::shared_ptr<std::vector<std::string>> functions;
118 std::shared_ptr<ContextVK> context = MockVulkanContextBuilder().Build();
121 std::vector<uint8_t>
data = {0x03, 0x02, 0x23, 0x07};
122 context->GetShaderLibrary()->RegisterFunction(
124 std::make_shared<fml::DataMapping>(
data), [](
bool) {});
125 shader_function = context->GetShaderLibrary()->GetFunction(
127 ASSERT_TRUE(shader_function);
128 functions = GetMockVulkanFunctions(context->GetDevice());
129 ASSERT_TRUE(std::find(functions->begin(), functions->end(),
130 "vkCreateShaderModule") != functions->end());
132 ASSERT_TRUE(std::find(functions->begin(), functions->end(),
133 "vkDestroyDevice") != functions->end());
136 TEST(ContextVKTest, DeletePipelineLibraryAfterContext) {
137 std::shared_ptr<PipelineLibrary> pipeline_library;
138 std::shared_ptr<std::vector<std::string>> functions;
140 std::shared_ptr<ContextVK> context = MockVulkanContextBuilder().Build();
143 pipeline_library = context->GetPipelineLibrary();
144 functions = GetMockVulkanFunctions(context->GetDevice());
145 ASSERT_TRUE(std::find(functions->begin(), functions->end(),
146 "vkCreatePipelineCache") != functions->end());
148 ASSERT_TRUE(std::find(functions->begin(), functions->end(),
149 "vkDestroyDevice") != functions->end());
152 TEST(ContextVKTest, CanCreateContextInAbsenceOfValidationLayers) {
155 auto context = MockVulkanContextBuilder()
156 .SetSettingsCallback([](
auto& settings) {
157 settings.enable_validation =
true;
160 ASSERT_NE(context,
nullptr);
162 reinterpret_cast<const CapabilitiesVK*
>(context->GetCapabilities().get());
166 TEST(ContextVKTest, CanCreateContextWithValidationLayers) {
168 MockVulkanContextBuilder()
169 .SetSettingsCallback(
170 [](
auto& settings) { settings.enable_validation =
true; })
171 .SetInstanceExtensions(
172 {
"VK_KHR_surface",
"VK_MVK_macos_surface",
"VK_EXT_debug_utils"})
173 .SetInstanceLayers({
"VK_LAYER_KHRONOS_validation"})
175 ASSERT_NE(context,
nullptr);
177 reinterpret_cast<const CapabilitiesVK*
>(context->GetCapabilities().get());
184 TEST(CapabilitiesVKTest, ContextInitializesWithNoStencilFormat) {
185 const std::shared_ptr<ContextVK> context =
186 MockVulkanContextBuilder()
187 .SetPhysicalDeviceFormatPropertiesCallback(
188 [](VkPhysicalDevice physicalDevice, VkFormat format,
189 VkFormatProperties* pFormatProperties) {
190 if (format == VK_FORMAT_R8G8B8A8_UNORM) {
191 pFormatProperties->optimalTilingFeatures =
192 static_cast<VkFormatFeatureFlags
>(
193 vk::FormatFeatureFlagBits::eColorAttachment);
194 }
else if (format == VK_FORMAT_D32_SFLOAT_S8_UINT) {
195 pFormatProperties->optimalTilingFeatures =
196 static_cast<VkFormatFeatureFlags
>(
197 vk::FormatFeatureFlagBits::eDepthStencilAttachment);
202 ASSERT_NE(context,
nullptr);
204 reinterpret_cast<const CapabilitiesVK*
>(context->GetCapabilities().get());
216 ContextFailsInitializationForNoCombinedDepthStencilFormat) {
218 const std::shared_ptr<ContextVK> context =
219 MockVulkanContextBuilder()
220 .SetPhysicalDeviceFormatPropertiesCallback(
221 [](VkPhysicalDevice physicalDevice, VkFormat format,
222 VkFormatProperties* pFormatProperties) {
223 if (format == VK_FORMAT_R8G8B8A8_UNORM) {
224 pFormatProperties->optimalTilingFeatures =
225 static_cast<VkFormatFeatureFlags
>(
226 vk::FormatFeatureFlagBits::eColorAttachment);
231 ASSERT_EQ(context,
nullptr);
234 TEST(ContextVKTest, WarmUpFunctionCreatesRenderPass) {
235 const std::shared_ptr<ContextVK> context = MockVulkanContextBuilder().Build();
238 context->InitializeCommonlyUsedShadersIfNeeded();
240 auto functions = GetMockVulkanFunctions(context->GetDevice());
241 ASSERT_TRUE(std::find(functions->begin(), functions->end(),
242 "vkCreateRenderPass") != functions->end());
245 TEST(ContextVKTest, FatalMissingValidations) {
246 EXPECT_DEATH(
const std::shared_ptr<ContextVK> context =
247 MockVulkanContextBuilder()
256 TEST(ContextVKTest, HasDefaultColorFormat) {
257 std::shared_ptr<ContextVK> context = MockVulkanContextBuilder().Build();
260 reinterpret_cast<const CapabilitiesVK*
>(context->GetCapabilities().get());
264 TEST(ContextVKTest, EmbedderOverridesUsesInstanceExtensions) {
266 auto other_context = MockVulkanContextBuilder().Build();
268 data.instance = other_context->GetInstance();
269 data.device = other_context->GetDevice();
270 data.physical_device = other_context->GetPhysicalDevice();
271 data.queue = VkQueue{};
272 data.queue_family_index = 0;
274 data.instance_extensions = {};
275 data.device_extensions = {
"VK_KHR_swapchain"};
278 auto context = MockVulkanContextBuilder().SetEmbedderData(
data).Build();
280 EXPECT_EQ(context,
nullptr);
283 TEST(ContextVKTest, EmbedderOverrides) {
285 auto other_context = MockVulkanContextBuilder().Build();
287 data.instance = other_context->GetInstance();
288 data.device = other_context->GetDevice();
289 data.physical_device = other_context->GetPhysicalDevice();
290 data.queue = VkQueue{};
291 data.queue_family_index = 0;
292 data.instance_extensions = {
"VK_KHR_surface",
293 "VK_KHR_portability_enumeration"};
294 data.device_extensions = {
"VK_KHR_swapchain"};
296 auto context = MockVulkanContextBuilder().SetEmbedderData(
data).Build();
298 EXPECT_TRUE(context->IsValid());
299 EXPECT_EQ(context->GetInstance(), other_context->GetInstance());
300 EXPECT_EQ(context->GetDevice(), other_context->GetDevice());
301 EXPECT_EQ(context->GetPhysicalDevice(), other_context->GetPhysicalDevice());
302 EXPECT_EQ(context->GetGraphicsQueue()->GetIndex().index, 0u);
303 EXPECT_EQ(context->GetGraphicsQueue()->GetIndex().family, 0u);
306 TEST(ContextVKTest, BatchSubmitCommandBuffersOnArm) {
307 std::shared_ptr<ContextVK> context =
308 MockVulkanContextBuilder()
309 .SetPhysicalPropertiesCallback(
310 [](VkPhysicalDevice device, VkPhysicalDeviceProperties* prop) {
311 prop->vendorID = 0x13B5;
312 prop->deviceType = VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU;
316 EXPECT_TRUE(context->EnqueueCommandBuffer(context->CreateCommandBuffer()));
317 EXPECT_TRUE(context->EnqueueCommandBuffer(context->CreateCommandBuffer()));
321 auto functions = GetMockVulkanFunctions(context->GetDevice());
322 EXPECT_TRUE(std::find(functions->begin(), functions->end(),
323 "vkAllocateCommandBuffers") != functions->end());
324 EXPECT_TRUE(std::find(functions->begin(), functions->end(),
325 "vkCreateFence") == functions->end());
327 context->FlushCommandBuffers();
330 functions = GetMockVulkanFunctions(context->GetDevice());
331 EXPECT_TRUE(std::find(functions->begin(), functions->end(),
332 "vkCreateFence") != functions->end());
335 TEST(ContextVKTest, BatchSubmitCommandBuffersOnNonArm) {
336 std::shared_ptr<ContextVK> context =
337 MockVulkanContextBuilder()
338 .SetPhysicalPropertiesCallback(
339 [](VkPhysicalDevice device, VkPhysicalDeviceProperties* prop) {
340 prop->vendorID = 0x8686;
341 prop->deviceType = VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU;
345 EXPECT_TRUE(context->EnqueueCommandBuffer(context->CreateCommandBuffer()));
346 EXPECT_TRUE(context->EnqueueCommandBuffer(context->CreateCommandBuffer()));
350 auto functions = GetMockVulkanFunctions(context->GetDevice());
351 EXPECT_TRUE(std::find(functions->begin(), functions->end(),
352 "vkAllocateCommandBuffers") != functions->end());
353 EXPECT_FALSE(std::find(functions->begin(), functions->end(),
354 "vkCreateFence") != functions->end());
357 TEST(ContextVKTest, AHBSwapchainCapabilitiesCanBeMissing) {
359 std::shared_ptr<ContextVK> context =
360 MockVulkanContextBuilder()
366 EXPECT_FALSE(context->GetShouldEnableSurfaceControlSwapchain());
370 auto other_context = MockVulkanContextBuilder().Build();
372 data.instance = other_context->GetInstance();
373 data.device = other_context->GetDevice();
374 data.physical_device = other_context->GetPhysicalDevice();
375 data.queue = VkQueue{};
376 data.queue_family_index = 0;
377 data.instance_extensions = {
"VK_KHR_surface",
"VK_KHR_android_surface"};
378 data.device_extensions = {
"VK_KHR_swapchain",
379 VK_KHR_EXTERNAL_FENCE_FD_EXTENSION_NAME,
380 VK_KHR_EXTERNAL_FENCE_EXTENSION_NAME,
381 VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME,
382 VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME};
384 auto context = MockVulkanContextBuilder()
388 .SetEmbedderData(
data)
391 EXPECT_TRUE(context->GetShouldEnableSurfaceControlSwapchain());
395 TEST(ContextVKTest, HashIsUniqueAcrossThreads) {
396 uint64_t hash1, hash2;
397 std::thread thread1([&]() {
398 auto context = MockVulkanContextBuilder().Build();
399 hash1 = context->GetHash();
401 std::thread thread2([&]() {
402 auto context = MockVulkanContextBuilder().Build();
403 hash2 = context->GetHash();
408 EXPECT_NE(hash1, hash2);
The Vulkan layers and extensions wrangler.
bool AreValidationsEnabled() const
PixelFormat GetDefaultStencilFormat() const override
Returns a supported PixelFormat for textures that store stencil information. May include a depth chan...
PixelFormat GetDefaultDepthStencilFormat() const override
Returns a supported PixelFormat for textures that store both a stencil and depth component....
PixelFormat GetDefaultColorFormat() const override
Returns a supported PixelFormat for textures that store 4-channel colors (red/green/blue/alpha).
static size_t ChooseThreadCountForWorkers(size_t hardware_concurrency)
PipelineDescriptor & SetVertexDescriptor(std::shared_ptr< VertexDescriptor > vertex_descriptor)
TEST(AllocationSizeTest, CanCreateTypedAllocations)
bool enable_surface_control
bool fatal_missing_validations
If validations are requested but cannot be enabled, log a fatal error.
const std::shared_ptr< Pipeline< T > > Get() const
std::shared_ptr< const fml::Mapping > data