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
This commit is contained in:
parent
c5fbab6bad
commit
7a0bc5af7f
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user