frontend: Add common --renderer=foo argument

Rather than reinventing --use-pixman and --use-gl throughout each
backend, just have a common --renderer=foo argument which can be used to
explicitly specify the renderer.

The old arguments are still handled for backwards compatibility.

Signed-off-by: Daniel Stone <daniels@collabora.com>
This commit is contained in:
Daniel Stone 2022-12-29 21:12:24 +00:00 committed by Marius Vlad
parent 54356be853
commit 75b3ecfcc3
7 changed files with 156 additions and 67 deletions

View file

@ -62,3 +62,32 @@ get_backend_from_string(const char *name,
return false; return false;
} }
struct {
char *name;
enum weston_renderer_type renderer;
} renderer_name_map[] = {
{ "auto", WESTON_RENDERER_AUTO },
{ "gl", WESTON_RENDERER_GL },
{ "noop", WESTON_RENDERER_NOOP },
{ "pixman", WESTON_RENDERER_PIXMAN },
};
bool
get_renderer_from_string(const char *name,
enum weston_renderer_type *renderer)
{
size_t i;
if (!name)
name = "auto";
for (i = 0; i < ARRAY_LENGTH(renderer_name_map); i++) {
if (strcmp(name, renderer_name_map[i].name) == 0) {
*renderer = renderer_name_map[i].renderer;
return true;
}
}
return false;
}

View file

@ -670,6 +670,13 @@ usage(int error_code)
#if defined(BUILD_X11_COMPOSITOR) #if defined(BUILD_X11_COMPOSITOR)
"\t\t\t\tx11\n" "\t\t\t\tx11\n"
#endif #endif
" --renderer=NAME\tRenderer to use, one of\n"
"\t\t\t\tauto\tAutomatic selection of one of the below renderers\n"
#if defined(ENABLE_EGL)
"\t\t\t\tgl\tOpenGL ES\n"
#endif
"\t\t\t\tnoop\tNo-op renderer for testing only\n"
"\t\t\t\tpixman\tPixman software renderer\n"
" --shell=NAME\tShell to load, defaults to desktop\n" " --shell=NAME\tShell to load, defaults to desktop\n"
" -S, --socket=NAME\tName of socket to listen on\n" " -S, --socket=NAME\tName of socket to listen on\n"
" -i, --idle-time=SECS\tIdle time in seconds\n" " -i, --idle-time=SECS\tIdle time in seconds\n"
@ -695,7 +702,7 @@ usage(int error_code)
"Options for drm:\n\n" "Options for drm:\n\n"
" --seat=SEAT\t\tThe seat that weston should run on, instead of the seat defined in XDG_SEAT\n" " --seat=SEAT\t\tThe seat that weston should run on, instead of the seat defined in XDG_SEAT\n"
" --drm-device=CARD\tThe DRM device to use, e.g. \"card0\".\n" " --drm-device=CARD\tThe DRM device to use, e.g. \"card0\".\n"
" --use-pixman\t\tUse the pixman (CPU) renderer\n" " --use-pixman\t\tUse the pixman (CPU) renderer (deprecated alias for --renderer=pixman)\n"
" --current-mode\tPrefer current KMS mode over EDID preferred mode\n" " --current-mode\tPrefer current KMS mode over EDID preferred mode\n"
" --continue-without-input\tAllow the compositor to start without input devices\n\n"); " --continue-without-input\tAllow the compositor to start without input devices\n\n");
#endif #endif
@ -708,8 +715,8 @@ usage(int error_code)
" --scale=SCALE\t\tScale factor of output\n" " --scale=SCALE\t\tScale factor of output\n"
" --transform=TR\tThe output transformation, TR is one of:\n" " --transform=TR\tThe output transformation, TR is one of:\n"
"\tnormal 90 180 270 flipped flipped-90 flipped-180 flipped-270\n" "\tnormal 90 180 270 flipped flipped-90 flipped-180 flipped-270\n"
" --use-pixman\t\tUse the pixman (CPU) renderer (default: no rendering)\n" " --use-pixman\t\tUse the pixman (CPU) renderer (deprecated alias for --renderer=pixman)\n"
" --use-gl\t\tUse the GL renderer (default: no rendering)\n" " --use-gl\t\tUse the GL renderer (deprecated alias for --renderer=gl)\n"
" --no-outputs\t\tDo not create any virtual outputs\n" " --no-outputs\t\tDo not create any virtual outputs\n"
"\n"); "\n");
#endif #endif
@ -748,7 +755,7 @@ usage(int error_code)
" --height=HEIGHT\tHeight of Wayland surface\n" " --height=HEIGHT\tHeight of Wayland surface\n"
" --scale=SCALE\t\tScale factor of output\n" " --scale=SCALE\t\tScale factor of output\n"
" --fullscreen\t\tRun in fullscreen mode\n" " --fullscreen\t\tRun in fullscreen mode\n"
" --use-pixman\t\tUse the pixman (CPU) renderer\n" " --use-pixman\t\tUse the pixman (CPU) renderer (deprecated alias for --renderer=pixman)\n"
" --output-count=COUNT\tCreate multiple outputs\n" " --output-count=COUNT\tCreate multiple outputs\n"
" --sprawl\t\tCreate one fullscreen output for every parent output\n" " --sprawl\t\tCreate one fullscreen output for every parent output\n"
" --display=DISPLAY\tWayland display to connect to\n\n"); " --display=DISPLAY\tWayland display to connect to\n\n");
@ -761,7 +768,7 @@ usage(int error_code)
" --height=HEIGHT\tHeight of X window\n" " --height=HEIGHT\tHeight of X window\n"
" --scale=SCALE\t\tScale factor of output\n" " --scale=SCALE\t\tScale factor of output\n"
" --fullscreen\t\tRun in fullscreen mode\n" " --fullscreen\t\tRun in fullscreen mode\n"
" --use-pixman\t\tUse the pixman (CPU) renderer\n" " --use-pixman\t\tUse the pixman (CPU) renderer (deprecated alias for --renderer=pixman)\n"
" --output-count=COUNT\tCreate multiple outputs\n" " --output-count=COUNT\tCreate multiple outputs\n"
" --no-input\t\tDont create input devices\n\n"); " --no-input\t\tDont create input devices\n\n");
#endif #endif
@ -2885,8 +2892,8 @@ load_pipewire(struct weston_compositor *c, struct weston_config *wc)
} }
static int static int
load_drm_backend(struct weston_compositor *c, load_drm_backend(struct weston_compositor *c, int *argc, char **argv,
int *argc, char **argv, struct weston_config *wc) struct weston_config *wc, enum weston_renderer_type renderer)
{ {
struct weston_drm_backend_config config = {{ 0, }}; struct weston_drm_backend_config config = {{ 0, }};
struct weston_config_section *section; struct weston_config_section *section;
@ -2912,10 +2919,14 @@ load_drm_backend(struct weston_compositor *c,
parse_options(options, ARRAY_LENGTH(options), argc, argv); parse_options(options, ARRAY_LENGTH(options), argc, argv);
if (force_pixman) if (force_pixman && renderer != WESTON_RENDERER_AUTO) {
weston_log("error: conflicting renderer specification\n");
return -1;
} else if (force_pixman) {
config.renderer = WESTON_RENDERER_PIXMAN; config.renderer = WESTON_RENDERER_PIXMAN;
else } else {
config.renderer = WESTON_RENDERER_AUTO; config.renderer = renderer;
}
section = weston_config_get_section(wc, "core", NULL, NULL); section = weston_config_get_section(wc, "core", NULL, NULL);
weston_config_section_get_string(section, weston_config_section_get_string(section,
@ -2976,7 +2987,8 @@ headless_backend_output_configure(struct weston_output *output)
static int static int
load_headless_backend(struct weston_compositor *c, load_headless_backend(struct weston_compositor *c,
int *argc, char **argv, struct weston_config *wc) int *argc, char **argv, struct weston_config *wc,
enum weston_renderer_type renderer)
{ {
const struct weston_windowed_output_api *api; const struct weston_windowed_output_api *api;
struct weston_headless_backend_config config = {{ 0, }}; struct weston_headless_backend_config config = {{ 0, }};
@ -3011,7 +3023,8 @@ load_headless_backend(struct weston_compositor *c,
parse_options(options, ARRAY_LENGTH(options), argc, argv); parse_options(options, ARRAY_LENGTH(options), argc, argv);
if (force_pixman && force_gl) { if ((force_pixman && force_gl) ||
(renderer != WESTON_RENDERER_AUTO && (force_pixman || force_gl))) {
weston_log("Conflicting renderer specifications\n"); weston_log("Conflicting renderer specifications\n");
return -1; return -1;
} else if (force_pixman) { } else if (force_pixman) {
@ -3019,7 +3032,7 @@ load_headless_backend(struct weston_compositor *c,
} else if (force_gl) { } else if (force_gl) {
config.renderer = WESTON_RENDERER_GL; config.renderer = WESTON_RENDERER_GL;
} else { } else {
config.renderer = WESTON_RENDERER_AUTO; config.renderer = renderer;
} }
if (transform) { if (transform) {
@ -3113,7 +3126,8 @@ weston_rdp_backend_config_init(struct weston_rdp_backend_config *config)
static int static int
load_rdp_backend(struct weston_compositor *c, load_rdp_backend(struct weston_compositor *c,
int *argc, char *argv[], struct weston_config *wc) int *argc, char *argv[], struct weston_config *wc,
enum weston_renderer_type renderer)
{ {
struct weston_rdp_backend_config config = {{ 0, }}; struct weston_rdp_backend_config config = {{ 0, }};
struct weston_config_section *section; struct weston_config_section *section;
@ -3143,6 +3157,7 @@ load_rdp_backend(struct weston_compositor *c,
parse_options(rdp_options, ARRAY_LENGTH(rdp_options), argc, argv); parse_options(rdp_options, ARRAY_LENGTH(rdp_options), argc, argv);
config.remotefx_codec = !no_remotefx_codec; config.remotefx_codec = !no_remotefx_codec;
config.renderer = renderer;
wet_set_simple_head_configurator(c, rdp_backend_output_configure); wet_set_simple_head_configurator(c, rdp_backend_output_configure);
section = weston_config_get_section(wc, "rdp", NULL, NULL); section = weston_config_get_section(wc, "rdp", NULL, NULL);
@ -3216,7 +3231,8 @@ weston_vnc_backend_config_init(struct weston_vnc_backend_config *config)
static int static int
load_vnc_backend(struct weston_compositor *c, load_vnc_backend(struct weston_compositor *c,
int *argc, char *argv[], struct weston_config *wc) int *argc, char *argv[], struct weston_config *wc,
enum weston_renderer_type renderer)
{ {
struct weston_vnc_backend_config config = {{ 0, }}; struct weston_vnc_backend_config config = {{ 0, }};
struct weston_config_section *section; struct weston_config_section *section;
@ -3239,6 +3255,8 @@ load_vnc_backend(struct weston_compositor *c,
parse_options(vnc_options, ARRAY_LENGTH(vnc_options), argc, argv); parse_options(vnc_options, ARRAY_LENGTH(vnc_options), argc, argv);
config.renderer = renderer;
wet_set_simple_head_configurator(c, vnc_backend_output_configure); wet_set_simple_head_configurator(c, vnc_backend_output_configure);
section = weston_config_get_section(wc, "vnc", NULL, NULL); section = weston_config_get_section(wc, "vnc", NULL, NULL);
weston_config_section_get_int(section, "refresh-rate", weston_config_section_get_int(section, "refresh-rate",
@ -3270,7 +3288,8 @@ x11_backend_output_configure(struct weston_output *output)
static int static int
load_x11_backend(struct weston_compositor *c, load_x11_backend(struct weston_compositor *c,
int *argc, char **argv, struct weston_config *wc) int *argc, char **argv, struct weston_config *wc,
enum weston_renderer_type renderer)
{ {
char *default_output; char *default_output;
const struct weston_windowed_output_api *api; const struct weston_windowed_output_api *api;
@ -3306,10 +3325,14 @@ load_x11_backend(struct weston_compositor *c,
config.base.struct_version = WESTON_X11_BACKEND_CONFIG_VERSION; config.base.struct_version = WESTON_X11_BACKEND_CONFIG_VERSION;
config.base.struct_size = sizeof(struct weston_x11_backend_config); config.base.struct_size = sizeof(struct weston_x11_backend_config);
if (force_pixman) if (force_pixman && renderer != WESTON_RENDERER_AUTO) {
weston_log("error: conflicting renderer specification\n");
return -1;
} else if (force_pixman) {
config.renderer = WESTON_RENDERER_PIXMAN; config.renderer = WESTON_RENDERER_PIXMAN;
else } else {
config.renderer = WESTON_RENDERER_AUTO; config.renderer = WESTON_RENDERER_AUTO;
}
wet_set_simple_head_configurator(c, x11_backend_output_configure); wet_set_simple_head_configurator(c, x11_backend_output_configure);
@ -3385,7 +3408,8 @@ wayland_backend_output_configure(struct weston_output *output)
static int static int
load_wayland_backend(struct weston_compositor *c, load_wayland_backend(struct weston_compositor *c,
int *argc, char **argv, struct weston_config *wc) int *argc, char **argv, struct weston_config *wc,
enum weston_renderer_type renderer)
{ {
struct weston_wayland_backend_config config = {{ 0, }}; struct weston_wayland_backend_config config = {{ 0, }};
struct weston_config_section *section; struct weston_config_section *section;
@ -3431,10 +3455,14 @@ load_wayland_backend(struct weston_compositor *c,
config.base.struct_size = sizeof(struct weston_wayland_backend_config); config.base.struct_size = sizeof(struct weston_wayland_backend_config);
config.base.struct_version = WESTON_WAYLAND_BACKEND_CONFIG_VERSION; config.base.struct_version = WESTON_WAYLAND_BACKEND_CONFIG_VERSION;
if (force_pixman) if (force_pixman && renderer != WESTON_RENDERER_AUTO) {
weston_log("error: conflicting renderer specification\n");
return -1;
} else if (force_pixman) {
config.renderer = WESTON_RENDERER_PIXMAN; config.renderer = WESTON_RENDERER_PIXMAN;
else } else {
config.renderer = WESTON_RENDERER_AUTO; config.renderer = renderer;
}
/* load the actual wayland backend and configure it */ /* load the actual wayland backend and configure it */
ret = weston_compositor_load_backend(c, WESTON_BACKEND_WAYLAND, ret = weston_compositor_load_backend(c, WESTON_BACKEND_WAYLAND,
@ -3506,28 +3534,41 @@ load_wayland_backend(struct weston_compositor *c,
static int static int
load_backend(struct weston_compositor *compositor, const char *name, load_backend(struct weston_compositor *compositor, const char *name,
int *argc, char **argv, struct weston_config *config) int *argc, char **argv, struct weston_config *config,
const char *renderer_name)
{ {
enum weston_compositor_backend backend; enum weston_compositor_backend backend;
enum weston_renderer_type renderer;
if (!get_backend_from_string(name, &backend)) { if (!get_backend_from_string(name, &backend)) {
weston_log("Error: unknown backend \"%s\"\n", name); weston_log("Error: unknown backend \"%s\"\n", name);
return -1; return -1;
} }
if (!get_renderer_from_string(renderer_name, &renderer)) {
weston_log("Error: unknown renderer \"%s\"\n", renderer_name);
return -1;
}
switch (backend) { switch (backend) {
case WESTON_BACKEND_DRM: case WESTON_BACKEND_DRM:
return load_drm_backend(compositor, argc, argv, config); return load_drm_backend(compositor, argc, argv, config,
renderer);
case WESTON_BACKEND_HEADLESS: case WESTON_BACKEND_HEADLESS:
return load_headless_backend(compositor, argc, argv, config); return load_headless_backend(compositor, argc, argv, config,
renderer);
case WESTON_BACKEND_RDP: case WESTON_BACKEND_RDP:
return load_rdp_backend(compositor, argc, argv, config); return load_rdp_backend(compositor, argc, argv, config,
renderer);
case WESTON_BACKEND_VNC: case WESTON_BACKEND_VNC:
return load_vnc_backend(compositor, argc, argv, config); return load_vnc_backend(compositor, argc, argv, config,
renderer);
case WESTON_BACKEND_WAYLAND: case WESTON_BACKEND_WAYLAND:
return load_wayland_backend(compositor, argc, argv, config); return load_wayland_backend(compositor, argc, argv, config,
renderer);
case WESTON_BACKEND_X11: case WESTON_BACKEND_X11:
return load_x11_backend(compositor, argc, argv, config); return load_x11_backend(compositor, argc, argv, config,
renderer);
default: default:
unreachable("unknown backend type in load_backend()"); unreachable("unknown backend type in load_backend()");
} }
@ -3670,6 +3711,7 @@ wet_main(int argc, char *argv[], const struct weston_testsuite_data *test_data)
struct wl_event_loop *loop; struct wl_event_loop *loop;
int i, fd; int i, fd;
char *backend = NULL; char *backend = NULL;
char *renderer = NULL;
char *shell = NULL; char *shell = NULL;
bool xwayland = false; bool xwayland = false;
char *modules = NULL; char *modules = NULL;
@ -3703,6 +3745,7 @@ wet_main(int argc, char *argv[], const struct weston_testsuite_data *test_data)
const struct weston_option core_options[] = { const struct weston_option core_options[] = {
{ WESTON_OPTION_STRING, "backend", 'B', &backend }, { WESTON_OPTION_STRING, "backend", 'B', &backend },
{ WESTON_OPTION_STRING, "renderer", 0, &renderer },
{ WESTON_OPTION_STRING, "shell", 0, &shell }, { WESTON_OPTION_STRING, "shell", 0, &shell },
{ WESTON_OPTION_STRING, "socket", 'S', &socket_name }, { WESTON_OPTION_STRING, "socket", 'S', &socket_name },
{ WESTON_OPTION_INTEGER, "idle-time", 'i', &idle_time }, { WESTON_OPTION_INTEGER, "idle-time", 'i', &idle_time },
@ -3837,6 +3880,11 @@ wet_main(int argc, char *argv[], const struct weston_testsuite_data *test_data)
raise(SIGSTOP); raise(SIGSTOP);
} }
if (!renderer) {
weston_config_section_get_string(section, "renderer",
&renderer, NULL);
}
if (!backend) { if (!backend) {
weston_config_section_get_string(section, "backend", &backend, weston_config_section_get_string(section, "backend", &backend,
NULL); NULL);
@ -3876,7 +3924,8 @@ wet_main(int argc, char *argv[], const struct weston_testsuite_data *test_data)
weston_config_section_get_bool(section, "require-input", weston_config_section_get_bool(section, "require-input",
&wet.compositor->require_input, true); &wet.compositor->require_input, true);
if (load_backend(wet.compositor, backend, &argc, argv, config) < 0) { if (load_backend(wet.compositor, backend, &argc, argv, config,
renderer) < 0) {
weston_log("fatal: failed to create compositor backend\n"); weston_log("fatal: failed to create compositor backend\n");
goto out; goto out;
} }

View file

@ -32,6 +32,10 @@ bool
get_backend_from_string(const char *name, get_backend_from_string(const char *name,
enum weston_compositor_backend *backend); enum weston_compositor_backend *backend);
bool
get_renderer_from_string(const char *name,
enum weston_renderer_type *renderer);
int int
wet_output_set_color_characteristics(struct weston_output *output, wet_output_set_color_characteristics(struct weston_output *output,
struct weston_config *wc, struct weston_config *wc,

View file

@ -34,15 +34,12 @@ stitching them together is performed by a *renderer*. By doing so, it is
compositing all surfaces into a single image, which is being handed out to a compositing all surfaces into a single image, which is being handed out to a
back-end, and finally, displayed on the screen. back-end, and finally, displayed on the screen.
libweston has a CPU-based type of renderer by making use of the libweston provides two useful renderers. One uses
`Pixman <http://www.pixman.org/>`_ library, but also one that can make `OpenGL ES <https://www.khronos.org/opengles/>`_, which will often be accelerated
use of the GPU to do that, which uses `OpenGL ES <https://www.khronos.org/opengles/>`_ by your GPU when suitable drivers are installed. The other uses the
and it is simply called the GL-renderer. `Pixman <http://www.pixman.org>`_ library which is entirely CPU (software)
rendered. You can select between these with the ``--renderer=gl`` and
Most of the back-ends provide a command line option to disable the GL-renderer, ``--renderer=pixman`` arguments when starting Weston.
and use the CPU for doing that. That happens by appending to the command line
``--use-pixman`` when running Weston. One might use the CPU-based renderer
to exclude any other potential issues with the GL-renderer.
Additional set-up steps Additional set-up steps
----------------------- -----------------------

View file

@ -188,7 +188,25 @@ directory are:
.fi .fi
.RE .RE
.TP 7 .TP 7
.BI "renderer=" auto
Selects a renderer to use for internal composition when required, or
.BI auto
to select the most appropriate renderer. Available renderers are:
.PP
.RS 10
.nf
.BR auto
.BR gl
.BR noop
.BR pixman
.fi
.RE
Not all backends support all renderers.
.TP 7
.BI "use-pixman=" true .BI "use-pixman=" true
Deprecated in favour of the
.BI "renderer="
option.
Enables pixman-based rendering for all outputs on backends that support it. Enables pixman-based rendering for all outputs on backends that support it.
Boolean, defaults to Boolean, defaults to
.BR false . .BR false .

View file

@ -185,6 +185,10 @@ Do not read
for the compositor. Avoids e.g. loading compositor modules via the for the compositor. Avoids e.g. loading compositor modules via the
configuration file, which is useful for unit tests. configuration file, which is useful for unit tests.
.TP .TP
\fB\-\-renderer\fR=\fIrenderer\fR
Select which renderer to use for Weston's internal composition. Defaults to
automatic selection.
.TP
\fB\-\-shell\fR=\fIshell\fR \fB\-\-shell\fR=\fIshell\fR
Select which shell to load to provide Weston's user interface. See Select which shell to load to provide Weston's user interface. See
.BR ENVIRONMENT "." .BR ENVIRONMENT "."
@ -236,7 +240,9 @@ Give all outputs a scale factor of
.I N. .I N.
.TP .TP
.B \-\-use\-pixman .B \-\-use\-pixman
Use the pixman renderer. By default, weston will try to use EGL and Deprecated in favour of the
.BI \-\-renderer
option. Use the pixman renderer. By default weston will try to use EGL and
GLES2 for rendering and will fall back to the pixman-based renderer for GLES2 for rendering and will fall back to the pixman-based renderer for
software compositing if EGL cannot be used. Passing this option will force software compositing if EGL cannot be used. Passing this option will force
weston to use the pixman renderer. weston to use the pixman renderer.
@ -262,7 +268,9 @@ Give all outputs a scale factor of
.I N. .I N.
.TP .TP
.B \-\-use\-pixman .B \-\-use\-pixman
Use the pixman renderer. By default weston will try to use EGL and Deprecated in favour of the
.BI \-\-renderer
option. Use the pixman renderer. By default weston will try to use EGL and
GLES2 for rendering. Passing this option will make weston use the GLES2 for rendering. Passing this option will make weston use the
pixman library for software compsiting. pixman library for software compsiting.
. .

View file

@ -218,30 +218,15 @@ backend_to_str(enum weston_compositor_backend b)
} }
static const char * static const char *
renderer_to_arg(enum weston_compositor_backend b, enum renderer_type r) renderer_to_str(enum renderer_type t)
{ {
static const char * const headless_names[] = { static const char * const names[] = {
[RENDERER_NOOP] = NULL, [RENDERER_NOOP] = "noop",
[RENDERER_PIXMAN] = "--use-pixman", [RENDERER_PIXMAN] = "pixman",
[RENDERER_GL] = "--use-gl", [RENDERER_GL] = "gl",
}; };
static const char * const drm_names[] = { assert(t >= 0 && t <= ARRAY_LENGTH(names));
[RENDERER_PIXMAN] = "--use-pixman", return names[t];
[RENDERER_GL] = NULL,
};
switch (b) {
case WESTON_BACKEND_HEADLESS:
assert(r >= RENDERER_NOOP && r <= RENDERER_GL);
return headless_names[r];
case WESTON_BACKEND_DRM:
assert(r >= RENDERER_PIXMAN && r <= RENDERER_GL);
return drm_names[r];
default:
assert(0 && "renderer_to_str() does not know the backend");
}
return NULL;
} }
static const char * static const char *
@ -291,7 +276,7 @@ execute_compositor(const struct compositor_setup *setup,
struct weston_testsuite_data test_data; struct weston_testsuite_data test_data;
struct prog_args args; struct prog_args args;
char *tmp; char *tmp;
const char *ctmp, *drm_device; const char *drm_device;
int lock_fd = -1; int lock_fd = -1;
int ret = RESULT_OK; int ret = RESULT_OK;
@ -367,9 +352,8 @@ execute_compositor(const struct compositor_setup *setup,
prog_args_take(&args, strdup("--no-config")); prog_args_take(&args, strdup("--no-config"));
} }
ctmp = renderer_to_arg(setup->backend, setup->renderer); str_printf(&tmp, "--renderer=%s", renderer_to_str(setup->renderer));
if (ctmp) prog_args_take(&args, strdup(tmp));
prog_args_take(&args, strdup(ctmp));
str_printf(&tmp, "--shell=%s", shell_to_str(setup->shell)); str_printf(&tmp, "--shell=%s", shell_to_str(setup->shell));
prog_args_take(&args, tmp); prog_args_take(&args, tmp);