Flutter Linux Embedder
fl_compositor_opengl_shader.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/gl.h>
8 
9 // Vertex shader to draw Flutter window contents.
10 static const char* vertex_shader_src =
11  "attribute vec2 position;\n"
12  "attribute vec2 in_texcoord;\n"
13  "uniform vec2 offset;\n"
14  "uniform vec2 scale;\n"
15  "varying vec2 texcoord;\n"
16  "\n"
17  "void main() {\n"
18  " gl_Position = vec4(offset + position * scale, 0, 1);\n"
19  " texcoord = in_texcoord;\n"
20  "}\n";
21 
22 // Fragment shader to draw Flutter window contents.
23 static const char* fragment_shader_src =
24  "#ifdef GL_ES\n"
25  "precision mediump float;\n"
26  "#endif\n"
27  "\n"
28  "uniform sampler2D texture;\n"
29  "varying vec2 texcoord;\n"
30  "\n"
31  "void main() {\n"
32  " gl_FragColor = texture2D(texture, texcoord);\n"
33  "}\n";
34 
36  GObject parent_instance;
37 
38  // Flutter OpenGL contexts.
39  FlOpenGLManager* opengl_manager;
40 
41  // Shader program.
42  GLuint program;
43 
44  // Location of layer offset in [program].
46 
47  // Location of layer scale in [program].
49 
50  // Verticies for the uniform square.
51  GLuint vertex_buffer;
52 };
53 
54 G_DEFINE_TYPE(FlCompositorOpenGLShader,
55  fl_compositor_opengl_shader,
56  G_TYPE_OBJECT)
57 
58 // Returns the log for the given OpenGL shader. Must be freed by the caller.
59 static gchar* get_shader_log(GLuint shader) {
60  GLint log_length;
61  gchar* log;
62 
63  glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_length);
64 
65  log = static_cast<gchar*>(g_malloc(log_length + 1));
66  glGetShaderInfoLog(shader, log_length, nullptr, log);
67 
68  return log;
69 }
70 
71 // Returns the log for the given OpenGL program. Must be freed by the caller.
72 static gchar* get_program_log(GLuint program) {
73  GLint log_length;
74  gchar* log;
75 
76  glGetProgramiv(program, GL_INFO_LOG_LENGTH, &log_length);
77 
78  log = static_cast<gchar*>(g_malloc(log_length + 1));
79  glGetProgramInfoLog(program, log_length, nullptr, log);
80 
81  return log;
82 }
83 
84 static void setup_shader(FlCompositorOpenGLShader* self) {
85  if (!fl_opengl_manager_make_platform_current(self->opengl_manager)) {
86  g_warning(
87  "Failed to setup compositor shaders, unable to make OpenGL context "
88  "current");
89  return;
90  }
91 
92  GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER);
93  glShaderSource(vertex_shader, 1, &vertex_shader_src, nullptr);
94  glCompileShader(vertex_shader);
95  GLint vertex_compile_status;
96  glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &vertex_compile_status);
97  if (vertex_compile_status == GL_FALSE) {
98  g_autofree gchar* shader_log = get_shader_log(vertex_shader);
99  g_warning("Failed to compile vertex shader: %s", shader_log);
100  }
101 
102  GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
103  glShaderSource(fragment_shader, 1, &fragment_shader_src, nullptr);
104  glCompileShader(fragment_shader);
105  GLint fragment_compile_status;
106  glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &fragment_compile_status);
107  if (fragment_compile_status == GL_FALSE) {
108  g_autofree gchar* shader_log = get_shader_log(fragment_shader);
109  g_warning("Failed to compile fragment shader: %s", shader_log);
110  }
111 
112  self->program = glCreateProgram();
113  glAttachShader(self->program, vertex_shader);
114  glAttachShader(self->program, fragment_shader);
115  glLinkProgram(self->program);
116 
117  GLint link_status;
118  glGetProgramiv(self->program, GL_LINK_STATUS, &link_status);
119  if (link_status == GL_FALSE) {
120  g_autofree gchar* program_log = get_program_log(self->program);
121  g_warning("Failed to link program: %s", program_log);
122  }
123 
124  self->offset_location = glGetUniformLocation(self->program, "offset");
125  self->scale_location = glGetUniformLocation(self->program, "scale");
126 
127  glDeleteShader(vertex_shader);
128  glDeleteShader(fragment_shader);
129 
130  // The uniform square abcd in two triangles cba + cdb
131  // a--b
132  // | |
133  // c--d
134  GLfloat const vertex_data[] = {-1, -1, 0, 0, 1, 1, 1, 1, -1, 1, 0, 1,
135  -1, -1, 0, 0, 1, -1, 1, 0, 1, 1, 1, 1};
136 
137  glGenBuffers(1, &self->vertex_buffer);
138  glBindBuffer(GL_ARRAY_BUFFER, self->vertex_buffer);
139  glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data,
140  GL_STATIC_DRAW);
141 }
142 
143 static void fl_compositor_opengl_shader_dispose(GObject* object) {
144  FlCompositorOpenGLShader* self = FL_COMPOSITOR_OPENGL_SHADER(object);
145 
146  if (self->opengl_manager != nullptr) {
147  if (fl_opengl_manager_make_platform_current(self->opengl_manager)) {
148  if (self->program != 0) {
149  glDeleteProgram(self->program);
150  }
151  if (self->vertex_buffer != 0) {
152  glDeleteBuffers(1, &self->vertex_buffer);
153  }
154  } else {
155  g_warning(
156  "Failed to cleanup compositor shaders, unable to make OpenGL context "
157  "current");
158  }
159  }
160  self->program = 0;
161  self->vertex_buffer = 0;
162 
163  g_clear_object(&self->opengl_manager);
164 
165  G_OBJECT_CLASS(fl_compositor_opengl_shader_parent_class)->dispose(object);
166 }
167 
169  FlCompositorOpenGLShaderClass* klass) {
170  G_OBJECT_CLASS(klass)->dispose = fl_compositor_opengl_shader_dispose;
171 }
172 
173 static void fl_compositor_opengl_shader_init(FlCompositorOpenGLShader* self) {}
174 
175 FlCompositorOpenGLShader* fl_compositor_opengl_shader_new(
176  FlOpenGLManager* opengl_manager) {
177  g_return_val_if_fail(FL_IS_OPENGL_MANAGER(opengl_manager), nullptr);
178 
179  FlCompositorOpenGLShader* self = FL_COMPOSITOR_OPENGL_SHADER(
180  g_object_new(fl_compositor_opengl_shader_get_type(), nullptr));
181 
182  self->opengl_manager = FL_OPENGL_MANAGER(g_object_ref(opengl_manager));
183 
184  setup_shader(self);
185 
186  return self;
187 }
188 
189 void fl_compositor_opengl_shader_use(FlCompositorOpenGLShader* self) {
190  g_return_if_fail(FL_IS_COMPOSITOR_OPENGL_SHADER(self));
191 
192  glBindBuffer(GL_ARRAY_BUFFER, self->vertex_buffer);
193  GLint position_location = glGetAttribLocation(self->program, "position");
194  glEnableVertexAttribArray(position_location);
195  glVertexAttribPointer(position_location, 2, GL_FLOAT, GL_FALSE,
196  sizeof(GLfloat) * 4, 0);
197  GLint texcoord_location = glGetAttribLocation(self->program, "in_texcoord");
198  glEnableVertexAttribArray(texcoord_location);
199  glVertexAttribPointer(texcoord_location, 2, GL_FLOAT, GL_FALSE,
200  sizeof(GLfloat) * 4,
201  reinterpret_cast<void*>(sizeof(GLfloat) * 2));
202 
203  glUseProgram(self->program);
204 }
205 
206 void fl_compositor_opengl_shader_set_offset(FlCompositorOpenGLShader* self,
207  double x,
208  double y) {
209  g_return_if_fail(FL_IS_COMPOSITOR_OPENGL_SHADER(self));
210  glUniform2f(self->offset_location, x, y);
211 }
212 
213 void fl_compositor_opengl_shader_set_scale(FlCompositorOpenGLShader* self,
214  double x,
215  double y) {
216  g_return_if_fail(FL_IS_COMPOSITOR_OPENGL_SHADER(self));
217  glUniform2f(self->scale_location, x, y);
218 }
FlFramebuffer double x
FlFramebuffer double double y
G_BEGIN_DECLS FlOpenGLManager * opengl_manager
static void setup_shader(FlCompositorOpenGLShader *self)
static const char * fragment_shader_src
static gchar * get_program_log(GLuint program)
static void fl_compositor_opengl_shader_dispose(GObject *object)
static void fl_compositor_opengl_shader_init(FlCompositorOpenGLShader *self)
void fl_compositor_opengl_shader_set_offset(FlCompositorOpenGLShader *self, double x, double y)
FlCompositorOpenGLShader * fl_compositor_opengl_shader_new(FlOpenGLManager *opengl_manager)
void fl_compositor_opengl_shader_set_scale(FlCompositorOpenGLShader *self, double x, double y)
static void fl_compositor_opengl_shader_class_init(FlCompositorOpenGLShaderClass *klass)
void fl_compositor_opengl_shader_use(FlCompositorOpenGLShader *self)
static const char * vertex_shader_src
G_DEFINE_TYPE(FlCompositorOpenGLShader, fl_compositor_opengl_shader, G_TYPE_OBJECT) static gchar *get_shader_log(GLuint shader)
gboolean fl_opengl_manager_make_platform_current(FlOpenGLManager *self)