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 = IRect32::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  context_->GetPipelineLibrary()->LogPipelineUsage(pipeline->GetDescriptor());
340 
341  pipeline_uses_input_attachments_ =
342  pipeline_->GetDescriptor().GetVertexDescriptor()->UsesInputAttacments();
343 
344  if (pipeline_uses_input_attachments_) {
345  if (bound_image_offset_ >= kMaxBindings) {
346  pipeline_ = PipelineRef(nullptr);
347  return;
348  }
349  vk::DescriptorImageInfo image_info;
350  image_info.imageLayout = vk::ImageLayout::eGeneral;
351  image_info.sampler = VK_NULL_HANDLE;
352  image_info.imageView = TextureVK::Cast(*color_image_vk_).GetImageView();
353  image_workspace_[bound_image_offset_++] = image_info;
354 
355  vk::WriteDescriptorSet write_set;
356  write_set.dstBinding = kMagicSubpassInputBinding;
357  write_set.descriptorCount = 1u;
358  write_set.descriptorType = vk::DescriptorType::eInputAttachment;
359  write_set.pImageInfo = &image_workspace_[bound_image_offset_ - 1];
360 
361  write_workspace_[descriptor_write_offset_++] = write_set;
362  }
363 }
364 
365 // |RenderPass|
366 void RenderPassVK::SetCommandLabel(std::string_view label) {
367 #ifdef IMPELLER_DEBUG
368  command_buffer_->PushDebugGroup(label);
369  has_label_ = true;
370 #endif // IMPELLER_DEBUG
371 }
372 
373 // |RenderPass|
374 void RenderPassVK::SetStencilReference(uint32_t value) {
375  if (current_stencil_ == value) {
376  return;
377  }
378  current_stencil_ = value;
379  command_buffer_vk_.setStencilReference(
380  vk::StencilFaceFlagBits::eVkStencilFrontAndBack, value);
381 }
382 
383 // |RenderPass|
384 void RenderPassVK::SetBaseVertex(uint64_t value) {
385  base_vertex_ = value;
386 }
387 
388 // |RenderPass|
389 void RenderPassVK::SetViewport(Viewport viewport) {
390  vk::Viewport viewport_vk = vk::Viewport()
391  .setWidth(viewport.rect.GetWidth())
392  .setHeight(-viewport.rect.GetHeight())
393  .setY(viewport.rect.GetHeight())
394  .setMinDepth(0.0f)
395  .setMaxDepth(1.0f);
396  command_buffer_vk_.setViewport(0, 1, &viewport_vk);
397 }
398 
399 // |RenderPass|
400 void RenderPassVK::SetScissor(IRect32 scissor) {
401  vk::Rect2D scissor_vk =
402  vk::Rect2D()
403  .setOffset(vk::Offset2D(scissor.GetX(), scissor.GetY()))
404  .setExtent(vk::Extent2D(scissor.GetWidth(), scissor.GetHeight()));
405  command_buffer_vk_.setScissor(0, 1, &scissor_vk);
406 }
407 
408 // |RenderPass|
409 void RenderPassVK::SetElementCount(size_t count) {
410  element_count_ = count;
411 }
412 
413 // |RenderPass|
414 void RenderPassVK::SetInstanceCount(size_t count) {
415  instance_count_ = count;
416 }
417 
418 // |RenderPass|
419 bool RenderPassVK::SetVertexBuffer(BufferView vertex_buffers[],
420  size_t vertex_buffer_count) {
421  if (!ValidateVertexBuffers(vertex_buffers, vertex_buffer_count)) {
422  return false;
423  }
424 
425  vk::Buffer buffers[kMaxVertexBuffers];
426  vk::DeviceSize vertex_buffer_offsets[kMaxVertexBuffers];
427  for (size_t i = 0; i < vertex_buffer_count; i++) {
428  buffers[i] =
429  DeviceBufferVK::Cast(*vertex_buffers[i].GetBuffer()).GetBuffer();
430  vertex_buffer_offsets[i] = vertex_buffers[i].GetRange().offset;
431  std::shared_ptr<const DeviceBuffer> device_buffer =
432  vertex_buffers[i].TakeBuffer();
433  if (device_buffer) {
434  command_buffer_->Track(device_buffer);
435  }
436  }
437 
438  // Bind the vertex buffers.
439  command_buffer_vk_.bindVertexBuffers(0u, vertex_buffer_count, buffers,
440  vertex_buffer_offsets);
441 
442  return true;
443 }
444 
445 // |RenderPass|
446 bool RenderPassVK::SetIndexBuffer(BufferView index_buffer,
447  IndexType index_type) {
448  if (!ValidateIndexBuffer(index_buffer, index_type)) {
449  return false;
450  }
451 
452  if (index_type != IndexType::kNone) {
453  has_index_buffer_ = true;
454 
455  BufferView index_buffer_view = std::move(index_buffer);
456  if (!index_buffer_view) {
457  return false;
458  }
459 
460  if (!index_buffer_view.GetBuffer()) {
461  VALIDATION_LOG << "Failed to acquire device buffer"
462  << " for index buffer view";
463  return false;
464  }
465 
466  std::shared_ptr<const DeviceBuffer> index_buffer =
467  index_buffer_view.TakeBuffer();
468  if (index_buffer && !command_buffer_->Track(index_buffer)) {
469  return false;
470  }
471 
472  vk::Buffer index_buffer_handle =
473  DeviceBufferVK::Cast(*index_buffer_view.GetBuffer()).GetBuffer();
474  command_buffer_vk_.bindIndexBuffer(index_buffer_handle,
475  index_buffer_view.GetRange().offset,
476  ToVKIndexType(index_type));
477  } else {
478  has_index_buffer_ = false;
479  }
480 
481  return true;
482 }
483 
484 // |RenderPass|
485 fml::Status RenderPassVK::Draw() {
486  if (!pipeline_) {
487  return fml::Status(fml::StatusCode::kCancelled,
488  "No valid pipeline is bound to the RenderPass.");
489  }
490 
491  //----------------------------------------------------------------------------
492  /// If there are immutable samplers referenced in the render pass, the base
493  /// pipeline variant is no longer valid and needs to be re-constructed to
494  /// reference the samplers.
495  ///
496  /// This is an instance of JIT creation of PSOs that can cause jank. It is
497  /// unavoidable because it isn't possible to know all possible combinations of
498  /// target YUV conversions. Fortunately, this will only ever happen when
499  /// rendering to external textures. Like Android Hardware Buffers on Android.
500  ///
501  /// Even when JIT creation is unavoidable, pipelines will cache their variants
502  /// when able and all pipeline creation will happen via a base pipeline cache
503  /// anyway. So the jank can be mostly entirely ameliorated and it should only
504  /// ever happen when the first unknown YUV conversion is encountered.
505  ///
506  /// Jank can be completely eliminated by pre-populating known YUV conversion
507  /// pipelines.
508  if (immutable_sampler_) {
509  std::shared_ptr<Pipeline<PipelineDescriptor>> pipeline_variant =
510  PipelineVK::Cast(*pipeline_)
511  .CreateVariantForImmutableSamplers(immutable_sampler_);
512  if (!pipeline_variant) {
513  return fml::Status(
514  fml::StatusCode::kAborted,
515  "Could not create pipeline variant with immutable sampler.");
516  }
517  pipeline_ = raw_ptr(pipeline_variant);
518  }
519 
520  const auto& context_vk = ContextVK::Cast(*context_);
521  const auto& pipeline_vk = PipelineVK::Cast(*pipeline_);
522 
523  auto descriptor_result = command_buffer_->AllocateDescriptorSets(
524  pipeline_vk.GetDescriptorSetLayout(), pipeline_vk.GetPipelineKey(),
525  context_vk);
526  if (!descriptor_result.ok()) {
527  return fml::Status(fml::StatusCode::kAborted,
528  "Could not allocate descriptor sets.");
529  }
530  const auto descriptor_set = descriptor_result.value();
531  const auto pipeline_layout = pipeline_vk.GetPipelineLayout();
532  command_buffer_vk_.bindPipeline(vk::PipelineBindPoint::eGraphics,
533  pipeline_vk.GetPipeline());
534 
535  for (auto i = 0u; i < descriptor_write_offset_; i++) {
536  write_workspace_[i].dstSet = descriptor_set;
537  }
538 
539  context_vk.GetDevice().updateDescriptorSets(descriptor_write_offset_,
540  write_workspace_.data(), 0u, {});
541 
542  command_buffer_vk_.bindDescriptorSets(
543  vk::PipelineBindPoint::eGraphics, // bind point
544  pipeline_layout, // layout
545  0, // first set
546  1, // set count
547  &descriptor_set, // sets
548  0, // offset count
549  nullptr // offsets
550  );
551 
552  if (pipeline_uses_input_attachments_) {
554  command_buffer_vk_, TextureVK::Cast(*color_image_vk_).GetImage());
555  }
556 
557  if (has_index_buffer_) {
558  command_buffer_vk_.drawIndexed(element_count_, // index count
559  instance_count_, // instance count
560  0u, // first index
561  base_vertex_, // vertex offset
562  0u // first instance
563  );
564  } else {
565  command_buffer_vk_.draw(element_count_, // vertex count
566  instance_count_, // instance count
567  base_vertex_, // vertex offset
568  0u // first instance
569  );
570  }
571 
572 #ifdef IMPELLER_DEBUG
573  if (has_label_) {
574  command_buffer_->PopDebugGroup();
575  }
576 #endif // IMPELLER_DEBUG
577  has_label_ = false;
578  has_index_buffer_ = false;
579  bound_image_offset_ = 0u;
580  bound_buffer_offset_ = 0u;
581  descriptor_write_offset_ = 0u;
582  instance_count_ = 1u;
583  base_vertex_ = 0u;
584  element_count_ = 0u;
585  pipeline_ = PipelineRef(nullptr);
586  pipeline_uses_input_attachments_ = false;
587  immutable_sampler_ = nullptr;
588  return fml::Status();
589 }
590 
591 // The RenderPassVK binding methods only need the binding, set, and buffer type
592 // information.
593 bool RenderPassVK::BindResource(ShaderStage stage,
595  const ShaderUniformSlot& slot,
596  const ShaderMetadata* metadata,
597  BufferView view) {
598  return BindResource(slot.binding, type, view);
599 }
600 
601 bool RenderPassVK::BindDynamicResource(ShaderStage stage,
603  const ShaderUniformSlot& slot,
604  std::unique_ptr<ShaderMetadata> metadata,
605  BufferView view) {
606  return BindResource(slot.binding, type, view);
607 }
608 
609 bool RenderPassVK::BindResource(size_t binding,
611  BufferView view) {
612  if (bound_buffer_offset_ >= kMaxBindings) {
613  return false;
614  }
615 
616  auto buffer = DeviceBufferVK::Cast(*view.GetBuffer()).GetBuffer();
617  if (!buffer) {
618  return false;
619  }
620 
621  std::shared_ptr<const DeviceBuffer> device_buffer = view.TakeBuffer();
622  if (device_buffer && !command_buffer_->Track(device_buffer)) {
623  return false;
624  }
625 
626  uint32_t offset = view.GetRange().offset;
627 
628  vk::DescriptorBufferInfo buffer_info;
629  buffer_info.buffer = buffer;
630  buffer_info.offset = offset;
631  buffer_info.range = view.GetRange().length;
632  buffer_workspace_[bound_buffer_offset_++] = buffer_info;
633 
634  vk::WriteDescriptorSet write_set;
635  write_set.dstBinding = binding;
636  write_set.descriptorCount = 1u;
637  write_set.descriptorType = ToVKDescriptorType(type);
638  write_set.pBufferInfo = &buffer_workspace_[bound_buffer_offset_ - 1];
639 
640  write_workspace_[descriptor_write_offset_++] = write_set;
641  return true;
642 }
643 
644 bool RenderPassVK::BindDynamicResource(ShaderStage stage,
646  const SampledImageSlot& slot,
647  std::unique_ptr<ShaderMetadata> metadata,
648  std::shared_ptr<const Texture> texture,
649  raw_ptr<const Sampler> sampler) {
650  return BindResource(stage, type, slot, nullptr, texture, sampler);
651 }
652 
653 bool RenderPassVK::BindResource(ShaderStage stage,
655  const SampledImageSlot& slot,
656  const ShaderMetadata* metadata,
657  std::shared_ptr<const Texture> texture,
658  raw_ptr<const Sampler> sampler) {
659  if (bound_buffer_offset_ >= kMaxBindings) {
660  return false;
661  }
662  if (!texture || !texture->IsValid() || !sampler) {
663  return false;
664  }
665  const TextureVK& texture_vk = TextureVK::Cast(*texture);
666  const SamplerVK& sampler_vk = SamplerVK::Cast(*sampler);
667 
668  if (!command_buffer_->Track(texture)) {
669  return false;
670  }
671 
672  if (!immutable_sampler_) {
673  immutable_sampler_ = texture_vk.GetImmutableSamplerVariant(sampler_vk);
674  }
675 
676  vk::DescriptorImageInfo image_info;
677  image_info.imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal;
678  image_info.sampler = sampler_vk.GetSampler();
679  image_info.imageView = texture_vk.GetImageView();
680  image_workspace_[bound_image_offset_++] = image_info;
681 
682  vk::WriteDescriptorSet write_set;
683  write_set.dstBinding = slot.binding;
684  write_set.descriptorCount = 1u;
685  write_set.descriptorType = vk::DescriptorType::eCombinedImageSampler;
686  write_set.pImageInfo = &image_workspace_[bound_image_offset_ - 1];
687 
688  write_workspace_[descriptor_write_offset_++] = write_set;
689  return true;
690 }
691 
692 bool RenderPassVK::OnEncodeCommands(const Context& context) const {
693  command_buffer_->GetCommandBuffer().endRenderPass();
694  return true;
695 }
696 
697 } // 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
TRect< int32_t > IRect32
Definition: rect.h:789
float Scalar
Definition: scalar.h:19
constexpr vk::IndexType ToVKIndexType(IndexType index_type)
Definition: formats_vk.h:357
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:294
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:298
Definition: comparable.h:95
std::shared_ptr< Texture > resolve_texture
Definition: formats.h:662
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