]> git.tdb.fi Git - libs/gl.git/blob - source/extension.cpp
Define some GL enums in case they don't exist
[libs/gl.git] / source / extension.cpp
1 #include <set>
2 #include <cstdlib>
3 #if defined(__ANDROID__)
4 #include <EGL/egl.h>
5 #elif !defined(_WIN32) && !defined(__APPLE__)
6 #define GLX_GLXEXT_PROTOTYPES
7 #include <GL/glx.h>
8 #endif
9 #include <msp/strings/format.h>
10 #include <msp/strings/utils.h>
11 #include "error.h"
12 #include "extension.h"
13 #include "gl.h"
14
15 #ifndef GL_VERSION_3_0
16 #define GL_NUM_EXTENSIONS 0x821D
17 #endif
18
19 #ifndef GL_VERSION_3_2
20 #define GL_CONTEXT_CORE_PROFILE_BIT 0x00000001
21 #define GL_CONTEXT_PROFILE_MASK 0x9126
22 #endif
23
24 using namespace std;
25
26 namespace Msp {
27 namespace GL {
28
29 Version::Version()
30 {
31         major = 0;
32         minor = 0;
33 }
34
35 Version::Version(unsigned short a, unsigned short i)
36 {
37         major = a;
38         minor = i;
39 }
40
41 Version::Version(const string &s)
42 {
43         vector<string> parts = split(s, '.');
44         major = lexical_cast<unsigned>(parts[0]);
45         minor = lexical_cast<unsigned>(parts[1]);
46 }
47
48 bool Version::operator>=(const Version &other) const
49 {
50         return major>other.major || (major==other.major && minor>=other.minor);
51 }
52
53
54 Extension::Extension(const char *n, InitFunc f):
55         name(n),
56         init_func(f),
57         init_done(false),
58         support(UNSUPPORTED)
59 { }
60
61 Extension::operator bool() const
62 {
63         if(!init_done)
64         {
65                 support = init_func();
66                 init_done = true;
67         }
68
69         return support>UNSUPPORTED;
70 }
71
72
73 Require::Require(const Extension &ext)
74 {
75         if(!ext)
76                 throw unsupported_extension(ext.get_name());
77 }
78
79
80 bool is_supported(const string &ext)
81 {
82         static set<string> extensions;
83         static bool init_done = false;
84
85         if(!init_done)
86         {
87                 if(get_gl_api()==OPENGL && get_gl_version()>=Version(3, 0))
88                 {
89                         typedef GLubyte *(APIENTRY *FPtr_glGetStringi)(GLenum, GLuint);
90                         FPtr_glGetStringi glGetStringi = reinterpret_cast<FPtr_glGetStringi>(get_proc_address("glGetStringi"));
91                         int n_extensions;
92                         glGetIntegerv(GL_NUM_EXTENSIONS, &n_extensions);
93                         for(int i=0; i<n_extensions; ++i)
94                                 extensions.insert(reinterpret_cast<const char *>(glGetStringi(GL_EXTENSIONS, i)));
95                 }
96                 else
97                 {
98                         if(const char *gl_ext = reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS)))
99                         {
100                                 vector<string> exts = split(gl_ext);
101                                 extensions.insert(exts.begin(), exts.end());
102                         }
103                 }
104
105                 init_done = true;
106         }
107
108         return extensions.count(ext);
109 }
110
111 bool is_supported(const Version &core_version, const Version &deprecated_version)
112 {
113         const Version &version = get_gl_version();
114         if(deprecated_version && version>=deprecated_version && get_gl_profile()==CORE_PROFILE)
115                 return false;
116         return (version>=core_version);
117 }
118
119 bool is_disabled(const string &ext)
120 {
121         static set<string> disabled_exts;
122         static bool init_done = false;
123
124         if(!init_done)
125         {
126                 if(const char *disable_ptr = getenv("MSPGL_DISABLE_EXTENSIONS"))
127                 {
128                         vector<string> disable = split(disable_ptr);
129                         disabled_exts.insert(disable.begin(), disable.end());
130                 }
131
132                 if(const char *renderer_ptr = reinterpret_cast<const char *>(glGetString(GL_RENDERER)))
133                 {
134                         string renderer = renderer_ptr;
135                         if(renderer.find("Radeon")!=string::npos || renderer.find("AMD")!=string::npos)
136                         {
137                                 /* Radeon doesn't process NV_primitive_restart correctly and treats
138                                 the restart index as a normal element if the indices are stored in a
139                                 buffer. */
140                                 disabled_exts.insert("GL_NV_primitive_restart");
141
142                                 /* AMD's uniform buffer objects only work with the core version of
143                                 shaders. */
144                                 if(get_gl_version()<Version(2, 0))
145                                         disabled_exts.insert("GL_ARB_uniform_buffer_object");
146                         }
147                 }
148
149                 init_done = true;
150         }
151
152         return disabled_exts.count(ext);
153 }
154
155 GLApi get_gl_api()
156 {
157 #ifdef GL_ES_VERSION_2_0
158         return OPENGL_ES2;
159 #else
160         return OPENGL;
161 #endif
162 }
163
164 inline GLProfile _get_gl_profile()
165 {
166         if(get_gl_api()==OPENGL && get_gl_version()>=Version(3, 0))
167         {
168                 int mask;
169                 glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &mask);
170                 if(mask==GL_CONTEXT_CORE_PROFILE_BIT)
171                         return CORE_PROFILE;
172         }
173
174         return COMPATIBILITY_PROFILE;
175 }
176
177 GLProfile get_gl_profile()
178 {
179         static GLProfile profile = _get_gl_profile();
180         return profile;
181 }
182
183 inline Version _get_gl_version()
184 {
185         const char *gl_ver_ptr = reinterpret_cast<const char *>(glGetString(GL_VERSION));
186         if(!gl_ver_ptr)
187                 throw runtime_error("OpenGL version not available");
188
189         string gl_ver = gl_ver_ptr;
190         if(!gl_ver.compare(0, 10, "OpenGL ES "))
191                 gl_ver.erase(0, 10);
192
193         Version ver(gl_ver.substr(0, gl_ver.find(' ')));
194
195         if(const char *force_ver_ptr = getenv("MSPGL_FORCE_VERSION"))
196         {
197                 Version force_ver(force_ver_ptr);
198                 if(!(force_ver>=ver))
199                         ver = force_ver;
200         }
201
202         return ver;
203 }
204
205 const Version &get_gl_version()
206 {
207         static Version version = _get_gl_version();
208         return version;
209 }
210
211 inline Version _get_glsl_version()
212 {
213         const char *glsl_ver_ptr = reinterpret_cast<const char *>(glGetString(GL_SHADING_LANGUAGE_VERSION));
214         if(!glsl_ver_ptr)
215                 throw runtime_error("GLSL version not available");
216
217         string glsl_ver = glsl_ver_ptr;
218         if(!glsl_ver.compare(0, 18, "OpenGL ES GLSL ES "))
219                 glsl_ver.erase(0, 18);
220
221         Version ver(glsl_ver.substr(0, glsl_ver.find(' ')));
222
223         if(const char *force_ver_ptr = getenv("MSPGL_FORCE_GLSL_VERSION"))
224         {
225                 Version force_ver(force_ver_ptr);
226                 if(!(force_ver>=ver))
227                         ver = force_ver;
228         }
229
230         return ver;
231 }
232
233 const Version &get_glsl_version()
234 {
235         static Version version = _get_glsl_version();
236         return version;
237 }
238
239 ExtFunc *get_proc_address(const string &name)
240 {
241 #if defined(WIN32)
242         return reinterpret_cast<ExtFunc *>(wglGetProcAddress(name.c_str()));
243 #elif defined(__APPLE__)
244         (void)name;
245         return 0;  // Not supported
246 #elif defined(__ANDROID__)
247         return eglGetProcAddress(name.c_str());
248 #else
249         return glXGetProcAddressARB(reinterpret_cast<const unsigned char *>(name.c_str()));
250 #endif
251 }
252
253 } // namespace GL
254 } // namespace Msp