blob: 0cfcaa45d2894234be0eb3f475d8c072c45029b1 [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;
45 if (profile.api == API_GL &&
46 profile.versionGreaterOrEqual(3, 2)) {
47 os << " " << (profile.core ? "core" : "compat");
48 }
49 return os;
50}
51
52
José Fonsecaa44df7a2015-01-05 19:59:59 +000053static inline bool
54isDigit(char c) {
55 return c >= '0' && c <= '9';
56}
57
58
59static unsigned
60parseNumber(const char * & p)
61{
62 unsigned n = 0;
63 char c = *p;
64 while (isDigit(c)) {
65 unsigned digit = c - '0';
66 n *= 10;
67 n += digit;
68 ++p;
69 c = *p;
70 }
71 return n;
72}
73
74
75/*
76 * Parse API and version numbers from a GL_VERSION string.
77 *
78 * OpenGL 2.1 specification states that GL_VERSION string is laid out as
79 *
80 * <version number><space><vendor-specific information>
81 *
82 * Where <version number> is either of the form <major number>.<minor number>
83 * or <major number>.<minor number>.<release number>, where the numbers all
84 * have one or more digits. The release number and vendor specific
85 * information are optional.
86 *
87 * OpenGL ES 1.x specification states that GL_VERSION is laid out as
88 *
89 * "OpenGL ES-XX 1.x" XX={CM,CL}
90 *
91 * OpenGL ES 2 and 3 specifications state that GL_VERSION is laid out as
92 *
93 * "OpenGL ES N.M vendor-specific information"
94 */
95static Profile
96parseVersion(const char *version)
97{
98 Profile profile(API_GL, 0, 0, false);
99
100 const char *p = version;
101
102 if (p[0] == 'O' &&
103 p[1] == 'p' &&
104 p[2] == 'e' &&
105 p[3] == 'n' &&
106 p[4] == 'G' &&
107 p[5] == 'L' &&
108 p[6] == ' ' &&
109 p[7] == 'E' &&
110 p[8] == 'S') {
111 p += 9;
112
113 profile.api = API_GLES;
114
115 // skip `-{CM,CL}`
116 if (*p == '-') {
117 ++p;
118 while (*p != ' ') {
119 if (*p == '\0') {
120 goto malformed;
121 }
122 ++p;
123 }
124 }
125
126 // skip white-space
127 while (*p == ' ') {
128 if (*p == '\0') {
129 goto malformed;
130 }
131 ++p;
132 }
133 }
134
135 if (!isDigit(*p)) {
136 goto malformed;
137 }
138
139 profile.major = parseNumber(p);
140 if (*p++ == '.' &&
141 isDigit(*p)) {
142 profile.minor = parseNumber(p);
143 } else {
144 goto malformed;
145 }
146
147 return profile;
148
149malformed:
150 os::log("warning: malformed GL_VERSION (\"%s\")\n", version);
151 return profile;
152}
153
154
155/*
156 * Get the profile of the current context.
157 */
158Profile
159getCurrentContextProfile(void)
160{
161 Profile profile(API_GL, 0, 0, false);
162
163 assert(parseVersion("3.0 Mesa 10.3.2") == Profile(API_GL, 3, 0));
164 assert(parseVersion("3.3 (Core Profile) Mesa 10.3.2") == Profile(API_GL, 3, 3));
165 assert(parseVersion("4.4.0 NVIDIA 331.89") == Profile(API_GL, 4, 4));
166 assert(parseVersion("OpenGL ES 3.0 Mesa 10.3.2") == Profile(API_GLES, 3, 0));
167
168 const char *version = (const char *)_glGetString(GL_VERSION);
169 if (!version) {
170 os::log("warning: null GL_VERSION\n");
171 return profile;
172 }
173
174 // Parse the version string.
175 profile = parseVersion(version);
176
177 if (profile.major >= 3) {
178 /*
179 * From OpenGL and OpenGL ES version 3 onwards, the GL version may also
180 * be queried via GL_MAJOR VERSION and GL_MINOR_VERSION, which should
181 * match the major number and minor number in GL_VERSION string, so use
182 * it to check we parsed the versions correcly.
183 */
184
185 GLint majorVersion = 0;
186 _glGetIntegerv(GL_MAJOR_VERSION, &majorVersion);
187 GLint minorVersion = 0;
188 _glGetIntegerv(GL_MINOR_VERSION, &minorVersion);
189
190 if (majorVersion != profile.major ||
191 minorVersion != profile.minor) {
192 os::log("apitrace: warning: OpenGL context version mismatch (GL_VERSION=\"%s\", but GL_MAJOR/MINOR_VERSION=%u.%u)\n",
193 version, majorVersion, minorVersion);
194 }
195 }
196
197 if (profile.api == API_GL &&
198 profile.versionGreaterOrEqual(3, 2)) {
199 GLint profileMask = 0;
200 _glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &profileMask);
201 if (profileMask & GL_CONTEXT_CORE_PROFILE_BIT) {
202 profile.core = true;
203 }
204 }
205
206 return profile;
207
208}
209
210
José Fonseca0396fa02015-01-05 16:20:08 +0000211} /* namespace glprofile */