1 /*
2  * Cogl
3  *
4  * A Low Level GPU Graphics and Utilities API
5  *
6  * Copyright (C) 2009 Intel Corporation.
7  *
8  * Permission is hereby granted, free of charge, to any person
9  * obtaining a copy of this software and associated documentation
10  * files (the "Software"), to deal in the Software without
11  * restriction, including without limitation the rights to use, copy,
12  * modify, merge, publish, distribute, sublicense, and/or sell copies
13  * of the Software, and to permit persons to whom the Software is
14  * furnished to do so, subject to the following conditions:
15  *
16  * The above copyright notice and this permission notice shall be
17  * included in all copies or substantial portions of the Software.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
23  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
24  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
25  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26  * SOFTWARE.
27  *
28  *
29  */
30 
31 #ifdef HAVE_CONFIG_H
32 #include "config.h"
33 #endif
34 
35 #include <string.h>
36 
37 #include "cogl-context-private.h"
38 
39 #include "cogl-feature-private.h"
40 #include "cogl-renderer-private.h"
41 #include "cogl-private.h"
42 
43 CoglBool
_cogl_feature_check(CoglRenderer * renderer,const char * driver_prefix,const CoglFeatureData * data,int gl_major,int gl_minor,CoglDriver driver,char * const * extensions,void * function_table)44 _cogl_feature_check (CoglRenderer *renderer,
45                      const char *driver_prefix,
46                      const CoglFeatureData *data,
47                      int gl_major,
48                      int gl_minor,
49                      CoglDriver driver,
50                      char * const *extensions,
51                      void *function_table)
52 
53 {
54   const char *suffix = NULL;
55   int func_num;
56   CoglExtGlesAvailability gles_availability = 0;
57   CoglBool in_core;
58 
59   switch (driver)
60     {
61     case COGL_DRIVER_GLES1:
62       gles_availability = COGL_EXT_IN_GLES;
63       break;
64     case COGL_DRIVER_GLES2:
65       gles_availability = COGL_EXT_IN_GLES2;
66 
67       if (COGL_CHECK_GL_VERSION (gl_major, gl_minor, 3, 0))
68         gles_availability |= COGL_EXT_IN_GLES3;
69       break;
70     case COGL_DRIVER_ANY:
71       g_assert_not_reached ();
72     case COGL_DRIVER_WEBGL:
73       /* FIXME: WebGL should probably have its own COGL_EXT_IN_WEBGL flag */
74       break;
75     case COGL_DRIVER_NOP:
76     case COGL_DRIVER_GL:
77     case COGL_DRIVER_GL3:
78       break;
79     }
80 
81   /* First check whether the functions should be directly provided by
82      GL */
83   if (((driver == COGL_DRIVER_GL ||
84         driver == COGL_DRIVER_GL3) &&
85        COGL_CHECK_GL_VERSION (gl_major, gl_minor,
86                               data->min_gl_major, data->min_gl_minor)) ||
87       (data->gles_availability & gles_availability))
88     {
89       suffix = "";
90       in_core = TRUE;
91     }
92   else
93     {
94       /* Otherwise try all of the extensions */
95       const char *namespace, *namespace_suffix;
96       unsigned int namespace_len;
97 
98       for (namespace = data->namespaces;
99            *namespace;
100            namespace += strlen (namespace) + 1)
101         {
102           const char *extension;
103           GString *full_extension_name = g_string_new ("");
104 
105           /* If the namespace part contains a ':' then the suffix for
106              the function names is different from the name space */
107           if ((namespace_suffix = strchr (namespace, ':')))
108             {
109               namespace_len = namespace_suffix - namespace;
110               namespace_suffix++;
111             }
112           else
113             {
114               namespace_len = strlen (namespace);
115               namespace_suffix = namespace;
116             }
117 
118           for (extension = data->extension_names;
119                *extension;
120                extension += strlen (extension) + 1)
121             {
122               g_string_assign (full_extension_name, driver_prefix);
123               g_string_append_c (full_extension_name, '_');
124               g_string_append_len (full_extension_name,
125                                    namespace, namespace_len);
126               g_string_append_c (full_extension_name, '_');
127               g_string_append (full_extension_name, extension);
128               if (_cogl_check_extension (full_extension_name->str,
129                                          extensions))
130                 break;
131             }
132 
133           g_string_free (full_extension_name, TRUE);
134 
135           /* If we found an extension with this namespace then use it
136              as the suffix */
137           if (*extension)
138             {
139               suffix = namespace_suffix;
140               break;
141             }
142         }
143 
144       in_core = FALSE;
145     }
146 
147   /* If we couldn't find anything that provides the functions then
148      give up */
149   if (suffix == NULL)
150     goto error;
151 
152   /* Try to get all of the entry points */
153   for (func_num = 0; data->functions[func_num].name; func_num++)
154     {
155       void *func;
156       char *full_function_name;
157 
158       full_function_name = g_strconcat (data->functions[func_num].name,
159                                         suffix, NULL);
160       func = _cogl_renderer_get_proc_address (renderer,
161                                               full_function_name,
162                                               in_core);
163       g_free (full_function_name);
164 
165       if (func == NULL)
166         goto error;
167 
168       /* Set the function pointer in the context */
169       *(void **) ((uint8_t *) function_table +
170                   data->functions[func_num].pointer_offset) = func;
171     }
172 
173   return TRUE;
174 
175   /* If the extension isn't found or one of the functions wasn't found
176    * then set all of the functions pointers to NULL so Cogl can safely
177    * do feature testing by just looking at the function pointers */
178 error:
179   for (func_num = 0; data->functions[func_num].name; func_num++)
180     *(void **) ((uint8_t *) function_table +
181                 data->functions[func_num].pointer_offset) = NULL;
182 
183   return FALSE;
184 }
185 
186 /* Define a set of arrays containing the functions required from GL
187    for each feature */
188 #define COGL_EXT_BEGIN(name,                                            \
189                        min_gl_major, min_gl_minor,                      \
190                        gles_availability,                               \
191                        namespaces, extension_names)                     \
192   static const CoglFeatureFunction cogl_ext_ ## name ## _funcs[] = {
193 #define COGL_EXT_FUNCTION(ret, name, args)                          \
194   { G_STRINGIFY (name), G_STRUCT_OFFSET (CoglContext, name) },
195 #define COGL_EXT_END()                      \
196   { NULL, 0 },                                  \
197   };
198 #include "gl-prototypes/cogl-all-functions.h"
199 
200 /* Define an array of features */
201 #undef COGL_EXT_BEGIN
202 #define COGL_EXT_BEGIN(name,                                            \
203                        min_gl_major, min_gl_minor,                      \
204                        gles_availability,                               \
205                        namespaces, extension_names)                     \
206   { min_gl_major, min_gl_minor, gles_availability, namespaces,          \
207       extension_names, 0, 0, 0,                                         \
208     cogl_ext_ ## name ## _funcs },
209 #undef COGL_EXT_FUNCTION
210 #define COGL_EXT_FUNCTION(ret, name, args)
211 #undef COGL_EXT_END
212 #define COGL_EXT_END()
213 
214 static const CoglFeatureData
215 cogl_feature_ext_functions_data[] =
216   {
217 #include "gl-prototypes/cogl-all-functions.h"
218   };
219 
220 void
_cogl_feature_check_ext_functions(CoglContext * context,int gl_major,int gl_minor,char * const * gl_extensions)221 _cogl_feature_check_ext_functions (CoglContext *context,
222                                    int gl_major,
223                                    int gl_minor,
224                                    char * const *gl_extensions)
225 {
226   int i;
227 
228   for (i = 0; i < G_N_ELEMENTS (cogl_feature_ext_functions_data); i++)
229     _cogl_feature_check (context->display->renderer,
230                          "GL", cogl_feature_ext_functions_data + i,
231                          gl_major, gl_minor, context->driver,
232                          gl_extensions,
233                          context);
234 }
235