VIGS: add h/w conversion from ARGB to XBGR
[sdk/emulator/qemu.git] / hw / vigs / vigs_gl_backend.c
1 /*
2  * vigs
3  *
4  * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact:
7  * Stanislav Vorobiov <s.vorobiov@samsung.com>
8  * Jinhyung Jo <jinhyung.jo@samsung.com>
9  * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
24  *
25  * Contributors:
26  * - S-Core Co., Ltd
27  *
28  */
29
30 #include "vigs_gl_backend.h"
31 #include "vigs_gl_pool.h"
32 #include "vigs_surface.h"
33 #include "vigs_plane.h"
34 #include "vigs_log.h"
35 #include "vigs_utils.h"
36 #include "vigs_ref.h"
37 #include "vigs_qt5.h"
38 #include "winsys_gl.h"
39 #include <math.h>
40
41 #ifdef __linux__
42 #include "drm/drm_fourcc.h"
43 #else
44 #define MAKE_FOURCC(a, b, c, d) (((unsigned int)(a)) | \
45                                 (((unsigned int)(b)) << 8) | \
46                                 (((unsigned int)(c)) << 16) | \
47                                 (((unsigned int)(d)) << 24))
48 #define DRM_FORMAT_ARGB8888    MAKE_FOURCC('A', 'R', '2', '4')
49 #define DRM_FORMAT_YUV420    MAKE_FOURCC('Y', 'U', '1', '2')
50 #define DRM_FORMAT_XBGR8888    MAKE_FOURCC('X', 'B', '2', '4')
51 #endif
52
53 struct vigs_gl_surface;
54
55 struct vigs_winsys_gl_surface
56 {
57     struct winsys_gl_surface base;
58
59     struct vigs_ref ref;
60
61     struct vigs_gl_backend *backend;
62
63     /*
64      * Will be set to NULL when orphaned.
65      */
66     struct vigs_gl_surface *parent;
67
68     /*
69      * GL texture format.
70      * @{
71      */
72
73     GLint tex_internalformat;
74     GLenum tex_format;
75     GLenum tex_type;
76
77     /*
78      * @}
79      */
80
81     /*
82      * Texture that represent this surface.
83      * Used as color attachment in 'fb'.
84      *
85      * Allocated on first access.
86      */
87     GLuint tex;
88 };
89
90 struct vigs_gl_surface
91 {
92     struct vigs_surface base;
93
94     /*
95      * Framebuffer that is used for rendering
96      * into front buffer.
97      *
98      * Allocated on first access.
99      */
100     GLuint fb;
101
102     /*
103      * Texture for temporary storage.
104      *
105      * Allocated on first access.
106      */
107     GLuint tmp_tex;
108
109     /*
110      * Ortho matrix for this surface.
111      */
112     GLfloat ortho[16];
113
114     /*
115      * Input textures for
116      * YUV conversion shader
117      */
118     GLuint yuv_textures[3];
119 };
120
121 static __inline struct vigs_winsys_gl_surface
122     *get_ws_sfc(struct vigs_gl_surface *sfc)
123 {
124     return (struct vigs_winsys_gl_surface*)sfc->base.ws_sfc;
125 }
126
127 /*
128  * PRIVATE.
129  * @{
130  */
131
132 static const char *g_vs_tex_source_gl2 =
133     "#version 120\n\n"
134     "attribute vec4 vertCoord;\n"
135     "uniform mat4 proj;\n"
136     "attribute vec2 texCoord;\n"
137     "varying vec2 v_texCoord;\n"
138     "void main()\n"
139     "{\n"
140     "    v_texCoord = texCoord;\n"
141     "    gl_Position = proj * vertCoord;\n"
142     "}\n";
143
144 static const char *g_vs_tex_source_gl3 =
145     "#version 140\n\n"
146     "in vec4 vertCoord;\n"
147     "uniform mat4 proj;\n"
148     "in vec2 texCoord;\n"
149     "out vec2 v_texCoord;\n"
150     "void main()\n"
151     "{\n"
152     "    v_texCoord = texCoord;\n"
153     "    gl_Position = proj * vertCoord;\n"
154     "}\n";
155
156 static const char *g_fs_tex_source_gl2 =
157     "#version 120\n\n"
158     "uniform sampler2D tex;\n"
159     "varying vec2 v_texCoord;\n"
160     "void main()\n"
161     "{\n"
162     "    gl_FragColor = texture2D(tex, v_texCoord);\n"
163     "}\n";
164
165 static const char *g_fs_tex_source_gl3 =
166     "#version 140\n\n"
167     "uniform sampler2D tex;\n"
168     "in vec2 v_texCoord;\n"
169     "out vec4 FragColor;\n"
170     "void main()\n"
171     "{\n"
172     "    FragColor = texture(tex, v_texCoord);\n"
173     "}\n";
174
175 static const char *g_vs_color_source_gl2 =
176     "#version 120\n\n"
177     "attribute vec4 vertCoord;\n"
178     "uniform mat4 proj;\n"
179     "void main()\n"
180     "{\n"
181     "    gl_Position = proj * vertCoord;\n"
182     "}\n";
183
184 static const char *g_vs_color_source_gl3 =
185     "#version 140\n\n"
186     "in vec4 vertCoord;\n"
187     "uniform mat4 proj;\n"
188     "void main()\n"
189     "{\n"
190     "    gl_Position = proj * vertCoord;\n"
191     "}\n";
192
193 static const char *g_fs_color_source_gl2 =
194     "#version 120\n\n"
195     "uniform vec4 color;\n"
196     "void main()\n"
197     "{\n"
198     "    gl_FragColor = color;\n"
199     "}\n";
200
201 static const char *g_fs_color_source_gl3 =
202     "#version 140\n\n"
203     "uniform vec4 color;\n"
204     "out vec4 FragColor;\n"
205     "void main()\n"
206     "{\n"
207     "    FragColor = color;\n"
208     "}\n";
209
210 static const char *g_vs_nv21_source_gl2 =
211     "#version 120\n\n"
212     "attribute vec4 vertCoord;\n"
213     "uniform mat4 proj;\n"
214     "attribute vec2 texCoord;\n"
215     "varying vec2 v_texCoord;\n"
216     "void main()\n"
217     "{\n"
218     "    v_texCoord = texCoord;\n"
219     "    gl_Position = proj * vertCoord;\n"
220     "}\n";
221
222 static const char *g_vs_nv21_source_gl3 =
223     "#version 140\n\n"
224     "in vec4 vertCoord;\n"
225     "uniform mat4 proj;\n"
226     "in vec2 texCoord;\n"
227     "out vec2 v_texCoord;\n"
228     "void main()\n"
229     "{\n"
230     "    v_texCoord = texCoord;\n"
231     "    gl_Position = proj * vertCoord;\n"
232     "}\n";
233
234 static const char *g_fs_nv21_source_gl2 =
235     "#version 120\n\n"
236     "uniform sampler2D ytex;\n"
237     "uniform sampler2D ctex;\n"
238     "uniform vec2 size;\n"
239     "uniform vec2 ytexSize;\n"
240     "uniform vec2 ctexSize;\n"
241     "varying vec2 v_texCoord;\n"
242     "void main()\n"
243     "{\n"
244     "    float ypos = floor((1.0 - v_texCoord.y) * size.y) * size.x + floor(v_texCoord.x * size.x);\n"
245     "    float ytexPos = floor(ypos / 4);\n"
246     "    vec4 ytexColor = texture2D(ytex, vec2((mod(ytexPos, ytexSize.x) + 0.5) / ytexSize.x, 1.0 - (floor(ytexPos / ytexSize.x) + 0.5) / ytexSize.y));\n"
247     "    float y = ytexColor[3 - int(mod(ypos + 1, 4))];\n"
248     "    float cpos = floor(floor((1.0 - v_texCoord.y) * size.y) / 2) * size.x + floor(v_texCoord.x * size.x);\n"
249     "    float ctexPos = floor(cpos / 4);\n"
250     "    vec4 ctexColor = texture2D(ctex, vec2((mod(ctexPos, ctexSize.x) + 0.5) / ctexSize.x, 1.0 - (floor(ctexPos / ctexSize.x) + 0.5) / ctexSize.y));\n"
251     "    int index = 2 * int(mod(floor(cpos / 2) + 1, 2));"
252     "    float u = ctexColor[index];\n"
253     "    float v = ctexColor[3 - index];\n"
254     "    u -= 0.5;"
255     "    v -= 0.5;"
256     "    gl_FragColor = vec4(y + 1.59765625 * v, y - 0.390625 * u - 0.8125 * v, y + 2.015625 * u, 1.0);\n"
257     "}\n";
258
259 static const char *g_fs_nv21_source_gl3 =
260     "#version 140\n\n"
261     "uniform sampler2D ytex;\n"
262     "uniform sampler2D ctex;\n"
263     "uniform vec2 size;\n"
264     "uniform vec2 ytexSize;\n"
265     "uniform vec2 ctexSize;\n"
266     "in vec2 v_texCoord;\n"
267     "out vec4 FragColor;\n"
268     "void main()\n"
269     "{\n"
270     "    float ypos = floor((1.0 - v_texCoord.y) * size.y) * size.x + floor(v_texCoord.x * size.x);\n"
271     "    float ytexPos = floor(ypos / 4);\n"
272     "    vec4 ytexColor = texture(ytex, vec2((mod(ytexPos, ytexSize.x) + 0.5) / ytexSize.x, 1.0 - (floor(ytexPos / ytexSize.x) + 0.5) / ytexSize.y));\n"
273     "    float y = ytexColor[3 - int(mod(ypos + 1, 4))];\n"
274     "    float cpos = floor(floor((1.0 - v_texCoord.y) * size.y) / 2) * size.x + floor(v_texCoord.x * size.x);\n"
275     "    float ctexPos = floor(cpos / 4);\n"
276     "    vec4 ctexColor = texture(ctex, vec2((mod(ctexPos, ctexSize.x) + 0.5) / ctexSize.x, 1.0 - (floor(ctexPos / ctexSize.x) + 0.5) / ctexSize.y));\n"
277     "    int index = 2 * int(mod(floor(cpos / 2) + 1, 2));"
278     "    float u = ctexColor[index];\n"
279     "    float v = ctexColor[3 - index];\n"
280     "    u -= 0.5;"
281     "    v -= 0.5;"
282     "    FragColor = vec4(y + 1.59765625 * v, y - 0.390625 * u - 0.8125 * v, y + 2.015625 * u, 1.0);\n"
283     "}\n";
284
285 static const char *g_vs_yuv420_source_gl2 =
286     "#version 120\n\n"
287     "attribute vec4 vertCoord;\n"
288     "uniform mat4 proj;\n"
289     "attribute vec2 texCoord;\n"
290     "varying vec2 v_texCoord;\n"
291     "void main()\n"
292     "{\n"
293     "    v_texCoord = texCoord;\n"
294     "    gl_Position = proj * vertCoord;\n"
295     "}\n";
296
297 static const char *g_vs_yuv420_source_gl3 =
298     "#version 140\n\n"
299     "in vec4 vertCoord;\n"
300     "uniform mat4 proj;\n"
301     "in vec2 texCoord;\n"
302     "out vec2 v_texCoord;\n"
303     "void main()\n"
304     "{\n"
305     "    v_texCoord = texCoord;\n"
306     "    gl_Position = proj * vertCoord;\n"
307     "}\n";
308
309 static const char *g_fs_yuv420_source_gl2 =
310     "#version 120\n\n"
311     "uniform sampler2D ytex;\n"
312     "uniform sampler2D utex;\n"
313     "uniform sampler2D vtex;\n"
314     "uniform vec2 size;\n"
315     "uniform vec2 ytexSize;\n"
316     "uniform vec2 utexSize;\n"
317     "uniform vec2 vtexSize;\n"
318     "varying vec2 v_texCoord;\n"
319     "void main()\n"
320     "{\n"
321     "    float ypos = floor((1.0 - v_texCoord.y) * size.y) * size.x + floor(v_texCoord.x * size.x);\n"
322     "    float ytexPos = floor(ypos / 4);\n"
323     "    vec4 ytexColor = texture2D(ytex, vec2((mod(ytexPos, ytexSize.x) + 0.5) / ytexSize.x, 1.0 - (floor(ytexPos / ytexSize.x) + 0.5) / ytexSize.y));\n"
324     "    float y = ytexColor[3 - int(mod(ypos + 1, 4))];\n"
325     "    float uvpos = floor(floor((1.0 - v_texCoord.y) * size.y) / 2) * size.x + floor(v_texCoord.x * size.x);\n"
326     "    float uvtexPos = floor(uvpos / 8);\n"
327     "    vec4 utexColor = texture2D(utex, vec2((mod(uvtexPos, utexSize.x) + 0.5) / utexSize.x, 1.0 - (floor(uvtexPos / utexSize.x) + 0.5) / utexSize.y));\n"
328     "    vec4 vtexColor = texture2D(vtex, vec2((mod(uvtexPos, vtexSize.x) + 0.5) / vtexSize.x, 1.0 - (floor(uvtexPos / vtexSize.x) + 0.5) / vtexSize.y));\n"
329     "    int index = 3 - int(mod((uvpos / 2) + 1, 4));\n"
330     "    float u = utexColor[index];\n"
331     "    float v = vtexColor[index];\n"
332     "    u -= 0.5;\n"
333     "    v -= 0.5;\n"
334     "    gl_FragColor = vec4(y + 1.59765625 * v, y - 0.390625 * u - 0.8125 * v, y + 2.015625 * u, 1.0);\n"
335     "}\n";
336
337 static const char *g_fs_yuv420_source_gl3 =
338     "#version 140\n\n"
339     "uniform sampler2D ytex;\n"
340     "uniform sampler2D utex;\n"
341     "uniform sampler2D vtex;\n"
342     "uniform vec2 size;\n"
343     "uniform vec2 ytexSize;\n"
344     "uniform vec2 utexSize;\n"
345     "uniform vec2 vtexSize;\n"
346     "in vec2 v_texCoord;\n"
347     "out vec4 FragColor;\n"
348     "void main()\n"
349     "{\n"
350     "    float ypos = floor((1.0 - v_texCoord.y) * size.y) * size.x + floor(v_texCoord.x * size.x);\n"
351     "    float ytexPos = floor(ypos / 4);\n"
352     "    vec4 ytexColor = texture(ytex, vec2((mod(ytexPos, ytexSize.x) + 0.5) / ytexSize.x, 1.0 - (floor(ytexPos / ytexSize.x) + 0.5) / ytexSize.y));\n"
353     "    float y = ytexColor[3 - int(mod(ypos + 1, 4))];\n"
354     "    float uvpos = floor(floor((1.0 - v_texCoord.y) * size.y) / 2) * size.x + floor(v_texCoord.x * size.x);\n"
355     "    float uvtexPos = floor(uvpos / 8);\n"
356     "    vec4 utexColor = texture(utex, vec2((mod(uvtexPos, utexSize.x) + 0.5) / utexSize.x, 1.0 - (floor(uvtexPos / utexSize.x) + 0.5) / utexSize.y));\n"
357     "    vec4 vtexColor = texture(vtex, vec2((mod(uvtexPos, vtexSize.x) + 0.5) / vtexSize.x, 1.0 - (floor(uvtexPos / vtexSize.x) + 0.5) / vtexSize.y));\n"
358     "    int index = 3 - int(mod((uvpos / 2) + 1, 4));\n"
359     "    float u = utexColor[index];\n"
360     "    float v = vtexColor[index];\n"
361     "    u -= 0.5;\n"
362     "    v -= 0.5;\n"
363     "    FragColor = vec4(y + 1.59765625 * v, y - 0.390625 * u - 0.8125 * v, y + 2.015625 * u, 1.0);\n"
364     "}\n";
365
366 static const char *g_fs_xbgr_source_gl2 =
367     "#version 120\n\n"
368     "uniform sampler2D tex;\n"
369     "varying vec2 v_texCoord;\n"
370     "void main()\n"
371     "{\n"
372     "    gl_FragColor = vec4(texture2D(tex, v_texCoord).bgr, 1.0);\n"
373     "}\n";
374
375 static const char *g_fs_xbgr_source_gl3 =
376     "#version 140\n\n"
377     "uniform sampler2D tex;\n"
378     "in vec2 v_texCoord;\n"
379     "out vec4 FragColor;\n"
380     "void main()\n"
381     "{\n"
382     "    FragColor = vec4(texture(tex, v_texCoord).bgr, 1.0);\n"
383     "}\n";
384
385 static GLuint vigs_gl_backend_alloc_tmp_texture(void *user_data,
386                                                 uint32_t width,
387                                                 uint32_t height,
388                                                 vigsp_surface_format format)
389 {
390     struct vigs_gl_backend *backend = (struct vigs_gl_backend*)user_data;
391     GLint tex_internalformat;
392     GLenum tex_format;
393     GLenum tex_type;
394     GLuint tex = 0, cur_tex = 0;
395
396     backend->GenTextures(1, &tex);
397
398     if (!tex) {
399         return 0;
400     }
401
402     switch (format) {
403     case vigsp_surface_bgrx8888:
404     case vigsp_surface_bgra8888:
405         tex_internalformat = GL_RGBA8;
406         tex_format = GL_BGRA;
407         tex_type = GL_UNSIGNED_INT_8_8_8_8_REV;
408         break;
409     default:
410         assert(false);
411         return 0;
412     }
413
414     backend->GetIntegerv(GL_TEXTURE_BINDING_2D, (GLint*)&cur_tex);
415     backend->BindTexture(GL_TEXTURE_2D, tex);
416
417     /*
418      * Workaround for problem in "Mesa DRI Intel(R) Ivybridge Desktop x86/MMX/SSE2, version 9.0.3":
419      * These lines used to be in 'vigs_gl_backend_init', but it turned out that they must
420      * be called after 'glBindTexture'.
421      */
422     backend->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
423     backend->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
424
425     backend->TexImage2D(GL_TEXTURE_2D, 0, tex_internalformat,
426                         width, height, 0,
427                         tex_format, tex_type,
428                         NULL);
429     backend->BindTexture(GL_TEXTURE_2D, cur_tex);
430
431     return tex;
432 }
433
434 static void vigs_gl_backend_release_tmp_texture(void *user_data, GLuint id)
435 {
436     struct vigs_gl_backend *backend = (struct vigs_gl_backend*)user_data;
437
438     backend->DeleteTextures(1, &id);
439 }
440
441 static GLuint vigs_gl_backend_alloc_framebuffer(void *user_data,
442                                                 uint32_t width,
443                                                 uint32_t height,
444                                                 vigsp_surface_format format)
445 {
446     struct vigs_gl_backend *backend = (struct vigs_gl_backend*)user_data;
447     GLuint fb = 0;
448
449     backend->GenFramebuffers(1, &fb);
450
451     return fb;
452 }
453
454 static void vigs_gl_backend_release_framebuffer(void *user_data, GLuint id)
455 {
456     struct vigs_gl_backend *backend = (struct vigs_gl_backend*)user_data;
457
458     backend->DeleteFramebuffers(1, &id);
459 }
460
461 static GLuint vigs_gl_create_shader(struct vigs_gl_backend *backend,
462                                     const char *source,
463                                     GLenum type)
464 {
465     GLuint shader = backend->CreateShader(type);
466     GLint tmp = 0;
467
468     if (!shader) {
469         VIGS_LOG_CRITICAL("Unable to create shader type %d", type);
470         return 0;
471     }
472
473     backend->ShaderSource(shader, 1, &source, NULL);
474     backend->CompileShader(shader);
475     backend->GetShaderiv(shader, GL_COMPILE_STATUS, &tmp);
476
477     if (!tmp) {
478         char *buff;
479
480         tmp = 0;
481
482         backend->GetShaderiv(shader, GL_INFO_LOG_LENGTH, &tmp);
483
484         buff = g_malloc0(tmp);
485
486         backend->GetShaderInfoLog(shader, tmp, NULL, buff);
487
488         VIGS_LOG_CRITICAL("Unable to compile shader (type = %d) - %s",
489                           type, buff);
490
491         backend->DeleteShader(shader);
492
493         g_free(buff);
494
495         return 0;
496     }
497
498     return shader;
499 }
500
501 static GLuint vigs_gl_create_program(struct vigs_gl_backend *backend,
502                                      GLuint vs_id,
503                                      GLuint fs_id)
504 {
505     GLuint program = backend->CreateProgram();
506     GLint tmp = 0;
507
508     if (!program) {
509         VIGS_LOG_CRITICAL("Unable to create program");
510         return 0;
511     }
512
513     backend->AttachShader(program, vs_id);
514     backend->AttachShader(program, fs_id);
515     backend->LinkProgram(program);
516     backend->GetProgramiv(program, GL_LINK_STATUS, &tmp);
517
518     if (!tmp) {
519         char *buff;
520
521         tmp = 0;
522
523         backend->GetProgramiv(program, GL_INFO_LOG_LENGTH, &tmp);
524
525         buff = g_malloc0(tmp);
526
527         backend->GetProgramInfoLog(program, tmp, NULL, buff);
528
529         VIGS_LOG_CRITICAL("Unable to link program - %s", buff);
530
531         backend->DeleteProgram(program);
532
533         g_free(buff);
534
535         return 0;
536     }
537
538     return program;
539 }
540
541 static void vigs_gl_draw_update_vert_tex_buffer(struct vigs_gl_backend *backend,
542                                                 uint32_t size)
543 {
544     void *ptr;
545
546     if (size > backend->vbo_size) {
547         backend->vbo_size = size;
548         backend->BufferData(GL_ARRAY_BUFFER,
549                             size,
550                             0,
551                             GL_STREAM_DRAW);
552     }
553
554     if (backend->MapBufferRange) {
555         ptr = backend->MapBufferRange(GL_ARRAY_BUFFER, 0, size,
556                                       GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT);
557
558         if (ptr) {
559             memcpy(ptr, vigs_vector_data(&backend->v1), size / 2);
560             memcpy(ptr + (size / 2), vigs_vector_data(&backend->v2), size / 2);
561
562             backend->UnmapBuffer(GL_ARRAY_BUFFER);
563         } else {
564             VIGS_LOG_ERROR("glMapBufferRange failed");
565         }
566     } else {
567         ptr = backend->MapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
568         if (ptr) {
569             memcpy(ptr, vigs_vector_data(&backend->v1), size / 2);
570             memcpy(ptr + (size / 2), vigs_vector_data(&backend->v2), size / 2);
571
572             backend->UnmapBuffer(GL_ARRAY_BUFFER);
573         } else {
574             backend->Finish();
575             backend->BufferSubData(GL_ARRAY_BUFFER, 0,
576                                    (size / 2), vigs_vector_data(&backend->v1));
577             backend->BufferSubData(GL_ARRAY_BUFFER, (size / 2),
578                                    (size / 2), vigs_vector_data(&backend->v2));
579         }
580     }
581 }
582
583 static void vigs_gl_draw_tex_prog(struct vigs_gl_backend *backend,
584                                   uint32_t count)
585 {
586     uint32_t size = count * 16;
587
588     vigs_gl_draw_update_vert_tex_buffer(backend, size);
589
590     backend->EnableVertexAttribArray(backend->tex_prog_vertCoord_loc);
591     backend->EnableVertexAttribArray(backend->tex_prog_texCoord_loc);
592
593     backend->VertexAttribPointer(backend->tex_prog_vertCoord_loc,
594                                  2, GL_FLOAT, GL_FALSE, 0, NULL);
595     backend->VertexAttribPointer(backend->tex_prog_texCoord_loc,
596                                  2, GL_FLOAT, GL_FALSE, 0, NULL + (size / 2));
597
598     backend->DrawArrays(GL_TRIANGLES, 0, count);
599
600     backend->DisableVertexAttribArray(backend->tex_prog_texCoord_loc);
601     backend->DisableVertexAttribArray(backend->tex_prog_vertCoord_loc);
602 }
603
604 static void vigs_gl_draw_color_prog(struct vigs_gl_backend *backend,
605                                     const GLfloat color[4],
606                                     uint32_t count)
607 {
608     uint32_t size = count * 8;
609     void *ptr;
610
611     if (size > backend->vbo_size) {
612         backend->vbo_size = size;
613         backend->BufferData(GL_ARRAY_BUFFER,
614                             size,
615                             0,
616                             GL_STREAM_DRAW);
617     }
618
619     if (backend->MapBufferRange) {
620         ptr = backend->MapBufferRange(GL_ARRAY_BUFFER, 0, size,
621                                       GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT);
622
623         if (ptr) {
624             memcpy(ptr, vigs_vector_data(&backend->v1), size);
625
626             backend->UnmapBuffer(GL_ARRAY_BUFFER);
627         } else {
628             VIGS_LOG_ERROR("glMapBufferRange failed");
629         }
630     } else {
631         ptr = backend->MapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
632         if (ptr) {
633             memcpy(ptr, vigs_vector_data(&backend->v1), size);
634
635             backend->UnmapBuffer(GL_ARRAY_BUFFER);
636         } else {
637             backend->Finish();
638             backend->BufferSubData(GL_ARRAY_BUFFER, 0, size,
639                                    vigs_vector_data(&backend->v1));
640         }
641     }
642
643     backend->Uniform4fv(backend->color_prog_color_loc, 1, color);
644
645     backend->EnableVertexAttribArray(backend->color_prog_vertCoord_loc);
646
647     backend->VertexAttribPointer(backend->color_prog_vertCoord_loc,
648                                  2, GL_FLOAT, GL_FALSE, 0, NULL);
649
650     backend->DrawArrays(GL_TRIANGLES, 0, count);
651
652     backend->DisableVertexAttribArray(backend->color_prog_vertCoord_loc);
653 }
654
655 static void vigs_gl_draw_nv21_prog(struct vigs_gl_backend *backend,
656                                    uint32_t count)
657 {
658     uint32_t size = count * 16;
659
660     vigs_gl_draw_update_vert_tex_buffer(backend, size);
661
662     backend->EnableVertexAttribArray(backend->nv21_prog_vertCoord_loc);
663     backend->EnableVertexAttribArray(backend->nv21_prog_texCoord_loc);
664
665     backend->VertexAttribPointer(backend->nv21_prog_vertCoord_loc,
666                                  2, GL_FLOAT, GL_FALSE, 0, NULL);
667     backend->VertexAttribPointer(backend->nv21_prog_texCoord_loc,
668                                  2, GL_FLOAT, GL_FALSE, 0, NULL + (size / 2));
669
670     backend->DrawArrays(GL_TRIANGLES, 0, count);
671
672     backend->DisableVertexAttribArray(backend->nv21_prog_texCoord_loc);
673     backend->DisableVertexAttribArray(backend->nv21_prog_vertCoord_loc);
674 }
675
676 static void vigs_gl_draw_yuv420_prog(struct vigs_gl_backend *backend,
677                                      uint32_t count)
678 {
679     uint32_t size = count * 16;
680
681     vigs_gl_draw_update_vert_tex_buffer(backend, size);
682
683     backend->EnableVertexAttribArray(backend->yuv420_prog_vertCoord_loc);
684     backend->EnableVertexAttribArray(backend->yuv420_prog_texCoord_loc);
685
686     backend->VertexAttribPointer(backend->yuv420_prog_vertCoord_loc,
687                                  2, GL_FLOAT, GL_FALSE, 0, NULL);
688     backend->VertexAttribPointer(backend->yuv420_prog_texCoord_loc,
689                                  2, GL_FLOAT, GL_FALSE, 0, NULL + (size / 2));
690
691     backend->DrawArrays(GL_TRIANGLES, 0, count);
692
693     backend->DisableVertexAttribArray(backend->yuv420_prog_texCoord_loc);
694     backend->DisableVertexAttribArray(backend->yuv420_prog_vertCoord_loc);
695 }
696
697 static void vigs_gl_draw_xbgr_prog(struct vigs_gl_backend *backend,
698                                   uint32_t count)
699 {
700     uint32_t size = count * 16;
701
702     vigs_gl_draw_update_vert_tex_buffer(backend, size);
703
704     backend->EnableVertexAttribArray(backend->xbgr_prog_vertCoord_loc);
705     backend->EnableVertexAttribArray(backend->xbgr_prog_texCoord_loc);
706
707     backend->VertexAttribPointer(backend->xbgr_prog_vertCoord_loc,
708                                  2, GL_FLOAT, GL_FALSE, 0, NULL);
709     backend->VertexAttribPointer(backend->xbgr_prog_texCoord_loc,
710                                  2, GL_FLOAT, GL_FALSE, 0, NULL + (size / 2));
711
712     backend->DrawArrays(GL_TRIANGLES, 0, count);
713
714     backend->DisableVertexAttribArray(backend->xbgr_prog_texCoord_loc);
715     backend->DisableVertexAttribArray(backend->xbgr_prog_vertCoord_loc);
716 }
717
718 static void vigs_gl_create_ortho(GLfloat left, GLfloat right,
719                                  GLfloat bottom, GLfloat top,
720                                  GLfloat nearf, GLfloat farf,
721                                  GLfloat ortho[16])
722 {
723     ortho[0] = 2.0f / (right - left);
724     ortho[5] = 2.0f / (top - bottom);
725     ortho[10] = -2.0f / (farf - nearf);
726     ortho[12] = -(right + left) / (right - left);
727     ortho[13] = -(top + bottom) / (top - bottom);
728     ortho[14] = -(farf + nearf) / (farf - nearf);
729     ortho[15] = 1.0f;
730 }
731
732 static void vigs_gl_translate_color(vigsp_color color,
733                                     vigsp_surface_format format,
734                                     GLfloat res[4])
735 {
736     res[3] = 1.0f;
737     switch (format) {
738     case vigsp_surface_bgra8888:
739         res[3] = (GLfloat)((color >> 24) & 0xFF) / 255.0f;
740         /* Fall through. */
741     case vigsp_surface_bgrx8888:
742         res[0] = (GLfloat)((color >> 16) & 0xFF) / 255.0f;
743         res[1] = (GLfloat)((color >> 8) & 0xFF) / 255.0f;
744         res[2] = (GLfloat)(color & 0xFF) / 255.0f;
745         break;
746     default:
747         assert(false);
748         res[0] = 0.0f;
749         res[1] = 0.0f;
750         res[2] = 0.0f;
751     }
752 }
753
754 static bool vigs_winsys_gl_surface_create_texture(struct vigs_winsys_gl_surface *ws_sfc)
755 {
756     GLuint cur_tex = 0, tmp_tex = 0;
757
758     if (ws_sfc->tex) {
759         return true;
760     }
761
762     ws_sfc->backend->GenTextures(1, &tmp_tex);
763
764     if (!tmp_tex) {
765         return false;
766     }
767
768     ws_sfc->backend->GetIntegerv(GL_TEXTURE_BINDING_2D, (GLint*)&cur_tex);
769     ws_sfc->backend->BindTexture(GL_TEXTURE_2D, tmp_tex);
770
771     /*
772      * Workaround for problem in "Mesa DRI Intel(R) Ivybridge Desktop x86/MMX/SSE2, version 9.0.3":
773      * These lines used to be in 'vigs_gl_backend_init', but it turned out that they must
774      * be called after 'glBindTexture'.
775      */
776     ws_sfc->backend->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
777     ws_sfc->backend->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
778
779     ws_sfc->backend->TexImage2D(GL_TEXTURE_2D, 0, ws_sfc->tex_internalformat,
780                                 ws_sfc->base.base.width, ws_sfc->base.base.height, 0,
781                                 ws_sfc->tex_format, ws_sfc->tex_type,
782                                 NULL);
783     ws_sfc->backend->BindTexture(GL_TEXTURE_2D, cur_tex);
784
785     ws_sfc->tex = tmp_tex;
786
787     return true;
788 }
789
790 static bool vigs_gl_surface_create_tmp_texture(struct vigs_gl_surface *gl_sfc)
791 {
792     struct vigs_gl_backend *gl_backend = (struct vigs_gl_backend*)gl_sfc->base.backend;
793
794     if (gl_sfc->tmp_tex) {
795         return true;
796     }
797
798     gl_sfc->tmp_tex = vigs_gl_pool_alloc(gl_backend->tex_pool,
799                                          gl_sfc->base.ws_sfc->width,
800                                          gl_sfc->base.ws_sfc->height,
801                                          gl_sfc->base.format);
802
803     return gl_sfc->tmp_tex != 0;
804 }
805
806 static bool vigs_gl_surface_setup_framebuffer(struct vigs_gl_surface *gl_sfc,
807                                               GLuint prog_id,
808                                               GLint proj_loc)
809 {
810     struct vigs_gl_backend *gl_backend = (struct vigs_gl_backend*)gl_sfc->base.backend;
811
812     if (!gl_sfc->fb) {
813         gl_sfc->fb = vigs_gl_pool_alloc(gl_backend->fb_pool,
814                                         gl_sfc->base.ws_sfc->width,
815                                         gl_sfc->base.ws_sfc->height,
816                                         gl_sfc->base.format);
817
818         if (!gl_sfc->fb) {
819             return false;
820         }
821     }
822
823     if (gl_backend->cur_prog_id != prog_id) {
824         gl_backend->UseProgram(prog_id);
825         gl_backend->cur_prog_id = prog_id;
826     }
827
828     gl_backend->Viewport(0, 0,
829                          gl_sfc->base.ws_sfc->width,
830                          gl_sfc->base.ws_sfc->height);
831
832     gl_backend->UniformMatrix4fv(proj_loc, 1, GL_FALSE, gl_sfc->ortho);
833
834     gl_backend->BindFramebuffer(GL_FRAMEBUFFER, gl_sfc->fb);
835
836     gl_backend->Disable(GL_BLEND);
837
838     return true;
839 }
840
841 static bool vigs_gl_update_dpy_texture(struct vigs_gl_backend *gl_backend,
842                                        uint32_t width, uint32_t height)
843 {
844     GLuint cur_tex = 0;
845
846     if (vigs_qt5_onscreen_enabled()) {
847         // find available texture by iteration.
848         // it is OK, since we have only very few textures.
849         gl_backend->current_dpy = NULL;
850         int i;
851         for (i = 0; i < TEXTURE_NUM; ++i) {
852             struct dpy_item *item = &(gl_backend->dpy_items[i]);
853             if(likely(!qemu_mutex_trylock(&item->mutex))) {
854                 if (item->available) {
855                     item->available = false;
856                     gl_backend->current_dpy = item;
857                     qemu_mutex_unlock(&item->mutex);
858                     break;
859                 }
860                 qemu_mutex_unlock(&item->mutex);
861             }
862         }
863         if (unlikely(!gl_backend->current_dpy)) {
864             // can not enter here.
865             // simply we drop this frame.
866             return false;
867         }
868     } else {
869         gl_backend->current_dpy = &gl_backend->dpy_items[0];
870     }
871
872     gl_backend->GetIntegerv(GL_TEXTURE_BINDING_2D, (GLint *)&cur_tex);
873
874     if (gl_backend->current_dpy->tex) {
875         if ((gl_backend->current_dpy->width == width) &&
876             (gl_backend->current_dpy->height == height)) {
877             return true;
878         }
879         gl_backend->BindTexture(GL_TEXTURE_2D, gl_backend->current_dpy->tex);
880     } else {
881         GLuint tmp_tex = 0;
882
883         gl_backend->GenTextures(1, &tmp_tex);
884
885         if (!tmp_tex) {
886             return false;
887         }
888
889         gl_backend->current_dpy->tex = tmp_tex;
890
891         gl_backend->BindTexture(GL_TEXTURE_2D, tmp_tex);
892
893         gl_backend->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
894         gl_backend->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
895         gl_backend->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
896         gl_backend->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
897     }
898
899     gl_backend->TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8,
900                            width, height, 0,
901                            GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV,
902                            NULL);
903
904     gl_backend->BindTexture(GL_TEXTURE_2D, cur_tex);
905
906     gl_backend->current_dpy->width = width;
907     gl_backend->current_dpy->height = height;
908
909     return true;
910 }
911
912 /*
913  * @}
914  */
915
916 /*
917  * vigs_winsys_gl_surface.
918  * @{
919  */
920
921 static void vigs_winsys_gl_surface_acquire(struct winsys_surface *sfc)
922 {
923     struct vigs_winsys_gl_surface *vigs_sfc = (struct vigs_winsys_gl_surface*)sfc;
924     vigs_ref_acquire(&vigs_sfc->ref);
925 }
926
927 static void vigs_winsys_gl_surface_release(struct winsys_surface *sfc)
928 {
929     struct vigs_winsys_gl_surface *vigs_sfc = (struct vigs_winsys_gl_surface*)sfc;
930     vigs_ref_release(&vigs_sfc->ref);
931 }
932
933 static void vigs_winsys_gl_surface_set_dirty(struct winsys_surface *sfc)
934 {
935     struct vigs_winsys_gl_surface *vigs_sfc = (struct vigs_winsys_gl_surface*)sfc;
936     if (vigs_sfc->parent) {
937         vigs_sfc->parent->base.is_dirty = true;
938     }
939 }
940
941 static void vigs_winsys_gl_surface_draw_pixels(struct winsys_surface *sfc,
942                                                uint8_t *pixels)
943 {
944     struct vigs_winsys_gl_surface *vigs_sfc = (struct vigs_winsys_gl_surface*)sfc;
945     bool has_current = vigs_sfc->backend->has_current(vigs_sfc->backend);
946     if (!vigs_sfc->parent) {
947         return;
948     }
949
950     if (has_current ||
951         vigs_sfc->backend->make_current(vigs_sfc->backend, true)) {
952         struct vigsp_rect rect;
953
954         rect.pos.x = 0;
955         rect.pos.y = 0;
956         rect.size.w = sfc->width;
957         rect.size.h = sfc->height;
958
959         vigs_sfc->parent->base.draw_pixels(&vigs_sfc->parent->base,
960                                            pixels,
961                                            &rect,
962                                            1);
963
964         vigs_sfc->parent->base.is_dirty = true;
965
966         vigs_sfc->backend->Finish();
967
968         if (!has_current) {
969             vigs_sfc->backend->make_current(vigs_sfc->backend, false);
970         }
971     } else {
972         VIGS_LOG_CRITICAL("make_current failed");
973     }
974 }
975
976 static void vigs_winsys_gl_surface_draw_pixels_scaled(struct winsys_surface *sfc,
977                                                       uint8_t *pixels,
978                                                       uint32_t width,
979                                                       uint32_t height)
980 {
981     struct vigs_winsys_gl_surface *vigs_sfc = (struct vigs_winsys_gl_surface*)sfc;
982     bool has_current = vigs_sfc->backend->has_current(vigs_sfc->backend);
983     if (!vigs_sfc->parent) {
984         return;
985     }
986
987     if (has_current ||
988         vigs_sfc->backend->make_current(vigs_sfc->backend, true)) {
989
990         vigs_sfc->parent->base.draw_pixels_scaled(&vigs_sfc->parent->base,
991                                                   pixels,
992                                                   width,
993                                                   height);
994
995         vigs_sfc->parent->base.is_dirty = true;
996
997         vigs_sfc->backend->Finish();
998
999         if (!has_current) {
1000             vigs_sfc->backend->make_current(vigs_sfc->backend, false);
1001         }
1002     } else {
1003         VIGS_LOG_CRITICAL("make_current failed");
1004     }
1005 }
1006
1007 static GLuint vigs_winsys_gl_surface_get_texture(struct winsys_gl_surface *sfc)
1008 {
1009     struct vigs_winsys_gl_surface *vigs_sfc = (struct vigs_winsys_gl_surface*)sfc;
1010     bool has_current = vigs_sfc->backend->has_current(vigs_sfc->backend);
1011
1012     if (!vigs_sfc->tex &&
1013         (has_current ||
1014         vigs_sfc->backend->make_current(vigs_sfc->backend, true))) {
1015
1016         vigs_winsys_gl_surface_create_texture(vigs_sfc);
1017
1018         if (!has_current) {
1019             vigs_sfc->backend->make_current(vigs_sfc->backend, false);
1020         }
1021     }
1022
1023     return vigs_sfc->tex;
1024 }
1025
1026 static void vigs_winsys_gl_surface_destroy(struct vigs_ref *ref)
1027 {
1028     struct vigs_winsys_gl_surface *vigs_sfc =
1029         container_of(ref, struct vigs_winsys_gl_surface, ref);
1030     bool has_current = vigs_sfc->backend->has_current(vigs_sfc->backend);
1031
1032     if (has_current ||
1033         vigs_sfc->backend->make_current(vigs_sfc->backend, true)) {
1034         if (vigs_sfc->tex) {
1035             vigs_sfc->backend->DeleteTextures(1, &vigs_sfc->tex);
1036         }
1037
1038         if (!has_current) {
1039             vigs_sfc->backend->make_current(vigs_sfc->backend, false);
1040         }
1041     }
1042
1043     vigs_ref_cleanup(&vigs_sfc->ref);
1044
1045     g_free(vigs_sfc);
1046 }
1047
1048 static struct vigs_winsys_gl_surface
1049     *vigs_winsys_gl_surface_create(struct vigs_gl_backend *backend,
1050                                    struct vigs_gl_surface *parent,
1051                                    uint32_t width,
1052                                    uint32_t height,
1053                                    GLint tex_internalformat,
1054                                    GLenum tex_format,
1055                                    GLenum tex_type)
1056 {
1057     struct vigs_winsys_gl_surface *ws_sfc;
1058
1059     ws_sfc = g_malloc0(sizeof(*ws_sfc));
1060
1061     ws_sfc->base.base.width = width;
1062     ws_sfc->base.base.height = height;
1063     ws_sfc->base.base.acquire = &vigs_winsys_gl_surface_acquire;
1064     ws_sfc->base.base.release = &vigs_winsys_gl_surface_release;
1065     ws_sfc->base.base.set_dirty = &vigs_winsys_gl_surface_set_dirty;
1066     ws_sfc->base.base.draw_pixels = &vigs_winsys_gl_surface_draw_pixels;
1067     ws_sfc->base.base.draw_pixels_scaled = &vigs_winsys_gl_surface_draw_pixels_scaled;
1068     ws_sfc->base.get_texture = &vigs_winsys_gl_surface_get_texture;
1069     ws_sfc->tex_internalformat = tex_internalformat;
1070     ws_sfc->tex_format = tex_format;
1071     ws_sfc->tex_type = tex_type;
1072     ws_sfc->backend = backend;
1073     ws_sfc->parent = parent;
1074
1075     vigs_ref_init(&ws_sfc->ref, &vigs_winsys_gl_surface_destroy);
1076
1077     return ws_sfc;
1078 }
1079
1080 static void vigs_winsys_gl_surface_orphan(struct vigs_winsys_gl_surface *sfc)
1081 {
1082     sfc->parent = NULL;
1083 }
1084
1085 /*
1086  * @}
1087  */
1088
1089 static void vigs_gl_backend_batch_start(struct vigs_backend *backend)
1090 {
1091     struct vigs_gl_backend *gl_backend = (struct vigs_gl_backend*)backend;
1092
1093     if (!gl_backend->make_current(gl_backend, true)) {
1094         VIGS_LOG_CRITICAL("make_current failed");
1095     }
1096 }
1097
1098 /*
1099  * vigs_gl_surface.
1100  * @{
1101  */
1102
1103 static void vigs_gl_surface_read_pixels(struct vigs_surface *sfc,
1104                                         uint8_t *pixels)
1105 {
1106     struct vigs_gl_backend *gl_backend = (struct vigs_gl_backend*)sfc->backend;
1107     struct vigs_gl_surface *gl_sfc = (struct vigs_gl_surface*)sfc;
1108     struct vigs_winsys_gl_surface *ws_sfc = get_ws_sfc(gl_sfc);
1109     GLfloat sfc_w, sfc_h;
1110     GLfloat *vert_coords;
1111     GLfloat *tex_coords;
1112
1113     if (!ws_sfc->tex) {
1114         VIGS_LOG_TRACE("skipping blank read");
1115         goto out;
1116     }
1117
1118     if (!vigs_winsys_gl_surface_create_texture(ws_sfc)) {
1119         goto out;
1120     }
1121
1122     if (!vigs_gl_surface_create_tmp_texture(gl_sfc)) {
1123         goto out;
1124     }
1125
1126     if (!vigs_gl_surface_setup_framebuffer(gl_sfc,
1127                                            gl_backend->tex_prog_id,
1128                                            gl_backend->tex_prog_proj_loc)) {
1129         goto out;
1130     }
1131
1132     vigs_vector_resize(&gl_backend->v1, 0);
1133     vigs_vector_resize(&gl_backend->v2, 0);
1134
1135     sfc_w = ws_sfc->base.base.width;
1136     sfc_h = ws_sfc->base.base.height;
1137
1138     gl_backend->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
1139                                      GL_TEXTURE_2D, gl_sfc->tmp_tex, 0);
1140
1141     vert_coords = vigs_vector_append(&gl_backend->v1,
1142                                      (12 * sizeof(GLfloat)));
1143     tex_coords = vigs_vector_append(&gl_backend->v2,
1144                                     (12 * sizeof(GLfloat)));
1145
1146     vert_coords[6] = vert_coords[0] = 0;
1147     vert_coords[7] = vert_coords[1] = sfc_h;
1148     vert_coords[2] = sfc_w;
1149     vert_coords[3] = sfc_h;
1150     vert_coords[8] = vert_coords[4] = sfc_w;
1151     vert_coords[9] = vert_coords[5] = 0;
1152     vert_coords[10] = 0;
1153     vert_coords[11] = 0;
1154
1155     tex_coords[6] = tex_coords[0] = 0;
1156     tex_coords[7] = tex_coords[1] = 0;
1157     tex_coords[2] = 1;
1158     tex_coords[3] = 0;
1159     tex_coords[8] = tex_coords[4] = 1;
1160     tex_coords[9] = tex_coords[5] = 1;
1161     tex_coords[10] = 0;
1162     tex_coords[11] = 1;
1163
1164     gl_backend->BindTexture(GL_TEXTURE_2D, ws_sfc->tex);
1165
1166     vigs_gl_draw_tex_prog(gl_backend, 6);
1167
1168     gl_backend->PixelStorei(GL_PACK_ALIGNMENT, 1);
1169     gl_backend->ReadPixels(0, 0, sfc_w, sfc_h,
1170                            ws_sfc->tex_format, ws_sfc->tex_type,
1171                            pixels);
1172
1173 out:
1174     gl_backend->BindFramebuffer(GL_FRAMEBUFFER, 0);
1175 }
1176
1177 static void vigs_gl_surface_draw_pixels(struct vigs_surface *sfc,
1178                                         uint8_t *pixels,
1179                                         const struct vigsp_rect *entries,
1180                                         uint32_t num_entries)
1181 {
1182     struct vigs_gl_backend *gl_backend = (struct vigs_gl_backend*)sfc->backend;
1183     struct vigs_gl_surface *gl_sfc = (struct vigs_gl_surface*)sfc;
1184     struct vigs_winsys_gl_surface *ws_sfc = get_ws_sfc(gl_sfc);
1185     GLfloat sfc_w, sfc_h;
1186     GLfloat *vert_coords;
1187     GLfloat *tex_coords;
1188     uint32_t i;
1189
1190     if (!vigs_winsys_gl_surface_create_texture(ws_sfc)) {
1191         goto out;
1192     }
1193
1194     if (!vigs_gl_surface_create_tmp_texture(gl_sfc)) {
1195         goto out;
1196     }
1197
1198     if (!vigs_gl_surface_setup_framebuffer(gl_sfc,
1199                                            gl_backend->tex_prog_id,
1200                                            gl_backend->tex_prog_proj_loc)) {
1201         goto out;
1202     }
1203
1204     sfc_w = ws_sfc->base.base.width;
1205     sfc_h = ws_sfc->base.base.height;
1206
1207     gl_backend->BindTexture(GL_TEXTURE_2D, gl_sfc->tmp_tex);
1208
1209     gl_backend->PixelStorei(GL_UNPACK_ALIGNMENT, 1);
1210     gl_backend->PixelStorei(GL_UNPACK_ROW_LENGTH, sfc_w);
1211
1212     for (i = 0; i < num_entries; ++i) {
1213         uint32_t x = entries[i].pos.x;
1214         uint32_t y = entries[i].pos.y;
1215         uint32_t width = entries[i].size.w;
1216         uint32_t height = entries[i].size.h;
1217         VIGS_LOG_TRACE("x = %u, y = %u, width = %u, height = %u",
1218                        x, y,
1219                        width, height);
1220         gl_backend->PixelStorei(GL_UNPACK_SKIP_PIXELS, x);
1221         gl_backend->PixelStorei(GL_UNPACK_SKIP_ROWS, y);
1222         gl_backend->TexSubImage2D(GL_TEXTURE_2D, 0, x, y,
1223                                   width, height,
1224                                   ws_sfc->tex_format,
1225                                   ws_sfc->tex_type,
1226                                   pixels);
1227     }
1228
1229     vigs_vector_resize(&gl_backend->v1, 0);
1230     vigs_vector_resize(&gl_backend->v2, 0);
1231
1232     gl_backend->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
1233                                      GL_TEXTURE_2D, ws_sfc->tex, 0);
1234
1235     for (i = 0; i < num_entries; ++i) {
1236         vert_coords = vigs_vector_append(&gl_backend->v1,
1237                                          (12 * sizeof(GLfloat)));
1238         tex_coords = vigs_vector_append(&gl_backend->v2,
1239                                         (12 * sizeof(GLfloat)));
1240
1241         vert_coords[6] = vert_coords[0] = entries[i].pos.x;
1242         vert_coords[7] = vert_coords[1] = sfc_h - entries[i].pos.y;
1243         vert_coords[2] = entries[i].pos.x + entries[i].size.w;
1244         vert_coords[3] = sfc_h - entries[i].pos.y;
1245         vert_coords[8] = vert_coords[4] = entries[i].pos.x + entries[i].size.w;
1246         vert_coords[9] = vert_coords[5] = sfc_h - (entries[i].pos.y + entries[i].size.h);
1247         vert_coords[10] = entries[i].pos.x;
1248         vert_coords[11] = sfc_h - (entries[i].pos.y + entries[i].size.h);
1249
1250         tex_coords[6] = tex_coords[0] = (GLfloat)entries[i].pos.x / sfc_w;
1251         tex_coords[7] = tex_coords[1] = (GLfloat)entries[i].pos.y / sfc_h;
1252         tex_coords[2] = (GLfloat)(entries[i].pos.x + entries[i].size.w) / sfc_w;
1253         tex_coords[3] = (GLfloat)entries[i].pos.y / sfc_h;
1254         tex_coords[8] = tex_coords[4] = (GLfloat)(entries[i].pos.x + entries[i].size.w) / sfc_w;
1255         tex_coords[9] = tex_coords[5] = (GLfloat)(entries[i].pos.y + entries[i].size.h) / sfc_h;
1256         tex_coords[10] = (GLfloat)entries[i].pos.x / sfc_w;
1257         tex_coords[11] = (GLfloat)(entries[i].pos.y + entries[i].size.h) / sfc_h;
1258     }
1259
1260     vigs_gl_draw_tex_prog(gl_backend, num_entries * 6);
1261
1262 out:
1263     gl_backend->BindFramebuffer(GL_FRAMEBUFFER, 0);
1264 }
1265
1266 static void vigs_gl_surface_draw_pixels_scaled(struct vigs_surface *sfc,
1267                                                uint8_t *pixels,
1268                                                uint32_t width,
1269                                                uint32_t height)
1270 {
1271     struct vigs_gl_backend *gl_backend = (struct vigs_gl_backend*)sfc->backend;
1272     struct vigs_gl_surface *gl_sfc = (struct vigs_gl_surface*)sfc;
1273     struct vigs_winsys_gl_surface *ws_sfc = get_ws_sfc(gl_sfc);
1274     GLfloat sfc_w, sfc_h;
1275     GLfloat *vert_coords;
1276     GLfloat *tex_coords;
1277
1278     sfc_w = ws_sfc->base.base.width;
1279     sfc_h = ws_sfc->base.base.height;
1280
1281     if (!vigs_winsys_gl_surface_create_texture(ws_sfc)) {
1282         goto out;
1283     }
1284
1285     if (!vigs_gl_surface_create_tmp_texture(gl_sfc)) {
1286         goto out;
1287     }
1288
1289     if (!vigs_gl_surface_setup_framebuffer(gl_sfc,
1290                                            gl_backend->tex_prog_id,
1291                                            gl_backend->tex_prog_proj_loc)) {
1292         goto out;
1293     }
1294
1295     gl_backend->BindTexture(GL_TEXTURE_2D, gl_sfc->tmp_tex);
1296
1297     gl_backend->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1298     gl_backend->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1299     gl_backend->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1300     gl_backend->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1301
1302     gl_backend->PixelStorei(GL_UNPACK_ALIGNMENT, 1);
1303     gl_backend->PixelStorei(GL_UNPACK_ROW_LENGTH, width);
1304     gl_backend->PixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
1305     gl_backend->PixelStorei(GL_UNPACK_SKIP_ROWS, 0);
1306
1307     if (width > sfc_w || height > sfc_h) {
1308         gl_backend->TexImage2D(GL_TEXTURE_2D, 0, ws_sfc->tex_internalformat,
1309                                width, height, 0,
1310                                ws_sfc->tex_format,
1311                                ws_sfc->tex_type,
1312                                pixels);
1313     } else {
1314         gl_backend->TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,
1315                                   width, height,
1316                                   ws_sfc->tex_format,
1317                                   ws_sfc->tex_type,
1318                                   pixels);
1319     }
1320
1321     vigs_vector_resize(&gl_backend->v1, 0);
1322     vigs_vector_resize(&gl_backend->v2, 0);
1323
1324     gl_backend->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
1325                                      GL_TEXTURE_2D, ws_sfc->tex, 0);
1326
1327     vert_coords = vigs_vector_append(&gl_backend->v1,
1328                                      (12 * sizeof(GLfloat)));
1329     tex_coords = vigs_vector_append(&gl_backend->v2,
1330                                     (12 * sizeof(GLfloat)));
1331
1332     vert_coords[6] = vert_coords[0] = 0;
1333     vert_coords[7] = vert_coords[1] = sfc_h;
1334     vert_coords[2] = sfc_w;
1335     vert_coords[3] = sfc_h;
1336     vert_coords[8] = vert_coords[4] = sfc_w;
1337     vert_coords[9] = vert_coords[5] = 0;
1338     vert_coords[10] = 0;
1339     vert_coords[11] = 0;
1340
1341     tex_coords[6] = tex_coords[0] = 0;
1342     tex_coords[7] = tex_coords[1] = 0;
1343     tex_coords[2] = (GLfloat)width / sfc_w;
1344     tex_coords[3] = 0;
1345     tex_coords[8] = tex_coords[4] = (GLfloat)width / sfc_w;
1346     tex_coords[9] = tex_coords[5] = (GLfloat)height / sfc_h;
1347     tex_coords[10] = 0;
1348     tex_coords[11] = (GLfloat)height / sfc_h;
1349
1350     vigs_gl_draw_tex_prog(gl_backend, 6);
1351
1352 out:
1353     gl_backend->BindFramebuffer(GL_FRAMEBUFFER, 0);
1354 }
1355
1356 static void vigs_gl_surface_copy(struct vigs_surface *dst,
1357                                  struct vigs_surface *src,
1358                                  const struct vigsp_copy *entries,
1359                                  uint32_t num_entries)
1360 {
1361     struct vigs_gl_backend *gl_backend = (struct vigs_gl_backend*)dst->backend;
1362     struct vigs_gl_surface *gl_dst = (struct vigs_gl_surface*)dst;
1363     struct vigs_gl_surface *gl_src = (struct vigs_gl_surface*)src;
1364     struct vigs_winsys_gl_surface *ws_dst = get_ws_sfc(gl_dst);
1365     struct vigs_winsys_gl_surface *ws_src = get_ws_sfc(gl_src);
1366     uint32_t total_entries = num_entries, i;
1367     GLfloat src_w, src_h;
1368     GLfloat dst_h;
1369     GLfloat *vert_coords;
1370     GLfloat *tex_coords;
1371
1372     if (!vigs_winsys_gl_surface_create_texture(ws_dst)) {
1373         goto out;
1374     }
1375
1376     if (!ws_src->tex) {
1377         VIGS_LOG_WARN("copying garbage ???");
1378     }
1379
1380     if (!vigs_winsys_gl_surface_create_texture(ws_src)) {
1381         goto out;
1382     }
1383
1384     if (!vigs_gl_surface_setup_framebuffer(gl_dst,
1385                                            gl_backend->tex_prog_id,
1386                                            gl_backend->tex_prog_proj_loc)) {
1387         goto out;
1388     }
1389
1390     vigs_vector_resize(&gl_backend->v1, 0);
1391     vigs_vector_resize(&gl_backend->v2, 0);
1392
1393     src_w = ws_src->base.base.width;
1394     src_h = ws_src->base.base.height;
1395     dst_h = ws_dst->base.base.height;
1396
1397     if (src == dst) {
1398         /*
1399          * Feedback loop is possible, use 'tmp_tex' instead.
1400          */
1401
1402         if (!vigs_gl_surface_create_tmp_texture(gl_dst)) {
1403             goto out;
1404         }
1405
1406         gl_backend->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
1407                                          GL_TEXTURE_2D, gl_dst->tmp_tex, 0);
1408
1409         ++total_entries;
1410
1411         vert_coords = vigs_vector_append(&gl_backend->v1,
1412                                          (12 * sizeof(GLfloat)));
1413         tex_coords = vigs_vector_append(&gl_backend->v2,
1414                                         (12 * sizeof(GLfloat)));
1415
1416         vert_coords[6] = vert_coords[0] = 0;
1417         vert_coords[7] = vert_coords[1] = src_h;
1418         vert_coords[2] = src_w;
1419         vert_coords[3] = src_h;
1420         vert_coords[8] = vert_coords[4] = src_w;
1421         vert_coords[9] = vert_coords[5] = 0;
1422         vert_coords[10] = 0;
1423         vert_coords[11] = 0;
1424
1425         tex_coords[6] = tex_coords[0] = 0;
1426         tex_coords[7] = tex_coords[1] = 1;
1427         tex_coords[2] = 1;
1428         tex_coords[3] = 1;
1429         tex_coords[8] = tex_coords[4] = 1;
1430         tex_coords[9] = tex_coords[5] = 0;
1431         tex_coords[10] = 0;
1432         tex_coords[11] = 0;
1433     } else {
1434         /*
1435          * No feedback loop possible, render to 'front_tex'.
1436          */
1437
1438         gl_backend->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
1439                                          GL_TEXTURE_2D, ws_dst->tex, 0);
1440     }
1441
1442     for (i = 0; i < num_entries; ++i) {
1443         vert_coords = vigs_vector_append(&gl_backend->v1,
1444                                          (12 * sizeof(GLfloat)));
1445         tex_coords = vigs_vector_append(&gl_backend->v2,
1446                                         (12 * sizeof(GLfloat)));
1447
1448         vert_coords[6] = vert_coords[0] = entries[i].to.x;
1449         vert_coords[7] = vert_coords[1] = dst_h - entries[i].to.y;
1450         vert_coords[2] = entries[i].to.x + entries[i].size.w;
1451         vert_coords[3] = dst_h - entries[i].to.y;
1452         vert_coords[8] = vert_coords[4] = entries[i].to.x + entries[i].size.w;
1453         vert_coords[9] = vert_coords[5] = dst_h - (entries[i].to.y + entries[i].size.h);
1454         vert_coords[10] = entries[i].to.x;
1455         vert_coords[11] = dst_h - (entries[i].to.y + entries[i].size.h);
1456
1457         tex_coords[6] = tex_coords[0] = (GLfloat)entries[i].from.x / src_w;
1458         tex_coords[7] = tex_coords[1] = (GLfloat)(src_h - entries[i].from.y) / src_h;
1459         tex_coords[2] = (GLfloat)(entries[i].from.x + entries[i].size.w) / src_w;
1460         tex_coords[3] = (GLfloat)(src_h - entries[i].from.y) / src_h;
1461         tex_coords[8] = tex_coords[4] = (GLfloat)(entries[i].from.x + entries[i].size.w) / src_w;
1462         tex_coords[9] = tex_coords[5] = (GLfloat)(src_h - (entries[i].from.y + entries[i].size.h)) / src_h;
1463         tex_coords[10] = (GLfloat)entries[i].from.x / src_w;
1464         tex_coords[11] = (GLfloat)(src_h - (entries[i].from.y + entries[i].size.h)) / src_h;
1465     }
1466
1467     gl_backend->BindTexture(GL_TEXTURE_2D, ws_src->tex);
1468
1469     vigs_gl_draw_tex_prog(gl_backend, total_entries * 6);
1470
1471     if (src == dst) {
1472         vigs_vector_resize(&gl_backend->v1, 0);
1473         vigs_vector_resize(&gl_backend->v2, 0);
1474
1475         vert_coords = vigs_vector_append(&gl_backend->v1,
1476                                          (12 * sizeof(GLfloat)));
1477         tex_coords = vigs_vector_append(&gl_backend->v2,
1478                                         (12 * sizeof(GLfloat)));
1479
1480         vert_coords[6] = vert_coords[0] = 0;
1481         vert_coords[7] = vert_coords[1] = src_h;
1482         vert_coords[2] = src_w;
1483         vert_coords[3] = src_h;
1484         vert_coords[8] = vert_coords[4] = src_w;
1485         vert_coords[9] = vert_coords[5] = 0;
1486         vert_coords[10] = 0;
1487         vert_coords[11] = 0;
1488
1489         tex_coords[6] = tex_coords[0] = 0;
1490         tex_coords[7] = tex_coords[1] = 1;
1491         tex_coords[2] = 1;
1492         tex_coords[3] = 1;
1493         tex_coords[8] = tex_coords[4] = 1;
1494         tex_coords[9] = tex_coords[5] = 0;
1495         tex_coords[10] = 0;
1496         tex_coords[11] = 0;
1497
1498         gl_backend->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
1499                                          GL_TEXTURE_2D, ws_dst->tex, 0);
1500
1501         gl_backend->BindTexture(GL_TEXTURE_2D, gl_dst->tmp_tex);
1502
1503         vigs_gl_draw_tex_prog(gl_backend, 6);
1504     }
1505
1506 out:
1507     gl_backend->BindFramebuffer(GL_FRAMEBUFFER, 0);
1508 }
1509
1510 static void vigs_gl_surface_solid_fill(struct vigs_surface *sfc,
1511                                        vigsp_color color,
1512                                        const struct vigsp_rect *entries,
1513                                        uint32_t num_entries)
1514 {
1515     struct vigs_gl_backend *gl_backend = (struct vigs_gl_backend*)sfc->backend;
1516     struct vigs_gl_surface *gl_sfc = (struct vigs_gl_surface*)sfc;
1517     struct vigs_winsys_gl_surface *ws_sfc = get_ws_sfc(gl_sfc);
1518     uint32_t i;
1519     GLfloat colorf[4];
1520     GLfloat sfc_h;
1521
1522     if (!vigs_winsys_gl_surface_create_texture(ws_sfc)) {
1523         goto out;
1524     }
1525
1526     if (!vigs_gl_surface_setup_framebuffer(gl_sfc,
1527                                            gl_backend->color_prog_id,
1528                                            gl_backend->color_prog_proj_loc)) {
1529         goto out;
1530     }
1531
1532     sfc_h = ws_sfc->base.base.height;
1533
1534     gl_backend->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
1535                                      GL_TEXTURE_2D, ws_sfc->tex, 0);
1536
1537     vigs_vector_resize(&gl_backend->v1, 0);
1538
1539     for (i = 0; i < num_entries; ++i) {
1540         GLfloat *vert_coords = vigs_vector_append(&gl_backend->v1,
1541                                                   (12 * sizeof(GLfloat)));
1542
1543         vert_coords[6] = vert_coords[0] = entries[i].pos.x;
1544         vert_coords[7] = vert_coords[1] = sfc_h - entries[i].pos.y;
1545         vert_coords[2] = entries[i].pos.x + entries[i].size.w;
1546         vert_coords[3] = sfc_h - entries[i].pos.y;
1547         vert_coords[8] = vert_coords[4] = entries[i].pos.x + entries[i].size.w;
1548         vert_coords[9] = vert_coords[5] = sfc_h - (entries[i].pos.y + entries[i].size.h);
1549         vert_coords[10] = entries[i].pos.x;
1550         vert_coords[11] = sfc_h - (entries[i].pos.y + entries[i].size.h);
1551     }
1552
1553     vigs_gl_translate_color(color, sfc->format, colorf);
1554
1555     vigs_gl_draw_color_prog(gl_backend, colorf, num_entries * 6);
1556
1557 out:
1558     gl_backend->BindFramebuffer(GL_FRAMEBUFFER, 0);
1559 }
1560
1561 static void vigs_gl_surface_ga_copy(struct vigs_surface *dst,
1562                                     uint32_t dst_stride,
1563                                     struct vigs_surface *src,
1564                                     uint8_t *src_pixels,
1565                                     uint32_t src_stride,
1566                                     const struct vigsp_copy *entry)
1567 {
1568     struct vigs_gl_backend *gl_backend = (struct vigs_gl_backend*)dst->backend;
1569     struct vigs_gl_surface *gl_dst = (struct vigs_gl_surface*)dst;
1570     struct vigs_winsys_gl_surface *ws_dst = get_ws_sfc(gl_dst);
1571     GLfloat dst_w, dst_h, height;
1572     GLfloat *vert_coords;
1573     GLfloat *tex_coords;
1574
1575     if ((entry->from.x != 0) ||
1576         (entry->to.x != 0) ||
1577         (entry->to.y != 0)) {
1578         VIGS_LOG_ERROR("not supported");
1579     }
1580
1581     if (entry->from.y * src_stride + entry->size.w * entry->size.h >
1582         src->stride * src->ws_sfc->height) {
1583         VIGS_LOG_ERROR("out of bounds");
1584         return;
1585     }
1586
1587     if (!src_pixels) {
1588         /*
1589          * Contents were flushed to GPU, so read them back,
1590          * not very pretty, but this path should be triggered
1591          * very rarely.
1592          */
1593         vigs_vector_resize(&gl_backend->v1, src->stride * src->ws_sfc->height);
1594
1595         src_pixels = vigs_vector_data(&gl_backend->v1);
1596
1597         vigs_gl_surface_read_pixels(src, src_pixels);
1598     }
1599
1600     if (!vigs_winsys_gl_surface_create_texture(ws_dst)) {
1601         goto out;
1602     }
1603
1604     if (!vigs_gl_surface_create_tmp_texture(gl_dst)) {
1605         goto out;
1606     }
1607
1608     if (!vigs_gl_surface_setup_framebuffer(gl_dst,
1609                                            gl_backend->tex_prog_id,
1610                                            gl_backend->tex_prog_proj_loc)) {
1611         goto out;
1612     }
1613
1614     height = (entry->size.w * entry->size.h + dst->stride - 1) / dst->stride;
1615
1616     dst_w = ws_dst->base.base.width;
1617     dst_h = ws_dst->base.base.height;
1618
1619     gl_backend->BindTexture(GL_TEXTURE_2D, gl_dst->tmp_tex);
1620
1621     gl_backend->PixelStorei(GL_UNPACK_ALIGNMENT, 1);
1622     gl_backend->PixelStorei(GL_UNPACK_ROW_LENGTH, 0);
1623     gl_backend->PixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
1624     gl_backend->PixelStorei(GL_UNPACK_SKIP_ROWS, 0);
1625     gl_backend->TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,
1626                               dst_w, height,
1627                               ws_dst->tex_format,
1628                               ws_dst->tex_type,
1629                               src_pixels + entry->from.y * src_stride);
1630
1631     vigs_vector_resize(&gl_backend->v1, 0);
1632     vigs_vector_resize(&gl_backend->v2, 0);
1633
1634     gl_backend->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
1635                                      GL_TEXTURE_2D, ws_dst->tex, 0);
1636
1637     vert_coords = vigs_vector_append(&gl_backend->v1,
1638                                      (12 * sizeof(GLfloat)));
1639     tex_coords = vigs_vector_append(&gl_backend->v2,
1640                                     (12 * sizeof(GLfloat)));
1641
1642     vert_coords[6] = vert_coords[0] = entry->to.x;
1643     vert_coords[7] = vert_coords[1] = dst_h - entry->to.y;
1644     vert_coords[2] = entry->to.x + dst_w;
1645     vert_coords[3] = dst_h - entry->to.y;
1646     vert_coords[8] = vert_coords[4] = entry->to.x + dst_w;
1647     vert_coords[9] = vert_coords[5] = dst_h - (entry->to.y + height);
1648     vert_coords[10] = entry->to.x;
1649     vert_coords[11] = dst_h - (entry->to.y + height);
1650
1651     tex_coords[6] = tex_coords[0] = (GLfloat)entry->to.x / dst_w;
1652     tex_coords[7] = tex_coords[1] = (GLfloat)entry->to.y / dst_h;
1653     tex_coords[2] = (GLfloat)(entry->to.x + dst_w) / dst_w;
1654     tex_coords[3] = (GLfloat)entry->to.y / dst_h;
1655     tex_coords[8] = tex_coords[4] = (GLfloat)(entry->to.x + dst_w) / dst_w;
1656     tex_coords[9] = tex_coords[5] = (GLfloat)(entry->to.y + height) / dst_h;
1657     tex_coords[10] = (GLfloat)entry->to.x / dst_w;
1658     tex_coords[11] = (GLfloat)(entry->to.y + height) / dst_h;
1659
1660     vigs_gl_draw_tex_prog(gl_backend, 6);
1661
1662 out:
1663     gl_backend->BindFramebuffer(GL_FRAMEBUFFER, 0);
1664 }
1665
1666 static GLuint vigs_gl_surface_create_pixel_buf(struct vigs_surface *sfc)
1667 {
1668     struct vigs_gl_backend *gl_backend = (struct vigs_gl_backend*)sfc->backend;
1669     struct vigs_gl_surface *gl_sfc = (struct vigs_gl_surface*)sfc;
1670     struct vigs_winsys_gl_surface *ws_sfc = get_ws_sfc(gl_sfc);
1671     GLsizei sfc_stride = sfc->stride;
1672     GLsizei sfc_h = ws_sfc->base.base.height;
1673     GLuint pbuf;
1674
1675     if (!ws_sfc->tex) {
1676         VIGS_LOG_ERROR("source surface must be not empty");
1677         return 0;
1678     }
1679
1680     gl_backend->GenBuffers(1, &pbuf);
1681
1682     gl_backend->BindBuffer(GL_PIXEL_PACK_BUFFER, pbuf);
1683
1684     gl_backend->BufferData(GL_PIXEL_PACK_BUFFER,
1685                            sfc_stride * sfc_h,
1686                            NULL,
1687                            GL_STREAM_COPY);
1688
1689     vigs_gl_surface_read_pixels(sfc, 0);
1690
1691     gl_backend->BindBuffer(GL_PIXEL_PACK_BUFFER, 0);
1692
1693     return pbuf;
1694 }
1695
1696 static bool vigs_gl_surface_setup_yuv_textures(struct vigs_surface *dst,
1697                                                struct vigs_surface *src)
1698 {
1699     struct vigs_gl_backend *gl_backend = (struct vigs_gl_backend*)dst->backend;
1700     struct vigs_gl_surface *gl_dst = (struct vigs_gl_surface*)dst;
1701     struct vigs_winsys_gl_surface *ws_dst = get_ws_sfc(gl_dst);
1702     GLsizei dst_w = ws_dst->base.base.width;
1703     GLsizei dst_h = ws_dst->base.base.height;
1704     GLsizei tex_widths[3] = {dst_w / 4, dst_w / 8, dst_w / 8};
1705     GLsizei tex_heights[3] = {dst_h, dst_h / 2, dst_h / 2};
1706     GLsizei pbuf_offsets[3] = {0, dst_w * dst_h, 5 * dst_w * dst_h / 4};
1707     int i;
1708     bool need_alloc = false;
1709     GLuint pbuf;
1710
1711     /*
1712      * We have to create and destroy pixel buffer at every yuv conversion,
1713      * because we can't check restoring of source texture.
1714      */
1715     pbuf = vigs_gl_surface_create_pixel_buf(src);
1716
1717     if (pbuf == 0) {
1718         return false;
1719     }
1720
1721     if (gl_dst->yuv_textures[0] == 0) {
1722         gl_backend->GenTextures(3, &gl_dst->yuv_textures[0]);
1723         need_alloc = true;
1724     }
1725
1726     gl_backend->BindBuffer(GL_PIXEL_UNPACK_BUFFER, pbuf);
1727
1728     for (i = 0; i < 3; i++) {
1729         gl_backend->ActiveTexture(GL_TEXTURE0 + i);
1730         gl_backend->BindTexture(GL_TEXTURE_2D, gl_dst->yuv_textures[i]);
1731
1732         gl_backend->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1733         gl_backend->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1734
1735         gl_backend->PixelStorei(GL_UNPACK_ALIGNMENT, 1);
1736         gl_backend->PixelStorei(GL_UNPACK_ROW_LENGTH, tex_widths[i]);
1737
1738         if (need_alloc) {
1739             gl_backend->TexImage2D(GL_TEXTURE_2D,
1740                                    0,
1741                                    ws_dst->tex_internalformat,
1742                                    tex_widths[i], tex_heights[i],
1743                                    0,
1744                                    ws_dst->tex_format,
1745                                    ws_dst->tex_type,
1746                                    (GLvoid *)(intptr_t)pbuf_offsets[i]);
1747         } else {
1748             gl_backend->TexSubImage2D(GL_TEXTURE_2D,
1749                                       0,
1750                                       0, 0,
1751                                       tex_widths[i], tex_heights[i],
1752                                       ws_dst->tex_format,
1753                                       ws_dst->tex_type,
1754                                       (GLvoid *)(intptr_t)pbuf_offsets[i]);
1755         }
1756     }
1757
1758     gl_backend->ActiveTexture(GL_TEXTURE0);
1759
1760     gl_backend->BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
1761
1762     gl_backend->DeleteBuffers(1, &pbuf);
1763
1764     return true;
1765 }
1766
1767 static void vigs_gl_surface_convert_yuv2argb(struct vigs_surface *dst,
1768                                              struct vigs_surface *src)
1769 {
1770     struct vigs_gl_backend *gl_backend = (struct vigs_gl_backend*)dst->backend;
1771     struct vigs_gl_surface *gl_dst = (struct vigs_gl_surface*)dst;
1772     struct vigs_winsys_gl_surface *ws_dst = get_ws_sfc(gl_dst);
1773     GLsizei dst_w = ws_dst->base.base.width;
1774     GLsizei dst_h = ws_dst->base.base.height;
1775     GLfloat *vert_coords;
1776     GLfloat *tex_coords;
1777
1778     if (!vigs_winsys_gl_surface_create_texture(ws_dst)) {
1779         goto out;
1780     }
1781
1782     if (!vigs_gl_surface_setup_yuv_textures(dst, src)) {
1783         goto out;
1784     }
1785
1786     if (!vigs_gl_surface_setup_framebuffer(gl_dst,
1787                                            gl_backend->yuv420_prog_id,
1788                                            gl_backend->yuv420_prog_proj_loc)) {
1789         goto out;
1790     }
1791
1792     vigs_vector_resize(&gl_backend->v1, 12 * sizeof(GLfloat));
1793     vigs_vector_resize(&gl_backend->v2, 12 * sizeof(GLfloat));
1794
1795     vert_coords = vigs_vector_data(&gl_backend->v1);
1796     tex_coords = vigs_vector_data(&gl_backend->v2);
1797
1798     vert_coords[6] = vert_coords[0] = 0;
1799     vert_coords[7] = vert_coords[1] = dst_h;
1800     vert_coords[2] = dst_w;
1801     vert_coords[3] = dst_h;
1802     vert_coords[8] = vert_coords[4] = dst_w;
1803     vert_coords[9] = vert_coords[5] = 0.0;
1804     vert_coords[10] = 0.0;
1805     vert_coords[11] = 0.0;
1806
1807     tex_coords[6] = tex_coords[0] = 0.0;
1808     tex_coords[7] = tex_coords[1] = 1.0;
1809     tex_coords[2] = 1.0;
1810     tex_coords[3] = 1.0;
1811     tex_coords[8] = tex_coords[4] = 1.0;
1812     tex_coords[9] = tex_coords[5] = 0.0;
1813     tex_coords[10] = 0.0;
1814     tex_coords[11] = 0.0;
1815
1816     gl_backend->FramebufferTexture2D(GL_FRAMEBUFFER,
1817                                      GL_COLOR_ATTACHMENT0,
1818                                      GL_TEXTURE_2D,
1819                                      ws_dst->tex,
1820                                      0);
1821
1822     gl_backend->UseProgram(gl_backend->yuv420_prog_id);
1823
1824     gl_backend->Uniform2f(gl_backend->yuv420_prog_ytexSize_loc,
1825                           dst_w / 4, dst_h);
1826     gl_backend->Uniform2f(gl_backend->yuv420_prog_utexSize_loc,
1827                           dst_w / 8, dst_h / 2);
1828     gl_backend->Uniform2f(gl_backend->yuv420_prog_vtexSize_loc,
1829                           dst_w / 8, dst_h / 2);
1830     gl_backend->Uniform2f(gl_backend->yuv420_prog_size_loc,
1831                           dst_w, dst_h);
1832
1833     vigs_gl_draw_yuv420_prog(gl_backend, 6);
1834
1835 out:
1836     gl_backend->BindFramebuffer(GL_FRAMEBUFFER, 0);
1837 }
1838
1839 static void vigs_gl_surface_convert_argb2xbgr(struct vigs_surface *dst,
1840                                               struct vigs_surface *src)
1841 {
1842     struct vigs_gl_backend *gl_backend = (struct vigs_gl_backend*)dst->backend;
1843     struct vigs_gl_surface *gl_dst = (struct vigs_gl_surface*)dst;
1844     struct vigs_gl_surface *gl_src = (struct vigs_gl_surface*)src;
1845     struct vigs_winsys_gl_surface *ws_dst = get_ws_sfc(gl_dst);
1846     struct vigs_winsys_gl_surface *ws_src = get_ws_sfc(gl_src);
1847     GLsizei dst_w = ws_dst->base.base.width;
1848     GLsizei dst_h = ws_dst->base.base.height;
1849     GLfloat *vert_coords;
1850     GLfloat *tex_coords;
1851
1852     if (!vigs_winsys_gl_surface_create_texture(ws_dst)) {
1853         goto out;
1854     }
1855
1856     if (!ws_src->tex) {
1857         VIGS_LOG_WARN("copying garbage ???");
1858     }
1859
1860     if (!vigs_winsys_gl_surface_create_texture(ws_src)) {
1861         goto out;
1862     }
1863
1864     if (!vigs_gl_surface_setup_framebuffer(gl_dst,
1865                                            gl_backend->xbgr_prog_id,
1866                                            gl_backend->xbgr_prog_proj_loc)) {
1867         goto out;
1868     }
1869
1870     vigs_vector_resize(&gl_backend->v1, 12 * sizeof(GLfloat));
1871     vigs_vector_resize(&gl_backend->v2, 12 * sizeof(GLfloat));
1872
1873     vert_coords = vigs_vector_data(&gl_backend->v1);
1874     tex_coords = vigs_vector_data(&gl_backend->v2);
1875
1876     vert_coords[6] = vert_coords[0] = 0;
1877     vert_coords[7] = vert_coords[1] = dst_h;
1878     vert_coords[2] = dst_w;
1879     vert_coords[3] = dst_h;
1880     vert_coords[8] = vert_coords[4] = dst_w;
1881     vert_coords[9] = vert_coords[5] = 0.0;
1882     vert_coords[10] = 0.0;
1883     vert_coords[11] = 0.0;
1884
1885     tex_coords[6] = tex_coords[0] = 0.0;
1886     tex_coords[7] = tex_coords[1] = 1.0;
1887     tex_coords[2] = 1.0;
1888     tex_coords[3] = 1.0;
1889     tex_coords[8] = tex_coords[4] = 1.0;
1890     tex_coords[9] = tex_coords[5] = 0.0;
1891     tex_coords[10] = 0.0;
1892     tex_coords[11] = 0.0;
1893
1894     gl_backend->FramebufferTexture2D(GL_FRAMEBUFFER,
1895                                      GL_COLOR_ATTACHMENT0,
1896                                      GL_TEXTURE_2D,
1897                                      ws_dst->tex,
1898                                      0);
1899
1900     gl_backend->BindTexture(GL_TEXTURE_2D, ws_src->tex);
1901
1902     gl_backend->UseProgram(gl_backend->xbgr_prog_id);
1903
1904     vigs_gl_draw_xbgr_prog(gl_backend, 6);
1905
1906     gl_backend->UseProgram(gl_backend->tex_prog_id);
1907
1908 out:
1909     gl_backend->BindFramebuffer(GL_FRAMEBUFFER, 0);
1910 }
1911
1912 static void vigs_gl_surface_convert(struct vigs_surface *dst,
1913                                     uint32_t dst_format,
1914                                     struct vigs_surface *src,
1915                                     uint32_t src_format,
1916                                     int y_invert)
1917 {
1918     uint32_t width = dst->ws_sfc->width;
1919     uint32_t height = dst->ws_sfc->height;
1920     bool conversion_supported = true;
1921
1922     struct vigsp_copy entry = {
1923         .from = { 0, 0 },
1924         .to = { 0, 0 },
1925         .size = { width, height }
1926     };
1927
1928     struct vigs_gl_surface *gl_dst = (struct vigs_gl_surface *)dst;
1929
1930     if (y_invert) {
1931         vigs_gl_create_ortho(0.0f, width, height, 0.0f,
1932                              -1.0f, 1.0f, gl_dst->ortho);
1933     }
1934
1935     switch (dst_format) {
1936     case DRM_FORMAT_ARGB8888:
1937         switch (src_format) {
1938         case DRM_FORMAT_YUV420:
1939             vigs_gl_surface_convert_yuv2argb(dst, src);
1940             break;
1941         case DRM_FORMAT_ARGB8888:
1942             vigs_gl_surface_copy(dst, src, &entry, 1);
1943             break;
1944         default:
1945             conversion_supported = false;
1946             break;
1947         }
1948         break;
1949     case DRM_FORMAT_XBGR8888:
1950         switch (src_format) {
1951         case DRM_FORMAT_ARGB8888:
1952             vigs_gl_surface_convert_argb2xbgr(dst, src);
1953             break;
1954         default:
1955             conversion_supported = false;
1956             break;
1957         }
1958         break;
1959     default:
1960         conversion_supported = false;
1961         break;
1962     }
1963
1964     if (y_invert) {
1965         vigs_gl_create_ortho(0.0f, width, 0.0f, height,
1966                              -1.0f, 1.0f, gl_dst->ortho);
1967     }
1968
1969     if (!conversion_supported) {
1970         VIGS_LOG_ERROR("format conversion from 0x%x to 0x%x is not supported",
1971                        src_format,
1972                        dst_format);
1973     }
1974 }
1975
1976 static void vigs_gl_surface_destroy(struct vigs_surface *sfc)
1977 {
1978     struct vigs_gl_backend *gl_backend = (struct vigs_gl_backend*)sfc->backend;
1979     struct vigs_gl_surface *gl_sfc = (struct vigs_gl_surface*)sfc;
1980     struct vigs_winsys_gl_surface *ws_sfc = get_ws_sfc(gl_sfc);
1981
1982     vigs_winsys_gl_surface_orphan(ws_sfc);
1983
1984     if (gl_sfc->fb) {
1985         vigs_gl_pool_release(gl_backend->fb_pool,
1986                              sfc->ws_sfc->width,
1987                              sfc->ws_sfc->height,
1988                              sfc->format);
1989     }
1990     if (gl_sfc->tmp_tex) {
1991         vigs_gl_pool_release(gl_backend->tex_pool,
1992                              sfc->ws_sfc->width,
1993                              sfc->ws_sfc->height,
1994                              sfc->format);
1995     }
1996
1997     gl_backend->DeleteTextures(3, &gl_sfc->yuv_textures[0]);
1998
1999     vigs_surface_cleanup(&gl_sfc->base);
2000
2001     g_free(gl_sfc);
2002 }
2003
2004 /*
2005  * @}
2006  */
2007
2008 static struct vigs_surface *vigs_gl_backend_create_surface(struct vigs_backend *backend,
2009                                                            uint32_t width,
2010                                                            uint32_t height,
2011                                                            uint32_t stride,
2012                                                            vigsp_surface_format format,
2013                                                            vigsp_surface_id id)
2014 {
2015     struct vigs_gl_surface *gl_sfc = NULL;
2016     struct vigs_winsys_gl_surface *ws_sfc = NULL;
2017     GLint tex_internalformat;
2018     GLenum tex_format;
2019     GLenum tex_type;
2020     GLint tex_bpp;
2021
2022     switch (format) {
2023     case vigsp_surface_bgrx8888:
2024     case vigsp_surface_bgra8888:
2025         tex_internalformat = GL_RGBA8;
2026         tex_format = GL_BGRA;
2027         tex_type = GL_UNSIGNED_INT_8_8_8_8_REV;
2028         break;
2029     default:
2030         assert(false);
2031         return NULL;
2032     }
2033
2034     tex_bpp = vigs_format_bpp(format);
2035
2036     if ((width * tex_bpp) != stride) {
2037         VIGS_LOG_ERROR("Custom strides not supported yet");
2038         return NULL;
2039     }
2040
2041     gl_sfc = g_malloc0(sizeof(*gl_sfc));
2042
2043     ws_sfc = vigs_winsys_gl_surface_create((struct vigs_gl_backend*)backend,
2044                                            gl_sfc,
2045                                            width,
2046                                            height,
2047                                            tex_internalformat,
2048                                            tex_format,
2049                                            tex_type);
2050
2051     vigs_surface_init(&gl_sfc->base,
2052                       &ws_sfc->base.base,
2053                       backend,
2054                       stride,
2055                       format,
2056                       id);
2057
2058     vigs_gl_create_ortho(0.0f, width, 0.0f, height,
2059                          -1.0f, 1.0f, gl_sfc->ortho);
2060
2061     ws_sfc->base.base.release(&ws_sfc->base.base);
2062
2063     gl_sfc->base.read_pixels = &vigs_gl_surface_read_pixels;
2064     gl_sfc->base.draw_pixels = &vigs_gl_surface_draw_pixels;
2065     gl_sfc->base.draw_pixels_scaled = &vigs_gl_surface_draw_pixels_scaled;
2066     gl_sfc->base.copy = &vigs_gl_surface_copy;
2067     gl_sfc->base.solid_fill = &vigs_gl_surface_solid_fill;
2068     gl_sfc->base.ga_copy = &vigs_gl_surface_ga_copy;
2069     gl_sfc->base.convert = &vigs_gl_surface_convert;
2070     gl_sfc->base.destroy = &vigs_gl_surface_destroy;
2071
2072     return &gl_sfc->base;
2073 }
2074
2075 static inline void
2076 vigs_gl_backend_sort_planes(const struct vigs_plane *planes,
2077                             const struct vigs_plane **sorted_planes)
2078 {
2079     /*
2080      * Sort planes, only 2 of them now, don't bother...
2081      * The 3rd plane is for HW cursor (should always be on top).
2082      */
2083
2084     assert(VIGS_MAX_PLANES == 3);
2085
2086     if (planes[0].z_pos <= planes[1].z_pos) {
2087         sorted_planes[0] = &planes[0];
2088         sorted_planes[1] = &planes[1];
2089     } else {
2090         sorted_planes[0] = &planes[1];
2091         sorted_planes[1] = &planes[0];
2092     }
2093
2094     sorted_planes[2] = &planes[2];
2095 }
2096
2097 /*
2098  * 'above_root' means we want to render only planes that are above root surface.
2099  * 'bottom' means that if at least one plane is going to be rendered it'll be
2100  *  bottom plane, i.e. the first one in surface stack.
2101  */
2102 static bool vigs_gl_backend_composite_planes(struct vigs_gl_backend *gl_backend,
2103                                              const struct vigs_plane **planes,
2104                                              bool above_root,
2105                                              bool bottom,
2106                                              GLfloat ortho[16])
2107 {
2108     uint32_t i;
2109     GLfloat *vert_coords = vigs_vector_data(&gl_backend->v1);
2110     GLfloat *tex_coords = vigs_vector_data(&gl_backend->v2);
2111
2112     for (i = 0; i < VIGS_MAX_PLANES; ++i) {
2113         const struct vigs_plane *plane = planes[i];
2114         GLfloat src_w, src_h;
2115         GLfloat tmp_x, tmp_y;
2116
2117         if (!vigs_plane_enabled(plane) || ((plane->z_pos >= 0) ^ above_root)) {
2118             continue;
2119         }
2120
2121         VIGS_LOG_DEBUG("plane[%u]: %ux%u format = %d, z_pos = %d, hflip = %d,"
2122                        " vflip = %d, rotation = %d ",
2123                        i,
2124                        plane->width,
2125                        plane->height,
2126                        plane->format,
2127                        plane->z_pos,
2128                        plane->hflip,
2129                        plane->vflip,
2130                        plane->rotation);
2131
2132         src_w = plane->width;
2133         src_h = plane->height;
2134
2135         vert_coords[6] = vert_coords[0] = plane->dst_x;
2136         vert_coords[7] = vert_coords[1] = plane->dst_y;
2137         vert_coords[2] = plane->dst_x + (int)plane->dst_size.w;
2138         vert_coords[3] = plane->dst_y;
2139         vert_coords[8] = vert_coords[4] = plane->dst_x + (int)plane->dst_size.w;
2140         vert_coords[9] = vert_coords[5] = plane->dst_y + (int)plane->dst_size.h;
2141         vert_coords[10] = plane->dst_x;
2142         vert_coords[11] = plane->dst_y + (int)plane->dst_size.h;
2143
2144         tex_coords[6] = tex_coords[0] = (GLfloat)plane->src_rect.pos.x / src_w;
2145         tex_coords[7] = tex_coords[1] = (GLfloat)(src_h - plane->src_rect.pos.y) / src_h;
2146         tex_coords[2] = (GLfloat)(plane->src_rect.pos.x + plane->src_rect.size.w) / src_w;
2147         tex_coords[3] = (GLfloat)(src_h - plane->src_rect.pos.y) / src_h;
2148         tex_coords[8] = tex_coords[4] = (GLfloat)(plane->src_rect.pos.x + plane->src_rect.size.w) / src_w;
2149         tex_coords[9] = tex_coords[5] = (GLfloat)(src_h - (plane->src_rect.pos.y + plane->src_rect.size.h)) / src_h;
2150         tex_coords[10] = (GLfloat)plane->src_rect.pos.x / src_w;
2151         tex_coords[11] = (GLfloat)(src_h - (plane->src_rect.pos.y + plane->src_rect.size.h)) / src_h;
2152
2153         if (plane->hflip) {
2154             tmp_x = tex_coords[0];
2155             tmp_y = tex_coords[1];
2156
2157             tex_coords[6] = tex_coords[0] = tex_coords[2];
2158             tex_coords[7] = tex_coords[1] = tex_coords[3];
2159
2160             tex_coords[2] = tmp_x;
2161             tex_coords[3] = tmp_y;
2162
2163             tmp_x = tex_coords[4];
2164             tmp_y = tex_coords[5];
2165
2166             tex_coords[8] = tex_coords[4] = tex_coords[10];
2167             tex_coords[9] = tex_coords[5] = tex_coords[11];
2168
2169             tex_coords[10] = tmp_x;
2170             tex_coords[11] = tmp_y;
2171         }
2172
2173         if (plane->vflip) {
2174             tmp_x = tex_coords[0];
2175             tmp_y = tex_coords[1];
2176
2177             tex_coords[6] = tex_coords[0] = tex_coords[10];
2178             tex_coords[7] = tex_coords[1] = tex_coords[11];
2179
2180             tex_coords[10] = tmp_x;
2181             tex_coords[11] = tmp_y;
2182
2183             tmp_x = tex_coords[4];
2184             tmp_y = tex_coords[5];
2185
2186             tex_coords[8] = tex_coords[4] = tex_coords[2];
2187             tex_coords[9] = tex_coords[5] = tex_coords[3];
2188
2189             tex_coords[2] = tmp_x;
2190             tex_coords[3] = tmp_y;
2191         }
2192
2193         switch (plane->rotation) {
2194         case vigsp_rotation90:
2195             tmp_x = tex_coords[0];
2196             tmp_y = tex_coords[1];
2197
2198             tex_coords[6] = tex_coords[0] = tex_coords[10];
2199             tex_coords[7] = tex_coords[1] = tex_coords[11];
2200             tex_coords[10] = tex_coords[4];
2201             tex_coords[11] = tex_coords[5];
2202             tex_coords[8] = tex_coords[4] = tex_coords[2];
2203             tex_coords[9] = tex_coords[5] = tex_coords[3];
2204             tex_coords[2] = tmp_x;
2205             tex_coords[3] = tmp_y;
2206
2207             break;
2208         case vigsp_rotation180:
2209             tmp_x = tex_coords[0];
2210             tmp_y = tex_coords[1];
2211
2212             tex_coords[6] = tex_coords[0] = tex_coords[4];
2213             tex_coords[7] = tex_coords[1] = tex_coords[5];
2214             tex_coords[8] = tex_coords[4] = tmp_x;
2215             tex_coords[9] = tex_coords[5] = tmp_y;
2216
2217             tmp_x = tex_coords[2];
2218             tmp_y = tex_coords[3];
2219
2220             tex_coords[2] = tex_coords[10];
2221             tex_coords[3] = tex_coords[11];
2222
2223             tex_coords[10] = tmp_x;
2224             tex_coords[11] = tmp_y;
2225
2226             break;
2227         case vigsp_rotation270:
2228             tmp_x = tex_coords[0];
2229             tmp_y = tex_coords[1];
2230
2231             tex_coords[6] = tex_coords[0] = tex_coords[2];
2232             tex_coords[7] = tex_coords[1] = tex_coords[3];
2233             tex_coords[2] = tex_coords[4];
2234             tex_coords[3] = tex_coords[5];
2235             tex_coords[8] = tex_coords[4] = tex_coords[10];
2236             tex_coords[9] = tex_coords[5] = tex_coords[11];
2237             tex_coords[10] = tmp_x;
2238             tex_coords[11] = tmp_y;
2239
2240             break;
2241         case vigsp_rotation0:
2242         default:
2243             break;
2244         }
2245
2246         if (!bottom && (plane->format == vigsp_plane_bgra8888)) {
2247             /*
2248              * This is not bottom plane and it has alpha, turn on blending.
2249              */
2250             gl_backend->Enable(GL_BLEND);
2251             gl_backend->BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2252         } else {
2253             gl_backend->Disable(GL_BLEND);
2254         }
2255
2256         if (plane->format == vigsp_plane_nv21) {
2257             struct vigs_gl_surface *gl_sfc;
2258             struct vigs_winsys_gl_surface *ws_sfc;
2259
2260             gl_backend->UseProgram(gl_backend->nv21_prog_id);
2261
2262             gl_backend->UniformMatrix4fv(gl_backend->nv21_prog_proj_loc,
2263                                          1, GL_FALSE, ortho);
2264
2265             gl_sfc = (struct vigs_gl_surface*)plane->surfaces[1];
2266             ws_sfc = get_ws_sfc(gl_sfc);
2267
2268             gl_backend->ActiveTexture(GL_TEXTURE1);
2269             gl_backend->BindTexture(GL_TEXTURE_2D, ws_sfc->tex);
2270
2271             gl_backend->Uniform2f(gl_backend->nv21_prog_ctexSize_loc,
2272                                   ws_sfc->base.base.width,
2273                                   ws_sfc->base.base.height);
2274
2275             gl_sfc = (struct vigs_gl_surface*)plane->surfaces[0];
2276             ws_sfc = get_ws_sfc(gl_sfc);
2277
2278             gl_backend->ActiveTexture(GL_TEXTURE0);
2279             gl_backend->BindTexture(GL_TEXTURE_2D, ws_sfc->tex);
2280
2281             gl_backend->Uniform2f(gl_backend->nv21_prog_ytexSize_loc,
2282                                   ws_sfc->base.base.width,
2283                                   ws_sfc->base.base.height);
2284
2285             gl_backend->Uniform2f(gl_backend->nv21_prog_size_loc, src_w, src_h);
2286
2287             vigs_gl_draw_nv21_prog(gl_backend, 6);
2288
2289             gl_backend->UseProgram(gl_backend->tex_prog_id);
2290         } else if (plane->format == vigsp_plane_yuv420) {
2291             struct vigs_gl_surface *gl_sfc;
2292             struct vigs_winsys_gl_surface *ws_sfc;
2293
2294             gl_backend->UseProgram(gl_backend->yuv420_prog_id);
2295
2296             gl_backend->UniformMatrix4fv(gl_backend->yuv420_prog_proj_loc,
2297                                          1, GL_FALSE, ortho);
2298
2299             gl_sfc = (struct vigs_gl_surface*)plane->surfaces[2];
2300             ws_sfc = get_ws_sfc(gl_sfc);
2301
2302             gl_backend->ActiveTexture(GL_TEXTURE2);
2303             gl_backend->BindTexture(GL_TEXTURE_2D, ws_sfc->tex);
2304
2305             gl_backend->Uniform2f(gl_backend->yuv420_prog_vtexSize_loc,
2306                                   ws_sfc->base.base.width,
2307                                   ws_sfc->base.base.height);
2308
2309             gl_sfc = (struct vigs_gl_surface*)plane->surfaces[1];
2310             ws_sfc = get_ws_sfc(gl_sfc);
2311
2312             gl_backend->ActiveTexture(GL_TEXTURE1);
2313             gl_backend->BindTexture(GL_TEXTURE_2D, ws_sfc->tex);
2314
2315             gl_backend->Uniform2f(gl_backend->yuv420_prog_utexSize_loc,
2316                                   ws_sfc->base.base.width,
2317                                   ws_sfc->base.base.height);
2318
2319             gl_sfc = (struct vigs_gl_surface*)plane->surfaces[0];
2320             ws_sfc = get_ws_sfc(gl_sfc);
2321
2322             gl_backend->ActiveTexture(GL_TEXTURE0);
2323             gl_backend->BindTexture(GL_TEXTURE_2D, ws_sfc->tex);
2324
2325             gl_backend->Uniform2f(gl_backend->yuv420_prog_ytexSize_loc,
2326                                   ws_sfc->base.base.width,
2327                                   ws_sfc->base.base.height);
2328
2329             gl_backend->Uniform2f(gl_backend->yuv420_prog_size_loc, src_w, src_h);
2330
2331             vigs_gl_draw_yuv420_prog(gl_backend, 6);
2332
2333             gl_backend->UseProgram(gl_backend->tex_prog_id);
2334         } else {
2335             struct vigs_gl_surface *gl_sfc;
2336             struct vigs_winsys_gl_surface *ws_sfc;
2337
2338             gl_sfc = (struct vigs_gl_surface*)plane->surfaces[0];
2339             ws_sfc = get_ws_sfc(gl_sfc);
2340
2341             gl_backend->BindTexture(GL_TEXTURE_2D, ws_sfc->tex);
2342
2343             vigs_gl_draw_tex_prog(gl_backend, 6);
2344         }
2345
2346         bottom = false;
2347     }
2348
2349     return bottom;
2350 }
2351
2352 static bool vigs_gl_backend_composite(struct vigs_surface *surface,
2353                                       const struct vigs_plane *planes,
2354                                       bool planes_dirty,
2355                                       uint8_t *display_data)
2356 {
2357     struct vigs_gl_backend *gl_backend = (struct vigs_gl_backend*)surface->backend;
2358     struct vigs_gl_surface *gl_root_sfc = (struct vigs_gl_surface*)surface;
2359     struct vigs_winsys_gl_surface *ws_root_sfc = get_ws_sfc(gl_root_sfc);
2360     uint32_t i;
2361     int j;
2362     GLfloat *vert_coords;
2363     GLfloat *tex_coords;
2364     const struct vigs_plane *sorted_planes[VIGS_MAX_PLANES];
2365     bool bottom = true;
2366
2367     VIGS_LOG_TRACE("enter");
2368
2369     if (surface->ptr) {
2370         if (!vigs_qt5_onscreen_enabled() && !planes_dirty) {
2371             memcpy(display_data,
2372                    surface->ptr,
2373                    surface->stride * surface->ws_sfc->height);
2374             return true;
2375         }
2376     } else if (!ws_root_sfc->tex) {
2377         VIGS_LOG_WARN("compositing garbage (root surface) ???");
2378     }
2379
2380     if (!vigs_winsys_gl_surface_create_texture(ws_root_sfc)) {
2381         goto out;
2382     }
2383
2384     if (!vigs_gl_update_dpy_texture(gl_backend,
2385                                     surface->ws_sfc->width,
2386                                     surface->ws_sfc->height)) {
2387         goto out;
2388     }
2389
2390     for (i = 0; i < VIGS_MAX_PLANES; ++i) {
2391         struct vigs_gl_surface *gl_sfc;
2392         struct vigs_winsys_gl_surface *ws_sfc;
2393
2394         if (!vigs_plane_enabled(&planes[i])) {
2395             continue;
2396         }
2397
2398         for (j = 0; j < 4; ++j) {
2399             gl_sfc = (struct vigs_gl_surface*)planes[i].surfaces[j];
2400
2401             if (!gl_sfc) {
2402                 continue;
2403             }
2404
2405             ws_sfc = get_ws_sfc(gl_sfc);
2406
2407             if (!ws_sfc->tex) {
2408                 VIGS_LOG_WARN("compositing garbage (plane %u, sfc %d) ???", i, j);
2409             }
2410
2411             if (!vigs_winsys_gl_surface_create_texture(ws_sfc)) {
2412                 goto out;
2413             }
2414         }
2415     }
2416
2417     if (!vigs_gl_surface_setup_framebuffer(gl_root_sfc,
2418                                            gl_backend->tex_prog_id,
2419                                            gl_backend->tex_prog_proj_loc)) {
2420         goto out;
2421     }
2422
2423     vigs_gl_backend_sort_planes(planes, sorted_planes);
2424
2425     vigs_vector_resize(&gl_backend->v1, 0);
2426     vigs_vector_resize(&gl_backend->v2, 0);
2427
2428     vert_coords = vigs_vector_append(&gl_backend->v1,
2429                                      (12 * sizeof(GLfloat)));
2430     tex_coords = vigs_vector_append(&gl_backend->v2,
2431                                     (12 * sizeof(GLfloat)));
2432
2433     if (surface->ptr) {
2434         /*
2435          * Root surface is scanout, upload it to texture.
2436          * Slow path.
2437          */
2438
2439         gl_backend->PixelStorei(GL_UNPACK_ALIGNMENT, 1);
2440         gl_backend->PixelStorei(GL_UNPACK_ROW_LENGTH, 0);
2441         gl_backend->PixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
2442         gl_backend->PixelStorei(GL_UNPACK_SKIP_ROWS, 0);
2443
2444         gl_backend->BindTexture(GL_TEXTURE_2D, ws_root_sfc->tex);
2445
2446         gl_backend->TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,
2447                                   ws_root_sfc->base.base.width,
2448                                   ws_root_sfc->base.base.height,
2449                                   ws_root_sfc->tex_format,
2450                                   ws_root_sfc->tex_type,
2451                                   surface->ptr);
2452     }
2453
2454     gl_backend->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
2455                                      GL_TEXTURE_2D, gl_backend->current_dpy->tex, 0);
2456
2457     gl_backend->Clear(GL_COLOR_BUFFER_BIT);
2458
2459     bottom = vigs_gl_backend_composite_planes(gl_backend,
2460                                               sorted_planes,
2461                                               false,
2462                                               bottom,
2463                                               gl_root_sfc->ortho);
2464
2465     /*
2466      * Render root surface.
2467      */
2468
2469     vert_coords[6] = vert_coords[0] = 0;
2470     vert_coords[7] = vert_coords[1] = ws_root_sfc->base.base.height;
2471     vert_coords[2] = ws_root_sfc->base.base.width;
2472     vert_coords[3] = ws_root_sfc->base.base.height;
2473     vert_coords[8] = vert_coords[4] = ws_root_sfc->base.base.width;
2474     vert_coords[9] = vert_coords[5] = 0;
2475     vert_coords[10] = 0;
2476     vert_coords[11] = 0;
2477
2478     if (!surface->ptr) {
2479         tex_coords[6] = tex_coords[0] = 0;
2480         tex_coords[7] = tex_coords[1] = 0;
2481         tex_coords[2] = 1;
2482         tex_coords[3] = 0;
2483         tex_coords[8] = tex_coords[4] = 1;
2484         tex_coords[9] = tex_coords[5] = 1;
2485         tex_coords[10] = 0;
2486         tex_coords[11] = 1;
2487     } else {
2488         tex_coords[6] = tex_coords[0] = 0;
2489         tex_coords[7] = tex_coords[1] = 1;
2490         tex_coords[2] = 1;
2491         tex_coords[3] = 1;
2492         tex_coords[8] = tex_coords[4] = 1;
2493         tex_coords[9] = tex_coords[5] = 0;
2494         tex_coords[10] = 0;
2495         tex_coords[11] = 0;
2496     }
2497
2498     if (!bottom) {
2499         /*
2500          * Root surface has planes beneath it, turn on blending.
2501          *
2502          * Note that we DON'T check for alpha on root surface, i.e.:
2503          * (surface->format == vigsp_surface_bgra8888)
2504          * The reasons are:
2505          * + X.Org doesn't allow having 32 depths, i.e. only bpp can
2506          *   be 32, depth must be <= 24, i.e. X.Org is not underlay-aware,
2507          *   but that doesn't mean we can't have them with X.Org
2508          * + Since we DO have something beneath the root surface that means
2509          *   root surface just got to have alpha, otherwise user won't be
2510          *   able to see that "something", i.e. specifying alpha in root
2511          *   surface format is not that necessary in this case
2512          */
2513         gl_backend->Enable(GL_BLEND);
2514         gl_backend->BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2515     } else {
2516         gl_backend->Disable(GL_BLEND);
2517     }
2518
2519     gl_backend->BindTexture(GL_TEXTURE_2D, ws_root_sfc->tex);
2520
2521     vigs_gl_draw_tex_prog(gl_backend, 6);
2522
2523     bottom = false;
2524
2525     vigs_gl_backend_composite_planes(gl_backend,
2526                                      sorted_planes,
2527                                      true,
2528                                      bottom,
2529                                      gl_root_sfc->ortho);
2530
2531 out:
2532     gl_backend->BindFramebuffer(GL_FRAMEBUFFER, 0);
2533
2534     return false;
2535 }
2536
2537 static bool vigs_gl_backend_capture(struct vigs_surface *surface,
2538                                     void *pixels)
2539 {
2540     struct vigs_gl_backend *gl_backend = (struct vigs_gl_backend*)surface->backend;
2541
2542     if (gl_backend->read_pixels_make_current(gl_backend, true)) {
2543
2544         if (!gl_backend->dpy_fb) {
2545             gl_backend->GenFramebuffers(1, &gl_backend->dpy_fb);
2546
2547             if (!gl_backend->dpy_fb) {
2548                 VIGS_LOG_ERROR("cannot create capture FB");
2549
2550                 gl_backend->read_pixels_make_current(gl_backend, false);
2551
2552                 return false;
2553             }
2554
2555         }
2556
2557         gl_backend->BindFramebuffer(GL_FRAMEBUFFER, gl_backend->dpy_fb);
2558         gl_backend->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
2559                                          GL_TEXTURE_2D, gl_backend->current_dpy->tex, 0);
2560
2561         gl_backend->ReadPixels(0, 0, gl_backend->current_dpy->width,
2562                                gl_backend->current_dpy->height,
2563                                GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV,
2564                                pixels);
2565         gl_backend->BindFramebuffer(GL_FRAMEBUFFER, 0);
2566
2567         gl_backend->read_pixels_make_current(gl_backend, false);
2568
2569         return true;
2570     }
2571
2572     return false;
2573 }
2574
2575 static void vigs_gl_backend_batch_end(struct vigs_backend *backend)
2576 {
2577     struct vigs_gl_backend *gl_backend = (struct vigs_gl_backend*)backend;
2578
2579     gl_backend->Finish();
2580     gl_backend->make_current(gl_backend, false);
2581 }
2582
2583 static bool vigs_gl_backend_display(struct vigs_backend *backend,
2584                                     uint8_t *display_data)
2585 {
2586     struct vigs_gl_backend *gl_backend = (struct vigs_gl_backend*)backend;
2587
2588     VIGS_LOG_TRACE("enter");
2589
2590     if (vigs_qt5_onscreen_enabled()) {
2591         if (gl_backend->current_dpy && gl_backend->current_dpy->tex) {
2592             vigs_qt5_dpy_render_texture(gl_backend->current_dpy);
2593         }
2594         return true;
2595     }
2596
2597     if (gl_backend->read_pixels_make_current(gl_backend, true)) {
2598         if (!gl_backend->dpy_fb) {
2599             gl_backend->GenFramebuffers(1, &gl_backend->dpy_fb);
2600             if (!gl_backend->dpy_fb) {
2601                 VIGS_LOG_CRITICAL("cannot create FB");
2602                 exit(1);
2603             }
2604
2605             gl_backend->BindFramebuffer(GL_FRAMEBUFFER, gl_backend->dpy_fb);
2606         }
2607
2608         gl_backend->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
2609                                          GL_TEXTURE_2D, gl_backend->current_dpy->tex, 0);
2610
2611         gl_backend->ReadPixels(0, 0, gl_backend->current_dpy->width,
2612                                gl_backend->current_dpy->height,
2613                                GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV,
2614                                display_data);
2615
2616         gl_backend->read_pixels_make_current(gl_backend, false);
2617
2618         return true;
2619     } else {
2620         return false;
2621     }
2622 }
2623
2624 bool vigs_gl_backend_init(struct vigs_gl_backend *gl_backend)
2625 {
2626     if (!gl_backend->make_current(gl_backend, true)) {
2627         return false;
2628     }
2629
2630     gl_backend->tex_pool = vigs_gl_pool_create("tmp_tex",
2631                                                &vigs_gl_backend_alloc_tmp_texture,
2632                                                &vigs_gl_backend_release_tmp_texture,
2633                                                gl_backend);
2634     gl_backend->fb_pool = vigs_gl_pool_create("fb",
2635                                               &vigs_gl_backend_alloc_framebuffer,
2636                                               &vigs_gl_backend_release_framebuffer,
2637                                               gl_backend);
2638
2639     if (gl_backend->is_gl_2) {
2640         const char *tmp = (const char*)gl_backend->GetString(GL_EXTENSIONS);
2641
2642         if (!tmp || (strstr(tmp, "GL_ARB_map_buffer_range ") == NULL)) {
2643             VIGS_LOG_WARN("glMapBufferRange not supported, using glBufferSubData");
2644         }
2645
2646         gl_backend->MapBufferRange = NULL;
2647     } else {
2648         gl_backend->GenVertexArrays(1, &gl_backend->vao);
2649
2650         if (!gl_backend->vao) {
2651             VIGS_LOG_CRITICAL("cannot create VAO");
2652             goto fail;
2653         }
2654
2655         gl_backend->BindVertexArray(gl_backend->vao);
2656     }
2657
2658     VIGS_LOG_INFO("Current GL_VENDOR = %s",
2659                   (const char *)gl_backend->GetString(GL_VENDOR));
2660     VIGS_LOG_INFO("Current GL_RENDERER = %s",
2661                   (const char *)gl_backend->GetString(GL_RENDERER));
2662     VIGS_LOG_INFO("Current GL_VERSION = %s",
2663                   (const char *)gl_backend->GetString(GL_VERSION));
2664
2665     gl_backend->tex_prog_vs_id = vigs_gl_create_shader(gl_backend,
2666         (gl_backend->is_gl_2 ? g_vs_tex_source_gl2 : g_vs_tex_source_gl3),
2667         GL_VERTEX_SHADER);
2668
2669     if (!gl_backend->tex_prog_vs_id) {
2670         goto fail;
2671     }
2672
2673     gl_backend->tex_prog_fs_id = vigs_gl_create_shader(gl_backend,
2674         (gl_backend->is_gl_2 ? g_fs_tex_source_gl2 : g_fs_tex_source_gl3),
2675         GL_FRAGMENT_SHADER);
2676
2677     if (!gl_backend->tex_prog_fs_id) {
2678         goto fail;
2679     }
2680
2681     gl_backend->tex_prog_id = vigs_gl_create_program(gl_backend,
2682                                                      gl_backend->tex_prog_vs_id,
2683                                                      gl_backend->tex_prog_fs_id);
2684
2685     if (!gl_backend->tex_prog_id) {
2686         goto fail;
2687     }
2688
2689     gl_backend->tex_prog_proj_loc = gl_backend->GetUniformLocation(gl_backend->tex_prog_id, "proj");
2690     gl_backend->tex_prog_vertCoord_loc = gl_backend->GetAttribLocation(gl_backend->tex_prog_id, "vertCoord");
2691     gl_backend->tex_prog_texCoord_loc = gl_backend->GetAttribLocation(gl_backend->tex_prog_id, "texCoord");
2692
2693     gl_backend->color_prog_vs_id = vigs_gl_create_shader(gl_backend,
2694         (gl_backend->is_gl_2 ? g_vs_color_source_gl2 : g_vs_color_source_gl3),
2695         GL_VERTEX_SHADER);
2696
2697     if (!gl_backend->color_prog_vs_id) {
2698         goto fail;
2699     }
2700
2701     gl_backend->color_prog_fs_id = vigs_gl_create_shader(gl_backend,
2702         (gl_backend->is_gl_2 ? g_fs_color_source_gl2 : g_fs_color_source_gl3),
2703         GL_FRAGMENT_SHADER);
2704
2705     if (!gl_backend->color_prog_fs_id) {
2706         goto fail;
2707     }
2708
2709     gl_backend->color_prog_id = vigs_gl_create_program(gl_backend,
2710                                                        gl_backend->color_prog_vs_id,
2711                                                        gl_backend->color_prog_fs_id);
2712
2713     if (!gl_backend->color_prog_id) {
2714         goto fail;
2715     }
2716
2717     gl_backend->color_prog_proj_loc = gl_backend->GetUniformLocation(gl_backend->color_prog_id, "proj");
2718     gl_backend->color_prog_vertCoord_loc = gl_backend->GetAttribLocation(gl_backend->color_prog_id, "vertCoord");
2719     gl_backend->color_prog_color_loc = gl_backend->GetUniformLocation(gl_backend->color_prog_id, "color");
2720
2721     gl_backend->nv21_prog_vs_id = vigs_gl_create_shader(gl_backend,
2722         (gl_backend->is_gl_2 ? g_vs_nv21_source_gl2 : g_vs_nv21_source_gl3),
2723         GL_VERTEX_SHADER);
2724
2725     if (!gl_backend->nv21_prog_vs_id) {
2726         goto fail;
2727     }
2728
2729     gl_backend->nv21_prog_fs_id = vigs_gl_create_shader(gl_backend,
2730         (gl_backend->is_gl_2 ? g_fs_nv21_source_gl2 : g_fs_nv21_source_gl3),
2731         GL_FRAGMENT_SHADER);
2732
2733     if (!gl_backend->nv21_prog_fs_id) {
2734         goto fail;
2735     }
2736
2737     gl_backend->nv21_prog_id = vigs_gl_create_program(gl_backend,
2738                                                       gl_backend->nv21_prog_vs_id,
2739                                                       gl_backend->nv21_prog_fs_id);
2740
2741     if (!gl_backend->nv21_prog_id) {
2742         goto fail;
2743     }
2744
2745     gl_backend->nv21_prog_proj_loc = gl_backend->GetUniformLocation(gl_backend->nv21_prog_id, "proj");
2746     gl_backend->nv21_prog_vertCoord_loc = gl_backend->GetAttribLocation(gl_backend->nv21_prog_id, "vertCoord");
2747     gl_backend->nv21_prog_texCoord_loc = gl_backend->GetAttribLocation(gl_backend->nv21_prog_id, "texCoord");
2748     gl_backend->nv21_prog_size_loc = gl_backend->GetUniformLocation(gl_backend->nv21_prog_id, "size");
2749     gl_backend->nv21_prog_ytexSize_loc = gl_backend->GetUniformLocation(gl_backend->nv21_prog_id, "ytexSize");
2750     gl_backend->nv21_prog_ctexSize_loc = gl_backend->GetUniformLocation(gl_backend->nv21_prog_id, "ctexSize");
2751     gl_backend->nv21_prog_ytex_loc = gl_backend->GetUniformLocation(gl_backend->nv21_prog_id, "ytex");
2752     gl_backend->nv21_prog_ctex_loc = gl_backend->GetUniformLocation(gl_backend->nv21_prog_id, "ctex");
2753
2754     gl_backend->yuv420_prog_vs_id = vigs_gl_create_shader(gl_backend,
2755         (gl_backend->is_gl_2 ? g_vs_yuv420_source_gl2 : g_vs_yuv420_source_gl3),
2756         GL_VERTEX_SHADER);
2757
2758     if (!gl_backend->yuv420_prog_vs_id) {
2759         goto fail;
2760     }
2761
2762     gl_backend->yuv420_prog_fs_id = vigs_gl_create_shader(gl_backend,
2763         (gl_backend->is_gl_2 ? g_fs_yuv420_source_gl2 : g_fs_yuv420_source_gl3),
2764         GL_FRAGMENT_SHADER);
2765
2766     if (!gl_backend->yuv420_prog_fs_id) {
2767         goto fail;
2768     }
2769
2770     gl_backend->yuv420_prog_id = vigs_gl_create_program(gl_backend,
2771                                                         gl_backend->yuv420_prog_vs_id,
2772                                                         gl_backend->yuv420_prog_fs_id);
2773
2774     if (!gl_backend->yuv420_prog_id) {
2775         goto fail;
2776     }
2777
2778     gl_backend->yuv420_prog_proj_loc = gl_backend->GetUniformLocation(gl_backend->yuv420_prog_id, "proj");
2779     gl_backend->yuv420_prog_vertCoord_loc = gl_backend->GetAttribLocation(gl_backend->yuv420_prog_id, "vertCoord");
2780     gl_backend->yuv420_prog_texCoord_loc = gl_backend->GetAttribLocation(gl_backend->yuv420_prog_id, "texCoord");
2781     gl_backend->yuv420_prog_size_loc = gl_backend->GetUniformLocation(gl_backend->yuv420_prog_id, "size");
2782     gl_backend->yuv420_prog_ytexSize_loc = gl_backend->GetUniformLocation(gl_backend->yuv420_prog_id, "ytexSize");
2783     gl_backend->yuv420_prog_utexSize_loc = gl_backend->GetUniformLocation(gl_backend->yuv420_prog_id, "utexSize");
2784     gl_backend->yuv420_prog_vtexSize_loc = gl_backend->GetUniformLocation(gl_backend->yuv420_prog_id, "vtexSize");
2785     gl_backend->yuv420_prog_ytex_loc = gl_backend->GetUniformLocation(gl_backend->yuv420_prog_id, "ytex");
2786     gl_backend->yuv420_prog_utex_loc = gl_backend->GetUniformLocation(gl_backend->yuv420_prog_id, "utex");
2787     gl_backend->yuv420_prog_vtex_loc = gl_backend->GetUniformLocation(gl_backend->yuv420_prog_id, "vtex");
2788
2789     gl_backend->xbgr_prog_fs_id = vigs_gl_create_shader(gl_backend,
2790         (gl_backend->is_gl_2 ? g_fs_xbgr_source_gl2 : g_fs_xbgr_source_gl3),
2791         GL_FRAGMENT_SHADER);
2792
2793     if (!gl_backend->xbgr_prog_fs_id) {
2794         goto fail;
2795     }
2796
2797     /*
2798      * Let's borrow compiled vertex shader from tex program
2799      */
2800
2801     gl_backend->xbgr_prog_id = vigs_gl_create_program(gl_backend,
2802                                                       gl_backend->tex_prog_vs_id,
2803                                                       gl_backend->xbgr_prog_fs_id);
2804
2805     if (!gl_backend->xbgr_prog_id) {
2806         goto fail;
2807     }
2808
2809     gl_backend->xbgr_prog_proj_loc = gl_backend->GetUniformLocation(gl_backend->xbgr_prog_id, "proj");
2810     gl_backend->xbgr_prog_vertCoord_loc = gl_backend->GetAttribLocation(gl_backend->xbgr_prog_id, "vertCoord");
2811     gl_backend->xbgr_prog_texCoord_loc = gl_backend->GetAttribLocation(gl_backend->xbgr_prog_id, "texCoord");
2812
2813     gl_backend->GenBuffers(1, &gl_backend->vbo);
2814     if (!gl_backend->vbo) {
2815         VIGS_LOG_CRITICAL("cannot create VBOs");
2816         goto fail;
2817     }
2818
2819     gl_backend->BindBuffer(GL_ARRAY_BUFFER, gl_backend->vbo);
2820
2821     gl_backend->UseProgram(gl_backend->nv21_prog_id);
2822     gl_backend->Uniform1i(gl_backend->nv21_prog_ytex_loc, 0);
2823     gl_backend->Uniform1i(gl_backend->nv21_prog_ctex_loc, 1);
2824
2825     gl_backend->UseProgram(gl_backend->yuv420_prog_id);
2826     gl_backend->Uniform1i(gl_backend->yuv420_prog_ytex_loc, 0);
2827     gl_backend->Uniform1i(gl_backend->yuv420_prog_utex_loc, 1);
2828     gl_backend->Uniform1i(gl_backend->yuv420_prog_vtex_loc, 2);
2829
2830     gl_backend->UseProgram(gl_backend->tex_prog_id);
2831     gl_backend->cur_prog_id = gl_backend->tex_prog_id;
2832
2833     gl_backend->ClearColor(0.0f, 0.0f, 0.0f, 0.0f);
2834     gl_backend->Disable(GL_DEPTH_TEST);
2835     gl_backend->Disable(GL_BLEND);
2836
2837     gl_backend->base.batch_start = &vigs_gl_backend_batch_start;
2838     gl_backend->base.create_surface = &vigs_gl_backend_create_surface;
2839     gl_backend->base.composite = &vigs_gl_backend_composite;
2840     gl_backend->base.capture = &vigs_gl_backend_capture;
2841     gl_backend->base.batch_end = &vigs_gl_backend_batch_end;
2842     gl_backend->base.display = &vigs_gl_backend_display;
2843
2844     gl_backend->make_current(gl_backend, false);
2845
2846     vigs_vector_init(&gl_backend->v1, 0);
2847     vigs_vector_init(&gl_backend->v2, 0);
2848
2849     int i;
2850     for (i = 0; i < TEXTURE_NUM; ++i) {
2851         gl_backend->dpy_items[i].available = true;
2852         qemu_mutex_init(&gl_backend->dpy_items[i].mutex);
2853     }
2854
2855     return true;
2856
2857 fail:
2858     gl_backend->make_current(gl_backend, false);
2859
2860     return false;
2861 }
2862
2863 void vigs_gl_backend_cleanup(struct vigs_gl_backend *gl_backend)
2864 {
2865     if (gl_backend->make_current(gl_backend, true)) {
2866         int i;
2867         for (i = 0; i < TEXTURE_NUM; i++) {
2868             if (gl_backend->dpy_items[i].tex) {
2869                 gl_backend->DeleteTextures(1, &gl_backend->dpy_items[i].tex);
2870             }
2871             qemu_mutex_destroy(&gl_backend->dpy_items[i].mutex);
2872         }
2873         if (gl_backend->dpy_fb) {
2874             gl_backend->DeleteFramebuffers(1, &gl_backend->dpy_fb);
2875         }
2876         gl_backend->DeleteBuffers(1, &gl_backend->vbo);
2877         gl_backend->DetachShader(gl_backend->yuv420_prog_id,
2878                                  gl_backend->yuv420_prog_vs_id);
2879         gl_backend->DetachShader(gl_backend->yuv420_prog_id,
2880                                  gl_backend->yuv420_prog_fs_id);
2881         gl_backend->DeleteShader(gl_backend->yuv420_prog_vs_id);
2882         gl_backend->DeleteShader(gl_backend->yuv420_prog_fs_id);
2883         gl_backend->DeleteProgram(gl_backend->yuv420_prog_id);
2884         gl_backend->DetachShader(gl_backend->nv21_prog_id,
2885                                  gl_backend->nv21_prog_vs_id);
2886         gl_backend->DetachShader(gl_backend->nv21_prog_id,
2887                                  gl_backend->nv21_prog_fs_id);
2888         gl_backend->DeleteShader(gl_backend->nv21_prog_vs_id);
2889         gl_backend->DeleteShader(gl_backend->nv21_prog_fs_id);
2890         gl_backend->DeleteProgram(gl_backend->nv21_prog_id);
2891         gl_backend->DetachShader(gl_backend->color_prog_id,
2892                                  gl_backend->color_prog_vs_id);
2893         gl_backend->DetachShader(gl_backend->color_prog_id,
2894                                  gl_backend->color_prog_fs_id);
2895         gl_backend->DeleteShader(gl_backend->color_prog_vs_id);
2896         gl_backend->DeleteShader(gl_backend->color_prog_fs_id);
2897         gl_backend->DeleteProgram(gl_backend->color_prog_id);
2898         gl_backend->DetachShader(gl_backend->tex_prog_id,
2899                                  gl_backend->tex_prog_vs_id);
2900         gl_backend->DetachShader(gl_backend->tex_prog_id,
2901                                  gl_backend->tex_prog_fs_id);
2902         gl_backend->DeleteShader(gl_backend->tex_prog_vs_id);
2903         gl_backend->DeleteShader(gl_backend->tex_prog_fs_id);
2904         gl_backend->DeleteProgram(gl_backend->tex_prog_id);
2905
2906         if (!gl_backend->is_gl_2) {
2907             gl_backend->DeleteVertexArrays(1, &gl_backend->vao);
2908         }
2909
2910         vigs_gl_pool_destroy(gl_backend->fb_pool);
2911         vigs_gl_pool_destroy(gl_backend->tex_pool);
2912
2913         gl_backend->make_current(gl_backend, false);
2914     }
2915
2916     vigs_vector_cleanup(&gl_backend->v2);
2917     vigs_vector_cleanup(&gl_backend->v1);
2918 }