@pmndrs/detect-gpu 6.0.0 → 6.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -1,72 +1,79 @@
1
+ //#region src/index.d.ts
1
2
  interface GetGPUTier {
3
+ /**
4
+ * URL of directory where benchmark data is hosted.
5
+ *
6
+ * @default https://unpkg.com/@pmndrs/detect-gpu@{version}/dist/benchmarks
7
+ */
8
+ benchmarksURL?: string;
9
+ /**
10
+ * Optionally pass in a WebGL context to avoid creating a temporary one
11
+ * internally.
12
+ */
13
+ glContext?: WebGLRenderingContext | WebGL2RenderingContext;
14
+ /**
15
+ * Whether to fail if the system performance is low or if no hardware GPU is
16
+ * available.
17
+ *
18
+ * @default false
19
+ */
20
+ failIfMajorPerformanceCaveat?: boolean;
21
+ /**
22
+ * Framerate per tier for mobile devices.
23
+ *
24
+ * @defaultValue [0, 15, 30, 60]
25
+ */
26
+ mobileTiers?: number[];
27
+ /**
28
+ * Framerate per tier for desktop devices.
29
+ *
30
+ * @defaultValue [0, 15, 30, 60]
31
+ */
32
+ desktopTiers?: number[];
33
+ /**
34
+ * Optionally override specific parameters. Used mainly for testing.
35
+ */
36
+ override?: {
37
+ renderer?: string;
2
38
  /**
3
- * URL of directory where benchmark data is hosted.
4
- *
5
- * @default https://unpkg.com/@pmndrs/detect-gpu@{version}/dist/benchmarks
39
+ * Override whether device is an iPad.
6
40
  */
7
- benchmarksURL?: string;
41
+ isIpad?: boolean;
8
42
  /**
9
- * Optionally pass in a WebGL context to avoid creating a temporary one
10
- * internally.
43
+ * Override whether device is a mobile device.
11
44
  */
12
- glContext?: WebGLRenderingContext | WebGL2RenderingContext;
13
- /**
14
- * Whether to fail if the system performance is low or if no hardware GPU is
15
- * available.
16
- *
17
- * @default false
18
- */
19
- failIfMajorPerformanceCaveat?: boolean;
20
- /**
21
- * Framerate per tier for mobile devices.
22
- *
23
- * @defaultValue [0, 15, 30, 60]
24
- */
25
- mobileTiers?: number[];
45
+ isMobile?: boolean;
26
46
  /**
27
- * Framerate per tier for desktop devices.
28
- *
29
- * @defaultValue [0, 15, 30, 60]
47
+ * Override device screen size.
30
48
  */
31
- desktopTiers?: number[];
49
+ screenSize?: {
50
+ width: number;
51
+ height: number;
52
+ };
32
53
  /**
33
- * Optionally override specific parameters. Used mainly for testing.
54
+ * Override how benchmark data is loaded
34
55
  */
35
- override?: {
36
- renderer?: string;
37
- /**
38
- * Override whether device is an iPad.
39
- */
40
- isIpad?: boolean;
41
- /**
42
- * Override whether device is a mobile device.
43
- */
44
- isMobile?: boolean;
45
- /**
46
- * Override device screen size.
47
- */
48
- screenSize?: {
49
- width: number;
50
- height: number;
51
- };
52
- /**
53
- * Override how benchmark data is loaded
54
- */
55
- loadBenchmarks?: (file: string) => Promise<ModelEntry[]>;
56
- };
56
+ loadBenchmarks?: (file: string) => Promise<ModelEntry[]>;
57
+ };
57
58
  }
58
- type TierType = 'SSR' | 'WEBGL_UNSUPPORTED' | 'BLOCKLISTED' | 'FALLBACK' | 'BENCHMARK';
59
+ type TierType = 'SSR' | 'WEBGL_UNSUPPORTED' | 'BLOCKLISTED' | 'FALLBACK' | 'BENCHMARK' | 'BENCHMARK_FETCH_FAILED';
59
60
  type TierResult = {
60
- tier: number;
61
- type: TierType;
62
- isMobile?: boolean;
63
- fps?: number;
64
- gpu?: string;
65
- device?: string;
61
+ tier: number;
62
+ type: TierType;
63
+ isMobile?: boolean;
64
+ fps?: number;
65
+ gpu?: string;
66
+ device?: string;
66
67
  };
67
68
  type ModelEntryScreen = [number, number, number, string | undefined];
68
69
  type ModelEntry = [string, string, string, 0 | 1, ModelEntryScreen[]];
69
- declare const getGPUTier: ({ mobileTiers, desktopTiers, override, glContext, failIfMajorPerformanceCaveat, benchmarksURL, }?: GetGPUTier) => Promise<TierResult>;
70
-
71
- export { getGPUTier };
72
- export type { GetGPUTier, ModelEntry, ModelEntryScreen, TierResult, TierType };
70
+ declare const getGPUTier: ({
71
+ mobileTiers,
72
+ desktopTiers,
73
+ override,
74
+ glContext,
75
+ failIfMajorPerformanceCaveat,
76
+ benchmarksURL
77
+ }?: GetGPUTier) => Promise<TierResult>;
78
+ //#endregion
79
+ export { GetGPUTier, ModelEntry, ModelEntryScreen, TierResult, TierType, getGPUTier };
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import{GL_VERTEX_SHADER as J,GL_FRAGMENT_SHADER as Q,GL_ARRAY_BUFFER as M,GL_STATIC_DRAW as ee,GL_FLOAT as te,GL_COLOR_BUFFER_BIT as re,GL_TRIANGLES as ne,GL_RGBA as oe,GL_UNSIGNED_BYTE as ae}from"webgl-constants";const ie="6.0.0",ce=["geforce 320m","geforce 8600","geforce 8600m gt","geforce 8800 gs","geforce 8800 gt","geforce 9400","geforce 9400m g","geforce 9400m","geforce 9600m gt","geforce 9600m","geforce fx go5200","geforce gt 120","geforce gt 130","geforce gt 330m","geforce gtx 285","google swiftshader","intel g41","intel g45","intel gma 4500mhd","intel gma x3100","intel hd 3000","intel q45","legacy","mali-2","mali-3","mali-4","quadro fx 1500","quadro fx 4","quadro fx 5","radeon hd 2400","radeon hd 2600","radeon hd 4670","radeon hd 4850","radeon hd 4870","radeon hd 5670","radeon hd 5750","radeon hd 6290","radeon hd 6300","radeon hd 6310","radeon hd 6320","radeon hd 6490m","radeon hd 6630m","radeon hd 6750m","radeon hd 6770m","radeon hd 6970m","sgx 543","sgx543"];function U(e){return e=e.toLowerCase().replace(/.*angle ?\((.+)\)(?: on vulkan [0-9.]+)?$/i,"$1").replace(/\s(\d{1,2}gb|direct3d.+$)|\(r\)| \([^)]+\)$/g,"").replace(/(?:vulkan|opengl) \d+\.\d+(?:\.\d+)?(?: \((.*)\))?/,"$1"),e}const F=typeof window>"u",w=(()=>{if(F)return;const{userAgent:e,platform:o,maxTouchPoints:s}=window.navigator,a=/(iphone|ipod|ipad)/i.test(e),t=o==="iPad"||o==="MacIntel"&&s>0&&!window.MSStream,r=/android/i.test(e);return{isIpad:t,isMobile:r||a||t,isSafari12:/Version\/12.+Safari/.test(e),isFirefox:/Firefox/.test(e)}})();function se(e,o,s){if(!s)return[o];const a=de(e),t="801621810",r="8016218135",m="80162181161",h="80162181255",c=w?.isIpad?[["a7",m,12],["a8",r,15],["a8x",r,15],["a9",r,15],["a9x",r,15],["a10",r,15],["a10x",r,15],["a12",t,15],["a12x",t,15],["a12z",t,15],["a14",t,15],["a15",t,15],["m1",t,15],["m2",t,15]]:[["a7",m,12],["a8",r,12],["a9",r,15],["a10",r,15],["a11",t,15],["a12",t,15],["a13",t,15],["a14",t,15],["a15",t,15],["a16",t,15],["a17",t,15]];let l;return a===h?l=c.filter(([,,i])=>i>=14):(l=c.filter(([,i])=>i===a),l.length||(l=c)),l.map(([i])=>`apple ${i} gpu`)}function de(e){const o=`
1
+ var e=`6.0.1`;const t=`geforce 320m.geforce 8600.geforce 8600m gt.geforce 8800 gs.geforce 8800 gt.geforce 9400.geforce 9400m g.geforce 9400m.geforce 9600m gt.geforce 9600m.geforce fx go5200.geforce gt 120.geforce gt 130.geforce gt 330m.geforce gtx 285.swiftshader.intel g41.intel g45.intel gma 4500mhd.intel gma x3100.intel hd 3000.intel q45.legacy.mali-2.mali-3.mali-4.quadro fx 1500.quadro fx 4.quadro fx 5.radeon hd 2400.radeon hd 2600.radeon hd 4670.radeon hd 4850.radeon hd 4870.radeon hd 5670.radeon hd 5750.radeon hd 6290.radeon hd 6300.radeon hd 6310.radeon hd 6320.radeon hd 6490m.radeon hd 6630m.radeon hd 6750m.radeon hd 6770m.radeon hd 6970m.sgx 543.sgx543`.split(`.`);function n(e){return e=e.toLowerCase().replace(/.*angle ?\((.+)\)(?: on vulkan [0-9.]+)?$/i,`$1`).replace(/\s(\d{1,2}gb|direct3d.+$)|\(r\)| \([^)]+\)$/g,``).replace(/(?:vulkan|opengl) \d+\.\d+(?:\.\d+)?(?: \((.*)\))?/,`$1`),e}const r=typeof window>`u`;function i(e,t){if(!t)return;let n=/(?:iPhone|CPU) OS (\d+)[._ ;)]/.exec(e),r=/Version\/(\d+)/.exec(e),i=n?parseInt(n[1],10):void 0,a=r?parseInt(r[1],10):void 0;return i!==void 0&&a!==void 0?i>=7&&a>i?a:i:i??a}const a=(()=>{if(r)return;let{userAgent:e,platform:t,maxTouchPoints:n}=window.navigator,a=/(iphone|ipod|ipad)/i.test(e),o=t===`iPad`||t===`MacIntel`&&n>0,s=/android/i.test(e),c=i(e,a||o);return{isIpad:o,isMobile:s||a||o,isSafari12:/Version\/12.+Safari/.test(e),isFirefox:/Firefox/.test(e),iOSVersion:c}})(),o=34962;function s(e,t,n){if(!n)return[t];let r=`801621810`,i=`8016218135`,o=`80162181161`,s=a?.isIpad?[[`a7`,o,12],[`a8`,i,15],[`a8x`,i,15],[`a9`,i,15],[`a9x`,i,15],[`a10`,i,15],[`a10x`,i,15],[`a12`,r,15],[`a12x`,r,15],[`a12z`,r,15],[`a14`,r,15],[`a15`,r,15],[`a16`,r,15],[`a17 pro`,r,15],[`m1`,r,15],[`m2`,r,15],[`m3`,r,15],[`m4`,r,15],[`m5`,r,15]]:[[`a7`,o,12],[`a8`,i,12],[`a9`,i,15],[`a10`,i,15],[`a11`,r,15],[`a12`,r,15],[`a13`,r,15],[`a14`,r,15],[`a15`,r,15],[`a16`,r,15],[`a17 pro`,r,15],[`a18`,r,15],[`a18 pro`,r,15],[`a19`,r,15],[`a19 pro`,r,15]];if(!(a?.iOSVersion!==void 0&&a.iOSVersion>=14)){let t=d(e);if(t===`80162181255`)s=s.filter(([,,e])=>e>=14);else{let e=s.filter(([,e])=>e===t);e.length&&(s=e)}}return s=u(s,a?.iOSVersion,!!a?.isIpad),s.map(([e])=>`apple ${e} gpu`)}const c=[{minIOS:13,iphone:9,ipad:8},{minIOS:16,iphone:10,ipad:9},{minIOS:17,iphone:12,ipad:10},{minIOS:26,iphone:13,ipad:12}];function l(e,t){let n=c.findLast(t=>e>=t.minIOS);return n?t?n.ipad:n.iphone:0}function u(e,t,n){if(!t)return e;let r=l(t,n);return r?e.filter(([e])=>{if(e.startsWith(`m`))return!0;let t=/^a(\d+)/.exec(e);return t?parseInt(t[1],10)>=r:!0}):e}function d(e){let t=e.createShader(35633),n=e.createShader(35632),r=e.createProgram();if(!(n&&t&&r))return;e.shaderSource(t,`
2
2
  precision highp float;
3
3
  attribute vec3 aPosition;
4
4
  varying float vvv;
@@ -6,7 +6,7 @@ import{GL_VERTEX_SHADER as J,GL_FRAGMENT_SHADER as Q,GL_ARRAY_BUFFER as M,GL_STA
6
6
  vvv = 0.31622776601683794;
7
7
  gl_Position = vec4(aPosition, 1.0);
8
8
  }
9
- `,s=`
9
+ `),e.shaderSource(n,`
10
10
  precision highp float;
11
11
  varying float vvv;
12
12
  void main() {
@@ -15,4 +15,4 @@ import{GL_VERTEX_SHADER as J,GL_FRAGMENT_SHADER as Q,GL_ARRAY_BUFFER as M,GL_STA
15
15
  enc -= enc.yzww * vec4(1.0 / 255.0, 1.0 / 255.0, 1.0 / 255.0, 0.0);
16
16
  gl_FragColor = enc;
17
17
  }
18
- `,a=e.createShader(J),t=e.createShader(Q),r=e.createProgram();if(!(t&&a&&r))return;e.shaderSource(a,o),e.shaderSource(t,s),e.compileShader(a),e.compileShader(t),e.attachShader(r,a),e.attachShader(r,t),e.linkProgram(r),e.detachShader(r,a),e.detachShader(r,t),e.deleteShader(a),e.deleteShader(t),e.useProgram(r);const m=e.createBuffer();e.bindBuffer(M,m),e.bufferData(M,new Float32Array([-1,-1,0,3,-1,0,-1,3,0]),ee);const h=e.getAttribLocation(r,"aPosition");e.vertexAttribPointer(h,3,te,!1,0,0),e.enableVertexAttribArray(h),e.clearColor(1,1,1,1),e.clear(re),e.viewport(0,0,1,1),e.drawArrays(ne,0,3);const c=new Uint8Array(4);return e.readPixels(0,0,1,1,oe,ae,c),e.deleteProgram(r),e.deleteBuffer(m),c.join("")}function le(e,o,s){return o==="apple gpu"?se(e,o,s):[o]}class k extends Error{constructor(o){super(o),Object.setPrototypeOf(this,new.target.prototype)}}function fe(e){return e=e.replace(/\([^)]+\)/,""),(e.match(/\d+/)||e.match(/(\W|^)([A-Za-z]{1,3})(\W|$)/g))?.join("").replace(/\W|amd/g,"")??""}const R=[],N=[];function ge(e,o){if(e===o)return 0;const s=e;e.length>o.length&&(e=o,o=s);let a=e.length,t=o.length;for(;a>0&&e.charCodeAt(~-a)===o.charCodeAt(~-t);)a--,t--;let r=0;for(;r<a&&e.charCodeAt(r)===o.charCodeAt(r);)r++;if(a-=r,t-=r,a===0)return t;let m,h=0,c,l,f=0,i=0;for(;f<a;)N[f]=e.charCodeAt(r+f),R[f]=++f;for(;i<t;)for(m=o.charCodeAt(r+i),c=i++,h=i,f=0;f<a;f++)l=m===N[f]?c:c+1,c=R[f],h=R[f]=c>h?l>h?h+1:l:l>c?c+1:l;return h}function he(e){return e.split(/[.,()\[\]/\s]/g).sort().filter((o,s,a)=>s===0||o!==a[s-1]).join(" ")}function ue(e,o=!1){const s={alpha:!1,antialias:!1,depth:!1,failIfMajorPerformanceCaveat:o,powerPreference:"high-performance",stencil:!1};e&&delete s.powerPreference;const a=window.document.createElement("canvas");return(a.getContext("webgl",s)||a.getContext("experimental-webgl",s))??void 0}function me(e){return e!=null}const pe=void 0,ve=async({mobileTiers:e=[0,15,30,60],desktopTiers:o=[0,15,30,60],override:s={},glContext:a,failIfMajorPerformanceCaveat:t=!1,benchmarksURL:r=`https://unpkg.com/@pmndrs/detect-gpu@${ie}/dist/benchmarks`}={})=>{const m={};if(F)return{tier:0,type:"SSR"};const{isIpad:h=!!w?.isIpad,isMobile:c=!!w?.isMobile,screenSize:l=window.screen,loadBenchmarks:f=async n=>{const d=await fetch(`${r}/${n}`).then(u=>u.json());if(parseInt(d.shift().split(".")[0],10)<4)throw new k("Detect GPU benchmark data is out of date. Please update to version 4x");return d}}=s;let{renderer:i}=s;const O=n=>{const d=c?["adreno","apple","mali-t","mali","nvidia","powervr","samsung"]:["intel","apple","amd","radeon","nvidia","geforce","adreno"];for(const u of d)if(n.includes(u))return u};async function j(n){const d=O(n);if(!d)return;const u=`${c?"m":"d"}-${d}${h?"-ipad":""}.json`,A=m[u]=m[u]??f(u);let L;try{L=await A}catch(g){if(g instanceof k)throw g;return}const W=fe(n);let p=L.filter(([,g])=>g===W);p.length||(p=L.filter(([g])=>g.includes(n)),pe?.(`found ${p.length} matching entries comparing model names`,{matched:p}));const $=p.length;if($===0)return;const K=he(n);let[V,,,,z]=$>1?p.map(g=>[g,ge(K,g[2])]).sort(([,g],[,_])=>g-_)[0][0]:p[0],x=Number.MAX_VALUE,P;const{devicePixelRatio:D}=window,q=l.width*D*l.height*D;for(const g of z){const[_,Y]=g,Z=_*Y,I=Math.abs(q-Z);I<x&&(x=I,P=g)}if(!P)return;const[,,X,H]=P;return[x,X,V,H]}const v=(n,d,u,A,L)=>({device:L,fps:A,gpu:u,isMobile:c,tier:n,type:d});let E,b="";if(i)i=U(i),E=[i];else{const n=a||ue(w?.isSafari12,t);if(!n)return v(0,"WEBGL_UNSUPPORTED");const d=w?.isFirefox?null:n.getExtension("WEBGL_debug_renderer_info");if(i=d?n.getParameter(d.UNMASKED_RENDERER_WEBGL):n.getParameter(n.RENDERER),!i)return v(1,"FALLBACK");b=i,i=U(i),E=le(n,i,c)}const C=(await Promise.all(E.map(j))).filter(me).sort(([n=Number.MAX_VALUE,d],[u=Number.MAX_VALUE,A])=>n===u?d-A:n-u);if(!C.length){const n=ce.find(d=>i.includes(d));return n?v(0,"BLOCKLISTED",n):v(1,"FALLBACK",`${i} (${b})`)}const[,S,G,B]=C[0];if(S===-1)return v(0,"BLOCKLISTED",G,S,B);const y=c?e:o;let T=0;for(let n=0;n<y.length;n++)S>=y[n]&&(T=n);return v(T,"BENCHMARK",G,S,B)};export{ve as getGPUTier};
18
+ `),e.compileShader(t),e.compileShader(n),e.attachShader(r,t),e.attachShader(r,n),e.linkProgram(r),e.detachShader(r,t),e.detachShader(r,n),e.deleteShader(t),e.deleteShader(n),e.useProgram(r);let i=e.createBuffer();e.bindBuffer(o,i),e.bufferData(o,new Float32Array([-1,-1,0,3,-1,0,-1,3,0]),35044);let a=e.getAttribLocation(r,`aPosition`);e.vertexAttribPointer(a,3,5126,!1,0,0),e.enableVertexAttribArray(a),e.clearColor(1,1,1,1),e.clear(16384),e.viewport(0,0,1,1),e.drawArrays(4,0,3);let s=new Uint8Array(4);return e.readPixels(0,0,1,1,6408,5121,s),e.deleteProgram(r),e.deleteBuffer(i),s.join(``)}function f(e,t,n){return t===`apple gpu`?s(e,t,n):[t]}function p(e){"@babel/helpers - typeof";return p=typeof Symbol==`function`&&typeof Symbol.iterator==`symbol`?function(e){return typeof e}:function(e){return e&&typeof Symbol==`function`&&e.constructor===Symbol&&e!==Symbol.prototype?`symbol`:typeof e},p(e)}function m(e,t){if(p(e)!=`object`||!e)return e;var n=e[Symbol.toPrimitive];if(n!==void 0){var r=n.call(e,t||`default`);if(p(r)!=`object`)return r;throw TypeError(`@@toPrimitive must return a primitive value.`)}return(t===`string`?String:Number)(e)}function h(e){var t=m(e,`string`);return p(t)==`symbol`?t:t+``}function g(e,t,n){return(t=h(t))in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}var _=class extends Error{constructor(...e){super(...e),g(this,`name`,`OutdatedBenchmarksError`)}};function v(e){return e=e.replace(/\([^)]+\)/,``),(e.match(/\d+/)||e.match(/(\W|^)([A-Za-z]{1,3})(\W|$)/g))?.join(``).replace(/\W|amd/g,``)??``}const y=[],b=[];function x(e,t){if(e===t)return 0;let n=e;e.length>t.length&&(e=t,t=n);let r=e.length,i=t.length;for(;r>0&&e.charCodeAt(r-1)===t.charCodeAt(i-1);)r--,i--;let a=0;for(;a<r&&e.charCodeAt(a)===t.charCodeAt(a);)a++;if(r-=a,i-=a,r===0)return i;let o,s=0,c,l,u=0,d=0;for(;u<r;)b[u]=e.charCodeAt(a+u),y[u]=++u;for(;d<i;)for(o=t.charCodeAt(a+d),c=d++,s=d,u=0;u<r;u++)l=o===b[u]?c:c+1,c=y[u],s=y[u]=c>s?l>s?s+1:l:l>c?c+1:l;return s}function S(e){return e.split(/[.,()[\]/\s]/g).sort().filter((e,t,n)=>t===0||e!==n[t-1]).join(` `)}function C(e,t=!1){let n={alpha:!1,antialias:!1,depth:!1,failIfMajorPerformanceCaveat:t,powerPreference:`high-performance`,stencil:!1};return e&&delete n.powerPreference,window.document.createElement(`canvas`).getContext(`webgl`,n)??void 0}function w(e){return e!=null}const T=async({mobileTiers:i=[0,15,30,60],desktopTiers:o=[0,15,30,60],override:s={},glContext:c,failIfMajorPerformanceCaveat:l=!1,benchmarksURL:u=`https://unpkg.com/@pmndrs/detect-gpu@${e}/dist/benchmarks`}={})=>{let d={},p=!1;if(r)return{tier:0,type:`SSR`};let{isIpad:m=!!a?.isIpad,isMobile:h=!!a?.isMobile,screenSize:g=window.screen,loadBenchmarks:y=async e=>{let[t,...n]=await fetch(`${u}/${e}`).then(e=>e.json());if(parseInt(t.split(`.`)[0],10)<4)throw new _(`Detect GPU benchmark data is out of date. Please update to version 4x`);return n}}=s,{renderer:b}=s,T=e=>{let t=h?[`adreno`,`apple`,`mali-t`,`mali`,`nvidia`,`powervr`,`samsung`]:[`intel`,`apple`,`amd`,`radeon`,`nvidia`,`geforce`,`adreno`];for(let n of t)if(e.includes(n))return n};async function D(e){let t=T(e);if(!t)return;let n=`${h?`m`:`d`}-${t}${m?`-ipad`:``}.json`,r=d[n]=d[n]??y(n),i;try{i=await r}catch(e){if(e instanceof _)throw e;p=!0;return}let a=v(e),o=i.filter(([,e])=>e===a);o.length||(o=i.filter(([t])=>t.includes(e)));let s=o.length;if(s===0)return;let c=S(e),[l,,,,u]=s>1?o.map(e=>[e,x(c,e[2])]).sort(([,e],[,t])=>e-t)[0][0]:o[0],f=Number.MAX_VALUE,b,{devicePixelRatio:C}=window,w=g.width*C*g.height*C;for(let e of u){let[t,n]=e,r=t*n,i=Math.abs(w-r);i<f&&(f=i,b=e)}if(!b)return;let[,,E,D]=b;return[f,E,l,D]}let O=(e,t,n,r,i)=>({device:i,fps:r,gpu:n,isMobile:h,tier:e,type:t}),k,A=``;if(b)b=n(b),k=[b];else{let e=c||C(a?.isSafari12,l);if(!e)return O(0,`WEBGL_UNSUPPORTED`);let t=a?.isFirefox?null:e.getExtension(`WEBGL_debug_renderer_info`);if(b=t?e.getParameter(t.UNMASKED_RENDERER_WEBGL):e.getParameter(e.RENDERER),!b)return O(1,`FALLBACK`);A=b,b=n(b),k=f(e,b,h)}if(!h&&b===`apple gpu`)return O(E(60,o),`BENCHMARK`,`apple m-series`,60);let j=(await Promise.all(k.map(D))).filter(w).sort(([e=Number.MAX_VALUE,t],[n=Number.MAX_VALUE,r])=>e===n?t-r:e-n);if(!j.length){let e=b.replace(/,/g,``),n=t.find(t=>e.includes(t));return n?O(0,`BLOCKLISTED`,n):p?O(1,`BENCHMARK_FETCH_FAILED`,`${b} (${A})`):O(1,`FALLBACK`,`${b} (${A})`)}let[,M,N,P]=j[0];return M===-1?O(0,`BLOCKLISTED`,N,M,P):O(E(M,h?i:o),`BENCHMARK`,N,M,P)};function E(e,t){for(let n=t.length-1;n>=0;n--)if(e>=t[n])return n;return 0}export{T as getGPUTier};
package/package.json CHANGED
@@ -1,107 +1,80 @@
1
- {
2
- "name": "@pmndrs/detect-gpu",
3
- "version": "6.0.0",
4
- "description": "Classify GPU's based on their benchmark score in order to provide an adaptive experience.",
5
- "author": "Tim van Scherpenzeel",
6
- "license": "MIT",
7
- "type": "module",
8
- "exports": {
9
- ".": {
10
- "types": "./dist/index.d.ts",
11
- "import": "./dist/index.mjs"
12
- }
13
- },
14
- "main": "./dist/index.mjs",
15
- "module": "./dist/index.mjs",
16
- "types": "./dist/index.d.ts",
17
- "homepage": "https://github.com/pmndrs/detect-gpu#readme",
18
- "bugs": {
19
- "url": "https://github.com/pmndrs/detect-gpu/issues"
20
- },
21
- "repository": {
22
- "type": "git",
23
- "url": "https://github.com/pmndrs/detect-gpu.git"
24
- },
25
- "publishConfig": {
26
- "access": "public"
27
- },
28
- "files": [
29
- "dist"
30
- ],
31
- "keywords": [
32
- "gpu",
33
- "detect",
34
- "webgl",
35
- "webgl2",
36
- "three.js",
37
- "babylonjs",
38
- "three",
39
- "babylon",
40
- "3d",
41
- "typescript",
42
- "javascript"
43
- ],
44
- "scripts": {
45
- "lint": "eslint src test scripts --fix --cache",
46
- "test": "jest --verbose=false",
47
- "test:watch": "jest --watch",
48
- "test:coverage": "jest --coverage",
49
- "test:debug": "node --inspect-brk ./node_modules/jest/bin/jest --runInBand --no-cache --watch",
50
- "prebuild": "rimraf dist",
51
- "build": "unbuild",
52
- "parse-analytics": "node ./scripts/analytics_parser.js",
53
- "update-benchmarks": "tsx ./scripts/update_benchmarks.ts"
54
- },
55
- "dependencies": {
56
- "webgl-constants": "^1.1.1"
57
- },
58
- "devDependencies": {
59
- "@eslint/js": "^9.0.0",
60
- "@types/jest": "^29.5.3",
61
- "@types/tar": "^6.1.0",
62
- "csvtojson": "^2.0.10",
63
- "eslint": "^9.0.0",
64
- "eslint-config-prettier": "^9.0.0",
65
- "globals": "^15.0.0",
66
- "jest": "^29.6.2",
67
- "jest-environment-jsdom": "^29.6.2",
68
- "prettier": "^3.0.1",
69
- "puppeteer": "^23.0.0",
70
- "rimraf": "^5.0.1",
71
- "tar": "^7.0.0",
72
- "ts-jest": "^29.1.1",
73
- "tsx": "^4.7.0",
74
- "typescript": "^5.5.4",
75
- "typescript-eslint": "^8.0.0",
76
- "unbuild": "^2.0.0"
77
- },
78
- "jest": {
79
- "testEnvironment": "jsdom",
80
- "testEnvironmentOptions": {
81
- "url": "http://localhost"
82
- },
83
- "moduleFileExtensions": [
84
- "js",
85
- "ts"
86
- ],
87
- "testMatch": [
88
- "**/test/**/*.test.ts"
89
- ],
90
- "testPathIgnorePatterns": [
91
- "<rootDir>/test/data.ts"
92
- ],
93
- "preset": "ts-jest",
94
- "transform": {
95
- "^.+\\.tsx?$": [
96
- "ts-jest",
97
- {
98
- "tsconfig": "tsconfig.json",
99
- "useESM": true
100
- }
101
- ]
102
- },
103
- "extensionsToTreatAsEsm": [
104
- ".ts"
105
- ]
106
- }
107
- }
1
+ {
2
+ "name": "@pmndrs/detect-gpu",
3
+ "version": "6.0.2",
4
+ "packageManager": "pnpm@10.13.1",
5
+ "engines": {
6
+ "node": ">=24"
7
+ },
8
+ "description": "Classify GPU's based on their benchmark score in order to provide an adaptive experience.",
9
+ "author": "Tim van Scherpenzeel",
10
+ "license": "MIT",
11
+ "type": "module",
12
+ "exports": {
13
+ ".": {
14
+ "types": "./dist/index.d.ts",
15
+ "import": "./dist/index.mjs"
16
+ }
17
+ },
18
+ "main": "./dist/index.mjs",
19
+ "module": "./dist/index.mjs",
20
+ "types": "./dist/index.d.ts",
21
+ "homepage": "https://github.com/pmndrs/detect-gpu#readme",
22
+ "bugs": {
23
+ "url": "https://github.com/pmndrs/detect-gpu/issues"
24
+ },
25
+ "repository": {
26
+ "type": "git",
27
+ "url": "https://github.com/pmndrs/detect-gpu.git"
28
+ },
29
+ "publishConfig": {
30
+ "access": "public"
31
+ },
32
+ "pnpm": {
33
+ "onlyBuiltDependencies": [
34
+ "esbuild"
35
+ ]
36
+ },
37
+ "files": [
38
+ "dist"
39
+ ],
40
+ "keywords": [
41
+ "gpu",
42
+ "detect",
43
+ "webgl",
44
+ "webgl2",
45
+ "three.js",
46
+ "babylonjs",
47
+ "three",
48
+ "babylon",
49
+ "3d",
50
+ "typescript",
51
+ "javascript"
52
+ ],
53
+ "scripts": {
54
+ "lint": "oxlint --type-aware --fix",
55
+ "format": "oxfmt",
56
+ "format:check": "oxfmt --check",
57
+ "test": "vitest run",
58
+ "test:watch": "vitest",
59
+ "test:coverage": "vitest run --coverage",
60
+ "build": "tsdown",
61
+ "dev": "pnpm run --parallel /^dev:/",
62
+ "dev:build": "tsdown --watch",
63
+ "dev:serve": "echo 'open http://localhost:8000/local.html' && python3 -m http.server 8000",
64
+ "update-benchmarks": "node ./scripts/update_benchmarks.ts"
65
+ },
66
+ "devDependencies": {
67
+ "@types/node": "^25.6.0",
68
+ "@types/tar": "^7.0.87",
69
+ "@vitest/coverage-v8": "^4.1.4",
70
+ "csv-parse": "^6.2.1",
71
+ "jsdom": "^29.0.2",
72
+ "oxfmt": "^0.44.0",
73
+ "oxlint": "^1.59.0",
74
+ "oxlint-tsgolint": "^0.21.1",
75
+ "tar": "^7.0.0",
76
+ "tsdown": "^0.21.7",
77
+ "typescript": "^6.0.2",
78
+ "vitest": "^4.1.4"
79
+ }
80
+ }
package/dist/index.d.ts DELETED
@@ -1,72 +0,0 @@
1
- interface GetGPUTier {
2
- /**
3
- * URL of directory where benchmark data is hosted.
4
- *
5
- * @default https://unpkg.com/@pmndrs/detect-gpu@{version}/dist/benchmarks
6
- */
7
- benchmarksURL?: string;
8
- /**
9
- * Optionally pass in a WebGL context to avoid creating a temporary one
10
- * internally.
11
- */
12
- glContext?: WebGLRenderingContext | WebGL2RenderingContext;
13
- /**
14
- * Whether to fail if the system performance is low or if no hardware GPU is
15
- * available.
16
- *
17
- * @default false
18
- */
19
- failIfMajorPerformanceCaveat?: boolean;
20
- /**
21
- * Framerate per tier for mobile devices.
22
- *
23
- * @defaultValue [0, 15, 30, 60]
24
- */
25
- mobileTiers?: number[];
26
- /**
27
- * Framerate per tier for desktop devices.
28
- *
29
- * @defaultValue [0, 15, 30, 60]
30
- */
31
- desktopTiers?: number[];
32
- /**
33
- * Optionally override specific parameters. Used mainly for testing.
34
- */
35
- override?: {
36
- renderer?: string;
37
- /**
38
- * Override whether device is an iPad.
39
- */
40
- isIpad?: boolean;
41
- /**
42
- * Override whether device is a mobile device.
43
- */
44
- isMobile?: boolean;
45
- /**
46
- * Override device screen size.
47
- */
48
- screenSize?: {
49
- width: number;
50
- height: number;
51
- };
52
- /**
53
- * Override how benchmark data is loaded
54
- */
55
- loadBenchmarks?: (file: string) => Promise<ModelEntry[]>;
56
- };
57
- }
58
- type TierType = 'SSR' | 'WEBGL_UNSUPPORTED' | 'BLOCKLISTED' | 'FALLBACK' | 'BENCHMARK';
59
- type TierResult = {
60
- tier: number;
61
- type: TierType;
62
- isMobile?: boolean;
63
- fps?: number;
64
- gpu?: string;
65
- device?: string;
66
- };
67
- type ModelEntryScreen = [number, number, number, string | undefined];
68
- type ModelEntry = [string, string, string, 0 | 1, ModelEntryScreen[]];
69
- declare const getGPUTier: ({ mobileTiers, desktopTiers, override, glContext, failIfMajorPerformanceCaveat, benchmarksURL, }?: GetGPUTier) => Promise<TierResult>;
70
-
71
- export { getGPUTier };
72
- export type { GetGPUTier, ModelEntry, ModelEntryScreen, TierResult, TierType };