gl-renderer: garbage-collect old shaders
This adds a heuristic for freeing shader programs that have not been needed for a while. The intention is to stop Weston accumulating shader programs indefinitely, especially in the future when color management will explode the number of possible different shader programs. Shader programs that have not been used in the past minute are freed, except always keep the ten most recently used shader programs anyway. The former rule is to ensure we keep shader programs that are actively used regardless of how many. The latter rule is to prevent freeing too many shader programs after Weston has been idle for a long time and then repaints just a small area. Many of the shader programs could still be relevant even though not needed in the first repaint after idle. The numbers ten and one minute in the above are arbitrary and not based on anything. These heuristics are simpler to implement than e.g. views taking references on shader programs. Expiry by time allows shader programs to survive a while even after their last user is gone, with the hope of being re-used soon. Tracking actual use instead of references also adapts to what is actually visible rather than what merely exists. Keeping the shader list in most recently used order might also make gl_renderer_get_program() more efficient on average. last_repaint_start time is used for shader timestamp to avoid calling clock_gettime() more often. Adding that variable is an ABI break, but libweston major has already been bumped to 10 since last release. Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
This commit is contained in:
parent
a8c4dfead5
commit
1ed2cad87e
|
@ -1130,6 +1130,7 @@ struct weston_compositor {
|
|||
|
||||
clockid_t presentation_clock;
|
||||
int32_t repaint_msec;
|
||||
struct timespec last_repaint_start;
|
||||
|
||||
unsigned int activate_serial;
|
||||
|
||||
|
|
|
@ -2919,6 +2919,7 @@ output_repaint_timer_handler(void *data)
|
|||
int ret = 0;
|
||||
|
||||
weston_compositor_read_presentation_clock(compositor, &now);
|
||||
compositor->last_repaint_start = now;
|
||||
|
||||
if (compositor->backend->repaint_begin)
|
||||
repaint_data = compositor->backend->repaint_begin(compositor);
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#define GL_RENDERER_INTERNAL_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <wayland-util.h>
|
||||
#include <GLES2/gl2.h>
|
||||
|
@ -82,6 +83,7 @@ struct gl_shader {
|
|||
GLint alpha_uniform;
|
||||
GLint color_uniform;
|
||||
struct wl_list link; /* gl_renderer::shader_list */
|
||||
struct timespec last_used;
|
||||
};
|
||||
|
||||
struct gl_renderer {
|
||||
|
@ -158,9 +160,9 @@ struct gl_renderer {
|
|||
|
||||
GLint gl_half_float_type;
|
||||
|
||||
/** struct gl_shader::link
|
||||
/** Shader program cache in most recently used order
|
||||
*
|
||||
* List constains cached shaders built from struct gl_shader_requirements
|
||||
* Uses struct gl_shader::link.
|
||||
*/
|
||||
struct wl_list shader_list;
|
||||
struct weston_log_scope *shader_scope;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* Copyright © 2012 Intel Corporation
|
||||
* Copyright © 2015,2019 Collabora, Ltd.
|
||||
* Copyright © 2015,2019,2021 Collabora, Ltd.
|
||||
* Copyright © 2016 NVIDIA Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
|
@ -774,11 +774,39 @@ gl_renderer_use_program(struct gl_renderer *gr, struct gl_shader **shaderp)
|
|||
if (gr->current_shader == shader)
|
||||
return true;
|
||||
|
||||
if (shader != gr->fallback_shader) {
|
||||
/* Update list order for most recently used. */
|
||||
wl_list_remove(&shader->link);
|
||||
wl_list_insert(&gr->shader_list, &shader->link);
|
||||
}
|
||||
shader->last_used = gr->compositor->last_repaint_start;
|
||||
|
||||
glUseProgram(shader->program);
|
||||
gr->current_shader = shader;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
gl_renderer_garbage_collect_programs(struct gl_renderer *gr)
|
||||
{
|
||||
struct gl_shader *shader, *tmp;
|
||||
unsigned count = 0;
|
||||
|
||||
wl_list_for_each_safe(shader, tmp, &gr->shader_list, link) {
|
||||
/* Keep the 10 most recently used always. */
|
||||
if (count++ < 10)
|
||||
continue;
|
||||
|
||||
/* Keep everything used in the past 1 minute. */
|
||||
if (timespec_sub_to_msec(&gr->compositor->last_repaint_start,
|
||||
&shader->last_used) < 60000)
|
||||
continue;
|
||||
|
||||
/* The rest throw away. */
|
||||
gl_shader_destroy(gr, shader);
|
||||
}
|
||||
}
|
||||
|
||||
static const struct gl_shader_requirements requirements_triangle_fan = {
|
||||
.variant = SHADER_VARIANT_SOLID,
|
||||
};
|
||||
|
@ -1807,6 +1835,8 @@ gl_renderer_repaint_output(struct weston_output *output,
|
|||
TIMELINE_RENDER_POINT_TYPE_END);
|
||||
|
||||
update_buffer_release_fences(compositor, output);
|
||||
|
||||
gl_renderer_garbage_collect_programs(gr);
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
Loading…
Reference in New Issue