// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. extern "C" { #include } #include "ui/gl/gl_context_glx.h" #include "base/debug/trace_event.h" #include "base/logging.h" #include "base/memory/scoped_ptr.h" #include "third_party/mesa/src/include/GL/osmesa.h" #include "ui/gl/GL/glextchromium.h" #include "ui/gl/gl_bindings.h" #include "ui/gl/gl_implementation.h" #include "ui/gl/gl_surface_glx.h" namespace gfx { GLContextGLX::GLContextGLX(GLShareGroup* share_group) : GLContextReal(share_group), context_(NULL), display_(NULL) { } XDisplay* GLContextGLX::display() { return display_; } bool GLContextGLX::Initialize( GLSurface* compatible_surface, GpuPreference gpu_preference) { display_ = static_cast(compatible_surface->GetDisplay()); GLXContext share_handle = static_cast( share_group() ? share_group()->GetHandle() : NULL); if (GLSurfaceGLX::IsCreateContextSupported()) { DVLOG(1) << "GLX_ARB_create_context supported."; std::vector attribs; if (GLSurfaceGLX::IsCreateContextRobustnessSupported()) { DVLOG(1) << "GLX_ARB_create_context_robustness supported."; attribs.push_back(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB); attribs.push_back(GLX_LOSE_CONTEXT_ON_RESET_ARB); } attribs.push_back(0); context_ = glXCreateContextAttribsARB( display_, static_cast(compatible_surface->GetConfig()), share_handle, True, &attribs.front()); if (!context_) { LOG(ERROR) << "Failed to create GL context with " << "glXCreateContextAttribsARB."; return false; } } else { DVLOG(1) << "GLX_ARB_create_context not supported."; context_ = glXCreateNewContext( display_, static_cast(compatible_surface->GetConfig()), GLX_RGBA_TYPE, share_handle, True); if (!context_) { LOG(ERROR) << "Failed to create GL context with glXCreateNewContext."; return false; } } DCHECK(context_); DVLOG(1) << " Successfully allocated " << (compatible_surface->IsOffscreen() ? "offscreen" : "onscreen") << " GL context with LOSE_CONTEXT_ON_RESET_ARB"; DVLOG(1) << (compatible_surface->IsOffscreen() ? "Offscreen" : "Onscreen") << " context was " << (glXIsDirect(display_, static_cast(context_)) ? "direct" : "indirect") << "."; return true; } void GLContextGLX::Destroy() { if (context_) { glXDestroyContext(display_, static_cast(context_)); context_ = NULL; } } bool GLContextGLX::MakeCurrent(GLSurface* surface) { DCHECK(context_); if (IsCurrent(surface)) return true; TRACE_EVENT0("gpu", "GLContextGLX::MakeCurrent"); if (!glXMakeContextCurrent( display_, reinterpret_cast(surface->GetHandle()), reinterpret_cast(surface->GetHandle()), static_cast(context_))) { LOG(ERROR) << "Couldn't make context current with X drawable."; Destroy(); return false; } // Set this as soon as the context is current, since we might call into GL. SetRealGLApi(); SetCurrent(surface); if (!InitializeDynamicBindings()) { ReleaseCurrent(surface); Destroy(); return false; } if (!surface->OnMakeCurrent(this)) { LOG(ERROR) << "Could not make current."; ReleaseCurrent(surface); Destroy(); return false; } return true; } void GLContextGLX::ReleaseCurrent(GLSurface* surface) { if (!IsCurrent(surface)) return; SetCurrent(NULL); if (!glXMakeContextCurrent(display_, 0, 0, 0)) LOG(ERROR) << "glXMakeCurrent failed in ReleaseCurrent"; } bool GLContextGLX::IsCurrent(GLSurface* surface) { bool native_context_is_current = glXGetCurrentContext() == static_cast(context_); // If our context is current then our notion of which GLContext is // current must be correct. On the other hand, third-party code // using OpenGL might change the current context. DCHECK(!native_context_is_current || (GetRealCurrent() == this)); if (!native_context_is_current) return false; if (surface) { if (glXGetCurrentDrawable() != reinterpret_cast(surface->GetHandle())) { return false; } } return true; } void* GLContextGLX::GetHandle() { return context_; } void GLContextGLX::SetSwapInterval(int interval) { DCHECK(IsCurrent(NULL)); if (HasExtension("GLX_EXT_swap_control") && g_driver_glx.fn.glXSwapIntervalEXTFn) { glXSwapIntervalEXT( display_, glXGetCurrentDrawable(), interval); } else if (HasExtension("GLX_MESA_swap_control") && g_driver_glx.fn.glXSwapIntervalMESAFn) { glXSwapIntervalMESA(interval); } else { if(interval == 0) LOG(WARNING) << "Could not disable vsync: driver does not " "support GLX_EXT_swap_control"; } } std::string GLContextGLX::GetExtensions() { DCHECK(IsCurrent(NULL)); const char* extensions = GLSurfaceGLX::GetGLXExtensions(); if (extensions) { return GLContext::GetExtensions() + " " + extensions; } return GLContext::GetExtensions(); } bool GLContextGLX::GetTotalGpuMemory(size_t* bytes) { DCHECK(bytes); *bytes = 0; if (HasExtension("GL_NVX_gpu_memory_info")) { GLint kbytes = 0; glGetIntegerv(GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX, &kbytes); *bytes = 1024*kbytes; return true; } return false; } bool GLContextGLX::WasAllocatedUsingRobustnessExtension() { return GLSurfaceGLX::IsCreateContextRobustnessSupported(); } GLContextGLX::~GLContextGLX() { Destroy(); } } // namespace gfx