Improve perf of uniform setters (#370)

This commit is contained in:
Xiaoji Chen 2017-12-07 11:45:57 -08:00 committed by GitHub
parent be430a33a7
commit 7f654b8c22
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 248 additions and 36 deletions

View File

@ -81,24 +81,24 @@ const UNIFORM_SETTERS = {
/* eslint-disable max-len */
[GL_FLOAT]: (gl, location, value) => gl.uniform1f(location, value),
[GL_FLOAT_VEC2]: (gl, location, value) => gl.uniform2fv(location, new Float32Array(value)),
[GL_FLOAT_VEC3]: (gl, location, value) => gl.uniform3fv(location, new Float32Array(value)),
[GL_FLOAT_VEC4]: (gl, location, value) => gl.uniform4fv(location, new Float32Array(value)),
[GL_FLOAT_VEC2]: (gl, location, value) => gl.uniform2fv(location, toFloatArray(value, 2)),
[GL_FLOAT_VEC3]: (gl, location, value) => gl.uniform3fv(location, toFloatArray(value, 3)),
[GL_FLOAT_VEC4]: (gl, location, value) => gl.uniform4fv(location, toFloatArray(value, 4)),
[GL_INT]: (gl, location, value) => gl.uniform1i(location, value),
[GL_INT_VEC2]: (gl, location, value) => gl.uniform2iv(location, new Int32Array(value)),
[GL_INT_VEC3]: (gl, location, value) => gl.uniform3iv(location, new Int32Array(value)),
[GL_INT_VEC4]: (gl, location, value) => gl.uniform4iv(location, new Int32Array(value)),
[GL_INT_VEC2]: (gl, location, value) => gl.uniform2iv(location, toIntArray(value, 2)),
[GL_INT_VEC3]: (gl, location, value) => gl.uniform3iv(location, toIntArray(value, 3)),
[GL_INT_VEC4]: (gl, location, value) => gl.uniform4iv(location, toIntArray(value, 4)),
[GL_BOOL]: (gl, location, value) => gl.uniform1i(location, value),
[GL_BOOL_VEC2]: (gl, location, value) => gl.uniform2iv(location, new Int32Array(value)),
[GL_BOOL_VEC3]: (gl, location, value) => gl.uniform3fv(location, new Int32Array(value)),
[GL_BOOL_VEC4]: (gl, location, value) => gl.uniform4iv(location, new Int32Array(value)),
[GL_BOOL_VEC2]: (gl, location, value) => gl.uniform2iv(location, toIntArray(value, 2)),
[GL_BOOL_VEC3]: (gl, location, value) => gl.uniform3iv(location, toIntArray(value, 3)),
[GL_BOOL_VEC4]: (gl, location, value) => gl.uniform4iv(location, toIntArray(value, 4)),
// uniformMatrix(false): don't transpose the matrix
[GL_FLOAT_MAT2]: (gl, location, value) => gl.uniformMatrix2fv(location, false, new Float32Array(value)),
[GL_FLOAT_MAT3]: (gl, location, value) => gl.uniformMatrix3fv(location, false, new Float32Array(value)),
[GL_FLOAT_MAT4]: (gl, location, value) => gl.uniformMatrix4fv(location, false, new Float32Array(value)),
[GL_FLOAT_MAT2]: (gl, location, value) => gl.uniformMatrix2fv(location, false, toFloatArray(value, 4)),
[GL_FLOAT_MAT3]: (gl, location, value) => gl.uniformMatrix3fv(location, false, toFloatArray(value, 9)),
[GL_FLOAT_MAT4]: (gl, location, value) => gl.uniformMatrix4fv(location, false, toFloatArray(value, 16)),
[GL_SAMPLER_2D]: (gl, location, value) => gl.uniform1i(location, value),
[GL_SAMPLER_CUBE]: (gl, location, value) => gl.uniform1i(location, value),
@ -106,17 +106,17 @@ const UNIFORM_SETTERS = {
// WEBGL2 - unsigned integers, irregular matrices, additional texture samplers
[GL_UNSIGNED_INT]: (gl, location, value) => gl.uniform1ui(location, value),
[GL_UNSIGNED_INT_VEC2]: (gl, location, value) => gl.uniform2uiv(location, new Uint32Array(value)),
[GL_UNSIGNED_INT_VEC3]: (gl, location, value) => gl.uniform3uiv(location, new Uint32Array(value)),
[GL_UNSIGNED_INT_VEC4]: (gl, location, value) => gl.uniform4uiv(location, new Uint32Array(value)),
[GL_UNSIGNED_INT_VEC2]: (gl, location, value) => gl.uniform2uiv(location, toUIntArray(value, 2)),
[GL_UNSIGNED_INT_VEC3]: (gl, location, value) => gl.uniform3uiv(location, toUIntArray(value, 3)),
[GL_UNSIGNED_INT_VEC4]: (gl, location, value) => gl.uniform4uiv(location, toUIntArray(value, 4)),
// uniformMatrix(false): don't transpose the matrix
[GL_FLOAT_MAT2x3]: (gl, location, value) => gl.uniformMatrix2x3fv(location, false, new Float32Array(value)),
[GL_FLOAT_MAT2x4]: (gl, location, value) => gl.uniformMatrix2x4fv(location, false, new Float32Array(value)),
[GL_FLOAT_MAT3x2]: (gl, location, value) => gl.uniformMatrix3x2fv(location, false, new Float32Array(value)),
[GL_FLOAT_MAT3x4]: (gl, location, value) => gl.uniformMatrix3x4fv(location, false, new Float32Array(value)),
[GL_FLOAT_MAT4x2]: (gl, location, value) => gl.uniformMatrix4x2fv(location, false, new Float32Array(value)),
[GL_FLOAT_MAT4x3]: (gl, location, value) => gl.uniformMatrix4x3fv(location, false, new Float32Array(value)),
[GL_FLOAT_MAT2x3]: (gl, location, value) => gl.uniformMatrix2x3fv(location, false, toFloatArray(value, 6)),
[GL_FLOAT_MAT2x4]: (gl, location, value) => gl.uniformMatrix2x4fv(location, false, toFloatArray(value, 8)),
[GL_FLOAT_MAT3x2]: (gl, location, value) => gl.uniformMatrix3x2fv(location, false, toFloatArray(value, 6)),
[GL_FLOAT_MAT3x4]: (gl, location, value) => gl.uniformMatrix3x4fv(location, false, toFloatArray(value, 12)),
[GL_FLOAT_MAT4x2]: (gl, location, value) => gl.uniformMatrix4x2fv(location, false, toFloatArray(value, 8)),
[GL_FLOAT_MAT4x3]: (gl, location, value) => gl.uniformMatrix4x3fv(location, false, toFloatArray(value, 12)),
[GL_SAMPLER_3D]: (gl, location, value) => gl.uniform1i(location, value),
[GL_SAMPLER_2D_SHADOW]: (gl, location, value) => gl.uniform1i(location, value),
@ -134,6 +134,56 @@ const UNIFORM_SETTERS = {
/* eslint-enable max-len */
};
// Pre-allocated typed arrays for temporary conversion
const FLOAT_ARRAY = [2, 3, 4, 6, 8, 9, 12, 16].reduce((arrays, length) => {
arrays[length] = new Float32Array(length);
return arrays;
}, {});
const INT_ARRAY = {
2: new Int32Array(2),
3: new Int32Array(3),
4: new Int32Array(4)
};
const UINT_ARRAY = {
2: new Uint32Array(2),
3: new Uint32Array(3),
4: new Uint32Array(4)
};
/* Functions to ensure the type of uniform values */
function toFloatArray(value, length) {
if (value instanceof Float32Array) {
return value;
}
const result = FLOAT_ARRAY[length];
for (let i = 0; i < length; i++) {
result[i] = value[i];
}
return result;
}
function toIntArray(value, length) {
if (value instanceof Int32Array) {
return value;
}
const result = INT_ARRAY[length];
for (let i = 0; i < length; i++) {
result[i] = value[i];
}
return result;
}
function toUIntArray(value, length) {
if (value instanceof Uint32Array) {
return value;
}
const result = UINT_ARRAY[length];
for (let i = 0; i < length; i++) {
result[i] = value[i];
}
return result;
}
export function parseUniformName(name) {
// name = name[name.length - 1] === ']' ?
// name.substr(0, name.length - 3) : name;

View File

@ -22,10 +22,12 @@
import {Bench} from 'probe.gl';
import shadersBench from './shaders.bench';
import uniformsBench from './uniforms.bench';
const suite = new Bench();
// add tests
uniformsBench(suite);
shadersBench(suite);
// Run the suite

View File

@ -0,0 +1,74 @@
// Copyright (c) 2015 - 2017 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import {createGLContext, Program} from 'luma.gl';
const gl = createGLContext();
const VS = `
uniform vec3 positions;
uniform mat4 uMVMatrix;
uniform mat4 uPMatrix;
void main(void) {
gl_Position = uPMatrix * uMVMatrix * vec4(positions, 1.0);
}
`;
const FS = `
void main(void) {
gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
}
`;
const program = new Program(gl, {vs: VS, fs: FS});
program.use();
const projectionMatrix = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1];
const projectionMatrixTyped = new Float32Array(projectionMatrix);
const projectionMatrixIntTyped = new Int32Array(projectionMatrix);
const positions = [0, 0, 1];
const positionsTyped = new Float32Array(positions);
const positionsIntTyped = new Int32Array(positions);
export default function uniformsBench(suite) {
return suite
.group('SET UNIFORMS')
.add('Set vec3 uniform from Float32Array', () => {
program.setUniforms({positions: positionsTyped});
})
.add('Set vec3 uniform from plain array', () => {
program.setUniforms({positions});
})
.add('Set vec3 uniform from Int32Array', () => {
program.setUniforms({positions: positionsIntTyped});
})
.add('Set mat4 uniform from Float32Array', () => {
program.setUniforms({uPMatrix: projectionMatrixTyped});
})
.add('Set mat4 uniform from plain array', () => {
program.setUniforms({uPMatrix: projectionMatrix});
})
.add('Set mat4 uniform from Int32Array', () => {
program.setUniforms({uPMatrix: projectionMatrixIntTyped});
})
;
}

View File

@ -39,13 +39,20 @@ precision highp float;
#endif
uniform float f;
uniform int i;
uniform bool b;
uniform vec2 v2;
uniform vec3 v3;
uniform vec4 v4;
// int vectors
// bool vectors
uniform int i;
uniform ivec2 iv2;
uniform ivec3 iv3;
uniform ivec4 iv4;
uniform bool b;
uniform bvec2 bv2;
uniform bvec3 bv3;
uniform bvec4 bv4;
uniform mat2 m2;
uniform mat3 m3;
uniform mat4 m4;
@ -54,24 +61,40 @@ uniform sampler2D s2d;
// uniform samplerCube sCube;
void main(void) {
vec4 v = vec4(f) + vec4(v2, 0., 0.) + vec4(v3, 0.) + v4;
ivec4 iv = ivec4(i) + ivec4(iv2, 0., 0.) + ivec4(iv3, 0.) + iv4;
bvec4 bv = bv4;
bv = bvec4(bv3, 0.);
bv = bvec4(bv2, 0., 0.);
bv = bvec4(b);
vec2 transform_v2 = m2 * v2;
vec3 transform_v3 = m3 * v3;
vec4 transform_v4 = m4 * v4;
v = texture2D(s2d, v2);
gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
}
`;
const WEBGL1_GOOD_UNIFORMS = {
f: 1.0,
i: 1,
b: true,
v2: new Float32Array([1, 2]), // FLOAT_VEC2 0x8B50
v3: new Float32Array([1, 2, 3]), // FLOAT_VEC3 0x8B51
v4: new Float32Array([1, 2, 3, 4]), // FLOAT_VEC4 0x8B52
// INT_VEC2 0x8B53
// INT_VEC3 0x8B54
// INT_VEC4 0x8B55
// BOOL 0x8B56
// BOOL_VEC2 0x8B57
// BOOL_VEC3 0x8B58
// BOOL_VEC4 0x8B59
i: -1,
iv2: new Int32Array([1, 2]), // INT_VEC2 0x8B53
iv3: new Int32Array([1, 2, 3]), // INT_VEC3 0x8B54
iv4: new Int32Array([1, 2, 3, 4]), // INT_VEC4 0x8B55
b: true, // BOOL 0x8B56
bv2: new Int32Array([false, true]), // BOOL_VEC2 0x8B57
bv3: new Int32Array([false, true, false]), // BOOL_VEC3 0x8B58
bv4: new Int32Array([false, true, false, true]), // BOOL_VEC4 0x8B59
m2: new Float32Array(MATRIX_2), // FLOAT_MAT2 0x8B5A
m3: new Float32Array(MATRIX_3), // FLOAT_MAT3 0x8B5B
m4: new Float32Array(MATRIX_4), // FLOAT_MAT4 0x8B5C
@ -155,14 +178,77 @@ test('WebGL#Uniforms pre verify uniforms', t => {
t.end();
});
test('WebGL#Uniforms Program construct/delete', t => {
test('WebGL#Uniforms Program uniform locations', t => {
const {gl} = fixture;
const program = new Program(gl, {
vs: VERTEX_SHADER,
fs: WEBGL1_FRAGMENT_SHADER
});
t.ok(program instanceof Program, 'Program construction successful');
for (const uniformName in WEBGL1_GOOD_UNIFORMS) {
t.ok(program._uniformSetters[uniformName], `Program found uniform setter ${uniformName}`);
}
t.end();
});
const testSetUniform = (gl, t) => {
const program = new Program(gl, {
vs: VERTEX_SHADER,
fs: WEBGL1_FRAGMENT_SHADER
});
program.use();
let uniforms = Object.assign({}, WEBGL1_GOOD_UNIFORMS);
t.comment('Test setting typed arrays');
program.setUniforms(uniforms);
t.pass('Set typed array uniforms successful');
uniforms = {};
for (const uniformName in WEBGL1_GOOD_UNIFORMS) {
const value = WEBGL1_GOOD_UNIFORMS[uniformName];
if (value.length) {
// Convert to plain array
uniforms[uniformName] = Array.from(value);
}
}
t.comment('Test setting plain arrays');
program.setUniforms(uniforms);
t.pass('Set plain array uniforms successful');
uniforms = {};
for (const uniformName in WEBGL1_GOOD_UNIFORMS) {
const value = WEBGL1_GOOD_UNIFORMS[uniformName];
if (value.length) {
// Convert to wrong typed array
uniforms[uniformName] = (value instanceof Float32Array) ?
new Int32Array(value) : new Float32Array(value);
}
}
t.comment('Test setting malformed typed arrays');
program.setUniforms(uniforms);
t.pass('Set malformed typed array uniforms successful');
t.end();
};
test('WebGL#Uniforms Program setUniforms', t => {
const {gl} = fixture;
testSetUniform(gl, t);
});
test('WebGL2#Uniforms Program setUniforms', t => {
const {gl2} = fixture;
if (gl2) {
testSetUniform(gl2, t);
} else {
t.end();
}
});