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