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