@kitware/vtk.js 28.12.4 → 28.13.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/Imaging/Core/ImageReslice.js +21 -50
- package/Interaction/UI/FPSMonitor.js +1 -0
- package/Proxy/Core/View2DProxy.js +3 -0
- package/Rendering/Core/ImageProperty.js +14 -5
- package/Rendering/Core/Mapper2D.js +10 -0
- package/Rendering/Core/RenderWindow.js +17 -8
- package/Rendering/Core/VolumeProperty.js +20 -8
- package/Rendering/OpenGL/BufferObject.js +5 -2
- package/Rendering/OpenGL/Helper.js +1 -0
- package/Rendering/OpenGL/ImageMapper.js +77 -43
- package/Rendering/OpenGL/ImageResliceMapper.js +76 -40
- package/Rendering/OpenGL/PolyDataMapper.js +8 -0
- package/Rendering/OpenGL/PolyDataMapper2D.js +8 -0
- package/Rendering/OpenGL/RenderWindow.d.ts +37 -1
- package/Rendering/OpenGL/RenderWindow.js +84 -0
- package/Rendering/OpenGL/Renderer.js +7 -1
- package/Rendering/OpenGL/ShaderCache.js +23 -22
- package/Rendering/OpenGL/ShaderProgram.js +12 -2
- package/Rendering/OpenGL/Texture.js +9 -3
- package/Rendering/OpenGL/TextureUnitManager.js +5 -0
- package/Rendering/OpenGL/VolumeMapper.js +52 -11
- package/package.json +1 -1
|
@@ -29,11 +29,10 @@ const {
|
|
|
29
29
|
// helper methods
|
|
30
30
|
// ----------------------------------------------------------------------------
|
|
31
31
|
|
|
32
|
-
function computeFnToString(property,
|
|
33
|
-
const pwfun = fn.apply(property);
|
|
32
|
+
function computeFnToString(property, pwfun, numberOfComponents) {
|
|
34
33
|
if (pwfun) {
|
|
35
34
|
const iComps = property.getIndependentComponents();
|
|
36
|
-
return `${
|
|
35
|
+
return `${pwfun.getMTime()}-${iComps}-${numberOfComponents}`;
|
|
37
36
|
}
|
|
38
37
|
return '0';
|
|
39
38
|
}
|
|
@@ -64,12 +63,6 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
|
|
|
64
63
|
model._openGLRenderWindow = model._openGLRenderer.getParent();
|
|
65
64
|
model.context = model._openGLRenderWindow.getContext();
|
|
66
65
|
model.tris.setOpenGLRenderWindow(model._openGLRenderWindow);
|
|
67
|
-
if (!model.openGLTexture) {
|
|
68
|
-
model.openGLTexture = vtkOpenGLTexture.newInstance();
|
|
69
|
-
}
|
|
70
|
-
model.openGLTexture.setOpenGLRenderWindow(model._openGLRenderWindow);
|
|
71
|
-
model.colorTexture.setOpenGLRenderWindow(model._openGLRenderWindow);
|
|
72
|
-
model.pwfTexture.setOpenGLRenderWindow(model._openGLRenderWindow);
|
|
73
66
|
}
|
|
74
67
|
};
|
|
75
68
|
publicAPI.translucentPass = (prepass, renderPass) => {
|
|
@@ -181,34 +174,54 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
|
|
|
181
174
|
if (!scalars) {
|
|
182
175
|
return;
|
|
183
176
|
}
|
|
177
|
+
if (model._scalars !== scalars) {
|
|
178
|
+
model._openGLRenderWindow.releaseGraphicsResourcesForObject(model._scalars);
|
|
179
|
+
model._scalars = scalars;
|
|
180
|
+
}
|
|
184
181
|
const numComp = scalars.getNumberOfComponents();
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
model.openGLTexture.
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
182
|
+
let toString = `${image.getMTime()}A${scalars.getMTime()}`;
|
|
183
|
+
const tex = model._openGLRenderWindow.getGraphicsResourceForObject(scalars);
|
|
184
|
+
const reBuildTex = !tex?.vtkObj || tex?.hash !== toString || model.openGLTextureString !== toString;
|
|
185
|
+
if (reBuildTex) {
|
|
186
|
+
if (!model.openGLTexture) {
|
|
187
|
+
model.openGLTexture = vtkOpenGLTexture.newInstance();
|
|
188
|
+
model.openGLTexture.setOpenGLRenderWindow(model._openGLRenderWindow);
|
|
189
|
+
}
|
|
190
|
+
// Build the image scalar texture
|
|
191
|
+
const dims = image.getDimensions();
|
|
192
|
+
// Use norm16 for the 3D texture if the extension is available
|
|
193
|
+
model.openGLTexture.setOglNorm16Ext(model.context.getExtension('EXT_texture_norm16'));
|
|
194
|
+
model.openGLTexture.releaseGraphicsResources(model._openGLRenderWindow);
|
|
195
|
+
model.openGLTexture.resetFormatAndType();
|
|
196
|
+
model.openGLTexture.create3DFilterableFromDataArray(dims[0], dims[1], dims[2], scalars);
|
|
197
|
+
model.openGLTextureString = toString;
|
|
198
|
+
if (scalars) {
|
|
199
|
+
model._openGLRenderWindow.setGraphicsResourceForObject(scalars, model.openGLTexture, model.openGLTextureString);
|
|
196
200
|
}
|
|
201
|
+
} else {
|
|
202
|
+
model.openGLTexture = tex.vtkObj;
|
|
203
|
+
model.openGLTextureString = tex.hash;
|
|
197
204
|
}
|
|
198
205
|
const ppty = actor.getProperty();
|
|
199
206
|
const iComps = ppty.getIndependentComponents();
|
|
200
207
|
const numIComps = iComps ? numComp : 1;
|
|
201
208
|
const textureHeight = iComps ? 2 * numIComps : 1;
|
|
202
|
-
const
|
|
203
|
-
|
|
209
|
+
const colorTransferFunc = ppty.getRGBTransferFunction();
|
|
210
|
+
toString = computeFnToString(ppty, colorTransferFunc, numIComps);
|
|
211
|
+
const cTex = model._openGLRenderWindow.getGraphicsResourceForObject(colorTransferFunc);
|
|
212
|
+
const reBuildC = !cTex?.vtkObj || cTex?.hash !== toString || model.colorTextureString !== toString;
|
|
213
|
+
if (reBuildC) {
|
|
204
214
|
const cWidth = 1024;
|
|
205
215
|
const cSize = cWidth * textureHeight * 3;
|
|
206
216
|
const cTable = new Uint8Array(cSize);
|
|
207
|
-
|
|
208
|
-
|
|
217
|
+
if (!model.colorTexture) {
|
|
218
|
+
model.colorTexture = vtkOpenGLTexture.newInstance();
|
|
219
|
+
model.colorTexture.setOpenGLRenderWindow(model._openGLRenderWindow);
|
|
220
|
+
}
|
|
221
|
+
if (colorTransferFunc) {
|
|
209
222
|
const tmpTable = new Float32Array(cWidth * 3);
|
|
210
223
|
for (let c = 0; c < numIComps; c++) {
|
|
211
|
-
cfun = ppty.getRGBTransferFunction(c);
|
|
224
|
+
const cfun = ppty.getRGBTransferFunction(c);
|
|
212
225
|
const cRange = cfun.getRange();
|
|
213
226
|
cfun.getTable(cRange[0], cRange[1], cWidth, tmpTable, 1);
|
|
214
227
|
if (iComps) {
|
|
@@ -231,28 +244,40 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
|
|
|
231
244
|
cTable[i + 1] = 255.0 * i / ((cWidth - 1) * 3);
|
|
232
245
|
cTable[i + 2] = 255.0 * i / ((cWidth - 1) * 3);
|
|
233
246
|
}
|
|
247
|
+
model.colorTexture.releaseGraphicsResources(model._openGLRenderWindow);
|
|
248
|
+
model.colorTexture.resetFormatAndType();
|
|
234
249
|
model.colorTexture.create2DFromRaw(cWidth, 1, 3, VtkDataTypes.UNSIGNED_CHAR, cTable);
|
|
235
250
|
}
|
|
236
|
-
model.colorTextureString =
|
|
251
|
+
model.colorTextureString = toString;
|
|
252
|
+
if (colorTransferFunc) {
|
|
253
|
+
model._openGLRenderWindow.setGraphicsResourceForObject(colorTransferFunc, model.colorTexture, model.colorTextureString);
|
|
254
|
+
}
|
|
255
|
+
} else {
|
|
256
|
+
model.colorTexture = cTex.vtkObj;
|
|
257
|
+
model.colorTextureString = cTex.hash;
|
|
237
258
|
}
|
|
238
259
|
|
|
239
260
|
// Build piecewise function buffer. This buffer is used either
|
|
240
261
|
// for component weighting or opacity, depending on whether we're
|
|
241
262
|
// rendering components independently or not.
|
|
242
|
-
const
|
|
243
|
-
|
|
263
|
+
const pwFunc = ppty.getPiecewiseFunction();
|
|
264
|
+
toString = computeFnToString(ppty, pwFunc, numIComps);
|
|
265
|
+
const pwfTex = model._openGLRenderWindow.getGraphicsResourceForObject(pwFunc);
|
|
266
|
+
// rebuild opacity tfun?
|
|
267
|
+
const reBuildPwf = !pwfTex?.vtkObj || pwfTex?.hash !== toString || model.pwfTextureString !== toString;
|
|
268
|
+
if (reBuildPwf) {
|
|
244
269
|
const pwfWidth = 1024;
|
|
245
270
|
const pwfSize = pwfWidth * textureHeight;
|
|
246
271
|
const pwfTable = new Uint8Array(pwfSize);
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
if (
|
|
272
|
+
if (!model.pwfTexture) {
|
|
273
|
+
model.pwfTexture = vtkOpenGLTexture.newInstance();
|
|
274
|
+
model.pwfTexture.setOpenGLRenderWindow(model._openGLRenderWindow);
|
|
275
|
+
}
|
|
276
|
+
if (pwFunc) {
|
|
252
277
|
const pwfFloatTable = new Float32Array(pwfSize);
|
|
253
278
|
const tmpTable = new Float32Array(pwfWidth);
|
|
254
279
|
for (let c = 0; c < numIComps; ++c) {
|
|
255
|
-
pwfun = ppty.getPiecewiseFunction(c);
|
|
280
|
+
const pwfun = ppty.getPiecewiseFunction(c);
|
|
256
281
|
if (pwfun === null) {
|
|
257
282
|
// Piecewise constant max if no function supplied for this component
|
|
258
283
|
pwfFloatTable.fill(1.0);
|
|
@@ -272,13 +297,23 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
|
|
|
272
297
|
}
|
|
273
298
|
}
|
|
274
299
|
}
|
|
300
|
+
model.pwfTexture.releaseGraphicsResources(model._openGLRenderWindow);
|
|
301
|
+
model.pwfTexture.resetFormatAndType();
|
|
275
302
|
model.pwfTexture.create2DFromRaw(pwfWidth, textureHeight, 1, VtkDataTypes.FLOAT, pwfFloatTable);
|
|
276
303
|
} else {
|
|
277
304
|
// default is opaque
|
|
278
305
|
pwfTable.fill(255.0);
|
|
306
|
+
model.pwfTexture.releaseGraphicsResources(model._openGLRenderWindow);
|
|
307
|
+
model.pwfTexture.resetFormatAndType();
|
|
279
308
|
model.pwfTexture.create2DFromRaw(pwfWidth, 1, 1, VtkDataTypes.UNSIGNED_CHAR, pwfTable);
|
|
280
309
|
}
|
|
281
|
-
model.pwfTextureString =
|
|
310
|
+
model.pwfTextureString = toString;
|
|
311
|
+
if (pwFunc) {
|
|
312
|
+
model._openGLRenderWindow.setGraphicsResourceForObject(pwFunc, model.pwfTexture, model.pwfTextureString);
|
|
313
|
+
}
|
|
314
|
+
} else {
|
|
315
|
+
model.pwfTexture = pwfTex.vtkObj;
|
|
316
|
+
model.pwfTextureString = pwfTex.hash;
|
|
282
317
|
}
|
|
283
318
|
const vboString = `${model.resliceGeom.getMTime()}A${model.renderable.getSlabThickness()}`;
|
|
284
319
|
if (!model.tris.getCABO().getElementCount() || model.VBOBuildString !== vboString) {
|
|
@@ -510,7 +545,7 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
|
|
|
510
545
|
if (!model.currentRenderPass && model.lastRenderPassShaderReplacement || model.currentRenderPass && model.currentRenderPass.getShaderReplacement() !== model.lastRenderPassShaderReplacement) {
|
|
511
546
|
needRebuild = true;
|
|
512
547
|
}
|
|
513
|
-
if (needRebuild || model.lastHaveSeenDepthRequest !== model.haveSeenDepthRequest || cellBO.getProgram() === 0 || model.lastTextureComponents !== tNumComp || model.lastIndependentComponents !== iComp || model.lastSlabThickness !== slabTh || model.lastSlabType !== slabType || model.lastSlabTrapezoidIntegration !== slabTrap) {
|
|
548
|
+
if (needRebuild || model.lastHaveSeenDepthRequest !== model.haveSeenDepthRequest || cellBO.getProgram()?.getHandle() === 0 || model.lastTextureComponents !== tNumComp || model.lastIndependentComponents !== iComp || model.lastSlabThickness !== slabTh || model.lastSlabType !== slabType || model.lastSlabTrapezoidIntegration !== slabTrap) {
|
|
514
549
|
model.lastHaveSeenDepthRequest = model.haveSeenDepthRequest;
|
|
515
550
|
model.lastTextureComponents = tNumComp;
|
|
516
551
|
model.lastIndependentComponents = iComp;
|
|
@@ -846,7 +881,8 @@ const DEFAULT_VALUES = {
|
|
|
846
881
|
tris: null,
|
|
847
882
|
colorTexture: null,
|
|
848
883
|
pwfTexture: null,
|
|
849
|
-
_externalOpenGLTexture: false
|
|
884
|
+
_externalOpenGLTexture: false,
|
|
885
|
+
_scalars: null
|
|
850
886
|
};
|
|
851
887
|
|
|
852
888
|
// ----------------------------------------------------------------------------
|
|
@@ -860,9 +896,9 @@ function extend(publicAPI, model) {
|
|
|
860
896
|
vtkReplacementShaderMapper.implementReplaceShaderCoincidentOffset(publicAPI, model, initialValues);
|
|
861
897
|
vtkReplacementShaderMapper.implementBuildShadersWithReplacements(publicAPI, model, initialValues);
|
|
862
898
|
model.tris = vtkHelper.newInstance();
|
|
863
|
-
model.openGLTexture =
|
|
864
|
-
model.colorTexture =
|
|
865
|
-
model.pwfTexture =
|
|
899
|
+
model.openGLTexture = null;
|
|
900
|
+
model.colorTexture = null;
|
|
901
|
+
model.pwfTexture = null;
|
|
866
902
|
model.VBOBuildTime = {};
|
|
867
903
|
obj(model.VBOBuildTime);
|
|
868
904
|
model.tmpMat4 = mat4.identity(new Float64Array(16));
|
|
@@ -1089,6 +1089,14 @@ function vtkOpenGLPolyDataMapper(publicAPI, model) {
|
|
|
1089
1089
|
model.VBOBuildString = toString;
|
|
1090
1090
|
}
|
|
1091
1091
|
};
|
|
1092
|
+
publicAPI.getAllocatedGPUMemoryInBytes = () => {
|
|
1093
|
+
let memUsed = 0;
|
|
1094
|
+
model.primitives.forEach(prim => {
|
|
1095
|
+
memUsed += prim.getAllocatedGPUMemoryInBytes();
|
|
1096
|
+
});
|
|
1097
|
+
// Return in MB
|
|
1098
|
+
return memUsed;
|
|
1099
|
+
};
|
|
1092
1100
|
}
|
|
1093
1101
|
|
|
1094
1102
|
// ----------------------------------------------------------------------------
|
|
@@ -406,6 +406,14 @@ function vtkOpenGLPolyDataMapper2D(publicAPI, model) {
|
|
|
406
406
|
mat4.transpose(tmpMat4, tmpMat4);
|
|
407
407
|
program.setUniformMatrix('WCVCMatrix', safeMatrixMultiply([tmpMat4, inverseShiftScaleMatrix], mat4, model.tmpMat4));
|
|
408
408
|
};
|
|
409
|
+
publicAPI.getAllocatedGPUMemoryInBytes = () => {
|
|
410
|
+
let memUsed = 0;
|
|
411
|
+
model.primitives.forEach(prim => {
|
|
412
|
+
memUsed += prim.getAllocatedGPUMemoryInBytes();
|
|
413
|
+
});
|
|
414
|
+
// Return in MB
|
|
415
|
+
return memUsed;
|
|
416
|
+
};
|
|
409
417
|
}
|
|
410
418
|
|
|
411
419
|
// ----------------------------------------------------------------------------
|
|
@@ -1,6 +1,11 @@
|
|
|
1
|
-
import { vtkAlgorithm, vtkObject } from './../../interfaces';
|
|
2
1
|
import { Nullable, Size, Vector2, Vector3 } from './../../types';
|
|
3
2
|
import { VtkDataTypes } from './../../Common/Core/DataArray';
|
|
3
|
+
import { vtkAlgorithm, vtkObject } from './../../interfaces';
|
|
4
|
+
import vtkBufferObject from './BufferObject';
|
|
5
|
+
import vtkCellArray from './../../Common/Core/CellArray';
|
|
6
|
+
import vtkDataArray from './../../Common/Core/DataArray';
|
|
7
|
+
import vtkOpenGLTexture from './Texture';
|
|
8
|
+
import vtkPoints from './../../Common/Core/Points';
|
|
4
9
|
import vtkRenderer from './../Core/Renderer';
|
|
5
10
|
import vtkTexture from './../Core/Texture';
|
|
6
11
|
import vtkViewStream from './../../IO/Core/ImageStream/ViewStream';
|
|
@@ -389,6 +394,37 @@ export interface vtkOpenGLRenderWindow extends vtkOpenGLRenderWindowBase {
|
|
|
389
394
|
* @see getContainerSize()
|
|
390
395
|
*/
|
|
391
396
|
getComputedDevicePixelRatio(): number;
|
|
397
|
+
|
|
398
|
+
/**
|
|
399
|
+
* Set graphics resources for vtk objects to be cached at the context level.
|
|
400
|
+
* This provides mappers with a convenient API to re-use allocated GPU resources
|
|
401
|
+
* without duplication.
|
|
402
|
+
*
|
|
403
|
+
* @param {Object} vtkObj VTK data object / array with resources on the GPU
|
|
404
|
+
* @param {Object} gObj Container object that maintains a handle to the graphics resource on the GPU
|
|
405
|
+
* @param {String} hash String hash that can be used by mappers to decide whether to discard or re-allocate
|
|
406
|
+
* the cached resource.
|
|
407
|
+
*/
|
|
408
|
+
setGraphicsResourceForObject(vtkObj: vtkCellArray | vtkDataArray | vtkPoints, gObj: vtkOpenGLTexture | vtkBufferObject, hash: string): void;
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* Get graphics resources for vtk objects cached at the context level.
|
|
412
|
+
* This provides mappers with a convenient API to re-use allocated GPU resources
|
|
413
|
+
* without duplication.
|
|
414
|
+
*
|
|
415
|
+
* @param {Object} vtkObj VTK data object / array with resources on the GPU
|
|
416
|
+
* the cached resource.
|
|
417
|
+
* @return {Object} Dictionary with the graphics resource and string hash
|
|
418
|
+
*/
|
|
419
|
+
getGraphicsResourceForObject(vtkObj: vtkCellArray | vtkDataArray | vtkPoints): {gObj: vtkOpenGLTexture | vtkBufferObject, hash: string};
|
|
420
|
+
|
|
421
|
+
/**
|
|
422
|
+
* Get approximate graphics memory usage, in bytes, for the context. This is a simple computation
|
|
423
|
+
* that analyzes how much memory is allocated on the GPU for textures, VBOs, etc. to give an
|
|
424
|
+
* application a view of its graphics memory consumption.
|
|
425
|
+
* Note that this ignores page resources.
|
|
426
|
+
*/
|
|
427
|
+
getGraphicsMemoryInfo(): number;
|
|
392
428
|
}
|
|
393
429
|
|
|
394
430
|
/**
|
|
@@ -424,6 +424,31 @@ function vtkOpenGLRenderWindow(publicAPI, model) {
|
|
|
424
424
|
}
|
|
425
425
|
return -1;
|
|
426
426
|
};
|
|
427
|
+
publicAPI.getDefaultTextureByteSize = function (vtkType) {
|
|
428
|
+
let oglNorm16Ext = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
|
|
429
|
+
let useHalfFloat = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
|
|
430
|
+
if (model.webgl2) {
|
|
431
|
+
switch (vtkType) {
|
|
432
|
+
case VtkDataTypes.CHAR:
|
|
433
|
+
case VtkDataTypes.SIGNED_CHAR:
|
|
434
|
+
case VtkDataTypes.UNSIGNED_CHAR:
|
|
435
|
+
return 1;
|
|
436
|
+
case oglNorm16Ext:
|
|
437
|
+
case useHalfFloat:
|
|
438
|
+
case VtkDataTypes.UNSIGNED_SHORT:
|
|
439
|
+
case VtkDataTypes.SHORT:
|
|
440
|
+
case VtkDataTypes.VOID:
|
|
441
|
+
// Used for unsigned int depth
|
|
442
|
+
return 2;
|
|
443
|
+
default:
|
|
444
|
+
// For all other cases, assume float
|
|
445
|
+
return 4;
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
// webgl1 type support is limited to 1 byte
|
|
450
|
+
return 1;
|
|
451
|
+
};
|
|
427
452
|
publicAPI.getDefaultTextureInternalFormat = function (vtktype, numComps) {
|
|
428
453
|
let oglNorm16Ext = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
|
|
429
454
|
let useHalfFloat = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
|
|
@@ -658,6 +683,9 @@ function vtkOpenGLRenderWindow(publicAPI, model) {
|
|
|
658
683
|
return lineWidthRange[1];
|
|
659
684
|
};
|
|
660
685
|
publicAPI.getGLInformations = () => {
|
|
686
|
+
if (model._glInformation) {
|
|
687
|
+
return model._glInformation;
|
|
688
|
+
}
|
|
661
689
|
const gl = publicAPI.get3DContext();
|
|
662
690
|
const glTextureFloat = gl.getExtension('OES_texture_float');
|
|
663
691
|
const glTextureHalfFloat = gl.getExtension('OES_texture_half_float');
|
|
@@ -675,6 +703,7 @@ function vtkOpenGLRenderWindow(publicAPI, model) {
|
|
|
675
703
|
};
|
|
676
704
|
}
|
|
677
705
|
}
|
|
706
|
+
model._glInformation = result;
|
|
678
707
|
return result;
|
|
679
708
|
};
|
|
680
709
|
publicAPI.traverseAllPasses = () => {
|
|
@@ -751,6 +780,58 @@ function vtkOpenGLRenderWindow(publicAPI, model) {
|
|
|
751
780
|
}
|
|
752
781
|
return modified;
|
|
753
782
|
};
|
|
783
|
+
publicAPI.getGraphicsResourceForObject = vtkObj => {
|
|
784
|
+
if (!vtkObj) {
|
|
785
|
+
return null;
|
|
786
|
+
}
|
|
787
|
+
const vtko = model._graphicsResources.get(vtkObj);
|
|
788
|
+
const vtkh = model._graphicsResourceHash.get(vtkObj);
|
|
789
|
+
return {
|
|
790
|
+
vtkObj: vtko,
|
|
791
|
+
hash: vtkh
|
|
792
|
+
};
|
|
793
|
+
};
|
|
794
|
+
publicAPI.setGraphicsResourceForObject = (vtkObj, gObj, hash) => {
|
|
795
|
+
if (!vtkObj) {
|
|
796
|
+
return;
|
|
797
|
+
}
|
|
798
|
+
model._graphicsResources.set(vtkObj, gObj);
|
|
799
|
+
model._graphicsResourceHash.set(vtkObj, hash);
|
|
800
|
+
};
|
|
801
|
+
publicAPI.getGraphicsMemoryInfo = () => {
|
|
802
|
+
let memUsed = 0;
|
|
803
|
+
model._graphicsResources.forEach((gObj, vtkObj) => {
|
|
804
|
+
memUsed += gObj.getAllocatedGPUMemoryInBytes();
|
|
805
|
+
});
|
|
806
|
+
return memUsed;
|
|
807
|
+
};
|
|
808
|
+
publicAPI.releaseGraphicsResourcesForObject = vtkObj => {
|
|
809
|
+
if (!vtkObj) {
|
|
810
|
+
return false;
|
|
811
|
+
}
|
|
812
|
+
model._graphicsResources.get(vtkObj)?.releaseGraphicsResources(publicAPI);
|
|
813
|
+
return model._graphicsResources.delete(vtkObj) && model._graphicsResourceHash.delete(vtkObj);
|
|
814
|
+
};
|
|
815
|
+
publicAPI.releaseGraphicsResources = () => {
|
|
816
|
+
// Clear the shader cache
|
|
817
|
+
if (model.shaderCache !== null) {
|
|
818
|
+
model.shaderCache.releaseGraphicsResources(publicAPI);
|
|
819
|
+
}
|
|
820
|
+
// Free cached graphics resources at the context level
|
|
821
|
+
model._graphicsResources.forEach((gObj, vtkObj) => {
|
|
822
|
+
gObj.releaseGraphicsResources(publicAPI);
|
|
823
|
+
});
|
|
824
|
+
model._graphicsResources.clear();
|
|
825
|
+
model._graphicsResourceHash.clear();
|
|
826
|
+
if (model.textureUnitManager !== null) {
|
|
827
|
+
model.textureUnitManager.freeAll();
|
|
828
|
+
}
|
|
829
|
+
// Finally, ask the renderers to release prop resources
|
|
830
|
+
model.renderable.getRenderersByReference().forEach(ren => {
|
|
831
|
+
const glRen = publicAPI.getViewNodeFor(ren);
|
|
832
|
+
glRen?.releaseGraphicsResources();
|
|
833
|
+
});
|
|
834
|
+
};
|
|
754
835
|
}
|
|
755
836
|
|
|
756
837
|
// ----------------------------------------------------------------------------
|
|
@@ -809,6 +890,9 @@ function extend(publicAPI, model) {
|
|
|
809
890
|
model.bgImage.style.height = '100%';
|
|
810
891
|
model.bgImage.style.zIndex = '-1';
|
|
811
892
|
model._textureResourceIds = new Map();
|
|
893
|
+
model._graphicsResources = new Map();
|
|
894
|
+
model._graphicsResourceHash = new Map();
|
|
895
|
+
model._glInformation = null;
|
|
812
896
|
model.myFactory = vtkViewNodeFactory.newInstance();
|
|
813
897
|
/* eslint-disable no-use-before-define */
|
|
814
898
|
model.myFactory.registerOverride('vtkRenderWindow', newInstance);
|
|
@@ -148,6 +148,12 @@ function vtkOpenGLRenderer(publicAPI, model) {
|
|
|
148
148
|
if (model.selector !== null) {
|
|
149
149
|
model.selector.releaseGraphicsResources();
|
|
150
150
|
}
|
|
151
|
+
// Releasing resources means that the next render should re-create resources
|
|
152
|
+
if (model.renderable) {
|
|
153
|
+
model.renderable.getViewProps().forEach(prop => {
|
|
154
|
+
prop.modified();
|
|
155
|
+
});
|
|
156
|
+
}
|
|
151
157
|
};
|
|
152
158
|
publicAPI.setOpenGLRenderWindow = rw => {
|
|
153
159
|
if (model._openGLRenderWindow === rw) {
|
|
@@ -168,7 +174,7 @@ function vtkOpenGLRenderer(publicAPI, model) {
|
|
|
168
174
|
|
|
169
175
|
const DEFAULT_VALUES = {
|
|
170
176
|
context: null,
|
|
171
|
-
|
|
177
|
+
_openGLRenderWindow: null,
|
|
172
178
|
selector: null
|
|
173
179
|
};
|
|
174
180
|
|
|
@@ -4,7 +4,7 @@ import vtkShaderProgram from './ShaderProgram.js';
|
|
|
4
4
|
|
|
5
5
|
// ----------------------------------------------------------------------------
|
|
6
6
|
|
|
7
|
-
const SET_GET_FIELDS = ['
|
|
7
|
+
const SET_GET_FIELDS = ['lastShaderProgramBound', 'context', '_openGLRenderWindow'];
|
|
8
8
|
|
|
9
9
|
// ----------------------------------------------------------------------------
|
|
10
10
|
// vtkShaderCache methods
|
|
@@ -67,24 +67,24 @@ function vtkShaderCache(publicAPI, model) {
|
|
|
67
67
|
// return NULL if there is an issue
|
|
68
68
|
publicAPI.readyShaderProgramArray = (vertexCode, fragmentCode, geometryCode) => {
|
|
69
69
|
const data = publicAPI.replaceShaderValues(vertexCode, fragmentCode, geometryCode);
|
|
70
|
-
const
|
|
71
|
-
return publicAPI.readyShaderProgram(
|
|
70
|
+
const shaderProgram = publicAPI.getShaderProgram(data.VSSource, data.FSSource, data.GSSource);
|
|
71
|
+
return publicAPI.readyShaderProgram(shaderProgram);
|
|
72
72
|
};
|
|
73
|
-
publicAPI.readyShaderProgram =
|
|
74
|
-
if (!
|
|
73
|
+
publicAPI.readyShaderProgram = program => {
|
|
74
|
+
if (!program) {
|
|
75
75
|
return null;
|
|
76
76
|
}
|
|
77
77
|
|
|
78
78
|
// compile if needed
|
|
79
|
-
if (!
|
|
79
|
+
if (!program.getCompiled() && !program.compileShader()) {
|
|
80
80
|
return null;
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
// bind if needed
|
|
84
|
-
if (!publicAPI.
|
|
84
|
+
if (!publicAPI.bindShaderProgram(program)) {
|
|
85
85
|
return null;
|
|
86
86
|
}
|
|
87
|
-
return
|
|
87
|
+
return program;
|
|
88
88
|
};
|
|
89
89
|
publicAPI.getShaderProgram = (vertexCode, fragmentCode, geometryCode) => {
|
|
90
90
|
// compute the MD5 and the check the map
|
|
@@ -116,27 +116,28 @@ function vtkShaderCache(publicAPI, model) {
|
|
|
116
116
|
// have to loop over all the programs were in use and invoke
|
|
117
117
|
// release graphics resources individually.
|
|
118
118
|
|
|
119
|
-
publicAPI.
|
|
120
|
-
Object.keys(model.shaderPrograms).map(key => model.shaderPrograms[key]).forEach(sp => sp.
|
|
119
|
+
publicAPI.releaseCurrentShaderProgram();
|
|
120
|
+
Object.keys(model.shaderPrograms).map(key => model.shaderPrograms[key]).forEach(sp => sp.cleanup());
|
|
121
|
+
model.shaderPrograms = {};
|
|
121
122
|
};
|
|
122
|
-
publicAPI.
|
|
123
|
+
publicAPI.releaseCurrentShaderProgram = () => {
|
|
123
124
|
// release prior shader
|
|
124
|
-
if (model.
|
|
125
|
-
model.
|
|
126
|
-
model.
|
|
125
|
+
if (model.lastShaderProgramBound) {
|
|
126
|
+
model.lastShaderProgramBound.cleanup();
|
|
127
|
+
model.lastShaderProgramBound = null;
|
|
127
128
|
}
|
|
128
129
|
};
|
|
129
|
-
publicAPI.
|
|
130
|
-
if (model.
|
|
130
|
+
publicAPI.bindShaderProgram = program => {
|
|
131
|
+
if (model.lastShaderProgramBound === program) {
|
|
131
132
|
return 1;
|
|
132
133
|
}
|
|
133
134
|
|
|
134
|
-
// release prior
|
|
135
|
-
if (model.
|
|
136
|
-
model.
|
|
135
|
+
// release prior program
|
|
136
|
+
if (model.lastShaderProgramBound) {
|
|
137
|
+
model.lastShaderProgramBound.release();
|
|
137
138
|
}
|
|
138
|
-
|
|
139
|
-
model.
|
|
139
|
+
program.bind();
|
|
140
|
+
model.lastShaderProgramBound = program;
|
|
140
141
|
return 1;
|
|
141
142
|
};
|
|
142
143
|
}
|
|
@@ -146,7 +147,7 @@ function vtkShaderCache(publicAPI, model) {
|
|
|
146
147
|
// ----------------------------------------------------------------------------
|
|
147
148
|
|
|
148
149
|
const DEFAULT_VALUES = {
|
|
149
|
-
|
|
150
|
+
lastShaderProgramBound: null,
|
|
150
151
|
shaderPrograms: null,
|
|
151
152
|
context: null
|
|
152
153
|
// _openGLRenderWindow: null,
|
|
@@ -64,8 +64,18 @@ function vtkShaderProgram(publicAPI, model) {
|
|
|
64
64
|
if (model.shaderType === 'Unknown' || model.handle === 0) {
|
|
65
65
|
return;
|
|
66
66
|
}
|
|
67
|
-
|
|
67
|
+
publicAPI.release();
|
|
68
|
+
if (model.vertexShaderHandle !== 0) {
|
|
69
|
+
model.context.detachShader(model.handle, model.vertexShaderHandle);
|
|
70
|
+
model.vertexShaderHandle = 0;
|
|
71
|
+
}
|
|
72
|
+
if (model.fragmentShaderHandle !== 0) {
|
|
73
|
+
model.context.detachShader(model.handle, model.fragmentShaderHandle);
|
|
74
|
+
model.fragmentShaderHandle = 0;
|
|
75
|
+
}
|
|
76
|
+
model.context.deleteProgram(model.handle);
|
|
68
77
|
model.handle = 0;
|
|
78
|
+
publicAPI.setCompiled(false);
|
|
69
79
|
};
|
|
70
80
|
publicAPI.bind = () => {
|
|
71
81
|
if (!model.linked && !publicAPI.link()) {
|
|
@@ -406,7 +416,7 @@ function vtkShaderProgram(publicAPI, model) {
|
|
|
406
416
|
}
|
|
407
417
|
if (shader.getShaderType() === 'Vertex') {
|
|
408
418
|
if (model.vertexShaderHandle !== 0) {
|
|
409
|
-
model.
|
|
419
|
+
model.context.detachShader(model.handle, model.vertexShaderHandle);
|
|
410
420
|
}
|
|
411
421
|
model.vertexShaderHandle = shader.getHandle();
|
|
412
422
|
}
|
|
@@ -212,6 +212,7 @@ function vtkOpenGLTexture(publicAPI, model) {
|
|
|
212
212
|
model.width = 0;
|
|
213
213
|
model.height = 0;
|
|
214
214
|
model.depth = 0;
|
|
215
|
+
model.allocatedGPUMemoryInBytes = 0;
|
|
215
216
|
}
|
|
216
217
|
if (model.shaderProgram) {
|
|
217
218
|
model.shaderProgram.releaseGraphicsResources(rwin);
|
|
@@ -701,6 +702,7 @@ function vtkOpenGLTexture(publicAPI, model) {
|
|
|
701
702
|
if (flip) {
|
|
702
703
|
model.context.pixelStorei(model.context.UNPACK_FLIP_Y_WEBGL, false);
|
|
703
704
|
}
|
|
705
|
+
model.allocatedGPUMemoryInBytes = model.width * model.height * model.depth * numComps * model._openGLRenderWindow.getDefaultTextureByteSize(dataType, model.oglNorm16Ext, model.useHalfFloat);
|
|
704
706
|
publicAPI.deactivate();
|
|
705
707
|
return true;
|
|
706
708
|
};
|
|
@@ -778,7 +780,7 @@ function vtkOpenGLTexture(publicAPI, model) {
|
|
|
778
780
|
h /= 2;
|
|
779
781
|
}
|
|
780
782
|
}
|
|
781
|
-
|
|
783
|
+
model.allocatedGPUMemoryInBytes = model.width * model.height * model.depth * numComps * model._openGLRenderWindow.getDefaultTextureByteSize(dataType, model.oglNorm16Ext, model.useHalfFloat);
|
|
782
784
|
// generateMipmap must not be called here because we manually upload all levels
|
|
783
785
|
// if it is called, all levels will be overwritten
|
|
784
786
|
|
|
@@ -828,6 +830,7 @@ function vtkOpenGLTexture(publicAPI, model) {
|
|
|
828
830
|
if (model.generateMipmap) {
|
|
829
831
|
model.context.generateMipmap(model.target);
|
|
830
832
|
}
|
|
833
|
+
model.allocatedGPUMemoryInBytes = model.width * model.height * model.depth * model.components * model._openGLRenderWindow.getDefaultTextureByteSize(dataType, model.oglNorm16Ext, model.useHalfFloat);
|
|
831
834
|
publicAPI.deactivate();
|
|
832
835
|
return true;
|
|
833
836
|
};
|
|
@@ -877,6 +880,7 @@ function vtkOpenGLTexture(publicAPI, model) {
|
|
|
877
880
|
if (model.generateMipmap) {
|
|
878
881
|
model.context.generateMipmap(model.target);
|
|
879
882
|
}
|
|
883
|
+
model.allocatedGPUMemoryInBytes = model.width * model.height * model.depth * model.components * model._openGLRenderWindow.getDefaultTextureByteSize(VtkDataTypes.UNSIGNED_CHAR, model.oglNorm16Ext, model.useHalfFloat);
|
|
880
884
|
publicAPI.deactivate();
|
|
881
885
|
return true;
|
|
882
886
|
};
|
|
@@ -1016,6 +1020,7 @@ function vtkOpenGLTexture(publicAPI, model) {
|
|
|
1016
1020
|
if (model.generateMipmap) {
|
|
1017
1021
|
model.context.generateMipmap(model.target);
|
|
1018
1022
|
}
|
|
1023
|
+
model.allocatedGPUMemoryInBytes = model.width * model.height * model.depth * model.components * model._openGLRenderWindow.getDefaultTextureByteSize(dataType, model.oglNorm16Ext, model.useHalfFloat);
|
|
1019
1024
|
publicAPI.deactivate();
|
|
1020
1025
|
return true;
|
|
1021
1026
|
};
|
|
@@ -1296,7 +1301,8 @@ const DEFAULT_VALUES = {
|
|
|
1296
1301
|
// the voxel intensity range is out of the accurate
|
|
1297
1302
|
// range of half float
|
|
1298
1303
|
useHalfFloat: true,
|
|
1299
|
-
oglNorm16Ext: null
|
|
1304
|
+
oglNorm16Ext: null,
|
|
1305
|
+
allocatedGPUMemoryInBytes: 0
|
|
1300
1306
|
};
|
|
1301
1307
|
|
|
1302
1308
|
// ----------------------------------------------------------------------------
|
|
@@ -1319,7 +1325,7 @@ function extend(publicAPI, model) {
|
|
|
1319
1325
|
// Build VTK API
|
|
1320
1326
|
set(publicAPI, model, ['format', 'openGLDataType']);
|
|
1321
1327
|
setGet(publicAPI, model, ['keyMatrixTime', 'minificationFilter', 'magnificationFilter', 'wrapS', 'wrapT', 'wrapR', 'generateMipmap', 'oglNorm16Ext']);
|
|
1322
|
-
get(publicAPI, model, ['width', 'height', 'volumeInfo', 'components', 'handle', 'target']);
|
|
1328
|
+
get(publicAPI, model, ['width', 'height', 'volumeInfo', 'components', 'handle', 'target', 'allocatedGPUMemoryInBytes']);
|
|
1323
1329
|
moveToProtected(publicAPI, model, ['openGLRenderWindow']);
|
|
1324
1330
|
|
|
1325
1331
|
// Object methods
|
|
@@ -81,6 +81,11 @@ function vtkOpenGLTextureUnitManager(publicAPI, model) {
|
|
|
81
81
|
publicAPI.free = val => {
|
|
82
82
|
model.textureUnits[val] = false;
|
|
83
83
|
};
|
|
84
|
+
publicAPI.freeAll = () => {
|
|
85
|
+
for (let i = 0; i < model.numberOfTextureUnits; ++i) {
|
|
86
|
+
model.textureUnits[i] = false;
|
|
87
|
+
}
|
|
88
|
+
};
|
|
84
89
|
}
|
|
85
90
|
|
|
86
91
|
// ----------------------------------------------------------------------------
|