Browse Source

recreate visuals based on param changes

- impostor/mesh (spacefill, ball+stick, ellipsoids)
- gpu/cpu mc (isosurface, gaussian surface)
Alexander Rose 4 years ago
parent
commit
61ab205a5d

+ 10 - 35
src/mol-math/geometry/gaussian-density.ts

@@ -1,36 +1,22 @@
 /**
- * Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2018-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
 
 import { Box3D, DensityData, DensityTextureData } from '../geometry';
-import { RuntimeContext, Task } from '../../mol-task';
 import { PositionData } from './common';
-import { GaussianDensityCPU } from './gaussian-density/cpu';
 import { WebGLContext } from '../../mol-gl/webgl/context';
 import { Texture } from '../../mol-gl/webgl/texture';
 import { GaussianDensityTexture2d, GaussianDensityTexture3d } from './gaussian-density/gpu';
+import { Task } from '../../mol-task/task';
+import { GaussianDensityCPU } from './gaussian-density/cpu';
 
-// import { GaussianDensityGPU, GaussianDensityTexture } from './gaussian-density/gpu';
-const GaussianDensityGPU = typeof document !== 'undefined'
-    ? (require('./gaussian-density/gpu') as typeof import('./gaussian-density/gpu')).GaussianDensityGPU
-    : void 0;
-const GaussianDensityTexture = typeof document !== 'undefined'
-    ? (require('./gaussian-density/gpu') as typeof import('./gaussian-density/gpu')).GaussianDensityTexture
-    : void 0;
-
-export const DefaultGaussianDensityGPUProps = {
+export const DefaultGaussianDensityProps = {
     resolution: 1,
     radiusOffset: 0,
     smoothness: 1.5,
 };
-export type GaussianDensityGPUProps = typeof DefaultGaussianDensityGPUProps
-
-export const DefaultGaussianDensityProps = {
-    ...DefaultGaussianDensityGPUProps,
-    useGpu: true,
-};
 export type GaussianDensityProps = typeof DefaultGaussianDensityProps
 
 export type GaussianDensityData = {
@@ -41,36 +27,25 @@ export type GaussianDensityTextureData = {
     radiusFactor: number
 } & DensityTextureData
 
-export function computeGaussianDensity(position: PositionData, box: Box3D, radius: (index: number) => number,  props: GaussianDensityProps, webgl?: WebGLContext) {
+export function computeGaussianDensity(position: PositionData, box: Box3D, radius: (index: number) => number,  props: GaussianDensityProps) {
     return Task.create('Gaussian Density', async ctx => {
-        return await GaussianDensity(ctx, position, box, radius, props, webgl);
-    });
-}
-
-export async function GaussianDensity(ctx: RuntimeContext, position: PositionData, box: Box3D, radius: (index: number) => number,  props: GaussianDensityProps, webgl?: WebGLContext): Promise<GaussianDensityData> {
-    if (props.useGpu) {
-        if (!GaussianDensityGPU) throw 'GPU computation not supported on this platform';
-        if (!webgl) throw 'No WebGL context provided';
-        return GaussianDensityGPU(position, box, radius, props, webgl);
-    } else {
         return await GaussianDensityCPU(ctx, position, box, radius, props);
-    }
+    });
 }
 
-export function computeGaussianDensityTexture(position: PositionData, box: Box3D, radius: (index: number) => number, props: GaussianDensityGPUProps, webgl: WebGLContext, texture?: Texture) {
+export function computeGaussianDensityTexture(position: PositionData, box: Box3D, radius: (index: number) => number, props: GaussianDensityProps, webgl: WebGLContext, texture?: Texture) {
     return _computeGaussianDensityTexture(webgl.isWebGL2 ? '3d' : '2d', position, box, radius, props, webgl, texture);
 }
 
-export function computeGaussianDensityTexture2d(position: PositionData, box: Box3D, radius: (index: number) => number, props: GaussianDensityGPUProps, webgl: WebGLContext, texture?: Texture) {
+export function computeGaussianDensityTexture2d(position: PositionData, box: Box3D, radius: (index: number) => number, props: GaussianDensityProps, webgl: WebGLContext, texture?: Texture) {
     return _computeGaussianDensityTexture('2d', position, box, radius, props, webgl, texture);
 }
 
-export function computeGaussianDensityTexture3d(position: PositionData, box: Box3D, radius: (index: number) => number, props: GaussianDensityGPUProps, webgl: WebGLContext, texture?: Texture) {
+export function computeGaussianDensityTexture3d(position: PositionData, box: Box3D, radius: (index: number) => number, props: GaussianDensityProps, webgl: WebGLContext, texture?: Texture) {
     return _computeGaussianDensityTexture('2d', position, box, radius, props, webgl, texture);
 }
 
-function _computeGaussianDensityTexture(type: '2d' | '3d', position: PositionData, box: Box3D, radius: (index: number) => number, props: GaussianDensityGPUProps, webgl: WebGLContext, texture?: Texture) {
-    if (!GaussianDensityTexture) throw 'GPU computation not supported on this platform';
+function _computeGaussianDensityTexture(type: '2d' | '3d', position: PositionData, box: Box3D, radius: (index: number) => number, props: GaussianDensityProps, webgl: WebGLContext, texture?: Texture) {
     return Task.create('Gaussian Density', async ctx => {
         return type === '2d' ?
             GaussianDensityTexture2d(webgl, position, box, radius, false, props, texture) :

+ 8 - 8
src/mol-math/geometry/gaussian-density/gpu.ts

@@ -7,7 +7,7 @@
 
 import { PositionData } from '../common';
 import { Box3D } from '../../geometry';
-import { GaussianDensityGPUProps, GaussianDensityData, GaussianDensityTextureData } from '../gaussian-density';
+import { GaussianDensityProps, GaussianDensityData, GaussianDensityTextureData } from '../gaussian-density';
 import { OrderedSet } from '../../../mol-data/int';
 import { Vec3, Tensor, Mat4, Vec2 } from '../../linear-algebra';
 import { ValueCell } from '../../../mol-util';
@@ -68,7 +68,7 @@ function getTexture(name: string, webgl: WebGLContext, kind: TextureKind, format
     return webgl.namedTextures[_name];
 }
 
-export function GaussianDensityGPU(position: PositionData, box: Box3D, radius: (index: number) => number, props: GaussianDensityGPUProps, webgl: WebGLContext): GaussianDensityData {
+export function GaussianDensityGPU(position: PositionData, box: Box3D, radius: (index: number) => number, props: GaussianDensityProps, webgl: WebGLContext): GaussianDensityData {
     // always use texture2d when the gaussian density needs to be downloaded from the GPU,
     // it's faster than texture3d
     // console.time('GaussianDensityTexture2d')
@@ -81,17 +81,17 @@ export function GaussianDensityGPU(position: PositionData, box: Box3D, radius: (
     return { field, idField, transform: getTransform(scale, bbox), radiusFactor };
 }
 
-export function GaussianDensityTexture(webgl: WebGLContext, position: PositionData, box: Box3D, radius: (index: number) => number, props: GaussianDensityGPUProps, oldTexture?: Texture): GaussianDensityTextureData {
+export function GaussianDensityTexture(webgl: WebGLContext, position: PositionData, box: Box3D, radius: (index: number) => number, props: GaussianDensityProps, oldTexture?: Texture): GaussianDensityTextureData {
     return webgl.isWebGL2 ?
         GaussianDensityTexture3d(webgl, position, box, radius, props, oldTexture) :
         GaussianDensityTexture2d(webgl, position, box, radius, false, props, oldTexture);
 }
 
-export function GaussianDensityTexture2d(webgl: WebGLContext, position: PositionData, box: Box3D, radius: (index: number) => number, powerOfTwo: boolean, props: GaussianDensityGPUProps, oldTexture?: Texture): GaussianDensityTextureData {
+export function GaussianDensityTexture2d(webgl: WebGLContext, position: PositionData, box: Box3D, radius: (index: number) => number, powerOfTwo: boolean, props: GaussianDensityProps, oldTexture?: Texture): GaussianDensityTextureData {
     return finalizeGaussianDensityTexture(calcGaussianDensityTexture2d(webgl, position, box, radius, powerOfTwo, props, oldTexture));
 }
 
-export function GaussianDensityTexture3d(webgl: WebGLContext, position: PositionData, box: Box3D, radius: (index: number) => number, props: GaussianDensityGPUProps, oldTexture?: Texture): GaussianDensityTextureData {
+export function GaussianDensityTexture3d(webgl: WebGLContext, position: PositionData, box: Box3D, radius: (index: number) => number, props: GaussianDensityProps, oldTexture?: Texture): GaussianDensityTextureData {
     return finalizeGaussianDensityTexture(calcGaussianDensityTexture3d(webgl, position, box, radius, props, oldTexture));
 }
 
@@ -118,7 +118,7 @@ type _GaussianDensityTextureData = {
     radiusFactor: number
 }
 
-function calcGaussianDensityTexture2d(webgl: WebGLContext, position: PositionData, box: Box3D, radius: (index: number) => number, powerOfTwo: boolean, props: GaussianDensityGPUProps, texture?: Texture): _GaussianDensityTextureData {
+function calcGaussianDensityTexture2d(webgl: WebGLContext, position: PositionData, box: Box3D, radius: (index: number) => number, powerOfTwo: boolean, props: GaussianDensityProps, texture?: Texture): _GaussianDensityTextureData {
     // console.log('2d');
     const { gl, resources, state, extensions: { colorBufferFloat, textureFloat, colorBufferHalfFloat, textureHalfFloat } } = webgl;
     const { smoothness, resolution } = props;
@@ -201,7 +201,7 @@ function calcGaussianDensityTexture2d(webgl: WebGLContext, position: PositionDat
     return { texture, scale, bbox: expandedBox, gridDim: dim, gridTexDim, gridTexScale, radiusFactor };
 }
 
-function calcGaussianDensityTexture3d(webgl: WebGLContext, position: PositionData, box: Box3D, radius: (index: number) => number, props: GaussianDensityGPUProps, texture?: Texture): _GaussianDensityTextureData {
+function calcGaussianDensityTexture3d(webgl: WebGLContext, position: PositionData, box: Box3D, radius: (index: number) => number, props: GaussianDensityProps, texture?: Texture): _GaussianDensityTextureData {
     // console.log('3d');
     const { gl, resources, state, extensions: { colorBufferFloat, textureFloat, colorBufferHalfFloat, textureHalfFloat } } = webgl;
     const { smoothness, resolution } = props;
@@ -259,7 +259,7 @@ function calcGaussianDensityTexture3d(webgl: WebGLContext, position: PositionDat
 
 //
 
-function prepareGaussianDensityData(position: PositionData, box: Box3D, radius: (index: number) => number, props: GaussianDensityGPUProps) {
+function prepareGaussianDensityData(position: PositionData, box: Box3D, radius: (index: number) => number, props: GaussianDensityProps) {
     const { resolution, radiusOffset } = props;
     const scaleFactor = 1 / resolution;
 

+ 1 - 3
src/mol-plugin-state/transforms/representation.ts

@@ -653,9 +653,7 @@ const VolumeRepresentation3D = PluginStateTransform.BuiltIn({
         return Task.create('Volume Representation', async ctx => {
             if (newParams.type.name !== oldParams.type.name) {
                 const oldProvider = plugin.representation.volume.registry.get(oldParams.type.name);
-                if (oldProvider.ensureCustomProperties) {
-                    oldProvider.ensureCustomProperties.detach(a.data);
-                }
+                oldProvider.ensureCustomProperties?.detach(a.data);
                 return StateTransformer.UpdateResult.Recreate;
             }
             const props = { ...b.data.repr.props, ...newParams.type.params };

+ 11 - 8
src/mol-repr/structure/complex-representation.ts

@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2018-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  * @author David Sehnal <david.sehnal@gmail.com>
@@ -20,9 +20,11 @@ import { Overpaint } from '../../mol-theme/overpaint';
 import { StructureParams } from './params';
 import { Clipping } from '../../mol-theme/clipping';
 import { Transparency } from '../../mol-theme/transparency';
+import { WebGLContext } from '../../mol-gl/webgl/context';
 
-export function ComplexRepresentation<P extends StructureParams>(label: string, ctx: RepresentationContext, getParams: RepresentationParamsGetter<Structure, P>, visualCtor: (materialId: number) => ComplexVisual<P>): StructureRepresentation<P> {
+export function ComplexRepresentation<P extends StructureParams>(label: string, ctx: RepresentationContext, getParams: RepresentationParamsGetter<Structure, P>, visualCtor: (materialId: number, props?: PD.Values<P>, webgl?: WebGLContext) => ComplexVisual<P>): StructureRepresentation<P> {
     let version = 0;
+    const { webgl } = ctx;
     const updated = new Subject<number>();
     const materialId = getNextMaterialId();
     const renderObjects: GraphicsRenderObject[] = [];
@@ -45,15 +47,16 @@ export function ComplexRepresentation<P extends StructureParams>(label: string,
         return Task.create('Creating or updating ComplexRepresentation', async runtime => {
             let newVisual = false;
             if (!visual) {
-                visual = visualCtor(materialId);
+                visual = visualCtor(materialId, _props, webgl);
+                newVisual = true;
+            } else if (visual.mustRecreate?.(_props, webgl)) {
+                visual.destroy();
+                visual = visualCtor(materialId, _props, webgl);
                 newVisual = true;
             }
-            const promise = visual.createOrUpdate({ webgl: ctx.webgl, runtime }, _theme, _props, structure);
+            const promise = visual.createOrUpdate({ webgl, runtime }, _theme, _props, structure);
             if (promise) await promise;
-            if (newVisual) {
-                // ensure state is current for new visual
-                setState(_state);
-            }
+            if (newVisual) setState(_state); // current state for new visual
             // update list of renderObjects
             renderObjects.length = 0;
             if (visual && visual.renderObject) renderObjects.push(visual.renderObject);

+ 4 - 2
src/mol-repr/structure/complex-visual.ts

@@ -52,6 +52,7 @@ interface ComplexVisualBuilder<P extends StructureParams, G extends Geometry> {
     getLoci(pickingId: PickingId, structure: Structure, id: number): Loci
     eachLocation(loci: Loci, structure: Structure, apply: (interval: Interval) => boolean, isMarking: boolean): boolean,
     setUpdateState(state: VisualUpdateState, newProps: PD.Values<P>, currentProps: PD.Values<P>, newTheme: Theme, currentTheme: Theme, newStructure: Structure, currentStructure: Structure): void
+    mustRecreate?: (props: PD.Values<P>) => boolean
 }
 
 interface ComplexVisualGeometryBuilder<P extends StructureParams, G extends Geometry> extends ComplexVisualBuilder<P, G> {
@@ -59,7 +60,7 @@ interface ComplexVisualGeometryBuilder<P extends StructureParams, G extends Geom
 }
 
 export function ComplexVisual<G extends Geometry, P extends StructureParams & Geometry.Params<G>>(builder: ComplexVisualGeometryBuilder<P, G>, materialId: number): ComplexVisual<P> {
-    const { defaultProps, createGeometry, createLocationIterator, getLoci, eachLocation, setUpdateState } = builder;
+    const { defaultProps, createGeometry, createLocationIterator, getLoci, eachLocation, setUpdateState, mustRecreate } = builder;
     const { updateValues, updateBoundingSphere, updateRenderableState, createPositionIterator } = builder.geometryUtils;
     const updateState = VisualUpdateState.create();
 
@@ -241,7 +242,8 @@ export function ComplexVisual<G extends Geometry, P extends StructureParams & Ge
         destroy() {
             // TODO
             renderObject = undefined;
-        }
+        },
+        mustRecreate
     };
 }
 

+ 7 - 7
src/mol-repr/structure/representation/ball-and-stick.ts

@@ -1,12 +1,12 @@
 /**
- * Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2018-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
 
-import { getElementSphereVisual, ElementSphereParams } from '../visual/element-sphere';
-import { getIntraUnitBondCylinderVisual, IntraUnitBondCylinderParams } from '../visual/bond-intra-unit-cylinder';
-import { InterUnitBondCylinderParams, getInterUnitBondCylinderVisual } from '../visual/bond-inter-unit-cylinder';
+import { IntraUnitBondCylinderVisual, IntraUnitBondCylinderParams } from '../visual/bond-intra-unit-cylinder';
+import { InterUnitBondCylinderParams, InterUnitBondCylinderVisual } from '../visual/bond-inter-unit-cylinder';
+import { ElementSphereVisual, ElementSphereParams } from '../visual/element-sphere';
 import { ParamDefinition as PD } from '../../../mol-util/param-definition';
 import { UnitsRepresentation } from '../units-representation';
 import { ComplexRepresentation } from '../complex-representation';
@@ -17,9 +17,9 @@ import { Structure } from '../../../mol-model/structure';
 import { getUnitKindsParam } from '../params';
 
 const BallAndStickVisuals = {
-    'element-sphere': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<Structure, ElementSphereParams>) => UnitsRepresentation('Element sphere', ctx, getParams, getElementSphereVisual(ctx.webgl)),
-    'intra-bond': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<Structure, IntraUnitBondCylinderParams>) => UnitsRepresentation('Intra-unit bond cylinder', ctx, getParams, getIntraUnitBondCylinderVisual(ctx.webgl)),
-    'inter-bond': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<Structure, InterUnitBondCylinderParams>) => ComplexRepresentation('Inter-unit bond cylinder', ctx, getParams, getInterUnitBondCylinderVisual(ctx.webgl)),
+    'element-sphere': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<Structure, ElementSphereParams>) => UnitsRepresentation('Element sphere', ctx, getParams, ElementSphereVisual),
+    'intra-bond': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<Structure, IntraUnitBondCylinderParams>) => UnitsRepresentation('Intra-unit bond cylinder', ctx, getParams, IntraUnitBondCylinderVisual),
+    'inter-bond': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<Structure, InterUnitBondCylinderParams>) => ComplexRepresentation('Inter-unit bond cylinder', ctx, getParams, InterUnitBondCylinderVisual),
 };
 
 export const BallAndStickParams = {

+ 5 - 5
src/mol-repr/structure/representation/ellipsoid.ts

@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2019-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2019-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
@@ -11,14 +11,14 @@ import { Structure } from '../../../mol-model/structure';
 import { UnitsRepresentation, StructureRepresentation, StructureRepresentationStateBuilder, StructureRepresentationProvider, ComplexRepresentation } from '../../../mol-repr/structure/representation';
 import { EllipsoidMeshParams, EllipsoidMeshVisual } from '../visual/ellipsoid-mesh';
 import { AtomSiteAnisotrop } from '../../../mol-model-formats/structure/property/anisotropic';
-import { IntraUnitBondCylinderParams, getIntraUnitBondCylinderVisual } from '../visual/bond-intra-unit-cylinder';
-import { getInterUnitBondCylinderVisual, InterUnitBondCylinderParams } from '../visual/bond-inter-unit-cylinder';
+import { IntraUnitBondCylinderParams, IntraUnitBondCylinderVisual } from '../visual/bond-intra-unit-cylinder';
+import { InterUnitBondCylinderVisual, InterUnitBondCylinderParams } from '../visual/bond-inter-unit-cylinder';
 import { getUnitKindsParam } from '../params';
 
 const EllipsoidVisuals = {
     'ellipsoid-mesh': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<Structure, EllipsoidMeshParams>) => UnitsRepresentation('Ellipsoid Mesh', ctx, getParams, EllipsoidMeshVisual),
-    'intra-bond': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<Structure, IntraUnitBondCylinderParams>) => UnitsRepresentation('Intra-unit bond cylinder', ctx, getParams, getIntraUnitBondCylinderVisual(ctx.webgl)),
-    'inter-bond': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<Structure, InterUnitBondCylinderParams>) => ComplexRepresentation('Inter-unit bond cylinder', ctx, getParams, getInterUnitBondCylinderVisual(ctx.webgl)),
+    'intra-bond': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<Structure, IntraUnitBondCylinderParams>) => UnitsRepresentation('Intra-unit bond cylinder', ctx, getParams, IntraUnitBondCylinderVisual),
+    'inter-bond': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<Structure, InterUnitBondCylinderParams>) => ComplexRepresentation('Inter-unit bond cylinder', ctx, getParams, InterUnitBondCylinderVisual),
 };
 
 export const EllipsoidParams = {

+ 3 - 6
src/mol-repr/structure/representation/gaussian-surface.ts

@@ -4,7 +4,7 @@
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
 
-import { GaussianSurfaceMeshVisual, GaussianSurfaceTextureMeshVisual, GaussianSurfaceMeshParams, StructureGaussianSurfaceMeshParams, StructureGaussianSurfaceMeshVisual } from '../visual/gaussian-surface-mesh';
+import { GaussianSurfaceMeshParams, StructureGaussianSurfaceMeshParams, StructureGaussianSurfaceVisual, GaussianSurfaceVisual } from '../visual/gaussian-surface-mesh';
 import { UnitsRepresentation } from '../units-representation';
 import { GaussianWireframeVisual, GaussianWireframeParams } from '../visual/gaussian-surface-wireframe';
 import { ParamDefinition as PD } from '../../../mol-util/param-definition';
@@ -14,11 +14,8 @@ import { ThemeRegistryContext } from '../../../mol-theme/theme';
 import { Structure } from '../../../mol-model/structure';
 
 const GaussianSurfaceVisuals = {
-    'gaussian-surface-mesh': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<Structure, GaussianSurfaceMeshParams>) => UnitsRepresentation('Gaussian surface mesh', ctx, getParams, GaussianSurfaceMeshVisual),
-    'structure-gaussian-surface-mesh': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<Structure, StructureGaussianSurfaceMeshParams>) => ComplexRepresentation('Structure-Gaussian surface mesh', ctx, getParams, StructureGaussianSurfaceMeshVisual),
-    'gaussian-surface-texture-mesh': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<Structure, GaussianSurfaceMeshParams>) => UnitsRepresentation('Gaussian surface texture-mesh', ctx, getParams, GaussianSurfaceTextureMeshVisual),
-    // TODO: don't enable yet as it breaks state sessions
-    // 'structure-gaussian-surface-texture-mesh': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<Structure, StructureGaussianSurfaceMeshParams>) => ComplexRepresentation('Structure-Gaussian surface texture-mesh', ctx, getParams, StructureGaussianSurfaceTextureMeshVisual),
+    'gaussian-surface-mesh': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<Structure, GaussianSurfaceMeshParams>) => UnitsRepresentation('Gaussian surface mesh', ctx, getParams, GaussianSurfaceVisual),
+    'structure-gaussian-surface-mesh': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<Structure, StructureGaussianSurfaceMeshParams>) => ComplexRepresentation('Structure-Gaussian surface mesh', ctx, getParams, StructureGaussianSurfaceVisual),
     'gaussian-surface-wireframe': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<Structure, GaussianWireframeParams>) => UnitsRepresentation('Gaussian surface wireframe', ctx, getParams, GaussianWireframeVisual),
 };
 

+ 3 - 3
src/mol-repr/structure/representation/spacefill.ts

@@ -1,10 +1,10 @@
 /**
- * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2018-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
 
-import { getElementSphereVisual, ElementSphereParams } from '../visual/element-sphere';
+import { ElementSphereVisual, ElementSphereParams } from '../visual/element-sphere';
 import { UnitsRepresentation } from '../units-representation';
 import { ParamDefinition as PD } from '../../../mol-util/param-definition';
 import { StructureRepresentation, StructureRepresentationProvider, StructureRepresentationStateBuilder } from '../representation';
@@ -13,7 +13,7 @@ import { ThemeRegistryContext } from '../../../mol-theme/theme';
 import { Structure } from '../../../mol-model/structure';
 
 const SpacefillVisuals = {
-    'element-sphere': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<Structure, ElementSphereParams>) => UnitsRepresentation('Element sphere', ctx, getParams, getElementSphereVisual(ctx.webgl)),
+    'element-sphere': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<Structure, ElementSphereParams>) => UnitsRepresentation('Sphere mesh', ctx, getParams, ElementSphereVisual),
 };
 
 export const SpacefillParams = {

+ 47 - 31
src/mol-repr/structure/units-representation.ts

@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2018-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  * @author David Sehnal <david.sehnal@gmail.com>
@@ -24,11 +24,13 @@ import { Mat4, EPSILON } from '../../mol-math/linear-algebra';
 import { Interval } from '../../mol-data/int';
 import { StructureParams } from './params';
 import { Clipping } from '../../mol-theme/clipping';
+import { WebGLContext } from '../../mol-gl/webgl/context';
 
 export interface UnitsVisual<P extends StructureParams> extends Visual<StructureGroup, P> { }
 
-export function UnitsRepresentation<P extends StructureParams>(label: string, ctx: RepresentationContext, getParams: RepresentationParamsGetter<Structure, P>, visualCtor: (materialId: number) => UnitsVisual<P>): StructureRepresentation<P> {
+export function UnitsRepresentation<P extends StructureParams>(label: string, ctx: RepresentationContext, getParams: RepresentationParamsGetter<Structure, P>, visualCtor: (materialId: number, props?: PD.Values<P>, webgl?: WebGLContext) => UnitsVisual<P>): StructureRepresentation<P> {
     let version = 0;
+    const { webgl } = ctx;
     const updated = new Subject<number>();
     const materialId = getNextMaterialId();
     const renderObjects: GraphicsRenderObject[] = [];
@@ -57,11 +59,10 @@ export function UnitsRepresentation<P extends StructureParams>(label: string, ct
                 _groups = structure.unitSymmetryGroups;
                 for (let i = 0; i < _groups.length; i++) {
                     const group = _groups[i];
-                    const visual = visualCtor(materialId);
-                    const promise = visual.createOrUpdate({ webgl: ctx.webgl, runtime }, _theme, _props, { group, structure });
+                    const visual = visualCtor(materialId, _props, webgl);
+                    const promise = visual.createOrUpdate({ webgl, runtime }, _theme, _props, { group, structure });
                     if (promise) await promise;
-                    // ensure state is current for new visual
-                    setVisualState(visual, group, _state);
+                    setVisualState(visual, group, _state); // current state for new visual
                     visuals.set(group.hashCode, { visual, group });
                     if (runtime.shouldUpdate) await runtime.update({ message: 'Creating or updating UnitsVisual', current: i, max: _groups.length });
                 }
@@ -80,9 +81,17 @@ export function UnitsRepresentation<P extends StructureParams>(label: string, ct
                         // console.log(label, 'found visualGroup to reuse');
                         // console.log('old', visualGroup.group)
                         // console.log('new', group)
-                        const { visual } = visualGroup;
-                        const promise = visual.createOrUpdate({ webgl: ctx.webgl, runtime }, _theme, _props, { group, structure });
-                        if (promise) await promise;
+                        let { visual } = visualGroup;
+                        if (visual.mustRecreate?.(_props, webgl)) {
+                            visual.destroy();
+                            visual = visualCtor(materialId, _props, webgl);
+                            const promise = visual.createOrUpdate({ webgl, runtime }, _theme, _props, { group, structure });
+                            if (promise) await promise;
+                            setVisualState(visual, group, _state); // current state for new visual
+                        } else {
+                            const promise = visual.createOrUpdate({ webgl, runtime }, _theme, _props, { group, structure });
+                            if (promise) await promise;
+                        }
                         visuals.set(group.hashCode, { visual, group });
                         oldVisuals.delete(group.hashCode);
 
@@ -95,11 +104,10 @@ export function UnitsRepresentation<P extends StructureParams>(label: string, ct
                     } else {
                         // console.log(label, 'did not find visualGroup to reuse, creating new');
                         // newGroups.push(group)
-                        const visual = visualCtor(materialId);
-                        const promise = visual.createOrUpdate({ webgl: ctx.webgl, runtime }, _theme, _props, { group, structure });
+                        const visual = visualCtor(materialId, _props, webgl);
+                        const promise = visual.createOrUpdate({ webgl, runtime }, _theme, _props, { group, structure });
                         if (promise) await promise;
-                        // ensure state is current for new visual
-                        setVisualState(visual, group, _state);
+                        setVisualState(visual, group, _state); // current state for new visual
                         visuals.set(group.hashCode, { visual, group });
                     }
                     if (runtime.shouldUpdate) await runtime.update({ message: 'Creating or updating UnitsVisual', current: i, max: _groups.length });
@@ -108,17 +116,6 @@ export function UnitsRepresentation<P extends StructureParams>(label: string, ct
                     // console.log(label, 'removed unused visual');
                     visual.destroy();
                 });
-
-                // TODO review logic
-                // For new groups, re-use left-over visuals
-                // const unusedVisuals: UnitsVisual<P>[] = []
-                // oldVisuals.forEach(({ visual }) => unusedVisuals.push(visual))
-                // newGroups.forEach(async group => {
-                //     const visual = unusedVisuals.pop() || visualCtor()
-                //     await visual.createOrUpdate({ ...ctx, runtime }, _props, group)
-                //     visuals.set(group.hashCode, { visual, group })
-                // })
-                // unusedVisuals.forEach(visual => visual.destroy())
             } else if (structure && structure !== _structure && Structure.areUnitIdsAndIndicesEqual(structure, _structure)) {
                 // console.log(label, 'structures equivalent but not identical');
                 // Expects that for structures with the same hashCode,
@@ -131,8 +128,18 @@ export function UnitsRepresentation<P extends StructureParams>(label: string, ct
                     const group = _groups[i];
                     const visualGroup = visuals.get(group.hashCode);
                     if (visualGroup) {
-                        const promise = visualGroup.visual.createOrUpdate({ webgl: ctx.webgl, runtime }, _theme, _props, { group, structure });
-                        if (promise) await promise;
+                        let { visual } = visualGroup;
+                        if (visual.mustRecreate?.(_props, ctx.webgl)) {
+                            visual.destroy();
+                            visual = visualCtor(materialId, _props, ctx.webgl);
+                            visualGroup.visual = visual;
+                            const promise = visual.createOrUpdate({ webgl, runtime }, _theme, _props, { group, structure });
+                            if (promise) await promise;
+                            setVisualState(visual, group, _state); // current state for new visual
+                        } else {
+                            const promise = visual.createOrUpdate({ webgl, runtime }, _theme, _props, { group, structure });
+                            if (promise) await promise;
+                        }
                         visualGroup.group = group;
                     } else {
                         throw new Error(`expected to find visual for hashCode ${group.hashCode}`);
@@ -142,12 +149,21 @@ export function UnitsRepresentation<P extends StructureParams>(label: string, ct
             } else {
                 // console.log(label, 'no new structure');
                 // No new structure given, just update all visuals with new props.
-                const visualsList: [ UnitsVisual<P>, Unit.SymmetryGroup ][] = []; // TODO avoid allocation
-                visuals.forEach(({ visual, group }) => visualsList.push([ visual, group ]));
+                const visualsList: { group: Unit.SymmetryGroup, visual: UnitsVisual<P> }[] = []; // TODO avoid allocation
+                visuals.forEach(vg => visualsList.push(vg));
                 for (let i = 0, il = visualsList.length; i < il; ++i) {
-                    const [ visual ] = visualsList[i];
-                    const promise = visual.createOrUpdate({ webgl: ctx.webgl, runtime }, _theme, _props);
-                    if (promise) await promise;
+                    let { visual, group } = visualsList[i];
+                    if (visual.mustRecreate?.(_props, ctx.webgl)) {
+                        visual.destroy();
+                        visual = visualCtor(materialId, _props, webgl);
+                        visualsList[i].visual = visual;
+                        const promise = visual.createOrUpdate({ webgl, runtime }, _theme, _props, { group, structure: _structure });
+                        if (promise) await promise;
+                        setVisualState(visual, group, _state); // current state for new visual
+                    } else {
+                        const promise = visual.createOrUpdate({ webgl, runtime }, _theme, _props);
+                        if (promise) await promise;
+                    }
                     if (runtime.shouldUpdate) await runtime.update({ message: 'Creating or updating UnitsVisual', current: i, max: il });
                 }
             }

+ 4 - 2
src/mol-repr/structure/units-visual.ts

@@ -58,6 +58,7 @@ interface UnitsVisualBuilder<P extends StructureParams, G extends Geometry> {
     getLoci(pickingId: PickingId, structureGroup: StructureGroup, id: number): Loci
     eachLocation(loci: Loci, structureGroup: StructureGroup, apply: (interval: Interval) => boolean, isMarking: boolean): boolean
     setUpdateState(state: VisualUpdateState, newProps: PD.Values<P>, currentProps: PD.Values<P>, newTheme: Theme, currentTheme: Theme, newStructureGroup: StructureGroup, currentStructureGroup: StructureGroup): void
+    mustRecreate?: (props: PD.Values<P>) => boolean
 }
 
 interface UnitsVisualGeometryBuilder<P extends StructureParams, G extends Geometry> extends UnitsVisualBuilder<P, G> {
@@ -65,7 +66,7 @@ interface UnitsVisualGeometryBuilder<P extends StructureParams, G extends Geomet
 }
 
 export function UnitsVisual<G extends Geometry, P extends StructureParams & Geometry.Params<G>>(builder: UnitsVisualGeometryBuilder<P, G>, materialId: number): UnitsVisual<P> {
-    const { defaultProps, createGeometry, createLocationIterator, getLoci, eachLocation, setUpdateState } = builder;
+    const { defaultProps, createGeometry, createLocationIterator, getLoci, eachLocation, setUpdateState, mustRecreate } = builder;
     const { createEmpty: createEmptyGeometry, updateValues, updateBoundingSphere, updateRenderableState, createPositionIterator } = builder.geometryUtils;
     const updateState = VisualUpdateState.create();
 
@@ -293,7 +294,8 @@ export function UnitsVisual<G extends Geometry, P extends StructureParams & Geom
         destroy() {
             // TODO
             renderObject = undefined;
-        }
+        },
+        mustRecreate
     };
 }
 

+ 11 - 2
src/mol-repr/structure/visual/bond-inter-unit-cylinder.ts

@@ -157,11 +157,14 @@ export const InterUnitBondCylinderParams = {
     ...BondCylinderParams,
     sizeFactor: PD.Numeric(0.3, { min: 0, max: 10, step: 0.01 }),
     sizeAspectRatio: PD.Numeric(2 / 3, { min: 0, max: 3, step: 0.01 }),
+    useImpostor: PD.Boolean(true),
 };
 export type InterUnitBondCylinderParams = typeof InterUnitBondCylinderParams
 
-export function getInterUnitBondCylinderVisual(webgl?: WebGLContext) {
-    return webgl && webgl.extensions.fragDepth ? InterUnitBondCylinderImpostorVisual : InterUnitBondCylinderMeshVisual;
+export function InterUnitBondCylinderVisual(materialId: number, props?: PD.Values<InterUnitBondCylinderParams>, webgl?: WebGLContext) {
+    return props?.useImpostor && webgl && webgl.extensions.fragDepth
+        ? InterUnitBondCylinderImpostorVisual(materialId)
+        : InterUnitBondCylinderMeshVisual(materialId);
 }
 
 export function InterUnitBondCylinderImpostorVisual(materialId: number): ComplexVisual<InterUnitBondCylinderParams> {
@@ -183,6 +186,9 @@ export function InterUnitBondCylinderImpostorVisual(materialId: number): Complex
                 !arrayEqual(newProps.includeTypes, currentProps.includeTypes) ||
                 !arrayEqual(newProps.excludeTypes, currentProps.excludeTypes)
             );
+        },
+        mustRecreate: (props: PD.Values<InterUnitBondCylinderParams>, webgl?: WebGLContext) => {
+            return !props.useImpostor || !webgl;
         }
     }, materialId);
 }
@@ -209,6 +215,9 @@ export function InterUnitBondCylinderMeshVisual(materialId: number): ComplexVisu
                 !arrayEqual(newProps.includeTypes, currentProps.includeTypes) ||
                 !arrayEqual(newProps.excludeTypes, currentProps.excludeTypes)
             );
+        },
+        mustRecreate: (props: PD.Values<InterUnitBondCylinderParams>, webgl?: WebGLContext) => {
+            return props.useImpostor && !!webgl;
         }
     }, materialId);
 }

+ 11 - 2
src/mol-repr/structure/visual/bond-intra-unit-cylinder.ts

@@ -141,11 +141,14 @@ export const IntraUnitBondCylinderParams = {
     ...BondCylinderParams,
     sizeFactor: PD.Numeric(0.3, { min: 0, max: 10, step: 0.01 }),
     sizeAspectRatio: PD.Numeric(2 / 3, { min: 0, max: 3, step: 0.01 }),
+    useImpostor: PD.Boolean(true),
 };
 export type IntraUnitBondCylinderParams = typeof IntraUnitBondCylinderParams
 
-export function getIntraUnitBondCylinderVisual(webgl?: WebGLContext) {
-    return webgl && webgl.extensions.fragDepth ? IntraUnitBondCylinderImpostorVisual : IntraUnitBondCylinderMeshVisual;
+export function IntraUnitBondCylinderVisual(materialId: number, props?: PD.Values<IntraUnitBondCylinderParams>, webgl?: WebGLContext) {
+    return props?.useImpostor && webgl && webgl.extensions.fragDepth
+        ? IntraUnitBondCylinderImpostorVisual(materialId)
+        : IntraUnitBondCylinderMeshVisual(materialId);
 }
 
 export function IntraUnitBondCylinderImpostorVisual(materialId: number): UnitsVisual<IntraUnitBondCylinderParams> {
@@ -178,6 +181,9 @@ export function IntraUnitBondCylinderImpostorVisual(materialId: number): UnitsVi
                     state.updateSize = true;
                 }
             }
+        },
+        mustRecreate: (props: PD.Values<IntraUnitBondCylinderParams>, webgl?: WebGLContext) => {
+            return !props.useImpostor || !webgl;
         }
     }, materialId);
 }
@@ -215,6 +221,9 @@ export function IntraUnitBondCylinderMeshVisual(materialId: number): UnitsVisual
                     state.updateSize = true;
                 }
             }
+        },
+        mustRecreate: (props: PD.Values<IntraUnitBondCylinderParams>, webgl?: WebGLContext) => {
+            return props.useImpostor && !!webgl;
         }
     }, materialId);
 }

+ 12 - 3
src/mol-repr/structure/visual/element-sphere.ts

@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2018-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  * @author David Sehnal <david.sehnal@gmail.com>
@@ -19,11 +19,14 @@ export const ElementSphereParams = {
     detail: PD.Numeric(0, { min: 0, max: 3, step: 1 }, BaseGeometry.CustomQualityParamInfo),
     ignoreHydrogens: PD.Boolean(false),
     traceOnly: PD.Boolean(false),
+    useImpostor: PD.Boolean(true),
 };
 export type ElementSphereParams = typeof ElementSphereParams
 
-export function getElementSphereVisual(webgl?: WebGLContext) {
-    return webgl && webgl.extensions.fragDepth ? ElementSphereImpostorVisual : ElementSphereMeshVisual;
+export function ElementSphereVisual(materialId: number, props?: PD.Values<ElementSphereParams>, webgl?: WebGLContext) {
+    return props?.useImpostor && webgl && webgl.extensions.fragDepth
+        ? ElementSphereImpostorVisual(materialId)
+        : ElementSphereMeshVisual(materialId);
 }
 
 export function ElementSphereImpostorVisual(materialId: number): UnitsVisual<ElementSphereParams> {
@@ -38,6 +41,9 @@ export function ElementSphereImpostorVisual(materialId: number): UnitsVisual<Ele
                 newProps.ignoreHydrogens !== currentProps.ignoreHydrogens ||
                 newProps.traceOnly !== currentProps.traceOnly
             );
+        },
+        mustRecreate: (props: PD.Values<ElementSphereParams>, webgl?: WebGLContext) => {
+            return !props.useImpostor || !webgl;
         }
     }, materialId);
 }
@@ -56,6 +62,9 @@ export function ElementSphereMeshVisual(materialId: number): UnitsVisual<Element
                 newProps.ignoreHydrogens !== currentProps.ignoreHydrogens ||
                 newProps.traceOnly !== currentProps.traceOnly
             );
+        },
+        mustRecreate: (props: PD.Values<ElementSphereParams>, webgl?: WebGLContext) => {
+            return props.useImpostor && !!webgl;
         }
     }, materialId);
 }

+ 6 - 6
src/mol-repr/structure/visual/gaussian-density-volume.ts

@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2018-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
@@ -8,7 +8,7 @@ import { ParamDefinition as PD } from '../../../mol-util/param-definition';
 import { VisualContext } from '../../visual';
 import { Structure, Unit } from '../../../mol-model/structure';
 import { Theme } from '../../../mol-theme/theme';
-import { GaussianDensityTextureProps, computeStructureGaussianDensityTexture, computeUnitGaussianDensityTexture, GaussianDensityTextureParams } from './util/gaussian';
+import { GaussianDensityProps, computeStructureGaussianDensityTexture, computeUnitGaussianDensityTexture, GaussianDensityParams } from './util/gaussian';
 import { DirectVolume } from '../../../mol-geo/geometry/direct-volume/direct-volume';
 import { ComplexDirectVolumeParams, ComplexVisual, ComplexDirectVolumeVisual } from '../complex-visual';
 import { VisualUpdateState } from '../../util';
@@ -18,7 +18,7 @@ import { Sphere3D } from '../../../mol-math/geometry';
 import { UnitsDirectVolumeParams, UnitsVisual, UnitsDirectVolumeVisual } from '../units-visual';
 import { getStructureExtraRadius, getUnitExtraRadius } from './util/common';
 
-async function createGaussianDensityVolume(ctx: VisualContext, structure: Structure, theme: Theme, props: GaussianDensityTextureProps, directVolume?: DirectVolume): Promise<DirectVolume> {
+async function createGaussianDensityVolume(ctx: VisualContext, structure: Structure, theme: Theme, props: GaussianDensityProps, directVolume?: DirectVolume): Promise<DirectVolume> {
     const { runtime, webgl } = ctx;
     if (webgl === undefined) throw new Error('createGaussianDensityVolume requires `webgl` object in VisualContext');
 
@@ -41,7 +41,7 @@ async function createGaussianDensityVolume(ctx: VisualContext, structure: Struct
 
 export const GaussianDensityVolumeParams = {
     ...ComplexDirectVolumeParams,
-    ...GaussianDensityTextureParams,
+    ...GaussianDensityParams,
     ignoreHydrogens: PD.Boolean(false),
 };
 export type GaussianDensityVolumeParams = typeof GaussianDensityVolumeParams
@@ -66,7 +66,7 @@ export function GaussianDensityVolumeVisual(materialId: number): ComplexVisual<G
 
 //
 
-async function createUnitsGaussianDensityVolume(ctx: VisualContext, unit: Unit, structure: Structure, theme: Theme, props: GaussianDensityTextureProps, directVolume?: DirectVolume): Promise<DirectVolume> {
+async function createUnitsGaussianDensityVolume(ctx: VisualContext, unit: Unit, structure: Structure, theme: Theme, props: GaussianDensityProps, directVolume?: DirectVolume): Promise<DirectVolume> {
     const { runtime, webgl } = ctx;
     if (webgl === undefined) throw new Error('createUnitGaussianDensityVolume requires `webgl` object in VisualContext');
 
@@ -89,7 +89,7 @@ async function createUnitsGaussianDensityVolume(ctx: VisualContext, unit: Unit,
 
 export const UnitsGaussianDensityVolumeParams = {
     ...UnitsDirectVolumeParams,
-    ...GaussianDensityTextureParams,
+    ...GaussianDensityParams,
     ignoreHydrogens: PD.Boolean(false),
 };
 export type UnitsGaussianDensityVolumeParams = typeof UnitsGaussianDensityVolumeParams

+ 47 - 14
src/mol-repr/structure/visual/gaussian-surface-mesh.ts

@@ -6,7 +6,7 @@
 
 import { ParamDefinition as PD } from '../../../mol-util/param-definition';
 import { UnitsMeshParams, UnitsTextureMeshParams, UnitsVisual, UnitsMeshVisual, UnitsTextureMeshVisual } from '../units-visual';
-import { GaussianDensityParams, computeUnitGaussianDensity, GaussianDensityTextureProps, computeUnitGaussianDensityTexture2d, GaussianDensityProps, computeStructureGaussianDensity, computeStructureGaussianDensityTexture2d } from './util/gaussian';
+import { GaussianDensityParams, computeUnitGaussianDensity, computeUnitGaussianDensityTexture2d, GaussianDensityProps, computeStructureGaussianDensity, computeStructureGaussianDensityTexture2d } from './util/gaussian';
 import { VisualContext } from '../../visual';
 import { Unit, Structure } from '../../../mol-model/structure';
 import { Theme } from '../../../mol-theme/theme';
@@ -19,16 +19,46 @@ import { calcActiveVoxels } from '../../../mol-gl/compute/marching-cubes/active-
 import { createHistogramPyramid } from '../../../mol-gl/compute/histogram-pyramid/reduction';
 import { createIsosurfaceBuffers } from '../../../mol-gl/compute/marching-cubes/isosurface';
 import { Sphere3D } from '../../../mol-math/geometry';
-import { ComplexVisual, ComplexMeshParams, ComplexMeshVisual, ComplexTextureMeshVisual } from '../complex-visual';
+import { ComplexVisual, ComplexMeshParams, ComplexMeshVisual, ComplexTextureMeshVisual, ComplexTextureMeshParams } from '../complex-visual';
 import { getUnitExtraRadius, getStructureExtraRadius } from './util/common';
+import { WebGLContext } from '../../../mol-gl/webgl/context';
+
+const SharedParams = {
+    ...GaussianDensityParams,
+    ignoreHydrogens: PD.Boolean(false),
+    useGpu: PD.Boolean(false),
+};
 
 export const GaussianSurfaceMeshParams = {
     ...UnitsMeshParams,
     ...UnitsTextureMeshParams,
-    ...GaussianDensityParams,
+    ...SharedParams,
 };
 export type GaussianSurfaceMeshParams = typeof GaussianSurfaceMeshParams
 
+export const StructureGaussianSurfaceMeshParams = {
+    ...ComplexMeshParams,
+    ...ComplexTextureMeshParams,
+    ...SharedParams,
+};
+export type StructureGaussianSurfaceMeshParams = typeof StructureGaussianSurfaceMeshParams
+
+function gpuSupport(webgl: WebGLContext) {
+    return webgl.extensions.colorBufferFloat && webgl.extensions.textureFloat && webgl.extensions.blendMinMax && webgl.extensions.drawBuffers;
+}
+
+export function GaussianSurfaceVisual(materialId: number, props?: PD.Values<GaussianSurfaceMeshParams>, webgl?: WebGLContext) {
+    return props?.useGpu && webgl && gpuSupport(webgl)
+        ? GaussianSurfaceTextureMeshVisual(materialId)
+        : GaussianSurfaceMeshVisual(materialId);
+}
+
+export function StructureGaussianSurfaceVisual(materialId: number, props?: PD.Values<StructureGaussianSurfaceMeshParams>, webgl?: WebGLContext) {
+    return props?.useGpu && webgl && gpuSupport(webgl)
+        ? StructureGaussianSurfaceTextureMeshVisual(materialId)
+        : StructureGaussianSurfaceMeshVisual(materialId);
+}
+
 //
 
 async function createGaussianSurfaceMesh(ctx: VisualContext, unit: Unit, structure: Structure, theme: Theme, props: GaussianDensityProps, mesh?: Mesh): Promise<Mesh> {
@@ -62,23 +92,18 @@ export function GaussianSurfaceMeshVisual(materialId: number): UnitsVisual<Gauss
             if (newProps.resolution !== currentProps.resolution) state.createGeometry = true;
             if (newProps.radiusOffset !== currentProps.radiusOffset) state.createGeometry = true;
             if (newProps.smoothness !== currentProps.smoothness) state.createGeometry = true;
-            if (newProps.useGpu !== currentProps.useGpu) state.createGeometry = true;
             if (newProps.ignoreHydrogens !== currentProps.ignoreHydrogens) state.createGeometry = true;
             if (newProps.traceOnly !== currentProps.traceOnly) state.createGeometry = true;
             if (newProps.includeParent !== currentProps.includeParent) state.createGeometry = true;
+        },
+        mustRecreate: (props: PD.Values<GaussianSurfaceMeshParams>, webgl?: WebGLContext) => {
+            return props.useGpu && !!webgl;
         }
     }, materialId);
 }
 
 //
 
-export const StructureGaussianSurfaceMeshParams = {
-    ...ComplexMeshParams,
-    ...GaussianDensityParams,
-    ignoreHydrogens: PD.Boolean(false),
-};
-export type StructureGaussianSurfaceMeshParams = typeof StructureGaussianSurfaceMeshParams
-
 async function createStructureGaussianSurfaceMesh(ctx: VisualContext, structure: Structure, theme: Theme, props: GaussianDensityProps, mesh?: Mesh): Promise<Mesh> {
     const { smoothness } = props;
     const { transform, field, idField, radiusFactor } = await computeStructureGaussianDensity(structure, props, ctx.webgl).runInContext(ctx.runtime);
@@ -110,9 +135,11 @@ export function StructureGaussianSurfaceMeshVisual(materialId: number): ComplexV
             if (newProps.resolution !== currentProps.resolution) state.createGeometry = true;
             if (newProps.radiusOffset !== currentProps.radiusOffset) state.createGeometry = true;
             if (newProps.smoothness !== currentProps.smoothness) state.createGeometry = true;
-            if (newProps.useGpu !== currentProps.useGpu) state.createGeometry = true;
             if (newProps.ignoreHydrogens !== currentProps.ignoreHydrogens) state.createGeometry = true;
             if (newProps.traceOnly !== currentProps.traceOnly) state.createGeometry = true;
+        },
+        mustRecreate: (props: PD.Values<StructureGaussianSurfaceMeshParams>, webgl?: WebGLContext) => {
+            return props.useGpu && !!webgl;
         }
     }, materialId);
 }
@@ -121,7 +148,7 @@ export function StructureGaussianSurfaceMeshVisual(materialId: number): ComplexV
 
 const GaussianSurfaceName = 'gaussian-surface';
 
-async function createGaussianSurfaceTextureMesh(ctx: VisualContext, unit: Unit, structure: Structure, theme: Theme, props: GaussianDensityTextureProps, textureMesh?: TextureMesh): Promise<TextureMesh> {
+async function createGaussianSurfaceTextureMesh(ctx: VisualContext, unit: Unit, structure: Structure, theme: Theme, props: GaussianDensityProps, textureMesh?: TextureMesh): Promise<TextureMesh> {
     if (!ctx.webgl) throw new Error('webgl context required to create gaussian surface texture-mesh');
 
     const { namedTextures, resources, extensions: { colorBufferFloat, textureFloat, colorBufferHalfFloat, textureHalfFloat } } = ctx.webgl;
@@ -182,13 +209,16 @@ export function GaussianSurfaceTextureMeshVisual(materialId: number): UnitsVisua
             if (newProps.ignoreHydrogens !== currentProps.ignoreHydrogens) state.createGeometry = true;
             if (newProps.traceOnly !== currentProps.traceOnly) state.createGeometry = true;
             if (newProps.includeParent !== currentProps.includeParent) state.createGeometry = true;
+        },
+        mustRecreate: (props: PD.Values<GaussianSurfaceMeshParams>, webgl?: WebGLContext) => {
+            return !props.useGpu || !webgl;
         }
     }, materialId);
 }
 
 //
 
-async function createStructureGaussianSurfaceTextureMesh(ctx: VisualContext, structure: Structure, theme: Theme, props: GaussianDensityTextureProps, textureMesh?: TextureMesh): Promise<TextureMesh> {
+async function createStructureGaussianSurfaceTextureMesh(ctx: VisualContext, structure: Structure, theme: Theme, props: GaussianDensityProps, textureMesh?: TextureMesh): Promise<TextureMesh> {
     if (!ctx.webgl) throw new Error('webgl context required to create structure gaussian surface texture-mesh');
 
     const { namedTextures, resources, extensions: { colorBufferFloat, textureFloat, colorBufferHalfFloat, textureHalfFloat } } = ctx.webgl;
@@ -248,6 +278,9 @@ export function StructureGaussianSurfaceTextureMeshVisual(materialId: number): C
             if (newProps.smoothness !== currentProps.smoothness) state.createGeometry = true;
             if (newProps.ignoreHydrogens !== currentProps.ignoreHydrogens) state.createGeometry = true;
             if (newProps.traceOnly !== currentProps.traceOnly) state.createGeometry = true;
+        },
+        mustRecreate: (props: PD.Values<StructureGaussianSurfaceMeshParams>, webgl?: WebGLContext) => {
+            return !props.useGpu || !webgl;
         }
     }, materialId);
 }

+ 2 - 3
src/mol-repr/structure/visual/gaussian-surface-wireframe.ts

@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2018-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
@@ -39,7 +39,7 @@ async function createGaussianWireframe(ctx: VisualContext, unit: Unit, structure
 export const GaussianWireframeParams = {
     ...UnitsLinesParams,
     ...GaussianDensityParams,
-    sizeFactor: PD.Numeric(1.5, { min: 0, max: 10, step: 0.1 }),
+    sizeFactor: PD.Numeric(3, { min: 0, max: 10, step: 0.1 }),
     lineSizeAttenuation: PD.Boolean(false),
     ignoreHydrogens: PD.Boolean(false),
 };
@@ -56,7 +56,6 @@ export function GaussianWireframeVisual(materialId: number): UnitsVisual<Gaussia
             if (newProps.resolution !== currentProps.resolution) state.createGeometry = true;
             if (newProps.radiusOffset !== currentProps.radiusOffset) state.createGeometry = true;
             if (newProps.smoothness !== currentProps.smoothness) state.createGeometry = true;
-            if (newProps.useGpu !== currentProps.useGpu) state.createGeometry = true;
             if (newProps.ignoreHydrogens !== currentProps.ignoreHydrogens) state.createGeometry = true;
             if (newProps.traceOnly !== currentProps.traceOnly) state.createGeometry = true;
             if (newProps.includeParent !== currentProps.includeParent) state.createGeometry = true;

+ 9 - 20
src/mol-repr/structure/visual/util/gaussian.ts

@@ -1,11 +1,10 @@
 /**
- * Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2018-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
 
 import { Unit, Structure } from '../../../../mol-model/structure';
-import { GaussianDensity } from '../../../../mol-math/geometry/gaussian-density';
 import { Task } from '../../../../mol-task';
 import { ParamDefinition as PD } from '../../../../mol-util/param-definition';
 import { GaussianDensityTexture, GaussianDensityTexture2d } from '../../../../mol-math/geometry/gaussian-density/gpu';
@@ -13,27 +12,17 @@ import { Texture } from '../../../../mol-gl/webgl/texture';
 import { WebGLContext } from '../../../../mol-gl/webgl/context';
 import { getUnitConformationAndRadius, getStructureConformationAndRadius, CommonSurfaceParams, ensureReasonableResolution } from './common';
 import { BaseGeometry } from '../../../../mol-geo/geometry/base';
+import { GaussianDensityCPU } from '../../../../mol-math/geometry/gaussian-density/cpu';
 
-const SharedGaussianDensityParams = {
+export const GaussianDensityParams = {
     resolution: PD.Numeric(1, { min: 0.1, max: 20, step: 0.1 }, { description: 'Grid resolution/cell spacing.', ...BaseGeometry.CustomQualityParamInfo }),
     radiusOffset: PD.Numeric(0, { min: 0, max: 10, step: 0.1 }, { description: 'Extra/offset radius added to the atoms/coarse elements for gaussian calculation. Useful to create coarse, low resolution surfaces.' }),
     smoothness: PD.Numeric(1.5, { min: 0.5, max: 2.5, step: 0.1 }, { description: 'Smoothness of the gausian surface, lower is smoother.' }),
     ...CommonSurfaceParams
 };
-
-export const GaussianDensityParams = {
-    ...SharedGaussianDensityParams,
-    useGpu: PD.Boolean(false),
-};
 export const DefaultGaussianDensityProps = PD.getDefaultValues(GaussianDensityParams);
 export type GaussianDensityProps = typeof DefaultGaussianDensityProps
 
-export const GaussianDensityTextureParams = {
-    ...SharedGaussianDensityParams
-};
-export const DefaultGaussianDensityTextureProps = PD.getDefaultValues(GaussianDensityTextureParams);
-export type GaussianDensityTextureProps = typeof DefaultGaussianDensityTextureProps
-
 //
 
 export function computeUnitGaussianDensity(structure: Structure, unit: Unit, props: GaussianDensityProps, webgl?: WebGLContext) {
@@ -41,11 +30,11 @@ export function computeUnitGaussianDensity(structure: Structure, unit: Unit, pro
     const p = ensureReasonableResolution(box, props);
     const { position, radius } = getUnitConformationAndRadius(structure, unit, p);
     return Task.create('Gaussian Density', async ctx => {
-        return await GaussianDensity(ctx, position, box, radius, p, webgl);
+        return await GaussianDensityCPU(ctx, position, box, radius, p);
     });
 }
 
-export function computeUnitGaussianDensityTexture(structure: Structure, unit: Unit, props: GaussianDensityTextureProps, webgl: WebGLContext, texture?: Texture) {
+export function computeUnitGaussianDensityTexture(structure: Structure, unit: Unit, props: GaussianDensityProps, webgl: WebGLContext, texture?: Texture) {
     const { box } = unit.lookup3d.boundary;
     const p = ensureReasonableResolution(box, props);
     const { position, radius } = getUnitConformationAndRadius(structure, unit, p);
@@ -54,7 +43,7 @@ export function computeUnitGaussianDensityTexture(structure: Structure, unit: Un
     });
 }
 
-export function computeUnitGaussianDensityTexture2d(structure: Structure, unit: Unit, powerOfTwo: boolean, props: GaussianDensityTextureProps, webgl: WebGLContext, texture?: Texture) {
+export function computeUnitGaussianDensityTexture2d(structure: Structure, unit: Unit, powerOfTwo: boolean, props: GaussianDensityProps, webgl: WebGLContext, texture?: Texture) {
     const { box } = unit.lookup3d.boundary;
     const p = ensureReasonableResolution(box, props);
     const { position, radius } = getUnitConformationAndRadius(structure, unit, p);
@@ -70,11 +59,11 @@ export function computeStructureGaussianDensity(structure: Structure, props: Gau
     const p = ensureReasonableResolution(box, props);
     const { position, radius } = getStructureConformationAndRadius(structure, props.ignoreHydrogens, props.traceOnly);
     return Task.create('Gaussian Density', async ctx => {
-        return await GaussianDensity(ctx, position, box, radius, p, webgl);
+        return await GaussianDensityCPU(ctx, position, box, radius, p);
     });
 }
 
-export function computeStructureGaussianDensityTexture(structure: Structure, props: GaussianDensityTextureProps, webgl: WebGLContext, texture?: Texture) {
+export function computeStructureGaussianDensityTexture(structure: Structure, props: GaussianDensityProps, webgl: WebGLContext, texture?: Texture) {
     const { box } = structure.lookup3d.boundary;
     const p = ensureReasonableResolution(box, props);
     const { position, radius } = getStructureConformationAndRadius(structure, props.ignoreHydrogens, props.traceOnly);
@@ -83,7 +72,7 @@ export function computeStructureGaussianDensityTexture(structure: Structure, pro
     });
 }
 
-export function computeStructureGaussianDensityTexture2d(structure: Structure, powerOfTwo: boolean, props: GaussianDensityTextureProps, webgl: WebGLContext, texture?: Texture) {
+export function computeStructureGaussianDensityTexture2d(structure: Structure, powerOfTwo: boolean, props: GaussianDensityProps, webgl: WebGLContext, texture?: Texture) {
     const { box } = structure.lookup3d.boundary;
     const p = ensureReasonableResolution(box, props);
     const { position, radius } = getStructureConformationAndRadius(structure, props.ignoreHydrogens, props.traceOnly);

+ 1 - 0
src/mol-repr/visual.ts

@@ -47,6 +47,7 @@ interface Visual<D, P extends PD.Params> {
     setTransparency: (transparency: Transparency) => void
     setClipping: (clipping: Clipping) => void
     destroy: () => void
+    mustRecreate?: (props: PD.Values<P>, webgl?: WebGLContext) => boolean
 }
 namespace Visual {
     export type LociApply = (loci: Loci, apply: (interval: Interval) => boolean, isMarking: boolean) => boolean

+ 25 - 8
src/mol-repr/volume/isosurface.ts

@@ -27,6 +27,7 @@ import { TextureMesh } from '../../mol-geo/geometry/texture-mesh/texture-mesh';
 import { calcActiveVoxels } from '../../mol-gl/compute/marching-cubes/active-voxels';
 import { createHistogramPyramid } from '../../mol-gl/compute/histogram-pyramid/reduction';
 import { createIsosurfaceBuffers } from '../../mol-gl/compute/marching-cubes/isosurface';
+import { WebGLContext } from '../../mol-gl/webgl/context';
 
 export const VolumeIsosurfaceParams = {
     isoValue: Volume.IsoValueParam
@@ -34,6 +35,16 @@ export const VolumeIsosurfaceParams = {
 export type VolumeIsosurfaceParams = typeof VolumeIsosurfaceParams
 export type VolumeIsosurfaceProps = PD.Values<VolumeIsosurfaceParams>
 
+function gpuSupport(webgl: WebGLContext) {
+    return webgl.extensions.colorBufferFloat && webgl.extensions.textureFloat && webgl.extensions.drawBuffers;
+}
+
+export function IsosurfaceVisual(materialId: number, props?: PD.Values<IsosurfaceMeshParams>, webgl?: WebGLContext) {
+    return props?.useGpu && webgl && gpuSupport(webgl)
+        ? IsosurfaceTextureMeshVisual(materialId)
+        : IsosurfaceMeshVisual(materialId);
+}
+
 function getLoci(volume: Volume, props: VolumeIsosurfaceProps) {
     return Volume.Isosurface.Loci(volume, props.isoValue);
 }
@@ -74,8 +85,10 @@ export async function createVolumeIsosurfaceMesh(ctx: VisualContext, volume: Vol
 
 export const IsosurfaceMeshParams = {
     ...Mesh.Params,
+    ...TextureMesh.Params,
+    ...VolumeIsosurfaceParams,
     quality: { ...Mesh.Params.quality, isEssential: false },
-    ...VolumeIsosurfaceParams
+    useGpu: PD.Boolean(false),
 };
 export type IsosurfaceMeshParams = typeof IsosurfaceMeshParams
 
@@ -89,7 +102,10 @@ export function IsosurfaceMeshVisual(materialId: number): VolumeVisual<Isosurfac
         setUpdateState: (state: VisualUpdateState, volume: Volume, newProps: PD.Values<IsosurfaceMeshParams>, currentProps: PD.Values<IsosurfaceMeshParams>) => {
             if (!Volume.IsoValue.areSame(newProps.isoValue, currentProps.isoValue, volume.grid.stats)) state.createGeometry = true;
         },
-        geometryUtils: Mesh.Utils
+        geometryUtils: Mesh.Utils,
+        mustRecreate: (props: PD.Values<IsosurfaceMeshParams>, webgl?: WebGLContext) => {
+            return props.useGpu && !!webgl;
+        }
     }, materialId);
 }
 
@@ -163,7 +179,10 @@ export function IsosurfaceTextureMeshVisual(materialId: number): VolumeVisual<Is
         setUpdateState: (state: VisualUpdateState, volume: Volume, newProps: PD.Values<IsosurfaceMeshParams>, currentProps: PD.Values<IsosurfaceMeshParams>) => {
             if (!Volume.IsoValue.areSame(newProps.isoValue, currentProps.isoValue, volume.grid.stats)) state.createGeometry = true;
         },
-        geometryUtils: TextureMesh.Utils
+        geometryUtils: TextureMesh.Utils,
+        mustRecreate: (props: PD.Values<IsosurfaceMeshParams>, webgl?: WebGLContext) => {
+            return !props.useGpu || !webgl;
+        }
     }, materialId);
 }
 
@@ -190,9 +209,9 @@ export async function createVolumeIsosurfaceWireframe(ctx: VisualContext, volume
 
 export const IsosurfaceWireframeParams = {
     ...Lines.Params,
+    ...VolumeIsosurfaceParams,
     quality: { ...Lines.Params.quality, isEssential: false },
-    sizeFactor: PD.Numeric(1.5, { min: 0, max: 10, step: 0.1 }),
-    ...VolumeIsosurfaceParams
+    sizeFactor: PD.Numeric(3, { min: 0, max: 10, step: 0.1 }),
 };
 export type IsosurfaceWireframeParams = typeof IsosurfaceWireframeParams
 
@@ -213,9 +232,7 @@ export function IsosurfaceWireframeVisual(materialId: number): VolumeVisual<Isos
 //
 
 const IsosurfaceVisuals = {
-    'solid': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<Volume, IsosurfaceMeshParams>) => VolumeRepresentation('Isosurface mesh', ctx, getParams, IsosurfaceMeshVisual, getLoci),
-    // TODO: don't enable yet as it breaks state sessions
-    // 'solid-gpu': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<Volume, IsosurfaceMeshParams>) => VolumeRepresentation('Isosurface texture-mesh', ctx, getParams, IsosurfaceTextureMeshVisual, getLoci),
+    'solid': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<Volume, IsosurfaceMeshParams>) => VolumeRepresentation('Isosurface mesh', ctx, getParams, IsosurfaceVisual, getLoci),
     'wireframe': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<Volume, IsosurfaceWireframeParams>) => VolumeRepresentation('Isosurface wireframe', ctx, getParams, IsosurfaceWireframeVisual, getLoci),
 };
 

+ 14 - 5
src/mol-repr/volume/representation.ts

@@ -30,6 +30,7 @@ import { Subject } from 'rxjs';
 import { Task } from '../../mol-task';
 import { SizeValues } from '../../mol-gl/renderable/schema';
 import { Clipping } from '../../mol-theme/clipping';
+import { WebGLContext } from '../../mol-gl/webgl/context';
 
 export interface VolumeVisual<P extends VolumeParams> extends Visual<Volume, P> { }
 
@@ -48,6 +49,7 @@ interface VolumeVisualBuilder<P extends VolumeParams, G extends Geometry> {
     getLoci(pickingId: PickingId, volume: Volume, props: PD.Values<P>, id: number): Loci
     eachLocation(loci: Loci, volume: Volume, props: PD.Values<P>, apply: (interval: Interval) => boolean): boolean
     setUpdateState(state: VisualUpdateState, volume: Volume, newProps: PD.Values<P>, currentProps: PD.Values<P>, newTheme: Theme, currentTheme: Theme): void
+    mustRecreate?: (props: PD.Values<P>) => boolean
 }
 
 interface VolumeVisualGeometryBuilder<P extends VolumeParams, G extends Geometry> extends VolumeVisualBuilder<P, G> {
@@ -55,7 +57,7 @@ interface VolumeVisualGeometryBuilder<P extends VolumeParams, G extends Geometry
 }
 
 export function VolumeVisual<G extends Geometry, P extends VolumeParams & Geometry.Params<G>>(builder: VolumeVisualGeometryBuilder<P, G>, materialId: number): VolumeVisual<P> {
-    const { defaultProps, createGeometry, createLocationIterator, getLoci, eachLocation, setUpdateState } = builder;
+    const { defaultProps, createGeometry, createLocationIterator, getLoci, eachLocation, setUpdateState, mustRecreate } = builder;
     const { updateValues, updateBoundingSphere, updateRenderableState, createPositionIterator } = builder.geometryUtils;
     const updateState = VisualUpdateState.create();
 
@@ -208,7 +210,8 @@ export function VolumeVisual<G extends Geometry, P extends VolumeParams & Geomet
         destroy() {
             // TODO
             renderObject = undefined;
-        }
+        },
+        mustRecreate
     };
 }
 
@@ -224,8 +227,9 @@ export const VolumeParams = {
 };
 export type VolumeParams = typeof VolumeParams
 
-export function VolumeRepresentation<P extends VolumeParams>(label: string, ctx: RepresentationContext, getParams: RepresentationParamsGetter<Volume, P>, visualCtor: (materialId: number) => VolumeVisual<P>, getLoci: (volume: Volume, props: PD.Values<P>) => Loci): VolumeRepresentation<P> {
+export function VolumeRepresentation<P extends VolumeParams>(label: string, ctx: RepresentationContext, getParams: RepresentationParamsGetter<Volume, P>, visualCtor: (materialId: number, props?: PD.Values<P>, webgl?: WebGLContext) => VolumeVisual<P>, getLoci: (volume: Volume, props: PD.Values<P>) => Loci): VolumeRepresentation<P> {
     let version = 0;
+    const { webgl } = ctx;
     const updated = new Subject<number>();
     const materialId = getNextMaterialId();
     const renderObjects: GraphicsRenderObject[] = [];
@@ -247,8 +251,13 @@ export function VolumeRepresentation<P extends VolumeParams>(label: string, ctx:
         Object.assign(_props, props, qualityProps);
 
         return Task.create('Creating or updating VolumeRepresentation', async runtime => {
-            if (!visual) visual = visualCtor(materialId);
-            const promise = visual.createOrUpdate({ webgl: ctx.webgl, runtime }, _theme, _props, volume);
+            if (!visual) {
+                visual = visualCtor(materialId, _props, webgl);
+            } else if (visual.mustRecreate?.(_props, webgl)) {
+                visual.destroy();
+                visual = visualCtor(materialId, _props, webgl);
+            }
+            const promise = visual.createOrUpdate({ webgl, runtime }, _theme, _props, volume);
             if (promise) await promise;
             // update list of renderObjects
             renderObjects.length = 0;

+ 3 - 3
src/tests/browser/marching-cubes.ts

@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2019-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2019-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
@@ -11,7 +11,7 @@ import { ColorNames } from '../../mol-util/color/names';
 import { PositionData, Box3D, Sphere3D } from '../../mol-math/geometry';
 import { OrderedSet } from '../../mol-data/int';
 import { Vec3 } from '../../mol-math/linear-algebra';
-import { computeGaussianDensityTexture2d, computeGaussianDensity } from '../../mol-math/geometry/gaussian-density';
+import { computeGaussianDensity, computeGaussianDensityTexture2d } from '../../mol-math/geometry/gaussian-density';
 import { calcActiveVoxels } from '../../mol-gl/compute/marching-cubes/active-voxels';
 import { createHistogramPyramid } from '../../mol-gl/compute/histogram-pyramid/reduction';
 import { createIsosurfaceBuffers } from '../../mol-gl/compute/marching-cubes/isosurface';
@@ -118,7 +118,7 @@ async function init() {
     //
 
     console.time('cpu gaussian');
-    const densityData = await computeGaussianDensity(position, box, radius, { ...props, useGpu: false }, webgl).run();
+    const densityData = await computeGaussianDensity(position, box, radius, props).run();
     console.timeEnd('cpu gaussian');
     console.log({ densityData });