mirror of
https://github.com/molstar/molstar.git
synced 2026-06-07 15:14:22 +08:00
Compare commits
33 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7a07701be0 | ||
|
|
42519a4f75 | ||
|
|
c898c16430 | ||
|
|
318863bd18 | ||
|
|
ce94760d02 | ||
|
|
da413cc9e6 | ||
|
|
c72e93a13d | ||
|
|
21f910a3ca | ||
|
|
e7ce693e50 | ||
|
|
29e8fe7904 | ||
|
|
baf3a6077e | ||
|
|
e030e7a32d | ||
|
|
125566ed75 | ||
|
|
c51cb67519 | ||
|
|
57f086b530 | ||
|
|
d1e17785b8 | ||
|
|
774328a1d8 | ||
|
|
175a0f48fa | ||
|
|
60b91ff032 | ||
|
|
2b003bc5b0 | ||
|
|
029a2fcab1 | ||
|
|
a828113d9b | ||
|
|
ab4d509eda | ||
|
|
1296f32fa8 | ||
|
|
5aa1ec9876 | ||
|
|
f2cf1ab226 | ||
|
|
2d34c2a40b | ||
|
|
a7181e865c | ||
|
|
0a71b788b3 | ||
|
|
1ed3d84043 | ||
|
|
f472b75d0d | ||
|
|
072a9d1ccd | ||
|
|
8e26d1be68 |
17
CHANGELOG.md
17
CHANGELOG.md
@@ -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
3890
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
54
package.json
54
package.json
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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__ -->
|
||||
|
||||
@@ -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;
|
||||
@@ -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.');
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -71,6 +71,7 @@ export class GeometryExporterUI extends CollapsableControls<{}, State> {
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
super.componentWillUnmount();
|
||||
this._controls?.dispose();
|
||||
this._controls = void 0;
|
||||
}
|
||||
|
||||
@@ -102,6 +102,7 @@ export class Mp4EncoderUI extends CollapsableControls<{}, State> {
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
super.componentWillUnmount();
|
||||
this._controls?.dispose();
|
||||
this._controls = void 0;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 };
|
||||
}
|
||||
|
||||
|
||||
@@ -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');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 };
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -258,6 +258,8 @@ namespace Scene {
|
||||
renderables[i].dispose();
|
||||
}
|
||||
renderables.length = 0;
|
||||
primitives.length = 0;
|
||||
volumes.length = 0;
|
||||
renderableMap.clear();
|
||||
boundingSphereDirty = true;
|
||||
boundingSphereVisibleDirty = true;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -68,7 +68,6 @@ uniform float uFogFar;
|
||||
uniform vec3 uFogColor;
|
||||
|
||||
uniform float uAlpha;
|
||||
uniform float uPickingAlphaThreshold;
|
||||
uniform bool uTransparentBackground;
|
||||
uniform float uXrayEdgeFalloff;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 = `
|
||||
|
||||
@@ -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; },
|
||||
|
||||
@@ -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
194
src/mol-gl/webgl/timer.ts
Normal 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);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -215,6 +215,7 @@ export class RemoteStateSnapshots extends PluginUIComponent<
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
super.componentWillUnmount();
|
||||
this._mounted = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -58,6 +58,7 @@ export class DownloadScreenshotControls extends PluginUIComponent<{ close: () =>
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
super.componentWillUnmount();
|
||||
this.setState({ imageData: void 0 });
|
||||
}
|
||||
|
||||
|
||||
@@ -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 = () => {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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');
|
||||
}
|
||||
|
||||
@@ -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');
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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');
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
|
||||
Reference in New Issue
Block a user