From 040467d118ec633260424660bfa2946eb50a8c3f Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Fri, 2 Oct 2015 14:17:48 +1000 Subject: [PATCH] ximagesrc: Gather and coalesce all damaged areas before retrieving. These days the xserver seems to give us the same damage regions over and over for entire windows, and we retrieve them multiple times, which gives time for more damage to appear. Instead, just quickly gather all damaged areas into a region list and copy out once. --- sys/ximage/gstximagesrc.c | 186 ++++++++++++++++++++------------------ 1 file changed, 98 insertions(+), 88 deletions(-) diff --git a/sys/ximage/gstximagesrc.c b/sys/ximage/gstximagesrc.c index f193194fc4..93f8f47b9a 100644 --- a/sys/ximage/gstximagesrc.c +++ b/sys/ximage/gstximagesrc.c @@ -536,6 +536,7 @@ gst_ximage_src_ximage_get (GstXImageSrc * ximagesrc) if (ximagesrc->have_xdamage && ximagesrc->use_damage && ximagesrc->last_ximage != NULL) { XEvent ev; + gboolean have_damage = FALSE; /* have_frame is TRUE when either the entire screen has been * grabbed or when the last image has been copied */ @@ -544,83 +545,91 @@ gst_ximage_src_ximage_get (GstXImageSrc * ximagesrc) GST_DEBUG_OBJECT (ximagesrc, "Retrieving screen using XDamage"); do { + XDamageNotifyEvent *damage_ev = (XDamageNotifyEvent *) (&ev); + XNextEvent (ximagesrc->xcontext->disp, &ev); - if (ev.type == ximagesrc->damage_event_base + XDamageNotify) { - XserverRegion parts; - XRectangle *rects; - int nrects; + if (ev.type == ximagesrc->damage_event_base + XDamageNotify && + damage_ev->level == XDamageReportNonEmpty) { - parts = XFixesCreateRegion (ximagesrc->xcontext->disp, 0, 0); XDamageSubtract (ximagesrc->xcontext->disp, ximagesrc->damage, None, - parts); - /* Now copy out all of the damaged rectangles. */ - rects = XFixesFetchRegion (ximagesrc->xcontext->disp, parts, &nrects); - if (rects != NULL) { - int i; - - if (!have_frame) { - GST_LOG_OBJECT (ximagesrc, - "Copying from last frame ximage->size: %" G_GSIZE_FORMAT, - gst_buffer_get_size (ximage)); - copy_buffer (ximage, ximagesrc->last_ximage); - have_frame = TRUE; - } - for (i = 0; i < nrects; i++) { - GST_LOG_OBJECT (ximagesrc, - "Damaged sub-region @ %d,%d size %dx%d reported", - rects[i].x, rects[i].y, rects[i].width, rects[i].height); - - /* if we only want a small area, clip this damage region to - * area we want */ - if (ximagesrc->endx > ximagesrc->startx && - ximagesrc->endy > ximagesrc->starty) { - /* see if damage area intersects */ - if (rects[i].x + rects[i].width - 1 < ximagesrc->startx || - rects[i].x > ximagesrc->endx) { - /* trivial reject */ - } else if (rects[i].y + rects[i].height - 1 < ximagesrc->starty || - rects[i].y > ximagesrc->endy) { - /* trivial reject */ - } else { - /* find intersect region */ - int startx, starty, width, height; - - startx = (rects[i].x < ximagesrc->startx) ? ximagesrc->startx : - rects[i].x; - starty = (rects[i].y < ximagesrc->starty) ? ximagesrc->starty : - rects[i].y; - width = (rects[i].x + rects[i].width - 1 < ximagesrc->endx) ? - rects[i].x + rects[i].width - startx : - ximagesrc->endx - startx + 1; - height = (rects[i].y + rects[i].height - 1 < ximagesrc->endy) ? - rects[i].y + rects[i].height - starty : ximagesrc->endy - - starty + 1; - - GST_LOG_OBJECT (ximagesrc, - "Retrieving damaged sub-region @ %d,%d size %dx%d as intersect region", - startx, starty, width, height); - XGetSubImage (ximagesrc->xcontext->disp, ximagesrc->xwindow, - startx, starty, width, height, AllPlanes, ZPixmap, - meta->ximage, startx - ximagesrc->startx, - starty - ximagesrc->starty); - } - } else { - - GST_LOG_OBJECT (ximagesrc, - "Retrieving damaged sub-region @ %d,%d size %dx%d", - rects[i].x, rects[i].y, rects[i].width, rects[i].height); - - XGetSubImage (ximagesrc->xcontext->disp, ximagesrc->xwindow, - rects[i].x, rects[i].y, - rects[i].width, rects[i].height, - AllPlanes, ZPixmap, meta->ximage, rects[i].x, rects[i].y); - } - } - free (rects); - } + ximagesrc->damage_region); + have_damage = TRUE; } } while (XPending (ximagesrc->xcontext->disp)); + + if (have_damage) { + XRectangle *rects; + int nrects; + + /* Now copy out all of the damaged rectangles. */ + rects = + XFixesFetchRegion (ximagesrc->xcontext->disp, + ximagesrc->damage_region, &nrects); + if (rects != NULL) { + int i; + + if (!have_frame) { + GST_LOG_OBJECT (ximagesrc, + "Copying from last frame ximage->size: %" G_GSIZE_FORMAT, + gst_buffer_get_size (ximage)); + copy_buffer (ximage, ximagesrc->last_ximage); + have_frame = TRUE; + } + for (i = 0; i < nrects; i++) { + GST_LOG_OBJECT (ximagesrc, + "Damaged sub-region @ %d,%d size %dx%d reported", + rects[i].x, rects[i].y, rects[i].width, rects[i].height); + + /* if we only want a small area, clip this damage region to + * area we want */ + if (ximagesrc->endx > ximagesrc->startx && + ximagesrc->endy > ximagesrc->starty) { + /* see if damage area intersects */ + if (rects[i].x + rects[i].width - 1 < ximagesrc->startx || + rects[i].x > ximagesrc->endx) { + /* trivial reject */ + } else if (rects[i].y + rects[i].height - 1 < ximagesrc->starty || + rects[i].y > ximagesrc->endy) { + /* trivial reject */ + } else { + /* find intersect region */ + int startx, starty, width, height; + + startx = (rects[i].x < ximagesrc->startx) ? ximagesrc->startx : + rects[i].x; + starty = (rects[i].y < ximagesrc->starty) ? ximagesrc->starty : + rects[i].y; + width = (rects[i].x + rects[i].width - 1 < ximagesrc->endx) ? + rects[i].x + rects[i].width - startx : + ximagesrc->endx - startx + 1; + height = (rects[i].y + rects[i].height - 1 < ximagesrc->endy) ? + rects[i].y + rects[i].height - starty : ximagesrc->endy - + starty + 1; + + GST_LOG_OBJECT (ximagesrc, + "Retrieving damaged sub-region @ %d,%d size %dx%d as intersect region", + startx, starty, width, height); + XGetSubImage (ximagesrc->xcontext->disp, ximagesrc->xwindow, + startx, starty, width, height, AllPlanes, ZPixmap, + meta->ximage, startx - ximagesrc->startx, + starty - ximagesrc->starty); + } + } else { + + GST_LOG_OBJECT (ximagesrc, + "Retrieving damaged sub-region @ %d,%d size %dx%d", + rects[i].x, rects[i].y, rects[i].width, rects[i].height); + + XGetSubImage (ximagesrc->xcontext->disp, ximagesrc->xwindow, + rects[i].x, rects[i].y, + rects[i].width, rects[i].height, + AllPlanes, ZPixmap, meta->ximage, rects[i].x, rects[i].y); + } + } + XFree (rects); + } + } if (!have_frame) { GST_LOG_OBJECT (ximagesrc, "Copying from last frame ximage->size: %" G_GSIZE_FORMAT, @@ -757,9 +766,10 @@ gst_ximage_src_ximage_get (GstXImageSrc * ximagesrc) iwidth = (cx + ximagesrc->cursor_image->width < ximagesrc->endx) ? cx + ximagesrc->cursor_image->width - startx : ximagesrc->endx - startx; - iheight = (cy + ximagesrc->cursor_image->height < ximagesrc->endy) ? - cy + ximagesrc->cursor_image->height - starty : - ximagesrc->endy - starty; + iheight = + (cy + ximagesrc->cursor_image->height < + ximagesrc->endy) ? cy + ximagesrc->cursor_image->height - + starty : ximagesrc->endy - starty; } } else { startx = cx; @@ -775,11 +785,11 @@ gst_ximage_src_ximage_get (GstXImageSrc * ximagesrc) GUINT_TO_LE (ximagesrc->cursor_image->pixels[i]); /* copy those pixels across */ for (j = starty; - j < starty + iheight && j < ximagesrc->starty + ximagesrc->height; - j++) { + j < starty + iheight + && j < ximagesrc->starty + ximagesrc->height; j++) { for (i = startx; - i < startx + iwidth && i < ximagesrc->startx + ximagesrc->width; - i++) { + i < startx + iwidth + && i < ximagesrc->startx + ximagesrc->width; i++) { guint8 *src, *dest; src = @@ -788,8 +798,8 @@ gst_ximage_src_ximage_get (GstXImageSrc * ximagesrc) dest = (guint8 *) & (meta->ximage->data[((j - ximagesrc->starty) * ximagesrc->width + (i - - ximagesrc->startx)) * (ximagesrc->xcontext->bpp / - 8)]); + ximagesrc->startx)) * + (ximagesrc->xcontext->bpp / 8)]); composite_pixel (ximagesrc->xcontext, (guint8 *) dest, (guint8 *) src); @@ -963,8 +973,8 @@ gst_ximage_src_set_property (GObject * object, guint prop_id, } static void -gst_ximage_src_get_property (GObject * object, guint prop_id, GValue * value, - GParamSpec * pspec) +gst_ximage_src_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) { GstXImageSrc *src = GST_XIMAGE_SRC (object); @@ -1116,16 +1126,16 @@ gst_ximage_src_get_caps (GstBaseSrc * bs, GstCaps * filter) format = gst_video_format_from_masks (xcontext->depth, xcontext->bpp, - xcontext->endianness, xcontext->r_mask_output, xcontext->g_mask_output, - xcontext->b_mask_output, alpha_mask); + xcontext->endianness, xcontext->r_mask_output, + xcontext->g_mask_output, xcontext->b_mask_output, alpha_mask); return gst_caps_new_simple ("video/x-raw", "format", G_TYPE_STRING, gst_video_format_to_string (format), "width", G_TYPE_INT, width, "height", G_TYPE_INT, height, "framerate", GST_TYPE_FRACTION_RANGE, 1, G_MAXINT, G_MAXINT, 1, - "pixel-aspect-ratio", GST_TYPE_FRACTION, xcontext->par_n, xcontext->par_d, - NULL); + "pixel-aspect-ratio", GST_TYPE_FRACTION, xcontext->par_n, + xcontext->par_d, NULL); } static gboolean @@ -1186,8 +1196,8 @@ gst_ximage_src_class_init (GstXImageSrcClass * klass) gc->finalize = gst_ximage_src_finalize; g_object_class_install_property (gc, PROP_DISPLAY_NAME, - g_param_spec_string ("display-name", "Display", "X Display Name", NULL, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_param_spec_string ("display-name", "Display", "X Display Name", + NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gc, PROP_SHOW_POINTER, g_param_spec_boolean ("show-pointer", "Show Mouse Pointer", "Show mouse pointer (if XFixes extension enabled)", TRUE,