Flutter Engine Uber Docs
Docs for the entire Flutter Engine repo.
 
Loading...
Searching...
No Matches
fl_compositor_opengl.h File Reference

Go to the source code of this file.

Functions

G_BEGIN_DECLS G_DECLARE_FINAL_TYPE (FlCompositorOpenGL, fl_compositor_opengl, FL, COMPOSITOR_OPENGL, GObject) FlCompositorOpenGL *fl_compositor_opengl_new(FlOpenGLManager *opengl_manager
 
gboolean fl_compositor_opengl_composite_layers (FlCompositorOpenGL *compositor, const FlutterLayer **layers, size_t layers_count)
 
void fl_compositor_opengl_get_frame_size (FlCompositorOpenGL *compositor, size_t *width, size_t *height)
 
gboolean fl_compositor_opengl_render (FlCompositorOpenGL *compositor, cairo_t *cr, GdkWindow *window)
 

Variables

G_BEGIN_DECLS gboolean shareable
 

Function Documentation

◆ fl_compositor_opengl_composite_layers()

gboolean fl_compositor_opengl_composite_layers ( FlCompositorOpenGL *  compositor,
const FlutterLayer **  layers,
size_t  layers_count 
)

fl_compositor_opengl_composite_layers: @compositor: an #FlCompositorOpenGL. @layers: layers to be composited. @layers_count: number of layers.

Composite layers into the stored frame using the current OpenGL context.

Returns TRUE if successful.

Definition at line 86 of file fl_compositor_opengl.cc.

88 {
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}
@ kFlutterLayerContentTypePlatformView
Indicates that the contents of this layer are determined by the embedder.
Definition embedder.h:2159
@ kFlutterLayerContentTypeBackingStore
Definition embedder.h:2157
static void composite_layer(FlCompositorOpenGL *self, FlFramebuffer *framebuffer, double x, double y, int width, int height)
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)
size_t fl_framebuffer_get_width(FlFramebuffer *self)
const FlutterLayer size_t layers_count
const FlutterLayer ** layers
bool epoxy_has_gl_extension(const char *extension)
int32_t height
int32_t width
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

References FlutterLayer::backing_store, composite_layer(), epoxy_has_gl_extension(), fl_compositor_opengl_shader_use(), fl_framebuffer_get_height(), fl_framebuffer_get_id(), fl_framebuffer_get_width(), fl_framebuffer_new(), FlutterOpenGLBackingStore::framebuffer, height, FlutterSize::height, i, kFlutterLayerContentTypeBackingStore, kFlutterLayerContentTypePlatformView, layers, layers_count, FlutterLayer::offset, FlutterBackingStore::open_gl, self, FlutterLayer::size, TRUE, FlutterLayer::type, FlutterOpenGLFramebuffer::user_data, width, FlutterSize::width, FlutterPoint::x, and FlutterPoint::y.

Referenced by fl_view_renderer_opengl_present_layers(), TEST_F(), TEST_F(), TEST_F(), TEST_F(), TEST_F(), TEST_F(), TEST_F(), and TEST_F().

◆ fl_compositor_opengl_get_frame_size()

void fl_compositor_opengl_get_frame_size ( FlCompositorOpenGL *  compositor,
size_t *  width,
size_t *  height 
)

fl_compositor_opengl_get_frame_size: @compositor: an #FlCompositorOpenGL. @width: location to write frame width in pixels. @height: location to write frame height in pixels.

Get the size of the layer ready for rendering.

Definition at line 225 of file fl_compositor_opengl.cc.

227 {
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}

References fl_framebuffer_get_height(), fl_framebuffer_get_width(), height, self, and width.

Referenced by G_DEFINE_TYPE(), TEST_F(), TEST_F(), and wait_for_frame().

◆ fl_compositor_opengl_render()

gboolean fl_compositor_opengl_render ( FlCompositorOpenGL *  compositor,
cairo_t *  cr,
GdkWindow *  window 
)

fl_compositor_opengl_render: @compositor: an #FlCompositorOpenGL. @cr: a Cairo rendering context. @window: window being rendered into.

Renders the current frame using the current OpenGL context.

Returns TRUE if successful.

Definition at line 240 of file fl_compositor_opengl.cc.

242 {
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}
GLFWwindow * window
Definition main.cc:60
g_autoptr(FlEngine) engine
FlFramebuffer * fl_framebuffer_create_sibling(FlFramebuffer *self)
gboolean fl_framebuffer_get_shareable(FlFramebuffer *self)
GLuint fl_framebuffer_get_texture_id(FlFramebuffer *self)
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
int64_t texture_id

References fl_framebuffer_create_sibling(), fl_framebuffer_get_height(), fl_framebuffer_get_shareable(), fl_framebuffer_get_texture_id(), fl_framebuffer_get_width(), g_autoptr(), gdk_cairo_draw_from_gl(), gdk_window_get_height(), gdk_window_get_scale_factor(), gdk_window_get_width(), height, self, texture_id, TRUE, width, and window.

Referenced by fl_view_renderer_opengl_draw(), TEST_F(), TEST_F(), TEST_F(), TEST_F(), TEST_F(), TEST_F(), TEST_F(), and TEST_F().

◆ G_DECLARE_FINAL_TYPE()

G_BEGIN_DECLS G_DECLARE_FINAL_TYPE ( FlCompositorOpenGL  ,
fl_compositor_opengl  ,
FL  ,
COMPOSITOR_OPENGL  ,
GObject   
)

FlCompositorOpenGL:

#FlCompositorOpenGL is class that implements compositing using OpenGL.

The composited frame is stored in an OpenGL framebuffer (texture).

A frame may be written by fl_compositor_opengl_composite_layers using one OpenGL context and read by fl_compositor_opengl_render using another. When the compositor is created as shareable the two contexts must belong to the same share group so the frame texture can be accessed from both, and the writing context issues a glFlush() so the frame is visible to the reading context. When not shareable the frame is copied to CPU memory by the writing context and uploaded into a new texture by the reading context. fl_compositor_opengl_new: @opengl_manager: an #FlOpenGLManager @shareable: TRUE if the compositor can use a framebuffer that is shared between contexts.

Creates a new OpenGL compositor.

Returns: a new #FlCompositorOpenGL.

Variable Documentation

◆ shareable

G_BEGIN_DECLS gboolean shareable