Skip to content
Commits on Source (5)
......@@ -748,10 +748,12 @@ usage(int error_code)
" --height=HEIGHT\tHeight of memory surface\n"
" --scale=SCALE\t\tScale factor of output\n"
" --transform=TR\tThe output transformation, TR is one of:\n"
"\tnormal 90 180 270 flipped flipped-90 flipped-180 flipped-270\n"
"\tnormal rotate-90 rotate-180 rotate-270 flipped flipped-rotate-90 flipped-rotate-180\n"
"\tflipped-rotate-270\n"
" --use-pixman\t\tUse the pixman (CPU) renderer (deprecated alias for --renderer=pixman)\n"
" --use-gl\t\tUse the GL renderer (deprecated alias for --renderer=gl)\n"
" --no-outputs\t\tDo not create any virtual outputs\n"
" --refresh-rate=RATE\tThe output refresh rate (in mHz)\n"
"\n");
#endif
......@@ -3167,7 +3169,9 @@ load_headless_backend(struct weston_compositor *c,
{ WESTON_OPTION_BOOLEAN, "use-gl", 0, &force_gl },
{ WESTON_OPTION_STRING, "transform", 0, &transform },
{ WESTON_OPTION_BOOLEAN, "no-outputs", 0, &no_outputs },
{ WESTON_OPTION_INTEGER, "refresh-rate", 0, &config.refresh },
};
config.refresh = -1;
parse_options(options, ARRAY_LENGTH(options), argc, argv);
......
......@@ -44,6 +44,11 @@ struct weston_headless_backend_config {
/** Use output decorations, requires use_gl = true */
bool decorate;
/** Output repaint refresh rate (in mHz). Supported values range from 0
* mHz to 1,000,000 mHz. 0 is a special value that triggers repaints
* only on capture requests, not on damages. */
int refresh;
};
#ifdef __cplusplus
......
......@@ -507,6 +507,9 @@ struct weston_output {
/** Used only between repaint_begin and repaint_cancel. */
bool repainted;
/** Repaints are triggered only on capture requests, not on damages. */
bool repaint_only_on_capture;
/** State of the repaint loop */
enum {
REPAINT_NOT_SCHEDULED = 0, /**< idle; no repaint will occur */
......
......@@ -47,11 +47,14 @@
#include "shared/weston-egl-ext.h"
#include "shared/cairo-util.h"
#include "shared/xalloc.h"
#include "shared/timespec-util.h"
#include "linux-dmabuf.h"
#include "output-capture.h"
#include "presentation-time-server-protocol.h"
#include <libweston/windowed-output-api.h>
#define DEFAULT_OUTPUT_REPAINT_REFRESH 60000 /* In mHz. */
struct headless_backend {
struct weston_backend base;
struct weston_compositor *compositor;
......@@ -63,6 +66,9 @@ struct headless_backend {
const struct pixel_format_info **formats;
unsigned int formats_count;
int refresh;
bool repaint_only_on_capture;
};
struct headless_head {
......@@ -157,6 +163,7 @@ headless_output_repaint(struct weston_output *output_base)
struct headless_output *output = to_headless_output(output_base);
struct weston_compositor *ec;
pixman_region32_t damage;
int delay_msec;
assert(output);
......@@ -173,7 +180,8 @@ headless_output_repaint(struct weston_output *output_base)
pixman_region32_fini(&damage);
wl_event_source_timer_update(output->finish_frame_timer, 16);
delay_msec = millihz_to_nsec(output->mode.refresh) / 1000000;
wl_event_source_timer_update(output->finish_frame_timer, delay_msec);
return 0;
}
......@@ -416,7 +424,7 @@ headless_output_set_size(struct weston_output *base,
WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
output->mode.width = output_width;
output->mode.height = output_height;
output->mode.refresh = 60000;
output->mode.refresh = output->backend->refresh;
wl_list_insert(&output->base.mode_list, &output->mode.link);
output->base.current_mode = &output->mode;
......@@ -451,6 +459,7 @@ headless_output_create(struct weston_backend *backend, const char *name)
output->base.disable = headless_output_disable;
output->base.enable = headless_output_enable;
output->base.attach_head = NULL;
output->base.repaint_only_on_capture = b->repaint_only_on_capture;
output->backend = b;
......@@ -565,6 +574,18 @@ headless_backend_create(struct weston_compositor *compositor,
b->formats_count = ARRAY_LENGTH(headless_formats);
b->formats = pixel_format_get_array(headless_formats, b->formats_count);
/* Wayland event source's timeout has a granularity of the order of
* milliseconds so the highest supported rate is 1 kHz. 0 is a special
* value that enables repaints only on capture. */
if (config->refresh > 0) {
b->refresh = MIN(config->refresh, 1000000);
} else if (config->refresh == 0) {
b->refresh = 1000000;
b->repaint_only_on_capture = true;
} else {
b->refresh = DEFAULT_OUTPUT_REPAINT_REFRESH;
}
if (!compositor->renderer) {
switch (config->renderer) {
case WESTON_RENDERER_GL: {
......@@ -639,6 +660,7 @@ err_free:
static void
config_init_to_defaults(struct weston_headless_backend_config *config)
{
config->refresh = DEFAULT_OUTPUT_REPAINT_REFRESH;
}
WL_EXPORT int
......
......@@ -3673,6 +3673,10 @@ weston_output_maybe_repaint(struct weston_output *output, struct timespec *now)
if (output->power_state == WESTON_OUTPUT_POWER_FORCED_OFF)
goto err;
if (output->repaint_only_on_capture &&
!weston_output_has_renderer_capture_tasks(output))
goto err;
/* If repaint fails, we aren't going to get weston_output_finish_frame
* to trigger a new repaint, so drop it from repaint and hope
* something schedules a successful repaint later. As repainting may
......@@ -7799,6 +7803,7 @@ weston_output_init(struct weston_output *output,
output->desired_protection = WESTON_HDCP_DISABLE;
output->allow_protection = true;
output->power_state = WESTON_OUTPUT_POWER_NORMAL;
output->repaint_only_on_capture = false;
wl_list_init(&output->head_list);
......
......@@ -57,6 +57,10 @@ if installed.
The PipeWire backend runs in memory without the need of graphical hardware and
creates a PipeWire node for each output. It can be used to capture Weston
outputs for processing with another application.
.TP
.I headless
The headless backend runs in memory. It can be used to capture Weston outputs
or to test client applications.
.
.\" ***************************************************************
.SH SHELLS
......@@ -289,6 +293,32 @@ See
See
.BR weston-vnc (7).
.
.SS headless backend options:
.TP
\fB\-\-width\fR=\fIW\fR, \fB\-\-height\fR=\fIH\fR
Make the default size of each output
.IR W x H " pixels."
.TP
.B \-\-scale\fR=\fIN\fR
Give all outputs a scale factor of
.IR N "."
.TP
\fB\-\-transform\fR=\fItransform\fR
Transform for the output, which can be rotated in 90-degree steps
and possibly flipped. Possible values are
.BR normal ", " rotate-90 ", " rotate-180 ", " rotate-270 ", "
.BR flipped ", " flipped-rotate-90 ", " flipped-rotate-180 ", and "
.BR flipped-rotate-270 .
.TP
.B \-\-no\-outputs
Do not create any virtual outputs.
.TP
.B \-\-refresh\-rate\fR=\fIN\fR
Give all outputs a refresh rate of
.IR N " mHz (60,000 mHz by default)."
Supported values range from 0 mHz to 1,000,000 mHz. 0 is a special value
that repaints as soon as possible on capture requests only, not on damages.
.
.
.\" ***************************************************************
.SH FILES
......
......@@ -43,6 +43,7 @@ fixture_setup(struct weston_test_harness *harness)
compositor_setup_defaults(&setup);
setup.shell = SHELL_TEST_DESKTOP;
setup.refresh = HIGHEST_OUTPUT_REFRESH;
return weston_test_harness_execute_as_client(harness, &setup);
}
......
......@@ -234,6 +234,7 @@ fixture_setup(struct weston_test_harness *harness, const struct setup_args *arg)
setup.height = WINDOW_HEIGHT;
setup.shell = SHELL_TEST_DESKTOP;
setup.logging_scopes = "log,color-lcms-profiles,color-lcms-transformations,color-lcms-optimizer";
setup.refresh = HIGHEST_OUTPUT_REFRESH;
file_name = output_filename_for_fixture(THIS_TEST_NAME, harness,
arg->meta.name, "icm");
......
......@@ -640,6 +640,7 @@ fixture_setup(struct weston_test_harness *harness)
compositor_setup_defaults(&setup);
setup.renderer = WESTON_RENDERER_GL;
setup.shell = SHELL_TEST_DESKTOP;
setup.refresh = HIGHEST_OUTPUT_REFRESH;
/* Create the sRGB ICC profile. We do that only once for this test
* program. */
......
......@@ -49,6 +49,7 @@ fixture_setup(struct weston_test_harness *harness)
compositor_setup_defaults(&setup);
setup.shell = SHELL_TEST_DESKTOP;
setup.refresh = HIGHEST_OUTPUT_REFRESH;
return weston_test_harness_execute_as_client(harness, &setup);
}
......
......@@ -37,6 +37,7 @@ fixture_setup(struct weston_test_harness *harness)
compositor_setup_defaults(&setup);
setup.shell = SHELL_TEST_DESKTOP;
setup.refresh = HIGHEST_OUTPUT_REFRESH;
return weston_test_harness_execute_as_client(harness, &setup);
}
......
......@@ -36,6 +36,7 @@ fixture_setup(struct weston_test_harness *harness)
compositor_setup_defaults(&setup);
setup.shell = SHELL_TEST_DESKTOP;
setup.refresh = HIGHEST_OUTPUT_REFRESH;
return weston_test_harness_execute_as_client(harness, &setup);
}
......
......@@ -43,6 +43,7 @@ fixture_setup(struct weston_test_harness *harness)
setup.width = 320;
setup.height = 240;
setup.shell = SHELL_DESKTOP;
setup.refresh = HIGHEST_OUTPUT_REFRESH;
weston_ini_setup (&setup,
cfgln("[shell]"),
......
......@@ -39,6 +39,7 @@ fixture_setup(struct weston_test_harness *harness)
compositor_setup_defaults(&setup);
setup.shell = SHELL_TEST_DESKTOP;
setup.refresh = HIGHEST_OUTPUT_REFRESH;
return weston_test_harness_execute_as_client(harness, &setup);
}
......
......@@ -41,6 +41,7 @@ fixture_setup(struct weston_test_harness *harness)
compositor_setup_defaults(&setup);
setup.shell = SHELL_TEST_DESKTOP;
setup.refresh = HIGHEST_OUTPUT_REFRESH;
/* We need to use the pixman renderer, since a few of the tests depend
* on the renderer holding onto a surface buffer until the next one
......
......@@ -103,6 +103,7 @@ fixture_setup(struct weston_test_harness *harness, const struct setup_args *arg)
setup.scale = arg->scale;
setup.transform = arg->transform;
setup.shell = SHELL_TEST_DESKTOP;
setup.refresh = HIGHEST_OUTPUT_REFRESH;
/*
* The test here works by swapping the whole wl_surface into a
......@@ -213,7 +214,7 @@ TEST(output_damage)
}
client->surface->buffer = buf[0];
move_client(client, 19, 19);
move_client_frame_sync(client, 19, 19);
/*
* Each time we commit a buffer with a different color, the damage box
......
......@@ -60,6 +60,7 @@ fixture_setup(struct weston_test_harness *harness, const struct setup_args *arg)
setup.height = 240;
setup.shell = SHELL_TEST_DESKTOP;
setup.logging_scopes = "log,test-harness-plugin";
setup.refresh = HIGHEST_OUTPUT_REFRESH;
return weston_test_harness_execute_as_client(harness, &setup);
}
......
......@@ -59,6 +59,7 @@ fixture_setup(struct weston_test_harness *harness, const struct setup_args *arg)
setup.width = 320;
setup.height = 240;
setup.shell = SHELL_TEST_DESKTOP;
setup.refresh = HIGHEST_OUTPUT_REFRESH;
return weston_test_harness_execute_as_client(harness, &setup);
}
......@@ -141,7 +142,7 @@ TEST(pointer_cursor_retains_committed_buffer_after_reenter)
client->surface = main_surface;
client->surface->buffer = create_shm_buffer_a8r8g8b8(client, 100, 100);
fill_image_with_color(client->surface->buffer->image, &red);
move_client(client, 50, 50);
move_client_frame_sync(client, 50, 50);
/* Move the pointer into the main surface. */
send_motion(client, &t1, 100, 100);
......
......@@ -40,6 +40,7 @@ fixture_setup(struct weston_test_harness *harness)
compositor_setup_defaults(&setup);
setup.shell = SHELL_TEST_DESKTOP;
setup.refresh = HIGHEST_OUTPUT_REFRESH;
return weston_test_harness_execute_as_client(harness, &setup);
}
......@@ -362,7 +363,7 @@ TEST(test_pointer_surface_move)
check_pointer_move(client, 50, 50);
/* move client center to pointer */
move_client(client, 0, 0);
move_client_frame_sync(client, 0, 0);
assert(surface_contains(client->surface, 50, 50));
check_pointer(client, 50, 50);
......
......@@ -46,6 +46,7 @@ fixture_setup(struct weston_test_harness *harness)
compositor_setup_defaults(&setup);
setup.shell = SHELL_TEST_DESKTOP;
setup.refresh = HIGHEST_OUTPUT_REFRESH;
return weston_test_harness_execute_as_client(harness, &setup);
}
......