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;
339 context_->GetPipelineLibrary()->LogPipelineUsage(pipeline->GetDescriptor());
341 pipeline_uses_input_attachments_ =
342 pipeline_->GetDescriptor().GetVertexDescriptor()->UsesInputAttacments();
344 if (pipeline_uses_input_attachments_) {
349 vk::DescriptorImageInfo image_info;
350 image_info.imageLayout = vk::ImageLayout::eGeneral;
351 image_info.sampler = VK_NULL_HANDLE;
352 image_info.imageView = TextureVK::Cast(*color_image_vk_).GetImageView();
353 image_workspace_[bound_image_offset_++] = image_info;
355 vk::WriteDescriptorSet write_set;
357 write_set.descriptorCount = 1u;
358 write_set.descriptorType = vk::DescriptorType::eInputAttachment;
359 write_set.pImageInfo = &image_workspace_[bound_image_offset_ - 1];
361 write_workspace_[descriptor_write_offset_++] = write_set;
366 void RenderPassVK::SetCommandLabel(std::string_view label) {
367 #ifdef IMPELLER_DEBUG
368 command_buffer_->PushDebugGroup(label);
374 void RenderPassVK::SetStencilReference(uint32_t
value) {
375 if (current_stencil_ ==
value) {
378 current_stencil_ =
value;
379 command_buffer_vk_.setStencilReference(
380 vk::StencilFaceFlagBits::eVkStencilFrontAndBack,
value);
384 void RenderPassVK::SetBaseVertex(uint64_t
value) {
385 base_vertex_ =
value;
389 void RenderPassVK::SetViewport(Viewport viewport) {
390 vk::Viewport viewport_vk = vk::Viewport()
391 .setWidth(viewport.rect.GetWidth())
392 .setHeight(-viewport.rect.GetHeight())
393 .setY(viewport.rect.GetHeight())
396 command_buffer_vk_.setViewport(0, 1, &viewport_vk);
400 void RenderPassVK::SetScissor(
IRect32 scissor) {
401 vk::Rect2D scissor_vk =
403 .setOffset(vk::Offset2D(scissor.GetX(), scissor.GetY()))
404 .setExtent(vk::Extent2D(scissor.GetWidth(), scissor.GetHeight()));
405 command_buffer_vk_.setScissor(0, 1, &scissor_vk);
409 void RenderPassVK::SetElementCount(
size_t count) {
410 element_count_ = count;
414 void RenderPassVK::SetInstanceCount(
size_t count) {
415 instance_count_ = count;
419 bool RenderPassVK::SetVertexBuffer(BufferView vertex_buffers[],
420 size_t vertex_buffer_count) {
421 if (!ValidateVertexBuffers(vertex_buffers, vertex_buffer_count)) {
427 for (
size_t i = 0; i < vertex_buffer_count; i++) {
429 DeviceBufferVK::Cast(*vertex_buffers[i].GetBuffer()).GetBuffer();
430 vertex_buffer_offsets[i] = vertex_buffers[i].GetRange().offset;
431 std::shared_ptr<const DeviceBuffer> device_buffer =
432 vertex_buffers[i].TakeBuffer();
434 command_buffer_->Track(device_buffer);
439 command_buffer_vk_.bindVertexBuffers(0u, vertex_buffer_count, buffers,
440 vertex_buffer_offsets);
446 bool RenderPassVK::SetIndexBuffer(BufferView index_buffer,
448 if (!ValidateIndexBuffer(index_buffer, index_type)) {
452 if (index_type != IndexType::kNone) {
453 has_index_buffer_ =
true;
455 BufferView index_buffer_view = std::move(index_buffer);
456 if (!index_buffer_view) {
460 if (!index_buffer_view.GetBuffer()) {
462 <<
" for index buffer view";
466 std::shared_ptr<const DeviceBuffer> index_buffer =
467 index_buffer_view.TakeBuffer();
468 if (index_buffer && !command_buffer_->Track(index_buffer)) {
472 vk::Buffer index_buffer_handle =
473 DeviceBufferVK::Cast(*index_buffer_view.GetBuffer()).GetBuffer();
474 command_buffer_vk_.bindIndexBuffer(index_buffer_handle,
475 index_buffer_view.GetRange().offset,
478 has_index_buffer_ =
false;
485 fml::Status RenderPassVK::Draw() {
487 return fml::Status(fml::StatusCode::kCancelled,
488 "No valid pipeline is bound to the RenderPass.");
508 if (immutable_sampler_) {
509 std::shared_ptr<Pipeline<PipelineDescriptor>> pipeline_variant =
510 PipelineVK::Cast(*pipeline_)
511 .CreateVariantForImmutableSamplers(immutable_sampler_);
512 if (!pipeline_variant) {
514 fml::StatusCode::kAborted,
515 "Could not create pipeline variant with immutable sampler.");
517 pipeline_ = raw_ptr(pipeline_variant);
520 const auto& context_vk = ContextVK::Cast(*context_);
521 const auto& pipeline_vk = PipelineVK::Cast(*pipeline_);
523 auto descriptor_result = command_buffer_->AllocateDescriptorSets(
524 pipeline_vk.GetDescriptorSetLayout(), pipeline_vk.GetPipelineKey(),
526 if (!descriptor_result.ok()) {
527 return fml::Status(fml::StatusCode::kAborted,
528 "Could not allocate descriptor sets.");
530 const auto descriptor_set = descriptor_result.value();
531 const auto pipeline_layout = pipeline_vk.GetPipelineLayout();
532 command_buffer_vk_.bindPipeline(vk::PipelineBindPoint::eGraphics,
533 pipeline_vk.GetPipeline());
535 for (
auto i = 0u; i < descriptor_write_offset_; i++) {
536 write_workspace_[i].dstSet = descriptor_set;
539 context_vk.GetDevice().updateDescriptorSets(descriptor_write_offset_,
540 write_workspace_.data(), 0u, {});
542 command_buffer_vk_.bindDescriptorSets(
543 vk::PipelineBindPoint::eGraphics,
552 if (pipeline_uses_input_attachments_) {
554 command_buffer_vk_, TextureVK::Cast(*color_image_vk_).GetImage());
557 if (has_index_buffer_) {
558 command_buffer_vk_.drawIndexed(element_count_,
565 command_buffer_vk_.draw(element_count_,
572 #ifdef IMPELLER_DEBUG
574 command_buffer_->PopDebugGroup();
578 has_index_buffer_ =
false;
579 bound_image_offset_ = 0u;
580 bound_buffer_offset_ = 0u;
581 descriptor_write_offset_ = 0u;
582 instance_count_ = 1u;
586 pipeline_uses_input_attachments_ =
false;
587 immutable_sampler_ =
nullptr;
588 return fml::Status();
595 const ShaderUniformSlot& slot,
596 const ShaderMetadata* metadata,
598 return BindResource(slot.binding,
type, view);
601 bool RenderPassVK::BindDynamicResource(
ShaderStage stage,
603 const ShaderUniformSlot& slot,
604 std::unique_ptr<ShaderMetadata> metadata,
606 return BindResource(slot.binding,
type, view);
609 bool RenderPassVK::BindResource(
size_t binding,
616 auto buffer = DeviceBufferVK::Cast(*view.GetBuffer()).GetBuffer();
621 std::shared_ptr<const DeviceBuffer> device_buffer = view.TakeBuffer();
622 if (device_buffer && !command_buffer_->Track(device_buffer)) {
626 uint32_t offset = view.GetRange().offset;
628 vk::DescriptorBufferInfo buffer_info;
629 buffer_info.buffer = buffer;
630 buffer_info.offset = offset;
631 buffer_info.range = view.GetRange().length;
632 buffer_workspace_[bound_buffer_offset_++] = buffer_info;
634 vk::WriteDescriptorSet write_set;
635 write_set.dstBinding = binding;
636 write_set.descriptorCount = 1u;
638 write_set.pBufferInfo = &buffer_workspace_[bound_buffer_offset_ - 1];
640 write_workspace_[descriptor_write_offset_++] = write_set;
644 bool RenderPassVK::BindDynamicResource(
ShaderStage stage,
646 const SampledImageSlot& slot,
647 std::unique_ptr<ShaderMetadata> metadata,
648 std::shared_ptr<const Texture> texture,
649 raw_ptr<const Sampler> sampler) {
650 return BindResource(stage,
type, slot,
nullptr, texture, sampler);
655 const SampledImageSlot& slot,
656 const ShaderMetadata* metadata,
657 std::shared_ptr<const Texture> texture,
658 raw_ptr<const Sampler> sampler) {
662 if (!texture || !texture->IsValid() || !sampler) {
665 const TextureVK& texture_vk = TextureVK::Cast(*texture);
666 const SamplerVK& sampler_vk = SamplerVK::Cast(*sampler);
668 if (!command_buffer_->Track(texture)) {
672 if (!immutable_sampler_) {
673 immutable_sampler_ = texture_vk.GetImmutableSamplerVariant(sampler_vk);
676 vk::DescriptorImageInfo image_info;
677 image_info.imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal;
678 image_info.sampler = sampler_vk.GetSampler();
679 image_info.imageView = texture_vk.GetImageView();
680 image_workspace_[bound_image_offset_++] = image_info;
682 vk::WriteDescriptorSet write_set;
683 write_set.dstBinding = slot.binding;
684 write_set.descriptorCount = 1u;
685 write_set.descriptorType = vk::DescriptorType::eCombinedImageSampler;
686 write_set.pImageInfo = &image_workspace_[bound_image_offset_ - 1];
688 write_workspace_[descriptor_write_offset_++] = write_set;
692 bool RenderPassVK::OnEncodeCommands(
const Context& context)
const {
693 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)