blob: a256a57a2ac18a975041f2672cb23805e54bd692 [file] [log] [blame]
Kristian Høgsbergd7c17262012-09-05 21:54:15 -04001/*
2 * Copyright © 2012 Intel Corporation
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and
5 * its documentation for any purpose is hereby granted without fee, provided
6 * that the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name of the copyright holders not be used in
9 * advertising or publicity pertaining to distribution of the software
10 * without specific, written prior permission. The copyright holders make
11 * no representations about the suitability of this software for any
12 * purpose. It is provided "as is" without express or implied warranty.
13 *
14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
15 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
16 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
17 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
18 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
19 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
20 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 */
22
Kristian Høgsberg25894fc2012-09-05 22:06:26 -040023#define _GNU_SOURCE
24
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -040025#include <stdlib.h>
Kristian Høgsberg25894fc2012-09-05 22:06:26 -040026#include <string.h>
27#include <ctype.h>
Pekka Paalanen0d64a0f2012-09-11 17:02:05 +030028#include <float.h>
29#include <assert.h>
Ander Conselvan de Oliveira27508c22012-11-08 17:20:46 +020030#include <linux/input.h>
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -040031
Kristian Høgsbergd7c17262012-09-05 21:54:15 -040032#include "compositor.h"
33
John Kåre Alsaker40684142012-11-13 19:10:25 +010034struct gles2_shader {
35 GLuint program;
36 GLuint vertex_shader, fragment_shader;
37 GLint proj_uniform;
38 GLint tex_uniforms[3];
39 GLint alpha_uniform;
40 GLint color_uniform;
41};
42
John Kåre Alsaker94659272012-11-13 19:10:18 +010043struct gles2_output_state {
44 EGLSurface egl_surface;
45};
46
John Kåre Alsaker878f4492012-11-13 19:10:23 +010047struct gles2_surface_state {
48 GLfloat color[4];
John Kåre Alsaker40684142012-11-13 19:10:25 +010049 struct gles2_shader *shader;
John Kåre Alsaker878f4492012-11-13 19:10:23 +010050};
51
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +010052struct gles2_renderer {
53 struct weston_renderer base;
54 int fragment_shader_debug;
55
56 EGLDisplay egl_display;
57 EGLContext egl_context;
58 EGLConfig egl_config;
John Kåre Alsaker44154502012-11-13 19:10:20 +010059
60 struct {
61 int32_t top, bottom, left, right;
62 GLuint texture;
63 int32_t width, height;
64 } border;
John Kåre Alsaker40684142012-11-13 19:10:25 +010065
66 struct gles2_shader texture_shader_rgba;
67 struct gles2_shader texture_shader_rgbx;
68 struct gles2_shader texture_shader_egl_external;
69 struct gles2_shader texture_shader_y_uv;
70 struct gles2_shader texture_shader_y_u_v;
71 struct gles2_shader texture_shader_y_xuxv;
72 struct gles2_shader invert_color_shader;
73 struct gles2_shader solid_shader;
74 struct gles2_shader *current_shader;
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +010075};
John Kåre Alsaker94659272012-11-13 19:10:18 +010076
77static inline struct gles2_output_state *
78get_output_state(struct weston_output *output)
79{
80 return (struct gles2_output_state *)output->renderer_state;
81}
82
John Kåre Alsaker878f4492012-11-13 19:10:23 +010083static inline struct gles2_surface_state *
84get_surface_state(struct weston_surface *surface)
85{
86 return (struct gles2_surface_state *)surface->renderer_state;
87}
88
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +010089static inline struct gles2_renderer *
90get_renderer(struct weston_compositor *ec)
91{
92 return (struct gles2_renderer *)ec->renderer;
93}
94
Kristian Høgsbergd7c17262012-09-05 21:54:15 -040095static const char *
96egl_error_string(EGLint code)
97{
98#define MYERRCODE(x) case x: return #x;
99 switch (code) {
100 MYERRCODE(EGL_SUCCESS)
101 MYERRCODE(EGL_NOT_INITIALIZED)
102 MYERRCODE(EGL_BAD_ACCESS)
103 MYERRCODE(EGL_BAD_ALLOC)
104 MYERRCODE(EGL_BAD_ATTRIBUTE)
105 MYERRCODE(EGL_BAD_CONTEXT)
106 MYERRCODE(EGL_BAD_CONFIG)
107 MYERRCODE(EGL_BAD_CURRENT_SURFACE)
108 MYERRCODE(EGL_BAD_DISPLAY)
109 MYERRCODE(EGL_BAD_SURFACE)
110 MYERRCODE(EGL_BAD_MATCH)
111 MYERRCODE(EGL_BAD_PARAMETER)
112 MYERRCODE(EGL_BAD_NATIVE_PIXMAP)
113 MYERRCODE(EGL_BAD_NATIVE_WINDOW)
114 MYERRCODE(EGL_CONTEXT_LOST)
115 default:
116 return "unknown";
117 }
118#undef MYERRCODE
119}
120
121static void
122print_egl_error_state(void)
123{
124 EGLint code;
125
126 code = eglGetError();
127 weston_log("EGL error state: %s (0x%04lx)\n",
128 egl_error_string(code), (long)code);
129}
130
Pekka Paalanen0d64a0f2012-09-11 17:02:05 +0300131struct polygon8 {
132 GLfloat x[8];
133 GLfloat y[8];
134 int n;
135};
136
137struct clip_context {
138 struct {
139 GLfloat x;
140 GLfloat y;
141 } prev;
142
143 struct {
144 GLfloat x1, y1;
145 GLfloat x2, y2;
146 } clip;
147
148 struct {
149 GLfloat *x;
150 GLfloat *y;
151 } vertices;
152};
153
154static GLfloat
155float_difference(GLfloat a, GLfloat b)
156{
157 /* http://www.altdevblogaday.com/2012/02/22/comparing-floating-point-numbers-2012-edition/ */
158 static const GLfloat max_diff = 4.0f * FLT_MIN;
159 static const GLfloat max_rel_diff = 4.0e-5;
160 GLfloat diff = a - b;
161 GLfloat adiff = fabsf(diff);
162
163 if (adiff <= max_diff)
164 return 0.0f;
165
166 a = fabsf(a);
167 b = fabsf(b);
168 if (adiff <= (a > b ? a : b) * max_rel_diff)
169 return 0.0f;
170
171 return diff;
172}
173
174/* A line segment (p1x, p1y)-(p2x, p2y) intersects the line x = x_arg.
175 * Compute the y coordinate of the intersection.
176 */
177static GLfloat
178clip_intersect_y(GLfloat p1x, GLfloat p1y, GLfloat p2x, GLfloat p2y,
179 GLfloat x_arg)
180{
181 GLfloat a;
182 GLfloat diff = float_difference(p1x, p2x);
183
184 /* Practically vertical line segment, yet the end points have already
185 * been determined to be on different sides of the line. Therefore
186 * the line segment is part of the line and intersects everywhere.
187 * Return the end point, so we use the whole line segment.
188 */
189 if (diff == 0.0f)
190 return p2y;
191
192 a = (x_arg - p2x) / diff;
193 return p2y + (p1y - p2y) * a;
194}
195
196/* A line segment (p1x, p1y)-(p2x, p2y) intersects the line y = y_arg.
197 * Compute the x coordinate of the intersection.
198 */
199static GLfloat
200clip_intersect_x(GLfloat p1x, GLfloat p1y, GLfloat p2x, GLfloat p2y,
201 GLfloat y_arg)
202{
203 GLfloat a;
204 GLfloat diff = float_difference(p1y, p2y);
205
206 /* Practically horizontal line segment, yet the end points have already
207 * been determined to be on different sides of the line. Therefore
208 * the line segment is part of the line and intersects everywhere.
209 * Return the end point, so we use the whole line segment.
210 */
211 if (diff == 0.0f)
212 return p2x;
213
214 a = (y_arg - p2y) / diff;
215 return p2x + (p1x - p2x) * a;
216}
217
218enum path_transition {
219 PATH_TRANSITION_OUT_TO_OUT = 0,
220 PATH_TRANSITION_OUT_TO_IN = 1,
221 PATH_TRANSITION_IN_TO_OUT = 2,
222 PATH_TRANSITION_IN_TO_IN = 3,
223};
224
225static void
226clip_append_vertex(struct clip_context *ctx, GLfloat x, GLfloat y)
227{
228 *ctx->vertices.x++ = x;
229 *ctx->vertices.y++ = y;
230}
231
232static enum path_transition
233path_transition_left_edge(struct clip_context *ctx, GLfloat x, GLfloat y)
234{
235 return ((ctx->prev.x >= ctx->clip.x1) << 1) | (x >= ctx->clip.x1);
236}
237
238static enum path_transition
239path_transition_right_edge(struct clip_context *ctx, GLfloat x, GLfloat y)
240{
241 return ((ctx->prev.x < ctx->clip.x2) << 1) | (x < ctx->clip.x2);
242}
243
244static enum path_transition
245path_transition_top_edge(struct clip_context *ctx, GLfloat x, GLfloat y)
246{
247 return ((ctx->prev.y >= ctx->clip.y1) << 1) | (y >= ctx->clip.y1);
248}
249
250static enum path_transition
251path_transition_bottom_edge(struct clip_context *ctx, GLfloat x, GLfloat y)
252{
253 return ((ctx->prev.y < ctx->clip.y2) << 1) | (y < ctx->clip.y2);
254}
255
256static void
257clip_polygon_leftright(struct clip_context *ctx,
258 enum path_transition transition,
259 GLfloat x, GLfloat y, GLfloat clip_x)
260{
261 GLfloat yi;
262
263 switch (transition) {
264 case PATH_TRANSITION_IN_TO_IN:
265 clip_append_vertex(ctx, x, y);
266 break;
267 case PATH_TRANSITION_IN_TO_OUT:
268 yi = clip_intersect_y(ctx->prev.x, ctx->prev.y, x, y, clip_x);
269 clip_append_vertex(ctx, clip_x, yi);
270 break;
271 case PATH_TRANSITION_OUT_TO_IN:
272 yi = clip_intersect_y(ctx->prev.x, ctx->prev.y, x, y, clip_x);
273 clip_append_vertex(ctx, clip_x, yi);
274 clip_append_vertex(ctx, x, y);
275 break;
276 case PATH_TRANSITION_OUT_TO_OUT:
277 /* nothing */
278 break;
279 default:
280 assert(0 && "bad enum path_transition");
281 }
282
283 ctx->prev.x = x;
284 ctx->prev.y = y;
285}
286
287static void
288clip_polygon_topbottom(struct clip_context *ctx,
289 enum path_transition transition,
290 GLfloat x, GLfloat y, GLfloat clip_y)
291{
292 GLfloat xi;
293
294 switch (transition) {
295 case PATH_TRANSITION_IN_TO_IN:
296 clip_append_vertex(ctx, x, y);
297 break;
298 case PATH_TRANSITION_IN_TO_OUT:
299 xi = clip_intersect_x(ctx->prev.x, ctx->prev.y, x, y, clip_y);
300 clip_append_vertex(ctx, xi, clip_y);
301 break;
302 case PATH_TRANSITION_OUT_TO_IN:
303 xi = clip_intersect_x(ctx->prev.x, ctx->prev.y, x, y, clip_y);
304 clip_append_vertex(ctx, xi, clip_y);
305 clip_append_vertex(ctx, x, y);
306 break;
307 case PATH_TRANSITION_OUT_TO_OUT:
308 /* nothing */
309 break;
310 default:
311 assert(0 && "bad enum path_transition");
312 }
313
314 ctx->prev.x = x;
315 ctx->prev.y = y;
316}
317
318static void
319clip_context_prepare(struct clip_context *ctx, const struct polygon8 *src,
320 GLfloat *dst_x, GLfloat *dst_y)
321{
322 ctx->prev.x = src->x[src->n - 1];
323 ctx->prev.y = src->y[src->n - 1];
324 ctx->vertices.x = dst_x;
325 ctx->vertices.y = dst_y;
326}
327
328static int
329clip_polygon_left(struct clip_context *ctx, const struct polygon8 *src,
330 GLfloat *dst_x, GLfloat *dst_y)
331{
332 enum path_transition trans;
333 int i;
334
335 clip_context_prepare(ctx, src, dst_x, dst_y);
336 for (i = 0; i < src->n; i++) {
337 trans = path_transition_left_edge(ctx, src->x[i], src->y[i]);
338 clip_polygon_leftright(ctx, trans, src->x[i], src->y[i],
339 ctx->clip.x1);
340 }
341 return ctx->vertices.x - dst_x;
342}
343
344static int
345clip_polygon_right(struct clip_context *ctx, const struct polygon8 *src,
346 GLfloat *dst_x, GLfloat *dst_y)
347{
348 enum path_transition trans;
349 int i;
350
351 clip_context_prepare(ctx, src, dst_x, dst_y);
352 for (i = 0; i < src->n; i++) {
353 trans = path_transition_right_edge(ctx, src->x[i], src->y[i]);
354 clip_polygon_leftright(ctx, trans, src->x[i], src->y[i],
355 ctx->clip.x2);
356 }
357 return ctx->vertices.x - dst_x;
358}
359
360static int
361clip_polygon_top(struct clip_context *ctx, const struct polygon8 *src,
362 GLfloat *dst_x, GLfloat *dst_y)
363{
364 enum path_transition trans;
365 int i;
366
367 clip_context_prepare(ctx, src, dst_x, dst_y);
368 for (i = 0; i < src->n; i++) {
369 trans = path_transition_top_edge(ctx, src->x[i], src->y[i]);
370 clip_polygon_topbottom(ctx, trans, src->x[i], src->y[i],
371 ctx->clip.y1);
372 }
373 return ctx->vertices.x - dst_x;
374}
375
376static int
377clip_polygon_bottom(struct clip_context *ctx, const struct polygon8 *src,
378 GLfloat *dst_x, GLfloat *dst_y)
379{
380 enum path_transition trans;
381 int i;
382
383 clip_context_prepare(ctx, src, dst_x, dst_y);
384 for (i = 0; i < src->n; i++) {
385 trans = path_transition_bottom_edge(ctx, src->x[i], src->y[i]);
386 clip_polygon_topbottom(ctx, trans, src->x[i], src->y[i],
387 ctx->clip.y2);
388 }
389 return ctx->vertices.x - dst_x;
390}
391
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400392#define max(a, b) (((a) > (b)) ? (a) : (b))
393#define min(a, b) (((a) > (b)) ? (b) : (a))
394#define clip(x, a, b) min(max(x, a), b)
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400395
Pekka Paalanen0d64a0f2012-09-11 17:02:05 +0300396/*
397 * Compute the boundary vertices of the intersection of the global coordinate
398 * aligned rectangle 'rect', and an arbitrary quadrilateral produced from
399 * 'surf_rect' when transformed from surface coordinates into global coordinates.
400 * The vertices are written to 'ex' and 'ey', and the return value is the
401 * number of vertices. Vertices are produced in clockwise winding order.
402 * Guarantees to produce either zero vertices, or 3-8 vertices with non-zero
403 * polygon area.
404 */
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400405static int
406calculate_edges(struct weston_surface *es, pixman_box32_t *rect,
407 pixman_box32_t *surf_rect, GLfloat *ex, GLfloat *ey)
408{
Pekka Paalanen0d64a0f2012-09-11 17:02:05 +0300409 struct polygon8 polygon;
410 struct clip_context ctx;
411 int i, n;
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400412 GLfloat min_x, max_x, min_y, max_y;
Pekka Paalanen0d64a0f2012-09-11 17:02:05 +0300413 struct polygon8 surf = {
414 { surf_rect->x1, surf_rect->x2, surf_rect->x2, surf_rect->x1 },
415 { surf_rect->y1, surf_rect->y1, surf_rect->y2, surf_rect->y2 },
416 4
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400417 };
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400418
Pekka Paalanen0d64a0f2012-09-11 17:02:05 +0300419 ctx.clip.x1 = rect->x1;
420 ctx.clip.y1 = rect->y1;
421 ctx.clip.x2 = rect->x2;
422 ctx.clip.y2 = rect->y2;
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400423
424 /* transform surface to screen space: */
Pekka Paalanen0d64a0f2012-09-11 17:02:05 +0300425 for (i = 0; i < surf.n; i++)
426 weston_surface_to_global_float(es, surf.x[i], surf.y[i],
427 &surf.x[i], &surf.y[i]);
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400428
429 /* find bounding box: */
Pekka Paalanen0d64a0f2012-09-11 17:02:05 +0300430 min_x = max_x = surf.x[0];
431 min_y = max_y = surf.y[0];
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400432
Pekka Paalanen0d64a0f2012-09-11 17:02:05 +0300433 for (i = 1; i < surf.n; i++) {
434 min_x = min(min_x, surf.x[i]);
435 max_x = max(max_x, surf.x[i]);
436 min_y = min(min_y, surf.y[i]);
437 max_y = max(max_y, surf.y[i]);
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400438 }
439
440 /* First, simple bounding box check to discard early transformed
441 * surface rects that do not intersect with the clip region:
442 */
Pekka Paalanen0d64a0f2012-09-11 17:02:05 +0300443 if ((min_x >= ctx.clip.x2) || (max_x <= ctx.clip.x1) ||
444 (min_y >= ctx.clip.y2) || (max_y <= ctx.clip.y1))
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400445 return 0;
446
447 /* Simple case, bounding box edges are parallel to surface edges,
448 * there will be only four edges. We just need to clip the surface
449 * vertices to the clip rect bounds:
450 */
451 if (!es->transform.enabled) {
Pekka Paalanen0d64a0f2012-09-11 17:02:05 +0300452 for (i = 0; i < surf.n; i++) {
453 ex[i] = clip(surf.x[i], ctx.clip.x1, ctx.clip.x2);
454 ey[i] = clip(surf.y[i], ctx.clip.y1, ctx.clip.y2);
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400455 }
Pekka Paalanen0d64a0f2012-09-11 17:02:05 +0300456 return surf.n;
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400457 }
458
Pekka Paalanen0d64a0f2012-09-11 17:02:05 +0300459 /* Transformed case: use a general polygon clipping algorithm to
460 * clip the surface rectangle with each side of 'rect'.
461 * The algorithm is Sutherland-Hodgman, as explained in
462 * http://www.codeguru.com/cpp/misc/misc/graphics/article.php/c8965/Polygon-Clipping.htm
463 * but without looking at any of that code.
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400464 */
Pekka Paalanen0d64a0f2012-09-11 17:02:05 +0300465 polygon.n = clip_polygon_left(&ctx, &surf, polygon.x, polygon.y);
466 surf.n = clip_polygon_right(&ctx, &polygon, surf.x, surf.y);
467 polygon.n = clip_polygon_top(&ctx, &surf, polygon.x, polygon.y);
468 surf.n = clip_polygon_bottom(&ctx, &polygon, surf.x, surf.y);
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400469
Pekka Paalanen0d64a0f2012-09-11 17:02:05 +0300470 /* Get rid of duplicate vertices */
471 ex[0] = surf.x[0];
472 ey[0] = surf.y[0];
473 n = 1;
474 for (i = 1; i < surf.n; i++) {
475 if (float_difference(ex[n - 1], surf.x[i]) == 0.0f &&
476 float_difference(ey[n - 1], surf.y[i]) == 0.0f)
477 continue;
478 ex[n] = surf.x[i];
479 ey[n] = surf.y[i];
480 n++;
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400481 }
Pekka Paalanen0d64a0f2012-09-11 17:02:05 +0300482 if (float_difference(ex[n - 1], surf.x[0]) == 0.0f &&
483 float_difference(ey[n - 1], surf.y[0]) == 0.0f)
484 n--;
485
486 if (n < 3)
487 return 0;
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400488
489 return n;
490}
491
492static int
493texture_region(struct weston_surface *es, pixman_region32_t *region,
494 pixman_region32_t *surf_region)
495{
496 struct weston_compositor *ec = es->compositor;
497 GLfloat *v, inv_width, inv_height;
498 unsigned int *vtxcnt, nvtx = 0;
499 pixman_box32_t *rects, *surf_rects;
500 int i, j, k, nrects, nsurf;
501
502 rects = pixman_region32_rectangles(region, &nrects);
503 surf_rects = pixman_region32_rectangles(surf_region, &nsurf);
504
505 /* worst case we can have 8 vertices per rect (ie. clipped into
506 * an octagon):
507 */
508 v = wl_array_add(&ec->vertices, nrects * nsurf * 8 * 4 * sizeof *v);
509 vtxcnt = wl_array_add(&ec->vtxcnt, nrects * nsurf * sizeof *vtxcnt);
510
511 inv_width = 1.0 / es->pitch;
512 inv_height = 1.0 / es->geometry.height;
513
514 for (i = 0; i < nrects; i++) {
515 pixman_box32_t *rect = &rects[i];
516 for (j = 0; j < nsurf; j++) {
517 pixman_box32_t *surf_rect = &surf_rects[j];
518 GLfloat sx, sy;
519 GLfloat ex[8], ey[8]; /* edge points in screen space */
520 int n;
521
522 /* The transformed surface, after clipping to the clip region,
523 * can have as many as eight sides, emitted as a triangle-fan.
524 * The first vertex in the triangle fan can be chosen arbitrarily,
525 * since the area is guaranteed to be convex.
526 *
527 * If a corner of the transformed surface falls outside of the
528 * clip region, instead of emitting one vertex for the corner
529 * of the surface, up to two are emitted for two corresponding
530 * intersection point(s) between the surface and the clip region.
531 *
532 * To do this, we first calculate the (up to eight) points that
533 * form the intersection of the clip rect and the transformed
534 * surface.
535 */
536 n = calculate_edges(es, rect, surf_rect, ex, ey);
537 if (n < 3)
538 continue;
539
540 /* emit edge points: */
541 for (k = 0; k < n; k++) {
542 weston_surface_from_global_float(es, ex[k], ey[k], &sx, &sy);
543 /* position: */
544 *(v++) = ex[k];
545 *(v++) = ey[k];
546 /* texcoord: */
547 *(v++) = sx * inv_width;
548 *(v++) = sy * inv_height;
549 }
550
551 vtxcnt[nvtx++] = n;
552 }
553 }
554
555 return nvtx;
556}
557
558static void
559triangle_fan_debug(struct weston_surface *surface, int first, int count)
560{
561 struct weston_compositor *compositor = surface->compositor;
John Kåre Alsaker40684142012-11-13 19:10:25 +0100562 struct gles2_renderer *gr = get_renderer(compositor);
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400563 int i;
564 GLushort *buffer;
565 GLushort *index;
566 int nelems;
567 static int color_idx = 0;
568 static const GLfloat color[][4] = {
569 { 1.0, 0.0, 0.0, 1.0 },
570 { 0.0, 1.0, 0.0, 1.0 },
571 { 0.0, 0.0, 1.0, 1.0 },
572 { 1.0, 1.0, 1.0, 1.0 },
573 };
574
575 nelems = (count - 1 + count - 2) * 2;
576
577 buffer = malloc(sizeof(GLushort) * nelems);
578 index = buffer;
579
580 for (i = 1; i < count; i++) {
581 *index++ = first;
582 *index++ = first + i;
583 }
584
585 for (i = 2; i < count; i++) {
586 *index++ = first + i - 1;
587 *index++ = first + i;
588 }
589
John Kåre Alsaker40684142012-11-13 19:10:25 +0100590 glUseProgram(gr->solid_shader.program);
591 glUniform4fv(gr->solid_shader.color_uniform, 1,
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400592 color[color_idx++ % ARRAY_LENGTH(color)]);
593 glDrawElements(GL_LINES, nelems, GL_UNSIGNED_SHORT, buffer);
John Kåre Alsaker40684142012-11-13 19:10:25 +0100594 glUseProgram(gr->current_shader->program);
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400595 free(buffer);
596}
597
598static void
599repaint_region(struct weston_surface *es, pixman_region32_t *region,
600 pixman_region32_t *surf_region)
601{
602 struct weston_compositor *ec = es->compositor;
603 GLfloat *v;
604 unsigned int *vtxcnt;
605 int i, first, nfans;
606
607 /* The final region to be painted is the intersection of
608 * 'region' and 'surf_region'. However, 'region' is in the global
609 * coordinates, and 'surf_region' is in the surface-local
610 * coordinates. texture_region() will iterate over all pairs of
611 * rectangles from both regions, compute the intersection
612 * polygon for each pair, and store it as a triangle fan if
613 * it has a non-zero area (at least 3 vertices, actually).
614 */
615 nfans = texture_region(es, region, surf_region);
616
617 v = ec->vertices.data;
618 vtxcnt = ec->vtxcnt.data;
619
620 /* position: */
621 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof *v, &v[0]);
622 glEnableVertexAttribArray(0);
623
624 /* texcoord: */
625 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof *v, &v[2]);
626 glEnableVertexAttribArray(1);
627
628 for (i = 0, first = 0; i < nfans; i++) {
629 glDrawArrays(GL_TRIANGLE_FAN, first, vtxcnt[i]);
630 if (ec->fan_debug)
631 triangle_fan_debug(es, first, vtxcnt[i]);
632 first += vtxcnt[i];
633 }
634
635 glDisableVertexAttribArray(1);
636 glDisableVertexAttribArray(0);
637
638 ec->vertices.size = 0;
639 ec->vtxcnt.size = 0;
640}
641
John Kåre Alsakera95b2d62012-11-13 19:10:21 +0100642static int
643use_output(struct weston_output *output)
644{
645 static int errored;
646 struct gles2_output_state *go = get_output_state(output);
647 struct gles2_renderer *gr = get_renderer(output->compositor);
648 EGLBoolean ret;
649
650 ret = eglMakeCurrent(gr->egl_display, go->egl_surface,
651 go->egl_surface, gr->egl_context);
652
653 if (ret == EGL_FALSE) {
654 if (errored)
655 return -1;
656 errored = 1;
657 weston_log("Failed to make EGL context current.\n");
658 print_egl_error_state();
659 return -1;
660 }
661
662 return 0;
663}
664
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400665static void
John Kåre Alsaker40684142012-11-13 19:10:25 +0100666use_shader(struct gles2_renderer *gr,
667 struct gles2_shader *shader)
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400668{
John Kåre Alsaker40684142012-11-13 19:10:25 +0100669 if (gr->current_shader == shader)
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400670 return;
671
672 glUseProgram(shader->program);
John Kåre Alsaker40684142012-11-13 19:10:25 +0100673 gr->current_shader = shader;
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400674}
675
676static void
John Kåre Alsaker40684142012-11-13 19:10:25 +0100677shader_uniforms(struct gles2_shader *shader,
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400678 struct weston_surface *surface,
679 struct weston_output *output)
680{
681 int i;
John Kåre Alsaker878f4492012-11-13 19:10:23 +0100682 struct gles2_surface_state *gs = get_surface_state(surface);
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400683
684 glUniformMatrix4fv(shader->proj_uniform,
685 1, GL_FALSE, output->matrix.d);
John Kåre Alsaker878f4492012-11-13 19:10:23 +0100686 glUniform4fv(shader->color_uniform, 1, gs->color);
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400687 glUniform1f(shader->alpha_uniform, surface->alpha);
688
689 for (i = 0; i < surface->num_textures; i++)
690 glUniform1i(shader->tex_uniforms[i], i);
691}
692
693static void
694draw_surface(struct weston_surface *es, struct weston_output *output,
695 pixman_region32_t *damage) /* in global coordinates */
696{
697 struct weston_compositor *ec = es->compositor;
John Kåre Alsaker40684142012-11-13 19:10:25 +0100698 struct gles2_renderer *gr = get_renderer(ec);
699 struct gles2_surface_state *gs = get_surface_state(es);
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400700 /* repaint bounding region in global coordinates: */
701 pixman_region32_t repaint;
702 /* non-opaque region in surface coordinates: */
703 pixman_region32_t surface_blend;
Ander Conselvan de Oliveira8ea818f2012-09-14 16:12:03 +0300704 pixman_region32_t *buffer_damage;
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400705 GLint filter;
706 int i;
707
708 pixman_region32_init(&repaint);
709 pixman_region32_intersect(&repaint,
710 &es->transform.boundingbox, damage);
711 pixman_region32_subtract(&repaint, &repaint, &es->clip);
712
713 if (!pixman_region32_not_empty(&repaint))
714 goto out;
715
Ander Conselvan de Oliveira8ea818f2012-09-14 16:12:03 +0300716 buffer_damage = &output->buffer_damage[output->current_buffer];
717 pixman_region32_subtract(buffer_damage, buffer_damage, &repaint);
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400718
719 glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
720
721 if (ec->fan_debug) {
John Kåre Alsaker40684142012-11-13 19:10:25 +0100722 use_shader(gr, &gr->solid_shader);
723 shader_uniforms(&gr->solid_shader, es, output);
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400724 }
725
John Kåre Alsaker40684142012-11-13 19:10:25 +0100726 use_shader(gr, gs->shader);
727 shader_uniforms(gs->shader, es, output);
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400728
729 if (es->transform.enabled || output->zoom.active)
730 filter = GL_LINEAR;
731 else
732 filter = GL_NEAREST;
733
734 for (i = 0; i < es->num_textures; i++) {
735 glActiveTexture(GL_TEXTURE0 + i);
736 glBindTexture(es->target, es->textures[i]);
737 glTexParameteri(es->target, GL_TEXTURE_MIN_FILTER, filter);
738 glTexParameteri(es->target, GL_TEXTURE_MAG_FILTER, filter);
739 }
740
741 /* blended region is whole surface minus opaque region: */
742 pixman_region32_init_rect(&surface_blend, 0, 0,
743 es->geometry.width, es->geometry.height);
744 pixman_region32_subtract(&surface_blend, &surface_blend, &es->opaque);
745
746 if (pixman_region32_not_empty(&es->opaque)) {
John Kåre Alsaker40684142012-11-13 19:10:25 +0100747 if (gs->shader == &gr->texture_shader_rgba) {
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400748 /* Special case for RGBA textures with possibly
749 * bad data in alpha channel: use the shader
750 * that forces texture alpha = 1.0.
751 * Xwayland surfaces need this.
752 */
John Kåre Alsaker40684142012-11-13 19:10:25 +0100753 use_shader(gr, &gr->texture_shader_rgbx);
754 shader_uniforms(&gr->texture_shader_rgbx, es, output);
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400755 }
756
757 if (es->alpha < 1.0)
758 glEnable(GL_BLEND);
759 else
760 glDisable(GL_BLEND);
761
762 repaint_region(es, &repaint, &es->opaque);
763 }
764
765 if (pixman_region32_not_empty(&surface_blend)) {
John Kåre Alsaker40684142012-11-13 19:10:25 +0100766 use_shader(gr, gs->shader);
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400767 glEnable(GL_BLEND);
768 repaint_region(es, &repaint, &surface_blend);
769 }
770
771 pixman_region32_fini(&surface_blend);
772
773out:
774 pixman_region32_fini(&repaint);
775}
776
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400777static void
778repaint_surfaces(struct weston_output *output, pixman_region32_t *damage)
779{
780 struct weston_compositor *compositor = output->compositor;
781 struct weston_surface *surface;
782
783 wl_list_for_each_reverse(surface, &compositor->surface_list, link)
784 if (surface->plane == &compositor->primary_plane)
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400785 draw_surface(surface, output, damage);
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400786}
787
John Kåre Alsaker44154502012-11-13 19:10:20 +0100788
789static int
790texture_border(struct weston_output *output)
791{
792 struct weston_compositor *ec = output->compositor;
793 struct gles2_renderer *gr = get_renderer(ec);
794 GLfloat *d;
795 unsigned int *p;
796 int i, j, k, n;
797 GLfloat x[4], y[4], u[4], v[4];
798
799 x[0] = -gr->border.left;
800 x[1] = 0;
801 x[2] = output->current->width;
802 x[3] = output->current->width + gr->border.right;
803
804 y[0] = -gr->border.top;
805 y[1] = 0;
806 y[2] = output->current->height;
807 y[3] = output->current->height + gr->border.bottom;
808
809 u[0] = 0.0;
810 u[1] = (GLfloat) gr->border.left / gr->border.width;
811 u[2] = (GLfloat) (gr->border.width - gr->border.right) / gr->border.width;
812 u[3] = 1.0;
813
814 v[0] = 0.0;
815 v[1] = (GLfloat) gr->border.top / gr->border.height;
816 v[2] = (GLfloat) (gr->border.height - gr->border.bottom) / gr->border.height;
817 v[3] = 1.0;
818
819 n = 8;
820 d = wl_array_add(&ec->vertices, n * 16 * sizeof *d);
821 p = wl_array_add(&ec->indices, n * 6 * sizeof *p);
822
823 k = 0;
824 for (i = 0; i < 3; i++)
825 for (j = 0; j < 3; j++) {
826
827 if (i == 1 && j == 1)
828 continue;
829
830 d[ 0] = x[i];
831 d[ 1] = y[j];
832 d[ 2] = u[i];
833 d[ 3] = v[j];
834
835 d[ 4] = x[i];
836 d[ 5] = y[j + 1];
837 d[ 6] = u[i];
838 d[ 7] = v[j + 1];
839
840 d[ 8] = x[i + 1];
841 d[ 9] = y[j];
842 d[10] = u[i + 1];
843 d[11] = v[j];
844
845 d[12] = x[i + 1];
846 d[13] = y[j + 1];
847 d[14] = u[i + 1];
848 d[15] = v[j + 1];
849
850 p[0] = k + 0;
851 p[1] = k + 1;
852 p[2] = k + 2;
853 p[3] = k + 2;
854 p[4] = k + 1;
855 p[5] = k + 3;
856
857 d += 16;
858 p += 6;
859 k += 4;
860 }
861
862 return k / 4;
863}
864
865static void
866draw_border(struct weston_output *output)
867{
868 struct weston_compositor *ec = output->compositor;
869 struct gles2_renderer *gr = get_renderer(ec);
John Kåre Alsaker40684142012-11-13 19:10:25 +0100870 struct gles2_shader *shader = &gr->texture_shader_rgba;
John Kåre Alsaker44154502012-11-13 19:10:20 +0100871 GLfloat *v;
872 int n;
873
874 glDisable(GL_BLEND);
John Kåre Alsaker40684142012-11-13 19:10:25 +0100875 use_shader(gr, shader);
John Kåre Alsaker44154502012-11-13 19:10:20 +0100876
877 glUniformMatrix4fv(shader->proj_uniform,
878 1, GL_FALSE, output->matrix.d);
879
880 glUniform1i(shader->tex_uniforms[0], 0);
881 glUniform1f(shader->alpha_uniform, 1);
882
883 n = texture_border(output);
884
885 glActiveTexture(GL_TEXTURE0);
886 glBindTexture(GL_TEXTURE_2D, gr->border.texture);
887
888 v = ec->vertices.data;
889 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof *v, &v[0]);
890 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof *v, &v[2]);
891 glEnableVertexAttribArray(0);
892 glEnableVertexAttribArray(1);
893
894 glDrawElements(GL_TRIANGLES, n * 6,
895 GL_UNSIGNED_INT, ec->indices.data);
896
897 glDisableVertexAttribArray(1);
898 glDisableVertexAttribArray(0);
899
900 ec->vertices.size = 0;
901 ec->indices.size = 0;
902}
903
Kristian Høgsbergfa1be022012-09-05 22:49:55 -0400904static void
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400905gles2_renderer_repaint_output(struct weston_output *output,
906 pixman_region32_t *output_damage)
907{
John Kåre Alsaker94659272012-11-13 19:10:18 +0100908 struct gles2_output_state *go = get_output_state(output);
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400909 struct weston_compositor *compositor = output->compositor;
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +0100910 struct gles2_renderer *gr = get_renderer(compositor);
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400911 EGLBoolean ret;
912 static int errored;
Ander Conselvan de Oliveira8ea818f2012-09-14 16:12:03 +0300913 int32_t width, height, i;
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400914
915 width = output->current->width +
916 output->border.left + output->border.right;
917 height = output->current->height +
918 output->border.top + output->border.bottom;
919
920 glViewport(0, 0, width, height);
921
John Kåre Alsakera95b2d62012-11-13 19:10:21 +0100922 if (use_output(output) < 0)
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400923 return;
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400924
925 /* if debugging, redraw everything outside the damage to clean up
926 * debug lines from the previous draw on this buffer:
927 */
928 if (compositor->fan_debug) {
929 pixman_region32_t undamaged;
930 pixman_region32_init(&undamaged);
931 pixman_region32_subtract(&undamaged, &output->region,
932 output_damage);
933 compositor->fan_debug = 0;
934 repaint_surfaces(output, &undamaged);
935 compositor->fan_debug = 1;
936 pixman_region32_fini(&undamaged);
937 }
938
Ander Conselvan de Oliveira8ea818f2012-09-14 16:12:03 +0300939 for (i = 0; i < 2; i++)
940 pixman_region32_union(&output->buffer_damage[i],
941 &output->buffer_damage[i],
942 output_damage);
943
944 pixman_region32_union(output_damage, output_damage,
945 &output->buffer_damage[output->current_buffer]);
946
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400947 repaint_surfaces(output, output_damage);
948
John Kåre Alsaker44154502012-11-13 19:10:20 +0100949 if (gr->border.texture)
950 draw_border(output);
951
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400952 wl_signal_emit(&output->frame_signal, output);
953
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +0100954 ret = eglSwapBuffers(gr->egl_display, go->egl_surface);
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400955 if (ret == EGL_FALSE && !errored) {
956 errored = 1;
957 weston_log("Failed in eglSwapBuffers.\n");
958 print_egl_error_state();
959 }
960
Ander Conselvan de Oliveira8ea818f2012-09-14 16:12:03 +0300961 output->current_buffer ^= 1;
962
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400963}
Kristian Høgsberg25894fc2012-09-05 22:06:26 -0400964
John Kåre Alsakera95b2d62012-11-13 19:10:21 +0100965static int
966gles2_renderer_read_pixels(struct weston_output *output,
967 pixman_format_code_t format, void *pixels,
968 uint32_t x, uint32_t y,
969 uint32_t width, uint32_t height)
970{
971 GLenum gl_format;
972
973 switch (format) {
974 case PIXMAN_a8r8g8b8:
975 gl_format = GL_BGRA_EXT;
976 break;
977 case PIXMAN_a8b8g8r8:
978 gl_format = GL_RGBA;
979 break;
980 default:
981 return -1;
982 }
983
984 if (use_output(output) < 0)
985 return -1;
986
987 glPixelStorei(GL_PACK_ALIGNMENT, 1);
988 glReadPixels(x, y, width, height, gl_format,
989 GL_UNSIGNED_BYTE, pixels);
990
991 return 0;
992}
993
Kristian Høgsbergfa1be022012-09-05 22:49:55 -0400994static void
Kristian Høgsbergb1fd2d62012-09-05 22:13:58 -0400995gles2_renderer_flush_damage(struct weston_surface *surface)
996{
997#ifdef GL_UNPACK_ROW_LENGTH
998 pixman_box32_t *rectangles;
999 void *data;
1000 int i, n;
1001#endif
1002
Pekka Paalanenbcdd5792012-11-07 12:25:13 +02001003 pixman_region32_union(&surface->texture_damage,
1004 &surface->texture_damage, &surface->damage);
1005
1006 /* Avoid upload, if the texture won't be used this time.
1007 * We still accumulate the damage in texture_damage.
1008 */
1009 if (surface->plane != &surface->compositor->primary_plane)
1010 return;
1011
1012 if (!pixman_region32_not_empty(&surface->texture_damage))
1013 return;
1014
Kristian Høgsbergb1fd2d62012-09-05 22:13:58 -04001015 glBindTexture(GL_TEXTURE_2D, surface->textures[0]);
1016
1017 if (!surface->compositor->has_unpack_subimage) {
1018 glTexImage2D(GL_TEXTURE_2D, 0, GL_BGRA_EXT,
1019 surface->pitch, surface->buffer->height, 0,
1020 GL_BGRA_EXT, GL_UNSIGNED_BYTE,
1021 wl_shm_buffer_get_data(surface->buffer));
1022
Pekka Paalanenbcdd5792012-11-07 12:25:13 +02001023 goto done;
Kristian Høgsbergb1fd2d62012-09-05 22:13:58 -04001024 }
1025
1026#ifdef GL_UNPACK_ROW_LENGTH
1027 /* Mesa does not define GL_EXT_unpack_subimage */
1028 glPixelStorei(GL_UNPACK_ROW_LENGTH, surface->pitch);
1029 data = wl_shm_buffer_get_data(surface->buffer);
Pekka Paalanenbcdd5792012-11-07 12:25:13 +02001030 rectangles = pixman_region32_rectangles(&surface->texture_damage, &n);
Kristian Høgsbergb1fd2d62012-09-05 22:13:58 -04001031 for (i = 0; i < n; i++) {
1032 glPixelStorei(GL_UNPACK_SKIP_PIXELS, rectangles[i].x1);
1033 glPixelStorei(GL_UNPACK_SKIP_ROWS, rectangles[i].y1);
1034 glTexSubImage2D(GL_TEXTURE_2D, 0,
1035 rectangles[i].x1, rectangles[i].y1,
1036 rectangles[i].x2 - rectangles[i].x1,
1037 rectangles[i].y2 - rectangles[i].y1,
1038 GL_BGRA_EXT, GL_UNSIGNED_BYTE, data);
1039 }
1040#endif
Pekka Paalanenbcdd5792012-11-07 12:25:13 +02001041
1042done:
1043 pixman_region32_fini(&surface->texture_damage);
1044 pixman_region32_init(&surface->texture_damage);
Kristian Høgsbergb1fd2d62012-09-05 22:13:58 -04001045}
1046
Kristian Høgsbergb7b77e62012-09-05 22:38:18 -04001047static void
1048ensure_textures(struct weston_surface *es, int num_textures)
1049{
1050 int i;
1051
1052 if (num_textures <= es->num_textures)
1053 return;
1054
1055 for (i = es->num_textures; i < num_textures; i++) {
1056 glGenTextures(1, &es->textures[i]);
1057 glBindTexture(es->target, es->textures[i]);
1058 glTexParameteri(es->target,
1059 GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1060 glTexParameteri(es->target,
1061 GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1062 }
1063 es->num_textures = num_textures;
1064 glBindTexture(es->target, 0);
1065}
1066
Kristian Høgsbergfa1be022012-09-05 22:49:55 -04001067static void
Kristian Høgsbergb7b77e62012-09-05 22:38:18 -04001068gles2_renderer_attach(struct weston_surface *es, struct wl_buffer *buffer)
1069{
1070 struct weston_compositor *ec = es->compositor;
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001071 struct gles2_renderer *gr = get_renderer(ec);
John Kåre Alsaker40684142012-11-13 19:10:25 +01001072 struct gles2_surface_state *gs = get_surface_state(es);
Kristian Høgsbergb7b77e62012-09-05 22:38:18 -04001073 EGLint attribs[3], format;
1074 int i, num_planes;
1075
1076 if (!buffer) {
1077 for (i = 0; i < es->num_images; i++) {
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001078 ec->destroy_image(gr->egl_display, es->images[i]);
Kristian Høgsbergb7b77e62012-09-05 22:38:18 -04001079 es->images[i] = NULL;
1080 }
1081 es->num_images = 0;
1082 glDeleteTextures(es->num_textures, es->textures);
1083 es->num_textures = 0;
1084 return;
1085 }
1086
1087 if (wl_buffer_is_shm(buffer)) {
1088 es->pitch = wl_shm_buffer_get_stride(buffer) / 4;
1089 es->target = GL_TEXTURE_2D;
1090
1091 ensure_textures(es, 1);
1092 glBindTexture(GL_TEXTURE_2D, es->textures[0]);
1093 glTexImage2D(GL_TEXTURE_2D, 0, GL_BGRA_EXT,
1094 es->pitch, buffer->height, 0,
1095 GL_BGRA_EXT, GL_UNSIGNED_BYTE, NULL);
1096 if (wl_shm_buffer_get_format(buffer) == WL_SHM_FORMAT_XRGB8888)
John Kåre Alsaker40684142012-11-13 19:10:25 +01001097 gs->shader = &gr->texture_shader_rgbx;
Kristian Høgsbergb7b77e62012-09-05 22:38:18 -04001098 else
John Kåre Alsaker40684142012-11-13 19:10:25 +01001099 gs->shader = &gr->texture_shader_rgba;
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001100 } else if (ec->query_buffer(gr->egl_display, buffer,
Kristian Høgsbergb7b77e62012-09-05 22:38:18 -04001101 EGL_TEXTURE_FORMAT, &format)) {
1102 for (i = 0; i < es->num_images; i++)
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001103 ec->destroy_image(gr->egl_display, es->images[i]);
Kristian Høgsbergb7b77e62012-09-05 22:38:18 -04001104 es->num_images = 0;
1105 es->target = GL_TEXTURE_2D;
1106 switch (format) {
1107 case EGL_TEXTURE_RGB:
1108 case EGL_TEXTURE_RGBA:
1109 default:
1110 num_planes = 1;
John Kåre Alsaker40684142012-11-13 19:10:25 +01001111 gs->shader = &gr->texture_shader_rgba;
Kristian Høgsbergb7b77e62012-09-05 22:38:18 -04001112 break;
1113 case EGL_TEXTURE_EXTERNAL_WL:
1114 num_planes = 1;
1115 es->target = GL_TEXTURE_EXTERNAL_OES;
John Kåre Alsaker40684142012-11-13 19:10:25 +01001116 gs->shader = &gr->texture_shader_egl_external;
Kristian Høgsbergb7b77e62012-09-05 22:38:18 -04001117 break;
1118 case EGL_TEXTURE_Y_UV_WL:
1119 num_planes = 2;
John Kåre Alsaker40684142012-11-13 19:10:25 +01001120 gs->shader = &gr->texture_shader_y_uv;
Kristian Høgsbergb7b77e62012-09-05 22:38:18 -04001121 break;
1122 case EGL_TEXTURE_Y_U_V_WL:
1123 num_planes = 3;
John Kåre Alsaker40684142012-11-13 19:10:25 +01001124 gs->shader = &gr->texture_shader_y_u_v;
Kristian Høgsbergb7b77e62012-09-05 22:38:18 -04001125 break;
1126 case EGL_TEXTURE_Y_XUXV_WL:
1127 num_planes = 2;
John Kåre Alsaker40684142012-11-13 19:10:25 +01001128 gs->shader = &gr->texture_shader_y_xuxv;
Kristian Høgsbergb7b77e62012-09-05 22:38:18 -04001129 break;
1130 }
1131
1132 ensure_textures(es, num_planes);
1133 for (i = 0; i < num_planes; i++) {
1134 attribs[0] = EGL_WAYLAND_PLANE_WL;
1135 attribs[1] = i;
1136 attribs[2] = EGL_NONE;
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001137 es->images[i] = ec->create_image(gr->egl_display,
Kristian Høgsbergb7b77e62012-09-05 22:38:18 -04001138 NULL,
1139 EGL_WAYLAND_BUFFER_WL,
1140 buffer, attribs);
1141 if (!es->images[i]) {
1142 weston_log("failed to create img for plane %d\n", i);
1143 continue;
1144 }
1145 es->num_images++;
1146
1147 glActiveTexture(GL_TEXTURE0 + i);
1148 glBindTexture(es->target, es->textures[i]);
1149 ec->image_target_texture_2d(es->target,
1150 es->images[i]);
1151 }
1152
1153 es->pitch = buffer->width;
1154 } else {
1155 weston_log("unhandled buffer type!\n");
1156 }
1157}
1158
Kristian Høgsberg42263852012-09-06 21:59:29 -04001159static void
John Kåre Alsaker878f4492012-11-13 19:10:23 +01001160gles2_renderer_surface_set_color(struct weston_surface *surface,
1161 float red, float green, float blue, float alpha)
1162{
1163 struct gles2_surface_state *gs = get_surface_state(surface);
John Kåre Alsaker40684142012-11-13 19:10:25 +01001164 struct gles2_renderer *gr = get_renderer(surface->compositor);
John Kåre Alsaker878f4492012-11-13 19:10:23 +01001165
1166 gs->color[0] = red;
1167 gs->color[1] = green;
1168 gs->color[2] = blue;
1169 gs->color[3] = alpha;
1170
John Kåre Alsaker40684142012-11-13 19:10:25 +01001171 gs->shader = &gr->solid_shader;
John Kåre Alsaker878f4492012-11-13 19:10:23 +01001172}
1173
1174static int
1175gles2_renderer_create_surface(struct weston_surface *surface)
1176{
1177 struct gles2_surface_state *gs;
1178
1179 gs = calloc(1, sizeof *gs);
1180
1181 if (!gs)
1182 return -1;
1183
1184 surface->renderer_state = gs;
1185
1186 return 0;
1187}
1188
1189static void
Kristian Høgsberg42263852012-09-06 21:59:29 -04001190gles2_renderer_destroy_surface(struct weston_surface *surface)
1191{
John Kåre Alsaker878f4492012-11-13 19:10:23 +01001192 struct gles2_surface_state *gs = get_surface_state(surface);
Kristian Høgsberg42263852012-09-06 21:59:29 -04001193 struct weston_compositor *ec = surface->compositor;
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001194 struct gles2_renderer *gr = get_renderer(ec);
Kristian Høgsberg42263852012-09-06 21:59:29 -04001195 int i;
1196
1197 glDeleteTextures(surface->num_textures, surface->textures);
1198
1199 for (i = 0; i < surface->num_images; i++)
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001200 ec->destroy_image(gr->egl_display, surface->images[i]);
John Kåre Alsaker878f4492012-11-13 19:10:23 +01001201
1202 free(gs);
Kristian Høgsberg42263852012-09-06 21:59:29 -04001203}
1204
Kristian Høgsberg25894fc2012-09-05 22:06:26 -04001205static const char vertex_shader[] =
1206 "uniform mat4 proj;\n"
1207 "attribute vec2 position;\n"
1208 "attribute vec2 texcoord;\n"
1209 "varying vec2 v_texcoord;\n"
1210 "void main()\n"
1211 "{\n"
1212 " gl_Position = proj * vec4(position, 0.0, 1.0);\n"
1213 " v_texcoord = texcoord;\n"
1214 "}\n";
1215
1216/* Declare common fragment shader uniforms */
1217#define FRAGMENT_CONVERT_YUV \
1218 " y *= alpha;\n" \
1219 " u *= alpha;\n" \
1220 " v *= alpha;\n" \
1221 " gl_FragColor.r = y + 1.59602678 * v;\n" \
1222 " gl_FragColor.g = y - 0.39176229 * u - 0.81296764 * v;\n" \
1223 " gl_FragColor.b = y + 2.01723214 * u;\n" \
1224 " gl_FragColor.a = alpha;\n"
1225
Ander Conselvan de Oliveira27508c22012-11-08 17:20:46 +02001226static const char fragment_debug[] =
1227 " gl_FragColor = vec4(0.0, 0.3, 0.0, 0.2) + gl_FragColor * 0.8;\n";
1228
1229static const char fragment_brace[] =
1230 "}\n";
1231
Kristian Høgsberg25894fc2012-09-05 22:06:26 -04001232static const char texture_fragment_shader_rgba[] =
1233 "precision mediump float;\n"
1234 "varying vec2 v_texcoord;\n"
1235 "uniform sampler2D tex;\n"
1236 "uniform float alpha;\n"
1237 "void main()\n"
1238 "{\n"
1239 " gl_FragColor = alpha * texture2D(tex, v_texcoord)\n;"
Ander Conselvan de Oliveira27508c22012-11-08 17:20:46 +02001240 ;
Kristian Høgsberg25894fc2012-09-05 22:06:26 -04001241
1242static const char texture_fragment_shader_rgbx[] =
1243 "precision mediump float;\n"
1244 "varying vec2 v_texcoord;\n"
1245 "uniform sampler2D tex;\n"
1246 "uniform float alpha;\n"
1247 "void main()\n"
1248 "{\n"
1249 " gl_FragColor.rgb = alpha * texture2D(tex, v_texcoord).rgb\n;"
1250 " gl_FragColor.a = alpha;\n"
Ander Conselvan de Oliveira27508c22012-11-08 17:20:46 +02001251 ;
Kristian Høgsberg25894fc2012-09-05 22:06:26 -04001252
1253static const char texture_fragment_shader_egl_external[] =
1254 "#extension GL_OES_EGL_image_external : require\n"
1255 "precision mediump float;\n"
1256 "varying vec2 v_texcoord;\n"
1257 "uniform samplerExternalOES tex;\n"
1258 "uniform float alpha;\n"
1259 "void main()\n"
1260 "{\n"
1261 " gl_FragColor = alpha * texture2D(tex, v_texcoord)\n;"
Ander Conselvan de Oliveira27508c22012-11-08 17:20:46 +02001262 ;
Kristian Høgsberg25894fc2012-09-05 22:06:26 -04001263
1264static const char texture_fragment_shader_y_uv[] =
1265 "precision mediump float;\n"
1266 "uniform sampler2D tex;\n"
1267 "uniform sampler2D tex1;\n"
1268 "varying vec2 v_texcoord;\n"
1269 "uniform float alpha;\n"
1270 "void main() {\n"
1271 " float y = 1.16438356 * (texture2D(tex, v_texcoord).x - 0.0625);\n"
1272 " float u = texture2D(tex1, v_texcoord).r - 0.5;\n"
1273 " float v = texture2D(tex1, v_texcoord).g - 0.5;\n"
1274 FRAGMENT_CONVERT_YUV
Ander Conselvan de Oliveira27508c22012-11-08 17:20:46 +02001275 ;
Kristian Høgsberg25894fc2012-09-05 22:06:26 -04001276
1277static const char texture_fragment_shader_y_u_v[] =
1278 "precision mediump float;\n"
1279 "uniform sampler2D tex;\n"
1280 "uniform sampler2D tex1;\n"
1281 "uniform sampler2D tex2;\n"
1282 "varying vec2 v_texcoord;\n"
1283 "uniform float alpha;\n"
1284 "void main() {\n"
1285 " float y = 1.16438356 * (texture2D(tex, v_texcoord).x - 0.0625);\n"
1286 " float u = texture2D(tex1, v_texcoord).x - 0.5;\n"
1287 " float v = texture2D(tex2, v_texcoord).x - 0.5;\n"
1288 FRAGMENT_CONVERT_YUV
Ander Conselvan de Oliveira27508c22012-11-08 17:20:46 +02001289 ;
Kristian Høgsberg25894fc2012-09-05 22:06:26 -04001290
1291static const char texture_fragment_shader_y_xuxv[] =
1292 "precision mediump float;\n"
1293 "uniform sampler2D tex;\n"
1294 "uniform sampler2D tex1;\n"
1295 "varying vec2 v_texcoord;\n"
1296 "uniform float alpha;\n"
1297 "void main() {\n"
1298 " float y = 1.16438356 * (texture2D(tex, v_texcoord).x - 0.0625);\n"
1299 " float u = texture2D(tex1, v_texcoord).g - 0.5;\n"
1300 " float v = texture2D(tex1, v_texcoord).a - 0.5;\n"
1301 FRAGMENT_CONVERT_YUV
Ander Conselvan de Oliveira27508c22012-11-08 17:20:46 +02001302 ;
Kristian Høgsberg25894fc2012-09-05 22:06:26 -04001303
1304static const char solid_fragment_shader[] =
1305 "precision mediump float;\n"
1306 "uniform vec4 color;\n"
1307 "uniform float alpha;\n"
1308 "void main()\n"
1309 "{\n"
1310 " gl_FragColor = alpha * color\n;"
Ander Conselvan de Oliveira27508c22012-11-08 17:20:46 +02001311 ;
Kristian Høgsberg25894fc2012-09-05 22:06:26 -04001312
1313static int
Ander Conselvan de Oliveira27508c22012-11-08 17:20:46 +02001314compile_shader(GLenum type, int count, const char **sources)
Kristian Høgsberg25894fc2012-09-05 22:06:26 -04001315{
1316 GLuint s;
1317 char msg[512];
1318 GLint status;
1319
1320 s = glCreateShader(type);
Ander Conselvan de Oliveira27508c22012-11-08 17:20:46 +02001321 glShaderSource(s, count, sources, NULL);
Kristian Høgsberg25894fc2012-09-05 22:06:26 -04001322 glCompileShader(s);
1323 glGetShaderiv(s, GL_COMPILE_STATUS, &status);
1324 if (!status) {
1325 glGetShaderInfoLog(s, sizeof msg, NULL, msg);
1326 weston_log("shader info: %s\n", msg);
1327 return GL_NONE;
1328 }
1329
1330 return s;
1331}
1332
1333static int
John Kåre Alsaker40684142012-11-13 19:10:25 +01001334shader_init(struct gles2_shader *shader, struct weston_compositor *ec,
Kristian Høgsberg25894fc2012-09-05 22:06:26 -04001335 const char *vertex_source, const char *fragment_source)
1336{
1337 char msg[512];
1338 GLint status;
Ander Conselvan de Oliveira27508c22012-11-08 17:20:46 +02001339 int count;
1340 const char *sources[3];
1341 struct gles2_renderer *renderer =
1342 (struct gles2_renderer *) ec->renderer;
Kristian Høgsberg25894fc2012-09-05 22:06:26 -04001343
1344 shader->vertex_shader =
Ander Conselvan de Oliveira27508c22012-11-08 17:20:46 +02001345 compile_shader(GL_VERTEX_SHADER, 1, &vertex_source);
1346
1347 if (renderer->fragment_shader_debug) {
1348 sources[0] = fragment_source;
1349 sources[1] = fragment_debug;
1350 sources[2] = fragment_brace;
1351 count = 3;
1352 } else {
1353 sources[0] = fragment_source;
1354 sources[1] = fragment_brace;
1355 count = 2;
1356 }
1357
Kristian Høgsberg25894fc2012-09-05 22:06:26 -04001358 shader->fragment_shader =
Ander Conselvan de Oliveira27508c22012-11-08 17:20:46 +02001359 compile_shader(GL_FRAGMENT_SHADER, count, sources);
Kristian Høgsberg25894fc2012-09-05 22:06:26 -04001360
1361 shader->program = glCreateProgram();
1362 glAttachShader(shader->program, shader->vertex_shader);
1363 glAttachShader(shader->program, shader->fragment_shader);
1364 glBindAttribLocation(shader->program, 0, "position");
1365 glBindAttribLocation(shader->program, 1, "texcoord");
1366
1367 glLinkProgram(shader->program);
1368 glGetProgramiv(shader->program, GL_LINK_STATUS, &status);
1369 if (!status) {
1370 glGetProgramInfoLog(shader->program, sizeof msg, NULL, msg);
1371 weston_log("link info: %s\n", msg);
1372 return -1;
1373 }
1374
1375 shader->proj_uniform = glGetUniformLocation(shader->program, "proj");
1376 shader->tex_uniforms[0] = glGetUniformLocation(shader->program, "tex");
1377 shader->tex_uniforms[1] = glGetUniformLocation(shader->program, "tex1");
1378 shader->tex_uniforms[2] = glGetUniformLocation(shader->program, "tex2");
1379 shader->alpha_uniform = glGetUniformLocation(shader->program, "alpha");
1380 shader->color_uniform = glGetUniformLocation(shader->program, "color");
1381
1382 return 0;
1383}
1384
1385static void
John Kåre Alsaker40684142012-11-13 19:10:25 +01001386shader_release(struct gles2_shader *shader)
Ander Conselvan de Oliveira27508c22012-11-08 17:20:46 +02001387{
1388 glDeleteShader(shader->vertex_shader);
1389 glDeleteShader(shader->fragment_shader);
1390 glDeleteProgram(shader->program);
1391
1392 shader->vertex_shader = 0;
1393 shader->fragment_shader = 0;
1394 shader->program = 0;
1395}
1396
1397static void
Kristian Høgsberg25894fc2012-09-05 22:06:26 -04001398log_extensions(const char *name, const char *extensions)
1399{
1400 const char *p, *end;
1401 int l;
1402 int len;
1403
1404 l = weston_log("%s:", name);
1405 p = extensions;
1406 while (*p) {
1407 end = strchrnul(p, ' ');
1408 len = end - p;
1409 if (l + len > 78)
1410 l = weston_log_continue("\n" STAMP_SPACE "%.*s",
1411 len, p);
1412 else
1413 l += weston_log_continue(" %.*s", len, p);
1414 for (p = end; isspace(*p); p++)
1415 ;
1416 }
1417 weston_log_continue("\n");
1418}
1419
1420static void
1421log_egl_gl_info(EGLDisplay egldpy)
1422{
1423 const char *str;
1424
1425 str = eglQueryString(egldpy, EGL_VERSION);
1426 weston_log("EGL version: %s\n", str ? str : "(null)");
1427
1428 str = eglQueryString(egldpy, EGL_VENDOR);
1429 weston_log("EGL vendor: %s\n", str ? str : "(null)");
1430
1431 str = eglQueryString(egldpy, EGL_CLIENT_APIS);
1432 weston_log("EGL client APIs: %s\n", str ? str : "(null)");
1433
1434 str = eglQueryString(egldpy, EGL_EXTENSIONS);
1435 log_extensions("EGL extensions", str ? str : "(null)");
1436
1437 str = (char *)glGetString(GL_VERSION);
1438 weston_log("GL version: %s\n", str ? str : "(null)");
1439
1440 str = (char *)glGetString(GL_SHADING_LANGUAGE_VERSION);
1441 weston_log("GLSL version: %s\n", str ? str : "(null)");
1442
1443 str = (char *)glGetString(GL_VENDOR);
1444 weston_log("GL vendor: %s\n", str ? str : "(null)");
1445
1446 str = (char *)glGetString(GL_RENDERER);
1447 weston_log("GL renderer: %s\n", str ? str : "(null)");
1448
1449 str = (char *)glGetString(GL_EXTENSIONS);
1450 log_extensions("GL extensions", str ? str : "(null)");
1451}
1452
Pekka Paalanen9c3fe252012-10-24 09:43:05 +03001453static void
1454log_egl_config_info(EGLDisplay egldpy, EGLConfig eglconfig)
1455{
1456 EGLint r, g, b, a;
1457
1458 weston_log("Chosen EGL config details:\n");
1459
1460 weston_log_continue(STAMP_SPACE "RGBA bits");
1461 if (eglGetConfigAttrib(egldpy, eglconfig, EGL_RED_SIZE, &r) &&
1462 eglGetConfigAttrib(egldpy, eglconfig, EGL_GREEN_SIZE, &g) &&
1463 eglGetConfigAttrib(egldpy, eglconfig, EGL_BLUE_SIZE, &b) &&
1464 eglGetConfigAttrib(egldpy, eglconfig, EGL_ALPHA_SIZE, &a))
1465 weston_log_continue(": %d %d %d %d\n", r, g, b, a);
1466 else
1467 weston_log_continue(" unknown\n");
1468
1469 weston_log_continue(STAMP_SPACE "swap interval range");
1470 if (eglGetConfigAttrib(egldpy, eglconfig, EGL_MIN_SWAP_INTERVAL, &a) &&
1471 eglGetConfigAttrib(egldpy, eglconfig, EGL_MAX_SWAP_INTERVAL, &b))
1472 weston_log_continue(": %d - %d\n", a, b);
1473 else
1474 weston_log_continue(" unknown\n");
1475}
1476
John Kåre Alsaker44154502012-11-13 19:10:20 +01001477static void
1478output_apply_border(struct weston_output *output, struct gles2_renderer *gr)
1479{
1480 output->border.top = gr->border.top;
1481 output->border.bottom = gr->border.bottom;
1482 output->border.left = gr->border.left;
1483 output->border.right = gr->border.right;
1484}
1485
1486WL_EXPORT void
1487gles2_renderer_set_border(struct weston_compositor *ec, int32_t width, int32_t height, void *data,
1488 int32_t *edges)
1489{
1490 struct gles2_renderer *gr = get_renderer(ec);
1491 struct weston_output *output;
1492
1493 gr->border.left = edges[0];
1494 gr->border.right = edges[1];
1495 gr->border.top = edges[2];
1496 gr->border.bottom = edges[3];
1497
1498 gr->border.width = width;
1499 gr->border.height = height;
1500
1501 glGenTextures(1, &gr->border.texture);
1502 glBindTexture(GL_TEXTURE_2D, gr->border.texture);
1503 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1504 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1505 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1506 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1507
1508 glTexImage2D(GL_TEXTURE_2D, 0, GL_BGRA_EXT,
1509 width,
1510 height,
1511 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE,
1512 data);
1513
1514 wl_list_for_each(output, &ec->output_list, link)
1515 output_apply_border(output, gr);
1516}
1517
John Kåre Alsaker94659272012-11-13 19:10:18 +01001518static int
1519gles2_renderer_setup(struct weston_compositor *ec, EGLSurface egl_surface);
1520
1521WL_EXPORT int
1522gles2_renderer_output_create(struct weston_output *output,
1523 EGLNativeWindowType window)
1524{
1525 struct weston_compositor *ec = output->compositor;
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001526 struct gles2_renderer *gr = get_renderer(ec);
John Kåre Alsaker94659272012-11-13 19:10:18 +01001527 struct gles2_output_state *go = calloc(1, sizeof *go);
1528
1529 if (!go)
1530 return -1;
1531
1532 go->egl_surface =
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001533 eglCreateWindowSurface(gr->egl_display,
1534 gr->egl_config,
John Kåre Alsaker94659272012-11-13 19:10:18 +01001535 window, NULL);
1536
1537 if (go->egl_surface == EGL_NO_SURFACE) {
1538 weston_log("failed to create egl surface\n");
1539 free(go);
1540 return -1;
1541 }
1542
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001543 if (gr->egl_context == NULL)
John Kåre Alsaker94659272012-11-13 19:10:18 +01001544 if (gles2_renderer_setup(ec, go->egl_surface) < 0) {
1545 free(go);
1546 return -1;
1547 }
1548
1549 output->renderer_state = go;
1550
John Kåre Alsaker44154502012-11-13 19:10:20 +01001551 output_apply_border(output, gr);
1552
John Kåre Alsaker94659272012-11-13 19:10:18 +01001553 return 0;
1554}
1555
1556WL_EXPORT void
1557gles2_renderer_output_destroy(struct weston_output *output)
1558{
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001559 struct gles2_renderer *gr = get_renderer(output->compositor);
John Kåre Alsaker94659272012-11-13 19:10:18 +01001560 struct gles2_output_state *go = get_output_state(output);
1561
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001562 eglDestroySurface(gr->egl_display, go->egl_surface);
John Kåre Alsaker94659272012-11-13 19:10:18 +01001563
1564 free(go);
1565}
1566
1567WL_EXPORT EGLSurface
1568gles2_renderer_output_surface(struct weston_output *output)
1569{
1570 return get_output_state(output)->egl_surface;
1571}
1572
Kristian Høgsberg3a0de882012-09-06 21:44:24 -04001573WL_EXPORT void
1574gles2_renderer_destroy(struct weston_compositor *ec)
1575{
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001576 struct gles2_renderer *gr = get_renderer(ec);
1577
Kristian Høgsberg3a0de882012-09-06 21:44:24 -04001578 if (ec->has_bind_display)
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001579 ec->unbind_display(gr->egl_display, ec->wl_display);
1580
1581 /* Work around crash in egl_dri2.c's dri2_make_current() - when does this apply? */
1582 eglMakeCurrent(gr->egl_display,
1583 EGL_NO_SURFACE, EGL_NO_SURFACE,
1584 EGL_NO_CONTEXT);
1585
1586 eglTerminate(gr->egl_display);
1587 eglReleaseThread();
1588}
1589
1590static int
1591egl_choose_config(struct gles2_renderer *gr, const EGLint *attribs,
1592 const EGLint *visual_id)
1593{
1594 EGLint count = 0;
1595 EGLint matched = 0;
1596 EGLConfig *configs;
1597 int i;
1598
1599 if (!eglGetConfigs(gr->egl_display, NULL, 0, &count) || count < 1)
1600 return -1;
1601
1602 configs = calloc(count, sizeof *configs);
1603 if (!configs)
1604 return -1;
1605
1606 if (!eglChooseConfig(gr->egl_display, attribs, configs,
1607 count, &matched))
1608 goto out;
1609
1610 for (i = 0; i < matched; ++i) {
1611 EGLint id;
1612
1613 if (visual_id) {
1614 if (!eglGetConfigAttrib(gr->egl_display,
1615 configs[i], EGL_NATIVE_VISUAL_ID,
1616 &id))
1617 continue;
1618
1619 if (id != *visual_id)
1620 continue;
1621 }
1622
1623 gr->egl_config = configs[i];
1624
1625 free(configs);
1626 return 0;
1627 }
1628
1629out:
1630 free(configs);
1631 return -1;
1632}
1633
1634WL_EXPORT const EGLint gles2_renderer_opaque_attribs[] = {
1635 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
1636 EGL_RED_SIZE, 1,
1637 EGL_GREEN_SIZE, 1,
1638 EGL_BLUE_SIZE, 1,
1639 EGL_ALPHA_SIZE, 0,
1640 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
1641 EGL_NONE
1642};
1643
1644WL_EXPORT const EGLint gles2_renderer_alpha_attribs[] = {
1645 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
1646 EGL_RED_SIZE, 1,
1647 EGL_GREEN_SIZE, 1,
1648 EGL_BLUE_SIZE, 1,
1649 EGL_ALPHA_SIZE, 1,
1650 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
1651 EGL_NONE
1652};
1653
1654WL_EXPORT int
1655gles2_renderer_create(struct weston_compositor *ec, EGLNativeDisplayType display,
1656 const EGLint *attribs, const EGLint *visual_id)
1657{
1658 struct gles2_renderer *gr;
1659 EGLint major, minor;
1660
1661 gr = calloc(1, sizeof *gr);
1662
1663 if (gr == NULL)
1664 return -1;
1665
John Kåre Alsakera95b2d62012-11-13 19:10:21 +01001666 gr->base.read_pixels = gles2_renderer_read_pixels;
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001667 gr->base.repaint_output = gles2_renderer_repaint_output;
1668 gr->base.flush_damage = gles2_renderer_flush_damage;
1669 gr->base.attach = gles2_renderer_attach;
John Kåre Alsaker878f4492012-11-13 19:10:23 +01001670 gr->base.create_surface = gles2_renderer_create_surface;
1671 gr->base.surface_set_color = gles2_renderer_surface_set_color;
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001672 gr->base.destroy_surface = gles2_renderer_destroy_surface;
1673
1674 gr->egl_display = eglGetDisplay(display);
1675 if (gr->egl_display == EGL_NO_DISPLAY) {
1676 weston_log("failed to create display\n");
1677 goto err_egl;
1678 }
1679
1680 if (!eglInitialize(gr->egl_display, &major, &minor)) {
1681 weston_log("failed to initialize display\n");
1682 goto err_egl;
1683 }
1684
1685 if (egl_choose_config(gr, attribs, visual_id) < 0) {
1686 weston_log("failed to choose EGL config\n");
1687 goto err_egl;
1688 }
1689
1690 ec->renderer = &gr->base;
1691
1692 return 0;
1693
1694err_egl:
1695 print_egl_error_state();
1696 free(gr);
1697 return -1;
1698}
1699
1700WL_EXPORT EGLDisplay
1701gles2_renderer_display(struct weston_compositor *ec)
1702{
1703 return get_renderer(ec)->egl_display;
Kristian Høgsberg3a0de882012-09-06 21:44:24 -04001704}
1705
Ander Conselvan de Oliveira27508c22012-11-08 17:20:46 +02001706static int
1707compile_shaders(struct weston_compositor *ec)
1708{
John Kåre Alsaker40684142012-11-13 19:10:25 +01001709 struct gles2_renderer *gr = get_renderer(ec);
1710
1711 if (shader_init(&gr->texture_shader_rgba, ec,
Ander Conselvan de Oliveira27508c22012-11-08 17:20:46 +02001712 vertex_shader, texture_fragment_shader_rgba) < 0)
1713 return -1;
John Kåre Alsaker40684142012-11-13 19:10:25 +01001714 if (shader_init(&gr->texture_shader_rgbx, ec,
Ander Conselvan de Oliveira27508c22012-11-08 17:20:46 +02001715 vertex_shader, texture_fragment_shader_rgbx) < 0)
1716 return -1;
1717 if (ec->has_egl_image_external &&
John Kåre Alsaker40684142012-11-13 19:10:25 +01001718 shader_init(&gr->texture_shader_egl_external, ec,
Ander Conselvan de Oliveira27508c22012-11-08 17:20:46 +02001719 vertex_shader, texture_fragment_shader_egl_external) < 0)
1720 return -1;
John Kåre Alsaker40684142012-11-13 19:10:25 +01001721 if (shader_init(&gr->texture_shader_y_uv, ec,
Ander Conselvan de Oliveira27508c22012-11-08 17:20:46 +02001722 vertex_shader, texture_fragment_shader_y_uv) < 0)
1723 return -1;
John Kåre Alsaker40684142012-11-13 19:10:25 +01001724 if (shader_init(&gr->texture_shader_y_u_v, ec,
Ander Conselvan de Oliveira27508c22012-11-08 17:20:46 +02001725 vertex_shader, texture_fragment_shader_y_u_v) < 0)
1726 return -1;
John Kåre Alsaker40684142012-11-13 19:10:25 +01001727 if (shader_init(&gr->texture_shader_y_xuxv, ec,
Ander Conselvan de Oliveira27508c22012-11-08 17:20:46 +02001728 vertex_shader, texture_fragment_shader_y_xuxv) < 0)
1729 return -1;
John Kåre Alsaker40684142012-11-13 19:10:25 +01001730 if (shader_init(&gr->solid_shader, ec,
Ander Conselvan de Oliveira27508c22012-11-08 17:20:46 +02001731 vertex_shader, solid_fragment_shader) < 0)
1732 return -1;
1733
1734 return 0;
1735}
1736
1737static void
1738fragment_debug_binding(struct wl_seat *seat, uint32_t time, uint32_t key,
1739 void *data)
1740{
1741 struct weston_compositor *ec = data;
John Kåre Alsaker40684142012-11-13 19:10:25 +01001742 struct gles2_renderer *gr = get_renderer(ec);
Ander Conselvan de Oliveira27508c22012-11-08 17:20:46 +02001743 struct weston_output *output;
1744
John Kåre Alsaker40684142012-11-13 19:10:25 +01001745 gr->fragment_shader_debug ^= 1;
Ander Conselvan de Oliveira27508c22012-11-08 17:20:46 +02001746
John Kåre Alsaker40684142012-11-13 19:10:25 +01001747 shader_release(&gr->texture_shader_rgba);
1748 shader_release(&gr->texture_shader_rgbx);
1749 shader_release(&gr->texture_shader_egl_external);
1750 shader_release(&gr->texture_shader_y_uv);
1751 shader_release(&gr->texture_shader_y_u_v);
1752 shader_release(&gr->texture_shader_y_xuxv);
1753 shader_release(&gr->solid_shader);
Ander Conselvan de Oliveira27508c22012-11-08 17:20:46 +02001754
1755 compile_shaders(ec);
1756
1757 wl_list_for_each(output, &ec->output_list, link)
1758 weston_output_damage(output);
1759}
1760
John Kåre Alsaker94659272012-11-13 19:10:18 +01001761static int
1762gles2_renderer_setup(struct weston_compositor *ec, EGLSurface egl_surface)
Kristian Høgsberg25894fc2012-09-05 22:06:26 -04001763{
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001764 struct gles2_renderer *gr = get_renderer(ec);
Kristian Høgsberg25894fc2012-09-05 22:06:26 -04001765 const char *extensions;
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04001766 EGLBoolean ret;
Kristian Høgsberg25894fc2012-09-05 22:06:26 -04001767
Kristian Høgsberg9793fc72012-09-06 21:07:40 -04001768 static const EGLint context_attribs[] = {
1769 EGL_CONTEXT_CLIENT_VERSION, 2,
1770 EGL_NONE
1771 };
1772
Kristian Høgsberg9793fc72012-09-06 21:07:40 -04001773 if (!eglBindAPI(EGL_OPENGL_ES_API)) {
1774 weston_log("failed to bind EGL_OPENGL_ES_API\n");
1775 print_egl_error_state();
1776 return -1;
1777 }
Pekka Paalanen9c3fe252012-10-24 09:43:05 +03001778
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001779 log_egl_config_info(gr->egl_display, gr->egl_config);
Pekka Paalanen9c3fe252012-10-24 09:43:05 +03001780
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001781 gr->egl_context = eglCreateContext(gr->egl_display, gr->egl_config,
Kristian Høgsberg9793fc72012-09-06 21:07:40 -04001782 EGL_NO_CONTEXT, context_attribs);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001783 if (gr->egl_context == NULL) {
Kristian Høgsberg9793fc72012-09-06 21:07:40 -04001784 weston_log("failed to create context\n");
1785 print_egl_error_state();
1786 return -1;
1787 }
1788
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001789 ret = eglMakeCurrent(gr->egl_display, egl_surface,
1790 egl_surface, gr->egl_context);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04001791 if (ret == EGL_FALSE) {
1792 weston_log("Failed to make EGL context current.\n");
1793 print_egl_error_state();
1794 return -1;
1795 }
1796
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001797 log_egl_gl_info(gr->egl_display);
Kristian Høgsberg25894fc2012-09-05 22:06:26 -04001798
1799 ec->image_target_texture_2d =
1800 (void *) eglGetProcAddress("glEGLImageTargetTexture2DOES");
1801 ec->image_target_renderbuffer_storage = (void *)
1802 eglGetProcAddress("glEGLImageTargetRenderbufferStorageOES");
1803 ec->create_image = (void *) eglGetProcAddress("eglCreateImageKHR");
1804 ec->destroy_image = (void *) eglGetProcAddress("eglDestroyImageKHR");
1805 ec->bind_display =
1806 (void *) eglGetProcAddress("eglBindWaylandDisplayWL");
1807 ec->unbind_display =
1808 (void *) eglGetProcAddress("eglUnbindWaylandDisplayWL");
1809 ec->query_buffer =
1810 (void *) eglGetProcAddress("eglQueryWaylandBufferWL");
1811
1812 extensions = (const char *) glGetString(GL_EXTENSIONS);
1813 if (!extensions) {
1814 weston_log("Retrieving GL extension string failed.\n");
1815 return -1;
1816 }
1817
1818 if (!strstr(extensions, "GL_EXT_texture_format_BGRA8888")) {
1819 weston_log("GL_EXT_texture_format_BGRA8888 not available\n");
1820 return -1;
1821 }
1822
1823 if (strstr(extensions, "GL_EXT_read_format_bgra"))
John Kåre Alsakerf9e710b2012-11-13 19:10:22 +01001824 ec->read_format = PIXMAN_a8r8g8b8;
Kristian Høgsberg25894fc2012-09-05 22:06:26 -04001825 else
John Kåre Alsakerf9e710b2012-11-13 19:10:22 +01001826 ec->read_format = PIXMAN_a8b8g8r8;
Kristian Høgsberg25894fc2012-09-05 22:06:26 -04001827
1828 if (strstr(extensions, "GL_EXT_unpack_subimage"))
1829 ec->has_unpack_subimage = 1;
1830
1831 if (strstr(extensions, "GL_OES_EGL_image_external"))
Ander Conselvan de Oliveira27508c22012-11-08 17:20:46 +02001832 ec->has_egl_image_external = 1;
Kristian Høgsberg25894fc2012-09-05 22:06:26 -04001833
1834 extensions =
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001835 (const char *) eglQueryString(gr->egl_display, EGL_EXTENSIONS);
Kristian Høgsberg25894fc2012-09-05 22:06:26 -04001836 if (!extensions) {
1837 weston_log("Retrieving EGL extension string failed.\n");
1838 return -1;
1839 }
1840
1841 if (strstr(extensions, "EGL_WL_bind_wayland_display"))
1842 ec->has_bind_display = 1;
Pekka Paalanen035a0322012-10-24 09:43:06 +03001843 if (ec->has_bind_display) {
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001844 ret = ec->bind_display(gr->egl_display, ec->wl_display);
Pekka Paalanen035a0322012-10-24 09:43:06 +03001845 if (!ret)
1846 ec->has_bind_display = 0;
1847 }
Kristian Høgsberg25894fc2012-09-05 22:06:26 -04001848
1849 glActiveTexture(GL_TEXTURE0);
1850
Ander Conselvan de Oliveira27508c22012-11-08 17:20:46 +02001851 if (compile_shaders(ec))
1852 return -1;
1853
1854 weston_compositor_add_debug_binding(ec, KEY_S,
1855 fragment_debug_binding, ec);
1856
Pekka Paalanen035a0322012-10-24 09:43:06 +03001857 weston_log("GL ES 2 renderer features:\n");
1858 weston_log_continue(STAMP_SPACE "read-back format: %s\n",
1859 ec->read_format == GL_BGRA_EXT ? "BGRA" : "RGBA");
1860 weston_log_continue(STAMP_SPACE "wl_shm sub-image to texture: %s\n",
1861 ec->has_unpack_subimage ? "yes" : "no");
1862 weston_log_continue(STAMP_SPACE "EGL Wayland extension: %s\n",
1863 ec->has_bind_display ? "yes" : "no");
1864
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001865
Kristian Høgsberg25894fc2012-09-05 22:06:26 -04001866 return 0;
1867}