summaryrefslogtreecommitdiffstats
path: root/gpu/command_buffer/service/gl_context_linux.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gpu/command_buffer/service/gl_context_linux.cc')
-rw-r--r--gpu/command_buffer/service/gl_context_linux.cc308
1 files changed, 308 insertions, 0 deletions
diff --git a/gpu/command_buffer/service/gl_context_linux.cc b/gpu/command_buffer/service/gl_context_linux.cc
new file mode 100644
index 0000000..0acbb02
--- /dev/null
+++ b/gpu/command_buffer/service/gl_context_linux.cc
@@ -0,0 +1,308 @@
+// Copyright (c) 2010 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.
+
+// This file implements the ViewGLContext and PbufferGLContext classes.
+
+#if !defined(UNIT_TEST)
+#include <dlfcn.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#endif
+
+#include "gpu/command_buffer/service/gl_context.h"
+#include "base/scoped_ptr.h"
+#include "gpu/command_buffer/service/gl_utils.h"
+#include "gpu/command_buffer/common/logging.h"
+
+namespace gpu {
+
+#if !defined(UNIT_TEST)
+
+// 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);
+ }
+};
+
+// Some versions of NVIDIA's GL libGL.so include a broken version of
+// dlopen/dlsym, and so linking it into chrome breaks it. So we dynamically
+// load it, and use glew to dynamically resolve symbols.
+// See http://code.google.com/p/chromium/issues/detail?id=16800
+
+static bool InitializeGLXEW(Display* display) {
+ static bool glxew_initialized = false;
+ if (!glxew_initialized) {
+ void* handle = dlopen("libGL.so.1", RTLD_LAZY | RTLD_GLOBAL);
+ if (!handle) {
+ LOG(ERROR) << "Could not find libGL.so.1";
+ return false;
+ }
+
+ // Initializes context-independent parts of GLEW
+ if (glxewInit() != GLEW_OK) {
+ LOG(ERROR) << "glxewInit failed";
+ return false;
+ }
+ // glxewContextInit really only needs a display connection to
+ // complete, and we don't want to have to create an OpenGL context
+ // just to get access to GLX 1.3 entry points to create pbuffers.
+ // We therefore added a glxewContextInitWithDisplay entry point.
+ if (glxewContextInitWithDisplay(display) != GLEW_OK) {
+ LOG(ERROR) << "glxewContextInit failed";
+ return false;
+ }
+ glxew_initialized = true;
+ }
+
+ return true;
+}
+
+#endif // UNIT_TEST
+
+bool ViewGLContext::Initialize(bool multisampled) {
+#if !defined(UNIT_TEST)
+ if (multisampled) {
+ DLOG(WARNING) << "Multisampling not implemented.";
+ }
+
+ if (!InitializeGLXEW(display_))
+ return false;
+
+ XWindowAttributes attributes;
+ XGetWindowAttributes(display_, window_, &attributes);
+ XVisualInfo visual_info_template;
+ visual_info_template.visualid = XVisualIDFromVisual(attributes.visual);
+ int visual_info_count = 0;
+ scoped_ptr_malloc<XVisualInfo, ScopedPtrXFree> visual_info_list(
+ XGetVisualInfo(display_, VisualIDMask,
+ &visual_info_template,
+ &visual_info_count));
+ DCHECK(visual_info_list.get());
+ DCHECK_GT(visual_info_count, 0);
+ context_ = NULL;
+ for (int i = 0; i < visual_info_count; ++i) {
+ context_ = glXCreateContext(display_, visual_info_list.get() + i, 0, True);
+ if (context_)
+ break;
+ }
+ if (!context_) {
+ DLOG(ERROR) << "Couldn't create GL context.";
+ return false;
+ }
+
+ if (!MakeCurrent()) {
+ Destroy();
+ DLOG(ERROR) << "Couldn't make context current for initialization.";
+ return false;
+ }
+
+ if (!InitializeGLEW()) {
+ Destroy();
+ return false;
+ }
+#endif // UNIT_TEST
+
+ return true;
+}
+
+void ViewGLContext::Destroy() {
+ #if !defined(UNIT_TEST)
+Bool result = glXMakeCurrent(display_, 0, 0);
+ // glXMakeCurrent isn't supposed to fail when unsetting the context, unless
+ // we have pending draws on an invalid window - which shouldn't be the case
+ // here.
+ DCHECK(result);
+ if (context_) {
+ glXDestroyContext(display_, context_);
+ context_ = NULL;
+ }
+#endif // UNIT_TEST
+}
+
+bool ViewGLContext::MakeCurrent() {
+#if !defined(UNIT_TEST)
+ if (glXGetCurrentDrawable() == window_ &&
+ glXGetCurrentContext() == context_) {
+ return true;
+ }
+ if (glXMakeCurrent(display_, window_, context_) != True) {
+ glXDestroyContext(display_, context_);
+ context_ = 0;
+ DLOG(ERROR) << "Couldn't make context current.";
+ return false;
+ }
+#endif // UNIT_TEST
+
+ return true;
+}
+
+bool ViewGLContext::IsOffscreen() {
+ return false;
+}
+
+void ViewGLContext::SwapBuffers() {
+#if !defined(UNIT_TEST)
+ glXSwapBuffers(display_, window_);
+#endif // UNIT_TEST
+}
+
+gfx::Size ViewGLContext::GetSize() {
+#if !defined(UNIT_TEST)
+ XWindowAttributes attributes;
+ XGetWindowAttributes(display_, window_, &attributes);
+ return gfx::Size(attributes.width, attributes.height);
+#else
+ return gfx::Size();
+#endif // UNIT_TEST
+}
+
+GLContextHandle ViewGLContext::GetHandle() {
+#if !defined(UNIT_TEST)
+ return context_;
+#else
+ return NULL;
+#endif // UNIT_TEST
+}
+
+bool PbufferGLContext::Initialize(GLContext* shared_context) {
+#if !defined(UNIT_TEST)
+ if (!InitializeGLXEW(display_))
+ return false;
+
+ if (!glXChooseFBConfig ||
+ !glXCreateNewContext ||
+ !glXCreatePbuffer ||
+ !glXDestroyPbuffer) {
+ DLOG(ERROR) << "Pbuffer support not available.";
+ return false;
+ }
+
+ // Get the shared context handle.
+ GLContextHandle shared_handle = NULL;
+ if (shared_context)
+ shared_handle = shared_context->GetHandle();
+
+ static const int config_attributes[] = {
+ GLX_DRAWABLE_TYPE,
+ GLX_PBUFFER_BIT,
+ GLX_RENDER_TYPE,
+ GLX_RGBA_BIT,
+ GLX_DOUBLEBUFFER,
+ 0,
+ 0
+ };
+
+ int nelements = 0;
+ // TODO(kbr): figure out whether hardcoding screen to 0 is sufficient.
+ scoped_ptr_malloc<GLXFBConfig, ScopedPtrXFree> config(
+ glXChooseFBConfig(display_, 0, config_attributes, &nelements));
+ if (!config.get()) {
+ DLOG(ERROR) << "glXChooseFBConfig failed.";
+ return false;
+ }
+ if (!nelements) {
+ DLOG(ERROR) << "glXChooseFBConfig returned 0 elements.";
+ return false;
+ }
+ context_ = glXCreateNewContext(display_,
+ config.get()[0],
+ GLX_RGBA_TYPE,
+ shared_handle,
+ True);
+ if (!context_) {
+ DLOG(ERROR) << "glXCreateNewContext failed.";
+ return false;
+ }
+ static const int pbuffer_attributes[] = {
+ GLX_PBUFFER_WIDTH,
+ 1,
+ GLX_PBUFFER_HEIGHT,
+ 1,
+ 0
+ };
+ pbuffer_ = glXCreatePbuffer(display_,
+ config.get()[0], pbuffer_attributes);
+ if (!pbuffer_) {
+ Destroy();
+ DLOG(ERROR) << "glXCreatePbuffer failed.";
+ return false;
+ }
+
+ if (!MakeCurrent()) {
+ Destroy();
+ DLOG(ERROR) << "Couldn't make context current for initialization.";
+ return false;
+ }
+
+ if (!InitializeGLEW()) {
+ Destroy();
+ return false;
+ }
+#endif // UNIT_TEST
+
+ return true;
+}
+
+void PbufferGLContext::Destroy() {
+#if !defined(UNIT_TEST)
+ Bool result = glXMakeCurrent(display_, 0, 0);
+ // glXMakeCurrent isn't supposed to fail when unsetting the context, unless
+ // we have pending draws on an invalid window - which shouldn't be the case
+ // here.
+ DCHECK(result);
+ if (context_) {
+ glXDestroyContext(display_, context_);
+ context_ = NULL;
+ }
+
+ if (pbuffer_) {
+ glXDestroyPbuffer(display_, pbuffer_);
+ pbuffer_ = NULL;
+ }
+#endif // UNIT_TEST
+}
+
+bool PbufferGLContext::MakeCurrent() {
+#if !defined(UNIT_TEST)
+ if (glXGetCurrentDrawable() == pbuffer_ &&
+ glXGetCurrentContext() == context_) {
+ return true;
+ }
+ if (glXMakeCurrent(display_, pbuffer_, context_) != True) {
+ glXDestroyContext(display_, context_);
+ context_ = NULL;
+ DLOG(ERROR) << "Couldn't make context current.";
+ return false;
+ }
+#endif // UNIT_TEST
+
+ return true;
+}
+
+bool PbufferGLContext::IsOffscreen() {
+ return true;
+}
+
+void PbufferGLContext::SwapBuffers() {
+ NOTREACHED() << "Attempted to call SwapBuffers on a pbuffer.";
+}
+
+gfx::Size PbufferGLContext::GetSize() {
+ NOTREACHED() << "Should not be requesting size of this pbuffer.";
+ return gfx::Size(1, 1);
+}
+
+GLContextHandle PbufferGLContext::GetHandle() {
+#if !defined(UNIT_TEST)
+ return context_;
+#else
+ return NULL;
+#endif // UNIT_TEST
+}
+
+} // namespace gpu