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,
82  bool is_swapchain) const {
83  RenderPassBuilderVK builder;
84 
85  render_target_.IterateAllColorAttachments([&](size_t bind_point,
86  const ColorAttachment&
87  attachment) -> bool {
88  builder.SetColorAttachment(
89  bind_point, //
90  attachment.texture->GetTextureDescriptor().format, //
91  attachment.texture->GetTextureDescriptor().sample_count, //
92  attachment.load_action, //
93  attachment.store_action, //
94  /*current_layout=*/TextureVK::Cast(*attachment.texture).GetLayout(), //
95  /*is_swapchain=*/is_swapchain);
96  return true;
97  });
98 
99  if (auto depth = render_target_.GetDepthAttachment(); depth.has_value()) {
100  builder.SetDepthStencilAttachment(
101  depth->texture->GetTextureDescriptor().format, //
102  depth->texture->GetTextureDescriptor().sample_count, //
103  depth->load_action, //
104  depth->store_action //
105  );
106  } else if (auto stencil = render_target_.GetStencilAttachment();
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 //
113  );
114  }
115 
116  if (recycled_renderpass != nullptr) {
117  return recycled_renderpass;
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  SharedHandleVK<vk::RenderPass> recycled_render_pass;
149  SharedHandleVK<vk::Framebuffer> recycled_framebuffer;
150  if (resolve_image_vk_) {
151  recycled_render_pass =
152  TextureVK::Cast(*resolve_image_vk_).GetCachedRenderPass();
153  recycled_framebuffer =
154  TextureVK::Cast(*resolve_image_vk_).GetCachedFramebuffer();
155  } else {
156  recycled_render_pass =
157  TextureVK::Cast(*color_image_vk_).GetCachedRenderPass();
158  recycled_framebuffer =
159  TextureVK::Cast(*color_image_vk_).GetCachedFramebuffer();
160  }
161 
162  const auto& target_size = render_target_.GetRenderTargetSize();
163 
164  bool is_swapchain = false;
165  if (resolve_image_vk_) {
166  is_swapchain = TextureVK::Cast(*resolve_image_vk_).IsSwapchainImage();
167  } else {
168  is_swapchain = TextureVK::Cast(*color_image_vk_).IsSwapchainImage();
169  }
170 
171  render_pass_ = CreateVKRenderPass(vk_context, recycled_render_pass,
172  command_buffer_, is_swapchain);
173  if (!render_pass_) {
174  VALIDATION_LOG << "Could not create renderpass.";
175  is_valid_ = false;
176  return;
177  }
178 
179  auto framebuffer = (recycled_framebuffer == nullptr)
180  ? CreateVKFramebuffer(vk_context, *render_pass_)
181  : recycled_framebuffer;
182  if (!framebuffer) {
183  VALIDATION_LOG << "Could not create framebuffer.";
184  is_valid_ = false;
185  return;
186  }
187 
188  if (!command_buffer_->Track(framebuffer) ||
189  !command_buffer_->Track(render_pass_)) {
190  is_valid_ = false;
191  return;
192  }
193  if (resolve_image_vk_) {
194  TextureVK::Cast(*resolve_image_vk_).SetCachedFramebuffer(framebuffer);
195  TextureVK::Cast(*resolve_image_vk_).SetCachedRenderPass(render_pass_);
196  } else {
197  TextureVK::Cast(*color_image_vk_).SetCachedFramebuffer(framebuffer);
198  TextureVK::Cast(*color_image_vk_).SetCachedRenderPass(render_pass_);
199  }
200 
201  std::array<vk::ClearValue, kMaxAttachments> clears;
202  size_t clear_count = GetVKClearValues(render_target_, clears);
203 
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);
212 
213  command_buffer_vk_.beginRenderPass(pass_info, vk::SubpassContents::eInline);
214 
215  if (resolve_image_vk_) {
216  TextureVK::Cast(*resolve_image_vk_)
218  is_swapchain ? vk::ImageLayout::eGeneral
219  : vk::ImageLayout::eShaderReadOnlyOptimal);
220  }
221  if (color_image_vk_) {
222  TextureVK::Cast(*color_image_vk_)
223  .SetLayoutWithoutEncoding(vk::ImageLayout::eGeneral);
224  }
225 
226  // Set the initial viewport.
227  const auto vp = Viewport{.rect = Rect::MakeSize(target_size)};
228  vk::Viewport viewport = vk::Viewport()
229  .setWidth(vp.rect.GetWidth())
230  .setHeight(-vp.rect.GetHeight())
231  .setY(vp.rect.GetHeight())
232  .setMinDepth(0.0f)
233  .setMaxDepth(1.0f);
234  command_buffer_vk_.setViewport(0, 1, &viewport);
235 
236  // Set the initial scissor.
237  const auto sc = IRect::MakeSize(target_size);
238  vk::Rect2D scissor =
239  vk::Rect2D()
240  .setOffset(vk::Offset2D(sc.GetX(), sc.GetY()))
241  .setExtent(vk::Extent2D(sc.GetWidth(), sc.GetHeight()));
242  command_buffer_vk_.setScissor(0, 1, &scissor);
243 
244  // Set the initial stencil reference.
245  command_buffer_vk_.setStencilReference(
246  vk::StencilFaceFlagBits::eVkStencilFrontAndBack, 0u);
247 
248  is_valid_ = true;
249 }
250 
251 RenderPassVK::~RenderPassVK() = default;
252 
253 bool RenderPassVK::IsValid() const {
254  return is_valid_;
255 }
256 
257 void RenderPassVK::OnSetLabel(std::string_view label) {
258 #ifdef IMPELLER_DEBUG
259  ContextVK::Cast(*context_).SetDebugName(render_pass_->Get(), label.data());
260 #endif // IMPELLER_DEBUG
261 }
262 
263 SharedHandleVK<vk::Framebuffer> RenderPassVK::CreateVKFramebuffer(
264  const ContextVK& context,
265  const vk::RenderPass& pass) const {
266  vk::FramebufferCreateInfo fb_info;
267 
268  fb_info.renderPass = pass;
269 
270  const auto target_size = render_target_.GetRenderTargetSize();
271  fb_info.width = target_size.width;
272  fb_info.height = target_size.height;
273  fb_info.layers = 1u;
274 
275  std::array<vk::ImageView, kMaxAttachments> attachments;
276  size_t count = 0;
277 
278  // This bit must be consistent to ensure compatibility with the pass created
279  // earlier. Follow this order: Color attachments, then depth-stencil, then
280  // stencil.
281  render_target_.IterateAllColorAttachments(
282  [&attachments, &count](size_t index,
283  const ColorAttachment& attachment) -> bool {
284  // The bind point doesn't matter here since that information is present
285  // in the render pass.
286  attachments[count++] =
287  TextureVK::Cast(*attachment.texture).GetRenderTargetView();
288  if (attachment.resolve_texture) {
289  attachments[count++] = TextureVK::Cast(*attachment.resolve_texture)
290  .GetRenderTargetView();
291  }
292  return true;
293  });
294 
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();
302  }
303 
304  fb_info.setPAttachments(attachments.data());
305  fb_info.setAttachmentCount(count);
306 
307  auto [result, framebuffer] =
308  context.GetDevice().createFramebufferUnique(fb_info);
309 
310  if (result != vk::Result::eSuccess) {
311  VALIDATION_LOG << "Could not create framebuffer: " << vk::to_string(result);
312  return {};
313  }
314 
315  return MakeSharedVK(std::move(framebuffer));
316 }
317 
318 // |RenderPass|
319 void RenderPassVK::SetPipeline(PipelineRef pipeline) {
320  pipeline_ = pipeline;
321  if (!pipeline_) {
322  return;
323  }
324 
325  pipeline_uses_input_attachments_ =
326  pipeline_->GetDescriptor().GetVertexDescriptor()->UsesInputAttacments();
327 
328  if (pipeline_uses_input_attachments_) {
329  if (bound_image_offset_ >= kMaxBindings) {
330  pipeline_ = PipelineRef(nullptr);
331  return;
332  }
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;
338 
339  vk::WriteDescriptorSet write_set;
340  write_set.dstBinding = kMagicSubpassInputBinding;
341  write_set.descriptorCount = 1u;
342  write_set.descriptorType = vk::DescriptorType::eInputAttachment;
343  write_set.pImageInfo = &image_workspace_[bound_image_offset_ - 1];
344 
345  write_workspace_[descriptor_write_offset_++] = write_set;
346  }
347 }
348 
349 // |RenderPass|
350 void RenderPassVK::SetCommandLabel(std::string_view label) {
351 #ifdef IMPELLER_DEBUG
352  command_buffer_->PushDebugGroup(label);
353  has_label_ = true;
354 #endif // IMPELLER_DEBUG
355 }
356 
357 // |RenderPass|
358 void RenderPassVK::SetStencilReference(uint32_t value) {
359  if (current_stencil_ == value) {
360  return;
361  }
362  current_stencil_ = value;
363  command_buffer_vk_.setStencilReference(
364  vk::StencilFaceFlagBits::eVkStencilFrontAndBack, value);
365 }
366 
367 // |RenderPass|
368 void RenderPassVK::SetBaseVertex(uint64_t value) {
369  base_vertex_ = value;
370 }
371 
372 // |RenderPass|
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())
378  .setMinDepth(0.0f)
379  .setMaxDepth(1.0f);
380  command_buffer_vk_.setViewport(0, 1, &viewport_vk);
381 }
382 
383 // |RenderPass|
384 void RenderPassVK::SetScissor(IRect scissor) {
385  vk::Rect2D scissor_vk =
386  vk::Rect2D()
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);
390 }
391 
392 // |RenderPass|
393 void RenderPassVK::SetElementCount(size_t count) {
394  element_count_ = count;
395 }
396 
397 // |RenderPass|
398 void RenderPassVK::SetInstanceCount(size_t count) {
399  instance_count_ = count;
400 }
401 
402 // |RenderPass|
403 bool RenderPassVK::SetVertexBuffer(BufferView vertex_buffers[],
404  size_t vertex_buffer_count) {
405  if (!ValidateVertexBuffers(vertex_buffers, vertex_buffer_count)) {
406  return false;
407  }
408 
409  vk::Buffer buffers[kMaxVertexBuffers];
410  vk::DeviceSize vertex_buffer_offsets[kMaxVertexBuffers];
411  for (size_t i = 0; i < vertex_buffer_count; i++) {
412  buffers[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();
417  if (device_buffer) {
418  command_buffer_->Track(device_buffer);
419  }
420  }
421 
422  // Bind the vertex buffers.
423  command_buffer_vk_.bindVertexBuffers(0u, vertex_buffer_count, buffers,
424  vertex_buffer_offsets);
425 
426  return true;
427 }
428 
429 // |RenderPass|
430 bool RenderPassVK::SetIndexBuffer(BufferView index_buffer,
431  IndexType index_type) {
432  if (!ValidateIndexBuffer(index_buffer, index_type)) {
433  return false;
434  }
435 
436  if (index_type != IndexType::kNone) {
437  has_index_buffer_ = true;
438 
439  BufferView index_buffer_view = std::move(index_buffer);
440  if (!index_buffer_view) {
441  return false;
442  }
443 
444  if (!index_buffer_view.GetBuffer()) {
445  VALIDATION_LOG << "Failed to acquire device buffer"
446  << " for index buffer view";
447  return false;
448  }
449 
450  std::shared_ptr<const DeviceBuffer> index_buffer =
451  index_buffer_view.TakeBuffer();
452  if (index_buffer && !command_buffer_->Track(index_buffer)) {
453  return false;
454  }
455 
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,
460  ToVKIndexType(index_type));
461  } else {
462  has_index_buffer_ = false;
463  }
464 
465  return true;
466 }
467 
468 // |RenderPass|
469 fml::Status RenderPassVK::Draw() {
470  if (!pipeline_) {
471  return fml::Status(fml::StatusCode::kCancelled,
472  "No valid pipeline is bound to the RenderPass.");
473  }
474 
475  //----------------------------------------------------------------------------
476  /// If there are immutable samplers referenced in the render pass, the base
477  /// pipeline variant is no longer valid and needs to be re-constructed to
478  /// reference the samplers.
479  ///
480  /// This is an instance of JIT creation of PSOs that can cause jank. It is
481  /// unavoidable because it isn't possible to know all possible combinations of
482  /// target YUV conversions. Fortunately, this will only ever happen when
483  /// rendering to external textures. Like Android Hardware Buffers on Android.
484  ///
485  /// Even when JIT creation is unavoidable, pipelines will cache their variants
486  /// when able and all pipeline creation will happen via a base pipeline cache
487  /// anyway. So the jank can be mostly entirely ameliorated and it should only
488  /// ever happen when the first unknown YUV conversion is encountered.
489  ///
490  /// Jank can be completely eliminated by pre-populating known YUV conversion
491  /// pipelines.
492  if (immutable_sampler_) {
493  std::shared_ptr<Pipeline<PipelineDescriptor>> pipeline_variant =
494  PipelineVK::Cast(*pipeline_)
495  .CreateVariantForImmutableSamplers(immutable_sampler_);
496  if (!pipeline_variant) {
497  return fml::Status(
498  fml::StatusCode::kAborted,
499  "Could not create pipeline variant with immutable sampler.");
500  }
501  pipeline_ = raw_ptr(pipeline_variant);
502  }
503 
504  const auto& context_vk = ContextVK::Cast(*context_);
505  const auto& pipeline_vk = PipelineVK::Cast(*pipeline_);
506 
507  auto descriptor_result = command_buffer_->AllocateDescriptorSets(
508  pipeline_vk.GetDescriptorSetLayout(), pipeline_vk.GetPipelineKey(),
509  context_vk);
510  if (!descriptor_result.ok()) {
511  return fml::Status(fml::StatusCode::kAborted,
512  "Could not allocate descriptor sets.");
513  }
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());
518 
519  for (auto i = 0u; i < descriptor_write_offset_; i++) {
520  write_workspace_[i].dstSet = descriptor_set;
521  }
522 
523  context_vk.GetDevice().updateDescriptorSets(descriptor_write_offset_,
524  write_workspace_.data(), 0u, {});
525 
526  command_buffer_vk_.bindDescriptorSets(
527  vk::PipelineBindPoint::eGraphics, // bind point
528  pipeline_layout, // layout
529  0, // first set
530  1, // set count
531  &descriptor_set, // sets
532  0, // offset count
533  nullptr // offsets
534  );
535 
536  if (pipeline_uses_input_attachments_) {
538  command_buffer_vk_, TextureVK::Cast(*color_image_vk_).GetImage());
539  }
540 
541  if (has_index_buffer_) {
542  command_buffer_vk_.drawIndexed(element_count_, // index count
543  instance_count_, // instance count
544  0u, // first index
545  base_vertex_, // vertex offset
546  0u // first instance
547  );
548  } else {
549  command_buffer_vk_.draw(element_count_, // vertex count
550  instance_count_, // instance count
551  base_vertex_, // vertex offset
552  0u // first instance
553  );
554  }
555 
556 #ifdef IMPELLER_DEBUG
557  if (has_label_) {
558  command_buffer_->PopDebugGroup();
559  }
560 #endif // IMPELLER_DEBUG
561  has_label_ = false;
562  has_index_buffer_ = false;
563  bound_image_offset_ = 0u;
564  bound_buffer_offset_ = 0u;
565  descriptor_write_offset_ = 0u;
566  instance_count_ = 1u;
567  base_vertex_ = 0u;
568  element_count_ = 0u;
569  pipeline_ = PipelineRef(nullptr);
570  pipeline_uses_input_attachments_ = false;
571  immutable_sampler_ = nullptr;
572  return fml::Status();
573 }
574 
575 // The RenderPassVK binding methods only need the binding, set, and buffer type
576 // information.
577 bool RenderPassVK::BindResource(ShaderStage stage,
579  const ShaderUniformSlot& slot,
580  const ShaderMetadata* metadata,
581  BufferView view) {
582  return BindResource(slot.binding, type, view);
583 }
584 
585 bool RenderPassVK::BindDynamicResource(ShaderStage stage,
587  const ShaderUniformSlot& slot,
588  std::unique_ptr<ShaderMetadata> metadata,
589  BufferView view) {
590  return BindResource(slot.binding, type, view);
591 }
592 
593 bool RenderPassVK::BindResource(size_t binding,
595  BufferView view) {
596  if (bound_buffer_offset_ >= kMaxBindings) {
597  return false;
598  }
599 
600  auto buffer = DeviceBufferVK::Cast(*view.GetBuffer()).GetBuffer();
601  if (!buffer) {
602  return false;
603  }
604 
605  std::shared_ptr<const DeviceBuffer> device_buffer = view.TakeBuffer();
606  if (device_buffer && !command_buffer_->Track(device_buffer)) {
607  return false;
608  }
609 
610  uint32_t offset = view.GetRange().offset;
611 
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;
617 
618  vk::WriteDescriptorSet write_set;
619  write_set.dstBinding = binding;
620  write_set.descriptorCount = 1u;
621  write_set.descriptorType = ToVKDescriptorType(type);
622  write_set.pBufferInfo = &buffer_workspace_[bound_buffer_offset_ - 1];
623 
624  write_workspace_[descriptor_write_offset_++] = write_set;
625  return true;
626 }
627 
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);
635 }
636 
637 bool RenderPassVK::BindResource(ShaderStage stage,
639  const SampledImageSlot& slot,
640  const ShaderMetadata* metadata,
641  std::shared_ptr<const Texture> texture,
642  raw_ptr<const Sampler> sampler) {
643  if (bound_buffer_offset_ >= kMaxBindings) {
644  return false;
645  }
646  if (!texture || !texture->IsValid() || !sampler) {
647  return false;
648  }
649  const TextureVK& texture_vk = TextureVK::Cast(*texture);
650  const SamplerVK& sampler_vk = SamplerVK::Cast(*sampler);
651 
652  if (!command_buffer_->Track(texture)) {
653  return false;
654  }
655 
656  if (!immutable_sampler_) {
657  immutable_sampler_ = texture_vk.GetImmutableSamplerVariant(sampler_vk);
658  }
659 
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;
665 
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];
671 
672  write_workspace_[descriptor_write_offset_++] = write_set;
673  return true;
674 }
675 
676 bool RenderPassVK::OnEncodeCommands(const Context& context) const {
677  command_buffer_->GetCommandBuffer().endRenderPass();
678  return true;
679 }
680 
681 } // 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:221
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: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)
Definition: comparable.h:95
SeparatedVector2 offset
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