| OLD | NEW | 
 | (Empty) | 
|    1 /* |  | 
|    2  * Copyright 2011 Google Inc. |  | 
|    3  * |  | 
|    4  * Use of this source code is governed by a BSD-style license that can be |  | 
|    5  * found in the LICENSE file. |  | 
|    6  */ |  | 
|    7 #include "gl/SkGLContext.h" |  | 
|    8  |  | 
|    9 #include <X11/Xlib.h> |  | 
|   10 #include <GL/glx.h> |  | 
|   11 #include <GL/glu.h> |  | 
|   12  |  | 
|   13 namespace { |  | 
|   14  |  | 
|   15 /* Note: Skia requires glx 1.3 or newer */ |  | 
|   16  |  | 
|   17 /* This struct is taken from a mesa demo.  Please update as required */ |  | 
|   18 static const struct { int major, minor; } gl_versions[] = { |  | 
|   19    {1, 0}, |  | 
|   20    {1, 1}, |  | 
|   21    {1, 2}, |  | 
|   22    {1, 3}, |  | 
|   23    {1, 4}, |  | 
|   24    {1, 5}, |  | 
|   25    {2, 0}, |  | 
|   26    {2, 1}, |  | 
|   27    {3, 0}, |  | 
|   28    {3, 1}, |  | 
|   29    {3, 2}, |  | 
|   30    {3, 3}, |  | 
|   31    {4, 0}, |  | 
|   32    {4, 1}, |  | 
|   33    {4, 2}, |  | 
|   34    {4, 3}, |  | 
|   35    {4, 4}, |  | 
|   36    {0, 0} /* end of list */ |  | 
|   37 }; |  | 
|   38 #define NUM_GL_VERSIONS SK_ARRAY_COUNT(gl_versions) |  | 
|   39  |  | 
|   40 static bool ctxErrorOccurred = false; |  | 
|   41 static int ctxErrorHandler(Display *dpy, XErrorEvent *ev) { |  | 
|   42     ctxErrorOccurred = true; |  | 
|   43     return 0; |  | 
|   44 } |  | 
|   45  |  | 
|   46 class GLXGLContext : public SkGLContext { |  | 
|   47 public: |  | 
|   48     GLXGLContext(GrGLStandard forcedGpuAPI, GLXGLContext* shareList); |  | 
|   49     ~GLXGLContext() override; |  | 
|   50  |  | 
|   51 private: |  | 
|   52     void destroyGLContext(); |  | 
|   53  |  | 
|   54     void onPlatformMakeCurrent() const override; |  | 
|   55     void onPlatformSwapBuffers() const override; |  | 
|   56     GrGLFuncPtr onPlatformGetProcAddress(const char*) const override; |  | 
|   57  |  | 
|   58     GLXContext fContext; |  | 
|   59     Display* fDisplay; |  | 
|   60     Pixmap fPixmap; |  | 
|   61     GLXPixmap fGlxPixmap; |  | 
|   62 }; |  | 
|   63  |  | 
|   64 GLXGLContext::GLXGLContext(GrGLStandard forcedGpuAPI, GLXGLContext* shareContext
     ) |  | 
|   65     : fContext(nullptr) |  | 
|   66     , fDisplay(nullptr) |  | 
|   67     , fPixmap(0) |  | 
|   68     , fGlxPixmap(0) { |  | 
|   69     fDisplay = XOpenDisplay(0); |  | 
|   70  |  | 
|   71     GLXContext glxShareContext = shareContext ? shareContext->fContext : nullptr
     ; |  | 
|   72  |  | 
|   73     if (!fDisplay) { |  | 
|   74         SkDebugf("Failed to open X display.\n"); |  | 
|   75         this->destroyGLContext(); |  | 
|   76         return; |  | 
|   77     } |  | 
|   78  |  | 
|   79     // Get a matching FB config |  | 
|   80     static int visual_attribs[] = { |  | 
|   81         GLX_X_RENDERABLE    , True, |  | 
|   82         GLX_DRAWABLE_TYPE   , GLX_PIXMAP_BIT, |  | 
|   83         None |  | 
|   84     }; |  | 
|   85  |  | 
|   86     int glx_major, glx_minor; |  | 
|   87  |  | 
|   88     // FBConfigs were added in GLX version 1.3. |  | 
|   89     if (!glXQueryVersion(fDisplay, &glx_major, &glx_minor) || |  | 
|   90             ((glx_major == 1) && (glx_minor < 3)) || (glx_major < 1)) { |  | 
|   91         SkDebugf("GLX version 1.3 or higher required.\n"); |  | 
|   92         this->destroyGLContext(); |  | 
|   93         return; |  | 
|   94     } |  | 
|   95  |  | 
|   96     //SkDebugf("Getting matching framebuffer configs.\n"); |  | 
|   97     int fbcount; |  | 
|   98     GLXFBConfig *fbc = glXChooseFBConfig(fDisplay, DefaultScreen(fDisplay), |  | 
|   99                                           visual_attribs, &fbcount); |  | 
|  100     if (!fbc) { |  | 
|  101         SkDebugf("Failed to retrieve a framebuffer config.\n"); |  | 
|  102         this->destroyGLContext(); |  | 
|  103         return; |  | 
|  104     } |  | 
|  105     //SkDebugf("Found %d matching FB configs.\n", fbcount); |  | 
|  106  |  | 
|  107     // Pick the FB config/visual with the most samples per pixel |  | 
|  108     //SkDebugf("Getting XVisualInfos.\n"); |  | 
|  109     int best_fbc = -1, best_num_samp = -1; |  | 
|  110  |  | 
|  111     int i; |  | 
|  112     for (i = 0; i < fbcount; ++i) { |  | 
|  113         XVisualInfo *vi = glXGetVisualFromFBConfig(fDisplay, fbc[i]); |  | 
|  114         if (vi) { |  | 
|  115             int samp_buf, samples; |  | 
|  116             glXGetFBConfigAttrib(fDisplay, fbc[i], GLX_SAMPLE_BUFFERS, &samp_buf
     ); |  | 
|  117             glXGetFBConfigAttrib(fDisplay, fbc[i], GLX_SAMPLES, &samples); |  | 
|  118  |  | 
|  119             //SkDebugf("  Matching fbconfig %d, visual ID 0x%2x: SAMPLE_BUFFERS 
     = %d," |  | 
|  120             //       " SAMPLES = %d\n", |  | 
|  121             //        i, (unsigned int)vi->visualid, samp_buf, samples); |  | 
|  122  |  | 
|  123             if (best_fbc < 0 || (samp_buf && samples > best_num_samp)) |  | 
|  124                 best_fbc = i, best_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; |  | 
|  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  |  | 
|  169  |  | 
|  170     // Check for the GLX_ARB_create_context extension string and the function. |  | 
|  171     // If either is not present, use GLX 1.3 context creation method. |  | 
|  172     if (!gluCheckExtension(reinterpret_cast<const GLubyte*>("GLX_ARB_create_cont
     ext"), |  | 
|  173                            reinterpret_cast<const GLubyte*>(glxExts))) { |  | 
|  174         if (kGLES_GrGLStandard != forcedGpuAPI) { |  | 
|  175             fContext = glXCreateNewContext(fDisplay, bestFbc, GLX_RGBA_TYPE, 0, 
     True); |  | 
|  176         } |  | 
|  177     } else { |  | 
|  178         //SkDebugf("Creating context.\n"); |  | 
|  179         PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB = |  | 
|  180             (PFNGLXCREATECONTEXTATTRIBSARBPROC) glXGetProcAddressARB((GrGLubyte*
     )"glXCreateContextAttribsARB"); |  | 
|  181  |  | 
|  182         if (kGLES_GrGLStandard == forcedGpuAPI) { |  | 
|  183             if (gluCheckExtension( |  | 
|  184                     reinterpret_cast<const GLubyte*>("GLX_EXT_create_context_es2
     _profile"), |  | 
|  185                     reinterpret_cast<const GLubyte*>(glxExts))) { |  | 
|  186                 static const int context_attribs_gles[] = { |  | 
|  187                     GLX_CONTEXT_MAJOR_VERSION_ARB, 3, |  | 
|  188                     GLX_CONTEXT_MINOR_VERSION_ARB, 0, |  | 
|  189                     GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_ES2_PROFILE_BIT_EX
     T, |  | 
|  190                     None |  | 
|  191                 }; |  | 
|  192                 fContext = glXCreateContextAttribsARB(fDisplay, bestFbc, glxShar
     eContext, True, |  | 
|  193                                                       context_attribs_gles); |  | 
|  194             } |  | 
|  195         } else { |  | 
|  196             // Well, unfortunately GLX will not just give us the highest context
      so instead we have |  | 
|  197             // to do this nastiness |  | 
|  198             for (i = NUM_GL_VERSIONS - 2; i > 0 ; i--) { |  | 
|  199                 /* don't bother below GL 3.0 */ |  | 
|  200                 if (gl_versions[i].major == 3 && gl_versions[i].minor == 0) { |  | 
|  201                     break; |  | 
|  202                 } |  | 
|  203                 // On Nvidia GPUs, to use Nv Path rendering we need a compatibil
     ity profile for the |  | 
|  204                 // time being. |  | 
|  205                 // TODO when Nvidia implements NVPR on Core profiles, we should 
     start requesting |  | 
|  206                 // core here |  | 
|  207                 static const int context_attribs_gl[] = { |  | 
|  208                       GLX_CONTEXT_MAJOR_VERSION_ARB, gl_versions[i].major, |  | 
|  209                       GLX_CONTEXT_MINOR_VERSION_ARB, gl_versions[i].minor, |  | 
|  210                       GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_COMPATIBILITY_PR
     OFILE_BIT_ARB, |  | 
|  211                       None |  | 
|  212                 }; |  | 
|  213                 fContext = |  | 
|  214                         glXCreateContextAttribsARB(fDisplay, bestFbc, glxShareCo
     ntext, True, |  | 
|  215                                                    context_attribs_gl); |  | 
|  216  |  | 
|  217                 // Sync to ensure any errors generated are processed. |  | 
|  218                 XSync(fDisplay, False); |  | 
|  219  |  | 
|  220                 if (!ctxErrorOccurred && fContext) { |  | 
|  221                     break; |  | 
|  222                 } |  | 
|  223                 // try again |  | 
|  224                 ctxErrorOccurred = false; |  | 
|  225             } |  | 
|  226  |  | 
|  227             // Couldn't create GL 3.0 context. |  | 
|  228             // Fall back to old-style 2.x context. |  | 
|  229             // When a context version below 3.0 is requested, |  | 
|  230             // implementations will return the newest context version |  | 
|  231             // compatible with OpenGL versions less than version 3.0. |  | 
|  232             if (ctxErrorOccurred || !fContext) { |  | 
|  233                 static const int context_attribs_gl_fallback[] = { |  | 
|  234                     GLX_CONTEXT_MAJOR_VERSION_ARB, 1, |  | 
|  235                     GLX_CONTEXT_MINOR_VERSION_ARB, 0, |  | 
|  236                     None |  | 
|  237                 }; |  | 
|  238  |  | 
|  239                 ctxErrorOccurred = false; |  | 
|  240  |  | 
|  241                 fContext = glXCreateContextAttribsARB(fDisplay, bestFbc, glxShar
     eContext, True, |  | 
|  242                                                       context_attribs_gl_fallbac
     k); |  | 
|  243             } |  | 
|  244         } |  | 
|  245     } |  | 
|  246  |  | 
|  247     // Sync to ensure any errors generated are processed. |  | 
|  248     XSync(fDisplay, False); |  | 
|  249  |  | 
|  250     // Restore the original error handler |  | 
|  251     XSetErrorHandler(oldHandler); |  | 
|  252  |  | 
|  253     if (ctxErrorOccurred || !fContext) { |  | 
|  254         SkDebugf("Failed to create an OpenGL context.\n"); |  | 
|  255         this->destroyGLContext(); |  | 
|  256         return; |  | 
|  257     } |  | 
|  258  |  | 
|  259     // Verify that context is a direct context |  | 
|  260     if (!glXIsDirect(fDisplay, fContext)) { |  | 
|  261         //SkDebugf("Indirect GLX rendering context obtained.\n"); |  | 
|  262     } else { |  | 
|  263         //SkDebugf("Direct GLX rendering context obtained.\n"); |  | 
|  264     } |  | 
|  265  |  | 
|  266     //SkDebugf("Making context current.\n"); |  | 
|  267     if (!glXMakeCurrent(fDisplay, fGlxPixmap, fContext)) { |  | 
|  268       SkDebugf("Could not set the context.\n"); |  | 
|  269         this->destroyGLContext(); |  | 
|  270         return; |  | 
|  271     } |  | 
|  272  |  | 
|  273     SkAutoTUnref<const GrGLInterface> gl(GrGLCreateNativeInterface()); |  | 
|  274     if (nullptr == gl.get()) { |  | 
|  275         SkDebugf("Failed to create gl interface"); |  | 
|  276         this->destroyGLContext(); |  | 
|  277         return; |  | 
|  278     } |  | 
|  279  |  | 
|  280     if (!gl->validate()) { |  | 
|  281         SkDebugf("Failed to validate gl interface"); |  | 
|  282         this->destroyGLContext(); |  | 
|  283         return; |  | 
|  284     } |  | 
|  285  |  | 
|  286     this->init(gl.release()); |  | 
|  287 } |  | 
|  288  |  | 
|  289  |  | 
|  290 GLXGLContext::~GLXGLContext() { |  | 
|  291     this->teardown(); |  | 
|  292     this->destroyGLContext(); |  | 
|  293 } |  | 
|  294  |  | 
|  295 void GLXGLContext::destroyGLContext() { |  | 
|  296     if (fDisplay) { |  | 
|  297         glXMakeCurrent(fDisplay, 0, 0); |  | 
|  298  |  | 
|  299         if (fContext) { |  | 
|  300             glXDestroyContext(fDisplay, fContext); |  | 
|  301             fContext = nullptr; |  | 
|  302         } |  | 
|  303  |  | 
|  304         if (fGlxPixmap) { |  | 
|  305             glXDestroyGLXPixmap(fDisplay, fGlxPixmap); |  | 
|  306             fGlxPixmap = 0; |  | 
|  307         } |  | 
|  308  |  | 
|  309         if (fPixmap) { |  | 
|  310             XFreePixmap(fDisplay, fPixmap); |  | 
|  311             fPixmap = 0; |  | 
|  312         } |  | 
|  313  |  | 
|  314         XCloseDisplay(fDisplay); |  | 
|  315         fDisplay = nullptr; |  | 
|  316     } |  | 
|  317 } |  | 
|  318  |  | 
|  319 void GLXGLContext::onPlatformMakeCurrent() const { |  | 
|  320     if (!glXMakeCurrent(fDisplay, fGlxPixmap, fContext)) { |  | 
|  321         SkDebugf("Could not set the context.\n"); |  | 
|  322     } |  | 
|  323 } |  | 
|  324  |  | 
|  325 void GLXGLContext::onPlatformSwapBuffers() const { |  | 
|  326     glXSwapBuffers(fDisplay, fGlxPixmap); |  | 
|  327 } |  | 
|  328  |  | 
|  329 GrGLFuncPtr GLXGLContext::onPlatformGetProcAddress(const char* procName) const { |  | 
|  330     return glXGetProcAddress(reinterpret_cast<const GLubyte*>(procName)); |  | 
|  331 } |  | 
|  332  |  | 
|  333 } // anonymous namespace |  | 
|  334  |  | 
|  335 SkGLContext* SkCreatePlatformGLContext(GrGLStandard forcedGpuAPI, SkGLContext* s
     hareContext) { |  | 
|  336     GLXGLContext* glxShareContext = reinterpret_cast<GLXGLContext*>(shareContext
     ); |  | 
|  337     GLXGLContext *ctx = new GLXGLContext(forcedGpuAPI, glxShareContext); |  | 
|  338     if (!ctx->isValid()) { |  | 
|  339         delete ctx; |  | 
|  340         return nullptr; |  | 
|  341     } |  | 
|  342     return ctx; |  | 
|  343 } |  | 
| OLD | NEW |