build: replace genshader by binary linker
[platform/upstream/kmscon.git] / src / uterm_drm3d_render.c
1 /*
2  * uterm - Linux User-Space Terminal
3  *
4  * Copyright (c) 2011-2013 David Herrmann <dh.herrmann@googlemail.com>
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining
7  * a copy of this software and associated documentation files
8  * (the "Software"), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
10  * distribute, sublicense, and/or sell copies of the Software, and to
11  * permit persons to whom the Software is furnished to do so, subject to
12  * the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included
15  * in all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
21  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24  */
25
26 /*
27  * DRM Video backend
28  */
29
30 #define EGL_EGLEXT_PROTOTYPES
31 #define GL_GLEXT_PROTOTYPES
32
33 #include <EGL/egl.h>
34 #include <EGL/eglext.h>
35 #include <errno.h>
36 #include <fcntl.h>
37 #include <gbm.h>
38 #include <GLES2/gl2.h>
39 #include <GLES2/gl2ext.h>
40 #include <inttypes.h>
41 #include <stdbool.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <unistd.h>
45 #include <xf86drm.h>
46 #include <xf86drmMode.h>
47 #include "eloop.h"
48 #include "shl_gl.h"
49 #include "shl_log.h"
50 #include "uterm_drm_shared_internal.h"
51 #include "uterm_drm3d_internal.h"
52 #include "uterm_video.h"
53 #include "uterm_video_internal.h"
54
55 #define LOG_SUBSYSTEM "uterm_drm3d_render"
56
57 extern const char _binary_src_uterm_drm3d_blend_vert_bin_start[];
58 extern const char _binary_src_uterm_drm3d_blend_vert_bin_end[];
59 extern const char _binary_src_uterm_drm3d_blend_frag_bin_start[];
60 extern const char _binary_src_uterm_drm3d_blend_frag_bin_end[];
61 extern const char _binary_src_uterm_drm3d_blit_vert_bin_start[];
62 extern const char _binary_src_uterm_drm3d_blit_vert_bin_end[];
63 extern const char _binary_src_uterm_drm3d_blit_frag_bin_start[];
64 extern const char _binary_src_uterm_drm3d_blit_frag_bin_end[];
65 extern const char _binary_src_uterm_drm3d_fill_vert_bin_start[];
66 extern const char _binary_src_uterm_drm3d_fill_vert_bin_end[];
67 extern const char _binary_src_uterm_drm3d_fill_frag_bin_start[];
68 extern const char _binary_src_uterm_drm3d_fill_frag_bin_end[];
69
70 static int init_shaders(struct uterm_video *video)
71 {
72         struct uterm_drm3d_video *v3d = uterm_drm_video_get_data(video);
73         int ret;
74         char *fill_attr[] = { "position", "color" };
75         char *blend_attr[] = { "position", "texture_position" };
76         char *blit_attr[] = { "position", "texture_position" };
77         int blend_vlen, blend_flen, blit_vlen, blit_flen, fill_vlen, fill_flen;
78         const char *blend_vert, *blend_frag;
79         const char *blit_vert, *blit_frag;
80         const char *fill_vert, *fill_frag;
81
82         if (v3d->sinit == 1)
83                 return -EFAULT;
84         else if (v3d->sinit == 2)
85                 return 0;
86
87         v3d->sinit = 1;
88
89         blend_vert = _binary_src_uterm_drm3d_blend_vert_bin_start;
90         blend_vlen = _binary_src_uterm_drm3d_blend_vert_bin_end - blend_vert;
91         blend_frag = _binary_src_uterm_drm3d_blend_frag_bin_start;
92         blend_flen = _binary_src_uterm_drm3d_blend_frag_bin_end - blend_frag;
93         blit_vert = _binary_src_uterm_drm3d_blit_vert_bin_start;
94         blit_vlen = _binary_src_uterm_drm3d_blit_vert_bin_end - blit_vert;
95         blit_frag = _binary_src_uterm_drm3d_blit_frag_bin_start;
96         blit_flen = _binary_src_uterm_drm3d_blit_frag_bin_end - blit_frag;
97         fill_vert = _binary_src_uterm_drm3d_fill_vert_bin_start;
98         fill_vlen = _binary_src_uterm_drm3d_fill_vert_bin_end - fill_vert;
99         fill_frag = _binary_src_uterm_drm3d_fill_frag_bin_start;
100         fill_flen = _binary_src_uterm_drm3d_fill_frag_bin_end - fill_frag;
101
102         ret = gl_shader_new(&v3d->fill_shader, fill_vert, fill_vlen,
103                             fill_frag, fill_flen, fill_attr, 2, log_llog,
104                             NULL);
105         if (ret)
106                 return ret;
107
108         v3d->uni_fill_proj = gl_shader_get_uniform(v3d->fill_shader,
109                                                    "projection");
110
111         ret = gl_shader_new(&v3d->blend_shader, blend_vert, blend_vlen,
112                             blend_frag, blend_flen, blend_attr, 2, log_llog,
113                             NULL);
114         if (ret)
115                 return ret;
116
117         v3d->uni_blend_proj = gl_shader_get_uniform(v3d->blend_shader,
118                                                     "projection");
119         v3d->uni_blend_tex = gl_shader_get_uniform(v3d->blend_shader,
120                                                    "texture");
121         v3d->uni_blend_fgcol = gl_shader_get_uniform(v3d->blend_shader,
122                                                      "fgcolor");
123         v3d->uni_blend_bgcol = gl_shader_get_uniform(v3d->blend_shader,
124                                                      "bgcolor");
125
126         ret = gl_shader_new(&v3d->blit_shader, blit_vert, blit_vlen,
127                             blit_frag, blit_flen, blit_attr, 2, log_llog,
128                             NULL);
129         if (ret)
130                 return ret;
131
132         v3d->uni_blit_proj = gl_shader_get_uniform(v3d->blit_shader,
133                                                    "projection");
134         v3d->uni_blit_tex = gl_shader_get_uniform(v3d->blit_shader,
135                                                   "texture");
136
137         gl_tex_new(&v3d->tex, 1);
138         v3d->sinit = 2;
139
140         return 0;
141 }
142
143 void uterm_drm3d_deinit_shaders(struct uterm_video *video)
144 {
145         struct uterm_drm3d_video *v3d = uterm_drm_video_get_data(video);
146
147         if (v3d->sinit == 0)
148                 return;
149
150         v3d->sinit = 0;
151         gl_tex_free(&v3d->tex, 1);
152         gl_shader_unref(v3d->blit_shader);
153         gl_shader_unref(v3d->blend_shader);
154         gl_shader_unref(v3d->fill_shader);
155 }
156
157 int uterm_drm3d_display_blit(struct uterm_display *disp,
158                              const struct uterm_video_buffer *buf,
159                              unsigned int x, unsigned int y)
160 {
161         struct uterm_drm3d_video *v3d;
162         unsigned int sw, sh, tmp, width, height, i;
163         float mat[16];
164         float vertices[6 * 2], texpos[6 * 2];
165         int ret;
166         uint8_t *packed, *src, *dst;
167
168         if (!buf || buf->format != UTERM_FORMAT_XRGB32)
169                 return -EINVAL;
170
171         v3d = uterm_drm_video_get_data(disp->video);
172         ret = uterm_drm3d_display_use(disp, NULL);
173         if (ret)
174                 return ret;
175         ret = init_shaders(disp->video);
176         if (ret)
177                 return ret;
178
179         sw = uterm_drm_mode_get_width(disp->current_mode);
180         sh = uterm_drm_mode_get_height(disp->current_mode);
181
182         vertices[0] = -1.0;
183         vertices[1] = -1.0;
184         vertices[2] = -1.0;
185         vertices[3] = +1.0;
186         vertices[4] = +1.0;
187         vertices[5] = +1.0;
188
189         vertices[6] = -1.0;
190         vertices[7] = -1.0;
191         vertices[8] = +1.0;
192         vertices[9] = +1.0;
193         vertices[10] = +1.0;
194         vertices[11] = -1.0;
195
196         texpos[0] = 0.0;
197         texpos[1] = 1.0;
198         texpos[2] = 0.0;
199         texpos[3] = 0.0;
200         texpos[4] = 1.0;
201         texpos[5] = 0.0;
202
203         texpos[6] = 0.0;
204         texpos[7] = 1.0;
205         texpos[8] = 1.0;
206         texpos[9] = 0.0;
207         texpos[10] = 1.0;
208         texpos[11] = 1.0;
209
210         tmp = x + buf->width;
211         if (tmp < x || x >= sw)
212                 return -EINVAL;
213         if (tmp > sw)
214                 width = sw - x;
215         else
216                 width = buf->width;
217
218         tmp = y + buf->height;
219         if (tmp < y || y >= sh)
220                 return -EINVAL;
221         if (tmp > sh)
222                 height = sh - y;
223         else
224                 height = buf->height;
225
226         glViewport(x, sh - y - height, width, height);
227         glDisable(GL_BLEND);
228
229         gl_shader_use(v3d->blit_shader);
230
231         gl_m4_identity(mat);
232         glUniformMatrix4fv(v3d->uni_blit_proj, 1, GL_FALSE, mat);
233
234         glActiveTexture(GL_TEXTURE0);
235         glBindTexture(GL_TEXTURE_2D, v3d->tex);
236         glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
237
238         if (v3d->supports_rowlen) {
239                 glPixelStorei(GL_UNPACK_ROW_LENGTH, buf->stride / 4);
240                 glTexImage2D(GL_TEXTURE_2D, 0, GL_BGRA_EXT, width, height, 0,
241                              GL_BGRA_EXT, GL_UNSIGNED_BYTE, buf->data);
242                 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
243         } else if (buf->stride == width) {
244                 glTexImage2D(GL_TEXTURE_2D, 0, GL_BGRA_EXT, width, height, 0,
245                              GL_BGRA_EXT, GL_UNSIGNED_BYTE, buf->data);
246         } else {
247                 packed = malloc(width * height);
248                 if (!packed)
249                         return -ENOMEM;
250
251                 src = buf->data;
252                 dst = packed;
253                 for (i = 0; i < height; ++i) {
254                         memcpy(dst, src, width * 4);
255                         dst += width * 4;
256                         src += buf->stride;
257                 }
258
259                 glTexImage2D(GL_TEXTURE_2D, 0, GL_BGRA_EXT, width, height, 0,
260                              GL_BGRA_EXT, GL_UNSIGNED_BYTE, packed);
261
262                 free(packed);
263         }
264
265         glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
266         glUniform1i(v3d->uni_blit_tex, 0);
267
268         glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, vertices);
269         glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, texpos);
270         glEnableVertexAttribArray(0);
271         glEnableVertexAttribArray(1);
272         glDrawArrays(GL_TRIANGLES, 0, 6);
273         glDisableVertexAttribArray(0);
274         glDisableVertexAttribArray(1);
275
276         if (gl_has_error(v3d->blit_shader)) {
277                 log_warning("GL error");
278                 return -EFAULT;
279         }
280
281         return 0;
282 }
283
284 static int display_blend(struct uterm_display *disp,
285                          const struct uterm_video_buffer *buf,
286                          unsigned int x, unsigned int y,
287                          uint8_t fr, uint8_t fg, uint8_t fb,
288                          uint8_t br, uint8_t bg, uint8_t bb)
289 {
290         struct uterm_drm3d_video *v3d;
291         unsigned int sw, sh, tmp, width, height, i;
292         float mat[16];
293         float vertices[6 * 2], texpos[6 * 2], fgcol[3], bgcol[3];
294         int ret;
295         uint8_t *packed, *src, *dst;
296
297         if (!buf || buf->format != UTERM_FORMAT_GREY)
298                 return -EINVAL;
299
300         v3d = uterm_drm_video_get_data(disp->video);
301         ret = uterm_drm3d_display_use(disp, NULL);
302         if (ret)
303                 return ret;
304         ret = init_shaders(disp->video);
305         if (ret)
306                 return ret;
307
308         sw = uterm_drm_mode_get_width(disp->current_mode);
309         sh = uterm_drm_mode_get_height(disp->current_mode);
310
311         vertices[0] = -1.0;
312         vertices[1] = -1.0;
313         vertices[2] = -1.0;
314         vertices[3] = +1.0;
315         vertices[4] = +1.0;
316         vertices[5] = +1.0;
317
318         vertices[6] = -1.0;
319         vertices[7] = -1.0;
320         vertices[8] = +1.0;
321         vertices[9] = +1.0;
322         vertices[10] = +1.0;
323         vertices[11] = -1.0;
324
325         texpos[0] = 0.0;
326         texpos[1] = 1.0;
327         texpos[2] = 0.0;
328         texpos[3] = 0.0;
329         texpos[4] = 1.0;
330         texpos[5] = 0.0;
331
332         texpos[6] = 0.0;
333         texpos[7] = 1.0;
334         texpos[8] = 1.0;
335         texpos[9] = 0.0;
336         texpos[10] = 1.0;
337         texpos[11] = 1.0;
338
339         fgcol[0] = fr / 255.0;
340         fgcol[1] = fg / 255.0;
341         fgcol[2] = fb / 255.0;
342         bgcol[0] = br / 255.0;
343         bgcol[1] = bg / 255.0;
344         bgcol[2] = bb / 255.0;
345
346         tmp = x + buf->width;
347         if (tmp < x || x >= sw)
348                 return -EINVAL;
349         if (tmp > sw)
350                 width = sw - x;
351         else
352                 width = buf->width;
353
354         tmp = y + buf->height;
355         if (tmp < y || y >= sh)
356                 return -EINVAL;
357         if (tmp > sh)
358                 height = sh - y;
359         else
360                 height = buf->height;
361
362         glViewport(x, sh - y - height, width, height);
363         glDisable(GL_BLEND);
364
365         gl_shader_use(v3d->blend_shader);
366
367         gl_m4_identity(mat);
368         glUniformMatrix4fv(v3d->uni_blend_proj, 1, GL_FALSE, mat);
369
370         glUniform3fv(v3d->uni_blend_fgcol, 1, fgcol);
371         glUniform3fv(v3d->uni_blend_bgcol, 1, bgcol);
372
373         glActiveTexture(GL_TEXTURE0);
374         glBindTexture(GL_TEXTURE_2D, v3d->tex);
375         glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
376
377         if (v3d->supports_rowlen) {
378                 glPixelStorei(GL_UNPACK_ROW_LENGTH, buf->stride);
379                 glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0,
380                              GL_ALPHA, GL_UNSIGNED_BYTE, buf->data);
381                 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
382         } else if (buf->stride == width) {
383                 glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0,
384                              GL_ALPHA, GL_UNSIGNED_BYTE, buf->data);
385         } else {
386                 packed = malloc(width * height);
387                 if (!packed)
388                         return -ENOMEM;
389
390                 src = buf->data;
391                 dst = packed;
392                 for (i = 0; i < height; ++i) {
393                         memcpy(dst, src, width);
394                         dst += width;
395                         src += buf->stride;
396                 }
397
398                 glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0,
399                              GL_ALPHA, GL_UNSIGNED_BYTE, packed);
400
401                 free(packed);
402         }
403
404         glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
405         glUniform1i(v3d->uni_blend_tex, 0);
406
407         glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, vertices);
408         glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, texpos);
409         glEnableVertexAttribArray(0);
410         glEnableVertexAttribArray(1);
411         glDrawArrays(GL_TRIANGLES, 0, 6);
412         glDisableVertexAttribArray(0);
413         glDisableVertexAttribArray(1);
414
415         if (gl_has_error(v3d->blend_shader)) {
416                 log_warning("GL error");
417                 return -EFAULT;
418         }
419
420         return 0;
421 }
422
423 int uterm_drm3d_display_fake_blendv(struct uterm_display *disp,
424                                     const struct uterm_video_blend_req *req,
425                                     size_t num)
426 {
427         int ret;
428         unsigned int i;
429
430         if (!disp || !req)
431                 return -EINVAL;
432
433         for (i = 0; i < num; ++i, ++req) {
434                 if (!req->buf)
435                         continue;
436
437                 ret = display_blend(disp, req->buf, req->x, req->y,
438                                     req->fr, req->fg, req->fb,
439                                     req->br, req->bg, req->bb);
440                 if (ret)
441                         return ret;
442         }
443
444         return 0;
445 }
446
447 int uterm_drm3d_display_fill(struct uterm_display *disp,
448                              uint8_t r, uint8_t g, uint8_t b,
449                              unsigned int x, unsigned int y,
450                              unsigned int width, unsigned int height)
451 {
452         struct uterm_drm3d_video *v3d;
453         unsigned int sw, sh, tmp, i;
454         float mat[16];
455         float vertices[6 * 2], colors[6 * 4];
456         int ret;
457
458         v3d = uterm_drm_video_get_data(disp->video);
459         ret = uterm_drm3d_display_use(disp, NULL);
460         if (ret)
461                 return ret;
462         ret = init_shaders(disp->video);
463         if (ret)
464                 return ret;
465
466         sw = uterm_drm_mode_get_width(disp->current_mode);
467         sh = uterm_drm_mode_get_height(disp->current_mode);
468
469         for (i = 0; i < 6; ++i) {
470                 colors[i * 4 + 0] = r / 255.0;
471                 colors[i * 4 + 1] = g / 255.0;
472                 colors[i * 4 + 2] = b / 255.0;
473                 colors[i * 4 + 3] = 1.0;
474         }
475
476         vertices[0] = -1.0;
477         vertices[1] = -1.0;
478         vertices[2] = -1.0;
479         vertices[3] = +1.0;
480         vertices[4] = +1.0;
481         vertices[5] = +1.0;
482
483         vertices[6] = -1.0;
484         vertices[7] = -1.0;
485         vertices[8] = +1.0;
486         vertices[9] = +1.0;
487         vertices[10] = +1.0;
488         vertices[11] = -1.0;
489
490         tmp = x + width;
491         if (tmp < x || x >= sw)
492                 return -EINVAL;
493         if (tmp > sw)
494                 width = sw - x;
495         tmp = y + height;
496         if (tmp < y || y >= sh)
497                 return -EINVAL;
498         if (tmp > sh)
499                 height = sh - y;
500
501         glViewport(x, y, width, height);
502         glDisable(GL_BLEND);
503
504         gl_shader_use(v3d->fill_shader);
505         gl_m4_identity(mat);
506         glUniformMatrix4fv(v3d->uni_fill_proj, 1, GL_FALSE, mat);
507         glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, vertices);
508         glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, colors);
509         glEnableVertexAttribArray(0);
510         glEnableVertexAttribArray(1);
511         glDrawArrays(GL_TRIANGLES, 0, 6);
512         glDisableVertexAttribArray(0);
513         glDisableVertexAttribArray(1);
514
515         if (gl_has_error(v3d->fill_shader)) {
516                 log_warning("GL error");
517                 return -EFAULT;
518         }
519
520         return 0;
521 }