1// Copyright (c) 2012 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
5extern "C" {
6#include <X11/extensions/Xcomposite.h>
7}
8
9#include "ui/gl/gl_image_glx.h"
10
11#include "base/basictypes.h"
12#include "base/logging.h"
13#include "base/memory/scoped_ptr.h"
14#include "base/message_loop/message_loop.h"
15#include "ui/gl/gl_bindings.h"
16#include "ui/gl/gl_surface_glx.h"
17
18namespace gfx {
19
20namespace {
21
22// scoped_ptr functor for XFree(). Use as follows:
23//   scoped_ptr_malloc<XVisualInfo, ScopedPtrXFree> foo(...);
24// where "XVisualInfo" is any X type that is freed with XFree.
25class ScopedPtrXFree {
26 public:
27  void operator()(void* x) const {
28    ::XFree(x);
29  }
30};
31
32int BindToTextureFormat(int depth) {
33  if (depth == 32)
34    return GLX_BIND_TO_TEXTURE_RGBA_EXT;
35
36  return GLX_BIND_TO_TEXTURE_RGB_EXT;
37}
38
39int TextureFormat(int depth) {
40  if (depth == 32)
41    return GLX_TEXTURE_FORMAT_RGBA_EXT;
42
43  return GLX_TEXTURE_FORMAT_RGB_EXT;
44}
45
46}  // namespace anonymous
47
48GLImageGLX::GLImageGLX(gfx::PluginWindowHandle window)
49  : display_(base::MessagePumpForUI::GetDefaultXDisplay()),
50    window_(window),
51    pixmap_(0),
52    glx_pixmap_(0) {
53}
54
55GLImageGLX::~GLImageGLX() {
56  Destroy();
57}
58
59bool GLImageGLX::Initialize() {
60  if (!GLSurfaceGLX::IsTextureFromPixmapSupported()) {
61    LOG(ERROR) << "GLX_EXT_texture_from_pixmap not supported.";
62    return false;
63  }
64
65  XWindowAttributes attributes;
66  if (!XGetWindowAttributes(display_, window_, &attributes)) {
67    LOG(ERROR) << "XGetWindowAttributes failed for window " << window_ << ".";
68    return false;
69  }
70
71  XVisualInfo templ;
72  templ.visualid = XVisualIDFromVisual(attributes.visual);
73  int num_visinfo = 0;
74  scoped_ptr_malloc<XVisualInfo, ScopedPtrXFree> visinfo(
75      XGetVisualInfo(display_,
76                     VisualIDMask,
77                     &templ,
78                     &num_visinfo));
79  if (!visinfo.get()) {
80    LOG(ERROR) << "XGetVisualInfo failed for visual id " <<
81        templ.visualid << ".";
82    return false;
83  }
84  if (!num_visinfo) {
85    LOG(ERROR) << "XGetVisualInfo returned 0 elements.";
86    return false;
87  }
88
89  int config_attribs[] = {
90    static_cast<int>(GLX_VISUAL_ID),
91    static_cast<int>(visinfo->visualid),
92    GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT,
93    GLX_BIND_TO_TEXTURE_TARGETS_EXT, GLX_TEXTURE_2D_EXT,
94    BindToTextureFormat(visinfo->depth), GL_TRUE,
95    0
96  };
97  int num_elements = 0;
98  scoped_ptr_malloc<GLXFBConfig, ScopedPtrXFree> config(
99      glXChooseFBConfig(display_,
100                        DefaultScreen(display_),
101                        config_attribs,
102                        &num_elements));
103  if (!config.get()) {
104    LOG(ERROR) << "glXChooseFBConfig failed.";
105    return false;
106  }
107  if (!num_elements) {
108    LOG(ERROR) << "glXChooseFBConfig returned 0 elements.";
109    return false;
110  }
111
112  // Create backing pixmap reference.
113  pixmap_ = XCompositeNameWindowPixmap(display_, window_);
114
115  XID root = 0;
116  int x = 0;
117  int y = 0;
118  unsigned int width = 0;
119  unsigned int height = 0;
120  unsigned int bw = 0;
121  unsigned int depth = 0;
122  if (!XGetGeometry(
123          display_, pixmap_, &root, &x, &y, &width, &height, &bw, &depth)) {
124    LOG(ERROR) << "XGetGeometry failed for pixmap " << pixmap_ << ".";
125    return false;
126  }
127
128  int pixmap_attribs[] = {
129    GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT,
130    GLX_TEXTURE_FORMAT_EXT, TextureFormat(visinfo->depth),
131    0
132  };
133  glx_pixmap_ = glXCreatePixmap(
134      display_,
135      *config.get(),
136      pixmap_,
137      pixmap_attribs);
138  if (!glx_pixmap_) {
139    LOG(ERROR) << "glXCreatePixmap failed.";
140    return false;
141  }
142
143  size_ = gfx::Size(width, height);
144  return true;
145}
146
147void GLImageGLX::Destroy() {
148  if (glx_pixmap_) {
149    glXDestroyGLXPixmap(display_, glx_pixmap_);
150    glx_pixmap_ = 0;
151  }
152  if (pixmap_) {
153    XFreePixmap(display_, pixmap_);
154    pixmap_ = 0;
155  }
156}
157
158gfx::Size GLImageGLX::GetSize() {
159  return size_;
160}
161
162bool GLImageGLX::BindTexImage() {
163  if (!glx_pixmap_)
164    return false;
165
166  glXBindTexImageEXT(display_, glx_pixmap_, GLX_FRONT_LEFT_EXT, 0);
167  return true;
168}
169
170void GLImageGLX::ReleaseTexImage() {
171  if (!glx_pixmap_)
172    return;
173
174  glXReleaseTexImageEXT(display_, glx_pixmap_, GLX_FRONT_LEFT_EXT);
175}
176
177void GLImageGLX::WillUseTexImage() {
178}
179
180void GLImageGLX::DidUseTexImage() {
181}
182
183}  // namespace gfx
184