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"
27 
28 namespace impeller {
29 
30 // Warning: if any of the constant values or layouts are changed in the
31 // framebuffer fetch shader, then this input binding may need to be
32 // manually changed.
33 //
34 // See: impeller/entity/shaders/blending/framebuffer_blend.frag
35 static constexpr size_t kMagicSubpassInputBinding = 64u;
36 
37 static vk::ClearColorValue VKClearValueFromColor(Color color) {
38  vk::ClearColorValue value;
39  value.setFloat32(
40  std::array<float, 4>{color.red, color.green, color.blue, color.alpha});
41  return value;
42 }
43 
44 static vk::ClearDepthStencilValue VKClearValueFromDepthStencil(uint32_t stencil,
45  Scalar depth) {
46  vk::ClearDepthStencilValue value;
47  value.depth = depth;
48  value.stencil = stencil;
49  return value;
50 }
51 
52 /// Converts an Impeller `Viewport` to a `vk::Viewport`. Impeller specifies
53 /// viewports in top-left-origin framebuffer coordinates, so the
54 /// negative-height trick from VK_KHR_maintenance1 is used to flip the Y axis
55 /// to match the GL convention that the rest of the engine assumes (NDC +Y
56 /// maps to the smaller framebuffer Y).
57 static vk::Viewport ToVkViewport(const Viewport& viewport) {
58  const auto& rect = viewport.rect;
59  return vk::Viewport()
60  .setX(rect.GetX())
61  .setY(rect.GetY() + rect.GetHeight())
62  .setWidth(rect.GetWidth())
63  .setHeight(-rect.GetHeight())
64  .setMinDepth(viewport.depth_range.z_near)
65  .setMaxDepth(viewport.depth_range.z_far);
66 }
67 
68 static size_t GetVKClearValues(
69  const RenderTarget& target,
70  std::array<vk::ClearValue, kMaxAttachments>& values) {
71  size_t offset = 0u;
73  [&values, &offset](size_t index,
74  const ColorAttachment& attachment) -> bool {
75  values.at(offset++) = VKClearValueFromColor(attachment.clear_color);
76  if (attachment.resolve_texture) {
77  values.at(offset++) = VKClearValueFromColor(attachment.clear_color);
78  }
79  return true;
80  });
81 
82  const auto& depth = target.GetDepthAttachment();
83  const auto& stencil = target.GetStencilAttachment();
84 
85  if (depth.has_value()) {
86  values.at(offset++) = VKClearValueFromDepthStencil(
87  stencil ? stencil->clear_stencil : 0u, depth->clear_depth);
88  } else if (stencil.has_value()) {
89  values.at(offset++) = VKClearValueFromDepthStencil(
90  stencil->clear_stencil, depth ? depth->clear_depth : 0.0f);
91  }
92  return offset;
93 }
94 
95 SharedHandleVK<vk::RenderPass> RenderPassVK::CreateVKRenderPass(
96  const ContextVK& context,
97  const SharedHandleVK<vk::RenderPass>& recycled_renderpass,
98  const std::shared_ptr<CommandBufferVK>& command_buffer,
99  bool is_swapchain) const {
100  if (recycled_renderpass != nullptr) {
101  return recycled_renderpass;
102  }
103 
104  RenderPassBuilderVK builder;
105  render_target_.IterateAllColorAttachments([&](size_t bind_point,
106  const ColorAttachment&
107  attachment) -> bool {
108  builder.SetColorAttachment(
109  bind_point, //
110  attachment.texture->GetTextureDescriptor().format, //
111  attachment.texture->GetTextureDescriptor().sample_count, //
112  attachment.load_action, //
113  attachment.store_action, //
114  /*current_layout=*/TextureVK::Cast(*attachment.texture).GetLayout(), //
115  /*is_swapchain=*/is_swapchain);
116  return true;
117  });
118 
119  if (auto depth = render_target_.GetDepthAttachment(); depth.has_value()) {
120  builder.SetDepthStencilAttachment(
121  depth->texture->GetTextureDescriptor().format, //
122  depth->texture->GetTextureDescriptor().sample_count, //
123  depth->load_action, //
124  depth->store_action //
125  );
126  } else if (auto stencil = render_target_.GetStencilAttachment();
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 //
133  );
134  }
135 
136  auto pass = builder.Build(context.GetDevice());
137 
138  if (!pass) {
139  VALIDATION_LOG << "Failed to create render pass for framebuffer.";
140  return {};
141  }
142 
143  context.SetDebugName(pass.get(), debug_label_.c_str());
144 
145  return MakeSharedVK(std::move(pass));
146 }
147 
148 RenderPassVK::RenderPassVK(const std::shared_ptr<const Context>& context,
149  const RenderTarget& target,
150  std::shared_ptr<CommandBufferVK> command_buffer)
151  : RenderPass(context, target), command_buffer_(std::move(command_buffer)) {
152  const ColorAttachment& color0 = render_target_.GetColorAttachment(0);
153  color_image_vk_ = color0.texture;
154  resolve_image_vk_ = color0.resolve_texture;
155 
156  const auto& vk_context = ContextVK::Cast(*context);
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);
161  return true;
162  });
163 
164  FramebufferAndRenderPass frame_data;
165  bool is_swapchain = false;
166  SampleCount sample_count =
167  color_image_vk_->GetTextureDescriptor().sample_count;
168  // The framebuffer references attachment views bound to a specific
169  // subresource, so the cache is keyed on color0's (mip_level, slice) as
170  // well as sample count. Caller-side invariants on the rest of the
171  // attachment set are the same as before.
172  const uint32_t cache_mip_level = color0.mip_level;
173  const uint32_t cache_slice = color0.slice;
174  TextureVK& frame_data_texture = TextureVK::Cast(
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);
179 
180  const auto& target_size = render_target_.GetRenderTargetSize();
181 
182  render_pass_ = CreateVKRenderPass(vk_context, frame_data.render_pass,
183  command_buffer_, is_swapchain);
184  if (!render_pass_) {
185  VALIDATION_LOG << "Could not create renderpass.";
186  is_valid_ = false;
187  return;
188  }
189 
190  auto framebuffer = (frame_data.framebuffer == nullptr)
191  ? CreateVKFramebuffer(vk_context, *render_pass_)
192  : frame_data.framebuffer;
193  if (!framebuffer) {
194  VALIDATION_LOG << "Could not create framebuffer.";
195  is_valid_ = false;
196  return;
197  }
198 
199  if (!command_buffer_->Track(framebuffer) ||
200  !command_buffer_->Track(render_pass_)) {
201  is_valid_ = false;
202  return;
203  }
204 
205  frame_data.framebuffer = framebuffer;
206  frame_data.render_pass = render_pass_;
207 
208  frame_data_texture.SetCachedFrameData(frame_data, sample_count,
209  cache_mip_level, cache_slice);
210 
211  // If the resolve image exists and has mipmaps, transition mip levels besides
212  // the base to shader read only in preparation for mipmap generation.
213  if (resolve_image_vk_ &&
214  resolve_image_vk_->GetTextureDescriptor().mip_count > 1) {
215  if (TextureVK::Cast(*resolve_image_vk_).GetLayout() ==
216  vk::ImageLayout::eUndefined) {
217  BarrierVK barrier;
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;
225  TextureVK::Cast(*resolve_image_vk_).SetLayout(barrier);
226  }
227  }
228 
229  std::array<vk::ClearValue, kMaxAttachments> clears;
230  size_t clear_count = GetVKClearValues(render_target_, clears);
231 
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);
240 
241  command_buffer_vk_.beginRenderPass(pass_info, vk::SubpassContents::eInline);
242 
243  if (resolve_image_vk_) {
244  TextureVK::Cast(*resolve_image_vk_)
246  is_swapchain ? vk::ImageLayout::eGeneral
247  : vk::ImageLayout::eShaderReadOnlyOptimal);
248  }
249  if (color_image_vk_) {
250  // Mirror the Vulkan render pass's `finalLayout` for the color attachment
251  // (see ComputeFinalLayout in render_pass_builder_vk.cc): swapchain and
252  // MSAA targets stay in eGeneral, but a non-swapchain, single-sampled
253  // color attachment transitions to eShaderReadOnlyOptimal on
254  // endRenderPass. Tracking it as eGeneral here desyncs the bookkeeping
255  // and produces an incorrect oldLayout on the next barrier (caught by
256  // Vulkan validation as VUID-vkCmdDraw-None-09600).
257  TextureVK::Cast(*color_image_vk_)
259  (is_swapchain || sample_count != SampleCount::kCount1)
260  ? vk::ImageLayout::eGeneral
261  : vk::ImageLayout::eShaderReadOnlyOptimal);
262  }
263 
264  // Set the initial viewport.
265  const auto vp = Viewport{.rect = Rect::MakeSize(target_size)};
266  vk::Viewport viewport = ToVkViewport(vp);
267  command_buffer_vk_.setViewport(0, 1, &viewport);
268 
269  // Set the initial scissor.
270  const auto sc = IRect32::MakeSize(target_size);
271  vk::Rect2D scissor =
272  vk::Rect2D()
273  .setOffset(vk::Offset2D(sc.GetX(), sc.GetY()))
274  .setExtent(vk::Extent2D(sc.GetWidth(), sc.GetHeight()));
275  command_buffer_vk_.setScissor(0, 1, &scissor);
276 
277  // Set the initial stencil reference.
278  command_buffer_vk_.setStencilReference(vk::StencilFaceFlagBits::eFrontAndBack,
279  0u);
280 
281  is_valid_ = true;
282 }
283 
284 RenderPassVK::~RenderPassVK() = default;
285 
286 bool RenderPassVK::IsValid() const {
287  return is_valid_;
288 }
289 
290 void RenderPassVK::OnSetLabel(std::string_view label) {
291 #ifdef IMPELLER_DEBUG
292  ContextVK::Cast(*context_).SetDebugName(render_pass_->Get(), label.data());
293 #endif // IMPELLER_DEBUG
294 }
295 
296 SharedHandleVK<vk::Framebuffer> RenderPassVK::CreateVKFramebuffer(
297  const ContextVK& context,
298  const vk::RenderPass& pass) const {
299  vk::FramebufferCreateInfo fb_info;
300 
301  fb_info.renderPass = pass;
302 
303  const auto target_size = render_target_.GetRenderTargetSize();
304  fb_info.width = target_size.width;
305  fb_info.height = target_size.height;
306  fb_info.layers = 1u;
307 
308  std::array<vk::ImageView, kMaxAttachments> attachments;
309  size_t count = 0;
310 
311  // This bit must be consistent to ensure compatibility with the pass created
312  // earlier. Follow this order: Color attachments, then depth-stencil, then
313  // stencil.
314  render_target_.IterateAllColorAttachments(
315  [&attachments, &count](size_t index,
316  const ColorAttachment& attachment) -> bool {
317  // The bind point doesn't matter here since that information is present
318  // in the render pass.
319  attachments[count++] =
320  TextureVK::Cast(*attachment.texture)
321  .GetRenderTargetView(attachment.mip_level, attachment.slice);
322  if (attachment.resolve_texture) {
323  // The resolve texture resolves into its own base level/layer.
324  attachments[count++] = TextureVK::Cast(*attachment.resolve_texture)
325  .GetRenderTargetView();
326  }
327  return true;
328  });
329 
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);
339  }
340 
341  fb_info.setPAttachments(attachments.data());
342  fb_info.setAttachmentCount(count);
343 
344  auto [result, framebuffer] =
345  context.GetDevice().createFramebufferUnique(fb_info);
346 
347  if (result != vk::Result::eSuccess) {
348  VALIDATION_LOG << "Could not create framebuffer: " << vk::to_string(result);
349  return {};
350  }
351 
352  return MakeSharedVK(std::move(framebuffer));
353 }
354 
355 // |RenderPass|
356 void RenderPassVK::SetPipeline(PipelineRef pipeline) {
357  pipeline_ = pipeline;
358  if (!pipeline_) {
359  return;
360  }
361  context_->GetPipelineLibrary()->LogPipelineUsage(pipeline->GetDescriptor());
362 
363  pipeline_uses_input_attachments_ =
364  pipeline_->GetDescriptor().GetVertexDescriptor()->UsesInputAttachments();
365 
366  if (pipeline_uses_input_attachments_) {
367  if (bound_image_offset_ >= kMaxBindings) {
368  pipeline_ = PipelineRef(nullptr);
369  return;
370  }
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;
376 
377  vk::WriteDescriptorSet write_set;
378  write_set.dstBinding = kMagicSubpassInputBinding;
379  write_set.descriptorCount = 1u;
380  write_set.descriptorType = vk::DescriptorType::eInputAttachment;
381  write_set.pImageInfo = &image_workspace_[bound_image_offset_ - 1];
382 
383  write_workspace_[descriptor_write_offset_++] = write_set;
384  }
385 }
386 
387 // |RenderPass|
388 void RenderPassVK::SetCommandLabel(std::string_view label) {
389 #ifdef IMPELLER_DEBUG
390  command_buffer_->PushDebugGroup(label);
391  has_label_ = true;
392 #endif // IMPELLER_DEBUG
393 }
394 
395 // |RenderPass|
396 void RenderPassVK::SetStencilReference(uint32_t value) {
397  if (current_stencil_ == value) {
398  return;
399  }
400  current_stencil_ = value;
401  command_buffer_vk_.setStencilReference(vk::StencilFaceFlagBits::eFrontAndBack,
402  value);
403 }
404 
405 // |RenderPass|
406 void RenderPassVK::SetBaseVertex(uint64_t value) {
407  base_vertex_ = value;
408 }
409 
410 // |RenderPass|
411 void RenderPassVK::SetViewport(Viewport viewport) {
412  vk::Viewport viewport_vk = ToVkViewport(viewport);
413  command_buffer_vk_.setViewport(0, 1, &viewport_vk);
414 }
415 
416 // |RenderPass|
417 void RenderPassVK::SetScissor(IRect32 scissor) {
418  vk::Rect2D scissor_vk =
419  vk::Rect2D()
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);
423 }
424 
425 // |RenderPass|
426 void RenderPassVK::SetElementCount(size_t count) {
427  element_count_ = count;
428 }
429 
430 // |RenderPass|
431 void RenderPassVK::SetInstanceCount(size_t count) {
432  instance_count_ = count;
433 }
434 
435 // |RenderPass|
436 bool RenderPassVK::SetVertexBuffer(BufferView vertex_buffers[],
437  size_t vertex_buffer_count) {
438  if (!ValidateVertexBuffers(vertex_buffers, vertex_buffer_count)) {
439  return false;
440  }
441 
442  vk::Buffer buffers[kMaxVertexBuffers];
443  vk::DeviceSize vertex_buffer_offsets[kMaxVertexBuffers];
444  for (size_t i = 0; i < vertex_buffer_count; i++) {
445  buffers[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();
450  if (device_buffer) {
451  command_buffer_->Track(device_buffer);
452  }
453  }
454 
455  // Bind the vertex buffers.
456  command_buffer_vk_.bindVertexBuffers(0u, vertex_buffer_count, buffers,
457  vertex_buffer_offsets);
458 
459  return true;
460 }
461 
462 // |RenderPass|
463 bool RenderPassVK::SetIndexBuffer(BufferView index_buffer,
464  IndexType index_type) {
465  if (!ValidateIndexBuffer(index_buffer, index_type)) {
466  return false;
467  }
468 
469  if (index_type != IndexType::kNone) {
470  has_index_buffer_ = true;
471 
472  BufferView index_buffer_view = std::move(index_buffer);
473  if (!index_buffer_view) {
474  return false;
475  }
476 
477  if (!index_buffer_view.GetBuffer()) {
478  VALIDATION_LOG << "Failed to acquire device buffer"
479  << " for index buffer view";
480  return false;
481  }
482 
483  std::shared_ptr<const DeviceBuffer> index_buffer =
484  index_buffer_view.TakeBuffer();
485  if (index_buffer && !command_buffer_->Track(index_buffer)) {
486  return false;
487  }
488 
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,
493  ToVKIndexType(index_type));
494  } else {
495  has_index_buffer_ = false;
496  }
497 
498  return true;
499 }
500 
501 // |RenderPass|
502 fml::Status RenderPassVK::Draw() {
503  if (!pipeline_) {
504  return fml::Status(fml::StatusCode::kCancelled,
505  "No valid pipeline is bound to the RenderPass.");
506  }
507 
508  //----------------------------------------------------------------------------
509  /// If there are immutable samplers referenced in the render pass, the base
510  /// pipeline variant is no longer valid and needs to be re-constructed to
511  /// reference the samplers.
512  ///
513  /// This is an instance of JIT creation of PSOs that can cause jank. It is
514  /// unavoidable because it isn't possible to know all possible combinations of
515  /// target YUV conversions. Fortunately, this will only ever happen when
516  /// rendering to external textures. Like Android Hardware Buffers on Android.
517  ///
518  /// Even when JIT creation is unavoidable, pipelines will cache their variants
519  /// when able and all pipeline creation will happen via a base pipeline cache
520  /// anyway. So the jank can be mostly entirely ameliorated and it should only
521  /// ever happen when the first unknown YUV conversion is encountered.
522  ///
523  /// Jank can be completely eliminated by pre-populating known YUV conversion
524  /// pipelines.
525  if (immutable_sampler_) {
526  std::shared_ptr<Pipeline<PipelineDescriptor>> pipeline_variant =
527  PipelineVK::Cast(*pipeline_)
528  .CreateVariantForImmutableSamplers(immutable_sampler_);
529  if (!pipeline_variant) {
530  return fml::Status(
531  fml::StatusCode::kAborted,
532  "Could not create pipeline variant with immutable sampler.");
533  }
534  pipeline_ = raw_ptr(pipeline_variant);
535  }
536 
537  const auto& context_vk = ContextVK::Cast(*context_);
538  const auto& pipeline_vk = PipelineVK::Cast(*pipeline_);
539 
540  auto descriptor_result = command_buffer_->AllocateDescriptorSets(
541  pipeline_vk.GetDescriptorSetLayout(), pipeline_vk.GetPipelineKey(),
542  context_vk);
543  if (!descriptor_result.ok()) {
544  return fml::Status(fml::StatusCode::kAborted,
545  "Could not allocate descriptor sets.");
546  }
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());
551 
552  for (auto i = 0u; i < descriptor_write_offset_; i++) {
553  write_workspace_[i].dstSet = descriptor_set;
554  }
555 
556  context_vk.GetDevice().updateDescriptorSets(descriptor_write_offset_,
557  write_workspace_.data(), 0u, {});
558 
559  command_buffer_vk_.bindDescriptorSets(
560  vk::PipelineBindPoint::eGraphics, // bind point
561  pipeline_layout, // layout
562  0, // first set
563  1, // set count
564  &descriptor_set, // sets
565  0, // offset count
566  nullptr // offsets
567  );
568 
569  if (pipeline_uses_input_attachments_) {
571  command_buffer_vk_, TextureVK::Cast(*color_image_vk_).GetImage());
572  }
573 
574  if (has_index_buffer_) {
575  command_buffer_vk_.drawIndexed(element_count_, // index count
576  instance_count_, // instance count
577  0u, // first index
578  base_vertex_, // vertex offset
579  0u // first instance
580  );
581  } else {
582  command_buffer_vk_.draw(element_count_, // vertex count
583  instance_count_, // instance count
584  base_vertex_, // vertex offset
585  0u // first instance
586  );
587  }
588 
589 #ifdef IMPELLER_DEBUG
590  if (has_label_) {
591  command_buffer_->PopDebugGroup();
592  }
593 #endif // IMPELLER_DEBUG
594  has_label_ = false;
595  has_index_buffer_ = false;
596  bound_image_offset_ = 0u;
597  bound_buffer_offset_ = 0u;
598  descriptor_write_offset_ = 0u;
599  instance_count_ = 1u;
600  base_vertex_ = 0u;
601  element_count_ = 0u;
602  pipeline_ = PipelineRef(nullptr);
603  pipeline_uses_input_attachments_ = false;
604  immutable_sampler_ = nullptr;
605  return fml::Status();
606 }
607 
608 // The RenderPassVK binding methods only need the binding, set, and buffer type
609 // information.
610 bool RenderPassVK::BindResource(ShaderStage stage,
611  DescriptorType type,
612  const ShaderUniformSlot& slot,
613  const ShaderMetadata* metadata,
614  BufferView view) {
615  return BindResource(slot.binding, type, view);
616 }
617 
618 bool RenderPassVK::BindDynamicResource(ShaderStage stage,
619  DescriptorType type,
620  const ShaderUniformSlot& slot,
621  std::unique_ptr<ShaderMetadata> metadata,
622  BufferView view) {
623  return BindResource(slot.binding, type, view);
624 }
625 
626 bool RenderPassVK::BindResource(size_t binding,
627  DescriptorType type,
628  BufferView view) {
629  if (bound_buffer_offset_ >= kMaxBindings) {
630  return false;
631  }
632 
633  auto buffer = DeviceBufferVK::Cast(*view.GetBuffer()).GetBuffer();
634  if (!buffer) {
635  return false;
636  }
637 
638  std::shared_ptr<const DeviceBuffer> device_buffer = view.TakeBuffer();
639  if (device_buffer && !command_buffer_->Track(device_buffer)) {
640  return false;
641  }
642 
643  uint32_t offset = view.GetRange().offset;
644 
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;
650 
651  vk::WriteDescriptorSet write_set;
652  write_set.dstBinding = binding;
653  write_set.descriptorCount = 1u;
654  write_set.descriptorType = ToVKDescriptorType(type);
655  write_set.pBufferInfo = &buffer_workspace_[bound_buffer_offset_ - 1];
656 
657  write_workspace_[descriptor_write_offset_++] = write_set;
658  return true;
659 }
660 
661 bool RenderPassVK::BindDynamicResource(ShaderStage stage,
662  DescriptorType type,
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);
668 }
669 
670 bool RenderPassVK::BindResource(ShaderStage stage,
671  DescriptorType type,
672  const SampledImageSlot& slot,
673  const ShaderMetadata* metadata,
674  std::shared_ptr<const Texture> texture,
675  raw_ptr<const Sampler> sampler) {
676  if (bound_buffer_offset_ >= kMaxBindings) {
677  return false;
678  }
679  if (!texture || !texture->IsValid() || !sampler) {
680  return false;
681  }
682  const TextureVK& texture_vk = TextureVK::Cast(*texture);
683  const SamplerVK& sampler_vk = SamplerVK::Cast(*sampler);
684 
685  if (!command_buffer_->Track(texture)) {
686  return false;
687  }
688 
689  if (!immutable_sampler_) {
690  immutable_sampler_ = texture_vk.GetImmutableSamplerVariant(sampler_vk);
691  }
692 
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;
698 
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];
704 
705  write_workspace_[descriptor_write_offset_++] = write_set;
706  return true;
707 }
708 
709 bool RenderPassVK::OnEncodeCommands(const Context& context) const {
710  command_buffer_->GetCommandBuffer().endRenderPass();
711  return true;
712 }
713 
714 } // namespace impeller
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
vk::ImageLayout SetLayoutWithoutEncoding(vk::ImageLayout layout) const
Definition: texture_vk.cc:186
bool SetLayout(const BarrierVK &barrier) const
Definition: texture_vk.cc:182
vk::ImageLayout GetLayout() const
Definition: texture_vk.cc:192
int32_t value
static vk::Viewport ToVkViewport(const Viewport &viewport)
TRect< int32_t > IRect32
Definition: rect.h:858
float Scalar
Definition: scalar.h:19
constexpr vk::IndexType ToVKIndexType(IndexType index_type)
Definition: formats_vk.h:391
raw_ptr< Pipeline< PipelineDescriptor > > PipelineRef
A raw ptr to a pipeline object.
Definition: pipeline.h:89
constexpr vk::DescriptorType ToVKDescriptorType(DescriptorType type)
Definition: formats_vk.h:328
static constexpr size_t kMaxBindings
Definition: pipeline_vk.h:23
constexpr size_t kMaxVertexBuffers
Definition: vertex_buffer.h:13
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)
SampleCount
Definition: formats.h:483
Definition: comparable.h:93
std::shared_ptr< ContextGLES > context
std::shared_ptr< PipelineGLES > pipeline
std::shared_ptr< CommandBuffer > command_buffer
std::shared_ptr< Texture > resolve_texture
Definition: formats.h:910
Scalar blue
Definition: color.h:138
Scalar alpha
Definition: color.h:143
Scalar red
Definition: color.h:128
Scalar green
Definition: color.h:133
constexpr static TRect MakeSize(const TSize< U > &size)
Definition: rect.h:150
DepthRange depth_range
Definition: formats.h:582
#define VALIDATION_LOG
Definition: validation.h:91