Skip to content

Commit 5a97360

Browse files
committed
fix: detect SwiftShader as BLOCKLISTED, not FALLBACK
SwiftShader is Chrome's CPU-based WebGL fallback, used when no GPU driver is available (CI, Docker, headless browsers, broken drivers). Consumers need to treat it as tier 0 / BLOCKLISTED so they can fall back to a non-WebGL experience — cpu-rasterized WebGL is functional but unusable for anything graphically interesting. Two bugs combined to make this not work (see #120): 1. The blocklist entry was "google swiftshader", but cleanRenderer produces strings like "google, swiftshader ..." (comma between the vendor and product). Substring match failed. 2. Renderer strings can legitimately contain punctuation that doesn't appear in curated blocklist entries. Relying on exact substring match against the raw cleaned string is fragile. Fixes: - Shorten the blocklist entry from "google swiftshader" to just "swiftshader". SwiftShader is Google-only and always software — no false positives to worry about, and it catches future renderer string variants that might omit or reorder the vendor prefix. - Normalize the renderer (strip commas, collapse whitespace) before the blocklist substring check so punctuation-only mismatches no longer slip through. - Document `fps` field semantics in the README result-types section: it's populated for BENCHMARK and the Apple Silicon FALLBACK only, `undefined` for all other types.
1 parent 97127e7 commit 5a97360

4 files changed

Lines changed: 21 additions & 3 deletions

File tree

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ Based on the reported `fps` the GPU is then classified into either `tier: 1 (>=
6969
| `WEBGL_UNSUPPORTED` | No WebGL context could be created. `tier` is always 0. |
7070
| `SSR` | Running server-side — no `window`, detection skipped. |
7171

72+
The `fps` field is populated only for `BENCHMARK` results (the measured framerate) and for the Apple Silicon desktop Safari `FALLBACK` (the conservative M1 floor of 60). All other `type` values leave `fps` as `undefined`.
73+
7274
## API
7375

7476
```ts

src/index.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -320,8 +320,11 @@ export const getGPUTier = async ({
320320
aDis === bDis ? aFps - bFps : aDis - bDis
321321
);
322322
if (!results.length) {
323+
// Commas in cleaned renderers (e.g. "google, swiftshader ...") break
324+
// substring matches against blocklist entries — strip them first.
325+
const renderForBlocklist = renderer!.replace(/,/g, '');
323326
const blocklistedModel: string | undefined = BLOCKLISTED_GPUS.find(
324-
(blocklistedModel) => renderer!.includes(blocklistedModel)
327+
(blocklistedModel) => renderForBlocklist.includes(blocklistedModel)
325328
);
326329
if (blocklistedModel) return toResult(0, 'BLOCKLISTED', blocklistedModel);
327330

src/internal/blocklistedGPUS.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ export const BLOCKLISTED_GPUS = [
1717
'geforce gt 130',
1818
'geforce gt 330m',
1919
'geforce gtx 285',
20-
'google swiftshader',
20+
'swiftshader',
2121
'intel g41',
2222
'intel g45',
2323
'intel gma 4500mhd',

test/index.test.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,19 @@ for (const { input, expected } of [
325325
});
326326
});
327327

328+
test('SwiftShader is detected as BLOCKLISTED tier 0', async () => {
329+
// SwiftShader is Chrome's CPU-based WebGL fallback — no hardware
330+
// acceleration, so consumers should treat it as unusable.
331+
const result = await getTier({
332+
isMobile: false,
333+
renderer:
334+
'ANGLE (Google, Vulkan 1.3.0 (SwiftShader Device (Subzero) (0x0000C0DE)), SwiftShader driver)',
335+
});
336+
expect(result.type).toBe('BLOCKLISTED');
337+
expect(result.tier).toBe(0);
338+
expect(result.gpu).toBe('swiftshader');
339+
});
340+
328341
test('Apple Silicon desktop Safari — conservative tier-3 FALLBACK', async () => {
329342
// Safari returns 'Apple GPU' uniformly for M1–M5 with no chip-level
330343
// discrimination available from WebGL. Since base M1 already hits the
@@ -402,7 +415,7 @@ test('Apple GPU on mobile does NOT take the desktop tier-3 path', async () => {
402415
},
403416
{
404417
expected: {
405-
gpu: 'google swiftshader',
418+
gpu: 'swiftshader',
406419
},
407420
input: {
408421
isMobile: false,

0 commit comments

Comments
 (0)