Skip to content

Commit db54434

Browse files
fix: Modulo performance and simplify tests
fix: Modulo negatives fix: Modulo accuracy issue on OSX with `integerCorrectionModulo` fix: Follow naming convention `div_with_int_check` to `divWithIntCheck` fix: Member expression with function fix: CPU variable assignment fix: `gpu.addFunction` needed to be before createKernel and documentation fix: mandelbulb.html from above .addFunction
1 parent 16bed15 commit db54434

File tree

16 files changed

+221
-112
lines changed

16 files changed

+221
-112
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -668,7 +668,7 @@ This gives you the flexibility of using parts of a single transformation without
668668

669669
## Adding custom functions
670670
### To `GPU` instance
671-
use `gpu.addFunction(function() {}, settings)` for adding custom functions to all kernels. Example:
671+
use `gpu.addFunction(function() {}, settings)` for adding custom functions to all kernels. Needs to be called BEFORE `gpu.createKernel`. Example:
672672

673673

674674
```js

dist/gpu-browser-core.js

Lines changed: 47 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
*
55
* GPU Accelerated JavaScript
66
*
7-
* @version 2.6.2
8-
* @date Sun Jan 19 2020 07:44:58 GMT-0500 (Eastern Standard Time)
7+
* @version 2.6.3
8+
* @date Tue Jan 21 2020 07:26:16 GMT-0500 (Eastern Standard Time)
99
*
1010
* @license MIT
1111
* The MIT License
@@ -896,7 +896,12 @@ class CPUFunctionNode extends FunctionNode {
896896
if (i > 0) {
897897
retArr.push(',');
898898
}
899-
this.astGeneric(declarations[i], retArr);
899+
const declaration = declarations[i];
900+
const info = this.getDeclaration(declaration.id);
901+
if (!info.valueType) {
902+
info.valueType = this.getType(declaration.init);
903+
}
904+
this.astGeneric(declaration, retArr);
900905
}
901906
if (!this.isState('in-for-loop-init')) {
902907
retArr.push(';');
@@ -6915,18 +6920,18 @@ void color(sampler2D image) {
69156920
actualColor = texture2D(image, vTexCoord);
69166921
}
69176922
6918-
float modulo(float num1, float num2) {
6919-
if (num2 == 0.0) {
6920-
return 0.0;
6923+
float modulo(float number, float divisor) {
6924+
if (number < 0.0) {
6925+
number = abs(number);
6926+
if (divisor < 0.0) {
6927+
divisor = abs(divisor);
6928+
}
6929+
return -mod(number, divisor);
69216930
}
6922-
bool isPositive = num1 >= 0.0;
6923-
num1 = abs(num1);
6924-
num2 = abs(num2);
6925-
for (int i = 0; i < LOOP_MAX; i++) {
6926-
if (num1 < num2) break;
6927-
num1 = num1 - num2;
6931+
if (divisor < 0.0) {
6932+
divisor = abs(divisor);
69286933
}
6929-
return isPositive ? num1 : -num1;
6934+
return mod(number, divisor);
69306935
}
69316936
69326937
__INJECTED_NATIVE__;
@@ -7157,7 +7162,7 @@ class WebGLFunctionNode extends FunctionNode {
71577162
}
71587163

71597164
if (this.fixIntegerDivisionAccuracy && ast.operator === '/') {
7160-
retArr.push('div_with_int_check(');
7165+
retArr.push('divWithIntCheck(');
71617166
this.pushState('building-float');
71627167
switch (this.getType(ast.left)) {
71637168
case 'Integer':
@@ -7338,7 +7343,7 @@ class WebGLFunctionNode extends FunctionNode {
73387343
return bitwiseResult;
73397344
}
73407345
const upconvertableOperators = {
7341-
'%': 'modulo',
7346+
'%': this.fixIntegerDivisionAccuracy ? 'integerCorrectionModulo' : 'modulo',
73427347
'**': 'pow',
73437348
};
73447349
const foundOperator = upconvertableOperators[ast.operator];
@@ -8221,7 +8226,7 @@ class WebGLFunctionNode extends FunctionNode {
82218226
if (targetType === argumentType) {
82228227
if (argument.type === 'Identifier') {
82238228
retArr.push(`user_${argument.name}`);
8224-
} else if (argument.type === 'ArrayExpression') {
8229+
} else if (argument.type === 'ArrayExpression' || argument.type === 'MemberExpression') {
82258230
this.astGeneric(argument, retArr);
82268231
} else {
82278232
throw this.astErrorOutput(`Unhandled argument type ${ argument.type }`, ast);
@@ -10572,11 +10577,25 @@ class WebGLKernel extends GLKernel {
1057210577

1057310578
_getDivideWithIntegerCheckString() {
1057410579
return this.fixIntegerDivisionAccuracy ?
10575-
`float div_with_int_check(float x, float y) {
10580+
`float divWithIntCheck(float x, float y) {
1057610581
if (floor(x) == x && floor(y) == y && integerMod(x, y) == 0.0) {
10577-
return float(int(x)/int(y));
10582+
return float(int(x) / int(y));
1057810583
}
1057910584
return x / y;
10585+
}
10586+
10587+
float integerCorrectionModulo(float number, float divisor) {
10588+
if (number < 0.0) {
10589+
number = abs(number);
10590+
if (divisor < 0.0) {
10591+
divisor = abs(divisor);
10592+
}
10593+
return -(number - (divisor * floor(divWithIntCheck(number, divisor))));
10594+
}
10595+
if (divisor < 0.0) {
10596+
divisor = abs(divisor);
10597+
}
10598+
return number - (divisor * floor(divWithIntCheck(number, divisor)));
1058010599
}` :
1058110600
'';
1058210601
}
@@ -11416,18 +11435,18 @@ void color(float r, float g, float b) {
1141611435
color(r,g,b,1.0);
1141711436
}
1141811437
11419-
float modulo(float num1, float num2) {
11420-
if (num2 == 0.0) {
11421-
return 0.0;
11438+
float modulo(float number, float divisor) {
11439+
if (number < 0.0) {
11440+
number = abs(number);
11441+
if (divisor < 0.0) {
11442+
divisor = abs(divisor);
11443+
}
11444+
return -mod(number, divisor);
1142211445
}
11423-
bool isPositive = num1 >= 0.0;
11424-
num1 = abs(num1);
11425-
num2 = abs(num2);
11426-
for (int i = 0; i < LOOP_MAX; i++) {
11427-
if (num1 < num2) break;
11428-
num1 = num1 - num2;
11446+
if (divisor < 0.0) {
11447+
divisor = abs(divisor);
1142911448
}
11430-
return isPositive ? num1 : -num1;
11449+
return mod(number, divisor);
1143111450
}
1143211451
1143311452
__INJECTED_NATIVE__;

dist/gpu-browser-core.min.js

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/gpu-browser.js

Lines changed: 47 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
*
55
* GPU Accelerated JavaScript
66
*
7-
* @version 2.6.2
8-
* @date Sun Jan 19 2020 07:44:57 GMT-0500 (Eastern Standard Time)
7+
* @version 2.6.3
8+
* @date Tue Jan 21 2020 07:26:16 GMT-0500 (Eastern Standard Time)
99
*
1010
* @license MIT
1111
* The MIT License
@@ -5330,7 +5330,12 @@ class CPUFunctionNode extends FunctionNode {
53305330
if (i > 0) {
53315331
retArr.push(',');
53325332
}
5333-
this.astGeneric(declarations[i], retArr);
5333+
const declaration = declarations[i];
5334+
const info = this.getDeclaration(declaration.id);
5335+
if (!info.valueType) {
5336+
info.valueType = this.getType(declaration.init);
5337+
}
5338+
this.astGeneric(declaration, retArr);
53345339
}
53355340
if (!this.isState('in-for-loop-init')) {
53365341
retArr.push(';');
@@ -11349,18 +11354,18 @@ void color(sampler2D image) {
1134911354
actualColor = texture2D(image, vTexCoord);
1135011355
}
1135111356

11352-
float modulo(float num1, float num2) {
11353-
if (num2 == 0.0) {
11354-
return 0.0;
11357+
float modulo(float number, float divisor) {
11358+
if (number < 0.0) {
11359+
number = abs(number);
11360+
if (divisor < 0.0) {
11361+
divisor = abs(divisor);
11362+
}
11363+
return -mod(number, divisor);
1135511364
}
11356-
bool isPositive = num1 >= 0.0;
11357-
num1 = abs(num1);
11358-
num2 = abs(num2);
11359-
for (int i = 0; i < LOOP_MAX; i++) {
11360-
if (num1 < num2) break;
11361-
num1 = num1 - num2;
11365+
if (divisor < 0.0) {
11366+
divisor = abs(divisor);
1136211367
}
11363-
return isPositive ? num1 : -num1;
11368+
return mod(number, divisor);
1136411369
}
1136511370

1136611371
__INJECTED_NATIVE__;
@@ -11591,7 +11596,7 @@ class WebGLFunctionNode extends FunctionNode {
1159111596
}
1159211597

1159311598
if (this.fixIntegerDivisionAccuracy && ast.operator === '/') {
11594-
retArr.push('div_with_int_check(');
11599+
retArr.push('divWithIntCheck(');
1159511600
this.pushState('building-float');
1159611601
switch (this.getType(ast.left)) {
1159711602
case 'Integer':
@@ -11772,7 +11777,7 @@ class WebGLFunctionNode extends FunctionNode {
1177211777
return bitwiseResult;
1177311778
}
1177411779
const upconvertableOperators = {
11775-
'%': 'modulo',
11780+
'%': this.fixIntegerDivisionAccuracy ? 'integerCorrectionModulo' : 'modulo',
1177611781
'**': 'pow',
1177711782
};
1177811783
const foundOperator = upconvertableOperators[ast.operator];
@@ -12655,7 +12660,7 @@ class WebGLFunctionNode extends FunctionNode {
1265512660
if (targetType === argumentType) {
1265612661
if (argument.type === 'Identifier') {
1265712662
retArr.push(`user_${argument.name}`);
12658-
} else if (argument.type === 'ArrayExpression') {
12663+
} else if (argument.type === 'ArrayExpression' || argument.type === 'MemberExpression') {
1265912664
this.astGeneric(argument, retArr);
1266012665
} else {
1266112666
throw this.astErrorOutput(`Unhandled argument type ${ argument.type }`, ast);
@@ -15006,11 +15011,25 @@ class WebGLKernel extends GLKernel {
1500615011

1500715012
_getDivideWithIntegerCheckString() {
1500815013
return this.fixIntegerDivisionAccuracy ?
15009-
`float div_with_int_check(float x, float y) {
15014+
`float divWithIntCheck(float x, float y) {
1501015015
if (floor(x) == x && floor(y) == y && integerMod(x, y) == 0.0) {
15011-
return float(int(x)/int(y));
15016+
return float(int(x) / int(y));
1501215017
}
1501315018
return x / y;
15019+
}
15020+
15021+
float integerCorrectionModulo(float number, float divisor) {
15022+
if (number < 0.0) {
15023+
number = abs(number);
15024+
if (divisor < 0.0) {
15025+
divisor = abs(divisor);
15026+
}
15027+
return -(number - (divisor * floor(divWithIntCheck(number, divisor))));
15028+
}
15029+
if (divisor < 0.0) {
15030+
divisor = abs(divisor);
15031+
}
15032+
return number - (divisor * floor(divWithIntCheck(number, divisor)));
1501415033
}` :
1501515034
'';
1501615035
}
@@ -15850,18 +15869,18 @@ void color(float r, float g, float b) {
1585015869
color(r,g,b,1.0);
1585115870
}
1585215871

15853-
float modulo(float num1, float num2) {
15854-
if (num2 == 0.0) {
15855-
return 0.0;
15872+
float modulo(float number, float divisor) {
15873+
if (number < 0.0) {
15874+
number = abs(number);
15875+
if (divisor < 0.0) {
15876+
divisor = abs(divisor);
15877+
}
15878+
return -mod(number, divisor);
1585615879
}
15857-
bool isPositive = num1 >= 0.0;
15858-
num1 = abs(num1);
15859-
num2 = abs(num2);
15860-
for (int i = 0; i < LOOP_MAX; i++) {
15861-
if (num1 < num2) break;
15862-
num1 = num1 - num2;
15880+
if (divisor < 0.0) {
15881+
divisor = abs(divisor);
1586315882
}
15864-
return isPositive ? num1 : -num1;
15883+
return mod(number, divisor);
1586515884
}
1586615885

1586715886
__INJECTED_NATIVE__;

dist/gpu-browser.min.js

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

examples/mandelbulb.html

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,7 @@ <h1>Mandelbulb - Real-time 3d fractal<br> in Javascript</h1>
336336

337337
let m = v-c;
338338

339-
return [r+m,g+m,b+m]
339+
return [r+m,g+m,b+m];
340340
}
341341

342342
// x,y,z - point on ray (marching)
@@ -432,18 +432,17 @@ <h1>Mandelbulb - Real-time 3d fractal<br> in Javascript</h1>
432432
document.addEventListener('pointerlockchange', lockChange, false);
433433

434434
const gl = canvas.getContext('webgl2', { premultipliedAlpha: false });
435-
const gpu = new GPU({ canvas, webGl: gl });
436-
437-
const raytracer = gpu.createKernel(kernelMarchingRays)
435+
const gpu = new GPU({ canvas, webGl: gl })
436+
.addFunction(sdPlane)
437+
.addFunction(mandelbulb)
438+
.addFunction(distScene)
439+
.addFunction(hsv2rgb);
440+
return gpu.createKernel(kernelMarchingRays)
441+
.setDebug(true)
438442
.setConstants({ pxWidth, pxHeight, iterations: 100 })
439443
.setOutput([pxWidth, pxHeight])
440444
.setGraphical(true)
441445
.setLoopMaxIterations(10000);
442-
gpu.addFunction(sdPlane);
443-
gpu.addFunction(mandelbulb);
444-
gpu.addFunction(distScene);
445-
gpu.addFunction(hsv2rgb);
446-
return raytracer;
447446
}
448447

449448
// ----------------------------------------------------

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "gpu.js",
3-
"version": "2.6.2",
3+
"version": "2.6.3",
44
"description": "GPU Accelerated JavaScript",
55
"engines": {
66
"node": ">=8.0.0"

src/backend/cpu/function-node.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,12 @@ class CPUFunctionNode extends FunctionNode {
326326
if (i > 0) {
327327
retArr.push(',');
328328
}
329-
this.astGeneric(declarations[i], retArr);
329+
const declaration = declarations[i];
330+
const info = this.getDeclaration(declaration.id);
331+
if (!info.valueType) {
332+
info.valueType = this.getType(declaration.init);
333+
}
334+
this.astGeneric(declaration, retArr);
330335
}
331336
if (!this.isState('in-for-loop-init')) {
332337
retArr.push(';');

src/backend/web-gl/fragment-shader.js

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -392,18 +392,18 @@ void color(sampler2D image) {
392392
actualColor = texture2D(image, vTexCoord);
393393
}
394394
395-
float modulo(float num1, float num2) {
396-
if (num2 == 0.0) {
397-
return 0.0;
395+
float modulo(float number, float divisor) {
396+
if (number < 0.0) {
397+
number = abs(number);
398+
if (divisor < 0.0) {
399+
divisor = abs(divisor);
400+
}
401+
return -mod(number, divisor);
398402
}
399-
bool isPositive = num1 >= 0.0;
400-
num1 = abs(num1);
401-
num2 = abs(num2);
402-
for (int i = 0; i < LOOP_MAX; i++) {
403-
if (num1 < num2) break;
404-
num1 = num1 - num2;
403+
if (divisor < 0.0) {
404+
divisor = abs(divisor);
405405
}
406-
return isPositive ? num1 : -num1;
406+
return mod(number, divisor);
407407
}
408408
409409
__INJECTED_NATIVE__;

src/backend/web-gl/function-node.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ class WebGLFunctionNode extends FunctionNode {
253253
}
254254

255255
if (this.fixIntegerDivisionAccuracy && ast.operator === '/') {
256-
retArr.push('div_with_int_check(');
256+
retArr.push('divWithIntCheck(');
257257
this.pushState('building-float');
258258
switch (this.getType(ast.left)) {
259259
case 'Integer':
@@ -435,7 +435,7 @@ class WebGLFunctionNode extends FunctionNode {
435435
return bitwiseResult;
436436
}
437437
const upconvertableOperators = {
438-
'%': 'modulo',
438+
'%': this.fixIntegerDivisionAccuracy ? 'integerCorrectionModulo' : 'modulo',
439439
'**': 'pow',
440440
};
441441
const foundOperator = upconvertableOperators[ast.operator];
@@ -1432,7 +1432,7 @@ class WebGLFunctionNode extends FunctionNode {
14321432
if (targetType === argumentType) {
14331433
if (argument.type === 'Identifier') {
14341434
retArr.push(`user_${argument.name}`);
1435-
} else if (argument.type === 'ArrayExpression') {
1435+
} else if (argument.type === 'ArrayExpression' || argument.type === 'MemberExpression') {
14361436
this.astGeneric(argument, retArr);
14371437
} else {
14381438
throw this.astErrorOutput(`Unhandled argument type ${ argument.type }`, ast);

0 commit comments

Comments
 (0)