10 #include "fml/status.h"
37 vk::ClearColorValue
value;
45 vk::ClearDepthStencilValue
value;
47 value.stencil = stencil;
53 std::array<vk::ClearValue, kMaxAttachments>& values) {
56 [&values, &
offset](
size_t index,
60 values.at(offset++) = VKClearValueFromColor(attachment.clear_color);
68 if (depth.has_value()) {
70 stencil ? stencil->clear_stencil : 0u, depth->clear_depth);
71 }
else if (stencil.has_value()) {
73 stencil->clear_stencil, depth ? depth->clear_depth : 0.0f);
78 SharedHandleVK<vk::RenderPass> RenderPassVK::CreateVKRenderPass(
79 const ContextVK& context,
80 const SharedHandleVK<vk::RenderPass>& recycled_renderpass,
81 const std::shared_ptr<CommandBufferVK>& command_buffer)
const {
82 RenderPassBuilderVK builder;
85 const ColorAttachment&
87 builder.SetColorAttachment(
89 attachment.texture->GetTextureDescriptor().format,
90 attachment.texture->GetTextureDescriptor().sample_count,
91 attachment.load_action,
92 attachment.store_action,
99 builder.SetDepthStencilAttachment(
100 depth->texture->GetTextureDescriptor().format,
101 depth->texture->GetTextureDescriptor().sample_count,
106 stencil.has_value()) {
107 builder.SetStencilAttachment(
108 stencil->texture->GetTextureDescriptor().format,
109 stencil->texture->GetTextureDescriptor().sample_count,
110 stencil->load_action,
111 stencil->store_action
115 if (recycled_renderpass !=
nullptr) {
116 return recycled_renderpass;
119 auto pass = builder.Build(context.GetDevice());
122 VALIDATION_LOG <<
"Failed to create render pass for framebuffer.";
126 context.SetDebugName(pass.get(), debug_label_.c_str());
131 RenderPassVK::RenderPassVK(
const std::shared_ptr<const Context>& context,
132 const RenderTarget& target,
133 std::shared_ptr<CommandBufferVK> command_buffer)
134 : RenderPass(context, target), command_buffer_(
std::move(command_buffer)) {
135 const ColorAttachment& color0 = render_target_.GetColorAttachment(0);
136 color_image_vk_ = color0.texture;
137 resolve_image_vk_ = color0.resolve_texture;
140 command_buffer_vk_ = command_buffer_->GetCommandBuffer();
141 render_target_.IterateAllAttachments([&](
const auto& attachment) ->
bool {
142 command_buffer_->Track(attachment.texture);
143 command_buffer_->Track(attachment.resolve_texture);
147 SharedHandleVK<vk::RenderPass> recycled_render_pass;
148 SharedHandleVK<vk::Framebuffer> recycled_framebuffer;
149 if (resolve_image_vk_) {
150 recycled_render_pass =
152 recycled_framebuffer =
156 const auto& target_size = render_target_.GetRenderTargetSize();
159 CreateVKRenderPass(vk_context, recycled_render_pass, command_buffer_);
166 auto framebuffer = (recycled_framebuffer ==
nullptr)
167 ? CreateVKFramebuffer(vk_context, *render_pass_)
168 : recycled_framebuffer;
175 if (!command_buffer_->Track(framebuffer) ||
176 !command_buffer_->Track(render_pass_)) {
180 if (resolve_image_vk_) {
187 std::array<vk::ClearValue, kMaxAttachments> clears;
190 vk::RenderPassBeginInfo pass_info;
191 pass_info.renderPass = *render_pass_;
192 pass_info.framebuffer = *framebuffer;
193 pass_info.renderArea.extent.width =
static_cast<uint32_t
>(target_size.width);
194 pass_info.renderArea.extent.height =
195 static_cast<uint32_t
>(target_size.height);
196 pass_info.setPClearValues(clears.data());
197 pass_info.setClearValueCount(clear_count);
199 command_buffer_vk_.beginRenderPass(pass_info, vk::SubpassContents::eInline);
201 if (resolve_image_vk_) {
205 if (color_image_vk_) {
212 vk::Viewport viewport = vk::Viewport()
213 .setWidth(vp.rect.GetWidth())
214 .setHeight(-vp.rect.GetHeight())
215 .setY(vp.rect.GetHeight())
218 command_buffer_vk_.setViewport(0, 1, &viewport);
224 .setOffset(vk::Offset2D(sc.GetX(), sc.GetY()))
225 .setExtent(vk::Extent2D(sc.GetWidth(), sc.GetHeight()));
226 command_buffer_vk_.setScissor(0, 1, &scissor);
229 command_buffer_vk_.setStencilReference(
230 vk::StencilFaceFlagBits::eVkStencilFrontAndBack, 0u);
235 RenderPassVK::~RenderPassVK() =
default;
237 bool RenderPassVK::IsValid()
const {
241 void RenderPassVK::OnSetLabel(std::string_view label) {
242 #ifdef IMPELLER_DEBUG
243 ContextVK::Cast(*context_).SetDebugName(render_pass_->Get(), label.data());
247 SharedHandleVK<vk::Framebuffer> RenderPassVK::CreateVKFramebuffer(
248 const ContextVK& context,
249 const vk::RenderPass& pass)
const {
250 vk::FramebufferCreateInfo fb_info;
252 fb_info.renderPass = pass;
254 const auto target_size = render_target_.GetRenderTargetSize();
255 fb_info.width = target_size.width;
256 fb_info.height = target_size.height;
259 std::array<vk::ImageView, kMaxAttachments> attachments;
265 render_target_.IterateAllColorAttachments(
266 [&attachments, &count](
size_t index,
267 const ColorAttachment& attachment) ->
bool {
270 attachments[count++] =
271 TextureVK::Cast(*attachment.texture).GetRenderTargetView();
272 if (attachment.resolve_texture) {
273 attachments[count++] = TextureVK::Cast(*attachment.resolve_texture)
274 .GetRenderTargetView();
279 if (
auto depth = render_target_.GetDepthAttachment(); depth.has_value()) {
280 attachments[count++] =
281 TextureVK::Cast(*depth->texture).GetRenderTargetView();
282 }
else if (
auto stencil = render_target_.GetStencilAttachment();
283 stencil.has_value()) {
284 attachments[count++] =
285 TextureVK::Cast(*stencil->texture).GetRenderTargetView();
288 fb_info.setPAttachments(attachments.data());
289 fb_info.setAttachmentCount(count);
291 auto [result, framebuffer] =
292 context.GetDevice().createFramebufferUnique(fb_info);
294 if (result != vk::Result::eSuccess) {
295 VALIDATION_LOG <<
"Could not create framebuffer: " << vk::to_string(result);
303 void RenderPassVK::SetPipeline(
PipelineRef pipeline) {
304 pipeline_ = pipeline;
309 pipeline_uses_input_attachments_ =
310 pipeline_->GetDescriptor().GetVertexDescriptor()->UsesInputAttacments();
312 if (pipeline_uses_input_attachments_) {
317 vk::DescriptorImageInfo image_info;
318 image_info.imageLayout = vk::ImageLayout::eGeneral;
319 image_info.sampler = VK_NULL_HANDLE;
320 image_info.imageView = TextureVK::Cast(*color_image_vk_).GetImageView();
321 image_workspace_[bound_image_offset_++] = image_info;
323 vk::WriteDescriptorSet write_set;
325 write_set.descriptorCount = 1u;
326 write_set.descriptorType = vk::DescriptorType::eInputAttachment;
327 write_set.pImageInfo = &image_workspace_[bound_image_offset_ - 1];
329 write_workspace_[descriptor_write_offset_++] = write_set;
334 void RenderPassVK::SetCommandLabel(std::string_view label) {
335 #ifdef IMPELLER_DEBUG
336 command_buffer_->PushDebugGroup(label);
342 void RenderPassVK::SetStencilReference(uint32_t
value) {
343 command_buffer_vk_.setStencilReference(
344 vk::StencilFaceFlagBits::eVkStencilFrontAndBack,
value);
348 void RenderPassVK::SetBaseVertex(uint64_t
value) {
349 base_vertex_ =
value;
353 void RenderPassVK::SetViewport(Viewport viewport) {
354 vk::Viewport viewport_vk = vk::Viewport()
355 .setWidth(viewport.rect.GetWidth())
356 .setHeight(-viewport.rect.GetHeight())
357 .setY(viewport.rect.GetHeight())
360 command_buffer_vk_.setViewport(0, 1, &viewport_vk);
364 void RenderPassVK::SetScissor(
IRect scissor) {
365 vk::Rect2D scissor_vk =
367 .setOffset(vk::Offset2D(scissor.GetX(), scissor.GetY()))
368 .setExtent(vk::Extent2D(scissor.GetWidth(), scissor.GetHeight()));
369 command_buffer_vk_.setScissor(0, 1, &scissor_vk);
373 void RenderPassVK::SetElementCount(
size_t count) {
374 element_count_ = count;
378 void RenderPassVK::SetInstanceCount(
size_t count) {
379 instance_count_ = count;
383 bool RenderPassVK::SetVertexBuffer(BufferView vertex_buffers[],
384 size_t vertex_buffer_count) {
385 if (!ValidateVertexBuffers(vertex_buffers, vertex_buffer_count)) {
391 for (
size_t i = 0; i < vertex_buffer_count; i++) {
393 DeviceBufferVK::Cast(*vertex_buffers[i].GetBuffer()).GetBuffer();
394 vertex_buffer_offsets[i] = vertex_buffers[i].GetRange().offset;
395 std::shared_ptr<const DeviceBuffer> device_buffer =
396 vertex_buffers[i].TakeBuffer();
398 command_buffer_->Track(device_buffer);
403 command_buffer_vk_.bindVertexBuffers(0u, vertex_buffer_count, buffers,
404 vertex_buffer_offsets);
410 bool RenderPassVK::SetIndexBuffer(BufferView index_buffer,
412 if (!ValidateIndexBuffer(index_buffer, index_type)) {
416 if (index_type != IndexType::kNone) {
417 has_index_buffer_ =
true;
419 BufferView index_buffer_view = std::move(index_buffer);
420 if (!index_buffer_view) {
424 if (!index_buffer_view.GetBuffer()) {
426 <<
" for index buffer view";
430 std::shared_ptr<const DeviceBuffer> index_buffer =
431 index_buffer_view.TakeBuffer();
432 if (index_buffer && !command_buffer_->Track(index_buffer)) {
436 vk::Buffer index_buffer_handle =
437 DeviceBufferVK::Cast(*index_buffer_view.GetBuffer()).GetBuffer();
438 command_buffer_vk_.bindIndexBuffer(index_buffer_handle,
439 index_buffer_view.GetRange().offset,
442 has_index_buffer_ =
false;
449 fml::Status RenderPassVK::Draw() {
451 return fml::Status(fml::StatusCode::kCancelled,
452 "No valid pipeline is bound to the RenderPass.");
472 if (immutable_sampler_) {
473 std::shared_ptr<Pipeline<PipelineDescriptor>> pipeline_variant =
474 PipelineVK::Cast(*pipeline_)
475 .CreateVariantForImmutableSamplers(immutable_sampler_);
476 if (!pipeline_variant) {
478 fml::StatusCode::kAborted,
479 "Could not create pipeline variant with immutable sampler.");
481 pipeline_ = raw_ptr(pipeline_variant);
484 const auto& context_vk = ContextVK::Cast(*context_);
485 const auto& pipeline_vk = PipelineVK::Cast(*pipeline_);
487 auto descriptor_result = command_buffer_->AllocateDescriptorSets(
488 pipeline_vk.GetDescriptorSetLayout(), context_vk);
489 if (!descriptor_result.ok()) {
490 return fml::Status(fml::StatusCode::kAborted,
491 "Could not allocate descriptor sets.");
493 const auto descriptor_set = descriptor_result.value();
494 const auto pipeline_layout = pipeline_vk.GetPipelineLayout();
495 command_buffer_vk_.bindPipeline(vk::PipelineBindPoint::eGraphics,
496 pipeline_vk.GetPipeline());
498 for (
auto i = 0u; i < descriptor_write_offset_; i++) {
499 write_workspace_[i].dstSet = descriptor_set;
502 context_vk.GetDevice().updateDescriptorSets(descriptor_write_offset_,
503 write_workspace_.data(), 0u, {});
505 command_buffer_vk_.bindDescriptorSets(
506 vk::PipelineBindPoint::eGraphics,
515 if (pipeline_uses_input_attachments_) {
517 command_buffer_vk_, TextureVK::Cast(*color_image_vk_).GetImage());
520 if (has_index_buffer_) {
521 command_buffer_vk_.drawIndexed(element_count_,
528 command_buffer_vk_.draw(element_count_,
535 #ifdef IMPELLER_DEBUG
537 command_buffer_->PopDebugGroup();
541 has_index_buffer_ =
false;
542 bound_image_offset_ = 0u;
543 bound_buffer_offset_ = 0u;
544 descriptor_write_offset_ = 0u;
545 instance_count_ = 1u;
549 pipeline_uses_input_attachments_ =
false;
550 immutable_sampler_ =
nullptr;
551 return fml::Status();
558 const ShaderUniformSlot& slot,
559 const ShaderMetadata* metadata,
561 return BindResource(slot.binding,
type, view);
564 bool RenderPassVK::BindDynamicResource(
ShaderStage stage,
566 const ShaderUniformSlot& slot,
567 std::unique_ptr<ShaderMetadata> metadata,
569 return BindResource(slot.binding,
type, view);
572 bool RenderPassVK::BindResource(
size_t binding,
579 auto buffer = DeviceBufferVK::Cast(*view.GetBuffer()).GetBuffer();
584 std::shared_ptr<const DeviceBuffer> device_buffer = view.TakeBuffer();
585 if (device_buffer && !command_buffer_->Track(device_buffer)) {
589 uint32_t
offset = view.GetRange().offset;
591 vk::DescriptorBufferInfo buffer_info;
592 buffer_info.buffer = buffer;
593 buffer_info.offset =
offset;
594 buffer_info.range = view.GetRange().length;
595 buffer_workspace_[bound_buffer_offset_++] = buffer_info;
597 vk::WriteDescriptorSet write_set;
598 write_set.dstBinding = binding;
599 write_set.descriptorCount = 1u;
601 write_set.pBufferInfo = &buffer_workspace_[bound_buffer_offset_ - 1];
603 write_workspace_[descriptor_write_offset_++] = write_set;
607 bool RenderPassVK::BindDynamicResource(
ShaderStage stage,
609 const SampledImageSlot& slot,
610 std::unique_ptr<ShaderMetadata> metadata,
611 std::shared_ptr<const Texture> texture,
612 raw_ptr<const Sampler> sampler) {
613 return BindResource(stage,
type, slot,
nullptr, texture, sampler);
618 const SampledImageSlot& slot,
619 const ShaderMetadata* metadata,
620 std::shared_ptr<const Texture> texture,
621 raw_ptr<const Sampler> sampler) {
625 if (!texture || !texture->IsValid() || !sampler) {
628 const TextureVK& texture_vk = TextureVK::Cast(*texture);
629 const SamplerVK& sampler_vk = SamplerVK::Cast(*sampler);
631 if (!command_buffer_->Track(texture)) {
635 if (!immutable_sampler_) {
636 immutable_sampler_ = texture_vk.GetImmutableSamplerVariant(sampler_vk);
639 vk::DescriptorImageInfo image_info;
640 image_info.imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal;
641 image_info.sampler = sampler_vk.GetSampler();
642 image_info.imageView = texture_vk.GetImageView();
643 image_workspace_[bound_image_offset_++] = image_info;
645 vk::WriteDescriptorSet write_set;
646 write_set.dstBinding = slot.binding;
647 write_set.descriptorCount = 1u;
648 write_set.descriptorType = vk::DescriptorType::eCombinedImageSampler;
649 write_set.pImageInfo = &image_workspace_[bound_image_offset_ - 1];
651 write_workspace_[descriptor_write_offset_++] = write_set;
655 bool RenderPassVK::OnEncodeCommands(
const Context& context)
const {
656 command_buffer_->GetCommandBuffer().endRenderPass();
660 const std::shared_ptr<Texture>& result_texture =
661 resolve_image_vk_ ? resolve_image_vk_ : color_image_vk_;
662 if (result_texture->GetTextureDescriptor().usage &
663 TextureUsage::kShaderRead) {
665 barrier.cmd_buffer = command_buffer_vk_;
666 barrier.src_access = vk::AccessFlagBits::eColorAttachmentWrite |
667 vk::AccessFlagBits::eTransferWrite;
668 barrier.src_stage = vk::PipelineStageFlagBits::eColorAttachmentOutput |
669 vk::PipelineStageFlagBits::eTransfer;
670 barrier.dst_access = vk::AccessFlagBits::eShaderRead;
671 barrier.dst_stage = vk::PipelineStageFlagBits::eFragmentShader;
673 barrier.new_layout = vk::ImageLayout::eShaderReadOnlyOptimal;
675 if (!TextureVK::Cast(*result_texture).SetLayout(barrier)) {
static TextureVK & Cast(Texture &base)
const RenderTarget render_target_
bool IterateAllColorAttachments(const std::function< bool(size_t index, const ColorAttachment &attachment)> &iterator) const
const std::optional< DepthAttachment > & GetDepthAttachment() const
const std::optional< StencilAttachment > & GetStencilAttachment() const
void SetCachedFramebuffer(const SharedHandleVK< vk::Framebuffer > &framebuffer)
SharedHandleVK< vk::RenderPass > GetCachedRenderPass() const
vk::ImageLayout SetLayoutWithoutEncoding(vk::ImageLayout layout) const
SharedHandleVK< vk::Framebuffer > GetCachedFramebuffer() const
vk::ImageLayout GetLayout() const
void SetCachedRenderPass(const SharedHandleVK< vk::RenderPass > &render_pass)
constexpr vk::IndexType ToVKIndexType(IndexType index_type)
raw_ptr< Pipeline< PipelineDescriptor > > PipelineRef
A raw ptr to a pipeline object.
constexpr vk::DescriptorType ToVKDescriptorType(DescriptorType type)
static constexpr size_t kMaxBindings
constexpr size_t kMaxVertexBuffers
static constexpr size_t kMagicSubpassInputBinding
static vk::ClearDepthStencilValue VKClearValueFromDepthStencil(uint32_t stencil, Scalar depth)
void InsertBarrierForInputAttachmentRead(const vk::CommandBuffer &buffer, const vk::Image &image)
Inserts the appropriate barriers to ensure that subsequent commands can read from the specified image...
static size_t GetVKClearValues(const RenderTarget &target, std::array< vk::ClearValue, kMaxAttachments > &values)
static vk::ClearColorValue VKClearValueFromColor(Color color)
auto MakeSharedVK(vk::UniqueHandle< T, VULKAN_HPP_DEFAULT_DISPATCHER_TYPE > handle)
std::shared_ptr< Texture > resolve_texture
constexpr static TRect MakeSize(const TSize< U > &size)