summaryrefslogtreecommitdiffstats
path: root/ui/gl/gl_surface_glx.cc
diff options
context:
space:
mode:
Diffstat (limited to 'ui/gl/gl_surface_glx.cc')
-rw-r--r--ui/gl/gl_surface_glx.cc326
1 files changed, 326 insertions, 0 deletions
diff --git a/ui/gl/gl_surface_glx.cc b/ui/gl/gl_surface_glx.cc
new file mode 100644
index 0000000..ba8ce92
--- /dev/null
+++ b/ui/gl/gl_surface_glx.cc
@@ -0,0 +1,326 @@
+// 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_surface_glx.h"
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop.h"
+#include "base/process_util.h"
+#include "third_party/mesa/MesaLib/include/GL/osmesa.h"
+#include "ui/base/x/x11_util.h"
+#include "ui/gl/gl_bindings.h"
+#include "ui/gl/gl_implementation.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);
+ }
+};
+
+Display* g_display;
+const char* g_glx_extensions = NULL;
+bool g_glx_create_context_robustness_supported = false;
+
+} // namespace anonymous
+
+GLSurfaceGLX::GLSurfaceGLX() {
+}
+
+GLSurfaceGLX::~GLSurfaceGLX() {
+}
+
+bool GLSurfaceGLX::InitializeOneOff() {
+ static bool initialized = false;
+ if (initialized)
+ return true;
+
+ g_display = base::MessagePumpForUI::GetDefaultXDisplay();
+ if (!g_display) {
+ LOG(ERROR) << "XOpenDisplay failed.";
+ return false;
+ }
+
+ int major, minor;
+ if (!glXQueryVersion(g_display, &major, &minor)) {
+ LOG(ERROR) << "glxQueryVersion failed";
+ return false;
+ }
+
+ if (major == 1 && minor < 3) {
+ LOG(ERROR) << "GLX 1.3 or later is required.";
+ return false;
+ }
+
+ g_glx_extensions = glXQueryExtensionsString(g_display, 0);
+ g_glx_create_context_robustness_supported =
+ HasGLXExtension("GLX_ARB_create_context_robustness");
+
+ initialized = true;
+ return true;
+}
+
+// static
+const char* GLSurfaceGLX::GetGLXExtensions() {
+ return g_glx_extensions;
+}
+
+// static
+bool GLSurfaceGLX::HasGLXExtension(const char* name) {
+ DCHECK(name);
+ const char* c_extensions = GetGLXExtensions();
+ if (!c_extensions)
+ return false;
+ std::string extensions(c_extensions);
+ extensions += " ";
+
+ std::string delimited_name(name);
+ delimited_name += " ";
+
+ return extensions.find(delimited_name) != std::string::npos;
+}
+
+// static
+bool GLSurfaceGLX::IsCreateContextRobustnessSupported() {
+ return g_glx_create_context_robustness_supported;
+}
+
+void* GLSurfaceGLX::GetDisplay() {
+ return g_display;
+}
+
+NativeViewGLSurfaceGLX::NativeViewGLSurfaceGLX(gfx::AcceleratedWidget window)
+ : window_(window),
+ config_(NULL) {
+}
+
+NativeViewGLSurfaceGLX::NativeViewGLSurfaceGLX()
+ : window_(0),
+ config_(NULL) {
+}
+
+NativeViewGLSurfaceGLX::~NativeViewGLSurfaceGLX() {
+ Destroy();
+}
+
+bool NativeViewGLSurfaceGLX::Initialize() {
+ XWindowAttributes attributes;
+ if (!XGetWindowAttributes(g_display, window_, &attributes)) {
+ LOG(ERROR) << "XGetWindowAttributes failed for window " << window_ << ".";
+ return false;
+ }
+ size_ = gfx::Size(attributes.width, attributes.height);
+ return true;
+}
+
+void NativeViewGLSurfaceGLX::Destroy() {
+}
+
+bool NativeViewGLSurfaceGLX::Resize(const gfx::Size& size) {
+ // On Intel drivers, the frame buffer won't be resize until the next swap. If
+ // we only do PostSubBuffer, then we're stuck in the old size. Force a swap
+ // now.
+ if (gfx::g_GLX_MESA_copy_sub_buffer && size_ != size)
+ SwapBuffers();
+ size_ = size;
+ return true;
+}
+
+bool NativeViewGLSurfaceGLX::IsOffscreen() {
+ return false;
+}
+
+bool NativeViewGLSurfaceGLX::SwapBuffers() {
+ glXSwapBuffers(g_display, window_);
+ return true;
+}
+
+gfx::Size NativeViewGLSurfaceGLX::GetSize() {
+ return size_;
+}
+
+void* NativeViewGLSurfaceGLX::GetHandle() {
+ return reinterpret_cast<void*>(window_);
+}
+
+std::string NativeViewGLSurfaceGLX::GetExtensions() {
+ std::string extensions = GLSurface::GetExtensions();
+ if (g_GLX_MESA_copy_sub_buffer) {
+ extensions += extensions.empty() ? "" : " ";
+ extensions += "GL_CHROMIUM_post_sub_buffer";
+ }
+ return extensions;
+}
+
+void* NativeViewGLSurfaceGLX::GetConfig() {
+ if (!config_) {
+ // This code path is expensive, but we only take it when
+ // attempting to use GLX_ARB_create_context_robustness, in which
+ // case we need a GLXFBConfig for the window in order to create a
+ // context for it.
+ //
+ // TODO(kbr): this is not a reliable code path. On platforms which
+ // support it, we should use glXChooseFBConfig in the browser
+ // process to choose the FBConfig and from there the X Visual to
+ // use when creating the window in the first place. Then we can
+ // pass that FBConfig down rather than attempting to reconstitute
+ // it.
+
+ XWindowAttributes attributes;
+ if (!XGetWindowAttributes(
+ g_display,
+ reinterpret_cast<GLXDrawable>(GetHandle()),
+ &attributes)) {
+ LOG(ERROR) << "XGetWindowAttributes failed for window " <<
+ reinterpret_cast<GLXDrawable>(GetHandle()) << ".";
+ return NULL;
+ }
+
+ int visual_id = XVisualIDFromVisual(attributes.visual);
+
+ int num_elements = 0;
+ scoped_ptr_malloc<GLXFBConfig, ScopedPtrXFree> configs(
+ glXGetFBConfigs(g_display,
+ DefaultScreen(g_display),
+ &num_elements));
+ if (!configs.get()) {
+ LOG(ERROR) << "glXGetFBConfigs failed.";
+ return NULL;
+ }
+ if (!num_elements) {
+ LOG(ERROR) << "glXGetFBConfigs returned 0 elements.";
+ return NULL;
+ }
+ bool found = false;
+ int i;
+ for (i = 0; i < num_elements; ++i) {
+ int value;
+ if (glXGetFBConfigAttrib(
+ g_display, configs.get()[i], GLX_VISUAL_ID, &value)) {
+ LOG(ERROR) << "glXGetFBConfigAttrib failed.";
+ return NULL;
+ }
+ if (value == visual_id) {
+ found = true;
+ break;
+ }
+ }
+ if (found) {
+ config_ = configs.get()[i];
+ }
+ }
+
+ return config_;
+}
+
+bool NativeViewGLSurfaceGLX::PostSubBuffer(
+ int x, int y, int width, int height) {
+ DCHECK(g_GLX_MESA_copy_sub_buffer);
+ glXCopySubBufferMESA(g_display, window_, x, y, width, height);
+ return true;
+}
+
+PbufferGLSurfaceGLX::PbufferGLSurfaceGLX(const gfx::Size& size)
+ : size_(size),
+ config_(NULL),
+ pbuffer_(0) {
+}
+
+PbufferGLSurfaceGLX::~PbufferGLSurfaceGLX() {
+ Destroy();
+}
+
+bool PbufferGLSurfaceGLX::Initialize() {
+ DCHECK(!pbuffer_);
+
+ static const int config_attributes[] = {
+ GLX_BUFFER_SIZE, 32,
+ GLX_ALPHA_SIZE, 8,
+ GLX_BLUE_SIZE, 8,
+ GLX_GREEN_SIZE, 8,
+ GLX_RED_SIZE, 8,
+ GLX_RENDER_TYPE, GLX_RGBA_BIT,
+ GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT,
+ GLX_DOUBLEBUFFER, False,
+ 0
+ };
+
+ int num_elements = 0;
+ scoped_ptr_malloc<GLXFBConfig, ScopedPtrXFree> configs(
+ glXChooseFBConfig(g_display,
+ DefaultScreen(g_display),
+ config_attributes,
+ &num_elements));
+ if (!configs.get()) {
+ LOG(ERROR) << "glXChooseFBConfig failed.";
+ return false;
+ }
+ if (!num_elements) {
+ LOG(ERROR) << "glXChooseFBConfig returned 0 elements.";
+ return false;
+ }
+
+ config_ = configs.get()[0];
+
+ const int pbuffer_attributes[] = {
+ GLX_PBUFFER_WIDTH, size_.width(),
+ GLX_PBUFFER_HEIGHT, size_.height(),
+ 0
+ };
+ pbuffer_ = glXCreatePbuffer(g_display,
+ static_cast<GLXFBConfig>(config_),
+ pbuffer_attributes);
+ if (!pbuffer_) {
+ Destroy();
+ LOG(ERROR) << "glXCreatePbuffer failed.";
+ return false;
+ }
+
+ return true;
+}
+
+void PbufferGLSurfaceGLX::Destroy() {
+ if (pbuffer_) {
+ glXDestroyPbuffer(g_display, pbuffer_);
+ pbuffer_ = 0;
+ }
+
+ config_ = NULL;
+}
+
+bool PbufferGLSurfaceGLX::IsOffscreen() {
+ return true;
+}
+
+bool PbufferGLSurfaceGLX::SwapBuffers() {
+ NOTREACHED() << "Attempted to call SwapBuffers on a pbuffer.";
+ return false;
+}
+
+gfx::Size PbufferGLSurfaceGLX::GetSize() {
+ return size_;
+}
+
+void* PbufferGLSurfaceGLX::GetHandle() {
+ return reinterpret_cast<void*>(pbuffer_);
+}
+
+void* PbufferGLSurfaceGLX::GetConfig() {
+ return config_;
+}
+
+} // namespace gfx