// Copyright (c) 2012 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. extern "C" { #include } #include "ui/gl/gl_image_glx.h" #include "base/basictypes.h" #include "base/logging.h" #include "base/memory/scoped_ptr.h" #include "base/message_loop/message_loop.h" #include "ui/gl/gl_bindings.h" #include "ui/gl/gl_surface_glx.h" namespace gfx { namespace { // scoped_ptr functor for XFree(). Use as follows: // scoped_ptr_malloc foo(...); // where "XVisualInfo" is any X type that is freed with XFree. class ScopedPtrXFree { public: void operator()(void* x) const { ::XFree(x); } }; int BindToTextureFormat(int depth) { if (depth == 32) return GLX_BIND_TO_TEXTURE_RGBA_EXT; return GLX_BIND_TO_TEXTURE_RGB_EXT; } int TextureFormat(int depth) { if (depth == 32) return GLX_TEXTURE_FORMAT_RGBA_EXT; return GLX_TEXTURE_FORMAT_RGB_EXT; } } // namespace anonymous GLImageGLX::GLImageGLX(gfx::PluginWindowHandle window) : display_(base::MessagePumpForUI::GetDefaultXDisplay()), window_(window), pixmap_(0), glx_pixmap_(0) { } bool GLImageGLX::Initialize() { if (!GLSurfaceGLX::IsTextureFromPixmapSupported()) { LOG(ERROR) << "GLX_EXT_texture_from_pixmap not supported."; return false; } XWindowAttributes attributes; if (!XGetWindowAttributes(display_, window_, &attributes)) { LOG(ERROR) << "XGetWindowAttributes failed for window " << window_ << "."; return false; } XVisualInfo templ; templ.visualid = XVisualIDFromVisual(attributes.visual); int num_visinfo = 0; scoped_ptr_malloc visinfo( XGetVisualInfo(display_, VisualIDMask, &templ, &num_visinfo)); if (!visinfo.get()) { LOG(ERROR) << "XGetVisualInfo failed for visual id " << templ.visualid << "."; return false; } if (!num_visinfo) { LOG(ERROR) << "XGetVisualInfo returned 0 elements."; return false; } int config_attribs[] = { static_cast(GLX_VISUAL_ID), static_cast(visinfo->visualid), GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT, GLX_BIND_TO_TEXTURE_TARGETS_EXT, GLX_TEXTURE_2D_EXT, BindToTextureFormat(visinfo->depth), GL_TRUE, 0 }; int num_elements = 0; scoped_ptr_malloc config( glXChooseFBConfig(display_, DefaultScreen(display_), config_attribs, &num_elements)); if (!config.get()) { LOG(ERROR) << "glXChooseFBConfig failed."; return false; } if (!num_elements) { LOG(ERROR) << "glXChooseFBConfig returned 0 elements."; return false; } // Create backing pixmap reference. pixmap_ = XCompositeNameWindowPixmap(display_, window_); XID root = 0; int x = 0; int y = 0; unsigned int width = 0; unsigned int height = 0; unsigned int bw = 0; unsigned int depth = 0; if (!XGetGeometry( display_, pixmap_, &root, &x, &y, &width, &height, &bw, &depth)) { LOG(ERROR) << "XGetGeometry failed for pixmap " << pixmap_ << "."; return false; } int pixmap_attribs[] = { GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT, GLX_TEXTURE_FORMAT_EXT, TextureFormat(visinfo->depth), 0 }; glx_pixmap_ = glXCreatePixmap( display_, *config.get(), pixmap_, pixmap_attribs); if (!glx_pixmap_) { LOG(ERROR) << "glXCreatePixmap failed."; return false; } size_ = gfx::Size(width, height); return true; } void GLImageGLX::Destroy() { if (glx_pixmap_) { glXDestroyGLXPixmap(display_, glx_pixmap_); glx_pixmap_ = 0; } if (pixmap_) { XFreePixmap(display_, pixmap_); pixmap_ = 0; } } gfx::Size GLImageGLX::GetSize() { return size_; } bool GLImageGLX::BindTexImage() { if (!glx_pixmap_) return false; glXBindTexImageEXT(display_, glx_pixmap_, GLX_FRONT_LEFT_EXT, 0); return true; } void GLImageGLX::ReleaseTexImage() { if (!glx_pixmap_) return; glXReleaseTexImageEXT(display_, glx_pixmap_, GLX_FRONT_LEFT_EXT); } GLImageGLX::~GLImageGLX() { Destroy(); } } // namespace gfx