Move EGLConfig, EGLContext and EGLDisplay fields into gles2-renderer.

This moves the EGLConfig, EGLContext and EGLDisplay fields into
gles2-renderer. It also moves EGLDisplay creation and EGLConfig
selection into gles2-renderer.
diff --git a/src/gles2-renderer.c b/src/gles2-renderer.c
index 2559602..0f1873d 100644
--- a/src/gles2-renderer.c
+++ b/src/gles2-renderer.c
@@ -31,15 +31,18 @@
 
 #include "compositor.h"
 
-struct gles2_renderer {
-	struct weston_renderer base;
-	int fragment_shader_debug;
-};
-
 struct gles2_output_state {
 	EGLSurface egl_surface;
 };
 
+struct gles2_renderer {
+	struct weston_renderer base;
+	int fragment_shader_debug;
+
+	EGLDisplay egl_display;
+	EGLContext egl_context;
+	EGLConfig egl_config;
+};
 
 static inline struct gles2_output_state *
 get_output_state(struct weston_output *output)
@@ -47,6 +50,12 @@
 	return (struct gles2_output_state *)output->renderer_state;
 }
 
+static inline struct gles2_renderer *
+get_renderer(struct weston_compositor *ec)
+{
+	return (struct gles2_renderer *)ec->renderer;
+}
+
 static const char *
 egl_error_string(EGLint code)
 {
@@ -719,6 +728,7 @@
 {
 	struct gles2_output_state *go = get_output_state(output);
 	struct weston_compositor *compositor = output->compositor;
+	struct gles2_renderer *gr = get_renderer(compositor);
 	EGLBoolean ret;
 	static int errored;
 	int32_t width, height, i;
@@ -730,8 +740,8 @@
 
 	glViewport(0, 0, width, height);
 
-	ret = eglMakeCurrent(compositor->egl_display, go->egl_surface,
-			     go->egl_surface, compositor->egl_context);
+	ret = eglMakeCurrent(gr->egl_display, go->egl_surface,
+			     go->egl_surface, gr->egl_context);
 	if (ret == EGL_FALSE) {
 		if (errored)
 			return;
@@ -767,7 +777,7 @@
 
 	wl_signal_emit(&output->frame_signal, output);
 
-	ret = eglSwapBuffers(compositor->egl_display, go->egl_surface);
+	ret = eglSwapBuffers(gr->egl_display, go->egl_surface);
 	if (ret == EGL_FALSE && !errored) {
 		errored = 1;
 		weston_log("Failed in eglSwapBuffers.\n");
@@ -855,12 +865,13 @@
 gles2_renderer_attach(struct weston_surface *es, struct wl_buffer *buffer)
 {
 	struct weston_compositor *ec = es->compositor;
+	struct gles2_renderer *gr = get_renderer(ec);
 	EGLint attribs[3], format;
 	int i, num_planes;
 
 	if (!buffer) {
 		for (i = 0; i < es->num_images; i++) {
-			ec->destroy_image(ec->egl_display, es->images[i]);
+			ec->destroy_image(gr->egl_display, es->images[i]);
 			es->images[i] = NULL;
 		}
 		es->num_images = 0;
@@ -882,10 +893,10 @@
 			es->shader = &ec->texture_shader_rgbx;
 		else
 			es->shader = &ec->texture_shader_rgba;
-	} else if (ec->query_buffer(ec->egl_display, buffer,
+	} else if (ec->query_buffer(gr->egl_display, buffer,
 				    EGL_TEXTURE_FORMAT, &format)) {
 		for (i = 0; i < es->num_images; i++)
-			ec->destroy_image(ec->egl_display, es->images[i]);
+			ec->destroy_image(gr->egl_display, es->images[i]);
 		es->num_images = 0;
 		es->target = GL_TEXTURE_2D;
 		switch (format) {
@@ -919,7 +930,7 @@
 			attribs[0] = EGL_WAYLAND_PLANE_WL;
 			attribs[1] = i;
 			attribs[2] = EGL_NONE;
-			es->images[i] = ec->create_image(ec->egl_display,
+			es->images[i] = ec->create_image(gr->egl_display,
 							 NULL,
 							 EGL_WAYLAND_BUFFER_WL,
 							 buffer, attribs);
@@ -945,12 +956,13 @@
 gles2_renderer_destroy_surface(struct weston_surface *surface)
 {
 	struct weston_compositor *ec = surface->compositor;
+	struct gles2_renderer *gr = get_renderer(ec);
 	int i;
 
 	glDeleteTextures(surface->num_textures, surface->textures);
 
 	for (i = 0; i < surface->num_images; i++)
-		ec->destroy_image(ec->egl_display, surface->images[i]);
+		ec->destroy_image(gr->egl_display, surface->images[i]);
 }
 
 static const char vertex_shader[] =
@@ -1233,14 +1245,15 @@
 				    EGLNativeWindowType window)
 {
 	struct weston_compositor *ec = output->compositor;
+	struct gles2_renderer *gr = get_renderer(ec);
 	struct gles2_output_state *go = calloc(1, sizeof *go);
 
 	if (!go)
 		return -1;
 
 	go->egl_surface =
-		eglCreateWindowSurface(ec->egl_display,
-				       ec->egl_config,
+		eglCreateWindowSurface(gr->egl_display,
+				       gr->egl_config,
 				       window, NULL);
 
 	if (go->egl_surface == EGL_NO_SURFACE) {
@@ -1249,7 +1262,7 @@
 		return -1;
 	}
 
-	if (ec->egl_context == NULL)
+	if (gr->egl_context == NULL)
 		if (gles2_renderer_setup(ec, go->egl_surface) < 0) {
 			free(go);
 			return -1;
@@ -1263,9 +1276,10 @@
 WL_EXPORT void
 gles2_renderer_output_destroy(struct weston_output *output)
 {
+	struct gles2_renderer *gr = get_renderer(output->compositor);
 	struct gles2_output_state *go = get_output_state(output);
 
-	eglDestroySurface(output->compositor->egl_display, go->egl_surface);
+	eglDestroySurface(gr->egl_display, go->egl_surface);
 
 	free(go);
 }
@@ -1279,8 +1293,131 @@
 WL_EXPORT void
 gles2_renderer_destroy(struct weston_compositor *ec)
 {
+	struct gles2_renderer *gr = get_renderer(ec);
+
 	if (ec->has_bind_display)
-		ec->unbind_display(ec->egl_display, ec->wl_display);
+		ec->unbind_display(gr->egl_display, ec->wl_display);
+
+	/* Work around crash in egl_dri2.c's dri2_make_current() - when does this apply? */
+	eglMakeCurrent(gr->egl_display,
+		       EGL_NO_SURFACE, EGL_NO_SURFACE,
+		       EGL_NO_CONTEXT);
+
+	eglTerminate(gr->egl_display);
+	eglReleaseThread();
+}
+
+static int
+egl_choose_config(struct gles2_renderer *gr, const EGLint *attribs,
+	const EGLint *visual_id)
+{
+	EGLint count = 0;
+	EGLint matched = 0;
+	EGLConfig *configs;
+	int i;
+
+	if (!eglGetConfigs(gr->egl_display, NULL, 0, &count) || count < 1)
+		return -1;
+
+	configs = calloc(count, sizeof *configs);
+	if (!configs)
+		return -1;
+
+	if (!eglChooseConfig(gr->egl_display, attribs, configs,
+			      count, &matched))
+		goto out;
+
+	for (i = 0; i < matched; ++i) {
+		EGLint id;
+
+		if (visual_id) {
+			if (!eglGetConfigAttrib(gr->egl_display,
+					configs[i], EGL_NATIVE_VISUAL_ID,
+					&id))
+				continue;
+
+			if (id != *visual_id)
+				continue;
+		}
+
+		gr->egl_config = configs[i];
+
+		free(configs);
+		return 0;
+	}
+
+out:
+	free(configs);
+	return -1;
+}
+
+WL_EXPORT const EGLint gles2_renderer_opaque_attribs[] = {
+	EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+	EGL_RED_SIZE, 1,
+	EGL_GREEN_SIZE, 1,
+	EGL_BLUE_SIZE, 1,
+	EGL_ALPHA_SIZE, 0,
+	EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+	EGL_NONE
+};
+
+WL_EXPORT const EGLint gles2_renderer_alpha_attribs[] = {
+	EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+	EGL_RED_SIZE, 1,
+	EGL_GREEN_SIZE, 1,
+	EGL_BLUE_SIZE, 1,
+	EGL_ALPHA_SIZE, 1,
+	EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+	EGL_NONE
+};
+
+WL_EXPORT int
+gles2_renderer_create(struct weston_compositor *ec, EGLNativeDisplayType display,
+	const EGLint *attribs, const EGLint *visual_id)
+{
+	struct gles2_renderer *gr;
+	EGLint major, minor;
+
+	gr = calloc(1, sizeof *gr);
+
+	if (gr == NULL)
+		return -1;
+
+	gr->base.repaint_output = gles2_renderer_repaint_output;
+	gr->base.flush_damage = gles2_renderer_flush_damage;
+	gr->base.attach = gles2_renderer_attach;
+	gr->base.destroy_surface = gles2_renderer_destroy_surface;
+
+	gr->egl_display = eglGetDisplay(display);
+	if (gr->egl_display == EGL_NO_DISPLAY) {
+		weston_log("failed to create display\n");
+		goto err_egl;
+	}
+
+	if (!eglInitialize(gr->egl_display, &major, &minor)) {
+		weston_log("failed to initialize display\n");
+		goto err_egl;
+	}
+
+	if (egl_choose_config(gr, attribs, visual_id) < 0) {
+		weston_log("failed to choose EGL config\n");
+		goto err_egl;
+	}
+
+	ec->renderer = &gr->base;
+
+	return 0;
+
+err_egl:
+	print_egl_error_state();
+	free(gr);
+	return -1;
+}
+
+WL_EXPORT EGLDisplay
+gles2_renderer_display(struct weston_compositor *ec)
+{
+	return get_renderer(ec)->egl_display;
 }
 
 static int
@@ -1340,7 +1477,7 @@
 static int
 gles2_renderer_setup(struct weston_compositor *ec, EGLSurface egl_surface)
 {
-	struct gles2_renderer *renderer;
+	struct gles2_renderer *gr = get_renderer(ec);
 	const char *extensions;
 	EGLBoolean ret;
 
@@ -1349,35 +1486,31 @@
 		EGL_NONE
 	};
 
-	renderer = calloc(1, sizeof *renderer);
-	if (renderer == NULL)
-		return -1;
-
 	if (!eglBindAPI(EGL_OPENGL_ES_API)) {
 		weston_log("failed to bind EGL_OPENGL_ES_API\n");
 		print_egl_error_state();
 		return -1;
 	}
 
-	log_egl_config_info(ec->egl_display, ec->egl_config);
+	log_egl_config_info(gr->egl_display, gr->egl_config);
 
-	ec->egl_context = eglCreateContext(ec->egl_display, ec->egl_config,
+	gr->egl_context = eglCreateContext(gr->egl_display, gr->egl_config,
 					   EGL_NO_CONTEXT, context_attribs);
-	if (ec->egl_context == NULL) {
+	if (gr->egl_context == NULL) {
 		weston_log("failed to create context\n");
 		print_egl_error_state();
 		return -1;
 	}
 
-	ret = eglMakeCurrent(ec->egl_display, egl_surface,
-			     egl_surface, ec->egl_context);
+	ret = eglMakeCurrent(gr->egl_display, egl_surface,
+			     egl_surface, gr->egl_context);
 	if (ret == EGL_FALSE) {
 		weston_log("Failed to make EGL context current.\n");
 		print_egl_error_state();
 		return -1;
 	}
 
-	log_egl_gl_info(ec->egl_display);
+	log_egl_gl_info(gr->egl_display);
 
 	ec->image_target_texture_2d =
 		(void *) eglGetProcAddress("glEGLImageTargetTexture2DOES");
@@ -1415,7 +1548,7 @@
 		ec->has_egl_image_external = 1;
 
 	extensions =
-		(const char *) eglQueryString(ec->egl_display, EGL_EXTENSIONS);
+		(const char *) eglQueryString(gr->egl_display, EGL_EXTENSIONS);
 	if (!extensions) {
 		weston_log("Retrieving EGL extension string failed.\n");
 		return -1;
@@ -1424,19 +1557,13 @@
 	if (strstr(extensions, "EGL_WL_bind_wayland_display"))
 		ec->has_bind_display = 1;
 	if (ec->has_bind_display) {
-		ret = ec->bind_display(ec->egl_display, ec->wl_display);
+		ret = ec->bind_display(gr->egl_display, ec->wl_display);
 		if (!ret)
 			ec->has_bind_display = 0;
 	}
 
 	glActiveTexture(GL_TEXTURE0);
 
-	renderer->base.repaint_output = gles2_renderer_repaint_output;
-	renderer->base.flush_damage = gles2_renderer_flush_damage;
-	renderer->base.attach = gles2_renderer_attach;
-	renderer->base.destroy_surface = gles2_renderer_destroy_surface;
-	ec->renderer = &renderer->base;
-
 	if (compile_shaders(ec))
 		return -1;
 
@@ -1451,5 +1578,6 @@
 	weston_log_continue(STAMP_SPACE "EGL Wayland extension: %s\n",
 			    ec->has_bind_display ? "yes" : "no");
 
+
 	return 0;
 }