Flutter Engine
 
Loading...
Searching...
No Matches
gpu_surface_gl_skia.cc
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
13#include "third_party/skia/include/core/SkAlphaType.h"
14#include "third_party/skia/include/core/SkColorFilter.h"
15#include "third_party/skia/include/core/SkColorSpace.h"
16#include "third_party/skia/include/core/SkColorType.h"
17#include "third_party/skia/include/core/SkSurface.h"
18#include "third_party/skia/include/gpu/ganesh/GrBackendSurface.h"
19#include "third_party/skia/include/gpu/ganesh/GrContextOptions.h"
20#include "third_party/skia/include/gpu/ganesh/SkSurfaceGanesh.h"
21#include "third_party/skia/include/gpu/ganesh/gl/GrGLBackendSurface.h"
22#include "third_party/skia/include/gpu/ganesh/gl/GrGLDirectContext.h"
23#include "third_party/skia/include/gpu/ganesh/gl/GrGLTypes.h"
24
25// These are common defines present on all OpenGL headers. However, we don't
26// want to perform GL header resolution on each platform we support. So just
27// define these upfront. It is unlikely we will need more. But, if we do, we can
28// add the same here.
29#define GPU_GL_RGBA8 0x8058
30#define GPU_GL_RGBA4 0x8056
31#define GPU_GL_RGB565 0x8D62
32
33namespace flutter {
34
35// Default maximum number of bytes of GPU memory of budgeted resources in the
36// cache.
37// The shell will dynamically increase or decrease this cache based on the
38// viewport size, unless a user has specifically requested a size on the Skia
39// system channel.
40static const size_t kGrCacheMaxByteSize = 24 * (1 << 20);
41
42sk_sp<GrDirectContext> GPUSurfaceGLSkia::MakeGLContext(
43 GPUSurfaceGLDelegate* delegate) {
44 auto context_switch = delegate->GLContextMakeCurrent();
45 if (!context_switch->GetResult()) {
46 FML_LOG(ERROR)
47 << "Could not make the context current to set up the Gr context.";
48 return nullptr;
49 }
50
51 const auto options =
52 MakeDefaultContextOptions(ContextType::kRender, GrBackendApi::kOpenGL);
53
54 auto context = GrDirectContexts::MakeGL(delegate->GetGLInterface(), options);
55
56 if (!context) {
57 FML_LOG(ERROR) << "Failed to set up Skia Gr context.";
58 return nullptr;
59 }
60
61 context->setResourceCacheLimit(kGrCacheMaxByteSize);
62
64
65 return context;
66}
67
69 bool render_to_surface)
70 : GPUSurfaceGLSkia(MakeGLContext(delegate), delegate, render_to_surface) {
71 context_owner_ = true;
72}
73
74GPUSurfaceGLSkia::GPUSurfaceGLSkia(const sk_sp<GrDirectContext>& gr_context,
75 GPUSurfaceGLDelegate* delegate,
76 bool render_to_surface)
77 : delegate_(delegate),
78 context_(gr_context),
79 render_to_surface_(render_to_surface),
80 weak_factory_(this) {
81 auto context_switch = delegate_->GLContextMakeCurrent();
82 if (!context_switch->GetResult()) {
83 FML_LOG(ERROR)
84 << "Could not make the context current to set up the Gr context.";
85 return;
86 }
87
88 delegate_->GLContextClearCurrent();
89
90 valid_ = gr_context != nullptr;
91}
92
94 if (!valid_) {
95 return;
96 }
97 auto context_switch = delegate_->GLContextMakeCurrent();
98 if (!context_switch->GetResult()) {
99 FML_LOG(ERROR) << "Could not make the context current to destroy the "
100 "GrDirectContext resources.";
101 return;
102 }
103
104 onscreen_surface_ = nullptr;
105 fbo_id_ = 0;
106 if (context_owner_) {
107 context_->releaseResourcesAndAbandonContext();
108 }
109 context_ = nullptr;
110
111 delegate_->GLContextClearCurrent();
112}
113
114// |Surface|
116 return valid_;
117}
118
119static SkColorType FirstSupportedColorType(GrDirectContext* context,
120 GrGLenum* format) {
121#define RETURN_IF_RENDERABLE(x, y) \
122 if (context->colorTypeSupportedAsSurface((x))) { \
123 *format = (y); \
124 return (x); \
125 }
126 RETURN_IF_RENDERABLE(kRGBA_8888_SkColorType, GPU_GL_RGBA8);
127 RETURN_IF_RENDERABLE(kARGB_4444_SkColorType, GPU_GL_RGBA4);
128 RETURN_IF_RENDERABLE(kRGB_565_SkColorType, GPU_GL_RGB565);
129 return kUnknown_SkColorType;
130}
131
132static sk_sp<SkSurface> WrapOnscreenSurface(GrDirectContext* context,
133 const DlISize& size,
134 intptr_t fbo) {
135 GrGLenum format = kUnknown_SkColorType;
136 const SkColorType color_type = FirstSupportedColorType(context, &format);
137
138 GrGLFramebufferInfo framebuffer_info = {};
139 framebuffer_info.fFBOID = static_cast<GrGLuint>(fbo);
140 framebuffer_info.fFormat = format;
141
142 auto render_target =
143 GrBackendRenderTargets::MakeGL(size.width, // width
144 size.height, // height
145 0, // sample count
146 0, // stencil bits
147 framebuffer_info // framebuffer info
148 );
149
150 sk_sp<SkColorSpace> colorspace = SkColorSpace::MakeSRGB();
151 SkSurfaceProps surface_props(0, kUnknown_SkPixelGeometry);
152
153 return SkSurfaces::WrapBackendRenderTarget(
154 context, // Gr context
155 render_target, // render target
156 GrSurfaceOrigin::kBottomLeft_GrSurfaceOrigin, // origin
157 color_type, // color type
158 colorspace, // colorspace
159 &surface_props // surface properties
160 );
161}
162
163bool GPUSurfaceGLSkia::CreateOrUpdateSurfaces(const DlISize& size) {
164 if (onscreen_surface_ != nullptr &&
165 size.width == onscreen_surface_->width() &&
166 size.height == onscreen_surface_->height()) {
167 // Surface size appears unchanged. So bail.
168 return true;
169 }
170
171 // We need to do some updates.
172 TRACE_EVENT0("flutter", "UpdateSurfacesSize");
173
174 // Either way, we need to get rid of previous surface.
175 onscreen_surface_ = nullptr;
176 fbo_id_ = 0;
177
178 if (size.IsEmpty()) {
179 FML_LOG(ERROR) << "Cannot create surfaces of empty size.";
180 return false;
181 }
182
183 sk_sp<SkSurface> onscreen_surface;
184
185 GLFrameInfo frame_info = {static_cast<uint32_t>(size.width),
186 static_cast<uint32_t>(size.height)};
187 const GLFBOInfo fbo_info = delegate_->GLContextFBO(frame_info);
188 onscreen_surface = WrapOnscreenSurface(context_.get(), // GL context
189 size, // root surface size
190 fbo_info.fbo_id // window FBO ID
191 );
192
193 if (onscreen_surface == nullptr) {
194 // If the onscreen surface could not be wrapped. There is absolutely no
195 // point in moving forward.
196 FML_LOG(ERROR) << "Could not wrap onscreen surface.";
197 return false;
198 }
199
200 onscreen_surface_ = std::move(onscreen_surface);
201 fbo_id_ = fbo_info.fbo_id;
202 existing_damage_ = fbo_info.existing_damage;
203
204 return true;
205}
206
207// |Surface|
211
212// |Surface|
213std::unique_ptr<SurfaceFrame> GPUSurfaceGLSkia::AcquireFrame(
214 const DlISize& size) {
215 if (delegate_ == nullptr) {
216 return nullptr;
217 }
218 auto context_switch = delegate_->GLContextMakeCurrent();
219 if (!context_switch->GetResult()) {
220 FML_LOG(ERROR)
221 << "Could not make the context current to acquire the frame.";
222 return nullptr;
223 }
224
225 SurfaceFrame::FramebufferInfo framebuffer_info;
226
227 // TODO(38466): Refactor GPU surface APIs take into account the fact that an
228 // external view embedder may want to render to the root surface.
229 if (!render_to_surface_) {
230 framebuffer_info.supports_readback = true;
231 return std::make_unique<SurfaceFrame>(
232 nullptr, framebuffer_info,
233 [](const SurfaceFrame& surface_frame, DlCanvas* canvas) {
234 return true;
235 },
236 [](const SurfaceFrame& surface_frame) { return true; }, size);
237 }
238
239 const auto root_surface_transformation = GetRootTransformation();
240
241 sk_sp<SkSurface> surface =
242 AcquireRenderSurface(size, root_surface_transformation);
243
244 if (surface == nullptr) {
245 return nullptr;
246 }
247
248 surface->getCanvas()->setMatrix(ToSkM44(root_surface_transformation));
249
250 SurfaceFrame::EncodeCallback encode_callback =
251 [weak = weak_factory_.GetWeakPtr()](const SurfaceFrame& surface_frame,
252 DlCanvas* canvas) {
253 TRACE_EVENT0("flutter", "GrDirectContext::flushAndSubmit");
254 if (weak) {
255 weak->context_->flushAndSubmit();
256 return true;
257 }
258 return false;
259 };
260 SurfaceFrame::SubmitCallback submit_callback =
261 [weak = weak_factory_.GetWeakPtr()](const SurfaceFrame& surface_frame) {
262 return weak ? weak->PresentSurface(surface_frame) : false;
263 };
264
265 framebuffer_info = delegate_->GLContextFramebufferInfo();
266 if (!framebuffer_info.existing_damage.has_value()) {
267 framebuffer_info.existing_damage = existing_damage_;
268 }
269 return std::make_unique<SurfaceFrame>(surface, framebuffer_info,
270 encode_callback, submit_callback, size,
271 std::move(context_switch));
272}
273
274bool GPUSurfaceGLSkia::PresentSurface(const SurfaceFrame& frame) {
275 if (delegate_ == nullptr || context_ == nullptr) {
276 return false;
277 }
278
280
281 GLPresentInfo present_info = {
282 .fbo_id = fbo_id_,
283 .frame_damage = frame.submit_info().frame_damage,
284 .presentation_time = frame.submit_info().presentation_time,
285 .buffer_damage = frame.submit_info().buffer_damage,
286 };
287 if (!delegate_->GLContextPresent(present_info)) {
288 return false;
289 }
290
291 if (delegate_->GLContextFBOResetAfterPresent()) {
292 auto current_size =
293 DlISize(onscreen_surface_->width(), onscreen_surface_->height());
294
295 GLFrameInfo frame_info = {static_cast<uint32_t>(current_size.width),
296 static_cast<uint32_t>(current_size.height)};
297
298 // The FBO has changed, ask the delegate for the new FBO and do a surface
299 // re-wrap.
300 const GLFBOInfo fbo_info = delegate_->GLContextFBO(frame_info);
301 auto new_onscreen_surface =
302 WrapOnscreenSurface(context_.get(), // GL context
303 current_size, // root surface size
304 fbo_info.fbo_id // window FBO ID
305 );
306
307 if (!new_onscreen_surface) {
308 return false;
309 }
310
311 onscreen_surface_ = std::move(new_onscreen_surface);
312 fbo_id_ = fbo_info.fbo_id;
313 existing_damage_ = fbo_info.existing_damage;
314 }
315
316 return true;
317}
318
319sk_sp<SkSurface> GPUSurfaceGLSkia::AcquireRenderSurface(
320 const DlISize& untransformed_size,
321 const DlMatrix& root_surface_transformation) {
322 const auto transformed_rect =
323 DlRect::MakeSize(untransformed_size)
324 .TransformAndClipBounds(root_surface_transformation);
325
326 const DlISize transformed_size =
327 DlIRect::RoundOut(transformed_rect).GetSize();
328
329 if (!CreateOrUpdateSurfaces(transformed_size)) {
330 return nullptr;
331 }
332
333 return onscreen_surface_;
334}
335
336// |Surface|
338 return context_.get();
339}
340
341// |Surface|
342std::unique_ptr<GLContextResult> GPUSurfaceGLSkia::MakeRenderContextCurrent() {
343 return delegate_->GLContextMakeCurrent();
344}
345
346// |Surface|
348 return delegate_->GLContextClearCurrent();
349}
350
351// |Surface|
355
356} // namespace flutter
Developer-facing API for rendering anything within the engine.
Definition dl_canvas.h:32
virtual bool AllowsDrawingWhenGpuDisabled() const
virtual std::unique_ptr< GLContextResult > GLContextMakeCurrent()=0
virtual bool GLContextClearCurrent()=0
virtual bool GLContextPresent(const GLPresentInfo &present_info)=0
virtual void GLContextSetDamageRegion(const std::optional< DlIRect > &region)
virtual sk_sp< const GrGLInterface > GetGLInterface() const
virtual bool GLContextFBOResetAfterPresent() const
virtual SurfaceFrame::FramebufferInfo GLContextFramebufferInfo() const
virtual GLFBOInfo GLContextFBO(GLFrameInfo frame_info) const =0
virtual DlMatrix GLContextSurfaceTransformation() const
GrDirectContext * GetContext() override
DlMatrix GetRootTransformation() const override
bool AllowsDrawingWhenGpuDisabled() const override
static sk_sp< GrDirectContext > MakeGLContext(GPUSurfaceGLDelegate *delegate)
GPUSurfaceGLSkia(GPUSurfaceGLDelegate *delegate, bool render_to_surface)
std::unique_ptr< GLContextResult > MakeRenderContextCurrent() override
std::unique_ptr< SurfaceFrame > AcquireFrame(const DlISize &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...
std::function< bool(SurfaceFrame &surface_frame, DlCanvas *canvas)> EncodeCallback
std::function< bool(SurfaceFrame &surface_frame)> SubmitCallback
const SubmitInfo & submit_info() const
MockDelegate delegate_
VkSurfaceKHR surface
Definition main.cc:65
uint32_t uint32_t * format
#define FML_LOG(severity)
Definition logging.h:101
#define GPU_GL_RGBA4
#define GPU_GL_RGB565
#define GPU_GL_RGBA8
#define RETURN_IF_RENDERABLE(x, y)
static SkColorType FirstSupportedColorType(GrDirectContext *context, GrGLenum *format)
impeller::Matrix DlMatrix
impeller::ISize32 DlISize
it will be possible to load the file into Perfetto s trace viewer use test Running tests that layout and measure text will not yield consistent results across various platforms Enabling this option will make font resolution default to the Ahem test font on all disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
static sk_sp< SkSurface > WrapOnscreenSurface(GrDirectContext *context, const DlISize &size, intptr_t fbo)
GrContextOptions MakeDefaultContextOptions(ContextType type, std::optional< GrBackendApi > api)
Initializes GrContextOptions with values suitable for Flutter. The options can be further tweaked bef...
static const size_t kGrCacheMaxByteSize
@ kRender
The context is used to render to a texture or renderbuffer.
SkM44 ToSkM44(const DlMatrix &matrix)
uint32_t color_type
std::optional< DlIRect > existing_damage
std::optional< DlIRect > frame_damage
std::optional< DlIRect > buffer_damage
std::optional< fml::TimePoint > presentation_time
A 4x4 matrix using column-major storage.
Definition matrix.h:37
RoundOut(const TRect< U > &r)
Definition rect.h:679
constexpr TRect TransformAndClipBounds(const Matrix &transform) const
Creates a new bounding box that contains this transformed rectangle, clipped against the near clippin...
Definition rect.h:438
static constexpr TRect MakeSize(const TSize< U > &size)
Definition rect.h:150
#define TRACE_EVENT0(category_group, name)