Commit | Line | Data |
---|---|---|
3719602c PC |
1 | /* Copyright (C) 2010-2020 The RetroArch team |
2 | * | |
3 | * --------------------------------------------------------------------------------------- | |
4 | * The following license statement only applies to this file (gl_capabilities.c). | |
5 | * --------------------------------------------------------------------------------------- | |
6 | * | |
7 | * Permission is hereby granted, free of charge, | |
8 | * to any person obtaining a copy of this software and associated documentation files (the "Software"), | |
9 | * to deal in the Software without restriction, including without limitation the rights to | |
10 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, | |
11 | * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: | |
12 | * | |
13 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. | |
14 | * | |
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, | |
16 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | |
18 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | |
19 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
21 | */ | |
22 | ||
23 | #include <stdio.h> | |
24 | #include <stdint.h> | |
25 | #include <math.h> | |
26 | #include <string.h> | |
27 | ||
28 | #include <boolean.h> | |
29 | ||
30 | #include <glsym/glsym.h> | |
31 | ||
32 | #include <gfx/gl_capabilities.h> | |
33 | ||
34 | static bool gl_core_context = false; | |
35 | ||
36 | bool gl_query_core_context_in_use(void) | |
37 | { | |
38 | return gl_core_context; | |
39 | } | |
40 | ||
41 | void gl_query_core_context_set(bool set) | |
42 | { | |
43 | gl_core_context = set; | |
44 | } | |
45 | ||
46 | void gl_query_core_context_unset(void) | |
47 | { | |
48 | gl_core_context = false; | |
49 | } | |
50 | ||
51 | bool gl_query_extension(const char *ext) | |
52 | { | |
53 | bool ret = false; | |
54 | ||
55 | if (gl_query_core_context_in_use()) | |
56 | { | |
57 | #ifdef GL_NUM_EXTENSIONS | |
58 | GLint i; | |
59 | GLint exts = 0; | |
60 | glGetIntegerv(GL_NUM_EXTENSIONS, &exts); | |
61 | for (i = 0; i < exts; i++) | |
62 | { | |
63 | const char *str = (const char*)glGetStringi(GL_EXTENSIONS, i); | |
64 | if (str && strstr(str, ext)) | |
65 | { | |
66 | ret = true; | |
67 | break; | |
68 | } | |
69 | } | |
70 | #endif | |
71 | } | |
72 | else | |
73 | { | |
74 | const char *str = (const char*)glGetString(GL_EXTENSIONS); | |
75 | ret = str && strstr(str, ext); | |
76 | } | |
77 | ||
78 | return ret; | |
79 | } | |
80 | ||
81 | bool gl_check_error(char **error_string) | |
82 | { | |
83 | int error = glGetError(); | |
84 | switch (error) | |
85 | { | |
86 | case GL_INVALID_ENUM: | |
87 | *error_string = strdup("GL: Invalid enum."); | |
88 | break; | |
89 | case GL_INVALID_VALUE: | |
90 | *error_string = strdup("GL: Invalid value."); | |
91 | break; | |
92 | case GL_INVALID_OPERATION: | |
93 | *error_string = strdup("GL: Invalid operation."); | |
94 | break; | |
95 | case GL_OUT_OF_MEMORY: | |
96 | *error_string = strdup("GL: Out of memory."); | |
97 | break; | |
98 | case GL_NO_ERROR: | |
99 | return true; | |
100 | default: | |
101 | *error_string = strdup("Non specified GL error."); | |
102 | break; | |
103 | } | |
104 | ||
105 | return false; | |
106 | } | |
107 | ||
108 | bool gl_check_capability(enum gl_capability_enum enum_idx) | |
109 | { | |
110 | unsigned major = 0; | |
111 | unsigned minor = 0; | |
112 | const char *vendor = (const char*)glGetString(GL_VENDOR); | |
113 | const char *renderer = (const char*)glGetString(GL_RENDERER); | |
114 | const char *version = (const char*)glGetString(GL_VERSION); | |
115 | #ifdef HAVE_OPENGLES | |
116 | if (version && sscanf(version, "OpenGL ES %u.%u", &major, &minor) != 2) | |
117 | #else | |
118 | if (version && sscanf(version, "%u.%u", &major, &minor) != 2) | |
119 | #endif | |
120 | major = minor = 0; | |
121 | ||
122 | (void)vendor; | |
123 | (void)renderer; | |
124 | ||
125 | switch (enum_idx) | |
126 | { | |
127 | case GL_CAPS_GLES3_SUPPORTED: | |
128 | #if defined(HAVE_OPENGLES) | |
129 | if (major >= 3) | |
130 | return true; | |
131 | #endif | |
132 | break; | |
133 | case GL_CAPS_EGLIMAGE: | |
134 | #if defined(HAVE_EGL) && defined(HAVE_OPENGLES) | |
135 | if (glEGLImageTargetTexture2DOES != NULL) | |
136 | return true; | |
137 | #endif | |
138 | break; | |
139 | case GL_CAPS_SYNC: | |
140 | #ifdef HAVE_OPENGLES | |
141 | if (major >= 3) | |
142 | return true; | |
143 | #else | |
144 | if (gl_query_extension("ARB_sync") && | |
145 | glFenceSync && glDeleteSync && glClientWaitSync) | |
146 | return true; | |
147 | #endif | |
148 | break; | |
149 | case GL_CAPS_MIPMAP: | |
150 | { | |
151 | static bool extension_queried = false; | |
152 | static bool extension = false; | |
153 | ||
154 | if (!extension_queried) | |
155 | { | |
156 | extension = gl_query_extension("ARB_framebuffer_object"); | |
157 | extension_queried = true; | |
158 | } | |
159 | ||
160 | if (extension) | |
161 | return true; | |
162 | } | |
163 | break; | |
164 | case GL_CAPS_VAO: | |
165 | #ifndef HAVE_OPENGLES | |
166 | if (!gl_query_core_context_in_use() && !gl_query_extension("ARB_vertex_array_object")) | |
167 | return false; | |
168 | ||
169 | if (glGenVertexArrays && glBindVertexArray && glDeleteVertexArrays) | |
170 | return true; | |
171 | #endif | |
172 | break; | |
173 | case GL_CAPS_FBO: | |
174 | #if defined(HAVE_PSGL) || defined(HAVE_OPENGLES2) || defined(HAVE_OPENGLES3) || defined(HAVE_OPENGLES_3_1) || defined(HAVE_OPENGLES_3_2) | |
175 | return true; | |
176 | #else | |
177 | if ( !gl_query_core_context_in_use() | |
178 | && !gl_query_extension("ARB_framebuffer_object") | |
179 | && !gl_query_extension("EXT_framebuffer_object")) | |
180 | return false; | |
181 | ||
182 | if (gl_query_extension("ARB_framebuffer_object")) | |
183 | return true; | |
184 | ||
185 | if (gl_query_extension("EXT_framebuffer_object")) | |
186 | return true; | |
187 | ||
188 | if (major >= 3) | |
189 | return true; | |
190 | break; | |
191 | #endif | |
192 | case GL_CAPS_ARGB8: | |
193 | #ifdef HAVE_OPENGLES | |
194 | if (gl_query_extension("OES_rgb8_rgba8") | |
195 | || gl_query_extension("ARM_rgba8") | |
196 | || major >= 3) | |
197 | return true; | |
198 | #else | |
199 | /* TODO/FIXME - implement this for non-GLES? */ | |
200 | #endif | |
201 | break; | |
202 | case GL_CAPS_DEBUG: | |
203 | if (gl_query_extension("KHR_debug")) | |
204 | return true; | |
205 | #ifndef HAVE_OPENGLES | |
206 | if (gl_query_extension("ARB_debug_output")) | |
207 | return true; | |
208 | #endif | |
209 | break; | |
210 | case GL_CAPS_PACKED_DEPTH_STENCIL: | |
211 | if (major >= 3) | |
212 | return true; | |
213 | if (gl_query_extension("OES_packed_depth_stencil")) | |
214 | return true; | |
215 | if (gl_query_extension("EXT_packed_depth_stencil")) | |
216 | return true; | |
217 | break; | |
218 | case GL_CAPS_ES2_COMPAT: | |
219 | #ifndef HAVE_OPENGLES | |
220 | /* ATI card detected, skipping check for GL_RGB565 support... */ | |
221 | if (vendor && renderer && (strstr(vendor, "ATI") || strstr(renderer, "ATI"))) | |
222 | return false; | |
223 | ||
224 | if (gl_query_extension("ARB_ES2_compatibility")) | |
225 | return true; | |
226 | #endif | |
227 | break; | |
228 | case GL_CAPS_UNPACK_ROW_LENGTH: | |
229 | #ifdef HAVE_OPENGLES | |
230 | if (major >= 3) | |
231 | return true; | |
232 | ||
233 | /* Extension GL_EXT_unpack_subimage, can copy textures faster | |
234 | * than using UNPACK_ROW_LENGTH */ | |
235 | if (gl_query_extension("GL_EXT_unpack_subimage")) | |
236 | return true; | |
237 | #endif | |
238 | break; | |
239 | case GL_CAPS_FULL_NPOT_SUPPORT: | |
240 | if (major >= 3) | |
241 | return true; | |
242 | #ifdef HAVE_OPENGLES | |
243 | if (gl_query_extension("ARB_texture_non_power_of_two") || | |
244 | gl_query_extension("OES_texture_npot")) | |
245 | return true; | |
246 | #else | |
247 | { | |
248 | GLint max_texture_size = 0; | |
249 | GLint max_native_instr = 0; | |
250 | /* try to detect actual npot support. might fail for older cards. */ | |
251 | bool arb_npot = gl_query_extension("ARB_texture_non_power_of_two"); | |
252 | bool arb_frag_program = gl_query_extension("ARB_fragment_program"); | |
253 | ||
254 | glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size); | |
255 | ||
256 | #ifdef GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB | |
257 | if (arb_frag_program && glGetProgramivARB) | |
258 | glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, | |
259 | GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB, &max_native_instr); | |
260 | #endif | |
261 | ||
262 | if (arb_npot && arb_frag_program && | |
263 | (max_texture_size >= 8192) && (max_native_instr >= 4096)) | |
264 | return true; | |
265 | } | |
266 | #endif | |
267 | break; | |
268 | case GL_CAPS_SRGB_FBO_ES3: | |
269 | #ifdef HAVE_OPENGLES | |
270 | if (major >= 3) | |
271 | return true; | |
272 | #else | |
273 | break; | |
274 | #endif | |
275 | case GL_CAPS_SRGB_FBO: | |
276 | #if defined(HAVE_OPENGLES) | |
277 | if (major >= 3 || gl_query_extension("EXT_sRGB")) | |
278 | return true; | |
279 | #endif | |
280 | if (gl_check_capability(GL_CAPS_FBO)) | |
281 | { | |
282 | if ( gl_query_core_context_in_use() || | |
283 | (gl_query_extension("EXT_texture_sRGB") | |
284 | && gl_query_extension("ARB_framebuffer_sRGB")) | |
285 | ) | |
286 | return true; | |
287 | } | |
288 | break; | |
289 | case GL_CAPS_FP_FBO: | |
290 | /* GLES - No extensions for float FBO currently. */ | |
291 | #ifndef HAVE_OPENGLES | |
292 | if (gl_check_capability(GL_CAPS_FBO)) | |
293 | { | |
294 | /* Float FBO is core in 3.2. */ | |
295 | if (gl_query_core_context_in_use() || gl_query_extension("ARB_texture_float")) | |
296 | return true; | |
297 | } | |
298 | #endif | |
299 | break; | |
300 | case GL_CAPS_BGRA8888: | |
301 | #ifdef HAVE_OPENGLES | |
302 | /* There are both APPLE and EXT variants. */ | |
303 | if (gl_query_extension("BGRA8888")) | |
304 | return true; | |
305 | #else | |
306 | return true; | |
307 | #endif | |
308 | break; | |
309 | case GL_CAPS_TEX_STORAGE: | |
310 | #ifdef HAVE_OPENGLES | |
311 | if (major >= 3) | |
312 | return true; | |
313 | #else | |
314 | if (vendor && strstr(vendor, "ATI Technologies")) | |
315 | return false; | |
316 | if (gl_query_extension("ARB_texture_storage")) | |
317 | return true; | |
318 | #endif | |
319 | break; | |
320 | case GL_CAPS_TEX_STORAGE_EXT: | |
321 | #ifdef TARGET_OS_IPHONE | |
322 | /* Not working on iOS */ | |
323 | return false; | |
324 | #else | |
325 | if (gl_query_extension("EXT_texture_storage")) | |
326 | return true; | |
327 | #endif | |
328 | break; | |
329 | case GL_CAPS_NONE: | |
330 | default: | |
331 | break; | |
332 | } | |
333 | ||
334 | return false; | |
335 | } |