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