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 /* Note: Skia requires glx 1.3 or newer */ 13 14 SkNativeGLContext::AutoContextRestore::AutoContextRestore() { 15 fOldGLXContext = glXGetCurrentContext(); 16 fOldDisplay = glXGetCurrentDisplay(); 17 fOldDrawable = glXGetCurrentDrawable(); 18 } 19 20 SkNativeGLContext::AutoContextRestore::~AutoContextRestore() { 21 if (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(GrGLStandard forcedGpuAPI) { 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 int glx_major, glx_minor; 86 87 // FBConfigs were added in GLX version 1.3. 88 if (!glXQueryVersion(fDisplay, &glx_major, &glx_minor) || 89 ((glx_major == 1) && (glx_minor < 3)) || (glx_major < 1)) { 90 SkDebugf("GLX version 1.3 or higher required.\n"); 91 this->destroyGLContext(); 92 return NULL; 93 } 94 95 //SkDebugf("Getting matching framebuffer configs.\n"); 96 int fbcount; 97 GLXFBConfig *fbc = glXChooseFBConfig(fDisplay, DefaultScreen(fDisplay), 98 visual_attribs, &fbcount); 99 if (!fbc) { 100 SkDebugf("Failed to retrieve a framebuffer config.\n"); 101 this->destroyGLContext(); 102 return NULL; 103 } 104 //SkDebugf("Found %d matching FB configs.\n", fbcount); 105 106 // Pick the FB config/visual with the most samples per pixel 107 //SkDebugf("Getting XVisualInfos.\n"); 108 int best_fbc = -1, best_num_samp = -1; 109 110 int i; 111 for (i = 0; i < fbcount; ++i) { 112 XVisualInfo *vi = glXGetVisualFromFBConfig(fDisplay, fbc[i]); 113 if (vi) { 114 int samp_buf, samples; 115 glXGetFBConfigAttrib(fDisplay, fbc[i], GLX_SAMPLE_BUFFERS, &samp_buf); 116 glXGetFBConfigAttrib(fDisplay, fbc[i], GLX_SAMPLES, &samples); 117 118 //SkDebugf(" Matching fbconfig %d, visual ID 0x%2x: SAMPLE_BUFFERS = %d," 119 // " SAMPLES = %d\n", 120 // i, (unsigned int)vi->visualid, samp_buf, samples); 121 122 if (best_fbc < 0 || (samp_buf && samples > best_num_samp)) 123 best_fbc = i, best_num_samp = samples; 124 } 125 XFree(vi); 126 } 127 128 GLXFBConfig bestFbc = fbc[best_fbc]; 129 130 // Be sure to free the FBConfig list allocated by glXChooseFBConfig() 131 XFree(fbc); 132 133 // Get a visual 134 XVisualInfo *vi = glXGetVisualFromFBConfig(fDisplay, bestFbc); 135 //SkDebugf("Chosen visual ID = 0x%x\n", (unsigned int)vi->visualid); 136 137 fPixmap = XCreatePixmap(fDisplay, RootWindow(fDisplay, vi->screen), 10, 10, vi->depth); 138 139 if (!fPixmap) { 140 SkDebugf("Failed to create pixmap.\n"); 141 this->destroyGLContext(); 142 return NULL; 143 } 144 145 fGlxPixmap = glXCreateGLXPixmap(fDisplay, vi, fPixmap); 146 147 // Done with the visual info data 148 XFree(vi); 149 150 // Create the context 151 152 // Install an X error handler so the application won't exit if GL 3.0 153 // context allocation fails. 154 // 155 // Note this error handler is global. 156 // All display connections in all threads of a process use the same 157 // error handler, so be sure to guard against other threads issuing 158 // X commands while this code is running. 159 ctxErrorOccurred = false; 160 int (*oldHandler)(Display*, XErrorEvent*) = 161 XSetErrorHandler(&ctxErrorHandler); 162 163 // Get the default screen's GLX extension list 164 const char *glxExts = glXQueryExtensionsString( 165 fDisplay, DefaultScreen(fDisplay) 166 ); 167 168 169 // Check for the GLX_ARB_create_context extension string and the function. 170 // If either is not present, use GLX 1.3 context creation method. 171 if (!gluCheckExtension(reinterpret_cast<const GLubyte*>("GLX_ARB_create_context"), 172 reinterpret_cast<const GLubyte*>(glxExts))) { 173 if (kGLES_GrGLStandard != forcedGpuAPI) { 174 fContext = glXCreateNewContext(fDisplay, bestFbc, GLX_RGBA_TYPE, 0, True); 175 } 176 } else { 177 //SkDebugf("Creating context.\n"); 178 PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB = 179 (PFNGLXCREATECONTEXTATTRIBSARBPROC) glXGetProcAddressARB((GrGLubyte*)"glXCreateContextAttribsARB"); 180 181 if (kGLES_GrGLStandard == forcedGpuAPI) { 182 if (gluCheckExtension( 183 reinterpret_cast<const GLubyte*>("GLX_EXT_create_context_es2_profile"), 184 reinterpret_cast<const GLubyte*>(glxExts))) { 185 static const int context_attribs_gles[] = { 186 GLX_CONTEXT_MAJOR_VERSION_ARB, 3, 187 GLX_CONTEXT_MINOR_VERSION_ARB, 0, 188 GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_ES2_PROFILE_BIT_EXT, 189 None 190 }; 191 fContext = glXCreateContextAttribsARB(fDisplay, bestFbc, 0, True, 192 context_attribs_gles); 193 } 194 } else { 195 // Well, unfortunately GLX will not just give us the highest context so instead we have 196 // to do this nastiness 197 for (i = NUM_GL_VERSIONS - 2; i > 0 ; i--) { 198 /* don't bother below GL 3.0 */ 199 if (gl_versions[i].major == 3 && gl_versions[i].minor == 0) { 200 break; 201 } 202 // On Nvidia GPUs, to use Nv Path rendering we need a compatibility profile for the 203 // time being. 204 // TODO when Nvidia implements NVPR on Core profiles, we should start requesting 205 // core here 206 static const int context_attribs_gl[] = { 207 GLX_CONTEXT_MAJOR_VERSION_ARB, gl_versions[i].major, 208 GLX_CONTEXT_MINOR_VERSION_ARB, gl_versions[i].minor, 209 GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB, 210 None 211 }; 212 fContext = 213 glXCreateContextAttribsARB(fDisplay, bestFbc, 0, True, context_attribs_gl); 214 215 // Sync to ensure any errors generated are processed. 216 XSync(fDisplay, False); 217 218 if (!ctxErrorOccurred && fContext) { 219 break; 220 } 221 // try again 222 ctxErrorOccurred = false; 223 } 224 225 // Couldn't create GL 3.0 context. 226 // Fall back to old-style 2.x context. 227 // When a context version below 3.0 is requested, 228 // implementations will return the newest context version 229 // compatible with OpenGL versions less than version 3.0. 230 if (ctxErrorOccurred || !fContext) { 231 static const int context_attribs_gl_fallback[] = { 232 GLX_CONTEXT_MAJOR_VERSION_ARB, 1, 233 GLX_CONTEXT_MINOR_VERSION_ARB, 0, 234 None 235 }; 236 237 ctxErrorOccurred = false; 238 239 fContext = glXCreateContextAttribsARB(fDisplay, bestFbc, 0, True, 240 context_attribs_gl_fallback); 241 } 242 } 243 } 244 245 // Sync to ensure any errors generated are processed. 246 XSync(fDisplay, False); 247 248 // Restore the original error handler 249 XSetErrorHandler(oldHandler); 250 251 if (ctxErrorOccurred || !fContext) { 252 SkDebugf("Failed to create an OpenGL context.\n"); 253 this->destroyGLContext(); 254 return NULL; 255 } 256 257 // Verify that context is a direct context 258 if (!glXIsDirect(fDisplay, fContext)) { 259 //SkDebugf("Indirect GLX rendering context obtained.\n"); 260 } else { 261 //SkDebugf("Direct GLX rendering context obtained.\n"); 262 } 263 264 //SkDebugf("Making context current.\n"); 265 if (!glXMakeCurrent(fDisplay, fGlxPixmap, fContext)) { 266 SkDebugf("Could not set the context.\n"); 267 this->destroyGLContext(); 268 return NULL; 269 } 270 271 const GrGLInterface* interface = GrGLCreateNativeInterface(); 272 if (!interface) { 273 SkDebugf("Failed to create gl interface"); 274 this->destroyGLContext(); 275 return NULL; 276 } 277 return interface; 278 } 279 280 void SkNativeGLContext::makeCurrent() const { 281 if (!glXMakeCurrent(fDisplay, fGlxPixmap, fContext)) { 282 SkDebugf("Could not set the context.\n"); 283 } 284 } 285 286 void SkNativeGLContext::swapBuffers() const { 287 glXSwapBuffers(fDisplay, fGlxPixmap); 288 } 289