@cornerstonejs/core 5.2.2 → 5.3.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/dist/esm/RenderingEngine/ContextPoolRenderingEngine.js +1 -1
- package/dist/esm/RenderingEngine/GenericViewport/GenericViewport.d.ts +1 -0
- package/dist/esm/RenderingEngine/GenericViewport/GenericViewport.js +3 -5
- package/dist/esm/RenderingEngine/GenericViewport/Planar/CpuImageSliceRenderPath.js +7 -3
- package/dist/esm/RenderingEngine/GenericViewport/Planar/PlanarRenderPathDecisionService.d.ts +4 -10
- package/dist/esm/RenderingEngine/GenericViewport/Planar/PlanarRenderPathDecisionService.js +8 -52
- package/dist/esm/RenderingEngine/GenericViewport/Planar/PlanarViewport.d.ts +7 -0
- package/dist/esm/RenderingEngine/GenericViewport/Planar/PlanarViewport.js +120 -9
- package/dist/esm/RenderingEngine/GenericViewport/Planar/PlanarViewportTypes.d.ts +2 -6
- package/dist/esm/RenderingEngine/GenericViewport/Planar/planarRenderPathSelector.d.ts +1 -1
- package/dist/esm/RenderingEngine/GenericViewport/Planar/planarRenderPathSelector.js +1 -1
- package/dist/esm/RenderingEngine/TiledRenderingEngine.js +2 -0
- package/dist/esm/RenderingEngine/WebGLContextPool.d.ts +1 -1
- package/dist/esm/RenderingEngine/WebGLContextPool.js +3 -1
- package/dist/esm/RenderingEngine/helpers/attachWebGLContextEvents.d.ts +2 -0
- package/dist/esm/RenderingEngine/helpers/attachWebGLContextEvents.js +22 -0
- package/dist/esm/enums/Events.d.ts +6 -1
- package/dist/esm/enums/Events.js +5 -0
- package/dist/esm/enums/RenderBackend.d.ts +7 -0
- package/dist/esm/enums/RenderBackend.js +7 -0
- package/dist/esm/enums/index.d.ts +2 -1
- package/dist/esm/enums/index.js +2 -1
- package/dist/esm/index.d.ts +3 -2
- package/dist/esm/index.js +3 -2
- package/dist/esm/init.d.ts +7 -1
- package/dist/esm/init.js +75 -32
- package/dist/esm/types/Cornerstone3DConfig.d.ts +2 -7
- package/dist/esm/utilities/renderingCapabilities.d.ts +16 -0
- package/dist/esm/utilities/renderingCapabilities.js +123 -0
- package/dist/esm/utilities/textureSupport.d.ts +7 -2
- package/dist/esm/utilities/textureSupport.js +68 -24
- package/dist/esm/version.d.ts +1 -1
- package/dist/esm/version.js +1 -1
- package/package.json +6 -6
|
@@ -43,7 +43,7 @@ class ContextPoolRenderingEngine extends BaseRenderingEngine {
|
|
|
43
43
|
if (!this.contextPool) {
|
|
44
44
|
const { rendering } = getConfiguration();
|
|
45
45
|
const { webGlContextCount } = rendering;
|
|
46
|
-
this.contextPool = new WebGLContextPool(webGlContextCount);
|
|
46
|
+
this.contextPool = new WebGLContextPool(webGlContextCount, this.id);
|
|
47
47
|
}
|
|
48
48
|
return this.contextPool;
|
|
49
49
|
}
|
|
@@ -60,6 +60,7 @@ declare abstract class GenericViewport<TViewState extends object, TDataPresentat
|
|
|
60
60
|
setRendered(): void;
|
|
61
61
|
setNeedsRender(): void;
|
|
62
62
|
abstract render(): void;
|
|
63
|
+
updateRenderingPipeline(): void;
|
|
63
64
|
resize(): void;
|
|
64
65
|
resetViewState(_options?: unknown): boolean;
|
|
65
66
|
resizeForRenderingEngine({ keepCamera, }?: RenderingEngineResizeOptions): void;
|
|
@@ -161,6 +161,8 @@ class GenericViewport {
|
|
|
161
161
|
setNeedsRender() {
|
|
162
162
|
this.viewportStatus = ViewportStatus.NEEDS_RENDER;
|
|
163
163
|
}
|
|
164
|
+
updateRenderingPipeline() {
|
|
165
|
+
}
|
|
164
166
|
resize() {
|
|
165
167
|
if (this.isDestroyed) {
|
|
166
168
|
return;
|
|
@@ -190,10 +192,6 @@ class GenericViewport {
|
|
|
190
192
|
const path = this.renderPathResolver.resolve(this.type, data, options);
|
|
191
193
|
const renderPath = path.createRenderPath();
|
|
192
194
|
const ctx = path.selectContext?.(this.renderContext) ?? this.renderContext;
|
|
193
|
-
const existing = this.bindings.get(displaySetId);
|
|
194
|
-
if (existing) {
|
|
195
|
-
existing.removeData();
|
|
196
|
-
}
|
|
197
195
|
const attachment = await renderPath.addData(ctx, data, options);
|
|
198
196
|
if (shouldIgnore?.()) {
|
|
199
197
|
attachment.removeData();
|
|
@@ -204,7 +202,7 @@ class GenericViewport {
|
|
|
204
202
|
throw new Error('Viewport has been destroyed');
|
|
205
203
|
}
|
|
206
204
|
const current = this.bindings.get(displaySetId);
|
|
207
|
-
if (current
|
|
205
|
+
if (current) {
|
|
208
206
|
current.removeData();
|
|
209
207
|
}
|
|
210
208
|
const role = options.role ?? 'overlay';
|
|
@@ -33,7 +33,7 @@ export class CpuImageSliceRenderPath {
|
|
|
33
33
|
getImageData: () => this.getImageData(rendering),
|
|
34
34
|
}, payload.image);
|
|
35
35
|
compatibilityActor.setVisibility(true);
|
|
36
|
-
const defaultViewport = getDefaultViewport(ctx.cpu.canvas, payload.image);
|
|
36
|
+
const defaultViewport = getDefaultViewport(ctx.cpu.canvas, payload.image, getCPUFallbackViewportModality(payload.image));
|
|
37
37
|
defaultViewport.displayedArea = resolvePlanarCpuImageDisplayedArea(payload.image);
|
|
38
38
|
const enabledElement = {
|
|
39
39
|
canvas: ctx.cpu.canvas,
|
|
@@ -196,7 +196,7 @@ export class CpuImageSliceRenderPath {
|
|
|
196
196
|
rendering,
|
|
197
197
|
viewState: camera,
|
|
198
198
|
});
|
|
199
|
-
rendering.fitScale = getCPUFallbackScalarScale(getDefaultViewport(rendering.enabledElement.canvas, image).scale);
|
|
199
|
+
rendering.fitScale = getCPUFallbackScalarScale(getDefaultViewport(rendering.enabledElement.canvas, image, getCPUFallbackViewportModality(image)).scale);
|
|
200
200
|
rendering.renderingInvalidated = true;
|
|
201
201
|
if (projection) {
|
|
202
202
|
applyPresentationState(rendering, projection.presentation, projection.resolvedICamera);
|
|
@@ -359,6 +359,10 @@ function worldToCPUImageDrawPoint(enabledElement, worldPos) {
|
|
|
359
359
|
function markCpuImagePreScaled(image) {
|
|
360
360
|
image.isPreScaled = image.preScale?.scaled;
|
|
361
361
|
}
|
|
362
|
+
function getCPUFallbackViewportModality(image) {
|
|
363
|
+
return (image.preScale?.scalingParameters?.modality ||
|
|
364
|
+
metaData.get(MetadataModules.GENERAL_SERIES, image.imageId)?.modality);
|
|
365
|
+
}
|
|
362
366
|
export function buildPlanarImageData(image, frameOfReferenceUID) {
|
|
363
367
|
const metadata = getImageDataMetadata(image);
|
|
364
368
|
const { dimensions, direction, modality, origin, spacing } = metadata;
|
|
@@ -428,7 +432,7 @@ async function updateRenderedImage(args) {
|
|
|
428
432
|
const enabledElement = rendering.enabledElement;
|
|
429
433
|
markCpuImagePreScaled(image);
|
|
430
434
|
const camera = ctx.viewport.getViewState();
|
|
431
|
-
const defaultViewport = getDefaultViewport(ctx.cpu.canvas, image);
|
|
435
|
+
const defaultViewport = getDefaultViewport(ctx.cpu.canvas, image, getCPUFallbackViewportModality(image));
|
|
432
436
|
const previousViewport = enabledElement.viewport;
|
|
433
437
|
defaultViewport.displayedArea = resolvePlanarCpuImageDisplayedArea(image);
|
|
434
438
|
enabledElement.image = image;
|
package/dist/esm/RenderingEngine/GenericViewport/Planar/PlanarRenderPathDecisionService.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { RenderBackend } from '../../../enums/index.js';
|
|
2
|
+
import type { RenderBackendValue } from '../../../enums/index.js';
|
|
1
3
|
import type { PlanarViewState, PlanarEffectiveRenderMode, PlanarOrientation, PlanarRegisteredDataSet } from './PlanarViewportTypes.js';
|
|
2
|
-
export declare const DEFAULT_PLANAR_CPU_IMAGE_THRESHOLD: number;
|
|
3
|
-
export declare const DEFAULT_PLANAR_CPU_VOLUME_THRESHOLD: number;
|
|
4
4
|
export interface SelectedPlanarRenderPath {
|
|
5
5
|
acquisitionOrientation?: PlanarViewState['orientation'];
|
|
6
6
|
renderMode: PlanarEffectiveRenderMode;
|
|
@@ -8,22 +8,16 @@ export interface SelectedPlanarRenderPath {
|
|
|
8
8
|
}
|
|
9
9
|
export interface PlanarRenderPathDecisionOptions {
|
|
10
10
|
orientation?: PlanarOrientation;
|
|
11
|
-
cpuThresholds?: {
|
|
12
|
-
image?: number;
|
|
13
|
-
volume?: number;
|
|
14
|
-
};
|
|
15
11
|
useSliceRendering?: boolean;
|
|
16
|
-
|
|
12
|
+
renderBackend?: RenderBackend | RenderBackendValue;
|
|
17
13
|
}
|
|
18
14
|
export declare class PlanarRenderPathDecisionService {
|
|
19
15
|
select(dataSet: PlanarRegisteredDataSet, options?: PlanarRenderPathDecisionOptions): SelectedPlanarRenderPath;
|
|
20
16
|
canRender(dataSet: PlanarRegisteredDataSet, options?: PlanarRenderPathDecisionOptions): boolean;
|
|
21
17
|
private selectImageRenderMode;
|
|
22
18
|
private selectVolumeRenderMode;
|
|
23
|
-
private
|
|
24
|
-
private shouldUseCPUForVolume;
|
|
19
|
+
private resolveBackend;
|
|
25
20
|
}
|
|
26
21
|
export declare const defaultPlanarRenderPathDecisionService: PlanarRenderPathDecisionService;
|
|
27
22
|
export declare function selectPlanarRenderPath(dataSet: PlanarRegisteredDataSet, options?: PlanarRenderPathDecisionOptions): SelectedPlanarRenderPath;
|
|
28
23
|
export declare function getPlanarAcquisitionOrientation(imageIds: string[]): PlanarViewState['orientation'] | undefined;
|
|
29
|
-
export declare function shouldUseCPU(imageIds: string[], threshold?: number): boolean;
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
import { vec3 } from 'gl-matrix';
|
|
2
2
|
import cache from '../../../cache/cache.js';
|
|
3
|
-
import { OrientationAxis } from '../../../enums/index.js';
|
|
4
|
-
import {
|
|
3
|
+
import { OrientationAxis, RenderBackend } from '../../../enums/index.js';
|
|
4
|
+
import { getEffectiveRenderBackend } from '../../../init.js';
|
|
5
5
|
import * as metaData from '../../../metaData.js';
|
|
6
6
|
import { ActorRenderMode } from '../../../types/index.js';
|
|
7
7
|
import { isValidVolume } from '../../../utilities/isValidVolume.js';
|
|
8
8
|
import { getOrientationFromScanAxisNormal } from '../../helpers/getCameraVectors.js';
|
|
9
|
-
export const DEFAULT_PLANAR_CPU_IMAGE_THRESHOLD = 64 * 1024 * 1024;
|
|
10
|
-
export const DEFAULT_PLANAR_CPU_VOLUME_THRESHOLD = Number.POSITIVE_INFINITY;
|
|
11
9
|
export class PlanarRenderPathDecisionService {
|
|
12
10
|
select(dataSet, options = {}) {
|
|
13
11
|
if (!dataSet.imageIds.length) {
|
|
@@ -31,7 +29,7 @@ export class PlanarRenderPathDecisionService {
|
|
|
31
29
|
return {
|
|
32
30
|
acquisitionOrientation,
|
|
33
31
|
renderMode: useVolumePath
|
|
34
|
-
? this.selectVolumeRenderMode(
|
|
32
|
+
? this.selectVolumeRenderMode(options)
|
|
35
33
|
: this.selectImageRenderMode(options),
|
|
36
34
|
volumeId,
|
|
37
35
|
};
|
|
@@ -57,29 +55,17 @@ export class PlanarRenderPathDecisionService {
|
|
|
57
55
|
return true;
|
|
58
56
|
}
|
|
59
57
|
selectImageRenderMode(options) {
|
|
60
|
-
return this.
|
|
58
|
+
return this.resolveBackend(options) === RenderBackend.CPU
|
|
61
59
|
? ActorRenderMode.CPU_IMAGE
|
|
62
60
|
: ActorRenderMode.VTK_IMAGE;
|
|
63
61
|
}
|
|
64
|
-
selectVolumeRenderMode(
|
|
65
|
-
return this.
|
|
62
|
+
selectVolumeRenderMode(options) {
|
|
63
|
+
return this.resolveBackend(options) === RenderBackend.CPU
|
|
66
64
|
? ActorRenderMode.CPU_VOLUME
|
|
67
65
|
: ActorRenderMode.VTK_VOLUME_SLICE;
|
|
68
66
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
return true;
|
|
72
|
-
}
|
|
73
|
-
return getShouldUseCPURendering();
|
|
74
|
-
}
|
|
75
|
-
shouldUseCPUForVolume(dataSet, options) {
|
|
76
|
-
if (options.webGLAvailable === false) {
|
|
77
|
-
return true;
|
|
78
|
-
}
|
|
79
|
-
const configuredCpuThresholds = getConfiguredPlanarCpuThresholds();
|
|
80
|
-
return shouldUseCPU(dataSet.imageIds, options.cpuThresholds?.volume ??
|
|
81
|
-
configuredCpuThresholds?.volume ??
|
|
82
|
-
DEFAULT_PLANAR_CPU_VOLUME_THRESHOLD);
|
|
67
|
+
resolveBackend(options) {
|
|
68
|
+
return getEffectiveRenderBackend(options.renderBackend);
|
|
83
69
|
}
|
|
84
70
|
}
|
|
85
71
|
export const defaultPlanarRenderPathDecisionService = new PlanarRenderPathDecisionService();
|
|
@@ -112,30 +98,6 @@ export function getPlanarAcquisitionOrientation(imageIds) {
|
|
|
112
98
|
}
|
|
113
99
|
return orientation;
|
|
114
100
|
}
|
|
115
|
-
export function shouldUseCPU(imageIds, threshold = DEFAULT_PLANAR_CPU_IMAGE_THRESHOLD) {
|
|
116
|
-
if (getShouldUseCPURendering()) {
|
|
117
|
-
return true;
|
|
118
|
-
}
|
|
119
|
-
const imageId = imageIds[0];
|
|
120
|
-
if (!imageId) {
|
|
121
|
-
return false;
|
|
122
|
-
}
|
|
123
|
-
const imagePlaneModule = metaData.get('imagePlaneModule', imageId);
|
|
124
|
-
const rows = imagePlaneModule?.rows;
|
|
125
|
-
const columns = imagePlaneModule?.columns;
|
|
126
|
-
if (!isPositiveSafeInteger(rows) || !isPositiveSafeInteger(columns)) {
|
|
127
|
-
return false;
|
|
128
|
-
}
|
|
129
|
-
if (!Number.isFinite(threshold)) {
|
|
130
|
-
return false;
|
|
131
|
-
}
|
|
132
|
-
const normalizedThreshold = Math.trunc(threshold);
|
|
133
|
-
if (!Number.isSafeInteger(normalizedThreshold) || normalizedThreshold < 0) {
|
|
134
|
-
return false;
|
|
135
|
-
}
|
|
136
|
-
return (BigInt(rows) * BigInt(columns) * BigInt(imageIds.length) >=
|
|
137
|
-
BigInt(normalizedThreshold));
|
|
138
|
-
}
|
|
139
101
|
function getVolumeId(dataSet) {
|
|
140
102
|
return dataSet.volumeId || cache.generateVolumeId(dataSet.imageIds);
|
|
141
103
|
}
|
|
@@ -154,9 +116,3 @@ function isVolumeBackedDataSet(dataSet, isAcquisitionPath) {
|
|
|
154
116
|
}
|
|
155
117
|
return !isAcquisitionPath && supportsVolumeRendering(dataSet);
|
|
156
118
|
}
|
|
157
|
-
function isPositiveSafeInteger(value) {
|
|
158
|
-
return typeof value === 'number' && Number.isSafeInteger(value) && value > 0;
|
|
159
|
-
}
|
|
160
|
-
function getConfiguredPlanarCpuThresholds() {
|
|
161
|
-
return getConfiguration().rendering?.planar?.cpuThresholds;
|
|
162
|
-
}
|
|
@@ -35,6 +35,9 @@ declare class PlanarViewport extends GenericViewport<PlanarViewState, PlanarData
|
|
|
35
35
|
private resolvedViewCacheRevision;
|
|
36
36
|
private cachedCanvasDimensions?;
|
|
37
37
|
private setDataRequestId;
|
|
38
|
+
private renderPipelineSwapId;
|
|
39
|
+
private readonly lastRenderPathErrorByDataId;
|
|
40
|
+
private readonly mountOptionsByDataId;
|
|
38
41
|
static get useCustomRenderingPipeline(): boolean;
|
|
39
42
|
constructor(args: PlanarViewportInput);
|
|
40
43
|
setDisplaySets(...entries: Array<{
|
|
@@ -130,6 +133,9 @@ declare class PlanarViewport extends GenericViewport<PlanarViewState, PlanarData
|
|
|
130
133
|
protected onDestroy(): void;
|
|
131
134
|
protected modified(previousCamera?: ICamera): void;
|
|
132
135
|
protected renderBindings(): boolean;
|
|
136
|
+
updateRenderingPipeline(): void;
|
|
137
|
+
private applyRenderingPipelineUpdate;
|
|
138
|
+
private reportRenderPathError;
|
|
133
139
|
private requestRenderingEngineRender;
|
|
134
140
|
private setRenderModeVisibility;
|
|
135
141
|
protected createLegacyCompatibilityHost(): {
|
|
@@ -168,6 +174,7 @@ declare class PlanarViewport extends GenericViewport<PlanarViewState, PlanarData
|
|
|
168
174
|
private isSegmentationOverlayBinding;
|
|
169
175
|
private getDataSet;
|
|
170
176
|
private loadPlanarData;
|
|
177
|
+
private getInheritedOverlayRenderBackend;
|
|
171
178
|
private applyLoadedPlanarViewState;
|
|
172
179
|
private createInitialVolumeSliceState;
|
|
173
180
|
private resolveRequestedOrientation;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Events, OrientationAxis, ViewportStatus, ViewportType, VOILUTFunctionType, } from '../../../enums/index.js';
|
|
1
|
+
import { Events, OrientationAxis, RenderBackend, ViewportStatus, ViewportType, VOILUTFunctionType, } from '../../../enums/index.js';
|
|
2
2
|
import { ActorRenderMode } from '../../../types/index.js';
|
|
3
3
|
import { isImageActor } from '../../../utilities/actorCheck.js';
|
|
4
4
|
import cache from '../../../cache/cache.js';
|
|
@@ -7,6 +7,7 @@ import imageIdToURI from '../../../utilities/imageIdToURI.js';
|
|
|
7
7
|
import { getImageDataMetadata } from '../../../utilities/getImageDataMetadata.js';
|
|
8
8
|
import genericViewportDisplaySetMetadataProvider from '../../../utilities/genericViewportDisplaySetMetadataProvider.js';
|
|
9
9
|
import triggerEvent from '../../../utilities/triggerEvent.js';
|
|
10
|
+
import eventTarget from '../../../eventTarget.js';
|
|
10
11
|
import getMinMax from '../../../utilities/getMinMax.js';
|
|
11
12
|
import renderingEngineCache from '../../renderingEngineCache.js';
|
|
12
13
|
import { getCameraVectors } from '../../helpers/getCameraVectors.js';
|
|
@@ -35,6 +36,9 @@ class PlanarViewport extends GenericViewport {
|
|
|
35
36
|
this.suppressEvents = false;
|
|
36
37
|
this.resolvedViewCacheRevision = 0;
|
|
37
38
|
this.setDataRequestId = 0;
|
|
39
|
+
this.renderPipelineSwapId = 0;
|
|
40
|
+
this.lastRenderPathErrorByDataId = new Map();
|
|
41
|
+
this.mountOptionsByDataId = new Map();
|
|
38
42
|
this.renderingEngineId = args.renderingEngineId;
|
|
39
43
|
this.canvas = args.canvas;
|
|
40
44
|
this.sWidth = args.sWidth;
|
|
@@ -200,6 +204,7 @@ class PlanarViewport extends GenericViewport {
|
|
|
200
204
|
if (!added) {
|
|
201
205
|
return;
|
|
202
206
|
}
|
|
207
|
+
this.mountOptionsByDataId.set(dataId, resolvedOptions);
|
|
203
208
|
this.clearResolvedViewCache();
|
|
204
209
|
this.setDefaultDataPresentation(dataId, {
|
|
205
210
|
visible: true,
|
|
@@ -215,6 +220,8 @@ class PlanarViewport extends GenericViewport {
|
|
|
215
220
|
}
|
|
216
221
|
removeData(dataId) {
|
|
217
222
|
this.clearResolvedViewCache();
|
|
223
|
+
this.mountOptionsByDataId.delete(dataId);
|
|
224
|
+
this.lastRenderPathErrorByDataId.delete(dataId);
|
|
218
225
|
super.removeData(dataId);
|
|
219
226
|
this.mountedData.handleRemovedData(dataId);
|
|
220
227
|
if (!this.isDestroyed && this.getCurrentBinding()) {
|
|
@@ -764,17 +771,106 @@ class PlanarViewport extends GenericViewport {
|
|
|
764
771
|
}
|
|
765
772
|
let renderedByAdapter = false;
|
|
766
773
|
const sourceBinding = this.getCurrentBinding();
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
774
|
+
const renderBinding = (binding, dataId) => {
|
|
775
|
+
if (!binding.render) {
|
|
776
|
+
return;
|
|
777
|
+
}
|
|
778
|
+
renderedByAdapter = true;
|
|
779
|
+
try {
|
|
780
|
+
binding.render();
|
|
781
|
+
this.lastRenderPathErrorByDataId.delete(dataId);
|
|
782
|
+
}
|
|
783
|
+
catch (error) {
|
|
784
|
+
this.reportRenderPathError(error, dataId);
|
|
785
|
+
}
|
|
786
|
+
};
|
|
787
|
+
for (const [dataId, binding] of this.bindings.entries()) {
|
|
770
788
|
if (binding === sourceBinding) {
|
|
771
|
-
|
|
789
|
+
renderBinding(binding, dataId);
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
for (const [dataId, binding] of this.bindings.entries()) {
|
|
793
|
+
if (binding !== sourceBinding) {
|
|
794
|
+
renderBinding(binding, dataId);
|
|
772
795
|
}
|
|
773
|
-
binding.render?.();
|
|
774
|
-
renderedByAdapter = renderedByAdapter || Boolean(binding.render);
|
|
775
796
|
}
|
|
776
797
|
return renderedByAdapter;
|
|
777
798
|
}
|
|
799
|
+
updateRenderingPipeline() {
|
|
800
|
+
void this.applyRenderingPipelineUpdate();
|
|
801
|
+
}
|
|
802
|
+
async applyRenderingPipelineUpdate() {
|
|
803
|
+
if (this.isDestroyed) {
|
|
804
|
+
return;
|
|
805
|
+
}
|
|
806
|
+
const swapId = ++this.renderPipelineSwapId;
|
|
807
|
+
const isStale = () => swapId !== this.renderPipelineSwapId || this.isDestroyed;
|
|
808
|
+
let changed = false;
|
|
809
|
+
const sourceBinding = this.getCurrentBinding();
|
|
810
|
+
const bindingEntries = Array.from(this.bindings.entries());
|
|
811
|
+
const orderedEntries = [
|
|
812
|
+
...bindingEntries.filter(([, binding]) => binding === sourceBinding),
|
|
813
|
+
...bindingEntries.filter(([, binding]) => binding !== sourceBinding),
|
|
814
|
+
];
|
|
815
|
+
for (const [dataId, binding] of orderedEntries) {
|
|
816
|
+
if (isStale()) {
|
|
817
|
+
return;
|
|
818
|
+
}
|
|
819
|
+
if (this.bindings.get(dataId) !== binding) {
|
|
820
|
+
continue;
|
|
821
|
+
}
|
|
822
|
+
const options = this.mountOptionsByDataId.get(dataId) ?? {};
|
|
823
|
+
try {
|
|
824
|
+
const { data, selectedPath } = await this.loadPlanarData(dataId, {
|
|
825
|
+
...options,
|
|
826
|
+
role: binding.role,
|
|
827
|
+
});
|
|
828
|
+
if (isStale() || this.bindings.get(dataId) !== binding) {
|
|
829
|
+
continue;
|
|
830
|
+
}
|
|
831
|
+
if (selectedPath.renderMode === binding.rendering.renderMode) {
|
|
832
|
+
continue;
|
|
833
|
+
}
|
|
834
|
+
const added = await this.addLoadedData(dataId, data, {
|
|
835
|
+
renderMode: selectedPath.renderMode,
|
|
836
|
+
role: binding.role,
|
|
837
|
+
}, () => isStale() || this.bindings.get(dataId) !== binding);
|
|
838
|
+
changed = changed || added;
|
|
839
|
+
}
|
|
840
|
+
catch (error) {
|
|
841
|
+
this.reportRenderPathError(error, dataId);
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
if (isStale() || !changed) {
|
|
845
|
+
return;
|
|
846
|
+
}
|
|
847
|
+
const sourceRenderMode = this.getCurrentPlanarRendering()?.renderMode;
|
|
848
|
+
if (sourceRenderMode) {
|
|
849
|
+
this.renderContext.display.activateRenderMode(sourceRenderMode);
|
|
850
|
+
}
|
|
851
|
+
this.clearResolvedViewCache();
|
|
852
|
+
this.updateBindingsCameraState();
|
|
853
|
+
this.render();
|
|
854
|
+
triggerEvent(eventTarget, Events.RENDERING_PIPELINE_CHANGED, {
|
|
855
|
+
renderingEngineId: this.renderingEngineId,
|
|
856
|
+
viewportId: this.id,
|
|
857
|
+
});
|
|
858
|
+
}
|
|
859
|
+
reportRenderPathError(error, dataId) {
|
|
860
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
861
|
+
const errorKey = dataId ?? '';
|
|
862
|
+
if (this.lastRenderPathErrorByDataId.get(errorKey) === message) {
|
|
863
|
+
return;
|
|
864
|
+
}
|
|
865
|
+
this.lastRenderPathErrorByDataId.set(errorKey, message);
|
|
866
|
+
console.error('[PlanarViewport] Render path error', dataId ?? '', error);
|
|
867
|
+
triggerEvent(eventTarget, Events.RENDER_PATH_ERROR, {
|
|
868
|
+
renderingEngineId: this.renderingEngineId,
|
|
869
|
+
viewportId: this.id,
|
|
870
|
+
dataId,
|
|
871
|
+
error,
|
|
872
|
+
});
|
|
873
|
+
}
|
|
778
874
|
requestRenderingEngineRender() {
|
|
779
875
|
const renderingEngine = renderingEngineCache.get(this.renderingEngineId);
|
|
780
876
|
if (renderingEngine) {
|
|
@@ -927,8 +1023,8 @@ class PlanarViewport extends GenericViewport {
|
|
|
927
1023
|
const resolvedOrientation = this.resolveRequestedOrientation(options.orientation);
|
|
928
1024
|
const selectedPath = selectPlanarRenderPath(dataSet, {
|
|
929
1025
|
orientation: resolvedOrientation,
|
|
930
|
-
|
|
931
|
-
|
|
1026
|
+
renderBackend: options.renderBackend ??
|
|
1027
|
+
this.getInheritedOverlayRenderBackend(options.role),
|
|
932
1028
|
});
|
|
933
1029
|
const data = await this.dataProvider.load(dataId, {
|
|
934
1030
|
acquisitionOrientation: selectedPath.acquisitionOrientation,
|
|
@@ -942,6 +1038,21 @@ class PlanarViewport extends GenericViewport {
|
|
|
942
1038
|
resolvedOrientation,
|
|
943
1039
|
};
|
|
944
1040
|
}
|
|
1041
|
+
getInheritedOverlayRenderBackend(role) {
|
|
1042
|
+
if (role === 'source') {
|
|
1043
|
+
return undefined;
|
|
1044
|
+
}
|
|
1045
|
+
switch (this.getCurrentPlanarRendering()?.renderMode) {
|
|
1046
|
+
case ActorRenderMode.CPU_IMAGE:
|
|
1047
|
+
case ActorRenderMode.CPU_VOLUME:
|
|
1048
|
+
return RenderBackend.CPU;
|
|
1049
|
+
case ActorRenderMode.VTK_IMAGE:
|
|
1050
|
+
case ActorRenderMode.VTK_VOLUME_SLICE:
|
|
1051
|
+
return RenderBackend.GPU;
|
|
1052
|
+
default:
|
|
1053
|
+
return undefined;
|
|
1054
|
+
}
|
|
1055
|
+
}
|
|
945
1056
|
applyLoadedPlanarViewState(resolvedOrientation, planarData, selectedPath) {
|
|
946
1057
|
const isVolumePath = selectedPath.renderMode === ActorRenderMode.CPU_VOLUME ||
|
|
947
1058
|
selectedPath.renderMode === ActorRenderMode.VTK_VOLUME_SLICE;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type vtkRenderer from '@kitware/vtk.js/Rendering/Core/Renderer';
|
|
2
2
|
import type vtkImageData from '@kitware/vtk.js/Common/DataModel/ImageData';
|
|
3
|
-
import type { BlendModes, InterpolationType, OrientationAxis, VOILUTFunctionType } from '../../../enums/index.js';
|
|
3
|
+
import type { BlendModes, InterpolationType, OrientationAxis, RenderBackend, RenderBackendValue, VOILUTFunctionType } from '../../../enums/index.js';
|
|
4
4
|
import type { ActorEntry, ActorRenderMode, ColormapPublic, IImage, IImageVolume, OrientationVectors, Point2, Point3, VOIRange } from '../../../types/index.js';
|
|
5
5
|
import type { ViewportInput } from '../../../types/IViewport.js';
|
|
6
6
|
import type ViewportInputOptions from '../../../types/ViewportInputOptions.js';
|
|
@@ -24,11 +24,7 @@ export interface PlanarRegisteredDataSet {
|
|
|
24
24
|
}
|
|
25
25
|
export interface PlanarSetDataOptions {
|
|
26
26
|
orientation?: PlanarOrientation;
|
|
27
|
-
|
|
28
|
-
image?: number;
|
|
29
|
-
volume?: number;
|
|
30
|
-
};
|
|
31
|
-
forceCPU?: boolean;
|
|
27
|
+
renderBackend?: RenderBackend | RenderBackendValue;
|
|
32
28
|
role?: BindingRole;
|
|
33
29
|
}
|
|
34
30
|
export interface PlanarDataLoadOptions {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { PlanarViewState, PlanarOrientation } from './PlanarViewportTypes.js';
|
|
2
|
-
export {
|
|
2
|
+
export { PlanarRenderPathDecisionService, defaultPlanarRenderPathDecisionService, getPlanarAcquisitionOrientation, selectPlanarRenderPath, } from './PlanarRenderPathDecisionService.js';
|
|
3
3
|
export type { PlanarRenderPathDecisionOptions, SelectedPlanarRenderPath, } from './PlanarRenderPathDecisionService.js';
|
|
4
4
|
export declare function normalizePlanarOrientation(orientation: PlanarOrientation | undefined, acquisitionOrientation?: PlanarViewState['orientation']): PlanarViewState['orientation'];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { OrientationAxis } from '../../../enums/index.js';
|
|
2
2
|
import { clonePlanarOrientation } from './planarLegacyCompatibility.js';
|
|
3
|
-
export {
|
|
3
|
+
export { PlanarRenderPathDecisionService, defaultPlanarRenderPathDecisionService, getPlanarAcquisitionOrientation, selectPlanarRenderPath, } from './PlanarRenderPathDecisionService.js';
|
|
4
4
|
export function normalizePlanarOrientation(orientation, acquisitionOrientation) {
|
|
5
5
|
if (!orientation || orientation === OrientationAxis.ACQUISITION) {
|
|
6
6
|
return OrientationAxis.ACQUISITION;
|
|
@@ -5,6 +5,7 @@ import triggerEvent from '../utilities/triggerEvent.js';
|
|
|
5
5
|
import viewportTypeUsesCustomRenderingPipeline from './helpers/viewportTypeUsesCustomRenderingPipeline.js';
|
|
6
6
|
import getOrCreateCanvas from './helpers/getOrCreateCanvas.js';
|
|
7
7
|
import { vtkOffscreenMultiRenderWindow } from './vtkClasses/index.js';
|
|
8
|
+
import { attachWebGLContextEvents } from './helpers/attachWebGLContextEvents.js';
|
|
8
9
|
import { getViewportClassForInput } from './helpers/viewportTypeToViewportClass.js';
|
|
9
10
|
class TiledRenderingEngine extends BaseRenderingEngine {
|
|
10
11
|
constructor(id) {
|
|
@@ -47,6 +48,7 @@ class TiledRenderingEngine extends BaseRenderingEngine {
|
|
|
47
48
|
vtkOffscreenMultiRenderWindow.newInstance();
|
|
48
49
|
this.offScreenCanvasContainer = document.createElement('div');
|
|
49
50
|
this.offscreenMultiRenderWindow.setContainer(this.offScreenCanvasContainer);
|
|
51
|
+
attachWebGLContextEvents(this.offscreenMultiRenderWindow, this.id);
|
|
50
52
|
}
|
|
51
53
|
}
|
|
52
54
|
enableVTKjsDrivenViewport(viewportInputEntry) {
|
|
@@ -5,7 +5,7 @@ declare class WebGLContextPool {
|
|
|
5
5
|
private viewportToContext;
|
|
6
6
|
private viewportSizes;
|
|
7
7
|
private contextMaxSizes;
|
|
8
|
-
constructor(count: number);
|
|
8
|
+
constructor(count: number, renderingEngineId?: string);
|
|
9
9
|
getContextByIndex(index: number): {
|
|
10
10
|
context: VtkOffscreenMultiRenderWindow;
|
|
11
11
|
container: HTMLDivElement;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { vtkOffscreenMultiRenderWindow } from './vtkClasses/index.js';
|
|
2
|
+
import { attachWebGLContextEvents } from './helpers/attachWebGLContextEvents.js';
|
|
2
3
|
class WebGLContextPool {
|
|
3
|
-
constructor(count) {
|
|
4
|
+
constructor(count, renderingEngineId = '') {
|
|
4
5
|
this.contexts = [];
|
|
5
6
|
this.offScreenCanvasContainers = [];
|
|
6
7
|
this.viewportToContext = new Map();
|
|
@@ -10,6 +11,7 @@ class WebGLContextPool {
|
|
|
10
11
|
const offscreenMultiRenderWindow = vtkOffscreenMultiRenderWindow.newInstance();
|
|
11
12
|
const container = document.createElement('div');
|
|
12
13
|
offscreenMultiRenderWindow.setContainer(container);
|
|
14
|
+
attachWebGLContextEvents(offscreenMultiRenderWindow, renderingEngineId, i);
|
|
13
15
|
this.contexts.push(offscreenMultiRenderWindow);
|
|
14
16
|
this.offScreenCanvasContainers.push(container);
|
|
15
17
|
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import eventTarget from '../../eventTarget.js';
|
|
2
|
+
import { Events } from '../../enums/index.js';
|
|
3
|
+
import triggerEvent from '../../utilities/triggerEvent.js';
|
|
4
|
+
export function attachWebGLContextEvents(offscreenMultiRenderWindow, renderingEngineId, contextIndex = 0) {
|
|
5
|
+
const canvas = offscreenMultiRenderWindow.getOpenGLRenderWindow?.()?.getCanvas?.();
|
|
6
|
+
if (!canvas) {
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
canvas.addEventListener('webglcontextlost', () => {
|
|
10
|
+
console.warn(`CornerstoneRender: WebGL context lost (renderingEngine=${renderingEngineId}, context=${contextIndex})`);
|
|
11
|
+
triggerEvent(eventTarget, Events.WEBGL_CONTEXT_LOST, {
|
|
12
|
+
renderingEngineId,
|
|
13
|
+
contextIndex,
|
|
14
|
+
});
|
|
15
|
+
});
|
|
16
|
+
canvas.addEventListener('webglcontextrestored', () => {
|
|
17
|
+
triggerEvent(eventTarget, Events.WEBGL_CONTEXT_RESTORED, {
|
|
18
|
+
renderingEngineId,
|
|
19
|
+
contextIndex,
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
}
|
|
@@ -43,6 +43,11 @@ declare enum Events {
|
|
|
43
43
|
GEOMETRY_LOADED = "GEOMETRY_LOADED",
|
|
44
44
|
GEOMETRY_LOAD_PROGRESS = "GEOMETRY_LOAD_PROGRESS",
|
|
45
45
|
GEOMETRY_LOADED_FAILED = "GEOMETRY_LOADED_FAILED",
|
|
46
|
-
ACTORS_CHANGED = "CORNERSTONE_ACTORS_CHANGED"
|
|
46
|
+
ACTORS_CHANGED = "CORNERSTONE_ACTORS_CHANGED",
|
|
47
|
+
RENDER_BACKEND_CHANGED = "CORNERSTONE_RENDER_BACKEND_CHANGED",
|
|
48
|
+
WEBGL_CONTEXT_LOST = "CORNERSTONE_WEBGL_CONTEXT_LOST",
|
|
49
|
+
WEBGL_CONTEXT_RESTORED = "CORNERSTONE_WEBGL_CONTEXT_RESTORED",
|
|
50
|
+
RENDER_PATH_ERROR = "CORNERSTONE_RENDER_PATH_ERROR",
|
|
51
|
+
RENDERING_PIPELINE_CHANGED = "CORNERSTONE_RENDERING_PIPELINE_CHANGED"
|
|
47
52
|
}
|
|
48
53
|
export default Events;
|
package/dist/esm/enums/Events.js
CHANGED
|
@@ -45,5 +45,10 @@ var Events;
|
|
|
45
45
|
Events["GEOMETRY_LOAD_PROGRESS"] = "GEOMETRY_LOAD_PROGRESS";
|
|
46
46
|
Events["GEOMETRY_LOADED_FAILED"] = "GEOMETRY_LOADED_FAILED";
|
|
47
47
|
Events["ACTORS_CHANGED"] = "CORNERSTONE_ACTORS_CHANGED";
|
|
48
|
+
Events["RENDER_BACKEND_CHANGED"] = "CORNERSTONE_RENDER_BACKEND_CHANGED";
|
|
49
|
+
Events["WEBGL_CONTEXT_LOST"] = "CORNERSTONE_WEBGL_CONTEXT_LOST";
|
|
50
|
+
Events["WEBGL_CONTEXT_RESTORED"] = "CORNERSTONE_WEBGL_CONTEXT_RESTORED";
|
|
51
|
+
Events["RENDER_PATH_ERROR"] = "CORNERSTONE_RENDER_PATH_ERROR";
|
|
52
|
+
Events["RENDERING_PIPELINE_CHANGED"] = "CORNERSTONE_RENDERING_PIPELINE_CHANGED";
|
|
48
53
|
})(Events || (Events = {}));
|
|
49
54
|
export default Events;
|
|
@@ -18,4 +18,5 @@ import MetadataModules from './MetadataModules.js';
|
|
|
18
18
|
import { GenerateImageType } from './GenerateImageType.js';
|
|
19
19
|
import VoxelManagerEnum from './VoxelManagerEnum.js';
|
|
20
20
|
import RenderingEngineModeEnum from './RenderingEngineModeEnum.js';
|
|
21
|
-
|
|
21
|
+
import RenderBackend, { type RenderBackendValue } from './RenderBackend.js';
|
|
22
|
+
export { Events, BlendModes, CalibrationTypes, InterpolationType, RequestType, ViewportType, ViewportTypes, type ViewportTypesMap, OrientationAxis, GeometryType, ContourType, MeshType, VOILUTFunctionType, DynamicOperatorType, ViewportStatus, VideoEnums, MetadataModules, ImageQualityStatus, VoxelManagerEnum, GenerateImageType, RenderingEngineModeEnum, RenderBackend, type RenderBackendValue, };
|
package/dist/esm/enums/index.js
CHANGED
|
@@ -18,4 +18,5 @@ import MetadataModules from './MetadataModules.js';
|
|
|
18
18
|
import { GenerateImageType } from './GenerateImageType.js';
|
|
19
19
|
import VoxelManagerEnum from './VoxelManagerEnum.js';
|
|
20
20
|
import RenderingEngineModeEnum from './RenderingEngineModeEnum.js';
|
|
21
|
-
|
|
21
|
+
import RenderBackend, {} from './RenderBackend.js';
|
|
22
|
+
export { Events, BlendModes, CalibrationTypes, InterpolationType, RequestType, ViewportType, ViewportTypes, OrientationAxis, GeometryType, ContourType, MeshType, VOILUTFunctionType, DynamicOperatorType, ViewportStatus, VideoEnums, MetadataModules, ImageQualityStatus, VoxelManagerEnum, GenerateImageType, RenderingEngineModeEnum, RenderBackend, };
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -34,7 +34,8 @@ import imageRetrievalPoolManager from './requestPool/imageRetrievalPoolManager.j
|
|
|
34
34
|
import imageLoadPoolManager from './requestPool/imageLoadPoolManager.js';
|
|
35
35
|
import getEnabledElement, { getEnabledElementByIds, getEnabledElementByViewportId, getEnabledElements } from './getEnabledElement.js';
|
|
36
36
|
import * as metaData from './metaData.js';
|
|
37
|
-
import { init, getShouldUseCPURendering, getUseGenericViewport, isCornerstoneInitialized, setUseCPURendering, setPreferSizeOverAccuracy, resetUseCPURendering, getConfiguration, setConfiguration, getWebWorkerManager, canRenderFloatTextures, peerImport, resetInitialization } from './init.js';
|
|
37
|
+
import { init, getShouldUseCPURendering, getUseGenericViewport, isCornerstoneInitialized, setUseCPURendering, setPreferSizeOverAccuracy, resetUseCPURendering, getRenderBackend, setRenderBackend, getEffectiveRenderBackend, getConfiguration, setConfiguration, getWebWorkerManager, canRenderFloatTextures, peerImport, resetInitialization } from './init.js';
|
|
38
|
+
import { getRenderingCapabilities, detectRenderingCapabilities } from './utilities/renderingCapabilities.js';
|
|
38
39
|
import Settings from './Settings.js';
|
|
39
40
|
import * as volumeLoader from './loaders/volumeLoader.js';
|
|
40
41
|
import * as imageLoader from './loaders/imageLoader.js';
|
|
@@ -111,4 +112,4 @@ declare const renderingEngineExportsV2: {
|
|
|
111
112
|
};
|
|
112
113
|
declare const LegacyVolumeViewport3D: typeof VolumeViewport3D;
|
|
113
114
|
export type { Types, IRetrieveConfiguration, RetrieveOptions, RetrieveStage, ImageLoadListener, IImagesLoader, };
|
|
114
|
-
export { init, isCornerstoneInitialized, peerImport, resetInitialization, getConfiguration, setConfiguration, getWebWorkerManager, canRenderFloatTextures, Enums, CONSTANTS, Events as EVENTS, Settings, BaseVolumeViewport, VolumeViewport, LegacyVolumeViewport3D, VolumeViewport3D, GenericVolumeViewport3D, Viewport, StackViewport, VideoViewport, WSIViewport, ECGViewport, ECGGenericViewport, GenericViewport, ViewportProjectionService, viewportProjection, viewportHasCanvasWorldTransform, viewportHasFrameOfReferenceUID, viewportHasPan, viewportHasZoom, RenderingEngine, BaseRenderingEngine, TiledRenderingEngine, ContextPoolRenderingEngine, ImageVolume, Surface, getRenderingEngine, getRenderingEngines, getEnabledElement, getEnabledElementByIds, getEnabledElements, getEnabledElementByViewportId, createVolumeActor, createVolumeMapper, cache, eventTarget, triggerEvent, convertColorArrayToRgbString, imageLoader, registerImageLoader, volumeLoader, metaData, utilities, setVolumesForViewports, addVolumesToViewports, addImageSlicesToViewports, DefaultRenderPathResolver, defaultRenderPathResolver, createDefaultECGRenderPaths, createECGRenderPathResolver, DefaultECGDataProvider, ecgProjection, VideoGenericViewport, createDefaultVideoRenderPaths, createVideoRenderPathResolver, DefaultVideoDataProvider, videoProjection, PlanarViewport, createDefaultPlanarRenderPaths, createPlanarRenderPathResolver, DefaultPlanarDataProvider, planarProjection, createDefaultVolume3DRenderPaths, createVolume3DRenderPathResolver, DefaultVolume3DDataProvider, volume3DProjection, WSIGenericViewport, createDefaultWSIRenderPaths, createWSIRenderPathResolver, DefaultWSIDataProvider, wsiProjection, renderingEngineExportsV2, getProjectionScaleMatrix, registerViewportType, isRegisteredViewportType, imageLoadPoolManager as requestPoolManager, imageRetrievalPoolManager, imageLoadPoolManager, getShouldUseCPURendering, setUseCPURendering, setPreferSizeOverAccuracy, resetUseCPURendering, getUseGenericViewport, geometryLoader, cornerstoneMeshLoader, ProgressiveRetrieveImages, decimatedVolumeLoader, ActorRenderMode, cornerstoneStreamingImageVolumeLoader, cornerstoneStreamingDynamicImageVolumeLoader, StreamingDynamicImageVolume, StreamingImageVolume, convertMapperToNotSharedMapper, version, };
|
|
115
|
+
export { init, isCornerstoneInitialized, peerImport, resetInitialization, getConfiguration, setConfiguration, getWebWorkerManager, canRenderFloatTextures, Enums, CONSTANTS, Events as EVENTS, Settings, BaseVolumeViewport, VolumeViewport, LegacyVolumeViewport3D, VolumeViewport3D, GenericVolumeViewport3D, Viewport, StackViewport, VideoViewport, WSIViewport, ECGViewport, ECGGenericViewport, GenericViewport, ViewportProjectionService, viewportProjection, viewportHasCanvasWorldTransform, viewportHasFrameOfReferenceUID, viewportHasPan, viewportHasZoom, RenderingEngine, BaseRenderingEngine, TiledRenderingEngine, ContextPoolRenderingEngine, ImageVolume, Surface, getRenderingEngine, getRenderingEngines, getEnabledElement, getEnabledElementByIds, getEnabledElements, getEnabledElementByViewportId, createVolumeActor, createVolumeMapper, cache, eventTarget, triggerEvent, convertColorArrayToRgbString, imageLoader, registerImageLoader, volumeLoader, metaData, utilities, setVolumesForViewports, addVolumesToViewports, addImageSlicesToViewports, DefaultRenderPathResolver, defaultRenderPathResolver, createDefaultECGRenderPaths, createECGRenderPathResolver, DefaultECGDataProvider, ecgProjection, VideoGenericViewport, createDefaultVideoRenderPaths, createVideoRenderPathResolver, DefaultVideoDataProvider, videoProjection, PlanarViewport, createDefaultPlanarRenderPaths, createPlanarRenderPathResolver, DefaultPlanarDataProvider, planarProjection, createDefaultVolume3DRenderPaths, createVolume3DRenderPathResolver, DefaultVolume3DDataProvider, volume3DProjection, WSIGenericViewport, createDefaultWSIRenderPaths, createWSIRenderPathResolver, DefaultWSIDataProvider, wsiProjection, renderingEngineExportsV2, getProjectionScaleMatrix, registerViewportType, isRegisteredViewportType, imageLoadPoolManager as requestPoolManager, imageRetrievalPoolManager, imageLoadPoolManager, getShouldUseCPURendering, setUseCPURendering, setPreferSizeOverAccuracy, resetUseCPURendering, getRenderBackend, setRenderBackend, getEffectiveRenderBackend, getRenderingCapabilities, detectRenderingCapabilities, getUseGenericViewport, geometryLoader, cornerstoneMeshLoader, ProgressiveRetrieveImages, decimatedVolumeLoader, ActorRenderMode, cornerstoneStreamingImageVolumeLoader, cornerstoneStreamingDynamicImageVolumeLoader, StreamingDynamicImageVolume, StreamingImageVolume, convertMapperToNotSharedMapper, version, };
|
package/dist/esm/index.js
CHANGED
|
@@ -28,7 +28,8 @@ import imageRetrievalPoolManager from './requestPool/imageRetrievalPoolManager.j
|
|
|
28
28
|
import imageLoadPoolManager from './requestPool/imageLoadPoolManager.js';
|
|
29
29
|
import getEnabledElement, { getEnabledElementByIds, getEnabledElementByViewportId, getEnabledElements, } from './getEnabledElement.js';
|
|
30
30
|
import * as metaData from './metaData.js';
|
|
31
|
-
import { init, getShouldUseCPURendering, getUseGenericViewport, isCornerstoneInitialized, setUseCPURendering, setPreferSizeOverAccuracy, resetUseCPURendering, getConfiguration, setConfiguration, getWebWorkerManager, canRenderFloatTextures, peerImport, resetInitialization, } from './init.js';
|
|
31
|
+
import { init, getShouldUseCPURendering, getUseGenericViewport, isCornerstoneInitialized, setUseCPURendering, setPreferSizeOverAccuracy, resetUseCPURendering, getRenderBackend, setRenderBackend, getEffectiveRenderBackend, getConfiguration, setConfiguration, getWebWorkerManager, canRenderFloatTextures, peerImport, resetInitialization, } from './init.js';
|
|
32
|
+
import { getRenderingCapabilities, detectRenderingCapabilities, } from './utilities/renderingCapabilities.js';
|
|
32
33
|
import Settings from './Settings.js';
|
|
33
34
|
import * as volumeLoader from './loaders/volumeLoader.js';
|
|
34
35
|
import * as imageLoader from './loaders/imageLoader.js';
|
|
@@ -77,4 +78,4 @@ const renderingEngineExportsV2 = {
|
|
|
77
78
|
wsiProjection,
|
|
78
79
|
};
|
|
79
80
|
const LegacyVolumeViewport3D = VolumeViewport3D;
|
|
80
|
-
export { init, isCornerstoneInitialized, peerImport, resetInitialization, getConfiguration, setConfiguration, getWebWorkerManager, canRenderFloatTextures, Enums, CONSTANTS, Events as EVENTS, Settings, BaseVolumeViewport, VolumeViewport, LegacyVolumeViewport3D, VolumeViewport3D, GenericVolumeViewport3D, Viewport, StackViewport, VideoViewport, WSIViewport, ECGViewport, ECGGenericViewport, GenericViewport, ViewportProjectionService, viewportProjection, viewportHasCanvasWorldTransform, viewportHasFrameOfReferenceUID, viewportHasPan, viewportHasZoom, RenderingEngine, BaseRenderingEngine, TiledRenderingEngine, ContextPoolRenderingEngine, ImageVolume, Surface, getRenderingEngine, getRenderingEngines, getEnabledElement, getEnabledElementByIds, getEnabledElements, getEnabledElementByViewportId, createVolumeActor, createVolumeMapper, cache, eventTarget, triggerEvent, convertColorArrayToRgbString, imageLoader, registerImageLoader, volumeLoader, metaData, utilities, setVolumesForViewports, addVolumesToViewports, addImageSlicesToViewports, DefaultRenderPathResolver, defaultRenderPathResolver, createDefaultECGRenderPaths, createECGRenderPathResolver, DefaultECGDataProvider, ecgProjection, VideoGenericViewport, createDefaultVideoRenderPaths, createVideoRenderPathResolver, DefaultVideoDataProvider, videoProjection, PlanarViewport, createDefaultPlanarRenderPaths, createPlanarRenderPathResolver, DefaultPlanarDataProvider, planarProjection, createDefaultVolume3DRenderPaths, createVolume3DRenderPathResolver, DefaultVolume3DDataProvider, volume3DProjection, WSIGenericViewport, createDefaultWSIRenderPaths, createWSIRenderPathResolver, DefaultWSIDataProvider, wsiProjection, renderingEngineExportsV2, getProjectionScaleMatrix, registerViewportType, isRegisteredViewportType, imageLoadPoolManager as requestPoolManager, imageRetrievalPoolManager, imageLoadPoolManager, getShouldUseCPURendering, setUseCPURendering, setPreferSizeOverAccuracy, resetUseCPURendering, getUseGenericViewport, geometryLoader, cornerstoneMeshLoader, ProgressiveRetrieveImages, decimatedVolumeLoader, ActorRenderMode, cornerstoneStreamingImageVolumeLoader, cornerstoneStreamingDynamicImageVolumeLoader, StreamingDynamicImageVolume, StreamingImageVolume, convertMapperToNotSharedMapper, version, };
|
|
81
|
+
export { init, isCornerstoneInitialized, peerImport, resetInitialization, getConfiguration, setConfiguration, getWebWorkerManager, canRenderFloatTextures, Enums, CONSTANTS, Events as EVENTS, Settings, BaseVolumeViewport, VolumeViewport, LegacyVolumeViewport3D, VolumeViewport3D, GenericVolumeViewport3D, Viewport, StackViewport, VideoViewport, WSIViewport, ECGViewport, ECGGenericViewport, GenericViewport, ViewportProjectionService, viewportProjection, viewportHasCanvasWorldTransform, viewportHasFrameOfReferenceUID, viewportHasPan, viewportHasZoom, RenderingEngine, BaseRenderingEngine, TiledRenderingEngine, ContextPoolRenderingEngine, ImageVolume, Surface, getRenderingEngine, getRenderingEngines, getEnabledElement, getEnabledElementByIds, getEnabledElements, getEnabledElementByViewportId, createVolumeActor, createVolumeMapper, cache, eventTarget, triggerEvent, convertColorArrayToRgbString, imageLoader, registerImageLoader, volumeLoader, metaData, utilities, setVolumesForViewports, addVolumesToViewports, addImageSlicesToViewports, DefaultRenderPathResolver, defaultRenderPathResolver, createDefaultECGRenderPaths, createECGRenderPathResolver, DefaultECGDataProvider, ecgProjection, VideoGenericViewport, createDefaultVideoRenderPaths, createVideoRenderPathResolver, DefaultVideoDataProvider, videoProjection, PlanarViewport, createDefaultPlanarRenderPaths, createPlanarRenderPathResolver, DefaultPlanarDataProvider, planarProjection, createDefaultVolume3DRenderPaths, createVolume3DRenderPathResolver, DefaultVolume3DDataProvider, volume3DProjection, WSIGenericViewport, createDefaultWSIRenderPaths, createWSIRenderPathResolver, DefaultWSIDataProvider, wsiProjection, renderingEngineExportsV2, getProjectionScaleMatrix, registerViewportType, isRegisteredViewportType, imageLoadPoolManager as requestPoolManager, imageRetrievalPoolManager, imageLoadPoolManager, getShouldUseCPURendering, setUseCPURendering, setPreferSizeOverAccuracy, resetUseCPURendering, getRenderBackend, setRenderBackend, getEffectiveRenderBackend, getRenderingCapabilities, detectRenderingCapabilities, getUseGenericViewport, geometryLoader, cornerstoneMeshLoader, ProgressiveRetrieveImages, decimatedVolumeLoader, ActorRenderMode, cornerstoneStreamingImageVolumeLoader, cornerstoneStreamingDynamicImageVolumeLoader, StreamingDynamicImageVolume, StreamingImageVolume, convertMapperToNotSharedMapper, version, };
|
package/dist/esm/init.d.ts
CHANGED
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
import type { Cornerstone3DConfig } from './types/index.js';
|
|
2
2
|
import CentralizedWebWorkerManager from './webWorkerManager/webWorkerManager.js';
|
|
3
|
+
import { RenderBackend } from './enums/index.js';
|
|
4
|
+
import type { RenderBackendValue } from './enums/index.js';
|
|
3
5
|
declare function init(configuration?: Cornerstone3DConfig): boolean;
|
|
4
6
|
declare function getCanUseNorm16Texture(): boolean;
|
|
7
|
+
declare function getRenderBackend(): RenderBackend;
|
|
8
|
+
declare function resolveAutoRenderBackend(): RenderBackend.GPU | RenderBackend.CPU;
|
|
9
|
+
declare function getEffectiveRenderBackend(override?: RenderBackend | RenderBackendValue): RenderBackend.GPU | RenderBackend.CPU;
|
|
10
|
+
declare function setRenderBackend(backend: RenderBackend | RenderBackendValue, reason?: string): void;
|
|
5
11
|
declare function setUseCPURendering(status: boolean, updateViewports?: boolean): void;
|
|
6
12
|
declare function setPreferSizeOverAccuracy(status: boolean): void;
|
|
7
13
|
declare function canRenderFloatTextures(): boolean;
|
|
@@ -14,4 +20,4 @@ declare function getConfiguration(): Cornerstone3DConfig;
|
|
|
14
20
|
declare function setConfiguration(c: Cornerstone3DConfig): void;
|
|
15
21
|
declare function getWebWorkerManager(): CentralizedWebWorkerManager;
|
|
16
22
|
declare function peerImport(moduleId: string): Promise<any>;
|
|
17
|
-
export { init, getShouldUseCPURendering, getUseGenericViewport, isCornerstoneInitialized, setUseCPURendering, setPreferSizeOverAccuracy, resetUseCPURendering, getConfiguration, setConfiguration, getWebWorkerManager, canRenderFloatTextures, peerImport, resetInitialization, getCanUseNorm16Texture, };
|
|
23
|
+
export { init, getShouldUseCPURendering, getUseGenericViewport, isCornerstoneInitialized, setUseCPURendering, setPreferSizeOverAccuracy, resetUseCPURendering, getRenderBackend, setRenderBackend, getEffectiveRenderBackend, resolveAutoRenderBackend, getConfiguration, setConfiguration, getWebWorkerManager, canRenderFloatTextures, peerImport, resetInitialization, getCanUseNorm16Texture, };
|
package/dist/esm/init.js
CHANGED
|
@@ -2,10 +2,11 @@ import { getRenderingEngines } from './RenderingEngine/getRenderingEngine.js';
|
|
|
2
2
|
let csRenderInitialized = false;
|
|
3
3
|
import deepMerge from './utilities/deepMerge.js';
|
|
4
4
|
import CentralizedWebWorkerManager from './webWorkerManager/webWorkerManager.js';
|
|
5
|
-
import {
|
|
6
|
-
import
|
|
5
|
+
import { getRenderingCapabilities } from './utilities/renderingCapabilities.js';
|
|
6
|
+
import triggerEvent from './utilities/triggerEvent.js';
|
|
7
|
+
import eventTarget from './eventTarget.js';
|
|
8
|
+
import { Events, RenderBackend, RenderingEngineModeEnum } from './enums/index.js';
|
|
7
9
|
const defaultConfig = {
|
|
8
|
-
gpuTier: { tier: 2 },
|
|
9
10
|
isMobile: false,
|
|
10
11
|
rendering: {
|
|
11
12
|
useCPURendering: false,
|
|
@@ -15,10 +16,7 @@ const defaultConfig = {
|
|
|
15
16
|
renderingEngineMode: RenderingEngineModeEnum.ContextPool,
|
|
16
17
|
webGlContextCount: 7,
|
|
17
18
|
planar: {
|
|
18
|
-
|
|
19
|
-
image: 64 * 1024 * 1024,
|
|
20
|
-
volume: Infinity,
|
|
21
|
-
},
|
|
19
|
+
renderBackend: RenderBackend.Auto,
|
|
22
20
|
cpuVolume: {
|
|
23
21
|
useViewportSamplingForLinear: true,
|
|
24
22
|
volumeModifiedThrottleMs: 5000,
|
|
@@ -38,21 +36,9 @@ let config = {
|
|
|
38
36
|
rendering: { ...defaultConfig.rendering },
|
|
39
37
|
};
|
|
40
38
|
let webWorkerManager = null;
|
|
41
|
-
let canUseNorm16Texture = false;
|
|
42
|
-
function _getGLContext() {
|
|
43
|
-
const canvas = document.createElement('canvas');
|
|
44
|
-
const gl = canvas.getContext('webgl2') ||
|
|
45
|
-
canvas.getContext('webgl') ||
|
|
46
|
-
canvas.getContext('experimental-webgl');
|
|
47
|
-
return gl;
|
|
48
|
-
}
|
|
49
|
-
function _hasActiveWebGLContext() {
|
|
50
|
-
const gl = _getGLContext();
|
|
51
|
-
return (gl instanceof WebGLRenderingContext || gl instanceof WebGL2RenderingContext);
|
|
52
|
-
}
|
|
53
39
|
function _hasNorm16TextureSupport() {
|
|
54
|
-
const
|
|
55
|
-
return
|
|
40
|
+
const capabilities = getRenderingCapabilities();
|
|
41
|
+
return capabilities.norm16 && capabilities.norm16Linear;
|
|
56
42
|
}
|
|
57
43
|
function isIOS() {
|
|
58
44
|
if (/iPad|iPhone|iPod/.test(navigator.platform)) {
|
|
@@ -68,7 +54,6 @@ function init(configuration = config) {
|
|
|
68
54
|
if (csRenderInitialized) {
|
|
69
55
|
return csRenderInitialized;
|
|
70
56
|
}
|
|
71
|
-
canUseNorm16Texture = _hasNorm16TextureSupport();
|
|
72
57
|
config = deepMerge(defaultConfig, configuration);
|
|
73
58
|
if (config.isMobile) {
|
|
74
59
|
config.rendering.webGlContextCount = 1;
|
|
@@ -77,17 +62,20 @@ function init(configuration = config) {
|
|
|
77
62
|
if (configuration.rendering?.preferSizeOverAccuracy) {
|
|
78
63
|
config.rendering.preferSizeOverAccuracy = true;
|
|
79
64
|
}
|
|
80
|
-
else {
|
|
65
|
+
else if (!_hasNorm16TextureSupport()) {
|
|
81
66
|
console.log('norm16 texture not supported, you can turn on the preferSizeOverAccuracy flag to use native data type, but be aware of the inaccuracy of the rendering in high bits');
|
|
82
67
|
}
|
|
83
68
|
}
|
|
84
|
-
const
|
|
85
|
-
if (!
|
|
69
|
+
const capabilities = getRenderingCapabilities();
|
|
70
|
+
if (!capabilities.webgl) {
|
|
86
71
|
console.log('CornerstoneRender: GPU not detected, using CPU rendering');
|
|
87
72
|
config.rendering.useCPURendering = true;
|
|
88
73
|
}
|
|
89
74
|
else {
|
|
90
75
|
console.log('CornerstoneRender: using GPU rendering');
|
|
76
|
+
if (capabilities.softwareRasterizer) {
|
|
77
|
+
console.log(`CornerstoneRender: software rasterizer detected (${capabilities.renderer}), GPU rendering may be slow`);
|
|
78
|
+
}
|
|
91
79
|
}
|
|
92
80
|
csRenderInitialized = true;
|
|
93
81
|
if (!webWorkerManager) {
|
|
@@ -96,14 +84,54 @@ function init(configuration = config) {
|
|
|
96
84
|
return csRenderInitialized;
|
|
97
85
|
}
|
|
98
86
|
function getCanUseNorm16Texture() {
|
|
99
|
-
return
|
|
87
|
+
return _hasNorm16TextureSupport();
|
|
88
|
+
}
|
|
89
|
+
function getRenderBackend() {
|
|
90
|
+
return (config.rendering.planar?.renderBackend ??
|
|
91
|
+
RenderBackend.Auto);
|
|
92
|
+
}
|
|
93
|
+
function resolveAutoRenderBackend() {
|
|
94
|
+
return config.rendering.useCPURendering
|
|
95
|
+
? RenderBackend.CPU
|
|
96
|
+
: RenderBackend.GPU;
|
|
97
|
+
}
|
|
98
|
+
function getEffectiveRenderBackend(override) {
|
|
99
|
+
const backend = (override ?? getRenderBackend());
|
|
100
|
+
if (backend === RenderBackend.GPU || backend === RenderBackend.CPU) {
|
|
101
|
+
return backend;
|
|
102
|
+
}
|
|
103
|
+
return resolveAutoRenderBackend();
|
|
104
|
+
}
|
|
105
|
+
function setRenderBackend(backend, reason) {
|
|
106
|
+
if (backend !== RenderBackend.Auto &&
|
|
107
|
+
backend !== RenderBackend.GPU &&
|
|
108
|
+
backend !== RenderBackend.CPU) {
|
|
109
|
+
throw new Error(`[setRenderBackend] Invalid render backend: ${String(backend)}`);
|
|
110
|
+
}
|
|
111
|
+
const previous = getRenderBackend();
|
|
112
|
+
if (previous === backend) {
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
config.rendering.planar = {
|
|
116
|
+
...config.rendering.planar,
|
|
117
|
+
renderBackend: backend,
|
|
118
|
+
};
|
|
119
|
+
_updateRenderingPipelinesForAllViewports();
|
|
120
|
+
triggerEvent(eventTarget, Events.RENDER_BACKEND_CHANGED, {
|
|
121
|
+
previous,
|
|
122
|
+
current: backend,
|
|
123
|
+
effectiveBackend: getEffectiveRenderBackend(),
|
|
124
|
+
reason,
|
|
125
|
+
});
|
|
100
126
|
}
|
|
101
127
|
function setUseCPURendering(status, updateViewports = true) {
|
|
128
|
+
const previousEffective = getEffectiveRenderBackend();
|
|
102
129
|
config.rendering.useCPURendering = status;
|
|
103
130
|
csRenderInitialized = true;
|
|
104
131
|
if (updateViewports) {
|
|
105
132
|
_updateRenderingPipelinesForAllViewports();
|
|
106
133
|
}
|
|
134
|
+
_notifyEffectiveBackendChange(previousEffective, 'setUseCPURendering');
|
|
107
135
|
}
|
|
108
136
|
function setPreferSizeOverAccuracy(status) {
|
|
109
137
|
config.rendering.preferSizeOverAccuracy = status;
|
|
@@ -111,14 +139,17 @@ function setPreferSizeOverAccuracy(status) {
|
|
|
111
139
|
_updateRenderingPipelinesForAllViewports();
|
|
112
140
|
}
|
|
113
141
|
function canRenderFloatTextures() {
|
|
114
|
-
|
|
115
|
-
|
|
142
|
+
const capabilities = getRenderingCapabilities();
|
|
143
|
+
if (capabilities.webgl2) {
|
|
144
|
+
return capabilities.floatLinear;
|
|
116
145
|
}
|
|
117
|
-
return
|
|
146
|
+
return !isIOS();
|
|
118
147
|
}
|
|
119
148
|
function resetUseCPURendering() {
|
|
120
|
-
|
|
149
|
+
const previousEffective = getEffectiveRenderBackend();
|
|
150
|
+
config.rendering.useCPURendering = !getRenderingCapabilities().webgl;
|
|
121
151
|
_updateRenderingPipelinesForAllViewports();
|
|
152
|
+
_notifyEffectiveBackendChange(previousEffective, 'resetUseCPURendering');
|
|
122
153
|
}
|
|
123
154
|
function getShouldUseCPURendering() {
|
|
124
155
|
return config.rendering.useCPURendering;
|
|
@@ -142,10 +173,22 @@ function setConfiguration(c) {
|
|
|
142
173
|
function _updateRenderingPipelinesForAllViewports() {
|
|
143
174
|
getRenderingEngines().forEach((engine) => {
|
|
144
175
|
engine.getViewports().forEach((viewport) => {
|
|
145
|
-
viewport.updateRenderingPipeline();
|
|
176
|
+
viewport.updateRenderingPipeline?.();
|
|
146
177
|
});
|
|
147
178
|
});
|
|
148
179
|
}
|
|
180
|
+
function _notifyEffectiveBackendChange(previousEffective, reason) {
|
|
181
|
+
const effectiveBackend = getEffectiveRenderBackend();
|
|
182
|
+
if (previousEffective === effectiveBackend) {
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
triggerEvent(eventTarget, Events.RENDER_BACKEND_CHANGED, {
|
|
186
|
+
previous: previousEffective,
|
|
187
|
+
current: effectiveBackend,
|
|
188
|
+
effectiveBackend,
|
|
189
|
+
reason,
|
|
190
|
+
});
|
|
191
|
+
}
|
|
149
192
|
function getWebWorkerManager() {
|
|
150
193
|
if (!webWorkerManager) {
|
|
151
194
|
webWorkerManager = new CentralizedWebWorkerManager();
|
|
@@ -155,4 +198,4 @@ function getWebWorkerManager() {
|
|
|
155
198
|
async function peerImport(moduleId) {
|
|
156
199
|
return config.peerImport(moduleId);
|
|
157
200
|
}
|
|
158
|
-
export { init, getShouldUseCPURendering, getUseGenericViewport, isCornerstoneInitialized, setUseCPURendering, setPreferSizeOverAccuracy, resetUseCPURendering, getConfiguration, setConfiguration, getWebWorkerManager, canRenderFloatTextures, peerImport, resetInitialization, getCanUseNorm16Texture, };
|
|
201
|
+
export { init, getShouldUseCPURendering, getUseGenericViewport, isCornerstoneInitialized, setUseCPURendering, setPreferSizeOverAccuracy, resetUseCPURendering, getRenderBackend, setRenderBackend, getEffectiveRenderBackend, resolveAutoRenderBackend, getConfiguration, setConfiguration, getWebWorkerManager, canRenderFloatTextures, peerImport, resetInitialization, getCanUseNorm16Texture, };
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import type { RenderingEngineModeType } from '../types/index.js';
|
|
2
|
+
import type { RenderBackend, RenderBackendValue } from '../enums/index.js';
|
|
2
3
|
interface Cornerstone3DConfig {
|
|
3
|
-
gpuTier?: {
|
|
4
|
-
tier?: number;
|
|
5
|
-
};
|
|
6
4
|
isMobile?: boolean;
|
|
7
5
|
rendering?: {
|
|
8
6
|
preferSizeOverAccuracy?: boolean;
|
|
@@ -12,10 +10,7 @@ interface Cornerstone3DConfig {
|
|
|
12
10
|
renderingEngineMode?: RenderingEngineModeType;
|
|
13
11
|
webGlContextCount?: number;
|
|
14
12
|
planar?: {
|
|
15
|
-
|
|
16
|
-
image?: number;
|
|
17
|
-
volume?: number;
|
|
18
|
-
};
|
|
13
|
+
renderBackend?: RenderBackend | RenderBackendValue;
|
|
19
14
|
cpuVolume?: {
|
|
20
15
|
useViewportSamplingForLinear?: boolean;
|
|
21
16
|
volumeModifiedThrottleMs?: number;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { TextureFormatSupport } from './textureSupport.js';
|
|
2
|
+
export declare const RENDERING_CAPABILITIES_PROBE_VERSION = 1;
|
|
3
|
+
export interface RenderingCapabilities extends TextureFormatSupport {
|
|
4
|
+
webgl: boolean;
|
|
5
|
+
webgl2: boolean;
|
|
6
|
+
maxTextureSize: number;
|
|
7
|
+
renderer: string;
|
|
8
|
+
softwareRasterizer: boolean;
|
|
9
|
+
}
|
|
10
|
+
export declare function detectRenderingCapabilities({ useCache, }?: {
|
|
11
|
+
useCache?: boolean;
|
|
12
|
+
}): RenderingCapabilities;
|
|
13
|
+
export declare function getRenderingCapabilities(): RenderingCapabilities;
|
|
14
|
+
export declare function resetRenderingCapabilities({ clearStorage, }?: {
|
|
15
|
+
clearStorage?: boolean;
|
|
16
|
+
}): void;
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { getSupportedTextureFormats } from './textureSupport.js';
|
|
2
|
+
export const RENDERING_CAPABILITIES_PROBE_VERSION = 1;
|
|
3
|
+
const STORAGE_KEY = 'cornerstone3D.renderingCapabilities';
|
|
4
|
+
const SOFTWARE_RASTERIZER_PATTERN = /swiftshader|llvmpipe|softpipe|software|microsoft basic render/i;
|
|
5
|
+
const NO_GPU_FORMATS = {
|
|
6
|
+
norm16: false,
|
|
7
|
+
norm16Linear: false,
|
|
8
|
+
float: false,
|
|
9
|
+
floatLinear: false,
|
|
10
|
+
halfFloat: false,
|
|
11
|
+
halfFloatLinear: false,
|
|
12
|
+
};
|
|
13
|
+
let cachedCapabilities = null;
|
|
14
|
+
function getWebGLContextInfo() {
|
|
15
|
+
const info = {
|
|
16
|
+
webgl: false,
|
|
17
|
+
webgl2: false,
|
|
18
|
+
maxTextureSize: 0,
|
|
19
|
+
renderer: '',
|
|
20
|
+
};
|
|
21
|
+
if (typeof document === 'undefined') {
|
|
22
|
+
return info;
|
|
23
|
+
}
|
|
24
|
+
try {
|
|
25
|
+
const canvas = document.createElement('canvas');
|
|
26
|
+
const gl2 = canvas.getContext('webgl2');
|
|
27
|
+
const gl = gl2 ||
|
|
28
|
+
canvas.getContext('webgl') ||
|
|
29
|
+
canvas.getContext('experimental-webgl');
|
|
30
|
+
if (!gl) {
|
|
31
|
+
return info;
|
|
32
|
+
}
|
|
33
|
+
info.webgl = true;
|
|
34
|
+
info.webgl2 = !!gl2;
|
|
35
|
+
info.maxTextureSize = Number(gl.getParameter(gl.MAX_TEXTURE_SIZE)) || 0;
|
|
36
|
+
const debugInfo = gl.getExtension('WEBGL_debug_renderer_info');
|
|
37
|
+
const renderer = debugInfo
|
|
38
|
+
? gl.getParameter(debugInfo.UNMASKED_RENDERER_WEBGL)
|
|
39
|
+
: gl.getParameter(gl.RENDERER);
|
|
40
|
+
info.renderer = typeof renderer === 'string' ? renderer : '';
|
|
41
|
+
const loseContext = gl.getExtension('WEBGL_lose_context');
|
|
42
|
+
if (loseContext) {
|
|
43
|
+
loseContext.loseContext();
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
}
|
|
48
|
+
return info;
|
|
49
|
+
}
|
|
50
|
+
function readCachedFormats(renderer, webgl2) {
|
|
51
|
+
try {
|
|
52
|
+
const raw = window.localStorage?.getItem(STORAGE_KEY);
|
|
53
|
+
if (!raw) {
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
const parsed = JSON.parse(raw);
|
|
57
|
+
if (parsed?.probeVersion !== RENDERING_CAPABILITIES_PROBE_VERSION ||
|
|
58
|
+
parsed?.renderer !== renderer ||
|
|
59
|
+
parsed?.webgl2 !== webgl2 ||
|
|
60
|
+
typeof parsed?.formats !== 'object' ||
|
|
61
|
+
parsed?.formats === null) {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
return { ...NO_GPU_FORMATS, ...parsed.formats };
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
function writeCachedFormats(renderer, webgl2, formats) {
|
|
71
|
+
try {
|
|
72
|
+
const payload = {
|
|
73
|
+
probeVersion: RENDERING_CAPABILITIES_PROBE_VERSION,
|
|
74
|
+
renderer,
|
|
75
|
+
webgl2,
|
|
76
|
+
formats,
|
|
77
|
+
};
|
|
78
|
+
window.localStorage?.setItem(STORAGE_KEY, JSON.stringify(payload));
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
export function detectRenderingCapabilities({ useCache = true, } = {}) {
|
|
84
|
+
const contextInfo = getWebGLContextInfo();
|
|
85
|
+
if (!contextInfo.webgl) {
|
|
86
|
+
return {
|
|
87
|
+
...contextInfo,
|
|
88
|
+
...NO_GPU_FORMATS,
|
|
89
|
+
softwareRasterizer: false,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
let formats = useCache
|
|
93
|
+
? readCachedFormats(contextInfo.renderer, contextInfo.webgl2)
|
|
94
|
+
: null;
|
|
95
|
+
if (!formats) {
|
|
96
|
+
const probed = getSupportedTextureFormats();
|
|
97
|
+
if (probed) {
|
|
98
|
+
writeCachedFormats(contextInfo.renderer, contextInfo.webgl2, probed);
|
|
99
|
+
}
|
|
100
|
+
formats = probed ?? { ...NO_GPU_FORMATS };
|
|
101
|
+
}
|
|
102
|
+
return {
|
|
103
|
+
...contextInfo,
|
|
104
|
+
...formats,
|
|
105
|
+
softwareRasterizer: SOFTWARE_RASTERIZER_PATTERN.test(contextInfo.renderer),
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
export function getRenderingCapabilities() {
|
|
109
|
+
if (!cachedCapabilities) {
|
|
110
|
+
cachedCapabilities = detectRenderingCapabilities();
|
|
111
|
+
}
|
|
112
|
+
return cachedCapabilities;
|
|
113
|
+
}
|
|
114
|
+
export function resetRenderingCapabilities({ clearStorage = false, } = {}) {
|
|
115
|
+
cachedCapabilities = null;
|
|
116
|
+
if (clearStorage) {
|
|
117
|
+
try {
|
|
118
|
+
window.localStorage?.removeItem(STORAGE_KEY);
|
|
119
|
+
}
|
|
120
|
+
catch {
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
export
|
|
1
|
+
export interface TextureFormatSupport {
|
|
2
2
|
norm16: boolean;
|
|
3
3
|
norm16Linear: boolean;
|
|
4
|
-
|
|
4
|
+
float: boolean;
|
|
5
|
+
floatLinear: boolean;
|
|
6
|
+
halfFloat: boolean;
|
|
7
|
+
halfFloatLinear: boolean;
|
|
8
|
+
}
|
|
9
|
+
export declare function getSupportedTextureFormats(): TextureFormatSupport | null;
|
|
@@ -2,14 +2,14 @@ const canvasSize = 4;
|
|
|
2
2
|
const texWidth = 5;
|
|
3
3
|
const texHeight = 1;
|
|
4
4
|
const pixelToCheck = [1, 1];
|
|
5
|
-
function
|
|
5
|
+
function createProbeContext() {
|
|
6
6
|
try {
|
|
7
7
|
const canvas = document.createElement('canvas');
|
|
8
8
|
canvas.width = canvasSize;
|
|
9
9
|
canvas.height = canvasSize;
|
|
10
10
|
const gl = canvas.getContext('webgl2');
|
|
11
11
|
if (!gl) {
|
|
12
|
-
return
|
|
12
|
+
return null;
|
|
13
13
|
}
|
|
14
14
|
const vs = `#version 300 es
|
|
15
15
|
void main() {
|
|
@@ -31,31 +31,40 @@ function main({ ext, filterType, texData, internalFormat, glDataType }) {
|
|
|
31
31
|
color = vec4(vec3(intColor.rrr), 1);
|
|
32
32
|
}
|
|
33
33
|
`;
|
|
34
|
-
let extToUse;
|
|
35
|
-
if (ext) {
|
|
36
|
-
extToUse = gl.getExtension(ext);
|
|
37
|
-
if (!extToUse) {
|
|
38
|
-
return false;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
34
|
const vertexShader = gl.createShader(gl.VERTEX_SHADER);
|
|
42
35
|
gl.shaderSource(vertexShader, vs);
|
|
43
36
|
gl.compileShader(vertexShader);
|
|
44
37
|
if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) {
|
|
45
|
-
return
|
|
38
|
+
return null;
|
|
46
39
|
}
|
|
47
40
|
const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
|
|
48
41
|
gl.shaderSource(fragmentShader, fs);
|
|
49
42
|
gl.compileShader(fragmentShader);
|
|
50
43
|
if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) {
|
|
51
|
-
return
|
|
44
|
+
return null;
|
|
52
45
|
}
|
|
53
46
|
const program = gl.createProgram();
|
|
54
47
|
gl.attachShader(program, vertexShader);
|
|
55
48
|
gl.attachShader(program, fragmentShader);
|
|
56
49
|
gl.linkProgram(program);
|
|
57
50
|
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
|
|
58
|
-
return
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
gl.useProgram(program);
|
|
54
|
+
return gl;
|
|
55
|
+
}
|
|
56
|
+
catch (e) {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
function probeFormat(gl, { ext, filterType, texData, internalFormat, glDataType }) {
|
|
61
|
+
try {
|
|
62
|
+
let extToUse;
|
|
63
|
+
if (ext) {
|
|
64
|
+
extToUse = gl.getExtension(ext);
|
|
65
|
+
if (!extToUse) {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
59
68
|
}
|
|
60
69
|
const tex = gl.createTexture();
|
|
61
70
|
gl.bindTexture(gl.TEXTURE_2D, tex);
|
|
@@ -63,15 +72,13 @@ function main({ ext, filterType, texData, internalFormat, glDataType }) {
|
|
|
63
72
|
const filter = filterType === 'LINEAR' ? gl.LINEAR : gl.NEAREST;
|
|
64
73
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, filter);
|
|
65
74
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, filter);
|
|
66
|
-
gl.
|
|
75
|
+
gl.clearColor(0, 0, 0, 0);
|
|
76
|
+
gl.clear(gl.COLOR_BUFFER_BIT);
|
|
67
77
|
gl.drawArrays(gl.POINTS, 0, 1);
|
|
68
78
|
const pixel = new Uint8Array(4);
|
|
69
79
|
gl.readPixels(pixelToCheck[0], pixelToCheck[1], 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixel);
|
|
70
80
|
const [r, g, b] = pixel;
|
|
71
|
-
|
|
72
|
-
if (webglLoseContext) {
|
|
73
|
-
webglLoseContext.loseContext();
|
|
74
|
-
}
|
|
81
|
+
gl.deleteTexture(tex);
|
|
75
82
|
return r === g && g === b && r !== 0;
|
|
76
83
|
}
|
|
77
84
|
catch (e) {
|
|
@@ -79,23 +86,60 @@ function main({ ext, filterType, texData, internalFormat, glDataType }) {
|
|
|
79
86
|
}
|
|
80
87
|
}
|
|
81
88
|
export function getSupportedTextureFormats() {
|
|
89
|
+
const gl = createProbeContext();
|
|
90
|
+
if (!gl) {
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
82
93
|
const norm16TexData = new Int16Array([
|
|
83
94
|
32767, 2000, 3000, 4000, 5000, 16784, 7000, 8000, 9000, 32767,
|
|
84
95
|
]);
|
|
85
|
-
|
|
86
|
-
|
|
96
|
+
const floatTexData = new Float32Array([0.3, 0.2, 0.3, 0.4, 0.5]);
|
|
97
|
+
const halfFloatTexData = new Uint16Array([13517, 12902, 13517, 13926, 14336]);
|
|
98
|
+
const result = {
|
|
99
|
+
norm16: probeFormat(gl, {
|
|
87
100
|
ext: 'EXT_texture_norm16',
|
|
88
101
|
filterType: 'NEAREST',
|
|
89
102
|
texData: norm16TexData,
|
|
90
|
-
internalFormat: (
|
|
91
|
-
glDataType: (
|
|
103
|
+
internalFormat: (_gl, ext) => ext.R16_SNORM_EXT,
|
|
104
|
+
glDataType: (_gl) => _gl.SHORT,
|
|
92
105
|
}),
|
|
93
|
-
norm16Linear:
|
|
106
|
+
norm16Linear: probeFormat(gl, {
|
|
94
107
|
ext: 'EXT_texture_norm16',
|
|
95
108
|
filterType: 'LINEAR',
|
|
96
109
|
texData: norm16TexData,
|
|
97
|
-
internalFormat: (
|
|
98
|
-
glDataType: (
|
|
110
|
+
internalFormat: (_gl, ext) => ext.R16_SNORM_EXT,
|
|
111
|
+
glDataType: (_gl) => _gl.SHORT,
|
|
112
|
+
}),
|
|
113
|
+
float: probeFormat(gl, {
|
|
114
|
+
filterType: 'NEAREST',
|
|
115
|
+
texData: floatTexData,
|
|
116
|
+
internalFormat: (_gl) => _gl.R32F,
|
|
117
|
+
glDataType: (_gl) => _gl.FLOAT,
|
|
118
|
+
}),
|
|
119
|
+
floatLinear: probeFormat(gl, {
|
|
120
|
+
ext: 'OES_texture_float_linear',
|
|
121
|
+
filterType: 'LINEAR',
|
|
122
|
+
texData: floatTexData,
|
|
123
|
+
internalFormat: (_gl) => _gl.R32F,
|
|
124
|
+
glDataType: (_gl) => _gl.FLOAT,
|
|
125
|
+
}),
|
|
126
|
+
halfFloat: probeFormat(gl, {
|
|
127
|
+
filterType: 'NEAREST',
|
|
128
|
+
texData: halfFloatTexData,
|
|
129
|
+
internalFormat: (_gl) => _gl.R16F,
|
|
130
|
+
glDataType: (_gl) => _gl.HALF_FLOAT,
|
|
131
|
+
}),
|
|
132
|
+
halfFloatLinear: probeFormat(gl, {
|
|
133
|
+
filterType: 'LINEAR',
|
|
134
|
+
texData: halfFloatTexData,
|
|
135
|
+
internalFormat: (_gl) => _gl.R16F,
|
|
136
|
+
glDataType: (_gl) => _gl.HALF_FLOAT,
|
|
99
137
|
}),
|
|
100
138
|
};
|
|
139
|
+
const contextLost = gl.isContextLost();
|
|
140
|
+
const webglLoseContext = gl.getExtension('WEBGL_lose_context');
|
|
141
|
+
if (webglLoseContext) {
|
|
142
|
+
webglLoseContext.loseContext();
|
|
143
|
+
}
|
|
144
|
+
return contextLost ? null : result;
|
|
101
145
|
}
|
package/dist/esm/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const version = "5.
|
|
1
|
+
export declare const version = "5.3.0";
|
package/dist/esm/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const version = '5.
|
|
1
|
+
export const version = '5.3.0';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cornerstonejs/core",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.3.0",
|
|
4
4
|
"description": "Cornerstone3D Core",
|
|
5
5
|
"module": "./dist/esm/index.js",
|
|
6
6
|
"types": "./dist/esm/index.d.ts",
|
|
@@ -85,18 +85,18 @@
|
|
|
85
85
|
"prepublishOnly": "pnpm run build"
|
|
86
86
|
},
|
|
87
87
|
"dependencies": {
|
|
88
|
-
"@cornerstonejs/utils": "5.
|
|
88
|
+
"@cornerstonejs/utils": "5.3.0",
|
|
89
89
|
"@kitware/vtk.js": "35.5.3",
|
|
90
90
|
"comlink": "4.4.2",
|
|
91
91
|
"gl-matrix": "3.4.3",
|
|
92
92
|
"loglevel": "1.9.2"
|
|
93
93
|
},
|
|
94
94
|
"devDependencies": {
|
|
95
|
-
"@cornerstonejs/metadata": "5.
|
|
95
|
+
"@cornerstonejs/metadata": "5.3.0"
|
|
96
96
|
},
|
|
97
97
|
"peerDependencies": {
|
|
98
|
-
"@cornerstonejs/metadata": "5.
|
|
99
|
-
"@cornerstonejs/utils": "5.
|
|
98
|
+
"@cornerstonejs/metadata": "5.3.0",
|
|
99
|
+
"@cornerstonejs/utils": "5.3.0"
|
|
100
100
|
},
|
|
101
101
|
"contributors": [
|
|
102
102
|
{
|
|
@@ -109,5 +109,5 @@
|
|
|
109
109
|
"type": "individual",
|
|
110
110
|
"url": "https://ohif.org/donate"
|
|
111
111
|
},
|
|
112
|
-
"gitHead": "
|
|
112
|
+
"gitHead": "6032c1e2640bcd18c7bd2bfb27181052b0e5d28e"
|
|
113
113
|
}
|