Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ShaderLab support MRT #2452

Merged
merged 32 commits into from
Dec 24, 2024
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
ad984da
feat: add mrt syntax
Sway007 Dec 5, 2024
e40dfd2
Merge branch 'dev/1.4' of github.com:galacean/engine into feat/shader…
Sway007 Dec 5, 2024
ebb3b91
feat: mrt code gen
Sway007 Dec 5, 2024
6368479
feat: code opt
Sway007 Dec 5, 2024
9e654a0
feat: code opt
Sway007 Dec 9, 2024
79f87b2
feat: add e2e and unitest case
Sway007 Dec 9, 2024
07f5f60
fix: code gen of invalid mrt property
Sway007 Dec 9, 2024
85adcc1
Merge branch 'dev/1.4' of github.com:galacean/engine into feat/shader…
Sway007 Dec 12, 2024
dfbfb80
revert: vitest config
Sway007 Dec 12, 2024
f5ddea8
feat: code opt
Sway007 Dec 13, 2024
5a3c447
feat: code opt
Sway007 Dec 16, 2024
e141551
Merge branch 'dev/1.4' of github.com:galacean/engine into feat/shader…
Sway007 Dec 17, 2024
e59f8b2
feat: code opt
Sway007 Dec 17, 2024
4a7c9fc
fix: resolve confict of mrt return
Sway007 Dec 17, 2024
31a90ee
feat: code opt
Sway007 Dec 17, 2024
58892a5
fix: type error
Sway007 Dec 17, 2024
c4be16e
feat: code opt
Sway007 Dec 17, 2024
8604847
feat: update test case
Sway007 Dec 17, 2024
85b7291
feat: code opt
Sway007 Dec 18, 2024
aa905b1
feat: code opt
Sway007 Dec 18, 2024
ab68939
feat: code opt
Sway007 Dec 19, 2024
3ebe87e
feat: code opt
Sway007 Dec 23, 2024
78c1919
refactor: opt code
GuoLei1990 Dec 23, 2024
20b1f01
fix: unitest
Sway007 Dec 23, 2024
3e6f35e
feat: rename ENonTerminal -> NoneTerminal
Sway007 Dec 23, 2024
15728c0
refactor: opt code
GuoLei1990 Dec 23, 2024
207dd18
feat: code opt
Sway007 Dec 24, 2024
528c1e2
feat: code opt
Sway007 Dec 24, 2024
324cd87
refactor: code opt
Sway007 Dec 24, 2024
a7d3cdf
feat: code opt
Sway007 Dec 24, 2024
1350cc9
feat: code opt
Sway007 Dec 24, 2024
e0ec460
feat: rename
Sway007 Dec 24, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 111 additions & 0 deletions e2e/case/shaderLab-mrt.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/**
* @title ShaderLab MRT
* @category Material
*/

import { Camera, Color, Logger, Material, MeshRenderer, PrimitiveMesh, Shader, WebGLEngine } from "@galacean/engine";
import { ShaderLab } from "@galacean/engine-shader-lab";
import { initScreenshot, updateForE2E } from "./.mockForE2E";

Check warning on line 8 in e2e/case/shaderLab-mrt.ts

View check run for this annotation

Codecov / codecov/patch

e2e/case/shaderLab-mrt.ts#L6-L8

Added lines #L6 - L8 were not covered by tests

const shaderLab = new ShaderLab();

Check warning on line 10 in e2e/case/shaderLab-mrt.ts

View check run for this annotation

Codecov / codecov/patch

e2e/case/shaderLab-mrt.ts#L10

Added line #L10 was not covered by tests

const shaderSource = `Shader "/custom.gs" {

Check warning on line 12 in e2e/case/shaderLab-mrt.ts

View check run for this annotation

Codecov / codecov/patch

e2e/case/shaderLab-mrt.ts#L12

Added line #L12 was not covered by tests
SubShader "Default" {
UsePass "pbr/Default/ShadowCaster"

Pass "Pass0" {
struct Attributes {
vec3 POSITION;
vec2 TEXCOORD_0;
vec4 JOINTS_0;
vec4 WEIGHTS_0;
};

struct Varyings {
vec2 uv;
};

mat4 renderer_MVPMat;

vec4 material_BaseColor;


VertexShader = vert;
FragmentShader = frag;

Varyings vert(Attributes attr) {
Varyings v;

vec4 position = vec4(attr.POSITION, 1.0);

// Skin
#ifdef RENDERER_HAS_SKIN
mat4 skinMatrix = getSkinMatrix(attr);
position = skinMatrix * position;
#endif

gl_Position = renderer_MVPMat * position;
v.uv = attr.TEXCOORD_0;

return v;
}

struct mrt {
layout(location = 0) vec4 fragColor0;
layout(location = 1) vec4 fragColor1;
};

mrt frag(Varyings v) {
mrt o;

vec4 baseColor = material_BaseColor;

#ifdef MATERIAL_HAS_BASETEXTURE
vec4 textureColor = texture2D(material_BaseTexture, v.uv);
#ifndef ENGINE_IS_COLORSPACE_GAMMA
textureColor = gammaToLinear(textureColor);
#endif
baseColor *= textureColor;
#endif

#ifdef MATERIAL_IS_ALPHA_CUTOFF
if( baseColor.a < material_AlphaCutoff ) {
discard;
}
#endif

o.fragColor0 = baseColor;
o.fragColor1 = baseColor;
zhuxudong marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
}`;

Logger.enable();
WebGLEngine.create({ canvas: "canvas", shaderLab }).then((engine) => {
engine.canvas.resizeByClientSize();

Check warning on line 86 in e2e/case/shaderLab-mrt.ts

View check run for this annotation

Codecov / codecov/patch

e2e/case/shaderLab-mrt.ts#L84-L86

Added lines #L84 - L86 were not covered by tests

const shader = Shader.create(shaderSource);
const scene = engine.sceneManager.activeScene;
const rootEntity = scene.createRootEntity();

Check warning on line 90 in e2e/case/shaderLab-mrt.ts

View check run for this annotation

Codecov / codecov/patch

e2e/case/shaderLab-mrt.ts#L88-L90

Added lines #L88 - L90 were not covered by tests

// camera
const cameraEntity = rootEntity.createChild("cameraNode");
cameraEntity.transform.setPosition(0, 0, 5);
const camera = cameraEntity.addComponent(Camera);

Check warning on line 95 in e2e/case/shaderLab-mrt.ts

View check run for this annotation

Codecov / codecov/patch

e2e/case/shaderLab-mrt.ts#L93-L95

Added lines #L93 - L95 were not covered by tests

// sphere
{
const sphere = rootEntity.createChild("sphere");
sphere.transform.position.x = -1;
const renderer = sphere.addComponent(MeshRenderer);
renderer.mesh = PrimitiveMesh.createSphere(engine);
const material = new Material(engine, shader);
material.shaderData.setColor("material_BaseColor", new Color(1, 0, 0, 0.2));
renderer.setMaterial(material);
}

Check warning on line 106 in e2e/case/shaderLab-mrt.ts

View check run for this annotation

Codecov / codecov/patch

e2e/case/shaderLab-mrt.ts#L98-L106

Added lines #L98 - L106 were not covered by tests

updateForE2E(engine);

Check warning on line 108 in e2e/case/shaderLab-mrt.ts

View check run for this annotation

Codecov / codecov/patch

e2e/case/shaderLab-mrt.ts#L108

Added line #L108 was not covered by tests

initScreenshot(engine, camera);
});

Check warning on line 111 in e2e/case/shaderLab-mrt.ts

View check run for this annotation

Codecov / codecov/patch

e2e/case/shaderLab-mrt.ts#L110-L111

Added lines #L110 - L111 were not covered by tests
5 changes: 5 additions & 0 deletions e2e/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,11 @@
caseFileName: "material-shaderLab",
threshold: 0.2
},
shaderLabMRT: {
category: "Material",
caseFileName: "shaderLab-mrt",
threshold: 0.2
},

Check warning on line 117 in e2e/config.ts

View check run for this annotation

Codecov / codecov/patch

e2e/config.ts#L113-L117

Added lines #L113 - L117 were not covered by tests
shaderReplacement: {
category: "Material",
caseFileName: "material-shaderReplacement",
Expand Down
3 changes: 3 additions & 0 deletions e2e/fixtures/originImage/Material_shaderLab-mrt.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 2 additions & 1 deletion packages/shader-lab/src/GSError.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ export class GSError extends Error {
if (i === start.line) {
remarkStart = start.column;
paddingLength += start.column;
} else if (i === end.line) {
}
if (i === end.line) {
GuoLei1990 marked this conversation as resolved.
Show resolved Hide resolved
remarkEnd = end.column;
}
const remarkLength = Math.max(remarkEnd - remarkStart, 1);
Expand Down
52 changes: 39 additions & 13 deletions packages/shader-lab/src/codeGen/CodeGenVisitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
// #if _VERBOSE
import { GSError } from "../GSError";
// #endif
import { ShaderLabUtils } from "../ShaderLabUtils";
import { Logger, ReturnableObjectPool } from "@galacean/engine";
import { TempArray } from "../TempArray";

Expand All @@ -23,6 +22,10 @@
// #if _VERBOSE
readonly errors: Error[] = [];
// #endif

abstract getFragDataCodeGen(index: string | number): string;

abstract getReferencedMRTPropText(index: string | number, ident: string): string;
protected static _tmpArrayPool = new ReturnableObjectPool(TempArray<string>, 10);

defaultCodeGen(children: NodeChild[]) {
Expand All @@ -41,36 +44,55 @@
}

visitPostfixExpression(node: ASTNode.PostfixExpression) {
if (node.children.length === 3) {
const context = VisitorContext.context;
const derivationLength = node.children.length;
const context = VisitorContext.context;

if (derivationLength === 3) {
const postExpr = node.children[0] as ASTNode.PostfixExpression;

const prop = node.children[2];

if (prop instanceof Token) {
if (context.isAttributeStruct(<string>postExpr.type)) {
const error = context.referenceAttribute(prop);
// #if _VERBOSE
if (error) {
// #if _VERBOSE
this.errors.push(<GSError>error);
// #endif
}
// #endif
return prop.lexeme;
} else if (context.isVaryingStruct(<string>postExpr.type)) {
const error = context.referenceVarying(prop);
// #if _VERBOSE
if (error) {
// #if _VERBOSE
this.errors.push(<GSError>error);
// #endif
}
return prop.lexeme;
} else if (context.isMRTStruct(<string>postExpr.type)) {
const error = context.referenceMRTProp(prop);
if (error) {
// #if _VERBOSE

Check warning on line 74 in packages/shader-lab/src/codeGen/CodeGenVisitor.ts

View check run for this annotation

Codecov / codecov/patch

packages/shader-lab/src/codeGen/CodeGenVisitor.ts#L74

Added line #L74 was not covered by tests
this.errors.push(<GSError>error);
// #endif

Check warning on line 76 in packages/shader-lab/src/codeGen/CodeGenVisitor.ts

View check run for this annotation

Codecov / codecov/patch

packages/shader-lab/src/codeGen/CodeGenVisitor.ts#L76

Added line #L76 was not covered by tests
}
// #endif
return prop.lexeme;
}

return `${postExpr.codeGen(this)}.${prop.lexeme}`;
} else {
return `${postExpr.codeGen(this)}.${prop.codeGen(this)}`;
}
} else if (derivationLength === 4) {
const identNode = node.children[0] as ASTNode.PostfixExpression;
const indexNode = node.children[2] as ASTNode.Expression;
const identLexeme = identNode.codeGen(this);
const indexLexeme = indexNode.codeGen(this);
if (identLexeme === "gl_FragData") {
const mrtLexeme = this.getFragDataCodeGen(indexLexeme);
context._referencedMRTList[mrtLexeme] = this.getReferencedMRTPropText(indexLexeme, mrtLexeme);
return mrtLexeme;
}
return `${identLexeme}[${indexLexeme}]`;
}
return this.defaultCodeGen(node.children);
}
Expand Down Expand Up @@ -134,12 +156,12 @@
}

visitDeclaration(node: ASTNode.Declaration): string {
const { context } = VisitorContext;
const child = node.children[0];
if (
child instanceof ASTNode.InitDeclaratorList &&
child.typeInfo.typeLexeme === VisitorContext.context.varyingStruct?.ident?.lexeme
) {
return "";

if (child instanceof ASTNode.InitDeclaratorList) {
const typeLexeme = child.typeInfo.typeLexeme;
if (context.isVaryingStruct(typeLexeme) || context.isMRTStruct(typeLexeme)) return "";
Sway007 marked this conversation as resolved.
Show resolved Hide resolved
}
return this.defaultCodeGen(node.children);
zhuxudong marked this conversation as resolved.
Show resolved Hide resolved
}
Expand Down Expand Up @@ -198,6 +220,10 @@
return this.defaultCodeGen(node.children);
}

visitLayoutQualifier(node: ASTNode.LayoutQualifier): string {
return this.defaultCodeGen(node.children);
}

Check warning on line 225 in packages/shader-lab/src/codeGen/CodeGenVisitor.ts

View check run for this annotation

Codecov / codecov/patch

packages/shader-lab/src/codeGen/CodeGenVisitor.ts#L224-L225

Added lines #L224 - L225 were not covered by tests

protected _reportError(loc: ShaderRange | ShaderPosition, message: string): void {
// #if _VERBOSE
this.errors.push(new GSError(GSErrorName.CompilationError, message, loc, ShaderLab._processingPassText));
Expand Down
38 changes: 38 additions & 0 deletions packages/shader-lab/src/codeGen/GLES100.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { BaseToken } from "../common/BaseToken";
import { ASTNode } from "../parser/AST";
import { GLESVisitor } from "./GLESVisitor";
import { VisitorContext } from "./VisitorContext";
import { ICodeSegment } from "./types";
Expand All @@ -21,6 +23,14 @@
return this._singleton;
}

override getFragDataCodeGen(index: string | number): string {
return `gl_FragData[${index}]`;
}

Check warning on line 28 in packages/shader-lab/src/codeGen/GLES100.ts

View check run for this annotation

Codecov / codecov/patch

packages/shader-lab/src/codeGen/GLES100.ts#L27-L28

Added lines #L27 - L28 were not covered by tests

override getReferencedMRTPropText(index: string | number, ident: string): string {
return "";
}

Check warning on line 32 in packages/shader-lab/src/codeGen/GLES100.ts

View check run for this annotation

Codecov / codecov/patch

packages/shader-lab/src/codeGen/GLES100.ts#L31-L32

Added lines #L31 - L32 were not covered by tests

override getAttributeDeclare(): ICodeSegment[] {
const ret: ICodeSegment[] = [];
for (const item of Object.values(VisitorContext.context._referencedAttributeList)) {
Expand All @@ -42,4 +52,32 @@
}
return ret;
}

override getMRTDeclare(): ICodeSegment[] | undefined {
return;
Sway007 marked this conversation as resolved.
Show resolved Hide resolved
}

override visitPostfixExpression(node: ASTNode.PostfixExpression): string {
const { children } = node;
const postExpr = children[0];
const { context } = VisitorContext;
if (postExpr instanceof ASTNode.PostfixExpression && context.isMRTStruct(<string>postExpr.type)) {
const propReferenced = children[2] as BaseToken;
const prop = context.mrtStruct!.propList.find((item) => item.ident.lexeme === propReferenced.lexeme);
if (!prop) {
this._reportError(propReferenced.location, `not found mrt property: ${propReferenced.lexeme}`);
return "";
}
return `gl_FragData[${prop.mrtIndex!}]`;
}

Check warning on line 72 in packages/shader-lab/src/codeGen/GLES100.ts

View check run for this annotation

Codecov / codecov/patch

packages/shader-lab/src/codeGen/GLES100.ts#L65-L72

Added lines #L65 - L72 were not covered by tests
return super.visitPostfixExpression(node);
}
Sway007 marked this conversation as resolved.
Show resolved Hide resolved

override visitJumpStatement(node: ASTNode.JumpStatement): string {
if (node.isFragReturnStatement) {
const expression = node.children[1] as ASTNode.Expression;
return `gl_FragColor = ${expression.codeGen(this)}`;
}

Check warning on line 80 in packages/shader-lab/src/codeGen/GLES100.ts

View check run for this annotation

Codecov / codecov/patch

packages/shader-lab/src/codeGen/GLES100.ts#L78-L80

Added lines #L78 - L80 were not covered by tests
return super.visitJumpStatement(node);
Sway007 marked this conversation as resolved.
Show resolved Hide resolved
}
}
59 changes: 56 additions & 3 deletions packages/shader-lab/src/codeGen/GLES300.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import { ShaderLab } from "../ShaderLab";

const V3_GL_FragColor = "GS_glFragColor";
const V3_GL_FragData = "GS_glFragData";

export class GLES300Visitor extends GLESVisitor {
override _versionText: string = "#version 300 es";
Expand All @@ -21,6 +22,14 @@
return this._singleton;
}

override getFragDataCodeGen(index: string | number): string {
return `${V3_GL_FragData}_${index}`;
}

override getReferencedMRTPropText(index: string | number, ident: string): string {
return `layout(location = ${index}) out vec4 ${ident};`;
}

override getAttributeDeclare(): ICodeSegment[] {
const ret: ICodeSegment[] = [];
for (const item of Object.values(VisitorContext.context._referencedAttributeList)) {
Expand All @@ -46,6 +55,26 @@
return ret;
}

override getMRTDeclare(): ICodeSegment[] {
const ret: ICodeSegment[] = [];
Sway007 marked this conversation as resolved.
Show resolved Hide resolved
const referencedMRTList = VisitorContext.context._referencedMRTList;
for (let ident in referencedMRTList) {
const info = referencedMRTList[ident];
if (typeof info === "string") {
ret.push({
text: info,
index: Number.MAX_SAFE_INTEGER
});
} else {
ret.push({
text: this.getReferencedMRTPropText(info.mrtIndex, ident),
index: info.ident.location.start.index
});
}
}
return ret;
}

override visitFunctionIdentifier(node: ASTNode.FunctionIdentifier): string {
const typeSpecifier = node.children[0] as ASTNode.TypeSpecifier;
if (typeSpecifier.children.length !== 1) {
Expand Down Expand Up @@ -81,11 +110,15 @@
}

override visitVariableIdentifier(node: ASTNode.VariableIdentifier): string {
if (VisitorContext.context.stage === EShaderStage.FRAGMENT && node.lexeme === "gl_FragColor") {
if (!VisitorContext.context._referencedVaryingList[V3_GL_FragColor]) {
const { context } = VisitorContext;
if (context.stage === EShaderStage.FRAGMENT && node.lexeme === "gl_FragColor") {
if (context.mrtStruct) {
this._reportError(node.location, "gl_FragColor cannot be used with MRT (Multiple Render Targets).");
}

Check warning on line 117 in packages/shader-lab/src/codeGen/GLES300.ts

View check run for this annotation

Codecov / codecov/patch

packages/shader-lab/src/codeGen/GLES300.ts#L116-L117

Added lines #L116 - L117 were not covered by tests
zhuxudong marked this conversation as resolved.
Show resolved Hide resolved
if (!context._referencedVaryingList[V3_GL_FragColor]) {
const token = Token.pool.get();
token.set(ETokenType.ID, V3_GL_FragColor, ShaderLab.createPosition(0, 0, 0));
VisitorContext.context._referencedVaryingList[V3_GL_FragColor] = {
context._referencedVaryingList[V3_GL_FragColor] = {
ident: token,
typeInfo: new SymbolType(EKeyword.VEC4, "vec4"),
qualifier: "out",
Expand All @@ -96,4 +129,24 @@
}
return super.visitVariableIdentifier(node);
}

override visitJumpStatement(node: ASTNode.JumpStatement): string {
if (node.isFragReturnStatement) {
const { _referencedVaryingList } = VisitorContext.context;
if (!_referencedVaryingList[V3_GL_FragColor]) {
const token = Token.pool.get();
token.set(ETokenType.ID, V3_GL_FragColor, ShaderLab.createPosition(0, 0, 0));
_referencedVaryingList[V3_GL_FragColor] = {
ident: token,
typeInfo: new SymbolType(EKeyword.VEC4, "vec4"),
qualifier: "out",
astNode: node
};
}
GuoLei1990 marked this conversation as resolved.
Show resolved Hide resolved

const expression = node.children[1] as ASTNode.Expression;
return `${V3_GL_FragColor} = ${expression.codeGen(this)};`;
}

Check warning on line 149 in packages/shader-lab/src/codeGen/GLES300.ts

View check run for this annotation

Codecov / codecov/patch

packages/shader-lab/src/codeGen/GLES300.ts#L135-L149

Added lines #L135 - L149 were not covered by tests
return super.visitJumpStatement(node);
}
}
Loading
Loading