ブラウザで3Dを描く仕組みといえば、長いあいだ WebGL でした。そこへ WebGPU という新しい土台が来ています。名前からして速そうですし、「WebGLの後継」と紹介されることも多いです。
ただ、この手の「新しい土台」は、本当に今使っていいのかが分かりにくいところです。対応しているブラウザはどれくらいあるのか。そして——これがいちばん気になるところですが——実際に速いのか。
今回は手元のMacで、まったく同じ計算をWebGPU・WebGL2・CPUの3通りで回して比べました。結果は思っていたのと違いました😳
- ★対応ブラウザは出そろっています(2025年9月のSafari 26.0で主要ブラウザが揃いました)
- ★★ところが、同じ計算ではどの重さでもWebGL2のほうが速いという結果でした(1.1〜2.3倍)
- ★逆に、シェーダを用意する費用はWebGPUが4分の1でした(11.1ms 対 42.0ms)
- ★WebGLに廃止の予定はありません。慌てて乗り換える話ではありませんでした
- ★どちらも無料で、自作アプリにも組み込めます。ただし別のマシンのGPUを借りる用途には使えません
実験は3つあります。章タイトルに【承前】と付いている章は、直前の章の続きです。
【前置き】15年ぶりに土台が入れ替わろうとしている
WebGLは、もともとデスクトップ用の古い3Dの仕組み(OpenGL ES)をブラウザに持ち込んだものです。長く使われてきましたが、いまのGPUの使い方とはだいぶ形が違っています。
WebGPUは、そこを作り直したものです。土台には各OSの新しい仕組み(macOSならMetal、WindowsならDirect3D 12)が使われます。ブラウザが違いを吸収して、1つの書き方で全部に届く——というのが売りです。
用語集
| 用語 | 平たく言うと | なぜそれが効くのか |
|---|---|---|
| WebGL / WebGL2 | ブラウザで3Dを描くための仕組み。15年ほど使われてきた | 今もほぼすべてのブラウザで動く。比較の相手 |
| WebGPU | その後継として作られた新しい仕組み。描画だけでなく計算にも使える | この記事の主役 |
| シェーダ | GPUの上で動く小さなプログラム | ★これを用意する費用が、あとで効いてくる |
| コンピュートシェーダ | 絵を描かずに計算だけをさせる使い方 | WebGLには正式には無い。WebGPUで正式に入った |
| パイプライン | 「この形のデータを、このシェーダで、こう処理する」という段取りを固めたもの | ★WebGPUは先に段取りを決めておく設計。ここが速さの分かれ目になる |
| アダプタ | ブラウザから見えるGPUの窓口 | どのGPUに繋がっているかを教えてくれる |
| 読み戻し (readback) | GPUで計算した結果をCPU側へ持ってくること | ★軽い処理ではここが支配的になる |
【下調べ】WebGLとWebGPUの15年
まず、この2つがどこから来たのかを並べておきます。どちらも「その時代のGPUの使い方」をWebに持ち込んだもので、生まれた年代が違うだけ、という見方をすると分かりやすいです。
| 時期 | できごと |
|---|---|
| 2011年3月 | WebGL 1.0 がKhronosから公開。土台はOpenGL ES 2.0(当時のスマホ向け3Dの規格) |
| 2014年9月 | WebGL 1.0 の対応ブラウザが80%を超える |
| 2016年6月 | Googleが「もっと直接的にGPUを触れるWeb API」の提案を始める |
| 2017年1月 | Khronosが「WebGL Next」の会合を開催。Google・Apple・Mozillaがそれぞれ試作を持ち寄る |
| 2017年2月 | AppleのWebKitチームが「WebGPU」という名前で提案。★出発点はMetalをそのままJavaScriptに写したものだった 同月、W3Cに「GPU for the Web」の場ができる |
| 2017年 | WebGL 2.0 がFirefoxとChromeに載る。土台はOpenGL ES 3.0 |
| 2022年2月 | Safari 15 の対応で、WebGL 2.0 が主要ブラウザに行き渡る |
| 2023年4月 | Chrome 113 でWebGPUが正式に出荷(設計開始から6年) |
| 2024年1月 | Chrome 121 でAndroidにも対応 |
| 2025年7月 | Firefox 141 で対応 |
| 2025年9月15日 | Safari 26.0 で対応(macOS・iOS・iPadOS・visionOS) |
★WebGPUは「思いついて作ったら3年で普及した」類のものではありません。提案から出荷まで6年、主要ブラウザに行き渡るまで8年かかっています。逆に言えば、それだけ時間をかけて各社が合意した土台ということでもあります。
シェーダの書き方でも一度もめている
WebGPUは当初、SPIR-V という中間形式をそのまま受け取る設計でした。ところが反対の声があり、WGSL という専用の言語を新しく作る方向に変わっています。
「新しいAPIなのに、なぜ独自の言語を覚え直すのか」と思うところですが、各社が自前のシェーダ言語(HLSL・MSL・GLSL)を持っている以上、どれか1つを選べなかったという事情がありました。
【下調べ・承前】設計が何を変えたのか
【下調べ・承前】実はWebGLもMetalの上で動いている
ここで、今回の実験の前提に関わる大事な話があります。調べていて「そうだったのか」と声が出たところです😳
WebGLは、いまのブラウザではそのまま実行されていません。ChromeもFirefoxもSafariも、ANGLE という変換の層を通しています。ANGLEはOpenGL ES向けの命令を受け取って、動いているOSの本来の仕組みに翻訳します。
| OS | WebGLの命令が最終的に届く先 |
|---|---|
| Windows | Direct3D 11 |
| macOS / iOS | Metal |
| Linux | OpenGL |
Appleは自社のSafariのWebGLをANGLEの上に載せ替えており、そのためにANGLEのMetal対応そのものを1年以上かけて手伝ったという経緯もあります。
★つまり今回の実験は「Metalへの2つの入口」を比べていた
WebGPUはMetalへ直接向かい、WebGLはANGLEを経由してMetalへ向かいます。行き先は同じです。
そう考えると、後で出てくる「WebGL2のほうが速かった」という結果も、間に1枚挟まっているほうが遅い、という単純な話にはならないと分かります。ANGLEのMetal対応はそれだけ作り込まれている、ということでもあります。
【下調べ・承前】対応ブラウザは出そろった
「今使っていいのか」に戻ります。2025年9月15日に出た Safari 26.0 で、主要ブラウザが出そろいました。
| ブラウザ | 状況 |
|---|---|
| Chrome / Edge | Windows(Direct3D 12)・macOS・ChromeOS で対応。Androidは Chrome 121 以降 |
| Safari | Safari 26.0(2025年9月15日)で対応。macOS Tahoe 26 のほか、macOS Sequoia・Sonoma でも動く。iOS 26・iPadOS 26・visionOS 26 も対応 |
| Firefox | 141(2025年7月)で対応開始。その後 macOS の Apple Silicon(145)→ 147(2026年1月)と広がった |
出典:web.dev「主要なブラウザで WebGPU がサポートされるようになりました」/WebKit「WebKit Features in Safari 26.0」
ここで大事なのは、iPhone・iPadでも使えるようになったことです。Webで3Dを配るとき、これまでは「iOSでどうするか」が最大の悩みでした。
【実験の準備】手元のMacで何が使えるのか
手元のMac(M4・macOS 26.6.1)で、ブラウザから見えるGPUの情報を取りました。
navigator.gpu → あり
adapter.info.vendor → apple
adapter.info.architecture → metal-3
adapter.limits.maxBufferSize → 4,294,967,292(約4GB)
adapter.limits.maxComputeWorkgroupSizeX → 1,024
対応している機能 → 22件
shader-f16 / subgroups / timestamp-query /
texture-compression-astc / float32-filterable ほか
★「metal-3」と自己申告してくれます。WebGPUがMetalの上に乗っていることが、ブラウザから読み取れるわけです。使える機能に shader-f16(半分の精度で速く計算する)や subgroups(GPUの中の小集団で協調する)が並んでいるのも、Metalの世代がそのまま出ています。
【実験の準備・承前】測り方とコードの全部
ここで、実際に何をどう測ったのかを全部出しておきます。HTMLファイル1つで動きます。ビルドも、ライブラリの読み込みもありません。
手順は4つだけ
| やること | |
|---|---|
| ① | HTMLを1つ作る。中にJavaScriptを全部書く(下にコードを載せます) |
| ② | そのフォルダでローカルサーバを立てる |
| ③ | ブラウザで開く。★file:// ではなく http://localhost:… で開く |
| ④ | 画面に結果がJSONで出る。それを読むだけ |
cd (bench.html を置いたフォルダ)
python3 -m http.server 8940
# そのあとブラウザで http://localhost:8940/bench.html を開く
# ★file:// で直接開くのではなく、localhost 経由にする
何を計算させているのか
3つの経路で、まったく同じことをさせます。
| 項目 | 内容 |
|---|---|
| 入力 | 100万個の数(32bitの小数) |
| 計算 | 1個につき v = v * 1.0000123 + 0.000001 を決めた回数くり返す |
| 出力 | 100万個の結果をCPU側に戻すところまで |
| くり返し回数 | 10 / 50 / 200 / 1,000 / 4,000 と振る(実験2) |
★掛けて足すだけの単純な式にしたのには理由があります。凝った計算にすると、片方の環境だけ得意・不得意が出てしまい、何を比べているのか分からなくなるからです。
コード① WebGPU(コンピュートシェーダ・WGSL)
WebGPUには「計算だけをさせる」入口があります。配列を渡して、番号ごとに処理させます。
@group(0) @binding(0) var<storage, read> inp : array<f32>;
@group(0) @binding(1) var<storage, read_write> outp : array<f32>;
@compute @workgroup_size(64)
fn main(@builtin(global_invocation_id) gid : vec3<u32>) {
let i = gid.x;
if (i >= arrayLength(&inp)) { return; } // はみ出した分は何もしない
var v = inp[i];
for (var k = 0u; k < 200u; k = k + 1u) { // ← ここの回数を10〜4000で振る
v = v * 1.0000123 + 0.000001;
}
outp[i] = v;
}
@workgroup_size(64) は「64個ずつまとめて動かす」という指定です。100万個を64で割った回数だけ、この処理を並べて走らせます。
コード② WebGL2(フラグメントシェーダ・GLSL)
WebGLには計算専用の入口がありません。そこで「絵を描く仕組みで計算させる」という、昔からのやり方を使います。
#version 300 es
precision highp float;
uniform sampler2D src;
out vec4 col;
void main(){
// 画素の位置=配列の何番目か。1024×1024 の絵を1枚描くと100万要素ぶんになる
float v = texelFetch(src, ivec2(gl_FragCoord.xy), 0).r;
for (int k = 0; k < 200; k++) {
v = v * 1.0000123 + 0.000001;
}
col = vec4(v, 0., 0., 1.);
}
★ここが面白いところです。1024×1024の絵を1枚描かせると、画素がちょうど100万個あります。1画素=配列の1要素と見立てて、色を塗るふりをして計算をさせているわけです。結果は絵(テクスチャ)として出てくるので、それを読み戻します。
コード③ CPU(素のJavaScript)
function cpuRun(src) {
const dst = new Float32Array(N);
for (let i = 0; i < N; i++) {
let v = src[i];
for (let k = 0; k < ITER; k++) v = v * 1.0000123 + 0.000001;
dst[i] = v;
}
return dst;
}
コード④ 測っている部分の骨組み
★ここがこの実験でいちばん大事なところです。準備(シェーダを用意する)と実行(送って計算して受け取る)を分けて、実行だけを測ります。
// ① 準備(計測しない)── シェーダを用意し、バッファを確保する
const prep = await gpuPrepare(ctx, src);
// ② 実行(ここだけ計測する)── 送る → 計算する → 受け取る
async function gpuExec(ctx, prep, src) {
device.queue.writeBuffer(prep.inBuf, 0, src); // 送る
const enc = device.createCommandEncoder();
const pass = enc.beginComputePass();
pass.setPipeline(prep.pipeline);
pass.setBindGroup(0, prep.bind);
pass.dispatchWorkgroups(Math.ceil(N / 64)); // 計算する
pass.end();
enc.copyBufferToBuffer(prep.outBuf, 0, prep.readBuf, 0, prep.bytes);
device.queue.submit([enc.finish()]);
await device.queue.onSubmittedWorkDone(); // 終わるまで待つ
await prep.readBuf.mapAsync(GPUMapMode.READ); // 受け取る
const dst = new Float32Array(prep.readBuf.getMappedRange().slice(0));
prep.readBuf.unmap();
return dst;
}
// ③ 7回まわして、1回目を捨てて中央値を見る
const ts = [];
for (let i = 0; i < 7; i++) {
const t0 = performance.now();
await gpuExec(ctx, prep, src);
ts.push(performance.now() - t0);
}
この分け方をしないと結果が変わる
最初はこれをやっておらず、WebGPU側だけ計測の中でシェーダをコンパイルしていました。その状態と直した状態で、差が1.6倍から1.2倍に変わっています(次の次の章)。
★「同じことを測っているつもり」がいちばん危ないので、手順を紙に書き出してから測るのがおすすめです。
コード⑤ 準備の費用を測るほう
実験3で使ったコードです。毎回シェーダのソースを1文字だけ変えています。同じソースだと、2回目以降は結果が使い回されて不当に速く見えるからです。
// 毎回ソースを1文字だけ変えて、使い回しを避ける
const src = WGSL(200 + r); // r は 0,1,2,3,4
const t0 = performance.now();
const m = device.createShaderModule({ code: src });
await device.createComputePipelineAsync({
layout: "auto", compute: { module: m, entryPoint: "main" }
});
const ms = performance.now() - t0;
結果の見方
画面にはこういうJSONが出ます。数字はミリ秒です。
{
"adapter": { "vendor": "apple", "architecture": "metal-3" },
"webgpu": { "best": 9.4, "median": 9.8, "prepare_ms": 1.3, "sample": 1.0287179946899414 },
"webgl2": { "best": 6.6, "median": 8.2, "prepare_ms": 0.3, "sample": 1.0287179946899414 },
"cpu": { "best": 1176.2, "median": 1763.2, "sample": 1.0287272930145264 }
}
見るところは3つです。
- median(中央値)を主に見る。★ばらつきが大きいので、1回の値では判断しない
- prepare_ms=準備にかかった時間。実行とは別で覚えておく
- ★sample=計算結果の見本。3つの経路で同じ値になっているかをここで確認する。同じ計算をさせたつもりで違うことをしていたら、ここがずれます
実際、CPUだけ末尾がわずかに違いました(…272930145264 対 …179946899414)。JavaScriptの数値は64bitで、GPUは32bitで計算しているためです。ずれた理由が説明できるかどうかが、確認の意味だと思っています。
【実験1】同じ計算を3通りで回す
比べ方はこうしました。100万個の数に、1個あたり200回の掛け算と足し算をするだけの単純な計算です。
v = v * 1.0000123 + 0.000001 ← これを200回くり返す
これを、WebGPU(コンピュートシェーダ)、WebGL2(フラグメントシェーダで代用)、CPU(素のJavaScript)の3通りで回します。測るのは「入力を送る → 計算する → 結果を受け取る」までです。
★結果の値も突き合わせて、同じ計算をしていることを確認しました。
| やり方 | 中央値 | 最良値 | CPUとの差 |
|---|---|---|---|
| CPU(素のJavaScript) | 840.9ms | 795.6ms | — |
| WebGPU | 11.1ms | 8.8ms | 約76倍速い |
| WebGL2 | 8.6ms | 7.3ms | 約98倍速い |
★★ WebGL2のほうが速い
GPUがCPUより桁違いに速いのは予想どおりでしたが、新しいWebGPUのほうが遅いという結果になりました。
最初は「測り方を間違えたのでは」と疑いました。実際、間違えていました——次の章がその話です。ただし直したあとも、順位は変わりませんでした。
【承前】測り方を間違えていた ── 差が4割変わった
最初の版では、WebGPU側だけ、計測している最中にシェーダをコンパイルしていました。WebGL2側は準備を計測の外に出していたので、片方だけ余計な仕事をさせていたことになります。
| 直す前 | 直した後 | |
|---|---|---|
| WebGPU | 12.4ms | 9.8ms |
| WebGL2 | 7.6ms | 8.2ms |
| 差 | 1.6倍 | 1.2倍 |
結論の向き(WebGL2のほうが速い)は変わりませんでしたが、差の大きさは4割ほど変わりました。もし「2倍近く違う」と書いていたら、それは実態より大げさな話になっていたわけです。
比べるときは「両方に同じ手順を踏ませる」
速さを比べる実験でいちばん多い失敗は、片方にだけ余分な仕事をさせてしまうことだと思います。今回は「準備」と「実行」を分けて、どちらも実行だけを測るようにしました。
そして準備の費用も別に測っておくと、あとで効いてきます(実験3)。
【実験2】処理の重さを変えると関係は変わるのか
ここで疑問が出ます。単に処理が軽すぎて、送り迎えの費用しか測れていないのでは?
そこで、1個あたりの反復回数を 10回から4,000回まで振って測りました。
| 1個あたりの反復 | WebGPU | WebGL2 | CPU | WebGPU / WebGL2 |
|---|---|---|---|---|
| 10回 | 9.6ms | 4.1ms | 120.4ms | 2.3倍 |
| 50回 | 8.7ms | 4.7ms | 445.0ms | 1.9倍 |
| 200回 | 11.1ms | 8.6ms | 840.9ms | 1.3倍 |
| 1,000回 | 11.2ms | 10.1ms | (重すぎて未計測) | 1.1倍 |
| 4,000回 | 20.3ms | 15.5ms | (同上) | 1.3倍 |
面白いのは増え方です。反復を10回から200回へ20倍にしても、GPU側は 9.6→11.1ms(WebGPU)、4.1→8.6ms(WebGL2)としか増えていません。一方CPUは 120→841ms とほぼ比例して増えています。
そして2つの差は、重くするほど縮みます(2.3倍 → 1.1倍)。つまりWebGPUが負けていたぶんの多くは、計算の速さではなく、送り迎えの手数だったことになります。
【実験3】シェーダを用意する費用は逆転する
最後に、さっき計測の外に出した「準備」のほうを測りました。シェーダのソースから、実際に使える状態にするまでの時間です。
★毎回ソースを少しずつ変えて、キャッシュが効かないようにしています(同じソースだと2回目以降が不当に速く見えます)。
| やり方 | 中央値 |
|---|---|
| WebGPU(パイプラインを作る) | 11.1ms |
| WebGL2(コンパイル → リンク → 使う) | 42.0ms |
★★ここは逆転しました。WebGPUのほうが約4分の1です。
WebGPUは「あらかじめ段取りを全部決めておく」設計なので、用意する工程が素直です。一方WebGLは、後から状態を変えられる自由度があるぶん、実際に使う直前まで仕事が残ります。
これは「最初のカクつき」の話でもある
シェーダを用意する費用は、ページを開いた直後や、新しい効果が初めて出るときに一気に払うものです。ここが4倍違うということは、立ち上がりの体感に直結します。
⚠なおWebGLは後回しにできる部分を後回しにするので、1回目だけ1.0msという嘘のように速い値も出ました。何回か回して中央値を見ないと騙されます。
【整理】WebGLはいつまで使えるのか
新しい土台が来ると、必ず気になるのがこれです。今あるWebGLのコードは、いつまで動くのか。調べた範囲では、答えははっきりしています。
★廃止の予定は出ていません
Khronos(WebGLを作っている団体)は「WebGLの継続的なサポートに取り組む」と明言しています。ブラウザ側にも、WebGLを削除するという計画は見当たりませんでした。
そしてWebGL 2.0 は96%以上のブラウザで動きます。これだけ広く使われているものを、いま止められる事業者はいません。
根拠として押さえておきたいのは次の3点です。
| 観点 | 状況 |
|---|---|
| 仕様の管理 | Khronosが引き続き管理。圧縮テクスチャ形式の追加やマルチドロー拡張、適合テストの拡充など手は入り続けている |
| ブラウザ側 | 削除の告知は見当たらない。むしろAppleはSafariのWebGLをANGLEの上に載せ替えるなど作り込みを続けている |
| 移行の考え方 | Khronos自身が「WebGLからWebGPUへの滑らかな移行」をW3Cやブラウザ各社と進めると表明。★置き換えを急がせる立場を取っていない |
出典:Khronos「WebGL 2.0 Achieves Pervasive Support from all Major Web Browsers」
ただし、「使える」と「これから伸びる」は別です。新しい機能はWebGPU側に載っていきますし、コンピュートのようにWebGLには最初から無いものもあります。WebGLは長く使えるが、大きく変わることはもう無い——という位置づけになりそうです。
現実的な落としどころは、「WebGPUがあればそれを使い、無ければWebGL2に落ちる」という作りです。実際、主要な3Dライブラリはこの形を採っています。今回の実測でも両者の実行速度は同じ桁だったので、落ちたときに極端に体験が悪くなる心配は要りません。
⚠ ただし「消えない」と「同じ性能で動き続ける」も別
WebGLはANGLEという変換の層に乗っています。OS側の仕組み(Metalなど)が変わっても、ANGLEが吸収してくれるのは強みですが、その吸収に手が入り続けるかどうかは、各社の投資しだいです。長い目で見れば、力が入る先はWebGPUに移っていくと考えるのが自然だと思います。
【整理】無料なのか、自分のアプリでも使えるのか
ここまで書いてきて、自分でも気になったことが2つあります。これは無料で使えるのか。そしてブラウザの外——自作のアプリでも使えるのか。順に整理します。
お金はかからない
| 何が | ライセンス | 商用利用 |
|---|---|---|
| WebGPUの仕様 | W3Cの標準(特許ポリシーはロイヤリティフリーが前提) | 可 |
| WebGLの仕様 | Khronosの標準 | 可 |
| Dawn(Chromeの実装・C/C++) | BSD 3-Clause | 可 |
| wgpu(Firefoxの実装・Rust) | Apache-2.0 / MIT のデュアル | 可 |
| ANGLE(WebGLの変換層) | BSD | 可 |
利用料もライセンス料もありません。自作のアプリに組み込んで販売しても問題ありません。
⚠ ただし「無料で計算力が手に入る」わけではない
動かしているのは目の前の端末に載っているGPUです。つまり実際の費用は、電気代・バッテリーの減り・発熱という形で、そのページを開いた人が払っています。
★重い処理を回すほど、相手の端末が熱くなり電池が減る——Web向けに作るときは、ここを忘れないほうがよさそうです。
WebGPUはGPUではなく、GPUに話しかけるための決まりごと
ここを取り違えると全部ずれるので、経路を1枚にしておきます。
だから正確に言うと、「WebGPUを使うと速くなる」のではなく「すでに載っているGPUを、ブラウザから使えるようになる」です。実験の準備でアダプタが metal-3 と答えたのが、この経路のいちばん下に届いている証拠でした。
自作アプリに組み込めるか → できる。しかも2通り
| やり方 | 中身 |
|---|---|
| ① WebViewを内蔵したアプリに載せる | ElectronやTauriのように、中身がWebのアプリならそのまま使える |
| ② ブラウザ抜きのネイティブアプリで使う | Dawn(C/C++)や wgpu(Rust)をライブラリとして直接リンクする |
★①は今回の実験そのものが証拠になっていた
このベンチマークを走らせたブラウザのUser-Agentを見たら、Electron/42.7.0 が入っていました。つまり今回の数字は、ブラウザではなくElectron製アプリの中で出たものです。
狙って確かめたわけではなく、あとから気づきました😅 逆に言えば、意識しなくても普通に動くということでもあります。
②のほうも実用段階です。wgpu は Vulkan・Metal・Direct3D 12・OpenGL の上でネイティブに動き、WebAssemblyに出すときだけ WebGPU / WebGL2 に乗り換わります。1つのコードで、デスクトップアプリとWebの両方に出せるわけです。名前に「Web」と付いていますが、もうWeb専用ではありません。
⚠ ただし「外部GPUのように使う」はできない
ここは間違えやすいので、3つに分けて書いておきます。
| やりたいこと | WebGPUでできるか | 実際の手段 |
|---|---|---|
| 手元の端末のGPUを使う | ◎ これが本来の用途 | WebGPU / WebGL |
| 別のマシンのGPUを借りる | ✕ 仕組み自体が無い | サーバ側で計算して結果だけ返す、画面を転送する |
| 外付けGPU(eGPU)を使う | △ OSが認識していれば | ⚠Apple SiliconのMacはeGPUに対応していない |
WebGPUが触れるのは、そのコードが動いている端末のGPUだけです。ネットワーク越しにGPUを借りる機能は仕様に入っていません。「重い処理をどこかの強いGPUに投げたい」なら、それはWebGPUの話ではなくサーバ側で計算して結果を返す作りになります。
逆向きの話:訪問者のGPUは「勝手に使える」
別のマシンのGPUは借りられませんが、ページを開いた人のGPUを、その人の許可なく計算に使うことは技術的には可能です。実際、過去にブラウザ上で暗号通貨の採掘をさせる行為が問題になりました。
いまはブラウザ側が実行時間などに制限をかけていますが、作る側としては「重い処理を回す=相手の電池と発熱を使っている」という自覚は持っておきたいところです。
【ここから整理】WebGPUの使いどころ
実測をふまえると、こう整理できます。
| こういう場面 | どちらが向くか | 理由(実測から) |
|---|---|---|
| 単純な計算を1回まわすだけ | WebGL2でも十分 | 実行は1.1〜2.3倍速く、準備も要らないなら手間が少ない |
| シェーダをたくさん切り替える | WebGPU | 用意する費用が約4分の1(11.1ms 対 42.0ms) |
| 絵を描かない計算をさせたい | WebGPU | コンピュートが正式にある。WebGLは描画の仕組みを間借りする必要がある |
| iPhone・iPadにも配りたい | どちらも可 | Safari 26以降ならWebGPUも動く。それ以前を切れないなら WebGL2 |
| とにかく広く届けたい | WebGL2を残す | 古い端末やブラウザではWebGPUが無い。両方用意するのが現実的 |
そして、どちらを使うにしても共通する話があります。GPUに渡すなら、渡す価値のある量の仕事をまとめて渡すこと。100万個の数に10回ずつ計算させるだけなら、その半分以上は送り迎えの時間でした。
つまずき集
- ★ヘッドレスのブラウザではWebGPUの計測が完了しませんでした。フラグを付けても、非同期の処理が終わる前に結果を吸い出してしまいます。実際のブラウザで動かして取りました
- ⚠
Safari --versionを実行するとSafariが起動します😅 版を知りたいだけなら、アプリの中のInfo.plistを読むほうが安全です - ⚠ CPUだけ計算結果の末尾が違いました(1.0287272930145264 対 GPUの1.0287179946899414)。JavaScriptの数値は64bitで、GPUは32bitで計算しているためです。「同じ計算」でも桁の扱いは同じではありません
- ★ 測定値のばらつきは大きめでした(7回で±30%程度)。中央値と最良値の両方を見るようにしています
まとめ
- ★対応ブラウザは出そろいました。2025年9月のSafari 26.0で主要ブラウザが揃い、iPhone・iPadでも動きます
- ★★「新しいほうが速い」ではありませんでした。同じ計算では、どの重さでもWebGL2のほうが速い(1.1〜2.3倍)
- ★差は重くするほど縮みます(2.3倍→1.1倍)。負けていたぶんの多くは計算の速さではなく送り迎えの手数でした
- ★軽い処理では、そもそも計算そのものを測れていません。反復を20倍にしてもGPU側の時間はほとんど増えず、CPUだけがほぼ比例して増えました
- ★★シェーダを用意する費用は逆にWebGPUが約4分の1(11.1ms 対 42.0ms)。立ち上がりの体感に効きます
- ★GPUとCPUの差は約98倍。どちらを選ぶかより、まずGPUに渡すかどうかのほうが桁が大きい
- ★WebGLに廃止の予定はありません。Khronosは継続支持を明言し、WebGL 2.0は96%以上のブラウザで動きます。ただし新しい機能はWebGPU側に載っていくので、「長く使えるが、もう大きくは変わらない」位置づけです
- ★WebGLもANGLEを通してMetalの上で動いています。今回の比較は「Metalへの2つの入口」を比べていたことになります
- ★仕様も実装も無料です(Dawn=BSD、wgpu=Apache-2.0/MIT)。ただし動くのは目の前の端末のGPUなので、費用は電気代とバッテリーという形で読者が払っています
- ★自作アプリにも組み込めます。ElectronやTauriならそのまま、ブラウザ抜きでもDawnやwgpuを直接リンクできます。★今回の数字も、実はElectron製アプリの中で出たものでした
- ⚠「別のマシンのGPUを借りる」用途には使えません。WebGPUが触れるのは、そのコードが動いている端末のGPUだけです
- ⚠測り方を間違えて差が4割変わりました。片方だけ計測の中でシェーダをコンパイルしていたためです。比べるときは両方に同じ手順を踏ませる
「新しい土台が来た」と聞くと、つい乗り換えを考えてしまいます。でも実測してみると、速さのために乗り換えるものではなく、できることが増えるから乗り換えるものだと分かりました。数字を取ってよかった回です😊
それでは、今回はここまで。最後までありがとうございました😊