[RFC PATCH 5/6] gl-renderer: Correct colors during rendering

Niels Ole Salscheider niels_ole at salscheider-online.de
Sun Mar 30 04:36:36 PDT 2014


This patch ignores the borders for now.

Signed-off-by: Niels Ole Salscheider <niels_ole at salscheider-online.de>
---
 src/gl-renderer.c | 309 ++++++++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 286 insertions(+), 23 deletions(-)

diff --git a/src/gl-renderer.c b/src/gl-renderer.c
index b2dfbac..fe3aa4d 100644
--- a/src/gl-renderer.c
+++ b/src/gl-renderer.c
@@ -38,6 +38,8 @@
 #include <EGL/eglext.h>
 #include "weston-egl-ext.h"
 
+#include "colorcorrection-server-protocol.h"
+
 struct gl_shader {
 	GLuint program;
 	GLuint vertex_shader, fragment_shader;
@@ -74,6 +76,11 @@ struct gl_output_state {
 	enum gl_border_status border_damage[BUFFER_DAMAGE_COUNT];
 	struct gl_border_image borders[4];
 	enum gl_border_status border_status;
+
+	GLuint fb;
+	GLuint fb_texture;
+	GLuint fb_mask_texture;
+	GLuint lut;
 };
 
 enum buffer_type {
@@ -82,6 +89,11 @@ enum buffer_type {
 	BUFFER_TYPE_EGL
 };
 
+enum draw_type {
+	DRAW_TYPE_NORMAL,
+	DRAW_TYPE_MASK
+};
+
 struct gl_surface_state {
 	GLfloat color[4];
 	struct gl_shader *shader;
@@ -91,6 +103,8 @@ struct gl_surface_state {
 	int needs_full_upload;
 	pixman_region32_t texture_damage;
 
+	GLuint lut;
+
 	EGLImageKHR images[3];
 	GLenum target;
 	int num_images;
@@ -526,7 +540,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 draw_type type)
 {
 	struct weston_compositor *ec = ev->surface->compositor;
 	struct gl_renderer *gr = get_renderer(ec);
@@ -559,9 +574,6 @@ draw_view(struct weston_view *ev, struct weston_output *output,
 		shader_uniforms(&gr->solid_shader, ev, output);
 	}
 
-	use_shader(gr, gs->shader);
-	shader_uniforms(gs->shader, ev, output);
-
 	if (ev->transform.enabled || output->zoom.active ||
 	    output->current_scale != ev->surface->buffer_viewport.scale)
 		filter = GL_LINEAR;
@@ -575,6 +587,16 @@ draw_view(struct weston_view *ev, struct weston_output *output,
 		glTexParameteri(gs->target, GL_TEXTURE_MAG_FILTER, filter);
 	}
 
+	/* Set LUT */
+	if (gr->has_texture_3d && ev->surface->clut.data) {
+		glActiveTexture(GL_TEXTURE0 + i);
+		glBindTexture(GL_TEXTURE_3D_OES, gs->lut);
+		glTexParameteri(GL_TEXTURE_3D_OES, GL_TEXTURE_MIN_FILTER,
+				GL_LINEAR);
+		glTexParameteri(GL_TEXTURE_3D_OES, GL_TEXTURE_MAG_FILTER,
+				GL_LINEAR);
+	}
+
 	/* blended region is whole surface minus opaque region: */
 	pixman_region32_init_rect(&surface_blend, 0, 0,
 				  ev->surface->width, ev->surface->height);
@@ -582,14 +604,34 @@ draw_view(struct weston_view *ev, struct weston_output *output,
 
 	/* XXX: Should we be using ev->transform.opaque here? */
 	if (pixman_region32_not_empty(&ev->surface->opaque)) {
-		if (gs->shader == &gr->texture_shader_rgba) {
+		if (gs->shader == &gr->texture_shader_rgba ||
+		    gs->shader == &gr->texture_shader_rgba_lut) {
 			/* Special case for RGBA textures with possibly
 			 * bad data in alpha channel: use the shader
 			 * that forces texture alpha = 1.0.
 			 * Xwayland surfaces need this.
 			 */
-			use_shader(gr, &gr->texture_shader_rgbx);
-			shader_uniforms(&gr->texture_shader_rgbx, ev, output);
+			if (type == DRAW_TYPE_NORMAL) {
+				if (gs->shader == &gr->texture_shader_rgba) {
+					use_shader(gr, &gr->texture_shader_rgbx);
+					shader_uniforms(&gr->texture_shader_rgbx,
+							ev, output);
+				} else {
+					use_shader(gr, &gr->texture_shader_rgbx_lut);
+					shader_uniforms(&gr->texture_shader_rgbx_lut,
+							ev, output);
+				}
+			} else {
+				float r = ev->surface->color_profile_mode ==
+					  WL_COLORCORRECTION_MODE_UNCORRECTED ?
+					  1.0f : 0.0f;
+				use_shader(gr, &gr->solid_shader);
+				glUniformMatrix4fv(gr->solid_shader.proj_uniform,
+						   1, GL_FALSE, output->matrix.d);
+				glUniform4f(gr->solid_shader.color_uniform,
+					    r, 0.0f, 0.0f, 1.0f);
+				glUniform1f(gr->solid_shader.alpha_uniform, 1.0f);
+			}
 		}
 
 		if (ev->alpha < 1.0)
@@ -601,7 +643,20 @@ draw_view(struct weston_view *ev, struct weston_output *output,
 	}
 
 	if (pixman_region32_not_empty(&surface_blend)) {
-		use_shader(gr, gs->shader);
+		if (type == DRAW_TYPE_NORMAL) {
+			use_shader(gr, gs->shader);
+			shader_uniforms(gs->shader, ev, output);
+		} else {
+			float r = ev->surface->color_profile_mode ==
+				  WL_COLORCORRECTION_MODE_UNCORRECTED ?
+				  1.0f : 0.0f;
+			use_shader(gr, &gr->solid_shader);
+			glUniformMatrix4fv(gr->solid_shader.proj_uniform,
+					   1, GL_FALSE, output->matrix.d);
+			glUniform4f(gr->solid_shader.color_uniform,
+				    r, 0.0f, 0.0f, 1.0f);
+			glUniform1f(gr->solid_shader.alpha_uniform, 1.0f);
+		}
 		glEnable(GL_BLEND);
 		repaint_region(ev, &repaint, &surface_blend);
 	}
@@ -613,14 +668,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 draw_type type)
 {
 	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, type);
 }
 
 static void
@@ -706,11 +762,11 @@ output_has_borders(struct weston_output *output)
 
 static void
 draw_output_borders(struct weston_output *output,
-		    enum gl_border_status border_status)
+		    enum gl_border_status border_status, enum draw_type type)
 {
 	struct gl_output_state *go = get_output_state(output);
 	struct gl_renderer *gr = get_renderer(output->compositor);
-	struct gl_shader *shader = &gr->texture_shader_rgba;
+	struct gl_shader *shader;
 	struct gl_border_image *top, *bottom, *left, *right;
 	struct weston_matrix matrix;
 	int full_width, full_height;
@@ -718,6 +774,11 @@ draw_output_borders(struct weston_output *output,
 	if (border_status == BORDER_STATUS_CLEAN)
 		return; /* Clean. Nothing to do. */
 
+	if (type == DRAW_TYPE_NORMAL) {
+		shader = &gr->texture_shader_rgba;
+	} else
+		shader = &gr->solid_shader;
+
 	top = &go->borders[GL_RENDERER_BORDER_TOP];
 	bottom = &go->borders[GL_RENDERER_BORDER_BOTTOM];
 	left = &go->borders[GL_RENDERER_BORDER_LEFT];
@@ -738,6 +799,8 @@ draw_output_borders(struct weston_output *output,
 
 	glUniform1i(shader->tex_uniforms[0], 0);
 	glUniform1f(shader->alpha_uniform, 1);
+	if (type == DRAW_TYPE_MASK)
+		glUniform4f(shader->color_uniform, 1.0f, 0.0f, 0.0f, 1.0f);
 	glActiveTexture(GL_TEXTURE0);
 
 	if (border_status & BORDER_TOP_DIRTY)
@@ -858,6 +921,103 @@ output_rotate_damage(struct weston_output *output,
 }
 
 static void
+use_fb(struct weston_output *output, GLuint *texture)
+{
+	struct gl_output_state *go = get_output_state(output);
+
+	if (!go->fb)
+		glGenFramebuffers(1, &go->fb);
+	glBindFramebuffer(GL_FRAMEBUFFER, go->fb);
+
+	if (!*texture)
+		glGenTextures(1, texture);
+	glBindTexture(GL_TEXTURE_2D, *texture);
+	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, output->width,
+		     output->height, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
+			GL_NEAREST);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
+			GL_NEAREST);
+
+	glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+			       GL_TEXTURE_2D, *texture, 0);
+}
+
+static int
+draw_fb(struct weston_output *output)
+{
+	struct gl_output_state *go = get_output_state(output);
+	struct weston_compositor *compositor = output->compositor;
+	struct gl_renderer *gr = get_renderer(compositor);
+
+	static GLushort indices [] = { 0, 1, 3, 2 };
+
+	GLfloat texcoord[] = {
+		0.0f, 0.0f,
+		1.0f, 0.0f,
+		1.0f, 1.0f,
+		0.0f, 1.0f,
+	};
+
+	GLfloat verts[] = {
+		output->x,                 output->y,
+		output->x + output->width, output->y,
+		output->x + output->width, output->y + output->height,
+		output->x,                 output->y + output->height
+	};
+
+	struct weston_matrix matrix;
+
+	glBindFramebuffer(GL_FRAMEBUFFER, 0);
+
+	use_shader(gr, &gr->fb_shader);
+
+	glViewport(0, 0, output->width, output->height);
+
+	weston_matrix_init(&matrix);
+	weston_matrix_translate(&matrix,
+				-(output->x + output->width / 2.0),
+				-(output->y + output->height / 2.0), 0);
+	weston_matrix_scale(&matrix,
+			    2.0 / output->width,
+			    2.0 / output->height, 1);
+	glUniformMatrix4fv(gr->fb_shader.proj_uniform, 1, GL_FALSE, matrix.d);
+
+	glUniform1i(gr->fb_shader.tex_uniforms[0], 0);
+	glUniform1i(gr->fb_shader.tex_uniforms[1], 1);
+	glUniform1i(gr->fb_shader.lut_uniform, 2);
+
+	glActiveTexture(GL_TEXTURE0);
+	glBindTexture(GL_TEXTURE_2D, go->fb_texture);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+	glActiveTexture(GL_TEXTURE1);
+	glBindTexture(GL_TEXTURE_2D, go->fb_mask_texture);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+	glActiveTexture(GL_TEXTURE2);
+	glBindTexture(GL_TEXTURE_3D_OES, go->lut);
+	glTexParameteri(GL_TEXTURE_3D_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+	glTexParameteri(GL_TEXTURE_3D_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+	glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, verts);
+	glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, texcoord);
+	glEnableVertexAttribArray(0);
+	glEnableVertexAttribArray(1);
+
+	glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT, indices);
+
+	glDisableVertexAttribArray(1);
+	glDisableVertexAttribArray(0);
+
+	return 0;
+}
+
+static void
+gl_renderer_attach_output_lut(struct weston_output *output);
+static void
 gl_renderer_repaint_output(struct weston_output *output,
 			      pixman_region32_t *output_damage)
 {
@@ -883,6 +1043,9 @@ gl_renderer_repaint_output(struct weston_output *output,
 	if (use_output(output) < 0)
 		return;
 
+	if (gr->has_texture_3d && output->clut.data)
+		use_fb(output, &go->fb_texture);
+
 	/* if debugging, redraw everything outside the damage to clean up
 	 * debug lines from the previous draw on this buffer:
 	 */
@@ -892,7 +1055,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, DRAW_TYPE_NORMAL);
 		gr->fan_debug = 1;
 		pixman_region32_fini(&undamaged);
 	}
@@ -906,14 +1069,24 @@ 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);
+	repaint_views(output, &total_damage, DRAW_TYPE_NORMAL);
+	draw_output_borders(output, border_damage, DRAW_TYPE_NORMAL);
 
-	pixman_region32_fini(&total_damage);
-	pixman_region32_fini(&buffer_damage);
+	if (gr->has_texture_3d && output->clut.data) {
+		use_fb(output, &go->fb_mask_texture);
+		glClear(GL_COLOR_BUFFER_BIT);
+		repaint_views(output, &total_damage, DRAW_TYPE_MASK);
+		draw_output_borders(output, border_damage, DRAW_TYPE_MASK);
 
-	draw_output_borders(output, border_damage);
+		gl_renderer_attach_output_lut(output);
+		if (draw_fb(output) < 0)
+			return;
+	}
 
+	pixman_region32_fini(&total_damage);
+	pixman_region32_fini(&buffer_damage);
 	pixman_region32_copy(&output->previous_damage, output_damage);
+
 	wl_signal_emit(&output->frame_signal, output);
 
 #ifdef EGL_EXT_swap_buffers_with_damage
@@ -1141,20 +1314,32 @@ gl_renderer_attach_shm(struct weston_surface *es, struct weston_buffer *buffer,
 
 	switch (wl_shm_buffer_get_format(shm_buffer)) {
 	case WL_SHM_FORMAT_XRGB8888:
-		gs->shader = &gr->texture_shader_rgbx;
+		if (gr->has_texture_3d && es->clut.data)
+			gs->shader = &gr->texture_shader_rgbx_lut;
+		else
+			gs->shader = &gr->texture_shader_rgbx;
 		pitch = wl_shm_buffer_get_stride(shm_buffer) / 4;
 		break;
 	case WL_SHM_FORMAT_ARGB8888:
-		gs->shader = &gr->texture_shader_rgba;
+		if (gr->has_texture_3d &&  es->clut.data)
+			gs->shader = &gr->texture_shader_rgba_lut;
+		else
+			gs->shader = &gr->texture_shader_rgba;
 		pitch = wl_shm_buffer_get_stride(shm_buffer) / 4;
 		break;
 	case WL_SHM_FORMAT_RGB565:
-		gs->shader = &gr->texture_shader_rgbx;
+		if (gr->has_texture_3d &&  es->clut.data)
+			gs->shader = &gr->texture_shader_rgbx_lut;
+		else
+			gs->shader = &gr->texture_shader_rgbx;
 		pitch = wl_shm_buffer_get_stride(shm_buffer) / 2;
 		break;
 	default:
 		weston_log("warning: unknown shm buffer format\n");
-		gs->shader = &gr->texture_shader_rgba;
+		if (gr->has_texture_3d &&  es->clut.data)
+			gs->shader = &gr->texture_shader_rgba_lut;
+		else
+			gs->shader = &gr->texture_shader_rgba;
 		pitch = wl_shm_buffer_get_stride(shm_buffer) / 4;
 	}
 
@@ -1208,12 +1393,18 @@ gl_renderer_attach_egl(struct weston_surface *es, struct weston_buffer *buffer,
 	case EGL_TEXTURE_RGBA:
 	default:
 		num_planes = 1;
-		gs->shader = &gr->texture_shader_rgba;
+		if (gr->has_texture_3d && es->clut.data)
+			gs->shader = &gr->texture_shader_rgba_lut;
+		else
+			gs->shader = &gr->texture_shader_rgba;
 		break;
 	case EGL_TEXTURE_EXTERNAL_WL:
 		num_planes = 1;
 		gs->target = GL_TEXTURE_EXTERNAL_OES;
-		gs->shader = &gr->texture_shader_egl_external;
+		if (gr->has_texture_3d && es->clut.data)
+			gs->shader = &gr->texture_shader_egl_external_lut;
+		else
+			gs->shader = &gr->texture_shader_egl_external;
 		break;
 	case EGL_TEXTURE_Y_UV_WL:
 		num_planes = 2;
@@ -1258,6 +1449,64 @@ gl_renderer_attach_egl(struct weston_surface *es, struct weston_buffer *buffer,
 }
 
 static void
+gl_renderer_attach_lut(struct weston_surface *es)
+{
+	struct weston_compositor *ec = es->compositor;
+	struct gl_renderer *gr = get_renderer(ec);
+	struct gl_surface_state *gs = get_surface_state(es);
+
+	if (!gs->lut) {
+		glGenTextures(1, &gs->lut);
+		glBindTexture(GL_TEXTURE_3D_OES, gs->lut);
+		glTexParameteri(GL_TEXTURE_3D_OES,
+				GL_TEXTURE_WRAP_R_OES, GL_CLAMP_TO_EDGE);
+		glTexParameteri(GL_TEXTURE_3D_OES,
+				GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+		glTexParameteri(GL_TEXTURE_3D_OES,
+				GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+	} else
+		glBindTexture(GL_TEXTURE_3D_OES, gs->lut);
+
+#ifdef GL_EXT_unpack_subimage
+		glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, 0);
+		glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, 0);
+		glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, 0);
+#endif
+	gr->teximage3d(GL_TEXTURE_3D_OES, 0, GL_RGB,
+		       es->clut.points, es->clut.points,  es->clut.points,
+		       0, GL_RGB, GL_UNSIGNED_BYTE,  es->clut.data);
+}
+
+static void
+gl_renderer_attach_output_lut(struct weston_output *output)
+{
+	struct gl_renderer *gr = get_renderer(output->compositor);
+	struct gl_output_state *go = get_output_state(output);
+
+	if (!go->lut) {
+		glGenTextures(1, &go->lut);
+		glBindTexture(GL_TEXTURE_3D_OES, go->lut);
+		glTexParameteri(GL_TEXTURE_3D_OES,
+				GL_TEXTURE_WRAP_R_OES, GL_CLAMP_TO_EDGE);
+		glTexParameteri(GL_TEXTURE_3D_OES,
+				GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+		glTexParameteri(GL_TEXTURE_3D_OES,
+				GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+	} else
+		glBindTexture(GL_TEXTURE_3D_OES, go->lut);
+
+#ifdef GL_EXT_unpack_subimage
+		glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, 0);
+		glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, 0);
+		glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, 0);
+#endif
+	gr->teximage3d(GL_TEXTURE_3D_OES, 0, GL_RGB,
+		       output->clut.points, output->clut.points,
+		       output->clut.points, 0, GL_RGB, GL_UNSIGNED_BYTE,
+		       output->clut.data);
+}
+
+static void
 gl_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
 {
 	struct weston_compositor *ec = es->compositor;
@@ -1277,6 +1526,8 @@ gl_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
 		gs->num_images = 0;
 		glDeleteTextures(gs->num_textures, gs->textures);
 		gs->num_textures = 0;
+		if (gs->lut)
+			glDeleteTextures(1, &gs->lut);
 		gs->buffer_type = BUFFER_TYPE_NULL;
 		gs->y_inverted = 1;
 		return;
@@ -1295,6 +1546,9 @@ gl_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
 		gs->buffer_type = BUFFER_TYPE_NULL;
 		gs->y_inverted = 1;
 	}
+
+	if (gr->has_texture_3d && es->clut.data)
+		gl_renderer_attach_lut(es);
 }
 
 static void
@@ -1323,6 +1577,8 @@ surface_state_destroy(struct gl_surface_state *gs, struct gl_renderer *gr)
 	gs->surface->renderer_state = NULL;
 
 	glDeleteTextures(gs->num_textures, gs->textures);
+	if (gs->lut)
+		glDeleteTextures(1, &gs->lut);
 
 	for (i = 0; i < gs->num_images; i++)
 		gr->destroy_image(gr->egl_display, gs->images[i]);
@@ -1877,6 +2133,13 @@ gl_renderer_output_destroy(struct weston_output *output)
 	for (i = 0; i < 2; i++)
 		pixman_region32_fini(&go->buffer_damage[i]);
 
+	if (go->fb_texture)
+		glDeleteTextures(1, &go->fb_texture);
+	if (go->fb_mask_texture)
+		glDeleteTextures(1, &go->fb_mask_texture);
+	if (go->fb)
+		glDeleteFramebuffers(1, &go->fb);
+
 	eglDestroySurface(gr->egl_display, go->egl_surface);
 
 	free(go);
-- 
1.9.1



More information about the wayland-devel mailing list