libweston: Implement alpha-compositing-v1 for gl renderer
diff --git a/Makefile.am b/Makefile.am
index e4da7b9..f298fd2 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -169,7 +169,9 @@
protocol/input-timestamps-unstable-v1-protocol.c \
protocol/input-timestamps-unstable-v1-server-protocol.h \
protocol/weston-touch-calibration-protocol.c \
- protocol/weston-touch-calibration-server-protocol.h
+ protocol/weston-touch-calibration-server-protocol.h \
+ protocol/alpha-compositing-unstable-v1-protocol.c \
+ protocol/alpha-compositing-unstable-v1-server-protocol.h
BUILT_SOURCES += $(nodist_libweston_@LIBWESTON_MAJOR@_la_SOURCES)
@@ -635,6 +637,8 @@
nodist_weston_simple_egl_SOURCES = \
protocol/xdg-shell-unstable-v6-protocol.c \
protocol/xdg-shell-unstable-v6-client-protocol.h \
+ protocol/alpha-compositing-unstable-v1-protocol.c \
+ protocol/alpha-compositing-unstable-v1-client-protocol.h \
protocol/ivi-application-protocol.c \
protocol/ivi-application-client-protocol.h
weston_simple_egl_CFLAGS = $(AM_CFLAGS) $(SIMPLE_EGL_CLIENT_CFLAGS)
@@ -934,7 +938,9 @@
protocol/tablet-unstable-v2-protocol.c \
protocol/tablet-unstable-v2-client-protocol.h \
protocol/input-timestamps-unstable-v1-protocol.c \
- protocol/input-timestamps-unstable-v1-client-protocol.h
+ protocol/input-timestamps-unstable-v1-client-protocol.h \
+ protocol/alpha-compositing-unstable-v1-protocol.c \
+ protocol/alpha-compositing-unstable-v1-client-protocol.h
westondatadir = $(datadir)/weston
dist_westondata_DATA = \
diff --git a/libweston/compositor.c b/libweston/compositor.c
index 8dc19f8..1c4c386 100644
--- a/libweston/compositor.c
+++ b/libweston/compositor.c
@@ -55,6 +55,7 @@
#include "timeline.h"
#include "compositor.h"
+#include "alpha-compositing-unstable-v1-server-protocol.h"
#include "viewporter-server-protocol.h"
#include "presentation-time-server-protocol.h"
#include "shared/helpers.h"
@@ -305,6 +306,8 @@
pixman_region32_init(&view->clip);
view->alpha = 1.0;
+ view->blending_alpha = 1.0;
+ view->blending_equation = ZWP_BLENDING_V1_BLENDING_EQUATION_NONE;
pixman_region32_init(&view->transform.opaque);
wl_list_init(&view->geometry.transformation_list);
@@ -445,6 +448,9 @@
state->buffer_viewport.buffer.src_width = wl_fixed_from_int(-1);
state->buffer_viewport.surface.width = -1;
state->buffer_viewport.changed = 0;
+
+ state->blending_equation = ZWP_BLENDING_V1_BLENDING_EQUATION_NONE;
+ state->blending_alpha = 1.0;
}
static void
@@ -1994,6 +2000,9 @@
if (surface->viewport_resource)
wl_resource_set_user_data(surface->viewport_resource, NULL);
+ if (surface->blending_resource)
+ wl_resource_set_user_data(surface->blending_resource, NULL);
+
weston_surface_destroy(surface);
}
@@ -3229,6 +3238,12 @@
wl_list_init(&state->feedback_list);
wl_signal_emit(&surface->commit_signal, surface);
+
+ /* zwp_alpha_compositing.blending */
+ wl_list_for_each(view, &surface->views, surface_link) {
+ view->blending_alpha = state->blending_alpha;
+ view->blending_equation = state->blending_equation;
+ }
}
static void
@@ -6247,6 +6262,129 @@
}
static void
+destroy_blending(struct wl_resource *resource)
+{
+ struct weston_surface *surface =
+ wl_resource_get_user_data(resource);
+
+ if (!surface)
+ return;
+
+ pixman_region32_union_rect(&surface->pending.damage_surface,
+ &surface->pending.damage_surface,
+ 0, 0, surface->width, surface->height);
+ surface->blending_resource = NULL;
+ surface->pending.blending_equation = ZWP_BLENDING_V1_BLENDING_EQUATION_NONE;
+ surface->pending.blending_alpha = 1.0;
+}
+
+static void
+blending_destroy(struct wl_client *client,
+ struct wl_resource *resource)
+{
+ wl_resource_destroy(resource);
+}
+
+static void
+blending_set_blending(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t equation)
+{
+ struct weston_surface *surface =
+ wl_resource_get_user_data(resource);
+
+ if (!surface)
+ return;
+
+ pixman_region32_union_rect(&surface->pending.damage_surface,
+ &surface->pending.damage_surface,
+ 0, 0, surface->width, surface->height);
+ surface->pending.blending_equation = equation;
+}
+
+static void
+blending_set_alpha(struct wl_client *client,
+ struct wl_resource *resource,
+ wl_fixed_t alpha)
+{
+ struct weston_surface *surface =
+ wl_resource_get_user_data(resource);
+
+ if (!surface)
+ return;
+
+ pixman_region32_union_rect(&surface->pending.damage_surface,
+ &surface->pending.damage_surface,
+ 0, 0, surface->width, surface->height);
+ surface->pending.blending_alpha = wl_fixed_to_double(alpha);
+}
+
+static const struct zwp_blending_v1_interface blending_interface = {
+ blending_destroy,
+ blending_set_blending,
+ blending_set_alpha
+};
+
+static void
+alpha_compositing_destroy(struct wl_client *client,
+ struct wl_resource *resource)
+{
+ wl_resource_destroy(resource);
+}
+
+static void
+alpha_compositing_get_blending(struct wl_client *client,
+ struct wl_resource *alpha_compositing,
+ uint32_t id,
+ struct wl_resource *surface_resource)
+{
+ struct weston_surface *surface =
+ wl_resource_get_user_data(surface_resource);
+ struct wl_resource *resource;
+
+ if (surface->blending_resource) {
+ wl_resource_post_error(alpha_compositing,
+ ZWP_ALPHA_COMPOSITING_V1_ERROR_BLENDING_EXISTS,
+ "a blending for that surface already exists");
+ return;
+ }
+
+ resource = wl_resource_create(client, &zwp_blending_v1_interface,
+ 1, id);
+ if (resource == NULL) {
+ wl_client_post_no_memory(client);
+ return;
+ }
+
+ wl_resource_set_implementation(resource, &blending_interface,
+ surface, destroy_blending);
+
+ surface->blending_resource = resource;
+}
+
+static const struct zwp_alpha_compositing_v1_interface alpha_compositing_interface = {
+ alpha_compositing_destroy,
+ alpha_compositing_get_blending,
+};
+
+static void
+bind_alpha_compositing(struct wl_client *client,
+ void *data, uint32_t version, uint32_t id)
+{
+ struct wl_resource *resource;
+
+ resource = wl_resource_create(client, &zwp_alpha_compositing_v1_interface,
+ version, id);
+ if (resource == NULL) {
+ wl_client_post_no_memory(client);
+ return;
+ }
+
+ wl_resource_set_implementation(resource, &alpha_compositing_interface,
+ NULL, NULL);
+}
+
+static void
compositor_bind(struct wl_client *client,
void *data, uint32_t version, uint32_t id)
{
@@ -6361,6 +6499,10 @@
ec, bind_presentation))
goto fail;
+ if (!wl_global_create(ec->wl_display, &zwp_alpha_compositing_v1_interface, 1,
+ ec, bind_alpha_compositing))
+ goto fail;
+
if (weston_input_init(ec) != 0)
goto fail;
diff --git a/libweston/compositor.h b/libweston/compositor.h
index abc9200..51c569f 100644
--- a/libweston/compositor.h
+++ b/libweston/compositor.h
@@ -1261,6 +1261,8 @@
pixman_region32_t clip; /* See weston_view_damage_below() */
float alpha; /* part of geometry, see below */
+ float blending_alpha;
+ int blending_equation;
void *renderer_state;
@@ -1360,6 +1362,9 @@
/* wp_viewport.set_source */
/* wp_viewport.set_destination */
struct weston_buffer_viewport buffer_viewport;
+
+ float blending_alpha;
+ int blending_equation;
};
struct weston_surface_activation_data {
@@ -1442,6 +1447,8 @@
/* wp_viewport resource for this surface */
struct wl_resource *viewport_resource;
+ struct wl_resource *blending_resource;
+
/* All the pending state, that wl_surface.commit will apply. */
struct weston_surface_state pending;
diff --git a/libweston/gl-renderer.c b/libweston/gl-renderer.c
index 2c50d2d..9bcab7f 100644
--- a/libweston/gl-renderer.c
+++ b/libweston/gl-renderer.c
@@ -54,6 +54,7 @@
#include "vertex-clipping.h"
#include "linux-dmabuf.h"
#include "linux-dmabuf-unstable-v1-server-protocol.h"
+#include "alpha-compositing-unstable-v1-server-protocol.h"
#include "shared/helpers.h"
#include "shared/platform.h"
@@ -879,11 +880,17 @@
int i;
struct gl_surface_state *gs = get_surface_state(view->surface);
struct gl_output_state *go = get_output_state(output);
+ float alpha = view->alpha;
+
+ if (view->blending_equation != ZWP_BLENDING_V1_BLENDING_EQUATION_NONE &&
+ view->blending_equation != ZWP_BLENDING_V1_BLENDING_EQUATION_OPAQUE) {
+ alpha *= view->blending_alpha;
+ }
glUniformMatrix4fv(shader->proj_uniform,
1, GL_FALSE, go->output_matrix.d);
glUniform4fv(shader->color_uniform, 1, gs->color);
- glUniform1f(shader->alpha_uniform, view->alpha);
+ glUniform1f(shader->alpha_uniform, alpha);
for (i = 0; i < gs->num_textures; i++)
glUniform1i(shader->tex_uniforms[i], i);
@@ -900,6 +907,8 @@
pixman_region32_t repaint;
/* opaque region in surface coordinates: */
pixman_region32_t surface_opaque;
+ pixman_region32_t surface_opaque_full;
+ pixman_region32_t *surface_opaque_src_ptr;
/* non-opaque region in surface coordinates: */
pixman_region32_t surface_blend;
GLint filter;
@@ -919,7 +928,13 @@
if (!pixman_region32_not_empty(&repaint))
goto out;
- glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ if (ev->blending_equation == ZWP_BLENDING_V1_BLENDING_EQUATION_PREMULTIPLIED) {
+ glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ } else if (ev->blending_equation == ZWP_BLENDING_V1_BLENDING_EQUATION_STRAIGHT) {
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ } else {
+ glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ }
if (gr->fan_debug) {
use_shader(gr, &gr->solid_shader);
@@ -951,14 +966,23 @@
pixman_region32_subtract(&surface_blend, &surface_blend,
&ev->surface->opaque);
+ if (ev->blending_equation == ZWP_BLENDING_V1_BLENDING_EQUATION_OPAQUE) {
+ pixman_region32_clear(&surface_blend);
+ pixman_region32_init_rect(&surface_opaque_full, 0, 0,
+ ev->surface->width, ev->surface->height);
+ surface_opaque_src_ptr = &surface_opaque_full;
+ } else {
+ surface_opaque_src_ptr = &ev->surface->opaque;
+ }
+
/* XXX: Should we be using ev->transform.opaque here? */
pixman_region32_init(&surface_opaque);
if (ev->geometry.scissor_enabled)
pixman_region32_intersect(&surface_opaque,
- &ev->surface->opaque,
+ surface_opaque_src_ptr,
&ev->geometry.scissor);
else
- pixman_region32_copy(&surface_opaque, &ev->surface->opaque);
+ pixman_region32_copy(&surface_opaque, surface_opaque_src_ptr);
if (pixman_region32_not_empty(&surface_opaque)) {
if (gs->shader == &gr->texture_shader_rgba) {