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