gpu.js/test/features/math-object.js
Robert Plummer 61dfe8a46a fix: #572 excessive calls, reuse textures
feat: introduce WebGL._replaceOutputTexture and WebGL._replaceSubOutputTextures to cut down on resource usage
feat: All supportable Math.methods added
fix: Safari not able to render texture arguments
feat: CPU gets a pipeline that acts like GPU with/without immutable
2020-03-22 17:29:26 -04:00

238 lines
5.3 KiB
JavaScript

const { assert, skip, test, module: describe, only } = require('qunit');
const { GPU } = require('../../src');
describe('features: math object');
function mathProps(mode) {
const props = ['E','LN10','LN2','LOG10E','LOG2E','PI','SQRT1_2','SQRT2'];
const gpu = new GPU({ mode });
for (let i = 0; i < props.length; i++) {
const prop = props[i];
const kernel = gpu.createKernel(`function() {
return Math.${prop};
}`, { output: [1] });
assert.equal(kernel()[0].toFixed(6), Math[prop].toFixed(6));
}
gpu.destroy();
}
test('All Math properties auto', () => {
mathProps();
});
test('All Math properties gpu', () => {
mathProps('gpu');
});
(GPU.isWebGLSupported ? test : skip)('All Math properties webgl', () => {
mathProps('webgl');
});
(GPU.isWebGL2Supported ? test : skip)('All Math properties webgl2', () => {
mathProps('webgl2');
});
(GPU.isHeadlessGLSupported ? test : skip)('All Math properties headlessgl', () => {
mathProps('headlessgl');
});
test('All Math properties cpu', () => {
mathProps('cpu');
});
function singleArgumentMathMethods(mode) {
const methods = [
'abs',
'acos',
'acosh',
'asin',
'asinh',
'atan',
'atanh',
'cbrt',
'ceil',
// 'clz32', // not supported, bits directly are hard
'cos',
'cosh',
'exp',
'expm1',
'floor',
'fround',
// 'hypot', // not supported, dynamically sized
'log',
'log10',
'log1p',
'log2',
'round',
'sign',
'sin',
'sinh',
'sqrt',
'tan',
'tanh',
'trunc',
];
const gpu = new GPU({ mode });
for (let i = 0; i < methods.length; i++) {
const method = methods[i];
const kernel = gpu.createKernel(`function(value) {
return Math.${method}(value);
}`, { output: [1] });
for (let j = 0; j < 10; j++) {
assert.equal(kernel(j / 10)[0].toFixed(3), Math[method](j / 10).toFixed(3), `Math.${method}(${j / 10})`);
}
}
gpu.destroy();
}
test('Single argument Math methods auto', () => {
singleArgumentMathMethods();
});
test('Single argument Math methods gpu', () => {
singleArgumentMathMethods('gpu');
});
(GPU.isWebGLSupported ? test : skip)('Single argument Math methods webgl', () => {
singleArgumentMathMethods('webgl');
});
(GPU.isWebGL2Supported ? test : skip)('Single argument Math methods webgl2', () => {
singleArgumentMathMethods('webgl2');
});
(GPU.isHeadlessGLSupported ? test : skip)('Single argument Math methods headlessgl', () => {
singleArgumentMathMethods('headlessgl');
});
test('Single argument Math methods cpu', () => {
singleArgumentMathMethods('cpu');
});
function twoArgumentMathMethods(mode) {
const methods = [
'atan2',
'imul',
'max',
'min',
'pow',
];
const gpu = new GPU({ mode });
for (let i = 0; i < methods.length; i++) {
const method = methods[i];
const kernel = gpu.createKernel(`function(value1, value2) {
return Math.${method}(value1, value2);
}`, { output: [1] });
for (let j = 0; j < 10; j++) {
const value1 = j / 10;
const value2 = value1;
assert.equal(kernel(value1, value2)[0].toFixed(3), Math[method](value1, value2).toFixed(3), `Math.${method}(${value1}, ${value2})`);
}
}
gpu.destroy();
}
test('Two argument Math methods auto', () => {
twoArgumentMathMethods();
});
test('Two argument Math methods gpu', () => {
twoArgumentMathMethods('gpu');
});
(GPU.isWebGLSupported ? test : skip)('Two argument Math methods webgl', () => {
twoArgumentMathMethods('webgl');
});
(GPU.isWebGL2Supported ? test : skip)('Two argument Math methods webgl2', () => {
twoArgumentMathMethods('webgl2');
});
(GPU.isHeadlessGLSupported ? test : skip)('Two argument Math methods headlessgl', () => {
twoArgumentMathMethods('headlessgl');
});
test('Two argument Math methods cpu', () => {
twoArgumentMathMethods('cpu');
});
function sqrtABTest(mode) {
const gpu = new GPU({ mode });
const f = gpu.createKernel(function(a, b) {
return Math.sqrt(a[this.thread.x] * b[this.thread.x]);
}, {
output : [6]
});
const a = [3, 4, 5, 6, 7, 8];
const b = [3, 4, 5, 6, 7, 8];
const res = f(a,b);
const exp = [3, 4, 5, 6, 7, 8];
assert.deepEqual(Array.from(res), exp);
gpu.destroy();
}
test('sqrtAB auto', () => {
sqrtABTest(null);
});
test('sqrtAB gpu', () => {
sqrtABTest('gpu');
});
(GPU.isWebGLSupported ? test : skip)('sqrtAB webgl', () => {
sqrtABTest('webgl');
});
(GPU.isWebGL2Supported ? test : skip)('sqrtAB webgl2', () => {
sqrtABTest('webgl2');
});
(GPU.isHeadlessGLSupported ? test : skip)('sqrtAB headlessgl', () => {
sqrtABTest('headlessgl');
});
test('sqrtAB cpu', () => {
sqrtABTest('cpu');
});
function mathRandom(mode) {
const gpu = new GPU({ mode });
const kernel = gpu.createKernel(function() {
return Math.random();
}, { output: [1] });
const result = kernel();
assert.ok(result[0] > 0 && result[0] < 1, `value was expected to be between o and 1, but was ${result[0]}`);
}
test('random auto', () => {
mathRandom();
});
test('random gpu', () => {
mathRandom('gpu');
});
(GPU.isWebGLSupported ? test : skip)('random webgl', () => {
mathRandom('webgl');
});
(GPU.isWebGL2Supported ? test : skip)('random webgl2', () => {
mathRandom('webgl2');
});
(GPU.isHeadlessGLSupported ? test : skip)('random headlessgl', () => {
mathRandom('headlessgl');
});
test('random cpu', () => {
mathRandom('cpu');
});