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