Tizen 2.0 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                                  cairo_gl_dispatch_entry_t *entries,
82                                  cairo_gl_dispatch_name_t dispatch_name)
83 {
84     cairo_gl_dispatch_entry_t *entry = entries;
85     void *handle = _cairo_gl_dispatch_open_lib ();
86
87     while (entry->name[CAIRO_GL_DISPATCH_NAME_CORE] != NULL) {
88         void *dispatch_ptr = &((char *) dispatch)[entry->offset];
89         const char *name = entry->name[dispatch_name];
90
91         /*
92          * In strictly conforming EGL implementations, eglGetProcAddress() can
93          * be used only to get extension functions, but some of the functions
94          * we want belong to core GL(ES). If the *GetProcAddress function
95          * provided by the context fails, try to get the address of the wanted
96          * GL function using standard system facilities (eg dlsym() in *nix
97          * systems).
98          */
99         cairo_gl_generic_func_t func = get_proc_addr (name);
100         if (func == NULL)
101             func = _cairo_gl_dispatch_get_proc_addr (handle, name);
102
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                                  int gl_version, cairo_gl_flavor_t gl_flavor)
115 {
116     cairo_gl_dispatch_name_t dispatch_name;
117
118     if (gl_flavor == CAIRO_GL_FLAVOR_DESKTOP)
119     {
120         if (gl_version >= CAIRO_GL_VERSION_ENCODE (1, 5))
121             dispatch_name = CAIRO_GL_DISPATCH_NAME_CORE;
122         else if (_cairo_gl_has_extension ("GL_ARB_vertex_buffer_object"))
123             dispatch_name = CAIRO_GL_DISPATCH_NAME_EXT;
124         else
125             return CAIRO_STATUS_DEVICE_ERROR;
126     }
127     else if (gl_flavor == CAIRO_GL_FLAVOR_ES &&
128              gl_version >= CAIRO_GL_VERSION_ENCODE (2, 0))
129     {
130         dispatch_name = CAIRO_GL_DISPATCH_NAME_ES;
131     }
132     else
133     {
134         return CAIRO_STATUS_DEVICE_ERROR;
135     }
136
137     _cairo_gl_dispatch_init_entries (dispatch, get_proc_addr,
138                                      dispatch_buffers_entries, dispatch_name);
139
140     return CAIRO_STATUS_SUCCESS;
141 }
142
143 static cairo_status_t
144 _cairo_gl_dispatch_init_shaders (cairo_gl_dispatch_t *dispatch,
145                                  cairo_gl_get_proc_addr_func_t get_proc_addr,
146                                  int gl_version, cairo_gl_flavor_t gl_flavor)
147 {
148     cairo_gl_dispatch_name_t dispatch_name;
149
150     if (gl_flavor == CAIRO_GL_FLAVOR_DESKTOP)
151     {
152         if (gl_version >= CAIRO_GL_VERSION_ENCODE (2, 0))
153             dispatch_name = CAIRO_GL_DISPATCH_NAME_CORE;
154         else if (_cairo_gl_has_extension ("GL_ARB_shader_objects"))
155             dispatch_name = CAIRO_GL_DISPATCH_NAME_EXT;
156         else
157             return CAIRO_STATUS_DEVICE_ERROR;
158     }
159     else if (gl_flavor == CAIRO_GL_FLAVOR_ES &&
160              gl_version >= CAIRO_GL_VERSION_ENCODE (2, 0))
161     {
162         dispatch_name = CAIRO_GL_DISPATCH_NAME_ES;
163     }
164     else
165     {
166         return CAIRO_STATUS_DEVICE_ERROR;
167     }
168
169     _cairo_gl_dispatch_init_entries (dispatch, get_proc_addr,
170                                      dispatch_shaders_entries, dispatch_name);
171
172     return CAIRO_STATUS_SUCCESS;
173 }
174
175 static cairo_status_t
176 _cairo_gl_dispatch_init_fbo (cairo_gl_dispatch_t *dispatch,
177                              cairo_gl_get_proc_addr_func_t get_proc_addr,
178                              int gl_version, cairo_gl_flavor_t gl_flavor)
179 {
180     cairo_gl_dispatch_name_t dispatch_name;
181
182     if (gl_flavor == CAIRO_GL_FLAVOR_DESKTOP)
183     {
184         if (gl_version >= CAIRO_GL_VERSION_ENCODE (3, 0) ||
185             _cairo_gl_has_extension ("GL_ARB_framebuffer_object"))
186             dispatch_name = CAIRO_GL_DISPATCH_NAME_CORE;
187         else if (_cairo_gl_has_extension ("GL_EXT_framebuffer_object"))
188             dispatch_name = CAIRO_GL_DISPATCH_NAME_EXT;
189         else
190             return CAIRO_STATUS_DEVICE_ERROR;
191     }
192     else if (gl_flavor == CAIRO_GL_FLAVOR_ES &&
193              gl_version >= CAIRO_GL_VERSION_ENCODE (2, 0))
194     {
195         dispatch_name = CAIRO_GL_DISPATCH_NAME_ES;
196     }
197     else
198     {
199         return CAIRO_STATUS_DEVICE_ERROR;
200     }
201
202     _cairo_gl_dispatch_init_entries (dispatch, get_proc_addr,
203                                      dispatch_fbo_entries, dispatch_name);
204
205     return CAIRO_STATUS_SUCCESS;
206 }
207
208 static cairo_status_t
209 _cairo_gl_dispatch_init_multisampling (cairo_gl_dispatch_t *dispatch,
210                                        cairo_gl_get_proc_addr_func_t get_proc_addr,
211                                        int gl_version,
212                                        cairo_gl_flavor_t gl_flavor)
213 {
214     /* For the multisampling table, the there are two GLES versions
215      * of the extension, so we put one in the EXT slot and one in
216      * the real ES slot.*/
217     cairo_gl_dispatch_name_t dispatch_name = CAIRO_GL_DISPATCH_NAME_CORE;
218     if (gl_flavor == CAIRO_GL_FLAVOR_ES) {
219         if (_cairo_gl_has_extension ("GL_EXT_multisampled_render_to_texture"))
220             dispatch_name = CAIRO_GL_DISPATCH_NAME_EXT;
221         else if (_cairo_gl_has_extension ("GL_IMG_multisampled_render_to_texture"))
222             dispatch_name = CAIRO_GL_DISPATCH_NAME_ES;
223     }
224     _cairo_gl_dispatch_init_entries (dispatch, get_proc_addr,
225                                      dispatch_multisampling_entries,
226                                      dispatch_name);
227     return CAIRO_STATUS_SUCCESS;
228 }
229
230 cairo_status_t
231 _cairo_gl_dispatch_init (cairo_gl_dispatch_t *dispatch,
232                          cairo_gl_get_proc_addr_func_t get_proc_addr)
233 {
234     cairo_status_t status;
235     int gl_version;
236     cairo_gl_flavor_t gl_flavor;
237
238     gl_version = _cairo_gl_get_version ();
239     gl_flavor = _cairo_gl_get_flavor ();
240
241     status = _cairo_gl_dispatch_init_buffers (dispatch, get_proc_addr,
242                                               gl_version, gl_flavor);
243     if (status != CAIRO_STATUS_SUCCESS)
244         return status;
245
246     status = _cairo_gl_dispatch_init_shaders (dispatch, get_proc_addr,
247                                               gl_version, gl_flavor);
248     if (status != CAIRO_STATUS_SUCCESS)
249         return status;
250
251     status = _cairo_gl_dispatch_init_fbo (dispatch, get_proc_addr,
252                                           gl_version, gl_flavor);
253     if (status != CAIRO_STATUS_SUCCESS)
254         return status;
255
256     status = _cairo_gl_dispatch_init_multisampling (dispatch, get_proc_addr,
257                                                     gl_version, gl_flavor);
258     if (status != CAIRO_STATUS_SUCCESS)
259         return status;
260
261     return CAIRO_STATUS_SUCCESS;
262 }