Flutter Engine
The Flutter Engine
pipeline_cache_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
5// FLUTTER_NOLINT: https://github.com/flutter/flutter/issues/123467
6
8
9#include <sstream>
10
11#include "flutter/fml/mapping.h"
13
14namespace impeller {
15
16static constexpr const char* kPipelineCacheFileName =
17 "flutter.impeller.vkcache";
18
19static bool VerifyExistingCache(const fml::Mapping& mapping,
20 const CapabilitiesVK& caps) {
21 return true;
22}
23
24static std::shared_ptr<fml::Mapping> DecorateCacheWithMetadata(
25 std::shared_ptr<fml::Mapping> data) {
26 return data;
27}
28
29static std::unique_ptr<fml::Mapping> RemoveMetadataFromCache(
30 std::unique_ptr<fml::Mapping> data) {
31 return data;
32}
33
34static std::unique_ptr<fml::Mapping> OpenCacheFile(
35 const fml::UniqueFD& base_directory,
36 const std::string& cache_file_name,
37 const CapabilitiesVK& caps) {
38 if (!base_directory.is_valid()) {
39 return nullptr;
40 }
41 std::unique_ptr<fml::Mapping> mapping =
42 fml::FileMapping::CreateReadOnly(base_directory, cache_file_name);
43 if (!mapping) {
44 return nullptr;
45 }
46 if (!VerifyExistingCache(*mapping, caps)) {
47 return nullptr;
48 }
49 mapping = RemoveMetadataFromCache(std::move(mapping));
50 if (!mapping) {
51 return nullptr;
52 }
53 return mapping;
54}
55
56PipelineCacheVK::PipelineCacheVK(std::shared_ptr<const Capabilities> caps,
57 std::shared_ptr<DeviceHolderVK> device_holder,
58 fml::UniqueFD cache_directory)
59 : caps_(std::move(caps)),
60 device_holder_(device_holder),
61 cache_directory_(std::move(cache_directory)) {
62 if (!caps_ || !device_holder->GetDevice()) {
63 return;
64 }
65
66 const auto& vk_caps = CapabilitiesVK::Cast(*caps_);
67
68 auto existing_cache_data =
69 OpenCacheFile(cache_directory_, kPipelineCacheFileName, vk_caps);
70
71 vk::PipelineCacheCreateInfo cache_info;
72 if (existing_cache_data) {
73 cache_info.initialDataSize = existing_cache_data->GetSize();
74 cache_info.pInitialData = existing_cache_data->GetMapping();
75 }
76
77 auto [result, existing_cache] =
78 device_holder->GetDevice().createPipelineCacheUnique(cache_info);
79
80 if (result == vk::Result::eSuccess) {
81 cache_ = std::move(existing_cache);
82 } else {
83 // Even though we perform consistency checks because we don't trust the
84 // driver, the driver may have additional information that may cause it to
85 // reject the cache too.
86 FML_LOG(INFO) << "Existing pipeline cache was invalid: "
87 << vk::to_string(result) << ". Starting with a fresh cache.";
88 cache_info.pInitialData = nullptr;
89 cache_info.initialDataSize = 0u;
90 auto [result2, new_cache] =
91 device_holder->GetDevice().createPipelineCacheUnique(cache_info);
92 if (result2 == vk::Result::eSuccess) {
93 cache_ = std::move(new_cache);
94 } else {
95 VALIDATION_LOG << "Could not create new pipeline cache: "
96 << vk::to_string(result2);
97 }
98 }
99
100 is_valid_ = !!cache_;
101}
102
104 std::shared_ptr<DeviceHolderVK> device_holder = device_holder_.lock();
105 if (device_holder) {
106 cache_.reset();
107 } else {
108 cache_.release();
109 }
110}
111
113 return is_valid_;
114}
115
117 const vk::GraphicsPipelineCreateInfo& info) {
118 std::shared_ptr<DeviceHolderVK> strong_device = device_holder_.lock();
119 if (!strong_device) {
120 return {};
121 }
122
123 auto [result, pipeline] =
124 strong_device->GetDevice().createGraphicsPipelineUnique(*cache_, info);
125 if (result != vk::Result::eSuccess) {
126 VALIDATION_LOG << "Could not create graphics pipeline: "
128 }
129 return std::move(pipeline);
130}
131
133 const vk::ComputePipelineCreateInfo& info) {
134 std::shared_ptr<DeviceHolderVK> strong_device = device_holder_.lock();
135 if (!strong_device) {
136 return {};
137 }
138
139 auto [result, pipeline] =
140 strong_device->GetDevice().createComputePipelineUnique(*cache_, info);
141 if (result != vk::Result::eSuccess) {
142 VALIDATION_LOG << "Could not create compute pipeline: "
144 }
145 return std::move(pipeline);
146}
147
148std::shared_ptr<fml::Mapping> PipelineCacheVK::CopyPipelineCacheData() const {
149 std::shared_ptr<DeviceHolderVK> strong_device = device_holder_.lock();
150 if (!strong_device) {
151 return nullptr;
152 }
153
154 if (!IsValid()) {
155 return nullptr;
156 }
157 auto [result, data] =
158 strong_device->GetDevice().getPipelineCacheData(*cache_);
159 if (result != vk::Result::eSuccess) {
160 VALIDATION_LOG << "Could not get pipeline cache data to persist.";
161 return nullptr;
162 }
163 auto shared_data = std::make_shared<std::vector<uint8_t>>();
164 std::swap(*shared_data, data);
165 return std::make_shared<fml::NonOwnedMapping>(
166 shared_data->data(), shared_data->size(), [shared_data](auto, auto) {});
167}
168
170 if (!cache_directory_.is_valid()) {
171 return;
172 }
173 auto data = CopyPipelineCacheData();
174 if (!data) {
175 VALIDATION_LOG << "Could not copy pipeline cache data.";
176 return;
177 }
178 data = DecorateCacheWithMetadata(std::move(data));
179 if (!data) {
181 << "Could not decorate pipeline cache with additional metadata.";
182 return;
183 }
184 if (!fml::WriteAtomically(cache_directory_, kPipelineCacheFileName, *data)) {
185 VALIDATION_LOG << "Could not persist pipeline cache to disk.";
186 return;
187 }
188}
189
191 return CapabilitiesVK::Cast(caps_.get());
192}
193
194} // namespace impeller
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition: DM.cpp:213
void swap(sk_sp< T > &a, sk_sp< T > &b)
Definition: SkRefCnt.h:341
static std::unique_ptr< FileMapping > CreateReadOnly(const std::string &path)
Definition: mapping.cc:20
bool is_valid() const
Definition: unique_object.h:89
static CapabilitiesVK & Cast(Capabilities &base)
Definition: backend_cast.h:13
The Vulkan layers and extensions wrangler.
PipelineCacheVK(std::shared_ptr< const Capabilities > caps, std::shared_ptr< DeviceHolderVK > device_holder, fml::UniqueFD cache_directory)
vk::UniquePipeline CreatePipeline(const vk::GraphicsPipelineCreateInfo &info)
const CapabilitiesVK * GetCapabilities() const
GAsyncResult * result
#define FML_LOG(severity)
Definition: logging.h:82
bool WriteAtomically(const fml::UniqueFD &base_directory, const char *file_name, const Mapping &mapping)
Definition: file_posix.cc:191
static std::unique_ptr< fml::Mapping > OpenCacheFile(const fml::UniqueFD &base_directory, const std::string &cache_file_name, const CapabilitiesVK &caps)
static std::unique_ptr< fml::Mapping > RemoveMetadataFromCache(std::unique_ptr< fml::Mapping > data)
static std::shared_ptr< fml::Mapping > DecorateCacheWithMetadata(std::shared_ptr< fml::Mapping > data)
static bool VerifyExistingCache(const fml::Mapping &mapping, const CapabilitiesVK &caps)
static constexpr const char * kPipelineCacheFileName
Definition: ref_ptr.h:256
static SkString to_string(int n)
Definition: nanobench.cpp:119
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:63
#define VALIDATION_LOG
Definition: validation.h:73