[weston,10/13] gl-renderer: Add stereoscopy support.

Submitted by Emmanuel Gil Peyrot on Nov. 14, 2017, 3:05 p.m.

Details

Message ID 20171114150600.1763-11-linkmauve@linkmauve.fr
State New
Headers show
Series "Add stereoscopy support" ( rev: 1 ) in Wayland

Not browsing as part of any series.

Commit Message

Emmanuel Gil Peyrot Nov. 14, 2017, 3:05 p.m.
Signed-off-by: Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
---
 libweston/compositor.c  |   5 +-
 libweston/gl-renderer.c | 135 ++++++++++++++++++++++++++++++++++++++++++------
 libweston/gl-renderer.h |   6 +++
 3 files changed, 128 insertions(+), 18 deletions(-)

Patch hide | download patch | download mbox

diff --git a/libweston/compositor.c b/libweston/compositor.c
index 9343bdbf..723dec02 100644
--- a/libweston/compositor.c
+++ b/libweston/compositor.c
@@ -5187,10 +5187,13 @@  destroy_stereoscopy_description(struct wl_resource *resource)
 	struct weston_surface *surface =
 		wl_resource_get_user_data(resource);
 
+	bool was_stereo = surface->pending.buffer_viewport.buffer.stereoscopy_layout !=
+	                  ZWP_STEREOSCOPY_V1_LAYOUT_NONE;
+
 	surface->stereoscopy_description_resource = NULL;
 	surface->pending.buffer_viewport.buffer.stereoscopy_layout = ZWP_STEREOSCOPY_V1_LAYOUT_NONE;
 	surface->pending.buffer_viewport.surface.default_side = ZWP_STEREOSCOPY_DESCRIPTION_V1_SIDE_DEFAULT;
-	surface->pending.buffer_viewport.changed = 1;
+	surface->pending.buffer_viewport.changed |= was_stereo;
 }
 
 static void
diff --git a/libweston/gl-renderer.c b/libweston/gl-renderer.c
index 244ce309..73b0d358 100644
--- a/libweston/gl-renderer.c
+++ b/libweston/gl-renderer.c
@@ -54,6 +54,7 @@ 
 #include "vertex-clipping.h"
 #include "linux-dmabuf.h"
 #include "linux-dmabuf-unstable-v1-server-protocol.h"
+#include "stereoscopy-unstable-v1-server-protocol.h"
 
 #include "shared/helpers.h"
 #include "shared/platform.h"
@@ -771,7 +772,8 @@  triangle_fan_debug(struct weston_view *view, int first, int count)
 
 static void
 repaint_region(struct weston_view *ev, pixman_region32_t *region,
-		pixman_region32_t *surf_region)
+               pixman_region32_t *surf_region,
+               enum gl_renderer_stereoscopy_side side)
 {
 	struct weston_compositor *ec = ev->surface->compositor;
 	struct gl_renderer *gr = get_renderer(ec);
@@ -792,6 +794,36 @@  repaint_region(struct weston_view *ev, pixman_region32_t *region,
 	v = gr->vertices.data;
 	vtxcnt = gr->vtxcnt.data;
 
+	assert(side == GL_RENDERER_SIDE_LEFT || side == GL_RENDERER_SIDE_RIGHT);
+	switch (ev->surface->buffer_viewport.buffer.stereoscopy_layout) {
+	case ZWP_STEREOSCOPY_V1_LAYOUT_NONE:
+		break;
+	case ZWP_STEREOSCOPY_V1_LAYOUT_FRAME_PACKING:
+		for (i = 0; i < nfans * 4; i++) {
+			if (side == GL_RENDERER_SIDE_RIGHT)
+				v[i * 4 + 3] += 25. / 24.;
+		}
+		break;
+	case ZWP_STEREOSCOPY_V1_LAYOUT_SIDE_BY_SIDE:
+		for (i = 0; i < nfans * 4; i++) {
+			v[i * 4 + 2] *= 0.5;
+			if (side == GL_RENDERER_SIDE_RIGHT)
+				v[i * 4 + 2] += 0.5;
+		}
+		break;
+	case ZWP_STEREOSCOPY_V1_LAYOUT_TOP_AND_BOTTOM:
+		for (i = 0; i < nfans * 4; i++) {
+			v[i * 4 + 3] *= 0.5;
+			if (side == GL_RENDERER_SIDE_RIGHT)
+				v[i * 4 + 3] += 0.5;
+		}
+		break;
+	default:
+		/* We currently only support side-by-side and
+		 * top-and-bottom layouts for client buffers. */
+		assert(0);
+	}
+
 	/* position: */
 	glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof *v, &v[0]);
 	glEnableVertexAttribArray(0);
@@ -881,7 +913,8 @@  shader_uniforms(struct gl_shader *shader,
 
 static void
 draw_view(struct weston_view *ev, struct weston_output *output,
-	  pixman_region32_t *damage) /* in global coordinates */
+          pixman_region32_t *damage, /* in global coordinates */
+          enum gl_renderer_stereoscopy_side side)
 {
 	struct weston_compositor *ec = ev->surface->compositor;
 	struct gl_renderer *gr = get_renderer(ec);
@@ -920,11 +953,22 @@  draw_view(struct weston_view *ev, struct weston_output *output,
 	shader_uniforms(gs->shader, ev, output);
 
 	if (ev->transform.enabled || output->zoom.active ||
-	    output->current_scale != ev->surface->buffer_viewport.buffer.scale)
+	    output->current_scale != ev->surface->buffer_viewport.buffer.scale ||
+	    (output->stereoscopy_layout != ZWP_STEREOSCOPY_V1_LAYOUT_NONE &&
+	     output->stereoscopy_layout != ZWP_STEREOSCOPY_V1_LAYOUT_FRAME_PACKING) ||
+	    ev->surface->buffer_viewport.buffer.stereoscopy_layout != ZWP_STEREOSCOPY_V1_LAYOUT_NONE)
 		filter = GL_LINEAR;
 	else
 		filter = GL_NEAREST;
 
+	if (output->stereoscopy_layout == ZWP_STEREOSCOPY_V1_LAYOUT_NONE &&
+	    side == GL_RENDERER_SIDE_DEFAULT) {
+		if (ev->surface->buffer_viewport.surface.default_side == ZWP_STEREOSCOPY_DESCRIPTION_V1_SIDE_DEFAULT)
+			side = GL_RENDERER_SIDE_LEFT;
+		else
+			side = ev->surface->buffer_viewport.surface.default_side;
+	}
+
 	for (i = 0; i < gs->num_textures; i++) {
 		glActiveTexture(GL_TEXTURE0 + i);
 		glBindTexture(gs->target, gs->textures[i]);
@@ -966,13 +1010,13 @@  draw_view(struct weston_view *ev, struct weston_output *output,
 		else
 			glDisable(GL_BLEND);
 
-		repaint_region(ev, &repaint, &surface_opaque);
+		repaint_region(ev, &repaint, &surface_opaque, side);
 	}
 
 	if (pixman_region32_not_empty(&surface_blend)) {
 		use_shader(gr, gs->shader);
 		glEnable(GL_BLEND);
-		repaint_region(ev, &repaint, &surface_blend);
+		repaint_region(ev, &repaint, &surface_blend, side);
 	}
 
 	pixman_region32_fini(&surface_blend);
@@ -983,14 +1027,15 @@  out:
 }
 
 static void
-repaint_views(struct weston_output *output, pixman_region32_t *damage)
+repaint_views(struct weston_output *output, pixman_region32_t *damage,
+              enum gl_renderer_stereoscopy_side side)
 {
 	struct weston_compositor *compositor = output->compositor;
 	struct weston_view *view;
 
 	wl_list_for_each_reverse(view, &compositor->view_list, link)
 		if (view->plane == &compositor->primary_plane)
-			draw_view(view, output, damage);
+			draw_view(view, output, damage, side);
 }
 
 static void
@@ -1248,14 +1293,6 @@  gl_renderer_repaint_output(struct weston_output *output,
 	if (use_output(output) < 0)
 		return;
 
-	begin_render_sync = timeline_create_render_sync(gr);
-
-	/* Calculate the viewport */
-	glViewport(go->borders[GL_RENDERER_BORDER_LEFT].width,
-		   go->borders[GL_RENDERER_BORDER_BOTTOM].height,
-		   output->current_mode->width,
-		   output->current_mode->height);
-
 	/* Calculate the global GL matrix */
 	go->output_matrix = output->matrix;
 	weston_matrix_translate(&go->output_matrix,
@@ -1274,7 +1311,7 @@  gl_renderer_repaint_output(struct weston_output *output,
 		pixman_region32_subtract(&undamaged, &output->region,
 					 output_damage);
 		gr->fan_debug = 0;
-		repaint_views(output, &undamaged);
+		repaint_views(output, &undamaged, GL_RENDERER_SIDE_DEFAULT);
 		gr->fan_debug = 1;
 		pixman_region32_fini(&undamaged);
 	}
@@ -1288,7 +1325,71 @@  gl_renderer_repaint_output(struct weston_output *output,
 	pixman_region32_union(&total_damage, &buffer_damage, output_damage);
 	border_damage |= go->border_status;
 
-	repaint_views(output, &total_damage);
+	begin_render_sync = timeline_create_render_sync(gr);
+
+	switch (output->stereoscopy_layout) {
+	case ZWP_STEREOSCOPY_V1_LAYOUT_NONE:
+		glViewport(go->borders[GL_RENDERER_BORDER_LEFT].width,
+			   go->borders[GL_RENDERER_BORDER_BOTTOM].height,
+			   output->current_mode->width,
+			   output->current_mode->height);
+
+		repaint_views(output, &total_damage, GL_RENDERER_SIDE_DEFAULT);
+		break;
+	case ZWP_STEREOSCOPY_V1_LAYOUT_SIDE_BY_SIDE:
+		/* Left eye */
+		glViewport(go->borders[GL_RENDERER_BORDER_LEFT].width,
+			   go->borders[GL_RENDERER_BORDER_BOTTOM].height,
+			   output->current_mode->width / 2,
+			   output->current_mode->height);
+
+		repaint_views(output, &total_damage, GL_RENDERER_SIDE_LEFT);
+
+		/* Right eye */
+		glViewport(go->borders[GL_RENDERER_BORDER_LEFT].width + output->current_mode->width / 2,
+			   go->borders[GL_RENDERER_BORDER_BOTTOM].height,
+			   output->current_mode->width / 2,
+			   output->current_mode->height);
+
+		repaint_views(output, &total_damage, GL_RENDERER_SIDE_RIGHT);
+		break;
+	case ZWP_STEREOSCOPY_V1_LAYOUT_TOP_AND_BOTTOM:
+		/* Left eye */
+		glViewport(go->borders[GL_RENDERER_BORDER_LEFT].width,
+			   go->borders[GL_RENDERER_BORDER_BOTTOM].height,
+			   output->current_mode->width,
+			   output->current_mode->height / 2);
+
+		repaint_views(output, &total_damage, GL_RENDERER_SIDE_LEFT);
+
+		/* Right eye */
+		glViewport(go->borders[GL_RENDERER_BORDER_LEFT].width,
+			   go->borders[GL_RENDERER_BORDER_BOTTOM].height + output->current_mode->height / 2,
+			   output->current_mode->width,
+			   output->current_mode->height / 2);
+
+		repaint_views(output, &total_damage, GL_RENDERER_SIDE_RIGHT);
+		break;
+	case ZWP_STEREOSCOPY_V1_LAYOUT_FRAME_PACKING:
+		/* Left eye */
+		glViewport(go->borders[GL_RENDERER_BORDER_LEFT].width,
+			   go->borders[GL_RENDERER_BORDER_BOTTOM].height,
+			   output->current_mode->width,
+			   output->current_mode->height);
+
+		repaint_views(output, &total_damage, GL_RENDERER_SIDE_LEFT);
+
+		/* Right eye, with 1/24th of the height unused in the middle. */
+		glViewport(go->borders[GL_RENDERER_BORDER_LEFT].width,
+			   go->borders[GL_RENDERER_BORDER_BOTTOM].height + output->current_mode->height * 25.0 / 24.0,
+			   output->current_mode->width,
+			   output->current_mode->height);
+
+		repaint_views(output, &total_damage, GL_RENDERER_SIDE_RIGHT);
+		break;
+	default:
+		assert(0);
+	}
 
 	pixman_region32_fini(&total_damage);
 	pixman_region32_fini(&buffer_damage);
diff --git a/libweston/gl-renderer.h b/libweston/gl-renderer.h
index b47ea07f..0469417f 100644
--- a/libweston/gl-renderer.h
+++ b/libweston/gl-renderer.h
@@ -56,6 +56,12 @@  enum gl_renderer_border_side {
 	GL_RENDERER_BORDER_BOTTOM = 3,
 };
 
+enum gl_renderer_stereoscopy_side {
+	GL_RENDERER_SIDE_DEFAULT = 0,
+	GL_RENDERER_SIDE_LEFT = 1,
+	GL_RENDERER_SIDE_RIGHT = 2,
+};
+
 struct gl_renderer_interface {
 	const EGLint *opaque_attribs;
 	const EGLint *alpha_attribs;