Skip to content

Commit

Permalink
(feat): Upgrade deck.gl and luma.gl (#805)
Browse files Browse the repository at this point in the history
* chore: wip attempt to upgrade deck&luma

* (fix): set `UNPACK_ALIGNMENT` and `PACK_ALIGNMENT` correctly

* (fix): use `float64` string instead of `GL.DOUBLE`

* (fix): `parameters` -> `sampler` and fix some consts related to `getRenderingAttrs`

* change Geometry drawMode to topology

* use triangle-list rather than fan (not verified to be correct)

* use setBindings in place of setUniforms

* correct size of texCoord attribute

* add bufferLayout to model, texCoords to attributeManager, rename shaderAssembler.

* chore: apply biome fix & remove unused GL imports

* chore: remove some dead code, rename (unused) gl arg, add comments

* rename 'device' to 'gl' (and comment that it's unused)

* set log level, allows us to see shader compilation errors

* change 'attribute' & 'varying' to 'in' & 'out', don't use gl_FragColor

* make sure opts are passed through draw, no null textures and 'uniform' object was spurious.

* (fix) geometry indices, remove bad texCoord attribute val

* no more cursed shader version patching

* correct format of setParametersWebGL args

* check if texture format is filterable

* use setBindings for textures, setUniforms for uniforms.

* remove references to WebGL1

* (fix): less wrong null texture handling

* (fix): remove filterable check

* passing simpler texture format, 3D still not working seemingly because of luma bug

* (chore) update luma&deck

* (chore): `model.delete` -> `model.destroy`

* chore: update zustand

* fix warning about deprecated 'import shallow'

* fix typo 'magFilterFilter'

* add comments on format to source-info

* SizeZ comments

* attempt to upgrade to luma.gl 9.0.16, dodgy lock file

* regenerate pnpm-lock to fix multiple luma.gl versions

* update deck & luma

* apply work-around for null textures

* (fix): rgb images, add alpha channel

* lensSelection was being set as string when it should be int

* (chore) update luma.gl

* (chore) update deck.gl

* allow newer react

* remove apparently redundant and deprecated gl alignment parameter setting.

* (chore) cleanup some old comments and unused imports

* (fix) move null texture patching to a more appropriate place

* remove commented code

Co-authored-by: Ilan Gold <[email protected]>

* (chore) remove redundant comments

* (chore) remove more redundant comments

* fix issue with scale-bar empty layer test by passing viewState width and height in defaultProps

* fix glsl-colormap needed to be a non-dev dependency

* Revert "chore: update zustand"

This reverts commit 2cf31b0.

* Revert "fix warning about deprecated 'import shallow'"

This reverts commit e2b5d50.

* Revert "remove apparently redundant and deprecated gl alignment parameter setting."

This reverts commit 7a1dd44.

* change comment on setParametersWebGL

* Revert "fix glsl-colormap needed to be a non-dev dependency"

This reverts commit f4be45b.

* fix missing GL import

* update type and documentation of 'interpolation' prop in line with luma changes

* fix type of interpolation in defaultProps

* (chore) update deck.gl

* (chore): rgb comment

* (fix): lint

---------

Co-authored-by: ilan-gold <[email protected]>
  • Loading branch information
xinaesthete and ilan-gold authored Nov 20, 2024
1 parent 6a4f915 commit 97aae18
Show file tree
Hide file tree
Showing 24 changed files with 1,711 additions and 1,257 deletions.
5 changes: 1 addition & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,4 @@ The [Changesets GitHub Action](https://github.com/changesets/action) will create

## 🌎 Browser Support

Viv supports both [WebGL1](https://caniuse.com/?search=webgl) and [WebGL2](https://caniuse.com/?search=webgl2)
contexts, to provides coverage across Safari, Firefox, Chrome, and Edge. Please
[file an issue](https://github.com/hms-dbmi/viv/issues/new) if you find a browser
in which Viv does not work.
Viv supports coverage across Safari, Firefox, Chrome, and Edge. Please [file an issue](https://github.com/hms-dbmi/viv/issues/new) if you find a browser in which Viv does not work.
18 changes: 9 additions & 9 deletions packages/constants/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import GL from '@luma.gl/constants';
import { GL } from '@luma.gl/constants';

export const MAX_COLOR_INTENSITY = 255;

Expand All @@ -18,28 +18,28 @@ export const DEFAULT_FONT_FAMILY =
*/
export const DTYPE_VALUES = {
Uint8: {
format: GL.R8UI,
format: 'r8uint',
dataFormat: GL.RED_INTEGER,
type: GL.UNSIGNED_BYTE,
max: 2 ** 8 - 1,
sampler: 'usampler2D'
},
Uint16: {
format: GL.R16UI,
format: 'r16uint',
dataFormat: GL.RED_INTEGER,
type: GL.UNSIGNED_SHORT,
max: 2 ** 16 - 1,
sampler: 'usampler2D'
},
Uint32: {
format: GL.R32UI,
format: 'r32uint',
dataFormat: GL.RED_INTEGER,
type: GL.UNSIGNED_INT,
max: 2 ** 32 - 1,
sampler: 'usampler2D'
},
Float32: {
format: GL.R32F,
format: 'r32float',
dataFormat: GL.RED,
type: GL.FLOAT,
// Not sure what to do about this one - a good use case for channel stats, I suppose:
Expand All @@ -48,29 +48,29 @@ export const DTYPE_VALUES = {
sampler: 'sampler2D'
},
Int8: {
format: GL.R8I,
format: 'r8int',
dataFormat: GL.RED_INTEGER,
type: GL.BYTE,
max: 2 ** (8 - 1) - 1,
sampler: 'isampler2D'
},
Int16: {
format: GL.R16I,
format: 'r16int',
dataFormat: GL.RED_INTEGER,
type: GL.SHORT,
max: 2 ** (16 - 1) - 1,
sampler: 'isampler2D'
},
Int32: {
format: GL.R32I,
format: 'r32int',
dataFormat: GL.RED_INTEGER,
type: GL.INT,
max: 2 ** (32 - 1) - 1,
sampler: 'isampler2D'
},
// Cast Float64 as 32 bit float point so it can be rendered.
Float64: {
format: GL.R32F,
format: 'r32float',
dataFormat: GL.RED,
type: GL.FLOAT,
// Not sure what to do about this one - a good use case for channel stats, I suppose:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,10 @@ const BaseExtension = class extends LayerExtension {
updateState({ props, oldProps, changeFlags, ...rest }) {
super.updateState({ props, oldProps, changeFlags, ...rest });
if (props.colormap !== oldProps.colormap) {
const { gl } = this.context;
const { device } = this.context;
if (this.state.model) {
this.state.model.delete();
this.setState({ model: this._getModel(gl) });
this.state.model.destroy();
this.setState({ model: this._getModel(device) });
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,10 @@ const AdditiveColormapExtension = class extends LayerExtension {
updateState({ props, oldProps, changeFlags, ...rest }) {
super.updateState({ props, oldProps, changeFlags, ...rest });
if (props.colormap !== oldProps.colormap) {
const { gl } = this.context;
const { device } = this.context;
if (this.state.model) {
this.state.model.delete();
this.setState({ model: this._getModel(gl) });
this.state.model.destroy();
this.setState({ model: this._getModel(device) });
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion packages/extensions/src/lens-extension/lens-module.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ export default {
`,
'fs:#main-end': `
bool isFragOnLensBounds = frag_on_lens_bounds(vTexCoord);
gl_FragColor = (lensEnabled && isFragOnLensBounds) ? vec4(lensBorderColor, 1.) : gl_FragColor;
fragColor = (lensEnabled && isFragOnLensBounds) ? vec4(lensBorderColor, 1.) : fragColor;
`
}
};
1 change: 1 addition & 0 deletions packages/layers/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"@deck.gl/geo-layers": "catalog:",
"@deck.gl/layers": "catalog:",
"@luma.gl/constants": "catalog:",
"@luma.gl/shadertools": "catalog:",
"@luma.gl/core": "catalog:",
"@luma.gl/engine": "catalog:",
"@luma.gl/webgl": "catalog:"
Expand Down
31 changes: 12 additions & 19 deletions packages/layers/src/bitmap-layer.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { COORDINATE_SYSTEM, CompositeLayer } from '@deck.gl/core';
import { BitmapLayer as BaseBitmapLayer } from '@deck.gl/layers';
import GL from '@luma.gl/constants';
import { Geometry, Model } from '@luma.gl/core';
import { GL } from '@luma.gl/constants';
import { Model } from '@luma.gl/engine';
import { addAlpha } from './utils';

const PHOTOMETRIC_INTERPRETATIONS = {
WhiteIsZero: 0,
Expand Down Expand Up @@ -88,22 +89,11 @@ class BitmapLayerWrapper extends BaseBitmapLayer {
photometricInterpretation,
transparentColorInHook
);
if (!gl) {
return null;
}

/*
0,0 --- 1,0
| |
0,1 --- 1,1
*/
return new Model(gl, {
return new Model(this.context.device, {
...this.getShaders(),
id: this.props.id,
geometry: new Geometry({
drawMode: GL.TRIANGLES,
vertexCount: 6
}),
bufferLayout: this.getAttributeManager().getBufferLayouts(),
topology: 'triangle-list',
isInstanced: false,
inject: {
'fs:DECKGL_FILTER_COLOR': photometricInterpretationShader
Expand Down Expand Up @@ -131,15 +121,17 @@ class BitmapLayerWrapper extends BaseBitmapLayer {
*/
const BitmapLayer = class extends CompositeLayer {
initializeState(args) {
const { gl } = this.context;
const { device } = this.context;
// This tells WebGL how to read row data from the texture. For example, the default here is 4 (i.e for RGBA, one byte per channel) so
// each row of data is expected to be a multiple of 4. This setting (i.e 1) allows us to have non-multiple-of-4 row sizes. For example, for 2 byte (16 bit data),
// we could use 2 as the value and it would still work, but 1 also works fine (and is more flexible for 8 bit - 1 byte - textures as well).
// https://stackoverflow.com/questions/42789896/webgl-error-arraybuffer-not-big-enough-for-request-in-case-of-gl-luminance
// This needs to be called here and not in the BitmapLayerWrapper because the `image` prop is converted to a texture outside of the layer, as controlled by the `image` type.
// See: https://github.com/visgl/deck.gl/pull/5197
gl.pixelStorei(GL.UNPACK_ALIGNMENT, 1);
gl.pixelStorei(GL.PACK_ALIGNMENT, 1);
device.setParametersWebGL({
[GL.UNPACK_ALIGNMENT]: 1,
[GL.PACK_ALIGNMENT]: 1
});
super.initializeState(args);
}

Expand All @@ -149,6 +141,7 @@ const BitmapLayer = class extends CompositeLayer {
transparentColor: transparentColorInHook
} = this.props;
const transparentColor = getTransparentColor(photometricInterpretation);
this.props.image.data = addAlpha(this.props.image.data);
return new BitmapLayerWrapper(this.props, {
// transparentColor is a prop applied to the original image data by deck.gl's
// BitmapLayer and needs to be in the original colorspace. It is used to determine
Expand Down
9 changes: 4 additions & 5 deletions packages/layers/src/image-layer.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { COORDINATE_SYSTEM, CompositeLayer } from '@deck.gl/core';
import GL from '@luma.gl/constants';
import { GL } from '@luma.gl/constants';

import { ColorPaletteExtension } from '@vivjs/extensions';
import { SIGNAL_ABORTED, isInterleaved } from '@vivjs/loaders';
Expand Down Expand Up @@ -27,7 +27,7 @@ const defaultProps = {
onViewportLoad: { type: 'function', value: null, compare: true },
interpolation: {
type: 'number',
value: GL.NEAREST,
value: 'nearest',
compare: true
},
extensions: {
Expand Down Expand Up @@ -88,9 +88,8 @@ const ImageLayer = class extends CompositeLayer {
// data is for BitmapLayer and needs to be of form { data: Uint8Array, width, height };
raster.data = raster.data[0];
if (raster.data.length === raster.width * raster.height * 3) {
// data is RGB (not RGBA) and need to update texture formats
raster.format = GL.RGB;
raster.dataFormat = GL.RGB;
// Previously there was a rgb format, but now we only convert to rgba in BitmapLater
raster.format = 'rgba8unorm';
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { CompositeLayer } from '@deck.gl/core';
import GL from '@luma.gl/constants';
import { GL } from '@luma.gl/constants';
import { Matrix4 } from '@math.gl/core';

import { ColorPaletteExtension } from '@vivjs/extensions';
Expand Down Expand Up @@ -108,8 +108,8 @@ const MultiscaleImageLayer = class extends CompositeLayer {
if (isInterleaved(loader[resolution].shape)) {
tile.data = tile.data[0];
if (tile.data.length === tile.width * tile.height * 3) {
tile.format = GL.RGB;
tile.dataFormat = GL.RGB; // is this not properly inferred?
// This indicates the data is RGB but it will be converted to RGBA
tile.format = 'rgba8unorm';
}
// can just return early, no need to check for webgl2
return tile;
Expand Down Expand Up @@ -179,7 +179,7 @@ const MultiscaleImageLayer = class extends CompositeLayer {
onHover,
onClick,
// Background image is nicest when LINEAR in my opinion.
interpolation: GL.LINEAR,
interpolation: 'linear',
onViewportLoad: null
});
const layers = [baseLayer, tiledLayer];
Expand Down
3 changes: 1 addition & 2 deletions packages/layers/src/multiscale-image-layer/utils.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import GL from '@luma.gl/constants';
import { getImageSize, isInterleaved } from '@vivjs/loaders';

import BitmapLayer from '../bitmap-layer';
Expand Down Expand Up @@ -50,6 +49,6 @@ export function renderSubLayers(props) {
id: `tile-sub-layer-${bounds}-${id}`,
tileId: { x, y, z },
// The auto setting is NEAREST at the highest resolution but LINEAR otherwise.
interpolation: z === maxZoom ? GL.NEAREST : GL.LINEAR
interpolation: z === maxZoom ? 'nearest' : 'linear'
});
}
2 changes: 1 addition & 1 deletion packages/layers/src/scale-bar-layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ const defaultProps = {
pickable: { type: 'boolean', value: true, compare: true },
viewState: {
type: 'object',
value: { zoom: 0, target: [0, 0, 0] },
value: { zoom: 0, target: [0, 0, 0], width: 1, height: 1 },
compare: true
},
unit: { type: 'string', value: '', compare: true },
Expand Down
14 changes: 14 additions & 0 deletions packages/layers/src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -258,3 +258,17 @@ export function snapValue(value) {

return [targetOrigUnits, targetNewUnits, snappedUnit.symbol];
}

export function addAlpha(array) {
if (!(array instanceof Uint8Array)) {
throw new Error('Expected Uint8Array');
}
const alphaArray = new Uint8Array(array.length + array.length / 3);
for (let i = 0; i < array.length / 3; i += 1) {
alphaArray[i * 4] = array[i * 3];
alphaArray[i * 4 + 1] = array[i * 3 + 1];
alphaArray[i * 4 + 2] = array[i * 3 + 2];
alphaArray[i * 4 + 3] = 255;
}
return alphaArray;
}
22 changes: 2 additions & 20 deletions packages/layers/src/volume-layer/volume-layer.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { COORDINATE_SYSTEM, CompositeLayer } from '@deck.gl/core';
import GL from '@luma.gl/constants';
import { isWebGL2 } from '@luma.gl/core';
import { GL } from '@luma.gl/constants';
import { Matrix4 } from '@math.gl/core';
import { ColorPalette3DExtensions } from '@vivjs/extensions';

Expand Down Expand Up @@ -34,7 +33,6 @@ const defaultProps = {
clippingPlanes: { type: 'array', value: [], compare: true },
onUpdate: { type: 'function', value: () => {}, compare: true },
useProgressIndicator: { type: 'boolean', value: true, compare: true },
useWebGL1Warning: { type: 'boolean', value: true, compare: true },
extensions: {
type: 'array',
value: [new ColorPalette3DExtensions.AdditiveBlendExtension()],
Expand All @@ -58,7 +56,6 @@ const defaultProps = {
* @property {function=} onViewportLoad Function that gets called when the data in the viewport loads.
* @property {Array.<Object>=} clippingPlanes List of math.gl [Plane](https://math.gl/modules/culling/docs/api-reference/plane) objects.
* @property {boolean=} useProgressIndicator Whether or not to use the default progress text + indicator (default is true)
* @property {boolean=} useWebGL1Warning Whether or not to use the default WebGL1 warning (default is true)
* @property {function=} onUpdate A callback to be used for getting updates of the progress, ({ progress }) => {}
* @property {Array=} extensions [deck.gl extensions](https://deck.gl/docs/developer-guide/custom-layers/layer-extensions) to add to the layers - default is AdditiveBlendExtension from ColorPalette3DExtensions.
*/
Expand Down Expand Up @@ -150,8 +147,7 @@ const VolumeLayer = class extends CompositeLayer {
}

renderLayers() {
const { loader, id, resolution, useProgressIndicator, useWebGL1Warning } =
this.props;
const { loader, id, resolution, useProgressIndicator } = this.props;
const { dtype } = loader[resolution];
const {
data,
Expand All @@ -162,20 +158,6 @@ const VolumeLayer = class extends CompositeLayer {
physicalSizeScalingMatrix,
resolutionMatrix
} = this.state;
const { gl } = this.context;
if (!isWebGL2(gl) && useWebGL1Warning) {
const { viewport } = this.context;
return getTextLayer(
[
'Volume rendering is only available on browsers that support WebGL2. If you',
'are using Safari, you can turn on WebGL2 by navigating in the top menubar',
'to check Develop > Experimental Features > WebGL 2.0 and then refreshing',
'the page.'
].join('\n'),
viewport,
id
);
}
if (!(width && height) && useProgressIndicator) {
const { viewport } = this.context;
return getTextLayer(
Expand Down
Loading

0 comments on commit 97aae18

Please sign in to comment.