// 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 } #include "base/logging.h" #include "base/memory/scoped_ptr.h" #include "ui/gl/gl_bindings.h" #include "ui/gl/gl_image_glx.h" #include "ui/gl/gl_surface_glx.h" namespace gl { namespace { bool ValidFormat(unsigned internalformat) { switch (internalformat) { case GL_RGB: case GL_RGBA: return true; default: return false; } } int TextureFormat(unsigned internalformat) { switch (internalformat) { case GL_RGB: return GLX_TEXTURE_FORMAT_RGB_EXT; case GL_RGBA: return GLX_TEXTURE_FORMAT_RGBA_EXT; default: NOTREACHED(); return 0; } } int BindToTextureFormat(unsigned internalformat) { switch (internalformat) { case GL_RGB: return GLX_BIND_TO_TEXTURE_RGB_EXT; 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; case GL_RGB: return 24u; 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 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 (!gfx::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; gfx::XScopedPtr 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_; } unsigned GLImageGLX::GetInternalFormat() { return internalformat_; } 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(GL_TEXTURE_2D), target); glXReleaseTexImageEXT(gfx::GetXDisplay(), glx_pixmap_, GLX_FRONT_LEFT_EXT); } bool GLImageGLX::CopyTexImage(unsigned target) { return false; } bool GLImageGLX::CopyTexSubImage(unsigned target, const gfx::Point& offset, const gfx::Rect& rect) { return false; } bool GLImageGLX::ScheduleOverlayPlane(gfx::AcceleratedWidget widget, int z_order, gfx::OverlayTransform transform, const gfx::Rect& bounds_rect, const gfx::RectF& crop_rect) { return false; } void GLImageGLX::OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd, uint64_t process_tracing_id, const std::string& dump_name) { // TODO(ericrk): Implement GLImage OnMemoryDump. crbug.com/514914 } } // namespace gl