5#include "flutter/shell/gpu/gpu_surface_metal_impeller.h"
8#import <QuartzCore/QuartzCore.h>
10#include "flutter/common/settings.h"
11#include "flutter/fml/make_copyable.h"
12#include "flutter/fml/mapping.h"
13#include "flutter/fml/trace_event.h"
18static_assert(!
__has_feature(objc_arc),
"ARC must be disabled.");
20#define ENABLE_EXPERIMENTAL_CANVAS false
25 std::shared_ptr<impeller::Context> context) {
26 auto renderer = std::make_shared<impeller::Renderer>(std::move(context));
28 FML_LOG(
ERROR) <<
"Could not create valid Impeller Renderer.";
35 const std::shared_ptr<impeller::Context>& context,
36 bool render_to_surface)
38 render_target_type_(delegate->GetRenderTargetType()),
41 std::make_shared<
impeller::AiksContext>(impeller_renderer_ ? context : nullptr,
43 render_to_surface_(render_to_surface) {
45 NSNumber* disablePartialRepaint =
46 [[NSBundle mainBundle] objectForInfoDictionaryKey:
@"FLTDisablePartialRepaint"];
47 if (disablePartialRepaint != nil) {
48 disable_partial_repaint_ = disablePartialRepaint.boolValue;
56 return !!aiks_context_ && aiks_context_->IsValid();
60std::unique_ptr<SurfaceFrame> GPUSurfaceMetalImpeller::AcquireFrame(
const SkISize& frame_size) {
61 TRACE_EVENT0(
"impeller",
"GPUSurfaceMetalImpeller::AcquireFrame");
69 FML_LOG(
ERROR) <<
"Metal surface was asked for an empty frame.";
73 if (!render_to_surface_) {
74 return std::make_unique<SurfaceFrame>(
75 nullptr, SurfaceFrame::FramebufferInfo(),
76 [](
const SurfaceFrame& surface_frame,
DlCanvas* canvas) {
return true; }, frame_size);
79 switch (render_target_type_) {
81 return AcquireFrameFromCAMetalLayer(frame_size);
83 return AcquireFrameFromMTLTexture(frame_size);
85 FML_CHECK(
false) <<
"Unknown MTLRenderTargetType type.";
91std::unique_ptr<SurfaceFrame> GPUSurfaceMetalImpeller::AcquireFrameFromCAMetalLayer(
96 FML_LOG(
ERROR) <<
"Invalid CAMetalLayer given by the embedder.";
100 auto* mtl_layer = (CAMetalLayer*)layer;
103 impeller_renderer_->GetContext(), mtl_layer);
108 last_texture_.
reset([drawable.texture retain]);
111 id<MTLTexture> last_texture =
static_cast<id<MTLTexture>
>(last_texture_);
114 disable_partial_repaint = disable_partial_repaint_,
116 aiks_context = aiks_context_,
119 ](SurfaceFrame& surface_frame,
DlCanvas* canvas)
mutable ->
bool {
124 auto display_list = surface_frame.BuildDisplayList();
126 FML_LOG(
ERROR) <<
"Could not build display list for surface frame.";
130 if (!disable_partial_repaint && damage) {
131 uintptr_t
texture =
reinterpret_cast<uintptr_t
>(last_texture);
133 for (
auto& entry : *damage) {
136 if (surface_frame.submit_info().frame_damage) {
137 entry.second.join(*surface_frame.submit_info().frame_damage);
145 std::optional<impeller::IRect> clip_rect;
146 if (surface_frame.submit_info().buffer_damage.has_value()) {
147 auto buffer_damage = surface_frame.submit_info().buffer_damage;
149 buffer_damage->width(), buffer_damage->height());
153 drawable, clip_rect);
161 if (clip_rect && clip_rect->IsEmpty()) {
168#if ENABLE_EXPERIMENTAL_CANVAS
171 display_list->Dispatch(collector, sk_cull_rect);
177 aiks_context->GetContentContext(), render_target,
178 display_list->root_has_backdrop_filter(), display_list->max_root_blend_mode(),
180 display_list->Dispatch(impeller_dispatcher, sk_cull_rect);
181 impeller_dispatcher.FinishRecording();
182 aiks_context->GetContentContext().GetTransientsBuffer().Reset();
183 aiks_context->GetContentContext().GetLazyGlyphAtlas()->ResetTextFrames();
188 display_list->Dispatch(impeller_dispatcher, sk_cull_rect);
189 auto picture = impeller_dispatcher.EndRecordingAsPicture();
195 return aiks_context->Render(
picture, render_target,
true);
200 SurfaceFrame::FramebufferInfo framebuffer_info;
201 framebuffer_info.supports_readback =
true;
203 if (!disable_partial_repaint_) {
206 uintptr_t
texture =
reinterpret_cast<uintptr_t
>(drawable.texture);
208 if (
i != damage_->end()) {
209 framebuffer_info.existing_damage =
i->second;
211 framebuffer_info.supports_partial_repaint =
true;
214 return std::make_unique<SurfaceFrame>(
nullptr,
223std::unique_ptr<SurfaceFrame> GPUSurfaceMetalImpeller::AcquireFrameFromMTLTexture(
225 GPUMTLTextureInfo texture_info = delegate_->
GetMTLTexture(frame_size);
226 id<MTLTexture> mtl_texture = (id<MTLTexture>)(texture_info.texture);
229 FML_LOG(
ERROR) <<
"Invalid MTLTexture given by the embedder.";
234 last_texture_.
reset([mtl_texture retain]);
241 aiks_context = aiks_context_,
245 ](SurfaceFrame& surface_frame,
DlCanvas* canvas)
mutable ->
bool {
250 auto display_list = surface_frame.BuildDisplayList();
252 FML_LOG(
ERROR) <<
"Could not build display list for surface frame.";
256 if (!disable_partial_repaint && damage) {
257 uintptr_t texture_ptr =
reinterpret_cast<uintptr_t
>(mtl_texture);
259 for (
auto& entry : *damage) {
260 if (entry.first != texture_ptr) {
262 if (surface_frame.submit_info().frame_damage) {
263 entry.second.join(*surface_frame.submit_info().frame_damage);
271 std::optional<impeller::IRect> clip_rect;
272 if (surface_frame.submit_info().buffer_damage.has_value()) {
273 auto buffer_damage = surface_frame.submit_info().buffer_damage;
275 buffer_damage->width(), buffer_damage->height());
281 if (clip_rect && clip_rect->IsEmpty()) {
287#if ENABLE_EXPERIMENTAL_CANVAS
290 display_list->Dispatch(collector, sk_cull_rect);
291 bool render_result =
renderer->Render(
296 aiks_context->GetContentContext(), render_target, cull_rect);
297 display_list->Dispatch(impeller_dispatcher, sk_cull_rect);
298 impeller_dispatcher.FinishRecording();
299 aiks_context->GetContentContext().GetTransientsBuffer().Reset();
300 aiks_context->GetContentContext().GetLazyGlyphAtlas()->ResetTextFrames();
305 display_list->Dispatch(impeller_dispatcher, sk_cull_rect);
306 auto picture = impeller_dispatcher.EndRecordingAsPicture();
308 bool render_result =
renderer->Render(
312 return aiks_context->Render(
picture, render_target,
true);
315 if (!render_result) {
320 return delegate->PresentTexture(texture_info);
323 SurfaceFrame::FramebufferInfo framebuffer_info;
324 framebuffer_info.supports_readback =
true;
326 if (!disable_partial_repaint_) {
329 uintptr_t
texture =
reinterpret_cast<uintptr_t
>(mtl_texture);
331 if (
i != damage_->end()) {
332 framebuffer_info.existing_damage =
i->second;
334 framebuffer_info.supports_partial_repaint =
true;
337 return std::make_unique<SurfaceFrame>(
nullptr,
347SkMatrix GPUSurfaceMetalImpeller::GetRootTransformation()
const {
359std::unique_ptr<GLContextResult> GPUSurfaceMetalImpeller::MakeRenderContextCurrent() {
361 return std::make_unique<GLContextDefaultResult>(
true);
364bool GPUSurfaceMetalImpeller::AllowsDrawingWhenGpuDisabled()
const {
369bool GPUSurfaceMetalImpeller::EnableRasterCache()
const {
374std::shared_ptr<impeller::AiksContext> GPUSurfaceMetalImpeller::GetAiksContext()
const {
375 return aiks_context_;
379 if (!(last_texture_ && [last_texture_ conformsToProtocol:
@protocol(MTLTexture)])) {
383 int bytesPerPixel = 0;
384 std::string pixel_format;
386 case MTLPixelFormatBGR10_XR:
388 pixel_format =
"MTLPixelFormatBGR10_XR";
390 case MTLPixelFormatBGRA10_XR:
392 pixel_format =
"MTLPixelFormatBGRA10_XR";
394 case MTLPixelFormatBGRA8Unorm:
396 pixel_format =
"MTLPixelFormatBGRA8Unorm";
398 case MTLPixelFormatRGBA16Float:
400 pixel_format =
"MTLPixelFormatRGBA16Float";
411 bytesPerRow:
texture.width * bytesPerPixel
415 .pixel_format = pixel_format,
static sk_sp< SkData > MakeZeroInitialized(size_t length)
std::function< bool(SurfaceFrame &surface_frame, DlCanvas *canvas)> SubmitCallback
T get() const __attribute((ns_returns_not_retained))
void reset(NST object=Traits::InvalidValue(), scoped_policy::OwnershipPolicy policy=scoped_policy::OwnershipPolicy::kAssume)
static std::unique_ptr< SurfaceMTL > MakeFromTexture(const std::shared_ptr< Context > &context, id< MTLTexture > texture, std::optional< IRect > clip_rect, id< CAMetalDrawable > drawable=nil)
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 > MakeFromMetalLayerDrawable(const std::shared_ptr< Context > &context, id< CAMetalDrawable > drawable, std::optional< IRect > clip_rect=std::nullopt)
Performs a first pass over the display list to collect all text frames.
#define FML_LOG(severity)
#define FML_CHECK(condition)
SK_API sk_sp< SkDocument > Make(SkWStream *dst, const SkSerialProcs *=nullptr, std::function< void(const SkPicture *)> onEndPage=nullptr)
sk_sp< const SkPicture > picture
static std::shared_ptr< impeller::Renderer > CreateImpellerRenderer(std::shared_ptr< impeller::Context > context)
internal::CopyableLambda< T > MakeCopyable(T lambda)
flutter::DlCanvas DlCanvas
static constexpr SkIRect MakeEmpty()
static constexpr SkIRect MakeWH(int32_t w, int32_t h)
static constexpr bool kSurfaceDataAccessible
A screenshot of the surface's raw data.
A 4x4 matrix using column-major storage.
constexpr Type GetHeight() const
Returns the height of the rectangle, equivalent to |GetSize().height|.
static constexpr TRect MakeXYWH(Type x, Type y, Type width, Type height)
constexpr Type GetWidth() const
Returns the width of the rectangle, equivalent to |GetSize().width|.
#define TRACE_EVENT0(category_group, name)