From c80a114530f82abf25650494ec692fb629ed1d04 Mon Sep 17 00:00:00 2001 From: Alexander Rose <alex.rose@rcsb.org> Date: Fri, 14 Dec 2018 13:02:38 -0800 Subject: [PATCH] wip, refactoring uniform handling --- src/mol-gl/webgl/program.ts | 60 +++++++++++++------------- src/mol-gl/webgl/uniform.ts | 86 +++++++++++++++++-------------------- 2 files changed, 70 insertions(+), 76 deletions(-) diff --git a/src/mol-gl/webgl/program.ts b/src/mol-gl/webgl/program.ts index b834889c3..6cc476d50 100644 --- a/src/mol-gl/webgl/program.ts +++ b/src/mol-gl/webgl/program.ts @@ -6,9 +6,9 @@ import { ShaderCode, DefineValues, addShaderDefines } from '../shader-code' import { WebGLContext } from './context'; -import { getUniformUpdaters, getTextureUniformUpdaters, UniformValues, UniformUpdater } from './uniform'; +import { UniformValues, getUniformSetters } from './uniform'; import { AttributeBuffers } from './buffer'; -import { TextureId, Textures } from './texture'; +import { Textures, TextureId } from './texture'; import { createReferenceCache, ReferenceCache } from 'mol-util/reference-cache'; import { idFactory } from 'mol-util/id-factory'; import { RenderableSchema } from '../renderable/schema'; @@ -27,20 +27,21 @@ export interface Program { destroy: () => void } -type AttributeLocations = { [k: string]: number } +type Locations = { [k: string]: number } -function getAttributeLocations(ctx: WebGLContext, program: WebGLProgram, schema: RenderableSchema) { +function getLocations(ctx: WebGLContext, program: WebGLProgram, schema: RenderableSchema) { const { gl } = ctx - const locations: AttributeLocations = {} - gl.useProgram(program) + const locations: Locations = {} Object.keys(schema).forEach(k => { const spec = schema[k] if (spec.type === 'attribute') { const loc = gl.getAttribLocation(program, k) - // if (loc === -1) { - // console.info(`Could not get attribute location for '${k}'`) - // } + // if (loc === -1) console.info(`Could not get attribute location for '${k}'`) locations[k] = loc + } else if (spec.type === 'uniform' || spec.type === 'texture') { + const loc = gl.getUniformLocation(program, k) + // if (loc === null) console.info(`Could not get uniform location for '${k}'`) + locations[k] = loc as number } }) return locations @@ -69,18 +70,12 @@ export function createProgram(ctx: WebGLContext, props: ProgramProps): Program { vertShaderRef.value.attach(program) fragShaderRef.value.attach(program) gl.linkProgram(program) - if (!gl.getProgramParameter(program, gl.LINK_STATUS)){ + if (!gl.getProgramParameter(program, gl.LINK_STATUS)) { throw new Error(`Could not compile WebGL program. \n\n${gl.getProgramInfoLog(program)}`); } - const uniformUpdaters = getUniformUpdaters(ctx, program, schema) - const attributeLocations = getAttributeLocations(ctx, program, schema) - const textureUniformUpdaters = getTextureUniformUpdaters(ctx, program, schema) - - const _uniformUpdaters: [string, UniformUpdater][] = [] - Object.keys(uniformUpdaters).forEach(k => { - _uniformUpdaters.push([k, uniformUpdaters[k]]) - }) + const locations = getLocations(ctx, program, schema) + const uniformSetters = getUniformSetters(schema) let destroyed = false @@ -93,23 +88,30 @@ export function createProgram(ctx: WebGLContext, props: ProgramProps): Program { gl.useProgram(program) }, setUniforms: (uniformValues: UniformValues) => { - for (let i = 0, il = _uniformUpdaters.length; i < il; ++i) { - const [k, uu] = _uniformUpdaters[i] - const uv = uniformValues[k] - if (uv !== undefined) uu.set(uv.ref.value) + const uniformKeys = Object.keys(uniformValues) + for (let i = 0, il = uniformKeys.length; i < il; ++i) { + const k = uniformKeys[i] + const l = locations[k] + const v = uniformValues[k] + if (v) uniformSetters[k](gl, l, v.ref.value) } }, bindAttributes: (attribueBuffers: AttributeBuffers) => { - Object.keys(attribueBuffers).forEach(k => { - const loc = attributeLocations[k] - if (loc !== -1) attribueBuffers[k].bind(loc) - }) + const attributeKeys = Object.keys(attribueBuffers) + for (let i = 0, il = attributeKeys.length; i < il; ++i) { + const k = attributeKeys[i] + const l = locations[k] + if (l !== -1) attribueBuffers[k].bind(l) + } }, bindTextures: (textures: Textures) => { - Object.keys(textures).forEach((k, i) => { + const textureKeys = Object.keys(textures) + for (let i = 0, il = textureKeys.length; i < il; ++i) { + const k = textureKeys[i] + const l = locations[k] textures[k].bind(i as TextureId) - textureUniformUpdaters[k].set(i) - }) + uniformSetters[k](gl, l, i as TextureId) + } }, destroy: () => { diff --git a/src/mol-gl/webgl/uniform.ts b/src/mol-gl/webgl/uniform.ts index f4ea53eb0..a979a64fe 100644 --- a/src/mol-gl/webgl/uniform.ts +++ b/src/mol-gl/webgl/uniform.ts @@ -5,9 +5,9 @@ */ import { Mat3, Mat4, Vec2, Vec3, Vec4 } from 'mol-math/linear-algebra' -import { WebGLContext } from './context'; -import { ValueCell, arrayEqual } from 'mol-util'; -import { RenderableSchema } from '../renderable/schema'; +import { ValueCell } from 'mol-util'; +import { GLRenderingContext } from './compat'; +import { RenderableSchema } from 'mol-gl/renderable/schema'; export type UniformKindValue = { 'f': number @@ -21,63 +21,55 @@ export type UniformKindValue = { } export type UniformKind = keyof UniformKindValue export type UniformType = number | Vec2 | Vec3 | Vec4 | Mat3 | Mat4 -export interface UniformUpdater { - set: (value: UniformType) => void, - clear: () => void -} export type UniformValues = { [k: string]: ValueCell<UniformType> } -export type UniformUpdaters = { [k: string]: UniformUpdater } -function createUniformSetter(ctx: WebGLContext, program: WebGLProgram, name: string, kind: UniformKind): (value: any) => void { - const { gl } = ctx - const location = gl.getUniformLocation(program, name) - if (location === null) { - // console.info(`Could not get WebGL uniform location for '${name}'`) - } +export function setUniform(gl: GLRenderingContext, location: WebGLUniformLocation | null, kind: UniformKind, value: any) { switch (kind) { - case 'f': return (value: number) => gl.uniform1f(location, value) - case 'i': case 't': return (value: number) => gl.uniform1i(location, value) - case 'v2': return (value: Vec2) => (gl as WebGLRenderingContext).uniform2fv(location, value) // TODO remove cast when webgl2 types are fixed - case 'v3': return (value: Vec3) => (gl as WebGLRenderingContext).uniform3fv(location, value) - case 'v4': return (value: Vec4) => (gl as WebGLRenderingContext).uniform4fv(location, value) - case 'm3': return (value: Mat3) => (gl as WebGLRenderingContext).uniformMatrix3fv(location, false, value) - case 'm4': return (value: Mat4) => (gl as WebGLRenderingContext).uniformMatrix4fv(location, false, value) + case 'f': gl.uniform1f(location, value); break + case 'i': case 't': gl.uniform1i(location, value); break + case 'v2': gl.uniform2fv(location, value); break + case 'v3': gl.uniform3fv(location, value); break + case 'v4': gl.uniform4fv(location, value); break + case 'm3': gl.uniformMatrix3fv(location, false, value); break + case 'm4': gl.uniformMatrix4fv(location, false, value); break + default: console.error(`unknown uniform kind '${kind}'`) } } -function createUniformUpdater(ctx: WebGLContext, program: WebGLProgram, name: string, kind: UniformKind): UniformUpdater { - const setter = createUniformSetter(ctx, program, name, kind) - let _value: UniformType | undefined = undefined - return { - set: value => { - if (_value !== value || (Array.isArray(_value) && Array.isArray(value) && arrayEqual(_value, value))) { - setter(value) - _value = value - } - }, - clear: () => { _value = undefined } +export type UniformSetter = (gl: GLRenderingContext, location: number, value: any) => void +export type UniformSetters = { [k: string]: UniformSetter } + +function uniform1f (gl: GLRenderingContext, location: number, value: any) { gl.uniform1f(location, value) } +function uniform1i (gl: GLRenderingContext, location: number, value: any) { gl.uniform1i(location, value) } +function uniform2fv (gl: GLRenderingContext, location: number, value: any) { gl.uniform2fv(location, value) } +function uniform3fv (gl: GLRenderingContext, location: number, value: any) { gl.uniform3fv(location, value) } +function uniform4fv (gl: GLRenderingContext, location: number, value: any) { gl.uniform4fv(location, value) } +function uniformMatrix3fv (gl: GLRenderingContext, location: number, value: any) { gl.uniformMatrix3fv(location, false, value) } +function uniformMatrix4fv (gl: GLRenderingContext, location: number, value: any) { gl.uniformMatrix4fv(location, false, value) } + +function getUniformSetter(kind: UniformKind) { + switch (kind) { + case 'f': return uniform1f + case 'i': case 't': return uniform1i + case 'v2': return uniform2fv + case 'v3': return uniform3fv + case 'v4': return uniform4fv + case 'm3': return uniformMatrix3fv + case 'm4': return uniformMatrix4fv } + throw new Error(`unknown uniform kind '${kind}'`) } -export function getUniformUpdaters(ctx: WebGLContext, program: WebGLProgram, schema: RenderableSchema) { - const updaters: UniformUpdaters = {} +export function getUniformSetters(schema: RenderableSchema) { + const setters: UniformSetters = {} Object.keys(schema).forEach(k => { const spec = schema[k] if (spec.type === 'uniform') { - updaters[k] = createUniformUpdater(ctx, program, k, spec.kind) - } - }) - return updaters -} - -export function getTextureUniformUpdaters(ctx: WebGLContext, program: WebGLProgram, schema: RenderableSchema) { - const updaters: UniformUpdaters = {} - Object.keys(schema).forEach(k => { - const spec = schema[k] - if (spec.type === 'texture') { - updaters[k] = createUniformUpdater(ctx, program, k, 't') + setters[k] = getUniformSetter(spec.kind as UniformKind) + } else if (spec.type === 'texture') { + setters[k] = getUniformSetter('t') } }) - return updaters + return setters } \ No newline at end of file -- GitLab