// luma.gl // SPDX-License-Identifier: MIT // Copyright (c) vis.gl contributors import type {Binding, UniformValue} from '@luma.gl/core'; import {log, splitUniformsAndBindings} from '@luma.gl/core'; // import type {ShaderUniformType, UniformValue, UniformFormat, UniformInfoDevice, Texture, Sampler} from '@luma.gl/core'; import {_resolveModules, ShaderModule, ShaderModuleInstance} from '@luma.gl/shadertools'; /** * ShaderInputs holds uniform and binding values for one or more shader modules, * - It can generate binary data for any uniform buffer * - It can manage a uniform buffer for each block * - It can update managed uniform buffers with a single call * - It performs some book keeping on what has changed to minimize unnecessary writes to uniform buffers. */ export class ShaderInputs< ShaderPropsT extends Partial>> = Partial< Record> > > { /** * The map of modules * @todo should should this include the resolved dependencies? */ modules: Readonly<{[P in keyof ShaderPropsT]: ShaderModule}>; /** Stores the uniform values for each module */ moduleUniforms: Record>; /** Stores the uniform bindings for each module */ moduleBindings: Record>; /** Tracks if uniforms have changed */ moduleUniformsChanged: Record; /** * Create a new UniformStore instance * @param modules */ constructor(modules: {[P in keyof ShaderPropsT]?: ShaderModule}) { // Extract modules with dependencies const resolvedModules = _resolveModules( Object.values(modules).filter(module => module.dependencies) ); for (const resolvedModule of resolvedModules) { // @ts-ignore modules[resolvedModule.name] = resolvedModule; } log.log(1, 'Creating ShaderInputs with modules', Object.keys(modules))(); // Store the module definitions and create storage for uniform values and binding values, per module this.modules = modules as {[P in keyof ShaderPropsT]: ShaderModule}; this.moduleUniforms = {} as Record>; this.moduleBindings = {} as Record>; // Initialize the modules for (const [name, module] of Object.entries(modules)) { const moduleName = name as keyof ShaderPropsT; // Get default uniforms from module this.moduleUniforms[moduleName] = module.defaultUniforms || {}; this.moduleBindings[moduleName] = {}; } } /** Destroy */ destroy(): void {} /** * Set module props */ setProps(props: Partial<{[P in keyof ShaderPropsT]?: Partial}>): void { for (const name of Object.keys(props)) { const moduleName = name as keyof ShaderPropsT; const moduleProps = props[moduleName]; const module = this.modules[moduleName]; if (!module) { // Ignore props for unregistered modules log.warn(`Module ${name} not found`)(); continue; // eslint-disable-line no-continue } const oldUniforms = this.moduleUniforms[moduleName] as (typeof module)['uniforms']; const oldBindings = this.moduleBindings[moduleName]; const uniformsAndBindings = module.getUniforms?.(moduleProps, oldUniforms) || (moduleProps as any); const {uniforms, bindings} = splitUniformsAndBindings(uniformsAndBindings); this.moduleUniforms[moduleName] = {...oldUniforms, ...uniforms}; this.moduleBindings[moduleName] = {...oldBindings, ...bindings}; // this.moduleUniformsChanged ||= moduleName; // console.log(`setProps(${String(moduleName)}`, moduleName, this.moduleUniforms[moduleName]) } } /** Merges all bindings for the shader (from the various modules) */ // getUniformBlocks(): Record { // return this.moduleUniforms; // } /** * Return the map of modules * @todo should should this include the resolved dependencies? */ getModules(): ShaderModuleInstance[] { return Object.values(this.modules); } /** Get all uniform values for all modules */ getUniformValues(): Record> { return this.moduleUniforms; } /** Merges all bindings for the shader (from the various modules) */ getBindings(): Record { const bindings = {} as Record; for (const moduleBindings of Object.values(this.moduleBindings)) { Object.assign(bindings, moduleBindings); } return bindings; } getDebugTable(): Record> { const table: Record> = {}; for (const [moduleName, module] of Object.entries(this.moduleUniforms)) { for (const [key, value] of Object.entries(module)) { table[`${moduleName}.${key}`] = { type: this.modules[moduleName].uniformTypes?.[key as keyof ShaderPropsT], value: String(value) }; } } return table; } }