10 #include "fml/status.h"
37 vk::ClearColorValue
value;
45 vk::ClearDepthStencilValue
value;
47 value.stencil = stencil;
53 std::array<vk::ClearValue, kMaxAttachments>& values) {
56 [&values, &
offset](
size_t index,
60 values.at(offset++) = VKClearValueFromColor(attachment.clear_color);
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);
78 SharedHandleVK<vk::RenderPass> RenderPassVK::CreateVKRenderPass(
79 const ContextVK& context,
80 const SharedHandleVK<vk::RenderPass>& recycled_renderpass,
81 const std::shared_ptr<CommandBufferVK>& command_buffer,
82 bool is_swapchain)
const {
83 RenderPassBuilderVK builder;
86 const ColorAttachment&
88 builder.SetColorAttachment(
90 attachment.texture->GetTextureDescriptor().format,
91 attachment.texture->GetTextureDescriptor().sample_count,
92 attachment.load_action,
93 attachment.store_action,
100 builder.SetDepthStencilAttachment(
101 depth->texture->GetTextureDescriptor().format,
102 depth->texture->GetTextureDescriptor().sample_count,
107 stencil.has_value()) {
108 builder.SetStencilAttachment(
109 stencil->texture->GetTextureDescriptor().format,
110 stencil->texture->GetTextureDescriptor().sample_count,
111 stencil->load_action,
112 stencil->store_action
116 if (recycled_renderpass !=
nullptr) {
117 return recycled_renderpass;
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 SharedHandleVK<vk::RenderPass> recycled_render_pass;
149 SharedHandleVK<vk::Framebuffer> recycled_framebuffer;
150 if (resolve_image_vk_) {
151 recycled_render_pass =
153 recycled_framebuffer =
156 recycled_render_pass =
158 recycled_framebuffer =
162 const auto& target_size = render_target_.GetRenderTargetSize();
164 bool is_swapchain =
false;
165 if (resolve_image_vk_) {
171 render_pass_ = CreateVKRenderPass(vk_context, recycled_render_pass,
172 command_buffer_, is_swapchain);
179 auto framebuffer = (recycled_framebuffer ==
nullptr)
180 ? CreateVKFramebuffer(vk_context, *render_pass_)
181 : recycled_framebuffer;
188 if (!command_buffer_->Track(framebuffer) ||
189 !command_buffer_->Track(render_pass_)) {
193 if (resolve_image_vk_) {
201 std::array<vk::ClearValue, kMaxAttachments> clears;
204 vk::RenderPassBeginInfo pass_info;
205 pass_info.renderPass = *render_pass_;
206 pass_info.framebuffer = *framebuffer;
207 pass_info.renderArea.extent.width =
static_cast<uint32_t
>(target_size.width);
208 pass_info.renderArea.extent.height =
209 static_cast<uint32_t
>(target_size.height);
210 pass_info.setPClearValues(clears.data());
211 pass_info.setClearValueCount(clear_count);
213 command_buffer_vk_.beginRenderPass(pass_info, vk::SubpassContents::eInline);
215 if (resolve_image_vk_) {
218 is_swapchain ? vk::ImageLayout::eGeneral
219 : vk::ImageLayout::eShaderReadOnlyOptimal);
221 if (color_image_vk_) {
228 vk::Viewport viewport = vk::Viewport()
229 .setWidth(vp.rect.GetWidth())
230 .setHeight(-vp.rect.GetHeight())
231 .setY(vp.rect.GetHeight())
234 command_buffer_vk_.setViewport(0, 1, &viewport);
240 .setOffset(vk::Offset2D(sc.GetX(), sc.GetY()))
241 .setExtent(vk::Extent2D(sc.GetWidth(), sc.GetHeight()));
242 command_buffer_vk_.setScissor(0, 1, &scissor);
245 command_buffer_vk_.setStencilReference(
246 vk::StencilFaceFlagBits::eVkStencilFrontAndBack, 0u);
251 RenderPassVK::~RenderPassVK() =
default;
253 bool RenderPassVK::IsValid()
const {
257 void RenderPassVK::OnSetLabel(std::string_view label) {
258 #ifdef IMPELLER_DEBUG
259 ContextVK::Cast(*context_).SetDebugName(render_pass_->Get(), label.data());
263 SharedHandleVK<vk::Framebuffer> RenderPassVK::CreateVKFramebuffer(
264 const ContextVK& context,
265 const vk::RenderPass& pass)
const {
266 vk::FramebufferCreateInfo fb_info;
268 fb_info.renderPass = pass;
270 const auto target_size = render_target_.GetRenderTargetSize();
271 fb_info.width = target_size.width;
272 fb_info.height = target_size.height;
275 std::array<vk::ImageView, kMaxAttachments> attachments;
281 render_target_.IterateAllColorAttachments(
282 [&attachments, &count](
size_t index,
283 const ColorAttachment& attachment) ->
bool {
286 attachments[count++] =
287 TextureVK::Cast(*attachment.texture).GetRenderTargetView();
288 if (attachment.resolve_texture) {
289 attachments[count++] = TextureVK::Cast(*attachment.resolve_texture)
290 .GetRenderTargetView();
295 if (
auto depth = render_target_.GetDepthAttachment(); depth.has_value()) {
296 attachments[count++] =
297 TextureVK::Cast(*depth->texture).GetRenderTargetView();
298 }
else if (
auto stencil = render_target_.GetStencilAttachment();
299 stencil.has_value()) {
300 attachments[count++] =
301 TextureVK::Cast(*stencil->texture).GetRenderTargetView();
304 fb_info.setPAttachments(attachments.data());
305 fb_info.setAttachmentCount(count);
307 auto [result, framebuffer] =
308 context.GetDevice().createFramebufferUnique(fb_info);
310 if (result != vk::Result::eSuccess) {
311 VALIDATION_LOG <<
"Could not create framebuffer: " << vk::to_string(result);
319 void RenderPassVK::SetPipeline(
PipelineRef pipeline) {
320 pipeline_ = pipeline;
325 pipeline_uses_input_attachments_ =
326 pipeline_->GetDescriptor().GetVertexDescriptor()->UsesInputAttacments();
328 if (pipeline_uses_input_attachments_) {
333 vk::DescriptorImageInfo image_info;
334 image_info.imageLayout = vk::ImageLayout::eGeneral;
335 image_info.sampler = VK_NULL_HANDLE;
336 image_info.imageView = TextureVK::Cast(*color_image_vk_).GetImageView();
337 image_workspace_[bound_image_offset_++] = image_info;
339 vk::WriteDescriptorSet write_set;
341 write_set.descriptorCount = 1u;
342 write_set.descriptorType = vk::DescriptorType::eInputAttachment;
343 write_set.pImageInfo = &image_workspace_[bound_image_offset_ - 1];
345 write_workspace_[descriptor_write_offset_++] = write_set;
350 void RenderPassVK::SetCommandLabel(std::string_view label) {
351 #ifdef IMPELLER_DEBUG
352 command_buffer_->PushDebugGroup(label);
358 void RenderPassVK::SetStencilReference(uint32_t
value) {
359 if (current_stencil_ ==
value) {
362 current_stencil_ =
value;
363 command_buffer_vk_.setStencilReference(
364 vk::StencilFaceFlagBits::eVkStencilFrontAndBack,
value);
368 void RenderPassVK::SetBaseVertex(uint64_t
value) {
369 base_vertex_ =
value;
373 void RenderPassVK::SetViewport(Viewport viewport) {
374 vk::Viewport viewport_vk = vk::Viewport()
375 .setWidth(viewport.rect.GetWidth())
376 .setHeight(-viewport.rect.GetHeight())
377 .setY(viewport.rect.GetHeight())
380 command_buffer_vk_.setViewport(0, 1, &viewport_vk);
384 void RenderPassVK::SetScissor(
IRect scissor) {
385 vk::Rect2D scissor_vk =
387 .setOffset(vk::Offset2D(scissor.GetX(), scissor.GetY()))
388 .setExtent(vk::Extent2D(scissor.GetWidth(), scissor.GetHeight()));
389 command_buffer_vk_.setScissor(0, 1, &scissor_vk);
393 void RenderPassVK::SetElementCount(
size_t count) {
394 element_count_ = count;
398 void RenderPassVK::SetInstanceCount(
size_t count) {
399 instance_count_ = count;
403 bool RenderPassVK::SetVertexBuffer(BufferView vertex_buffers[],
404 size_t vertex_buffer_count) {
405 if (!ValidateVertexBuffers(vertex_buffers, vertex_buffer_count)) {
411 for (
size_t i = 0; i < vertex_buffer_count; i++) {
413 DeviceBufferVK::Cast(*vertex_buffers[i].GetBuffer()).GetBuffer();
414 vertex_buffer_offsets[i] = vertex_buffers[i].GetRange().offset;
415 std::shared_ptr<const DeviceBuffer> device_buffer =
416 vertex_buffers[i].TakeBuffer();
418 command_buffer_->Track(device_buffer);
423 command_buffer_vk_.bindVertexBuffers(0u, vertex_buffer_count, buffers,
424 vertex_buffer_offsets);
430 bool RenderPassVK::SetIndexBuffer(BufferView index_buffer,
432 if (!ValidateIndexBuffer(index_buffer, index_type)) {
436 if (index_type != IndexType::kNone) {
437 has_index_buffer_ =
true;
439 BufferView index_buffer_view = std::move(index_buffer);
440 if (!index_buffer_view) {
444 if (!index_buffer_view.GetBuffer()) {
446 <<
" for index buffer view";
450 std::shared_ptr<const DeviceBuffer> index_buffer =
451 index_buffer_view.TakeBuffer();
452 if (index_buffer && !command_buffer_->Track(index_buffer)) {
456 vk::Buffer index_buffer_handle =
457 DeviceBufferVK::Cast(*index_buffer_view.GetBuffer()).GetBuffer();
458 command_buffer_vk_.bindIndexBuffer(index_buffer_handle,
459 index_buffer_view.GetRange().offset,
462 has_index_buffer_ =
false;
469 fml::Status RenderPassVK::Draw() {
471 return fml::Status(fml::StatusCode::kCancelled,
472 "No valid pipeline is bound to the RenderPass.");
492 if (immutable_sampler_) {
493 std::shared_ptr<Pipeline<PipelineDescriptor>> pipeline_variant =
494 PipelineVK::Cast(*pipeline_)
495 .CreateVariantForImmutableSamplers(immutable_sampler_);
496 if (!pipeline_variant) {
498 fml::StatusCode::kAborted,
499 "Could not create pipeline variant with immutable sampler.");
501 pipeline_ = raw_ptr(pipeline_variant);
504 const auto& context_vk = ContextVK::Cast(*context_);
505 const auto& pipeline_vk = PipelineVK::Cast(*pipeline_);
507 auto descriptor_result = command_buffer_->AllocateDescriptorSets(
508 pipeline_vk.GetDescriptorSetLayout(), pipeline_vk.GetPipelineKey(),
510 if (!descriptor_result.ok()) {
511 return fml::Status(fml::StatusCode::kAborted,
512 "Could not allocate descriptor sets.");
514 const auto descriptor_set = descriptor_result.value();
515 const auto pipeline_layout = pipeline_vk.GetPipelineLayout();
516 command_buffer_vk_.bindPipeline(vk::PipelineBindPoint::eGraphics,
517 pipeline_vk.GetPipeline());
519 for (
auto i = 0u; i < descriptor_write_offset_; i++) {
520 write_workspace_[i].dstSet = descriptor_set;
523 context_vk.GetDevice().updateDescriptorSets(descriptor_write_offset_,
524 write_workspace_.data(), 0u, {});
526 command_buffer_vk_.bindDescriptorSets(
527 vk::PipelineBindPoint::eGraphics,
536 if (pipeline_uses_input_attachments_) {
538 command_buffer_vk_, TextureVK::Cast(*color_image_vk_).GetImage());
541 if (has_index_buffer_) {
542 command_buffer_vk_.drawIndexed(element_count_,
549 command_buffer_vk_.draw(element_count_,
556 #ifdef IMPELLER_DEBUG
558 command_buffer_->PopDebugGroup();
562 has_index_buffer_ =
false;
563 bound_image_offset_ = 0u;
564 bound_buffer_offset_ = 0u;
565 descriptor_write_offset_ = 0u;
566 instance_count_ = 1u;
570 pipeline_uses_input_attachments_ =
false;
571 immutable_sampler_ =
nullptr;
572 return fml::Status();
579 const ShaderUniformSlot& slot,
580 const ShaderMetadata* metadata,
582 return BindResource(slot.binding,
type, view);
585 bool RenderPassVK::BindDynamicResource(
ShaderStage stage,
587 const ShaderUniformSlot& slot,
588 std::unique_ptr<ShaderMetadata> metadata,
590 return BindResource(slot.binding,
type, view);
593 bool RenderPassVK::BindResource(
size_t binding,
600 auto buffer = DeviceBufferVK::Cast(*view.GetBuffer()).GetBuffer();
605 std::shared_ptr<const DeviceBuffer> device_buffer = view.TakeBuffer();
606 if (device_buffer && !command_buffer_->Track(device_buffer)) {
610 uint32_t
offset = view.GetRange().offset;
612 vk::DescriptorBufferInfo buffer_info;
613 buffer_info.buffer = buffer;
614 buffer_info.offset =
offset;
615 buffer_info.range = view.GetRange().length;
616 buffer_workspace_[bound_buffer_offset_++] = buffer_info;
618 vk::WriteDescriptorSet write_set;
619 write_set.dstBinding = binding;
620 write_set.descriptorCount = 1u;
622 write_set.pBufferInfo = &buffer_workspace_[bound_buffer_offset_ - 1];
624 write_workspace_[descriptor_write_offset_++] = write_set;
628 bool RenderPassVK::BindDynamicResource(
ShaderStage stage,
630 const SampledImageSlot& slot,
631 std::unique_ptr<ShaderMetadata> metadata,
632 std::shared_ptr<const Texture> texture,
633 raw_ptr<const Sampler> sampler) {
634 return BindResource(stage,
type, slot,
nullptr, texture, sampler);
639 const SampledImageSlot& slot,
640 const ShaderMetadata* metadata,
641 std::shared_ptr<const Texture> texture,
642 raw_ptr<const Sampler> sampler) {
646 if (!texture || !texture->IsValid() || !sampler) {
649 const TextureVK& texture_vk = TextureVK::Cast(*texture);
650 const SamplerVK& sampler_vk = SamplerVK::Cast(*sampler);
652 if (!command_buffer_->Track(texture)) {
656 if (!immutable_sampler_) {
657 immutable_sampler_ = texture_vk.GetImmutableSamplerVariant(sampler_vk);
660 vk::DescriptorImageInfo image_info;
661 image_info.imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal;
662 image_info.sampler = sampler_vk.GetSampler();
663 image_info.imageView = texture_vk.GetImageView();
664 image_workspace_[bound_image_offset_++] = image_info;
666 vk::WriteDescriptorSet write_set;
667 write_set.dstBinding = slot.binding;
668 write_set.descriptorCount = 1u;
669 write_set.descriptorType = vk::DescriptorType::eCombinedImageSampler;
670 write_set.pImageInfo = &image_workspace_[bound_image_offset_ - 1];
672 write_workspace_[descriptor_write_offset_++] = write_set;
676 bool RenderPassVK::OnEncodeCommands(
const Context& context)
const {
677 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
void SetCachedFramebuffer(const SharedHandleVK< vk::Framebuffer > &framebuffer)
SharedHandleVK< vk::RenderPass > GetCachedRenderPass() const
vk::ImageLayout SetLayoutWithoutEncoding(vk::ImageLayout layout) const
SharedHandleVK< vk::Framebuffer > GetCachedFramebuffer() const
vk::ImageLayout GetLayout() const
void SetCachedRenderPass(const SharedHandleVK< vk::RenderPass > &render_pass)
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)