git subrepo clone https://github.com/libretro/libretro-common.git deps/libretro-common
[pcsx_rearmed.git] / deps / libretro-common / gfx / gl_capabilities.c
CommitLineData
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
34static bool gl_core_context = false;
35
36bool gl_query_core_context_in_use(void)
37{
38 return gl_core_context;
39}
40
41void gl_query_core_context_set(bool set)
42{
43 gl_core_context = set;
44}
45
46void gl_query_core_context_unset(void)
47{
48 gl_core_context = false;
49}
50
51bool 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
81bool 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
108bool 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}