Merge branch 'straight-alpha-fb' into 'main'

Draft: Add support for KMS devices that only support straight alpha fb encoding

See merge request wayland/weston!2046
This commit is contained in:
Leandro Ribeiro 2026-05-05 20:38:56 +00:00
commit e9ebd0958c
17 changed files with 366 additions and 47 deletions

View file

@ -378,6 +378,15 @@ enum weston_repaint_status {
REPAINT_DEFERRED,
};
/** Output's required framebuffer alpha encoding
*
* \ingroup output
*/
enum weston_output_fb_alpha_encoding {
WESTON_OUTPUT_FB_ALPHA_ENCODING_PREMULT = 0,
WESTON_OUTPUT_FB_ALPHA_ENCODING_STRAIGHT,
};
/** Content producer for heads
*
* \rst
@ -581,6 +590,8 @@ struct weston_output {
enum weston_color_format color_format;
enum weston_output_fb_alpha_encoding fb_alpha_encoding;
/**
* Set by the shell to indicate there's some content for this
* output to display.

View file

@ -423,6 +423,8 @@ struct drm_plane_state {
uint64_t zpos;
uint16_t alpha;
enum wdrm_plane_blend blend_mode;
enum wdrm_plane_color_encoding color_encoding;
enum wdrm_plane_color_range color_range;
@ -1007,6 +1009,10 @@ bool
drm_plane_supports_color_range(struct drm_plane *plane,
enum wdrm_plane_color_range range);
bool
drm_plane_supports_blend_mode(struct drm_plane *plane,
enum wdrm_plane_blend blend_mode);
void
drm_output_render(struct drm_output_state *state);

View file

@ -56,6 +56,7 @@ enum wdrm_plane_property {
WDRM_PLANE_ZPOS,
WDRM_PLANE_ROTATION,
WDRM_PLANE_ALPHA,
WDRM_PLANE_BLEND,
WDRM_PLANE_COLOR_ENCODING,
WDRM_PLANE_COLOR_RANGE,
WDRM_PLANE__COUNT
@ -105,6 +106,17 @@ enum wdrm_plane_color_range {
};
#define WDRM_PLANE_COLOR_RANGE_DEFAULT WDRM_PLANE_COLOR_RANGE_LIMITED
/**
* Possible values for the WDRM_PLANE_BLEND property.
*/
enum wdrm_plane_blend {
WDRM_PLANE_BLEND_NONE = 0,
WDRM_PLANE_BLEND_PREMULT,
WDRM_PLANE_BLEND_COVERAGE,
WDRM_PLANE_BLEND__COUNT
};
#define WDRM_PLANE_BLEND_DEFAULT WDRM_PLANE_BLEND_PREMULT
/**
* List of properties attached to a DRM connector
*/

View file

@ -562,6 +562,18 @@ drm_output_render(struct drm_output_state *state)
scanout_state = drm_output_state_get_plane(state, scanout_plane);
weston_assert_ptr_null(c, scanout_state->fb);
if (output->base.fb_alpha_encoding == WESTON_OUTPUT_FB_ALPHA_ENCODING_PREMULT) {
weston_assert_true(c, drm_plane_supports_blend_mode(scanout_plane,
WDRM_PLANE_BLEND_DEFAULT));
scanout_state->blend_mode = WDRM_PLANE_BLEND_DEFAULT;
} else if (output->base.fb_alpha_encoding == WESTON_OUTPUT_FB_ALPHA_ENCODING_STRAIGHT) {
weston_assert_true(c, drm_plane_supports_blend_mode(scanout_plane,
WDRM_PLANE_BLEND_COVERAGE));
scanout_state->blend_mode = WDRM_PLANE_BLEND_COVERAGE;
} else {
weston_assert_not_reached(c, "unknown fb alpha encoding");
}
pixman_region32_init(&damage);
weston_output_flush_damage_for_primary_plane(&output->base, &damage);
@ -2677,6 +2689,19 @@ drm_output_init_planes(struct drm_output *output)
}
primary_plane_zpos_min = scanout_plane->zpos_min;
/**
* If only coverage blend mode supported by primary plane, renderers
* should produce straight alpha fb's.
*/
if (!drm_plane_supports_blend_mode(scanout_plane, WDRM_PLANE_BLEND_DEFAULT)) {
if (!drm_plane_supports_blend_mode(scanout_plane, WDRM_PLANE_BLEND_COVERAGE)) {
weston_log("Error: primary plane must support either premult "
"or coverage alpha blend mode.\n");
return -1;
}
output->base.fb_alpha_encoding = WESTON_OUTPUT_FB_ALPHA_ENCODING_STRAIGHT;
}
/* Failing to find a cursor plane is not fatal, as we'll fall back
* to software cursor. */
cursor_plane =
@ -2884,6 +2909,27 @@ should_wait_drm_events(struct drm_device *device)
return false;
}
static void
maybe_disable_underlays_for_coverage_alpha(struct drm_output *output,
const struct weston_renderer *renderer)
{
struct weston_compositor *wc = output->base.compositor;
/**
* When straight alpha mode is set, we must feed the primary plane with
* straight alpha fb's. If renderer can't do that, we can still support
* straight alpha outputs by disabling underlays (as the primary plane
* won't get blended with something below it).
*/
if (output->base.fb_alpha_encoding == WESTON_OUTPUT_FB_ALPHA_ENCODING_STRAIGHT &&
!renderer->can_render_fb_encoding_straight_alpha(wc)) {
weston_log("Disabling underlay planes for output '%s': straight alpha "
"is set but renderer can't produce straight alpha fb's.\n",
output->base.name);
output->has_underlay = false;
}
}
static int
drm_output_enable(struct weston_output *base)
{
@ -2922,6 +2968,8 @@ drm_output_enable(struct weston_output *base)
if (ret < 0)
goto err_crtc;
maybe_disable_underlays_for_coverage_alpha(output, b->compositor->renderer);
if (drm_output_init_legacy_gamma_size(output) < 0)
goto err_planes;

View file

@ -37,6 +37,7 @@
#include <libweston/libweston.h>
#include <libweston/backend-drm.h>
#include "shared/helpers.h"
#include "shared/weston-assert.h"
#include "shared/weston-drm-fourcc.h"
#include "drm-internal.h"
#include "pixel-formats.h"
@ -100,6 +101,18 @@ struct drm_property_enum_info plane_color_range_enums[] = {
},
};
struct drm_property_enum_info plane_blend_enums[] = {
[WDRM_PLANE_BLEND_NONE] = {
.name = "None",
},
[WDRM_PLANE_BLEND_PREMULT] = {
.name = "Pre-multiplied",
},
[WDRM_PLANE_BLEND_COVERAGE] = {
.name = "Coverage",
},
};
const struct drm_property_info plane_props[] = {
[WDRM_PLANE_TYPE] = {
.name = "type",
@ -126,6 +139,11 @@ const struct drm_property_info plane_props[] = {
.num_enum_values = WDRM_PLANE_ROTATION__COUNT,
},
[WDRM_PLANE_ALPHA] = { .name = "alpha" },
[WDRM_PLANE_BLEND] = {
.name = "pixel blend mode",
.enum_values = plane_blend_enums,
.num_enum_values = WDRM_PLANE_BLEND__COUNT,
},
[WDRM_PLANE_COLOR_ENCODING] = {
.name = "COLOR_ENCODING",
.enum_values = plane_color_encoding_enums,
@ -704,6 +722,31 @@ drm_plane_supports_color_range(struct drm_plane *plane,
return enum_info->valid;
}
/**
* Check if a blend mode is supported by a KMS plane
*
* If the blend mode property is not supported by the plane, this assumes that
* the blend mode is unsupported if different from WDRM_PLANE_BLEND_DEFAULT.
*
* @param plane The KMS plane
* @param blend_mode The blend mode to check
* @return True if supported, false otherwise
*/
bool
drm_plane_supports_blend_mode(struct drm_plane *plane,
enum wdrm_plane_blend blend_mode)
{
const struct drm_property_info *info = &plane->props[WDRM_PLANE_BLEND];
const struct drm_property_enum_info *enum_info;
if (info->prop_id == 0)
return blend_mode == WDRM_PLANE_BLEND_DEFAULT;
enum_info = &info->enum_values[blend_mode];
return enum_info->valid;
}
/**
* Mark an output state as current on the output, i.e. it has been
* submitted to the kernel. The mode argument determines whether this
@ -1258,8 +1301,10 @@ drm_plane_set_color_encoding(struct drm_plane *plane,
enum wdrm_plane_color_encoding color_encoding,
drmModeAtomicReq *req)
{
if (color_encoding == WDRM_PLANE_COLOR_ENCODING__COUNT)
return 0;
struct weston_compositor *wc = plane->base.compositor;
weston_assert_s32_ge(wc, color_encoding, 0);
weston_assert_s32_lt(wc, color_encoding, WDRM_PLANE_COLOR_ENCODING__COUNT);
if (plane->props[WDRM_PLANE_COLOR_ENCODING].prop_id == 0) {
if (color_encoding == WDRM_PLANE_COLOR_ENCODING_DEFAULT)
@ -1268,7 +1313,7 @@ drm_plane_set_color_encoding(struct drm_plane *plane,
return -1;
}
assert(drm_plane_supports_color_encoding(plane, color_encoding));
weston_assert_true(wc, drm_plane_supports_color_encoding(plane, color_encoding));
return plane_add_prop(req, plane, WDRM_PLANE_COLOR_ENCODING,
color_encoding);
@ -1279,8 +1324,10 @@ drm_plane_set_color_range(struct drm_plane *plane,
enum wdrm_plane_color_range color_range,
drmModeAtomicReq *req)
{
if (color_range == WDRM_PLANE_COLOR_RANGE__COUNT)
return 0;
struct weston_compositor *wc = plane->base.compositor;
weston_assert_s32_ge(wc, color_range, 0);
weston_assert_s32_lt(wc, color_range, WDRM_PLANE_COLOR_RANGE__COUNT);
if (plane->props[WDRM_PLANE_COLOR_RANGE].prop_id == 0) {
if (color_range == WDRM_PLANE_COLOR_RANGE_DEFAULT)
@ -1289,11 +1336,33 @@ drm_plane_set_color_range(struct drm_plane *plane,
return -1;
}
assert(drm_plane_supports_color_range(plane, color_range));
weston_assert_true(wc, drm_plane_supports_color_range(plane, color_range));
return plane_add_prop(req, plane, WDRM_PLANE_COLOR_RANGE, color_range);
}
static int
drm_plane_set_blend_mode(struct drm_plane *plane,
enum wdrm_plane_blend blend_mode,
drmModeAtomicReq *req)
{
struct weston_compositor *wc = plane->base.compositor;
weston_assert_s32_ge(wc, blend_mode, 0);
weston_assert_s32_lt(wc, blend_mode, WDRM_PLANE_BLEND__COUNT);
if (plane->props[WDRM_PLANE_BLEND].prop_id == 0) {
if (blend_mode == WDRM_PLANE_BLEND_DEFAULT)
return 0;
return -1;
}
weston_assert_true(wc, drm_plane_supports_blend_mode(plane, blend_mode));
return plane_add_prop(req, plane, WDRM_PLANE_BLEND, blend_mode);
}
static int
drm_output_apply_state_atomic(struct drm_output_state *state,
drmModeAtomicReq *req,
@ -1485,6 +1554,10 @@ drm_output_apply_state_atomic(struct drm_output_state *state,
WDRM_PLANE_ALPHA,
plane_state->alpha);
ret |= drm_plane_set_blend_mode(plane,
plane_state->blend_mode,
req);
ret |= drm_plane_set_color_encoding(plane,
plane_state->color_encoding,
req);

View file

@ -58,8 +58,10 @@ drm_plane_state_alloc(struct drm_output_state *state_output,
state->alpha = (plane->alpha_max < DRM_PLANE_ALPHA_OPAQUE) ?
plane->alpha_max : DRM_PLANE_ALPHA_OPAQUE;
state->color_encoding = WDRM_PLANE_COLOR_ENCODING__COUNT;
state->color_range = WDRM_PLANE_COLOR_RANGE__COUNT;
state->blend_mode = WDRM_PLANE_BLEND_DEFAULT;
state->color_encoding = WDRM_PLANE_COLOR_ENCODING_DEFAULT;
state->color_range = WDRM_PLANE_COLOR_RANGE_DEFAULT;
/* Here we only add the plane state to the desired link, and not
* set the member. Having an output pointer set means that the

View file

@ -103,6 +103,36 @@ drm_output_check_plane_has_view_assigned(struct drm_plane *plane,
return false;
}
static bool
select_plane_blend_mode(struct drm_plane_state *state,
struct drm_fb *fb, char **err_msg)
{
struct drm_plane *plane = state->plane;
if (drm_plane_supports_blend_mode(plane, WDRM_PLANE_BLEND_DEFAULT)) {
state->blend_mode = WDRM_PLANE_BLEND_DEFAULT;
return true;
}
/**
* TODO: for now we don't support coverage alpha from the color
* representation protocol. With that we'd be able to place non-opaque
* straight alpha content in planes that only support coverage blend
* mode.
*/
if (drm_plane_supports_blend_mode(plane, WDRM_PLANE_BLEND_COVERAGE)) {
if (state->alpha != DRM_PLANE_ALPHA_OPAQUE || fb->format->bits.a != 0) {
str_printf(err_msg, "can't offload non-opaque content for outputs in alpha coverage mode");
return false;
}
state->blend_mode = WDRM_PLANE_BLEND_COVERAGE;
return true;
}
str_printf(err_msg, "neither pre-mult or coverage blend modes are supported");
return false;
}
static struct drm_plane_state *
drm_output_try_paint_node_on_plane(struct drm_plane_handle *handle,
struct drm_output_state *output_state,
@ -116,6 +146,7 @@ drm_output_try_paint_node_on_plane(struct drm_plane_handle *handle,
struct drm_backend *b = device->backend;
struct drm_plane *plane = handle->plane;
struct drm_plane_state *state = NULL;
char *err_msg;
assert(!device->disable_client_buffer_scanout);
assert(output == handle->output);
@ -133,6 +164,13 @@ drm_output_try_paint_node_on_plane(struct drm_plane_handle *handle,
drm_plane_state_coords_for_paint_node(state, pnode, zpos);
if (!select_plane_blend_mode(state, fb, &err_msg)) {
drm_debug(b, "\t\t\t[paint node] not placing paint node %s on plane %lu: %s\n",
pnode->internal_name, (unsigned long) plane->plane_id, err_msg);
free(err_msg);
goto out;
}
/* We hold one reference for the lifetime of this function; from
* calling drm_fb_get_from_paint_node() in
* drm_output_prepare_plane_view(), so, we take another reference
@ -238,6 +276,7 @@ drm_output_prepare_cursor_paint_node(struct drm_output_state *output_state,
struct drm_plane *plane;
struct drm_plane_state *plane_state;
const char *p_name;
char *err_msg;
assert(!device->cursors_are_broken);
assert(handle);
@ -283,6 +322,13 @@ drm_output_prepare_cursor_paint_node(struct drm_output_state *output_state,
*/
plane_state->fb = drm_fb_ref(output->gbm_cursor_fb[0]);
if (!select_plane_blend_mode(plane_state, plane_state->fb, &err_msg)) {
drm_debug(b, "\t\t\t\t[%s] not assigning paint node %s to %s plane (%s)\n",
p_name, pnode->internal_name, p_name, err_msg);
free(err_msg);
goto err;
}
/* The cursor API is somewhat special: in cursor_bo_update(), we upload
* a buffer which is always cursor_width x cursor_height, even if the
* surface we want to promote is actually smaller than this. Manually

View file

@ -8339,6 +8339,7 @@ weston_output_init(struct weston_output *output,
output->allow_protection = true;
output->power_state = WESTON_OUTPUT_POWER_NORMAL;
output->repaint_only_on_capture = false;
output->fb_alpha_encoding = WESTON_OUTPUT_FB_ALPHA_ENCODING_PREMULT;
wl_list_init(&output->head_list);

View file

@ -201,6 +201,14 @@ struct weston_renderer {
uint32_t format,
const uint64_t *modifiers, unsigned int count);
/** Checks if renderer is able to produce fb's with straight alpha
* encoding (i.e. not pre-multiplied by alpha).
*
* \param wc The Weston compositor instance.
* \return True if renderer is capable, false otherwise.
*/
bool (*can_render_fb_encoding_straight_alpha)(struct weston_compositor *wc);
enum weston_renderer_type type;
const struct gl_renderer_interface *gl;
const struct vulkan_renderer_interface *vulkan;

View file

@ -57,6 +57,12 @@ noop_renderer_flush_damage(struct weston_paint_node *pnode)
{
}
static bool
noop_renderer_can_render_fb_encoding_straight_alpha(struct weston_compositor *wc)
{
return false;
}
static void
noop_renderer_attach(struct weston_paint_node *pnode)
{
@ -135,6 +141,7 @@ noop_renderer_init(struct weston_compositor *ec)
renderer->base.flush_damage = noop_renderer_flush_damage;
renderer->base.attach = noop_renderer_attach;
renderer->base.destroy = noop_renderer_destroy;
renderer->base.can_render_fb_encoding_straight_alpha = noop_renderer_can_render_fb_encoding_straight_alpha;
renderer->base.type = WESTON_RENDERER_NOOP;
ec->renderer = &renderer->base;

View file

@ -947,6 +947,12 @@ pixman_renderer_destroy_renderbuffer(weston_renderbuffer_t renderbuffer)
free(rb);
}
static bool
pixman_renderer_can_render_fb_encoding_straight_alpha(struct weston_compositor *wc)
{
return false;
}
static bool
pixman_renderer_discard_renderbuffers(struct pixman_output_state *po,
bool destroy)
@ -1080,6 +1086,8 @@ pixman_renderer_init(struct weston_compositor *ec)
renderer->base.create_renderbuffer_dmabuf = NULL;
renderer->base.destroy_renderbuffer =
pixman_renderer_destroy_renderbuffer;
renderer->base.can_render_fb_encoding_straight_alpha =
pixman_renderer_can_render_fb_encoding_straight_alpha;
renderer->base.type = WESTON_RENDERER_PIXMAN;
renderer->base.pixman = &pixman_renderer_interface;
ec->renderer = &renderer->base;

View file

@ -60,6 +60,10 @@
#define SHADER_COLOR_MAPPING_3DLUT 1
#define SHADER_COLOR_MAPPING_MATRIX 2
/* enum gl_shader_fb_alpha_encoding */
#define SHADER_FB_ALPHA_ENCODING_PREMULT 0
#define SHADER_FB_ALPHA_ENCODING_STRAIGHT 1
#if DEF_VARIANT == SHADER_VARIANT_EXTERNAL
#extension GL_OES_EGL_image_external : require
#endif
@ -91,6 +95,7 @@ compile_const int c_color_post_curve = DEF_COLOR_POST_CURVE;
compile_const int c_fb_fetch_curve = DEF_FB_FETCH_CURVE;
compile_const int c_fb_store_curve = DEF_FB_STORE_CURVE;
compile_const int c_color_effect = DEF_COLOR_EFFECT;
compile_const int c_fb_alpha_encoding = DEF_FB_ALPHA_ENCODING;
compile_const bool c_input_is_premult = DEF_INPUT_IS_PREMULT;
compile_const bool c_tint = DEF_TINT;
@ -570,15 +575,29 @@ main()
vec4 src;
vec4 dst;
/* Always alpha pre-multiplied. */
src = fragment_input_color_premult();
/* Framebuffer must have straight alpha. */
/**
* Framebuffer content is pre-multiplied if c_alpha_premult_blending,
* straight alpha otherwise.
*/
dst = gl_LastFragData[0];
dst.rgb = color_curve(c_fb_fetch_curve, fb_fetch_curve_lut,
fb_fetch_curve_par, dst.rgb);
/* glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); */
dst = src + (1.0 - src.a) * dst;
if (c_fb_alpha_encoding == SHADER_FB_ALPHA_ENCODING_PREMULT) {
/* glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); */
dst = src + (1.0 - src.a) * dst;
} else {
/* SHADER_FB_ALPHA_ENCODING_STRAIGHT; same formula here, but
* dst is not alpha pre-mult. */
dst.rgb = src.rgb + (1.0 - src.a) * dst.rgb * dst.a;
dst.a = src.a + (1.0 - src.a) * dst.a;
/* Leave the fb as straight alpha */
if (dst.a > 0.0)
dst.rgb /= dst.a;
}
dst.rgb = color_curve(c_fb_store_curve, fb_store_curve_lut,
fb_store_curve_par, dst.rgb);

View file

@ -252,6 +252,12 @@ enum gl_shader_color_mapping {
SHADER_COLOR_MAPPING_MATRIX,
};
/* Keep the following in sync with fragment.glsl. */
enum gl_shader_fb_alpha_encoding {
SHADER_FB_ALPHA_ENCODING_PREMULT = 0,
SHADER_FB_ALPHA_ENCODING_STRAIGHT,
};
enum gl_shader_attrib_loc {
SHADER_ATTRIB_LOC_POSITION = 0,
SHADER_ATTRIB_LOC_TEXCOORD,
@ -313,6 +319,7 @@ struct gl_shader_requirements
unsigned color_post_curve:3; /* enum gl_shader_color_curve */
bool shader_blending:1;
unsigned fb_alpha_encoding:1; /* enum gl_shader_fb_alpha_encoding */
unsigned fb_fetch_curve:3; /* enum gl_shader_color_curve */
unsigned fb_store_curve:3; /* enum gl_shader_color_curve */
@ -320,7 +327,7 @@ struct gl_shader_requirements
* The total size of all bitfields plus pad_bits_ must fill up exactly
* how many bytes the compiler allocates for them together.
*/
unsigned pad_bits_:7;
unsigned pad_bits_:6;
};
static_assert(sizeof(struct gl_shader_requirements) ==
4 /* total bitfield size in bytes */,
@ -406,6 +413,8 @@ struct gl_shader_config {
union gl_shader_config_color_curve fb_fetch_curve;
union gl_shader_config_color_curve fb_store_curve;
enum gl_shader_fb_alpha_encoding fb_alpha_encoding;
enum weston_color_matrix_coef yuv_coefficients;
enum weston_color_quant_range yuv_range;
};
@ -787,7 +796,8 @@ void
gl_shader_blender_destroy(struct gl_shader_blender *shader_blender);
struct gl_shader_blender *
gl_shader_blender_create(struct gl_renderer *gr, struct weston_output *output);
gl_shader_blender_create(struct gl_renderer *gr, struct weston_output *output,
enum gl_shader_fb_alpha_encoding fb_alpha_encoding);
void
gl_shader_config_set_blender(struct gl_renderer *gr,

View file

@ -4842,6 +4842,26 @@ gl_renderer_create_window_surface(struct gl_renderer *gr,
return egl_surface;
}
static bool
gl_renderer_can_render_fb_encoding_straight_alpha(struct weston_compositor *wc)
{
const struct weston_testsuite_quirks *quirks = &wc->test_data.test_quirks;
struct gl_renderer *gr = get_renderer(wc);
if (!gl_features_has(gr, FEATURE_SHADER_BLENDING))
return false;
/* In-shader blending is required. */
if (quirks->blending_impl == WESTON_BLENDING_IMPL_FF)
return false;
/* This forbids in-shader blending. */
if (quirks->gl_force_full_redraw_of_shadow_fb)
return false;
return true;
}
static int
gl_renderer_output_create(struct weston_output *output,
EGLSurface surface,
@ -4849,16 +4869,18 @@ gl_renderer_output_create(struct weston_output *output,
const struct weston_geometry *area)
{
struct gl_output_state *go;
struct gl_renderer *gr = get_renderer(output->compositor);
const struct weston_testsuite_quirks *quirks;
struct weston_compositor *wc = output->compositor;
struct gl_renderer *gr = get_renderer(wc);
const struct weston_testsuite_quirks *quirks = &wc->test_data.test_quirks;
enum gl_shader_fb_alpha_encoding fb_alpha_encoding;
bool needs_fb_curves;
bool needs_shadow;
bool needs_shader_blending;
bool needs_straight_alpha;
int i;
assert(!get_output_state(output));
quirks = &output->compositor->test_data.test_quirks;
go = zalloc(sizeof *go);
if (go == NULL)
return -1;
@ -4882,27 +4904,35 @@ gl_renderer_output_create(struct weston_output *output,
go->render_sync = EGL_NO_SYNC_KHR;
needs_shadow = quirks->gl_force_full_redraw_of_shadow_fb;
needs_straight_alpha = output->fb_alpha_encoding == WESTON_OUTPUT_FB_ALPHA_ENCODING_STRAIGHT &&
gl_renderer_can_render_fb_encoding_straight_alpha(wc);
needs_shader_blending = quirks->blending_impl == WESTON_BLENDING_IMPL_SHADER ||
needs_straight_alpha;
needs_fb_curves = output->color_outcome->from_blend_to_output &&
!output->from_blend_to_output_by_backend;
if (needs_fb_curves)
weston_assert_true(gr->compositor, gl_features_has(gr, FEATURE_COLOR_TRANSFORMS));
weston_assert_true(wc, gl_features_has(gr, FEATURE_COLOR_TRANSFORMS));
if (!needs_shadow && needs_fb_curves) {
if (needs_shader_blending)
weston_assert_false(wc, needs_shadow);
if (!needs_shadow && (needs_fb_curves || needs_shader_blending)) {
switch (quirks->blending_impl) {
case WESTON_BLENDING_IMPL_AUTO:
go->shader_blender = gl_shader_blender_create(gr, output);
break;
case WESTON_BLENDING_IMPL_FF:
weston_assert_false(wc, needs_shader_blending);
go->shader_blender = NULL;
break;
case WESTON_BLENDING_IMPL_AUTO:
case WESTON_BLENDING_IMPL_SHADER:
go->shader_blender = gl_shader_blender_create(gr, output);
if (!go->shader_blender) {
weston_log("Error: quirks were used to force in-shader blending, "
"but it's not supported by the GLES implementation.\n"
fb_alpha_encoding = needs_straight_alpha ? SHADER_FB_ALPHA_ENCODING_STRAIGHT :
SHADER_FB_ALPHA_ENCODING_PREMULT;
go->shader_blender = gl_shader_blender_create(gr, output, fb_alpha_encoding);
if (needs_shader_blending && !go->shader_blender) {
weston_log("Error: in-shader blending required but not supported by "
"the GLES implementation.\n"
"Quitting...\n");
weston_compositor_exit_with_code(gr->compositor, RESULT_SKIP);
weston_compositor_exit_with_code(wc, RESULT_SKIP);
}
break;
}
@ -5282,6 +5312,7 @@ gl_renderer_display_create(struct weston_compositor *ec,
gr->base.surface_copy_content = gl_renderer_surface_copy_content;
gr->base.fill_buffer_info = gl_renderer_fill_buffer_info;
gr->base.buffer_init = gl_renderer_buffer_init;
gr->base.can_render_fb_encoding_straight_alpha = gl_renderer_can_render_fb_encoding_straight_alpha;
gr->base.output_set_border = gl_renderer_output_set_border;
gr->base.type = WESTON_RENDERER_GL;

View file

@ -67,6 +67,7 @@ struct gl_renderer_color_effect {
/** for in-shader blending */
struct gl_shader_blender {
enum gl_shader_fb_alpha_encoding fb_alpha_encoding;
struct gl_renderer_color_curve fb_fetch_curve;
struct gl_renderer_color_curve fb_store_curve;
};
@ -588,40 +589,51 @@ gl_shader_blender_destroy(struct gl_shader_blender *shader_blender)
}
struct gl_shader_blender *
gl_shader_blender_create(struct gl_renderer *gr, struct weston_output *output)
gl_shader_blender_create(struct gl_renderer *gr, struct weston_output *output,
enum gl_shader_fb_alpha_encoding fb_alpha_encoding)
{
struct gl_shader_blender *shader_blender;
struct weston_color_curve *fb_fetch;
const struct weston_color_curve *fb_store;
const struct weston_color_transform *xform;
const struct weston_color_curve identity_curve = {
.type = WESTON_COLOR_CURVE_TYPE_IDENTITY,
};
bool ok;
if (!gl_features_has(gr, FEATURE_SHADER_BLENDING))
return NULL;
xform = output->color_outcome->from_blend_to_output;
if (!xform)
return NULL;
fb_store = weston_color_transform_as_single_curve(xform);
if (!fb_store)
return NULL;
fb_fetch = weston_color_curve_create_inverse(fb_store);
if (!fb_fetch)
return NULL;
shader_blender = xzalloc(sizeof *shader_blender);
ok = gl_color_curve_init(gr, &shader_blender->fb_store_curve, fb_store, NULL) &&
gl_color_curve_init(gr, &shader_blender->fb_fetch_curve, fb_fetch, NULL);
free(fb_fetch);
shader_blender->fb_alpha_encoding = fb_alpha_encoding;
if (!ok) {
free(shader_blender);
return NULL;
xform = output->color_outcome->from_blend_to_output;
if (xform) {
fb_store = weston_color_transform_as_single_curve(xform);
if (!fb_store)
goto fail;
fb_fetch = weston_color_curve_create_inverse(fb_store);
if (!fb_fetch)
goto fail;
ok = gl_color_curve_init(gr, &shader_blender->fb_store_curve, fb_store, NULL) &&
gl_color_curve_init(gr, &shader_blender->fb_fetch_curve, fb_fetch, NULL);
free(fb_fetch);
} else {
ok = gl_color_curve_init(gr, &shader_blender->fb_store_curve, &identity_curve, NULL) &&
gl_color_curve_init(gr, &shader_blender->fb_fetch_curve, &identity_curve, NULL);
}
if (!ok)
goto fail;
return shader_blender;
fail:
free(shader_blender);
return NULL;
}
void
@ -637,9 +649,12 @@ gl_shader_config_set_blender(struct gl_renderer *gr,
sconf->req.fb_store_curve = shader_blender->fb_store_curve.type;
sconf->fb_store_curve = shader_blender->fb_store_curve.u;
sconf->fb_alpha_encoding = shader_blender->fb_alpha_encoding;
} else {
sconf->req.shader_blending = false;
sconf->req.fb_fetch_curve = SHADER_COLOR_CURVE_IDENTITY;
sconf->req.fb_store_curve = SHADER_COLOR_CURVE_IDENTITY;
sconf->fb_alpha_encoding = SHADER_FB_ALPHA_ENCODING_PREMULT;
}
}

View file

@ -192,6 +192,18 @@ gl_shader_color_mapping_to_string(enum gl_shader_color_mapping kind)
return gl_shader_enum_map_get(gl_shader_color_mapping_mapping, kind);
}
static const struct gl_shader_enum_map gl_shader_fb_alpha_encoding_mapping[] = {
ENUMVAL(SHADER_FB_ALPHA_ENCODING_PREMULT, "pre-mult"),
ENUMVAL(SHADER_FB_ALPHA_ENCODING_STRAIGHT, "straight"),
};
static const struct gl_shader_enum_map *
gl_shader_fb_alpha_encoding_to_string(enum gl_shader_fb_alpha_encoding kind)
{
return gl_shader_enum_map_get(gl_shader_fb_alpha_encoding_mapping, kind);
}
static void
dump_program_with_line_numbers(int count, const char **sources)
{
@ -257,7 +269,7 @@ create_shader_description_string(const struct gl_shader_requirements *req)
int size;
char *str;
size = asprintf(&str, "%s tc, %s tex, %s effect, CP{ %s, %s, %s }, %cpremult_in %ctint %cshader_blending (%s, %s)",
size = asprintf(&str, "%s tc, %s tex, %s effect, CP{ %s, %s, %s }, %cpremult_in %ctint %cshader_blending fb_alpha_encoding %s (%s, %s)",
gl_shader_texcoord_input_to_string(req->texcoord_input)->desc,
gl_shader_texture_variant_to_string(req->variant)->desc,
gl_shader_color_effect_to_string(req->color_effect)->desc,
@ -267,6 +279,7 @@ create_shader_description_string(const struct gl_shader_requirements *req)
req->input_is_premult ? '+' : '-',
req->tint ? '+' : '-',
req->shader_blending ? '+' : '-',
gl_shader_fb_alpha_encoding_to_string(req->fb_alpha_encoding)->desc,
gl_shader_color_curve_to_string(req->fb_fetch_curve)->desc,
gl_shader_color_curve_to_string(req->fb_store_curve)->desc);
if (size < 0)
@ -306,6 +319,7 @@ create_fragment_shader_config_string(const struct gl_shader_requirements *req)
"#define DEF_COLOR_MAPPING %s\n"
"#define DEF_COLOR_POST_CURVE %s\n"
"#define DEF_SHADER_BLENDING %s\n"
"#define DEF_FB_ALPHA_ENCODING %s\n"
"#define DEF_FB_FETCH_CURVE %s\n"
"#define DEF_FB_STORE_CURVE %s\n"
"#define DEF_COLOR_EFFECT %s\n"
@ -318,6 +332,7 @@ create_fragment_shader_config_string(const struct gl_shader_requirements *req)
gl_shader_color_mapping_to_string(req->color_mapping)->symbol,
gl_shader_color_curve_to_string(req->color_post_curve)->symbol,
req->shader_blending ? "1" : "0",
gl_shader_fb_alpha_encoding_to_string(req->fb_alpha_encoding)->symbol,
gl_shader_color_curve_to_string(req->fb_fetch_curve)->symbol,
gl_shader_color_curve_to_string(req->fb_store_curve)->symbol,
gl_shader_color_effect_to_string(req->color_effect)->symbol,

View file

@ -3187,6 +3187,12 @@ vulkan_renderer_buffer_init(struct weston_compositor *ec,
wl_signal_add(&buffer->destroy_signal, &vb->destroy_listener);
}
static bool
vulkan_renderer_can_render_fb_encoding_straight_alpha(struct weston_compositor *wc)
{
return false;
}
static void
vulkan_renderer_output_destroy_border(struct weston_output *output,
enum weston_renderer_border_side side)
@ -4384,6 +4390,7 @@ vulkan_renderer_display_create(struct weston_compositor *ec,
vr->base.attach = vulkan_renderer_attach;
vr->base.destroy = vulkan_renderer_destroy;
vr->base.buffer_init = vulkan_renderer_buffer_init;
vr->base.can_render_fb_encoding_straight_alpha = vulkan_renderer_can_render_fb_encoding_straight_alpha;
vr->base.output_set_border = vulkan_renderer_output_set_border,
vr->base.type = WESTON_RENDERER_VULKAN;