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