Skip to content

Commit

Permalink
fix: gpujs#585 check for inaccurate results for very small kernel
Browse files Browse the repository at this point in the history
fix: gpujs#585 add features.isSpeedTacticSupported and tests
  • Loading branch information
robertleeplummerjr committed Mar 30, 2020
1 parent 1955ad3 commit 7e62639
Show file tree
Hide file tree
Showing 12 changed files with 159 additions and 24 deletions.
34 changes: 28 additions & 6 deletions dist/gpu-browser-core.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
*
* GPU Accelerated JavaScript
*
* @version 2.9.1
* @date Tue Mar 24 2020 07:52:55 GMT-0400 (Eastern Daylight Time)
* @version 2.9.2
* @date Mon Mar 30 2020 08:17:24 GMT-0400 (Eastern Daylight Time)
*
* @license MIT
* The MIT License
Expand Down Expand Up @@ -4615,6 +4615,29 @@ class GLKernel extends Kernel {
return result[0] === 2 && result[1] === 1511;
}

static getIsSpeedTacticSupported() {
function kernelFunction(value) {
return value[this.thread.x];
}
const kernel = new this(kernelFunction.toString(), {
context: this.testContext,
canvas: this.testCanvas,
validate: false,
output: [4],
returnType: 'Number',
precision: 'unsigned',
tactic: 'speed',
});
const args = [
[0, 1, 2, 3]
];
kernel.build.apply(kernel, args);
kernel.run.apply(kernel, args);
const result = kernel.renderOutput();
kernel.destroy(true);
return Math.round(result[0]) === 0 && Math.round(result[1]) === 1 && Math.round(result[2]) === 2 && Math.round(result[3]) === 3;
}

static get testCanvas() {
throw new Error(`"testCanvas" not defined on ${ this.name }`);
}
Expand All @@ -4629,6 +4652,7 @@ class GLKernel extends Kernel {
return Object.freeze({
isFloatRead: this.getIsFloatRead(),
isIntegerDivisionAccurate: this.getIsIntegerDivisionAccurate(),
isSpeedTacticSupported: this.getIsSpeedTacticSupported(),
isTextureFloat: this.getIsTextureFloat(),
isDrawBuffers,
kernelMap: isDrawBuffers,
Expand Down Expand Up @@ -5371,6 +5395,7 @@ class GLKernel extends Kernel {
}
getVariablePrecisionString(textureSize = this.texSize, tactic = this.tactic, isInt = false) {
if (!tactic) {
if (!this.constructor.features.isSpeedTacticSupported) return 'highp';
const low = this.constructor.features[isInt ? 'lowIntPrecision' : 'lowFloatPrecision'];
const medium = this.constructor.features[isInt ? 'mediumIntPrecision' : 'mediumFloatPrecision'];
const high = this.constructor.features[isInt ? 'highIntPrecision' : 'highFloatPrecision'];
Expand Down Expand Up @@ -12749,6 +12774,7 @@ class WebGL2Kernel extends WebGLKernel {
return Object.freeze({
isFloatRead: this.getIsFloatRead(),
isIntegerDivisionAccurate: this.getIsIntegerDivisionAccurate(),
isSpeedTacticSupported: this.getIsSpeedTacticSupported(),
kernelMap: true,
isTextureFloat: true,
isDrawBuffers: true,
Expand All @@ -12767,10 +12793,6 @@ class WebGL2Kernel extends WebGLKernel {
return true;
}

static getIsIntegerDivisionAccurate() {
return super.getIsIntegerDivisionAccurate();
}

static getChannelCount() {
return testContext.getParameter(testContext.MAX_DRAW_BUFFERS);
}
Expand Down
6 changes: 3 additions & 3 deletions dist/gpu-browser-core.min.js

Large diffs are not rendered by default.

34 changes: 28 additions & 6 deletions dist/gpu-browser.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
*
* GPU Accelerated JavaScript
*
* @version 2.9.1
* @date Tue Mar 24 2020 07:52:55 GMT-0400 (Eastern Daylight Time)
* @version 2.9.2
* @date Mon Mar 30 2020 08:17:24 GMT-0400 (Eastern Daylight Time)
*
* @license MIT
* The MIT License
Expand Down Expand Up @@ -9068,6 +9068,29 @@ class GLKernel extends Kernel {
return result[0] === 2 && result[1] === 1511;
}

static getIsSpeedTacticSupported() {
function kernelFunction(value) {
return value[this.thread.x];
}
const kernel = new this(kernelFunction.toString(), {
context: this.testContext,
canvas: this.testCanvas,
validate: false,
output: [4],
returnType: 'Number',
precision: 'unsigned',
tactic: 'speed',
});
const args = [
[0, 1, 2, 3]
];
kernel.build.apply(kernel, args);
kernel.run.apply(kernel, args);
const result = kernel.renderOutput();
kernel.destroy(true);
return Math.round(result[0]) === 0 && Math.round(result[1]) === 1 && Math.round(result[2]) === 2 && Math.round(result[3]) === 3;
}

static get testCanvas() {
throw new Error(`"testCanvas" not defined on ${ this.name }`);
}
Expand All @@ -9082,6 +9105,7 @@ class GLKernel extends Kernel {
return Object.freeze({
isFloatRead: this.getIsFloatRead(),
isIntegerDivisionAccurate: this.getIsIntegerDivisionAccurate(),
isSpeedTacticSupported: this.getIsSpeedTacticSupported(),
isTextureFloat: this.getIsTextureFloat(),
isDrawBuffers,
kernelMap: isDrawBuffers,
Expand Down Expand Up @@ -9824,6 +9848,7 @@ class GLKernel extends Kernel {
}
getVariablePrecisionString(textureSize = this.texSize, tactic = this.tactic, isInt = false) {
if (!tactic) {
if (!this.constructor.features.isSpeedTacticSupported) return 'highp';
const low = this.constructor.features[isInt ? 'lowIntPrecision' : 'lowFloatPrecision'];
const medium = this.constructor.features[isInt ? 'mediumIntPrecision' : 'mediumFloatPrecision'];
const high = this.constructor.features[isInt ? 'highIntPrecision' : 'highFloatPrecision'];
Expand Down Expand Up @@ -17202,6 +17227,7 @@ class WebGL2Kernel extends WebGLKernel {
return Object.freeze({
isFloatRead: this.getIsFloatRead(),
isIntegerDivisionAccurate: this.getIsIntegerDivisionAccurate(),
isSpeedTacticSupported: this.getIsSpeedTacticSupported(),
kernelMap: true,
isTextureFloat: true,
isDrawBuffers: true,
Expand All @@ -17220,10 +17246,6 @@ class WebGL2Kernel extends WebGLKernel {
return true;
}

static getIsIntegerDivisionAccurate() {
return super.getIsIntegerDivisionAccurate();
}

static getChannelCount() {
return testContext.getParameter(testContext.MAX_DRAW_BUFFERS);
}
Expand Down
6 changes: 3 additions & 3 deletions dist/gpu-browser.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "gpu.js",
"version": "2.9.1",
"version": "2.9.2",
"description": "GPU Accelerated JavaScript",
"engines": {
"node": ">=8.0.0"
Expand Down
25 changes: 25 additions & 0 deletions src/backend/gl/kernel.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,29 @@ class GLKernel extends Kernel {
return result[0] === 2 && result[1] === 1511;
}

static getIsSpeedTacticSupported() {
function kernelFunction(value) {
return value[this.thread.x];
}
const kernel = new this(kernelFunction.toString(), {
context: this.testContext,
canvas: this.testCanvas,
validate: false,
output: [4],
returnType: 'Number',
precision: 'unsigned',
tactic: 'speed',
});
const args = [
[0, 1, 2, 3]
];
kernel.build.apply(kernel, args);
kernel.run.apply(kernel, args);
const result = kernel.renderOutput();
kernel.destroy(true);
return Math.round(result[0]) === 0 && Math.round(result[1]) === 1 && Math.round(result[2]) === 2 && Math.round(result[3]) === 3;
}

/**
* @abstract
*/
Expand All @@ -95,6 +118,7 @@ class GLKernel extends Kernel {
return Object.freeze({
isFloatRead: this.getIsFloatRead(),
isIntegerDivisionAccurate: this.getIsIntegerDivisionAccurate(),
isSpeedTacticSupported: this.getIsSpeedTacticSupported(),
isTextureFloat: this.getIsTextureFloat(),
isDrawBuffers,
kernelMap: isDrawBuffers,
Expand Down Expand Up @@ -942,6 +966,7 @@ class GLKernel extends Kernel {
}
getVariablePrecisionString(textureSize = this.texSize, tactic = this.tactic, isInt = false) {
if (!tactic) {
if (!this.constructor.features.isSpeedTacticSupported) return 'highp';
const low = this.constructor.features[isInt ? 'lowIntPrecision' : 'lowFloatPrecision'];
const medium = this.constructor.features[isInt ? 'mediumIntPrecision' : 'mediumFloatPrecision'];
const high = this.constructor.features[isInt ? 'highIntPrecision' : 'highFloatPrecision'];
Expand Down
5 changes: 1 addition & 4 deletions src/backend/web-gl2/kernel.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ class WebGL2Kernel extends WebGLKernel {
return Object.freeze({
isFloatRead: this.getIsFloatRead(),
isIntegerDivisionAccurate: this.getIsIntegerDivisionAccurate(),
isSpeedTacticSupported: this.getIsSpeedTacticSupported(),
kernelMap: true,
isTextureFloat: true,
isDrawBuffers: true,
Expand All @@ -89,10 +90,6 @@ class WebGL2Kernel extends WebGLKernel {
return true;
}

static getIsIntegerDivisionAccurate() {
return super.getIsIntegerDivisionAccurate();
}

static getChannelCount() {
return testContext.getParameter(testContext.MAX_DRAW_BUFFERS);
}
Expand Down
1 change: 1 addition & 0 deletions src/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,7 @@ export interface IKernelFeatures {
isFloatRead: boolean;
kernelMap: boolean;
isIntegerDivisionAccurate: boolean;
isSpeedTacticSupported: boolean;
isTextureFloat: boolean;
isDrawBuffers: boolean;
channelCount: number;
Expand Down
1 change: 1 addition & 0 deletions test/all.html
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@
<script type="module" src="issues/560-minification-madness.js"></script>
<script type="module" src="issues/564-boolean.js"></script>
<script type="module" src="issues/567-wrong-modulus.js"></script>
<script type="module" src="issues/585-inaccurate-lookups.js"></script>
<script type="module" src="issues/586-unable-to-resize.js"></script>
<script type="module" src="issues/91-create-kernel-map-array.js"></script>
<script type="module" src="issues/96-param-names.js"></script>
Expand Down
22 changes: 22 additions & 0 deletions test/internal/backend/gl-kernel.js
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ test('getVariablePrecisionString() when tactic is not set and texSize is within
lowFloatPrecision: { rangeMax: Math.log2(3 * 3) },
mediumFloatPrecision: { rangeMax: Math.log2(4 * 4) },
highFloatPrecision: { rangeMax: Math.log2(5 * 5) },
isSpeedTacticSupported: true,
}
}
};
Expand All @@ -144,6 +145,7 @@ test('getVariablePrecisionString() when tactic is not set and texSize is within
lowFloatPrecision: { rangeMax: Math.log2(3 * 3) },
mediumFloatPrecision: { rangeMax: Math.log2(4 * 4) },
highFloatPrecision: { rangeMax: Math.log2(5 * 5) },
isSpeedTacticSupported: true,
}
}
};
Expand All @@ -159,6 +161,7 @@ test('getVariablePrecisionString() when tactic is not set and texSize is within
lowFloatPrecision: { rangeMax: Math.log2(3 * 3) },
mediumFloatPrecision: { rangeMax: Math.log2(4 * 4) },
highFloatPrecision: { rangeMax: Math.log2(5 * 5) },
isSpeedTacticSupported: true,
}
}
};
Expand All @@ -174,6 +177,7 @@ test('getVariablePrecisionString() when tactic is not set and texSize is outside
lowFloatPrecision: { rangeMax: Math.log2(3 * 3) },
mediumFloatPrecision: { rangeMax: Math.log2(4 * 4) },
highFloatPrecision: { rangeMax: Math.log2(5 * 5) },
isSpeedTacticSupported: true,
}
}
};
Expand All @@ -189,6 +193,7 @@ test('getVariablePrecisionString() when tactic is not set and texSize is within
lowIntPrecision: { rangeMax: Math.log2(3 * 3) },
mediumIntPrecision: { rangeMax: Math.log2(4 * 4) },
highIntPrecision: { rangeMax: Math.log2(5 * 5) },
isSpeedTacticSupported: true,
}
}
};
Expand All @@ -204,6 +209,7 @@ test('getVariablePrecisionString() when tactic is not set and texSize is within
lowIntPrecision: { rangeMax: Math.log2(3 * 3) },
mediumIntPrecision: { rangeMax: Math.log2(4 * 4) },
highIntPrecision: { rangeMax: Math.log2(5 * 5) },
isSpeedTacticSupported: true,
}
}
};
Expand All @@ -219,6 +225,7 @@ test('getVariablePrecisionString() when tactic is not set and texSize is within
lowIntPrecision: { rangeMax: Math.log2(3 * 3) },
mediumIntPrecision: { rangeMax: Math.log2(4 * 4) },
highIntPrecision: { rangeMax: Math.log2(5 * 5) },
isSpeedTacticSupported: true,
}
}
};
Expand All @@ -234,20 +241,35 @@ test('getVariablePrecisionString() when tactic is not set and texSize is outside
lowIntPrecision: { rangeMax: Math.log2(3 * 3) },
mediumIntPrecision: { rangeMax: Math.log2(4 * 4) },
highIntPrecision: { rangeMax: Math.log2(5 * 5) },
isSpeedTacticSupported: true,
}
}
};
const textureSize = [6, 6];
assert.throws(() => GLKernel.prototype.getVariablePrecisionString.call(mockInstance, textureSize, null, true));
});

test('getVariablePrecisionString() when features.isSpeedTacticSupported is false returns "highp"', () => {
const mockInstance = {
tactic: null,
constructor: {
features: {
isSpeedTacticSupported: false,
}
}
};
const textureSize = [1, 1];
assert.equal(GLKernel.prototype.getVariablePrecisionString.call(mockInstance, textureSize, null, true), 'highp');
});

function testGetFeatures(canvas, context) {
const gpu = new GPU({ canvas, context });
const { Kernel } = gpu;
Kernel.setupFeatureChecks();
const features = Kernel.getFeatures();
assert.ok(typeof features.isFloatRead === 'boolean');
assert.ok(typeof features.isIntegerDivisionAccurate === 'boolean');
assert.ok(typeof features.isSpeedTacticSupported === 'boolean');
assert.ok(typeof features.isTextureFloat === 'boolean');
assert.ok(typeof features.isDrawBuffers === 'boolean');
assert.ok(typeof features.kernelMap === 'boolean');
Expand Down
45 changes: 45 additions & 0 deletions test/issues/585-inaccurate-lookups.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
const { assert, skip, test, module: describe, only } = require('qunit');
const { GPU } = require('../../src');

describe('issue #585 - inaccurate lookups');

function testResize(mode) {
const gpu = new GPU({ mode });
const kernel = gpu.createKernel(function(value) {
return value[this.thread.x];
}, {
output: [4],
});

const result = kernel([0,1,2,3]);
console.log(result);
assert.equal(Math.round(result[0]), 0);
assert.equal(Math.round(result[1]), 1);
assert.equal(Math.round(result[2]), 2);
assert.equal(Math.round(result[3]), 3);
gpu.destroy();
}

test('auto', () => {
testResize();
});

test('gpu', () => {
testResize('gpu');
});

(GPU.isWebGLSupported ? test : skip)('webgl', () => {
testResize('webgl');
});

(GPU.isWebGL2Supported ? test : skip)('webgl2', () => {
testResize('webgl2');
});

(GPU.isHeadlessGLSupported ? test : skip)('headlessgl', () => {
testResize('headlessgl');
});

test('cpu', () => {
testResize('cpu');
});

0 comments on commit 7e62639

Please sign in to comment.