はじめに
WebGLのWEBGL_debug_renderer_info
という拡張機能を使うと、ユーザーのGPU情報を取得できるようです。
今回はそれを使って遊んでいきます。
コード
function getGPUInfo() {
const canvas = document.createElement('canvas');
const gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
if (gl) {
const debugInfo = gl.getExtension('WEBGL_debug_renderer_info');
if (debugInfo) {
const vendor = gl.getParameter(debugInfo.UNMASKED_VENDOR_WEBGL);
const renderer = gl.getParameter(debugInfo.UNMASKED_RENDERER_WEBGL);
console.log(renderer);
console.log(vendor);
}
}
}
getGPUInfo();
実行結果
自分の環境(Windows11,Edge)だと、
ANGLE (Intel, Intel(R) UHD Graphics 600 (0x00003185) Direct3D11 vs_5_0 ps_5_0, D3D11)
Google Inc. (Intel)
と出力された。
項目 | 説明 |
---|---|
ANGLE |
Almost Native Graphics Layer Engineの略。WebGLが直接GPUを使わず、変換レイヤーを通して描画していることを示す(主にWindows) |
Intel |
ベンダー(メーカー) |
Intel(R) UHD Graphics 600 |
GPU名(実際に使われているグラボの名称)。 |
0x00003185 |
デバイスID。 |
Direct3D11 |
Windowsで3Dグラフィックを表示するための仕組みで、Microsoftが提供する「DirectX」の3D描画用API。(バージョンが11) |
vs_5_0 ps_5_0 |
Vertex Shader / Pixel Shader のバージョン(5.0) |
D3D11 |
さっき書いたDirect3D11 のこと。(なんで2回?) |
補足:ベンダーが「Google Inc. (Intel)」になってるのは、ANGLEがGoogle製だからだと思われる。
「Intel (Google Inc.)」とかのほうがいいのでは...?
情報量が多すぎる
ごちゃごちゃしててわかりずらい!!
正直GPU名とメーカー以外いらない
GPU名の抽出
実際の出力は環境によって形式がバラバラ。
なので、よくあるパターンを正規表現で用意して、GPU名と思われる部分だけを抽出する。
const r1 = renderer.match(/, (.*?)Direct3D/);
const r2 = renderer.match(/, (.*?) \(\d/);
const r3 = renderer.match(/ANGLE \((.*?) *Direct3D/);
const r4 = renderer.match(/Mesa (.*?)\((CFL|ICL|TGL|RPL|RKL|WHL|GLK)/);
const r5 = renderer.match(/Renderer: (.*?), Unspecified/);
const r6 = renderer.match(/, (.*?)\((KBL|HSW)/);
const r7 = renderer.match(/ANGLE \((.*?)\) on/);
const r8 = renderer.match(/, (.*?), OpenGL/);
const r9 = renderer.match(/(.*?), or similar/);
const r10 = renderer.match(/, (.*?) \(stoney/);
const r11 = renderer.match(/, Vulkan \d+\.\d+\.\d+ \((.*?) \(0x/);
const v1 = vendor.match(/\(([^()]+)\)/);
(これ作るのが一番地獄だった)
次に、ベンダー(メーカー)を抜き出す。
GPUのメーカーは、ソフトの開発者(GPUメーカー)
の形式が多い。
ごくたまにGoogle Inc.(Google Inc.(Intel))
のようにネストされたカッコがある場合もある。
これは正規表現1つでいける。
const v1 = vendor.match(/\(([^()]+)\)/);
あとは抜き出した文字列の中から一番短いものを選ぶ。(無駄な情報がないもの)
const rendererMatch = [r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11]
.filter(Boolean).map(e => e[1].trim());
renderer = rendererMatch.length > 0 ? rendererMatch.reduce((e, t) => t.length < e.length ? t : e) : renderer;
// ベンダーは正規表現1つなので上書きしちゃえばOK
vendor = v1 ? v1[1] : vendor;
完全版コード
最初のコードと組み合わせる。
function getGPUInfo() {
const canvas = document.createElement('canvas');
const gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
if (gl) {
const debugInfo = gl.getExtension('WEBGL_debug_renderer_info');
if (debugInfo) {
let vendor = gl.getParameter(debugInfo.UNMASKED_VENDOR_WEBGL);
let renderer = gl.getParameter(debugInfo.UNMASKED_RENDERER_WEBGL);
const r1 = renderer.match(/, (.*?)Direct3D/);
const r2 = renderer.match(/, (.*?) \(\d/);
const r3 = renderer.match(/ANGLE \((.*?) *Direct3D/);
const r4 = renderer.match(/Mesa (.*?)\((CFL|ICL|TGL|RPL|RKL|WHL|GLK)/);
const r5 = renderer.match(/Renderer: (.*?), Unspecified/);
const r6 = renderer.match(/, (.*?)\((KBL|HSW)/);
const r7 = renderer.match(/ANGLE \((.*?)\) on/);
const r8 = renderer.match(/, (.*?), OpenGL/);
const r9 = renderer.match(/(.*?), or similar/);
const r10 = renderer.match(/, (.*?) \(stoney/);
const r11 = renderer.match(/, Vulkan \d+\.\d+\.\d+ \((.*?) \(0x/);
const v1 = vendor.match(/\(([^()]+)\)/);
const rendererMatch = [r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11]
.filter(Boolean).map(e => e[1].trim());
renderer = rendererMatch.length > 0 ? rendererMatch.reduce((e, t) => t.length < e.length ? t : e) : renderer;
vendor = v1 ? v1[1] : vendor;
console.log(renderer);
console.log(vendor);
}
}
}
getGPUInfo();
IE11対応版
function getGPUInfo() {
var canvas = document.createElement('canvas');
var gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
if (gl) {
var debugInfo = gl.getExtension('WEBGL_debug_renderer_info');
if (debugInfo) {
var vendor = gl.getParameter(debugInfo.UNMASKED_VENDOR_WEBGL);
var renderer = gl.getParameter(debugInfo.UNMASKED_RENDERER_WEBGL);
var r1 = renderer.match(/, (.*?)Direct3D/);
var r2 = renderer.match(/, (.*?) \(\d/);
var r3 = renderer.match(/ANGLE \((.*?) *Direct3D/);
var r4 = renderer.match(/Mesa (.*?)\((CFL|ICL|TGL|RPL|RKL|WHL|GLK)/);
var r5 = renderer.match(/Renderer: (.*?), Unspecified/);
var r6 = renderer.match(/, (.*?)\((KBL|HSW)/);
var r7 = renderer.match(/ANGLE \((.*?)\) on/);
var r8 = renderer.match(/, (.*?), OpenGL/);
var r9 = renderer.match(/(.*?), or similar/);
var r10 = renderer.match(/, (.*?) \(stoney/);
var r11 = renderer.match(/, Vulkan \d+\.\d+\.\d+ \((.*?) \(0x/);
var v1 = vendor.match(/\(([^()]+)\)/);
var rendererMatch = [r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11]
.filter(function(e){ return e; })
.map(function(e){ return e[1].trim(); });
renderer = rendererMatch.length > 0 ? rendererMatch.reduce(function(e, t){
return t.length < e.length ? t : e;
}) : renderer;
vendor = v1 ? v1[1] : vendor;
console.log(renderer);
console.log(vendor);
}
}
}
getGPUInfo();
出力
Intel(R) UHD Graphics 600
Intel
スッキリ!
...したが、GPU情報がスッキリした代わりにコードがごちゃごちゃになってしまった...
まあ良いとしよう。
環境依存について
- Chromium系(Chrome,Edge,Opera)は動作確認済み
- Firefoxはユーザーが拒否してなければ取得できる(精度低いが)
- IEは、IE11なら取得できた。(10以下は無理)
おまけ:Firefoxでの実行結果
Intel(R) HD Graphics 400
Intel
いや性能下がってますやん...
(同じPCです)
タスクマネージャー見たらやっぱIntel(R) UHD Graphics 600
が正しいようなので、FirefoxのGPU情報はあまり信用しない方がいいようです...
参考