Flutter Engine Uber Docs
Docs for the entire Flutter Engine repo.
 
Loading...
Searching...
No Matches
fl_compositor_opengl.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 <epoxy/egl.h>
8#include <epoxy/gl.h>
9
15
18
19 // TRUE if can share framebuffers between contexts.
20 gboolean shareable;
21
22 // Flutter OpenGL contexts.
23 FlOpenGLManager* opengl_manager;
24
25 // Last rendered frame.
26 FlFramebuffer* framebuffer;
27
28 // Last rendered frame pixels (only set if shareable is FALSE).
29 uint8_t* pixels;
30
31 // Shader program used to composite layers.
32 FlCompositorOpenGLShader* shader;
33};
34
35G_DEFINE_TYPE(FlCompositorOpenGL, fl_compositor_opengl, G_TYPE_OBJECT)
36
37static void fl_compositor_opengl_dispose(GObject* object) {
38 FlCompositorOpenGL* self = FL_COMPOSITOR_OPENGL(object);
39
40 g_clear_object(&self->shader);
41
42 g_clear_object(&self->opengl_manager);
43 g_clear_object(&self->framebuffer);
44 g_clear_pointer(&self->pixels, g_free);
45
46 G_OBJECT_CLASS(fl_compositor_opengl_parent_class)->dispose(object);
47}
48
49static void fl_compositor_opengl_class_init(FlCompositorOpenGLClass* klass) {
50 G_OBJECT_CLASS(klass)->dispose = fl_compositor_opengl_dispose;
51}
52
53static void fl_compositor_opengl_init(FlCompositorOpenGL* self) {}
54
55FlCompositorOpenGL* fl_compositor_opengl_new(FlOpenGLManager* opengl_manager,
56 gboolean shareable) {
57 FlCompositorOpenGL* self = FL_COMPOSITOR_OPENGL(
58 g_object_new(fl_compositor_opengl_get_type(), nullptr));
59
60 self->shareable = shareable;
61 self->opengl_manager = FL_OPENGL_MANAGER(g_object_ref(opengl_manager));
62 self->shader = fl_compositor_opengl_shader_new(opengl_manager);
63
64 return self;
65}
66
67static void composite_layer(FlCompositorOpenGL* self,
68 FlFramebuffer* framebuffer,
69 double x,
70 double y,
71 int width,
72 int height) {
73 size_t texture_width = fl_framebuffer_get_width(framebuffer);
74 size_t texture_height = fl_framebuffer_get_height(framebuffer);
76 (2 * y / height) - 1.0);
77 fl_compositor_opengl_shader_set_scale(self->shader, texture_width / width,
78 texture_height / height);
79
80 GLuint texture_id = fl_framebuffer_get_texture_id(framebuffer);
81 glBindTexture(GL_TEXTURE_2D, texture_id);
82
83 glDrawArrays(GL_TRIANGLES, 0, 6);
84}
85
86gboolean fl_compositor_opengl_composite_layers(FlCompositorOpenGL* self,
87 const FlutterLayer** layers,
88 size_t layers_count) {
89 if (layers_count == 0) {
90 return TRUE;
91 }
92
93 GLint general_format = GL_RGBA;
94 if (epoxy_has_gl_extension("GL_EXT_texture_format_BGRA8888")) {
95 general_format = GL_BGRA_EXT;
96 }
97
98 // Save bindings that are set by this function. All bindings must be restored
99 // to their original values because Skia expects that its bindings have not
100 // been altered.
101 GLint saved_texture_binding;
102 glGetIntegerv(GL_TEXTURE_BINDING_2D, &saved_texture_binding);
103 GLint saved_vao_binding;
104 glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &saved_vao_binding);
105 GLint saved_array_buffer_binding;
106 glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &saved_array_buffer_binding);
107 GLint saved_draw_framebuffer_binding;
108 glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &saved_draw_framebuffer_binding);
109 GLint saved_read_framebuffer_binding;
110 glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &saved_read_framebuffer_binding);
111 GLint saved_current_program;
112 glGetIntegerv(GL_CURRENT_PROGRAM, &saved_current_program);
113 GLboolean saved_scissor_test = glIsEnabled(GL_SCISSOR_TEST);
114 GLboolean saved_blend = glIsEnabled(GL_BLEND);
115 GLint saved_src_rgb;
116 glGetIntegerv(GL_BLEND_SRC_RGB, &saved_src_rgb);
117 GLint saved_src_alpha;
118 glGetIntegerv(GL_BLEND_SRC_ALPHA, &saved_src_alpha);
119 GLint saved_dst_rgb;
120 glGetIntegerv(GL_BLEND_DST_RGB, &saved_dst_rgb);
121 GLint saved_dst_alpha;
122 glGetIntegerv(GL_BLEND_DST_ALPHA, &saved_dst_alpha);
123
124 // Update framebuffer to write into.
125 size_t width = layers[0]->size.width;
126 size_t height = layers[0]->size.height;
127 if (self->framebuffer == nullptr ||
128 fl_framebuffer_get_width(self->framebuffer) != width ||
129 fl_framebuffer_get_height(self->framebuffer) != height) {
130 g_clear_object(&self->framebuffer);
131 self->framebuffer =
132 fl_framebuffer_new(general_format, width, height, self->shareable);
133
134 // If not shareable make buffer to copy frame pixels into.
135 if (!self->shareable) {
136 size_t data_length = width * height * 4;
137 self->pixels =
138 static_cast<uint8_t*>(g_realloc(self->pixels, data_length));
139 }
140 }
141
142 // FIXME(robert-ancell): The vertex array is the same for all views, but
143 // cannot be shared in OpenGL. Find a way to not generate this every time.
144 GLuint vao;
145 glGenVertexArrays(1, &vao);
146 glBindVertexArray(vao);
147
148 glEnable(GL_BLEND);
149 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
150
152
153 // Disable the scissor test as it can affect blit operations.
154 // Prevents regressions like: https://github.com/flutter/flutter/issues/140828
155 // See OpenGL specification version 4.6, section 18.3.1.
156 glDisable(GL_SCISSOR_TEST);
157
158 glBindFramebuffer(GL_DRAW_FRAMEBUFFER,
159 fl_framebuffer_get_id(self->framebuffer));
160 gboolean first_layer = TRUE;
161 for (size_t i = 0; i < layers_count; ++i) {
162 const FlutterLayer* layer = layers[i];
163 switch (layer->type) {
165 const FlutterBackingStore* backing_store = layer->backing_store;
166 FlFramebuffer* framebuffer =
167 FL_FRAMEBUFFER(backing_store->open_gl.framebuffer.user_data);
168 glBindFramebuffer(GL_READ_FRAMEBUFFER,
169 fl_framebuffer_get_id(framebuffer));
170 // The first layer can be blitted, and following layers composited with
171 // this.
172 if (first_layer) {
173 glBlitFramebuffer(layer->offset.x, layer->offset.y, layer->size.width,
174 layer->size.height, layer->offset.x,
175 layer->offset.y, layer->size.width,
176 layer->size.height, GL_COLOR_BUFFER_BIT,
177 GL_NEAREST);
178 first_layer = FALSE;
179 } else {
180 composite_layer(self, framebuffer, layer->offset.x, layer->offset.y,
181 width, height);
182 }
183 } break;
185 // TODO(robert-ancell) Not implemented -
186 // https://github.com/flutter/flutter/issues/41724
187 } break;
188 }
189 }
190 glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
191 glFlush();
192
193 glDeleteVertexArrays(1, &vao);
194
195 if (saved_blend) {
196 glEnable(GL_BLEND);
197 } else {
198 glDisable(GL_BLEND);
199 }
200 if (saved_scissor_test) {
201 glEnable(GL_SCISSOR_TEST);
202 } else {
203 glDisable(GL_SCISSOR_TEST);
204 }
205
206 glBindTexture(GL_TEXTURE_2D, saved_texture_binding);
207 glBindVertexArray(saved_vao_binding);
208 glBindBuffer(GL_ARRAY_BUFFER, saved_array_buffer_binding);
209 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, saved_draw_framebuffer_binding);
210 glUseProgram(saved_current_program);
211 glBlendFuncSeparate(saved_src_rgb, saved_dst_rgb, saved_src_alpha,
212 saved_dst_alpha);
213
214 if (!self->shareable) {
215 glBindFramebuffer(GL_READ_FRAMEBUFFER,
216 fl_framebuffer_get_id(self->framebuffer));
217 glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, self->pixels);
218 glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
219 }
220 glBindFramebuffer(GL_READ_FRAMEBUFFER, saved_read_framebuffer_binding);
221
222 return TRUE;
223}
224
226 size_t* width,
227 size_t* height) {
228 if (width != nullptr) {
229 *width = self->framebuffer != nullptr
230 ? fl_framebuffer_get_width(self->framebuffer)
231 : 0;
232 }
233 if (height != nullptr) {
234 *height = self->framebuffer != nullptr
235 ? fl_framebuffer_get_height(self->framebuffer)
236 : 0;
237 }
238}
239
240gboolean fl_compositor_opengl_render(FlCompositorOpenGL* self,
241 cairo_t* cr,
242 GdkWindow* window) {
243 if (self->framebuffer == nullptr) {
244 return FALSE;
245 }
246
247 gint scale_factor = gdk_window_get_scale_factor(window);
248 size_t width = gdk_window_get_width(window) * scale_factor;
249 size_t height = gdk_window_get_height(window) * scale_factor;
250
251 if (fl_framebuffer_get_shareable(self->framebuffer)) {
252 g_autoptr(FlFramebuffer) sibling =
255 GL_TEXTURE, scale_factor, 0, 0, width, height);
256 } else {
257 GLint saved_texture_binding;
258 glGetIntegerv(GL_TEXTURE_BINDING_2D, &saved_texture_binding);
259
260 GLuint texture_id;
261 glGenTextures(1, &texture_id);
262 glBindTexture(GL_TEXTURE_2D, texture_id);
263 GLsizei fb_width = 0;
264 GLsizei fb_height = 0;
265 if (self->framebuffer != nullptr) {
266 fb_width =
267 static_cast<GLsizei>(fl_framebuffer_get_width(self->framebuffer));
268 fb_height =
269 static_cast<GLsizei>(fl_framebuffer_get_height(self->framebuffer));
270 }
271 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, fb_width, fb_height, 0, GL_RGBA,
272 GL_UNSIGNED_BYTE, self->pixels);
273
274 gdk_cairo_draw_from_gl(cr, window, texture_id, GL_TEXTURE, scale_factor, 0,
275 0, width, height);
276
277 glDeleteTextures(1, &texture_id);
278
279 glBindTexture(GL_TEXTURE_2D, saved_texture_binding);
280 }
281
282 glFlush();
283
284 return TRUE;
285}
int32_t x
@ kFlutterLayerContentTypePlatformView
Indicates that the contents of this layer are determined by the embedder.
Definition embedder.h:2159
@ kFlutterLayerContentTypeBackingStore
Definition embedder.h:2157
GLFWwindow * window
Definition main.cc:60
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)
static void fl_compositor_opengl_dispose(GObject *object)
static void fl_compositor_opengl_init(FlCompositorOpenGL *self)
FlCompositorOpenGL * fl_compositor_opengl_new(FlOpenGLManager *opengl_manager, gboolean shareable)
void fl_compositor_opengl_get_frame_size(FlCompositorOpenGL *self, size_t *width, size_t *height)
static void fl_compositor_opengl_class_init(FlCompositorOpenGLClass *klass)
static void composite_layer(FlCompositorOpenGL *self, FlFramebuffer *framebuffer, double x, double y, int width, int height)
gboolean fl_compositor_opengl_render(FlCompositorOpenGL *self, cairo_t *cr, GdkWindow *window)
gboolean fl_compositor_opengl_composite_layers(FlCompositorOpenGL *self, const FlutterLayer **layers, size_t layers_count)
G_BEGIN_DECLS gboolean shareable
FlCompositorOpenGLShader * fl_compositor_opengl_shader_new(FlOpenGLManager *opengl_manager)
void fl_compositor_opengl_shader_set_offset(FlCompositorOpenGLShader *self, double x, double y)
void fl_compositor_opengl_shader_set_scale(FlCompositorOpenGLShader *self, double x, double y)
void fl_compositor_opengl_shader_use(FlCompositorOpenGLShader *self)
size_t fl_framebuffer_get_height(FlFramebuffer *self)
FlFramebuffer * fl_framebuffer_new(GLint format, size_t width, size_t height, gboolean shareable)
GLuint fl_framebuffer_get_id(FlFramebuffer *self)
FlFramebuffer * fl_framebuffer_create_sibling(FlFramebuffer *self)
gboolean fl_framebuffer_get_shareable(FlFramebuffer *self)
size_t fl_framebuffer_get_width(FlFramebuffer *self)
GLuint fl_framebuffer_get_texture_id(FlFramebuffer *self)
const FlutterLayer size_t layers_count
const FlutterLayer ** layers
bool epoxy_has_gl_extension(const char *extension)
void gdk_cairo_draw_from_gl(cairo_t *cr, GdkWindow *window, int source, int source_type, int buffer_scale, int x, int y, int width, int height)
Definition mock_gtk.cc:170
int gdk_window_get_width(GdkWindow *window)
Definition mock_gtk.cc:79
gint gdk_window_get_scale_factor(GdkWindow *window)
Definition mock_gtk.cc:95
int gdk_window_get_height(GdkWindow *window)
Definition mock_gtk.cc:87
double y
int32_t height
int32_t width
FlCompositorOpenGLShader * shader
FlOpenGLManager * opengl_manager
FlutterOpenGLBackingStore open_gl
The description of the OpenGL backing store.
Definition embedder.h:2132
FlutterPoint offset
Definition embedder.h:2200
FlutterLayerContentType type
Definition embedder.h:2189
const FlutterBackingStore * backing_store
Definition embedder.h:2193
FlutterSize size
The size of the layer (in physical pixels).
Definition embedder.h:2202
FlutterOpenGLFramebuffer framebuffer
Definition embedder.h:1975
void * user_data
User data to be returned on the invocation of the destruction callback.
Definition embedder.h:554
double height
Definition embedder.h:636
double width
Definition embedder.h:635
int64_t texture_id