OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 extern "C" { | |
6 #include <X11/Xlib.h> | |
7 } | |
8 | |
9 #include "ui/gfx/gl/gl_surface_glx.h" | |
10 | |
11 #include "base/basictypes.h" | |
12 #include "base/logging.h" | |
13 #include "base/memory/scoped_ptr.h" | |
14 #include "base/message_loop.h" | |
15 #include "base/process_util.h" | |
16 #include "third_party/mesa/MesaLib/include/GL/osmesa.h" | |
17 #include "ui/base/x/x11_util.h" | |
18 #include "ui/gfx/gl/gl_bindings.h" | |
19 #include "ui/gfx/gl/gl_implementation.h" | |
20 | |
21 namespace gfx { | |
22 | |
23 namespace { | |
24 | |
25 // scoped_ptr functor for XFree(). Use as follows: | |
26 // scoped_ptr_malloc<XVisualInfo, ScopedPtrXFree> foo(...); | |
27 // where "XVisualInfo" is any X type that is freed with XFree. | |
28 class ScopedPtrXFree { | |
29 public: | |
30 void operator()(void* x) const { | |
31 ::XFree(x); | |
32 } | |
33 }; | |
34 | |
35 Display* g_display; | |
36 const char* g_glx_extensions = NULL; | |
37 bool g_glx_create_context_robustness_supported = false; | |
38 | |
39 } // namespace anonymous | |
40 | |
41 GLSurfaceGLX::GLSurfaceGLX() { | |
42 } | |
43 | |
44 GLSurfaceGLX::~GLSurfaceGLX() { | |
45 } | |
46 | |
47 bool GLSurfaceGLX::InitializeOneOff() { | |
48 static bool initialized = false; | |
49 if (initialized) | |
50 return true; | |
51 | |
52 g_display = base::MessagePumpForUI::GetDefaultXDisplay(); | |
53 if (!g_display) { | |
54 LOG(ERROR) << "XOpenDisplay failed."; | |
55 return false; | |
56 } | |
57 | |
58 int major, minor; | |
59 if (!glXQueryVersion(g_display, &major, &minor)) { | |
60 LOG(ERROR) << "glxQueryVersion failed"; | |
61 return false; | |
62 } | |
63 | |
64 if (major == 1 && minor < 3) { | |
65 LOG(ERROR) << "GLX 1.3 or later is required."; | |
66 return false; | |
67 } | |
68 | |
69 g_glx_extensions = glXQueryExtensionsString(g_display, 0); | |
70 g_glx_create_context_robustness_supported = | |
71 HasGLXExtension("GLX_ARB_create_context_robustness"); | |
72 | |
73 initialized = true; | |
74 return true; | |
75 } | |
76 | |
77 // static | |
78 const char* GLSurfaceGLX::GetGLXExtensions() { | |
79 return g_glx_extensions; | |
80 } | |
81 | |
82 // static | |
83 bool GLSurfaceGLX::HasGLXExtension(const char* name) { | |
84 DCHECK(name); | |
85 const char* c_extensions = GetGLXExtensions(); | |
86 if (!c_extensions) | |
87 return false; | |
88 std::string extensions(c_extensions); | |
89 extensions += " "; | |
90 | |
91 std::string delimited_name(name); | |
92 delimited_name += " "; | |
93 | |
94 return extensions.find(delimited_name) != std::string::npos; | |
95 } | |
96 | |
97 // static | |
98 bool GLSurfaceGLX::IsCreateContextRobustnessSupported() { | |
99 return g_glx_create_context_robustness_supported; | |
100 } | |
101 | |
102 void* GLSurfaceGLX::GetDisplay() { | |
103 return g_display; | |
104 } | |
105 | |
106 NativeViewGLSurfaceGLX::NativeViewGLSurfaceGLX(gfx::AcceleratedWidget window) | |
107 : window_(window), | |
108 config_(NULL) { | |
109 } | |
110 | |
111 NativeViewGLSurfaceGLX::NativeViewGLSurfaceGLX() | |
112 : window_(0), | |
113 config_(NULL) { | |
114 } | |
115 | |
116 NativeViewGLSurfaceGLX::~NativeViewGLSurfaceGLX() { | |
117 Destroy(); | |
118 } | |
119 | |
120 bool NativeViewGLSurfaceGLX::Initialize() { | |
121 XWindowAttributes attributes; | |
122 if (!XGetWindowAttributes(g_display, window_, &attributes)) { | |
123 LOG(ERROR) << "XGetWindowAttributes failed for window " << window_ << "."; | |
124 return false; | |
125 } | |
126 size_ = gfx::Size(attributes.width, attributes.height); | |
127 return true; | |
128 } | |
129 | |
130 void NativeViewGLSurfaceGLX::Destroy() { | |
131 } | |
132 | |
133 bool NativeViewGLSurfaceGLX::Resize(const gfx::Size& size) { | |
134 // On Intel drivers, the frame buffer won't be resize until the next swap. If | |
135 // we only do PostSubBuffer, then we're stuck in the old size. Force a swap | |
136 // now. | |
137 if (gfx::g_GLX_MESA_copy_sub_buffer && size_ != size) | |
138 SwapBuffers(); | |
139 size_ = size; | |
140 return true; | |
141 } | |
142 | |
143 bool NativeViewGLSurfaceGLX::IsOffscreen() { | |
144 return false; | |
145 } | |
146 | |
147 bool NativeViewGLSurfaceGLX::SwapBuffers() { | |
148 glXSwapBuffers(g_display, window_); | |
149 return true; | |
150 } | |
151 | |
152 gfx::Size NativeViewGLSurfaceGLX::GetSize() { | |
153 return size_; | |
154 } | |
155 | |
156 void* NativeViewGLSurfaceGLX::GetHandle() { | |
157 return reinterpret_cast<void*>(window_); | |
158 } | |
159 | |
160 std::string NativeViewGLSurfaceGLX::GetExtensions() { | |
161 std::string extensions = GLSurface::GetExtensions(); | |
162 if (g_GLX_MESA_copy_sub_buffer) { | |
163 extensions += extensions.empty() ? "" : " "; | |
164 extensions += "GL_CHROMIUM_post_sub_buffer"; | |
165 } | |
166 return extensions; | |
167 } | |
168 | |
169 void* NativeViewGLSurfaceGLX::GetConfig() { | |
170 if (!config_) { | |
171 // This code path is expensive, but we only take it when | |
172 // attempting to use GLX_ARB_create_context_robustness, in which | |
173 // case we need a GLXFBConfig for the window in order to create a | |
174 // context for it. | |
175 // | |
176 // TODO(kbr): this is not a reliable code path. On platforms which | |
177 // support it, we should use glXChooseFBConfig in the browser | |
178 // process to choose the FBConfig and from there the X Visual to | |
179 // use when creating the window in the first place. Then we can | |
180 // pass that FBConfig down rather than attempting to reconstitute | |
181 // it. | |
182 | |
183 XWindowAttributes attributes; | |
184 if (!XGetWindowAttributes( | |
185 g_display, | |
186 reinterpret_cast<GLXDrawable>(GetHandle()), | |
187 &attributes)) { | |
188 LOG(ERROR) << "XGetWindowAttributes failed for window " << | |
189 reinterpret_cast<GLXDrawable>(GetHandle()) << "."; | |
190 return NULL; | |
191 } | |
192 | |
193 int visual_id = XVisualIDFromVisual(attributes.visual); | |
194 | |
195 int num_elements = 0; | |
196 scoped_ptr_malloc<GLXFBConfig, ScopedPtrXFree> configs( | |
197 glXGetFBConfigs(g_display, | |
198 DefaultScreen(g_display), | |
199 &num_elements)); | |
200 if (!configs.get()) { | |
201 LOG(ERROR) << "glXGetFBConfigs failed."; | |
202 return NULL; | |
203 } | |
204 if (!num_elements) { | |
205 LOG(ERROR) << "glXGetFBConfigs returned 0 elements."; | |
206 return NULL; | |
207 } | |
208 bool found = false; | |
209 int i; | |
210 for (i = 0; i < num_elements; ++i) { | |
211 int value; | |
212 if (glXGetFBConfigAttrib( | |
213 g_display, configs.get()[i], GLX_VISUAL_ID, &value)) { | |
214 LOG(ERROR) << "glXGetFBConfigAttrib failed."; | |
215 return NULL; | |
216 } | |
217 if (value == visual_id) { | |
218 found = true; | |
219 break; | |
220 } | |
221 } | |
222 if (found) { | |
223 config_ = configs.get()[i]; | |
224 } | |
225 } | |
226 | |
227 return config_; | |
228 } | |
229 | |
230 bool NativeViewGLSurfaceGLX::PostSubBuffer( | |
231 int x, int y, int width, int height) { | |
232 DCHECK(g_GLX_MESA_copy_sub_buffer); | |
233 glXCopySubBufferMESA(g_display, window_, x, y, width, height); | |
234 return true; | |
235 } | |
236 | |
237 PbufferGLSurfaceGLX::PbufferGLSurfaceGLX(const gfx::Size& size) | |
238 : size_(size), | |
239 config_(NULL), | |
240 pbuffer_(0) { | |
241 } | |
242 | |
243 PbufferGLSurfaceGLX::~PbufferGLSurfaceGLX() { | |
244 Destroy(); | |
245 } | |
246 | |
247 bool PbufferGLSurfaceGLX::Initialize() { | |
248 DCHECK(!pbuffer_); | |
249 | |
250 static const int config_attributes[] = { | |
251 GLX_BUFFER_SIZE, 32, | |
252 GLX_ALPHA_SIZE, 8, | |
253 GLX_BLUE_SIZE, 8, | |
254 GLX_GREEN_SIZE, 8, | |
255 GLX_RED_SIZE, 8, | |
256 GLX_RENDER_TYPE, GLX_RGBA_BIT, | |
257 GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT, | |
258 GLX_DOUBLEBUFFER, False, | |
259 0 | |
260 }; | |
261 | |
262 int num_elements = 0; | |
263 scoped_ptr_malloc<GLXFBConfig, ScopedPtrXFree> configs( | |
264 glXChooseFBConfig(g_display, | |
265 DefaultScreen(g_display), | |
266 config_attributes, | |
267 &num_elements)); | |
268 if (!configs.get()) { | |
269 LOG(ERROR) << "glXChooseFBConfig failed."; | |
270 return false; | |
271 } | |
272 if (!num_elements) { | |
273 LOG(ERROR) << "glXChooseFBConfig returned 0 elements."; | |
274 return false; | |
275 } | |
276 | |
277 config_ = configs.get()[0]; | |
278 | |
279 const int pbuffer_attributes[] = { | |
280 GLX_PBUFFER_WIDTH, size_.width(), | |
281 GLX_PBUFFER_HEIGHT, size_.height(), | |
282 0 | |
283 }; | |
284 pbuffer_ = glXCreatePbuffer(g_display, | |
285 static_cast<GLXFBConfig>(config_), | |
286 pbuffer_attributes); | |
287 if (!pbuffer_) { | |
288 Destroy(); | |
289 LOG(ERROR) << "glXCreatePbuffer failed."; | |
290 return false; | |
291 } | |
292 | |
293 return true; | |
294 } | |
295 | |
296 void PbufferGLSurfaceGLX::Destroy() { | |
297 if (pbuffer_) { | |
298 glXDestroyPbuffer(g_display, pbuffer_); | |
299 pbuffer_ = 0; | |
300 } | |
301 | |
302 config_ = NULL; | |
303 } | |
304 | |
305 bool PbufferGLSurfaceGLX::IsOffscreen() { | |
306 return true; | |
307 } | |
308 | |
309 bool PbufferGLSurfaceGLX::SwapBuffers() { | |
310 NOTREACHED() << "Attempted to call SwapBuffers on a pbuffer."; | |
311 return false; | |
312 } | |
313 | |
314 gfx::Size PbufferGLSurfaceGLX::GetSize() { | |
315 return size_; | |
316 } | |
317 | |
318 void* PbufferGLSurfaceGLX::GetHandle() { | |
319 return reinterpret_cast<void*>(pbuffer_); | |
320 } | |
321 | |
322 void* PbufferGLSurfaceGLX::GetConfig() { | |
323 return config_; | |
324 } | |
325 | |
326 } // namespace gfx | |
OLD | NEW |