gpu: Port convert op to GskGpuColorStates

Make it handle straight alpha, too, by checking if the alt colorspace is
premultiplied - which is the colorspace of the source.
This commit is contained in:
Benjamin Otte 2024-07-03 08:05:58 +02:00
parent 88dc49a5b6
commit f65d4914e4
4 changed files with 33 additions and 161 deletions

View File

@ -17,74 +17,19 @@ struct _GskGpuConvertOp
}; };
#define VARIATION_OPACITY (1u << 0) #define VARIATION_OPACITY (1u << 0)
#define VARIATION_ALPHA_ALL_CHANNELS (1u << 1) #define VARIATION_STRAIGHT_ALPHA (1u << 1)
#define VARIATION_SOURCE_UNPREMULTIPLY (1u << 2)
#define VARIATION_TARGET_PREMULTIPLY (1u << 3)
#define VARIATION_SOURCE_SHIFT 8u
#define VARIATION_TARGET_SHIFT 16u
#define VARIATION_COLOR_STATE_MASK 0xFFu
static guint
gsk_gpu_convert_encode_variation (GdkColorState *source,
gboolean source_premultiplied,
GdkColorState *target,
gboolean target_premultiplied,
gboolean opacity)
{
guint conversion;
if (source == target)
{
if (source_premultiplied == target_premultiplied)
{
/* no changes should be caught before running a shader */
g_assert (opacity);
if (source_premultiplied)
conversion = VARIATION_ALPHA_ALL_CHANNELS;
else
conversion = 0;
}
else
{
if (source_premultiplied)
conversion = VARIATION_SOURCE_UNPREMULTIPLY;
else
conversion = VARIATION_TARGET_PREMULTIPLY;
}
}
else
{
conversion = GDK_DEFAULT_COLOR_STATE_ID (source) << VARIATION_SOURCE_SHIFT;
conversion |= GDK_DEFAULT_COLOR_STATE_ID (target) << VARIATION_TARGET_SHIFT;
if (source_premultiplied)
conversion |= VARIATION_SOURCE_UNPREMULTIPLY;
if (target_premultiplied)
conversion |= VARIATION_TARGET_PREMULTIPLY;
}
if (opacity)
conversion |= VARIATION_OPACITY;
return conversion;
}
static void static void
gsk_gpu_convert_op_print_instance (GskGpuShaderOp *shader, gsk_gpu_convert_op_print_instance (GskGpuShaderOp *shader,
gpointer instance_, gpointer instance_,
GString *string) GString *string)
{ {
GskGpuConvertInstance *instance = (GskGpuConvertInstance *) instance_; GskGpuConvertInstance *instance = (GskGpuConvertInstance *) instance_;
GdkColorState *source, *target;
source = gdk_color_state_get_by_id ((shader->variation >> VARIATION_SOURCE_SHIFT) & VARIATION_COLOR_STATE_MASK);
target = gdk_color_state_get_by_id ((shader->variation >> VARIATION_TARGET_SHIFT) & VARIATION_COLOR_STATE_MASK);
gsk_gpu_print_rect (string, instance->rect); gsk_gpu_print_rect (string, instance->rect);
gsk_gpu_print_image_descriptor (string, shader->desc, instance->tex_id); gsk_gpu_print_image_descriptor (string, shader->desc, instance->tex_id);
g_string_append_printf (string, "%s%s -> %s%s ", if (shader->variation & VARIATION_STRAIGHT_ALPHA)
gdk_color_state_get_name (source), gsk_gpu_print_string (string, "straight");
(shader->variation & VARIATION_SOURCE_UNPREMULTIPLY) ? "(p)" : "",
gdk_color_state_get_name (target),
(shader->variation & VARIATION_TARGET_PREMULTIPLY) ? "(p)" : "");
} }
static const GskGpuShaderOpClass GSK_GPU_CONVERT_OP_CLASS = { static const GskGpuShaderOpClass GSK_GPU_CONVERT_OP_CLASS = {
@ -111,30 +56,22 @@ static const GskGpuShaderOpClass GSK_GPU_CONVERT_OP_CLASS = {
void void
gsk_gpu_convert_op (GskGpuFrame *frame, gsk_gpu_convert_op (GskGpuFrame *frame,
GskGpuShaderClip clip, GskGpuShaderClip clip,
GdkColorState *source, GskGpuColorStates color_states,
gboolean source_premultiplied,
GdkColorState *target,
gboolean target_premultiplied,
float opacity, float opacity,
GskGpuDescriptors *desc, GskGpuDescriptors *desc,
guint32 descriptor, guint32 descriptor,
gboolean straight_alpha,
const graphene_rect_t *rect, const graphene_rect_t *rect,
const graphene_point_t *offset, const graphene_point_t *offset,
const graphene_rect_t *tex_rect) const graphene_rect_t *tex_rect)
{ {
GskGpuConvertInstance *instance; GskGpuConvertInstance *instance;
guint variation;
variation = gsk_gpu_convert_encode_variation (source,
source_premultiplied,
target,
target_premultiplied,
opacity < 1.0);
gsk_gpu_shader_op_alloc (frame, gsk_gpu_shader_op_alloc (frame,
&GSK_GPU_CONVERT_OP_CLASS, &GSK_GPU_CONVERT_OP_CLASS,
DEFAULT_COLOR_STATES, color_states,
variation, (opacity < 1.0 ? VARIATION_OPACITY : 0) |
(straight_alpha ? VARIATION_STRAIGHT_ALPHA : 0),
clip, clip,
desc, desc,
&instance); &instance);

View File

@ -8,13 +8,11 @@ G_BEGIN_DECLS
void gsk_gpu_convert_op (GskGpuFrame *frame, void gsk_gpu_convert_op (GskGpuFrame *frame,
GskGpuShaderClip clip, GskGpuShaderClip clip,
GdkColorState *from, GskGpuColorStates color_states,
gboolean from_premultiplied,
GdkColorState *to,
gboolean to_premultiplied,
float opacity, float opacity,
GskGpuDescriptors *desc, GskGpuDescriptors *desc,
guint32 descriptor, guint32 descriptor,
gboolean straight_alpha,
const graphene_rect_t *rect, const graphene_rect_t *rect,
const graphene_point_t *offset, const graphene_point_t *offset,
const graphene_rect_t *tex_rect); const graphene_rect_t *tex_rect);

View File

@ -247,6 +247,14 @@ gsk_gpu_node_processor_sync_globals (GskGpuNodeProcessor *self,
gsk_gpu_node_processor_emit_blend_op (self); gsk_gpu_node_processor_emit_blend_op (self);
} }
static inline GskGpuColorStates
gsk_gpu_node_processor_color_states_self (GskGpuNodeProcessor *self)
{
return gsk_gpu_color_states_create (self->ccs,
TRUE,
self->ccs,
TRUE);
}
static guint32 static guint32
gsk_gpu_node_processor_add_image (GskGpuNodeProcessor *self, gsk_gpu_node_processor_add_image (GskGpuNodeProcessor *self,
GskGpuImage *image, GskGpuImage *image,
@ -559,22 +567,22 @@ gsk_gpu_node_processor_image_op (GskGpuNodeProcessor *self,
const graphene_rect_t *tex_rect) const graphene_rect_t *tex_rect)
{ {
guint32 descriptor; guint32 descriptor;
gboolean straight_alpha;
g_assert (self->pending_globals == 0); g_assert (self->pending_globals == 0);
descriptor = gsk_gpu_node_processor_add_image (self, image, GSK_GPU_SAMPLER_DEFAULT); descriptor = gsk_gpu_node_processor_add_image (self, image, GSK_GPU_SAMPLER_DEFAULT);
straight_alpha = gsk_gpu_image_get_flags (image) & GSK_GPU_IMAGE_STRAIGHT_ALPHA;
if (gsk_gpu_image_get_flags (image) & GSK_GPU_IMAGE_STRAIGHT_ALPHA) if (straight_alpha)
{ {
gsk_gpu_convert_op (self->frame, gsk_gpu_convert_op (self->frame,
gsk_gpu_clip_get_shader_clip (&self->clip, &self->offset, rect), gsk_gpu_clip_get_shader_clip (&self->clip, &self->offset, rect),
GDK_COLOR_STATE_SRGB, gsk_gpu_node_processor_color_states_self (self),
FALSE,
GDK_COLOR_STATE_SRGB,
TRUE,
self->opacity, self->opacity,
self->desc, self->desc,
descriptor, descriptor,
straight_alpha,
rect, rect,
&self->offset, &self->offset,
tex_rect); tex_rect);

View File

@ -1,74 +1,10 @@
#include "common.glsl" #include "common.glsl"
#define VARIATION_OPACITY (1u << 0) #define VARIATION_OPACITY (1u << 0)
#define VARIATION_ALPHA_ALL_CHANNELS (1u << 1) #define VARIATION_STRAIGHT_ALPHA (1u << 1)
#define VARIATION_SOURCE_UNPREMULTIPLY (1u << 2)
#define VARIATION_TARGET_PREMULTIPLY (1u << 3)
#define VARIATION_SOURCE_SHIFT 8u
#define VARIATION_TARGET_SHIFT 16u
#define VARIATION_COLOR_STATE_MASK 0xFFu
#define HAS_VARIATION(var) ((GSK_VARIATION & var) == var) #define HAS_VARIATION(var) ((GSK_VARIATION & var) == var)
#define SOURCE_COLOR_STATE ((GSK_VARIATION >> VARIATION_SOURCE_SHIFT) & VARIATION_COLOR_STATE_MASK)
#define TARGET_COLOR_STATE ((GSK_VARIATION >> VARIATION_TARGET_SHIFT) & VARIATION_COLOR_STATE_MASK)
vec4
srgb_to_linear_srgb (vec4 color)
{
return vec4 (srgb_eotf (color.r),
srgb_eotf (color.g),
srgb_eotf (color.b),
color.a);
}
vec4
linear_srgb_to_srgb (vec4 color)
{
return vec4 (srgb_oetf (color.r),
srgb_oetf (color.g),
srgb_oetf (color.b),
color.a);
}
#define PAIR(_from_cs, _to_cs) ((_from_cs) << 16 | (_to_cs))
bool
do_conversion (vec4 color,
uint from_cs,
uint to_cs,
out vec4 result)
{
switch (PAIR (from_cs, to_cs))
{
case PAIR (GDK_COLOR_STATE_ID_SRGB, GDK_COLOR_STATE_ID_SRGB_LINEAR):
result = srgb_to_linear_srgb (color);
break;
case PAIR (GDK_COLOR_STATE_ID_SRGB_LINEAR, GDK_COLOR_STATE_ID_SRGB):
result = linear_srgb_to_srgb (color);
break;
default:
return false;
}
return true;
}
vec4
color_convert (vec4 color)
{
vec4 result;
if (SOURCE_COLOR_STATE == TARGET_COLOR_STATE)
return color;
if (!do_conversion (color, SOURCE_COLOR_STATE, TARGET_COLOR_STATE, result))
result = vec4 (1.0, 0.0, 0.8, 1.0);
return result;
}
PASS(0) vec2 _pos; PASS(0) vec2 _pos;
PASS_FLAT(1) Rect _rect; PASS_FLAT(1) Rect _rect;
PASS(2) vec2 _tex_coord; PASS(2) vec2 _tex_coord;
@ -106,26 +42,19 @@ void
run (out vec4 color, run (out vec4 color,
out vec2 position) out vec2 position)
{ {
vec4 pixel = gsk_texture (_tex_id, _tex_coord); vec4 pixel;
if (HAS_VARIATION (VARIATION_STRAIGHT_ALPHA))
pixel = gsk_texture_straight_alpha (_tex_id, _tex_coord);
else
pixel = gsk_texture (_tex_id, _tex_coord);
if (HAS_VARIATION (VARIATION_SOURCE_UNPREMULTIPLY)) pixel = output_color_from_alt (pixel);
pixel = color_unpremultiply (pixel);
pixel = color_convert (pixel);
float alpha = rect_coverage (_rect, _pos); float alpha = rect_coverage (_rect, _pos);
if (HAS_VARIATION (VARIATION_OPACITY)) if (HAS_VARIATION (VARIATION_OPACITY))
alpha *= _opacity; alpha *= _opacity;
if (HAS_VARIATION (VARIATION_ALPHA_ALL_CHANNELS)) color = output_color_alpha (pixel, alpha);
pixel *= alpha;
else
pixel.a *= alpha;
if (HAS_VARIATION (VARIATION_TARGET_PREMULTIPLY))
color = color_premultiply (pixel);
else
color = pixel;
position = _pos; position = _pos;
} }