]> git.sesse.net Git - vlc/blobdiff - modules/video_output/xcb/xcb.c
Factor SHM and non SHM pictures a little
[vlc] / modules / video_output / xcb / xcb.c
index 33101e8c8f72bacba8666ac660dc93f69ddd7afd..99520d99b531e7abf5f92fdbbb8555ae196e95d5 100644 (file)
@@ -88,6 +88,7 @@ struct vout_sys_t
 
 static int Init (vout_thread_t *);
 static void Deinit (vout_thread_t *);
+static void Render (vout_thread_t *, picture_t *);
 static void Display (vout_thread_t *, picture_t *);
 static int Manage (vout_thread_t *);
 
@@ -148,13 +149,13 @@ static int Open (vlc_object_t *obj)
     if ((vt = xcb_aux_find_visual_by_attrs (scr, XCB_VISUAL_CLASS_TRUE_COLOR,
                                             scr->root_depth)) != NULL)
         msg_Dbg (vout, "using TrueColor visual ID %d", (int)vt->visual_id);
-#if 0
     else
+#if 0
     if ((vt = xcb_aux_find_visual_by_attrs (scr, XCB_VISUAL_CLASS_STATIC_COLOR,
                                             scr->root_depth)) != NULL)
         msg_Dbg (vout, "using static color visual ID %d", (int)vt->visual_id);
-#endif
     else
+#endif
     if ((scr->root_depth == 8)
      && (vt = xcb_aux_find_visual_by_attrs (scr, XCB_VISUAL_CLASS_STATIC_GRAY,
                                             scr->root_depth)) != NULL)
@@ -202,6 +203,12 @@ static int Open (vlc_object_t *obj)
             goto error;
     }
     vout->fmt_out.i_chroma = vout->output.i_chroma;
+    if (!gray)
+    {
+        vout->output.i_rmask = vt->red_mask;
+        vout->output.i_gmask = vt->green_mask;
+        vout->output.i_bmask = vt->blue_mask;
+    }
 
     /* Create colormap (needed to select non-default visual) */
     p_sys->cmap = xcb_generate_id (p_sys->conn);
@@ -226,8 +233,19 @@ static int Open (vlc_object_t *obj)
         }
     }
 
+    /* Get window */
+    /* FIXME: WTH to put as initial width/height values??? */
+    p_sys->embed = vout_RequestXWindow (vout, &(int){ 0 }, &(int){ 0 },
+                                        &(unsigned){ 0 }, &(unsigned){ 0 });
+    if (p_sys->embed == NULL)
+    {
+        msg_Err (vout, "parent window not available");
+        goto error;
+    }
+
     vout->pf_init = Init;
     vout->pf_end = Deinit;
+    vout->pf_render = Render;
     vout->pf_display = Display;
     vout->pf_manage = Manage;
     return VLC_SUCCESS;
@@ -246,7 +264,8 @@ static void Close (vlc_object_t *obj)
     vout_thread_t *vout = (vout_thread_t *)obj;
     vout_sys_t *p_sys = vout->p_sys;
 
-    assert (p_sys->embed == NULL);
+    if (p_sys->embed)
+        vout_ReleaseWindow (p_sys->embed);
     /* colormap is garbage-ollected by X (?) */
     if (p_sys->conn)
         xcb_disconnect (p_sys->conn);
@@ -255,13 +274,12 @@ static void Close (vlc_object_t *obj)
 
 struct picture_sys_t
 {
-    xcb_connection_t *conn;
-    xcb_image_t *image;
-    xcb_shm_seg_t segment;
+    xcb_connection_t *conn; /* Shared connection to X server */
+    xcb_image_t *image;  /* Picture buffer */
+    xcb_image_t *native; /* Rendered picture buffer (in X server format) */
+    xcb_shm_seg_t segment; /* Shared memory segment X ID */
 };
 
-static void PictureRelease (picture_t *pic);
-static void PictureShmRelease (picture_t *pic);
 #define SHM_ERR ((void *)(intptr_t)(-1))
 
 static int PictureInit (vout_thread_t *vout, picture_t *pic)
@@ -313,6 +331,8 @@ static int PictureInit (vout_thread_t *vout, picture_t *pic)
             shm = SHM_ERR;
         }
     }
+    else
+        priv->segment = 0;
 
     const unsigned real_width = pic->p->i_pitch / (p_sys->bpp >> 3);
     /* FIXME: anyway to getthing more intuitive than that?? */
@@ -339,18 +359,13 @@ static int PictureInit (vout_thread_t *vout, picture_t *pic)
         goto error;
     }
     if (shm != SHM_ERR && xcb_image_native (p_sys->conn, img, 0) == NULL)
-    {
-        msg_Err (vout, "incompatible X server image format");
-        xcb_image_destroy (img);
-        goto error;
-    }
+        msg_Warn (vout, "incompatible X server image format");
 
     priv->conn = p_sys->conn;
     priv->image = img;
+    priv->native = NULL;
     pic->p_sys = priv;
     pic->p->p_pixels = img->data;
-    pic->pf_release = (shm != SHM_ERR) ? PictureShmRelease
-                                       : PictureRelease;
     pic->i_status = DESTROYED_PICTURE;
     pic->i_type = DIRECT_PICTURE;
     return VLC_SUCCESS;
@@ -358,7 +373,7 @@ static int PictureInit (vout_thread_t *vout, picture_t *pic)
 error:
     if (shm != SHM_ERR)
         shmdt (shm);
-    free (p_sys);
+    free (priv);
     return VLC_EGENERIC;
 }
 
@@ -366,26 +381,21 @@ error:
 /**
  * Release picture private data
  */
-static void PictureRelease (picture_t *pic)
+static void PictureDeinit (picture_t *pic)
 {
     struct picture_sys_t *p_sys = pic->p_sys;
 
+    if (p_sys->segment != 0)
+    {
+        xcb_shm_detach (p_sys->conn, p_sys->segment);
+        shmdt (p_sys->image->data);
+    }
+    if ((p_sys->native != NULL) && (p_sys->native != p_sys->image))
+        xcb_image_destroy (p_sys->native);
     xcb_image_destroy (p_sys->image);
     free (p_sys);
 }
 
-/**
- * Release shared memory picture private data
- */
-static void PictureShmRelease (picture_t *pic)
-{
-    struct picture_sys_t *p_sys = pic->p_sys;
-
-    xcb_shm_detach (p_sys->conn, p_sys->segment);
-    shmdt (p_sys->image->data);
-    PictureRelease (pic);
-}
-
 /**
  * Allocate drawable window and picture buffers.
  */
@@ -395,24 +405,31 @@ static int Init (vout_thread_t *vout)
     const xcb_screen_t *screen = p_sys->screen;
     unsigned x, y, width, height;
 
-    /* Determine parent window */
+    /* Determine parent window and size */
     if (vout->b_fullscreen)
     {
-        p_sys->embed = NULL;
         p_sys->parent = screen->root;
         width = screen->width_in_pixels;
         height = screen->height_in_pixels;
     }
     else
     {
-        p_sys->embed = vout_RequestXWindow (vout, &(int){ 0 }, &(int){ 0 },
-                                            &width, &height);
-        if (p_sys->embed == NULL)
-        {
-            msg_Err (vout, "cannot get window");
-            return VLC_EGENERIC;
-        }
         p_sys->parent = p_sys->embed->handle.xid;
+
+        /* Subscribe to parent window resize events */
+        const uint32_t value = XCB_EVENT_MASK_STRUCTURE_NOTIFY;
+        xcb_change_window_attributes (p_sys->conn, p_sys->parent,
+                                      XCB_CW_EVENT_MASK, &value);
+
+        xcb_get_geometry_cookie_t ck;
+        ck = xcb_get_geometry (p_sys->conn, p_sys->parent);
+
+        xcb_get_geometry_reply_t *geo;
+        xcb_generic_error_t *err;
+        geo = xcb_get_geometry_reply (p_sys->conn, ck, &err);
+        width = geo->width;
+        height = geo->height;
+        free (geo);
     }
 
     vout_PlacePicture (vout, width, height, &x, &y, &width, &height);
@@ -438,7 +455,7 @@ static int Init (vout_thread_t *vout)
     /* Create window */
     const uint32_t mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK
                         | XCB_CW_COLORMAP;
-    uint32_t values[] = {
+    const uint32_t values[] = {
         /* XCB_CW_BACK_PIXEL */
         screen->black_pixel,
         /* XCB_CW_EVENT_MASK */
@@ -492,14 +509,26 @@ static void Deinit (vout_thread_t *vout)
     vout_sys_t *p_sys = vout->p_sys;
 
     while (I_OUTPUTPICTURES > 0)
-        picture_Release (PP_OUTPUTPICTURE[--I_OUTPUTPICTURES]);
+        PictureDeinit (PP_OUTPUTPICTURE[--I_OUTPUTPICTURES]);
 
     xcb_unmap_window (p_sys->conn, p_sys->window);
     xcb_destroy_window (p_sys->conn, p_sys->window);
-    vout_ReleaseWindow (p_sys->embed);
-    p_sys->embed = NULL;
 }
 
+/**
+ * Prepares an image ahead of display.
+ */
+static void Render (vout_thread_t *vout, picture_t *pic)
+{
+    vout_sys_t *p_sys = vout->p_sys;
+    picture_sys_t *priv = pic->p_sys;
+
+    if ((priv->native != NULL) && (priv->native != priv->image))
+        xcb_image_destroy (priv->native);
+    priv->native = xcb_image_native (p_sys->conn, priv->image, 1);
+}
+
+
 /**
  * Sends an image to the X server.
  */
@@ -507,9 +536,9 @@ static void Display (vout_thread_t *vout, picture_t *pic)
 {
     vout_sys_t *p_sys = vout->p_sys;
     picture_sys_t *priv = pic->p_sys;
-    xcb_image_t *img = priv->image;
+    xcb_image_t *img = priv->image, *native = priv->native;
 
-    if (img->base == NULL)
+    if ((native == img) && (img->base == NULL))
     {
         xcb_shm_segment_info_t info = {
             .shmseg = priv->segment,
@@ -521,16 +550,8 @@ static void Display (vout_thread_t *vout, picture_t *pic)
                         0, 0, 0, 0, img->width, img->height, 0);
     }
     else
-    {
-        xcb_image_t *native = xcb_image_native (p_sys->conn, img, 1);
-
-        if (native == NULL)
-            return;
-
+    if (native != NULL)
         xcb_image_put (p_sys->conn, p_sys->window, p_sys->gc, native, 0, 0, 0);
-        if (native != img)
-            xcb_image_destroy (native);
-    }
     xcb_flush (p_sys->conn);
 }
 
@@ -543,7 +564,7 @@ static int Manage (vout_thread_t *vout)
     xcb_generic_event_t *ev;
 
     while ((ev = xcb_poll_for_event (p_sys->conn)) != NULL)
-        ProcessEvent (vout, ev);
+        ProcessEvent (vout, p_sys->conn, p_sys->window, ev);
 
     if (xcb_connection_has_error (p_sys->conn))
     {