7 #include "flutter/fml/make_copyable.h"
8 #include "flutter/fml/status_or.h"
9 #include "flutter/fml/trace_event.h"
22 vk::PipelineCreationFeedbackEXT feedback;
26 feedback.flags = vk::PipelineCreationFeedbackFlagBits::eValid;
33 return vk::FrontFace::eClockwise;
35 return vk::FrontFace::eCounterClockwise;
41 std::stringstream& stream,
42 const vk::PipelineCreationFeedbackEXT& feedback) {
43 const auto pipeline_cache_hit =
45 vk::PipelineCreationFeedbackFlagBits::eApplicationPipelineCacheHit;
46 const auto base_pipeline_accl =
48 vk::PipelineCreationFeedbackFlagBits::eBasePipelineAcceleration;
49 auto duration = std::chrono::duration_cast<MillisecondsF>(
50 std::chrono::nanoseconds{feedback.duration});
51 stream <<
"Time: " << duration.count() <<
"ms"
52 <<
" Cache Hit: " <<
static_cast<bool>(pipeline_cache_hit)
53 <<
" Base Accel: " <<
static_cast<bool>(base_pipeline_accl)
54 <<
" Thread: " << std::this_thread::get_id();
59 const vk::PipelineCreationFeedbackCreateInfoEXT& feedback) {
60 std::stringstream stream;
61 stream << std::fixed << std::showpoint << std::setprecision(2);
62 stream << std::endl <<
">>>>>>" << std::endl;
63 stream <<
"Pipeline '" << desc.
GetLabel() <<
"' ";
65 *feedback.pPipelineCreationFeedback);
66 if (feedback.pipelineStageCreationFeedbackCount != 0) {
69 for (
size_t i = 0, count = feedback.pipelineStageCreationFeedbackCount;
71 stream <<
"\tStage " << i + 1 <<
": ";
73 stream, feedback.pPipelineStageCreationFeedbacks[i]);
78 stream << std::endl <<
"<<<<<<" << std::endl;
79 FML_LOG(ERROR) << stream.str();
84 const vk::PipelineCreationFeedbackCreateInfoEXT& feedback) {
85 static int64_t gPipelineCacheHits = 0;
86 static int64_t gPipelineCacheMisses = 0;
87 static int64_t gPipelines = 0;
88 if (feedback.pPipelineCreationFeedback->flags &
89 vk::PipelineCreationFeedbackFlagBits::eApplicationPipelineCacheHit) {
92 gPipelineCacheMisses++;
95 static constexpr int64_t kImpellerPipelineTraceID = 1988;
96 FML_TRACE_COUNTER(
"impeller",
98 kImpellerPipelineTraceID,
99 "PipelineCacheHits", gPipelineCacheHits,
100 "PipelineCacheMisses", gPipelineCacheMisses,
101 "TotalPipelines", gPipelines
107 const vk::PipelineCreationFeedbackCreateInfoEXT& feedback) {
108 constexpr
bool kReportPipelineCreationFeedbackToLogs =
false;
109 constexpr
bool kReportPipelineCreationFeedbackToTraces =
true;
110 if (kReportPipelineCreationFeedbackToLogs) {
113 if (kReportPipelineCreationFeedbackToTraces) {
127 const vk::Device& device,
155 auto pass = builder.
Build(device);
163 "Compat Render Pass: " + desc.
GetLabel());
169 fml::StatusOr<vk::UniqueDescriptorSetLayout> MakeDescriptorSetLayout(
170 const PipelineDescriptor& desc,
171 const std::shared_ptr<DeviceHolderVK>& device_holder,
172 const std::shared_ptr<SamplerVK>& immutable_sampler) {
173 std::vector<vk::DescriptorSetLayoutBinding> set_bindings;
175 vk::Sampler vk_immutable_sampler =
176 immutable_sampler ? immutable_sampler->GetSampler()
177 :
static_cast<vk::Sampler
>(VK_NULL_HANDLE);
179 for (
auto layout : desc.GetVertexDescriptor()->GetDescriptorSetLayouts()) {
180 vk::DescriptorSetLayoutBinding set_binding;
181 set_binding.binding = layout.binding;
182 set_binding.descriptorCount = 1u;
191 if (vk_immutable_sampler &&
193 set_binding.setImmutableSamplers(vk_immutable_sampler);
195 set_bindings.push_back(set_binding);
198 vk::DescriptorSetLayoutCreateInfo desc_set_layout_info;
199 desc_set_layout_info.setBindings(set_bindings);
201 auto [descs_result, descs_layout] =
202 device_holder->GetDevice().createDescriptorSetLayoutUnique(
203 desc_set_layout_info);
204 if (descs_result != vk::Result::eSuccess) {
206 return {fml::Status(fml::StatusCode::kUnknown,
207 "unable to create uniform descriptors")};
211 "Descriptor Set Layout " + desc.GetLabel());
213 return fml::StatusOr<vk::UniqueDescriptorSetLayout>(std::move(descs_layout));
216 fml::StatusOr<vk::UniquePipelineLayout> MakePipelineLayout(
217 const PipelineDescriptor& desc,
218 const std::shared_ptr<DeviceHolderVK>& device_holder,
219 const vk::DescriptorSetLayout& descs_layout) {
220 vk::PipelineLayoutCreateInfo pipeline_layout_info;
221 pipeline_layout_info.setSetLayouts(descs_layout);
222 auto pipeline_layout = device_holder->GetDevice().createPipelineLayoutUnique(
223 pipeline_layout_info);
224 if (pipeline_layout.result != vk::Result::eSuccess) {
225 VALIDATION_LOG <<
"Could not create pipeline layout for pipeline "
226 << desc.GetLabel() <<
": "
227 << vk::to_string(pipeline_layout.result);
228 return {fml::Status(fml::StatusCode::kUnknown,
229 "Could not create pipeline layout for pipeline.")};
233 "Pipeline Layout " + desc.GetLabel());
235 return std::move(pipeline_layout.value);
238 fml::StatusOr<vk::UniquePipeline> MakePipeline(
239 const PipelineDescriptor& desc,
240 const std::shared_ptr<DeviceHolderVK>& device_holder,
241 const std::shared_ptr<PipelineCacheVK>& pso_cache,
242 const vk::PipelineLayout& pipeline_layout,
243 const vk::RenderPass& render_pass) {
244 vk::StructureChain<vk::GraphicsPipelineCreateInfo,
245 vk::PipelineCreationFeedbackCreateInfoEXT>
248 const auto* caps = pso_cache->GetCapabilities();
250 const auto supports_pipeline_creation_feedback = caps->HasExtension(
252 if (!supports_pipeline_creation_feedback) {
253 chain.unlink<vk::PipelineCreationFeedbackCreateInfoEXT>();
256 auto& pipeline_info = chain.get<vk::GraphicsPipelineCreateInfo>();
257 pipeline_info.setLayout(pipeline_layout);
262 vk::PipelineDynamicStateCreateInfo dynamic_create_state_info;
263 std::vector<vk::DynamicState> dynamic_states = {
264 vk::DynamicState::eViewport,
265 vk::DynamicState::eScissor,
266 vk::DynamicState::eStencilReference,
268 dynamic_create_state_info.setDynamicStates(dynamic_states);
269 pipeline_info.setPDynamicState(&dynamic_create_state_info);
274 vk::PipelineViewportStateCreateInfo viewport_state;
275 viewport_state.setViewportCount(1u);
276 viewport_state.setScissorCount(1u);
279 pipeline_info.setPViewportState(&viewport_state);
284 const auto& constants = desc.GetSpecializationConstants();
286 std::vector<std::vector<vk::SpecializationMapEntry>> map_entries(
287 desc.GetStageEntrypoints().size());
288 std::vector<vk::SpecializationInfo> specialization_infos(
289 desc.GetStageEntrypoints().size());
290 std::vector<vk::PipelineShaderStageCreateInfo> shader_stages;
292 size_t entrypoint_count = 0;
293 for (
const auto& entrypoint : desc.GetStageEntrypoints()) {
295 if (!stage.has_value()) {
298 return {fml::Status(fml::StatusCode::kUnknown,
299 "Unsupported shader type in pipeline.")};
302 std::vector<vk::SpecializationMapEntry>& entries =
303 map_entries[entrypoint_count];
304 for (
auto i = 0u; i < constants.size(); i++) {
305 vk::SpecializationMapEntry entry;
306 entry.offset = (i *
sizeof(
Scalar));
307 entry.size =
sizeof(
Scalar);
308 entry.constantID = i;
309 entries.emplace_back(entry);
312 vk::SpecializationInfo& specialization_info =
313 specialization_infos[entrypoint_count];
314 specialization_info.setMapEntries(map_entries[entrypoint_count]);
315 specialization_info.setPData(constants.data());
316 specialization_info.setDataSize(
sizeof(
Scalar) * constants.size());
318 vk::PipelineShaderStageCreateInfo info;
319 info.setStage(stage.value());
320 info.setPName(
"main");
323 info.setPSpecializationInfo(&specialization_info);
324 shader_stages.push_back(info);
327 pipeline_info.setStages(shader_stages);
332 vk::PipelineRasterizationStateCreateInfo rasterization_state;
333 rasterization_state.setFrontFace(
ToVKFrontFace(desc.GetWindingOrder()));
335 rasterization_state.setPolygonMode(
ToVKPolygonMode(desc.GetPolygonMode()));
336 rasterization_state.setLineWidth(1.0f);
337 rasterization_state.setDepthClampEnable(
false);
338 rasterization_state.setRasterizerDiscardEnable(
false);
339 pipeline_info.setPRasterizationState(&rasterization_state);
344 vk::PipelineMultisampleStateCreateInfo multisample_state;
345 multisample_state.setRasterizationSamples(
347 pipeline_info.setPMultisampleState(&multisample_state);
351 vk::PipelineInputAssemblyStateCreateInfo input_assembly;
353 input_assembly.setTopology(topology);
354 pipeline_info.setPInputAssemblyState(&input_assembly);
358 std::vector<vk::PipelineColorBlendAttachmentState> attachment_blend_state;
359 for (
const auto& color_desc : desc.GetColorAttachmentDescriptors()) {
363 attachment_blend_state.push_back(
366 vk::PipelineColorBlendStateCreateInfo blend_state;
367 blend_state.setAttachments(attachment_blend_state);
368 pipeline_info.setPColorBlendState(&blend_state);
373 pipeline_info.setBasePipelineHandle(VK_NULL_HANDLE);
374 pipeline_info.setSubpass(0u);
375 pipeline_info.setRenderPass(render_pass);
380 std::vector<vk::VertexInputAttributeDescription> attr_descs;
381 std::vector<vk::VertexInputBindingDescription> buffer_descs;
383 const auto& stage_inputs = desc.GetVertexDescriptor()->GetStageInputs();
384 const auto& stage_buffer_layouts =
385 desc.GetVertexDescriptor()->GetStageLayouts();
386 for (
const ShaderStageIOSlot& stage_in : stage_inputs) {
387 vk::VertexInputAttributeDescription attr_desc;
388 attr_desc.setBinding(stage_in.binding);
389 attr_desc.setLocation(stage_in.location);
391 attr_desc.setOffset(stage_in.offset);
392 attr_descs.push_back(attr_desc);
394 for (
const ShaderStageBufferLayout& layout : stage_buffer_layouts) {
395 vk::VertexInputBindingDescription binding_description;
396 binding_description.setBinding(layout.binding);
397 binding_description.setInputRate(vk::VertexInputRate::eVertex);
398 binding_description.setStride(layout.stride);
399 buffer_descs.push_back(binding_description);
402 vk::PipelineVertexInputStateCreateInfo vertex_input_state;
403 vertex_input_state.setVertexAttributeDescriptions(attr_descs);
404 vertex_input_state.setVertexBindingDescriptions(buffer_descs);
406 pipeline_info.setPVertexInputState(&vertex_input_state);
412 desc.GetDepthStencilAttachmentDescriptor(),
413 desc.GetFrontStencilAttachmentDescriptor(),
414 desc.GetBackStencilAttachmentDescriptor());
415 pipeline_info.setPDepthStencilState(&depth_stencil_state);
421 auto& feedback = chain.get<vk::PipelineCreationFeedbackCreateInfoEXT>();
423 std::vector<vk::PipelineCreationFeedbackEXT> stage_feedbacks(
425 feedback.setPPipelineCreationFeedback(&pipeline_feedback);
426 feedback.setPipelineStageCreationFeedbacks(stage_feedbacks);
431 auto pipeline = pso_cache->CreatePipeline(pipeline_info);
433 VALIDATION_LOG <<
"Could not create graphics pipeline: " << desc.GetLabel();
434 return {fml::Status(fml::StatusCode::kUnknown,
435 "Could not create graphics pipeline.")};
438 if (supports_pipeline_creation_feedback) {
443 "Pipeline " + desc.GetLabel());
445 return std::move(pipeline);
451 const std::shared_ptr<DeviceHolderVK>& device_holder,
452 const std::weak_ptr<PipelineLibrary>& weak_library,
453 std::shared_ptr<SamplerVK> immutable_sampler) {
454 TRACE_EVENT0(
"flutter",
"PipelineVK::Create");
456 auto library = weak_library.lock();
458 if (!device_holder || !library) {
464 fml::StatusOr<vk::UniqueDescriptorSetLayout> descs_layout =
465 MakeDescriptorSetLayout(desc, device_holder, immutable_sampler);
466 if (!descs_layout.ok()) {
470 fml::StatusOr<vk::UniquePipelineLayout> pipeline_layout =
471 MakePipelineLayout(desc, device_holder, descs_layout.value().get());
472 if (!pipeline_layout.ok()) {
476 vk::UniqueRenderPass render_pass =
483 fml::StatusOr<vk::UniquePipeline> pipeline =
484 MakePipeline(desc, device_holder, pso_cache,
485 pipeline_layout.value().get(), render_pass.get());
486 if (!pipeline.ok()) {
490 auto pipeline_vk = std::unique_ptr<PipelineVK>(
new PipelineVK(
494 std::move(pipeline.value()),
495 std::move(render_pass),
496 std::move(pipeline_layout.value()),
497 std::move(descs_layout.value()),
498 std::move(immutable_sampler)
500 if (!pipeline_vk->IsValid()) {
507 PipelineVK::PipelineVK(std::weak_ptr<DeviceHolderVK> device_holder,
508 std::weak_ptr<PipelineLibrary> library,
510 vk::UniquePipeline pipeline,
511 vk::UniqueRenderPass render_pass,
512 vk::UniquePipelineLayout layout,
513 vk::UniqueDescriptorSetLayout descriptor_set_layout,
514 std::shared_ptr<SamplerVK> immutable_sampler)
516 device_holder_(
std::move(device_holder)),
517 pipeline_(
std::move(pipeline)),
518 render_pass_(
std::move(render_pass)),
519 layout_(
std::move(layout)),
520 descriptor_set_layout_(
std::move(descriptor_set_layout)),
521 immutable_sampler_(
std::move(immutable_sampler)) {
522 is_valid_ = pipeline_ && render_pass_ && layout_ && descriptor_set_layout_;
526 if (
auto device = device_holder_.lock(); !device) {
527 descriptor_set_layout_.release();
529 render_pass_.release();
534 bool PipelineVK::IsValid()
const {
547 return *descriptor_set_layout_;
551 const std::shared_ptr<SamplerVK>& immutable_sampler)
const {
552 if (!immutable_sampler) {
556 Lock lock(immutable_sampler_variants_mutex_);
557 auto found = immutable_sampler_variants_.find(cache_key);
558 if (found != immutable_sampler_variants_.end()) {
559 return found->second;
561 auto device_holder = device_holder_.lock();
562 if (!device_holder) {
565 return (immutable_sampler_variants_[cache_key] =