24 vk::PipelineCreationFeedbackEXT feedback;
28 feedback.flags = vk::PipelineCreationFeedbackFlagBits::eValid;
35 return vk::FrontFace::eClockwise;
37 return vk::FrontFace::eCounterClockwise;
43 std::stringstream& stream,
44 const vk::PipelineCreationFeedbackEXT& feedback) {
45 const auto pipeline_cache_hit =
47 vk::PipelineCreationFeedbackFlagBits::eApplicationPipelineCacheHit;
48 const auto base_pipeline_accl =
50 vk::PipelineCreationFeedbackFlagBits::eBasePipelineAcceleration;
51 auto duration = std::chrono::duration_cast<MillisecondsF>(
52 std::chrono::nanoseconds{feedback.duration});
53 stream <<
"Time: " << duration.count() <<
"ms"
54 <<
" Cache Hit: " <<
static_cast<bool>(pipeline_cache_hit)
55 <<
" Base Accel: " <<
static_cast<bool>(base_pipeline_accl)
56 <<
" Thread: " << std::this_thread::get_id();
61 const vk::PipelineCreationFeedbackCreateInfoEXT& feedback) {
62 std::stringstream stream;
63 stream << std::fixed << std::showpoint << std::setprecision(2);
64 stream << std::endl <<
">>>>>>" << std::endl;
65 stream <<
"Pipeline '" << desc.
GetLabel() <<
"' ";
67 *feedback.pPipelineCreationFeedback);
68 if (feedback.pipelineStageCreationFeedbackCount != 0) {
71 for (
size_t i = 0, count = feedback.pipelineStageCreationFeedbackCount;
73 stream <<
"\tStage " <<
i + 1 <<
": ";
75 stream, feedback.pPipelineStageCreationFeedbacks[
i]);
80 stream << std::endl <<
"<<<<<<" << std::endl;
86 const vk::PipelineCreationFeedbackCreateInfoEXT& feedback) {
87 static int64_t gPipelineCacheHits = 0;
88 static int64_t gPipelineCacheMisses = 0;
89 static int64_t gPipelines = 0;
90 if (feedback.pPipelineCreationFeedback->flags &
91 vk::PipelineCreationFeedbackFlagBits::eApplicationPipelineCacheHit) {
94 gPipelineCacheMisses++;
97 static constexpr int64_t kImpellerPipelineTraceID = 1988;
100 kImpellerPipelineTraceID,
101 "PipelineCacheHits", gPipelineCacheHits,
102 "PipelineCacheMisses", gPipelineCacheMisses,
103 "TotalPipelines", gPipelines
109 const vk::PipelineCreationFeedbackCreateInfoEXT& feedback) {
110 constexpr bool kReportPipelineCreationFeedbackToLogs =
false;
111 constexpr bool kReportPipelineCreationFeedbackToTraces =
true;
112 if (kReportPipelineCreationFeedbackToLogs) {
115 if (kReportPipelineCreationFeedbackToTraces) {
167 std::format(
"Compat Render Pass: {}", desc.
GetLabel()));
175 const PipelineDescriptor& desc,
176 const std::shared_ptr<DeviceHolderVK>& device_holder,
177 const std::shared_ptr<SamplerVK>& immutable_sampler) {
178 std::vector<vk::DescriptorSetLayoutBinding> set_bindings;
180 vk::Sampler vk_immutable_sampler =
181 immutable_sampler ? immutable_sampler->GetSampler()
182 :
static_cast<vk::Sampler
>(VK_NULL_HANDLE);
184 for (
auto layout : desc.GetVertexDescriptor()->GetDescriptorSetLayouts()) {
185 vk::DescriptorSetLayoutBinding set_binding;
186 set_binding.binding = layout.binding;
187 set_binding.descriptorCount = 1u;
196 if (vk_immutable_sampler &&
198 set_binding.setImmutableSamplers(vk_immutable_sampler);
200 set_bindings.push_back(set_binding);
203 vk::DescriptorSetLayoutCreateInfo desc_set_layout_info;
204 desc_set_layout_info.setBindings(set_bindings);
206 auto [descs_result, descs_layout] =
207 device_holder->GetDevice().createDescriptorSetLayoutUnique(
208 desc_set_layout_info);
209 if (descs_result != vk::Result::eSuccess) {
212 "unable to create uniform descriptors")};
217 device_holder->GetDevice(), descs_layout.get(),
218 std::format(
"Descriptor Set Layout: {}", desc.GetLabel()));
225 const PipelineDescriptor& desc,
226 const std::shared_ptr<DeviceHolderVK>& device_holder,
227 const vk::DescriptorSetLayout& descs_layout) {
228 vk::PipelineLayoutCreateInfo pipeline_layout_info;
229 pipeline_layout_info.setSetLayouts(descs_layout);
230 auto pipeline_layout = device_holder->GetDevice().createPipelineLayoutUnique(
231 pipeline_layout_info);
232 if (pipeline_layout.result != vk::Result::eSuccess) {
233 VALIDATION_LOG <<
"Could not create pipeline layout for pipeline "
234 << desc.GetLabel() <<
": "
235 << vk::to_string(pipeline_layout.result);
237 "Could not create pipeline layout for pipeline.")};
242 std::format(
"Pipeline Layout {}", desc.GetLabel()));
245 return std::move(pipeline_layout.value);
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()) {
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();
448 "Could not create graphics pipeline.")};
451 if (supports_pipeline_creation_feedback) {
457 std::format(
"Pipeline {}", desc.GetLabel()));
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) {
472 auto library = weak_library.lock();
474 if (!device_holder || !library) {
481 MakeDescriptorSetLayout(desc, device_holder, immutable_sampler);
482 if (!descs_layout.
ok()) {
487 MakePipelineLayout(desc, device_holder, descs_layout.
value().get());
488 if (!pipeline_layout.
ok()) {
492 vk::UniqueRenderPass render_pass =
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()) {
525PipelineVK::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)),
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_;
547 descriptor_set_layout_.release();
549 render_pass_.release();
554bool 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
#define FML_LOG(severity)
#define FML_UNREACHABLE()
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 vk::DescriptorType ToVKDescriptorType(DescriptorType type)
constexpr vk::PolygonMode ToVKPolygonMode(PolygonMode mode)
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 std::optional< vk::ShaderStageFlagBits > ToVKShaderStageFlagBits(ShaderStage stage)
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
#define FML_TRACE_COUNTER(category_group, name, counter_id, arg1,...)
#define TRACE_EVENT1(category_group, name, arg1_name, arg1_val)