소스 검색

Update Effects

Sebastien Vandenberghe 6 년 전
부모
커밋
0b8b1a9196
3개의 변경된 파일102개의 추가작업 그리고 31개의 파일을 삭제
  1. 7 2
      src/Engines/WebGPU/webgpuPipelineContext.ts
  2. 76 17
      src/Engines/webgpuEngine.ts
  3. 19 12
      src/Materials/effect.ts

+ 7 - 2
src/Engines/WebGPU/webgpuPipelineContext.ts

@@ -26,8 +26,13 @@ export interface IWebGPUPipelineContextVertexInputsCache {
 export class WebGPUPipelineContext implements IPipelineContext {
     public engine: WebGPUEngine;
 
-    public vertexShaderCode: string;
-    public fragmentShaderCode: string;
+    public availableAttributes: { [key: string]: number };
+    public availableUBOs: { [key: string]: number };
+    public sources: {
+        vertex: string
+        fragment: string,
+    };
+
     public stages: Nullable<GPURenderPipelineStageDescriptor>;
 
     public samplers: { [name: string]: Nullable<IWebGPUPipelineContextSamplerCache> } = { };

+ 76 - 17
src/Engines/webgpuEngine.ts

@@ -110,7 +110,15 @@ export class WebGPUEngine extends Engine {
     private _uniformsBuffers: { [name: string]: WebGPUDataBuffer } = {};
 
     // Caches
-    private _compiledStages: { [key: string]: GPURenderPipelineStageDescriptor } = {};
+    private _compiledShaders: { [key: string]: {
+        stages: GPURenderPipelineStageDescriptor,
+        availableAttributes: { [key: string]: number },
+        availableUBOs: { [key: string]: number }
+        sources: {
+            vertex: string
+            fragment: string,
+        }
+    } } = {};
 
     // Temporary...
     private _decodeCanvas = document.createElement("canvas");
@@ -678,8 +686,13 @@ export class WebGPUEngine extends Engine {
         const fragment = baseName.fragmentElement || baseName.fragment || baseName;
 
         const name = vertex + "+" + fragment + "@" + (defines ? defines : (<EffectCreationOptions>attributesNamesOrOptions).defines);
-        const effect = new Effect(baseName, attributesNamesOrOptions, uniformsNamesOrEngine, samplers, this, defines, fallbacks, onCompiled, onError, indexParameters, name);
-        return effect;
+        const shader = this._compiledShaders[name];
+        if (shader) {
+            return new Effect(baseName, attributesNamesOrOptions, uniformsNamesOrEngine, samplers, this, defines, fallbacks, onCompiled, onError, indexParameters, name, shader.sources);
+        }
+        else {
+            return new Effect(baseName, attributesNamesOrOptions, uniformsNamesOrEngine, samplers, this, defines, fallbacks, onCompiled, onError, indexParameters, name);
+        }
     }
 
     private _compileRawShaderToSpirV(source: string, type: string): Uint32Array {
@@ -762,12 +775,13 @@ export class WebGPUEngine extends Engine {
         transformFeedbackVaryings: Nullable<string[]>,
         key: string) {
         const webGpuContext = pipelineContext as WebGPUPipelineContext;
-        webGpuContext.vertexShaderCode = vertexSourceCode;
-        webGpuContext.fragmentShaderCode = fragmentSourceCode;
 
-        const stages = this._compiledStages[key];
-        if (stages) {
-            webGpuContext.stages = stages;
+        const shader = this._compiledShaders[key];
+        if (shader) {
+            webGpuContext.stages = shader.stages;
+            webGpuContext.availableAttributes = shader.availableAttributes;
+            webGpuContext.availableUBOs = shader.availableUBOs;
+            webGpuContext.sources = shader.sources;
         }
         else {
             if (createAsRaw) {
@@ -776,29 +790,74 @@ export class WebGPUEngine extends Engine {
             else {
                 webGpuContext.stages = this._compilePipelineStageDescriptor(vertexSourceCode, fragmentSourceCode, defines);
             }
-            this._compiledStages[key] = webGpuContext.stages;
+
+            this._findAttributes(webGpuContext, vertexSourceCode);
+            this._findUBOs(webGpuContext, fragmentSourceCode);
+
+            this._compiledShaders[key] = {
+                stages: webGpuContext.stages,
+                availableAttributes: webGpuContext.availableAttributes,
+                availableUBOs: webGpuContext.availableUBOs,
+                sources: {
+                    fragment: fragmentSourceCode,
+                    vertex: vertexSourceCode
+                }
+            };
         }
     }
 
-    public getAttributes(pipelineContext: IPipelineContext, attributesNames: string[]): number[] {
-        const results = new Array(attributesNames.length);
-
+    private _findAttributes(pipelineContext: WebGPUPipelineContext, vertexSourceCode: string): void {
         // TODO.
         // Hard coded for WebGPU until an introspection lib is available.
 
-        const vertexShaderCode = (pipelineContext as WebGPUPipelineContext).vertexShaderCode;
+        const results: { [key: string]: number } = { };
+
+        const vertexShaderCode = vertexSourceCode;
         const attributesRegex = /layout\(location\s*=\s*([0-9]*)\)\s*in\s*\S*\s*(\S*);/gm;
         let matches: RegExpExecArray | null;
         while (matches = attributesRegex.exec(vertexShaderCode)) {
             const location = matches[1];
             const name = matches[2];
 
-            const shaderLocation = attributesNames.indexOf(name);
-            if (shaderLocation === -1) {
+            results[name] = +location;
+        }
+
+        pipelineContext.availableAttributes = results;
+    }
+
+    private _findUBOs(pipelineContext: WebGPUPipelineContext, fragmentSourceCode: string): void {
+        // TODO.
+        // Hard coded for WebGPU until an introspection lib is available.
+
+        const samplersRegex = /layout\(set\s*=\s*(\d+)\s*,\s*binding\s*=\s*(\d+).*\)\s*uniform\s*(texture\S*)\s*(\S*)\s*;/gm;
+        const results: { [key: string]: number } = { };
+        let matches: RegExpExecArray | null;
+        while (matches = samplersRegex.exec(fragmentSourceCode)) {
+            // const set = matches[1];
+            const binding = matches[2];
+            // const type = matches[3];
+            const name = matches[4].replace("Texture", "");
+
+            results[name] = +binding;
+        }
+
+        pipelineContext.availableUBOs = results;
+    }
+
+    public getAttributes(pipelineContext: IPipelineContext, attributesNames: string[]): number[] {
+        const results = new Array(attributesNames.length);
+        const gpuPipelineContext = (pipelineContext as WebGPUPipelineContext);
+
+        // TODO.
+        // Hard coded for WebGPU until an introspection lib is available.
+        for (let i = 0; i < attributesNames.length; i++) {
+            const attributeName = attributesNames[i];
+            const attributeLocation = gpuPipelineContext.availableAttributes[attributeName];
+            if (attributeLocation === undefined) {
                 continue;
             }
 
-            results[shaderLocation] = +location;
+            results[i] = attributeLocation;
         }
 
         return results;
@@ -1961,7 +2020,7 @@ export class WebGPUEngine extends Engine {
      */
     public dispose(): void {
         this._decodeEngine.dispose();
-        this._compiledStages = { };
+        this._compiledShaders = { };
         super.dispose();
     }
 

+ 19 - 12
src/Materials/effect.ts

@@ -7,6 +7,7 @@ import { Logger } from "../Misc/logger";
 import { IDisposable } from '../scene';
 import { IPipelineContext } from '../Engines/IPipelineContext';
 import { DataBuffer } from '../Meshes/dataBuffer';
+import { WebGPUPipelineContext } from '../Engines/WebGPU/webgpuPipelineContext';
 
 declare type Engine = import("../Engines/engine").Engine;
 declare type InternalTexture = import("../Materials/Textures/internalTexture").InternalTexture;
@@ -287,9 +288,14 @@ export class Effect implements IDisposable {
      * @param onError Callback that will be called if an error occurs during shader compilation.
      * @param indexParameters Parameters to be used with Babylons include syntax to iterate over an array (eg. {lights: 10})
      * @param key Effect Key identifying uniquely compiled shader variants
+     * @param sources Already processed sources for the current key.
      */
     constructor(baseName: any, attributesNamesOrOptions: string[] | EffectCreationOptions, uniformsNamesOrEngine: string[] | Engine, samplers: Nullable<string[]> = null, engine?: Engine, defines: Nullable<string> = null,
-        fallbacks: Nullable<EffectFallbacks> = null, onCompiled: Nullable<(effect: Effect) => void> = null, onError: Nullable<(effect: Effect, errors: string) => void> = null, indexParameters?: any, key: string = "") {
+        fallbacks: Nullable<EffectFallbacks> = null, onCompiled: Nullable<(effect: Effect) => void> = null, onError: Nullable<(effect: Effect, errors: string) => void> = null, indexParameters?: any, key: string = "",
+        sources?: {
+            vertex: string
+            fragment: string,
+        }) {
         this.name = baseName;
         this._key = key;
 
@@ -328,6 +334,13 @@ export class Effect implements IDisposable {
 
         this.uniqueId = Effect._uniqueIdSeed++;
 
+        if (sources) {
+            this._fragmentSourceCode = sources.fragment;
+            this._vertexSourceCode = sources.vertex;
+            this._prepareEffect();
+            return;
+        }
+
         var vertexSource: any;
         var fragmentSource: any;
 
@@ -862,18 +875,12 @@ export class Effect implements IDisposable {
                 }
                 else {
                     // TODO. CLEANUP THIS STUFF (FOR SEB) !!!
-                    const samplersRegex = /layout\(set\s*=\s*(\d+)\s*,\s*binding\s*=\s*(\d+).*\)\s*uniform\s*(texture\S*)\s*(\S*)\s*;/gm;
-                    const foundSamplers: { [key: string]: number } = { };
-                    let matches: RegExpExecArray | null;
-                    while (matches = samplersRegex.exec(this._fragmentSourceCode)) {
-                        // const set = matches[1];
-                        const binding = matches[2];
-                        // const type = matches[3];
-                        const name = matches[4].replace("Texture", "");
-
-                        foundSamplers[name] = +binding;
-                    }
+                    this._fragmentSourceCode = "";
+                    // this._fragmentSourceCodeOverride = "";
+                    this._vertexSourceCode = "";
+                    // this._vertexSourceCodeOverride = "";
 
+                    const foundSamplers = (this._pipelineContext as WebGPUPipelineContext).availableUBOs;
                     let index: number;
                     for (index = 0; index < this._samplerList.length; index++) {
                         const name = this._samplerList[index];