/* * 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 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; } } } } 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]; }