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