diff --git a/gsk/gpu/gskgpucolorconvertop.c b/gsk/gpu/gskgpucolorconvertop.c new file mode 100644 index 0000000000..77c82f7878 --- /dev/null +++ b/gsk/gpu/gskgpucolorconvertop.c @@ -0,0 +1,86 @@ +#include "config.h" + +#include "gskgpucolorconvertopprivate.h" + +#include "gskgpuframeprivate.h" +#include "gskgpuprintprivate.h" +#include "gskrectprivate.h" +#include "gdk/gdkcolorstateprivate.h" + +#include "gpu/shaders/gskgpucolorconvertinstance.h" + +typedef struct _GskGpuColorConvertOp GskGpuColorConvertOp; + +struct _GskGpuColorConvertOp +{ + GskGpuShaderOp op; +}; + +static guint +gsk_gpu_color_conversion (GdkColorState *from, + GdkColorState *to) +{ + if (from == to) + return 0; + + return GDK_DEFAULT_COLOR_STATE_ID (from) | (GDK_DEFAULT_COLOR_STATE_ID (to) << 16); +} + +static void +gsk_gpu_color_convert_op_print_instance (GskGpuShaderOp *shader, + gpointer instance_, + GString *string) +{ + GskGpuColorconvertInstance *instance = (GskGpuColorconvertInstance *) instance_; + + gsk_gpu_print_rect (string, instance->rect); + gsk_gpu_print_image_descriptor (string, shader->desc, instance->tex_id); + gsk_gpu_print_color_conversion (string, shader->variation); +} + +static const GskGpuShaderOpClass GSK_GPU_COLOR_CONVERT_OP_CLASS = { + { + GSK_GPU_OP_SIZE (GskGpuColorConvertOp), + 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 + }, + "gskgpucolorconvert", + sizeof (GskGpuColorconvertInstance), +#ifdef GDK_RENDERING_VULKAN + &gsk_gpu_colorconvert_info, +#endif + gsk_gpu_color_convert_op_print_instance, + gsk_gpu_colorconvert_setup_attrib_locations, + gsk_gpu_colorconvert_setup_vao +}; + +void +gsk_gpu_color_convert_op (GskGpuFrame *frame, + GskGpuShaderClip clip, + GdkColorState *from, + GdkColorState *to, + GskGpuDescriptors *desc, + guint32 descriptor, + const graphene_rect_t *rect, + const graphene_point_t *offset, + const graphene_rect_t *tex_rect) +{ + GskGpuColorconvertInstance *instance; + + gsk_gpu_shader_op_alloc (frame, + &GSK_GPU_COLOR_CONVERT_OP_CLASS, + gsk_gpu_color_conversion (from, to), + 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; +} + diff --git a/gsk/gpu/gskgpucolorconvertopprivate.h b/gsk/gpu/gskgpucolorconvertopprivate.h new file mode 100644 index 0000000000..71e83927d3 --- /dev/null +++ b/gsk/gpu/gskgpucolorconvertopprivate.h @@ -0,0 +1,21 @@ +#pragma once + +#include "gskgpushaderopprivate.h" + +#include + +G_BEGIN_DECLS + +void gsk_gpu_color_convert_op (GskGpuFrame *frame, + GskGpuShaderClip clip, + GdkColorState *from, + GdkColorState *to, + GskGpuDescriptors *desc, + guint32 descriptor, + const graphene_rect_t *rect, + const graphene_point_t *offset, + const graphene_rect_t *tex_rect); + + +G_END_DECLS + diff --git a/gsk/gpu/gskgpuprint.c b/gsk/gpu/gskgpuprint.c index 7fa9df3dcb..eb6241a85d 100644 --- a/gsk/gpu/gskgpuprint.c +++ b/gsk/gpu/gskgpuprint.c @@ -2,6 +2,8 @@ #include "gskgpuprintprivate.h" +#include "gdk/gdkrgbaprivate.h" +#include "gdk/gdkcolorstateprivate.h" #include "gskgpudescriptorsprivate.h" #include "gskgpuimageprivate.h" @@ -155,3 +157,11 @@ gsk_gpu_print_image_descriptor (GString *string, gsk_gpu_print_image (string, gsk_gpu_descriptors_get_image (desc, id)); } +void +gsk_gpu_print_color_conversion (GString *string, + guint conversion) +{ + g_string_append_printf (string, "%s->%s ", + gdk_color_state_get_name_from_id (conversion & 0xffff), + gdk_color_state_get_name_from_id (conversion >> 16)); +} diff --git a/gsk/gpu/gskgpuprintprivate.h b/gsk/gpu/gskgpuprintprivate.h index e9ee57e4cb..770fa40f75 100644 --- a/gsk/gpu/gskgpuprintprivate.h +++ b/gsk/gpu/gskgpuprintprivate.h @@ -35,3 +35,5 @@ void gsk_gpu_print_image (GString void gsk_gpu_print_image_descriptor (GString *string, GskGpuDescriptors *desc, guint32 descriptor); +void gsk_gpu_print_color_conversion (GString *string, + guint conversion); diff --git a/gsk/gpu/shaders/color.glsl b/gsk/gpu/shaders/color.glsl index 3f18784593..521ea5995d 100644 --- a/gsk/gpu/shaders/color.glsl +++ b/gsk/gpu/shaders/color.glsl @@ -19,4 +19,4 @@ luminance (vec3 color) return dot (vec3 (0.2126, 0.7152, 0.0722), color); } -#endif /* _COLOR_ */ +#endif diff --git a/gsk/gpu/shaders/gskgpucolorconvert.glsl b/gsk/gpu/shaders/gskgpucolorconvert.glsl new file mode 100644 index 0000000000..aba40e67ef --- /dev/null +++ b/gsk/gpu/shaders/gskgpucolorconvert.glsl @@ -0,0 +1,116 @@ +#include "common.glsl" + +PASS(0) vec2 _pos; +PASS_FLAT(1) Rect _rect; +PASS(2) vec2 _tex_coord; +PASS_FLAT(3) uint _tex_id; + +#ifdef GSK_VERTEX_SHADER + +IN(0) vec4 in_rect; +IN(1) vec4 in_tex_rect; +IN(2) uint in_tex_id; + +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; +} + +#endif + + + +#ifdef GSK_FRAGMENT_SHADER + +float +srgb_transfer_function (float v) +{ + if (v >= 0.04045) + return pow (((v + 0.055)/(1.0 + 0.055)), 2.4); + else + return v / 12.92; +} + +float +srgb_inverse_transfer_function (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_transfer_function (color.r), + srgb_transfer_function (color.g), + srgb_transfer_function (color.b), + color.a); +} + +vec4 +linear_srgb_to_srgb (vec4 color) +{ + return vec4 (srgb_inverse_transfer_function (color.r), + srgb_inverse_transfer_function (color.g), + srgb_inverse_transfer_function (color.b), + color.a); +} + +#define RGB 0u +#define LINRGB 1u + +#define pair(u,v) ((u)|((v) << 16)) +#define first(p) ((p) & 0xffffu) +#define second(p) ((p) >> 16) + +bool +do_conversion (in vec4 color, in uint f, out vec4 result) +{ + switch (f) + { + case pair (RGB, LINRGB): result = srgb_to_linear_srgb (color); break; + case pair (LINRGB, RGB): result = linear_srgb_to_srgb (color); break; + + default: return false; + } + + return true; +} + +vec4 +color_convert (in vec4 color, in uint f) +{ + vec4 result; + + if (f == 0u) + return color; + + do_conversion (color, f, result); + + return result; +} + +void +run (out vec4 color, + out vec2 position) +{ + vec4 pixel = gsk_texture (_tex_id, _tex_coord); + + pixel = color_unpremultiply (pixel); + pixel = color_convert (pixel, GSK_VARIATION); + + color = color_premultiply (pixel) * rect_coverage (_rect, _pos); + position = _pos; +} + +#endif diff --git a/gsk/gpu/shaders/meson.build b/gsk/gpu/shaders/meson.build index c27144cf61..c51400ff84 100644 --- a/gsk/gpu/shaders/meson.build +++ b/gsk/gpu/shaders/meson.build @@ -18,6 +18,7 @@ gsk_private_gpu_shaders = files([ 'gskgpuborder.glsl', 'gskgpuboxshadow.glsl', 'gskgpucolor.glsl', + 'gskgpucolorconvert.glsl', 'gskgpucolorize.glsl', 'gskgpucolormatrix.glsl', 'gskgpuconicgradient.glsl', diff --git a/gsk/meson.build b/gsk/meson.build index b30a7ec9f8..5023cde38e 100644 --- a/gsk/meson.build +++ b/gsk/meson.build @@ -105,6 +105,7 @@ gsk_private_sources = files([ 'gpu/gskgpushaderop.c', 'gpu/gskgpuscissorop.c', 'gpu/gskgpustraightalphaop.c', + 'gpu/gskgpucolorconvertop.c', 'gpu/gskgputextureop.c', 'gpu/gskgpuuberop.c', 'gpu/gskgpuuploadop.c',