diff --git a/CHANGELOG.md b/CHANGELOG.md
index 40b0426843bf46aaa4db84f662c14388229f14c6..a99819548e3eff87cc33be53d1307d4099a2b148 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,7 @@ Note that since we don't clearly distinguish between a public and private interf
 
 ## [Unreleased]
 
+- Bind shared textures only once per pass, not for each render item
 
 ## [v3.11.0] - 2022-07-04
 
diff --git a/src/mol-gl/renderable.ts b/src/mol-gl/renderable.ts
index e0c4db03086fba4c7e3750fc225569651b02b397..c8758d53cdac056fab72ce22a698b1ee70f6cd37 100644
--- a/src/mol-gl/renderable.ts
+++ b/src/mol-gl/renderable.ts
@@ -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>
  */
@@ -10,7 +10,6 @@ import { GraphicsRenderItem, ComputeRenderItem, GraphicsRenderVariant } from './
 import { ValueCell } from '../mol-util';
 import { idFactory } from '../mol-util/id-factory';
 import { clamp } from '../mol-math/interpolate';
-import { Textures } from './webgl/texture';
 
 const getNextRenderableId = idFactory();
 
@@ -30,7 +29,7 @@ export interface Renderable<T extends RenderableValues> {
     readonly values: T
     readonly state: RenderableState
 
-    render: (variant: GraphicsRenderVariant, sharedTexturesList?: Textures) => void
+    render: (variant: GraphicsRenderVariant, sharedTexturesCount: number) => void
     getProgram: (variant: GraphicsRenderVariant) => Program
     update: () => void
     dispose: () => void
@@ -43,11 +42,11 @@ export function createRenderable<T extends Values<RenderableSchema>>(renderItem:
         values,
         state,
 
-        render: (variant: GraphicsRenderVariant, sharedTexturesList?: Textures) => {
+        render: (variant: GraphicsRenderVariant, sharedTexturesCount: number) => {
             if (values.uAlpha && values.alpha) {
                 ValueCell.updateIfChanged(values.uAlpha, clamp(values.alpha.ref.value * state.alphaFactor, 0, 1));
             }
-            renderItem.render(variant, sharedTexturesList);
+            renderItem.render(variant, sharedTexturesCount);
         },
         getProgram: (variant: GraphicsRenderVariant) => renderItem.getProgram(variant),
         update: () => renderItem.update(),
@@ -73,7 +72,7 @@ export function createComputeRenderable<T extends Values<RenderableSchema>>(rend
         id: getNextRenderableId(),
         values,
 
-        render: () => renderItem.render('compute'),
+        render: () => renderItem.render('compute', 0),
         update: () => renderItem.update(),
         dispose: () => renderItem.destroy()
     };
diff --git a/src/mol-gl/renderer.ts b/src/mol-gl/renderer.ts
index 93d7e73fd85dfb257d129112ba83102e93557052..8c6a4710b764e7be2a87dc7784a67675e15b820f 100644
--- a/src/mol-gl/renderer.ts
+++ b/src/mol-gl/renderer.ts
@@ -258,6 +258,7 @@ namespace Renderer {
             if (globalUniformsNeedUpdate) {
                 // console.log('globalUniformsNeedUpdate')
                 program.setUniforms(globalUniformList);
+                program.bindTextures(sharedTexturesList, 0);
                 globalUniformsNeedUpdate = false;
             }
 
@@ -315,7 +316,7 @@ namespace Renderer {
                 }
             }
 
-            r.render(variant, sharedTexturesList);
+            r.render(variant, sharedTexturesList.length);
         };
 
         const update = (camera: ICamera) => {
diff --git a/src/mol-gl/webgl/render-item.ts b/src/mol-gl/webgl/render-item.ts
index f25090291d9a891331e313133817586396949d7a..04fd09723e37a842ca8c702e630fe7bd45c840a8 100644
--- a/src/mol-gl/webgl/render-item.ts
+++ b/src/mol-gl/webgl/render-item.ts
@@ -1,11 +1,11 @@
 /**
- * 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 { createAttributeBuffers, ElementsBuffer, AttributeKind } from './buffer';
-import { createTextures, Texture, Textures } from './texture';
+import { createTextures, Texture } from './texture';
 import { WebGLContext, checkError } from './context';
 import { ShaderCode, DefineValues } from '../shader-code';
 import { Program } from './program';
@@ -42,7 +42,7 @@ export interface RenderItem<T extends string> {
     readonly materialId: number
     getProgram: (variant: T) => Program
 
-    render: (variant: T, sharedTexturesList?: Textures) => void
+    render: (variant: T, sharedTexturesCount: number) => void
     update: () => Readonly<ValueChanges>
     destroy: () => void
 }
@@ -166,17 +166,12 @@ export function createRenderItem<T extends string>(ctx: WebGLContext, drawMode:
         materialId,
         getProgram: (variant: T) => programs[variant],
 
-        render: (variant: T, sharedTexturesList?: Textures) => {
+        render: (variant: T, sharedTexturesCount: number) => {
             if (drawCount === 0 || instanceCount === 0 || ctx.isContextLost) return;
             const program = programs[variant];
             if (program.id === currentProgramId && state.currentRenderItemId === id) {
                 program.setUniforms(uniformValueEntries);
-                if (sharedTexturesList && sharedTexturesList.length > 0) {
-                    program.bindTextures(sharedTexturesList, 0);
-                    program.bindTextures(textures, sharedTexturesList.length);
-                } else {
-                    program.bindTextures(textures, 0);
-                }
+                program.bindTextures(textures, sharedTexturesCount);
             } else {
                 const vertexArray = vertexArrays[variant];
                 if (program.id !== state.currentProgramId || program.id !== currentProgramId ||
@@ -190,12 +185,7 @@ export function createRenderItem<T extends string>(ctx: WebGLContext, drawMode:
                 }
                 program.setUniforms(uniformValueEntries);
                 program.setUniforms(frontBufferUniformValueEntries);
-                if (sharedTexturesList && sharedTexturesList.length > 0) {
-                    program.bindTextures(sharedTexturesList, 0);
-                    program.bindTextures(textures, sharedTexturesList.length);
-                } else {
-                    program.bindTextures(textures, 0);
-                }
+                program.bindTextures(textures, sharedTexturesCount);
                 if (vertexArray) {
                     vertexArray.bind();
                     // need to bind elements buffer explicitly since it is not always recorded in the VAO