diff --git a/bin/resources/Reflection.nzsl b/bin/resources/Reflection.nzsl new file mode 100644 index 00000000..c4fb0477 --- /dev/null +++ b/bin/resources/Reflection.nzsl @@ -0,0 +1,15 @@ +[nzsl_version("1.1")] +[author("SirLynix"), desc("Test module")] +[license("MIT")] +module Shader; + +import * from DataStruct; + +[layout(std140)] +struct Output +{ + color: vec4[f32], + normal: vec3[f32], + roughness: f32, + metalness: f32 +} diff --git a/bin/resources/Reflection.nzsl.json b/bin/resources/Reflection.nzsl.json new file mode 100644 index 00000000..68f24a1d --- /dev/null +++ b/bin/resources/Reflection.nzsl.json @@ -0,0 +1,45 @@ +{ + "structs": [ + { + "name": "Output", + "structIndex": 0, + "layout": "std140", + "members": [ + { + "name": "color", + "type": { + "type": "vector", + "dims": 4, + "baseType": "f32" + }, + "offset": 0 + }, + { + "name": "normal", + "type": { + "type": "vector", + "dims": 3, + "baseType": "f32" + }, + "offset": 16 + }, + { + "name": "roughness", + "type": { + "type": "primitive", + "primitiveType": "f32" + }, + "offset": 28 + }, + { + "name": "metalness", + "type": { + "type": "primitive", + "primitiveType": "f32" + }, + "offset": 32 + } + ] + } + ] +} \ No newline at end of file diff --git a/include/NZSL/Ast/ExpressionType.hpp b/include/NZSL/Ast/ExpressionType.hpp index a9490528..ec58ef92 100644 --- a/include/NZSL/Ast/ExpressionType.hpp +++ b/include/NZSL/Ast/ExpressionType.hpp @@ -158,6 +158,11 @@ namespace nzsl::Ast MethodType(const MethodType& methodType); MethodType(MethodType&&) noexcept = default; + inline auto& ObjectType(); + inline const auto& ObjectType() const; + + template void SetupObjectType(T&& value); + MethodType& operator=(const MethodType& methodType); MethodType& operator=(MethodType&&) noexcept = default; diff --git a/include/NZSL/Ast/ExpressionType.inl b/include/NZSL/Ast/ExpressionType.inl index f977dc52..dc5ce3e0 100644 --- a/include/NZSL/Ast/ExpressionType.inl +++ b/include/NZSL/Ast/ExpressionType.inl @@ -160,6 +160,23 @@ namespace nzsl::Ast return !operator==(rhs); } + inline auto& MethodType::ObjectType() + { + return objectType->type; + } + + inline const auto& MethodType::ObjectType() const + { + return objectType->type; + } + + template + void MethodType::SetupObjectType(T&& value) + { + objectType = std::make_unique(); + objectType->type = std::forward(value); + } + inline bool ModuleType::operator==(const ModuleType& rhs) const { diff --git a/include/NZSL/Parser.hpp b/include/NZSL/Parser.hpp index afa5d810..87ed27ec 100644 --- a/include/NZSL/Parser.hpp +++ b/include/NZSL/Parser.hpp @@ -28,10 +28,14 @@ namespace nzsl static std::string_view ToString(Ast::BuiltinEntry builtinEntry); static std::string_view ToString(Ast::DepthWriteMode depthWriteMode); static std::string_view ToString(Ast::InterpolationQualifier interpolationQualifier); + static std::string_view ToString(Ast::IntrinsicType intrinsicType); static std::string_view ToString(Ast::LoopUnroll loopUnroll); static std::string_view ToString(Ast::MemoryLayout memoryLayout); static std::string_view ToString(Ast::ModuleFeature moduleFeature); static std::string_view ToString(Ast::TypeConstant typeConstant); + static std::string_view ToString(AccessPolicy accessPolicy); + static std::string_view ToString(ImageFormat imageFormat); + static std::string_view ToString(ImageType imageType); static std::string_view ToString(ShaderStageType shaderStage); private: diff --git a/src/NZSL/Ast/AstSerializer.cpp b/src/NZSL/Ast/AstSerializer.cpp index 11f9b30c..30be05cc 100644 --- a/src/NZSL/Ast/AstSerializer.cpp +++ b/src/NZSL/Ast/AstSerializer.cpp @@ -1163,8 +1163,7 @@ NAZARA_WARNING_GCC_DISABLE("-Wmaybe-uninitialized") SizeT(methodIndex); MethodType methodType; - methodType.objectType = std::make_unique(); - methodType.objectType->type = std::move(objectType); + methodType.SetupObjectType(std::move(objectType)); methodType.methodIndex = methodIndex; type = std::move(methodType); diff --git a/src/NZSL/Ast/ExpressionType.cpp b/src/NZSL/Ast/ExpressionType.cpp index e3bf28fc..901fd9cc 100644 --- a/src/NZSL/Ast/ExpressionType.cpp +++ b/src/NZSL/Ast/ExpressionType.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -450,18 +451,7 @@ namespace nzsl::Ast std::string ToString(const SamplerType& type, const Stringifier& /*stringifier*/) { - std::string_view dimensionStr; - switch (type.dim) - { - case ImageType::E1D: dimensionStr = "1D"; break; - case ImageType::E1D_Array: dimensionStr = "1DArray"; break; - case ImageType::E2D: dimensionStr = "2D"; break; - case ImageType::E2D_Array: dimensionStr = "2DArray"; break; - case ImageType::E3D: dimensionStr = "3D"; break; - case ImageType::Cubemap: dimensionStr = "Cube"; break; - } - - return fmt::format("{}sampler{}[{}]", (type.depth) ? "depth_" : "", dimensionStr, ToString(type.sampledType)); + return fmt::format("{}sampler{}[{}]", (type.depth) ? "depth_" : "", Parser::ToString(type.dim), ToString(type.sampledType)); } std::string ToString(const StorageType& type, const Stringifier& stringifier) @@ -479,18 +469,7 @@ namespace nzsl::Ast std::string ToString(const TextureType& type, const Stringifier& /*stringifier*/) { - std::string_view dimensionStr; - switch (type.dim) - { - case ImageType::E1D: dimensionStr = "1D"; break; - case ImageType::E1D_Array: dimensionStr = "1DArray"; break; - case ImageType::E2D: dimensionStr = "2D"; break; - case ImageType::E2D_Array: dimensionStr = "2DArray"; break; - case ImageType::E3D: dimensionStr = "3D"; break; - case ImageType::Cubemap: dimensionStr = "Cube"; break; - } - - return fmt::format("texture{}[{}]", dimensionStr, ToString(type.baseType)); + return fmt::format("texture{}[{}]", Parser::ToString(type.dim), ToString(type.baseType)); } std::string ToString(const Type& type, const Stringifier& stringifier) diff --git a/src/NZSL/Ast/Transformations/ResolveTransformer.cpp b/src/NZSL/Ast/Transformations/ResolveTransformer.cpp index 5c5f0291..69d93c87 100644 --- a/src/NZSL/Ast/Transformations/ResolveTransformer.cpp +++ b/src/NZSL/Ast/Transformations/ResolveTransformer.cpp @@ -986,8 +986,8 @@ namespace nzsl::Ast for (const auto& [intrinsic, data] : LangData::s_intrinsicData) { - if (!data.functionName.empty()) - RegisterBuiltinIntrinsic(std::string(data.functionName), intrinsic); + if (!data.isMethod) + RegisterBuiltinIntrinsic(std::string(data.name), intrinsic); } // Constants @@ -1404,8 +1404,7 @@ namespace nzsl::Ast else throw CompilerUnknownMethodError{ identifierEntry.sourceLocation, ToString(resolvedType, indexedExpr->sourceLocation), identifierEntry.identifier }; - methodType.objectType = std::make_unique(); - methodType.objectType->type = resolvedType; + methodType.SetupObjectType(resolvedType); // TODO: Add a MethodExpression? auto identifierExpr = std::make_unique(); @@ -1428,8 +1427,7 @@ namespace nzsl::Ast else throw CompilerUnknownMethodError{ identifierEntry.sourceLocation, ToString(resolvedType, indexedExpr->sourceLocation), identifierEntry.identifier }; - methodType.objectType = std::make_unique(); - methodType.objectType->type = resolvedType; + methodType.SetupObjectType(resolvedType); // TODO: Add a MethodExpression? auto identifierExpr = std::make_unique(); @@ -1452,8 +1450,7 @@ namespace nzsl::Ast MethodType methodType; methodType.methodIndex = 0; //< FIXME - methodType.objectType = std::make_unique(); - methodType.objectType->type = resolvedType; + methodType.SetupObjectType(resolvedType); identifierExpr->cachedExpressionType = std::move(methodType); indexedExpr = std::move(identifierExpr); diff --git a/src/NZSL/Ast/Transformations/ValidationTransformer.cpp b/src/NZSL/Ast/Transformations/ValidationTransformer.cpp index 60d9b11d..d76b7b7d 100644 --- a/src/NZSL/Ast/Transformations/ValidationTransformer.cpp +++ b/src/NZSL/Ast/Transformations/ValidationTransformer.cpp @@ -1505,7 +1505,7 @@ namespace nzsl::Ast void ValidationTransformer::ValidateIntrinsicParameters(IntrinsicExpression& node, const T& intrinsicData) { if (node.parameters.size() != intrinsicData.nonConstraintParameterCount) - throw CompilerIntrinsicExpectedParameterCountError{ node.sourceLocation, Nz::SafeCast(intrinsicData.nonConstraintParameterCount), intrinsicData.functionName, Nz::SafeCast(node.parameters.size()) }; + throw CompilerIntrinsicExpectedParameterCountError{ node.sourceLocation, Nz::SafeCast(intrinsicData.nonConstraintParameterCount), intrinsicData.name, Nz::SafeCast(node.parameters.size()) }; std::optional unresolvedParameter; diff --git a/src/NZSL/Ast/Utils.cpp b/src/NZSL/Ast/Utils.cpp index e1161d46..dea07dfe 100644 --- a/src/NZSL/Ast/Utils.cpp +++ b/src/NZSL/Ast/Utils.cpp @@ -182,7 +182,7 @@ namespace nzsl::Ast const auto& intrinsicData = intrinsicIt->second; if (intrinsicExpr.parameters.size() != intrinsicData.nonConstraintParameterCount) - throw CompilerIntrinsicExpectedParameterCountError{ intrinsicExpr.sourceLocation, Nz::SafeCast(intrinsicData.nonConstraintParameterCount), intrinsicData.functionName, Nz::SafeCast(intrinsicExpr.parameters.size()) }; + throw CompilerIntrinsicExpectedParameterCountError{ intrinsicExpr.sourceLocation, Nz::SafeCast(intrinsicData.nonConstraintParameterCount), intrinsicData.name, Nz::SafeCast(intrinsicExpr.parameters.size()) }; std::array, 2> parameterTypes; if (intrinsicData.returnType == ReturnType::Param0Type || intrinsicData.returnType == ReturnType::Param1Type) @@ -270,7 +270,7 @@ namespace nzsl::Ast return vecType; } else - throw AstInternalError{ intrinsicExpr.sourceLocation, fmt::format("intrinsic {} first parameter is not a primitive nor vector", intrinsicData.functionName) }; + throw AstInternalError{ intrinsicExpr.sourceLocation, fmt::format("intrinsic {} first parameter is not a primitive nor vector", intrinsicData.name) }; } case ReturnType::Param0SampledValue: @@ -281,7 +281,7 @@ namespace nzsl::Ast const ExpressionType& paramType = ResolveAlias(*expressionType); if (!IsSamplerType(paramType)) - throw AstInternalError{ intrinsicExpr.sourceLocation, fmt::format("intrinsic {} first parameter is not a sampler", intrinsicData.functionName) }; + throw AstInternalError{ intrinsicExpr.sourceLocation, fmt::format("intrinsic {} first parameter is not a sampler", intrinsicData.name) }; const SamplerType& samplerType = std::get(paramType); if (samplerType.depth) @@ -298,7 +298,7 @@ namespace nzsl::Ast const ExpressionType& paramType = ResolveAlias(*expressionType); if (!IsTextureType(paramType)) - throw AstInternalError{ intrinsicExpr.sourceLocation, fmt::format("intrinsic {} first parameter is not a sampler", intrinsicData.functionName) }; + throw AstInternalError{ intrinsicExpr.sourceLocation, fmt::format("intrinsic {} first parameter is not a sampler", intrinsicData.name) }; const TextureType& textureType = std::get(paramType); return VectorType{ 4, textureType.baseType }; @@ -312,7 +312,7 @@ namespace nzsl::Ast const ExpressionType& paramType = ResolveAlias(*expressionType); if (!IsMatrixType(paramType)) - throw AstInternalError{ intrinsicExpr.sourceLocation, fmt::format("intrinsic {} first parameter is not a matrix", intrinsicData.functionName) }; + throw AstInternalError{ intrinsicExpr.sourceLocation, fmt::format("intrinsic {} first parameter is not a matrix", intrinsicData.name) }; MatrixType matrixType = std::get(paramType); std::swap(matrixType.columnCount, matrixType.rowCount); @@ -346,7 +346,7 @@ namespace nzsl::Ast const ExpressionType& paramType = ResolveAlias(*expressionType); if (!IsVectorType(paramType)) - throw AstInternalError{ intrinsicExpr.sourceLocation, fmt::format("intrinsic {} first parameter is not a vector", intrinsicData.functionName) }; + throw AstInternalError{ intrinsicExpr.sourceLocation, fmt::format("intrinsic {} first parameter is not a vector", intrinsicData.name) }; const VectorType& vecType = std::get(paramType); return vecType.type; diff --git a/src/NZSL/Lang/LangData.hpp b/src/NZSL/Lang/LangData.hpp index 8eca87a8..cd51f964 100644 --- a/src/NZSL/Lang/LangData.hpp +++ b/src/NZSL/Lang/LangData.hpp @@ -87,18 +87,6 @@ namespace nzsl::LangData { "rgba32f", { 6, Nz::SafeCast(ImageFormat::RGBA32f) }} }); - struct ImageFormatData - { - std::string_view identifier; - }; - - constexpr auto s_imageFormats = frozen::make_unordered_map({ - { ImageFormat::RGBA8, { "rgba8" } }, - { ImageFormat::RGBA8Snorm, { "rgba8_snorm" } }, - { ImageFormat::RGBA16f, { "rgba16f" } }, - { ImageFormat::RGBA32f, { "rgba32f" } }, - }); - struct DepthWriteModeData { std::string_view identifier; @@ -122,6 +110,18 @@ namespace nzsl::LangData { ShaderStageType::Fragment, { "frag", "fragment" }}, { ShaderStageType::Vertex, { "vert", "vertex" }}, }); + + struct ImageFormatData + { + std::string_view identifier; + }; + + constexpr auto s_imageFormats = frozen::make_unordered_map({ + { ImageFormat::RGBA8, { "rgba8" } }, + { ImageFormat::RGBA8Snorm, { "rgba8_snorm" } }, + { ImageFormat::RGBA16f, { "rgba16f" } }, + { ImageFormat::RGBA32f, { "rgba32f" } }, + }); struct InterpolationData { @@ -152,14 +152,14 @@ namespace nzsl::LangData Numerical, // Integer/Floating-point/Unsigned integer NumericalVec, // Numerical or vector of numerical Sampler, // sampler - SampleCoordinates, // floating-point vector used to sample the texture parameter + SampleCoordinates, // Floating-point vector used to sample the texture parameter Scalar, // Boolean/Integer/Floating-point/Unsigned integer ScalarVec, // Scalar or vector of scalar SignedNumerical, // Integer/Floating-point value SignedNumericalVec, // signed numerical or vector of signed numerical Texture, // texture - TextureCoordinates, // integer vector used to sample the texture parameter - TextureData, // texture content + TextureCoordinates, // Integer vector used to sample the texture parameter + TextureData, // Texture content // Constraints SameType, // Checks that all types since the last SameTypeBarrier (or first parameter) are the same (note that literal types are taken into account, i.e. FloatLiteral is compatible with f32 and f64) @@ -186,7 +186,8 @@ namespace nzsl::LangData struct IntrinsicData { - std::string_view functionName; // empty if not a function + std::string_view name; + bool isMethod; ReturnType returnType; const ParameterType* parameterTypes; std::size_t nonConstraintParameterCount; @@ -204,7 +205,7 @@ namespace nzsl::LangData }; template - constexpr IntrinsicData Build(std::string_view name, ReturnType retType, Params, std::optional requiredStage = std::nullopt) + constexpr IntrinsicData Build(std::string_view name, bool isMethod, ReturnType retType, Params, std::optional requiredStage = std::nullopt) { constexpr auto& parameterArray = IntrinsicFuncHelper::parameterArray; @@ -215,74 +216,74 @@ namespace nzsl::LangData nonConstraintParameterCount++; } - return { name, retType, parameterArray.data(), nonConstraintParameterCount, parameterArray.size(), requiredStage }; + return { name, isMethod, retType, parameterArray.data(), nonConstraintParameterCount, parameterArray.size(), requiredStage }; } constexpr auto data = frozen::make_unordered_map({ - { Ast::IntrinsicType::Abs, Build("abs", ReturnType::Param0Type, Params{}) }, - { Ast::IntrinsicType::All, Build("all", ReturnType::Bool, Params{}) }, - { Ast::IntrinsicType::Any, Build("any", ReturnType::Bool, Params{}) }, - { Ast::IntrinsicType::ArcCos, Build("acos", ReturnType::Param0Type, Params{}) }, - { Ast::IntrinsicType::ArcCosh, Build("acosh", ReturnType::Param0Type, Params{}) }, - { Ast::IntrinsicType::ArcSin, Build("asin", ReturnType::Param0Type, Params{}) }, - { Ast::IntrinsicType::ArcSinh, Build("asinh", ReturnType::Param0Type, Params{}) }, - { Ast::IntrinsicType::ArcTan, Build("atan", ReturnType::Param0Type, Params{}) }, - { Ast::IntrinsicType::ArcTan2, Build("atan2", ReturnType::Param0Type, Params{}) }, - { Ast::IntrinsicType::ArcTanh, Build("atanh", ReturnType::Param0Type, Params{}) }, - { Ast::IntrinsicType::ArraySize, Build("", ReturnType::U32, Params{}) }, - { Ast::IntrinsicType::Ceil, Build("ceil", ReturnType::Param0Type, Params{}) }, - { Ast::IntrinsicType::Clamp, Build("clamp", ReturnType::Param0Type, Params{}) }, - { Ast::IntrinsicType::Cos, Build("cos", ReturnType::Param0Type, Params{}) }, - { Ast::IntrinsicType::Cosh, Build("cosh", ReturnType::Param0Type, Params{}) }, - { Ast::IntrinsicType::CrossProduct, Build("cross", ReturnType::Param0Type, Params{}) }, - { Ast::IntrinsicType::DegToRad, Build("deg2rad", ReturnType::Param0Type, Params{}) }, - { Ast::IntrinsicType::Ddx, Build("ddx", ReturnType::Param0Type, Params{}, ShaderStageType::Fragment) }, - { Ast::IntrinsicType::DdxCoarse, Build("ddxcoarse", ReturnType::Param0Type, Params{}, ShaderStageType::Fragment) }, - { Ast::IntrinsicType::DdxFine, Build("ddxfine", ReturnType::Param0Type, Params{}, ShaderStageType::Fragment) }, - { Ast::IntrinsicType::Ddy, Build("ddy", ReturnType::Param0Type, Params{}, ShaderStageType::Fragment) }, - { Ast::IntrinsicType::DdyCoarse, Build("ddycoarse", ReturnType::Param0Type, Params{}, ShaderStageType::Fragment) }, - { Ast::IntrinsicType::DdyFine, Build("ddyfine", ReturnType::Param0Type, Params{}, ShaderStageType::Fragment) }, - { Ast::IntrinsicType::Distance, Build("distance", ReturnType::Param0VecComponent, Params{}) }, - { Ast::IntrinsicType::DotProduct, Build("dot", ReturnType::Param0VecComponent, Params{}) }, - { Ast::IntrinsicType::Exp, Build("exp", ReturnType::Param0Type, Params{}) }, - { Ast::IntrinsicType::Exp2, Build("exp2", ReturnType::Param0Type, Params{}) }, - { Ast::IntrinsicType::Floor, Build("floor", ReturnType::Param0Type, Params{}) }, - { Ast::IntrinsicType::Fract, Build("fract", ReturnType::Param0Type, Params{}) }, - { Ast::IntrinsicType::Fwidth, Build("fwidth", ReturnType::Param0Type, Params{}, ShaderStageType::Fragment) }, - { Ast::IntrinsicType::FwidthCoarse, Build("fwidthcoarse", ReturnType::Param0Type, Params{}, ShaderStageType::Fragment) }, - { Ast::IntrinsicType::FwidthFine, Build("fwidthfine", ReturnType::Param0Type, Params{}, ShaderStageType::Fragment) }, - { Ast::IntrinsicType::InverseSqrt, Build("rsqrt", ReturnType::Param0Type, Params{}) }, - { Ast::IntrinsicType::IsInf, Build("isinf", ReturnType::Param0AsBool, Params{}) }, - { Ast::IntrinsicType::IsNaN, Build("isnan", ReturnType::Param0AsBool, Params{}) }, - { Ast::IntrinsicType::Length, Build("length", ReturnType::Param0VecComponent, Params{}) }, - { Ast::IntrinsicType::Lerp, Build("lerp", ReturnType::Param0Type, Params{}) }, - { Ast::IntrinsicType::Log, Build("log", ReturnType::Param0Type, Params{}) }, - { Ast::IntrinsicType::Log2, Build("log2", ReturnType::Param0Type, Params{}) }, - { Ast::IntrinsicType::MatrixInverse, Build("inverse", ReturnType::Param0Type, Params{}) }, - { Ast::IntrinsicType::MatrixTranspose, Build("transpose", ReturnType::Param0Transposed, Params{}) }, - { Ast::IntrinsicType::Max, Build("max", ReturnType::Param0Type, Params{}) }, - { Ast::IntrinsicType::Min, Build("min", ReturnType::Param0Type, Params{}) }, - { Ast::IntrinsicType::Normalize, Build("normalize", ReturnType::Param0Type, Params{}) }, - { Ast::IntrinsicType::Not, Build("not", ReturnType::Param0Type, Params{}) }, - { Ast::IntrinsicType::Pow, Build("pow", ReturnType::Param0Type, Params{}) }, - { Ast::IntrinsicType::RadToDeg, Build("rad2deg", ReturnType::Param0Type, Params{}) }, - { Ast::IntrinsicType::Reflect, Build("reflect", ReturnType::Param0Type, Params{}) }, - { Ast::IntrinsicType::Round, Build("round", ReturnType::Param0Type, Params{}) }, - { Ast::IntrinsicType::RoundEven, Build("roundeven", ReturnType::Param0Type, Params{}) }, - { Ast::IntrinsicType::Select, Build("select", ReturnType::Param1Type, Params{}) }, - { Ast::IntrinsicType::Sign, Build("sign", ReturnType::Param0Type, Params{}) }, - { Ast::IntrinsicType::Sin, Build("sin", ReturnType::Param0Type, Params{}) }, - { Ast::IntrinsicType::Sinh, Build("sinh", ReturnType::Param0Type, Params{}) }, - { Ast::IntrinsicType::SmoothStep, Build("smoothstep", ReturnType::Param0Type, Params{}) }, - { Ast::IntrinsicType::Step, Build("step", ReturnType::Param0Type, Params{}) }, - { Ast::IntrinsicType::Sqrt, Build("sqrt", ReturnType::Param0Type, Params{}) }, - { Ast::IntrinsicType::Tan, Build("tan", ReturnType::Param0Type, Params{}) }, - { Ast::IntrinsicType::Tanh, Build("tanh", ReturnType::Param0Type, Params{}) }, - { Ast::IntrinsicType::TextureRead, Build("", ReturnType::Param0TextureValue, Params{}) }, - { Ast::IntrinsicType::TextureSampleImplicitLod, Build("", ReturnType::Param0SampledValue, Params{}, ShaderStageType::Fragment) }, - { Ast::IntrinsicType::TextureSampleImplicitLodDepthComp, Build("", ReturnType::Param0SampledValue, Params{}, ShaderStageType::Fragment) }, - { Ast::IntrinsicType::TextureWrite, Build("", ReturnType::None, Params{}) }, - { Ast::IntrinsicType::Trunc, Build("trunc", ReturnType::Param0Type, Params{}) }, + { Ast::IntrinsicType::Abs, Build("abs", false, ReturnType::Param0Type, Params{}) }, + { Ast::IntrinsicType::All, Build("all", false, ReturnType::Bool, Params{}) }, + { Ast::IntrinsicType::Any, Build("any", false, ReturnType::Bool, Params{}) }, + { Ast::IntrinsicType::ArcCos, Build("acos", false, ReturnType::Param0Type, Params{}) }, + { Ast::IntrinsicType::ArcCosh, Build("acosh", false, ReturnType::Param0Type, Params{}) }, + { Ast::IntrinsicType::ArcSin, Build("asin", false, ReturnType::Param0Type, Params{}) }, + { Ast::IntrinsicType::ArcSinh, Build("asinh", false, ReturnType::Param0Type, Params{}) }, + { Ast::IntrinsicType::ArcTan, Build("atan", false, ReturnType::Param0Type, Params{}) }, + { Ast::IntrinsicType::ArcTan2, Build("atan2", false, ReturnType::Param0Type, Params{}) }, + { Ast::IntrinsicType::ArcTanh, Build("atanh", false, ReturnType::Param0Type, Params{}) }, + { Ast::IntrinsicType::ArraySize, Build("arraySize", true, ReturnType::U32, Params{}) }, + { Ast::IntrinsicType::Ceil, Build("ceil", false, ReturnType::Param0Type, Params{}) }, + { Ast::IntrinsicType::Clamp, Build("clamp", false, ReturnType::Param0Type, Params{}) }, + { Ast::IntrinsicType::Cos, Build("cos", false, ReturnType::Param0Type, Params{}) }, + { Ast::IntrinsicType::Cosh, Build("cosh", false, ReturnType::Param0Type, Params{}) }, + { Ast::IntrinsicType::CrossProduct, Build("cross", false, ReturnType::Param0Type, Params{}) }, + { Ast::IntrinsicType::DegToRad, Build("deg2rad", false, ReturnType::Param0Type, Params{}) }, + { Ast::IntrinsicType::Ddx, Build("ddx", false, ReturnType::Param0Type, Params{}, ShaderStageType::Fragment) }, + { Ast::IntrinsicType::DdxCoarse, Build("ddxcoarse", false, ReturnType::Param0Type, Params{}, ShaderStageType::Fragment) }, + { Ast::IntrinsicType::DdxFine, Build("ddxfine", false, ReturnType::Param0Type, Params{}, ShaderStageType::Fragment) }, + { Ast::IntrinsicType::Ddy, Build("ddy", false, ReturnType::Param0Type, Params{}, ShaderStageType::Fragment) }, + { Ast::IntrinsicType::DdyCoarse, Build("ddycoarse", false, ReturnType::Param0Type, Params{}, ShaderStageType::Fragment) }, + { Ast::IntrinsicType::DdyFine, Build("ddyfine", false, ReturnType::Param0Type, Params{}, ShaderStageType::Fragment) }, + { Ast::IntrinsicType::Distance, Build("distance", false, ReturnType::Param0VecComponent, Params{}) }, + { Ast::IntrinsicType::DotProduct, Build("dot", false, ReturnType::Param0VecComponent, Params{}) }, + { Ast::IntrinsicType::Exp, Build("exp", false, ReturnType::Param0Type, Params{}) }, + { Ast::IntrinsicType::Exp2, Build("exp2", false, ReturnType::Param0Type, Params{}) }, + { Ast::IntrinsicType::Floor, Build("floor", false, ReturnType::Param0Type, Params{}) }, + { Ast::IntrinsicType::Fract, Build("fract", false, ReturnType::Param0Type, Params{}) }, + { Ast::IntrinsicType::Fwidth, Build("fwidth", false, ReturnType::Param0Type, Params{}, ShaderStageType::Fragment) }, + { Ast::IntrinsicType::FwidthCoarse, Build("fwidthcoarse", false, ReturnType::Param0Type, Params{}, ShaderStageType::Fragment) }, + { Ast::IntrinsicType::FwidthFine, Build("fwidthfine", false, ReturnType::Param0Type, Params{}, ShaderStageType::Fragment) }, + { Ast::IntrinsicType::InverseSqrt, Build("rsqrt", false, ReturnType::Param0Type, Params{}) }, + { Ast::IntrinsicType::IsInf, Build("isinf", false, ReturnType::Param0AsBool, Params{}) }, + { Ast::IntrinsicType::IsNaN, Build("isnan", false, ReturnType::Param0AsBool, Params{}) }, + { Ast::IntrinsicType::Length, Build("length", false, ReturnType::Param0VecComponent, Params{}) }, + { Ast::IntrinsicType::Lerp, Build("lerp", false, ReturnType::Param0Type, Params{}) }, + { Ast::IntrinsicType::Log, Build("log", false, ReturnType::Param0Type, Params{}) }, + { Ast::IntrinsicType::Log2, Build("log2", false, ReturnType::Param0Type, Params{}) }, + { Ast::IntrinsicType::MatrixInverse, Build("inverse", false, ReturnType::Param0Type, Params{}) }, + { Ast::IntrinsicType::MatrixTranspose, Build("transpose", false, ReturnType::Param0Transposed, Params{}) }, + { Ast::IntrinsicType::Max, Build("max", false, ReturnType::Param0Type, Params{}) }, + { Ast::IntrinsicType::Min, Build("min", false, ReturnType::Param0Type, Params{}) }, + { Ast::IntrinsicType::Normalize, Build("normalize", false, ReturnType::Param0Type, Params{}) }, + { Ast::IntrinsicType::Not, Build("not", false, ReturnType::Param0Type, Params{}) }, + { Ast::IntrinsicType::Pow, Build("pow", false, ReturnType::Param0Type, Params{}) }, + { Ast::IntrinsicType::RadToDeg, Build("rad2deg", false, ReturnType::Param0Type, Params{}) }, + { Ast::IntrinsicType::Reflect, Build("reflect", false, ReturnType::Param0Type, Params{}) }, + { Ast::IntrinsicType::Round, Build("round", false, ReturnType::Param0Type, Params{}) }, + { Ast::IntrinsicType::RoundEven, Build("roundeven", false, ReturnType::Param0Type, Params{}) }, + { Ast::IntrinsicType::Select, Build("select", false, ReturnType::Param1Type, Params{}) }, + { Ast::IntrinsicType::Sign, Build("sign", false, ReturnType::Param0Type, Params{}) }, + { Ast::IntrinsicType::Sin, Build("sin", false, ReturnType::Param0Type, Params{}) }, + { Ast::IntrinsicType::Sinh, Build("sinh", false, ReturnType::Param0Type, Params{}) }, + { Ast::IntrinsicType::SmoothStep, Build("smoothstep", false, ReturnType::Param0Type, Params{}) }, + { Ast::IntrinsicType::Step, Build("step", false, ReturnType::Param0Type, Params{}) }, + { Ast::IntrinsicType::Sqrt, Build("sqrt", false, ReturnType::Param0Type, Params{}) }, + { Ast::IntrinsicType::Tan, Build("tan", false, ReturnType::Param0Type, Params{}) }, + { Ast::IntrinsicType::Tanh, Build("tanh", false, ReturnType::Param0Type, Params{}) }, + { Ast::IntrinsicType::TextureRead, Build("textureRead", true, ReturnType::Param0TextureValue, Params{}) }, + { Ast::IntrinsicType::TextureSampleImplicitLod, Build("textureSampleImplicitLod", true, ReturnType::Param0SampledValue, Params{}, ShaderStageType::Fragment) }, + { Ast::IntrinsicType::TextureSampleImplicitLodDepthComp, Build("textureSampleImplicitLodDepthComp", true, ReturnType::Param0SampledValue, Params{}, ShaderStageType::Fragment) }, + { Ast::IntrinsicType::TextureWrite, Build("textureWrite", true, ReturnType::None, Params{}) }, + { Ast::IntrinsicType::Trunc, Build("trunc", false, ReturnType::Param0Type, Params{}) }, }); } diff --git a/src/NZSL/LangWriter.cpp b/src/NZSL/LangWriter.cpp index be2d26c8..1a7aab4f 100644 --- a/src/NZSL/LangWriter.cpp +++ b/src/NZSL/LangWriter.cpp @@ -408,11 +408,10 @@ namespace nzsl void LangWriter::Append(const Ast::StorageType& storageType) { Append("storage[", storageType.containedType); - switch (storageType.accessPolicy) + if (storageType.accessPolicy != AccessPolicy::ReadWrite) { - case AccessPolicy::ReadOnly: Append(", readonly"); break; - case AccessPolicy::ReadWrite: break; - case AccessPolicy::WriteOnly: Append(", writeonly"); break; + Append(", "); + Append(Parser::ToString(storageType.accessPolicy)); } Append("]"); } @@ -437,19 +436,11 @@ namespace nzsl } Append("[", textureType.baseType, ", "); - switch (textureType.accessPolicy) - { - case AccessPolicy::ReadOnly: Append("readonly"); break; - case AccessPolicy::ReadWrite: Append("readwrite"); break; - case AccessPolicy::WriteOnly: Append("writeonly"); break; - } + Append(Parser::ToString(textureType.accessPolicy)); if (textureType.format != ImageFormat::Unknown) - { - auto formatIt = LangData::s_imageFormats.find(textureType.format); - assert(formatIt != LangData::s_imageFormats.end()); - Append(", ", formatIt->second.identifier); - } + Append(", ", Parser::ToString(textureType.format)); + Append("]"); } @@ -1333,9 +1324,9 @@ namespace nzsl { auto intrinsicIt = LangData::s_intrinsicData.find(node.intrinsic); assert(intrinsicIt != LangData::s_intrinsicData.end()); - assert(!intrinsicIt->second.functionName.empty()); + assert(!intrinsicIt->second.isMethod); - Append(intrinsicIt->second.functionName); + Append(intrinsicIt->second.name); break; } diff --git a/src/NZSL/Parser.cpp b/src/NZSL/Parser.cpp index 00a17e3f..b263a066 100644 --- a/src/NZSL/Parser.cpp +++ b/src/NZSL/Parser.cpp @@ -154,6 +154,14 @@ namespace nzsl return it->second.identifier; } + std::string_view Parser::ToString(Ast::IntrinsicType intrinsicType) + { + auto it = LangData::s_intrinsicData.find(intrinsicType); + assert(it != LangData::s_intrinsicData.end()); + + return it->second.name; + } + std::string_view Parser::ToString(Ast::LoopUnroll loopUnroll) { auto it = LangData::s_unrollModes.find(loopUnroll); @@ -192,6 +200,33 @@ namespace nzsl NAZARA_UNREACHABLE(); } + + std::string_view Parser::ToString(AccessPolicy accessPolicy) + { + switch (accessPolicy) + { + case AccessPolicy::ReadOnly: return "readonly"; + case AccessPolicy::ReadWrite: return "readwrite"; + case AccessPolicy::WriteOnly: return "writeonly"; + } + + NAZARA_UNREACHABLE(); + } + + std::string_view Parser::ToString(ImageType imageType) + { + switch (imageType) + { + case ImageType::E1D: return "1D"; + case ImageType::E1D_Array: return "1DArray"; + case ImageType::E2D: return "2D"; + case ImageType::E2D_Array: return "2DArray"; + case ImageType::E3D: return "3D"; + case ImageType::Cubemap: return "Cube"; + } + + NAZARA_UNREACHABLE(); + } std::string_view Parser::ToString(ShaderStageType shaderStage) { @@ -201,6 +236,14 @@ namespace nzsl return it->second.identifier; } + std::string_view Parser::ToString(ImageFormat imageFormat) + { + auto formatIt = LangData::s_imageFormats.find(imageFormat); + assert(formatIt != LangData::s_imageFormats.end()); + + return formatIt->second.identifier; + } + const Token& Parser::Advance() { const Token& token = Peek(); diff --git a/src/ShaderCompiler/Compiler.cpp b/src/ShaderCompiler/Compiler.cpp index 79a02ba0..79d5fbc9 100644 --- a/src/ShaderCompiler/Compiler.cpp +++ b/src/ShaderCompiler/Compiler.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -30,6 +31,7 @@ #include #include #include +#include namespace nzslc { @@ -201,6 +203,9 @@ namespace nzslc if (m_options.count("compile") > 0) Step("Compiling"sv, __LINE__, &Compiler::Compile); + + if (m_options.count("reflect") > 0) + Step("Reflecting"sv, __LINE__, &Compiler::Reflect); }); } @@ -240,6 +245,9 @@ You can also specify -header as a suffix (ex: --compile=glsl-header) to generate ("p,partial", "Allow partial compilation") ("skip-unchanged", "After compilation, compare the output with the current output file and skip writing if the content is the same", cxxopts::value()->default_value("false")); + options.add_options("reflection") + ("r,reflect", "Outputs informations about a struct as a json", cxxopts::value>()); + options.add_options("glsl output") ("gl-es", "Generate GLSL ES instead of GLSL", cxxopts::value()->default_value("false")) ("gl-version", "OpenGL version (310 being 3.1)", cxxopts::value(), "version") @@ -690,12 +698,342 @@ You can also specify -header as a suffix (ex: --compile=glsl-header) to generate throw std::runtime_error(fmt::format("{} has unknown extension \"{}\"", Nz::PathToString(m_inputFilePath.filename()), Nz::PathToString(extension))); } + void Compiler::Reflect() + { + m_outputHeader = false; + + // if no output path has been provided, output in the same folder as the input file + std::filesystem::path outputFilePath = m_outputPath; + if (outputFilePath.empty()) + outputFilePath = m_inputFilePath.parent_path(); + + outputFilePath /= m_inputFilePath.filename(); + outputFilePath += Nz::Utf8Path(".json"); + + const std::vector& reflectTypes = m_options["reflect"].as>(); + + std::unordered_set remainingStructs(reflectTypes.begin(), reflectTypes.end()); + + nlohmann::ordered_json structArray = nlohmann::ordered_json::array(); + + std::unordered_map structFieldOffsets; + + nzsl::Ast::ReflectVisitor::Callbacks callbacks; + callbacks.onStructDeclaration = [&](const nzsl::Ast::DeclareStructStatement& structDecl) + { + auto it = remainingStructs.find(structDecl.description.name); + if (it == remainingStructs.end()) + return; + + remainingStructs.erase(it); + + nlohmann::ordered_json structDoc; + structDoc["name"] = structDecl.description.name; + if (!structDecl.description.tag.empty()) + structDoc["tag"] = structDecl.description.tag; + + if (structDecl.structIndex) + structDoc["structIndex"] = *structDecl.structIndex; + + nlohmann::ordered_json structMemberArray = nlohmann::ordered_json::array(); + + std::optional fieldOffsets; + if (structDecl.description.layout.IsResultingValue()) + { + structDoc["layout"] = nzsl::Parser::ToString(structDecl.description.layout.GetResultingValue()); + switch (structDecl.description.layout.GetResultingValue()) + { + case nzsl::Ast::MemoryLayout::Scalar: + fieldOffsets.emplace(nzsl::StructLayout::Scalar); + break; + + case nzsl::Ast::MemoryLayout::Std140: + fieldOffsets.emplace(nzsl::StructLayout::Std140); + break; + + case nzsl::Ast::MemoryLayout::Std430: + fieldOffsets.emplace(nzsl::StructLayout::Std430); + break; + } + } + else if (structDecl.description.layout.IsExpression()) + structDoc["layout"] = "unresolved"; + + for (const auto& member : structDecl.description.members) + { + nlohmann::ordered_json memberDoc; + memberDoc["name"] = member.name; + + if (member.cond.HasValue()) + { + if (member.cond.IsResultingValue()) + { + if (!member.cond.GetResultingValue()) + continue; + } + else + { + memberDoc["condition"] = "unresolved"; + fieldOffsets.reset(); //< member offset can no longer be guaranteed at this point + } + } + + if (member.type.IsResultingValue()) + { + memberDoc["type"] = ReflectType(member.type.GetResultingValue()); + if (fieldOffsets) + { + auto structFinder = [&](std::size_t structIndex) -> const nzsl::FieldOffsets& + { + return Nz::Retrieve(structFieldOffsets, structIndex); + }; + + memberDoc["offset"] = nzsl::Ast::RegisterStructField(*fieldOffsets, member.type.GetResultingValue(), structFinder); + } + } + else if (member.type.IsExpression()) + memberDoc["type"] = "unresolved"; + + if (member.locationIndex.IsResultingValue()) + memberDoc["location"] = member.locationIndex.GetResultingValue(); + else if (member.locationIndex.IsExpression()) + memberDoc["location"] = "unresolved"; + + structMemberArray.push_back(std::move(memberDoc)); + } + + if (fieldOffsets && structDecl.structIndex) + structFieldOffsets.emplace(*structDecl.structIndex, *fieldOffsets); + + structDoc["members"] = std::move(structMemberArray); + + structArray.push_back(std::move(structDoc)); + + // TODO: Stop visit if remainingStructs.empty() + }; + + nzsl::Ast::ReflectVisitor reflectVisitor; + reflectVisitor.Reflect(*m_shaderModule, callbacks); + + if (!remainingStructs.empty()) + throw std::runtime_error(fmt::format("struct \"{}\" was not found", *remainingStructs.begin())); + + nlohmann::ordered_json result; + result["structs"] = std::move(structArray); + + if (m_skipOutput) + return; + + if (m_outputToStdout) + { + OutputToStdout(result.dump(1, '\t')); + return; + } + + std::string output = result.dump(1, '\t'); + OutputFile(std::move(outputFilePath), output.data(), output.size()); + } + + nlohmann::ordered_json Compiler::ReflectType(const nzsl::Ast::ExpressionType& exprType) const + { + return std::visit([this](auto&& type) + { + return ReflectType(type); + }, exprType); + } + + nlohmann::ordered_json Compiler::ReflectType(const nzsl::Ast::NoType& /*exprType*/) const + { + return { + {"type", "noType"} + }; + } + + nlohmann::ordered_json Compiler::ReflectType(const nzsl::Ast::AliasType& exprType) const + { + return { + {"type", "alias"}, + {"targetType", ReflectType(exprType.TargetType())} + }; + } + + nlohmann::ordered_json Compiler::ReflectType(const nzsl::Ast::ArrayType& exprType) const + { + return { + {"type", "array"}, + {"length", exprType.length}, + {"isWrapped", exprType.isWrapped}, + {"innerType", ReflectType(exprType.InnerType())}, + }; + } + + nlohmann::ordered_json Compiler::ReflectType(const nzsl::Ast::DynArrayType& exprType) const + { + return { + {"type", "dynArray"}, + {"isWrapped", exprType.isWrapped}, + {"innerType", ReflectType(exprType.InnerType())}, + }; + } + + nlohmann::ordered_json Compiler::ReflectType(const nzsl::Ast::FunctionType& exprType) const + { + return { + {"type", "function"}, + {"index", exprType.funcIndex} + }; + } + + nlohmann::ordered_json Compiler::ReflectType(const nzsl::Ast::ImplicitArrayType& /*exprType*/) const + { + return { + {"type", "implicitArray"} + }; + } + + nlohmann::ordered_json Compiler::ReflectType(const nzsl::Ast::ImplicitMatrixType& exprType) const + { + return { + {"type", "implicitMatrix"}, + {"columnCount", exprType.columnCount}, + {"rowCount", exprType.rowCount} + }; + } + + nlohmann::ordered_json Compiler::ReflectType(const nzsl::Ast::ImplicitVectorType& exprType) const + { + return { + {"type", "implicitVector"}, + {"dims", exprType.componentCount} + }; + } + + nlohmann::ordered_json Compiler::ReflectType(const nzsl::Ast::IntrinsicFunctionType& exprType) const + { + return { + {"type", "intrinsicFunction"}, + {"intrinsic", nzsl::Parser::ToString(exprType.intrinsic)} + }; + } + + nlohmann::ordered_json Compiler::ReflectType(const nzsl::Ast::MatrixType& exprType) const + { + return { + {"type", "matrix"}, + {"columnCount", exprType.columnCount}, + {"rowCount", exprType.rowCount}, + {"cellType", nzsl::Ast::ToString(exprType.type)}, + }; + } + + nlohmann::ordered_json Compiler::ReflectType(const nzsl::Ast::MethodType& exprType) const + { + return { + {"type", "method"}, + {"objectType", ReflectType(exprType.ObjectType())}, + {"methodIndex", exprType.methodIndex } + }; + } + + nlohmann::ordered_json Compiler::ReflectType(const nzsl::Ast::ModuleType& exprType) const + { + return { + {"type", "module"}, + {"index", exprType.moduleIndex} + }; + } + + nlohmann::ordered_json Compiler::ReflectType(const nzsl::Ast::NamedExternalBlockType& exprType) const + { + return { + {"type", "namedExternalBlock"}, + {"index", exprType.namedExternalBlockIndex} + }; + } + + nlohmann::ordered_json Compiler::ReflectType(const nzsl::Ast::PrimitiveType& exprType) const + { + return { + {"type", "primitive"}, + {"primitiveType", nzsl::Ast::ToString(exprType)} + }; + } + + nlohmann::ordered_json Compiler::ReflectType(const nzsl::Ast::PushConstantType& exprType) const + { + return { + {"type", "push_constant"}, + {"structIndex", exprType.containedType.structIndex} + }; + } + + nlohmann::ordered_json Compiler::ReflectType(const nzsl::Ast::SamplerType& exprType) const + { + return { + {"type", "sampler"}, + {"depth", exprType.depth}, + {"dim", nzsl::Parser::ToString(exprType.dim)}, + {"sampledType", nzsl::Ast::ToString(exprType.sampledType)} + }; + } + + nlohmann::ordered_json Compiler::ReflectType(const nzsl::Ast::StorageType& exprType) const + { + return { + {"type", "storage"}, + {"structIndex", exprType.containedType.structIndex} + }; + } + + nlohmann::ordered_json Compiler::ReflectType(const nzsl::Ast::StructType& exprType) const + { + return { + {"type", "struct"}, + {"index", exprType.structIndex} + }; + } + + nlohmann::ordered_json Compiler::ReflectType(const nzsl::Ast::TextureType& exprType) const + { + return { + {"type", "texture"}, + {"accessPolicy", exprType.accessPolicy}, + {"baseType", nzsl::Ast::ToString(exprType.baseType)}, + {"dim", nzsl::Parser::ToString(exprType.dim)}, + {"format", nzsl::Parser::ToString(exprType.format)}, + }; + } + + nlohmann::ordered_json Compiler::ReflectType(const nzsl::Ast::Type& exprType) const + { + return { + {"type", "type"}, + {"index", exprType.typeIndex} + }; + } + + nlohmann::ordered_json Compiler::ReflectType(const nzsl::Ast::UniformType& exprType) const + { + return { + {"type", "uniform"}, + {"structIndex", exprType.containedType.structIndex} + }; + } + + nlohmann::ordered_json Compiler::ReflectType(const nzsl::Ast::VectorType& exprType) const + { + return { + {"type", "vector"}, + {"dims", exprType.componentCount}, + {"baseType", nzsl::Ast::ToString(exprType.type)} + }; + } + void Compiler::Resolve() { using namespace std::literals; - nzsl::Ast::TransformerContext context; - context.partialCompilation = m_options.count("partial") > 0; + m_transformerContext.partialCompilation = m_options.count("partial") > 0; nzsl::Ast::ResolveTransformer::Options resolverOpt; @@ -726,8 +1064,8 @@ You can also specify -header as a suffix (ex: --compile=glsl-header) to generate nzsl::Ast::ResolveTransformer resolver; nzsl::Ast::ValidationTransformer validation; - Step("AST processing"sv, __LINE__, [&] { resolver.Transform(*m_shaderModule, context, resolverOpt); }); - Step("AST validation"sv, __LINE__, [&] { validation.Transform(*m_shaderModule, context); }); + Step("AST processing"sv, __LINE__, [&] { resolver.Transform(*m_shaderModule, m_transformerContext, resolverOpt); }); + Step("AST validation"sv, __LINE__, [&] { validation.Transform(*m_shaderModule, m_transformerContext); }); } template diff --git a/src/ShaderCompiler/Compiler.hpp b/src/ShaderCompiler/Compiler.hpp index 921bcd32..f42efbd6 100644 --- a/src/ShaderCompiler/Compiler.hpp +++ b/src/ShaderCompiler/Compiler.hpp @@ -10,7 +10,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -64,6 +66,30 @@ namespace nzslc void OutputFile(std::filesystem::path filePath, const void* data, std::size_t size, bool disallowHeader = false); void OutputToStdout(std::string_view str); void ReadInput(); + void Reflect(); + nlohmann::ordered_json ReflectType(const nzsl::Ast::ExpressionType& exprType) const; + nlohmann::ordered_json ReflectType(const nzsl::Ast::NoType& exprType) const; + nlohmann::ordered_json ReflectType(const nzsl::Ast::AliasType& exprType) const; + nlohmann::ordered_json ReflectType(const nzsl::Ast::ArrayType& exprType) const; + nlohmann::ordered_json ReflectType(const nzsl::Ast::DynArrayType& exprType) const; + nlohmann::ordered_json ReflectType(const nzsl::Ast::FunctionType& exprType) const; + nlohmann::ordered_json ReflectType(const nzsl::Ast::ImplicitArrayType& exprType) const; + nlohmann::ordered_json ReflectType(const nzsl::Ast::ImplicitMatrixType& exprType) const; + nlohmann::ordered_json ReflectType(const nzsl::Ast::ImplicitVectorType& exprType) const; + nlohmann::ordered_json ReflectType(const nzsl::Ast::IntrinsicFunctionType& exprType) const; + nlohmann::ordered_json ReflectType(const nzsl::Ast::MatrixType& exprType) const; + nlohmann::ordered_json ReflectType(const nzsl::Ast::MethodType& exprType) const; + nlohmann::ordered_json ReflectType(const nzsl::Ast::ModuleType& exprType) const; + nlohmann::ordered_json ReflectType(const nzsl::Ast::NamedExternalBlockType& exprType) const; + nlohmann::ordered_json ReflectType(const nzsl::Ast::PrimitiveType& exprType) const; + nlohmann::ordered_json ReflectType(const nzsl::Ast::PushConstantType& exprType) const; + nlohmann::ordered_json ReflectType(const nzsl::Ast::SamplerType& exprType) const; + nlohmann::ordered_json ReflectType(const nzsl::Ast::StorageType& exprType) const; + nlohmann::ordered_json ReflectType(const nzsl::Ast::StructType& exprType) const; + nlohmann::ordered_json ReflectType(const nzsl::Ast::TextureType& exprType) const; + nlohmann::ordered_json ReflectType(const nzsl::Ast::Type& exprType) const; + nlohmann::ordered_json ReflectType(const nzsl::Ast::UniformType& exprType) const; + nlohmann::ordered_json ReflectType(const nzsl::Ast::VectorType& exprType) const; void Resolve(); template auto Step(std::enable_if_t, std::string_view> stepName, std::size_t uniqueIndex, F&& func, Args&&... args) -> decltype(std::invoke(func, std::forward(args)...)); template auto Step(std::enable_if_t, std::string_view> stepName, std::size_t uniqueIndex, F&& func, Args&&... args) -> decltype(std::invoke(func, this, std::forward(args)...)); @@ -88,6 +114,7 @@ namespace nzslc std::vector m_steps; LogFormat m_logFormat; nzsl::Ast::ModulePtr m_shaderModule; + nzsl::Ast::TransformerContext m_transformerContext; cxxopts::ParseResult& m_options; bool m_isProfiling; bool m_outputHeader; diff --git a/tests/src/Tests/NzslcTests.cpp b/tests/src/Tests/NzslcTests.cpp index 7e482249..dd4b1577 100644 --- a/tests/src/Tests/NzslcTests.cpp +++ b/tests/src/Tests/NzslcTests.cpp @@ -59,4 +59,22 @@ TEST_CASE("Standalone compiler", "[NZSLC]") // Generate the same shader a second time with --skip-unchanged and ensure file wasn't modified ExecuteCommand("./nzslc --skip-unchanged --verbose --compile=spv --debug-level=regular -o test_files -m ../resources/modules/Color.nzslb -m ../resources/modules/Data/OutputStruct.nzslb -m ../resources/modules/Data/DataStruct.nzslb ../resources/Shader.nzslb", "Skipped file .+Shader.spv"); } + + WHEN("Performing reflection") + { + REQUIRE(std::filesystem::exists("../resources/Reflection.nzsl")); + + auto Cleanup = [] + { + if (std::filesystem::is_directory("test_files")) + std::filesystem::remove_all("test_files"); + }; + + Cleanup(); + + Nz::CallOnExit cleanupOnExit(std::move(Cleanup)); + + ExecuteCommand("./nzslc --verbose --reflect=Output --partial -o test_files ../resources/Reflection.nzsl"); + CheckFileMatch("../resources/Reflection.nzsl.json", "test_files/Reflection.nzsl.json"); + } }