blob: 5520c032363a4e485e4c54a1b30ead5fa8dc6490 [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
Jose Fonseca4a697ec2015-05-28 15:55:33 +010031#include <sstream>
32
José Fonsecaa44df7a2015-01-05 19:59:59 +000033#include "os.hpp"
34#include "glproc.hpp"
35
José Fonseca0396fa02015-01-05 16:20:08 +000036
37namespace glprofile {
38
39
Jose Fonseca0e1d41b2015-03-13 17:17:47 +000040bool
41Profile::matches(const Profile expected) const
42{
43 if (api != expected.api) {
44 return false;
45 }
46
47 if (!versionGreaterOrEqual(expected.major, expected.minor)) {
48 return false;
49 }
50
51 /*
52 * GLX_ARB_create_context/WGL_ARB_create_context specs state that
53 *
54 * "If version 3.1 is requested, the context returned may implement
55 * any of the following versions:
56 *
57 * * Version 3.1. The GL_ARB_compatibility extension may or may not
58 * be implemented, as determined by the implementation.
59 *
60 * * The core profile of version 3.2 or greater."
61 */
62 if (core != expected.core &&
63 (expected.major != 3 || expected.minor != 1)) {
64 return false;
65 }
66
67 /*
68 * Only check forward-compatible flag prior to 3.2 contexts.
69 *
70 * Note that on MacOSX all 3.2+ context must be forward-compatible.
71 */
72#ifndef __APPLE__
73 if (forwardCompatible > expected.forwardCompatible) {
74 return false;
75 }
76#endif
77
78 return true;
79}
80
81
Jose Fonseca4a697ec2015-05-28 15:55:33 +010082std::string
83Profile::str(void) const
84{
85 std::stringstream ss;
86 ss << *this;
87 return ss.str();
88}
89
90
José Fonseca0396fa02015-01-05 16:20:08 +000091std::ostream &
92operator << (std::ostream &os, const Profile & profile) {
93 os << "OpenGL";
94 if (profile.api == API_GLES) {
95 os << " ES";
96 }
97 os << " " << profile.major << "." << profile.minor;
Jose Fonseca56c419c2015-03-13 16:07:33 +000098 if (profile.api == API_GL) {
99 if (profile.versionGreaterOrEqual(3, 2)) {
100 os << " " << (profile.core ? "core" : "compat");
101 }
102 if (profile.forwardCompatible) {
103 os << " forward-compatible";
104 }
José Fonseca0396fa02015-01-05 16:20:08 +0000105 }
106 return os;
107}
108
109
José Fonsecaa44df7a2015-01-05 19:59:59 +0000110static inline bool
111isDigit(char c) {
112 return c >= '0' && c <= '9';
113}
114
115
116static unsigned
117parseNumber(const char * & p)
118{
119 unsigned n = 0;
120 char c = *p;
121 while (isDigit(c)) {
122 unsigned digit = c - '0';
123 n *= 10;
124 n += digit;
125 ++p;
126 c = *p;
127 }
128 return n;
129}
130
131
132/*
133 * Parse API and version numbers from a GL_VERSION string.
134 *
135 * OpenGL 2.1 specification states that GL_VERSION string is laid out as
136 *
137 * <version number><space><vendor-specific information>
138 *
139 * Where <version number> is either of the form <major number>.<minor number>
140 * or <major number>.<minor number>.<release number>, where the numbers all
141 * have one or more digits. The release number and vendor specific
142 * information are optional.
143 *
144 * OpenGL ES 1.x specification states that GL_VERSION is laid out as
145 *
146 * "OpenGL ES-XX 1.x" XX={CM,CL}
147 *
148 * OpenGL ES 2 and 3 specifications state that GL_VERSION is laid out as
149 *
150 * "OpenGL ES N.M vendor-specific information"
151 */
152static Profile
153parseVersion(const char *version)
154{
155 Profile profile(API_GL, 0, 0, false);
156
157 const char *p = version;
158
159 if (p[0] == 'O' &&
160 p[1] == 'p' &&
161 p[2] == 'e' &&
162 p[3] == 'n' &&
163 p[4] == 'G' &&
164 p[5] == 'L' &&
165 p[6] == ' ' &&
166 p[7] == 'E' &&
167 p[8] == 'S') {
168 p += 9;
169
170 profile.api = API_GLES;
171
172 // skip `-{CM,CL}`
173 if (*p == '-') {
174 ++p;
175 while (*p != ' ') {
176 if (*p == '\0') {
177 goto malformed;
178 }
179 ++p;
180 }
181 }
182
183 // skip white-space
184 while (*p == ' ') {
185 if (*p == '\0') {
186 goto malformed;
187 }
188 ++p;
189 }
190 }
191
192 if (!isDigit(*p)) {
193 goto malformed;
194 }
195
196 profile.major = parseNumber(p);
197 if (*p++ == '.' &&
198 isDigit(*p)) {
199 profile.minor = parseNumber(p);
200 } else {
201 goto malformed;
202 }
203
204 return profile;
205
206malformed:
207 os::log("warning: malformed GL_VERSION (\"%s\")\n", version);
208 return profile;
209}
210
211
212/*
213 * Get the profile of the current context.
214 */
215Profile
216getCurrentContextProfile(void)
217{
218 Profile profile(API_GL, 0, 0, false);
219
220 assert(parseVersion("3.0 Mesa 10.3.2") == Profile(API_GL, 3, 0));
221 assert(parseVersion("3.3 (Core Profile) Mesa 10.3.2") == Profile(API_GL, 3, 3));
222 assert(parseVersion("4.4.0 NVIDIA 331.89") == Profile(API_GL, 4, 4));
223 assert(parseVersion("OpenGL ES 3.0 Mesa 10.3.2") == Profile(API_GLES, 3, 0));
224
225 const char *version = (const char *)_glGetString(GL_VERSION);
226 if (!version) {
Jose Fonseca4a697ec2015-05-28 15:55:33 +0100227 os::log("apitrace: warning: got null GL_VERSION\n");
José Fonsecaa44df7a2015-01-05 19:59:59 +0000228 return profile;
229 }
230
231 // Parse the version string.
232 profile = parseVersion(version);
233
234 if (profile.major >= 3) {
235 /*
236 * From OpenGL and OpenGL ES version 3 onwards, the GL version may also
237 * be queried via GL_MAJOR VERSION and GL_MINOR_VERSION, which should
238 * match the major number and minor number in GL_VERSION string, so use
239 * it to check we parsed the versions correcly.
240 */
241
242 GLint majorVersion = 0;
243 _glGetIntegerv(GL_MAJOR_VERSION, &majorVersion);
244 GLint minorVersion = 0;
245 _glGetIntegerv(GL_MINOR_VERSION, &minorVersion);
246
247 if (majorVersion != profile.major ||
248 minorVersion != profile.minor) {
249 os::log("apitrace: warning: OpenGL context version mismatch (GL_VERSION=\"%s\", but GL_MAJOR/MINOR_VERSION=%u.%u)\n",
250 version, majorVersion, minorVersion);
251 }
252 }
253
Jose Fonseca56c419c2015-03-13 16:07:33 +0000254 if (profile.api == API_GL) {
255 if (profile.versionGreaterOrEqual(3, 0)) {
256 GLint contextFlags = 0;
257 _glGetIntegerv(GL_CONTEXT_FLAGS, &contextFlags);
258 if (contextFlags & GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT) {
259 profile.forwardCompatible = true;
260 }
261 }
262
263 if (profile.versionGreaterOrEqual(3, 2)) {
264 GLint profileMask = 0;
265 _glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &profileMask);
266 if (profileMask & GL_CONTEXT_CORE_PROFILE_BIT) {
267 profile.core = true;
268 }
José Fonsecaa44df7a2015-01-05 19:59:59 +0000269 }
270 }
271
272 return profile;
273
274}
275
276
José Fonseca440d8aa2015-01-23 15:32:23 +0000277void
278Extensions::getCurrentContextExtensions(const Profile & profile)
279{
280 assert(strings.empty());
281 if (profile.major >= 3) {
282 // Use glGetStringi
283 GLint num_strings = 0;
284 _glGetIntegerv(GL_NUM_EXTENSIONS, &num_strings);
285 assert(num_strings);
286 for (int i = 0; i < num_strings; ++i) {
287 const char *extension = reinterpret_cast<const char *>(_glGetStringi(GL_EXTENSIONS, i));
288 assert(extension);
289 if (extension) {
290 strings.insert(extension);
291 }
292 }
293 } else {
294 // Use glGetString
295 const char *begin = reinterpret_cast<const char *>(_glGetString(GL_EXTENSIONS));
296 assert(begin);
297 if (begin) {
298 do {
299 const char *end = begin;
300 char c = *end;
301 while (c != '\0' && c != ' ') {
302 ++end;
303 c = *end;
304 }
305 if (end != begin) {
306 strings.insert(std::string(begin, end));
307 }
308 if (c == '\0') {
309 break;
310 }
311 begin = end + 1;
312 } while(true);
313 }
314 }
315}
316
317
318bool
319Extensions::has(const char *string) const
320{
321 return strings.find(string) != strings.end();
322}
323
324
José Fonseca0396fa02015-01-05 16:20:08 +0000325} /* namespace glprofile */