7 #include "flutter/fml/make_copyable.h"
8 #include "flutter/fml/status_or.h"
9 #include "flutter/fml/trace_event.h"
23 vk::PipelineCreationFeedbackEXT feedback;
27 feedback.flags = vk::PipelineCreationFeedbackFlagBits::eValid;
34 return vk::FrontFace::eClockwise;
36 return vk::FrontFace::eCounterClockwise;
42 std::stringstream& stream,
43 const vk::PipelineCreationFeedbackEXT& feedback) {
44 const auto pipeline_cache_hit =
46 vk::PipelineCreationFeedbackFlagBits::eApplicationPipelineCacheHit;
47 const auto base_pipeline_accl =
49 vk::PipelineCreationFeedbackFlagBits::eBasePipelineAcceleration;
50 auto duration = std::chrono::duration_cast<MillisecondsF>(
51 std::chrono::nanoseconds{feedback.duration});
52 stream <<
"Time: " << duration.count() <<
"ms"
53 <<
" Cache Hit: " <<
static_cast<bool>(pipeline_cache_hit)
54 <<
" Base Accel: " <<
static_cast<bool>(base_pipeline_accl)
55 <<
" Thread: " << std::this_thread::get_id();
60 const vk::PipelineCreationFeedbackCreateInfoEXT& feedback) {
61 std::stringstream stream;
62 stream << std::fixed << std::showpoint << std::setprecision(2);
63 stream << std::endl <<
">>>>>>" << std::endl;
64 stream <<
"Pipeline '" << desc.
GetLabel() <<
"' ";
66 *feedback.pPipelineCreationFeedback);
67 if (feedback.pipelineStageCreationFeedbackCount != 0) {
70 for (
size_t i = 0, count = feedback.pipelineStageCreationFeedbackCount;
72 stream <<
"\tStage " << i + 1 <<
": ";
74 stream, feedback.pPipelineStageCreationFeedbacks[i]);
79 stream << std::endl <<
"<<<<<<" << std::endl;
80 FML_LOG(ERROR) << stream.str();
85 const vk::PipelineCreationFeedbackCreateInfoEXT& feedback) {
86 static int64_t gPipelineCacheHits = 0;
87 static int64_t gPipelineCacheMisses = 0;
88 static int64_t gPipelines = 0;
89 if (feedback.pPipelineCreationFeedback->flags &
90 vk::PipelineCreationFeedbackFlagBits::eApplicationPipelineCacheHit) {
93 gPipelineCacheMisses++;
96 static constexpr int64_t kImpellerPipelineTraceID = 1988;
97 FML_TRACE_COUNTER(
"impeller",
99 kImpellerPipelineTraceID,
100 "PipelineCacheHits", gPipelineCacheHits,
101 "PipelineCacheMisses", gPipelineCacheMisses,
102 "TotalPipelines", gPipelines
108 const vk::PipelineCreationFeedbackCreateInfoEXT& feedback) {
109 constexpr
bool kReportPipelineCreationFeedbackToLogs =
false;
110 constexpr
bool kReportPipelineCreationFeedbackToTraces =
true;
111 if (kReportPipelineCreationFeedbackToLogs) {
114 if (kReportPipelineCreationFeedbackToTraces) {
128 const vk::Device& device,
156 auto pass = builder.
Build(device);
163 #ifdef IMPELLER_DEBUG
173 fml::StatusOr<vk::UniqueDescriptorSetLayout> MakeDescriptorSetLayout(
174 const PipelineDescriptor& desc,
175 const std::shared_ptr<DeviceHolderVK>& device_holder,
176 const std::shared_ptr<SamplerVK>& immutable_sampler) {
177 std::vector<vk::DescriptorSetLayoutBinding> set_bindings;
179 vk::Sampler vk_immutable_sampler =
180 immutable_sampler ? immutable_sampler->GetSampler()
181 :
static_cast<vk::Sampler
>(VK_NULL_HANDLE);
183 for (
auto layout : desc.GetVertexDescriptor()->GetDescriptorSetLayouts()) {
184 vk::DescriptorSetLayoutBinding set_binding;
185 set_binding.binding = layout.binding;
186 set_binding.descriptorCount = 1u;
195 if (vk_immutable_sampler &&
197 set_binding.setImmutableSamplers(vk_immutable_sampler);
199 set_bindings.push_back(set_binding);
202 vk::DescriptorSetLayoutCreateInfo desc_set_layout_info;
203 desc_set_layout_info.setBindings(set_bindings);
205 auto [descs_result, descs_layout] =
206 device_holder->GetDevice().createDescriptorSetLayoutUnique(
207 desc_set_layout_info);
208 if (descs_result != vk::Result::eSuccess) {
210 return {fml::Status(fml::StatusCode::kUnknown,
211 "unable to create uniform descriptors")};
214 #ifdef IMPELLER_DEBUG
216 device_holder->GetDevice(), descs_layout.get(),
217 SPrintF(
"Descriptor Set Layout: %s", desc.GetLabel().data()));
220 return fml::StatusOr<vk::UniqueDescriptorSetLayout>(std::move(descs_layout));
223 fml::StatusOr<vk::UniquePipelineLayout> MakePipelineLayout(
224 const PipelineDescriptor& desc,
225 const std::shared_ptr<DeviceHolderVK>& device_holder,
226 const vk::DescriptorSetLayout& descs_layout) {
227 vk::PipelineLayoutCreateInfo pipeline_layout_info;
228 pipeline_layout_info.setSetLayouts(descs_layout);
229 auto pipeline_layout = device_holder->GetDevice().createPipelineLayoutUnique(
230 pipeline_layout_info);
231 if (pipeline_layout.result != vk::Result::eSuccess) {
232 VALIDATION_LOG <<
"Could not create pipeline layout for pipeline "
233 << desc.GetLabel() <<
": "
234 << vk::to_string(pipeline_layout.result);
235 return {fml::Status(fml::StatusCode::kUnknown,
236 "Could not create pipeline layout for pipeline.")};
239 #ifdef IMPELLER_DEBUG
241 device_holder->GetDevice(), *pipeline_layout.value,
242 SPrintF(
"Pipeline Layout %s", desc.GetLabel().data()));
245 return std::move(pipeline_layout.value);
248 fml::StatusOr<vk::UniquePipeline> MakePipeline(
249 const PipelineDescriptor& desc,
250 const std::shared_ptr<DeviceHolderVK>& device_holder,
251 const std::shared_ptr<PipelineCacheVK>& pso_cache,
252 const vk::PipelineLayout& pipeline_layout,
253 const vk::RenderPass& render_pass) {
254 vk::StructureChain<vk::GraphicsPipelineCreateInfo,
255 vk::PipelineCreationFeedbackCreateInfoEXT>
258 const auto* caps = pso_cache->GetCapabilities();
260 const auto supports_pipeline_creation_feedback = caps->HasExtension(
262 if (!supports_pipeline_creation_feedback) {
263 chain.unlink<vk::PipelineCreationFeedbackCreateInfoEXT>();
266 auto& pipeline_info = chain.get<vk::GraphicsPipelineCreateInfo>();
267 pipeline_info.setLayout(pipeline_layout);
272 vk::PipelineDynamicStateCreateInfo dynamic_create_state_info;
273 std::vector<vk::DynamicState> dynamic_states = {
274 vk::DynamicState::eViewport,
275 vk::DynamicState::eScissor,
276 vk::DynamicState::eStencilReference,
278 dynamic_create_state_info.setDynamicStates(dynamic_states);
279 pipeline_info.setPDynamicState(&dynamic_create_state_info);
284 vk::PipelineViewportStateCreateInfo viewport_state;
285 viewport_state.setViewportCount(1u);
286 viewport_state.setScissorCount(1u);
289 pipeline_info.setPViewportState(&viewport_state);
294 const auto& constants = desc.GetSpecializationConstants();
296 std::vector<std::vector<vk::SpecializationMapEntry>> map_entries(
297 desc.GetStageEntrypoints().size());
298 std::vector<vk::SpecializationInfo> specialization_infos(
299 desc.GetStageEntrypoints().size());
300 std::vector<vk::PipelineShaderStageCreateInfo> shader_stages;
302 size_t entrypoint_count = 0;
303 for (
const auto& entrypoint : desc.GetStageEntrypoints()) {
305 if (!stage.has_value()) {
308 return {fml::Status(fml::StatusCode::kUnknown,
309 "Unsupported shader type in pipeline.")};
312 std::vector<vk::SpecializationMapEntry>& entries =
313 map_entries[entrypoint_count];
314 for (
auto i = 0u; i < constants.size(); i++) {
315 vk::SpecializationMapEntry entry;
316 entry.offset = (i *
sizeof(
Scalar));
317 entry.size =
sizeof(
Scalar);
318 entry.constantID = i;
319 entries.emplace_back(entry);
322 vk::SpecializationInfo& specialization_info =
323 specialization_infos[entrypoint_count];
324 specialization_info.setMapEntries(map_entries[entrypoint_count]);
325 specialization_info.setPData(constants.data());
326 specialization_info.setDataSize(
sizeof(
Scalar) * constants.size());
328 vk::PipelineShaderStageCreateInfo info;
329 info.setStage(stage.value());
330 info.setPName(
"main");
333 info.setPSpecializationInfo(&specialization_info);
334 shader_stages.push_back(info);
337 pipeline_info.setStages(shader_stages);
342 vk::PipelineRasterizationStateCreateInfo rasterization_state;
343 rasterization_state.setFrontFace(
ToVKFrontFace(desc.GetWindingOrder()));
345 rasterization_state.setPolygonMode(
ToVKPolygonMode(desc.GetPolygonMode()));
346 rasterization_state.setLineWidth(1.0f);
347 rasterization_state.setDepthClampEnable(
false);
348 rasterization_state.setRasterizerDiscardEnable(
false);
349 pipeline_info.setPRasterizationState(&rasterization_state);
354 vk::PipelineMultisampleStateCreateInfo multisample_state;
355 multisample_state.setRasterizationSamples(
357 pipeline_info.setPMultisampleState(&multisample_state);
361 vk::PipelineInputAssemblyStateCreateInfo input_assembly;
363 input_assembly.setTopology(topology);
364 input_assembly.setPrimitiveRestartEnable(
365 caps->SupportsPrimitiveRestart() &&
367 pipeline_info.setPInputAssemblyState(&input_assembly);
371 std::vector<vk::PipelineColorBlendAttachmentState> attachment_blend_state;
372 for (
const auto& color_desc : desc.GetColorAttachmentDescriptors()) {
376 attachment_blend_state.push_back(
379 vk::PipelineColorBlendStateCreateInfo blend_state;
380 blend_state.setAttachments(attachment_blend_state);
381 pipeline_info.setPColorBlendState(&blend_state);
386 pipeline_info.setBasePipelineHandle(VK_NULL_HANDLE);
387 pipeline_info.setSubpass(0u);
388 pipeline_info.setRenderPass(render_pass);
393 std::vector<vk::VertexInputAttributeDescription> attr_descs;
394 std::vector<vk::VertexInputBindingDescription> buffer_descs;
396 const auto& stage_inputs = desc.GetVertexDescriptor()->GetStageInputs();
397 const auto& stage_buffer_layouts =
398 desc.GetVertexDescriptor()->GetStageLayouts();
399 for (
const ShaderStageIOSlot& stage_in : stage_inputs) {
400 vk::VertexInputAttributeDescription attr_desc;
401 attr_desc.setBinding(stage_in.binding);
402 attr_desc.setLocation(stage_in.location);
404 attr_desc.setOffset(stage_in.offset);
405 attr_descs.push_back(attr_desc);
407 for (
const ShaderStageBufferLayout& layout : stage_buffer_layouts) {
408 vk::VertexInputBindingDescription binding_description;
409 binding_description.setBinding(layout.binding);
410 binding_description.setInputRate(vk::VertexInputRate::eVertex);
411 binding_description.setStride(layout.stride);
412 buffer_descs.push_back(binding_description);
415 vk::PipelineVertexInputStateCreateInfo vertex_input_state;
416 vertex_input_state.setVertexAttributeDescriptions(attr_descs);
417 vertex_input_state.setVertexBindingDescriptions(buffer_descs);
419 pipeline_info.setPVertexInputState(&vertex_input_state);
425 desc.GetDepthStencilAttachmentDescriptor(),
426 desc.GetFrontStencilAttachmentDescriptor(),
427 desc.GetBackStencilAttachmentDescriptor());
428 pipeline_info.setPDepthStencilState(&depth_stencil_state);
434 auto& feedback = chain.get<vk::PipelineCreationFeedbackCreateInfoEXT>();
436 std::vector<vk::PipelineCreationFeedbackEXT> stage_feedbacks(
438 feedback.setPPipelineCreationFeedback(&pipeline_feedback);
439 feedback.setPipelineStageCreationFeedbacks(stage_feedbacks);
444 auto pipeline = pso_cache->CreatePipeline(pipeline_info);
446 VALIDATION_LOG <<
"Could not create graphics pipeline: " << desc.GetLabel();
447 return {fml::Status(fml::StatusCode::kUnknown,
448 "Could not create graphics pipeline.")};
451 if (supports_pipeline_creation_feedback) {
455 #ifdef IMPELLER_DEBUG
457 SPrintF(
"Pipeline %s", desc.GetLabel().data()));
460 return std::move(pipeline);
466 const std::shared_ptr<DeviceHolderVK>& device_holder,
467 const std::weak_ptr<PipelineLibrary>& weak_library,
469 std::shared_ptr<SamplerVK> immutable_sampler) {
470 TRACE_EVENT1(
"flutter",
"PipelineVK::Create",
"Name", desc.
GetLabel().data());
472 auto library = weak_library.lock();
474 if (!device_holder || !library) {
480 fml::StatusOr<vk::UniqueDescriptorSetLayout> descs_layout =
481 MakeDescriptorSetLayout(desc, device_holder, immutable_sampler);
482 if (!descs_layout.ok()) {
486 fml::StatusOr<vk::UniquePipelineLayout> pipeline_layout =
487 MakePipelineLayout(desc, device_holder, descs_layout.value().get());
488 if (!pipeline_layout.ok()) {
492 vk::UniqueRenderPass render_pass =
499 fml::StatusOr<vk::UniquePipeline> pipeline =
500 MakePipeline(desc, device_holder, pso_cache,
501 pipeline_layout.value().get(), render_pass.get());
502 if (!pipeline.ok()) {
507 auto pipeline_vk = std::unique_ptr<PipelineVK>(
new PipelineVK(
511 std::move(pipeline.value()),
512 std::move(render_pass),
513 std::move(pipeline_layout.value()),
514 std::move(descs_layout.value()),
516 std::move(immutable_sampler)
518 if (!pipeline_vk->IsValid()) {
525 PipelineVK::PipelineVK(std::weak_ptr<DeviceHolderVK> device_holder,
526 std::weak_ptr<PipelineLibrary> library,
528 vk::UniquePipeline pipeline,
529 vk::UniqueRenderPass render_pass,
530 vk::UniquePipelineLayout layout,
531 vk::UniqueDescriptorSetLayout descriptor_set_layout,
533 std::shared_ptr<SamplerVK> immutable_sampler)
535 device_holder_(
std::move(device_holder)),
536 pipeline_(
std::move(pipeline)),
537 render_pass_(
std::move(render_pass)),
538 layout_(
std::move(layout)),
539 descriptor_set_layout_(
std::move(descriptor_set_layout)),
540 immutable_sampler_(
std::move(immutable_sampler)),
541 pipeline_key_(pipeline_key) {
542 is_valid_ = pipeline_ && render_pass_ && layout_ && descriptor_set_layout_;
546 if (
auto device = device_holder_.lock(); !device) {
547 descriptor_set_layout_.release();
549 render_pass_.release();
554 bool PipelineVK::IsValid()
const {
567 return *descriptor_set_layout_;
571 const std::shared_ptr<SamplerVK>& immutable_sampler)
const {
572 if (!immutable_sampler) {
576 Lock lock(immutable_sampler_variants_mutex_);
577 auto found = immutable_sampler_variants_.find(cache_key);
578 if (found != immutable_sampler_variants_.end()) {
579 return found->second;
581 auto device_holder = device_holder_.lock();
582 if (!device_holder) {
587 return (immutable_sampler_variants_[cache_key] =
static ShaderFunctionVK & Cast(ShaderFunction &base)
bool SetDebugName(T handle, std::string_view label) const
std::string_view GetLabel() const
PixelFormat GetDepthPixelFormat() const
std::optional< DepthAttachmentDescriptor > GetDepthStencilAttachmentDescriptor() const
PixelFormat GetStencilPixelFormat() const
const std::map< size_t, ColorAttachmentDescriptor > & GetColorAttachmentDescriptors() const
bool HasStencilAttachmentDescriptors() const
SampleCount GetSampleCount() const
Describes the fixed function and programmable aspects of rendering and compute operations performed b...
const std::weak_ptr< PipelineLibrary > library_
const PipelineDescriptor desc_
const std::shared_ptr< PipelineCacheVK > & GetPSOCache() const
std::shared_ptr< PipelineVK > CreateVariantForImmutableSamplers(const std::shared_ptr< SamplerVK > &immutable_sampler) const
const vk::PipelineLayout & GetPipelineLayout() const
const vk::DescriptorSetLayout & GetDescriptorSetLayout() const
vk::Pipeline GetPipeline() const
static std::unique_ptr< PipelineVK > Create(const PipelineDescriptor &desc, const std::shared_ptr< DeviceHolderVK > &device_holder, const std::weak_ptr< PipelineLibrary > &weak_library, PipelineKey pipeline_key, std::shared_ptr< SamplerVK > immutable_sampler={})
RenderPassBuilderVK & SetDepthStencilAttachment(PixelFormat format, SampleCount sample_count, LoadAction load_action, StoreAction store_action)
RenderPassBuilderVK & SetStencilAttachment(PixelFormat format, SampleCount sample_count, LoadAction load_action, StoreAction store_action)
RenderPassBuilderVK & SetColorAttachment(size_t index, PixelFormat format, SampleCount sample_count, LoadAction load_action, StoreAction store_action, vk::ImageLayout current_layout=vk::ImageLayout::eUndefined, bool is_swapchain=false)
vk::UniqueRenderPass Build(const vk::Device &device) const
vk::Format ToVertexDescriptorFormat(const ShaderStageIOSlot &input)
static void ReportPipelineCreationFeedback(const PipelineDescriptor &desc, const vk::PipelineCreationFeedbackCreateInfoEXT &feedback)
constexpr vk::PipelineColorBlendAttachmentState ToVKPipelineColorBlendAttachmentState(const ColorAttachmentDescriptor &desc)
static vk::PipelineCreationFeedbackEXT EmptyFeedback()
constexpr vk::SampleCountFlagBits ToVKSampleCountFlagBits(SampleCount count)
constexpr std::optional< vk::ShaderStageFlagBits > ToVKShaderStageFlagBits(ShaderStage stage)
constexpr vk::DescriptorType ToVKDescriptorType(DescriptorType type)
constexpr vk::PolygonMode ToVKPolygonMode(PolygonMode mode)
std::string SPrintF(const char *format,...)
constexpr vk::CullModeFlags ToVKCullModeFlags(CullMode mode)
static void ReportPipelineCreationFeedbackToLog(std::stringstream &stream, const vk::PipelineCreationFeedbackEXT &feedback)
vk::PipelineDepthStencilStateCreateInfo ToVKPipelineDepthStencilStateCreateInfo(std::optional< DepthAttachmentDescriptor > depth, std::optional< StencilAttachmentDescriptor > front, std::optional< StencilAttachmentDescriptor > back)
constexpr bool PrimitiveTopologySupportsPrimitiveRestart(PrimitiveType primitive)
constexpr vk::FrontFace ToVKFrontFace(WindingOrder order)
constexpr vk::ShaderStageFlags ToVkShaderStage(ShaderStage stage)
constexpr vk::PrimitiveTopology ToVKPrimitiveTopology(PrimitiveType primitive)
static void ReportPipelineCreationFeedbackToTrace(const PipelineDescriptor &desc, const vk::PipelineCreationFeedbackCreateInfoEXT &feedback)
static vk::UniqueRenderPass CreateCompatRenderPassForPipeline(const vk::Device &device, const PipelineDescriptor &desc)
@ kEXTPipelineCreationFeedback