10 #include "fml/status.h"
38 vk::ClearColorValue
value;
46 vk::ClearDepthStencilValue
value;
48 value.stencil = stencil;
58 const auto& rect = viewport.
rect;
61 .setY(rect.GetY() + rect.GetHeight())
62 .setWidth(rect.GetWidth())
63 .setHeight(-rect.GetHeight())
70 std::array<vk::ClearValue, kMaxAttachments>& values) {
73 [&values, &offset](
size_t index,
77 values.at(offset++) = VKClearValueFromColor(attachment.clear_color);
85 if (depth.has_value()) {
87 stencil ? stencil->clear_stencil : 0u, depth->clear_depth);
88 }
else if (stencil.has_value()) {
90 stencil->clear_stencil, depth ? depth->clear_depth : 0.0f);
95 SharedHandleVK<vk::RenderPass> RenderPassVK::CreateVKRenderPass(
97 const SharedHandleVK<vk::RenderPass>& recycled_renderpass,
99 bool is_swapchain)
const {
100 if (recycled_renderpass !=
nullptr) {
101 return recycled_renderpass;
104 RenderPassBuilderVK builder;
106 const ColorAttachment&
107 attachment) ->
bool {
108 builder.SetColorAttachment(
110 attachment.texture->GetTextureDescriptor().format,
111 attachment.texture->GetTextureDescriptor().sample_count,
112 attachment.load_action,
113 attachment.store_action,
120 builder.SetDepthStencilAttachment(
121 depth->texture->GetTextureDescriptor().format,
122 depth->texture->GetTextureDescriptor().sample_count,
127 stencil.has_value()) {
128 builder.SetStencilAttachment(
129 stencil->texture->GetTextureDescriptor().format,
130 stencil->texture->GetTextureDescriptor().sample_count,
131 stencil->load_action,
132 stencil->store_action
136 auto pass = builder.Build(
context.GetDevice());
139 VALIDATION_LOG <<
"Failed to create render pass for framebuffer.";
143 context.SetDebugName(pass.get(), debug_label_.c_str());
148 RenderPassVK::RenderPassVK(
const std::shared_ptr<const Context>&
context,
149 const RenderTarget& target,
152 const ColorAttachment& color0 = render_target_.GetColorAttachment(0);
153 color_image_vk_ = color0.texture;
154 resolve_image_vk_ = color0.resolve_texture;
157 command_buffer_vk_ = command_buffer_->GetCommandBuffer();
158 render_target_.IterateAllAttachments([&](
const auto& attachment) ->
bool {
159 command_buffer_->Track(attachment.texture);
160 command_buffer_->Track(attachment.resolve_texture);
164 FramebufferAndRenderPass frame_data;
165 bool is_swapchain =
false;
167 color_image_vk_->GetTextureDescriptor().sample_count;
172 const uint32_t cache_mip_level = color0.mip_level;
173 const uint32_t cache_slice = color0.slice;
175 resolve_image_vk_ ? *resolve_image_vk_ : *color_image_vk_);
176 is_swapchain = frame_data_texture.IsSwapchainImage();
177 frame_data = frame_data_texture.GetCachedFrameData(
178 sample_count, cache_mip_level, cache_slice);
180 const auto& target_size = render_target_.GetRenderTargetSize();
182 render_pass_ = CreateVKRenderPass(vk_context, frame_data.render_pass,
183 command_buffer_, is_swapchain);
190 auto framebuffer = (frame_data.framebuffer ==
nullptr)
191 ? CreateVKFramebuffer(vk_context, *render_pass_)
192 : frame_data.framebuffer;
199 if (!command_buffer_->Track(framebuffer) ||
200 !command_buffer_->Track(render_pass_)) {
205 frame_data.framebuffer = framebuffer;
206 frame_data.render_pass = render_pass_;
208 frame_data_texture.SetCachedFrameData(frame_data, sample_count,
209 cache_mip_level, cache_slice);
213 if (resolve_image_vk_ &&
214 resolve_image_vk_->GetTextureDescriptor().mip_count > 1) {
216 vk::ImageLayout::eUndefined) {
218 barrier.new_layout = vk::ImageLayout::eShaderReadOnlyOptimal;
219 barrier.cmd_buffer = command_buffer_->GetCommandBuffer();
220 barrier.src_stage = vk::PipelineStageFlagBits::eBottomOfPipe;
221 barrier.src_access = {};
222 barrier.dst_stage = vk::PipelineStageFlagBits::eFragmentShader;
223 barrier.dst_access = vk::AccessFlagBits::eShaderRead;
224 barrier.base_mip_level = 1;
229 std::array<vk::ClearValue, kMaxAttachments> clears;
232 vk::RenderPassBeginInfo pass_info;
233 pass_info.renderPass = *render_pass_;
234 pass_info.framebuffer = *framebuffer;
235 pass_info.renderArea.extent.width =
static_cast<uint32_t
>(target_size.width);
236 pass_info.renderArea.extent.height =
237 static_cast<uint32_t
>(target_size.height);
238 pass_info.setPClearValues(clears.data());
239 pass_info.setClearValueCount(clear_count);
241 command_buffer_vk_.beginRenderPass(pass_info, vk::SubpassContents::eInline);
243 if (resolve_image_vk_) {
246 is_swapchain ? vk::ImageLayout::eGeneral
247 : vk::ImageLayout::eShaderReadOnlyOptimal);
249 if (color_image_vk_) {
260 ? vk::ImageLayout::eGeneral
261 : vk::ImageLayout::eShaderReadOnlyOptimal);
267 command_buffer_vk_.setViewport(0, 1, &viewport);
273 .setOffset(vk::Offset2D(sc.GetX(), sc.GetY()))
274 .setExtent(vk::Extent2D(sc.GetWidth(), sc.GetHeight()));
275 command_buffer_vk_.setScissor(0, 1, &scissor);
278 command_buffer_vk_.setStencilReference(vk::StencilFaceFlagBits::eFrontAndBack,
284 RenderPassVK::~RenderPassVK() =
default;
286 bool RenderPassVK::IsValid()
const {
290 void RenderPassVK::OnSetLabel(std::string_view label) {
291 #ifdef IMPELLER_DEBUG
292 ContextVK::Cast(*context_).SetDebugName(render_pass_->Get(), label.data());
296 SharedHandleVK<vk::Framebuffer> RenderPassVK::CreateVKFramebuffer(
298 const vk::RenderPass& pass)
const {
299 vk::FramebufferCreateInfo fb_info;
301 fb_info.renderPass = pass;
303 const auto target_size = render_target_.GetRenderTargetSize();
304 fb_info.width = target_size.width;
305 fb_info.height = target_size.height;
308 std::array<vk::ImageView, kMaxAttachments> attachments;
314 render_target_.IterateAllColorAttachments(
315 [&attachments, &count](
size_t index,
316 const ColorAttachment& attachment) ->
bool {
319 attachments[count++] =
320 TextureVK::Cast(*attachment.texture)
321 .GetRenderTargetView(attachment.mip_level, attachment.slice);
322 if (attachment.resolve_texture) {
324 attachments[count++] = TextureVK::Cast(*attachment.resolve_texture)
325 .GetRenderTargetView();
330 if (
auto depth = render_target_.GetDepthAttachment(); depth.has_value()) {
331 attachments[count++] =
332 TextureVK::Cast(*depth->texture)
333 .GetRenderTargetView(depth->mip_level, depth->slice);
334 }
else if (
auto stencil = render_target_.GetStencilAttachment();
335 stencil.has_value()) {
336 attachments[count++] =
337 TextureVK::Cast(*stencil->texture)
338 .GetRenderTargetView(stencil->mip_level, stencil->slice);
341 fb_info.setPAttachments(attachments.data());
342 fb_info.setAttachmentCount(count);
344 auto [result, framebuffer] =
345 context.GetDevice().createFramebufferUnique(fb_info);
347 if (result != vk::Result::eSuccess) {
348 VALIDATION_LOG <<
"Could not create framebuffer: " << vk::to_string(result);
361 context_->GetPipelineLibrary()->LogPipelineUsage(
pipeline->GetDescriptor());
363 pipeline_uses_input_attachments_ =
364 pipeline_->GetDescriptor().GetVertexDescriptor()->UsesInputAttachments();
366 if (pipeline_uses_input_attachments_) {
371 vk::DescriptorImageInfo image_info;
372 image_info.imageLayout = vk::ImageLayout::eGeneral;
373 image_info.sampler = VK_NULL_HANDLE;
374 image_info.imageView = TextureVK::Cast(*color_image_vk_).GetImageView();
375 image_workspace_[bound_image_offset_++] = image_info;
377 vk::WriteDescriptorSet write_set;
379 write_set.descriptorCount = 1u;
380 write_set.descriptorType = vk::DescriptorType::eInputAttachment;
381 write_set.pImageInfo = &image_workspace_[bound_image_offset_ - 1];
383 write_workspace_[descriptor_write_offset_++] = write_set;
388 void RenderPassVK::SetCommandLabel(std::string_view label) {
389 #ifdef IMPELLER_DEBUG
390 command_buffer_->PushDebugGroup(label);
396 void RenderPassVK::SetStencilReference(uint32_t
value) {
397 if (current_stencil_ ==
value) {
400 current_stencil_ =
value;
401 command_buffer_vk_.setStencilReference(vk::StencilFaceFlagBits::eFrontAndBack,
406 void RenderPassVK::SetBaseVertex(uint64_t
value) {
407 base_vertex_ =
value;
411 void RenderPassVK::SetViewport(Viewport viewport) {
413 command_buffer_vk_.setViewport(0, 1, &viewport_vk);
417 void RenderPassVK::SetScissor(
IRect32 scissor) {
418 vk::Rect2D scissor_vk =
420 .setOffset(vk::Offset2D(scissor.GetX(), scissor.GetY()))
421 .setExtent(vk::Extent2D(scissor.GetWidth(), scissor.GetHeight()));
422 command_buffer_vk_.setScissor(0, 1, &scissor_vk);
426 void RenderPassVK::SetElementCount(
size_t count) {
427 element_count_ = count;
431 void RenderPassVK::SetInstanceCount(
size_t count) {
432 instance_count_ = count;
436 bool RenderPassVK::SetVertexBuffer(BufferView vertex_buffers[],
437 size_t vertex_buffer_count) {
438 if (!ValidateVertexBuffers(vertex_buffers, vertex_buffer_count)) {
444 for (
size_t i = 0; i < vertex_buffer_count; i++) {
446 DeviceBufferVK::Cast(*vertex_buffers[i].GetBuffer()).GetBuffer();
447 vertex_buffer_offsets[i] = vertex_buffers[i].GetRange().offset;
448 std::shared_ptr<const DeviceBuffer> device_buffer =
449 vertex_buffers[i].TakeBuffer();
451 command_buffer_->Track(device_buffer);
456 command_buffer_vk_.bindVertexBuffers(0u, vertex_buffer_count, buffers,
457 vertex_buffer_offsets);
463 bool RenderPassVK::SetIndexBuffer(BufferView index_buffer,
465 if (!ValidateIndexBuffer(index_buffer, index_type)) {
469 if (index_type != IndexType::kNone) {
470 has_index_buffer_ =
true;
472 BufferView index_buffer_view = std::move(index_buffer);
473 if (!index_buffer_view) {
477 if (!index_buffer_view.GetBuffer()) {
479 <<
" for index buffer view";
483 std::shared_ptr<const DeviceBuffer> index_buffer =
484 index_buffer_view.TakeBuffer();
485 if (index_buffer && !command_buffer_->Track(index_buffer)) {
489 vk::Buffer index_buffer_handle =
490 DeviceBufferVK::Cast(*index_buffer_view.GetBuffer()).GetBuffer();
491 command_buffer_vk_.bindIndexBuffer(index_buffer_handle,
492 index_buffer_view.GetRange().offset,
495 has_index_buffer_ =
false;
502 fml::Status RenderPassVK::Draw() {
504 return fml::Status(fml::StatusCode::kCancelled,
505 "No valid pipeline is bound to the RenderPass.");
525 if (immutable_sampler_) {
526 std::shared_ptr<Pipeline<PipelineDescriptor>> pipeline_variant =
527 PipelineVK::Cast(*pipeline_)
528 .CreateVariantForImmutableSamplers(immutable_sampler_);
529 if (!pipeline_variant) {
531 fml::StatusCode::kAborted,
532 "Could not create pipeline variant with immutable sampler.");
534 pipeline_ = raw_ptr(pipeline_variant);
537 const auto& context_vk = ContextVK::Cast(*context_);
538 const auto& pipeline_vk = PipelineVK::Cast(*pipeline_);
540 auto descriptor_result = command_buffer_->AllocateDescriptorSets(
541 pipeline_vk.GetDescriptorSetLayout(), pipeline_vk.GetPipelineKey(),
543 if (!descriptor_result.ok()) {
544 return fml::Status(fml::StatusCode::kAborted,
545 "Could not allocate descriptor sets.");
547 const auto descriptor_set = descriptor_result.value();
548 const auto pipeline_layout = pipeline_vk.GetPipelineLayout();
549 command_buffer_vk_.bindPipeline(vk::PipelineBindPoint::eGraphics,
550 pipeline_vk.GetPipeline());
552 for (
auto i = 0u; i < descriptor_write_offset_; i++) {
553 write_workspace_[i].dstSet = descriptor_set;
556 context_vk.GetDevice().updateDescriptorSets(descriptor_write_offset_,
557 write_workspace_.data(), 0u, {});
559 command_buffer_vk_.bindDescriptorSets(
560 vk::PipelineBindPoint::eGraphics,
569 if (pipeline_uses_input_attachments_) {
571 command_buffer_vk_, TextureVK::Cast(*color_image_vk_).GetImage());
574 if (has_index_buffer_) {
575 command_buffer_vk_.drawIndexed(element_count_,
582 command_buffer_vk_.draw(element_count_,
589 #ifdef IMPELLER_DEBUG
591 command_buffer_->PopDebugGroup();
595 has_index_buffer_ =
false;
596 bound_image_offset_ = 0u;
597 bound_buffer_offset_ = 0u;
598 descriptor_write_offset_ = 0u;
599 instance_count_ = 1u;
603 pipeline_uses_input_attachments_ =
false;
604 immutable_sampler_ =
nullptr;
605 return fml::Status();
612 const ShaderUniformSlot& slot,
613 const ShaderMetadata* metadata,
615 return BindResource(slot.binding, type, view);
618 bool RenderPassVK::BindDynamicResource(
ShaderStage stage,
620 const ShaderUniformSlot& slot,
621 std::unique_ptr<ShaderMetadata> metadata,
623 return BindResource(slot.binding, type, view);
626 bool RenderPassVK::BindResource(
size_t binding,
633 auto buffer = DeviceBufferVK::Cast(*view.GetBuffer()).GetBuffer();
638 std::shared_ptr<const DeviceBuffer> device_buffer = view.TakeBuffer();
639 if (device_buffer && !command_buffer_->Track(device_buffer)) {
643 uint32_t offset = view.GetRange().offset;
645 vk::DescriptorBufferInfo buffer_info;
646 buffer_info.buffer = buffer;
647 buffer_info.offset = offset;
648 buffer_info.range = view.GetRange().length;
649 buffer_workspace_[bound_buffer_offset_++] = buffer_info;
651 vk::WriteDescriptorSet write_set;
652 write_set.dstBinding = binding;
653 write_set.descriptorCount = 1u;
655 write_set.pBufferInfo = &buffer_workspace_[bound_buffer_offset_ - 1];
657 write_workspace_[descriptor_write_offset_++] = write_set;
661 bool RenderPassVK::BindDynamicResource(
ShaderStage stage,
663 const SampledImageSlot& slot,
664 std::unique_ptr<ShaderMetadata> metadata,
665 std::shared_ptr<const Texture> texture,
666 raw_ptr<const Sampler> sampler) {
667 return BindResource(stage, type, slot,
nullptr, texture, sampler);
672 const SampledImageSlot& slot,
673 const ShaderMetadata* metadata,
674 std::shared_ptr<const Texture> texture,
675 raw_ptr<const Sampler> sampler) {
679 if (!texture || !texture->IsValid() || !sampler) {
682 const TextureVK& texture_vk = TextureVK::Cast(*texture);
683 const SamplerVK& sampler_vk = SamplerVK::Cast(*sampler);
685 if (!command_buffer_->Track(texture)) {
689 if (!immutable_sampler_) {
690 immutable_sampler_ = texture_vk.GetImmutableSamplerVariant(sampler_vk);
693 vk::DescriptorImageInfo image_info;
694 image_info.imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal;
695 image_info.sampler = sampler_vk.GetSampler();
696 image_info.imageView = texture_vk.GetImageView();
697 image_workspace_[bound_image_offset_++] = image_info;
699 vk::WriteDescriptorSet write_set;
700 write_set.dstBinding = slot.binding;
701 write_set.descriptorCount = 1u;
702 write_set.descriptorType = vk::DescriptorType::eCombinedImageSampler;
703 write_set.pImageInfo = &image_workspace_[bound_image_offset_ - 1];
705 write_workspace_[descriptor_write_offset_++] = write_set;
709 bool RenderPassVK::OnEncodeCommands(
const Context&
context)
const {
710 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
vk::ImageLayout SetLayoutWithoutEncoding(vk::ImageLayout layout) const
bool SetLayout(const BarrierVK &barrier) const
vk::ImageLayout GetLayout() const
static vk::Viewport ToVkViewport(const Viewport &viewport)
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< ContextGLES > context
std::shared_ptr< PipelineGLES > pipeline
std::shared_ptr< CommandBuffer > command_buffer
std::shared_ptr< Texture > resolve_texture
constexpr static TRect MakeSize(const TSize< U > &size)