diff --git a/packages/shader-lab/src/parser/AST.ts b/packages/shader-lab/src/parser/AST.ts index b8ffcf4999..46a0ff5dc6 100644 --- a/packages/shader-lab/src/parser/AST.ts +++ b/packages/shader-lab/src/parser/AST.ts @@ -717,9 +717,9 @@ export namespace ASTNode { } } // #if _VERBOSE - const builtinFn = BuiltinFunction.getFn(fnIdent, ...(paramSig ?? [])); + const builtinFn = BuiltinFunction.getFn(fnIdent, paramSig); if (builtinFn) { - this.type = BuiltinFunction.getReturnType(builtinFn.fun, builtinFn.genType); + this.type = builtinFn.realReturnType; return; } // #endif diff --git a/packages/shader-lab/src/parser/builtin/functions.ts b/packages/shader-lab/src/parser/builtin/functions.ts index a7ee936864..9e2df31585 100644 --- a/packages/shader-lab/src/parser/builtin/functions.ts +++ b/packages/shader-lab/src/parser/builtin/functions.ts @@ -28,11 +28,17 @@ function isGenericType(t: BuiltinType) { const BuiltinFunctionTable: Map = new Map(); export class BuiltinFunction { - private _returnType: BuiltinType; ident: string; readonly args: BuiltinType[]; readonly scope: EShaderStage; + private _returnType: BuiltinType; + private _realReturnType: NonGenericGalaceanType; + + get realReturnType(): NonGenericGalaceanType { + return this._realReturnType; + } + private constructor(ident: string, returnType: BuiltinType, scope: EShaderStage, ...args: BuiltinType[]) { this.ident = ident; this._returnType = returnType; @@ -59,33 +65,33 @@ export class BuiltinFunction { BuiltinFunctionTable.set(ident, list); } - static getFn( - ident: string, - ...args: BuiltinType[] - ): { fun: BuiltinFunction; genType: Exclude } | undefined { + static getFn(ident: string, parameterTypes: NonGenericGalaceanType[]): BuiltinFunction | undefined { const list = BuiltinFunctionTable.get(ident); - let realType = TypeAny; - if (list?.length) { - const fun = list.find((item) => { - if (item.args.length !== args.length) return false; - let genType = 0; - for (let i = 0; i < args.length; i++) { - if (args[i] === TypeAny) continue; - realType = args[i]; - if (isGenericType(item.args[i])) { - if (genType === 0) { - genType = args[i]; - continue; - } else { - realType = genType; + if (list) { + for (let length = list.length, i = 0; i < length; i++) { + const fn = list[i]; + const fnArgs = fn.args; + const argLength = fnArgs.length; + if (argLength !== parameterTypes.length) continue; + // Try to match generic parameter type. + let returnType = TypeAny; + let found = true; + for (let i = 0; i < argLength; i++) { + const curFnArg = fnArgs[i]; + if (isGenericType(curFnArg)) { + if (returnType === TypeAny) returnType = parameterTypes[i]; + } else { + if (curFnArg !== parameterTypes[i] && parameterTypes[i] !== TypeAny) { + found = false; + break; } } - if (args[i] === TypeAny) continue; - if (args[i] !== realType) return false; } - return true; - }); - if (fun) return { fun, genType: realType }; + if (found) { + fn._realReturnType = returnType; + return fn; + } + } } } } @@ -249,8 +255,8 @@ BuiltinFunction._create("textureSize", EKeyword.IVEC2, EKeyword.SAMPLER_CUBE_SHA BuiltinFunction._create("textureSize", EKeyword.IVEC3, EGenType.GSampler2DArray, EKeyword.INT); BuiltinFunction._create("textureSize", EKeyword.IVEC3, EKeyword.SAMPLER2D_ARRAY_SHADOW, EKeyword.INT); -BuiltinFunction._create("texture2D", EKeyword.SAMPLER2D, EKeyword.VEC2); -BuiltinFunction._create("texture2D", EKeyword.SAMPLER2D, EKeyword.VEC2, EKeyword.FLOAT); +BuiltinFunction._create("texture2D", EKeyword.VEC4, EKeyword.SAMPLER2D, EKeyword.VEC2); +BuiltinFunction._create("texture2D", EKeyword.VEC4, EKeyword.SAMPLER2D, EKeyword.VEC2, EKeyword.FLOAT); BuiltinFunction._create("texture", EGenType.GVec4, EGenType.GSampler2D, EKeyword.VEC2, EKeyword.FLOAT); BuiltinFunction._create("texture", EGenType.GVec4, EGenType.GSampler2D, EKeyword.VEC2); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 406b59d8ca..65e34c2305 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -304,6 +304,9 @@ importers: '@galacean/engine-shaderlab': specifier: workspace:* version: link:../packages/shader-lab + '@galacean/engine-shader-shaderlab': + specifier: workspace:* + version: link:../packages/shader-shaderlab devDependencies: '@vitest/browser': specifier: 2.1.3 diff --git a/tests/package.json b/tests/package.json index 2475ec254b..cd587121ed 100644 --- a/tests/package.json +++ b/tests/package.json @@ -23,7 +23,8 @@ "@galacean/engine-rhi-webgl": "workspace:*", "@galacean/engine-physics-lite": "workspace:*", "@galacean/engine-shaderlab": "workspace:*", - "@galacean/engine-physics-physx": "workspace:*" + "@galacean/engine-physics-physx": "workspace:*", + "@galacean/engine-shader-shaderlab": "workspace:*" }, "devDependencies": { "@vitest/browser": "2.1.3" diff --git a/tests/src/shader-lab/ShaderLab.test.ts b/tests/src/shader-lab/ShaderLab.test.ts index 60cec92ada..dc7f14dfe2 100644 --- a/tests/src/shader-lab/ShaderLab.test.ts +++ b/tests/src/shader-lab/ShaderLab.test.ts @@ -9,6 +9,7 @@ import { Color } from "@galacean/engine-math"; import { ShaderLab as ShaderLabVerbose, GSError } from "@galacean/engine-shaderlab/verbose"; import { ShaderLab as ShaderLabRelease } from "@galacean/engine-shaderlab"; import { glslValidate, shaderParse } from "./ShaderValidate"; +import { registerIncludes } from "@galacean/engine-shader-shaderlab"; import { IShaderContent } from "@galacean/engine-design"; import { describe, beforeAll, expect, assert, it } from "vitest"; @@ -17,6 +18,28 @@ const { readFile } = server.commands; const demoShader = await readFile("./shaders/demo.shader"); +const commonMacros = [ + { name: "RENDERER_IS_RECEIVE_SHADOWS" }, + { name: "MATERIAL_IS_TRANSPARENT" }, + { name: "RENDERER_HAS_UV" }, + { name: "RENDERER_HAS_NORMAL" }, + { name: "RENDERER_HAS_TANGENT" }, + { name: "SCENE_FOG_MODE", value: "0" }, + { name: "SCENE_SHADOW_CASCADED_COUNT", value: "1" }, + { name: "CAMERA_ORTHOGRAPHIC" }, + { name: "MATERIAL_NEED_WORLD_POS" }, + { name: "MATERIAL_NEED_TILING_OFFSET" }, + { name: "SCENE_DIRECT_LIGHT_COUNT", value: "1" }, + { name: "MATERIAL_ENABLE_SS_REFRACTION" }, + { name: "MATERIAL_HAS_TRANSMISSION" }, + { name: "MATERIAL_HAS_THICKNESS" }, + { name: "MATERIAL_HAS_ABSORPTION" }, + { name: "MATERIAL_HAS_TRANSMISSION_TEXTURE" }, + { name: "REFRACTION_SPHERE" } +] + .map((item) => `#define ${item.name} ${item.value ?? ""}`) + .join("\n"); + function toString(v: Color): string { return `Color(${v.r}, ${v.g}, ${v.b}, ${v.a})`; } @@ -124,6 +147,13 @@ describe("ShaderLab", () => { expect(passList[0].isUsePass).to.be.true; expect(passList[0].name).eq("pbr/Default/Forward"); pass1 = passList[1]; + registerIncludes(); + }); + + it("builtin-function", async () => { + let shaderSource = await readFile("./shaders/builtin-function.shader"); + shaderSource = shaderSource.replace("__$$insert_maros$$__", commonMacros); + glslValidate(shaderSource, shaderLabVerbose, {}); }); it("create shaderLab", async () => { diff --git a/tests/src/shader-lab/ShaderValidate.ts b/tests/src/shader-lab/ShaderValidate.ts index bf7bb14c8a..457a50de17 100644 --- a/tests/src/shader-lab/ShaderValidate.ts +++ b/tests/src/shader-lab/ShaderValidate.ts @@ -90,6 +90,11 @@ export function glslValidate(shaderSource, _shaderLab?: ShaderLab, includeMap = // @ts-ignore ShaderPass._shaderRootPath ); + if (shaderLab.errors) { + for (const error of shaderLab.errors) { + console.error(error.toString()); + } + } validateShaderPass(pass, compiledPass.vertex, compiledPass.fragment); }); }); diff --git a/tests/src/shader-lab/shaders/builtin-function.shader b/tests/src/shader-lab/shaders/builtin-function.shader new file mode 100644 index 0000000000..fc63ec3597 --- /dev/null +++ b/tests/src/shader-lab/shaders/builtin-function.shader @@ -0,0 +1,37 @@ +Shader "/Folder1/test.gs" { + SubShader "Default" { + UsePass "pbr/Default/ShadowCaster" + + Pass "Forward Pass" { + Tags { pipelineStage = "Forward"} + + DepthState { + WriteEnabled = depthWriteEnabled; + } + + BlendState { + Enabled = blendEnabled; + SourceColorBlendFactor = sourceColorBlendFactor; + DestinationColorBlendFactor = destinationColorBlendFactor; + SourceAlphaBlendFactor = sourceAlphaBlendFactor; + DestinationAlphaBlendFactor = destinationAlphaBlendFactor; + } + + RasterState{ + CullMode = rasterStateCullMode; + } + + RenderQueueType = renderQueueType; + + #define IS_METALLIC_WORKFLOW + #define MATERIAL_ENABLE_IRIDESCENCE + + __$$insert_maros$$__ + + VertexShader = PBRVertex; + FragmentShader = PBRFragment; + + #include "ForwardPassPBR.glsl" + } + } +}