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 5 extern "C" { 6 #include <X11/Xlib.h> 7 } 8 9 #include "ui/gl/gl_image_glx.h" 10 11 #include "base/logging.h" 12 #include "base/memory/scoped_ptr.h" 13 #include "ui/gl/gl_bindings.h" 14 #include "ui/gl/gl_surface_glx.h" 15 16 namespace gfx { 17 18 namespace { 19 20 // scoped_ptr functor for XFree(). Use as follows: 21 // scoped_ptr<XVisualInfo, ScopedPtrXFree> foo(...); 22 // where "XVisualInfo" is any X type that is freed with XFree. 23 struct ScopedPtrXFree { 24 void operator()(void* x) const { ::XFree(x); } 25 }; 26 27 bool ValidFormat(unsigned internalformat) { 28 switch (internalformat) { 29 case GL_BGRA8_EXT: 30 return true; 31 default: 32 return false; 33 } 34 } 35 36 int TextureFormat(unsigned internalformat) { 37 switch (internalformat) { 38 case GL_BGRA8_EXT: 39 return GLX_TEXTURE_FORMAT_RGBA_EXT; 40 default: 41 NOTREACHED(); 42 return 0; 43 } 44 } 45 46 int BindToTextureFormat(unsigned internalformat) { 47 switch (internalformat) { 48 case GL_BGRA8_EXT: 49 return GLX_BIND_TO_TEXTURE_RGBA_EXT; 50 default: 51 NOTREACHED(); 52 return 0; 53 } 54 } 55 56 unsigned PixmapDepth(unsigned internalformat) { 57 switch (internalformat) { 58 case GL_BGRA8_EXT: 59 return 32u; 60 default: 61 NOTREACHED(); 62 return 0u; 63 } 64 } 65 66 bool ActualPixmapGeometry(XID pixmap, gfx::Size* size, unsigned* depth) { 67 XID root_return; 68 int x_return; 69 int y_return; 70 unsigned width_return; 71 unsigned height_return; 72 unsigned border_width_return; 73 unsigned depth_return; 74 if (!XGetGeometry(gfx::GetXDisplay(), 75 pixmap, 76 &root_return, 77 &x_return, 78 &y_return, 79 &width_return, 80 &height_return, 81 &border_width_return, 82 &depth_return)) 83 return false; 84 85 if (size) 86 *size = gfx::Size(width_return, height_return); 87 if (depth) 88 *depth = depth_return; 89 return true; 90 } 91 92 unsigned ActualPixmapDepth(XID pixmap) { 93 unsigned depth; 94 if (!ActualPixmapGeometry(pixmap, NULL, &depth)) 95 return -1; 96 97 return depth; 98 } 99 100 gfx::Size ActualPixmapSize(XID pixmap) { 101 gfx::Size size; 102 if (!ActualPixmapGeometry(pixmap, &size, NULL)) 103 return gfx::Size(); 104 105 return size; 106 } 107 108 } // namespace anonymous 109 110 GLImageGLX::GLImageGLX(const gfx::Size& size, unsigned internalformat) 111 : glx_pixmap_(0), size_(size), internalformat_(internalformat) { 112 } 113 114 GLImageGLX::~GLImageGLX() { 115 DCHECK_EQ(0u, glx_pixmap_); 116 } 117 118 bool GLImageGLX::Initialize(XID pixmap) { 119 if (!GLSurfaceGLX::IsTextureFromPixmapSupported()) { 120 DVLOG(0) << "GLX_EXT_texture_from_pixmap not supported."; 121 return false; 122 } 123 124 if (!ValidFormat(internalformat_)) { 125 DVLOG(0) << "Invalid format: " << internalformat_; 126 return false; 127 } 128 129 DCHECK_EQ(PixmapDepth(internalformat_), ActualPixmapDepth(pixmap)); 130 DCHECK_EQ(size_.ToString(), ActualPixmapSize(pixmap).ToString()); 131 132 int config_attribs[] = { 133 GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT, 134 GLX_BIND_TO_TEXTURE_TARGETS_EXT, GLX_TEXTURE_2D_EXT, 135 BindToTextureFormat(internalformat_), GL_TRUE, 136 0}; 137 int num_elements = 0; 138 scoped_ptr<GLXFBConfig, ScopedPtrXFree> config( 139 glXChooseFBConfig(gfx::GetXDisplay(), 140 DefaultScreen(gfx::GetXDisplay()), 141 config_attribs, 142 &num_elements)); 143 if (!config.get()) { 144 DVLOG(0) << "glXChooseFBConfig failed."; 145 return false; 146 } 147 if (!num_elements) { 148 DVLOG(0) << "glXChooseFBConfig returned 0 elements."; 149 return false; 150 } 151 152 int pixmap_attribs[] = {GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT, 153 GLX_TEXTURE_FORMAT_EXT, 154 TextureFormat(internalformat_), 0}; 155 glx_pixmap_ = glXCreatePixmap( 156 gfx::GetXDisplay(), *config.get(), pixmap, pixmap_attribs); 157 if (!glx_pixmap_) { 158 DVLOG(0) << "glXCreatePixmap failed."; 159 return false; 160 } 161 162 return true; 163 } 164 165 void GLImageGLX::Destroy(bool have_context) { 166 if (glx_pixmap_) { 167 glXDestroyGLXPixmap(gfx::GetXDisplay(), glx_pixmap_); 168 glx_pixmap_ = 0; 169 } 170 } 171 172 gfx::Size GLImageGLX::GetSize() { return size_; } 173 174 bool GLImageGLX::BindTexImage(unsigned target) { 175 if (!glx_pixmap_) 176 return false; 177 178 // Requires TEXTURE_2D target. 179 if (target != GL_TEXTURE_2D) 180 return false; 181 182 glXBindTexImageEXT(gfx::GetXDisplay(), glx_pixmap_, GLX_FRONT_LEFT_EXT, 0); 183 return true; 184 } 185 186 void GLImageGLX::ReleaseTexImage(unsigned target) { 187 DCHECK_NE(0u, glx_pixmap_); 188 DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D), target); 189 190 glXReleaseTexImageEXT(gfx::GetXDisplay(), glx_pixmap_, GLX_FRONT_LEFT_EXT); 191 } 192 193 bool GLImageGLX::CopyTexImage(unsigned target) { 194 return false; 195 } 196 197 bool GLImageGLX::ScheduleOverlayPlane(gfx::AcceleratedWidget widget, 198 int z_order, 199 OverlayTransform transform, 200 const Rect& bounds_rect, 201 const RectF& crop_rect) { 202 return false; 203 } 204 205 } // namespace gfx 206