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