Compare commits

...

33 Commits

Author SHA1 Message Date
Alexander Rose
7a07701be0 3.9.1 2022-06-19 19:21:25 -07:00
Alexander Rose
42519a4f75 changelog 2022-06-19 19:16:15 -07:00
Alexander Rose
c898c16430 package updates 2022-06-19 19:15:06 -07:00
Alexander Rose
318863bd18 fix missing aromatic bond display
- simplify code to always show when aromatic
2022-06-19 19:05:58 -07:00
Alexander Rose
ce94760d02 fix missing uGroupCount update for visuals 2022-06-19 18:51:16 -07:00
dsehnal
da413cc9e6 added missing super.componentWillUnmount 2022-06-10 14:53:26 +02:00
David Sehnal
c72e93a13d Merge pull request #452 from simeonborko/sborko/screenshot-unmount
DownloadScreenshotControls: componentWillUnmount
2022-06-10 14:46:19 +02:00
Simeon Borko
21f910a3ca DownloadScreenshotControls: componentWillUnmount
This should solve the error:

Warning: Can't perform a React state update on an unmounted component.
This is a no-op, but it indicates a memory leak in your application.
To fix, cancel all subscriptions and asynchronous tasks in the componentWillUnmount method.
2022-06-10 10:04:31 +02:00
Alexander Rose
e7ce693e50 3.9.0 2022-05-30 11:46:42 -07:00
Alexander Rose
29e8fe7904 fix types 2022-05-30 11:41:40 -07:00
Alexander Rose
baf3a6077e package updates 2022-05-30 11:32:05 -07:00
Alexander Rose
e030e7a32d changelog 2022-05-30 11:29:23 -07:00
Alexander Rose
125566ed75 only call renderBlendedTransparent when needed 2022-05-30 11:27:58 -07:00
Alexander Rose
c51cb67519 Merge pull request #447 from molstar/pick-drawbuffers
use drawbuffers for picking
2022-05-29 23:35:53 -07:00
Alexander Rose
57f086b530 Merge branch 'master' into pick-drawbuffers 2022-05-29 23:32:57 -07:00
Alexander Rose
d1e17785b8 Merge pull request #446 from molstar/webgl-timer
Webgl timing support
2022-05-29 23:32:29 -07:00
Alexander Rose
774328a1d8 Merge branch 'master' into webgl-timer 2022-05-29 23:31:13 -07:00
Alexander Rose
175a0f48fa lint fix 2022-05-29 23:30:36 -07:00
Alexander Rose
60b91ff032 Merge branch 'master' into pick-drawbuffers 2022-05-29 11:11:29 -07:00
David Sehnal
2b003bc5b0 Merge pull request #445 from aliaksei-chareshneu/fix_bad_axis_order
Add check that a data block contains volume data before parsing
2022-05-29 16:00:10 +02:00
David Sehnal
029a2fcab1 Merge branch 'master' into fix_bad_axis_order 2022-05-29 15:59:52 +02:00
Alexander Rose
a828113d9b use drawbuffers for picking 2022-05-28 13:17:35 -07:00
Alexander Rose
ab4d509eda fix rendering volumes
- when wboit is switched off and postprocessing is enabled
2022-05-28 13:13:35 -07:00
Alexander Rose
1296f32fa8 tweak alpha-orbitals example 2022-05-28 11:54:33 -07:00
Alexander Rose
5aa1ec9876 add timing mode 2022-05-28 11:43:13 -07:00
Alexander Rose
f2cf1ab226 add support for GPU timer queries 2022-05-28 11:20:22 -07:00
Alexander Rose
2d34c2a40b fix Scene.clear not clearing primitives/volumes 2022-05-28 11:07:03 -07:00
Aliaksei
a7181e865c Skipping server data block
Co-authored-by: David Sehnal <dsehnal@users.noreply.github.com>
2022-05-28 08:16:58 +02:00
Aliaksei
0a71b788b3 Apply suggestions from code review
fix bugs and optimizing the code related to iteration over data blocks

Co-authored-by: David Sehnal <dsehnal@users.noreply.github.com>
2022-05-27 18:22:00 +02:00
aliaksei-chareshneu
1ed3d84043 fix to skip block with header SERVER 2022-05-27 14:26:42 +02:00
aliaksei-chareshneu
f472b75d0d iterate over all blocks as even 0th can contain data 2022-05-27 13:53:08 +02:00
aliaksei-chareshneu
072a9d1ccd add name and email to header; add changelog entry 2022-05-27 12:19:51 +02:00
aliaksei-chareshneu
8e26d1be68 fix bad axis ordering bug 2022-05-27 10:34:48 +02:00
60 changed files with 2335 additions and 2598 deletions

View File

@@ -6,6 +6,23 @@ Note that since we don't clearly distinguish between a public and private interf
## [Unreleased]
## [v3.9.1] - 2022-06-19
- Fix missing ``super.componentWillUnmount()`` calls (@simeonborko)
- Fix missing ``uGroupCount`` update for visuals
- Fix missing aromatic bond display
## [v3.9.0] - 2022-05-30
- Improve picking by using drawbuffers (when available) to reduce number of drawcalls
- GPU timing support
- Add ``timing-mode`` Viewer GET param
- Add support for webgl timer queries
- Add timer marks around GPU render & compute operations
- Volume Server CIF: Add check that a data block contains volume data before parsing
- Fix ``Scene.clear`` not clearing primitives & volumes arrays (@JonStargaryen)
- Fix rendering volumes when wboit is switched off and postprocessing is enabled
## [v3.8.2] - 2022-05-22
- Fix ``Scene.opacityAverage`` not taking xray shaded into account

3890
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "molstar",
"version": "3.8.2",
"version": "3.9.1",
"description": "A comprehensive macromolecular library.",
"homepage": "https://github.com/molstar/molstar#readme",
"repository": {
@@ -94,51 +94,51 @@
"@graphql-codegen/add": "^3.1.1",
"@graphql-codegen/cli": "^2.6.2",
"@graphql-codegen/time": "^3.1.1",
"@graphql-codegen/typescript": "^2.4.11",
"@graphql-codegen/typescript": "^2.5.1",
"@graphql-codegen/typescript-graphql-files-modules": "^2.1.1",
"@graphql-codegen/typescript-graphql-request": "^4.4.8",
"@graphql-codegen/typescript-operations": "^2.4.0",
"@graphql-codegen/typescript-graphql-request": "^4.4.10",
"@graphql-codegen/typescript-operations": "^2.4.2",
"@types/cors": "^2.8.12",
"@types/gl": "^4.1.0",
"@types/jest": "^27.5.1",
"@types/react": "^18.0.9",
"@types/react-dom": "^18.0.4",
"@typescript-eslint/eslint-plugin": "^5.25.0",
"@typescript-eslint/parser": "^5.25.0",
"@types/jest": "^28.1.2",
"@types/react": "^18.0.14",
"@types/react-dom": "^18.0.5",
"@typescript-eslint/eslint-plugin": "^5.28.0",
"@typescript-eslint/parser": "^5.28.0",
"benchmark": "^2.1.4",
"concurrently": "^7.2.0",
"concurrently": "^7.2.2",
"cpx2": "^4.2.0",
"crypto-browserify": "^3.12.0",
"css-loader": "^6.7.1",
"eslint": "^8.16.0",
"eslint": "^8.18.0",
"extra-watch-webpack-plugin": "^1.0.3",
"file-loader": "^6.2.0",
"fs-extra": "^10.1.0",
"graphql": "^16.5.0",
"http-server": "^14.1.0",
"jest": "^28.1.0",
"mini-css-extract-plugin": "^2.6.0",
"http-server": "^14.1.1",
"jest": "^28.1.1",
"mini-css-extract-plugin": "^2.6.1",
"path-browserify": "^1.0.1",
"raw-loader": "^4.0.2",
"react": "^18.1.0",
"react-dom": "^18.1.0",
"sass": "^1.52.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"sass": "^1.52.3",
"sass-loader": "^13.0.0",
"simple-git": "^3.7.1",
"simple-git": "^3.8.0",
"stream-browserify": "^3.0.0",
"style-loader": "^3.3.1",
"ts-jest": "^28.0.2",
"typescript": "^4.6.4",
"webpack": "^5.72.1",
"webpack-cli": "^4.9.2"
"ts-jest": "^28.0.5",
"typescript": "^4.7.4",
"webpack": "^5.73.0",
"webpack-cli": "^4.10.0"
},
"dependencies": {
"@types/argparse": "^2.0.10",
"@types/benchmark": "^2.1.1",
"@types/compression": "1.7.2",
"@types/express": "^4.17.13",
"@types/node": "^16.11.36",
"@types/node-fetch": "^2.6.1",
"@types/node": "^16.11.41",
"@types/node-fetch": "^2.6.2",
"@types/swagger-ui-dist": "3.30.1",
"argparse": "^2.0.1",
"body-parser": "^1.20.0",
@@ -146,11 +146,11 @@
"cors": "^2.8.5",
"express": "^4.18.1",
"h264-mp4-encoder": "^1.0.12",
"immer": "^9.0.14",
"immutable": "^4.0.0",
"immer": "^9.0.15",
"immutable": "^4.1.0",
"node-fetch": "^2.6.7",
"rxjs": "^7.5.5",
"swagger-ui-dist": "^4.11.1",
"swagger-ui-dist": "^4.12.0",
"tslib": "^2.4.0",
"util.promisify": "^1.1.1",
"xhr2": "^0.2.1"

View File

@@ -47,7 +47,7 @@ import '../../mol-util/polyfill';
import { ObjectKeys } from '../../mol-util/type-helpers';
export { PLUGIN_VERSION as version } from '../../mol-plugin/version';
export { setDebugMode, setProductionMode } from '../../mol-util/debug';
export { setDebugMode, setProductionMode, setTimingMode } from '../../mol-util/debug';
const CustomFormats = [
['g3d', G3dProvider] as const

View File

@@ -46,7 +46,10 @@
}
var debugMode = getParam('debug-mode', '[^&]+').trim() === '1';
if (debugMode) molstar.setDebugMode(debugMode, debugMode);
if (debugMode) molstar.setDebugMode(debugMode);
var timingMode = getParam('timing-mode', '[^&]+').trim() === '1';
if (timingMode) molstar.setTimingMode(timingMode);
var hideControls = getParam('hide-controls', '[^&]+').trim() === '1';
var collapseLeftPanel = getParam('collapse-left-panel', '[^&]+').trim() === '1';

View File

@@ -55,6 +55,17 @@
</a>
</div>
<script>
function getParam(name, regex) {
var r = new RegExp(name + '=' + '(' + regex + ')[&]?', 'i');
return decodeURIComponent(((window.location.search || '').match(r) || [])[1] || '');
}
var debugMode = getParam('debug-mode', '[^&]+').trim() === '1';
if (debugMode) AlphaOrbitalsExample.setDebugMode(debugMode);
var timingMode = getParam('timing-mode', '[^&]+').trim() === '1';
if (timingMode) AlphaOrbitalsExample.setTimingMode(timingMode);
AlphaOrbitalsExample.init('app')
</script>
<!-- __MOLSTAR_ANALYTICS__ -->

View File

@@ -1,5 +1,5 @@
/**
* 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>
*/
@@ -25,6 +25,8 @@ import { DemoMoleculeSDF, DemoOrbitals } from './example-data';
import './index.html';
require('mol-plugin-ui/skin/light.scss');
import { setDebugMode, setTimingMode } from '../../mol-util/debug';
interface DemoInput {
moleculeSdf: string,
basis: Basis,
@@ -222,4 +224,6 @@ export class AlphaOrbitalsExample {
}
}
(window as any).AlphaOrbitalsExample = new AlphaOrbitalsExample();
(window as any).AlphaOrbitalsExample = new AlphaOrbitalsExample();
(window as any).AlphaOrbitalsExample.setDebugMode = setDebugMode;
(window as any).AlphaOrbitalsExample.setTimingMode = setTimingMode;

View File

@@ -1,5 +1,5 @@
/**
* 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>
*/
@@ -8,6 +8,7 @@ import { sortArray } from '../../mol-data/util';
import { canComputeGrid3dOnGPU } from '../../mol-gl/compute/grid3d';
import { WebGLContext } from '../../mol-gl/webgl/context';
import { Task } from '../../mol-task';
import { isTimingMode } from '../../mol-util/debug';
import { AlphaOrbital, createGrid, CubeGrid, CubeGridComputationParams, initCubeGrid } from './data-model';
import { gpuComputeAlphaOrbitalsDensityGridValues } from './gpu/compute';
@@ -19,9 +20,9 @@ export function createSphericalCollocationDensityGrid(
let matrix: Float32Array;
if (canComputeGrid3dOnGPU(webgl)) {
// console.time('gpu');
matrix = await gpuComputeAlphaOrbitalsDensityGridValues(ctx, webgl!, cubeGrid, orbitals);
// console.timeEnd('gpu');
if (isTimingMode) webgl.timer.mark('createSphericalCollocationDensityGrid');
matrix = await gpuComputeAlphaOrbitalsDensityGridValues(ctx, webgl, cubeGrid, orbitals);
if (isTimingMode) webgl.timer.markEnd('createSphericalCollocationDensityGrid');
} else {
throw new Error('Missing OES_texture_float WebGL extension.');
}

View File

@@ -1,5 +1,5 @@
/**
* 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.
*
* Inspired by https://github.com/dgasmith/gau2grid.
*
@@ -10,12 +10,11 @@ import { sortArray } from '../../mol-data/util';
import { canComputeGrid3dOnGPU } from '../../mol-gl/compute/grid3d';
import { WebGLContext } from '../../mol-gl/webgl/context';
import { Task } from '../../mol-task';
import { isTimingMode } from '../../mol-util/debug';
import { sphericalCollocation } from './collocation';
import { AlphaOrbital, createGrid, CubeGrid, CubeGridComputationParams, initCubeGrid } from './data-model';
import { gpuComputeAlphaOrbitalsGridValues } from './gpu/compute';
// setDebugMode(true);
export function createSphericalCollocationGrid(
params: CubeGridComputationParams, orbital: AlphaOrbital, webgl?: WebGLContext
): Task<CubeGrid> {
@@ -24,9 +23,9 @@ export function createSphericalCollocationGrid(
let matrix: Float32Array;
if (canComputeGrid3dOnGPU(webgl)) {
// console.time('gpu');
matrix = await gpuComputeAlphaOrbitalsGridValues(ctx, webgl!, cubeGrid, orbital);
// console.timeEnd('gpu');
if (isTimingMode) webgl.timer.mark('createSphericalCollocationGrid');
matrix = await gpuComputeAlphaOrbitalsGridValues(ctx, webgl, cubeGrid, orbital);
if (isTimingMode) webgl.timer.markEnd('createSphericalCollocationGrid');
} else {
// console.time('cpu');
matrix = await sphericalCollocation(cubeGrid, orbital, ctx);

View File

@@ -71,6 +71,7 @@ export class GeometryExporterUI extends CollapsableControls<{}, State> {
}
componentWillUnmount() {
super.componentWillUnmount();
this._controls?.dispose();
this._controls = void 0;
}

View File

@@ -102,6 +102,7 @@ export class Mp4EncoderUI extends CollapsableControls<{}, State> {
}
componentWillUnmount() {
super.componentWillUnmount();
this._controls?.dispose();
this._controls = void 0;
}

View File

@@ -30,7 +30,7 @@ import { PickData } from './passes/pick';
import { PickHelper } from './passes/pick';
import { ImagePass, ImageProps } from './passes/image';
import { Sphere3D } from '../mol-math/geometry';
import { isDebugMode } from '../mol-util/debug';
import { isDebugMode, isTimingMode } from '../mol-util/debug';
import { CameraHelperParams } from './helper/camera-helper';
import { produce } from 'immer';
import { HandleHelperParams } from './helper/handle-helper';
@@ -413,6 +413,7 @@ namespace Canvas3D {
cam = stereoCamera;
}
if (isTimingMode) webgl.timer.mark('Canvas3D.render');
const ctx = { renderer, camera: cam, scene, helper };
if (MultiSamplePass.isEnabled(p.multiSample)) {
const forceOn = !cameraChanged && markingUpdated && !controls.isAnimating;
@@ -420,6 +421,8 @@ namespace Canvas3D {
} else {
passes.draw.render(ctx, p, true);
}
if (isTimingMode) webgl.timer.markEnd('Canvas3D.render');
// if only marking has updated, do not set the flag to dirty
pickHelper.dirty = pickHelper.dirty || shouldRender;
didRender = true;

View File

@@ -20,6 +20,7 @@ import { WboitPass } from './wboit';
import { AntialiasingPass, PostprocessingPass, PostprocessingProps } from './postprocessing';
import { MarkingPass, MarkingProps } from './marking';
import { CopyRenderable, createCopyRenderable } from '../../mol-gl/compute/util';
import { isTimingMode } from '../../mol-util/debug';
type Props = {
postprocessing: PostprocessingProps
@@ -143,8 +144,12 @@ export class DrawPass {
// render transparent primitives and volumes
if (scene.opacityAverage < 1 || scene.volumes.renderables.length > 0) {
this.wboit.bind();
renderer.renderWboitTransparent(scene.primitives, camera, this.depthTextureOpaque);
renderer.renderWboitTransparent(scene.volumes, camera, this.depthTextureOpaque);
if (scene.opacityAverage < 1) {
renderer.renderWboitTransparent(scene.primitives, camera, this.depthTextureOpaque);
}
if (scene.volumes.renderables.length > 0) {
renderer.renderWboitTransparent(scene.volumes, camera, this.depthTextureOpaque);
}
// evaluate wboit
if (PostprocessingPass.isEnabled(postprocessingProps)) {
@@ -203,10 +208,31 @@ export class DrawPass {
}
}
renderer.renderBlendedVolume(scene.volumes, camera, this.depthTextureOpaque);
if (scene.volumes.renderables.length > 0) {
const target = PostprocessingPass.isEnabled(postprocessingProps)
? this.postprocessing.target : this.colorTarget;
if (!this.packedDepth) {
this.depthTextureOpaque.detachFramebuffer(target.framebuffer, 'depth');
} else {
this.colorTarget.depthRenderbuffer?.detachFramebuffer(target.framebuffer);
}
target.bind();
renderer.renderBlendedVolume(scene.volumes, camera, this.depthTextureOpaque);
if (!this.packedDepth) {
this.depthTextureOpaque.attachFramebuffer(target.framebuffer, 'depth');
} else {
this.colorTarget.depthRenderbuffer?.attachFramebuffer(target.framebuffer);
}
target.bind();
}
}
renderer.renderBlendedTransparent(scene.primitives, camera, null);
if (scene.opacityAverage < 1) {
renderer.renderBlendedTransparent(scene.primitives, camera, null);
}
}
private _render(renderer: Renderer, camera: ICamera, scene: Scene, helper: Helper, toDrawingBuffer: boolean, props: Props) {
@@ -286,6 +312,7 @@ export class DrawPass {
}
render(ctx: RenderContext, props: Props, toDrawingBuffer: boolean) {
if (isTimingMode) this.webgl.timer.mark('DrawPass.render');
const { renderer, camera, scene, helper } = ctx;
renderer.setTransparentBackground(props.transparentBackground);
renderer.setDrawingBufferSize(this.colorTarget.getWidth(), this.colorTarget.getHeight());
@@ -297,6 +324,7 @@ export class DrawPass {
} else {
this._render(renderer, camera, scene, helper, toDrawingBuffer, props);
}
if (isTimingMode) this.webgl.timer.markEnd('DrawPass.render');
}
getColorTarget(postprocessingProps: PostprocessingProps): RenderTarget {

View File

@@ -18,6 +18,7 @@ import { quad_vert } from '../../mol-gl/shader/quad.vert';
import { fxaa_frag } from '../../mol-gl/shader/fxaa.frag';
import { Viewport } from '../camera/util';
import { RenderTarget } from '../../mol-gl/webgl/render-target';
import { isTimingMode } from '../../mol-util/debug';
export const FxaaParams = {
edgeThresholdMin: PD.Numeric(0.0312, { min: 0.0312, max: 0.0833, step: 0.0001 }, { description: 'Trims the algorithm from processing darks.' }),
@@ -83,6 +84,7 @@ export class FxaaPass {
}
render(viewport: Viewport, target: RenderTarget | undefined) {
if (isTimingMode) this.webgl.timer.mark('FxaaPass.render');
if (target) {
target.bind();
} else {
@@ -90,6 +92,7 @@ export class FxaaPass {
}
this.updateState(viewport);
this.renderable.render();
if (isTimingMode) this.webgl.timer.markEnd('FxaaPass.render');
}
}

View File

@@ -20,6 +20,7 @@ import { Viewport } from '../camera/util';
import { RenderTarget } from '../../mol-gl/webgl/render-target';
import { Color } from '../../mol-util/color';
import { edge_frag } from '../../mol-gl/shader/marking/edge.frag';
import { isTimingMode } from '../../mol-util/debug';
export const MarkingParams = {
enabled: PD.Boolean(true),
@@ -117,6 +118,7 @@ export class MarkingPass {
}
render(viewport: Viewport, target: RenderTarget | undefined) {
if (isTimingMode) this.webgl.timer.mark('MarkingPass.render');
this.edgesTarget.bind();
this.setEdgeState(viewport);
this.edge.render();
@@ -128,6 +130,7 @@ export class MarkingPass {
}
this.setOverlayState(viewport);
this.overlay.render();
if (isTimingMode) this.webgl.timer.markEnd('MarkingPass.render');
}
}

View File

@@ -25,6 +25,7 @@ import { StereoCamera } from '../camera/stereo';
import { quad_vert } from '../../mol-gl/shader/quad.vert';
import { compose_frag } from '../../mol-gl/shader/compose.frag';
import { MarkingProps } from './marking';
import { isTimingMode } from '../../mol-util/debug';
const ComposeSchema = {
...QuadSchema,
@@ -126,6 +127,7 @@ export class MultiSamplePass {
const { camera } = ctx;
const { compose, composeTarget, drawPass, webgl } = this;
const { gl, state } = webgl;
if (isTimingMode) webgl.timer.mark('MultiSamplePass.renderMultiSample');
// based on the Multisample Anti-Aliasing Render Pass
// contributed to three.js by bhouston / http://clara.io/
@@ -198,12 +200,14 @@ export class MultiSamplePass {
camera.viewOffset.enabled = false;
camera.update();
if (isTimingMode) webgl.timer.markEnd('MultiSamplePass.renderMultiSample');
}
private renderTemporalMultiSample(sampleIndex: number, ctx: RenderContext, props: Props, toDrawingBuffer: boolean) {
const { camera } = ctx;
const { compose, composeTarget, holdTarget, drawPass, webgl } = this;
const { gl, state } = webgl;
if (isTimingMode) webgl.timer.mark('MultiSamplePass.renderTemporalMultiSample');
// based on the Multisample Anti-Aliasing Render Pass
// contributed to three.js by bhouston / http://clara.io/
@@ -301,6 +305,7 @@ export class MultiSamplePass {
camera.viewOffset.enabled = false;
camera.update();
if (isTimingMode) webgl.timer.markEnd('MultiSamplePass.renderTemporalMultiSample');
return sampleIndex >= offsetList.length ? -2 : sampleIndex;
}

View File

@@ -7,10 +7,15 @@
import { PickingId } from '../../mol-geo/geometry/picking';
import { PickType, Renderer } from '../../mol-gl/renderer';
import { Scene } from '../../mol-gl/scene';
import { isWebGL2 } from '../../mol-gl/webgl/compat';
import { WebGLContext } from '../../mol-gl/webgl/context';
import { Framebuffer } from '../../mol-gl/webgl/framebuffer';
import { RenderTarget } from '../../mol-gl/webgl/render-target';
import { Renderbuffer } from '../../mol-gl/webgl/renderbuffer';
import { Texture } from '../../mol-gl/webgl/texture';
import { Vec3 } from '../../mol-math/linear-algebra';
import { spiral2d } from '../../mol-math/misc';
import { isTimingMode } from '../../mol-util/debug';
import { unpackRGBToInt, unpackRGBAToDepth } from '../../mol-util/number-packing';
import { Camera, ICamera } from '../camera';
import { StereoCamera } from '../camera/stereo';
@@ -24,10 +29,24 @@ const NullId = Math.pow(2, 24) - 2;
export type PickData = { id: PickingId, position: Vec3 }
export class PickPass {
readonly objectPickTarget: RenderTarget;
readonly instancePickTarget: RenderTarget;
readonly groupPickTarget: RenderTarget;
readonly depthPickTarget: RenderTarget;
private readonly objectPickTarget: RenderTarget;
private readonly instancePickTarget: RenderTarget;
private readonly groupPickTarget: RenderTarget;
private readonly depthPickTarget: RenderTarget;
private readonly framebuffer: Framebuffer;
private readonly objectPickTexture: Texture;
private readonly instancePickTexture: Texture;
private readonly groupPickTexture: Texture;
private readonly depthPickTexture: Texture;
private readonly objectPickFramebuffer: Framebuffer;
private readonly instancePickFramebuffer: Framebuffer;
private readonly groupPickFramebuffer: Framebuffer;
private readonly depthPickFramebuffer: Framebuffer;
private readonly depthRenderbuffer: Renderbuffer;
private pickWidth: number;
private pickHeight: number;
@@ -37,10 +56,89 @@ export class PickPass {
this.pickWidth = Math.ceil(drawPass.colorTarget.getWidth() * pickScale);
this.pickHeight = Math.ceil(drawPass.colorTarget.getHeight() * pickScale);
this.objectPickTarget = webgl.createRenderTarget(this.pickWidth, this.pickHeight);
this.instancePickTarget = webgl.createRenderTarget(this.pickWidth, this.pickHeight);
this.groupPickTarget = webgl.createRenderTarget(this.pickWidth, this.pickHeight);
this.depthPickTarget = webgl.createRenderTarget(this.pickWidth, this.pickHeight);
const { resources, extensions: { drawBuffers }, gl } = webgl;
if (drawBuffers) {
this.objectPickTexture = resources.texture('image-uint8', 'rgba', 'ubyte', 'nearest');
this.objectPickTexture.define(this.pickWidth, this.pickHeight);
this.instancePickTexture = resources.texture('image-uint8', 'rgba', 'ubyte', 'nearest');
this.instancePickTexture.define(this.pickWidth, this.pickHeight);
this.groupPickTexture = resources.texture('image-uint8', 'rgba', 'ubyte', 'nearest');
this.groupPickTexture.define(this.pickWidth, this.pickHeight);
this.depthPickTexture = resources.texture('image-uint8', 'rgba', 'ubyte', 'nearest');
this.depthPickTexture.define(this.pickWidth, this.pickHeight);
this.framebuffer = resources.framebuffer();
this.objectPickFramebuffer = resources.framebuffer();
this.instancePickFramebuffer = resources.framebuffer();
this.groupPickFramebuffer = resources.framebuffer();
this.depthPickFramebuffer = resources.framebuffer();
this.framebuffer.bind();
drawBuffers!.drawBuffers([
drawBuffers!.COLOR_ATTACHMENT0,
drawBuffers!.COLOR_ATTACHMENT1,
drawBuffers!.COLOR_ATTACHMENT2,
drawBuffers!.COLOR_ATTACHMENT3,
]);
this.objectPickTexture.attachFramebuffer(this.framebuffer, 'color0');
this.instancePickTexture.attachFramebuffer(this.framebuffer, 'color1');
this.groupPickTexture.attachFramebuffer(this.framebuffer, 'color2');
this.depthPickTexture.attachFramebuffer(this.framebuffer, 'color3');
this.depthRenderbuffer = isWebGL2(gl)
? resources.renderbuffer('depth32f', 'depth', this.pickWidth, this.pickHeight)
: resources.renderbuffer('depth16', 'depth', this.pickWidth, this.pickHeight);
this.depthRenderbuffer.attachFramebuffer(this.framebuffer);
this.objectPickTexture.attachFramebuffer(this.objectPickFramebuffer, 'color0');
this.instancePickTexture.attachFramebuffer(this.instancePickFramebuffer, 'color0');
this.groupPickTexture.attachFramebuffer(this.groupPickFramebuffer, 'color0');
this.depthPickTexture.attachFramebuffer(this.depthPickFramebuffer, 'color0');
} else {
this.objectPickTarget = webgl.createRenderTarget(this.pickWidth, this.pickHeight);
this.instancePickTarget = webgl.createRenderTarget(this.pickWidth, this.pickHeight);
this.groupPickTarget = webgl.createRenderTarget(this.pickWidth, this.pickHeight);
this.depthPickTarget = webgl.createRenderTarget(this.pickWidth, this.pickHeight);
}
}
bindObject() {
if (this.webgl.extensions.drawBuffers) {
this.objectPickFramebuffer.bind();
} else {
this.objectPickTarget.bind();
}
}
bindInstance() {
if (this.webgl.extensions.drawBuffers) {
this.instancePickFramebuffer.bind();
} else {
this.instancePickTarget.bind();
}
}
bindGroup() {
if (this.webgl.extensions.drawBuffers) {
this.groupPickFramebuffer.bind();
} else {
this.groupPickTarget.bind();
}
}
bindDepth() {
if (this.webgl.extensions.drawBuffers) {
this.depthPickFramebuffer.bind();
} else {
this.depthPickTarget.bind();
}
}
get drawingBufferHeight() {
@@ -56,19 +154,30 @@ export class PickPass {
this.pickWidth = pickWidth;
this.pickHeight = pickHeight;
this.objectPickTarget.setSize(this.pickWidth, this.pickHeight);
this.instancePickTarget.setSize(this.pickWidth, this.pickHeight);
this.groupPickTarget.setSize(this.pickWidth, this.pickHeight);
this.depthPickTarget.setSize(this.pickWidth, this.pickHeight);
if (this.webgl.extensions.drawBuffers) {
this.objectPickTexture.define(this.pickWidth, this.pickHeight);
this.instancePickTexture.define(this.pickWidth, this.pickHeight);
this.groupPickTexture.define(this.pickWidth, this.pickHeight);
this.depthPickTexture.define(this.pickWidth, this.pickHeight);
this.depthRenderbuffer.setSize(this.pickWidth, this.pickHeight);
} else {
this.objectPickTarget.setSize(this.pickWidth, this.pickHeight);
this.instancePickTarget.setSize(this.pickWidth, this.pickHeight);
this.groupPickTarget.setSize(this.pickWidth, this.pickHeight);
this.depthPickTarget.setSize(this.pickWidth, this.pickHeight);
}
}
}
private renderVariant(renderer: Renderer, camera: ICamera, scene: Scene, helper: Helper, variant: 'pick' | 'depth', pickType: number) {
renderer.clear(false);
renderer.update(camera);
renderer.renderPick(scene.primitives, camera, variant, null, pickType);
renderer.renderPick(helper.handle.scene, camera, variant, null, pickType);
if (helper.handle.isEnabled) {
renderer.renderPick(helper.handle.scene, camera, variant, null, pickType);
}
if (helper.camera.isEnabled) {
helper.camera.update(camera);
@@ -78,18 +187,23 @@ export class PickPass {
}
render(renderer: Renderer, camera: ICamera, scene: Scene, helper: Helper) {
this.objectPickTarget.bind();
this.renderVariant(renderer, camera, scene, helper, 'pick', PickType.Object);
if (this.webgl.extensions.drawBuffers) {
this.framebuffer.bind();
this.renderVariant(renderer, camera, scene, helper, 'pick', PickType.None);
} else {
this.objectPickTarget.bind();
this.renderVariant(renderer, camera, scene, helper, 'pick', PickType.Object);
this.instancePickTarget.bind();
this.renderVariant(renderer, camera, scene, helper, 'pick', PickType.Instance);
this.instancePickTarget.bind();
this.renderVariant(renderer, camera, scene, helper, 'pick', PickType.Instance);
this.groupPickTarget.bind();
this.renderVariant(renderer, camera, scene, helper, 'pick', PickType.Group);
// printTexture(this.webgl, this.groupPickTarget.texture, { id: 'group' })
this.groupPickTarget.bind();
this.renderVariant(renderer, camera, scene, helper, 'pick', PickType.Group);
// printTexture(this.webgl, this.groupPickTarget.texture, { id: 'group' })
this.depthPickTarget.bind();
this.renderVariant(renderer, camera, scene, helper, 'depth', PickType.None);
this.depthPickTarget.bind();
this.renderVariant(renderer, camera, scene, helper, 'depth', PickType.None);
}
}
}
@@ -144,19 +258,21 @@ export class PickHelper {
}
private syncBuffers() {
if (isTimingMode) this.webgl.timer.mark('PickHelper.syncBuffers');
const { pickX, pickY, pickWidth, pickHeight } = this;
this.pickPass.objectPickTarget.bind();
this.pickPass.bindObject();
this.webgl.readPixels(pickX, pickY, pickWidth, pickHeight, this.objectBuffer);
this.pickPass.instancePickTarget.bind();
this.pickPass.bindInstance();
this.webgl.readPixels(pickX, pickY, pickWidth, pickHeight, this.instanceBuffer);
this.pickPass.groupPickTarget.bind();
this.pickPass.bindGroup();
this.webgl.readPixels(pickX, pickY, pickWidth, pickHeight, this.groupBuffer);
this.pickPass.depthPickTarget.bind();
this.pickPass.bindDepth();
this.webgl.readPixels(pickX, pickY, pickWidth, pickHeight, this.depthBuffer);
if (isTimingMode) this.webgl.timer.markEnd('PickHelper.syncBuffers');
}
private getBufferIdx(x: number, y: number): number {
@@ -175,11 +291,12 @@ export class PickHelper {
}
private render(camera: Camera | StereoCamera) {
if (isTimingMode) this.webgl.timer.mark('PickHelper.render');
const { pickX, pickY, pickWidth, pickHeight, halfPickWidth } = this;
const { renderer, scene, helper } = this;
renderer.setTransparentBackground(false);
renderer.setDrawingBufferSize(this.pickPass.objectPickTarget.getWidth(), this.pickPass.objectPickTarget.getHeight());
renderer.setDrawingBufferSize(pickWidth, pickHeight);
renderer.setPixelRatio(this.pickScale);
if (StereoCamera.is(camera)) {
@@ -194,6 +311,7 @@ export class PickHelper {
}
this.dirty = false;
if (isTimingMode) this.webgl.timer.markEnd('PickHelper.render');
}
private identifyInternal(x: number, y: number, camera: Camera | StereoCamera): PickData | undefined {
@@ -214,8 +332,10 @@ export class PickHelper {
) return;
if (this.dirty) {
if (isTimingMode) this.webgl.timer.mark('PickHelper.identify');
this.render(camera);
this.syncBuffers();
if (isTimingMode) this.webgl.timer.markEnd('PickHelper.identify');
}
const xv = x - viewport.x;
@@ -237,6 +357,7 @@ export class PickHelper {
if (groupId === -1 || groupId === NullId) return;
const z = this.getDepth(xp, yp);
// console.log('z', z);
const position = Vec3.create(x, viewport.height - y, z);
if (StereoCamera.is(camera)) {
const halfWidth = Math.floor(viewport.width / 2);
@@ -251,7 +372,7 @@ export class PickHelper {
cameraUnproject(position, position, viewport, camera.inverseProjectionView);
}
// console.log({ { objectId, instanceId, groupId }, position} );
// console.log({ id: { objectId, instanceId, groupId }, position });
return { id: { objectId, instanceId, groupId }, position };
}

View File

@@ -27,6 +27,7 @@ import { Framebuffer } from '../../mol-gl/webgl/framebuffer';
import { Color } from '../../mol-util/color';
import { FxaaParams, FxaaPass } from './fxaa';
import { SmaaParams, SmaaPass } from './smaa';
import { isTimingMode } from '../../mol-util/debug';
const OutlinesSchema = {
...QuadSchema,
@@ -549,6 +550,7 @@ export class PostprocessingPass {
}
render(camera: ICamera, toDrawingBuffer: boolean, transparentBackground: boolean, backgroundColor: Color, props: PostprocessingProps) {
if (isTimingMode) this.webgl.timer.mark('PostprocessingPass.render');
this.updateState(camera, transparentBackground, backgroundColor, props);
if (props.outline.name === 'on') {
@@ -585,6 +587,7 @@ export class PostprocessingPass {
gl.clear(gl.COLOR_BUFFER_BIT);
this.renderable.render();
if (isTimingMode) this.webgl.timer.markEnd('PostprocessingPass.render');
}
}

View File

@@ -22,7 +22,7 @@ import { weights_frag } from '../../mol-gl/shader/smaa/weights.frag';
import { edges_vert } from '../../mol-gl/shader/smaa/edges.vert';
import { edges_frag } from '../../mol-gl/shader/smaa/edges.frag';
import { Viewport } from '../camera/util';
import { isDebugMode } from '../../mol-util/debug';
import { isDebugMode, isTimingMode } from '../../mol-util/debug';
export const SmaaParams = {
edgeThreshold: PD.Numeric(0.1, { min: 0.05, max: 0.15, step: 0.01 }),
@@ -120,6 +120,7 @@ export class SmaaPass {
}
render(viewport: Viewport, target: RenderTarget | undefined) {
if (isTimingMode) this.webgl.timer.mark('SmaaPass.render');
this.edgesTarget.bind();
this.updateState(viewport);
this.edgesRenderable.render();
@@ -135,8 +136,8 @@ export class SmaaPass {
}
this.updateState(viewport);
this.blendRenderable.render();
if (isTimingMode) this.webgl.timer.markEnd('SmaaPass.render');
}
}
//

View File

@@ -17,7 +17,7 @@ import { quad_vert } from '../../mol-gl/shader/quad.vert';
import { evaluateWboit_frag } from '../../mol-gl/shader/evaluate-wboit.frag';
import { Framebuffer } from '../../mol-gl/webgl/framebuffer';
import { Vec2 } from '../../mol-math/linear-algebra';
import { isDebugMode } from '../../mol-util/debug';
import { isDebugMode, isTimingMode } from '../../mol-util/debug';
const EvaluateWboitSchema = {
...QuadSchema,
@@ -71,6 +71,7 @@ export class WboitPass {
}
render() {
if (isTimingMode) this.webgl.timer.mark('WboitPass.render');
const { state, gl } = this.webgl;
state.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
@@ -78,6 +79,7 @@ export class WboitPass {
this.renderable.update();
this.renderable.render();
if (isTimingMode) this.webgl.timer.markEnd('WboitPass.render');
}
setSize(width: number, height: number) {

View File

@@ -20,6 +20,7 @@ import { accumulate_frag } from '../../../mol-gl/shader/compute/color-smoothing/
import { accumulate_vert } from '../../../mol-gl/shader/compute/color-smoothing/accumulate.vert';
import { isWebGL2 } from '../../../mol-gl/webgl/compat';
import { TextureMeshValues } from '../../../mol-gl/renderable/texture-mesh';
import { isTimingMode } from '../../../mol-util/debug';
export const ColorAccumulateSchema = {
drawCount: ValueSpec('number'),
@@ -255,6 +256,7 @@ export function calcTextureMeshColorSmoothing(input: ColorSmoothingInput, resolu
const { drawBuffers } = webgl.extensions;
if (!drawBuffers) throw new Error('need WebGL draw buffers');
if (isTimingMode) webgl.timer.mark('calcTextureMeshColorSmoothing');
const { gl, resources, state, extensions: { colorBufferHalfFloat, textureHalfFloat } } = webgl;
const isInstanceType = input.colorType.endsWith('Instance');
@@ -321,6 +323,7 @@ export function calcTextureMeshColorSmoothing(input: ColorSmoothingInput, resolu
const { uCurrentSlice, uCurrentX, uCurrentY } = accumulateRenderable.values;
if (isTimingMode) webgl.timer.mark('ColorAccumulate.render');
setAccumulateDefaults(webgl);
gl.viewport(0, 0, width, height);
gl.scissor(0, 0, width, height);
@@ -349,6 +352,7 @@ export function calcTextureMeshColorSmoothing(input: ColorSmoothingInput, resolu
accumulateTexture.detachFramebuffer(framebuffer, 0);
countTexture.detachFramebuffer(framebuffer, 1);
drawBuffers.drawBuffers([gl.COLOR_ATTACHMENT0, gl.NONE]);
if (isTimingMode) webgl.timer.markEnd('ColorAccumulate.render');
// const accImage = new Float32Array(width * height * 4);
// accumulateTexture.attachFramebuffer(framebuffer, 0);
@@ -364,6 +368,7 @@ export function calcTextureMeshColorSmoothing(input: ColorSmoothingInput, resolu
// normalize
if (isTimingMode) webgl.timer.mark('ColorNormalize.render');
if (!texture) texture = resources.texture('image-uint8', 'rgba', 'ubyte', 'linear');
texture.define(width, height);
@@ -376,6 +381,7 @@ export function calcTextureMeshColorSmoothing(input: ColorSmoothingInput, resolu
gl.scissor(0, 0, width, height);
gl.clear(gl.COLOR_BUFFER_BIT);
normalizeRenderable.render();
if (isTimingMode) webgl.timer.markEnd('ColorNormalize.render');
// const normImage = new Uint8Array(width * height * 4);
// texture.attachFramebuffer(framebuffer, 0);
@@ -385,6 +391,7 @@ export function calcTextureMeshColorSmoothing(input: ColorSmoothingInput, resolu
const gridTransform = Vec4.create(min[0], min[1], min[2], scaleFactor);
const type = isInstanceType ? 'volumeInstance' : 'volume';
if (isTimingMode) webgl.timer.markEnd('calcTextureMeshColorSmoothing');
return { texture, gridDim, gridTexDim: Vec2.create(width, height), gridTransform, type };
}

View File

@@ -1,5 +1,5 @@
/**
* 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>
*/
@@ -18,8 +18,9 @@ import { createComputeRenderItem } from '../webgl/render-item';
import { createComputeRenderable } from '../renderable';
import { isLittleEndian } from '../../mol-util/is-little-endian';
import { RuntimeContext } from '../../mol-task';
import { isTimingMode } from '../../mol-util/debug';
export function canComputeGrid3dOnGPU(webgl?: WebGLContext) {
export function canComputeGrid3dOnGPU(webgl?: WebGLContext): webgl is WebGLContext {
return !!webgl?.extensions.textureFloat;
}
@@ -159,7 +160,8 @@ export function createGrid3dComputeRenderable<S extends RenderableSchema, P, CS>
const array = new Uint8Array(uWidth * uWidth * 4);
if (spec.cumulative) {
const { gl } = webgl;
const { gl, state } = webgl;
if (isTimingMode) webgl.timer.mark('Grid3dCompute.renderCumulative');
const states = spec.cumulative.states(params);
@@ -167,7 +169,7 @@ export function createGrid3dComputeRenderable<S extends RenderableSchema, P, CS>
tex[1].define(uWidth, uWidth);
resetGl(webgl, uWidth);
gl.clearColor(0, 0, 0, 0);
state.clearColor(0, 0, 0, 0);
tex[0].attachFramebuffer(framebuffer, 'color0');
gl.clear(gl.COLOR_BUFFER_BIT);
@@ -175,12 +177,13 @@ export function createGrid3dComputeRenderable<S extends RenderableSchema, P, CS>
tex[1].attachFramebuffer(framebuffer, 'color0');
gl.clear(gl.COLOR_BUFFER_BIT);
if (spec.cumulative.yieldPeriod) {
if (spec.cumulative.yieldPeriod && !isTimingMode) {
await ctx.update({ message: 'Computing...', isIndeterminate: false, current: 0, max: states.length });
}
const yieldPeriod = Math.max(1, spec.cumulative.yieldPeriod ?? 1 | 0);
if (isTimingMode) webgl.timer.mark('Grid3dCompute.renderBatch');
for (let i = 0; i < states.length; i++) {
ValueCell.update(cells.tCumulativeSum, tex[(i + 1) % 2]);
tex[i % 2].attachFramebuffer(framebuffer, 'color0');
@@ -191,23 +194,31 @@ export function createGrid3dComputeRenderable<S extends RenderableSchema, P, CS>
if (spec.cumulative.yieldPeriod && i !== states.length - 1) {
if (i % yieldPeriod === yieldPeriod - 1) {
webgl.readPixels(0, 0, 1, 1, array);
webgl.waitForGpuCommandsCompleteSync();
if (isTimingMode) webgl.timer.markEnd('Grid3dCompute.renderBatch');
if (isTimingMode) webgl.timer.mark('Grid3dCompute.renderBatch');
}
if (ctx.shouldUpdate) {
if (ctx.shouldUpdate && !isTimingMode) {
await ctx.update({ current: i + 1 });
}
}
}
if (isTimingMode) webgl.timer.markEnd('Grid3dCompute.renderBatch');
if (isTimingMode) webgl.timer.markEnd('Grid3dCompute.renderCumulative');
} else {
if (isTimingMode) webgl.timer.mark('Grid3dCompute.render');
tex[0].define(uWidth, uWidth);
tex[0].attachFramebuffer(framebuffer, 'color0');
framebuffer.bind();
resetGl(webgl, uWidth);
renderable.update();
renderable.render();
if (isTimingMode) webgl.timer.markEnd('Grid3dCompute.render');
}
if (isTimingMode) webgl.timer.mark('Grid3dCompute.readPixels');
webgl.readPixels(0, 0, uWidth, uWidth, array);
if (isTimingMode) webgl.timer.markEnd('Grid3dCompute.readPixels');
return new Float32Array(array.buffer, array.byteOffset, nx * ny * nz);
};
}

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2019-2021 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>
*/
@@ -19,6 +19,7 @@ import { isPowerOfTwo } from '../../../mol-math/misc';
import { quad_vert } from '../../../mol-gl/shader/quad.vert';
import { reduction_frag } from '../../../mol-gl/shader/histogram-pyramid/reduction.frag';
import { isWebGL2 } from '../../webgl/compat';
import { isTimingMode } from '../../../mol-util/debug';
const HistopyramidReductionSchema = {
...QuadSchema,
@@ -120,6 +121,7 @@ export interface HistogramPyramid {
}
export function createHistogramPyramid(ctx: WebGLContext, inputTexture: Texture, scale: Vec2, gridTexDim: Vec3): HistogramPyramid {
if (isTimingMode) ctx.timer.mark('createHistogramPyramid');
const { gl } = ctx;
const w = inputTexture.getWidth();
const h = inputTexture.getHeight();
@@ -193,6 +195,7 @@ export function createHistogramPyramid(ctx: WebGLContext, inputTexture: Texture,
}
gl.finish();
if (isTimingMode) ctx.timer.markEnd('createHistogramPyramid');
// printTexture(ctx, pyramidTex, 2)

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2019-2021 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>
*/
@@ -16,6 +16,7 @@ import { QuadSchema, QuadValues } from '../util';
import { quad_vert } from '../../../mol-gl/shader/quad.vert';
import { sum_frag } from '../../../mol-gl/shader/histogram-pyramid/sum.frag';
import { isWebGL2 } from '../../webgl/compat';
import { isTimingMode } from '../../../mol-util/debug';
const HistopyramidSumSchema = {
...QuadSchema,
@@ -66,6 +67,7 @@ const sumBytes = new Uint8Array(4);
const sumInts = new Int32Array(4);
export function getHistopyramidSum(ctx: WebGLContext, pyramidTopTexture: Texture) {
if (isTimingMode) ctx.timer.mark('getHistopyramidSum');
const { gl, resources } = ctx;
const renderable = getHistopyramidSumRenderable(ctx, pyramidTopTexture);
@@ -93,6 +95,7 @@ export function getHistopyramidSum(ctx: WebGLContext, pyramidTopTexture: Texture
ctx.readPixels(0, 0, 1, 1, isWebGL2(gl) ? sumInts : sumBytes);
ctx.unbindFramebuffer();
if (isTimingMode) ctx.timer.markEnd('getHistopyramidSum');
return isWebGL2(gl)
? sumInts[0]

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2019-2021 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>
*/
@@ -16,6 +16,7 @@ import { QuadSchema, QuadValues } from '../util';
import { getTriCount } from './tables';
import { quad_vert } from '../../../mol-gl/shader/quad.vert';
import { activeVoxels_frag } from '../../../mol-gl/shader/marching-cubes/active-voxels.frag';
import { isTimingMode } from '../../../mol-util/debug';
const ActiveVoxelsSchema = {
...QuadSchema,
@@ -83,6 +84,7 @@ function setRenderingDefaults(ctx: WebGLContext) {
}
export function calcActiveVoxels(ctx: WebGLContext, volumeData: Texture, gridDim: Vec3, gridTexDim: Vec3, isoValue: number, gridScale: Vec2) {
if (isTimingMode) ctx.timer.mark('calcActiveVoxels');
const { gl, resources } = ctx;
const width = volumeData.getWidth();
const height = volumeData.getHeight();
@@ -115,6 +117,7 @@ export function calcActiveVoxels(ctx: WebGLContext, volumeData: Texture, gridDim
// console.log('at', readTexture(ctx, activeVoxelsTex));
gl.finish();
if (isTimingMode) ctx.timer.markEnd('calcActiveVoxels');
return activeVoxelsTex;
}

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2019-2021 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>
*/
@@ -19,6 +19,7 @@ import { quad_vert } from '../../../mol-gl/shader/quad.vert';
import { isosurface_frag } from '../../../mol-gl/shader/marching-cubes/isosurface.frag';
import { calcActiveVoxels } from './active-voxels';
import { isWebGL2 } from '../../webgl/compat';
import { isTimingMode } from '../../../mol-util/debug';
const IsosurfaceSchema = {
...QuadSchema,
@@ -122,6 +123,7 @@ export function createIsosurfaceBuffers(ctx: WebGLContext, activeVoxelsBase: Tex
const { drawBuffers } = ctx.extensions;
if (!drawBuffers) throw new Error('need WebGL draw buffers');
if (isTimingMode) ctx.timer.mark('createIsosurfaceBuffers');
const { gl, resources, extensions } = ctx;
const { pyramidTex, height, levels, scale, count } = histogramPyramid;
const width = pyramidTex.getWidth();
@@ -192,6 +194,7 @@ export function createIsosurfaceBuffers(ctx: WebGLContext, activeVoxelsBase: Tex
renderable.render();
gl.finish();
if (isTimingMode) ctx.timer.markEnd('createIsosurfaceBuffers');
return { vertexTexture, groupTexture, normalTexture, vertexCount: count };
}
@@ -208,20 +211,11 @@ export function createIsosurfaceBuffers(ctx: WebGLContext, activeVoxelsBase: Tex
* Implementation based on http://www.miaumiau.cat/2016/10/stream-compaction-in-webgl/
*/
export function extractIsosurface(ctx: WebGLContext, volumeData: Texture, gridDim: Vec3, gridTexDim: Vec3, gridTexScale: Vec2, transform: Mat4, isoValue: number, invert: boolean, packedGroup: boolean, axisOrder: Vec3, vertexTexture?: Texture, groupTexture?: Texture, normalTexture?: Texture) {
// console.time('calcActiveVoxels');
if (isTimingMode) ctx.timer.mark('extractIsosurface');
const activeVoxelsTex = calcActiveVoxels(ctx, volumeData, gridDim, gridTexDim, isoValue, gridTexScale);
// ctx.waitForGpuCommandsCompleteSync();
// console.timeEnd('calcActiveVoxels');
// console.time('createHistogramPyramid');
const compacted = createHistogramPyramid(ctx, activeVoxelsTex, gridTexScale, gridTexDim);
// ctx.waitForGpuCommandsCompleteSync();
// console.timeEnd('createHistogramPyramid');
// console.time('createIsosurfaceBuffers');
const gv = createIsosurfaceBuffers(ctx, activeVoxelsTex, volumeData, compacted, gridDim, gridTexDim, transform, isoValue, invert, packedGroup, axisOrder, vertexTexture, groupTexture, normalTexture);
// ctx.waitForGpuCommandsCompleteSync();
// console.timeEnd('createIsosurfaceBuffers');
if (isTimingMode) ctx.timer.markEnd('extractIsosurface');
return gv;
}

View File

@@ -19,6 +19,7 @@ import { degToRad } from '../mol-math/misc';
import { Texture, Textures } from './webgl/texture';
import { arrayMapUpsert } from '../mol-util/array';
import { clamp } from '../mol-math/interpolate';
import { isTimingMode } from '../mol-util/debug';
export interface RendererStats {
programCount: number
@@ -360,6 +361,7 @@ namespace Renderer {
};
const renderPick = (group: Scene.Group, camera: ICamera, variant: GraphicsRenderVariant, depthTexture: Texture | null, pickType: PickType) => {
if (isTimingMode) ctx.timer.mark('Renderer.renderPick');
state.disable(gl.BLEND);
state.enable(gl.DEPTH_TEST);
state.depthMask(true);
@@ -373,9 +375,11 @@ namespace Renderer {
renderObject(renderables[i], variant, Flag.None);
}
}
if (isTimingMode) ctx.timer.markEnd('Renderer.renderPick');
};
const renderDepth = (group: Scene.Group, camera: ICamera, depthTexture: Texture | null) => {
if (isTimingMode) ctx.timer.mark('Renderer.renderDepth');
state.disable(gl.BLEND);
state.enable(gl.DEPTH_TEST);
state.depthMask(true);
@@ -386,9 +390,11 @@ namespace Renderer {
for (let i = 0, il = renderables.length; i < il; ++i) {
renderObject(renderables[i], 'depth', Flag.None);
}
if (isTimingMode) ctx.timer.markEnd('Renderer.renderDepth');
};
const renderDepthOpaque = (group: Scene.Group, camera: ICamera, depthTexture: Texture | null) => {
if (isTimingMode) ctx.timer.mark('Renderer.renderDepthOpaque');
state.disable(gl.BLEND);
state.enable(gl.DEPTH_TEST);
state.depthMask(true);
@@ -402,9 +408,11 @@ namespace Renderer {
renderObject(r, 'depth', Flag.None);
}
}
if (isTimingMode) ctx.timer.markEnd('Renderer.renderDepthOpaque');
};
const renderDepthTransparent = (group: Scene.Group, camera: ICamera, depthTexture: Texture | null) => {
if (isTimingMode) ctx.timer.mark('Renderer.renderDepthTransparent');
state.disable(gl.BLEND);
state.enable(gl.DEPTH_TEST);
state.depthMask(true);
@@ -418,9 +426,11 @@ namespace Renderer {
renderObject(r, 'depth', Flag.None);
}
}
if (isTimingMode) ctx.timer.markEnd('Renderer.renderDepthTransparent');
};
const renderMarkingDepth = (group: Scene.Group, camera: ICamera, depthTexture: Texture | null) => {
if (isTimingMode) ctx.timer.mark('Renderer.renderMarkingDepth');
state.disable(gl.BLEND);
state.enable(gl.DEPTH_TEST);
state.depthMask(true);
@@ -436,9 +446,11 @@ namespace Renderer {
renderObject(renderables[i], 'marking', Flag.None);
}
}
if (isTimingMode) ctx.timer.markEnd('Renderer.renderMarkingDepth');
};
const renderMarkingMask = (group: Scene.Group, camera: ICamera, depthTexture: Texture | null) => {
if (isTimingMode) ctx.timer.mark('Renderer.renderMarkingMask');
state.disable(gl.BLEND);
state.enable(gl.DEPTH_TEST);
state.depthMask(true);
@@ -454,6 +466,7 @@ namespace Renderer {
renderObject(renderables[i], 'marking', Flag.None);
}
}
if (isTimingMode) ctx.timer.markEnd('Renderer.renderMarkingMask');
};
const renderBlended = (group: Scene.Group, camera: ICamera, depthTexture: Texture | null) => {
@@ -462,6 +475,7 @@ namespace Renderer {
};
const renderBlendedOpaque = (group: Scene.Group, camera: ICamera, depthTexture: Texture | null) => {
if (isTimingMode) ctx.timer.mark('Renderer.renderBlendedOpaque');
state.disable(gl.BLEND);
state.enable(gl.DEPTH_TEST);
state.depthMask(true);
@@ -477,9 +491,11 @@ namespace Renderer {
renderObject(r, 'colorBlended', Flag.BlendedBack);
}
}
if (isTimingMode) ctx.timer.markEnd('Renderer.renderBlendedOpaque');
};
const renderBlendedTransparent = (group: Scene.Group, camera: ICamera, depthTexture: Texture | null) => {
if (isTimingMode) ctx.timer.mark('Renderer.renderBlendedTransparent');
state.enable(gl.DEPTH_TEST);
updateInternal(group, camera, depthTexture, Mask.Transparent, false);
@@ -516,9 +532,11 @@ namespace Renderer {
}
}
}
if (isTimingMode) ctx.timer.markEnd('Renderer.renderBlendedTransparent');
};
const renderBlendedVolume = (group: Scene.Group, camera: ICamera, depthTexture: Texture | null) => {
if (isTimingMode) ctx.timer.mark('Renderer.renderBlendedVolume');
state.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
state.enable(gl.BLEND);
@@ -531,9 +549,11 @@ namespace Renderer {
renderObject(r, 'colorBlended', Flag.None);
}
}
if (isTimingMode) ctx.timer.markEnd('Renderer.renderBlendedVolume');
};
const renderWboitOpaque = (group: Scene.Group, camera: ICamera, depthTexture: Texture | null) => {
if (isTimingMode) ctx.timer.mark('Renderer.renderWboitOpaque');
state.disable(gl.BLEND);
state.enable(gl.DEPTH_TEST);
state.depthMask(true);
@@ -551,9 +571,11 @@ namespace Renderer {
renderObject(r, 'colorWboit', Flag.None);
}
}
if (isTimingMode) ctx.timer.markEnd('Renderer.renderWboitOpaque');
};
const renderWboitTransparent = (group: Scene.Group, camera: ICamera, depthTexture: Texture | null) => {
if (isTimingMode) ctx.timer.mark('Renderer.renderWboitTransparent');
updateInternal(group, camera, depthTexture, Mask.Transparent, false);
const { renderables } = group;
@@ -567,6 +589,7 @@ namespace Renderer {
renderObject(r, 'colorWboit', Flag.None);
}
}
if (isTimingMode) ctx.timer.markEnd('Renderer.renderWboitTransparent');
};
return {

View File

@@ -258,6 +258,8 @@ namespace Scene {
renderables[i].dispose();
}
renderables.length = 0;
primitives.length = 0;
volumes.length = 0;
renderableMap.clear();
boundingSphereDirty = true;
boundingSphereVisibleDirty = true;

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2018-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
@@ -236,6 +236,18 @@ function getDefinesCode(defines: ShaderDefines, ignore?: IgnoreDefine) {
return lines.join('\n') + '\n';
}
function getGlsl100VertPrefix(extensions: WebGLExtensions, shaderExtensions: ShaderExtensions) {
const prefix: string[] = [];
if (shaderExtensions.drawBuffers) {
if (extensions.drawBuffers) {
prefix.push('#define requiredDrawBuffers');
} else if (shaderExtensions.drawBuffers === 'required') {
throw new Error(`required 'GL_EXT_draw_buffers' extension not available`);
}
}
return prefix.join('\n') + '\n';
}
function getGlsl100FragPrefix(extensions: WebGLExtensions, shaderExtensions: ShaderExtensions) {
const prefix: string[] = [
'#extension GL_OES_standard_derivatives : enable'
@@ -271,7 +283,7 @@ function getGlsl100FragPrefix(extensions: WebGLExtensions, shaderExtensions: Sha
return prefix.join('\n') + '\n';
}
const glsl300VertPrefix = `#version 300 es
const glsl300VertPrefixCommon = `
#define attribute in
#define varying out
#define texture2D texture
@@ -288,24 +300,42 @@ const glsl300FragPrefixCommon = `
#define depthTextureSupport
`;
function getGlsl300VertPrefix(extensions: WebGLExtensions, shaderExtensions: ShaderExtensions) {
const prefix = [
'#version 300 es',
];
if (shaderExtensions.drawBuffers) {
if (extensions.drawBuffers) {
prefix.push('#define requiredDrawBuffers');
}
}
prefix.push(glsl300VertPrefixCommon);
return prefix.join('\n') + '\n';
}
function getGlsl300FragPrefix(gl: WebGL2RenderingContext, extensions: WebGLExtensions, shaderExtensions: ShaderExtensions, outTypes: FragOutTypes) {
const prefix = [
'#version 300 es',
`layout(location = 0) out highp ${outTypes[0] || 'vec4'} out_FragData0;`
];
if (shaderExtensions.fragDepth) {
prefix.push('#define enabledFragDepth');
if (extensions.fragDepth) {
prefix.push('#define enabledFragDepth');
}
}
if (shaderExtensions.drawBuffers) {
prefix.push('#define requiredDrawBuffers');
const maxDrawBuffers = gl.getParameter(gl.MAX_DRAW_BUFFERS) as number;
for (let i = 1, il = maxDrawBuffers; i < il; ++i) {
prefix.push(`layout(location = ${i}) out highp ${outTypes[i] || 'vec4'} out_FragData${i};`);
if (extensions.drawBuffers) {
prefix.push('#define requiredDrawBuffers');
const maxDrawBuffers = gl.getParameter(gl.MAX_DRAW_BUFFERS) as number;
for (let i = 1, il = maxDrawBuffers; i < il; ++i) {
prefix.push(`layout(location = ${i}) out highp ${outTypes[i] || 'vec4'} out_FragData${i};`);
}
}
}
if (shaderExtensions.shaderTextureLod) {
prefix.push('#define enabledShaderTextureLod');
if (extensions.shaderTextureLod) {
prefix.push('#define enabledShaderTextureLod');
}
}
prefix.push(glsl300FragPrefixCommon);
return prefix.join('\n') + '\n';
@@ -318,7 +348,9 @@ function transformGlsl300Frag(frag: string) {
export function addShaderDefines(gl: GLRenderingContext, extensions: WebGLExtensions, defines: ShaderDefines, shaders: ShaderCode): ShaderCode {
const vertHeader = getDefinesCode(defines, shaders.ignoreDefine);
const fragHeader = getDefinesCode(defines, shaders.ignoreDefine);
const vertPrefix = isWebGL2(gl) ? glsl300VertPrefix : '';
const vertPrefix = isWebGL2(gl)
? getGlsl300VertPrefix(extensions, shaders.extensions)
: getGlsl100VertPrefix(extensions, shaders.extensions);
const fragPrefix = isWebGL2(gl)
? getGlsl300FragPrefix(gl, extensions, shaders.extensions, shaders.outTypes)
: getGlsl100FragPrefix(extensions, shaders.extensions);

View File

@@ -56,13 +56,19 @@ export const assign_color_varying = `
vSubstance.rgb = mix(vec3(uMetalness, uRoughness, uBumpiness), vSubstance.rgb, vSubstance.a);
#endif
#elif defined(dRenderVariant_pick)
if (uPickType == 1) {
vColor = vec4(packIntToRGB(float(uObjectId)), 1.0);
} else if (uPickType == 2) {
vColor = vec4(packIntToRGB(aInstance), 1.0);
} else {
vColor = vec4(packIntToRGB(group), 1.0);
}
#ifdef requiredDrawBuffers
vObject = vec4(packIntToRGB(float(uObjectId)), 1.0);
vInstance = vec4(packIntToRGB(aInstance), 1.0);
vGroup = vec4(packIntToRGB(group), 1.0);
#else
if (uPickType == 1) {
vColor = vec4(packIntToRGB(float(uObjectId)), 1.0);
} else if (uPickType == 2) {
vColor = vec4(packIntToRGB(aInstance), 1.0);
} else {
vColor = vec4(packIntToRGB(group), 1.0);
}
#endif
#endif
#ifdef dTransparency

View File

@@ -28,8 +28,6 @@ export const assign_material_color = `
roughness = mix(roughness, vSubstance.g, vSubstance.a);
bumpiness = mix(bumpiness, vSubstance.b, vSubstance.a);
#endif
#elif defined(dRenderVariant_pick)
vec4 material = vColor;
#elif defined(dRenderVariant_depth)
if (fragmentDepth > getDepth(gl_FragCoord.xy / uDrawingBufferSize)) {
discard;

View File

@@ -28,9 +28,21 @@ uniform float uBumpiness;
#endif
#elif defined(dRenderVariant_pick)
#if __VERSION__ == 100
varying vec4 vColor;
#ifdef requiredDrawBuffers
varying vec4 vObject;
varying vec4 vInstance;
varying vec4 vGroup;
#else
varying vec4 vColor;
#endif
#else
flat in vec4 vColor;
#ifdef requiredDrawBuffers
flat in vec4 vObject;
flat in vec4 vInstance;
flat in vec4 vGroup;
#else
flat in vec4 vColor;
#endif
#endif
#endif

View File

@@ -56,9 +56,21 @@ uniform float uBumpiness;
#endif
#elif defined(dRenderVariant_pick)
#if __VERSION__ == 100
varying vec4 vColor;
#ifdef requiredDrawBuffers
varying vec4 vObject;
varying vec4 vInstance;
varying vec4 vGroup;
#else
varying vec4 vColor;
#endif
#else
flat out vec4 vColor;
#ifdef requiredDrawBuffers
flat out vec4 vObject;
flat out vec4 vInstance;
flat out vec4 vGroup;
#else
flat out vec4 vColor;
#endif
#endif
#endif

View File

@@ -121,7 +121,14 @@ void main() {
#if defined(dRenderVariant_pick)
#include check_picking_alpha
gl_FragColor = material;
#ifdef requiredDrawBuffers
gl_FragColor = vObject;
gl_FragData[1] = vInstance;
gl_FragData[2] = vGroup;
gl_FragData[3] = packDepthToRGBA(fragmentDepth);
#else
gl_FragColor = vColor;
#endif
#elif defined(dRenderVariant_depth)
gl_FragColor = material;
#elif defined(dRenderVariant_marking)

View File

@@ -68,7 +68,6 @@ uniform float uFogFar;
uniform vec3 uFogColor;
uniform float uAlpha;
uniform float uPickingAlphaThreshold;
uniform bool uTransparentBackground;
uniform float uXrayEdgeFalloff;

View File

@@ -103,13 +103,21 @@ void main() {
#if defined(dRenderVariant_pick)
if (imageData.a < 0.3)
discard;
if (uPickType == 1) {
#ifdef requiredDrawBuffers
gl_FragColor = vec4(packIntToRGB(float(uObjectId)), 1.0);
} else if (uPickType == 2) {
gl_FragColor = vec4(packIntToRGB(vInstance), 1.0);
} else {
gl_FragColor = vec4(texture2D(tGroupTex, vUv).rgb, 1.0);
}
gl_FragData[1] = vec4(packIntToRGB(vInstance), 1.0);
gl_FragData[2] = vec4(texture2D(tGroupTex, vUv).rgb, 1.0);
gl_FragData[3] = packDepthToRGBA(gl_FragCoord.z);
#else
gl_FragColor = vColor;
if (uPickType == 1) {
gl_FragColor = vec4(packIntToRGB(float(uObjectId)), 1.0);
} else if (uPickType == 2) {
gl_FragColor = vec4(packIntToRGB(vInstance), 1.0);
} else {
gl_FragColor = vec4(texture2D(tGroupTex, vUv).rgb, 1.0);
}
#endif
#elif defined(dRenderVariant_depth)
if (imageData.a < 0.05)
discard;

View File

@@ -21,7 +21,14 @@ void main(){
#if defined(dRenderVariant_pick)
#include check_picking_alpha
gl_FragColor = material;
#ifdef requiredDrawBuffers
gl_FragColor = vObject;
gl_FragData[1] = vInstance;
gl_FragData[2] = vGroup;
gl_FragData[3] = packDepthToRGBA(fragmentDepth);
#else
gl_FragColor = vColor;
#endif
#elif defined(dRenderVariant_depth)
gl_FragColor = material;
#elif defined(dRenderVariant_marking)

View File

@@ -37,7 +37,14 @@ void main() {
#if defined(dRenderVariant_pick)
#include check_picking_alpha
gl_FragColor = material;
#ifdef requiredDrawBuffers
gl_FragColor = vObject;
gl_FragData[1] = vInstance;
gl_FragData[2] = vGroup;
gl_FragData[3] = packDepthToRGBA(fragmentDepth);
#else
gl_FragColor = vColor;
#endif
#elif defined(dRenderVariant_depth)
gl_FragColor = material;
#elif defined(dRenderVariant_marking)

View File

@@ -33,7 +33,14 @@ void main(){
#if defined(dRenderVariant_pick)
#include check_picking_alpha
gl_FragColor = material;
#ifdef requiredDrawBuffers
gl_FragColor = vObject;
gl_FragData[1] = vInstance;
gl_FragData[2] = vGroup;
gl_FragData[3] = packDepthToRGBA(fragmentDepth);
#else
gl_FragColor = vColor;
#endif
#elif defined(dRenderVariant_depth)
gl_FragColor = material;
#elif defined(dRenderVariant_marking)

View File

@@ -86,7 +86,14 @@ void main(void){
#if defined(dRenderVariant_pick)
#include check_picking_alpha
gl_FragColor = material;
#ifdef requiredDrawBuffers
gl_FragColor = vObject;
gl_FragData[1] = vInstance;
gl_FragData[2] = vGroup;
gl_FragData[3] = packDepthToRGBA(fragmentDepth);
#else
gl_FragColor = vColor;
#endif
#elif defined(dRenderVariant_depth)
gl_FragColor = material;
#elif defined(dRenderVariant_marking)

View File

@@ -36,7 +36,9 @@ void main(){
#include assign_material_color
if (vTexCoord.x > 1.0) {
gl_FragColor = vec4(uBackgroundColor, uBackgroundOpacity * material.a);
#if defined(dRenderVariant_color)
material = vec4(uBackgroundColor, uBackgroundOpacity * material.a);
#endif
} else {
// retrieve signed distance
float sdf = texture2D(tFont, vTexCoord).a + uBorderWidth;
@@ -49,24 +51,35 @@ void main(){
a = pow(a, 1.0 / gamma);
if (a < 0.5) discard;
material.a *= a;
// add border
float t = 0.5 + uBorderWidth;
if (uBorderWidth > 0.0 && sdf < t) {
material.xyz = mix(uBorderColor, material.xyz, smoothstep(t - w, t, sdf));
}
#if defined(dRenderVariant_color)
material.a *= a;
gl_FragColor = material;
// add border
float t = 0.5 + uBorderWidth;
if (uBorderWidth > 0.0 && sdf < t) {
material.xyz = mix(uBorderColor, material.xyz, smoothstep(t - w, t, sdf));
}
#endif
}
#if defined(dRenderVariant_pick)
#include check_picking_alpha
#ifdef requiredDrawBuffers
gl_FragColor = vObject;
gl_FragData[1] = vInstance;
gl_FragData[2] = vGroup;
gl_FragData[3] = packDepthToRGBA(fragmentDepth);
#else
gl_FragColor = vColor;
#endif
#elif defined(dRenderVariant_depth)
gl_FragColor = material;
#elif defined(dRenderVariant_marking)
gl_FragColor = material;
#elif defined(dRenderVariant_color)
gl_FragColor = material;
#include apply_marker_color
#include apply_fog
#include wboit_write

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2018-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
@@ -320,6 +320,87 @@ export function getSRGB(gl: GLRenderingContext): COMPAT_sRGB | null {
}
}
export interface COMPAT_disjoint_timer_query {
/** A GLint indicating the number of bits used to hold the query result for the given target. */
QUERY_COUNTER_BITS: number
/** A WebGLQuery object, which is the currently active query for the given target. */
CURRENT_QUERY: number
/** A GLuint64EXT containing the query result. */
QUERY_RESULT: number
/** A GLboolean indicating whether or not a query result is available. */
QUERY_RESULT_AVAILABLE: number
/** Elapsed time (in nanoseconds). */
TIME_ELAPSED: number
/** The current time. */
TIMESTAMP: number
/** A GLboolean indicating whether or not the GPU performed any disjoint operation. */
GPU_DISJOINT: number
/** Creates a new WebGLTimerQueryEXT. */
createQuery: () => WebGLQuery
/** Deletes a given WebGLTimerQueryEXT. */
deleteQuery: (query: WebGLQuery) => void
/** Returns true if a given object is a valid WebGLTimerQueryEXT. */
isQuery: (query: WebGLQuery) => boolean
/** The timer starts when all commands prior to beginQueryEXT have been fully executed. */
beginQuery: (target: number, query: WebGLQuery) => void
/** The timer stops when all commands prior to endQueryEXT have been fully executed. */
endQuery: (target: number) => void
/** Records the current time into the corresponding query object. */
queryCounter: (query: WebGLQuery, target: number) => void
/** Returns information about a query target. */
getQuery: (target: number, pname: number) => WebGLQuery | number
/** Return the state of a query object. */
getQueryParameter: (query: WebGLQuery, pname: number) => number | boolean
}
export function getDisjointTimerQuery(gl: GLRenderingContext): COMPAT_disjoint_timer_query | null {
if (isWebGL2(gl)) {
// Firefox has EXT_disjoint_timer_query in webgl2
const ext = gl.getExtension('EXT_disjoint_timer_query_webgl2') || gl.getExtension('EXT_disjoint_timer_query');
if (ext === null) return null;
return {
QUERY_COUNTER_BITS: ext.QUERY_COUNTER_BITS_EXT,
CURRENT_QUERY: gl.CURRENT_QUERY,
QUERY_RESULT: gl.QUERY_RESULT,
QUERY_RESULT_AVAILABLE: gl.QUERY_RESULT_AVAILABLE,
TIME_ELAPSED: ext.TIME_ELAPSED_EXT,
TIMESTAMP: ext.TIMESTAMP_EXT,
GPU_DISJOINT: ext.GPU_DISJOINT_EXT,
createQuery: gl.createQuery.bind(gl),
deleteQuery: gl.deleteQuery.bind(gl),
isQuery: gl.isQuery.bind(gl),
beginQuery: gl.beginQuery.bind(gl),
endQuery: gl.endQuery.bind(gl),
queryCounter: ext.queryCounterEXT.bind(ext),
getQuery: gl.getQuery.bind(gl),
getQueryParameter: gl.getQueryParameter.bind(gl),
};
} else {
const ext = gl.getExtension('EXT_disjoint_timer_query');
if (ext === null) return null;
return {
QUERY_COUNTER_BITS: ext.QUERY_COUNTER_BITS_EXT,
CURRENT_QUERY: ext.CURRENT_QUERY_EXT,
QUERY_RESULT: ext.QUERY_RESULT_EXT,
QUERY_RESULT_AVAILABLE: ext.QUERY_RESULT_AVAILABLE_EXT,
TIME_ELAPSED: ext.TIME_ELAPSED_EXT,
TIMESTAMP: ext.TIMESTAMP_EXT,
GPU_DISJOINT: ext.GPU_DISJOINT_EXT,
createQuery: ext.createQueryEXT.bind(ext),
deleteQuery: ext.deleteQueryEXT.bind(ext),
isQuery: ext.isQueryEXT.bind(ext),
beginQuery: ext.beginQueryEXT.bind(ext),
endQuery: ext.endQueryEXT.bind(ext),
queryCounter: ext.queryCounterEXT.bind(ext),
getQuery: ext.getQueryEXT.bind(ext),
getQueryParameter: ext.getQueryObjectEXT.bind(ext),
};
}
}
//
const TextureTestVertShader = `

View File

@@ -17,6 +17,7 @@ import { BehaviorSubject } from 'rxjs';
import { now } from '../../mol-util/now';
import { Texture, TextureFilter } from './texture';
import { ComputeRenderable } from '../renderable';
import { createTimer, WebGLTimer } from './timer';
export function getGLContext(canvas: HTMLCanvasElement, attribs?: WebGLContextAttributes & { preferWebGl1?: boolean }): GLRenderingContext | null {
function get(id: 'webgl' | 'experimental-webgl' | 'webgl2') {
@@ -186,6 +187,7 @@ export interface WebGLContext {
readonly state: WebGLState
readonly stats: WebGLStats
readonly resources: WebGLResources
readonly timer: WebGLTimer
readonly maxTextureSize: number
readonly max3dTextureSize: number
@@ -221,6 +223,7 @@ export function createContext(gl: GLRenderingContext, props: Partial<{ pixelScal
const state = createState(gl);
const stats = createStats();
const resources = createResources(gl, state, stats, extensions);
const timer = createTimer(gl, extensions);
const parameters = {
maxTextureSize: gl.getParameter(gl.MAX_TEXTURE_SIZE) as number,
@@ -289,6 +292,7 @@ export function createContext(gl: GLRenderingContext, props: Partial<{ pixelScal
state,
stats,
resources,
timer,
get maxTextureSize() { return parameters.maxTextureSize; },
get max3dTextureSize() { return parameters.max3dTextureSize; },

View File

@@ -1,10 +1,10 @@
/**
* Copyright (c) 2018-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { GLRenderingContext, COMPAT_instanced_arrays, COMPAT_standard_derivatives, COMPAT_vertex_array_object, getInstancedArrays, getStandardDerivatives, COMPAT_element_index_uint, getElementIndexUint, COMPAT_texture_float, getTextureFloat, COMPAT_texture_float_linear, getTextureFloatLinear, COMPAT_blend_minmax, getBlendMinMax, getFragDepth, COMPAT_frag_depth, COMPAT_color_buffer_float, getColorBufferFloat, COMPAT_draw_buffers, getDrawBuffers, getShaderTextureLod, COMPAT_shader_texture_lod, getDepthTexture, COMPAT_depth_texture, COMPAT_sRGB, getSRGB, getTextureHalfFloat, getTextureHalfFloatLinear, COMPAT_texture_half_float, COMPAT_texture_half_float_linear, COMPAT_color_buffer_half_float, getColorBufferHalfFloat, getVertexArrayObject } from './compat';
import { GLRenderingContext, COMPAT_instanced_arrays, COMPAT_standard_derivatives, COMPAT_vertex_array_object, getInstancedArrays, getStandardDerivatives, COMPAT_element_index_uint, getElementIndexUint, COMPAT_texture_float, getTextureFloat, COMPAT_texture_float_linear, getTextureFloatLinear, COMPAT_blend_minmax, getBlendMinMax, getFragDepth, COMPAT_frag_depth, COMPAT_color_buffer_float, getColorBufferFloat, COMPAT_draw_buffers, getDrawBuffers, getShaderTextureLod, COMPAT_shader_texture_lod, getDepthTexture, COMPAT_depth_texture, COMPAT_sRGB, getSRGB, getTextureHalfFloat, getTextureHalfFloatLinear, COMPAT_texture_half_float, COMPAT_texture_half_float_linear, COMPAT_color_buffer_half_float, getColorBufferHalfFloat, getVertexArrayObject, getDisjointTimerQuery, COMPAT_disjoint_timer_query } from './compat';
import { isDebugMode } from '../../mol-util/debug';
export type WebGLExtensions = {
@@ -25,6 +25,7 @@ export type WebGLExtensions = {
drawBuffers: COMPAT_draw_buffers | null
shaderTextureLod: COMPAT_shader_texture_lod | null
sRGB: COMPAT_sRGB | null
disjointTimerQuery: COMPAT_disjoint_timer_query | null
}
export function createExtensions(gl: GLRenderingContext): WebGLExtensions {
@@ -99,6 +100,10 @@ export function createExtensions(gl: GLRenderingContext): WebGLExtensions {
if (isDebugMode && sRGB === null) {
console.log('Could not find support for "sRGB"');
}
const disjointTimerQuery = getDisjointTimerQuery(gl);
if (isDebugMode && disjointTimerQuery === null) {
console.log('Could not find support for "disjoint_timer_query"');
}
return {
instancedArrays,
@@ -118,5 +123,6 @@ export function createExtensions(gl: GLRenderingContext): WebGLExtensions {
drawBuffers,
shaderTextureLod,
sRGB,
disjointTimerQuery,
};
}

194
src/mol-gl/webgl/timer.ts Normal file
View File

@@ -0,0 +1,194 @@
/**
* Copyright (c) 2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { GLRenderingContext } from './compat';
import { WebGLExtensions } from './extensions';
export type TimerResult = {
readonly label: string
readonly timeElapsed: number
readonly children: TimerResult[]
}
function getQuery(extensions: WebGLExtensions) {
return extensions.disjointTimerQuery ? extensions.disjointTimerQuery.createQuery() : null;
}
export type WebGLTimer = {
/** Check with GPU for finished timers. */
resolve: () => TimerResult[]
mark: (label: string) => void
markEnd: (label: string) => void
clear: () => void
destroy: () => void
}
type Measure = { label: string, queries: WebGLQuery[], children: Measure[], root: boolean, timeElapsed?: number };
type QueryResult = { timeElapsed?: number, refCount: number };
export function createTimer(gl: GLRenderingContext, extensions: WebGLExtensions): WebGLTimer {
const dtq = extensions.disjointTimerQuery;
const queries = new Map<WebGLQuery, QueryResult>();
const pending = new Map<string, Measure>();
const stack: Measure[] = [];
let measures: Measure[] = [];
let current: WebGLQuery | null = null;
const clear = () => {
if (!dtq) return;
queries.forEach((_, query) => {
dtq.deleteQuery(query);
});
pending.clear();
measures = [];
current = null;
};
const add = () => {
if (!dtq) return;
const query = getQuery(extensions);
if (!query) return;
dtq.beginQuery(dtq.TIME_ELAPSED, query);
pending.forEach((measure, _) => {
measure.queries.push(query);
});
queries.set(query, { refCount: pending.size });
current = query;
};
return {
resolve: () => {
const results: TimerResult[] = [];
if (!dtq || !measures.length) return results;
// console.log('resolve');
queries.forEach((result, query) => {
if (result.timeElapsed !== undefined) return;
const available = dtq.getQueryParameter(query, dtq.QUERY_RESULT_AVAILABLE);
const disjoint = gl.getParameter(dtq.GPU_DISJOINT);
if (available && !disjoint) {
const timeElapsed = dtq.getQueryParameter(query, dtq.QUERY_RESULT) as number;
result.timeElapsed = timeElapsed;
// console.log('timeElapsed', result.timeElapsed);
}
if (available || disjoint) {
dtq.deleteQuery(query);
}
});
const unresolved: Measure[] = [];
for (const measure of measures) {
if (measure.queries.every(q => queries.get(q)?.timeElapsed !== undefined)) {
let timeElapsed = 0;
for (const query of measure.queries) {
const result = queries.get(query)!;
timeElapsed += result.timeElapsed!;
result.refCount -= 1;
}
measure.timeElapsed = timeElapsed;
if (measure.root) {
const children: TimerResult[] = [];
const add = (measures: Measure[], children: TimerResult[]) => {
for (const measure of measures) {
const result: TimerResult = {
label: measure.label,
timeElapsed: measure.timeElapsed!,
children: []
};
children.push(result);
add(measure.children, result.children);
}
};
add(measure.children, children);
results.push({ label: measure.label, timeElapsed, children });
}
} else {
unresolved.push(measure);
}
}
measures = unresolved;
queries.forEach((result, query) => {
if (result.refCount === 0) {
queries.delete(query);
}
});
return results;
},
mark: (label: string) => {
if (!dtq) return;
if (pending.has(label)) {
throw new Error(`Timer mark for '${label}' already exists`);
}
if (current !== null) {
dtq.endQuery(dtq.TIME_ELAPSED);
}
const measure: Measure = { label, queries: [], children: [], root: current === null };
pending.set(label, measure);
if (stack.length) {
stack[stack.length - 1].children.push(measure);
}
stack.push(measure);
add();
},
markEnd: (label: string) => {
if (!dtq) return;
const measure = pending.get(label);
if (!measure) {
throw new Error(`Timer mark for '${label}' does not exist`);
}
if (stack.pop()?.label !== label) {
throw new Error(`Timer mark for '${label}' has pending nested mark`);
}
dtq.endQuery(dtq.TIME_ELAPSED);
pending.delete(label);
measures.push(measure);
if (pending.size > 0) {
add();
} else {
current = null;
}
},
clear,
destroy: () => {
clear();
}
};
}
function formatTimerResult(result: TimerResult) {
const timeElapsed = result.timeElapsed / 1000 / 1000;
return `${result.label} ${timeElapsed.toFixed(2)}ms`;
}
export function printTimerResults(results: TimerResult[]) {
return results.map(r => {
const f = formatTimerResult(r);
if (r.children.length) {
console.groupCollapsed(f);
printTimerResults(r.children);
console.groupEnd();
} else {
console.log(f);
}
});
}

View File

@@ -21,6 +21,7 @@ import { ValueSpec, AttributeSpec, UniformSpec, TextureSpec, DefineSpec, Values
import { gaussianDensity_vert } from '../../../mol-gl/shader/gaussian-density.vert';
import { gaussianDensity_frag } from '../../../mol-gl/shader/gaussian-density.frag';
import { Framebuffer } from '../../../mol-gl/webgl/framebuffer';
import { isTimingMode } from '../../../mol-util/debug';
const GaussianDensitySchema = {
drawCount: ValueSpec('number'),
@@ -85,11 +86,17 @@ export function GaussianDensityTexture(webgl: WebGLContext, position: PositionDa
}
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));
if (isTimingMode) webgl.timer.mark('GaussianDensityTexture2d');
const data = calcGaussianDensityTexture2d(webgl, position, box, radius, powerOfTwo, props, oldTexture);
if (isTimingMode) webgl.timer.markEnd('GaussianDensityTexture2d');
return finalizeGaussianDensityTexture(data);
}
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));
if (isTimingMode) webgl.timer.mark('GaussianDensityTexture3d');
const data = calcGaussianDensityTexture3d(webgl, position, box, radius, props, oldTexture);
if (isTimingMode) webgl.timer.markEnd('GaussianDensityTexture3d');
return finalizeGaussianDensityTexture(data);
}
function finalizeGaussianDensityTexture({ texture, scale, bbox, gridDim, gridTexDim, gridTexScale, radiusFactor, resolution, maxRadius }: _GaussianDensityTextureData): GaussianDensityTextureData {

View File

@@ -1,8 +1,9 @@
/**
* Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
* @author Alexander Rose <alexander.rose@weirdbyte.de>
* @author Aliaksei Chareshneu <chareshneu.tech@gmail.com>
*/
import { StateTransforms } from '../transforms';
@@ -182,7 +183,6 @@ export const CubeProvider = DataFormatProvider({
}
});
type DsCifParams = { entryId?: string | string[] };
export const DscifProvider = DataFormatProvider({
@@ -197,16 +197,21 @@ export const DscifProvider = DataFormatProvider({
parse: async (plugin, data, params?: DsCifParams) => {
const cifCell = await plugin.build().to(data).apply(StateTransforms.Data.ParseCif).commit();
const b = plugin.build().to(cifCell);
const blocks = cifCell.obj!.data.blocks.slice(1); // zero block contains query meta-data
const blocks = cifCell.obj!.data.blocks;
if (blocks.length !== 1 && blocks.length !== 2) throw new Error('unknown number of blocks');
if (blocks.length === 0) throw new Error('no data blocks');
const volumes: StateObjectSelector<PluginStateObject.Volume.Data>[] = [];
let i = 0;
for (const block of blocks) {
// Skip "server" data block.
if (block.header.toUpperCase() === 'SERVER') continue;
const entryId = Array.isArray(params?.entryId) ? params?.entryId[i] : params?.entryId;
volumes.push(b.apply(StateTransforms.Volume.VolumeFromDensityServerCif, { blockHeader: block.header, entryId }).selector);
i++;
if (block.categories['volume_data_3d_info']?.rowCount > 0) {
volumes.push(b.apply(StateTransforms.Volume.VolumeFromDensityServerCif, { blockHeader: block.header, entryId }).selector);
i++;
}
}
await b.commit();

View File

@@ -215,6 +215,7 @@ export class RemoteStateSnapshots extends PluginUIComponent<
}
componentWillUnmount() {
super.componentWillUnmount();
this._mounted = false;
}

View File

@@ -58,6 +58,7 @@ export class DownloadScreenshotControls extends PluginUIComponent<{ close: () =>
}
componentWillUnmount() {
super.componentWillUnmount();
this.setState({ imageData: void 0 });
}

View File

@@ -1,12 +1,15 @@
/**
* 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 Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { PluginContext } from './context';
import { now } from '../mol-util/now';
import { PluginAnimationManager } from '../mol-plugin-state/manager/animation';
import { isTimingMode } from '../mol-util/debug';
import { printTimerResults } from '../mol-gl/webgl/timer';
export class PluginAnimationLoop {
private currentFrame: any = void 0;
@@ -19,6 +22,15 @@ export class PluginAnimationLoop {
async tick(t: number, options?: { isSynchronous?: boolean, manualDraw?: boolean, animation?: PluginAnimationManager.AnimationInfo }) {
await this.plugin.managers.animation.tick(t, options?.isSynchronous, options?.animation);
this.plugin.canvas3d?.tick(t as now.Timestamp, options);
if (isTimingMode) {
const timerResults = this.plugin.canvas3d?.webgl.timer.resolve();
if (timerResults) {
for (const result of timerResults) {
printTimerResults([result]);
}
}
}
}
private frame = () => {

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
@@ -132,6 +132,7 @@ export function ShapeRepresentation<D, G extends Geometry, P extends Geometry.Pa
// console.log('update geometry')
ValueCell.updateIfChanged(_renderObject.values.drawCount, Geometry.getDrawCount(_shape.geometry));
ValueCell.updateIfChanged(_renderObject.values.uVertexCount, Geometry.getVertexCount(_shape.geometry));
ValueCell.updateIfChanged(_renderObject.values.uGroupCount, Geometry.getGroupCount(_shape.geometry));
}
if (updateState.updateTransform || updateState.createGeometry) {

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2018-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
@@ -161,6 +161,7 @@ export function ComplexVisual<G extends Geometry, P extends StructureParams & Ge
if (newGeometry) {
ValueCell.updateIfChanged(renderObject.values.drawCount, Geometry.getDrawCount(newGeometry));
ValueCell.updateIfChanged(renderObject.values.uVertexCount, Geometry.getVertexCount(newGeometry));
ValueCell.updateIfChanged(renderObject.values.uGroupCount, Geometry.getGroupCount(newGeometry));
} else {
throw new Error('expected geometry to be given');
}

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
@@ -207,6 +207,7 @@ export function UnitsVisual<G extends Geometry, P extends StructureParams & Geom
if (newGeometry) {
ValueCell.updateIfChanged(renderObject.values.drawCount, Geometry.getDrawCount(newGeometry));
ValueCell.updateIfChanged(renderObject.values.uVertexCount, Geometry.getVertexCount(newGeometry));
ValueCell.updateIfChanged(renderObject.values.uGroupCount, Geometry.getGroupCount(newGeometry));
} else {
throw new Error('expected geometry to be given');
}

View File

@@ -149,10 +149,8 @@ function getIntraUnitBondCylinderBuilderProps(unit: Unit.Atomic, structure: Stru
if (isBondType(f, BondType.Flag.Aromatic) || (arCount && !ignoreComputedAromatic)) {
if (arCount === 2) {
return LinkStyle.MirroredAromatic;
} else if (arCount === 1 || deloTriplets?.getThirdElement(aI, bI)) {
return LinkStyle.Aromatic;
} else {
// case for bonds between two aromatic rings
return LinkStyle.Aromatic;
}
}
}

View File

@@ -110,10 +110,8 @@ function createIntraUnitBondLines(ctx: VisualContext, unit: Unit, structure: Str
if (isBondType(f, BondType.Flag.Aromatic) || (arCount && !ignoreComputedAromatic)) {
if (arCount === 2) {
return LinkStyle.MirroredAromatic;
} else if (arCount === 1 || deloTriplets?.getThirdElement(aI, bI)) {
return LinkStyle.Aromatic;
} else {
// case for bonds between two aromatic rings
return LinkStyle.Aromatic;
}
}
}

View File

@@ -27,6 +27,7 @@ import { applyMeshColorSmoothing } from '../../../mol-geo/geometry/mesh/color-sm
import { applyTextureMeshColorSmoothing } from '../../../mol-geo/geometry/texture-mesh/color-smoothing';
import { ColorSmoothingParams, getColorSmoothingProps } from '../../../mol-geo/geometry/base';
import { Vec3 } from '../../../mol-math/linear-algebra';
import { isTimingMode } from '../../../mol-util/debug';
const SharedParams = {
...GaussianDensityParams,
@@ -213,6 +214,7 @@ const GaussianSurfaceName = 'gaussian-surface';
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');
if (isTimingMode) ctx.webgl.timer.mark('createGaussianSurfaceTextureMesh');
const { namedTextures, resources, extensions: { colorBufferFloat, textureFloat, colorBufferHalfFloat, textureHalfFloat } } = ctx.webgl;
if (!namedTextures[GaussianSurfaceName]) {
namedTextures[GaussianSurfaceName] = colorBufferHalfFloat && textureHalfFloat
@@ -222,18 +224,13 @@ async function createGaussianSurfaceTextureMesh(ctx: VisualContext, unit: Unit,
: resources.texture('image-uint8', 'rgba', 'ubyte', 'linear');
}
// console.time('computeUnitGaussianDensityTexture2d');
const densityTextureData = await computeUnitGaussianDensityTexture2d(structure, unit, theme.size, true, props, ctx.webgl, namedTextures[GaussianSurfaceName]).runInContext(ctx.runtime);
// console.log(densityTextureData);
// console.log('vertexGroupTexture', readTexture(ctx.webgl, densityTextureData.texture));
// ctx.webgl.waitForGpuCommandsCompleteSync();
// console.timeEnd('computeUnitGaussianDensityTexture2d');
const isoLevel = Math.exp(-props.smoothness) / densityTextureData.radiusFactor;
const axisOrder = Vec3.create(0, 1, 2);
const buffer = textureMesh?.doubleBuffer.get();
const gv = extractIsosurface(ctx.webgl, densityTextureData.texture, densityTextureData.gridDim, densityTextureData.gridTexDim, densityTextureData.gridTexScale, densityTextureData.transform, isoLevel, false, true, axisOrder, buffer?.vertex, buffer?.group, buffer?.normal);
if (isTimingMode) ctx.webgl.timer.markEnd('createGaussianSurfaceTextureMesh');
const boundingSphere = Sphere3D.expand(Sphere3D(), unit.boundary.sphere, densityTextureData.maxRadius);
const surface = TextureMesh.create(gv.vertexCount, 1, gv.vertexTexture, gv.groupTexture, gv.normalTexture, boundingSphere, textureMesh);
@@ -290,6 +287,7 @@ export function GaussianSurfaceTextureMeshVisual(materialId: number): UnitsVisua
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');
if (isTimingMode) ctx.webgl.timer.mark('createStructureGaussianSurfaceTextureMesh');
const { namedTextures, resources, extensions: { colorBufferFloat, textureFloat, colorBufferHalfFloat, textureHalfFloat } } = ctx.webgl;
if (!namedTextures[GaussianSurfaceName]) {
namedTextures[GaussianSurfaceName] = colorBufferHalfFloat && textureHalfFloat
@@ -299,18 +297,13 @@ async function createStructureGaussianSurfaceTextureMesh(ctx: VisualContext, str
: resources.texture('image-uint8', 'rgba', 'ubyte', 'linear');
}
// console.time('computeUnitGaussianDensityTexture2d');
const densityTextureData = await computeStructureGaussianDensityTexture2d(structure, theme.size, true, props, ctx.webgl, namedTextures[GaussianSurfaceName]).runInContext(ctx.runtime);
// console.log(densityTextureData);
// console.log('vertexGroupTexture', readTexture(ctx.webgl, densityTextureData.texture));
// ctx.webgl.waitForGpuCommandsCompleteSync();
// console.timeEnd('computeUnitGaussianDensityTexture2d');
const isoLevel = Math.exp(-props.smoothness) / densityTextureData.radiusFactor;
const axisOrder = Vec3.create(0, 1, 2);
const buffer = textureMesh?.doubleBuffer.get();
const gv = extractIsosurface(ctx.webgl, densityTextureData.texture, densityTextureData.gridDim, densityTextureData.gridTexDim, densityTextureData.gridTexScale, densityTextureData.transform, isoLevel, false, true, axisOrder, buffer?.vertex, buffer?.group, buffer?.normal);
if (isTimingMode) ctx.webgl.timer.markEnd('createStructureGaussianSurfaceTextureMesh');
const boundingSphere = Sphere3D.expand(Sphere3D(), structure.boundary.sphere, densityTextureData.maxRadius);
const surface = TextureMesh.create(gv.vertexCount, 1, gv.vertexTexture, gv.groupTexture, gv.normalTexture, boundingSphere, textureMesh);

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2018-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
@@ -130,6 +130,7 @@ export function VolumeVisual<G extends Geometry, P extends VolumeParams & Geomet
if (newGeometry) {
ValueCell.updateIfChanged(renderObject.values.drawCount, Geometry.getDrawCount(newGeometry));
ValueCell.updateIfChanged(renderObject.values.uVertexCount, Geometry.getVertexCount(newGeometry));
ValueCell.updateIfChanged(renderObject.values.uGroupCount, Geometry.getGroupCount(newGeometry));
} else {
throw new Error('expected geometry to be given');
}

View File

@@ -7,7 +7,7 @@
import { Task } from '../task';
import { isProductionMode } from '../../mol-util/debug';
const hasPerformance = (typeof performance !== 'undefined') && performance.mark && performance.measure;
const hasPerformance = (typeof performance !== 'undefined') && !!performance.mark && performance.measure;
const timingEnabled = hasPerformance && !isProductionMode;
export namespace UserTiming {

View File

@@ -30,7 +30,12 @@ let isDebugMode = function getIsDebug() {
}
}();
export { isProductionMode, isDebugMode };
/**
* set to true to gather timings, mostly used in `mol-gl`
*/
let isTimingMode = false;
export { isProductionMode, isDebugMode, isTimingMode };
export function setProductionMode(value?: boolean) {
if (typeof value !== 'undefined') isProductionMode = value;
@@ -38,4 +43,8 @@ export function setProductionMode(value?: boolean) {
export function setDebugMode(value?: boolean) {
if (typeof value !== 'undefined') isDebugMode = value;
}
}
export function setTimingMode(value?: boolean) {
if (typeof value !== 'undefined') isTimingMode = value;
}

View File

@@ -19,7 +19,8 @@ function isRetriableNetworkError(error: any) {
export async function fetchRetry(url: string, timeout: number, retryCount: number, onRetry?: () => void): Promise<Response> {
const controller = new AbortController();
const id = setTimeout(() => controller.abort(), timeout);
const result = await retryIf(() => fetch(url, { signal: controller.signal }), {
const signal = controller.signal as any; // TODO: fix type
const result = await retryIf(() => fetch(url, { signal }), {
retryThenIf: r => r.status === 408 /** timeout */ || r.status === 429 /** too many requests */ || (r.status >= 500 && r.status < 600),
// TODO test retryCatchIf
retryCatchIf: e => isRetriableNetworkError(e),