Ver Fonte

wip, refactoring uniform handling

Alexander Rose há 6 anos atrás
pai
commit
c80a114530
2 ficheiros alterados com 70 adições e 76 exclusões
  1. 31 29
      src/mol-gl/webgl/program.ts
  2. 39 47
      src/mol-gl/webgl/uniform.ts

+ 31 - 29
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: () => {

+ 39 - 47
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
 }