]> git.tdb.fi Git - libs/gl.git/blob - source/backends/opengl/extension.cpp
a55da9bac1c7b30ab965b6ce70e20390eafda6d1
[libs/gl.git] / source / backends / opengl / 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 Extension::Extension(const char *n, InitFunc f):
32         name(n),
33         init_func(f),
34         init_done(false),
35         support(UNSUPPORTED)
36 { }
37
38 Extension::operator bool() const
39 {
40         if(!init_done)
41         {
42                 support = init_func();
43                 init_done = true;
44         }
45
46         return support>UNSUPPORTED;
47 }
48
49
50 Require::Require(const Extension &ext)
51 {
52         if(!ext)
53                 throw unsupported_extension(ext.get_name());
54 }
55
56
57 bool is_supported(const string &ext)
58 {
59         if(is_disabled(ext))
60                 return false;
61
62         static set<string> extensions;
63         static bool init_done = false;
64
65         if(!init_done)
66         {
67                 if(get_backend_api()==OPENGL && get_backend_version()>=Version(3, 0))
68                 {
69                         typedef GLubyte *(APIENTRY *FPtr_glGetStringi)(GLenum, GLuint);
70                         FPtr_glGetStringi glGetStringi = reinterpret_cast<FPtr_glGetStringi>(get_proc_address("glGetStringi"));
71                         int n_extensions;
72                         glGetIntegerv(GL_NUM_EXTENSIONS, &n_extensions);
73                         for(int i=0; i<n_extensions; ++i)
74                                 extensions.insert(reinterpret_cast<const char *>(glGetStringi(GL_EXTENSIONS, i)));
75                 }
76                 else
77                 {
78                         if(const char *gl_ext = reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS)))
79                         {
80                                 vector<string> exts = split(gl_ext);
81                                 extensions.insert(exts.begin(), exts.end());
82                         }
83                 }
84
85                 init_done = true;
86         }
87
88         return extensions.count(ext);
89 }
90
91 bool is_supported(const Version &core_version, const Version &deprecated_version)
92 {
93         const Version &version = get_backend_version();
94         if(deprecated_version && version>=deprecated_version && get_gl_profile()==CORE_PROFILE)
95                 return false;
96         return (version>=core_version);
97 }
98
99 bool is_disabled(const string &ext)
100 {
101         static set<string> disabled_exts;
102         static bool init_done = false;
103
104         if(!init_done)
105         {
106                 if(const char *disable_ptr = getenv("MSPGL_DISABLE_EXTENSIONS"))
107                 {
108                         vector<string> disable = split(disable_ptr);
109                         disabled_exts.insert(disable.begin(), disable.end());
110                 }
111
112                 if(const char *renderer_ptr = reinterpret_cast<const char *>(glGetString(GL_RENDERER)))
113                 {
114                         string renderer = renderer_ptr;
115                         if(renderer.find("Radeon")!=string::npos || renderer.find("AMD")!=string::npos)
116                         {
117                                 // The core primitive restart feature does not work either.
118                                 disabled_exts.insert("GL_MSP_primitive_restart");
119
120                                 /* AMD's uniform buffer objects only work with the core version of
121                                 shaders. */
122                                 if(get_backend_version()<Version(2, 0))
123                                         disabled_exts.insert("GL_ARB_uniform_buffer_object");
124                         }
125                 }
126
127                 init_done = true;
128         }
129
130         return disabled_exts.count(ext);
131 }
132
133 inline GLProfile _get_gl_profile()
134 {
135         if(get_backend_api()==OPENGL && get_backend_version()>=Version(3, 0))
136         {
137                 int mask;
138                 glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &mask);
139                 if(mask==GL_CONTEXT_CORE_PROFILE_BIT)
140                         return CORE_PROFILE;
141         }
142
143         return COMPATIBILITY_PROFILE;
144 }
145
146 GLProfile get_gl_profile()
147 {
148         static GLProfile profile = _get_gl_profile();
149         return profile;
150 }
151
152 inline Version _get_glsl_version()
153 {
154         const char *glsl_ver_ptr = reinterpret_cast<const char *>(glGetString(GL_SHADING_LANGUAGE_VERSION));
155         if(!glsl_ver_ptr)
156                 throw runtime_error("GLSL version not available");
157
158         string glsl_ver = glsl_ver_ptr;
159         if(!glsl_ver.compare(0, 18, "OpenGL ES GLSL ES "))
160                 glsl_ver.erase(0, 18);
161
162         Version ver(glsl_ver.substr(0, glsl_ver.find(' ')));
163
164         if(const char *force_ver_ptr = getenv("MSPGL_FORCE_GLSL_VERSION"))
165         {
166                 Version force_ver(force_ver_ptr);
167                 if(force_ver<ver)
168                         ver = force_ver;
169         }
170
171         return ver;
172 }
173
174 const Version &get_glsl_version()
175 {
176         static Version version = _get_glsl_version();
177         return version;
178 }
179
180 ExtFunc *get_proc_address(const string &name)
181 {
182 #if defined(_WIN32)
183         return reinterpret_cast<ExtFunc *>(wglGetProcAddress(name.c_str()));
184 #elif defined(__APPLE__)
185         (void)name;
186         return 0;  // Not supported
187 #elif defined(__ANDROID__)
188         return eglGetProcAddress(name.c_str());
189 #else
190         return glXGetProcAddressARB(reinterpret_cast<const unsigned char *>(name.c_str()));
191 #endif
192 }
193
194 } // namespace GL
195 } // namespace Msp