// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/renderer_host/accelerated_surface_container_touch.h" #include #include #include "base/memory/scoped_ptr.h" #include "third_party/angle/include/EGL/egl.h" #include "third_party/angle/include/EGL/eglext.h" #include "ui/gfx/gl/gl_bindings.h" #include "ui/gfx/gl/gl_implementation.h" #include "ui/gfx/gl/gl_surface_egl.h" #include "ui/gfx/rect.h" #include "ui/gfx/gl/gl_surface_glx.h" #include "ui/gfx/transform.h" namespace { class AcceleratedSurfaceContainerTouchEGL : public AcceleratedSurfaceContainerTouch { public: AcceleratedSurfaceContainerTouchEGL(ui::CompositorGL* compositor, const gfx::Size& size, uint64 surface_handle); // TextureGL implementation virtual void Draw(const ui::TextureDrawParams& params, const gfx::Rect& clip_bounds) OVERRIDE; private: ~AcceleratedSurfaceContainerTouchEGL(); void* image_; DISALLOW_COPY_AND_ASSIGN(AcceleratedSurfaceContainerTouchEGL); }; class AcceleratedSurfaceContainerTouchGLX : public AcceleratedSurfaceContainerTouch { public: AcceleratedSurfaceContainerTouchGLX(ui::CompositorGL* compositor, const gfx::Size& size, uint64 surface_handle); // TextureGL implementation virtual void Draw(const ui::TextureDrawParams& params, const gfx::Rect& clip_bounds) OVERRIDE; private: ~AcceleratedSurfaceContainerTouchGLX(); XID pixmap_; XID glx_pixmap_; DISALLOW_COPY_AND_ASSIGN(AcceleratedSurfaceContainerTouchGLX); }; class ScopedPtrXFree { public: void operator()(void* x) const { ::XFree(x); } }; AcceleratedSurfaceContainerTouchEGL::AcceleratedSurfaceContainerTouchEGL( ui::CompositorGL* compositor, const gfx::Size& size, uint64 surface_handle) : AcceleratedSurfaceContainerTouch(compositor, size), image_(NULL) { compositor_->MakeCurrent(); image_ = eglCreateImageKHR( gfx::GLSurfaceEGL::GetHardwareDisplay(), EGL_NO_CONTEXT, EGL_NATIVE_PIXMAP_KHR, reinterpret_cast(surface_handle), NULL); glGenTextures(1, &texture_id_); glBindTexture(GL_TEXTURE_2D, texture_id_); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image_); glFlush(); } AcceleratedSurfaceContainerTouchEGL::~AcceleratedSurfaceContainerTouchEGL() { eglDestroyImageKHR(gfx::GLSurfaceEGL::GetHardwareDisplay(), image_); glFlush(); } void AcceleratedSurfaceContainerTouchEGL::Draw( const ui::TextureDrawParams& params, const gfx::Rect& clip_bounds) { DCHECK(compositor_->program_no_swizzle()); ui::TextureDrawParams modified_params = params; // Texture from GPU is flipped vertically. ui::Transform flipped; flipped.SetScaleY(-1.0); flipped.SetTranslateY(size_.height()); flipped.ConcatTransform(params.transform); modified_params.transform = flipped; DrawInternal(*compositor_->program_no_swizzle(), modified_params, clip_bounds); } AcceleratedSurfaceContainerTouchGLX::AcceleratedSurfaceContainerTouchGLX( ui::CompositorGL* compositor, const gfx::Size& size, uint64 surface_handle) : AcceleratedSurfaceContainerTouch(compositor, size), pixmap_(0), glx_pixmap_(0) { // Create pixmap from window. Display* dpy = gfx::GLSurfaceGLX::GetDisplay(); int event_base, error_base; if (XCompositeQueryExtension(dpy, &event_base, &error_base)) { int major = 0, minor = 2; XCompositeQueryVersion(dpy, &major, &minor); if (major == 0 && minor < 2) { LOG(ERROR) << "Pixmap from window not supported."; return; } } pixmap_ = XCompositeNameWindowPixmap(dpy, surface_handle); // Wrap the pixmap in a GLXPixmap int screen = DefaultScreen(dpy); XWindowAttributes gwa; XGetWindowAttributes(dpy, RootWindow(dpy, screen), &gwa); unsigned int visualid = XVisualIDFromVisual(gwa.visual); int nfbconfigs, config; scoped_ptr_malloc fbconfigs( glXGetFBConfigs(dpy, screen, &nfbconfigs)); for (config = 0; config < nfbconfigs; config++) { XVisualInfo* visinfo = glXGetVisualFromFBConfig( dpy, fbconfigs.get()[config]); if (!visinfo || visinfo->visualid != visualid) continue; int value; glXGetFBConfigAttrib(dpy, fbconfigs.get()[config], GLX_DRAWABLE_TYPE, &value); if (!(value & GLX_PIXMAP_BIT)) continue; glXGetFBConfigAttrib(dpy, fbconfigs.get()[config], GLX_BIND_TO_TEXTURE_TARGETS_EXT, &value); if (!(value & GLX_TEXTURE_2D_BIT_EXT)) continue; glXGetFBConfigAttrib(dpy, fbconfigs.get()[config], GLX_BIND_TO_TEXTURE_RGB_EXT, &value); if (value == GL_FALSE) continue; break; } if (config == nfbconfigs) { LOG(ERROR) << "Could not find configuration suitable for binding a pixmap " << "as a texture."; return; } const int pixmapAttribs[] = { GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT, GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGB_EXT, 0 }; glx_pixmap_ = glXCreatePixmap( dpy, fbconfigs.get()[config], pixmap_, pixmapAttribs); // Create texture. compositor_->MakeCurrent(); glGenTextures(1, &texture_id_); glBindTexture(GL_TEXTURE_2D, texture_id_); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } AcceleratedSurfaceContainerTouchGLX::~AcceleratedSurfaceContainerTouchGLX() { Display* dpy = gfx::GLSurfaceGLX::GetDisplay(); if (glx_pixmap_) glXDestroyGLXPixmap(dpy, glx_pixmap_); if (pixmap_) XFreePixmap(dpy, pixmap_); } void AcceleratedSurfaceContainerTouchGLX::Draw( const ui::TextureDrawParams& params, const gfx::Rect& clip_bounds) { DCHECK(compositor_->program_no_swizzle()); Display* dpy = gfx::GLSurfaceGLX::GetDisplay(); glBindTexture(GL_TEXTURE_2D, texture_id_); glXBindTexImageEXT(dpy, glx_pixmap_, GLX_FRONT_LEFT_EXT, NULL); DrawInternal(*compositor_->program_no_swizzle(), params, clip_bounds); glXReleaseTexImageEXT(dpy, glx_pixmap_, GLX_FRONT_LEFT_EXT); } } // namespace AcceleratedSurfaceContainerTouch::AcceleratedSurfaceContainerTouch( ui::CompositorGL* compositor, const gfx::Size& size) : TextureGL(compositor, size) { } // static AcceleratedSurfaceContainerTouch* AcceleratedSurfaceContainerTouch::CreateAcceleratedSurfaceContainer( ui::CompositorGL* compositor, const gfx::Size& size, uint64 surface_handle) { switch (gfx::GetGLImplementation()) { case gfx::kGLImplementationDesktopGL: return new AcceleratedSurfaceContainerTouchGLX(compositor, size, surface_handle); case gfx::kGLImplementationEGLGLES2: return new AcceleratedSurfaceContainerTouchEGL(compositor, size, surface_handle); default: NOTREACHED(); return NULL; } } void AcceleratedSurfaceContainerTouch::SetCanvas( const SkCanvas& canvas, const gfx::Point& origin, const gfx::Size& overall_size) { NOTREACHED(); }