| /* |
| * 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; |
| // These null checks are for test GL contexts that return nullptr in their |
| // glGetString implementation. |
| if (!rendererString) { |
| rendererString = ""; |
| } |
| if (!versionString) { |
| versionString = ""; |
| } |
| |
| 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; |
| } |
| } |
| } |
| if (strcmp("Mesa Offscreen", rendererString)) { |
| return kOSMesa_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) == kBasicStencilFuncCnt); |
| 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 < kBasicStencilFuncCnt); |
| |
| return gTable[basicFunc]; |
| } |