@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.
@@ -29,11 +29,10 @@ const {
29
29
  // helper methods
30
30
  // ----------------------------------------------------------------------------
31
31
 
32
- function computeFnToString(property, fn, numberOfComponents) {
33
- const pwfun = fn.apply(property);
32
+ function computeFnToString(property, pwfun, numberOfComponents) {
34
33
  if (pwfun) {
35
34
  const iComps = property.getIndependentComponents();
36
- return `${property.getMTime()}-${iComps}-${numberOfComponents}`;
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
- if (!model._externalOpenGLTexture) {
186
- const toString = `${image.getMTime()}A${scalars.getMTime()}`;
187
- if (model.openGLTextureString !== toString) {
188
- // Build the image scalar texture
189
- const dims = image.getDimensions();
190
- // Use norm16 for the 3D texture if the extension is available
191
- model.openGLTexture.getOglNorm16Ext(model.context.getExtension('EXT_texture_norm16'));
192
- model.openGLTexture.releaseGraphicsResources(model._openGLRenderWindow);
193
- model.openGLTexture.resetFormatAndType();
194
- model.openGLTexture.create3DFilterableFromDataArray(dims[0], dims[1], dims[2], scalars);
195
- model.openGLTextureString = toString;
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 cfunToString = computeFnToString(ppty, ppty.getRGBTransferFunction, numIComps);
203
- if (model.colorTextureString !== cfunToString) {
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
- let cfun = ppty.getRGBTransferFunction();
208
- if (cfun) {
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 = cfunToString;
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 pwfunToString = computeFnToString(ppty, ppty.getPiecewiseFunction, numIComps);
243
- if (model.pwfTextureString !== pwfunToString) {
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
- let pwfun = ppty.getPiecewiseFunction();
248
- // support case where pwfun is added/removed
249
- model.pwfTexture.releaseGraphicsResources(model._openGLRenderWindow);
250
- model.pwfTexture.resetFormatAndType();
251
- if (pwfun) {
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 = pwfunToString;
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 = vtkOpenGLTexture.newInstance();
864
- model.colorTexture = vtkOpenGLTexture.newInstance();
865
- model.pwfTexture = vtkOpenGLTexture.newInstance();
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
- // _openGLRenderWindow: null,
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 = ['lastShaderBound', 'context', '_openGLRenderWindow'];
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 shader = publicAPI.getShaderProgram(data.VSSource, data.FSSource, data.GSSource);
71
- return publicAPI.readyShaderProgram(shader);
70
+ const shaderProgram = publicAPI.getShaderProgram(data.VSSource, data.FSSource, data.GSSource);
71
+ return publicAPI.readyShaderProgram(shaderProgram);
72
72
  };
73
- publicAPI.readyShaderProgram = shader => {
74
- if (!shader) {
73
+ publicAPI.readyShaderProgram = program => {
74
+ if (!program) {
75
75
  return null;
76
76
  }
77
77
 
78
78
  // compile if needed
79
- if (!shader.getCompiled() && !shader.compileShader()) {
79
+ if (!program.getCompiled() && !program.compileShader()) {
80
80
  return null;
81
81
  }
82
82
 
83
83
  // bind if needed
84
- if (!publicAPI.bindShader(shader)) {
84
+ if (!publicAPI.bindShaderProgram(program)) {
85
85
  return null;
86
86
  }
87
- return shader;
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.releaseCurrentShader();
120
- Object.keys(model.shaderPrograms).map(key => model.shaderPrograms[key]).forEach(sp => sp.releaseGraphicsResources(win));
119
+ publicAPI.releaseCurrentShaderProgram();
120
+ Object.keys(model.shaderPrograms).map(key => model.shaderPrograms[key]).forEach(sp => sp.cleanup());
121
+ model.shaderPrograms = {};
121
122
  };
122
- publicAPI.releaseGraphicsResources = () => {
123
+ publicAPI.releaseCurrentShaderProgram = () => {
123
124
  // release prior shader
124
- if (model.astShaderBound) {
125
- model.lastShaderBound.release();
126
- model.lastShaderBound = null;
125
+ if (model.lastShaderProgramBound) {
126
+ model.lastShaderProgramBound.cleanup();
127
+ model.lastShaderProgramBound = null;
127
128
  }
128
129
  };
129
- publicAPI.bindShader = shader => {
130
- if (model.lastShaderBound === shader) {
130
+ publicAPI.bindShaderProgram = program => {
131
+ if (model.lastShaderProgramBound === program) {
131
132
  return 1;
132
133
  }
133
134
 
134
- // release prior shader
135
- if (model.lastShaderBound) {
136
- model.lastShaderBound.release();
135
+ // release prior program
136
+ if (model.lastShaderProgramBound) {
137
+ model.lastShaderProgramBound.release();
137
138
  }
138
- shader.bind();
139
- model.lastShaderBound = shader;
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
- lastShaderBound: null,
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
- model.context.deleteShader(model.handle);
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.comntext.detachShader(model.handle, model.vertexShaderHandle);
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
  // ----------------------------------------------------------------------------