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