drc: handle upto 64k page size
[pcsx_rearmed.git] / deps / libretro-common / gfx / gl_capabilities.c
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 }