]> git.tdb.fi Git - libs/gl.git/blob - source/extension.cpp
Hide windows.h from public headers
[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)
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                                 /* Radeon doesn't process NV_primitive_restart correctly and treats
143                                 the restart index as a normal element if the indices are stored in a
144                                 buffer. */
145                                 disabled_exts.insert("GL_NV_primitive_restart");
146
147                                 // The core primitive restart feature does not work either.
148                                 disabled_exts.insert("GL_MSP_primitive_restart");
149
150                                 /* AMD's uniform buffer objects only work with the core version of
151                                 shaders. */
152                                 if(get_gl_version()<Version(2, 0))
153                                         disabled_exts.insert("GL_ARB_uniform_buffer_object");
154                         }
155                 }
156
157                 init_done = true;
158         }
159
160         return disabled_exts.count(ext);
161 }
162
163 GLApi get_gl_api()
164 {
165 #ifdef GL_ES_VERSION_2_0
166         return OPENGL_ES2;
167 #else
168         return OPENGL;
169 #endif
170 }
171
172 inline GLProfile _get_gl_profile()
173 {
174         if(get_gl_api()==OPENGL && get_gl_version()>=Version(3, 0))
175         {
176                 int mask;
177                 glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &mask);
178                 if(mask==GL_CONTEXT_CORE_PROFILE_BIT)
179                         return CORE_PROFILE;
180         }
181
182         return COMPATIBILITY_PROFILE;
183 }
184
185 GLProfile get_gl_profile()
186 {
187         static GLProfile profile = _get_gl_profile();
188         return profile;
189 }
190
191 inline Version _get_gl_version()
192 {
193         const char *gl_ver_ptr = reinterpret_cast<const char *>(glGetString(GL_VERSION));
194         if(!gl_ver_ptr)
195                 throw runtime_error("OpenGL version not available");
196
197         string gl_ver = gl_ver_ptr;
198         if(!gl_ver.compare(0, 10, "OpenGL ES "))
199                 gl_ver.erase(0, 10);
200
201         Version ver(gl_ver.substr(0, gl_ver.find(' ')));
202
203         if(const char *force_ver_ptr = getenv("MSPGL_FORCE_VERSION"))
204         {
205                 Version force_ver(force_ver_ptr);
206                 if(force_ver<ver)
207                         ver = force_ver;
208         }
209
210         return ver;
211 }
212
213 const Version &get_gl_version()
214 {
215         static Version version = _get_gl_version();
216         return version;
217 }
218
219 inline Version _get_glsl_version()
220 {
221         const char *glsl_ver_ptr = reinterpret_cast<const char *>(glGetString(GL_SHADING_LANGUAGE_VERSION));
222         if(!glsl_ver_ptr)
223                 throw runtime_error("GLSL version not available");
224
225         string glsl_ver = glsl_ver_ptr;
226         if(!glsl_ver.compare(0, 18, "OpenGL ES GLSL ES "))
227                 glsl_ver.erase(0, 18);
228
229         Version ver(glsl_ver.substr(0, glsl_ver.find(' ')));
230
231         if(const char *force_ver_ptr = getenv("MSPGL_FORCE_GLSL_VERSION"))
232         {
233                 Version force_ver(force_ver_ptr);
234                 if(force_ver<ver)
235                         ver = force_ver;
236         }
237
238         return ver;
239 }
240
241 const Version &get_glsl_version()
242 {
243         static Version version = _get_glsl_version();
244         return version;
245 }
246
247 ExtFunc *get_proc_address(const string &name)
248 {
249 #if defined(_WIN32)
250         return reinterpret_cast<ExtFunc *>(wglGetProcAddress(name.c_str()));
251 #elif defined(__APPLE__)
252         (void)name;
253         return 0;  // Not supported
254 #elif defined(__ANDROID__)
255         return eglGetProcAddress(name.c_str());
256 #else
257         return glXGetProcAddressARB(reinterpret_cast<const unsigned char *>(name.c_str()));
258 #endif
259 }
260
261 } // namespace GL
262 } // namespace Msp