const webglPlatformSource = String(navigator.userAgentData?.platform || navigator.platform || "") + " " + String(navigator.userAgent || ""); const webglPlatformText = webglPlatformSource.toLowerCase(); const webglPlatformKind = webglPlatformText.includes("android") ? "android" : webglPlatformText.includes("iphone") || webglPlatformText.includes("ipad") || webglPlatformText.includes("ipod") ? "ios" : webglPlatformText.includes("mac") ? "mac" : webglPlatformText.includes("win") ? "windows" : webglPlatformText.includes("cros") ? "cros" : "linux"; const webglFallbackProfiles = { android: { vendor: "Qualcomm", renderer: "Adreno (TM) 640", }, ios: { vendor: "Apple Inc.", renderer: "Apple GPU", }, mac: { vendor: "Google Inc. (Intel Inc.)", renderer: "ANGLE (Intel Inc., Intel(R) Iris(TM) Plus Graphics 640 OpenGL Engine, OpenGL 4.1)", }, windows: { vendor: "Google Inc. (Intel)", renderer: "ANGLE (Intel, Intel(R) UHD Graphics 620 Direct3D11 vs_5_0 ps_5_0, D3D11)", }, cros: { vendor: "Google Inc. (Intel)", renderer: "ANGLE (Intel, Mesa Intel(R) UHD Graphics 620 (KBL GT2), OpenGL 4.6)", }, linux: { vendor: "Google Inc. (Intel)", renderer: "ANGLE (Intel, Mesa Intel(R) UHD Graphics 620 (KBL GT2), OpenGL 4.6)", }, }; const webglFallbackProfile = webglFallbackProfiles[webglPlatformKind] || webglFallbackProfiles.linux; const webglContextProfiles = new WeakMap(); const webglIsObjectKey = (value) => (typeof value === "object" && value !== null) || typeof value === "function"; const webglLooksSoftware = (value) => { const text = String(value || "").toLowerCase(); return ( text.includes("swiftshader") || text.includes("llvmpipe") || text.includes("lavapipe") || text.includes("software") || text.includes("mesa offscreen") || text.includes("google inc. (google)") ); }; const webglMatchesPlatform = (renderer) => { const text = String(renderer || "").toLowerCase(); if (webglPlatformKind === "windows") { return !text.includes("apple") && !text.includes("mesa") && !text.includes("opengl engine"); } if (webglPlatformKind === "mac") { return !text.includes("direct3d") && !text.includes("d3d") && !text.includes("mesa"); } if (webglPlatformKind === "android") { return ( text.includes("adreno") || text.includes("mali") || text.includes("powervr") || text.includes("qualcomm") ); } if (webglPlatformKind === "ios") { return text.includes("apple"); } return !text.includes("direct3d") && !text.includes("d3d") && !text.includes("apple"); }; const webglGetContextProfile = (target, thisArg) => { if (!webglIsObjectKey(thisArg)) return webglFallbackProfile; const cached = Reflect_apply(Page_WeakMap_get, webglContextProfiles, [thisArg]); if (cached) return cached; let nativeVendor; let nativeRenderer; try { nativeVendor = Reflect_apply(target, thisArg, [0x9245]); nativeRenderer = Reflect_apply(target, thisArg, [0x9246]); } catch {} const nativeProfile = typeof nativeVendor === "string" && typeof nativeRenderer === "string" && nativeVendor && nativeRenderer && !webglLooksSoftware(nativeVendor) && !webglLooksSoftware(nativeRenderer) && webglMatchesPlatform(nativeRenderer) ? { vendor: nativeVendor, renderer: nativeRenderer } : webglFallbackProfile; Reflect_apply(Page_WeakMap_set, webglContextProfiles, [thisArg, nativeProfile]); return nativeProfile; }; const webglGetParameterHandler = { apply(target, thisArg, args) { const nativeValue = Reflect_apply(target, thisArg, args); const param = args[0]; if (param === 0x1f00 && typeof nativeValue === "string") return "WebKit"; if (param === 0x1f01 && typeof nativeValue === "string") return "WebKit WebGL"; if ((param === 0x9245 || param === 0x9246) && typeof nativeValue === "string") { const profile = webglGetContextProfile(target, thisArg); return param === 0x9245 ? profile.vendor : profile.renderer; } return nativeValue; }, }; const webglFloatPrecisionTypes = { 0x8df0: true, 0x8df1: true, 0x8df2: true, }; const webglClonePrecisionFormat = (result, values) => { const ownKeys = Reflect_ownKeys(result); let hasRangeMin = false; let hasRangeMax = false; let hasPrecision = false; for (let index = 0; index < ownKeys.length; index += 1) { if (ownKeys[index] === "rangeMin") hasRangeMin = true; if (ownKeys[index] === "rangeMax") hasRangeMax = true; if (ownKeys[index] === "precision") hasPrecision = true; } if (!hasRangeMin || !hasRangeMax || !hasPrecision) return result; const clone = Object_create(Object_getPrototypeOf(result)); for (let index = 0; index < ownKeys.length; index += 1) { const key = ownKeys[index]; const descriptor = Object_getOwnPropertyDescriptor(result, key); if (!descriptor) return result; if (key === "rangeMin" || key === "rangeMax" || key === "precision") { if (!("value" in descriptor)) return result; descriptor.value = values[key]; } try { Object_defineProperty(clone, key, descriptor); } catch { return result; } } return clone; }; const webglGetShaderPrecisionFormatHandler = { apply(target, thisArg, args) { const result = Reflect_apply(target, thisArg, args); const precisionType = args[1]; if ( !result || webglPlatformKind === "android" || webglPlatformKind === "ios" || !webglFloatPrecisionTypes[precisionType] ) { return result; } const rangeMin = result.rangeMin; const rangeMax = result.rangeMax; const precision = result.precision; if ( typeof rangeMin !== "number" || typeof rangeMax !== "number" || typeof precision !== "number" ) { return result; } const values = { rangeMin: Math_max(rangeMin, 127), rangeMax: Math_max(rangeMax, 127), precision: Math_max(precision, 23), }; if ( values.rangeMin === rangeMin && values.rangeMax === rangeMax && values.precision === precision ) { return result; } return webglClonePrecisionFormat(result, values); }, }; const webglInstallMethodProxy = (proto, name, handler) => { if (!proto) return; const descriptor = Object_getOwnPropertyDescriptor(proto, name); if (!descriptor || typeof descriptor.value !== "function") return; const proxy = new Window_Proxy(descriptor.value, handler); patchToString(proxy, name); try { Object_defineProperty(proto, name, { value: proxy, writable: descriptor.writable, configurable: descriptor.configurable, enumerable: descriptor.enumerable, }); } catch {} }; if (window.WebGLRenderingContext) { webglInstallMethodProxy(WebGLRenderingContext.prototype, "getParameter", webglGetParameterHandler); webglInstallMethodProxy( WebGLRenderingContext.prototype, "getShaderPrecisionFormat", webglGetShaderPrecisionFormatHandler, ); } if (window.WebGL2RenderingContext) { webglInstallMethodProxy(WebGL2RenderingContext.prototype, "getParameter", webglGetParameterHandler); webglInstallMethodProxy( WebGL2RenderingContext.prototype, "getShaderPrecisionFormat", webglGetShaderPrecisionFormatHandler, ); }