[gtk/matthiasc/color-profiles: 3/3] Linearize gl textures
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/matthiasc/color-profiles: 3/3] Linearize gl textures
- Date: Thu, 30 Sep 2021 05:13:38 +0000 (UTC)
commit 5ea7e640e806aed1568bcd31db9a947564f0a342
Author: Matthias Clasen <mclasen redhat com>
Date: Thu Sep 30 01:08:16 2021 -0400
Linearize gl textures
GL textures are typically in non-linear sRGB,
and in that case, we need to linearize them.
gsk/meson.build | 1 +
gsk/ngl/gskngldriver.c | 115 ++++++++++++++++++++++++++++++++++++++-
gsk/ngl/gsknglprograms.defs | 4 ++
gsk/ngl/resources/linearize.glsl | 43 +++++++++++++++
4 files changed, 162 insertions(+), 1 deletion(-)
---
diff --git a/gsk/meson.build b/gsk/meson.build
index eb33866da5..7c1442cfd6 100644
--- a/gsk/meson.build
+++ b/gsk/meson.build
@@ -20,6 +20,7 @@ gsk_private_ngl_shaders = [
'ngl/resources/custom.glsl',
'ngl/resources/filled_border.glsl',
'ngl/resources/postprocessing.glsl',
+ 'ngl/resources/linearize.glsl',
]
gsk_public_sources = files([
diff --git a/gsk/ngl/gskngldriver.c b/gsk/ngl/gskngldriver.c
index 07ac4b3c75..16467c99d7 100644
--- a/gsk/ngl/gskngldriver.c
+++ b/gsk/ngl/gskngldriver.c
@@ -39,6 +39,7 @@
#include "gsknglprogramprivate.h"
#include "gsknglshadowlibraryprivate.h"
#include "gskngltexturepoolprivate.h"
+#include "fp16private.h"
#define ATLAS_SIZE 512
#define MAX_OLD_RATIO 0.5
@@ -705,6 +706,74 @@ gsk_ngl_driver_cache_texture (GskNglDriver *self,
g_hash_table_insert (self->texture_id_to_key, GUINT_TO_POINTER (texture_id), k);
}
+static void
+draw_offscreen (GskNglCommandQueue *command_queue,
+ float min_x,
+ float min_y,
+ float max_x,
+ float max_y)
+{
+ GskNglDrawVertex *vertices = gsk_ngl_command_queue_add_vertices (command_queue);
+ float min_u = 0;
+ float min_v = 1;
+ float max_u = 1;
+ float max_v = 0;
+ guint16 c[4] = { FP16_ZERO, FP16_ZERO, FP16_ZERO, FP16_ZERO };
+
+ vertices[0] = (GskNglDrawVertex) { .position = { min_x, min_y }, .uv = { min_u, min_v }, .color = { c[0],
c[1], c[2], c[3] } };
+ vertices[1] = (GskNglDrawVertex) { .position = { min_x, max_y }, .uv = { min_u, max_v }, .color = { c[0],
c[1], c[2], c[3] } };
+ vertices[2] = (GskNglDrawVertex) { .position = { max_x, min_y }, .uv = { max_u, min_v }, .color = { c[0],
c[1], c[2], c[3] } };
+ vertices[3] = (GskNglDrawVertex) { .position = { max_x, max_y }, .uv = { max_u, max_v }, .color = { c[0],
c[1], c[2], c[3] } };
+ vertices[4] = (GskNglDrawVertex) { .position = { min_x, max_y }, .uv = { min_u, max_v }, .color = { c[0],
c[1], c[2], c[3] } };
+ vertices[5] = (GskNglDrawVertex) { .position = { max_x, min_y }, .uv = { max_u, min_v }, .color = { c[0],
c[1], c[2], c[3] } };
+}
+
+static void
+set_viewport_for_size (GskNglProgram *program,
+ float width,
+ float height)
+{
+ float viewport[4] = { 0, 0, width, height };
+
+ gsk_ngl_uniform_state_set4fv (program->uniforms,
+ program->program_info,
+ UNIFORM_SHARED_VIEWPORT, 0,
+ 1,
+ (const float *)&viewport);
+}
+
+#define ORTHO_NEAR_PLANE -10000
+#define ORTHO_FAR_PLANE 10000
+
+static void
+set_projection_for_size (GskNglProgram *program,
+ float width,
+ float height)
+{
+ graphene_matrix_t projection;
+
+ graphene_matrix_init_ortho (&projection, 0, width, 0, height, ORTHO_NEAR_PLANE, ORTHO_FAR_PLANE);
+ graphene_matrix_scale (&projection, 1, -1, 1);
+
+ gsk_ngl_uniform_state_set_matrix (program->uniforms,
+ program->program_info,
+ UNIFORM_SHARED_PROJECTION, 0,
+ &projection);
+}
+
+static void
+reset_modelview (GskNglProgram *program)
+{
+ graphene_matrix_t modelview;
+
+ graphene_matrix_init_identity (&modelview);
+
+ gsk_ngl_uniform_state_set_matrix (program->uniforms,
+ program->program_info,
+ UNIFORM_SHARED_MODELVIEW, 0,
+ &modelview);
+}
+
/**
* gsk_ngl_driver_load_texture:
* @self: a `GdkTexture`
@@ -754,8 +823,52 @@ gsk_ngl_driver_load_texture (GskNglDriver *self,
if (gdk_gl_context_is_shared (context, texture_context))
{
+ guint gl_texture_id;
+
+ gl_texture_id = gdk_gl_texture_get_id (gl_texture);
+
/* A GL texture from the same GL context is a simple task... */
- return gdk_gl_texture_get_id (gl_texture);
+ if (gdk_color_profile_is_linear (gdk_texture_get_color_profile (texture)))
+ {
+ return gl_texture_id;
+ }
+ else
+ {
+ GskNglRenderTarget *target;
+ guint prev_fbo;
+
+ gdk_gl_context_make_current (context);
+
+ width = gdk_texture_get_width (texture);
+ height = gdk_texture_get_height (texture);
+
+ gsk_ngl_driver_create_render_target (self,
+ width, height,
+ min_filter, mag_filter,
+ &target);
+
+ prev_fbo = gsk_ngl_command_queue_bind_framebuffer (self->command_queue,
target->framebuffer_id);
+ gsk_ngl_command_queue_clear (self->command_queue, 0, &GRAPHENE_RECT_INIT (0, 0, width,
height));
+
+ gsk_ngl_command_queue_begin_draw (self->command_queue,
+ self->linearize_no_clip->program_info,
+ width, height);
+
+ set_projection_for_size (self->linearize_no_clip, width, height);
+ set_viewport_for_size (self->linearize_no_clip, width, height);
+ reset_modelview (self->linearize_no_clip);
+
+ gsk_ngl_program_set_uniform_texture (self->linearize_no_clip,
+ UNIFORM_SHARED_SOURCE, 0,
+ GL_TEXTURE_2D, GL_TEXTURE0, gl_texture_id);
+ draw_offscreen (self->command_queue, 0, 0, width, height);
+
+ gsk_ngl_command_queue_end_draw (self->command_queue);
+
+ gsk_ngl_command_queue_bind_framebuffer (self->command_queue, prev_fbo);
+
+ return gsk_ngl_driver_release_render_target (self, target, FALSE);
+ }
}
else
{
diff --git a/gsk/ngl/gsknglprograms.defs b/gsk/ngl/gsknglprograms.defs
index 72b383b8fa..1454e56770 100644
--- a/gsk/ngl/gsknglprograms.defs
+++ b/gsk/ngl/gsknglprograms.defs
@@ -86,3 +86,7 @@ GSK_NGL_DEFINE_PROGRAM (unblurred_outset_shadow,
GSK_NGL_DEFINE_PROGRAM (postprocessing,
"/org/gtk/libgsk/ngl/postprocessing.glsl",
GSK_NGL_NO_UNIFORMS)
+
+GSK_NGL_DEFINE_PROGRAM (linearize,
+ "/org/gtk/libgsk/ngl/linearize.glsl",
+ GSK_NGL_NO_UNIFORMS)
diff --git a/gsk/ngl/resources/linearize.glsl b/gsk/ngl/resources/linearize.glsl
new file mode 100644
index 0000000000..73806e156a
--- /dev/null
+++ b/gsk/ngl/resources/linearize.glsl
@@ -0,0 +1,43 @@
+
+// VERTEX_SHADER:
+// linearize.glsl
+
+void main() {
+ gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
+
+ vUv = vec2(aUv.x, aUv.y);
+}
+
+// FRAGMENT_SHADER:
+// linearize.glsl
+
+float u_gamma = 2.2;
+
+vec4 gsk_unpremultiply(vec4 c)
+{
+ if (c.a != 0)
+ return vec4(c.rgb / c.a, c.a);
+ else
+ return c;
+}
+
+vec4 gsk_srgb_to_linear(vec4 srgb)
+{
+ vec3 linear_rgb = pow(srgb.rgb, vec3(u_gamma));
+ return vec4(linear_rgb, srgb.a);
+}
+
+vec4 gsk_linear_to_srgb(vec4 linear_rgba)
+{
+ vec3 srgb = pow(linear_rgba.rgb , vec3(1/u_gamma));
+ return vec4(srgb, linear_rgba.a);
+}
+void main() {
+ vec4 diffuse = GskTexture(u_source, vUv);
+
+ diffuse = gsk_unpremultiply(diffuse);
+ diffuse = gsk_srgb_to_linear(diffuse);
+ diffuse = gsk_premultiply(diffuse);
+
+ gskSetOutputColor(diffuse);
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]