1 /**
2  * @file lv_opengles_driver.c
3  *
4  */
5 
6 /*********************
7  *      INCLUDES
8  *********************/
9 #include "../../display/lv_display.h"
10 #include "../../misc/lv_area_private.h"
11 
12 #if LV_USE_OPENGLES
13 
14 #include "lv_opengles_debug.h"
15 #include "lv_opengles_driver.h"
16 
17 /*********************
18  *      DEFINES
19  *********************/
20 
21 #define LV_OPENGLES_VERTEX_BUFFER_LEN 16
22 
23 /**********************
24  *      TYPEDEFS
25  **********************/
26 
27 /**********************
28  *  STATIC PROTOTYPES
29  **********************/
30 static void lv_opengles_render_internal(unsigned int texture, const lv_area_t * texture_area, lv_opa_t opa,
31                                         int32_t disp_w, int32_t disp_h, const lv_area_t * texture_clip_area, bool flip, lv_color_t fill_color);
32 static void lv_opengles_enable_blending(void);
33 static void lv_opengles_vertex_buffer_init(const void * data, unsigned int size);
34 static void lv_opengles_vertex_buffer_deinit(void);
35 static void lv_opengles_vertex_buffer_bind(void);
36 static void lv_opengles_vertex_buffer_unbind(void);
37 static void lv_opengles_vertex_array_init(void);
38 static void lv_opengles_vertex_array_deinit(void);
39 static void lv_opengles_vertex_array_bind(void);
40 static void lv_opengles_vertex_array_unbind(void);
41 static void lv_opengles_vertex_array_add_buffer(void);
42 static void lv_opengles_index_buffer_init(const unsigned int * data, unsigned int count);
43 static void lv_opengles_index_buffer_deinit(void);
44 static unsigned int lv_opengles_index_buffer_get_count(void);
45 static void lv_opengles_index_buffer_bind(void);
46 static void lv_opengles_index_buffer_unbind(void);
47 static unsigned int lv_opengles_shader_compile(unsigned int type, const char * source);
48 static unsigned int lv_opengles_shader_create(const char * vertexShader, const char * fragmentShader);
49 static void lv_opengles_shader_init(void);
50 static void lv_opengles_shader_deinit(void);
51 static void lv_opengles_shader_bind(void);
52 static void lv_opengles_shader_unbind(void);
53 static int lv_opengles_shader_get_uniform_location(const char * name);
54 static void lv_opengles_shader_set_uniform1i(const char * name, int value);
55 static void lv_opengles_shader_set_uniformmatrix3fv(const char * name, int count, bool transpose, const float * values);
56 static void lv_opengles_shader_set_uniform1f(const char * name, float value);
57 static void lv_opengles_shader_set_uniform3f(const char * name, float value_0, float value_1, float value_2);
58 static void lv_opengles_render_draw(void);
59 static float lv_opengles_map_float(float x, float min_in, float max_in, float min_out, float max_out);
60 
61 /***********************
62  *   GLOBAL PROTOTYPES
63  ***********************/
64 
65 /**********************
66  *  STATIC VARIABLES
67  **********************/
68 static bool is_init;
69 
70 static unsigned int vertex_buffer_id = 0;
71 
72 static unsigned int vertex_array_id = 0;
73 
74 static unsigned int index_buffer_id = 0;
75 static unsigned int index_buffer_count = 0;
76 
77 static unsigned int shader_id;
78 
79 static const char * shader_names[] = { "u_Texture", "u_ColorDepth", "u_VertexTransform", "u_Opa", "u_IsFill", "u_FillColor" };
80 static int shader_location[] = { 0, 0, 0, 0, 0, 0 };
81 
82 static const char * vertex_shader =
83     "#version 300 es\n"
84     "\n"
85     "in vec4 position;\n"
86     "in vec2 texCoord;\n"
87     "\n"
88     "out vec2 v_TexCoord;\n"
89     "\n"
90     "uniform mat3 u_VertexTransform;\n"
91     "\n"
92     "void main()\n"
93     "{\n"
94     "    gl_Position = vec4((u_VertexTransform * vec3(position.xy, 1)).xy, position.zw);\n"
95     "    v_TexCoord = texCoord;\n"
96     "};\n";
97 
98 static const char * fragment_shader =
99     "#version 300 es\n"
100     "\n"
101     "precision lowp float;\n"
102     "\n"
103     "layout(location = 0) out vec4 color;\n"
104     "\n"
105     "in vec2 v_TexCoord;\n"
106     "\n"
107     "uniform sampler2D u_Texture;\n"
108     "uniform int u_ColorDepth;\n"
109     "uniform float u_Opa;\n"
110     "uniform bool u_IsFill;\n"
111     "uniform vec3 u_FillColor;\n"
112     "\n"
113     "void main()\n"
114     "{\n"
115     "    vec4 texColor;\n"
116     "    if (u_IsFill) {\n"
117     "        texColor = vec4(u_FillColor, 1.0f);\n"
118     "    } else {\n"
119     "        texColor = texture(u_Texture, v_TexCoord);\n"
120     "    }\n"
121     "    if (u_ColorDepth == 8) {\n"
122     "        float gray = texColor.r;\n"
123     "        color = vec4(gray, gray, gray, u_Opa);\n"
124     "    } else {\n"
125     "        float combinedAlpha = texColor.a * u_Opa;\n"
126     "        color = vec4(texColor.rgb * combinedAlpha, combinedAlpha);\n"
127     "    }\n"
128     "};\n";
129 
130 /**********************
131  *      MACROS
132  **********************/
133 
134 /**********************
135  *   GLOBAL FUNCTIONS
136  **********************/
137 
lv_opengles_init(void)138 void lv_opengles_init(void)
139 {
140     if(is_init) return;
141 
142     lv_opengles_enable_blending();
143 
144     unsigned int indices[] = {
145         0, 1, 2,
146         2, 3, 0
147     };
148 
149     lv_opengles_vertex_buffer_init(NULL, sizeof(float) * LV_OPENGLES_VERTEX_BUFFER_LEN);
150 
151     lv_opengles_vertex_array_init();
152     lv_opengles_vertex_array_add_buffer();
153 
154     lv_opengles_index_buffer_init(indices, 6);
155 
156     lv_opengles_shader_init();
157     lv_opengles_shader_bind();
158 
159     /* unbind everything */
160     lv_opengles_vertex_array_unbind();
161     lv_opengles_vertex_buffer_unbind();
162     lv_opengles_index_buffer_unbind();
163     lv_opengles_shader_unbind();
164 
165     is_init = true;
166 }
167 
lv_opengles_deinit(void)168 void lv_opengles_deinit(void)
169 {
170     if(!is_init) return;
171 
172     lv_opengles_shader_deinit();
173     lv_opengles_index_buffer_deinit();
174     lv_opengles_vertex_buffer_deinit();
175     lv_opengles_vertex_array_deinit();
176 
177     is_init = false;
178 }
179 
lv_opengles_render_texture(unsigned int texture,const lv_area_t * texture_area,lv_opa_t opa,int32_t disp_w,int32_t disp_h,const lv_area_t * texture_clip_area,bool flip)180 void lv_opengles_render_texture(unsigned int texture, const lv_area_t * texture_area, lv_opa_t opa, int32_t disp_w,
181                                 int32_t disp_h, const lv_area_t * texture_clip_area, bool flip)
182 {
183     lv_opengles_render_internal(texture, texture_area, opa, disp_w, disp_h, texture_clip_area, flip, lv_color_black());
184 }
185 
lv_opengles_render_fill(lv_color_t color,const lv_area_t * area,lv_opa_t opa,int32_t disp_w,int32_t disp_h)186 void lv_opengles_render_fill(lv_color_t color, const lv_area_t * area, lv_opa_t opa, int32_t disp_w, int32_t disp_h)
187 {
188     lv_opengles_render_internal(0, area, opa, disp_w, disp_h, area, false, color);
189 }
190 
lv_opengles_render_clear(void)191 void lv_opengles_render_clear(void)
192 {
193     GL_CALL(glClear(GL_COLOR_BUFFER_BIT));
194 }
195 
lv_opengles_viewport(int32_t x,int32_t y,int32_t w,int32_t h)196 void lv_opengles_viewport(int32_t x, int32_t y, int32_t w, int32_t h)
197 {
198     glViewport(x, y, w, h);
199 }
200 
201 /**********************
202  *   STATIC FUNCTIONS
203  **********************/
204 
lv_opengles_render_internal(unsigned int texture,const lv_area_t * texture_area,lv_opa_t opa,int32_t disp_w,int32_t disp_h,const lv_area_t * texture_clip_area,bool flip,lv_color_t fill_color)205 static void lv_opengles_render_internal(unsigned int texture, const lv_area_t * texture_area, lv_opa_t opa,
206                                         int32_t disp_w, int32_t disp_h, const lv_area_t * texture_clip_area, bool flip, lv_color_t fill_color)
207 {
208     lv_area_t intersection;
209     if(!lv_area_intersect(&intersection, texture_area, texture_clip_area)) return;
210 
211     GL_CALL(glActiveTexture(GL_TEXTURE0));
212     GL_CALL(glBindTexture(GL_TEXTURE_2D, texture));
213 
214     float tex_w = (float)lv_area_get_width(&intersection);
215     float tex_h = (float)lv_area_get_height(&intersection);
216 
217     float hor_scale = tex_w / (float)disp_w;
218     float ver_scale = tex_h / (float)disp_h;
219     float hor_translate = (float)intersection.x1 / (float)disp_w * 2.0f - (1.0f - hor_scale);
220     float ver_translate = -((float)intersection.y1 / (float)disp_h * 2.0f - (1.0f - ver_scale));
221     if(flip) ver_scale = -ver_scale;
222     float matrix[9] = {
223         hor_scale, 0.0f,      hor_translate,
224         0.0f,      ver_scale, ver_translate,
225         0.0f,      0.0f,      1.0f
226     };
227 
228     if(texture != 0) {
229         float x_coef = 1.0f / (float)(2 * lv_area_get_width(texture_area));
230         float y_coef = 1.0f / (float)(2 * lv_area_get_height(texture_area));
231         float tex_clip_x1 = lv_opengles_map_float(texture_clip_area->x1, texture_area->x1, texture_area->x2, x_coef,
232                                                   1.0f - x_coef);
233         float tex_clip_x2 = lv_opengles_map_float(texture_clip_area->x2, texture_area->x1, texture_area->x2, x_coef,
234                                                   1.0f - x_coef);
235         float tex_clip_y1 = lv_opengles_map_float(texture_clip_area->y1, texture_area->y1, texture_area->y2, y_coef,
236                                                   1.0f - y_coef);
237         float tex_clip_y2 = lv_opengles_map_float(texture_clip_area->y2, texture_area->y1, texture_area->y2, y_coef,
238                                                   1.0f - y_coef);
239 
240         float positions[LV_OPENGLES_VERTEX_BUFFER_LEN] = {
241             -1.0f,  1.0f,  tex_clip_x1, tex_clip_y2,
242             1.0f,  1.0f,  tex_clip_x2, tex_clip_y2,
243             1.0f, -1.0f,  tex_clip_x2, tex_clip_y1,
244             -1.0f, -1.0f,  tex_clip_x1, tex_clip_y1
245         };
246         lv_opengles_vertex_buffer_init(positions, sizeof(positions));
247     }
248 
249     lv_opengles_shader_bind();
250     lv_opengles_shader_set_uniform1i("u_ColorDepth", LV_COLOR_DEPTH);
251     lv_opengles_shader_set_uniform1i("u_Texture", 0);
252     lv_opengles_shader_set_uniformmatrix3fv("u_VertexTransform", 1, true, matrix);
253     lv_opengles_shader_set_uniform1f("u_Opa", (float)opa / (float)LV_OPA_100);
254     lv_opengles_shader_set_uniform1i("u_IsFill", texture == 0);
255     lv_opengles_shader_set_uniform3f("u_FillColor", (float)fill_color.red / 255.0f, (float)fill_color.green / 255.0f,
256                                      (float)fill_color.blue / 255.0f);
257     lv_opengles_render_draw();
258 }
259 
lv_opengles_enable_blending(void)260 static void lv_opengles_enable_blending(void)
261 {
262     glEnable(GL_BLEND);
263     glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
264 }
265 
lv_opengles_vertex_buffer_init(const void * data,unsigned int size)266 static void lv_opengles_vertex_buffer_init(const void * data, unsigned int size)
267 {
268     if(vertex_buffer_id == 0) GL_CALL(glGenBuffers(1, &vertex_buffer_id));
269     GL_CALL(glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_id));
270     GL_CALL(glBufferData(GL_ARRAY_BUFFER, size, data, GL_DYNAMIC_DRAW));
271 }
272 
lv_opengles_vertex_buffer_deinit(void)273 static void lv_opengles_vertex_buffer_deinit(void)
274 {
275     if(vertex_buffer_id == 0) return;
276     GL_CALL(glDeleteBuffers(1, &vertex_buffer_id));
277     vertex_buffer_id = 0;
278 }
279 
lv_opengles_vertex_buffer_bind(void)280 static void lv_opengles_vertex_buffer_bind(void)
281 {
282     GL_CALL(glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_id));
283 }
284 
lv_opengles_vertex_buffer_unbind(void)285 static void lv_opengles_vertex_buffer_unbind(void)
286 {
287     GL_CALL(glBindBuffer(GL_ARRAY_BUFFER, 0));
288 }
289 
lv_opengles_vertex_array_init(void)290 static void lv_opengles_vertex_array_init(void)
291 {
292     if(vertex_array_id == 0) GL_CALL(glGenVertexArrays(1, &vertex_array_id));
293 }
294 
lv_opengles_vertex_array_deinit(void)295 static void lv_opengles_vertex_array_deinit(void)
296 {
297     if(vertex_array_id == 0) return;
298     GL_CALL(glDeleteVertexArrays(1, &vertex_array_id));
299     vertex_array_id = 0;
300 }
301 
lv_opengles_vertex_array_bind(void)302 static void lv_opengles_vertex_array_bind(void)
303 {
304     GL_CALL(glBindVertexArray(vertex_array_id));
305 }
306 
lv_opengles_vertex_array_unbind(void)307 static void lv_opengles_vertex_array_unbind(void)
308 {
309     GL_CALL(glBindVertexArray(0));
310 }
311 
lv_opengles_vertex_array_add_buffer(void)312 static void lv_opengles_vertex_array_add_buffer(void)
313 {
314     lv_opengles_vertex_buffer_bind();
315     intptr_t offset = 0;
316 
317     for(unsigned int i = 0; i < 2; i++) {
318         lv_opengles_vertex_array_bind();
319         GL_CALL(glEnableVertexAttribArray(i));
320         GL_CALL(glVertexAttribPointer(i, 2, GL_FLOAT, GL_FALSE, 16, (const void *)offset));
321         offset += 2 * 4;
322     }
323 }
324 
lv_opengles_index_buffer_init(const unsigned int * data,unsigned int count)325 static void lv_opengles_index_buffer_init(const unsigned int * data, unsigned int count)
326 {
327     index_buffer_count = count;
328     if(index_buffer_id == 0) GL_CALL(glGenBuffers(1, &index_buffer_id));
329 
330     GL_CALL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer_id));
331 
332     GL_CALL(glBufferData(GL_ELEMENT_ARRAY_BUFFER, count * sizeof(GLuint), data, GL_STATIC_DRAW));
333 }
334 
lv_opengles_index_buffer_deinit(void)335 static void lv_opengles_index_buffer_deinit(void)
336 {
337     if(index_buffer_id == 0) return;
338     GL_CALL(glDeleteBuffers(1, &index_buffer_id));
339     index_buffer_id = 0;
340 }
341 
lv_opengles_index_buffer_get_count(void)342 static unsigned int lv_opengles_index_buffer_get_count(void)
343 {
344     return index_buffer_count;
345 }
346 
lv_opengles_index_buffer_bind(void)347 static void lv_opengles_index_buffer_bind(void)
348 {
349     GL_CALL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer_id));
350 }
351 
lv_opengles_index_buffer_unbind(void)352 static void lv_opengles_index_buffer_unbind(void)
353 {
354     GL_CALL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
355 }
356 
lv_opengles_shader_compile(unsigned int type,const char * source)357 static unsigned int lv_opengles_shader_compile(unsigned int type, const char * source)
358 {
359     unsigned int id;
360     GL_CALL(id = glCreateShader(type));
361     const char * src = source;
362     GL_CALL(glShaderSource(id, 1, &src, NULL));
363     GL_CALL(glCompileShader(id));
364 
365     int result;
366     GL_CALL(glGetShaderiv(id, GL_COMPILE_STATUS, &result));
367     if(result == GL_FALSE) {
368         int length;
369         GL_CALL(glGetShaderiv(id, GL_INFO_LOG_LENGTH, &length));
370         char * message = lv_malloc_zeroed(length * sizeof(char));
371         GL_CALL(glGetShaderInfoLog(id, length, &length, message));
372         LV_LOG_ERROR("Failed to compile %s shader!", type == GL_VERTEX_SHADER ? "vertex" : "fragment");
373         LV_LOG_ERROR("%s", message);
374         GL_CALL(glDeleteShader(id));
375         return 0;
376     }
377 
378     return id;
379 }
380 
lv_opengles_shader_create(const char * vertexShader,const char * fragmentShader)381 static unsigned int lv_opengles_shader_create(const char * vertexShader, const char * fragmentShader)
382 {
383     unsigned int program;
384     GL_CALL(program = glCreateProgram());
385     unsigned int vs = lv_opengles_shader_compile(GL_VERTEX_SHADER, vertexShader);
386     unsigned int fs = lv_opengles_shader_compile(GL_FRAGMENT_SHADER, fragmentShader);
387 
388     GL_CALL(glAttachShader(program, vs));
389     GL_CALL(glAttachShader(program, fs));
390     GL_CALL(glLinkProgram(program));
391     GL_CALL(glValidateProgram(program));
392 
393     GL_CALL(glDeleteShader(vs));
394     GL_CALL(glDeleteShader(fs));
395 
396     return program;
397 }
398 
lv_opengles_shader_init(void)399 static void lv_opengles_shader_init(void)
400 {
401     if(shader_id == 0) shader_id = lv_opengles_shader_create(vertex_shader, fragment_shader);
402 }
403 
lv_opengles_shader_deinit(void)404 static void lv_opengles_shader_deinit(void)
405 {
406     if(shader_id == 0) return;
407     GL_CALL(glDeleteProgram(shader_id));
408     shader_id = 0;
409 }
410 
lv_opengles_shader_bind(void)411 static void lv_opengles_shader_bind(void)
412 {
413     GL_CALL(glUseProgram(shader_id));
414 }
415 
lv_opengles_shader_unbind(void)416 static void lv_opengles_shader_unbind(void)
417 {
418     GL_CALL(glUseProgram(0));
419 }
420 
lv_opengles_shader_get_uniform_location(const char * name)421 static int lv_opengles_shader_get_uniform_location(const char * name)
422 {
423     int id = -1;
424     for(size_t i = 0; i < sizeof(shader_location) / sizeof(int); i++) {
425         if(lv_strcmp(shader_names[i], name) == 0) {
426             id = i;
427         }
428     }
429     if(id == -1) {
430         return -1;
431     }
432 
433     if(shader_location[id] != 0) {
434         return shader_location[id];
435     }
436 
437     int location;
438     GL_CALL(location = glGetUniformLocation(shader_id, name));
439     if(location == -1)
440         LV_LOG_WARN("Warning: uniform '%s' doesn't exist!", name);
441 
442     shader_location[id] = location;
443     return location;
444 }
445 
lv_opengles_shader_set_uniform1i(const char * name,int value)446 static void lv_opengles_shader_set_uniform1i(const char * name, int value)
447 {
448     GL_CALL(glUniform1i(lv_opengles_shader_get_uniform_location(name), value));
449 }
450 
lv_opengles_shader_set_uniformmatrix3fv(const char * name,int count,bool transpose,const float * values)451 static void lv_opengles_shader_set_uniformmatrix3fv(const char * name, int count, bool transpose, const float * values)
452 {
453     GL_CALL(glUniformMatrix3fv(lv_opengles_shader_get_uniform_location(name), count, transpose, values));
454 }
455 
lv_opengles_shader_set_uniform1f(const char * name,float value)456 static void lv_opengles_shader_set_uniform1f(const char * name, float value)
457 {
458     GL_CALL(glUniform1f(lv_opengles_shader_get_uniform_location(name), value));
459 }
460 
lv_opengles_shader_set_uniform3f(const char * name,float value_0,float value_1,float value_2)461 static void lv_opengles_shader_set_uniform3f(const char * name, float value_0, float value_1, float value_2)
462 {
463     GL_CALL(glUniform3f(lv_opengles_shader_get_uniform_location(name), value_0, value_1, value_2));
464 }
465 
lv_opengles_render_draw(void)466 static void lv_opengles_render_draw(void)
467 {
468     lv_opengles_shader_bind();
469     lv_opengles_vertex_array_bind();
470     lv_opengles_index_buffer_bind();
471     unsigned int count = lv_opengles_index_buffer_get_count();
472     GL_CALL(glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_INT, NULL));
473 }
474 
475 /**
476  * Copied from `lv_map` in lv_math.h to operate on floats
477  */
lv_opengles_map_float(float x,float min_in,float max_in,float min_out,float max_out)478 static float lv_opengles_map_float(float x, float min_in, float max_in, float min_out, float max_out)
479 {
480     if(max_in >= min_in && x >= max_in) return max_out;
481     if(max_in >= min_in && x <= min_in) return min_out;
482 
483     if(max_in <= min_in && x <= max_in) return max_out;
484     if(max_in <= min_in && x >= min_in) return min_out;
485 
486     /**
487      * The equation should be:
488      *   ((x - min_in) * delta_out) / delta in) + min_out
489      * To avoid rounding error reorder the operations:
490      *   (x - min_in) * (delta_out / delta_min) + min_out
491      */
492 
493     float delta_in = max_in - min_in;
494     float delta_out = max_out - min_out;
495 
496     return ((x - min_in) * delta_out) / delta_in + min_out;
497 }
498 
499 #endif /* LV_USE_OPENGLES */
500