Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
gpu_surface_metal_skia.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
5#include "flutter/shell/gpu/gpu_surface_metal_skia.h"
6
7#import <Metal/Metal.h>
8#import <QuartzCore/QuartzCore.h>
9
10#include <utility>
11
12#include "flutter/common/graphics/persistent_cache.h"
13#include "flutter/fml/make_copyable.h"
14#include "flutter/fml/platform/darwin/cf_utils.h"
15#include "flutter/fml/platform/darwin/scoped_nsobject.h"
16#include "flutter/fml/trace_event.h"
17#include "flutter/shell/gpu/gpu_surface_metal_delegate.h"
33
34static_assert(!__has_feature(objc_arc), "ARC must be disabled.");
35
36namespace flutter {
37
38namespace {
39sk_sp<SkSurface> CreateSurfaceFromMetalTexture(GrDirectContext* context,
40 id<MTLTexture> texture,
41 GrSurfaceOrigin origin,
42 MsaaSampleCount sample_cnt,
44 sk_sp<SkColorSpace> color_space,
45 const SkSurfaceProps* props,
47 SkSurface::ReleaseContext release_context) {
48 GrMtlTextureInfo info;
49 info.fTexture.reset([texture retain]);
50 GrBackendTexture backend_texture =
51 GrBackendTextures::MakeMtl(texture.width, texture.height, skgpu::Mipmapped::kNo, info);
53 context, backend_texture, origin, static_cast<int>(sample_cnt), color_type,
54 std::move(color_space), props, release_proc, release_context);
55}
56} // namespace
57
60 MsaaSampleCount msaa_samples,
61 bool render_to_surface)
62 : delegate_(delegate),
63 render_target_type_(delegate->GetRenderTargetType()),
64 context_(std::move(context)),
65 msaa_samples_(msaa_samples),
66 render_to_surface_(render_to_surface) {
67 // If this preference is explicitly set, we allow for disabling partial repaint.
68 NSNumber* disablePartialRepaint =
69 [[NSBundle mainBundle] objectForInfoDictionaryKey:@"FLTDisablePartialRepaint"];
70 if (disablePartialRepaint != nil) {
71 disable_partial_repaint_ = disablePartialRepaint.boolValue;
72 }
73}
74
76
77// |Surface|
79 return context_ != nullptr;
80}
81
82void GPUSurfaceMetalSkia::PrecompileKnownSkSLsIfNecessary() {
83 auto* current_context = GetContext();
84 if (current_context == precompiled_sksl_context_) {
85 // Known SkSLs have already been prepared in this context.
86 return;
87 }
88 precompiled_sksl_context_ = current_context;
90}
91
92// |Surface|
93std::unique_ptr<SurfaceFrame> GPUSurfaceMetalSkia::AcquireFrame(const SkISize& frame_size) {
94 if (!IsValid()) {
95 FML_LOG(ERROR) << "Metal surface was invalid.";
96 return nullptr;
97 }
98
99 if (frame_size.isEmpty()) {
100 FML_LOG(ERROR) << "Metal surface was asked for an empty frame.";
101 return nullptr;
102 }
103
104 if (!render_to_surface_) {
105 return std::make_unique<SurfaceFrame>(
107 [](const SurfaceFrame& surface_frame, DlCanvas* canvas) { return true; }, frame_size);
108 }
109
110 PrecompileKnownSkSLsIfNecessary();
111
112 switch (render_target_type_) {
114 return AcquireFrameFromCAMetalLayer(frame_size);
116 return AcquireFrameFromMTLTexture(frame_size);
117 default:
118 FML_CHECK(false) << "Unknown MTLRenderTargetType type.";
119 }
120
121 return nullptr;
122}
123
124std::unique_ptr<SurfaceFrame> GPUSurfaceMetalSkia::AcquireFrameFromCAMetalLayer(
125 const SkISize& frame_info) {
126 auto layer = delegate_->GetCAMetalLayer(frame_info);
127 if (!layer) {
128 FML_LOG(ERROR) << "Invalid CAMetalLayer given by the embedder.";
129 return nullptr;
130 }
131
132 auto* mtl_layer = (CAMetalLayer*)layer;
133 // Get the drawable eagerly, we will need texture object to identify target framebuffer
135 reinterpret_cast<id<CAMetalDrawable>>([[mtl_layer nextDrawable] retain]));
136
137 if (!drawable.get()) {
138 FML_LOG(ERROR) << "Could not obtain drawable from the metal layer.";
139 return nullptr;
140 }
141
142 auto surface = CreateSurfaceFromMetalTexture(context_.get(), drawable.get().texture,
143 kTopLeft_GrSurfaceOrigin, // origin
144 msaa_samples_, // sample count
145 kBGRA_8888_SkColorType, // color type
146 nullptr, // colorspace
147 nullptr, // surface properties
148 nullptr, // release proc
149 nullptr // release context
150 );
151
152 if (!surface) {
153 FML_LOG(ERROR) << "Could not create the SkSurface from the CAMetalLayer.";
154 return nullptr;
155 }
156
157 auto submit_callback = [this, drawable](const SurfaceFrame& surface_frame,
158 DlCanvas* canvas) -> bool {
159 TRACE_EVENT0("flutter", "GPUSurfaceMetal::Submit");
160 if (canvas == nullptr) {
161 FML_DLOG(ERROR) << "Canvas not available.";
162 return false;
163 }
164
165 {
166 TRACE_EVENT0("flutter", "SkCanvas::Flush");
167 canvas->Flush();
168 }
169
170 if (!disable_partial_repaint_) {
171 uintptr_t texture = reinterpret_cast<uintptr_t>(drawable.get().texture);
172 for (auto& entry : damage_) {
173 if (entry.first != texture) {
174 // Accumulate damage for other framebuffers
175 if (surface_frame.submit_info().frame_damage) {
176 entry.second.join(*surface_frame.submit_info().frame_damage);
177 }
178 }
179 }
180 // Reset accumulated damage for current framebuffer
181 damage_[texture] = SkIRect::MakeEmpty();
182 }
183
184 return delegate_->PresentDrawable(drawable);
185 };
186
187 SurfaceFrame::FramebufferInfo framebuffer_info;
188 framebuffer_info.supports_readback = true;
189
190 if (!disable_partial_repaint_) {
191 // Provide accumulated damage to rasterizer (area in current framebuffer that lags behind
192 // front buffer)
193 uintptr_t texture = reinterpret_cast<uintptr_t>(drawable.get().texture);
194 auto i = damage_.find(texture);
195 if (i != damage_.end()) {
196 framebuffer_info.existing_damage = i->second;
197 }
198 framebuffer_info.supports_partial_repaint = true;
199 }
200
201 return std::make_unique<SurfaceFrame>(std::move(surface), framebuffer_info, submit_callback,
202 frame_info);
203}
204
205std::unique_ptr<SurfaceFrame> GPUSurfaceMetalSkia::AcquireFrameFromMTLTexture(
206 const SkISize& frame_info) {
207 GPUMTLTextureInfo texture = delegate_->GetMTLTexture(frame_info);
208 id<MTLTexture> mtl_texture = (id<MTLTexture>)(texture.texture);
209
210 if (!mtl_texture) {
211 FML_LOG(ERROR) << "Invalid MTLTexture given by the embedder.";
212 return nullptr;
213 }
214
215 sk_sp<SkSurface> surface = CreateSurfaceFromMetalTexture(
216 context_.get(), mtl_texture, kTopLeft_GrSurfaceOrigin, msaa_samples_, kBGRA_8888_SkColorType,
217 nullptr, nullptr, static_cast<SkSurfaces::TextureReleaseProc>(texture.destruction_callback),
218 texture.destruction_context);
219
220 if (!surface) {
221 FML_LOG(ERROR) << "Could not create the SkSurface from the metal texture.";
222 return nullptr;
223 }
224
225 auto submit_callback = [texture = texture, delegate = delegate_](
226 const SurfaceFrame& surface_frame, DlCanvas* canvas) -> bool {
227 TRACE_EVENT0("flutter", "GPUSurfaceMetal::PresentTexture");
228 if (canvas == nullptr) {
229 FML_DLOG(ERROR) << "Canvas not available.";
230 return false;
231 }
232
233 {
234 TRACE_EVENT0("flutter", "SkCanvas::Flush");
235 canvas->Flush();
236 }
237
238 return delegate->PresentTexture(texture);
239 };
240
241 SurfaceFrame::FramebufferInfo framebuffer_info;
242 framebuffer_info.supports_readback = true;
243
244 return std::make_unique<SurfaceFrame>(std::move(surface), framebuffer_info, submit_callback,
245 frame_info);
246}
247
248// |Surface|
250 // This backend does not currently support root surface transformations. Just
251 // return identity.
252 return {};
253}
254
255// |Surface|
257 return context_.get();
258}
259
260// |Surface|
261std::unique_ptr<GLContextResult> GPUSurfaceMetalSkia::MakeRenderContextCurrent() {
262 // A context may either be necessary to render to the surface or to snapshot an offscreen
263 // surface. Either way, SkSL precompilation must be attempted.
264 PrecompileKnownSkSLsIfNecessary();
265
266 // This backend has no such concept.
267 return std::make_unique<GLContextDefaultResult>(true);
268}
269
273
274} // namespace flutter
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition DM.cpp:213
GrSurfaceOrigin
Definition GrTypes.h:147
@ kTopLeft_GrSurfaceOrigin
Definition GrTypes.h:148
SkColorType
Definition SkColorType.h:19
@ kBGRA_8888_SkColorType
pixel with 8 bits for blue, green, red, alpha; in 32-bit word
Definition SkColorType.h:26
#define __has_feature(x)
void * ReleaseContext
Definition SkSurface.h:249
Developer-facing API for rendering anything within the engine.
Definition dl_canvas.h:37
Interface implemented by all platform surfaces that can present a metal backing store to the "screen"...
virtual bool AllowsDrawingWhenGpuDisabled() const
Whether to allow drawing to the surface when the GPU is disabled.
virtual GPUMTLTextureInfo GetMTLTexture(const SkISize &frame_info) const =0
Returns the handle to the MTLTexture to render to. This is only called when the specified render targ...
virtual GPUCAMetalLayerHandle GetCAMetalLayer(const SkISize &frame_info) const =0
Returns the handle to the CAMetalLayer to render to. This is only called when the specified render ta...
virtual bool PresentDrawable(GrMTLHandle drawable) const =0
Presents the drawable to the "screen". The drawable is obtained from the CAMetalLayer that given by G...
GrDirectContext * GetContext() override
GPUSurfaceMetalSkia(GPUSurfaceMetalDelegate *delegate, sk_sp< GrDirectContext > context, MsaaSampleCount msaa_samples, bool render_to_surface=true)
bool AllowsDrawingWhenGpuDisabled() const override
SkMatrix GetRootTransformation() const override
std::unique_ptr< GLContextResult > MakeRenderContextCurrent() override
std::unique_ptr< SurfaceFrame > AcquireFrame(const SkISize &size) override
static PersistentCache * GetCacheForProcess()
size_t PrecompileKnownSkSLs(GrDirectContext *context) const
Precompile SkSLs packaged with the application and gathered during previous runs in the given context...
T * get() const
Definition SkRefCnt.h:303
void reset(T *ptr=nullptr)
Definition SkRefCnt.h:310
MockDelegate delegate_
VkSurfaceKHR surface
Definition main.cc:49
#define FML_DLOG(severity)
Definition logging.h:102
#define FML_LOG(severity)
Definition logging.h:82
#define FML_CHECK(condition)
Definition logging.h:85
FlTexture * texture
MsaaSampleCount
SK_API GrBackendTexture MakeMtl(int width, int height, skgpu::Mipmapped, const GrMtlTextureInfo &mtlInfo, std::string_view label={})
SK_API sk_sp< SkSurface > WrapBackendTexture(GrRecordingContext *context, const GrBackendTexture &backendTexture, GrSurfaceOrigin origin, int sampleCnt, SkColorType colorType, sk_sp< SkColorSpace > colorSpace, const SkSurfaceProps *surfaceProps, TextureReleaseProc textureReleaseProc=nullptr, ReleaseContext releaseContext=nullptr)
void(*)(ReleaseContext) TextureReleaseProc
Definition ref_ptr.h:256
uint32_t color_type
static constexpr SkIRect MakeEmpty()
Definition SkRect.h:45
bool isEmpty() const
Definition SkSize.h:31
#define ERROR(message)
#define TRACE_EVENT0(category_group, name)