diff --git a/CHANGELOG.md b/CHANGELOG.md index b880389397ad2b8dea2402c3b4a1670d05f69f3c..d501c71631412a80938a1c598c0dcd02cbc68efe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ Note that since we don't clearly distinguish between a public and private interf - Avoid `renderMarkingDepth` for fully transparent renderables - Remove `camera.far` doubling workaround - Add `ModifiersKeys.areNone` helper function +- Fix rendering issues caused by VAO reuse - Add "Zoom All", "Orient Axes", "Reset Axes" buttons to the "Reset Camera" button - Improve trackball move-state handling when key bindings use modifiers diff --git a/src/mol-gl/_spec/renderer.spec.ts b/src/mol-gl/_spec/renderer.spec.ts index 40215246c7f01c866d84de66303e1b51db7c4cb9..4842ca9c9407e97059239e3b167f945c3acbbd6f 100644 --- a/src/mol-gl/_spec/renderer.spec.ts +++ b/src/mol-gl/_spec/renderer.spec.ts @@ -53,7 +53,7 @@ describe('renderer', () => { scene.commit(); expect(ctx.stats.resourceCounts.attribute).toBe(ctx.isWebGL2 ? 4 : 5); expect(ctx.stats.resourceCounts.texture).toBe(9); - expect(ctx.stats.resourceCounts.vertexArray).toBe(ctx.extensions.vertexArrayObject ? 1 : 0); + expect(ctx.stats.resourceCounts.vertexArray).toBe(ctx.extensions.vertexArrayObject ? 6 : 0); expect(ctx.stats.resourceCounts.program).toBe(6); expect(ctx.stats.resourceCounts.shader).toBe(12); diff --git a/src/mol-gl/webgl/render-item.ts b/src/mol-gl/webgl/render-item.ts index 03f99fb5f0e6c9311f49f024468fbb2f17f4dda5..252da58f816b85b579d10981bc867a674230d7c2 100644 --- a/src/mol-gl/webgl/render-item.ts +++ b/src/mol-gl/webgl/render-item.ts @@ -144,7 +144,10 @@ export function createRenderItem<T extends string>(ctx: WebGLContext, drawMode: elementsBuffer = resources.elements(elements.ref.value); } - let vertexArray: VertexArray | null = vertexArrayObject ? resources.vertexArray(programs, attributeBuffers, elementsBuffer) : null; + const vertexArrays: Record<string, VertexArray | null> = {}; + for (const k of renderVariants) { + vertexArrays[k] = vertexArrayObject ? resources.vertexArray(programs[k], attributeBuffers, elementsBuffer) : null; + } let drawCount: number = values.drawCount.ref.value; let instanceCount: number = values.instanceCount.ref.value; @@ -170,6 +173,7 @@ export function createRenderItem<T extends string>(ctx: WebGLContext, drawMode: program.setUniforms(uniformValueEntries); program.bindTextures(textures, sharedTexturesCount); } else { + const vertexArray = vertexArrays[variant]; if (program.id !== state.currentProgramId || program.id !== currentProgramId || materialId === -1 || materialId !== state.currentMaterialId ) { @@ -291,9 +295,12 @@ export function createRenderItem<T extends string>(ctx: WebGLContext, drawMode: } if (valueChanges.attributes || valueChanges.defines || valueChanges.elements) { - // console.log('program/defines or buffers changed, update vao'); - if (vertexArray) vertexArray.destroy(); - vertexArray = vertexArrayObject ? resources.vertexArray(programs, attributeBuffers, elementsBuffer) : null; + // console.log('program/defines or buffers changed, update vaos'); + for (const k of renderVariants) { + const vertexArray = vertexArrays[k]; + if (vertexArray) vertexArray.destroy(); + vertexArrays[k] = vertexArrayObject ? resources.vertexArray(programs[k], attributeBuffers, elementsBuffer) : null; + } } for (let i = 0, il = textures.length; i < il; ++i) { @@ -341,8 +348,9 @@ export function createRenderItem<T extends string>(ctx: WebGLContext, drawMode: if (!destroyed) { for (const k of renderVariants) { programs[k].destroy(); + const vertexArray = vertexArrays[k]; + if (vertexArray) vertexArray.destroy(); } - if (vertexArray) vertexArray.destroy(); textures.forEach(([k, texture]) => { // lifetime of textures with kind 'texture' is defined externally if (schema[k].kind !== 'texture') texture.destroy(); diff --git a/src/mol-gl/webgl/resources.ts b/src/mol-gl/webgl/resources.ts index ae036cd3812072870c6d32ed930dc201b9699904..dc75c5d60257aec9511c97926f6b94d6f7dd54fc 100644 --- a/src/mol-gl/webgl/resources.ts +++ b/src/mol-gl/webgl/resources.ts @@ -4,7 +4,7 @@ * @author Alexander Rose <alexander.rose@weirdbyte.de> */ -import { ProgramProps, createProgram, Program, Programs } from './program'; +import { ProgramProps, createProgram, Program } from './program'; import { ShaderType, createShader, Shader, ShaderProps } from './shader'; import { GLRenderingContext } from './compat'; import { Framebuffer, createFramebuffer } from './framebuffer'; @@ -60,7 +60,7 @@ export interface WebGLResources { shader: (type: ShaderType, source: string) => Shader texture: (kind: TextureKind, format: TextureFormat, type: TextureType, filter: TextureFilter) => Texture, cubeTexture: (faces: CubeFaces, mipmaps: boolean, onload?: () => void) => Texture, - vertexArray: (programs: Programs, attributeBuffers: AttributeBuffers, elementsBuffer?: ElementsBuffer) => VertexArray, + vertexArray: (program: Program, attributeBuffers: AttributeBuffers, elementsBuffer?: ElementsBuffer) => VertexArray, getByteCounts: () => ByteCounts @@ -142,8 +142,8 @@ export function createResources(gl: GLRenderingContext, state: WebGLState, stats cubeTexture: (faces: CubeFaces, mipmaps: boolean, onload?: () => void) => { return wrap('cubeTexture', createCubeTexture(gl, faces, mipmaps, onload)); }, - vertexArray: (programs: Programs, attributeBuffers: AttributeBuffers, elementsBuffer?: ElementsBuffer) => { - return wrap('vertexArray', createVertexArray(gl, extensions, programs, attributeBuffers, elementsBuffer)); + vertexArray: (program: Program, attributeBuffers: AttributeBuffers, elementsBuffer?: ElementsBuffer) => { + return wrap('vertexArray', createVertexArray(gl, extensions, program, attributeBuffers, elementsBuffer)); }, getByteCounts: () => { diff --git a/src/mol-gl/webgl/vertex-array.ts b/src/mol-gl/webgl/vertex-array.ts index 966bb4d92ecff088d90cb95ff040d1f92fd67599..1e6eec37943142870432f49bfc734ca0e5f5d3a8 100644 --- a/src/mol-gl/webgl/vertex-array.ts +++ b/src/mol-gl/webgl/vertex-array.ts @@ -4,7 +4,7 @@ * @author Alexander Rose <alexander.rose@weirdbyte.de> */ -import { Programs } from './program'; +import { Program } from './program'; import { ElementsBuffer, AttributeBuffers } from './buffer'; import { WebGLExtensions } from './extensions'; import { idFactory } from '../../mol-util/id-factory'; @@ -41,7 +41,7 @@ export interface VertexArray { destroy: () => void } -export function createVertexArray(gl: GLRenderingContext, extensions: WebGLExtensions, programs: Programs, attributeBuffers: AttributeBuffers, elementsBuffer?: ElementsBuffer): VertexArray { +export function createVertexArray(gl: GLRenderingContext, extensions: WebGLExtensions, program: Program, attributeBuffers: AttributeBuffers, elementsBuffer?: ElementsBuffer): VertexArray { const id = getNextVertexArrayId(); let vertexArray = getVertexArray(extensions); let vertexArrayObject = getVertexArrayObject(extensions); @@ -49,7 +49,7 @@ export function createVertexArray(gl: GLRenderingContext, extensions: WebGLExten function update() { vertexArrayObject.bindVertexArray(vertexArray); if (elementsBuffer) elementsBuffer.bind(); - for (const p of Object.values(programs)) p.bindAttributes(attributeBuffers); + program.bindAttributes(attributeBuffers); vertexArrayObject.bindVertexArray(null); }