• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * GStreamer
3  * Copyright (C) 2012 Matthew Waters <ystreet00@gmail.com>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20 
21 /**
22  * SECTION:gstglfeature
23  * @short_description: OpenGL feature checking
24  * @title: GstGLFeature
25  * @see_also: #GstGLContext
26  */
27 
28 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif
31 
32 #include <string.h>
33 
34 #include "gstglfeature.h"
35 
36 #include "gstglcontext.h"
37 #include "gstglfeature_private.h"
38 #include "gstglfuncs.h"
39 
40 #define GST_CAT_DEFAULT gl_feature
41 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
42 
43 static void
_init_debug(void)44 _init_debug (void)
45 {
46   static gsize _init = 0;
47 
48   if (g_once_init_enter (&_init)) {
49     GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "glfeature", 0,
50         "OpenGL feature detection");
51     g_once_init_leave (&_init, 1);
52   }
53 }
54 
55 /**
56  * gst_gl_check_extension:
57  * @name: the extension to search for
58  * @ext: the list of possible extensions
59  *
60  * Returns: whether @name is in the space separated list of @ext
61  */
62 gboolean
gst_gl_check_extension(const char * name,const gchar * ext)63 gst_gl_check_extension (const char *name, const gchar * ext)
64 {
65   char *end;
66   int name_len, n;
67 
68   if (name == NULL || ext == NULL)
69     return FALSE;
70 
71   end = (char *) (ext + strlen (ext));
72 
73   name_len = strlen (name);
74 
75   while (ext < end) {
76     n = strcspn (ext, " ");
77 
78     if ((name_len == n) && (!strncmp (name, ext, n)))
79       return TRUE;
80     ext += (n + 1);
81   }
82 
83   return FALSE;
84 }
85 
86 /* Define a set of arrays containing the functions required from GL
87    for each feature */
88 #define GST_GL_EXT_BEGIN(name,                                            \
89                        gl_availability,                                 \
90                        min_gl_major, min_gl_minor,                      \
91                        min_gles_major, min_gles_minor,                  \
92                        namespaces, extension_names)                     \
93   static const GstGLFeatureFunction gst_gl_ext_ ## name ## _funcs[] = {
94 #define GST_GL_EXT_FUNCTION(ret, name, args)                          \
95   { G_STRINGIFY (name), G_STRUCT_OFFSET (GstGLFuncs, name) },
96 #define GST_GL_EXT_END()                      \
97   { NULL, 0 },                                  \
98   };
99 #include "glprototypes/all_functions.h"
100 
101 #undef GST_GL_EXT_BEGIN
102 #undef GST_GL_EXT_FUNCTION
103 #undef GST_GL_EXT_END
104 
105 #define GST_GL_EXT_BEGIN(name,                                          \
106                        gl_availability,                                 \
107                        min_gl_major, min_gl_minor,                      \
108                        min_gles_major, min_gles_minor,                  \
109                        namespaces, extension_names)                     \
110   { G_STRINGIFY (name), gl_availability, min_gl_major, min_gl_minor, min_gles_major,        \
111     min_gles_minor, namespaces, extension_names,                        \
112     gst_gl_ext_ ## name ## _funcs },
113 #define GST_GL_EXT_FUNCTION(ret, name, args)
114 #define GST_GL_EXT_END()
115 
116 static const GstGLFeatureData gst_gl_feature_ext_functions_data[] = {
117 #include "glprototypes/all_functions.h"
118 };
119 
120 #undef GST_GL_EXT_BEGIN
121 #undef GST_GL_EXT_FUNCTION
122 #undef GST_GL_EXT_END
123 
124 static gboolean
_gst_gl_feature_check_for_extension(const GstGLFeatureData * data,const char * driver_prefix,const char * extensions_string,const char ** suffix)125 _gst_gl_feature_check_for_extension (const GstGLFeatureData * data,
126     const char *driver_prefix, const char *extensions_string,
127     const char **suffix)
128 {
129   const char *namespace, *namespace_suffix;
130   unsigned int namespace_len;
131 
132   g_return_val_if_fail (suffix != NULL, FALSE);
133 
134   for (namespace = data->namespaces; *namespace;
135       namespace += strlen (namespace) + 1) {
136     const char *extension;
137     GString *full_extension_name = g_string_new ("");
138 
139     /* If the namespace part contains a ':' then the suffix for
140        the function names is different from the name space */
141     if ((namespace_suffix = strchr (namespace, ':'))) {
142       namespace_len = namespace_suffix - namespace;
143       namespace_suffix++;
144     } else {
145       namespace_len = strlen (namespace);
146       namespace_suffix = namespace;
147     }
148 
149     for (extension = data->extension_names; *extension;
150         extension += strlen (extension) + 1) {
151       g_string_assign (full_extension_name, driver_prefix);
152       g_string_append_c (full_extension_name, '_');
153       g_string_append_len (full_extension_name, namespace, namespace_len);
154       g_string_append_c (full_extension_name, '_');
155       g_string_append (full_extension_name, extension);
156 
157       if (gst_gl_check_extension (full_extension_name->str, extensions_string)) {
158         GST_TRACE ("found %s in extension string", full_extension_name->str);
159         break;
160       }
161     }
162 
163     g_string_free (full_extension_name, TRUE);
164 
165     /* If we found an extension with this namespace then use it
166        as the suffix */
167     if (*extension) {
168       *suffix = namespace_suffix;
169       return TRUE;
170     }
171   }
172 
173   return FALSE;
174 }
175 
176 gboolean
_gst_gl_feature_check(GstGLContext * context,const char * driver_prefix,const GstGLFeatureData * data,int gl_major,int gl_minor,const char * extensions_string)177 _gst_gl_feature_check (GstGLContext * context,
178     const char *driver_prefix,
179     const GstGLFeatureData * data,
180     int gl_major, int gl_minor, const char *extensions_string)
181 {
182   char *full_function_name = NULL;
183   gboolean in_core = FALSE;
184   const char *suffix = NULL;
185   int func_num;
186   GstGLFuncs *gst_gl = context->gl_vtable;
187   guint gl_min = 0, gl_maj = 0;
188   GstGLAPI gl_api = gst_gl_context_get_gl_api (context);
189 
190   if (gl_api & (GST_GL_API_OPENGL | GST_GL_API_OPENGL3)) {
191     gl_maj = data->min_gl_major;
192     gl_min = data->min_gl_minor;
193   } else if (gl_api & (GST_GL_API_GLES1 | GST_GL_API_GLES2)) {
194     gl_maj = data->min_gles_major;
195     gl_min = data->min_gles_minor;
196   }
197 
198   GST_DEBUG ("%s, 0x%x, %d.%d vs 0x%x, %d.%d", data->feature_name,
199       data->gl_availability, gl_maj, gl_min,
200       gst_gl_context_get_gl_api (context), gl_major, gl_minor);
201 
202   /* First check whether the functions should be directly provided by
203      GL */
204   if (gst_gl_context_check_gl_version (context, data->gl_availability, gl_maj,
205           gl_min)) {
206     in_core = TRUE;
207     suffix = "";
208   } else {
209     /* Otherwise try all of the extensions */
210     if (!_gst_gl_feature_check_for_extension (data, driver_prefix,
211             extensions_string, &suffix))
212       goto error;
213   }
214 
215   /* If we couldn't find anything that provides the functions then
216      give up */
217   if (suffix == NULL)
218     goto error;
219 
220   /* Try to get all of the entry points */
221   for (func_num = 0; data->functions[func_num].name; func_num++) {
222     void *func;
223 
224     g_free (full_function_name);
225 
226     full_function_name = g_strconcat ("gl", data->functions[func_num].name,
227         suffix, NULL);
228     GST_TRACE ("%s should %sbe in core", full_function_name,
229         in_core ? "" : "not ");
230     func = gst_gl_context_get_proc_address (context, full_function_name);
231 
232     if (func == NULL && in_core) {
233       GST_TRACE ("%s was not found in core, trying the extension version",
234           full_function_name);
235       if (!_gst_gl_feature_check_for_extension (data, driver_prefix,
236               extensions_string, &suffix)) {
237         goto error;
238       } else {
239         g_free (full_function_name);
240         full_function_name = g_strconcat ("gl", data->functions[func_num].name,
241             suffix, NULL);
242         func = gst_gl_context_get_proc_address (context, full_function_name);
243       }
244     }
245 
246     if (func == NULL) {
247       goto error;
248     }
249 
250     /* Set the function pointer in the context */
251     *(void **) ((guint8 *) gst_gl +
252         data->functions[func_num].pointer_offset) = func;
253 
254   }
255 
256   g_free (full_function_name);
257 
258   return TRUE;
259 
260   /* If the extension isn't found or one of the functions wasn't found
261    * then set all of the functions pointers to NULL so we can safely
262    * do feature testing by just looking at the function pointers */
263 error:
264   GST_DEBUG ("failed to find feature %s", data->feature_name);
265 
266   for (func_num = 0; data->functions[func_num].name; func_num++) {
267     *(void **) ((guint8 *) gst_gl +
268         data->functions[func_num].pointer_offset) = NULL;
269   }
270 
271   if (full_function_name) {
272     GST_DEBUG ("failed to find function %s", full_function_name);
273     g_free (full_function_name);
274   }
275 
276   return FALSE;
277 }
278 
279 void
_gst_gl_feature_check_ext_functions(GstGLContext * context,int gl_major,int gl_minor,const char * gl_extensions)280 _gst_gl_feature_check_ext_functions (GstGLContext * context,
281     int gl_major, int gl_minor, const char *gl_extensions)
282 {
283   int i;
284 
285   _init_debug ();
286 
287   for (i = 0; i < G_N_ELEMENTS (gst_gl_feature_ext_functions_data); i++) {
288     _gst_gl_feature_check (context, "GL",
289         gst_gl_feature_ext_functions_data + i, gl_major, gl_minor,
290         gl_extensions);
291   }
292 }
293