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_context_glx.h" | |
10 | |
11 #include "base/debug/trace_event.h" | |
12 #include "base/logging.h" | |
13 #include "base/memory/scoped_ptr.h" | |
14 #include "third_party/mesa/MesaLib/include/GL/osmesa.h" | |
15 #include "ui/gfx/gl/gl_bindings.h" | |
16 #include "ui/gfx/gl/gl_implementation.h" | |
17 #include "ui/gfx/gl/gl_surface_glx.h" | |
18 | |
19 namespace gfx { | |
20 | |
21 namespace { | |
22 | |
23 // scoped_ptr functor for XFree(). Use as follows: | |
24 // scoped_ptr_malloc<XVisualInfo, ScopedPtrXFree> foo(...); | |
25 // where "XVisualInfo" is any X type that is freed with XFree. | |
26 class ScopedPtrXFree { | |
27 public: | |
28 void operator()(void* x) const { | |
29 ::XFree(x); | |
30 } | |
31 }; | |
32 | |
33 } // namespace anonymous | |
34 | |
35 GLContextGLX::GLContextGLX(GLShareGroup* share_group) | |
36 : GLContext(share_group), | |
37 context_(NULL), | |
38 display_(NULL) { | |
39 } | |
40 | |
41 GLContextGLX::~GLContextGLX() { | |
42 Destroy(); | |
43 } | |
44 | |
45 Display* GLContextGLX::display() { | |
46 return display_; | |
47 } | |
48 | |
49 bool GLContextGLX::Initialize( | |
50 GLSurface* compatible_surface, GpuPreference gpu_preference) { | |
51 display_ = static_cast<Display*>(compatible_surface->GetDisplay()); | |
52 | |
53 GLXContext share_handle = static_cast<GLXContext>( | |
54 share_group() ? share_group()->GetHandle() : NULL); | |
55 | |
56 if (GLSurfaceGLX::IsCreateContextRobustnessSupported()) { | |
57 DLOG(INFO) << "GLX_ARB_create_context_robustness supported."; | |
58 | |
59 std::vector<int> attribs; | |
60 attribs.push_back(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB); | |
61 attribs.push_back(GLX_LOSE_CONTEXT_ON_RESET_ARB); | |
62 attribs.push_back(0); | |
63 context_ = glXCreateContextAttribsARB( | |
64 display_, | |
65 static_cast<GLXFBConfig>(compatible_surface->GetConfig()), | |
66 share_handle, | |
67 True, | |
68 &attribs.front()); | |
69 if (context_) { | |
70 DLOG(INFO) << " Successfully allocated " | |
71 << (compatible_surface->IsOffscreen() ? | |
72 "offscreen" : "onscreen") | |
73 << " GL context with LOSE_CONTEXT_ON_RESET_ARB"; | |
74 } else { | |
75 // TODO(kbr): it is not expected that things will work properly | |
76 // in this case, since we will likely allocate our offscreen | |
77 // contexts with this bit set and the onscreen contexts without, | |
78 // and won't be able to put them in the same share group. | |
79 // Consider what to do here; force loss of all contexts and | |
80 // reallocation without ARB_robustness? | |
81 LOG(ERROR) << | |
82 " FAILED to allocate GL context with LOSE_CONTEXT_ON_RESET_ARB"; | |
83 } | |
84 } | |
85 | |
86 if (!context_) { | |
87 // The means by which the context is created depends on whether | |
88 // the drawable type works reliably with GLX 1.3. If it does not | |
89 // then fall back to GLX 1.2. | |
90 if (compatible_surface->IsOffscreen()) { | |
91 context_ = glXCreateNewContext( | |
92 display_, | |
93 static_cast<GLXFBConfig>(compatible_surface->GetConfig()), | |
94 GLX_RGBA_TYPE, | |
95 share_handle, | |
96 True); | |
97 } else { | |
98 // Get the visuals for the X drawable. | |
99 XWindowAttributes attributes; | |
100 if (!XGetWindowAttributes( | |
101 display_, | |
102 reinterpret_cast<GLXDrawable>(compatible_surface->GetHandle()), | |
103 &attributes)) { | |
104 LOG(ERROR) << "XGetWindowAttributes failed for window " << | |
105 reinterpret_cast<GLXDrawable>( | |
106 compatible_surface->GetHandle()) << "."; | |
107 return false; | |
108 } | |
109 | |
110 XVisualInfo visual_info_template; | |
111 visual_info_template.visualid = XVisualIDFromVisual(attributes.visual); | |
112 | |
113 int visual_info_count = 0; | |
114 scoped_ptr_malloc<XVisualInfo, ScopedPtrXFree> visual_info_list( | |
115 XGetVisualInfo(display_, VisualIDMask, | |
116 &visual_info_template, | |
117 &visual_info_count)); | |
118 | |
119 DCHECK(visual_info_list.get()); | |
120 if (visual_info_count == 0) { | |
121 LOG(ERROR) << "No visual info for visual ID."; | |
122 return false; | |
123 } | |
124 | |
125 // Attempt to create a context with each visual in turn until one works. | |
126 context_ = glXCreateContext( | |
127 display_, | |
128 visual_info_list.get(), | |
129 share_handle, | |
130 True); | |
131 } | |
132 } | |
133 | |
134 if (!context_) { | |
135 LOG(ERROR) << "Couldn't create GL context."; | |
136 return false; | |
137 } | |
138 | |
139 DLOG(INFO) << (compatible_surface->IsOffscreen() ? "Offscreen" : "Onscreen") | |
140 << " context was " | |
141 << (glXIsDirect(display_, | |
142 static_cast<GLXContext>(context_)) | |
143 ? "direct" : "indirect") | |
144 << "."; | |
145 | |
146 return true; | |
147 } | |
148 | |
149 void GLContextGLX::Destroy() { | |
150 if (context_) { | |
151 glXDestroyContext(display_, | |
152 static_cast<GLXContext>(context_)); | |
153 context_ = NULL; | |
154 } | |
155 } | |
156 | |
157 bool GLContextGLX::MakeCurrent(GLSurface* surface) { | |
158 DCHECK(context_); | |
159 if (IsCurrent(surface)) | |
160 return true; | |
161 | |
162 TRACE_EVENT0("gpu", "GLContextGLX::MakeCurrent"); | |
163 if (!glXMakeCurrent( | |
164 display_, | |
165 reinterpret_cast<GLXDrawable>(surface->GetHandle()), | |
166 static_cast<GLXContext>(context_))) { | |
167 LOG(ERROR) << "Couldn't make context current with X drawable."; | |
168 Destroy(); | |
169 return false; | |
170 } | |
171 | |
172 SetCurrent(this, surface); | |
173 if (!InitializeExtensionBindings()) { | |
174 ReleaseCurrent(surface); | |
175 Destroy(); | |
176 return false; | |
177 } | |
178 | |
179 if (!surface->OnMakeCurrent(this)) { | |
180 LOG(ERROR) << "Could not make current."; | |
181 ReleaseCurrent(surface); | |
182 Destroy(); | |
183 return false; | |
184 } | |
185 | |
186 return true; | |
187 } | |
188 | |
189 void GLContextGLX::ReleaseCurrent(GLSurface* surface) { | |
190 if (!IsCurrent(surface)) | |
191 return; | |
192 | |
193 SetCurrent(NULL, NULL); | |
194 if (!glXMakeCurrent(display_, 0, 0)) | |
195 LOG(ERROR) << "glXMakeCurrent failed in ReleaseCurrent"; | |
196 } | |
197 | |
198 bool GLContextGLX::IsCurrent(GLSurface* surface) { | |
199 bool native_context_is_current = | |
200 glXGetCurrentContext() == static_cast<GLXContext>(context_); | |
201 | |
202 // If our context is current then our notion of which GLContext is | |
203 // current must be correct. On the other hand, third-party code | |
204 // using OpenGL might change the current context. | |
205 DCHECK(!native_context_is_current || (GetCurrent() == this)); | |
206 | |
207 if (!native_context_is_current) | |
208 return false; | |
209 | |
210 if (surface) { | |
211 if (glXGetCurrentDrawable() != | |
212 reinterpret_cast<GLXDrawable>(surface->GetHandle())) { | |
213 return false; | |
214 } | |
215 } | |
216 | |
217 return true; | |
218 } | |
219 | |
220 void* GLContextGLX::GetHandle() { | |
221 return context_; | |
222 } | |
223 | |
224 void GLContextGLX::SetSwapInterval(int interval) { | |
225 DCHECK(IsCurrent(NULL)); | |
226 if (HasExtension("GLX_EXT_swap_control") && glXSwapIntervalEXT) { | |
227 glXSwapIntervalEXT( | |
228 display_, | |
229 glXGetCurrentDrawable(), | |
230 interval); | |
231 } else { | |
232 if(interval == 0) | |
233 LOG(WARNING) << | |
234 "Could not disable vsync: driver does not " | |
235 "support GLX_EXT_swap_control"; | |
236 } | |
237 } | |
238 | |
239 std::string GLContextGLX::GetExtensions() { | |
240 DCHECK(IsCurrent(NULL)); | |
241 const char* extensions = GLSurfaceGLX::GetGLXExtensions(); | |
242 if (extensions) { | |
243 return GLContext::GetExtensions() + " " + extensions; | |
244 } | |
245 | |
246 return GLContext::GetExtensions(); | |
247 } | |
248 | |
249 bool GLContextGLX::WasAllocatedUsingARBRobustness() { | |
250 return GLSurfaceGLX::IsCreateContextRobustnessSupported(); | |
251 } | |
252 | |
253 } // namespace gfx | |
OLD | NEW |