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

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: Add comment for CaptureCursor 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"
16 #include "remoting/host/capturer_helper.h" 17 #include "remoting/host/capturer_helper.h"
17 #include "remoting/host/differ.h" 18 #include "remoting/host/differ.h"
18 #include "remoting/host/x_server_pixel_buffer.h" 19 #include "remoting/host/x_server_pixel_buffer.h"
19 20
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
70 class CapturerLinux : public Capturer { 71 class CapturerLinux : public Capturer {
71 public: 72 public:
72 CapturerLinux(); 73 CapturerLinux();
73 virtual ~CapturerLinux(); 74 virtual ~CapturerLinux();
74 75
75 bool Init(); // TODO(ajwong): Do we really want this to be synchronous? 76 bool Init(); // TODO(ajwong): Do we really want this to be synchronous?
76 77
77 // Capturer interface. 78 // Capturer interface.
78 virtual void Start() OVERRIDE; 79 virtual void Start() OVERRIDE;
79 virtual void Stop() OVERRIDE; 80 virtual void Stop() OVERRIDE;
81 virtual void SetCursorShapeChangedCallback(
82 const CursorShapeChangedCallback& callback) OVERRIDE;
80 virtual void ScreenConfigurationChanged() OVERRIDE; 83 virtual void ScreenConfigurationChanged() OVERRIDE;
81 virtual media::VideoFrame::Format pixel_format() const OVERRIDE; 84 virtual media::VideoFrame::Format pixel_format() const OVERRIDE;
82 virtual void ClearInvalidRegion() OVERRIDE; 85 virtual void ClearInvalidRegion() OVERRIDE;
83 virtual void InvalidateRegion(const SkRegion& invalid_region) OVERRIDE; 86 virtual void InvalidateRegion(const SkRegion& invalid_region) OVERRIDE;
84 virtual void InvalidateScreen(const SkISize& size) OVERRIDE; 87 virtual void InvalidateScreen(const SkISize& size) OVERRIDE;
85 virtual void InvalidateFullScreen() OVERRIDE; 88 virtual void InvalidateFullScreen() OVERRIDE;
86 virtual void CaptureInvalidRegion( 89 virtual void CaptureInvalidRegion(
87 const CaptureCompletedCallback& callback) OVERRIDE; 90 const CaptureCompletedCallback& callback) OVERRIDE;
88 virtual const SkISize& size_most_recent() const OVERRIDE; 91 virtual const SkISize& size_most_recent() const OVERRIDE;
89 92
90 private: 93 private:
91 void InitXDamage(); 94 void InitXDamage();
92 95
93 // Read and handle all currently-pending XEvents. 96 // Read and handle all currently-pending XEvents.
94 // In the DAMAGE case, process the XDamage events and store the resulting 97 // In the DAMAGE case, process the XDamage events and store the resulting
95 // damage rectangles in the CapturerHelper. 98 // damage rectangles in the CapturerHelper.
96 // In all cases, call ScreenConfigurationChanged() in response to any 99 // In all cases, call ScreenConfigurationChanged() in response to any
97 // ConfigNotify events. 100 // ConfigNotify events.
98 void ProcessPendingXEvents(); 101 void ProcessPendingXEvents();
99 102
100 // Capture screen pixels, and return the data in a new CaptureData object, 103 // Capture screen pixels, and return the data in a new CaptureData object,
101 // to be freed by the caller. 104 // to be freed by the caller.
102 // In the DAMAGE case, the CapturerHelper already holds the list of invalid 105 // In the DAMAGE case, the CapturerHelper already holds the list of invalid
103 // rectangles from ProcessPendingXEvents(). 106 // rectangles from ProcessPendingXEvents().
104 // In the non-DAMAGE case, this captures the whole screen, then calculates 107 // In the non-DAMAGE case, this captures the whole screen, then calculates
105 // some invalid rectangles that include any differences between this and the 108 // some invalid rectangles that include any differences between this and the
106 // previous capture. 109 // previous capture.
107 CaptureData* CaptureFrame(); 110 CaptureData* CaptureFrame();
108 111
112 // Capture the cursor shape pixels and call the CursorShapeChangedCallback,
Wez 2012/05/16 00:20:04 nit: "shape pixels" -> "image" ?
garykac 2012/05/22 00:42:03 Done.
113 // if it has been set (using SetCursorShapeChangedCallback).
114 void CaptureCursor();
115
109 // Synchronize the current buffer with |last_buffer_|, by copying pixels from 116 // Synchronize the current buffer with |last_buffer_|, by copying pixels from
110 // the area of |last_invalid_rects|. 117 // the area of |last_invalid_rects|.
111 // Note this only works on the assumption that kNumBuffers == 2, as 118 // Note this only works on the assumption that kNumBuffers == 2, as
112 // |last_invalid_rects| holds the differences from the previous buffer and 119 // |last_invalid_rects| holds the differences from the previous buffer and
113 // the one prior to that (which will then be the current buffer). 120 // the one prior to that (which will then be the current buffer).
114 void SynchronizeFrame(); 121 void SynchronizeFrame();
115 122
116 void DeinitXlib(); 123 void DeinitXlib();
117 124
118 // Capture a rectangle from |x_server_pixel_buffer_|, and copy the data into 125 // Capture a rectangle from |x_server_pixel_buffer_|, and copy the data into
119 // |capture_data|. 126 // |capture_data|.
120 void CaptureRect(const SkIRect& rect, CaptureData* capture_data); 127 void CaptureRect(const SkIRect& rect, CaptureData* capture_data);
121 128
122 // We expose two forms of blitting to handle variations in the pixel format. 129 // We expose two forms of blitting to handle variations in the pixel format.
123 // In FastBlit, the operation is effectively a memcpy. 130 // In FastBlit, the operation is effectively a memcpy.
124 void FastBlit(uint8* image, const SkIRect& rect, CaptureData* capture_data); 131 void FastBlit(uint8* image, const SkIRect& rect, CaptureData* capture_data);
125 void SlowBlit(uint8* image, const SkIRect& rect, CaptureData* capture_data); 132 void SlowBlit(uint8* image, const SkIRect& rect, CaptureData* capture_data);
126 133
127 // X11 graphics context. 134 // X11 graphics context.
128 Display* display_; 135 Display* display_;
129 GC gc_; 136 GC gc_;
130 Window root_window_; 137 Window root_window_;
131 138
139 // XFixes.
140 bool has_xfixes_;
141 int xfixes_event_base_;
142 int xfixes_error_base_;
143
132 // XDamage information. 144 // XDamage information.
133 bool use_damage_; 145 bool use_damage_;
134 Damage damage_handle_; 146 Damage damage_handle_;
135 int damage_event_base_; 147 int damage_event_base_;
136 int damage_error_base_; 148 int damage_error_base_;
137 XserverRegion damage_region_; 149 XserverRegion damage_region_;
138 150
139 // Access to the X Server's pixel buffer. 151 // Access to the X Server's pixel buffer.
140 XServerPixelBuffer x_server_pixel_buffer_; 152 XServerPixelBuffer x_server_pixel_buffer_;
141 153
142 // A thread-safe list of invalid rectangles, and the size of the most 154 // A thread-safe list of invalid rectangles, and the size of the most
143 // recently captured screen. 155 // recently captured screen.
144 CapturerHelper helper_; 156 CapturerHelper helper_;
145 157
158 // Callback to call whenever the cursor shape is changed.
Wez 2012/05/16 00:20:04 nit: "Callback notified ..."
garykac 2012/05/22 00:42:03 Done.
159 CursorShapeChangedCallback cursor_shape_changed_callback_;
160
146 // Capture state. 161 // Capture state.
147 static const int kNumBuffers = 2; 162 static const int kNumBuffers = 2;
148 VideoFrameBuffer buffers_[kNumBuffers]; 163 VideoFrameBuffer buffers_[kNumBuffers];
149 int current_buffer_; 164 int current_buffer_;
150 165
151 // Format of pixels returned in buffer. 166 // Format of pixels returned in buffer.
152 media::VideoFrame::Format pixel_format_; 167 media::VideoFrame::Format pixel_format_;
153 168
154 // Invalid region from the previous capture. This is used to synchronize the 169 // Invalid region from the previous capture. This is used to synchronize the
155 // current with the last buffer used. 170 // current with the last buffer used.
156 SkRegion last_invalid_region_; 171 SkRegion last_invalid_region_;
157 172
158 // Last capture buffer used. 173 // Last capture buffer used.
159 uint8* last_buffer_; 174 uint8* last_buffer_;
160 175
161 // |Differ| for use when polling for changes. 176 // |Differ| for use when polling for changes.
162 scoped_ptr<Differ> differ_; 177 scoped_ptr<Differ> differ_;
163 178
164 DISALLOW_COPY_AND_ASSIGN(CapturerLinux); 179 DISALLOW_COPY_AND_ASSIGN(CapturerLinux);
165 }; 180 };
166 181
167 CapturerLinux::CapturerLinux() 182 CapturerLinux::CapturerLinux()
168 : display_(NULL), 183 : display_(NULL),
169 gc_(NULL), 184 gc_(NULL),
170 root_window_(BadValue), 185 root_window_(BadValue),
186 has_xfixes_(false),
187 xfixes_event_base_(-1),
188 xfixes_error_base_(-1),
171 use_damage_(false), 189 use_damage_(false),
172 damage_handle_(0), 190 damage_handle_(0),
173 damage_event_base_(-1), 191 damage_event_base_(-1),
174 damage_error_base_(-1), 192 damage_error_base_(-1),
175 damage_region_(0), 193 damage_region_(0),
176 current_buffer_(0), 194 current_buffer_(0),
177 pixel_format_(media::VideoFrame::RGB32), 195 pixel_format_(media::VideoFrame::RGB32),
178 last_buffer_(NULL) { 196 last_buffer_(NULL) {
179 helper_.SetLogGridSize(4); 197 helper_.SetLogGridSize(4);
180 } 198 }
(...skipping 20 matching lines...) Expand all
201 return false; 219 return false;
202 } 220 }
203 221
204 gc_ = XCreateGC(display_, root_window_, 0, NULL); 222 gc_ = XCreateGC(display_, root_window_, 0, NULL);
205 if (gc_ == NULL) { 223 if (gc_ == NULL) {
206 LOG(ERROR) << "Unable to get graphics context"; 224 LOG(ERROR) << "Unable to get graphics context";
207 DeinitXlib(); 225 DeinitXlib();
208 return false; 226 return false;
209 } 227 }
210 228
229 // Check for XFixes extension. This is required for our XDamage support and
Wez 2012/05/16 00:20:04 nit: Suggest "This is required for cursor shape no
garykac 2012/05/22 00:42:03 Done.
230 // to get the cursor shape notifications.
231 if (XFixesQueryExtension(display_, &xfixes_event_base_,
232 &xfixes_error_base_)) {
233 has_xfixes_ = true;
234 } else {
235 LOG(INFO) << "X server does not support XFixes.";
236 }
237
211 if (ShouldUseXDamage()) { 238 if (ShouldUseXDamage()) {
212 InitXDamage(); 239 InitXDamage();
213 } 240 }
214 241
215 // Register for changes to the dimensions of the root window. 242 // Register for changes to the dimensions of the root window.
216 XSelectInput(display_, root_window_, StructureNotifyMask); 243 XSelectInput(display_, root_window_, StructureNotifyMask);
217 244
245 if (has_xfixes_) {
246 // Register for changes to the cursor shape.
247 XFixesSelectCursorInput(display_, root_window_,
248 XFixesDisplayCursorNotifyMask);
249 }
250
218 return true; 251 return true;
219 } 252 }
220 253
221 void CapturerLinux::InitXDamage() { 254 void CapturerLinux::InitXDamage() {
222 // Check for XFixes and XDamage extensions. If both are found then use 255 if (!has_xfixes_)
256 return;
257
258 // Check for XDamage extension. If this and XFixes are both found then use
Wez 2012/05/16 00:20:04 nit: You've already tested for XFixes, so don't me
garykac 2012/05/22 00:42:03 Done.
223 // XDamage to get explicit notifications of on-screen changes. 259 // XDamage to get explicit notifications of on-screen changes.
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;
229 }
230 if (!XDamageQueryExtension(display_, &damage_event_base_, 260 if (!XDamageQueryExtension(display_, &damage_event_base_,
231 &damage_error_base_)) { 261 &damage_error_base_)) {
232 LOG(INFO) << "X server does not support XDamage."; 262 LOG(INFO) << "X server does not support XDamage.";
233 return; 263 return;
234 } 264 }
235 265
236 // TODO(lambroslambrou): Disable DAMAGE in situations where it is known 266 // TODO(lambroslambrou): Disable DAMAGE in situations where it is known
237 // to fail, such as when Desktop Effects are enabled, with graphics 267 // to fail, such as when Desktop Effects are enabled, with graphics
238 // drivers (nVidia, ATI) that fail to report DAMAGE notifications 268 // drivers (nVidia, ATI) that fail to report DAMAGE notifications
239 // properly. 269 // properly.
(...skipping 17 matching lines...) Expand all
257 use_damage_ = true; 287 use_damage_ = true;
258 LOG(INFO) << "Using XDamage extension."; 288 LOG(INFO) << "Using XDamage extension.";
259 } 289 }
260 290
261 void CapturerLinux::Start() { 291 void CapturerLinux::Start() {
262 } 292 }
263 293
264 void CapturerLinux::Stop() { 294 void CapturerLinux::Stop() {
265 } 295 }
266 296
297 void CapturerLinux::SetCursorShapeChangedCallback(
298 const CursorShapeChangedCallback& callback) {
299 cursor_shape_changed_callback_ = callback;
300 }
301
267 void CapturerLinux::ScreenConfigurationChanged() { 302 void CapturerLinux::ScreenConfigurationChanged() {
268 last_buffer_ = NULL; 303 last_buffer_ = NULL;
269 for (int i = 0; i < kNumBuffers; ++i) { 304 for (int i = 0; i < kNumBuffers; ++i) {
270 buffers_[i].set_needs_update(); 305 buffers_[i].set_needs_update();
271 } 306 }
272 helper_.ClearInvalidRegion(); 307 helper_.ClearInvalidRegion();
273 x_server_pixel_buffer_.Init(display_); 308 x_server_pixel_buffer_.Init(display_);
274 } 309 }
275 310
276 media::VideoFrame::Format CapturerLinux::pixel_format() const { 311 media::VideoFrame::Format CapturerLinux::pixel_format() const {
(...skipping 12 matching lines...) Expand all
289 helper_.InvalidateScreen(size); 324 helper_.InvalidateScreen(size);
290 } 325 }
291 326
292 void CapturerLinux::InvalidateFullScreen() { 327 void CapturerLinux::InvalidateFullScreen() {
293 helper_.InvalidateFullScreen(); 328 helper_.InvalidateFullScreen();
294 last_buffer_ = NULL; 329 last_buffer_ = NULL;
295 } 330 }
296 331
297 void CapturerLinux::CaptureInvalidRegion( 332 void CapturerLinux::CaptureInvalidRegion(
298 const CaptureCompletedCallback& callback) { 333 const CaptureCompletedCallback& callback) {
299 // TODO(lambroslambrou): In the non-DAMAGE case, there should be no need 334 // Process XEvents for XDamage and cursor shape.
Wez 2012/05/16 00:20:04 nit: "... cursor shape tracking"
garykac 2012/05/22 00:42:03 Done.
300 // for any X event processing in this class.
301 ProcessPendingXEvents(); 335 ProcessPendingXEvents();
302 336
303 // Resize the current buffer if there was a recent change of 337 // Resize the current buffer if there was a recent change of
304 // screen-resolution. 338 // screen-resolution.
305 VideoFrameBuffer &current = buffers_[current_buffer_]; 339 VideoFrameBuffer &current = buffers_[current_buffer_];
306 current.Update(display_, root_window_); 340 current.Update(display_, root_window_);
307 // Also refresh the Differ helper used by CaptureFrame(), if needed. 341 // Also refresh the Differ helper used by CaptureFrame(), if needed.
308 if (!use_damage_ && !last_buffer_) { 342 if (!use_damage_ && !last_buffer_) {
309 differ_.reset(new Differ(current.size().width(), current.size().height(), 343 differ_.reset(new Differ(current.size().width(), current.size().height(),
310 kBytesPerPixel, current.bytes_per_row())); 344 kBytesPerPixel, current.bytes_per_row()));
311 } 345 }
312 346
313 scoped_refptr<CaptureData> capture_data(CaptureFrame()); 347 scoped_refptr<CaptureData> capture_data(CaptureFrame());
314 348
315 current_buffer_ = (current_buffer_ + 1) % kNumBuffers; 349 current_buffer_ = (current_buffer_ + 1) % kNumBuffers;
316 350
317 callback.Run(capture_data); 351 callback.Run(capture_data);
318 } 352 }
319 353
320 void CapturerLinux::ProcessPendingXEvents() { 354 void CapturerLinux::ProcessPendingXEvents() {
321 // Find the number of events that are outstanding "now." We don't just loop 355 // Find the number of events that are outstanding "now." We don't just loop
322 // on XPending because we want to guarantee this terminates. 356 // on XPending because we want to guarantee this terminates.
323 int events_to_process = XPending(display_); 357 int events_to_process = XPending(display_);
324 XEvent e; 358 XEvent e;
325 359
326 for (int i = 0; i < events_to_process; i++) { 360 for (int i = 0; i < events_to_process; i++) {
327 XNextEvent(display_, &e); 361 XNextEvent(display_, &e);
328 if (use_damage_ && (e.type == damage_event_base_ + XDamageNotify)) { 362 if (use_damage_ && (e.type == damage_event_base_ + XDamageNotify)) {
329 XDamageNotifyEvent *event = reinterpret_cast<XDamageNotifyEvent*>(&e); 363 XDamageNotifyEvent* event = reinterpret_cast<XDamageNotifyEvent*>(&e);
330 DCHECK(event->level == XDamageReportNonEmpty); 364 DCHECK(event->level == XDamageReportNonEmpty);
331 } else if (e.type == ConfigureNotify) { 365 } else if (e.type == ConfigureNotify) {
332 ScreenConfigurationChanged(); 366 ScreenConfigurationChanged();
367 } else if (has_xfixes_ &&
368 e.type == xfixes_event_base_ + XFixesCursorNotify) {
369 XFixesCursorNotifyEvent* cne;
370 cne = reinterpret_cast<XFixesCursorNotifyEvent*>(&e);
371 if (cne->subtype == XFixesDisplayCursorNotify) {
372 CaptureCursor();
373 }
333 } else { 374 } else {
334 LOG(WARNING) << "Got unknown event type: " << e.type; 375 LOG(WARNING) << "Got unknown event type: " << e.type;
335 } 376 }
336 } 377 }
337 } 378 }
338 379
380 void CapturerLinux::CaptureCursor() {
381 DCHECK(has_xfixes_);
382 if (cursor_shape_changed_callback_.is_null())
383 return;
384
385 // TODO(garykac) Get cursor shape using XFixesGetCursorImage.
386
387 scoped_refptr<CursorShapeData> cursor_data;
388 cursor_shape_changed_callback_.Run(cursor_data);
389 }
390
339 CaptureData* CapturerLinux::CaptureFrame() { 391 CaptureData* CapturerLinux::CaptureFrame() {
340 VideoFrameBuffer& buffer = buffers_[current_buffer_]; 392 VideoFrameBuffer& buffer = buffers_[current_buffer_];
341 DataPlanes planes; 393 DataPlanes planes;
342 planes.data[0] = buffer.ptr(); 394 planes.data[0] = buffer.ptr();
343 planes.strides[0] = buffer.bytes_per_row(); 395 planes.strides[0] = buffer.bytes_per_row();
344 396
345 CaptureData* capture_data = new CaptureData(planes, buffer.size(), 397 CaptureData* capture_data = new CaptureData(planes, buffer.size(),
346 media::VideoFrame::RGB32); 398 media::VideoFrame::RGB32);
347 399
348 // Pass the screen size to the helper, so it can clip the invalid region if it 400 // 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 } 603 }
552 return capturer; 604 return capturer;
553 } 605 }
554 606
555 // static 607 // static
556 void Capturer::EnableXDamage(bool enable) { 608 void Capturer::EnableXDamage(bool enable) {
557 g_should_use_x_damage = enable; 609 g_should_use_x_damage = enable;
558 } 610 }
559 611
560 } // namespace remoting 612 } // namespace remoting
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698