[PATCH weston 2/2] compositor: Added the ability to draw damage to a texture and in turn to the framebuffer. Also added a shader which inverts colors.

Zoxc zoxc32 at gmail.com
Fri Sep 7 15:42:32 PDT 2012


---
 src/compositor.c | 165 +++++++++++++++++++++++++++++++++++++++++++++++++------
 src/compositor.h |   8 +++
 src/shell.c      |  11 ++++
 3 files changed, 167 insertions(+), 17 deletions(-)

diff --git a/src/compositor.c b/src/compositor.c
index 7013b4a..e625171 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -1256,23 +1256,12 @@ triangle_fan_debug(struct weston_surface *surface, int first, int count)
 }
 
 static void
-repaint_region(struct weston_surface *es, pixman_region32_t *region,
-		pixman_region32_t *surf_region)
+repaint_region(struct weston_compositor *ec, struct weston_surface *es,
+		int nfans)
 {
-	struct weston_compositor *ec = es->compositor;
 	GLfloat *v;
 	unsigned int *vtxcnt;
-	int i, first, nfans;
-
-	/* The final region to be painted is the intersection of
-	 * 'region' and 'surf_region'. However, 'region' is in the global
-	 * coordinates, and 'surf_region' is in the surface-local
-	 * coordinates. texture_region() will iterate over all pairs of
-	 * rectangles from both regions, compute the intersection
-	 * polygon for each pair, and store it as a triangle fan if
-	 * it has a non-zero area (at least 3 vertices, actually).
-	 */
-	nfans = texture_region(es, region, surf_region);
+	int i, first;
 
 	v = ec->vertices.data;
 	vtxcnt = ec->vtxcnt.data;
@@ -1287,7 +1276,7 @@ repaint_region(struct weston_surface *es, pixman_region32_t *region,
 
 	for (i = 0, first = 0; i < nfans; i++) {
 		glDrawArrays(GL_TRIANGLE_FAN, first, vtxcnt[i]);
-		if (ec->fan_debug)
+		if (es && ec->fan_debug)
 			triangle_fan_debug(es, first, vtxcnt[i]);
 		first += vtxcnt[i];
 	}
@@ -1300,6 +1289,73 @@ repaint_region(struct weston_surface *es, pixman_region32_t *region,
 }
 
 static void
+repaint_surface(struct weston_surface *es, pixman_region32_t *region,
+		pixman_region32_t *surf_region)
+{
+	/* The final region to be painted is the intersection of
+	 * 'region' and 'surf_region'. However, 'region' is in the global
+	 * coordinates, and 'surf_region' is in the surface-local
+	 * coordinates. texture_region() will iterate over all pairs of
+	 * rectangles from both regions, compute the intersection
+	 * polygon for each pair, and store it as a triangle fan if
+	 * it has a non-zero area (at least 3 vertices, actually).
+	 */
+	int nfans = texture_region(es, region, surf_region);
+
+	repaint_region(es->compositor, es, nfans);
+}
+
+static void
+output_emit_vertex(struct weston_output *output, GLfloat **v, int32_t x, int32_t y)
+{
+	struct weston_vector vector;
+
+	/* position: */
+	*((*v)++) = x;
+	*((*v)++) = y;
+
+	/* texcoord: */
+
+	vector.f[0] = x;
+	vector.f[1] = y;
+	vector.f[2] = 0.0f;
+	vector.f[3] = 1.0f;
+
+	weston_matrix_transform(&output->matrix, &vector);
+
+	*((*v)++) = (vector.f[0] + 1.0f) * 0.5f;
+	*((*v)++) = (vector.f[1] + 1.0f) * 0.5f;
+}
+
+static void
+repaint_output(struct weston_output *output, pixman_region32_t *region)
+{
+	struct weston_compositor *ec = output->compositor;
+	GLfloat *v;
+	unsigned int *vtxcnt, nvtx = 0;
+	pixman_box32_t *rects;
+	int i, nrects;
+
+	rects = pixman_region32_rectangles(region, &nrects);
+
+	v = wl_array_add(&ec->vertices, nrects * 4 * 4 * sizeof *v);
+	vtxcnt = wl_array_add(&ec->vtxcnt, nrects * sizeof *vtxcnt);
+
+	for (i = 0; i < nrects; i++) {
+		pixman_box32_t *rect = &rects[i];
+
+		output_emit_vertex(output, &v, rect->x1, rect->y1);
+		output_emit_vertex(output, &v, rect->x2, rect->y1);
+		output_emit_vertex(output, &v, rect->x2, rect->y2);
+		output_emit_vertex(output, &v, rect->x1, rect->y2);
+
+		vtxcnt[nvtx++] = 4;
+	}
+
+	repaint_region(ec, NULL, nvtx);
+}
+
+static void
 weston_compositor_use_shader(struct weston_compositor *compositor,
 			     struct weston_shader *shader)
 {
@@ -1329,11 +1385,64 @@ weston_shader_uniforms(struct weston_shader *shader,
 WL_EXPORT void
 weston_output_repaint_start(struct weston_output *output, pixman_region32_t *damage)
 {
+	output->indirect_drawing = output->compositor->invert_color && !output->indirect_disable;
+
+	if(output->indirect_drawing) {
+		if(!output->indirect_fbo)
+			glGenFramebuffers(1, &output->indirect_fbo);
+
+		glBindFramebuffer(GL_FRAMEBUFFER, output->indirect_fbo);
+
+		if(!output->indirect_texture) {
+			glGenTextures(1, &output->indirect_texture);
+
+			glBindTexture(GL_TEXTURE_2D, output->indirect_texture);
+
+			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+			glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, output->current->width, output->current->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
+			glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, output->indirect_texture, 0);
+		}
+
+		GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+
+		if(status != GL_FRAMEBUFFER_COMPLETE) {
+			weston_log("unable to create framebuffer for indirect rendering %d\n", (int)status);
+			output->indirect_drawing = 0;
+			output->indirect_disable = 1;
+
+			return;
+		}
+	}
 }
 
 WL_EXPORT void
 weston_output_repaint_finish(struct weston_output *output, pixman_region32_t *damage)
 {
+	struct weston_compositor *ec = output->compositor;
+
+	if(output->indirect_drawing) {
+		glBindFramebuffer(GL_FRAMEBUFFER, 0);
+
+		struct weston_shader *shader = &ec->invert_color_shader;
+
+		weston_compositor_use_shader(ec, shader);
+
+		glUniformMatrix4fv(shader->proj_uniform,
+				   1, GL_FALSE, output->matrix.d);
+		glUniform1f(shader->alpha_uniform, 1.0);
+		glUniform1i(shader->tex_uniforms[0], 0);
+
+		glDisable(GL_BLEND);
+
+		glActiveTexture(GL_TEXTURE0);
+		glBindTexture(GL_TEXTURE_2D, output->indirect_texture);
+
+		repaint_output(output, damage);
+	}
 }
 
 WL_EXPORT void
@@ -1402,13 +1511,13 @@ weston_surface_draw(struct weston_surface *es, struct weston_output *output,
 		else
 			glDisable(GL_BLEND);
 
-		repaint_region(es, &repaint, &es->opaque);
+		repaint_surface(es, &repaint, &es->opaque);
 	}
 
 	if (pixman_region32_not_empty(&surface_blend)) {
 		weston_compositor_use_shader(ec, es->shader);
 		glEnable(GL_BLEND);
-		repaint_region(es, &repaint, &surface_blend);
+		repaint_surface(es, &repaint, &surface_blend);
 	}
 
 	pixman_region32_fini(&surface_blend);
@@ -3337,6 +3446,17 @@ static const char texture_fragment_shader_y_xuxv[] =
 	FRAGMENT_CONVERT_YUV
 	"}\n";
 
+static const char invert_color_fragment_shader[] =
+	"precision mediump float;\n"
+	"varying vec2 v_texcoord;\n"
+	"uniform sampler2D tex;\n"
+	"uniform float alpha;\n"
+	"void main()\n"
+	"{\n"
+	"   gl_FragColor = texture2D(tex, v_texcoord);\n;"
+	"   gl_FragColor.rgb = vec3(1.0) - gl_FragColor.rgb;\n;"
+	"}\n";
+
 static const char solid_fragment_shader[] =
 	"precision mediump float;\n"
 	"uniform vec4 color;\n"
@@ -3411,6 +3531,9 @@ weston_output_destroy(struct weston_output *output)
 	pixman_region32_fini(&output->previous_damage);
 	output->compositor->output_id_pool &= ~(1 << output->id);
 
+	glDeleteTextures(1, &output->indirect_texture);
+	glDeleteFramebuffers(1, &output->indirect_fbo);
+
 	wl_display_remove_global(c->wl_display, output->global);
 }
 
@@ -3539,6 +3662,11 @@ weston_output_move(struct weston_output *output, int x, int y)
 	pixman_region32_init_rect(&output->region, x, y,
 				  output->width,
 				  output->height);
+
+	if(output->indirect_texture) {
+		glDeleteTextures(1, &output->indirect_texture);
+		output->indirect_texture = 0;
+	}
 }
 
 WL_EXPORT void
@@ -3806,6 +3934,9 @@ weston_compositor_init_gl(struct weston_compositor *ec)
 	if (weston_shader_init(&ec->texture_shader_y_xuxv,
 			       vertex_shader, texture_fragment_shader_y_xuxv) < 0)
 		return -1;
+	if (weston_shader_init(&ec->invert_color_shader,
+			     vertex_shader, invert_color_fragment_shader) < 0)
+		return -1;
 	if (weston_shader_init(&ec->solid_shader,
 			     vertex_shader, solid_fragment_shader) < 0)
 		return -1;
diff --git a/src/compositor.h b/src/compositor.h
index 27505f4..5e1ca10 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -168,6 +168,11 @@ struct weston_output {
 	uint32_t frame_time;
 	int disable_planes;
 
+	int indirect_disable;
+	int indirect_drawing;
+	GLuint indirect_texture;
+	GLuint indirect_fbo;
+
 	char *make, *model;
 	uint32_t subpixel;
 	uint32_t transform;
@@ -280,6 +285,7 @@ struct weston_compositor {
 	struct weston_shader texture_shader_y_uv;
 	struct weston_shader texture_shader_y_u_v;
 	struct weston_shader texture_shader_y_xuxv;
+	struct weston_shader invert_color_shader;
 	struct weston_shader solid_shader;
 	struct weston_shader *current_shader;
 	struct wl_display *wl_display;
@@ -324,6 +330,8 @@ struct weston_compositor {
 	struct weston_plane primary_plane;
 	int fan_debug;
 
+	int invert_color;
+
 	uint32_t focus;
 
 	PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC
diff --git a/src/shell.c b/src/shell.c
index 06d8684..7ab91e1 100644
--- a/src/shell.c
+++ b/src/shell.c
@@ -3488,6 +3488,15 @@ debug_repaint_binding(struct wl_seat *seat, uint32_t time, uint32_t key,
 	}
 }
 
+static void
+invert_color_binding(struct wl_seat *seat, uint32_t time, uint32_t key,
+			  void *data)
+{
+	struct desktop_shell *shell = data;
+	struct weston_compositor *compositor = shell->compositor;
+	compositor->invert_color = !compositor->invert_color;
+	weston_compositor_damage_all(compositor);
+}
 
 static void
 fan_debug_repaint_binding(struct wl_seat *seat, uint32_t time, uint32_t key,
@@ -3664,6 +3673,8 @@ shell_add_bindings(struct weston_compositor *ec, struct desktop_shell *shell)
 				          backlight_binding, ec);
 	weston_compositor_add_key_binding(ec, KEY_SPACE, mod | MODIFIER_SHIFT,
 				          debug_repaint_binding, shell);
+	weston_compositor_add_key_binding(ec, KEY_I, mod | MODIFIER_ALT,
+				          invert_color_binding, shell);
 	weston_compositor_add_key_binding(ec, KEY_SPACE, mod | MODIFIER_ALT,
 				          fan_debug_repaint_binding, shell);
 	weston_compositor_add_key_binding(ec, KEY_K, mod,
-- 
1.7.12



More information about the wayland-devel mailing list