ソースを参照

fix unused vertex attribute handling

Alexander Rose 3 年 前
コミット
a85ede5058

+ 1 - 0
CHANGELOG.md

@@ -7,6 +7,7 @@ Note that since we don't clearly distinguish between a public and private interf
 ## [Unreleased]
 
 - Fix double canvas context creation (in plugin context)
+- Fix unused vertex attribute handling (track which are used, disable the rest)
 
 ## [v2.3.7] - 2021-11-8
 

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

@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2018-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
@@ -11,6 +11,7 @@ import { idFactory } from '../../mol-util/id-factory';
 import { ValueOf } from '../../mol-util/type-helpers';
 import { GLRenderingContext } from './compat';
 import { WebGLExtensions } from './extensions';
+import { WebGLState } from './state';
 
 const getNextBufferId = idFactory();
 
@@ -192,7 +193,7 @@ export interface AttributeBuffer extends Buffer {
     bind: (location: number) => void
 }
 
-export function createAttributeBuffer<T extends ArrayType, S extends AttributeItemSize>(gl: GLRenderingContext, extensions: WebGLExtensions, array: T, itemSize: S, divisor: number, usageHint: UsageHint = 'dynamic'): AttributeBuffer {
+export function createAttributeBuffer<T extends ArrayType, S extends AttributeItemSize>(gl: GLRenderingContext, state: WebGLState, extensions: WebGLExtensions, array: T, itemSize: S, divisor: number, usageHint: UsageHint = 'dynamic'): AttributeBuffer {
     const { instancedArrays } = extensions;
 
     const buffer = createBuffer(gl, array, usageHint, 'attribute');
@@ -204,12 +205,12 @@ export function createAttributeBuffer<T extends ArrayType, S extends AttributeIt
             gl.bindBuffer(_bufferType, buffer.getBuffer());
             if (itemSize === 16) {
                 for (let i = 0; i < 4; ++i) {
-                    gl.enableVertexAttribArray(location + i);
+                    state.enableVertexAttrib(location + i);
                     gl.vertexAttribPointer(location + i, 4, _dataType, false, 4 * 4 * _bpe, i * 4 * _bpe);
                     instancedArrays.vertexAttribDivisor(location + i, divisor);
                 }
             } else {
-                gl.enableVertexAttribArray(location);
+                state.enableVertexAttrib(location);
                 gl.vertexAttribPointer(location, itemSize, _dataType, false, 0, 0);
                 instancedArrays.vertexAttribDivisor(location, divisor);
             }

+ 5 - 3
src/mol-gl/webgl/program.ts

@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2018-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
@@ -39,12 +39,12 @@ function getLocations(gl: GLRenderingContext, program: WebGLProgram, schema: Ren
         if (spec.type === 'attribute') {
             const loc = gl.getAttribLocation(program, k);
             // unused attributes will result in a `-1` location which is usually fine
-            // if (loc === -1) console.info(`Could not get attribute location for '${k}'`)
+            // if (loc === -1) console.info(`Could not get attribute location for '${k}'`);
             locations[k] = loc;
         } else if (spec.type === 'uniform' || spec.type === 'texture') {
             const loc = gl.getUniformLocation(program, k);
             // unused uniforms will result in a `null` location which is usually fine
-            // if (loc === null) console.info(`Could not get uniform location for '${k}'`)
+            // if (loc === null) console.info(`Could not get uniform location for '${k}'`);
             locations[k] = loc as number;
         }
     });
@@ -192,11 +192,13 @@ export function createProgram(gl: GLRenderingContext, state: WebGLState, extensi
             }
         },
         bindAttributes: (attributeBuffers: AttributeBuffers) => {
+            state.clearVertexAttribsState();
             for (let i = 0, il = attributeBuffers.length; i < il; ++i) {
                 const [k, buffer] = attributeBuffers[i];
                 const l = locations[k];
                 if (l !== -1) buffer.bind(l);
             }
+            state.disableUnusedVertexAttribs();
         },
         bindTextures: (textures: Textures, startingTargetUnit: number) => {
             for (let i = 0, il = textures.length; i < il; ++i) {

+ 1 - 1
src/mol-gl/webgl/resources.ts

@@ -114,7 +114,7 @@ export function createResources(gl: GLRenderingContext, state: WebGLState, stats
 
     return {
         attribute: (array: ArrayType, itemSize: AttributeItemSize, divisor: number, usageHint?: UsageHint) => {
-            return wrap('attribute', createAttributeBuffer(gl, extensions, array, itemSize, divisor, usageHint));
+            return wrap('attribute', createAttributeBuffer(gl, state, extensions, array, itemSize, divisor, usageHint));
         },
         elements: (array: ElementsType, usageHint?: UsageHint) => {
             return wrap('elements', createElementsBuffer(gl, array, usageHint));

+ 33 - 2
src/mol-gl/webgl/state.ts

@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2018-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
@@ -59,11 +59,15 @@ export type WebGLState = {
     /** set the RGB blend equation and alpha blend equation separately, determines how a new pixel is combined with an existing */
     blendEquationSeparate: (modeRGB: number, modeAlpha: number) => void
 
+    enableVertexAttrib: (index: number) => void
+    clearVertexAttribsState: () => void
+    disableUnusedVertexAttribs: () => void
+
     reset: () => void
 }
 
 export function createState(gl: GLRenderingContext): WebGLState {
-    let enabledCapabilities: { [k: number]: boolean } = {};
+    let enabledCapabilities: Record<number, boolean> = {};
 
     let currentFrontFace = gl.getParameter(gl.FRONT_FACE);
     let currentCullFace = gl.getParameter(gl.CULL_FACE_MODE);
@@ -79,6 +83,16 @@ export function createState(gl: GLRenderingContext): WebGLState {
     let currentBlendEqRGB = gl.getParameter(gl.BLEND_EQUATION_RGB);
     let currentBlendEqAlpha = gl.getParameter(gl.BLEND_EQUATION_ALPHA);
 
+    let maxVertexAttribs = gl.getParameter(gl.MAX_VERTEX_ATTRIBS);
+    const vertexAttribsState: number[] = [];
+
+    const clearVertexAttribsState = () => {
+        for (let i = 0; i < maxVertexAttribs; ++i) {
+            vertexAttribsState[i] = 0;
+        }
+    };
+    clearVertexAttribsState();
+
     return {
         currentProgramId: -1,
         currentMaterialId: -1,
@@ -168,6 +182,17 @@ export function createState(gl: GLRenderingContext): WebGLState {
             }
         },
 
+        enableVertexAttrib: (index: number) => {
+            gl.enableVertexAttribArray(index);
+            vertexAttribsState[index] = 1;
+        },
+        clearVertexAttribsState,
+        disableUnusedVertexAttribs: () => {
+            for (let i = 0; i < maxVertexAttribs; ++i) {
+                if (vertexAttribsState[i] === 0) gl.disableVertexAttribArray(i);
+            }
+        },
+
         reset: () => {
             enabledCapabilities = {};
 
@@ -184,6 +209,12 @@ export function createState(gl: GLRenderingContext): WebGLState {
 
             currentBlendEqRGB = gl.getParameter(gl.BLEND_EQUATION_RGB);
             currentBlendEqAlpha = gl.getParameter(gl.BLEND_EQUATION_ALPHA);
+
+            maxVertexAttribs = gl.getParameter(gl.MAX_VERTEX_ATTRIBS);
+            vertexAttribsState.length = 0;
+            for (let i = 0; i < maxVertexAttribs; ++i) {
+                vertexAttribsState[i] = 0;
+            }
         }
     };
 }