Index: gpu/command_buffer/service/x_utils.cc |
=================================================================== |
--- gpu/command_buffer/service/x_utils.cc (revision 43138) |
+++ gpu/command_buffer/service/x_utils.cc (working copy) |
@@ -6,21 +6,33 @@ |
#include <dlfcn.h> |
+#include "base/scoped_ptr.h" |
#include "gpu/command_buffer/service/precompile.h" |
#include "gpu/command_buffer/common/logging.h" |
#include "gpu/command_buffer/service/x_utils.h" |
namespace gpu { |
+// 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 g_glxew_initialized = false; |
static bool g_glew_initialized = false; |
-bool XWindowWrapper::Initialize() { |
- if (!g_glew_initialized) { |
+static bool InitializeGLXEW() { |
+ if (!g_glxew_initialized) { |
void* handle = dlopen("libGL.so.1", RTLD_LAZY | RTLD_GLOBAL); |
if (!handle) { |
LOG(ERROR) << "Could not find libGL.so.1"; |
@@ -29,78 +41,210 @@ |
// Initializes context-independent parts of GLEW |
if (glxewInit() != GLEW_OK) { |
- LOG(ERROR) << "GLXEW failed initialization"; |
+ LOG(ERROR) << "glxewInit failed"; |
return false; |
} |
+ // Hack to work around apparently incorrect assumption in |
+ // glxewContextInit. Documentation indicates that all of the work |
+ // it does is actually context-independent. We require GLX 1.3 |
+ // entry points to be present for successful initialization of the |
+ // off-screen code path in the GLES2Decoder. TODO(kbr): clean this |
+ // up. |
+ if (glxewContextInit() != GLEW_OK) { |
+ LOG(ERROR) << "glxewContextInit failed"; |
+ return false; |
+ } |
+ g_glxew_initialized = true; |
+ } |
+ return true; |
+} |
+ |
+// GLEW initialization is extremely expensive because it looks up |
+// hundreds of function pointers. Realistically we are not going to |
+// switch between GL implementations on the fly, so for the time being |
+// we only do the context-dependent GLEW initialization once. |
+static bool InitializeGLEW() { |
+ if (!g_glew_initialized) { |
+ // Initializes context-dependent parts of GLEW |
+ if (glewInit() != GLEW_OK) { |
+ LOG(ERROR) << "GLEW failed initialization"; |
+ return false; |
+ } |
+ |
+ if (!glewIsSupported("GL_VERSION_2_0")) { |
+ LOG(ERROR) << "GL implementation doesn't support GL version 2.0"; |
+ return false; |
+ } |
g_glew_initialized = true; |
} |
+ return true; |
+} |
+ |
+GLXContextWrapper::~GLXContextWrapper() { |
+} |
+ |
+bool GLXContextWrapper::Initialize() { |
+ if (!MakeCurrent()) { |
+ Destroy(); |
+ DLOG(ERROR) << "Couldn't make context current for initialization."; |
+ return false; |
+ } |
+ |
+ if (!InitializeGLEW()) { |
+ Destroy(); |
+ return false; |
+ } |
+ |
+ return true; |
+} |
+ |
+void GLXContextWrapper::Destroy() { |
+ Bool result = glXMakeCurrent(GetDisplay(), 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 (GetContext()) { |
+ glXDestroyContext(GetDisplay(), GetContext()); |
+ SetContext(NULL); |
+ } |
+} |
+ |
+bool XWindowWrapper::Initialize() { |
+ if (!InitializeGLXEW()) |
+ return false; |
+ |
XWindowAttributes attributes; |
- XGetWindowAttributes(display_, window_, &attributes); |
+ XGetWindowAttributes(GetDisplay(), window_, &attributes); |
XVisualInfo visual_info_template; |
visual_info_template.visualid = XVisualIDFromVisual(attributes.visual); |
int visual_info_count = 0; |
- XVisualInfo *visual_info_list = XGetVisualInfo(display_, VisualIDMask, |
- &visual_info_template, |
- &visual_info_count); |
- DCHECK(visual_info_list); |
+ scoped_ptr_malloc<XVisualInfo, ScopedPtrXFree> visual_info_list( |
+ XGetVisualInfo(GetDisplay(), VisualIDMask, |
+ &visual_info_template, |
+ &visual_info_count)); |
+ DCHECK(visual_info_list.get()); |
DCHECK_GT(visual_info_count, 0); |
- context_ = 0; |
+ SetContext(NULL); |
for (int i = 0; i < visual_info_count; ++i) { |
- context_ = glXCreateContext(display_, visual_info_list + i, 0, |
- True); |
- if (context_) break; |
+ SetContext(glXCreateContext(GetDisplay(), visual_info_list.get() + i, 0, |
+ True)); |
+ if (GetContext()) |
+ break; |
} |
- XFree(visual_info_list); |
- if (!context_) { |
+ if (!GetContext()) { |
DLOG(ERROR) << "Couldn't create GL context."; |
return false; |
} |
- if (!MakeCurrent()) { |
+ return GLXContextWrapper::Initialize(); |
+} |
+ |
+bool XWindowWrapper::MakeCurrent() { |
+ if (glXGetCurrentDrawable() == window_ && |
+ glXGetCurrentContext() == GetContext()) { |
+ return true; |
+ } |
+ if (glXMakeCurrent(GetDisplay(), window_, GetContext()) != True) { |
+ glXDestroyContext(GetDisplay(), GetContext()); |
+ SetContext(0); |
+ DLOG(ERROR) << "Couldn't make context current."; |
return false; |
} |
+ return true; |
+} |
- // Initializes context-dependent parts of GLEW |
- if (glewInit() != GLEW_OK) { |
- LOG(ERROR) << "GLEW failed initialization"; |
+bool XWindowWrapper::IsOffscreen() { |
+ return false; |
+} |
+ |
+void XWindowWrapper::SwapBuffers() { |
+ glXSwapBuffers(GetDisplay(), window_); |
+} |
+ |
+bool GLXPbufferWrapper::Initialize() { |
+ if (!InitializeGLXEW()) |
return false; |
+ |
+ if (!glXChooseFBConfig || |
+ !glXCreateNewContext || |
+ !glXCreatePbuffer || |
+ !glXDestroyPbuffer) { |
+ DLOG(ERROR) << "Pbuffer support not available."; |
+ return false; |
} |
- if (!glewIsSupported("GL_VERSION_2_0")) { |
- LOG(ERROR) << "GL implementation doesn't support GL version 2.0"; |
+ 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(GetDisplay(), 0, config_attributes, &nelements)); |
+ if (!config.get()) { |
+ DLOG(ERROR) << "glXChooseFBConfig failed."; |
return false; |
} |
+ if (!nelements) { |
+ DLOG(ERROR) << "glXChooseFBConfig returned 0 elements."; |
+ return false; |
+ } |
+ SetContext(glXCreateNewContext(GetDisplay(), |
+ config.get()[0], GLX_RGBA_TYPE, 0, True)); |
+ if (!GetContext()) { |
+ DLOG(ERROR) << "glXCreateNewContext failed."; |
+ return false; |
+ } |
+ static const int pbuffer_attributes[] = { |
+ GLX_PBUFFER_WIDTH, |
+ 1, |
+ GLX_PBUFFER_HEIGHT, |
+ 1, |
+ 0 |
+ }; |
+ pbuffer_ = glXCreatePbuffer(GetDisplay(), |
+ config.get()[0], pbuffer_attributes); |
+ if (!pbuffer_) { |
+ Destroy(); |
+ DLOG(ERROR) << "glXCreatePbuffer failed."; |
+ return false; |
+ } |
+ return GLXContextWrapper::Initialize(); |
+} |
- return true; |
+void GLXPbufferWrapper::Destroy() { |
+ GLXContextWrapper::Destroy(); |
+ if (pbuffer_) { |
+ glXDestroyPbuffer(GetDisplay(), pbuffer_); |
+ pbuffer_ = NULL; |
+ } |
} |
-bool XWindowWrapper::MakeCurrent() { |
- if (glXGetCurrentDrawable() == window_ && |
- glXGetCurrentContext() == context_) { |
+bool GLXPbufferWrapper::MakeCurrent() { |
+ if (glXGetCurrentDrawable() == pbuffer_ && |
+ glXGetCurrentContext() == GetContext()) { |
return true; |
} |
- if (glXMakeCurrent(display_, window_, context_) != True) { |
- glXDestroyContext(display_, context_); |
- context_ = 0; |
+ if (glXMakeCurrent(GetDisplay(), pbuffer_, GetContext()) != True) { |
+ glXDestroyContext(GetDisplay(), GetContext()); |
+ SetContext(0); |
DLOG(ERROR) << "Couldn't make context current."; |
return false; |
} |
return true; |
} |
-void XWindowWrapper::Destroy() { |
- 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_ = 0; |
- } |
+bool GLXPbufferWrapper::IsOffscreen() { |
+ return true; |
} |
-void XWindowWrapper::SwapBuffers() { |
- glXSwapBuffers(display_, window_); |
+void GLXPbufferWrapper::SwapBuffers() { |
} |
} // namespace gpu |