OLD | NEW |
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 "content/common/gpu/image_transport_surface.h" | 5 #include "content/common/gpu/image_transport_surface.h" |
6 | 6 |
7 // This conflicts with the defines in Xlib.h and must come first. | |
8 #include "content/common/gpu/gpu_messages.h" | |
9 | |
10 #include <X11/Xlib.h> | |
11 #include <X11/extensions/Xcomposite.h> | |
12 #include <map> | |
13 #include <vector> | |
14 | |
15 // Note: these must be included before anything that includes gl_bindings.h | |
16 // They're effectively standard library headers. | |
17 #include "third_party/khronos/EGL/egl.h" | |
18 #include "third_party/khronos/EGL/eglext.h" | |
19 #include "third_party/mesa/MesaLib/include/GL/osmesa.h" | |
20 | |
21 #include "base/bind.h" | |
22 #include "base/debug/trace_event.h" | |
23 #include "base/memory/weak_ptr.h" | |
24 #include "content/common/gpu/gpu_channel.h" | |
25 #include "content/common/gpu/gpu_channel_manager.h" | |
26 #include "content/common/gpu/gpu_command_buffer_stub.h" | |
27 #include "content/common/gpu/texture_image_transport_surface.h" | 7 #include "content/common/gpu/texture_image_transport_surface.h" |
28 #include "gpu/command_buffer/service/gpu_scheduler.h" | |
29 #include "ui/gfx/rect.h" | |
30 #include "ui/gl/gl_bindings.h" | |
31 #include "ui/gl/gl_context.h" | |
32 #include "ui/gl/gl_implementation.h" | |
33 #include "ui/gl/gl_surface_egl.h" | |
34 #include "ui/gl/gl_surface_glx.h" | |
35 #include "ui/gl/gl_surface_osmesa.h" | |
36 | |
37 namespace { | |
38 | |
39 class ScopedDisplayLock { | |
40 public: | |
41 ScopedDisplayLock(Display* display): display_(display) { | |
42 XLockDisplay(display_); | |
43 } | |
44 | |
45 ~ScopedDisplayLock() { | |
46 XUnlockDisplay(display_); | |
47 } | |
48 | |
49 private: | |
50 Display* display_; | |
51 | |
52 DISALLOW_COPY_AND_ASSIGN(ScopedDisplayLock); | |
53 }; | |
54 | |
55 // The GL context associated with the surface must be current when | |
56 // an instance is created or destroyed. | |
57 class EGLAcceleratedSurface : public base::RefCounted<EGLAcceleratedSurface> { | |
58 public: | |
59 explicit EGLAcceleratedSurface(const gfx::Size& size); | |
60 const gfx::Size& size() const { return size_; } | |
61 uint32 pixmap() const { return pixmap_; } | |
62 uint32 texture() const { return texture_; } | |
63 | |
64 private: | |
65 ~EGLAcceleratedSurface(); | |
66 | |
67 gfx::Size size_; | |
68 void* image_; | |
69 uint32 pixmap_; | |
70 uint32 texture_; | |
71 | |
72 friend class base::RefCounted<EGLAcceleratedSurface>; | |
73 DISALLOW_COPY_AND_ASSIGN(EGLAcceleratedSurface); | |
74 }; | |
75 | |
76 // We are backed by an Pbuffer offscreen surface for the purposes of creating a | |
77 // context, but use FBOs to render to X Pixmap backed EGLImages. | |
78 class EGLImageTransportSurface | |
79 : public ImageTransportSurface, | |
80 public gfx::PbufferGLSurfaceEGL, | |
81 public base::SupportsWeakPtr<EGLImageTransportSurface> { | |
82 public: | |
83 EGLImageTransportSurface(GpuChannelManager* manager, | |
84 GpuCommandBufferStub* stub); | |
85 | |
86 // gfx::GLSurface implementation | |
87 virtual bool Initialize() OVERRIDE; | |
88 virtual void Destroy() OVERRIDE; | |
89 virtual bool IsOffscreen() OVERRIDE; | |
90 virtual bool SwapBuffers() OVERRIDE; | |
91 virtual bool PostSubBuffer(int x, int y, int width, int height) OVERRIDE; | |
92 virtual std::string GetExtensions() OVERRIDE; | |
93 virtual gfx::Size GetSize() OVERRIDE; | |
94 virtual bool OnMakeCurrent(gfx::GLContext* context) OVERRIDE; | |
95 virtual unsigned int GetBackingFrameBufferObject() OVERRIDE; | |
96 virtual void SetBackbufferAllocation(bool allocated) OVERRIDE; | |
97 virtual void SetFrontbufferAllocation(bool allocated) OVERRIDE; | |
98 | |
99 protected: | |
100 // ImageTransportSurface implementation | |
101 virtual void OnNewSurfaceACK( | |
102 uint64 surface_handle, TransportDIB::Handle shm_handle) OVERRIDE; | |
103 virtual void OnBufferPresented(uint32 sync_point) OVERRIDE; | |
104 virtual void OnResizeViewACK() OVERRIDE; | |
105 virtual void OnResize(gfx::Size size) OVERRIDE; | |
106 | |
107 private: | |
108 virtual ~EGLImageTransportSurface() OVERRIDE; | |
109 void ReleaseSurface(scoped_refptr<EGLAcceleratedSurface>* surface); | |
110 void SendBuffersSwapped(); | |
111 void SendPostSubBuffer(int x, int y, int width, int height); | |
112 | |
113 // Tracks the current buffer allocation state. | |
114 bool backbuffer_suggested_allocation_; | |
115 bool frontbuffer_suggested_allocation_; | |
116 | |
117 // The expected size when visible. | |
118 gfx::Size visible_size_; | |
119 | |
120 uint32 fbo_id_; | |
121 | |
122 scoped_refptr<EGLAcceleratedSurface> back_surface_; | |
123 scoped_refptr<EGLAcceleratedSurface> front_surface_; | |
124 gfx::Rect previous_damage_rect_; | |
125 | |
126 // Whether or not we've successfully made the surface current once. | |
127 bool made_current_; | |
128 | |
129 scoped_ptr<ImageTransportHelper> helper_; | |
130 | |
131 DISALLOW_COPY_AND_ASSIGN(EGLImageTransportSurface); | |
132 }; | |
133 | |
134 // We render to an off-screen (but mapped) window that the browser process will | |
135 // read from via XComposite | |
136 class GLXImageTransportSurface | |
137 : public ImageTransportSurface, | |
138 public gfx::NativeViewGLSurfaceGLX, | |
139 public base::SupportsWeakPtr<GLXImageTransportSurface> { | |
140 public: | |
141 GLXImageTransportSurface(GpuChannelManager* manager, | |
142 GpuCommandBufferStub* stub); | |
143 | |
144 // gfx::GLSurface implementation: | |
145 virtual bool Initialize() OVERRIDE; | |
146 virtual void Destroy() OVERRIDE; | |
147 virtual bool SwapBuffers() OVERRIDE; | |
148 virtual bool PostSubBuffer(int x, int y, int width, int height) OVERRIDE; | |
149 virtual std::string GetExtensions(); | |
150 virtual gfx::Size GetSize() OVERRIDE; | |
151 virtual bool OnMakeCurrent(gfx::GLContext* context) OVERRIDE; | |
152 virtual void SetBackbufferAllocation(bool allocated) OVERRIDE; | |
153 virtual void SetFrontbufferAllocation(bool allocated) OVERRIDE; | |
154 | |
155 protected: | |
156 // ImageTransportSurface implementation: | |
157 virtual void OnNewSurfaceACK( | |
158 uint64 surface_handle, TransportDIB::Handle shm_handle) OVERRIDE; | |
159 virtual void OnBufferPresented(uint32 sync_point) OVERRIDE; | |
160 virtual void OnResizeViewACK() OVERRIDE; | |
161 virtual void OnResize(gfx::Size size) OVERRIDE; | |
162 | |
163 private: | |
164 virtual ~GLXImageTransportSurface(); | |
165 | |
166 // Tell the browser to release the surface. | |
167 void ReleaseSurface(); | |
168 | |
169 void SendBuffersSwapped(); | |
170 void SendPostSubBuffer(int x, int y, int width, int height); | |
171 | |
172 void ResizeSurface(gfx::Size size); | |
173 | |
174 // Tracks the current buffer allocation state. | |
175 bool backbuffer_suggested_allocation_; | |
176 bool frontbuffer_suggested_allocation_; | |
177 | |
178 XID dummy_parent_; | |
179 gfx::Size size_; | |
180 | |
181 // Whether or not the image has been bound on the browser side. | |
182 bool bound_; | |
183 | |
184 // Whether or not we need to send a resize on the next swap. | |
185 bool needs_resize_; | |
186 | |
187 // Whether or not we've successfully made the surface current once. | |
188 bool made_current_; | |
189 | |
190 scoped_ptr<ImageTransportHelper> helper_; | |
191 | |
192 DISALLOW_COPY_AND_ASSIGN(GLXImageTransportSurface); | |
193 }; | |
194 | |
195 // We render to a hunk of shared memory that we get from the browser. | |
196 // Swapping buffers simply means telling the browser to read the contents | |
197 // of the memory. | |
198 class OSMesaImageTransportSurface : public ImageTransportSurface, | |
199 public gfx::GLSurfaceOSMesa { | |
200 public: | |
201 OSMesaImageTransportSurface(GpuChannelManager* manager, | |
202 GpuCommandBufferStub* stub); | |
203 | |
204 // gfx::GLSurface implementation: | |
205 virtual bool Initialize() OVERRIDE; | |
206 virtual void Destroy() OVERRIDE; | |
207 virtual bool IsOffscreen() OVERRIDE; | |
208 virtual bool SwapBuffers() OVERRIDE; | |
209 virtual bool PostSubBuffer(int x, int y, int width, int height) OVERRIDE; | |
210 virtual std::string GetExtensions() OVERRIDE; | |
211 virtual gfx::Size GetSize() OVERRIDE; | |
212 | |
213 protected: | |
214 // ImageTransportSurface implementation: | |
215 virtual void OnNewSurfaceACK( | |
216 uint64 surface_handle, TransportDIB::Handle shm_handle) OVERRIDE; | |
217 virtual void OnBufferPresented(uint32 sync_point) OVERRIDE; | |
218 virtual void OnResizeViewACK() OVERRIDE; | |
219 virtual void OnResize(gfx::Size size) OVERRIDE; | |
220 | |
221 private: | |
222 virtual ~OSMesaImageTransportSurface(); | |
223 | |
224 // Tell the browser to release the surface. | |
225 void ReleaseSurface(); | |
226 | |
227 scoped_ptr<TransportDIB> shared_mem_; | |
228 uint32 shared_id_; | |
229 gfx::Size size_; | |
230 | |
231 scoped_ptr<ImageTransportHelper> helper_; | |
232 | |
233 DISALLOW_COPY_AND_ASSIGN(OSMesaImageTransportSurface); | |
234 }; | |
235 | |
236 EGLAcceleratedSurface::EGLAcceleratedSurface(const gfx::Size& size) | |
237 : size_(size), texture_(0) { | |
238 Display* dpy = gfx::GLSurfaceEGL::GetNativeDisplay(); | |
239 EGLDisplay edpy = gfx::GLSurfaceEGL::GetHardwareDisplay(); | |
240 | |
241 XID window = XDefaultRootWindow(dpy); | |
242 XWindowAttributes gwa; | |
243 bool success = XGetWindowAttributes(dpy, window, &gwa); | |
244 DCHECK(success); | |
245 pixmap_ = XCreatePixmap( | |
246 dpy, window, size_.width(), size_.height(), gwa.depth); | |
247 | |
248 image_ = eglCreateImageKHR( | |
249 edpy, EGL_NO_CONTEXT, EGL_NATIVE_PIXMAP_KHR, | |
250 reinterpret_cast<void*>(pixmap_), NULL); | |
251 | |
252 glGenTextures(1, &texture_); | |
253 | |
254 GLint current_texture = 0; | |
255 glGetIntegerv(GL_TEXTURE_BINDING_2D, ¤t_texture); | |
256 | |
257 glBindTexture(GL_TEXTURE_2D, texture_); | |
258 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |
259 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |
260 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | |
261 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | |
262 glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image_); | |
263 | |
264 glBindTexture(GL_TEXTURE_2D, current_texture); | |
265 } | |
266 | |
267 EGLAcceleratedSurface::~EGLAcceleratedSurface() { | |
268 glDeleteTextures(1, &texture_); | |
269 eglDestroyImageKHR(gfx::GLSurfaceEGL::GetHardwareDisplay(), image_); | |
270 XFreePixmap(gfx::GLSurfaceEGL::GetNativeDisplay(), pixmap_); | |
271 } | |
272 | |
273 EGLImageTransportSurface::EGLImageTransportSurface( | |
274 GpuChannelManager* manager, | |
275 GpuCommandBufferStub* stub) | |
276 : gfx::PbufferGLSurfaceEGL(false, gfx::Size(16, 16)), | |
277 backbuffer_suggested_allocation_(true), | |
278 frontbuffer_suggested_allocation_(true), | |
279 fbo_id_(0), | |
280 made_current_(false) { | |
281 helper_.reset(new ImageTransportHelper(this, | |
282 manager, | |
283 stub, | |
284 gfx::kNullPluginWindow)); | |
285 } | |
286 | |
287 EGLImageTransportSurface::~EGLImageTransportSurface() { | |
288 Destroy(); | |
289 } | |
290 | |
291 bool EGLImageTransportSurface::Initialize() { | |
292 if (!helper_->Initialize()) | |
293 return false; | |
294 return gfx::PbufferGLSurfaceEGL::Initialize(); | |
295 } | |
296 | |
297 void EGLImageTransportSurface::Destroy() { | |
298 if (back_surface_.get()) | |
299 ReleaseSurface(&back_surface_); | |
300 if (front_surface_.get()) | |
301 ReleaseSurface(&front_surface_); | |
302 | |
303 helper_->Destroy(); | |
304 gfx::PbufferGLSurfaceEGL::Destroy(); | |
305 } | |
306 | |
307 // Make sure that buffer swaps occur for the surface, so we can send the data | |
308 // to the actual onscreen surface in the browser | |
309 bool EGLImageTransportSurface::IsOffscreen() { | |
310 return false; | |
311 } | |
312 | |
313 bool EGLImageTransportSurface::OnMakeCurrent(gfx::GLContext* context) { | |
314 if (made_current_) | |
315 return true; | |
316 | |
317 if (!context->HasExtension("EGL_KHR_image") && | |
318 !context->HasExtension("EGL_KHR_image_pixmap")) { | |
319 DLOG(ERROR) << "EGLImage from X11 pixmap not supported"; | |
320 return false; | |
321 } | |
322 | |
323 glGenFramebuffersEXT(1, &fbo_id_); | |
324 glBindFramebufferEXT(GL_FRAMEBUFFER, fbo_id_); | |
325 | |
326 // Creating 16x16 (instead of 1x1) to work around ARM Mali driver issue | |
327 // (see https://code.google.com/p/chrome-os-partner/issues/detail?id=9445) | |
328 OnResize(gfx::Size(16, 16)); | |
329 | |
330 GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER); | |
331 if (status != GL_FRAMEBUFFER_COMPLETE) { | |
332 DLOG(ERROR) << "Framebuffer incomplete."; | |
333 return false; | |
334 } | |
335 | |
336 made_current_ = true; | |
337 return true; | |
338 } | |
339 | |
340 unsigned int EGLImageTransportSurface::GetBackingFrameBufferObject() { | |
341 return fbo_id_; | |
342 } | |
343 | |
344 void EGLImageTransportSurface::SetBackbufferAllocation(bool allocated) { | |
345 if (backbuffer_suggested_allocation_ == allocated) | |
346 return; | |
347 backbuffer_suggested_allocation_ = allocated; | |
348 | |
349 if (backbuffer_suggested_allocation_) | |
350 OnResize(visible_size_); | |
351 else | |
352 ReleaseSurface(&back_surface_); | |
353 } | |
354 | |
355 void EGLImageTransportSurface::SetFrontbufferAllocation(bool allocated) { | |
356 if (frontbuffer_suggested_allocation_ == allocated) | |
357 return; | |
358 frontbuffer_suggested_allocation_ = allocated; | |
359 } | |
360 | |
361 void EGLImageTransportSurface::ReleaseSurface( | |
362 scoped_refptr<EGLAcceleratedSurface>* surface) { | |
363 if (surface->get()) { | |
364 GpuHostMsg_AcceleratedSurfaceRelease_Params params; | |
365 params.identifier = (*surface)->pixmap(); | |
366 helper_->SendAcceleratedSurfaceRelease(params); | |
367 *surface = NULL; | |
368 } | |
369 } | |
370 | |
371 void EGLImageTransportSurface::OnResize(gfx::Size size) { | |
372 visible_size_ = size; | |
373 back_surface_ = new EGLAcceleratedSurface(size); | |
374 | |
375 GLint previous_fbo_id = 0; | |
376 glGetIntegerv(GL_FRAMEBUFFER_BINDING, &previous_fbo_id); | |
377 | |
378 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo_id_); | |
379 glFramebufferTexture2DEXT(GL_FRAMEBUFFER, | |
380 GL_COLOR_ATTACHMENT0, | |
381 GL_TEXTURE_2D, | |
382 back_surface_->texture(), | |
383 0); | |
384 glFlush(); | |
385 | |
386 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, previous_fbo_id); | |
387 | |
388 GpuHostMsg_AcceleratedSurfaceNew_Params params; | |
389 params.width = size.width(); | |
390 params.height = size.height(); | |
391 params.surface_handle = back_surface_->pixmap(); | |
392 helper_->SendAcceleratedSurfaceNew(params); | |
393 | |
394 helper_->SetScheduled(false); | |
395 } | |
396 | |
397 bool EGLImageTransportSurface::SwapBuffers() { | |
398 DCHECK(backbuffer_suggested_allocation_); | |
399 if (!frontbuffer_suggested_allocation_) | |
400 return true; | |
401 front_surface_.swap(back_surface_); | |
402 DCHECK_NE(front_surface_.get(), static_cast<EGLAcceleratedSurface*>(NULL)); | |
403 helper_->DeferToFence(base::Bind( | |
404 &EGLImageTransportSurface::SendBuffersSwapped, | |
405 AsWeakPtr())); | |
406 | |
407 gfx::Size expected_size = front_surface_->size(); | |
408 if (!back_surface_.get() || back_surface_->size() != expected_size) { | |
409 OnResize(expected_size); | |
410 } else { | |
411 glFramebufferTexture2DEXT(GL_FRAMEBUFFER, | |
412 GL_COLOR_ATTACHMENT0, | |
413 GL_TEXTURE_2D, | |
414 back_surface_->texture(), | |
415 0); | |
416 } | |
417 previous_damage_rect_ = gfx::Rect(front_surface_->size()); | |
418 return true; | |
419 } | |
420 | |
421 void EGLImageTransportSurface::SendBuffersSwapped() { | |
422 GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params params; | |
423 params.surface_handle = front_surface_->pixmap(); | |
424 helper_->SendAcceleratedSurfaceBuffersSwapped(params); | |
425 helper_->SetScheduled(false); | |
426 } | |
427 | |
428 bool EGLImageTransportSurface::PostSubBuffer( | |
429 int x, int y, int width, int height) { | |
430 DCHECK(backbuffer_suggested_allocation_); | |
431 if (!frontbuffer_suggested_allocation_) | |
432 return true; | |
433 // If we are recreating the frontbuffer with this swap, make sure we are | |
434 // drawing a full frame. | |
435 DCHECK(front_surface_.get() || | |
436 (!x && !y && gfx::Size(width, height) == visible_size_)); | |
437 DCHECK_NE(back_surface_.get(), static_cast<EGLAcceleratedSurface*>(NULL)); | |
438 gfx::Size expected_size = back_surface_->size(); | |
439 bool surfaces_same_size = front_surface_.get() && | |
440 front_surface_->size() == expected_size; | |
441 | |
442 const gfx::Rect new_damage_rect(x, y, width, height); | |
443 | |
444 // An empty damage rect is a successful no-op. | |
445 if (new_damage_rect.IsEmpty()) | |
446 return true; | |
447 | |
448 if (surfaces_same_size) { | |
449 std::vector<gfx::Rect> regions_to_copy; | |
450 GetRegionsToCopy(previous_damage_rect_, new_damage_rect, ®ions_to_copy); | |
451 | |
452 GLint previous_texture_id = 0; | |
453 glGetIntegerv(GL_ACTIVE_TEXTURE, &previous_texture_id); | |
454 glFramebufferTexture2DEXT(GL_FRAMEBUFFER, | |
455 GL_COLOR_ATTACHMENT0, | |
456 GL_TEXTURE_2D, | |
457 front_surface_->texture(), | |
458 0); | |
459 glBindTexture(GL_TEXTURE_2D, back_surface_->texture()); | |
460 | |
461 for (size_t i = 0; i < regions_to_copy.size(); ++i) { | |
462 const gfx::Rect& region_to_copy = regions_to_copy[i]; | |
463 if (!region_to_copy.IsEmpty()) { | |
464 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, region_to_copy.x(), | |
465 region_to_copy.y(), region_to_copy.x(), region_to_copy.y(), | |
466 region_to_copy.width(), region_to_copy.height()); | |
467 } | |
468 } | |
469 glBindTexture(GL_TEXTURE_2D, previous_texture_id); | |
470 } | |
471 | |
472 front_surface_.swap(back_surface_); | |
473 | |
474 if (!surfaces_same_size) { | |
475 DCHECK(new_damage_rect == gfx::Rect(expected_size)); | |
476 OnResize(expected_size); | |
477 } | |
478 | |
479 helper_->DeferToFence(base::Bind( | |
480 &EGLImageTransportSurface::SendPostSubBuffer, | |
481 AsWeakPtr(), x, y, width, height)); | |
482 | |
483 previous_damage_rect_ = new_damage_rect; | |
484 | |
485 return true; | |
486 } | |
487 | |
488 void EGLImageTransportSurface::SendPostSubBuffer( | |
489 int x, int y, int width, int height) { | |
490 GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params params; | |
491 params.surface_handle = front_surface_->pixmap(); | |
492 params.x = x; | |
493 params.y = y; | |
494 params.width = width; | |
495 params.height = height; | |
496 | |
497 helper_->SendAcceleratedSurfacePostSubBuffer(params); | |
498 helper_->SetScheduled(false); | |
499 } | |
500 | |
501 std::string EGLImageTransportSurface::GetExtensions() { | |
502 std::string extensions = gfx::GLSurface::GetExtensions(); | |
503 extensions += extensions.empty() ? "" : " "; | |
504 extensions += "GL_CHROMIUM_front_buffer_cached "; | |
505 extensions += "GL_CHROMIUM_post_sub_buffer"; | |
506 return extensions; | |
507 } | |
508 | |
509 gfx::Size EGLImageTransportSurface::GetSize() { | |
510 return back_surface_->size(); | |
511 } | |
512 | |
513 void EGLImageTransportSurface::OnNewSurfaceACK( | |
514 uint64 surface_handle, TransportDIB::Handle /*shm_handle*/) { | |
515 DCHECK_EQ(back_surface_->pixmap(), surface_handle); | |
516 helper_->SetScheduled(true); | |
517 } | |
518 | |
519 void EGLImageTransportSurface::OnBufferPresented(uint32 sync_point) { | |
520 helper_->SetScheduled(true); | |
521 } | |
522 | |
523 void EGLImageTransportSurface::OnResizeViewACK() { | |
524 NOTREACHED(); | |
525 } | |
526 | |
527 GLXImageTransportSurface::GLXImageTransportSurface( | |
528 GpuChannelManager* manager, | |
529 GpuCommandBufferStub* stub) | |
530 : gfx::NativeViewGLSurfaceGLX(), | |
531 backbuffer_suggested_allocation_(true), | |
532 frontbuffer_suggested_allocation_(true), | |
533 dummy_parent_(0), | |
534 size_(1, 1), | |
535 bound_(false), | |
536 needs_resize_(false), | |
537 made_current_(false) { | |
538 helper_.reset(new ImageTransportHelper(this, | |
539 manager, | |
540 stub, | |
541 gfx::kNullPluginWindow)); | |
542 } | |
543 | |
544 GLXImageTransportSurface::~GLXImageTransportSurface() { | |
545 Destroy(); | |
546 } | |
547 | |
548 bool GLXImageTransportSurface::Initialize() { | |
549 // Create a dummy window to host the real window. | |
550 Display* dpy = static_cast<Display*>(GetDisplay()); | |
551 ScopedDisplayLock lock(dpy); | |
552 | |
553 XSetWindowAttributes swa; | |
554 swa.override_redirect = True; | |
555 dummy_parent_ = XCreateWindow( | |
556 dpy, | |
557 RootWindow(dpy, DefaultScreen(dpy)), // parent | |
558 -100, -100, 1, 1, | |
559 0, // border width | |
560 CopyFromParent, // depth | |
561 InputOutput, | |
562 CopyFromParent, // visual | |
563 CWOverrideRedirect, &swa); | |
564 XMapWindow(dpy, dummy_parent_); | |
565 | |
566 swa.event_mask = StructureNotifyMask; | |
567 swa.override_redirect = false; | |
568 window_ = XCreateWindow(dpy, | |
569 dummy_parent_, | |
570 0, 0, size_.width(), size_.height(), | |
571 0, // border width | |
572 CopyFromParent, // depth | |
573 InputOutput, | |
574 CopyFromParent, // visual | |
575 CWEventMask, &swa); | |
576 XMapWindow(dpy, window_); | |
577 while (1) { | |
578 XEvent event; | |
579 XWindowEvent(dpy, window_, StructureNotifyMask, &event); | |
580 if (event.type == MapNotify && event.xmap.window == window_) | |
581 break; | |
582 } | |
583 XSelectInput(dpy, window_, NoEventMask); | |
584 | |
585 // Manual setting must be used to avoid unnecessary rendering by server. | |
586 XCompositeRedirectWindow(dpy, window_, CompositeRedirectManual); | |
587 OnResize(size_); | |
588 | |
589 if (!helper_->Initialize()) | |
590 return false; | |
591 return gfx::NativeViewGLSurfaceGLX::Initialize(); | |
592 } | |
593 | |
594 void GLXImageTransportSurface::Destroy() { | |
595 if (bound_) | |
596 ReleaseSurface(); | |
597 | |
598 if (window_) { | |
599 Display* dpy = static_cast<Display*>(GetDisplay()); | |
600 XDestroyWindow(dpy, window_); | |
601 XDestroyWindow(dpy, dummy_parent_); | |
602 } | |
603 | |
604 helper_->Destroy(); | |
605 gfx::NativeViewGLSurfaceGLX::Destroy(); | |
606 } | |
607 | |
608 void GLXImageTransportSurface::ReleaseSurface() { | |
609 DCHECK(bound_); | |
610 GpuHostMsg_AcceleratedSurfaceRelease_Params params; | |
611 params.identifier = window_; | |
612 helper_->SendAcceleratedSurfaceRelease(params); | |
613 bound_ = false; | |
614 } | |
615 | |
616 void GLXImageTransportSurface::SetBackbufferAllocation(bool allocated) { | |
617 if (backbuffer_suggested_allocation_ == allocated) | |
618 return; | |
619 backbuffer_suggested_allocation_ = allocated; | |
620 | |
621 if (backbuffer_suggested_allocation_) | |
622 ResizeSurface(size_); | |
623 else | |
624 ResizeSurface(gfx::Size(1,1)); | |
625 } | |
626 | |
627 void GLXImageTransportSurface::SetFrontbufferAllocation(bool allocated) { | |
628 if (frontbuffer_suggested_allocation_ == allocated) | |
629 return; | |
630 frontbuffer_suggested_allocation_ = allocated; | |
631 | |
632 // We recreate frontbuffer by recreating backbuffer and swapping. | |
633 // But we release frontbuffer by telling UI to release its handle on it. | |
634 if (!frontbuffer_suggested_allocation_ && bound_) | |
635 ReleaseSurface(); | |
636 } | |
637 | |
638 void GLXImageTransportSurface::ResizeSurface(gfx::Size size) { | |
639 Display* dpy = static_cast<Display*>(GetDisplay()); | |
640 XResizeWindow(dpy, window_, size.width(), size.height()); | |
641 glXWaitX(); | |
642 // Seems necessary to perform a swap after a resize | |
643 // in order to resize the front and back buffers (Intel driver bug). | |
644 // This doesn't always happen with scissoring enabled, so do it now. | |
645 if (gfx::g_GLX_MESA_copy_sub_buffer && gfx::GLSurface::GetCurrent() == this) | |
646 gfx::NativeViewGLSurfaceGLX::SwapBuffers(); | |
647 needs_resize_ = true; | |
648 } | |
649 | |
650 void GLXImageTransportSurface::OnResize(gfx::Size size) { | |
651 TRACE_EVENT0("gpu", "GLXImageTransportSurface::OnResize"); | |
652 size_ = size; | |
653 ResizeSurface(size_); | |
654 } | |
655 | |
656 bool GLXImageTransportSurface::SwapBuffers() { | |
657 DCHECK(backbuffer_suggested_allocation_); | |
658 if (!frontbuffer_suggested_allocation_) | |
659 return true; | |
660 gfx::NativeViewGLSurfaceGLX::SwapBuffers(); | |
661 helper_->DeferToFence(base::Bind( | |
662 &GLXImageTransportSurface::SendBuffersSwapped, | |
663 AsWeakPtr())); | |
664 | |
665 if (needs_resize_) { | |
666 GpuHostMsg_AcceleratedSurfaceNew_Params params; | |
667 params.width = size_.width(); | |
668 params.height = size_.height(); | |
669 params.surface_handle = window_; | |
670 helper_->SendAcceleratedSurfaceNew(params); | |
671 bound_ = true; | |
672 needs_resize_ = false; | |
673 } | |
674 return true; | |
675 } | |
676 | |
677 void GLXImageTransportSurface::SendBuffersSwapped() { | |
678 GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params params; | |
679 params.surface_handle = window_; | |
680 helper_->SendAcceleratedSurfaceBuffersSwapped(params); | |
681 helper_->SetScheduled(false); | |
682 } | |
683 | |
684 bool GLXImageTransportSurface::PostSubBuffer( | |
685 int x, int y, int width, int height) { | |
686 DCHECK(backbuffer_suggested_allocation_); | |
687 if (!frontbuffer_suggested_allocation_) | |
688 return true; | |
689 gfx::NativeViewGLSurfaceGLX::PostSubBuffer(x, y, width, height); | |
690 helper_->DeferToFence(base::Bind( | |
691 &GLXImageTransportSurface::SendPostSubBuffer, | |
692 AsWeakPtr(), x, y, width, height)); | |
693 | |
694 if (needs_resize_) { | |
695 GpuHostMsg_AcceleratedSurfaceNew_Params params; | |
696 params.width = size_.width(); | |
697 params.height = size_.height(); | |
698 params.surface_handle = window_; | |
699 helper_->SendAcceleratedSurfaceNew(params); | |
700 bound_ = true; | |
701 needs_resize_ = false; | |
702 } | |
703 return true; | |
704 } | |
705 | |
706 void GLXImageTransportSurface::SendPostSubBuffer( | |
707 int x, int y, int width, int height) { | |
708 GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params params; | |
709 params.surface_handle = window_; | |
710 params.x = x; | |
711 params.y = y; | |
712 params.width = width; | |
713 params.height = height; | |
714 | |
715 helper_->SendAcceleratedSurfacePostSubBuffer(params); | |
716 helper_->SetScheduled(false); | |
717 } | |
718 | |
719 std::string GLXImageTransportSurface::GetExtensions() { | |
720 std::string extensions = gfx::NativeViewGLSurfaceGLX::GetExtensions(); | |
721 extensions += extensions.empty() ? "" : " "; | |
722 extensions += "GL_CHROMIUM_front_buffer_cached"; | |
723 return extensions; | |
724 } | |
725 | |
726 gfx::Size GLXImageTransportSurface::GetSize() { | |
727 return size_; | |
728 } | |
729 | |
730 bool GLXImageTransportSurface::OnMakeCurrent(gfx::GLContext* context) { | |
731 if (made_current_) | |
732 return true; | |
733 | |
734 // Check for driver support. | |
735 Display* dpy = static_cast<Display*>(GetDisplay()); | |
736 int event_base, error_base; | |
737 if (XCompositeQueryExtension(dpy, &event_base, &error_base)) { | |
738 int major = 0, minor = 2; | |
739 XCompositeQueryVersion(dpy, &major, &minor); | |
740 if (major == 0 && minor < 2) { | |
741 DLOG(ERROR) << "Pixmap from window not supported."; | |
742 return false; | |
743 } | |
744 } | |
745 | |
746 context->SetSwapInterval(0); | |
747 | |
748 made_current_ = true; | |
749 return true; | |
750 } | |
751 | |
752 void GLXImageTransportSurface::OnNewSurfaceACK( | |
753 uint64 surface_handle, TransportDIB::Handle /*shm_handle*/) { | |
754 } | |
755 | |
756 void GLXImageTransportSurface::OnBufferPresented(uint32 sync_point) { | |
757 helper_->SetScheduled(true); | |
758 } | |
759 | |
760 void GLXImageTransportSurface::OnResizeViewACK() { | |
761 NOTREACHED(); | |
762 } | |
763 | |
764 OSMesaImageTransportSurface::OSMesaImageTransportSurface( | |
765 GpuChannelManager* manager, | |
766 GpuCommandBufferStub* stub) | |
767 : gfx::GLSurfaceOSMesa(OSMESA_RGBA, gfx::Size(1, 1)), | |
768 size_(gfx::Size(1, 1)) { | |
769 helper_.reset(new ImageTransportHelper(this, | |
770 manager, | |
771 stub, | |
772 gfx::kNullPluginWindow)); | |
773 } | |
774 | |
775 OSMesaImageTransportSurface::~OSMesaImageTransportSurface() { | |
776 Destroy(); | |
777 } | |
778 | |
779 bool OSMesaImageTransportSurface::Initialize() { | |
780 if (!helper_->Initialize()) | |
781 return false; | |
782 return gfx::GLSurfaceOSMesa::Initialize(); | |
783 } | |
784 | |
785 void OSMesaImageTransportSurface::Destroy() { | |
786 if (shared_mem_.get()) | |
787 ReleaseSurface(); | |
788 | |
789 helper_->Destroy(); | |
790 gfx::GLSurfaceOSMesa::Destroy(); | |
791 } | |
792 | |
793 // Make sure that buffer swaps occur for the surface, so we can send the data | |
794 // to the actual onscreen surface in the browser | |
795 bool OSMesaImageTransportSurface::IsOffscreen() { | |
796 return false; | |
797 } | |
798 | |
799 void OSMesaImageTransportSurface::ReleaseSurface() { | |
800 GpuHostMsg_AcceleratedSurfaceRelease_Params params; | |
801 params.identifier = shared_id_; | |
802 helper_->SendAcceleratedSurfaceRelease(params); | |
803 | |
804 shared_mem_.reset(); | |
805 shared_id_ = 0; | |
806 } | |
807 | |
808 void OSMesaImageTransportSurface::OnResize(gfx::Size size) { | |
809 shared_mem_.reset(); | |
810 shared_id_ = 0; | |
811 | |
812 GLSurfaceOSMesa::Resize(size); | |
813 | |
814 // Now that we resized/reallocated the memory buffer, we need to change | |
815 // what OSMesa is pointing at to the new buffer. | |
816 helper_->MakeCurrent(); | |
817 | |
818 size_ = size; | |
819 | |
820 GpuHostMsg_AcceleratedSurfaceNew_Params params; | |
821 params.width = size_.width(); | |
822 params.height = size_.height(); | |
823 params.surface_handle = 0; // id comes from the browser with the shared mem | |
824 helper_->SendAcceleratedSurfaceNew(params); | |
825 | |
826 helper_->SetScheduled(false); | |
827 } | |
828 | |
829 void OSMesaImageTransportSurface::OnNewSurfaceACK( | |
830 uint64 surface_handle, TransportDIB::Handle shm_handle) { | |
831 shared_id_ = surface_handle; | |
832 shared_mem_.reset(TransportDIB::Map(shm_handle)); | |
833 DCHECK_NE(shared_mem_.get(), static_cast<void*>(NULL)); | |
834 | |
835 helper_->SetScheduled(true); | |
836 } | |
837 | |
838 void OSMesaImageTransportSurface::OnResizeViewACK() { | |
839 NOTREACHED(); | |
840 } | |
841 | |
842 bool OSMesaImageTransportSurface::SwapBuffers() { | |
843 DCHECK_NE(shared_mem_.get(), static_cast<void*>(NULL)); | |
844 | |
845 // Copy the OSMesa buffer to the shared memory | |
846 glFinish(); | |
847 memcpy(shared_mem_->memory(), GetHandle(), size_.GetArea() * 4); | |
848 | |
849 GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params params; | |
850 params.surface_handle = shared_id_; | |
851 helper_->SendAcceleratedSurfaceBuffersSwapped(params); | |
852 | |
853 helper_->SetScheduled(false); | |
854 return true; | |
855 } | |
856 | |
857 bool OSMesaImageTransportSurface::PostSubBuffer( | |
858 int x, int y, int width, int height) { | |
859 DCHECK_NE(shared_mem_.get(), static_cast<void*>(NULL)); | |
860 | |
861 // Copy the OSMesa buffer to the shared memory | |
862 glFinish(); | |
863 | |
864 int flipped_y = GetSize().height() - y - height; | |
865 | |
866 for (int row = 0; row < height; ++row) { | |
867 int mem_offset = ((flipped_y + row) * size_.width() + x); | |
868 int32* dest_address = static_cast<int32*>(shared_mem_->memory()) + | |
869 mem_offset; | |
870 int32* src_address = static_cast<int32*>(GetHandle()) + mem_offset; | |
871 memcpy(dest_address, src_address, width * 4); | |
872 } | |
873 | |
874 GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params params; | |
875 params.surface_handle = shared_id_; | |
876 params.x = x; | |
877 params.y = y; | |
878 params.width = width; | |
879 params.height = height; | |
880 helper_->SendAcceleratedSurfacePostSubBuffer(params); | |
881 | |
882 helper_->SetScheduled(false); | |
883 return true; | |
884 } | |
885 | |
886 std::string OSMesaImageTransportSurface::GetExtensions() { | |
887 std::string extensions = gfx::GLSurface::GetExtensions(); | |
888 extensions += extensions.empty() ? "" : " "; | |
889 extensions += "GL_CHROMIUM_front_buffer_cached "; | |
890 extensions += "GL_CHROMIUM_post_sub_buffer"; | |
891 return extensions; | |
892 } | |
893 | |
894 void OSMesaImageTransportSurface::OnBufferPresented(uint32 sync_point) { | |
895 helper_->SetScheduled(true); | |
896 } | |
897 | |
898 gfx::Size OSMesaImageTransportSurface::GetSize() { | |
899 return size_; | |
900 } | |
901 | |
902 } // namespace | |
903 | 8 |
904 // static | 9 // static |
905 scoped_refptr<gfx::GLSurface> ImageTransportSurface::CreateSurface( | 10 scoped_refptr<gfx::GLSurface> ImageTransportSurface::CreateSurface( |
906 GpuChannelManager* manager, | 11 GpuChannelManager* manager, |
907 GpuCommandBufferStub* stub, | 12 GpuCommandBufferStub* stub, |
908 const gfx::GLSurfaceHandle& handle) { | 13 const gfx::GLSurfaceHandle& handle) { |
909 scoped_refptr<gfx::GLSurface> surface; | 14 scoped_refptr<gfx::GLSurface> surface; |
910 if (!handle.handle) { | 15 if (!handle.handle) { |
911 DCHECK(handle.transport); | 16 DCHECK(handle.transport); |
912 if (!handle.parent_client_id) { | 17 DCHECK(handle.parent_client_id); |
913 switch (gfx::GetGLImplementation()) { | 18 surface = new TextureImageTransportSurface(manager, stub, handle); |
914 case gfx::kGLImplementationDesktopGL: | |
915 surface = new GLXImageTransportSurface(manager, stub); | |
916 break; | |
917 case gfx::kGLImplementationEGLGLES2: | |
918 surface = new EGLImageTransportSurface(manager, stub); | |
919 break; | |
920 case gfx::kGLImplementationOSMesaGL: | |
921 surface = new OSMesaImageTransportSurface(manager, stub); | |
922 break; | |
923 default: | |
924 NOTREACHED(); | |
925 return NULL; | |
926 } | |
927 } else { | |
928 surface = new TextureImageTransportSurface(manager, stub, handle); | |
929 } | |
930 } else { | 19 } else { |
931 surface = gfx::GLSurface::CreateViewGLSurface(false, handle.handle); | 20 surface = gfx::GLSurface::CreateViewGLSurface(false, handle.handle); |
932 if (!surface.get()) | 21 if (!surface.get()) |
933 return NULL; | 22 return NULL; |
934 surface = new PassThroughImageTransportSurface(manager, | 23 surface = new PassThroughImageTransportSurface(manager, |
935 stub, | 24 stub, |
936 surface.get(), | 25 surface.get(), |
937 handle.transport); | 26 handle.transport); |
938 } | 27 } |
939 | 28 |
940 if (surface->Initialize()) | 29 if (surface->Initialize()) |
941 return surface; | 30 return surface; |
942 else | 31 else |
943 return NULL; | 32 return NULL; |
944 } | 33 } |
OLD | NEW |