compositor: Add opaque rect shader feature
authorKristian Høgsberg <krh@bitplanet.net>
Wed, 16 May 2012 03:16:53 +0000 (23:16 -0400)
committerKristian Høgsberg <krh@bitplanet.net>
Wed, 16 May 2012 20:00:41 +0000 (16:00 -0400)
This lets us mark a rectangle in a texture and force the alpha to one
inside.  This is useful for textures coming from X windows, where the X
window part is xRGB, that is 32 bit RGB with an undefined alpha channel
and the decorations are rendered with a well-defined alpha channel.

src/compositor.c
src/compositor.h
src/xserver-launcher.c

index 622db58..c26a31e 100644 (file)
@@ -228,6 +228,10 @@ weston_surface_create(struct weston_compositor *compositor)
        surface->alpha = 255;
        surface->brightness = 255;
        surface->saturation = 255;
+       surface->opaque_rect[0] = 0.0;
+       surface->opaque_rect[1] = 0.0;
+       surface->opaque_rect[2] = 0.0;
+       surface->opaque_rect[3] = 0.0;
        surface->pitch = 1;
 
        surface->buffer = NULL;
@@ -861,6 +865,7 @@ weston_surface_draw(struct weston_surface *es, struct weston_output *output,
        glUniform1f(es->shader->saturation_uniform, es->saturation / 255.0);
        glUniform1f(es->shader->texwidth_uniform,
                    (GLfloat)es->geometry.width / es->pitch);
+       glUniform4fv(es->shader->opaque_uniform, 1, es->opaque_rect);
 
        if (es->transform.enabled || output->zoom.active)
                filter = GL_LINEAR;
@@ -2325,6 +2330,7 @@ static const char texture_fragment_shader[] =
        "uniform float bright;\n"
        "uniform float saturation;\n"
        "uniform float texwidth;\n"
+       "uniform vec4 opaque;\n"
        "void main()\n"
        "{\n"
        "   if (v_texcoord.x < 0.0 || v_texcoord.x > texwidth ||\n"
@@ -2335,6 +2341,9 @@ static const char texture_fragment_shader[] =
        "   vec3 range = (gl_FragColor.rgb - vec3 (gray, gray, gray)) * saturation;\n"
        "   gl_FragColor = vec4(vec3(gray + range), gl_FragColor.a);\n"
        "   gl_FragColor = vec4(vec3(bright, bright, bright) * gl_FragColor.rgb, gl_FragColor.a);\n"
+       "   if (opaque.x <= v_texcoord.x && v_texcoord.x < opaque.y &&\n"
+       "       opaque.z <= v_texcoord.y && v_texcoord.y < opaque.w)\n"
+       "      gl_FragColor.a = 1.0;\n"
        "   gl_FragColor = alpha * gl_FragColor;\n"
        "}\n";
 
@@ -2401,6 +2410,8 @@ weston_shader_init(struct weston_shader *shader,
        shader->color_uniform = glGetUniformLocation(shader->program, "color");
        shader->texwidth_uniform = glGetUniformLocation(shader->program,
                                                        "texwidth");
+       shader->opaque_uniform =
+               glGetUniformLocation(shader->program, "opaque");
 
        return 0;
 }
index 2e66f22..e8edbb4 100644 (file)
@@ -166,6 +166,7 @@ struct weston_shader {
        GLint saturation_uniform;
        GLint color_uniform;
        GLint texwidth_uniform;
+       GLint opaque_uniform;
 };
 
 struct weston_animation {
@@ -326,6 +327,7 @@ struct weston_surface {
        struct wl_list layer_link;
        struct weston_shader *shader;
        GLfloat color[4];
+       GLfloat opaque_rect[4];
        uint32_t alpha;
        uint32_t brightness;
        uint32_t saturation;
index 551030f..070ffb4 100644 (file)
@@ -841,6 +841,22 @@ weston_wm_window_draw_decoration(void *data)
 
        cairo_destroy(cr);
        cairo_surface_destroy(surface);
+
+       if (window->surface) {
+               /* We leave an extra pixel around the X window area to
+                * make sure we don't sample from the undefined alpha
+                * channel when filtering. */
+               window->surface->opaque_rect[0] =
+                       (double) (t->margin + t->width - 1) / width;
+               window->surface->opaque_rect[1] =
+                       (double) (t->margin + t->width + 
+                                 window->width + 1) / width;
+               window->surface->opaque_rect[2] =
+                       (double) (t->margin + t->titlebar_height - 1) / height;
+               window->surface->opaque_rect[3] =
+                       (double) (t->margin + t->titlebar_height +
+                                 window->height + 1) / height;
+       }
 }
 
 static void
@@ -1767,6 +1783,8 @@ xserver_set_window_id(struct wl_client *client, struct wl_resource *resource,
        wl_signal_add(&surface->resource.destroy_signal,
                      &window->surface_destroy_listener);
 
+       weston_wm_window_schedule_repaint(window);
+
        if (shell_interface->create_shell_surface) {
                shell_interface->create_shell_surface(shell_interface->shell,
                                                      window->surface,