XShmCreatePixmap() as copy dest for XCopyArea()

xorg at pengaru.com xorg at pengaru.com
Thu Jul 9 00:48:02 UTC 2020


On Wed, Jul 08, 2020 at 11:27:32AM -0400, Adam Jackson wrote:
> On Tue, 2020-07-07 at 13:13 -0700, xorg at pengaru.com wrote:
> > Hello list,
> > 
> > I'm trying to use XShmCreatePixmap() in combination with XCopyArea()
> > to achieve something resembling an XShmGetSubImage() for copying
> > damaged areas piecemeal out of the root window into a shmseg for a
> > screencap tool.
> 
> MIT-SHM pixmap support is optional, and often not supported because for
> most modern X drivers it's a pessimization. I think there happens to be
> a bug in glamor where we claim to support shm pixmaps but don't
> actually implement it correctly; does your test case work if you
> disable acceleration in xorg.conf?
> 

I'd tried intel and modesetting drivers with the same results, just
now tried noaccel on intel and it seems to not matter.  But see below,
I think I've figured out my problem.

> > It seems like no matter what I do, the XCopyArea() never actually
> > writes to the shmseg.  If instead I use XShmGetImage() with the same
> > source drawable (root) and an XShmImage created from the very same
> > shminfo as the XShmPixmap, my shmseg gets written to just fine - but
> > it fills the entire XShmImage on every update which I'd like to
> > avoid.
> 
> XShmGetImage is an awkward API, yeah. The width and height of the image
> to download are derived from the XImage, not the drawable; if you
> create a shm segment exactly as large as the region you want to copy
> it'll do what you want. See the source (sigh) for more details:
> 
> https://gitlab.freedesktop.org/xorg/lib/libxext/-/blob/master/src/XShm.c#L373
> 
> Strictly speaking, you can just munge image->{width,height} before
> sending the request instead of creating a new one, you'll just have to
> compensate for that when you read the pixels back out of it.
> 

The trouble with the ShmGetImage request is it doesn't supply a
destination stride, so you can't possibly coax it into copying small
damage areas into a larger mirror maintained directly in the shmseg.

I'd basically have to treat the shmseg as a pipe instead, and do a
second copy client-side out of the shmseg into the larger mirror
buffer, for every damaged area.  Which is undesirable when the whole
goal is to minimize copying.

While replying to your email I realized something: I'm not using a
composited desktop, and don't have a wallpaper or anything, so my root
window is blank.

Thinking again about how XCopyArea() takes a GC and XShmGetImage()
doesn't, I toggled compositing and re-ran the XCopyArea() test now
that compositing would be putting everything into the root window.

It worked!  The XCopyArea() was producing the expected contents.
So maybe this is just a matter of setting IncludeInferiors on the
copying GC, does that sound right?

While I've got your attention, do you know of a more efficient means
of getting this data out of the X server for screencap purposes?  I'm
currently encoding video directly from the shmseg, XShmGetImage()
works fine for full-frame captures without using damage but I need the
XCopyArea() w/XShmPixmap for the damage-tracking mode.  Maybe I can
throw all of this away if there's an entirely different superior
approach...

Thanks a lot for the feedback, it indirectly was quite helpful in
making me think more about my code and less about potential Xorg bugs
to see noaccel make no difference.

Cheers,
Vito Caputo


More information about the xorg-devel mailing list