Quellcode durchsuchen

fix unneccessary render & geo updates

- uniforms & defines
- bufferSubData instead of bufferData
- scene remove
- drawCount
- geo builder
Alexander Rose vor 4 Jahren
Ursprung
Commit
39b9710d16

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

@@ -413,7 +413,6 @@ namespace Canvas3D {
             if (renderObjects) {
                 renderObjects.forEach(o => scene.remove(o));
                 reprRenderObjects.delete(repr);
-                scene.update(repr.renderObjects, false, true);
                 forceDrawAfterAllCommited = true;
                 if (isDebugMode) consoleStats();
             }

+ 1 - 1
src/mol-canvas3d/helper/bounding-sphere-helper.ts

@@ -132,7 +132,7 @@ function updateBoundingSphereData(scene: Scene, boundingSphere: Sphere3D, data:
         const mesh = createBoundingSphereMesh(boundingSphere, data && data.mesh);
         const renderObject = data ? data.renderObject : createBoundingSphereRenderObject(mesh, color, materialId, transform);
         if (data) {
-            ValueCell.update(renderObject.values.drawCount, Geometry.getDrawCount(mesh));
+            ValueCell.updateIfChanged(renderObject.values.drawCount, Geometry.getDrawCount(mesh));
         } else {
             scene.add(renderObject);
         }

+ 2 - 8
src/mol-canvas3d/helper/camera-helper.ts

@@ -15,7 +15,6 @@ import { Mesh } from '../../mol-geo/geometry/mesh/mesh';
 import { ColorNames } from '../../mol-util/color/names';
 import { addCylinder } from '../../mol-geo/geometry/mesh/builder/cylinder';
 import { Viewport } from '../camera/util';
-import { ValueCell } from '../../mol-util';
 import { Sphere3D } from '../../mol-math/geometry';
 import { ParamDefinition as PD } from '../../mol-util/param-definition';
 import produce from 'immer';
@@ -91,19 +90,14 @@ export class CameraHelper {
         if (!this.renderObject) return;
 
         updateCamera(this.camera, camera.viewport);
-
-        const m = this.renderObject.values.aTransform.ref.value as unknown as Mat4;
-        Mat4.extractRotation(m, camera.view);
+        Mat4.extractRotation(this.scene.view, camera.view);
 
         const r = this.renderObject.values.boundingSphere.ref.value.radius;
-        Mat4.setTranslation(m, Vec3.create(
+        Mat4.setTranslation(this.scene.view, Vec3.create(
             -camera.viewport.width / 2 + r,
             -camera.viewport.height / 2 + r,
             0
         ));
-
-        ValueCell.update(this.renderObject.values.aTransform, this.renderObject.values.aTransform.ref.value);
-        this.scene.update([this.renderObject], true);
     }
 }
 

+ 10 - 5
src/mol-canvas3d/passes/postprocessing.ts

@@ -152,11 +152,16 @@ export class PostprocessingPass {
     }
 
     render(toDrawingBuffer: boolean) {
-        ValueCell.update(this.renderable.values.uFar, this.camera.far);
-        ValueCell.update(this.renderable.values.uNear, this.camera.near);
-        ValueCell.update(this.renderable.values.uFogFar, this.camera.fogFar);
-        ValueCell.update(this.renderable.values.uFogNear, this.camera.fogNear);
-        ValueCell.update(this.renderable.values.dOrthographic, this.camera.state.mode === 'orthographic' ? 1 : 0);
+        ValueCell.updateIfChanged(this.renderable.values.uFar, this.camera.far);
+        ValueCell.updateIfChanged(this.renderable.values.uNear, this.camera.near);
+        ValueCell.updateIfChanged(this.renderable.values.uFogFar, this.camera.fogFar);
+        ValueCell.updateIfChanged(this.renderable.values.uFogNear, this.camera.fogNear);
+
+        const orthographic = this.camera.state.mode === 'orthographic' ? 1 : 0;
+        if (this.renderable.values.dOrthographic.ref.value !==  orthographic) {
+            ValueCell.updateIfChanged(this.renderable.values.dOrthographic, orthographic);
+            this.renderable.update();
+        }
 
         const { gl, state } = this.webgl;
         if (toDrawingBuffer) {

+ 22 - 13
src/mol-geo/geometry/lines/lines-builder.ts

@@ -23,30 +23,20 @@ const tmpDir = Vec3();
 
 // avoiding namespace lookup improved performance in Chrome (Aug 2020)
 const caAdd = ChunkedArray.add;
-const caAdd2 = ChunkedArray.add2;
 const caAdd3 = ChunkedArray.add3;
 
 export namespace LinesBuilder {
     export function create(initialCount = 2048, chunkSize = 1024, lines?: Lines): LinesBuilder {
-        const mappings = ChunkedArray.create(Float32Array, 2, chunkSize, lines ? lines.mappingBuffer.ref.value : initialCount);
         const groups = ChunkedArray.create(Float32Array, 1, chunkSize, lines ? lines.groupBuffer.ref.value : initialCount);
-        const indices = ChunkedArray.create(Uint32Array, 3, chunkSize * 3, lines ? lines.indexBuffer.ref.value : initialCount * 3);
         const starts = ChunkedArray.create(Float32Array, 3, chunkSize, lines ? lines.startBuffer.ref.value : initialCount);
         const ends = ChunkedArray.create(Float32Array, 3, chunkSize, lines ? lines.endBuffer.ref.value : initialCount);
 
         const add = (startX: number, startY: number, startZ: number, endX: number, endY: number, endZ: number, group: number) => {
-            const offset = mappings.elementCount;
             for (let i = 0; i < 4; ++i) {
                 caAdd3(starts, startX, startY, startZ);
                 caAdd3(ends, endX, endY, endZ);
                 caAdd(groups, group);
             }
-            caAdd2(mappings, -1, 1);
-            caAdd2(mappings, -1, -1);
-            caAdd2(mappings, 1, 1);
-            caAdd2(mappings, 1, -1);
-            caAdd3(indices, offset, offset + 1, offset + 2);
-            caAdd3(indices, offset + 1, offset + 3, offset + 2);
         };
 
         const addFixedCountDashes = (start: Vec3, end: Vec3, segmentCount: number, group: number) => {
@@ -83,13 +73,32 @@ export namespace LinesBuilder {
                 }
             },
             getLines: () => {
-                const mb = ChunkedArray.compact(mappings, true) as Float32Array;
-                const ib = ChunkedArray.compact(indices, true) as Uint32Array;
+                const lineCount = groups.elementCount / 4;
                 const gb = ChunkedArray.compact(groups, true) as Float32Array;
                 const sb = ChunkedArray.compact(starts, true) as Float32Array;
                 const eb = ChunkedArray.compact(ends, true) as Float32Array;
-                return Lines.create(mb, ib, gb, sb, eb, indices.elementCount / 2, lines);
+                const mb = lines && lineCount <= lines.lineCount ? lines.mappingBuffer.ref.value : new Float32Array(lineCount * 8);
+                const ib = lines && lineCount <= lines.lineCount ? lines.indexBuffer.ref.value : new Uint32Array(lineCount * 6);
+                if (!lines || lineCount > lines.lineCount) fillMappingAndIndices(lineCount, mb, ib);
+                return Lines.create(mb, ib, gb, sb, eb, lineCount, lines);
             }
         };
     }
+}
+
+function fillMappingAndIndices(n: number, mb: Float32Array, ib: Uint32Array) {
+    for (let i = 0; i < n; ++i) {
+        const mo = i * 8;
+        mb[mo] = -1; mb[mo + 1] = 1;
+        mb[mo + 2] = -1; mb[mo + 3] = -1;
+        mb[mo + 4] = 1; mb[mo + 5] = 1;
+        mb[mo + 6] = 1; mb[mo + 7] = -1;
+    }
+
+    for (let i = 0; i < n; ++i) {
+        const o = i * 4;
+        const io = i * 6;
+        ib[io] = o; ib[io + 1] = o + 1; ib[io + 2] = o + 2;
+        ib[io + 3] = o + 1; ib[io + 4] = o + 3; ib[io + 5] = o + 2;
+    }
 }

+ 4 - 2
src/mol-geo/geometry/lines/lines.ts

@@ -140,9 +140,11 @@ export namespace Lines {
     }
 
     function update(mappings: Float32Array, indices: Uint32Array, groups: Float32Array, starts: Float32Array, ends: Float32Array, lineCount: number, lines: Lines) {
+        if (lineCount > lines.lineCount) {
+            ValueCell.update(lines.mappingBuffer, mappings);
+            ValueCell.update(lines.indexBuffer, indices);
+        }
         lines.lineCount = lineCount;
-        ValueCell.update(lines.mappingBuffer, mappings);
-        ValueCell.update(lines.indexBuffer, indices);
         ValueCell.update(lines.groupBuffer, groups);
         ValueCell.update(lines.startBuffer, starts);
         ValueCell.update(lines.endBuffer, ends);

+ 4 - 2
src/mol-geo/geometry/spheres/spheres.ts

@@ -111,10 +111,12 @@ export namespace Spheres {
     }
 
     function update(centers: Float32Array, mappings: Float32Array, indices: Uint32Array, groups: Float32Array, sphereCount: number, spheres: Spheres) {
+        if (sphereCount > spheres.sphereCount) {
+            ValueCell.update(spheres.mappingBuffer, mappings);
+            ValueCell.update(spheres.indexBuffer, indices);
+        }
         spheres.sphereCount = sphereCount;
         ValueCell.update(spheres.centerBuffer, centers);
-        ValueCell.update(spheres.mappingBuffer, mappings);
-        ValueCell.update(spheres.indexBuffer, indices);
         ValueCell.update(spheres.groupBuffer, groups);
         return spheres;
     }

+ 2 - 2
src/mol-geo/geometry/transform-data.ts

@@ -44,8 +44,8 @@ export function createTransform(transformArray: Float32Array, instanceCount: num
     if (transformData) {
         ValueCell.update(transformData.matrix, transformData.matrix.ref.value);
         ValueCell.update(transformData.transform, transformArray);
-        ValueCell.update(transformData.uInstanceCount, instanceCount);
-        ValueCell.update(transformData.instanceCount, instanceCount);
+        ValueCell.updateIfChanged(transformData.uInstanceCount, instanceCount);
+        ValueCell.updateIfChanged(transformData.instanceCount, instanceCount);
 
         const aTransform = transformData.aTransform.ref.value.length >= instanceCount * 16 ? transformData.aTransform.ref.value : new Float32Array(instanceCount * 16);
         aTransform.set(transformArray);

+ 1 - 1
src/mol-geo/util.ts

@@ -21,7 +21,7 @@ export function normalizeVec3Array<T extends NumberArray> (a: T, count: number)
     return a;
 }
 
-const tmpV3 = Vec3.zero();
+const tmpV3 = Vec3();
 
 export function transformPositionArray (t: Mat4, array: NumberArray, offset: number, count: number) {
     for (let i = 0, il = count * 3; i < il; i += 3) {

+ 3 - 3
src/mol-gl/scene.ts

@@ -68,7 +68,7 @@ interface Scene extends Object3D {
 
     /** Returns `true` if some visibility has changed, `false` otherwise. */
     syncVisibility: () => boolean
-    update: (objects: ArrayLike<GraphicsRenderObject> | undefined, keepBoundingSphere: boolean, isRemoving?: boolean) => void
+    update: (objects: ArrayLike<GraphicsRenderObject> | undefined, keepBoundingSphere: boolean) => void
     add: (o: GraphicsRenderObject) => void // Renderable<any>
     remove: (o: GraphicsRenderObject) => void
     commit: (maxTimeMs?: number) => boolean
@@ -170,7 +170,7 @@ namespace Scene {
             get up () { return object3d.up; },
 
             syncVisibility,
-            update(objects, keepBoundingSphere, isRemoving) {
+            update(objects, keepBoundingSphere) {
                 Object3D.update(object3d);
                 if (objects) {
                     for (let i = 0, il = objects.length; i < il; ++i) {
@@ -178,7 +178,7 @@ namespace Scene {
                         if (!o) continue;
                         o.update();
                     }
-                } else if (!isRemoving) {
+                } else {
                     for (let i = 0, il = renderables.length; i < il; ++i) {
                         renderables[i].update();
                     }

+ 5 - 1
src/mol-gl/webgl/buffer.ts

@@ -135,7 +135,11 @@ function createBuffer(gl: GLRenderingContext, array: ArrayType, usageHint: Usage
         updateData,
         updateSubData: (array: ArrayType, offset: number, count: number) => {
             gl.bindBuffer(_bufferType, _buffer);
-            gl.bufferSubData(_bufferType, offset * _bpe, array.subarray(offset, offset + count));
+            if (count - offset === array.length) {
+                gl.bufferSubData(_bufferType, 0, array);
+            } else {
+                gl.bufferSubData(_bufferType, offset * _bpe, array.subarray(offset, offset + count));
+            }
         },
 
         reset: () => {

+ 12 - 12
src/mol-gl/webgl/render-item.ts

@@ -205,14 +205,14 @@ export function createRenderItem<T extends string>(ctx: WebGLContext, drawMode:
             for (let i = 0, il = defineValueEntries.length; i < il; ++i) {
                 const [k, value] = defineValueEntries[i];
                 if (value.ref.version !== versions[k]) {
-                    // console.log('define version changed', k)
+                    // console.log('define version changed', k);
                     valueChanges.defines = true;
                     versions[k] = value.ref.version;
                 }
             }
 
             if (valueChanges.defines) {
-                // console.log('some defines changed, need to rebuild programs')
+                // console.log('some defines changed, need to rebuild programs');
                 for (const k of renderVariants) {
                     programs[k].destroy();
                     programs[k] = createProgramVariant(ctx, k, defineValues, shaderCode, schema);
@@ -220,14 +220,14 @@ export function createRenderItem<T extends string>(ctx: WebGLContext, drawMode:
             }
 
             if (values.drawCount.ref.version !== versions.drawCount) {
-                // console.log('drawCount version changed')
+                // console.log('drawCount version changed');
                 stats.drawCount += values.drawCount.ref.value - drawCount;
                 stats.instancedDrawCount += instanceCount * values.drawCount.ref.value - instanceCount * drawCount;
                 drawCount = values.drawCount.ref.value;
                 versions.drawCount = values.drawCount.ref.version;
             }
             if (values.instanceCount.ref.version !== versions.instanceCount) {
-                // console.log('instanceCount version changed')
+                // console.log('instanceCount version changed');
                 stats.instanceCount += values.instanceCount.ref.value - instanceCount;
                 stats.instancedDrawCount += values.instanceCount.ref.value * drawCount - instanceCount * drawCount;
                 instanceCount = values.instanceCount.ref.value;
@@ -239,10 +239,10 @@ export function createRenderItem<T extends string>(ctx: WebGLContext, drawMode:
                 const value = attributeValues[k];
                 if (value.ref.version !== versions[k]) {
                     if (buffer.length >= value.ref.value.length) {
-                        // console.log('attribute array large enough to update', buffer.id, k, value.ref.id, value.ref.version)
-                        buffer.updateData(value.ref.value);
+                        // console.log('attribute array large enough to update', buffer.id, k, value.ref.id, value.ref.version);
+                        buffer.updateSubData(value.ref.value, 0, buffer.length);
                     } else {
-                        // console.log('attribute array too small, need to create new attribute', buffer.id, k, value.ref.id, value.ref.version)
+                        // console.log('attribute array too small, need to create new attribute', buffer.id, k, value.ref.id, value.ref.version);
                         buffer.destroy();
                         const { itemSize, divisor } = schema[k] as AttributeSpec<AttributeKind>;
                         attributeBuffers[i][1] = resources.attribute(value.ref.value, itemSize, divisor);
@@ -254,10 +254,10 @@ export function createRenderItem<T extends string>(ctx: WebGLContext, drawMode:
 
             if (elementsBuffer && values.elements.ref.version !== versions.elements) {
                 if (elementsBuffer.length >= values.elements.ref.value.length) {
-                    // console.log('elements array large enough to update', values.elements.ref.id, values.elements.ref.version)
-                    elementsBuffer.updateData(values.elements.ref.value);
+                    // console.log('elements array large enough to update', values.elements.ref.id, values.elements.ref.version);
+                    elementsBuffer.updateSubData(values.elements.ref.value, 0, elementsBuffer.length);
                 } else {
-                    // console.log('elements array to small, need to create new elements', values.elements.ref.id, values.elements.ref.version)
+                    // console.log('elements array to small, need to create new elements', values.elements.ref.id, values.elements.ref.version);
                     elementsBuffer.destroy();
                     elementsBuffer = resources.elements(values.elements.ref.value);
                     valueChanges.elements = true;
@@ -266,7 +266,7 @@ export function createRenderItem<T extends string>(ctx: WebGLContext, drawMode:
             }
 
             if (valueChanges.attributes || valueChanges.defines || valueChanges.elements) {
-                // console.log('program/defines or buffers changed, update vaos')
+                // console.log('program/defines or buffers changed, update vaos');
                 for (const k of renderVariants) {
                     const vertexArray = vertexArrays[k];
                     if (vertexArray) vertexArray.destroy();
@@ -280,7 +280,7 @@ export function createRenderItem<T extends string>(ctx: WebGLContext, drawMode:
                 if (value.ref.version !== versions[k]) {
                     // update of textures with kind 'texture' is done externally
                     if (schema[k].kind !== 'texture') {
-                        // console.log('texture version changed, uploading image', k)
+                        // console.log('texture version changed, uploading image', k);
                         texture.load(value.ref.value as TextureImage<any> | TextureVolume<any>);
                         versions[k] = value.ref.version;
                         valueChanges.textures = true;

+ 1 - 1
src/mol-repr/shape/representation.ts

@@ -126,7 +126,7 @@ export function ShapeRepresentation<D, G extends Geometry, P extends Geometry.Pa
 
                 if (updateState.createGeometry) {
                     // console.log('update geometry')
-                    ValueCell.update(_renderObject.values.drawCount, Geometry.getDrawCount(_shape.geometry));
+                    ValueCell.updateIfChanged(_renderObject.values.drawCount, Geometry.getDrawCount(_shape.geometry));
                 }
 
                 if (updateState.updateTransform || updateState.createGeometry) {

+ 1 - 1
src/mol-repr/structure/complex-visual.ts

@@ -138,7 +138,7 @@ export function ComplexVisual<G extends Geometry, P extends StructureParams & Ge
 
             if (updateState.createGeometry) {
                 if (newGeometry) {
-                    ValueCell.update(renderObject.values.drawCount, Geometry.getDrawCount(newGeometry));
+                    ValueCell.updateIfChanged(renderObject.values.drawCount, Geometry.getDrawCount(newGeometry));
                     updateBoundingSphere(renderObject.values as RenderObjectValues<G['kind']>, newGeometry);
                 } else {
                     throw new Error('expected geometry to be given');

+ 1 - 1
src/mol-repr/structure/units-visual.ts

@@ -176,7 +176,7 @@ export function UnitsVisual<G extends Geometry, P extends StructureParams & Geom
             if (updateState.createGeometry) {
                 // console.log('update geometry');
                 if (newGeometry) {
-                    ValueCell.update(renderObject.values.drawCount, Geometry.getDrawCount(newGeometry));
+                    ValueCell.updateIfChanged(renderObject.values.drawCount, Geometry.getDrawCount(newGeometry));
                 } else {
                     throw new Error('expected geometry to be given');
                 }

+ 1 - 1
src/mol-repr/volume/representation.ts

@@ -120,7 +120,7 @@ export function VolumeVisual<G extends Geometry, P extends VolumeParams & Geomet
 
             if (updateState.createGeometry) {
                 if (newGeometry) {
-                    ValueCell.update(renderObject.values.drawCount, Geometry.getDrawCount(newGeometry));
+                    ValueCell.updateIfChanged(renderObject.values.drawCount, Geometry.getDrawCount(newGeometry));
                     updateBoundingSphere(renderObject.values as RenderObjectValues<G['kind']>, newGeometry);
                 } else {
                     throw new Error('expected geometry to be given');