├── .editorconfig ├── .eslintignore ├── .eslintrc.js ├── .github └── workflows │ ├── test.yml │ └── update-benchmark.yml ├── .gitignore ├── .npmrc ├── .prettierrc.json ├── CHANGELOG.md ├── LICENSE ├── README.md ├── benchmarks.tar.gz ├── benchmarks ├── d-adreno.json ├── d-amd.json ├── d-apple.json ├── d-geforce.json ├── d-intel.json ├── d-nvidia.json ├── d-radeon.json ├── m-adreno.json ├── m-apple-ipad.json ├── m-apple.json ├── m-intel.json ├── m-mali-t.json ├── m-mali.json ├── m-nvidia.json ├── m-powervr.json └── m-samsung.json ├── data └── analytics.csv ├── example ├── index.html └── index.ts ├── index.html ├── package.json ├── rollup ├── config.dev.ts └── config.lib.ts ├── scripts ├── analytics_embed.js ├── analytics_parser.js ├── internalBenchmarkResults.ts ├── types.ts └── update_benchmarks.ts ├── src ├── index.ts └── internal │ ├── blocklistedGPUS.ts │ ├── cleanRenderer.ts │ ├── deobfuscateAppleGPU.ts │ ├── deobfuscateRenderer.ts │ ├── deviceInfo.ts │ ├── error.ts │ ├── getGPUVersion.ts │ ├── getLevenshteinDistance.ts │ ├── getWebGLContext.ts │ ├── ssr.ts │ └── util.ts ├── test ├── data.ts ├── index.test.ts ├── ssr.test.ts └── utils.ts ├── tsconfig.json └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | insert_final_newline = true 5 | trim_trailing_whitespace = true 6 | indent_style = space 7 | indent_size = 2 8 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | /node_modules/ 2 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | const OFF = 0; 2 | const WARN = 1; 3 | const ERROR = 2; 4 | 5 | module.exports = { 6 | env: { 7 | node: true, 8 | }, 9 | extends: [ 10 | 'plugin:@typescript-eslint/recommended', 11 | 'prettier', 12 | ], 13 | overrides: [{ 14 | files: ['*.js'], 15 | rules: { 16 | '@typescript-eslint/no-var-requires': 'off' 17 | } 18 | }], 19 | parser: '@typescript-eslint/parser', 20 | parserOptions: { 21 | ecmaVersion: 2018, 22 | sourceType: 'module', 23 | }, 24 | rules: { 25 | '@typescript-eslint/ban-ts-ignore': OFF, 26 | '@typescript-eslint/explicit-module-boundary-types': OFF, 27 | '@typescript-eslint/no-explicit-any': WARN 28 | } 29 | }; 30 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Run actions on Pull Request or Push 2 | on: 3 | push: 4 | branches: 5 | - master 6 | pull_request: 7 | branches: 8 | - master 9 | types: 10 | - opened 11 | - synchronize 12 | - reopened 13 | - ready_for_review 14 | 15 | jobs: 16 | test: 17 | name: Run test & lint 18 | runs-on: Ubuntu-20.04 19 | steps: 20 | - uses: actions/checkout@v4 21 | - uses: actions/setup-node@v4 22 | with: 23 | node-version: '18.x' 24 | - uses: actions/cache@v4 25 | id: yarn-cache 26 | with: 27 | path: | 28 | node_modules 29 | */*/node_modules 30 | key: ${{ runner.os }}-install-${{ hashFiles('**/yarn.lock') }} 31 | - run: yarn install 32 | if: ${{ steps.yarn-cache.outputs.cache-hit != 'true' }} 33 | 34 | - run: yarn install --prefers-offline 35 | if: ${{ steps.yarn-cache.outputs.cache-hit == 'true' }} 36 | 37 | - run: yarn run test 38 | - run: yarn run lint 39 | -------------------------------------------------------------------------------- /.github/workflows/update-benchmark.yml: -------------------------------------------------------------------------------- 1 | name: Weekly update 2 | on: 3 | schedule: 4 | - cron: "0 0 * * 0" 5 | workflow_dispatch: 6 | 7 | jobs: 8 | auto-update: 9 | name: Automated benchmarks update 10 | runs-on: Ubuntu-20.04 11 | 12 | steps: 13 | - uses: actions/checkout@v4 14 | with: 15 | ref: ${{ github.head_ref }} 16 | - uses: actions/setup-node@v4 17 | with: 18 | node-version: '18.x' 19 | - uses: actions/cache@v4 20 | id: yarn-cache 21 | with: 22 | path: | 23 | node_modules 24 | */*/node_modules 25 | key: ${{ runner.os }}-install-${{ hashFiles('**/yarn.lock') }} 26 | - run: yarn install 27 | if: ${{ steps.yarn-cache.outputs.cache-hit != 'true' }} 28 | 29 | - run: yarn install --prefers-offline 30 | if: ${{ steps.yarn-cache.outputs.cache-hit == 'true' }} 31 | 32 | - name: Bump patch 33 | run: npm version patch --no-git-tag-version 34 | 35 | - name: Update 36 | id: update 37 | run: yarn run update-benchmarks 38 | 39 | - name: Build final result 40 | run: yarn build 41 | 42 | - uses: JS-DevTools/npm-publish@v1 43 | with: 44 | token: ${{ secrets.NPM_TOKEN }} 45 | access: public 46 | 47 | - name: Push Changes 48 | uses: stefanzweifel/git-auto-commit-action@v4 49 | with: 50 | commit_message: Automated weekly update of the benchmark. 51 | skip_dirty_check: true 52 | skip_fetch: true 53 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # ============================================================================ # 2 | # Operating System Files 3 | # ============================================================================ # 4 | 5 | # Windows 6 | web.config 7 | ehthumbs.db 8 | ehthumbs_vista.db 9 | [Tt]humbs.db 10 | Desktop.ini 11 | $RECYCLE.BIN/ 12 | 13 | # MacOS / Mac OS X 14 | ._* 15 | .DS_Store 16 | .DS_Store? 17 | .AppleDouble 18 | .LSOverride 19 | .Spotlight-V100 20 | .Trashes 21 | Icon? 22 | 23 | # Linux 24 | *~ 25 | .directory 26 | 27 | # ============================================================================ # 28 | # Logs 29 | # ============================================================================ # 30 | 31 | # Logs 32 | *.log 33 | 34 | # ============================================================================ # 35 | # IDE / Editor 36 | # ============================================================================ # 37 | 38 | # Sublime Text 39 | *.tmlanguage.cache 40 | *.tmPreferences.cache 41 | *.stTheme.cache 42 | *.sublime-workspace 43 | *.sublime-project 44 | sftp-config.json 45 | 46 | # Visual Studio Code 47 | .vscode/* 48 | !.vscode/settings.json 49 | !.vscode/tasks.json 50 | !.vscode/launch.json 51 | !.vscode/extensions.json 52 | 53 | # Visual Studio 54 | .vs 55 | 56 | # XCode 57 | xcuserdata/ 58 | 59 | # ============================================================================ # 60 | # Languages 61 | # ============================================================================ # 62 | 63 | # Typescript 64 | node_modules 65 | 66 | # ============================================================================ # 67 | # Application 68 | # ============================================================================ # 69 | 70 | # Directories 71 | dist 72 | /example/build/* 73 | /coverage 74 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | package-lock=false 2 | -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "semi": true, 3 | "singleQuote": true, 4 | "trailingComma": "es5", 5 | "printWidth": 80 6 | } 7 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # CHANGELOG 2 | 3 | Patch version updates, unless noted otherwise, are automated benchmark updates ran weekly by our CI. 4 | 5 | # 4.0.0 6 | 7 | - Split apple mobile benchmark data into two files (apple and apple-ipad) **BREAKING CHANGE** 8 | - Throw when benchmark data is incompatible with library **BREAKING CHANGE** 9 | - Improved iOS device deobfuscation / detection (see https://github.com/pmndrs/detect-gpu/issues/77) 10 | - With multiple results of the same resolution, the one with the lowest fps is picked 11 | - Fixed detection of M1 desktop gpus on non Safari browsers (see https://github.com/pmndrs/detect-gpu/issues/84) 12 | 13 | # 3.1.3 14 | 15 | - Build files included the wrong benchmark version number 16 | - Removed unused Travis build file 17 | 18 | # 3.1.2 (IGNORE) 19 | 20 | - iPhone 12 Pro Max was being reported as iPhone 11 Pro Max due to wrong resolution in `scripts/internalBenchmarkResults.ts` 21 | 22 | # 3.1.1 23 | 24 | - Return raw renderer string if WebGL renderer has been found but is not included in the benchmarks 25 | 26 | # 3.1.0 27 | 28 | - Update README.md 29 | - Update benchmarks (added support for RTX 3060 / RTX 3070) 30 | - Fixed test suite 31 | 32 | # 3.0.0 33 | 34 | - Fixed SSR functionality 35 | - Changed 'IS_SRR' tier type to 'SSR' **BREAKING CHANGE** 36 | - Fixed issue where errors were being thrown when running in non-browser environments 37 | - Removed undefined from return type of `loadBenchmarks` override 38 | 39 | # 2.0.4 40 | 41 | - Update package.json to provide more information when published on NPM 42 | 43 | # 2.0.3 44 | 45 | - Update README.md 46 | 47 | # 2.0.2 48 | 49 | - Fixed package publishing issue 50 | 51 | # 2.0.1 52 | 53 | - Fixed issue with wrong path to types in `package.json` 54 | 55 | # 2.0.0 56 | 57 | ## API 58 | 59 | ```ts 60 | import { getGPUTier } from 'detect-gpu'; 61 | 62 | const GPUTier = getGPUTier({ 63 | glContext: gl, // Optionally pass in a WebGL context to avoid creating a temporary one internally 64 | mobileBenchmarkPercentages: [0, 50, 30, 20], // (Default) [TIER_0, TIER_1, TIER_2, TIER_3] 65 | desktopBenchmarkPercentages: [0, 50, 30, 20], // (Default) [TIER_0, TIER_1, TIER_2, TIER_3] 66 | failIfMajorPerformanceCaveat: true, // (Default) Fail to detect if the WebGL implementation determines the performance would be dramatically lower than the equivalent OpenGL implementation 67 | forceRendererString: 'Apple A11 GPU', // (Development) Force a certain renderer string 68 | forceMobile: true, // (Development) Force the use of mobile benchmarking scores 69 | }); 70 | 71 | // Example output: 72 | // { 73 | // "tier": GPU_DESKTOP_TIER_1, 74 | // "type": "BENCHMARK - intel iris graphics 6100", 75 | // } 76 | ``` 77 | 78 | turns into 79 | 80 | ```ts 81 | import { getGPUTier } from 'detect-gpu'; 82 | 83 | (async () => { 84 | const gpuTier = await getGPUTier({ 85 | benchmarksURL?: string; // (Default, "https://unpkg.com/detect-gpu@${PKG_VERSION}/dist/benchmarks") Provide location of where to access benchmark data 86 | failIfMajorPerformanceCaveat?: boolean; // (Default, false) Fail to detect if the WebGL implementation determines the performance would be dramatically lower than the equivalent OpenGL 87 | glContext?: WebGLRenderingContext | WebGL2RenderingContext; // (Default, undefined) Optionally pass in a WebGL context to avoid creating a temporary one internally 88 | desktopTiers?: number[]; // (Default, [0, 15, 30, 60]) Framerate per tier 89 | mobileTiers?: number[]; // (Default, [0, 15, 30, 60]) Framerate per tier 90 | override?: { // (Default, false) Override specific functionality, useful for development 91 | renderer?: string; // Manually override reported GPU renderer string 92 | isIpad?: boolean; // Manually report device as being an iPad 93 | isMobile?: boolean; // Manually report device as being a mobile device 94 | screenSize?: { width: number; height: number }; // Manually adjust reported screenSize 95 | loadBenchmarks?: (file: string) => Promise; // Optionally modify method for loading benchmark data 96 | }; 97 | }) 98 | 99 | // Example output: 100 | // { 101 | // "tier": 1, 102 | // "isMobile": false, 103 | // "type": "BENCHMARK", 104 | // "fps": 21, 105 | // "gpu": "intel iris graphics 6100" 106 | // } 107 | })(); 108 | ``` 109 | 110 | Please note that `getGPUTier` now returns a `Promise`, this wasn't the case before. 111 | 112 | Please note that the benchmark tier is now picked based on a `resolution normalized fps` instead of dividing the benchmark list into % chuncks and determining it that way. 113 | 114 | ## Benchmark data 115 | 116 | Previously the benchmark data was included inside of the `detect-gpu` bundle. By default we now use the benchmark data served on `https://unpkg.com/detect-gpu@${pkg.version}/dist/benchmarks` but you can also serve the benchmark data yourself. 117 | 118 | This is possible by downloading [benchmarks.tar.gz](https://github.com/TimvanScherpenzeel/detect-gpu/raw/master/benchmarks.tar.gz) and serving it from a public directory on your webserver (optimal, prevents loading of redundant benchmarks) like this: 119 | 120 | ```ts 121 | // Application 122 | import { getGPUTier } from '../src'; 123 | 124 | (async () => { 125 | const data = await getGPUTier({ 126 | benchmarksURL: '/benchmarks', 127 | }); 128 | })(); 129 | ``` 130 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Tim van Scherpenzeel 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Detect GPU 2 | 3 | [![npm version](https://badge.fury.io/js/detect-gpu.svg)](https://badge.fury.io/js/detect-gpu) 4 | [![gzip size](https://img.badgesize.io/https:/unpkg.com/detect-gpu/dist/detect-gpu.esm.js?compression=gzip)](https://unpkg.com/detect-gpu) 5 | [![install size](https://packagephobia.now.sh/badge?p=detect-gpu)](https://packagephobia.now.sh/result?p=detect-gpu) 6 | 7 | Classifies GPUs based on their 3D rendering benchmark score allowing the developer to provide sensible default settings for graphically intensive applications. Think of it like a user-agent detection for the GPU but more powerful. 8 | 9 | ## Demo 10 | 11 | [Live demo](https://pmndrs.github.io/detect-gpu/) 12 | 13 | ## Installation 14 | 15 | By default we use the [UNPKG](https://unpkg.com) CDN to host the benchmark data. If you would like to serve the benchmark data yourself download the required benchmarking data from [benchmarks.tar.gz](https://github.com/pmndrs/detect-gpu/raw/master/benchmarks.tar.gz) and serve it from a public directory. 16 | 17 | Make sure you have [Node.js](http://nodejs.org/) installed. 18 | 19 | ```sh 20 | $ npm install detect-gpu 21 | ``` 22 | 23 | ## Usage 24 | 25 | ```ts 26 | import { getGPUTier } from 'detect-gpu'; 27 | 28 | (async () => { 29 | const gpuTier = await getGPUTier(); 30 | 31 | // Example output: 32 | // { 33 | // "tier": 1, 34 | // "isMobile": false, 35 | // "type": "BENCHMARK", 36 | // "fps": 21, 37 | // "gpu": "intel iris graphics 6100" 38 | // } 39 | })(); 40 | ``` 41 | 42 | `detect-gpu` uses rendering benchmark scores (framerate, normalized by resolution) in order to determine what tier should be assigned to the user's GPU. If no `WebGLContext` can be created, the GPU is blocklisted or the GPU has reported to render on less than `15 fps` `tier: 0` is assigned. One should provide a fallback to a non-WebGL experience. 43 | 44 | Based on the reported `fps` the GPU is then classified into either `tier: 1 (>= 15 fps)`, `tier: 2 (>= 30 fps)` or `tier: 3 (>= 60 fps)`. The higher the tier the more graphically intensive workload you can offer to the user. 45 | 46 | ## API 47 | 48 | ```ts 49 | getGPUTier({ 50 | /** 51 | * URL of directory where benchmark data is hosted. 52 | * 53 | * @default https://unpkg.com/detect-gpu@{version}/dist/benchmarks 54 | */ 55 | benchmarksURL?: string; 56 | /** 57 | * Optionally pass in a WebGL context to avoid creating a temporary one 58 | * internally. 59 | */ 60 | glContext?: WebGLRenderingContext | WebGL2RenderingContext; 61 | /** 62 | * Whether to fail if the system performance is low or if no hardware GPU is 63 | * available. 64 | * 65 | * @default false 66 | */ 67 | failIfMajorPerformanceCaveat?: boolean; 68 | /** 69 | * Framerate per tier for mobile devices. 70 | * 71 | * @defaultValue [0, 15, 30, 60] 72 | */ 73 | mobileTiers?: number[]; 74 | /** 75 | * Framerate per tier for desktop devices. 76 | * 77 | * @defaultValue [0, 15, 30, 60] 78 | */ 79 | desktopTiers?: number[]; 80 | /** 81 | * Optionally override specific parameters. Used mainly for testing. 82 | */ 83 | override?: { 84 | renderer?: string; 85 | /** 86 | * Override whether device is an iPad. 87 | */ 88 | isIpad?: boolean; 89 | /** 90 | * Override whether device is a mobile device. 91 | */ 92 | isMobile?: boolean; 93 | /** 94 | * Override device screen size. 95 | */ 96 | screenSize?: { width: number; height: number }; 97 | /** 98 | * Override how benchmark data is loaded 99 | */ 100 | loadBenchmarks?: (file: string) => Promise; 101 | }; 102 | }) 103 | ``` 104 | 105 | ## Support 106 | 107 | Special care has been taken to make sure all browsers that support `WebGL` are also supported by `detect-gpu` including `IE 11`. 108 | 109 | ## Changelog 110 | 111 | [Changelog](CHANGELOG.md) 112 | 113 | ## Licence 114 | 115 | My work is released under the [MIT license](https://raw.githubusercontent.com/pmndrs/detect-gpu/master/LICENSE). 116 | 117 | `detect-gpu` uses both mobile and desktop benchmarking scores from [https://gfxbench.com](https://gfxbench.com). 118 | -------------------------------------------------------------------------------- /benchmarks.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmndrs/detect-gpu/8c81b70ee82310d2c1fd388254368ab5f71241d5/benchmarks.tar.gz -------------------------------------------------------------------------------- /benchmarks/d-adreno.json: -------------------------------------------------------------------------------- 1 | [ 2 | "5", 3 | [ 4 | "qualcomm adreno 540", 5 | "540", 6 | "540 adreno qualcomm", 7 | 0, 8 | [ 9 | [ 10 | 1919, 11 | 1279, 12 | 19 13 | ] 14 | ] 15 | ], 16 | [ 17 | "qualcomm adreno 540 gpu", 18 | "540", 19 | "540 adreno gpu qualcomm", 20 | 0, 21 | [ 22 | [ 23 | 1919, 24 | 1279, 25 | 24 26 | ] 27 | ] 28 | ], 29 | [ 30 | "qualcomm adreno 618 gpu", 31 | "618", 32 | "618 adreno gpu qualcomm", 33 | 0, 34 | [ 35 | [ 36 | 1920, 37 | 1080, 38 | 20 39 | ] 40 | ] 41 | ], 42 | [ 43 | "qualcomm adreno 630 gpu", 44 | "630", 45 | "630 adreno gpu qualcomm", 46 | 0, 47 | [ 48 | [ 49 | 1920, 50 | 1080, 51 | 21 52 | ] 53 | ] 54 | ], 55 | [ 56 | "qualcomm adreno 675 gpu", 57 | "675", 58 | "675 adreno gpu qualcomm", 59 | 0, 60 | [ 61 | [ 62 | 1920, 63 | 1080, 64 | 58 65 | ] 66 | ] 67 | ], 68 | [ 69 | "qualcomm adreno 680 gpu", 70 | "680", 71 | "680 adreno gpu qualcomm", 72 | 0, 73 | [ 74 | [ 75 | 2880, 76 | 1920, 77 | 24 78 | ] 79 | ] 80 | ], 81 | [ 82 | "qualcomm adreno 685 gpu", 83 | "685", 84 | "685 adreno gpu qualcomm", 85 | 0, 86 | [ 87 | [ 88 | 1920, 89 | 1080, 90 | 28 91 | ], 92 | [ 93 | 2560, 94 | 1600, 95 | 58 96 | ] 97 | ] 98 | ], 99 | [ 100 | "qualcomm adreno 690 gpu", 101 | "690", 102 | "690 adreno gpu qualcomm", 103 | 0, 104 | [ 105 | [ 106 | 1920, 107 | 1080, 108 | 60 109 | ], 110 | [ 111 | 1920, 112 | 1280, 113 | 28 114 | ] 115 | ] 116 | ], 117 | [ 118 | "qualcomm adreno 7c+ gen 3", 119 | "7", 120 | "3 7c+ adreno gen qualcomm", 121 | 0, 122 | [ 123 | [ 124 | 1920, 125 | 1080, 126 | 44 127 | ] 128 | ] 129 | ], 130 | [ 131 | "qualcomm adreno 8cx gen 3", 132 | "8", 133 | "3 8cx adreno gen qualcomm", 134 | 0, 135 | [ 136 | [ 137 | 1920, 138 | 1080, 139 | 22 140 | ], 141 | [ 142 | 1920, 143 | 1200, 144 | 60 145 | ] 146 | ] 147 | ], 148 | [ 149 | "qualcomm adreno 8cx gen 4", 150 | "8", 151 | "4 8cx adreno gen qualcomm", 152 | 0, 153 | [ 154 | [ 155 | 2880, 156 | 1800, 157 | 60 158 | ] 159 | ] 160 | ], 161 | [ 162 | "qualcomm adreno x1-45 gpu", 163 | "1", 164 | "adreno gpu qualcomm x1-45", 165 | 0, 166 | [ 167 | [ 168 | 2880, 169 | 1800, 170 | 58 171 | ] 172 | ] 173 | ], 174 | [ 175 | "qualcomm mi pad 5 adreno 640 gpu", 176 | "5", 177 | "5 640 adreno gpu mi pad qualcomm", 178 | 0, 179 | [ 180 | [ 181 | 2560, 182 | 1600, 183 | 34 184 | ] 185 | ] 186 | ], 187 | [ 188 | "qualcomm snapdragon x elite - x1e78100 - qualcomm adreno gpu", 189 | "1", 190 | "- adreno elite gpu qualcomm snapdragon x x1e78100", 191 | 0, 192 | [ 193 | [ 194 | 2880, 195 | 1620, 196 | 115 197 | ] 198 | ] 199 | ], 200 | [ 201 | "qualcomm snapdragon x elite - x1e80100 - qualcomm adreno gpu", 202 | "1", 203 | "- adreno elite gpu qualcomm snapdragon x x1e80100", 204 | 0, 205 | [ 206 | [ 207 | 2496, 208 | 1664, 209 | 60 210 | ] 211 | ] 212 | ], 213 | [ 214 | "qualcomm snapdragon x elite - x1e84100 - qualcomm adreno gpu", 215 | "1", 216 | "- adreno elite gpu qualcomm snapdragon x x1e84100", 217 | 0, 218 | [ 219 | [ 220 | 2880, 221 | 1800, 222 | 60 223 | ] 224 | ] 225 | ] 226 | ] -------------------------------------------------------------------------------- /benchmarks/d-apple.json: -------------------------------------------------------------------------------- 1 | [ 2 | "5", 3 | [ 4 | "apple a14", 5 | "14", 6 | "a14 apple", 7 | 0, 8 | [ 9 | [ 10 | 2704, 11 | 1756, 12 | 120 13 | ] 14 | ] 15 | ], 16 | [ 17 | "apple m1", 18 | "1", 19 | "apple m1", 20 | 0, 21 | [ 22 | [ 23 | 2880, 24 | 1800, 25 | 198 26 | ] 27 | ] 28 | ], 29 | [ 30 | "apple m1 max", 31 | "1", 32 | "apple m1 max", 33 | 0, 34 | [ 35 | [ 36 | 3456, 37 | 2234, 38 | 556 39 | ] 40 | ] 41 | ], 42 | [ 43 | "apple m1 pro", 44 | "1", 45 | "apple m1 pro", 46 | 0, 47 | [ 48 | [ 49 | 3024, 50 | 1964, 51 | 378 52 | ] 53 | ] 54 | ], 55 | [ 56 | "apple m1 ultra", 57 | "1", 58 | "apple m1 ultra", 59 | 0, 60 | [ 61 | [ 62 | 5120, 63 | 2880, 64 | 437 65 | ] 66 | ] 67 | ], 68 | [ 69 | "apple m2", 70 | "2", 71 | "apple m2", 72 | 0, 73 | [ 74 | [ 75 | 2880, 76 | 1800, 77 | 60 78 | ], 79 | [ 80 | 2940, 81 | 1912, 82 | 209 83 | ] 84 | ] 85 | ], 86 | [ 87 | "apple m2 max", 88 | "2", 89 | "apple m2 max", 90 | 0, 91 | [ 92 | [ 93 | 3456, 94 | 2234, 95 | 120 96 | ] 97 | ] 98 | ], 99 | [ 100 | "apple m2 pro", 101 | "2", 102 | "apple m2 pro", 103 | 0, 104 | [ 105 | [ 106 | 3024, 107 | 1964, 108 | 120 109 | ], 110 | [ 111 | 5120, 112 | 2880, 113 | 60 114 | ] 115 | ] 116 | ], 117 | [ 118 | "apple m2 ultra", 119 | "2", 120 | "apple m2 ultra", 121 | 0, 122 | [ 123 | [ 124 | 5120, 125 | 2880, 126 | 60 127 | ] 128 | ] 129 | ], 130 | [ 131 | "apple m3", 132 | "3", 133 | "apple m3", 134 | 0, 135 | [ 136 | [ 137 | 2940, 138 | 1912, 139 | 60 140 | ], 141 | [ 142 | 4480, 143 | 2520, 144 | 60 145 | ] 146 | ] 147 | ], 148 | [ 149 | "apple m3 max", 150 | "3", 151 | "apple m3 max", 152 | 0, 153 | [ 154 | [ 155 | 3456, 156 | 2234, 157 | 120 158 | ] 159 | ] 160 | ], 161 | [ 162 | "apple m3 pro", 163 | "3", 164 | "apple m3 pro", 165 | 0, 166 | [ 167 | [ 168 | 3024, 169 | 1964, 170 | 120 171 | ] 172 | ] 173 | ], 174 | [ 175 | "apple m4", 176 | "4", 177 | "apple m4", 178 | 0, 179 | [ 180 | [ 181 | 1920, 182 | 1080, 183 | 144 184 | ] 185 | ] 186 | ], 187 | [ 188 | "apple m4 max", 189 | "4", 190 | "apple m4 max", 191 | 0, 192 | [ 193 | [ 194 | 3024, 195 | 1964, 196 | 120 197 | ], 198 | [ 199 | 3456, 200 | 2234, 201 | 120 202 | ] 203 | ] 204 | ], 205 | [ 206 | "apple m4 pro", 207 | "4", 208 | "apple m4 pro", 209 | 0, 210 | [ 211 | [ 212 | 4112, 213 | 2658, 214 | 120 215 | ], 216 | [ 217 | 5120, 218 | 2880, 219 | 120 220 | ] 221 | ] 222 | ], 223 | [ 224 | "apple paravirtual device", 225 | "", 226 | "apple device paravirtual", 227 | 0, 228 | [ 229 | [ 230 | 1024, 231 | 768, 232 | 30 233 | ], 234 | [ 235 | 2048, 236 | 1362, 237 | 59 238 | ] 239 | ] 240 | ] 241 | ] -------------------------------------------------------------------------------- /benchmarks/m-apple-ipad.json: -------------------------------------------------------------------------------- 1 | [ 2 | "5", 3 | [ 4 | "apple a10 gpu", 5 | "10", 6 | "a10 apple gpu", 7 | 0, 8 | [ 9 | [ 10 | 2048, 11 | 1536, 12 | 41, 13 | "apple ipad (6th gen)" 14 | ], 15 | [ 16 | 2160, 17 | 1620, 18 | 38, 19 | "apple ipad (10.2-inch) (7th generation)" 20 | ] 21 | ] 22 | ], 23 | [ 24 | "apple a10x gpu", 25 | "10", 26 | "a10x apple gpu", 27 | 0, 28 | [ 29 | [ 30 | 2048, 31 | 1536, 32 | 59, 33 | "apple ipad pro (10.5-inch)" 34 | ], 35 | [ 36 | 2224, 37 | 1668, 38 | 51, 39 | "apple ipad pro (10.5-inch)" 40 | ], 41 | [ 42 | 2732, 43 | 2048, 44 | 36, 45 | "apple ipad pro (12.9-inch, 2nd gen)" 46 | ] 47 | ] 48 | ], 49 | [ 50 | "apple a12 gpu", 51 | "12", 52 | "a12 apple gpu", 53 | 0, 54 | [ 55 | [ 56 | 2048, 57 | 1536, 58 | 60, 59 | "apple ipad mini (2019)" 60 | ], 61 | [ 62 | 2160, 63 | 1620, 64 | 59, 65 | "apple ipad 8th gen (wifi+cellular)" 66 | ], 67 | [ 68 | 2224, 69 | 1668, 70 | 58, 71 | "apple ipad air (2019)" 72 | ] 73 | ] 74 | ], 75 | [ 76 | "apple a12x gpu", 77 | "12", 78 | "a12x apple gpu", 79 | 0, 80 | [ 81 | [ 82 | 2388, 83 | 1668, 84 | 115, 85 | "apple ipad pro (11-inch)" 86 | ], 87 | [ 88 | 2732, 89 | 2048, 90 | 60, 91 | "apple ipad pro (12.9-inch) (3rd generation)" 92 | ] 93 | ] 94 | ], 95 | [ 96 | "apple a12z gpu", 97 | "12", 98 | "a12z apple gpu", 99 | 0, 100 | [ 101 | [ 102 | 2388, 103 | 1668, 104 | 113, 105 | "apple ipad pro (11-inch) (2rd generation)" 106 | ], 107 | [ 108 | 2732, 109 | 2048, 110 | 60, 111 | "apple ipad pro (12.9 inch) (4th generation)" 112 | ] 113 | ] 114 | ], 115 | [ 116 | "apple a13 gpu", 117 | "13", 118 | "a13 apple gpu", 119 | 0, 120 | [ 121 | [ 122 | 2160, 123 | 1620, 124 | 60, 125 | "apple ipad 9th gen" 126 | ] 127 | ] 128 | ], 129 | [ 130 | "apple a14 gpu", 131 | "14", 132 | "a14 apple gpu", 133 | 0, 134 | [ 135 | [ 136 | 2360, 137 | 1640, 138 | 60, 139 | "apple ipad (10th generation)" 140 | ], 141 | [ 142 | 2388, 143 | 1668, 144 | 52, 145 | "apple ipad air 4th gen (wi-fi only)" 146 | ] 147 | ] 148 | ], 149 | [ 150 | "apple a15 gpu", 151 | "15", 152 | "a15 apple gpu", 153 | 0, 154 | [ 155 | [ 156 | 2266, 157 | 1488, 158 | 60, 159 | "apple ipad mini (6th gen)" 160 | ], 161 | [ 162 | 2388, 163 | 1668, 164 | 60, 165 | "apple ipad mini (6th gen)" 166 | ] 167 | ] 168 | ], 169 | [ 170 | "apple a17 pro gpu", 171 | "17", 172 | "a17 apple gpu pro", 173 | 0, 174 | [ 175 | [ 176 | 2266, 177 | 1488, 178 | 60, 179 | "apple ipad mini 7th gen cellular (a17)" 180 | ] 181 | ] 182 | ], 183 | [ 184 | "apple a7 gpu", 185 | "7", 186 | "a7 apple gpu", 187 | 0, 188 | [ 189 | [ 190 | 2048, 191 | 1536, 192 | 10, 193 | "apple ipad mini 3" 194 | ] 195 | ] 196 | ], 197 | [ 198 | "apple a8 gpu", 199 | "8", 200 | "a8 apple gpu", 201 | 0, 202 | [ 203 | [ 204 | 2048, 205 | 1536, 206 | 16, 207 | "apple ipad mini 4" 208 | ] 209 | ] 210 | ], 211 | [ 212 | "apple a8x gpu", 213 | "8", 214 | "a8x apple gpu", 215 | 0, 216 | [ 217 | [ 218 | 2048, 219 | 1536, 220 | 30, 221 | "apple ipad air 2" 222 | ] 223 | ] 224 | ], 225 | [ 226 | "apple a9 gpu", 227 | "9", 228 | "a9 apple gpu", 229 | 0, 230 | [ 231 | [ 232 | 2048, 233 | 1536, 234 | 29, 235 | "apple ipad 9.7 (5th gen)" 236 | ] 237 | ] 238 | ], 239 | [ 240 | "apple a9x gpu", 241 | "9", 242 | "a9x apple gpu", 243 | 0, 244 | [ 245 | [ 246 | 2048, 247 | 1536, 248 | 40, 249 | "apple ipad pro 9.7" 250 | ], 251 | [ 252 | 2732, 253 | 2048, 254 | 35, 255 | "apple ipad pro" 256 | ] 257 | ] 258 | ], 259 | [ 260 | "apple m1 gpu", 261 | "1", 262 | "apple gpu m1", 263 | 0, 264 | [ 265 | [ 266 | 2360, 267 | 1640, 268 | 60, 269 | "apple ipad air (5th generation)" 270 | ], 271 | [ 272 | 2388, 273 | 1668, 274 | 120, 275 | "apple ipad pro (11-inch) (3rd generation)" 276 | ], 277 | [ 278 | 2732, 279 | 2048, 280 | 60, 281 | "apple ipad pro (12.9-inch) (5th generation)" 282 | ], 283 | [ 284 | 2752, 285 | 2064, 286 | 103, 287 | "apple ipad pro (12.9-inch) (5th generation)" 288 | ] 289 | ] 290 | ], 291 | [ 292 | "apple m2 gpu", 293 | "2", 294 | "apple gpu m2", 295 | 0, 296 | [ 297 | [ 298 | 2360, 299 | 1640, 300 | 60, 301 | "apple ipad air 6th gen (m2)" 302 | ], 303 | [ 304 | 2388, 305 | 1668, 306 | 120, 307 | "apple ipad pro 11 inch (4th gen)" 308 | ], 309 | [ 310 | 2732, 311 | 2048, 312 | 60, 313 | "apple ipad air 13-inch (m2)" 314 | ] 315 | ] 316 | ], 317 | [ 318 | "apple m4 gpu", 319 | "4", 320 | "apple gpu m4", 321 | 0, 322 | [ 323 | [ 324 | 2420, 325 | 1668, 326 | 120, 327 | "apple ipad pro 11-inch (m4)" 328 | ], 329 | [ 330 | 2752, 331 | 2064, 332 | 120, 333 | "apple ipad pro 12.9 inch 7th gen" 334 | ] 335 | ] 336 | ] 337 | ] -------------------------------------------------------------------------------- /benchmarks/m-apple.json: -------------------------------------------------------------------------------- 1 | [ 2 | "5", 3 | [ 4 | "apple a10 gpu", 5 | "10", 6 | "a10 apple gpu", 7 | 0, 8 | [ 9 | [ 10 | 1136, 11 | 640, 12 | 60, 13 | "apple ipod touch (7th gen)" 14 | ], 15 | [ 16 | 1334, 17 | 750, 18 | 104, 19 | "apple iphone 7" 20 | ], 21 | [ 22 | 1920, 23 | 1080, 24 | 60, 25 | "apple iphone 7 plus" 26 | ], 27 | [ 28 | 2001, 29 | 1125, 30 | 59, 31 | "apple iphone x" 32 | ] 33 | ] 34 | ], 35 | [ 36 | "apple a11 gpu", 37 | "11", 38 | "a11 apple gpu", 39 | 0, 40 | [ 41 | [ 42 | 1334, 43 | 750, 44 | 64, 45 | "apple iphone 8" 46 | ], 47 | [ 48 | 1920, 49 | 1080, 50 | 78, 51 | "apple iphone 8 plus" 52 | ] 53 | ] 54 | ], 55 | [ 56 | "apple a12 gpu", 57 | "12", 58 | "a12 apple gpu", 59 | 0, 60 | [ 61 | [ 62 | 1792, 63 | 828, 64 | 65, 65 | "apple iphone xr" 66 | ], 67 | [ 68 | 2436, 69 | 1125, 70 | 60, 71 | "apple iphone xs max" 72 | ], 73 | [ 74 | 2208, 75 | 1242, 76 | 60, 77 | "apple iphone xs max" 78 | ] 79 | ] 80 | ], 81 | [ 82 | "apple a13 gpu", 83 | "13", 84 | "a13 apple gpu", 85 | 0, 86 | [ 87 | [ 88 | 1334, 89 | 750, 90 | 75, 91 | "apple iphone se (2nd gen)" 92 | ], 93 | [ 94 | 1792, 95 | 828, 96 | 60, 97 | "apple iphone 11" 98 | ], 99 | [ 100 | 2436, 101 | 1125, 102 | 59, 103 | "apple iphone 11 pro" 104 | ], 105 | [ 106 | 2688, 107 | 1242, 108 | 70, 109 | "apple iphone 11 pro max" 110 | ] 111 | ] 112 | ], 113 | [ 114 | "apple a14 gpu", 115 | "14", 116 | "a14 apple gpu", 117 | 0, 118 | [ 119 | [ 120 | 2338, 121 | 1080, 122 | 61, 123 | "apple iphone 12 mini" 124 | ], 125 | [ 126 | 2436, 127 | 1125, 128 | 61, 129 | "apple iphone 12" 130 | ], 131 | [ 132 | 2778, 133 | 1284, 134 | 60, 135 | "apple iphone 12 pro max" 136 | ] 137 | ] 138 | ], 139 | [ 140 | "apple a15 gpu", 141 | "15", 142 | "a15 apple gpu", 143 | 0, 144 | [ 145 | [ 146 | 1334, 147 | 750, 148 | 118, 149 | "apple iphone se (2022)" 150 | ], 151 | [ 152 | 2338, 153 | 1080, 154 | 60, 155 | "apple iphone 13 mini" 156 | ], 157 | [ 158 | 2532, 159 | 1170, 160 | 60, 161 | "apple iphone 13" 162 | ], 163 | [ 164 | 2778, 165 | 1284, 166 | 60, 167 | "apple iphone 13 pro max" 168 | ] 169 | ] 170 | ], 171 | [ 172 | "apple a16 gpu", 173 | "16", 174 | "a16 apple gpu", 175 | 0, 176 | [ 177 | [ 178 | 2532, 179 | 1170, 180 | 60, 181 | "apple iphone 14 pro" 182 | ], 183 | [ 184 | 2778, 185 | 1284, 186 | 60, 187 | "apple iphone 14 pro max" 188 | ] 189 | ] 190 | ], 191 | [ 192 | "apple a17 pro gpu", 193 | "17", 194 | "a17 apple gpu pro", 195 | 0, 196 | [ 197 | [ 198 | 2532, 199 | 1170, 200 | 60, 201 | "apple iphone 15 pro" 202 | ], 203 | [ 204 | 2778, 205 | 1284, 206 | 50, 207 | "apple iphone 15 pro max" 208 | ] 209 | ] 210 | ], 211 | [ 212 | "apple a18 gpu", 213 | "18", 214 | "a18 apple gpu", 215 | 0, 216 | [ 217 | [ 218 | 2532, 219 | 1170, 220 | 60, 221 | "apple iphone 16 (iphone17,5)" 222 | ], 223 | [ 224 | 2778, 225 | 1284, 226 | 60, 227 | "apple iphone 16 (iphone17,4)" 228 | ], 229 | [ 230 | 2793, 231 | 1290, 232 | 60, 233 | "apple iphone 16 (iphone17,4)" 234 | ] 235 | ] 236 | ], 237 | [ 238 | "apple a18 pro gpu", 239 | "18", 240 | "a18 apple gpu pro", 241 | 0, 242 | [ 243 | [ 244 | 2532, 245 | 1170, 246 | 60, 247 | "apple iphone 16 (iphone17,1)" 248 | ], 249 | [ 250 | 2778, 251 | 1284, 252 | 60, 253 | "apple iphone 16 (iphone17,2)" 254 | ] 255 | ] 256 | ], 257 | [ 258 | "apple a7 gpu", 259 | "7", 260 | "a7 apple gpu", 261 | 0, 262 | [ 263 | [ 264 | 1136, 265 | 640, 266 | 32, 267 | "apple iphone 5s" 268 | ] 269 | ] 270 | ], 271 | [ 272 | "apple a8 gpu", 273 | "8", 274 | "a8 apple gpu", 275 | 0, 276 | [ 277 | [ 278 | 1136, 279 | 640, 280 | 40, 281 | "apple ipod touch 6" 282 | ], 283 | [ 284 | 1334, 285 | 750, 286 | 36, 287 | "apple iphone 6" 288 | ], 289 | [ 290 | 1920, 291 | 1080, 292 | 21, 293 | "apple iphone 6 plus" 294 | ] 295 | ] 296 | ], 297 | [ 298 | "apple a9 gpu", 299 | "9", 300 | "a9 apple gpu", 301 | 0, 302 | [ 303 | [ 304 | 1136, 305 | 640, 306 | 90, 307 | "apple iphone se" 308 | ], 309 | [ 310 | 1334, 311 | 750, 312 | 72, 313 | "apple iphone 6s" 314 | ], 315 | [ 316 | 1920, 317 | 1080, 318 | 42, 319 | "apple iphone 6s plus" 320 | ] 321 | ] 322 | ] 323 | ] -------------------------------------------------------------------------------- /benchmarks/m-intel.json: -------------------------------------------------------------------------------- 1 | [ 2 | "5", 3 | [ 4 | "intel intel hd graphics for atom x5", 5 | "5", 6 | "atom for graphics hd intel x5", 7 | 0, 8 | [ 9 | [ 10 | 1024, 11 | 600, 12 | 35, 13 | "amazon aeokn" 14 | ], 15 | [ 16 | 1024, 17 | 720, 18 | 13, 19 | "arbor venus 8" 20 | ], 21 | [ 22 | 1217, 23 | 720, 24 | 23, 25 | "gole gole1" 26 | ], 27 | [ 28 | 1280, 29 | 736, 30 | 27, 31 | "medion p850x" 32 | ], 33 | [ 34 | 1360, 35 | 704, 36 | 15, 37 | "chuwi hibox hero mini pc" 38 | ], 39 | [ 40 | 1280, 41 | 752, 42 | 21, 43 | "tetratab casebook 3" 44 | ], 45 | [ 46 | 1280, 47 | 759, 48 | 28, 49 | "lenovo yoga a12 (yb-q501f)" 50 | ], 51 | [ 52 | 1366, 53 | 720, 54 | 19, 55 | "nextbook nx16a11264 ares 11 (x5-z8300)" 56 | ], 57 | [ 58 | 1920, 59 | 996, 60 | 20, 61 | "teclast x16 pro" 62 | ], 63 | [ 64 | 1920, 65 | 1008, 66 | 12, 67 | "teclast tbook 16 pro" 68 | ], 69 | [ 70 | 1920, 71 | 1016, 72 | 13, 73 | "teclast x16 plus" 74 | ], 75 | [ 76 | 1920, 77 | 1104, 78 | 13, 79 | "medion p851x" 80 | ], 81 | [ 82 | 1920, 83 | 1116, 84 | 13, 85 | "teclast x80 pro (x5-z8350)" 86 | ], 87 | [ 88 | 1920, 89 | 1128, 90 | 8, 91 | "cube technology i12-y" 92 | ], 93 | [ 94 | 1920, 95 | 1133, 96 | 9, 97 | "cube technology i1-tfp (x5-z8350)" 98 | ], 99 | [ 100 | 1920, 101 | 1134, 102 | 11, 103 | "microtech e-tab pro lte" 104 | ], 105 | [ 106 | 1920, 107 | 1136, 108 | 14, 109 | "cube technology iwork 10 ultimate (i15-t)" 110 | ], 111 | [ 112 | 1920, 113 | 1214, 114 | 10, 115 | "chuwi cw-hi10 plus (x5-z8350)" 116 | ], 117 | [ 118 | 2048, 119 | 1440, 120 | 8, 121 | "teclast x98 plus" 122 | ], 123 | [ 124 | 2160, 125 | 1368, 126 | 10, 127 | "chuwi hi12 (x5-z8350)" 128 | ], 129 | [ 130 | 2048, 131 | 1452, 132 | 10, 133 | "teclast x98 plus ii" 134 | ], 135 | [ 136 | 2048, 137 | 1536, 138 | 14, 139 | "xiaomi mi pad 2" 140 | ], 141 | [ 142 | 2560, 143 | 1356, 144 | 7, 145 | "baofeng a1" 146 | ], 147 | [ 148 | 2560, 149 | 1504, 150 | 6, 151 | "chuwi hibook pro (z8350)" 152 | ], 153 | [ 154 | 2560, 155 | 1518, 156 | 11, 157 | "lenovo yt3-x90 yoga tablet 3 pro (x5-z8550)" 158 | ] 159 | ] 160 | ], 161 | [ 162 | "intel intel hd graphics for baytrail", 163 | "hdfor", 164 | "baytrail for graphics hd intel", 165 | 0, 166 | [ 167 | [ 168 | 1024, 169 | 552, 170 | 13, 171 | "multilaser intel 7qc" 172 | ], 173 | [ 174 | 1024, 175 | 696, 176 | 17, 177 | "thundersoft dual os tablet" 178 | ], 179 | [ 180 | 1024, 181 | 720, 182 | 15, 183 | "airis onepad 785i" 184 | ], 185 | [ 186 | 1184, 187 | 720, 188 | 18, 189 | "trimble tdc500" 190 | ], 191 | [ 192 | 1280, 193 | 736, 194 | 12, 195 | "acer a1-840" 196 | ], 197 | [ 198 | 1280, 199 | 752, 200 | 9, 201 | "imuz mupad win 10.1 ii" 202 | ], 203 | [ 204 | 1366, 205 | 720, 206 | 13, 207 | "nextbook nxa116qc164" 208 | ], 209 | [ 210 | 1366, 211 | 724, 212 | 10, 213 | "cube technology i10 remix" 214 | ], 215 | [ 216 | 1440, 217 | 1008, 218 | 12, 219 | "teclast x89 kindow" 220 | ], 221 | [ 222 | 1920, 223 | 1008, 224 | 8, 225 | "minix neo z64" 226 | ], 227 | [ 228 | 1920, 229 | 1014, 230 | 9, 231 | "cube technology i7 cx remix" 232 | ], 233 | [ 234 | 1920, 235 | 1032, 236 | 11, 237 | "hp slate 17" 238 | ], 239 | [ 240 | 1920, 241 | 1104, 242 | 5, 243 | "jltd d630" 244 | ], 245 | [ 246 | 1920, 247 | 1128, 248 | 6, 249 | "intel(r) e1008" 250 | ], 251 | [ 252 | 1920, 253 | 1133, 254 | 9, 255 | "pipo w3f" 256 | ], 257 | [ 258 | 2048, 259 | 1440, 260 | 6, 261 | "kruger & matz eagle 975 (km0975)" 262 | ], 263 | [ 264 | 2048, 265 | 1448, 266 | 6, 267 | "jide e-tab 3g" 268 | ], 269 | [ 270 | 2048, 271 | 1464, 272 | 6, 273 | "reeder a10ix air" 274 | ], 275 | [ 276 | 2560, 277 | 1344, 278 | 7, 279 | "lenovo yoga tablet 2 pro-1380" 280 | ], 281 | [ 282 | 2560, 283 | 1504, 284 | 5, 285 | "teclast x10hd 3g" 286 | ] 287 | ] 288 | ], 289 | [ 290 | "intel mesa dri intel bay trail", 291 | "dribay", 292 | "bay dri intel mesa trail", 293 | 0, 294 | [ 295 | [ 296 | 1366, 297 | 768, 298 | 15, 299 | "google chromebook pixel (2015, n2830)" 300 | ] 301 | ] 302 | ], 303 | [ 304 | "intel mesa dri intel hd", 305 | "drihd", 306 | "dri hd intel mesa", 307 | 0, 308 | [ 309 | [ 310 | 688, 311 | 412, 312 | 39, 313 | "hp chromebook x360 11 g1 ee" 314 | ], 315 | [ 316 | 960, 317 | 568, 318 | 36, 319 | "google chromebook pixel (2015, n3450)" 320 | ], 321 | [ 322 | 1024, 323 | 561, 324 | 28, 325 | "aaeon up-cht01 up board" 326 | ], 327 | [ 328 | 1024, 329 | 736, 330 | 33, 331 | "google chromebook reef (n3350)" 332 | ] 333 | ] 334 | ], 335 | [ 336 | "intel mesa dri intel hd graphics 400", 337 | "400", 338 | "400 dri graphics hd intel mesa", 339 | 0, 340 | [ 341 | [ 342 | 688, 343 | 412, 344 | 41, 345 | "asus c202sa chromebook" 346 | ], 347 | [ 348 | 768, 349 | 431, 350 | 45, 351 | "hp chromebook 11 g5" 352 | ], 353 | [ 354 | 960, 355 | 568, 356 | 25, 357 | "acer chromebook r11 (n3050)" 358 | ], 359 | [ 360 | 1366, 361 | 768, 362 | 19, 363 | "samsung chromebook 3" 364 | ], 365 | [ 366 | 1536, 367 | 832, 368 | 25, 369 | "google chromebook r11 (n3160)" 370 | ], 371 | [ 372 | 1920, 373 | 1080, 374 | 17, 375 | "acer chromebook 14" 376 | ] 377 | ] 378 | ], 379 | [ 380 | "intel mesa dri intel hd graphics 510", 381 | "510", 382 | "510 dri graphics hd intel mesa", 383 | 0, 384 | [ 385 | [ 386 | 690, 387 | 378, 388 | 53, 389 | "hp chromebook chell" 390 | ], 391 | [ 392 | 688, 393 | 412, 394 | 60, 395 | "acer chromebook 14 for work" 396 | ] 397 | ] 398 | ], 399 | [ 400 | "intel mesa dri intel hd graphics 515", 401 | "515", 402 | "515 dri graphics hd intel mesa", 403 | 0, 404 | [ 405 | [ 406 | 1033, 407 | 617, 408 | 56, 409 | "samsung chromebook pro (m7-6y75, caroline)" 410 | ], 411 | [ 412 | 1536, 413 | 1088, 414 | 32, 415 | "google chromebook pixel (2015, m3-6y30)" 416 | ], 417 | [ 418 | 1920, 419 | 980, 420 | 32, 421 | "asus c302 chromebook flip" 422 | ], 423 | [ 424 | 2400, 425 | 1504, 426 | 22, 427 | "samsung chromebook pro (caroline)" 428 | ], 429 | [ 430 | 3200, 431 | 1640, 432 | 12, 433 | "google chromebook pixel (2015, 4405y)" 434 | ] 435 | ] 436 | ], 437 | [ 438 | "intel mesa dri intel hd graphics 520", 439 | "520", 440 | "520 dri graphics hd intel mesa", 441 | 0, 442 | [ 443 | [ 444 | 700, 445 | 412, 446 | 60, 447 | "acer chromebook 14 for work (i3-6100u)" 448 | ] 449 | ] 450 | ], 451 | [ 452 | "intel mesa dri intel hd graphics 5500", 453 | "5500", 454 | "5500 dri graphics hd intel mesa", 455 | 0, 456 | [ 457 | [ 458 | 1080, 459 | 575, 460 | 59, 461 | "google chromebook pixel (2015, i3-5005u)" 462 | ], 463 | [ 464 | 1920, 465 | 1000, 466 | 30, 467 | "google chromebook pixel (2015, i5-5300u)" 468 | ], 469 | [ 470 | 2560, 471 | 1700, 472 | 14, 473 | "google chromebook pixel (2015, i5-5200u)" 474 | ] 475 | ] 476 | ], 477 | [ 478 | "intel mesa dri intel hd graphics 615", 479 | "615", 480 | "615 dri graphics hd intel mesa", 481 | 0, 482 | [ 483 | [ 484 | 1034, 485 | 618, 486 | 55, 487 | "google soraka (4415y)" 488 | ], 489 | [ 490 | 1200, 491 | 720, 492 | 34, 493 | "google poppy (4410y, kabylake)" 494 | ], 495 | [ 496 | 2400, 497 | 1504, 498 | 21, 499 | "google chromebook eve (i5-7y54)" 500 | ] 501 | ] 502 | ], 503 | [ 504 | "intel mesa dri intel kabylake gt2", 505 | "2", 506 | "dri gt2 intel kabylake mesa", 507 | 0, 508 | [ 509 | [ 510 | 960, 511 | 568, 512 | 38, 513 | "google chromebook pixel (2015, m3-7y30)" 514 | ] 515 | ] 516 | ] 517 | ] -------------------------------------------------------------------------------- /benchmarks/m-mali-t.json: -------------------------------------------------------------------------------- 1 | [ 2 | "5", 3 | [ 4 | "arm mali-t604 mp4", 5 | "604", 6 | "arm mali-t604 mp4", 7 | 0, 8 | [ 9 | [ 10 | 2560, 11 | 1504, 12 | 4, 13 | "google nexus 10" 14 | ] 15 | ] 16 | ], 17 | [ 18 | "arm mali-t622", 19 | "622", 20 | "arm mali-t622", 21 | 0, 22 | [ 23 | [ 24 | 1024, 25 | 564, 26 | 12, 27 | "telechips tcc896x (quad core, development board)" 28 | ], 29 | [ 30 | 1280, 31 | 720, 32 | 7, 33 | "leadcore l1860 (mali-t622, development board)" 34 | ] 35 | ] 36 | ], 37 | [ 38 | "arm mali-t624", 39 | "624", 40 | "arm mali-t624", 41 | 0, 42 | [ 43 | [ 44 | 1794, 45 | 1080, 46 | 7, 47 | "huawei grace" 48 | ], 49 | [ 50 | 1812, 51 | 1080, 52 | 6, 53 | "huawei abc-ul00" 54 | ], 55 | [ 56 | 1830, 57 | 1080, 58 | 10, 59 | "huawei p8 max (dav-70x)" 60 | ], 61 | [ 62 | 1920, 63 | 1080, 64 | 4, 65 | "sony amai vp9" 66 | ], 67 | [ 68 | 1920, 69 | 1104, 70 | 9, 71 | "huawei dtab compact d-02h (docomo)" 72 | ], 73 | [ 74 | 1920, 75 | 1128, 76 | 8, 77 | "huawei dtab d-01h (docomo)" 78 | ], 79 | [ 80 | 1824, 81 | 1200, 82 | 9, 83 | "huawei mediapad m2 (m2-80xx)" 84 | ], 85 | [ 86 | 1830, 87 | 1200, 88 | 9, 89 | "huawei mediapad x2 (gem-701l, gem-702l, gem-703l)" 90 | ] 91 | ] 92 | ], 93 | [ 94 | "arm mali-t624 mp2", 95 | "624", 96 | "arm mali-t624 mp2", 97 | 0, 98 | [ 99 | [ 100 | 1280, 101 | 720, 102 | 5, 103 | "samsung sm-g910f (mali-t624)" 104 | ] 105 | ] 106 | ], 107 | [ 108 | "arm mali-t624 mp4", 109 | "624", 110 | "arm mali-t624 mp4", 111 | 0, 112 | [ 113 | [ 114 | 1794, 115 | 1080, 116 | 9, 117 | "huawei z100" 118 | ] 119 | ] 120 | ], 121 | [ 122 | "arm mali-t628", 123 | "628", 124 | "arm mali-t628", 125 | 0, 126 | [ 127 | [ 128 | 1024, 129 | 600, 130 | 30, 131 | "thinkware inavi davinci" 132 | ], 133 | [ 134 | 2560, 135 | 1536, 136 | 8, 137 | "meizu mx4 pro" 138 | ] 139 | ] 140 | ], 141 | [ 142 | "arm mali-t628 mp2", 143 | "628", 144 | "arm mali-t628 mp2", 145 | 0, 146 | [ 147 | [ 148 | 1280, 149 | 720, 150 | 8, 151 | "leadcore l1860 (development board)" 152 | ] 153 | ] 154 | ], 155 | [ 156 | "arm mali-t628 mp6", 157 | "628", 158 | "arm mali-t628 mp6", 159 | 0, 160 | [ 161 | [ 162 | 800, 163 | 480, 164 | 35, 165 | "gen2wave rp1600" 166 | ], 167 | [ 168 | 1280, 169 | 672, 170 | 14, 171 | "hardkernel odroid-xu3 (development board)" 172 | ], 173 | [ 174 | 1280, 175 | 720, 176 | 26, 177 | "samsung galaxy alpha (mali-t628, sm-g850)" 178 | ], 179 | [ 180 | 1920, 181 | 1080, 182 | 11, 183 | "samsung galaxy note iii (mali-t628, sm-n900, sm-n9000q)" 184 | ], 185 | [ 186 | 2560, 187 | 1600, 188 | 3, 189 | "samsung sm-t520 galaxy tab 10.1" 190 | ] 191 | ] 192 | ], 193 | [ 194 | "arm mali-t720", 195 | "720", 196 | "arm mali-t720", 197 | 0, 198 | [ 199 | [ 200 | 432, 201 | 240, 202 | 16, 203 | "unihertz jelly pro" 204 | ], 205 | [ 206 | 782, 207 | 480, 208 | 8, 209 | "mobiistar lai zoro" 210 | ], 211 | [ 212 | 784, 213 | 480, 214 | 8, 215 | "lg k3 (k100)" 216 | ], 217 | [ 218 | 791, 219 | 480, 220 | 6, 221 | "i-mobile i-style 812 4g" 222 | ], 223 | [ 224 | 800, 225 | 480, 226 | 4, 227 | "lava iris 550" 228 | ], 229 | [ 230 | 854, 231 | 480, 232 | 3, 233 | "verykool sl5009 jet" 234 | ], 235 | [ 236 | 897, 237 | 540, 238 | 5, 239 | "bluboo xfire" 240 | ], 241 | [ 242 | 960, 243 | 540, 244 | 3, 245 | "siswoo a5 chocolate" 246 | ], 247 | [ 248 | 1024, 249 | 552, 250 | 4, 251 | "bb-mobile tq763i techno 7.0 lte" 252 | ], 253 | [ 254 | 1024, 255 | 714, 256 | 9, 257 | "bluedot bnt-791 (2g)" 258 | ], 259 | [ 260 | 1024, 261 | 720, 262 | 3, 263 | "zte e8qp" 264 | ], 265 | [ 266 | 1280, 267 | 624, 268 | 10, 269 | "panasonic p55 novo 4g" 270 | ], 271 | [ 272 | 1280, 273 | 648, 274 | 4, 275 | "tcl 9025" 276 | ], 277 | [ 278 | 1280, 279 | 656, 280 | 7, 281 | "acer a1-734 iconia talk s" 282 | ], 283 | [ 284 | 1184, 285 | 720, 286 | 4, 287 | "lenovo xt1700, xt1706, k10a40" 288 | ], 289 | [ 290 | 1187, 291 | 720, 292 | 7, 293 | "lg k8 (k350)" 294 | ], 295 | [ 296 | 1189, 297 | 720, 298 | 5, 299 | "ark impulse p2" 300 | ], 301 | [ 302 | 1193, 303 | 720, 304 | 7, 305 | "lg x power (k220, f750)" 306 | ], 307 | [ 308 | 1196, 309 | 720, 310 | 2, 311 | "dtac phone m2" 312 | ], 313 | [ 314 | 1198, 315 | 720, 316 | 5, 317 | "dtac phone t3" 318 | ], 319 | [ 320 | 1205, 321 | 720, 322 | 7, 323 | "firefly aurii passion" 324 | ], 325 | [ 326 | 1206, 327 | 720, 328 | 4, 329 | "archos 50 power" 330 | ], 331 | [ 332 | 1208, 333 | 720, 334 | 3, 335 | "advan i7 plus" 336 | ], 337 | [ 338 | 1217, 339 | 720, 340 | 7, 341 | "energy sistem energy phone max 2+" 342 | ], 343 | [ 344 | 1238, 345 | 720, 346 | 9, 347 | "vnpt technology vivas lotus s3 lte" 348 | ], 349 | [ 350 | 1280, 351 | 720, 352 | 2, 353 | "archos bush spira c2 5" 354 | ], 355 | [ 356 | 1280, 357 | 736, 358 | 2, 359 | "digma cs1062ml citi 1903 4g" 360 | ], 361 | [ 362 | 1280, 363 | 737, 364 | 3, 365 | "waywalkers t805g" 366 | ], 367 | [ 368 | 1280, 369 | 740, 370 | 3, 371 | "casper via l8" 372 | ], 373 | [ 374 | 1280, 375 | 746, 376 | 3, 377 | "philips tle821l e line 4g" 378 | ], 379 | [ 380 | 1280, 381 | 752, 382 | 3, 383 | "4good light at200" 384 | ], 385 | [ 386 | 1280, 387 | 755, 388 | 7, 389 | "leotec letab1020 supernova qi32" 390 | ], 391 | [ 392 | 1356, 393 | 720, 394 | 8, 395 | "xiaolajiao la-v11" 396 | ], 397 | [ 398 | 1360, 399 | 720, 400 | 7, 401 | "tecno in5" 402 | ], 403 | [ 404 | 1368, 405 | 720, 406 | 7, 407 | "tinno p100" 408 | ], 409 | [ 410 | 1280, 411 | 800, 412 | 4, 413 | "samsung galaxy tab e 8.0 (sm-t375x, sm-t377x)" 414 | ], 415 | [ 416 | 1920, 417 | 936, 418 | 4, 419 | "panasonic eluga note" 420 | ], 421 | [ 422 | 1920, 423 | 996, 424 | 4, 425 | "cube technology u83 iplay10" 426 | ], 427 | [ 428 | 1776, 429 | 1080, 430 | 4, 431 | "fly fs522 cirrus 14" 432 | ], 433 | [ 434 | 1787, 435 | 1080, 436 | 5, 437 | "lg x cam (k580, f690)" 438 | ], 439 | [ 440 | 1920, 441 | 1008, 442 | 6, 443 | "alcatel one touch xess (p17aa)" 444 | ], 445 | [ 446 | 1794, 447 | 1080, 448 | 3, 449 | "ramos mos 1 max" 450 | ], 451 | [ 452 | 1800, 453 | 1080, 454 | 4, 455 | "archos sense 55 s" 456 | ], 457 | [ 458 | 1815, 459 | 1080, 460 | 4, 461 | "archos diamond plus" 462 | ], 463 | [ 464 | 1920, 465 | 1032, 466 | 5, 467 | "virgin media tellytablet" 468 | ], 469 | [ 470 | 1920, 471 | 1080, 472 | 2, 473 | "infocus m640" 474 | ], 475 | [ 476 | 1920, 477 | 1104, 478 | 4, 479 | "vestel v tab 7030" 480 | ], 481 | [ 482 | 1920, 483 | 1116, 484 | 4, 485 | "jty q101" 486 | ], 487 | [ 488 | 1920, 489 | 1128, 490 | 2, 491 | "archos 80 oxygen" 492 | ], 493 | [ 494 | 2009, 495 | 1080, 496 | 4, 497 | "tcl 5099" 498 | ], 499 | [ 500 | 1920, 501 | 1136, 502 | 4, 503 | "asus zenpad 10 (p028 z301m)" 504 | ], 505 | [ 506 | 2712, 507 | 1440, 508 | 45, 509 | "lenovo tab 2 501lv (softbank)" 510 | ] 511 | ] 512 | ], 513 | [ 514 | "arm mali-t760", 515 | "760", 516 | "arm mali-t760", 517 | 0, 518 | [ 519 | [ 520 | 854, 521 | 480, 522 | 14, 523 | "aux t6200l" 524 | ], 525 | [ 526 | 897, 527 | 540, 528 | 13, 529 | "sony xperia e4g (e20xx)" 530 | ], 531 | [ 532 | 960, 533 | 540, 534 | 12, 535 | "gionee v381" 536 | ], 537 | [ 538 | 960, 539 | 568, 540 | 24, 541 | "asus c100pa chromebook flip" 542 | ], 543 | [ 544 | 1024, 545 | 552, 546 | 12, 547 | "archos 70 helium" 548 | ], 549 | [ 550 | 1024, 551 | 720, 552 | 10, 553 | "wiz t-8168" 554 | ], 555 | [ 556 | 1188, 557 | 720, 558 | 9, 559 | "lg h520 magna, h522 prime plus" 560 | ], 561 | [ 562 | 1196, 563 | 720, 564 | 9, 565 | "acer s57 liquid jade z" 566 | ], 567 | [ 568 | 1280, 569 | 720, 570 | 8, 571 | "dunetek vitamin a" 572 | ], 573 | [ 574 | 1280, 575 | 736, 576 | 8, 577 | "archos 80b helium" 578 | ], 579 | [ 580 | 1280, 581 | 752, 582 | 8, 583 | "frael m10g 4g" 584 | ], 585 | [ 586 | 1280, 587 | 768, 588 | 8, 589 | "meizu m1" 590 | ], 591 | [ 592 | 1794, 593 | 1080, 594 | 6, 595 | "sugar 2 ss136 l8560" 596 | ], 597 | [ 598 | 1920, 599 | 1032, 600 | 9, 601 | "qbic bxp-300 box pc" 602 | ], 603 | [ 604 | 1920, 605 | 1080, 606 | 4, 607 | "byxpress mphone xone" 608 | ], 609 | [ 610 | 1920, 611 | 1104, 612 | 6, 613 | "cube technology t7" 614 | ], 615 | [ 616 | 1920, 617 | 1128, 618 | 5, 619 | "nec lavietab pc-te510bal" 620 | ], 621 | [ 622 | 2048, 623 | 1440, 624 | 3, 625 | "teclast p98 4g" 626 | ], 627 | [ 628 | 2560, 629 | 1440, 630 | 10, 631 | "samsung galaxy note 4 (mali-t760, sm-n910x, sm-n916)" 632 | ] 633 | ] 634 | ], 635 | [ 636 | "arm mali-t760 mp6", 637 | "760", 638 | "arm mali-t760 mp6", 639 | 0, 640 | [ 641 | [ 642 | 1920, 643 | 1080, 644 | 17, 645 | "samsung galaxy a8 (mali-t760, sm-a800x, scv32)" 646 | ], 647 | [ 648 | 2048, 649 | 1536, 650 | 12, 651 | "samsung galaxy tab s 2 8.0 (sm-t710, sm-t715)" 652 | ], 653 | [ 654 | 2560, 655 | 1532, 656 | 10, 657 | "samsung galaxy note edge (mali-t760, sm-n915x)" 658 | ], 659 | [ 660 | 2560, 661 | 1600, 662 | 10, 663 | "samsung galaxy tab s 10.5 (mali-t760, sm-t805s)" 664 | ] 665 | ] 666 | ], 667 | [ 668 | "arm mali-t760 mp8", 669 | "760", 670 | "arm mali-t760 mp8", 671 | 0, 672 | [ 673 | [ 674 | 1280, 675 | 768, 676 | 42, 677 | "samsung sm-w2016" 678 | ], 679 | [ 680 | 1920, 681 | 1080, 682 | 25, 683 | "meizu niux" 684 | ], 685 | [ 686 | 2160, 687 | 1200, 688 | 17, 689 | "idealens k2" 690 | ], 691 | [ 692 | 2560, 693 | 1440, 694 | 12, 695 | "le xiang deepoon m2 vr" 696 | ], 697 | [ 698 | 2560, 699 | 1504, 700 | 15, 701 | "bungbungame kalos 2" 702 | ] 703 | ] 704 | ], 705 | [ 706 | "arm mali-t764", 707 | "764", 708 | "arm mali-t764", 709 | 0, 710 | [ 711 | [ 712 | 1024, 713 | 600, 714 | 19, 715 | "gpd q9" 716 | ], 717 | [ 718 | 1280, 719 | 720, 720 | 15, 721 | "gpd xd" 722 | ], 723 | [ 724 | 1280, 725 | 752, 726 | 13, 727 | "kruger & matz 1064.1g eagle" 728 | ], 729 | [ 730 | 1280, 731 | 800, 732 | 13, 733 | "pipo p7" 734 | ], 735 | [ 736 | 1920, 737 | 1008, 738 | 6, 739 | "rockchip mk809 4k tv stick" 740 | ], 741 | [ 742 | 1920, 743 | 1010, 744 | 8, 745 | "pipo p7 hd" 746 | ], 747 | [ 748 | 1920, 749 | 1020, 750 | 5, 751 | "rockchip mk903v mini tv" 752 | ], 753 | [ 754 | 1920, 755 | 1032, 756 | 7, 757 | "acooo oneboard pro+" 758 | ], 759 | [ 760 | 1872, 761 | 1080, 762 | 7, 763 | "contextmedia wallboard 32 tablet (p-wal-106-yit-01)" 764 | ], 765 | [ 766 | 1920, 767 | 1080, 768 | 7, 769 | "rockchip cs4k tv box" 770 | ], 771 | [ 772 | 1920, 773 | 1128, 774 | 7, 775 | "archos 101 oxygen" 776 | ], 777 | [ 778 | 2048, 779 | 1437, 780 | 5, 781 | "haier pad 971" 782 | ], 783 | [ 784 | 2048, 785 | 1440, 786 | 5, 787 | "hisense f5281 vidaa pad" 788 | ], 789 | [ 790 | 2560, 791 | 1504, 792 | 4, 793 | "teclast p90hd" 794 | ] 795 | ] 796 | ], 797 | [ 798 | "arm mali-t820", 799 | "820", 800 | "arm mali-t820", 801 | 0, 802 | [ 803 | [ 804 | 1344, 805 | 720, 806 | 5, 807 | "lenovo k320t" 808 | ], 809 | [ 810 | 1776, 811 | 1080, 812 | 6, 813 | "leagoo t5c" 814 | ], 815 | [ 816 | 1920, 817 | 1008, 818 | 7, 819 | "probox2 ava tv box" 820 | ], 821 | [ 822 | 1920, 823 | 1080, 824 | 4, 825 | "skyworth coocaa 5s32 n2" 826 | ] 827 | ] 828 | ], 829 | [ 830 | "arm mali-t830", 831 | "830", 832 | "arm mali-t830", 833 | 0, 834 | [ 835 | [ 836 | 1280, 837 | 720, 838 | 9, 839 | "samsung galaxy on7 (mali-t830, sm-g600x)" 840 | ], 841 | [ 842 | 1280, 843 | 800, 844 | 9, 845 | "samsung sm-t230nw (mali-t830)" 846 | ], 847 | [ 848 | 1776, 849 | 1080, 850 | 9, 851 | "huawei p10 lite (was-xxx)" 852 | ], 853 | [ 854 | 1794, 855 | 1080, 856 | 9, 857 | "huawei honor 6x (bln-xxx)" 858 | ], 859 | [ 860 | 1920, 861 | 1080, 862 | 5, 863 | "samsung galaxy on7 prime 2018 (sm-g611)" 864 | ], 865 | [ 866 | 2033, 867 | 1080, 868 | 8, 869 | "huawei p smart (fig-xxx)" 870 | ], 871 | [ 872 | 2040, 873 | 1080, 874 | 9, 875 | "huawei maimang 6 (rne-xxx)" 876 | ], 877 | [ 878 | 1920, 879 | 1200, 880 | 5, 881 | "samsung galaxy tab a 10.1 (sm-t580, sm-t585)" 882 | ] 883 | ] 884 | ], 885 | [ 886 | "arm mali-t860", 887 | "860", 888 | "arm mali-t860", 889 | 0, 890 | [ 891 | [ 892 | 1184, 893 | 720, 894 | 8, 895 | "tcl a626" 896 | ], 897 | [ 898 | 1196, 899 | 720, 900 | 8, 901 | "green orange go t2" 902 | ], 903 | [ 904 | 1280, 905 | 720, 906 | 14, 907 | "htc one a9s" 908 | ], 909 | [ 910 | 1920, 911 | 1024, 912 | 17, 913 | "hardkernel odroid-n1 (development board)" 914 | ], 915 | [ 916 | 1920, 917 | 1032, 918 | 16, 919 | "contextmedia p-wal-108-elc-02" 920 | ], 921 | [ 922 | 1920, 923 | 1080, 924 | 7, 925 | "htc u play (u-2u)" 926 | ], 927 | [ 928 | 1920, 929 | 1116, 930 | 15, 931 | "imuz revolution a8" 932 | ], 933 | [ 934 | 1920, 935 | 1128, 936 | 15, 937 | "rockchip rk3399 (development board)" 938 | ], 939 | [ 940 | 2400, 941 | 1440, 942 | 10, 943 | "samsung chromebook plus (kevin)" 944 | ] 945 | ] 946 | ], 947 | [ 948 | "arm mali-t860 mp2", 949 | "860", 950 | "arm mali-t860 mp2", 951 | 0, 952 | [ 953 | [ 954 | 598, 955 | 480, 956 | 25, 957 | "cipherlab 9700a" 958 | ], 959 | [ 960 | 1184, 961 | 720, 962 | 11, 963 | "vernee m5" 964 | ], 965 | [ 966 | 1193, 967 | 720, 968 | 11, 969 | "lg x power 2 (u+, x500, m-x320, m320)" 970 | ], 971 | [ 972 | 1196, 973 | 720, 974 | 11, 975 | "lava z25" 976 | ], 977 | [ 978 | 1199, 979 | 720, 980 | 11, 981 | "lg stylus 3 (m400)" 982 | ], 983 | [ 984 | 1212, 985 | 720, 986 | 11, 987 | "meeg 306" 988 | ], 989 | [ 990 | 1280, 991 | 720, 992 | 10, 993 | "oppo r66" 994 | ], 995 | [ 996 | 1336, 997 | 720, 998 | 13, 999 | "asus pegasus 4s (x018d zb570tl)" 1000 | ], 1001 | [ 1002 | 1344, 1003 | 720, 1004 | 13, 1005 | "allview x4 soul infinity n" 1006 | ], 1007 | [ 1008 | 1776, 1009 | 1080, 1010 | 7, 1011 | "benq f55" 1012 | ], 1013 | [ 1014 | 1794, 1015 | 1080, 1016 | 6, 1017 | "alcatel 7070" 1018 | ], 1019 | [ 1020 | 1798, 1021 | 1080, 1022 | 7, 1023 | "energy sistem energy phone pro 3" 1024 | ], 1025 | [ 1026 | 1806, 1027 | 1080, 1028 | 8, 1029 | "tecno phantom 6" 1030 | ], 1031 | [ 1032 | 1807, 1033 | 1080, 1034 | 7, 1035 | "covia fleaz cp-j55a g07" 1036 | ], 1037 | [ 1038 | 1810, 1039 | 1080, 1040 | 8, 1041 | "archos 55 diamond 2 plus" 1042 | ], 1043 | [ 1044 | 1920, 1045 | 1080, 1046 | 4, 1047 | "advan vandroid i55c" 1048 | ], 1049 | [ 1050 | 2004, 1051 | 1080, 1052 | 7, 1053 | "asus zenfone max plus m1 (x018d zb570tl)" 1054 | ], 1055 | [ 1056 | 1920, 1057 | 1128, 1058 | 7, 1059 | "verizon qtaxia1" 1060 | ] 1061 | ] 1062 | ], 1063 | [ 1064 | "arm mali-t880", 1065 | "880", 1066 | "arm mali-t880", 1067 | 0, 1068 | [ 1069 | [ 1070 | 1184, 1071 | 720, 1072 | 22, 1073 | "doogee mix" 1074 | ], 1075 | [ 1076 | 1280, 1077 | 720, 1078 | 20, 1079 | "lenovo k8" 1080 | ], 1081 | [ 1082 | 1344, 1083 | 720, 1084 | 18, 1085 | "casper via f2" 1086 | ], 1087 | [ 1088 | 1776, 1089 | 1080, 1090 | 11, 1091 | "alcatel 6060 (mali-t880)" 1092 | ], 1093 | [ 1094 | 1794, 1095 | 1080, 1096 | 20, 1097 | "huawei mate 8 (nxt-xxx)" 1098 | ], 1099 | [ 1100 | 1824, 1101 | 1080, 1102 | 11, 1103 | "meiigoo m1" 1104 | ], 1105 | [ 1106 | 1920, 1107 | 1080, 1108 | 10, 1109 | "letv leeco lex650" 1110 | ], 1111 | [ 1112 | 2016, 1113 | 1080, 1114 | 9, 1115 | "vernee mix 2" 1116 | ], 1117 | [ 1118 | 2064, 1119 | 1080, 1120 | 10, 1121 | "umi s2 pro" 1122 | ], 1123 | [ 1124 | 2392, 1125 | 1440, 1126 | 12, 1127 | "huawei honor v8 (knt-al20)" 1128 | ], 1129 | [ 1130 | 2434, 1131 | 1440, 1132 | 11, 1133 | "huawei honor note 8 premium edition (edi-al10)" 1134 | ], 1135 | [ 1136 | 2560, 1137 | 1440, 1138 | 24, 1139 | "meizu pro 6 plus" 1140 | ], 1141 | [ 1142 | 2560, 1143 | 1480, 1144 | 10, 1145 | "huawei dtab compact d-01j (docomo)" 1146 | ], 1147 | [ 1148 | 2560, 1149 | 1600, 1150 | 10, 1151 | "huawei mediapad m3 (btv-xxx)" 1152 | ] 1153 | ] 1154 | ], 1155 | [ 1156 | "arm mali-t880 mp12", 1157 | "880", 1158 | "arm mali-t880 mp12", 1159 | 0, 1160 | [ 1161 | [ 1162 | 1920, 1163 | 1080, 1164 | 44, 1165 | "samsung galaxy s7 (sm-g930f)" 1166 | ], 1167 | [ 1168 | 2560, 1169 | 1440, 1170 | 27, 1171 | "samsung galaxy note 7 (mali-t880, sm-n930)" 1172 | ] 1173 | ] 1174 | ], 1175 | [ 1176 | "arm mali-t880 mp2", 1177 | "880", 1178 | "arm mali-t880 mp2", 1179 | 0, 1180 | [ 1181 | [ 1182 | 1184, 1183 | 720, 1184 | 19, 1185 | "sony pikachu" 1186 | ], 1187 | [ 1188 | 1376, 1189 | 720, 1190 | 17, 1191 | "umi s2" 1192 | ], 1193 | [ 1194 | 1776, 1195 | 1080, 1196 | 10, 1197 | "coolpad a9s-9" 1198 | ], 1199 | [ 1200 | 1800, 1201 | 1080, 1202 | 11, 1203 | "infinix x603" 1204 | ], 1205 | [ 1206 | 1920, 1207 | 1080, 1208 | 9, 1209 | "innjoo pro2" 1210 | ] 1211 | ] 1212 | ], 1213 | [ 1214 | "arm mali-t880 mp4", 1215 | "880", 1216 | "arm mali-t880 mp4", 1217 | 0, 1218 | [ 1219 | [ 1220 | 1280, 1221 | 672, 1222 | 18, 1223 | "mediatek x20 (development board)" 1224 | ], 1225 | [ 1226 | 1794, 1227 | 1080, 1228 | 13, 1229 | "infocus tsp" 1230 | ], 1231 | [ 1232 | 1800, 1233 | 1080, 1234 | 16, 1235 | "infinix x602 zero 4 plus" 1236 | ], 1237 | [ 1238 | 1806, 1239 | 1080, 1240 | 16, 1241 | "tecno phantom a9" 1242 | ], 1243 | [ 1244 | 1810, 1245 | 1080, 1246 | 8, 1247 | "mobiistar prime x pro" 1248 | ], 1249 | [ 1250 | 1815, 1251 | 1080, 1252 | 16, 1253 | "tecno phantom 6 plus" 1254 | ], 1255 | [ 1256 | 1920, 1257 | 1080, 1258 | 7, 1259 | "elephone r9" 1260 | ], 1261 | [ 1262 | 2048, 1263 | 1440, 1264 | 12, 1265 | "brown tab 1" 1266 | ], 1267 | [ 1268 | 2392, 1269 | 1440, 1270 | 12, 1271 | "vernee apollo" 1272 | ], 1273 | [ 1274 | 2416, 1275 | 1440, 1276 | 11, 1277 | "freetel ftj162b kiwami2" 1278 | ], 1279 | [ 1280 | 2560, 1281 | 1440, 1282 | 10, 1283 | "ivvi i5" 1284 | ] 1285 | ] 1286 | ], 1287 | [ 1288 | "mali-t830", 1289 | "830", 1290 | "mali-t830", 1291 | 0, 1292 | [ 1293 | [ 1294 | 1480, 1295 | 720, 1296 | 10, 1297 | "samsung gm-j600fn" 1298 | ] 1299 | ] 1300 | ] 1301 | ] -------------------------------------------------------------------------------- /benchmarks/m-mali.json: -------------------------------------------------------------------------------- 1 | [ 2 | "5", 3 | [ 4 | "arm mali-g31", 5 | "31", 6 | "arm mali-g31", 7 | 0, 8 | [ 9 | [ 10 | 1920, 11 | 1080, 12 | 7, 13 | "mecool km9 pro" 14 | ] 15 | ] 16 | ], 17 | [ 18 | "arm mali-g51", 19 | "51", 20 | "arm mali-g51", 21 | 0, 22 | [ 23 | [ 24 | 1920, 25 | 636, 26 | 10, 27 | "telechips tcc803x_lcn" 28 | ], 29 | [ 30 | 1920, 31 | 1080, 32 | 5, 33 | "skyworth 8n10 g1a" 34 | ], 35 | [ 36 | 2224, 37 | 1080, 38 | 19, 39 | "huawei honor 9x" 40 | ] 41 | ] 42 | ], 43 | [ 44 | "arm mali-g52", 45 | "52", 46 | "arm mali-g52", 47 | 0, 48 | [ 49 | [ 50 | 1448, 51 | 720, 52 | 29, 53 | "samsung galaxy a21s" 54 | ], 55 | [ 56 | 1473, 57 | 720, 58 | 16, 59 | "samsung sm-a127f" 60 | ], 61 | [ 62 | 1554, 63 | 720, 64 | 18, 65 | "xiaomi redmi c3qp" 66 | ] 67 | ] 68 | ], 69 | [ 70 | "arm mali-g52 mc1", 71 | "52", 72 | "arm mali-g52 mc1", 73 | 0, 74 | [ 75 | [ 76 | 1280, 77 | 736, 78 | 25, 79 | "amazon fire hd 8 (kfonwi, 2020)" 80 | ] 81 | ] 82 | ], 83 | [ 84 | "arm mali-g52 mc2", 85 | "52", 86 | "arm mali-g52 mc2", 87 | 0, 88 | [ 89 | [ 90 | 1543, 91 | 688, 92 | 43, 93 | "ulefone power armor 14 pro" 94 | ], 95 | [ 96 | 2110, 97 | 1080, 98 | 23, 99 | "xiaomi redmi 10x 4g" 100 | ], 101 | [ 102 | 2195, 103 | 1080, 104 | 19, 105 | "samsung galaxy a31 (sm-a315n)" 106 | ], 107 | [ 108 | 2208, 109 | 1080, 110 | 22, 111 | "infinix hot 11s (x6812b)" 112 | ], 113 | [ 114 | 2264, 115 | 1080, 116 | 20, 117 | "xiaomi redmi 9 m2004j19c" 118 | ], 119 | [ 120 | 2400, 121 | 1080, 122 | 20, 123 | "huawei y9a frl-l22" 124 | ] 125 | ] 126 | ], 127 | [ 128 | "arm mali-g57", 129 | "57", 130 | "arm mali-g57", 131 | 0, 132 | [ 133 | [ 134 | 2256, 135 | 1080, 136 | 49, 137 | "unisoc ums9620" 138 | ] 139 | ] 140 | ], 141 | [ 142 | "arm mali-g57 mc2", 143 | "57", 144 | "arm mali-g57 mc2", 145 | 0, 146 | [ 147 | [ 148 | 2174, 149 | 1080, 150 | 39, 151 | "poco m4 pro 5g (21091116ag)" 152 | ], 153 | [ 154 | 2177, 155 | 1080, 156 | 36, 157 | "xiaomi poco m4 pro" 158 | ], 159 | [ 160 | 2208, 161 | 1080, 162 | 35, 163 | "samsung galaxy a22 5g" 164 | ] 165 | ] 166 | ], 167 | [ 168 | "arm mali-g57 mc3", 169 | "57", 170 | "arm mali-g57 mc3", 171 | 0, 172 | [ 173 | [ 174 | 2158, 175 | 1080, 176 | 48, 177 | "realme rmx2173" 178 | ] 179 | ] 180 | ], 181 | [ 182 | "arm mali-g610 mc6", 183 | "610", 184 | "arm mali-g610 mc6", 185 | 0, 186 | [ 187 | [ 188 | 2316, 189 | 1080, 190 | 60, 191 | "realme gt neo 3 150w" 192 | ] 193 | ] 194 | ], 195 | [ 196 | "arm mali-g68", 197 | "68", 198 | "arm mali-g68", 199 | 0, 200 | [ 201 | [ 202 | 2207, 203 | 1080, 204 | 57, 205 | "samsung galaxy m33" 206 | ] 207 | ] 208 | ], 209 | [ 210 | "arm mali-g68 mc4", 211 | "68", 212 | "arm mali-g68 mc4", 213 | 0, 214 | [ 215 | [ 216 | 2153, 217 | 1080, 218 | 56, 219 | "oppo reno6 5g" 220 | ], 221 | [ 222 | 2944, 223 | 1712, 224 | 31, 225 | "lenovo tab p12" 226 | ] 227 | ] 228 | ], 229 | [ 230 | "arm mali-g71", 231 | "71", 232 | "arm mali-g71", 233 | 0, 234 | [ 235 | [ 236 | 1280, 237 | 720, 238 | 14, 239 | "samsung sm-j337" 240 | ], 241 | [ 242 | 1812, 243 | 1080, 244 | 53, 245 | "huawei mate 9 (mha-xxx)" 246 | ], 247 | [ 248 | 1920, 249 | 1080, 250 | 12, 251 | "sony amai vp9 (mali-g71)" 252 | ], 253 | [ 254 | 2009, 255 | 1080, 256 | 11, 257 | "tcl 6062" 258 | ], 259 | [ 260 | 2016, 261 | 1080, 262 | 11, 263 | "gionee s11" 264 | ], 265 | [ 266 | 2038, 267 | 1080, 268 | 10, 269 | "ulefone power 3" 270 | ], 271 | [ 272 | 2076, 273 | 1080, 274 | 15, 275 | "samsung galaxy a8 2018 (sm-a530x)" 276 | ], 277 | [ 278 | 2094, 279 | 1080, 280 | 15, 281 | "samsung sm-a730x" 282 | ], 283 | [ 284 | 2160, 285 | 1080, 286 | 9, 287 | "oukitel k6" 288 | ], 289 | [ 290 | 2368, 291 | 1440, 292 | 35, 293 | "huawei honor v9 (duk-xxx)" 294 | ], 295 | [ 296 | 2560, 297 | 1440, 298 | 32, 299 | "huawei mate 9 pro (lon-xxx)" 300 | ], 301 | [ 302 | 2678, 303 | 1440, 304 | 41, 305 | "samsung galaxy s8 (mali-g71, sm-g950x)" 306 | ], 307 | [ 308 | 2960, 309 | 1440, 310 | 39, 311 | "samsung galaxy s8+ (mali-g71, sm-g955x)" 312 | ] 313 | ] 314 | ], 315 | [ 316 | "arm mali-g715-immortalis mc11", 317 | "715", 318 | "arm mali-g715-immortalis mc11", 319 | 0, 320 | [ 321 | [ 322 | 2311, 323 | 1080, 324 | 121, 325 | "vivo x90" 326 | ] 327 | ] 328 | ], 329 | [ 330 | "arm mali-g72", 331 | "72", 332 | "arm mali-g72", 333 | 0, 334 | [ 335 | [ 336 | 2041, 337 | 1080, 338 | 55, 339 | "huawei mate 10 pro (bla-xxx)" 340 | ], 341 | [ 342 | 2094, 343 | 1080, 344 | 57, 345 | "samsung galaxy note 9" 346 | ], 347 | [ 348 | 2160, 349 | 1080, 350 | 56, 351 | "huawei honor view 10 (v10, bkl-xxx)" 352 | ], 353 | [ 354 | 2186, 355 | 1080, 356 | 24, 357 | "samsung galaxy a51 (sm-a515f)" 358 | ], 359 | [ 360 | 2218, 361 | 1080, 362 | 21, 363 | "motorola one vision" 364 | ], 365 | [ 366 | 2560, 367 | 1440, 368 | 43, 369 | "huawei mate 10 (alp-xxx)" 370 | ], 371 | [ 372 | 2768, 373 | 1440, 374 | 47, 375 | "samsung galaxy s9 (mali-g72, sm-g960)" 376 | ], 377 | [ 378 | 2792, 379 | 1440, 380 | 47, 381 | "samsung galaxy s9+ (mali-g72, sm-g965)" 382 | ] 383 | ] 384 | ], 385 | [ 386 | "arm mali-g72 mp3", 387 | "72", 388 | "arm mali-g72 mp3", 389 | 0, 390 | [ 391 | [ 392 | 1465, 393 | 678, 394 | 39, 395 | "motorola one macro" 396 | ] 397 | ] 398 | ], 399 | [ 400 | "arm mali-g720-immortalis mc12", 401 | "720", 402 | "arm mali-g720-immortalis mc12", 403 | 0, 404 | [ 405 | [ 406 | 2680, 407 | 1260, 408 | 120, 409 | "vivo x100" 410 | ] 411 | ] 412 | ], 413 | [ 414 | "arm mali-g76", 415 | "76", 416 | "arm mali-g76", 417 | 0, 418 | [ 419 | [ 420 | 2020, 421 | 1080, 422 | 60, 423 | "samsung galaxy s10e (mali-g76, sm-g970x)" 424 | ], 425 | [ 426 | 2029, 427 | 1080, 428 | 31, 429 | "samsung galaxy s10 plus sm-g975n" 430 | ], 431 | [ 432 | 2047, 433 | 1080, 434 | 60, 435 | "samsung sm-g975f" 436 | ], 437 | [ 438 | 2064, 439 | 1080, 440 | 60, 441 | "samsung galaxy note 10 5g (mali-g76, sm-n971x)" 442 | ], 443 | [ 444 | 2111, 445 | 1080, 446 | 46, 447 | "huawei nova 5t (yal-l21)" 448 | ], 449 | [ 450 | 2159, 451 | 1080, 452 | 47, 453 | "samsung galaxy a51 5g" 454 | ], 455 | [ 456 | 2176, 457 | 1080, 458 | 54, 459 | "samsung galaxy s10 5g (sm-g977n)" 460 | ], 461 | [ 462 | 2232, 463 | 1080, 464 | 59, 465 | "huawei honor 20 pro yal-l41" 466 | ], 467 | [ 468 | 2265, 469 | 1080, 470 | 59, 471 | "huawei p30 pro" 472 | ], 473 | [ 474 | 2328, 475 | 1128, 476 | 60, 477 | "huawei mate 30 pro (lio-lx9, lio-xl00" 478 | ], 479 | [ 480 | 2723, 481 | 1440, 482 | 57, 483 | "samsung galaxy s10 (mali-g76, sm-g973x)" 484 | ], 485 | [ 486 | 2730, 487 | 1440, 488 | 56, 489 | "samsung galaxy s10+ (mali-g76, sm-g975x)" 490 | ], 491 | [ 492 | 2733, 493 | 1440, 494 | 56, 495 | "samsung galaxy s10 5g (mali-g76, sm-g977x)" 496 | ], 497 | [ 498 | 2759, 499 | 1440, 500 | 59, 501 | "samsung galaxy note 10+ (mali-g76, sm-n975x)" 502 | ], 503 | [ 504 | 2861, 505 | 1440, 506 | 48, 507 | "huawei mate 20 pro" 508 | ] 509 | ] 510 | ], 511 | [ 512 | "arm mali-g76 mc4", 513 | "76", 514 | "arm mali-g76 mc4", 515 | 0, 516 | [ 517 | [ 518 | 2134, 519 | 1080, 520 | 45, 521 | "xiaomi redmi note 8 pro" 522 | ] 523 | ] 524 | ], 525 | [ 526 | "arm mali-g77", 527 | "77", 528 | "arm mali-g77", 529 | 0, 530 | [ 531 | [ 532 | 2168, 533 | 1080, 534 | 93, 535 | "samsung galaxy s20 fe (sm-g780f)" 536 | ], 537 | [ 538 | 2173, 539 | 1080, 540 | 58, 541 | "samsung galaxy note 20 (sm-n980f)" 542 | ], 543 | [ 544 | 2178, 545 | 1080, 546 | 65, 547 | "samsung galaxy s20 5g (sm-g981b)" 548 | ], 549 | [ 550 | 2200, 551 | 1080, 552 | 113, 553 | "samsung galaxy s20 ultra 5g (sm-g988b)" 554 | ], 555 | [ 556 | 2327, 557 | 1038, 558 | 57, 559 | "samsung galaxy s20+ 5g (sm-g986b)" 560 | ], 561 | [ 562 | 2304, 563 | 1080, 564 | 55, 565 | "oppo pdcm00" 566 | ] 567 | ] 568 | ], 569 | [ 570 | "arm mali-g77 mc9", 571 | "77", 572 | "arm mali-g77 mc9", 573 | 0, 574 | [ 575 | [ 576 | 2161, 577 | 1080, 578 | 69, 579 | "oneplus nord 2 5g" 580 | ], 581 | [ 582 | 2293, 583 | 1080, 584 | 59, 585 | "oppo pdsm00" 586 | ], 587 | [ 588 | 2304, 589 | 1080, 590 | 102, 591 | "xiaomi poco x3 gt (21061110ag)" 592 | ] 593 | ] 594 | ], 595 | [ 596 | "arm mali-g78", 597 | "78", 598 | "arm mali-g78", 599 | 0, 600 | [ 601 | [ 602 | 2272, 603 | 1017, 604 | 90, 605 | "google pixel 6" 606 | ], 607 | [ 608 | 2176, 609 | 1080, 610 | 114, 611 | "samsung galaxy s21 5g (sm-g991b)" 612 | ], 613 | [ 614 | 2646, 615 | 1288, 616 | 90, 617 | "huawei mate 40 pro 5g" 618 | ] 619 | ] 620 | ], 621 | [ 622 | "arm mali-t604 mp4", 623 | "604", 624 | "arm mali-t604 mp4", 625 | 0, 626 | [ 627 | [ 628 | 2560, 629 | 1504, 630 | 4, 631 | "google nexus 10" 632 | ] 633 | ] 634 | ], 635 | [ 636 | "arm mali-t622", 637 | "622", 638 | "arm mali-t622", 639 | 0, 640 | [ 641 | [ 642 | 1024, 643 | 564, 644 | 12, 645 | "telechips tcc896x (quad core, development board)" 646 | ], 647 | [ 648 | 1280, 649 | 720, 650 | 7, 651 | "leadcore l1860 (mali-t622, development board)" 652 | ] 653 | ] 654 | ], 655 | [ 656 | "arm mali-t624", 657 | "624", 658 | "arm mali-t624", 659 | 0, 660 | [ 661 | [ 662 | 1794, 663 | 1080, 664 | 7, 665 | "huawei grace" 666 | ], 667 | [ 668 | 1812, 669 | 1080, 670 | 6, 671 | "huawei abc-ul00" 672 | ], 673 | [ 674 | 1830, 675 | 1080, 676 | 10, 677 | "huawei p8 max (dav-70x)" 678 | ], 679 | [ 680 | 1920, 681 | 1080, 682 | 4, 683 | "sony amai vp9" 684 | ], 685 | [ 686 | 1920, 687 | 1104, 688 | 9, 689 | "huawei dtab compact d-02h (docomo)" 690 | ], 691 | [ 692 | 1920, 693 | 1128, 694 | 8, 695 | "huawei dtab d-01h (docomo)" 696 | ], 697 | [ 698 | 1824, 699 | 1200, 700 | 9, 701 | "huawei mediapad m2 (m2-80xx)" 702 | ], 703 | [ 704 | 1830, 705 | 1200, 706 | 9, 707 | "huawei mediapad x2 (gem-701l, gem-702l, gem-703l)" 708 | ] 709 | ] 710 | ], 711 | [ 712 | "arm mali-t624 mp2", 713 | "624", 714 | "arm mali-t624 mp2", 715 | 0, 716 | [ 717 | [ 718 | 1280, 719 | 720, 720 | 5, 721 | "samsung sm-g910f (mali-t624)" 722 | ] 723 | ] 724 | ], 725 | [ 726 | "arm mali-t624 mp4", 727 | "624", 728 | "arm mali-t624 mp4", 729 | 0, 730 | [ 731 | [ 732 | 1794, 733 | 1080, 734 | 9, 735 | "huawei z100" 736 | ] 737 | ] 738 | ], 739 | [ 740 | "arm mali-t628", 741 | "628", 742 | "arm mali-t628", 743 | 0, 744 | [ 745 | [ 746 | 1024, 747 | 600, 748 | 30, 749 | "thinkware inavi davinci" 750 | ], 751 | [ 752 | 2560, 753 | 1536, 754 | 8, 755 | "meizu mx4 pro" 756 | ] 757 | ] 758 | ], 759 | [ 760 | "arm mali-t628 mp2", 761 | "628", 762 | "arm mali-t628 mp2", 763 | 0, 764 | [ 765 | [ 766 | 1280, 767 | 720, 768 | 8, 769 | "leadcore l1860 (development board)" 770 | ] 771 | ] 772 | ], 773 | [ 774 | "arm mali-t628 mp6", 775 | "628", 776 | "arm mali-t628 mp6", 777 | 0, 778 | [ 779 | [ 780 | 800, 781 | 480, 782 | 35, 783 | "gen2wave rp1600" 784 | ], 785 | [ 786 | 1280, 787 | 672, 788 | 14, 789 | "hardkernel odroid-xu3 (development board)" 790 | ], 791 | [ 792 | 1280, 793 | 720, 794 | 26, 795 | "samsung galaxy alpha (mali-t628, sm-g850)" 796 | ], 797 | [ 798 | 1920, 799 | 1080, 800 | 11, 801 | "samsung galaxy note iii (mali-t628, sm-n900, sm-n9000q)" 802 | ], 803 | [ 804 | 2560, 805 | 1600, 806 | 3, 807 | "samsung sm-t520 galaxy tab 10.1" 808 | ] 809 | ] 810 | ], 811 | [ 812 | "arm mali-t720", 813 | "720", 814 | "arm mali-t720", 815 | 0, 816 | [ 817 | [ 818 | 432, 819 | 240, 820 | 16, 821 | "unihertz jelly pro" 822 | ], 823 | [ 824 | 782, 825 | 480, 826 | 8, 827 | "mobiistar lai zoro" 828 | ], 829 | [ 830 | 784, 831 | 480, 832 | 8, 833 | "lg k3 (k100)" 834 | ], 835 | [ 836 | 791, 837 | 480, 838 | 6, 839 | "i-mobile i-style 812 4g" 840 | ], 841 | [ 842 | 800, 843 | 480, 844 | 4, 845 | "lava iris 550" 846 | ], 847 | [ 848 | 854, 849 | 480, 850 | 3, 851 | "verykool sl5009 jet" 852 | ], 853 | [ 854 | 897, 855 | 540, 856 | 5, 857 | "bluboo xfire" 858 | ], 859 | [ 860 | 960, 861 | 540, 862 | 3, 863 | "siswoo a5 chocolate" 864 | ], 865 | [ 866 | 1024, 867 | 552, 868 | 4, 869 | "bb-mobile tq763i techno 7.0 lte" 870 | ], 871 | [ 872 | 1024, 873 | 714, 874 | 9, 875 | "bluedot bnt-791 (2g)" 876 | ], 877 | [ 878 | 1024, 879 | 720, 880 | 3, 881 | "zte e8qp" 882 | ], 883 | [ 884 | 1280, 885 | 624, 886 | 10, 887 | "panasonic p55 novo 4g" 888 | ], 889 | [ 890 | 1280, 891 | 648, 892 | 4, 893 | "tcl 9025" 894 | ], 895 | [ 896 | 1280, 897 | 656, 898 | 7, 899 | "acer a1-734 iconia talk s" 900 | ], 901 | [ 902 | 1184, 903 | 720, 904 | 4, 905 | "lenovo xt1700, xt1706, k10a40" 906 | ], 907 | [ 908 | 1187, 909 | 720, 910 | 7, 911 | "lg k8 (k350)" 912 | ], 913 | [ 914 | 1189, 915 | 720, 916 | 5, 917 | "ark impulse p2" 918 | ], 919 | [ 920 | 1193, 921 | 720, 922 | 7, 923 | "lg x power (k220, f750)" 924 | ], 925 | [ 926 | 1196, 927 | 720, 928 | 2, 929 | "dtac phone m2" 930 | ], 931 | [ 932 | 1198, 933 | 720, 934 | 5, 935 | "dtac phone t3" 936 | ], 937 | [ 938 | 1205, 939 | 720, 940 | 7, 941 | "firefly aurii passion" 942 | ], 943 | [ 944 | 1206, 945 | 720, 946 | 4, 947 | "archos 50 power" 948 | ], 949 | [ 950 | 1208, 951 | 720, 952 | 3, 953 | "advan i7 plus" 954 | ], 955 | [ 956 | 1217, 957 | 720, 958 | 7, 959 | "energy sistem energy phone max 2+" 960 | ], 961 | [ 962 | 1238, 963 | 720, 964 | 9, 965 | "vnpt technology vivas lotus s3 lte" 966 | ], 967 | [ 968 | 1280, 969 | 720, 970 | 2, 971 | "archos bush spira c2 5" 972 | ], 973 | [ 974 | 1280, 975 | 736, 976 | 2, 977 | "digma cs1062ml citi 1903 4g" 978 | ], 979 | [ 980 | 1280, 981 | 737, 982 | 3, 983 | "waywalkers t805g" 984 | ], 985 | [ 986 | 1280, 987 | 740, 988 | 3, 989 | "casper via l8" 990 | ], 991 | [ 992 | 1280, 993 | 746, 994 | 3, 995 | "philips tle821l e line 4g" 996 | ], 997 | [ 998 | 1280, 999 | 752, 1000 | 3, 1001 | "4good light at200" 1002 | ], 1003 | [ 1004 | 1280, 1005 | 755, 1006 | 7, 1007 | "leotec letab1020 supernova qi32" 1008 | ], 1009 | [ 1010 | 1356, 1011 | 720, 1012 | 8, 1013 | "xiaolajiao la-v11" 1014 | ], 1015 | [ 1016 | 1360, 1017 | 720, 1018 | 7, 1019 | "tecno in5" 1020 | ], 1021 | [ 1022 | 1368, 1023 | 720, 1024 | 7, 1025 | "tinno p100" 1026 | ], 1027 | [ 1028 | 1280, 1029 | 800, 1030 | 4, 1031 | "samsung galaxy tab e 8.0 (sm-t375x, sm-t377x)" 1032 | ], 1033 | [ 1034 | 1920, 1035 | 936, 1036 | 4, 1037 | "panasonic eluga note" 1038 | ], 1039 | [ 1040 | 1920, 1041 | 996, 1042 | 4, 1043 | "cube technology u83 iplay10" 1044 | ], 1045 | [ 1046 | 1776, 1047 | 1080, 1048 | 4, 1049 | "fly fs522 cirrus 14" 1050 | ], 1051 | [ 1052 | 1787, 1053 | 1080, 1054 | 5, 1055 | "lg x cam (k580, f690)" 1056 | ], 1057 | [ 1058 | 1920, 1059 | 1008, 1060 | 6, 1061 | "alcatel one touch xess (p17aa)" 1062 | ], 1063 | [ 1064 | 1794, 1065 | 1080, 1066 | 3, 1067 | "ramos mos 1 max" 1068 | ], 1069 | [ 1070 | 1800, 1071 | 1080, 1072 | 4, 1073 | "archos sense 55 s" 1074 | ], 1075 | [ 1076 | 1815, 1077 | 1080, 1078 | 4, 1079 | "archos diamond plus" 1080 | ], 1081 | [ 1082 | 1920, 1083 | 1032, 1084 | 5, 1085 | "virgin media tellytablet" 1086 | ], 1087 | [ 1088 | 1920, 1089 | 1080, 1090 | 2, 1091 | "infocus m640" 1092 | ], 1093 | [ 1094 | 1920, 1095 | 1104, 1096 | 4, 1097 | "vestel v tab 7030" 1098 | ], 1099 | [ 1100 | 1920, 1101 | 1116, 1102 | 4, 1103 | "jty q101" 1104 | ], 1105 | [ 1106 | 1920, 1107 | 1128, 1108 | 2, 1109 | "archos 80 oxygen" 1110 | ], 1111 | [ 1112 | 2009, 1113 | 1080, 1114 | 4, 1115 | "tcl 5099" 1116 | ], 1117 | [ 1118 | 1920, 1119 | 1136, 1120 | 4, 1121 | "asus zenpad 10 (p028 z301m)" 1122 | ], 1123 | [ 1124 | 2712, 1125 | 1440, 1126 | 45, 1127 | "lenovo tab 2 501lv (softbank)" 1128 | ] 1129 | ] 1130 | ], 1131 | [ 1132 | "arm mali-t760", 1133 | "760", 1134 | "arm mali-t760", 1135 | 0, 1136 | [ 1137 | [ 1138 | 854, 1139 | 480, 1140 | 14, 1141 | "aux t6200l" 1142 | ], 1143 | [ 1144 | 897, 1145 | 540, 1146 | 13, 1147 | "sony xperia e4g (e20xx)" 1148 | ], 1149 | [ 1150 | 960, 1151 | 540, 1152 | 12, 1153 | "gionee v381" 1154 | ], 1155 | [ 1156 | 960, 1157 | 568, 1158 | 24, 1159 | "asus c100pa chromebook flip" 1160 | ], 1161 | [ 1162 | 1024, 1163 | 552, 1164 | 12, 1165 | "archos 70 helium" 1166 | ], 1167 | [ 1168 | 1024, 1169 | 720, 1170 | 10, 1171 | "wiz t-8168" 1172 | ], 1173 | [ 1174 | 1188, 1175 | 720, 1176 | 9, 1177 | "lg h520 magna, h522 prime plus" 1178 | ], 1179 | [ 1180 | 1196, 1181 | 720, 1182 | 9, 1183 | "acer s57 liquid jade z" 1184 | ], 1185 | [ 1186 | 1280, 1187 | 720, 1188 | 8, 1189 | "dunetek vitamin a" 1190 | ], 1191 | [ 1192 | 1280, 1193 | 736, 1194 | 8, 1195 | "archos 80b helium" 1196 | ], 1197 | [ 1198 | 1280, 1199 | 752, 1200 | 8, 1201 | "frael m10g 4g" 1202 | ], 1203 | [ 1204 | 1280, 1205 | 768, 1206 | 8, 1207 | "meizu m1" 1208 | ], 1209 | [ 1210 | 1794, 1211 | 1080, 1212 | 6, 1213 | "sugar 2 ss136 l8560" 1214 | ], 1215 | [ 1216 | 1920, 1217 | 1032, 1218 | 9, 1219 | "qbic bxp-300 box pc" 1220 | ], 1221 | [ 1222 | 1920, 1223 | 1080, 1224 | 4, 1225 | "byxpress mphone xone" 1226 | ], 1227 | [ 1228 | 1920, 1229 | 1104, 1230 | 6, 1231 | "cube technology t7" 1232 | ], 1233 | [ 1234 | 1920, 1235 | 1128, 1236 | 5, 1237 | "nec lavietab pc-te510bal" 1238 | ], 1239 | [ 1240 | 2048, 1241 | 1440, 1242 | 3, 1243 | "teclast p98 4g" 1244 | ], 1245 | [ 1246 | 2560, 1247 | 1440, 1248 | 10, 1249 | "samsung galaxy note 4 (mali-t760, sm-n910x, sm-n916)" 1250 | ] 1251 | ] 1252 | ], 1253 | [ 1254 | "arm mali-t760 mp6", 1255 | "760", 1256 | "arm mali-t760 mp6", 1257 | 0, 1258 | [ 1259 | [ 1260 | 1920, 1261 | 1080, 1262 | 17, 1263 | "samsung galaxy a8 (mali-t760, sm-a800x, scv32)" 1264 | ], 1265 | [ 1266 | 2048, 1267 | 1536, 1268 | 12, 1269 | "samsung galaxy tab s 2 8.0 (sm-t710, sm-t715)" 1270 | ], 1271 | [ 1272 | 2560, 1273 | 1532, 1274 | 10, 1275 | "samsung galaxy note edge (mali-t760, sm-n915x)" 1276 | ], 1277 | [ 1278 | 2560, 1279 | 1600, 1280 | 10, 1281 | "samsung galaxy tab s 10.5 (mali-t760, sm-t805s)" 1282 | ] 1283 | ] 1284 | ], 1285 | [ 1286 | "arm mali-t760 mp8", 1287 | "760", 1288 | "arm mali-t760 mp8", 1289 | 0, 1290 | [ 1291 | [ 1292 | 1280, 1293 | 768, 1294 | 42, 1295 | "samsung sm-w2016" 1296 | ], 1297 | [ 1298 | 1920, 1299 | 1080, 1300 | 25, 1301 | "meizu niux" 1302 | ], 1303 | [ 1304 | 2160, 1305 | 1200, 1306 | 17, 1307 | "idealens k2" 1308 | ], 1309 | [ 1310 | 2560, 1311 | 1440, 1312 | 12, 1313 | "le xiang deepoon m2 vr" 1314 | ], 1315 | [ 1316 | 2560, 1317 | 1504, 1318 | 15, 1319 | "bungbungame kalos 2" 1320 | ] 1321 | ] 1322 | ], 1323 | [ 1324 | "arm mali-t764", 1325 | "764", 1326 | "arm mali-t764", 1327 | 0, 1328 | [ 1329 | [ 1330 | 1024, 1331 | 600, 1332 | 19, 1333 | "gpd q9" 1334 | ], 1335 | [ 1336 | 1280, 1337 | 720, 1338 | 15, 1339 | "gpd xd" 1340 | ], 1341 | [ 1342 | 1280, 1343 | 752, 1344 | 13, 1345 | "kruger & matz 1064.1g eagle" 1346 | ], 1347 | [ 1348 | 1280, 1349 | 800, 1350 | 13, 1351 | "pipo p7" 1352 | ], 1353 | [ 1354 | 1920, 1355 | 1008, 1356 | 6, 1357 | "rockchip mk809 4k tv stick" 1358 | ], 1359 | [ 1360 | 1920, 1361 | 1010, 1362 | 8, 1363 | "pipo p7 hd" 1364 | ], 1365 | [ 1366 | 1920, 1367 | 1020, 1368 | 5, 1369 | "rockchip mk903v mini tv" 1370 | ], 1371 | [ 1372 | 1920, 1373 | 1032, 1374 | 7, 1375 | "acooo oneboard pro+" 1376 | ], 1377 | [ 1378 | 1872, 1379 | 1080, 1380 | 7, 1381 | "contextmedia wallboard 32 tablet (p-wal-106-yit-01)" 1382 | ], 1383 | [ 1384 | 1920, 1385 | 1080, 1386 | 7, 1387 | "rockchip cs4k tv box" 1388 | ], 1389 | [ 1390 | 1920, 1391 | 1128, 1392 | 7, 1393 | "archos 101 oxygen" 1394 | ], 1395 | [ 1396 | 2048, 1397 | 1437, 1398 | 5, 1399 | "haier pad 971" 1400 | ], 1401 | [ 1402 | 2048, 1403 | 1440, 1404 | 5, 1405 | "hisense f5281 vidaa pad" 1406 | ], 1407 | [ 1408 | 2560, 1409 | 1504, 1410 | 4, 1411 | "teclast p90hd" 1412 | ] 1413 | ] 1414 | ], 1415 | [ 1416 | "arm mali-t820", 1417 | "820", 1418 | "arm mali-t820", 1419 | 0, 1420 | [ 1421 | [ 1422 | 1344, 1423 | 720, 1424 | 5, 1425 | "lenovo k320t" 1426 | ], 1427 | [ 1428 | 1776, 1429 | 1080, 1430 | 6, 1431 | "leagoo t5c" 1432 | ], 1433 | [ 1434 | 1920, 1435 | 1008, 1436 | 7, 1437 | "probox2 ava tv box" 1438 | ], 1439 | [ 1440 | 1920, 1441 | 1080, 1442 | 4, 1443 | "skyworth coocaa 5s32 n2" 1444 | ] 1445 | ] 1446 | ], 1447 | [ 1448 | "arm mali-t830", 1449 | "830", 1450 | "arm mali-t830", 1451 | 0, 1452 | [ 1453 | [ 1454 | 1280, 1455 | 720, 1456 | 9, 1457 | "samsung galaxy on7 (mali-t830, sm-g600x)" 1458 | ], 1459 | [ 1460 | 1280, 1461 | 800, 1462 | 9, 1463 | "samsung sm-t230nw (mali-t830)" 1464 | ], 1465 | [ 1466 | 1776, 1467 | 1080, 1468 | 9, 1469 | "huawei p10 lite (was-xxx)" 1470 | ], 1471 | [ 1472 | 1794, 1473 | 1080, 1474 | 9, 1475 | "huawei honor 6x (bln-xxx)" 1476 | ], 1477 | [ 1478 | 1920, 1479 | 1080, 1480 | 5, 1481 | "samsung galaxy on7 prime 2018 (sm-g611)" 1482 | ], 1483 | [ 1484 | 2033, 1485 | 1080, 1486 | 8, 1487 | "huawei p smart (fig-xxx)" 1488 | ], 1489 | [ 1490 | 2040, 1491 | 1080, 1492 | 9, 1493 | "huawei maimang 6 (rne-xxx)" 1494 | ], 1495 | [ 1496 | 1920, 1497 | 1200, 1498 | 5, 1499 | "samsung galaxy tab a 10.1 (sm-t580, sm-t585)" 1500 | ] 1501 | ] 1502 | ], 1503 | [ 1504 | "arm mali-t860", 1505 | "860", 1506 | "arm mali-t860", 1507 | 0, 1508 | [ 1509 | [ 1510 | 1184, 1511 | 720, 1512 | 8, 1513 | "tcl a626" 1514 | ], 1515 | [ 1516 | 1196, 1517 | 720, 1518 | 8, 1519 | "green orange go t2" 1520 | ], 1521 | [ 1522 | 1280, 1523 | 720, 1524 | 14, 1525 | "htc one a9s" 1526 | ], 1527 | [ 1528 | 1920, 1529 | 1024, 1530 | 17, 1531 | "hardkernel odroid-n1 (development board)" 1532 | ], 1533 | [ 1534 | 1920, 1535 | 1032, 1536 | 16, 1537 | "contextmedia p-wal-108-elc-02" 1538 | ], 1539 | [ 1540 | 1920, 1541 | 1080, 1542 | 7, 1543 | "htc u play (u-2u)" 1544 | ], 1545 | [ 1546 | 1920, 1547 | 1116, 1548 | 15, 1549 | "imuz revolution a8" 1550 | ], 1551 | [ 1552 | 1920, 1553 | 1128, 1554 | 15, 1555 | "rockchip rk3399 (development board)" 1556 | ], 1557 | [ 1558 | 2400, 1559 | 1440, 1560 | 10, 1561 | "samsung chromebook plus (kevin)" 1562 | ] 1563 | ] 1564 | ], 1565 | [ 1566 | "arm mali-t860 mp2", 1567 | "860", 1568 | "arm mali-t860 mp2", 1569 | 0, 1570 | [ 1571 | [ 1572 | 598, 1573 | 480, 1574 | 25, 1575 | "cipherlab 9700a" 1576 | ], 1577 | [ 1578 | 1184, 1579 | 720, 1580 | 11, 1581 | "vernee m5" 1582 | ], 1583 | [ 1584 | 1193, 1585 | 720, 1586 | 11, 1587 | "lg x power 2 (u+, x500, m-x320, m320)" 1588 | ], 1589 | [ 1590 | 1196, 1591 | 720, 1592 | 11, 1593 | "lava z25" 1594 | ], 1595 | [ 1596 | 1199, 1597 | 720, 1598 | 11, 1599 | "lg stylus 3 (m400)" 1600 | ], 1601 | [ 1602 | 1212, 1603 | 720, 1604 | 11, 1605 | "meeg 306" 1606 | ], 1607 | [ 1608 | 1280, 1609 | 720, 1610 | 10, 1611 | "oppo r66" 1612 | ], 1613 | [ 1614 | 1336, 1615 | 720, 1616 | 13, 1617 | "asus pegasus 4s (x018d zb570tl)" 1618 | ], 1619 | [ 1620 | 1344, 1621 | 720, 1622 | 13, 1623 | "allview x4 soul infinity n" 1624 | ], 1625 | [ 1626 | 1776, 1627 | 1080, 1628 | 7, 1629 | "benq f55" 1630 | ], 1631 | [ 1632 | 1794, 1633 | 1080, 1634 | 6, 1635 | "alcatel 7070" 1636 | ], 1637 | [ 1638 | 1798, 1639 | 1080, 1640 | 7, 1641 | "energy sistem energy phone pro 3" 1642 | ], 1643 | [ 1644 | 1806, 1645 | 1080, 1646 | 8, 1647 | "tecno phantom 6" 1648 | ], 1649 | [ 1650 | 1807, 1651 | 1080, 1652 | 7, 1653 | "covia fleaz cp-j55a g07" 1654 | ], 1655 | [ 1656 | 1810, 1657 | 1080, 1658 | 8, 1659 | "archos 55 diamond 2 plus" 1660 | ], 1661 | [ 1662 | 1920, 1663 | 1080, 1664 | 4, 1665 | "advan vandroid i55c" 1666 | ], 1667 | [ 1668 | 2004, 1669 | 1080, 1670 | 7, 1671 | "asus zenfone max plus m1 (x018d zb570tl)" 1672 | ], 1673 | [ 1674 | 1920, 1675 | 1128, 1676 | 7, 1677 | "verizon qtaxia1" 1678 | ] 1679 | ] 1680 | ], 1681 | [ 1682 | "arm mali-t880", 1683 | "880", 1684 | "arm mali-t880", 1685 | 0, 1686 | [ 1687 | [ 1688 | 1184, 1689 | 720, 1690 | 22, 1691 | "doogee mix" 1692 | ], 1693 | [ 1694 | 1280, 1695 | 720, 1696 | 20, 1697 | "lenovo k8" 1698 | ], 1699 | [ 1700 | 1344, 1701 | 720, 1702 | 18, 1703 | "casper via f2" 1704 | ], 1705 | [ 1706 | 1776, 1707 | 1080, 1708 | 11, 1709 | "alcatel 6060 (mali-t880)" 1710 | ], 1711 | [ 1712 | 1794, 1713 | 1080, 1714 | 20, 1715 | "huawei mate 8 (nxt-xxx)" 1716 | ], 1717 | [ 1718 | 1824, 1719 | 1080, 1720 | 11, 1721 | "meiigoo m1" 1722 | ], 1723 | [ 1724 | 1920, 1725 | 1080, 1726 | 10, 1727 | "letv leeco lex650" 1728 | ], 1729 | [ 1730 | 2016, 1731 | 1080, 1732 | 9, 1733 | "vernee mix 2" 1734 | ], 1735 | [ 1736 | 2064, 1737 | 1080, 1738 | 10, 1739 | "umi s2 pro" 1740 | ], 1741 | [ 1742 | 2392, 1743 | 1440, 1744 | 12, 1745 | "huawei honor v8 (knt-al20)" 1746 | ], 1747 | [ 1748 | 2434, 1749 | 1440, 1750 | 11, 1751 | "huawei honor note 8 premium edition (edi-al10)" 1752 | ], 1753 | [ 1754 | 2560, 1755 | 1440, 1756 | 24, 1757 | "meizu pro 6 plus" 1758 | ], 1759 | [ 1760 | 2560, 1761 | 1480, 1762 | 10, 1763 | "huawei dtab compact d-01j (docomo)" 1764 | ], 1765 | [ 1766 | 2560, 1767 | 1600, 1768 | 10, 1769 | "huawei mediapad m3 (btv-xxx)" 1770 | ] 1771 | ] 1772 | ], 1773 | [ 1774 | "arm mali-t880 mp12", 1775 | "880", 1776 | "arm mali-t880 mp12", 1777 | 0, 1778 | [ 1779 | [ 1780 | 1920, 1781 | 1080, 1782 | 44, 1783 | "samsung galaxy s7 (sm-g930f)" 1784 | ], 1785 | [ 1786 | 2560, 1787 | 1440, 1788 | 27, 1789 | "samsung galaxy note 7 (mali-t880, sm-n930)" 1790 | ] 1791 | ] 1792 | ], 1793 | [ 1794 | "arm mali-t880 mp2", 1795 | "880", 1796 | "arm mali-t880 mp2", 1797 | 0, 1798 | [ 1799 | [ 1800 | 1184, 1801 | 720, 1802 | 19, 1803 | "sony pikachu" 1804 | ], 1805 | [ 1806 | 1376, 1807 | 720, 1808 | 17, 1809 | "umi s2" 1810 | ], 1811 | [ 1812 | 1776, 1813 | 1080, 1814 | 10, 1815 | "coolpad a9s-9" 1816 | ], 1817 | [ 1818 | 1800, 1819 | 1080, 1820 | 11, 1821 | "infinix x603" 1822 | ], 1823 | [ 1824 | 1920, 1825 | 1080, 1826 | 9, 1827 | "innjoo pro2" 1828 | ] 1829 | ] 1830 | ], 1831 | [ 1832 | "arm mali-t880 mp4", 1833 | "880", 1834 | "arm mali-t880 mp4", 1835 | 0, 1836 | [ 1837 | [ 1838 | 1280, 1839 | 672, 1840 | 18, 1841 | "mediatek x20 (development board)" 1842 | ], 1843 | [ 1844 | 1794, 1845 | 1080, 1846 | 13, 1847 | "infocus tsp" 1848 | ], 1849 | [ 1850 | 1800, 1851 | 1080, 1852 | 16, 1853 | "infinix x602 zero 4 plus" 1854 | ], 1855 | [ 1856 | 1806, 1857 | 1080, 1858 | 16, 1859 | "tecno phantom a9" 1860 | ], 1861 | [ 1862 | 1810, 1863 | 1080, 1864 | 8, 1865 | "mobiistar prime x pro" 1866 | ], 1867 | [ 1868 | 1815, 1869 | 1080, 1870 | 16, 1871 | "tecno phantom 6 plus" 1872 | ], 1873 | [ 1874 | 1920, 1875 | 1080, 1876 | 7, 1877 | "elephone r9" 1878 | ], 1879 | [ 1880 | 2048, 1881 | 1440, 1882 | 12, 1883 | "brown tab 1" 1884 | ], 1885 | [ 1886 | 2392, 1887 | 1440, 1888 | 12, 1889 | "vernee apollo" 1890 | ], 1891 | [ 1892 | 2416, 1893 | 1440, 1894 | 11, 1895 | "freetel ftj162b kiwami2" 1896 | ], 1897 | [ 1898 | 2560, 1899 | 1440, 1900 | 10, 1901 | "ivvi i5" 1902 | ] 1903 | ] 1904 | ], 1905 | [ 1906 | "mali-g71", 1907 | "71", 1908 | "mali-g71", 1909 | 0, 1910 | [ 1911 | [ 1912 | 2220, 1913 | 1080, 1914 | 54, 1915 | "samsung s8+ sm-g955f" 1916 | ] 1917 | ] 1918 | ], 1919 | [ 1920 | "mali-g72", 1921 | "72", 1922 | "mali-g72", 1923 | 0, 1924 | [ 1925 | [ 1926 | 2220, 1927 | 1080, 1928 | 56, 1929 | "samsung s9+ sm-g965f" 1930 | ] 1931 | ] 1932 | ], 1933 | [ 1934 | "mali-t830", 1935 | "830", 1936 | "mali-t830", 1937 | 0, 1938 | [ 1939 | [ 1940 | 1480, 1941 | 720, 1942 | 10, 1943 | "samsung gm-j600fn" 1944 | ] 1945 | ] 1946 | ] 1947 | ] -------------------------------------------------------------------------------- /benchmarks/m-nvidia.json: -------------------------------------------------------------------------------- 1 | [ 2 | "5", 3 | [ 4 | "nvidia tegra", 5 | "", 6 | "nvidia tegra", 7 | 0, 8 | [ 9 | [ 10 | 2048, 11 | 1440, 12 | 23, 13 | "google nexus 9" 14 | ] 15 | ] 16 | ], 17 | [ 18 | "nvidia tegra k1", 19 | "1", 20 | "k1 nvidia tegra", 21 | 0, 22 | [ 23 | [ 24 | 1920, 25 | 1008, 26 | 32, 27 | "nvidia jetson tk1 (pm375, development board)" 28 | ], 29 | [ 30 | 1920, 31 | 1032, 32 | 12, 33 | "lenovo k1 hd (2014)" 34 | ], 35 | [ 36 | 1920, 37 | 1080, 38 | 28, 39 | "nvidia tegra gk20a (ardbeg, development board)" 40 | ], 41 | [ 42 | 1920, 43 | 1104, 44 | 29, 45 | "google project tango" 46 | ], 47 | [ 48 | 2048, 49 | 1536, 50 | 21, 51 | "xiaomi mi pad" 52 | ], 53 | [ 54 | 3840, 55 | 2088, 56 | 8, 57 | "lenovo thinkvision 28" 58 | ] 59 | ] 60 | ], 61 | [ 62 | "nvidia tegra x1", 63 | "1", 64 | "nvidia tegra x1", 65 | 0, 66 | [ 67 | [ 68 | 1920, 69 | 1080, 70 | 60, 71 | "nvidia shield android tv" 72 | ], 73 | [ 74 | 2560, 75 | 1688, 76 | 33, 77 | "google pixel c" 78 | ] 79 | ] 80 | ] 81 | ] -------------------------------------------------------------------------------- /benchmarks/m-powervr.json: -------------------------------------------------------------------------------- 1 | [ 2 | "5", 3 | [ 4 | "powervr rogue g6110", 5 | "6110", 6 | "g6110 powervr rogue", 7 | 0, 8 | [ 9 | [ 10 | 1024, 11 | 600, 12 | 11, 13 | "dasaita mtcd px5 head unit" 14 | ], 15 | [ 16 | 1280, 17 | 752, 18 | 8, 19 | "visual land prestige prime 10se" 20 | ], 21 | [ 22 | 1366, 23 | 720, 24 | 7, 25 | "ditecma m1092r" 26 | ], 27 | [ 28 | 1920, 29 | 1008, 30 | 6, 31 | "vensmile t051 tv box" 32 | ], 33 | [ 34 | 1920, 35 | 1016, 36 | 5, 37 | "geekbuying geekbox tv box" 38 | ], 39 | [ 40 | 1920, 41 | 1032, 42 | 4, 43 | "hannspree hsg1351" 44 | ], 45 | [ 46 | 1920, 47 | 1080, 48 | 5, 49 | "10moons tv box (rogue g6110)" 50 | ], 51 | [ 52 | 1920, 53 | 1128, 54 | 5, 55 | "teclast p10" 56 | ] 57 | ] 58 | ], 59 | [ 60 | "powervr rogue g6200", 61 | "6200", 62 | "g6200 powervr rogue", 63 | 0, 64 | [ 65 | [ 66 | 1280, 67 | 720, 68 | 15, 69 | "infocus m530" 70 | ], 71 | [ 72 | 1280, 73 | 736, 74 | 12, 75 | "amazon kindle fire hd 8 (5th gen, kfmewi)" 76 | ], 77 | [ 78 | 1280, 79 | 752, 80 | 12, 81 | "amazon kindle fire hd 10 (5th gen, kftbwi)" 82 | ], 83 | [ 84 | 1280, 85 | 800, 86 | 9, 87 | "amazon kindle fire hd 7 (4th gen, kfaswi)" 88 | ], 89 | [ 90 | 1794, 91 | 1080, 92 | 5, 93 | "ubik uno" 94 | ], 95 | [ 96 | 1920, 97 | 1080, 98 | 6, 99 | "cherry mobile x220 cosmos one plus" 100 | ], 101 | [ 102 | 1920, 103 | 1152, 104 | 8, 105 | "meizu mx4 (m460, m460a, m461)" 106 | ], 107 | [ 108 | 2392, 109 | 1440, 110 | 6, 111 | "hasee hl9916004" 112 | ], 113 | [ 114 | 2560, 115 | 1440, 116 | 6, 117 | "condor allure a100 pgn-607" 118 | ] 119 | ] 120 | ], 121 | [ 122 | "powervr rogue g6230", 123 | "6230", 124 | "g6230 powervr rogue", 125 | 0, 126 | [ 127 | [ 128 | 1920, 129 | 1008, 130 | 8, 131 | "rikomagic mk80 tv box (tronsmart draco aw80, fantasy a80)" 132 | ], 133 | [ 134 | 1920, 135 | 1016, 136 | 7, 137 | "cubietech cubieboard 4 (cc-a80, hansen-a80, development board)" 138 | ], 139 | [ 140 | 2048, 141 | 1440, 142 | 5, 143 | "teclast p98air" 144 | ], 145 | [ 146 | 2048, 147 | 1464, 148 | 7, 149 | "actions gs900a (development board)" 150 | ] 151 | ] 152 | ], 153 | [ 154 | "powervr rogue g6400", 155 | "6400", 156 | "g6400 powervr rogue", 157 | 0, 158 | [ 159 | [ 160 | 1794, 161 | 1080, 162 | 8, 163 | "lg f490 liger (g6400)" 164 | ], 165 | [ 166 | 1920, 167 | 1032, 168 | 8, 169 | "renesas lager" 170 | ] 171 | ] 172 | ], 173 | [ 174 | "powervr rogue g6430", 175 | "6430", 176 | "g6430 powervr rogue", 177 | 0, 178 | [ 179 | [ 180 | 1024, 181 | 552, 182 | 26, 183 | "asus fonepad 7 (k01f fe171mg)" 184 | ], 185 | [ 186 | 1280, 187 | 720, 188 | 27, 189 | "asus zenfone 2 (z008 ze550ml)" 190 | ], 191 | [ 192 | 1280, 193 | 736, 194 | 20, 195 | "asus fonepad 7 (k019 fe375cg)" 196 | ], 197 | [ 198 | 1280, 199 | 752, 200 | 27, 201 | "asus zenpad 10 (p01t z300cl)" 202 | ], 203 | [ 204 | 1788, 205 | 1080, 206 | 8, 207 | "lg f490 liger (g6430)" 208 | ], 209 | [ 210 | 1920, 211 | 1080, 212 | 15, 213 | "asus zenfone zoom (intel z3560, z00xsb zx551ml)" 214 | ], 215 | [ 216 | 1920, 217 | 1104, 218 | 11, 219 | "asus memo pad 8 ast21 (intel z3580, k015 me581cl)" 220 | ], 221 | [ 222 | 2048, 223 | 1440, 224 | 11, 225 | "asus zenpad s 8.0 (p01m z580c)" 226 | ], 227 | [ 228 | 2560, 229 | 1504, 230 | 9, 231 | "dell venue 10 7040" 232 | ] 233 | ] 234 | ], 235 | [ 236 | "powervr rogue ge8100", 237 | "8100", 238 | "ge8100 powervr rogue", 239 | 0, 240 | [ 241 | [ 242 | 906, 243 | 480, 244 | 8, 245 | "tinno k600" 246 | ], 247 | [ 248 | 1184, 249 | 720, 250 | 5, 251 | "mediatek mt6739 (development board, rogue ge8100)" 252 | ], 253 | [ 254 | 1339, 255 | 720, 256 | 5, 257 | "vodafone vfd 720" 258 | ], 259 | [ 260 | 1344, 261 | 720, 262 | 6, 263 | "gionee f205" 264 | ] 265 | ] 266 | ], 267 | [ 268 | "powervr rogue ge8300", 269 | "8300", 270 | "ge8300 powervr rogue", 271 | 0, 272 | [ 273 | [ 274 | 1280, 275 | 752, 276 | 9, 277 | "acer b3-a40 iconia one 10" 278 | ], 279 | [ 280 | 1208, 281 | 800, 282 | 8, 283 | "verizon qtaki1" 284 | ], 285 | [ 286 | 1920, 287 | 1128, 288 | 5, 289 | "acer b3-a40 fhd iconia one 10" 290 | ] 291 | ] 292 | ], 293 | [ 294 | "powervr rogue ge8320", 295 | "8320", 296 | "ge8320 powervr rogue", 297 | 0, 298 | [ 299 | [ 300 | 1465, 301 | 720, 302 | 21, 303 | "samsung galaxy a12" 304 | ] 305 | ] 306 | ], 307 | [ 308 | "powervr rogue gx6250", 309 | "6250", 310 | "gx6250 powervr rogue", 311 | 0, 312 | [ 313 | [ 314 | 688, 315 | 412, 316 | 16, 317 | "lenovo n23 yoga / flex 11 chromebook" 318 | ], 319 | [ 320 | 1280, 321 | 672, 322 | 25, 323 | "renesas salvator-x-r8a7796" 324 | ], 325 | [ 326 | 1280, 327 | 736, 328 | 25, 329 | "mediatek mt8173 (development board)" 330 | ], 331 | [ 332 | 1920, 333 | 980, 334 | 10, 335 | "google chromebook pixel (2015, rogue gx6250)" 336 | ], 337 | [ 338 | 1920, 339 | 1016, 340 | 14, 341 | "peloton ruby" 342 | ], 343 | [ 344 | 1920, 345 | 1020, 346 | 8, 347 | "acer chromebook r13" 348 | ], 349 | [ 350 | 1920, 351 | 1032, 352 | 13, 353 | "renesas salvator-x-m3" 354 | ], 355 | [ 356 | 1920, 357 | 1080, 358 | 12, 359 | "xiaomi mibox 3 pro tv box" 360 | ], 361 | [ 362 | 1920, 363 | 1128, 364 | 10, 365 | "amazon kindle fire hd 10 (2017, kfsuwi)" 366 | ], 367 | [ 368 | 2048, 369 | 1536, 370 | 7, 371 | "alps jdtab j01" 372 | ], 373 | [ 374 | 2560, 375 | 1504, 376 | 7, 377 | "onda f109" 378 | ] 379 | ] 380 | ], 381 | [ 382 | "powervr rogue gx6650", 383 | "6650", 384 | "gx6650 powervr rogue", 385 | 0, 386 | [ 387 | [ 388 | 1280, 389 | 672, 390 | 52, 391 | "renesas salvator-x" 392 | ], 393 | [ 394 | 1920, 395 | 968, 396 | 30, 397 | "renesas salvator-x-r8a7795" 398 | ], 399 | [ 400 | 1920, 401 | 1032, 402 | 24, 403 | "renesas salvator-x (octa core)" 404 | ] 405 | ] 406 | ], 407 | [ 408 | "powervr rogue han", 409 | "han", 410 | "han powervr rogue", 411 | 0, 412 | [ 413 | [ 414 | 1794, 415 | 1080, 416 | 6, 417 | "ireadygo w3d" 418 | ], 419 | [ 420 | 1920, 421 | 1080, 422 | 6, 423 | "changhong x6" 424 | ], 425 | [ 426 | 2392, 427 | 1440, 428 | 5, 429 | "alcatel one touch d820" 430 | ], 431 | [ 432 | 2560, 433 | 1440, 434 | 4, 435 | "alcatel 6071y phantom" 436 | ] 437 | ] 438 | ], 439 | [ 440 | "powervr rogue hood", 441 | "", 442 | "hood powervr rogue", 443 | 0, 444 | [ 445 | [ 446 | 1280, 447 | 736, 448 | 16, 449 | "dell venue 7 3740" 450 | ], 451 | [ 452 | 1920, 453 | 1080, 454 | 12, 455 | "lenovo p90" 456 | ], 457 | [ 458 | 1920, 459 | 1104, 460 | 9, 461 | "dell venue 8 3840" 462 | ] 463 | ] 464 | ], 465 | [ 466 | "powervr rogue lando", 467 | "", 468 | "lando powervr rogue", 469 | 0, 470 | [ 471 | [ 472 | 1920, 473 | 1080, 474 | 13, 475 | "spreadtrum sp9861e (development board, rogue lando)" 476 | ] 477 | ] 478 | ], 479 | [ 480 | "powervr rogue marlowe", 481 | "", 482 | "marlowe powervr rogue", 483 | 0, 484 | [ 485 | [ 486 | 1920, 487 | 1080, 488 | 39, 489 | "meitu v6 mp1605" 490 | ], 491 | [ 492 | 2560, 493 | 1440, 494 | 25, 495 | "meizu pro 7 plus" 496 | ] 497 | ] 498 | ] 499 | ] -------------------------------------------------------------------------------- /benchmarks/m-samsung.json: -------------------------------------------------------------------------------- 1 | [ 2 | "5", 3 | [ 4 | "samsung xclipse 920", 5 | "920", 6 | "920 samsung xclipse", 7 | 0, 8 | [ 9 | [ 10 | 2115, 11 | 1080, 12 | 119, 13 | "samsung galaxy s22 5g (sm-s901b)" 14 | ], 15 | [ 16 | 2808, 17 | 1440, 18 | 99, 19 | "samsung galaxy s22 ultra (sm-s908b)" 20 | ] 21 | ] 22 | ] 23 | ] -------------------------------------------------------------------------------- /example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | detect-gpu 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /example/index.ts: -------------------------------------------------------------------------------- 1 | // Application 2 | import { getGPUTier } from '../src'; 3 | 4 | (async () => { 5 | const data = await getGPUTier({ 6 | benchmarksURL: '/build/benchmarks', 7 | }); 8 | 9 | document.body.innerHTML = `
${JSON.stringify(data, null, 2)}
`; 10 | })(); 11 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | detect-gpu 6 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "detect-gpu", 3 | "version": "5.0.70", 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 | "main": "dist/detect-gpu.umd.js", 8 | "module": "dist/detect-gpu.esm.js", 9 | "types": "dist/src/index.d.ts", 10 | "homepage": "https://github.com/pmndrs/detect-gpu#readme", 11 | "bugs": { 12 | "url": "https://github.com/pmndrs/detect-gpu/issues" 13 | }, 14 | "repository": { 15 | "type": "git", 16 | "url": "https://github.com/pmndrs/detect-gpu.git" 17 | }, 18 | "files": [ 19 | "dist" 20 | ], 21 | "keywords": [ 22 | "gpu", 23 | "detect", 24 | "webgl", 25 | "webgl2", 26 | "three.js", 27 | "babylonjs", 28 | "three", 29 | "babylon", 30 | "3d", 31 | "typescript", 32 | "javascript" 33 | ], 34 | "scripts": { 35 | "start": "rollup -c rollup/config.lib.ts -w --configPlugin rollup-plugin-typescript2", 36 | "lint": "eslint \"src/**/*.ts\" \"test/**/*.ts\" \"test/**/*.test.ts\" \"rollup/**/*.ts\" \"scripts/**/*.ts\" \"scripts/**/*.js\" --fix --cache --cache-location ~/.eslintcache/eslintcache", 37 | "test": "jest --verbose=false", 38 | "test:watch": "jest --watch", 39 | "test:coverage": "jest --coverage", 40 | "test:debug": "node --inspect-brk ./node_modules/jest/bin/jest --runInBand --no-cache --watch", 41 | "prebuild": "rimraf dist", 42 | "build": "rollup -c rollup/config.lib.ts --configPlugin rollup-plugin-typescript2", 43 | "example": "rollup -w -c rollup/config.dev.ts --configPlugin rollup-plugin-typescript2", 44 | "parse-analytics": "node ./scripts/analytics_parser.js", 45 | "update-benchmarks": "rimraf benchmarks && mkdir -p benchmarks && mkdir -p benchmarks-min && ts-node -O '{\"module\":\"commonjs\"}' ./scripts/update_benchmarks.ts && tar -czvf benchmarks.tar.gz benchmarks-min/*.json && rm -rf benchmarks-min" 46 | }, 47 | "dependencies": { 48 | "webgl-constants": "^1.1.1" 49 | }, 50 | "devDependencies": { 51 | "@rollup/plugin-json": "^6.0.0", 52 | "@rollup/plugin-node-resolve": "^15.1.0", 53 | "@types/jest": "^29.5.3", 54 | "@typescript-eslint/eslint-plugin": "^6.4.0", 55 | "@typescript-eslint/parser": "^6.4.0", 56 | "csvtojson": "^2.0.10", 57 | "eslint": "^8.4.1", 58 | "eslint-config-prettier": "^9.0.0", 59 | "eslint-plugin-prettier": "^5.0.0", 60 | "jest": "^29.6.2", 61 | "jest-environment-jsdom": "^29.6.2", 62 | "moment": "^2.29.1", 63 | "prettier": "^3.0.1", 64 | "puppeteer": "^13.0.0", 65 | "rimraf": "^5.0.1", 66 | "rollup": "^3.28.0", 67 | "rollup-plugin-commonjs": "^10.1.0", 68 | "rollup-plugin-copy": "^3.4.0", 69 | "rollup-plugin-filesize": "^10.0.0", 70 | "rollup-plugin-livereload": "^2.0.0", 71 | "rollup-plugin-serve": "^2.0.2", 72 | "rollup-plugin-sourcemaps": "^0.6.3", 73 | "rollup-plugin-terser": "^7.0.2", 74 | "rollup-plugin-typescript2": "^0.31.1", 75 | "ts-jest": "^29.1.1", 76 | "ts-node": "^10.0.0", 77 | "typescript": "^5.1.6" 78 | }, 79 | "jest": { 80 | "testEnvironmentOptions": { 81 | "url": "http://localhost" 82 | }, 83 | "moduleFileExtensions": [ 84 | "js", 85 | "ts" 86 | ], 87 | "testMatch": [ 88 | "**/test/**/*.test.ts" 89 | ], 90 | "testPathIgnorePatterns": [ 91 | "/test/data.ts" 92 | ], 93 | "preset": "ts-jest", 94 | "transform": { 95 | "^.+\\.tsx?$": [ 96 | "ts-jest", 97 | { 98 | "tsconfig": "tsconfig.json" 99 | } 100 | ] 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /rollup/config.dev.ts: -------------------------------------------------------------------------------- 1 | // Vendor 2 | import json from '@rollup/plugin-json'; 3 | import resolve from '@rollup/plugin-node-resolve'; 4 | import commonjs from 'rollup-plugin-commonjs'; 5 | import copy from 'rollup-plugin-copy'; 6 | import livereload from 'rollup-plugin-livereload'; 7 | import serve from 'rollup-plugin-serve'; 8 | import sourcemaps from 'rollup-plugin-sourcemaps'; 9 | import typescript from 'rollup-plugin-typescript2'; 10 | 11 | export default { 12 | input: 'example/index.ts', 13 | output: [ 14 | { 15 | dir: `./dist`, 16 | format: 'esm', 17 | sourcemap: true, 18 | }, 19 | ], 20 | plugins: [ 21 | livereload({ 22 | exts: ['ts', 'html', 'js', 'css'], 23 | verbose: true, 24 | watch: '.', 25 | }), 26 | typescript(), 27 | resolve(), 28 | commonjs(), 29 | serve({ 30 | contentBase: ['./example'], 31 | host: 'localhost', 32 | open: true, 33 | openPage: '/', 34 | port: 3003, 35 | }), 36 | copy({ 37 | targets: [{ dest: 'example/build', src: 'benchmarks' }], 38 | }), 39 | json(), 40 | sourcemaps(), 41 | ], 42 | }; 43 | -------------------------------------------------------------------------------- /rollup/config.lib.ts: -------------------------------------------------------------------------------- 1 | // Vendor 2 | import json from '@rollup/plugin-json'; 3 | import resolve from '@rollup/plugin-node-resolve'; 4 | import { ModuleFormat, RollupOptions } from 'rollup'; 5 | import commonjs from 'rollup-plugin-commonjs'; 6 | import copy from 'rollup-plugin-copy'; 7 | import filesize from 'rollup-plugin-filesize'; 8 | import sourcemaps from 'rollup-plugin-sourcemaps'; 9 | import { terser } from 'rollup-plugin-terser'; 10 | import typescript from 'rollup-plugin-typescript2'; 11 | 12 | const formats: ModuleFormat[] = ['esm', 'umd']; 13 | 14 | export default formats.map( 15 | (format): RollupOptions => ({ 16 | input: './src/index.ts', 17 | output: { 18 | file: `./dist/detect-gpu.${format}.js`, 19 | format, 20 | name: 'DetectGPU', 21 | sourcemap: true, 22 | }, 23 | plugins: [ 24 | terser({ 25 | format: { 26 | comments: false, 27 | }, 28 | }), 29 | filesize(), 30 | typescript( 31 | ['esm'].includes(format) 32 | ? {} 33 | : { 34 | tsconfigOverride: { 35 | compilerOptions: { 36 | target: 'es5', 37 | }, 38 | }, 39 | } 40 | ), 41 | resolve(), 42 | commonjs(), 43 | copy({ 44 | targets: [{ dest: 'dist', src: 'benchmarks' }], 45 | }), 46 | json(), 47 | sourcemaps(), 48 | ], 49 | }) 50 | ); 51 | -------------------------------------------------------------------------------- /scripts/analytics_embed.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | if (typeof window !== 'undefined' && window && typeof document !== 'undefined' && document) { 3 | // Configuration 4 | var trackingCode = 'UA-INSERT_TRACKING_CODE'; 5 | 6 | // Create Google Analytics object (registers under the global: "$$__analytics") 7 | (function(i, s, o, g, r, a, m) { 8 | i['GoogleAnalyticsObject'] = r; 9 | (i[r] = 10 | i[r] || 11 | function() { 12 | (i[r].q = i[r].q || []).push(arguments); 13 | }), 14 | (i[r].l = 1 * new Date()); 15 | (a = s.createElement(o)), (m = s.getElementsByTagName(o)[0]); 16 | a.async = 1; 17 | a.src = g; 18 | m.parentNode.insertBefore(a, m); 19 | })(window, document, 'script', '//www.google-analytics.com/analytics.js', '$$__analytics'); 20 | 21 | $$__analytics('create', trackingCode, 'auto'); 22 | $$__analytics('send', 'pageview'); 23 | 24 | // Utilities 25 | function sortArray(arr) { 26 | arr.sort(function(a, b) { 27 | var nameA = a.toLowerCase(); 28 | var nameB = b.toLowerCase(); 29 | 30 | if (nameA < nameB) return -1; 31 | if (nameA > nameB) return 1; 32 | 33 | return 0; 34 | }); 35 | 36 | return arr; 37 | } 38 | 39 | document.addEventListener('DOMContentLoaded', function() { 40 | // Report wether WebGL is supported: boolean 41 | var webglCanvas = document.createElement('canvas'); 42 | var webgl = webglCanvas.getContext('webgl') || webglCanvas.getContext('experimental-webgl'); 43 | var isWebGLSupported = !!webgl; 44 | 45 | $$__analytics('send', 'event', 'isWebGLSupported', 'load', isWebGLSupported, { 46 | nonInteraction: true, 47 | }); 48 | 49 | if (webgl) { 50 | // Report WebGL unmasked renderer string: string 51 | var glExtensionDebugRendererInfo = webgl.getExtension('WEBGL_debug_renderer_info'); 52 | var renderer = 53 | glExtensionDebugRendererInfo && 54 | webgl.getParameter(glExtensionDebugRendererInfo.UNMASKED_RENDERER_WEBGL); 55 | 56 | $$__analytics('send', 'event', 'webGLRenderer', 'load', renderer.toString(), { 57 | nonInteraction: true, 58 | }); 59 | 60 | // Report supported WebGL extensions: [string, string, ...] 61 | var extensions = webgl.getSupportedExtensions(); 62 | 63 | $$__analytics( 64 | 'send', 65 | 'event', 66 | 'webglSupportedExtensions', 67 | 'load', 68 | JSON.stringify(sortArray(extensions)), 69 | { 70 | nonInteraction: true, 71 | } 72 | ); 73 | } 74 | 75 | // Report wether WebGL2 is supported: boolean 76 | var webgl2Canvas = document.createElement('canvas'); 77 | var webgl2 = 78 | webgl2Canvas.getContext('webgl2') || webgl2Canvas.getContext('experimental-webgl2'); 79 | var isWebGL2Supported = !!webgl2; 80 | 81 | $$__analytics('send', 'event', 'isWebGL2Supported', 'load', isWebGL2Supported, { 82 | nonInteraction: true, 83 | }); 84 | 85 | if (webgl2) { 86 | // Report supported WebGL extensions: [string, string, ...] 87 | var extensions = webgl2.getSupportedExtensions(); 88 | 89 | $$__analytics( 90 | 'send', 91 | 'event', 92 | 'webgl2SupportedExtensions', 93 | 'load', 94 | JSON.stringify(sortArray(extensions)), 95 | { 96 | nonInteraction: true, 97 | } 98 | ); 99 | } 100 | 101 | webglCanvas = null; 102 | webgl2Canvas = null; 103 | webgl = null; 104 | webgl2 = null; 105 | }); 106 | } 107 | })(); 108 | -------------------------------------------------------------------------------- /scripts/analytics_parser.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | // @ts-check 4 | 5 | // Native 6 | const fs = require('fs'); 7 | const path = require('path'); 8 | 9 | // Vendor 10 | const csv = require('csvtojson'); 11 | const moment = require('moment'); 12 | 13 | function getRendererData(type, renderers) { 14 | const data = renderers.filter((renderer) => renderer.field2 === type); 15 | 16 | return data.map((renderer) => { 17 | const name = renderer.field1; 18 | const amount = renderer.field4; 19 | 20 | return `${amount} - ${name}`; 21 | }); 22 | } 23 | 24 | function parseAnalytics(file) { 25 | return new Promise((resolve) => { 26 | csv({ noheader: true }) 27 | .fromFile(file) 28 | .then((data) => { 29 | // Remove static header and footer information 30 | const dateEntry = data.slice(3, 4); 31 | const dateRange = dateEntry[0].field1.replace('# ', '').split('-'); 32 | const timeSpan = moment 33 | .duration(moment(dateRange[1]).diff(moment(dateRange[0]))) 34 | .asDays(); 35 | const entries = data.slice(6, data.length - (timeSpan + 4)); 36 | 37 | const mobileData = getRendererData('mobile', entries); 38 | const tabletData = getRendererData('tablet', entries); 39 | const desktopData = getRendererData('desktop', entries); 40 | 41 | resolve({ 42 | desktopData, 43 | mobileData, 44 | tabletData, 45 | }); 46 | }); 47 | }); 48 | } 49 | 50 | parseAnalytics(path.resolve('./data/analytics.csv')).then((result) => { 51 | const output = './test/data.ts'; 52 | const data = ` 53 | export const RENDERER_DESKTOP = [ 54 | ${result.desktopData.map( 55 | (entry) => `\n\'${entry.replace(',', '')}\'` 56 | )} 57 | ]; 58 | 59 | export const RENDERER_TABLET = [ 60 | ${result.tabletData.map((entry) => `\n\'${entry.replace(',', '')}\'`)} 61 | ]; 62 | 63 | export const RENDERER_MOBILE = [ 64 | ${result.mobileData.map((entry) => `\n\'${entry.replace(',', '')}\'`)} 65 | ]; 66 | `; 67 | 68 | fs.writeFile(path.resolve(output), data, (error) => { 69 | if (!error) { 70 | console.log(`Written file to ${output}`); 71 | } else { 72 | console.error(error); 73 | } 74 | }); 75 | }); 76 | -------------------------------------------------------------------------------- /scripts/internalBenchmarkResults.ts: -------------------------------------------------------------------------------- 1 | import { BenchmarkRow } from './types'; 2 | 3 | export const internalBenchmarkResults: BenchmarkRow[] = [ 4 | { 5 | date: '2021.01.29', 6 | device: 'ONEPLUS A6003', 7 | fps: 58, 8 | gpu: 'Adreno (TM) 630', 9 | mobile: true, 10 | resolution: '2280 x 1080', 11 | }, 12 | { 13 | date: '2021.01.29', 14 | device: 'Google Pixel 3a', 15 | fps: 20, 16 | gpu: 'Adreno (TM) 615', 17 | mobile: true, 18 | resolution: '2088 x 1080', 19 | }, 20 | { 21 | date: '2021.01.29', 22 | device: 'Google Pixel 5', 23 | fps: 42, 24 | gpu: 'Adreno (TM) 620', 25 | mobile: true, 26 | resolution: '2340 x 1080', 27 | }, 28 | { 29 | date: '2021.01.29', 30 | device: 'Google Pixel 4', 31 | fps: 60, 32 | gpu: 'Adreno (TM) 640', 33 | mobile: true, 34 | resolution: '2280 x 1080', 35 | }, 36 | { 37 | date: '2021.01.29', 38 | device: 'Xiaomi Mi 9T', 39 | fps: 34, 40 | gpu: 'Adreno (TM) 618', 41 | mobile: true, 42 | resolution: '2210 x 1080', 43 | }, 44 | { 45 | date: '2021.01.29', 46 | device: 'Google Pixel XL', 47 | fps: 28, 48 | gpu: 'Adreno (TM) 530', 49 | mobile: true, 50 | resolution: '2392 x 1440', 51 | }, 52 | { 53 | date: '2021.01.29', 54 | device: 'Samsung GM-J600FN', 55 | fps: 10, 56 | gpu: 'Mali-T830', 57 | mobile: true, 58 | resolution: '1480 x 720', 59 | }, 60 | { 61 | date: '2021.01.29', 62 | device: 'Samsung Galaxy S7 (SM-930x)', 63 | fps: 27, 64 | gpu: 'Adreno (TM) 530', 65 | mobile: true, 66 | resolution: '2560 x 1140', 67 | }, 68 | { 69 | date: '2021.01.29', 70 | device: 'motorola moto g(7) play', 71 | fps: 18, 72 | gpu: 'Adreno (TM) 506', 73 | mobile: true, 74 | resolution: '1512 x 720', 75 | }, 76 | { 77 | date: '2021.01.29', 78 | device: 'Samsung S8+ SM-G955F', 79 | fps: 54, 80 | gpu: 'Mali-G71', 81 | mobile: true, 82 | resolution: '2220 x 1080', 83 | }, 84 | { 85 | date: '2021.01.29', 86 | device: 'Samsung S9+ SM-G965F', 87 | fps: 56, 88 | gpu: 'Mali-G72', 89 | mobile: true, 90 | resolution: '2220 x 1080', 91 | }, 92 | { 93 | date: '2021.01.29', 94 | device: 'Apple iPhone 12 Pro Max', 95 | fps: 60, 96 | gpu: 'Apple A14 GPU', 97 | mobile: true, 98 | resolution: '2778 x 1284', 99 | }, 100 | { 101 | date: '2021.01.29', 102 | device: 'Apple iPad Pro (12.9 inch) (4th generation)', 103 | fps: 60, 104 | gpu: 'Apple A12Z GPU', 105 | mobile: true, 106 | resolution: '2732 x 2048', 107 | }, 108 | ]; 109 | -------------------------------------------------------------------------------- /scripts/types.ts: -------------------------------------------------------------------------------- 1 | export type BenchmarkRow = { 2 | date: string; 3 | device: string; 4 | gpu: string; 5 | fps: number; 6 | mobile: boolean; 7 | resolution: string; 8 | }; 9 | -------------------------------------------------------------------------------- /scripts/update_benchmarks.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-explicit-any */ 2 | 3 | // Vendor 4 | import fs from 'fs'; 5 | import puppeteer from 'puppeteer'; 6 | 7 | // Application 8 | import { BLOCKLISTED_GPUS } from '../src/internal/blocklistedGPUS'; 9 | import { cleanRenderer } from '../src/internal/cleanRenderer'; 10 | import { getGPUVersion } from '../src/internal/getGPUVersion'; 11 | import { tokenizeForLevenshteinDistance } from '../src/internal/getLevenshteinDistance'; 12 | import { internalBenchmarkResults } from './internalBenchmarkResults'; 13 | import { BenchmarkRow } from './types'; 14 | 15 | // Package 16 | import { version } from '../package.json'; 17 | 18 | const libraryMajorVersion = version.split('.')[0]; 19 | 20 | const BENCHMARK_URL = `https://gfxbench.com/result.jsp?benchmark=gfx50&test=544&text-filter=&order=median&ff-lmobile=true&ff-smobile=true&os-Android_gl=true&os-Android_vulkan=true&os-iOS_gl=true&os-iOS_metal=true&os-Linux_gl=true&os-OS_X_gl=true&os-OS_X_metal=true&os-Windows_dx=true&os-Windows_dx12=true&os-Windows_gl=true&os-Windows_vulkan=true&pu-dGPU=true&pu-iGPU=true&pu-GPU=true&arch-ARM=true&arch-unknown=true&arch-x86=true&base=device`; 21 | 22 | const TYPES = [ 23 | 'adreno', 24 | 'apple', 25 | 'mali-t', 26 | 'mali', 27 | 'nvidia', 28 | 'powervr', 29 | 'intel', 30 | 'amd', 31 | 'radeon', 32 | 'nvidia', 33 | 'geforce', 34 | 'samsung' 35 | ]; 36 | 37 | type Optional = Pick, K> & Omit; 38 | 39 | (async () => { 40 | let benchmarks = await fetchBenchmarks(); 41 | benchmarks.push(...internalBenchmarkResults); 42 | benchmarks = benchmarks 43 | .map((benchmark) => { 44 | benchmark.gpu = cleanRenderer(benchmark.gpu) 45 | .replace(/\s*\([^)]+(\))/g, '') 46 | .replace(/(\d+)\/[^ ]+/, '$1') 47 | .replace( 48 | /x\.org |inc\. |open source technology center |imagination technologies |™ |nvidia corporation |apple inc\. |advanced micro devices, inc\. | series$| edition$| graphics$/g, 49 | '' 50 | ) 51 | .replace(/(qualcomm|adreno)[^ ] /g, 'qualcomm ') 52 | .replace(/qualcomm (qualcomm )+/g, 'qualcomm ') 53 | .trim(); 54 | benchmark.device = benchmark.device.toLowerCase(); 55 | return benchmark; 56 | }) 57 | .sort((a, b) => a.gpu.localeCompare(b.gpu)); 58 | 59 | await Promise.all([true, false].map(exportBenchmarks)); 60 | 61 | async function exportBenchmarks(isMobile: boolean): Promise { 62 | const rows = benchmarks.filter( 63 | ({ mobile, gpu }) => 64 | mobile === isMobile && 65 | TYPES.filter((type): boolean => gpu.includes(type)).length > 0 66 | ); 67 | 68 | const rowsByGpu = Object.values( 69 | rows.reduce((groupedByKey, row) => { 70 | const groupKey = row.gpu; 71 | (groupedByKey[groupKey] = groupedByKey[groupKey] || []).push(row); 72 | return groupedByKey; 73 | }, {} as Record) 74 | ); 75 | 76 | return Promise.all([ 77 | ...TYPES.map(async (type) => { 78 | const devicesByGpu = rowsByGpu 79 | .filter(([{ gpu }]) => gpu.includes(type)) 80 | .map((rows) => { 81 | const { gpu } = rows[0]; 82 | const blocklisted = BLOCKLISTED_GPUS.find((blocklistedModel) => 83 | gpu.includes(blocklistedModel) 84 | ); 85 | const devices = Object.entries( 86 | rows.reduce( 87 | ( 88 | fpsByResolution: { [k: string]: [string, number] }, 89 | { resolution, fps, device } 90 | ) => { 91 | fpsByResolution[resolution] = [ 92 | device, 93 | blocklisted ? -1 : fps, 94 | ]; 95 | return fpsByResolution; 96 | }, 97 | {} 98 | ) 99 | ) 100 | .map(([resolution, [device, fps]]) => { 101 | const [width, height] = resolution.split(' x ').map(Number); 102 | return { width, height, fps, device }; 103 | }) 104 | .sort( 105 | ({ width: aW, height: aH }, { width: bW, height: bH }) => 106 | aW * aH - bW * bH 107 | ); 108 | return { 109 | blocklisted, 110 | devices, 111 | gpu, 112 | gpuVersion: getGPUVersion(gpu), 113 | }; 114 | }); 115 | 116 | if (devicesByGpu.length === 0) { 117 | return Promise.resolve(); 118 | } 119 | const outputFile = async ( 120 | type: string, 121 | models: typeof devicesByGpu 122 | ) => { 123 | const serializedModels = models.map( 124 | ({ gpu, gpuVersion, blocklisted, devices }) => [ 125 | gpu, 126 | gpuVersion, 127 | tokenizeForLevenshteinDistance(gpu), 128 | blocklisted ? 1 : 0, 129 | devices.map(({ width, height, fps, device }) => 130 | isMobile ? [width, height, fps, device] : [width, height, fps] 131 | ), 132 | ] 133 | ); 134 | const data = [libraryMajorVersion, ...serializedModels]; 135 | await Promise.all( 136 | [true, false].map(async (minified) => { 137 | const file = `./benchmarks${minified ? '-min' : ''}/${ 138 | isMobile ? 'm' : 'd' 139 | }-${type}.json`; 140 | const json = JSON.stringify(data, null, minified ? undefined : 2); 141 | await fs.promises.writeFile(file, json); 142 | if (!minified) { 143 | console.log(`Exported ${file}`); 144 | } 145 | }) 146 | ); 147 | }; 148 | 149 | // Output ipads seperately from other ios devices: 150 | if (type === 'apple' && isMobile) { 151 | await Promise.all([ 152 | outputFile( 153 | 'apple-ipad', 154 | devicesByGpu 155 | .map((gpu) => ({ 156 | ...gpu, 157 | devices: gpu.devices.filter(({ device }) => 158 | device.includes('ipad') 159 | ), 160 | })) 161 | .filter(({ devices }) => devices.length > 0) 162 | ), 163 | outputFile( 164 | 'apple', 165 | devicesByGpu 166 | .map((gpu) => ({ 167 | ...gpu, 168 | devices: gpu.devices.filter( 169 | ({ device }) => !device.includes('ipad') 170 | ), 171 | })) 172 | .filter(({ devices }) => devices.length > 0) 173 | ), 174 | ]); 175 | } else { 176 | await outputFile(type, devicesByGpu); 177 | } 178 | }), 179 | // outputFile(getOutputFilename(`all-${isMobile ? 'm' : 'd'}`), rowsByGpu), 180 | ]); 181 | } 182 | })().catch((err) => { 183 | throw err; 184 | }); 185 | 186 | async function fetchBenchmarks() { 187 | const browser = await puppeteer.launch({ headless: true }); 188 | const page = await browser.newPage(); 189 | 190 | await page.goto(BENCHMARK_URL, { waitUntil: 'networkidle2' }); 191 | 192 | const benchmarks = await page.evaluate((): BenchmarkRow[] => { 193 | const { 194 | firstResult, 195 | deviceName, 196 | fpses, 197 | gpuNameLookup, 198 | screenSizeLookup, 199 | screenSizes, 200 | gpuName, 201 | formFactorLookup, 202 | formFactor, 203 | } = window as unknown as { 204 | firstResult: string[]; 205 | deviceName: string[]; 206 | fpses: string[]; 207 | gpuNameLookup: string[]; 208 | screenSizeLookup: string[]; 209 | screenSizes: number[]; 210 | gpuName: number[]; 211 | formFactorLookup: string[]; 212 | formFactor: number[]; 213 | }; 214 | 215 | return gpuName 216 | .map( 217 | (gpuIndex, index): Optional => ({ 218 | date: firstResult[index], 219 | device: deviceName[index].toLowerCase(), 220 | fps: 221 | fpses[index] === '' 222 | ? undefined 223 | : Math.round(Number(fpses[index].replace(/[^\d.]+/g, ''))), 224 | gpu: gpuNameLookup[gpuIndex], 225 | mobile: formFactorLookup[formFactor[index]].includes('mobile'), 226 | resolution: screenSizeLookup[screenSizes[index]], 227 | }) 228 | ) 229 | .filter((row): row is BenchmarkRow => row.fps !== undefined); 230 | }); 231 | await browser.close(); 232 | return benchmarks; 233 | } 234 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | // Data 2 | import { version } from '../package.json'; 3 | 4 | // Internal 5 | import { BLOCKLISTED_GPUS } from './internal/blocklistedGPUS'; 6 | import { cleanRenderer } from './internal/cleanRenderer'; 7 | import { deobfuscateRenderer } from './internal/deobfuscateRenderer'; 8 | import { deviceInfo } from './internal/deviceInfo'; 9 | import { OutdatedBenchmarksError } from './internal/error'; 10 | import { getGPUVersion } from './internal/getGPUVersion'; 11 | import { 12 | getLevenshteinDistance, 13 | tokenizeForLevenshteinDistance, 14 | } from './internal/getLevenshteinDistance'; 15 | import { getWebGLContext } from './internal/getWebGLContext'; 16 | import { isSSR } from './internal/ssr'; 17 | import { isDefined } from './internal/util'; 18 | 19 | // Types 20 | export interface GetGPUTier { 21 | /** 22 | * URL of directory where benchmark data is hosted. 23 | * 24 | * @default https://unpkg.com/detect-gpu@{version}/dist/benchmarks 25 | */ 26 | benchmarksURL?: string; 27 | /** 28 | * Optionally pass in a WebGL context to avoid creating a temporary one 29 | * internally. 30 | */ 31 | glContext?: WebGLRenderingContext | WebGL2RenderingContext; 32 | /** 33 | * Whether to fail if the system performance is low or if no hardware GPU is 34 | * available. 35 | * 36 | * @default false 37 | */ 38 | failIfMajorPerformanceCaveat?: boolean; 39 | /** 40 | * Framerate per tier for mobile devices. 41 | * 42 | * @defaultValue [0, 15, 30, 60] 43 | */ 44 | mobileTiers?: number[]; 45 | /** 46 | * Framerate per tier for desktop devices. 47 | * 48 | * @defaultValue [0, 15, 30, 60] 49 | */ 50 | desktopTiers?: number[]; 51 | /** 52 | * Optionally override specific parameters. Used mainly for testing. 53 | */ 54 | override?: { 55 | renderer?: string; 56 | /** 57 | * Override whether device is an iPad. 58 | */ 59 | isIpad?: boolean; 60 | /** 61 | * Override whether device is a mobile device. 62 | */ 63 | isMobile?: boolean; 64 | /** 65 | * Override device screen size. 66 | */ 67 | screenSize?: { width: number; height: number }; 68 | /** 69 | * Override how benchmark data is loaded 70 | */ 71 | loadBenchmarks?: (file: string) => Promise; 72 | }; 73 | } 74 | 75 | export type TierType = 76 | | 'SSR' 77 | | 'WEBGL_UNSUPPORTED' 78 | | 'BLOCKLISTED' 79 | | 'FALLBACK' 80 | | 'BENCHMARK'; 81 | 82 | export type TierResult = { 83 | tier: number; 84 | type: TierType; 85 | isMobile?: boolean; 86 | fps?: number; 87 | gpu?: string; 88 | device?: string; 89 | }; 90 | 91 | export type ModelEntryScreen = [number, number, number, string | undefined]; 92 | 93 | export type ModelEntry = [string, string, string, 0 | 1, ModelEntryScreen[]]; 94 | 95 | const debug = false ? console.log : undefined; 96 | 97 | export const getGPUTier = async ({ 98 | mobileTiers = [0, 15, 30, 60], 99 | desktopTiers = [0, 15, 30, 60], 100 | override = {}, 101 | glContext, 102 | failIfMajorPerformanceCaveat = false, 103 | benchmarksURL = `https://unpkg.com/detect-gpu@${version}/dist/benchmarks`, 104 | }: GetGPUTier = {}): Promise => { 105 | const queryCache: { [k: string]: Promise } = {}; 106 | if (isSSR) { 107 | return { 108 | tier: 0, 109 | type: 'SSR', 110 | }; 111 | } 112 | 113 | const { 114 | isIpad = !!deviceInfo?.isIpad, 115 | isMobile = !!deviceInfo?.isMobile, 116 | screenSize = window.screen, 117 | loadBenchmarks = async (file: string) => { 118 | const data: ModelEntry[] = await fetch(`${benchmarksURL}/${file}`).then( 119 | (response) => response.json() 120 | ); 121 | 122 | // Remove version tag and check version is supported 123 | const version = parseInt( 124 | (data.shift() as unknown as string).split('.')[0], 125 | 10 126 | ); 127 | if (version < 4) { 128 | throw new OutdatedBenchmarksError( 129 | 'Detect GPU benchmark data is out of date. Please update to version 4x' 130 | ); 131 | } 132 | return data; 133 | }, 134 | } = override; 135 | let { renderer } = override; 136 | const getGpuType = (renderer: string) => { 137 | const types = isMobile 138 | ? ([ 139 | 'adreno', 140 | 'apple', 141 | 'mali-t', 142 | 'mali', 143 | 'nvidia', 144 | 'powervr', 145 | 'samsung', 146 | ] as const) 147 | : ([ 148 | 'intel', 149 | 'apple', 150 | 'amd', 151 | 'radeon', 152 | 'nvidia', 153 | 'geforce', 154 | 'adreno', 155 | ] as const); 156 | for (const type of types) { 157 | if (renderer.includes(type)) { 158 | return type; 159 | } 160 | } 161 | }; 162 | 163 | async function queryBenchmarks(renderer: string) { 164 | const type = getGpuType(renderer); 165 | if (!type) { 166 | return; 167 | } 168 | 169 | debug?.('queryBenchmarks - found type:', { type }); 170 | 171 | const benchmarkFile = `${isMobile ? 'm' : 'd'}-${type}${ 172 | isIpad ? '-ipad' : '' 173 | }.json`; 174 | 175 | const benchmark = (queryCache[benchmarkFile] = 176 | queryCache[benchmarkFile] ?? loadBenchmarks(benchmarkFile)); 177 | let benchmarks: ModelEntry[]; 178 | try { 179 | benchmarks = await benchmark; 180 | } catch (error) { 181 | if (error instanceof OutdatedBenchmarksError) { 182 | throw error; 183 | } 184 | debug?.("queryBenchmarks - couldn't load benchmark:", { error }); 185 | return; 186 | } 187 | 188 | const version = getGPUVersion(renderer); 189 | 190 | let matched = benchmarks.filter( 191 | ([, modelVersion]) => modelVersion === version 192 | ); 193 | 194 | debug?.( 195 | `found ${matched.length} matching entries using version '${version}':`, 196 | 197 | matched.map(([model]) => model) 198 | ); 199 | 200 | // If nothing matched, try comparing model names: 201 | if (!matched.length) { 202 | matched = benchmarks.filter(([model]) => model.includes(renderer)); 203 | 204 | debug?.( 205 | `found ${matched.length} matching entries comparing model names`, 206 | { 207 | matched, 208 | } 209 | ); 210 | } 211 | 212 | const matchCount = matched.length; 213 | 214 | if (matchCount === 0) { 215 | return; 216 | } 217 | 218 | const tokenizedRenderer = tokenizeForLevenshteinDistance(renderer); 219 | // eslint-disable-next-line prefer-const 220 | let [gpu, , , , fpsesByPixelCount] = 221 | matchCount > 1 222 | ? matched 223 | .map( 224 | (match) => 225 | [ 226 | match, 227 | getLevenshteinDistance(tokenizedRenderer, match[2]), 228 | ] as const 229 | ) 230 | .sort(([, a], [, b]) => a - b)[0][0] 231 | : matched[0]; 232 | 233 | debug?.( 234 | `${renderer} matched closest to ${gpu} with the following screen sizes`, 235 | JSON.stringify(fpsesByPixelCount) 236 | ); 237 | 238 | let minDistance = Number.MAX_VALUE; 239 | let closest: ModelEntryScreen | undefined; 240 | const { devicePixelRatio } = window; 241 | const pixelCount = 242 | screenSize.width * 243 | devicePixelRatio * 244 | screenSize.height * 245 | devicePixelRatio; 246 | 247 | for (const match of fpsesByPixelCount) { 248 | const [width, height] = match; 249 | const entryPixelCount = width * height; 250 | const distance = Math.abs(pixelCount - entryPixelCount); 251 | 252 | if (distance < minDistance) { 253 | minDistance = distance; 254 | closest = match; 255 | } 256 | } 257 | 258 | if (!closest) { 259 | return; 260 | } 261 | 262 | // eslint-disable-next-line @typescript-eslint/no-non-null-assertion 263 | const [, , fps, device] = closest!; 264 | 265 | return [minDistance, fps, gpu, device] as const; 266 | } 267 | 268 | const toResult = ( 269 | tier: number, 270 | type: TierType, 271 | gpu?: string, 272 | fps?: number, 273 | device?: string 274 | ) => ({ 275 | device, 276 | fps, 277 | gpu, 278 | isMobile, 279 | tier, 280 | type, 281 | }); 282 | 283 | let renderers: string[]; 284 | let rawRenderer = ''; 285 | 286 | if (!renderer) { 287 | const gl = 288 | glContext || 289 | getWebGLContext(deviceInfo?.isSafari12, failIfMajorPerformanceCaveat); 290 | 291 | if (!gl) { 292 | return toResult(0, 'WEBGL_UNSUPPORTED'); 293 | } 294 | 295 | const debugRendererInfo = deviceInfo?.isFirefox 296 | ? null 297 | : gl.getExtension('WEBGL_debug_renderer_info'); 298 | 299 | renderer = debugRendererInfo 300 | ? gl.getParameter(debugRendererInfo.UNMASKED_RENDERER_WEBGL) 301 | : gl.getParameter(gl.RENDERER); 302 | 303 | if (!renderer) { 304 | return toResult(1, 'FALLBACK'); 305 | } 306 | 307 | rawRenderer = renderer; 308 | renderer = cleanRenderer(renderer); 309 | renderers = deobfuscateRenderer(gl, renderer, isMobile); 310 | } else { 311 | renderer = cleanRenderer(renderer); 312 | renderers = [renderer]; 313 | } 314 | 315 | const results = (await Promise.all(renderers.map(queryBenchmarks))) 316 | .filter(isDefined) 317 | .sort(([aDis = Number.MAX_VALUE, aFps], [bDis = Number.MAX_VALUE, bFps]) => 318 | aDis === bDis ? aFps - bFps : aDis - bDis 319 | ); 320 | if (!results.length) { 321 | const blocklistedModel: string | undefined = BLOCKLISTED_GPUS.find( 322 | // eslint-disable-next-line @typescript-eslint/no-non-null-assertion 323 | (blocklistedModel) => renderer!.includes(blocklistedModel) 324 | ); 325 | return blocklistedModel 326 | ? toResult(0, 'BLOCKLISTED', blocklistedModel) 327 | : toResult(1, 'FALLBACK', `${renderer} (${rawRenderer})`); 328 | } 329 | 330 | const [, fps, model, device] = results[0]; 331 | 332 | if (fps === -1) { 333 | return toResult(0, 'BLOCKLISTED', model, fps, device); 334 | } 335 | 336 | const tiers = isMobile ? mobileTiers : desktopTiers; 337 | let tier = 0; 338 | 339 | for (let i = 0; i < tiers.length; i++) { 340 | if (fps >= tiers[i]) { 341 | tier = i; 342 | } 343 | } 344 | 345 | return toResult(tier, 'BENCHMARK', model, fps, device); 346 | }; 347 | -------------------------------------------------------------------------------- /src/internal/blocklistedGPUS.ts: -------------------------------------------------------------------------------- 1 | // GPU blocklist 2 | // SEE: https://chromium.googlesource.com/chromium/src/+/master/gpu/config/software_rendering_list.json 3 | // SEE: https://hg.mozilla.org/mozilla-central/raw-file/tip/services/settings/dumps/blocklists/gfx.json 4 | export const BLOCKLISTED_GPUS = [ 5 | 'geforce 320m', 6 | 'geforce 8600', 7 | 'geforce 8600m gt', 8 | 'geforce 8800 gs', 9 | 'geforce 8800 gt', 10 | 'geforce 9400', 11 | 'geforce 9400m g', 12 | 'geforce 9400m', 13 | 'geforce 9600m gt', 14 | 'geforce 9600m', 15 | 'geforce fx go5200', 16 | 'geforce gt 120', 17 | 'geforce gt 130', 18 | 'geforce gt 330m', 19 | 'geforce gtx 285', 20 | 'google swiftshader', 21 | 'intel g41', 22 | 'intel g45', 23 | 'intel gma 4500mhd', 24 | 'intel gma x3100', 25 | 'intel hd 3000', 26 | 'intel q45', 27 | 'legacy', 28 | 'mali-2', 29 | 'mali-3', 30 | 'mali-4', 31 | 'quadro fx 1500', 32 | 'quadro fx 4', 33 | 'quadro fx 5', 34 | 'radeon hd 2400', 35 | 'radeon hd 2600', 36 | 'radeon hd 4670', 37 | 'radeon hd 4850', 38 | 'radeon hd 4870', 39 | 'radeon hd 5670', 40 | 'radeon hd 5750', 41 | 'radeon hd 6290', 42 | 'radeon hd 6300', 43 | 'radeon hd 6310', 44 | 'radeon hd 6320', 45 | 'radeon hd 6490m', 46 | 'radeon hd 6630m', 47 | 'radeon hd 6750m', 48 | 'radeon hd 6770m', 49 | 'radeon hd 6970m', 50 | 'sgx 543', 51 | 'sgx543', 52 | ]; 53 | -------------------------------------------------------------------------------- /src/internal/cleanRenderer.ts: -------------------------------------------------------------------------------- 1 | const debug = false ? console.log : undefined; 2 | 3 | export function cleanRenderer(renderer: string) { 4 | debug?.('cleanRenderer', { renderer }); 5 | 6 | renderer = renderer 7 | .toLowerCase() 8 | // Strip off ANGLE() - for example: 9 | // 'ANGLE (NVIDIA TITAN Xp)' becomes 'NVIDIA TITAN Xp', 10 | // 'Samsung Electronics Co., Ltd. ANGLE (Samsung Xclipse 920) on Vulkan 1.1.179' becomes 'Samsung Xclipse 920': 11 | .replace(/.*angle ?\((.+)\)(?: on vulkan [0-9.]+)?$/i, '$1') 12 | // Strip off [number]gb & strip off direct3d and after - for example: 13 | // 'Radeon (TM) RX 470 Series Direct3D11 vs_5_0 ps_5_0' becomes 14 | // 'Radeon (TM) RX 470 Series' 15 | .replace(/\s(\d{1,2}gb|direct3d.+$)|\(r\)| \([^)]+\)$/g, '') 16 | // Strip out graphics API. The one Vulkan example we've seen includes 17 | // the GPU in parens after the Vulkan version so this also keeps that 18 | // eg. 'vulkan 1.2.175 (nvidia nvidia geforce gtx 970 (0x000013c2))' 19 | // becomes 'nvidia nvidia geforce gtx 970 (0x000013c2)' 20 | // `OpenGL 4.5.0` gets removed all together 21 | .replace(/(?:vulkan|opengl) \d+\.\d+(?:\.\d+)?(?: \((.*)\))?/, '$1') 22 | 23 | debug?.('cleanRenderer - renderer cleaned to', { renderer }); 24 | 25 | return renderer; 26 | }; 27 | -------------------------------------------------------------------------------- /src/internal/deobfuscateAppleGPU.ts: -------------------------------------------------------------------------------- 1 | // Vendor 2 | import { 3 | GL_ARRAY_BUFFER, 4 | GL_COLOR_BUFFER_BIT, 5 | GL_FLOAT, 6 | GL_FRAGMENT_SHADER, 7 | GL_RGBA, 8 | GL_STATIC_DRAW, 9 | GL_TRIANGLES, 10 | GL_UNSIGNED_BYTE, 11 | GL_VERTEX_SHADER, 12 | } from 'webgl-constants'; 13 | 14 | // Internal 15 | import { deviceInfo } from './deviceInfo'; 16 | 17 | const debug = false ? console.warn : undefined; 18 | 19 | export function deobfuscateAppleGPU( 20 | gl: WebGLRenderingContext, 21 | renderer: string, 22 | isMobileTier: boolean 23 | ) { 24 | if (!isMobileTier) { 25 | debug?.('Safari 14+ obfuscates its GPU type and version, using fallback'); 26 | return [renderer]; 27 | } 28 | const pixelId = calculateMagicPixelId(gl); 29 | const codeA = '801621810' as const; 30 | const codeB = '8016218135' as const; 31 | const codeC = '80162181161' as const; 32 | const codeFB = '80162181255'; 33 | 34 | // All chipsets that support at least iOS 12: 35 | const possibleChipsets: [ 36 | string, 37 | typeof codeA | typeof codeB | typeof codeC, 38 | number, 39 | ][] = deviceInfo?.isIpad 40 | ? [ 41 | // ['a4', 5], // ipad 1st gen 42 | // ['a5', 9], // ipad 2 / ipad mini 1st gen 43 | // ['a5x', 9], // ipad 3rd gen 44 | // ['a6x', 10], // ipad 4th gen 45 | ['a7', codeC, 12], // ipad air / ipad mini 2 / ipad mini 3 46 | ['a8', codeB, 15], // pad mini 4 47 | ['a8x', codeB, 15], // ipad air 2 48 | ['a9', codeB, 15], // ipad 5th gen 49 | ['a9x', codeB, 15], // pro 9.7 2016 / pro 12.9 2015 50 | ['a10', codeB, 15], // ipad 7th gen / ipad 6th gen 51 | ['a10x', codeB, 15], // pro 10.5 2017 / pro 12.9 2nd gen, 2017 52 | ['a12', codeA, 15], // ipad 8th gen / ipad air 3rd gen / ipad mini 5th gen 53 | ['a12x', codeA, 15], // ipad pro 11 3st gen / ipad pro 12.9 3rd gen 54 | ['a12z', codeA, 15], // ipad pro 11 4nd gen / ipad pro 12.9 4th gen 55 | ['a14', codeA, 15], // ipad air 4th gen 56 | ['a15', codeA, 15], // ipad mini 6th gen / ipad 10th gen 57 | ['m1', codeA, 15], // ipad pro 11 5nd gen / ipad pro 12.9 5th gen / ipad air 5th gen 58 | ['m2', codeA, 15], // ipad pro 11 6nd gen / ipad pro 12.9 6th gen 59 | ] 60 | : [ 61 | // ['a4', 7], // 4 / ipod touch 4th gen 62 | // ['a5', 9], // 4S / ipod touch 5th gen 63 | // ['a6', 10], // 5 / 5C 64 | ['a7', codeC, 12], // 5S 65 | ['a8', codeB, 12], // 6 / 6 plus / ipod touch 6th gen 66 | ['a9', codeB, 15], // 6s / 6s plus/ se 1st gen 67 | ['a10', codeB, 15], // 7 / 7 plus / iPod Touch 7th gen 68 | ['a11', codeA, 15], // 8 / 8 plus / X 69 | ['a12', codeA, 15], // XS / XS Max / XR 70 | ['a13', codeA, 15], // 11 / 11 pro / 11 pro max / se 2nd gen 71 | ['a14', codeA, 15], // 12 / 12 mini / 12 pro / 12 pro max 72 | ['a15', codeA, 15], // 13 / 13 mini / 13 pro / 13 pro max / se 3rd gen / 14 / 14 plus 73 | ['a16', codeA, 15], // 14 pro / 14 pro max / 15 / 15 plus 74 | ['a17', codeA, 15], // 15 pro / 15 pro max 75 | ]; 76 | let chipsets: typeof possibleChipsets; 77 | 78 | // In iOS 14.x Apple started normalizing the outcome of this hack, 79 | // we use this fact to limit the list to devices that support ios 14+ 80 | if (pixelId === codeFB) { 81 | chipsets = possibleChipsets.filter(([, , iosVersion]) => iosVersion >= 14); 82 | } else { 83 | chipsets = possibleChipsets.filter(([, id]) => id === pixelId); 84 | // If nothing was found to match the pixel id, include all chipsets: 85 | if (!chipsets.length) { 86 | chipsets = possibleChipsets; 87 | } 88 | } 89 | const renderers = chipsets.map(([gpu]) => `apple ${gpu} gpu`); 90 | debug?.( 91 | `iOS 12.2+ obfuscates its GPU type and version, using closest matches: ${JSON.stringify( 92 | renderers 93 | )}` 94 | ); 95 | return renderers; 96 | } 97 | 98 | // Apple GPU (iOS 12.2+, Safari 14+) 99 | // SEE: https://github.com/pmndrs/detect-gpu/issues/7 100 | // CREDIT: https://medium.com/@Samsy/detecting-apple-a10-iphone-7-to-a11-iphone-8-and-b019b8f0eb87 101 | // CREDIT: https://github.com/Samsy/appleGPUDetection/blob/master/index.js 102 | function calculateMagicPixelId(gl: WebGLRenderingContext) { 103 | const vertexShaderSource = /* glsl */ ` 104 | precision highp float; 105 | attribute vec3 aPosition; 106 | varying float vvv; 107 | void main() { 108 | vvv = 0.31622776601683794; 109 | gl_Position = vec4(aPosition, 1.0); 110 | } 111 | `; 112 | 113 | const fragmentShaderSource = /* glsl */ ` 114 | precision highp float; 115 | varying float vvv; 116 | void main() { 117 | vec4 enc = vec4(1.0, 255.0, 65025.0, 16581375.0) * vvv; 118 | enc = fract(enc); 119 | enc -= enc.yzww * vec4(1.0 / 255.0, 1.0 / 255.0, 1.0 / 255.0, 0.0); 120 | gl_FragColor = enc; 121 | } 122 | `; 123 | 124 | const vertexShader = gl.createShader(GL_VERTEX_SHADER); 125 | const fragmentShader = gl.createShader(GL_FRAGMENT_SHADER); 126 | const program = gl.createProgram(); 127 | if (!(fragmentShader && vertexShader && program)) return; 128 | gl.shaderSource(vertexShader, vertexShaderSource); 129 | gl.shaderSource(fragmentShader, fragmentShaderSource); 130 | gl.compileShader(vertexShader); 131 | gl.compileShader(fragmentShader); 132 | gl.attachShader(program, vertexShader); 133 | gl.attachShader(program, fragmentShader); 134 | 135 | gl.linkProgram(program); 136 | 137 | gl.detachShader(program, vertexShader); 138 | gl.detachShader(program, fragmentShader); 139 | gl.deleteShader(vertexShader); 140 | gl.deleteShader(fragmentShader); 141 | 142 | gl.useProgram(program); 143 | 144 | const vertexArray = gl.createBuffer(); 145 | gl.bindBuffer(GL_ARRAY_BUFFER, vertexArray); 146 | gl.bufferData( 147 | GL_ARRAY_BUFFER, 148 | new Float32Array([-1, -1, 0, 3, -1, 0, -1, 3, 0]), 149 | GL_STATIC_DRAW 150 | ); 151 | 152 | const aPosition = gl.getAttribLocation(program, 'aPosition'); 153 | gl.vertexAttribPointer(aPosition, 3, GL_FLOAT, false, 0, 0); 154 | gl.enableVertexAttribArray(aPosition); 155 | 156 | gl.clearColor(1, 1, 1, 1); 157 | gl.clear(GL_COLOR_BUFFER_BIT); 158 | gl.viewport(0, 0, 1, 1); 159 | gl.drawArrays(GL_TRIANGLES, 0, 3); 160 | 161 | const pixels = new Uint8Array(4); 162 | gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixels); 163 | 164 | gl.deleteProgram(program); 165 | gl.deleteBuffer(vertexArray); 166 | return pixels.join(''); 167 | } 168 | -------------------------------------------------------------------------------- /src/internal/deobfuscateRenderer.ts: -------------------------------------------------------------------------------- 1 | // Internal 2 | import { deobfuscateAppleGPU } from './deobfuscateAppleGPU'; 3 | 4 | export function deobfuscateRenderer( 5 | gl: WebGLRenderingContext | WebGL2RenderingContext, 6 | renderer: string, 7 | isMobileTier: boolean 8 | ) { 9 | return renderer === 'apple gpu' 10 | ? deobfuscateAppleGPU(gl, renderer, isMobileTier) 11 | : [renderer]; 12 | } 13 | -------------------------------------------------------------------------------- /src/internal/deviceInfo.ts: -------------------------------------------------------------------------------- 1 | import { isSSR } from './ssr'; 2 | 3 | export const deviceInfo = (() => { 4 | if (isSSR) { 5 | return; 6 | } 7 | 8 | const { userAgent, platform, maxTouchPoints } = window.navigator; 9 | 10 | const isIOS = /(iphone|ipod|ipad)/i.test(userAgent); 11 | 12 | // Workaround for ipadOS, force detection as tablet 13 | // SEE: https://github.com/lancedikson/bowser/issues/329 14 | // SEE: https://stackoverflow.com/questions/58019463/how-to-detect-device-name-in-safari-on-ios-13-while-it-doesnt-show-the-correct 15 | const isIpad = 16 | platform === 'iPad' || 17 | // @ts-expect-error window.MSStream is non standard 18 | (platform === 'MacIntel' && maxTouchPoints > 0 && !window.MSStream); 19 | 20 | const isAndroid = /android/i.test(userAgent); 21 | 22 | return { 23 | isIpad, 24 | isMobile: isAndroid || isIOS || isIpad, 25 | isSafari12: /Version\/12.+Safari/.test(userAgent), 26 | isFirefox: /Firefox/.test(userAgent) 27 | }; 28 | })(); 29 | -------------------------------------------------------------------------------- /src/internal/error.ts: -------------------------------------------------------------------------------- 1 | export class OutdatedBenchmarksError extends Error { 2 | constructor(message?: string) { 3 | super(message); // 'Error' breaks prototype chain here 4 | Object.setPrototypeOf(this, new.target.prototype); // restore prototype chain 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/internal/getGPUVersion.ts: -------------------------------------------------------------------------------- 1 | export function getGPUVersion(model: string) { 2 | model = model.replace(/\([^)]+\)/, ''); 3 | 4 | const matches = 5 | // First set of digits 6 | model.match(/\d+/) || 7 | // If the renderer did not contain any numbers, match letters 8 | model.match(/(\W|^)([A-Za-z]{1,3})(\W|$)/g); 9 | 10 | // Remove any non-word characters and also remove 'amd' which could be matched 11 | // in the clause above 12 | return matches?.join('').replace(/\W|amd/g, '') ?? ''; 13 | } 14 | -------------------------------------------------------------------------------- /src/internal/getLevenshteinDistance.ts: -------------------------------------------------------------------------------- 1 | // Caches 2 | const array: number[] = []; 3 | const charCodeCache: number[] = []; 4 | 5 | // Compute the difference (distance) between two strings 6 | // SEE: https://en.wikipedia.org/wiki/Levenshtein_distance 7 | // CREDIT: https://github.com/sindresorhus/leven (version 3.1.0) 8 | export function getLevenshteinDistance(left: string, right: string): number { 9 | if (left === right) { 10 | return 0; 11 | } 12 | 13 | const swap = left; 14 | 15 | // Swapping the strings if `a` is longer than `b` so we know which one is the 16 | // shortest & which one is the longest 17 | if (left.length > right.length) { 18 | left = right; 19 | right = swap; 20 | } 21 | 22 | let leftLength = left.length; 23 | let rightLength = right.length; 24 | 25 | // Performing suffix trimming: 26 | // We can linearly drop suffix common to both strings since they 27 | // don't increase distance at all 28 | // Note: `~-` is the bitwise way to perform a `- 1` operation 29 | while (leftLength > 0 && 30 | left.charCodeAt(~-leftLength) === right.charCodeAt(~-rightLength)) { 31 | leftLength--; 32 | rightLength--; 33 | } 34 | 35 | // Performing prefix trimming 36 | // We can linearly drop prefix common to both strings since they 37 | // don't increase distance at all 38 | let start = 0; 39 | 40 | while (start < leftLength && 41 | left.charCodeAt(start) === right.charCodeAt(start)) { 42 | start++; 43 | } 44 | 45 | leftLength -= start; 46 | rightLength -= start; 47 | 48 | if (leftLength === 0) { 49 | return rightLength; 50 | } 51 | 52 | let bCharCode; 53 | let result = 0; 54 | let temp; 55 | let temp2; 56 | let i = 0; 57 | let j = 0; 58 | 59 | while (i < leftLength) { 60 | charCodeCache[i] = left.charCodeAt(start + i); 61 | array[i] = ++i; 62 | } 63 | 64 | while (j < rightLength) { 65 | bCharCode = right.charCodeAt(start + j); 66 | temp = j++; 67 | result = j; 68 | 69 | for (i = 0; i < leftLength; i++) { 70 | temp2 = bCharCode === charCodeCache[i] ? temp : temp + 1; 71 | temp = array[i]; 72 | // eslint-disable-next-line no-multi-assign 73 | result = array[i] = 74 | temp > result 75 | ? temp2 > result 76 | ? result + 1 77 | : temp2 78 | : temp2 > temp 79 | ? temp + 1 80 | : temp2; 81 | } 82 | } 83 | 84 | return result; 85 | } 86 | 87 | export function tokenizeForLevenshteinDistance(str: string): string { 88 | return str 89 | .split(/[.,()\[\]/\s]/g) 90 | .sort() 91 | // Remove duplicates 92 | .filter((item, pos, arr) => pos === 0 || item !== arr[pos - 1]) 93 | .join(' '); 94 | } 95 | -------------------------------------------------------------------------------- /src/internal/getWebGLContext.ts: -------------------------------------------------------------------------------- 1 | export function getWebGLContext(isSafari12?: boolean, 2 | failIfMajorPerformanceCaveat = false) { 3 | const attributes: { 4 | alpha: boolean; 5 | antialias: boolean; 6 | depth: boolean; 7 | failIfMajorPerformanceCaveat: boolean; 8 | powerPreference?: string; 9 | stencil: boolean; 10 | } = { 11 | alpha: false, 12 | antialias: false, 13 | depth: false, 14 | failIfMajorPerformanceCaveat, 15 | powerPreference: 'high-performance', 16 | stencil: false, 17 | }; 18 | 19 | // Workaround for Safari 12, which otherwise crashes with powerPreference set 20 | // to high-performance: https://github.com/pmndrs/detect-gpu/issues/5 21 | if (isSafari12) { 22 | delete attributes.powerPreference; 23 | } 24 | 25 | const canvas = window.document.createElement('canvas'); 26 | 27 | const gl = (canvas.getContext('webgl', attributes) || 28 | canvas.getContext( 29 | 'experimental-webgl', 30 | attributes 31 | )) as WebGLRenderingContext | null; 32 | 33 | return gl ?? undefined; 34 | } 35 | -------------------------------------------------------------------------------- /src/internal/ssr.ts: -------------------------------------------------------------------------------- 1 | export const isSSR = typeof window === 'undefined'; 2 | -------------------------------------------------------------------------------- /src/internal/util.ts: -------------------------------------------------------------------------------- 1 | export function isDefined(val: T | undefined | null | void): val is T { 2 | return val !== undefined && val !== null; 3 | } 4 | -------------------------------------------------------------------------------- /test/index.test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @jest-environment jsdom 3 | */ 4 | 5 | // Data 6 | import { RENDERER_DESKTOP, RENDERER_MOBILE, RENDERER_TABLET } from './data'; 7 | 8 | // Application 9 | import { ModelEntry } from '../src'; 10 | import { expectGPUResults, getTier } from './utils'; 11 | 12 | const isDebug = !!process.env.DEBUG; 13 | 14 | for (const renderers of [RENDERER_MOBILE, RENDERER_TABLET, RENDERER_DESKTOP]) { 15 | for (const renderer of renderers) { 16 | test(`${renderer} -> GPUTier returns a valid tier`, async () => { 17 | const input = { 18 | isIpad: /apple.+x/i.test(renderer), 19 | isMobile: renderers !== RENDERER_DESKTOP, 20 | renderer, 21 | }; 22 | 23 | const result = await getTier(input); 24 | const jsonResult = JSON.stringify(result, null, 2); 25 | const { type, tier } = result; 26 | 27 | if (isDebug) { 28 | console.log( 29 | `${tier === 0 ? `TIER 0` : type} -> Input: ${JSON.stringify( 30 | input, 31 | null, 32 | 2 33 | )} - Output: ${jsonResult}` 34 | ); 35 | } 36 | 37 | expect([0, 1, 2, 3]).toContain(tier); 38 | 39 | expect([ 40 | 'WEBGL_UNSUPPORTED', 41 | 'BLOCKLISTED', 42 | 'FALLBACK', 43 | 'BENCHMARK', 44 | ]).toContain(type); 45 | }); 46 | } 47 | } 48 | 49 | const topTierDesktop = 50 | 'ANGLE (NVIDIA GeForce RTX 2080 Ti Direct3D11 vs_5_0 ps_5_0)'; 51 | test(`Top tier desktop: ${topTierDesktop}`, async () => { 52 | expectGPUResults( 53 | { 54 | isMobile: false, 55 | tier: 3, 56 | type: 'BENCHMARK', 57 | }, 58 | await getTier({ 59 | isMobile: false, 60 | renderer: topTierDesktop, 61 | }) 62 | ); 63 | }); 64 | 65 | const bottomTierDesktop = 66 | 'ANGLE (AMD Radeon(TM) HD 8280E Direct3D11 vs_5_0 ps_5_0)'; 67 | 68 | test(`Bottom tier desktop: ${bottomTierDesktop}`, async () => { 69 | expectGPUResults( 70 | { 71 | isMobile: false, 72 | tier: 0, 73 | type: 'BENCHMARK', 74 | }, 75 | await getTier({ 76 | isMobile: false, 77 | renderer: bottomTierDesktop, 78 | }) 79 | ); 80 | }); 81 | 82 | // expect BENCHMARK results: 83 | for (const { input, expected } of [ 84 | { 85 | expected: { 86 | gpu: 'intel uhd graphics 620', 87 | }, 88 | input: { 89 | isMobile: false, 90 | renderer: 'Intel UHD Graphics 620', 91 | }, 92 | }, 93 | { 94 | expected: { 95 | gpu: 'nvidia geforce rtx 2080 ti', 96 | }, 97 | input: { 98 | isMobile: false, 99 | renderer: 'GeForce RTX 2080 Ti/PCIe/SSE2', 100 | }, 101 | }, 102 | { 103 | expected: { 104 | gpu: 'nvidia geforce rtx 2080 ti', 105 | }, 106 | input: { 107 | isMobile: false, 108 | renderer: 'ANGLE (NVIDIA GeForce RTX 2080 Ti Direct3D11 vs_5_0 ps_5_0)', 109 | }, 110 | }, 111 | { 112 | expected: { 113 | gpu: 'amd radeon rx vega m gh', 114 | }, 115 | input: { 116 | isMobile: false, 117 | renderer: 'ANGLE (Radeon RX Vega M GH Graphics Direct3D11 vs_5_0 ps_5_0)', 118 | }, 119 | }, 120 | { 121 | expected: { 122 | device: 'apple ipad pro (11-inch)', 123 | gpu: 'apple a12x gpu', 124 | }, 125 | input: { 126 | isIpad: true, 127 | isMobile: true, 128 | renderer: 'Apple A12X GPU', 129 | }, 130 | }, 131 | { 132 | expected: { 133 | gpu: 'apple a12x gpu', 134 | }, 135 | input: { 136 | isIpad: true, 137 | isMobile: true, 138 | renderer: 'Apple A12X GPU', 139 | }, 140 | }, 141 | { 142 | expected: { 143 | gpu: 'apple a9x gpu', 144 | }, 145 | input: { 146 | isIpad: true, 147 | isMobile: true, 148 | renderer: 'Apple a9x GPU', 149 | }, 150 | }, 151 | { 152 | expected: { 153 | gpu: 'apple a10 gpu', 154 | }, 155 | input: { 156 | isMobile: true, 157 | renderer: 'Apple a10 GPU', 158 | }, 159 | }, 160 | { 161 | expected: { 162 | gpu: 'intel mesa dri intel uhd graphics 630', 163 | }, 164 | input: { 165 | isMobile: false, 166 | renderer: 'Mesa DRI Intel(R) UHD Graphics 630 (Coffeelake 3x8 GT2)', 167 | }, 168 | }, 169 | { 170 | expected: { 171 | gpu: 'nvidia geforce gtx 750', 172 | }, 173 | input: { 174 | isMobile: false, 175 | renderer: 'GeForce GTX 750/PCIe/SSE2', 176 | }, 177 | }, 178 | { 179 | expected: { 180 | gpu: 'nvidia geforce gtx 1060', 181 | }, 182 | input: { 183 | isMobile: false, 184 | renderer: 'GeForce GTX 1060', 185 | }, 186 | }, 187 | { 188 | expected: { 189 | gpu: 'radeon rx 470', 190 | }, 191 | input: { 192 | isMobile: false, 193 | renderer: 'ANGLE (Radeon (TM) RX 470 Series Direct3D11 vs_5_0 ps_5_0)', 194 | }, 195 | }, 196 | { 197 | expected: { 198 | gpu: 'amd radeon hd 6470m', 199 | }, 200 | input: { 201 | isMobile: false, 202 | renderer: 'ANGLE (Radeon (TM) HD 6470M Direct3D9Ex vs_3_0 ps_3_0)', 203 | }, 204 | }, 205 | { 206 | expected: { 207 | gpu: 'nvidia geforce gtx 1060', 208 | }, 209 | input: { 210 | isMobile: false, 211 | renderer: 'ANGLE (NVIDIA GeForce GTX 1060 6GB Direct3D11 vs_5_0 ps_5_0)', 212 | }, 213 | }, 214 | { 215 | expected: { 216 | gpu: 'nvidia tegra', 217 | }, 218 | input: { 219 | isMobile: true, 220 | renderer: 'NVIDIA Tegra', 221 | }, 222 | }, 223 | { 224 | expected: { 225 | gpu: 'arm mali-g51', 226 | }, 227 | input: { 228 | isMobile: true, 229 | renderer: 'Mali-G51', 230 | }, 231 | }, 232 | { 233 | expected: { 234 | gpu: 'samsung xclipse 920', 235 | }, 236 | input: { 237 | isMobile: true, 238 | renderer: 'ANGLE (Samsung Xclipse 920) on Vulkan 1.1.179', 239 | }, 240 | }, 241 | { 242 | expected: { 243 | gpu: 'nvidia geforce gtx 970', 244 | }, 245 | input: { 246 | isMobile: false, 247 | renderer: 'ANGLE (NVIDIA, Vulkan 1.2.175 (NVIDIA NVIDIA GeForce GTX 970 (0x000013C2)), NVIDIA)', 248 | }, 249 | }, 250 | { 251 | expected: { 252 | gpu: 'amd renoir', 253 | }, 254 | input: { 255 | isMobile: false, 256 | renderer: 'amd, amd renoir (llvm 14.0.6), opengl 4.6)', 257 | }, 258 | }, 259 | ]) { 260 | test(`${input.renderer} should find ${expected.gpu}`, async () => { 261 | expectGPUResults( 262 | { 263 | type: 'BENCHMARK', 264 | ...expected, 265 | }, 266 | await getTier(input) 267 | ); 268 | }); 269 | } 270 | 271 | // expect FALLBACK results: 272 | [ 273 | { 274 | isMobile: true, 275 | renderer: 'this renderer does not exist', 276 | }, 277 | { 278 | isMobile: false, 279 | renderer: 'this renderer does not exist', 280 | }, 281 | ].map((settings) => { 282 | test(`${settings.renderer} should return FALLBACK`, async () => { 283 | expectGPUResults( 284 | { 285 | gpu: undefined, 286 | isMobile: settings.isMobile, 287 | type: 'FALLBACK', 288 | }, 289 | await getTier(settings) 290 | ); 291 | }); 292 | }); 293 | 294 | // expect BLOCKLISTED results: 295 | [ 296 | { 297 | input: { 298 | isMobile: false, 299 | renderer: 'ANGLE (ATI Radeon HD 5670 Direct3D11 vs_5_0 ps_5_0)', 300 | }, 301 | }, 302 | { 303 | input: { 304 | isMobile: false, 305 | renderer: 'AMD Radeon HD 6970M OpenGL Engine', 306 | }, 307 | }, 308 | { 309 | input: { 310 | isMobile: false, 311 | renderer: 'ANGLE (NVIDIA Quadro FX 1500 Direct3D9Ex vs_3_0 ps_3_0)', 312 | }, 313 | }, 314 | { 315 | input: { 316 | isMobile: false, 317 | renderer: 'Intel(R) G45/G43 Express Chipset', 318 | }, 319 | }, 320 | { 321 | input: { 322 | isMobile: false, 323 | renderer: 'PowerVR SGX 543', 324 | }, 325 | }, 326 | { 327 | expected: { 328 | gpu: 'google swiftshader', 329 | }, 330 | input: { 331 | isMobile: false, 332 | renderer: 'Google SwiftShader', 333 | }, 334 | }, 335 | { 336 | input: { 337 | isMobile: false, 338 | renderer: 'Intel GMA X3100 OpenGL Engine', 339 | }, 340 | }, 341 | { 342 | input: { 343 | isMobile: false, 344 | renderer: 'NVIDIA GeForce GT 120 OpenGL Engine', 345 | }, 346 | }, 347 | ].map(({ expected = {}, input }) => { 348 | test(`${input.renderer} should return BLOCKLISTED`, async () => { 349 | expectGPUResults( 350 | { 351 | ...expected, 352 | tier: 0, 353 | type: 'BLOCKLISTED', 354 | }, 355 | await getTier(input) 356 | ); 357 | }); 358 | }); 359 | 360 | test(`When queryBenchmarks throws, FALLBACK is returned`, async () => { 361 | expectGPUResults( 362 | { 363 | tier: 1, 364 | type: 'FALLBACK', 365 | }, 366 | await getTier({ 367 | loadBenchmarks: async (): Promise => { 368 | throw new Error(); 369 | }, 370 | renderer: bottomTierDesktop, 371 | }) 372 | ); 373 | }); 374 | -------------------------------------------------------------------------------- /test/ssr.test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @jest-environment node 3 | */ 4 | 5 | import { expectGPUResults, getTier } from './utils'; 6 | 7 | test(`SSR`, async () => { 8 | expectGPUResults( 9 | { 10 | tier: undefined, 11 | type: 'SSR', 12 | }, 13 | await getTier() 14 | ); 15 | }); 16 | -------------------------------------------------------------------------------- /test/utils.ts: -------------------------------------------------------------------------------- 1 | import { getGPUTier, GetGPUTier, ModelEntry, TierResult } from '../src'; 2 | 3 | export function getTier(override: GetGPUTier['override'] = {}) { 4 | return getGPUTier({ 5 | desktopTiers: [0, 15, 30, 60], 6 | mobileTiers: [0, 15, 30, 60], 7 | override: { 8 | loadBenchmarks: async (file: string): Promise => 9 | (await import(`../benchmarks/${file}`)).default, 10 | ...override, 11 | }, 12 | }); 13 | } 14 | 15 | export function expectGPUResults( 16 | expected: Partial, 17 | result: TierResult 18 | ) { 19 | if (expected.type) { 20 | expect(result.type).toBe(expected.type); 21 | } 22 | 23 | if (expected.tier !== undefined) { 24 | expect(result.tier).toBe(expected.tier); 25 | } 26 | 27 | if (expected.isMobile !== undefined) { 28 | expect(result.isMobile).toBe(expected.isMobile); 29 | } 30 | 31 | if (expected.gpu !== undefined) { 32 | expect(result.gpu).toBe(expected.gpu); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "moduleResolution": "node", 4 | "target": "ES2016", 5 | "module": "ESNext", 6 | "lib": ["es2020", "dom"], 7 | "strict": true, 8 | "sourceMap": true, 9 | "declaration": true, 10 | "esModuleInterop": true, 11 | "allowSyntheticDefaultImports": true, 12 | "noImplicitAny": true, 13 | "resolveJsonModule": true, 14 | "declarationDir": "dist/types", 15 | "outDir": "dist/lib", 16 | "typeRoots": ["node_modules/@types"] 17 | }, 18 | "include": ["src/**/*.ts", "rollup/*.ts", "example/**/*.ts"], 19 | "exclude": ["node_modules"] 20 | } 21 | --------------------------------------------------------------------------------