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/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/src/include/GL/osmesa.h" 15 #include "ui/gl/GL/glextchromium.h" 16 #include "ui/gl/gl_bindings.h" 17 #include "ui/gl/gl_implementation.h" 18 #include "ui/gl/gl_surface_glx.h" 19 20 namespace gfx { 21 22 namespace { 23 24 // scoped_ptr functor for XFree(). Use as follows: 25 // scoped_ptr_malloc<XVisualInfo, ScopedPtrXFree> foo(...); 26 // where "XVisualInfo" is any X type that is freed with XFree. 27 class ScopedPtrXFree { 28 public: 29 void operator()(void* x) const { 30 ::XFree(x); 31 } 32 }; 33 34 } // namespace 35 36 GLContextGLX::GLContextGLX(GLShareGroup* share_group) 37 : GLContextReal(share_group), 38 context_(NULL), 39 display_(NULL) { 40 } 41 42 XDisplay* GLContextGLX::display() { 43 return display_; 44 } 45 46 bool GLContextGLX::Initialize( 47 GLSurface* compatible_surface, GpuPreference gpu_preference) { 48 display_ = static_cast<XDisplay*>(compatible_surface->GetDisplay()); 49 50 GLXContext share_handle = static_cast<GLXContext>( 51 share_group() ? share_group()->GetHandle() : NULL); 52 53 if (GLSurfaceGLX::IsCreateContextSupported()) { 54 DVLOG(1) << "GLX_ARB_create_context supported."; 55 std::vector<int> attribs; 56 if (GLSurfaceGLX::IsCreateContextRobustnessSupported()) { 57 DVLOG(1) << "GLX_ARB_create_context_robustness supported."; 58 attribs.push_back(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB); 59 attribs.push_back(GLX_LOSE_CONTEXT_ON_RESET_ARB); 60 } 61 attribs.push_back(0); 62 context_ = glXCreateContextAttribsARB( 63 display_, 64 static_cast<GLXFBConfig>(compatible_surface->GetConfig()), 65 share_handle, 66 True, 67 &attribs.front()); 68 if (!context_) { 69 LOG(ERROR) << "Failed to create GL context with " 70 << "glXCreateContextAttribsARB."; 71 return false; 72 } 73 } else { 74 DVLOG(1) << "GLX_ARB_create_context not supported."; 75 context_ = glXCreateNewContext( 76 display_, 77 static_cast<GLXFBConfig>(compatible_surface->GetConfig()), 78 GLX_RGBA_TYPE, 79 share_handle, 80 True); 81 if (!context_) { 82 LOG(ERROR) << "Failed to create GL context with glXCreateNewContext."; 83 return false; 84 } 85 } 86 DCHECK(context_); 87 DVLOG(1) << " Successfully allocated " 88 << (compatible_surface->IsOffscreen() ? 89 "offscreen" : "onscreen") 90 << " GL context with LOSE_CONTEXT_ON_RESET_ARB"; 91 92 DVLOG(1) << (compatible_surface->IsOffscreen() ? "Offscreen" : "Onscreen") 93 << " context was " 94 << (glXIsDirect(display_, 95 static_cast<GLXContext>(context_)) 96 ? "direct" : "indirect") 97 << "."; 98 99 return true; 100 } 101 102 void GLContextGLX::Destroy() { 103 if (context_) { 104 glXDestroyContext(display_, 105 static_cast<GLXContext>(context_)); 106 context_ = NULL; 107 } 108 } 109 110 bool GLContextGLX::MakeCurrent(GLSurface* surface) { 111 DCHECK(context_); 112 if (IsCurrent(surface)) 113 return true; 114 115 TRACE_EVENT0("gpu", "GLContextGLX::MakeCurrent"); 116 if (!glXMakeContextCurrent( 117 display_, 118 reinterpret_cast<GLXDrawable>(surface->GetHandle()), 119 reinterpret_cast<GLXDrawable>(surface->GetHandle()), 120 static_cast<GLXContext>(context_))) { 121 LOG(ERROR) << "Couldn't make context current with X drawable."; 122 Destroy(); 123 return false; 124 } 125 126 // Set this as soon as the context is current, since we might call into GL. 127 SetRealGLApi(); 128 129 SetCurrent(surface); 130 if (!InitializeExtensionBindings()) { 131 ReleaseCurrent(surface); 132 Destroy(); 133 return false; 134 } 135 136 if (!surface->OnMakeCurrent(this)) { 137 LOG(ERROR) << "Could not make current."; 138 ReleaseCurrent(surface); 139 Destroy(); 140 return false; 141 } 142 143 return true; 144 } 145 146 void GLContextGLX::ReleaseCurrent(GLSurface* surface) { 147 if (!IsCurrent(surface)) 148 return; 149 150 SetCurrent(NULL); 151 if (!glXMakeContextCurrent(display_, 0, 0, 0)) 152 LOG(ERROR) << "glXMakeCurrent failed in ReleaseCurrent"; 153 } 154 155 bool GLContextGLX::IsCurrent(GLSurface* surface) { 156 bool native_context_is_current = 157 glXGetCurrentContext() == static_cast<GLXContext>(context_); 158 159 // If our context is current then our notion of which GLContext is 160 // current must be correct. On the other hand, third-party code 161 // using OpenGL might change the current context. 162 DCHECK(!native_context_is_current || (GetRealCurrent() == this)); 163 164 if (!native_context_is_current) 165 return false; 166 167 if (surface) { 168 if (glXGetCurrentDrawable() != 169 reinterpret_cast<GLXDrawable>(surface->GetHandle())) { 170 return false; 171 } 172 } 173 174 return true; 175 } 176 177 void* GLContextGLX::GetHandle() { 178 return context_; 179 } 180 181 void GLContextGLX::SetSwapInterval(int interval) { 182 DCHECK(IsCurrent(NULL)); 183 if (HasExtension("GLX_EXT_swap_control") && 184 g_driver_glx.fn.glXSwapIntervalEXTFn) { 185 glXSwapIntervalEXT( 186 display_, 187 glXGetCurrentDrawable(), 188 interval); 189 } else if (HasExtension("GLX_MESA_swap_control") && 190 g_driver_glx.fn.glXSwapIntervalMESAFn) { 191 glXSwapIntervalMESA(interval); 192 } else { 193 if(interval == 0) 194 LOG(WARNING) << 195 "Could not disable vsync: driver does not " 196 "support GLX_EXT_swap_control"; 197 } 198 } 199 200 std::string GLContextGLX::GetExtensions() { 201 DCHECK(IsCurrent(NULL)); 202 const char* extensions = GLSurfaceGLX::GetGLXExtensions(); 203 if (extensions) { 204 return GLContext::GetExtensions() + " " + extensions; 205 } 206 207 return GLContext::GetExtensions(); 208 } 209 210 bool GLContextGLX::GetTotalGpuMemory(size_t* bytes) { 211 DCHECK(bytes); 212 *bytes = 0; 213 if (HasExtension("GL_NVX_gpu_memory_info")) { 214 GLint kbytes = 0; 215 glGetIntegerv(GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX, &kbytes); 216 *bytes = 1024*kbytes; 217 return true; 218 } 219 return false; 220 } 221 222 bool GLContextGLX::WasAllocatedUsingRobustnessExtension() { 223 return GLSurfaceGLX::IsCreateContextRobustnessSupported(); 224 } 225 226 GLContextGLX::~GLContextGLX() { 227 Destroy(); 228 } 229 230 } // namespace gfx 231