Renderer · function
describeGpu
Ask what part this machine has, before building a renderer.
Explained in Hello world.
function describeGpu(options?: DescribeGpuOptions): Promise<GpuIdentity>import { describeGpu } from '@driftengine/core';Parameters
| Parameter | Type | Description |
|---|---|---|
options? | DescribeGpuOptions |
In depth
The gap this closes: isWeakGpuFamily is exported for a consumer to classify the part it is
running on, and until now the only string to hand it arrived on a renderer that had already been
constructed — by which time the profile has been consumed and, as applyResolutionScale puts
it, everything except the pixel density is memory allocated at construction. So the one function
the engine offers for this decision took an argument the engine would not give you in time.
Reported from outside 2026-08-28, by a consumer that had fallen back to (pointer: coarse)
instead: a good proxy, right about a phone and wrong about a weak desktop, which is exactly the
case isWeakGpuFamily exists for.
WebGL2 is asked first, and that order is a measurement rather than a preference. The first
version of this asked WebGPU first, and on this machine it answered amd rdna-4 where the built
WebGL2 renderer answered ANGLE (AMD, Vulkan 1.4.354 (AMD Radeon RX 9070 XT (RADV GFX1201) (0x00007550)), radv) — the same part, two spellings, and only one of them carries a model
number. That is not cosmetic: GPUAdapterInfo reports an architecture bucket to limit
fingerprinting, so adreno-7xx is one string for both the 710 measured at 112 ms a frame and
the 740 in a flagship, and the table above deliberately refuses to clamp it. The unmasked
WebGL2 string says Adreno (TM) 710 and the table does clamp that. Asking the API that names
the part first therefore gives a more accurate verdict on the devices this table exists for,
and it costs an adapter request less on every machine that answers.
So this can be more precise than the renderer's own rendererName, and a caller comparing
the two should expect that rather than read it as a fault: a WebGPU renderer on that phone
knows only adreno-7xx and its internal clamp cannot fire, while a consumer that called this
has the part number and can choose a profile the clamp could not reach.
What it costs is one detached WebGL2 context, created and immediately handed back, and — only
where that declines to name the part — one adapter request. An adapter request, not a device
request, which is the cheap half of what selectBackend does. Only a consumer that asks pays it.
Why this rather than a callback inside createRenderer. Handing the profile in as a function
of the part was the alternative and was not taken: the WebGL2 name cannot be read off the real
canvas before the profile is chosen anyway, since that canvas's antialias comes from the
profile; and a fallback from WebGPU to WebGL2 mid-creation would have to call that function a
second time with a different identity, which is a re-entrancy trap inside the one function every
consumer calls. This keeps the decision in the consumer's hands and the signature unchanged.
Nothing here throws. A machine that will name itself through neither API is an ordinary
outcome and answers source: 'none' with an empty name — which isWeakGpuFamily reads as not
weak, the same "unknown is not weak" rule the table is built on. A caller gets the good profile
and ResolutionGovernor corrects it from measurement, which is the design.