Flutter Impeller
render_pass_mtl.mm
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 "flutter/fml/closure.h"
8 #include "flutter/fml/logging.h"
9 #include "flutter/fml/make_copyable.h"
10 #include "flutter/fml/trace_event.h"
12 #include "impeller/core/formats.h"
22 
23 namespace impeller {
24 
26  const Attachment& desc,
27  MTLRenderPassAttachmentDescriptor* attachment) {
28  bool needs_resolve =
31 
32  if (needs_resolve && !desc.resolve_texture) {
33  VALIDATION_LOG << "Resolve store action specified on attachment but no "
34  "resolve texture was specified.";
35  return false;
36  }
37 
38  if (desc.resolve_texture && !needs_resolve) {
39  VALIDATION_LOG << "A resolve texture was specified even though the store "
40  "action doesn't require it.";
41  return false;
42  }
43 
44  if (!desc.resolve_texture) {
45  return true;
46  }
47 
48  attachment.resolveTexture =
50 
51  return true;
52 }
53 
54 static bool ConfigureAttachment(const Attachment& desc,
55  MTLRenderPassAttachmentDescriptor* attachment) {
56  if (!desc.texture) {
57  return false;
58  }
59 
60  attachment.texture = TextureMTL::Cast(*desc.texture).GetMTLTexture();
61  attachment.loadAction = ToMTLLoadAction(desc.load_action);
62  attachment.storeAction = ToMTLStoreAction(desc.store_action);
63 
64  if (!ConfigureResolveTextureAttachment(desc, attachment)) {
65  return false;
66  }
67 
68  return true;
69 }
70 
72  const ColorAttachment& desc,
73  MTLRenderPassColorAttachmentDescriptor* attachment) {
74  if (!ConfigureAttachment(desc, attachment)) {
75  return false;
76  }
77  attachment.clearColor = ToMTLClearColor(desc.clear_color);
78  return true;
79 }
80 
82  const DepthAttachment& desc,
83  MTLRenderPassDepthAttachmentDescriptor* attachment) {
84  if (!ConfigureAttachment(desc, attachment)) {
85  return false;
86  }
87  attachment.clearDepth = desc.clear_depth;
88  return true;
89 }
90 
92  const StencilAttachment& desc,
93  MTLRenderPassStencilAttachmentDescriptor* attachment) {
94  if (!ConfigureAttachment(desc, attachment)) {
95  return false;
96  }
97  attachment.clearStencil = desc.clear_stencil;
98  return true;
99 }
100 
101 // TODO(csg): Move this to formats_mtl.h
102 static MTLRenderPassDescriptor* ToMTLRenderPassDescriptor(
103  const RenderTarget& desc) {
104  auto result = [MTLRenderPassDescriptor renderPassDescriptor];
105 
106  const auto& colors = desc.GetColorAttachments();
107 
108  for (const auto& color : colors) {
109  if (!ConfigureColorAttachment(color.second,
110  result.colorAttachments[color.first])) {
111  VALIDATION_LOG << "Could not configure color attachment at index "
112  << color.first;
113  return nil;
114  }
115  }
116 
117  const auto& depth = desc.GetDepthAttachment();
118 
119  if (depth.has_value() &&
120  !ConfigureDepthAttachment(depth.value(), result.depthAttachment)) {
121  VALIDATION_LOG << "Could not configure depth attachment.";
122  return nil;
123  }
124 
125  const auto& stencil = desc.GetStencilAttachment();
126 
127  if (stencil.has_value() &&
128  !ConfigureStencilAttachment(stencil.value(), result.stencilAttachment)) {
129  VALIDATION_LOG << "Could not configure stencil attachment.";
130  return nil;
131  }
132 
133  return result;
134 }
135 
136 RenderPassMTL::RenderPassMTL(std::weak_ptr<const Context> context,
137  const RenderTarget& target,
138  id<MTLCommandBuffer> buffer)
139  : RenderPass(std::move(context), target),
140  buffer_(buffer),
141  desc_(ToMTLRenderPassDescriptor(GetRenderTarget())) {
142  if (!buffer_ || !desc_ || !render_target_.IsValid()) {
143  return;
144  }
145  is_valid_ = true;
146 }
147 
148 RenderPassMTL::~RenderPassMTL() = default;
149 
150 bool RenderPassMTL::IsValid() const {
151  return is_valid_;
152 }
153 
154 void RenderPassMTL::OnSetLabel(std::string label) {
155  if (label.empty()) {
156  return;
157  }
158  label_ = std::move(label);
159 }
160 
161 bool RenderPassMTL::OnEncodeCommands(const Context& context) const {
162  TRACE_EVENT0("impeller", "RenderPassMTL::EncodeCommands");
163  if (!IsValid()) {
164  return false;
165  }
166  auto render_command_encoder =
167  [buffer_ renderCommandEncoderWithDescriptor:desc_];
168 
169  if (!render_command_encoder) {
170  return false;
171  }
172 
173  if (!label_.empty()) {
174  [render_command_encoder setLabel:@(label_.c_str())];
175  }
176 
177  // Success or failure, the pass must end. The buffer can only process one pass
178  // at a time.
179  fml::ScopedCleanupClosure auto_end(
180  [render_command_encoder]() { [render_command_encoder endEncoding]; });
181 
182  return EncodeCommands(context.GetResourceAllocator(), render_command_encoder);
183 }
184 
185 //-----------------------------------------------------------------------------
186 /// @brief Ensures that bindings on the pass are not redundantly set or
187 /// updated. Avoids making the driver do additional checks and makes
188 /// the frame insights during profiling and instrumentation not
189 /// complain about the same.
190 ///
191 /// There should be no change to rendering if this caching was
192 /// absent.
193 ///
195  explicit PassBindingsCache(id<MTLRenderCommandEncoder> encoder)
196  : encoder_(encoder) {}
197 
198  PassBindingsCache(const PassBindingsCache&) = delete;
199 
201 
202  void SetRenderPipelineState(id<MTLRenderPipelineState> pipeline) {
203  if (pipeline == pipeline_) {
204  return;
205  }
206  pipeline_ = pipeline;
207  [encoder_ setRenderPipelineState:pipeline_];
208  }
209 
210  void SetDepthStencilState(id<MTLDepthStencilState> depth_stencil) {
211  if (depth_stencil_ == depth_stencil) {
212  return;
213  }
214  depth_stencil_ = depth_stencil;
215  [encoder_ setDepthStencilState:depth_stencil_];
216  }
217 
218  bool SetBuffer(ShaderStage stage,
219  uint64_t index,
220  uint64_t offset,
221  id<MTLBuffer> buffer) {
222  auto& buffers_map = buffers_[stage];
223  auto found = buffers_map.find(index);
224  if (found != buffers_map.end() && found->second.buffer == buffer) {
225  // The right buffer is bound. Check if its offset needs to be updated.
226  if (found->second.offset == offset) {
227  // Buffer and its offset is identical. Nothing to do.
228  return true;
229  }
230 
231  // Only the offset needs to be updated.
232  found->second.offset = offset;
233 
234  switch (stage) {
235  case ShaderStage::kVertex:
236  [encoder_ setVertexBufferOffset:offset atIndex:index];
237  return true;
238  case ShaderStage::kFragment:
239  [encoder_ setFragmentBufferOffset:offset atIndex:index];
240  return true;
241  default:
242  VALIDATION_LOG << "Cannot update buffer offset of an unknown stage.";
243  return false;
244  }
245  return true;
246  }
247  buffers_map[index] = {buffer, static_cast<size_t>(offset)};
248  switch (stage) {
249  case ShaderStage::kVertex:
250  [encoder_ setVertexBuffer:buffer offset:offset atIndex:index];
251  return true;
252  case ShaderStage::kFragment:
253  [encoder_ setFragmentBuffer:buffer offset:offset atIndex:index];
254  return true;
255  default:
256  VALIDATION_LOG << "Cannot bind buffer to unknown shader stage.";
257  return false;
258  }
259  return false;
260  }
261 
262  bool SetTexture(ShaderStage stage, uint64_t index, id<MTLTexture> texture) {
263  auto& texture_map = textures_[stage];
264  auto found = texture_map.find(index);
265  if (found != texture_map.end() && found->second == texture) {
266  // Already bound.
267  return true;
268  }
269  texture_map[index] = texture;
270  switch (stage) {
271  case ShaderStage::kVertex:
272  [encoder_ setVertexTexture:texture atIndex:index];
273  return true;
274  case ShaderStage::kFragment:
275  [encoder_ setFragmentTexture:texture atIndex:index];
276  return true;
277  default:
278  VALIDATION_LOG << "Cannot bind buffer to unknown shader stage.";
279  return false;
280  }
281  return false;
282  }
283 
285  uint64_t index,
286  id<MTLSamplerState> sampler) {
287  auto& sampler_map = samplers_[stage];
288  auto found = sampler_map.find(index);
289  if (found != sampler_map.end() && found->second == sampler) {
290  // Already bound.
291  return true;
292  }
293  sampler_map[index] = sampler;
294  switch (stage) {
295  case ShaderStage::kVertex:
296  [encoder_ setVertexSamplerState:sampler atIndex:index];
297  return true;
298  case ShaderStage::kFragment:
299  [encoder_ setFragmentSamplerState:sampler atIndex:index];
300  return true;
301  default:
302  VALIDATION_LOG << "Cannot bind buffer to unknown shader stage.";
303  return false;
304  }
305  return false;
306  }
307 
308  void SetViewport(const Viewport& viewport) {
309  if (viewport_.has_value() && viewport_.value() == viewport) {
310  return;
311  }
312  [encoder_ setViewport:MTLViewport{
313  .originX = viewport.rect.origin.x,
314  .originY = viewport.rect.origin.y,
315  .width = viewport.rect.size.width,
316  .height = viewport.rect.size.height,
317  .znear = viewport.depth_range.z_near,
318  .zfar = viewport.depth_range.z_far,
319  }];
320  viewport_ = viewport;
321  }
322 
323  void SetScissor(const IRect& scissor) {
324  if (scissor_.has_value() && scissor_.value() == scissor) {
325  return;
326  }
327  [encoder_
328  setScissorRect:MTLScissorRect{
329  .x = static_cast<NSUInteger>(scissor.origin.x),
330  .y = static_cast<NSUInteger>(scissor.origin.y),
331  .width = static_cast<NSUInteger>(scissor.size.width),
332  .height =
333  static_cast<NSUInteger>(scissor.size.height),
334  }];
335  scissor_ = scissor;
336  }
337 
338  private:
339  struct BufferOffsetPair {
340  id<MTLBuffer> buffer = nullptr;
341  size_t offset = 0u;
342  };
343  using BufferMap = std::map<uint64_t, BufferOffsetPair>;
344  using TextureMap = std::map<uint64_t, id<MTLTexture>>;
345  using SamplerMap = std::map<uint64_t, id<MTLSamplerState>>;
346 
347  const id<MTLRenderCommandEncoder> encoder_;
348  id<MTLRenderPipelineState> pipeline_ = nullptr;
349  id<MTLDepthStencilState> depth_stencil_ = nullptr;
350  std::map<ShaderStage, BufferMap> buffers_;
351  std::map<ShaderStage, TextureMap> textures_;
352  std::map<ShaderStage, SamplerMap> samplers_;
353  std::optional<Viewport> viewport_;
354  std::optional<IRect> scissor_;
355 };
356 
357 static bool Bind(PassBindingsCache& pass,
358  Allocator& allocator,
359  ShaderStage stage,
360  size_t bind_index,
361  const BufferView& view) {
362  if (!view.buffer) {
363  return false;
364  }
365 
366  auto device_buffer = view.buffer->GetDeviceBuffer(allocator);
367  if (!device_buffer) {
368  return false;
369  }
370 
371  auto buffer = DeviceBufferMTL::Cast(*device_buffer).GetMTLBuffer();
372  // The Metal call is a void return and we don't want to make it on nil.
373  if (!buffer) {
374  return false;
375  }
376 
377  return pass.SetBuffer(stage, bind_index, view.range.offset, buffer);
378 }
379 
380 static bool Bind(PassBindingsCache& pass,
381  ShaderStage stage,
382  size_t bind_index,
383  const Sampler& sampler,
384  const Texture& texture) {
385  if (!sampler.IsValid() || !texture.IsValid()) {
386  return false;
387  }
388 
389  if (texture.NeedsMipmapGeneration()) {
390  // TODO(127697): generate mips when the GPU is available on iOS.
391 #if !FML_OS_IOS
393  << "Texture at binding index " << bind_index
394  << " has a mip count > 1, but the mipmap has not been generated.";
395  return false;
396 #endif // !FML_OS_IOS
397  }
398 
399  return pass.SetTexture(stage, bind_index,
400  TextureMTL::Cast(texture).GetMTLTexture()) &&
401  pass.SetSampler(stage, bind_index,
402  SamplerMTL::Cast(sampler).GetMTLSamplerState());
403 }
404 
405 bool RenderPassMTL::EncodeCommands(const std::shared_ptr<Allocator>& allocator,
406  id<MTLRenderCommandEncoder> encoder) const {
407  PassBindingsCache pass_bindings(encoder);
408  auto bind_stage_resources = [&allocator, &pass_bindings](
409  const Bindings& bindings,
410  ShaderStage stage) -> bool {
411  if (stage == ShaderStage::kVertex) {
412  if (!Bind(pass_bindings, *allocator, stage,
413  VertexDescriptor::kReservedVertexBufferIndex,
414  bindings.vertex_buffer.view.resource)) {
415  return false;
416  }
417  }
418  for (const auto& buffer : bindings.buffers) {
419  if (!Bind(pass_bindings, *allocator, stage, buffer.first,
420  buffer.second.view.resource)) {
421  return false;
422  }
423  }
424  for (const auto& data : bindings.sampled_images) {
425  if (!Bind(pass_bindings, stage, data.first, *data.second.sampler.resource,
426  *data.second.texture.resource)) {
427  return false;
428  }
429  }
430  return true;
431  };
432 
433  const auto target_sample_count = render_target_.GetSampleCount();
434 
435  fml::closure pop_debug_marker = [encoder]() { [encoder popDebugGroup]; };
436  for (const auto& command : commands_) {
437  if (command.vertex_count == 0u) {
438  continue;
439  }
440  if (command.instance_count == 0u) {
441  continue;
442  }
443 
444 #ifdef IMPELLER_DEBUG
445  fml::ScopedCleanupClosure auto_pop_debug_marker(pop_debug_marker);
446  if (!command.label.empty()) {
447  [encoder pushDebugGroup:@(command.label.c_str())];
448  } else {
449  auto_pop_debug_marker.Release();
450  }
451 #endif // IMPELLER_DEBUG
452 
453  const auto& pipeline_desc = command.pipeline->GetDescriptor();
454  if (target_sample_count != pipeline_desc.GetSampleCount()) {
455  VALIDATION_LOG << "Pipeline for command and the render target disagree "
456  "on sample counts (target was "
457  << static_cast<uint64_t>(target_sample_count)
458  << " but pipeline wanted "
459  << static_cast<uint64_t>(pipeline_desc.GetSampleCount())
460  << ").";
461  return false;
462  }
463 
464  pass_bindings.SetRenderPipelineState(
465  PipelineMTL::Cast(*command.pipeline).GetMTLRenderPipelineState());
466  pass_bindings.SetDepthStencilState(
467  PipelineMTL::Cast(*command.pipeline).GetMTLDepthStencilState());
468  pass_bindings.SetViewport(command.viewport.value_or<Viewport>(
469  {.rect = Rect::MakeSize(GetRenderTargetSize())}));
470  pass_bindings.SetScissor(
471  command.scissor.value_or(IRect::MakeSize(GetRenderTargetSize())));
472 
473  [encoder setFrontFacingWinding:pipeline_desc.GetWindingOrder() ==
474  WindingOrder::kClockwise
475  ? MTLWindingClockwise
476  : MTLWindingCounterClockwise];
477  [encoder setCullMode:ToMTLCullMode(pipeline_desc.GetCullMode())];
478  [encoder setTriangleFillMode:ToMTLTriangleFillMode(
479  pipeline_desc.GetPolygonMode())];
480  [encoder setStencilReferenceValue:command.stencil_reference];
481 
482  if (!bind_stage_resources(command.vertex_bindings, ShaderStage::kVertex)) {
483  return false;
484  }
485  if (!bind_stage_resources(command.fragment_bindings,
486  ShaderStage::kFragment)) {
487  return false;
488  }
489 
490  const PrimitiveType primitive_type = pipeline_desc.GetPrimitiveType();
491  if (command.index_type == IndexType::kNone) {
492  if (command.instance_count != 1u) {
493 #if TARGET_OS_SIMULATOR
494  VALIDATION_LOG << "iOS Simulator does not support instanced rendering.";
495  return false;
496 #else // TARGET_OS_SIMULATOR
497  [encoder drawPrimitives:ToMTLPrimitiveType(primitive_type)
498  vertexStart:command.base_vertex
499  vertexCount:command.vertex_count
500  instanceCount:command.instance_count
501  baseInstance:0u];
502 #endif // TARGET_OS_SIMULATOR
503  } else {
504  [encoder drawPrimitives:ToMTLPrimitiveType(primitive_type)
505  vertexStart:command.base_vertex
506  vertexCount:command.vertex_count];
507  }
508  continue;
509  }
510 
511  if (command.index_type == IndexType::kUnknown) {
512  return false;
513  }
514  auto index_buffer = command.index_buffer.buffer;
515  if (!index_buffer) {
516  return false;
517  }
518  auto device_buffer = index_buffer->GetDeviceBuffer(*allocator);
519  if (!device_buffer) {
520  return false;
521  }
522  auto mtl_index_buffer =
523  DeviceBufferMTL::Cast(*device_buffer).GetMTLBuffer();
524  if (!mtl_index_buffer) {
525  return false;
526  }
527 
528  FML_DCHECK(command.vertex_count *
529  (command.index_type == IndexType::k16bit ? 2 : 4) ==
530  command.index_buffer.range.length);
531 
532  if (command.instance_count != 1u) {
533 #if TARGET_OS_SIMULATOR
534  VALIDATION_LOG << "iOS Simulator does not support instanced rendering.";
535  return false;
536 #else // TARGET_OS_SIMULATOR
537  [encoder drawIndexedPrimitives:ToMTLPrimitiveType(primitive_type)
538  indexCount:command.vertex_count
539  indexType:ToMTLIndexType(command.index_type)
540  indexBuffer:mtl_index_buffer
541  indexBufferOffset:command.index_buffer.range.offset
542  instanceCount:command.instance_count
543  baseVertex:command.base_vertex
544  baseInstance:0u];
545 #endif // TARGET_OS_SIMULATOR
546  } else {
547  [encoder drawIndexedPrimitives:ToMTLPrimitiveType(primitive_type)
548  indexCount:command.vertex_count
549  indexType:ToMTLIndexType(command.index_type)
550  indexBuffer:mtl_index_buffer
551  indexBufferOffset:command.index_buffer.range.offset];
552  }
553  }
554  return true;
555 }
556 
557 } // namespace impeller
impeller::StoreAction::kMultisampleResolve
@ kMultisampleResolve
impeller::Texture::NeedsMipmapGeneration
bool NeedsMipmapGeneration() const
Definition: texture.cc:85
host_buffer.h
impeller::PrimitiveType
PrimitiveType
Definition: formats.h:328
impeller::TRect::size
TSize< Type > size
Definition: rect.h:24
impeller::StoreAction::kStoreAndMultisampleResolve
@ kStoreAndMultisampleResolve
impeller::ConfigureColorAttachment
static bool ConfigureColorAttachment(const ColorAttachment &desc, MTLRenderPassColorAttachmentDescriptor *attachment)
Definition: render_pass_mtl.mm:71
impeller::Attachment::store_action
StoreAction store_action
Definition: formats.h:594
impeller::TPoint::y
Type y
Definition: point.h:24
impeller::Viewport::rect
Rect rect
Definition: formats.h:353
impeller::ConfigureStencilAttachment
static bool ConfigureStencilAttachment(const StencilAttachment &desc, MTLRenderPassStencilAttachmentDescriptor *attachment)
Definition: render_pass_mtl.mm:91
impeller::PassBindingsCache::PassBindingsCache
PassBindingsCache(id< MTLRenderCommandEncoder > encoder)
Definition: render_pass_mtl.mm:195
impeller::Viewport::depth_range
DepthRange depth_range
Definition: formats.h:354
context_mtl.h
render_pass_mtl.h
impeller::DepthRange::z_far
Scalar z_far
Definition: formats.h:345
impeller::ColorAttachment
Definition: formats.h:599
impeller::Range::offset
size_t offset
Definition: range.h:14
impeller::DepthRange::z_near
Scalar z_near
Definition: formats.h:344
impeller::ConfigureAttachment
static bool ConfigureAttachment(const Attachment &desc, MTLRenderPassAttachmentDescriptor *attachment)
Definition: render_pass_mtl.mm:54
formats.h
impeller::TextureMTL::GetMTLTexture
id< MTLTexture > GetMTLTexture() const
Definition: texture_mtl.mm:100
formats_mtl.h
impeller::ShaderStage
ShaderStage
Definition: shader_types.h:20
impeller::ToMTLStoreAction
constexpr MTLStoreAction ToMTLStoreAction(StoreAction action)
Definition: formats_mtl.h:305
impeller::BufferView::range
Range range
Definition: buffer_view.h:16
impeller::RenderTarget::GetColorAttachments
const std::map< size_t, ColorAttachment > & GetColorAttachments() const
Definition: render_target.cc:209
impeller::Texture::IsValid
virtual bool IsValid() const =0
pipeline_mtl.h
impeller::ToMTLClearColor
MTLClearColor ToMTLClearColor(const Color &color)
Definition: formats_mtl.h:370
vertex_descriptor.h
impeller::PassBindingsCache::SetScissor
void SetScissor(const IRect &scissor)
Definition: render_pass_mtl.mm:323
impeller::PassBindingsCache::SetTexture
bool SetTexture(ShaderStage stage, uint64_t index, id< MTLTexture > texture)
Definition: render_pass_mtl.mm:262
impeller::StencilAttachment
Definition: formats.h:607
impeller::ConfigureDepthAttachment
static bool ConfigureDepthAttachment(const DepthAttachment &desc, MTLRenderPassDepthAttachmentDescriptor *attachment)
Definition: render_pass_mtl.mm:81
impeller::Texture
Definition: texture.h:17
impeller::Sampler
Definition: sampler.h:12
impeller::RenderTarget::GetDepthAttachment
const std::optional< DepthAttachment > & GetDepthAttachment() const
Definition: render_target.cc:214
impeller::ColorAttachment::clear_color
Color clear_color
Definition: formats.h:600
impeller::ToMTLLoadAction
constexpr MTLLoadAction ToMTLLoadAction(LoadAction action)
Definition: formats_mtl.h:277
impeller::ToMTLRenderPassDescriptor
static MTLRenderPassDescriptor * ToMTLRenderPassDescriptor(const RenderTarget &desc)
Definition: render_pass_mtl.mm:102
impeller::Attachment::texture
std::shared_ptr< Texture > texture
Definition: formats.h:591
impeller::ToMTLPrimitiveType
constexpr MTLPrimitiveType ToMTLPrimitiveType(PrimitiveType type)
Definition: formats_mtl.h:149
impeller::PassBindingsCache
Ensures that bindings on the pass are not redundantly set or updated. Avoids making the driver do add...
Definition: render_pass_mtl.mm:194
impeller::BufferView::buffer
std::shared_ptr< const Buffer > buffer
Definition: buffer_view.h:14
impeller::SamplerMap
std::unordered_map< SamplerDescriptor, std::shared_ptr< const Sampler >, ComparableHash< SamplerDescriptor >, ComparableEqual< SamplerDescriptor > > SamplerMap
Definition: sampler_descriptor.h:56
backend_cast.h
impeller::PassBindingsCache::SetDepthStencilState
void SetDepthStencilState(id< MTLDepthStencilState > depth_stencil)
Definition: render_pass_mtl.mm:210
impeller::Allocator
An object that allocates device memory.
Definition: allocator.h:25
impeller::TRect::origin
TPoint< Type > origin
Definition: rect.h:23
impeller::Attachment
Definition: formats.h:590
impeller::RenderTarget
Definition: render_target.h:48
impeller::StencilAttachment::clear_stencil
uint32_t clear_stencil
Definition: formats.h:608
impeller::ConfigureResolveTextureAttachment
static bool ConfigureResolveTextureAttachment(const Attachment &desc, MTLRenderPassAttachmentDescriptor *attachment)
Definition: render_pass_mtl.mm:25
impeller::TSize::width
Type width
Definition: size.h:21
impeller::TPoint::x
Type x
Definition: point.h:23
impeller::PassBindingsCache::SetSampler
bool SetSampler(ShaderStage stage, uint64_t index, id< MTLSamplerState > sampler)
Definition: render_pass_mtl.mm:284
impeller::Viewport
Definition: formats.h:352
VALIDATION_LOG
#define VALIDATION_LOG
Definition: validation.h:60
impeller::BufferView
Definition: buffer_view.h:13
impeller::Attachment::resolve_texture
std::shared_ptr< Texture > resolve_texture
Definition: formats.h:592
impeller::PassBindingsCache::SetViewport
void SetViewport(const Viewport &viewport)
Definition: render_pass_mtl.mm:308
std
Definition: comparable.h:98
impeller::Sampler::IsValid
virtual bool IsValid() const =0
texture_mtl.h
impeller::BackendCast< TextureMTL, Texture >::Cast
static TextureMTL & Cast(Texture &base)
Definition: backend_cast.h:14
impeller::Attachment::load_action
LoadAction load_action
Definition: formats.h:593
impeller::ToMTLIndexType
constexpr MTLIndexType ToMTLIndexType(IndexType type)
Definition: formats_mtl.h:175
impeller::DepthAttachment::clear_depth
double clear_depth
Definition: formats.h:604
impeller::TSize::height
Type height
Definition: size.h:22
sampler_mtl.h
impeller::PassBindingsCache::SetBuffer
bool SetBuffer(ShaderStage stage, uint64_t index, uint64_t offset, id< MTLBuffer > buffer)
Definition: render_pass_mtl.mm:218
impeller::DepthAttachment
Definition: formats.h:603
impeller::PassBindingsCache::SetRenderPipelineState
void SetRenderPipelineState(id< MTLRenderPipelineState > pipeline)
Definition: render_pass_mtl.mm:202
impeller::RenderTarget::GetStencilAttachment
const std::optional< StencilAttachment > & GetStencilAttachment() const
Definition: render_target.cc:218
shader_types.h
impeller::ToMTLCullMode
constexpr MTLCullMode ToMTLCullMode(CullMode mode)
Definition: formats_mtl.h:184
impeller
Definition: aiks_context.cc:10
impeller::ToMTLTriangleFillMode
constexpr MTLTriangleFillMode ToMTLTriangleFillMode(PolygonMode mode)
Definition: formats_mtl.h:165
impeller::TRect< int64_t >
device_buffer_mtl.h
impeller::Bind
static bool Bind(PassBindingsCache &pass, ShaderStage stage, size_t bind_index, const Sampler &sampler, const Texture &texture)
Definition: render_pass_mtl.mm:380