瀏覽代碼

Merge pull request #5290 from BabylonJS/parallelCompilation

First commit
David Catuhe 6 年之前
父節點
當前提交
21f33e643d
共有 4 個文件被更改,包括 114 次插入36 次删除
  1. 64 1
      src/Engine/babylon.engine.ts
  2. 2 1
      src/Engine/babylon.nullEngine.ts
  3. 40 34
      src/Materials/babylon.effect.ts
  4. 8 0
      src/babylon.mixins.ts

+ 64 - 1
src/Engine/babylon.engine.ts

@@ -157,6 +157,12 @@ module BABYLON {
         public timerQuery: EXT_disjoint_timer_query;
         /** Defines if timestamp can be used with timer query */
         public canUseTimestampForTimerQuery: boolean;
+        /** Function used to let the system compiles shaders in background */
+        public parallelShaderCompile: {
+            MAX_SHADER_COMPILER_THREADS_KHR: number;
+            maxShaderCompilerThreadsKHR: (thread: number) => void;           
+            COMPLETION_STATUS_KHR: number;
+        }
     }
 
     /** Interface defining initialization parameters for Engine class */
@@ -1352,6 +1358,13 @@ module BABYLON {
                 }
             }
 
+            // Shader compiler threads
+            this._caps.parallelShaderCompile = this._gl.getExtension('KHR_parallel_shader_compile');
+            if (this._caps.parallelShaderCompile) {
+                const threads = this._gl.getParameter(this._caps.parallelShaderCompile.MAX_SHADER_COMPILER_THREADS_KHR);
+                this._caps.parallelShaderCompile.maxShaderCompilerThreadsKHR(threads);
+            }
+
             // Depth Texture
             if (this._webGLVersion > 1) {
                 this._caps.depthTextureExtension = true;
@@ -1379,6 +1392,7 @@ module BABYLON {
                     this._caps.vertexArrayObject = false;
                 }
             }
+
             // Instances count
             if (this._webGLVersion > 1) {
                 this._caps.instancedArrays = true;
@@ -3305,6 +3319,24 @@ module BABYLON {
                 this.bindTransformFeedback(null);
             }
 
+            shaderProgram.context = context;
+            shaderProgram.vertexShader = vertexShader;
+            shaderProgram.fragmentShader = fragmentShader;
+
+            if (!this._caps.parallelShaderCompile) {
+                this._finalizeProgram(shaderProgram);
+            } else {
+                shaderProgram.isParallelCompiled = true;
+            }
+
+            return shaderProgram;
+        }
+
+        private _finalizeProgram(shaderProgram: WebGLProgram) {
+            const context = shaderProgram.context!;
+            const vertexShader = shaderProgram.vertexShader!;
+            const fragmentShader = shaderProgram.fragmentShader!;
+
             var linked = context.getProgramParameter(shaderProgram, context.LINK_STATUS);
 
             if (!linked) {
@@ -3329,7 +3361,38 @@ module BABYLON {
             context.deleteShader(vertexShader);
             context.deleteShader(fragmentShader);
 
-            return shaderProgram;
+            shaderProgram.context = undefined;
+            shaderProgram.vertexShader = undefined;
+            shaderProgram.fragmentShader = undefined;
+
+            if (shaderProgram.onCompiled) {
+                shaderProgram.onCompiled();
+                shaderProgram.onCompiled = undefined;
+            }
+        }
+
+        /** @hidden */
+        public _isProgramCompiled(shaderProgram: WebGLProgram): boolean {
+           if (!shaderProgram.isParallelCompiled) {
+               return true;
+           }
+
+           if (this._gl.getProgramParameter(shaderProgram, this._caps.parallelShaderCompile.COMPLETION_STATUS_KHR)) {
+               this._finalizeProgram(shaderProgram);
+               return true;
+           }
+
+           return false;
+        }
+
+        /** @hidden */
+        public _executeWhenProgramIsCompiled(shaderProgram: WebGLProgram, action: () => void) {
+            if (!shaderProgram.isParallelCompiled) {
+                action();
+                return;
+            }
+
+            shaderProgram.onCompiled = action;
         }
 
         /**

+ 2 - 1
src/Engine/babylon.nullEngine.ts

@@ -173,7 +173,8 @@ module BABYLON {
         public createShaderProgram(vertexCode: string, fragmentCode: string, defines: string, context?: WebGLRenderingContext): WebGLProgram {
             return {
                 transformFeedback: null,
-                __SPECTOR_rebuildProgram: null
+                __SPECTOR_rebuildProgram: null,
+                isParallelCompiled: false
             };
         }
 

+ 40 - 34
src/Materials/babylon.effect.ts

@@ -363,6 +363,9 @@ module BABYLON {
          * @returns if the effect is compiled and prepared.
          */
         public isReady(): boolean {
+            if (!this._isReady && this._program && this._program.isParallelCompiled) {
+                return this._engine._isProgramCompiled(this._program);
+            }
             return this._isReady;
         }
 
@@ -784,43 +787,46 @@ module BABYLON {
                 }
                 this._program.__SPECTOR_rebuildProgram = this._rebuildProgram.bind(this);
 
-                if (engine.supportsUniformBuffers) {
-                    for (var name in this._uniformBuffersNames) {
-                        this.bindUniformBlock(name, this._uniformBuffersNames[name]);
+                engine._executeWhenProgramIsCompiled(this._program, () => {
+                    if (engine.supportsUniformBuffers) {
+                        for (var name in this._uniformBuffersNames) {
+                            this.bindUniformBlock(name, this._uniformBuffersNames[name]);
+                        }
                     }
-                }
-
-                this._uniforms = engine.getUniforms(this._program, this._uniformsNames);
-                this._attributes = engine.getAttributes(this._program, attributesNames);
-
-                var index: number;
-                for (index = 0; index < this._samplers.length; index++) {
-                    var sampler = this.getUniform(this._samplers[index]);
-
-                    if (sampler == null) {
-                        this._samplers.splice(index, 1);
-                        index--;
+    
+                    this._uniforms = engine.getUniforms(this._program, this._uniformsNames);
+                    this._attributes = engine.getAttributes(this._program, attributesNames);
+    
+                    var index: number;
+                    for (index = 0; index < this._samplers.length; index++) {
+                        var sampler = this.getUniform(this._samplers[index]);
+    
+                        if (sampler == null) {
+                            this._samplers.splice(index, 1);
+                            index--;
+                        }
                     }
-                }
-
-                engine.bindSamplers(this);
-
-                this._compilationError = "";
-                this._isReady = true;
-                if (this.onCompiled) {
-                    this.onCompiled(this);
-                }
-                this.onCompileObservable.notifyObservers(this);
-                this.onCompileObservable.clear();
-
-                // Unbind mesh reference in fallbacks
-                if (this._fallbacks) {
-                    this._fallbacks.unBindMesh();
-                }
+    
+                    engine.bindSamplers(this);
+    
+                    this._compilationError = "";
+                    this._isReady = true;
+                    if (this.onCompiled) {
+                        this.onCompiled(this);
+                    }
+                    this.onCompileObservable.notifyObservers(this);
+                    this.onCompileObservable.clear();
+    
+                    // Unbind mesh reference in fallbacks
+                    if (this._fallbacks) {
+                        this._fallbacks.unBindMesh();
+                    }
+    
+                    if (previousProgram) {
+                        this.getEngine()._deleteProgram(previousProgram);
+                    }
+                });
 
-                if (previousProgram) {
-                    this.getEngine()._deleteProgram(previousProgram);
-                }
             } catch (e) {
                 this._compilationError = e.message;
 

+ 8 - 0
src/babylon.mixins.ts

@@ -22,6 +22,14 @@ interface Window {
     setImmediate(handler: (...args: any[]) => void): number;
 }
 
+interface WebGLProgram {
+    context?: WebGLRenderingContext;
+    vertexShader?: WebGLShader;
+    fragmentShader?: WebGLShader;
+    isParallelCompiled: boolean;
+    onCompiled?: () => void;
+}
+
 interface WebGLRenderingContext {
     drawArraysInstanced(mode: number, first: number, count: number, primcount: number): void;
     drawElementsInstanced(mode: number, count: number, type: number, offset: number, primcount: number): void;