Flutter Impeller
impeller::SurfaceMTL Class Referencefinal

#include <surface_mtl.h>

Inheritance diagram for impeller::SurfaceMTL:
impeller::Surface

Public Member Functions

 ~SurfaceMTL () override
 
id< MTLDrawable > drawable () const
 
IRect coverage () const
 
void PresentWithTransaction (bool present_with_transaction)
 
bool PreparePresent () const
 Perform the final blit and trigger end of frame workloads. More...
 
bool Present () const override
 
void SetFrameBoundary (bool frame_boundary)
 
- Public Member Functions inherited from impeller::Surface
 Surface ()
 
 Surface (const RenderTarget &target_desc)
 
virtual ~Surface ()
 
const ISizeGetSize () const
 
bool IsValid () const
 
const RenderTargetGetRenderTarget () const
 

Static Public Member Functions

static id< CAMetalDrawable > GetMetalDrawableAndValidate (const std::shared_ptr< Context > &context, CAMetalLayer *layer)
 Wraps the current drawable of the given Metal layer to create a surface Impeller can render to. The surface must be created as late as possible and discarded immediately after rendering to it. More...
 
static std::unique_ptr< SurfaceMTLMakeFromMetalLayerDrawable (const std::shared_ptr< Context > &context, id< CAMetalDrawable > drawable, const std::shared_ptr< SwapchainTransientsMTL > &transients, std::optional< IRect > clip_rect=std::nullopt)
 
static std::unique_ptr< SurfaceMTLMakeFromTexture (const std::shared_ptr< Context > &context, id< MTLTexture > texture, const std::shared_ptr< SwapchainTransientsMTL > &transients, std::optional< IRect > clip_rect, id< CAMetalDrawable > drawable=nil)
 

Detailed Description

Definition at line 18 of file surface_mtl.h.

Constructor & Destructor Documentation

◆ ~SurfaceMTL()

impeller::SurfaceMTL::~SurfaceMTL ( )
overridedefault

Member Function Documentation

◆ coverage()

IRect impeller::SurfaceMTL::coverage ( ) const

Definition at line 212 of file surface_mtl.mm.

212  {
213  return IRect::MakeSize(resolve_texture_->GetSize());
214 }
constexpr static TRect MakeSize(const TSize< U > &size)
Definition: rect.h:150

References impeller::TRect< T >::MakeSize().

◆ drawable()

id<MTLDrawable> impeller::SurfaceMTL::drawable ( ) const
inline

Definition at line 59 of file surface_mtl.h.

59 { return drawable_; }

Referenced by MakeFromMetalLayerDrawable(), MakeFromTexture(), and Present().

◆ GetMetalDrawableAndValidate()

id< CAMetalDrawable > impeller::SurfaceMTL::GetMetalDrawableAndValidate ( const std::shared_ptr< Context > &  context,
CAMetalLayer *  layer 
)
static

Wraps the current drawable of the given Metal layer to create a surface Impeller can render to. The surface must be created as late as possible and discarded immediately after rendering to it.

Parameters
[in]contextThe context
[in]layerThe layer whose current drawable to wrap to create a surface.
Returns
A pointer to the wrapped surface or null.

Definition at line 29 of file surface_mtl.mm.

31  {
32  TRACE_EVENT0("impeller", "SurfaceMTL::WrapCurrentMetalLayerDrawable");
33 
34  if (context == nullptr || !context->IsValid() || layer == nil) {
35  return nullptr;
36  }
37 
38  id<CAMetalDrawable> current_drawable = nil;
39  {
40  TRACE_EVENT0("impeller", "WaitForNextDrawable");
41  current_drawable = [layer nextDrawable];
42  }
43 
44  if (!current_drawable) {
45  VALIDATION_LOG << "Could not acquire current drawable.";
46  return nullptr;
47  }
48  return current_drawable;
49 }
#define VALIDATION_LOG
Definition: validation.h:91

References VALIDATION_LOG.

◆ MakeFromMetalLayerDrawable()

std::unique_ptr< SurfaceMTL > impeller::SurfaceMTL::MakeFromMetalLayerDrawable ( const std::shared_ptr< Context > &  context,
id< CAMetalDrawable >  drawable,
const std::shared_ptr< SwapchainTransientsMTL > &  transients,
std::optional< IRect clip_rect = std::nullopt 
)
static

Definition at line 113 of file surface_mtl.mm.

117  {
118  return SurfaceMTL::MakeFromTexture(context, drawable.texture, transients,
119  clip_rect, drawable);
120 }
static std::unique_ptr< SurfaceMTL > MakeFromTexture(const std::shared_ptr< Context > &context, id< MTLTexture > texture, const std::shared_ptr< SwapchainTransientsMTL > &transients, std::optional< IRect > clip_rect, id< CAMetalDrawable > drawable=nil)
Definition: surface_mtl.mm:122
id< MTLDrawable > drawable() const
Definition: surface_mtl.h:59

References drawable(), and MakeFromTexture().

◆ MakeFromTexture()

std::unique_ptr< SurfaceMTL > impeller::SurfaceMTL::MakeFromTexture ( const std::shared_ptr< Context > &  context,
id< MTLTexture >  texture,
const std::shared_ptr< SwapchainTransientsMTL > &  transients,
std::optional< IRect clip_rect,
id< CAMetalDrawable >  drawable = nil 
)
static

Definition at line 122 of file surface_mtl.mm.

127  {
128  bool partial_repaint_blit_required = ShouldPerformPartialRepaint(clip_rect);
129 
130  // The returned render target is the texture that Impeller will render the
131  // root pass to. If partial repaint is in use, this may be a new texture which
132  // is smaller than the given MTLTexture.
133  auto render_target = WrapTextureWithRenderTarget(
134  transients, texture, partial_repaint_blit_required, clip_rect);
135  if (!render_target) {
136  return nullptr;
137  }
138 
139  // If partial repainting, set a "source" texture. The presence of a source
140  // texture and clip rect instructs the surface to blit this texture to the
141  // destination texture.
142  auto source_texture = partial_repaint_blit_required
143  ? render_target->GetRenderTargetTexture()
144  : nullptr;
145 
146  // The final "destination" texture is the texture that will be presented. In
147  // this case, it's always the given drawable.
148  std::shared_ptr<Texture> destination_texture;
149  if (partial_repaint_blit_required) {
150  // If blitting for partial repaint, we need to wrap the drawable. Simply
151  // reuse the texture descriptor that was already formed for the new render
152  // target, but override the size with the drawable's size.
153  auto destination_descriptor =
154  render_target->GetRenderTargetTexture()->GetTextureDescriptor();
155  destination_descriptor.size = {static_cast<ISize::Type>(texture.width),
156  static_cast<ISize::Type>(texture.height)};
157  destination_texture = TextureMTL::Wrapper(destination_descriptor, texture);
158  } else {
159  // When not partial repaint blit is needed, the render target texture _is_
160  // the drawable texture.
161  destination_texture = render_target->GetRenderTargetTexture();
162  }
163 
164  return std::unique_ptr<SurfaceMTL>(new SurfaceMTL(
165  context, // context
166  *render_target, // target
167  render_target->GetRenderTargetTexture(), // resolve_texture
168  drawable, // drawable
169  source_texture, // source_texture
170  destination_texture, // destination_texture
171  partial_repaint_blit_required, // requires_blit
172  clip_rect // clip_rect
173  ));
174 }
static std::shared_ptr< TextureMTL > Wrapper(TextureDescriptor desc, id< MTLTexture > texture, std::function< void()> deletion_proc=nullptr)
Definition: texture_mtl.mm:42
static std::optional< RenderTarget > WrapTextureWithRenderTarget(const std::shared_ptr< SwapchainTransientsMTL > &transients, id< MTLTexture > texture, bool requires_blit, std::optional< IRect > clip_rect)
Definition: surface_mtl.mm:51

References drawable(), impeller::TextureMTL::Wrapper(), and impeller::WrapTextureWithRenderTarget().

Referenced by MakeFromMetalLayerDrawable().

◆ PreparePresent()

bool impeller::SurfaceMTL::PreparePresent ( ) const

Perform the final blit and trigger end of frame workloads.

Definition at line 216 of file surface_mtl.mm.

216  {
217  auto context = context_.lock();
218  if (!context) {
219  return false;
220  }
221 
222 #ifdef IMPELLER_DEBUG
223  context->GetResourceAllocator()->DebugTraceMemoryStatistics();
224  if (frame_boundary_) {
225  ContextMTL::Cast(context.get())->GetCaptureManager()->FinishCapture();
226  }
227 #endif // IMPELLER_DEBUG
228 
229  if (requires_blit_) {
230  if (!(source_texture_ && destination_texture_)) {
231  return false;
232  }
233 
234  auto blit_command_buffer = context->CreateCommandBuffer();
235  if (!blit_command_buffer) {
236  return false;
237  }
238  auto blit_pass = blit_command_buffer->CreateBlitPass();
239  if (!clip_rect_.has_value()) {
240  VALIDATION_LOG << "Missing clip rectangle.";
241  return false;
242  }
243  blit_pass->AddCopy(source_texture_, destination_texture_, clip_rect_,
244  clip_rect_->GetOrigin());
245  blit_pass->EncodeCommands();
246  if (!context->GetCommandQueue()->Submit({blit_command_buffer}).ok()) {
247  return false;
248  }
249  }
250 #ifdef IMPELLER_DEBUG
251  ContextMTL::Cast(context.get())->GetGPUTracer()->MarkFrameEnd();
252 #endif // IMPELLER_DEBUG
253  prepared_ = true;
254  return true;
255 }
static ContextMTL & Cast(Context &base)
Definition: backend_cast.h:13
std::shared_ptr< CommandBuffer > CreateCommandBuffer() const override
Create a new command buffer. Command buffers can be used to encode graphics, blit,...
Definition: context_mtl.mm:325

References impeller::BackendCast< ContextMTL, Context >::Cast(), impeller::ContextMTL::CreateCommandBuffer(), and VALIDATION_LOG.

Referenced by Present().

◆ Present()

bool impeller::SurfaceMTL::Present ( ) const
overridevirtual

Reimplemented from impeller::Surface.

Definition at line 258 of file surface_mtl.mm.

258  {
259  if (!prepared_) {
260  PreparePresent();
261  }
262  auto context = context_.lock();
263  if (!context) {
264  return false;
265  }
266 
267  if (drawable_) {
268  id<MTLCommandBuffer> command_buffer =
269  ContextMTL::Cast(context.get())
270  ->CreateMTLCommandBuffer("Present Waiter Command Buffer");
271 
272  id<CAMetalDrawable> metal_drawable =
273  reinterpret_cast<id<CAMetalDrawable>>(drawable_);
274  if ([metal_drawable conformsToProtocol:@protocol(FlutterMetalDrawable)]) {
275  [(id<FlutterMetalDrawable>)metal_drawable
276  flutterPrepareForPresent:command_buffer];
277  }
278 
279  // Intel iOS simulators do not seem to give backpressure on Metal drawable
280  // aquisition, which can result in Impeller running head of the GPU
281  // workload by dozens of frames. Slow this process down by blocking
282  // on submit until the last command buffer is at least scheduled.
283 #if defined(FML_OS_IOS_SIMULATOR) && defined(FML_ARCH_CPU_X86_64)
284  constexpr bool alwaysWaitForScheduling = true;
285 #else
286  constexpr bool alwaysWaitForScheduling = false;
287 #endif // defined(FML_OS_IOS_SIMULATOR) && defined(FML_ARCH_CPU_X86_64)
288 
289  // If the threads have been merged, or there is a pending frame capture,
290  // then block on cmd buffer scheduling to ensure that the
291  // transaction/capture work correctly.
292  if (present_with_transaction_ || [[NSThread currentThread] isMainThread] ||
293  [[MTLCaptureManager sharedCaptureManager] isCapturing] ||
294  alwaysWaitForScheduling) {
295  TRACE_EVENT0("flutter", "waitUntilScheduled");
296  [command_buffer commit];
297 #if defined(FML_OS_IOS_SIMULATOR) && defined(FML_ARCH_CPU_X86_64)
298  [command_buffer waitUntilCompleted];
299 #else
300  [command_buffer waitUntilScheduled];
301 #endif // defined(FML_OS_IOS_SIMULATOR) && defined(FML_ARCH_CPU_X86_64)
302  [drawable_ present];
303  } else {
304  // The drawable may come from a FlutterMetalLayer, so it can't be
305  // presented through the command buffer.
306  id<CAMetalDrawable> drawable = drawable_;
307  [command_buffer addScheduledHandler:^(id<MTLCommandBuffer> buffer) {
308  [drawable present];
309  }];
310  [command_buffer commit];
311  }
312  }
313 
314  return true;
315 }
id< MTLCommandBuffer > CreateMTLCommandBuffer(const std::string &label) const
Definition: context_mtl.mm:380
bool PreparePresent() const
Perform the final blit and trigger end of frame workloads.
Definition: surface_mtl.mm:216

References impeller::BackendCast< ContextMTL, Context >::Cast(), impeller::ContextMTL::CreateMTLCommandBuffer(), drawable(), and PreparePresent().

◆ PresentWithTransaction()

void impeller::SurfaceMTL::PresentWithTransaction ( bool  present_with_transaction)
inline

Mark this surface as presenting with a transaction.

If true, [Present] will block on the scheduling of a command buffer.

Definition at line 67 of file surface_mtl.h.

67  {
68  present_with_transaction_ = present_with_transaction;
69  }

◆ SetFrameBoundary()

void impeller::SurfaceMTL::SetFrameBoundary ( bool  frame_boundary)
inline

Definition at line 77 of file surface_mtl.h.

77  {
78  frame_boundary_ = frame_boundary;
79  }

The documentation for this class was generated from the following files: