瀏覽代碼

Merge pull request #552 from molstar/perf-caveat

add support for failIfMajorPerformanceCaveat
Alexander Rose 2 年之前
父節點
當前提交
1cf1f07232

+ 1 - 0
CHANGELOG.md

@@ -9,6 +9,7 @@ Note that since we don't clearly distinguish between a public and private interf
 - [Fix] Clone ``Canvas3DParams`` when creating a ``Canvas3D`` instance to prevent shared state between multiple instances
 - [Fix] Clone ``Canvas3DParams`` when creating a ``Canvas3D`` instance to prevent shared state between multiple instances
 - Add ``includeResidueTest`` option to ``alignAndSuperposeWithSIFTSMapping``
 - Add ``includeResidueTest`` option to ``alignAndSuperposeWithSIFTSMapping``
 - Add ``parentDisplay`` param for interactions representation.
 - Add ``parentDisplay`` param for interactions representation.
+- Support for ``failIfMajorPerformanceCaveat`` webgl attribute. Add ``PluginConfig.General.AllowMajorPerformanceCaveat`` and ``allow-major-performance-caveat`` Viewer GET param.
 - Fix handling of PDB TER records (#549)
 - Fix handling of PDB TER records (#549)
 - Add support for getting multiple loci from a representation (``.getAllLoci()``)
 - Add support for getting multiple loci from a representation (``.getAllLoci()``)
 - Add ``key`` property to intra- and inter-bonds for referencing source data
 - Add ``key`` property to intra- and inter-bonds for referencing source data

+ 2 - 0
src/apps/viewer/app.ts

@@ -89,6 +89,7 @@ const DefaultViewerOptions = {
     pickPadding: PluginConfig.General.PickPadding.defaultValue,
     pickPadding: PluginConfig.General.PickPadding.defaultValue,
     enableWboit: PluginConfig.General.EnableWboit.defaultValue,
     enableWboit: PluginConfig.General.EnableWboit.defaultValue,
     preferWebgl1: PluginConfig.General.PreferWebGl1.defaultValue,
     preferWebgl1: PluginConfig.General.PreferWebGl1.defaultValue,
+    allowMajorPerformanceCaveat: PluginConfig.General.AllowMajorPerformanceCaveat.defaultValue,
 
 
     viewportShowExpand: PluginConfig.Viewport.ShowExpand.defaultValue,
     viewportShowExpand: PluginConfig.Viewport.ShowExpand.defaultValue,
     viewportShowControls: PluginConfig.Viewport.ShowControls.defaultValue,
     viewportShowControls: PluginConfig.Viewport.ShowControls.defaultValue,
@@ -159,6 +160,7 @@ export class Viewer {
                 [PluginConfig.General.PickPadding, o.pickPadding],
                 [PluginConfig.General.PickPadding, o.pickPadding],
                 [PluginConfig.General.EnableWboit, o.enableWboit],
                 [PluginConfig.General.EnableWboit, o.enableWboit],
                 [PluginConfig.General.PreferWebGl1, o.preferWebgl1],
                 [PluginConfig.General.PreferWebGl1, o.preferWebgl1],
+                [PluginConfig.General.AllowMajorPerformanceCaveat, o.allowMajorPerformanceCaveat],
                 [PluginConfig.Viewport.ShowExpand, o.viewportShowExpand],
                 [PluginConfig.Viewport.ShowExpand, o.viewportShowExpand],
                 [PluginConfig.Viewport.ShowControls, o.viewportShowControls],
                 [PluginConfig.Viewport.ShowControls, o.viewportShowControls],
                 [PluginConfig.Viewport.ShowSettings, o.viewportShowSettings],
                 [PluginConfig.Viewport.ShowSettings, o.viewportShowSettings],

+ 2 - 0
src/apps/viewer/index.html

@@ -61,6 +61,7 @@
             var pickPadding = getParam('pick-padding', '[^&]+').trim();
             var pickPadding = getParam('pick-padding', '[^&]+').trim();
             var disableWboit = getParam('disable-wboit', '[^&]+').trim() === '1';
             var disableWboit = getParam('disable-wboit', '[^&]+').trim() === '1';
             var preferWebgl1 = getParam('prefer-webgl1', '[^&]+').trim() === '1' || void 0;
             var preferWebgl1 = getParam('prefer-webgl1', '[^&]+').trim() === '1' || void 0;
+            var allowMajorPerformanceCaveat = getParam('allow-major-performance-caveat', '[^&]+').trim() === '1';
 
 
             molstar.Viewer.create('app', {
             molstar.Viewer.create('app', {
                 layoutShowControls: !hideControls,
                 layoutShowControls: !hideControls,
@@ -76,6 +77,7 @@
                 pickPadding: isNaN(parseFloat(pickPadding)) ? 1 : parseFloat(pickPadding),
                 pickPadding: isNaN(parseFloat(pickPadding)) ? 1 : parseFloat(pickPadding),
                 enableWboit: disableWboit ? false : void 0, // use default value if disable-wboit is not set
                 enableWboit: disableWboit ? false : void 0, // use default value if disable-wboit is not set
                 preferWebgl1: preferWebgl1,
                 preferWebgl1: preferWebgl1,
+                allowMajorPerformanceCaveat: allowMajorPerformanceCaveat,
             }).then(viewer => {
             }).then(viewer => {
                 var snapshotId = getParam('snapshot-id', '[^&]+').trim();
                 var snapshotId = getParam('snapshot-id', '[^&]+').trim();
                 if (snapshotId) viewer.setRemoteSnapshot(snapshotId);
                 if (snapshotId) viewer.setRemoteSnapshot(snapshotId);

+ 2 - 0
src/extensions/geo-export/ui.tsx

@@ -60,6 +60,8 @@ export class GeometryExporterUI extends CollapsableControls<{}, State> {
     }
     }
 
 
     componentDidMount() {
     componentDidMount() {
+        if (!this.plugin.canvas3d) return;
+
         const merged = merge(
         const merged = merge(
             this.controls.behaviors.params,
             this.controls.behaviors.params,
             this.plugin.canvas3d!.reprCount
             this.plugin.canvas3d!.reprCount

+ 3 - 1
src/extensions/mp4-export/controls.ts

@@ -118,11 +118,13 @@ export class Mp4Controls extends PluginComponent {
     }
     }
 
 
     private init() {
     private init() {
+        if (!this.plugin.canvas3d) return;
+
         this.subscribe(this.plugin.managers.animation.events.updated.pipe(debounceTime(16)), () => {
         this.subscribe(this.plugin.managers.animation.events.updated.pipe(debounceTime(16)), () => {
             this.sync();
             this.sync();
         });
         });
 
 
-        this.subscribe(this.plugin.canvas3d?.resized!, () => this.syncInfo());
+        this.subscribe(this.plugin.canvas3d.resized, () => this.syncInfo());
         this.subscribe(this.plugin.helpers.viewportScreenshot?.events.previewed!, () => this.syncInfo());
         this.subscribe(this.plugin.helpers.viewportScreenshot?.events.previewed!, () => this.syncInfo());
 
 
         this.subscribe(this.plugin.behaviors.state.isBusy, b => this.updateCanApply(b));
         this.subscribe(this.plugin.behaviors.state.isBusy, b => this.updateCanApply(b));

+ 3 - 1
src/mol-canvas3d/canvas3d.ts

@@ -117,6 +117,7 @@ interface Canvas3DContext {
 
 
 namespace Canvas3DContext {
 namespace Canvas3DContext {
     export const DefaultAttribs = {
     export const DefaultAttribs = {
+        failIfMajorPerformanceCaveat: false,
         /** true by default to avoid issues with Safari (Jan 2021) */
         /** true by default to avoid issues with Safari (Jan 2021) */
         antialias: true,
         antialias: true,
         /** true to support multiple Canvas3D objects with a single context */
         /** true to support multiple Canvas3D objects with a single context */
@@ -132,8 +133,9 @@ namespace Canvas3DContext {
 
 
     export function fromCanvas(canvas: HTMLCanvasElement, assetManager: AssetManager, attribs: Partial<Attribs> = {}): Canvas3DContext {
     export function fromCanvas(canvas: HTMLCanvasElement, assetManager: AssetManager, attribs: Partial<Attribs> = {}): Canvas3DContext {
         const a = { ...DefaultAttribs, ...attribs };
         const a = { ...DefaultAttribs, ...attribs };
-        const { antialias, preserveDrawingBuffer, pixelScale, preferWebGl1 } = a;
+        const { failIfMajorPerformanceCaveat, antialias, preserveDrawingBuffer, pixelScale, preferWebGl1 } = a;
         const gl = getGLContext(canvas, {
         const gl = getGLContext(canvas, {
+            failIfMajorPerformanceCaveat,
             antialias,
             antialias,
             preserveDrawingBuffer,
             preserveDrawingBuffer,
             alpha: true, // the renderer requires an alpha channel
             alpha: true, // the renderer requires an alpha channel

+ 13 - 10
src/mol-plugin-ui/controls/screenshot.tsx

@@ -1,7 +1,8 @@
 /**
 /**
- * Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2020-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  *
  * @author David Sehnal <david.sehnal@gmail.com>
  * @author David Sehnal <david.sehnal@gmail.com>
+ * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
  */
 
 
 import * as React from 'react';
 import * as React from 'react';
@@ -25,7 +26,7 @@ export interface ScreenshotPreviewProps {
 const _ScreenshotPreview = (props: ScreenshotPreviewProps) => {
 const _ScreenshotPreview = (props: ScreenshotPreviewProps) => {
     const { plugin, cropFrameColor } = props;
     const { plugin, cropFrameColor } = props;
 
 
-    const helper = plugin.helpers.viewportScreenshot!;
+    const helper = plugin.helpers.viewportScreenshot;
     const [currentCanvas, setCurrentCanvas] = useState<HTMLCanvasElement | null>(null);
     const [currentCanvas, setCurrentCanvas] = useState<HTMLCanvasElement | null>(null);
     const canvasRef = useRef<HTMLCanvasElement | null>(null);
     const canvasRef = useRef<HTMLCanvasElement | null>(null);
     const propsRef = useRef(props);
     const propsRef = useRef(props);
@@ -70,8 +71,8 @@ const _ScreenshotPreview = (props: ScreenshotPreviewProps) => {
         subscribe(plugin.state.data.behaviors.isUpdating, v => {
         subscribe(plugin.state.data.behaviors.isUpdating, v => {
             if (!v) isDirty = true;
             if (!v) isDirty = true;
         });
         });
-        subscribe(helper.behaviors.values, () => isDirty = true);
-        subscribe(helper.behaviors.cropParams, () => isDirty = true);
+        subscribe(helper?.behaviors.values, () => isDirty = true);
+        subscribe(helper?.behaviors.cropParams, () => isDirty = true);
 
 
         let resizeObserver: any = void 0;
         let resizeObserver: any = void 0;
         if (typeof ResizeObserver !== 'undefined') {
         if (typeof ResizeObserver !== 'undefined') {
@@ -108,7 +109,9 @@ export const ScreenshotPreview = React.memo(_ScreenshotPreview, (prev, next) =>
 
 
 declare const ResizeObserver: any;
 declare const ResizeObserver: any;
 
 
-function drawPreview(helper: ViewportScreenshotHelper, target: HTMLCanvasElement, customBackground?: string, borderColor?: string, borderWidth?: number) {
+function drawPreview(helper: ViewportScreenshotHelper | undefined, target: HTMLCanvasElement, customBackground?: string, borderColor?: string, borderWidth?: number) {
+    if (!helper) return;
+
     const { canvas, width, height } = helper.getPreview()!;
     const { canvas, width, height } = helper.getPreview()!;
     const ctx = target.getContext('2d');
     const ctx = target.getContext('2d');
     if (!ctx) return;
     if (!ctx) return;
@@ -151,9 +154,9 @@ function drawPreview(helper: ViewportScreenshotHelper, target: HTMLCanvasElement
 
 
 function ViewportFrame({ plugin, canvas, color = 'rgba(255, 87, 45, 0.75)' }: { plugin: PluginContext, canvas: HTMLCanvasElement | null, color?: string }) {
 function ViewportFrame({ plugin, canvas, color = 'rgba(255, 87, 45, 0.75)' }: { plugin: PluginContext, canvas: HTMLCanvasElement | null, color?: string }) {
     const helper = plugin.helpers.viewportScreenshot;
     const helper = plugin.helpers.viewportScreenshot;
-    const params = useBehavior(helper?.behaviors.values!);
-    const cropParams = useBehavior(helper?.behaviors.cropParams!);
-    const crop = useBehavior(helper?.behaviors.relativeCrop!);
+    const params = useBehavior(helper?.behaviors.values);
+    const cropParams = useBehavior(helper?.behaviors.cropParams);
+    const crop = useBehavior(helper?.behaviors.relativeCrop);
     const cropFrameRef = useRef<Viewport>({ x: 0, y: 0, width: 0, height: 0 });
     const cropFrameRef = useRef<Viewport>({ x: 0, y: 0, width: 0, height: 0 });
     useBehavior(params?.resolution.name === 'viewport' ? plugin.canvas3d?.resized : void 0);
     useBehavior(params?.resolution.name === 'viewport' ? plugin.canvas3d?.resized : void 0);
 
 
@@ -161,7 +164,7 @@ function ViewportFrame({ plugin, canvas, color = 'rgba(255, 87, 45, 0.75)' }: {
     const [start, setStart] = useState([0, 0]);
     const [start, setStart] = useState([0, 0]);
     const [current, setCurrent] = useState([0, 0]);
     const [current, setCurrent] = useState([0, 0]);
 
 
-    if (!helper || !canvas) return null;
+    if (!helper || !canvas || !crop) return null;
 
 
     const { width, height } = helper.getSizeAndViewport();
     const { width, height } = helper.getSizeAndViewport();
 
 
@@ -267,7 +270,7 @@ function ViewportFrame({ plugin, canvas, color = 'rgba(255, 87, 45, 0.75)' }: {
 
 
     function finish() {
     function finish() {
         const cropFrame = cropFrameRef.current;
         const cropFrame = cropFrameRef.current;
-        if (cropParams.auto) {
+        if (cropParams?.auto) {
             helper?.behaviors.cropParams.next({ ...cropParams, auto: false });
             helper?.behaviors.cropParams.next({ ...cropParams, auto: false });
         }
         }
         helper?.behaviors.relativeCrop.next({
         helper?.behaviors.relativeCrop.next({

+ 7 - 5
src/mol-plugin-ui/left-panel.tsx

@@ -141,11 +141,13 @@ class FullSettings extends PluginUIComponent {
         this.subscribe(this.plugin.events.canvas3d.settingsUpdated, () => this.forceUpdate());
         this.subscribe(this.plugin.events.canvas3d.settingsUpdated, () => this.forceUpdate());
         this.subscribe(this.plugin.layout.events.updated, () => this.forceUpdate());
         this.subscribe(this.plugin.layout.events.updated, () => this.forceUpdate());
 
 
-        this.subscribe(this.plugin.canvas3d!.camera.stateChanged, state => {
-            if (state.radiusMax !== undefined || state.radius !== undefined) {
-                this.forceUpdate();
-            }
-        });
+        if (this.plugin.canvas3d) {
+            this.subscribe(this.plugin.canvas3d.camera.stateChanged, state => {
+                if (state.radiusMax !== undefined || state.radius !== undefined) {
+                    this.forceUpdate();
+                }
+            });
+        }
     }
     }
 
 
     render() {
     render() {

+ 1 - 1
src/mol-plugin-ui/viewport/canvas.tsx

@@ -59,7 +59,7 @@ export class ViewportCanvas extends PluginUIComponent<ViewportCanvasParams, View
         return <div className='msp-no-webgl'>
         return <div className='msp-no-webgl'>
             <div>
             <div>
                 <p><b>WebGL does not seem to be available.</b></p>
                 <p><b>WebGL does not seem to be available.</b></p>
-                <p>This can be caused by an outdated browser, graphics card driver issue, or bad weather. Sometimes, just restarting the browser helps.</p>
+                <p>This can be caused by an outdated browser, graphics card driver issue, or bad weather. Sometimes, just restarting the browser helps. Also, make sure hardware acceleration is enabled in your browser.</p>
                 <p>For a list of supported browsers, refer to <a href='http://caniuse.com/#feat=webgl' target='_blank'>http://caniuse.com/#feat=webgl</a>.</p>
                 <p>For a list of supported browsers, refer to <a href='http://caniuse.com/#feat=webgl' target='_blank'>http://caniuse.com/#feat=webgl</a>.</p>
             </div>
             </div>
         </div>;
         </div>;

+ 8 - 5
src/mol-plugin-ui/viewport/screenshot.tsx

@@ -1,5 +1,5 @@
 /**
 /**
- * Copyright (c) 2019-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2019-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  * @author David Sehnal <david.sehnal@gmail.com>
  * @author David Sehnal <david.sehnal@gmail.com>
@@ -96,18 +96,21 @@ export class DownloadScreenshotControls extends PluginUIComponent<{ close: () =>
 }
 }
 
 
 function ScreenshotParams({ plugin, isDisabled }: { plugin: PluginContext, isDisabled: boolean }) {
 function ScreenshotParams({ plugin, isDisabled }: { plugin: PluginContext, isDisabled: boolean }) {
-    const helper = plugin.helpers.viewportScreenshot!;
-    const values = useBehavior(helper.behaviors.values);
+    const helper = plugin.helpers.viewportScreenshot;
+
+    const values = useBehavior(helper?.behaviors.values);
+    if (!helper) return null;
 
 
     return <ParameterControls params={helper.params} values={values} onChangeValues={v => helper.behaviors.values.next(v)} isDisabled={isDisabled} />;
     return <ParameterControls params={helper.params} values={values} onChangeValues={v => helper.behaviors.values.next(v)} isDisabled={isDisabled} />;
 }
 }
 
 
 function CropControls({ plugin }: { plugin: PluginContext }) {
 function CropControls({ plugin }: { plugin: PluginContext }) {
     const helper = plugin.helpers.viewportScreenshot;
     const helper = plugin.helpers.viewportScreenshot;
-    const cropParams = useBehavior(helper?.behaviors.cropParams!);
+
+    const cropParams = useBehavior(helper?.behaviors.cropParams);
     useBehavior(helper?.behaviors.relativeCrop);
     useBehavior(helper?.behaviors.relativeCrop);
 
 
-    if (!helper) return null;
+    if (!helper || !cropParams) return null;
 
 
     return <div style={{ width: '100%', height: '24px', marginTop: '8px' }}>
     return <div style={{ width: '100%', height: '24px', marginTop: '8px' }}>
         <ToggleButton icon={CropOrginalSvg} title='Auto-crop' inline isSelected={cropParams.auto}
         <ToggleButton icon={CropOrginalSvg} title='Auto-crop' inline isSelected={cropParams.auto}

+ 2 - 0
src/mol-plugin-ui/viewport/simple-settings.tsx

@@ -22,6 +22,8 @@ import { ViewportHelpContent } from './help';
 
 
 export class SimpleSettingsControl extends PluginUIComponent {
 export class SimpleSettingsControl extends PluginUIComponent {
     componentDidMount() {
     componentDidMount() {
+        if (!this.plugin.canvas3d) return;
+
         this.subscribe(this.plugin.events.canvas3d.settingsUpdated, () => this.forceUpdate());
         this.subscribe(this.plugin.events.canvas3d.settingsUpdated, () => this.forceUpdate());
 
 
         this.subscribe(this.plugin.canvas3d!.camera.stateChanged, state => {
         this.subscribe(this.plugin.canvas3d!.camera.stateChanged, state => {

+ 1 - 0
src/mol-plugin/config.ts

@@ -35,6 +35,7 @@ export const PluginConfig = {
         // as of Oct 1 2021, WebGL 2 doesn't work on iOS 15.
         // as of Oct 1 2021, WebGL 2 doesn't work on iOS 15.
         // TODO: check back in a few weeks to see if it was fixed
         // TODO: check back in a few weeks to see if it was fixed
         PreferWebGl1: item('plugin-config.prefer-webgl1', PluginFeatureDetection.preferWebGl1),
         PreferWebGl1: item('plugin-config.prefer-webgl1', PluginFeatureDetection.preferWebGl1),
+        AllowMajorPerformanceCaveat: item('plugin-config.allow-major-performance-caveat', false),
     },
     },
     State: {
     State: {
         DefaultServer: item('plugin-state.server', 'https://webchem.ncbr.muni.cz/molstar-state'),
         DefaultServer: item('plugin-state.server', 'https://webchem.ncbr.muni.cz/molstar-state'),

+ 2 - 1
src/mol-plugin/context.ts

@@ -201,7 +201,8 @@ export class PluginContext {
                 const pickPadding = this.config.get(PluginConfig.General.PickPadding) ?? 1;
                 const pickPadding = this.config.get(PluginConfig.General.PickPadding) ?? 1;
                 const enableWboit = this.config.get(PluginConfig.General.EnableWboit) || false;
                 const enableWboit = this.config.get(PluginConfig.General.EnableWboit) || false;
                 const preferWebGl1 = this.config.get(PluginConfig.General.PreferWebGl1) || false;
                 const preferWebGl1 = this.config.get(PluginConfig.General.PreferWebGl1) || false;
-                (this.canvas3dContext as Canvas3DContext) = Canvas3DContext.fromCanvas(canvas, this.managers.asset, { antialias, preserveDrawingBuffer, pixelScale, pickScale, pickPadding, enableWboit, preferWebGl1 });
+                const failIfMajorPerformanceCaveat = !(this.config.get(PluginConfig.General.AllowMajorPerformanceCaveat) ?? false);
+                (this.canvas3dContext as Canvas3DContext) = Canvas3DContext.fromCanvas(canvas, this.managers.asset, { antialias, preserveDrawingBuffer, pixelScale, pickScale, pickPadding, enableWboit, preferWebGl1, failIfMajorPerformanceCaveat });
             }
             }
             (this.canvas3d as Canvas3D) = Canvas3D.create(this.canvas3dContext!);
             (this.canvas3d as Canvas3D) = Canvas3D.create(this.canvas3dContext!);
             this.canvas3dInit.next(true);
             this.canvas3dInit.next(true);