blob: 14dcf64aa0a07f7a37f70cf7cf4e4f32cde76ef7 [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øgsbergecf6ede2012-09-05 21:59:35 -040023#include <stdlib.h>
24
Kristian Høgsbergd7c17262012-09-05 21:54:15 -040025#include "compositor.h"
26
27static const char *
28egl_error_string(EGLint code)
29{
30#define MYERRCODE(x) case x: return #x;
31 switch (code) {
32 MYERRCODE(EGL_SUCCESS)
33 MYERRCODE(EGL_NOT_INITIALIZED)
34 MYERRCODE(EGL_BAD_ACCESS)
35 MYERRCODE(EGL_BAD_ALLOC)
36 MYERRCODE(EGL_BAD_ATTRIBUTE)
37 MYERRCODE(EGL_BAD_CONTEXT)
38 MYERRCODE(EGL_BAD_CONFIG)
39 MYERRCODE(EGL_BAD_CURRENT_SURFACE)
40 MYERRCODE(EGL_BAD_DISPLAY)
41 MYERRCODE(EGL_BAD_SURFACE)
42 MYERRCODE(EGL_BAD_MATCH)
43 MYERRCODE(EGL_BAD_PARAMETER)
44 MYERRCODE(EGL_BAD_NATIVE_PIXMAP)
45 MYERRCODE(EGL_BAD_NATIVE_WINDOW)
46 MYERRCODE(EGL_CONTEXT_LOST)
47 default:
48 return "unknown";
49 }
50#undef MYERRCODE
51}
52
53static void
54print_egl_error_state(void)
55{
56 EGLint code;
57
58 code = eglGetError();
59 weston_log("EGL error state: %s (0x%04lx)\n",
60 egl_error_string(code), (long)code);
61}
62
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -040063#define max(a, b) (((a) > (b)) ? (a) : (b))
64#define min(a, b) (((a) > (b)) ? (b) : (a))
65#define clip(x, a, b) min(max(x, a), b)
66#define sign(x) ((x) >= 0)
67
68static int
69calculate_edges(struct weston_surface *es, pixman_box32_t *rect,
70 pixman_box32_t *surf_rect, GLfloat *ex, GLfloat *ey)
71{
72 int i, n = 0;
73 GLfloat min_x, max_x, min_y, max_y;
74 GLfloat x[4] = {
75 surf_rect->x1, surf_rect->x2, surf_rect->x2, surf_rect->x1,
76 };
77 GLfloat y[4] = {
78 surf_rect->y1, surf_rect->y1, surf_rect->y2, surf_rect->y2,
79 };
80 GLfloat cx1 = rect->x1;
81 GLfloat cx2 = rect->x2;
82 GLfloat cy1 = rect->y1;
83 GLfloat cy2 = rect->y2;
84
85 GLfloat dist_squared(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2)
86 {
87 GLfloat dx = (x1 - x2);
88 GLfloat dy = (y1 - y2);
89 return dx * dx + dy * dy;
90 }
91
92 void append_vertex(GLfloat x, GLfloat y)
93 {
94 /* don't emit duplicate vertices: */
95 if ((n > 0) && (ex[n-1] == x) && (ey[n-1] == y))
96 return;
97 ex[n] = x;
98 ey[n] = y;
99 n++;
100 }
101
102 /* transform surface to screen space: */
103 for (i = 0; i < 4; i++)
104 weston_surface_to_global_float(es, x[i], y[i], &x[i], &y[i]);
105
106 /* find bounding box: */
107 min_x = max_x = x[0];
108 min_y = max_y = y[0];
109
110 for (i = 1; i < 4; i++) {
111 min_x = min(min_x, x[i]);
112 max_x = max(max_x, x[i]);
113 min_y = min(min_y, y[i]);
114 max_y = max(max_y, y[i]);
115 }
116
117 /* First, simple bounding box check to discard early transformed
118 * surface rects that do not intersect with the clip region:
119 */
120 if ((min_x > cx2) || (max_x < cx1) ||
121 (min_y > cy2) || (max_y < cy1))
122 return 0;
123
124 /* Simple case, bounding box edges are parallel to surface edges,
125 * there will be only four edges. We just need to clip the surface
126 * vertices to the clip rect bounds:
127 */
128 if (!es->transform.enabled) {
129 for (i = 0; i < 4; i++) {
130 ex[n] = clip(x[i], cx1, cx2);
131 ey[n] = clip(y[i], cy1, cy2);
132 n++;
133 }
134 return 4;
135 }
136
137 /* Hard case, transformation applied. We need to find the vertices
138 * of the shape that is the intersection of the clip rect and
139 * transformed surface. This can be anything from 3 to 8 sides.
140 *
141 * Observation: all the resulting vertices will be the intersection
142 * points of the transformed surface and the clip rect, plus the
143 * vertices of the clip rect which are enclosed by the transformed
144 * surface and the vertices of the transformed surface which are
145 * enclosed by the clip rect.
146 *
147 * Observation: there will be zero, one, or two resulting vertices
148 * for each edge of the src rect.
149 *
150 * Loop over four edges of the transformed rect:
151 */
152 for (i = 0; i < 4; i++) {
153 GLfloat x1, y1, x2, y2;
154 int last_n = n;
155
156 x1 = x[i];
157 y1 = y[i];
158
159 /* if this vertex is contained in the clip rect, use it as-is: */
160 if ((cx1 <= x1) && (x1 <= cx2) &&
161 (cy1 <= y1) && (y1 <= cy2))
162 append_vertex(x1, y1);
163
164 /* for remaining, we consider the point as part of a line: */
165 x2 = x[(i+1) % 4];
166 y2 = y[(i+1) % 4];
167
168 if (x1 == x2) {
169 append_vertex(clip(x1, cx1, cx2), clip(y1, cy1, cy2));
170 append_vertex(clip(x2, cx1, cx2), clip(y2, cy1, cy2));
171 } else if (y1 == y2) {
172 append_vertex(clip(x1, cx1, cx2), clip(y1, cy1, cy2));
173 append_vertex(clip(x2, cx1, cx2), clip(y2, cy1, cy2));
174 } else {
175 GLfloat m, c, p;
176 GLfloat tx[2], ty[2];
177 int tn = 0;
178
179 int intersect_horiz(GLfloat y, GLfloat *p)
180 {
181 GLfloat x;
182
183 /* if y does not lie between y1 and y2, no
184 * intersection possible
185 */
186 if (sign(y-y1) == sign(y-y2))
187 return 0;
188
189 x = (y - c) / m;
190
191 /* if x does not lie between cx1 and cx2, no
192 * intersection:
193 */
194 if (sign(x-cx1) == sign(x-cx2))
195 return 0;
196
197 *p = x;
198 return 1;
199 }
200
201 int intersect_vert(GLfloat x, GLfloat *p)
202 {
203 GLfloat y;
204
205 if (sign(x-x1) == sign(x-x2))
206 return 0;
207
208 y = m * x + c;
209
210 if (sign(y-cy1) == sign(y-cy2))
211 return 0;
212
213 *p = y;
214 return 1;
215 }
216
217 /* y = mx + c */
218 m = (y2 - y1) / (x2 - x1);
219 c = y1 - m * x1;
220
221 /* check for up to two intersections with the four edges
222 * of the clip rect. Note that we don't know the orientation
223 * of the transformed surface wrt. the clip rect. So if when
224 * there are two intersection points, we need to put the one
225 * closest to x1,y1 first:
226 */
227
228 /* check top clip rect edge: */
229 if (intersect_horiz(cy1, &p)) {
230 ty[tn] = cy1;
231 tx[tn] = p;
232 tn++;
233 }
234
235 /* check right clip rect edge: */
236 if (intersect_vert(cx2, &p)) {
237 ty[tn] = p;
238 tx[tn] = cx2;
239 tn++;
240 if (tn == 2)
241 goto edge_check_done;
242 }
243
244 /* check bottom clip rect edge: */
245 if (intersect_horiz(cy2, &p)) {
246 ty[tn] = cy2;
247 tx[tn] = p;
248 tn++;
249 if (tn == 2)
250 goto edge_check_done;
251 }
252
253 /* check left clip rect edge: */
254 if (intersect_vert(cx1, &p)) {
255 ty[tn] = p;
256 tx[tn] = cx1;
257 tn++;
258 }
259
260edge_check_done:
261 if (tn == 1) {
262 append_vertex(tx[0], ty[0]);
263 } else if (tn == 2) {
264 if (dist_squared(x1, y1, tx[0], ty[0]) <
265 dist_squared(x1, y1, tx[1], ty[1])) {
266 append_vertex(tx[0], ty[0]);
267 append_vertex(tx[1], ty[1]);
268 } else {
269 append_vertex(tx[1], ty[1]);
270 append_vertex(tx[0], ty[0]);
271 }
272 }
273
274 if (n == last_n) {
275 GLfloat best_x=0, best_y=0;
276 uint32_t d, best_d = (unsigned int)-1; /* distance squared */
277 uint32_t max_d = dist_squared(x2, y2,
278 x[(i+2) % 4], y[(i+2) % 4]);
279
280 /* if there are no vertices on this line, it could be that
281 * there is a vertex of the clip rect that is enclosed by
282 * the transformed surface. Find the vertex of the clip
283 * rect that is reached by the shortest line perpendicular
284 * to the current edge, if any.
285 *
286 * slope of perpendicular is 1/m, so
287 *
288 * cy = -cx/m + c2
289 * c2 = cy + cx/m
290 *
291 */
292
293 int perp_intersect(GLfloat cx, GLfloat cy, uint32_t *d)
294 {
295 GLfloat c2 = cy + cx/m;
296 GLfloat x = (c2 - c) / (m + 1/m);
297
298 /* if the x position of the intersection of the
299 * perpendicular with the transformed edge does
300 * not lie within the bounds of the edge, then
301 * no intersection:
302 */
303 if (sign(x-x1) == sign(x-x2))
304 return 0;
305
306 *d = dist_squared(cx, cy, x, (m * x) + c);
307
308 /* if intersection distance is further away than
309 * opposite edge of surface region, it is invalid:
310 */
311 if (*d > max_d)
312 return 0;
313
314 return 1;
315 }
316
317 if (perp_intersect(cx1, cy1, &d)) {
318 best_x = cx1;
319 best_y = cy1;
320 best_d = d;
321 }
322
323 if (perp_intersect(cx1, cy2, &d) && (d < best_d)) {
324 best_x = cx1;
325 best_y = cy2;
326 best_d = d;
327 }
328
329 if (perp_intersect(cx2, cy2, &d) && (d < best_d)) {
330 best_x = cx2;
331 best_y = cy2;
332 best_d = d;
333 }
334
335 if (perp_intersect(cx2, cy1, &d) && (d < best_d)) {
336 best_x = cx2;
337 best_y = cy1;
338 best_d = d;
339 }
340
341 if (best_d != (unsigned int)-1) // XXX can this happen?
342 append_vertex(best_x, best_y);
343 }
344 }
345
346 }
347
348 return n;
349}
350
351static int
352texture_region(struct weston_surface *es, pixman_region32_t *region,
353 pixman_region32_t *surf_region)
354{
355 struct weston_compositor *ec = es->compositor;
356 GLfloat *v, inv_width, inv_height;
357 unsigned int *vtxcnt, nvtx = 0;
358 pixman_box32_t *rects, *surf_rects;
359 int i, j, k, nrects, nsurf;
360
361 rects = pixman_region32_rectangles(region, &nrects);
362 surf_rects = pixman_region32_rectangles(surf_region, &nsurf);
363
364 /* worst case we can have 8 vertices per rect (ie. clipped into
365 * an octagon):
366 */
367 v = wl_array_add(&ec->vertices, nrects * nsurf * 8 * 4 * sizeof *v);
368 vtxcnt = wl_array_add(&ec->vtxcnt, nrects * nsurf * sizeof *vtxcnt);
369
370 inv_width = 1.0 / es->pitch;
371 inv_height = 1.0 / es->geometry.height;
372
373 for (i = 0; i < nrects; i++) {
374 pixman_box32_t *rect = &rects[i];
375 for (j = 0; j < nsurf; j++) {
376 pixman_box32_t *surf_rect = &surf_rects[j];
377 GLfloat sx, sy;
378 GLfloat ex[8], ey[8]; /* edge points in screen space */
379 int n;
380
381 /* The transformed surface, after clipping to the clip region,
382 * can have as many as eight sides, emitted as a triangle-fan.
383 * The first vertex in the triangle fan can be chosen arbitrarily,
384 * since the area is guaranteed to be convex.
385 *
386 * If a corner of the transformed surface falls outside of the
387 * clip region, instead of emitting one vertex for the corner
388 * of the surface, up to two are emitted for two corresponding
389 * intersection point(s) between the surface and the clip region.
390 *
391 * To do this, we first calculate the (up to eight) points that
392 * form the intersection of the clip rect and the transformed
393 * surface.
394 */
395 n = calculate_edges(es, rect, surf_rect, ex, ey);
396 if (n < 3)
397 continue;
398
399 /* emit edge points: */
400 for (k = 0; k < n; k++) {
401 weston_surface_from_global_float(es, ex[k], ey[k], &sx, &sy);
402 /* position: */
403 *(v++) = ex[k];
404 *(v++) = ey[k];
405 /* texcoord: */
406 *(v++) = sx * inv_width;
407 *(v++) = sy * inv_height;
408 }
409
410 vtxcnt[nvtx++] = n;
411 }
412 }
413
414 return nvtx;
415}
416
417static void
418triangle_fan_debug(struct weston_surface *surface, int first, int count)
419{
420 struct weston_compositor *compositor = surface->compositor;
421 int i;
422 GLushort *buffer;
423 GLushort *index;
424 int nelems;
425 static int color_idx = 0;
426 static const GLfloat color[][4] = {
427 { 1.0, 0.0, 0.0, 1.0 },
428 { 0.0, 1.0, 0.0, 1.0 },
429 { 0.0, 0.0, 1.0, 1.0 },
430 { 1.0, 1.0, 1.0, 1.0 },
431 };
432
433 nelems = (count - 1 + count - 2) * 2;
434
435 buffer = malloc(sizeof(GLushort) * nelems);
436 index = buffer;
437
438 for (i = 1; i < count; i++) {
439 *index++ = first;
440 *index++ = first + i;
441 }
442
443 for (i = 2; i < count; i++) {
444 *index++ = first + i - 1;
445 *index++ = first + i;
446 }
447
448 glUseProgram(compositor->solid_shader.program);
449 glUniform4fv(compositor->solid_shader.color_uniform, 1,
450 color[color_idx++ % ARRAY_LENGTH(color)]);
451 glDrawElements(GL_LINES, nelems, GL_UNSIGNED_SHORT, buffer);
452 glUseProgram(compositor->current_shader->program);
453 free(buffer);
454}
455
456static void
457repaint_region(struct weston_surface *es, pixman_region32_t *region,
458 pixman_region32_t *surf_region)
459{
460 struct weston_compositor *ec = es->compositor;
461 GLfloat *v;
462 unsigned int *vtxcnt;
463 int i, first, nfans;
464
465 /* The final region to be painted is the intersection of
466 * 'region' and 'surf_region'. However, 'region' is in the global
467 * coordinates, and 'surf_region' is in the surface-local
468 * coordinates. texture_region() will iterate over all pairs of
469 * rectangles from both regions, compute the intersection
470 * polygon for each pair, and store it as a triangle fan if
471 * it has a non-zero area (at least 3 vertices, actually).
472 */
473 nfans = texture_region(es, region, surf_region);
474
475 v = ec->vertices.data;
476 vtxcnt = ec->vtxcnt.data;
477
478 /* position: */
479 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof *v, &v[0]);
480 glEnableVertexAttribArray(0);
481
482 /* texcoord: */
483 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof *v, &v[2]);
484 glEnableVertexAttribArray(1);
485
486 for (i = 0, first = 0; i < nfans; i++) {
487 glDrawArrays(GL_TRIANGLE_FAN, first, vtxcnt[i]);
488 if (ec->fan_debug)
489 triangle_fan_debug(es, first, vtxcnt[i]);
490 first += vtxcnt[i];
491 }
492
493 glDisableVertexAttribArray(1);
494 glDisableVertexAttribArray(0);
495
496 ec->vertices.size = 0;
497 ec->vtxcnt.size = 0;
498}
499
500static void
501weston_compositor_use_shader(struct weston_compositor *compositor,
502 struct weston_shader *shader)
503{
504 if (compositor->current_shader == shader)
505 return;
506
507 glUseProgram(shader->program);
508 compositor->current_shader = shader;
509}
510
511static void
512weston_shader_uniforms(struct weston_shader *shader,
513 struct weston_surface *surface,
514 struct weston_output *output)
515{
516 int i;
517
518 glUniformMatrix4fv(shader->proj_uniform,
519 1, GL_FALSE, output->matrix.d);
520 glUniform4fv(shader->color_uniform, 1, surface->color);
521 glUniform1f(shader->alpha_uniform, surface->alpha);
522
523 for (i = 0; i < surface->num_textures; i++)
524 glUniform1i(shader->tex_uniforms[i], i);
525}
526
527static void
528draw_surface(struct weston_surface *es, struct weston_output *output,
529 pixman_region32_t *damage) /* in global coordinates */
530{
531 struct weston_compositor *ec = es->compositor;
532 /* repaint bounding region in global coordinates: */
533 pixman_region32_t repaint;
534 /* non-opaque region in surface coordinates: */
535 pixman_region32_t surface_blend;
536 GLint filter;
537 int i;
538
539 pixman_region32_init(&repaint);
540 pixman_region32_intersect(&repaint,
541 &es->transform.boundingbox, damage);
542 pixman_region32_subtract(&repaint, &repaint, &es->clip);
543
544 if (!pixman_region32_not_empty(&repaint))
545 goto out;
546
547 pixman_region32_subtract(&ec->primary_plane.damage,
548 &ec->primary_plane.damage, &repaint);
549
550 glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
551
552 if (ec->fan_debug) {
553 weston_compositor_use_shader(ec, &ec->solid_shader);
554 weston_shader_uniforms(&ec->solid_shader, es, output);
555 }
556
557 weston_compositor_use_shader(ec, es->shader);
558 weston_shader_uniforms(es->shader, es, output);
559
560 if (es->transform.enabled || output->zoom.active)
561 filter = GL_LINEAR;
562 else
563 filter = GL_NEAREST;
564
565 for (i = 0; i < es->num_textures; i++) {
566 glActiveTexture(GL_TEXTURE0 + i);
567 glBindTexture(es->target, es->textures[i]);
568 glTexParameteri(es->target, GL_TEXTURE_MIN_FILTER, filter);
569 glTexParameteri(es->target, GL_TEXTURE_MAG_FILTER, filter);
570 }
571
572 /* blended region is whole surface minus opaque region: */
573 pixman_region32_init_rect(&surface_blend, 0, 0,
574 es->geometry.width, es->geometry.height);
575 pixman_region32_subtract(&surface_blend, &surface_blend, &es->opaque);
576
577 if (pixman_region32_not_empty(&es->opaque)) {
578 if (es->shader == &ec->texture_shader_rgba) {
579 /* Special case for RGBA textures with possibly
580 * bad data in alpha channel: use the shader
581 * that forces texture alpha = 1.0.
582 * Xwayland surfaces need this.
583 */
584 weston_compositor_use_shader(ec, &ec->texture_shader_rgbx);
585 weston_shader_uniforms(&ec->texture_shader_rgbx, es, output);
586 }
587
588 if (es->alpha < 1.0)
589 glEnable(GL_BLEND);
590 else
591 glDisable(GL_BLEND);
592
593 repaint_region(es, &repaint, &es->opaque);
594 }
595
596 if (pixman_region32_not_empty(&surface_blend)) {
597 weston_compositor_use_shader(ec, es->shader);
598 glEnable(GL_BLEND);
599 repaint_region(es, &repaint, &surface_blend);
600 }
601
602 pixman_region32_fini(&surface_blend);
603
604out:
605 pixman_region32_fini(&repaint);
606}
607
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400608static void
609repaint_surfaces(struct weston_output *output, pixman_region32_t *damage)
610{
611 struct weston_compositor *compositor = output->compositor;
612 struct weston_surface *surface;
613
614 wl_list_for_each_reverse(surface, &compositor->surface_list, link)
615 if (surface->plane == &compositor->primary_plane)
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400616 draw_surface(surface, output, damage);
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400617}
618
619WL_EXPORT void
620gles2_renderer_repaint_output(struct weston_output *output,
621 pixman_region32_t *output_damage)
622{
623 struct weston_compositor *compositor = output->compositor;
624 EGLBoolean ret;
625 static int errored;
626 int32_t width, height;
627
628 width = output->current->width +
629 output->border.left + output->border.right;
630 height = output->current->height +
631 output->border.top + output->border.bottom;
632
633 glViewport(0, 0, width, height);
634
635 ret = eglMakeCurrent(compositor->egl_display, output->egl_surface,
636 output->egl_surface, compositor->egl_context);
637 if (ret == EGL_FALSE) {
638 if (errored)
639 return;
640 errored = 1;
641 weston_log("Failed to make EGL context current.\n");
642 print_egl_error_state();
643 return;
644 }
645
646 /* if debugging, redraw everything outside the damage to clean up
647 * debug lines from the previous draw on this buffer:
648 */
649 if (compositor->fan_debug) {
650 pixman_region32_t undamaged;
651 pixman_region32_init(&undamaged);
652 pixman_region32_subtract(&undamaged, &output->region,
653 output_damage);
654 compositor->fan_debug = 0;
655 repaint_surfaces(output, &undamaged);
656 compositor->fan_debug = 1;
657 pixman_region32_fini(&undamaged);
658 }
659
660 repaint_surfaces(output, output_damage);
661
662 wl_signal_emit(&output->frame_signal, output);
663
664 ret = eglSwapBuffers(compositor->egl_display, output->egl_surface);
665 if (ret == EGL_FALSE && !errored) {
666 errored = 1;
667 weston_log("Failed in eglSwapBuffers.\n");
668 print_egl_error_state();
669 }
670
671}