Flutter Impeller
render_pass_vk.cc
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
6 
7 #include <array>
8 #include <cstdint>
9 
10 #include "fml/status.h"
14 #include "impeller/core/formats.h"
15 #include "impeller/core/texture.h"
26 
27 namespace impeller {
28 
29 // Warning: if any of the constant values or layouts are changed in the
30 // framebuffer fetch shader, then this input binding may need to be
31 // manually changed.
32 //
33 // See: impeller/entity/shaders/blending/framebuffer_blend.frag
34 static constexpr size_t kMagicSubpassInputBinding = 64u;
35 
36 static vk::ClearColorValue VKClearValueFromColor(Color color) {
37  vk::ClearColorValue value;
38  value.setFloat32(
39  std::array<float, 4>{color.red, color.green, color.blue, color.alpha});
40  return value;
41 }
42 
43 static vk::ClearDepthStencilValue VKClearValueFromDepthStencil(uint32_t stencil,
44  Scalar depth) {
45  vk::ClearDepthStencilValue value;
46  value.depth = depth;
47  value.stencil = stencil;
48  return value;
49 }
50 
51 static size_t GetVKClearValues(
52  const RenderTarget& target,
53  std::array<vk::ClearValue, kMaxAttachments>& values) {
54  size_t offset = 0u;
56  [&values, &offset](size_t index,
57  const ColorAttachment& attachment) -> bool {
58  values.at(offset++) = VKClearValueFromColor(attachment.clear_color);
59  if (attachment.resolve_texture) {
60  values.at(offset++) = VKClearValueFromColor(attachment.clear_color);
61  }
62  return true;
63  });
64 
65  const auto& depth = target.GetDepthAttachment();
66  const auto& stencil = target.GetStencilAttachment();
67 
68  if (depth.has_value()) {
69  values.at(offset++) = VKClearValueFromDepthStencil(
70  stencil ? stencil->clear_stencil : 0u, depth->clear_depth);
71  } else if (stencil.has_value()) {
72  values.at(offset++) = VKClearValueFromDepthStencil(
73  stencil->clear_stencil, depth ? depth->clear_depth : 0.0f);
74  }
75  return offset;
76 }
77 
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) const {
82  RenderPassBuilderVK builder;
83 
84  render_target_.IterateAllColorAttachments([&](size_t bind_point,
85  const ColorAttachment&
86  attachment) -> bool {
87  builder.SetColorAttachment(
88  bind_point, //
89  attachment.texture->GetTextureDescriptor().format, //
90  attachment.texture->GetTextureDescriptor().sample_count, //
91  attachment.load_action, //
92  attachment.store_action, //
93  /*current_layout=*/TextureVK::Cast(*attachment.texture).GetLayout() //
94  );
95  return true;
96  });
97 
98  if (auto depth = render_target_.GetDepthAttachment(); depth.has_value()) {
99  builder.SetDepthStencilAttachment(
100  depth->texture->GetTextureDescriptor().format, //
101  depth->texture->GetTextureDescriptor().sample_count, //
102  depth->load_action, //
103  depth->store_action //
104  );
105  } else if (auto stencil = render_target_.GetStencilAttachment();
106  stencil.has_value()) {
107  builder.SetStencilAttachment(
108  stencil->texture->GetTextureDescriptor().format, //
109  stencil->texture->GetTextureDescriptor().sample_count, //
110  stencil->load_action, //
111  stencil->store_action //
112  );
113  }
114 
115  if (recycled_renderpass != nullptr) {
116  return recycled_renderpass;
117  }
118 
119  auto pass = builder.Build(context.GetDevice());
120 
121  if (!pass) {
122  VALIDATION_LOG << "Failed to create render pass for framebuffer.";
123  return {};
124  }
125 
126  context.SetDebugName(pass.get(), debug_label_.c_str());
127 
128  return MakeSharedVK(std::move(pass));
129 }
130 
131 RenderPassVK::RenderPassVK(const std::shared_ptr<const Context>& context,
132  const RenderTarget& target,
133  std::shared_ptr<CommandBufferVK> command_buffer)
134  : RenderPass(context, target), command_buffer_(std::move(command_buffer)) {
135  const ColorAttachment& color0 = render_target_.GetColorAttachment(0);
136  color_image_vk_ = color0.texture;
137  resolve_image_vk_ = color0.resolve_texture;
138 
139  const auto& vk_context = ContextVK::Cast(*context);
140  command_buffer_vk_ = command_buffer_->GetCommandBuffer();
141  render_target_.IterateAllAttachments([&](const auto& attachment) -> bool {
142  command_buffer_->Track(attachment.texture);
143  command_buffer_->Track(attachment.resolve_texture);
144  return true;
145  });
146 
147  SharedHandleVK<vk::RenderPass> recycled_render_pass;
148  SharedHandleVK<vk::Framebuffer> recycled_framebuffer;
149  if (resolve_image_vk_) {
150  recycled_render_pass =
151  TextureVK::Cast(*resolve_image_vk_).GetCachedRenderPass();
152  recycled_framebuffer =
153  TextureVK::Cast(*resolve_image_vk_).GetCachedFramebuffer();
154  }
155 
156  const auto& target_size = render_target_.GetRenderTargetSize();
157 
158  render_pass_ =
159  CreateVKRenderPass(vk_context, recycled_render_pass, command_buffer_);
160  if (!render_pass_) {
161  VALIDATION_LOG << "Could not create renderpass.";
162  is_valid_ = false;
163  return;
164  }
165 
166  auto framebuffer = (recycled_framebuffer == nullptr)
167  ? CreateVKFramebuffer(vk_context, *render_pass_)
168  : recycled_framebuffer;
169  if (!framebuffer) {
170  VALIDATION_LOG << "Could not create framebuffer.";
171  is_valid_ = false;
172  return;
173  }
174 
175  if (!command_buffer_->Track(framebuffer) ||
176  !command_buffer_->Track(render_pass_)) {
177  is_valid_ = false;
178  return;
179  }
180  if (resolve_image_vk_) {
181  TextureVK::Cast(*resolve_image_vk_).SetCachedFramebuffer(framebuffer);
182  TextureVK::Cast(*resolve_image_vk_).SetCachedRenderPass(render_pass_);
183  TextureVK::Cast(*resolve_image_vk_)
184  .SetLayoutWithoutEncoding(vk::ImageLayout::eGeneral);
185  }
186 
187  std::array<vk::ClearValue, kMaxAttachments> clears;
188  size_t clear_count = GetVKClearValues(render_target_, clears);
189 
190  vk::RenderPassBeginInfo pass_info;
191  pass_info.renderPass = *render_pass_;
192  pass_info.framebuffer = *framebuffer;
193  pass_info.renderArea.extent.width = static_cast<uint32_t>(target_size.width);
194  pass_info.renderArea.extent.height =
195  static_cast<uint32_t>(target_size.height);
196  pass_info.setPClearValues(clears.data());
197  pass_info.setClearValueCount(clear_count);
198 
199  command_buffer_vk_.beginRenderPass(pass_info, vk::SubpassContents::eInline);
200 
201  if (resolve_image_vk_) {
202  TextureVK::Cast(*resolve_image_vk_)
203  .SetLayoutWithoutEncoding(vk::ImageLayout::eGeneral);
204  }
205  if (color_image_vk_) {
206  TextureVK::Cast(*color_image_vk_)
207  .SetLayoutWithoutEncoding(vk::ImageLayout::eGeneral);
208  }
209 
210  // Set the initial viewport.
211  const auto vp = Viewport{.rect = Rect::MakeSize(target_size)};
212  vk::Viewport viewport = vk::Viewport()
213  .setWidth(vp.rect.GetWidth())
214  .setHeight(-vp.rect.GetHeight())
215  .setY(vp.rect.GetHeight())
216  .setMinDepth(0.0f)
217  .setMaxDepth(1.0f);
218  command_buffer_vk_.setViewport(0, 1, &viewport);
219 
220  // Set the initial scissor.
221  const auto sc = IRect::MakeSize(target_size);
222  vk::Rect2D scissor =
223  vk::Rect2D()
224  .setOffset(vk::Offset2D(sc.GetX(), sc.GetY()))
225  .setExtent(vk::Extent2D(sc.GetWidth(), sc.GetHeight()));
226  command_buffer_vk_.setScissor(0, 1, &scissor);
227 
228  // Set the initial stencil reference.
229  command_buffer_vk_.setStencilReference(
230  vk::StencilFaceFlagBits::eVkStencilFrontAndBack, 0u);
231 
232  is_valid_ = true;
233 }
234 
235 RenderPassVK::~RenderPassVK() = default;
236 
237 bool RenderPassVK::IsValid() const {
238  return is_valid_;
239 }
240 
241 void RenderPassVK::OnSetLabel(std::string_view label) {
242 #ifdef IMPELLER_DEBUG
243  ContextVK::Cast(*context_).SetDebugName(render_pass_->Get(), label.data());
244 #endif // IMPELLER_DEBUG
245 }
246 
247 SharedHandleVK<vk::Framebuffer> RenderPassVK::CreateVKFramebuffer(
248  const ContextVK& context,
249  const vk::RenderPass& pass) const {
250  vk::FramebufferCreateInfo fb_info;
251 
252  fb_info.renderPass = pass;
253 
254  const auto target_size = render_target_.GetRenderTargetSize();
255  fb_info.width = target_size.width;
256  fb_info.height = target_size.height;
257  fb_info.layers = 1u;
258 
259  std::array<vk::ImageView, kMaxAttachments> attachments;
260  size_t count = 0;
261 
262  // This bit must be consistent to ensure compatibility with the pass created
263  // earlier. Follow this order: Color attachments, then depth-stencil, then
264  // stencil.
265  render_target_.IterateAllColorAttachments(
266  [&attachments, &count](size_t index,
267  const ColorAttachment& attachment) -> bool {
268  // The bind point doesn't matter here since that information is present
269  // in the render pass.
270  attachments[count++] =
271  TextureVK::Cast(*attachment.texture).GetRenderTargetView();
272  if (attachment.resolve_texture) {
273  attachments[count++] = TextureVK::Cast(*attachment.resolve_texture)
274  .GetRenderTargetView();
275  }
276  return true;
277  });
278 
279  if (auto depth = render_target_.GetDepthAttachment(); depth.has_value()) {
280  attachments[count++] =
281  TextureVK::Cast(*depth->texture).GetRenderTargetView();
282  } else if (auto stencil = render_target_.GetStencilAttachment();
283  stencil.has_value()) {
284  attachments[count++] =
285  TextureVK::Cast(*stencil->texture).GetRenderTargetView();
286  }
287 
288  fb_info.setPAttachments(attachments.data());
289  fb_info.setAttachmentCount(count);
290 
291  auto [result, framebuffer] =
292  context.GetDevice().createFramebufferUnique(fb_info);
293 
294  if (result != vk::Result::eSuccess) {
295  VALIDATION_LOG << "Could not create framebuffer: " << vk::to_string(result);
296  return {};
297  }
298 
299  return MakeSharedVK(std::move(framebuffer));
300 }
301 
302 // |RenderPass|
303 void RenderPassVK::SetPipeline(PipelineRef pipeline) {
304  pipeline_ = pipeline;
305  if (!pipeline_) {
306  return;
307  }
308 
309  pipeline_uses_input_attachments_ =
310  pipeline_->GetDescriptor().GetVertexDescriptor()->UsesInputAttacments();
311 
312  if (pipeline_uses_input_attachments_) {
313  if (bound_image_offset_ >= kMaxBindings) {
314  pipeline_ = PipelineRef(nullptr);
315  return;
316  }
317  vk::DescriptorImageInfo image_info;
318  image_info.imageLayout = vk::ImageLayout::eGeneral;
319  image_info.sampler = VK_NULL_HANDLE;
320  image_info.imageView = TextureVK::Cast(*color_image_vk_).GetImageView();
321  image_workspace_[bound_image_offset_++] = image_info;
322 
323  vk::WriteDescriptorSet write_set;
324  write_set.dstBinding = kMagicSubpassInputBinding;
325  write_set.descriptorCount = 1u;
326  write_set.descriptorType = vk::DescriptorType::eInputAttachment;
327  write_set.pImageInfo = &image_workspace_[bound_image_offset_ - 1];
328 
329  write_workspace_[descriptor_write_offset_++] = write_set;
330  }
331 }
332 
333 // |RenderPass|
334 void RenderPassVK::SetCommandLabel(std::string_view label) {
335 #ifdef IMPELLER_DEBUG
336  command_buffer_->PushDebugGroup(label);
337  has_label_ = true;
338 #endif // IMPELLER_DEBUG
339 }
340 
341 // |RenderPass|
342 void RenderPassVK::SetStencilReference(uint32_t value) {
343  command_buffer_vk_.setStencilReference(
344  vk::StencilFaceFlagBits::eVkStencilFrontAndBack, value);
345 }
346 
347 // |RenderPass|
348 void RenderPassVK::SetBaseVertex(uint64_t value) {
349  base_vertex_ = value;
350 }
351 
352 // |RenderPass|
353 void RenderPassVK::SetViewport(Viewport viewport) {
354  vk::Viewport viewport_vk = vk::Viewport()
355  .setWidth(viewport.rect.GetWidth())
356  .setHeight(-viewport.rect.GetHeight())
357  .setY(viewport.rect.GetHeight())
358  .setMinDepth(0.0f)
359  .setMaxDepth(1.0f);
360  command_buffer_vk_.setViewport(0, 1, &viewport_vk);
361 }
362 
363 // |RenderPass|
364 void RenderPassVK::SetScissor(IRect scissor) {
365  vk::Rect2D scissor_vk =
366  vk::Rect2D()
367  .setOffset(vk::Offset2D(scissor.GetX(), scissor.GetY()))
368  .setExtent(vk::Extent2D(scissor.GetWidth(), scissor.GetHeight()));
369  command_buffer_vk_.setScissor(0, 1, &scissor_vk);
370 }
371 
372 // |RenderPass|
373 void RenderPassVK::SetElementCount(size_t count) {
374  element_count_ = count;
375 }
376 
377 // |RenderPass|
378 void RenderPassVK::SetInstanceCount(size_t count) {
379  instance_count_ = count;
380 }
381 
382 // |RenderPass|
383 bool RenderPassVK::SetVertexBuffer(BufferView vertex_buffers[],
384  size_t vertex_buffer_count) {
385  if (!ValidateVertexBuffers(vertex_buffers, vertex_buffer_count)) {
386  return false;
387  }
388 
389  vk::Buffer buffers[kMaxVertexBuffers];
390  vk::DeviceSize vertex_buffer_offsets[kMaxVertexBuffers];
391  for (size_t i = 0; i < vertex_buffer_count; i++) {
392  buffers[i] =
393  DeviceBufferVK::Cast(*vertex_buffers[i].GetBuffer()).GetBuffer();
394  vertex_buffer_offsets[i] = vertex_buffers[i].GetRange().offset;
395  std::shared_ptr<const DeviceBuffer> device_buffer =
396  vertex_buffers[i].TakeBuffer();
397  if (device_buffer) {
398  command_buffer_->Track(device_buffer);
399  }
400  }
401 
402  // Bind the vertex buffers.
403  command_buffer_vk_.bindVertexBuffers(0u, vertex_buffer_count, buffers,
404  vertex_buffer_offsets);
405 
406  return true;
407 }
408 
409 // |RenderPass|
410 bool RenderPassVK::SetIndexBuffer(BufferView index_buffer,
411  IndexType index_type) {
412  if (!ValidateIndexBuffer(index_buffer, index_type)) {
413  return false;
414  }
415 
416  if (index_type != IndexType::kNone) {
417  has_index_buffer_ = true;
418 
419  BufferView index_buffer_view = std::move(index_buffer);
420  if (!index_buffer_view) {
421  return false;
422  }
423 
424  if (!index_buffer_view.GetBuffer()) {
425  VALIDATION_LOG << "Failed to acquire device buffer"
426  << " for index buffer view";
427  return false;
428  }
429 
430  std::shared_ptr<const DeviceBuffer> index_buffer =
431  index_buffer_view.TakeBuffer();
432  if (index_buffer && !command_buffer_->Track(index_buffer)) {
433  return false;
434  }
435 
436  vk::Buffer index_buffer_handle =
437  DeviceBufferVK::Cast(*index_buffer_view.GetBuffer()).GetBuffer();
438  command_buffer_vk_.bindIndexBuffer(index_buffer_handle,
439  index_buffer_view.GetRange().offset,
440  ToVKIndexType(index_type));
441  } else {
442  has_index_buffer_ = false;
443  }
444 
445  return true;
446 }
447 
448 // |RenderPass|
449 fml::Status RenderPassVK::Draw() {
450  if (!pipeline_) {
451  return fml::Status(fml::StatusCode::kCancelled,
452  "No valid pipeline is bound to the RenderPass.");
453  }
454 
455  //----------------------------------------------------------------------------
456  /// If there are immutable samplers referenced in the render pass, the base
457  /// pipeline variant is no longer valid and needs to be re-constructed to
458  /// reference the samplers.
459  ///
460  /// This is an instance of JIT creation of PSOs that can cause jank. It is
461  /// unavoidable because it isn't possible to know all possible combinations of
462  /// target YUV conversions. Fortunately, this will only ever happen when
463  /// rendering to external textures. Like Android Hardware Buffers on Android.
464  ///
465  /// Even when JIT creation is unavoidable, pipelines will cache their variants
466  /// when able and all pipeline creation will happen via a base pipeline cache
467  /// anyway. So the jank can be mostly entirely ameliorated and it should only
468  /// ever happen when the first unknown YUV conversion is encountered.
469  ///
470  /// Jank can be completely eliminated by pre-populating known YUV conversion
471  /// pipelines.
472  if (immutable_sampler_) {
473  std::shared_ptr<Pipeline<PipelineDescriptor>> pipeline_variant =
474  PipelineVK::Cast(*pipeline_)
475  .CreateVariantForImmutableSamplers(immutable_sampler_);
476  if (!pipeline_variant) {
477  return fml::Status(
478  fml::StatusCode::kAborted,
479  "Could not create pipeline variant with immutable sampler.");
480  }
481  pipeline_ = raw_ptr(pipeline_variant);
482  }
483 
484  const auto& context_vk = ContextVK::Cast(*context_);
485  const auto& pipeline_vk = PipelineVK::Cast(*pipeline_);
486 
487  auto descriptor_result = command_buffer_->AllocateDescriptorSets(
488  pipeline_vk.GetDescriptorSetLayout(), context_vk);
489  if (!descriptor_result.ok()) {
490  return fml::Status(fml::StatusCode::kAborted,
491  "Could not allocate descriptor sets.");
492  }
493  const auto descriptor_set = descriptor_result.value();
494  const auto pipeline_layout = pipeline_vk.GetPipelineLayout();
495  command_buffer_vk_.bindPipeline(vk::PipelineBindPoint::eGraphics,
496  pipeline_vk.GetPipeline());
497 
498  for (auto i = 0u; i < descriptor_write_offset_; i++) {
499  write_workspace_[i].dstSet = descriptor_set;
500  }
501 
502  context_vk.GetDevice().updateDescriptorSets(descriptor_write_offset_,
503  write_workspace_.data(), 0u, {});
504 
505  command_buffer_vk_.bindDescriptorSets(
506  vk::PipelineBindPoint::eGraphics, // bind point
507  pipeline_layout, // layout
508  0, // first set
509  1, // set count
510  &descriptor_set, // sets
511  0, // offset count
512  nullptr // offsets
513  );
514 
515  if (pipeline_uses_input_attachments_) {
517  command_buffer_vk_, TextureVK::Cast(*color_image_vk_).GetImage());
518  }
519 
520  if (has_index_buffer_) {
521  command_buffer_vk_.drawIndexed(element_count_, // index count
522  instance_count_, // instance count
523  0u, // first index
524  base_vertex_, // vertex offset
525  0u // first instance
526  );
527  } else {
528  command_buffer_vk_.draw(element_count_, // vertex count
529  instance_count_, // instance count
530  base_vertex_, // vertex offset
531  0u // first instance
532  );
533  }
534 
535 #ifdef IMPELLER_DEBUG
536  if (has_label_) {
537  command_buffer_->PopDebugGroup();
538  }
539 #endif // IMPELLER_DEBUG
540  has_label_ = false;
541  has_index_buffer_ = false;
542  bound_image_offset_ = 0u;
543  bound_buffer_offset_ = 0u;
544  descriptor_write_offset_ = 0u;
545  instance_count_ = 1u;
546  base_vertex_ = 0u;
547  element_count_ = 0u;
548  pipeline_ = PipelineRef(nullptr);
549  pipeline_uses_input_attachments_ = false;
550  immutable_sampler_ = nullptr;
551  return fml::Status();
552 }
553 
554 // The RenderPassVK binding methods only need the binding, set, and buffer type
555 // information.
556 bool RenderPassVK::BindResource(ShaderStage stage,
558  const ShaderUniformSlot& slot,
559  const ShaderMetadata* metadata,
560  BufferView view) {
561  return BindResource(slot.binding, type, view);
562 }
563 
564 bool RenderPassVK::BindDynamicResource(ShaderStage stage,
566  const ShaderUniformSlot& slot,
567  std::unique_ptr<ShaderMetadata> metadata,
568  BufferView view) {
569  return BindResource(slot.binding, type, view);
570 }
571 
572 bool RenderPassVK::BindResource(size_t binding,
574  BufferView view) {
575  if (bound_buffer_offset_ >= kMaxBindings) {
576  return false;
577  }
578 
579  auto buffer = DeviceBufferVK::Cast(*view.GetBuffer()).GetBuffer();
580  if (!buffer) {
581  return false;
582  }
583 
584  std::shared_ptr<const DeviceBuffer> device_buffer = view.TakeBuffer();
585  if (device_buffer && !command_buffer_->Track(device_buffer)) {
586  return false;
587  }
588 
589  uint32_t offset = view.GetRange().offset;
590 
591  vk::DescriptorBufferInfo buffer_info;
592  buffer_info.buffer = buffer;
593  buffer_info.offset = offset;
594  buffer_info.range = view.GetRange().length;
595  buffer_workspace_[bound_buffer_offset_++] = buffer_info;
596 
597  vk::WriteDescriptorSet write_set;
598  write_set.dstBinding = binding;
599  write_set.descriptorCount = 1u;
600  write_set.descriptorType = ToVKDescriptorType(type);
601  write_set.pBufferInfo = &buffer_workspace_[bound_buffer_offset_ - 1];
602 
603  write_workspace_[descriptor_write_offset_++] = write_set;
604  return true;
605 }
606 
607 bool RenderPassVK::BindDynamicResource(ShaderStage stage,
609  const SampledImageSlot& slot,
610  std::unique_ptr<ShaderMetadata> metadata,
611  std::shared_ptr<const Texture> texture,
612  raw_ptr<const Sampler> sampler) {
613  return BindResource(stage, type, slot, nullptr, texture, sampler);
614 }
615 
616 bool RenderPassVK::BindResource(ShaderStage stage,
618  const SampledImageSlot& slot,
619  const ShaderMetadata* metadata,
620  std::shared_ptr<const Texture> texture,
621  raw_ptr<const Sampler> sampler) {
622  if (bound_buffer_offset_ >= kMaxBindings) {
623  return false;
624  }
625  if (!texture || !texture->IsValid() || !sampler) {
626  return false;
627  }
628  const TextureVK& texture_vk = TextureVK::Cast(*texture);
629  const SamplerVK& sampler_vk = SamplerVK::Cast(*sampler);
630 
631  if (!command_buffer_->Track(texture)) {
632  return false;
633  }
634 
635  if (!immutable_sampler_) {
636  immutable_sampler_ = texture_vk.GetImmutableSamplerVariant(sampler_vk);
637  }
638 
639  vk::DescriptorImageInfo image_info;
640  image_info.imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal;
641  image_info.sampler = sampler_vk.GetSampler();
642  image_info.imageView = texture_vk.GetImageView();
643  image_workspace_[bound_image_offset_++] = image_info;
644 
645  vk::WriteDescriptorSet write_set;
646  write_set.dstBinding = slot.binding;
647  write_set.descriptorCount = 1u;
648  write_set.descriptorType = vk::DescriptorType::eCombinedImageSampler;
649  write_set.pImageInfo = &image_workspace_[bound_image_offset_ - 1];
650 
651  write_workspace_[descriptor_write_offset_++] = write_set;
652  return true;
653 }
654 
655 bool RenderPassVK::OnEncodeCommands(const Context& context) const {
656  command_buffer_->GetCommandBuffer().endRenderPass();
657 
658  // If this render target will be consumed by a subsequent render pass,
659  // perform a layout transition to a shader read state.
660  const std::shared_ptr<Texture>& result_texture =
661  resolve_image_vk_ ? resolve_image_vk_ : color_image_vk_;
662  if (result_texture->GetTextureDescriptor().usage &
663  TextureUsage::kShaderRead) {
664  BarrierVK barrier;
665  barrier.cmd_buffer = command_buffer_vk_;
666  barrier.src_access = vk::AccessFlagBits::eColorAttachmentWrite |
667  vk::AccessFlagBits::eTransferWrite;
668  barrier.src_stage = vk::PipelineStageFlagBits::eColorAttachmentOutput |
669  vk::PipelineStageFlagBits::eTransfer;
670  barrier.dst_access = vk::AccessFlagBits::eShaderRead;
671  barrier.dst_stage = vk::PipelineStageFlagBits::eFragmentShader;
672 
673  barrier.new_layout = vk::ImageLayout::eShaderReadOnlyOptimal;
674 
675  if (!TextureVK::Cast(*result_texture).SetLayout(barrier)) {
676  return false;
677  }
678  }
679 
680  return true;
681 }
682 
683 } // namespace impeller
GLenum type
static TextureVK & Cast(Texture &base)
Definition: backend_cast.h:13
const RenderTarget render_target_
Definition: render_pass.h:247
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
void SetCachedFramebuffer(const SharedHandleVK< vk::Framebuffer > &framebuffer)
Definition: texture_vk.cc:199
SharedHandleVK< vk::RenderPass > GetCachedRenderPass() const
Definition: texture_vk.cc:213
vk::ImageLayout SetLayoutWithoutEncoding(vk::ImageLayout layout) const
Definition: texture_vk.cc:185
SharedHandleVK< vk::Framebuffer > GetCachedFramebuffer() const
Definition: texture_vk.cc:209
vk::ImageLayout GetLayout() const
Definition: texture_vk.cc:191
void SetCachedRenderPass(const SharedHandleVK< vk::RenderPass > &render_pass)
Definition: texture_vk.cc:204
int32_t value
float Scalar
Definition: scalar.h:18
constexpr vk::IndexType ToVKIndexType(IndexType index_type)
Definition: formats_vk.h:355
raw_ptr< Pipeline< PipelineDescriptor > > PipelineRef
A raw ptr to a pipeline object.
Definition: pipeline.h:86
constexpr vk::DescriptorType ToVKDescriptorType(DescriptorType type)
Definition: formats_vk.h:292
static constexpr size_t kMaxBindings
Definition: pipeline_vk.h:26
constexpr size_t kMaxVertexBuffers
Definition: vertex_buffer.h:13
IRect64 IRect
Definition: rect.h:795
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)
Definition: comparable.h:95
SeparatedVector2 offset
std::shared_ptr< Texture > resolve_texture
Definition: formats.h:658
Scalar blue
Definition: color.h:137
Scalar alpha
Definition: color.h:142
Scalar red
Definition: color.h:127
Scalar green
Definition: color.h:132
constexpr static TRect MakeSize(const TSize< U > &size)
Definition: rect.h:150
#define VALIDATION_LOG
Definition: validation.h:91