Skip to content

Commit

Permalink
fix: Upgrade gpu-mock.js to latest 100% code coverage tested
Browse files Browse the repository at this point in the history
fix: Added tests for building kernels with "dev" mode
feat: Added a `.toArray()` method on `Input`, for usage with "dev" mode
fix: `Input.size` to reflect exactly what was sent in, rather than make up dimensions that aren't there
fix: `KernelArgument.dimensions` to fill in missing dimensions from size
fix: Only safe declarations when using a literal
  • Loading branch information
robertleeplummerjr committed Jul 11, 2019
1 parent 8283290 commit 5605504
Show file tree
Hide file tree
Showing 17 changed files with 1,311 additions and 261 deletions.
327 changes: 269 additions & 58 deletions dist/gpu-browser-core.js

Large diffs are not rendered by default.

331 changes: 271 additions & 60 deletions dist/gpu-browser-core.min.js

Large diffs are not rendered by default.

327 changes: 269 additions & 58 deletions dist/gpu-browser.js

Large diffs are not rendered by default.

331 changes: 271 additions & 60 deletions dist/gpu-browser.min.js

Large diffs are not rendered by default.

7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
{
"name": "gpu.js",
"version": "2.0.0-rc.20",
"version": "2.0.0-rc.21",
"description": "GPU Accelerated JavaScript",
"engines": {
"node": ">=10.0.0"
},
"main": "./src/index.js",
"files": [
"src", "dist"
"src",
"dist"
],
"unpkg": "./dist/gpu-browser.min.js",
"jsdelivr": "./dist/gpu-browser.min.js",
Expand All @@ -19,7 +20,7 @@
"acorn": "^5.1.1",
"gl": "^4.3.3",
"gl-wiretap": "^0.6.0",
"gpu-mock.js": "^1.0.1"
"gpu-mock.js": "^1.1.0"
},
"devDependencies": {
"benchmark": "^2.1.4",
Expand Down
12 changes: 10 additions & 2 deletions src/backend/web-gl/function-node.js
Original file line number Diff line number Diff line change
Expand Up @@ -593,11 +593,19 @@ class WebGLFunctionNode extends FunctionNode {
if (forNode.init) {
this.pushState('in-for-loop-init');
this.astGeneric(forNode.init, initArr);
for (let i = 0; i < initArr.length; i++) {
if (initArr[i].includes && initArr[i].includes(',')) {
const { declarations } = forNode.init;
for (let i = 0; i < declarations.length; i++) {
if (declarations[i].init && declarations[i].init.type !== 'Literal') {
isSafe = false;
}
}
if (isSafe) {
for (let i = 0; i < initArr.length; i++) {
if (initArr[i].includes && initArr[i].includes(',')) {
isSafe = false;
}
}
}
this.popState('in-for-loop-init');
} else {
isSafe = false;
Expand Down
3 changes: 2 additions & 1 deletion src/backend/web-gl/kernel-value/dynamic-single-input.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ class WebGLKernelValueDynamicSingleInput extends WebGLKernelValueSingleInput {
}

updateValue(value) {
this.dimensions = value.size;
let [w, h, d] = value.size;
this.dimensions = new Int32Array([w || 1, h || 1, d || 1]);
this.textureSize = utils.getMemoryOptimizedFloatTextureSize(this.dimensions, this.bitRatio);
this.uploadArrayLength = this.textureSize[0] * this.textureSize[1] * this.bitRatio;
this.uploadValue = new Float32Array(this.uploadArrayLength);
Expand Down
3 changes: 2 additions & 1 deletion src/backend/web-gl/kernel-value/dynamic-unsigned-input.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ class WebGLKernelValueDynamicUnsignedInput extends WebGLKernelValueUnsignedInput
}

updateValue(value) {
this.dimensions = value.size;
let [w, h, d] = value.size;
this.dimensions = new Int32Array([w || 1, h || 1, d || 1]);
this.textureSize = utils.getMemoryOptimizedPackedTextureSize(this.dimensions, this.bitRatio);
this.uploadArrayLength = this.textureSize[0] * this.textureSize[1] * (4 / this.bitRatio);
const Type = this.getTransferArrayType(value.value);
Expand Down
3 changes: 2 additions & 1 deletion src/backend/web-gl/kernel-value/single-input.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ class WebGLKernelValueSingleInput extends WebGLKernelValue {
super(value, settings);
this.requestTexture();
this.bitRatio = 4;
this.dimensions = value.size;
let [w, h, d] = value.size;
this.dimensions = new Int32Array([w || 1, h || 1, d || 1]);
this.textureSize = utils.getMemoryOptimizedFloatTextureSize(this.dimensions, this.bitRatio);
this.uploadArrayLength = this.textureSize[0] * this.textureSize[1] * this.bitRatio;
this.uploadValue = new Float32Array(this.uploadArrayLength);
Expand Down
3 changes: 2 additions & 1 deletion src/backend/web-gl/kernel-value/unsigned-input.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ class WebGLKernelValueUnsignedInput extends WebGLKernelValue {
super(value, settings);
this.requestTexture();
this.bitRatio = this.getBitRatio(value);
this.dimensions = value.size;
const [w, h, d] = value.size;
this.dimensions = new Int32Array([w || 1, h || 1, d || 1]);
this.textureSize = utils.getMemoryOptimizedPackedTextureSize(this.dimensions, this.bitRatio);
this.uploadArrayLength = this.textureSize[0] * this.textureSize[1] * (4 / this.bitRatio);
this.TranserArrayType = this.getTransferArrayType(value.value);
Expand Down
3 changes: 2 additions & 1 deletion src/backend/web-gl2/kernel-value/dynamic-single-input.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ class WebGL2KernelValueDynamicSingleInput extends WebGL2KernelValueSingleInput {
}

updateValue(value) {
this.dimensions = value.size;
let [w, h, d] = value.size;
this.dimensions = new Int32Array([w || 1, h || 1, d || 1]);
this.textureSize = utils.getMemoryOptimizedFloatTextureSize(this.dimensions, this.bitRatio);
this.uploadArrayLength = this.textureSize[0] * this.textureSize[1] * this.bitRatio;
this.uploadValue = new Float32Array(this.uploadArrayLength);
Expand Down
3 changes: 2 additions & 1 deletion src/gpu.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const gpuMock = require('gpu-mock.js');
const { gpuMock } = require('gpu-mock.js');
const { utils } = require('./utils');
const { CPUKernel } = require('./backend/cpu/kernel');
const { HeadlessGLKernel } = require('./backend/headless-gl/kernel');
Expand Down Expand Up @@ -477,6 +477,7 @@ class GPU {
* @desc Destroys all memory associated with gpu.js & the webGl if we created it
*/
destroy() {
if (!this.kernels) return;
// perform on next run loop - for some reason we dont get lose context events
// if webGl is created and destroyed in the same run loop.
setTimeout(() => {
Expand Down
39 changes: 30 additions & 9 deletions src/input.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,45 @@
class Input {
constructor(value, size) {
this.value = value;
this.size = new Int32Array(3);
if (Array.isArray(size)) {
for (let i = 0; i < this.size.length; i++) {
this.size[i] = size[i] || 1;
}
this.size = size;
} else {
this.size = new Int32Array(3);
if (size.z) {
this.size = new Int32Array([size.x, size.y, size.z]);
} else if (size.y) {
this.size = new Int32Array([size.x, size.y, 1]);
this.size = new Int32Array([size.x, size.y]);
} else {
this.size = new Int32Array([size.x, 1, 1]);
this.size = new Int32Array([size.x]);
}
}

const [w, h, d] = this.size;
if (d) {
if (this.value.length !== (w * h * d)) {
throw new Error(`Input size ${this.value.length} does not match ${w} * ${h} * ${d} = ${(h * w * d)}`);
}
} else if (h) {
if (this.value.length !== (w * h)) {
throw new Error(`Input size ${this.value.length} does not match ${w} * ${h} = ${(h * w)}`);
}
} else {
if (this.value.length !== w) {
throw new Error(`Input size ${this.value.length} does not match ${w}`);
}
}

const [h, w, d] = this.size;
if (this.value.length !== (h * w * d)) {
throw new Error(`Input size ${this.value.length} does not match ${w} * ${h} * ${d} = ${(h * w * d)}`);
}

toArray() {
const { utils } = require('./utils');
const [w, h, d] = this.size;
if (d) {
return utils.erectMemoryOptimized3DFloat(this.value.subarray ? this.value : new Float32Array(this.value), w, h, d);
} else if (h) {
return utils.erectMemoryOptimized2DFloat(this.value.subarray ? this.value : new Float32Array(this.value), w, h);
} else {
return this.value;
}
}
}
Expand Down
1 change: 1 addition & 0 deletions test/all.html
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@
<script type="module" src="features/cpu-with-textures.js"></script>
<script type="module" src="features/create-kernel-map.js"></script>
<script type="module" src="features/demo.js"></script>
<script type="module" src="features/dev-mode.js"></script>
<script type="module" src="features/dynamic-arguments.js"></script>
<script type="module" src="features/dynamic-output.js"></script>
<script type="module" src="features/function-return.js"></script>
Expand Down
147 changes: 147 additions & 0 deletions test/features/dev-mode.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
const { assert, skip, test, module: describe, only } = require('qunit');
const { GPU, input } = require('../../src');

describe('features: dev mode');

test('works with integer', () => {
const gpu = new GPU({ mode: 'dev' });
const kernel = gpu.createKernel(function(value) {
return value;
}, { output: [1] });
assert.deepEqual(kernel(1), new Float32Array([1]));
gpu.destroy();
});

test('works with float', () => {
const gpu = new GPU({ mode: 'dev' });
const kernel = gpu.createKernel(function(value) {
return value;
}, { output: [1] });
assert.deepEqual(kernel(1.5), new Float32Array([1.5]));
gpu.destroy();
});

test('works with array', () => {
const gpu = new GPU({ mode: 'dev' });
const kernel = gpu.createKernel(function(value) {
return value[this.thread.x];
}, { output: [4] });
assert.deepEqual(kernel([1,2,3,4]), new Float32Array([1,2,3,4]));
gpu.destroy();
});

test('works with matrix', () => {
const gpu = new GPU({ mode: 'dev' });
const kernel = gpu.createKernel(function(value) {
return value[this.thread.y][this.thread.x];
}, { output: [4, 2] });
assert.deepEqual(kernel(
[
[1,2,3,4],
[5,6,7,8]
]
), [
new Float32Array([1,2,3,4]),
new Float32Array([5,6,7,8]),
]);
gpu.destroy();
});

test('works with cube', () => {
const gpu = new GPU({ mode: 'dev' });
const kernel = gpu.createKernel(function(value) {
return value[this.thread.z][this.thread.y][this.thread.x];
}, { output: [4, 2, 2] });
assert.deepEqual(kernel(
[
[
[1,2,3,4],
[5,6,7,8]
],
[
[9,10,11,12],
[13,14,15,16]
]
]
), [
[
new Float32Array([1,2,3,4]),
new Float32Array([5,6,7,8]),
],[
new Float32Array([9,10,11,12]),
new Float32Array([13,14,15,16]),
]
]);
gpu.destroy();
});

test('works with input array', () => {
const gpu = new GPU({ mode: 'dev' });
const kernel = gpu.createKernel(function(value) {
return value[this.thread.x];
}, { output: [4] });
assert.deepEqual(kernel(input([1,2,3,4], [4])), new Float32Array([1,2,3,4]));
gpu.destroy();
});

test('works with input matrix', () => {
const gpu = new GPU({ mode: 'dev' });
const kernel = gpu.createKernel(function(value) {
return value[this.thread.y][this.thread.x];
}, { output: [4, 2] });
assert.deepEqual(kernel(input([1,2,3,4,5,6,7,8], [4, 2])), [
new Float32Array([1,2,3,4]),
new Float32Array([5,6,7,8]),
]);
gpu.destroy();
});

test('works with input cube', () => {
const gpu = new GPU({ mode: 'dev' });
const kernel = gpu.createKernel(function(value) {
return value[this.thread.z][this.thread.y][this.thread.x];
}, { output: [4, 2, 2] });
assert.deepEqual(kernel(
input([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16], [4,2,2])
), [
[
new Float32Array([1,2,3,4]),
new Float32Array([5,6,7,8]),
],[
new Float32Array([9,10,11,12]),
new Float32Array([13,14,15,16]),
]
]);
gpu.destroy();
});

test('works with texture', () => {
const texture = ((new GPU()).createKernel(function (cube) {
return cube[this.thread.z][this.thread.y][this.thread.x];
}, { output: [4,2,2], pipeline: true }))([
[
new Float32Array([1,2,3,4]),
new Float32Array([5,6,7,8]),
],[
new Float32Array([9,10,11,12]),
new Float32Array([13,14,15,16]),
]
]);
assert.ok(texture.constructor.name.match('Texture'));
const gpu = new GPU({ mode: 'dev' });
const kernel = gpu.createKernel(function(value) {
return value[this.thread.z][this.thread.y][this.thread.x];
}, { output: [4, 2, 2] });
assert.deepEqual(kernel(
texture
), [
[
new Float32Array([1,2,3,4]),
new Float32Array([5,6,7,8]),
],[
new Float32Array([9,10,11,12]),
new Float32Array([13,14,15,16]),
]
]);
gpu.destroy();
});
22 changes: 22 additions & 0 deletions test/features/input.js
Original file line number Diff line number Diff line change
Expand Up @@ -312,3 +312,25 @@ test("inputInt32ArrayX gpu", () => {
test("inputInt32ArrayX cpu", () => {
inputInt32ArrayX('cpu');
});

test('.toArray() with array', () => {
assert.deepEqual(input([1,2,3,4], [4]).toArray(), [1,2,3,4]);
});
test('.toArray() with matrix', () => {
assert.deepEqual(input([1,2,3,4,5,6,7,8], [4,2]).toArray(), [new Float32Array([1,2,3,4]), new Float32Array([5,6,7,8])]);
});
test('.toArray() with grid', () => {
assert.deepEqual(
input([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16], [4,2,2]).toArray(),
[
[
new Float32Array([1,2,3,4]),
new Float32Array([5,6,7,8]),
],
[
new Float32Array([9,10,11,12]),
new Float32Array([13,14,15,16])
]
]
);
});
10 changes: 5 additions & 5 deletions test/internal/math.random.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,22 +83,22 @@ test('never above 1 every time auto', () => {
mathRandomNeverAboveOne();
});

test('never above 1 every time gpu', () => {
test('never above 1 every time gpu', () => {
mathRandomNeverAboveOne('gpu');
});

(GPU.isWebGLSupported ? test : skip)('never above 1 every time webgl', () => {
(GPU.isWebGLSupported ? test : skip)('never above 1 every time webgl', () => {
mathRandomNeverAboveOne('webgl');
});

(GPU.isWebGL2Supported ? test : skip)('never above 1 every time webgl2', () => {
(GPU.isWebGL2Supported ? test : skip)('never above 1 every time webgl2', () => {
mathRandomNeverAboveOne('webgl2');
});

(GPU.isHeadlessGLSupported ? test : skip)('never above 1 every time headlessgl', () => {
(GPU.isHeadlessGLSupported ? test : skip)('never above 1 every time headlessgl', () => {
mathRandomNeverAboveOne('headlessgl');
});

test('never above 1 every time cpu', () => {
test('never above 1 every time cpu', () => {
mathRandomNeverAboveOne('cpu');
});

0 comments on commit 5605504

Please sign in to comment.