浏览代码

Fix Processor WebGPU

Sebastien Vandenberghe 6 年之前
父节点
当前提交
78a087a5eb

+ 1 - 1
package.json

@@ -106,4 +106,4 @@
         "xhr2": "^0.1.4",
         "xmlbuilder": "8.2.2"
     }
-}
+}

+ 2 - 1
src/Engines/Processors/shaderProcessingOptions.ts

@@ -1,4 +1,5 @@
 import { IShaderProcessor } from './iShaderProcessor';
+import { Nullable } from '../../types';
 
 /** @hidden */
 export interface ProcessingOptions {
@@ -9,7 +10,7 @@ export interface ProcessingOptions {
     supportsUniformBuffers: boolean;
     shadersRepository: string;
     includesShadersStore: { [key: string]: string };
-    processor?: IShaderProcessor;
+    processor: Nullable<IShaderProcessor>;
     version: string;
     platformName: string;
     lookForClosingBracketForUniformBuffer?: boolean;

+ 52 - 0
src/Engines/WebGPU/webgpuShaderProcessors.ts

@@ -0,0 +1,52 @@
+import { IShaderProcessor } from '../Processors/iShaderProcessor';
+
+/** @hidden */
+export class WebGPUShaderProcessor implements IShaderProcessor {
+    // attributeProcessor?: (attribute: string) => string;
+    // varyingProcessor?: (varying: string, isFragment: boolean) => string;
+    // uniformProcessor?: (uniform: string, isFragment: boolean) => string;
+    // uniformBufferProcessor?: (uniformBuffer: string, isFragment: boolean) => string;
+    // endOfUniformBufferProcessor?: (closingBracketLine: string, isFragment: boolean) => string;
+    // lineProcessor?: (line: string, isFragment: boolean) => string;
+    // preProcessor?: (code: string, defines: string[], isFragment: boolean) => string;
+    // postProcessor?: (code: string, defines: string[], isFragment: boolean) => string;
+
+    // public preProcessor(preparedSourceCode: string, defines: string[], isFragment: boolean): string {
+    //     return "#define WEBGPU \n" + preparedSourceCode;
+    // }
+
+    public attributeProcessor(attribute: string) {
+        return attribute.replace("attribute", "in");
+    }
+
+    public varyingProcessor(varying: string, isFragment: boolean) {
+        return varying.replace("varying", isFragment ? "in" : "out");
+    }
+
+    public postProcessor(code: string, defines: string[], isFragment: boolean) {
+        const hasDrawBuffersExtension = code.search(/#extension.+GL_EXT_draw_buffers.+require/) !== -1;
+
+        // Remove extensions
+        var regex = /#extension.+(GL_OVR_multiview2|GL_OES_standard_derivatives|GL_EXT_shader_texture_lod|GL_EXT_frag_depth|GL_EXT_draw_buffers).+(enable|require)/g;
+        code = code.replace(regex, "");
+
+        // Replace instructions
+        code = code.replace(/texture2D\s*\(/g, "texture(");
+        if (isFragment) {
+            code = code.replace(/texture2DLodEXT\s*\(/g, "textureLod(");
+            code = code.replace(/textureCubeLodEXT\s*\(/g, "textureLod(");
+            code = code.replace(/textureCube\s*\(/g, "texture(");
+            code = code.replace(/gl_FragDepthEXT/g, "gl_FragDepth");
+            code = code.replace(/gl_FragColor/g, "glFragColor");
+            code = code.replace(/gl_FragData/g, "glFragData");
+            code = code.replace(/void\s+?main\s*\(/g, (hasDrawBuffersExtension ? "" : "layout(location = 0) out vec4 glFragColor;\n") + "void main(");
+        } else {
+            var hasMultiviewExtension = defines.indexOf("#define MULTIVIEW") !== -1;
+            if (hasMultiviewExtension) {
+                return "#extension GL_OVR_multiview2 : require\nlayout (num_views = 2) in;\n" + code;
+            }
+        }
+
+        return code;
+    }
+}

+ 15 - 6
src/Engines/engine.ts

@@ -558,7 +558,7 @@ export class Engine {
     // Public members
 
     /** @hidden */
-    public _shaderProcessor: IShaderProcessor;
+    public _shaderProcessor: Nullable<IShaderProcessor>;
 
     /**
      * Gets or sets a boolean that indicates if textures must be forced to power of 2 size even if not required
@@ -1216,11 +1216,6 @@ export class Engine {
             this.initWebVR();
         }
 
-        // Shader processor
-        if (this.webGLVersion > 1) {
-            this._shaderProcessor = new WebGL2ShaderProcessor();
-        }
-
         // Detect if we are running on a faulty buggy OS.
         this._badOS = /iPad/i.test(navigator.userAgent) || /iPhone/i.test(navigator.userAgent);
 
@@ -1285,6 +1280,20 @@ export class Engine {
         if (!Engine.audioEngine && audioEngine && Engine.AudioEngineFactory) {
             Engine.audioEngine = Engine.AudioEngineFactory(this.getRenderingCanvas());
         }
+
+        // Shader processor
+        this._shaderProcessor = this._getShaderProcessor();
+    }
+
+    /**
+     * Gets a shader processor implementation fitting with the current engine type.
+     * @returns The shader processor implementation.
+     */
+    protected _getShaderProcessor(): Nullable<IShaderProcessor> {
+        if (this.webGLVersion > 1) {
+            return new WebGL2ShaderProcessor();
+        }
+        return null;
     }
 
     // WebVR

+ 11 - 1
src/Engines/webgpuEngine.ts

@@ -18,6 +18,8 @@ import { DataBuffer } from '../Meshes/dataBuffer';
 import { WebGPUDataBuffer } from '../Meshes/WebGPU/webgpuDataBuffer';
 import { IInternalTextureLoader } from "../Materials/Textures/internalTextureLoader";
 import { BaseTexture } from "../Materials/Textures/baseTexture";
+import { IShaderProcessor } from "./Processors/iShaderProcessor";
+import { WebGPUShaderProcessor } from "./WebGPU/webgpuShaderProcessors";
 
 /**
  * Options to create the WebGPU engine
@@ -334,6 +336,14 @@ export class WebGPUEngine extends Engine {
         };
     }
 
+    /**
+     * Gets a shader processor implementation fitting with the current engine type.
+     * @returns The shader processor implementation.
+     */
+    protected _getShaderProcessor(): Nullable<IShaderProcessor> {
+        return new WebGPUShaderProcessor();
+    }
+
     //------------------------------------------------------------------------------
     //                          Static Pipeline WebGPU States
     //------------------------------------------------------------------------------
@@ -743,7 +753,7 @@ export class WebGPUEngine extends Engine {
     private _compilePipelineStageDescriptor(vertexCode: string, fragmentCode: string, defines: Nullable<string>): GPURenderPipelineStageDescriptor {
         this.onBeforeShaderCompilationObservable.notifyObservers(this);
 
-        var shaderVersion = "#version 450\n#define WEBGPU \n";
+        var shaderVersion = "#version 450\n";
         var vertexShader = this._compileShaderToSpirV(vertexCode, "vertex", defines, shaderVersion);
         var fragmentShader = this._compileShaderToSpirV(fragmentCode, "fragment", defines, shaderVersion);
 

+ 3 - 160
src/Materials/effect.ts

@@ -9,6 +9,7 @@ import { IPipelineContext } from '../Engines/IPipelineContext';
 import { DataBuffer } from '../Meshes/dataBuffer';
 import { WebGPUPipelineContext } from '../Engines/WebGPU/webgpuPipelineContext';
 import { ShaderProcessor } from '../Engines/Processors/shaderProcessor';
+import { ProcessingOptions } from '../Engines/Processors/shaderProcessingOptions';
 
 declare type Engine = import("../Engines/engine").Engine;
 declare type InternalTexture = import("../Materials/Textures/internalTexture").InternalTexture;
@@ -369,7 +370,7 @@ export class Effect implements IDisposable {
             fragmentSource = baseName.fragment || baseName;
         }
 
-        let processorOptions = {
+        let processorOptions: ProcessingOptions = {
             defines: this.defines.split("\n"),
             indexParameters: this._indexParameters,
             isFragment: false,
@@ -379,7 +380,7 @@ export class Effect implements IDisposable {
             shadersRepository: Effect.ShadersRepository,
             includesShadersStore: Effect.IncludesShadersStore,
             version: (this._engine.webGLVersion * 100).toString(),
-            platformName: this._engine.webGLVersion >= 2 ? "WEBGL2" : "WEBGL1"
+            platformName: this._engine.isWebGPU ? "WEBGPU" : this._engine.webGLVersion >= 2 ? "WEBGL2" : "WEBGL1"
         };
 
         this._loadVertexShader(vertexSource, (vertexCode) => {
@@ -664,164 +665,6 @@ export class Effect implements IDisposable {
         }
     }
 
-    // private _processShaderConversion(sourceCode: string, isFragment: boolean, callback: (data: any) => void): void {
-
-    //     var preparedSourceCode = this._processPrecision(sourceCode);
-
-    //     if (this._engine.webGLVersion == 1 && !this._engine.isWebGPU) {
-    //         callback(preparedSourceCode);
-    //         return;
-    //     }
-
-    //     // Already converted
-    //     if (preparedSourceCode.indexOf("#version 3") !== -1) {
-    //         callback(preparedSourceCode.replace("#version 300 es", ""));
-    //         return;
-    //     }
-
-    //     var hasDrawBuffersExtension = preparedSourceCode.search(/#extension.+GL_EXT_draw_buffers.+require/) !== -1;
-
-    //     // Remove extensions
-    //     // #extension GL_OES_standard_derivatives : enable
-    //     // #extension GL_EXT_shader_texture_lod : enable
-    //     // #extension GL_EXT_frag_depth : enable
-    //     // #extension GL_EXT_draw_buffers : require
-    //     var regex = /#extension.+(GL_OVR_multiview2|GL_OES_standard_derivatives|GL_EXT_shader_texture_lod|GL_EXT_frag_depth|GL_EXT_draw_buffers).+(enable|require)/g;
-    //     var result = preparedSourceCode.replace(regex, "");
-
-    //     // Migrate to GLSL v300
-    //     result = result.replace(/varying(?![\n\r])\s/g, isFragment ? "in " : "out ");
-    //     result = result.replace(/attribute[ \t]/g, "in ");
-    //     result = result.replace(/[ \t]attribute/g, " in");
-
-    //     result = result.replace(/texture2D\s*\(/g, "texture(");
-    //     if (isFragment) {
-    //         result = result.replace(/texture2DLodEXT\s*\(/g, "textureLod(");
-    //         result = result.replace(/textureCubeLodEXT\s*\(/g, "textureLod(");
-    //         result = result.replace(/textureCube\s*\(/g, "texture(");
-    //         result = result.replace(/gl_FragDepthEXT/g, "gl_FragDepth");
-    //         result = result.replace(/gl_FragColor/g, "glFragColor");
-    //         result = result.replace(/gl_FragData/g, "glFragData");
-    //         if (this._engine.isWebGPU) {
-    //             result = result.replace(/void\s+?main\s*\(/g, "layout(location = 0) out vec4 glFragColor;\nvoid main(");
-    //         }
-    //         else {
-    //             result = result.replace(/void\s+?main\s*\(/g, (hasDrawBuffersExtension ? "" : "out vec4 glFragColor;\n") + "void main(");
-    //         }
-    //     }
-
-    //     // Add multiview setup to top of file when defined
-    //     var hasMultiviewExtension = this.defines.indexOf("#define MULTIVIEW\n") !== -1;
-    //     if (hasMultiviewExtension && !isFragment) {
-    //         result = "#extension GL_OVR_multiview2 : require\nlayout (num_views = 2) in;\n" + result;
-    //     }
-
-    //     callback(result);
-    // }
-
-    // private _processIncludes(sourceCode: string, callback: (data: any) => void): void {
-    //     var regex = /#include<(.+)>(\((.*)\))*(\[(.*)\])*/g;
-    //     var match = regex.exec(sourceCode);
-
-    //     var returnValue = new String(sourceCode);
-
-    //     while (match != null) {
-    //         var includeFile = match[1];
-
-    //         // Uniform declaration
-    //         if (includeFile.indexOf("__decl__") !== -1) {
-    //             includeFile = includeFile.replace(/__decl__/, "");
-    //             if (this._engine.supportsUniformBuffers) {
-    //                 includeFile = includeFile.replace(/Vertex/, "Ubo");
-    //                 includeFile = includeFile.replace(/Fragment/, "Ubo");
-    //             }
-    //             includeFile = includeFile + "Declaration";
-    //         }
-
-    //         if (Effect.IncludesShadersStore[includeFile]) {
-    //             // Substitution
-    //             var includeContent = Effect.IncludesShadersStore[includeFile];
-    //             if (match[2]) {
-    //                 var splits = match[3].split(",");
-
-    //                 for (var index = 0; index < splits.length; index += 2) {
-    //                     var source = new RegExp(splits[index], "g");
-    //                     var dest = splits[index + 1];
-
-    //                     includeContent = includeContent.replace(source, dest);
-    //                 }
-    //             }
-
-    //             if (match[4]) {
-    //                 var indexString = match[5];
-
-    //                 if (indexString.indexOf("..") !== -1) {
-    //                     var indexSplits = indexString.split("..");
-    //                     var minIndex = parseInt(indexSplits[0]);
-    //                     var maxIndex = parseInt(indexSplits[1]);
-    //                     var sourceIncludeContent = includeContent.slice(0);
-    //                     includeContent = "";
-
-    //                     if (isNaN(maxIndex)) {
-    //                         maxIndex = this._indexParameters[indexSplits[1]];
-    //                     }
-
-    //                     for (var i = minIndex; i < maxIndex; i++) {
-    //                         if (!this._engine.supportsUniformBuffers) {
-    //                             // Ubo replacement
-    //                             sourceIncludeContent = sourceIncludeContent.replace(/light\{X\}.(\w*)/g, (str: string, p1: string) => {
-    //                                 return p1 + "{X}";
-    //                             });
-    //                         }
-    //                         includeContent += sourceIncludeContent.replace(/\{X\}/g, i.toString()) + "\n";
-    //                     }
-    //                 } else {
-    //                     if (!this._engine.supportsUniformBuffers) {
-    //                         // Ubo replacement
-    //                         includeContent = includeContent.replace(/light\{X\}.(\w*)/g, (str: string, p1: string) => {
-    //                             return p1 + "{X}";
-    //                         });
-    //                     }
-    //                     includeContent = includeContent.replace(/\{X\}/g, indexString);
-    //                 }
-    //             }
-
-    //             // Replace
-    //             returnValue = returnValue.replace(match[0], includeContent);
-    //         } else {
-    //             var includeShaderUrl = Effect.ShadersRepository + "ShadersInclude/" + includeFile + ".fx";
-
-    //             this._engine._loadFile(includeShaderUrl, (fileContent) => {
-    //                 Effect.IncludesShadersStore[includeFile] = fileContent as string;
-    //                 this._processIncludes(<string>returnValue, callback);
-    //             });
-    //             return;
-    //         }
-
-    //         match = regex.exec(sourceCode);
-    //     }
-
-    //     callback(returnValue);
-    // }
-
-    // private _processPrecision(source: string): string {
-    //     const shouldUseHighPrecisionShader = this._engine._shouldUseHighPrecisionShader;
-
-    //     if (source.indexOf("precision highp float") === -1) {
-    //         if (!shouldUseHighPrecisionShader) {
-    //             source = "precision mediump float;\n" + source;
-    //         } else {
-    //             source = "precision highp float;\n" + source;
-    //         }
-    //     } else {
-    //         if (!shouldUseHighPrecisionShader) { // Moving highp to mediump
-    //             source = source.replace("precision highp float", "precision mediump float");
-    //         }
-    //     }
-
-    //     return source;
-    // }
-
     /**
      * Recompiles the webGL program
      * @param vertexSourceCode The source code for the vertex shader.