16c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org/* 26c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. 36c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org * 46c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org * Use of this source code is governed by a BSD-style license 56c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org * that can be found in the LICENSE file in the root of the source 66c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org * tree. An additional intellectual property rights grant can be found 76c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org * in the file PATENTS. All contributing project authors may 86c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org * be found in the AUTHORS file in the root of the source tree. 96c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org */ 106c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org 116c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org#include "webrtc/modules/desktop_capture/x11/x_server_pixel_buffer.h" 126c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org 133f45c2e0ac4cb280f941efa3a3476895795e3dd6pbos@webrtc.org#include <assert.h> 14e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org#include <string.h> 156c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org#include <sys/shm.h> 166c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org 17e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org#include "webrtc/modules/desktop_capture/desktop_frame.h" 18e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org#include "webrtc/modules/desktop_capture/x11/x_error_trap.h" 196c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org#include "webrtc/system_wrappers/interface/logging.h" 206c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org 216c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.orgnamespace { 226c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org 23e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org// Returns the number of bits |mask| has to be shifted left so its last 24e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org// (most-significant) bit set becomes the most-significant bit of the word. 25e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org// When |mask| is 0 the function returns 31. 26e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.orguint32_t MaskToShift(uint32_t mask) { 27e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org int shift = 0; 28e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org if ((mask & 0xffff0000u) == 0) { 29e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org mask <<= 16; 30e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org shift += 16; 31e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org } 32e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org if ((mask & 0xff000000u) == 0) { 33e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org mask <<= 8; 34e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org shift += 8; 35e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org } 36e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org if ((mask & 0xf0000000u) == 0) { 37e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org mask <<= 4; 38e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org shift += 4; 39e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org } 40e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org if ((mask & 0xc0000000u) == 0) { 41e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org mask <<= 2; 42e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org shift += 2; 43e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org } 44e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org if ((mask & 0x80000000u) == 0) 45e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org shift += 1; 466c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org 47e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org return shift; 486c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org} 496c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org 50e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org// Returns true if |image| is in RGB format. 51e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.orgbool IsXImageRGBFormat(XImage* image) { 52e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org return image->bits_per_pixel == 32 && 53e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org image->red_mask == 0xff0000 && 54e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org image->green_mask == 0xff00 && 55e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org image->blue_mask == 0xff; 566c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org} 576c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org 586c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org} // namespace 596c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org 606c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.orgnamespace webrtc { 616c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org 626c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.orgXServerPixelBuffer::XServerPixelBuffer() 63e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org : display_(NULL), window_(0), 646c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org x_image_(NULL), 656c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org shm_segment_info_(NULL), shm_pixmap_(0), shm_gc_(NULL) { 666c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org} 676c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org 686c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.orgXServerPixelBuffer::~XServerPixelBuffer() { 696c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org Release(); 706c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org} 716c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org 726c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.orgvoid XServerPixelBuffer::Release() { 736c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org if (x_image_) { 746c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org XDestroyImage(x_image_); 756c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org x_image_ = NULL; 766c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org } 776c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org if (shm_pixmap_) { 786c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org XFreePixmap(display_, shm_pixmap_); 796c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org shm_pixmap_ = 0; 806c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org } 816c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org if (shm_gc_) { 826c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org XFreeGC(display_, shm_gc_); 836c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org shm_gc_ = NULL; 846c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org } 856c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org if (shm_segment_info_) { 866c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org if (shm_segment_info_->shmaddr != reinterpret_cast<char*>(-1)) 876c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org shmdt(shm_segment_info_->shmaddr); 886c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org if (shm_segment_info_->shmid != -1) 896c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org shmctl(shm_segment_info_->shmid, IPC_RMID, 0); 906c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org delete shm_segment_info_; 916c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org shm_segment_info_ = NULL; 926c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org } 93e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org window_ = 0; 946c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org} 956c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org 96e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.orgbool XServerPixelBuffer::Init(Display* display, Window window) { 976c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org Release(); 986c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org display_ = display; 996c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org 100e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org XWindowAttributes attributes; 101e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org { 102e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org XErrorTrap error_trap(display_); 103e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org if (!XGetWindowAttributes(display_, window, &attributes) || 104e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org error_trap.GetLastErrorAndDisable() != 0) { 105e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org return false; 106e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org } 107e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org } 108e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org 109e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org window_size_ = DesktopSize(attributes.width, attributes.height); 110e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org window_ = window; 111e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org InitShm(attributes); 112e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org 113e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org return true; 1146c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org} 1156c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org 116e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.orgvoid XServerPixelBuffer::InitShm(const XWindowAttributes& attributes) { 117e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org Visual* default_visual = attributes.visual; 118e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org int default_depth = attributes.depth; 1196c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org 1206c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org int major, minor; 121e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org Bool have_pixmaps; 122e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org if (!XShmQueryVersion(display_, &major, &minor, &have_pixmaps)) { 1236c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org // Shared memory not supported. CaptureRect will use the XImage API instead. 1246c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org return; 125e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org } 1266c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org 1276c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org bool using_shm = false; 1286c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org shm_segment_info_ = new XShmSegmentInfo; 1296c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org shm_segment_info_->shmid = -1; 1306c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org shm_segment_info_->shmaddr = reinterpret_cast<char*>(-1); 1316c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org shm_segment_info_->readOnly = False; 1326c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org x_image_ = XShmCreateImage(display_, default_visual, default_depth, ZPixmap, 133e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org 0, shm_segment_info_, window_size_.width(), 134e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org window_size_.height()); 1356c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org if (x_image_) { 1366c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org shm_segment_info_->shmid = shmget( 1376c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org IPC_PRIVATE, x_image_->bytes_per_line * x_image_->height, 1386c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org IPC_CREAT | 0600); 1396c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org if (shm_segment_info_->shmid != -1) { 1406c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org shm_segment_info_->shmaddr = x_image_->data = 1416c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org reinterpret_cast<char*>(shmat(shm_segment_info_->shmid, 0, 0)); 1426c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org if (x_image_->data != reinterpret_cast<char*>(-1)) { 143e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org XErrorTrap error_trap(display_); 1446c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org using_shm = XShmAttach(display_, shm_segment_info_); 1456c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org XSync(display_, False); 146e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org if (error_trap.GetLastErrorAndDisable() != 0) 1476c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org using_shm = false; 1486c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org if (using_shm) { 1496c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org LOG(LS_VERBOSE) << "Using X shared memory segment " 1506c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org << shm_segment_info_->shmid; 1516c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org } 1526c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org } 1536c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org } else { 1546c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org LOG(LS_WARNING) << "Failed to get shared memory segment. " 1556c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org "Performance may be degraded."; 1566c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org } 1576c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org } 1586c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org 1596c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org if (!using_shm) { 1606c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org LOG(LS_WARNING) << "Not using shared memory. Performance may be degraded."; 1616c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org Release(); 1626c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org return; 1636c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org } 1646c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org 165e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org if (have_pixmaps) 166e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org have_pixmaps = InitPixmaps(default_depth); 1676c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org 1686c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org shmctl(shm_segment_info_->shmid, IPC_RMID, 0); 1696c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org shm_segment_info_->shmid = -1; 1706c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org 1716c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org LOG(LS_VERBOSE) << "Using X shared memory extension v" 1726c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org << major << "." << minor 173e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org << " with" << (have_pixmaps ? "" : "out") << " pixmaps."; 1746c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org} 1756c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org 1766c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.orgbool XServerPixelBuffer::InitPixmaps(int depth) { 1776c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org if (XShmPixmapFormat(display_) != ZPixmap) 1786c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org return false; 1796c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org 180e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org { 181e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org XErrorTrap error_trap(display_); 182e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org shm_pixmap_ = XShmCreatePixmap(display_, window_, 183e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org shm_segment_info_->shmaddr, 184e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org shm_segment_info_, 185e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org window_size_.width(), 186e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org window_size_.height(), depth); 187e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org XSync(display_, False); 188e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org if (error_trap.GetLastErrorAndDisable() != 0) { 189e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org // |shm_pixmap_| is not not valid because the request was not processed 190e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org // by the X Server, so zero it. 191e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org shm_pixmap_ = 0; 192e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org return false; 193e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org } 1946c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org } 1956c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org 196e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org { 197e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org XErrorTrap error_trap(display_); 198e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org XGCValues shm_gc_values; 199e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org shm_gc_values.subwindow_mode = IncludeInferiors; 200e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org shm_gc_values.graphics_exposures = False; 201e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org shm_gc_ = XCreateGC(display_, window_, 202e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org GCSubwindowMode | GCGraphicsExposures, 203e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org &shm_gc_values); 204e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org XSync(display_, False); 205e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org if (error_trap.GetLastErrorAndDisable() != 0) { 206e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org XFreePixmap(display_, shm_pixmap_); 207e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org shm_pixmap_ = 0; 208e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org shm_gc_ = 0; // See shm_pixmap_ comment above. 209e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org return false; 210e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org } 2116c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org } 2126c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org 2136c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org return true; 2146c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org} 2156c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org 216dcbf62b4cf1d7a28fb002efdf671f784378c8c98jiayl@webrtc.orgbool XServerPixelBuffer::IsWindowValid() const { 217dcbf62b4cf1d7a28fb002efdf671f784378c8c98jiayl@webrtc.org XWindowAttributes attributes; 218dcbf62b4cf1d7a28fb002efdf671f784378c8c98jiayl@webrtc.org { 219dcbf62b4cf1d7a28fb002efdf671f784378c8c98jiayl@webrtc.org XErrorTrap error_trap(display_); 220dcbf62b4cf1d7a28fb002efdf671f784378c8c98jiayl@webrtc.org if (!XGetWindowAttributes(display_, window_, &attributes) || 221dcbf62b4cf1d7a28fb002efdf671f784378c8c98jiayl@webrtc.org error_trap.GetLastErrorAndDisable() != 0) { 222dcbf62b4cf1d7a28fb002efdf671f784378c8c98jiayl@webrtc.org return false; 223dcbf62b4cf1d7a28fb002efdf671f784378c8c98jiayl@webrtc.org } 224dcbf62b4cf1d7a28fb002efdf671f784378c8c98jiayl@webrtc.org } 225dcbf62b4cf1d7a28fb002efdf671f784378c8c98jiayl@webrtc.org return true; 226dcbf62b4cf1d7a28fb002efdf671f784378c8c98jiayl@webrtc.org} 227dcbf62b4cf1d7a28fb002efdf671f784378c8c98jiayl@webrtc.org 2286c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.orgvoid XServerPixelBuffer::Synchronize() { 2296c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org if (shm_segment_info_ && !shm_pixmap_) { 2306c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org // XShmGetImage can fail if the display is being reconfigured. 231e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org XErrorTrap error_trap(display_); 232e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org XShmGetImage(display_, window_, x_image_, 0, 0, AllPlanes); 2336c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org } 2346c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org} 2356c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org 236e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.orgvoid XServerPixelBuffer::CaptureRect(const DesktopRect& rect, 237e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org DesktopFrame* frame) { 238e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org assert(rect.right() <= window_size_.width()); 239e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org assert(rect.bottom() <= window_size_.height()); 240e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org 241e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org uint8_t* data; 2426c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org 2436c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org if (shm_segment_info_) { 2446c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org if (shm_pixmap_) { 245e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org XCopyArea(display_, window_, shm_pixmap_, shm_gc_, 2466c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org rect.left(), rect.top(), rect.width(), rect.height(), 2476c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org rect.left(), rect.top()); 2486c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org XSync(display_, False); 2496c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org } 250e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org data = reinterpret_cast<uint8_t*>(x_image_->data) + 2516c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org rect.top() * x_image_->bytes_per_line + 2526c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org rect.left() * x_image_->bits_per_pixel / 8; 2536c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org } else { 2546c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org if (x_image_) 2556c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org XDestroyImage(x_image_); 256e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org x_image_ = XGetImage(display_, window_, rect.left(), rect.top(), 2576c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org rect.width(), rect.height(), AllPlanes, ZPixmap); 258e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org data = reinterpret_cast<uint8_t*>(x_image_->data); 2596c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org } 2606c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org 261e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org if (IsXImageRGBFormat(x_image_)) { 262e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org FastBlit(data, rect, frame); 263e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org } else { 264e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org SlowBlit(data, rect, frame); 265e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org } 2666c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org} 2676c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org 268e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.orgvoid XServerPixelBuffer::FastBlit(uint8_t* image, 269e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org const DesktopRect& rect, 270e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org DesktopFrame* frame) { 271e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org uint8_t* src_pos = image; 272e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org int src_stride = x_image_->bytes_per_line; 273e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org int dst_x = rect.left(), dst_y = rect.top(); 274e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org 275e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org uint8_t* dst_pos = frame->data() + frame->stride() * dst_y; 276e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org dst_pos += dst_x * DesktopFrame::kBytesPerPixel; 277e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org 278e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org int height = rect.height(); 279e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org int row_bytes = rect.width() * DesktopFrame::kBytesPerPixel; 280e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org for (int y = 0; y < height; ++y) { 281e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org memcpy(dst_pos, src_pos, row_bytes); 282e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org src_pos += src_stride; 283e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org dst_pos += frame->stride(); 284e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org } 2856c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org} 2866c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org 287e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.orgvoid XServerPixelBuffer::SlowBlit(uint8_t* image, 288e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org const DesktopRect& rect, 289e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org DesktopFrame* frame) { 290e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org int src_stride = x_image_->bytes_per_line; 291e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org int dst_x = rect.left(), dst_y = rect.top(); 292e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org int width = rect.width(), height = rect.height(); 293e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org 294e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org uint32_t red_mask = x_image_->red_mask; 295e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org uint32_t green_mask = x_image_->red_mask; 296e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org uint32_t blue_mask = x_image_->blue_mask; 297e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org 298e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org uint32_t red_shift = MaskToShift(red_mask); 299e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org uint32_t green_shift = MaskToShift(green_mask); 300e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org uint32_t blue_shift = MaskToShift(blue_mask); 301e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org 302e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org int bits_per_pixel = x_image_->bits_per_pixel; 303e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org 304e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org uint8_t* dst_pos = frame->data() + frame->stride() * dst_y; 305e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org uint8_t* src_pos = image; 306e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org dst_pos += dst_x * DesktopFrame::kBytesPerPixel; 307e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org // TODO(hclam): Optimize, perhaps using MMX code or by converting to 308e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org // YUV directly. 309e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org // TODO(sergeyu): This code doesn't handle XImage byte order properly and 310e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org // won't work with 24bpp images. Fix it. 311e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org for (int y = 0; y < height; y++) { 312e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org uint32_t* dst_pos_32 = reinterpret_cast<uint32_t*>(dst_pos); 313e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org uint32_t* src_pos_32 = reinterpret_cast<uint32_t*>(src_pos); 314e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org uint16_t* src_pos_16 = reinterpret_cast<uint16_t*>(src_pos); 315e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org for (int x = 0; x < width; x++) { 316e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org // Dereference through an appropriately-aligned pointer. 317e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org uint32_t pixel; 318e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org if (bits_per_pixel == 32) { 319e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org pixel = src_pos_32[x]; 320e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org } else if (bits_per_pixel == 16) { 321e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org pixel = src_pos_16[x]; 322e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org } else { 323e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org pixel = src_pos[x]; 324e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org } 325e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org uint32_t r = (pixel & red_mask) << red_shift; 326e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org uint32_t g = (pixel & green_mask) << green_shift; 327e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org uint32_t b = (pixel & blue_mask) << blue_shift; 328e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org // Write as 32-bit RGB. 329e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org dst_pos_32[x] = ((r >> 8) & 0xff0000) | ((g >> 16) & 0xff00) | 330e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org ((b >> 24) & 0xff); 331e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org } 332e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org dst_pos += frame->stride(); 333e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org src_pos += src_stride; 334e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org } 3356c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org} 3366c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org 3376c82a7ea6ea92e8c68b37112186fd928b11ddc49sergeyu@chromium.org} // namespace webrtc 338