diff --git a/src/display.c b/src/display.c index f78c54b6d71608375109a85349e4b712b8e0576b..24aacc4432f192dbe9725642f1ea3a8922b89c6b 100644 --- a/src/display.c +++ b/src/display.c @@ -408,23 +408,29 @@ int display_open(display_t *d, session_t *session) return X11SPICE_ERR_NODAMAGE; } - dcookie = xcb_damage_query_version(d->c, XCB_DAMAGE_MAJOR_VERSION, XCB_DAMAGE_MINOR_VERSION); - damage_version = xcb_damage_query_version_reply(d->c, dcookie, &error); - if (error) { - fprintf(stderr, "Error: Could not query damage; type %d; code %d; major %d; minor %d\n", - error->response_type, error->error_code, error->major_code, error->minor_code); - return X11SPICE_ERR_NODAMAGE; - } - free(damage_version); - - d->damage = xcb_generate_id(d->c); - cookie = - xcb_damage_create_checked(d->c, d->damage, d->root, XCB_DAMAGE_REPORT_LEVEL_RAW_RECTANGLES); - error = xcb_request_check(d->c, cookie); - if (error) { - fprintf(stderr, "Error: Could not create damage; type %d; code %d; major %d; minor %d\n", - error->response_type, error->error_code, error->major_code, error->minor_code); - return X11SPICE_ERR_NODAMAGE; + if (session->options.full_screen_fps <= 0) { + dcookie = + xcb_damage_query_version(d->c, XCB_DAMAGE_MAJOR_VERSION, XCB_DAMAGE_MINOR_VERSION); + damage_version = xcb_damage_query_version_reply(d->c, dcookie, &error); + if (error) { + fprintf(stderr, + "Error: Could not query damage; type %d; code %d; major %d; minor %d\n", + error->response_type, error->error_code, error->major_code, error->minor_code); + return X11SPICE_ERR_NODAMAGE; + } + free(damage_version); + + d->damage = xcb_generate_id(d->c); + cookie = + xcb_damage_create_checked(d->c, d->damage, d->root, + XCB_DAMAGE_REPORT_LEVEL_RAW_RECTANGLES); + error = xcb_request_check(d->c, cookie); + if (error) { + fprintf(stderr, + "Error: Could not create damage; type %d; code %d; major %d; minor %d\n", + error->response_type, error->error_code, error->major_code, error->minor_code); + return X11SPICE_ERR_NODAMAGE; + } } d->shm_ext = xcb_get_extension_data(d->c, &xcb_shm_id); @@ -741,7 +747,9 @@ void display_close(display_t *d) { shm_cache_destroy(d); g_mutex_clear(&d->shm_cache_mutex); - xcb_damage_destroy(d->c, d->damage); + if (d->session->options.full_screen_fps <= 0) { + xcb_damage_destroy(d->c, d->damage); + } display_destroy_screen_images(d); xcb_disconnect(d->c); } diff --git a/src/options.c b/src/options.c index ef817bbb10d7efb41bfa72a8eae2cfabbcfbb325..866cb11fce17a3db03e84b5b6ead22460eba0f2a 100644 --- a/src/options.c +++ b/src/options.c @@ -80,6 +80,7 @@ void options_free(options_t *options) str_replace(&options->on_connect, NULL); str_replace(&options->on_disconnect, NULL); str_replace(&options->user_config_file, NULL); + str_replace(&options->codecs, NULL); } @@ -395,6 +396,9 @@ static void options_from_config(options_t *options) options->trust_damage = NEVER_TRUST; g_free(trust_damage); + options->full_screen_fps = int_option(userkey, systemkey, "spice", "full-screen-fps"); + string_option(&options->codecs, userkey, systemkey, "spice", "codecs"); + #if defined(HAVE_LIBAUDIT_H) /* Pick an arbitrary default in the user range. CodeWeavers was founed in 1996, so 1196 it is... */ if (options->audit_message_type == 0) diff --git a/src/options.h b/src/options.h index 19e22e4311b7c119004be7e856159a9799d24345..06fe859b55b41236ce043badd252a9ecb84d20ff 100644 --- a/src/options.h +++ b/src/options.h @@ -62,9 +62,11 @@ typedef struct { char *uinput_path; char *on_connect; char *on_disconnect; + char *codecs; int audit; int audit_message_type; damage_trust_t trust_damage; + int full_screen_fps; /* file names of config files */ char *user_config_file; diff --git a/src/scan.c b/src/scan.c index 7b6d8f5fc68a70c2dda620712f74e128dc341d3c..69a8b0484e6e73feb2c3686269d345d6ff1ff84e 100644 --- a/src/scan.c +++ b/src/scan.c @@ -113,6 +113,9 @@ static QXLDrawable *shm_image_to_drawable(spice_t *s, shm_image_t *shmi, int x, static guint64 get_timeout(scanner_t *scanner) { + if (scanner->session->options.full_screen_fps > 0) { + return G_USEC_PER_SEC / scanner->session->options.full_screen_fps; + } return G_USEC_PER_SEC / scanner->target_fps / NUM_SCANLINES; } @@ -384,6 +387,18 @@ static gpointer g_async_queue_timeout_pop(GAsyncQueue *queue, guint64 t) } #endif +static void scanner_push_screen(scanner_t *scanner) +{ + scan_report_t whole_screen = { + .type = SCANLINE_SCAN_REPORT, + .x = 0,.y = 0, + .w = scanner->session->display.width, + .h = scanner->session->display.height + }; + + handle_scan_report(scanner->session, &whole_screen); +} + static void *scanner_run(void *opaque) { scanner_t *scanner = (scanner_t *) opaque; @@ -391,8 +406,12 @@ static void *scanner_run(void *opaque) scan_report_t *r; r = (scan_report_t *) g_async_queue_timeout_pop(scanner->queue, get_timeout(scanner)); if (!r) { - scan_update_fps(scanner, -1); - scanner_periodic(scanner); + if (scanner->session->options.full_screen_fps > 0) { + scanner_push_screen(scanner); + } else { + scan_update_fps(scanner, -1); + scanner_periodic(scanner); + } continue; } diff --git a/src/spice.c b/src/spice.c index 8bb55b210ba796f2970217fec2b0fba773614382..0c6c6101392068247b78b787aa2a80b261953ba9 100644 --- a/src/spice.c +++ b/src/spice.c @@ -565,6 +565,12 @@ static void set_options(spice_t *s, options_t *options) if (options->spice_password) spice_server_set_ticket(s->server, options->spice_password, 0, 0, 0); + if (options->codecs) + spice_server_set_video_codecs(s->server, options->codecs); + + if (options->full_screen_fps > 0) + spice_server_set_streaming_video(s->server, SPICE_STREAM_VIDEO_ALL); + spice_server_set_exit_on_disconnect(s->server, options->exit_on_disconnect); } diff --git a/src/xdg/x11spice/x11spice.conf b/src/xdg/x11spice/x11spice.conf index 6b1ee8d71fe529306f197082b6b06541febd5544..eecce685918419bce9967b735737ac6ce9e19098 100644 --- a/src/xdg/x11spice/x11spice.conf +++ b/src/xdg/x11spice/x11spice.conf @@ -100,6 +100,30 @@ #----------------------------------------------------------------------------- #trust-damage=auto +#----------------------------------------------------------------------------- +# full-screen-fps +# There are use cases where the most effective thing we can +# do is simply transmit the whole screen periodically, and +# trust the spice server and the video codecs to optimize. +# 0 disables; otherwise the number indicates how often to +# transmit the full screen +# Default 0. +#----------------------------------------------------------------------------- +#full-screen-fps=0 + +#----------------------------------------------------------------------------- +# codecs +# This configuration field allows you to specify which +# spice codecs to use. An example specification is: +# gstreamer:vp8;gstreamer:h264;spice:mjpeg +# which specifies vp8 first, followed by h264, and then by +# traditional spice mjpeg encoding. +# If no codecs are given, we will allow Spice to choose +# a reasonable default, which is usually spice:mjpeg. +# Default blank. +#----------------------------------------------------------------------------- +#codecs=spice:mjpeg + #----------------------------------------------------------------------------- # minimize Starts the x11spice gui minimized. Default false. #-----------------------------------------------------------------------------