Skip to content

Commit 74326c9

Browse files
bruyeretfinetjul
authored andcommitted
feat: Add GPU resource sharing to the ImageCPRMapper
1 parent 7ba1a01 commit 74326c9

File tree

1 file changed

+147
-65
lines changed
  • Sources/Rendering/OpenGL/ImageCPRMapper

1 file changed

+147
-65
lines changed

Sources/Rendering/OpenGL/ImageCPRMapper/index.js

Lines changed: 147 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,13 @@ function vtkOpenGLImageCPRMapper(publicAPI, model) {
4141
// Set our className
4242
model.classHierarchy.push('vtkOpenGLImageCPRMapper');
4343

44+
function unregisterGraphicsResources(renderWindow) {
45+
[model._scalars, model._colorTransferFunc, model._pwFunc].forEach(
46+
(coreObject) =>
47+
renderWindow.unregisterGraphicsResourceUser(coreObject, publicAPI)
48+
);
49+
}
50+
4451
publicAPI.buildPass = (prepass) => {
4552
if (prepass) {
4653
model.currentRenderPass = null;
@@ -49,18 +56,23 @@ function vtkOpenGLImageCPRMapper(publicAPI, model) {
4956
);
5057
model._openGLRenderer =
5158
publicAPI.getFirstAncestorOfType('vtkOpenGLRenderer');
59+
const oldOglRenderWindow = model._openGLRenderWindow;
5260
model._openGLRenderWindow = model._openGLRenderer.getLastAncestorOfType(
5361
'vtkOpenGLRenderWindow'
5462
);
63+
if (
64+
oldOglRenderWindow &&
65+
!oldOglRenderWindow.isDeleted() &&
66+
oldOglRenderWindow !== model._openGLRenderWindow
67+
) {
68+
unregisterGraphicsResources(oldOglRenderWindow);
69+
}
5570
model.context = model._openGLRenderWindow.getContext();
5671
model.openGLCamera = model._openGLRenderer.getViewNodeFor(
5772
model._openGLRenderer.getRenderable().getActiveCamera()
5873
);
5974

6075
model.tris.setOpenGLRenderWindow(model._openGLRenderWindow);
61-
model.volumeTexture.setOpenGLRenderWindow(model._openGLRenderWindow);
62-
model.colorTexture.setOpenGLRenderWindow(model._openGLRenderWindow);
63-
model.pwfTexture.setOpenGLRenderWindow(model._openGLRenderWindow);
6476
}
6577
};
6678

@@ -147,30 +159,8 @@ function vtkOpenGLImageCPRMapper(publicAPI, model) {
147159
if (publicAPI.getNeedToRebuildBufferObjects(ren, actor)) {
148160
publicAPI.buildBufferObjects(ren, actor);
149161
}
150-
};
151-
152-
publicAPI.getNeedToRebuildBufferObjects = (ren, actor) => {
153-
// first do a coarse check
154-
// Note that the actor's mtime includes it's properties mtime
155-
const vmtime = model.VBOBuildTime.getMTime();
156-
if (
157-
vmtime < publicAPI.getMTime() ||
158-
vmtime < model.renderable.getMTime() ||
159-
vmtime < actor.getMTime() ||
160-
vmtime < model.currentImageDataInput.getMTime() ||
161-
vmtime < model.currentCenterlineInput.getMTime()
162-
) {
163-
return true;
164-
}
165-
return false;
166-
};
167-
168-
publicAPI.buildBufferObjects = (ren, actor) => {
169-
const image = model.currentImageDataInput;
170-
const centerline = model.currentCenterlineInput;
171-
const actorProperty = actor.getProperty();
172-
173162
// Set interpolation on the texture based on property setting
163+
const actorProperty = actor.getProperty();
174164
if (actorProperty.getInterpolationType() === InterpolationType.NEAREST) {
175165
model.volumeTexture.setMinificationFilter(Filter.NEAREST);
176166
model.volumeTexture.setMagnificationFilter(Filter.NEAREST);
@@ -186,61 +176,104 @@ function vtkOpenGLImageCPRMapper(publicAPI, model) {
186176
model.pwfTexture.setMinificationFilter(Filter.LINEAR);
187177
model.pwfTexture.setMagnificationFilter(Filter.LINEAR);
188178
}
179+
};
180+
181+
publicAPI.getNeedToRebuildBufferObjects = (ren, actor) => {
182+
// first do a coarse check
183+
// Note that the actor's mtime includes it's properties mtime
184+
const vmtime = model.VBOBuildTime.getMTime();
185+
return (
186+
vmtime < publicAPI.getMTime() ||
187+
vmtime < model.renderable.getMTime() ||
188+
vmtime < actor.getMTime() ||
189+
vmtime < model.currentImageDataInput.getMTime() ||
190+
vmtime < model.currentCenterlineInput.getMTime() ||
191+
!model.volumeTexture?.getHandle()
192+
);
193+
};
194+
195+
publicAPI.buildBufferObjects = (ren, actor) => {
196+
const image = model.currentImageDataInput;
197+
const centerline = model.currentCenterlineInput;
189198

190199
// Rebuild the volumeTexture if the data has changed
191-
const imageTime = image.getMTime();
192-
if (model.volumeTextureTime !== imageTime) {
200+
const scalars = image?.getPointData()?.getScalars();
201+
if (!scalars) {
202+
return;
203+
}
204+
const cachedScalarsEntry =
205+
model._openGLRenderWindow.getGraphicsResourceForObject(scalars);
206+
const volumeTextureHash = `${image.getMTime()}A${scalars.getMTime()}`;
207+
const reBuildTex =
208+
!cachedScalarsEntry?.oglObject?.getHandle() ||
209+
cachedScalarsEntry?.hash !== volumeTextureHash;
210+
if (reBuildTex) {
211+
model.volumeTexture = vtkOpenGLTexture.newInstance();
212+
model.volumeTexture.setOpenGLRenderWindow(model._openGLRenderWindow);
193213
// Build the textures
194214
const dims = image.getDimensions();
195-
const scalars = image.getPointData().getScalars();
196-
if (!scalars) {
197-
return;
198-
}
199215
// Use norm16 for scalar texture if the extension is available
200216
model.volumeTexture.setOglNorm16Ext(
201217
model.context.getExtension('EXT_texture_norm16')
202218
);
203-
model.volumeTexture.releaseGraphicsResources(model._openGLRenderWindow);
204219
model.volumeTexture.resetFormatAndType();
205-
model.volumeTexture.create3DFilterableFromRaw(
220+
model.volumeTexture.create3DFilterableFromDataArray(
206221
dims[0],
207222
dims[1],
208223
dims[2],
209-
scalars.getNumberOfComponents(),
210-
scalars.getDataType(),
211-
scalars.getData(),
224+
scalars,
212225
model.renderable.getPreferSizeOverAccuracy()
213226
);
214-
model.volumeTextureTime = imageTime;
227+
model._openGLRenderWindow.setGraphicsResourceForObject(
228+
scalars,
229+
model.volumeTexture,
230+
volumeTextureHash
231+
);
232+
if (scalars !== model._scalars) {
233+
model._openGLRenderWindow.registerGraphicsResourceUser(
234+
scalars,
235+
publicAPI
236+
);
237+
model._openGLRenderWindow.unregisterGraphicsResourceUser(
238+
model._scalars,
239+
publicAPI
240+
);
241+
}
242+
model._scalars = scalars;
243+
} else {
244+
model.volumeTexture = cachedScalarsEntry.oglObject;
215245
}
216246

217247
// Rebuild the color texture if needed
218-
const scalars = image.getPointData() && image.getPointData().getScalars();
219-
if (!scalars) {
220-
return;
221-
}
222248
const numComp = scalars.getNumberOfComponents();
223249
const ppty = actor.getProperty();
224250
const iComps = ppty.getIndependentComponents();
225251
const numIComps = iComps ? numComp : 1;
226252
const textureHeight = iComps ? 2 * numIComps : 1;
227253

228-
const cfunToString = computeFnToString(
254+
const colorTransferFunc = ppty.getRGBTransferFunction();
255+
const colorTextureHash = computeFnToString(
229256
ppty,
230257
ppty.getRGBTransferFunction,
231258
numIComps
232259
);
233260

234-
if (model.colorTextureString !== cfunToString) {
261+
const cachedColorEntry =
262+
model._openGLRenderWindow.getGraphicsResourceForObject(colorTransferFunc);
263+
const reBuildColorTexture =
264+
!cachedColorEntry?.oglObject?.getHandle() ||
265+
cachedColorEntry?.hash !== colorTextureHash;
266+
if (reBuildColorTexture) {
235267
const cWidth = 1024;
236268
const cSize = cWidth * textureHeight * 3;
237269
const cTable = new Uint8ClampedArray(cSize);
238-
let cfun = ppty.getRGBTransferFunction();
239-
if (cfun) {
270+
model.colorTexture = vtkOpenGLTexture.newInstance();
271+
model.colorTexture.setOpenGLRenderWindow(model._openGLRenderWindow);
272+
if (colorTransferFunc) {
240273
const tmpTable = new Float32Array(cWidth * 3);
241274

242275
for (let c = 0; c < numIComps; c++) {
243-
cfun = ppty.getRGBTransferFunction(c);
276+
const cfun = ppty.getRGBTransferFunction(c);
244277
const cRange = cfun.getRange();
245278
cfun.getTable(cRange[0], cRange[1], cWidth, tmpTable, 1);
246279
if (iComps) {
@@ -254,7 +287,6 @@ function vtkOpenGLImageCPRMapper(publicAPI, model) {
254287
}
255288
}
256289
}
257-
model.colorTexture.releaseGraphicsResources(model._openGLRenderWindow);
258290
model.colorTexture.resetFormatAndType();
259291
model.colorTexture.create2DFromRaw(
260292
cWidth,
@@ -269,6 +301,7 @@ function vtkOpenGLImageCPRMapper(publicAPI, model) {
269301
cTable[i + 1] = (255.0 * i) / ((cWidth - 1) * 3);
270302
cTable[i + 2] = (255.0 * i) / ((cWidth - 1) * 3);
271303
}
304+
model.colorTexture.resetFormatAndType();
272305
model.colorTexture.create2DFromRaw(
273306
cWidth,
274307
1,
@@ -278,32 +311,54 @@ function vtkOpenGLImageCPRMapper(publicAPI, model) {
278311
);
279312
}
280313

281-
model.colorTextureString = cfunToString;
314+
if (colorTransferFunc) {
315+
model._openGLRenderWindow.setGraphicsResourceForObject(
316+
colorTransferFunc,
317+
model.colorTexture,
318+
colorTextureHash
319+
);
320+
if (colorTransferFunc !== model._colorTransferFunc) {
321+
model._openGLRenderWindow.registerGraphicsResourceUser(
322+
colorTransferFunc,
323+
publicAPI
324+
);
325+
model._openGLRenderWindow.unregisterGraphicsResourceUser(
326+
model._colorTransferFunc,
327+
publicAPI
328+
);
329+
}
330+
model._colorTransferFunc = colorTransferFunc;
331+
}
332+
} else {
333+
model.colorTexture = cachedColorEntry.oglObject;
282334
}
283335

284336
// Build piecewise function buffer. This buffer is used either
285337
// for component weighting or opacity, depending on whether we're
286338
// rendering components independently or not.
287-
const pwfunToString = computeFnToString(
339+
const pwFunc = ppty.getPiecewiseFunction();
340+
const pwfTextureHash = computeFnToString(
288341
ppty,
289342
ppty.getPiecewiseFunction,
290343
numIComps
291344
);
292-
293-
if (model.pwfTextureString !== pwfunToString) {
345+
const cachedPwfEntry =
346+
model._openGLRenderWindow.getGraphicsResourceForObject(pwFunc);
347+
const reBuildPwf =
348+
!cachedPwfEntry?.oglObject?.getHandle() ||
349+
cachedPwfEntry?.hash !== pwfTextureHash;
350+
if (reBuildPwf) {
294351
const pwfWidth = 1024;
295352
const pwfSize = pwfWidth * textureHeight;
296353
const pwfTable = new Uint8ClampedArray(pwfSize);
297-
let pwfun = ppty.getPiecewiseFunction();
298-
// support case where pwfun is added/removed
299-
model.pwfTexture.releaseGraphicsResources(model._openGLRenderWindow);
300-
model.pwfTexture.resetFormatAndType();
301-
if (pwfun) {
354+
model.pwfTexture = vtkOpenGLTexture.newInstance();
355+
model.pwfTexture.setOpenGLRenderWindow(model._openGLRenderWindow);
356+
if (pwFunc) {
302357
const pwfFloatTable = new Float32Array(pwfSize);
303358
const tmpTable = new Float32Array(pwfWidth);
304359

305360
for (let c = 0; c < numIComps; ++c) {
306-
pwfun = ppty.getPiecewiseFunction(c);
361+
const pwfun = ppty.getPiecewiseFunction(c);
307362
if (pwfun === null) {
308363
// Piecewise constant max if no function supplied for this component
309364
pwfFloatTable.fill(1.0);
@@ -323,6 +378,7 @@ function vtkOpenGLImageCPRMapper(publicAPI, model) {
323378
}
324379
}
325380
}
381+
model.pwfTexture.resetFormatAndType();
326382
model.pwfTexture.create2DFromRaw(
327383
pwfWidth,
328384
textureHeight,
@@ -333,6 +389,7 @@ function vtkOpenGLImageCPRMapper(publicAPI, model) {
333389
} else {
334390
// default is opaque
335391
pwfTable.fill(255.0);
392+
model.pwfTexture.resetFormatAndType();
336393
model.pwfTexture.create2DFromRaw(
337394
pwfWidth,
338395
1,
@@ -341,7 +398,26 @@ function vtkOpenGLImageCPRMapper(publicAPI, model) {
341398
pwfTable
342399
);
343400
}
344-
model.pwfTextureString = pwfunToString;
401+
if (pwFunc) {
402+
model._openGLRenderWindow.setGraphicsResourceForObject(
403+
pwFunc,
404+
model.pwfTexture,
405+
pwfTextureHash
406+
);
407+
if (pwFunc !== model._pwFunc) {
408+
model._openGLRenderWindow.registerGraphicsResourceUser(
409+
pwFunc,
410+
publicAPI
411+
);
412+
model._openGLRenderWindow.unregisterGraphicsResourceUser(
413+
model._pwFunc,
414+
publicAPI
415+
);
416+
}
417+
model._pwFunc = pwFunc;
418+
}
419+
} else {
420+
model.pwfTexture = cachedPwfEntry.oglObject;
345421
}
346422

347423
// Rebuild the image vertices if needed
@@ -1308,6 +1384,12 @@ function vtkOpenGLImageCPRMapper(publicAPI, model) {
13081384
publicAPI.setCameraShaderParameters(cellBO, ren, actor);
13091385
publicAPI.setPropertyShaderParameters(cellBO, ren, actor);
13101386
};
1387+
1388+
publicAPI.delete = macro.chain(() => {
1389+
if (model._openGLRenderWindow) {
1390+
unregisterGraphicsResources(model._openGLRenderWindow);
1391+
}
1392+
}, publicAPI.delete);
13111393
}
13121394

13131395
// ----------------------------------------------------------------------------
@@ -1317,18 +1399,18 @@ function vtkOpenGLImageCPRMapper(publicAPI, model) {
13171399
const DEFAULT_VALUES = {
13181400
currentRenderPass: null,
13191401
volumeTexture: null,
1320-
volumeTextureTime: 0,
13211402
colorTexture: null,
1322-
colorTextureString: null,
13231403
pwfTexture: null,
1324-
pwfTextureString: null,
13251404
tris: null,
13261405
lastHaveSeenDepthRequest: false,
13271406
haveSeenDepthRequest: false,
13281407
lastTextureComponents: 0,
13291408
lastIndependentComponents: 0,
13301409
imagemat: null,
13311410
imagematinv: null,
1411+
// _scalars: null,
1412+
// _colorTransferFunc: null,
1413+
// _pwFunc: null,
13321414
};
13331415

13341416
// ----------------------------------------------------------------------------
@@ -1348,9 +1430,9 @@ export function extend(publicAPI, model, initialValues = {}) {
13481430
macro.algo(publicAPI, model, 2, 0);
13491431

13501432
model.tris = vtkHelper.newInstance();
1351-
model.volumeTexture = vtkOpenGLTexture.newInstance();
1352-
model.colorTexture = vtkOpenGLTexture.newInstance();
1353-
model.pwfTexture = vtkOpenGLTexture.newInstance();
1433+
model.volumeTexture = null;
1434+
model.colorTexture = null;
1435+
model.pwfTexture = null;
13541436

13551437
model.imagemat = mat4.identity(new Float64Array(16));
13561438
model.imagematinv = mat4.identity(new Float64Array(16));

0 commit comments

Comments
 (0)