[gtk/matthiasc/color-profile-rebased: 30/51] gsk: Apply gamma to frames




commit 7e91c156fec5a7f4812625e5155fab8690c9dd1e
Author: Matthias Clasen <mclasen redhat com>
Date:   Sun May 8 13:17:31 2022 -0400

    gsk: Apply gamma to frames
    
    Use a shader to go from linear sRGB to sRGB when
    we are done with a frame.

 gsk/gl/gskglprograms.defs            |  5 +++++
 gsk/gl/gskglrenderjob.c              | 31 ++++++++++++++++++++++++++++++-
 gsk/gl/resources/postprocessing.glsl | 22 ++++++++++++++++++++++
 gsk/gl/resources/preamble.glsl       | 20 ++++++++++++++++++++
 gsk/meson.build                      |  1 +
 5 files changed, 78 insertions(+), 1 deletion(-)
---
diff --git a/gsk/gl/gskglprograms.defs b/gsk/gl/gskglprograms.defs
index 1ff99fab89..db85f77cc2 100644
--- a/gsk/gl/gskglprograms.defs
+++ b/gsk/gl/gskglprograms.defs
@@ -82,3 +82,8 @@ GSK_GL_DEFINE_PROGRAM (unblurred_outset_shadow,
                        GSK_GL_ADD_UNIFORM (1, UNBLURRED_OUTSET_SHADOW_SPREAD, u_spread)
                        GSK_GL_ADD_UNIFORM (2, UNBLURRED_OUTSET_SHADOW_OFFSET, u_offset)
                        GSK_GL_ADD_UNIFORM (3, UNBLURRED_OUTSET_SHADOW_OUTLINE_RECT, u_outline_rect))
+
+GSK_GL_DEFINE_PROGRAM (postprocessing,
+                       GSK_GL_SHADER_SINGLE (GSK_GL_SHADER_RESOURCE ("postprocessing.glsl")),
+                       GSK_GL_NO_UNIFORMS)
+
diff --git a/gsk/gl/gskglrenderjob.c b/gsk/gl/gskglrenderjob.c
index 699a809d81..5cfa7863ba 100644
--- a/gsk/gl/gskglrenderjob.c
+++ b/gsk/gl/gskglrenderjob.c
@@ -4053,6 +4053,21 @@ gsk_gl_render_job_render_flipped (GskGLRenderJob *job,
   glDeleteTextures (1, &texture_id);
 }
 
+static void
+gsk_gl_render_job_postprocess (GskGLRenderJob *job,
+                               guint           texture_id)
+{
+  gsk_gl_command_queue_bind_framebuffer (job->command_queue, job->framebuffer);
+  gsk_gl_command_queue_clear (job->command_queue, 0, &job->viewport);
+
+  gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, postprocessing));
+  gsk_gl_program_set_uniform_texture (job->current_program,
+                                      UNIFORM_SHARED_SOURCE, 0,
+                                      GL_TEXTURE_2D, GL_TEXTURE0, texture_id);
+  gsk_gl_render_job_draw_offscreen_rect (job, &job->viewport);
+  gsk_gl_render_job_end_draw (job);
+}
+
 void
 gsk_gl_render_job_render (GskGLRenderJob *job,
                           GskRenderNode  *root)
@@ -4060,6 +4075,8 @@ gsk_gl_render_job_render (GskGLRenderJob *job,
   G_GNUC_UNUSED gint64 start_time;
   guint scale_factor;
   guint surface_height;
+  GskGLRenderTarget *render_target;
+  guint texture_id;
 
   g_return_if_fail (job != NULL);
   g_return_if_fail (root != NULL);
@@ -4070,16 +4087,28 @@ gsk_gl_render_job_render (GskGLRenderJob *job,
 
   gsk_gl_command_queue_make_current (job->command_queue);
 
+  if (!gsk_gl_driver_create_render_target (job->driver,
+                                           job->viewport.size.width,
+                                           job->viewport.size.height,
+                                           job->target_format,
+                                           GL_NEAREST, GL_NEAREST,
+                                           &render_target))
+    g_assert_not_reached ();
+
   /* Build the command queue using the shared GL context for all renderers
    * on the same display.
    */
   start_time = GDK_PROFILER_CURRENT_TIME;
   gdk_gl_context_push_debug_group (job->command_queue->context, "Building command queue");
-  gsk_gl_command_queue_bind_framebuffer (job->command_queue, job->framebuffer);
+  gsk_gl_command_queue_bind_framebuffer (job->command_queue, render_target->framebuffer_id);
   if (job->clear_framebuffer)
     gsk_gl_command_queue_clear (job->command_queue, 0, &job->viewport);
   gsk_gl_render_job_visit_node (job, root);
   gdk_gl_context_pop_debug_group (job->command_queue->context);
+
+  texture_id = gsk_gl_driver_release_render_target (job->driver, render_target, FALSE);
+  gsk_gl_render_job_postprocess (job, texture_id);
+
   gdk_profiler_add_mark (start_time, GDK_PROFILER_CURRENT_TIME-start_time, "Build GL command queue", "");
 
 #if 0
diff --git a/gsk/gl/resources/postprocessing.glsl b/gsk/gl/resources/postprocessing.glsl
new file mode 100644
index 0000000000..c381beccef
--- /dev/null
+++ b/gsk/gl/resources/postprocessing.glsl
@@ -0,0 +1,22 @@
+
+// VERTEX_SHADER:
+// postprocessing.glsl
+
+void main() {
+  gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
+
+  vUv = vec2(aUv.x, aUv.y);
+}
+
+// FRAGMENT_SHADER:
+// postprocessing.glsl
+
+void main() {
+  vec4 diffuse = GskTexture(u_source, vUv);
+
+  diffuse = gsk_unpremultiply(diffuse);
+  diffuse = gsk_linear_to_srgb(diffuse);
+  diffuse = gsk_premultiply(diffuse);
+
+  gskSetOutputColor(diffuse);
+}
diff --git a/gsk/gl/resources/preamble.glsl b/gsk/gl/resources/preamble.glsl
index 5f5d2b780a..68a89552e9 100644
--- a/gsk/gl/resources/preamble.glsl
+++ b/gsk/gl/resources/preamble.glsl
@@ -46,6 +46,26 @@ vec4 gsk_premultiply(vec4 c) {
   return vec4(c.rgb * c.a, c.a);
 }
 
+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(2.2));
+  return vec4(linear_rgb, srgb.a);
+}
+
+vec4 gsk_linear_to_srgb(vec4 linear_rgba)
+{
+  vec3 srgb = pow(linear_rgba.rgb , vec3(1/2.2));
+  return vec4(srgb, linear_rgba.a);
+}
+
 vec4 gsk_scaled_premultiply(vec4 c, float s) {
   // Fast version of gsk_premultiply(c) * s
   // 4 muls instead of 7
diff --git a/gsk/meson.build b/gsk/meson.build
index 02e9c58954..2e7fa1a3be 100644
--- a/gsk/meson.build
+++ b/gsk/meson.build
@@ -19,6 +19,7 @@ gsk_private_gl_shaders = [
   'gl/resources/repeat.glsl',
   'gl/resources/custom.glsl',
   'gl/resources/filled_border.glsl',
+  'gl/resources/postprocessing.glsl',
 ]
 
 gsk_public_sources = files([


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]