@kitware/vtk.js 34.0.0-beta.1 → 34.0.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/IO/Geometry/GLTFImporter/Decoder.js +35 -21
- package/IO/Geometry/GLTFImporter/Parser.js +15 -6
- package/IO/Geometry/GLTFImporter/Reader.js +7 -10
- package/IO/Geometry/GLTFImporter/Utils.js +9 -27
- package/Rendering/Core/Texture.d.ts +81 -29
- package/Rendering/Core/Texture.js +171 -86
- package/Rendering/WebGPU/CellArrayMapper.js +139 -199
- package/Rendering/WebGPU/PolyDataMapper.js +35 -15
- package/Rendering/WebGPU/Renderer.js +1 -1
- package/Rendering/WebGPU/Texture.js +106 -97
- package/Rendering/WebGPU/TextureManager.js +37 -6
- package/package.json +1 -1
- package/IO/Geometry/GLTFImporter/ORMTexture.worker.js +0 -42
- package/_virtual/rollup-plugin-worker-loader__module_Sources/IO/Geometry/GLTFImporter/ORMTexture.worker.js +0 -296
|
@@ -1,14 +1,9 @@
|
|
|
1
1
|
import { m as macro } from '../../macros2.js';
|
|
2
2
|
import HalfFloat from '../../Common/Core/HalfFloat.js';
|
|
3
|
-
import vtkWebGPUBufferManager from './BufferManager.js';
|
|
4
3
|
import vtkWebGPUTextureView from './TextureView.js';
|
|
5
4
|
import vtkWebGPUTypes from './Types.js';
|
|
6
5
|
import vtkTexture from '../Core/Texture.js';
|
|
7
6
|
|
|
8
|
-
const {
|
|
9
|
-
BufferUsage
|
|
10
|
-
} = vtkWebGPUBufferManager;
|
|
11
|
-
|
|
12
7
|
// ----------------------------------------------------------------------------
|
|
13
8
|
// Global methods
|
|
14
9
|
// ----------------------------------------------------------------------------
|
|
@@ -59,127 +54,141 @@ function vtkWebGPUTexture(publicAPI, model) {
|
|
|
59
54
|
|
|
60
55
|
publicAPI.writeImageData = req => {
|
|
61
56
|
let nativeArray = [];
|
|
62
|
-
|
|
57
|
+
const _copyImageToTexture = source => {
|
|
63
58
|
model.device.getHandle().queue.copyExternalImageToTexture({
|
|
64
|
-
source
|
|
59
|
+
source,
|
|
65
60
|
flipY: req.flip
|
|
66
61
|
}, {
|
|
67
62
|
texture: model.handle,
|
|
68
|
-
premultipliedAlpha: true
|
|
69
|
-
|
|
63
|
+
premultipliedAlpha: true,
|
|
64
|
+
mipLevel: 0,
|
|
65
|
+
origin: {
|
|
66
|
+
x: 0,
|
|
67
|
+
y: 0,
|
|
68
|
+
z: 0
|
|
69
|
+
}
|
|
70
|
+
}, [source.width, source.height, model.depth]);
|
|
71
|
+
|
|
72
|
+
// Generate mipmaps on GPU if needed
|
|
73
|
+
if (publicAPI.getDimensionality() !== 3 && model.mipLevel > 0) {
|
|
74
|
+
vtkTexture.generateMipmaps(model.device.getHandle(), model.handle, model.mipLevel + 1);
|
|
75
|
+
}
|
|
70
76
|
model.ready = true;
|
|
77
|
+
};
|
|
78
|
+
if (req.canvas) {
|
|
79
|
+
_copyImageToTexture(req.canvas);
|
|
71
80
|
return;
|
|
72
81
|
}
|
|
73
|
-
if (req.
|
|
82
|
+
if (req.imageBitmap) {
|
|
83
|
+
req.width = req.imageBitmap.width;
|
|
84
|
+
req.height = req.imageBitmap.height;
|
|
85
|
+
req.depth = 1;
|
|
86
|
+
req.format = 'rgba8unorm';
|
|
87
|
+
req.flip = true;
|
|
88
|
+
_copyImageToTexture(req.imageBitmap);
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
if (req.jsImageData) {
|
|
74
92
|
req.width = req.jsImageData.width;
|
|
75
93
|
req.height = req.jsImageData.height;
|
|
76
94
|
req.depth = 1;
|
|
77
95
|
req.format = 'rgba8unorm';
|
|
78
96
|
req.flip = true;
|
|
79
|
-
req.
|
|
97
|
+
_copyImageToTexture(req.jsImageData);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
if (req.image) {
|
|
101
|
+
req.width = req.image.width;
|
|
102
|
+
req.height = req.image.height;
|
|
103
|
+
req.depth = 1;
|
|
104
|
+
req.format = 'rgba8unorm';
|
|
105
|
+
req.flip = true;
|
|
106
|
+
_copyImageToTexture(req.image);
|
|
107
|
+
return;
|
|
80
108
|
}
|
|
81
109
|
const tDetails = vtkWebGPUTypes.getDetailsFromTextureFormat(model.format);
|
|
82
110
|
let bufferBytesPerRow = model.width * tDetails.stride;
|
|
83
|
-
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Align texture data to ensure bytesPerRow is a multiple of 256.
|
|
114
|
+
* This is necessary for WebGPU texture uploads, especially for half-float formats.
|
|
115
|
+
* It also handles half-float conversion if the texture format requires it.
|
|
116
|
+
* @param {*} arr - The input array containing texture data.
|
|
117
|
+
* @param {*} height - The height of the texture.
|
|
118
|
+
* @param {*} depth - The depth of the texture (1 for 2D textures).
|
|
119
|
+
* @returns
|
|
120
|
+
*/
|
|
121
|
+
const alignTextureData = (arr, height, depth) => {
|
|
84
122
|
// bytesPerRow must be a multiple of 256 so we might need to rebuild
|
|
85
123
|
// the data here before passing to the buffer. e.g. if it is unorm8x4 then
|
|
86
124
|
// we need to have width be a multiple of 64
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
// is this a half float texture?
|
|
125
|
+
// Check if the texture is half float
|
|
90
126
|
const halfFloat = tDetails.elementSize === 2 && tDetails.sampleType === 'float';
|
|
127
|
+
const bytesPerElement = arr.BYTES_PER_ELEMENT;
|
|
128
|
+
const inWidthInBytes = arr.length / (height * depth) * bytesPerElement;
|
|
91
129
|
|
|
92
|
-
// if
|
|
93
|
-
if (halfFloat
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
130
|
+
// No changes needed if not half float and already aligned
|
|
131
|
+
if (!halfFloat && inWidthInBytes % 256 === 0) {
|
|
132
|
+
return [arr, inWidthInBytes];
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Calculate dimensions for the new buffer
|
|
136
|
+
const inWidth = inWidthInBytes / bytesPerElement;
|
|
137
|
+
const outBytesPerElement = tDetails.elementSize;
|
|
138
|
+
const outWidthInBytes = 256 * Math.floor((inWidth * outBytesPerElement + 255) / 256);
|
|
139
|
+
const outWidth = outWidthInBytes / outBytesPerElement;
|
|
140
|
+
|
|
141
|
+
// Create the output array
|
|
142
|
+
const outArray = macro.newTypedArray(halfFloat ? 'Uint16Array' : arr.constructor.name, outWidth * height * depth);
|
|
143
|
+
|
|
144
|
+
// Copy and convert data when needed
|
|
145
|
+
const totalRows = height * depth;
|
|
146
|
+
if (halfFloat) {
|
|
147
|
+
for (let v = 0; v < totalRows; v++) {
|
|
148
|
+
const inOffset = v * inWidth;
|
|
149
|
+
const outOffset = v * outWidth;
|
|
150
|
+
for (let i = 0; i < inWidth; i++) {
|
|
151
|
+
outArray[outOffset + i] = HalfFloat.toHalf(arr[inOffset + i]);
|
|
107
152
|
}
|
|
108
153
|
}
|
|
109
|
-
|
|
154
|
+
} else if (outWidth === inWidth) {
|
|
155
|
+
// If the output width is the same as input, just copy
|
|
156
|
+
outArray.set(arr);
|
|
157
|
+
} else {
|
|
158
|
+
for (let v = 0; v < totalRows; v++) {
|
|
159
|
+
outArray.set(arr.subarray(v * inWidth, (v + 1) * inWidth), v * outWidth);
|
|
160
|
+
}
|
|
110
161
|
}
|
|
111
|
-
return [
|
|
162
|
+
return [outArray, outWidthInBytes];
|
|
112
163
|
};
|
|
113
164
|
if (req.nativeArray) {
|
|
114
165
|
nativeArray = req.nativeArray;
|
|
115
166
|
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
const cmdEnc = model.device.createCommandEncoder();
|
|
128
|
-
if (publicAPI.getDimensionality() !== 3) {
|
|
129
|
-
// Non-3D, supports mipmaps
|
|
130
|
-
const mips = vtkTexture.generateMipmaps(nativeArray, model.width, model.height, model.mipLevel);
|
|
131
|
-
let currentWidth = model.width;
|
|
132
|
-
let currentHeight = model.height;
|
|
133
|
-
for (let m = 0; m <= model.mipLevel; m++) {
|
|
134
|
-
const fix = fixAll(mips[m], currentHeight, 1);
|
|
135
|
-
bufferBytesPerRow = fix[1];
|
|
136
|
-
const buffRequest = {
|
|
137
|
-
dataArray: req.dataArray ? req.dataArray : null,
|
|
138
|
-
nativeArray: fix[0],
|
|
139
|
-
/* eslint-disable no-undef */
|
|
140
|
-
usage: BufferUsage.Texture
|
|
141
|
-
/* eslint-enable no-undef */
|
|
142
|
-
};
|
|
143
|
-
|
|
144
|
-
const buff = model.device.getBufferManager().getBuffer(buffRequest);
|
|
145
|
-
cmdEnc.copyBufferToTexture({
|
|
146
|
-
buffer: buff.getHandle(),
|
|
147
|
-
offset: 0,
|
|
148
|
-
bytesPerRow: bufferBytesPerRow,
|
|
149
|
-
rowsPerImage: currentHeight
|
|
150
|
-
}, {
|
|
151
|
-
texture: model.handle,
|
|
152
|
-
mipLevel: m
|
|
153
|
-
}, [currentWidth, currentHeight, 1]);
|
|
154
|
-
currentWidth /= 2;
|
|
155
|
-
currentHeight /= 2;
|
|
167
|
+
const is3D = publicAPI.getDimensionality() === 3;
|
|
168
|
+
const alignedTextureData = alignTextureData(nativeArray, model.height, is3D ? model.depth : 1);
|
|
169
|
+
bufferBytesPerRow = alignedTextureData[1];
|
|
170
|
+
const data = alignedTextureData[0];
|
|
171
|
+
model.device.getHandle().queue.writeTexture({
|
|
172
|
+
texture: model.handle,
|
|
173
|
+
mipLevel: 0,
|
|
174
|
+
origin: {
|
|
175
|
+
x: 0,
|
|
176
|
+
y: 0,
|
|
177
|
+
z: 0
|
|
156
178
|
}
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
};
|
|
169
|
-
|
|
170
|
-
buffRequest.nativeArray = fix[0];
|
|
171
|
-
const buff = model.device.getBufferManager().getBuffer(buffRequest);
|
|
172
|
-
cmdEnc.copyBufferToTexture({
|
|
173
|
-
buffer: buff.getHandle(),
|
|
174
|
-
offset: 0,
|
|
175
|
-
bytesPerRow: bufferBytesPerRow,
|
|
176
|
-
rowsPerImage: model.height
|
|
177
|
-
}, {
|
|
178
|
-
texture: model.handle
|
|
179
|
-
}, [model.width, model.height, model.depth]);
|
|
180
|
-
model.device.submitCommandEncoder(cmdEnc);
|
|
181
|
-
model.ready = true;
|
|
179
|
+
}, data, {
|
|
180
|
+
offset: 0,
|
|
181
|
+
bytesPerRow: bufferBytesPerRow,
|
|
182
|
+
rowsPerImage: model.height
|
|
183
|
+
}, {
|
|
184
|
+
width: model.width,
|
|
185
|
+
height: model.height,
|
|
186
|
+
depthOrArrayLayers: is3D ? model.depth : 1
|
|
187
|
+
});
|
|
188
|
+
if (!is3D && model.mipLevel > 0) {
|
|
189
|
+
vtkTexture.generateMipmaps(model.device.getHandle(), model.handle, model.mipLevel + 1);
|
|
182
190
|
}
|
|
191
|
+
model.ready = true;
|
|
183
192
|
};
|
|
184
193
|
|
|
185
194
|
// when data is pulled out of this texture what scale must be applied to
|
|
@@ -69,6 +69,12 @@ function vtkWebGPUTextureManager(publicAPI, model) {
|
|
|
69
69
|
req.height = req.image.height;
|
|
70
70
|
req.depth = 1;
|
|
71
71
|
req.format = 'rgba8unorm';
|
|
72
|
+
req.flip = true;
|
|
73
|
+
/* eslint-disable no-undef */
|
|
74
|
+
/* eslint-disable no-bitwise */
|
|
75
|
+
req.usage = GPUTextureUsage.STORAGE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.RENDER_ATTACHMENT;
|
|
76
|
+
/* eslint-enable no-undef */
|
|
77
|
+
/* eslint-enable no-bitwise */
|
|
72
78
|
}
|
|
73
79
|
|
|
74
80
|
// fill in based on js imageData
|
|
@@ -79,7 +85,26 @@ function vtkWebGPUTextureManager(publicAPI, model) {
|
|
|
79
85
|
req.format = 'rgba8unorm';
|
|
80
86
|
req.flip = true;
|
|
81
87
|
req.nativeArray = req.jsImageData.data;
|
|
88
|
+
/* eslint-disable no-undef */
|
|
89
|
+
/* eslint-disable no-bitwise */
|
|
90
|
+
req.usage = GPUTextureUsage.STORAGE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.RENDER_ATTACHMENT;
|
|
91
|
+
/* eslint-enable no-undef */
|
|
92
|
+
/* eslint-enable no-bitwise */
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (req.imageBitmap) {
|
|
96
|
+
req.width = req.imageBitmap.width;
|
|
97
|
+
req.height = req.imageBitmap.height;
|
|
98
|
+
req.depth = 1;
|
|
99
|
+
req.format = 'rgba8unorm';
|
|
100
|
+
req.flip = true;
|
|
101
|
+
/* eslint-disable no-undef */
|
|
102
|
+
/* eslint-disable no-bitwise */
|
|
103
|
+
req.usage = GPUTextureUsage.STORAGE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.RENDER_ATTACHMENT;
|
|
104
|
+
/* eslint-enable no-undef */
|
|
105
|
+
/* eslint-enable no-bitwise */
|
|
82
106
|
}
|
|
107
|
+
|
|
83
108
|
if (req.canvas) {
|
|
84
109
|
req.width = req.canvas.width;
|
|
85
110
|
req.height = req.canvas.height;
|
|
@@ -88,7 +113,7 @@ function vtkWebGPUTextureManager(publicAPI, model) {
|
|
|
88
113
|
req.flip = true;
|
|
89
114
|
/* eslint-disable no-undef */
|
|
90
115
|
/* eslint-disable no-bitwise */
|
|
91
|
-
req.usage = GPUTextureUsage.
|
|
116
|
+
req.usage = GPUTextureUsage.STORAGE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.RENDER_ATTACHMENT;
|
|
92
117
|
/* eslint-enable no-undef */
|
|
93
118
|
/* eslint-enable no-bitwise */
|
|
94
119
|
}
|
|
@@ -96,7 +121,9 @@ function vtkWebGPUTextureManager(publicAPI, model) {
|
|
|
96
121
|
|
|
97
122
|
// create a texture (used by getTexture)
|
|
98
123
|
function _createTexture(req) {
|
|
99
|
-
const newTex = vtkWebGPUTexture.newInstance(
|
|
124
|
+
const newTex = vtkWebGPUTexture.newInstance({
|
|
125
|
+
label: req.label
|
|
126
|
+
});
|
|
100
127
|
newTex.create(model.device, {
|
|
101
128
|
width: req.width,
|
|
102
129
|
height: req.height,
|
|
@@ -107,7 +134,7 @@ function vtkWebGPUTextureManager(publicAPI, model) {
|
|
|
107
134
|
});
|
|
108
135
|
|
|
109
136
|
// fill the texture if we have data
|
|
110
|
-
if (req.nativeArray || req.image || req.canvas) {
|
|
137
|
+
if (req.nativeArray || req.image || req.canvas || req.imageBitmap) {
|
|
111
138
|
newTex.writeImageData(req);
|
|
112
139
|
}
|
|
113
140
|
return newTex;
|
|
@@ -116,7 +143,7 @@ function vtkWebGPUTextureManager(publicAPI, model) {
|
|
|
116
143
|
// get a texture or create it if not cached.
|
|
117
144
|
// this is the main entry point
|
|
118
145
|
publicAPI.getTexture = req => {
|
|
119
|
-
// if we have a source
|
|
146
|
+
// if we have a source then get/create/cache the texture
|
|
120
147
|
if (req.hash) {
|
|
121
148
|
// if a matching texture already exists then return it
|
|
122
149
|
return model.device.getCachedObject(req.hash, _createTexture, req);
|
|
@@ -133,9 +160,11 @@ function vtkWebGPUTextureManager(publicAPI, model) {
|
|
|
133
160
|
treq.hash = treq.time + treq.format + treq.mipLevel;
|
|
134
161
|
return model.device.getTextureManager().getTexture(treq);
|
|
135
162
|
};
|
|
136
|
-
publicAPI.getTextureForVTKTexture = srcTexture
|
|
163
|
+
publicAPI.getTextureForVTKTexture = function (srcTexture) {
|
|
164
|
+
let label = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : undefined;
|
|
137
165
|
const treq = {
|
|
138
|
-
time: srcTexture.getMTime()
|
|
166
|
+
time: srcTexture.getMTime(),
|
|
167
|
+
label
|
|
139
168
|
};
|
|
140
169
|
if (srcTexture.getInputData()) {
|
|
141
170
|
treq.imageData = srcTexture.getInputData();
|
|
@@ -143,6 +172,8 @@ function vtkWebGPUTextureManager(publicAPI, model) {
|
|
|
143
172
|
treq.image = srcTexture.getImage();
|
|
144
173
|
} else if (srcTexture.getJsImageData()) {
|
|
145
174
|
treq.jsImageData = srcTexture.getJsImageData();
|
|
175
|
+
} else if (srcTexture.getImageBitmap()) {
|
|
176
|
+
treq.imageBitmap = srcTexture.getImageBitmap();
|
|
146
177
|
} else if (srcTexture.getCanvas()) {
|
|
147
178
|
treq.canvas = srcTexture.getCanvas();
|
|
148
179
|
}
|
package/package.json
CHANGED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import registerWebworker from 'webworker-promise/lib/register';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
*
|
|
5
|
-
* @param {ArrayBuffer} imageBuffer
|
|
6
|
-
* @param {string} mimeType
|
|
7
|
-
* @param {string} channel
|
|
8
|
-
* @returns {Promise<ImageData>}
|
|
9
|
-
*/
|
|
10
|
-
registerWebworker(async _ref => {
|
|
11
|
-
let {
|
|
12
|
-
imageBuffer,
|
|
13
|
-
mimeType,
|
|
14
|
-
channel
|
|
15
|
-
} = _ref;
|
|
16
|
-
const channelsMap = {
|
|
17
|
-
r: 0,
|
|
18
|
-
g: 1,
|
|
19
|
-
b: 2
|
|
20
|
-
};
|
|
21
|
-
const blob = new Blob([imageBuffer], {
|
|
22
|
-
type: mimeType
|
|
23
|
-
});
|
|
24
|
-
const img = await createImageBitmap(blob);
|
|
25
|
-
const canvas = new OffscreenCanvas(img.width, img.height);
|
|
26
|
-
const ctx = canvas.getContext('2d');
|
|
27
|
-
ctx.drawImage(img, 0, 0, img.width, img.height);
|
|
28
|
-
const bitmap = ctx.getImageData(0, 0, img.width, img.height);
|
|
29
|
-
if (channel) {
|
|
30
|
-
const idx = channelsMap[channel];
|
|
31
|
-
for (let i = 0; i < bitmap.data.length; i += 4) {
|
|
32
|
-
const channelValue = bitmap.data[i + idx];
|
|
33
|
-
bitmap.data[i] = channelValue; // red channel
|
|
34
|
-
bitmap.data[i + 1] = channelValue; // green channel
|
|
35
|
-
bitmap.data[i + 2] = channelValue; // blue channel
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
return {
|
|
40
|
-
bitmap
|
|
41
|
-
};
|
|
42
|
-
});
|