@kitware/vtk.js 19.3.0 → 19.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Common/Core/HalfFloat.d.ts +24 -0
- package/Common/Core/HalfFloat.js +80 -0
- package/Common/Core.js +2 -0
- package/README.md +1 -1
- package/Rendering/WebGPU/Texture.js +17 -8
- package/Rendering/WebGPU/TextureManager.js +4 -1
- package/Rendering/WebGPU/VolumePassFSQ.js +17 -6
- package/Utilities/TestResults/TESTS-Chrome_Headless_93.0.4577.82_(Linux_x86_64).xml +2251 -0
- package/Utilities/config/rules-examples.js +1 -1
- package/Utilities/config/rules-tests.js +9 -2
- package/Utilities/config/rules-vtk.js +1 -1
- package/package.json +2 -4
- package/Utilities/TestResults/TESTS-Chrome_Headless_93.0.4577.63_(Linux_x86_64).xml +0 -2251
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helper class to convert to/from half float
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Convert a number to half float representation
|
|
7
|
+
* @param {number} input
|
|
8
|
+
* @return encoded half float number (16 bits)
|
|
9
|
+
*/
|
|
10
|
+
export function toHalf(input: number): number;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Convert a half float representation to a number
|
|
14
|
+
* @param {number} input
|
|
15
|
+
* @return decoded half float number
|
|
16
|
+
*/
|
|
17
|
+
export function fromHalf(input: number): number;
|
|
18
|
+
|
|
19
|
+
export declare const HalfFloat: {
|
|
20
|
+
toHalf: typeof toHalf;
|
|
21
|
+
fromHalf: typeof fromHalf;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export default HalfFloat;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/* eslint-disable no-bitwise */
|
|
2
|
+
var floatView = new Float32Array(1);
|
|
3
|
+
var int32View = new Int32Array(floatView.buffer);
|
|
4
|
+
/* eslint-disable no-bitwise */
|
|
5
|
+
|
|
6
|
+
/* This method is faster than the OpenEXR implementation (very often
|
|
7
|
+
* used, eg. in Ogre), with the additional benefit of rounding, inspired
|
|
8
|
+
* by James Tursa?s half-precision code. */
|
|
9
|
+
|
|
10
|
+
function toHalf(val) {
|
|
11
|
+
floatView[0] = val;
|
|
12
|
+
var x = int32View[0];
|
|
13
|
+
var bits = x >> 16 & 0x8000;
|
|
14
|
+
/* Get the sign */
|
|
15
|
+
|
|
16
|
+
var m = x >> 12 & 0x07ff;
|
|
17
|
+
/* Keep one extra bit for rounding */
|
|
18
|
+
|
|
19
|
+
var e = x >> 23 & 0xff;
|
|
20
|
+
/* Using int is faster here */
|
|
21
|
+
|
|
22
|
+
/* If zero, or denormal, or exponent underflows too much for a denormal
|
|
23
|
+
* half, return signed zero. */
|
|
24
|
+
|
|
25
|
+
if (e < 103) {
|
|
26
|
+
return bits;
|
|
27
|
+
}
|
|
28
|
+
/* If NaN, return NaN. If Inf or exponent overflow, return Inf. */
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
if (e > 142) {
|
|
32
|
+
bits |= 0x7c00;
|
|
33
|
+
/* If exponent was 0xff and one mantissa bit was set, it means NaN,
|
|
34
|
+
* not Inf, so make sure we set one mantissa bit too. */
|
|
35
|
+
|
|
36
|
+
bits |= (e === 255 ? 0 : 1) && x & 0x007fffff;
|
|
37
|
+
return bits;
|
|
38
|
+
}
|
|
39
|
+
/* If exponent underflows but not too much, return a denormal */
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
if (e < 113) {
|
|
43
|
+
m |= 0x0800;
|
|
44
|
+
/* Extra rounding may overflow and set mantissa to 0 and exponent
|
|
45
|
+
* to 1, which is OK. */
|
|
46
|
+
|
|
47
|
+
bits |= (m >> 114 - e) + (m >> 113 - e & 1);
|
|
48
|
+
return bits;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
bits |= e - 112 << 10 | m >> 1;
|
|
52
|
+
/* Extra rounding. An overflow will set mantissa to 0 and increment
|
|
53
|
+
* the exponent, which is OK. */
|
|
54
|
+
|
|
55
|
+
bits += m & 1;
|
|
56
|
+
return bits;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function fromHalf(h) {
|
|
60
|
+
var s = (h & 0x8000) >> 15;
|
|
61
|
+
var e = (h & 0x7c00) >> 10;
|
|
62
|
+
var f = h & 0x03ff;
|
|
63
|
+
|
|
64
|
+
if (e === 0) {
|
|
65
|
+
return (s ? -1 : 1) * Math.pow(2, -14) * (f / Math.pow(2, 10));
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (e === 0x1f) {
|
|
69
|
+
return f ? NaN : (s ? -1 : 1) * Infinity;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return (s ? -1 : 1) * Math.pow(2, e - 15) * (1 + f / Math.pow(2, 10));
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
var HalfFloat = {
|
|
76
|
+
fromHalf: fromHalf,
|
|
77
|
+
toHalf: toHalf
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
export { HalfFloat as default };
|
package/Common/Core.js
CHANGED
|
@@ -2,6 +2,7 @@ import Base64 from './Core/Base64.js';
|
|
|
2
2
|
import vtkCellArray from './Core/CellArray.js';
|
|
3
3
|
import vtkDataArray from './Core/DataArray.js';
|
|
4
4
|
import Endian from './Core/Endian.js';
|
|
5
|
+
import HalfFloat from './Core/HalfFloat.js';
|
|
5
6
|
import ImageHelper from './Core/ImageHelper.js';
|
|
6
7
|
import vtkLookupTable from './Core/LookupTable.js';
|
|
7
8
|
import { v as vtkMath } from './Core/Math/index.js';
|
|
@@ -18,6 +19,7 @@ var Core = {
|
|
|
18
19
|
vtkCellArray: vtkCellArray,
|
|
19
20
|
vtkDataArray: vtkDataArray,
|
|
20
21
|
vtkEndian: Endian,
|
|
22
|
+
vtkHalfFloat: HalfFloat,
|
|
21
23
|
vtkImageHelper: ImageHelper,
|
|
22
24
|
vtkLookupTable: vtkLookupTable,
|
|
23
25
|
vtkMath: vtkMath,
|
package/README.md
CHANGED
|
@@ -48,7 +48,7 @@ In general VTK tries to be as portable as possible; the specific configurations
|
|
|
48
48
|
|
|
49
49
|
vtk.js supports the following development environments:
|
|
50
50
|
|
|
51
|
-
- Node
|
|
51
|
+
- Node 12+
|
|
52
52
|
- NPM 6+
|
|
53
53
|
|
|
54
54
|
and we use [@babel/preset-env](https://www.npmjs.com/package/@babel/preset-env) with the [defaults](https://github.com/Kitware/vtk-js/blob/master/.browserslistrc) set of [browsers target](https://browserl.ist/?q=defaults).
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import macro from '../../macros.js';
|
|
2
|
+
import HalfFloat from '../../Common/Core/HalfFloat.js';
|
|
2
3
|
import vtkWebGPUBufferManager from './BufferManager.js';
|
|
3
4
|
import vtkWebGPUTextureView from './TextureView.js';
|
|
4
5
|
import vtkWebGPUTypes from './Types.js';
|
|
@@ -79,20 +80,28 @@ function vtkWebGPUTexture(publicAPI, model) {
|
|
|
79
80
|
// the data here before passing to the buffer. e.g. if it is unorm8x4 then
|
|
80
81
|
// we need to have width be a multiple of 64
|
|
81
82
|
|
|
82
|
-
var currWidthInBytes = model.width * tDetails.stride;
|
|
83
|
+
var currWidthInBytes = model.width * tDetails.stride; // is this a half float texture?
|
|
83
84
|
|
|
84
|
-
if
|
|
85
|
-
|
|
85
|
+
var halfFloat = tDetails.elementSize === 2 && tDetails.sampleType === 'float'; // if we need to copy the data
|
|
86
|
+
|
|
87
|
+
if (halfFloat || currWidthInBytes % 256) {
|
|
88
|
+
var inArray = req.nativeArray;
|
|
86
89
|
var bufferWidthInBytes = 256 * Math.floor((currWidthInBytes + 255) / 256);
|
|
87
|
-
var bufferWidth = bufferWidthInBytes /
|
|
88
|
-
var
|
|
89
|
-
var
|
|
90
|
+
var bufferWidth = bufferWidthInBytes / tDetails.elementSize;
|
|
91
|
+
var inWidth = currWidthInBytes / inArray.BYTES_PER_ELEMENT;
|
|
92
|
+
var outArray = macro.newTypedArray(halfFloat ? 'Uint16Array' : inArray.name, bufferWidth * model.height * model.depth);
|
|
90
93
|
|
|
91
94
|
for (var v = 0; v < model.height * model.depth; v++) {
|
|
92
|
-
|
|
95
|
+
if (halfFloat) {
|
|
96
|
+
for (var i = 0; i < inWidth; i++) {
|
|
97
|
+
outArray[v * bufferWidth + i] = HalfFloat.toHalf(inArray[v * inWidth + i]);
|
|
98
|
+
}
|
|
99
|
+
} else {
|
|
100
|
+
outArray.set(inArray.subarray(v * inWidth, (v + 1) * inWidth), v * bufferWidth);
|
|
101
|
+
}
|
|
93
102
|
}
|
|
94
103
|
|
|
95
|
-
buffRequest.nativeArray =
|
|
104
|
+
buffRequest.nativeArray = outArray;
|
|
96
105
|
bufferBytesPerRow = bufferWidthInBytes;
|
|
97
106
|
}
|
|
98
107
|
|
|
@@ -58,6 +58,8 @@ function vtkWebGPUTextureManager(publicAPI, model) {
|
|
|
58
58
|
case VtkDataTypes.UNSIGNED_CHAR:
|
|
59
59
|
req.format += '8unorm';
|
|
60
60
|
break;
|
|
61
|
+
// todo extend to other types that are not filterable
|
|
62
|
+
// as they can be useful
|
|
61
63
|
|
|
62
64
|
case VtkDataTypes.FLOAT:
|
|
63
65
|
case VtkDataTypes.UNSIGNED_INT:
|
|
@@ -66,7 +68,8 @@ function vtkWebGPUTextureManager(publicAPI, model) {
|
|
|
66
68
|
case VtkDataTypes.UNSIGNED_SHORT:
|
|
67
69
|
case VtkDataTypes.SHORT:
|
|
68
70
|
default:
|
|
69
|
-
|
|
71
|
+
req.format += '16float';
|
|
72
|
+
break;
|
|
70
73
|
}
|
|
71
74
|
} // fill in values based on image if the request has it
|
|
72
75
|
|
|
@@ -5,6 +5,7 @@ import vtkWebGPUUniformBuffer from './UniformBuffer.js';
|
|
|
5
5
|
import vtkWebGPUShaderCache from './ShaderCache.js';
|
|
6
6
|
import vtkWebGPUStorageBuffer from './StorageBuffer.js';
|
|
7
7
|
import vtkWebGPUSampler from './Sampler.js';
|
|
8
|
+
import vtkWebGPUTypes from './Types.js';
|
|
8
9
|
import { BlendMode } from '../Core/VolumeMapper/Constants.js';
|
|
9
10
|
import { i as identity, t as translate, j as transpose, g as invert, m as multiply, s as scale } from '../../vendor/gl-matrix/esm/mat4.js';
|
|
10
11
|
|
|
@@ -240,8 +241,7 @@ function vtkWebGPUVolumePassFSQ(publicAPI, model) {
|
|
|
240
241
|
|
|
241
242
|
var modelToIndex = _image3.getWorldToIndex();
|
|
242
243
|
|
|
243
|
-
|
|
244
|
-
multiply(tmpMat4, tmp2Mat4, tmpMat4); // tmpMat4 is now SC -> Index
|
|
244
|
+
multiply(tmpMat4, modelToIndex, tmpMat4); // tmpMat4 is now SC -> Index
|
|
245
245
|
|
|
246
246
|
var dims = _image3.getDimensions();
|
|
247
247
|
|
|
@@ -301,13 +301,23 @@ function vtkWebGPUVolumePassFSQ(publicAPI, model) {
|
|
|
301
301
|
|
|
302
302
|
var numComp = scalars.getNumberOfComponents();
|
|
303
303
|
var iComps = vprop.getIndependentComponents(); // const numIComps = iComps ? numComp : 1;
|
|
304
|
+
// half float
|
|
304
305
|
|
|
306
|
+
var tformat = model.textureViews[_vidx2 + 4].getTexture().getFormat();
|
|
307
|
+
|
|
308
|
+
var tDetails = vtkWebGPUTypes.getDetailsFromTextureFormat(tformat);
|
|
309
|
+
var halfFloat = tDetails.elementSize === 2 && tDetails.sampleType === 'float';
|
|
305
310
|
var volInfo = {
|
|
306
311
|
scale: [255.0],
|
|
307
312
|
offset: [0.0]
|
|
308
|
-
};
|
|
313
|
+
};
|
|
314
|
+
|
|
315
|
+
if (halfFloat) {
|
|
316
|
+
volInfo.scale[0] = 1.0;
|
|
317
|
+
} // three levels of shift scale combined into one
|
|
309
318
|
// for performance in the fragment shader
|
|
310
319
|
|
|
320
|
+
|
|
311
321
|
for (var compIdx = 0; compIdx < numComp; compIdx++) {
|
|
312
322
|
var target = iComps ? compIdx : 0;
|
|
313
323
|
var sscale = volInfo.scale[compIdx];
|
|
@@ -381,10 +391,8 @@ function vtkWebGPUVolumePassFSQ(publicAPI, model) {
|
|
|
381
391
|
model.sampleDist = sampleDist;
|
|
382
392
|
model.UBO.setValue('SampleDistance', sampleDist);
|
|
383
393
|
model.UBO.sendIfNeeded(device);
|
|
384
|
-
}
|
|
394
|
+
} // add in 3d volume textures
|
|
385
395
|
|
|
386
|
-
publicAPI.updateLUTImage(device);
|
|
387
|
-
publicAPI.updateSSBO(device); // add in 3d volume textures
|
|
388
396
|
|
|
389
397
|
for (var vidx = 0; vidx < model.volumes.length; vidx++) {
|
|
390
398
|
var webgpuvol = model.volumes[vidx];
|
|
@@ -406,6 +414,9 @@ function vtkWebGPUVolumePassFSQ(publicAPI, model) {
|
|
|
406
414
|
model.textureViews[vidx + 4] = tview;
|
|
407
415
|
}
|
|
408
416
|
}
|
|
417
|
+
|
|
418
|
+
publicAPI.updateLUTImage(device);
|
|
419
|
+
publicAPI.updateSSBO(device);
|
|
409
420
|
};
|
|
410
421
|
|
|
411
422
|
publicAPI.computePipelineHash = function () {
|