blob: 28c0b506dae670513082d75f5c0546bd89bfbdd1 [file] [log] [blame]
Kristian Høgsbergd7c17262012-09-05 21:54:15 -04001/*
2 * Copyright © 2012 Intel Corporation
Pekka Paalaneneb35cbe2015-02-09 13:37:27 +02003 * Copyright © 2015 Collabora, Ltd.
Kristian Høgsbergd7c17262012-09-05 21:54:15 -04004 *
Bryce Harringtona0bbfea2015-06-11 15:35:43 -07005 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sublicense, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
Kristian Høgsbergd7c17262012-09-05 21:54:15 -040012 *
Bryce Harringtona0bbfea2015-06-11 15:35:43 -070013 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial
15 * portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
21 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
22 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 * SOFTWARE.
Kristian Høgsbergd7c17262012-09-05 21:54:15 -040025 */
26
Daniel Stonec228e232013-05-22 18:03:19 +030027#include "config.h"
Kristian Høgsberg25894fc2012-09-05 22:06:26 -040028
John Kåre Alsaker30d2b1f2012-11-13 19:10:28 +010029#include <GLES2/gl2.h>
30#include <GLES2/gl2ext.h>
31
Derek Foremanf8180982014-10-16 16:37:02 -050032#include <stdbool.h>
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -040033#include <stdlib.h>
Kristian Høgsberg25894fc2012-09-05 22:06:26 -040034#include <string.h>
35#include <ctype.h>
Pekka Paalanen0d64a0f2012-09-11 17:02:05 +030036#include <float.h>
37#include <assert.h>
Ander Conselvan de Oliveira27508c22012-11-08 17:20:46 +020038#include <linux/input.h>
Pekka Paalanena3525802014-06-12 16:49:29 +030039#include <drm_fourcc.h>
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -040040
John Kåre Alsaker30d2b1f2012-11-13 19:10:28 +010041#include "gl-renderer.h"
Sam Spilsbury619859c2013-09-13 10:01:21 +080042#include "vertex-clipping.h"
Pekka Paalanena3525802014-06-12 16:49:29 +030043#include "linux-dmabuf.h"
Jonas Ådahl57e48f02015-11-17 16:00:28 +080044#include "linux-dmabuf-unstable-v1-server-protocol.h"
John Kåre Alsaker30d2b1f2012-11-13 19:10:28 +010045
Jon Cruz35b2eaa2015-06-15 15:37:08 -070046#include "shared/helpers.h"
John Kåre Alsaker30d2b1f2012-11-13 19:10:28 +010047#include "weston-egl-ext.h"
Kristian Høgsbergd7c17262012-09-05 21:54:15 -040048
John Kåre Alsaker779b52a2012-11-13 19:10:29 +010049struct gl_shader {
John Kåre Alsaker40684142012-11-13 19:10:25 +010050 GLuint program;
51 GLuint vertex_shader, fragment_shader;
52 GLint proj_uniform;
53 GLint tex_uniforms[3];
54 GLint alpha_uniform;
55 GLint color_uniform;
Ander Conselvan de Oliveira1ed73242013-05-17 14:00:40 +030056 const char *vertex_source, *fragment_source;
John Kåre Alsaker40684142012-11-13 19:10:25 +010057};
58
Ander Conselvan de Oliveira1c169ff2013-03-05 17:30:30 +020059#define BUFFER_DAMAGE_COUNT 2
60
Jason Ekstrande5512d42014-02-04 21:36:38 -060061enum gl_border_status {
62 BORDER_STATUS_CLEAN = 0,
63 BORDER_TOP_DIRTY = 1 << GL_RENDERER_BORDER_TOP,
64 BORDER_LEFT_DIRTY = 1 << GL_RENDERER_BORDER_LEFT,
65 BORDER_RIGHT_DIRTY = 1 << GL_RENDERER_BORDER_RIGHT,
66 BORDER_BOTTOM_DIRTY = 1 << GL_RENDERER_BORDER_BOTTOM,
67 BORDER_ALL_DIRTY = 0xf,
68 BORDER_SIZE_CHANGED = 0x10
69};
70
Jason Ekstrand0b61bf42013-10-27 22:24:54 -050071struct gl_border_image {
72 GLuint tex;
73 int32_t width, height;
74 int32_t tex_width;
Jason Ekstrand0b61bf42013-10-27 22:24:54 -050075 void *data;
76};
77
John Kåre Alsaker779b52a2012-11-13 19:10:29 +010078struct gl_output_state {
John Kåre Alsaker94659272012-11-13 19:10:18 +010079 EGLSurface egl_surface;
Ander Conselvan de Oliveira1c169ff2013-03-05 17:30:30 +020080 pixman_region32_t buffer_damage[BUFFER_DAMAGE_COUNT];
Derek Foreman4c582662014-10-09 18:39:44 -050081 int buffer_damage_index;
Jason Ekstrande5512d42014-02-04 21:36:38 -060082 enum gl_border_status border_damage[BUFFER_DAMAGE_COUNT];
Jason Ekstrand0b61bf42013-10-27 22:24:54 -050083 struct gl_border_image borders[4];
Jason Ekstrande5512d42014-02-04 21:36:38 -060084 enum gl_border_status border_status;
Jason Ekstrandfb23df72014-10-16 10:55:21 -050085
86 struct weston_matrix output_matrix;
John Kåre Alsaker94659272012-11-13 19:10:18 +010087};
88
Ander Conselvan de Oliveiraa9bf1612013-06-07 16:52:44 +030089enum buffer_type {
90 BUFFER_TYPE_NULL,
Pekka Paalanenaeb917e2015-02-09 13:56:56 +020091 BUFFER_TYPE_SOLID, /* internal solid color surfaces without a buffer */
Ander Conselvan de Oliveiraa9bf1612013-06-07 16:52:44 +030092 BUFFER_TYPE_SHM,
93 BUFFER_TYPE_EGL
94};
95
Louis-Francis Ratté-Boulianne534defd2015-06-08 16:37:05 +030096struct gl_renderer;
97
98struct egl_image {
99 struct gl_renderer *renderer;
100 EGLImageKHR image;
101 int refcount;
Emmanuel Gil Peyrotb8053502016-01-11 19:04:34 +0000102};
Pekka Paalanena3525802014-06-12 16:49:29 +0300103
Emmanuel Gil Peyrotbc35fda2016-01-11 19:04:35 +0000104enum import_type {
105 IMPORT_TYPE_INVALID,
106 IMPORT_TYPE_DIRECT,
107 IMPORT_TYPE_GL_CONVERSION
108};
109
Emmanuel Gil Peyrotb8053502016-01-11 19:04:34 +0000110struct dmabuf_image {
Pekka Paalanena3525802014-06-12 16:49:29 +0300111 struct linux_dmabuf_buffer *dmabuf;
Emmanuel Gil Peyrotb8053502016-01-11 19:04:34 +0000112 int num_images;
113 struct egl_image *images[3];
Pekka Paalanena3525802014-06-12 16:49:29 +0300114 struct wl_list link;
Emmanuel Gil Peyrotbc35fda2016-01-11 19:04:35 +0000115
116 enum import_type import_type;
117 GLenum target;
118 struct gl_shader *shader;
119};
120
121struct yuv_plane_descriptor {
122 int width_divisor;
123 int height_divisor;
124 uint32_t format;
125 int plane_index;
126};
127
128struct yuv_format_descriptor {
129 uint32_t format;
130 int input_planes;
131 int output_planes;
132 int texture_type;
133 struct yuv_plane_descriptor plane[4];
Louis-Francis Ratté-Boulianne534defd2015-06-08 16:37:05 +0300134};
135
John Kåre Alsaker779b52a2012-11-13 19:10:29 +0100136struct gl_surface_state {
John Kåre Alsaker878f4492012-11-13 19:10:23 +0100137 GLfloat color[4];
John Kåre Alsaker779b52a2012-11-13 19:10:29 +0100138 struct gl_shader *shader;
John Kåre Alsaker75cc5712012-11-13 19:10:26 +0100139
140 GLuint textures[3];
141 int num_textures;
Derek Foreman4c11fe72015-11-18 16:32:27 -0600142 bool needs_full_upload;
Pekka Paalanen81ee3f52012-12-04 15:58:16 +0200143 pixman_region32_t texture_damage;
John Kåre Alsaker75cc5712012-11-13 19:10:26 +0100144
Neil Roberts4d085e72014-04-07 15:01:01 +0100145 /* These are only used by SHM surfaces to detect when we need
146 * to do a full upload to specify a new internal texture
147 * format */
148 GLenum gl_format;
149 GLenum gl_pixel_type;
150
Louis-Francis Ratté-Boulianne534defd2015-06-08 16:37:05 +0300151 struct egl_image* images[3];
John Kåre Alsaker75cc5712012-11-13 19:10:26 +0100152 GLenum target;
153 int num_images;
Pekka Paalanenfb003d32012-12-04 15:58:13 +0200154
155 struct weston_buffer_reference buffer_ref;
Ander Conselvan de Oliveiraa9bf1612013-06-07 16:52:44 +0300156 enum buffer_type buffer_type;
Pekka Paalanen68033ac2012-12-04 15:58:15 +0200157 int pitch; /* in pixels */
Alexander Larsson4ea95522013-05-22 14:41:37 +0200158 int height; /* in pixels */
Stanislav Vorobiovbfbb8e52013-08-29 11:36:44 +0400159 int y_inverted;
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300160
161 struct weston_surface *surface;
162
163 struct wl_listener surface_destroy_listener;
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300164 struct wl_listener renderer_destroy_listener;
John Kåre Alsaker878f4492012-11-13 19:10:23 +0100165};
166
John Kåre Alsaker779b52a2012-11-13 19:10:29 +0100167struct gl_renderer {
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +0100168 struct weston_renderer base;
169 int fragment_shader_debug;
Kristian Høgsberg8799d412013-05-07 10:50:09 -0400170 int fan_debug;
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +0300171 struct weston_binding *fragment_binding;
172 struct weston_binding *fan_binding;
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +0100173
174 EGLDisplay egl_display;
175 EGLContext egl_context;
176 EGLConfig egl_config;
John Kåre Alsaker44154502012-11-13 19:10:20 +0100177
Armin Krezović28d240f2016-06-23 11:59:35 +0200178 EGLSurface dummy_surface;
179
Kristian Høgsberg7b9195f2013-05-08 22:38:05 -0400180 struct wl_array vertices;
Kristian Høgsberg7b9195f2013-05-08 22:38:05 -0400181 struct wl_array vtxcnt;
182
John Kåre Alsaker320711d2012-11-13 19:10:27 +0100183 PFNGLEGLIMAGETARGETTEXTURE2DOESPROC image_target_texture_2d;
184 PFNEGLCREATEIMAGEKHRPROC create_image;
185 PFNEGLDESTROYIMAGEKHRPROC destroy_image;
186
Jason Ekstrand8e96f9e2014-02-04 21:36:39 -0600187#ifdef EGL_EXT_swap_buffers_with_damage
188 PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC swap_buffers_with_damage;
189#endif
190
Jonny Lamb671148f2015-03-20 15:26:52 +0100191 PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC create_platform_window;
Jonny Lamb671148f2015-03-20 15:26:52 +0100192
John Kåre Alsaker320711d2012-11-13 19:10:27 +0100193 int has_unpack_subimage;
194
195 PFNEGLBINDWAYLANDDISPLAYWL bind_display;
196 PFNEGLUNBINDWAYLANDDISPLAYWL unbind_display;
197 PFNEGLQUERYWAYLANDBUFFERWL query_buffer;
198 int has_bind_display;
199
200 int has_egl_image_external;
201
Ander Conselvan de Oliveira1c169ff2013-03-05 17:30:30 +0200202 int has_egl_buffer_age;
203
Neil Roberts77c1a5b2014-03-07 18:05:50 +0000204 int has_configless_context;
205
Armin Krezović28d240f2016-06-23 11:59:35 +0200206 int has_surfaceless_context;
207
Pekka Paalanena3525802014-06-12 16:49:29 +0300208 int has_dmabuf_import;
209 struct wl_list dmabuf_images;
210
John Kåre Alsaker779b52a2012-11-13 19:10:29 +0100211 struct gl_shader texture_shader_rgba;
212 struct gl_shader texture_shader_rgbx;
213 struct gl_shader texture_shader_egl_external;
214 struct gl_shader texture_shader_y_uv;
215 struct gl_shader texture_shader_y_u_v;
216 struct gl_shader texture_shader_y_xuxv;
217 struct gl_shader invert_color_shader;
218 struct gl_shader solid_shader;
219 struct gl_shader *current_shader;
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300220
221 struct wl_signal destroy_signal;
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +0100222};
John Kåre Alsaker94659272012-11-13 19:10:18 +0100223
Jonny Lamb70eba3f2015-03-20 15:26:50 +0100224static PFNEGLGETPLATFORMDISPLAYEXTPROC get_platform_display = NULL;
Jonny Lamb70eba3f2015-03-20 15:26:50 +0100225
Emmanuel Gil Peyrotb8053502016-01-11 19:04:34 +0000226static inline const char *
227dump_format(uint32_t format, char out[4])
228{
229#if BYTE_ORDER == BIG_ENDIAN
230 format = __builtin_bswap32(format);
231#endif
232 memcpy(out, &format, 4);
233 return out;
234}
235
John Kåre Alsaker779b52a2012-11-13 19:10:29 +0100236static inline struct gl_output_state *
John Kåre Alsaker94659272012-11-13 19:10:18 +0100237get_output_state(struct weston_output *output)
238{
John Kåre Alsaker779b52a2012-11-13 19:10:29 +0100239 return (struct gl_output_state *)output->renderer_state;
John Kåre Alsaker94659272012-11-13 19:10:18 +0100240}
241
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300242static int
243gl_renderer_create_surface(struct weston_surface *surface);
244
John Kåre Alsaker779b52a2012-11-13 19:10:29 +0100245static inline struct gl_surface_state *
John Kåre Alsaker878f4492012-11-13 19:10:23 +0100246get_surface_state(struct weston_surface *surface)
247{
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300248 if (!surface->renderer_state)
249 gl_renderer_create_surface(surface);
250
John Kåre Alsaker779b52a2012-11-13 19:10:29 +0100251 return (struct gl_surface_state *)surface->renderer_state;
John Kåre Alsaker878f4492012-11-13 19:10:23 +0100252}
253
John Kåre Alsaker779b52a2012-11-13 19:10:29 +0100254static inline struct gl_renderer *
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +0100255get_renderer(struct weston_compositor *ec)
256{
John Kåre Alsaker779b52a2012-11-13 19:10:29 +0100257 return (struct gl_renderer *)ec->renderer;
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +0100258}
259
Louis-Francis Ratté-Boulianne534defd2015-06-08 16:37:05 +0300260static struct egl_image*
261egl_image_create(struct gl_renderer *gr, EGLenum target,
262 EGLClientBuffer buffer, const EGLint *attribs)
263{
264 struct egl_image *img;
265
266 img = zalloc(sizeof *img);
267 img->renderer = gr;
268 img->refcount = 1;
269 img->image = gr->create_image(gr->egl_display, EGL_NO_CONTEXT,
270 target, buffer, attribs);
271
272 if (img->image == EGL_NO_IMAGE_KHR) {
273 free(img);
274 return NULL;
275 }
276
277 return img;
278}
279
280static struct egl_image*
281egl_image_ref(struct egl_image *image)
282{
283 image->refcount++;
284
285 return image;
286}
287
288static int
289egl_image_unref(struct egl_image *image)
290{
291 struct gl_renderer *gr = image->renderer;
292
293 assert(image->refcount > 0);
294
295 image->refcount--;
296 if (image->refcount > 0)
297 return image->refcount;
298
299 gr->destroy_image(gr->egl_display, image->image);
300 free(image);
301
302 return 0;
303}
304
Emmanuel Gil Peyrotb8053502016-01-11 19:04:34 +0000305static struct dmabuf_image*
306dmabuf_image_create(void)
307{
308 struct dmabuf_image *img;
309
310 img = zalloc(sizeof *img);
311 wl_list_init(&img->link);
312
313 return img;
314}
315
316static void
317dmabuf_image_destroy(struct dmabuf_image *image)
318{
319 int i;
320
321 for (i = 0; i < image->num_images; ++i)
322 egl_image_unref(image->images[i]);
323
324 if (image->dmabuf)
325 linux_dmabuf_buffer_set_user_data(image->dmabuf, NULL, NULL);
326
327 wl_list_remove(&image->link);
328}
329
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400330static const char *
331egl_error_string(EGLint code)
332{
333#define MYERRCODE(x) case x: return #x;
334 switch (code) {
335 MYERRCODE(EGL_SUCCESS)
336 MYERRCODE(EGL_NOT_INITIALIZED)
337 MYERRCODE(EGL_BAD_ACCESS)
338 MYERRCODE(EGL_BAD_ALLOC)
339 MYERRCODE(EGL_BAD_ATTRIBUTE)
340 MYERRCODE(EGL_BAD_CONTEXT)
341 MYERRCODE(EGL_BAD_CONFIG)
342 MYERRCODE(EGL_BAD_CURRENT_SURFACE)
343 MYERRCODE(EGL_BAD_DISPLAY)
344 MYERRCODE(EGL_BAD_SURFACE)
345 MYERRCODE(EGL_BAD_MATCH)
346 MYERRCODE(EGL_BAD_PARAMETER)
347 MYERRCODE(EGL_BAD_NATIVE_PIXMAP)
348 MYERRCODE(EGL_BAD_NATIVE_WINDOW)
349 MYERRCODE(EGL_CONTEXT_LOST)
350 default:
351 return "unknown";
352 }
353#undef MYERRCODE
354}
355
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +0300356static void
Pekka Paalanen326529f2012-11-27 12:25:25 +0200357gl_renderer_print_egl_error_state(void)
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400358{
359 EGLint code;
360
361 code = eglGetError();
362 weston_log("EGL error state: %s (0x%04lx)\n",
363 egl_error_string(code), (long)code);
364}
365
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400366#define max(a, b) (((a) > (b)) ? (a) : (b))
367#define min(a, b) (((a) > (b)) ? (b) : (a))
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400368
Pekka Paalanen0d64a0f2012-09-11 17:02:05 +0300369/*
370 * Compute the boundary vertices of the intersection of the global coordinate
371 * aligned rectangle 'rect', and an arbitrary quadrilateral produced from
372 * 'surf_rect' when transformed from surface coordinates into global coordinates.
373 * The vertices are written to 'ex' and 'ey', and the return value is the
374 * number of vertices. Vertices are produced in clockwise winding order.
375 * Guarantees to produce either zero vertices, or 3-8 vertices with non-zero
376 * polygon area.
377 */
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400378static int
Jason Ekstranda7af7042013-10-12 22:38:11 -0500379calculate_edges(struct weston_view *ev, pixman_box32_t *rect,
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400380 pixman_box32_t *surf_rect, GLfloat *ex, GLfloat *ey)
381{
Sam Spilsbury619859c2013-09-13 10:01:21 +0800382
Pekka Paalanen0d64a0f2012-09-11 17:02:05 +0300383 struct clip_context ctx;
384 int i, n;
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400385 GLfloat min_x, max_x, min_y, max_y;
Pekka Paalanen0d64a0f2012-09-11 17:02:05 +0300386 struct polygon8 surf = {
387 { surf_rect->x1, surf_rect->x2, surf_rect->x2, surf_rect->x1 },
388 { surf_rect->y1, surf_rect->y1, surf_rect->y2, surf_rect->y2 },
389 4
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400390 };
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400391
Pekka Paalanen0d64a0f2012-09-11 17:02:05 +0300392 ctx.clip.x1 = rect->x1;
393 ctx.clip.y1 = rect->y1;
394 ctx.clip.x2 = rect->x2;
395 ctx.clip.y2 = rect->y2;
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400396
397 /* transform surface to screen space: */
Pekka Paalanen0d64a0f2012-09-11 17:02:05 +0300398 for (i = 0; i < surf.n; i++)
Jason Ekstranda7af7042013-10-12 22:38:11 -0500399 weston_view_to_global_float(ev, surf.x[i], surf.y[i],
400 &surf.x[i], &surf.y[i]);
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400401
402 /* find bounding box: */
Pekka Paalanen0d64a0f2012-09-11 17:02:05 +0300403 min_x = max_x = surf.x[0];
404 min_y = max_y = surf.y[0];
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400405
Pekka Paalanen0d64a0f2012-09-11 17:02:05 +0300406 for (i = 1; i < surf.n; i++) {
407 min_x = min(min_x, surf.x[i]);
408 max_x = max(max_x, surf.x[i]);
409 min_y = min(min_y, surf.y[i]);
410 max_y = max(max_y, surf.y[i]);
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400411 }
412
413 /* First, simple bounding box check to discard early transformed
414 * surface rects that do not intersect with the clip region:
415 */
Pekka Paalanen0d64a0f2012-09-11 17:02:05 +0300416 if ((min_x >= ctx.clip.x2) || (max_x <= ctx.clip.x1) ||
417 (min_y >= ctx.clip.y2) || (max_y <= ctx.clip.y1))
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400418 return 0;
419
420 /* Simple case, bounding box edges are parallel to surface edges,
421 * there will be only four edges. We just need to clip the surface
422 * vertices to the clip rect bounds:
423 */
Jason Ekstranda7af7042013-10-12 22:38:11 -0500424 if (!ev->transform.enabled)
Sam Spilsbury619859c2013-09-13 10:01:21 +0800425 return clip_simple(&ctx, &surf, ex, ey);
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400426
Pekka Paalanen0d64a0f2012-09-11 17:02:05 +0300427 /* Transformed case: use a general polygon clipping algorithm to
428 * clip the surface rectangle with each side of 'rect'.
429 * The algorithm is Sutherland-Hodgman, as explained in
430 * http://www.codeguru.com/cpp/misc/misc/graphics/article.php/c8965/Polygon-Clipping.htm
431 * but without looking at any of that code.
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400432 */
Sam Spilsbury619859c2013-09-13 10:01:21 +0800433 n = clip_transformed(&ctx, &surf, ex, ey);
Pekka Paalanen0d64a0f2012-09-11 17:02:05 +0300434
435 if (n < 3)
436 return 0;
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400437
438 return n;
439}
440
Derek Foremanf8180982014-10-16 16:37:02 -0500441static bool
442merge_down(pixman_box32_t *a, pixman_box32_t *b, pixman_box32_t *merge)
443{
444 if (a->x1 == b->x1 && a->x2 == b->x2 && a->y1 == b->y2) {
445 merge->x1 = a->x1;
446 merge->x2 = a->x2;
447 merge->y1 = b->y1;
448 merge->y2 = a->y2;
449 return true;
450 }
451 return false;
452}
453
454static int
455compress_bands(pixman_box32_t *inrects, int nrects,
456 pixman_box32_t **outrects)
457{
458 bool merged;
459 pixman_box32_t *out, merge_rect;
460 int i, j, nout;
461
462 if (!nrects) {
463 *outrects = NULL;
464 return 0;
465 }
466
467 /* nrects is an upper bound - we're not too worried about
468 * allocating a little extra
469 */
470 out = malloc(sizeof(pixman_box32_t) * nrects);
471 out[0] = inrects[0];
472 nout = 1;
473 for (i = 1; i < nrects; i++) {
474 for (j = 0; j < nout; j++) {
475 merged = merge_down(&inrects[i], &out[j], &merge_rect);
476 if (merged) {
477 out[j] = merge_rect;
478 break;
479 }
480 }
481 if (!merged) {
482 out[nout] = inrects[i];
483 nout++;
484 }
485 }
486 *outrects = out;
487 return nout;
488}
489
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400490static int
Jason Ekstranda7af7042013-10-12 22:38:11 -0500491texture_region(struct weston_view *ev, pixman_region32_t *region,
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400492 pixman_region32_t *surf_region)
493{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500494 struct gl_surface_state *gs = get_surface_state(ev->surface);
495 struct weston_compositor *ec = ev->surface->compositor;
Kristian Høgsberg7b9195f2013-05-08 22:38:05 -0400496 struct gl_renderer *gr = get_renderer(ec);
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400497 GLfloat *v, inv_width, inv_height;
498 unsigned int *vtxcnt, nvtx = 0;
499 pixman_box32_t *rects, *surf_rects;
Derek Foremanf8180982014-10-16 16:37:02 -0500500 pixman_box32_t *raw_rects;
501 int i, j, k, nrects, nsurf, raw_nrects;
502 bool used_band_compression;
503 raw_rects = pixman_region32_rectangles(region, &raw_nrects);
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400504 surf_rects = pixman_region32_rectangles(surf_region, &nsurf);
505
Derek Foremanf8180982014-10-16 16:37:02 -0500506 if (raw_nrects < 4) {
507 used_band_compression = false;
508 nrects = raw_nrects;
509 rects = raw_rects;
510 } else {
511 nrects = compress_bands(raw_rects, raw_nrects, &rects);
512 used_band_compression = true;
513 }
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400514 /* worst case we can have 8 vertices per rect (ie. clipped into
515 * an octagon):
516 */
Kristian Høgsberg7b9195f2013-05-08 22:38:05 -0400517 v = wl_array_add(&gr->vertices, nrects * nsurf * 8 * 4 * sizeof *v);
518 vtxcnt = wl_array_add(&gr->vtxcnt, nrects * nsurf * sizeof *vtxcnt);
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400519
Pekka Paalanen68033ac2012-12-04 15:58:15 +0200520 inv_width = 1.0 / gs->pitch;
Alexander Larsson4ea95522013-05-22 14:41:37 +0200521 inv_height = 1.0 / gs->height;
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400522
523 for (i = 0; i < nrects; i++) {
524 pixman_box32_t *rect = &rects[i];
525 for (j = 0; j < nsurf; j++) {
526 pixman_box32_t *surf_rect = &surf_rects[j];
Ander Conselvan de Oliveira0396ba22012-11-28 17:10:26 +0200527 GLfloat sx, sy, bx, by;
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400528 GLfloat ex[8], ey[8]; /* edge points in screen space */
529 int n;
530
531 /* The transformed surface, after clipping to the clip region,
532 * can have as many as eight sides, emitted as a triangle-fan.
533 * The first vertex in the triangle fan can be chosen arbitrarily,
534 * since the area is guaranteed to be convex.
535 *
536 * If a corner of the transformed surface falls outside of the
537 * clip region, instead of emitting one vertex for the corner
538 * of the surface, up to two are emitted for two corresponding
539 * intersection point(s) between the surface and the clip region.
540 *
541 * To do this, we first calculate the (up to eight) points that
542 * form the intersection of the clip rect and the transformed
543 * surface.
544 */
Jason Ekstranda7af7042013-10-12 22:38:11 -0500545 n = calculate_edges(ev, rect, surf_rect, ex, ey);
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400546 if (n < 3)
547 continue;
548
549 /* emit edge points: */
550 for (k = 0; k < n; k++) {
Jason Ekstranda7af7042013-10-12 22:38:11 -0500551 weston_view_from_global_float(ev, ex[k], ey[k],
552 &sx, &sy);
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400553 /* position: */
554 *(v++) = ex[k];
555 *(v++) = ey[k];
556 /* texcoord: */
Jason Ekstranda7af7042013-10-12 22:38:11 -0500557 weston_surface_to_buffer_float(ev->surface,
558 sx, sy,
Ander Conselvan de Oliveira0396ba22012-11-28 17:10:26 +0200559 &bx, &by);
560 *(v++) = bx * inv_width;
Stanislav Vorobiovbfbb8e52013-08-29 11:36:44 +0400561 if (gs->y_inverted) {
562 *(v++) = by * inv_height;
563 } else {
564 *(v++) = (gs->height - by) * inv_height;
565 }
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400566 }
567
568 vtxcnt[nvtx++] = n;
569 }
570 }
571
Derek Foremanf8180982014-10-16 16:37:02 -0500572 if (used_band_compression)
573 free(rects);
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400574 return nvtx;
575}
576
577static void
Jason Ekstranda7af7042013-10-12 22:38:11 -0500578triangle_fan_debug(struct weston_view *view, int first, int count)
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400579{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500580 struct weston_compositor *compositor = view->surface->compositor;
John Kåre Alsaker779b52a2012-11-13 19:10:29 +0100581 struct gl_renderer *gr = get_renderer(compositor);
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400582 int i;
583 GLushort *buffer;
584 GLushort *index;
585 int nelems;
586 static int color_idx = 0;
587 static const GLfloat color[][4] = {
588 { 1.0, 0.0, 0.0, 1.0 },
589 { 0.0, 1.0, 0.0, 1.0 },
590 { 0.0, 0.0, 1.0, 1.0 },
591 { 1.0, 1.0, 1.0, 1.0 },
592 };
593
594 nelems = (count - 1 + count - 2) * 2;
595
596 buffer = malloc(sizeof(GLushort) * nelems);
597 index = buffer;
598
599 for (i = 1; i < count; i++) {
600 *index++ = first;
601 *index++ = first + i;
602 }
603
604 for (i = 2; i < count; i++) {
605 *index++ = first + i - 1;
606 *index++ = first + i;
607 }
608
John Kåre Alsaker40684142012-11-13 19:10:25 +0100609 glUseProgram(gr->solid_shader.program);
610 glUniform4fv(gr->solid_shader.color_uniform, 1,
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400611 color[color_idx++ % ARRAY_LENGTH(color)]);
612 glDrawElements(GL_LINES, nelems, GL_UNSIGNED_SHORT, buffer);
John Kåre Alsaker40684142012-11-13 19:10:25 +0100613 glUseProgram(gr->current_shader->program);
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400614 free(buffer);
615}
616
617static void
Jason Ekstranda7af7042013-10-12 22:38:11 -0500618repaint_region(struct weston_view *ev, pixman_region32_t *region,
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400619 pixman_region32_t *surf_region)
620{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500621 struct weston_compositor *ec = ev->surface->compositor;
Kristian Høgsberg8799d412013-05-07 10:50:09 -0400622 struct gl_renderer *gr = get_renderer(ec);
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400623 GLfloat *v;
624 unsigned int *vtxcnt;
625 int i, first, nfans;
626
627 /* The final region to be painted is the intersection of
628 * 'region' and 'surf_region'. However, 'region' is in the global
629 * coordinates, and 'surf_region' is in the surface-local
630 * coordinates. texture_region() will iterate over all pairs of
631 * rectangles from both regions, compute the intersection
632 * polygon for each pair, and store it as a triangle fan if
Bryce Harringtonea8fb942016-01-13 18:48:56 -0800633 * it has a non-zero area (at least 3 vertices, actually).
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400634 */
Jason Ekstranda7af7042013-10-12 22:38:11 -0500635 nfans = texture_region(ev, region, surf_region);
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400636
Kristian Høgsberg7b9195f2013-05-08 22:38:05 -0400637 v = gr->vertices.data;
638 vtxcnt = gr->vtxcnt.data;
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400639
640 /* position: */
641 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof *v, &v[0]);
642 glEnableVertexAttribArray(0);
643
644 /* texcoord: */
645 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof *v, &v[2]);
646 glEnableVertexAttribArray(1);
647
648 for (i = 0, first = 0; i < nfans; i++) {
649 glDrawArrays(GL_TRIANGLE_FAN, first, vtxcnt[i]);
Kristian Høgsberg8799d412013-05-07 10:50:09 -0400650 if (gr->fan_debug)
Jason Ekstranda7af7042013-10-12 22:38:11 -0500651 triangle_fan_debug(ev, first, vtxcnt[i]);
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400652 first += vtxcnt[i];
653 }
654
655 glDisableVertexAttribArray(1);
656 glDisableVertexAttribArray(0);
657
Kristian Høgsberg7b9195f2013-05-08 22:38:05 -0400658 gr->vertices.size = 0;
659 gr->vtxcnt.size = 0;
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400660}
661
John Kåre Alsakera95b2d62012-11-13 19:10:21 +0100662static int
663use_output(struct weston_output *output)
664{
665 static int errored;
John Kåre Alsaker779b52a2012-11-13 19:10:29 +0100666 struct gl_output_state *go = get_output_state(output);
667 struct gl_renderer *gr = get_renderer(output->compositor);
John Kåre Alsakera95b2d62012-11-13 19:10:21 +0100668 EGLBoolean ret;
669
670 ret = eglMakeCurrent(gr->egl_display, go->egl_surface,
671 go->egl_surface, gr->egl_context);
672
673 if (ret == EGL_FALSE) {
674 if (errored)
675 return -1;
676 errored = 1;
677 weston_log("Failed to make EGL context current.\n");
Pekka Paalanen326529f2012-11-27 12:25:25 +0200678 gl_renderer_print_egl_error_state();
John Kåre Alsakera95b2d62012-11-13 19:10:21 +0100679 return -1;
680 }
681
682 return 0;
683}
684
Ander Conselvan de Oliveira1ed73242013-05-17 14:00:40 +0300685static int
686shader_init(struct gl_shader *shader, struct gl_renderer *gr,
687 const char *vertex_source, const char *fragment_source);
688
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400689static void
Ander Conselvan de Oliveira1ed73242013-05-17 14:00:40 +0300690use_shader(struct gl_renderer *gr, struct gl_shader *shader)
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400691{
Ander Conselvan de Oliveira1ed73242013-05-17 14:00:40 +0300692 if (!shader->program) {
693 int ret;
694
695 ret = shader_init(shader, gr,
696 shader->vertex_source,
697 shader->fragment_source);
698
699 if (ret < 0)
700 weston_log("warning: failed to compile shader\n");
701 }
702
John Kåre Alsaker40684142012-11-13 19:10:25 +0100703 if (gr->current_shader == shader)
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400704 return;
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400705 glUseProgram(shader->program);
John Kåre Alsaker40684142012-11-13 19:10:25 +0100706 gr->current_shader = shader;
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400707}
708
709static void
John Kåre Alsaker779b52a2012-11-13 19:10:29 +0100710shader_uniforms(struct gl_shader *shader,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500711 struct weston_view *view,
712 struct weston_output *output)
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400713{
714 int i;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500715 struct gl_surface_state *gs = get_surface_state(view->surface);
Jason Ekstrandfb23df72014-10-16 10:55:21 -0500716 struct gl_output_state *go = get_output_state(output);
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400717
718 glUniformMatrix4fv(shader->proj_uniform,
Jason Ekstrandfb23df72014-10-16 10:55:21 -0500719 1, GL_FALSE, go->output_matrix.d);
John Kåre Alsaker878f4492012-11-13 19:10:23 +0100720 glUniform4fv(shader->color_uniform, 1, gs->color);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500721 glUniform1f(shader->alpha_uniform, view->alpha);
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400722
John Kåre Alsaker75cc5712012-11-13 19:10:26 +0100723 for (i = 0; i < gs->num_textures; i++)
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400724 glUniform1i(shader->tex_uniforms[i], i);
725}
726
727static void
Jason Ekstranda7af7042013-10-12 22:38:11 -0500728draw_view(struct weston_view *ev, struct weston_output *output,
729 pixman_region32_t *damage) /* in global coordinates */
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400730{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500731 struct weston_compositor *ec = ev->surface->compositor;
John Kåre Alsaker779b52a2012-11-13 19:10:29 +0100732 struct gl_renderer *gr = get_renderer(ec);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500733 struct gl_surface_state *gs = get_surface_state(ev->surface);
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400734 /* repaint bounding region in global coordinates: */
735 pixman_region32_t repaint;
Pekka Paalanenfa79b1d2015-02-18 09:48:59 +0200736 /* opaque region in surface coordinates: */
737 pixman_region32_t surface_opaque;
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400738 /* non-opaque region in surface coordinates: */
739 pixman_region32_t surface_blend;
740 GLint filter;
741 int i;
742
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +0200743 /* In case of a runtime switch of renderers, we may not have received
744 * an attach for this surface since the switch. In that case we don't
745 * have a valid buffer or a proper shader set up so skip rendering. */
746 if (!gs->shader)
747 return;
748
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400749 pixman_region32_init(&repaint);
750 pixman_region32_intersect(&repaint,
Pekka Paalanen25c0ca52015-02-19 11:15:33 +0200751 &ev->transform.boundingbox, damage);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500752 pixman_region32_subtract(&repaint, &repaint, &ev->clip);
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400753
754 if (!pixman_region32_not_empty(&repaint))
755 goto out;
756
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400757 glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
758
Kristian Høgsberg8799d412013-05-07 10:50:09 -0400759 if (gr->fan_debug) {
John Kåre Alsaker40684142012-11-13 19:10:25 +0100760 use_shader(gr, &gr->solid_shader);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500761 shader_uniforms(&gr->solid_shader, ev, output);
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400762 }
763
John Kåre Alsaker40684142012-11-13 19:10:25 +0100764 use_shader(gr, gs->shader);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500765 shader_uniforms(gs->shader, ev, output);
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400766
Jason Ekstranda7af7042013-10-12 22:38:11 -0500767 if (ev->transform.enabled || output->zoom.active ||
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200768 output->current_scale != ev->surface->buffer_viewport.buffer.scale)
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400769 filter = GL_LINEAR;
770 else
771 filter = GL_NEAREST;
772
John Kåre Alsaker75cc5712012-11-13 19:10:26 +0100773 for (i = 0; i < gs->num_textures; i++) {
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400774 glActiveTexture(GL_TEXTURE0 + i);
John Kåre Alsaker75cc5712012-11-13 19:10:26 +0100775 glBindTexture(gs->target, gs->textures[i]);
776 glTexParameteri(gs->target, GL_TEXTURE_MIN_FILTER, filter);
777 glTexParameteri(gs->target, GL_TEXTURE_MAG_FILTER, filter);
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400778 }
779
780 /* blended region is whole surface minus opaque region: */
781 pixman_region32_init_rect(&surface_blend, 0, 0,
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600782 ev->surface->width, ev->surface->height);
Pekka Paalanenfa79b1d2015-02-18 09:48:59 +0200783 if (ev->geometry.scissor_enabled)
784 pixman_region32_intersect(&surface_blend, &surface_blend,
785 &ev->geometry.scissor);
786 pixman_region32_subtract(&surface_blend, &surface_blend,
787 &ev->surface->opaque);
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400788
Jason Ekstranda7af7042013-10-12 22:38:11 -0500789 /* XXX: Should we be using ev->transform.opaque here? */
Pekka Paalanenfa79b1d2015-02-18 09:48:59 +0200790 pixman_region32_init(&surface_opaque);
791 if (ev->geometry.scissor_enabled)
792 pixman_region32_intersect(&surface_opaque,
793 &ev->surface->opaque,
794 &ev->geometry.scissor);
795 else
796 pixman_region32_copy(&surface_opaque, &ev->surface->opaque);
797
798 if (pixman_region32_not_empty(&surface_opaque)) {
John Kåre Alsaker40684142012-11-13 19:10:25 +0100799 if (gs->shader == &gr->texture_shader_rgba) {
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400800 /* Special case for RGBA textures with possibly
801 * bad data in alpha channel: use the shader
802 * that forces texture alpha = 1.0.
803 * Xwayland surfaces need this.
804 */
John Kåre Alsaker40684142012-11-13 19:10:25 +0100805 use_shader(gr, &gr->texture_shader_rgbx);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500806 shader_uniforms(&gr->texture_shader_rgbx, ev, output);
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400807 }
808
Jason Ekstranda7af7042013-10-12 22:38:11 -0500809 if (ev->alpha < 1.0)
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400810 glEnable(GL_BLEND);
811 else
812 glDisable(GL_BLEND);
813
Pekka Paalanenfa79b1d2015-02-18 09:48:59 +0200814 repaint_region(ev, &repaint, &surface_opaque);
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400815 }
816
817 if (pixman_region32_not_empty(&surface_blend)) {
John Kåre Alsaker40684142012-11-13 19:10:25 +0100818 use_shader(gr, gs->shader);
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400819 glEnable(GL_BLEND);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500820 repaint_region(ev, &repaint, &surface_blend);
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400821 }
822
823 pixman_region32_fini(&surface_blend);
Pekka Paalanenfa79b1d2015-02-18 09:48:59 +0200824 pixman_region32_fini(&surface_opaque);
Kristian Høgsbergecf6ede2012-09-05 21:59:35 -0400825
826out:
827 pixman_region32_fini(&repaint);
828}
829
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400830static void
Jason Ekstranda7af7042013-10-12 22:38:11 -0500831repaint_views(struct weston_output *output, pixman_region32_t *damage)
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400832{
833 struct weston_compositor *compositor = output->compositor;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500834 struct weston_view *view;
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400835
Jason Ekstranda7af7042013-10-12 22:38:11 -0500836 wl_list_for_each_reverse(view, &compositor->view_list, link)
837 if (view->plane == &compositor->primary_plane)
838 draw_view(view, output, damage);
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400839}
840
Jason Ekstrand0b61bf42013-10-27 22:24:54 -0500841static void
Jason Ekstrande5512d42014-02-04 21:36:38 -0600842draw_output_border_texture(struct gl_output_state *go,
843 enum gl_renderer_border_side side,
844 int32_t x, int32_t y,
Jason Ekstrand0b61bf42013-10-27 22:24:54 -0500845 int32_t width, int32_t height)
846{
Jason Ekstrande5512d42014-02-04 21:36:38 -0600847 struct gl_border_image *img = &go->borders[side];
Jason Ekstrand0b61bf42013-10-27 22:24:54 -0500848 static GLushort indices [] = { 0, 1, 3, 3, 1, 2 };
849
850 if (!img->data) {
851 if (img->tex) {
852 glDeleteTextures(1, &img->tex);
853 img->tex = 0;
854 }
855
856 return;
857 }
858
859 if (!img->tex) {
860 glGenTextures(1, &img->tex);
861 glBindTexture(GL_TEXTURE_2D, img->tex);
862
863 glTexParameteri(GL_TEXTURE_2D,
864 GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
865 glTexParameteri(GL_TEXTURE_2D,
866 GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
867 glTexParameteri(GL_TEXTURE_2D,
868 GL_TEXTURE_MIN_FILTER, GL_NEAREST);
869 glTexParameteri(GL_TEXTURE_2D,
870 GL_TEXTURE_MAG_FILTER, GL_NEAREST);
871 } else {
872 glBindTexture(GL_TEXTURE_2D, img->tex);
873 }
874
Jason Ekstrande5512d42014-02-04 21:36:38 -0600875 if (go->border_status & (1 << side)) {
Jason Ekstrand0b61bf42013-10-27 22:24:54 -0500876#ifdef GL_EXT_unpack_subimage
877 glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, 0);
878 glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, 0);
879 glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, 0);
880#endif
881 glTexImage2D(GL_TEXTURE_2D, 0, GL_BGRA_EXT,
882 img->tex_width, img->height, 0,
883 GL_BGRA_EXT, GL_UNSIGNED_BYTE, img->data);
Jason Ekstrand0b61bf42013-10-27 22:24:54 -0500884 }
885
886 GLfloat texcoord[] = {
887 0.0f, 0.0f,
888 (GLfloat)img->width / (GLfloat)img->tex_width, 0.0f,
889 (GLfloat)img->width / (GLfloat)img->tex_width, 1.0f,
890 0.0f, 1.0f,
891 };
892
893 GLfloat verts[] = {
894 x, y,
895 x + width, y,
896 x + width, y + height,
897 x, y + height
898 };
899
900 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, verts);
901 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, texcoord);
902 glEnableVertexAttribArray(0);
903 glEnableVertexAttribArray(1);
904
905 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
906
907 glDisableVertexAttribArray(1);
908 glDisableVertexAttribArray(0);
909}
910
Jason Ekstrand8e96f9e2014-02-04 21:36:39 -0600911static int
912output_has_borders(struct weston_output *output)
913{
914 struct gl_output_state *go = get_output_state(output);
915
916 return go->borders[GL_RENDERER_BORDER_TOP].data ||
917 go->borders[GL_RENDERER_BORDER_RIGHT].data ||
918 go->borders[GL_RENDERER_BORDER_BOTTOM].data ||
919 go->borders[GL_RENDERER_BORDER_LEFT].data;
920}
921
Jason Ekstrand0b61bf42013-10-27 22:24:54 -0500922static void
Jason Ekstrande5512d42014-02-04 21:36:38 -0600923draw_output_borders(struct weston_output *output,
924 enum gl_border_status border_status)
Jason Ekstrand0b61bf42013-10-27 22:24:54 -0500925{
926 struct gl_output_state *go = get_output_state(output);
927 struct gl_renderer *gr = get_renderer(output->compositor);
928 struct gl_shader *shader = &gr->texture_shader_rgba;
Jason Ekstrand00b84282013-10-27 22:24:59 -0500929 struct gl_border_image *top, *bottom, *left, *right;
930 struct weston_matrix matrix;
931 int full_width, full_height;
932
Jason Ekstrande5512d42014-02-04 21:36:38 -0600933 if (border_status == BORDER_STATUS_CLEAN)
934 return; /* Clean. Nothing to do. */
935
Jason Ekstrand00b84282013-10-27 22:24:59 -0500936 top = &go->borders[GL_RENDERER_BORDER_TOP];
937 bottom = &go->borders[GL_RENDERER_BORDER_BOTTOM];
938 left = &go->borders[GL_RENDERER_BORDER_LEFT];
939 right = &go->borders[GL_RENDERER_BORDER_RIGHT];
940
941 full_width = output->current_mode->width + left->width + right->width;
942 full_height = output->current_mode->height + top->height + bottom->height;
Jason Ekstrand0b61bf42013-10-27 22:24:54 -0500943
944 glDisable(GL_BLEND);
945 use_shader(gr, shader);
946
Jason Ekstrand00b84282013-10-27 22:24:59 -0500947 glViewport(0, 0, full_width, full_height);
948
949 weston_matrix_init(&matrix);
950 weston_matrix_translate(&matrix, -full_width/2.0, -full_height/2.0, 0);
951 weston_matrix_scale(&matrix, 2.0/full_width, -2.0/full_height, 1);
952 glUniformMatrix4fv(shader->proj_uniform, 1, GL_FALSE, matrix.d);
Jason Ekstrand0b61bf42013-10-27 22:24:54 -0500953
954 glUniform1i(shader->tex_uniforms[0], 0);
955 glUniform1f(shader->alpha_uniform, 1);
956 glActiveTexture(GL_TEXTURE0);
957
Jason Ekstrande5512d42014-02-04 21:36:38 -0600958 if (border_status & BORDER_TOP_DIRTY)
959 draw_output_border_texture(go, GL_RENDERER_BORDER_TOP,
960 0, 0,
961 full_width, top->height);
962 if (border_status & BORDER_LEFT_DIRTY)
963 draw_output_border_texture(go, GL_RENDERER_BORDER_LEFT,
964 0, top->height,
965 left->width, output->current_mode->height);
966 if (border_status & BORDER_RIGHT_DIRTY)
967 draw_output_border_texture(go, GL_RENDERER_BORDER_RIGHT,
968 full_width - right->width, top->height,
969 right->width, output->current_mode->height);
970 if (border_status & BORDER_BOTTOM_DIRTY)
971 draw_output_border_texture(go, GL_RENDERER_BORDER_BOTTOM,
972 0, full_height - bottom->height,
973 full_width, bottom->height);
Jason Ekstrand0b61bf42013-10-27 22:24:54 -0500974}
John Kåre Alsaker44154502012-11-13 19:10:20 +0100975
Kristian Høgsbergfa1be022012-09-05 22:49:55 -0400976static void
Jason Ekstrand8e96f9e2014-02-04 21:36:39 -0600977output_get_border_damage(struct weston_output *output,
978 enum gl_border_status border_status,
979 pixman_region32_t *damage)
980{
981 struct gl_output_state *go = get_output_state(output);
982 struct gl_border_image *top, *bottom, *left, *right;
983 int full_width, full_height;
984
985 if (border_status == BORDER_STATUS_CLEAN)
986 return; /* Clean. Nothing to do. */
987
988 top = &go->borders[GL_RENDERER_BORDER_TOP];
989 bottom = &go->borders[GL_RENDERER_BORDER_BOTTOM];
990 left = &go->borders[GL_RENDERER_BORDER_LEFT];
991 right = &go->borders[GL_RENDERER_BORDER_RIGHT];
992
993 full_width = output->current_mode->width + left->width + right->width;
994 full_height = output->current_mode->height + top->height + bottom->height;
995 if (border_status & BORDER_TOP_DIRTY)
996 pixman_region32_union_rect(damage, damage,
997 0, 0,
998 full_width, top->height);
999 if (border_status & BORDER_LEFT_DIRTY)
1000 pixman_region32_union_rect(damage, damage,
1001 0, top->height,
1002 left->width, output->current_mode->height);
1003 if (border_status & BORDER_RIGHT_DIRTY)
1004 pixman_region32_union_rect(damage, damage,
1005 full_width - right->width, top->height,
1006 right->width, output->current_mode->height);
1007 if (border_status & BORDER_BOTTOM_DIRTY)
1008 pixman_region32_union_rect(damage, damage,
1009 0, full_height - bottom->height,
1010 full_width, bottom->height);
1011}
1012
1013static void
Jason Ekstrande5512d42014-02-04 21:36:38 -06001014output_get_damage(struct weston_output *output,
1015 pixman_region32_t *buffer_damage, uint32_t *border_damage)
Ander Conselvan de Oliveira1c169ff2013-03-05 17:30:30 +02001016{
1017 struct gl_output_state *go = get_output_state(output);
1018 struct gl_renderer *gr = get_renderer(output->compositor);
1019 EGLint buffer_age = 0;
1020 EGLBoolean ret;
1021 int i;
1022
1023 if (gr->has_egl_buffer_age) {
1024 ret = eglQuerySurface(gr->egl_display, go->egl_surface,
1025 EGL_BUFFER_AGE_EXT, &buffer_age);
1026 if (ret == EGL_FALSE) {
1027 weston_log("buffer age query failed.\n");
1028 gl_renderer_print_egl_error_state();
1029 }
1030 }
1031
Jason Ekstrande5512d42014-02-04 21:36:38 -06001032 if (buffer_age == 0 || buffer_age - 1 > BUFFER_DAMAGE_COUNT) {
Ander Conselvan de Oliveira1c169ff2013-03-05 17:30:30 +02001033 pixman_region32_copy(buffer_damage, &output->region);
Jason Ekstrande5512d42014-02-04 21:36:38 -06001034 *border_damage = BORDER_ALL_DIRTY;
1035 } else {
Ander Conselvan de Oliveira1c169ff2013-03-05 17:30:30 +02001036 for (i = 0; i < buffer_age - 1; i++)
Derek Foreman4c582662014-10-09 18:39:44 -05001037 *border_damage |= go->border_damage[(go->buffer_damage_index + i) % BUFFER_DAMAGE_COUNT];
Jason Ekstrande5512d42014-02-04 21:36:38 -06001038
1039 if (*border_damage & BORDER_SIZE_CHANGED) {
1040 /* If we've had a resize, we have to do a full
1041 * repaint. */
1042 *border_damage |= BORDER_ALL_DIRTY;
1043 pixman_region32_copy(buffer_damage, &output->region);
1044 } else {
1045 for (i = 0; i < buffer_age - 1; i++)
1046 pixman_region32_union(buffer_damage,
1047 buffer_damage,
Derek Foreman4c582662014-10-09 18:39:44 -05001048 &go->buffer_damage[(go->buffer_damage_index + i) % BUFFER_DAMAGE_COUNT]);
Jason Ekstrande5512d42014-02-04 21:36:38 -06001049 }
1050 }
Ander Conselvan de Oliveira1c169ff2013-03-05 17:30:30 +02001051}
1052
1053static void
1054output_rotate_damage(struct weston_output *output,
Jason Ekstrande5512d42014-02-04 21:36:38 -06001055 pixman_region32_t *output_damage,
1056 enum gl_border_status border_status)
Ander Conselvan de Oliveira1c169ff2013-03-05 17:30:30 +02001057{
1058 struct gl_output_state *go = get_output_state(output);
1059 struct gl_renderer *gr = get_renderer(output->compositor);
Ander Conselvan de Oliveira1c169ff2013-03-05 17:30:30 +02001060
1061 if (!gr->has_egl_buffer_age)
1062 return;
1063
Derek Foreman4c582662014-10-09 18:39:44 -05001064 go->buffer_damage_index += BUFFER_DAMAGE_COUNT - 1;
1065 go->buffer_damage_index %= BUFFER_DAMAGE_COUNT;
Ander Conselvan de Oliveira1c169ff2013-03-05 17:30:30 +02001066
Derek Foreman4c582662014-10-09 18:39:44 -05001067 pixman_region32_copy(&go->buffer_damage[go->buffer_damage_index], output_damage);
1068 go->border_damage[go->buffer_damage_index] = border_status;
Ander Conselvan de Oliveira1c169ff2013-03-05 17:30:30 +02001069}
1070
Derek Foremanc4cfe852015-05-15 12:12:40 -05001071/* NOTE: We now allow falling back to ARGB gl visuals when XRGB is
1072 * unavailable, so we're assuming the background has no transparency
1073 * and that everything with a blend, like drop shadows, will have something
1074 * opaque (like the background) drawn underneath it.
1075 *
1076 * Depending on the underlying hardware, violating that assumption could
1077 * result in seeing through to another display plane.
1078 */
Ander Conselvan de Oliveira1c169ff2013-03-05 17:30:30 +02001079static void
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01001080gl_renderer_repaint_output(struct weston_output *output,
Kristian Høgsbergd7c17262012-09-05 21:54:15 -04001081 pixman_region32_t *output_damage)
1082{
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01001083 struct gl_output_state *go = get_output_state(output);
Kristian Høgsbergd7c17262012-09-05 21:54:15 -04001084 struct weston_compositor *compositor = output->compositor;
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01001085 struct gl_renderer *gr = get_renderer(compositor);
Kristian Høgsbergd7c17262012-09-05 21:54:15 -04001086 EGLBoolean ret;
1087 static int errored;
Jason Ekstrand8e96f9e2014-02-04 21:36:39 -06001088#ifdef EGL_EXT_swap_buffers_with_damage
1089 int i, nrects, buffer_height;
1090 EGLint *egl_damage, *d;
1091 pixman_box32_t *rects;
1092#endif
Ander Conselvan de Oliveira1c169ff2013-03-05 17:30:30 +02001093 pixman_region32_t buffer_damage, total_damage;
Jason Ekstrande5512d42014-02-04 21:36:38 -06001094 enum gl_border_status border_damage = BORDER_STATUS_CLEAN;
Kristian Høgsbergd7c17262012-09-05 21:54:15 -04001095
Jason Ekstrandae0c6e32014-10-16 10:55:20 -05001096 if (use_output(output) < 0)
1097 return;
1098
Jason Ekstrand00b84282013-10-27 22:24:59 -05001099 /* Calculate the viewport */
1100 glViewport(go->borders[GL_RENDERER_BORDER_LEFT].width,
1101 go->borders[GL_RENDERER_BORDER_BOTTOM].height,
1102 output->current_mode->width,
1103 output->current_mode->height);
Kristian Høgsbergd7c17262012-09-05 21:54:15 -04001104
Jason Ekstrandfb23df72014-10-16 10:55:21 -05001105 /* Calculate the global GL matrix */
1106 go->output_matrix = output->matrix;
1107 weston_matrix_translate(&go->output_matrix,
1108 -(output->current_mode->width / 2.0),
1109 -(output->current_mode->height / 2.0), 0);
1110 weston_matrix_scale(&go->output_matrix,
1111 2.0 / output->current_mode->width,
1112 -2.0 / output->current_mode->height, 1);
1113
Kristian Høgsbergd7c17262012-09-05 21:54:15 -04001114 /* if debugging, redraw everything outside the damage to clean up
1115 * debug lines from the previous draw on this buffer:
1116 */
Kristian Høgsberg8799d412013-05-07 10:50:09 -04001117 if (gr->fan_debug) {
Kristian Høgsbergd7c17262012-09-05 21:54:15 -04001118 pixman_region32_t undamaged;
1119 pixman_region32_init(&undamaged);
1120 pixman_region32_subtract(&undamaged, &output->region,
1121 output_damage);
Kristian Høgsberg8799d412013-05-07 10:50:09 -04001122 gr->fan_debug = 0;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001123 repaint_views(output, &undamaged);
Kristian Høgsberg8799d412013-05-07 10:50:09 -04001124 gr->fan_debug = 1;
Kristian Høgsbergd7c17262012-09-05 21:54:15 -04001125 pixman_region32_fini(&undamaged);
1126 }
1127
Ander Conselvan de Oliveirab605c062013-03-05 17:30:28 +02001128 pixman_region32_init(&total_damage);
Ander Conselvan de Oliveira1c169ff2013-03-05 17:30:30 +02001129 pixman_region32_init(&buffer_damage);
1130
Jason Ekstrande5512d42014-02-04 21:36:38 -06001131 output_get_damage(output, &buffer_damage, &border_damage);
1132 output_rotate_damage(output, output_damage, go->border_status);
Ander Conselvan de Oliveira1c169ff2013-03-05 17:30:30 +02001133
1134 pixman_region32_union(&total_damage, &buffer_damage, output_damage);
Jason Ekstrande5512d42014-02-04 21:36:38 -06001135 border_damage |= go->border_status;
Ander Conselvan de Oliveira8ea818f2012-09-14 16:12:03 +03001136
Jason Ekstranda7af7042013-10-12 22:38:11 -05001137 repaint_views(output, &total_damage);
Ander Conselvan de Oliveirab605c062013-03-05 17:30:28 +02001138
1139 pixman_region32_fini(&total_damage);
Ander Conselvan de Oliveira1c169ff2013-03-05 17:30:30 +02001140 pixman_region32_fini(&buffer_damage);
Kristian Høgsbergd7c17262012-09-05 21:54:15 -04001141
Jason Ekstrande5512d42014-02-04 21:36:38 -06001142 draw_output_borders(output, border_damage);
John Kåre Alsaker44154502012-11-13 19:10:20 +01001143
Ander Conselvan de Oliveirab8fcca92012-11-16 17:23:52 +02001144 pixman_region32_copy(&output->previous_damage, output_damage);
Kristian Høgsbergd7c17262012-09-05 21:54:15 -04001145 wl_signal_emit(&output->frame_signal, output);
1146
Jason Ekstrand8e96f9e2014-02-04 21:36:39 -06001147#ifdef EGL_EXT_swap_buffers_with_damage
1148 if (gr->swap_buffers_with_damage) {
1149 pixman_region32_init(&buffer_damage);
1150 weston_transformed_region(output->width, output->height,
1151 output->transform,
1152 output->current_scale,
1153 output_damage, &buffer_damage);
1154
1155 if (output_has_borders(output)) {
1156 pixman_region32_translate(&buffer_damage,
1157 go->borders[GL_RENDERER_BORDER_LEFT].width,
1158 go->borders[GL_RENDERER_BORDER_TOP].height);
1159 output_get_border_damage(output, go->border_status,
1160 &buffer_damage);
1161 }
1162
1163 rects = pixman_region32_rectangles(&buffer_damage, &nrects);
1164 egl_damage = malloc(nrects * 4 * sizeof(EGLint));
1165
1166 buffer_height = go->borders[GL_RENDERER_BORDER_TOP].height +
1167 output->current_mode->height +
1168 go->borders[GL_RENDERER_BORDER_BOTTOM].height;
1169
1170 d = egl_damage;
1171 for (i = 0; i < nrects; ++i) {
1172 *d++ = rects[i].x1;
1173 *d++ = buffer_height - rects[i].y2;
1174 *d++ = rects[i].x2 - rects[i].x1;
1175 *d++ = rects[i].y2 - rects[i].y1;
1176 }
1177 ret = gr->swap_buffers_with_damage(gr->egl_display,
1178 go->egl_surface,
1179 egl_damage, nrects);
1180 free(egl_damage);
1181 pixman_region32_fini(&buffer_damage);
1182 } else {
1183 ret = eglSwapBuffers(gr->egl_display, go->egl_surface);
1184 }
1185#else /* ! defined EGL_EXT_swap_buffers_with_damage */
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001186 ret = eglSwapBuffers(gr->egl_display, go->egl_surface);
Jason Ekstrand8e96f9e2014-02-04 21:36:39 -06001187#endif
1188
Kristian Høgsbergd7c17262012-09-05 21:54:15 -04001189 if (ret == EGL_FALSE && !errored) {
1190 errored = 1;
1191 weston_log("Failed in eglSwapBuffers.\n");
Pekka Paalanen326529f2012-11-27 12:25:25 +02001192 gl_renderer_print_egl_error_state();
Kristian Høgsbergd7c17262012-09-05 21:54:15 -04001193 }
1194
Jason Ekstrande5512d42014-02-04 21:36:38 -06001195 go->border_status = BORDER_STATUS_CLEAN;
Kristian Høgsbergd7c17262012-09-05 21:54:15 -04001196}
Kristian Høgsberg25894fc2012-09-05 22:06:26 -04001197
John Kåre Alsakera95b2d62012-11-13 19:10:21 +01001198static int
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01001199gl_renderer_read_pixels(struct weston_output *output,
John Kåre Alsakera95b2d62012-11-13 19:10:21 +01001200 pixman_format_code_t format, void *pixels,
1201 uint32_t x, uint32_t y,
1202 uint32_t width, uint32_t height)
1203{
1204 GLenum gl_format;
Jason Ekstrand701f6362014-04-02 19:53:59 -05001205 struct gl_output_state *go = get_output_state(output);
1206
1207 x += go->borders[GL_RENDERER_BORDER_LEFT].width;
1208 y += go->borders[GL_RENDERER_BORDER_BOTTOM].height;
John Kåre Alsakera95b2d62012-11-13 19:10:21 +01001209
1210 switch (format) {
1211 case PIXMAN_a8r8g8b8:
1212 gl_format = GL_BGRA_EXT;
1213 break;
1214 case PIXMAN_a8b8g8r8:
1215 gl_format = GL_RGBA;
1216 break;
1217 default:
1218 return -1;
1219 }
1220
1221 if (use_output(output) < 0)
1222 return -1;
1223
1224 glPixelStorei(GL_PACK_ALIGNMENT, 1);
1225 glReadPixels(x, y, width, height, gl_format,
1226 GL_UNSIGNED_BYTE, pixels);
1227
1228 return 0;
1229}
1230
Kristian Høgsbergfa1be022012-09-05 22:49:55 -04001231static void
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01001232gl_renderer_flush_damage(struct weston_surface *surface)
Kristian Høgsbergb1fd2d62012-09-05 22:13:58 -04001233{
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01001234 struct gl_renderer *gr = get_renderer(surface->compositor);
1235 struct gl_surface_state *gs = get_surface_state(surface);
Jason Ekstrand6bd62942013-06-20 20:38:23 -05001236 struct weston_buffer *buffer = gs->buffer_ref.buffer;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001237 struct weston_view *view;
Derek Foreman97746792015-11-18 16:32:28 -06001238 bool texture_used;
John Kåre Alsaker75cc5712012-11-13 19:10:26 +01001239
Kristian Høgsbergce7a5d82013-08-07 09:55:07 -07001240#ifdef GL_EXT_unpack_subimage
Kristian Høgsbergb1fd2d62012-09-05 22:13:58 -04001241 pixman_box32_t *rectangles;
1242 void *data;
1243 int i, n;
1244#endif
1245
Pekka Paalanen81ee3f52012-12-04 15:58:16 +02001246 pixman_region32_union(&gs->texture_damage,
1247 &gs->texture_damage, &surface->damage);
Pekka Paalanenbcdd5792012-11-07 12:25:13 +02001248
Pekka Paalanenfb003d32012-12-04 15:58:13 +02001249 if (!buffer)
1250 return;
1251
Pekka Paalanenbcdd5792012-11-07 12:25:13 +02001252 /* Avoid upload, if the texture won't be used this time.
Pekka Paalanenfb003d32012-12-04 15:58:13 +02001253 * We still accumulate the damage in texture_damage, and
1254 * hold the reference to the buffer, in case the surface
1255 * migrates back to the primary plane.
Pekka Paalanenbcdd5792012-11-07 12:25:13 +02001256 */
Derek Foreman97746792015-11-18 16:32:28 -06001257 texture_used = false;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001258 wl_list_for_each(view, &surface->views, surface_link) {
1259 if (view->plane == &surface->compositor->primary_plane) {
Derek Foreman97746792015-11-18 16:32:28 -06001260 texture_used = true;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001261 break;
1262 }
1263 }
1264 if (!texture_used)
Pekka Paalanenbcdd5792012-11-07 12:25:13 +02001265 return;
1266
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02001267 if (!pixman_region32_not_empty(&gs->texture_damage) &&
1268 !gs->needs_full_upload)
Pekka Paalanenfb003d32012-12-04 15:58:13 +02001269 goto done;
Pekka Paalanenbcdd5792012-11-07 12:25:13 +02001270
John Kåre Alsaker75cc5712012-11-13 19:10:26 +01001271 glBindTexture(GL_TEXTURE_2D, gs->textures[0]);
Kristian Høgsbergb1fd2d62012-09-05 22:13:58 -04001272
John Kåre Alsaker320711d2012-11-13 19:10:27 +01001273 if (!gr->has_unpack_subimage) {
Neil Robertse5051712013-11-13 15:44:06 +00001274 wl_shm_buffer_begin_access(buffer->shm_buffer);
Neil Roberts4d085e72014-04-07 15:01:01 +01001275 glTexImage2D(GL_TEXTURE_2D, 0, gs->gl_format,
Pekka Paalanen68033ac2012-12-04 15:58:15 +02001276 gs->pitch, buffer->height, 0,
Neil Roberts4d085e72014-04-07 15:01:01 +01001277 gs->gl_format, gs->gl_pixel_type,
Jason Ekstrand6bd62942013-06-20 20:38:23 -05001278 wl_shm_buffer_get_data(buffer->shm_buffer));
Neil Robertse5051712013-11-13 15:44:06 +00001279 wl_shm_buffer_end_access(buffer->shm_buffer);
Kristian Høgsbergb1fd2d62012-09-05 22:13:58 -04001280
Pekka Paalanenbcdd5792012-11-07 12:25:13 +02001281 goto done;
Kristian Høgsbergb1fd2d62012-09-05 22:13:58 -04001282 }
1283
Kristian Høgsbergce7a5d82013-08-07 09:55:07 -07001284#ifdef GL_EXT_unpack_subimage
1285 glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, gs->pitch);
Jason Ekstrand6bd62942013-06-20 20:38:23 -05001286 data = wl_shm_buffer_get_data(buffer->shm_buffer);
Ander Conselvan de Oliveira6be5f432013-06-07 16:52:45 +03001287
1288 if (gs->needs_full_upload) {
Kristian Høgsbergce7a5d82013-08-07 09:55:07 -07001289 glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, 0);
1290 glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, 0);
Neil Robertse5051712013-11-13 15:44:06 +00001291 wl_shm_buffer_begin_access(buffer->shm_buffer);
Neil Roberts4d085e72014-04-07 15:01:01 +01001292 glTexImage2D(GL_TEXTURE_2D, 0, gs->gl_format,
Neil Roberts39a443f2014-04-04 16:24:54 +01001293 gs->pitch, buffer->height, 0,
Neil Roberts4d085e72014-04-07 15:01:01 +01001294 gs->gl_format, gs->gl_pixel_type, data);
Neil Robertse5051712013-11-13 15:44:06 +00001295 wl_shm_buffer_end_access(buffer->shm_buffer);
Ander Conselvan de Oliveira6be5f432013-06-07 16:52:45 +03001296 goto done;
1297 }
1298
Pekka Paalanen81ee3f52012-12-04 15:58:16 +02001299 rectangles = pixman_region32_rectangles(&gs->texture_damage, &n);
Neil Robertse5051712013-11-13 15:44:06 +00001300 wl_shm_buffer_begin_access(buffer->shm_buffer);
Kristian Høgsbergb1fd2d62012-09-05 22:13:58 -04001301 for (i = 0; i < n; i++) {
Ander Conselvan de Oliveira0396ba22012-11-28 17:10:26 +02001302 pixman_box32_t r;
1303
1304 r = weston_surface_to_buffer_rect(surface, rectangles[i]);
1305
Kristian Høgsbergce7a5d82013-08-07 09:55:07 -07001306 glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, r.x1);
1307 glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, r.y1);
Ander Conselvan de Oliveira0396ba22012-11-28 17:10:26 +02001308 glTexSubImage2D(GL_TEXTURE_2D, 0, r.x1, r.y1,
1309 r.x2 - r.x1, r.y2 - r.y1,
Neil Roberts4d085e72014-04-07 15:01:01 +01001310 gs->gl_format, gs->gl_pixel_type, data);
Kristian Høgsbergb1fd2d62012-09-05 22:13:58 -04001311 }
Neil Robertse5051712013-11-13 15:44:06 +00001312 wl_shm_buffer_end_access(buffer->shm_buffer);
Kristian Høgsbergb1fd2d62012-09-05 22:13:58 -04001313#endif
Pekka Paalanenbcdd5792012-11-07 12:25:13 +02001314
1315done:
Pekka Paalanen81ee3f52012-12-04 15:58:16 +02001316 pixman_region32_fini(&gs->texture_damage);
1317 pixman_region32_init(&gs->texture_damage);
Derek Foreman4c11fe72015-11-18 16:32:27 -06001318 gs->needs_full_upload = false;
Pekka Paalanenfb003d32012-12-04 15:58:13 +02001319
1320 weston_buffer_reference(&gs->buffer_ref, NULL);
Kristian Høgsbergb1fd2d62012-09-05 22:13:58 -04001321}
1322
Kristian Høgsbergb7b77e62012-09-05 22:38:18 -04001323static void
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01001324ensure_textures(struct gl_surface_state *gs, int num_textures)
Kristian Høgsbergb7b77e62012-09-05 22:38:18 -04001325{
1326 int i;
1327
John Kåre Alsaker75cc5712012-11-13 19:10:26 +01001328 if (num_textures <= gs->num_textures)
Kristian Høgsbergb7b77e62012-09-05 22:38:18 -04001329 return;
1330
John Kåre Alsaker75cc5712012-11-13 19:10:26 +01001331 for (i = gs->num_textures; i < num_textures; i++) {
1332 glGenTextures(1, &gs->textures[i]);
1333 glBindTexture(gs->target, gs->textures[i]);
1334 glTexParameteri(gs->target,
Kristian Høgsbergb7b77e62012-09-05 22:38:18 -04001335 GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
John Kåre Alsaker75cc5712012-11-13 19:10:26 +01001336 glTexParameteri(gs->target,
Kristian Høgsbergb7b77e62012-09-05 22:38:18 -04001337 GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1338 }
John Kåre Alsaker75cc5712012-11-13 19:10:26 +01001339 gs->num_textures = num_textures;
1340 glBindTexture(gs->target, 0);
Kristian Høgsbergb7b77e62012-09-05 22:38:18 -04001341}
1342
Kristian Høgsbergfa1be022012-09-05 22:49:55 -04001343static void
Ander Conselvan de Oliveira047e9b92013-06-07 16:52:46 +03001344gl_renderer_attach_shm(struct weston_surface *es, struct weston_buffer *buffer,
1345 struct wl_shm_buffer *shm_buffer)
1346{
1347 struct weston_compositor *ec = es->compositor;
1348 struct gl_renderer *gr = get_renderer(ec);
1349 struct gl_surface_state *gs = get_surface_state(es);
Neil Roberts4d085e72014-04-07 15:01:01 +01001350 GLenum gl_format, gl_pixel_type;
Tomeu Vizoso12072b62013-08-06 20:05:55 +02001351 int pitch;
Ander Conselvan de Oliveira047e9b92013-06-07 16:52:46 +03001352
1353 buffer->shm_buffer = shm_buffer;
1354 buffer->width = wl_shm_buffer_get_width(shm_buffer);
1355 buffer->height = wl_shm_buffer_get_height(shm_buffer);
1356
Tomeu Vizoso12072b62013-08-06 20:05:55 +02001357 switch (wl_shm_buffer_get_format(shm_buffer)) {
1358 case WL_SHM_FORMAT_XRGB8888:
1359 gs->shader = &gr->texture_shader_rgbx;
1360 pitch = wl_shm_buffer_get_stride(shm_buffer) / 4;
Neil Roberts4d085e72014-04-07 15:01:01 +01001361 gl_format = GL_BGRA_EXT;
1362 gl_pixel_type = GL_UNSIGNED_BYTE;
Tomeu Vizoso12072b62013-08-06 20:05:55 +02001363 break;
1364 case WL_SHM_FORMAT_ARGB8888:
1365 gs->shader = &gr->texture_shader_rgba;
1366 pitch = wl_shm_buffer_get_stride(shm_buffer) / 4;
Neil Roberts4d085e72014-04-07 15:01:01 +01001367 gl_format = GL_BGRA_EXT;
1368 gl_pixel_type = GL_UNSIGNED_BYTE;
Tomeu Vizoso12072b62013-08-06 20:05:55 +02001369 break;
1370 case WL_SHM_FORMAT_RGB565:
1371 gs->shader = &gr->texture_shader_rgbx;
1372 pitch = wl_shm_buffer_get_stride(shm_buffer) / 2;
Neil Roberts4d085e72014-04-07 15:01:01 +01001373 gl_format = GL_RGB;
1374 gl_pixel_type = GL_UNSIGNED_SHORT_5_6_5;
Tomeu Vizoso12072b62013-08-06 20:05:55 +02001375 break;
1376 default:
Neil Roberts4d085e72014-04-07 15:01:01 +01001377 weston_log("warning: unknown shm buffer format: %08x\n",
1378 wl_shm_buffer_get_format(shm_buffer));
1379 return;
Tomeu Vizoso12072b62013-08-06 20:05:55 +02001380 }
1381
Ander Conselvan de Oliveira047e9b92013-06-07 16:52:46 +03001382 /* Only allocate a texture if it doesn't match existing one.
1383 * If a switch from DRM allocated buffer to a SHM buffer is
1384 * happening, we need to allocate a new texture buffer. */
Tomeu Vizoso12072b62013-08-06 20:05:55 +02001385 if (pitch != gs->pitch ||
Ander Conselvan de Oliveira047e9b92013-06-07 16:52:46 +03001386 buffer->height != gs->height ||
Neil Roberts4d085e72014-04-07 15:01:01 +01001387 gl_format != gs->gl_format ||
1388 gl_pixel_type != gs->gl_pixel_type ||
Ander Conselvan de Oliveira047e9b92013-06-07 16:52:46 +03001389 gs->buffer_type != BUFFER_TYPE_SHM) {
Tomeu Vizoso12072b62013-08-06 20:05:55 +02001390 gs->pitch = pitch;
Ander Conselvan de Oliveira047e9b92013-06-07 16:52:46 +03001391 gs->height = buffer->height;
1392 gs->target = GL_TEXTURE_2D;
Neil Roberts4d085e72014-04-07 15:01:01 +01001393 gs->gl_format = gl_format;
1394 gs->gl_pixel_type = gl_pixel_type;
Ander Conselvan de Oliveira047e9b92013-06-07 16:52:46 +03001395 gs->buffer_type = BUFFER_TYPE_SHM;
Derek Foreman4c11fe72015-11-18 16:32:27 -06001396 gs->needs_full_upload = true;
Stanislav Vorobiovbfbb8e52013-08-29 11:36:44 +04001397 gs->y_inverted = 1;
Ander Conselvan de Oliveira047e9b92013-06-07 16:52:46 +03001398
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +03001399 gs->surface = es;
1400
Ander Conselvan de Oliveira047e9b92013-06-07 16:52:46 +03001401 ensure_textures(gs, 1);
Ander Conselvan de Oliveira047e9b92013-06-07 16:52:46 +03001402 }
Ander Conselvan de Oliveira047e9b92013-06-07 16:52:46 +03001403}
1404
1405static void
1406gl_renderer_attach_egl(struct weston_surface *es, struct weston_buffer *buffer,
1407 uint32_t format)
1408{
1409 struct weston_compositor *ec = es->compositor;
1410 struct gl_renderer *gr = get_renderer(ec);
1411 struct gl_surface_state *gs = get_surface_state(es);
1412 EGLint attribs[3];
1413 int i, num_planes;
1414
1415 buffer->legacy_buffer = (struct wl_buffer *)buffer->resource;
1416 gr->query_buffer(gr->egl_display, buffer->legacy_buffer,
1417 EGL_WIDTH, &buffer->width);
1418 gr->query_buffer(gr->egl_display, buffer->legacy_buffer,
1419 EGL_HEIGHT, &buffer->height);
Stanislav Vorobiovbfbb8e52013-08-29 11:36:44 +04001420 gr->query_buffer(gr->egl_display, buffer->legacy_buffer,
1421 EGL_WAYLAND_Y_INVERTED_WL, &buffer->y_inverted);
Ander Conselvan de Oliveira047e9b92013-06-07 16:52:46 +03001422
Louis-Francis Ratté-Boulianne534defd2015-06-08 16:37:05 +03001423 for (i = 0; i < gs->num_images; i++) {
1424 egl_image_unref(gs->images[i]);
1425 gs->images[i] = NULL;
1426 }
Ander Conselvan de Oliveira047e9b92013-06-07 16:52:46 +03001427 gs->num_images = 0;
1428 gs->target = GL_TEXTURE_2D;
1429 switch (format) {
1430 case EGL_TEXTURE_RGB:
1431 case EGL_TEXTURE_RGBA:
1432 default:
1433 num_planes = 1;
1434 gs->shader = &gr->texture_shader_rgba;
1435 break;
1436 case EGL_TEXTURE_EXTERNAL_WL:
1437 num_planes = 1;
1438 gs->target = GL_TEXTURE_EXTERNAL_OES;
1439 gs->shader = &gr->texture_shader_egl_external;
1440 break;
1441 case EGL_TEXTURE_Y_UV_WL:
1442 num_planes = 2;
1443 gs->shader = &gr->texture_shader_y_uv;
1444 break;
1445 case EGL_TEXTURE_Y_U_V_WL:
1446 num_planes = 3;
1447 gs->shader = &gr->texture_shader_y_u_v;
1448 break;
1449 case EGL_TEXTURE_Y_XUXV_WL:
1450 num_planes = 2;
1451 gs->shader = &gr->texture_shader_y_xuxv;
1452 break;
1453 }
1454
1455 ensure_textures(gs, num_planes);
1456 for (i = 0; i < num_planes; i++) {
1457 attribs[0] = EGL_WAYLAND_PLANE_WL;
1458 attribs[1] = i;
1459 attribs[2] = EGL_NONE;
Louis-Francis Ratté-Boulianne534defd2015-06-08 16:37:05 +03001460 gs->images[i] = egl_image_create(gr,
Ander Conselvan de Oliveira047e9b92013-06-07 16:52:46 +03001461 EGL_WAYLAND_BUFFER_WL,
1462 buffer->legacy_buffer,
1463 attribs);
1464 if (!gs->images[i]) {
1465 weston_log("failed to create img for plane %d\n", i);
1466 continue;
1467 }
1468 gs->num_images++;
1469
1470 glActiveTexture(GL_TEXTURE0 + i);
1471 glBindTexture(gs->target, gs->textures[i]);
1472 gr->image_target_texture_2d(gs->target,
Louis-Francis Ratté-Boulianne534defd2015-06-08 16:37:05 +03001473 gs->images[i]->image);
Ander Conselvan de Oliveira047e9b92013-06-07 16:52:46 +03001474 }
1475
1476 gs->pitch = buffer->width;
1477 gs->height = buffer->height;
1478 gs->buffer_type = BUFFER_TYPE_EGL;
Stanislav Vorobiovbfbb8e52013-08-29 11:36:44 +04001479 gs->y_inverted = buffer->y_inverted;
Ander Conselvan de Oliveira047e9b92013-06-07 16:52:46 +03001480}
1481
1482static void
Pekka Paalanena3525802014-06-12 16:49:29 +03001483gl_renderer_destroy_dmabuf(struct linux_dmabuf_buffer *dmabuf)
1484{
Emmanuel Gil Peyrotb8053502016-01-11 19:04:34 +00001485 struct dmabuf_image *image = dmabuf->user_data;
Pekka Paalanena3525802014-06-12 16:49:29 +03001486
Emmanuel Gil Peyrotb8053502016-01-11 19:04:34 +00001487 dmabuf_image_destroy(image);
Pekka Paalanena3525802014-06-12 16:49:29 +03001488}
1489
1490static struct egl_image *
Emmanuel Gil Peyrotb8053502016-01-11 19:04:34 +00001491import_simple_dmabuf(struct gl_renderer *gr,
1492 struct dmabuf_attributes *attributes)
Pekka Paalanena3525802014-06-12 16:49:29 +03001493{
1494 struct egl_image *image;
1495 EGLint attribs[30];
1496 int atti = 0;
1497
Pekka Paalanena3525802014-06-12 16:49:29 +03001498 /* This requires the Mesa commit in
1499 * Mesa 10.3 (08264e5dad4df448e7718e782ad9077902089a07) or
1500 * Mesa 10.2.7 (55d28925e6109a4afd61f109e845a8a51bd17652).
1501 * Otherwise Mesa closes the fd behind our back and re-importing
1502 * will fail.
1503 * https://bugs.freedesktop.org/show_bug.cgi?id=76188
1504 */
1505
1506 attribs[atti++] = EGL_WIDTH;
Emmanuel Gil Peyrotb8053502016-01-11 19:04:34 +00001507 attribs[atti++] = attributes->width;
Pekka Paalanena3525802014-06-12 16:49:29 +03001508 attribs[atti++] = EGL_HEIGHT;
Emmanuel Gil Peyrotb8053502016-01-11 19:04:34 +00001509 attribs[atti++] = attributes->height;
Pekka Paalanena3525802014-06-12 16:49:29 +03001510 attribs[atti++] = EGL_LINUX_DRM_FOURCC_EXT;
Emmanuel Gil Peyrotb8053502016-01-11 19:04:34 +00001511 attribs[atti++] = attributes->format;
Pekka Paalanena3525802014-06-12 16:49:29 +03001512 /* XXX: Add modifier here when supported */
1513
Emmanuel Gil Peyrotb8053502016-01-11 19:04:34 +00001514 if (attributes->n_planes > 0) {
Pekka Paalanena3525802014-06-12 16:49:29 +03001515 attribs[atti++] = EGL_DMA_BUF_PLANE0_FD_EXT;
Emmanuel Gil Peyrotb8053502016-01-11 19:04:34 +00001516 attribs[atti++] = attributes->fd[0];
Pekka Paalanena3525802014-06-12 16:49:29 +03001517 attribs[atti++] = EGL_DMA_BUF_PLANE0_OFFSET_EXT;
Emmanuel Gil Peyrotb8053502016-01-11 19:04:34 +00001518 attribs[atti++] = attributes->offset[0];
Pekka Paalanena3525802014-06-12 16:49:29 +03001519 attribs[atti++] = EGL_DMA_BUF_PLANE0_PITCH_EXT;
Emmanuel Gil Peyrotb8053502016-01-11 19:04:34 +00001520 attribs[atti++] = attributes->stride[0];
Pekka Paalanena3525802014-06-12 16:49:29 +03001521 }
1522
Emmanuel Gil Peyrotb8053502016-01-11 19:04:34 +00001523 if (attributes->n_planes > 1) {
Pekka Paalanena3525802014-06-12 16:49:29 +03001524 attribs[atti++] = EGL_DMA_BUF_PLANE1_FD_EXT;
Emmanuel Gil Peyrotb8053502016-01-11 19:04:34 +00001525 attribs[atti++] = attributes->fd[1];
Pekka Paalanena3525802014-06-12 16:49:29 +03001526 attribs[atti++] = EGL_DMA_BUF_PLANE1_OFFSET_EXT;
Emmanuel Gil Peyrotb8053502016-01-11 19:04:34 +00001527 attribs[atti++] = attributes->offset[1];
Pekka Paalanena3525802014-06-12 16:49:29 +03001528 attribs[atti++] = EGL_DMA_BUF_PLANE1_PITCH_EXT;
Emmanuel Gil Peyrotb8053502016-01-11 19:04:34 +00001529 attribs[atti++] = attributes->stride[1];
Pekka Paalanena3525802014-06-12 16:49:29 +03001530 }
1531
Emmanuel Gil Peyrotb8053502016-01-11 19:04:34 +00001532 if (attributes->n_planes > 2) {
Pekka Paalanena3525802014-06-12 16:49:29 +03001533 attribs[atti++] = EGL_DMA_BUF_PLANE2_FD_EXT;
Emmanuel Gil Peyrotb8053502016-01-11 19:04:34 +00001534 attribs[atti++] = attributes->fd[2];
Pekka Paalanena3525802014-06-12 16:49:29 +03001535 attribs[atti++] = EGL_DMA_BUF_PLANE2_OFFSET_EXT;
Emmanuel Gil Peyrotb8053502016-01-11 19:04:34 +00001536 attribs[atti++] = attributes->offset[2];
Pekka Paalanena3525802014-06-12 16:49:29 +03001537 attribs[atti++] = EGL_DMA_BUF_PLANE2_PITCH_EXT;
Emmanuel Gil Peyrotb8053502016-01-11 19:04:34 +00001538 attribs[atti++] = attributes->stride[2];
Pekka Paalanena3525802014-06-12 16:49:29 +03001539 }
1540
1541 attribs[atti++] = EGL_NONE;
1542
1543 image = egl_image_create(gr, EGL_LINUX_DMA_BUF_EXT, NULL,
1544 attribs);
1545
Emmanuel Gil Peyrotb8053502016-01-11 19:04:34 +00001546 return image;
1547}
Pekka Paalanena3525802014-06-12 16:49:29 +03001548
Emmanuel Gil Peyrotbc35fda2016-01-11 19:04:35 +00001549/* The kernel header drm_fourcc.h defines the DRM formats below. We duplicate
1550 * some of the definitions here so that building Weston won't require
1551 * bleeding-edge kernel headers.
1552 */
1553#ifndef DRM_FORMAT_R8
1554#define DRM_FORMAT_R8 fourcc_code('R', '8', ' ', ' ') /* [7:0] R */
1555#endif
1556
1557#ifndef DRM_FORMAT_GR88
1558#define DRM_FORMAT_GR88 fourcc_code('G', 'R', '8', '8') /* [15:0] G:R 8:8 little endian */
1559#endif
1560
1561struct yuv_format_descriptor yuv_formats[] = {
1562 {
1563 .format = DRM_FORMAT_YUYV,
1564 .input_planes = 1,
1565 .output_planes = 2,
1566 .texture_type = EGL_TEXTURE_Y_XUXV_WL,
1567 {{
1568 .width_divisor = 1,
1569 .height_divisor = 1,
1570 .format = DRM_FORMAT_GR88,
1571 .plane_index = 0
1572 }, {
1573 .width_divisor = 2,
1574 .height_divisor = 1,
1575 .format = DRM_FORMAT_ARGB8888,
1576 .plane_index = 0
1577 }}
1578 }, {
1579 .format = DRM_FORMAT_NV12,
1580 .input_planes = 2,
1581 .output_planes = 2,
1582 .texture_type = EGL_TEXTURE_Y_UV_WL,
1583 {{
1584 .width_divisor = 1,
1585 .height_divisor = 1,
1586 .format = DRM_FORMAT_R8,
1587 .plane_index = 0
1588 }, {
1589 .width_divisor = 2,
1590 .height_divisor = 2,
1591 .format = DRM_FORMAT_GR88,
1592 .plane_index = 1
1593 }}
1594 }, {
1595 .format = DRM_FORMAT_YUV420,
1596 .input_planes = 3,
1597 .output_planes = 3,
1598 .texture_type = EGL_TEXTURE_Y_U_V_WL,
1599 {{
1600 .width_divisor = 1,
1601 .height_divisor = 1,
1602 .format = DRM_FORMAT_R8,
1603 .plane_index = 0
1604 }, {
1605 .width_divisor = 2,
1606 .height_divisor = 2,
1607 .format = DRM_FORMAT_R8,
1608 .plane_index = 1
1609 }, {
1610 .width_divisor = 2,
1611 .height_divisor = 2,
1612 .format = DRM_FORMAT_R8,
1613 .plane_index = 2
1614 }}
1615 }
1616};
1617
1618static struct egl_image *
1619import_dmabuf_single_plane(struct gl_renderer *gr,
1620 const struct dmabuf_attributes *attributes,
1621 struct yuv_plane_descriptor *descriptor)
1622{
1623 struct dmabuf_attributes plane;
1624 struct egl_image *image;
1625 char fmt[4];
1626
1627 plane.width = attributes->width / descriptor->width_divisor;
1628 plane.height = attributes->height / descriptor->height_divisor;
1629 plane.format = descriptor->format;
1630 plane.n_planes = 1;
1631 plane.fd[0] = attributes->fd[descriptor->plane_index];
1632 plane.offset[0] = attributes->offset[descriptor->plane_index];
1633 plane.stride[0] = attributes->stride[descriptor->plane_index];
1634 plane.modifier[0] = attributes->modifier[descriptor->plane_index];
1635
1636 image = import_simple_dmabuf(gr, &plane);
1637 if (!image) {
1638 weston_log("Failed to import plane %d as %.4s\n",
1639 descriptor->plane_index,
1640 dump_format(descriptor->format, fmt));
1641 return NULL;
1642 }
1643
1644 return image;
1645}
1646
1647static bool
1648import_yuv_dmabuf(struct gl_renderer *gr,
1649 struct dmabuf_image *image)
1650{
1651 unsigned i;
1652 int j;
1653 int ret;
1654 struct yuv_format_descriptor *format = NULL;
1655 struct dmabuf_attributes *attributes = &image->dmabuf->attributes;
1656 char fmt[4];
1657
1658 for (i = 0; i < ARRAY_LENGTH(yuv_formats); ++i) {
1659 if (yuv_formats[i].format == attributes->format) {
1660 format = &yuv_formats[i];
1661 break;
1662 }
1663 }
1664
1665 if (!format) {
1666 weston_log("Error during import, and no known conversion for format "
1667 "%.4s in the renderer",
1668 dump_format(attributes->format, fmt));
1669 return false;
1670 }
1671
1672 if (attributes->n_planes != format->input_planes) {
1673 weston_log("%.4s dmabuf must contain %d plane%s (%d provided)",
1674 dump_format(format->format, fmt),
1675 format->input_planes,
1676 (format->input_planes > 1) ? "s" : "",
1677 attributes->n_planes);
1678 return false;
1679 }
1680
1681 for (j = 0; j < format->output_planes; ++j) {
1682 image->images[j] = import_dmabuf_single_plane(gr, attributes,
1683 &format->plane[j]);
1684 if (!image->images[j]) {
1685 while (j) {
1686 ret = egl_image_unref(image->images[--j]);
1687 assert(ret == 0);
1688 }
1689 return false;
1690 }
1691 }
1692
1693 image->num_images = format->output_planes;
1694
1695 switch (format->texture_type) {
1696 case EGL_TEXTURE_Y_XUXV_WL:
1697 image->shader = &gr->texture_shader_y_xuxv;
1698 break;
1699 case EGL_TEXTURE_Y_UV_WL:
1700 image->shader = &gr->texture_shader_y_uv;
1701 break;
1702 case EGL_TEXTURE_Y_U_V_WL:
1703 image->shader = &gr->texture_shader_y_u_v;
1704 break;
1705 default:
1706 assert(false);
1707 }
1708
1709 return true;
1710}
1711
1712static GLenum
1713choose_texture_target(struct dmabuf_attributes *attributes)
1714{
1715 if (attributes->n_planes > 1)
1716 return GL_TEXTURE_EXTERNAL_OES;
1717
1718 switch (attributes->format & ~DRM_FORMAT_BIG_ENDIAN) {
1719 case DRM_FORMAT_YUYV:
1720 case DRM_FORMAT_YVYU:
1721 case DRM_FORMAT_UYVY:
1722 case DRM_FORMAT_VYUY:
1723 case DRM_FORMAT_AYUV:
1724 return GL_TEXTURE_EXTERNAL_OES;
1725 default:
1726 return GL_TEXTURE_2D;
1727 }
1728}
1729
Emmanuel Gil Peyrotb8053502016-01-11 19:04:34 +00001730static struct dmabuf_image *
1731import_dmabuf(struct gl_renderer *gr,
1732 struct linux_dmabuf_buffer *dmabuf)
1733{
1734 struct egl_image *egl_image;
1735 struct dmabuf_image *image;
Emmanuel Gil Peyrotb8053502016-01-11 19:04:34 +00001736
1737 image = dmabuf_image_create();
Pekka Paalanena3525802014-06-12 16:49:29 +03001738 image->dmabuf = dmabuf;
Emmanuel Gil Peyrotbc35fda2016-01-11 19:04:35 +00001739
1740 egl_image = import_simple_dmabuf(gr, &dmabuf->attributes);
1741 if (egl_image) {
1742 image->num_images = 1;
1743 image->images[0] = egl_image;
1744 image->import_type = IMPORT_TYPE_DIRECT;
1745 image->target = choose_texture_target(&dmabuf->attributes);
1746
1747 switch (image->target) {
1748 case GL_TEXTURE_2D:
1749 image->shader = &gr->texture_shader_rgba;
1750 break;
1751 default:
1752 image->shader = &gr->texture_shader_egl_external;
1753 }
1754 } else {
1755 if (!import_yuv_dmabuf(gr, image)) {
1756 dmabuf_image_destroy(image);
1757 return NULL;
1758 }
1759 image->import_type = IMPORT_TYPE_GL_CONVERSION;
1760 image->target = GL_TEXTURE_2D;
1761 }
Pekka Paalanena3525802014-06-12 16:49:29 +03001762
1763 return image;
1764}
1765
1766static bool
1767gl_renderer_import_dmabuf(struct weston_compositor *ec,
1768 struct linux_dmabuf_buffer *dmabuf)
1769{
1770 struct gl_renderer *gr = get_renderer(ec);
Emmanuel Gil Peyrotb8053502016-01-11 19:04:34 +00001771 struct dmabuf_image *image;
Pekka Paalanena3525802014-06-12 16:49:29 +03001772 int i;
1773
1774 assert(gr->has_dmabuf_import);
1775
Emmanuel Gil Peyrotc3996922015-11-24 19:28:24 +00001776 for (i = 0; i < dmabuf->attributes.n_planes; i++) {
Pekka Paalanena3525802014-06-12 16:49:29 +03001777 /* EGL import does not have modifiers */
Emmanuel Gil Peyrotc3996922015-11-24 19:28:24 +00001778 if (dmabuf->attributes.modifier[i] != 0)
Pekka Paalanena3525802014-06-12 16:49:29 +03001779 return false;
1780 }
1781
1782 /* reject all flags we do not recognize or handle */
Emmanuel Gil Peyrotc3996922015-11-24 19:28:24 +00001783 if (dmabuf->attributes.flags & ~ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_Y_INVERT)
Pekka Paalanena3525802014-06-12 16:49:29 +03001784 return false;
1785
1786 image = import_dmabuf(gr, dmabuf);
1787 if (!image)
1788 return false;
1789
Emmanuel Gil Peyrotb8053502016-01-11 19:04:34 +00001790 wl_list_insert(&gr->dmabuf_images, &image->link);
1791 linux_dmabuf_buffer_set_user_data(dmabuf, image,
1792 gl_renderer_destroy_dmabuf);
Pekka Paalanena3525802014-06-12 16:49:29 +03001793
1794 return true;
1795}
1796
Emmanuel Gil Peyrotbc35fda2016-01-11 19:04:35 +00001797static bool
1798import_known_dmabuf(struct gl_renderer *gr,
1799 struct dmabuf_image *image)
Pekka Paalanena3525802014-06-12 16:49:29 +03001800{
Emmanuel Gil Peyrotbc35fda2016-01-11 19:04:35 +00001801 switch (image->import_type) {
1802 case IMPORT_TYPE_DIRECT:
1803 image->images[0] = import_simple_dmabuf(gr, &image->dmabuf->attributes);
1804 if (!image->images[0])
1805 return false;
1806 break;
Pekka Paalanena3525802014-06-12 16:49:29 +03001807
Emmanuel Gil Peyrotbc35fda2016-01-11 19:04:35 +00001808 case IMPORT_TYPE_GL_CONVERSION:
1809 if (!import_yuv_dmabuf(gr, image))
1810 return false;
1811 break;
1812
Pekka Paalanena3525802014-06-12 16:49:29 +03001813 default:
Emmanuel Gil Peyrotbc35fda2016-01-11 19:04:35 +00001814 weston_log("Invalid import type for dmabuf\n");
1815 return false;
Pekka Paalanena3525802014-06-12 16:49:29 +03001816 }
Emmanuel Gil Peyrotbc35fda2016-01-11 19:04:35 +00001817
1818 return true;
Pekka Paalanena3525802014-06-12 16:49:29 +03001819}
1820
1821static void
1822gl_renderer_attach_dmabuf(struct weston_surface *surface,
1823 struct weston_buffer *buffer,
1824 struct linux_dmabuf_buffer *dmabuf)
1825{
1826 struct gl_renderer *gr = get_renderer(surface->compositor);
1827 struct gl_surface_state *gs = get_surface_state(surface);
Emmanuel Gil Peyrotb8053502016-01-11 19:04:34 +00001828 struct dmabuf_image *image;
Pekka Paalanena3525802014-06-12 16:49:29 +03001829 int i;
Emmanuel Gil Peyrotb8053502016-01-11 19:04:34 +00001830 int ret;
Pekka Paalanena3525802014-06-12 16:49:29 +03001831
1832 if (!gr->has_dmabuf_import) {
1833 linux_dmabuf_buffer_send_server_error(dmabuf,
1834 "EGL dmabuf import not supported");
1835 return;
1836 }
1837
Emmanuel Gil Peyrotc3996922015-11-24 19:28:24 +00001838 buffer->width = dmabuf->attributes.width;
1839 buffer->height = dmabuf->attributes.height;
Pekka Paalanena3525802014-06-12 16:49:29 +03001840 buffer->y_inverted =
Emmanuel Gil Peyrotc3996922015-11-24 19:28:24 +00001841 !!(dmabuf->attributes.flags & ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_Y_INVERT);
Pekka Paalanena3525802014-06-12 16:49:29 +03001842
1843 for (i = 0; i < gs->num_images; i++)
1844 egl_image_unref(gs->images[i]);
1845 gs->num_images = 0;
1846
Pekka Paalanena3525802014-06-12 16:49:29 +03001847 /*
1848 * We try to always hold an imported EGLImage from the dmabuf
1849 * to prevent the client from preventing re-imports. But, we also
1850 * need to re-import every time the contents may change because
1851 * GL driver's caching may need flushing.
1852 *
1853 * Here we release the cache reference which has to be final.
1854 */
Emmanuel Gil Peyrotb8053502016-01-11 19:04:34 +00001855 image = linux_dmabuf_buffer_get_user_data(dmabuf);
Pekka Paalanena3525802014-06-12 16:49:29 +03001856
Emmanuel Gil Peyrotb8053502016-01-11 19:04:34 +00001857 /* The dmabuf_image should have been created during the import */
1858 assert(image != NULL);
1859
1860 for (i = 0; i < image->num_images; ++i) {
1861 ret = egl_image_unref(image->images[i]);
Pekka Paalanena3525802014-06-12 16:49:29 +03001862 assert(ret == 0);
1863 }
1864
Emmanuel Gil Peyrotbc35fda2016-01-11 19:04:35 +00001865 if (!import_known_dmabuf(gr, image)) {
1866 linux_dmabuf_buffer_send_server_error(dmabuf, "EGL dmabuf import failed");
1867 return;
Pekka Paalanena3525802014-06-12 16:49:29 +03001868 }
Pekka Paalanena3525802014-06-12 16:49:29 +03001869
Emmanuel Gil Peyrotb8053502016-01-11 19:04:34 +00001870 gs->num_images = image->num_images;
1871 for (i = 0; i < gs->num_images; ++i)
1872 gs->images[i] = egl_image_ref(image->images[i]);
Pekka Paalanena3525802014-06-12 16:49:29 +03001873
Emmanuel Gil Peyrotbc35fda2016-01-11 19:04:35 +00001874 gs->target = image->target;
Emmanuel Gil Peyrotb8053502016-01-11 19:04:34 +00001875 ensure_textures(gs, gs->num_images);
1876 for (i = 0; i < gs->num_images; ++i) {
1877 glActiveTexture(GL_TEXTURE0 + i);
1878 glBindTexture(gs->target, gs->textures[i]);
1879 gr->image_target_texture_2d(gs->target, gs->images[i]->image);
1880 }
Pekka Paalanena3525802014-06-12 16:49:29 +03001881
Emmanuel Gil Peyrotbc35fda2016-01-11 19:04:35 +00001882 gs->shader = image->shader;
Pekka Paalanena3525802014-06-12 16:49:29 +03001883 gs->pitch = buffer->width;
1884 gs->height = buffer->height;
1885 gs->buffer_type = BUFFER_TYPE_EGL;
1886 gs->y_inverted = buffer->y_inverted;
1887}
1888
1889static void
Jason Ekstrand6bd62942013-06-20 20:38:23 -05001890gl_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
Kristian Høgsbergb7b77e62012-09-05 22:38:18 -04001891{
1892 struct weston_compositor *ec = es->compositor;
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01001893 struct gl_renderer *gr = get_renderer(ec);
1894 struct gl_surface_state *gs = get_surface_state(es);
Jason Ekstrand6bd62942013-06-20 20:38:23 -05001895 struct wl_shm_buffer *shm_buffer;
Pekka Paalanena3525802014-06-12 16:49:29 +03001896 struct linux_dmabuf_buffer *dmabuf;
Ander Conselvan de Oliveira047e9b92013-06-07 16:52:46 +03001897 EGLint format;
1898 int i;
Kristian Høgsbergb7b77e62012-09-05 22:38:18 -04001899
Pekka Paalanenfb003d32012-12-04 15:58:13 +02001900 weston_buffer_reference(&gs->buffer_ref, buffer);
1901
Kristian Høgsbergb7b77e62012-09-05 22:38:18 -04001902 if (!buffer) {
John Kåre Alsaker75cc5712012-11-13 19:10:26 +01001903 for (i = 0; i < gs->num_images; i++) {
Louis-Francis Ratté-Boulianne534defd2015-06-08 16:37:05 +03001904 egl_image_unref(gs->images[i]);
John Kåre Alsaker75cc5712012-11-13 19:10:26 +01001905 gs->images[i] = NULL;
Kristian Høgsbergb7b77e62012-09-05 22:38:18 -04001906 }
John Kåre Alsaker75cc5712012-11-13 19:10:26 +01001907 gs->num_images = 0;
1908 glDeleteTextures(gs->num_textures, gs->textures);
1909 gs->num_textures = 0;
Ander Conselvan de Oliveiraa9bf1612013-06-07 16:52:44 +03001910 gs->buffer_type = BUFFER_TYPE_NULL;
Stanislav Vorobiovbfbb8e52013-08-29 11:36:44 +04001911 gs->y_inverted = 1;
Kristian Høgsbergb7b77e62012-09-05 22:38:18 -04001912 return;
1913 }
1914
Jason Ekstrand6bd62942013-06-20 20:38:23 -05001915 shm_buffer = wl_shm_buffer_get(buffer->resource);
Jason Ekstrand6bd62942013-06-20 20:38:23 -05001916
Ander Conselvan de Oliveira047e9b92013-06-07 16:52:46 +03001917 if (shm_buffer)
1918 gl_renderer_attach_shm(es, buffer, shm_buffer);
Kristian Høgsberg47229392013-08-07 11:59:54 -07001919 else if (gr->query_buffer(gr->egl_display, (void *) buffer->resource,
Ander Conselvan de Oliveira047e9b92013-06-07 16:52:46 +03001920 EGL_TEXTURE_FORMAT, &format))
1921 gl_renderer_attach_egl(es, buffer, format);
Pekka Paalanena3525802014-06-12 16:49:29 +03001922 else if ((dmabuf = linux_dmabuf_buffer_get(buffer->resource)))
1923 gl_renderer_attach_dmabuf(es, buffer, dmabuf);
Ander Conselvan de Oliveira047e9b92013-06-07 16:52:46 +03001924 else {
Kristian Høgsbergb7b77e62012-09-05 22:38:18 -04001925 weston_log("unhandled buffer type!\n");
Pekka Paalanenfb003d32012-12-04 15:58:13 +02001926 weston_buffer_reference(&gs->buffer_ref, NULL);
Ander Conselvan de Oliveiraa9bf1612013-06-07 16:52:44 +03001927 gs->buffer_type = BUFFER_TYPE_NULL;
Stanislav Vorobiovbfbb8e52013-08-29 11:36:44 +04001928 gs->y_inverted = 1;
Kristian Høgsbergb7b77e62012-09-05 22:38:18 -04001929 }
1930}
1931
Kristian Høgsberg42263852012-09-06 21:59:29 -04001932static void
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01001933gl_renderer_surface_set_color(struct weston_surface *surface,
John Kåre Alsaker878f4492012-11-13 19:10:23 +01001934 float red, float green, float blue, float alpha)
1935{
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01001936 struct gl_surface_state *gs = get_surface_state(surface);
1937 struct gl_renderer *gr = get_renderer(surface->compositor);
John Kåre Alsaker878f4492012-11-13 19:10:23 +01001938
1939 gs->color[0] = red;
1940 gs->color[1] = green;
1941 gs->color[2] = blue;
1942 gs->color[3] = alpha;
Pekka Paalanenaeb917e2015-02-09 13:56:56 +02001943 gs->buffer_type = BUFFER_TYPE_SOLID;
1944 gs->pitch = 1;
1945 gs->height = 1;
John Kåre Alsaker878f4492012-11-13 19:10:23 +01001946
John Kåre Alsaker40684142012-11-13 19:10:25 +01001947 gs->shader = &gr->solid_shader;
John Kåre Alsaker878f4492012-11-13 19:10:23 +01001948}
1949
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +03001950static void
Pekka Paalaneneb35cbe2015-02-09 13:37:27 +02001951gl_renderer_surface_get_content_size(struct weston_surface *surface,
1952 int *width, int *height)
1953{
1954 struct gl_surface_state *gs = get_surface_state(surface);
1955
1956 if (gs->buffer_type == BUFFER_TYPE_NULL) {
1957 *width = 0;
1958 *height = 0;
1959 } else {
1960 *width = gs->pitch;
1961 *height = gs->height;
1962 }
1963}
1964
1965static uint32_t
1966pack_color(pixman_format_code_t format, float *c)
1967{
1968 uint8_t r = round(c[0] * 255.0f);
1969 uint8_t g = round(c[1] * 255.0f);
1970 uint8_t b = round(c[2] * 255.0f);
1971 uint8_t a = round(c[3] * 255.0f);
1972
1973 switch (format) {
1974 case PIXMAN_a8b8g8r8:
1975 return (a << 24) | (b << 16) | (g << 8) | r;
1976 default:
1977 assert(0);
1978 return 0;
1979 }
1980}
1981
1982static int
1983gl_renderer_surface_copy_content(struct weston_surface *surface,
1984 void *target, size_t size,
1985 int src_x, int src_y,
1986 int width, int height)
1987{
1988 static const GLfloat verts[4 * 2] = {
1989 0.0f, 0.0f,
1990 1.0f, 0.0f,
1991 1.0f, 1.0f,
1992 0.0f, 1.0f
1993 };
1994 static const GLfloat projmat_normal[16] = { /* transpose */
1995 2.0f, 0.0f, 0.0f, 0.0f,
1996 0.0f, 2.0f, 0.0f, 0.0f,
1997 0.0f, 0.0f, 1.0f, 0.0f,
1998 -1.0f, -1.0f, 0.0f, 1.0f
1999 };
2000 static const GLfloat projmat_yinvert[16] = { /* transpose */
2001 2.0f, 0.0f, 0.0f, 0.0f,
2002 0.0f, -2.0f, 0.0f, 0.0f,
2003 0.0f, 0.0f, 1.0f, 0.0f,
2004 -1.0f, 1.0f, 0.0f, 1.0f
2005 };
2006 const pixman_format_code_t format = PIXMAN_a8b8g8r8;
2007 const size_t bytespp = 4; /* PIXMAN_a8b8g8r8 */
2008 const GLenum gl_format = GL_RGBA; /* PIXMAN_a8b8g8r8 little-endian */
2009 struct gl_renderer *gr = get_renderer(surface->compositor);
2010 struct gl_surface_state *gs = get_surface_state(surface);
2011 int cw, ch;
2012 GLuint fbo;
2013 GLuint tex;
2014 GLenum status;
2015 const GLfloat *proj;
2016 int i;
2017
2018 gl_renderer_surface_get_content_size(surface, &cw, &ch);
2019
2020 switch (gs->buffer_type) {
2021 case BUFFER_TYPE_NULL:
2022 return -1;
2023 case BUFFER_TYPE_SOLID:
2024 *(uint32_t *)target = pack_color(format, gs->color);
2025 return 0;
2026 case BUFFER_TYPE_SHM:
2027 gl_renderer_flush_damage(surface);
2028 /* fall through */
2029 case BUFFER_TYPE_EGL:
2030 break;
2031 }
2032
2033 glGenTextures(1, &tex);
2034 glBindTexture(GL_TEXTURE_2D, tex);
2035 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, cw, ch,
2036 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
2037 glBindTexture(GL_TEXTURE_2D, 0);
2038
2039 glGenFramebuffers(1, &fbo);
2040 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
2041 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
2042 GL_TEXTURE_2D, tex, 0);
2043
2044 status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
2045 if (status != GL_FRAMEBUFFER_COMPLETE) {
2046 weston_log("%s: fbo error: %#x\n", __func__, status);
2047 glDeleteFramebuffers(1, &fbo);
2048 glDeleteTextures(1, &tex);
2049 return -1;
2050 }
2051
2052 glViewport(0, 0, cw, ch);
2053 glDisable(GL_BLEND);
2054 use_shader(gr, gs->shader);
2055 if (gs->y_inverted)
2056 proj = projmat_normal;
2057 else
2058 proj = projmat_yinvert;
2059
2060 glUniformMatrix4fv(gs->shader->proj_uniform, 1, GL_FALSE, proj);
2061 glUniform1f(gs->shader->alpha_uniform, 1.0f);
2062
2063 for (i = 0; i < gs->num_textures; i++) {
2064 glUniform1i(gs->shader->tex_uniforms[i], i);
2065
2066 glActiveTexture(GL_TEXTURE0 + i);
2067 glBindTexture(gs->target, gs->textures[i]);
2068 glTexParameteri(gs->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2069 glTexParameteri(gs->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2070 }
2071
2072 /* position: */
2073 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, verts);
2074 glEnableVertexAttribArray(0);
2075
2076 /* texcoord: */
2077 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, verts);
2078 glEnableVertexAttribArray(1);
2079
2080 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
2081
2082 glDisableVertexAttribArray(1);
2083 glDisableVertexAttribArray(0);
2084
2085 glPixelStorei(GL_PACK_ALIGNMENT, bytespp);
2086 glReadPixels(src_x, src_y, width, height, gl_format,
2087 GL_UNSIGNED_BYTE, target);
2088
2089 glDeleteFramebuffers(1, &fbo);
2090 glDeleteTextures(1, &tex);
2091
2092 return 0;
2093}
2094
2095static void
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +03002096surface_state_destroy(struct gl_surface_state *gs, struct gl_renderer *gr)
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +03002097{
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +03002098 int i;
2099
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +03002100 wl_list_remove(&gs->surface_destroy_listener.link);
2101 wl_list_remove(&gs->renderer_destroy_listener.link);
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +03002102
2103 gs->surface->renderer_state = NULL;
2104
2105 glDeleteTextures(gs->num_textures, gs->textures);
2106
2107 for (i = 0; i < gs->num_images; i++)
Louis-Francis Ratté-Boulianne534defd2015-06-08 16:37:05 +03002108 egl_image_unref(gs->images[i]);
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +03002109
2110 weston_buffer_reference(&gs->buffer_ref, NULL);
2111 pixman_region32_fini(&gs->texture_damage);
2112 free(gs);
2113}
2114
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +03002115static void
2116surface_state_handle_surface_destroy(struct wl_listener *listener, void *data)
2117{
2118 struct gl_surface_state *gs;
2119 struct gl_renderer *gr;
2120
2121 gs = container_of(listener, struct gl_surface_state,
2122 surface_destroy_listener);
2123
2124 gr = get_renderer(gs->surface->compositor);
2125
2126 surface_state_destroy(gs, gr);
2127}
2128
2129static void
2130surface_state_handle_renderer_destroy(struct wl_listener *listener, void *data)
2131{
2132 struct gl_surface_state *gs;
2133 struct gl_renderer *gr;
2134
2135 gr = data;
2136
2137 gs = container_of(listener, struct gl_surface_state,
2138 renderer_destroy_listener);
2139
2140 surface_state_destroy(gs, gr);
2141}
2142
John Kåre Alsaker878f4492012-11-13 19:10:23 +01002143static int
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01002144gl_renderer_create_surface(struct weston_surface *surface)
John Kåre Alsaker878f4492012-11-13 19:10:23 +01002145{
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01002146 struct gl_surface_state *gs;
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +03002147 struct gl_renderer *gr = get_renderer(surface->compositor);
John Kåre Alsaker878f4492012-11-13 19:10:23 +01002148
Bryce Harringtonde16d892014-11-20 22:21:57 -08002149 gs = zalloc(sizeof *gs);
2150 if (gs == NULL)
John Kåre Alsaker878f4492012-11-13 19:10:23 +01002151 return -1;
2152
Pekka Paalanen68033ac2012-12-04 15:58:15 +02002153 /* A buffer is never attached to solid color surfaces, yet
2154 * they still go through texcoord computations. Do not divide
2155 * by zero there.
2156 */
2157 gs->pitch = 1;
Stanislav Vorobiovbfbb8e52013-08-29 11:36:44 +04002158 gs->y_inverted = 1;
Pekka Paalanen68033ac2012-12-04 15:58:15 +02002159
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +03002160 gs->surface = surface;
2161
Pekka Paalanen81ee3f52012-12-04 15:58:16 +02002162 pixman_region32_init(&gs->texture_damage);
John Kåre Alsaker878f4492012-11-13 19:10:23 +01002163 surface->renderer_state = gs;
2164
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +03002165 gs->surface_destroy_listener.notify =
2166 surface_state_handle_surface_destroy;
2167 wl_signal_add(&surface->destroy_signal,
2168 &gs->surface_destroy_listener);
2169
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +03002170 gs->renderer_destroy_listener.notify =
2171 surface_state_handle_renderer_destroy;
2172 wl_signal_add(&gr->destroy_signal,
2173 &gs->renderer_destroy_listener);
2174
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02002175 if (surface->buffer_ref.buffer) {
2176 gl_renderer_attach(surface, surface->buffer_ref.buffer);
2177 gl_renderer_flush_damage(surface);
2178 }
2179
John Kåre Alsaker878f4492012-11-13 19:10:23 +01002180 return 0;
2181}
2182
Kristian Høgsberg25894fc2012-09-05 22:06:26 -04002183static const char vertex_shader[] =
2184 "uniform mat4 proj;\n"
2185 "attribute vec2 position;\n"
2186 "attribute vec2 texcoord;\n"
2187 "varying vec2 v_texcoord;\n"
2188 "void main()\n"
2189 "{\n"
2190 " gl_Position = proj * vec4(position, 0.0, 1.0);\n"
2191 " v_texcoord = texcoord;\n"
2192 "}\n";
2193
2194/* Declare common fragment shader uniforms */
2195#define FRAGMENT_CONVERT_YUV \
2196 " y *= alpha;\n" \
2197 " u *= alpha;\n" \
2198 " v *= alpha;\n" \
2199 " gl_FragColor.r = y + 1.59602678 * v;\n" \
2200 " gl_FragColor.g = y - 0.39176229 * u - 0.81296764 * v;\n" \
2201 " gl_FragColor.b = y + 2.01723214 * u;\n" \
2202 " gl_FragColor.a = alpha;\n"
2203
Ander Conselvan de Oliveira27508c22012-11-08 17:20:46 +02002204static const char fragment_debug[] =
2205 " gl_FragColor = vec4(0.0, 0.3, 0.0, 0.2) + gl_FragColor * 0.8;\n";
2206
2207static const char fragment_brace[] =
2208 "}\n";
2209
Kristian Høgsberg25894fc2012-09-05 22:06:26 -04002210static const char texture_fragment_shader_rgba[] =
2211 "precision mediump float;\n"
2212 "varying vec2 v_texcoord;\n"
2213 "uniform sampler2D tex;\n"
2214 "uniform float alpha;\n"
2215 "void main()\n"
2216 "{\n"
2217 " gl_FragColor = alpha * texture2D(tex, v_texcoord)\n;"
Ander Conselvan de Oliveira27508c22012-11-08 17:20:46 +02002218 ;
Kristian Høgsberg25894fc2012-09-05 22:06:26 -04002219
2220static const char texture_fragment_shader_rgbx[] =
2221 "precision mediump float;\n"
2222 "varying vec2 v_texcoord;\n"
2223 "uniform sampler2D tex;\n"
2224 "uniform float alpha;\n"
2225 "void main()\n"
2226 "{\n"
2227 " gl_FragColor.rgb = alpha * texture2D(tex, v_texcoord).rgb\n;"
2228 " gl_FragColor.a = alpha;\n"
Ander Conselvan de Oliveira27508c22012-11-08 17:20:46 +02002229 ;
Kristian Høgsberg25894fc2012-09-05 22:06:26 -04002230
2231static const char texture_fragment_shader_egl_external[] =
2232 "#extension GL_OES_EGL_image_external : require\n"
2233 "precision mediump float;\n"
2234 "varying vec2 v_texcoord;\n"
2235 "uniform samplerExternalOES tex;\n"
2236 "uniform float alpha;\n"
2237 "void main()\n"
2238 "{\n"
2239 " gl_FragColor = alpha * texture2D(tex, v_texcoord)\n;"
Ander Conselvan de Oliveira27508c22012-11-08 17:20:46 +02002240 ;
Kristian Høgsberg25894fc2012-09-05 22:06:26 -04002241
2242static const char texture_fragment_shader_y_uv[] =
2243 "precision mediump float;\n"
2244 "uniform sampler2D tex;\n"
2245 "uniform sampler2D tex1;\n"
2246 "varying vec2 v_texcoord;\n"
2247 "uniform float alpha;\n"
2248 "void main() {\n"
2249 " float y = 1.16438356 * (texture2D(tex, v_texcoord).x - 0.0625);\n"
2250 " float u = texture2D(tex1, v_texcoord).r - 0.5;\n"
2251 " float v = texture2D(tex1, v_texcoord).g - 0.5;\n"
2252 FRAGMENT_CONVERT_YUV
Ander Conselvan de Oliveira27508c22012-11-08 17:20:46 +02002253 ;
Kristian Høgsberg25894fc2012-09-05 22:06:26 -04002254
2255static const char texture_fragment_shader_y_u_v[] =
2256 "precision mediump float;\n"
2257 "uniform sampler2D tex;\n"
2258 "uniform sampler2D tex1;\n"
2259 "uniform sampler2D tex2;\n"
2260 "varying vec2 v_texcoord;\n"
2261 "uniform float alpha;\n"
2262 "void main() {\n"
2263 " float y = 1.16438356 * (texture2D(tex, v_texcoord).x - 0.0625);\n"
2264 " float u = texture2D(tex1, v_texcoord).x - 0.5;\n"
2265 " float v = texture2D(tex2, v_texcoord).x - 0.5;\n"
2266 FRAGMENT_CONVERT_YUV
Ander Conselvan de Oliveira27508c22012-11-08 17:20:46 +02002267 ;
Kristian Høgsberg25894fc2012-09-05 22:06:26 -04002268
2269static const char texture_fragment_shader_y_xuxv[] =
2270 "precision mediump float;\n"
2271 "uniform sampler2D tex;\n"
2272 "uniform sampler2D tex1;\n"
2273 "varying vec2 v_texcoord;\n"
2274 "uniform float alpha;\n"
2275 "void main() {\n"
2276 " float y = 1.16438356 * (texture2D(tex, v_texcoord).x - 0.0625);\n"
2277 " float u = texture2D(tex1, v_texcoord).g - 0.5;\n"
2278 " float v = texture2D(tex1, v_texcoord).a - 0.5;\n"
2279 FRAGMENT_CONVERT_YUV
Ander Conselvan de Oliveira27508c22012-11-08 17:20:46 +02002280 ;
Kristian Høgsberg25894fc2012-09-05 22:06:26 -04002281
2282static const char solid_fragment_shader[] =
2283 "precision mediump float;\n"
2284 "uniform vec4 color;\n"
2285 "uniform float alpha;\n"
2286 "void main()\n"
2287 "{\n"
2288 " gl_FragColor = alpha * color\n;"
Ander Conselvan de Oliveira27508c22012-11-08 17:20:46 +02002289 ;
Kristian Høgsberg25894fc2012-09-05 22:06:26 -04002290
2291static int
Ander Conselvan de Oliveira27508c22012-11-08 17:20:46 +02002292compile_shader(GLenum type, int count, const char **sources)
Kristian Høgsberg25894fc2012-09-05 22:06:26 -04002293{
2294 GLuint s;
2295 char msg[512];
2296 GLint status;
2297
2298 s = glCreateShader(type);
Ander Conselvan de Oliveira27508c22012-11-08 17:20:46 +02002299 glShaderSource(s, count, sources, NULL);
Kristian Høgsberg25894fc2012-09-05 22:06:26 -04002300 glCompileShader(s);
2301 glGetShaderiv(s, GL_COMPILE_STATUS, &status);
2302 if (!status) {
2303 glGetShaderInfoLog(s, sizeof msg, NULL, msg);
2304 weston_log("shader info: %s\n", msg);
2305 return GL_NONE;
2306 }
2307
2308 return s;
2309}
2310
2311static int
Ander Conselvan de Oliveira1ed73242013-05-17 14:00:40 +03002312shader_init(struct gl_shader *shader, struct gl_renderer *renderer,
Kristian Høgsberg25894fc2012-09-05 22:06:26 -04002313 const char *vertex_source, const char *fragment_source)
2314{
2315 char msg[512];
2316 GLint status;
Ander Conselvan de Oliveira27508c22012-11-08 17:20:46 +02002317 int count;
2318 const char *sources[3];
Kristian Høgsberg25894fc2012-09-05 22:06:26 -04002319
2320 shader->vertex_shader =
Ander Conselvan de Oliveira27508c22012-11-08 17:20:46 +02002321 compile_shader(GL_VERTEX_SHADER, 1, &vertex_source);
2322
2323 if (renderer->fragment_shader_debug) {
2324 sources[0] = fragment_source;
2325 sources[1] = fragment_debug;
2326 sources[2] = fragment_brace;
2327 count = 3;
2328 } else {
2329 sources[0] = fragment_source;
2330 sources[1] = fragment_brace;
2331 count = 2;
2332 }
2333
Kristian Høgsberg25894fc2012-09-05 22:06:26 -04002334 shader->fragment_shader =
Ander Conselvan de Oliveira27508c22012-11-08 17:20:46 +02002335 compile_shader(GL_FRAGMENT_SHADER, count, sources);
Kristian Høgsberg25894fc2012-09-05 22:06:26 -04002336
2337 shader->program = glCreateProgram();
2338 glAttachShader(shader->program, shader->vertex_shader);
2339 glAttachShader(shader->program, shader->fragment_shader);
2340 glBindAttribLocation(shader->program, 0, "position");
2341 glBindAttribLocation(shader->program, 1, "texcoord");
2342
2343 glLinkProgram(shader->program);
2344 glGetProgramiv(shader->program, GL_LINK_STATUS, &status);
2345 if (!status) {
2346 glGetProgramInfoLog(shader->program, sizeof msg, NULL, msg);
2347 weston_log("link info: %s\n", msg);
2348 return -1;
2349 }
2350
2351 shader->proj_uniform = glGetUniformLocation(shader->program, "proj");
2352 shader->tex_uniforms[0] = glGetUniformLocation(shader->program, "tex");
2353 shader->tex_uniforms[1] = glGetUniformLocation(shader->program, "tex1");
2354 shader->tex_uniforms[2] = glGetUniformLocation(shader->program, "tex2");
2355 shader->alpha_uniform = glGetUniformLocation(shader->program, "alpha");
2356 shader->color_uniform = glGetUniformLocation(shader->program, "color");
2357
2358 return 0;
2359}
2360
2361static void
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01002362shader_release(struct gl_shader *shader)
Ander Conselvan de Oliveira27508c22012-11-08 17:20:46 +02002363{
2364 glDeleteShader(shader->vertex_shader);
2365 glDeleteShader(shader->fragment_shader);
2366 glDeleteProgram(shader->program);
2367
2368 shader->vertex_shader = 0;
2369 shader->fragment_shader = 0;
2370 shader->program = 0;
2371}
2372
2373static void
Kristian Høgsberg25894fc2012-09-05 22:06:26 -04002374log_extensions(const char *name, const char *extensions)
2375{
2376 const char *p, *end;
2377 int l;
2378 int len;
2379
2380 l = weston_log("%s:", name);
2381 p = extensions;
2382 while (*p) {
2383 end = strchrnul(p, ' ');
2384 len = end - p;
2385 if (l + len > 78)
2386 l = weston_log_continue("\n" STAMP_SPACE "%.*s",
2387 len, p);
2388 else
2389 l += weston_log_continue(" %.*s", len, p);
2390 for (p = end; isspace(*p); p++)
2391 ;
2392 }
2393 weston_log_continue("\n");
2394}
2395
2396static void
2397log_egl_gl_info(EGLDisplay egldpy)
2398{
2399 const char *str;
2400
2401 str = eglQueryString(egldpy, EGL_VERSION);
2402 weston_log("EGL version: %s\n", str ? str : "(null)");
2403
2404 str = eglQueryString(egldpy, EGL_VENDOR);
2405 weston_log("EGL vendor: %s\n", str ? str : "(null)");
2406
2407 str = eglQueryString(egldpy, EGL_CLIENT_APIS);
2408 weston_log("EGL client APIs: %s\n", str ? str : "(null)");
2409
2410 str = eglQueryString(egldpy, EGL_EXTENSIONS);
2411 log_extensions("EGL extensions", str ? str : "(null)");
2412
2413 str = (char *)glGetString(GL_VERSION);
2414 weston_log("GL version: %s\n", str ? str : "(null)");
2415
2416 str = (char *)glGetString(GL_SHADING_LANGUAGE_VERSION);
2417 weston_log("GLSL version: %s\n", str ? str : "(null)");
2418
2419 str = (char *)glGetString(GL_VENDOR);
2420 weston_log("GL vendor: %s\n", str ? str : "(null)");
2421
2422 str = (char *)glGetString(GL_RENDERER);
2423 weston_log("GL renderer: %s\n", str ? str : "(null)");
2424
2425 str = (char *)glGetString(GL_EXTENSIONS);
2426 log_extensions("GL extensions", str ? str : "(null)");
2427}
2428
Pekka Paalanen9c3fe252012-10-24 09:43:05 +03002429static void
2430log_egl_config_info(EGLDisplay egldpy, EGLConfig eglconfig)
2431{
2432 EGLint r, g, b, a;
2433
2434 weston_log("Chosen EGL config details:\n");
2435
2436 weston_log_continue(STAMP_SPACE "RGBA bits");
2437 if (eglGetConfigAttrib(egldpy, eglconfig, EGL_RED_SIZE, &r) &&
2438 eglGetConfigAttrib(egldpy, eglconfig, EGL_GREEN_SIZE, &g) &&
2439 eglGetConfigAttrib(egldpy, eglconfig, EGL_BLUE_SIZE, &b) &&
2440 eglGetConfigAttrib(egldpy, eglconfig, EGL_ALPHA_SIZE, &a))
2441 weston_log_continue(": %d %d %d %d\n", r, g, b, a);
2442 else
2443 weston_log_continue(" unknown\n");
2444
2445 weston_log_continue(STAMP_SPACE "swap interval range");
2446 if (eglGetConfigAttrib(egldpy, eglconfig, EGL_MIN_SWAP_INTERVAL, &a) &&
2447 eglGetConfigAttrib(egldpy, eglconfig, EGL_MAX_SWAP_INTERVAL, &b))
2448 weston_log_continue(": %d - %d\n", a, b);
2449 else
2450 weston_log_continue(" unknown\n");
2451}
2452
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002453static int
Derek Foremane76f1852015-05-15 12:12:39 -05002454match_config_to_visual(EGLDisplay egl_display,
2455 EGLint visual_id,
2456 EGLConfig *configs,
2457 int count)
2458{
2459 int i;
2460
2461 for (i = 0; i < count; ++i) {
2462 EGLint id;
2463
2464 if (!eglGetConfigAttrib(egl_display,
2465 configs[i], EGL_NATIVE_VISUAL_ID,
2466 &id))
2467 continue;
2468
2469 if (id == visual_id)
2470 return i;
2471 }
2472
Derek Foremane76f1852015-05-15 12:12:39 -05002473 return -1;
2474}
2475
2476static int
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002477egl_choose_config(struct gl_renderer *gr, const EGLint *attribs,
Derek Foremane76f1852015-05-15 12:12:39 -05002478 const EGLint *visual_id, const int n_ids,
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002479 EGLConfig *config_out)
2480{
2481 EGLint count = 0;
2482 EGLint matched = 0;
2483 EGLConfig *configs;
Derek Foremane76f1852015-05-15 12:12:39 -05002484 int i, config_index = -1;
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002485
Derek Foremana7e19912015-05-20 14:57:58 -05002486 if (!eglGetConfigs(gr->egl_display, NULL, 0, &count) || count < 1) {
2487 weston_log("No EGL configs to choose from.\n");
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002488 return -1;
Derek Foremana7e19912015-05-20 14:57:58 -05002489 }
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002490 configs = calloc(count, sizeof *configs);
2491 if (!configs)
2492 return -1;
2493
2494 if (!eglChooseConfig(gr->egl_display, attribs, configs,
Derek Foremana7e19912015-05-20 14:57:58 -05002495 count, &matched) || !matched) {
2496 weston_log("No EGL configs with appropriate attributes.\n");
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002497 goto out;
Derek Foremana7e19912015-05-20 14:57:58 -05002498 }
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002499
Derek Foremane76f1852015-05-15 12:12:39 -05002500 if (!visual_id)
2501 config_index = 0;
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002502
Derek Foremane76f1852015-05-15 12:12:39 -05002503 for (i = 0; config_index == -1 && i < n_ids; i++)
2504 config_index = match_config_to_visual(gr->egl_display,
2505 visual_id[i],
2506 configs,
2507 matched);
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002508
Derek Foremane76f1852015-05-15 12:12:39 -05002509 if (config_index != -1)
2510 *config_out = configs[config_index];
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002511
2512out:
2513 free(configs);
Derek Foremane76f1852015-05-15 12:12:39 -05002514 if (config_index == -1)
2515 return -1;
2516
Derek Foremana7e19912015-05-20 14:57:58 -05002517 if (i > 1)
2518 weston_log("Unable to use first choice EGL config with id"
2519 " 0x%x, succeeded with alternate id 0x%x.\n",
2520 visual_id[0], visual_id[i - 1]);
Derek Foremane76f1852015-05-15 12:12:39 -05002521 return 0;
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002522}
2523
John Kåre Alsaker44154502012-11-13 19:10:20 +01002524static void
Jason Ekstrand0b61bf42013-10-27 22:24:54 -05002525gl_renderer_output_set_border(struct weston_output *output,
2526 enum gl_renderer_border_side side,
2527 int32_t width, int32_t height,
2528 int32_t tex_width, unsigned char *data)
2529{
2530 struct gl_output_state *go = get_output_state(output);
2531
Jason Ekstrande5512d42014-02-04 21:36:38 -06002532 if (go->borders[side].width != width ||
2533 go->borders[side].height != height)
2534 /* In this case, we have to blow everything and do a full
2535 * repaint. */
2536 go->border_status |= BORDER_SIZE_CHANGED | BORDER_ALL_DIRTY;
2537
2538 if (data == NULL) {
2539 width = 0;
2540 height = 0;
2541 }
2542
Jason Ekstrand0b61bf42013-10-27 22:24:54 -05002543 go->borders[side].width = width;
2544 go->borders[side].height = height;
2545 go->borders[side].tex_width = tex_width;
2546 go->borders[side].data = data;
Jason Ekstrande5512d42014-02-04 21:36:38 -06002547 go->border_status |= 1 << side;
Jason Ekstrand0b61bf42013-10-27 22:24:54 -05002548}
2549
John Kåre Alsaker94659272012-11-13 19:10:18 +01002550static int
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01002551gl_renderer_setup(struct weston_compositor *ec, EGLSurface egl_surface);
John Kåre Alsaker94659272012-11-13 19:10:18 +01002552
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03002553static int
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01002554gl_renderer_output_create(struct weston_output *output,
Jonny Lamb671148f2015-03-20 15:26:52 +01002555 EGLNativeWindowType window_for_legacy,
2556 void *window_for_platform,
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002557 const EGLint *attribs,
Derek Foremane76f1852015-05-15 12:12:39 -05002558 const EGLint *visual_id,
2559 int n_ids)
John Kåre Alsaker94659272012-11-13 19:10:18 +01002560{
2561 struct weston_compositor *ec = output->compositor;
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01002562 struct gl_renderer *gr = get_renderer(ec);
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002563 struct gl_output_state *go;
2564 EGLConfig egl_config;
Ander Conselvan de Oliveirab8fcca92012-11-16 17:23:52 +02002565 int i;
John Kåre Alsaker94659272012-11-13 19:10:18 +01002566
Derek Foremane76f1852015-05-15 12:12:39 -05002567 if (egl_choose_config(gr, attribs, visual_id,
2568 n_ids, &egl_config) == -1) {
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002569 weston_log("failed to choose EGL config for output\n");
2570 return -1;
2571 }
2572
2573 if (egl_config != gr->egl_config &&
2574 !gr->has_configless_context) {
2575 weston_log("attempted to use a different EGL config for an "
2576 "output but EGL_MESA_configless_context is not "
2577 "supported\n");
2578 return -1;
2579 }
2580
Bryce Harringtonde16d892014-11-20 22:21:57 -08002581 go = zalloc(sizeof *go);
2582 if (go == NULL)
John Kåre Alsaker94659272012-11-13 19:10:18 +01002583 return -1;
2584
Jonny Lamb671148f2015-03-20 15:26:52 +01002585 if (gr->create_platform_window) {
2586 go->egl_surface =
2587 gr->create_platform_window(gr->egl_display,
2588 egl_config,
2589 window_for_platform,
2590 NULL);
Jonny Lambf1ec5062015-03-24 13:12:05 +01002591 } else {
Jonny Lamb671148f2015-03-20 15:26:52 +01002592 go->egl_surface =
2593 eglCreateWindowSurface(gr->egl_display,
2594 egl_config,
2595 window_for_legacy, NULL);
Jonny Lambf1ec5062015-03-24 13:12:05 +01002596 }
John Kåre Alsaker94659272012-11-13 19:10:18 +01002597
2598 if (go->egl_surface == EGL_NO_SURFACE) {
2599 weston_log("failed to create egl surface\n");
2600 free(go);
2601 return -1;
2602 }
2603
Ander Conselvan de Oliveira1c169ff2013-03-05 17:30:30 +02002604 for (i = 0; i < BUFFER_DAMAGE_COUNT; i++)
Ander Conselvan de Oliveirab8fcca92012-11-16 17:23:52 +02002605 pixman_region32_init(&go->buffer_damage[i]);
2606
John Kåre Alsaker94659272012-11-13 19:10:18 +01002607 output->renderer_state = go;
2608
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002609 log_egl_config_info(gr->egl_display, egl_config);
2610
John Kåre Alsaker94659272012-11-13 19:10:18 +01002611 return 0;
2612}
2613
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03002614static void
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01002615gl_renderer_output_destroy(struct weston_output *output)
John Kåre Alsaker94659272012-11-13 19:10:18 +01002616{
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01002617 struct gl_renderer *gr = get_renderer(output->compositor);
2618 struct gl_output_state *go = get_output_state(output);
Ander Conselvan de Oliveirab8fcca92012-11-16 17:23:52 +02002619 int i;
2620
2621 for (i = 0; i < 2; i++)
2622 pixman_region32_fini(&go->buffer_damage[i]);
John Kåre Alsaker94659272012-11-13 19:10:18 +01002623
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002624 eglDestroySurface(gr->egl_display, go->egl_surface);
John Kåre Alsaker94659272012-11-13 19:10:18 +01002625
2626 free(go);
2627}
2628
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03002629static EGLSurface
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01002630gl_renderer_output_surface(struct weston_output *output)
John Kåre Alsaker94659272012-11-13 19:10:18 +01002631{
2632 return get_output_state(output)->egl_surface;
2633}
2634
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002635static void
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01002636gl_renderer_destroy(struct weston_compositor *ec)
Kristian Høgsberg3a0de882012-09-06 21:44:24 -04002637{
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01002638 struct gl_renderer *gr = get_renderer(ec);
Emmanuel Gil Peyrotb8053502016-01-11 19:04:34 +00002639 struct dmabuf_image *image, *next;
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002640
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +03002641 wl_signal_emit(&gr->destroy_signal, gr);
2642
John Kåre Alsaker320711d2012-11-13 19:10:27 +01002643 if (gr->has_bind_display)
2644 gr->unbind_display(gr->egl_display, ec->wl_display);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002645
2646 /* Work around crash in egl_dri2.c's dri2_make_current() - when does this apply? */
2647 eglMakeCurrent(gr->egl_display,
2648 EGL_NO_SURFACE, EGL_NO_SURFACE,
2649 EGL_NO_CONTEXT);
2650
Pekka Paalanena3525802014-06-12 16:49:29 +03002651
Emmanuel Gil Peyrotb8053502016-01-11 19:04:34 +00002652 wl_list_for_each_safe(image, next, &gr->dmabuf_images, link)
2653 dmabuf_image_destroy(image);
Pekka Paalanena3525802014-06-12 16:49:29 +03002654
Armin Krezović28d240f2016-06-23 11:59:35 +02002655 if (gr->dummy_surface != EGL_NO_SURFACE)
2656 eglDestroySurface(gr->egl_display, gr->dummy_surface);
2657
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002658 eglTerminate(gr->egl_display);
2659 eglReleaseThread();
Scott Moreau976a0502013-03-07 10:15:17 -07002660
Kristian Høgsberg7b9195f2013-05-08 22:38:05 -04002661 wl_array_release(&gr->vertices);
Kristian Høgsberg7b9195f2013-05-08 22:38:05 -04002662 wl_array_release(&gr->vtxcnt);
2663
Mariusz Ceiercbb91582014-02-08 20:11:24 +01002664 if (gr->fragment_binding)
2665 weston_binding_destroy(gr->fragment_binding);
2666 if (gr->fan_binding)
2667 weston_binding_destroy(gr->fan_binding);
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +03002668
Scott Moreau976a0502013-03-07 10:15:17 -07002669 free(gr);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002670}
2671
Miguel A. Vicocc3a1922016-03-21 17:37:33 +01002672static bool
2673check_extension(const char *extensions, const char *extension)
2674{
2675 size_t extlen = strlen(extension);
2676 const char *end = extensions + strlen(extensions);
2677
2678 while (extensions < end) {
2679 size_t n = 0;
2680
2681 /* Skip whitespaces, if any */
2682 if (*extensions == ' ') {
2683 extensions++;
2684 continue;
2685 }
2686
2687 n = strcspn(extensions, " ");
2688
2689 /* Compare strings */
2690 if (n == extlen && strncmp(extension, extensions, n) == 0)
2691 return true; /* Found */
2692
2693 extensions += n;
2694 }
2695
2696 /* Not found */
2697 return false;
2698}
2699
Pekka Paalanen8b69d032015-04-08 17:02:22 +03002700static void
2701renderer_setup_egl_client_extensions(struct gl_renderer *gr)
2702{
2703 const char *extensions;
2704
2705 extensions = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
2706 if (!extensions) {
2707 weston_log("Retrieving EGL client extension string failed.\n");
2708 return;
2709 }
2710
Miguel A. Vicocc3a1922016-03-21 17:37:33 +01002711 if (check_extension(extensions, "EGL_EXT_platform_base"))
Pekka Paalanen8b69d032015-04-08 17:02:22 +03002712 gr->create_platform_window =
2713 (void *) eglGetProcAddress("eglCreatePlatformWindowSurfaceEXT");
2714 else
2715 weston_log("warning: EGL_EXT_platform_base not supported.\n");
2716}
2717
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002718static int
Neil Robertsb7f85332014-03-07 18:05:49 +00002719gl_renderer_setup_egl_extensions(struct weston_compositor *ec)
2720{
2721 struct gl_renderer *gr = get_renderer(ec);
2722 const char *extensions;
2723 EGLBoolean ret;
2724
2725 gr->create_image = (void *) eglGetProcAddress("eglCreateImageKHR");
2726 gr->destroy_image = (void *) eglGetProcAddress("eglDestroyImageKHR");
2727 gr->bind_display =
2728 (void *) eglGetProcAddress("eglBindWaylandDisplayWL");
2729 gr->unbind_display =
2730 (void *) eglGetProcAddress("eglUnbindWaylandDisplayWL");
2731 gr->query_buffer =
2732 (void *) eglGetProcAddress("eglQueryWaylandBufferWL");
2733
2734 extensions =
2735 (const char *) eglQueryString(gr->egl_display, EGL_EXTENSIONS);
2736 if (!extensions) {
2737 weston_log("Retrieving EGL extension string failed.\n");
2738 return -1;
2739 }
2740
Miguel A. Vicocc3a1922016-03-21 17:37:33 +01002741 if (check_extension(extensions, "EGL_WL_bind_wayland_display"))
Neil Robertsb7f85332014-03-07 18:05:49 +00002742 gr->has_bind_display = 1;
2743 if (gr->has_bind_display) {
2744 ret = gr->bind_display(gr->egl_display, ec->wl_display);
2745 if (!ret)
2746 gr->has_bind_display = 0;
2747 }
2748
Miguel A. Vicocc3a1922016-03-21 17:37:33 +01002749 if (check_extension(extensions, "EGL_EXT_buffer_age"))
Neil Robertsb7f85332014-03-07 18:05:49 +00002750 gr->has_egl_buffer_age = 1;
2751 else
2752 weston_log("warning: EGL_EXT_buffer_age not supported. "
2753 "Performance could be affected.\n");
2754
2755#ifdef EGL_EXT_swap_buffers_with_damage
Miguel A. Vicocc3a1922016-03-21 17:37:33 +01002756 if (check_extension(extensions, "EGL_EXT_swap_buffers_with_damage"))
Neil Robertsb7f85332014-03-07 18:05:49 +00002757 gr->swap_buffers_with_damage =
2758 (void *) eglGetProcAddress("eglSwapBuffersWithDamageEXT");
2759 else
2760 weston_log("warning: EGL_EXT_swap_buffers_with_damage not "
2761 "supported. Performance could be affected.\n");
2762#endif
2763
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002764#ifdef EGL_MESA_configless_context
Miguel A. Vicocc3a1922016-03-21 17:37:33 +01002765 if (check_extension(extensions, "EGL_MESA_configless_context"))
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002766 gr->has_configless_context = 1;
2767#endif
2768
Armin Krezović28d240f2016-06-23 11:59:35 +02002769 if (check_extension(extensions, "EGL_KHR_surfaceless_context"))
2770 gr->has_surfaceless_context = 1;
2771
Pekka Paalanena3525802014-06-12 16:49:29 +03002772#ifdef EGL_EXT_image_dma_buf_import
Miguel A. Vicocc3a1922016-03-21 17:37:33 +01002773 if (check_extension(extensions, "EGL_EXT_image_dma_buf_import"))
Pekka Paalanena3525802014-06-12 16:49:29 +03002774 gr->has_dmabuf_import = 1;
2775#endif
2776
Pekka Paalanen8b69d032015-04-08 17:02:22 +03002777 renderer_setup_egl_client_extensions(gr);
2778
Neil Robertsb7f85332014-03-07 18:05:49 +00002779 return 0;
2780}
2781
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03002782static const EGLint gl_renderer_opaque_attribs[] = {
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002783 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
2784 EGL_RED_SIZE, 1,
2785 EGL_GREEN_SIZE, 1,
2786 EGL_BLUE_SIZE, 1,
2787 EGL_ALPHA_SIZE, 0,
2788 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
2789 EGL_NONE
2790};
2791
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03002792static const EGLint gl_renderer_alpha_attribs[] = {
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002793 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
2794 EGL_RED_SIZE, 1,
2795 EGL_GREEN_SIZE, 1,
2796 EGL_BLUE_SIZE, 1,
2797 EGL_ALPHA_SIZE, 1,
2798 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
2799 EGL_NONE
2800};
2801
Armin Krezović28d240f2016-06-23 11:59:35 +02002802
Jonny Lamb70eba3f2015-03-20 15:26:50 +01002803/** Checks whether a platform EGL client extension is supported
2804 *
2805 * \param ec The weston compositor
2806 * \param extension_suffix The EGL client extension suffix
2807 * \return 1 if supported, 0 if using fallbacks, -1 unsupported
2808 *
2809 * This function checks whether a specific platform_* extension is supported
2810 * by EGL.
2811 *
2812 * The extension suffix should be the suffix of the platform extension (that
2813 * specifies a <platform> argument as defined in EGL_EXT_platform_base). For
2814 * example, passing "foo" will check whether either "EGL_KHR_platform_foo",
2815 * "EGL_EXT_platform_foo", or "EGL_MESA_platform_foo" is supported.
2816 *
2817 * The return value is 1:
2818 * - if the supplied EGL client extension is supported.
2819 * The return value is 0:
2820 * - if the platform_base client extension isn't supported so will
2821 * fallback to eglGetDisplay and friends.
2822 * The return value is -1:
2823 * - if the supplied EGL client extension is not supported.
2824 */
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03002825static int
Jonny Lamb70eba3f2015-03-20 15:26:50 +01002826gl_renderer_supports(struct weston_compositor *ec,
2827 const char *extension_suffix)
2828{
2829 static const char *extensions = NULL;
2830 char s[64];
2831
2832 if (!extensions) {
2833 extensions = (const char *) eglQueryString(
2834 EGL_NO_DISPLAY, EGL_EXTENSIONS);
2835
2836 if (!extensions)
2837 return 0;
2838
2839 log_extensions("EGL client extensions",
2840 extensions);
2841 }
2842
Miguel A. Vicocc3a1922016-03-21 17:37:33 +01002843 if (!check_extension(extensions, "EGL_EXT_platform_base"))
Pekka Paalanenf2824542015-04-08 17:02:21 +03002844 return 0;
2845
Jonny Lamb70eba3f2015-03-20 15:26:50 +01002846 snprintf(s, sizeof s, "EGL_KHR_platform_%s", extension_suffix);
Miguel A. Vicocc3a1922016-03-21 17:37:33 +01002847 if (check_extension(extensions, s))
Jonny Lamb70eba3f2015-03-20 15:26:50 +01002848 return 1;
2849
2850 snprintf(s, sizeof s, "EGL_EXT_platform_%s", extension_suffix);
Miguel A. Vicocc3a1922016-03-21 17:37:33 +01002851 if (check_extension(extensions, s))
Jonny Lamb70eba3f2015-03-20 15:26:50 +01002852 return 1;
2853
2854 snprintf(s, sizeof s, "EGL_MESA_platform_%s", extension_suffix);
Miguel A. Vicocc3a1922016-03-21 17:37:33 +01002855 if (check_extension(extensions, s))
Jonny Lamb70eba3f2015-03-20 15:26:50 +01002856 return 1;
2857
Pekka Paalanenf2824542015-04-08 17:02:21 +03002858 /* at this point we definitely have some platform extensions but
2859 * haven't found the supplied platform, so chances are it's
Jonny Lamb70eba3f2015-03-20 15:26:50 +01002860 * not supported. */
2861
2862 return -1;
2863}
2864
Jonny Lamb74eed312015-03-24 13:12:04 +01002865static const char *
2866platform_to_extension(EGLenum platform)
2867{
2868 switch (platform) {
2869 case EGL_PLATFORM_GBM_KHR:
2870 return "gbm";
2871 case EGL_PLATFORM_WAYLAND_KHR:
2872 return "wayland";
2873 case EGL_PLATFORM_X11_KHR:
2874 return "x11";
2875 default:
2876 assert(0 && "bad EGL platform enum");
2877 }
2878}
2879
Jonny Lamb70eba3f2015-03-20 15:26:50 +01002880static int
Armin Krezović28d240f2016-06-23 11:59:35 +02002881gl_renderer_create_pbuffer_surface(struct gl_renderer *gr) {
2882 EGLConfig pbuffer_config;
2883
2884 static const EGLint pbuffer_config_attribs[] = {
2885 EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
2886 EGL_RED_SIZE, 1,
2887 EGL_GREEN_SIZE, 1,
2888 EGL_BLUE_SIZE, 1,
2889 EGL_ALPHA_SIZE, 0,
2890 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
2891 EGL_NONE
2892 };
2893
2894 static const EGLint pbuffer_attribs[] = {
2895 EGL_WIDTH, 10,
2896 EGL_HEIGHT, 10,
2897 EGL_NONE
2898 };
2899
2900 if (egl_choose_config(gr, pbuffer_config_attribs, NULL, 0, &pbuffer_config) < 0) {
2901 weston_log("failed to choose EGL config for PbufferSurface");
2902 return -1;
2903 }
2904
2905 gr->dummy_surface = eglCreatePbufferSurface(gr->egl_display,
2906 pbuffer_config,
2907 pbuffer_attribs);
2908
2909 if (gr->dummy_surface == EGL_NO_SURFACE) {
2910 weston_log("failed to create PbufferSurface\n");
2911 return -1;
2912 }
2913
2914 return 0;
2915}
2916
2917static int
Jonny Lamb70eba3f2015-03-20 15:26:50 +01002918gl_renderer_create(struct weston_compositor *ec, EGLenum platform,
2919 void *native_window, const EGLint *attribs,
Derek Foremane76f1852015-05-15 12:12:39 -05002920 const EGLint *visual_id, int n_ids)
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002921{
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01002922 struct gl_renderer *gr;
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002923 EGLint major, minor;
Jonny Lamb74eed312015-03-24 13:12:04 +01002924 int supports = 0;
2925
2926 if (platform) {
2927 supports = gl_renderer_supports(
2928 ec, platform_to_extension(platform));
2929 if (supports < 0)
2930 return -1;
2931 }
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002932
Bryce Harringtonde16d892014-11-20 22:21:57 -08002933 gr = zalloc(sizeof *gr);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002934 if (gr == NULL)
2935 return -1;
2936
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01002937 gr->base.read_pixels = gl_renderer_read_pixels;
2938 gr->base.repaint_output = gl_renderer_repaint_output;
2939 gr->base.flush_damage = gl_renderer_flush_damage;
2940 gr->base.attach = gl_renderer_attach;
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01002941 gr->base.surface_set_color = gl_renderer_surface_set_color;
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002942 gr->base.destroy = gl_renderer_destroy;
Pekka Paalaneneb35cbe2015-02-09 13:37:27 +02002943 gr->base.surface_get_content_size =
2944 gl_renderer_surface_get_content_size;
2945 gr->base.surface_copy_content = gl_renderer_surface_copy_content;
Jonny Lamb74eed312015-03-24 13:12:04 +01002946 gr->egl_display = NULL;
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002947
Jonny Lambf1ec5062015-03-24 13:12:05 +01002948 /* extension_suffix is supported */
Jonny Lamb74eed312015-03-24 13:12:04 +01002949 if (supports) {
2950 if (!get_platform_display) {
2951 get_platform_display = (void *) eglGetProcAddress(
2952 "eglGetPlatformDisplayEXT");
2953 }
Jonny Lamb70eba3f2015-03-20 15:26:50 +01002954
Jonny Lamb74eed312015-03-24 13:12:04 +01002955 /* also wrap this in the supports check because
2956 * eglGetProcAddress can return non-NULL and still not
2957 * support the feature at runtime, so ensure the
2958 * appropriate extension checks have been done. */
2959 if (get_platform_display && platform) {
2960 gr->egl_display = get_platform_display(platform,
2961 native_window,
2962 NULL);
2963 }
2964 }
Jonny Lamb74eed312015-03-24 13:12:04 +01002965
2966 if (!gr->egl_display) {
Jonny Lamb70eba3f2015-03-20 15:26:50 +01002967 weston_log("warning: either no EGL_EXT_platform_base "
2968 "support or specific platform support; "
2969 "falling back to eglGetDisplay.\n");
2970 gr->egl_display = eglGetDisplay(native_window);
Jonny Lamb70eba3f2015-03-20 15:26:50 +01002971 }
Jonny Lamb70eba3f2015-03-20 15:26:50 +01002972
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002973 if (gr->egl_display == EGL_NO_DISPLAY) {
2974 weston_log("failed to create display\n");
Derek Foreman066ca0c2015-06-11 12:14:45 -05002975 goto fail;
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002976 }
2977
2978 if (!eglInitialize(gr->egl_display, &major, &minor)) {
2979 weston_log("failed to initialize display\n");
Derek Foreman066ca0c2015-06-11 12:14:45 -05002980 goto fail_with_error;
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002981 }
2982
Derek Foremane76f1852015-05-15 12:12:39 -05002983 if (egl_choose_config(gr, attribs, visual_id,
2984 n_ids, &gr->egl_config) < 0) {
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002985 weston_log("failed to choose EGL config\n");
Dawid Gajownik1a912a92015-08-21 00:20:54 -03002986 goto fail_terminate;
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002987 }
2988
2989 ec->renderer = &gr->base;
Pekka Paalanen7bb65102013-05-22 18:03:04 +03002990 ec->capabilities |= WESTON_CAP_ROTATION_ANY;
Pekka Paalanen4fc5dd02013-05-22 18:03:05 +03002991 ec->capabilities |= WESTON_CAP_CAPTURE_YFLIP;
Pekka Paalanenfa79b1d2015-02-18 09:48:59 +02002992 ec->capabilities |= WESTON_CAP_VIEW_CLIP_MASK;
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002993
Neil Robertsb7f85332014-03-07 18:05:49 +00002994 if (gl_renderer_setup_egl_extensions(ec) < 0)
Derek Foreman066ca0c2015-06-11 12:14:45 -05002995 goto fail_with_error;
Neil Robertsb7f85332014-03-07 18:05:49 +00002996
Pekka Paalanena3525802014-06-12 16:49:29 +03002997 wl_list_init(&gr->dmabuf_images);
2998 if (gr->has_dmabuf_import)
2999 gr->base.import_dmabuf = gl_renderer_import_dmabuf;
3000
Armin Krezović28d240f2016-06-23 11:59:35 +02003001 if (gr->has_surfaceless_context) {
3002 weston_log("EGL_KHR_surfaceless_context available\n");
3003 gr->dummy_surface = EGL_NO_SURFACE;
3004 } else {
3005 weston_log("EGL_KHR_surfaceless_context unavailable. "
3006 "Trying PbufferSurface\n");
3007
3008 if (gl_renderer_create_pbuffer_surface(gr) < 0)
3009 goto fail_with_error;
3010 }
3011
Tomeu Vizoso12072b62013-08-06 20:05:55 +02003012 wl_display_add_shm_format(ec->wl_display, WL_SHM_FORMAT_RGB565);
3013
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +03003014 wl_signal_init(&gr->destroy_signal);
3015
Armin Krezović28d240f2016-06-23 11:59:35 +02003016 if (gl_renderer_setup(ec, gr->dummy_surface) < 0) {
3017 if (gr->dummy_surface != EGL_NO_SURFACE)
3018 eglDestroySurface(gr->egl_display, gr->dummy_surface);
3019 goto fail_with_error;
3020 }
3021
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01003022 return 0;
3023
Derek Foreman066ca0c2015-06-11 12:14:45 -05003024fail_with_error:
Pekka Paalanen326529f2012-11-27 12:25:25 +02003025 gl_renderer_print_egl_error_state();
Dawid Gajownik1a912a92015-08-21 00:20:54 -03003026fail_terminate:
3027 eglTerminate(gr->egl_display);
Derek Foreman066ca0c2015-06-11 12:14:45 -05003028fail:
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01003029 free(gr);
3030 return -1;
3031}
3032
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03003033static EGLDisplay
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01003034gl_renderer_display(struct weston_compositor *ec)
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01003035{
3036 return get_renderer(ec)->egl_display;
Kristian Høgsberg3a0de882012-09-06 21:44:24 -04003037}
3038
Ander Conselvan de Oliveira27508c22012-11-08 17:20:46 +02003039static int
3040compile_shaders(struct weston_compositor *ec)
3041{
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01003042 struct gl_renderer *gr = get_renderer(ec);
John Kåre Alsaker40684142012-11-13 19:10:25 +01003043
Ander Conselvan de Oliveira1ed73242013-05-17 14:00:40 +03003044 gr->texture_shader_rgba.vertex_source = vertex_shader;
3045 gr->texture_shader_rgba.fragment_source = texture_fragment_shader_rgba;
3046
3047 gr->texture_shader_rgbx.vertex_source = vertex_shader;
3048 gr->texture_shader_rgbx.fragment_source = texture_fragment_shader_rgbx;
3049
3050 gr->texture_shader_egl_external.vertex_source = vertex_shader;
3051 gr->texture_shader_egl_external.fragment_source =
3052 texture_fragment_shader_egl_external;
3053
3054 gr->texture_shader_y_uv.vertex_source = vertex_shader;
3055 gr->texture_shader_y_uv.fragment_source = texture_fragment_shader_y_uv;
3056
3057 gr->texture_shader_y_u_v.vertex_source = vertex_shader;
3058 gr->texture_shader_y_u_v.fragment_source =
3059 texture_fragment_shader_y_u_v;
3060
Ander Conselvan de Oliveira41a50ea2013-11-27 17:43:51 +02003061 gr->texture_shader_y_xuxv.vertex_source = vertex_shader;
Ander Conselvan de Oliveira1ed73242013-05-17 14:00:40 +03003062 gr->texture_shader_y_xuxv.fragment_source =
3063 texture_fragment_shader_y_xuxv;
3064
3065 gr->solid_shader.vertex_source = vertex_shader;
3066 gr->solid_shader.fragment_source = solid_fragment_shader;
Ander Conselvan de Oliveira27508c22012-11-08 17:20:46 +02003067
3068 return 0;
3069}
3070
3071static void
Derek Foreman8ae2db52015-07-15 13:00:36 -05003072fragment_debug_binding(struct weston_keyboard *keyboard, uint32_t time,
3073 uint32_t key, void *data)
Ander Conselvan de Oliveira27508c22012-11-08 17:20:46 +02003074{
3075 struct weston_compositor *ec = data;
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01003076 struct gl_renderer *gr = get_renderer(ec);
Ander Conselvan de Oliveira27508c22012-11-08 17:20:46 +02003077 struct weston_output *output;
3078
John Kåre Alsaker40684142012-11-13 19:10:25 +01003079 gr->fragment_shader_debug ^= 1;
Ander Conselvan de Oliveira27508c22012-11-08 17:20:46 +02003080
John Kåre Alsaker40684142012-11-13 19:10:25 +01003081 shader_release(&gr->texture_shader_rgba);
3082 shader_release(&gr->texture_shader_rgbx);
3083 shader_release(&gr->texture_shader_egl_external);
3084 shader_release(&gr->texture_shader_y_uv);
3085 shader_release(&gr->texture_shader_y_u_v);
3086 shader_release(&gr->texture_shader_y_xuxv);
3087 shader_release(&gr->solid_shader);
Ander Conselvan de Oliveira27508c22012-11-08 17:20:46 +02003088
Ander Conselvan de Oliveira03fb4ef2012-12-03 17:08:11 +02003089 /* Force use_shader() to call glUseProgram(), since we need to use
3090 * the recompiled version of the shader. */
3091 gr->current_shader = NULL;
3092
Ander Conselvan de Oliveira27508c22012-11-08 17:20:46 +02003093 wl_list_for_each(output, &ec->output_list, link)
3094 weston_output_damage(output);
3095}
3096
Kristian Høgsberg8799d412013-05-07 10:50:09 -04003097static void
Derek Foreman8ae2db52015-07-15 13:00:36 -05003098fan_debug_repaint_binding(struct weston_keyboard *keyboard, uint32_t time,
3099 uint32_t key, void *data)
Kristian Høgsberg8799d412013-05-07 10:50:09 -04003100{
3101 struct weston_compositor *compositor = data;
3102 struct gl_renderer *gr = get_renderer(compositor);
3103
3104 gr->fan_debug = !gr->fan_debug;
3105 weston_compositor_damage_all(compositor);
3106}
3107
John Kåre Alsaker94659272012-11-13 19:10:18 +01003108static int
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01003109gl_renderer_setup(struct weston_compositor *ec, EGLSurface egl_surface)
Kristian Høgsberg25894fc2012-09-05 22:06:26 -04003110{
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01003111 struct gl_renderer *gr = get_renderer(ec);
Kristian Høgsberg25894fc2012-09-05 22:06:26 -04003112 const char *extensions;
Neil Roberts77c1a5b2014-03-07 18:05:50 +00003113 EGLConfig context_config;
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04003114 EGLBoolean ret;
Kristian Høgsberg25894fc2012-09-05 22:06:26 -04003115
Kristian Høgsberg9793fc72012-09-06 21:07:40 -04003116 static const EGLint context_attribs[] = {
3117 EGL_CONTEXT_CLIENT_VERSION, 2,
3118 EGL_NONE
3119 };
3120
Kristian Høgsberg9793fc72012-09-06 21:07:40 -04003121 if (!eglBindAPI(EGL_OPENGL_ES_API)) {
3122 weston_log("failed to bind EGL_OPENGL_ES_API\n");
Pekka Paalanen326529f2012-11-27 12:25:25 +02003123 gl_renderer_print_egl_error_state();
Kristian Høgsberg9793fc72012-09-06 21:07:40 -04003124 return -1;
3125 }
Pekka Paalanen9c3fe252012-10-24 09:43:05 +03003126
Neil Roberts77c1a5b2014-03-07 18:05:50 +00003127 context_config = gr->egl_config;
Pekka Paalanen9c3fe252012-10-24 09:43:05 +03003128
Neil Roberts77c1a5b2014-03-07 18:05:50 +00003129#ifdef EGL_MESA_configless_context
3130 if (gr->has_configless_context)
3131 context_config = EGL_NO_CONFIG_MESA;
3132#endif
3133
3134 gr->egl_context = eglCreateContext(gr->egl_display, context_config,
Kristian Høgsberg9793fc72012-09-06 21:07:40 -04003135 EGL_NO_CONTEXT, context_attribs);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01003136 if (gr->egl_context == NULL) {
Kristian Høgsberg9793fc72012-09-06 21:07:40 -04003137 weston_log("failed to create context\n");
Pekka Paalanen326529f2012-11-27 12:25:25 +02003138 gl_renderer_print_egl_error_state();
Kristian Høgsberg9793fc72012-09-06 21:07:40 -04003139 return -1;
3140 }
3141
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01003142 ret = eglMakeCurrent(gr->egl_display, egl_surface,
3143 egl_surface, gr->egl_context);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04003144 if (ret == EGL_FALSE) {
3145 weston_log("Failed to make EGL context current.\n");
Pekka Paalanen326529f2012-11-27 12:25:25 +02003146 gl_renderer_print_egl_error_state();
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04003147 return -1;
3148 }
3149
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01003150 log_egl_gl_info(gr->egl_display);
Kristian Høgsberg25894fc2012-09-05 22:06:26 -04003151
John Kåre Alsaker320711d2012-11-13 19:10:27 +01003152 gr->image_target_texture_2d =
Kristian Høgsberg25894fc2012-09-05 22:06:26 -04003153 (void *) eglGetProcAddress("glEGLImageTargetTexture2DOES");
Kristian Høgsberg25894fc2012-09-05 22:06:26 -04003154
3155 extensions = (const char *) glGetString(GL_EXTENSIONS);
3156 if (!extensions) {
3157 weston_log("Retrieving GL extension string failed.\n");
3158 return -1;
3159 }
3160
Miguel A. Vicocc3a1922016-03-21 17:37:33 +01003161 if (!check_extension(extensions, "GL_EXT_texture_format_BGRA8888")) {
Kristian Høgsberg25894fc2012-09-05 22:06:26 -04003162 weston_log("GL_EXT_texture_format_BGRA8888 not available\n");
3163 return -1;
3164 }
3165
Miguel A. Vicocc3a1922016-03-21 17:37:33 +01003166 if (check_extension(extensions, "GL_EXT_read_format_bgra"))
John Kåre Alsakerf9e710b2012-11-13 19:10:22 +01003167 ec->read_format = PIXMAN_a8r8g8b8;
Kristian Høgsberg25894fc2012-09-05 22:06:26 -04003168 else
John Kåre Alsakerf9e710b2012-11-13 19:10:22 +01003169 ec->read_format = PIXMAN_a8b8g8r8;
Kristian Høgsberg25894fc2012-09-05 22:06:26 -04003170
Kristian Høgsberg1c4f1632013-08-07 12:11:27 -07003171#ifdef GL_EXT_unpack_subimage
Miguel A. Vicocc3a1922016-03-21 17:37:33 +01003172 if (check_extension(extensions, "GL_EXT_unpack_subimage"))
John Kåre Alsaker320711d2012-11-13 19:10:27 +01003173 gr->has_unpack_subimage = 1;
Kristian Høgsberg1c4f1632013-08-07 12:11:27 -07003174#endif
Kristian Høgsberg25894fc2012-09-05 22:06:26 -04003175
Miguel A. Vicocc3a1922016-03-21 17:37:33 +01003176 if (check_extension(extensions, "GL_OES_EGL_image_external"))
John Kåre Alsaker320711d2012-11-13 19:10:27 +01003177 gr->has_egl_image_external = 1;
Kristian Høgsberg25894fc2012-09-05 22:06:26 -04003178
Kristian Høgsberg25894fc2012-09-05 22:06:26 -04003179 glActiveTexture(GL_TEXTURE0);
3180
Ander Conselvan de Oliveira27508c22012-11-08 17:20:46 +02003181 if (compile_shaders(ec))
3182 return -1;
3183
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +03003184 gr->fragment_binding =
3185 weston_compositor_add_debug_binding(ec, KEY_S,
3186 fragment_debug_binding,
3187 ec);
3188 gr->fan_binding =
3189 weston_compositor_add_debug_binding(ec, KEY_F,
3190 fan_debug_repaint_binding,
3191 ec);
Ander Conselvan de Oliveira27508c22012-11-08 17:20:46 +02003192
Pekka Paalanen035a0322012-10-24 09:43:06 +03003193 weston_log("GL ES 2 renderer features:\n");
3194 weston_log_continue(STAMP_SPACE "read-back format: %s\n",
Pekka Paalanenfe4eacf2013-01-10 16:50:42 +02003195 ec->read_format == PIXMAN_a8r8g8b8 ? "BGRA" : "RGBA");
Pekka Paalanen035a0322012-10-24 09:43:06 +03003196 weston_log_continue(STAMP_SPACE "wl_shm sub-image to texture: %s\n",
John Kåre Alsaker320711d2012-11-13 19:10:27 +01003197 gr->has_unpack_subimage ? "yes" : "no");
Pekka Paalanen035a0322012-10-24 09:43:06 +03003198 weston_log_continue(STAMP_SPACE "EGL Wayland extension: %s\n",
John Kåre Alsaker320711d2012-11-13 19:10:27 +01003199 gr->has_bind_display ? "yes" : "no");
Pekka Paalanen035a0322012-10-24 09:43:06 +03003200
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01003201
Kristian Høgsberg25894fc2012-09-05 22:06:26 -04003202 return 0;
3203}
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03003204
3205WL_EXPORT struct gl_renderer_interface gl_renderer_interface = {
3206 .opaque_attribs = gl_renderer_opaque_attribs,
3207 .alpha_attribs = gl_renderer_alpha_attribs,
3208
3209 .create = gl_renderer_create,
3210 .display = gl_renderer_display,
3211 .output_create = gl_renderer_output_create,
3212 .output_destroy = gl_renderer_output_destroy,
3213 .output_surface = gl_renderer_output_surface,
Jason Ekstrand0b61bf42013-10-27 22:24:54 -05003214 .output_set_border = gl_renderer_output_set_border,
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03003215 .print_egl_error_state = gl_renderer_print_egl_error_state
3216};