From c63d94483b1e52817ca01ca82a867a78ebd39fa6 Mon Sep 17 00:00:00 2001
From: emersion <contact@emersion.fr>
Date: Sat, 24 Mar 2018 18:30:28 -0400
Subject: Redesign wlr_texture

- Textures are now immutable (apart from those created from raw
  pixels), no more invalid textures
- Move all wl_drm stuff in wlr_renderer
- Most of wlr_texture fields are now private
- Remove some duplicated DMA-BUF code in the DRM backend
- Add more assertions
- Stride is now always given as bytes rather than pixels
- Drop wl_shm functions

Fun fact: this patch has been written 10,000 meters up in the air.
---
 render/gles2/renderer.c | 124 ++++++++-----
 render/gles2/texture.c  | 464 +++++++++++++++++++-----------------------------
 2 files changed, 259 insertions(+), 329 deletions(-)

(limited to 'render/gles2')

diff --git a/render/gles2/renderer.c b/render/gles2/renderer.c
index 9403c0ed..dcda45e9 100644
--- a/render/gles2/renderer.c
+++ b/render/gles2/renderer.c
@@ -12,23 +12,27 @@
 #include <wlr/render/wlr_renderer.h>
 #include <wlr/types/wlr_matrix.h>
 #include <wlr/util/log.h>
-#include "render/gles2.h"
 #include "glapi.h"
+#include "render/gles2.h"
 
 static const struct wlr_renderer_impl renderer_impl;
 
-static struct wlr_gles2_renderer *gles2_get_renderer(
+struct wlr_gles2_renderer *gles2_get_renderer(
 		struct wlr_renderer *wlr_renderer) {
 	assert(wlr_renderer->impl == &renderer_impl);
-	struct wlr_gles2_renderer *renderer =
-		(struct wlr_gles2_renderer *)wlr_renderer;
+	return (struct wlr_gles2_renderer *)wlr_renderer;
+}
+
+struct wlr_gles2_renderer *gles2_get_renderer_in_context(
+		struct wlr_renderer *wlr_renderer) {
+	struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer);
 	assert(eglGetCurrentContext() == renderer->egl->context);
 	return renderer;
 }
 
 static void gles2_begin(struct wlr_renderer *wlr_renderer, uint32_t width,
 		uint32_t height) {
-	gles2_get_renderer(wlr_renderer);
+	gles2_get_renderer_in_context(wlr_renderer);
 
 	GLES2_DEBUG_PUSH;
 
@@ -45,13 +49,13 @@ static void gles2_begin(struct wlr_renderer *wlr_renderer, uint32_t width,
 }
 
 static void gles2_end(struct wlr_renderer *wlr_renderer) {
-	gles2_get_renderer(wlr_renderer);
+	gles2_get_renderer_in_context(wlr_renderer);
 	// no-op
 }
 
 static void gles2_clear(struct wlr_renderer *wlr_renderer,
 		const float color[static 4]) {
-	gles2_get_renderer(wlr_renderer);
+	gles2_get_renderer_in_context(wlr_renderer);
 
 	GLES2_DEBUG_PUSH;
 	glClearColor(color[0], color[1], color[2], color[3]);
@@ -61,7 +65,7 @@ static void gles2_clear(struct wlr_renderer *wlr_renderer,
 
 static void gles2_scissor(struct wlr_renderer *wlr_renderer,
 		struct wlr_box *box) {
-	gles2_get_renderer(wlr_renderer);
+	gles2_get_renderer_in_context(wlr_renderer);
 
 	GLES2_DEBUG_PUSH;
 	if (box != NULL) {
@@ -73,14 +77,6 @@ static void gles2_scissor(struct wlr_renderer *wlr_renderer,
 	GLES2_DEBUG_POP;
 }
 
-static struct wlr_texture *gles2_renderer_texture_create(
-		struct wlr_renderer *wlr_renderer) {
-	assert(wlr_renderer->impl == &renderer_impl);
-	struct wlr_gles2_renderer *renderer =
-		(struct wlr_gles2_renderer *)wlr_renderer;
-	return gles2_texture_create(renderer->egl);
-}
-
 static void draw_quad() {
 	GLfloat verts[] = {
 		1, 0, // top right
@@ -107,21 +103,28 @@ static void draw_quad() {
 	glDisableVertexAttribArray(1);
 }
 
-static bool gles2_render_texture_with_matrix(
-		struct wlr_renderer *wlr_renderer, struct wlr_texture *wlr_texture,
-		const float matrix[static 9], float alpha) {
-	struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer);
-	struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture);
-	if (!wlr_texture->valid) {
-		wlr_log(L_ERROR, "attempt to render invalid texture");
-		return false;
-	}
-
-	GLuint prog = renderer->shaders.tex_rgba;
-	if (texture->target == GL_TEXTURE_EXTERNAL_OES) {
+static bool gles2_render_texture_with_matrix(struct wlr_renderer *wlr_renderer,
+		struct wlr_texture *wlr_texture, const float matrix[static 9],
+		float alpha) {
+	struct wlr_gles2_renderer *renderer =
+		gles2_get_renderer_in_context(wlr_renderer);
+	struct wlr_gles2_texture *texture =
+		gles2_get_texture_in_context(wlr_texture);
+
+	GLuint prog;
+	GLenum target;
+	switch (texture->type) {
+	case WLR_GLES2_TEXTURE_GLTEX:
+	case WLR_GLES2_TEXTURE_WL_DRM_GL:
+		prog = texture->has_alpha ? renderer->shaders.tex_rgba :
+			renderer->shaders.tex_rgbx;
+		target = GL_TEXTURE_2D;
+		break;
+	case WLR_GLES2_TEXTURE_WL_DRM_EXT:
+	case WLR_GLES2_TEXTURE_DMABUF:
 		prog = renderer->shaders.tex_ext;
-	} else if (!texture->pixel_format->has_alpha) {
-		prog = renderer->shaders.tex_rgbx;
+		target = GL_TEXTURE_EXTERNAL_OES;
+		break;
 	}
 
 	// OpenGL ES 2 requires the glUniformMatrix3fv transpose parameter to be set
@@ -130,15 +133,23 @@ static bool gles2_render_texture_with_matrix(
 	wlr_matrix_transpose(transposition, matrix);
 
 	GLES2_DEBUG_PUSH;
-	glBindTexture(texture->target, texture->tex_id);
-	glTexParameteri(texture->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-	glTexParameteri(texture->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+	GLuint tex_id = texture->type == WLR_GLES2_TEXTURE_GLTEX ?
+		texture->gl_tex : texture->image_tex;
+	glActiveTexture(GL_TEXTURE0);
+	glBindTexture(target, tex_id);
+
+	glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+	glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
 	glUseProgram(prog);
 
 	glUniformMatrix3fv(0, 1, GL_FALSE, transposition);
-	glUniform1i(1, wlr_texture->inverted_y);
+	glUniform1i(1, texture->inverted_y);
 	glUniform1f(3, alpha);
+
 	draw_quad();
+
 	GLES2_DEBUG_POP;
 	return true;
 }
@@ -146,7 +157,8 @@ static bool gles2_render_texture_with_matrix(
 
 static void gles2_render_quad(struct wlr_renderer *wlr_renderer,
 		const float color[static 4], const float matrix[static 9]) {
-	struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer);
+	struct wlr_gles2_renderer *renderer =
+		gles2_get_renderer_in_context(wlr_renderer);
 
 	// OpenGL ES 2 requires the glUniformMatrix3fv transpose parameter to be set
 	// to GL_FALSE
@@ -163,7 +175,8 @@ static void gles2_render_quad(struct wlr_renderer *wlr_renderer,
 
 static void gles2_render_ellipse(struct wlr_renderer *wlr_renderer,
 		const float color[static 4], const float matrix[static 9]) {
-	struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer);
+	struct wlr_gles2_renderer *renderer =
+		gles2_get_renderer_in_context(wlr_renderer);
 
 	// OpenGL ES 2 requires the glUniformMatrix3fv transpose parameter to be set
 	// to GL_FALSE
@@ -183,20 +196,38 @@ static const enum wl_shm_format *gles2_renderer_formats(
 	return gles2_formats(len);
 }
 
-static bool gles2_buffer_is_drm(struct wlr_renderer *wlr_renderer,
-		struct wl_resource *buffer) {
-	struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer);
+static bool gles2_resource_is_wl_drm_buffer(struct wlr_renderer *wlr_renderer,
+		struct wl_resource *resource) {
+	struct wlr_gles2_renderer *renderer =
+		gles2_get_renderer_in_context(wlr_renderer);
+
+	if (!eglQueryWaylandBufferWL) {
+		return false;
+	}
+
+	EGLint fmt;
+	return eglQueryWaylandBufferWL(renderer->egl->display, resource,
+		EGL_TEXTURE_FORMAT, &fmt);
+}
+
+static void gles2_wl_drm_buffer_get_size(struct wlr_renderer *wlr_renderer,
+		struct wl_resource *buffer, int *width, int *height) {
+	struct wlr_gles2_renderer *renderer =
+		gles2_get_renderer_in_context(wlr_renderer);
+
+	if (!eglQueryWaylandBufferWL) {
+		return;
+	}
 
-	EGLint format;
-	return wlr_egl_query_buffer(renderer->egl, buffer, EGL_TEXTURE_FORMAT,
-		&format);
+	eglQueryWaylandBufferWL(renderer->egl->display, buffer, EGL_WIDTH, width);
+	eglQueryWaylandBufferWL(renderer->egl->display, buffer, EGL_HEIGHT, height);
 }
 
 static bool gles2_read_pixels(struct wlr_renderer *wlr_renderer,
 		enum wl_shm_format wl_fmt, 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) {
-	gles2_get_renderer(wlr_renderer);
+	gles2_get_renderer_in_context(wlr_renderer);
 
 	const struct gles2_pixel_format *fmt = gles2_format_from_wl(wl_fmt);
 	if (fmt == NULL) {
@@ -254,14 +285,17 @@ static const struct wlr_renderer_impl renderer_impl = {
 	.end = gles2_end,
 	.clear = gles2_clear,
 	.scissor = gles2_scissor,
-	.texture_create = gles2_renderer_texture_create,
 	.render_texture_with_matrix = gles2_render_texture_with_matrix,
 	.render_quad = gles2_render_quad,
 	.render_ellipse = gles2_render_ellipse,
 	.formats = gles2_renderer_formats,
-	.buffer_is_drm = gles2_buffer_is_drm,
+	.resource_is_wl_drm_buffer = gles2_resource_is_wl_drm_buffer,
+	.wl_drm_buffer_get_size = gles2_wl_drm_buffer_get_size,
 	.read_pixels = gles2_read_pixels,
 	.format_supported = gles2_format_supported,
+	.texture_from_pixels = gles2_texture_from_pixels,
+	.texture_from_wl_drm = gles2_texture_from_wl_drm,
+	.texture_from_dmabuf = gles2_texture_from_dmabuf,
 };
 
 void gles2_push_marker(const char *file, const char *func) {
diff --git a/render/gles2/texture.c b/render/gles2/texture.c
index 46193c78..82effd71 100644
--- a/render/gles2/texture.c
+++ b/render/gles2/texture.c
@@ -10,366 +10,262 @@
 #include <wlr/render/interface.h>
 #include <wlr/types/wlr_matrix.h>
 #include <wlr/util/log.h>
+#include "glapi.h"
 #include "render/gles2.h"
 #include "util/signal.h"
 
-static struct gles2_pixel_format external_pixel_format = {
-	.wl_format = 0,
-	.depth = 0,
-	.bpp = 0,
-	.gl_format = 0,
-	.gl_type = 0,
-};
-
-static void gles2_texture_ensure(struct wlr_gles2_texture *texture,
-		GLenum target) {
-	if (texture->tex_id) {
-		return;
-	}
-	texture->target = target;
-	glGenTextures(1, &texture->tex_id);
-	glBindTexture(target, texture->tex_id);
-	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-}
-
 static const struct wlr_texture_impl texture_impl;
 
-struct wlr_gles2_texture *gles2_get_texture(struct wlr_texture *wlr_texture) {
+static struct wlr_gles2_texture *gles2_get_texture(
+		struct wlr_texture *wlr_texture) {
 	assert(wlr_texture->impl == &texture_impl);
 	return (struct wlr_gles2_texture *)wlr_texture;
 }
 
-static bool gles2_texture_upload_pixels(struct wlr_texture *wlr_texture,
-		enum wl_shm_format format, int stride, int width, int height,
-		const unsigned char *pixels) {
+struct wlr_gles2_texture *gles2_get_texture_in_context(
+		struct wlr_texture *wlr_texture) {
 	struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture);
-
-	const struct gles2_pixel_format *fmt = gles2_format_from_wl(format);
-	if (!fmt || !fmt->gl_format) {
-		wlr_log(L_ERROR, "No supported pixel format for this texture");
-		return false;
-	}
-	texture->wlr_texture.width = width;
-	texture->wlr_texture.height = height;
-	texture->wlr_texture.format = format;
-	texture->pixel_format = fmt;
-
-	GLES2_DEBUG_PUSH;
-	gles2_texture_ensure(texture, GL_TEXTURE_2D);
-	glBindTexture(GL_TEXTURE_2D, texture->tex_id);
-	glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, stride);
-	glTexImage2D(GL_TEXTURE_2D, 0, fmt->gl_format, width, height, 0,
-		fmt->gl_format, fmt->gl_type, pixels);
-	GLES2_DEBUG_POP;
-
-	texture->wlr_texture.valid = true;
-	return true;
+	assert(eglGetCurrentContext() == texture->renderer->egl->context);
+	return texture;
 }
 
-static bool gles2_texture_update_pixels(struct wlr_texture *wlr_texture,
-		enum wl_shm_format format, int stride, int x, int y,
-		int width, int height, const unsigned char *pixels) {
+static void gles2_texture_get_size(struct wlr_texture *wlr_texture, int *width,
+		int *height) {
 	struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture);
-
-	// TODO: Test if the unpack subimage extension is supported and adjust the
-	// upload strategy if not
-	if (!texture->wlr_texture.valid
-			|| texture->wlr_texture.format != format
-		/*	|| unpack not supported */) {
-		return gles2_texture_upload_pixels(&texture->wlr_texture, format,
-			stride, width, height, pixels);
-	}
-	const struct gles2_pixel_format *fmt = texture->pixel_format;
-	GLES2_DEBUG_PUSH;
-	glBindTexture(GL_TEXTURE_2D, texture->tex_id);
-	glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, stride);
-	glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, x);
-	glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, y);
-	glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, fmt->gl_format,
-		fmt->gl_type, pixels);
-	glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, 0);
-	glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, 0);
-	GLES2_DEBUG_POP;
-	return true;
+	*width = texture->width;
+	*height = texture->height;
 }
 
-static bool gles2_texture_upload_shm(struct wlr_texture *wlr_texture,
-		uint32_t format, struct wl_shm_buffer *buffer) {
-	struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture);
+static bool gles2_texture_write_pixels(struct wlr_texture *wlr_texture,
+		enum wl_shm_format wl_fmt, 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, const void *data) {
+	struct wlr_gles2_texture *texture =
+		gles2_get_texture_in_context(wlr_texture);
+
+	if (texture->type != WLR_GLES2_TEXTURE_GLTEX) {
+		wlr_log(L_ERROR, "Cannot write pixels to immutable texture");
+		return false;
+	}
 
-	const struct gles2_pixel_format *fmt = gles2_format_from_wl(format);
-	if (!fmt || !fmt->gl_format) {
-		wlr_log(L_ERROR, "Unsupported pixel format %"PRIu32" for this texture",
-				format);
+	const struct gles2_pixel_format *fmt = gles2_format_from_wl(wl_fmt);
+	if (fmt == NULL) {
+		wlr_log(L_ERROR, "Unsupported pixel format %"PRIu32, wl_fmt);
 		return false;
 	}
-	wl_shm_buffer_begin_access(buffer);
-	uint8_t *pixels = wl_shm_buffer_get_data(buffer);
-	int width = wl_shm_buffer_get_width(buffer);
-	int height = wl_shm_buffer_get_height(buffer);
-	int pitch = wl_shm_buffer_get_stride(buffer) / (fmt->bpp / 8);
-	texture->wlr_texture.width = width;
-	texture->wlr_texture.height = height;
-	texture->wlr_texture.format = format;
-	texture->pixel_format = fmt;
 
+	// TODO: what if the unpack subimage extension isn't supported?
 	GLES2_DEBUG_PUSH;
-	gles2_texture_ensure(texture, GL_TEXTURE_2D);
-	glBindTexture(GL_TEXTURE_2D, texture->tex_id);
-	glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, pitch);
-	glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, 0);
-	glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, 0);
-	glTexImage2D(GL_TEXTURE_2D, 0, fmt->gl_format, width, height, 0,
-		fmt->gl_format, fmt->gl_type, pixels);
-	GLES2_DEBUG_POP;
 
-	texture->wlr_texture.valid = true;
-	wl_shm_buffer_end_access(buffer);
-	return true;
-}
+	glBindTexture(GL_TEXTURE_2D, texture->gl_tex);
 
-static bool gles2_texture_update_shm(struct wlr_texture *wlr_texture,
-		uint32_t format, int x, int y, int width, int height,
-		struct wl_shm_buffer *buffer) {
-	struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture);
+	glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, stride / (fmt->bpp / 8));
+	glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, src_x);
+	glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, src_y);
 
-	// TODO: Test if the unpack subimage extension is supported and adjust the
-	// upload strategy if not
-	assert(texture);
-	if (!texture->wlr_texture.valid
-			|| texture->wlr_texture.format != format
-		/*	|| unpack not supported */) {
-		return gles2_texture_upload_shm(&texture->wlr_texture, format, buffer);
-	}
-	const struct gles2_pixel_format *fmt = texture->pixel_format;
-	wl_shm_buffer_begin_access(buffer);
-	uint8_t *pixels = wl_shm_buffer_get_data(buffer);
-	int pitch = wl_shm_buffer_get_stride(buffer) / (fmt->bpp / 8);
+	glTexSubImage2D(GL_TEXTURE_2D, 0, dst_x, dst_y, width, height,
+		fmt->gl_format, fmt->gl_type, data);
 
-	GLES2_DEBUG_PUSH;
-	glBindTexture(GL_TEXTURE_2D, texture->tex_id);
-	glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, pitch);
-	glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, x);
-	glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, y);
-	glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height,
-			fmt->gl_format, fmt->gl_type, pixels);
+	glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, 0);
 	glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, 0);
 	glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, 0);
-	GLES2_DEBUG_POP;
-
-	wl_shm_buffer_end_access(buffer);
 
+	GLES2_DEBUG_POP;
 	return true;
 }
 
-static bool gles2_texture_upload_drm(struct wlr_texture *wlr_texture,
-		struct wl_resource *buf) {
-	struct wlr_gles2_texture *tex = gles2_get_texture(wlr_texture);
-	if (!glEGLImageTargetTexture2DOES) {
-		return false;
+static void gles2_texture_destroy(struct wlr_texture *wlr_texture) {
+	if (wlr_texture == NULL) {
+		return;
 	}
 
-	EGLint format;
-	if (!wlr_egl_query_buffer(tex->egl, buf, EGL_TEXTURE_FORMAT, &format)) {
-		wlr_log(L_INFO, "upload_drm called with no drm buffer");
-		return false;
-	}
+	struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture);
 
-	wlr_egl_query_buffer(tex->egl, buf, EGL_WIDTH,
-		(EGLint*)&tex->wlr_texture.width);
-	wlr_egl_query_buffer(tex->egl, buf, EGL_HEIGHT,
-		(EGLint*)&tex->wlr_texture.height);
+	wlr_egl_make_current(texture->renderer->egl, EGL_NO_SURFACE, NULL);
 
-	EGLint inverted_y;
-	if (wlr_egl_query_buffer(tex->egl, buf, EGL_WAYLAND_Y_INVERTED_WL,
-			&inverted_y)) {
-		tex->wlr_texture.inverted_y = !!inverted_y;
+	GLES2_DEBUG_PUSH;
+
+	if (texture->image_tex) {
+		glDeleteTextures(1, &texture->image_tex);
+	}
+	if (texture->image) {
+		assert(eglDestroyImageKHR);
+		eglDestroyImageKHR(texture->renderer->egl->display, texture->image);
 	}
 
-	GLenum target;
-	const struct gles2_pixel_format *pf;
-	switch (format) {
-	case EGL_TEXTURE_RGB:
-	case EGL_TEXTURE_RGBA:
-		target = GL_TEXTURE_2D;
-		pf = gles2_format_from_wl(WL_SHM_FORMAT_ARGB8888);
-		break;
-	case EGL_TEXTURE_EXTERNAL_WL:
-		target = GL_TEXTURE_EXTERNAL_OES;
-		pf = &external_pixel_format;
-		break;
-	default:
-		wlr_log(L_ERROR, "invalid/unsupported egl buffer format");
-		return false;
+	if (texture->type == WLR_GLES2_TEXTURE_GLTEX) {
+		glDeleteTextures(1, &texture->gl_tex);
 	}
 
-	GLES2_DEBUG_PUSH;
-	gles2_texture_ensure(tex, target);
-	glBindTexture(GL_TEXTURE_2D, tex->tex_id);
 	GLES2_DEBUG_POP;
 
-	EGLint attribs[] = { EGL_WAYLAND_PLANE_WL, 0, EGL_NONE };
+	free(texture);
+}
 
-	if (tex->image) {
-		wlr_egl_destroy_image(tex->egl, tex->image);
+static const struct wlr_texture_impl texture_impl = {
+	.get_size = gles2_texture_get_size,
+	.write_pixels = gles2_texture_write_pixels,
+	.destroy = gles2_texture_destroy,
+};
+
+struct wlr_texture *gles2_texture_from_pixels(struct wlr_renderer *wlr_renderer,
+		enum wl_shm_format wl_fmt, uint32_t stride, uint32_t width,
+		uint32_t height, const void *data) {
+	struct wlr_gles2_renderer *renderer =
+		gles2_get_renderer_in_context(wlr_renderer);
+
+	const struct gles2_pixel_format *fmt = gles2_format_from_wl(wl_fmt);
+	if (fmt == NULL) {
+		wlr_log(L_ERROR, "Unsupported pixel format %"PRIu32, wl_fmt);
+		return NULL;
 	}
 
-	tex->image = wlr_egl_create_image(tex->egl, EGL_WAYLAND_BUFFER_WL,
-		(EGLClientBuffer*) buf, attribs);
-	if (!tex->image) {
-		wlr_log(L_ERROR, "failed to create EGL image");
- 		return false;
+	struct wlr_gles2_texture *texture =
+		calloc(1, sizeof(struct wlr_gles2_texture));
+	if (texture == NULL) {
+		wlr_log(L_ERROR, "Allocation failed");
+		return NULL;
 	}
+	wlr_texture_init(&texture->wlr_texture, &texture_impl);
+	texture->renderer = renderer;
+	texture->width = width;
+	texture->height = height;
+	texture->type = WLR_GLES2_TEXTURE_GLTEX;
+	texture->has_alpha = fmt->has_alpha;
 
 	GLES2_DEBUG_PUSH;
-	glActiveTexture(GL_TEXTURE0);
-	glBindTexture(target, tex->tex_id);
-	glEGLImageTargetTexture2DOES(target, tex->image);
-	GLES2_DEBUG_POP;
-	tex->wlr_texture.valid = true;
-	tex->pixel_format = pf;
-
-	return true;
-}
 
-static bool gles2_texture_upload_eglimage(struct wlr_texture *wlr_texture,
-		EGLImageKHR image, uint32_t width, uint32_t height) {
-	struct wlr_gles2_texture *tex = gles2_get_texture(wlr_texture);
+	glGenTextures(1, &texture->gl_tex);
+	glBindTexture(GL_TEXTURE_2D, texture->gl_tex);
 
-	tex->image = image;
-	tex->pixel_format = &external_pixel_format;
-	tex->wlr_texture.valid = true;
-	tex->wlr_texture.width = width;
-	tex->wlr_texture.height = height;
+	glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, stride / (fmt->bpp / 8));
+	glTexImage2D(GL_TEXTURE_2D, 0, fmt->gl_format, width, height, 0,
+		fmt->gl_format, fmt->gl_type, data);
+	glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, 0);
 
-	GLES2_DEBUG_PUSH;
-	gles2_texture_ensure(tex, GL_TEXTURE_2D);
-	glActiveTexture(GL_TEXTURE0);
-	glBindTexture(GL_TEXTURE_EXTERNAL_OES, tex->tex_id);
-	glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, tex->image);
 	GLES2_DEBUG_POP;
-
-	return true;
+	return (struct wlr_texture *)texture;
 }
 
-static bool gles2_texture_upload_dmabuf(struct wlr_texture *wlr_texture,
-		struct wl_resource *dmabuf_resource) {
-	struct wlr_gles2_texture *tex = gles2_get_texture(wlr_texture);
-	struct wlr_dmabuf_buffer *dmabuf =
-		wlr_dmabuf_buffer_from_buffer_resource(dmabuf_resource);
+struct wlr_texture *gles2_texture_from_wl_drm(struct wlr_renderer *wlr_renderer,
+		struct wl_resource *data) {
+	struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer);
 
-	if (!tex->egl->egl_exts.dmabuf_import) {
-		wlr_log(L_ERROR, "Want dmabuf but extension not present");
-		return false;
+	if (!eglQueryWaylandBufferWL || !eglCreateImageKHR ||
+			!glEGLImageTargetTexture2DOES) {
+		return NULL;
 	}
 
-	tex->wlr_texture.width = dmabuf->attributes.width;
-	tex->wlr_texture.height = dmabuf->attributes.height;
+	EGLint fmt;
+	if (!eglQueryWaylandBufferWL(renderer->egl->display, data,
+			EGL_TEXTURE_FORMAT, &fmt)) {
+		return NULL;
+	}
 
-	if (tex->image) {
-		wlr_egl_destroy_image(tex->egl, tex->image);
+	EGLint width, height;
+	eglQueryWaylandBufferWL(renderer->egl->display, data, EGL_WIDTH, &width);
+	eglQueryWaylandBufferWL(renderer->egl->display, data, EGL_HEIGHT, &height);
+
+	EGLint inverted_y;
+	if (!eglQueryWaylandBufferWL(renderer->egl->display, data,
+			EGL_WAYLAND_Y_INVERTED_WL, &inverted_y)) {
+		inverted_y = 0;
 	}
 
-	if (wlr_dmabuf_buffer_has_inverted_y(dmabuf)) {
-		wlr_texture->inverted_y = true;
+	struct wlr_gles2_texture *texture =
+		calloc(1, sizeof(struct wlr_gles2_texture));
+	if (texture == NULL) {
+		wlr_log(L_ERROR, "Allocation failed");
+		return NULL;
 	}
+	wlr_texture_init(&texture->wlr_texture, &texture_impl);
+	texture->renderer = renderer;
+	texture->width = width;
+	texture->height = height;
+	texture->wl_drm = data;
+	texture->inverted_y = !!inverted_y;
 
 	GLenum target;
-	const struct gles2_pixel_format *pf;
-	if (dmabuf->attributes.n_planes > 1) {
-		target = GL_TEXTURE_EXTERNAL_OES;
-		pf = &external_pixel_format;
-	} else {
+	switch (fmt) {
+	case EGL_TEXTURE_RGB:
+	case EGL_TEXTURE_RGBA:
 		target = GL_TEXTURE_2D;
-		pf = gles2_format_from_wl(WL_SHM_FORMAT_ARGB8888);
+		texture->type = WLR_GLES2_TEXTURE_WL_DRM_GL;
+		texture->has_alpha = fmt == EGL_TEXTURE_RGBA;
+		break;
+	case EGL_TEXTURE_EXTERNAL_WL:
+		target = GL_TEXTURE_EXTERNAL_OES;
+		texture->type = WLR_GLES2_TEXTURE_WL_DRM_EXT;
+		texture->has_alpha = true;
+		break;
+	default:
+		wlr_log(L_ERROR, "Invalid or unsupported EGL buffer format");
+		free(texture);
+		return NULL;
 	}
-	GLES2_DEBUG_PUSH;
-	gles2_texture_ensure(tex, target);
-	glBindTexture(target, tex->tex_id);
-	tex->image = wlr_egl_create_image_from_dmabuf(tex->egl, &dmabuf->attributes);
-	glActiveTexture(GL_TEXTURE0);
-	glEGLImageTargetTexture2DOES(target, tex->image);
-	GLES2_DEBUG_POP;
-	tex->pixel_format = pf;
-	tex->wlr_texture.valid = true;
-	return true;
-}
 
-static bool gles2_texture_get_dmabuf_size(struct wlr_texture *texture, struct
-		wl_resource *resource, int *width, int *height) {
-	if (!wlr_dmabuf_resource_is_buffer(resource)) {
-		return false;
+	EGLint attribs[] = {
+		EGL_WAYLAND_PLANE_WL, 0,
+		EGL_NONE,
+	};
+	texture->image = eglCreateImageKHR(renderer->egl->display,
+		renderer->egl->context, EGL_WAYLAND_BUFFER_WL, data, attribs);
+	if (texture->image == NULL) {
+		free(texture);
+		return NULL;
 	}
 
-	struct wlr_dmabuf_buffer *dmabuf =
-		wlr_dmabuf_buffer_from_buffer_resource(resource);
-	*width = dmabuf->attributes.width;
-	*height = dmabuf->attributes.height;
-	return true;
-}
-
-static void gles2_texture_get_buffer_size(struct wlr_texture *texture,
-		struct wl_resource *resource, int *width, int *height) {
-	struct wl_shm_buffer *buffer = wl_shm_buffer_get(resource);
-	if (!buffer) {
-		struct wlr_gles2_texture *tex = (struct wlr_gles2_texture *)texture;
-		if (!glEGLImageTargetTexture2DOES) {
-			return;
-		}
-		if (!wlr_egl_query_buffer(tex->egl, resource, EGL_WIDTH,
-				(EGLint*)width)) {
-			if (!gles2_texture_get_dmabuf_size(texture, resource, width,
-					height)) {
-				wlr_log(L_ERROR, "could not get size of the buffer");
-				return;
-			}
-		}
-		wlr_egl_query_buffer(tex->egl, resource, EGL_HEIGHT, (EGLint*)height);
+	GLES2_DEBUG_PUSH;
 
-		return;
-	}
+	glGenTextures(1, &texture->image_tex);
+	glBindTexture(target, texture->image_tex);
+	glEGLImageTargetTexture2DOES(target, texture->image);
 
-	*width = wl_shm_buffer_get_width(buffer);
-	*height = wl_shm_buffer_get_height(buffer);
+	GLES2_DEBUG_POP;
+	return (struct wlr_texture *)texture;
 }
 
-static void gles2_texture_destroy(struct wlr_texture *wlr_texture) {
-	struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture);
+struct wlr_texture *gles2_texture_from_dmabuf(struct wlr_renderer *wlr_renderer,
+		struct wlr_dmabuf_buffer_attribs *attribs) {
+	struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer);
 
-	wlr_signal_emit_safe(&texture->wlr_texture.destroy_signal,
-		&texture->wlr_texture);
-	if (texture->tex_id) {
-		GLES2_DEBUG_PUSH;
-		glDeleteTextures(1, &texture->tex_id);
-		GLES2_DEBUG_POP;
+	if (!glEGLImageTargetTexture2DOES) {
+		return NULL;
 	}
 
-	if (texture->image) {
-		wlr_egl_destroy_image(texture->egl, texture->image);
+	if (!renderer->egl->egl_exts.dmabuf_import) {
+		wlr_log(L_ERROR, "Cannot create DMA-BUF texture: EGL extension "
+			"unavailable");
+		return NULL;
 	}
 
-	free(texture);
-}
-
-static const struct wlr_texture_impl texture_impl = {
-	.upload_pixels = gles2_texture_upload_pixels,
-	.update_pixels = gles2_texture_update_pixels,
-	.upload_shm = gles2_texture_upload_shm,
-	.update_shm = gles2_texture_update_shm,
-	.upload_drm = gles2_texture_upload_drm,
-	.upload_dmabuf = gles2_texture_upload_dmabuf,
-	.upload_eglimage = gles2_texture_upload_eglimage,
-	.get_buffer_size = gles2_texture_get_buffer_size,
-	.destroy = gles2_texture_destroy,
-};
-
-struct wlr_texture *gles2_texture_create(struct wlr_egl *egl) {
-	struct wlr_gles2_texture *texture;
-	if (!(texture = calloc(1, sizeof(struct wlr_gles2_texture)))) {
+	struct wlr_gles2_texture *texture =
+		calloc(1, sizeof(struct wlr_gles2_texture));
+	if (texture == NULL) {
+		wlr_log(L_ERROR, "Allocation failed");
 		return NULL;
 	}
 	wlr_texture_init(&texture->wlr_texture, &texture_impl);
-	texture->egl = egl;
-	return &texture->wlr_texture;
+	texture->renderer = renderer;
+	texture->width = attribs->width;
+	texture->height = attribs->height;
+	texture->type = WLR_GLES2_TEXTURE_DMABUF;
+	texture->has_alpha = true;
+	texture->inverted_y =
+		(attribs->flags & WLR_DMABUF_BUFFER_ATTRIBS_FLAGS_Y_INVERT) != 0;
+
+	texture->image = wlr_egl_create_image_from_dmabuf(renderer->egl, attribs);
+	if (texture->image == NULL) {
+		free(texture);
+		return NULL;
+	}
+
+	GLES2_DEBUG_PUSH;
+
+	glGenTextures(1, &texture->image_tex);
+	glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture->image_tex);
+	glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, texture->image);
+
+	GLES2_DEBUG_POP;
+	return (struct wlr_texture *)texture;
 }
-- 
cgit v1.2.3