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