OLD | NEW |
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // This class implements the XWindowWrapper class. | 5 // This class implements the XWindowWrapper class. |
6 | 6 |
7 #include <dlfcn.h> | 7 #include <dlfcn.h> |
8 | 8 |
| 9 #include "base/scoped_ptr.h" |
9 #include "gpu/command_buffer/service/precompile.h" | 10 #include "gpu/command_buffer/service/precompile.h" |
10 #include "gpu/command_buffer/common/logging.h" | 11 #include "gpu/command_buffer/common/logging.h" |
11 #include "gpu/command_buffer/service/x_utils.h" | 12 #include "gpu/command_buffer/service/x_utils.h" |
12 | 13 |
13 namespace gpu { | 14 namespace gpu { |
14 | 15 |
| 16 // scoped_ptr functor for XFree(). Use as follows: |
| 17 // scoped_ptr_malloc<XVisualInfo, ScopedPtrXFree> foo(...); |
| 18 // where "XVisualInfo" is any X type that is freed with XFree. |
| 19 class ScopedPtrXFree { |
| 20 public: |
| 21 void operator()(void* x) const { |
| 22 ::XFree(x); |
| 23 } |
| 24 }; |
| 25 |
15 // Some versions of NVIDIA's GL libGL.so include a broken version of | 26 // Some versions of NVIDIA's GL libGL.so include a broken version of |
16 // dlopen/dlsym, and so linking it into chrome breaks it. So we dynamically | 27 // dlopen/dlsym, and so linking it into chrome breaks it. So we dynamically |
17 // load it, and use glew to dynamically resolve symbols. | 28 // load it, and use glew to dynamically resolve symbols. |
18 // See http://code.google.com/p/chromium/issues/detail?id=16800 | 29 // See http://code.google.com/p/chromium/issues/detail?id=16800 |
19 | 30 |
| 31 static bool g_glxew_initialized = false; |
20 static bool g_glew_initialized = false; | 32 static bool g_glew_initialized = false; |
21 | 33 |
22 bool XWindowWrapper::Initialize() { | 34 static bool InitializeGLXEW() { |
23 if (!g_glew_initialized) { | 35 if (!g_glxew_initialized) { |
24 void* handle = dlopen("libGL.so.1", RTLD_LAZY | RTLD_GLOBAL); | 36 void* handle = dlopen("libGL.so.1", RTLD_LAZY | RTLD_GLOBAL); |
25 if (!handle) { | 37 if (!handle) { |
26 LOG(ERROR) << "Could not find libGL.so.1"; | 38 LOG(ERROR) << "Could not find libGL.so.1"; |
27 return false; | 39 return false; |
28 } | 40 } |
29 | 41 |
30 // Initializes context-independent parts of GLEW | 42 // Initializes context-independent parts of GLEW |
31 if (glxewInit() != GLEW_OK) { | 43 if (glxewInit() != GLEW_OK) { |
32 LOG(ERROR) << "GLXEW failed initialization"; | 44 LOG(ERROR) << "glxewInit failed"; |
| 45 return false; |
| 46 } |
| 47 // Hack to work around apparently incorrect assumption in |
| 48 // glxewContextInit. Documentation indicates that all of the work |
| 49 // it does is actually context-independent. We require GLX 1.3 |
| 50 // entry points to be present for successful initialization of the |
| 51 // off-screen code path in the GLES2Decoder. TODO(kbr): clean this |
| 52 // up. |
| 53 if (glxewContextInit() != GLEW_OK) { |
| 54 LOG(ERROR) << "glxewContextInit failed"; |
| 55 return false; |
| 56 } |
| 57 g_glxew_initialized = true; |
| 58 } |
| 59 return true; |
| 60 } |
| 61 |
| 62 // GLEW initialization is extremely expensive because it looks up |
| 63 // hundreds of function pointers. Realistically we are not going to |
| 64 // switch between GL implementations on the fly, so for the time being |
| 65 // we only do the context-dependent GLEW initialization once. |
| 66 static bool InitializeGLEW() { |
| 67 if (!g_glew_initialized) { |
| 68 // Initializes context-dependent parts of GLEW |
| 69 if (glewInit() != GLEW_OK) { |
| 70 LOG(ERROR) << "GLEW failed initialization"; |
| 71 return false; |
| 72 } |
| 73 |
| 74 if (!glewIsSupported("GL_VERSION_2_0")) { |
| 75 LOG(ERROR) << "GL implementation doesn't support GL version 2.0"; |
33 return false; | 76 return false; |
34 } | 77 } |
35 g_glew_initialized = true; | 78 g_glew_initialized = true; |
36 } | 79 } |
37 XWindowAttributes attributes; | 80 return true; |
38 XGetWindowAttributes(display_, window_, &attributes); | 81 } |
39 XVisualInfo visual_info_template; | 82 |
40 visual_info_template.visualid = XVisualIDFromVisual(attributes.visual); | 83 GLXContextWrapper::~GLXContextWrapper() { |
41 int visual_info_count = 0; | 84 } |
42 XVisualInfo *visual_info_list = XGetVisualInfo(display_, VisualIDMask, | 85 |
43 &visual_info_template, | 86 bool GLXContextWrapper::Initialize() { |
44 &visual_info_count); | |
45 DCHECK(visual_info_list); | |
46 DCHECK_GT(visual_info_count, 0); | |
47 context_ = 0; | |
48 for (int i = 0; i < visual_info_count; ++i) { | |
49 context_ = glXCreateContext(display_, visual_info_list + i, 0, | |
50 True); | |
51 if (context_) break; | |
52 } | |
53 XFree(visual_info_list); | |
54 if (!context_) { | |
55 DLOG(ERROR) << "Couldn't create GL context."; | |
56 return false; | |
57 } | |
58 if (!MakeCurrent()) { | 87 if (!MakeCurrent()) { |
59 return false; | 88 Destroy(); |
60 } | 89 DLOG(ERROR) << "Couldn't make context current for initialization."; |
61 | 90 return false; |
62 // Initializes context-dependent parts of GLEW | 91 } |
63 if (glewInit() != GLEW_OK) { | 92 |
64 LOG(ERROR) << "GLEW failed initialization"; | 93 if (!InitializeGLEW()) { |
65 return false; | 94 Destroy(); |
66 } | 95 return false; |
67 | 96 } |
68 if (!glewIsSupported("GL_VERSION_2_0")) { | 97 |
69 LOG(ERROR) << "GL implementation doesn't support GL version 2.0"; | 98 return true; |
70 return false; | 99 } |
71 } | 100 |
72 | 101 void GLXContextWrapper::Destroy() { |
73 return true; | 102 Bool result = glXMakeCurrent(GetDisplay(), 0, 0); |
74 } | |
75 | |
76 bool XWindowWrapper::MakeCurrent() { | |
77 if (glXGetCurrentDrawable() == window_ && | |
78 glXGetCurrentContext() == context_) { | |
79 return true; | |
80 } | |
81 if (glXMakeCurrent(display_, window_, context_) != True) { | |
82 glXDestroyContext(display_, context_); | |
83 context_ = 0; | |
84 DLOG(ERROR) << "Couldn't make context current."; | |
85 return false; | |
86 } | |
87 return true; | |
88 } | |
89 | |
90 void XWindowWrapper::Destroy() { | |
91 Bool result = glXMakeCurrent(display_, 0, 0); | |
92 // glXMakeCurrent isn't supposed to fail when unsetting the context, unless | 103 // glXMakeCurrent isn't supposed to fail when unsetting the context, unless |
93 // we have pending draws on an invalid window - which shouldn't be the case | 104 // we have pending draws on an invalid window - which shouldn't be the case |
94 // here. | 105 // here. |
95 DCHECK(result); | 106 DCHECK(result); |
96 if (context_) { | 107 if (GetContext()) { |
97 glXDestroyContext(display_, context_); | 108 glXDestroyContext(GetDisplay(), GetContext()); |
98 context_ = 0; | 109 SetContext(NULL); |
99 } | 110 } |
| 111 } |
| 112 |
| 113 bool XWindowWrapper::Initialize() { |
| 114 if (!InitializeGLXEW()) |
| 115 return false; |
| 116 |
| 117 XWindowAttributes attributes; |
| 118 XGetWindowAttributes(GetDisplay(), window_, &attributes); |
| 119 XVisualInfo visual_info_template; |
| 120 visual_info_template.visualid = XVisualIDFromVisual(attributes.visual); |
| 121 int visual_info_count = 0; |
| 122 scoped_ptr_malloc<XVisualInfo, ScopedPtrXFree> visual_info_list( |
| 123 XGetVisualInfo(GetDisplay(), VisualIDMask, |
| 124 &visual_info_template, |
| 125 &visual_info_count)); |
| 126 DCHECK(visual_info_list.get()); |
| 127 DCHECK_GT(visual_info_count, 0); |
| 128 SetContext(NULL); |
| 129 for (int i = 0; i < visual_info_count; ++i) { |
| 130 SetContext(glXCreateContext(GetDisplay(), visual_info_list.get() + i, 0, |
| 131 True)); |
| 132 if (GetContext()) |
| 133 break; |
| 134 } |
| 135 if (!GetContext()) { |
| 136 DLOG(ERROR) << "Couldn't create GL context."; |
| 137 return false; |
| 138 } |
| 139 return GLXContextWrapper::Initialize(); |
| 140 } |
| 141 |
| 142 bool XWindowWrapper::MakeCurrent() { |
| 143 if (glXGetCurrentDrawable() == window_ && |
| 144 glXGetCurrentContext() == GetContext()) { |
| 145 return true; |
| 146 } |
| 147 if (glXMakeCurrent(GetDisplay(), window_, GetContext()) != True) { |
| 148 glXDestroyContext(GetDisplay(), GetContext()); |
| 149 SetContext(0); |
| 150 DLOG(ERROR) << "Couldn't make context current."; |
| 151 return false; |
| 152 } |
| 153 return true; |
| 154 } |
| 155 |
| 156 bool XWindowWrapper::IsOffscreen() { |
| 157 return false; |
100 } | 158 } |
101 | 159 |
102 void XWindowWrapper::SwapBuffers() { | 160 void XWindowWrapper::SwapBuffers() { |
103 glXSwapBuffers(display_, window_); | 161 glXSwapBuffers(GetDisplay(), window_); |
| 162 } |
| 163 |
| 164 bool GLXPbufferWrapper::Initialize() { |
| 165 if (!InitializeGLXEW()) |
| 166 return false; |
| 167 |
| 168 if (!glXChooseFBConfig || |
| 169 !glXCreateNewContext || |
| 170 !glXCreatePbuffer || |
| 171 !glXDestroyPbuffer) { |
| 172 DLOG(ERROR) << "Pbuffer support not available."; |
| 173 return false; |
| 174 } |
| 175 |
| 176 static const int config_attributes[] = { |
| 177 GLX_DRAWABLE_TYPE, |
| 178 GLX_PBUFFER_BIT, |
| 179 GLX_RENDER_TYPE, |
| 180 GLX_RGBA_BIT, |
| 181 GLX_DOUBLEBUFFER, |
| 182 0, |
| 183 0 |
| 184 }; |
| 185 |
| 186 int nelements = 0; |
| 187 // TODO(kbr): figure out whether hardcoding screen to 0 is sufficient. |
| 188 scoped_ptr_malloc<GLXFBConfig, ScopedPtrXFree> config( |
| 189 glXChooseFBConfig(GetDisplay(), 0, config_attributes, &nelements)); |
| 190 if (!config.get()) { |
| 191 DLOG(ERROR) << "glXChooseFBConfig failed."; |
| 192 return false; |
| 193 } |
| 194 if (!nelements) { |
| 195 DLOG(ERROR) << "glXChooseFBConfig returned 0 elements."; |
| 196 return false; |
| 197 } |
| 198 SetContext(glXCreateNewContext(GetDisplay(), |
| 199 config.get()[0], GLX_RGBA_TYPE, 0, True)); |
| 200 if (!GetContext()) { |
| 201 DLOG(ERROR) << "glXCreateNewContext failed."; |
| 202 return false; |
| 203 } |
| 204 static const int pbuffer_attributes[] = { |
| 205 GLX_PBUFFER_WIDTH, |
| 206 1, |
| 207 GLX_PBUFFER_HEIGHT, |
| 208 1, |
| 209 0 |
| 210 }; |
| 211 pbuffer_ = glXCreatePbuffer(GetDisplay(), |
| 212 config.get()[0], pbuffer_attributes); |
| 213 if (!pbuffer_) { |
| 214 Destroy(); |
| 215 DLOG(ERROR) << "glXCreatePbuffer failed."; |
| 216 return false; |
| 217 } |
| 218 return GLXContextWrapper::Initialize(); |
| 219 } |
| 220 |
| 221 void GLXPbufferWrapper::Destroy() { |
| 222 GLXContextWrapper::Destroy(); |
| 223 if (pbuffer_) { |
| 224 glXDestroyPbuffer(GetDisplay(), pbuffer_); |
| 225 pbuffer_ = NULL; |
| 226 } |
| 227 } |
| 228 |
| 229 bool GLXPbufferWrapper::MakeCurrent() { |
| 230 if (glXGetCurrentDrawable() == pbuffer_ && |
| 231 glXGetCurrentContext() == GetContext()) { |
| 232 return true; |
| 233 } |
| 234 if (glXMakeCurrent(GetDisplay(), pbuffer_, GetContext()) != True) { |
| 235 glXDestroyContext(GetDisplay(), GetContext()); |
| 236 SetContext(0); |
| 237 DLOG(ERROR) << "Couldn't make context current."; |
| 238 return false; |
| 239 } |
| 240 return true; |
| 241 } |
| 242 |
| 243 bool GLXPbufferWrapper::IsOffscreen() { |
| 244 return true; |
| 245 } |
| 246 |
| 247 void GLXPbufferWrapper::SwapBuffers() { |
104 } | 248 } |
105 | 249 |
106 } // namespace gpu | 250 } // namespace gpu |
OLD | NEW |