[mutter/gnome-3-36] background: Limit mipmap levels to avoid loss of visible detail



commit 7e1d0ebd47d463ef1ab0c1b3957ad3cf911bd2d7
Author: Daniel van Vugt <daniel van vugt canonical com>
Date:   Mon Feb 10 17:07:48 2020 +0800

    background: Limit mipmap levels to avoid loss of visible detail
    
    When the wallpaper image is larger than the monitor resolution we already
    use mipmapping to scale it down smoothly in hardware. We use
    `GL_TEXTURE_MIN_FILTER` = `GL_LINEAR_MIPMAP_LINEAR` for the highest quality
    scaling that GL can do. However that option is designed for 3D use cases
    where the mipmap level is changing over time or space.
    
    Since our wallpaper is not changing distance from us we can improve the
    rendering quality even more than `GL_LINEAR_MIPMAP_LINEAR`. To do this we
    now set `GL_TEXTURE_MAX_LEVEL` (if available) to limit the mipmap level or
    blurriness level to the lowest resolution (highest level) that is still
    equal to or higher than the monitor itself. This way we get the benefits
    of mipmapping (downscaling in hardware) *and* retain the maximum possible
    sharpness for the monitor resolution -- something that
    `GL_LINEAR_MIPMAP_LINEAR` alone doesn't do.
    
    Example:
    
      Monitor is 1920x1080
      Wallpaper photo is 4000x3000
      Mipmaps stored on the GPU are 4000x3000, 2000x1500, 1000x750, ...
    
      Before: You would see an average of the 2000x1500 and 1000x750 images.
      After:  You will now only see the 2000x1500 image, linearly sampled.
    
    https://gitlab.gnome.org/GNOME/mutter/merge_requests/1003
    
    (cherry picked from commit 7a0bc5af7f4f25c84df9e65b2a86b83f33074933)

 src/compositor/meta-background.c | 33 +++++++++++++++++++++++++++++++++
 1 file changed, 33 insertions(+)
---
diff --git a/src/compositor/meta-background.c b/src/compositor/meta-background.c
index 30be332616..4927ae6384 100644
--- a/src/compositor/meta-background.c
+++ b/src/compositor/meta-background.c
@@ -747,6 +747,25 @@ get_wrap_mode (GDesktopBackgroundStyle style)
     }
 }
 
+static int
+get_best_mipmap_level (CoglTexture *texture,
+                       int          visible_width,
+                       int          visible_height)
+{
+  int mipmap_width = cogl_texture_get_width (texture);
+  int mipmap_height = cogl_texture_get_height (texture);
+  int halves = 0;
+
+  while (mipmap_width >= visible_width && mipmap_height >= visible_height)
+    {
+      halves++;
+      mipmap_width /= 2;
+      mipmap_height /= 2;
+    }
+
+  return MAX (0, halves - 1);
+}
+
 CoglTexture *
 meta_background_get_texture (MetaBackground         *self,
                              int                     monitor_index,
@@ -854,10 +873,17 @@ meta_background_get_texture (MetaBackground         *self,
       if (texture2 != NULL && self->blend_factor != 0.0)
         {
           CoglPipeline *pipeline = create_pipeline (PIPELINE_REPLACE);
+          int mipmap_level;
+
+          mipmap_level = get_best_mipmap_level (texture2,
+                                                texture_width,
+                                                texture_height);
+
           cogl_pipeline_set_color4f (pipeline,
                                       self->blend_factor, self->blend_factor, self->blend_factor, 
self->blend_factor);
           cogl_pipeline_set_layer_texture (pipeline, 0, texture2);
           cogl_pipeline_set_layer_wrap_mode (pipeline, 0, get_wrap_mode (self->style));
+          cogl_pipeline_set_layer_max_mipmap_level (pipeline, 0, mipmap_level);
 
           bare_region_visible = draw_texture (self,
                                               monitor->fbo, pipeline,
@@ -876,6 +902,12 @@ meta_background_get_texture (MetaBackground         *self,
       if (texture1 != NULL && self->blend_factor != 1.0)
         {
           CoglPipeline *pipeline = create_pipeline (PIPELINE_ADD);
+          int mipmap_level;
+
+          mipmap_level = get_best_mipmap_level (texture1,
+                                                texture_width,
+                                                texture_height);
+
           cogl_pipeline_set_color4f (pipeline,
                                      (1 - self->blend_factor),
                                      (1 - self->blend_factor),
@@ -883,6 +915,7 @@ meta_background_get_texture (MetaBackground         *self,
                                      (1 - self->blend_factor));;
           cogl_pipeline_set_layer_texture (pipeline, 0, texture1);
           cogl_pipeline_set_layer_wrap_mode (pipeline, 0, get_wrap_mode (self->style));
+          cogl_pipeline_set_layer_max_mipmap_level (pipeline, 0, mipmap_level);
 
           bare_region_visible = bare_region_visible || draw_texture (self,
                                                                      monitor->fbo, pipeline,


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