Change GL_RGB to GL_RGBA for rendering 2D visualizer
[platform/core/api/mediavision.git] / test / testsuites / common / visualizer / src / mv_util_render_2d.cpp
1 /**
2  * Copyright (c) 2022 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "mv_util_render_2d.h"
18
19 static char vs_fill[] = "                             \n\
20                                                       \n\
21 attribute vec4 a_Vertex;                              \n\
22 uniform mat4 u_PMVMatrix;                             \n\
23 void main(void)                                       \n\
24 {                                                     \n\
25     gl_Position = u_PMVMatrix * a_Vertex;             \n\
26 }                                                     ";
27
28 static char fs_fill[] = "                             \n\
29                                                       \n\
30 precision mediump float;                              \n\
31 uniform vec4 u_Color;                                 \n\
32                                                       \n\
33 void main(void)                                       \n\
34 {                                                     \n\
35     gl_FragColor = u_Color;                           \n\
36 }                                                       ";
37
38 static char vs_tex[] = "                              \n\
39 attribute vec4 a_Vertex;                              \n\
40 attribute vec2 a_TexCoord;                            \n\
41 varying vec2 v_TexCoord;                              \n\
42 uniform mat4 u_PMVMatrix;                             \n\
43                                                       \n\
44 void main(void)                                       \n\
45 {                                                     \n\
46     gl_Position = u_PMVMatrix * a_Vertex;             \n\
47     v_TexCoord  = a_TexCoord;                         \n\
48 }                                                     \n";
49
50 static char fs_tex[] = "                              \n\
51 precision mediump float;                              \n\
52 varying vec2 v_TexCoord;                              \n\
53 uniform sampler2D u_sampler;                          \n\
54 uniform vec4 u_Color;                                 \n\
55                                                       \n\
56 void main(void)                                       \n\
57 {                                                     \n\
58     gl_FragColor = texture2D(u_sampler, v_TexCoord);  \n\
59     gl_FragColor *= u_Color;                          \n\
60 }                                                     \n";
61
62 static char fs_extex[] = "                            \n\
63 #extension GL_NV_EGL_stream_consumer_external: enable \n\
64 #extension GL_OES_EGL_image_external : enable         \n\
65 precision mediump float;                              \n\
66 varying vec2 v_TexCoord;                              \n\
67 uniform samplerExternalOES u_sampler;                 \n\
68 uniform vec4 u_Color;                                 \n\
69                                                       \n\
70 void main(void)                                       \n\
71 {                                                     \n\
72     gl_FragColor = texture2D(u_sampler, v_TexCoord);  \n\
73     gl_FragColor *= u_Color;                          \n\
74 }                                                     \n";
75
76 static char fs_cmap_jet[] = "                          \n\
77 precision mediump float;                              \n\
78 varying     vec2      v_TexCoord;                     \n\
79 uniform     sampler2D u_sampler;                      \n\
80 uniform     vec4      u_Color;                        \n\
81                                                       \n\
82 float cmap_jet_red(float x)                           \n\
83 {                                                     \n\
84     if (x < 0.7) {                                    \n\
85         return 4.0 * x - 1.5;                         \n\
86     } else {                                          \n\
87         return -4.0 * x + 4.5;                        \n\
88     }                                                 \n\
89 }                                                     \n\
90                                                       \n\
91 float cmap_jet_green(float x)                         \n\
92 {                                                     \n\
93     if (x < 0.5) {                                    \n\
94         return 4.0 * x - 0.5;                         \n\
95     } else {                                          \n\
96         return -4.0 * x + 3.5;                        \n\
97     }                                                 \n\
98 }                                                     \n\
99                                                       \n\
100 float cmap_jet_blue(float x)                          \n\
101 {                                                     \n\
102     if (x < 0.3) {                                    \n\
103        return 4.0 * x + 0.5;                          \n\
104     } else {                                          \n\
105        return -4.0 * x + 2.5;                         \n\
106     }                                                 \n\
107 }                                                     \n\
108                                                       \n\
109 vec4 colormap_jet(float x)                            \n\
110 {                                                     \n\
111     float r = clamp(cmap_jet_red(x),   0.0, 1.0);     \n\
112     float g = clamp(cmap_jet_green(x), 0.0, 1.0);     \n\
113     float b = clamp(cmap_jet_blue(x),  0.0, 1.0);     \n\
114     return vec4(r, g, b, 1.0);                        \n\
115 }                                                     \n\
116                                                       \n\
117 void main(void)                                       \n\
118 {                                                     \n\
119     vec4 src_col = texture2D(u_sampler, v_TexCoord);  \n\
120     gl_FragColor = colormap_jet(src_col.r);           \n\
121     gl_FragColor *= u_Color;                          \n\
122 }                                                     \n";
123
124 static char vs_tex_yuyv[] = "                         \n\
125 attribute vec4 a_Vertex;                              \n\
126 attribute vec2 a_TexCoord;                            \n\
127 varying vec2 v_TexCoord;                              \n\
128 varying vec2 v_TexCoordPix;                           \n\
129 uniform mat4 u_PMVMatrix;                             \n\
130 uniform vec2 u_TexDim;                                \n\
131                                                       \n\
132 void main(void)                                       \n\
133 {                                                     \n\
134     gl_Position = u_PMVMatrix * a_Vertex;             \n\
135     v_TexCoord = a_TexCoord;                          \n\
136     v_TexCoordPix = a_TexCoord * u_TexDim;            \n\
137 }                                                     \n";
138
139 static char fs_tex_yuyv[] = "                         \n\
140 precision mediump float;                              \n\
141 varying vec2 v_TexCoord;                              \n\
142 varying vec2 v_TexCoordPix;                           \n\
143 uniform sampler2D u_sampler;                          \n\
144 uniform vec4 u_Color;                                 \n\
145                                                       \n\
146 void main(void)                                       \n\
147 {                                                     \n\
148     vec2 evenodd = mod(v_TexCoordPix, 2.0);           \n\
149     vec3 yuv, rgb;                                    \n\
150     vec4 texcol = texture2D(u_sampler, v_TexCoord);   \n\
151     if (evenodd.x < 1.0) {                            \n\
152         yuv.r = texcol.r;       /* Y */               \n\
153         yuv.g = texcol.g - 0.5; /* U */               \n\
154         yuv.b = texcol.a - 0.5; /* V */               \n\
155     } else {                                          \n\
156         yuv.r = texcol.b;       /* Y */               \n\
157         yuv.g = texcol.g - 0.5; /* U */               \n\
158         yuv.b = texcol.a - 0.5; /* V */               \n\
159     }                                                 \n\
160                                                       \n\
161     rgb = mat3 (    1,        1,     1,               \n\
162                     0, -0.34413, 1.772,               \n\
163                 1.402, -0.71414,     0) * yuv;        \n\
164     gl_FragColor = vec4(rgb, 1.0);                    \n\
165     gl_FragColor *= u_Color;                          \n\
166 }                                                     \n";
167
168 #define SHADER_NUM 5
169 static char *s_shader[SHADER_NUM * 2] = { vs_fill,      fs_fill, vs_tex,          fs_tex,          vs_tex,
170                                                                                   fs_extex, vs_tex,      fs_cmap_jet, vs_tex_yuyv, fs_tex_yuyv };
171
172 static shader_obj_t s_sobj[SHADER_NUM];
173 static int s_loc_mtx[SHADER_NUM];
174 static int s_loc_color[SHADER_NUM];
175 static int s_loc_texdim[SHADER_NUM];
176
177 static EGLDisplay s_dpy;
178 static EGLSurface s_sfc;
179 static EGLContext s_ctx;
180
181 GLuint create_2d_texture(void *imgbuf, int width, int height)
182 {
183         GLuint texid;
184
185         glGenTextures(1, &texid);
186         glBindTexture(GL_TEXTURE_2D, texid);
187
188         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
189         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
190         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
191         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
192
193         glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
194
195         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, imgbuf);
196
197         return texid;
198 }
199
200 static EGLConfig find_egl_config(int r, int g, int b, int a, int d, int s, int ms, int sfc_type, int ver)
201 {
202         EGLint num_conf, i;
203         EGLBoolean ret;
204         EGLConfig conf = 0, *conf_array = NULL;
205
206         EGLint config_attribs[] = { EGL_RED_SIZE,
207                                                                 8,
208                                                                 EGL_GREEN_SIZE,
209                                                                 8,
210                                                                 EGL_BLUE_SIZE,
211                                                                 8,
212                                                                 EGL_ALPHA_SIZE,
213                                                                 8,
214                                                                 EGL_DEPTH_SIZE,
215                                                                 EGL_DONT_CARE,
216                                                                 EGL_STENCIL_SIZE,
217                                                                 EGL_DONT_CARE,
218                                                                 EGL_SAMPLES,
219                                                                 EGL_DONT_CARE,
220                                                                 EGL_SURFACE_TYPE,
221                                                                 EGL_WINDOW_BIT,
222                                                                 EGL_RENDERABLE_TYPE,
223                                                                 EGL_OPENGL_ES2_BIT,
224                                                                 EGL_NONE };
225
226         config_attribs[1] = r;
227         config_attribs[3] = g;
228         config_attribs[5] = b;
229         config_attribs[7] = a;
230         config_attribs[9] = d;
231         config_attribs[11] = s;
232         config_attribs[13] = ms;
233         config_attribs[15] = sfc_type;
234
235         switch (ver) {
236         case 1:
237         case 2:
238                 config_attribs[17] = EGL_OPENGL_ES2_BIT;
239                 break;
240         default:
241                 LOGE("Invalid version");
242                 goto exit;
243         }
244
245         ret = eglChooseConfig(s_dpy, config_attribs, NULL, 0, &num_conf);
246         if (ret != EGL_TRUE || num_conf == 0) {
247                 LOGE("Failed to call eglChooseConfig");
248                 goto exit;
249         }
250
251         conf_array = (EGLConfig *) calloc(num_conf, sizeof(EGLConfig));
252         if (conf_array == NULL) {
253                 LOGE("EGLConfig is NULL");
254                 goto exit;
255         }
256
257         ret = eglChooseConfig(s_dpy, config_attribs, conf_array, num_conf, &num_conf);
258         if (ret != EGL_TRUE) {
259                 LOGE("Failed to call eglChooseConfig");
260                 goto exit;
261         }
262
263         for (i = 0; i < num_conf; i++) {
264                 EGLint id, rsize, gsize, bsize, asize;
265
266                 eglGetConfigAttrib(s_dpy, conf_array[i], EGL_CONFIG_ID, &id);
267                 eglGetConfigAttrib(s_dpy, conf_array[i], EGL_RED_SIZE, &rsize);
268                 eglGetConfigAttrib(s_dpy, conf_array[i], EGL_GREEN_SIZE, &gsize);
269                 eglGetConfigAttrib(s_dpy, conf_array[i], EGL_BLUE_SIZE, &bsize);
270                 eglGetConfigAttrib(s_dpy, conf_array[i], EGL_ALPHA_SIZE, &asize);
271
272                 if (rsize == r && gsize == g && bsize == b && asize == a) {
273                         conf = conf_array[i];
274                         break;
275                 }
276         }
277
278         if (i == num_conf) {
279                 LOGE("Index is out of range");
280                 goto exit;
281         }
282
283 exit:
284         if (conf_array)
285                 free(conf_array);
286
287         return conf;
288 }
289
290 int egl_init_with_platform_window_surface(int gles_version, int depth_size, int stencil_size, int sample_num, int win_w,
291                                                                                   int win_h)
292 {
293         void *native_dpy, *native_win;
294         EGLint major, minor;
295         EGLConfig config;
296         EGLBoolean ret;
297         EGLint context_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
298         EGLint sfc_attr[] = { EGL_NONE };
299
300         native_dpy = winsys_init_native_display();
301         if ((native_dpy != EGL_DEFAULT_DISPLAY) && (native_dpy == NULL)) {
302                 LOGE("native_dpy is not valid");
303                 return MEDIA_VISION_ERROR_INTERNAL;
304         }
305
306         s_dpy = eglGetDisplay(native_dpy);
307         if (s_dpy == EGL_NO_DISPLAY) {
308                 LOGE("s_dpy is EGL_NO_DISPLAY");
309                 return MEDIA_VISION_ERROR_INTERNAL;
310         }
311
312         ret = eglInitialize(s_dpy, &major, &minor);
313         if (ret != EGL_TRUE) {
314                 LOGE("Failed to initialize egl");
315                 return MEDIA_VISION_ERROR_INTERNAL;
316         }
317
318         eglBindAPI(EGL_OPENGL_ES_API);
319
320         config = find_egl_config(8, 8, 8, 8, depth_size, stencil_size, sample_num, EGL_WINDOW_BIT, gles_version);
321         if (config == NULL) {
322                 LOGE("Failed to find egl configuration");
323                 return MEDIA_VISION_ERROR_INTERNAL;
324         }
325
326         native_win = winsys_init_native_window(s_dpy, win_w, win_h);
327         if (native_win == NULL) {
328                 LOGE("window is NULL");
329                 return MEDIA_VISION_ERROR_INTERNAL;
330         }
331
332         s_sfc = eglCreateWindowSurface(s_dpy, config, (NativeWindowType) native_win, sfc_attr);
333         if (s_sfc == EGL_NO_SURFACE) {
334                 LOGE("s_sfc is EGL_NO_SURFACE");
335                 return MEDIA_VISION_ERROR_INTERNAL;
336         }
337
338         switch (gles_version) {
339         case 1:
340                 context_attribs[1] = 1;
341                 break;
342         case 2:
343                 context_attribs[1] = 2;
344                 break;
345         case 3:
346                 context_attribs[1] = 3;
347                 break;
348         default:
349                 LOGE("Invalid gles version");
350                 return MEDIA_VISION_ERROR_INTERNAL;
351         }
352
353         s_ctx = eglCreateContext(s_dpy, config, EGL_NO_CONTEXT, context_attribs);
354         if (s_ctx == EGL_NO_CONTEXT) {
355                 LOGE("s_ctx is EGL_NO_CONTEXT");
356                 return MEDIA_VISION_ERROR_INTERNAL;
357         }
358
359         ret = eglMakeCurrent(s_dpy, s_sfc, s_sfc, s_ctx);
360         if (ret != EGL_TRUE) {
361                 LOGE("Falied to call eglMakeCurrent()");
362                 return MEDIA_VISION_ERROR_INTERNAL;
363         }
364
365         return MEDIA_VISION_ERROR_NONE;
366 }
367
368 int egl_swap()
369 {
370         EGLBoolean ret;
371
372         ret = eglSwapBuffers(s_dpy, s_sfc);
373         if (ret != EGL_TRUE) {
374                 LOGE("Failed to call eglSwapBuffers()");
375                 return MEDIA_VISION_ERROR_INTERNAL;
376         }
377
378         return MEDIA_VISION_ERROR_NONE;
379 }
380
381 static float varray[] = { 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0 };
382
383 static float tarray[] = { 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0 };
384
385 static float tarray2[] = { 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.0 };
386
387 static float s_matprj[16];
388 static void set_projection_matrix(int w, int h)
389 {
390         float mat_proj[] = {
391                 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f, 1.0f
392         };
393
394         mat_proj[0] = 2.0f / (float) w;
395         mat_proj[5] = -2.0f / (float) h;
396
397         memcpy(s_matprj, mat_proj, 16 * sizeof(float));
398 }
399
400 int init_2d_renderer(int w, int h)
401 {
402         int i;
403
404         for (i = 0; i < SHADER_NUM; i++) {
405                 if (generate_shader(&s_sobj[i], s_shader[2 * i], s_shader[2 * i + 1]) < 0) {
406                         LOGE("%s(%d)", __FILE__, __LINE__);
407                         return MEDIA_VISION_ERROR_INTERNAL;
408                 }
409
410                 s_loc_mtx[i] = glGetUniformLocation(s_sobj[i].program, "u_PMVMatrix");
411                 s_loc_color[i] = glGetUniformLocation(s_sobj[i].program, "u_Color");
412                 s_loc_texdim[i] = glGetUniformLocation(s_sobj[i].program, "u_TexDim");
413         }
414
415         set_projection_matrix(w, h);
416
417         return MEDIA_VISION_ERROR_NONE;
418 }
419
420 typedef struct _texparam {
421         int textype;
422         int texid;
423         int x, y, w, h;
424         int texw, texh;
425         int upsidedown;
426         float color[4];
427         float rot;
428         float px, py;
429         int blendfunc_en;
430         unsigned int blendfunc[4];
431         float *user_texcoord;
432 } texparam_t;
433
434 static void draw_2d_texture_in(texparam_t *tparam)
435 {
436         int ttype = tparam->textype;
437         int texid = tparam->texid;
438         float x = tparam->x;
439         float y = tparam->y;
440         float w = tparam->w;
441         float h = tparam->h;
442         float rot = tparam->rot;
443         shader_obj_t *sobj = &s_sobj[ttype];
444         float matrix[16];
445         float *uv = tarray;
446
447         glBindBuffer(GL_ARRAY_BUFFER, 0);
448         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
449
450         glUseProgram(sobj->program);
451         glUniform1i(sobj->loc_tex, 0);
452
453         switch (ttype) {
454         case 0: /* fill     */
455                 break;
456         case 1: /* tex      */
457         case 4: /* tex_yuyv */
458                 glBindTexture(GL_TEXTURE_2D, texid);
459                 uv = tparam->upsidedown ? tarray2 : tarray;
460                 break;
461         case 2: /* tex_extex */
462                 glBindTexture(GL_TEXTURE_EXTERNAL_OES, texid);
463                 uv = tparam->upsidedown ? tarray : tarray2;
464                 break;
465         default:
466                 break;
467         }
468
469         if (tparam->user_texcoord)
470                 uv = tparam->user_texcoord;
471
472         if (sobj->loc_uv >= 0) {
473                 glEnableVertexAttribArray(sobj->loc_uv);
474                 glVertexAttribPointer(sobj->loc_uv, 2, GL_FLOAT, GL_FALSE, 0, uv);
475         }
476
477         glEnable(GL_BLEND);
478
479         if (tparam->blendfunc_en) {
480                 glBlendFuncSeparate(tparam->blendfunc[0], tparam->blendfunc[1], tparam->blendfunc[2], tparam->blendfunc[3]);
481         } else {
482                 glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
483         }
484
485         if (matrix_identity(matrix) != MEDIA_VISION_ERROR_NONE)
486                 LOGE("Failed to call matrix_identity");
487         if (matrix_translate(matrix, x, y, 0.0f) != MEDIA_VISION_ERROR_NONE)
488                 LOGE("Failed to call matrix_translate");
489
490         if (rot != 0) {
491                 float px = tparam->px;
492                 float py = tparam->py;
493                 if (matrix_translate(matrix, px, py, 0.0f) != MEDIA_VISION_ERROR_NONE)
494                         LOGE("Failed to call matrix_translate");
495
496                 if (matrix_rotate(matrix, rot, 0.0f, 0.0f, 1.0f) != MEDIA_VISION_ERROR_NONE)
497                         LOGE("Failed to call matrix_rotate");
498                 if (matrix_translate(matrix, -px, -py, 0.0f) != MEDIA_VISION_ERROR_NONE)
499                         LOGE("Failed to call matrix_translate");
500         }
501         if (matrix_scale(matrix, w, h, 1.0f) != MEDIA_VISION_ERROR_NONE)
502                 LOGE("Failed to call matrix_scale");
503         if (matrix_mult(matrix, s_matprj, matrix) != MEDIA_VISION_ERROR_NONE)
504                 LOGE("Failed to call matrix_mult");
505
506         glUniformMatrix4fv(s_loc_mtx[ttype], 1, GL_FALSE, matrix);
507         glUniform4fv(s_loc_color[ttype], 1, tparam->color);
508
509         if (s_loc_texdim[ttype] >= 0) {
510                 float texdim[2];
511                 texdim[0] = tparam->texw;
512                 texdim[1] = tparam->texh;
513                 glUniform2fv(s_loc_texdim[ttype], 1, texdim);
514         }
515
516         if (sobj->loc_vtx >= 0) {
517                 glEnableVertexAttribArray(sobj->loc_vtx);
518                 glVertexAttribPointer(sobj->loc_vtx, 2, GL_FLOAT, GL_FALSE, 0, varray);
519         }
520
521         glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
522
523         glDisable(GL_BLEND);
524 }
525
526 int load_texture(mv_source_h source, int *lpTexID, int *lpWidth, int *lpHeight)
527 {
528         GLuint texid;
529         unsigned char *data_buffer = NULL;
530         unsigned int width, height;
531         unsigned int buffer_size = 0;
532         int err = mv_source_get_buffer(source, &data_buffer, &buffer_size);
533         if (MEDIA_VISION_ERROR_NONE != err) {
534                 LOGE("ERROR: Errors were occurred during getting buffer from the "
535                          "source; code %i\n",
536                          err);
537                 return err;
538         }
539
540         err = mv_source_get_width(source, &width);
541         if (MEDIA_VISION_ERROR_NONE != err) {
542                 LOGE("ERROR: Errors were occurred during getting width from the "
543                          "source; code %i\n",
544                          err);
545                 return err;
546         }
547
548         err = mv_source_get_height(source, &height);
549         if (MEDIA_VISION_ERROR_NONE != err) {
550                 LOGE("ERROR: Errors were occurred during getting height from the "
551                          "source; code %i\n",
552                          err);
553                 return err;
554         }
555         texid = create_2d_texture(data_buffer, width, height);
556
557         if (lpTexID)
558                 *lpTexID = texid;
559         if (lpWidth)
560                 *lpWidth = width;
561         if (lpHeight)
562                 *lpHeight = height;
563
564         return MEDIA_VISION_ERROR_NONE;
565 }
566
567 int draw_2d_texture(texture_2d_t *tex, int x, int y, int w, int h, int upsidedown)
568 {
569         texparam_t tparam = { 0 };
570
571         if (tex == NULL) {
572                 LOGE("tex is NULL");
573                 return MEDIA_VISION_ERROR_INTERNAL;
574         }
575
576         tparam.x = x;
577         tparam.y = y;
578         tparam.w = w;
579         tparam.h = h;
580         tparam.texid = tex->texid;
581         tparam.textype = 1;
582         tparam.texw = tex->width;
583         tparam.texh = tex->height;
584         tparam.color[0] = 1.0f;
585         tparam.color[1] = 1.0f;
586         tparam.color[2] = 1.0f;
587         tparam.color[3] = 1.0f;
588         tparam.upsidedown = upsidedown;
589
590         if (tex->format == pixfmt_fourcc('Y', 'U', 'Y', 'V'))
591                 tparam.textype = 4;
592
593         draw_2d_texture_in(&tparam);
594
595         return MEDIA_VISION_ERROR_NONE;
596 }