| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "content/browser/renderer_host/accelerated_surface_container_linux.h" | |
| 6 | |
| 7 #include <X11/Xlib.h> | |
| 8 #include <X11/extensions/Xcomposite.h> | |
| 9 | |
| 10 #include "base/lazy_instance.h" | |
| 11 #include "base/memory/scoped_ptr.h" | |
| 12 #include "third_party/angle/include/EGL/egl.h" | |
| 13 #include "third_party/angle/include/EGL/eglext.h" | |
| 14 #include "ui/gfx/gl/gl_bindings.h" | |
| 15 #include "ui/gfx/gl/gl_implementation.h" | |
| 16 #include "ui/gfx/gl/gl_surface_egl.h" | |
| 17 #include "ui/gfx/gl/gl_surface_glx.h" | |
| 18 #include "ui/gfx/rect.h" | |
| 19 #include "ui/gfx/transform.h" | |
| 20 | |
| 21 namespace { | |
| 22 | |
| 23 class AcceleratedSurfaceContainerLinuxEGL | |
| 24 : public AcceleratedSurfaceContainerLinux { | |
| 25 public: | |
| 26 explicit AcceleratedSurfaceContainerLinuxEGL(const gfx::Size& size); | |
| 27 | |
| 28 virtual bool Initialize(uint64* surface_id) OVERRIDE; | |
| 29 | |
| 30 // TextureGL implementation | |
| 31 virtual void Draw(const ui::TextureDrawParams& params, | |
| 32 const gfx::Rect& clip_bounds_in_texture) OVERRIDE; | |
| 33 | |
| 34 private: | |
| 35 virtual ~AcceleratedSurfaceContainerLinuxEGL(); | |
| 36 | |
| 37 void* image_; | |
| 38 | |
| 39 DISALLOW_COPY_AND_ASSIGN(AcceleratedSurfaceContainerLinuxEGL); | |
| 40 }; | |
| 41 | |
| 42 class AcceleratedSurfaceContainerLinuxGLX | |
| 43 : public AcceleratedSurfaceContainerLinux { | |
| 44 public: | |
| 45 explicit AcceleratedSurfaceContainerLinuxGLX(const gfx::Size& size); | |
| 46 | |
| 47 virtual bool Initialize(uint64* surface_id) OVERRIDE; | |
| 48 | |
| 49 // TextureGL implementation | |
| 50 virtual void Draw(const ui::TextureDrawParams& params, | |
| 51 const gfx::Rect& clip_bounds_in_texture) OVERRIDE; | |
| 52 | |
| 53 protected: | |
| 54 static bool InitializeOneOff(); | |
| 55 | |
| 56 static base::LazyInstance<GLXFBConfig> fbconfig_; | |
| 57 | |
| 58 private: | |
| 59 virtual ~AcceleratedSurfaceContainerLinuxGLX(); | |
| 60 | |
| 61 XID pixmap_; | |
| 62 XID glx_pixmap_; | |
| 63 | |
| 64 DISALLOW_COPY_AND_ASSIGN(AcceleratedSurfaceContainerLinuxGLX); | |
| 65 }; | |
| 66 | |
| 67 class AcceleratedSurfaceContainerLinuxOSMesa | |
| 68 : public AcceleratedSurfaceContainerLinux { | |
| 69 public: | |
| 70 explicit AcceleratedSurfaceContainerLinuxOSMesa(const gfx::Size& size); | |
| 71 | |
| 72 virtual bool Initialize(uint64* surface_id) OVERRIDE; | |
| 73 | |
| 74 // TextureGL implementation | |
| 75 virtual void Draw(const ui::TextureDrawParams& params, | |
| 76 const gfx::Rect& clip_bounds_in_texture) OVERRIDE; | |
| 77 | |
| 78 // Some implementations of this class use shared memory, this gives the handle | |
| 79 // to the shared buffer, which is part of the surface container. | |
| 80 // When shared memory is not used, this will return | |
| 81 // TransportDIB::DefaultHandleValue(). | |
| 82 virtual TransportDIB::Handle Handle() const OVERRIDE; | |
| 83 | |
| 84 private: | |
| 85 virtual ~AcceleratedSurfaceContainerLinuxOSMesa(); | |
| 86 | |
| 87 scoped_ptr<TransportDIB> shared_mem_; | |
| 88 | |
| 89 DISALLOW_COPY_AND_ASSIGN(AcceleratedSurfaceContainerLinuxOSMesa); | |
| 90 }; | |
| 91 | |
| 92 class ScopedPtrXFree { | |
| 93 public: | |
| 94 void operator()(void* x) const { | |
| 95 ::XFree(x); | |
| 96 } | |
| 97 }; | |
| 98 | |
| 99 // static | |
| 100 base::LazyInstance<GLXFBConfig> AcceleratedSurfaceContainerLinuxGLX::fbconfig_( | |
| 101 base::LINKER_INITIALIZED); | |
| 102 | |
| 103 AcceleratedSurfaceContainerLinuxEGL::AcceleratedSurfaceContainerLinuxEGL( | |
| 104 const gfx::Size& size) | |
| 105 : AcceleratedSurfaceContainerLinux(size), | |
| 106 image_(NULL) { | |
| 107 } | |
| 108 | |
| 109 bool AcceleratedSurfaceContainerLinuxEGL::Initialize(uint64* surface_id) { | |
| 110 ui::SharedResources* instance = ui::SharedResources::GetInstance(); | |
| 111 DCHECK(instance); | |
| 112 instance->MakeSharedContextCurrent(); | |
| 113 | |
| 114 image_ = eglCreateImageKHR( | |
| 115 gfx::GLSurfaceEGL::GetHardwareDisplay(), EGL_NO_CONTEXT, | |
| 116 EGL_NATIVE_PIXMAP_KHR, reinterpret_cast<void*>(*surface_id), NULL); | |
| 117 | |
| 118 glGenTextures(1, &texture_id_); | |
| 119 glBindTexture(GL_TEXTURE_2D, texture_id_); | |
| 120 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |
| 121 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |
| 122 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | |
| 123 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | |
| 124 glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image_); | |
| 125 glFlush(); | |
| 126 | |
| 127 return true; | |
| 128 } | |
| 129 | |
| 130 AcceleratedSurfaceContainerLinuxEGL::~AcceleratedSurfaceContainerLinuxEGL() { | |
| 131 ui::SharedResources* instance = ui::SharedResources::GetInstance(); | |
| 132 DCHECK(instance); | |
| 133 instance->MakeSharedContextCurrent(); | |
| 134 | |
| 135 eglDestroyImageKHR(gfx::GLSurfaceEGL::GetHardwareDisplay(), image_); | |
| 136 glFlush(); | |
| 137 } | |
| 138 | |
| 139 void AcceleratedSurfaceContainerLinuxEGL::Draw( | |
| 140 const ui::TextureDrawParams& params, | |
| 141 const gfx::Rect& clip_bounds_in_texture) { | |
| 142 ui::SharedResources* instance = ui::SharedResources::GetInstance(); | |
| 143 DCHECK(instance); | |
| 144 | |
| 145 ui::TextureDrawParams modified_params = params; | |
| 146 modified_params.vertically_flipped = true; | |
| 147 | |
| 148 DrawInternal(*instance->program_no_swizzle(), | |
| 149 modified_params, | |
| 150 clip_bounds_in_texture); | |
| 151 } | |
| 152 | |
| 153 AcceleratedSurfaceContainerLinuxGLX::AcceleratedSurfaceContainerLinuxGLX( | |
| 154 const gfx::Size& size) | |
| 155 : AcceleratedSurfaceContainerLinux(size), | |
| 156 pixmap_(0), | |
| 157 glx_pixmap_(0) { | |
| 158 } | |
| 159 | |
| 160 bool AcceleratedSurfaceContainerLinuxGLX::Initialize(uint64* surface_id) { | |
| 161 ui::SharedResources* instance = ui::SharedResources::GetInstance(); | |
| 162 DCHECK(instance); | |
| 163 instance->MakeSharedContextCurrent(); | |
| 164 | |
| 165 if (!AcceleratedSurfaceContainerLinuxGLX::InitializeOneOff()) | |
| 166 return false; | |
| 167 | |
| 168 // Create pixmap from window. | |
| 169 // We receive a window here rather than a pixmap directly because drivers | |
| 170 // require (or required) that the pixmap used to create the GL texture be | |
| 171 // created in the same process as the texture. | |
| 172 Display* dpy = gfx::GLSurfaceGLX::GetDisplay(); | |
| 173 pixmap_ = XCompositeNameWindowPixmap(dpy, *surface_id); | |
| 174 | |
| 175 // Wrap the pixmap in a GLXPixmap | |
| 176 const int pixmapAttribs[] = { | |
| 177 GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT, | |
| 178 GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGB_EXT, | |
| 179 0 | |
| 180 }; | |
| 181 | |
| 182 glx_pixmap_ = glXCreatePixmap( | |
| 183 dpy, fbconfig_.Get(), pixmap_, pixmapAttribs); | |
| 184 | |
| 185 // Create texture. | |
| 186 glGenTextures(1, &texture_id_); | |
| 187 glBindTexture(GL_TEXTURE_2D, texture_id_); | |
| 188 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |
| 189 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |
| 190 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | |
| 191 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | |
| 192 | |
| 193 return true; | |
| 194 } | |
| 195 | |
| 196 AcceleratedSurfaceContainerLinuxGLX::~AcceleratedSurfaceContainerLinuxGLX() { | |
| 197 ui::SharedResources* instance = ui::SharedResources::GetInstance(); | |
| 198 DCHECK(instance); | |
| 199 instance->MakeSharedContextCurrent(); | |
| 200 | |
| 201 Display* dpy = gfx::GLSurfaceGLX::GetDisplay(); | |
| 202 if (glx_pixmap_) | |
| 203 glXDestroyGLXPixmap(dpy, glx_pixmap_); | |
| 204 if (pixmap_) | |
| 205 XFreePixmap(dpy, pixmap_); | |
| 206 } | |
| 207 | |
| 208 void AcceleratedSurfaceContainerLinuxGLX::Draw( | |
| 209 const ui::TextureDrawParams& params, | |
| 210 const gfx::Rect& clip_bounds_in_texture) { | |
| 211 ui::SharedResources* instance = ui::SharedResources::GetInstance(); | |
| 212 DCHECK(instance); | |
| 213 | |
| 214 Display* dpy = gfx::GLSurfaceGLX::GetDisplay(); | |
| 215 | |
| 216 glBindTexture(GL_TEXTURE_2D, texture_id_); | |
| 217 glXBindTexImageEXT(dpy, glx_pixmap_, GLX_FRONT_LEFT_EXT, NULL); | |
| 218 DrawInternal(*instance->program_no_swizzle(), | |
| 219 params, | |
| 220 clip_bounds_in_texture); | |
| 221 glXReleaseTexImageEXT(dpy, glx_pixmap_, GLX_FRONT_LEFT_EXT); | |
| 222 } | |
| 223 | |
| 224 // static | |
| 225 bool AcceleratedSurfaceContainerLinuxGLX::InitializeOneOff() | |
| 226 { | |
| 227 static bool initialized = false; | |
| 228 if (initialized) | |
| 229 return true; | |
| 230 | |
| 231 Display* dpy = gfx::GLSurfaceGLX::GetDisplay(); | |
| 232 int event_base, error_base; | |
| 233 if (XCompositeQueryExtension(dpy, &event_base, &error_base)) { | |
| 234 int major = 0, minor = 2; | |
| 235 XCompositeQueryVersion(dpy, &major, &minor); | |
| 236 if (major == 0 && minor < 2) { | |
| 237 LOG(ERROR) << "Pixmap from window not supported."; | |
| 238 return false; | |
| 239 } | |
| 240 } | |
| 241 | |
| 242 // Wrap the pixmap in a GLXPixmap | |
| 243 int screen = DefaultScreen(dpy); | |
| 244 XWindowAttributes gwa; | |
| 245 XGetWindowAttributes(dpy, RootWindow(dpy, screen), &gwa); | |
| 246 unsigned int visualid = XVisualIDFromVisual(gwa.visual); | |
| 247 | |
| 248 int nfbconfigs, config; | |
| 249 scoped_ptr_malloc<GLXFBConfig, ScopedPtrXFree> fbconfigs( | |
| 250 glXGetFBConfigs(dpy, screen, &nfbconfigs)); | |
| 251 | |
| 252 for (config = 0; config < nfbconfigs; config++) { | |
| 253 XVisualInfo* visinfo = glXGetVisualFromFBConfig( | |
| 254 dpy, fbconfigs.get()[config]); | |
| 255 if (!visinfo || visinfo->visualid != visualid) | |
| 256 continue; | |
| 257 | |
| 258 int value; | |
| 259 glXGetFBConfigAttrib(dpy, | |
| 260 fbconfigs.get()[config], | |
| 261 GLX_DRAWABLE_TYPE, | |
| 262 &value); | |
| 263 if (!(value & GLX_PIXMAP_BIT)) | |
| 264 continue; | |
| 265 | |
| 266 glXGetFBConfigAttrib(dpy, | |
| 267 fbconfigs.get()[config], | |
| 268 GLX_BIND_TO_TEXTURE_TARGETS_EXT, | |
| 269 &value); | |
| 270 if (!(value & GLX_TEXTURE_2D_BIT_EXT)) | |
| 271 continue; | |
| 272 | |
| 273 glXGetFBConfigAttrib(dpy, | |
| 274 fbconfigs.get()[config], | |
| 275 GLX_BIND_TO_TEXTURE_RGB_EXT, | |
| 276 &value); | |
| 277 if (value == GL_FALSE) | |
| 278 continue; | |
| 279 | |
| 280 break; | |
| 281 } | |
| 282 | |
| 283 if (config == nfbconfigs) { | |
| 284 LOG(ERROR) | |
| 285 << "Could not find configuration suitable for binding a pixmap " | |
| 286 << "as a texture."; | |
| 287 return false; | |
| 288 } | |
| 289 | |
| 290 fbconfig_.Get() = fbconfigs.get()[config]; | |
| 291 | |
| 292 initialized = true; | |
| 293 return initialized; | |
| 294 } | |
| 295 | |
| 296 AcceleratedSurfaceContainerLinuxOSMesa::AcceleratedSurfaceContainerLinuxOSMesa( | |
| 297 const gfx::Size& size) | |
| 298 : AcceleratedSurfaceContainerLinux(size) { | |
| 299 } | |
| 300 | |
| 301 bool AcceleratedSurfaceContainerLinuxOSMesa::Initialize(uint64* surface_id) { | |
| 302 static uint32 next_id = 1; | |
| 303 | |
| 304 ui::SharedResources* instance = ui::SharedResources::GetInstance(); | |
| 305 DCHECK(instance); | |
| 306 instance->MakeSharedContextCurrent(); | |
| 307 | |
| 308 // We expect to make the id here, so don't want the other end giving us one | |
| 309 DCHECK_EQ(*surface_id, static_cast<uint64>(0)); | |
| 310 | |
| 311 // It's possible that this ID gneration could clash with IDs from other | |
| 312 // AcceleratedSurfaceContainerLinux* objects, however we should never have | |
| 313 // ids active from more than one type at the same time, so we have free | |
| 314 // reign of the id namespace. | |
| 315 *surface_id = next_id++; | |
| 316 | |
| 317 shared_mem_.reset( | |
| 318 TransportDIB::Create(size_.GetArea() * 4, // GL_RGBA=4 B/px | |
| 319 *surface_id)); | |
| 320 // Create texture. | |
| 321 glGenTextures(1, &texture_id_); | |
| 322 glBindTexture(GL_TEXTURE_2D, texture_id_); | |
| 323 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |
| 324 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |
| 325 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | |
| 326 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | |
| 327 | |
| 328 // we generate the ID to be used here. | |
| 329 return true; | |
| 330 } | |
| 331 | |
| 332 void AcceleratedSurfaceContainerLinuxOSMesa::Draw( | |
| 333 const ui::TextureDrawParams& params, | |
| 334 const gfx::Rect& clip_bounds_in_texture) { | |
| 335 ui::SharedResources* instance = ui::SharedResources::GetInstance(); | |
| 336 DCHECK(instance); | |
| 337 | |
| 338 if (shared_mem_.get()) { | |
| 339 glBindTexture(GL_TEXTURE_2D, texture_id_); | |
| 340 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, | |
| 341 size_.width(), size_.height(), 0, | |
| 342 GL_RGBA, GL_UNSIGNED_BYTE, shared_mem_->memory()); | |
| 343 | |
| 344 DrawInternal(*instance->program_no_swizzle(), | |
| 345 params, | |
| 346 clip_bounds_in_texture); | |
| 347 } | |
| 348 } | |
| 349 | |
| 350 TransportDIB::Handle AcceleratedSurfaceContainerLinuxOSMesa::Handle() const { | |
| 351 if (shared_mem_.get()) | |
| 352 return shared_mem_->handle(); | |
| 353 else | |
| 354 return TransportDIB::DefaultHandleValue(); | |
| 355 } | |
| 356 | |
| 357 AcceleratedSurfaceContainerLinuxOSMesa:: | |
| 358 ~AcceleratedSurfaceContainerLinuxOSMesa() { | |
| 359 } | |
| 360 | |
| 361 } // namespace | |
| 362 | |
| 363 AcceleratedSurfaceContainerLinux::AcceleratedSurfaceContainerLinux( | |
| 364 const gfx::Size& size) : TextureGL(size) { | |
| 365 } | |
| 366 | |
| 367 TransportDIB::Handle AcceleratedSurfaceContainerLinux::Handle() const { | |
| 368 return TransportDIB::DefaultHandleValue(); | |
| 369 } | |
| 370 | |
| 371 // static | |
| 372 AcceleratedSurfaceContainerLinux* | |
| 373 AcceleratedSurfaceContainerLinux::CreateAcceleratedSurfaceContainer( | |
| 374 const gfx::Size& size) { | |
| 375 switch (gfx::GetGLImplementation()) { | |
| 376 case gfx::kGLImplementationDesktopGL: | |
| 377 return new AcceleratedSurfaceContainerLinuxGLX(size); | |
| 378 case gfx::kGLImplementationEGLGLES2: | |
| 379 return new AcceleratedSurfaceContainerLinuxEGL(size); | |
| 380 case gfx::kGLImplementationOSMesaGL: | |
| 381 return new AcceleratedSurfaceContainerLinuxOSMesa(size); | |
| 382 default: | |
| 383 NOTREACHED(); | |
| 384 return NULL; | |
| 385 } | |
| 386 } | |
| 387 | |
| 388 void AcceleratedSurfaceContainerLinux::SetCanvas( | |
| 389 const SkCanvas& canvas, | |
| 390 const gfx::Point& origin, | |
| 391 const gfx::Size& overall_size) { | |
| 392 NOTREACHED(); | |
| 393 } | |
| 394 | |
| OLD | NEW |