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