普通文本  |  188行  |  4.42 KB

// 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 <X11/extensions/Xcomposite.h>
}

#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<XVisualInfo, ScopedPtrXFree> 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) {
}

GLImageGLX::~GLImageGLX() {
  Destroy();
}

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<XVisualInfo, ScopedPtrXFree> 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<int>(GLX_VISUAL_ID),
    static_cast<int>(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<GLXFBConfig, ScopedPtrXFree> 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(unsigned target) {
  if (!glx_pixmap_)
    return false;

  // Requires TEXTURE_2D target.
  if (target != GL_TEXTURE_2D)
    return false;

  glXBindTexImageEXT(display_, glx_pixmap_, GLX_FRONT_LEFT_EXT, 0);
  return true;
}

void GLImageGLX::ReleaseTexImage(unsigned target) {
  DCHECK(glx_pixmap_);
  DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D), target);

  glXReleaseTexImageEXT(display_, glx_pixmap_, GLX_FRONT_LEFT_EXT);
}

void GLImageGLX::WillUseTexImage() {
}

void GLImageGLX::DidUseTexImage() {
}

}  // namespace gfx