1 /* Cairo - a vector graphics library with display and print output
2 *
3 * Copyright © 2009 Chris Wilson
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it either under the terms of the GNU Lesser General Public
7 * License version 2.1 as published by the Free Software Foundation
8 * (the "LGPL") or, at your option, under the terms of the Mozilla
9 * Public License Version 1.1 (the "MPL"). If you do not alter this
10 * notice, a recipient may use your version of this file under either
11 * the MPL or the LGPL.
12 *
13 * You should have received a copy of the LGPL along with this library
14 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
16 * You should have received a copy of the MPL along with this library
17 * in the file COPYING-MPL-1.1
18 *
19 * The contents of this file are subject to the Mozilla Public License
20 * Version 1.1 (the "License"); you may not use this file except in
21 * compliance with the License. You may obtain a copy of the License at
22 * http://www.mozilla.org/MPL/
23 *
24 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
25 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
26 * the specific language governing rights and limitations.
27 *
28 * The Original Code is the cairo graphics library.
29 *
30 * The Initial Developer of the Original Code is Chris Wilson.
31 */
32
33 #include "cairo-boilerplate-private.h"
34
35 #include <cairo-vg.h>
36
37 /* XXX Not sure how to handle library specific context initialization */
38 //#define USE_SHIVA
39 //#define USE_AMANITH
40
41 #if CAIRO_HAS_GLX_FUNCTIONS
42
43 #include <X11/Xlib.h>
44 #include <GL/glx.h>
45
46 typedef struct _vg_closure {
47 Display *dpy;
48 int screen;
49 Window win;
50
51 GLXContext ctx;
52 cairo_surface_t *surface;
53 } vg_closure_glx_t;
54
55 static void
_cairo_boilerplate_vg_cleanup_glx(void * closure)56 _cairo_boilerplate_vg_cleanup_glx (void *closure)
57 {
58 vg_closure_glx_t *vgc = closure;
59
60 #ifdef USE_AMANITH
61 vgDestroyContextAM ();
62 #endif
63 #ifdef USE_SHIVA
64 vgDestroyContextSH ();
65 #endif
66
67 glXDestroyContext (vgc->dpy, vgc->ctx);
68 XDestroyWindow (vgc->dpy, vgc->win);
69 XCloseDisplay (vgc->dpy);
70 free (vgc);
71 }
72
73 static cairo_surface_t *
_cairo_boilerplate_vg_create_surface_glx(const char * name,cairo_content_t content,double width,double height,double max_width,double max_height,cairo_boilerplate_mode_t mode,void ** closure)74 _cairo_boilerplate_vg_create_surface_glx (const char *name,
75 cairo_content_t content,
76 double width,
77 double height,
78 double max_width,
79 double max_height,
80 cairo_boilerplate_mode_t mode,
81 void **closure)
82 {
83 int rgba_attribs[] = {
84 GLX_RGBA,
85 GLX_RED_SIZE, 1,
86 GLX_GREEN_SIZE, 1,
87 GLX_BLUE_SIZE, 1,
88 GLX_ALPHA_SIZE, 1,
89 GLX_DOUBLEBUFFER,
90 GLX_NONE
91 };
92 int rgb_attribs[] = {
93 GLX_RGBA,
94 GLX_RED_SIZE, 1,
95 GLX_GREEN_SIZE, 1,
96 GLX_BLUE_SIZE, 1,
97 GLX_DOUBLEBUFFER,
98 GLX_NONE
99 };
100 XVisualInfo *vi;
101 Display *dpy;
102 Colormap cmap;
103 XSetWindowAttributes swa;
104 cairo_surface_t *surface;
105 cairo_vg_context_t *context;
106 vg_closure_glx_t *vgc;
107
108 vgc = malloc (sizeof (vg_closure_glx_t));
109 *closure = vgc;
110
111 if (width == 0)
112 width = 1;
113 if (height == 0)
114 height = 1;
115
116 dpy = XOpenDisplay (NULL);
117 vgc->dpy = dpy;
118 if (vgc->dpy == NULL) {
119 fprintf (stderr, "Failed to open display: %s\n", XDisplayName(0));
120 free (vgc);
121 return NULL;
122 }
123
124 if (content == CAIRO_CONTENT_COLOR)
125 vi = glXChooseVisual (dpy, DefaultScreen (dpy), rgb_attribs);
126 else
127 vi = glXChooseVisual (dpy, DefaultScreen (dpy), rgba_attribs);
128
129 if (vi == NULL) {
130 fprintf (stderr, "Failed to create RGB, double-buffered visual\n");
131 XCloseDisplay (dpy);
132 free (vgc);
133 return NULL;
134 }
135
136 vgc->ctx = glXCreateContext (dpy, vi, NULL, True);
137 cmap = XCreateColormap (dpy,
138 RootWindow (dpy, vi->screen),
139 vi->visual,
140 AllocNone);
141 swa.colormap = cmap;
142 swa.border_pixel = 0;
143 vgc->win = XCreateWindow (dpy, RootWindow (dpy, vi->screen),
144 -1, -1, 1, 1, 0,
145 vi->depth,
146 InputOutput,
147 vi->visual,
148 CWBorderPixel | CWColormap, &swa);
149 XFreeColormap (dpy, cmap);
150 XFree (vi);
151
152 XMapWindow (dpy, vgc->win);
153
154 /* we need an active context to initialise VG */
155 glXMakeContextCurrent (dpy, vgc->win, vgc->win, vgc->ctx);
156
157 #ifdef USE_AMANITH
158 vgInitContextAM (width, height, VG_FALSE, VG_TRUE);
159 #endif
160 #ifdef USE_SHIVA
161 vgCreateContextSH (width, height);
162 #endif
163
164 context = cairo_vg_context_create_for_glx (dpy, vgc->ctx);
165 vgc->surface = cairo_vg_surface_create (context, content, width, height);
166 cairo_vg_context_destroy (context);
167
168 surface = vgc->surface;
169 if (cairo_surface_status (surface))
170 _cairo_boilerplate_vg_cleanup_glx (vgc);
171
172 return surface;
173 }
174 #endif
175
176 #if CAIRO_HAS_EGL_FUNCTIONS
177 typedef struct _vg_closure_egl {
178 EGLDisplay *dpy;
179 EGLContext *ctx;
180 EGLSurface *dummy;
181 } vg_closure_egl_t;
182
183 static void
_cairo_boilerplate_vg_cleanup_egl(void * closure)184 _cairo_boilerplate_vg_cleanup_egl (void *closure)
185 {
186 vg_closure_egl_t *vgc = closure;
187
188 #ifdef USE_AMANITH
189 vgDestroyContextAM ();
190 #endif
191 #ifdef USE_SHIVA
192 vgDestroyContextSH ();
193 #endif
194
195 eglDestroyContext (vgc->dpy, vgc->ctx);
196 eglDestroySurface (vgc->dpy, vgc->dummy);
197 eglTerminate (vgc->dpy);
198 free (vgc);
199 }
200
201 static cairo_surface_t *
_cairo_boilerplate_vg_create_surface_egl(const char * name,cairo_content_t content,double width,double height,double max_width,double max_height,cairo_boilerplate_mode_t mode,void ** closure)202 _cairo_boilerplate_vg_create_surface_egl (const char *name,
203 cairo_content_t content,
204 double width,
205 double height,
206 double max_width,
207 double max_height,
208 cairo_boilerplate_mode_t mode,
209 void **closure)
210 {
211 int rgba_attribs[] = {
212 EGL_RED_SIZE, 8,
213 EGL_GREEN_SIZE, 8,
214 EGL_BLUE_SIZE, 8,
215 EGL_ALPHA_SIZE, 8,
216 EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
217 EGL_RENDERABLE_TYPE, EGL_OPENVG_BIT,
218 EGL_NONE
219 };
220 int rgb_attribs[] = {
221 EGL_RED_SIZE, 8,
222 EGL_GREEN_SIZE, 8,
223 EGL_BLUE_SIZE, 8,
224 EGL_ALPHA_SIZE, 8,
225 EGL_VG_ALPHA_FORMAT, EGL_VG_ALPHA_FORMAT_PRE_BIT,
226 EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
227 EGL_RENDERABLE_TYPE, EGL_OPENVG_BIT,
228 EGL_NONE
229 };
230 int dummy_attribs[] = {
231 EGL_WIDTH, 8, EGL_HEIGHT, 8,
232 EGL_NONE
233 };
234 EGLDisplay *dpy;
235 int major, minor;
236 EGLConfig config;
237 int num_configs;
238 EGLContext *egl_context;
239 EGLSurface *dummy;
240 cairo_vg_context_t *context;
241 cairo_surface_t *surface;
242 vg_closure_egl_t *vgc;
243
244 dpy = eglGetDisplay (EGL_DEFAULT_DISPLAY);
245
246 if (! eglInitialize (dpy, &major, &minor))
247 return NULL;
248
249 eglBindAPI (EGL_OPENVG_API);
250
251 if (! eglChooseConfig (dpy,
252 content == CAIRO_CONTENT_COLOR_ALPHA ?
253 rgba_attribs : rgb_attribs,
254 &config, 1, &num_configs) ||
255 num_configs != 1)
256 {
257 return NULL;
258 }
259
260 egl_context = eglCreateContext (dpy, config, NULL, NULL);
261 if (egl_context == NULL)
262 return NULL;
263
264 /* Create a dummy surface in order to enable a context to initialise VG */
265 dummy = eglCreatePbufferSurface (dpy, config, dummy_attribs);
266 if (dummy == NULL)
267 return NULL;
268 if (! eglMakeCurrent (dpy, dummy, dummy, egl_context))
269 return NULL;
270
271 #ifdef USE_AMANITH
272 vgInitContextAM (width, height, VG_FALSE, VG_TRUE);
273 #endif
274 #ifdef USE_SHIVA
275 vgCreateContextSH (width, height);
276 #endif
277
278 vgc = xmalloc (sizeof (vg_closure_egl_t));
279 vgc->dpy = dpy;
280 vgc->ctx = egl_context;
281 vgc->dummy = dummy;
282 *closure = vgc;
283
284 context = cairo_vg_context_create_for_egl (vgc->dpy, vgc->ctx);
285 surface = cairo_vg_surface_create (context, content, width, height);
286 cairo_vg_context_destroy (context);
287
288 if (cairo_surface_status (surface))
289 _cairo_boilerplate_vg_cleanup_egl (vgc);
290
291 return surface;
292 }
293 #endif
294
295 static void
_cairo_boilerplate_vg_synchronize(void * closure)296 _cairo_boilerplate_vg_synchronize (void *closure)
297 {
298 vgFinish ();
299 }
300
301 static const cairo_boilerplate_target_t targets[] = {
302 #if CAIRO_HAS_GLX_FUNCTIONS
303 {
304 "vg-glx", "vg", NULL, NULL,
305 CAIRO_SURFACE_TYPE_VG, CAIRO_CONTENT_COLOR_ALPHA, 1,
306 "cairo_vg_context_create_for_glx",
307 _cairo_boilerplate_vg_create_surface_glx,
308 cairo_surface_create_similar,
309 NULL, NULL,
310 _cairo_boilerplate_get_image_surface,
311 cairo_surface_write_to_png,
312 _cairo_boilerplate_vg_cleanup_glx,
313 _cairo_boilerplate_vg_synchronize,
314 NULL,
315 TRUE, FALSE, FALSE
316 },
317 {
318 "vg-glx", "vg", NULL, NULL,
319 CAIRO_SURFACE_TYPE_VG, CAIRO_CONTENT_COLOR, 1,
320 "cairo_vg_context_create_for_glx",
321 _cairo_boilerplate_vg_create_surface_glx,
322 cairo_surface_create_similar,
323 NULL, NULL,
324 _cairo_boilerplate_get_image_surface,
325 cairo_surface_write_to_png,
326 _cairo_boilerplate_vg_cleanup_glx,
327 _cairo_boilerplate_vg_synchronize,
328 NULL,
329 FALSE, FALSE, FALSE
330 },
331 #endif
332 #if CAIRO_HAS_EGL_FUNCTIONS
333 {
334 "vg-egl", "vg", NULL, NULL,
335 CAIRO_SURFACE_TYPE_VG, CAIRO_CONTENT_COLOR_ALPHA, 1,
336 "cairo_vg_context_create_for_egl",
337 _cairo_boilerplate_vg_create_surface_egl,
338 cairo_surface_create_similar,
339 NULL, NULL,
340 _cairo_boilerplate_get_image_surface,
341 cairo_surface_write_to_png,
342 _cairo_boilerplate_vg_cleanup_egl,
343 _cairo_boilerplate_vg_synchronize,
344 NULL,
345 TRUE, FALSE, FALSE
346 },
347 {
348 "vg-egl", "vg", NULL, NULL,
349 CAIRO_SURFACE_TYPE_VG, CAIRO_CONTENT_COLOR, 1,
350 "cairo_vg_context_create_for_egl",
351 _cairo_boilerplate_vg_create_surface_egl,
352 cairo_surface_create_similar,
353 NULL, NULL,
354 _cairo_boilerplate_get_image_surface,
355 cairo_surface_write_to_png,
356 _cairo_boilerplate_vg_cleanup_egl,
357 _cairo_boilerplate_vg_synchronize,
358 NULL,
359 FALSE, FALSE, FALSE
360 },
361 #endif
362 };
363 CAIRO_BOILERPLATE (vg, targets)
364