[PATCH 2/5] gl-renderer: Add support for per-output multi-texture borders.

Jason Ekstrand jason at jlekstrand.net
Sat Oct 19 18:42:44 CEST 2013


This new border API is sufficiently powerful border suffort for doing a
full window frame.

Signed-off-by: Jason Ekstrand <jason at jlekstrand.net>
---
 src/gl-renderer.c | 132 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
 src/gl-renderer.h |  39 ++++++++++++++++
 2 files changed, 168 insertions(+), 3 deletions(-)

diff --git a/src/gl-renderer.c b/src/gl-renderer.c
index f02445b..7ca5c22 100644
--- a/src/gl-renderer.c
+++ b/src/gl-renderer.c
@@ -50,9 +50,18 @@ struct gl_shader {
 
 #define BUFFER_DAMAGE_COUNT 2
 
+struct gl_border_image {
+	GLuint tex;
+	int32_t width, height;
+	int32_t tex_width;
+	int dirty;
+	void *data;
+};
+
 struct gl_output_state {
 	EGLSurface egl_surface;
 	pixman_region32_t buffer_damage[BUFFER_DAMAGE_COUNT];
+	struct gl_border_image borders[4];
 };
 
 enum buffer_type {
@@ -570,6 +579,104 @@ repaint_surfaces(struct weston_output *output, pixman_region32_t *damage)
 			draw_surface(surface, output, damage);
 }
 
+static void
+draw_output_border_texture(struct gl_border_image *img, int32_t x, int32_t y,
+			   int32_t width, int32_t height)
+{
+	static GLushort indices [] = { 0, 1, 3, 3, 1, 2 };
+
+	if (!img->data) {
+		if (img->tex) {
+			glDeleteTextures(1, &img->tex);
+			img->tex = 0;
+		}
+
+		return;
+	}
+
+	if (!img->tex) {
+		glGenTextures(1, &img->tex);
+		glBindTexture(GL_TEXTURE_2D, img->tex);
+
+		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);
+	} else {
+		glBindTexture(GL_TEXTURE_2D, img->tex);
+	}
+
+	if (img->dirty) {
+		glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, 0);
+		glTexImage2D(GL_TEXTURE_2D, 0, GL_BGRA_EXT,
+			     img->tex_width, img->height, 0,
+			     GL_BGRA_EXT, GL_UNSIGNED_BYTE, img->data);
+
+	}
+
+	glBindTexture(GL_TEXTURE_2D, img->tex);
+
+	GLfloat texcoord[] = {
+		0.0f, 0.0f,
+		(GLfloat)img->width / (GLfloat)img->tex_width, 0.0f,
+		(GLfloat)img->width / (GLfloat)img->tex_width, 1.0f,
+		0.0f, 1.0f,
+	};
+
+	GLfloat verts[] = {
+		x, y,
+		x + width, y,
+		x + width, y + height,
+		x, y + height
+	};
+
+	glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, verts);
+	glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, texcoord);
+	glEnableVertexAttribArray(0);
+	glEnableVertexAttribArray(1);
+
+	glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
+
+	glDisableVertexAttribArray(1);
+	glDisableVertexAttribArray(0);
+}
+
+static void
+draw_output_border(struct weston_output *output)
+{
+	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;
+	int32_t full_width;
+
+	glDisable(GL_BLEND);
+	use_shader(gr, shader);
+
+	glUniformMatrix4fv(shader->proj_uniform,
+			   1, GL_FALSE, output->matrix.d);
+
+	glUniform1i(shader->tex_uniforms[0], 0);
+	glUniform1f(shader->alpha_uniform, 1);
+	glActiveTexture(GL_TEXTURE0);
+
+	full_width = output->width + output->border.left + output->border.right;
+	draw_output_border_texture(&go->borders[0],
+				   -output->border.left, -output->border.top,
+				   full_width, output->border.top);
+	draw_output_border_texture(&go->borders[1],
+				   -output->border.left, 0,
+				   output->border.left, output->height);
+	draw_output_border_texture(&go->borders[2],
+				   output->width, 0,
+				   output->border.right, output->height);
+	draw_output_border_texture(&go->borders[3],
+				   -output->border.left, output->height,
+				   full_width, output->border.bottom);
+}
 
 static int
 texture_border(struct weston_output *output)
@@ -648,7 +755,7 @@ texture_border(struct weston_output *output)
 }
 
 static void
-draw_border(struct weston_output *output)
+draw_global_border(struct weston_output *output)
 {
 	struct weston_compositor *ec = output->compositor;
 	struct gl_renderer *gr = get_renderer(ec);
@@ -780,8 +887,11 @@ gl_renderer_repaint_output(struct weston_output *output,
 	pixman_region32_fini(&total_damage);
 	pixman_region32_fini(&buffer_damage);
 
-	if (gr->border.texture)
-		draw_border(output);
+	if (gr->border.texture) {
+		draw_global_border(output);
+	} else {
+		draw_output_border(output);
+	}
 
 	pixman_region32_copy(&output->previous_damage, output_damage);
 	wl_signal_emit(&output->frame_signal, output);
@@ -1432,6 +1542,21 @@ log_egl_config_info(EGLDisplay egldpy, EGLConfig eglconfig)
 }
 
 static void
+gl_renderer_output_set_border(struct weston_output *output,
+			      enum gl_renderer_border_side side,
+			      int32_t width, int32_t height,
+			      int32_t tex_width, unsigned char *data)
+{
+	struct gl_output_state *go = get_output_state(output);
+
+	go->borders[side].width = width;
+	go->borders[side].height = height;
+	go->borders[side].tex_width = tex_width;
+	go->borders[side].data = data;
+	go->borders[side].dirty = 1;
+}
+
+static void
 output_apply_border(struct weston_output *output, struct gl_renderer *gr)
 {
 	output->border.top = gr->border.top;
@@ -1873,6 +1998,7 @@ WL_EXPORT struct gl_renderer_interface gl_renderer_interface = {
 	.output_create = gl_renderer_output_create,
 	.output_destroy = gl_renderer_output_destroy,
 	.output_surface = gl_renderer_output_surface,
+	.output_set_border = gl_renderer_output_set_border,
 	.set_border = gl_renderer_set_border,
 	.print_egl_error_state = gl_renderer_print_egl_error_state
 };
diff --git a/src/gl-renderer.h b/src/gl-renderer.h
index 0342134..8a36c89 100644
--- a/src/gl-renderer.h
+++ b/src/gl-renderer.h
@@ -39,6 +39,13 @@ typedef intptr_t EGLNativeWindowType;
 
 #endif
 
+enum gl_renderer_border_side {
+	GL_RENDERER_BORDER_TOP = 0,
+	GL_RENDERER_BORDER_LEFT = 1,
+	GL_RENDERER_BORDER_RIGHT = 2,
+	GL_RENDERER_BORDER_BOTTOM = 3,
+};
+
 struct gl_renderer_interface {
 	const EGLint *opaque_attribs;
 	const EGLint *alpha_attribs;
@@ -57,6 +64,38 @@ struct gl_renderer_interface {
 
 	EGLSurface (*output_surface)(struct weston_output *output);
 
+	/* Sets the output border.
+	 *
+	 * The side specifies the side for which we are setting the border.
+	 * The width and height are the width and height of the border.
+	 * The tex_width patemeter specifies the width of the actual
+	 * texture; this may be larger than width if the data is not
+	 * tightly packed.
+	 *
+	 * The top and bottom textures will extend over the sides to the
+	 * full width of the bordered window while.  The right and left
+	 * edges, however, will extend only to the top and bottom of the
+	 * compositor surface.  This is demonstrated by the picture below:
+	 *
+	 * +-----------------------+
+	 * |          TOP          |
+	 * +-+-------------------+-+
+	 * | |                   | |
+	 * |L|                   |R|
+	 * |E|                   |I|
+	 * |F|                   |G|
+	 * |T|                   |H|
+	 * | |                   |T|
+	 * | |                   | |
+	 * +-+-------------------+-+
+	 * |        BOTTOM         |
+	 * +-----------------------+
+	 */
+	void (*output_set_border)(struct weston_output *output,
+				  enum gl_renderer_border_side side,
+				  int32_t width, int32_t height,
+				  int32_t tex_width, unsigned char *data);
+
 	void (*set_border)(struct weston_compositor *ec,
 			   int32_t width, int32_t height,
 			   void *data, int32_t *edges);
-- 
1.8.3.1



More information about the wayland-devel mailing list