diff --git a/src/mol-canvas3d/canvas3d.ts b/src/mol-canvas3d/canvas3d.ts
index 4e3574b88fcac7d01359f7556b9b0276e4079bc5..c3de16b2ba485769268b7d703d13e8308eb66e67 100644
--- a/src/mol-canvas3d/canvas3d.ts
+++ b/src/mol-canvas3d/canvas3d.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>
  * @author David Sehnal <david.sehnal@gmail.com>
@@ -469,6 +469,13 @@ namespace Canvas3D {
                 materialId: r.materialId,
             })));
             console.log(webgl.stats);
+
+            const { texture, attribute, elements } = webgl.resources.getByteCounts();
+            console.log({
+                texture: `${(texture / 1024 / 1024).toFixed(3)} MiB`,
+                attribute: `${(attribute / 1024 / 1024).toFixed(3)} MiB`,
+                elements: `${(elements / 1024 / 1024).toFixed(3)} MiB`,
+            });
         }
 
         function add(repr: Representation.Any) {
diff --git a/src/mol-gl/webgl/resources.ts b/src/mol-gl/webgl/resources.ts
index dc0bcdee13faecb27f3faa5dab3c0c7d92238f69..047c658d6996dca191ad9c123fd8419d5ff7967b 100644
--- a/src/mol-gl/webgl/resources.ts
+++ b/src/mol-gl/webgl/resources.ts
@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2020-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
@@ -45,6 +45,12 @@ interface Resource {
 
 type ResourceName = keyof WebGLStats['resourceCounts']
 
+type ByteCounts = {
+    texture: number
+    attribute: number
+    elements: number
+}
+
 export interface WebGLResources {
     attribute: (array: ArrayType, itemSize: AttributeItemSize, divisor: number, usageHint?: UsageHint) => AttributeBuffer
     elements: (array: ElementsType, usageHint?: UsageHint) => ElementsBuffer
@@ -55,6 +61,8 @@ export interface WebGLResources {
     texture: (kind: TextureKind, format: TextureFormat, type: TextureType, filter: TextureFilter) => Texture,
     vertexArray: (program: Program, attributeBuffers: AttributeBuffers, elementsBuffer?: ElementsBuffer) => VertexArray,
 
+    getByteCounts: () => ByteCounts
+
     reset: () => void
     destroy: () => void
 }
@@ -128,6 +136,25 @@ export function createResources(gl: GLRenderingContext, state: WebGLState, stats
             return wrap('vertexArray', createVertexArray(extensions, program, attributeBuffers, elementsBuffer));
         },
 
+        getByteCounts: () => {
+            let texture = 0;
+            sets.texture.forEach(r => {
+                texture += (r as Texture).getByteCount();
+            });
+
+            let attribute = 0;
+            sets.attribute.forEach(r => {
+                attribute += (r as AttributeBuffer).length * 4;
+            });
+
+            let elements = 0;
+            sets.elements.forEach(r => {
+                elements += (r as ElementsBuffer).length * 4;
+            });
+
+            return { texture, attribute, elements };
+        },
+
         reset: () => {
             sets.attribute.forEach(r => r.reset());
             sets.elements.forEach(r => r.reset());
diff --git a/src/mol-gl/webgl/texture.ts b/src/mol-gl/webgl/texture.ts
index 0cd5edd669ac9a8577879ca5c9eb06359dce5d7e..3847d82d313e809843fad5f5b2da189458dc8509 100644
--- a/src/mol-gl/webgl/texture.ts
+++ b/src/mol-gl/webgl/texture.ts
@@ -90,6 +90,29 @@ export function getInternalFormat(gl: GLRenderingContext, format: TextureFormat,
     return getFormat(gl, format, type);
 }
 
+function getByteCount(format: TextureFormat, type: TextureType, width: number, height: number, depth: number): number {
+    const bpe = getFormatSize(format) * getTypeSize(type);
+    return bpe * width * height * (depth || 1);
+}
+
+function getFormatSize(format: TextureFormat) {
+    switch (format) {
+        case 'alpha': return 1;
+        case 'rgb': return 3;
+        case 'rgba': return 4;
+        case 'depth': return 4;
+    }
+}
+
+function getTypeSize(type: TextureType): number {
+    switch (type) {
+        case 'ubyte': return 1;
+        case 'ushort': return 2;
+        case 'float': return 4;
+        case 'fp16': return 2;
+    }
+}
+
 export function getType(gl: GLRenderingContext, extensions: WebGLExtensions, type: TextureType): number {
     switch (type) {
         case 'ubyte': return gl.UNSIGNED_BYTE;
@@ -147,6 +170,8 @@ export interface Texture {
     getHeight: () => number
     getDepth: () => number
 
+    getByteCount: () => number
+
     define: (width: number, height: number, depth?: number) => void
     load: (image: TextureImage<any> | TextureVolume<any>) => void
     bind: (id: TextureId) => void
@@ -265,6 +290,8 @@ export function createTexture(gl: GLRenderingContext, extensions: WebGLExtension
         getHeight: () => height,
         getDepth: () => depth,
 
+        getByteCount: () => getByteCount(_format, _type, width, height, depth),
+
         define,
         load,
         bind: (id: TextureId) => {
@@ -339,6 +366,7 @@ export function createNullTexture(gl: GLRenderingContext, kind: TextureKind): Te
         getWidth: () => 0,
         getHeight: () => 0,
         getDepth: () => 0,
+        getByteCount: () => 0,
 
         define: () => {},
         load: () => {},