11 #include "fml/status.h"
26 #include "vulkan/vulkan_handles.hpp"
38 vk::ClearColorValue value;
46 vk::ClearDepthStencilValue value;
48 value.stencil = stencil;
54 std::vector<vk::ClearValue> clears;
58 if (
color.resolve_texture) {
66 if (depth.has_value()) {
68 stencil ? stencil->clear_stencil : 0u, depth->clear_depth));
69 }
else if (stencil.has_value()) {
71 stencil->clear_stencil, depth ? depth->clear_depth : 0.0f));
77 SharedHandleVK<vk::RenderPass> RenderPassVK::CreateVKRenderPass(
78 const ContextVK& context,
79 const SharedHandleVK<vk::RenderPass>& recycled_renderpass,
80 const std::shared_ptr<CommandBufferVK>& command_buffer)
const {
82 barrier.new_layout = vk::ImageLayout::eGeneral;
83 barrier.cmd_buffer = command_buffer->GetCommandBuffer();
84 barrier.src_access = vk::AccessFlagBits::eShaderRead;
85 barrier.src_stage = vk::PipelineStageFlagBits::eFragmentShader;
86 barrier.dst_access = vk::AccessFlagBits::eColorAttachmentWrite |
87 vk::AccessFlagBits::eTransferWrite;
88 barrier.dst_stage = vk::PipelineStageFlagBits::eColorAttachmentOutput |
89 vk::PipelineStageFlagBits::eTransfer;
91 RenderPassBuilderVK builder;
94 builder.SetColorAttachment(
96 color.texture->GetTextureDescriptor().format,
97 color.texture->GetTextureDescriptor().sample_count,
102 if (
color.resolve_texture) {
108 builder.SetDepthStencilAttachment(
109 depth->texture->GetTextureDescriptor().format,
110 depth->texture->GetTextureDescriptor().sample_count,
115 stencil.has_value()) {
116 builder.SetStencilAttachment(
117 stencil->texture->GetTextureDescriptor().format,
118 stencil->texture->GetTextureDescriptor().sample_count,
119 stencil->load_action,
120 stencil->store_action
124 if (recycled_renderpass !=
nullptr) {
125 return recycled_renderpass;
128 auto pass = builder.Build(context.GetDevice());
131 VALIDATION_LOG <<
"Failed to create render pass for framebuffer.";
135 context.SetDebugName(pass.get(), debug_label_.c_str());
140 RenderPassVK::RenderPassVK(
const std::shared_ptr<const Context>& context,
141 const RenderTarget& target,
142 std::shared_ptr<CommandBufferVK> command_buffer)
143 : RenderPass(context, target), command_buffer_(
std::move(command_buffer)) {
145 render_target_.GetColorAttachments().find(0u)->second.texture;
147 render_target_.GetColorAttachments().find(0u)->second.resolve_texture;
150 command_buffer_vk_ = command_buffer_->GetCommandBuffer();
151 render_target_.IterateAllAttachments([&](
const auto& attachment) ->
bool {
152 command_buffer_->Track(attachment.texture);
153 command_buffer_->Track(attachment.resolve_texture);
157 SharedHandleVK<vk::RenderPass> recycled_render_pass;
158 SharedHandleVK<vk::Framebuffer> recycled_framebuffer;
159 if (resolve_image_vk_) {
160 recycled_render_pass =
162 recycled_framebuffer =
166 const auto& target_size = render_target_.GetRenderTargetSize();
169 CreateVKRenderPass(vk_context, recycled_render_pass, command_buffer_);
176 auto framebuffer = (recycled_framebuffer ==
nullptr)
177 ? CreateVKFramebuffer(vk_context, *render_pass_)
178 : recycled_framebuffer;
185 if (!command_buffer_->Track(framebuffer) ||
186 !command_buffer_->Track(render_pass_)) {
190 if (resolve_image_vk_) {
197 vk::RenderPassBeginInfo pass_info;
198 pass_info.renderPass = *render_pass_;
199 pass_info.framebuffer = *framebuffer;
200 pass_info.renderArea.extent.width =
static_cast<uint32_t
>(target_size.width);
201 pass_info.renderArea.extent.height =
202 static_cast<uint32_t
>(target_size.height);
203 pass_info.setClearValues(clear_values);
205 command_buffer_vk_.beginRenderPass(pass_info, vk::SubpassContents::eInline);
209 vk::Viewport viewport = vk::Viewport()
210 .setWidth(vp.rect.GetWidth())
211 .setHeight(-vp.rect.GetHeight())
212 .setY(vp.rect.GetHeight())
215 command_buffer_vk_.setViewport(0, 1, &viewport);
221 .setOffset(vk::Offset2D(sc.GetX(), sc.GetY()))
222 .setExtent(vk::Extent2D(sc.GetWidth(), sc.GetHeight()));
223 command_buffer_vk_.setScissor(0, 1, &scissor);
226 command_buffer_vk_.setStencilReference(
227 vk::StencilFaceFlagBits::eVkStencilFrontAndBack, 0u);
232 RenderPassVK::~RenderPassVK() =
default;
234 bool RenderPassVK::IsValid()
const {
238 void RenderPassVK::OnSetLabel(std::string label) {
239 #ifdef IMPELLER_DEBUG
240 ContextVK::Cast(*context_).SetDebugName(render_pass_->Get(),
241 std::string(label).c_str());
242 #endif // IMPELLER_DEBUG
245 SharedHandleVK<vk::Framebuffer> RenderPassVK::CreateVKFramebuffer(
246 const ContextVK& context,
247 const vk::RenderPass& pass)
const {
248 vk::FramebufferCreateInfo fb_info;
250 fb_info.renderPass = pass;
252 const auto target_size = render_target_.GetRenderTargetSize();
253 fb_info.width = target_size.width;
254 fb_info.height = target_size.height;
257 std::vector<vk::ImageView> attachments;
262 for (
const auto& [_,
color] : render_target_.GetColorAttachments()) {
265 attachments.emplace_back(
266 TextureVK::Cast(*
color.texture).GetRenderTargetView());
267 if (
color.resolve_texture) {
268 attachments.emplace_back(
269 TextureVK::Cast(*
color.resolve_texture).GetRenderTargetView());
272 if (
auto depth = render_target_.GetDepthAttachment(); depth.has_value()) {
273 attachments.emplace_back(
274 TextureVK::Cast(*depth->texture).GetRenderTargetView());
275 }
else if (
auto stencil = render_target_.GetStencilAttachment();
276 stencil.has_value()) {
277 attachments.emplace_back(
278 TextureVK::Cast(*stencil->texture).GetRenderTargetView());
281 fb_info.setAttachments(attachments);
283 auto [result, framebuffer] =
284 context.GetDevice().createFramebufferUnique(fb_info);
286 if (result != vk::Result::eSuccess) {
287 VALIDATION_LOG <<
"Could not create framebuffer: " << vk::to_string(result);
295 void RenderPassVK::SetPipeline(
296 const std::shared_ptr<Pipeline<PipelineDescriptor>>& pipeline) {
297 pipeline_ = pipeline.get();
302 pipeline_uses_input_attachments_ =
303 pipeline_->GetDescriptor().GetVertexDescriptor()->UsesInputAttacments();
305 if (pipeline_uses_input_attachments_) {
310 vk::DescriptorImageInfo image_info;
311 image_info.imageLayout = vk::ImageLayout::eGeneral;
312 image_info.sampler = VK_NULL_HANDLE;
313 image_info.imageView = TextureVK::Cast(*color_image_vk_).GetImageView();
314 image_workspace_[bound_image_offset_++] = image_info;
316 vk::WriteDescriptorSet write_set;
318 write_set.descriptorCount = 1u;
319 write_set.descriptorType = vk::DescriptorType::eInputAttachment;
320 write_set.pImageInfo = &image_workspace_[bound_image_offset_ - 1];
322 write_workspace_[descriptor_write_offset_++] = write_set;
327 void RenderPassVK::SetCommandLabel(std::string_view label) {
328 #ifdef IMPELLER_DEBUG
329 command_buffer_->PushDebugGroup(label);
331 #endif // IMPELLER_DEBUG
335 void RenderPassVK::SetStencilReference(uint32_t value) {
336 command_buffer_vk_.setStencilReference(
337 vk::StencilFaceFlagBits::eVkStencilFrontAndBack, value);
341 void RenderPassVK::SetBaseVertex(uint64_t value) {
342 base_vertex_ = value;
346 void RenderPassVK::SetViewport(Viewport viewport) {
347 vk::Viewport viewport_vk = vk::Viewport()
348 .setWidth(viewport.rect.GetWidth())
349 .setHeight(-viewport.rect.GetHeight())
350 .setY(viewport.rect.GetHeight())
353 command_buffer_vk_.setViewport(0, 1, &viewport_vk);
357 void RenderPassVK::SetScissor(
IRect scissor) {
358 vk::Rect2D scissor_vk =
360 .setOffset(vk::Offset2D(scissor.GetX(), scissor.GetY()))
361 .setExtent(vk::Extent2D(scissor.GetWidth(), scissor.GetHeight()));
362 command_buffer_vk_.setScissor(0, 1, &scissor_vk);
366 void RenderPassVK::SetInstanceCount(
size_t count) {
367 instance_count_ = count;
371 bool RenderPassVK::SetVertexBuffer(VertexBuffer buffer) {
372 vertex_count_ = buffer.vertex_count;
373 if (buffer.index_type == IndexType::kUnknown || !buffer.vertex_buffer) {
377 if (!command_buffer_->Track(buffer.vertex_buffer.buffer)) {
382 vk::Buffer vertex_buffer_handle =
383 DeviceBufferVK::Cast(*buffer.vertex_buffer.buffer).GetBuffer();
384 vk::Buffer vertex_buffers[] = {vertex_buffer_handle};
385 vk::DeviceSize vertex_buffer_offsets[] = {buffer.vertex_buffer.range.offset};
387 command_buffer_vk_.bindVertexBuffers(0u, 1u, vertex_buffers,
388 vertex_buffer_offsets);
391 if (buffer.index_type != IndexType::kNone) {
392 has_index_buffer_ =
true;
393 const BufferView& index_buffer_view = buffer.index_buffer;
394 if (!index_buffer_view) {
398 const std::shared_ptr<const DeviceBuffer>& index_buffer =
399 index_buffer_view.buffer;
402 <<
" for index buffer view";
406 if (!command_buffer_->Track(index_buffer)) {
410 vk::Buffer index_buffer_handle =
411 DeviceBufferVK::Cast(*index_buffer).GetBuffer();
412 command_buffer_vk_.bindIndexBuffer(index_buffer_handle,
413 index_buffer_view.range.offset,
416 has_index_buffer_ =
false;
422 fml::Status RenderPassVK::Draw() {
424 return fml::Status(fml::StatusCode::kCancelled,
425 "No valid pipeline is bound to the RenderPass.");
445 if (immutable_sampler_) {
446 std::shared_ptr<PipelineVK> pipeline_variant =
447 PipelineVK::Cast(*pipeline_)
448 .CreateVariantForImmutableSamplers(immutable_sampler_);
449 if (!pipeline_variant) {
451 fml::StatusCode::kAborted,
452 "Could not create pipeline variant with immutable sampler.");
454 pipeline_ = pipeline_variant.get();
457 const auto& context_vk = ContextVK::Cast(*context_);
458 const auto& pipeline_vk = PipelineVK::Cast(*pipeline_);
460 auto descriptor_result = command_buffer_->AllocateDescriptorSets(
461 pipeline_vk.GetDescriptorSetLayout(), context_vk);
462 if (!descriptor_result.ok()) {
463 return fml::Status(fml::StatusCode::kAborted,
464 "Could not allocate descriptor sets.");
466 const auto descriptor_set = descriptor_result.value();
467 const auto pipeline_layout = pipeline_vk.GetPipelineLayout();
468 command_buffer_vk_.bindPipeline(vk::PipelineBindPoint::eGraphics,
469 pipeline_vk.GetPipeline());
471 for (
auto i = 0u; i < descriptor_write_offset_; i++) {
472 write_workspace_[i].dstSet = descriptor_set;
475 context_vk.GetDevice().updateDescriptorSets(descriptor_write_offset_,
476 write_workspace_.data(), 0u, {});
478 command_buffer_vk_.bindDescriptorSets(
479 vk::PipelineBindPoint::eGraphics,
488 if (pipeline_uses_input_attachments_) {
490 command_buffer_vk_, TextureVK::Cast(*color_image_vk_).GetImage());
493 if (has_index_buffer_) {
494 command_buffer_vk_.drawIndexed(vertex_count_,
501 command_buffer_vk_.draw(vertex_count_,
508 #ifdef IMPELLER_DEBUG
510 command_buffer_->PopDebugGroup();
512 #endif // IMPELLER_DEBUG
514 has_index_buffer_ =
false;
515 bound_image_offset_ = 0u;
516 bound_buffer_offset_ = 0u;
517 descriptor_write_offset_ = 0u;
518 instance_count_ = 1u;
522 pipeline_uses_input_attachments_ =
false;
523 immutable_sampler_ =
nullptr;
524 return fml::Status();
531 const ShaderUniformSlot& slot,
532 const ShaderMetadata& metadata,
534 return BindResource(slot.binding,
type, view);
537 bool RenderPassVK::BindResource(
540 const ShaderUniformSlot& slot,
541 const std::shared_ptr<const ShaderMetadata>& metadata,
543 return BindResource(slot.binding,
type, view);
546 bool RenderPassVK::BindResource(
size_t binding,
548 const BufferView& view) {
553 const std::shared_ptr<const DeviceBuffer>& device_buffer = view.buffer;
554 auto buffer = DeviceBufferVK::Cast(*device_buffer).GetBuffer();
559 if (!command_buffer_->Track(device_buffer)) {
563 uint32_t
offset = view.range.offset;
565 vk::DescriptorBufferInfo buffer_info;
566 buffer_info.buffer = buffer;
567 buffer_info.offset =
offset;
568 buffer_info.range = view.range.length;
569 buffer_workspace_[bound_buffer_offset_++] = buffer_info;
571 vk::WriteDescriptorSet write_set;
572 write_set.dstBinding = binding;
573 write_set.descriptorCount = 1u;
575 write_set.pBufferInfo = &buffer_workspace_[bound_buffer_offset_ - 1];
577 write_workspace_[descriptor_write_offset_++] = write_set;
583 const SampledImageSlot& slot,
584 const ShaderMetadata& metadata,
585 std::shared_ptr<const Texture> texture,
586 const std::unique_ptr<const Sampler>& sampler) {
590 if (!texture->IsValid() || !sampler) {
593 const TextureVK& texture_vk = TextureVK::Cast(*texture);
594 const SamplerVK& sampler_vk = SamplerVK::Cast(*sampler);
596 if (!command_buffer_->Track(texture)) {
600 if (!immutable_sampler_) {
601 immutable_sampler_ = texture_vk.GetImmutableSamplerVariant(sampler_vk);
604 vk::DescriptorImageInfo image_info;
605 image_info.imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal;
606 image_info.sampler = sampler_vk.GetSampler();
607 image_info.imageView = texture_vk.GetImageView();
608 image_workspace_[bound_image_offset_++] = image_info;
610 vk::WriteDescriptorSet write_set;
611 write_set.dstBinding = slot.binding;
612 write_set.descriptorCount = 1u;
613 write_set.descriptorType = vk::DescriptorType::eCombinedImageSampler;
614 write_set.pImageInfo = &image_workspace_[bound_image_offset_ - 1];
616 write_workspace_[descriptor_write_offset_++] = write_set;
620 bool RenderPassVK::OnEncodeCommands(
const Context& context)
const {
621 command_buffer_->GetCommandBuffer().endRenderPass();
625 const std::shared_ptr<Texture>& result_texture =
626 resolve_image_vk_ ? resolve_image_vk_ : color_image_vk_;
627 if (result_texture->GetTextureDescriptor().usage &
628 TextureUsage::kShaderRead) {
630 barrier.cmd_buffer = command_buffer_vk_;
631 barrier.src_access = vk::AccessFlagBits::eColorAttachmentWrite |
632 vk::AccessFlagBits::eTransferWrite;
633 barrier.src_stage = vk::PipelineStageFlagBits::eColorAttachmentOutput |
634 vk::PipelineStageFlagBits::eTransfer;
635 barrier.dst_access = vk::AccessFlagBits::eShaderRead;
636 barrier.dst_stage = vk::PipelineStageFlagBits::eFragmentShader;
638 barrier.new_layout = vk::ImageLayout::eShaderReadOnlyOptimal;
640 if (!TextureVK::Cast(*result_texture).SetLayout(barrier)) {