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

ParameterTypeDescription
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.