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