OLD | NEW |
| (Empty) |
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 forcedGpuAP
I) { | |
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_cont
ext"), | |
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_EX
T, | |
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 compatibil
ity 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_PR
OFILE_BIT_ARB, | |
210 None | |
211 }; | |
212 fContext = | |
213 glXCreateContextAttribsARB(fDisplay, bestFbc, 0, True, c
ontext_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_fallbac
k); | |
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 } | |
OLD | NEW |