20PipelineLibraryVK::PipelineLibraryVK(
21 const std::shared_ptr<DeviceHolderVK>& device_holder,
22 std::shared_ptr<const Capabilities> caps,
24 std::shared_ptr<fml::ConcurrentTaskRunner> worker_task_runner)
25 : device_holder_(device_holder),
26 pso_cache_(
std::make_shared<PipelineCacheVK>(
std::move(caps),
28 std::move(cache_directory))),
29 worker_task_runner_(
std::move(worker_task_runner)),
30 compile_queue_(PipelineCompileQueue::
Create(worker_task_runner_)) {
32 if (!pso_cache_->IsValid() || !worker_task_runner_) {
39PipelineLibraryVK::~PipelineLibraryVK() =
default;
42bool PipelineLibraryVK::IsValid()
const {
46std::unique_ptr<ComputePipelineVK> PipelineLibraryVK::CreateComputePipeline(
47 const ComputePipelineDescriptor& desc,
48 PipelineKey pipeline_key) {
50 vk::ComputePipelineCreateInfo pipeline_info;
55 const auto entrypoint = desc.GetStageEntrypoint();
61 std::shared_ptr<DeviceHolderVK> strong_device = device_holder_.lock();
65 auto device_properties = strong_device->GetPhysicalDevice().getProperties();
66 auto max_wg_size = device_properties.limits.maxComputeWorkGroupSize;
70 vk::SpecializationMapEntry specialization_map_entry[1];
72 uint32_t workgroup_size_x = max_wg_size[0];
73 specialization_map_entry[0].constantID = 0;
74 specialization_map_entry[0].offset = 0;
75 specialization_map_entry[0].size =
sizeof(uint32_t);
77 vk::SpecializationInfo specialization_info;
78 specialization_info.mapEntryCount = 1;
79 specialization_info.pMapEntries = &specialization_map_entry[0];
80 specialization_info.dataSize =
sizeof(uint32_t);
81 specialization_info.pData = &workgroup_size_x;
83 vk::PipelineShaderStageCreateInfo info;
84 info.setStage(vk::ShaderStageFlagBits::eCompute);
85 info.setPName(
"main");
86 info.setModule(ShaderFunctionVK::Cast(entrypoint.get())->GetModule());
87 info.setPSpecializationInfo(&specialization_info);
88 pipeline_info.setStage(info);
93 std::vector<vk::DescriptorSetLayoutBinding> desc_bindings;
95 for (
auto layout : desc.GetDescriptorSetLayouts()) {
97 desc_bindings.push_back(vk_desc_layout);
100 vk::DescriptorSetLayoutCreateInfo descs_layout_info;
101 descs_layout_info.setBindings(desc_bindings);
103 auto [descs_result, descs_layout] =
104 strong_device->GetDevice().createDescriptorSetLayoutUnique(
106 if (descs_result != vk::Result::eSuccess) {
111 ContextVK::SetDebugName(strong_device->GetDevice(), descs_layout.get(),
112 "Descriptor Set Layout " + desc.GetLabel());
117 vk::PipelineLayoutCreateInfo pipeline_layout_info;
118 pipeline_layout_info.setSetLayouts(descs_layout.get());
119 auto pipeline_layout = strong_device->GetDevice().createPipelineLayoutUnique(
120 pipeline_layout_info);
121 if (pipeline_layout.result != vk::Result::eSuccess) {
122 VALIDATION_LOG <<
"Could not create pipeline layout for pipeline "
123 << desc.GetLabel() <<
": "
124 << vk::to_string(pipeline_layout.result);
127 pipeline_info.setLayout(pipeline_layout.value.get());
132 auto pipeline = pso_cache_->CreatePipeline(pipeline_info);
134 VALIDATION_LOG <<
"Could not create graphics pipeline: " << desc.GetLabel();
138 ContextVK::SetDebugName(strong_device->GetDevice(), *pipeline_layout.value,
139 "Pipeline Layout " + desc.GetLabel());
140 ContextVK::SetDebugName(strong_device->GetDevice(), *pipeline,
141 "Pipeline " + desc.GetLabel());
143 return std::make_unique<ComputePipelineVK>(
148 std::move(pipeline_layout.value),
149 std::move(descs_layout),
154PipelineFuture<PipelineDescriptor> PipelineLibraryVK::GetPipeline(
155 PipelineDescriptor descriptor,
158 Lock lock(pipelines_mutex_);
160 return found->second;
167 RealizedFuture<std::shared_ptr<Pipeline<PipelineDescriptor>>>(
nullptr)};
170 auto promise = std::make_shared<
171 NoExceptionPromise<std::shared_ptr<Pipeline<PipelineDescriptor>>>>();
172 auto pipeline_future =
173 PipelineFuture<PipelineDescriptor>{descriptor, promise->get_future()};
176 auto weak_this = weak_from_this();
179 auto generation_task = [descriptor, weak_this, promise, next_key]() {
180 auto thiz = weak_this.lock();
182 promise->set_value(
nullptr);
186 promise->set_value(PipelineVK::Create(
188 PipelineLibraryVK::Cast(*thiz).device_holder_.lock(),
195 compile_queue_->PostJobForDescriptor(descriptor,
196 std::move(generation_task));
201 return pipeline_future;
205PipelineFuture<ComputePipelineDescriptor> PipelineLibraryVK::GetPipeline(
206 ComputePipelineDescriptor descriptor,
208 Lock lock(pipelines_mutex_);
209 if (
auto found = compute_pipelines_.find(descriptor);
210 found != compute_pipelines_.end()) {
211 return found->second;
218 RealizedFuture<std::shared_ptr<Pipeline<ComputePipelineDescriptor>>>(
222 auto promise = std::make_shared<
223 std::promise<std::shared_ptr<Pipeline<ComputePipelineDescriptor>>>>();
224 auto pipeline_future = PipelineFuture<ComputePipelineDescriptor>{
225 descriptor, promise->get_future()};
226 compute_pipelines_[descriptor] = pipeline_future;
228 auto weak_this = weak_from_this();
231 auto generation_task = [descriptor, weak_this, promise, next_key]() {
232 auto self = weak_this.lock();
234 promise->set_value(
nullptr);
235 VALIDATION_LOG <<
"Pipeline library was collected before the pipeline "
240 auto pipeline = PipelineLibraryVK::Cast(*self).CreateComputePipeline(
241 descriptor, next_key);
243 promise->set_value(
nullptr);
244 VALIDATION_LOG <<
"Could not create pipeline: " << descriptor.GetLabel();
248 promise->set_value(std::move(pipeline));
252 worker_task_runner_->PostTask(generation_task);
257 return pipeline_future;
261bool PipelineLibraryVK::HasPipeline(
const PipelineDescriptor& descriptor) {
262 Lock lock(pipelines_mutex_);
267void PipelineLibraryVK::RemovePipelinesWithEntryPoint(
268 std::shared_ptr<const ShaderFunction> function) {
269 Lock lock(pipelines_mutex_);
272 return item->first.GetEntrypointForStage(
function->GetStage())
273 ->IsEqual(*function);
277void PipelineLibraryVK::DidAcquireSurfaceFrame() {
278 if (++frames_acquired_ == 50u) {
280 cache_dirty_ =
false;
281 PersistPipelineCacheToDisk();
283 frames_acquired_ = 0;
287void PipelineLibraryVK::PersistPipelineCacheToDisk() {
288 worker_task_runner_->PostTask(
289 [weak_cache =
decltype(pso_cache_)::weak_type(pso_cache_)]() {
290 auto cache = weak_cache.lock();
294 cache->PersistCacheToDisk();
298const std::shared_ptr<PipelineCacheVK>& PipelineLibraryVK::GetPSOCache()
const {
302const std::shared_ptr<fml::ConcurrentTaskRunner>&
303PipelineLibraryVK::GetWorkerTaskRunner()
const {
304 return worker_task_runner_;
308 return compile_queue_.get();
A task queue designed for managing compilation of pipeline state objects.
std::vector< std::pair< uint64_t, std::unique_ptr< GenericRenderPipelineHandle > > > pipelines_
#define FML_DCHECK(condition)
Dart_NativeFunction function
void erase_if(Collection &container, const std::function< bool(typename Collection::iterator)> &predicate)
ScopedObject< Object > Create(CtorArgs &&... args)
constexpr vk::DescriptorSetLayoutBinding ToVKDescriptorSetLayoutBinding(const DescriptorSetLayout &layout)
#define TRACE_EVENT0(category_group, name)