summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--man/weston.ini.man10
-rw-r--r--src/compositor.c83
-rw-r--r--src/compositor.h2
3 files changed, 84 insertions, 11 deletions
diff --git a/man/weston.ini.man b/man/weston.ini.man
index 7a353c93..d7df0e4c 100644
--- a/man/weston.ini.man
+++ b/man/weston.ini.man
@@ -137,6 +137,16 @@ directory are:
.fi
.RE
.TP 7
+.BI "repaint-window=" N
+Set the approximate length of the repaint window in milliseconds. The repaint
+window is used to control and reduce the output latency for clients. If the
+window is longer than the output refresh period, the repaint will be done
+immediately when the previous repaint finishes, not processing client requests
+in between. If the repaint window is too short, the compositor may miss the
+target vertical blank, increasing output latency. The default value is 7
+milliseconds. The allowed range is from -10 to 1000 milliseconds. Using a
+negative value will force the compositor to always miss the target vblank.
+.TP 7
.BI "gbm-format="format
sets the GBM format used for the framebuffer for the GBM backend. Can be
.B xrgb8888,
diff --git a/src/compositor.c b/src/compositor.c
index e060be1f..3f6aa7d6 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -62,6 +62,28 @@
#include "git-version.h"
#include "version.h"
+#define DEFAULT_REPAINT_WINDOW 7 /* milliseconds */
+
+#define NSEC_PER_SEC 1000000000
+
+static void
+timespec_sub(struct timespec *r,
+ const struct timespec *a, const struct timespec *b)
+{
+ r->tv_sec = a->tv_sec - b->tv_sec;
+ r->tv_nsec = a->tv_nsec - b->tv_nsec;
+ if (r->tv_nsec < 0) {
+ r->tv_sec--;
+ r->tv_nsec += NSEC_PER_SEC;
+ }
+}
+
+static int64_t
+timespec_to_nsec(const struct timespec *a)
+{
+ return (int64_t)a->tv_sec * NSEC_PER_SEC + a->tv_nsec;
+}
+
static struct wl_list child_process_list;
static struct weston_compositor *segv_compositor;
@@ -2346,19 +2368,38 @@ weston_output_schedule_repaint_reset(struct weston_output *output)
weston_compositor_read_input, compositor);
}
+static int
+output_repaint_timer_handler(void *data)
+{
+ struct weston_output *output = data;
+ struct weston_compositor *compositor = output->compositor;
+
+ if (output->repaint_needed &&
+ compositor->state != WESTON_COMPOSITOR_SLEEPING &&
+ compositor->state != WESTON_COMPOSITOR_OFFSCREEN &&
+ weston_output_repaint(output) == 0)
+ return 0;
+
+ weston_output_schedule_repaint_reset(output);
+
+ return 0;
+}
+
WL_EXPORT void
weston_output_finish_frame(struct weston_output *output,
const struct timespec *stamp,
uint32_t presented_flags)
{
struct weston_compositor *compositor = output->compositor;
- int r;
- uint32_t refresh_nsec;
+ int32_t refresh_nsec;
+ struct timespec now;
+ struct timespec gone;
+ int msec;
TL_POINT("core_repaint_finished", TLP_OUTPUT(output),
TLP_VBLANK(stamp), TLP_END);
- refresh_nsec = 1000000000000UL / output->current_mode->refresh;
+ refresh_nsec = 1000000000000LL / output->current_mode->refresh;
weston_presentation_feedback_present_list(&output->feedback_list,
output, refresh_nsec, stamp,
output->msc,
@@ -2366,15 +2407,16 @@ weston_output_finish_frame(struct weston_output *output,
output->frame_time = stamp->tv_sec * 1000 + stamp->tv_nsec / 1000000;
- if (output->repaint_needed &&
- compositor->state != WESTON_COMPOSITOR_SLEEPING &&
- compositor->state != WESTON_COMPOSITOR_OFFSCREEN) {
- r = weston_output_repaint(output);
- if (!r)
- return;
- }
+ weston_compositor_read_presentation_clock(compositor, &now);
+ timespec_sub(&gone, &now, stamp);
+ msec = (refresh_nsec - timespec_to_nsec(&gone)) / 1000000; /* floor */
+ msec -= compositor->repaint_msec;
- weston_output_schedule_repaint_reset(output);
+ /* Also sanity check. */
+ if (msec < 1 || msec > 1000)
+ output_repaint_timer_handler(output);
+ else
+ wl_event_source_timer_update(output->repaint_timer, msec);
}
static void
@@ -3873,6 +3915,8 @@ weston_output_destroy(struct weston_output *output)
output->destroying = 1;
+ wl_event_source_remove(output->repaint_timer);
+
weston_presentation_feedback_discard_list(&output->feedback_list);
weston_compositor_remove_output(output->compositor, output);
@@ -4033,6 +4077,8 @@ weston_output_init(struct weston_output *output, struct weston_compositor *c,
int x, int y, int mm_width, int mm_height, uint32_t transform,
int32_t scale)
{
+ struct wl_event_loop *loop;
+
output->compositor = c;
output->x = x;
output->y = y;
@@ -4053,6 +4099,10 @@ weston_output_init(struct weston_output *output, struct weston_compositor *c,
wl_list_init(&output->resource_list);
wl_list_init(&output->feedback_list);
+ loop = wl_display_get_event_loop(c->wl_display);
+ output->repaint_timer = wl_event_loop_add_timer(loop,
+ output_repaint_timer_handler, output);
+
output->id = ffs(~output->compositor->output_id_pool) - 1;
output->compositor->output_id_pool |= 1 << output->id;
@@ -4517,6 +4567,17 @@ weston_compositor_init(struct weston_compositor *ec,
weston_compositor_add_debug_binding(ec, KEY_T,
timeline_key_binding_handler, ec);
+ s = weston_config_get_section(ec->config, "core", NULL, NULL);
+ weston_config_section_get_int(s, "repaint-window", &ec->repaint_msec,
+ DEFAULT_REPAINT_WINDOW);
+ if (ec->repaint_msec < -10 || ec->repaint_msec > 1000) {
+ weston_log("Invalid repaint_window value in config: %d\n",
+ ec->repaint_msec);
+ ec->repaint_msec = DEFAULT_REPAINT_WINDOW;
+ }
+ weston_log("Output repaint window is %d ms maximum.\n",
+ ec->repaint_msec);
+
weston_compositor_schedule_repaint(ec);
return 0;
diff --git a/src/compositor.h b/src/compositor.h
index a05b208f..24ed4fc0 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -196,6 +196,7 @@ struct weston_output {
pixman_region32_t previous_damage;
int repaint_needed;
int repaint_scheduled;
+ struct wl_event_source *repaint_timer;
struct weston_output_zoom zoom;
int dirty;
struct wl_signal frame_signal;
@@ -683,6 +684,7 @@ struct weston_compositor {
int32_t kb_repeat_delay;
clockid_t presentation_clock;
+ int32_t repaint_msec;
int exit_code;
};