| // 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/Xlib.h> |
| } |
| |
| #include "ui/gl/gl_image_glx.h" |
| |
| #include "base/logging.h" |
| #include "base/memory/scoped_ptr.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<XVisualInfo, ScopedPtrXFree> foo(...); |
| // where "XVisualInfo" is any X type that is freed with XFree. |
| struct ScopedPtrXFree { |
| void operator()(void* x) const { ::XFree(x); } |
| }; |
| |
| bool ValidFormat(unsigned internalformat) { |
| switch (internalformat) { |
| case GL_RGBA: |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| int TextureFormat(unsigned internalformat) { |
| switch (internalformat) { |
| case GL_RGBA: |
| return GLX_TEXTURE_FORMAT_RGBA_EXT; |
| default: |
| NOTREACHED(); |
| return 0; |
| } |
| } |
| |
| int BindToTextureFormat(unsigned internalformat) { |
| switch (internalformat) { |
| case GL_RGBA: |
| return GLX_BIND_TO_TEXTURE_RGBA_EXT; |
| default: |
| NOTREACHED(); |
| return 0; |
| } |
| } |
| |
| unsigned PixmapDepth(unsigned internalformat) { |
| switch (internalformat) { |
| case GL_RGBA: |
| return 32u; |
| default: |
| NOTREACHED(); |
| return 0u; |
| } |
| } |
| |
| bool ActualPixmapGeometry(XID pixmap, gfx::Size* size, unsigned* depth) { |
| XID root_return; |
| int x_return; |
| int y_return; |
| unsigned width_return; |
| unsigned height_return; |
| unsigned border_width_return; |
| unsigned depth_return; |
| if (!XGetGeometry(gfx::GetXDisplay(), |
| pixmap, |
| &root_return, |
| &x_return, |
| &y_return, |
| &width_return, |
| &height_return, |
| &border_width_return, |
| &depth_return)) |
| return false; |
| |
| if (size) |
| *size = gfx::Size(width_return, height_return); |
| if (depth) |
| *depth = depth_return; |
| return true; |
| } |
| |
| unsigned ActualPixmapDepth(XID pixmap) { |
| unsigned depth; |
| if (!ActualPixmapGeometry(pixmap, NULL, &depth)) |
| return -1; |
| |
| return depth; |
| } |
| |
| gfx::Size ActualPixmapSize(XID pixmap) { |
| gfx::Size size; |
| if (!ActualPixmapGeometry(pixmap, &size, NULL)) |
| return gfx::Size(); |
| |
| return size; |
| } |
| |
| } // namespace anonymous |
| |
| GLImageGLX::GLImageGLX(const gfx::Size& size, unsigned internalformat) |
| : glx_pixmap_(0), size_(size), internalformat_(internalformat) { |
| } |
| |
| GLImageGLX::~GLImageGLX() { |
| DCHECK_EQ(0u, glx_pixmap_); |
| } |
| |
| bool GLImageGLX::Initialize(XID pixmap) { |
| if (!GLSurfaceGLX::IsTextureFromPixmapSupported()) { |
| DVLOG(0) << "GLX_EXT_texture_from_pixmap not supported."; |
| return false; |
| } |
| |
| if (!ValidFormat(internalformat_)) { |
| DVLOG(0) << "Invalid format: " << internalformat_; |
| return false; |
| } |
| |
| DCHECK_EQ(PixmapDepth(internalformat_), ActualPixmapDepth(pixmap)); |
| DCHECK_EQ(size_.ToString(), ActualPixmapSize(pixmap).ToString()); |
| |
| int config_attribs[] = { |
| GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT, |
| GLX_BIND_TO_TEXTURE_TARGETS_EXT, GLX_TEXTURE_2D_EXT, |
| BindToTextureFormat(internalformat_), GL_TRUE, |
| 0}; |
| int num_elements = 0; |
| scoped_ptr<GLXFBConfig, ScopedPtrXFree> config( |
| glXChooseFBConfig(gfx::GetXDisplay(), |
| DefaultScreen(gfx::GetXDisplay()), |
| config_attribs, |
| &num_elements)); |
| if (!config.get()) { |
| DVLOG(0) << "glXChooseFBConfig failed."; |
| return false; |
| } |
| if (!num_elements) { |
| DVLOG(0) << "glXChooseFBConfig returned 0 elements."; |
| return false; |
| } |
| |
| int pixmap_attribs[] = {GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT, |
| GLX_TEXTURE_FORMAT_EXT, |
| TextureFormat(internalformat_), 0}; |
| glx_pixmap_ = glXCreatePixmap( |
| gfx::GetXDisplay(), *config.get(), pixmap, pixmap_attribs); |
| if (!glx_pixmap_) { |
| DVLOG(0) << "glXCreatePixmap failed."; |
| return false; |
| } |
| |
| return true; |
| } |
| |
| void GLImageGLX::Destroy(bool have_context) { |
| if (glx_pixmap_) { |
| glXDestroyGLXPixmap(gfx::GetXDisplay(), glx_pixmap_); |
| glx_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(gfx::GetXDisplay(), glx_pixmap_, GLX_FRONT_LEFT_EXT, 0); |
| return true; |
| } |
| |
| void GLImageGLX::ReleaseTexImage(unsigned target) { |
| DCHECK_NE(0u, glx_pixmap_); |
| DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D), target); |
| |
| glXReleaseTexImageEXT(gfx::GetXDisplay(), glx_pixmap_, GLX_FRONT_LEFT_EXT); |
| } |
| |
| bool GLImageGLX::CopyTexImage(unsigned target) { |
| return false; |
| } |
| |
| bool GLImageGLX::ScheduleOverlayPlane(gfx::AcceleratedWidget widget, |
| int z_order, |
| OverlayTransform transform, |
| const Rect& bounds_rect, |
| const RectF& crop_rect) { |
| return false; |
| } |
| |
| } // namespace gfx |