PipelineFactory
The PipelineFactory
class provides a createRenderPipeline()
method that caches and reuses render pipelines.
The purpose of the pipeline factory is to speed up applications that tend to create multiple render pipelines with the same shaders and other properties. By returning the same cached pipeline, and when used alongside a ShaderFactory
, the pipeline factory minimizes the amount of time spent in shader compilation and linking.
Pipeline creation involves linking shaders. The linking stage is highly dependent on graphics drivers, and the time spent accumulates when creating many pipelines during application startup or during dynamic renderings. Also, on some graphics drivers, pipeline linking can grow non-linearly into the multi-second range for big shaders.
The PipelineFactory
will return the requested pipeline, creating it the first time, and then re-using a cached version if it is requested more than once. An application that tends to create multiple identical RenderPipeline
instances
should consider replacing normal pipeline creation.
It is possible to create multiple pipeline factories, but normally applications rely on the default pipeline factory that is created for each device.
Limitations:
ComputePipeline
caching is not currently supported.
Usage
An application that tends to create multiple identical RenderPipeline
instances
should consider replacing normal pipeline creation.
To deduplicate RenderPipeline
instances, simply replace normal pipeline creation
const pipeline = device.createRenderPipeline({vs, fs, ...}));
with similar calls to the default pipeline factory
import {PipelineFactory} from '@luma.gl/engine';
const pipelineFactory = PipelineFactory.getDefaultPipelineFactory(device);
const pipeline = pipelineFactory.createRenderPipeline({vs, fs, ...}));
To prevent the cache from growing too big, an optional release()
method is also available.
pipelineFactory.release(pipeline);
Pipelines are destroyed by the factory automatically after all users of the pipeline have released their references. To clean up unused pipelines and avoid memory leaks, every call to createRenderPipeline
must be paired with a corresponding call to release
at some later time.
shadertools Integration
import {PipelineFactory} from '@luma.gl/engine';
const pipelineFactory = new PipelineFactory(device);
const vs = device.createShader({
stage: 'vertex',
source: `
attribute vec4 position;
void main() {
#ifdef MY_DEFINE
gl_Position = position;
#else
gl_Position = position.wzyx;
#endif
}
`
});
const fs = device.createShader({
stage: 'fragment',
source: `
void main() {
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
MY_SHADER_HOOK(gl_FragColor);
}
`
});
pipelineFactory.addShaderHook('fs:MY_SHADER_HOOK(inout vec4 color)');
pipelineFactory.addDefaultModule(dirlight); // Will be included in all following programs
const pipeline1 = pipelineFactory.createRenderPipeline({vs, fs}); // Basic, no defines, only default module
const program2 = pipelineFactory.createRenderPipeline({vs, fs}); // Cached, same as pipeline 1, use count 2
const program3 = pipelineFactory.createRenderPipeline({
// New pipeline, with different source based on define
vs,
fs,
defines: {
MY_DEFINE: true
}
});
const program4 = pipelineFactory.createRenderPipeline({
// New pipeline, with different source based on module and its injection
vs,
fs,
defines: {
MY_DEFINE: true
},
modules: [picking]
});
const program5 = pipelineFactory.createRenderPipeline({
// Cached, same as pipeline 4, use count 2
vs,
fs,
defines: {
MY_DEFINE: true
},
modules: [picking]
});
pipelineFactory.release(program1); // Cached pipeline still available, use count 1
pipelineFactory.release(program2); // Cached pipeline deleted
pipelineFactory.release(program3); // Cached pipeline deleted
pipelineFactory.release(program4); // Cached pipeline still available, use count 1
pipelineFactory.release(program5); // Cached pipeline deleted
Static Methods
PipelineFactory.getDefaultPipelineFactory()
Returns the default pipeline factory for a device.
PipelineFactory.getDefaultPipelineFactory(device: Device): PipelineFactory
While it is possible to create multiple factories, most applications will use the default factory.
Methods
createRenderPipeline()
Get a program that fits the parameters provided.
createRenderPipeline(props: RenderPipelineProps): RenderPipeline
If one is already cached, return it, otherwise create and cache a new one.
opts
can include the following (see assembleShaders
for details):
vs
: Base vertexShader
resource.fs
: Base fragmentShader
resource.defines
: Object indicating#define
constants to include in the shaders.modules
: Array of module objects to include in the shaders.inject
: Object of hook injections to include in the shaders.
release()
release(pipeline: RenderPipeline): void
Indicates that a pipeline is no longer in use. Each call to createRenderPipeline()
increments a reference count, and only when all references to a pipeline are released, the pipeline is destroyed and deleted from the cache.
getUniforms(program: Program): Object
Returns an object containing all the uniforms defined for the program. Returns null
if program
isn't managed by the PipelineFactory
.