Home | History | Annotate | Download | only in unix
      1 
      2 /*
      3  * Copyright 2011 Google Inc.
      4  *
      5  * Use of this source code is governed by a BSD-style license that can be
      6  * found in the LICENSE file.
      7  */
      8 #include "gl/SkNativeGLContext.h"
      9 
     10 #include <GL/glu.h>
     11 
     12 SkNativeGLContext::AutoContextRestore::AutoContextRestore() {
     13     fOldGLXContext = glXGetCurrentContext();
     14     fOldDisplay = glXGetCurrentDisplay();
     15     fOldDrawable = glXGetCurrentDrawable();
     16 }
     17 
     18 SkNativeGLContext::AutoContextRestore::~AutoContextRestore() {
     19     if (NULL != fOldDisplay) {
     20         glXMakeCurrent(fOldDisplay, fOldDrawable, fOldGLXContext);
     21     }
     22 }
     23 
     24 ///////////////////////////////////////////////////////////////////////////////
     25 
     26 static bool ctxErrorOccurred = false;
     27 static int ctxErrorHandler(Display *dpy, XErrorEvent *ev) {
     28     ctxErrorOccurred = true;
     29     return 0;
     30 }
     31 
     32 SkNativeGLContext::SkNativeGLContext()
     33     : fContext(NULL)
     34     , fDisplay(NULL)
     35     , fPixmap(0)
     36     , fGlxPixmap(0) {
     37 }
     38 
     39 SkNativeGLContext::~SkNativeGLContext() {
     40     this->destroyGLContext();
     41 }
     42 
     43 void SkNativeGLContext::destroyGLContext() {
     44     if (fDisplay) {
     45         glXMakeCurrent(fDisplay, 0, 0);
     46 
     47         if (fContext) {
     48             glXDestroyContext(fDisplay, fContext);
     49             fContext = NULL;
     50         }
     51 
     52         if (fGlxPixmap) {
     53             glXDestroyGLXPixmap(fDisplay, fGlxPixmap);
     54             fGlxPixmap = 0;
     55         }
     56 
     57         if (fPixmap) {
     58             XFreePixmap(fDisplay, fPixmap);
     59             fPixmap = 0;
     60         }
     61 
     62         XCloseDisplay(fDisplay);
     63         fDisplay = NULL;
     64     }
     65 }
     66 
     67 const GrGLInterface* SkNativeGLContext::createGLContext() {
     68     fDisplay = XOpenDisplay(0);
     69 
     70     if (!fDisplay) {
     71         SkDebugf("Failed to open X display.\n");
     72         this->destroyGLContext();
     73         return NULL;
     74     }
     75 
     76     // Get a matching FB config
     77     static int visual_attribs[] = {
     78         GLX_X_RENDERABLE    , True,
     79         GLX_DRAWABLE_TYPE   , GLX_PIXMAP_BIT,
     80         None
     81     };
     82 
     83     int glx_major, glx_minor;
     84 
     85     // FBConfigs were added in GLX version 1.3.
     86     if (!glXQueryVersion(fDisplay, &glx_major, &glx_minor) ||
     87             ( (glx_major == 1) && (glx_minor < 3) ) || (glx_major < 1))
     88     {
     89         SkDebugf("Invalid GLX version.");
     90         this->destroyGLContext();
     91         return NULL;
     92     }
     93 
     94     //SkDebugf("Getting matching framebuffer configs.\n");
     95     int fbcount;
     96     GLXFBConfig *fbc = glXChooseFBConfig(fDisplay, DefaultScreen(fDisplay),
     97                                           visual_attribs, &fbcount);
     98     if (!fbc) {
     99         SkDebugf("Failed to retrieve a framebuffer config.\n");
    100         this->destroyGLContext();
    101         return NULL;
    102     }
    103     //SkDebugf("Found %d matching FB configs.\n", fbcount);
    104 
    105     // Pick the FB config/visual with the most samples per pixel
    106     //SkDebugf("Getting XVisualInfos.\n");
    107     int best_fbc = -1, worst_fbc = -1, best_num_samp = -1, worst_num_samp = 999;
    108 
    109     int i;
    110     for (i = 0; i < fbcount; ++i) {
    111         XVisualInfo *vi = glXGetVisualFromFBConfig(fDisplay, fbc[i]);
    112         if (vi) {
    113             int samp_buf, samples;
    114             glXGetFBConfigAttrib(fDisplay, fbc[i], GLX_SAMPLE_BUFFERS, &samp_buf);
    115             glXGetFBConfigAttrib(fDisplay, fbc[i], GLX_SAMPLES, &samples);
    116 
    117             //SkDebugf("  Matching fbconfig %d, visual ID 0x%2x: SAMPLE_BUFFERS = %d,"
    118             //       " SAMPLES = %d\n",
    119             //        i, (unsigned int)vi->visualid, samp_buf, samples);
    120 
    121             if (best_fbc < 0 || (samp_buf && samples > best_num_samp))
    122                 best_fbc = i, best_num_samp = samples;
    123             if (worst_fbc < 0 || !samp_buf || samples < worst_num_samp)
    124                 worst_fbc = i, worst_num_samp = samples;
    125         }
    126         XFree(vi);
    127     }
    128 
    129     GLXFBConfig bestFbc = fbc[best_fbc];
    130 
    131     // Be sure to free the FBConfig list allocated by glXChooseFBConfig()
    132     XFree(fbc);
    133 
    134     // Get a visual
    135     XVisualInfo *vi = glXGetVisualFromFBConfig(fDisplay, bestFbc);
    136     //SkDebugf("Chosen visual ID = 0x%x\n", (unsigned int)vi->visualid);
    137 
    138     fPixmap = XCreatePixmap(fDisplay, RootWindow(fDisplay, vi->screen), 10, 10, vi->depth);
    139 
    140     if (!fPixmap) {
    141         SkDebugf("Failed to create pixmap.\n");
    142         this->destroyGLContext();
    143         return NULL;
    144     }
    145 
    146     fGlxPixmap = glXCreateGLXPixmap(fDisplay, vi, fPixmap);
    147 
    148     // Done with the visual info data
    149     XFree(vi);
    150 
    151     // Create the context
    152 
    153     // Install an X error handler so the application won't exit if GL 3.0
    154     // context allocation fails.
    155     //
    156     // Note this error handler is global.
    157     // All display connections in all threads of a process use the same
    158     // error handler, so be sure to guard against other threads issuing
    159     // X commands while this code is running.
    160     ctxErrorOccurred = false;
    161     int (*oldHandler)(Display*, XErrorEvent*) =
    162         XSetErrorHandler(&ctxErrorHandler);
    163 
    164     // Get the default screen's GLX extension list
    165     const char *glxExts = glXQueryExtensionsString(
    166         fDisplay, DefaultScreen(fDisplay)
    167     );
    168     // Check for the GLX_ARB_create_context extension string and the function.
    169     // If either is not present, use GLX 1.3 context creation method.
    170     if (!gluCheckExtension(
    171           reinterpret_cast<const GLubyte*>("GLX_ARB_create_context")
    172           , reinterpret_cast<const GLubyte*>(glxExts)))
    173     {
    174         //SkDebugf("GLX_ARB_create_context not found."
    175         //       " Using old-style GLX context.\n");
    176         fContext = glXCreateNewContext(fDisplay, bestFbc, GLX_RGBA_TYPE, 0, True);
    177 
    178     } else {
    179         //SkDebugf("Creating context.\n");
    180 
    181         PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB =
    182             (PFNGLXCREATECONTEXTATTRIBSARBPROC) glXGetProcAddressARB((GrGLubyte*)"glXCreateContextAttribsARB");
    183         int context_attribs[] = {
    184             GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
    185             GLX_CONTEXT_MINOR_VERSION_ARB, 0,
    186             //GLX_CONTEXT_FLAGS_ARB        , GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
    187             None
    188         };
    189         fContext = glXCreateContextAttribsARB(
    190             fDisplay, bestFbc, 0, True, context_attribs
    191         );
    192 
    193         // Sync to ensure any errors generated are processed.
    194         XSync(fDisplay, False);
    195         if (!ctxErrorOccurred && fContext) {
    196            //SkDebugf( "Created GL 3.0 context.\n" );
    197         } else {
    198             // Couldn't create GL 3.0 context.
    199             // Fall back to old-style 2.x context.
    200             // When a context version below 3.0 is requested,
    201             // implementations will return the newest context version compatible
    202             // with OpenGL versions less than version 3.0.
    203 
    204             // GLX_CONTEXT_MAJOR_VERSION_ARB = 1
    205             context_attribs[1] = 1;
    206             // GLX_CONTEXT_MINOR_VERSION_ARB = 0
    207             context_attribs[3] = 0;
    208 
    209             ctxErrorOccurred = false;
    210 
    211             //SkDebugf("Failed to create GL 3.0 context."
    212             //       " Using old-style GLX context.\n");
    213             fContext = glXCreateContextAttribsARB(
    214                 fDisplay, bestFbc, 0, True, context_attribs
    215             );
    216         }
    217     }
    218 
    219     // Sync to ensure any errors generated are processed.
    220     XSync(fDisplay, False);
    221 
    222     // Restore the original error handler
    223     XSetErrorHandler(oldHandler);
    224 
    225     if (ctxErrorOccurred || !fContext) {
    226         SkDebugf("Failed to create an OpenGL context.\n");
    227         this->destroyGLContext();
    228         return NULL;
    229     }
    230 
    231     // Verify that context is a direct context
    232     if (!glXIsDirect(fDisplay, fContext)) {
    233         //SkDebugf("Indirect GLX rendering context obtained.\n");
    234     } else {
    235         //SkDebugf("Direct GLX rendering context obtained.\n");
    236     }
    237 
    238     //SkDebugf("Making context current.\n");
    239     if (!glXMakeCurrent(fDisplay, fGlxPixmap, fContext)) {
    240       SkDebugf("Could not set the context.\n");
    241         this->destroyGLContext();
    242         return NULL;
    243     }
    244 
    245     const GrGLInterface* interface = GrGLCreateNativeInterface();
    246     if (!interface) {
    247         SkDebugf("Failed to create gl interface");
    248         this->destroyGLContext();
    249         return NULL;
    250     }
    251     return interface;
    252 }
    253 
    254 void SkNativeGLContext::makeCurrent() const {
    255     if (!glXMakeCurrent(fDisplay, fGlxPixmap, fContext)) {
    256         SkDebugf("Could not set the context.\n");
    257     }
    258 }
    259