Skip to content

Commit 252bd51

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 252bd51

4 files changed

Lines changed: 26 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: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -320,8 +320,14 @@ export const getGPUTier = async ({
320320
aDis === bDis ? aFps - bFps : aDis - bDis
321321
);
322322
if (!results.length) {
323+
// Strip punctuation so multi-word blocklist entries match cleaned
324+
// renderer strings that contain commas or collapsed whitespace
325+
// (e.g. "google, swiftshader ..." vs. blocklist entry "swiftshader").
326+
const normalizedForBlocklist = renderer!
327+
.replace(/[,]/g, '')
328+
.replace(/\s+/g, ' ');
323329
const blocklistedModel: string | undefined = BLOCKLISTED_GPUS.find(
324-
(blocklistedModel) => renderer!.includes(blocklistedModel)
330+
(blocklistedModel) => normalizedForBlocklist.includes(blocklistedModel)
325331
);
326332
if (blocklistedModel) return toResult(0, 'BLOCKLISTED', blocklistedModel);
327333

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: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,21 @@ for (const { input, expected } of [
325325
});
326326
});
327327

328+
test('SwiftShader is detected as BLOCKLISTED tier 0', async () => {
329+
// Chrome's CPU-based WebGL fallback. Users see this in CI, Docker,
330+
// headless browsers, or when their GPU driver is broken. Previously
331+
// fell through to FALLBACK because the comma in "google, swiftshader"
332+
// broke the substring match against the blocklist entry.
333+
const result = await getTier({
334+
isMobile: false,
335+
renderer:
336+
'ANGLE (Google, Vulkan 1.3.0 (SwiftShader Device (Subzero) (0x0000C0DE)), SwiftShader driver)',
337+
});
338+
expect(result.type).toBe('BLOCKLISTED');
339+
expect(result.tier).toBe(0);
340+
expect(result.gpu).toBe('swiftshader');
341+
});
342+
328343
test('Apple Silicon desktop Safari — conservative tier-3 FALLBACK', async () => {
329344
// Safari returns 'Apple GPU' uniformly for M1–M5 with no chip-level
330345
// discrimination available from WebGL. Since base M1 already hits the
@@ -402,7 +417,7 @@ test('Apple GPU on mobile does NOT take the desktop tier-3 path', async () => {
402417
},
403418
{
404419
expected: {
405-
gpu: 'google swiftshader',
420+
gpu: 'swiftshader',
406421
},
407422
input: {
408423
isMobile: false,

0 commit comments

Comments
 (0)