Skip to content

Commit

Permalink
fix(rendering): test norm16 linear to decide on using it (#1801)
Browse files Browse the repository at this point in the history
  • Loading branch information
sedghi authored Feb 3, 2025
1 parent 1739d37 commit a08dbbd
Show file tree
Hide file tree
Showing 8 changed files with 213 additions and 41 deletions.
2 changes: 1 addition & 1 deletion packages/core/examples/volumeViewport3D/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ async function run() {
'1.3.6.1.4.1.14519.5.2.1.7009.2403.871108593056125491804754960339',
SeriesInstanceUID:
'1.3.6.1.4.1.14519.5.2.1.7009.2403.367700692008930469189923116409',
wadoRsRoot: 'https://domvja9iplmyu.cloudfront.net/dicomweb',
wadoRsRoot: 'https://d14fa38qiwhyfd.cloudfront.net/dicomweb',
});

// Instantiate a rendering engine
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import vtkDataArray from '@kitware/vtk.js/Common/Core/DataArray';
import { Representation } from '@kitware/vtk.js/Rendering/Core/Property/Constants';
import vtkOpenGLTexture from '@kitware/vtk.js/Rendering/OpenGL/Texture';
import { getConstructorFromType } from '../../utilities/getBufferConfiguration';
import { getCanUseNorm16Texture } from '../../init';

/**
* vtkStreamingOpenGLVolumeMapper - A derived class of the core vtkOpenGLVolumeMapper class.
Expand Down Expand Up @@ -261,7 +262,9 @@ function vtkStreamingOpenGLVolumeMapper(publicAPI, model) {

if (shouldReset) {
const norm16Ext = model.context.getExtension('EXT_texture_norm16');
model.scalarTexture.setOglNorm16Ext(norm16Ext);
model.scalarTexture.setOglNorm16Ext(
getCanUseNorm16Texture() ? norm16Ext : null
);
model.scalarTexture.resetFormatAndType();

model.scalarTexture.setTextureParameters({
Expand Down
24 changes: 11 additions & 13 deletions packages/core/src/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ let csRenderInitialized = false;
import deepMerge from './utilities/deepMerge';
import type { Cornerstone3DConfig } from './types';
import CentralizedWebWorkerManager from './webWorkerManager/webWorkerManager';
import { getSupportedTextureFormats } from './utilities/textureSupport';

// TODO: change config into a class with methods to better control get/set
const defaultConfig: Cornerstone3DConfig = {
Expand All @@ -28,6 +29,7 @@ let config: Cornerstone3DConfig = {
};

let webWorkerManager = null;
let canUseNorm16Texture = false;

function _getGLContext(): RenderingContext {
// Create canvas element. The canvas is not added to the
Expand All @@ -54,19 +56,8 @@ function _hasActiveWebGLContext() {
}

function _hasNorm16TextureSupport() {
const gl = _getGLContext();

if (gl) {
const ext = (gl as WebGL2RenderingContext).getExtension(
'EXT_texture_norm16'
);

if (ext) {
return true;
}
}

return false;
const supportedTextureFormats = getSupportedTextureFormats();
return supportedTextureFormats.norm16 && supportedTextureFormats.norm16Linear;
}

function isIOS() {
Expand Down Expand Up @@ -101,6 +92,8 @@ function init(configuration = config): boolean {
return csRenderInitialized;
}

canUseNorm16Texture = _hasNorm16TextureSupport();

// merge configs
config = deepMerge(defaultConfig, configuration);

Expand Down Expand Up @@ -131,6 +124,10 @@ function init(configuration = config): boolean {
return csRenderInitialized;
}

function getCanUseNorm16Texture(): boolean {
return canUseNorm16Texture;
}

/**
* It sets the useCPURenderingOnlyForDebugOrTests variable to the status value.
* This only should be used for debugging or tests. DO NOT USE IT IF YOU ARE NOT
Expand Down Expand Up @@ -255,4 +252,5 @@ export {
canRenderFloatTextures,
peerImport,
resetInitialization,
getCanUseNorm16Texture,
};
160 changes: 160 additions & 0 deletions packages/core/src/utilities/textureSupport.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
const canvasSize = 4;
const texWidth = 5;
const texHeight = 1;
const pixelToCheck = [1, 1];

function main({ ext, filterType, texData, internalFormat, glDataType }) {
try {
const canvas = document.createElement('canvas');
canvas.width = canvasSize;
canvas.height = canvasSize;
const gl = canvas.getContext('webgl2');
if (!gl) {
return false;
}

const vs = `#version 300 es
void main() {
gl_PointSize = ${canvasSize.toFixed(1)};
gl_Position = vec4(0, 0, 0, 1);
}
`;
const fs = `#version 300 es
precision highp float;
precision highp int;
precision highp sampler2D;
uniform sampler2D u_image;
out vec4 color;
void main() {
vec4 intColor = texture(u_image, gl_PointCoord.xy);
color = vec4(vec3(intColor.rrr), 1);
}
`;

let extToUse;
if (ext) {
extToUse = gl.getExtension(ext);
if (!extToUse) {
return false;
}
}

const vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, vs);
gl.compileShader(vertexShader);
if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) {
return false;
}

const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, fs);
gl.compileShader(fragmentShader);
if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) {
return false;
}

const program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);

if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
return false;
}

const tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);
gl.texImage2D(
gl.TEXTURE_2D,
0,
internalFormat(gl, extToUse),
texWidth,
texHeight,
0,
gl.RED,
glDataType(gl, extToUse),
texData
);

const filter = filterType === 'LINEAR' ? gl.LINEAR : gl.NEAREST;
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, filter);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, filter);
gl.useProgram(program);
gl.drawArrays(gl.POINTS, 0, 1);

const pixel = new Uint8Array(4);
gl.readPixels(
pixelToCheck[0],
pixelToCheck[1],
1,
1,
gl.RGBA,
gl.UNSIGNED_BYTE,
pixel
);
const [r, g, b] = pixel;

const webglLoseContext = gl.getExtension('WEBGL_lose_context');
if (webglLoseContext) {
webglLoseContext.loseContext();
}

return r === g && g === b && r !== 0;
} catch (e) {
return false;
}
}

export function getSupportedTextureFormats() {
const norm16TexData = new Int16Array([
32767, 2000, 3000, 4000, 5000, 16784, 7000, 8000, 9000, 32767,
]);

// const floatTexData = new Float32Array([0.3, 0.2, 0.3, 0.4, 0.5]);
// const halfFloatTexData = new Uint16Array([13517, 12902, 13517, 13926, 14336]);

return {
norm16: main({
ext: 'EXT_texture_norm16',
filterType: 'NEAREST',
texData: norm16TexData,
internalFormat: (gl, ext) => ext.R16_SNORM_EXT,
glDataType: (gl) => gl.SHORT,
}),
norm16Linear: main({
ext: 'EXT_texture_norm16',
filterType: 'LINEAR',
texData: norm16TexData,
internalFormat: (gl, ext) => ext.R16_SNORM_EXT,
glDataType: (gl) => gl.SHORT,
}),
// float: main({
// filterType: 'NEAREST',
// texData: floatTexData,
// internalFormat: (gl) => gl.R16F,
// glDataType: (gl) => gl.FLOAT,
// }),
// floatLinear: main({
// ext: 'OES_texture_float_linear',
// filterType: 'LINEAR',
// texData: floatTexData,
// internalFormat: (gl) => gl.R16F,
// glDataType: (gl) => gl.FLOAT,
// }),
// halfFloat: main({
// filterType: 'NEAREST',
// texData: halfFloatTexData,
// internalFormat: (gl) => gl.R16F,
// glDataType: (gl) => gl.HALF_FLOAT,
// }),
// halfFloatLinear: main({
// filterType: 'LINEAR',
// texData: halfFloatTexData,
// internalFormat: (gl) => gl.R16F,
// glDataType: (gl) => gl.HALF_FLOAT,
// }),
};
}
14 changes: 13 additions & 1 deletion packages/docs/docs/getting-started/vue-angular-react-etc.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,15 @@ export default defineConfig({

## Troubleshooting

### 1. @icr/polyseg-wasm Build Issues
### 1. Polyseg & Labelmap interpolation

By default, we don't include the `@icr/polyseg-wasm`, `itk-wasm`, and `@itk-wasm/morphological-contour-interpolation` libraries in our bundle to keep the size pretty small. If you need these features, you'll need to install them separately and import them into your project. You can do this by running

```bash
yarn install @icr/polyseg-wasm itk-wasm @itk-wasm/morphological-contour-interpolation
```

### 1. Build Issues

If you're using 3D segmentation features and encounter issues with `@icr/polyseg-wasm`, add the following to your Vite configuration:

Expand All @@ -44,6 +52,10 @@ build: {
},
```

:::note
You might need to add `external: ["itk-wasm", "@itk-wasm/morphological-contour-interpolation"],` to the rollupOptions as well
:::

### 2. Path Resolution Issues with @cornerstonejs/core

If you encounter the error "No known conditions for "./types" specifier in "@cornerstonejs/core" package" during build (while development works fine), add the following alias to your Vite configuration:
Expand Down
2 changes: 1 addition & 1 deletion packages/tools/examples/rectangleROIThreshold/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ async function run() {
bindings: [{ mouseButton: MouseBindings.Wheel }],
});

const wadoRsRoot = 'https://domvja9iplmyu.cloudfront.net/dicomweb';
const wadoRsRoot = 'https://d14fa38qiwhyfd.cloudfront.net/dicomweb';
const StudyInstanceUID =
'1.3.6.1.4.1.14519.5.2.1.7009.2403.871108593056125491804754960339';

Expand Down
30 changes: 15 additions & 15 deletions packages/tools/examples/referenceLines/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -216,42 +216,42 @@ async function run() {
// Get Cornerstone imageIds and fetch metadata into RAM
const t2_tse_sag = await createImageIdsAndCacheMetaData({
StudyInstanceUID:
'1.3.6.1.4.1.14519.5.2.1.7311.5101.158323547117540061132729905711',
'1.3.6.1.4.1.14519.5.2.1.7310.5101.860473186348887719777907797922',
SeriesInstanceUID:
'1.3.6.1.4.1.14519.5.2.1.7311.5101.250911858840767891342974687368',
wadoRsRoot: 'https://domvja9iplmyu.cloudfront.net/dicomweb',
'1.3.6.1.4.1.14519.5.2.1.7310.5101.273373775382048821331022842977',
wadoRsRoot: 'https://d14fa38qiwhyfd.cloudfront.net/dicomweb',
});

const t2_tse_tra = await createImageIdsAndCacheMetaData({
StudyInstanceUID:
'1.3.6.1.4.1.14519.5.2.1.7311.5101.158323547117540061132729905711',
'1.3.6.1.4.1.14519.5.2.1.7310.5101.860473186348887719777907797922',
SeriesInstanceUID:
'1.3.6.1.4.1.14519.5.2.1.7311.5101.160028252338004527274326500702',
wadoRsRoot: 'https://domvja9iplmyu.cloudfront.net/dicomweb',
'1.3.6.1.4.1.14519.5.2.1.7310.5101.181235565127625868343692734421',
wadoRsRoot: 'https://d14fa38qiwhyfd.cloudfront.net/dicomweb',
});

const t2_tse_cor = await createImageIdsAndCacheMetaData({
StudyInstanceUID:
'1.3.6.1.4.1.14519.5.2.1.7311.5101.158323547117540061132729905711',
'1.3.6.1.4.1.14519.5.2.1.7310.5101.860473186348887719777907797922',
SeriesInstanceUID:
'1.3.6.1.4.1.14519.5.2.1.7311.5101.604184452348902957788528403471',
wadoRsRoot: 'https://domvja9iplmyu.cloudfront.net/dicomweb',
'1.3.6.1.4.1.14519.5.2.1.7310.5101.541287716256540872350916735453',
wadoRsRoot: 'https://d14fa38qiwhyfd.cloudfront.net/dicomweb',
});

const adc = await createImageIdsAndCacheMetaData({
StudyInstanceUID:
'1.3.6.1.4.1.14519.5.2.1.7311.5101.158323547117540061132729905711',
'1.3.6.1.4.1.14519.5.2.1.7310.5101.860473186348887719777907797922',
SeriesInstanceUID:
'1.3.6.1.4.1.14519.5.2.1.7311.5101.339319789559896104041345048780',
wadoRsRoot: 'https://domvja9iplmyu.cloudfront.net/dicomweb',
'1.3.6.1.4.1.14519.5.2.1.7310.5101.578717574224767028424309620369',
wadoRsRoot: 'https://d14fa38qiwhyfd.cloudfront.net/dicomweb',
});

const t2_tse_tra_vol = await createImageIdsAndCacheMetaData({
StudyInstanceUID:
'1.3.6.1.4.1.14519.5.2.1.7311.5101.158323547117540061132729905711',
'1.3.6.1.4.1.14519.5.2.1.7310.5101.860473186348887719777907797922',
SeriesInstanceUID:
'1.3.6.1.4.1.14519.5.2.1.7311.5101.160028252338004527274326500702',
wadoRsRoot: 'https://domvja9iplmyu.cloudfront.net/dicomweb',
'1.3.6.1.4.1.14519.5.2.1.7310.5101.318150454185225367122580810394',
wadoRsRoot: 'https://d14fa38qiwhyfd.cloudfront.net/dicomweb',
});

// Instantiate a rendering engine
Expand Down
17 changes: 8 additions & 9 deletions packages/tools/examples/scaleOverlayTool/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,9 @@ element2.style.height = '500px';
viewportGrid.appendChild(element);
viewportGrid.appendChild(element2);
content.appendChild(viewportGrid);

const wadoRsRoot = 'https://d14fa38qiwhyfd.cloudfront.net/dicomweb';
const StudyInstanceUID =
'1.3.6.1.4.1.14519.5.2.1.7009.2403.334240657131972136850343327463';
const instructions = document.createElement('p');
instructions.innerText =
'Left Click: Length Tool\nRight Click: Zoom\n Mouse Wheel: Stack Scroll';
Expand Down Expand Up @@ -141,19 +143,16 @@ async function run() {

// Get Cornerstone imageIds and fetch metadata into RAM
const imageIds = await createImageIdsAndCacheMetaData({
StudyInstanceUID:
'1.3.6.1.4.1.14519.5.2.1.7311.5101.158323547117540061132729905711',
StudyInstanceUID,
SeriesInstanceUID:
'1.3.6.1.4.1.14519.5.2.1.7311.5101.250911858840767891342974687368',
wadoRsRoot: 'https://domvja9iplmyu.cloudfront.net/dicomweb',
'1.3.6.1.4.1.14519.5.2.1.7009.2403.879445243400782656317561081015',
wadoRsRoot,
});

const imageIds2 = await createImageIdsAndCacheMetaData({
StudyInstanceUID:
'1.3.6.1.4.1.14519.5.2.1.7009.2403.334240657131972136850343327463',
StudyInstanceUID,
SeriesInstanceUID:
'1.3.6.1.4.1.14519.5.2.1.7009.2403.226151125820845824875394858561',
wadoRsRoot: 'https://d14fa38qiwhyfd.cloudfront.net/dicomweb',
wadoRsRoot,
});
// Instantiate a rendering engine
const renderingEngineId = 'myRenderingEngine';
Expand Down

0 comments on commit a08dbbd

Please sign in to comment.