Flutter Impeller
pipeline_cache_data_vk.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 
6 
7 #include "flutter/fml/file.h"
10 
11 namespace impeller {
12 
13 static constexpr const char* kPipelineCacheFileName =
14  "flutter.impeller.vkcache";
15 
16 bool PipelineCacheDataPersist(const fml::UniqueFD& cache_directory,
17  const VkPhysicalDeviceProperties& props,
18  const vk::UniquePipelineCache& cache) {
19  if (!cache_directory.is_valid()) {
20  return false;
21  }
22  size_t data_size = 0u;
23  if (cache.getOwner().getPipelineCacheData(*cache, &data_size, nullptr) !=
24  vk::Result::eSuccess) {
25  VALIDATION_LOG << "Could not fetch pipeline cache size.";
26  return false;
27  }
28  if (data_size == 0u) {
29  return true;
30  }
31  auto allocation = std::make_shared<Allocation>();
32  if (!allocation->Truncate(Bytes{sizeof(PipelineCacheHeaderVK) + data_size},
33  false)) {
34  VALIDATION_LOG << "Could not allocate pipeline cache data staging buffer.";
35  return false;
36  }
37  // Read the cache data and obtain the actual data size (which may be smaller
38  // than the original query for the data size if rendering operations happened
39  // after that call)
40  vk::Result lookup_result = cache.getOwner().getPipelineCacheData(
41  *cache, &data_size,
42  allocation->GetBuffer() + sizeof(PipelineCacheHeaderVK));
43 
44  // Some drivers may return incomplete erroneously, but this is not an
45  // error condition as some/all data was still written.
46  if (lookup_result != vk::Result::eSuccess &&
47  lookup_result != vk::Result::eIncomplete) {
48  VALIDATION_LOG << "Could not copy pipeline cache data.";
49  return false;
50  }
51 
52  const auto header = PipelineCacheHeaderVK{props, data_size};
53  std::memcpy(allocation->GetBuffer(), &header, sizeof(header));
54 
55  fml::NonOwnedMapping allocation_mapping(
56  allocation->GetBuffer(), sizeof(PipelineCacheHeaderVK) + data_size);
57  if (!fml::WriteAtomically(cache_directory, kPipelineCacheFileName,
58  allocation_mapping)) {
59  VALIDATION_LOG << "Could not write cache file to disk.";
60  return false;
61  }
62  return true;
63 }
64 
65 std::unique_ptr<fml::Mapping> PipelineCacheDataRetrieve(
66  const fml::UniqueFD& cache_directory,
67  const VkPhysicalDeviceProperties& props) {
68  if (!cache_directory.is_valid()) {
69  return nullptr;
70  }
71  std::shared_ptr<fml::FileMapping> on_disk_data =
72  fml::FileMapping::CreateReadOnly(cache_directory, kPipelineCacheFileName);
73  if (!on_disk_data) {
74  return nullptr;
75  }
76  if (on_disk_data->GetSize() < sizeof(PipelineCacheHeaderVK)) {
77  VALIDATION_LOG << "Pipeline cache data size is too small.";
78  return nullptr;
79  }
80  auto on_disk_header = PipelineCacheHeaderVK{};
81  std::memcpy(&on_disk_header, //
82  on_disk_data->GetMapping(), //
83  sizeof(on_disk_header) //
84  );
85  const auto current_header = PipelineCacheHeaderVK{props, 0u};
86  if (!on_disk_header.IsCompatibleWith(current_header)) {
87  FML_LOG(WARNING)
88  << "Persisted pipeline cache is not compatible with current "
89  "Vulkan context. Ignoring.";
90  return nullptr;
91  }
92  // Zero sized data is known to cause issues.
93  if (on_disk_header.data_size == 0u) {
94  return nullptr;
95  }
96  return std::make_unique<fml::NonOwnedMapping>(
97  on_disk_data->GetMapping() + sizeof(on_disk_header),
98  on_disk_header.data_size, [on_disk_data](auto, auto) {});
99 }
100 
102 
104  const VkPhysicalDeviceProperties& props,
105  uint64_t p_data_size)
106  : driver_version(props.driverVersion),
107  vendor_id(props.vendorID),
108  device_id(props.deviceID),
109  data_size(p_data_size) {
110  std::memcpy(uuid, props.pipelineCacheUUID, VK_UUID_SIZE);
111 }
112 
114  const PipelineCacheHeaderVK& o) const {
115  // Check for everything but the data size.
116  return magic == o.magic && //
117  driver_version == o.driver_version && //
118  vendor_id == o.vendor_id && //
119  device_id == o.device_id && //
120  abi == o.abi && //
121  std::memcmp(uuid, o.uuid, VK_UUID_SIZE) == 0;
122 }
123 
124 } // namespace impeller
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...
static constexpr const char * kPipelineCacheFileName
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.
PipelineCacheHeaderVK()
Constructs a new empty instance.
#define VALIDATION_LOG
Definition: validation.h:91