PlatformEffect
The Android form: a media3 Effect that runs as its own pass, or a TextureOverlay that the pipeline blends with the overlays next to it.
The Apple form: one step of a Core Image chain.
A step, not a bare CIFilter, so an effect can be a transform plus a composite, or a rect operation with no filter at all.
A platform's own realization of one EffectSpec, opaque to common code.
Produced by an EffectResolver and consumed by whichever backend is rendering. Never implemented by a consumer, and never shared between two pipelines.
The JVM form: a fragment of a filter graph.
The platform object here is data rather than a GPU handle, so a resolver is a pure function from a spec to a value and can be asserted on in a unit test with no toolchain installed. How a fragment is spelled on a command line belongs to the backend that runs it, not here.
The browser form: a declaration of one render pass, not a compiled program.
A WebGL program needs a live context, costs milliseconds to link and cannot be shared between contexts, so a resolver cannot hand back a realised program the way the Android and Apple ones do. It hands back what to draw instead, and the pipeline compiles and caches by WebGlPass.programKey. Media3 splits GlEffect from toGlShaderProgram for the same reason.