1 #include <assert.h>
2 #include <GLES2/gl2.h>
3 #include <GLES2/gl2ext.h>
4 #include <stdint.h>
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <wayland-server-protocol.h>
8 #include <wayland-util.h>
9 #include <wlr/render/egl.h>
10 #include <wlr/render/interface.h>
11 #include <wlr/render/wlr_renderer.h>
12 #include <wlr/types/wlr_matrix.h>
13 #include <wlr/types/wlr_linux_dmabuf_v1.h>
14 #include <wlr/util/log.h>
15 #include "render/gles2.h"
16
17 static const GLfloat verts[] = {
18 1, 0, // top right
19 0, 0, // top left
20 1, 1, // bottom right
21 0, 1, // bottom left
22 };
23
24 static const struct wlr_renderer_impl renderer_impl;
25
gles2_get_renderer(struct wlr_renderer * wlr_renderer)26 struct wlr_gles2_renderer *gles2_get_renderer(
27 struct wlr_renderer *wlr_renderer) {
28 assert(wlr_renderer->impl == &renderer_impl);
29 return (struct wlr_gles2_renderer *)wlr_renderer;
30 }
31
gles2_get_renderer_in_context(struct wlr_renderer * wlr_renderer)32 static struct wlr_gles2_renderer *gles2_get_renderer_in_context(
33 struct wlr_renderer *wlr_renderer) {
34 struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer);
35 assert(wlr_egl_is_current(renderer->egl));
36 return renderer;
37 }
38
gles2_begin(struct wlr_renderer * wlr_renderer,uint32_t width,uint32_t height)39 static void gles2_begin(struct wlr_renderer *wlr_renderer, uint32_t width,
40 uint32_t height) {
41 struct wlr_gles2_renderer *renderer =
42 gles2_get_renderer_in_context(wlr_renderer);
43
44 push_gles2_debug(renderer);
45
46 glViewport(0, 0, width, height);
47 renderer->viewport_width = width;
48 renderer->viewport_height = height;
49
50 // enable transparency
51 glEnable(GL_BLEND);
52 glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
53
54 // XXX: maybe we should save output projection and remove some of the need
55 // for users to sling matricies themselves
56
57 pop_gles2_debug(renderer);
58 }
59
gles2_end(struct wlr_renderer * wlr_renderer)60 static void gles2_end(struct wlr_renderer *wlr_renderer) {
61 gles2_get_renderer_in_context(wlr_renderer);
62 // no-op
63 }
64
gles2_clear(struct wlr_renderer * wlr_renderer,const float color[static4])65 static void gles2_clear(struct wlr_renderer *wlr_renderer,
66 const float color[static 4]) {
67 struct wlr_gles2_renderer *renderer =
68 gles2_get_renderer_in_context(wlr_renderer);
69
70 push_gles2_debug(renderer);
71 glClearColor(color[0], color[1], color[2], color[3]);
72 glClear(GL_COLOR_BUFFER_BIT);
73 pop_gles2_debug(renderer);
74 }
75
gles2_scissor(struct wlr_renderer * wlr_renderer,struct wlr_box * box)76 static void gles2_scissor(struct wlr_renderer *wlr_renderer,
77 struct wlr_box *box) {
78 struct wlr_gles2_renderer *renderer =
79 gles2_get_renderer_in_context(wlr_renderer);
80
81 push_gles2_debug(renderer);
82 if (box != NULL) {
83 struct wlr_box gl_box;
84 wlr_box_transform(&gl_box, box, WL_OUTPUT_TRANSFORM_FLIPPED_180,
85 renderer->viewport_width, renderer->viewport_height);
86
87 glScissor(gl_box.x, gl_box.y, gl_box.width, gl_box.height);
88 glEnable(GL_SCISSOR_TEST);
89 } else {
90 glDisable(GL_SCISSOR_TEST);
91 }
92 pop_gles2_debug(renderer);
93 }
94
gles2_render_subtexture_with_matrix(struct wlr_renderer * wlr_renderer,struct wlr_texture * wlr_texture,const struct wlr_fbox * box,const float matrix[static9],float alpha)95 static bool gles2_render_subtexture_with_matrix(
96 struct wlr_renderer *wlr_renderer, struct wlr_texture *wlr_texture,
97 const struct wlr_fbox *box, const float matrix[static 9],
98 float alpha) {
99 struct wlr_gles2_renderer *renderer =
100 gles2_get_renderer_in_context(wlr_renderer);
101 struct wlr_gles2_texture *texture =
102 gles2_get_texture(wlr_texture);
103
104 struct wlr_gles2_tex_shader *shader = NULL;
105
106 switch (texture->target) {
107 case GL_TEXTURE_2D:
108 if (texture->has_alpha) {
109 shader = &renderer->shaders.tex_rgba;
110 } else {
111 shader = &renderer->shaders.tex_rgbx;
112 }
113 break;
114 case GL_TEXTURE_EXTERNAL_OES:
115 shader = &renderer->shaders.tex_ext;
116
117 if (!renderer->exts.egl_image_external_oes) {
118 wlr_log(WLR_ERROR, "Failed to render texture: "
119 "GL_TEXTURE_EXTERNAL_OES not supported");
120 return false;
121 }
122 break;
123 default:
124 abort();
125 }
126
127 // OpenGL ES 2 requires the glUniformMatrix3fv transpose parameter to be set
128 // to GL_FALSE
129 float transposition[9];
130 wlr_matrix_transpose(transposition, matrix);
131
132 push_gles2_debug(renderer);
133
134 glActiveTexture(GL_TEXTURE0);
135 glBindTexture(texture->target, texture->tex);
136
137 glTexParameteri(texture->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
138
139 glUseProgram(shader->program);
140
141 glUniformMatrix3fv(shader->proj, 1, GL_FALSE, transposition);
142 glUniform1i(shader->invert_y, texture->inverted_y);
143 glUniform1i(shader->tex, 0);
144 glUniform1f(shader->alpha, alpha);
145
146 const GLfloat x1 = box->x / wlr_texture->width;
147 const GLfloat y1 = box->y / wlr_texture->height;
148 const GLfloat x2 = (box->x + box->width) / wlr_texture->width;
149 const GLfloat y2 = (box->y + box->height) / wlr_texture->height;
150 const GLfloat texcoord[] = {
151 x2, y1, // top right
152 x1, y1, // top left
153 x2, y2, // bottom right
154 x1, y2, // bottom left
155 };
156
157 glVertexAttribPointer(shader->pos_attrib, 2, GL_FLOAT, GL_FALSE, 0, verts);
158 glVertexAttribPointer(shader->tex_attrib, 2, GL_FLOAT, GL_FALSE, 0, texcoord);
159
160 glEnableVertexAttribArray(shader->pos_attrib);
161 glEnableVertexAttribArray(shader->tex_attrib);
162
163 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
164
165 glDisableVertexAttribArray(shader->pos_attrib);
166 glDisableVertexAttribArray(shader->tex_attrib);
167
168 glBindTexture(texture->target, 0);
169
170 pop_gles2_debug(renderer);
171 return true;
172 }
173
gles2_render_quad_with_matrix(struct wlr_renderer * wlr_renderer,const float color[static4],const float matrix[static9])174 static void gles2_render_quad_with_matrix(struct wlr_renderer *wlr_renderer,
175 const float color[static 4], const float matrix[static 9]) {
176 struct wlr_gles2_renderer *renderer =
177 gles2_get_renderer_in_context(wlr_renderer);
178
179 // OpenGL ES 2 requires the glUniformMatrix3fv transpose parameter to be set
180 // to GL_FALSE
181 float transposition[9];
182 wlr_matrix_transpose(transposition, matrix);
183
184 push_gles2_debug(renderer);
185 glUseProgram(renderer->shaders.quad.program);
186
187 glUniformMatrix3fv(renderer->shaders.quad.proj, 1, GL_FALSE, transposition);
188 glUniform4f(renderer->shaders.quad.color, color[0], color[1], color[2], color[3]);
189
190 glVertexAttribPointer(renderer->shaders.quad.pos_attrib, 2, GL_FLOAT, GL_FALSE,
191 0, verts);
192
193 glEnableVertexAttribArray(renderer->shaders.quad.pos_attrib);
194
195 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
196
197 glDisableVertexAttribArray(renderer->shaders.quad.pos_attrib);
198
199 pop_gles2_debug(renderer);
200 }
201
gles2_render_ellipse_with_matrix(struct wlr_renderer * wlr_renderer,const float color[static4],const float matrix[static9])202 static void gles2_render_ellipse_with_matrix(struct wlr_renderer *wlr_renderer,
203 const float color[static 4], const float matrix[static 9]) {
204 struct wlr_gles2_renderer *renderer =
205 gles2_get_renderer_in_context(wlr_renderer);
206
207 // OpenGL ES 2 requires the glUniformMatrix3fv transpose parameter to be set
208 // to GL_FALSE
209 float transposition[9];
210 wlr_matrix_transpose(transposition, matrix);
211
212 static const GLfloat texcoord[] = {
213 1, 0, // top right
214 0, 0, // top left
215 1, 1, // bottom right
216 0, 1, // bottom left
217 };
218
219 push_gles2_debug(renderer);
220 glUseProgram(renderer->shaders.ellipse.program);
221
222 glUniformMatrix3fv(renderer->shaders.ellipse.proj, 1, GL_FALSE, transposition);
223 glUniform4f(renderer->shaders.ellipse.color, color[0], color[1], color[2], color[3]);
224
225 glVertexAttribPointer(renderer->shaders.ellipse.pos_attrib, 2, GL_FLOAT,
226 GL_FALSE, 0, verts);
227 glVertexAttribPointer(renderer->shaders.ellipse.tex_attrib, 2, GL_FLOAT,
228 GL_FALSE, 0, texcoord);
229
230 glEnableVertexAttribArray(renderer->shaders.ellipse.pos_attrib);
231 glEnableVertexAttribArray(renderer->shaders.ellipse.tex_attrib);
232
233 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
234
235 glDisableVertexAttribArray(renderer->shaders.ellipse.pos_attrib);
236 glDisableVertexAttribArray(renderer->shaders.ellipse.tex_attrib);
237 pop_gles2_debug(renderer);
238 }
239
gles2_renderer_formats(struct wlr_renderer * wlr_renderer,size_t * len)240 static const enum wl_shm_format *gles2_renderer_formats(
241 struct wlr_renderer *wlr_renderer, size_t *len) {
242 return get_gles2_wl_formats(len);
243 }
244
gles2_format_supported(struct wlr_renderer * wlr_renderer,enum wl_shm_format wl_fmt)245 static bool gles2_format_supported(struct wlr_renderer *wlr_renderer,
246 enum wl_shm_format wl_fmt) {
247 return get_gles2_format_from_wl(wl_fmt) != NULL;
248 }
249
gles2_resource_is_wl_drm_buffer(struct wlr_renderer * wlr_renderer,struct wl_resource * resource)250 static bool gles2_resource_is_wl_drm_buffer(struct wlr_renderer *wlr_renderer,
251 struct wl_resource *resource) {
252 struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer);
253
254 if (!renderer->egl->exts.bind_wayland_display_wl) {
255 return false;
256 }
257
258 EGLint fmt;
259 return renderer->egl->procs.eglQueryWaylandBufferWL(renderer->egl->display,
260 resource, EGL_TEXTURE_FORMAT, &fmt);
261 }
262
gles2_wl_drm_buffer_get_size(struct wlr_renderer * wlr_renderer,struct wl_resource * buffer,int * width,int * height)263 static void gles2_wl_drm_buffer_get_size(struct wlr_renderer *wlr_renderer,
264 struct wl_resource *buffer, int *width, int *height) {
265 struct wlr_gles2_renderer *renderer =
266 gles2_get_renderer(wlr_renderer);
267
268 if (!renderer->egl->exts.bind_wayland_display_wl) {
269 return;
270 }
271
272 renderer->egl->procs.eglQueryWaylandBufferWL(renderer->egl->display,
273 buffer, EGL_WIDTH, width);
274 renderer->egl->procs.eglQueryWaylandBufferWL(renderer->egl->display,
275 buffer, EGL_HEIGHT, height);
276 }
277
gles2_get_dmabuf_formats(struct wlr_renderer * wlr_renderer)278 static const struct wlr_drm_format_set *gles2_get_dmabuf_formats(
279 struct wlr_renderer *wlr_renderer) {
280 struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer);
281 return wlr_egl_get_dmabuf_formats(renderer->egl);
282 }
283
gles2_preferred_read_format(struct wlr_renderer * wlr_renderer)284 static enum wl_shm_format gles2_preferred_read_format(
285 struct wlr_renderer *wlr_renderer) {
286 struct wlr_gles2_renderer *renderer =
287 gles2_get_renderer_in_context(wlr_renderer);
288
289 GLint gl_format = -1, gl_type = -1;
290 push_gles2_debug(renderer);
291 glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &gl_format);
292 glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, &gl_type);
293 pop_gles2_debug(renderer);
294
295 EGLint alpha_size = -1;
296 eglGetConfigAttrib(renderer->egl->display, renderer->egl->config,
297 EGL_ALPHA_SIZE, &alpha_size);
298
299 const struct wlr_gles2_pixel_format *fmt =
300 get_gles2_format_from_gl(gl_format, gl_type, alpha_size > 0);
301 if (fmt != NULL) {
302 return fmt->wl_format;
303 }
304
305 if (renderer->exts.read_format_bgra_ext) {
306 return WL_SHM_FORMAT_XRGB8888;
307 }
308 return WL_SHM_FORMAT_XBGR8888;
309 }
310
gles2_read_pixels(struct wlr_renderer * wlr_renderer,enum wl_shm_format wl_fmt,uint32_t * flags,uint32_t stride,uint32_t width,uint32_t height,uint32_t src_x,uint32_t src_y,uint32_t dst_x,uint32_t dst_y,void * data)311 static bool gles2_read_pixels(struct wlr_renderer *wlr_renderer,
312 enum wl_shm_format wl_fmt, uint32_t *flags, uint32_t stride,
313 uint32_t width, uint32_t height, uint32_t src_x, uint32_t src_y,
314 uint32_t dst_x, uint32_t dst_y, void *data) {
315 struct wlr_gles2_renderer *renderer =
316 gles2_get_renderer_in_context(wlr_renderer);
317
318 const struct wlr_gles2_pixel_format *fmt = get_gles2_format_from_wl(wl_fmt);
319 if (fmt == NULL) {
320 wlr_log(WLR_ERROR, "Cannot read pixels: unsupported pixel format");
321 return false;
322 }
323
324 if (fmt->gl_format == GL_BGRA_EXT && !renderer->exts.read_format_bgra_ext) {
325 wlr_log(WLR_ERROR,
326 "Cannot read pixels: missing GL_EXT_read_format_bgra extension");
327 return false;
328 }
329
330 push_gles2_debug(renderer);
331
332 // Make sure any pending drawing is finished before we try to read it
333 glFinish();
334
335 glGetError(); // Clear the error flag
336
337 unsigned char *p = (unsigned char *)data + dst_y * stride;
338 uint32_t pack_stride = width * fmt->bpp / 8;
339 if (pack_stride == stride && dst_x == 0 && flags != NULL) {
340 // Under these particular conditions, we can read the pixels with only
341 // one glReadPixels call
342 glReadPixels(src_x, renderer->viewport_height - height - src_y,
343 width, height, fmt->gl_format, fmt->gl_type, p);
344 *flags = WLR_RENDERER_READ_PIXELS_Y_INVERT;
345 } else {
346 // Unfortunately GLES2 doesn't support GL_PACK_*, so we have to read
347 // the lines out row by row
348 for (size_t i = 0; i < height; ++i) {
349 glReadPixels(src_x, renderer->viewport_height - src_y - i - 1, width, 1, fmt->gl_format,
350 fmt->gl_type, p + i * stride + dst_x * fmt->bpp / 8);
351 }
352 if (flags != NULL) {
353 *flags = 0;
354 }
355 }
356
357 pop_gles2_debug(renderer);
358
359 return glGetError() == GL_NO_ERROR;
360 }
361
gles2_blit_dmabuf(struct wlr_renderer * wlr_renderer,struct wlr_dmabuf_attributes * dst_attr,struct wlr_dmabuf_attributes * src_attr)362 static bool gles2_blit_dmabuf(struct wlr_renderer *wlr_renderer,
363 struct wlr_dmabuf_attributes *dst_attr,
364 struct wlr_dmabuf_attributes *src_attr) {
365 struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer);
366 if (!renderer->procs.glEGLImageTargetRenderbufferStorageOES) {
367 return false;
368 }
369
370 struct wlr_egl_context old_context;
371 wlr_egl_save_context(&old_context);
372
373 bool r = false;
374 struct wlr_texture *src_tex =
375 wlr_texture_from_dmabuf(wlr_renderer, src_attr);
376 if (!src_tex) {
377 goto restore_context_out;
378 }
379
380 // This is to take into account y-inversion on both buffers rather than
381 // just the source buffer.
382 bool src_inverted_y =
383 !!(src_attr->flags & WLR_DMABUF_ATTRIBUTES_FLAGS_Y_INVERT);
384 bool dst_inverted_y =
385 !!(dst_attr->flags & WLR_DMABUF_ATTRIBUTES_FLAGS_Y_INVERT);
386 struct wlr_gles2_texture *gles2_src_tex = gles2_get_texture(src_tex);
387 // The result is negated because wlr_matrix_projection y-inverts the
388 // texture.
389 gles2_src_tex->inverted_y = !(src_inverted_y ^ dst_inverted_y);
390
391 if (!wlr_egl_make_current(renderer->egl, EGL_NO_SURFACE, NULL)) {
392 goto texture_destroy_out;
393 }
394
395 // TODO: The imported buffer should be checked with
396 // eglQueryDmaBufModifiersEXT to see if it may be modified.
397 bool external_only = false;
398 EGLImageKHR image = wlr_egl_create_image_from_dmabuf(renderer->egl, dst_attr,
399 &external_only);
400 if (image == EGL_NO_IMAGE_KHR) {
401 goto texture_destroy_out;
402 }
403
404 GLuint rbo = 0;
405 glGenRenderbuffers(1, &rbo);
406 glBindRenderbuffer(GL_RENDERBUFFER, rbo);
407 renderer->procs.glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER,
408 image);
409 glBindRenderbuffer(GL_RENDERBUFFER, 0);
410
411 GLuint fbo = 0;
412 glGenFramebuffers(1, &fbo);
413 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
414 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
415 GL_RENDERBUFFER, rbo);
416
417 GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
418 if (status != GL_FRAMEBUFFER_COMPLETE) {
419 goto out;
420 }
421
422 // TODO: use ANGLE_framebuffer_blit if available
423 float mat[9];
424 wlr_matrix_projection(mat, 1, 1, WL_OUTPUT_TRANSFORM_NORMAL);
425
426 wlr_renderer_begin(wlr_renderer, dst_attr->width, dst_attr->height);
427 wlr_renderer_clear(wlr_renderer, (float[]){ 0.0, 0.0, 0.0, 0.0 });
428 wlr_render_texture_with_matrix(wlr_renderer, src_tex, mat, 1.0f);
429 wlr_renderer_end(wlr_renderer);
430
431 r = true;
432 out:
433 glBindFramebuffer(GL_FRAMEBUFFER, 0);
434 glDeleteFramebuffers(1, &fbo);
435 glDeleteRenderbuffers(1, &rbo);
436 wlr_egl_destroy_image(renderer->egl, image);
437 texture_destroy_out:
438 wlr_texture_destroy(src_tex);
439 restore_context_out:
440 wlr_egl_restore_context(&old_context);
441 return r;
442 }
443
gles2_init_wl_display(struct wlr_renderer * wlr_renderer,struct wl_display * wl_display)444 static bool gles2_init_wl_display(struct wlr_renderer *wlr_renderer,
445 struct wl_display *wl_display) {
446 struct wlr_gles2_renderer *renderer =
447 gles2_get_renderer(wlr_renderer);
448
449 if (renderer->egl->exts.bind_wayland_display_wl) {
450 if (!wlr_egl_bind_display(renderer->egl, wl_display)) {
451 wlr_log(WLR_ERROR, "Failed to bind wl_display to EGL");
452 return false;
453 }
454 } else {
455 wlr_log(WLR_INFO, "EGL_WL_bind_wayland_display is not supported");
456 }
457
458 if (renderer->egl->exts.image_dmabuf_import_ext) {
459 if (wlr_linux_dmabuf_v1_create(wl_display, wlr_renderer) == NULL) {
460 return false;
461 }
462 } else {
463 wlr_log(WLR_INFO, "EGL_EXT_image_dma_buf_import is not supported");
464 }
465
466 return true;
467 }
468
wlr_gles2_renderer_get_egl(struct wlr_renderer * wlr_renderer)469 struct wlr_egl *wlr_gles2_renderer_get_egl(struct wlr_renderer *wlr_renderer) {
470 struct wlr_gles2_renderer *renderer =
471 gles2_get_renderer(wlr_renderer);
472 return renderer->egl;
473 }
474
gles2_destroy(struct wlr_renderer * wlr_renderer)475 static void gles2_destroy(struct wlr_renderer *wlr_renderer) {
476 struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer);
477
478 wlr_egl_make_current(renderer->egl, EGL_NO_SURFACE, NULL);
479
480 push_gles2_debug(renderer);
481 glDeleteProgram(renderer->shaders.quad.program);
482 glDeleteProgram(renderer->shaders.ellipse.program);
483 glDeleteProgram(renderer->shaders.tex_rgba.program);
484 glDeleteProgram(renderer->shaders.tex_rgbx.program);
485 glDeleteProgram(renderer->shaders.tex_ext.program);
486 pop_gles2_debug(renderer);
487
488 if (renderer->exts.debug_khr) {
489 glDisable(GL_DEBUG_OUTPUT_KHR);
490 renderer->procs.glDebugMessageCallbackKHR(NULL, NULL);
491 }
492
493 wlr_egl_unset_current(renderer->egl);
494
495 free(renderer);
496 }
497
498 static const struct wlr_renderer_impl renderer_impl = {
499 .destroy = gles2_destroy,
500 .begin = gles2_begin,
501 .end = gles2_end,
502 .clear = gles2_clear,
503 .scissor = gles2_scissor,
504 .render_subtexture_with_matrix = gles2_render_subtexture_with_matrix,
505 .render_quad_with_matrix = gles2_render_quad_with_matrix,
506 .render_ellipse_with_matrix = gles2_render_ellipse_with_matrix,
507 .formats = gles2_renderer_formats,
508 .format_supported = gles2_format_supported,
509 .resource_is_wl_drm_buffer = gles2_resource_is_wl_drm_buffer,
510 .wl_drm_buffer_get_size = gles2_wl_drm_buffer_get_size,
511 .get_dmabuf_formats = gles2_get_dmabuf_formats,
512 .preferred_read_format = gles2_preferred_read_format,
513 .read_pixels = gles2_read_pixels,
514 .texture_from_pixels = gles2_texture_from_pixels,
515 .texture_from_wl_drm = gles2_texture_from_wl_drm,
516 .texture_from_dmabuf = gles2_texture_from_dmabuf,
517 .init_wl_display = gles2_init_wl_display,
518 .blit_dmabuf = gles2_blit_dmabuf,
519 };
520
push_gles2_debug_(struct wlr_gles2_renderer * renderer,const char * file,const char * func)521 void push_gles2_debug_(struct wlr_gles2_renderer *renderer,
522 const char *file, const char *func) {
523 if (!renderer->procs.glPushDebugGroupKHR) {
524 return;
525 }
526
527 int len = snprintf(NULL, 0, "%s:%s", file, func) + 1;
528 char str[len];
529 snprintf(str, len, "%s:%s", file, func);
530 renderer->procs.glPushDebugGroupKHR(GL_DEBUG_SOURCE_APPLICATION_KHR, 1, -1, str);
531 }
532
pop_gles2_debug(struct wlr_gles2_renderer * renderer)533 void pop_gles2_debug(struct wlr_gles2_renderer *renderer) {
534 if (renderer->procs.glPopDebugGroupKHR) {
535 renderer->procs.glPopDebugGroupKHR();
536 }
537 }
538
gles2_log_importance_to_wlr(GLenum type)539 static enum wlr_log_importance gles2_log_importance_to_wlr(GLenum type) {
540 switch (type) {
541 case GL_DEBUG_TYPE_ERROR_KHR: return WLR_ERROR;
542 case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_KHR: return WLR_DEBUG;
543 case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_KHR: return WLR_ERROR;
544 case GL_DEBUG_TYPE_PORTABILITY_KHR: return WLR_DEBUG;
545 case GL_DEBUG_TYPE_PERFORMANCE_KHR: return WLR_DEBUG;
546 case GL_DEBUG_TYPE_OTHER_KHR: return WLR_DEBUG;
547 case GL_DEBUG_TYPE_MARKER_KHR: return WLR_DEBUG;
548 case GL_DEBUG_TYPE_PUSH_GROUP_KHR: return WLR_DEBUG;
549 case GL_DEBUG_TYPE_POP_GROUP_KHR: return WLR_DEBUG;
550 default: return WLR_DEBUG;
551 }
552 }
553
gles2_log(GLenum src,GLenum type,GLuint id,GLenum severity,GLsizei len,const GLchar * msg,const void * user)554 static void gles2_log(GLenum src, GLenum type, GLuint id, GLenum severity,
555 GLsizei len, const GLchar *msg, const void *user) {
556 _wlr_log(gles2_log_importance_to_wlr(type), "[GLES2] %s", msg);
557 }
558
compile_shader(struct wlr_gles2_renderer * renderer,GLuint type,const GLchar * src)559 static GLuint compile_shader(struct wlr_gles2_renderer *renderer,
560 GLuint type, const GLchar *src) {
561 push_gles2_debug(renderer);
562
563 GLuint shader = glCreateShader(type);
564 glShaderSource(shader, 1, &src, NULL);
565 glCompileShader(shader);
566
567 GLint ok;
568 glGetShaderiv(shader, GL_COMPILE_STATUS, &ok);
569 if (ok == GL_FALSE) {
570 glDeleteShader(shader);
571 shader = 0;
572 }
573
574 pop_gles2_debug(renderer);
575 return shader;
576 }
577
link_program(struct wlr_gles2_renderer * renderer,const GLchar * vert_src,const GLchar * frag_src)578 static GLuint link_program(struct wlr_gles2_renderer *renderer,
579 const GLchar *vert_src, const GLchar *frag_src) {
580 push_gles2_debug(renderer);
581
582 GLuint vert = compile_shader(renderer, GL_VERTEX_SHADER, vert_src);
583 if (!vert) {
584 goto error;
585 }
586
587 GLuint frag = compile_shader(renderer, GL_FRAGMENT_SHADER, frag_src);
588 if (!frag) {
589 glDeleteShader(vert);
590 goto error;
591 }
592
593 GLuint prog = glCreateProgram();
594 glAttachShader(prog, vert);
595 glAttachShader(prog, frag);
596 glLinkProgram(prog);
597
598 glDetachShader(prog, vert);
599 glDetachShader(prog, frag);
600 glDeleteShader(vert);
601 glDeleteShader(frag);
602
603 GLint ok;
604 glGetProgramiv(prog, GL_LINK_STATUS, &ok);
605 if (ok == GL_FALSE) {
606 glDeleteProgram(prog);
607 goto error;
608 }
609
610 pop_gles2_debug(renderer);
611 return prog;
612
613 error:
614 pop_gles2_debug(renderer);
615 return 0;
616 }
617
check_gl_ext(const char * exts,const char * ext)618 static bool check_gl_ext(const char *exts, const char *ext) {
619 size_t extlen = strlen(ext);
620 const char *end = exts + strlen(exts);
621
622 while (exts < end) {
623 if (exts[0] == ' ') {
624 exts++;
625 continue;
626 }
627 size_t n = strcspn(exts, " ");
628 if (n == extlen && strncmp(ext, exts, n) == 0) {
629 return true;
630 }
631 exts += n;
632 }
633 return false;
634 }
635
load_gl_proc(void * proc_ptr,const char * name)636 static void load_gl_proc(void *proc_ptr, const char *name) {
637 void *proc = (void *)eglGetProcAddress(name);
638 if (proc == NULL) {
639 wlr_log(WLR_ERROR, "eglGetProcAddress(%s) failed", name);
640 abort();
641 }
642 *(void **)proc_ptr = proc;
643 }
644
645 extern const GLchar quad_vertex_src[];
646 extern const GLchar quad_fragment_src[];
647 extern const GLchar ellipse_fragment_src[];
648 extern const GLchar tex_vertex_src[];
649 extern const GLchar tex_fragment_src_rgba[];
650 extern const GLchar tex_fragment_src_rgbx[];
651 extern const GLchar tex_fragment_src_external[];
652
wlr_gles2_renderer_create(struct wlr_egl * egl)653 struct wlr_renderer *wlr_gles2_renderer_create(struct wlr_egl *egl) {
654 if (!wlr_egl_make_current(egl, EGL_NO_SURFACE, NULL)) {
655 return NULL;
656 }
657
658 const char *exts_str = (const char *)glGetString(GL_EXTENSIONS);
659 if (exts_str == NULL) {
660 wlr_log(WLR_ERROR, "Failed to get GL_EXTENSIONS");
661 return NULL;
662 }
663
664 struct wlr_gles2_renderer *renderer =
665 calloc(1, sizeof(struct wlr_gles2_renderer));
666 if (renderer == NULL) {
667 return NULL;
668 }
669 wlr_renderer_init(&renderer->wlr_renderer, &renderer_impl);
670
671 renderer->egl = egl;
672 renderer->exts_str = exts_str;
673
674 wlr_log(WLR_INFO, "Using %s", glGetString(GL_VERSION));
675 wlr_log(WLR_INFO, "GL vendor: %s", glGetString(GL_VENDOR));
676 wlr_log(WLR_INFO, "GL renderer: %s", glGetString(GL_RENDERER));
677 wlr_log(WLR_INFO, "Supported GLES2 extensions: %s", exts_str);
678
679 if (!check_gl_ext(exts_str, "GL_EXT_texture_format_BGRA8888")) {
680 wlr_log(WLR_ERROR, "BGRA8888 format not supported by GLES2");
681 free(renderer);
682 return NULL;
683 }
684
685 renderer->exts.read_format_bgra_ext =
686 check_gl_ext(exts_str, "GL_EXT_read_format_bgra");
687
688 if (check_gl_ext(exts_str, "GL_KHR_debug")) {
689 renderer->exts.debug_khr = true;
690 load_gl_proc(&renderer->procs.glDebugMessageCallbackKHR,
691 "glDebugMessageCallbackKHR");
692 load_gl_proc(&renderer->procs.glDebugMessageControlKHR,
693 "glDebugMessageControlKHR");
694 }
695
696 if (check_gl_ext(exts_str, "GL_OES_EGL_image_external")) {
697 renderer->exts.egl_image_external_oes = true;
698 load_gl_proc(&renderer->procs.glEGLImageTargetTexture2DOES,
699 "glEGLImageTargetTexture2DOES");
700 }
701
702 if (check_gl_ext(exts_str, "GL_OES_EGL_image")) {
703 renderer->exts.egl_image_oes = true;
704 load_gl_proc(&renderer->procs.glEGLImageTargetRenderbufferStorageOES,
705 "glEGLImageTargetRenderbufferStorageOES");
706 }
707
708 if (renderer->exts.debug_khr) {
709 glEnable(GL_DEBUG_OUTPUT_KHR);
710 glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_KHR);
711 renderer->procs.glDebugMessageCallbackKHR(gles2_log, NULL);
712
713 // Silence unwanted message types
714 renderer->procs.glDebugMessageControlKHR(GL_DONT_CARE,
715 GL_DEBUG_TYPE_POP_GROUP_KHR, GL_DONT_CARE, 0, NULL, GL_FALSE);
716 renderer->procs.glDebugMessageControlKHR(GL_DONT_CARE,
717 GL_DEBUG_TYPE_PUSH_GROUP_KHR, GL_DONT_CARE, 0, NULL, GL_FALSE);
718 }
719
720 push_gles2_debug(renderer);
721
722 GLuint prog;
723 renderer->shaders.quad.program = prog =
724 link_program(renderer, quad_vertex_src, quad_fragment_src);
725 if (!renderer->shaders.quad.program) {
726 goto error;
727 }
728 renderer->shaders.quad.proj = glGetUniformLocation(prog, "proj");
729 renderer->shaders.quad.color = glGetUniformLocation(prog, "color");
730 renderer->shaders.quad.pos_attrib = glGetAttribLocation(prog, "pos");
731
732 renderer->shaders.ellipse.program = prog =
733 link_program(renderer, quad_vertex_src, ellipse_fragment_src);
734 if (!renderer->shaders.ellipse.program) {
735 goto error;
736 }
737 renderer->shaders.ellipse.proj = glGetUniformLocation(prog, "proj");
738 renderer->shaders.ellipse.color = glGetUniformLocation(prog, "color");
739 renderer->shaders.ellipse.pos_attrib = glGetAttribLocation(prog, "pos");
740 renderer->shaders.ellipse.tex_attrib = glGetAttribLocation(prog, "texcoord");
741
742 renderer->shaders.tex_rgba.program = prog =
743 link_program(renderer, tex_vertex_src, tex_fragment_src_rgba);
744 if (!renderer->shaders.tex_rgba.program) {
745 goto error;
746 }
747 renderer->shaders.tex_rgba.proj = glGetUniformLocation(prog, "proj");
748 renderer->shaders.tex_rgba.invert_y = glGetUniformLocation(prog, "invert_y");
749 renderer->shaders.tex_rgba.tex = glGetUniformLocation(prog, "tex");
750 renderer->shaders.tex_rgba.alpha = glGetUniformLocation(prog, "alpha");
751 renderer->shaders.tex_rgba.pos_attrib = glGetAttribLocation(prog, "pos");
752 renderer->shaders.tex_rgba.tex_attrib = glGetAttribLocation(prog, "texcoord");
753
754 renderer->shaders.tex_rgbx.program = prog =
755 link_program(renderer, tex_vertex_src, tex_fragment_src_rgbx);
756 if (!renderer->shaders.tex_rgbx.program) {
757 goto error;
758 }
759 renderer->shaders.tex_rgbx.proj = glGetUniformLocation(prog, "proj");
760 renderer->shaders.tex_rgbx.invert_y = glGetUniformLocation(prog, "invert_y");
761 renderer->shaders.tex_rgbx.tex = glGetUniformLocation(prog, "tex");
762 renderer->shaders.tex_rgbx.alpha = glGetUniformLocation(prog, "alpha");
763 renderer->shaders.tex_rgbx.pos_attrib = glGetAttribLocation(prog, "pos");
764 renderer->shaders.tex_rgbx.tex_attrib = glGetAttribLocation(prog, "texcoord");
765
766 if (renderer->exts.egl_image_external_oes) {
767 renderer->shaders.tex_ext.program = prog =
768 link_program(renderer, tex_vertex_src, tex_fragment_src_external);
769 if (!renderer->shaders.tex_ext.program) {
770 goto error;
771 }
772 renderer->shaders.tex_ext.proj = glGetUniformLocation(prog, "proj");
773 renderer->shaders.tex_ext.invert_y = glGetUniformLocation(prog, "invert_y");
774 renderer->shaders.tex_ext.tex = glGetUniformLocation(prog, "tex");
775 renderer->shaders.tex_ext.alpha = glGetUniformLocation(prog, "alpha");
776 renderer->shaders.tex_ext.pos_attrib = glGetAttribLocation(prog, "pos");
777 renderer->shaders.tex_ext.tex_attrib = glGetAttribLocation(prog, "texcoord");
778 }
779
780 pop_gles2_debug(renderer);
781
782 wlr_egl_unset_current(renderer->egl);
783
784 return &renderer->wlr_renderer;
785
786 error:
787 glDeleteProgram(renderer->shaders.quad.program);
788 glDeleteProgram(renderer->shaders.ellipse.program);
789 glDeleteProgram(renderer->shaders.tex_rgba.program);
790 glDeleteProgram(renderer->shaders.tex_rgbx.program);
791 glDeleteProgram(renderer->shaders.tex_ext.program);
792
793 pop_gles2_debug(renderer);
794
795 if (renderer->exts.debug_khr) {
796 glDisable(GL_DEBUG_OUTPUT_KHR);
797 renderer->procs.glDebugMessageCallbackKHR(NULL, NULL);
798 }
799
800 wlr_egl_unset_current(renderer->egl);
801
802 free(renderer);
803 return NULL;
804 }
805
wlr_gles2_renderer_check_ext(struct wlr_renderer * wlr_renderer,const char * ext)806 bool wlr_gles2_renderer_check_ext(struct wlr_renderer *wlr_renderer,
807 const char *ext) {
808 struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer);
809 return check_gl_ext(renderer->exts_str, ext);
810 }
811