10 #include "fml/status.h"
38 vk::ClearColorValue
value;
46 vk::ClearDepthStencilValue
value;
48 value.stencil = stencil;
54 std::array<vk::ClearValue, kMaxAttachments>& values) {
57 [&values, &offset](
size_t index,
61 values.at(offset++) = VKClearValueFromColor(attachment.clear_color);
69 if (depth.has_value()) {
71 stencil ? stencil->clear_stencil : 0u, depth->clear_depth);
72 }
else if (stencil.has_value()) {
74 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,
83 bool is_swapchain)
const {
84 if (recycled_renderpass !=
nullptr) {
85 return recycled_renderpass;
88 RenderPassBuilderVK builder;
90 const ColorAttachment&
92 builder.SetColorAttachment(
94 attachment.texture->GetTextureDescriptor().format,
95 attachment.texture->GetTextureDescriptor().sample_count,
96 attachment.load_action,
97 attachment.store_action,
104 builder.SetDepthStencilAttachment(
105 depth->texture->GetTextureDescriptor().format,
106 depth->texture->GetTextureDescriptor().sample_count,
111 stencil.has_value()) {
112 builder.SetStencilAttachment(
113 stencil->texture->GetTextureDescriptor().format,
114 stencil->texture->GetTextureDescriptor().sample_count,
115 stencil->load_action,
116 stencil->store_action
120 auto pass = builder.Build(context.GetDevice());
123 VALIDATION_LOG <<
"Failed to create render pass for framebuffer.";
127 context.SetDebugName(pass.get(), debug_label_.c_str());
132 RenderPassVK::RenderPassVK(
const std::shared_ptr<const Context>& context,
133 const RenderTarget& target,
134 std::shared_ptr<CommandBufferVK> command_buffer)
135 : RenderPass(context, target), command_buffer_(
std::move(command_buffer)) {
136 const ColorAttachment& color0 = render_target_.GetColorAttachment(0);
137 color_image_vk_ = color0.texture;
138 resolve_image_vk_ = color0.resolve_texture;
141 command_buffer_vk_ = command_buffer_->GetCommandBuffer();
142 render_target_.IterateAllAttachments([&](
const auto& attachment) ->
bool {
143 command_buffer_->Track(attachment.texture);
144 command_buffer_->Track(attachment.resolve_texture);
148 FramebufferAndRenderPass frame_data;
149 bool is_swapchain =
false;
151 color_image_vk_->GetTextureDescriptor().sample_count;
152 if (resolve_image_vk_) {
162 const auto& target_size = render_target_.GetRenderTargetSize();
164 render_pass_ = CreateVKRenderPass(vk_context, frame_data.render_pass,
165 command_buffer_, is_swapchain);
172 auto framebuffer = (frame_data.framebuffer ==
nullptr)
173 ? CreateVKFramebuffer(vk_context, *render_pass_)
174 : frame_data.framebuffer;
181 if (!command_buffer_->Track(framebuffer) ||
182 !command_buffer_->Track(render_pass_)) {
187 frame_data.framebuffer = framebuffer;
188 frame_data.render_pass = render_pass_;
190 if (resolve_image_vk_) {
200 if (resolve_image_vk_ &&
201 resolve_image_vk_->GetTextureDescriptor().mip_count > 1) {
203 vk::ImageLayout::eUndefined) {
205 barrier.new_layout = vk::ImageLayout::eShaderReadOnlyOptimal;
206 barrier.cmd_buffer = command_buffer_->GetCommandBuffer();
207 barrier.src_stage = vk::PipelineStageFlagBits::eBottomOfPipe;
208 barrier.src_access = {};
209 barrier.dst_stage = vk::PipelineStageFlagBits::eFragmentShader;
210 barrier.dst_access = vk::AccessFlagBits::eShaderRead;
211 barrier.base_mip_level = 1;
216 std::array<vk::ClearValue, kMaxAttachments> clears;
219 vk::RenderPassBeginInfo pass_info;
220 pass_info.renderPass = *render_pass_;
221 pass_info.framebuffer = *framebuffer;
222 pass_info.renderArea.extent.width =
static_cast<uint32_t
>(target_size.width);
223 pass_info.renderArea.extent.height =
224 static_cast<uint32_t
>(target_size.height);
225 pass_info.setPClearValues(clears.data());
226 pass_info.setClearValueCount(clear_count);
228 command_buffer_vk_.beginRenderPass(pass_info, vk::SubpassContents::eInline);
230 if (resolve_image_vk_) {
233 is_swapchain ? vk::ImageLayout::eGeneral
234 : vk::ImageLayout::eShaderReadOnlyOptimal);
236 if (color_image_vk_) {
243 vk::Viewport viewport = vk::Viewport()
244 .setWidth(vp.rect.GetWidth())
245 .setHeight(-vp.rect.GetHeight())
246 .setY(vp.rect.GetHeight())
249 command_buffer_vk_.setViewport(0, 1, &viewport);
255 .setOffset(vk::Offset2D(sc.GetX(), sc.GetY()))
256 .setExtent(vk::Extent2D(sc.GetWidth(), sc.GetHeight()));
257 command_buffer_vk_.setScissor(0, 1, &scissor);
260 command_buffer_vk_.setStencilReference(
261 vk::StencilFaceFlagBits::eVkStencilFrontAndBack, 0u);
266 RenderPassVK::~RenderPassVK() =
default;
268 bool RenderPassVK::IsValid()
const {
272 void RenderPassVK::OnSetLabel(std::string_view label) {
273 #ifdef IMPELLER_DEBUG
274 ContextVK::Cast(*context_).SetDebugName(render_pass_->Get(), label.data());
278 SharedHandleVK<vk::Framebuffer> RenderPassVK::CreateVKFramebuffer(
279 const ContextVK& context,
280 const vk::RenderPass& pass)
const {
281 vk::FramebufferCreateInfo fb_info;
283 fb_info.renderPass = pass;
285 const auto target_size = render_target_.GetRenderTargetSize();
286 fb_info.width = target_size.width;
287 fb_info.height = target_size.height;
290 std::array<vk::ImageView, kMaxAttachments> attachments;
296 render_target_.IterateAllColorAttachments(
297 [&attachments, &count](
size_t index,
298 const ColorAttachment& attachment) ->
bool {
301 attachments[count++] =
302 TextureVK::Cast(*attachment.texture).GetRenderTargetView();
303 if (attachment.resolve_texture) {
304 attachments[count++] = TextureVK::Cast(*attachment.resolve_texture)
305 .GetRenderTargetView();
310 if (
auto depth = render_target_.GetDepthAttachment(); depth.has_value()) {
311 attachments[count++] =
312 TextureVK::Cast(*depth->texture).GetRenderTargetView();
313 }
else if (
auto stencil = render_target_.GetStencilAttachment();
314 stencil.has_value()) {
315 attachments[count++] =
316 TextureVK::Cast(*stencil->texture).GetRenderTargetView();
319 fb_info.setPAttachments(attachments.data());
320 fb_info.setAttachmentCount(count);
322 auto [result, framebuffer] =
323 context.GetDevice().createFramebufferUnique(fb_info);
325 if (result != vk::Result::eSuccess) {
326 VALIDATION_LOG <<
"Could not create framebuffer: " << vk::to_string(result);
334 void RenderPassVK::SetPipeline(
PipelineRef pipeline) {
335 pipeline_ = pipeline;
340 pipeline_uses_input_attachments_ =
341 pipeline_->GetDescriptor().GetVertexDescriptor()->UsesInputAttacments();
343 if (pipeline_uses_input_attachments_) {
348 vk::DescriptorImageInfo image_info;
349 image_info.imageLayout = vk::ImageLayout::eGeneral;
350 image_info.sampler = VK_NULL_HANDLE;
351 image_info.imageView = TextureVK::Cast(*color_image_vk_).GetImageView();
352 image_workspace_[bound_image_offset_++] = image_info;
354 vk::WriteDescriptorSet write_set;
356 write_set.descriptorCount = 1u;
357 write_set.descriptorType = vk::DescriptorType::eInputAttachment;
358 write_set.pImageInfo = &image_workspace_[bound_image_offset_ - 1];
360 write_workspace_[descriptor_write_offset_++] = write_set;
365 void RenderPassVK::SetCommandLabel(std::string_view label) {
366 #ifdef IMPELLER_DEBUG
367 command_buffer_->PushDebugGroup(label);
373 void RenderPassVK::SetStencilReference(uint32_t
value) {
374 if (current_stencil_ ==
value) {
377 current_stencil_ =
value;
378 command_buffer_vk_.setStencilReference(
379 vk::StencilFaceFlagBits::eVkStencilFrontAndBack,
value);
383 void RenderPassVK::SetBaseVertex(uint64_t
value) {
384 base_vertex_ =
value;
388 void RenderPassVK::SetViewport(Viewport viewport) {
389 vk::Viewport viewport_vk = vk::Viewport()
390 .setWidth(viewport.rect.GetWidth())
391 .setHeight(-viewport.rect.GetHeight())
392 .setY(viewport.rect.GetHeight())
395 command_buffer_vk_.setViewport(0, 1, &viewport_vk);
399 void RenderPassVK::SetScissor(
IRect scissor) {
400 vk::Rect2D scissor_vk =
402 .setOffset(vk::Offset2D(scissor.GetX(), scissor.GetY()))
403 .setExtent(vk::Extent2D(scissor.GetWidth(), scissor.GetHeight()));
404 command_buffer_vk_.setScissor(0, 1, &scissor_vk);
408 void RenderPassVK::SetElementCount(
size_t count) {
409 element_count_ = count;
413 void RenderPassVK::SetInstanceCount(
size_t count) {
414 instance_count_ = count;
418 bool RenderPassVK::SetVertexBuffer(BufferView vertex_buffers[],
419 size_t vertex_buffer_count) {
420 if (!ValidateVertexBuffers(vertex_buffers, vertex_buffer_count)) {
426 for (
size_t i = 0; i < vertex_buffer_count; i++) {
428 DeviceBufferVK::Cast(*vertex_buffers[i].GetBuffer()).GetBuffer();
429 vertex_buffer_offsets[i] = vertex_buffers[i].GetRange().offset;
430 std::shared_ptr<const DeviceBuffer> device_buffer =
431 vertex_buffers[i].TakeBuffer();
433 command_buffer_->Track(device_buffer);
438 command_buffer_vk_.bindVertexBuffers(0u, vertex_buffer_count, buffers,
439 vertex_buffer_offsets);
445 bool RenderPassVK::SetIndexBuffer(BufferView index_buffer,
447 if (!ValidateIndexBuffer(index_buffer, index_type)) {
451 if (index_type != IndexType::kNone) {
452 has_index_buffer_ =
true;
454 BufferView index_buffer_view = std::move(index_buffer);
455 if (!index_buffer_view) {
459 if (!index_buffer_view.GetBuffer()) {
461 <<
" for index buffer view";
465 std::shared_ptr<const DeviceBuffer> index_buffer =
466 index_buffer_view.TakeBuffer();
467 if (index_buffer && !command_buffer_->Track(index_buffer)) {
471 vk::Buffer index_buffer_handle =
472 DeviceBufferVK::Cast(*index_buffer_view.GetBuffer()).GetBuffer();
473 command_buffer_vk_.bindIndexBuffer(index_buffer_handle,
474 index_buffer_view.GetRange().offset,
477 has_index_buffer_ =
false;
484 fml::Status RenderPassVK::Draw() {
486 return fml::Status(fml::StatusCode::kCancelled,
487 "No valid pipeline is bound to the RenderPass.");
507 if (immutable_sampler_) {
508 std::shared_ptr<Pipeline<PipelineDescriptor>> pipeline_variant =
509 PipelineVK::Cast(*pipeline_)
510 .CreateVariantForImmutableSamplers(immutable_sampler_);
511 if (!pipeline_variant) {
513 fml::StatusCode::kAborted,
514 "Could not create pipeline variant with immutable sampler.");
516 pipeline_ = raw_ptr(pipeline_variant);
519 const auto& context_vk = ContextVK::Cast(*context_);
520 const auto& pipeline_vk = PipelineVK::Cast(*pipeline_);
522 auto descriptor_result = command_buffer_->AllocateDescriptorSets(
523 pipeline_vk.GetDescriptorSetLayout(), pipeline_vk.GetPipelineKey(),
525 if (!descriptor_result.ok()) {
526 return fml::Status(fml::StatusCode::kAborted,
527 "Could not allocate descriptor sets.");
529 const auto descriptor_set = descriptor_result.value();
530 const auto pipeline_layout = pipeline_vk.GetPipelineLayout();
531 command_buffer_vk_.bindPipeline(vk::PipelineBindPoint::eGraphics,
532 pipeline_vk.GetPipeline());
534 for (
auto i = 0u; i < descriptor_write_offset_; i++) {
535 write_workspace_[i].dstSet = descriptor_set;
538 context_vk.GetDevice().updateDescriptorSets(descriptor_write_offset_,
539 write_workspace_.data(), 0u, {});
541 command_buffer_vk_.bindDescriptorSets(
542 vk::PipelineBindPoint::eGraphics,
551 if (pipeline_uses_input_attachments_) {
553 command_buffer_vk_, TextureVK::Cast(*color_image_vk_).GetImage());
556 if (has_index_buffer_) {
557 command_buffer_vk_.drawIndexed(element_count_,
564 command_buffer_vk_.draw(element_count_,
571 #ifdef IMPELLER_DEBUG
573 command_buffer_->PopDebugGroup();
577 has_index_buffer_ =
false;
578 bound_image_offset_ = 0u;
579 bound_buffer_offset_ = 0u;
580 descriptor_write_offset_ = 0u;
581 instance_count_ = 1u;
585 pipeline_uses_input_attachments_ =
false;
586 immutable_sampler_ =
nullptr;
587 return fml::Status();
594 const ShaderUniformSlot& slot,
595 const ShaderMetadata* metadata,
597 return BindResource(slot.binding,
type, view);
600 bool RenderPassVK::BindDynamicResource(
ShaderStage stage,
602 const ShaderUniformSlot& slot,
603 std::unique_ptr<ShaderMetadata> metadata,
605 return BindResource(slot.binding,
type, view);
608 bool RenderPassVK::BindResource(
size_t binding,
615 auto buffer = DeviceBufferVK::Cast(*view.GetBuffer()).GetBuffer();
620 std::shared_ptr<const DeviceBuffer> device_buffer = view.TakeBuffer();
621 if (device_buffer && !command_buffer_->Track(device_buffer)) {
625 uint32_t offset = view.GetRange().offset;
627 vk::DescriptorBufferInfo buffer_info;
628 buffer_info.buffer = buffer;
629 buffer_info.offset = offset;
630 buffer_info.range = view.GetRange().length;
631 buffer_workspace_[bound_buffer_offset_++] = buffer_info;
633 vk::WriteDescriptorSet write_set;
634 write_set.dstBinding = binding;
635 write_set.descriptorCount = 1u;
637 write_set.pBufferInfo = &buffer_workspace_[bound_buffer_offset_ - 1];
639 write_workspace_[descriptor_write_offset_++] = write_set;
643 bool RenderPassVK::BindDynamicResource(
ShaderStage stage,
645 const SampledImageSlot& slot,
646 std::unique_ptr<ShaderMetadata> metadata,
647 std::shared_ptr<const Texture> texture,
648 raw_ptr<const Sampler> sampler) {
649 return BindResource(stage,
type, slot,
nullptr, texture, sampler);
654 const SampledImageSlot& slot,
655 const ShaderMetadata* metadata,
656 std::shared_ptr<const Texture> texture,
657 raw_ptr<const Sampler> sampler) {
661 if (!texture || !texture->IsValid() || !sampler) {
664 const TextureVK& texture_vk = TextureVK::Cast(*texture);
665 const SamplerVK& sampler_vk = SamplerVK::Cast(*sampler);
667 if (!command_buffer_->Track(texture)) {
671 if (!immutable_sampler_) {
672 immutable_sampler_ = texture_vk.GetImmutableSamplerVariant(sampler_vk);
675 vk::DescriptorImageInfo image_info;
676 image_info.imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal;
677 image_info.sampler = sampler_vk.GetSampler();
678 image_info.imageView = texture_vk.GetImageView();
679 image_workspace_[bound_image_offset_++] = image_info;
681 vk::WriteDescriptorSet write_set;
682 write_set.dstBinding = slot.binding;
683 write_set.descriptorCount = 1u;
684 write_set.descriptorType = vk::DescriptorType::eCombinedImageSampler;
685 write_set.pImageInfo = &image_workspace_[bound_image_offset_ - 1];
687 write_workspace_[descriptor_write_offset_++] = write_set;
691 bool RenderPassVK::OnEncodeCommands(
const Context& context)
const {
692 command_buffer_->GetCommandBuffer().endRenderPass();
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
bool IsSwapchainImage() const
const FramebufferAndRenderPass & GetCachedFrameData(SampleCount sample_count) const
vk::ImageLayout SetLayoutWithoutEncoding(vk::ImageLayout layout) const
bool SetLayout(const BarrierVK &barrier) const
vk::ImageLayout GetLayout() const
void SetCachedFrameData(const FramebufferAndRenderPass &data, SampleCount sample_count)
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)