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