Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(117)

Side by Side Diff: remoting/host/capturer_linux.cc

Issue 10382184: [Chromoting] Initial plumbing for cursor shape. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Remove extra LOGs Created 8 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "remoting/host/capturer.h" 5 #include "remoting/host/capturer.h"
6 6
7 #include <X11/Xlib.h> 7 #include <X11/Xlib.h>
8 #include <X11/Xutil.h> 8 #include <X11/Xutil.h>
9 #include <X11/extensions/Xdamage.h> 9 #include <X11/extensions/Xdamage.h>
10 #include <X11/extensions/Xfixes.h>
10 11
11 #include <set> 12 #include <set>
12 13
13 #include "base/basictypes.h" 14 #include "base/basictypes.h"
14 #include "base/logging.h" 15 #include "base/logging.h"
15 #include "base/memory/scoped_ptr.h" 16 #include "base/memory/scoped_ptr.h"
17 #include "remoting/base/capture_data.h"
18 #include "remoting/base/cursor_shape_data.h"
16 #include "remoting/host/capturer_helper.h" 19 #include "remoting/host/capturer_helper.h"
17 #include "remoting/host/differ.h" 20 #include "remoting/host/differ.h"
18 #include "remoting/host/x_server_pixel_buffer.h" 21 #include "remoting/host/x_server_pixel_buffer.h"
19 22
20 namespace remoting { 23 namespace remoting {
21 24
22 namespace { 25 namespace {
23 26
24 static const int kBytesPerPixel = 4; 27 static const int kBytesPerPixel = 4;
25 28
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
70 class CapturerLinux : public Capturer { 73 class CapturerLinux : public Capturer {
71 public: 74 public:
72 CapturerLinux(); 75 CapturerLinux();
73 virtual ~CapturerLinux(); 76 virtual ~CapturerLinux();
74 77
75 bool Init(); // TODO(ajwong): Do we really want this to be synchronous? 78 bool Init(); // TODO(ajwong): Do we really want this to be synchronous?
76 79
77 // Capturer interface. 80 // Capturer interface.
78 virtual void Start() OVERRIDE; 81 virtual void Start() OVERRIDE;
79 virtual void Stop() OVERRIDE; 82 virtual void Stop() OVERRIDE;
83 virtual void SetCursorShapeChangedCallback(
84 const CursorShapeChangedCallback& callback) OVERRIDE;
80 virtual void ScreenConfigurationChanged() OVERRIDE; 85 virtual void ScreenConfigurationChanged() OVERRIDE;
81 virtual media::VideoFrame::Format pixel_format() const OVERRIDE; 86 virtual media::VideoFrame::Format pixel_format() const OVERRIDE;
82 virtual void ClearInvalidRegion() OVERRIDE; 87 virtual void ClearInvalidRegion() OVERRIDE;
83 virtual void InvalidateRegion(const SkRegion& invalid_region) OVERRIDE; 88 virtual void InvalidateRegion(const SkRegion& invalid_region) OVERRIDE;
84 virtual void InvalidateScreen(const SkISize& size) OVERRIDE; 89 virtual void InvalidateScreen(const SkISize& size) OVERRIDE;
85 virtual void InvalidateFullScreen() OVERRIDE; 90 virtual void InvalidateFullScreen() OVERRIDE;
86 virtual void CaptureInvalidRegion( 91 virtual void CaptureInvalidRegion(
87 const CaptureCompletedCallback& callback) OVERRIDE; 92 const CaptureCompletedCallback& callback) OVERRIDE;
88 virtual const SkISize& size_most_recent() const OVERRIDE; 93 virtual const SkISize& size_most_recent() const OVERRIDE;
89 94
90 private: 95 private:
91 void InitXDamage(); 96 void InitXDamage();
92 97
93 // Read and handle all currently-pending XEvents. 98 // Read and handle all currently-pending XEvents.
94 // In the DAMAGE case, process the XDamage events and store the resulting 99 // In the DAMAGE case, process the XDamage events and store the resulting
95 // damage rectangles in the CapturerHelper. 100 // damage rectangles in the CapturerHelper.
96 // In all cases, call ScreenConfigurationChanged() in response to any 101 // In all cases, call ScreenConfigurationChanged() in response to any
97 // ConfigNotify events. 102 // ConfigNotify events.
98 void ProcessPendingXEvents(); 103 void ProcessPendingXEvents();
99 104
100 // Capture screen pixels, and return the data in a new CaptureData object, 105 // Capture screen pixels, and return the data in a new CaptureData object,
101 // to be freed by the caller. 106 // to be freed by the caller.
102 // In the DAMAGE case, the CapturerHelper already holds the list of invalid 107 // In the DAMAGE case, the CapturerHelper already holds the list of invalid
103 // rectangles from ProcessPendingXEvents(). 108 // rectangles from ProcessPendingXEvents().
104 // In the non-DAMAGE case, this captures the whole screen, then calculates 109 // In the non-DAMAGE case, this captures the whole screen, then calculates
105 // some invalid rectangles that include any differences between this and the 110 // some invalid rectangles that include any differences between this and the
106 // previous capture. 111 // previous capture.
107 CaptureData* CaptureFrame(); 112 CaptureData* CaptureFrame();
108 113
114 // Capture the cursor image and call the CursorShapeChangedCallback if it
115 // has been set (using SetCursorShapeChangedCallback).
116 void CaptureCursor();
117
109 // Synchronize the current buffer with |last_buffer_|, by copying pixels from 118 // Synchronize the current buffer with |last_buffer_|, by copying pixels from
110 // the area of |last_invalid_rects|. 119 // the area of |last_invalid_rects|.
111 // Note this only works on the assumption that kNumBuffers == 2, as 120 // Note this only works on the assumption that kNumBuffers == 2, as
112 // |last_invalid_rects| holds the differences from the previous buffer and 121 // |last_invalid_rects| holds the differences from the previous buffer and
113 // the one prior to that (which will then be the current buffer). 122 // the one prior to that (which will then be the current buffer).
114 void SynchronizeFrame(); 123 void SynchronizeFrame();
115 124
116 void DeinitXlib(); 125 void DeinitXlib();
117 126
118 // Capture a rectangle from |x_server_pixel_buffer_|, and copy the data into 127 // Capture a rectangle from |x_server_pixel_buffer_|, and copy the data into
119 // |capture_data|. 128 // |capture_data|.
120 void CaptureRect(const SkIRect& rect, CaptureData* capture_data); 129 void CaptureRect(const SkIRect& rect, CaptureData* capture_data);
121 130
122 // We expose two forms of blitting to handle variations in the pixel format. 131 // We expose two forms of blitting to handle variations in the pixel format.
123 // In FastBlit, the operation is effectively a memcpy. 132 // In FastBlit, the operation is effectively a memcpy.
124 void FastBlit(uint8* image, const SkIRect& rect, CaptureData* capture_data); 133 void FastBlit(uint8* image, const SkIRect& rect, CaptureData* capture_data);
125 void SlowBlit(uint8* image, const SkIRect& rect, CaptureData* capture_data); 134 void SlowBlit(uint8* image, const SkIRect& rect, CaptureData* capture_data);
126 135
127 // X11 graphics context. 136 // X11 graphics context.
128 Display* display_; 137 Display* display_;
129 GC gc_; 138 GC gc_;
130 Window root_window_; 139 Window root_window_;
131 140
141 // XFixes.
142 bool has_xfixes_;
143 int xfixes_event_base_;
144 int xfixes_error_base_;
145
132 // XDamage information. 146 // XDamage information.
133 bool use_damage_; 147 bool use_damage_;
134 Damage damage_handle_; 148 Damage damage_handle_;
135 int damage_event_base_; 149 int damage_event_base_;
136 int damage_error_base_; 150 int damage_error_base_;
137 XserverRegion damage_region_; 151 XserverRegion damage_region_;
138 152
139 // Access to the X Server's pixel buffer. 153 // Access to the X Server's pixel buffer.
140 XServerPixelBuffer x_server_pixel_buffer_; 154 XServerPixelBuffer x_server_pixel_buffer_;
141 155
142 // A thread-safe list of invalid rectangles, and the size of the most 156 // A thread-safe list of invalid rectangles, and the size of the most
143 // recently captured screen. 157 // recently captured screen.
144 CapturerHelper helper_; 158 CapturerHelper helper_;
145 159
160 // Callback notified whenever the cursor shape is changed.
161 CursorShapeChangedCallback cursor_shape_changed_callback_;
162
146 // Capture state. 163 // Capture state.
147 static const int kNumBuffers = 2; 164 static const int kNumBuffers = 2;
148 VideoFrameBuffer buffers_[kNumBuffers]; 165 VideoFrameBuffer buffers_[kNumBuffers];
149 int current_buffer_; 166 int current_buffer_;
150 167
151 // Format of pixels returned in buffer. 168 // Format of pixels returned in buffer.
152 media::VideoFrame::Format pixel_format_; 169 media::VideoFrame::Format pixel_format_;
153 170
154 // Invalid region from the previous capture. This is used to synchronize the 171 // Invalid region from the previous capture. This is used to synchronize the
155 // current with the last buffer used. 172 // current with the last buffer used.
156 SkRegion last_invalid_region_; 173 SkRegion last_invalid_region_;
157 174
158 // Last capture buffer used. 175 // Last capture buffer used.
159 uint8* last_buffer_; 176 uint8* last_buffer_;
160 177
161 // |Differ| for use when polling for changes. 178 // |Differ| for use when polling for changes.
162 scoped_ptr<Differ> differ_; 179 scoped_ptr<Differ> differ_;
163 180
164 DISALLOW_COPY_AND_ASSIGN(CapturerLinux); 181 DISALLOW_COPY_AND_ASSIGN(CapturerLinux);
165 }; 182 };
166 183
167 CapturerLinux::CapturerLinux() 184 CapturerLinux::CapturerLinux()
168 : display_(NULL), 185 : display_(NULL),
169 gc_(NULL), 186 gc_(NULL),
170 root_window_(BadValue), 187 root_window_(BadValue),
188 has_xfixes_(false),
189 xfixes_event_base_(-1),
190 xfixes_error_base_(-1),
171 use_damage_(false), 191 use_damage_(false),
172 damage_handle_(0), 192 damage_handle_(0),
173 damage_event_base_(-1), 193 damage_event_base_(-1),
174 damage_error_base_(-1), 194 damage_error_base_(-1),
175 damage_region_(0), 195 damage_region_(0),
176 current_buffer_(0), 196 current_buffer_(0),
177 pixel_format_(media::VideoFrame::RGB32), 197 pixel_format_(media::VideoFrame::RGB32),
178 last_buffer_(NULL) { 198 last_buffer_(NULL) {
179 helper_.SetLogGridSize(4); 199 helper_.SetLogGridSize(4);
180 } 200 }
(...skipping 20 matching lines...) Expand all
201 return false; 221 return false;
202 } 222 }
203 223
204 gc_ = XCreateGC(display_, root_window_, 0, NULL); 224 gc_ = XCreateGC(display_, root_window_, 0, NULL);
205 if (gc_ == NULL) { 225 if (gc_ == NULL) {
206 LOG(ERROR) << "Unable to get graphics context"; 226 LOG(ERROR) << "Unable to get graphics context";
207 DeinitXlib(); 227 DeinitXlib();
208 return false; 228 return false;
209 } 229 }
210 230
231 // Check for XFixes extension. This is required for cursor shape
232 // notifications, and for our use of XDamage.
233 if (XFixesQueryExtension(display_, &xfixes_event_base_,
234 &xfixes_error_base_)) {
235 has_xfixes_ = true;
236 } else {
237 LOG(INFO) << "X server does not support XFixes.";
238 }
239
211 if (ShouldUseXDamage()) { 240 if (ShouldUseXDamage()) {
212 InitXDamage(); 241 InitXDamage();
213 } 242 }
214 243
215 // Register for changes to the dimensions of the root window. 244 // Register for changes to the dimensions of the root window.
216 XSelectInput(display_, root_window_, StructureNotifyMask); 245 XSelectInput(display_, root_window_, StructureNotifyMask);
217 246
247 if (has_xfixes_) {
248 // Register for changes to the cursor shape.
249 XFixesSelectCursorInput(display_, root_window_,
250 XFixesDisplayCursorNotifyMask);
251 }
252
218 return true; 253 return true;
219 } 254 }
220 255
221 void CapturerLinux::InitXDamage() { 256 void CapturerLinux::InitXDamage() {
222 // Check for XFixes and XDamage extensions. If both are found then use 257 // Our use of XDamage requires XFixes.
223 // XDamage to get explicit notifications of on-screen changes. 258 if (!has_xfixes_)
Wez 2012/05/23 00:01:57 nit: Use {} consistently with the other if()s belo
garykac 2012/05/26 01:58:01 Done.
224 int xfixes_event_base;
225 int xfixes_error_base;
226 if (!XFixesQueryExtension(display_, &xfixes_event_base, &xfixes_error_base)) {
227 LOG(INFO) << "X server does not support XFixes.";
228 return; 259 return;
229 } 260
261 // Check for XDamage extension.
230 if (!XDamageQueryExtension(display_, &damage_event_base_, 262 if (!XDamageQueryExtension(display_, &damage_event_base_,
231 &damage_error_base_)) { 263 &damage_error_base_)) {
232 LOG(INFO) << "X server does not support XDamage."; 264 LOG(INFO) << "X server does not support XDamage.";
233 return; 265 return;
234 } 266 }
235 267
236 // TODO(lambroslambrou): Disable DAMAGE in situations where it is known 268 // TODO(lambroslambrou): Disable DAMAGE in situations where it is known
237 // to fail, such as when Desktop Effects are enabled, with graphics 269 // to fail, such as when Desktop Effects are enabled, with graphics
238 // drivers (nVidia, ATI) that fail to report DAMAGE notifications 270 // drivers (nVidia, ATI) that fail to report DAMAGE notifications
239 // properly. 271 // properly.
(...skipping 17 matching lines...) Expand all
257 use_damage_ = true; 289 use_damage_ = true;
258 LOG(INFO) << "Using XDamage extension."; 290 LOG(INFO) << "Using XDamage extension.";
259 } 291 }
260 292
261 void CapturerLinux::Start() { 293 void CapturerLinux::Start() {
262 } 294 }
263 295
264 void CapturerLinux::Stop() { 296 void CapturerLinux::Stop() {
265 } 297 }
266 298
299 void CapturerLinux::SetCursorShapeChangedCallback(
300 const CursorShapeChangedCallback& callback) {
301 cursor_shape_changed_callback_ = callback;
302 }
303
267 void CapturerLinux::ScreenConfigurationChanged() { 304 void CapturerLinux::ScreenConfigurationChanged() {
268 last_buffer_ = NULL; 305 last_buffer_ = NULL;
269 for (int i = 0; i < kNumBuffers; ++i) { 306 for (int i = 0; i < kNumBuffers; ++i) {
270 buffers_[i].set_needs_update(); 307 buffers_[i].set_needs_update();
271 } 308 }
272 helper_.ClearInvalidRegion(); 309 helper_.ClearInvalidRegion();
273 x_server_pixel_buffer_.Init(display_); 310 x_server_pixel_buffer_.Init(display_);
274 } 311 }
275 312
276 media::VideoFrame::Format CapturerLinux::pixel_format() const { 313 media::VideoFrame::Format CapturerLinux::pixel_format() const {
(...skipping 12 matching lines...) Expand all
289 helper_.InvalidateScreen(size); 326 helper_.InvalidateScreen(size);
290 } 327 }
291 328
292 void CapturerLinux::InvalidateFullScreen() { 329 void CapturerLinux::InvalidateFullScreen() {
293 helper_.InvalidateFullScreen(); 330 helper_.InvalidateFullScreen();
294 last_buffer_ = NULL; 331 last_buffer_ = NULL;
295 } 332 }
296 333
297 void CapturerLinux::CaptureInvalidRegion( 334 void CapturerLinux::CaptureInvalidRegion(
298 const CaptureCompletedCallback& callback) { 335 const CaptureCompletedCallback& callback) {
299 // TODO(lambroslambrou): In the non-DAMAGE case, there should be no need 336 // Process XEvents for XDamage and cursor shape tracking.
300 // for any X event processing in this class.
301 ProcessPendingXEvents(); 337 ProcessPendingXEvents();
302 338
303 // Resize the current buffer if there was a recent change of 339 // Resize the current buffer if there was a recent change of
304 // screen-resolution. 340 // screen-resolution.
305 VideoFrameBuffer &current = buffers_[current_buffer_]; 341 VideoFrameBuffer &current = buffers_[current_buffer_];
306 current.Update(display_, root_window_); 342 current.Update(display_, root_window_);
307 // Also refresh the Differ helper used by CaptureFrame(), if needed. 343 // Also refresh the Differ helper used by CaptureFrame(), if needed.
308 if (!use_damage_ && !last_buffer_) { 344 if (!use_damage_ && !last_buffer_) {
309 differ_.reset(new Differ(current.size().width(), current.size().height(), 345 differ_.reset(new Differ(current.size().width(), current.size().height(),
310 kBytesPerPixel, current.bytes_per_row())); 346 kBytesPerPixel, current.bytes_per_row()));
311 } 347 }
312 348
313 scoped_refptr<CaptureData> capture_data(CaptureFrame()); 349 scoped_refptr<CaptureData> capture_data(CaptureFrame());
314 350
315 current_buffer_ = (current_buffer_ + 1) % kNumBuffers; 351 current_buffer_ = (current_buffer_ + 1) % kNumBuffers;
316 352
317 callback.Run(capture_data); 353 callback.Run(capture_data);
318 } 354 }
319 355
320 void CapturerLinux::ProcessPendingXEvents() { 356 void CapturerLinux::ProcessPendingXEvents() {
321 // Find the number of events that are outstanding "now." We don't just loop 357 // Find the number of events that are outstanding "now." We don't just loop
322 // on XPending because we want to guarantee this terminates. 358 // on XPending because we want to guarantee this terminates.
323 int events_to_process = XPending(display_); 359 int events_to_process = XPending(display_);
324 XEvent e; 360 XEvent e;
325 361
326 for (int i = 0; i < events_to_process; i++) { 362 for (int i = 0; i < events_to_process; i++) {
327 XNextEvent(display_, &e); 363 XNextEvent(display_, &e);
328 if (use_damage_ && (e.type == damage_event_base_ + XDamageNotify)) { 364 if (use_damage_ && (e.type == damage_event_base_ + XDamageNotify)) {
329 XDamageNotifyEvent *event = reinterpret_cast<XDamageNotifyEvent*>(&e); 365 XDamageNotifyEvent* event = reinterpret_cast<XDamageNotifyEvent*>(&e);
330 DCHECK(event->level == XDamageReportNonEmpty); 366 DCHECK(event->level == XDamageReportNonEmpty);
331 } else if (e.type == ConfigureNotify) { 367 } else if (e.type == ConfigureNotify) {
332 ScreenConfigurationChanged(); 368 ScreenConfigurationChanged();
369 } else if (has_xfixes_ &&
370 e.type == xfixes_event_base_ + XFixesCursorNotify) {
371 XFixesCursorNotifyEvent* cne;
372 cne = reinterpret_cast<XFixesCursorNotifyEvent*>(&e);
373 if (cne->subtype == XFixesDisplayCursorNotify) {
374 CaptureCursor();
375 }
333 } else { 376 } else {
334 LOG(WARNING) << "Got unknown event type: " << e.type; 377 LOG(WARNING) << "Got unknown event type: " << e.type;
335 } 378 }
336 } 379 }
337 } 380 }
338 381
382 void CapturerLinux::CaptureCursor() {
383 DCHECK(has_xfixes_);
384 if (cursor_shape_changed_callback_.is_null())
385 return;
386
387 XFixesCursorImage* img = XFixesGetCursorImage(display_);
388 if (!img)
Wez 2012/05/23 00:01:57 nit: Here and above, use {} consistently with othe
garykac 2012/05/26 01:58:01 Done.
389 return;
390
391 SkISize size, hotspot;
392 size.set(img->width, img->height);
393 hotspot.set(img->xhot, img->yhot);
394 const int bytes_per_pixel = 4;
395 int total_bytes = img->width * img->height * bytes_per_pixel;
Wez 2012/05/23 00:01:57 nit: Rather than set these up here, why not use e.
garykac 2012/05/26 01:58:01 Done.
396 scoped_array<uint8> data(new uint8[total_bytes]);
397
398 // Xlib stores 32-bit data in longs, even if longs are 64-bits long.
Wez 2012/05/23 00:01:57 nit: I'd recommend simplifying this to use the slo
garykac 2012/05/26 01:58:01 Done.
399 if (sizeof(unsigned long) == sizeof(uint32)) {
400 // Longs are 32-bits, do a simple memcpy.
401 memcpy(data.get(), img->pixels, total_bytes);
402 } else {
403 // Longs are 64-bits, copy each long into a uint32.
404 unsigned long* src = img->pixels;
405 uint32* dst = reinterpret_cast<uint32*>(data.get());
406 uint32* dst_end = dst + (img->width * img->height);
407 while (dst < dst_end) {
408 *dst++ = *src++;
409 }
410 }
411 XFree(img);
412
413 scoped_refptr<CursorShapeData> cursor_data = new CursorShapeData();
414 cursor_data->Initialize(data.Pass(), size, hotspot, bytes_per_pixel);
415 cursor_shape_changed_callback_.Run(cursor_data);
416 }
417
339 CaptureData* CapturerLinux::CaptureFrame() { 418 CaptureData* CapturerLinux::CaptureFrame() {
340 VideoFrameBuffer& buffer = buffers_[current_buffer_]; 419 VideoFrameBuffer& buffer = buffers_[current_buffer_];
341 DataPlanes planes; 420 DataPlanes planes;
342 planes.data[0] = buffer.ptr(); 421 planes.data[0] = buffer.ptr();
343 planes.strides[0] = buffer.bytes_per_row(); 422 planes.strides[0] = buffer.bytes_per_row();
344 423
345 CaptureData* capture_data = new CaptureData(planes, buffer.size(), 424 CaptureData* capture_data = new CaptureData(planes, buffer.size(),
346 media::VideoFrame::RGB32); 425 media::VideoFrame::RGB32);
347 426
348 // Pass the screen size to the helper, so it can clip the invalid region if it 427 // Pass the screen size to the helper, so it can clip the invalid region if it
(...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after
551 } 630 }
552 return capturer; 631 return capturer;
553 } 632 }
554 633
555 // static 634 // static
556 void Capturer::EnableXDamage(bool enable) { 635 void Capturer::EnableXDamage(bool enable) {
557 g_should_use_x_damage = enable; 636 g_should_use_x_damage = enable;
558 } 637 }
559 638
560 } // namespace remoting 639 } // namespace remoting
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698