[PATCH weston 6/7] gl-renderer: implement surface_copy_content

Pekka Paalanen ppaalanen at gmail.com
Fri Feb 13 02:02:24 PST 2015


From: Pekka Paalanen <pekka.paalanen at collabora.co.uk>

Taking the easy way, always do a rendering pass when copying any real
buffer or texture. Will handle YUV formats, and makes it easy to always
return data the right y-direction up.

All the FBO GL state is created and torn down on every invocation, so this
is a pretty naive implementation.

Signed-off-by: Pekka Paalanen <pekka.paalanen at collabora.co.uk>
---
 src/gl-renderer.c | 164 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 164 insertions(+)

diff --git a/src/gl-renderer.c b/src/gl-renderer.c
index 022fc79..70b94e7 100644
--- a/src/gl-renderer.c
+++ b/src/gl-renderer.c
@@ -1,5 +1,6 @@
 /*
  * Copyright © 2012 Intel Corporation
+ * Copyright © 2015 Collabora, Ltd.
  *
  * Permission to use, copy, modify, distribute, and sell this software and
  * its documentation for any purpose is hereby granted without fee, provided
@@ -1364,6 +1365,166 @@ gl_renderer_surface_set_color(struct weston_surface *surface,
 }
 
 static void
+gl_renderer_surface_get_content_size(struct weston_surface *surface,
+				     int *width, int *height)
+{
+	struct gl_surface_state *gs = get_surface_state(surface);
+
+	if (gs->buffer_type == BUFFER_TYPE_NULL) {
+		*width = 0;
+		*height = 0;
+	} else {
+		*width = gs->pitch;
+		*height = gs->height;
+	}
+}
+
+static uint32_t
+pack_color(pixman_format_code_t format, float *c)
+{
+	uint32_t r32 = (uint8_t)round(c[0] * 255.0f);
+	uint32_t g32 = (uint8_t)round(c[1] * 255.0f);
+	uint32_t b32 = (uint8_t)round(c[2] * 255.0f);
+	uint32_t a32 = (uint8_t)round(c[3] * 255.0f);
+
+	switch (format) {
+	case PIXMAN_a8r8g8b8:
+		return (a32 << 24) | (r32 << 16) | (g32 << 8) | b32;
+	case PIXMAN_a8b8g8r8:
+		return (a32 << 24) | (b32 << 16) | (g32 << 8) | r32;
+	case PIXMAN_r8g8b8a8:
+		return (r32 << 24) | (g32 << 16) | (b32 << 8) | a32;
+	case PIXMAN_b8g8r8a8:
+		return (b32 << 24) | (g32 << 16) | (r32 << 8) | a32;
+	default:
+		return 0;
+	}
+}
+
+static int
+gl_renderer_surface_copy_content(struct weston_surface *surface,
+				 void *target, size_t stride, size_t size,
+				 int src_x, int src_y,
+				 int width, int height,
+				 pixman_format_code_t format)
+{
+	static const GLfloat verts[4 * 2] = {
+		0.0f, 0.0f,
+		1.0f, 0.0f,
+		1.0f, 1.0f,
+		0.0f, 1.0f
+	};
+	static const GLfloat projmat_normal[16] = { /* transpose */
+		 2.0f,  0.0f, 0.0f, 0.0f,
+		 0.0f,  2.0f, 0.0f, 0.0f,
+		 0.0f,  0.0f, 1.0f, 0.0f,
+		-1.0f, -1.0f, 0.0f, 1.0f
+	};
+	static const GLfloat projmat_yinvert[16] = { /* transpose */
+		 2.0f,  0.0f, 0.0f, 0.0f,
+		 0.0f, -2.0f, 0.0f, 0.0f,
+		 0.0f,  0.0f, 1.0f, 0.0f,
+		-1.0f,  1.0f, 0.0f, 1.0f
+	};
+	struct gl_renderer *gr = get_renderer(surface->compositor);
+	struct gl_surface_state *gs = get_surface_state(surface);
+	int cw, ch;
+	size_t bytespp;
+	GLuint fbo;
+	GLuint tex;
+	GLenum status;
+	GLenum gl_format;
+	const GLfloat *proj;
+	int i;
+
+	gl_renderer_surface_get_content_size(surface, &cw, &ch);
+
+	/* XXX: correct only for little-endian */
+	switch (format) {
+	case PIXMAN_a8b8g8r8:
+		bytespp = 4;
+		gl_format = GL_RGBA;
+		break;
+	default:
+		return -1;
+	}
+
+	switch (gs->buffer_type) {
+	case BUFFER_TYPE_NULL:
+		return -1;
+	case BUFFER_TYPE_SOLID:
+		*(uint32_t *)target = pack_color(format, gs->color);
+		return 0;
+	case BUFFER_TYPE_SHM:
+		gl_renderer_flush_damage(surface);
+		/* fall through */
+	case BUFFER_TYPE_EGL:
+		break;
+	}
+
+	glGenTextures(1, &tex);
+	glBindTexture(GL_TEXTURE_2D, tex);
+	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, cw, ch,
+		     0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+	glBindTexture(GL_TEXTURE_2D, 0);
+
+	glGenFramebuffers(1, &fbo);
+	glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+	glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+			       GL_TEXTURE_2D, tex, 0);
+
+	status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+	if (status != GL_FRAMEBUFFER_COMPLETE) {
+		weston_log("%s: fbo error: %#x\n", __func__, status);
+		glDeleteFramebuffers(1, &fbo);
+		glDeleteTextures(1, &tex);
+		return -1;
+	}
+
+	glViewport(0, 0, cw, ch);
+	glDisable(GL_BLEND);
+	use_shader(gr, gs->shader);
+	if (gs->y_inverted)
+		proj = projmat_normal;
+	else
+		proj = projmat_yinvert;
+
+	glUniformMatrix4fv(gs->shader->proj_uniform, 1, GL_FALSE, proj);
+	glUniform1f(gs->shader->alpha_uniform, 1.0f);
+
+	for (i = 0; i < gs->num_textures; i++) {
+		glUniform1i(gs->shader->tex_uniforms[i], i);
+
+		glActiveTexture(GL_TEXTURE0 + i);
+		glBindTexture(gs->target, gs->textures[i]);
+		glTexParameteri(gs->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+		glTexParameteri(gs->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+	}
+
+	/* position: */
+	glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, verts);
+	glEnableVertexAttribArray(0);
+
+	/* texcoord: */
+	glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, verts);
+	glEnableVertexAttribArray(1);
+
+	glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+
+	glDisableVertexAttribArray(1);
+	glDisableVertexAttribArray(0);
+
+	glPixelStorei(GL_PACK_ALIGNMENT, bytespp);
+	glReadPixels(src_x, src_y, width, height, gl_format,
+		     GL_UNSIGNED_BYTE, target);
+
+	glDeleteFramebuffers(1, &fbo);
+	glDeleteTextures(1, &tex);
+
+	return 0;
+}
+
+static void
 surface_state_destroy(struct gl_surface_state *gs, struct gl_renderer *gr)
 {
 	int i;
@@ -1992,6 +2153,9 @@ gl_renderer_create(struct weston_compositor *ec, EGLNativeDisplayType display,
 	gr->base.attach = gl_renderer_attach;
 	gr->base.surface_set_color = gl_renderer_surface_set_color;
 	gr->base.destroy = gl_renderer_destroy;
+	gr->base.surface_get_content_size =
+		gl_renderer_surface_get_content_size;
+	gr->base.surface_copy_content = gl_renderer_surface_copy_content;
 
 	gr->egl_display = eglGetDisplay(display);
 	if (gr->egl_display == EGL_NO_DISPLAY) {
-- 
2.0.5



More information about the wayland-devel mailing list