Implemented shared memory capture method.
BUG=None
TEST=None
Review URL: http://codereview.chromium.org/6677083
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@78874 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/remoting/host/capturer_linux.cc b/remoting/host/capturer_linux.cc
index a168358..db0ffc4 100644
--- a/remoting/host/capturer_linux.cc
+++ b/remoting/host/capturer_linux.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -11,32 +11,10 @@
#include <set>
#include "remoting/base/types.h"
+#include "remoting/host/x_server_pixel_buffer.h"
namespace remoting {
-static int IndexOfLowestBit(unsigned int mask) {
- int i = 0;
-
- // Extra-special do-while premature optimization, just to make dmaclach@
- // happy.
- do {
- if (mask & 1) {
- return i;
- }
- mask >>= 1;
- ++i;
- } while (mask);
-
- NOTREACHED() << "mask should never be 0.";
- return 0;
-}
-
-static bool IsRgb32(XImage* image) {
- return (IndexOfLowestBit(image->red_mask) == 16) &&
- (IndexOfLowestBit(image->green_mask) == 8) &&
- (IndexOfLowestBit(image->blue_mask) == 0);
-}
-
// Private Implementation pattern to avoid leaking the X11 types into the header
// file.
class CapturerLinuxPimpl {
@@ -53,10 +31,8 @@
void DeinitXlib();
// We expose two forms of blitting to handle variations in the pixel format.
// In FastBlit, the operation is effectively a memcpy.
- void FastBlit(XImage* image, int dest_x, int dest_y,
- CaptureData* capture_data);
- void SlowBlit(XImage* image, int dest_x, int dest_y,
- CaptureData* capture_data);
+ void FastBlit(uint8* image, const gfx::Rect& rect, CaptureData* capture_data);
+ void SlowBlit(uint8* image, const gfx::Rect& rect, CaptureData* capture_data);
static const int kBytesPerPixel = 4;
@@ -76,6 +52,9 @@
int damage_event_base_;
int damage_error_base_;
+ // Access to the X Server's pixel buffer.
+ XServerPixelBuffer x_server_pixel_buffer_;
+
// Capture state.
uint8* buffers_[CapturerLinux::kNumBuffers];
int stride_;
@@ -150,6 +129,8 @@
return false;
}
+ x_server_pixel_buffer_.Init(display_);
+
root_window_ = RootWindow(display_, DefaultScreen(display_));
if (root_window_ == BadValue) {
LOG(ERROR) << "Unable to get the root window";
@@ -273,21 +254,18 @@
for (InvalidRects::const_iterator it = rects.begin();
it != rects.end();
++it) {
- XImage* image = XGetImage(display_, root_window_, it->x(), it->y(),
- it->width(), it->height(), AllPlanes, ZPixmap);
-
+ uint8* image = x_server_pixel_buffer_.CaptureRect(*it);
// Check if we can fastpath the blit.
- if ((image->depth == 24 || image->depth == 32) &&
- image->bits_per_pixel == 32 &&
- IsRgb32(image)) {
+ int depth = x_server_pixel_buffer_.GetDepth();
+ int bpp = x_server_pixel_buffer_.GetBitsPerPixel();
+ bool is_rgb = x_server_pixel_buffer_.IsRgb();
+ if ((depth == 24 || depth == 32) && bpp == 32 && is_rgb) {
VLOG(3) << "Fast blitting";
- FastBlit(image, it->x(), it->y(), capture_data);
+ FastBlit(image, *it, capture_data);
} else {
VLOG(3) << "Slow blitting";
- SlowBlit(image, it->x(), it->y(), capture_data);
+ SlowBlit(image, *it, capture_data);
}
-
- XDestroyImage(image);
}
// TODO(ajwong): We should only repair the rects that were copied!
@@ -314,60 +292,76 @@
}
}
-void CapturerLinuxPimpl::FastBlit(XImage* image, int dest_x, int dest_y,
+void CapturerLinuxPimpl::FastBlit(uint8* image, const gfx::Rect& rect,
CaptureData* capture_data) {
- uint8* src_pos = reinterpret_cast<uint8*>(image->data);
+ uint8* src_pos = image;
+ int src_stride = x_server_pixel_buffer_.GetStride();
+ int dst_x = rect.x(), dst_y = rect.y();
DataPlanes planes = capture_data->data_planes();
uint8* dst_buffer = planes.data[0];
const int dst_stride = planes.strides[0];
- const int src_stride = image->bytes_per_line;
- uint8* dst_pos = dst_buffer + dst_stride * dest_y;
- dst_pos += dest_x * kBytesPerPixel;
+ uint8* dst_pos = dst_buffer + dst_stride * dst_y;
+ dst_pos += dst_x * kBytesPerPixel;
- for (int y = 0; y < image->height; ++y) {
- memcpy(dst_pos, src_pos, image->width * kBytesPerPixel);
-
+ int height = rect.height(), row_bytes = rect.width() * kBytesPerPixel;
+ for (int y = 0; y < height; ++y) {
+ memcpy(dst_pos, src_pos, row_bytes);
src_pos += src_stride;
dst_pos += dst_stride;
}
}
-void CapturerLinuxPimpl::SlowBlit(XImage* image, int dest_x, int dest_y,
+void CapturerLinuxPimpl::SlowBlit(uint8* image, const gfx::Rect& rect,
CaptureData* capture_data) {
DataPlanes planes = capture_data->data_planes();
uint8* dst_buffer = planes.data[0];
const int dst_stride = planes.strides[0];
+ int src_stride = x_server_pixel_buffer_.GetStride();
+ int dst_x = rect.x(), dst_y = rect.y();
+ int width = rect.width(), height = rect.height();
- unsigned int red_shift = IndexOfLowestBit(image->red_mask);
- unsigned int blue_shift = IndexOfLowestBit(image->blue_mask);
- unsigned int green_shift = IndexOfLowestBit(image->green_mask);
+ unsigned int red_mask = x_server_pixel_buffer_.GetRedMask();
+ unsigned int blue_mask = x_server_pixel_buffer_.GetBlueMask();
+ unsigned int green_mask = x_server_pixel_buffer_.GetGreenMask();
+ unsigned int red_shift = x_server_pixel_buffer_.GetRedShift();
+ unsigned int blue_shift = x_server_pixel_buffer_.GetBlueShift();
+ unsigned int green_shift = x_server_pixel_buffer_.GetGreenShift();
- unsigned int max_red = image->red_mask >> red_shift;
- unsigned int max_blue = image->blue_mask >> blue_shift;
- unsigned int max_green = image->green_mask >> green_shift;
+ unsigned int max_red = red_mask >> red_shift;
+ unsigned int max_blue = blue_mask >> blue_shift;
+ unsigned int max_green = green_mask >> green_shift;
- // Produce an upside-down image.
- uint8* dst_pos = dst_buffer + dst_stride * (height_ - dest_y - 1);
- dst_pos += dest_x * kBytesPerPixel;
- // TODO(jamiewalch): Optimize, perhaps using MMX code or by converting to
+ unsigned int bits_per_pixel = x_server_pixel_buffer_.GetBitsPerPixel();
+
+ uint8* dst_pos = dst_buffer + dst_stride * dst_y;
+ uint8* src_pos = image;
+ dst_pos += dst_x * kBytesPerPixel;
+ // TODO(hclam): Optimize, perhaps using MMX code or by converting to
// YUV directly
- for (int y = 0; y < image->height; y++) {
+ for (int y = 0; y < height; y++) {
uint32_t* dst_pos_32 = reinterpret_cast<uint32_t*>(dst_pos);
- for (int x = 0; x < image->width; x++) {
- unsigned long pixel = XGetPixel(image, x, y);
- uint32_t r = (((pixel & image->red_mask) >> red_shift) * max_red) / 255;
- uint32_t g =
- (((pixel & image->green_mask) >> green_shift) * max_blue) / 255;
- uint32_t b =
- (((pixel & image->blue_mask) >> blue_shift) * max_green) / 255;
-
+ uint32_t* src_pos_32 = reinterpret_cast<uint32_t*>(src_pos);
+ uint16_t* src_pos_16 = reinterpret_cast<uint16_t*>(src_pos);
+ for (int x = 0; x < width; x++) {
+ // Dereference through an appropriately-aligned pointer.
+ uint32_t pixel;
+ if (bits_per_pixel == 32)
+ pixel = src_pos_32[x];
+ else if (bits_per_pixel == 16)
+ pixel = src_pos_16[x];
+ else
+ pixel = src_pos[x];
+ uint32_t r = (((pixel & red_mask) >> red_shift) * 255) / max_red;
+ uint32_t b = (((pixel & blue_mask) >> blue_shift) * 255) / max_blue;
+ uint32_t g = (((pixel & green_mask) >> green_shift) * 255) / max_green;
// Write as 32-bit RGB.
dst_pos_32[x] = r << 16 | g << 8 | b;
}
- dst_pos -= dst_stride;
+ dst_pos += dst_stride;
+ src_pos += src_stride;
}
}