/* * 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 "src/gpu/ganesh/gl/GrGLUtil.h" #include "include/core/SkString.h" #include "include/gpu/ganesh/gl/GrGLExtensions.h" #include "include/gpu/ganesh/gl/GrGLFunctions.h" #include "include/private/base/SkTArray.h" #include "src/core/SkStringUtils.h" #include "src/gpu/ganesh/GrStencilSettings.h" #include #include #include #include #include #include using namespace skia_private; /////////////////////////////////////////////////////////////////////////////// #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 (!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; } // WebGL might look like "OpenGL ES 2.0 (WebGL 1.0 (OpenGL ES 2.0 Chromium))" int esMajor, esMinor; n = sscanf(versionString, "OpenGL ES %d.%d (WebGL %d.%d", &esMajor, &esMinor, &major, &minor); if (4 == n) { return kWebGL_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; } GrGLVersion GrGLGetVersionFromString(const char* versionString) { if (!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); } // WebGL might look like "OpenGL ES 2.0 (WebGL 1.0 (OpenGL ES 2.0 Chromium))" int esMajor, esMinor; n = sscanf(versionString, "OpenGL ES %d.%d (WebGL %d.%d", &esMajor, &esMinor, &major, &minor); if (4 == 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; } GrGLVersion GrGLGetVersion(const GrGLInterface* gl) { SkASSERT(gl); const GrGLubyte* v; GR_GL_CALL_RET(gl, v, GetString(GR_GL_VERSION)); return GrGLGetVersionFromString((const char*)v); } static GrGLSLVersion get_glsl_version(const char* versionString) { SkASSERT(versionString); 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; } static GrGLVendor get_vendor(const char* vendorString) { SkASSERT(vendorString); if (0 == strcmp(vendorString, "ARM")) { return GrGLVendor::kARM; } if (0 == strcmp(vendorString, "Google Inc.")) { return GrGLVendor::kGoogle; } if (0 == strcmp(vendorString, "Imagination Technologies")) { return GrGLVendor::kImagination; } if (0 == strncmp(vendorString, "Intel ", 6) || 0 == strcmp(vendorString, "Intel")) { return GrGLVendor::kIntel; } if (0 == strcmp(vendorString, "Qualcomm") || 0 == strcmp(vendorString, "freedreno")) { return GrGLVendor::kQualcomm; } if (0 == strcmp(vendorString, "NVIDIA Corporation")) { return GrGLVendor::kNVIDIA; } if (0 == strcmp(vendorString, "ATI Technologies Inc.")) { return GrGLVendor::kATI; } if (0 == strcmp(vendorString, "Apple")) { return GrGLVendor::kApple; } return GrGLVendor::kOther; } static GrGLRenderer get_renderer(const char* rendererString, const GrGLExtensions& extensions) { SkASSERT(rendererString); static const char kTegraStr[] = "NVIDIA Tegra"; if (0 == strncmp(rendererString, kTegraStr, std::size(kTegraStr) - 1)) { // Tegra strings are not very descriptive. We distinguish between the modern and legacy // architectures by the presence of NV_path_rendering. return extensions.has("GL_NV_path_rendering") ? GrGLRenderer::kTegra : GrGLRenderer::kTegra_PreK1; } int lastDigit; int n = sscanf(rendererString, "PowerVR SGX 54%d", &lastDigit); if (1 == n && lastDigit >= 0 && lastDigit <= 9) { return GrGLRenderer::kPowerVR54x; } if (strstr(rendererString, "PowerVR B-Series")) { return GrGLRenderer::kPowerVRBSeries; } // 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, std::size(kAppleA4Str) - 1) || 0 == strncmp(rendererString, kAppleA5Str, std::size(kAppleA5Str) - 1) || 0 == strncmp(rendererString, kAppleA6Str, std::size(kAppleA6Str) - 1)) { return GrGLRenderer::kPowerVR54x; } static const char kPowerVRRogueStr[] = "PowerVR Rogue"; static const char kAppleA7Str[] = "Apple A7"; static const char kAppleA8Str[] = "Apple A8"; if (0 == strncmp(rendererString, kPowerVRRogueStr, std::size(kPowerVRRogueStr) - 1) || 0 == strncmp(rendererString, kAppleA7Str, std::size(kAppleA7Str) - 1) || 0 == strncmp(rendererString, kAppleA8Str, std::size(kAppleA8Str) - 1)) { return GrGLRenderer::kPowerVRRogue; } int adrenoNumber; n = sscanf(rendererString, "Adreno (TM) %d", &adrenoNumber); if (n < 1) { // retry with freedreno driver n = sscanf(rendererString, "FD%d", &adrenoNumber); } if (1 == n) { if (adrenoNumber >= 300) { if (adrenoNumber < 400) { return GrGLRenderer::kAdreno3xx; } if (adrenoNumber < 500) { return adrenoNumber >= 430 ? GrGLRenderer::kAdreno430 : GrGLRenderer::kAdreno4xx_other; } if (adrenoNumber < 600) { return adrenoNumber == 530 ? GrGLRenderer::kAdreno530 : GrGLRenderer::kAdreno5xx_other; } if (adrenoNumber < 700) { if (adrenoNumber == 615) { return GrGLRenderer::kAdreno615; } if (adrenoNumber == 620) { return GrGLRenderer::kAdreno620; } if (adrenoNumber == 630) { return GrGLRenderer::kAdreno630; } if (adrenoNumber == 640) { return GrGLRenderer::kAdreno640; } return GrGLRenderer::kAdreno6xx_other; } } } if (const char* intelString = strstr(rendererString, "Intel")) { // These generic strings seem to always come from Haswell: Iris 5100 or Iris Pro 5200 if (0 == strcmp("Intel Iris OpenGL Engine", intelString) || 0 == strcmp("Intel Iris Pro OpenGL Engine", intelString)) { return GrGLRenderer::kIntelHaswell; } if (strstr(intelString, "Sandybridge")) { return GrGLRenderer::kIntelSandyBridge; } if (strstr(intelString, "Bay Trail")) { return GrGLRenderer::kIntelValleyView; } // In Mesa, 'RKL' can be followed by 'Graphics', same for 'TGL' and 'ADL'. // Referenced from the following Mesa source code: // https://github.com/mesa3d/mesa/blob/master/include/pci_ids/iris_pci_ids.h if (strstr(intelString, "RKL")) { return GrGLRenderer::kIntelRocketLake; } if (strstr(intelString, "TGL")) { return GrGLRenderer::kIntelTigerLake; } // For Windows on ADL-S devices, 'AlderLake-S' might be followed by 'Intel(R)'. if (strstr(intelString, "ADL") || strstr(intelString, "AlderLake")) { return GrGLRenderer::kIntelAlderLake; } // For Windows on TGL or other ADL devices, we might only get 'Xe' from the string. // Since they are both 12th gen, we could temporarily use 'kIntelTigerLake' to cover // both TGL and ADL. if (strstr(intelString, "Xe")) { return GrGLRenderer::kIntelTigerLake; } // There are many possible intervening strings here: // 'Intel(R)' is a common prefix // 'Iris' may appear, followed by '(R)' or '(TM)' // 'Iris' can then be followed by 'Graphics', 'Pro Graphics', or 'Plus Graphics' // If 'Iris' isn't there, we might have 'HD Graphics' or 'UHD Graphics' // // In all cases, though, we end with 'Graphics ', an optional 'P', and a number, // so just skip to that and handle two cases: if (const char* intelGfxString = strstr(intelString, "Graphics")) { int intelNumber; if (sscanf(intelGfxString, "Graphics %d", &intelNumber) || sscanf(intelGfxString, "Graphics P%d", &intelNumber)) { if (intelNumber == 2000 || intelNumber == 3000) { return GrGLRenderer::kIntelSandyBridge; } if (intelNumber == 2500 || intelNumber == 4000) { return GrGLRenderer::kIntelIvyBridge; } if (intelNumber >= 4200 && intelNumber <= 5200) { return GrGLRenderer::kIntelHaswell; } if (intelNumber >= 400 && intelNumber <= 405) { return GrGLRenderer::kIntelCherryView; } if (intelNumber >= 5300 && intelNumber <= 6300) { return GrGLRenderer::kIntelBroadwell; } if (intelNumber >= 500 && intelNumber <= 505) { return GrGLRenderer::kIntelApolloLake; } if (intelNumber >= 510 && intelNumber <= 580) { return GrGLRenderer::kIntelSkyLake; } if (intelNumber >= 600 && intelNumber <= 605) { return GrGLRenderer::kIntelGeminiLake; } // 610 and 630 are reused from KabyLake to CoffeeLake. The CoffeeLake variants // are "UHD Graphics", while the KabyLake ones are "HD Graphics" if (intelNumber == 610 || intelNumber == 630) { return strstr(intelString, "UHD") ? GrGLRenderer::kIntelCoffeeLake : GrGLRenderer::kIntelKabyLake; } if (intelNumber >= 610 && intelNumber <= 650) { return GrGLRenderer::kIntelKabyLake; } if (intelNumber == 655) { return GrGLRenderer::kIntelCoffeeLake; } // 710/730/750/770 are all 12th gen UHD Graphics, but it's hard to distinguish // among RKL, TGL and ADL. We might temporarily use 'kIntelTigerLake' to cover all. if (intelNumber >= 710 && intelNumber <= 770) { return GrGLRenderer::kIntelTigerLake; } if (intelNumber >= 910 && intelNumber <= 950) { return GrGLRenderer::kIntelIceLake; } } } } // The AMD string can have a somewhat arbitrary preamble (see skbug.com/7195) static constexpr char kRadeonStr[] = "Radeon "; if (const char* amdString = strstr(rendererString, kRadeonStr)) { amdString += strlen(kRadeonStr); // Sometimes there is a (TM) and sometimes not. static constexpr char kTMStr[] = "(TM) "; if (!strncmp(amdString, kTMStr, strlen(kTMStr))) { amdString += strlen(kTMStr); } char amd0, amd1, amd2; int amdModel; n = sscanf(amdString, "R9 M3%c%c", &amd0, &amd1); if (2 == n && isdigit(amd0) && isdigit(amd1)) { return GrGLRenderer::kAMDRadeonR9M3xx; } n = sscanf(amdString, "R9 M4%c%c", &amd0, &amd1); if (2 == n && isdigit(amd0) && isdigit(amd1)) { return GrGLRenderer::kAMDRadeonR9M4xx; } n = sscanf(amdString, "HD 7%c%c%c Series", &amd0, &amd1, &amd2); if (3 == n && isdigit(amd0) && isdigit(amd1) && isdigit(amd2)) { return GrGLRenderer::kAMDRadeonHD7xxx; } n = sscanf(amdString, "Pro 5%c%c%c", &amd0, &amd1, &amd2); if (3 == n && isdigit(amd0) && isdigit(amd1) && isdigit(amd2)) { return GrGLRenderer::kAMDRadeonPro5xxx; } n = sscanf(amdString, "Pro Vega %i", &amdModel); if (1 == n) { return GrGLRenderer::kAMDRadeonProVegaxx; } } if (strstr(rendererString, "llvmpipe")) { return GrGLRenderer::kGalliumLLVM; } static const char kMaliGStr[] = "Mali-G"; if (0 == strncmp(rendererString, kMaliGStr, std::size(kMaliGStr) - 1)) { return GrGLRenderer::kMaliG; } static const char kMaliTStr[] = "Mali-T"; if (0 == strncmp(rendererString, kMaliTStr, std::size(kMaliTStr) - 1)) { return GrGLRenderer::kMaliT; } int mali400Num; if (1 == sscanf(rendererString, "Mali-%d", &mali400Num) && mali400Num >= 400 && mali400Num < 500) { return GrGLRenderer::kMali4xx; } static const char kAppleStr[] = "Apple"; if (0 == strncmp(rendererString, kAppleStr, std::size(kAppleStr) - 1)) { return GrGLRenderer::kApple; } if (strstr(rendererString, "WebGL")) { return GrGLRenderer::kWebGL; } return GrGLRenderer::kOther; } static bool is_commamd_buffer(const char* rendererString, const char* versionString) { SkASSERT(rendererString); SkASSERT(versionString); int major, minor; static const char kChromium[] = "Chromium"; char suffix[std::size(kChromium)] = {0}; return (0 == strcmp(rendererString, kChromium) || (3 == sscanf(versionString, "OpenGL ES %d.%d %8s", &major, &minor, suffix) && 0 == strcmp(kChromium, suffix))); } static bool is_virgl(const char* rendererString) { return !!strstr(rendererString, "virgl"); } static std::tuple get_driver_and_version(GrGLStandard standard, GrGLVendor vendor, const char* vendorString, const char* rendererString, const char* versionString) { SkASSERT(rendererString); SkASSERT(versionString); GrGLDriver driver = GrGLDriver::kUnknown; GrGLDriverVersion driverVersion = GR_GL_DRIVER_UNKNOWN_VER; int major, minor, rev, driverMajor, driverMinor, driverPoint; // This is the same on ES and regular GL. if (!strcmp(vendorString, "freedreno")) { driver = GrGLDriver::kFreedreno; } else if (GR_IS_GR_GL(standard)) { if (vendor == GrGLVendor::kNVIDIA) { driver = GrGLDriver::kNVIDIA; 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 (n == 5) { driverVersion = GR_GL_DRIVER_VER(driverMajor, driverMinor, 0); } } else { int n = sscanf(versionString, "%d.%d Mesa %d.%d", &major, &minor, &driverMajor, &driverMinor); if (n != 4) { n = sscanf(versionString, "%d.%d (Core Profile) Mesa %d.%d", &major, &minor, &driverMajor, &driverMinor); } if (n == 4) { driver = GrGLDriver::kMesa; driverVersion = GR_GL_DRIVER_VER(driverMajor, driverMinor, 0); } } } else if (standard == kGLES_GrGLStandard) { if (vendor == GrGLVendor::kNVIDIA) { driver = GrGLDriver::kNVIDIA; 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 (n == 4) { driverVersion = GR_GL_DRIVER_VER(driverMajor, driverMinor, 0); } } else if (vendor == GrGLVendor::kImagination) { int revision; int n = sscanf(versionString, "OpenGL ES %d.%d build %d.%d@%d", &major, &minor, &driverMajor, &driverMinor, &revision); if (n == 5) { driver = GrGLDriver::kImagination; driverVersion = GR_GL_DRIVER_VER(driverMajor, driverMinor, 0); } } else { int n = sscanf(versionString, "OpenGL ES %d.%d Mesa %d.%d", &major, &minor, &driverMajor, &driverMinor); if (n == 4) { driver = GrGLDriver::kMesa; driverVersion = GR_GL_DRIVER_VER(driverMajor, driverMinor, 0); } } } if (driver == GrGLDriver::kUnknown) { if (vendor == GrGLVendor::kIntel) { // We presume we're on the Intel driver since it hasn't identified itself as Mesa. driver = GrGLDriver::kIntel; // This is how the macOS version strings are structured. This might be different on // different // OSes. int n = sscanf(versionString, "%d.%d INTEL-%d.%d.%d", &major, &minor, &driverMajor, &driverMinor, &driverPoint); if (n == 5) { driverVersion = GR_GL_DRIVER_VER(driverMajor, driverMinor, driverPoint); } } else if (vendor == GrGLVendor::kQualcomm) { driver = GrGLDriver::kQualcomm; int n = sscanf(versionString, "OpenGL ES %d.%d V@%d.%d", &major, &minor, &driverMajor, &driverMinor); if (n == 4) { driverVersion = GR_GL_DRIVER_VER(driverMajor, driverMinor, 0); } } else if (vendor == GrGLVendor::kImagination) { int revision; int n = sscanf(versionString, "OpenGL ES %d.%d build %d.%d@%d", &major, &minor, &driverMajor, &driverMinor, &revision); if (n == 5) { // Revision is a large number (looks like a source control revision number) that // doesn't fit into the 'patch' bits, so omit it until we need it. driverVersion = GR_GL_DRIVER_VER(driverMajor, driverMinor, 0); } } else if (vendor == GrGLVendor::kARM) { // Example: // OpenGL ES 3.2 v1.r26p0-01rel0.217d2597f6bd19b169343737782e56e3 // It's unclear how to interpret what comes between "p" and "rel". Every string we've // seen so far has "0-01" there. We ignore it for now. int ignored0; int ignored1; int n = sscanf(versionString, "OpenGL ES %d.%d v%d.r%dp%d-%drel", &major, &minor, &driverMajor, &driverMinor, &ignored0, &ignored1); if (n == 6) { driver = GrGLDriver::kARM; driverVersion = GR_GL_DRIVER_VER(driverMajor, driverMinor, 0); } } else if (vendor == GrGLVendor::kApple) { // There doesn't appear to be a minor version int n = sscanf(versionString, "%d.%d Metal - %d", &major, &minor, &driverMajor); if (n == 3) { driver = GrGLDriver::kApple; driverVersion = GR_GL_DRIVER_VER(driverMajor, 0, 0); } } else { static constexpr char kEmulatorPrefix[] = "Android Emulator OpenGL ES Translator"; if (0 == strncmp(kEmulatorPrefix, rendererString, strlen(kEmulatorPrefix))) { driver = GrGLDriver::kAndroidEmulator; } } } return {driver, driverVersion}; } // If this is detected as ANGLE then the ANGLE backend is returned along with rendererString // stripped of "ANGLE(" and ")" at the start and end, respectively. static std::tuple get_angle_backend(const char* rendererString) { // crbug.com/1203705 ANGLE renderer will be "ANGLE (, , )" // on ANGLE's GL backend with related substitutions for the inner strings on other backends. static constexpr char kHeader[] = "ANGLE ("; static constexpr size_t kHeaderLength = std::size(kHeader) - 1; int rendererLength = strlen(rendererString); if (!strncmp(rendererString, kHeader, kHeaderLength) && rendererString[rendererLength - 1] == ')') { SkString innerString; innerString.set(rendererString + kHeaderLength, rendererLength - kHeaderLength - 1); if (strstr(rendererString, "Direct3D11")) { return {GrGLANGLEBackend::kD3D11, std::move(innerString)}; } else if (strstr(rendererString, "Direct3D9")) { return {GrGLANGLEBackend::kD3D9, std::move(innerString)}; } else if (strstr(rendererString, "Metal")) { return {GrGLANGLEBackend::kMetal, std::move(innerString)}; } else if (strstr(rendererString, "OpenGL")) { return {GrGLANGLEBackend::kOpenGL, std::move(innerString)}; } else if (strstr(rendererString, "Vulkan")) { return {GrGLANGLEBackend::kVulkan, std::move(innerString)}; } } return {GrGLANGLEBackend::kUnknown, {}}; } static std::tuple get_angle_gl_vendor_and_renderer( const char* innerString, const GrGLExtensions& extensions) { TArray parts; SkStrSplit(innerString, ",", &parts); // This would need some fixing if we have substrings that contain commas. if (parts.size() != 3) { return {GrGLVendor::kOther, GrGLRenderer::kOther, GrGLDriver::kUnknown, GR_GL_DRIVER_UNKNOWN_VER}; } const char* angleVendorString = parts[0].c_str(); const char* angleRendererString = parts[1].c_str() + 1; // skip initial space const char* angleVersionString = parts[2].c_str() + 1; // skip initial space GrGLVendor angleVendor = get_vendor(angleVendorString); auto [angleDriver, angleDriverVersion] = get_driver_and_version(kGLES_GrGLStandard, angleVendor, angleVendorString, angleRendererString, angleVersionString); auto angleRenderer = get_renderer(angleRendererString, extensions); return {angleVendor, angleRenderer, angleDriver, angleDriverVersion}; } static GrGLVendor get_angle_metal_vendor(const char* innerString) { if (strstr(innerString, "Intel")) { return GrGLVendor::kIntel; } return GrGLVendor::kOther; } static GrGLVendor get_angle_vulkan_vendor(const char* innerString) { if (strstr(innerString, "ARM")) { return GrGLVendor::kARM; } return GrGLVendor::kOther; } static std::tuple get_angle_d3d_vendor_and_renderer(const char* innerString) { auto vendor = GrGLVendor::kOther; auto renderer = GrGLRenderer::kOther; if (strstr(innerString, "Intel")) { vendor = GrGLVendor::kIntel; const char* modelStr; int modelNumber; if ((modelStr = strstr(innerString, "HD Graphics")) && (1 == sscanf(modelStr, "HD Graphics %i", &modelNumber) || 1 == sscanf(modelStr, "HD Graphics P%i", &modelNumber))) { switch (modelNumber) { case 2000: case 3000: renderer = GrGLRenderer::kIntelSandyBridge; break; case 4000: case 2500: renderer = GrGLRenderer::kIntelSandyBridge; break; case 510: case 515: case 520: case 530: renderer = GrGLRenderer::kIntelSkyLake; break; } } else if ((modelStr = strstr(innerString, "Iris")) && (1 == sscanf(modelStr, "Iris(TM) Graphics %i", &modelNumber) || 1 == sscanf(modelStr, "Iris(TM) Pro Graphics %i", &modelNumber) || 1 == sscanf(modelStr, "Iris(TM) Pro Graphics P%i", &modelNumber))) { switch (modelNumber) { case 540: case 550: case 555: case 580: renderer = GrGLRenderer::kIntelSkyLake; break; } } } else if (strstr(innerString, "NVIDIA")) { vendor = GrGLVendor::kNVIDIA; } else if (strstr(innerString, "Radeon")) { vendor = GrGLVendor::kATI; } // We haven't had a need yet to parse the D3D driver string. return {vendor, renderer, GrGLDriver::kUnknown, GR_GL_DRIVER_UNKNOWN_VER}; } static std::tuple get_webgl_vendor_and_renderer( const GrGLInterface* interface) { if (!interface->fExtensions.has("WEBGL_debug_renderer_info")) { return {GrGLVendor::kOther, GrGLRenderer::kOther}; } auto getString = [&](GrGLenum s) { const GrGLubyte* bytes = interface->fFunctions.fGetString(s); if (!bytes) { return ""; } return reinterpret_cast(bytes); }; const char* webglVendorString = getString(GR_UNMASKED_VENDOR_WEBGL); const char* webglRendererString = getString(GR_UNMASKED_RENDERER_WEBGL); GrGLVendor webglVendor = get_vendor(webglVendorString); GrGLRenderer webglRenderer = get_renderer(webglRendererString, interface->fExtensions); if (webglVendor == GrGLVendor::kOther && strstr(webglRendererString, "Intel")) { webglVendor = GrGLVendor::kIntel; } return {webglVendor, webglRenderer}; } GrGLDriverInfo GrGLGetDriverInfo(const GrGLInterface* interface) { if (!interface) { return {}; } SkASSERT(interface->fStandard != kNone_GrGLStandard); GrGLDriverInfo info; info.fStandard = interface->fStandard; auto getString = [&](GrGLenum s) { const GrGLubyte* bytes = interface->fFunctions.fGetString(s); if (!bytes) { return ""; } return reinterpret_cast(bytes); }; const char* const version = getString(GR_GL_VERSION); const char* const slversion = getString(GR_GL_SHADING_LANGUAGE_VERSION); const char* const renderer = getString(GR_GL_RENDERER); const char* const vendor = getString(GR_GL_VENDOR); info.fVersion = GrGLGetVersionFromString(version); info.fGLSLVersion = get_glsl_version(slversion); info.fVendor = get_vendor(vendor); info.fRenderer = get_renderer(renderer, interface->fExtensions); std::tie(info.fDriver, info.fDriverVersion) = get_driver_and_version(interface->fStandard, info.fVendor, vendor, renderer, version); SkString innerAngleRendererString; std::tie(info.fANGLEBackend, innerAngleRendererString) = get_angle_backend(renderer); if (info.fANGLEBackend == GrGLANGLEBackend::kD3D9 || info.fANGLEBackend == GrGLANGLEBackend::kD3D11) { std::tie(info.fANGLEVendor, info.fANGLERenderer, info.fANGLEDriver, info.fANGLEDriverVersion) = get_angle_d3d_vendor_and_renderer(innerAngleRendererString.c_str()); } else if (info.fANGLEBackend == GrGLANGLEBackend::kOpenGL) { std::tie(info.fANGLEVendor, info.fANGLERenderer, info.fANGLEDriver, info.fANGLEDriverVersion) = get_angle_gl_vendor_and_renderer(innerAngleRendererString.c_str(), interface->fExtensions); } else if (info.fANGLEBackend == GrGLANGLEBackend::kMetal) { info.fANGLEVendor = get_angle_metal_vendor(innerAngleRendererString.c_str()); } else if (info.fANGLEBackend == GrGLANGLEBackend::kVulkan) { info.fANGLEVendor = get_angle_vulkan_vendor(innerAngleRendererString.c_str()); } if (info.fRenderer == GrGLRenderer::kWebGL) { std::tie(info.fWebGLVendor, info.fWebGLRenderer) = get_webgl_vendor_and_renderer(interface); } info.fIsOverCommandBuffer = is_commamd_buffer(renderer, version); info.fIsRunningOverVirgl = is_virgl(renderer); return info; } GrGLenum GrToGLStencilFunc(GrStencilTest test) { static const GrGLenum gTable[kGrStencilTestCount] = { GR_GL_ALWAYS, // kAlways GR_GL_NEVER, // kNever GR_GL_GREATER, // kGreater GR_GL_GEQUAL, // kGEqual GR_GL_LESS, // kLess GR_GL_LEQUAL, // kLEqual GR_GL_EQUAL, // kEqual GR_GL_NOTEQUAL, // kNotEqual }; static_assert(0 == (int)GrStencilTest::kAlways); static_assert(1 == (int)GrStencilTest::kNever); static_assert(2 == (int)GrStencilTest::kGreater); static_assert(3 == (int)GrStencilTest::kGEqual); static_assert(4 == (int)GrStencilTest::kLess); static_assert(5 == (int)GrStencilTest::kLEqual); static_assert(6 == (int)GrStencilTest::kEqual); static_assert(7 == (int)GrStencilTest::kNotEqual); SkASSERT(test < (GrStencilTest)kGrStencilTestCount); return gTable[(int)test]; } bool GrGLFormatIsCompressed(GrGLFormat format) { switch (format) { case GrGLFormat::kCOMPRESSED_ETC1_RGB8: case GrGLFormat::kCOMPRESSED_RGB8_ETC2: case GrGLFormat::kCOMPRESSED_RGB8_BC1: case GrGLFormat::kCOMPRESSED_RGBA8_BC1: return true; case GrGLFormat::kRGBA8: case GrGLFormat::kR8: case GrGLFormat::kALPHA8: case GrGLFormat::kLUMINANCE8: case GrGLFormat::kLUMINANCE8_ALPHA8: case GrGLFormat::kBGRA8: case GrGLFormat::kRGB565: case GrGLFormat::kRGBA16F: case GrGLFormat::kR16F: case GrGLFormat::kLUMINANCE16F: case GrGLFormat::kRGB8: case GrGLFormat::kRGBX8: case GrGLFormat::kRG8: case GrGLFormat::kRGB10_A2: case GrGLFormat::kRGBA4: case GrGLFormat::kSRGB8_ALPHA8: case GrGLFormat::kR16: case GrGLFormat::kRG16: case GrGLFormat::kRGBA16: case GrGLFormat::kRG16F: case GrGLFormat::kSTENCIL_INDEX8: case GrGLFormat::kSTENCIL_INDEX16: case GrGLFormat::kDEPTH24_STENCIL8: case GrGLFormat::kUnknown: return false; } SkUNREACHABLE; }