13d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org/*
23d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org *  Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
33d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org *
43d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org *  Use of this source code is governed by a BSD-style license
53d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org *  that can be found in the LICENSE file in the root of the source
63d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org *  tree. An additional intellectual property rights grant can be found
73d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org *  in the file PATENTS.  All contributing project authors may
83d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org *  be found in the AUTHORS file in the root of the source tree.
93d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org */
103d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
113d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org#include "webrtc/modules/desktop_capture/x11/x_server_pixel_buffer.h"
123d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
1312dc1a38ca54a000e4fecfbc6d41138b895c9ca5pbos@webrtc.org#include <assert.h>
149f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org#include <string.h>
153d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org#include <sys/shm.h>
163d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
179f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org#include "webrtc/modules/desktop_capture/desktop_frame.h"
189f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org#include "webrtc/modules/desktop_capture/x11/x_error_trap.h"
1998f53510b222f71fdd8b799b2f33737ceeb28c61Henrik Kjellander#include "webrtc/system_wrappers/include/logging.h"
203d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
213d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.orgnamespace {
223d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
239f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org// Returns the number of bits |mask| has to be shifted left so its last
249f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org// (most-significant) bit set becomes the most-significant bit of the word.
259f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org// When |mask| is 0 the function returns 31.
269f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.orguint32_t MaskToShift(uint32_t mask) {
279f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org  int shift = 0;
289f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org  if ((mask & 0xffff0000u) == 0) {
299f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org    mask <<= 16;
309f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org    shift += 16;
319f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org  }
329f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org  if ((mask & 0xff000000u) == 0) {
339f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org    mask <<= 8;
349f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org    shift += 8;
359f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org  }
369f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org  if ((mask & 0xf0000000u) == 0) {
379f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org    mask <<= 4;
389f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org    shift += 4;
399f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org  }
409f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org  if ((mask & 0xc0000000u) == 0) {
419f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org    mask <<= 2;
429f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org    shift += 2;
439f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org  }
449f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org  if ((mask & 0x80000000u) == 0)
459f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org    shift += 1;
463d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
479f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org  return shift;
483d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org}
493d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
509f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org// Returns true if |image| is in RGB format.
519f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.orgbool IsXImageRGBFormat(XImage* image) {
529f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org  return image->bits_per_pixel == 32 &&
539f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org      image->red_mask == 0xff0000 &&
549f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org      image->green_mask == 0xff00 &&
559f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org      image->blue_mask == 0xff;
563d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org}
573d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
583d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org}  // namespace
593d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
603d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.orgnamespace webrtc {
613d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
623d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.orgXServerPixelBuffer::XServerPixelBuffer()
639f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org    : display_(NULL), window_(0),
643d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org      x_image_(NULL),
653d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org      shm_segment_info_(NULL), shm_pixmap_(0), shm_gc_(NULL) {
663d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org}
673d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
683d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.orgXServerPixelBuffer::~XServerPixelBuffer() {
693d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  Release();
703d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org}
713d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
723d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.orgvoid XServerPixelBuffer::Release() {
733d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  if (x_image_) {
743d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org    XDestroyImage(x_image_);
753d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org    x_image_ = NULL;
763d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  }
773d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  if (shm_pixmap_) {
783d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org    XFreePixmap(display_, shm_pixmap_);
793d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org    shm_pixmap_ = 0;
803d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  }
813d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  if (shm_gc_) {
823d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org    XFreeGC(display_, shm_gc_);
833d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org    shm_gc_ = NULL;
843d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  }
853d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  if (shm_segment_info_) {
863d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org    if (shm_segment_info_->shmaddr != reinterpret_cast<char*>(-1))
873d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org      shmdt(shm_segment_info_->shmaddr);
883d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org    if (shm_segment_info_->shmid != -1)
893d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org      shmctl(shm_segment_info_->shmid, IPC_RMID, 0);
903d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org    delete shm_segment_info_;
913d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org    shm_segment_info_ = NULL;
923d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  }
939f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org  window_ = 0;
943d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org}
953d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
969f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.orgbool XServerPixelBuffer::Init(Display* display, Window window) {
973d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  Release();
983d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  display_ = display;
993d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
1009f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org  XWindowAttributes attributes;
1019f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org  {
1029f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org    XErrorTrap error_trap(display_);
1039f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org    if (!XGetWindowAttributes(display_, window, &attributes) ||
1049f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org        error_trap.GetLastErrorAndDisable() != 0) {
1059f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org      return false;
1069f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org    }
1079f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org  }
1089f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org
1099f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org  window_size_ = DesktopSize(attributes.width, attributes.height);
1109f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org  window_ = window;
1119f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org  InitShm(attributes);
1129f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org
1139f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org  return true;
1143d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org}
1153d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
1169f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.orgvoid XServerPixelBuffer::InitShm(const XWindowAttributes& attributes) {
1179f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org  Visual* default_visual = attributes.visual;
1189f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org  int default_depth = attributes.depth;
1193d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
1203d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  int major, minor;
1219f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org  Bool have_pixmaps;
1229f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org  if (!XShmQueryVersion(display_, &major, &minor, &have_pixmaps)) {
1233d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org    // Shared memory not supported. CaptureRect will use the XImage API instead.
1243d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org    return;
1259f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org  }
1263d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
1273d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  bool using_shm = false;
1283d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  shm_segment_info_ = new XShmSegmentInfo;
1293d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  shm_segment_info_->shmid = -1;
1303d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  shm_segment_info_->shmaddr = reinterpret_cast<char*>(-1);
1313d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  shm_segment_info_->readOnly = False;
1323d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  x_image_ = XShmCreateImage(display_, default_visual, default_depth, ZPixmap,
1339f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org                             0, shm_segment_info_, window_size_.width(),
1349f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org                             window_size_.height());
1353d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  if (x_image_) {
1363d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org    shm_segment_info_->shmid = shmget(
1373d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org        IPC_PRIVATE, x_image_->bytes_per_line * x_image_->height,
1383d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org        IPC_CREAT | 0600);
1393d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org    if (shm_segment_info_->shmid != -1) {
1403d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org      shm_segment_info_->shmaddr = x_image_->data =
1413d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org          reinterpret_cast<char*>(shmat(shm_segment_info_->shmid, 0, 0));
1423d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org      if (x_image_->data != reinterpret_cast<char*>(-1)) {
1439f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org        XErrorTrap error_trap(display_);
1443d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org        using_shm = XShmAttach(display_, shm_segment_info_);
1453d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org        XSync(display_, False);
1469f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org        if (error_trap.GetLastErrorAndDisable() != 0)
1473d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org          using_shm = false;
1483d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org        if (using_shm) {
1493d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org          LOG(LS_VERBOSE) << "Using X shared memory segment "
1503d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org                          << shm_segment_info_->shmid;
1513d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org        }
1523d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org      }
1533d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org    } else {
1543d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org      LOG(LS_WARNING) << "Failed to get shared memory segment. "
1553d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org                      "Performance may be degraded.";
1563d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org    }
1573d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  }
1583d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
1593d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  if (!using_shm) {
1603d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org    LOG(LS_WARNING) << "Not using shared memory. Performance may be degraded.";
1613d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org    Release();
1623d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org    return;
1633d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  }
1643d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
1659f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org  if (have_pixmaps)
1669f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org    have_pixmaps = InitPixmaps(default_depth);
1673d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
1683d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  shmctl(shm_segment_info_->shmid, IPC_RMID, 0);
1693d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  shm_segment_info_->shmid = -1;
1703d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
1713d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  LOG(LS_VERBOSE) << "Using X shared memory extension v"
1723d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org                  << major << "." << minor
1739f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org                  << " with" << (have_pixmaps ? "" : "out") << " pixmaps.";
1743d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org}
1753d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
1763d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.orgbool XServerPixelBuffer::InitPixmaps(int depth) {
1773d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  if (XShmPixmapFormat(display_) != ZPixmap)
1783d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org    return false;
1793d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
1809f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org  {
1819f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org    XErrorTrap error_trap(display_);
1829f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org    shm_pixmap_ = XShmCreatePixmap(display_, window_,
1839f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org                                   shm_segment_info_->shmaddr,
1849f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org                                   shm_segment_info_,
1859f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org                                   window_size_.width(),
1869f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org                                   window_size_.height(), depth);
1879f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org    XSync(display_, False);
1889f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org    if (error_trap.GetLastErrorAndDisable() != 0) {
1899f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org      // |shm_pixmap_| is not not valid because the request was not processed
1909f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org      // by the X Server, so zero it.
1919f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org      shm_pixmap_ = 0;
1929f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org      return false;
1939f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org    }
1943d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  }
1953d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
1969f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org  {
1979f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org    XErrorTrap error_trap(display_);
1989f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org    XGCValues shm_gc_values;
1999f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org    shm_gc_values.subwindow_mode = IncludeInferiors;
2009f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org    shm_gc_values.graphics_exposures = False;
2019f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org    shm_gc_ = XCreateGC(display_, window_,
2029f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org                        GCSubwindowMode | GCGraphicsExposures,
2039f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org                        &shm_gc_values);
2049f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org    XSync(display_, False);
2059f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org    if (error_trap.GetLastErrorAndDisable() != 0) {
2069f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org      XFreePixmap(display_, shm_pixmap_);
2079f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org      shm_pixmap_ = 0;
2089f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org      shm_gc_ = 0;  // See shm_pixmap_ comment above.
2099f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org      return false;
2109f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org    }
2113d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  }
2123d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
2133d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  return true;
2143d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org}
2153d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
216cc1ba15fe737bfc58ef279d50d7e713cbd8b9310jiayl@webrtc.orgbool XServerPixelBuffer::IsWindowValid() const {
217cc1ba15fe737bfc58ef279d50d7e713cbd8b9310jiayl@webrtc.org  XWindowAttributes attributes;
218cc1ba15fe737bfc58ef279d50d7e713cbd8b9310jiayl@webrtc.org  {
219cc1ba15fe737bfc58ef279d50d7e713cbd8b9310jiayl@webrtc.org    XErrorTrap error_trap(display_);
220cc1ba15fe737bfc58ef279d50d7e713cbd8b9310jiayl@webrtc.org    if (!XGetWindowAttributes(display_, window_, &attributes) ||
221cc1ba15fe737bfc58ef279d50d7e713cbd8b9310jiayl@webrtc.org        error_trap.GetLastErrorAndDisable() != 0) {
222cc1ba15fe737bfc58ef279d50d7e713cbd8b9310jiayl@webrtc.org      return false;
223cc1ba15fe737bfc58ef279d50d7e713cbd8b9310jiayl@webrtc.org    }
224cc1ba15fe737bfc58ef279d50d7e713cbd8b9310jiayl@webrtc.org  }
225cc1ba15fe737bfc58ef279d50d7e713cbd8b9310jiayl@webrtc.org  return true;
226cc1ba15fe737bfc58ef279d50d7e713cbd8b9310jiayl@webrtc.org}
227cc1ba15fe737bfc58ef279d50d7e713cbd8b9310jiayl@webrtc.org
2283d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.orgvoid XServerPixelBuffer::Synchronize() {
2293d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  if (shm_segment_info_ && !shm_pixmap_) {
2303d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org    // XShmGetImage can fail if the display is being reconfigured.
2319f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org    XErrorTrap error_trap(display_);
2329f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org    XShmGetImage(display_, window_, x_image_, 0, 0, AllPlanes);
2333d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  }
2343d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org}
2353d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
2369f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.orgvoid XServerPixelBuffer::CaptureRect(const DesktopRect& rect,
2379f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org                                     DesktopFrame* frame) {
2389f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org  assert(rect.right() <= window_size_.width());
2399f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org  assert(rect.bottom() <= window_size_.height());
2409f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org
2419f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org  uint8_t* data;
2423d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
2433d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  if (shm_segment_info_) {
2443d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org    if (shm_pixmap_) {
2459f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org      XCopyArea(display_, window_, shm_pixmap_, shm_gc_,
2463d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org                rect.left(), rect.top(), rect.width(), rect.height(),
2473d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org                rect.left(), rect.top());
2483d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org      XSync(display_, False);
2493d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org    }
2509f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org    data = reinterpret_cast<uint8_t*>(x_image_->data) +
2513d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org        rect.top() * x_image_->bytes_per_line +
2523d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org        rect.left() * x_image_->bits_per_pixel / 8;
2533d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  } else {
2543d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org    if (x_image_)
2553d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org      XDestroyImage(x_image_);
2569f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org    x_image_ = XGetImage(display_, window_, rect.left(), rect.top(),
2573d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org                         rect.width(), rect.height(), AllPlanes, ZPixmap);
2589f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org    data = reinterpret_cast<uint8_t*>(x_image_->data);
2593d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  }
2603d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
2619f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org  if (IsXImageRGBFormat(x_image_)) {
2629f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org    FastBlit(data, rect, frame);
2639f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org  } else {
2649f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org    SlowBlit(data, rect, frame);
2659f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org  }
2663d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org}
2673d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
2689f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.orgvoid XServerPixelBuffer::FastBlit(uint8_t* image,
2699f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org                                  const DesktopRect& rect,
2709f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org                                  DesktopFrame* frame) {
2719f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org  uint8_t* src_pos = image;
2729f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org  int src_stride = x_image_->bytes_per_line;
2739f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org  int dst_x = rect.left(), dst_y = rect.top();
2749f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org
2759f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org  uint8_t* dst_pos = frame->data() + frame->stride() * dst_y;
2769f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org  dst_pos += dst_x * DesktopFrame::kBytesPerPixel;
2779f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org
2789f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org  int height = rect.height();
2799f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org  int row_bytes = rect.width() * DesktopFrame::kBytesPerPixel;
2809f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org  for (int y = 0; y < height; ++y) {
2819f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org    memcpy(dst_pos, src_pos, row_bytes);
2829f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org    src_pos += src_stride;
2839f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org    dst_pos += frame->stride();
2849f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org  }
2853d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org}
2863d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
2879f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.orgvoid XServerPixelBuffer::SlowBlit(uint8_t* image,
2889f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org                                  const DesktopRect& rect,
2899f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org                                  DesktopFrame* frame) {
2909f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org  int src_stride = x_image_->bytes_per_line;
2919f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org  int dst_x = rect.left(), dst_y = rect.top();
2929f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org  int width = rect.width(), height = rect.height();
2939f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org
2949f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org  uint32_t red_mask = x_image_->red_mask;
2959f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org  uint32_t green_mask = x_image_->red_mask;
2969f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org  uint32_t blue_mask = x_image_->blue_mask;
2979f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org
2989f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org  uint32_t red_shift = MaskToShift(red_mask);
2999f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org  uint32_t green_shift = MaskToShift(green_mask);
3009f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org  uint32_t blue_shift = MaskToShift(blue_mask);
3019f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org
3029f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org  int bits_per_pixel = x_image_->bits_per_pixel;
3039f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org
3049f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org  uint8_t* dst_pos = frame->data() + frame->stride() * dst_y;
3059f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org  uint8_t* src_pos = image;
3069f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org  dst_pos += dst_x * DesktopFrame::kBytesPerPixel;
3079f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org  // TODO(hclam): Optimize, perhaps using MMX code or by converting to
3089f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org  // YUV directly.
3099f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org  // TODO(sergeyu): This code doesn't handle XImage byte order properly and
3109f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org  // won't work with 24bpp images. Fix it.
3119f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org  for (int y = 0; y < height; y++) {
3129f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org    uint32_t* dst_pos_32 = reinterpret_cast<uint32_t*>(dst_pos);
3139f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org    uint32_t* src_pos_32 = reinterpret_cast<uint32_t*>(src_pos);
3149f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org    uint16_t* src_pos_16 = reinterpret_cast<uint16_t*>(src_pos);
3159f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org    for (int x = 0; x < width; x++) {
3169f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org      // Dereference through an appropriately-aligned pointer.
3179f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org      uint32_t pixel;
3189f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org      if (bits_per_pixel == 32) {
3199f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org        pixel = src_pos_32[x];
3209f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org      } else if (bits_per_pixel == 16) {
3219f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org        pixel = src_pos_16[x];
3229f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org      } else {
3239f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org        pixel = src_pos[x];
3249f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org      }
3259f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org      uint32_t r = (pixel & red_mask) << red_shift;
3269f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org      uint32_t g = (pixel & green_mask) << green_shift;
3279f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org      uint32_t b = (pixel & blue_mask) << blue_shift;
3289f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org      // Write as 32-bit RGB.
3299f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org      dst_pos_32[x] = ((r >> 8) & 0xff0000) | ((g >> 16) & 0xff00) |
3309f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org          ((b >> 24) & 0xff);
3319f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org    }
3329f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org    dst_pos += frame->stride();
3339f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org    src_pos += src_stride;
3349f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org  }
3353d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org}
3363d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
3373d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org}  // namespace webrtc
338