[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