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