Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit b043fe4

Browse files
Use glBlitFramebuffer when rendering (#53080)
This is much faster than using a shader which is not required currently (we are not doing any transformations).
1 parent e3abca2 commit b043fe4

File tree

4 files changed

+380
-105
lines changed

4 files changed

+380
-105
lines changed

shell/platform/linux/fl_renderer.cc

Lines changed: 150 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -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.
6164
static 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.
7477
static 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+
103236
static 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

316420
void 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

388438
void 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

Comments
 (0)