blob: 6eb7e35534af6066af1e9010a4edc61a8957ab11 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +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 */
bungeman@google.com16bab872011-05-17 14:24:46 +00008#include "SkEGLContext.h"
9#include "SkTypes.h"
10
11#include <GL/gl.h>
12#include <GL/glext.h>
13#include <GL/glu.h>
14#include <GL/glx.h>
15#include <X11/Xlib.h>
16
17#define SK_GL_GET_PROC(T, F) T F = NULL; \
18 F = (T) glXGetProcAddressARB(reinterpret_cast<const GLubyte*>(#F));
19
20static bool ctxErrorOccurred = false;
21static int ctxErrorHandler(Display *dpy, XErrorEvent *ev) {
22 ctxErrorOccurred = true;
23 return 0;
24}
25
26SkEGLContext::SkEGLContext() : context(NULL), display(NULL), pixmap(0), glxPixmap(0) {
27}
28
29SkEGLContext::~SkEGLContext() {
30 if (this->display) {
31 glXMakeCurrent(this->display, 0, 0);
32
33 if (this->context)
34 glXDestroyContext(this->display, this->context);
35
36 if (this->glxPixmap)
37 glXDestroyGLXPixmap(this->display, this->glxPixmap);
38
39 if (this->pixmap)
40 XFreePixmap(this->display, this->pixmap);
41
42 XCloseDisplay(this->display);
43 }
44}
45
46bool SkEGLContext::init(const int width, const int height) {
47 Display *display = XOpenDisplay(0);
48 this->display = display;
49
50 if (!display) {
51 SkDebugf("Failed to open X display.\n");
52 return false;
53 }
54
55 // Get a matching FB config
56 static int visual_attribs[] = {
57 GLX_X_RENDERABLE , True,
58 GLX_DRAWABLE_TYPE , GLX_PIXMAP_BIT,
59 GLX_RENDER_TYPE , GLX_RGBA_BIT,
60 GLX_X_VISUAL_TYPE , GLX_TRUE_COLOR,
61 GLX_RED_SIZE , 8,
62 GLX_GREEN_SIZE , 8,
63 GLX_BLUE_SIZE , 8,
64 GLX_ALPHA_SIZE , 8,
65 GLX_DEPTH_SIZE , 24,
66 GLX_STENCIL_SIZE , 8,
67 GLX_DOUBLEBUFFER , True,
68 //GLX_SAMPLE_BUFFERS , 1,
69 //GLX_SAMPLES , 4,
70 None
71 };
72
73 int glx_major, glx_minor;
74
75 // FBConfigs were added in GLX version 1.3.
76 if (!glXQueryVersion( display, &glx_major, &glx_minor) ||
77 ( (glx_major == 1) && (glx_minor < 3) ) || (glx_major < 1))
78 {
79 SkDebugf("Invalid GLX version.");
80 return false;
81 }
82
83 //SkDebugf("Getting matching framebuffer configs.\n");
84 int fbcount;
85 GLXFBConfig *fbc = glXChooseFBConfig(display, DefaultScreen(display),
86 visual_attribs, &fbcount);
87 if (!fbc) {
88 SkDebugf("Failed to retrieve a framebuffer config.\n");
89 return false;
90 }
91 //SkDebugf("Found %d matching FB configs.\n", fbcount);
92
93 // Pick the FB config/visual with the most samples per pixel
94 //SkDebugf("Getting XVisualInfos.\n");
95 int best_fbc = -1, worst_fbc = -1, best_num_samp = -1, worst_num_samp = 999;
96
97 int i;
98 for (i = 0; i < fbcount; ++i) {
99 XVisualInfo *vi = glXGetVisualFromFBConfig(display, fbc[i]);
100 if (vi) {
101 int samp_buf, samples;
102 glXGetFBConfigAttrib(display, fbc[i], GLX_SAMPLE_BUFFERS, &samp_buf);
103 glXGetFBConfigAttrib(display, fbc[i], GLX_SAMPLES, &samples);
104
105 //SkDebugf(" Matching fbconfig %d, visual ID 0x%2x: SAMPLE_BUFFERS = %d,"
106 // " SAMPLES = %d\n",
107 // i, (unsigned int)vi->visualid, samp_buf, samples);
108
109 if (best_fbc < 0 || (samp_buf && samples > best_num_samp))
110 best_fbc = i, best_num_samp = samples;
111 if (worst_fbc < 0 || !samp_buf || samples < worst_num_samp)
112 worst_fbc = i, worst_num_samp = samples;
113 }
114 XFree(vi);
115 }
116
117 GLXFBConfig bestFbc = fbc[best_fbc];
118
119 // Be sure to free the FBConfig list allocated by glXChooseFBConfig()
120 XFree(fbc);
121
122 // Get a visual
123 XVisualInfo *vi = glXGetVisualFromFBConfig(display, bestFbc);
124 //SkDebugf("Chosen visual ID = 0x%x\n", (unsigned int)vi->visualid);
125
126 Pixmap pixmap = XCreatePixmap(
127 display, RootWindow(display, vi->screen), width, height, vi->depth
128 );
129
130 this->pixmap = pixmap;
131 if (!pixmap) {
132 SkDebugf("Failed to create pixmap.\n");
133 return false;
134 }
135
136 GLXPixmap glxPixmap = glXCreateGLXPixmap(display, vi, pixmap);
137 this->glxPixmap = glxPixmap;
138
139 // Done with the visual info data
140 XFree(vi);
141
142 // Create the context
143 GLXContext ctx = 0;
144
145 // Install an X error handler so the application won't exit if GL 3.0
146 // context allocation fails.
147 //
148 // Note this error handler is global.
149 // All display connections in all threads of a process use the same
150 // error handler, so be sure to guard against other threads issuing
151 // X commands while this code is running.
152 ctxErrorOccurred = false;
153 int (*oldHandler)(Display*, XErrorEvent*) =
154 XSetErrorHandler(&ctxErrorHandler);
155
156 // Get the default screen's GLX extension list
157 const char *glxExts = glXQueryExtensionsString(
158 display, DefaultScreen(display)
159 );
160 // Check for the GLX_ARB_create_context extension string and the function.
161 // If either is not present, use GLX 1.3 context creation method.
162 if (!gluCheckExtension(
163 reinterpret_cast<const GLubyte*>("GLX_ARB_create_context")
164 , reinterpret_cast<const GLubyte*>(glxExts)))
165 {
166 //SkDebugf("GLX_ARB_create_context not found."
167 // " Using old-style GLX context.\n");
168 ctx = glXCreateNewContext(display, bestFbc, GLX_RGBA_TYPE, 0, True);
169
170 } else {
171 //SkDebugf("Creating context.\n");
172
173 SK_GL_GET_PROC(PFNGLXCREATECONTEXTATTRIBSARBPROC, glXCreateContextAttribsARB)
174 int context_attribs[] = {
175 GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
176 GLX_CONTEXT_MINOR_VERSION_ARB, 0,
177 //GLX_CONTEXT_FLAGS_ARB , GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
178 None
179 };
180 ctx = glXCreateContextAttribsARB(
181 display, bestFbc, 0, True, context_attribs
182 );
183
184 // Sync to ensure any errors generated are processed.
185 XSync(display, False);
186 if (!ctxErrorOccurred && ctx) {
187 //SkDebugf( "Created GL 3.0 context.\n" );
188 } else {
189 // Couldn't create GL 3.0 context.
190 // Fall back to old-style 2.x context.
191 // When a context version below 3.0 is requested,
192 // implementations will return the newest context version compatible
193 // with OpenGL versions less than version 3.0.
194
195 // GLX_CONTEXT_MAJOR_VERSION_ARB = 1
196 context_attribs[1] = 1;
197 // GLX_CONTEXT_MINOR_VERSION_ARB = 0
198 context_attribs[3] = 0;
199
200 ctxErrorOccurred = false;
201
202 //SkDebugf("Failed to create GL 3.0 context."
203 // " Using old-style GLX context.\n");
204 ctx = glXCreateContextAttribsARB(
205 display, bestFbc, 0, True, context_attribs
206 );
207 }
208 }
209
210 // Sync to ensure any errors generated are processed.
211 XSync(display, False);
212
213 // Restore the original error handler
214 XSetErrorHandler(oldHandler);
215
216 if (ctxErrorOccurred || !ctx) {
217 SkDebugf("Failed to create an OpenGL context.\n");
218 return false;
219 }
220 this->context = ctx;
221
222 // Verify that context is a direct context
223 if (!glXIsDirect(display, ctx)) {
224 //SkDebugf("Indirect GLX rendering context obtained.\n");
225 } else {
226 //SkDebugf("Direct GLX rendering context obtained.\n");
227 }
228
229 //SkDebugf("Making context current.\n");
230 if (!glXMakeCurrent(display, glxPixmap, ctx)) {
231 SkDebugf("Could not set the context.\n");
232 return false;
233 }
234
235 //Setup the framebuffers
236 const GLubyte* glExts = glGetString(GL_EXTENSIONS);
237 if (!gluCheckExtension(
238 reinterpret_cast<const GLubyte*>("GL_EXT_framebuffer_object")
239 , glExts))
240 {
241 SkDebugf("GL_EXT_framebuffer_object not found.\n");
242 return false;
243 }
244 SK_GL_GET_PROC(PFNGLGENFRAMEBUFFERSEXTPROC, glGenFramebuffersEXT)
245 SK_GL_GET_PROC(PFNGLBINDFRAMEBUFFEREXTPROC, glBindFramebufferEXT)
246 SK_GL_GET_PROC(PFNGLGENRENDERBUFFERSPROC, glGenRenderbuffersEXT)
247 SK_GL_GET_PROC(PFNGLBINDRENDERBUFFERPROC, glBindRenderbufferEXT)
248 SK_GL_GET_PROC(PFNGLRENDERBUFFERSTORAGEPROC, glRenderbufferStorageEXT)
249 SK_GL_GET_PROC(PFNGLFRAMEBUFFERRENDERBUFFERPROC, glFramebufferRenderbufferEXT)
250 SK_GL_GET_PROC(PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC, glCheckFramebufferStatusEXT)
251
252 GLuint fboID;
253 GLuint cbID;
254 GLuint dsID;
255 glGenFramebuffersEXT(1, &fboID);
256 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fboID);
257 glGenRenderbuffersEXT(1, &cbID);
258 glBindRenderbufferEXT(GL_RENDERBUFFER, cbID);
259 glRenderbufferStorageEXT(GL_RENDERBUFFER, GL_RGBA, width, height);
260 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, cbID);
261 glGenRenderbuffersEXT(1, &dsID);
262 glBindRenderbufferEXT(GL_RENDERBUFFER, dsID);
263 glRenderbufferStorageEXT(GL_RENDERBUFFER, GL_DEPTH_STENCIL, width, height);
264 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, dsID);
265 glViewport(0, 0, width, height);
266 glClearStencil(0);
267 glClear(GL_STENCIL_BUFFER_BIT);
268
269 GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER);
270 return GL_FRAMEBUFFER_COMPLETE == status;
271}