blob: 739b4d47d1d605d9a78946708318306bb0a964c0 [file] [log] [blame]
// 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() {
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);
}
void GLImageGLX::WillUseTexImage() {
}
void GLImageGLX::DidUseTexImage() {
}
} // namespace gfx