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 "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