Bug 1287666 - Avoid a round trip to the X server in nsShmImage::CreateDrawTarget. r=lsalzman
authorAndrew Comminos <andrew@comminos.com>
Thu, 21 Jul 2016 13:41:09 -0400
changeset 306486 ddcceb6bf9a6e4a1dc12df5967d78674f7d0bd62
parent 306485 eb5d2f565ba413cc423e35c93e1c1df67dfe1317
child 306487 46de97426f7b5467a37e1512ed022f2908d8626a
push id30487
push usercbook@mozilla.com
push dateTue, 26 Jul 2016 09:54:38 +0000
treeherdermozilla-central@215d196020ff [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerslsalzman
bugs1287666
milestone50.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1287666 - Avoid a round trip to the X server in nsShmImage::CreateDrawTarget. r=lsalzman MozReview-Commit-ID: LpvsntOCMab
widget/nsShmImage.cpp
widget/nsShmImage.h
--- a/widget/nsShmImage.cpp
+++ b/widget/nsShmImage.cpp
@@ -27,28 +27,24 @@ nsShmImage::nsShmImage(Display* aDisplay
                        unsigned int aDepth)
   : mWindow(aWindow)
   , mVisual(aVisual)
   , mDepth(aDepth)
   , mFormat(mozilla::gfx::SurfaceFormat::UNKNOWN)
   , mSize(0, 0)
   , mPixmap(XCB_NONE)
   , mGC(XCB_NONE)
+  , mRequestPending(false)
   , mShmSeg(XCB_NONE)
   , mShmId(-1)
   , mShmAddr(nullptr)
 {
   mConnection = XGetXCBConnection(aDisplay);
-  mozilla::PodZero(&mLastRequest);
-  if (aDisplay == mozilla::DefaultXDisplay()) {
-    // If another thread spins the X event loop during a checked call,
-    // an error that should've been checked by XCB may be handled by the Xlib
-    // error handler. See bug 1287463.
-    NS_WARNING("Main thread X display used with nsShmImage!");
-  }
+  mozilla::PodZero(&mPutRequest);
+  mozilla::PodZero(&mSyncRequest);
 }
 
 nsShmImage::~nsShmImage()
 {
   DestroyImage();
 }
 
 // If XShm isn't available to our client, we'll try XShm once, fail,
@@ -245,23 +241,29 @@ nsShmImage::DestroyImage()
 }
 
 already_AddRefed<DrawTarget>
 nsShmImage::CreateDrawTarget(const mozilla::LayoutDeviceIntRegion& aRegion)
 {
   // Wait for any in-flight requests to complete.
   // Typically X clients would wait for a XShmCompletionEvent to be received,
   // but this works as it's sent immediately after the request is processed.
-  xcb_generic_error_t* error;
-  if (mLastRequest.sequence != XCB_NONE &&
-      (error = xcb_request_check(mConnection, mLastRequest)))
-  {
-    gShmAvailable = false;
-    free(error);
-    return nullptr;
+  if (mRequestPending) {
+    xcb_get_input_focus_reply_t* reply;
+    if ((reply = xcb_get_input_focus_reply(mConnection, mSyncRequest, nullptr))) {
+      free(reply);
+    }
+    mRequestPending = false;
+
+    xcb_generic_error_t* error;
+    if ((error = xcb_request_check(mConnection, mPutRequest))) {
+      gShmAvailable = false;
+      free(error);
+      return nullptr;
+    }
   }
 
   // Due to bug 1205045, we must avoid making GTK calls off the main thread to query window size.
   // Instead we just track the largest offset within the image we are drawing to and grow the image
   // to accomodate it. Since usually the entire window is invalidated on the first paint to it,
   // this should grow the image to the necessary size quickly without many intermediate reallocations.
   IntRect bounds = aRegion.GetBounds().ToUnknownRect();
   IntSize size(bounds.XMost(), bounds.YMost());
@@ -296,23 +298,28 @@ nsShmImage::Put(const mozilla::LayoutDev
     mGC = xcb_generate_id(mConnection);
     xcb_create_gc(mConnection, mGC, mWindow, 0, nullptr);
   }
 
   xcb_set_clip_rectangles(mConnection, XCB_CLIP_ORDERING_YX_BANDED, mGC, 0, 0,
                           xrects.Length(), xrects.Elements());
 
   if (mPixmap != XCB_NONE) {
-    mLastRequest = xcb_copy_area_checked(mConnection, mPixmap, mWindow, mGC,
-                                         0, 0, 0, 0, mSize.width, mSize.height);
+    mPutRequest = xcb_copy_area_checked(mConnection, mPixmap, mWindow, mGC,
+                                        0, 0, 0, 0, mSize.width, mSize.height);
   } else {
-    mLastRequest = xcb_shm_put_image_checked(mConnection, mWindow, mGC,
-                                             mSize.width, mSize.height,
-                                             0, 0, mSize.width, mSize.height,
-                                             0, 0, mDepth,
-                                             XCB_IMAGE_FORMAT_Z_PIXMAP, 0,
-                                             mShmSeg, 0);
+    mPutRequest = xcb_shm_put_image_checked(mConnection, mWindow, mGC,
+                                            mSize.width, mSize.height,
+                                            0, 0, mSize.width, mSize.height,
+                                            0, 0, mDepth,
+                                            XCB_IMAGE_FORMAT_Z_PIXMAP, 0,
+                                            mShmSeg, 0);
   }
 
+  // Send a request that returns a response so that we don't have to start a
+  // sync in nsShmImage::CreateDrawTarget to retrieve the result of mPutRequest.
+  mSyncRequest = xcb_get_input_focus(mConnection);
+  mRequestPending = true;
+
   xcb_flush(mConnection);
 }
 
 #endif  // MOZ_HAVE_SHMIMAGE
--- a/widget/nsShmImage.h
+++ b/widget/nsShmImage.h
@@ -53,17 +53,19 @@ private:
   Visual*                      mVisual;
   unsigned int                 mDepth;
 
   mozilla::gfx::SurfaceFormat  mFormat;
   mozilla::gfx::IntSize        mSize;
 
   xcb_pixmap_t                 mPixmap;
   xcb_gcontext_t               mGC;
-  xcb_void_cookie_t            mLastRequest;
+  xcb_void_cookie_t            mPutRequest;
+  xcb_get_input_focus_cookie_t mSyncRequest;
+  bool                         mRequestPending;
 
   xcb_shm_seg_t                mShmSeg;
   int                          mShmId;
   uint8_t*                     mShmAddr;
 };
 
 #endif // MOZ_HAVE_SHMIMAGE