Rework a bit the webgl helper to allow having several programs

Without this, doing render passes with different programs using one
helper instance was not really doable
This commit is contained in:
Olivier Guyot
2022-03-09 23:24:27 +01:00
parent 7892c31715
commit cfaf9a14e5
4 changed files with 56 additions and 47 deletions
+2 -2
View File
@@ -540,7 +540,7 @@ class WebGLPointsLayerRenderer extends WebGLLayerRenderer {
this.previousExtent_ = frameState.extent.slice(); this.previousExtent_ = frameState.extent.slice();
} }
this.helper.useProgram(this.program_); this.helper.useProgram(this.program_, frameState);
this.helper.prepareDraw(frameState); this.helper.prepareDraw(frameState);
// write new data // write new data
@@ -726,7 +726,7 @@ class WebGLPointsLayerRenderer extends WebGLLayerRenderer {
Math.floor(frameState.size[1] / 2), Math.floor(frameState.size[1] / 2),
]); ]);
this.helper.useProgram(this.hitProgram_); this.helper.useProgram(this.hitProgram_, frameState);
this.helper.prepareDrawToRenderTarget( this.helper.prepareDrawToRenderTarget(
frameState, frameState,
this.hitRenderTarget_, this.hitRenderTarget_,
+1 -1
View File
@@ -508,7 +508,7 @@ class WebGLTileLayerRenderer extends WebGLLayerRenderer {
} }
} }
this.helper.useProgram(this.program_); this.helper.useProgram(this.program_, frameState);
this.helper.prepareDraw(frameState, !blend); this.helper.prepareDraw(frameState, !blend);
const zs = Object.keys(tileTexturesByZ) const zs = Object.keys(tileTexturesByZ)
+25 -25
View File
@@ -49,6 +49,7 @@ export const DefaultUniform = {
TIME: 'u_time', TIME: 'u_time',
ZOOM: 'u_zoom', ZOOM: 'u_zoom',
RESOLUTION: 'u_resolution', RESOLUTION: 'u_resolution',
SIZE_PX: 'u_sizePx',
}; };
/** /**
@@ -206,11 +207,12 @@ function releaseCanvas(key) {
* Shaders must be compiled and assembled into a program like so: * Shaders must be compiled and assembled into a program like so:
* ```js * ```js
* // here we simply create two shaders and assemble them in a program which is then used * // here we simply create two shaders and assemble them in a program which is then used
* // for subsequent rendering calls * // for subsequent rendering calls; note how a frameState is required to set up a program,
* // as several default uniforms are computed from it (projection matrix, zoom level, etc.)
* const vertexShader = new WebGLVertex(VERTEX_SHADER); * const vertexShader = new WebGLVertex(VERTEX_SHADER);
* const fragmentShader = new WebGLFragment(FRAGMENT_SHADER); * const fragmentShader = new WebGLFragment(FRAGMENT_SHADER);
* const program = this.context.getProgram(fragmentShader, vertexShader); * const program = this.context.getProgram(fragmentShader, vertexShader);
* helper.useProgram(this.program); * helper.useProgram(this.program, frameState);
* ``` * ```
* *
* Uniforms are defined using the `uniforms` option and can either be explicit values or callbacks taking the frame state as argument. * Uniforms are defined using the `uniforms` option and can either be explicit values or callbacks taking the frame state as argument.
@@ -564,8 +566,6 @@ class WebGLHelper extends Disposable {
canvas.style.width = size[0] + 'px'; canvas.style.width = size[0] + 'px';
canvas.style.height = size[1] + 'px'; canvas.style.height = size[1] + 'px';
gl.useProgram(this.currentProgram_);
// loop backwards in post processes list // loop backwards in post processes list
for (let i = this.postProcessPasses_.length - 1; i >= 0; i--) { for (let i = this.postProcessPasses_.length - 1; i >= 0; i--) {
this.postProcessPasses_[i].init(frameState); this.postProcessPasses_[i].init(frameState);
@@ -581,10 +581,6 @@ class WebGLHelper extends Disposable {
gl.ONE, gl.ONE,
opt_disableAlphaBlend ? gl.ZERO : gl.ONE_MINUS_SRC_ALPHA opt_disableAlphaBlend ? gl.ZERO : gl.ONE_MINUS_SRC_ALPHA
); );
gl.useProgram(this.currentProgram_);
this.applyFrameState(frameState);
this.applyUniforms(frameState);
} }
/** /**
@@ -609,10 +605,6 @@ class WebGLHelper extends Disposable {
gl.ONE, gl.ONE,
opt_disableAlphaBlend ? gl.ZERO : gl.ONE_MINUS_SRC_ALPHA opt_disableAlphaBlend ? gl.ZERO : gl.ONE_MINUS_SRC_ALPHA
); );
gl.useProgram(this.currentProgram_);
this.applyFrameState(frameState);
this.applyUniforms(frameState);
} }
/** /**
@@ -709,6 +701,7 @@ class WebGLHelper extends Disposable {
DefaultUniform.RESOLUTION, DefaultUniform.RESOLUTION,
frameState.viewState.resolution frameState.viewState.resolution
); );
this.setUniformFloatVec2(DefaultUniform.SIZE_PX, [size[0], size[1]]);
} }
/** /**
@@ -803,22 +796,20 @@ class WebGLHelper extends Disposable {
} }
/** /**
* Use a program. If the program is already in use, this will return `false`. * Set up a program for use. The program will be set as the current one. Then, the uniforms used
* in the program will be set based on the current frame state and the helper configuration.
* @param {WebGLProgram} program Program. * @param {WebGLProgram} program Program.
* @return {boolean} Changed. * @param {import("../PluggableMap.js").FrameState} frameState Frame state.
* @api * @api
*/ */
useProgram(program) { useProgram(program, frameState) {
if (program == this.currentProgram_) { const gl = this.getGL();
return false; gl.useProgram(program);
} else { this.currentProgram_ = program;
const gl = this.getGL(); this.uniformLocations_ = {};
gl.useProgram(program); this.attribLocations_ = {};
this.currentProgram_ = program; this.applyFrameState(frameState);
this.uniformLocations_ = {}; this.applyUniforms(frameState);
this.attribLocations_ = {};
return true;
}
} }
/** /**
@@ -959,6 +950,15 @@ class WebGLHelper extends Disposable {
this.getGL().uniform1f(this.getUniformLocation(uniform), value); this.getGL().uniform1f(this.getUniformLocation(uniform), value);
} }
/**
* Give a value for a vec2 uniform
* @param {string} uniform Uniform name
* @param {Array<number>} value Array of length 4.
*/
setUniformFloatVec2(uniform, value) {
this.getGL().uniform2fv(this.getUniformLocation(uniform), value);
}
/** /**
* Give a value for a vec4 uniform * Give a value for a vec4 uniform
* @param {string} uniform Uniform name * @param {string} uniform Uniform name
+28 -19
View File
@@ -57,6 +57,15 @@ const INVALID_FRAGMENT_SHADER = `
gl_FragColor = vec4(oops, 1.0, 1.0, 1.0); gl_FragColor = vec4(oops, 1.0, 1.0, 1.0);
}`; }`;
const SAMPLE_FRAMESTATE = {
size: [100, 150],
viewState: {
rotation: 0.4,
resolution: 2,
center: [10, 20],
},
};
describe('ol/webgl/WebGLHelper', function () { describe('ol/webgl/WebGLHelper', function () {
let h; let h;
afterEach(function () { afterEach(function () {
@@ -117,7 +126,10 @@ describe('ol/webgl/WebGLHelper', function () {
u_test4: createTransform(), u_test4: createTransform(),
}, },
}); });
h.useProgram(h.getProgram(FRAGMENT_SHADER, VERTEX_SHADER)); h.useProgram(
h.getProgram(FRAGMENT_SHADER, VERTEX_SHADER),
SAMPLE_FRAMESTATE
);
h.prepareDraw({ h.prepareDraw({
pixelRatio: 2, pixelRatio: 2,
size: [50, 80], size: [50, 80],
@@ -164,7 +176,7 @@ describe('ol/webgl/WebGLHelper', function () {
h = new WebGLHelper(); h = new WebGLHelper();
p = h.getProgram(FRAGMENT_SHADER, VERTEX_SHADER); p = h.getProgram(FRAGMENT_SHADER, VERTEX_SHADER);
h.useProgram(p); h.useProgram(p, SAMPLE_FRAMESTATE);
}); });
it('has saved the program', function () { it('has saved the program', function () {
@@ -209,34 +221,30 @@ describe('ol/webgl/WebGLHelper', function () {
}); });
describe('#makeProjectionTransform', function () { describe('#makeProjectionTransform', function () {
let frameState;
beforeEach(function () { beforeEach(function () {
h = new WebGLHelper(); h = new WebGLHelper();
frameState = {
size: [100, 150],
viewState: {
rotation: 0.4,
resolution: 2,
center: [10, 20],
},
};
}); });
it('gives out the correct transform', function () { it('gives out the correct transform', function () {
const scaleX = 2 / frameState.size[0] / frameState.viewState.resolution; const scaleX =
const scaleY = 2 / frameState.size[1] / frameState.viewState.resolution; 2 /
SAMPLE_FRAMESTATE.size[0] /
SAMPLE_FRAMESTATE.viewState.resolution;
const scaleY =
2 /
SAMPLE_FRAMESTATE.size[1] /
SAMPLE_FRAMESTATE.viewState.resolution;
const given = createTransform(); const given = createTransform();
const expected = createTransform(); const expected = createTransform();
scaleTransform(expected, scaleX, scaleY); scaleTransform(expected, scaleX, scaleY);
rotateTransform(expected, -frameState.viewState.rotation); rotateTransform(expected, -SAMPLE_FRAMESTATE.viewState.rotation);
translateTransform( translateTransform(
expected, expected,
-frameState.viewState.center[0], -SAMPLE_FRAMESTATE.viewState.center[0],
-frameState.viewState.center[1] -SAMPLE_FRAMESTATE.viewState.center[1]
); );
h.makeProjectionTransform(frameState, given); h.makeProjectionTransform(SAMPLE_FRAMESTATE, given);
expect(given.map((val) => val.toFixed(15))).to.eql( expect(given.map((val) => val.toFixed(15))).to.eql(
expected.map((val) => val.toFixed(15)) expected.map((val) => val.toFixed(15))
@@ -377,7 +385,8 @@ describe('ol/webgl/WebGLHelper', function () {
void main(void) { void main(void) {
gl_Position = vec4(u_test, attr3, 0.0, 1.0); gl_Position = vec4(u_test, attr3, 0.0, 1.0);
}` }`
) ),
SAMPLE_FRAMESTATE
); );
}); });