| 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 |