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
6#if !SLIMPELLER
7
9
10#import <Metal/Metal.h>
11#import <QuartzCore/QuartzCore.h>
12
13#include <utility>
14
20#include "third_party/skia/include/core/SkColorSpace.h"
21#include "third_party/skia/include/core/SkColorType.h"
22#include "third_party/skia/include/core/SkRefCnt.h"
23#include "third_party/skia/include/core/SkSurface.h"
24#include "third_party/skia/include/core/SkSurfaceProps.h"
25#include "third_party/skia/include/gpu/GpuTypes.h"
26#include "third_party/skia/include/gpu/ganesh/GrBackendSurface.h"
27#include "third_party/skia/include/gpu/ganesh/SkSurfaceGanesh.h"
28#include "third_party/skia/include/gpu/ganesh/mtl/GrMtlBackendSurface.h"
29#include "third_party/skia/include/gpu/ganesh/mtl/GrMtlTypes.h"
30#include "third_party/skia/include/ports/SkCFObject.h"
31
32static_assert(__has_feature(objc_arc), "ARC must be enabled.");
33
34namespace flutter {
35
36namespace {
37sk_sp<SkSurface> CreateSurfaceFromMetalTexture(GrDirectContext* context,
38 id<MTLTexture> texture,
39 GrSurfaceOrigin origin,
40 SkColorType color_type,
41 sk_sp<SkColorSpace> color_space,
42 const SkSurfaceProps* props,
43 SkSurfaces::TextureReleaseProc release_proc,
44 SkSurface::ReleaseContext release_context) {
45 GrMtlTextureInfo info;
46 info.fTexture.retain((__bridge GrMTLHandle)texture);
47 GrBackendTexture backend_texture =
48 GrBackendTextures::MakeMtl(texture.width, texture.height, skgpu::Mipmapped::kNo, info);
49 return SkSurfaces::WrapBackendTexture(context, backend_texture, origin, 1, color_type,
50 std::move(color_space), props, release_proc,
51 release_context);
52}
53} // namespace
54
56 sk_sp<GrDirectContext> context,
57 bool render_to_surface)
58 : delegate_(delegate),
59 render_target_type_(delegate->GetRenderTargetType()),
60 context_(std::move(context)),
61 render_to_surface_(render_to_surface) {
62 // If this preference is explicitly set, we allow for disabling partial repaint.
63 NSNumber* disablePartialRepaint =
64 [[NSBundle mainBundle] objectForInfoDictionaryKey:@"FLTDisablePartialRepaint"];
65 if (disablePartialRepaint != nil) {
66 disable_partial_repaint_ = disablePartialRepaint.boolValue;
67 }
68}
69
71
72// |Surface|
74 return context_ != nullptr;
75}
76
77void GPUSurfaceMetalSkia::PrecompileKnownSkSLsIfNecessary() {
78 auto* current_context = GetContext();
79 if (current_context == precompiled_sksl_context_) {
80 // Known SkSLs have already been prepared in this context.
81 return;
82 }
83 precompiled_sksl_context_ = current_context;
85}
86
87// |Surface|
88std::unique_ptr<SurfaceFrame> GPUSurfaceMetalSkia::AcquireFrame(const DlISize& frame_size) {
89 if (!IsValid()) {
90 FML_LOG(ERROR) << "Metal surface was invalid.";
91 return nullptr;
92 }
93
94 if (frame_size.IsEmpty()) {
95 FML_LOG(ERROR) << "Metal surface was asked for an empty frame.";
96 return nullptr;
97 }
98
99 if (!render_to_surface_) {
100 return std::make_unique<SurfaceFrame>(
101 nullptr, //
102 SurfaceFrame::FramebufferInfo(), //
103 [](const SurfaceFrame& surface_frame, DlCanvas* canvas) { return true; }, //
104 [](const SurfaceFrame& surface_frame) { return true; }, //
105 frame_size //
106 );
107 }
108
109 PrecompileKnownSkSLsIfNecessary();
110
111 switch (render_target_type_) {
113 return AcquireFrameFromCAMetalLayer(frame_size);
115 return AcquireFrameFromMTLTexture(frame_size);
116 default:
117 FML_CHECK(false) << "Unknown MTLRenderTargetType type.";
118 }
119
120 return nullptr;
121}
122
123std::unique_ptr<SurfaceFrame> GPUSurfaceMetalSkia::AcquireFrameFromCAMetalLayer(
124 const DlISize& frame_info) {
125 CAMetalLayer* layer = (__bridge CAMetalLayer*)delegate_->GetCAMetalLayer(frame_info);
126 if (!layer) {
127 FML_LOG(ERROR) << "Invalid CAMetalLayer given by the embedder.";
128 return nullptr;
129 }
130
131 // Get the drawable eagerly, we will need texture object to identify target framebuffer
132 id<CAMetalDrawable> drawable = [layer nextDrawable];
133 if (!drawable) {
134 FML_LOG(ERROR) << "Could not obtain drawable from the metal layer.";
135 return nullptr;
136 }
137
138 auto surface = CreateSurfaceFromMetalTexture(context_.get(), drawable.texture,
139 kTopLeft_GrSurfaceOrigin, // origin
140 kBGRA_8888_SkColorType, // color type
141 nullptr, // colorspace
142 nullptr, // surface properties
143 nullptr, // release proc
144 nullptr // release context
145 );
146
147 if (!surface) {
148 FML_LOG(ERROR) << "Could not create the SkSurface from the CAMetalLayer.";
149 return nullptr;
150 }
151
152 // drawable is a local and needs to be strongly-captured.
153 SurfaceFrame::EncodeCallback encode_callback =
154 [this, drawable, layer](const SurfaceFrame& surface_frame, DlCanvas* canvas) -> bool {
155 layer.presentsWithTransaction = surface_frame.submit_info().present_with_transaction;
156 if (canvas == nullptr) {
157 FML_DLOG(ERROR) << "Canvas not available.";
158 return false;
159 }
160
161 {
162 TRACE_EVENT0("flutter", "SkCanvas::Flush");
163 canvas->Flush();
164 }
165
166 if (!disable_partial_repaint_) {
167 void* texture = (__bridge void*)drawable.texture;
168 for (auto& entry : damage_) {
169 if (entry.first != texture) {
170 // Accumulate damage for other framebuffers
171 if (surface_frame.submit_info().frame_damage) {
172 entry.second = entry.second.Union(*surface_frame.submit_info().frame_damage);
173 }
174 }
175 }
176 // Reset accumulated damage for current framebuffer
177 damage_[texture] = DlIRect();
178 }
179
180 return true;
181 };
182
183 // drawable is a local and needs to be strongly-captured.
184 SurfaceFrame::SubmitCallback submit_callback =
185 [this, drawable](const SurfaceFrame& surface_frame) -> bool {
186 TRACE_EVENT0("flutter", "GPUSurfaceMetal::Submit");
187 return delegate_->PresentDrawable((__bridge GrMTLHandle)drawable);
188 };
189
190 SurfaceFrame::FramebufferInfo framebuffer_info;
191 framebuffer_info.supports_readback = true;
192
193 if (!disable_partial_repaint_) {
194 // Provide accumulated damage to rasterizer (area in current framebuffer that lags behind
195 // front buffer)
196 void* texture = (__bridge void*)drawable.texture;
197 auto i = damage_.find(texture);
198 if (i != damage_.end()) {
199 framebuffer_info.existing_damage = i->second;
200 }
201 framebuffer_info.supports_partial_repaint = true;
202 }
203
204 return std::make_unique<SurfaceFrame>(std::move(surface), framebuffer_info, encode_callback,
205 submit_callback, frame_info);
206}
207
208std::unique_ptr<SurfaceFrame> GPUSurfaceMetalSkia::AcquireFrameFromMTLTexture(
209 const DlISize& frame_info) {
210 GPUMTLTextureInfo texture = delegate_->GetMTLTexture(frame_info);
211 id<MTLTexture> mtl_texture = (__bridge id<MTLTexture>)texture.texture;
212
213 if (!mtl_texture) {
214 FML_LOG(ERROR) << "Invalid MTLTexture given by the embedder.";
215 return nullptr;
216 }
217
218 sk_sp<SkSurface> surface = CreateSurfaceFromMetalTexture(
219 context_.get(), mtl_texture, kTopLeft_GrSurfaceOrigin, kBGRA_8888_SkColorType, nullptr,
220 nullptr, static_cast<SkSurfaces::TextureReleaseProc>(texture.destruction_callback),
221 texture.destruction_context);
222
223 if (!surface) {
224 FML_LOG(ERROR) << "Could not create the SkSurface from the metal texture.";
225 return nullptr;
226 }
227
228 auto encode_callback = [](const SurfaceFrame& surface_frame, DlCanvas* canvas) -> bool {
229 if (canvas == nullptr) {
230 FML_DLOG(ERROR) << "Canvas not available.";
231 return false;
232 }
233
234 {
235 TRACE_EVENT0("flutter", "SkCanvas::Flush");
236 canvas->Flush();
237 }
238
239 return true;
240 };
241 auto submit_callback = [texture = texture,
242 delegate = delegate_](const SurfaceFrame& surface_frame) {
243 TRACE_EVENT0("flutter", "GPUSurfaceMetal::PresentTexture");
244 return delegate->PresentTexture(texture);
245 };
246
247 SurfaceFrame::FramebufferInfo framebuffer_info;
248 framebuffer_info.supports_readback = true;
249
250 return std::make_unique<SurfaceFrame>(std::move(surface), framebuffer_info, encode_callback,
251 submit_callback, frame_info);
252}
253
254// |Surface|
255DlMatrix GPUSurfaceMetalSkia::GetRootTransformation() const {
256 // This backend does not currently support root surface transformations. Just
257 // return identity.
258 return {};
259}
260
261// |Surface|
262GrDirectContext* GPUSurfaceMetalSkia::GetContext() {
263 return context_.get();
264}
265
266// |Surface|
267std::unique_ptr<GLContextResult> GPUSurfaceMetalSkia::MakeRenderContextCurrent() {
268 // A context may either be necessary to render to the surface or to snapshot an offscreen
269 // surface. Either way, SkSL precompilation must be attempted.
270 PrecompileKnownSkSLsIfNecessary();
271
272 // This backend has no such concept.
273 return std::make_unique<GLContextDefaultResult>(true);
274}
275
276bool GPUSurfaceMetalSkia::AllowsDrawingWhenGpuDisabled() const {
277 return delegate_->AllowsDrawingWhenGpuDisabled();
278}
279
280} // namespace flutter
281
282#endif // !SLIMPELLER
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 bool PresentDrawable(GrMTLHandle drawable) const =0
Presents the drawable to the "screen". The drawable is obtained from the CAMetalLayer that given by G...
virtual GPUMTLTextureInfo GetMTLTexture(const DlISize &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 DlISize &frame_info) const =0
Returns the handle to the CAMetalLayer to render to. This is only called when the specified render ta...
GPUSurfaceMetalSkia(GPUSurfaceMetalDelegate *delegate, sk_sp< GrDirectContext > context, bool render_to_surface=true)
static PersistentCache * GetCacheForProcess()
size_t PrecompileKnownSkSLs(GrDirectContext *context) const
Precompile SkSLs packaged with the application and gathered during previous runs in the given context...
std::function< bool(SurfaceFrame &surface_frame, DlCanvas *canvas)> EncodeCallback
std::function< bool(SurfaceFrame &surface_frame)> SubmitCallback
MockDelegate delegate_
VkSurfaceKHR surface
Definition main.cc:65
#define FML_DLOG(severity)
Definition logging.h:121
#define FML_LOG(severity)
Definition logging.h:101
#define FML_CHECK(condition)
Definition logging.h:104
FlTexture * texture
impeller::Matrix DlMatrix
impeller::ISize32 DlISize
impeller::IRect32 DlIRect
Definition ref_ptr.h:261
flutter::DlCanvas DlCanvas
uint32_t color_type
#define TRACE_EVENT0(category_group, name)