Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 26 additions & 2 deletions Sources/Rendering/WebGPU/BindGroup/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import macro from 'vtk.js/Sources/macros';

const { vtkErrorMacro } = macro;

// ----------------------------------------------------------------------------
// vtkWebGPUBindGroup methods
// ----------------------------------------------------------------------------
Expand Down Expand Up @@ -30,6 +32,7 @@ function vtkWebGPUBindGroup(publicAPI, model) {
publicAPI.getBindGroupLayout = (device) => {
const entries = [];
for (let i = 0; i < model.bindables.length; i++) {
model.bindables[i].setDevice?.(device);
const entry = model.bindables[i].getBindGroupLayoutEntry();
entry.binding = i;
entries.push(entry);
Expand All @@ -38,13 +41,19 @@ function vtkWebGPUBindGroup(publicAPI, model) {
};

publicAPI.getBindGroup = (device) => {
const deviceChanged = model.bindGroupDevice !== device;

for (let i = 0; i < model.bindables.length; i++) {
model.bindables[i].setDevice?.(device);
}

// check mtime
let mtime = publicAPI.getMTime();
for (let i = 0; i < model.bindables.length; i++) {
const tm = model.bindables[i].getBindGroupTime().getMTime();
mtime = tm > mtime ? tm : mtime;
}
if (mtime < model.bindGroupTime.getMTime()) {
if (!deviceChanged && mtime < model.bindGroupTime.getMTime()) {
return model.bindGroup;
}

Expand All @@ -60,19 +69,33 @@ function vtkWebGPUBindGroup(publicAPI, model) {
entries,
label: model.label,
});
model.bindGroupDevice = device;
model.bindGroupTime.modified();

return model.bindGroup;
};

publicAPI.getShaderCode = (pipeline) => {
const lines = [];
const bgroup = pipeline.getBindGroupLayoutCount(model.label);
const bgroup = pipeline.getBindGroupLayoutIndex(model.label);
if (bgroup < 0) {
vtkErrorMacro(
`vtkWebGPUBindGroup: bind group layout ${model.label} was not found in pipeline`
);
return '';
}
for (let i = 0; i < model.bindables.length; i++) {
lines.push(model.bindables[i].getShaderCode(i, bgroup));
}
return lines.join('\n');
};

publicAPI.releaseGraphicsResources = () => {
model.bindGroup = null;
model.bindGroupDevice = null;
model.bindGroupTime.modified();
publicAPI.modified();
};
}

// ----------------------------------------------------------------------------
Expand All @@ -82,6 +105,7 @@ function vtkWebGPUBindGroup(publicAPI, model) {
const DEFAULT_VALUES = {
device: null,
handle: null,
bindGroupDevice: null,
label: null,
};

Expand Down
14 changes: 14 additions & 0 deletions Sources/Rendering/WebGPU/ForwardPass/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,20 @@ function vtkForwardPass(publicAPI, model) {
publicAPI.addVolume = (volume) => {
model.volumes.push(volume);
};

publicAPI.releaseGraphicsResources = () => {
model.opaquePass?.releaseGraphicsResources?.();
model.translucentPass?.releaseGraphicsResources?.();
model.volumePass?.releaseGraphicsResources?.();

model.opaquePass = null;
model.translucentPass = null;
model.volumePass = null;
model._finalBlitEncoder = null;
model._finalBlitOutputTextureView = null;
model._fullScreenQuad = null;
model._fsqSampler = null;
};
}

// ----------------------------------------------------------------------------
Expand Down
4 changes: 2 additions & 2 deletions Sources/Rendering/WebGPU/IndexBuffer/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class _LimitedMap {
return true;
}
}
return undefined;
return false;
}

get(key) {
Expand Down Expand Up @@ -300,7 +300,7 @@ function vtkWebGPUIndexBuffer(publicAPI, model) {
} else {
state.flatIdToPointId = new Uint32Array(numPts + state.extraPoints);
}
if (numPts + state.extraPoints < 0x8fff) {
if (numPts + state.extraPoints <= 0x7fff) {
state.pointIdToFlatId = new Int16Array(numPts);
} else {
state.pointIdToFlatId = new Int32Array(numPts);
Expand Down
6 changes: 6 additions & 0 deletions Sources/Rendering/WebGPU/OpaquePass/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,12 @@ function vtkWebGPUOpaquePass(publicAPI, model) {
// default settings are fine for this
model.renderEncoder.setPipelineHash('op');
};

publicAPI.releaseGraphicsResources = () => {
model.renderEncoder = null;
model.colorTexture = null;
model.depthTexture = null;
};
}

// ----------------------------------------------------------------------------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,14 @@ function vtkWebGPUOrderIndependentTranslucentPass(publicAPI, model) {
},
});
};

publicAPI.releaseGraphicsResources = () => {
model.translucentRenderEncoder = null;
model.translucentFinalEncoder = null;
model.translucentColorTexture = null;
model.translucentAccumulateTexture = null;
model.fullScreenQuad = null;
};
}

// ----------------------------------------------------------------------------
Expand Down
4 changes: 2 additions & 2 deletions Sources/Rendering/WebGPU/Pipeline/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,13 +95,13 @@ function vtkWebGPUPipeline(publicAPI, model) {

publicAPI.getBindGroupLayout = (idx) => model.layouts[idx].layout;

publicAPI.getBindGroupLayoutCount = (llabel) => {
publicAPI.getBindGroupLayoutIndex = (llabel) => {
for (let i = 0; i < model.layouts.length; i++) {
if (model.layouts[i].label === llabel) {
return i;
}
}
return 0;
return -1; // Not found
};

publicAPI.bindVertexInput = (renderEncoder, vInput) => {
Expand Down
14 changes: 12 additions & 2 deletions Sources/Rendering/WebGPU/RenderEncoder/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import * as macro from 'vtk.js/Sources/macros';
import vtkWebGPUShaderCache from 'vtk.js/Sources/Rendering/WebGPU/ShaderCache';

const { vtkErrorMacro } = macro;

// methods we forward to the handle
const forwarded = [
'setBindGroup',
Expand Down Expand Up @@ -70,7 +72,9 @@ function vtkWebGPURenderEncoder(publicAPI, model) {
}

// check depth buffer
if (!model.depthTextureView !== !('depthStencil' in pd)) {
const hasDepthAttachment = !!model.depthTextureView;
const pipelineUsesDepth = 'depthStencil' in pd;
if (hasDepthAttachment !== pipelineUsesDepth) {
console.log('mismatched depth attachments');
console.trace();
} else if (model.depthTextureView) {
Expand Down Expand Up @@ -98,7 +102,13 @@ function vtkWebGPURenderEncoder(publicAPI, model) {

publicAPI.activateBindGroup = (bg) => {
const device = model.boundPipeline.getDevice();
const midx = model.boundPipeline.getBindGroupLayoutCount(bg.getLabel());
const midx = model.boundPipeline.getBindGroupLayoutIndex(bg.getLabel());
if (midx < 0) {
vtkErrorMacro(
`vtkWebGPURenderEncoder: could not find bind group layout ${bg.getLabel()}`
);
return;
}
model.handle.setBindGroup(midx, bg.getBindGroup(device));
// verify bind group layout matches
const bgl1 = device.getBindGroupLayoutDescription(
Expand Down
86 changes: 81 additions & 5 deletions Sources/Rendering/WebGPU/RenderWindow/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import vtkRenderPass from 'vtk.js/Sources/Rendering/SceneGraph/RenderPass';
import vtkRenderWindowViewNode from 'vtk.js/Sources/Rendering/SceneGraph/RenderWindowViewNode';
import HalfFloat from 'vtk.js/Sources/Common/Core/HalfFloat';

const { vtkErrorMacro } = macro;
const { vtkErrorMacro, vtkWarningMacro } = macro;
// const IS_CHROME = navigator.userAgent.indexOf('Chrome') !== -1;
const SCREENSHOT_PLACEHOLDER = {
position: 'absolute',
Expand All @@ -31,6 +31,66 @@ function vtkWebGPURenderWindow(publicAPI, model) {

publicAPI.getViewNodeFactory = () => model.myFactory;

function releaseViewNodeResources(viewNode, visited = new Set()) {
if (!viewNode || visited.has(viewNode)) {
return;
}
visited.add(viewNode);
Comment thread
daker marked this conversation as resolved.

const children = viewNode.getChildren?.() || [];
for (let i = 0; i < children.length; i++) {
const child = children[i];
child?.releaseGraphicsResources?.();
releaseViewNodeResources(child, visited);
}
}

function queueRenderAfterInitialization() {
const subscription = publicAPI.onInitialized(() => {
subscription.unsubscribe();
if (!model.deleted) {
publicAPI.traverseAllPasses();
}
});
}

function handleDeviceLost(info, deviceGeneration) {
if (
model.deleted ||
deviceGeneration !== model.deviceGeneration ||
model.handlingDeviceLost
) {
return;
}

model.handlingDeviceLost = true;
model.deviceLostInfo = info;

const reason = info?.reason ?? 'unknown';
const message = info?.message || 'WebGPU device was lost.';
vtkWarningMacro(`WebGPU device lost (${reason}): ${message}`);

publicAPI.releaseGraphicsResources();
publicAPI.invokeDeviceLost({
reason,
message,
recoverable: reason !== 'destroyed',
});

if (reason !== 'destroyed') {
queueRenderAfterInitialization();
publicAPI.initialize();
}

model.handlingDeviceLost = false;
}

function watchForDeviceLoss(deviceHandle, deviceGeneration) {
deviceHandle.lost.then((info) => {
handleDeviceLost(info, deviceGeneration);
});
}

// Auto update style
const previousSize = [0, 0];
function updateWindow() {
Expand Down Expand Up @@ -128,6 +188,7 @@ function vtkWebGPURenderWindow(publicAPI, model) {
publicAPI.initialize = () => {
if (!model.initializing) {
model.initializing = true;
model.deviceLostInfo = null;
if (!navigator.gpu) {
vtkErrorMacro('WebGPU is not enabled.');
return;
Expand Down Expand Up @@ -213,20 +274,29 @@ function vtkWebGPURenderWindow(publicAPI, model) {
model.device = null;
return;
}
// model.device.getHandle().lost.then((info) => {
// console.log(`${info.message}`);
// publicAPI.releaseGraphicsResources();
// });
model.deviceGeneration += 1;
watchForDeviceLoss(model.device.getHandle(), model.deviceGeneration);
model.context = model.canvas.getContext('webgpu');
};

publicAPI.releaseGraphicsResources = () => {
if (model.renderPasses) {
for (let i = 0; i < model.renderPasses.length; i++) {
model.renderPasses[i]?.releaseGraphicsResources?.();
}
}
releaseViewNodeResources(publicAPI);
const rp = vtkRenderPass.newInstance();
rp.setCurrentOperation('Release');
rp.traverse(publicAPI, null);
if (model.context) {
model.context.unconfigure();
}
model.adapter = null;
model.device = null;
model.context = null;
model.commandEncoder = null;
model._configured = false;
model.initialized = false;
model.initializing = false;
};
Expand Down Expand Up @@ -573,6 +643,10 @@ function vtkWebGPURenderWindow(publicAPI, model) {

const DEFAULT_VALUES = {
initialized: false,
initializing: false,
handlingDeviceLost: false,
deviceGeneration: 0,
deviceLostInfo: null,
context: null,
adapter: null,
device: null,
Expand Down Expand Up @@ -623,10 +697,12 @@ export function extend(publicAPI, model, initialValues = {}) {

macro.event(publicAPI, model, 'imageReady');
macro.event(publicAPI, model, 'initialized');
macro.event(publicAPI, model, 'deviceLost');

// Build VTK API
macro.get(publicAPI, model, [
'commandEncoder',
'deviceLostInfo',
'device',
'presentationFormat',
'useBackgroundImage',
Expand Down
7 changes: 7 additions & 0 deletions Sources/Rendering/WebGPU/Renderer/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -527,6 +527,13 @@ function vtkWebGPURenderer(publicAPI, model) {
if (model.selector !== null) {
model.selector.releaseGraphicsResources();
}
model.clearFSQ?.releaseGraphicsResources?.();
model.clearFSQ = null;
model.bindGroup.releaseGraphicsResources?.();
model.UBO.releaseGraphicsResources?.();
model.SSBO.releaseGraphicsResources?.();
model.renderEncoder = null;
model.backgroundTexLoaded = false;
};
}

Expand Down
10 changes: 10 additions & 0 deletions Sources/Rendering/WebGPU/SimpleMapper/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,16 @@ function vtkWebGPUSimpleMapper(publicAPI, model) {
model.device.createPipeline(model.pipelineHash, model.pipeline);
}
};

publicAPI.releaseGraphicsResources = () => {
model.vertexInput?.releaseGraphicsResources?.();
model.bindGroup?.releaseGraphicsResources?.();
model.UBO?.releaseGraphicsResources?.();
model.SSBO?.releaseGraphicsResources?.();
model.pipeline = null;
model.renderEncoder = null;
model.textureViews.length = 0;
};
}

// ----------------------------------------------------------------------------
Expand Down
Loading
Loading