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_) {
68 return std::make_unique<SurfaceFrame>(
69 nullptr, SurfaceFrame::FramebufferInfo(),
70 [](
const SurfaceFrame& surface_frame, DlCanvas* canvas) {
return true; },
71 [](
const SurfaceFrame& surface_frame) {
return true; }, frame_size);
74 switch (render_target_type_) {
76 return AcquireFrameFromCAMetalLayer(frame_size);
78 return AcquireFrameFromMTLTexture(frame_size);
80 FML_CHECK(
false) <<
"Unknown MTLRenderTargetType type.";
86std::unique_ptr<SurfaceFrame> GPUSurfaceMetalImpeller::AcquireFrameFromCAMetalLayer(
88 CAMetalLayer* layer = (__bridge CAMetalLayer*)delegate_->
GetCAMetalLayer(frame_size);
90 FML_LOG(ERROR) <<
"Invalid CAMetalLayer given by the embedder.";
94 id<CAMetalDrawable> drawable =
100 last_texture_ = drawable.texture;
107 __weak id<MTLTexture> weak_last_texture = last_texture_;
108 __weak CAMetalLayer* weak_layer = layer;
111 disable_partial_repaint = disable_partial_repaint_,
112 aiks_context = aiks_context_,
116 swapchain_transients = swapchain_transients_
117 ](SurfaceFrame& surface_frame, DlCanvas* canvas)
mutable ->
bool {
118 id<MTLTexture> strong_last_texture = weak_last_texture;
119 CAMetalLayer* strong_layer = weak_layer;
120 if (!strong_last_texture || !strong_layer) {
123 strong_layer.presentsWithTransaction = surface_frame.submit_info().present_with_transaction;
128 auto display_list = surface_frame.BuildDisplayList();
130 FML_LOG(ERROR) <<
"Could not build display list for surface frame.";
134 if (!disable_partial_repaint && damage) {
135 void*
texture = (__bridge
void*)strong_last_texture;
136 for (
auto& entry : *damage) {
139 if (surface_frame.submit_info().frame_damage) {
140 entry.second = entry.second.Union(*surface_frame.submit_info().frame_damage);
148 std::optional<impeller::IRect> clip_rect;
149 if (surface_frame.submit_info().buffer_damage.has_value()) {
150 auto buffer_damage = surface_frame.submit_info().buffer_damage;
153 buffer_damage->GetRight(), buffer_damage->GetBottom());
157 aiks_context->GetContext(), drawable, swapchain_transients, clip_rect);
164 surface->PresentWithTransaction(surface_frame.submit_info().present_with_transaction);
166 if (clip_rect && clip_rect->IsEmpty()) {
167 if (!
surface->PreparePresent()) {
170 surface_frame.set_user_data(std::move(surface));
175 surface->SetFrameBoundary(surface_frame.submit_info().frame_boundary);
177 const bool reset_host_buffer = surface_frame.submit_info().frame_boundary;
184 if (!render_result) {
188 if (!
surface->PreparePresent()) {
191 surface_frame.set_user_data(std::move(surface));
195 SurfaceFrame::FramebufferInfo framebuffer_info;
196 framebuffer_info.supports_readback =
true;
198 if (!disable_partial_repaint_) {
201 void*
texture = (__bridge
void*)drawable.texture;
203 if (
i != damage_->end()) {
204 framebuffer_info.existing_damage =
i->second;
206 framebuffer_info.supports_partial_repaint =
true;
209 return std::make_unique<SurfaceFrame>(
213 [](SurfaceFrame& surface_frame) {
return surface_frame.take_user_data()->Present(); },
220std::unique_ptr<SurfaceFrame> GPUSurfaceMetalImpeller::AcquireFrameFromMTLTexture(
222 GPUMTLTextureInfo texture_info = delegate_->
GetMTLTexture(frame_size);
223 id<MTLTexture> mtl_texture = (__bridge id<MTLTexture>)texture_info.
texture;
225 FML_LOG(ERROR) <<
"Invalid MTLTexture given by the embedder.";
230 last_texture_ = mtl_texture;
237 __weak id<MTLTexture> weak_texture = mtl_texture;
241 aiks_context = aiks_context_,
243 swapchain_transients = swapchain_transients_
244 ](SurfaceFrame& surface_frame, DlCanvas* canvas)
mutable ->
bool {
245 id<MTLTexture> strong_texture = weak_texture;
246 if (!strong_texture) {
252 auto display_list = surface_frame.BuildDisplayList();
254 FML_LOG(ERROR) <<
"Could not build display list for surface frame.";
258 if (!disable_partial_repaint && damage) {
259 void* texture_ptr = (__bridge
void*)strong_texture;
260 for (
auto& entry : *damage) {
261 if (entry.first != texture_ptr) {
263 if (surface_frame.submit_info().frame_damage) {
264 entry.second = entry.second.Union(*surface_frame.submit_info().frame_damage);
269 (*damage)[texture_ptr] =
DlIRect();
272 std::optional<impeller::IRect> clip_rect;
273 if (surface_frame.submit_info().buffer_damage.has_value()) {
274 auto buffer_damage = surface_frame.submit_info().buffer_damage;
277 buffer_damage->GetRight(), buffer_damage->GetBottom());
281 aiks_context->GetContext(), strong_texture, swapchain_transients, clip_rect);
283 surface->PresentWithTransaction(surface_frame.submit_info().present_with_transaction);
285 if (clip_rect && clip_rect->IsEmpty()) {
286 if (!
surface->PreparePresent()) {
299 if (!render_result) {
300 FML_LOG(ERROR) <<
"Failed to render Impeller frame";
303 if (!
surface->PreparePresent()) {
306 return surface->PreparePresent();
310 [texture_info, delegate = delegate_](
const SurfaceFrame& surface_frame) {
311 return delegate->PresentTexture(texture_info);
314 SurfaceFrame::FramebufferInfo framebuffer_info;
315 framebuffer_info.supports_readback =
true;
317 if (!disable_partial_repaint_) {
320 void*
texture = (__bridge
void*)mtl_texture;
322 if (
i != damage_->end()) {
323 framebuffer_info.existing_damage =
i->second;
325 framebuffer_info.supports_partial_repaint =
true;
328 return std::make_unique<SurfaceFrame>(
nullptr,
339DlMatrix GPUSurfaceMetalImpeller::GetRootTransformation()
const {
346GrDirectContext* GPUSurfaceMetalImpeller::GetContext() {
351std::unique_ptr<GLContextResult> GPUSurfaceMetalImpeller::MakeRenderContextCurrent() {
353 return std::make_unique<GLContextDefaultResult>(
true);
356bool GPUSurfaceMetalImpeller::AllowsDrawingWhenGpuDisabled()
const {
361bool GPUSurfaceMetalImpeller::EnableRasterCache()
const {
366std::shared_ptr<impeller::AiksContext> GPUSurfaceMetalImpeller::GetAiksContext()
const {
367 return aiks_context_;
371 if (!(last_texture_ && [last_texture_ conformsToProtocol:
@protocol(MTLTexture)])) {
374 id<MTLTexture>
texture = last_texture_;
375 int bytesPerPixel = 0;
376 std::string pixel_format;
378 case MTLPixelFormatBGR10_XR:
380 pixel_format =
"MTLPixelFormatBGR10_XR";
382 case MTLPixelFormatBGRA10_XR:
384 pixel_format =
"MTLPixelFormatBGRA10_XR";
386 case MTLPixelFormatBGRA8Unorm:
388 pixel_format =
"MTLPixelFormatBGRA8Unorm";
390 case MTLPixelFormatRGBA16Float:
392 pixel_format =
"MTLPixelFormatRGBA16Float";
400 sk_sp<SkData> result =
401 SkData::MakeZeroInitialized(
texture.width *
texture.height * bytesPerPixel);
402 [
texture getBytes:result->writable_data()
403 bytesPerRow:
texture.width * bytesPerPixel
407 .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)