forked from galacean/engine
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathShaderLab.ts
148 lines (127 loc) · 4.16 KB
/
ShaderLab.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
import { Lexer } from "./lexer";
import { ShaderTargetParser } from "./parser";
import { Preprocessor } from "./preprocessor";
import { GLES100Visitor, GLES300Visitor } from "./codeGen";
import { IShaderContent, IShaderLab } from "@galacean/engine-design";
import { ShaderContentParser } from "./contentParser";
// @ts-ignore
import { Logger, ShaderLib, ShaderMacro, ShaderPlatformTarget } from "@galacean/engine";
import { ShaderPosition, ShaderRange } from "./common";
// #if _VERBOSE
import { GSError } from "./GSError";
// #endif
import { PpParser } from "./preprocessor/PpParser";
import { ShaderLabUtils } from "./ShaderLabUtils";
import { IShaderProgramSource } from "@galacean/engine-design/types/shader-lab/IShaderProgramSource";
/** @internal */
export class ShaderLab implements IShaderLab {
private static _parser = ShaderTargetParser.create();
private static _shaderPositionPool = ShaderLabUtils.createObjectPool(ShaderPosition);
private static _shaderRangePool = ShaderLabUtils.createObjectPool(ShaderRange);
// #if _VERBOSE
static _processingPassText?: string;
// #endif
static createPosition(index: number, line?: number, column?: number): ShaderPosition {
const position = this._shaderPositionPool.get();
position.set(
index,
// #if _VERBOSE
line,
column
// #endif
);
return position;
}
static createRange(start: ShaderPosition, end: ShaderPosition): ShaderRange {
const range = this._shaderRangePool.get();
range.set(start, end);
return range;
}
// #if _VERBOSE
/** Retrieve the compilation errors */
readonly errors: Error[] = [];
// #endif
_parseShaderPass(
source: string,
vertexEntry: string,
fragmentEntry: string,
macros: ShaderMacro[],
backend: ShaderPlatformTarget,
platformMacros: string[],
basePathForIncludeKey: string
): IShaderProgramSource | undefined {
Preprocessor.reset(ShaderLib, basePathForIncludeKey);
for (const macro of macros) {
Preprocessor.addPredefinedMacro(macro.name, macro.value);
}
for (let i = 0; i < platformMacros.length; i++) {
Preprocessor.addPredefinedMacro(platformMacros[i]);
}
const preprocessorStart = performance.now();
const ppdContent = Preprocessor.process(source);
// #if _VERBOSE
if (PpParser._errors.length > 0) {
for (const err of PpParser._errors) {
this.errors.push(<GSError>err);
}
this._logErrors();
return undefined;
}
// #endif
Logger.info(`[pass compilation - preprocessor] cost time ${performance.now() - preprocessorStart}ms`);
const lexer = new Lexer(ppdContent);
const tokens = lexer.tokenize();
const { _parser: parser } = ShaderLab;
ShaderLab._processingPassText = ppdContent;
const program = parser.parse(tokens);
// #if _VERBOSE
for (const err of parser.errors) {
this.errors.push(err);
}
// #endif
if (!program) {
// #if _VERBOSE
this._logErrors();
// #endif
return undefined;
}
const codeGen =
backend === ShaderPlatformTarget.GLES100 ? GLES100Visitor.getVisitor() : GLES300Visitor.getVisitor();
const start = performance.now();
const ret = codeGen.visitShaderProgram(program, vertexEntry, fragmentEntry);
Logger.info(`[CodeGen] cost time: ${performance.now() - start}ms`);
ShaderLab._processingPassText = undefined;
// #if _VERBOSE
for (const err of codeGen.errors) {
this.errors.push(err);
}
this._logErrors();
// #endif
return ret;
}
_parseShaderContent(shaderSource: string): IShaderContent {
ShaderLabUtils.clearAllShaderLabObjectPool();
ShaderContentParser.reset();
const ret = ShaderContentParser.parse(shaderSource);
// #if _VERBOSE
this.errors.length = 0;
for (const error of ShaderContentParser._errors) {
this.errors.push(error);
}
// #endif
return ret;
}
// #if _VERBOSE
/**
* @internal
*/
_logErrors() {
const errors = this.errors;
if (errors.length === 0 || !Logger.isEnabled) return;
Logger.error(`${errors.length} errors occur!`);
for (const err of errors) {
Logger.error(err.toString());
}
}
// #endif
}