Flutter Impeller
pipeline_cache_data_vk_unittests.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 
5 #include "flutter/fml/build_config.h"
6 #include "flutter/fml/file.h"
7 #include "flutter/testing/testing.h"
13 #include "impeller/renderer/backend/vulkan/test/mock_vulkan.h"
14 
15 namespace impeller::testing {
16 
17 TEST(PipelineCacheDataVKTest, CanTestHeaderCompatibility) {
18  {
21  EXPECT_EQ(a.abi, sizeof(void*));
22 #ifdef FML_ARCH_CPU_64_BITS
23  EXPECT_EQ(a.abi, 8u);
24 #elif FML_ARCH_CPU_32_BITS
25  EXPECT_EQ(a.abi, 4u);
26 #endif
27  EXPECT_TRUE(a.IsCompatibleWith(b));
28  }
29  // Different data sizes don't matter.
30  {
33  a.data_size = b.data_size + 100u;
34  EXPECT_TRUE(a.IsCompatibleWith(b));
35  }
36  // Magic, Driver, vendor, ABI, and UUID matter.
37  {
40  b.magic = 100;
41  EXPECT_FALSE(a.IsCompatibleWith(b));
42  }
43  {
46  b.driver_version = 100;
47  EXPECT_FALSE(a.IsCompatibleWith(b));
48  }
49  {
52  b.vendor_id = 100;
53  EXPECT_FALSE(a.IsCompatibleWith(b));
54  }
55  {
58  b.device_id = 100;
59  EXPECT_FALSE(a.IsCompatibleWith(b));
60  }
61  {
64  b.abi = a.abi / 2u;
65  EXPECT_FALSE(a.IsCompatibleWith(b));
66  }
67  {
70  for (size_t i = 0; i < VK_UUID_SIZE; i++) {
71  b.uuid[i] = a.uuid[i] + 1;
72  }
73  EXPECT_FALSE(a.IsCompatibleWith(b));
74  }
75 }
76 
77 TEST(PipelineCacheDataVKTest, CanCreateFromDeviceProperties) {
78  vk::PhysicalDeviceProperties props;
79  std::array<uint8_t, 16> uuid{
80  0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
81  };
82  props.pipelineCacheUUID = uuid;
83  props.deviceID = 10;
84  props.vendorID = 11;
85  props.driverVersion = 12;
86  PipelineCacheHeaderVK header(props, 99);
87  EXPECT_EQ(uuid.size(), std::size(header.uuid));
88  EXPECT_EQ(props.deviceID, header.device_id);
89  EXPECT_EQ(props.vendorID, header.vendor_id);
90  EXPECT_EQ(props.driverVersion, header.driver_version);
91  for (size_t i = 0; i < uuid.size(); i++) {
92  EXPECT_EQ(header.uuid[i], uuid.at(i));
93  }
94 }
95 
96 TEST(PipelineCacheDataVKTest, WritesIncompleteCacheData) {
97  fml::ScopedTemporaryDirectory temp_dir;
98  auto context = MockVulkanContextBuilder().Build();
99  auto cache = context->GetDevice().createPipelineCacheUnique({});
100  const auto& caps = CapabilitiesVK::Cast(*context->GetCapabilities());
101 
102  ASSERT_TRUE(PipelineCacheDataPersist(
103  temp_dir.fd(), caps.GetPhysicalDeviceProperties(), cache.value));
104 
105  std::unique_ptr<fml::FileMapping> mapping = fml::FileMapping::CreateReadOnly(
106  temp_dir.fd(), "flutter.impeller.vkcache");
107  ASSERT_TRUE(mapping);
108  PipelineCacheHeaderVK header;
109  ASSERT_GE(mapping->GetSize(), sizeof(header));
110  std::memcpy(&header, mapping->GetMapping(), sizeof(header));
111  ASSERT_EQ(mapping->GetSize(), sizeof(header) + header.data_size);
112 }
113 
116 
117 TEST_P(PipelineCacheDataVKPlaygroundTest, CanPersistAndRetrievePipelineCache) {
118  fml::ScopedTemporaryDirectory temp_dir;
119  const auto& surface_context = SurfaceContextVK::Cast(*GetContext());
120  const auto& context_vk = ContextVK::Cast(*surface_context.GetParent());
121  const auto& caps = CapabilitiesVK::Cast(*context_vk.GetCapabilities());
122 
123  {
124  auto cache = context_vk.GetDevice().createPipelineCacheUnique({});
125  ASSERT_EQ(cache.result, vk::Result::eSuccess);
126  ASSERT_FALSE(fml::FileExists(temp_dir.fd(), "flutter.impeller.vkcache"));
127  ASSERT_TRUE(PipelineCacheDataPersist(
128  temp_dir.fd(), caps.GetPhysicalDeviceProperties(), cache.value));
129  }
130  ASSERT_TRUE(fml::FileExists(temp_dir.fd(), "flutter.impeller.vkcache"));
131 
132  auto mapping = PipelineCacheDataRetrieve(temp_dir.fd(),
133  caps.GetPhysicalDeviceProperties());
134  ASSERT_NE(mapping, nullptr);
135  // Assert that the utility has stripped away the cache header giving us clean
136  // pipeline cache bootstrap information.
137  vk::PipelineCacheHeaderVersionOne vk_cache_header;
138  ASSERT_GE(mapping->GetSize(), sizeof(vk_cache_header));
139  std::memcpy(&vk_cache_header, mapping->GetMapping(), sizeof(vk_cache_header));
140  ASSERT_EQ(vk_cache_header.headerVersion,
141  vk::PipelineCacheHeaderVersion::eOne);
142 }
143 
145  IntegrityChecksArePerformedOnPersistedData) {
146  fml::ScopedTemporaryDirectory temp_dir;
147  const auto& surface_context = SurfaceContextVK::Cast(*GetContext());
148  const auto& context_vk = ContextVK::Cast(*surface_context.GetParent());
149  const auto& caps = CapabilitiesVK::Cast(*context_vk.GetCapabilities());
150 
151  {
152  auto cache = context_vk.GetDevice().createPipelineCacheUnique({});
153  ASSERT_EQ(cache.result, vk::Result::eSuccess);
154  ASSERT_FALSE(fml::FileExists(temp_dir.fd(), "flutter.impeller.vkcache"));
155  ASSERT_TRUE(PipelineCacheDataPersist(
156  temp_dir.fd(), caps.GetPhysicalDeviceProperties(), cache.value));
157  }
158  ASSERT_TRUE(fml::FileExists(temp_dir.fd(), "flutter.impeller.vkcache"));
159  auto incompatible_caps = caps.GetPhysicalDeviceProperties();
160  // Simulate a driver version bump.
161  incompatible_caps.driverVersion =
162  caps.GetPhysicalDeviceProperties().driverVersion + 1u;
163  auto mapping = PipelineCacheDataRetrieve(temp_dir.fd(), incompatible_caps);
164  ASSERT_EQ(mapping, nullptr);
165 }
166 
167 } // namespace impeller::testing
static CapabilitiesVK & Cast(Capabilities &base)
Definition: backend_cast.h:13
TEST(AllocationSizeTest, CanCreateTypedAllocations)
TEST_P(AiksTest, DrawAtlasNoColor)
INSTANTIATE_VULKAN_PLAYGROUND_SUITE(DriverInfoVKTest)
std::unique_ptr< fml::Mapping > PipelineCacheDataRetrieve(const fml::UniqueFD &cache_directory, const VkPhysicalDeviceProperties &props)
Retrieve the previously persisted pipeline cache data. This function provides integrity checks the Vu...
bool PipelineCacheDataPersist(const fml::UniqueFD &cache_directory, const VkPhysicalDeviceProperties &props, const vk::UniquePipelineCache &cache)
Persist the pipeline cache to a file in the given cache directory. This function performs integrity c...
An Impeller specific header prepended to all pipeline cache information that is persisted on disk....
bool IsCompatibleWith(const PipelineCacheHeaderVK &other) const
Determines whether the specified o is compatible with.