[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

xserver-xorg-video-qxl: Changes to 'upstream-unstable'



 configure.ac                        |    8 +
 examples/spiceqxl.xorg.conf.example |   73 ++++++++++-----
 scripts/Xspice                      |   83 ++++++++++++-----
 src/dfps.c                          |   33 +++++-
 src/qxl.h                           |    8 -
 src/qxl_driver.c                    |   22 ++--
 src/qxl_kms.c                       |   29 +++++-
 src/qxl_option_helpers.c            |   27 ++++-
 src/qxl_surface.c                   |    3 
 src/spiceccid/Makefile.am           |    5 -
 src/spiceccid/spiceccid.c           |    2 
 src/spiceqxl_audio.c                |  174 ++++++++++++++++++++++--------------
 src/spiceqxl_display.c              |    2 
 src/spiceqxl_io_port.c              |   11 --
 src/spiceqxl_main_loop.c            |    6 -
 src/spiceqxl_spice_server.c         |   22 +++-
 src/spiceqxl_uinput.c               |   15 ++-
 src/spiceqxl_uinput.h               |    1 
 src/spiceqxl_vdagent.c              |    9 +
 src/uxa/uxa-damage.c                |   24 +++-
 src/uxa/uxa-glyphs.c                |    2 
 src/uxa/uxa-render.c                |    4 
 22 files changed, 383 insertions(+), 180 deletions(-)

New commits:
commit 4d7160c49614c9132e7b7ae4ccfda952daffeefb
Author: Francois Gouget <fgouget@codeweavers.com>
Date:   Fri Oct 28 16:50:18 2016 +0200

    spiceqxl: Remove an unused macro
    
    Signed-off-by: Francois Gouget <fgouget@codeweavers.com>

diff --git a/src/spiceqxl_io_port.c b/src/spiceqxl_io_port.c
index 165b8a9..6721d3f 100644
--- a/src/spiceqxl_io_port.c
+++ b/src/spiceqxl_io_port.c
@@ -44,17 +44,6 @@
         ret = &m_item->el;                                              \
     }
 
-#undef SPICE_RING_CONS_ITEM
-#define SPICE_RING_CONS_ITEM(r, ret) {                                  \
-        typeof(r) start = r;                                            \
-        typeof(r) end = r + 1;                                          \
-        uint32_t cons = (r)->cons & SPICE_RING_INDEX_MASK(r);           \
-        typeof(&(r)->items[cons]) m_item = &(r)->items[cons];           \
-        if (!((uint8_t*)m_item >= (uint8_t*)(start) && (uint8_t*)(m_item + 1) <= (uint8_t*)(end))) { \
-            abort();                                                    \
-        }                                                               \
-        ret = &m_item->el;                                              \
-    }
 
 static int spiceqxl_io_port_debug_level = -1;
 

commit 9739b6a60459f48044d7ef7fff393e631bcef5bf
Author: Hans de Goede <hdegoede@redhat.com>
Date:   Tue Oct 4 13:29:29 2016 +0200

    Fix crash caused by attempting to access the screen pixmap before it is created
    
    qxl_resize_primary_to_virtual() was using pScrn->pScreen != NULL to check
    if createScreenResources has been called. But starting with xserver 1.19
    pScrn->pScreen is non NULL even before createScreenResources is called,
    causing an invalid access to the screenPixmap in
    qxl_resize_primary_to_virtual().
    
    This commit fixes this.
    
    BugLink: https://bugzilla.redhat.com/show_bug.cgi?id=1381045
    Signed-off-by: Hans de Goede <hdegoede@redhat.com>
    Acked-by: Christophe Fergeau <cfergeau@redhat.com>

diff --git a/src/qxl.h b/src/qxl.h
index 5cc8d05..885048c 100644
--- a/src/qxl.h
+++ b/src/qxl.h
@@ -234,6 +234,7 @@ struct _qxl_screen_t
     struct qxl_ring *		cursor_ring;
     struct qxl_ring *		release_ring;
 
+    Bool                        screen_resources_created;
     int                         device_primary;
     struct qxl_bo *             primary_bo;
     int				num_modes;
diff --git a/src/qxl_driver.c b/src/qxl_driver.c
index fc1b629..8aecf3c 100644
--- a/src/qxl_driver.c
+++ b/src/qxl_driver.c
@@ -530,7 +530,6 @@ qxl_create_primary(qxl_screen_t *qxl)
 Bool
 qxl_resize_primary_to_virtual (qxl_screen_t *qxl)
 {
-    ScreenPtr pScreen;
     long new_surface0_size;
 
     if ((qxl->primary_mode.x_res == qxl->virtual_x &&
@@ -566,9 +565,9 @@ qxl_resize_primary_to_virtual (qxl_screen_t *qxl)
     qxl->primary = qxl_create_primary(qxl);
     qxl->bytes_per_pixel = (qxl->pScrn->bitsPerPixel + 7) / 8;
     
-    pScreen = qxl->pScrn->pScreen;
-    if (pScreen)
+    if (qxl->screen_resources_created)
     {
+        ScreenPtr pScreen = qxl->pScrn->pScreen;
 	PixmapPtr root = pScreen->GetScreenPixmap (pScreen);
 
         if (qxl->deferred_fps <= 0)
@@ -645,6 +644,7 @@ qxl_create_screen_resources (ScreenPtr pScreen)
     qxl_create_desired_modes (qxl);
     qxl_update_edid (qxl);
     
+    qxl->screen_resources_created = TRUE;
     return TRUE;
 }
 
diff --git a/src/qxl_kms.c b/src/qxl_kms.c
index fe37af0..d11b20e 100644
--- a/src/qxl_kms.c
+++ b/src/qxl_kms.c
@@ -235,6 +235,7 @@ qxl_create_screen_resources_kms(ScreenPtr pScreen)
     if (!uxa_resources_init (pScreen))
 	return FALSE;
     
+    qxl->screen_resources_created = TRUE;
     return TRUE;
 }
 

commit e13d28ee5d8724fc4b22f26bce01a7d36355f272
Author: Owen W. Taylor <otaylor@fishsoup.net>
Date:   Fri Aug 26 11:44:55 2016 -0400

    Check for either xfont.pc or xfont2.pc
    
    More recent versions of Xfont have a different API (with namespacing
    for libXfont functions.) Check for xfont2.pc and if found, use that, and
    use the new API. The rational for preferring libXfont2 is that as a recent
    change the xserver module looks for and requires libXfont2, and it's better
    not to have both versions of the library in process.

diff --git a/configure.ac b/configure.ac
index 7e95b01..451d42a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -60,8 +60,14 @@ XORG_DRIVER_CHECK_EXT(RENDER, renderproto)
 XORG_DRIVER_CHECK_EXT(XV, videoproto)
 XORG_DRIVER_CHECK_EXT(XFreeXDGA, xf86dgaproto)
 
+# We can use either version 1 or version 2 of libXfont
+PKG_CHECK_EXISTS(xfont2,
+                 [xfont_pc=xfont2
+                  AC_DEFINE(HAVE_XFONT2,1,[Version 2 of the libXfont library])],
+                 [xfont_pc=xfont])
+
 # Obtain compiler/linker options for the driver dependencies
-PKG_CHECK_MODULES(XORG, [xorg-server >= 1.0.99.901] xproto fontsproto xfont $REQUIRED_MODULES)
+PKG_CHECK_MODULES(XORG, [xorg-server >= 1.0.99.901] xproto fontsproto $xfont_pc $REQUIRED_MODULES)
 
 
 save_CFLAGS="$CFLAGS"
diff --git a/src/uxa/uxa-damage.c b/src/uxa/uxa-damage.c
index a6d1ee3..6afb346 100644
--- a/src/uxa/uxa-damage.c
+++ b/src/uxa/uxa-damage.c
@@ -35,7 +35,11 @@
 #include    <X11/X.h>
 #include    <X11/fonts/font.h>
 #include    <X11/fonts/fontstruct.h>
+#ifdef HAVE_XFONT2
+#include    <X11/fonts/libxfont2.h>
+#else
 #include    <X11/fonts/fontutil.h>
+#endif
 
 #include    "uxa-damage.h"
 
@@ -947,8 +951,12 @@ uxa_damage_chars (RegionPtr	region,
 {
     ExtentInfoRec   extents;
     BoxRec	    box;
-    
+
+#ifdef HAVE_XFONT2
+    xfont2_query_glyph_extents(font, charinfo, n, &extents);
+#else
     QueryGlyphExtents(font, charinfo, n, &extents);
+#endif
     if (imageblt)
     {
 	if (extents.overallWidth > extents.overallRight)

commit 2b7e4fb2c93a2061b79ac8fb37628698d49618cc
Author: Francois Gouget <fgouget@codeweavers.com>
Date:   Wed Jul 6 16:17:52 2016 +0200

    Xspice: Add --video-codecs to specify encoder and codec preferences
    
    Signed-off-by: Francois Gouget <fgouget@codeweavers.com>
    Acked-by: Jeremy White <jwhite@codeweavers.com>

diff --git a/scripts/Xspice b/scripts/Xspice
index 15a5a5e..bf8112f 100755
--- a/scripts/Xspice
+++ b/scripts/Xspice
@@ -87,6 +87,7 @@ parser.add_argument('--zlib-glz-wan-compression',
 # TODO - sound support
 parser.add_argument('--streaming-video', choices=['off', 'all', 'filter'],
                     help='filter by default')
+parser.add_argument('--video-codecs', help="Sets a semicolon-separated list of preferred video codecs to use. Each takes the form encoder:codec, with spice:mjpeg being the default and other options being provided by gstreamer for the mjpeg, vp8 and h264 codecs.")
 add_boolean('--ipv4-only')
 add_boolean('--ipv6-only')
 parser.add_argument('--vdagent', action='store_true', dest='vdagent_enabled', default=False, help='launch vdagent & vdagentd. They provide clipboard & resolution automation')
@@ -282,7 +283,7 @@ var_args = ['port', 'tls_port', 'disable_ticketing',
     'x509_key_file', 'x509_key_password',
     'tls_ciphers', 'dh_file', 'password', 'image_compression',
     'jpeg_wan_compression', 'zlib_glz_wan_compression',
-    'streaming_video', 'deferred_fps', 'exit_on_disconnect',
+    'streaming_video', 'video_codecs', 'deferred_fps', 'exit_on_disconnect',
     'vdagent_enabled', 'vdagent_virtio_path', 'vdagent_uinput_path',
     'vdagent_uid', 'vdagent_gid']
 

commit 14ff3c26e204d334a9c110debfaa2ef8cab97bf6
Author: Francois Gouget <fgouget@codeweavers.com>
Date:   Thu Jul 7 15:23:56 2016 +0200

    spiceqxl: Add SpiceVideoCodecs to specify video codec preference
    
    Signed-off-by: Francois Gouget <fgouget@codeweavers.com>
    Signed-off-by: Jeremy White <jwhite@codeweavers.com>

diff --git a/examples/spiceqxl.xorg.conf.example b/examples/spiceqxl.xorg.conf.example
index ec6321e..b6f4840 100644
--- a/examples/spiceqxl.xorg.conf.example
+++ b/examples/spiceqxl.xorg.conf.example
@@ -52,6 +52,13 @@ Section "Device"
     # default: filter
     #Option "SpiceStreamingVideo" ""
 
+    # Set video codecs to use.  Provide a semicolon list of
+    # codecs, in preference order.  Each codec requires an encoder
+    # which can be one of spice or gstreamer, and then a codec type,
+    # for instance mjpeg or vp8. The default is spice:mjpeg,
+    # which uses the builtin mjpeg encoder.
+    #Option "SpiceVideoCodecs" ""
+
     # Set zlib glz wan compression. Options are auto, never, always.
     # default: auto
     #Option "SpiceZlibGlzWanCompression" ""
diff --git a/src/qxl.h b/src/qxl.h
index ff55604..5cc8d05 100644
--- a/src/qxl.h
+++ b/src/qxl.h
@@ -158,6 +158,7 @@ enum {
     OPTION_SURFACE_BUFFER_SIZE,
     OPTION_COMMAND_BUFFER_SIZE,
     OPTION_SPICE_SMARTCARD_FILE,
+    OPTION_SPICE_VIDEO_CODECS,
 #endif
     OPTION_COUNT,
 };
diff --git a/src/qxl_driver.c b/src/qxl_driver.c
index e21addd..fc1b629 100644
--- a/src/qxl_driver.c
+++ b/src/qxl_driver.c
@@ -154,6 +154,8 @@ const OptionInfoRec DefaultOptions[] =
       "CommandBufferSize",        OPTV_INTEGER,    {DEFAULT_COMMAND_BUFFER_SIZE}, FALSE},
     { OPTION_SPICE_SMARTCARD_FILE,
       "SpiceSmartcardFile",       OPTV_STRING,    {0}, FALSE},
+    { OPTION_SPICE_VIDEO_CODECS,
+      "SpiceVideoCodecs",         OPTV_STRING,    {0}, FALSE},
 #endif
 
     { -1, NULL, OPTV_NONE, {0}, FALSE }
diff --git a/src/spiceqxl_spice_server.c b/src/spiceqxl_spice_server.c
index b2b31ff..6e8cf50 100644
--- a/src/spiceqxl_spice_server.c
+++ b/src/spiceqxl_spice_server.c
@@ -173,6 +173,9 @@ void xspice_set_spice_server_options(OptionInfoPtr options)
     const char *streaming_video =
         get_str_option(options, OPTION_SPICE_STREAMING_VIDEO,
                        "XSPICE_STREAMING_VIDEO");
+    const char *video_codecs =
+        get_str_option(options, OPTION_SPICE_VIDEO_CODECS,
+                       "XSPICE_VIDEO_CODECS");
     int agent_mouse =
         get_bool_option(options, OPTION_SPICE_AGENT_MOUSE,
                         "XSPICE_AGENT_MOUSE");
@@ -294,6 +297,18 @@ void xspice_set_spice_server_options(OptionInfoPtr options)
         spice_server_set_streaming_video(spice_server, streaming_video_opt);
     }
 
+    if (video_codecs) {
+#if SPICE_SERVER_VERSION >= 0x000d02 /* 0.13.2 */
+        if (spice_server_set_video_codecs(spice_server, video_codecs)) {
+            fprintf(stderr, "spice: invalid video encoder %s\n", video_codecs);
+            exit(1);
+        }
+#else
+        fprintf(stderr, "spice: video_codecs are not available (spice >= 0.13.2 required)\n");
+        exit(1);
+#endif
+    }
+
     spice_server_set_agent_mouse(spice_server, agent_mouse);
     spice_server_set_playback_compression(spice_server, playback_compression);
 

commit edd1a409f879f74193c2789f50240005bcf00783
Author: Christophe Fergeau <cfergeau@redhat.com>
Date:   Tue Apr 5 18:17:26 2016 +0200

    xspice: Don't create Xorg time in timer_add
    
    SpiceCoreInterface::timer_add() is used by spice-server for integration
    with external mainloops. timer_add() is only meant to create a disabled
    timer, this timer will then be started with a call to timer_start().
    
    The current implementation in Xspice creates a timer which will trigger
    in a very long time, assuming this will never happen. This 'forever' is
    1,000,000 seconds, which amounts to 11 days. After that time, some
    timers which are meant to be disabled (eg migration related timers in
    spice-server) fire, then causing a crash with some failed assertions.
    
    Instead of creating the X timer right away in timer_add(), we can wait
    until timer_start() is called before starting it, which avoids this
    issue.

diff --git a/src/spiceqxl_main_loop.c b/src/spiceqxl_main_loop.c
index ac9e43f..db89b6d 100644
--- a/src/spiceqxl_main_loop.c
+++ b/src/spiceqxl_main_loop.c
@@ -171,7 +171,6 @@ static SpiceTimer* timer_add(SpiceTimerFunc func, void *opaque)
 {
     SpiceTimer *timer = calloc(sizeof(SpiceTimer), 1);
 
-    timer->xorg_timer = TimerSet(NULL, 0, 1e9 /* TODO: infinity? */, xorg_timer_callback, timer);
     timer->func = func;
     timer->opaque = opaque;
     return timer;
@@ -179,7 +178,8 @@ static SpiceTimer* timer_add(SpiceTimerFunc func, void *opaque)
 
 static void timer_start(SpiceTimer *timer, uint32_t ms)
 {
-    TimerSet(timer->xorg_timer, 0 /* flags */, ms, xorg_timer_callback, timer);
+    timer->xorg_timer = TimerSet(timer->xorg_timer, 0 /* flags */,
+                                 ms, xorg_timer_callback, timer);
 }
 
 static void timer_cancel(SpiceTimer *timer)

commit 76fd0a374f6879fba6f1d281d06003937ad4980c
Author: Francois Gouget <fgouget@codeweavers.com>
Date:   Fri Mar 18 15:32:22 2016 +0100

    spiceqxl_audio: Stop the playback channel if there is nothing to play
    
    This lets the client free the audio resources when an audio application
    is not actually playing anything, typically because playback is paused.
    This matches QEMU's behavior.
    As a side benefit it stops the client's mm-time from being stuck (due
    to the audio backend's delay updates being applied to the mm-time of
    the last audio message) which lets video streams play in this situation.
    
    Signed-off-by: Francois Gouget <fgouget@codeweavers.com>

diff --git a/src/spiceqxl_audio.c b/src/spiceqxl_audio.c
index 8d187b7..52a45f0 100644
--- a/src/spiceqxl_audio.c
+++ b/src/spiceqxl_audio.c
@@ -46,6 +46,7 @@
        and feed ahead into the Spice server (up to FEED_BUFFER_PERIODS).
 */
 
+#define IDLE_MS              300
 #define PERIOD_MS            10
 #define READ_BUFFER_PERIODS  2
 #define FEED_BUFFER_PERIODS  8
@@ -72,7 +73,7 @@ struct audio_data {
     int fifo_count;
     int closed_fifos;
     SpiceTimer *wall_timer;
-    int wall_timer_live;
+    int wall_timer_type;
     int dir_watch;
     int fifo_dir_watch;
     SpiceWatch *fifo_dir_qxl_watch;
@@ -279,9 +280,9 @@ static void read_from_fifos(int fd, int event, void *opaque)
     int i;
     int maxlen = 0;
 
-    if (data->wall_timer_live) {
+    if (data->wall_timer_type) {
         qxl->core->timer_cancel(data->wall_timer);
-        data->wall_timer_live = 0;
+        data->wall_timer_type = 0;
     }
 
     for (i = 0; i < data->fifo_count; i++) {
@@ -333,12 +334,16 @@ static void read_from_fifos(int fd, int event, void *opaque)
     if (!process_fifos(qxl, data, maxlen)) {
         /* There is still some fifo data to process */
         qxl->core->timer_start(data->wall_timer, PERIOD_MS);
-        data->wall_timer_live = 1;
+        data->wall_timer_type = PERIOD_MS;
 
     } else if (data->fifo_count) {
         /* All the fifo data was processed. Wait for more */
         start_watching(qxl);
 
+        /* But none may arrive so stop processing if that happens */
+        qxl->core->timer_start(data->wall_timer, IDLE_MS);
+        data->wall_timer_type = IDLE_MS;
+
     } else if (data->active) {
         /* There is no open fifo anymore */
         spice_server_playback_stop(&qxl->playback_sin);
@@ -361,14 +366,23 @@ static void start_watching(qxl_screen_t *qxl)
     }
 }
 
+/* a helper for read_from_fifos() */
 static void wall_ticker(void *opaque)
 {
     qxl_screen_t *qxl = opaque;
     struct audio_data *data = qxl->playback_opaque;
 
-    data->wall_timer_live = 0;
-
-    read_from_fifos(-1, 0, qxl);
+    if (data->wall_timer_type == IDLE_MS) {
+        /* The audio is likely paused in the application(s) */
+        if (data->active) {
+            spice_server_playback_stop(&qxl->playback_sin);
+            data->active = 0;
+        }
+        data->wall_timer_type = 0;
+    } else {
+        data->wall_timer_type = 0;
+        read_from_fifos(-1, 0, qxl);
+    }
 }
 
 #if defined(HAVE_SYS_INOTIFY_H)

commit 5f5b502ecdae7fb4e37e9285be9ee7a2107aff28
Author: Francois Gouget <fgouget@codeweavers.com>
Date:   Fri Mar 18 15:32:17 2016 +0100

    spiceqxl_audio: Only start the playback channel when fifos are present
    
    This lets the client free the audio resources when they are not needed.
    This matches QEMU's behavior.
    As a side benefit it stops the client's mm-time from being stuck (due
    to the audio backend's delay updates being applied to the mm-time of
    the last audio message, that is the channel's creation) when no audio
    application is running.
    
    Signed-off-by: Francois Gouget <fgouget@codeweavers.com>

diff --git a/src/spiceqxl_audio.c b/src/spiceqxl_audio.c
index 5fd76c8..8d187b7 100644
--- a/src/spiceqxl_audio.c
+++ b/src/spiceqxl_audio.c
@@ -63,6 +63,7 @@ struct fifo_data {
 
 struct audio_data {
     struct fifo_data fifos[MAX_FIFOS];
+    int active;
     uint32_t *spice_buffer;
     int spice_buffer_bytes;
     int period_bytes;
@@ -247,7 +248,6 @@ static int process_fifos(qxl_screen_t *qxl, struct audio_data *data, int maxlen)
     return TRUE;
 }
 
-
 /* a helper for read_from_fifos() */
 static void condense_fifos(qxl_screen_t *qxl)
 {
@@ -278,6 +278,12 @@ static void read_from_fifos(int fd, int event, void *opaque)
     struct audio_data *data = qxl->playback_opaque;
     int i;
     int maxlen = 0;
+
+    if (data->wall_timer_live) {
+        qxl->core->timer_cancel(data->wall_timer);
+        data->wall_timer_live = 0;
+    }
+
     for (i = 0; i < data->fifo_count; i++) {
         struct fifo_data *f = &data->fifos[i];
 
@@ -319,17 +325,24 @@ static void read_from_fifos(int fd, int event, void *opaque)
         condense_fifos(qxl);
     }
 
+    if (maxlen && !data->active) {
+        spice_server_playback_start(&qxl->playback_sin);
+        data->active = 1;
+    }
+
     if (!process_fifos(qxl, data, maxlen)) {
-        if (! data->wall_timer_live) {
-            qxl->core->timer_start(data->wall_timer, PERIOD_MS);
-            data->wall_timer_live = 1;
-        }
-    } else {
+        /* There is still some fifo data to process */
+        qxl->core->timer_start(data->wall_timer, PERIOD_MS);
+        data->wall_timer_live = 1;
+
+    } else if (data->fifo_count) {
+        /* All the fifo data was processed. Wait for more */
         start_watching(qxl);
-        if (data->wall_timer_live) {
-            qxl->core->timer_cancel(data->wall_timer);
-        }
-        data->wall_timer_live = 0;
+
+    } else if (data->active) {
+        /* There is no open fifo anymore */
+        spice_server_playback_stop(&qxl->playback_sin);
+        data->active = 0;
     }
 }
 
@@ -459,8 +472,6 @@ static void audio_initialize (qxl_screen_t *qxl)
         data->fifos[i].size = data->period_bytes * READ_BUFFER_PERIODS;
         data->fifos[i].buffer = calloc(1, data->fifos[i].size);
     }
-
-    spice_server_playback_start(&qxl->playback_sin);
 }
 
 

commit 5671929aecb742e7aaee4f4caf5e00cff344769a
Author: Francois Gouget <fgouget@codeweavers.com>
Date:   Fri Mar 18 15:32:11 2016 +0100

    spiceqxl_audio: Fix a race condition in the audio playback
    
    can_feed() depends on the time and thus could return false in
    process_fifos(), causing it to stop reading from the fifos, and then
    true in watch_or_wait() so that the wall_timer would not be set, but
    the fifos would not be watched either because they already contain
    data to process. The audio playback would then come to a stop.
    
    Signed-off-by: Francois Gouget <fgouget@codeweavers.com>

diff --git a/src/spiceqxl_audio.c b/src/spiceqxl_audio.c
index 0015fb9..5fd76c8 100644
--- a/src/spiceqxl_audio.c
+++ b/src/spiceqxl_audio.c
@@ -151,6 +151,7 @@ static void mix_in_one_fifo(struct fifo_data *f, int16_t *out, int len)
     free(in);
 }
 
+/* a helper for process_fifos() */
 static void mix_in_fifos(qxl_screen_t *qxl)
 {
     int i;
@@ -181,6 +182,7 @@ static void mix_in_fifos(qxl_screen_t *qxl)
     }
 }
 
+/* a helper for process_fifos() */
 static int can_feed(struct audio_data *data)
 {
     struct timeval end, diff;
@@ -202,6 +204,7 @@ static int can_feed(struct audio_data *data)
     return 0;
 }
 
+/* a helper for process_fifos() */
 static void did_feed(struct audio_data *data, int len)
 {
     struct timeval diff;
@@ -216,8 +219,7 @@ static void did_feed(struct audio_data *data, int len)
     timeradd(&data->fed_through_time, &diff, &data->fed_through_time);
 }
 
-static void watch_or_wait(qxl_screen_t *qxl);
-static void process_fifos(qxl_screen_t *qxl, struct audio_data *data, int maxlen)
+static int process_fifos(qxl_screen_t *qxl, struct audio_data *data, int maxlen)
 {
     while (maxlen > 0) {
         if (! data->spice_buffer) {
@@ -228,8 +230,9 @@ static void process_fifos(qxl_screen_t *qxl, struct audio_data *data, int maxlen
                 data->period_bytes * READ_BUFFER_PERIODS;
         }
 
-        if (! can_feed(data))
-            break;
+        if (! can_feed(data)) {
+            return FALSE;
+        }
 
         mix_in_fifos(qxl);
 
@@ -241,8 +244,7 @@ static void process_fifos(qxl_screen_t *qxl, struct audio_data *data, int maxlen
             data->spice_buffer = NULL;
         }
     }
-
-    watch_or_wait(qxl);
+    return TRUE;
 }
 
 
@@ -269,6 +271,7 @@ static void condense_fifos(qxl_screen_t *qxl)
     }
 }
 
+static void start_watching(qxl_screen_t *qxl);
 static void read_from_fifos(int fd, int event, void *opaque)
 {
     qxl_screen_t *qxl = opaque;
@@ -316,9 +319,21 @@ static void read_from_fifos(int fd, int event, void *opaque)
         condense_fifos(qxl);
     }
 
-    process_fifos(qxl, data, maxlen);
+    if (!process_fifos(qxl, data, maxlen)) {
+        if (! data->wall_timer_live) {
+            qxl->core->timer_start(data->wall_timer, PERIOD_MS);
+            data->wall_timer_live = 1;
+        }
+    } else {
+        start_watching(qxl);
+        if (data->wall_timer_live) {
+            qxl->core->timer_cancel(data->wall_timer);
+        }
+        data->wall_timer_live = 0;
+    }
 }
 
+/* a helper for read_from_fifos() */
 static void start_watching(qxl_screen_t *qxl)
 {
     struct audio_data *data = qxl->playback_opaque;
@@ -333,24 +348,6 @@ static void start_watching(qxl_screen_t *qxl)
     }
 }
 
-static void watch_or_wait(qxl_screen_t *qxl)
-{
-    struct audio_data *data = qxl->playback_opaque;
-
-    if (! can_feed(data)) {
-        if (! data->wall_timer_live) {
-            qxl->core->timer_start(data->wall_timer, PERIOD_MS);
-            data->wall_timer_live++;
-        }
-    }
-    else {
-        start_watching(qxl);
-        if (data->wall_timer_live)
-            qxl->core->timer_cancel(data->wall_timer);
-        data->wall_timer_live = 0;
-    }
-}
-
 static void wall_ticker(void *opaque)
 {
     qxl_screen_t *qxl = opaque;

commit 0d20d7d8425f397bdb15288747321fbc6d01820e
Author: Francois Gouget <fgouget@codeweavers.com>
Date:   Fri Mar 18 15:32:07 2016 +0100

    spiceqxl_audio: Only condense the fifo list when one has been closed
    
    Signed-off-by: Francois Gouget <fgouget@codeweavers.com>

diff --git a/src/spiceqxl_audio.c b/src/spiceqxl_audio.c
index 122dd95..0015fb9 100644
--- a/src/spiceqxl_audio.c
+++ b/src/spiceqxl_audio.c
@@ -69,6 +69,7 @@ struct audio_data {
     struct timeval fed_through_time;
     int remainder;
     int fifo_count;
+    int closed_fifos;
     SpiceTimer *wall_timer;
     int wall_timer_live;
     int dir_watch;
@@ -215,25 +216,6 @@ static void did_feed(struct audio_data *data, int len)
     timeradd(&data->fed_through_time, &diff, &data->fed_through_time);
 }
 
-static void condense_fifos(struct audio_data *data)
-{
-    int i;
-    struct fifo_data tmp;
-
-    for (i = 0; i < data->fifo_count; i++) {
-        struct fifo_data *f = &data->fifos[i];
-        if (f->fd == -1 && f->len == 0) {
-            if ((i + 1) < data->fifo_count) {
-                tmp = *f;
-                *f = data->fifos[data->fifo_count - 1];
-                data->fifos[data->fifo_count - 1] = tmp;
-            }
-            data->fifo_count--;
-            i--;
-        }
-    }
-}
-
 static void watch_or_wait(qxl_screen_t *qxl);
 static void process_fifos(qxl_screen_t *qxl, struct audio_data *data, int maxlen)
 {
@@ -263,6 +245,30 @@ static void process_fifos(qxl_screen_t *qxl, struct audio_data *data, int maxlen
     watch_or_wait(qxl);
 }
 
+
+/* a helper for read_from_fifos() */
+static void condense_fifos(qxl_screen_t *qxl)
+{
+    struct audio_data *data = qxl->playback_opaque;
+    int i;
+
+    for (i = 0; i < data->fifo_count; i++) {
+        struct fifo_data *f = &data->fifos[i];
+        if (f->fd == -1 && f->len == 0) {
+            if ((i + 1) < data->fifo_count) {
+                struct fifo_data tmp = *f;
+                *f = data->fifos[data->fifo_count - 1];
+                data->fifos[data->fifo_count - 1] = tmp;
+            }
+            data->fifo_count--;
+            i--;
+            if (!--data->closed_fifos) {
+                break;
+            }
+        }
+    }
+}
+
 static void read_from_fifos(int fd, int event, void *opaque)
 {
     qxl_screen_t *qxl = opaque;
@@ -289,6 +295,10 @@ static void read_from_fifos(int fd, int event, void *opaque)
                 f->watch = NULL;
                 close(f->fd);
                 f->fd = -1;
+                /* Setting closed_fifos will only have an effect once
+                 * the closed fifo's buffer is empty.
+                 */
+                data->closed_fifos++;
             }
 
             if (f->size == f->len) {
@@ -302,6 +312,10 @@ static void read_from_fifos(int fd, int event, void *opaque)
             maxlen = f->len;
     }
 
+    if (data->closed_fifos) {
+        condense_fifos(qxl);
+    }
+
     process_fifos(qxl, data, maxlen);
 }
 
@@ -344,8 +358,6 @@ static void wall_ticker(void *opaque)
 
     data->wall_timer_live = 0;
 
-    condense_fifos(data);
-
     read_from_fifos(-1, 0, qxl);
 }
 
@@ -358,8 +370,6 @@ static void handle_one_change(qxl_screen_t *qxl, struct inotify_event *e)
         struct fifo_data *f;
         char *fname;
 
-        condense_fifos(data);
-
         f = &data->fifos[data->fifo_count];
 
         if (data->fifo_count == MAX_FIFOS) {

commit 692df47b261d38dcd2df23d855032a262359fd5e
Author: Francois Gouget <fgouget@codeweavers.com>
Date:   Fri Mar 18 15:32:03 2016 +0100

    spiceqxl_audio: Let the audio play when no client is connected
    
    Simply keep reading from the fifos in reasonably sized chunks.
    
    Signed-off-by: Francois Gouget <fgouget@codeweavers.com>

diff --git a/src/spiceqxl_audio.c b/src/spiceqxl_audio.c
index eba9b10..122dd95 100644
--- a/src/spiceqxl_audio.c
+++ b/src/spiceqxl_audio.c
@@ -108,14 +108,18 @@ static inline void fifo_remove_data(struct fifo_data *f, unsigned char *dest, in
     int remain = f->size - remove_from;
 
     if (remain < len) {
-        memcpy(dest, f->buffer + remove_from, remain);
-        dest += remain;
+        if (dest) {
+            memcpy(dest, f->buffer + remove_from, remain);
+            dest += remain;
+        }
         len -= remain;
         f->len -= remain;
         remove_from = 0;
     }
 
-    memcpy(dest, f->buffer + remove_from, len);
+    if (dest) {
+        memcpy(dest, f->buffer + remove_from, len);
+    }
     f->len -= len;
 }
 
@@ -152,7 +156,9 @@ static void mix_in_fifos(qxl_screen_t *qxl)
     struct audio_data *data = qxl->playback_opaque;
     struct fifo_data *f;
 
-    memset(data->spice_buffer, 0, data->spice_buffer_bytes);
+    if (data->spice_buffer) {
+        memset(data->spice_buffer, 0, data->spice_buffer_bytes);
+    }
 
     if (data->fifo_count == 0)
         return;
@@ -164,8 +170,13 @@ static void mix_in_fifos(qxl_screen_t *qxl)
     /* Extra fifos need to be mixed in */
     for (i = 1; i < data->fifo_count; i++) {
         f = &data->fifos[i];
-        if (f->len > 0)
-            mix_in_one_fifo(f, (int16_t *) data->spice_buffer, data->spice_buffer_bytes);
+        if (f->len > 0) {
+            if (data->spice_buffer) {
+                mix_in_one_fifo(f, (int16_t *) data->spice_buffer, data->spice_buffer_bytes);
+            } else {
+                fifo_remove_data(f, NULL, min(data->spice_buffer_bytes, f->len));
+            }
+        }
     }
 }
 
@@ -230,12 +241,11 @@ static void process_fifos(qxl_screen_t *qxl, struct audio_data *data, int maxlen
         if (! data->spice_buffer) {
             uint32_t chunk_frames;
             spice_server_playback_get_buffer(&qxl->playback_sin, &data->spice_buffer, &chunk_frames);
-            data->spice_buffer_bytes = chunk_frames * sizeof(int16_t) * SPICE_INTERFACE_PLAYBACK_CHAN;
+            data->spice_buffer_bytes = data->spice_buffer ?
+                chunk_frames * sizeof(int16_t) * SPICE_INTERFACE_PLAYBACK_CHAN :
+                data->period_bytes * READ_BUFFER_PERIODS;
         }
 
-        if (! data->spice_buffer)
-            break;
-
         if (! can_feed(data))
             break;
 
@@ -244,8 +254,10 @@ static void process_fifos(qxl_screen_t *qxl, struct audio_data *data, int maxlen
         did_feed(data, data->spice_buffer_bytes);
         maxlen -= data->spice_buffer_bytes;
 
-        spice_server_playback_put_samples(&qxl->playback_sin, data->spice_buffer);
-        data->spice_buffer = NULL;
+        if (data->spice_buffer) {
+            spice_server_playback_put_samples(&qxl->playback_sin, data->spice_buffer);
+            data->spice_buffer = NULL;
+        }
     }
 
     watch_or_wait(qxl);

commit 91ee004cda2fb31de75508c44710ac09256edab4
Author: Francois Gouget <fgouget@codeweavers.com>
Date:   Mon Jan 11 02:21:50 2016 +0100

    server: Convert qxl->monitors_config to a QXLPHYSICAL using physical_address()
    
    This avoids compilation errors with -Werror on 32 bit systems and is
    more correct than a direct cast.
    
    Signed-off-by: Francois Gouget <fgouget@codeweavers.com>

diff --git a/src/spiceqxl_display.c b/src/spiceqxl_display.c
index a3a8978..c3609d8 100644
--- a/src/spiceqxl_display.c
+++ b/src/spiceqxl_display.c
@@ -350,6 +350,6 @@ void qxl_add_spice_display_interface(qxl_screen_t *qxl)
 
 void spiceqxl_display_monitors_config(qxl_screen_t *qxl)
 {
-    spice_qxl_monitors_config_async(&qxl->display_sin, (QXLPHYSICAL)qxl->monitors_config,
+    spice_qxl_monitors_config_async(&qxl->display_sin, physical_address(qxl, qxl->monitors_config, 0),
                                     MEMSLOT_GROUP, 0);
 }

commit 67d8beb98cb81d88273ba12f07a270bed9787473
Author: Jeremy White <jwhite@codeweavers.com>
Date:   Wed Nov 25 13:36:00 2015 -0600

    Optimize dfps mode to send updates only for the primary pixmap.
    
    We don't need to update the screen when we use a temporary or
    offscreen pixmap.

diff --git a/src/dfps.c b/src/dfps.c
index f113f27..fe0f09e 100644
--- a/src/dfps.c
+++ b/src/dfps.c
@@ -128,6 +128,14 @@ static Bool unaccel (void)
     return FALSE;
 }
 
+static Bool is_main_pixmap(PixmapPtr pixmap)
+{
+    ScreenPtr screen = pixmap->drawable.pScreen;
+    if (screen && pixmap == screen->GetScreenPixmap(screen))
+        return TRUE;
+    return FALSE;
+}
+
 
 /* Establish a maximum number of disparate regions we'll track before we just
    treat the entire bounding rectangle as having changed.
@@ -200,7 +208,8 @@ static void dfps_solid (PixmapPtr pixmap, int x_1, int y_1, int x_2, int y_2)
     fbFill(&pixmap->drawable, info->pgc, x_1, y_1, x_2 - x_1, y_2 - y_1);
 
     /* Track the updated region */
-    dfps_update_box(&info->updated_region, x_1, x_2, y_1, y_2);
+    if (is_main_pixmap(pixmap))
+        dfps_update_box(&info->updated_region, x_1, x_2, y_1, y_2);
     return;
 }
 
@@ -252,7 +261,8 @@ static void dfps_copy (PixmapPtr dest,
     fbCopyArea(&info->copy_src->drawable, &dest->drawable, info->pgc, src_x1, src_y1, width, height, dest_x1, dest_y1);
 
     /* Update the tracking region */
-    dfps_update_box(&info->updated_region, dest_x1, dest_x1 + width, dest_y1, dest_y1 + height);
+    if (is_main_pixmap(dest))
+        dfps_update_box(&info->updated_region, dest_x1, dest_x1 + width, dest_y1, dest_y1 + height);
 }
 
 static void dfps_done_copy (PixmapPtr dest)
@@ -277,7 +287,8 @@ static Bool dfps_put_image (PixmapPtr dest, int x, int y, int w, int h,
     if (!(info = dfps_get_info (dest)))
         return FALSE;
 
-    dfps_update_box(&info->updated_region, x, x + w, y, y + h);
+    if (is_main_pixmap(dest))
+        dfps_update_box(&info->updated_region, x, x + w, y, y + h);
 
     fbPrepareAccess(dest);
     fbGetPixmapBitsData(dest, dst, dst_stride, dst_bpp);
@@ -299,7 +310,8 @@ static Bool dfps_prepare_access (PixmapPtr pixmap, RegionPtr region, uxa_access_
         if (!(info = dfps_get_info (pixmap)))
             return FALSE;
 
-        dfps_update_region(&info->updated_region, region);
+        if (is_main_pixmap(pixmap))
+            dfps_update_region(&info->updated_region, region);
     }
     return TRUE;
 }

commit a8213444463690e4a7a851bd0a41008818bc5c97
Author: Jeremy White <jwhite@codeweavers.com>
Date:   Wed Nov 25 11:47:00 2015 -0600

    Provide an implementation for put_image in dfps mode.
    
    This prevents the fallback from calling prepare_access
    against the whole screen, which in turn keeps us from
    transmitting the whole screen more than necessary.

diff --git a/src/dfps.c b/src/dfps.c
index 568ba5e..f113f27 100644
--- a/src/dfps.c
+++ b/src/dfps.c
@@ -270,15 +270,22 @@ static Bool dfps_put_image (PixmapPtr dest, int x, int y, int w, int h,
                char *src, int src_pitch)
 {
     dfps_info_t *info;
+    FbBits *dst;
+    FbStride dst_stride;
+    int dst_bpp;
 
     if (!(info = dfps_get_info (dest)))
         return FALSE;
 


Reply to: