diff --git a/src/mol-gl/scene.ts b/src/mol-gl/scene.ts index 57764dd718ca6ca31a704306ea8fd8ad5dbda4a0..71e1adbc6b843f61a825ba020cf3b4420b6cf01f 100644 --- a/src/mol-gl/scene.ts +++ b/src/mol-gl/scene.ts @@ -60,10 +60,10 @@ namespace Scene { update: () => { update() - renderableMap.forEach((o, r) => o.update()) + renderableMap.forEach(o => o.update()) boundingSphere = undefined }, - + add: (o: RenderObject) => { if (!renderableMap.has(o)) { renderableMap.set(o, createRenderable(ctx, o)) diff --git a/src/mol-gl/shader-code.ts b/src/mol-gl/shader-code.ts index 2fa41cdaea2b58a1bab762bca1a56b19c0da0dcf..93f933e6bb7e8ec21921d1a37775da287f0e0696 100644 --- a/src/mol-gl/shader-code.ts +++ b/src/mol-gl/shader-code.ts @@ -6,25 +6,33 @@ */ import { ValueCell } from 'mol-util'; +import { idFactory } from 'mol-util/id-factory'; export type DefineKind = 'boolean' | 'string' export type DefineType = boolean | string export type DefineValues = { [k: string]: ValueCell<DefineType> } +const shaderCodeId = idFactory() + export interface ShaderCode { + id: number vert: string frag: string } -export const PointShaderCode: ShaderCode = { - vert: require('mol-gl/shader/point.vert'), - frag: require('mol-gl/shader/point.frag') +export function ShaderCode(vert: string, frag: string): ShaderCode { + return { id: shaderCodeId(), vert, frag } } -export const MeshShaderCode: ShaderCode = { - vert: require('mol-gl/shader/mesh.vert'), - frag: require('mol-gl/shader/mesh.frag') -} +export const PointShaderCode = ShaderCode( + require('mol-gl/shader/point.vert'), + require('mol-gl/shader/point.frag') +) + +export const MeshShaderCode = ShaderCode( + require('mol-gl/shader/mesh.vert'), + require('mol-gl/shader/mesh.frag') +) export type ShaderDefines = { [k: string]: ValueCell<DefineType> @@ -47,9 +55,10 @@ function getDefinesCode (defines: ShaderDefines) { return lines.join('\n') + '\n' } -export function addShaderDefines(defines: ShaderDefines, shaders: ShaderCode) { +export function addShaderDefines(defines: ShaderDefines, shaders: ShaderCode): ShaderCode { const header = getDefinesCode(defines) return { + id: shaderCodeId(), vert: `${header}${shaders.vert}`, frag: `${header}${shaders.frag}` } diff --git a/src/mol-gl/webgl/program.ts b/src/mol-gl/webgl/program.ts index d64d1ca58868a7552bf222f8cd93e9158ff3a3c0..46047d66441a5a847ce1c6c0c1064852bf0cb51a 100644 --- a/src/mol-gl/webgl/program.ts +++ b/src/mol-gl/webgl/program.ts @@ -4,7 +4,7 @@ * @author Alexander Rose <alexander.rose@weirdbyte.de> */ -import { ShaderCode } from '../shader-code' +import { ShaderCode, DefineValues, addShaderDefines } from '../shader-code' import { Context } from './context'; import { getUniformUpdaters, getTextureUniformUpdaters, UniformValues } from './uniform'; import { AttributeBuffers } from './buffer'; @@ -12,6 +12,7 @@ import { TextureId, Textures } from './texture'; import { createReferenceCache, ReferenceCache } from 'mol-util/reference-cache'; import { idFactory } from 'mol-util/id-factory'; import { RenderableSchema } from '../renderable/schema'; +import { hashFnv32a, hashString } from 'mol-data/util'; const getNextProgramId = idFactory() @@ -46,19 +47,21 @@ function getAttributeLocations(ctx: Context, program: WebGLProgram, schema: Rend } export interface ProgramProps { + defineValues: DefineValues, shaderCode: ShaderCode, schema: RenderableSchema } export function createProgram(ctx: Context, props: ProgramProps): Program { const { gl, shaderCache } = ctx - const { shaderCode, schema } = props + const { defineValues, shaderCode: _shaderCode, schema } = props const program = gl.createProgram() if (program === null) { throw new Error('Could not create WebGL program') } + const shaderCode = addShaderDefines(defineValues, _shaderCode) const vertShaderRef = shaderCache.get(ctx, { type: 'vert', source: shaderCode.vert }) const fragShaderRef = shaderCache.get(ctx, { type: 'frag', source: shaderCode.frag }) @@ -113,7 +116,14 @@ export type ProgramCache = ReferenceCache<Program, ProgramProps, Context> export function createProgramCache(): ProgramCache { return createReferenceCache( - (props: ProgramProps) => JSON.stringify(props), + (props: ProgramProps) => { + const array = [props.shaderCode.id] + Object.keys(props.defineValues).forEach(k => { + const v = props.defineValues[k].ref.value + array.push(hashString(k), typeof v === 'boolean' ? v ? 1 : 0 : hashString(v)) + }) + return hashFnv32a(array).toString() + }, (ctx: Context, props: ProgramProps) => createProgram(ctx, props), (program: Program) => { program.destroy() } ) diff --git a/src/mol-gl/webgl/render-item.ts b/src/mol-gl/webgl/render-item.ts index 284591374c09de8e144518f3bff698b72036fc20..d7277fec66e11fe6630b8165714f5c400f9c6242 100644 --- a/src/mol-gl/webgl/render-item.ts +++ b/src/mol-gl/webgl/render-item.ts @@ -7,7 +7,7 @@ import { createAttributeBuffers, createElementsBuffer, ElementsBuffer, createAttributeBuffer, ArrayKind } from './buffer'; import { createTextures } from './texture'; import { Context } from './context'; -import { ShaderCode, addShaderDefines } from '../shader-code'; +import { ShaderCode } from '../shader-code'; import { Program } from './program'; import { RenderableSchema, RenderableValues, AttributeSpec, getValueVersions, splitValues, Values } from '../renderable/schema'; import { idFactory } from 'mol-util/id-factory'; @@ -74,7 +74,8 @@ export function createRenderItem(ctx: Context, drawMode: DrawMode, shaderCode: S Object.keys(RenderVariantDefines).forEach(k => { const variantDefineValues: Values<RenderableSchema> = (RenderVariantDefines as any)[k] programs[k] = programCache.get(ctx, { - shaderCode: addShaderDefines({ ...defineValues, ...variantDefineValues }, shaderCode), + defineValues: { ...defineValues, ...variantDefineValues }, + shaderCode, schema }) }) @@ -117,7 +118,7 @@ export function createRenderItem(ctx: Context, drawMode: DrawMode, shaderCode: S program.setUniforms(uniformValues) if (oesVertexArrayObject && vertexArray) { oesVertexArrayObject.bindVertexArrayOES(vertexArray) - // TODO need to bind elements buffer explicitely since it is not always recorded in the VAO + // need to bind elements buffer explicitely since it is not always recorded in the VAO if (elementsBuffer) elementsBuffer.bind() } else { if (elementsBuffer) elementsBuffer.bind() @@ -147,7 +148,8 @@ export function createRenderItem(ctx: Context, drawMode: DrawMode, shaderCode: S const variantDefineValues: Values<RenderableSchema> = (RenderVariantDefines as any)[k] programs[k].free() programs[k] = programCache.get(ctx, { - shaderCode: addShaderDefines({ ...defineValues, ...variantDefineValues }, shaderCode), + defineValues: { ...defineValues, ...variantDefineValues }, + shaderCode, schema }) }) diff --git a/src/mol-view/viewer.ts b/src/mol-view/viewer.ts index 7c4070cd107c4ceec5a209bfedca4e9d75f87635..95952a7fdd5754441f0bd66f69691ee2e4278655 100644 --- a/src/mol-view/viewer.ts +++ b/src/mol-view/viewer.ts @@ -175,7 +175,6 @@ namespace Viewer { let didRender = false controls.update() camera.update() - scene.update() if (force || !Mat4.areEqual(camera.projectionView, prevProjectionView, EPSILON.Value) || !Mat4.areEqual(scene.view, prevSceneView, EPSILON.Value)) { // console.log('foo', force, prevSceneView, scene.view) Mat4.copy(prevProjectionView, camera.projectionView) @@ -274,6 +273,7 @@ namespace Viewer { } reprMap.set(repr, newRO) reprCount.next(reprMap.size) + scene.update() }, remove: (repr: Representation<any>) => { const renderObjectSet = reprMap.get(repr) @@ -281,6 +281,7 @@ namespace Viewer { renderObjectSet.forEach(o => scene.remove(o)) reprMap.delete(repr) reprCount.next(reprMap.size) + scene.update() } }, update: () => scene.update(),