Преглед изворни кода

Allow logging of shader code when a compilation error occurs

Popov72 пре 5 година
родитељ
комит
8389cc6c01
1 измењених фајлова са 49 додато и 0 уклоњено
  1. 49 0
      src/Materials/effect.ts

+ 49 - 0
src/Materials/effect.ts

@@ -10,6 +10,7 @@ import { ShaderProcessor } from '../Engines/Processors/shaderProcessor';
 import { IMatrixLike, IVector2Like, IVector3Like, IVector4Like, IColor3Like, IColor4Like } from '../Maths/math.like';
 import { ThinEngine } from '../Engines/thinEngine';
 import { IEffectFallbacks } from './iEffectFallbacks';
+import { WebGLPipelineContext } from '../Engines/WebGL/webGLPipelineContext';
 
 declare type Engine = import("../Engines/engine").Engine;
 declare type InternalTexture = import("../Materials/Textures/internalTexture").InternalTexture;
@@ -76,6 +77,10 @@ export class Effect implements IDisposable {
      */
     public static ShadersRepository = "src/Shaders/";
     /**
+     * Enable logging of the shader code when a compilation error occurs
+     */
+    public static LogShaderCodeOnCompilationError = true;
+    /**
      * Name of the effect.
      */
     public name: any = null;
@@ -612,6 +617,26 @@ export class Effect implements IDisposable {
         }
     }
 
+    private _getShaderCodeAndErrorLine(shader: WebGLShader, error: Nullable<string>, isFragment: boolean): [Nullable<string>, Nullable<string>] {
+        const regexp = isFragment ? /FRAGMENT SHADER ERROR: 0:(\d+?):/ : /VERTEX SHADER ERROR: 0:(\d+?):/;
+        const code = this._engine?._gl?.getShaderSource(shader) ?? null;
+
+        let errorLine = null;
+
+        if (error && code) {
+            const res = error.match(regexp);
+            if (res && res.length === 2) {
+                const lineNumber = parseInt(res[1]);
+                const lines = code.split("\n", -1);
+                if (lines.length >= lineNumber) {
+                    errorLine = `Offending line [${lineNumber}] in ${isFragment ? "fragment" : "vertex"} code: ${lines[lineNumber - 1]}`;
+                }
+            }
+        }
+
+        return [code, errorLine];
+    }
+
     private _processCompilationErrors(e: any, previousPipelineContext: Nullable<IPipelineContext> = null) {
         this._compilationError = e.message;
         let attributesNames = this._attributesNames;
@@ -626,6 +651,30 @@ export class Effect implements IDisposable {
             return " " + attribute;
         }));
         Logger.Error("Defines:\r\n" + this.defines);
+        if (Effect.LogShaderCodeOnCompilationError) {
+            let pcw = this._pipelineContext as WebGLPipelineContext;
+            let lineErrorVertex = null, lineErrorFragment = null, code = null;
+            if (pcw.vertexShader) {
+                [code, lineErrorVertex] = this._getShaderCodeAndErrorLine(pcw.vertexShader, this._compilationError, false);
+                if (code) {
+                    Logger.Error("Vertex code:");
+                    Logger.Error(code);
+                }
+            }
+            if (pcw.fragmentShader) {
+                [code, lineErrorFragment] = this._getShaderCodeAndErrorLine(pcw.fragmentShader, this._compilationError, true);
+                if (code) {
+                    Logger.Error("Fragment code:");
+                    Logger.Error(code);
+                }
+            }
+            if (lineErrorVertex) {
+                Logger.Error(lineErrorVertex);
+            }
+            if (lineErrorFragment) {
+                Logger.Error(lineErrorFragment);
+            }
+        }
         Logger.Error("Error: " + this._compilationError);
         if (previousPipelineContext) {
             this._pipelineContext = previousPipelineContext;