mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-11-10 02:40:11 +00:00
gpu: Add a color convert shader
This shader converts between two color states, by using the same functions that we use on the cpu. The conversion to perform is passed as part of the variation. As premultiplication is part of color states on the shader, we also encode the premultiplication in the shader. And because opacity is a useful optimization, we also allow setting opacity. For now, the only possible color states are srgb and srgb-linear.
This commit is contained in:
parent
4fa6f791f4
commit
a78796f22c
@ -81,6 +81,12 @@ gdk_color_state_get_depth (GdkColorState *self)
|
||||
return self->depth;
|
||||
}
|
||||
|
||||
static inline GdkColorState *
|
||||
gdk_color_state_get_by_id (GdkColorStateId id)
|
||||
{
|
||||
return (GdkColorState *) &gdk_default_color_states[id];
|
||||
}
|
||||
|
||||
#define gdk_color_state_ref(self) _gdk_color_state_ref (self)
|
||||
static inline GdkColorState *
|
||||
_gdk_color_state_ref (GdkColorState *self)
|
||||
|
146
gsk/gpu/gskgpuconvertop.c
Normal file
146
gsk/gpu/gskgpuconvertop.c
Normal file
@ -0,0 +1,146 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "gskgpuconvertopprivate.h"
|
||||
|
||||
#include "gskgpuframeprivate.h"
|
||||
#include "gskgpuprintprivate.h"
|
||||
#include "gskrectprivate.h"
|
||||
#include "gdk/gdkcolorstateprivate.h"
|
||||
|
||||
#include "gpu/shaders/gskgpuconvertinstance.h"
|
||||
|
||||
typedef struct _GskGpuConvertOp GskGpuConvertOp;
|
||||
|
||||
struct _GskGpuConvertOp
|
||||
{
|
||||
GskGpuShaderOp op;
|
||||
};
|
||||
|
||||
#define VARIATION_OPACITY (1u << 0)
|
||||
#define VARIATION_ALPHA_ALL_CHANNELS (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
|
||||
gsk_gpu_convert_op_print_instance (GskGpuShaderOp *shader,
|
||||
gpointer instance_,
|
||||
GString *string)
|
||||
{
|
||||
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_image_descriptor (string, shader->desc, instance->tex_id);
|
||||
g_string_append_printf (string, "%s%s -> %s%s ",
|
||||
gdk_color_state_get_name (source),
|
||||
(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 = {
|
||||
{
|
||||
GSK_GPU_OP_SIZE (GskGpuConvertOp),
|
||||
GSK_GPU_STAGE_SHADER,
|
||||
gsk_gpu_shader_op_finish,
|
||||
gsk_gpu_shader_op_print,
|
||||
#ifdef GDK_RENDERING_VULKAN
|
||||
gsk_gpu_shader_op_vk_command,
|
||||
#endif
|
||||
gsk_gpu_shader_op_gl_command
|
||||
},
|
||||
"gskgpuconvert",
|
||||
sizeof (GskGpuConvertInstance),
|
||||
#ifdef GDK_RENDERING_VULKAN
|
||||
&gsk_gpu_convert_info,
|
||||
#endif
|
||||
gsk_gpu_convert_op_print_instance,
|
||||
gsk_gpu_convert_setup_attrib_locations,
|
||||
gsk_gpu_convert_setup_vao
|
||||
};
|
||||
|
||||
void
|
||||
gsk_gpu_convert_op (GskGpuFrame *frame,
|
||||
GskGpuShaderClip clip,
|
||||
GdkColorState *source,
|
||||
gboolean source_premultiplied,
|
||||
GdkColorState *target,
|
||||
gboolean target_premultiplied,
|
||||
float opacity,
|
||||
GskGpuDescriptors *desc,
|
||||
guint32 descriptor,
|
||||
const graphene_rect_t *rect,
|
||||
const graphene_point_t *offset,
|
||||
const graphene_rect_t *tex_rect)
|
||||
{
|
||||
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_CONVERT_OP_CLASS,
|
||||
variation,
|
||||
clip,
|
||||
desc,
|
||||
&instance);
|
||||
|
||||
gsk_gpu_rect_to_float (rect, offset, instance->rect);
|
||||
gsk_gpu_rect_to_float (tex_rect, offset, instance->tex_rect);
|
||||
instance->tex_id = descriptor;
|
||||
instance->opacity = opacity;
|
||||
}
|
||||
|
24
gsk/gpu/gskgpuconvertopprivate.h
Normal file
24
gsk/gpu/gskgpuconvertopprivate.h
Normal file
@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#include "gskgpushaderopprivate.h"
|
||||
|
||||
#include <graphene.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
void gsk_gpu_convert_op (GskGpuFrame *frame,
|
||||
GskGpuShaderClip clip,
|
||||
GdkColorState *from,
|
||||
gboolean from_premultiplied,
|
||||
GdkColorState *to,
|
||||
gboolean to_premultiplied,
|
||||
float opacity,
|
||||
GskGpuDescriptors *desc,
|
||||
guint32 descriptor,
|
||||
const graphene_rect_t *rect,
|
||||
const graphene_point_t *offset,
|
||||
const graphene_rect_t *tex_rect);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
@ -52,6 +52,9 @@
|
||||
#define GSK_MASK_MODE_LUMINANCE 2u
|
||||
#define GSK_MASK_MODE_INVERTED_LUMINANCE 3u
|
||||
|
||||
#define GDK_COLOR_STATE_ID_SRGB 0u
|
||||
#define GDK_COLOR_STATE_ID_SRGB_LINEAR 1u
|
||||
|
||||
#define TOP 0u
|
||||
#define RIGHT 1u
|
||||
#define BOTTOM 2u
|
||||
|
151
gsk/gpu/shaders/gskgpuconvert.glsl
Normal file
151
gsk/gpu/shaders/gskgpuconvert.glsl
Normal file
@ -0,0 +1,151 @@
|
||||
#include "common.glsl"
|
||||
|
||||
#define VARIATION_OPACITY (1u << 0)
|
||||
#define VARIATION_ALPHA_ALL_CHANNELS (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 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)
|
||||
|
||||
float
|
||||
srgb_eotf (float v)
|
||||
{
|
||||
if (v >= 0.04045)
|
||||
return pow (((v + 0.055) / (1.0 + 0.055)), 2.4);
|
||||
else
|
||||
return v / 12.92;
|
||||
}
|
||||
|
||||
float
|
||||
srgb_oetf (float v)
|
||||
{
|
||||
if (v > 0.0031308)
|
||||
return 1.055 * pow (v, 1.0 / 2.4) - 0.055;
|
||||
else
|
||||
return 12.92 * v;
|
||||
}
|
||||
|
||||
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_FLAT(1) Rect _rect;
|
||||
PASS(2) vec2 _tex_coord;
|
||||
PASS_FLAT(3) uint _tex_id;
|
||||
PASS_FLAT(4) float _opacity;
|
||||
|
||||
#ifdef GSK_VERTEX_SHADER
|
||||
|
||||
IN(0) vec4 in_rect;
|
||||
IN(1) vec4 in_tex_rect;
|
||||
IN(2) uint in_tex_id;
|
||||
IN(3) float in_opacity;
|
||||
|
||||
void
|
||||
run (out vec2 pos)
|
||||
{
|
||||
Rect r = rect_from_gsk (in_rect);
|
||||
|
||||
pos = rect_get_position (r);
|
||||
|
||||
_pos = pos;
|
||||
_rect = r;
|
||||
_tex_coord = rect_get_coord (rect_from_gsk (in_tex_rect), pos);
|
||||
_tex_id = in_tex_id;
|
||||
_opacity = in_opacity;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifdef GSK_FRAGMENT_SHADER
|
||||
|
||||
void
|
||||
run (out vec4 color,
|
||||
out vec2 position)
|
||||
{
|
||||
vec4 pixel = gsk_texture (_tex_id, _tex_coord);
|
||||
|
||||
if (HAS_VARIATION (VARIATION_SOURCE_UNPREMULTIPLY))
|
||||
pixel = color_unpremultiply (pixel);
|
||||
|
||||
pixel = color_convert (pixel);
|
||||
|
||||
float alpha = rect_coverage (_rect, _pos);
|
||||
if (HAS_VARIATION (VARIATION_OPACITY))
|
||||
alpha *= _opacity;
|
||||
|
||||
if (HAS_VARIATION (VARIATION_ALPHA_ALL_CHANNELS))
|
||||
pixel *= alpha;
|
||||
else
|
||||
pixel.a *= alpha;
|
||||
|
||||
if (HAS_VARIATION (VARIATION_TARGET_PREMULTIPLY))
|
||||
color = color_premultiply (pixel);
|
||||
else
|
||||
color = pixel;
|
||||
|
||||
position = _pos;
|
||||
}
|
||||
|
||||
#endif
|
@ -19,6 +19,7 @@ gsk_private_gpu_shaders = files([
|
||||
'gskgpucolorize.glsl',
|
||||
'gskgpucolormatrix.glsl',
|
||||
'gskgpuconicgradient.glsl',
|
||||
'gskgpuconvert.glsl',
|
||||
'gskgpucrossfade.glsl',
|
||||
'gskgpulineargradient.glsl',
|
||||
'gskgpumask.glsl',
|
||||
|
@ -88,6 +88,7 @@ gsk_private_sources = files([
|
||||
'gpu/gskgpucolormatrixop.c',
|
||||
'gpu/gskgpucolorop.c',
|
||||
'gpu/gskgpuconicgradientop.c',
|
||||
'gpu/gskgpuconvertop.c',
|
||||
'gpu/gskgpucrossfadeop.c',
|
||||
'gpu/gskgpudescriptors.c',
|
||||
'gpu/gskgpudownloadop.c',
|
||||
|
Loading…
Reference in New Issue
Block a user