shl: shader: add "len" parameter to shader sources
[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 *gl_static_fill_vert;
58 extern const char *gl_static_fill_frag;
59 extern const char *gl_static_blend_vert;
60 extern const char *gl_static_blend_frag;
61 extern const char *gl_static_blit_vert;
62 extern const char *gl_static_blit_frag;
63
64 static int init_shaders(struct uterm_video *video)
65 {
66         struct uterm_drm3d_video *v3d = uterm_drm_video_get_data(video);
67         int ret;
68         char *fill_attr[] = { "position", "color" };
69         char *blend_attr[] = { "position", "texture_position" };
70         char *blit_attr[] = { "position", "texture_position" };
71
72         if (v3d->sinit == 1)
73                 return -EFAULT;
74         else if (v3d->sinit == 2)
75                 return 0;
76
77         v3d->sinit = 1;
78
79         ret = gl_shader_new(&v3d->fill_shader, gl_static_fill_vert, -1,
80                             gl_static_fill_frag, -1, fill_attr, 2, log_llog,
81                             NULL);
82         if (ret)
83                 return ret;
84
85         v3d->uni_fill_proj = gl_shader_get_uniform(v3d->fill_shader,
86                                                    "projection");
87
88         ret = gl_shader_new(&v3d->blend_shader, gl_static_blend_vert, -1,
89                             gl_static_blend_frag, -1, blend_attr, 2, log_llog,
90                             NULL);
91         if (ret)
92                 return ret;
93
94         v3d->uni_blend_proj = gl_shader_get_uniform(v3d->blend_shader,
95                                                     "projection");
96         v3d->uni_blend_tex = gl_shader_get_uniform(v3d->blend_shader,
97                                                    "texture");
98         v3d->uni_blend_fgcol = gl_shader_get_uniform(v3d->blend_shader,
99                                                      "fgcolor");
100         v3d->uni_blend_bgcol = gl_shader_get_uniform(v3d->blend_shader,
101                                                      "bgcolor");
102
103         ret = gl_shader_new(&v3d->blit_shader, gl_static_blit_vert, -1,
104                             gl_static_blit_frag, -1, blit_attr, 2, log_llog,
105                             NULL);
106         if (ret)
107                 return ret;
108
109         v3d->uni_blit_proj = gl_shader_get_uniform(v3d->blit_shader,
110                                                    "projection");
111         v3d->uni_blit_tex = gl_shader_get_uniform(v3d->blit_shader,
112                                                   "texture");
113
114         gl_tex_new(&v3d->tex, 1);
115         v3d->sinit = 2;
116
117         return 0;
118 }
119
120 void uterm_drm3d_deinit_shaders(struct uterm_video *video)
121 {
122         struct uterm_drm3d_video *v3d = uterm_drm_video_get_data(video);
123
124         if (v3d->sinit == 0)
125                 return;
126
127         v3d->sinit = 0;
128         gl_tex_free(&v3d->tex, 1);
129         gl_shader_unref(v3d->blit_shader);
130         gl_shader_unref(v3d->blend_shader);
131         gl_shader_unref(v3d->fill_shader);
132 }
133
134 int uterm_drm3d_display_blit(struct uterm_display *disp,
135                              const struct uterm_video_buffer *buf,
136                              unsigned int x, unsigned int y)
137 {
138         struct uterm_drm3d_video *v3d;
139         unsigned int sw, sh, tmp, width, height, i;
140         float mat[16];
141         float vertices[6 * 2], texpos[6 * 2];
142         int ret;
143         uint8_t *packed, *src, *dst;
144
145         if (!buf || buf->format != UTERM_FORMAT_XRGB32)
146                 return -EINVAL;
147
148         v3d = uterm_drm_video_get_data(disp->video);
149         ret = uterm_drm3d_display_use(disp, NULL);
150         if (ret)
151                 return ret;
152         ret = init_shaders(disp->video);
153         if (ret)
154                 return ret;
155
156         sw = uterm_drm_mode_get_width(disp->current_mode);
157         sh = uterm_drm_mode_get_height(disp->current_mode);
158
159         vertices[0] = -1.0;
160         vertices[1] = -1.0;
161         vertices[2] = -1.0;
162         vertices[3] = +1.0;
163         vertices[4] = +1.0;
164         vertices[5] = +1.0;
165
166         vertices[6] = -1.0;
167         vertices[7] = -1.0;
168         vertices[8] = +1.0;
169         vertices[9] = +1.0;
170         vertices[10] = +1.0;
171         vertices[11] = -1.0;
172
173         texpos[0] = 0.0;
174         texpos[1] = 1.0;
175         texpos[2] = 0.0;
176         texpos[3] = 0.0;
177         texpos[4] = 1.0;
178         texpos[5] = 0.0;
179
180         texpos[6] = 0.0;
181         texpos[7] = 1.0;
182         texpos[8] = 1.0;
183         texpos[9] = 0.0;
184         texpos[10] = 1.0;
185         texpos[11] = 1.0;
186
187         tmp = x + buf->width;
188         if (tmp < x || x >= sw)
189                 return -EINVAL;
190         if (tmp > sw)
191                 width = sw - x;
192         else
193                 width = buf->width;
194
195         tmp = y + buf->height;
196         if (tmp < y || y >= sh)
197                 return -EINVAL;
198         if (tmp > sh)
199                 height = sh - y;
200         else
201                 height = buf->height;
202
203         glViewport(x, sh - y - height, width, height);
204         glDisable(GL_BLEND);
205
206         gl_shader_use(v3d->blit_shader);
207
208         gl_m4_identity(mat);
209         glUniformMatrix4fv(v3d->uni_blit_proj, 1, GL_FALSE, mat);
210
211         glActiveTexture(GL_TEXTURE0);
212         glBindTexture(GL_TEXTURE_2D, v3d->tex);
213         glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
214
215         if (v3d->supports_rowlen) {
216                 glPixelStorei(GL_UNPACK_ROW_LENGTH, buf->stride / 4);
217                 glTexImage2D(GL_TEXTURE_2D, 0, GL_BGRA_EXT, width, height, 0,
218                              GL_BGRA_EXT, GL_UNSIGNED_BYTE, buf->data);
219                 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
220         } else if (buf->stride == width) {
221                 glTexImage2D(GL_TEXTURE_2D, 0, GL_BGRA_EXT, width, height, 0,
222                              GL_BGRA_EXT, GL_UNSIGNED_BYTE, buf->data);
223         } else {
224                 packed = malloc(width * height);
225                 if (!packed)
226                         return -ENOMEM;
227
228                 src = buf->data;
229                 dst = packed;
230                 for (i = 0; i < height; ++i) {
231                         memcpy(dst, src, width * 4);
232                         dst += width * 4;
233                         src += buf->stride;
234                 }
235
236                 glTexImage2D(GL_TEXTURE_2D, 0, GL_BGRA_EXT, width, height, 0,
237                              GL_BGRA_EXT, GL_UNSIGNED_BYTE, packed);
238
239                 free(packed);
240         }
241
242         glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
243         glUniform1i(v3d->uni_blit_tex, 0);
244
245         glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, vertices);
246         glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, texpos);
247         glEnableVertexAttribArray(0);
248         glEnableVertexAttribArray(1);
249         glDrawArrays(GL_TRIANGLES, 0, 6);
250         glDisableVertexAttribArray(0);
251         glDisableVertexAttribArray(1);
252
253         if (gl_has_error(v3d->blit_shader)) {
254                 log_warning("GL error");
255                 return -EFAULT;
256         }
257
258         return 0;
259 }
260
261 static int display_blend(struct uterm_display *disp,
262                          const struct uterm_video_buffer *buf,
263                          unsigned int x, unsigned int y,
264                          uint8_t fr, uint8_t fg, uint8_t fb,
265                          uint8_t br, uint8_t bg, uint8_t bb)
266 {
267         struct uterm_drm3d_video *v3d;
268         unsigned int sw, sh, tmp, width, height, i;
269         float mat[16];
270         float vertices[6 * 2], texpos[6 * 2], fgcol[3], bgcol[3];
271         int ret;
272         uint8_t *packed, *src, *dst;
273
274         if (!buf || buf->format != UTERM_FORMAT_GREY)
275                 return -EINVAL;
276
277         v3d = uterm_drm_video_get_data(disp->video);
278         ret = uterm_drm3d_display_use(disp, NULL);
279         if (ret)
280                 return ret;
281         ret = init_shaders(disp->video);
282         if (ret)
283                 return ret;
284
285         sw = uterm_drm_mode_get_width(disp->current_mode);
286         sh = uterm_drm_mode_get_height(disp->current_mode);
287
288         vertices[0] = -1.0;
289         vertices[1] = -1.0;
290         vertices[2] = -1.0;
291         vertices[3] = +1.0;
292         vertices[4] = +1.0;
293         vertices[5] = +1.0;
294
295         vertices[6] = -1.0;
296         vertices[7] = -1.0;
297         vertices[8] = +1.0;
298         vertices[9] = +1.0;
299         vertices[10] = +1.0;
300         vertices[11] = -1.0;
301
302         texpos[0] = 0.0;
303         texpos[1] = 1.0;
304         texpos[2] = 0.0;
305         texpos[3] = 0.0;
306         texpos[4] = 1.0;
307         texpos[5] = 0.0;
308
309         texpos[6] = 0.0;
310         texpos[7] = 1.0;
311         texpos[8] = 1.0;
312         texpos[9] = 0.0;
313         texpos[10] = 1.0;
314         texpos[11] = 1.0;
315
316         fgcol[0] = fr / 255.0;
317         fgcol[1] = fg / 255.0;
318         fgcol[2] = fb / 255.0;
319         bgcol[0] = br / 255.0;
320         bgcol[1] = bg / 255.0;
321         bgcol[2] = bb / 255.0;
322
323         tmp = x + buf->width;
324         if (tmp < x || x >= sw)
325                 return -EINVAL;
326         if (tmp > sw)
327                 width = sw - x;
328         else
329                 width = buf->width;
330
331         tmp = y + buf->height;
332         if (tmp < y || y >= sh)
333                 return -EINVAL;
334         if (tmp > sh)
335                 height = sh - y;
336         else
337                 height = buf->height;
338
339         glViewport(x, sh - y - height, width, height);
340         glDisable(GL_BLEND);
341
342         gl_shader_use(v3d->blend_shader);
343
344         gl_m4_identity(mat);
345         glUniformMatrix4fv(v3d->uni_blend_proj, 1, GL_FALSE, mat);
346
347         glUniform3fv(v3d->uni_blend_fgcol, 1, fgcol);
348         glUniform3fv(v3d->uni_blend_bgcol, 1, bgcol);
349
350         glActiveTexture(GL_TEXTURE0);
351         glBindTexture(GL_TEXTURE_2D, v3d->tex);
352         glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
353
354         if (v3d->supports_rowlen) {
355                 glPixelStorei(GL_UNPACK_ROW_LENGTH, buf->stride);
356                 glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0,
357                              GL_ALPHA, GL_UNSIGNED_BYTE, buf->data);
358                 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
359         } else if (buf->stride == width) {
360                 glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0,
361                              GL_ALPHA, GL_UNSIGNED_BYTE, buf->data);
362         } else {
363                 packed = malloc(width * height);
364                 if (!packed)
365                         return -ENOMEM;
366
367                 src = buf->data;
368                 dst = packed;
369                 for (i = 0; i < height; ++i) {
370                         memcpy(dst, src, width);
371                         dst += width;
372                         src += buf->stride;
373                 }
374
375                 glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0,
376                              GL_ALPHA, GL_UNSIGNED_BYTE, packed);
377
378                 free(packed);
379         }
380
381         glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
382         glUniform1i(v3d->uni_blend_tex, 0);
383
384         glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, vertices);
385         glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, texpos);
386         glEnableVertexAttribArray(0);
387         glEnableVertexAttribArray(1);
388         glDrawArrays(GL_TRIANGLES, 0, 6);
389         glDisableVertexAttribArray(0);
390         glDisableVertexAttribArray(1);
391
392         if (gl_has_error(v3d->blend_shader)) {
393                 log_warning("GL error");
394                 return -EFAULT;
395         }
396
397         return 0;
398 }
399
400 int uterm_drm3d_display_fake_blendv(struct uterm_display *disp,
401                                     const struct uterm_video_blend_req *req,
402                                     size_t num)
403 {
404         int ret;
405         unsigned int i;
406
407         if (!disp || !req)
408                 return -EINVAL;
409
410         for (i = 0; i < num; ++i, ++req) {
411                 if (!req->buf)
412                         continue;
413
414                 ret = display_blend(disp, req->buf, req->x, req->y,
415                                     req->fr, req->fg, req->fb,
416                                     req->br, req->bg, req->bb);
417                 if (ret)
418                         return ret;
419         }
420
421         return 0;
422 }
423
424 int uterm_drm3d_display_fill(struct uterm_display *disp,
425                              uint8_t r, uint8_t g, uint8_t b,
426                              unsigned int x, unsigned int y,
427                              unsigned int width, unsigned int height)
428 {
429         struct uterm_drm3d_video *v3d;
430         unsigned int sw, sh, tmp, i;
431         float mat[16];
432         float vertices[6 * 2], colors[6 * 4];
433         int ret;
434
435         v3d = uterm_drm_video_get_data(disp->video);
436         ret = uterm_drm3d_display_use(disp, NULL);
437         if (ret)
438                 return ret;
439         ret = init_shaders(disp->video);
440         if (ret)
441                 return ret;
442
443         sw = uterm_drm_mode_get_width(disp->current_mode);
444         sh = uterm_drm_mode_get_height(disp->current_mode);
445
446         for (i = 0; i < 6; ++i) {
447                 colors[i * 4 + 0] = r / 255.0;
448                 colors[i * 4 + 1] = g / 255.0;
449                 colors[i * 4 + 2] = b / 255.0;
450                 colors[i * 4 + 3] = 1.0;
451         }
452
453         vertices[0] = -1.0;
454         vertices[1] = -1.0;
455         vertices[2] = -1.0;
456         vertices[3] = +1.0;
457         vertices[4] = +1.0;
458         vertices[5] = +1.0;
459
460         vertices[6] = -1.0;
461         vertices[7] = -1.0;
462         vertices[8] = +1.0;
463         vertices[9] = +1.0;
464         vertices[10] = +1.0;
465         vertices[11] = -1.0;
466
467         tmp = x + width;
468         if (tmp < x || x >= sw)
469                 return -EINVAL;
470         if (tmp > sw)
471                 width = sw - x;
472         tmp = y + height;
473         if (tmp < y || y >= sh)
474                 return -EINVAL;
475         if (tmp > sh)
476                 height = sh - y;
477
478         glViewport(x, y, width, height);
479         glDisable(GL_BLEND);
480
481         gl_shader_use(v3d->fill_shader);
482         gl_m4_identity(mat);
483         glUniformMatrix4fv(v3d->uni_fill_proj, 1, GL_FALSE, mat);
484         glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, vertices);
485         glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, colors);
486         glEnableVertexAttribArray(0);
487         glEnableVertexAttribArray(1);
488         glDrawArrays(GL_TRIANGLES, 0, 6);
489         glDisableVertexAttribArray(0);
490         glDisableVertexAttribArray(1);
491
492         if (gl_has_error(v3d->fill_shader)) {
493                 log_warning("GL error");
494                 return -EFAULT;
495         }
496
497         return 0;
498 }