gpu.js/test/internal/deep-types.js
Robert Plummer 86af54efef fix: Node support for v8+
fix: Move `make` cli command to gulp so it runs in parallel
fix: Add official support for `Array1D(2|3|4)`, `Array2D(2|3|4)`, and `Array3D(2|3|4)` and unit tests
fix: Add offical support for `Array(2)`, `Array(3)`, and `Array(4)` and unit tests
fix: Mandelbulb constant used a constant, so moved to appropriate location
fix: Failing unit test for Safari
fix: When not falling back in HeadlessGL, call `STACKGL_resize_drawingbuffer`
fix: Remove `xyz` variable from glsl
fix: Add `uniform4fv` and `uniform4iv` to WebGL implementation
fix: Check for kernel settings `constantTypes` and `argumentTypes`
fix: Inherit type from kernel in KernelValue constructors
fix: Add some typescript details for `GPUVariableType`, `IKernelSettings`, and `ITypesList`
fix: Add support for 4d array in `utils.getMemoryOptimizedFloatTextureSize` for the special use case of `Array3D(2|3|4)`
fix: Add `utils.flatten4dArrayTo` for the special use case of `Array3D(2|3|4)`
fix: Add support for 4d array in `utils.flattenTo`
fix: Bump and build
2019-07-24 12:56:05 -04:00

568 lines
20 KiB
JavaScript

const sinon = require('sinon');
const { assert, test, module: describe, only, skip } = require('qunit');
const { GPU, FunctionBuilder } = require('../../src');
describe('internal: deep types');
function oneLayerDeepFloat(mode) {
const gpu = new GPU({ mode });
function childFunction(childFunctionArgument1) {
return childFunctionArgument1 + 1;
}
gpu.addFunction(childFunction);
const kernel = gpu.createKernel(function(kernelArgument1) {
return childFunction(kernelArgument1);
}, { output: [1] });
sinon.spy(FunctionBuilder.prototype, 'lookupReturnType');
try {
const result = kernel(1.5);
assert.equal(result[0], 2.5);
assert.equal(FunctionBuilder.prototype.lookupReturnType.callCount, 1);
assert.equal(FunctionBuilder.prototype.lookupReturnType.args[0][0], 'childFunction');
} finally {
FunctionBuilder.prototype.lookupReturnType.restore();
}
}
(GPU.isWebGLSupported ? test : skip)('one layer deep float WebGL', () => {
oneLayerDeepFloat('webgl');
});
(GPU.isWebGL2Supported ? test : skip)('one layer deep float WebGL2', () => {
oneLayerDeepFloat('webgl2');
});
(GPU.isHeadlessGLSupported ? test : skip)('one layer deep float HeadlessGL', () => {
oneLayerDeepFloat('headlessgl');
});
function twoLayerDeepFloat(mode) {
const gpu = new GPU({ mode });
function child1Function(child1FunctionArgument1) {
return child2Function(child1FunctionArgument1);
}
function child2Function(child2FunctionArgument1) {
return child2FunctionArgument1 + 1;
}
gpu
.addFunction(child1Function)
.addFunction(child2Function);
const kernel = gpu.createKernel(function(kernelArgument1) {
return child1Function(kernelArgument1);
}, { output: [1] });
sinon.spy(FunctionBuilder.prototype, 'lookupReturnType');
try {
const result = kernel(1.5);
assert.equal(result[0], 2.5);
assert.equal(FunctionBuilder.prototype.lookupReturnType.callCount, 3);
assert.equal(FunctionBuilder.prototype.lookupReturnType.args[0][0], 'child1Function');
assert.equal(FunctionBuilder.prototype.lookupReturnType.args[1][0], 'child2Function');
assert.equal(FunctionBuilder.prototype.lookupReturnType.args[2][0], 'child2Function');
} finally {
FunctionBuilder.prototype.lookupReturnType.restore();
}
}
(GPU.isWebGLSupported ? test : skip)('two layer deep float WebGL', () => {
twoLayerDeepFloat('webgl');
});
(GPU.isWebGL2Supported ? test : skip)('two layer deep float WebGL2', () => {
twoLayerDeepFloat('webgl2');
});
(GPU.isHeadlessGLSupported ? test : skip)('two layer deep float HeadlessGL', () => {
twoLayerDeepFloat('headlessgl');
});
function twoArgumentLayerDeepFloat(mode) {
const gpu = new GPU({ mode });
function child1Function(child1FunctionArgument1) {
return child1FunctionArgument1 + 1;
}
function child2Function(child2FunctionArgument1) {
return child2FunctionArgument1 + 1;
}
gpu
.addFunction(child1Function)
.addFunction(child2Function);
const kernel = gpu.createKernel(function(kernelArgument1) {
return child1Function(child2Function(kernelArgument1));
}, { output: [1] });
sinon.spy(FunctionBuilder.prototype, 'lookupReturnType');
try {
const result = kernel(1.5);
assert.equal(kernel.returnType, 'Float');
assert.equal(result[0], 3.5);
assert.equal(FunctionBuilder.prototype.lookupReturnType.callCount, 3);
assert.equal(FunctionBuilder.prototype.lookupReturnType.args[0][0], 'child2Function');
assert.equal(FunctionBuilder.prototype.lookupReturnType.args[1][0], 'child1Function');
assert.equal(FunctionBuilder.prototype.lookupReturnType.args[2][0], 'child2Function');
} finally {
FunctionBuilder.prototype.lookupReturnType.restore();
}
}
(GPU.isWebGLSupported ? test : skip)('two argument layer deep float WebGL', () => {
twoArgumentLayerDeepFloat('webgl');
});
(GPU.isWebGL2Supported ? test : skip)('two argument layer deep float WebGL2', () => {
twoArgumentLayerDeepFloat('webgl2');
});
(GPU.isHeadlessGLSupported ? test : skip)('two argument layer deep float HeadlessGL', () => {
twoArgumentLayerDeepFloat('headlessgl');
});
function threeLayerDeepFloat(mode) {
const gpu = new GPU({ mode });
function child1Function(child1FunctionArgument1) {
return child2Function(child1FunctionArgument1);
}
function child2Function(child2FunctionArgument1) {
return child3Function(child2FunctionArgument1 + 1);
}
function child3Function(child3FunctionArgument1) {
return child3FunctionArgument1 + 1;
}
gpu
.addFunction(child1Function)
.addFunction(child2Function)
.addFunction(child3Function);
const kernel = gpu.createKernel(function(kernelArgument1) {
return child1Function(kernelArgument1);
}, { output: [1] });
sinon.spy(FunctionBuilder.prototype, 'lookupReturnType');
try {
const result = kernel(1.5);
assert.equal(result[0], 3.5);
assert.equal(FunctionBuilder.prototype.lookupReturnType.callCount, 5);
assert.equal(FunctionBuilder.prototype.lookupReturnType.args[0][0], 'child1Function');
assert.equal(FunctionBuilder.prototype.lookupReturnType.args[1][0], 'child2Function');
assert.equal(FunctionBuilder.prototype.lookupReturnType.args[2][0], 'child3Function');
assert.equal(FunctionBuilder.prototype.lookupReturnType.args[3][0], 'child2Function');
assert.equal(FunctionBuilder.prototype.lookupReturnType.args[4][0], 'child3Function');
} finally {
FunctionBuilder.prototype.lookupReturnType.restore();
}
}
(GPU.isWebGLSupported ? test : skip)('three layer deep float WebGL', () => {
threeLayerDeepFloat('webgl');
});
(GPU.isWebGL2Supported ? test : skip)('three layer deep float WebGL2', () => {
threeLayerDeepFloat('webgl2');
});
(GPU.isHeadlessGLSupported ? test : skip)('three layer deep float HeadlessGL', () => {
threeLayerDeepFloat('headlessgl');
});
function threeArgumentLayerDeepFloat(mode) {
const gpu = new GPU({ mode });
function child1Function(child1FunctionArgument1) {
return child1FunctionArgument1 + 1;
}
function child2Function(child2FunctionArgument1) {
return child2FunctionArgument1 + 1;
}
function child3Function(child3FunctionArgument1) {
return child3FunctionArgument1 + 1;
}
gpu
.addFunction(child1Function)
.addFunction(child2Function)
.addFunction(child3Function);
const kernel = gpu.createKernel(function(kernelArgument1) {
return child1Function(child2Function(child3Function(kernelArgument1)));
}, { output: [1] });
sinon.spy(FunctionBuilder.prototype, 'lookupReturnType');
try {
const result = kernel(1.5);
assert.equal(result[0], 4.5);
assert.equal(FunctionBuilder.prototype.lookupReturnType.callCount, 5);
assert.equal(FunctionBuilder.prototype.lookupReturnType.args[0][0], 'child3Function');
assert.equal(FunctionBuilder.prototype.lookupReturnType.args[1][0], 'child2Function');
assert.equal(FunctionBuilder.prototype.lookupReturnType.args[2][0], 'child1Function');
assert.equal(FunctionBuilder.prototype.lookupReturnType.args[3][0], 'child2Function');
assert.equal(FunctionBuilder.prototype.lookupReturnType.args[4][0], 'child3Function');
} finally {
FunctionBuilder.prototype.lookupReturnType.restore();
}
}
(GPU.isWebGLSupported ? test : skip)('three argument layer deep float WebGL', () => {
threeArgumentLayerDeepFloat('webgl');
});
(GPU.isWebGL2Supported ? test : skip)('three argument layer deep float WebGL2', () => {
threeArgumentLayerDeepFloat('webgl2');
});
(GPU.isHeadlessGLSupported ? test : skip)('three argument layer deep float HeadlessGL', () => {
threeArgumentLayerDeepFloat('headlessgl');
});
function threeArgumentLayerDeepNumberTexture1(mode) {
const gpu = new GPU({ mode });
const texture = gpu.createKernel(function() {
return 1.5;
}, { output: [1], pipeline: true, precision: 'single' })();
function child1Function(child1FunctionArgument1) {
return child1FunctionArgument1 + 1;
}
function child2Function(child2FunctionArgument1) {
return child2FunctionArgument1 + 1;
}
function child3Function(child3FunctionArgument1) {
return child3FunctionArgument1[this.thread.x] + 1;
}
gpu
.addFunction(child1Function)
.addFunction(child2Function)
.addFunction(child3Function);
const kernel = gpu.createKernel(function(kernelArgument1) {
return child1Function(child2Function(child3Function(kernelArgument1)));
}, { output: [1] });
sinon.spy(FunctionBuilder.prototype, 'lookupReturnType');
try {
const result = kernel(texture);
assert.equal(result[0], 4.5);
assert.equal(FunctionBuilder.prototype.lookupReturnType.callCount, 5);
assert.equal(FunctionBuilder.prototype.lookupReturnType.args[0][0], 'child3Function');
assert.equal(FunctionBuilder.prototype.lookupReturnType.args[1][0], 'child2Function');
assert.equal(FunctionBuilder.prototype.lookupReturnType.args[2][0], 'child1Function');
assert.equal(FunctionBuilder.prototype.lookupReturnType.args[3][0], 'child2Function');
assert.equal(FunctionBuilder.prototype.lookupReturnType.args[4][0], 'child3Function');
} finally {
FunctionBuilder.prototype.lookupReturnType.restore();
}
}
(GPU.isSinglePrecisionSupported && GPU.isWebGLSupported ? test : skip)('three argument layer deep NumberTexture(1) WebGL', () => {
threeArgumentLayerDeepNumberTexture1('webgl');
});
(GPU.isSinglePrecisionSupported && GPU.isWebGL2Supported ? test : skip)('three argument layer deep NumberTexture(1) WebGL2', () => {
threeArgumentLayerDeepNumberTexture1('webgl2');
});
(GPU.isSinglePrecisionSupported && GPU.isHeadlessGLSupported ? test : skip)('three argument layer deep NumberTexture(1) HeadlessGL', () => {
threeArgumentLayerDeepNumberTexture1('headlessgl');
});
function circlicalLogic(mode) {
const gpu = new GPU({ mode });
function child1Function(child1FunctionArgument1) {
return child1Function(child1FunctionArgument1);
}
gpu
.addFunction(child1Function);
const kernel = gpu.createKernel(function(kernelArgument1) {
return child1Function(kernelArgument1);
}, { output: [1] });
assert.throws(() => {
kernel(1.5);
});
}
(GPU.isWebGLSupported ? test : skip)('circlical logic webgl', () => {
circlicalLogic('webgl');
});
(GPU.isWebGL2Supported ? test : skip)('circlical logic webgl2', () => {
circlicalLogic('webgl2');
});
(GPU.isHeadlessGLSupported ? test : skip)('circlical logic headlessgl', () => {
circlicalLogic('headlessgl');
});
function arrayTexture1(mode) {
const gpu = new GPU({ mode });
function addOne(functionValue) {
return functionValue[this.thread.x] + 1;
}
gpu.addFunction(addOne);
const texture1 = gpu.createKernel(function() {
return 1;
}, {
output: [1],
precision: 'single',
pipeline: true,
})();
if (mode !== 'cpu') {
assert.equal(texture1.type, 'ArrayTexture(1)');
}
const kernel = gpu.createKernel(function(kernelValue) {
return addOne(kernelValue);
}, { output: [1] });
const result = kernel(texture1);
assert.equal(result[0], 2);
gpu.destroy();
}
(GPU.isSinglePrecisionSupported ? test : skip)('ArrayTexture(1) auto', ()=> {
arrayTexture1();
});
(GPU.isSinglePrecisionSupported ? test : skip)('ArrayTexture(1) gpu', ()=> {
arrayTexture1('gpu');
});
(GPU.isSinglePrecisionSupported && GPU.isWebGLSupported ? test : skip)('ArrayTexture(1) webgl', ()=> {
arrayTexture1('webgl');
});
(GPU.isSinglePrecisionSupported && GPU.isWebGL2Supported ? test : skip)('ArrayTexture(1) webgl2', ()=> {
arrayTexture1('webgl2');
});
(GPU.isSinglePrecisionSupported && GPU.isHeadlessGLSupported ? test : skip)('ArrayTexture(1) headlessgl', ()=> {
arrayTexture1('headlessgl');
});
(GPU.isSinglePrecisionSupported ? test : skip)('ArrayTexture(1) cpu', ()=> {
arrayTexture1('cpu');
});
function arrayTexture2(mode) {
const gpu = new GPU({ mode });
function addOne(functionValue) {
const declaredValue = functionValue[this.thread.x];
return declaredValue[0] + 1 + declaredValue[1] + 1;
}
gpu.addFunction(addOne);
const texture1 = gpu.createKernel(function() {
return [1,2];
}, {
output: [1],
precision: 'single',
pipeline: true,
})();
if (mode !== 'cpu') {
assert.equal(texture1.type, 'ArrayTexture(2)');
}
const kernel = gpu.createKernel(function(kernelValue) {
return addOne(kernelValue);
}, { output: [1] });
const result = kernel(texture1);
assert.equal(result[0], 5);
gpu.destroy();
}
(GPU.isSinglePrecisionSupported ? test : skip)('ArrayTexture(2) auto', ()=> {
arrayTexture2();
});
(GPU.isSinglePrecisionSupported ? test : skip)('ArrayTexture(2) gpu', ()=> {
arrayTexture2('gpu');
});
(GPU.isSinglePrecisionSupported && GPU.isWebGLSupported ? test : skip)('ArrayTexture(2) webgl', ()=> {
arrayTexture2('webgl');
});
(GPU.isSinglePrecisionSupported && GPU.isWebGL2Supported ? test : skip)('ArrayTexture(2) webgl2', ()=> {
arrayTexture2('webgl2');
});
(GPU.isSinglePrecisionSupported && GPU.isHeadlessGLSupported ? test : skip)('ArrayTexture(2) headlessgl', ()=> {
arrayTexture2('headlessgl');
});
(GPU.isSinglePrecisionSupported ? test : skip)('ArrayTexture(2) cpu', ()=> {
arrayTexture2('cpu');
});
function arrayTexture3(mode) {
const gpu = new GPU({ mode });
function addOne(functionValue) {
const declaredValue = functionValue[this.thread.x];
return declaredValue[0] + 1
+ declaredValue[1] + 1
+ declaredValue[2] + 1;
}
gpu.addFunction(addOne);
const texture1 = gpu.createKernel(function() {
return [1,2,3];
}, {
output: [1],
precision: 'single',
pipeline: true,
})();
if (mode !== 'cpu') {
assert.equal(texture1.type, 'ArrayTexture(3)');
}
const kernel = gpu.createKernel(function(kernelValue) {
return addOne(kernelValue);
}, { output: [1] });
const result = kernel(texture1);
assert.equal(result[0], 9);
gpu.destroy();
}
(GPU.isSinglePrecisionSupported ? test : skip)('ArrayTexture(3) auto', ()=> {
arrayTexture3();
});
(GPU.isSinglePrecisionSupported ? test : skip)('ArrayTexture(3) gpu', ()=> {
arrayTexture3('gpu');
});
(GPU.isSinglePrecisionSupported && GPU.isWebGLSupported ? test : skip)('ArrayTexture(3) webgl', ()=> {
arrayTexture3('webgl');
});
(GPU.isSinglePrecisionSupported && GPU.isWebGL2Supported ? test : skip)('ArrayTexture(3) webgl2', ()=> {
arrayTexture3('webgl2');
});
(GPU.isSinglePrecisionSupported && GPU.isHeadlessGLSupported ? test : skip)('ArrayTexture(3) headlessgl', ()=> {
arrayTexture3('headlessgl');
});
(GPU.isSinglePrecisionSupported ? test : skip)('ArrayTexture(3) cpu', ()=> {
arrayTexture3('cpu');
});
function arrayTexture4(mode) {
const gpu = new GPU({ mode });
function addOne(functionValue) {
const declaredValue = functionValue[this.thread.x];
return declaredValue[0] + 1
+ declaredValue[1] + 1
+ declaredValue[2] + 1
+ declaredValue[3] + 1;
}
gpu.addFunction(addOne);
const texture1 = gpu.createKernel(function() {
return [1,2,3,4];
}, {
output: [1],
precision: 'single',
pipeline: true,
})();
if (mode !== 'cpu') {
assert.equal(texture1.type, 'ArrayTexture(4)');
}
const kernel = gpu.createKernel(function(kernelValue) {
return addOne(kernelValue);
}, { output: [1] });
const result = kernel(texture1);
assert.equal(result[0], 14);
gpu.destroy();
}
(GPU.isSinglePrecisionSupported ? test : skip)('ArrayTexture(4) auto', ()=> {
arrayTexture4();
});
(GPU.isSinglePrecisionSupported ? test : skip)('ArrayTexture(4) gpu', ()=> {
arrayTexture4('gpu');
});
(GPU.isSinglePrecisionSupported && GPU.isWebGLSupported ? test : skip)('ArrayTexture(4) webgl', ()=> {
arrayTexture4('webgl');
});
(GPU.isSinglePrecisionSupported && GPU.isWebGL2Supported ? test : skip)('ArrayTexture(4) webgl2', ()=> {
arrayTexture4('webgl2');
});
(GPU.isSinglePrecisionSupported && GPU.isHeadlessGLSupported ? test : skip)('ArrayTexture(4) headlessgl', ()=> {
arrayTexture4('headlessgl');
});
(GPU.isSinglePrecisionSupported ? test : skip)('ArrayTexture(4) cpu', ()=> {
arrayTexture4('cpu');
});
function testTortureTest(mode) {
const gpu = new GPU({ mode });
function addFloatArray(addFloatArrayArgument1, addFloatArrayArgument2) {
return addFloatArrayArgument1 + addFloatArrayArgument2[this.thread.x];
}
function addArrayFloat(addArrayFloatArgument1, addArrayFloatArgument2) {
return addArrayFloatArgument1[this.thread.x] + addArrayFloatArgument2;
}
function addArrayArray(addArrayArrayArgument1, addArrayArrayArgument2) {
return addArrayArrayArgument1[this.thread.x] + addArrayArrayArgument2[this.thread.x];
}
function addFloatFloat(addFloatFloatArgument1, addFloatFloatArgument2) {
return addFloatFloatArgument1 + addFloatFloatArgument2;
}
gpu
.addFunction(addFloatArray)
.addFunction(addArrayFloat)
.addFunction(addArrayArray)
.addFunction(addFloatFloat);
const texture = gpu.createKernel(function() { return 2; }, { output: [1], precision: 'single' })();
// sinon.spy(FunctionBuilder.prototype, 'lookupArgumentType');
sinon.spy(FunctionBuilder.prototype, 'lookupReturnType');
try {
const kernel = gpu.createKernel(function (v1, v2, v3, v4, v5) {
return addFloatFloat(v4, addArrayFloat(v3, addFloatArray(addArrayArray(v1, v5), v2)));
}, {output: [1]});
const result = kernel([1], texture, [3], 4, new Float32Array([5]));
assert.equal(result[0], 1 + 2 + 3 + 4 + 5);
assert.equal(FunctionBuilder.prototype.lookupReturnType.callCount, 7);
assert.equal(FunctionBuilder.prototype.lookupReturnType.returnValues.length, 7);
assert.equal(FunctionBuilder.prototype.lookupReturnType.args[0][0], 'addArrayArray');
assert.equal(FunctionBuilder.prototype.lookupReturnType.returnValues[0], 'Number');
assert.equal(FunctionBuilder.prototype.lookupReturnType.args[1][0], 'addFloatArray');
assert.equal(FunctionBuilder.prototype.lookupReturnType.returnValues[1], 'Number');
assert.equal(FunctionBuilder.prototype.lookupReturnType.args[2][0], 'addArrayFloat');
assert.equal(FunctionBuilder.prototype.lookupReturnType.returnValues[2], 'Number');
assert.equal(FunctionBuilder.prototype.lookupReturnType.args[3][0], 'addFloatFloat');
assert.equal(FunctionBuilder.prototype.lookupReturnType.returnValues[3], 'Float');
assert.equal(FunctionBuilder.prototype.lookupReturnType.args[4][0], 'addArrayFloat');
assert.equal(FunctionBuilder.prototype.lookupReturnType.returnValues[4], 'Number');
assert.equal(FunctionBuilder.prototype.lookupReturnType.args[5][0], 'addFloatArray');
assert.equal(FunctionBuilder.prototype.lookupReturnType.returnValues[5], 'Number');
assert.equal(FunctionBuilder.prototype.lookupReturnType.args[6][0], 'addArrayArray');
assert.equal(FunctionBuilder.prototype.lookupReturnType.returnValues[6], 'Number');
} finally {
FunctionBuilder.prototype.lookupReturnType.restore();
}
}
(GPU.isSinglePrecisionSupported ? test : skip)('torture test auto', () => {
testTortureTest();
});
(GPU.isSinglePrecisionSupported ? test : skip)('torture test gpu', () => {
testTortureTest('gpu');
});
(GPU.isSinglePrecisionSupported && GPU.isWebGLSupported ? test : skip)('torture test webgl', () => {
testTortureTest('webgl');
});
(GPU.isSinglePrecisionSupported && GPU.isWebGL2Supported ? test : skip)('torture test webgl2', () => {
testTortureTest('webgl2');
});
(GPU.isSinglePrecisionSupported && GPU.isHeadlessGLSupported ? test : skip)('torture test headlessgl', () => {
testTortureTest('headlessgl');
});
test('torture test cpu', () => {
testTortureTest('cpu');
});
function testKernelMap(mode) {
const gpu = new GPU({ mode });
function calc1(v1, v2) {
return v2[this.thread.x] - v1;
}
function calc2(v1, v2) {
return v1 * v2;
}
const kernelMap = gpu.createKernelMap({
calc1,
calc2,
}, function (outputs, targets) {
const output = outputs[this.thread.x];
return calc2(calc1(output, targets), output);
}, { output: [1], pipeline: true });
try {
const result = kernelMap([1], [3]);
assert.equal(result.calc1.toArray()[0], 2);
assert.equal(result.calc2.toArray()[0], 2);
assert.equal(result.result.toArray()[0], 2);
} finally {
gpu.destroy();
}
}
(GPU.isWebGLSupported ? test : skip)('kernel map webgl', () => {
testKernelMap('webgl');
});
(GPU.isWebGL2Supported ? test : skip)('kernel map webgl2', () => {
testKernelMap('webgl2');
});
(GPU.isHeadlessGLSupported ? test : skip)('kernel map headlessgl', () => {
testKernelMap('headlessgl');
});