{"version":3,"file":"GpuProgram.mjs","sources":["../../../../../src/rendering/renderers/gpu/shader/GpuProgram.ts"],"sourcesContent":["import { createIdFromString } from '../../shared/utils/createIdFromString';\nimport { extractAttributesFromGpuProgram } from './utils/extractAttributesFromGpuProgram';\nimport { extractStructAndGroups } from './utils/extractStructAndGroups';\nimport { generateGpuLayoutGroups } from './utils/generateGpuLayoutGroups';\nimport { generateLayoutHash } from './utils/generateLayoutHash';\nimport { removeStructAndGroupDuplicates } from './utils/removeStructAndGroupDuplicates';\n\nimport type { ExtractedAttributeData } from '../../gl/shader/program/extractAttributesFromGlProgram';\nimport type { StructsAndGroups } from './utils/extractStructAndGroups';\n\n/**\n * a WebGPU descriptions of how the program is laid out\n * @see https://gpuweb.github.io/gpuweb/#gpupipelinelayout\n * @memberof rendering\n */\nexport type ProgramPipelineLayoutDescription = GPUBindGroupLayoutEntry[][];\n/**\n * a map the maps names of uniforms to group indexes\n * @memberof rendering\n */\nexport type ProgramLayout = Record<string, number>[];\n\n/**\n * the program source\n * @memberof rendering\n */\nexport interface ProgramSource\n{\n    /** The wgsl source code of the shader. */\n    source: string;\n    /** The main function to run in this shader */\n    entryPoint?: string;\n}\n\n/**\n * The options for the gpu program\n * @memberof rendering\n */\nexport interface GpuProgramOptions\n{\n    /**\n     * the name of the program, this is added to the label of the GPU Program created\n     * under the hood. Makes it much easier to debug!\n     */\n    name?: string;\n    /** The fragment glsl shader source. */\n    fragment?: ProgramSource;\n    /** The vertex glsl shader source. */\n    vertex?: ProgramSource;\n    /** The layout of the program. If not provided, it will be generated from the shader sources. */\n    layout?: ProgramLayout;\n    /** The gpu layout of the program. If not provided, it will be generated from the shader sources. */\n    gpuLayout?: ProgramPipelineLayoutDescription;\n}\n\nconst programCache: Record<string, GpuProgram> = Object.create(null);\n\n/**\n * A wrapper for a WebGPU Program, specifically designed for the WebGPU renderer.\n * This class facilitates the creation and management of shader code that integrates with the WebGPU pipeline.\n *\n * To leverage the full capabilities of this class, familiarity with WGSL shaders is recommended.\n * @see https://gpuweb.github.io/gpuweb/#index\n * @example\n *\n * // Create a new program\n * const program = new GpuProgram({\n *   vertex: {\n *    source: '...',\n *    entryPoint: 'main',\n *   },\n *   fragment:{\n *    source: '...',\n *    entryPoint: 'main',\n *   },\n * });\n *\n *\n * Note: Both fragment and vertex shader sources can coexist within a single WGSL source file\n * this can make things a bit simpler.\n *\n * For optimal usage and best performance, it help to reuse programs whenever possible.\n * The {@link GpuProgram.from} helper function is designed for this purpose, utilizing an\n * internal cache to efficiently manage and retrieve program instances.\n * By leveraging this function, you can significantly reduce overhead and enhance the performance of your rendering pipeline.\n *\n * An important distinction between WebGL and WebGPU regarding program data retrieval:\n * While WebGL allows extraction of program information directly from its compiled state,\n * WebGPU does not offer such a capability. Therefore, in the context of WebGPU, we're required\n * to manually extract the program layout information from the source code itself.\n * @memberof rendering\n */\nexport class GpuProgram\n{\n    /** The fragment glsl shader source. */\n    public readonly fragment?: ProgramSource;\n    /** The vertex glsl shader source */\n    public readonly vertex?: ProgramSource;\n\n    /**\n     * Mapping of uniform names to group indexes for organizing shader program uniforms.\n     * Automatically generated from shader sources if not provided.\n     * @example\n     * // Assuming a shader with two uniforms, `u_time` and `u_resolution`, grouped respectively:\n     * [\n     *   { \"u_time\": 0 },\n     *   { \"u_resolution\": 1 }\n     * ]\n     */\n    public readonly layout: ProgramLayout;\n\n    /**\n     * Configuration for the WebGPU bind group layouts, detailing resource organization for the shader.\n     * Generated from shader sources if not explicitly provided.\n     * @example\n     * // Assuming a shader program that requires two bind groups:\n     * [\n     *   // First bind group layout entries\n     *   [{ binding: 0, visibility: GPUShaderStage.VERTEX, type: \"uniform-buffer\" }],\n     *   // Second bind group layout entries\n     *   [{ binding: 1, visibility: GPUShaderStage.FRAGMENT, type: \"sampler\" },\n     *    { binding: 2, visibility: GPUShaderStage.FRAGMENT, type: \"sampled-texture\" }]\n     * ]\n     */\n    public readonly gpuLayout: ProgramPipelineLayoutDescription;\n\n    /**\n     * @internal\n     * @ignore\n     */\n    public _layoutKey = 0;\n\n    /**\n     * @internal\n     * @ignore\n     */\n    public _attributeLocationsKey = 0;\n\n    /** the structs and groups extracted from the shader sources */\n    public readonly structsAndGroups: StructsAndGroups;\n    /**\n     * the name of the program, this is added to the label of the GPU Program created under the hood.\n     * Makes it much easier to debug!\n     */\n    public readonly name: string;\n    private _attributeData: Record<string, ExtractedAttributeData>;\n\n    /** if true, the program will automatically assign global uniforms to group[0] */\n    public autoAssignGlobalUniforms: boolean;\n    /** if true, the program will automatically assign local uniforms to group[1] */\n    public autoAssignLocalUniforms: boolean;\n\n    /**\n     * Create a new GpuProgram\n     * @param options - The options for the gpu program\n     */\n    constructor(options: GpuProgramOptions)\n    {\n        const { fragment, vertex, layout, gpuLayout, name } = options;\n\n        this.name = name;\n\n        this.fragment = fragment;\n        this.vertex = vertex;\n\n        // TODO this should be cached - or dealt with at a system level.\n        if (fragment.source === vertex.source)\n        {\n            const structsAndGroups = extractStructAndGroups(fragment.source);\n\n            this.structsAndGroups = structsAndGroups;\n        }\n        else\n        {\n            const vertexStructsAndGroups = extractStructAndGroups(vertex.source);\n            const fragmentStructsAndGroups = extractStructAndGroups(fragment.source);\n\n            this.structsAndGroups = removeStructAndGroupDuplicates(vertexStructsAndGroups, fragmentStructsAndGroups);\n        }\n\n        // todo layout\n        this.layout = layout ?? generateLayoutHash(this.structsAndGroups);\n\n        // struct properties!\n\n        this.gpuLayout = gpuLayout ?? generateGpuLayoutGroups(this.structsAndGroups);\n\n        this.autoAssignGlobalUniforms = !!(this.layout[0]?.globalUniforms !== undefined);\n        this.autoAssignLocalUniforms = !!(this.layout[1]?.localUniforms !== undefined);\n\n        this._generateProgramKey();\n    }\n\n    // TODO maker this pure\n    private _generateProgramKey()\n    {\n        const { vertex, fragment } = this;\n\n        const bigKey = vertex.source + fragment.source + vertex.entryPoint + fragment.entryPoint;\n\n        this._layoutKey = createIdFromString(bigKey, 'program');\n    }\n\n    get attributeData()\n    {\n        this._attributeData ??= extractAttributesFromGpuProgram(this.vertex);\n\n        return this._attributeData;\n    }\n    /** destroys the program */\n    public destroy(): void\n    {\n        (this.gpuLayout as null) = null;\n        (this.layout as null) = null;\n        (this.structsAndGroups as null) = null;\n        (this.fragment as null) = null;\n        (this.vertex as null) = null;\n    }\n\n    /**\n     * Helper function that creates a program for a given source.\n     * It will check the program cache if the program has already been created.\n     * If it has that one will be returned, if not a new one will be created and cached.\n     * @param options - The options for the program.\n     * @returns A program using the same source\n     */\n    public static from(options: GpuProgramOptions): GpuProgram\n    {\n        // eslint-disable-next-line max-len\n        const key = `${options.vertex.source}:${options.fragment.source}:${options.fragment.entryPoint}:${options.vertex.entryPoint}`;\n\n        if (!programCache[key])\n        {\n            programCache[key] = new GpuProgram(options);\n        }\n\n        return programCache[key];\n    }\n}\n\n"],"names":[],"mappings":"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"}