1/*
2 * Copyright 2011 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8
9#include "GrGLUtil.h"
10#include "SkMatrix.h"
11#include <stdio.h>
12
13void GrGLClearErr(const GrGLInterface* gl) {
14    while (GR_GL_NO_ERROR != gl->fFunctions.fGetError()) {}
15}
16
17namespace {
18const char *get_error_string(uint32_t err) {
19    switch (err) {
20    case GR_GL_NO_ERROR:
21        return "";
22    case GR_GL_INVALID_ENUM:
23        return "Invalid Enum";
24    case GR_GL_INVALID_VALUE:
25        return "Invalid Value";
26    case GR_GL_INVALID_OPERATION:
27        return "Invalid Operation";
28    case GR_GL_OUT_OF_MEMORY:
29        return "Out of Memory";
30    case GR_GL_CONTEXT_LOST:
31        return "Context Lost";
32    }
33    return "Unknown";
34}
35}
36
37void GrGLCheckErr(const GrGLInterface* gl,
38                  const char* location,
39                  const char* call) {
40    uint32_t err = GR_GL_GET_ERROR(gl);
41    if (GR_GL_NO_ERROR != err) {
42        SkDebugf("---- glGetError 0x%x(%s)", err, get_error_string(err));
43        if (location) {
44            SkDebugf(" at\n\t%s", location);
45        }
46        if (call) {
47            SkDebugf("\n\t\t%s", call);
48        }
49        SkDebugf("\n");
50    }
51}
52
53///////////////////////////////////////////////////////////////////////////////
54
55#if GR_GL_LOG_CALLS
56    bool gLogCallsGL = !!(GR_GL_LOG_CALLS_START);
57#endif
58
59#if GR_GL_CHECK_ERROR
60    bool gCheckErrorGL = !!(GR_GL_CHECK_ERROR_START);
61#endif
62
63///////////////////////////////////////////////////////////////////////////////
64
65GrGLStandard GrGLGetStandardInUseFromString(const char* versionString) {
66    if (nullptr == versionString) {
67        SkDebugf("nullptr GL version string.");
68        return kNone_GrGLStandard;
69    }
70
71    int major, minor;
72
73    // check for desktop
74    int n = sscanf(versionString, "%d.%d", &major, &minor);
75    if (2 == n) {
76        return kGL_GrGLStandard;
77    }
78
79    // check for ES 1
80    char profile[2];
81    n = sscanf(versionString, "OpenGL ES-%c%c %d.%d", profile, profile+1, &major, &minor);
82    if (4 == n) {
83        // we no longer support ES1.
84        return kNone_GrGLStandard;
85    }
86
87    // check for ES2
88    n = sscanf(versionString, "OpenGL ES %d.%d", &major, &minor);
89    if (2 == n) {
90        return kGLES_GrGLStandard;
91    }
92    return kNone_GrGLStandard;
93}
94
95void GrGLGetDriverInfo(GrGLStandard standard,
96                       GrGLVendor vendor,
97                       const char* rendererString,
98                       const char* versionString,
99                       GrGLDriver* outDriver,
100                       GrGLDriverVersion* outVersion) {
101    int major, minor, rev, driverMajor, driverMinor;
102
103    *outDriver = kUnknown_GrGLDriver;
104    *outVersion = GR_GL_DRIVER_UNKNOWN_VER;
105
106    if (0 == strcmp(rendererString, "Chromium")) {
107        *outDriver = kChromium_GrGLDriver;
108        return;
109    }
110
111    if (standard == kGL_GrGLStandard) {
112        if (kNVIDIA_GrGLVendor == vendor) {
113            *outDriver = kNVIDIA_GrGLDriver;
114            int n = sscanf(versionString, "%d.%d.%d NVIDIA %d.%d",
115                           &major, &minor, &rev, &driverMajor, &driverMinor);
116            // Some older NVIDIA drivers don't report the driver version.
117            if (5 == n) {
118                *outVersion = GR_GL_DRIVER_VER(driverMajor, driverMinor);
119            }
120            return;
121        }
122
123        int n = sscanf(versionString, "%d.%d Mesa %d.%d",
124                       &major, &minor, &driverMajor, &driverMinor);
125        if (4 == n) {
126            *outDriver = kMesa_GrGLDriver;
127            *outVersion = GR_GL_DRIVER_VER(driverMajor, driverMinor);
128            return;
129        }
130    }
131    else {
132        if (kNVIDIA_GrGLVendor == vendor) {
133            *outDriver = kNVIDIA_GrGLDriver;
134            int n = sscanf(versionString, "OpenGL ES %d.%d NVIDIA %d.%d",
135                           &major, &minor, &driverMajor, &driverMinor);
136            // Some older NVIDIA drivers don't report the driver version.
137            if (4 == n) {
138                *outVersion = GR_GL_DRIVER_VER(driverMajor, driverMinor);
139            }
140            return;
141        }
142
143        int n = sscanf(versionString, "OpenGL ES %d.%d Mesa %d.%d",
144                       &major, &minor, &driverMajor, &driverMinor);
145        if (4 == n) {
146            *outDriver = kMesa_GrGLDriver;
147            *outVersion = GR_GL_DRIVER_VER(driverMajor, driverMinor);
148            return;
149        }
150        if (0 == strncmp("ANGLE", rendererString, 5)) {
151            *outDriver = kANGLE_GrGLDriver;
152            n = sscanf(versionString, "OpenGL ES %d.%d (ANGLE %d.%d", &major, &minor, &driverMajor,
153                                                                      &driverMinor);
154            if (4 == n) {
155                *outVersion = GR_GL_DRIVER_VER(driverMajor, driverMinor);
156            }
157            return;
158        }
159    }
160
161    if (kIntel_GrGLVendor == vendor) {
162        // We presume we're on the Intel driver since it hasn't identified itself as Mesa.
163        *outDriver = kIntel_GrGLDriver;
164    }
165}
166
167GrGLVersion GrGLGetVersionFromString(const char* versionString) {
168    if (nullptr == versionString) {
169        SkDebugf("nullptr GL version string.");
170        return GR_GL_INVALID_VER;
171    }
172
173    int major, minor;
174
175    // check for mesa
176    int mesaMajor, mesaMinor;
177    int n = sscanf(versionString, "%d.%d Mesa %d.%d", &major, &minor, &mesaMajor, &mesaMinor);
178    if (4 == n) {
179        return GR_GL_VER(major, minor);
180    }
181
182    n = sscanf(versionString, "%d.%d", &major, &minor);
183    if (2 == n) {
184        return GR_GL_VER(major, minor);
185    }
186
187    char profile[2];
188    n = sscanf(versionString, "OpenGL ES-%c%c %d.%d", profile, profile+1,
189               &major, &minor);
190    if (4 == n) {
191        return GR_GL_VER(major, minor);
192    }
193
194    n = sscanf(versionString, "OpenGL ES %d.%d", &major, &minor);
195    if (2 == n) {
196        return GR_GL_VER(major, minor);
197    }
198
199    return GR_GL_INVALID_VER;
200}
201
202GrGLSLVersion GrGLGetGLSLVersionFromString(const char* versionString) {
203    if (nullptr == versionString) {
204        SkDebugf("nullptr GLSL version string.");
205        return GR_GLSL_INVALID_VER;
206    }
207
208    int major, minor;
209
210    int n = sscanf(versionString, "%d.%d", &major, &minor);
211    if (2 == n) {
212        return GR_GLSL_VER(major, minor);
213    }
214
215    n = sscanf(versionString, "OpenGL ES GLSL ES %d.%d", &major, &minor);
216    if (2 == n) {
217        return GR_GLSL_VER(major, minor);
218    }
219
220#ifdef SK_BUILD_FOR_ANDROID
221    // android hack until the gpu vender updates their drivers
222    n = sscanf(versionString, "OpenGL ES GLSL %d.%d", &major, &minor);
223    if (2 == n) {
224        return GR_GLSL_VER(major, minor);
225    }
226#endif
227
228    return GR_GLSL_INVALID_VER;
229}
230
231GrGLVendor GrGLGetVendorFromString(const char* vendorString) {
232    if (vendorString) {
233        if (0 == strcmp(vendorString, "ARM")) {
234            return kARM_GrGLVendor;
235        }
236        if (0 == strcmp(vendorString, "Imagination Technologies")) {
237            return kImagination_GrGLVendor;
238        }
239        if (0 == strncmp(vendorString, "Intel ", 6) || 0 == strcmp(vendorString, "Intel")) {
240            return kIntel_GrGLVendor;
241        }
242        if (0 == strcmp(vendorString, "Qualcomm")) {
243            return kQualcomm_GrGLVendor;
244        }
245        if (0 == strcmp(vendorString, "NVIDIA Corporation")) {
246            return kNVIDIA_GrGLVendor;
247        }
248    }
249    return kOther_GrGLVendor;
250}
251
252GrGLRenderer GrGLGetRendererFromString(const char* rendererString) {
253    if (rendererString) {
254        if (0 == strcmp(rendererString, "NVIDIA Tegra 3")) {
255            return kTegra3_GrGLRenderer;
256        } else if (0 == strcmp(rendererString, "NVIDIA Tegra")) {
257            return kTegra2_GrGLRenderer;
258        }
259        int lastDigit;
260        int n = sscanf(rendererString, "PowerVR SGX 54%d", &lastDigit);
261        if (1 == n && lastDigit >= 0 && lastDigit <= 9) {
262            return kPowerVR54x_GrGLRenderer;
263        }
264        // certain iOS devices also use PowerVR54x GPUs
265        static const char kAppleA4Str[] = "Apple A4";
266        static const char kAppleA5Str[] = "Apple A5";
267        static const char kAppleA6Str[] = "Apple A6";
268        if (0 == strncmp(rendererString, kAppleA4Str,
269                         SK_ARRAY_COUNT(kAppleA4Str)-1) ||
270            0 == strncmp(rendererString, kAppleA5Str,
271                         SK_ARRAY_COUNT(kAppleA5Str)-1) ||
272            0 == strncmp(rendererString, kAppleA6Str,
273                         SK_ARRAY_COUNT(kAppleA6Str)-1)) {
274            return kPowerVR54x_GrGLRenderer;
275        }
276        static const char kPowerVRRogueStr[] = "PowerVR Rogue";
277        static const char kAppleA7Str[] = "Apple A7";
278        static const char kAppleA8Str[] = "Apple A8";
279        if (0 == strncmp(rendererString, kPowerVRRogueStr,
280                         SK_ARRAY_COUNT(kPowerVRRogueStr)-1) ||
281            0 == strncmp(rendererString, kAppleA7Str,
282                         SK_ARRAY_COUNT(kAppleA7Str)-1) ||
283            0 == strncmp(rendererString, kAppleA8Str,
284                         SK_ARRAY_COUNT(kAppleA8Str)-1)) {
285            return kPowerVRRogue_GrGLRenderer;
286        }
287        int adrenoNumber;
288        n = sscanf(rendererString, "Adreno (TM) %d", &adrenoNumber);
289        if (1 == n) {
290            if (adrenoNumber >= 300) {
291                if (adrenoNumber < 400) {
292                    return kAdreno3xx_GrGLRenderer;
293                }
294                if (adrenoNumber < 500) {
295                    return kAdreno4xx_GrGLRenderer;
296                }
297            }
298        }
299    }
300    return kOther_GrGLRenderer;
301}
302
303GrGLVersion GrGLGetVersion(const GrGLInterface* gl) {
304    const GrGLubyte* v;
305    GR_GL_CALL_RET(gl, v, GetString(GR_GL_VERSION));
306    return GrGLGetVersionFromString((const char*) v);
307}
308
309GrGLSLVersion GrGLGetGLSLVersion(const GrGLInterface* gl) {
310    const GrGLubyte* v;
311    GR_GL_CALL_RET(gl, v, GetString(GR_GL_SHADING_LANGUAGE_VERSION));
312    return GrGLGetGLSLVersionFromString((const char*) v);
313}
314
315GrGLVendor GrGLGetVendor(const GrGLInterface* gl) {
316    const GrGLubyte* v;
317    GR_GL_CALL_RET(gl, v, GetString(GR_GL_VENDOR));
318    return GrGLGetVendorFromString((const char*) v);
319}
320
321GrGLRenderer GrGLGetRenderer(const GrGLInterface* gl) {
322    const GrGLubyte* v;
323    GR_GL_CALL_RET(gl, v, GetString(GR_GL_RENDERER));
324    return GrGLGetRendererFromString((const char*) v);
325}
326
327GrGLenum GrToGLStencilFunc(GrStencilFunc basicFunc) {
328    static const GrGLenum gTable[] = {
329        GR_GL_ALWAYS,           // kAlways_StencilFunc
330        GR_GL_NEVER,            // kNever_StencilFunc
331        GR_GL_GREATER,          // kGreater_StencilFunc
332        GR_GL_GEQUAL,           // kGEqual_StencilFunc
333        GR_GL_LESS,             // kLess_StencilFunc
334        GR_GL_LEQUAL,           // kLEqual_StencilFunc,
335        GR_GL_EQUAL,            // kEqual_StencilFunc,
336        GR_GL_NOTEQUAL,         // kNotEqual_StencilFunc,
337    };
338    GR_STATIC_ASSERT(SK_ARRAY_COUNT(gTable) == kBasicStencilFuncCount);
339    GR_STATIC_ASSERT(0 == kAlways_StencilFunc);
340    GR_STATIC_ASSERT(1 == kNever_StencilFunc);
341    GR_STATIC_ASSERT(2 == kGreater_StencilFunc);
342    GR_STATIC_ASSERT(3 == kGEqual_StencilFunc);
343    GR_STATIC_ASSERT(4 == kLess_StencilFunc);
344    GR_STATIC_ASSERT(5 == kLEqual_StencilFunc);
345    GR_STATIC_ASSERT(6 == kEqual_StencilFunc);
346    GR_STATIC_ASSERT(7 == kNotEqual_StencilFunc);
347    SkASSERT((unsigned) basicFunc < kBasicStencilFuncCount);
348
349    return gTable[basicFunc];
350}
351