tizen 2.3.1 release
[framework/graphics/cairo.git] / src / cairo-gl-dispatch.c
1 /* cairo - a vector graphics library with display and print output
2  *
3  * Copyright © 2010 Linaro Limited
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  * Contributor(s):
29  *      Alexandros Frantzis <alexandros.frantzis@linaro.org>
30  */
31
32 #include "cairoint.h"
33 #include "cairo-gl-private.h"
34 #include "cairo-gl-dispatch-private.h"
35 #if CAIRO_HAS_DLSYM
36 #include <dlfcn.h>
37 #endif
38
39 #if CAIRO_HAS_DLSYM
40 static void *
41 _cairo_gl_dispatch_open_lib (void)
42 {
43     return dlopen (NULL, RTLD_LAZY);
44 }
45
46 static void
47 _cairo_gl_dispatch_close_lib (void *handle)
48 {
49     dlclose (handle);
50 }
51
52 static cairo_gl_generic_func_t
53 _cairo_gl_dispatch_get_proc_addr (void *handle, const char *name)
54 {
55     return (cairo_gl_generic_func_t) dlsym (handle, name);
56 }
57 #else
58 static void *
59 _cairo_gl_dispatch_open_lib (void)
60 {
61     return NULL;
62 }
63
64 static void
65 _cairo_gl_dispatch_close_lib (void *handle)
66 {
67     return;
68 }
69
70 static cairo_gl_generic_func_t
71 _cairo_gl_dispatch_get_proc_addr (void *handle, const char *name)
72 {
73     return NULL;
74 }
75 #endif /* CAIRO_HAS_DLSYM */
76
77
78 static void
79 _cairo_gl_dispatch_init_entries (cairo_gl_dispatch_t *dispatch,
80                                  cairo_gl_get_proc_addr_func_t get_proc_addr,
81                                  void *data,
82                                  cairo_gl_dispatch_entry_t *entries,
83                                  cairo_gl_dispatch_name_t dispatch_name)
84 {
85     cairo_gl_dispatch_entry_t *entry = entries;
86     void *handle = _cairo_gl_dispatch_open_lib ();
87
88     while (entry->name[CAIRO_GL_DISPATCH_NAME_CORE] != NULL) {
89         void *dispatch_ptr = &((char *) dispatch)[entry->offset];
90         const char *name = entry->name[dispatch_name];
91
92         /*
93          * In strictly conforming EGL implementations, eglGetProcAddress() can
94          * be used only to get extension functions, but some of the functions
95          * we want belong to core GL(ES). If the *GetProcAddress function
96          * provided by the context fails, try to get the address of the wanted
97          * GL function using standard system facilities (eg dlsym() in *nix
98          * systems).
99          */
100         cairo_gl_generic_func_t func = get_proc_addr (data, name);
101         if (func == NULL)
102             func = _cairo_gl_dispatch_get_proc_addr (handle, name);
103         *((cairo_gl_generic_func_t *) dispatch_ptr) = func;
104
105         ++entry;
106     }
107
108     _cairo_gl_dispatch_close_lib (handle);
109 }
110
111 static cairo_status_t
112 _cairo_gl_dispatch_init_buffers (cairo_gl_dispatch_t *dispatch,
113                                  cairo_gl_get_proc_addr_func_t get_proc_addr,
114                                  void *data,
115                                  int gl_version, cairo_gl_flavor_t gl_flavor)
116 {
117     cairo_gl_dispatch_name_t dispatch_name;
118
119     if (gl_flavor == CAIRO_GL_FLAVOR_DESKTOP)
120     {
121         if (gl_version >= CAIRO_GL_VERSION_ENCODE (1, 5))
122             dispatch_name = CAIRO_GL_DISPATCH_NAME_CORE;
123         else if (_cairo_gl_has_extension (dispatch, "GL_ARB_vertex_buffer_object"))
124             dispatch_name = CAIRO_GL_DISPATCH_NAME_EXT;
125         else
126             return CAIRO_STATUS_DEVICE_ERROR;
127     }
128     else if (gl_flavor == CAIRO_GL_FLAVOR_ES3)
129     {
130         dispatch_name = CAIRO_GL_DISPATCH_NAME_CORE;
131     }
132     else if (gl_flavor == CAIRO_GL_FLAVOR_ES2 &&
133              gl_version >= CAIRO_GL_VERSION_ENCODE (2, 0))
134     {
135         dispatch_name = CAIRO_GL_DISPATCH_NAME_ES;
136     }
137     else
138     {
139         return CAIRO_STATUS_DEVICE_ERROR;
140     }
141
142     _cairo_gl_dispatch_init_entries (dispatch, get_proc_addr, data,
143                                      dispatch_buffers_entries, dispatch_name);
144
145     return CAIRO_STATUS_SUCCESS;
146 }
147
148 static void
149 _cairo_gl_dispatch_init_core (cairo_gl_dispatch_t *dispatch,
150                               cairo_gl_get_proc_addr_func_t get_proc_addr,
151                               void *data)
152 {
153     cairo_gl_dispatch_name_t dispatch_name = CAIRO_GL_DISPATCH_NAME_CORE;
154
155     _cairo_gl_dispatch_init_entries (dispatch, get_proc_addr, data,
156                                      dispatch_core_entries, dispatch_name);
157
158 }
159
160 static cairo_status_t
161 _cairo_gl_dispatch_init_shaders (cairo_gl_dispatch_t *dispatch,
162                                  cairo_gl_get_proc_addr_func_t get_proc_addr,
163                                  void *data,
164                                  int gl_version, cairo_gl_flavor_t gl_flavor)
165 {
166     cairo_gl_dispatch_name_t dispatch_name;
167
168     if (gl_flavor == CAIRO_GL_FLAVOR_DESKTOP)
169     {
170         if (gl_version >= CAIRO_GL_VERSION_ENCODE (2, 0))
171             dispatch_name = CAIRO_GL_DISPATCH_NAME_CORE;
172         else if (_cairo_gl_has_extension (dispatch, "GL_ARB_shader_objects"))
173             dispatch_name = CAIRO_GL_DISPATCH_NAME_EXT;
174         else
175             return CAIRO_STATUS_DEVICE_ERROR;
176     }
177     else if (gl_flavor == CAIRO_GL_FLAVOR_ES3)
178     {
179         dispatch_name = CAIRO_GL_DISPATCH_NAME_CORE;
180     }
181     else if (gl_flavor == CAIRO_GL_FLAVOR_ES2 &&
182              gl_version >= CAIRO_GL_VERSION_ENCODE (2, 0))
183     {
184         dispatch_name = CAIRO_GL_DISPATCH_NAME_ES;
185     }
186     else
187     {
188         return CAIRO_STATUS_DEVICE_ERROR;
189     }
190
191     _cairo_gl_dispatch_init_entries (dispatch, get_proc_addr, data,
192                                      dispatch_shaders_entries, dispatch_name);
193
194     return CAIRO_STATUS_SUCCESS;
195 }
196
197 static cairo_status_t
198 _cairo_gl_dispatch_init_fbo (cairo_gl_dispatch_t *dispatch,
199                              cairo_gl_get_proc_addr_func_t get_proc_addr,
200                              void *data,
201                              int gl_version, cairo_gl_flavor_t gl_flavor)
202 {
203     cairo_gl_dispatch_name_t dispatch_name;
204
205     if (gl_flavor == CAIRO_GL_FLAVOR_DESKTOP)
206     {
207         if (gl_version >= CAIRO_GL_VERSION_ENCODE (3, 0) ||
208             _cairo_gl_has_extension (dispatch, "GL_ARB_framebuffer_object"))
209             dispatch_name = CAIRO_GL_DISPATCH_NAME_CORE;
210         else if (_cairo_gl_has_extension (dispatch, "GL_EXT_framebuffer_object"))
211             dispatch_name = CAIRO_GL_DISPATCH_NAME_EXT;
212         else
213             return CAIRO_STATUS_DEVICE_ERROR;
214     }
215     else if (gl_flavor == CAIRO_GL_FLAVOR_ES3)
216     {
217         dispatch_name = CAIRO_GL_DISPATCH_NAME_CORE;
218     }
219     else if (gl_flavor == CAIRO_GL_FLAVOR_ES2 &&
220              gl_version >= CAIRO_GL_VERSION_ENCODE (2, 0))
221     {
222         dispatch_name = CAIRO_GL_DISPATCH_NAME_ES;
223     }
224     else
225     {
226         return CAIRO_STATUS_DEVICE_ERROR;
227     }
228
229     _cairo_gl_dispatch_init_entries (dispatch, get_proc_addr, data,
230                                      dispatch_fbo_entries, dispatch_name);
231
232     return CAIRO_STATUS_SUCCESS;
233 }
234
235 static cairo_status_t
236 _cairo_gl_dispatch_init_multisampling (cairo_gl_dispatch_t *dispatch,
237                                        cairo_gl_get_proc_addr_func_t get_proc_addr,
238                                        void *data, int gl_version,
239                                        cairo_gl_flavor_t gl_flavor)
240 {
241     /* For the multisampling table, there are two GLES versions of the
242      * extension, so we put one in the EXT slot and one in the real ES slot.*/
243     cairo_gl_dispatch_name_t dispatch_name = CAIRO_GL_DISPATCH_NAME_CORE;
244     if (gl_flavor == CAIRO_GL_FLAVOR_ES2) {
245         if (_cairo_gl_has_extension (dispatch, "GL_EXT_multisampled_render_to_texture"))
246             dispatch_name = CAIRO_GL_DISPATCH_NAME_EXT;
247         else if (_cairo_gl_has_extension (dispatch, "GL_IMG_multisampled_render_to_texture"))
248             dispatch_name = CAIRO_GL_DISPATCH_NAME_ES;
249         else if (_cairo_gl_has_extension (dispatch, "GL_ANGLE_framebuffer_multisample") &&
250                  _cairo_gl_has_extension (dispatch, "GL_ANGLE_framebuffer_blit"))
251             dispatch_name = CAIRO_GL_DISPATCH_NAME_CORE;
252     }
253
254     _cairo_gl_dispatch_init_entries (dispatch, get_proc_addr, data,
255                                      dispatch_multisampling_entries,
256                                      dispatch_name);
257
258     return CAIRO_STATUS_SUCCESS;
259 }
260
261 cairo_status_t
262 _cairo_gl_dispatch_init (cairo_gl_dispatch_t *dispatch,
263                          cairo_gl_get_proc_addr_func_t get_proc_addr,
264                          void *data)
265 {
266     cairo_status_t status;
267     int gl_version;
268     cairo_gl_flavor_t gl_flavor;
269
270     _cairo_gl_dispatch_init_core (dispatch, get_proc_addr, data);
271     gl_version = _cairo_gl_get_version (dispatch);
272     gl_flavor = _cairo_gl_get_flavor (dispatch);
273
274
275     status = _cairo_gl_dispatch_init_buffers (dispatch, get_proc_addr, data,
276                                               gl_version, gl_flavor);
277     if (status != CAIRO_STATUS_SUCCESS)
278         return status;
279
280     status = _cairo_gl_dispatch_init_shaders (dispatch, get_proc_addr, data,
281                                               gl_version, gl_flavor);
282     if (status != CAIRO_STATUS_SUCCESS)
283         return status;
284
285     status = _cairo_gl_dispatch_init_fbo (dispatch, get_proc_addr, data,
286                                           gl_version, gl_flavor);
287     if (status != CAIRO_STATUS_SUCCESS)
288         return status;
289
290     status = _cairo_gl_dispatch_init_multisampling (dispatch, get_proc_addr,
291                                                     data, gl_version, gl_flavor);
292     if (status != CAIRO_STATUS_SUCCESS)
293         return status;
294
295     return CAIRO_STATUS_SUCCESS;
296 }