From 12f7237e4060388494c549623f4a640327b7ca08 Mon Sep 17 00:00:00 2001 From: Yong He Date: Tue, 14 Nov 2023 17:46:05 -0800 Subject: Add GLSL Compatibility. (#3321) * Parse glsl buffer blocks to GLSLInterfaceBlockDecl * Parse glsl local size layout declarations * Parse (and ignore) glsl version directives * spelling * Better l-value interpretation for glsl interface blocks * Better l-value interpretation for glsl interface blocks * Add compile flag for enabling glsl * Parse and ignore precision modifiers. * Automatically import `glsl` module for compatiblity. * Complete vector and matrix types for glsl * Remove generated file from repo * Bump .gitignore * do not mark out globals as params * Synthesize entrypoint layout from global inout vars. * update test result. * Allow HLSL semantic on global variables. * Fix. * Fix test. * Fix win32 compile error. * Add more builtin input/output and texture intrinsics. * Add struct/array constructor syntax. * Skip `#extension` lines. * overide operator * for matrix/vector multiplication. * Add `matrixCompMult`. * Parse modifiers in for loop init var declr. * Add more glsl intrinsics, add stage into to var layout. * Allow `int[3] x` syntax. * Fix array type syntax. --------- Co-authored-by: Ellie Hermaszewska Co-authored-by: Yong He --- source/slang/core.meta.slang | 7 +- source/slang/glsl.meta.slang | 449 +++++++++++++++++++++ source/slang/hlsl.meta.slang | 2 +- source/slang/slang-ast-decl.h | 4 + source/slang/slang-ast-modifier.h | 8 +- source/slang/slang-check-decl.cpp | 21 + source/slang/slang-check-expr.cpp | 24 +- source/slang/slang-check-overload.cpp | 24 +- source/slang/slang-compiler.h | 13 +- source/slang/slang-diagnostic-defs.h | 6 +- source/slang/slang-emit-glsl.cpp | 4 + source/slang/slang-emit.cpp | 4 + source/slang/slang-ir-inst-defs.h | 4 +- source/slang/slang-ir-insts.h | 8 + .../slang/slang-ir-translate-glsl-global-var.cpp | 211 ++++++++++ source/slang/slang-ir-translate-glsl-global-var.h | 17 + source/slang/slang-ir.h | 1 + source/slang/slang-lower-to-ir.cpp | 23 +- source/slang/slang-options.cpp | 11 +- source/slang/slang-parser.cpp | 205 ++++++++-- source/slang/slang-preprocessor.cpp | 28 ++ source/slang/slang-stdlib-textures.cpp | 16 +- source/slang/slang-stdlib-textures.h | 2 + source/slang/slang-stdlib.cpp | 12 + source/slang/slang-type-system-shared.h | 6 +- source/slang/slang.cpp | 47 ++- 26 files changed, 1092 insertions(+), 65 deletions(-) create mode 100644 source/slang/glsl.meta.slang create mode 100644 source/slang/slang-ir-translate-glsl-global-var.cpp create mode 100644 source/slang/slang-ir-translate-glsl-global-var.h (limited to 'source') diff --git a/source/slang/core.meta.slang b/source/slang/core.meta.slang index 4dff9888d..b1437670e 100644 --- a/source/slang/core.meta.slang +++ b/source/slang/core.meta.slang @@ -1482,9 +1482,14 @@ for(auto& prefixInfo : kTexturePrefixes) for(auto& shapeInfo : kBaseTextureShapes) for(int isArray = 0; isArray < 2; ++isArray) for(int isMultisample = 0; isMultisample < 2; ++isMultisample) +for(int isShadow = 0; isShadow < 2; ++isShadow) for(auto& accessInfo : kBaseTextureAccessLevels) { - TextureTypeInfo info(prefixInfo, shapeInfo, isArray, isMultisample, accessInfo, sb, path); + // Define `Shadow` flavored types only for combined texture-samplers. + if (!prefixInfo.combined && isShadow == 1) + continue; + + TextureTypeInfo info(prefixInfo, shapeInfo, isArray, isMultisample, isShadow, accessInfo, sb, path); info.emitTypeDecl(); } diff --git a/source/slang/glsl.meta.slang b/source/slang/glsl.meta.slang new file mode 100644 index 000000000..a9518f914 --- /dev/null +++ b/source/slang/glsl.meta.slang @@ -0,0 +1,449 @@ +// +// From the GLSL spec, section 4.1. 'asic Types' +// + +typealias vec2 = vector; +typealias vec3 = vector; +typealias vec4 = vector; + +typealias dvec2 = vector; +typealias dvec3 = vector; +typealias dvec4 = vector; + +typealias bvec2 = vector; +typealias bvec3 = vector; +typealias bvec4 = vector; + +typealias ivec2 = vector; +typealias ivec3 = vector; +typealias ivec4 = vector; + +typealias uvec2 = vector; +typealias uvec3 = vector; +typealias uvec4 = vector; + +typealias i8vec2 = vector; +typealias i8vec3 = vector; +typealias i8vec4 = vector; + +typealias u8vec2 = vector; +typealias u8vec3 = vector; +typealias u8vec4 = vector; + +typealias i16vec2 = vector; +typealias i16vec3 = vector; +typealias i16vec4 = vector; + +typealias u16vec2 = vector; +typealias u16vec3 = vector; +typealias u16vec4 = vector; + +typealias i64vec2 = vector; +typealias i64vec3 = vector; +typealias i64vec4 = vector; + +typealias u64vec2 = vector; +typealias u64vec3 = vector; +typealias u64vec4 = vector; + +typealias mat2 = matrix; +typealias mat3 = matrix; +typealias mat4 = matrix; + +typealias mat2x2 = matrix; +typealias mat2x3 = matrix; +typealias mat2x4 = matrix; + +typealias mat3x2 = matrix; +typealias mat3x3 = matrix; +typealias mat3x4 = matrix; + +typealias mat4x2 = matrix; +typealias mat4x3 = matrix; +typealias mat4x4 = matrix; + +typealias dmat2 = matrix; +typealias dmat3 = matrix; +typealias dmat4 = matrix; + +typealias dmat2x2 = matrix; +typealias dmat2x3 = matrix; +typealias dmat2x4 = matrix; + +typealias dmat3x2 = matrix; +typealias dmat3x3 = matrix; +typealias dmat3x4 = matrix; + +typealias dmat4x2 = matrix; +typealias dmat4x3 = matrix; +typealias dmat4x4 = matrix; + +typealias usampler1D = Sampler1D; +typealias isampler1D = Sampler1D; +typealias sampler1D = Sampler1D; + +typealias usampler2D = Sampler2D; +typealias isampler2D = Sampler2D; +typealias sampler2D = Sampler2D; + +typealias usampler3D = Sampler3D; +typealias isampler3D = Sampler3D; +typealias sampler3D = Sampler3D; + +typealias usamplerCube = SamplerCube; +typealias isamplerCube = SamplerCube; +typealias samplerCube = SamplerCube; + +typealias usampler1DShadow = Sampler1DShadow; +typealias isampler1DShadow = Sampler1DShadow; +typealias sampler1DShadow = Sampler1DShadow; + +typealias usampler2DShadow = Sampler2DShadow; +typealias isampler2DShadow = Sampler2DShadow; +typealias sampler2DShadow = Sampler2DShadow; + +typealias usamplerCubeShadow = SamplerCubeShadow; +typealias isamplerCubeShadow = SamplerCubeShadow; +typealias samplerCubeShadow = SamplerCubeShadow; + +typealias usampler1DArray = Sampler1DArray; +typealias isampler1DArray = Sampler1DArray; +typealias sampler1DArray = Sampler1DArray; + +typealias usampler2DArray = Sampler2DArray; +typealias isampler2DArray = Sampler2DArray; +typealias sampler2DArray = Sampler2DArray; + +typealias usamplerCubeArray = SamplerCubeArray; +typealias isamplerCubeArray = SamplerCubeArray; +typealias samplerCubeArray = SamplerCubeArray; + +typealias usampler1DArrayShadow = Sampler1DArrayShadow; +typealias isampler1DArrayShadow = Sampler1DArrayShadow; +typealias sampler1DArrayShadow = Sampler1DArrayShadow; + +typealias usampler2DArrayShadow = Sampler2DArrayShadow; +typealias isampler2DArrayShadow = Sampler2DArrayShadow; +typealias sampler2DArrayShadow = Sampler2DArrayShadow; + +typealias usamplerCubeArrayShadow = SamplerCubeArrayShadow; +typealias isamplerCubeArrayShadow = SamplerCubeArrayShadow; +typealias samplerCubeArrayShadow = SamplerCubeArrayShadow; + +__intrinsic_op(vectorReshape) +vector __vectorReshape(vector vin); + +[ForceInline] +vector texelFetch (Sampler1D> sampler, int p, int lod) +{ + return __vectorReshape<4>(sampler.Load(int2(p, lod))); +} + +[ForceInline] +vector texelFetch (Sampler2D> sampler, ivec2 p, int lod) +{ + return __vectorReshape<4>(sampler.Load(int3(p, lod))); +} + +[ForceInline] +vector texelFetch (Sampler3D> sampler, ivec3 p, int lod) +{ + return __vectorReshape<4>(sampler.Load(int4(p, lod))); +} + +[ForceInline] +vector texelFetch (Sampler1DArray> sampler, ivec2 p, int lod) +{ + return __vectorReshape<4>(sampler.Load(int3(p, lod))); +} + +[ForceInline] +vector texelFetch (Sampler2DArray> sampler, ivec3 p, int lod) +{ + return __vectorReshape<4>(sampler.Load(int4(p, lod))); +} + +[ForceInline] +vector texture (Sampler1D> sampler, float p, float bias = 0.0) +{ + return __vectorReshape<4>(sampler.SampleBias(p, bias)); +} + +[ForceInline] +vector texture (Sampler2D> sampler, float2 p, float bias = 0.0) +{ + return __vectorReshape<4>(sampler.SampleBias(p, bias)); +} + +[ForceInline] +vector texture (Sampler3D> sampler, float3 p, float bias = 0.0) +{ + return __vectorReshape<4>(sampler.SampleBias(p, bias)); +} + +[ForceInline] +vector texture (SamplerCube> sampler, float3 p, float bias = 0.0) +{ + return __vectorReshape<4>(sampler.SampleBias(p, bias)); +} + +[ForceInline] +float texture (Sampler1DShadow> sampler, float2 p) +{ + return sampler.SampleCmp(p.x, p.y); +} + +[ForceInline] +float texture (Sampler2DShadow> sampler, float3 p) +{ + return sampler.SampleCmp(p.xy, p.z); +} + +[ForceInline] +float texture (SamplerCubeShadow> sampler, float4 p) +{ + return sampler.SampleCmp(p.xyz, p.w); +} + +[ForceInline] +vector texture (Sampler1DArray> sampler, float2 p, float bias = 0.0) +{ + return __vectorReshape<4>(sampler.SampleBias(p, bias)); +} + +[ForceInline] +vector texture (Sampler2DArray> sampler, float3 p, float bias = 0.0) +{ + return __vectorReshape<4>(sampler.SampleBias(p, bias)); +} + +[ForceInline] +vector texture (SamplerCubeArray> sampler, float4 p, float bias = 0.0) +{ + return __vectorReshape<4>(sampler.SampleBias(p, bias)); +} + +[ForceInline] +float texture (Sampler1DArrayShadow> sampler, float3 p) +{ + return sampler.SampleCmp(p.xy, p.z); +} + +[ForceInline] +float texture (Sampler2DArrayShadow> sampler, float4 p) +{ + return sampler.SampleCmp(p.xyz, p.w); +} + +// TODO: define `texture` for SamplerCubeArrayShadow. + + +vector textureGrad (Sampler1D> sampler, float P, float dPdx, float dPdy) +{ + return __vectorReshape<4>(sampler.SampleGrad(P, dPdx, dPdy)); +} + +vector textureGrad (Sampler2D> sampler, vec2 P, vec2 dPdx, vec2 dPdy) +{ + return __vectorReshape<4>(sampler.SampleGrad(P, dPdx, dPdy)); +} + +vector textureGrad (Sampler3D> sampler, vec3 P, vec3 dPdx, vec3 dPdy) +{ + return __vectorReshape<4>(sampler.SampleGrad(P, dPdx, dPdy)); +} + +vector textureGrad (SamplerCube> sampler, vec3 P, vec3 dPdx, vec3 dPdy) +{ + return __vectorReshape<4>(sampler.SampleGrad(P, dPdx, dPdy)); +} + +vector textureGrad (Sampler1DArray> sampler, vec2 P, float dPdx, float dPdy) +{ + return __vectorReshape<4>(sampler.SampleGrad(P, dPdx, dPdy)); +} + +vector textureGrad (Sampler2DArray> sampler, vec3 P, vec2 dPdx, vec2 dPdy) +{ + return __vectorReshape<4>(sampler.SampleGrad(P, dPdx, dPdy)); +} + +vector textureGrad (SamplerCubeArray> sampler, vec4 P, vec3 dPdx, vec3 dPdy) +{ + return __vectorReshape<4>(sampler.SampleGrad(P, dPdx, dPdy)); +} + + +out float4 gl_Position : SV_Position; +out float gl_PointSize : SV_PointSize; +in vec4 gl_FragCoord : SV_Position; +out float gl_FragDepth : SV_Depth; +out int gl_FragStencilRef : SV_StencilRef; + +in uvec3 gl_GlobalInvocationID : SV_DispatchThreadID; +in uvec3 gl_WorkGroupID : SV_GroupID; +in uvec3 gl_LocalInvocationIndex : SV_GroupIndex; +in uvec3 gl_LocalInvocationID : SV_GroupThreadID; + +// TODO: define overload for tessellation control stage. +in int gl_InvocationID : SV_GSInstanceID; + +in int gl_InstanceIndex : SV_InstanceID; +in bool gl_FrontFacing : SV_IsFrontFace; + +// TODO: define overload for geometry stage. +in int gl_Layer : SV_RenderTargetArrayIndex; + +in int gl_SampleID : SV_SampleIndex; +in int gl_VertexIndex : SV_VertexID; +in int gl_ViewIndex : SV_ViewID; +in int gl_ViewportIndex : SV_ViewportArrayIndex; + + +// Override operator* behavior to compute algebric product of matrices and vectors. + +[OverloadRank(15)] +[ForceInline] +matrix operator*(matrix m1, matrix m2) +{ + return mul(m2, m1); +} + +[OverloadRank(15)] +[ForceInline] +matrix operator*(matrix m1, matrix m2) +{ + return mul(m2, m1); +} + +[OverloadRank(15)] +[ForceInline] +matrix operator*(matrix m1, matrix m2) +{ + return mul(m2, m1); +} + +[ForceInline] +[OverloadRank(15)] +matrix operator*(matrix m1, matrix m2) +{ + return mul(m2, m1); +} + +[ForceInline] +[OverloadRank(15)] +vector operator*(vector v, matrix m) +{ + return mul(m, v); +} + +[ForceInline] +[OverloadRank(15)] +vector operator*(matrix m, vector v) +{ + return mul(v, m); +} + +__intrinsic_op(mul) +matrix matrixCompMult(matrix left, matrix right); + +__intrinsic_op(cmpLE) +vector lessThanEqual(vector x, vector y); +__intrinsic_op(cmpLT) +vector lessThan(vector x, vector y); +__intrinsic_op(cmpGT) +vector greaterThan(vector x, vector y); +__intrinsic_op(cmpGE) +vector greaterThanEqual(vector x, vector y); +__intrinsic_op(cmpEQ) +vector equal(vector x, vector y); +__intrinsic_op(cmpNE) +vector notEqual(vector x, vector y); + +__generic +extension vector +{ + [ForceInline] __init(vector bigger) { this = bigger.xy; } + [ForceInline] __init(vector bigger) { this = bigger.xy; } +} + +__generic +extension vector +{ + [ForceInline] __init(vector bigger) { this = bigger.xyz; } +} + +[ForceInline] +[OverloadRank(15)] +bool operator==(vector left, vector right) +{ + return all(equal(left, right)); +} + +[ForceInline] +[OverloadRank(15)] +bool operator!=(vector left, vector right) +{ + return any(notEqual(left, right)); +} + +[ForceInline] +[OverloadRank(14)] +bool operator==(vector left, vector right) +{ + return all(equal(left, right)); +} + +[ForceInline] +[OverloadRank(14)] +bool operator!=(vector left, vector right) +{ + return any(notEqual(left, right)); +} + +[ForceInline] +[OverloadRank(14)] +bool operator==(vector left, vector right) +{ + return all(equal(left, right)); +} + +[ForceInline] +[OverloadRank(14)] +bool operator!=(vector left, vector right) +{ + return any(notEqual(left, right)); +} + +${{{{ +for (auto type : kBaseTypes) { + char const* typeName = type.name; + if (!type.flags) continue; +}}}} +[ForceInline] +[OverloadRank(15)] +bool operator==(vector<$(typeName), N> left, vector<$(typeName), N> right) +{ + return all(equal(left, right)); +} + +[ForceInline] +[OverloadRank(15)] +bool operator!=(vector<$(typeName), N> left, vector<$(typeName), N> right) +{ + return any(notEqual(left, right)); +} +${{{{ +} +}}}} + +[ForceInline] int findLSB(int v) { return firstbitlow(v); } +[ForceInline] uint findLSB(uint v) { return firstbitlow(v); } +[ForceInline] vector findLSB(vector value) +{ + return firstbitlow(value); +} +[ForceInline] vector findLSB(vector value) +{ + return firstbitlow(value); +} diff --git a/source/slang/hlsl.meta.slang b/source/slang/hlsl.meta.slang index e29e0c3cc..6520ab1fa 100644 --- a/source/slang/hlsl.meta.slang +++ b/source/slang/hlsl.meta.slang @@ -2457,7 +2457,7 @@ T dot(vector x, vector y) __generic vector dst(vector x, vector y); -// Given a RWByteAddressBuffer allow it to be interpretted as a RWStructuredBuffer +// Given a RWByteAddressBuffer allow it to be interpreted as a RWStructuredBuffer __intrinsic_op($(kIROp_GetEquivalentStructuredBuffer)) RWStructuredBuffer __getEquivalentStructuredBuffer(RWByteAddressBuffer b); diff --git a/source/slang/slang-ast-decl.h b/source/slang/slang-ast-decl.h index 553a5c26f..e43141cad 100644 --- a/source/slang/slang-ast-decl.h +++ b/source/slang/slang-ast-decl.h @@ -151,6 +151,10 @@ class ClassDecl : public AggTypeDecl SLANG_AST_CLASS(ClassDecl) }; +class GLSLInterfaceBlockDecl : public AggTypeDecl +{ + SLANG_AST_CLASS(GLSLInterfaceBlockDecl); +}; // TODO: Is it appropriate to treat an `enum` as an aggregate type? // Most code that looks for, e.g., conformances assumes user-defined diff --git a/source/slang/slang-ast-modifier.h b/source/slang/slang-ast-modifier.h index 4288017fa..9ee3fea86 100644 --- a/source/slang/slang-ast-modifier.h +++ b/source/slang/slang-ast-modifier.h @@ -30,7 +30,7 @@ class ExportedModifier : public Modifier { SLANG_AST_CLASS(ExportedModifier)}; class ConstExprModifier : public Modifier { SLANG_AST_CLASS(ConstExprModifier)}; class GloballyCoherentModifier : public Modifier { SLANG_AST_CLASS(GloballyCoherentModifier)}; class ExternCppModifier : public Modifier { SLANG_AST_CLASS(ExternCppModifier)}; - +class GLSLPrecisionModifier : public Modifier { SLANG_AST_CLASS(GLSLPrecisionModifier)}; // Marks that the definition of a decl is not yet synthesized. class ToBeSynthesizedModifier : public Modifier {SLANG_AST_CLASS(ToBeSynthesizedModifier)}; @@ -765,6 +765,12 @@ class DisableArrayFlatteningAttribute : public Attribute SLANG_AST_CLASS(DisableArrayFlatteningAttribute); }; +// A GLSL layout(local_size_x = 64, ... attribute) +class GLSLLayoutLocalSizeAttribute : public Attribute +{ + SLANG_AST_CLASS(GLSLLayoutLocalSizeAttribute) +}; + // TODO: for attributes that take arguments, the syntax node // classes should provide accessors for the values of those arguments. diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index 8d7337318..c31c94a85 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -389,6 +389,11 @@ namespace Slang // if(decl->hasModifier()) return false; + // While not normally allowed, out variables are not constant + // parameters, this can happen for example in GLSL mode + if(decl->hasModifier()) return false; + if(decl->hasModifier()) return false; + // The `groupshared` modifier indicates that a variable cannot // be a shader parameters, but is instead transient storage // allocated for the duration of a thread-group's execution. @@ -1219,6 +1224,22 @@ namespace Slang varDecl->type.type = m_astBuilder->getConstantBufferType(varDecl->type); } } + + if (getLinkage()->getAllowGLSLInput()) + { + // If we are in GLSL compatiblity mode, we want to treat all global variables + // without any `uniform` modifiers as true global variables by default. + if (!varDecl->findModifier() && + !varDecl->findModifier() && + !varDecl->findModifier()) + { + if (!as(varDecl->type) && !as(varDecl->type)) + { + auto staticModifier = m_astBuilder->create(); + addModifier(varDecl, staticModifier); + } + } + } } } diff --git a/source/slang/slang-check-expr.cpp b/source/slang/slang-check-expr.cpp index 2f8b28afc..e130275bb 100644 --- a/source/slang/slang-check-expr.cpp +++ b/source/slang/slang-check-expr.cpp @@ -269,6 +269,25 @@ namespace Slang } } + static bool isMutableGLSLBufferBlockVarExpr(Expr* expr) + { + if(const auto varExpr = as(expr)) + { + if(const auto declRefType = as(varExpr->type->getCanonicalType())) + { + if(declRefType->getDeclRef().getDecl()->isDerivedFrom(ASTNodeType::GLSLInterfaceBlockDecl)) + { + const auto d = varExpr->declRef.getDecl(); + if(d->hasModifier() && !d->hasModifier()) + { + return true; + } + } + } + } + return false; + } + DeclRefExpr* SemanticsVisitor::ConstructDeclRefExpr( DeclRef declRef, Expr* baseExpr, @@ -370,7 +389,10 @@ namespace Slang // l-value status of the base expression into account now. if(!baseExpr->type.isLeftValue) { - expr->type.isLeftValue = false; + // One exception to this is if we're reading the contents + // of a GLSL buffer interface block which isn't marked as + // read_only + expr->type.isLeftValue = isMutableGLSLBufferBlockVarExpr(baseExpr); } else { diff --git a/source/slang/slang-check-overload.cpp b/source/slang/slang-check-overload.cpp index 27062fc0c..2d7315cd2 100644 --- a/source/slang/slang-check-overload.cpp +++ b/source/slang/slang-check-overload.cpp @@ -2005,13 +2005,25 @@ namespace Slang typeCheckingCache->resolvedOperatorOverloadCache[key] = *context.bestCandidate; return CompleteOverloadCandidate(context, *context.bestCandidate); } - else + else if (auto typetype = as(funcExprType)) { - // Nothing at all was found that we could even consider invoking - getSink()->diagnose(expr->functionExpr, Diagnostics::expectedFunction, funcExprType); - expr->type = QualType(m_astBuilder->getErrorType()); - return expr; - } + // We allow a special case when `funcExpr` represents a composite type, + // in which case we will try to construct the type via memberwise assignment from the arguments. + // + auto initListExpr = m_astBuilder->create(); + initListExpr->loc = expr->loc; + initListExpr->args.addRange(expr->arguments); + initListExpr->type = m_astBuilder->getInitializerListType(); + Expr* outExpr = nullptr; + if (_coerceInitializerList(typetype->getType(), &outExpr, initListExpr)) + return outExpr; + } + + // Nothing at all was found that we could even consider invoking. + // In all other cases, this is an error. + getSink()->diagnose(expr->functionExpr, Diagnostics::expectedFunction, funcExprType); + expr->type = QualType(m_astBuilder->getErrorType()); + return expr; } void SemanticsVisitor::AddGenericOverloadCandidate( diff --git a/source/slang/slang-compiler.h b/source/slang/slang-compiler.h index c3f2d8e70..e8c624b01 100755 --- a/source/slang/slang-compiler.h +++ b/source/slang/slang-compiler.h @@ -1812,6 +1812,14 @@ namespace Slang { m_enableEffectAnnotations = value; } + bool getAllowGLSLInput() + { + return m_allowGLSLInput; + } + void setAllowGLSLInput(bool value) + { + m_allowGLSLInput = value; + } // Information on the targets we are being asked to // generate code for. @@ -1972,6 +1980,7 @@ namespace Slang bool m_requireCacheFileSystem = false; bool m_useFalcorCustomSharedKeywordSemantics = false; bool m_enableEffectAnnotations = false; + bool m_allowGLSLInput = false; // Modules that have been read in with the -r option List> m_libModules; @@ -2641,6 +2650,7 @@ namespace Slang virtual SLANG_NO_THROW SlangResult SLANG_MCALL setGlobalGenericArgs(int genericArgCount, char const** genericArgs) SLANG_OVERRIDE; virtual SLANG_NO_THROW SlangResult SLANG_MCALL setTypeNameForGlobalExistentialTypeParam(int slotIndex, char const* typeName) SLANG_OVERRIDE; virtual SLANG_NO_THROW SlangResult SLANG_MCALL setTypeNameForEntryPointExistentialTypeParam(int entryPointIndex, int slotIndex, char const* typeName) SLANG_OVERRIDE; + virtual SLANG_NO_THROW void SLANG_MCALL setAllowGLSLInput(bool value) SLANG_OVERRIDE; virtual SLANG_NO_THROW SlangResult SLANG_MCALL compile() SLANG_OVERRIDE; virtual SLANG_NO_THROW char const* SLANG_MCALL getDiagnosticOutput() SLANG_OVERRIDE; virtual SLANG_NO_THROW SlangResult SLANG_MCALL getDiagnosticOutputBlob(ISlangBlob** outBlob) SLANG_OVERRIDE; @@ -3055,7 +3065,7 @@ namespace Slang ComPtr coreLibraryCode; //ComPtr slangLibraryCode; ComPtr hlslLibraryCode; - //ComPtr glslLibraryCode; + ComPtr glslLibraryCode; ComPtr autodiffLibraryCode; String getStdlibPath(); @@ -3063,6 +3073,7 @@ namespace Slang ComPtr getCoreLibraryCode(); ComPtr getHLSLLibraryCode(); ComPtr getAutodiffLibraryCode(); + ComPtr getGLSLLibraryCode(); RefPtr m_sharedASTBuilder; diff --git a/source/slang/slang-diagnostic-defs.h b/source/slang/slang-diagnostic-defs.h index 58a2fbf4a..75308c829 100644 --- a/source/slang/slang-diagnostic-defs.h +++ b/source/slang/slang-diagnostic-defs.h @@ -66,7 +66,7 @@ DIAGNOSTIC( 8, Error, outputPathsImplyDifferentFormats, "the output paths '$0' and '$1' require different code-generation targets") DIAGNOSTIC( 10, Error, explicitOutputPathsAndMultipleTargets, "canot use both explicit output paths ('-o') and multiple targets ('-target')") -DIAGNOSTIC( 11, Error, glslIsNotSupported, "the Slang compiler does not support GLSL as a source language") +DIAGNOSTIC( 11, Error, glslIsNotSupported, "the Slang compiler does not support GLSL as a source language by default, please use -allow-glsl") DIAGNOSTIC( 12, Error, cannotDeduceSourceLanguage, "can't deduce language for input file '$0'") DIAGNOSTIC( 13, Error, unknownCodeGenerationTarget, "unknown code generation target '$0'") DIAGNOSTIC( 14, Error, unknownProfile, "unknown profile '$0'") @@ -173,6 +173,7 @@ DIAGNOSTIC(15202, Error, divideByZeroInPreprocessorExpression, "division by zero DIAGNOSTIC(15203, Error, expectedTokenInDefinedExpression, "expected '$0' in 'defined' expression") DIAGNOSTIC(15204, Warning, directiveExpectsExpression, "'$0' directive requires an expression") DIAGNOSTIC(15205, Warning, undefinedIdentifierInPreprocessorExpression, "undefined identifier '$0' in preprocessor expression will evaluate to zero") +DIAGNOSTIC(15206, Error, expectedIntegralVersionNumber, "Expected integer for #version number") DIAGNOSTIC(-1, Note, seeOpeningToken, "see opening '$0'") @@ -741,6 +742,9 @@ DIAGNOSTIC(55102, Error, invalidTorchKernelParamType, "'$0' is not a valid param DIAGNOSTIC(56001, Error, unableToAutoMapCUDATypeToHostType, "Could not automatically map '$0' to a host type. Automatic binding generation failed for '$1'") DIAGNOSTIC(57001, Warning, spirvOptFailed, "spirv-opt failed. $0") + +// GLSL Compatibility +DIAGNOSTIC(58001, Error, entryPointMustReturnVoidWhenGlobalOutputPresent, "entry point must return 'void' when global output variables are present.") // // 8xxxx - Issues specific to a particular library/technology/platform/etc. // diff --git a/source/slang/slang-emit-glsl.cpp b/source/slang/slang-emit-glsl.cpp index ccb296e84..4a75e84a0 100644 --- a/source/slang/slang-emit-glsl.cpp +++ b/source/slang/slang-emit-glsl.cpp @@ -732,6 +732,10 @@ void GLSLSourceEmitter::_emitGLSLTextureOrTextureSamplerType(IRTextureTypeBase* { m_writer->emit("Array"); } + if (type->isShadow()) + { + m_writer->emit("Shadow"); + } } void GLSLSourceEmitter::_emitGLSLTypePrefix(IRType* type, bool promoteHalfToFloat) diff --git a/source/slang/slang-emit.cpp b/source/slang/slang-emit.cpp index ce982a58c..1ee5ba67c 100644 --- a/source/slang/slang-emit.cpp +++ b/source/slang/slang-emit.cpp @@ -64,6 +64,7 @@ #include "slang-ir-wrap-structured-buffers.h" #include "slang-ir-liveness.h" #include "slang-ir-glsl-liveness.h" +#include "slang-ir-translate-glsl-global-var.h" #include "slang-ir-legalize-uniform-buffer-load.h" #include "slang-ir-lower-buffer-element-type.h" #include "slang-ir-string-hash.h" @@ -231,6 +232,7 @@ Result linkAndOptimizeIR( dumpIRIfEnabled(codeGenContext, irModule, "LINKED"); #endif + validateIRModuleIfEnabled(codeGenContext, irModule); // If the user specified the flag that they want us to dump @@ -238,6 +240,8 @@ Result linkAndOptimizeIR( // un-specialized IR. dumpIRIfEnabled(codeGenContext, irModule); + translateGLSLGlobalVar(codeGenContext, irModule); + // Replace any global constants with their values. // replaceGlobalConstants(irModule); diff --git a/source/slang/slang-ir-inst-defs.h b/source/slang/slang-ir-inst-defs.h index e32f0d084..8f87d23e7 100644 --- a/source/slang/slang-ir-inst-defs.h +++ b/source/slang/slang-ir-inst-defs.h @@ -823,6 +823,9 @@ INST(HighLevelDeclDecoration, highLevelDecl, 1, 0) /// A call to the decorated function should always be folded into its use site. INST(AlwaysFoldIntoUseSiteDecoration, alwaysFold, 0, 0) + INST(GlobalOutputDecoration, output, 0, 0) + INST(GlobalInputDecoration, output, 0, 0) + INST(GLSLLocationDecoration, glslLocation, 1, 0) INST(PayloadDecoration, payload, 0, 0) /* Mesh Shader outputs */ @@ -832,7 +835,6 @@ INST(HighLevelDeclDecoration, highLevelDecl, 1, 0) INST_RANGE(MeshOutputDecoration, VerticesDecoration, PrimitivesDecoration) INST(HLSLMeshPayloadDecoration, payload, 0, 0) INST(GLSLPrimitivesRateDecoration, perprimitive, 0, 0) - // Marks an inst that represents the gl_Position output. INST(GLPositionOutputDecoration, PositionOutput, 0, 0) diff --git a/source/slang/slang-ir-insts.h b/source/slang/slang-ir-insts.h index a2662d53f..2869f7058 100644 --- a/source/slang/slang-ir-insts.h +++ b/source/slang/slang-ir-insts.h @@ -361,6 +361,14 @@ IR_SIMPLE_DECORATION(AlwaysFoldIntoUseSiteDecoration) IR_SIMPLE_DECORATION(StaticRequirementDecoration) IR_SIMPLE_DECORATION(NonCopyableTypeDecoration) IR_SIMPLE_DECORATION(HLSLMeshPayloadDecoration) +IR_SIMPLE_DECORATION(GlobalInputDecoration) +IR_SIMPLE_DECORATION(GlobalOutputDecoration) + +struct IRGLSLLocationDecoration : IRDecoration +{ + IR_LEAF_ISA(GLSLLocationDecoration) + IRIntLit* getLocation() { return cast(getOperand(0)); } +}; struct IRNVAPIMagicDecoration : IRDecoration { diff --git a/source/slang/slang-ir-translate-glsl-global-var.cpp b/source/slang/slang-ir-translate-glsl-global-var.cpp new file mode 100644 index 000000000..41005e9d4 --- /dev/null +++ b/source/slang/slang-ir-translate-glsl-global-var.cpp @@ -0,0 +1,211 @@ +#include "slang-ir-translate-glsl-global-var.h" + +#include "slang-ir.h" +#include "slang-ir-insts.h" +#include "slang-ir-util.h" + +namespace Slang +{ + struct GlobalVarTranslationContext + { + CodeGenContext* context; + + void processModule(IRModule* module) + { + List outputVars; + List inputVars; + List entryPoints; + for (auto inst : module->getGlobalInsts()) + { + if (inst->findDecoration()) + outputVars.add(inst); + if (inst->findDecoration()) + inputVars.add(inst); + if (inst->findDecoration()) + entryPoints.add(inst); + } + + IRBuilder builder(module); + + bool hasInput = inputVars.getCount() != 0; + bool hasOutput = outputVars.getCount() != 0; + + if (!hasInput && !hasOutput) + return; + + for (auto entryPoint : entryPoints) + { + auto entryPointFunc = as(entryPoint); + if (!entryPointFunc) + continue; + + auto entryPointDecor = entryPointFunc->findDecoration(); + + IRVarLayout* resultVarLayout = nullptr; + IRVarLayout* paramLayout = nullptr; + IRType* resultType = entryPointFunc->getResultType(); + + // Create a struct type to receive all inputs. + builder.setInsertBefore(entryPointFunc); + auto inputStructType = builder.createStructType(); + IRStructTypeLayout::Builder inputStructTypeLayoutBuilder(&builder); + UInt inputVarIndex = 0; + List inputKeys; + for (auto input : inputVars) + { + auto inputType = cast(input->getDataType())->getValueType(); + auto key = builder.createStructKey(); + inputKeys.add(key); + if (auto nameHint = input->findDecoration()) + { + builder.addNameHintDecoration(key, nameHint->getName()); + } + builder.createStructField(inputStructType, key, inputType); + IRTypeLayout::Builder fieldTypeLayout(&builder); + fieldTypeLayout.addResourceUsage(LayoutResourceKind::VaryingInput, LayoutSize(1)); + IRVarLayout::Builder varLayoutBuilder(&builder, fieldTypeLayout.build()); + varLayoutBuilder.setStage(entryPointDecor->getProfile().getStage()); + if (auto locationDecoration = input->findDecoration()) + { + varLayoutBuilder.findOrAddResourceInfo(LayoutResourceKind::VaryingInput)->offset = (UInt)getIntVal(locationDecoration->getLocation()); + } + if (auto semanticDecor = input->findDecoration()) + { + varLayoutBuilder.setSystemValueSemantic(semanticDecor->getSemanticName(), semanticDecor->getSemanticIndex()); + } + else + { + if (entryPointDecor->getProfile().getStage() == Stage::Fragment) + { + varLayoutBuilder.setUserSemantic("COLOR", inputVarIndex); + } + else if (entryPointDecor->getProfile().getStage() == Stage::Vertex) + { + varLayoutBuilder.setUserSemantic("VERTEX_IN_", inputVarIndex); + } + inputVarIndex++; + } + inputStructTypeLayoutBuilder.addField(key, varLayoutBuilder.build()); + } + auto paramTypeLayout = inputStructTypeLayoutBuilder.build(); + IRVarLayout::Builder paramVarLayoutBuilder(&builder, paramTypeLayout); + paramLayout = paramVarLayoutBuilder.build(); + + // Add an entry point parameter for all the inputs. + auto firstBlock = entryPointFunc->getFirstBlock(); + builder.setInsertInto(firstBlock); + auto inputParam = builder.emitParam(inputStructType); + builder.addLayoutDecoration(inputParam, paramLayout); + + // Initialize all global variables. + for (Index i = 0; i < inputVars.getCount(); i++) + { + auto input = inputVars[i]; + setInsertBeforeOrdinaryInst(&builder, firstBlock->getFirstOrdinaryInst()); + auto inputType = cast(input->getDataType())->getValueType(); + builder.emitStore(input, + builder.emitFieldExtract(inputType, inputParam, inputKeys[i])); + } + + // For each entry point, introduce a new parameter to represent each input parameter, + // and return all outputs via a struct value. + if (hasOutput) + { + // If we have global outputs, the entry-point must not return anything itself. + if (as(entryPoint->getDataType())->getResultType()->getOp() != kIROp_VoidType) + { + context->getSink()->diagnose(entryPointFunc, Diagnostics::entryPointMustReturnVoidWhenGlobalOutputPresent); + continue; + } + builder.setInsertBefore(entryPointFunc); + resultType = builder.createStructType(); + IRStructTypeLayout::Builder typeLayoutBuilder(&builder); + UInt outputVarIndex = 0; + for (auto output : outputVars) + { + auto key = builder.createStructKey(); + if (auto nameHint = output->findDecoration()) + { + builder.addNameHintDecoration(key, nameHint->getName()); + } + auto ptrType = as(output->getDataType()); + builder.createStructField(resultType, key, ptrType->getValueType()); + IRTypeLayout::Builder fieldTypeLayout(&builder); + fieldTypeLayout.addResourceUsage(LayoutResourceKind::VaryingOutput, LayoutSize(1)); + IRVarLayout::Builder varLayoutBuilder(&builder, fieldTypeLayout.build()); + varLayoutBuilder.setStage(entryPointDecor->getProfile().getStage()); + if (auto semanticDecor = output->findDecoration()) + { + varLayoutBuilder.setSystemValueSemantic(semanticDecor->getSemanticName(), semanticDecor->getSemanticIndex()); + } + else + { + if (auto locationDecoration = output->findDecoration()) + { + varLayoutBuilder.findOrAddResourceInfo(LayoutResourceKind::VaryingOutput)->offset = (UInt)getIntVal(locationDecoration->getLocation()); + } + if (entryPointDecor->getProfile().getStage() == Stage::Fragment) + { + varLayoutBuilder.setSystemValueSemantic("SV_TARGET", outputVarIndex); + } + else if (entryPointDecor->getProfile().getStage() == Stage::Vertex) + { + varLayoutBuilder.setUserSemantic("COLOR", outputVarIndex); + } + outputVarIndex++; + } + typeLayoutBuilder.addField(key, varLayoutBuilder.build()); + } + auto resultTypeLayout = typeLayoutBuilder.build(); + IRVarLayout::Builder resultVarLayoutBuilder(&builder, resultTypeLayout); + resultVarLayout = resultVarLayoutBuilder.build(); + + for (auto block : entryPointFunc->getBlocks()) + { + if (auto returnInst = as(block->getTerminator())) + { + // Return the struct value. + builder.setInsertBefore(returnInst); + List fieldVals; + for (auto outputVar : outputVars) + { + auto load = builder.emitLoad(outputVar); + fieldVals.add(load); + } + auto resultVal = builder.emitMakeStruct(resultType, (UInt)fieldVals.getCount(), fieldVals.getBuffer()); + builder.emitReturn(resultVal); + returnInst->removeAndDeallocate(); + } + } + } + if (auto entryPointLayoutDecor = entryPointFunc->findDecoration()) + { + if (auto entryPointLayout = as(entryPointLayoutDecor->getLayout())) + { + if (paramLayout) + builder.replaceOperand(entryPointLayout->getOperands(), paramLayout); + if (resultVarLayout) + builder.replaceOperand(entryPointLayout->getOperands() + 1, resultVarLayout); + } + + } + // Update func type for the entry point. + List paramTypes; + for (auto param : entryPointFunc->getParams()) + { + paramTypes.add(param->getDataType()); + } + IRType* newFuncType = builder.getFuncType(paramTypes, resultType); + entryPointFunc->setFullType(newFuncType); + } + } + }; + + void translateGLSLGlobalVar(CodeGenContext* context, IRModule* module) + { + + GlobalVarTranslationContext ctx; + ctx.context = context; + ctx.processModule(module); + } +} diff --git a/source/slang/slang-ir-translate-glsl-global-var.h b/source/slang/slang-ir-translate-glsl-global-var.h new file mode 100644 index 000000000..f22b6c028 --- /dev/null +++ b/source/slang/slang-ir-translate-glsl-global-var.h @@ -0,0 +1,17 @@ +// slang-ir-translate-glsl-global-var.h +#ifndef SLANG_IR_TRANSLATE_GLSL_GLOBAL_VAR_H +#define SLANG_IR_TRANSLATE_GLSL_GLOBAL_VAR_H + +namespace Slang +{ + + struct IRModule; + struct CodeGenContext; + + /// Translate global in/out variables defined in GLSL-flavored code + /// into entry point parameters with system value semantics. + void translateGLSLGlobalVar(CodeGenContext* context, IRModule* module); + +} + +#endif // SLANG_IR_TRANSLATE_GLSL_GLOBAL_VAR_H diff --git a/source/slang/slang-ir.h b/source/slang/slang-ir.h index 8d7cad0b4..f0be72248 100644 --- a/source/slang/slang-ir.h +++ b/source/slang/slang-ir.h @@ -1378,6 +1378,7 @@ struct IRResourceTypeBase : IRType bool isFeedback() const { return getFlavor().isFeedback(); } bool isMultisample() const { return getFlavor().isMultisample(); } bool isArray() const { return getFlavor().isArray(); } + bool isShadow() const { return getFlavor().isShadow(); } SlangResourceShape getShape() const { return getFlavor().getShape(); } SlangResourceAccess getAccess() const { return getFlavor().getAccess(); } diff --git a/source/slang/slang-lower-to-ir.cpp b/source/slang/slang-lower-to-ir.cpp index b2c0dbb18..38651c5a4 100644 --- a/source/slang/slang-lower-to-ir.cpp +++ b/source/slang/slang-lower-to-ir.cpp @@ -30,7 +30,6 @@ #include "slang-ir-obfuscate-loc.h" #include "slang-ir-use-uninitialized-out-param.h" #include "slang-ir-peephole.h" - #include "slang-mangle.h" #include "slang-type-layout.h" #include "slang-visitor.h" @@ -2155,7 +2154,23 @@ void addVarDecorations( { builder->addSimpleDecoration(inst); } - + else if (as(mod)) + { + builder->addSimpleDecoration(inst); + } + else if (as(mod)) + { + builder->addSimpleDecoration(inst); + } + else if (auto glslLocationMod = as(mod)) + { + builder->addDecoration(inst, kIROp_GLSLLocationDecoration, + builder->getIntValue(builder->getIntType(), stringToInt(glslLocationMod->valToken.getContent()))); + } + else if (auto hlslSemantic = as< HLSLSimpleSemantic>(mod)) + { + builder->addSemanticDecoration(inst, hlslSemantic->name.getContent()); + } // TODO: what are other modifiers we need to propagate through? } if(auto t = composeGetters(inst->getFullType(), &IROutTypeBase::getValueType)) @@ -8024,6 +8039,10 @@ struct DeclLoweringVisitor : DeclVisitor { irAggType = subBuilder->createClassType(); } + else if (as(decl)) + { + return LoweredValInfo(); + } else { getSink()->diagnose(decl->loc, Diagnostics::unimplemented, "lower unknown AggType to IR"); diff --git a/source/slang/slang-options.cpp b/source/slang/slang-options.cpp index 67f95df1e..1c1ad8f1c 100644 --- a/source/slang/slang-options.cpp +++ b/source/slang/slang-options.cpp @@ -141,6 +141,7 @@ enum class OptionKind FileSystem, Heterogeneous, NoMangle, + AllowGLSL, // Internal @@ -621,7 +622,8 @@ void initCommandOptions(CommandOptions& options) { OptionKind::FileSystem, "-file-system", "-file-system ", "Set the filesystem hook to use for a compile request."}, { OptionKind::Heterogeneous, "-heterogeneous", nullptr, "Output heterogeneity-related code." }, - { OptionKind::NoMangle, "-no-mangle", nullptr, "Do as little mangling of names as possible." } + { OptionKind::NoMangle, "-no-mangle", nullptr, "Do as little mangling of names as possible." }, + { OptionKind::AllowGLSL, "-allow-glsl", nullptr, "Enable GLSL as an input language." }, }; _addOptions(makeConstArrayView(experimentalOpts), options); @@ -912,6 +914,8 @@ struct OptionsParser String m_spirvCoreGrammarJSONPath; + bool m_allowGLSLInput = false; + CommandLineReader m_reader; CommandOptionsWriter::Style m_helpStyle = CommandOptionsWriter::Style::Text; @@ -1812,6 +1816,7 @@ SlangResult OptionsParser::_parse( switch (optionKind) { case OptionKind::NoMangle: m_flags |= SLANG_COMPILE_FLAG_NO_MANGLING; break; + case OptionKind::AllowGLSL: m_allowGLSLInput = true; break; case OptionKind::EmitIr: m_requestImpl->m_emitIr = true; break; case OptionKind::LoadStdLib: { @@ -2152,7 +2157,7 @@ SlangResult OptionsParser::_parse( m_compileRequest->setEnableEffectAnnotations(true); break; } - + case OptionKind::EntryPointName: { CommandLineArg name; @@ -2482,6 +2487,8 @@ SlangResult OptionsParser::_parse( m_compileRequest->setCompileFlags(m_flags); + m_compileRequest->setAllowGLSLInput(m_allowGLSLInput); + // As a compatability feature, if the user didn't list any explicit entry // point names, *and* they are compiling a single translation unit, *and* they // have either specified a stage, or we can assume one from the naming diff --git a/source/slang/slang-parser.cpp b/source/slang/slang-parser.cpp index 8c9604df6..0a2076fd0 100644 --- a/source/slang/slang-parser.cpp +++ b/source/slang/slang-parser.cpp @@ -82,6 +82,7 @@ namespace Slang struct ParserOptions { bool enableEffectAnnotations = false; + bool allowGLSLInput = false; }; // TODO: implement two pass parsing for file reference and struct type recognition @@ -186,6 +187,7 @@ namespace Slang void parseSourceFile(ModuleDecl* program); Decl* ParseStruct(); ClassDecl* ParseClass(); + GLSLInterfaceBlockDecl* ParseGLSLInterfaceBlock(); Stmt* ParseStatement(Stmt* parentStmt = nullptr); Stmt* parseBlockStatement(); Stmt* parseLabelStatement(); @@ -1161,7 +1163,17 @@ namespace Slang AddModifier(&modifierLink, parsedModifier); continue; } - + else if (parser->options.allowGLSLInput) + { + if (AdvanceIf(parser, "flat")) + { + parsedModifier = parser->astBuilder->create(); + parsedModifier->keywordName = nameToken.getName(); + parsedModifier->loc = nameToken.loc; + AddModifier(&modifierLink, parsedModifier); + continue; + } + } // If there was no match for a modifier keyword, then we // must be at the end of the modifier sequence return modifiers; @@ -2135,8 +2147,34 @@ namespace Slang memberExpr->name = expectIdentifier(parser).name; return memberExpr; } + + // Parse optional `[]` braces after a type expression, that indicate an array type + static Expr* parseBracketTypeSuffix(Parser* parser, Expr* inTypeExpr) + { + auto typeExpr = inTypeExpr; + for (;;) + { + Token token; + if (parser->LookAheadToken(TokenType::LBracket)) + { + IndexExpr* arrType = parser->astBuilder->create(); + arrType->loc = typeExpr->loc; + arrType->baseExpression = typeExpr; + parser->ReadToken(TokenType::LBracket); + if (!parser->LookAheadToken(TokenType::RBracket)) + { + arrType->indexExprs.add(parser->ParseExpression()); + } + parser->ReadToken(TokenType::RBracket); + typeExpr = arrType; + } + else + break; + } + return typeExpr; + } - // Parse option `[]` braces after a type expression, that indicate an array type + // Parse option `[]` or `*` braces after a type expression, that indicate an array or pointer type static Expr* parsePostfixTypeSuffix( Parser* parser, Expr* inTypeExpr) @@ -2400,7 +2438,7 @@ namespace Slang } /// Parse a type specifier, without dealing with modifiers. - static TypeSpec _parseSimpleTypeSpec(Parser* parser) + static TypeSpec _parseSimpleTypeSpec(Parser* parser, bool mightBeGLSLInterfaceBlock) { TypeSpec typeSpec; @@ -2436,6 +2474,15 @@ namespace Slang typeSpec.expr = createDeclRefType(parser, decl); return typeSpec; } + else if( mightBeGLSLInterfaceBlock + && parser->LookAheadToken(TokenType::Identifier) + && parser->LookAheadToken(TokenType::LBrace,1) ) + { + auto decl = parser->ParseGLSLInterfaceBlock(); + typeSpec.decl = decl; + typeSpec.expr = createDeclRefType(parser, decl); + return typeSpec; + } else if(parser->LookAheadToken("enum")) { auto decl = parseEnumDecl(parser); @@ -2493,6 +2540,19 @@ namespace Slang return typeSpec; } + static bool hasPotentialGLSLInterfaceBlockModifier(Parser* parser, Modifiers& mods) + { + if (!parser->options.allowGLSLInput) + return false; + + for (auto mod : mods) + { + if (as(mod) || as(mod) || as(mod)) + return true; + } + return false; + } + /// Parse a type specifier, following the given list of modifiers. /// /// If there are any modifiers in `ioModifiers`, this function may modify it @@ -2501,7 +2561,7 @@ namespace Slang /// static TypeSpec _parseTypeSpec(Parser* parser, Modifiers& ioModifiers) { - TypeSpec typeSpec = _parseSimpleTypeSpec(parser); + TypeSpec typeSpec = _parseSimpleTypeSpec(parser, hasPotentialGLSLInterfaceBlockModifier(parser, ioModifiers)); // We don't know whether `ioModifiers` has any modifiers in it, // or which of them might be type modifiers, so we will delegate @@ -2526,7 +2586,7 @@ namespace Slang static TypeSpec _parseTypeSpec(Parser* parser) { Modifiers modifiers = ParseModifiers(parser); - TypeSpec typeSpec = _parseSimpleTypeSpec(parser); + TypeSpec typeSpec = _parseSimpleTypeSpec(parser, hasPotentialGLSLInterfaceBlockModifier(parser, modifiers)); typeSpec = _applyModifiersToTypeSpec(parser, typeSpec, modifiers); @@ -2549,6 +2609,7 @@ namespace Slang return nullptr; } + // We may need to build up multiple declarations in a group, // but the common case will be when we have just a single // declaration @@ -2560,6 +2621,11 @@ namespace Slang // it might declare a `struct` type. if(typeSpec.decl) declGroupBuilder.addDecl(typeSpec.decl); + else + { + // Allow using brackets directly after type name to declare an array typed variable. + typeSpec.expr = parseBracketTypeSuffix(parser, typeSpec.expr); + } if( AdvanceIf(parser, TokenType::Semicolon) ) { @@ -2960,12 +3026,9 @@ namespace Slang reflectionNameModifier->nameAndLoc = NameLoc(reflectionNameToken); addModifier(bufferVarDecl, reflectionNameModifier); - // Both the buffer variable and its type need to have names generated - bufferVarDecl->nameAndLoc.name = generateName(parser, "parameterGroup_" + String(reflectionNameToken.getContent())); + // The parameter group type need to have its name generated. bufferDataTypeDecl->nameAndLoc.name = generateName(parser, "ParameterGroup_" + String(reflectionNameToken.getContent())); - addModifier(bufferDataTypeDecl, parser->astBuilder->create()); - addModifier(bufferVarDecl, parser->astBuilder->create()); // TODO(tfoley): We end up constructing unchecked syntax here that // is expected to type check into the right form, but it might be @@ -3003,12 +3066,28 @@ namespace Slang // The declarations in the body belong to the data type. parseDeclBody(parser, bufferDataTypeDecl); - // All HLSL buffer declarations are "transparent" in that their - // members are implicitly made visible in the parent scope. - // We achieve this by applying the transparent modifier to the variable. - auto transparentModifier = parser->astBuilder->create(); - transparentModifier->next = bufferVarDecl->modifiers.first; - bufferVarDecl->modifiers.first = transparentModifier; + if (parser->LookAheadToken(TokenType::Identifier) && + parser->LookAheadToken(TokenType::Semicolon, 1)) + { + // If the user specified an explicit name of the buffer var, use it. + bufferVarDecl->nameAndLoc = ParseDeclName(parser); + parser->ReadToken(TokenType::Semicolon); + } + else + { + // Otherwise, we need to generate a name for the buffer variable. + bufferVarDecl->nameAndLoc.name = generateName(parser, "parameterGroup_" + String(reflectionNameToken.getContent())); + + // We also need to make the declaration "transparent" so that their + // members are implicitly made visible in the parent scope. + // We achieve this by applying the transparent modifier to the variable. + auto transparentModifier = parser->astBuilder->create(); + transparentModifier->next = bufferVarDecl->modifiers.first; + bufferVarDecl->modifiers.first = transparentModifier; + + addModifier(bufferVarDecl, parser->astBuilder->create()); + addModifier(bufferDataTypeDecl, parser->astBuilder->create()); + } // Because we are constructing two declarations, we have a thorny // issue that were are only supposed to return one. @@ -4026,6 +4105,48 @@ namespace Slang return nullptr; } + static bool parseGLSLGlobalDecl(Parser* parser, ContainerDecl* containerDecl) + { + SLANG_UNUSED(containerDecl); + + if (AdvanceIf(parser, "precision")) + { + // skip global precision declarations. + parser->ReadToken(); + parser->ReadToken(); + parser->ReadToken(TokenType::Semicolon); + return true; + } + + Modifier* layoutModifier = nullptr; + if (parser->LookAheadToken("layout")) + { + tryParseUsingSyntaxDecl(parser, &layoutModifier); + } + + DeclBase* decl = nullptr; + if (parser->LookAheadToken("uniform", 0) && + (parser->LookAheadToken(TokenType::LBrace, 1) || + parser->LookAheadToken(TokenType::Identifier, 1) && + parser->LookAheadToken(TokenType::LBrace, 2))) + { + parser->ReadToken(); + decl = as(parseHLSLCBufferDecl(parser, containerDecl)); + if (decl) + AddMember(parser->currentScope, (Decl*)decl); + } + else if (layoutModifier) + { + decl = ParseDecl(parser, containerDecl); + } + + if (decl) + { + addModifier(decl, layoutModifier); + return true; + } + return false; + } static void parseDecls( Parser* parser, @@ -4035,6 +4156,11 @@ namespace Slang Token closingBraceToken; while (!AdvanceIfMatch(parser, matchType, &closingBraceToken)) { + if (parser->options.allowGLSLInput) + { + if (parseGLSLGlobalDecl(parser, containerDecl)) + continue; + } ParseDecl(parser, containerDecl); } containerDecl->closingSourceLoc = closingBraceToken.loc; @@ -4081,6 +4207,18 @@ namespace Slang program->loc = tokenReader.peekLoc(); } + if (options.allowGLSLInput) + { + auto glslName = getName(this, "glsl"); + if (program->nameAndLoc.name != glslName) + { + auto importDecl = astBuilder->create(); + importDecl->moduleNameAndLoc.name = glslName; + importDecl->scope = currentScope; + AddMember(currentScope, importDecl); + } + } + parseDecls(this, program, MatchedTokenType::File); PopScope(); @@ -4140,6 +4278,23 @@ namespace Slang return rs; } + GLSLInterfaceBlockDecl* Parser::ParseGLSLInterfaceBlock() + { + // + // MyBlockName { float myData[]; } myBufferName; + // + + auto* rs = astBuilder->create(); + FillPosition(rs); + + // As for struct, skip completion request token to prevent producing a + // block named completion request. + AdvanceIf(this, TokenType::CompletionRequest); + rs->nameAndLoc = expectIdentifier(this); + parseDeclBody(this, rs); + return rs; + } + static EnumCaseDecl* parseEnumCaseDecl(Parser* parser) { EnumCaseDecl* decl = parser->astBuilder->create(); @@ -4841,9 +4996,10 @@ namespace Slang FillPosition(stmt); ReadToken("for"); ReadToken(TokenType::LParent); - if (peekTypeName(this)) + auto modifiers = ParseModifiers(this); + if (peekTypeName(this) || !modifiers.isEmpty()) { - stmt->initialStatement = parseVarDeclrStatement(Modifiers()); + stmt->initialStatement = parseVarDeclrStatement(modifiers); } else { @@ -6703,7 +6859,7 @@ namespace Slang // If there are any modifiers, then we know that we are actually // in the type case. // - auto typeSpec = _parseSimpleTypeSpec(parser); + auto typeSpec = _parseSimpleTypeSpec(parser, false); typeSpec = _applyModifiersToTypeSpec(parser, typeSpec, modifiers); auto typeExpr = typeSpec.expr; @@ -6742,6 +6898,7 @@ namespace Slang { ParserOptions options = {}; options.enableEffectAnnotations = translationUnit->compileRequest->getLinkage()->getEnableEffectAnnotations(); + options.allowGLSLInput = translationUnit->compileRequest->getLinkage()->getAllowGLSLInput(); Parser parser(astBuilder, tokens, sink, outerScope, options); parser.namePool = translationUnit->getNamePool(); @@ -6924,7 +7081,6 @@ namespace Slang return modifier; } - static SlangResult parseSemanticVersion(Parser* parser, Token& outToken, SemanticVersion& outVersion) { parser->ReadToken(TokenType::LParent); @@ -6981,12 +7137,12 @@ namespace Slang parser->sink->diagnose(token, Diagnostics::invalidCUDASMVersion); return nullptr; } - + static NodeBase* parseLayoutModifier(Parser* parser, void* /*userData*/) { ModifierListBuilder listBuilder; - UncheckedAttribute* numThreadsAttrib = nullptr; + GLSLLayoutLocalSizeAttribute* numThreadsAttrib = nullptr; listBuilder.add(parser->astBuilder->create()); @@ -7009,13 +7165,12 @@ namespace Slang { if (!numThreadsAttrib) { - numThreadsAttrib = parser->astBuilder->create(); + numThreadsAttrib = parser->astBuilder->create(); numThreadsAttrib->args.setCount(3); // Just mark the loc and name from the first in the list numThreadsAttrib->keywordName = getName(parser, "numthreads"); numThreadsAttrib->loc = nameAndLoc.loc; - numThreadsAttrib->scope = parser->currentScope; } if (AdvanceIf(parser, TokenType::OpAssign)) @@ -7272,6 +7427,9 @@ namespace Slang _makeParseModifier("const", ConstModifier::kReflectClassInfo), _makeParseModifier("instance", InstanceModifier::kReflectClassInfo), _makeParseModifier("__builtin", BuiltinModifier::kReflectClassInfo), + _makeParseModifier("highp", GLSLPrecisionModifier::kReflectClassInfo), + _makeParseModifier("lowp", GLSLPrecisionModifier::kReflectClassInfo), + _makeParseModifier("mediump", GLSLPrecisionModifier::kReflectClassInfo), _makeParseModifier("__global", ActualGlobalModifier::kReflectClassInfo), @@ -7296,6 +7454,7 @@ namespace Slang _makeParseModifier("uniform", HLSLUniformModifier::kReflectClassInfo), _makeParseModifier("volatile", HLSLVolatileModifier::kReflectClassInfo), _makeParseModifier("export", HLSLExportModifier::kReflectClassInfo), + _makeParseModifier("buffer", GLSLBufferModifier::kReflectClassInfo), // Modifiers for geometry shader input _makeParseModifier("point", HLSLPointModifier::kReflectClassInfo), diff --git a/source/slang/slang-preprocessor.cpp b/source/slang/slang-preprocessor.cpp index aefbf7619..02f46103b 100644 --- a/source/slang/slang-preprocessor.cpp +++ b/source/slang/slang-preprocessor.cpp @@ -3635,6 +3635,29 @@ static void HandlePragmaDirective(PreprocessorDirectiveContext* context) (subDirective->callback)(context, subDirectiveToken); } +static void HandleExtensionDirective(PreprocessorDirectiveContext* context) +{ + SkipToEndOfLine(context); +} + +static void HandleVersionDirective(PreprocessorDirectiveContext* context) +{ + [[maybe_unused]] + int version; + switch(PeekTokenType(context)) + { + case TokenType::IntegerLiteral: + version = stringToInt(AdvanceToken(context).getContent()); + break; + default: + GetSink(context)->diagnose(GetDirectiveLoc(context), Diagnostics::expectedIntegralVersionNumber); + break; + } + + SkipToEndOfLine(context); + // TODO, just skip the version for now +} + // Handle an invalid directive static void HandleInvalidDirective(PreprocessorDirectiveContext* context) { @@ -3689,6 +3712,11 @@ static const PreprocessorDirective kDirectives[] = { "line", &HandleLineDirective, 0 }, { "pragma", &HandlePragmaDirective, 0 }, + // GLSL + { "version", &HandleVersionDirective, 0 }, + { "extension", &HandleExtensionDirective, 0 }, + + { nullptr, nullptr, 0 }, }; diff --git a/source/slang/slang-stdlib-textures.cpp b/source/slang/slang-stdlib-textures.cpp index 9254bf966..98380033c 100644 --- a/source/slang/slang-stdlib-textures.cpp +++ b/source/slang/slang-stdlib-textures.cpp @@ -50,6 +50,7 @@ TextureTypeInfo::TextureTypeInfo( BaseTextureShapeInfo const& base, bool isArray, bool isMultisample, + bool isShadow, BaseTextureAccessInfo const& accessInfo, StringBuilder& inSB, String const& inPath) @@ -57,6 +58,7 @@ TextureTypeInfo::TextureTypeInfo( , base(base) , isArray(isArray) , isMultisample(isMultisample) + , isShadow(isShadow) , accessInfo(accessInfo) , sb(inSB) , path(inPath) @@ -177,7 +179,7 @@ void TextureTypeInfo::emitTypeDecl() unsigned flavor = baseShape; if (isArray) flavor |= TextureFlavor::ArrayFlag; if (isMultisample) flavor |= TextureFlavor::MultisampleFlag; - // if (isShadow) flavor |= TextureFlavor::ShadowFlag; + if (isShadow) flavor |= TextureFlavor::ShadowFlag; flavor |= (access << 8); @@ -204,7 +206,7 @@ void TextureTypeInfo::emitTypeDecl() sb << baseShapeName; if (isMultisample) sb << "MS"; if (isArray) sb << "Array"; - // if (isShadow) sb << "Shadow"; + if (isShadow) sb << "Shadow"; sb << "\n"; // The struct body @@ -988,7 +990,7 @@ void TextureTypeInfo::writeSampleFunctions() { TextureFlavor::Shape baseShape = base.baseShape; char const* samplerStateParam = prefixInfo.combined ? "" : "SamplerState s, "; - + char const* comparisonSamplerStateParam = prefixInfo.combined ? "" : "SamplerComparisonState s, "; // `Sample()` writeFunc( @@ -1081,7 +1083,7 @@ void TextureTypeInfo::writeSampleFunctions() "float", "SampleCmp", cat( - "SamplerComparisonState s, ", + comparisonSamplerStateParam, "float", base.coordCount + isArray, " location, ", "float compareValue" ), @@ -1093,7 +1095,7 @@ void TextureTypeInfo::writeSampleFunctions() "float", "SampleCmpLevelZero", cat( - "SamplerComparisonState s, ", + comparisonSamplerStateParam, "float", base.coordCount + isArray, " location, ", "float compareValue" ), @@ -1113,7 +1115,7 @@ void TextureTypeInfo::writeSampleFunctions() "float", "SampleCmp", cat( - "SamplerComparisonState s, ", + comparisonSamplerStateParam, "float", base.coordCount + isArray, " location, ", "float compareValue, " "constexpr int", base.coordCount, " offset" @@ -1126,7 +1128,7 @@ void TextureTypeInfo::writeSampleFunctions() "float", "SampleCmpLevelZero", cat( - "SamplerComparisonState s, ", + comparisonSamplerStateParam, "float", base.coordCount + isArray, " location, ", "float compareValue, " "constexpr int", base.coordCount, " offset" diff --git a/source/slang/slang-stdlib-textures.h b/source/slang/slang-stdlib-textures.h index 19008a3f0..dc2f64a41 100644 --- a/source/slang/slang-stdlib-textures.h +++ b/source/slang/slang-stdlib-textures.h @@ -44,6 +44,7 @@ struct TextureTypeInfo BaseTextureShapeInfo const& base, bool isArray, bool isMultisample, + bool isShadow, BaseTextureAccessInfo const& accessInfo, StringBuilder& inSB, String const& inPath); @@ -52,6 +53,7 @@ struct TextureTypeInfo BaseTextureShapeInfo const& base; bool isArray; bool isMultisample; + bool isShadow; BaseTextureAccessInfo const& accessInfo; StringBuilder& sb; String path; diff --git a/source/slang/slang-stdlib.cpp b/source/slang/slang-stdlib.cpp index 5fec05c80..5a977694a 100644 --- a/source/slang/slang-stdlib.cpp +++ b/source/slang/slang-stdlib.cpp @@ -335,4 +335,16 @@ namespace Slang #endif return autodiffLibraryCode; } + + ComPtr Session::getGLSLLibraryCode() + { + if (!glslLibraryCode) + { + const String path = getStdlibPath(); + StringBuilder sb; +#include "glsl.meta.slang.h" + glslLibraryCode = StringBlob::moveCreate(sb); + } + return glslLibraryCode; + } } diff --git a/source/slang/slang-type-system-shared.h b/source/slang/slang-type-system-shared.h index 2e824e0a0..4fa48d23e 100644 --- a/source/slang/slang-type-system-shared.h +++ b/source/slang/slang-type-system-shared.h @@ -48,9 +48,7 @@ FOREACH_BASE_TYPE(DEFINE_BASE_TYPE) MultisampleFlag = SLANG_TEXTURE_MULTISAMPLE_FLAG, // Whether or not this is a shadow texture - // - // TODO(tfoley): is this even meaningful/used? - // ShadowFlag = 0x80, + ShadowFlag = SLANG_TEXTURE_SHADOW_FLAG, // For feedback texture FeedbackFlag = SLANG_TEXTURE_FEEDBACK_FLAG, @@ -84,7 +82,7 @@ FOREACH_BASE_TYPE(DEFINE_BASE_TYPE) bool isArray() const { return (flavor & ArrayFlag) != 0; } bool isMultisample() const { return (flavor & MultisampleFlag) != 0; } bool isFeedback() const { return (flavor & FeedbackFlag) != 0; } - // bool isShadow() const { return (flavor & ShadowFlag) != 0; } + bool isShadow() const { return (flavor & ShadowFlag) != 0; } SLANG_FORCE_INLINE bool operator==(const ThisType& rhs) const { return flavor == rhs.flavor; } SLANG_FORCE_INLINE bool operator!=(const ThisType& rhs) const { return !(*this == rhs); } diff --git a/source/slang/slang.cpp b/source/slang/slang.cpp index af853102a..0331a5f8e 100644 --- a/source/slang/slang.cpp +++ b/source/slang/slang.cpp @@ -2534,22 +2534,26 @@ SlangResult FrontEndCompileRequest::executeActionsInner() { SLANG_AST_BUILDER_RAII(getLinkage()->getASTBuilder()); - // We currently allow GlSL files on the command line so that we can - // drive our "pass-through" mode, but we really want to issue an error - // message if the user is seriously asking us to compile them. for (TranslationUnitRequest* translationUnit : translationUnits) { // Make sure SourceFile representation is available for all translationUnits SLANG_RETURN_ON_FAIL(translationUnit->requireSourceFiles()); - switch(translationUnit->sourceLanguage) + if(!getLinkage()->getAllowGLSLInput()) { - default: - break; + // We currently allow GlSL files on the command line so that we can + // drive our "pass-through" mode, but we really want to issue an error + // message if the user is seriously asking us to compile them and + // doesn't explicitly opt into the glsl frontend + switch(translationUnit->sourceLanguage) + { + default: + break; - case SourceLanguage::GLSL: - getSink()->diagnose(SourceLoc(), Diagnostics::glslIsNotSupported); - return SLANG_FAIL; + case SourceLanguage::GLSL: + getSink()->diagnose(SourceLoc(), Diagnostics::glslIsNotSupported); + return SLANG_FAIL; + } } } @@ -3230,12 +3234,23 @@ RefPtr Linkage::findOrImportModule( PathInfo pathIncludedFromInfo = getSourceManager()->getPathInfo(loc, SourceLocType::Actual); PathInfo filePathInfo; + ComPtr fileContents; + // We have to load via the found path - as that is how file was originally loaded if (SLANG_FAILED(includeSystem.findFile(fileName, pathIncludedFromInfo.foundPath, filePathInfo))) { - sink->diagnose(loc, Diagnostics::cannotFindFile, fileName); - mapNameToLoadedModules[name] = nullptr; - return nullptr; + if (name && name->text == "glsl") + { + // This is a builtin glsl module, just load it from embedded definition. + fileContents = getSessionImpl()->getGLSLLibraryCode(); + filePathInfo = PathInfo::makeFromString("glsl"); + } + else + { + sink->diagnose(loc, Diagnostics::cannotFindFile, fileName); + mapNameToLoadedModules[name] = nullptr; + return nullptr; + } } // Maybe this was loaded previously at a different relative name? @@ -3243,8 +3258,7 @@ RefPtr Linkage::findOrImportModule( return loadedModule; // Try to load it - ComPtr fileContents; - if(SLANG_FAILED(includeSystem.loadFile(filePathInfo, fileContents))) + if( !fileContents && SLANG_FAILED(includeSystem.loadFile(filePathInfo, fileContents))) { sink->diagnose(loc, Diagnostics::cannotOpenFile, fileName); mapNameToLoadedModules[name] = nullptr; @@ -5267,6 +5281,11 @@ SlangResult EndToEndCompileRequest::setTypeNameForEntryPointExistentialTypeParam return SLANG_OK; } +void EndToEndCompileRequest::setAllowGLSLInput(bool value) +{ + getLinkage()->setAllowGLSLInput(value); +} + SlangResult EndToEndCompileRequest::EndToEndCompileRequest::compile() { SlangResult res = SLANG_FAIL; -- cgit v1.2.3