Home | History | Annotate | Download | only in gl
      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