blob: de996b3363dbbdf3b7e16edaa818bb9122cfd3a7 [file] [log] [blame]
José Fonseca0396fa02015-01-05 16:20:08 +00001/**************************************************************************
2 *
3 * Copyright 2014 VMware, Inc.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 *
24 **************************************************************************/
25
26
27#include "glprofile.hpp"
28
José Fonsecaa44df7a2015-01-05 19:59:59 +000029#include <assert.h>
30
31#include "os.hpp"
32#include "glproc.hpp"
33
José Fonseca0396fa02015-01-05 16:20:08 +000034
35namespace glprofile {
36
37
38std::ostream &
39operator << (std::ostream &os, const Profile & profile) {
40 os << "OpenGL";
41 if (profile.api == API_GLES) {
42 os << " ES";
43 }
44 os << " " << profile.major << "." << profile.minor;
Jose Fonseca56c419c2015-03-13 16:07:33 +000045 if (profile.api == API_GL) {
46 if (profile.versionGreaterOrEqual(3, 2)) {
47 os << " " << (profile.core ? "core" : "compat");
48 }
49 if (profile.forwardCompatible) {
50 os << " forward-compatible";
51 }
José Fonseca0396fa02015-01-05 16:20:08 +000052 }
53 return os;
54}
55
56
José Fonsecaa44df7a2015-01-05 19:59:59 +000057static inline bool
58isDigit(char c) {
59 return c >= '0' && c <= '9';
60}
61
62
63static unsigned
64parseNumber(const char * & p)
65{
66 unsigned n = 0;
67 char c = *p;
68 while (isDigit(c)) {
69 unsigned digit = c - '0';
70 n *= 10;
71 n += digit;
72 ++p;
73 c = *p;
74 }
75 return n;
76}
77
78
79/*
80 * Parse API and version numbers from a GL_VERSION string.
81 *
82 * OpenGL 2.1 specification states that GL_VERSION string is laid out as
83 *
84 * <version number><space><vendor-specific information>
85 *
86 * Where <version number> is either of the form <major number>.<minor number>
87 * or <major number>.<minor number>.<release number>, where the numbers all
88 * have one or more digits. The release number and vendor specific
89 * information are optional.
90 *
91 * OpenGL ES 1.x specification states that GL_VERSION is laid out as
92 *
93 * "OpenGL ES-XX 1.x" XX={CM,CL}
94 *
95 * OpenGL ES 2 and 3 specifications state that GL_VERSION is laid out as
96 *
97 * "OpenGL ES N.M vendor-specific information"
98 */
99static Profile
100parseVersion(const char *version)
101{
102 Profile profile(API_GL, 0, 0, false);
103
104 const char *p = version;
105
106 if (p[0] == 'O' &&
107 p[1] == 'p' &&
108 p[2] == 'e' &&
109 p[3] == 'n' &&
110 p[4] == 'G' &&
111 p[5] == 'L' &&
112 p[6] == ' ' &&
113 p[7] == 'E' &&
114 p[8] == 'S') {
115 p += 9;
116
117 profile.api = API_GLES;
118
119 // skip `-{CM,CL}`
120 if (*p == '-') {
121 ++p;
122 while (*p != ' ') {
123 if (*p == '\0') {
124 goto malformed;
125 }
126 ++p;
127 }
128 }
129
130 // skip white-space
131 while (*p == ' ') {
132 if (*p == '\0') {
133 goto malformed;
134 }
135 ++p;
136 }
137 }
138
139 if (!isDigit(*p)) {
140 goto malformed;
141 }
142
143 profile.major = parseNumber(p);
144 if (*p++ == '.' &&
145 isDigit(*p)) {
146 profile.minor = parseNumber(p);
147 } else {
148 goto malformed;
149 }
150
151 return profile;
152
153malformed:
154 os::log("warning: malformed GL_VERSION (\"%s\")\n", version);
155 return profile;
156}
157
158
159/*
160 * Get the profile of the current context.
161 */
162Profile
163getCurrentContextProfile(void)
164{
165 Profile profile(API_GL, 0, 0, false);
166
167 assert(parseVersion("3.0 Mesa 10.3.2") == Profile(API_GL, 3, 0));
168 assert(parseVersion("3.3 (Core Profile) Mesa 10.3.2") == Profile(API_GL, 3, 3));
169 assert(parseVersion("4.4.0 NVIDIA 331.89") == Profile(API_GL, 4, 4));
170 assert(parseVersion("OpenGL ES 3.0 Mesa 10.3.2") == Profile(API_GLES, 3, 0));
171
172 const char *version = (const char *)_glGetString(GL_VERSION);
173 if (!version) {
174 os::log("warning: null GL_VERSION\n");
175 return profile;
176 }
177
178 // Parse the version string.
179 profile = parseVersion(version);
180
181 if (profile.major >= 3) {
182 /*
183 * From OpenGL and OpenGL ES version 3 onwards, the GL version may also
184 * be queried via GL_MAJOR VERSION and GL_MINOR_VERSION, which should
185 * match the major number and minor number in GL_VERSION string, so use
186 * it to check we parsed the versions correcly.
187 */
188
189 GLint majorVersion = 0;
190 _glGetIntegerv(GL_MAJOR_VERSION, &majorVersion);
191 GLint minorVersion = 0;
192 _glGetIntegerv(GL_MINOR_VERSION, &minorVersion);
193
194 if (majorVersion != profile.major ||
195 minorVersion != profile.minor) {
196 os::log("apitrace: warning: OpenGL context version mismatch (GL_VERSION=\"%s\", but GL_MAJOR/MINOR_VERSION=%u.%u)\n",
197 version, majorVersion, minorVersion);
198 }
199 }
200
Jose Fonseca56c419c2015-03-13 16:07:33 +0000201 if (profile.api == API_GL) {
202 if (profile.versionGreaterOrEqual(3, 0)) {
203 GLint contextFlags = 0;
204 _glGetIntegerv(GL_CONTEXT_FLAGS, &contextFlags);
205 if (contextFlags & GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT) {
206 profile.forwardCompatible = true;
207 }
208 }
209
210 if (profile.versionGreaterOrEqual(3, 2)) {
211 GLint profileMask = 0;
212 _glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &profileMask);
213 if (profileMask & GL_CONTEXT_CORE_PROFILE_BIT) {
214 profile.core = true;
215 }
José Fonsecaa44df7a2015-01-05 19:59:59 +0000216 }
217 }
218
219 return profile;
220
221}
222
223
José Fonseca440d8aa2015-01-23 15:32:23 +0000224void
225Extensions::getCurrentContextExtensions(const Profile & profile)
226{
227 assert(strings.empty());
228 if (profile.major >= 3) {
229 // Use glGetStringi
230 GLint num_strings = 0;
231 _glGetIntegerv(GL_NUM_EXTENSIONS, &num_strings);
232 assert(num_strings);
233 for (int i = 0; i < num_strings; ++i) {
234 const char *extension = reinterpret_cast<const char *>(_glGetStringi(GL_EXTENSIONS, i));
235 assert(extension);
236 if (extension) {
237 strings.insert(extension);
238 }
239 }
240 } else {
241 // Use glGetString
242 const char *begin = reinterpret_cast<const char *>(_glGetString(GL_EXTENSIONS));
243 assert(begin);
244 if (begin) {
245 do {
246 const char *end = begin;
247 char c = *end;
248 while (c != '\0' && c != ' ') {
249 ++end;
250 c = *end;
251 }
252 if (end != begin) {
253 strings.insert(std::string(begin, end));
254 }
255 if (c == '\0') {
256 break;
257 }
258 begin = end + 1;
259 } while(true);
260 }
261 }
262}
263
264
265bool
266Extensions::has(const char *string) const
267{
268 return strings.find(string) != strings.end();
269}
270
271
José Fonseca0396fa02015-01-05 16:20:08 +0000272} /* namespace glprofile */