cursor-renderer/native: Unpremultiply for color state transformation
Without doing this, a non-linear color state transformation could result in premultiplied colour values larger than the alpha value, which manifested with artifacts such as parts of the cursor shining brighter than SDR white (with HDR enabled). This was reported in the GNOME Shell Matrix room on August 8th 2024, and I later hit it myself. v2: * Fix add_pipeline_snippet function formatting. (Sebastian Wick) Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/4224>
This commit is contained in:
@ -89,6 +89,9 @@ struct _MetaCursorRendererNativePrivate
|
|||||||
gboolean input_disconnected;
|
gboolean input_disconnected;
|
||||||
GMutex input_mutex;
|
GMutex input_mutex;
|
||||||
GCond input_cond;
|
GCond input_cond;
|
||||||
|
|
||||||
|
CoglSnippet *premult_snippet;
|
||||||
|
CoglSnippet *unpremult_snippet;
|
||||||
};
|
};
|
||||||
typedef struct _MetaCursorRendererNativePrivate MetaCursorRendererNativePrivate;
|
typedef struct _MetaCursorRendererNativePrivate MetaCursorRendererNativePrivate;
|
||||||
|
|
||||||
@ -183,6 +186,8 @@ meta_cursor_renderer_native_finalize (GObject *object)
|
|||||||
g_clear_signal_handler (&priv->texture_changed_handler_id,
|
g_clear_signal_handler (&priv->texture_changed_handler_id,
|
||||||
priv->current_cursor);
|
priv->current_cursor);
|
||||||
g_clear_object (&priv->current_cursor);
|
g_clear_object (&priv->current_cursor);
|
||||||
|
g_clear_object (&priv->premult_snippet);
|
||||||
|
g_clear_object (&priv->unpremult_snippet);
|
||||||
g_clear_handle_id (&priv->animation_timeout_id, g_source_remove);
|
g_clear_handle_id (&priv->animation_timeout_id, g_source_remove);
|
||||||
|
|
||||||
G_OBJECT_CLASS (meta_cursor_renderer_native_parent_class)->finalize (object);
|
G_OBJECT_CLASS (meta_cursor_renderer_native_parent_class)->finalize (object);
|
||||||
@ -725,6 +730,40 @@ load_cursor_sprite_gbm_buffer_for_crtc (MetaCursorRendererNative *native,
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
add_pipeline_snippet (CoglPipeline *pipeline,
|
||||||
|
CoglSnippet **snippet,
|
||||||
|
const char *snippet_source)
|
||||||
|
{
|
||||||
|
if (!*snippet)
|
||||||
|
*snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT, "",
|
||||||
|
snippet_source);
|
||||||
|
|
||||||
|
cogl_pipeline_add_snippet (pipeline, *snippet);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
add_pipeline_premultiply (MetaCursorRendererNative *cursor_renderer_native,
|
||||||
|
CoglPipeline *pipeline)
|
||||||
|
{
|
||||||
|
MetaCursorRendererNativePrivate *priv =
|
||||||
|
meta_cursor_renderer_native_get_instance_private (cursor_renderer_native);
|
||||||
|
|
||||||
|
add_pipeline_snippet (pipeline, &priv->premult_snippet,
|
||||||
|
" cogl_color_out.rgb *= cogl_color_out.a;\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
add_pipeline_unpremultiply (MetaCursorRendererNative *cursor_renderer_native,
|
||||||
|
CoglPipeline *pipeline)
|
||||||
|
{
|
||||||
|
MetaCursorRendererNativePrivate *priv =
|
||||||
|
meta_cursor_renderer_native_get_instance_private (cursor_renderer_native);
|
||||||
|
|
||||||
|
add_pipeline_snippet (pipeline, &priv->unpremult_snippet,
|
||||||
|
" cogl_color_out.rgb /= cogl_color_out.a;\n");
|
||||||
|
}
|
||||||
|
|
||||||
static CoglTexture *
|
static CoglTexture *
|
||||||
scale_and_transform_cursor_sprite_cpu (MetaCursorRendererNative *cursor_renderer_native,
|
scale_and_transform_cursor_sprite_cpu (MetaCursorRendererNative *cursor_renderer_native,
|
||||||
ClutterColorState *target_color_state,
|
ClutterColorState *target_color_state,
|
||||||
@ -772,11 +811,17 @@ scale_and_transform_cursor_sprite_cpu (MetaCursorRendererNative *cursor_renderer
|
|||||||
cogl_pipeline_set_layer_texture (pipeline, 0, src_texture);
|
cogl_pipeline_set_layer_texture (pipeline, 0, src_texture);
|
||||||
cogl_pipeline_set_layer_matrix (pipeline, 0, matrix);
|
cogl_pipeline_set_layer_matrix (pipeline, 0, matrix);
|
||||||
|
|
||||||
|
if (cogl_texture_get_premultiplied (src_texture))
|
||||||
|
add_pipeline_unpremultiply (cursor_renderer_native, pipeline);
|
||||||
|
|
||||||
color_state = meta_cursor_sprite_get_color_state (cursor_sprite);
|
color_state = meta_cursor_sprite_get_color_state (cursor_sprite);
|
||||||
clutter_color_state_add_pipeline_transform (color_state,
|
clutter_color_state_add_pipeline_transform (color_state,
|
||||||
target_color_state,
|
target_color_state,
|
||||||
pipeline);
|
pipeline);
|
||||||
|
|
||||||
|
if (cogl_texture_get_premultiplied (dst_texture))
|
||||||
|
add_pipeline_premultiply (cursor_renderer_native, pipeline);
|
||||||
|
|
||||||
cogl_framebuffer_clear4f (COGL_FRAMEBUFFER (offscreen),
|
cogl_framebuffer_clear4f (COGL_FRAMEBUFFER (offscreen),
|
||||||
COGL_BUFFER_BIT_COLOR,
|
COGL_BUFFER_BIT_COLOR,
|
||||||
0.0f, 0.0f, 0.0f, 0.0f);
|
0.0f, 0.0f, 0.0f, 0.0f);
|
||||||
|
Reference in New Issue
Block a user