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