Alexander Rose пре 6 година
родитељ
комит
4783d1aa11

+ 9 - 9
src/mol-gl/_spec/renderer.spec.ts

@@ -117,9 +117,9 @@ describe('renderer', () => {
         expect(ctx.gl.canvas.width).toBe(32)
         expect(ctx.gl.canvas.height).toBe(32)
 
-        expect(ctx.bufferCount).toBe(0);
-        expect(ctx.textureCount).toBe(0);
-        expect(ctx.vaoCount).toBe(0);
+        expect(ctx.stats.bufferCount).toBe(0);
+        expect(ctx.stats.textureCount).toBe(0);
+        expect(ctx.stats.vaoCount).toBe(0);
         expect(ctx.programCache.count).toBe(0);
         expect(ctx.shaderCache.count).toBe(0);
 
@@ -137,16 +137,16 @@ describe('renderer', () => {
         const points = createPoints()
 
         scene.add(points)
-        expect(ctx.bufferCount).toBe(4);
-        expect(ctx.textureCount).toBe(5);
-        expect(ctx.vaoCount).toBe(4);
+        expect(ctx.stats.bufferCount).toBe(4);
+        expect(ctx.stats.textureCount).toBe(5);
+        expect(ctx.stats.vaoCount).toBe(4);
         expect(ctx.programCache.count).toBe(4);
         expect(ctx.shaderCache.count).toBe(8);
 
         scene.remove(points)
-        expect(ctx.bufferCount).toBe(0);
-        expect(ctx.textureCount).toBe(0);
-        expect(ctx.vaoCount).toBe(0);
+        expect(ctx.stats.bufferCount).toBe(0);
+        expect(ctx.stats.textureCount).toBe(0);
+        expect(ctx.stats.vaoCount).toBe(0);
         expect(ctx.programCache.count).toBe(4);
         expect(ctx.shaderCache.count).toBe(8);
 

+ 2 - 1
src/mol-gl/renderable/util.ts

@@ -65,7 +65,8 @@ export function printImageData(imageData: ImageData, scale = 1) {
         const img = document.createElement('img')
         img.src = objectURL
         img.style.width = imageData.width * scale + 'px'
-        img.style.height = imageData.height * scale + 'px'
+        img.style.height = imageData.height * scale + 'px';
+        (img.style as any).imageRendering = 'pixelated' // works in Chrome
         img.style.position = 'absolute'
         img.style.top = '0px'
         img.style.left = '0px'

+ 10 - 10
src/mol-gl/renderer.ts

@@ -53,7 +53,7 @@ export type RendererProps = typeof DefaultRendererProps
 
 namespace Renderer {
     export function create(ctx: WebGLContext, camera: Camera, props: Partial<RendererProps> = {}): Renderer {
-        const { gl } = ctx
+        const { gl, state, stats } = ctx
         let { clearColor, viewport: _viewport, pickingAlphaThreshold } = { ...DefaultRendererProps, ...props }
 
         const viewport = Viewport.clone(_viewport)
@@ -111,7 +111,7 @@ namespace Renderer {
         const renderObject = (r: Renderable<RenderableValues & BaseValues>, variant: RenderVariant) => {
             const program = r.getProgram(variant)
             if (r.state.visible) {
-                if (ctx.currentProgramId !== program.id) {
+                if (state.currentProgramId !== program.id) {
                     // console.log('new program')
                     globalUniformsNeedUpdate = true
                 }
@@ -238,15 +238,15 @@ namespace Renderer {
                     programCount: ctx.programCache.count,
                     shaderCount: ctx.shaderCache.count,
 
-                    bufferCount: ctx.bufferCount,
-                    framebufferCount: ctx.framebufferCount,
-                    renderbufferCount: ctx.renderbufferCount,
-                    textureCount: ctx.textureCount,
-                    vaoCount: ctx.vaoCount,
+                    bufferCount: stats.bufferCount,
+                    framebufferCount: stats.framebufferCount,
+                    renderbufferCount: stats.renderbufferCount,
+                    textureCount: stats.textureCount,
+                    vaoCount: stats.vaoCount,
 
-                    drawCount: ctx.drawCount,
-                    instanceCount: ctx.instanceCount,
-                    instancedDrawCount: ctx.instancedDrawCount,
+                    drawCount: stats.drawCount,
+                    instanceCount: stats.instanceCount,
+                    instancedDrawCount: stats.instancedDrawCount,
                 }
             },
             dispose: () => {

+ 14 - 9
src/mol-gl/shader-code.ts

@@ -6,7 +6,8 @@
 
 import { ValueCell } from 'mol-util';
 import { idFactory } from 'mol-util/id-factory';
-import { WebGLContext } from './webgl/context';
+import { WebGLExtensions } from './webgl/context';
+import { isWebGL2, GLRenderingContext } from './webgl/compat';
 
 export type DefineKind = 'boolean' | 'string' | 'number'
 export type DefineType = boolean | string
@@ -66,6 +67,8 @@ export const DirectVolumeShaderCode = ShaderCode(
     { standardDerivatives: false, fragDepth: true }
 )
 
+
+
 export type ShaderDefines = {
     [k: string]: ValueCell<DefineType>
 }
@@ -91,16 +94,18 @@ function getDefinesCode (defines: ShaderDefines) {
     return lines.join('\n') + '\n'
 }
 
-function getGlsl100FragPrefix(ctx: WebGLContext, extensions: ShaderExtensions) {
+function getGlsl100FragPrefix(extensions: WebGLExtensions, shaderExtensions: ShaderExtensions) {
     const prefix: string[] = []
-    if (extensions.standardDerivatives) {
+    if (shaderExtensions.standardDerivatives) {
         prefix.push('#extension GL_OES_standard_derivatives : enable')
         prefix.push('#define enabledStandardDerivatives')
     }
-    if (extensions.fragDepth) {
-        if (ctx.extensions.fragDepth) {
+    if (shaderExtensions.fragDepth) {
+        if (extensions.fragDepth) {
             prefix.push('#extension GL_EXT_frag_depth : enable')
             prefix.push('#define enabledFragDepth')
+        } else {
+            throw new Error(`requested 'GL_EXT_frag_depth' extension is unavailable`)
         }
     }
     return prefix.join('\n') + '\n'
@@ -123,11 +128,11 @@ layout(location = 0) out highp vec4 out_FragColor;
 #define enabledFragDepth
 `
 
-export function addShaderDefines(ctx: WebGLContext, defines: ShaderDefines, shaders: ShaderCode): ShaderCode {
-    const { isWebGL2 } = ctx
+export function addShaderDefines(gl: GLRenderingContext, extensions: WebGLExtensions, defines: ShaderDefines, shaders: ShaderCode): ShaderCode {
+    const webgl2 = isWebGL2(gl)
     const header = getDefinesCode(defines)
-    const vertPrefix = isWebGL2 ? glsl300VertPrefix : ''
-    const fragPrefix = isWebGL2 ? glsl300FragPrefix : getGlsl100FragPrefix(ctx, shaders.extensions)
+    const vertPrefix = webgl2 ? glsl300VertPrefix : ''
+    const fragPrefix = webgl2 ? glsl300FragPrefix : getGlsl100FragPrefix(extensions, shaders.extensions)
     return {
         id: shaderCodeId(),
         vert: `${vertPrefix}${header}${shaders.vert}`,

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

@@ -9,6 +9,7 @@ import { ValueCell } from 'mol-util';
 import { RenderableSchema } from '../renderable/schema';
 import { idFactory } from 'mol-util/id-factory';
 import { ValueOf } from 'mol-util/type-helpers';
+import { GLRenderingContext } from './compat';
 
 const getNextBufferId = idFactory()
 
@@ -97,7 +98,7 @@ export interface Buffer {
 }
 
 export function createBuffer(ctx: WebGLContext, array: ArrayType, usageHint: UsageHint, bufferType: BufferType): Buffer {
-    const { gl } = ctx
+    const { gl, stats } = ctx
     const _buffer = gl.createBuffer()
     if (_buffer === null) {
         throw new Error('Could not create WebGL buffer')
@@ -116,7 +117,7 @@ export function createBuffer(ctx: WebGLContext, array: ArrayType, usageHint: Usa
     updateData(array)
 
     let destroyed = false
-    ctx.bufferCount += 1
+    stats.bufferCount += 1
 
     return {
         id: getNextBufferId(),
@@ -139,7 +140,7 @@ export function createBuffer(ctx: WebGLContext, array: ArrayType, usageHint: Usa
             if (destroyed) return
             gl.deleteBuffer(_buffer)
             destroyed = true
-            ctx.bufferCount -= 1
+            stats.bufferCount -= 1
         }
     }
 }
@@ -149,8 +150,7 @@ export function createBuffer(ctx: WebGLContext, array: ArrayType, usageHint: Usa
 export type AttributeItemSize = 1 | 2 | 3 | 4 | 16
 export type AttributeKind = 'float32' | 'int32'
 
-export function getAttribType(ctx: WebGLContext, kind: AttributeKind, itemSize: AttributeItemSize) {
-    const { gl } = ctx
+export function getAttribType(gl: GLRenderingContext, kind: AttributeKind, itemSize: AttributeItemSize) {
     switch (kind) {
         case 'int32':
             switch (itemSize) {

+ 61 - 42
src/mol-gl/webgl/context.ts

@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
@@ -113,7 +113,7 @@ export function createImageData(buffer: ArrayLike<number>, width: number, height
 
 //
 
-type Extensions = {
+export type WebGLExtensions = {
     instancedArrays: COMPAT_instanced_arrays
     standardDerivatives: COMPAT_standard_derivatives
     blendMinMax: COMPAT_blend_minmax
@@ -124,20 +124,7 @@ type Extensions = {
     fragDepth: COMPAT_frag_depth | null
 }
 
-/** A WebGL context object, including the rendering context, resource caches and counts */
-export interface WebGLContext {
-    readonly gl: GLRenderingContext
-    readonly isWebGL2: boolean
-    readonly extensions: Extensions
-    readonly pixelRatio: number
-
-    readonly shaderCache: ShaderCache
-    readonly programCache: ProgramCache
-    readonly framebufferCache: FramebufferCache
-
-    currentProgramId: number
-    currentMaterialId: number
-
+export type WebGLStats = {
     bufferCount: number
     framebufferCount: number
     renderbufferCount: number
@@ -147,6 +134,26 @@ export interface WebGLContext {
     drawCount: number
     instanceCount: number
     instancedDrawCount: number
+}
+
+export type WebGLState = {
+    currentProgramId: number
+    currentMaterialId: number
+}
+
+/** A WebGL context object, including the rendering context, resource caches and counts */
+export interface WebGLContext {
+    readonly gl: GLRenderingContext
+    readonly isWebGL2: boolean
+    readonly pixelRatio: number
+
+    readonly extensions: WebGLExtensions
+    readonly state: WebGLState
+    readonly stats: WebGLStats
+
+    readonly shaderCache: ShaderCache
+    readonly programCache: ProgramCache
+    readonly framebufferCache: FramebufferCache
 
     readonly maxTextureSize: number
     readonly maxDrawBuffers: number
@@ -193,9 +200,37 @@ export function createContext(gl: GLRenderingContext): WebGLContext {
         console.log('Could not find support for "frag_depth"')
     }
 
-    const shaderCache = createShaderCache()
-    const programCache = createProgramCache()
-    const framebufferCache = createFramebufferCache()
+    const state: WebGLState = {
+        currentProgramId: -1,
+        currentMaterialId: -1,
+    }
+
+    const stats: WebGLStats = {
+        bufferCount: 0,
+        framebufferCount: 0,
+        renderbufferCount: 0,
+        textureCount: 0,
+        vaoCount: 0,
+
+        drawCount: 0,
+        instanceCount: 0,
+        instancedDrawCount: 0,
+    }
+
+    const extensions: WebGLExtensions = {
+        instancedArrays,
+        standardDerivatives,
+        blendMinMax,
+        textureFloat,
+        textureFloatLinear,
+        elementIndexUint,
+        vertexArrayObject,
+        fragDepth
+    }
+
+    const shaderCache: ShaderCache = createShaderCache(gl)
+    const programCache: ProgramCache = createProgramCache(gl, state, extensions, shaderCache)
+    const framebufferCache: FramebufferCache = createFramebufferCache(gl, stats)
 
     const parameters = {
         maxTextureSize: gl.getParameter(gl.MAX_TEXTURE_SIZE),
@@ -247,35 +282,19 @@ export function createContext(gl: GLRenderingContext): WebGLContext {
     return {
         gl,
         isWebGL2: isWebGL2(gl),
-        extensions: {
-            instancedArrays,
-            standardDerivatives,
-            blendMinMax,
-            textureFloat,
-            textureFloatLinear,
-            elementIndexUint,
-            vertexArrayObject,
-            fragDepth
+        get pixelRatio () {
+            // this can change during the lifetime of a rendering context, so need to re-obtain on access
+            return getPixelRatio()
         },
-        get pixelRatio () { return getPixelRatio() },
+
+        extensions,
+        state,
+        stats,
 
         shaderCache,
         programCache,
         framebufferCache,
 
-        currentProgramId: -1,
-        currentMaterialId: -1,
-
-        bufferCount: 0,
-        framebufferCount: 0,
-        renderbufferCount: 0,
-        textureCount: 0,
-        vaoCount: 0,
-
-        drawCount: 0,
-        instanceCount: 0,
-        instancedDrawCount: 0,
-
         get maxTextureSize () { return parameters.maxTextureSize },
         get maxDrawBuffers () { return parameters.maxDrawBuffers },
 

+ 9 - 9
src/mol-gl/webgl/framebuffer.ts

@@ -1,12 +1,13 @@
 /**
- * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
 
-import { WebGLContext } from './context'
+import { WebGLStats } from './context'
 import { idFactory } from 'mol-util/id-factory';
 import { ReferenceCache, createReferenceCache } from 'mol-util/reference-cache';
+import { GLRenderingContext } from './compat';
 
 const getNextFramebufferId = idFactory()
 
@@ -17,15 +18,14 @@ export interface Framebuffer {
     destroy: () => void
 }
 
-export function createFramebuffer (ctx: WebGLContext): Framebuffer {
-    const { gl } = ctx
+export function createFramebuffer (gl: GLRenderingContext, stats: WebGLStats): Framebuffer {
     const _framebuffer = gl.createFramebuffer()
     if (_framebuffer === null) {
         throw new Error('Could not create WebGL framebuffer')
     }
 
     let destroyed = false
-    ctx.framebufferCount += 1
+    stats.framebufferCount += 1
 
     return {
         id: getNextFramebufferId(),
@@ -35,17 +35,17 @@ export function createFramebuffer (ctx: WebGLContext): Framebuffer {
             if (destroyed) return
             gl.deleteFramebuffer(_framebuffer)
             destroyed = true
-            ctx.framebufferCount -= 1
+            stats.framebufferCount -= 1
         }
     }
 }
 
-export type FramebufferCache = ReferenceCache<Framebuffer, string, WebGLContext>
+export type FramebufferCache = ReferenceCache<Framebuffer, string>
 
-export function createFramebufferCache(): FramebufferCache {
+export function createFramebufferCache(gl: GLRenderingContext, stats: WebGLStats): FramebufferCache {
     return createReferenceCache(
         (name: string) => name,
-        (ctx: WebGLContext) => createFramebuffer(ctx),
+        () => createFramebuffer(gl, stats),
         (framebuffer: Framebuffer) => { framebuffer.destroy() }
     )
 }

+ 18 - 20
src/mol-gl/webgl/program.ts

@@ -5,7 +5,7 @@
  */
 
 import { ShaderCode, DefineValues, addShaderDefines } from '../shader-code'
-import { WebGLContext } from './context';
+import { WebGLExtensions, WebGLState } from './context';
 import { getUniformSetters, UniformsList, getUniformType } from './uniform';
 import { AttributeBuffers, getAttribType } from './buffer';
 import { TextureId, Textures } from './texture';
@@ -14,6 +14,8 @@ import { idFactory } from 'mol-util/id-factory';
 import { RenderableSchema } from '../renderable/schema';
 import { hashFnv32a, hashString } from 'mol-data/util';
 import { isProductionMode } from 'mol-util/debug';
+import { GLRenderingContext } from './compat';
+import { ShaderCache } from './shader';
 
 const getNextProgramId = idFactory()
 
@@ -30,8 +32,7 @@ export interface Program {
 
 type Locations = { [k: string]: number }
 
-function getLocations(ctx: WebGLContext, program: WebGLProgram, schema: RenderableSchema) {
-    const { gl } = ctx
+function getLocations(gl: GLRenderingContext, program: WebGLProgram, schema: RenderableSchema) {
     const locations: Locations = {}
     Object.keys(schema).forEach(k => {
         const spec = schema[k]
@@ -48,8 +49,7 @@ function getLocations(ctx: WebGLContext, program: WebGLProgram, schema: Renderab
     return locations
 }
 
-function checkActiveAttributes(ctx: WebGLContext, program: WebGLProgram, schema: RenderableSchema) {
-    const { gl } = ctx
+function checkActiveAttributes(gl: GLRenderingContext, program: WebGLProgram, schema: RenderableSchema) {
     const attribCount = gl.getProgramParameter(program, gl.ACTIVE_ATTRIBUTES);
     for (let i = 0; i < attribCount; ++i) {
         const info = gl.getActiveAttrib(program, i);
@@ -66,7 +66,7 @@ function checkActiveAttributes(ctx: WebGLContext, program: WebGLProgram, schema:
             if (spec.type !== 'attribute') {
                 throw new Error(`'${name}' must be of type 'attribute' but is '${spec.type}'`)
             }
-            const attribType = getAttribType(ctx, spec.kind, spec.itemSize)
+            const attribType = getAttribType(gl, spec.kind, spec.itemSize)
             if (attribType !== type) {
                 throw new Error(`unexpected attribute type for ${name}`)
             }
@@ -74,8 +74,7 @@ function checkActiveAttributes(ctx: WebGLContext, program: WebGLProgram, schema:
     }
 }
 
-function checkActiveUniforms(ctx: WebGLContext, program: WebGLProgram, schema: RenderableSchema) {
-    const { gl } = ctx
+function checkActiveUniforms(gl: GLRenderingContext, program: WebGLProgram, schema: RenderableSchema) {
     const attribCount = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS);
     for (let i = 0; i < attribCount; ++i) {
         const info = gl.getActiveUniform(program, i);
@@ -119,8 +118,7 @@ export interface ProgramProps {
     schema: RenderableSchema
 }
 
-export function createProgram(ctx: WebGLContext, props: ProgramProps): Program {
-    const { gl, shaderCache } = ctx
+export function createProgram(gl: GLRenderingContext, state: WebGLState, extensions: WebGLExtensions, shaderCache: ShaderCache, props: ProgramProps): Program {
     const { defineValues, shaderCode: _shaderCode, schema } = props
 
     const program = gl.createProgram()
@@ -129,9 +127,9 @@ export function createProgram(ctx: WebGLContext, props: ProgramProps): Program {
     }
     const programId = getNextProgramId()
 
-    const shaderCode = addShaderDefines(ctx, defineValues, _shaderCode)
-    const vertShaderRef = shaderCache.get(ctx, { type: 'vert', source: shaderCode.vert })
-    const fragShaderRef = shaderCache.get(ctx, { type: 'frag', source: shaderCode.frag })
+    const shaderCode = addShaderDefines(gl, extensions, defineValues, _shaderCode)
+    const vertShaderRef = shaderCache.get({ type: 'vert', source: shaderCode.vert })
+    const fragShaderRef = shaderCache.get({ type: 'frag', source: shaderCode.frag })
 
     vertShaderRef.value.attach(program)
     fragShaderRef.value.attach(program)
@@ -140,12 +138,12 @@ export function createProgram(ctx: WebGLContext, props: ProgramProps): Program {
         throw new Error(`Could not compile WebGL program. \n\n${gl.getProgramInfoLog(program)}`);
     }
 
-    const locations = getLocations(ctx, program, schema)
+    const locations = getLocations(gl, program, schema)
     const uniformSetters = getUniformSetters(schema)
 
     if (!isProductionMode) {
-        checkActiveAttributes(ctx, program, schema)
-        checkActiveUniforms(ctx, program, schema)
+        checkActiveAttributes(gl, program, schema)
+        checkActiveUniforms(gl, program, schema)
     }
 
     let destroyed = false
@@ -155,7 +153,7 @@ export function createProgram(ctx: WebGLContext, props: ProgramProps): Program {
 
         use: () => {
             // console.log('use', programId)
-            ctx.currentProgramId = programId
+            state.currentProgramId = programId
             gl.useProgram(program)
         },
         setUniforms: (uniformValues: UniformsList) => {
@@ -191,14 +189,14 @@ export function createProgram(ctx: WebGLContext, props: ProgramProps): Program {
     }
 }
 
-export type ProgramCache = ReferenceCache<Program, ProgramProps, WebGLContext>
+export type ProgramCache = ReferenceCache<Program, ProgramProps>
 
 function defineValueHash(v: boolean | number | string): number {
     return typeof v === 'boolean' ? (v ? 1 : 0) :
         typeof v === 'number' ? v : hashString(v)
 }
 
-export function createProgramCache(): ProgramCache {
+export function createProgramCache(gl: GLRenderingContext, state: WebGLState, extensions: WebGLExtensions, shaderCache: ShaderCache): ProgramCache {
     return createReferenceCache(
         (props: ProgramProps) => {
             const array = [ props.shaderCode.id ]
@@ -208,7 +206,7 @@ export function createProgramCache(): ProgramCache {
             })
             return hashFnv32a(array).toString()
         },
-        (ctx: WebGLContext, props: ProgramProps) => createProgram(ctx, props),
+        (props: ProgramProps) => createProgram(gl, state, extensions, shaderCache, props),
         (program: Program) => { program.destroy() }
     )
 }

+ 16 - 14
src/mol-gl/webgl/render-item.ts

@@ -5,7 +5,7 @@
  */
 
 import { createAttributeBuffers, createElementsBuffer, ElementsBuffer, createAttributeBuffer, AttributeKind } from './buffer';
-import { createTextures } from './texture';
+import { createTextures, Texture } from './texture';
 import { WebGLContext } from './context';
 import { ShaderCode } from '../shader-code';
 import { Program } from './program';
@@ -84,7 +84,7 @@ function resetValueChanges(valueChanges: ValueChanges) {
  */
 export function createRenderItem(ctx: WebGLContext, drawMode: DrawMode, shaderCode: ShaderCode, schema: RenderableSchema, values: RenderableValues, materialId: number): RenderItem {
     const id = getNextRenderItemId()
-    const { programCache } = ctx
+    const { stats, state, programCache } = ctx
     const { instancedArrays, vertexArrayObject } = ctx.extensions
 
     const { attributeValues, defineValues, textureValues, uniformValues, materialUniformValues } = splitValues(schema, values)
@@ -100,7 +100,7 @@ export function createRenderItem(ctx: WebGLContext, drawMode: DrawMode, shaderCo
     const programs: ProgramVariants = {}
     Object.keys(RenderVariantDefines).forEach(k => {
         const variantDefineValues: Values<RenderableSchema> = (RenderVariantDefines as any)[k]
-        programs[k] = programCache.get(ctx, {
+        programs[k] = programCache.get({
             defineValues: { ...defineValues, ...variantDefineValues },
             shaderCode,
             schema
@@ -124,9 +124,9 @@ export function createRenderItem(ctx: WebGLContext, drawMode: DrawMode, shaderCo
     let drawCount = values.drawCount.ref.value
     let instanceCount = values.instanceCount.ref.value
 
-    ctx.drawCount += drawCount
-    ctx.instanceCount += instanceCount
-    ctx.instancedDrawCount += instanceCount * drawCount
+    stats.drawCount += drawCount
+    stats.instanceCount += instanceCount
+    stats.instancedDrawCount += instanceCount * drawCount
 
     const valueChanges = createValueChanges()
 
@@ -144,12 +144,12 @@ export function createRenderItem(ctx: WebGLContext, drawMode: DrawMode, shaderCo
             const vertexArray = vertexArrays[variant]
             program.setUniforms(uniformValueEntries)
             if (program.id !== currentProgramId ||
-                materialId === -1 || materialId !== ctx.currentMaterialId
+                materialId === -1 || materialId !== state.currentMaterialId
             ) {
                 // console.log('program.id changed or materialId changed/-1', materialId)
                 program.setUniforms(materialUniformValueEntries)
                 currentProgramId = program.id
-                ctx.currentMaterialId = materialId
+                state.currentMaterialId = materialId
             }
             program.bindTextures(textures)
             if (vertexArrayObject && vertexArray) {
@@ -183,7 +183,7 @@ export function createRenderItem(ctx: WebGLContext, drawMode: DrawMode, shaderCo
                 Object.keys(RenderVariantDefines).forEach(k => {
                     const variantDefineValues: Values<RenderableSchema> = (RenderVariantDefines as any)[k]
                     programs[k].free()
-                    programs[k] = programCache.get(ctx, {
+                    programs[k] = programCache.get({
                         defineValues: { ...defineValues, ...variantDefineValues },
                         shaderCode,
                         schema
@@ -193,15 +193,15 @@ export function createRenderItem(ctx: WebGLContext, drawMode: DrawMode, shaderCo
 
             if (values.drawCount.ref.version !== versions.drawCount) {
                 // console.log('drawCount version changed')
-                ctx.drawCount += values.drawCount.ref.value - drawCount
-                ctx.instancedDrawCount += instanceCount * values.drawCount.ref.value - instanceCount * drawCount
+                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')
-                ctx.instanceCount += values.instanceCount.ref.value - instanceCount
-                ctx.instancedDrawCount += values.instanceCount.ref.value * drawCount - instanceCount * drawCount
+                stats.instanceCount += values.instanceCount.ref.value - instanceCount
+                stats.instancedDrawCount += values.instanceCount.ref.value * drawCount - instanceCount * drawCount
                 instanceCount = values.instanceCount.ref.value
                 versions.instanceCount = values.instanceCount.ref.version
             }
@@ -217,7 +217,7 @@ export function createRenderItem(ctx: WebGLContext, drawMode: DrawMode, shaderCo
                         // console.log('attribute array to small, need to create new attribute', k, value.ref.id, value.ref.version)
                         buffer.destroy()
                         const { itemSize, divisor } = schema[k] as AttributeSpec<AttributeKind>
-                        attributeBuffers[i] = [k, createAttributeBuffer(ctx, value.ref.value, itemSize, divisor)]
+                        attributeBuffers[i][1] = createAttributeBuffer(ctx, value.ref.value, itemSize, divisor)
                         valueChanges.attributes = true
                     }
                     versions[k] = value.ref.version
@@ -264,6 +264,8 @@ export function createRenderItem(ctx: WebGLContext, drawMode: DrawMode, shaderCo
                         texture.load(value.ref.value as TextureImage<any> | TextureVolume<any>)
                         versions[k] = value.ref.version
                         valueChanges.textures = true
+                    } else {
+                        textures[i][1] = value.ref.value as Texture
                     }
                 }
             }

+ 2 - 2
src/mol-gl/webgl/render-target.ts

@@ -31,7 +31,7 @@ export interface RenderTarget {
 }
 
 export function createRenderTarget (ctx: WebGLContext, _width: number, _height: number): RenderTarget {
-    const { gl } = ctx
+    const { gl, stats } = ctx
 
     const image: Mutable<TextureImage<Uint8Array>> = {
         array: new Uint8Array(_width * _height * 4),
@@ -42,7 +42,7 @@ export function createRenderTarget (ctx: WebGLContext, _width: number, _height:
     const targetTexture = createTexture(ctx, 'image-uint8', 'rgba', 'ubyte', 'linear')
     targetTexture.load(image)
 
-    const framebuffer = createFramebuffer(ctx)
+    const framebuffer = createFramebuffer(gl, stats)
 
     // attach the texture as the first color attachment
     targetTexture.attachFramebuffer(framebuffer, 'color0')

+ 3 - 3
src/mol-gl/webgl/renderbuffer.ts

@@ -42,7 +42,7 @@ export interface Renderbuffer {
 }
 
 export function createRenderbuffer (ctx: WebGLContext, format: RenderbufferFormat, attachment: RenderbufferAttachment, _width: number, _height: number): Renderbuffer {
-    const { gl } = ctx
+    const { gl, stats } = ctx
     const _renderbuffer = gl.createRenderbuffer()
     if (_renderbuffer === null) {
         throw new Error('Could not create WebGL renderbuffer')
@@ -57,7 +57,7 @@ export function createRenderbuffer (ctx: WebGLContext, format: RenderbufferForma
     gl.framebufferRenderbuffer(gl.FRAMEBUFFER, _attachment, gl.RENDERBUFFER, _renderbuffer)
 
     let destroyed = false
-    ctx.renderbufferCount += 1
+    stats.renderbufferCount += 1
 
     return {
         id: getNextRenderbufferId(),
@@ -72,7 +72,7 @@ export function createRenderbuffer (ctx: WebGLContext, format: RenderbufferForma
             if (destroyed) return
             gl.deleteRenderbuffer(_renderbuffer)
             destroyed = true
-            ctx.framebufferCount -= 1
+            stats.framebufferCount -= 1
         }
     }
 }

+ 6 - 7
src/mol-gl/webgl/shader.ts

@@ -1,12 +1,12 @@
 /**
- * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
 
 import { createReferenceCache, ReferenceCache } from 'mol-util/reference-cache';
-import { WebGLContext } from './context';
 import { idFactory } from 'mol-util/id-factory';
+import { GLRenderingContext } from './compat';
 
 const getNextShaderId = idFactory()
 
@@ -26,8 +26,7 @@ export interface Shader {
     destroy: () => void
 }
 
-function createShader(ctx: WebGLContext, props: ShaderProps): Shader {
-    const { gl } = ctx
+function createShader(gl: GLRenderingContext, props: ShaderProps): Shader {
     const { type, source } = props
 
     const shader = gl.createShader(type === 'vert' ? gl.VERTEX_SHADER : gl.FRAGMENT_SHADER)
@@ -54,12 +53,12 @@ function createShader(ctx: WebGLContext, props: ShaderProps): Shader {
     }
 }
 
-export type ShaderCache = ReferenceCache<Shader, ShaderProps, WebGLContext>
+export type ShaderCache = ReferenceCache<Shader, ShaderProps>
 
-export function createShaderCache(): ShaderCache {
+export function createShaderCache(gl: GLRenderingContext): ShaderCache {
     return createReferenceCache(
         (props: ShaderProps) => JSON.stringify(props),
-        (ctx: WebGLContext, props: ShaderProps) => createShader(ctx, props),
+        (props: ShaderProps) => createShader(gl, props),
         (shader: Shader) => { shader.destroy() }
     )
 }

+ 4 - 4
src/mol-gl/webgl/texture.ts

@@ -42,7 +42,7 @@ export function getTarget(ctx: WebGLContext, kind: TextureKind): number {
             case 'volume-float32': return gl.TEXTURE_3D
         }
     }
-    throw new Error('unknown texture kind')
+    throw new Error(`unknown texture kind '${kind}'`)
 }
 
 export function getFormat(ctx: WebGLContext, format: TextureFormat): number {
@@ -143,7 +143,7 @@ export type Textures = [string, Texture][]
 
 export function createTexture(ctx: WebGLContext, kind: TextureKind, _format: TextureFormat, _type: TextureType, _filter: TextureFilter): Texture {
     const id = getNextTextureId()
-    const { gl } = ctx
+    const { gl, stats } = ctx
     const texture = gl.createTexture()
     if (texture === null) {
         throw new Error('Could not create WebGL texture')
@@ -166,7 +166,7 @@ export function createTexture(ctx: WebGLContext, kind: TextureKind, _format: Tex
     let width = 0, height = 0, depth = 0
 
     let destroyed = false
-    ctx.textureCount += 1
+    stats.textureCount += 1
 
     return {
         id,
@@ -238,7 +238,7 @@ export function createTexture(ctx: WebGLContext, kind: TextureKind, _format: Tex
             if (destroyed) return
             gl.deleteTexture(texture)
             destroyed = true
-            ctx.textureCount -= 1
+            stats.textureCount -= 1
         }
     }
 }

+ 2 - 2
src/mol-gl/webgl/vertex-array.ts

@@ -16,7 +16,7 @@ export function createVertexArray(ctx: WebGLContext, program: Program, attribute
         vertexArrayObject.bindVertexArray(vertexArray)
         if (elementsBuffer) elementsBuffer.bind()
         program.bindAttributes(attributeBuffers)
-        ctx.vaoCount += 1
+        ctx.stats.vaoCount += 1
         vertexArrayObject.bindVertexArray(null)
     }
     return vertexArray
@@ -36,6 +36,6 @@ export function deleteVertexArray(ctx: WebGLContext, vertexArray: WebGLVertexArr
     const { vertexArrayObject } = ctx.extensions
     if (vertexArrayObject && vertexArray) {
         vertexArrayObject.deleteVertexArray(vertexArray)
-        ctx.vaoCount -= 1
+        ctx.stats.vaoCount -= 1
     }
 }

+ 4 - 3
src/mol-math/geometry/gaussian-density/gpu.ts

@@ -110,7 +110,7 @@ async function calcGaussianDensityTexture2d(ctx: RuntimeContext, webgl: WebGLCon
     const { gl, framebufferCache } = webgl
     const { uCurrentSlice, uCurrentX, uCurrentY } = renderable.values
 
-    const framebuffer = framebufferCache.get(webgl, FramebufferName).value
+    const framebuffer = framebufferCache.get(FramebufferName).value
     framebuffer.bind()
     setRenderingDefaults(gl)
 
@@ -168,7 +168,7 @@ async function calcGaussianDensityTexture3d(ctx: RuntimeContext, webgl: WebGLCon
     const { gl, framebufferCache } = webgl
     const { uCurrentSlice } = renderable.values
 
-    const framebuffer = framebufferCache.get(webgl, FramebufferName).value
+    const framebuffer = framebufferCache.get(FramebufferName).value
     framebuffer.bind()
     setRenderingDefaults(gl)
     gl.viewport(0, 0, dx, dy)
@@ -312,6 +312,7 @@ function setupGroupIdRendering(webgl: WebGLContext, renderable: ComputeRenderabl
 }
 
 function getTexture2dSize(maxTexSize: number, gridDim: Vec3) {
+    maxTexSize = 256
     let texDimX = 0
     let texDimY = gridDim[1]
     let texRows = 1
@@ -342,7 +343,7 @@ async function fieldFromTexture2d(ctx: WebGLContext, texture: Texture, dim: Vec3
 
     const image = new Uint8Array(width * height * 4)
 
-    const framebuffer = framebufferCache.get(ctx, FramebufferName).value
+    const framebuffer = framebufferCache.get(FramebufferName).value
     framebuffer.bind()
     texture.attachFramebuffer(framebuffer, 0)
     // TODO too slow, why? Too many checks if gpu ready???

+ 4 - 5
src/mol-util/_spec/reference-cache.spec.ts

@@ -10,20 +10,19 @@ describe('reference-cache', () => {
     it('basic', () => {
         const refCache = createReferenceCache(
             (x: number) => x.toString(),
-            (ctx: {}, x) => x,
+            (x) => x,
             () => {}
         )
         expect(refCache.count).toBe(0)
 
-        const ctx = {}
-        const ref2a = refCache.get(ctx, 2)
+        const ref2a = refCache.get(2)
         expect(refCache.count).toBe(1)
 
-        const ref2b = refCache.get(ctx, 2)
+        const ref2b = refCache.get(2)
         expect(refCache.count).toBe(1)
         expect(ref2b.value).toBe(2)
 
-        const ref3 = refCache.get(ctx, 3)
+        const ref3 = refCache.get(3)
         expect(refCache.count).toBe(2)
         expect(ref3.value).toBe(3)
 

+ 1 - 1
src/mol-util/float-packing.ts

@@ -15,7 +15,7 @@ export function encodeFloatLog(value: number) { return Math.log(value + 1.0) / f
 /** decode logarithmically encoded float */
 export function decodeFloatLog(value: number) { return Math.exp(value * floatLogFactor) - 1.0 }
 
-/** encode float as rgb triplet */
+/** encode float as normalized rgb triplet */
 export function encodeFloatRGB(value: number) {
     value = clamp(value, 0.0, 16777216.0 - 1.0) + 1.0
     const b = (value % 256) / 255.0

+ 6 - 6
src/mol-util/reference-cache.ts

@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
@@ -24,22 +24,22 @@ export function createReferenceItem<T>(ref: Reference<T>) {
     }
 }
 
-export interface ReferenceCache<T, P, C> {
-    get: (ctx: C, props: P) => ReferenceItem<T>
+export interface ReferenceCache<T, P> {
+    get: (props: P) => ReferenceItem<T>
     clear: () => void
     readonly count: number
     dispose: () => void
 }
 
-export function createReferenceCache<T, P, C>(hashFn: (props: P) => string, ctor: (ctx: C, props: P) => T, deleteFn: (v: T) => void): ReferenceCache<T, P, C> {
+export function createReferenceCache<T, P, C>(hashFn: (props: P) => string, ctor: (props: P) => T, deleteFn: (v: T) => void): ReferenceCache<T, P> {
     const map: Map<string, Reference<T>> = new Map()
 
     return {
-        get: (ctx: C, props: P) => {
+        get: (props: P) => {
             const id = hashFn(props)
             let ref = map.get(id)
             if (!ref) {
-                ref = createReference<T>(ctor(ctx, props))
+                ref = createReference<T>(ctor(props))
                 map.set(id, ref)
             }
             ref.usageCount += 1