| /* | |
| * Copyright 2011 Google Inc. | |
| * | |
| * Use of this source code is governed by a BSD-style license that can be | |
| * found in the LICENSE file. | |
| */ | |
| #include "GrGLUtil.h" | |
| #include "SkMatrix.h" | |
| #include <stdio.h> | |
| void GrGLClearErr(const GrGLInterface* gl) { | |
| while (GR_GL_NO_ERROR != gl->fFunctions.fGetError()) {} | |
| } | |
| namespace { | |
| const char *get_error_string(uint32_t err) { | |
| switch (err) { | |
| case GR_GL_NO_ERROR: | |
| return ""; | |
| case GR_GL_INVALID_ENUM: | |
| return "Invalid Enum"; | |
| case GR_GL_INVALID_VALUE: | |
| return "Invalid Value"; | |
| case GR_GL_INVALID_OPERATION: | |
| return "Invalid Operation"; | |
| case GR_GL_OUT_OF_MEMORY: | |
| return "Out of Memory"; | |
| case GR_GL_CONTEXT_LOST: | |
| return "Context Lost"; | |
| } | |
| return "Unknown"; | |
| } | |
| } | |
| void GrGLCheckErr(const GrGLInterface* gl, | |
| const char* location, | |
| const char* call) { | |
| uint32_t err = GR_GL_GET_ERROR(gl); | |
| if (GR_GL_NO_ERROR != err) { | |
| SkDebugf("---- glGetError 0x%x(%s)", err, get_error_string(err)); | |
| if (location) { | |
| SkDebugf(" at\n\t%s", location); | |
| } | |
| if (call) { | |
| SkDebugf("\n\t\t%s", call); | |
| } | |
| SkDebugf("\n"); | |
| } | |
| } | |
| /////////////////////////////////////////////////////////////////////////////// | |
| #if GR_GL_LOG_CALLS | |
| bool gLogCallsGL = !!(GR_GL_LOG_CALLS_START); | |
| #endif | |
| #if GR_GL_CHECK_ERROR | |
| bool gCheckErrorGL = !!(GR_GL_CHECK_ERROR_START); | |
| #endif | |
| /////////////////////////////////////////////////////////////////////////////// | |
| GrGLStandard GrGLGetStandardInUseFromString(const char* versionString) { | |
| if (nullptr == versionString) { | |
| SkDebugf("nullptr GL version string."); | |
| return kNone_GrGLStandard; | |
| } | |
| int major, minor; | |
| // check for desktop | |
| int n = sscanf(versionString, "%d.%d", &major, &minor); | |
| if (2 == n) { | |
| return kGL_GrGLStandard; | |
| } | |
| // check for ES 1 | |
| char profile[2]; | |
| n = sscanf(versionString, "OpenGL ES-%c%c %d.%d", profile, profile+1, &major, &minor); | |
| if (4 == n) { | |
| // we no longer support ES1. | |
| return kNone_GrGLStandard; | |
| } | |
| // check for ES2 | |
| n = sscanf(versionString, "OpenGL ES %d.%d", &major, &minor); | |
| if (2 == n) { | |
| return kGLES_GrGLStandard; | |
| } | |
| return kNone_GrGLStandard; | |
| } | |
| void GrGLGetDriverInfo(GrGLStandard standard, | |
| GrGLVendor vendor, | |
| const char* rendererString, | |
| const char* versionString, | |
| GrGLDriver* outDriver, | |
| GrGLDriverVersion* outVersion) { | |
| int major, minor, rev, driverMajor, driverMinor; | |
| *outDriver = kUnknown_GrGLDriver; | |
| *outVersion = GR_GL_DRIVER_UNKNOWN_VER; | |
| if (0 == strcmp(rendererString, "Chromium")) { | |
| *outDriver = kChromium_GrGLDriver; | |
| return; | |
| } | |
| if (standard == kGL_GrGLStandard) { | |
| if (kNVIDIA_GrGLVendor == vendor) { | |
| *outDriver = kNVIDIA_GrGLDriver; | |
| int n = sscanf(versionString, "%d.%d.%d NVIDIA %d.%d", | |
| &major, &minor, &rev, &driverMajor, &driverMinor); | |
| // Some older NVIDIA drivers don't report the driver version. | |
| if (5 == n) { | |
| *outVersion = GR_GL_DRIVER_VER(driverMajor, driverMinor); | |
| } | |
| return; | |
| } | |
| int n = sscanf(versionString, "%d.%d Mesa %d.%d", | |
| &major, &minor, &driverMajor, &driverMinor); | |
| if (4 == n) { | |
| *outDriver = kMesa_GrGLDriver; | |
| *outVersion = GR_GL_DRIVER_VER(driverMajor, driverMinor); | |
| return; | |
| } | |
| } | |
| else { | |
| if (kNVIDIA_GrGLVendor == vendor) { | |
| *outDriver = kNVIDIA_GrGLDriver; | |
| int n = sscanf(versionString, "OpenGL ES %d.%d NVIDIA %d.%d", | |
| &major, &minor, &driverMajor, &driverMinor); | |
| // Some older NVIDIA drivers don't report the driver version. | |
| if (4 == n) { | |
| *outVersion = GR_GL_DRIVER_VER(driverMajor, driverMinor); | |
| } | |
| return; | |
| } | |
| int n = sscanf(versionString, "OpenGL ES %d.%d Mesa %d.%d", | |
| &major, &minor, &driverMajor, &driverMinor); | |
| if (4 == n) { | |
| *outDriver = kMesa_GrGLDriver; | |
| *outVersion = GR_GL_DRIVER_VER(driverMajor, driverMinor); | |
| return; | |
| } | |
| if (0 == strncmp("ANGLE", rendererString, 5)) { | |
| *outDriver = kANGLE_GrGLDriver; | |
| n = sscanf(versionString, "OpenGL ES %d.%d (ANGLE %d.%d", &major, &minor, &driverMajor, | |
| &driverMinor); | |
| if (4 == n) { | |
| *outVersion = GR_GL_DRIVER_VER(driverMajor, driverMinor); | |
| } | |
| return; | |
| } | |
| } | |
| if (kIntel_GrGLVendor == vendor) { | |
| // We presume we're on the Intel driver since it hasn't identified itself as Mesa. | |
| *outDriver = kIntel_GrGLDriver; | |
| } | |
| } | |
| GrGLVersion GrGLGetVersionFromString(const char* versionString) { | |
| if (nullptr == versionString) { | |
| SkDebugf("nullptr GL version string."); | |
| return GR_GL_INVALID_VER; | |
| } | |
| int major, minor; | |
| // check for mesa | |
| int mesaMajor, mesaMinor; | |
| int n = sscanf(versionString, "%d.%d Mesa %d.%d", &major, &minor, &mesaMajor, &mesaMinor); | |
| if (4 == n) { | |
| return GR_GL_VER(major, minor); | |
| } | |
| n = sscanf(versionString, "%d.%d", &major, &minor); | |
| if (2 == n) { | |
| return GR_GL_VER(major, minor); | |
| } | |
| char profile[2]; | |
| n = sscanf(versionString, "OpenGL ES-%c%c %d.%d", profile, profile+1, | |
| &major, &minor); | |
| if (4 == n) { | |
| return GR_GL_VER(major, minor); | |
| } | |
| n = sscanf(versionString, "OpenGL ES %d.%d", &major, &minor); | |
| if (2 == n) { | |
| return GR_GL_VER(major, minor); | |
| } | |
| return GR_GL_INVALID_VER; | |
| } | |
| GrGLSLVersion GrGLGetGLSLVersionFromString(const char* versionString) { | |
| if (nullptr == versionString) { | |
| SkDebugf("nullptr GLSL version string."); | |
| return GR_GLSL_INVALID_VER; | |
| } | |
| int major, minor; | |
| int n = sscanf(versionString, "%d.%d", &major, &minor); | |
| if (2 == n) { | |
| return GR_GLSL_VER(major, minor); | |
| } | |
| n = sscanf(versionString, "OpenGL ES GLSL ES %d.%d", &major, &minor); | |
| if (2 == n) { | |
| return GR_GLSL_VER(major, minor); | |
| } | |
| #ifdef SK_BUILD_FOR_ANDROID | |
| // android hack until the gpu vender updates their drivers | |
| n = sscanf(versionString, "OpenGL ES GLSL %d.%d", &major, &minor); | |
| if (2 == n) { | |
| return GR_GLSL_VER(major, minor); | |
| } | |
| #endif | |
| return GR_GLSL_INVALID_VER; | |
| } | |
| GrGLVendor GrGLGetVendorFromString(const char* vendorString) { | |
| if (vendorString) { | |
| if (0 == strcmp(vendorString, "ARM")) { | |
| return kARM_GrGLVendor; | |
| } | |
| if (0 == strcmp(vendorString, "Imagination Technologies")) { | |
| return kImagination_GrGLVendor; | |
| } | |
| if (0 == strncmp(vendorString, "Intel ", 6) || 0 == strcmp(vendorString, "Intel")) { | |
| return kIntel_GrGLVendor; | |
| } | |
| if (0 == strcmp(vendorString, "Qualcomm")) { | |
| return kQualcomm_GrGLVendor; | |
| } | |
| if (0 == strcmp(vendorString, "NVIDIA Corporation")) { | |
| return kNVIDIA_GrGLVendor; | |
| } | |
| } | |
| return kOther_GrGLVendor; | |
| } | |
| GrGLRenderer GrGLGetRendererFromString(const char* rendererString) { | |
| if (rendererString) { | |
| if (0 == strcmp(rendererString, "NVIDIA Tegra 3")) { | |
| return kTegra3_GrGLRenderer; | |
| } else if (0 == strcmp(rendererString, "NVIDIA Tegra")) { | |
| return kTegra2_GrGLRenderer; | |
| } | |
| int lastDigit; | |
| int n = sscanf(rendererString, "PowerVR SGX 54%d", &lastDigit); | |
| if (1 == n && lastDigit >= 0 && lastDigit <= 9) { | |
| return kPowerVR54x_GrGLRenderer; | |
| } | |
| // certain iOS devices also use PowerVR54x GPUs | |
| static const char kAppleA4Str[] = "Apple A4"; | |
| static const char kAppleA5Str[] = "Apple A5"; | |
| static const char kAppleA6Str[] = "Apple A6"; | |
| if (0 == strncmp(rendererString, kAppleA4Str, | |
| SK_ARRAY_COUNT(kAppleA4Str)-1) || | |
| 0 == strncmp(rendererString, kAppleA5Str, | |
| SK_ARRAY_COUNT(kAppleA5Str)-1) || | |
| 0 == strncmp(rendererString, kAppleA6Str, | |
| SK_ARRAY_COUNT(kAppleA6Str)-1)) { | |
| return kPowerVR54x_GrGLRenderer; | |
| } | |
| static const char kPowerVRRogueStr[] = "PowerVR Rogue"; | |
| static const char kAppleA7Str[] = "Apple A7"; | |
| static const char kAppleA8Str[] = "Apple A8"; | |
| if (0 == strncmp(rendererString, kPowerVRRogueStr, | |
| SK_ARRAY_COUNT(kPowerVRRogueStr)-1) || | |
| 0 == strncmp(rendererString, kAppleA7Str, | |
| SK_ARRAY_COUNT(kAppleA7Str)-1) || | |
| 0 == strncmp(rendererString, kAppleA8Str, | |
| SK_ARRAY_COUNT(kAppleA8Str)-1)) { | |
| return kPowerVRRogue_GrGLRenderer; | |
| } | |
| int adrenoNumber; | |
| n = sscanf(rendererString, "Adreno (TM) %d", &adrenoNumber); | |
| if (1 == n) { | |
| if (adrenoNumber >= 300) { | |
| if (adrenoNumber < 400) { | |
| return kAdreno3xx_GrGLRenderer; | |
| } | |
| if (adrenoNumber < 500) { | |
| return kAdreno4xx_GrGLRenderer; | |
| } | |
| } | |
| } | |
| } | |
| return kOther_GrGLRenderer; | |
| } | |
| GrGLVersion GrGLGetVersion(const GrGLInterface* gl) { | |
| const GrGLubyte* v; | |
| GR_GL_CALL_RET(gl, v, GetString(GR_GL_VERSION)); | |
| return GrGLGetVersionFromString((const char*) v); | |
| } | |
| GrGLSLVersion GrGLGetGLSLVersion(const GrGLInterface* gl) { | |
| const GrGLubyte* v; | |
| GR_GL_CALL_RET(gl, v, GetString(GR_GL_SHADING_LANGUAGE_VERSION)); | |
| return GrGLGetGLSLVersionFromString((const char*) v); | |
| } | |
| GrGLVendor GrGLGetVendor(const GrGLInterface* gl) { | |
| const GrGLubyte* v; | |
| GR_GL_CALL_RET(gl, v, GetString(GR_GL_VENDOR)); | |
| return GrGLGetVendorFromString((const char*) v); | |
| } | |
| GrGLRenderer GrGLGetRenderer(const GrGLInterface* gl) { | |
| const GrGLubyte* v; | |
| GR_GL_CALL_RET(gl, v, GetString(GR_GL_RENDERER)); | |
| return GrGLGetRendererFromString((const char*) v); | |
| } | |
| GrGLenum GrToGLStencilFunc(GrStencilFunc basicFunc) { | |
| static const GrGLenum gTable[] = { | |
| GR_GL_ALWAYS, // kAlways_StencilFunc | |
| GR_GL_NEVER, // kNever_StencilFunc | |
| GR_GL_GREATER, // kGreater_StencilFunc | |
| GR_GL_GEQUAL, // kGEqual_StencilFunc | |
| GR_GL_LESS, // kLess_StencilFunc | |
| GR_GL_LEQUAL, // kLEqual_StencilFunc, | |
| GR_GL_EQUAL, // kEqual_StencilFunc, | |
| GR_GL_NOTEQUAL, // kNotEqual_StencilFunc, | |
| }; | |
| GR_STATIC_ASSERT(SK_ARRAY_COUNT(gTable) == kBasicStencilFuncCount); | |
| GR_STATIC_ASSERT(0 == kAlways_StencilFunc); | |
| GR_STATIC_ASSERT(1 == kNever_StencilFunc); | |
| GR_STATIC_ASSERT(2 == kGreater_StencilFunc); | |
| GR_STATIC_ASSERT(3 == kGEqual_StencilFunc); | |
| GR_STATIC_ASSERT(4 == kLess_StencilFunc); | |
| GR_STATIC_ASSERT(5 == kLEqual_StencilFunc); | |
| GR_STATIC_ASSERT(6 == kEqual_StencilFunc); | |
| GR_STATIC_ASSERT(7 == kNotEqual_StencilFunc); | |
| SkASSERT((unsigned) basicFunc < kBasicStencilFuncCount); | |
| return gTable[basicFunc]; | |
| } |