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 22 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
113 changes: 113 additions & 0 deletions e2e/case/shaderLab-mrt.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
/**
* @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";

const shaderLab = new ShaderLab();

const shaderSource = `Shader "/custom.gs" {
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

return o;
}
}
}
}`;

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

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

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

// 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);
}

updateForE2E(engine);

initScreenshot(engine, camera);
});
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 @@ export const E2E_CONFIG = {
caseFileName: "material-shaderLab",
threshold: 0.2
},
shaderLabMRT: {
category: "Material",
caseFileName: "shaderLab-mrt",
threshold: 0.2
},
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
6 changes: 3 additions & 3 deletions packages/shader-lab/src/ShaderLabUtils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ClearableObjectPool, IPoolElement } from "@galacean/engine";
import { ClearableObjectPool, IPoolElement, Logger } from "@galacean/engine";
import { GSErrorName } from "./GSError";
import { ShaderRange } from "./common/ShaderRange";
import { ShaderPosition } from "./common/ShaderPosition";
Expand Down Expand Up @@ -27,11 +27,11 @@ export class ShaderLabUtils {
source: string,
location: ShaderRange | ShaderPosition,
file?: string
): Error {
): Error | undefined {
// #if _VERBOSE
return new GSError(errorName, message, location, source, file);
// #else
return new Error(`[${errorName}]: ${message}`);
Logger.error(message);
// #endif
Sway007 marked this conversation as resolved.
Show resolved Hide resolved
}
}
48 changes: 39 additions & 9 deletions packages/shader-lab/src/codeGen/CodeGenVisitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@ import { GSErrorName } from "../GSError";
// #if _VERBOSE
import { GSError } from "../GSError";
// #endif
import { ShaderLabUtils } from "../ShaderLabUtils";
import { Logger, ReturnableObjectPool } from "@galacean/engine";
import { TempArray } from "../TempArray";

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

/**
* @internal
* The code generator
Expand All @@ -23,6 +25,10 @@ export abstract class CodeGenVisitor {
// #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,11 +47,11 @@ export abstract class CodeGenVisitor {
}

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) {
Expand All @@ -65,12 +71,36 @@ export abstract class CodeGenVisitor {
}
// #endif
return prop.lexeme;
} else if (context.isMRTStruct(<string>postExpr.type)) {
const error = context.referenceMRTProp(prop);
// #if _VERBOSE
if (error) {
this.errors.push(<GSError>error);
}
// #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") {
// #if _VERBOSE
if (context._referencedVaryingList[V3_GL_FragColor]) {
this._reportError(identNode.location, "cannot use both gl_FragData and gl_FragColor");
}
// #endif
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 +164,12 @@ export abstract class CodeGenVisitor {
}

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
50 changes: 42 additions & 8 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,25 +23,57 @@ export class GLES100Visitor extends GLESVisitor {
return this._singleton;
}

override getAttributeDeclare(): ICodeSegment[] {
const ret: ICodeSegment[] = [];
override getFragDataCodeGen(index: string | number): string {
return `gl_FragData[${index}]`;
}

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

override getAttributeDeclare(out: ICodeSegment[]): void {
for (const item of Object.values(VisitorContext.context._referencedAttributeList)) {
ret.push({
out.push({
text: `attribute ${item.typeInfo.typeLexeme} ${item.ident.lexeme};`,
index: item.ident.location.start.index
});
}
return ret;
}

override getVaryingDeclare(): ICodeSegment[] {
const ret: ICodeSegment[] = [];
override getVaryingDeclare(out: ICodeSegment[]): void {
for (const item of Object.values(VisitorContext.context._referencedVaryingList)) {
ret.push({
out.push({
text: `varying ${item.typeInfo.typeLexeme} ${item.ident.lexeme};`,
index: item.ident.location.start.index
});
}
return ret;
}

override getMRTDeclare(out: ICodeSegment[]): void {
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!}]`;
}
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)}`;
}
return super.visitJumpStatement(node);
Sway007 marked this conversation as resolved.
Show resolved Hide resolved
}
}
Loading
Loading