Flutter Engine Uber Docs
Docs for the entire Flutter Engine repo.
 
Loading...
Searching...
No Matches
fl_view_renderer.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
7#include <gdk/gdkwayland.h>
8
14
16 GtkDrawingArea parent_instance;
17
18 // Engine this widget is rendering.
19 FlEngine* engine;
20
21 // Rendering context when using OpenGL.
22 GdkGLContext* render_context;
23
24 // Combines layers into frame.
25 FlCompositor* compositor;
26
27 // Background color.
29
30 // TRUE if the view size should be controlled by Flutter.
32
33 // TRUE if have got the first frame to render.
35};
36
38
40
41G_DEFINE_TYPE(FlViewRenderer, fl_view_renderer, GTK_TYPE_DRAWING_AREA)
42
43// Redraw the view from the GTK thread.
44static gboolean redraw_cb(gpointer user_data) {
45 g_autoptr(FlViewRenderer) self = FL_VIEW_RENDERER(user_data);
46
47 if (self->compositor == nullptr) {
48 return G_SOURCE_REMOVE;
49 }
50
51 if (!self->have_first_frame) {
52 self->have_first_frame = TRUE;
54 }
55
56 // If Flutter is controlling the window size, then resize the view if
57 // necessary.
58 GtkWidget* render_widget = GTK_WIDGET(self);
59 GtkAllocation allocation;
60 gtk_widget_get_allocation(render_widget, &allocation);
61 gint scale_factor = gtk_widget_get_scale_factor(render_widget);
62 size_t width = allocation.width * scale_factor;
63 size_t height = allocation.height * scale_factor;
64 size_t frame_width, frame_height;
65 fl_compositor_get_frame_size(self->compositor, &frame_width, &frame_height);
66 gboolean frame_size_matches = width == frame_width && height == frame_height;
67 if (self->sized_to_content && !frame_size_matches) {
68 gtk_widget_set_size_request(render_widget, frame_width / scale_factor,
69 frame_height / scale_factor);
70 GtkWidget* toplevel = gtk_widget_get_toplevel(render_widget);
71 if (GTK_IS_WINDOW(toplevel)) {
72 // Resize to smallest size, so that the window will shrink to fit the new
73 // size of the render area.
74 gtk_window_resize(GTK_WINDOW(toplevel), 1, 1);
75 }
76 return G_SOURCE_REMOVE;
77 }
78
79 gtk_widget_queue_draw(render_widget);
80
81 return G_SOURCE_REMOVE;
82}
83
84static void setup_opengl(FlViewRenderer* self) {
85 g_autoptr(GError) error = nullptr;
86
87 self->render_context = gdk_window_create_gl_context(
88 gtk_widget_get_window(GTK_WIDGET(self)), &error);
89 if (self->render_context == nullptr) {
90 g_warning("Failed to create OpenGL context: %s", error->message);
91 return;
92 }
93
94 if (!gdk_gl_context_realize(self->render_context, &error)) {
95 g_warning("Failed to realize OpenGL context: %s", error->message);
96 return;
97 }
98
99 // If using Wayland, then EGL is in use and we can access the frame
100 // from the Flutter context using EGLImage. If not (i.e. X11 using GLX)
101 // then we have to copy the texture via the CPU.
102 gboolean shareable =
103 GDK_IS_WAYLAND_DISPLAY(gtk_widget_get_display(GTK_WIDGET(self)));
104 self->compositor = FL_COMPOSITOR(fl_compositor_opengl_new(
107}
108
109static void setup_software(FlViewRenderer* self) {
110 self->compositor = FL_COMPOSITOR(
112}
113
114static void paint_background(FlViewRenderer* self, cairo_t* cr) {
115 // Don't bother drawing if fully transparent - the widget above this will
116 // already be drawn by GTK.
117 if (self->background_color->red == 0 && self->background_color->green == 0 &&
118 self->background_color->blue == 0 && self->background_color->alpha == 0) {
119 return;
120 }
121
122 gdk_cairo_set_source_rgba(cr, self->background_color);
123 cairo_paint(cr);
124}
125
126// Implements GtkWidget::realize.
127static void fl_view_renderer_realize(GtkWidget* widget) {
128 FlViewRenderer* self = FL_VIEW_RENDERER(widget);
129
130 GTK_WIDGET_CLASS(fl_view_renderer_parent_class)->realize(widget);
131
132 switch (fl_engine_get_renderer_type(self->engine)) {
133 case kOpenGL:
135 break;
136 case kSoftware:
138 break;
139 default:
140 break;
141 }
142}
143
144// Implements GtkWidget::draw.
145static gboolean fl_view_renderer_draw(GtkWidget* widget, cairo_t* cr) {
146 FlViewRenderer* self = FL_VIEW_RENDERER(widget);
147
149
150 // The compositor is created when the widget is realized; if it is not yet
151 // available there is nothing to render beyond the background.
152 if (self->compositor == nullptr) {
153 return TRUE;
154 }
155
156 if (self->render_context) {
157 gdk_gl_context_make_current(self->render_context);
158 }
159
160 gboolean wait_for_frame = !self->sized_to_content;
161 gboolean result = fl_compositor_render(
162 self->compositor, cr, gtk_widget_get_window(widget), wait_for_frame);
163
164 if (self->render_context) {
166 }
167
168 return result;
169}
170
171static void fl_view_renderer_dispose(GObject* object) {
172 FlViewRenderer* self = FL_VIEW_RENDERER(object);
173
174 g_clear_object(&self->render_context);
175 g_clear_object(&self->engine);
176 g_clear_pointer(&self->background_color, gdk_rgba_free);
177
178 G_OBJECT_CLASS(fl_view_renderer_parent_class)->dispose(object);
179}
180
181static void fl_view_renderer_finalize(GObject* object) {
182 FlViewRenderer* self = FL_VIEW_RENDERER(object);
183
184 // The compositor is released here rather than in dispose() so it outlives a
185 // forced dispose (e.g. gtk_widget_destroy()) and is only freed once the last
186 // reference is dropped. This keeps it alive for the raster thread, which
187 // holds a strong reference on the view (and thus this renderer) while
188 // presenting.
189 g_clear_object(&self->compositor);
190
191 G_OBJECT_CLASS(fl_view_renderer_parent_class)->finalize(object);
192}
193
194static void fl_view_renderer_class_init(FlViewRendererClass* klass) {
195 G_OBJECT_CLASS(klass)->dispose = fl_view_renderer_dispose;
196 G_OBJECT_CLASS(klass)->finalize = fl_view_renderer_finalize;
197
198 GtkWidgetClass* widget_class = GTK_WIDGET_CLASS(klass);
199 widget_class->realize = fl_view_renderer_realize;
200 widget_class->draw = fl_view_renderer_draw;
201
203 g_signal_new("first-frame", fl_view_renderer_get_type(),
204 G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0);
205}
206
207static void fl_view_renderer_init(FlViewRenderer* self) {
208 GdkRGBA default_background = {
209 .red = 0.0, .green = 0.0, .blue = 0.0, .alpha = 1.0};
210 self->background_color = gdk_rgba_copy(&default_background);
211}
212
213FlViewRenderer* fl_view_renderer_new(FlEngine* engine,
214 gboolean sized_to_content) {
215 g_return_val_if_fail(FL_IS_ENGINE(engine), nullptr);
216
217 FlViewRenderer* self =
218 FL_VIEW_RENDERER(g_object_new(fl_view_renderer_get_type(), nullptr));
219
220 self->engine = FL_ENGINE(g_object_ref(engine));
221 self->sized_to_content = sized_to_content;
222
223 return self;
224}
225
227 const GdkRGBA* color) {
228 g_return_if_fail(FL_IS_VIEW_RENDERER(self));
229 gdk_rgba_free(self->background_color);
230 self->background_color = gdk_rgba_copy(color);
231}
232
234 const FlutterLayer** layers,
235 size_t layers_count) {
236 g_return_if_fail(FL_IS_VIEW_RENDERER(self));
237
238 // Frames may be presented before the widget is realized and the compositor
239 // is set up; ignore them.
240 if (self->compositor == nullptr) {
241 return;
242 }
243
245
246 // Perform the redraw in the GTK thread.
247 g_idle_add(redraw_cb, g_object_ref(self));
248}
@ kOpenGL
Definition embedder.h:80
@ kSoftware
Definition embedder.h:81
FlutterEngine engine
Definition main.cc:84
g_autoptr(FlEngine) engine
G_DEFINE_TYPE(FlBasicMessageChannelResponseHandle, fl_basic_message_channel_response_handle, G_TYPE_OBJECT) static void fl_basic_message_channel_response_handle_dispose(GObject *object)
gboolean fl_compositor_render(FlCompositor *self, cairo_t *cr, GdkWindow *window, gboolean wait_for_frame)
void fl_compositor_get_frame_size(FlCompositor *self, size_t *width, size_t *height)
gboolean fl_compositor_present_layers(FlCompositor *self, const FlutterLayer **layers, size_t layers_count)
FlCompositorOpenGL * fl_compositor_opengl_new(FlTaskRunner *task_runner, FlOpenGLManager *opengl_manager, gboolean shareable)
G_BEGIN_DECLS FlOpenGLManager gboolean shareable
const FlutterLayer size_t layers_count
const FlutterLayer ** layers
FlCompositorSoftware * fl_compositor_software_new(FlTaskRunner *task_runner)
return TRUE
FlTaskRunner * fl_engine_get_task_runner(FlEngine *self)
FlOpenGLManager * fl_engine_get_opengl_manager(FlEngine *self)
Definition fl_engine.cc:749
FlutterRendererType fl_engine_get_renderer_type(FlEngine *self)
Definition fl_engine.cc:744
const uint8_t uint32_t uint32_t GError ** error
static gboolean fl_view_renderer_draw(GtkWidget *widget, cairo_t *cr)
FlViewRenderer * fl_view_renderer_new(FlEngine *engine, gboolean sized_to_content)
static void fl_view_renderer_dispose(GObject *object)
void fl_view_renderer_set_background_color(FlViewRenderer *self, const GdkRGBA *color)
static void fl_view_renderer_realize(GtkWidget *widget)
static gboolean redraw_cb(gpointer user_data)
static void setup_software(FlViewRenderer *self)
static void fl_view_renderer_init(FlViewRenderer *self)
static void fl_view_renderer_finalize(GObject *object)
static void setup_opengl(FlViewRenderer *self)
@ LAST_SIGNAL
@ SIGNAL_FIRST_FRAME
static void fl_view_renderer_class_init(FlViewRendererClass *klass)
static void paint_background(FlViewRenderer *self, cairo_t *cr)
void fl_view_renderer_present_layers(FlViewRenderer *self, const FlutterLayer **layers, size_t layers_count)
static guint fl_view_renderer_signals[LAST_SIGNAL]
G_BEGIN_DECLS gboolean sized_to_content
GdkDisplay * gtk_widget_get_display(GtkWidget *widget)
Definition mock_gtk.cc:253
void gtk_widget_queue_draw(GtkWidget *widget)
Definition mock_gtk.cc:271
void gtk_window_resize(GtkWindow *window, gint width, gint height)
Definition mock_gtk.cc:207
void gdk_gl_context_clear_current(GdkGLContext *context)
Definition mock_gtk.cc:162
void gtk_widget_get_allocation(GtkWidget *widget, GtkAllocation *allocation)
Definition mock_gtk.cc:245
void gdk_gl_context_make_current(GdkGLContext *context)
Definition mock_gtk.cc:166
GtkWidget * gtk_widget_get_toplevel(GtkWidget *widget)
Definition mock_gtk.cc:304
GdkGLContext * gdk_window_create_gl_context(GdkWindow *window, GError **error)
Definition mock_gtk.cc:149
void gdk_gl_context_realize(GdkGLContext *context)
Definition mock_gtk.cc:158
GdkWindow * gtk_widget_get_window(GtkWidget *widget)
Definition mock_gtk.cc:309
gint gtk_widget_get_scale_factor(GtkWidget *widget)
Definition mock_gtk.cc:258
void gdk_cairo_set_source_rgba(cairo_t *cr, const GdkRGBA *rgba)
Definition mock_gtk.cc:154
int32_t height
int32_t width
GdkGLContext * render_context
GdkRGBA * background_color
FlCompositor * compositor
GtkDrawingArea parent_instance