diff --git a/Sources/Rendering/WebGPU/Actor/index.js b/Sources/Rendering/WebGPU/Actor/index.js index 24e48f2becc..84f90843be3 100644 --- a/Sources/Rendering/WebGPU/Actor/index.js +++ b/Sources/Rendering/WebGPU/Actor/index.js @@ -5,6 +5,7 @@ import vtkProp from 'vtk.js/Sources/Rendering/Core/Prop'; import vtkViewNode from 'vtk.js/Sources/Rendering/SceneGraph/ViewNode'; import { registerOverride } from 'vtk.js/Sources/Rendering/WebGPU/ViewNodeFactory'; +import { getWebGPUContext } from 'vtk.js/Sources/Rendering/WebGPU/Helpers/Context'; const { CoordinateSystem } = vtkProp; @@ -19,11 +20,9 @@ function vtkWebGPUActor(publicAPI, model) { // Builds myself. publicAPI.buildPass = (prepass) => { if (prepass) { - model.WebGPURenderer = - publicAPI.getFirstAncestorOfType('vtkWebGPURenderer'); - model.WebGPURenderWindow = model.WebGPURenderer.getFirstAncestorOfType( - 'vtkWebGPURenderWindow' - ); + const { renderer, renderWindow } = getWebGPUContext(publicAPI); + model.WebGPURenderer = renderer; + model.WebGPURenderWindow = renderWindow; if (model.propID === undefined) { model.propID = model.WebGPURenderWindow.getUniquePropID(); } diff --git a/Sources/Rendering/WebGPU/Actor2D/index.js b/Sources/Rendering/WebGPU/Actor2D/index.js index 0a60954ac0a..1184bdf6a8e 100644 --- a/Sources/Rendering/WebGPU/Actor2D/index.js +++ b/Sources/Rendering/WebGPU/Actor2D/index.js @@ -5,6 +5,7 @@ import vtkProp from 'vtk.js/Sources/Rendering/Core/Prop'; import vtkViewNode from 'vtk.js/Sources/Rendering/SceneGraph/ViewNode'; import { registerOverride } from 'vtk.js/Sources/Rendering/WebGPU/ViewNodeFactory'; +import { getWebGPUContext } from 'vtk.js/Sources/Rendering/WebGPU/Helpers/Context'; const { CoordinateSystem } = vtkProp; @@ -19,11 +20,9 @@ function vtkWebGPUActor2D(publicAPI, model) { // Builds myself. publicAPI.buildPass = (prepass) => { if (prepass) { - model.WebGPURenderer = - publicAPI.getFirstAncestorOfType('vtkWebGPURenderer'); - model.WebGPURenderWindow = model.WebGPURenderer.getFirstAncestorOfType( - 'vtkWebGPURenderWindow' - ); + const { renderer, renderWindow } = getWebGPUContext(publicAPI); + model.WebGPURenderer = renderer; + model.WebGPURenderWindow = renderWindow; if (model.propID === undefined) { model.propID = model.WebGPURenderWindow.getUniquePropID(); } diff --git a/Sources/Rendering/WebGPU/BufferManager/index.js b/Sources/Rendering/WebGPU/BufferManager/index.js index 433e4b8ddf6..2426cac52a5 100644 --- a/Sources/Rendering/WebGPU/BufferManager/index.js +++ b/Sources/Rendering/WebGPU/BufferManager/index.js @@ -197,6 +197,40 @@ function generateNormals(cellArray, pointArray) { return packedVBO; } +// Build a cache key from the request fields that determine buffer contents, so +// callers cannot forget a content affecting field (e.g. shift or scale, which +// _createBuffer bakes into the packed data). Returns null for usages whose +// contents are not fully described by these fields (RawVertex / UniformArray / +// Storage / Texture carry a raw nativeArray); those callers must supply +// req.hash themselves. +function _computeBufferHash(req) { + switch (req.usage) { + case BufferUsage.Index: + case BufferUsage.PointArray: + case BufferUsage.NormalsFromPoints: + break; + default: + return null; + } + const parts = [`u${req.usage}`]; + if (req.format) parts.push(`f${req.format}`); + if (req.dataArray) parts.push(`d${req.dataArray.getMTime()}`); + if (req.cells) parts.push(`c${req.cells.getMTime()}`); + if (req.indexBuffer) parts.push(`i${req.indexBuffer.getMTime?.() ?? 0}`); + if (req.representation !== undefined) parts.push(`R${req.representation}`); + if (req.primitiveType !== undefined) parts.push(`P${req.primitiveType}`); + if (req.cellOffset !== undefined) parts.push(`O${req.cellOffset}`); + if (req.cellData) parts.push('cd'); + if (req.packExtra) parts.push('pe'); + if (req.shift !== undefined) { + parts.push(`s${Array.isArray(req.shift) ? req.shift.join() : req.shift}`); + } + if (req.scale !== undefined) { + parts.push(`S${Array.isArray(req.scale) ? req.scale.join() : req.scale}`); + } + return parts.join(''); +} + // ---------------------------------------------------------------------------- // vtkWebGPUBufferManager methods // ---------------------------------------------------------------------------- @@ -335,9 +369,12 @@ function vtkWebGPUBufferManager(publicAPI, model) { publicAPI.hasBuffer = (hash) => model.device.hasCachedObject(hash); publicAPI.getBuffer = (req) => { - // if we have a source the get/create/cache the buffer - if (req.hash) { - return model.device.getCachedObject(req.hash, _createBuffer, req); + // Prefer an explicit caller hash, otherwise derive one from the request + // fields that determine the buffer contents so shift/scale/etc. cannot be + // silently dropped from the cache key. + const hash = req.hash ?? _computeBufferHash(req); + if (hash) { + return model.device.getCachedObject(hash, _createBuffer, req); } return _createBuffer(req); diff --git a/Sources/Rendering/WebGPU/CellArrayMapper/index.js b/Sources/Rendering/WebGPU/CellArrayMapper/index.js index 5c4af2d74e7..6d93568fe8f 100644 --- a/Sources/Rendering/WebGPU/CellArrayMapper/index.js +++ b/Sources/Rendering/WebGPU/CellArrayMapper/index.js @@ -12,6 +12,7 @@ import vtkWebGPUBufferManager from 'vtk.js/Sources/Rendering/WebGPU/BufferManage import vtkWebGPUShaderCache from 'vtk.js/Sources/Rendering/WebGPU/ShaderCache'; import vtkWebGPUUniformBuffer from 'vtk.js/Sources/Rendering/WebGPU/UniformBuffer'; import vtkWebGPUSimpleMapper from 'vtk.js/Sources/Rendering/WebGPU/SimpleMapper'; +import { getWebGPUContext } from 'vtk.js/Sources/Rendering/WebGPU/Helpers/Context'; import vtkWebGPUTypes from 'vtk.js/Sources/Rendering/WebGPU/Types'; import { addClipPlaneEntries, @@ -391,11 +392,6 @@ fn main( const tmp2Mat4 = new Float64Array(16); -function isEdges(hash) { - // edge pipelines have "edge" in them - return hash.indexOf('edge') >= 0; -} - // ---------------------------------------------------------------------------- // vtkWebGPUCellArrayMapper methods // ---------------------------------------------------------------------------- @@ -406,22 +402,19 @@ function vtkWebGPUCellArrayMapper(publicAPI, model) { publicAPI.buildPass = (prepass) => { if (prepass) { - if (model.is2D) { - model.WebGPUActor = - publicAPI.getFirstAncestorOfType('vtkWebGPUActor2D'); - model.forceZValue = true; - } else { - model.WebGPUActor = publicAPI.getFirstAncestorOfType('vtkWebGPUActor'); - model.forceZValue = false; - } + model.forceZValue = model.is2D; + const { parent, renderer, renderWindow, device } = getWebGPUContext( + publicAPI, + model.is2D ? 'vtkWebGPUActor2D' : 'vtkWebGPUActor' + ); + model.WebGPUActor = parent; model.coordinateSystem = model.WebGPUActor.getRenderable().getCoordinateSystem(); model.useRendererMatrix = model.coordinateSystem !== CoordinateSystem.DISPLAY; - model.WebGPURenderer = - model.WebGPUActor.getFirstAncestorOfType('vtkWebGPURenderer'); - model.WebGPURenderWindow = model.WebGPURenderer.getParent(); - model.device = model.WebGPURenderWindow.getDevice(); + model.WebGPURenderer = renderer; + model.WebGPURenderWindow = renderWindow; + model.device = device; } }; @@ -911,7 +904,7 @@ function vtkWebGPUCellArrayMapper(publicAPI, model) { // we only apply lighting when there is a "var normal" declaration in the // fragment shader code. That is the lighting trigger. publicAPI.replaceShaderLight = (hash, pipeline, vertexInput) => { - if (hash.includes('sel')) return; + if (model.selectionPass) return; const vDesc = pipeline.getShaderDescription('vertex'); if (!vDesc.hasOutput('vertexVC')) vDesc.addOutput('vec4', 'vertexVC'); @@ -925,9 +918,9 @@ function vtkWebGPUCellArrayMapper(publicAPI, model) { const needLighting = hasNormal && model.useRendererMatrix && - !isEdges(hash) && + !publicAPI.isEdgePrimitive() && !model.is2D && - !hash.includes('sel'); + !model.selectionPass; if (needLighting) { const lightingCode = [ // Vectors needed for light calculations @@ -1040,7 +1033,7 @@ function vtkWebGPUCellArrayMapper(publicAPI, model) { publicAPI.replaceShaderColor = (hash, pipeline, vertexInput) => { // By default, set the colors to be flat - if (isEdges(hash)) { + if (publicAPI.isEdgePrimitive()) { const fDesc = pipeline.getShaderDescription('fragment'); let code = fDesc.getCode(); code = vtkWebGPUShaderCache.substitute(code, '//VTK::Color::Impl', [ @@ -1231,7 +1224,7 @@ function vtkWebGPUCellArrayMapper(publicAPI, model) { ); publicAPI.replaceShaderSelect = (hash, pipeline, vertexInput) => { - if (hash.includes('sel')) { + if (model.selectionPass) { const selectBuffer = vertexInput.getBuffer('selectId'); if (selectBuffer) { const vDesc = pipeline.getShaderDescription('vertex'); @@ -1342,9 +1335,6 @@ function vtkWebGPUCellArrayMapper(publicAPI, model) { let indexBuffer = null; if (cells) { indexBuffer = device.getBufferManager().getBuffer({ - hash: `R${representation}P${primType}O${ - model.cellOffset - }${cells.getMTime()}`, usage: BufferUsage.Index, cells, numberOfPoints: points.getNumberOfPoints(), @@ -1357,23 +1347,15 @@ function vtkWebGPUCellArrayMapper(publicAPI, model) { vertexInput.setIndexBuffer(null); } - // hash = all things that can change the values on the buffer - // since mtimes are unique we can use - // - indexBuffer mtime - because cells drive how we pack - // - relevant dataArray mtime - the source data - // - shift - not currently captured - // - scale - not currently captured - // - format - // - usage - // - packExtra - covered by format + // The buffer cache key is derived by BufferManager.getBuffer from the + // request fields (dataArray/indexBuffer mtimes, shift, scale, format, usage, + // packExtra, cellOffset), so callers pass inputs rather than a hand built + // hash and cannot silently drop a content affecting field. // --- Points Buffer --- if (points) { const shift = model.WebGPUActor.getBufferShift(model.WebGPURenderer); vertexInput.addBuffer( device.getBufferManager().getBuffer({ - hash: `${points.getMTime()}I${ - indexBuffer?.getMTime?.() ?? 0 - }${shift.join()}float32x4`, usage: BufferUsage.PointArray, format: 'float32x4', dataArray: points, @@ -1412,7 +1394,6 @@ function vtkWebGPUCellArrayMapper(publicAPI, model) { scale: 127, }; if (normals) { - buffRequest.hash = `${normals.getMTime()}I${indexBuffer.getMTime()}snorm8x4`; buffRequest.dataArray = normals; buffRequest.usage = BufferUsage.PointArray; vertexInput.addBuffer( @@ -1421,7 +1402,6 @@ function vtkWebGPUCellArrayMapper(publicAPI, model) { ); } else if (primType === PrimitiveTypes.Triangles) { model._usesCellNormals = true; - buffRequest.hash = `PFN${points.getMTime()}I${indexBuffer.getMTime()}snorm8x4`; buffRequest.dataArray = points; buffRequest.cells = cells; buffRequest.usage = BufferUsage.NormalsFromPoints; @@ -1455,9 +1435,6 @@ function vtkWebGPUCellArrayMapper(publicAPI, model) { device.getBufferManager().getBuffer({ usage: BufferUsage.PointArray, format: 'unorm8x4', - hash: `${haveCellScalars}${c.getMTime()}I${indexBuffer.getMTime()}O${ - model.cellOffset - }unorm8x4`, dataArray: c, indexBuffer, cellData: haveCellScalars, diff --git a/Sources/Rendering/WebGPU/CubeAxesActor/index.js b/Sources/Rendering/WebGPU/CubeAxesActor/index.js index 6e9eddc5787..ae8c32b27b4 100644 --- a/Sources/Rendering/WebGPU/CubeAxesActor/index.js +++ b/Sources/Rendering/WebGPU/CubeAxesActor/index.js @@ -3,6 +3,7 @@ import vtkCubeAxesActor from 'vtk.js/Sources/Rendering/Core/CubeAxesActor'; import vtkViewNode from 'vtk.js/Sources/Rendering/SceneGraph/ViewNode'; import { registerOverride } from 'vtk.js/Sources/Rendering/WebGPU/ViewNodeFactory'; +import { getWebGPUContext } from 'vtk.js/Sources/Rendering/WebGPU/Helpers/Context'; // ---------------------------------------------------------------------------- // vtkWebGPUCubeAxesActor methods @@ -14,9 +15,9 @@ function vtkWebGPUCubeAxesActor(publicAPI, model) { // Builds myself. publicAPI.buildPass = (prepass) => { if (prepass) { - model.WebGPURenderer = - publicAPI.getFirstAncestorOfType('vtkWebGPURenderer'); - model.WebGPURenderWindow = model.WebGPURenderer.getParent(); + const { renderer, renderWindow } = getWebGPUContext(publicAPI); + model.WebGPURenderer = renderer; + model.WebGPURenderWindow = renderWindow; if (!model.CubeAxesActorHelper.getRenderable()) { model.CubeAxesActorHelper.setRenderable(model.renderable); diff --git a/Sources/Rendering/WebGPU/Glyph3DMapper/index.js b/Sources/Rendering/WebGPU/Glyph3DMapper/index.js index a333c0be72f..bc24b9c05db 100644 --- a/Sources/Rendering/WebGPU/Glyph3DMapper/index.js +++ b/Sources/Rendering/WebGPU/Glyph3DMapper/index.js @@ -4,6 +4,7 @@ import vtkWebGPUPolyDataMapper from 'vtk.js/Sources/Rendering/WebGPU/PolyDataMap import vtkWebGPUStorageBuffer from 'vtk.js/Sources/Rendering/WebGPU/StorageBuffer'; import vtkWebGPUShaderCache from 'vtk.js/Sources/Rendering/WebGPU/ShaderCache'; import { registerOverride } from 'vtk.js/Sources/Rendering/WebGPU/ViewNodeFactory'; +import { getWebGPUContext } from 'vtk.js/Sources/Rendering/WebGPU/Helpers/Context'; function vtkWebGPUGlyph3DCellArrayMapper(publicAPI, model) { // Set our className @@ -91,7 +92,7 @@ function vtkWebGPUGlyph3DCellArrayMapper(publicAPI, model) { ); publicAPI.replaceShaderSelect = (hash, pipeline, vertexInput) => { - if (hash.includes('sel')) { + if (model.selectionPass) { const vDesc = pipeline.getShaderDescription('vertex'); vDesc.addOutput('u32', 'attributeID', 'flat'); vDesc.addOutput('u32', 'compositeID', 'flat'); @@ -187,10 +188,8 @@ function vtkWebGPUGlyph3DMapper(publicAPI, model) { ) { // In Core class all arrays are rebuilt when this happens // but these arrays can be shared between all primType - model.WebGPURenderWindow = publicAPI.getFirstAncestorOfType( - 'vtkWebGPURenderWindow' - ); - const device = model.WebGPURenderWindow.getDevice(); + const { renderWindow, device } = getWebGPUContext(publicAPI); + model.WebGPURenderWindow = renderWindow; const ssboInstances = Math.max(model.numInstances, 1); model.SSBO.clearData(); diff --git a/Sources/Rendering/WebGPU/Helpers/Context.js b/Sources/Rendering/WebGPU/Helpers/Context.js new file mode 100644 index 00000000000..5e0346ca572 --- /dev/null +++ b/Sources/Rendering/WebGPU/Helpers/Context.js @@ -0,0 +1,24 @@ +/** + * Resolve the WebGPU rendering context (renderer, render window, device) for a + * view node, replacing the ancestor walk that was copy pasted across mappers, + * actors and passes. + * Pass parentType when the caller first needs an intermediate ancestor (the + * actor or image slice the node draws through); the walk to the renderer starts + * from that ancestor. Omit it for nodes (actors, volumes, passes) that sit + * directly under the renderer. + * @param {*} node + * @param {*} parentType + * @returns { parent, renderer, renderWindow, device } + */ +export function getWebGPUContext(node, parentType = null) { + const parent = parentType ? node.getFirstAncestorOfType(parentType) : null; + const from = parent ?? node; + const renderer = from?.getFirstAncestorOfType('vtkWebGPURenderer'); + const renderWindow = renderer?.getFirstAncestorOfType( + 'vtkWebGPURenderWindow' + ); + const device = renderWindow?.getDevice(); + return { parent, renderer, renderWindow, device }; +} + +export default { getWebGPUContext }; diff --git a/Sources/Rendering/WebGPU/ImageCPRMapper/index.js b/Sources/Rendering/WebGPU/ImageCPRMapper/index.js index c072d18d32f..63d5853c9a6 100644 --- a/Sources/Rendering/WebGPU/ImageCPRMapper/index.js +++ b/Sources/Rendering/WebGPU/ImageCPRMapper/index.js @@ -14,6 +14,7 @@ import { MAX_CLIPPING_PLANES, } from 'vtk.js/Sources/Rendering/WebGPU/Helpers/ClippingPlanes'; import { computeFnToString } from 'vtk.js/Sources/Rendering/WebGPU/Helpers/ImageSampling'; +import { getWebGPUContext } from 'vtk.js/Sources/Rendering/WebGPU/Helpers/Context'; import { registerOverride } from 'vtk.js/Sources/Rendering/WebGPU/ViewNodeFactory'; const { BufferUsage } = vtkWebGPUBufferManager; @@ -300,13 +301,14 @@ function vtkWebGPUImageCPRMapper(publicAPI, model) { publicAPI.buildPass = (prepass) => { if (prepass) { - model.WebGPUImageSlice = publicAPI.getFirstAncestorOfType( + const { parent, renderer, renderWindow, device } = getWebGPUContext( + publicAPI, 'vtkWebGPUImageSlice' ); - model.WebGPURenderer = - model.WebGPUImageSlice.getFirstAncestorOfType('vtkWebGPURenderer'); - model.WebGPURenderWindow = model.WebGPURenderer.getParent(); - model.device = model.WebGPURenderWindow.getDevice(); + model.WebGPUImageSlice = parent; + model.WebGPURenderer = renderer; + model.WebGPURenderWindow = renderWindow; + model.device = device; publicAPI.setWebGPURenderer(model.WebGPURenderer); } }; @@ -340,7 +342,9 @@ function vtkWebGPUImageCPRMapper(publicAPI, model) { model.currentImageDataInput = model.renderable.getInputData(0); model.currentCenterlineInput = model.renderable.getOrientedCenterline(); - publicAPI.prepareToDraw(model.WebGPURenderer.getRenderEncoder()); + const renderEncoder = model.WebGPURenderer.getRenderEncoder(); + model.selectionPass = renderEncoder?.getPipelineHash?.() === 'sel'; + publicAPI.prepareToDraw(renderEncoder); model.renderEncoder.registerDrawCallback(model.pipeline, publicAPI.draw); }; @@ -890,7 +894,7 @@ function vtkWebGPUImageCPRMapper(publicAPI, model) { ); publicAPI.replaceShaderRenderEncoder = (hash, pipeline) => { - if (hash.includes('sel')) { + if (model.selectionPass) { const fDesc = pipeline.getShaderDescription('fragment'); fDesc.addOutput('vec4', 'outColor'); let code = fDesc.getCode(); diff --git a/Sources/Rendering/WebGPU/ImageMapper/index.js b/Sources/Rendering/WebGPU/ImageMapper/index.js index 2f5e92cd964..2fd221539c7 100644 --- a/Sources/Rendering/WebGPU/ImageMapper/index.js +++ b/Sources/Rendering/WebGPU/ImageMapper/index.js @@ -4,6 +4,7 @@ import * as macro from 'vtk.js/Sources/macros'; import vtkWebGPUShaderCache from 'vtk.js/Sources/Rendering/WebGPU/ShaderCache'; import vtkWebGPUFullScreenQuad from 'vtk.js/Sources/Rendering/WebGPU/FullScreenQuad'; import vtkWebGPUUniformBuffer from 'vtk.js/Sources/Rendering/WebGPU/UniformBuffer'; +import { getWebGPUContext } from 'vtk.js/Sources/Rendering/WebGPU/Helpers/Context'; import { addClipPlaneEntries, getClippingPlaneEquationsInCoords, @@ -118,13 +119,14 @@ function vtkWebGPUImageMapper(publicAPI, model) { publicAPI.buildPass = (prepass) => { if (prepass) { - model.WebGPUImageSlice = publicAPI.getFirstAncestorOfType( + const { parent, renderer, renderWindow, device } = getWebGPUContext( + publicAPI, 'vtkWebGPUImageSlice' ); - model.WebGPURenderer = - model.WebGPUImageSlice.getFirstAncestorOfType('vtkWebGPURenderer'); - model.WebGPURenderWindow = model.WebGPURenderer.getParent(); - model.device = model.WebGPURenderWindow.getDevice(); + model.WebGPUImageSlice = parent; + model.WebGPURenderer = renderer; + model.WebGPURenderWindow = renderWindow; + model.device = device; const ren = model.WebGPURenderer.getRenderable(); // is slice set by the camera diff --git a/Sources/Rendering/WebGPU/ImageResliceMapper/index.js b/Sources/Rendering/WebGPU/ImageResliceMapper/index.js index 8344cfca890..7ff248ff26a 100644 --- a/Sources/Rendering/WebGPU/ImageResliceMapper/index.js +++ b/Sources/Rendering/WebGPU/ImageResliceMapper/index.js @@ -10,6 +10,7 @@ import vtkTransform from 'vtk.js/Sources/Common/Transform/Transform'; import vtkWebGPUImageMapper from 'vtk.js/Sources/Rendering/WebGPU/ImageMapper'; import vtkWebGPUShaderCache from 'vtk.js/Sources/Rendering/WebGPU/ShaderCache'; import { getTextureChannelMode } from 'vtk.js/Sources/Rendering/WebGPU/Helpers/ImageSampling'; +import { getWebGPUContext } from 'vtk.js/Sources/Rendering/WebGPU/Helpers/Context'; import { getInputProperty, getLabelOutlineTextureParameters, @@ -683,13 +684,14 @@ function vtkWebGPUImageResliceMapper(publicAPI, model) { if (!prepass) { return; } - model.WebGPUImageSlice = publicAPI.getFirstAncestorOfType( + const { parent, renderer, renderWindow, device } = getWebGPUContext( + publicAPI, 'vtkWebGPUImageSlice' ); - model.WebGPURenderer = - model.WebGPUImageSlice.getFirstAncestorOfType('vtkWebGPURenderer'); - model.WebGPURenderWindow = model.WebGPURenderer.getParent(); - model.device = model.WebGPURenderWindow.getDevice(); + model.WebGPUImageSlice = parent; + model.WebGPURenderer = renderer; + model.WebGPURenderWindow = renderWindow; + model.device = device; }; publicAPI.render = () => { diff --git a/Sources/Rendering/WebGPU/ImageSlice/index.js b/Sources/Rendering/WebGPU/ImageSlice/index.js index 5218a2f7bd8..657befbff81 100644 --- a/Sources/Rendering/WebGPU/ImageSlice/index.js +++ b/Sources/Rendering/WebGPU/ImageSlice/index.js @@ -4,6 +4,7 @@ import * as macro from 'vtk.js/Sources/macros'; import vtkViewNode from 'vtk.js/Sources/Rendering/SceneGraph/ViewNode'; import { registerOverride } from 'vtk.js/Sources/Rendering/WebGPU/ViewNodeFactory'; +import { getWebGPUContext } from 'vtk.js/Sources/Rendering/WebGPU/Helpers/Context'; // ---------------------------------------------------------------------------- // vtkWebGPUImageSlice methods @@ -23,11 +24,9 @@ function vtkWebGPUImageSlice(publicAPI, model) { return; } - model.WebGPURenderer = - publicAPI.getFirstAncestorOfType('vtkWebGPURenderer'); - model.WebGPURenderWindow = model.WebGPURenderer.getFirstAncestorOfType( - 'vtkWebGPURenderWindow' - ); + const { renderer, renderWindow } = getWebGPUContext(publicAPI); + model.WebGPURenderer = renderer; + model.WebGPURenderWindow = renderWindow; if (model.propID === undefined) { model.propID = model.WebGPURenderWindow.getUniquePropID(); } diff --git a/Sources/Rendering/WebGPU/PixelSpaceCallbackMapper/index.js b/Sources/Rendering/WebGPU/PixelSpaceCallbackMapper/index.js index 78a9202b131..57980079af5 100644 --- a/Sources/Rendering/WebGPU/PixelSpaceCallbackMapper/index.js +++ b/Sources/Rendering/WebGPU/PixelSpaceCallbackMapper/index.js @@ -2,6 +2,7 @@ import macro from 'vtk.js/Sources/macros'; import vtkViewNode from 'vtk.js/Sources/Rendering/SceneGraph/ViewNode'; import { registerOverride } from 'vtk.js/Sources/Rendering/WebGPU/ViewNodeFactory'; +import { getWebGPUContext } from 'vtk.js/Sources/Rendering/WebGPU/Helpers/Context'; // ---------------------------------------------------------------------------- // vtkWebGPUPixelSpaceCallbackMapper methods @@ -11,9 +12,9 @@ function vtkWebGPUPixelSpaceCallbackMapper(publicAPI, model) { model.classHierarchy.push('vtkWebGPUPixelSpaceCallbackMapper'); publicAPI.opaquePass = (prepass, renderPass) => { - model.WebGPURenderer = - publicAPI.getFirstAncestorOfType('vtkWebGPURenderer'); - model.WebGPURenderWindow = model.WebGPURenderer.getParent(); + const { renderer, renderWindow } = getWebGPUContext(publicAPI); + model.WebGPURenderer = renderer; + model.WebGPURenderWindow = renderWindow; const aspectRatio = model.WebGPURenderer.getAspectRatio(); const camera = model.WebGPURenderer ? model.WebGPURenderer.getRenderable().getActiveCamera() diff --git a/Sources/Rendering/WebGPU/ScalarBarActor/index.js b/Sources/Rendering/WebGPU/ScalarBarActor/index.js index e97720926e5..a05d1709230 100644 --- a/Sources/Rendering/WebGPU/ScalarBarActor/index.js +++ b/Sources/Rendering/WebGPU/ScalarBarActor/index.js @@ -3,6 +3,7 @@ import vtkScalarBarActor from 'vtk.js/Sources/Rendering/Core/ScalarBarActor'; import vtkViewNode from 'vtk.js/Sources/Rendering/SceneGraph/ViewNode'; import { registerOverride } from 'vtk.js/Sources/Rendering/WebGPU/ViewNodeFactory'; +import { getWebGPUContext } from 'vtk.js/Sources/Rendering/WebGPU/Helpers/Context'; // ---------------------------------------------------------------------------- // vtkWebGPUScalarBarActor methods @@ -14,9 +15,9 @@ function vtkWebGPUScalarBarActor(publicAPI, model) { // Builds myself. publicAPI.buildPass = (prepass) => { if (prepass) { - model.WebGPURenderer = - publicAPI.getFirstAncestorOfType('vtkWebGPURenderer'); - model.WebGPURenderWindow = model.WebGPURenderer.getParent(); + const { renderer, renderWindow } = getWebGPUContext(publicAPI); + model.WebGPURenderer = renderer; + model.WebGPURenderWindow = renderWindow; if (!model.scalarBarActorHelper.getRenderable()) { model.scalarBarActorHelper.setRenderable(model.renderable); diff --git a/Sources/Rendering/WebGPU/Skybox/index.js b/Sources/Rendering/WebGPU/Skybox/index.js index 6d1edbe7696..68ba9dab12b 100644 --- a/Sources/Rendering/WebGPU/Skybox/index.js +++ b/Sources/Rendering/WebGPU/Skybox/index.js @@ -9,6 +9,7 @@ import vtkWebGPUTexture from 'vtk.js/Sources/Rendering/WebGPU/Texture'; import vtkWebGPUUniformBuffer from 'vtk.js/Sources/Rendering/WebGPU/UniformBuffer'; import { registerOverride } from 'vtk.js/Sources/Rendering/WebGPU/ViewNodeFactory'; +import { getWebGPUContext } from 'vtk.js/Sources/Rendering/WebGPU/Helpers/Context'; const { VtkDataTypes } = vtkDataArray; const { vtkErrorMacro } = macro; @@ -176,11 +177,9 @@ function vtkWebGPUSkybox(publicAPI, model) { publicAPI.buildPass = (prepass) => { if (prepass) { - model.WebGPURenderer = - publicAPI.getFirstAncestorOfType('vtkWebGPURenderer'); - model.WebGPURenderWindow = model.WebGPURenderer?.getFirstAncestorOfType( - 'vtkWebGPURenderWindow' - ); + const { renderer, renderWindow } = getWebGPUContext(publicAPI); + model.WebGPURenderer = renderer; + model.WebGPURenderWindow = renderWindow; if (model.WebGPURenderer) { const renderer = model.WebGPURenderer.getRenderable(); diff --git a/Sources/Rendering/WebGPU/Volume/index.js b/Sources/Rendering/WebGPU/Volume/index.js index b8c0185fec6..4297cad8371 100644 --- a/Sources/Rendering/WebGPU/Volume/index.js +++ b/Sources/Rendering/WebGPU/Volume/index.js @@ -4,6 +4,7 @@ import macro from 'vtk.js/Sources/macros'; import vtkViewNode from 'vtk.js/Sources/Rendering/SceneGraph/ViewNode'; import { registerOverride } from 'vtk.js/Sources/Rendering/WebGPU/ViewNodeFactory'; +import { getWebGPUContext } from 'vtk.js/Sources/Rendering/WebGPU/Helpers/Context'; // ---------------------------------------------------------------------------- // vtkWebGPUVolume methods @@ -19,11 +20,9 @@ function vtkWebGPUVolume(publicAPI, model) { return; } if (prepass) { - model.WebGPURenderer = - publicAPI.getFirstAncestorOfType('vtkWebGPURenderer'); - model.WebGPURenderWindow = model.WebGPURenderer.getFirstAncestorOfType( - 'vtkWebGPURenderWindow' - ); + const { renderer, renderWindow } = getWebGPUContext(publicAPI); + model.WebGPURenderer = renderer; + model.WebGPURenderWindow = renderWindow; // for the future if we support hardware selection of volumes if (model.propID === undefined) { model.propID = model.WebGPURenderWindow.getUniquePropID();