11 #include "flutter/fml/container.h"
12 #include "flutter/fml/trace_event.h"
24 PipelineLibraryVK::PipelineLibraryVK(
25 const std::shared_ptr<DeviceHolder>& device_holder,
26 std::shared_ptr<const Capabilities> caps,
27 fml::UniqueFD cache_directory,
28 std::shared_ptr<fml::ConcurrentTaskRunner> worker_task_runner)
29 : device_holder_(device_holder),
30 pso_cache_(
std::make_shared<PipelineCacheVK>(
std::move(caps),
32 std::move(cache_directory))),
33 worker_task_runner_(
std::move(worker_task_runner)) {
34 FML_DCHECK(worker_task_runner_);
35 if (!pso_cache_->IsValid() || !worker_task_runner_) {
45 bool PipelineLibraryVK::IsValid()
const {
66 vk::ImageLayout::eUndefined
79 const vk::Device& device,
81 std::vector<vk::AttachmentDescription> attachments;
83 std::vector<vk::AttachmentReference> color_refs;
92 color_refs[bind_point] =
93 vk::AttachmentReference{
static_cast<uint32_t
>(attachments.size()),
94 vk::ImageLayout::eColorAttachmentOptimal};
95 attachments.emplace_back(
101 depth_stencil_ref = vk::AttachmentReference{
102 static_cast<uint32_t
>(attachments.size()),
103 vk::ImageLayout::eDepthStencilAttachmentOptimal};
108 depth_stencil_ref = vk::AttachmentReference{
109 static_cast<uint32_t
>(attachments.size()),
110 vk::ImageLayout::eDepthStencilAttachmentOptimal};
115 vk::SubpassDescription subpass_desc;
116 subpass_desc.pipelineBindPoint = vk::PipelineBindPoint::eGraphics;
117 subpass_desc.setColorAttachments(color_refs);
118 subpass_desc.setPDepthStencilAttachment(&depth_stencil_ref);
120 vk::RenderPassCreateInfo render_pass_desc;
121 render_pass_desc.setAttachments(attachments);
122 render_pass_desc.setPSubpasses(&subpass_desc);
123 render_pass_desc.setSubpassCount(1u);
125 auto [result, pass] = device.createRenderPassUnique(render_pass_desc);
126 if (result != vk::Result::eSuccess) {
128 << desc.
GetLabel() <<
"'. Error: " << vk::to_string(result);
137 "Compat Render Pass: " + desc.
GetLabel());
139 return std::move(pass);
145 return vk::FrontFace::eClockwise;
147 return vk::FrontFace::eCounterClockwise;
153 vk::PipelineCreationFeedbackEXT feedback;
157 feedback.flags = vk::PipelineCreationFeedbackFlagBits::eValid;
162 std::stringstream& stream,
163 const vk::PipelineCreationFeedbackEXT& feedback) {
164 const auto pipeline_cache_hit =
166 vk::PipelineCreationFeedbackFlagBits::eApplicationPipelineCacheHit;
167 const auto base_pipeline_accl =
169 vk::PipelineCreationFeedbackFlagBits::eBasePipelineAcceleration;
170 auto duration = std::chrono::duration_cast<MillisecondsF>(
171 std::chrono::nanoseconds{feedback.duration});
172 stream <<
"Time: " << duration.count() <<
"ms"
173 <<
" Cache Hit: " <<
static_cast<bool>(pipeline_cache_hit)
174 <<
" Base Accel: " <<
static_cast<bool>(base_pipeline_accl)
175 <<
" Thread: " << std::this_thread::get_id();
180 const vk::PipelineCreationFeedbackCreateInfoEXT& feedback) {
181 std::stringstream stream;
182 stream << std::fixed << std::showpoint << std::setprecision(2);
183 stream << std::endl <<
">>>>>>" << std::endl;
184 stream <<
"Pipeline '" << desc.
GetLabel() <<
"' ";
186 *feedback.pPipelineCreationFeedback);
187 if (feedback.pipelineStageCreationFeedbackCount != 0) {
190 for (
size_t i = 0, count = feedback.pipelineStageCreationFeedbackCount;
192 stream <<
"\tStage " << i + 1 <<
": ";
194 stream, feedback.pPipelineStageCreationFeedbacks[i]);
195 if (i != count - 1) {
199 stream << std::endl <<
"<<<<<<" << std::endl;
200 FML_LOG(ERROR) << stream.str();
205 const vk::PipelineCreationFeedbackCreateInfoEXT& feedback) {
206 static int64_t gPipelineCacheHits = 0;
207 static int64_t gPipelineCacheMisses = 0;
208 static int64_t gPipelines = 0;
209 if (feedback.pPipelineCreationFeedback->flags &
210 vk::PipelineCreationFeedbackFlagBits::eApplicationPipelineCacheHit) {
211 gPipelineCacheHits++;
213 gPipelineCacheMisses++;
216 static constexpr int64_t kImpellerPipelineTraceID = 1988;
217 FML_TRACE_COUNTER(
"impeller",
219 kImpellerPipelineTraceID,
220 "PipelineCacheHits", gPipelineCacheHits,
221 "PipelineCacheMisses", gPipelineCacheMisses,
222 "TotalPipelines", gPipelines
228 const vk::PipelineCreationFeedbackCreateInfoEXT& feedback) {
229 constexpr
bool kReportPipelineCreationFeedbackToLogs =
false;
230 constexpr
bool kReportPipelineCreationFeedbackToTraces =
true;
231 if (kReportPipelineCreationFeedbackToLogs) {
234 if (kReportPipelineCreationFeedbackToTraces) {
239 std::unique_ptr<PipelineVK> PipelineLibraryVK::CreatePipeline(
240 const PipelineDescriptor& desc) {
241 TRACE_EVENT0(
"flutter", __FUNCTION__);
242 vk::StructureChain<vk::GraphicsPipelineCreateInfo,
243 vk::PipelineCreationFeedbackCreateInfoEXT>
246 const auto& supports_pipeline_creation_feedback =
247 pso_cache_->GetCapabilities()->HasOptionalDeviceExtension(
249 if (!supports_pipeline_creation_feedback) {
250 chain.unlink<vk::PipelineCreationFeedbackCreateInfoEXT>();
253 auto& pipeline_info = chain.get<vk::GraphicsPipelineCreateInfo>();
258 vk::PipelineDynamicStateCreateInfo dynamic_create_state_info;
259 std::vector<vk::DynamicState> dynamic_states = {
260 vk::DynamicState::eViewport,
261 vk::DynamicState::eScissor,
262 vk::DynamicState::eStencilReference,
264 dynamic_create_state_info.setDynamicStates(dynamic_states);
265 pipeline_info.setPDynamicState(&dynamic_create_state_info);
270 vk::PipelineViewportStateCreateInfo viewport_state;
271 viewport_state.setViewportCount(1u);
272 viewport_state.setScissorCount(1u);
275 pipeline_info.setPViewportState(&viewport_state);
280 std::vector<vk::PipelineShaderStageCreateInfo> shader_stages;
281 for (
const auto& entrypoint : desc.GetStageEntrypoints()) {
283 if (!stage.has_value()) {
288 vk::PipelineShaderStageCreateInfo info;
289 info.setStage(stage.value());
290 info.setPName(
"main");
293 shader_stages.push_back(info);
295 pipeline_info.setStages(shader_stages);
300 vk::PipelineRasterizationStateCreateInfo rasterization_state;
301 rasterization_state.setFrontFace(
ToVKFrontFace(desc.GetWindingOrder()));
303 rasterization_state.setPolygonMode(
ToVKPolygonMode(desc.GetPolygonMode()));
304 rasterization_state.setLineWidth(1.0f);
305 rasterization_state.setDepthClampEnable(
false);
306 rasterization_state.setRasterizerDiscardEnable(
false);
307 pipeline_info.setPRasterizationState(&rasterization_state);
312 vk::PipelineMultisampleStateCreateInfo multisample_state;
313 multisample_state.setRasterizationSamples(
315 pipeline_info.setPMultisampleState(&multisample_state);
319 vk::PipelineInputAssemblyStateCreateInfo input_assembly;
321 input_assembly.setTopology(topology);
322 pipeline_info.setPInputAssemblyState(&input_assembly);
326 std::vector<vk::PipelineColorBlendAttachmentState> attachment_blend_state;
327 for (
const auto& color_desc : desc.GetColorAttachmentDescriptors()) {
331 attachment_blend_state.push_back(
334 vk::PipelineColorBlendStateCreateInfo blend_state;
335 blend_state.setAttachments(attachment_blend_state);
336 pipeline_info.setPColorBlendState(&blend_state);
338 std::shared_ptr<DeviceHolder> strong_device = device_holder_.lock();
339 if (!strong_device) {
346 pipeline_info.setBasePipelineHandle(VK_NULL_HANDLE);
347 pipeline_info.setSubpass(0);
348 pipeline_info.setRenderPass(render_pass.get());
356 std::vector<vk::VertexInputAttributeDescription> attr_descs;
357 std::vector<vk::VertexInputBindingDescription> buffer_descs;
359 const auto& stage_inputs = desc.GetVertexDescriptor()->GetStageInputs();
360 const auto& stage_buffer_layouts =
361 desc.GetVertexDescriptor()->GetStageLayouts();
362 for (
const ShaderStageIOSlot& stage_in : stage_inputs) {
363 vk::VertexInputAttributeDescription attr_desc;
364 attr_desc.setBinding(stage_in.binding);
365 attr_desc.setLocation(stage_in.location);
367 attr_desc.setOffset(stage_in.offset);
368 attr_descs.push_back(attr_desc);
370 for (
const ShaderStageBufferLayout& layout : stage_buffer_layouts) {
371 vk::VertexInputBindingDescription binding_description;
372 binding_description.setBinding(layout.binding);
373 binding_description.setInputRate(vk::VertexInputRate::eVertex);
374 binding_description.setStride(layout.stride);
375 buffer_descs.push_back(binding_description);
378 vk::PipelineVertexInputStateCreateInfo vertex_input_state;
379 vertex_input_state.setVertexAttributeDescriptions(attr_descs);
380 vertex_input_state.setVertexBindingDescriptions(buffer_descs);
382 pipeline_info.setPVertexInputState(&vertex_input_state);
387 std::vector<vk::DescriptorSetLayoutBinding> desc_bindings;
389 for (
auto layout : desc.GetVertexDescriptor()->GetDescriptorSetLayouts()) {
391 desc_bindings.push_back(vk_desc_layout);
394 vk::DescriptorSetLayoutCreateInfo descs_layout_info;
395 descs_layout_info.setBindings(desc_bindings);
397 auto [descs_result, descs_layout] =
398 strong_device->GetDevice().createDescriptorSetLayoutUnique(
400 if (descs_result != vk::Result::eSuccess) {
406 "Descriptor Set Layout " + desc.GetLabel());
411 vk::PipelineLayoutCreateInfo pipeline_layout_info;
412 pipeline_layout_info.setSetLayouts(descs_layout.get());
413 auto pipeline_layout = strong_device->GetDevice().createPipelineLayoutUnique(
414 pipeline_layout_info);
415 if (pipeline_layout.result != vk::Result::eSuccess) {
416 VALIDATION_LOG <<
"Could not create pipeline layout for pipeline "
417 << desc.GetLabel() <<
": "
418 << vk::to_string(pipeline_layout.result);
421 pipeline_info.setLayout(pipeline_layout.value.get());
427 desc.GetDepthStencilAttachmentDescriptor(),
428 desc.GetFrontStencilAttachmentDescriptor(),
429 desc.GetBackStencilAttachmentDescriptor());
430 pipeline_info.setPDepthStencilState(&depth_stencil_state);
436 auto& feedback = chain.get<vk::PipelineCreationFeedbackCreateInfoEXT>();
438 std::vector<vk::PipelineCreationFeedbackEXT> stage_feedbacks(
440 feedback.setPPipelineCreationFeedback(&pipeline_feedback);
441 feedback.setPipelineStageCreationFeedbacks(stage_feedbacks);
446 auto pipeline = pso_cache_->CreatePipeline(pipeline_info);
448 VALIDATION_LOG <<
"Could not create graphics pipeline: " << desc.GetLabel();
452 if (supports_pipeline_creation_feedback) {
457 "Pipeline Layout " + desc.GetLabel());
459 "Pipeline " + desc.GetLabel());
461 return std::make_unique<PipelineVK>(device_holder_,
465 std::move(render_pass),
466 std::move(pipeline_layout.value),
467 std::move(descs_layout)
471 std::unique_ptr<ComputePipelineVK> PipelineLibraryVK::CreateComputePipeline(
472 const ComputePipelineDescriptor& desc) {
473 TRACE_EVENT0(
"flutter", __FUNCTION__);
474 vk::ComputePipelineCreateInfo pipeline_info;
479 const auto entrypoint = desc.GetStageEntrypoint();
485 std::shared_ptr<DeviceHolder> strong_device = device_holder_.lock();
486 if (!strong_device) {
489 auto device_properties = strong_device->GetPhysicalDevice().getProperties();
490 auto max_wg_size = device_properties.limits.maxComputeWorkGroupSize;
494 vk::SpecializationMapEntry specialization_map_entry[1];
496 uint32_t workgroup_size_x = max_wg_size[0];
497 specialization_map_entry[0].constantID = 0;
498 specialization_map_entry[0].offset = 0;
499 specialization_map_entry[0].size =
sizeof(uint32_t);
501 vk::SpecializationInfo specialization_info;
502 specialization_info.mapEntryCount = 1;
503 specialization_info.pMapEntries = &specialization_map_entry[0];
504 specialization_info.dataSize =
sizeof(uint32_t);
505 specialization_info.pData = &workgroup_size_x;
507 vk::PipelineShaderStageCreateInfo info;
508 info.setStage(vk::ShaderStageFlagBits::eCompute);
509 info.setPName(
"main");
511 info.setPSpecializationInfo(&specialization_info);
512 pipeline_info.setStage(info);
517 std::vector<vk::DescriptorSetLayoutBinding> desc_bindings;
519 for (
auto layout : desc.GetDescriptorSetLayouts()) {
521 desc_bindings.push_back(vk_desc_layout);
524 vk::DescriptorSetLayoutCreateInfo descs_layout_info;
525 descs_layout_info.setBindings(desc_bindings);
527 auto [descs_result, descs_layout] =
528 strong_device->GetDevice().createDescriptorSetLayoutUnique(
530 if (descs_result != vk::Result::eSuccess) {
536 "Descriptor Set Layout " + desc.GetLabel());
541 vk::PipelineLayoutCreateInfo pipeline_layout_info;
542 pipeline_layout_info.setSetLayouts(descs_layout.get());
543 auto pipeline_layout = strong_device->GetDevice().createPipelineLayoutUnique(
544 pipeline_layout_info);
545 if (pipeline_layout.result != vk::Result::eSuccess) {
546 VALIDATION_LOG <<
"Could not create pipeline layout for pipeline "
547 << desc.GetLabel() <<
": "
548 << vk::to_string(pipeline_layout.result);
551 pipeline_info.setLayout(pipeline_layout.value.get());
556 auto pipeline = pso_cache_->CreatePipeline(pipeline_info);
558 VALIDATION_LOG <<
"Could not create graphics pipeline: " << desc.GetLabel();
563 "Pipeline Layout " + desc.GetLabel());
565 "Pipeline " + desc.GetLabel());
567 return std::make_unique<ComputePipelineVK>(
572 std::move(pipeline_layout.value),
573 std::move(descs_layout)
578 PipelineFuture<PipelineDescriptor> PipelineLibraryVK::GetPipeline(
579 PipelineDescriptor descriptor) {
580 Lock lock(pipelines_mutex_);
581 if (
auto found = pipelines_.find(descriptor); found != pipelines_.end()) {
582 return found->second;
588 RealizedFuture<std::shared_ptr<Pipeline<PipelineDescriptor>>>(
nullptr)};
591 auto promise = std::make_shared<
592 std::promise<std::shared_ptr<Pipeline<PipelineDescriptor>>>>();
593 auto pipeline_future =
594 PipelineFuture<PipelineDescriptor>{descriptor, promise->get_future()};
595 pipelines_[descriptor] = pipeline_future;
597 auto weak_this = weak_from_this();
599 worker_task_runner_->PostTask([descriptor, weak_this, promise]() {
600 auto thiz = weak_this.lock();
602 promise->set_value(
nullptr);
603 VALIDATION_LOG <<
"Pipeline library was collected before the pipeline "
610 promise->set_value(
nullptr);
611 VALIDATION_LOG <<
"Could not create pipeline: " << descriptor.GetLabel();
615 promise->set_value(std::move(pipeline));
618 return pipeline_future;
622 PipelineFuture<ComputePipelineDescriptor> PipelineLibraryVK::GetPipeline(
623 ComputePipelineDescriptor descriptor) {
624 Lock lock(compute_pipelines_mutex_);
625 if (
auto found = compute_pipelines_.find(descriptor);
626 found != compute_pipelines_.end()) {
627 return found->second;
633 RealizedFuture<std::shared_ptr<Pipeline<ComputePipelineDescriptor>>>(
637 auto promise = std::make_shared<
638 std::promise<std::shared_ptr<Pipeline<ComputePipelineDescriptor>>>>();
639 auto pipeline_future = PipelineFuture<ComputePipelineDescriptor>{
640 descriptor, promise->get_future()};
641 compute_pipelines_[descriptor] = pipeline_future;
643 auto weak_this = weak_from_this();
645 worker_task_runner_->PostTask([descriptor, weak_this, promise]() {
646 auto self = weak_this.lock();
648 promise->set_value(
nullptr);
649 VALIDATION_LOG <<
"Pipeline library was collected before the pipeline "
657 promise->set_value(
nullptr);
658 VALIDATION_LOG <<
"Could not create pipeline: " << descriptor.GetLabel();
662 promise->set_value(std::move(pipeline));
665 return pipeline_future;
669 void PipelineLibraryVK::RemovePipelinesWithEntryPoint(
670 std::shared_ptr<const ShaderFunction>
function) {
671 Lock lock(pipelines_mutex_);
673 fml::erase_if(pipelines_, [&](
auto item) {
674 return item->first.GetEntrypointForStage(function->GetStage())
675 ->IsEqual(*
function);
680 if (++frames_acquired_ == 50u) {
681 PersistPipelineCacheToDisk();
685 void PipelineLibraryVK::PersistPipelineCacheToDisk() {
686 worker_task_runner_->PostTask(
687 [weak_cache = decltype(pso_cache_)::weak_type(pso_cache_)]() {
688 auto cache = weak_cache.lock();
692 cache->PersistCacheToDisk();