@@ -48,6 +48,9 @@ typedef struct {
4848 // was rendered
4949 bool had_first_frame;
5050
51+ // True if we can use glBlitFramebuffer.
52+ bool has_gl_framebuffer_blit;
53+
5154 // Shader program.
5255 GLuint program;
5356
@@ -59,7 +62,7 @@ G_DEFINE_TYPE_WITH_PRIVATE(FlRenderer, fl_renderer, G_TYPE_OBJECT)
5962
6063// Returns the log for the given OpenGL shader. Must be freed by the caller.
6164static gchar* get_shader_log(GLuint shader) {
62- int log_length;
65+ GLint log_length;
6366 gchar* log;
6467
6568 glGetShaderiv (shader, GL_INFO_LOG_LENGTH, &log_length);
@@ -72,7 +75,7 @@ static gchar* get_shader_log(GLuint shader) {
7275
7376// Returns the log for the given OpenGL program. Must be freed by the caller.
7477static gchar* get_program_log (GLuint program) {
75- int log_length;
78+ GLint log_length;
7679 gchar* log;
7780
7881 glGetProgramiv (program, GL_INFO_LOG_LENGTH, &log_length);
@@ -100,6 +103,136 @@ static void fl_renderer_unblock_main_thread(FlRenderer* self) {
100103 }
101104}
102105
106+ static void setup_shader (FlRenderer* self) {
107+ FlRendererPrivate* priv = reinterpret_cast <FlRendererPrivate*>(
108+ fl_renderer_get_instance_private (self));
109+
110+ GLuint vertex_shader = glCreateShader (GL_VERTEX_SHADER);
111+ glShaderSource (vertex_shader, 1 , &vertex_shader_src, nullptr );
112+ glCompileShader (vertex_shader);
113+ GLint vertex_compile_status;
114+ glGetShaderiv (vertex_shader, GL_COMPILE_STATUS, &vertex_compile_status);
115+ if (vertex_compile_status == GL_FALSE) {
116+ g_autofree gchar* shader_log = get_shader_log (vertex_shader);
117+ g_warning (" Failed to compile vertex shader: %s" , shader_log);
118+ }
119+
120+ GLuint fragment_shader = glCreateShader (GL_FRAGMENT_SHADER);
121+ glShaderSource (fragment_shader, 1 , &fragment_shader_src, nullptr );
122+ glCompileShader (fragment_shader);
123+ GLint fragment_compile_status;
124+ glGetShaderiv (fragment_shader, GL_COMPILE_STATUS, &fragment_compile_status);
125+ if (fragment_compile_status == GL_FALSE) {
126+ g_autofree gchar* shader_log = get_shader_log (fragment_shader);
127+ g_warning (" Failed to compile fragment shader: %s" , shader_log);
128+ }
129+
130+ priv->program = glCreateProgram ();
131+ glAttachShader (priv->program , vertex_shader);
132+ glAttachShader (priv->program , fragment_shader);
133+ glLinkProgram (priv->program );
134+
135+ GLint link_status;
136+ glGetProgramiv (priv->program , GL_LINK_STATUS, &link_status);
137+ if (link_status == GL_FALSE) {
138+ g_autofree gchar* program_log = get_program_log (priv->program );
139+ g_warning (" Failed to link program: %s" , program_log);
140+ }
141+
142+ glDeleteShader (vertex_shader);
143+ glDeleteShader (fragment_shader);
144+ }
145+
146+ static void render_with_blit (FlRenderer* self) {
147+ FlRendererPrivate* priv = reinterpret_cast <FlRendererPrivate*>(
148+ fl_renderer_get_instance_private (self));
149+
150+ // Disable the scissor test as it can affect blit operations.
151+ // Prevents regressions like: https://github.com/flutter/flutter/issues/140828
152+ // See OpenGL specification version 4.6, section 18.3.1.
153+ glDisable (GL_SCISSOR_TEST);
154+
155+ for (guint i = 0 ; i < priv->textures ->len ; i++) {
156+ FlBackingStoreProvider* texture =
157+ FL_BACKING_STORE_PROVIDER (g_ptr_array_index (priv->textures , i));
158+
159+ uint32_t framebuffer_id =
160+ fl_backing_store_provider_get_gl_framebuffer_id (texture);
161+ glBindFramebuffer (GL_READ_FRAMEBUFFER, framebuffer_id);
162+ GdkRectangle geometry = fl_backing_store_provider_get_geometry (texture);
163+ glBlitFramebuffer (0 , 0 , geometry.width , geometry.height , geometry.x ,
164+ geometry.y , geometry.x + geometry.width ,
165+ geometry.y + geometry.height , GL_COLOR_BUFFER_BIT,
166+ GL_NEAREST);
167+ }
168+ glBindFramebuffer (GL_READ_FRAMEBUFFER, 0 );
169+ }
170+
171+ static void render_with_textures (FlRenderer* self, int width, int height) {
172+ FlRendererPrivate* priv = reinterpret_cast <FlRendererPrivate*>(
173+ fl_renderer_get_instance_private (self));
174+
175+ // Save bindings that are set by this function. All bindings must be restored
176+ // to their original values because Skia expects that its bindings have not
177+ // been altered.
178+ GLint saved_texture_binding;
179+ glGetIntegerv (GL_TEXTURE_BINDING_2D, &saved_texture_binding);
180+ GLint saved_vao_binding;
181+ glGetIntegerv (GL_VERTEX_ARRAY_BINDING, &saved_vao_binding);
182+ GLint saved_array_buffer_binding;
183+ glGetIntegerv (GL_ARRAY_BUFFER_BINDING, &saved_array_buffer_binding);
184+
185+ glUseProgram (priv->program );
186+
187+ for (guint i = 0 ; i < priv->textures ->len ; i++) {
188+ FlBackingStoreProvider* texture =
189+ FL_BACKING_STORE_PROVIDER (g_ptr_array_index (priv->textures , i));
190+
191+ uint32_t texture_id = fl_backing_store_provider_get_gl_texture_id (texture);
192+ glBindTexture (GL_TEXTURE_2D, texture_id);
193+
194+ // Translate into OpenGL co-ordinates
195+ GdkRectangle texture_geometry =
196+ fl_backing_store_provider_get_geometry (texture);
197+ GLfloat texture_x = texture_geometry.x ;
198+ GLfloat texture_y = texture_geometry.y ;
199+ GLfloat texture_width = texture_geometry.width ;
200+ GLfloat texture_height = texture_geometry.height ;
201+ GLfloat x0 = pixels_to_gl_coords (texture_x, width);
202+ GLfloat y0 =
203+ pixels_to_gl_coords (height - (texture_y + texture_height), height);
204+ GLfloat x1 = pixels_to_gl_coords (texture_x + texture_width, width);
205+ GLfloat y1 = pixels_to_gl_coords (height - texture_y, height);
206+ GLfloat vertex_data[] = {x0, y0, 0 , 0 , x1, y1, 1 , 1 , x0, y1, 0 , 1 ,
207+ x0, y0, 0 , 0 , x1, y0, 1 , 0 , x1, y1, 1 , 1 };
208+
209+ GLuint vao, vertex_buffer;
210+ glGenVertexArrays (1 , &vao);
211+ glBindVertexArray (vao);
212+ glGenBuffers (1 , &vertex_buffer);
213+ glBindBuffer (GL_ARRAY_BUFFER, vertex_buffer);
214+ glBufferData (GL_ARRAY_BUFFER, sizeof (vertex_data), vertex_data,
215+ GL_STATIC_DRAW);
216+ GLint position_index = glGetAttribLocation (priv->program , " position" );
217+ glEnableVertexAttribArray (position_index);
218+ glVertexAttribPointer (position_index, 2 , GL_FLOAT, GL_FALSE,
219+ sizeof (GLfloat) * 4 , 0 );
220+ GLint texcoord_index = glGetAttribLocation (priv->program , " in_texcoord" );
221+ glEnableVertexAttribArray (texcoord_index);
222+ glVertexAttribPointer (texcoord_index, 2 , GL_FLOAT, GL_FALSE,
223+ sizeof (GLfloat) * 4 , (void *)(sizeof (GLfloat) * 2 ));
224+
225+ glDrawArrays (GL_TRIANGLES, 0 , 6 );
226+
227+ glDeleteVertexArrays (1 , &vao);
228+ glDeleteBuffers (1 , &vertex_buffer);
229+ }
230+
231+ glBindTexture (GL_TEXTURE_2D, saved_texture_binding);
232+ glBindVertexArray (saved_vao_binding);
233+ glBindBuffer (GL_ARRAY_BUFFER, saved_array_buffer_binding);
234+ }
235+
103236static void fl_renderer_dispose (GObject* object) {
104237 FlRenderer* self = FL_RENDERER (object);
105238 FlRendererPrivate* priv = reinterpret_cast <FlRendererPrivate*>(
@@ -244,10 +377,6 @@ gboolean fl_renderer_present_layers(FlRenderer* self,
244377
245378 fl_renderer_unblock_main_thread (self);
246379
247- if (!priv->view ) {
248- return FALSE ;
249- }
250-
251380 g_ptr_array_set_size (priv->textures , 0 );
252381 for (size_t i = 0 ; i < layers_count; ++i) {
253382 const FlutterLayer* layer = layers[i];
@@ -266,7 +395,9 @@ gboolean fl_renderer_present_layers(FlRenderer* self,
266395 }
267396 }
268397
269- fl_view_redraw (priv->view );
398+ if (priv->view != nullptr ) {
399+ fl_view_redraw (priv->view );
400+ }
270401
271402 return TRUE ;
272403}
@@ -277,40 +408,13 @@ void fl_renderer_setup(FlRenderer* self) {
277408
278409 g_return_if_fail (FL_IS_RENDERER (self));
279410
280- GLuint vertex_shader = glCreateShader (GL_VERTEX_SHADER);
281- glShaderSource (vertex_shader, 1 , &vertex_shader_src, nullptr );
282- glCompileShader (vertex_shader);
283- int vertex_compile_status;
284- glGetShaderiv (vertex_shader, GL_COMPILE_STATUS, &vertex_compile_status);
285- if (vertex_compile_status == GL_FALSE) {
286- g_autofree gchar* shader_log = get_shader_log (vertex_shader);
287- g_warning (" Failed to compile vertex shader: %s" , shader_log);
288- }
411+ priv->has_gl_framebuffer_blit =
412+ epoxy_gl_version () >= 30 ||
413+ epoxy_has_gl_extension (" GL_EXT_framebuffer_blit" );
289414
290- GLuint fragment_shader = glCreateShader (GL_FRAGMENT_SHADER);
291- glShaderSource (fragment_shader, 1 , &fragment_shader_src, nullptr );
292- glCompileShader (fragment_shader);
293- int fragment_compile_status;
294- glGetShaderiv (fragment_shader, GL_COMPILE_STATUS, &fragment_compile_status);
295- if (fragment_compile_status == GL_FALSE) {
296- g_autofree gchar* shader_log = get_shader_log (fragment_shader);
297- g_warning (" Failed to compile fragment shader: %s" , shader_log);
415+ if (!priv->has_gl_framebuffer_blit ) {
416+ setup_shader (self);
298417 }
299-
300- priv->program = glCreateProgram ();
301- glAttachShader (priv->program , vertex_shader);
302- glAttachShader (priv->program , fragment_shader);
303- glLinkProgram (priv->program );
304-
305- int link_status;
306- glGetProgramiv (priv->program , GL_LINK_STATUS, &link_status);
307- if (link_status == GL_FALSE) {
308- g_autofree gchar* program_log = get_program_log (priv->program );
309- g_warning (" Failed to link program: %s" , program_log);
310- }
311-
312- glDeleteShader (vertex_shader);
313- glDeleteShader (fragment_shader);
314418}
315419
316420void fl_renderer_render (FlRenderer* self, int width, int height) {
@@ -319,70 +423,16 @@ void fl_renderer_render(FlRenderer* self, int width, int height) {
319423
320424 g_return_if_fail (FL_IS_RENDERER (self));
321425
322- // Save bindings that are set by this function. All bindings must be restored
323- // to their original values because Skia expects that its bindings have not
324- // been altered.
325- GLint saved_texture_binding;
326- glGetIntegerv (GL_TEXTURE_BINDING_2D, &saved_texture_binding);
327- GLint saved_vao_binding;
328- glGetIntegerv (GL_VERTEX_ARRAY_BINDING, &saved_vao_binding);
329- GLint saved_array_buffer_binding;
330- glGetIntegerv (GL_ARRAY_BUFFER_BINDING, &saved_array_buffer_binding);
331-
332426 glClearColor (0.0 , 0.0 , 0.0 , 1.0 );
333427 glClear (GL_COLOR_BUFFER_BIT);
334428
335- glUseProgram (priv->program );
336-
337- for (guint i = 0 ; i < priv->textures ->len ; i++) {
338- FlBackingStoreProvider* texture =
339- FL_BACKING_STORE_PROVIDER (g_ptr_array_index (priv->textures , i));
340-
341- uint32_t texture_id = fl_backing_store_provider_get_gl_texture_id (texture);
342- glBindTexture (GL_TEXTURE_2D, texture_id);
343-
344- // Translate into OpenGL co-ordinates
345- GdkRectangle texture_geometry =
346- fl_backing_store_provider_get_geometry (texture);
347- GLfloat texture_x = texture_geometry.x ;
348- GLfloat texture_y = texture_geometry.y ;
349- GLfloat texture_width = texture_geometry.width ;
350- GLfloat texture_height = texture_geometry.height ;
351- GLfloat x0 = pixels_to_gl_coords (texture_x, width);
352- GLfloat y0 =
353- pixels_to_gl_coords (height - (texture_y + texture_height), height);
354- GLfloat x1 = pixels_to_gl_coords (texture_x + texture_width, width);
355- GLfloat y1 = pixels_to_gl_coords (height - texture_y, height);
356- GLfloat vertex_data[] = {x0, y0, 0 , 0 , x1, y1, 1 , 1 , x0, y1, 0 , 1 ,
357- x0, y0, 0 , 0 , x1, y0, 1 , 0 , x1, y1, 1 , 1 };
358-
359- GLuint vao, vertex_buffer;
360- glGenVertexArrays (1 , &vao);
361- glBindVertexArray (vao);
362- glGenBuffers (1 , &vertex_buffer);
363- glBindBuffer (GL_ARRAY_BUFFER, vertex_buffer);
364- glBufferData (GL_ARRAY_BUFFER, sizeof (vertex_data), vertex_data,
365- GL_STATIC_DRAW);
366- GLint position_index = glGetAttribLocation (priv->program , " position" );
367- glEnableVertexAttribArray (position_index);
368- glVertexAttribPointer (position_index, 2 , GL_FLOAT, GL_FALSE,
369- sizeof (GLfloat) * 4 , 0 );
370- GLint texcoord_index = glGetAttribLocation (priv->program , " in_texcoord" );
371- glEnableVertexAttribArray (texcoord_index);
372- glVertexAttribPointer (texcoord_index, 2 , GL_FLOAT, GL_FALSE,
373- sizeof (GLfloat) * 4 , (void *)(sizeof (GLfloat) * 2 ));
374-
375- glDrawArrays (GL_TRIANGLES, 0 , 6 );
376-
377- glDeleteVertexArrays (1 , &vao);
378- glDeleteBuffers (1 , &vertex_buffer);
429+ if (priv->has_gl_framebuffer_blit ) {
430+ render_with_blit (self);
431+ } else {
432+ render_with_textures (self, width, height);
379433 }
380434
381435 glFlush ();
382-
383- glBindTexture (GL_TEXTURE_2D, saved_texture_binding);
384- glBindVertexArray (saved_vao_binding);
385- glBindBuffer (GL_ARRAY_BUFFER, saved_array_buffer_binding);
386436}
387437
388438void fl_renderer_cleanup (FlRenderer* self) {
@@ -391,5 +441,7 @@ void fl_renderer_cleanup(FlRenderer* self) {
391441
392442 g_return_if_fail (FL_IS_RENDERER (self));
393443
394- glDeleteProgram (priv->program );
444+ if (priv->program != 0 ) {
445+ glDeleteProgram (priv->program );
446+ }
395447}
0 commit comments