Skip to content

Commit

Permalink
#899 speedup the X11 shadow server using the XShm code to capture the…
Browse files Browse the repository at this point in the history
… pixels

git-svn-id: https://xpra.org/svn/Xpra/trunk@10246 3bb7dfac-3a0b-4e04-842a-767bc560f471
  • Loading branch information
totaam committed Aug 9, 2015
1 parent ed6d377 commit 172d0ac
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 7 deletions.
4 changes: 4 additions & 0 deletions src/xpra/server/shadow_server_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ def __init__(self, root_window):
self.dynamic_property_names = []
self.internal_property_names = []

def suspend(self):
pass

def is_managed(self):
return True

Expand Down Expand Up @@ -250,6 +253,7 @@ def _process_unmap_window(self, proto, packet):
for ss in self._server_sources.values():
ss.unmap_window(wid, window)
self.mapped_at = None
self.root_window_model.suspend()

def _process_configure_window(self, proto, packet):
wid, x, y, w, h = packet[1:6]
Expand Down
14 changes: 7 additions & 7 deletions src/xpra/x11/bindings/ximage.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -507,29 +507,29 @@ cdef class XShmWrapper(object):
def get_size(self): #@DuplicatedSignature
return self.width, self.height

def get_image(self, Pixmap xpixmap, int x, int y, int w, int h):
def get_image(self, Drawable drawable, int x, int y, int w, int h):
assert self.image!=NULL, "cannot retrieve image wrapper: XImage is NULL!"
if self.closed:
return None
if x>=self.width or y>=self.height:
xshmlog("XShmWrapper.get_image%s position outside image dimensions %ix%i", (xpixmap, x, y, w, h), self.width, self.height)
xshmlog("XShmWrapper.get_image%s position outside image dimensions %ix%i", (drawable, x, y, w, h), self.width, self.height)
return None
#clamp size to image size:
if x+w>self.width:
w = self.width-x
if y+h>self.height:
h = self.height-y
if not self.got_image:
if not XShmGetImage(self.display, xpixmap, self.image, 0, 0, 0xFFFFFFFF):
xshmlog("XShmWrapper.get_image(%#x, %i, %i, %i, %i) XShmGetImage failed!", xpixmap, x, y, w, h)
if not XShmGetImage(self.display, drawable, self.image, 0, 0, 0xFFFFFFFF):
xshmlog("XShmWrapper.get_image(%#x, %i, %i, %i, %i) XShmGetImage failed!", drawable, x, y, w, h)
return None
self.got_image = True
self.ref_count += 1
cdef XShmImageWrapper imageWrapper
imageWrapper = XShmImageWrapper(x, y, w, h)
imageWrapper.set_image(self.image)
imageWrapper.set_free_callback(self.free_image_callback)
xshmdebug("XShmWrapper.get_image(%#x, %i, %i, %i, %i)=%s (ref_count=%i)", xpixmap, x, y, w, h, imageWrapper, self.ref_count)
xshmdebug("XShmWrapper.get_image(%#x, %i, %i, %i, %i)=%s (ref_count=%i)", drawable, x, y, w, h, imageWrapper, self.ref_count)
return imageWrapper

def discard(self):
Expand Down Expand Up @@ -725,8 +725,8 @@ cdef class XImageBindings(X11CoreBindings):
xshm.init(self.display, xwindow, attrs.visual, attrs.width, attrs.height, attrs.depth)
return xshm

def get_ximage(self, xpixmap, x, y, width, height): #@DuplicatedSignature
return get_image(self.display, xpixmap, x, y, width, height)
def get_ximage(self, drawable, x, y, width, height): #@DuplicatedSignature
return get_image(self.display, drawable, x, y, width, height)

def get_xcomposite_pixmap(self, xwindow):
return xcomposite_name_window_pixmap(self.display, xwindow)
49 changes: 49 additions & 0 deletions src/xpra/x11/shadow_x11_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,67 @@
# Xpra is released under the terms of the GNU GPL v2, or, at your option, any
# later version. See the file COPYING for details.

import os, time

from xpra.gtk_common.gtk_util import get_xwindow, get_default_root_window
from xpra.x11.x11_server_base import X11ServerBase
from xpra.server.shadow_server_base import ShadowServerBase
from xpra.server.gtk_root_window_model import GTKRootWindowModel
from xpra.x11.bindings.ximage import XImageBindings #@UnresolvedImport
from xpra.gtk_common.error import xsync
XImage = XImageBindings()

from xpra.log import Logger
log = Logger("x11", "shadow")

USE_XSHM = os.environ.get("XPRA_XSHM", "1")=="1"


class GTKX11RootWindowModel(GTKRootWindowModel):

def __init__(self, root_window):
GTKRootWindowModel.__init__(self, root_window)
self.xshm = None

def __repr__(self):
return "GTKX11RootWindowModel(%#x)" % get_xwindow(self.window)

def suspend(self):
#we can cleanup the current xshm area and we'll create a new one later
self.cleanup()

def cleanup(self):
if self.xshm:
with xsync:
self.xshm.cleanup()
self.xshm = None


def get_image(self, x, y, width, height, logger=None):
try:
start = time.time()
with xsync:
if USE_XSHM:
log("X11 shadow get_image, xshm=%s", self.xshm)
if self.xshm is None:
self.xshm = XImage.get_XShmWrapper(get_xwindow(self.window))
self.xshm.setup()
if self.xshm:
image = self.xshm.get_image(get_xwindow(self.window), x, y, width, height)
#discard to ensure we will call XShmGetImage next time around
self.xshm.discard()
return image
#fallback to gtk capture:
return GTKRootWindowModel.get_image(self, x, y, width, height, logger)
except Exception as e:
log.warn("Warning: failed to capture root window pixels:")
log.warn(" %s", e)
#cleanup and hope for the best!
self.cleanup()
finally:
end = time.time()
log("X11 shadow captured %s pixels at %i MPixels/s using %s", width*height, (width*height/(end-start))//1024//1024, ["GTK", "XSHM"][USE_XSHM])


class ShadowX11Server(ShadowServerBase, X11ServerBase):

Expand Down

0 comments on commit 172d0ac

Please sign in to comment.