8#import <QuartzCore/QuartzCore.h>
22static_assert(__has_feature(objc_arc),
"ARC must be enabled.");
28 const std::shared_ptr<impeller::AiksContext>& context,
29 bool render_to_surface)
31 render_target_type_(delegate->GetRenderTargetType()),
32 aiks_context_(context),
33 render_to_surface_(render_to_surface) {
35 NSNumber* disablePartialRepaint =
36 [[NSBundle mainBundle] objectForInfoDictionaryKey:
@"FLTDisablePartialRepaint"];
37 if (disablePartialRepaint != nil) {
38 disable_partial_repaint_ = disablePartialRepaint.boolValue;
41 swapchain_transients_ = std::make_shared<impeller::SwapchainTransientsMTL>(
42 aiks_context_->GetContext()->GetResourceAllocator());
50 return !!aiks_context_ && aiks_context_->IsValid();
54std::unique_ptr<SurfaceFrame> GPUSurfaceMetalImpeller::AcquireFrame(
const DlISize& frame_size) {
55 TRACE_EVENT0(
"impeller",
"GPUSurfaceMetalImpeller::AcquireFrame");
58 FML_LOG(ERROR) <<
"Metal surface was invalid.";
63 FML_LOG(ERROR) <<
"Metal surface was asked for an empty frame.";
67 if (!render_to_surface_) {
71 return std::make_unique<SurfaceFrame>(
72 nullptr, SurfaceFrame::FramebufferInfo(),
73 [](
const SurfaceFrame& surface_frame, DlCanvas* canvas) {
return true; },
75 [context = aiks_context_->GetContext()](
const SurfaceFrame& surface_frame) {
80 [](
const SurfaceFrame& surface_frame) {
return true; },
85 switch (render_target_type_) {
87 return AcquireFrameFromCAMetalLayer(frame_size);
89 return AcquireFrameFromMTLTexture(frame_size);
91 FML_CHECK(
false) <<
"Unknown MTLRenderTargetType type.";
97std::unique_ptr<SurfaceFrame> GPUSurfaceMetalImpeller::AcquireFrameFromCAMetalLayer(
99 CAMetalLayer* layer = (__bridge CAMetalLayer*)delegate_->
GetCAMetalLayer(frame_size);
101 FML_LOG(ERROR) <<
"Invalid CAMetalLayer given by the embedder.";
105 id<CAMetalDrawable> drawable =
111 last_texture_ = drawable.texture;
118 __weak id<MTLTexture> weak_last_texture = last_texture_;
119 __weak CAMetalLayer* weak_layer = layer;
122 disable_partial_repaint = disable_partial_repaint_,
123 aiks_context = aiks_context_,
127 swapchain_transients = swapchain_transients_
128 ](SurfaceFrame& surface_frame, DlCanvas* canvas)
mutable ->
bool {
129 id<MTLTexture> strong_last_texture = weak_last_texture;
130 CAMetalLayer* strong_layer = weak_layer;
131 if (!strong_last_texture || !strong_layer) {
134 strong_layer.presentsWithTransaction = surface_frame.submit_info().present_with_transaction;
139 auto display_list = surface_frame.BuildDisplayList();
141 FML_LOG(ERROR) <<
"Could not build display list for surface frame.";
145 if (!disable_partial_repaint && damage) {
146 void*
texture = (__bridge
void*)strong_last_texture;
147 for (
auto& entry : *damage) {
150 if (surface_frame.submit_info().frame_damage) {
151 entry.second = entry.second.Union(*surface_frame.submit_info().frame_damage);
159 std::optional<impeller::IRect> clip_rect;
160 if (surface_frame.submit_info().buffer_damage.has_value()) {
161 auto buffer_damage = surface_frame.submit_info().buffer_damage;
164 buffer_damage->GetRight(), buffer_damage->GetBottom());
168 aiks_context->GetContext(), drawable, swapchain_transients, clip_rect);
175 surface->PresentWithTransaction(surface_frame.submit_info().present_with_transaction);
177 if (clip_rect && clip_rect->IsEmpty()) {
178 if (!
surface->PreparePresent()) {
181 surface_frame.set_user_data(std::move(surface));
186 surface->SetFrameBoundary(surface_frame.submit_info().frame_boundary);
188 const bool reset_host_buffer = surface_frame.submit_info().frame_boundary;
195 if (!render_result) {
199 if (!
surface->PreparePresent()) {
202 surface_frame.set_user_data(std::move(surface));
206 SurfaceFrame::FramebufferInfo framebuffer_info;
207 framebuffer_info.supports_readback =
true;
209 if (!disable_partial_repaint_) {
212 void*
texture = (__bridge
void*)drawable.texture;
214 if (
i != damage_->end()) {
215 framebuffer_info.existing_damage =
i->second;
217 framebuffer_info.supports_partial_repaint =
true;
220 return std::make_unique<SurfaceFrame>(
224 [](SurfaceFrame& surface_frame) {
return surface_frame.take_user_data()->Present(); },
231std::unique_ptr<SurfaceFrame> GPUSurfaceMetalImpeller::AcquireFrameFromMTLTexture(
233 GPUMTLTextureInfo texture_info = delegate_->
GetMTLTexture(frame_size);
234 id<MTLTexture> mtl_texture = (__bridge id<MTLTexture>)texture_info.
texture;
236 FML_LOG(ERROR) <<
"Invalid MTLTexture given by the embedder.";
241 last_texture_ = mtl_texture;
248 __weak id<MTLTexture> weak_texture = mtl_texture;
252 aiks_context = aiks_context_,
254 swapchain_transients = swapchain_transients_
255 ](SurfaceFrame& surface_frame, DlCanvas* canvas)
mutable ->
bool {
256 id<MTLTexture> strong_texture = weak_texture;
257 if (!strong_texture) {
263 auto display_list = surface_frame.BuildDisplayList();
265 FML_LOG(ERROR) <<
"Could not build display list for surface frame.";
269 if (!disable_partial_repaint && damage) {
270 void* texture_ptr = (__bridge
void*)strong_texture;
271 for (
auto& entry : *damage) {
272 if (entry.first != texture_ptr) {
274 if (surface_frame.submit_info().frame_damage) {
275 entry.second = entry.second.Union(*surface_frame.submit_info().frame_damage);
280 (*damage)[texture_ptr] =
DlIRect();
283 std::optional<impeller::IRect> clip_rect;
284 if (surface_frame.submit_info().buffer_damage.has_value()) {
285 auto buffer_damage = surface_frame.submit_info().buffer_damage;
288 buffer_damage->GetRight(), buffer_damage->GetBottom());
292 aiks_context->GetContext(), strong_texture, swapchain_transients, clip_rect);
294 surface->PresentWithTransaction(surface_frame.submit_info().present_with_transaction);
296 if (clip_rect && clip_rect->IsEmpty()) {
297 if (!
surface->PreparePresent()) {
310 if (!render_result) {
311 FML_LOG(ERROR) <<
"Failed to render Impeller frame";
314 if (!
surface->PreparePresent()) {
317 return surface->PreparePresent();
321 [texture_info, delegate = delegate_](
const SurfaceFrame& surface_frame) {
322 return delegate->PresentTexture(texture_info);
325 SurfaceFrame::FramebufferInfo framebuffer_info;
326 framebuffer_info.supports_readback =
true;
328 if (!disable_partial_repaint_) {
331 void*
texture = (__bridge
void*)mtl_texture;
333 if (
i != damage_->end()) {
334 framebuffer_info.existing_damage =
i->second;
336 framebuffer_info.supports_partial_repaint =
true;
339 return std::make_unique<SurfaceFrame>(
nullptr,
350DlMatrix GPUSurfaceMetalImpeller::GetRootTransformation()
const {
357GrDirectContext* GPUSurfaceMetalImpeller::GetContext() {
362std::unique_ptr<GLContextResult> GPUSurfaceMetalImpeller::MakeRenderContextCurrent() {
364 return std::make_unique<GLContextDefaultResult>(
true);
367bool GPUSurfaceMetalImpeller::AllowsDrawingWhenGpuDisabled()
const {
372bool GPUSurfaceMetalImpeller::EnableRasterCache()
const {
377std::shared_ptr<impeller::AiksContext> GPUSurfaceMetalImpeller::GetAiksContext()
const {
378 return aiks_context_;
382 if (!(last_texture_ && [last_texture_ conformsToProtocol:
@protocol(MTLTexture)])) {
385 id<MTLTexture>
texture = last_texture_;
386 int bytesPerPixel = 0;
387 std::string pixel_format;
389 case MTLPixelFormatBGR10_XR:
391 pixel_format =
"MTLPixelFormatBGR10_XR";
393 case MTLPixelFormatBGRA10_XR:
395 pixel_format =
"MTLPixelFormatBGRA10_XR";
397 case MTLPixelFormatBGRA8Unorm:
399 pixel_format =
"MTLPixelFormatBGRA8Unorm";
401 case MTLPixelFormatRGBA16Float:
403 pixel_format =
"MTLPixelFormatRGBA16Float";
411 sk_sp<SkData> result =
412 SkData::MakeZeroInitialized(
texture.width *
texture.height * bytesPerPixel);
413 [
texture getBytes:result->writable_data()
414 bytesPerRow:
texture.width * bytesPerPixel
418 .pixel_format = pixel_format,
std::function< bool(SurfaceFrame &surface_frame, DlCanvas *canvas)> EncodeCallback
std::function< bool(SurfaceFrame &surface_frame)> SubmitCallback
static ContextMTL & Cast(Context &base)
static std::unique_ptr< 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 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....
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)
#define FML_LOG(severity)
#define FML_CHECK(condition)
impeller::Matrix DlMatrix
impeller::ISize32 DlISize
impeller::IRect32 DlIRect
internal::CopyableLambda< T > MakeCopyable(T lambda)
bool RenderToTarget(ContentContext &context, RenderTarget render_target, const sk_sp< flutter::DisplayList > &display_list, Rect cull_rect, bool reset_host_buffer, bool is_onscreen)
Render the provided display list to the render target.
GPUMTLTextureHandle texture
static constexpr bool kSurfaceDataAccessible
A screenshot of the surface's raw data.
static constexpr std::enable_if_t< std::is_floating_point_v< FT >, TRect > Make(const TRect< U > &rect)
static constexpr TRect MakeLTRB(Type left, Type top, Type right, Type bottom)
constexpr bool IsEmpty() const
Returns true if either of the width or height are 0, negative, or NaN.
#define TRACE_EVENT0(category_group, name)