blob: 907e2b8238d6d8c2fe7c1639a41f6b94d2b46c74 [file] [log] [blame]
bsalomon@google.com373a6632011-10-19 20:43:20 +00001
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 "SkNativeGLContext.h"
9
10#include <GL/glu.h>
11
bsalomon@google.com57f5d982011-10-24 21:17:53 +000012SkNativeGLContext::AutoContextRestore::AutoContextRestore() {
13 fOldGLXContext = glXGetCurrentContext();
14 fOldDisplay = glXGetCurrentDisplay();
15 fOldDrawable = glXGetCurrentDrawable();
16}
17
18SkNativeGLContext::AutoContextRestore::~AutoContextRestore() {
19 if (NULL != fOldDisplay) {
20 glXMakeCurrent(fOldDisplay, fOldDrawable, fOldGLXContext);
21 }
22}
23
24///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com373a6632011-10-19 20:43:20 +000025
26static bool ctxErrorOccurred = false;
27static int ctxErrorHandler(Display *dpy, XErrorEvent *ev) {
28 ctxErrorOccurred = true;
29 return 0;
30}
31
32SkNativeGLContext::SkNativeGLContext()
33 : fContext(NULL)
34 , fDisplay(NULL)
35 , fPixmap(0)
36 , fGlxPixmap(0) {
37}
38
39SkNativeGLContext::~SkNativeGLContext() {
40 this->destroyGLContext();
41}
42
43void 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
67const 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
254void SkNativeGLContext::makeCurrent() const {
255 if (!glXMakeCurrent(fDisplay, fGlxPixmap, fContext)) {
256 SkDebugf("Could not set the context.\n");
257 }
258}