Documentation
    Preparing search index...

    Interface RendererCapabilities

    What a backend can do (§62).

    §62 requires capability reporting to cover maximum texture dimensions, texture formats, multisampling, floating-point targets, timestamp queries, storage buffers, compute shaders, indirect draw, compressed textures, shader precision, and maximum uniforms and bindings — and requires applications to be able to declare required and optional capabilities against that set.

    Two members carried this record until WP-R1.1 (2026-08-21), when the WebGPU backend arrived and made the rest of §62's list answerable: a backend that can run compute has to be able to say so, and an application that needs compute has to be able to ask. The widening is deliberately done once, with all of §62's list, rather than a field per packet — a capability record that grows a member per pipeline churns every implementor once per pipeline.

    The original wording of this doc is the reason, and it is kept because it is still the rule: reporting a field the backend has not queried would be worse than not reporting it, because capability negotiation is precisely the place where a confident wrong answer costs a crash. So the members below are optional rather than required, and undefined is a third answer distinct from false — "this backend has not been taught to answer" rather than "this backend cannot". That also makes the widening additive in the strict sense (decision, WP-R1.1): every existing implementation, test double, and third-party backend still satisfies the type unchanged, which is the hazard §61 records about adding interface members.

    Coverage across the shipped backends is honest rather than total. NullRenderer answers every member with the floor; WebglRenderer answers with WebGL 2's honest conservative values (computeShaders: false is a true statement about WebGL 2, not a shortfall) but deliberately omits maxUniformBufferBytes and maxBindings — R-30b's recorded law, a capability query must be lazy if the alternative moves recorded transcripts, applies verbatim to the two extra getParameter calls, and nothing in the engine reads either number yet (see webgl-renderer.ts); WebgpuRenderer answers from the device's own limits and reports maximumSkinningJoints (RFC 0003's colour pair behind registerSkinningPipeline()). This paragraph claimed the three backends "answer all of them" until 2026-08-29; the omissions above were deliberate from the day each backend's record landed.

    A consumer therefore reads a member as a tri-state:

    if (renderer.capabilities.computeShaders === true) {
    // …dispatch
    }

    §62's "applications may declare required and optional capabilities" is the other half, and it lives where the selection does (WP-R1.9): RendererResolveOptions.capabilities in renderer-registry.ts — "auto" skips a backend that does not affirm every required name, a named backend fails fast, and optional shortfalls are reported. The tri-state above is load-bearing there: undefined never satisfies a requirement.

    Treat instances as immutable: a renderer publishes its capabilities once, at Renderer.initialize time, and callers only read them.

    interface RendererCapabilities {
        backend: RendererBackend;
        compressedTextureFormats?: readonly string[];
        computeShaders?: boolean;
        floatRenderTargets?: boolean;
        indirectDraw?: boolean;
        maxAnisotropy?: number;
        maxBindings?: number;
        maximumSkinningJoints?: number;
        maxTextureSize: number;
        maxUniformBufferBytes?: number;
        multisampling?: boolean;
        shaderPrecision?: "none" | "lowp" | "mediump" | "highp";
        storageBuffers?: boolean;
        textureFormats?: readonly string[];
        timestampQueries?: boolean;
    }
    Index

    Which §62 backend this is.

    compressedTextureFormats?: readonly string[]

    §62 "compressed textures": the compressed texture formats available, by their canonical names ("bc7-rgba-unorm", "etc2-rgba8unorm", …), or an empty list where none are.

    computeShaders?: boolean

    §62 "compute shaders": whether the backend can dispatch compute (§82).

    false on WebGL 2 is a true statement, not a shortfall — WebGL 2 has no compute stage at all, and §62's tiers exist so that an application can read that and pick the CPU path rather than discover it at dispatch time.

    floatRenderTargets?: boolean

    §62 "floating-point targets": whether a render target may hold floating-point components rather than eight-bit normalised ones.

    indirectDraw?: boolean

    §62 "indirect draw": whether draw arguments may be read from a buffer.

    maxAnisotropy?: number

    §62 / §77 anisotropy ceiling: the largest TextureSource.anisotropy this backend will honour, or 1 where anisotropic filtering is absent.

    Optional with the same tri-state as the other WP-R1.1 members — undefined means "not queried yet", which is the construction-time answer on the GPU backends. Reading the WebGL extension at initialize would move landed GL transcripts (R-30b's lazy-query law), so @fourjs/render-webgl!WebglRenderer resolves this on the first read of the field, after init, not during it.

    maxBindings?: number

    §62 "maximum bindings": how many resources one shader stage may bind at once — texture units on WebGL 2, bindings per bind group on WebGPU. 0 for a backend that binds nothing.

    maximumSkinningJoints?: number

    The most bones one skinned draw may use (§54, §62; RFC 0003), or 0 where skinning is unsupported.

    Optional with the tri-state every WP-R1.1 member carries — undefined means "this backend has not been taught to answer", distinct from 0 — which is a recorded deviation from RFC 0003's required-member sketch: the RFC predates the widening law WP-R1.1 landed (every added member is optional, absent means not reported), and a required member here would break every third-party Renderer for a number most backends answer with a constant. The WebGL 2 backend reports @fourjs/render's declared MAX_SKINNING_JOINTS (see mesh.ts for the portability arithmetic); a skinned draw against it additionally requires its registerSkinningPipeline() — the capability says what the backend can do, registration is the application opting in to paying for it.

    maxTextureSize: number

    Largest texture edge length, in texels, the backend accepts (§62 "maximum texture dimensions"). 0 means the backend has no textures at all, which is the honest answer for NullRenderer.

    maxUniformBufferBytes?: number

    §62 "maximum uniforms": the largest uniform buffer binding, in bytes, a single shader may see. 0 for a backend with no shaders.

    Bytes rather than WebGL 2's "uniform vectors", because a byte size is the quantity a caller sizing a buffer actually needs. The WebGPU backend reports the device's maxUniformBufferBindingSize; the WebGL 2 backend deliberately reports nothing here (R-30b — see webgl-renderer.ts for the lazy-query law). Until 2026-08-29 this doc described a WebGL 2 MAX_VERTEX_UNIFORM_VECTORS-to-bytes conversion; no such code ever existed.

    multisampling?: boolean

    §62 "multisampling": whether the backend can allocate a multisampled surface.

    shaderPrecision?: "none" | "lowp" | "mediump" | "highp"

    §62 "shader precision": the highest floating-point precision the fragment stage supports, or "none" for a backend with no shaders at all.

    "highp" on both WebGL 2 (GLSL ES 3.00 requires fragment-stage highp) and WebGPU (WGSL's f32 is single precision by definition).

    storageBuffers?: boolean

    §62 "storage buffers": whether a shader may read and write a storage buffer.

    textureFormats?: readonly string[]

    §62 "texture formats": the render-target and texture formats this backend accepts, by their engine-side names.

    Engine names, not backend names — "rgba8" means "eight-bit unsigned normalised colour", and whether the backend spells that RGBA8, rgba8unorm or bgra8unorm is its own business (§60a, render-target.ts). A backend with no textures reports an empty list.

    timestampQueries?: boolean

    §62 "timestamp queries": whether the backend can time GPU work (§84's GPU-side half). false on WebGL 2 without EXT_disjoint_timer_query_webgl2, and false under SwiftShader.