[weston] gl-renderer: add support of WL_SHM_FORMAT_YUV420

Vincent Abriou vincent.abriou at st.com
Thu Aug 4 13:35:06 UTC 2016


This patch allow weston to accept WL_SHM_FORMAT_YUV420 buffers.

In a gstreamer pipeline, the support of the WL_SHM_FORMAT_YUV420 by
weston avoid pixel conversion between software decoders and waylandsink.
Indeed, software decoders output I420 (YUV420 planar) that will
match with WL_SHM_FORMAT_YUV420.

It has been tested on top of weston-1.11

Change-Id: I672c68606e4e9c10550174f5ef8402eaf3512ea5
Signed-off-by: Vincent Abriou <vincent.abriou at st.com>
---
 libweston/gl-renderer.c | 70 +++++++++++++++++++++++++++++++++++++++----------
 1 file changed, 56 insertions(+), 14 deletions(-)

diff --git a/libweston/gl-renderer.c b/libweston/gl-renderer.c
index ed44c6d..57cfade 100644
--- a/libweston/gl-renderer.c
+++ b/libweston/gl-renderer.c
@@ -160,6 +160,11 @@ struct gl_surface_state {
 	int height; /* in pixels */
 	int y_inverted;
 
+	/* Extension needed for SHM YUV texture */
+	int offset[3]; /* offet per plane */
+	int hsub[3];   /* horizontal subsampling per plane */
+	int vsub[3];   /* vertical subsampling per plane */
+
 	struct weston_surface *surface;
 
 	struct wl_listener surface_destroy_listener;
@@ -1228,7 +1233,7 @@ gl_renderer_flush_damage(struct weston_surface *surface)
 	bool texture_used;
 	pixman_box32_t *rectangles;
 	void *data;
-	int i, n;
+	int i, j, n;
 
 	pixman_region32_union(&gs->texture_damage,
 			      &gs->texture_damage, &surface->damage);
@@ -1255,14 +1260,15 @@ gl_renderer_flush_damage(struct weston_surface *surface)
 	    !gs->needs_full_upload)
 		goto done;
 
-	glBindTexture(GL_TEXTURE_2D, gs->textures[0]);
-
 	if (!gr->has_unpack_subimage) {
 		wl_shm_buffer_begin_access(buffer->shm_buffer);
-		glTexImage2D(GL_TEXTURE_2D, 0, gs->gl_format,
-			     gs->pitch, buffer->height, 0,
-			     gs->gl_format, gs->gl_pixel_type,
-			     wl_shm_buffer_get_data(buffer->shm_buffer));
+		for (j = 0; j < gs->num_textures; j++) {
+			glBindTexture(GL_TEXTURE_2D, gs->textures[j]);
+			glTexImage2D(GL_TEXTURE_2D, 0, gs->gl_format,
+					gs->pitch / gs->hsub[j], buffer->height / gs->vsub[j], 0,
+					gs->gl_format, gs->gl_pixel_type,
+					wl_shm_buffer_get_data(buffer->shm_buffer) + gs->offset[j]);
+		}
 		wl_shm_buffer_end_access(buffer->shm_buffer);
 
 		goto done;
@@ -1275,9 +1281,12 @@ gl_renderer_flush_damage(struct weston_surface *surface)
 		glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, 0);
 		glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, 0);
 		wl_shm_buffer_begin_access(buffer->shm_buffer);
-		glTexImage2D(GL_TEXTURE_2D, 0, gs->gl_format,
-			     gs->pitch, buffer->height, 0,
-			     gs->gl_format, gs->gl_pixel_type, data);
+		for (j = 0; j < gs->num_textures; j++) {
+			glBindTexture(GL_TEXTURE_2D, gs->textures[j]);
+			glTexImage2D(GL_TEXTURE_2D, 0, gs->gl_format,
+					gs->pitch / gs->hsub[j], buffer->height / gs->vsub[j], 0,
+					gs->gl_format, gs->gl_pixel_type, data + gs->offset[j]);
+		}
 		wl_shm_buffer_end_access(buffer->shm_buffer);
 		goto done;
 	}
@@ -1291,9 +1300,12 @@ gl_renderer_flush_damage(struct weston_surface *surface)
 
 		glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, r.x1);
 		glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, r.y1);
-		glTexSubImage2D(GL_TEXTURE_2D, 0, r.x1, r.y1,
-				r.x2 - r.x1, r.y2 - r.y1,
-				gs->gl_format, gs->gl_pixel_type, data);
+		for (j = 0; j < gs->num_textures; j++) {
+			glBindTexture(GL_TEXTURE_2D, gs->textures[j]);
+			glTexSubImage2D(GL_TEXTURE_2D, 0, r.x1 / gs->hsub[j], r.y1 / gs->vsub[j],
+					(r.x2 - r.x1) / gs->hsub[j], (r.y2 - r.y1) / gs->vsub[j],
+					gs->gl_format, gs->gl_pixel_type, data + gs->offset[j]);
+		}
 	}
 	wl_shm_buffer_end_access(buffer->shm_buffer);
 
@@ -1334,6 +1346,7 @@ gl_renderer_attach_shm(struct weston_surface *es, struct weston_buffer *buffer,
 	struct gl_surface_state *gs = get_surface_state(es);
 	GLenum gl_format, gl_pixel_type;
 	int pitch;
+	int num_planes;
 
 	buffer->shm_buffer = shm_buffer;
 	buffer->width = wl_shm_buffer_get_width(shm_buffer);
@@ -1345,18 +1358,46 @@ gl_renderer_attach_shm(struct weston_surface *es, struct weston_buffer *buffer,
 		pitch = wl_shm_buffer_get_stride(shm_buffer) / 4;
 		gl_format = GL_BGRA_EXT;
 		gl_pixel_type = GL_UNSIGNED_BYTE;
+		num_planes = 1;
+		gs->offset[0] = 0;
+		gs->hsub[0] = 1;
+		gs->vsub[0] = 1;
 		break;
 	case WL_SHM_FORMAT_ARGB8888:
 		gs->shader = &gr->texture_shader_rgba;
 		pitch = wl_shm_buffer_get_stride(shm_buffer) / 4;
 		gl_format = GL_BGRA_EXT;
 		gl_pixel_type = GL_UNSIGNED_BYTE;
+		num_planes = 1;
+		gs->offset[0] = 0;
+		gs->hsub[0] = 1;
+		gs->vsub[0] = 1;
 		break;
 	case WL_SHM_FORMAT_RGB565:
 		gs->shader = &gr->texture_shader_rgbx;
 		pitch = wl_shm_buffer_get_stride(shm_buffer) / 2;
 		gl_format = GL_RGB;
 		gl_pixel_type = GL_UNSIGNED_SHORT_5_6_5;
+		num_planes = 1;
+		gs->offset[0] = 0;
+		gs->hsub[0] = 1;
+		gs->vsub[0] = 1;
+		break;
+	case WL_SHM_FORMAT_YUV420:
+		gs->shader = &gr->texture_shader_y_u_v;
+		pitch = wl_shm_buffer_get_stride(shm_buffer);
+		gl_format = GL_LUMINANCE;
+		gl_pixel_type = GL_UNSIGNED_BYTE;
+		num_planes = 3;
+		gs->offset[0] = 0;
+		gs->hsub[0] = 1;
+		gs->vsub[0] = 1;
+		gs->offset[1] = gs->offset[0] + (pitch / gs->hsub[0]) * (buffer->height / gs->vsub[0]);
+		gs->hsub[1] = 2;
+		gs->vsub[1] = 2;
+		gs->offset[2] = gs->offset[1] + (pitch / gs->hsub[1]) * (buffer->height / gs->vsub[1]);
+		gs->hsub[2] = 2;
+		gs->vsub[2] = 2;
 		break;
 	default:
 		weston_log("warning: unknown shm buffer format: %08x\n",
@@ -1383,7 +1424,7 @@ gl_renderer_attach_shm(struct weston_surface *es, struct weston_buffer *buffer,
 
 		gs->surface = es;
 
-		ensure_textures(gs, 1);
+		ensure_textures(gs, num_planes);
 	}
 }
 
@@ -2961,6 +3002,7 @@ gl_renderer_create(struct weston_compositor *ec, EGLenum platform,
 	}
 
 	wl_display_add_shm_format(ec->wl_display, WL_SHM_FORMAT_RGB565);
+	wl_display_add_shm_format(ec->wl_display, WL_SHM_FORMAT_YUV420);
 
 	wl_signal_init(&gr->destroy_signal);
 
-- 
1.9.1



More information about the wayland-devel mailing list