11 #include "fml/status.h"
28 #include "vulkan/vulkan_handles.hpp"
40 vk::ClearColorValue value;
48 vk::ClearDepthStencilValue value;
50 value.stencil = stencil;
56 std::vector<vk::ClearValue> clears;
60 if (color.resolve_texture) {
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));
79 SharedHandleVK<vk::RenderPass> RenderPassVK::CreateVKRenderPass(
80 const ContextVK& context,
81 const SharedHandleVK<vk::RenderPass>& recycled_renderpass,
82 const std::shared_ptr<CommandBufferVK>& command_buffer)
const {
84 barrier.new_layout = vk::ImageLayout::eGeneral;
85 barrier.cmd_buffer = command_buffer->GetEncoder()->GetCommandBuffer();
86 barrier.src_access = vk::AccessFlagBits::eShaderRead;
87 barrier.src_stage = vk::PipelineStageFlagBits::eFragmentShader;
88 barrier.dst_access = vk::AccessFlagBits::eColorAttachmentWrite |
89 vk::AccessFlagBits::eTransferWrite;
90 barrier.dst_stage = vk::PipelineStageFlagBits::eColorAttachmentOutput |
91 vk::PipelineStageFlagBits::eTransfer;
93 RenderPassBuilderVK builder;
96 builder.SetColorAttachment(
98 color.texture->GetTextureDescriptor().format,
99 color.texture->GetTextureDescriptor().sample_count,
104 if (color.resolve_texture) {
110 builder.SetDepthStencilAttachment(
111 depth->texture->GetTextureDescriptor().format,
112 depth->texture->GetTextureDescriptor().sample_count,
117 stencil.has_value()) {
118 builder.SetStencilAttachment(
119 stencil->texture->GetTextureDescriptor().format,
120 stencil->texture->GetTextureDescriptor().sample_count,
121 stencil->load_action,
122 stencil->store_action
126 if (recycled_renderpass !=
nullptr) {
127 return recycled_renderpass;
130 auto pass = builder.Build(context.GetDevice());
133 VALIDATION_LOG <<
"Failed to create render pass for framebuffer.";
137 context.SetDebugName(pass.get(), debug_label_.c_str());
142 RenderPassVK::RenderPassVK(
const std::shared_ptr<const Context>& context,
143 const RenderTarget& target,
144 std::shared_ptr<CommandBufferVK> command_buffer)
145 : RenderPass(context, target), command_buffer_(
std::move(command_buffer)) {
147 render_target_.GetColorAttachments().find(0u)->second.texture;
149 render_target_.GetColorAttachments().find(0u)->second.resolve_texture;
152 const std::shared_ptr<CommandEncoderVK>& encoder =
153 command_buffer_->GetEncoder();
154 command_buffer_vk_ = encoder->GetCommandBuffer();
155 render_target_.IterateAllAttachments(
156 [&encoder](
const auto& attachment) ->
bool {
157 encoder->Track(attachment.texture);
158 encoder->Track(attachment.resolve_texture);
162 SharedHandleVK<vk::RenderPass> recycled_render_pass;
163 SharedHandleVK<vk::Framebuffer> recycled_framebuffer;
164 if (resolve_image_vk_) {
165 recycled_render_pass =
167 recycled_framebuffer =
171 const auto& target_size = render_target_.GetRenderTargetSize();
174 CreateVKRenderPass(vk_context, recycled_render_pass, command_buffer_);
181 auto framebuffer = (recycled_framebuffer ==
nullptr)
182 ? CreateVKFramebuffer(vk_context, *render_pass_)
183 : recycled_framebuffer;
190 if (!encoder->Track(framebuffer) || !encoder->Track(render_pass_)) {
194 if (resolve_image_vk_) {
201 vk::RenderPassBeginInfo pass_info;
202 pass_info.renderPass = *render_pass_;
203 pass_info.framebuffer = *framebuffer;
204 pass_info.renderArea.extent.width =
static_cast<uint32_t
>(target_size.width);
205 pass_info.renderArea.extent.height =
206 static_cast<uint32_t
>(target_size.height);
207 pass_info.setClearValues(clear_values);
209 command_buffer_vk_.beginRenderPass(pass_info, vk::SubpassContents::eInline);
213 vk::Viewport viewport = vk::Viewport()
214 .setWidth(vp.rect.GetWidth())
215 .setHeight(-vp.rect.GetHeight())
216 .setY(vp.rect.GetHeight())
219 command_buffer_vk_.setViewport(0, 1, &viewport);
225 .setOffset(vk::Offset2D(sc.GetX(), sc.GetY()))
226 .setExtent(vk::Extent2D(sc.GetWidth(), sc.GetHeight()));
227 command_buffer_vk_.setScissor(0, 1, &scissor);
230 command_buffer_vk_.setStencilReference(
231 vk::StencilFaceFlagBits::eVkStencilFrontAndBack, 0u);
236 RenderPassVK::~RenderPassVK() =
default;
238 bool RenderPassVK::IsValid()
const {
242 void RenderPassVK::OnSetLabel(std::string label) {
243 #ifdef IMPELLER_DEBUG
244 ContextVK::Cast(*context_).SetDebugName(render_pass_->Get(),
245 std::string(label).c_str());
246 #endif // IMPELLER_DEBUG
249 SharedHandleVK<vk::Framebuffer> RenderPassVK::CreateVKFramebuffer(
250 const ContextVK& context,
251 const vk::RenderPass& pass)
const {
252 vk::FramebufferCreateInfo fb_info;
254 fb_info.renderPass = pass;
256 const auto target_size = render_target_.GetRenderTargetSize();
257 fb_info.width = target_size.width;
258 fb_info.height = target_size.height;
261 std::vector<vk::ImageView> attachments;
266 for (
const auto& [_, color] : render_target_.GetColorAttachments()) {
269 attachments.emplace_back(
270 TextureVK::Cast(*color.texture).GetRenderTargetView());
271 if (color.resolve_texture) {
272 attachments.emplace_back(
273 TextureVK::Cast(*color.resolve_texture).GetRenderTargetView());
276 if (
auto depth = render_target_.GetDepthAttachment(); depth.has_value()) {
277 attachments.emplace_back(
278 TextureVK::Cast(*depth->texture).GetRenderTargetView());
279 }
else if (
auto stencil = render_target_.GetStencilAttachment();
280 stencil.has_value()) {
281 attachments.emplace_back(
282 TextureVK::Cast(*stencil->texture).GetRenderTargetView());
285 fb_info.setAttachments(attachments);
287 auto [result, framebuffer] =
288 context.GetDevice().createFramebufferUnique(fb_info);
290 if (result != vk::Result::eSuccess) {
291 VALIDATION_LOG <<
"Could not create framebuffer: " << vk::to_string(result);
299 void RenderPassVK::SetPipeline(
300 const std::shared_ptr<Pipeline<PipelineDescriptor>>& pipeline) {
301 pipeline_ = pipeline;
307 pipeline_uses_input_attachments_ =
308 pipeline_->GetDescriptor().GetVertexDescriptor()->UsesInputAttacments();
310 if (pipeline_uses_input_attachments_) {
315 vk::DescriptorImageInfo image_info;
316 image_info.imageLayout = vk::ImageLayout::eGeneral;
317 image_info.sampler = VK_NULL_HANDLE;
318 image_info.imageView = TextureVK::Cast(*color_image_vk_).GetImageView();
319 image_workspace_[bound_image_offset_++] = image_info;
321 vk::WriteDescriptorSet write_set;
323 write_set.descriptorCount = 1u;
324 write_set.descriptorType = vk::DescriptorType::eInputAttachment;
325 write_set.pImageInfo = &image_workspace_[bound_image_offset_ - 1];
327 write_workspace_[descriptor_write_offset_++] = write_set;
332 void RenderPassVK::SetCommandLabel(std::string_view label) {
333 #ifdef IMPELLER_DEBUG
334 command_buffer_->GetEncoder()->PushDebugGroup(label);
336 #endif // IMPELLER_DEBUG
340 void RenderPassVK::SetStencilReference(uint32_t value) {
341 command_buffer_vk_.setStencilReference(
342 vk::StencilFaceFlagBits::eVkStencilFrontAndBack, value);
346 void RenderPassVK::SetBaseVertex(uint64_t value) {
347 base_vertex_ = value;
351 void RenderPassVK::SetViewport(Viewport viewport) {
352 vk::Viewport viewport_vk = vk::Viewport()
353 .setWidth(viewport.rect.GetWidth())
354 .setHeight(-viewport.rect.GetHeight())
355 .setY(viewport.rect.GetHeight())
358 command_buffer_vk_.setViewport(0, 1, &viewport_vk);
362 void RenderPassVK::SetScissor(
IRect scissor) {
363 vk::Rect2D scissor_vk =
365 .setOffset(vk::Offset2D(scissor.GetX(), scissor.GetY()))
366 .setExtent(vk::Extent2D(scissor.GetWidth(), scissor.GetHeight()));
367 command_buffer_vk_.setScissor(0, 1, &scissor_vk);
371 void RenderPassVK::SetInstanceCount(
size_t count) {
372 instance_count_ = count;
376 bool RenderPassVK::SetVertexBuffer(VertexBuffer buffer) {
377 vertex_count_ = buffer.vertex_count;
378 if (buffer.index_type == IndexType::kUnknown || !buffer.vertex_buffer) {
382 if (!command_buffer_->GetEncoder()->Track(buffer.vertex_buffer.buffer)) {
387 vk::Buffer vertex_buffer_handle =
388 DeviceBufferVK::Cast(*buffer.vertex_buffer.buffer).GetBuffer();
389 vk::Buffer vertex_buffers[] = {vertex_buffer_handle};
390 vk::DeviceSize vertex_buffer_offsets[] = {buffer.vertex_buffer.range.offset};
392 command_buffer_vk_.bindVertexBuffers(0u, 1u, vertex_buffers,
393 vertex_buffer_offsets);
396 if (buffer.index_type != IndexType::kNone) {
397 has_index_buffer_ =
true;
398 const BufferView& index_buffer_view = buffer.index_buffer;
399 if (!index_buffer_view) {
403 const std::shared_ptr<const DeviceBuffer>& index_buffer =
404 index_buffer_view.buffer;
407 <<
" for index buffer view";
411 if (!command_buffer_->GetEncoder()->Track(index_buffer)) {
415 vk::Buffer index_buffer_handle =
416 DeviceBufferVK::Cast(*index_buffer).GetBuffer();
417 command_buffer_vk_.bindIndexBuffer(index_buffer_handle,
418 index_buffer_view.range.offset,
421 has_index_buffer_ =
false;
427 fml::Status RenderPassVK::Draw() {
429 return fml::Status(fml::StatusCode::kCancelled,
430 "No valid pipeline is bound to the RenderPass.");
450 if (immutable_sampler_) {
451 std::shared_ptr<PipelineVK> pipeline_variant =
452 PipelineVK::Cast(*pipeline_)
453 .CreateVariantForImmutableSamplers(immutable_sampler_);
454 if (!pipeline_variant) {
456 fml::StatusCode::kAborted,
457 "Could not create pipeline variant with immutable sampler.");
459 pipeline_ = std::move(pipeline_variant);
462 const auto& context_vk = ContextVK::Cast(*context_);
463 const auto& pipeline_vk = PipelineVK::Cast(*pipeline_);
465 auto descriptor_result =
466 command_buffer_->GetEncoder()->AllocateDescriptorSets(
467 pipeline_vk.GetDescriptorSetLayout(), context_vk);
468 if (!descriptor_result.ok()) {
469 return fml::Status(fml::StatusCode::kAborted,
470 "Could not allocate descriptor sets.");
472 const auto descriptor_set = descriptor_result.value();
473 const auto pipeline_layout = pipeline_vk.GetPipelineLayout();
474 command_buffer_vk_.bindPipeline(vk::PipelineBindPoint::eGraphics,
475 pipeline_vk.GetPipeline());
477 for (
auto i = 0u; i < descriptor_write_offset_; i++) {
478 write_workspace_[i].dstSet = descriptor_set;
481 context_vk.GetDevice().updateDescriptorSets(descriptor_write_offset_,
482 write_workspace_.data(), 0u, {});
484 command_buffer_vk_.bindDescriptorSets(
485 vk::PipelineBindPoint::eGraphics,
494 if (pipeline_uses_input_attachments_) {
496 command_buffer_vk_, TextureVK::Cast(*color_image_vk_).GetImage());
499 if (has_index_buffer_) {
500 command_buffer_vk_.drawIndexed(vertex_count_,
507 command_buffer_vk_.draw(vertex_count_,
514 #ifdef IMPELLER_DEBUG
516 command_buffer_->GetEncoder()->PopDebugGroup();
518 #endif // IMPELLER_DEBUG
520 has_index_buffer_ =
false;
521 bound_image_offset_ = 0u;
522 bound_buffer_offset_ = 0u;
523 descriptor_write_offset_ = 0u;
524 instance_count_ = 1u;
528 pipeline_uses_input_attachments_ =
false;
529 immutable_sampler_ =
nullptr;
530 return fml::Status();
537 const ShaderUniformSlot& slot,
538 const ShaderMetadata& metadata,
540 return BindResource(slot.binding, type, view);
543 bool RenderPassVK::BindResource(
546 const ShaderUniformSlot& slot,
547 const std::shared_ptr<const ShaderMetadata>& metadata,
549 return BindResource(slot.binding, type, view);
552 bool RenderPassVK::BindResource(
size_t binding,
554 const BufferView& view) {
559 const std::shared_ptr<const DeviceBuffer>& device_buffer = view.buffer;
560 auto buffer = DeviceBufferVK::Cast(*device_buffer).GetBuffer();
565 if (!command_buffer_->GetEncoder()->Track(device_buffer)) {
569 uint32_t
offset = view.range.offset;
571 vk::DescriptorBufferInfo buffer_info;
572 buffer_info.buffer = buffer;
573 buffer_info.offset =
offset;
574 buffer_info.range = view.range.length;
575 buffer_workspace_[bound_buffer_offset_++] = buffer_info;
577 vk::WriteDescriptorSet write_set;
578 write_set.dstBinding = binding;
579 write_set.descriptorCount = 1u;
581 write_set.pBufferInfo = &buffer_workspace_[bound_buffer_offset_ - 1];
583 write_workspace_[descriptor_write_offset_++] = write_set;
589 const SampledImageSlot& slot,
590 const ShaderMetadata& metadata,
591 std::shared_ptr<const Texture> texture,
592 const std::unique_ptr<const Sampler>& sampler) {
596 if (!texture->IsValid() || !sampler) {
599 const TextureVK& texture_vk = TextureVK::Cast(*texture);
600 const SamplerVK& sampler_vk = SamplerVK::Cast(*sampler);
602 if (!command_buffer_->GetEncoder()->Track(texture)) {
606 if (!immutable_sampler_) {
607 immutable_sampler_ = texture_vk.GetImmutableSamplerVariant(sampler_vk);
610 vk::DescriptorImageInfo image_info;
611 image_info.imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal;
612 image_info.sampler = sampler_vk.GetSampler();
613 image_info.imageView = texture_vk.GetImageView();
614 image_workspace_[bound_image_offset_++] = image_info;
616 vk::WriteDescriptorSet write_set;
617 write_set.dstBinding = slot.binding;
618 write_set.descriptorCount = 1u;
619 write_set.descriptorType = vk::DescriptorType::eCombinedImageSampler;
620 write_set.pImageInfo = &image_workspace_[bound_image_offset_ - 1];
622 write_workspace_[descriptor_write_offset_++] = write_set;
626 bool RenderPassVK::OnEncodeCommands(
const Context& context)
const {
627 command_buffer_->GetEncoder()->GetCommandBuffer().endRenderPass();
631 const std::shared_ptr<Texture>& result_texture =
632 resolve_image_vk_ ? resolve_image_vk_ : color_image_vk_;
633 if (result_texture->GetTextureDescriptor().usage &
634 TextureUsage::kShaderRead) {
636 barrier.cmd_buffer = command_buffer_vk_;
637 barrier.src_access = vk::AccessFlagBits::eColorAttachmentWrite |
638 vk::AccessFlagBits::eTransferWrite;
639 barrier.src_stage = vk::PipelineStageFlagBits::eColorAttachmentOutput |
640 vk::PipelineStageFlagBits::eTransfer;
641 barrier.dst_access = vk::AccessFlagBits::eShaderRead;
642 barrier.dst_stage = vk::PipelineStageFlagBits::eFragmentShader;
644 barrier.new_layout = vk::ImageLayout::eShaderReadOnlyOptimal;
646 if (!TextureVK::Cast(*result_texture).SetLayout(barrier)) {