diff options
Diffstat (limited to 'source/slang')
| -rw-r--r-- | source/slang/core.meta.slang | 104 | ||||
| -rw-r--r-- | source/slang/glsl.meta.slang | 54 | ||||
| -rw-r--r-- | source/slang/hlsl.meta.slang | 921 | ||||
| -rw-r--r-- | source/slang/slang-ast-print.cpp | 15 | ||||
| -rw-r--r-- | source/slang/slang-ast-print.h | 5 | ||||
| -rw-r--r-- | source/slang/slang-capability.cpp | 19 | ||||
| -rwxr-xr-x | source/slang/slang-compiler.h | 1 | ||||
| -rw-r--r-- | source/slang/slang-diagnostic-defs.h | 3 | ||||
| -rw-r--r-- | source/slang/slang-doc-ast.h | 2 | ||||
| -rw-r--r-- | source/slang/slang-doc-markdown-writer.cpp | 2437 | ||||
| -rw-r--r-- | source/slang/slang-doc-markdown-writer.h | 167 | ||||
| -rw-r--r-- | source/slang/slang-language-server-completion.cpp | 12 | ||||
| -rw-r--r-- | source/slang/slang.cpp | 91 |
13 files changed, 2988 insertions, 843 deletions
diff --git a/source/slang/core.meta.slang b/source/slang/core.meta.slang index 62c9a2800..d0f0fcee2 100644 --- a/source/slang/core.meta.slang +++ b/source/slang/core.meta.slang @@ -1,15 +1,24 @@ // Slang `core` library // Aliases for base types +/// @category scalar_types Scalar types typedef half float16_t; +/// @category scalar_types typedef float float32_t; +/// @category scalar_types typedef double float64_t; +/// @category scalar_types typedef int int32_t; + +/// @category scalar_types typedef uint uint32_t; +/// @category scalar_types typedef uintptr_t size_t; -typedef uintptr_t usize_t +/// @category scalar_types +typedef uintptr_t usize_t; +/// @category scalar_types typedef intptr_t ssize_t; // Modifier for variables that must resolve to compile-time constants @@ -446,6 +455,7 @@ interface IRWArray<T> : IArray<T> // argument. The left-to-right evaluation order guaranteed by Slang then ensures that // `left` is evaluated before `right`. // +//@hidden: __generic<T,U> [__unsafeForceInlineEarly] U operator,(T left, U right) @@ -457,20 +467,29 @@ U operator,(T left, U right) // follow that definition for the scalar condition overload, so this declaration just serves // for type-checking purpose only. -__generic<T> __intrinsic_op(select) T operator?:(bool condition, T ifTrue, T ifFalse); +//@hidden: +__generic<T> __intrinsic_op(select) T operator?: (bool condition, T ifTrue, T ifFalse); + +//@hidden: __generic<T, let N : int> __intrinsic_op(select) vector<T,N> operator?:(vector<bool,N> condition, vector<T,N> ifTrue, vector<T,N> ifFalse); // Users are advised to use `select` instead if non-short-circuiting behavior is intended. +//@public: __generic<T> __intrinsic_op(select) T select(bool condition, T ifTrue, T ifFalse); __generic<T, let N : int> __intrinsic_op(select) vector<T,N> select(vector<bool,N> condition, vector<T,N> ifTrue, vector<T,N> ifFalse); // Allow real-number types to be cast into each other +//@hidden: __intrinsic_op($(kIROp_FloatCast)) T __realCast<T : __BuiltinRealType, U : __BuiltinRealType>(U val); +//@hidden: __intrinsic_op($(kIROp_CastIntToFloat)) - T __realCast<T : __BuiltinRealType, U : __BuiltinIntegerType>(U val); +T __realCast<T : __BuiltinRealType, U : __BuiltinIntegerType>(U val); +//@hidden: __intrinsic_op($(kIROp_IntCast)) - T __intCast<T : __BuiltinType, U : __BuiltinType>(U val); +T __intCast<T : __BuiltinType, U : __BuiltinType>(U val); + +//@hidden: ${{{{ // We are going to use code generation to produce the // declarations for all of our base types. @@ -716,17 +735,20 @@ ${{{{ // (eventually we can have the traditional syntax sugar for this) }}}} +//@hidden: __magic_type(NullPtrType) struct NullPtr { }; +//@hidden: __magic_type(NoneType) __intrinsic_type($(kIROp_VoidType)) struct __none_t { }; +//@public: __generic<T, let addrSpace : uint64_t = $( (uint64_t)AddressSpace::UserPointer)ULL> __magic_type(PtrType) __intrinsic_type($(kIROp_PtrType)) @@ -752,6 +774,7 @@ struct Ptr } }; +//@hidden: __intrinsic_op($(kIROp_Load)) T __load<T, let addrSpace : uint64_t>(Ptr<T, addrSpace> ptr); @@ -788,6 +811,7 @@ __generic<T, let addrSpace : uint64_t> __intrinsic_op($(kIROp_Eql)) bool operator ==(Ptr<T, addrSpace> p1, Ptr<T, addrSpace> p2); +//@public: extension bool : IRangedValue { __generic<T, let addrSpace : uint64_t> @@ -847,6 +871,7 @@ extension uintptr_t : IRangedValue static const int size = $(SLANG_PROCESSOR_X86_64?"8":"4"); } +//@hidden: __generic<T> __magic_type(OutType) __intrinsic_type($(kIROp_OutType)) @@ -873,6 +898,7 @@ struct ConstRef typealias __Addr<T> = Ptr<T, $( (uint64_t)AddressSpace::Generic)ULL>; +//@public: __generic<T> __magic_type(OptionalType) __intrinsic_type($(kIROp_OptionalType)) @@ -895,6 +921,7 @@ struct Optional __init(T val); }; +//@hidden: __generic<T> [__unsafeForceInlineEarly] bool operator==(Optional<T> val, __none_t noneVal) @@ -920,6 +947,7 @@ bool operator!=(__none_t noneVal, Optional<T> val) return val.hasValue; } +//@public: __generic<each T> __magic_type(TupleType) struct Tuple @@ -936,7 +964,7 @@ Tuple<T, U> concat<each T, each U>(Tuple<T> t, Tuple<U> u) return makeTuple(expand each t, expand each u); } - +//@hidden: [__unsafeForceInlineEarly] bool __assign(inout bool v, bool newVal) { @@ -978,6 +1006,7 @@ void __tupleGreaterKernel<T : IComparable>(inout bool result, inout bool exit, T } } +//@public: __generic<each T : IComparable> extension Tuple<T> : IComparable { @@ -1027,6 +1056,7 @@ interface IDifferentiableFunc<TR : IDifferentiable, each TP : IDifferentiable> : TR operator()(expand each TP p); } +//@hidden: __generic<T> __magic_type(NativeRefType) __intrinsic_type($(kIROp_NativePtrType)) @@ -1049,6 +1079,7 @@ T __attachToNativeRef(NativeRef<T> nativeVal) return result; } +//@public: __magic_type(StringType) __intrinsic_type($(kIROp_StringType)) struct String @@ -1086,8 +1117,10 @@ struct String } }; +/// @category misc_types typedef String string; +/// @category misc_types __magic_type(NativeStringType) __intrinsic_type($(kIROp_NativeStringType)) struct NativeString @@ -1133,11 +1166,14 @@ extension Ptr<void> __init(NativeRef<T> ptr); } +//@hidden: __magic_type(DynamicType) __intrinsic_type($(kIROp_DynamicType)) struct __Dynamic {}; +//@public: + extension half : IRangedValue { static const half maxValue = half(65504); @@ -1200,7 +1236,9 @@ struct Array : IRWArray<T> __intrinsic_op($(kIROp_GetArrayLength)) int getCount(); } - /// An `N` component vector with elements of type `T`. + +/// @category math_types Math types +/// An `N` component vector with elements of type `T`. __generic<T = float, let N : int = 4> __magic_type(VectorExpressionType) struct vector : IRWArray<T> @@ -1225,10 +1263,13 @@ struct vector : IRWArray<T> int getCount() { return N; } } -const int kRowMajorMatrixLayout = $(SLANG_MATRIX_LAYOUT_ROW_MAJOR); -const int kColumnMajorMatrixLayout = $(SLANG_MATRIX_LAYOUT_COLUMN_MAJOR); +//@hidden: +static const int kRowMajorMatrixLayout = $(SLANG_MATRIX_LAYOUT_ROW_MAJOR); +static const int kColumnMajorMatrixLayout = $(SLANG_MATRIX_LAYOUT_COLUMN_MAJOR); - /// A matrix with `R` rows and `C` columns, with elements of type `T`. +//@public: +/// A matrix with `R` rows and `C` columns, with elements of type `T`. +/// @category math_types Math types __generic<T = float, let R : int = 4, let C : int = 4, let L : int = $(SLANG_MATRIX_LAYOUT_MODE_UNKNOWN)> __magic_type(MatrixExpressionType) struct matrix : IRWArray<vector<T,C>> @@ -1248,9 +1289,11 @@ struct matrix : IRWArray<vector<T,C>> int getCount() { return R; } } +//@hidden: __intrinsic_op($(kIROp_Eql)) -vector<bool, N> __vectorEql<T, let N:int>(vector<T, N> left, vector<T,N> right); +vector<bool, N> __vectorEql<T, let N : int>(vector<T, N> left, vector<T, N> right); +//@public: __generic<T:__BuiltinFloatingPointType, let N : int> extension vector<T,N> : IFloat { @@ -1360,10 +1403,12 @@ extension matrix<int16_t,R,C,L> __init(int value) { this = matrix<T,R,C,L>(T(value)); } } +//@hidden: __intrinsic_op(makeVector) __generic<T, let N:int> vector<T,N*2> __makeVector(vector<T,N> vec1, vector<T,N> vec2); +//@public: __generic<T> extension vector<T, 4> { @@ -1385,6 +1430,7 @@ extension matrix<T, 2, 2, L> } } +//@hidden: ${{{{ static const struct { char const* name; @@ -1458,6 +1504,7 @@ __intrinsic_type($(kIROp_ConstantBufferType)) __magic_type(ConstantBufferType) struct ConstantBuffer {} +///@category texture_types __generic<T> __intrinsic_type($(kIROp_TextureBufferType)) __magic_type(TextureBufferType) @@ -1468,6 +1515,7 @@ __intrinsic_type($(kIROp_ParameterBlockType)) __magic_type(ParameterBlockType) struct ParameterBlock {} +/// @category stage_io __generic<T, let MAX_VERTS : uint> __magic_type(VerticesType) __intrinsic_type($(kIROp_VerticesType)) @@ -1507,6 +1555,7 @@ struct OutputVertices } }; +/// @category stage_io __generic<T, let MAX_PRIMITIVES : uint> __magic_type(IndicesType) __intrinsic_type($(kIROp_IndicesType)) @@ -1539,6 +1588,7 @@ struct OutputIndices } }; +/// @category stage_io __generic<T, let MAX_PRIMITIVES : uint> __magic_type(PrimitivesType) __intrinsic_type($(kIROp_PrimitivesType)) @@ -1573,7 +1623,7 @@ struct OutputPrimitives } }; -//@ hidden: +//@ public: // Need to add constructors to the types above @@ -1757,6 +1807,7 @@ ${{{{ } }}}} +//@ hidden: __generic<T, U> __intrinsic_op(0) T __slang_noop_cast(U u); @@ -1764,14 +1815,16 @@ T __slang_noop_cast(U u); //@ public: - /// Sampling state for filtered texture fetches. +/// Sampling state for filtered texture fetches. +/// @category sampler_types Sampler types __magic_type(SamplerStateType, $(int(SamplerStateFlavor::SamplerState))) __intrinsic_type($(kIROp_SamplerStateType)) struct SamplerState { } - /// Sampling state for filtered texture fetches that include a comparison operation before filtering. +/// Sampling state for filtered texture fetches that include a comparison operation before filtering. +/// @category sampler_types __magic_type(SamplerStateType, $(int(SamplerStateFlavor::SamplerComparisonState))) __intrinsic_type($(kIROp_SamplerComparisonStateType)) struct SamplerComparisonState @@ -2212,7 +2265,9 @@ ${{{{ //@ public: -// Bit cast +/// Bit cast between types. `T` and `U` must have the same size. +/// They can be any scalar, vector, matrix, struct or array types. +/// @category conversion __generic<T, U> [__unsafeForceInlineEarly] __intrinsic_op($(kIROp_BitCast)) @@ -2224,15 +2279,16 @@ __generic<T, U> __intrinsic_op($(kIROp_CreateExistentialObject)) T createDynamicObject(uint typeId, U value); -// Reinterpret +/// Reinterpret type `U` as type `T`. `T` and `U` +/// can be any scalar, vector, matrix, struct or array types. +/// @category conversion __generic<T, U> [__unsafeForceInlineEarly] __intrinsic_op($(kIROp_Reinterpret)) T reinterpret(U value); -// Use an otherwise unused value -// -// This can be used to silence the warning about returning before initializing an out paramter. +/// Use an otherwise unused value +/// This can be used to silence the warning about returning before initializing an out paramter. __generic<T> [__readNone] [ForceInline] @@ -2267,6 +2323,8 @@ int __SyntaxError() } } +//@ hidden: + /// For downstream compilers that allow sizeof/alignof/offsetof /// Can't be called in the C/C++ style. Need to use __size_of<some_type>() as opposed to sizeof(some_type). __generic<T> @@ -2350,7 +2408,7 @@ __generic<E : __EnumType> __intrinsic_op($(kIROp_Neq)) bool operator!=(E left, E right); -//@ public: +//@ hidden: // public interfaces for generic arithmetic types. @@ -2722,8 +2780,8 @@ __Addr<T> __getLegalizedSPIRVGlobalParamAddr(T val); __intrinsic_op($(kIROp_RequireComputeDerivative)) void __requireComputeDerivative(); -// Atomic<T> - +//@ public: +/// @category misc_types enum MemoryOrder { Relaxed = $(kIRMemoryOrder_Relaxed), @@ -2767,6 +2825,7 @@ struct Atomic<T : IAtomicable> MemoryOrder failOrder = MemoryOrder.Relaxed); } +/// These addtional members are only available when `T` conforms to `IArithmeticAtomicable`. extension<T : IArithmeticAtomicable> Atomic<T> { __intrinsic_op($(kIROp_AtomicAdd)) @@ -2779,6 +2838,7 @@ extension<T : IArithmeticAtomicable> Atomic<T> [__ref] T min(T value, MemoryOrder order = MemoryOrder.Relaxed); // returns original value } +/// These addtional members are only available when `T` conforms to `IBitAtomicable`. extension<T : IBitAtomicable> Atomic<T> { __intrinsic_op($(kIROp_AtomicAnd)) @@ -2793,6 +2853,8 @@ extension<T : IBitAtomicable> Atomic<T> [__ref] T decrement(MemoryOrder order = MemoryOrder.Relaxed); } +//@ hidden: + __generic<T : IArithmeticAtomicable> [ForceInline] T operator +=(__ref Atomic<T> v, T value) diff --git a/source/slang/glsl.meta.slang b/source/slang/glsl.meta.slang index 0078d39cb..ada908306 100644 --- a/source/slang/glsl.meta.slang +++ b/source/slang/glsl.meta.slang @@ -1535,7 +1535,7 @@ public typealias isamplerCube = SamplerCube<int4>; public typealias samplerCube = SamplerCube<float4>; __generic<let sampleCount:int=0, let format:int=0> -public typealias sampler1DShadow = __TextureImpl< +public typealias sampler1DShadow = _Texture< float, __Shape1D, 0, // isArray @@ -1548,7 +1548,7 @@ public typealias sampler1DShadow = __TextureImpl< >; __generic<let sampleCount:int=0, let format:int=0> -public typealias sampler2DShadow = __TextureImpl< +public typealias sampler2DShadow = _Texture< float, __Shape2D, 0, // isArray @@ -1561,7 +1561,7 @@ public typealias sampler2DShadow = __TextureImpl< >; __generic<let sampleCount:int=0, let format:int=0> -public typealias samplerCubeShadow = __TextureImpl< +public typealias samplerCubeShadow = _Texture< float, __ShapeCube, 0, // isArray @@ -1586,7 +1586,7 @@ public typealias isamplerCubeArray = SamplerCubeArray<int4>; public typealias samplerCubeArray = SamplerCubeArray<float4>; __generic<let sampleCount:int=0, let format:int=0> -public typealias sampler1DArrayShadow = __TextureImpl< +public typealias sampler1DArrayShadow = _Texture< float, __Shape1D, 1, // isArray @@ -1599,7 +1599,7 @@ public typealias sampler1DArrayShadow = __TextureImpl< >; __generic<let sampleCount:int=0, let format:int=0> -public typealias sampler2DArrayShadow = __TextureImpl< +public typealias sampler2DArrayShadow = _Texture< float, __Shape2D, 1, // isArray @@ -1612,7 +1612,7 @@ public typealias sampler2DArrayShadow = __TextureImpl< >; __generic<let sampleCount:int=0, let format:int=0> -public typealias samplerCubeArrayShadow = __TextureImpl< +public typealias samplerCubeArrayShadow = _Texture< float, __ShapeCube, 1, // isArray @@ -1633,13 +1633,13 @@ public typealias isampler2DMSArray = Sampler2DMSArray<int4>; public typealias usampler2DMSArray = Sampler2DMSArray<uint4>; __generic<T=float4, let sampleCount:int=0, let format:int=0> -public typealias Sampler2DRect = __TextureImpl<T, __Shape2D, 0, 0, sampleCount, 0, 0, 1, format>; +public typealias Sampler2DRect = _Texture<T, __Shape2D, 0, 0, sampleCount, 0, 0, 1, format>; public typealias sampler2DRect = Sampler2DRect<float4>; public typealias isampler2DRect = Sampler2DRect<int4>; public typealias usampler2DRect = Sampler2DRect<uint4>; __generic<let sampleCount:int=0, let format:int=0> -public typealias sampler2DRectShadow = __TextureImpl< +public typealias sampler2DRectShadow = _Texture< float, __Shape2D, 0, // isArray @@ -1652,7 +1652,7 @@ public typealias sampler2DRectShadow = __TextureImpl< >; __generic<T, let format:int=0> -public typealias SamplerBuffer = __TextureImpl< +public typealias SamplerBuffer = _Texture< T, __ShapeBuffer, 0, // isArray @@ -1871,7 +1871,7 @@ public ivec3 textureSize(Sampler2DMSArray<vector<T,N>,sampleCount> sampler) __generic<T, let isArray:int, let sampleCount:int, let isShadow:int, let format:int> [ForceInline] [require(glsl_hlsl_metal_spirv, texture_querylod)] -public vec2 textureQueryLod(__TextureImpl< +public vec2 textureQueryLod(_Texture< T, __Shape1D, isArray, @@ -1904,7 +1904,7 @@ public vec2 textureQueryLod(__TextureImpl< __generic<T, Shape: __ITextureShape, let isArray:int, let sampleCount:int, let isShadow:int, let format:int> [ForceInline] [require(glsl_hlsl_metal_spirv, texture_querylod)] -public vec2 textureQueryLod(__TextureImpl< +public vec2 textureQueryLod(_Texture< T, Shape, isArray, @@ -2130,7 +2130,7 @@ public vector<T,4> texture(Sampler1D<vector<T,N>> sampler, float p, constexpr fl __generic<T:__BuiltinArithmeticType, let N:int, Shape: __ITextureShape, let isArray:int, let sampleCount:int, let format:int> [ForceInline] [require(cpp_glsl_hlsl_spirv, texture_sm_4_0_fragment)] -public vector<T,4> texture(__TextureImpl< +public vector<T,4> texture(_Texture< vector<T,N>, Shape, isArray, @@ -2148,7 +2148,7 @@ public vector<T,4> texture(__TextureImpl< __generic<T:__BuiltinArithmeticType, let N:int, Shape: __ITextureShape, let isArray:int, let sampleCount:int, let format:int> [ForceInline] [require(cpp_glsl_hlsl_spirv, texture_sm_4_0_fragment)] -public vector<T,4> texture(__TextureImpl< +public vector<T,4> texture(_Texture< vector<T,N>, Shape, isArray, @@ -2566,7 +2566,7 @@ public vector<T,4> textureLod(Sampler1D<vector<T,N>> sampler, float p, float lod __generic<T:__BuiltinArithmeticType, let N:int, Shape: __ITextureShape, let isArray:int, let sampleCount:int, let format:int> [ForceInline] [require(cpp_cuda_glsl_hlsl_spirv, texture_sm_4_0_fragment)] -public vector<T,4> textureLod(__TextureImpl< +public vector<T,4> textureLod(_Texture< vector<T,N>, Shape, isArray, @@ -2814,7 +2814,7 @@ public vector<T,4> texelFetch(Sampler1D<vector<T,N>> sampler, int p, int lod) __generic<T:__BuiltinArithmeticType, let N:int, Shape:__ITextureShape, let isArray:int, let sampleCount:int, let format:int> [ForceInline] [require(cpp_glsl_hlsl_spirv, texture_sm_4_1_samplerless)] -public vector<T,4> texelFetch(__TextureImpl< +public vector<T,4> texelFetch(_Texture< vector<T,N>, Shape, isArray, @@ -2848,7 +2848,7 @@ public vector<T,4> texelFetch(SamplerBuffer<vector<T,N>,format> sampler, int p) __generic<T:__BuiltinArithmeticType, let N:int, let isArray:int, let sampleCount:int, let format:int> [ForceInline] [require(cpp_glsl_hlsl_spirv, texture_sm_4_1_samplerless)] -public vector<T,4> texelFetch(__TextureImpl< +public vector<T,4> texelFetch(_Texture< vector<T,N>, __Shape2D, isArray, @@ -2884,7 +2884,7 @@ public vector<T,4> texelFetchOffset(Sampler1D<vector<T,N>> sampler, int p, int l __generic<T:__BuiltinArithmeticType, let N:int, Shape:__ITextureShape, let isArray:int, let sampleCount:int, let format:int> [ForceInline] [require(cpp_glsl_hlsl_spirv, texture_sm_4_1_samplerless)] -public vector<T,4> texelFetchOffset(__TextureImpl< +public vector<T,4> texelFetchOffset(_Texture< vector<T,N>, Shape, isArray, @@ -3196,7 +3196,7 @@ public vector<T,4> textureLodOffset(Sampler1D<vector<T,N>> sampler, float p, flo __generic<T:__BuiltinArithmeticType, let N:int, Shape:__ITextureShape, let isArray:int, let sampleCount:int, let format:int> [ForceInline] [require(cpp_glsl_hlsl_spirv, texture_sm_4_0)] -public vector<T,4> textureLodOffset(__TextureImpl< +public vector<T,4> textureLodOffset(_Texture< vector<T,N>, Shape, isArray, @@ -3551,7 +3551,7 @@ public vector<T,4> textureGrad(Sampler1D<vector<T,N>> sampler, float p, float dP __generic<T:__BuiltinArithmeticType, let N:int, Shape:__ITextureShape, let isArray:int, let sampleCount:int, let format:int> [ForceInline] [require(cpp_glsl_hlsl_spirv, texture_sm_4_1)] -public vector<T,4> textureGrad(__TextureImpl< +public vector<T,4> textureGrad(_Texture< vector<T,N>, Shape, isArray, @@ -3666,7 +3666,7 @@ public vector<T,4> textureGradOffset(Sampler1D<vector<T,N>> sampler, float p, fl __generic<T:__BuiltinArithmeticType, let N:int, Shape:__ITextureShape, let isArray:int, let sampleCount:int, let format:int> [require(cpp_glsl_hlsl_spirv, texture_sm_4_1)] [ForceInline] -public vector<T,4> textureGradOffset(__TextureImpl< +public vector<T,4> textureGradOffset(_Texture< vector<T,N>, Shape, isArray, @@ -4024,7 +4024,7 @@ public float textureProjGradOffset(sampler2DShadow sampler, vec4 p, vec2 dPdx, v __generic<T:__BuiltinArithmeticType, let N:int, Shape:__ITextureShape, let isArray:int, let sampleCount:int, let format:int> [ForceInline] [require(glsl_hlsl_spirv, texture_gather)] -public vector<T,4> textureGather(__TextureImpl< +public vector<T,4> textureGather(_Texture< vector<T,N>, Shape, isArray, @@ -4048,7 +4048,7 @@ public vector<T,4> textureGather(__TextureImpl< __generic<Shape:__ITextureShape, let isArray:int, let sampleCount:int, let format:int> [ForceInline] [require(glsl_hlsl_spirv, texture_gather)] -public vec4 textureGather(__TextureImpl< +public vec4 textureGather(_Texture< float, Shape, isArray, @@ -4070,7 +4070,7 @@ public vec4 textureGather(__TextureImpl< __generic<T:__BuiltinArithmeticType, let N:int, let isArray:int, let sampleCount:int, let format:int> [ForceInline] [require(glsl_hlsl_spirv, texture_gather)] -public vector<T,4> textureGatherOffset(__TextureImpl< +public vector<T,4> textureGatherOffset(_Texture< vector<T,N>, __Shape2D, isArray, @@ -4094,7 +4094,7 @@ public vector<T,4> textureGatherOffset(__TextureImpl< __generic<let isArray:int, let sampleCount:int, let format:int> [ForceInline] [require(glsl_hlsl_spirv, texture_gather)] -public vec4 textureGatherOffset(__TextureImpl< +public vec4 textureGatherOffset(_Texture< float, __Shape2D, isArray, @@ -4116,7 +4116,7 @@ public vec4 textureGatherOffset(__TextureImpl< __generic<T:__BuiltinArithmeticType, let N:int, let isArray:int, let sampleCount:int, let format:int> [ForceInline] [require(glsl_hlsl_spirv, texture_gather)] -public vector<T,4> textureGatherOffsets(__TextureImpl< +public vector<T,4> textureGatherOffsets(_Texture< vector<T,N>, __Shape2D, isArray, @@ -4140,7 +4140,7 @@ public vector<T,4> textureGatherOffsets(__TextureImpl< __generic<let isArray:int, let sampleCount:int, let format:int> [ForceInline] [require(glsl_hlsl_spirv, texture_gather)] -public vec4 textureGatherOffsets(__TextureImpl< +public vec4 textureGatherOffsets(_Texture< float, __Shape2D, isArray, @@ -4574,7 +4574,7 @@ ${{{{ }}}} __generic<let format:int=0> - public typealias $(fullTypeName) = __TextureImpl< + public typealias $(fullTypeName) = _Texture< $(targetType.type), $(targetShape.shape), $(targetShape.isArray), // isArray diff --git a/source/slang/hlsl.meta.slang b/source/slang/hlsl.meta.slang index b0553aa19..ed1c9fcb6 100644 --- a/source/slang/hlsl.meta.slang +++ b/source/slang/hlsl.meta.slang @@ -1,35 +1,42 @@ // Slang HLSL compatibility library +//@hidden: typedef uint UINT; __intrinsic_op($(kIROp_RequireGLSLExtension)) void __requireGLSLExtension(String extensionName); +//@public: [sealed] interface IBufferDataLayout { } +/// @category misc_types __intrinsic_type($(kIROp_DefaultBufferLayoutType)) struct DefaultDataLayout : IBufferDataLayout {}; +/// @category misc_types __intrinsic_type($(kIROp_Std140BufferLayoutType)) [require(spirv)] [require(glsl)] struct Std140DataLayout : IBufferDataLayout {}; +/// @category misc_types __intrinsic_type($(kIROp_Std430BufferLayoutType)) [require(spirv)] [require(glsl)] struct Std430DataLayout : IBufferDataLayout {}; +/// @category misc_types __intrinsic_type($(kIROp_ScalarBufferLayoutType)) struct ScalarDataLayout : IBufferDataLayout {}; +//@hidden: __generic<T, L : IBufferDataLayout = DefaultDataLayout> __intrinsic_type($(kIROp_GLSLShaderStorageBufferType)) __magic_type(GLSLShaderStorageBufferType) @@ -57,6 +64,26 @@ __intrinsic_op($(kIROp_StructuredBufferGetDimensions)) [require(cpp_cuda_glsl_hlsl_metal_spirv, structuredbuffer_rw)] uint2 __structuredBufferGetDimensions<T,L:IBufferDataLayout>(RasterizerOrderedStructuredBuffer<T,L> buffer); +//@public: +/** +Represents an opaque handle to an append structured buffer allocated in global memory. +A structured buffer can be viewed as an array of the specified element type. +An append structure buffer internally maintains an atomic counter to keep track of the number of elements in the buffer, +and provide an atomic operation to append a new element to the buffer. + @param T The element type of the buffer. + @param L The memory layout of the buffer. + @remarks +This type is supported natively when targeting HLSL. +When generating code for other targets, this type is translated into a pair or an ordinary `RWStructuredBuffer` and +a separate `RWStructuredBuffer` that holds the atomic counter. +The `L` generic parameter is used to specify the memory layout of the buffer when +generating SPIRV. +`L` must be one of `DefaultDataLayout`, `Std140DataLayout`, `Std430DataLayout` or `ScalarDataLayout`. +The default value is `DefaultDataLayout`. +When generating code for other targets, this parameter is ignored and has no effect on the generated code. + @see `RWStructuredBuffer`, `ConsumeStructuredBuffer`, `RasterizerOrderedStructuredBuffer`. + @category buffer_types +*/ __generic<T, L:IBufferDataLayout=DefaultDataLayout> __magic_type(HLSLAppendStructuredBufferType) __intrinsic_type($(kIROp_HLSLAppendStructuredBufferType)) @@ -77,6 +104,7 @@ struct AppendStructuredBuffer } }; +/// @category buffer_types __magic_type(HLSLByteAddressBufferType) __intrinsic_type($(kIROp_HLSLByteAddressBufferType)) [require(cpp_cuda_glsl_hlsl_metal_spirv, byteaddressbuffer)] @@ -309,6 +337,8 @@ interface __ITextureShape interface __ITextureShape1D2D3D : __ITextureShape { } + +/// @category misc_types Miscelaneous types __magic_type(TextureShape1DType) __intrinsic_type($(kIROp_TextureShape1DType)) struct __Shape1D : __ITextureShape1D2D3D @@ -317,6 +347,7 @@ struct __Shape1D : __ITextureShape1D2D3D static const int dimensions = 1; static const int planeDimensions = 1; } +/// @category misc_types __magic_type(TextureShape2DType) __intrinsic_type($(kIROp_TextureShape2DType)) struct __Shape2D : __ITextureShape1D2D3D @@ -325,6 +356,7 @@ struct __Shape2D : __ITextureShape1D2D3D static const int dimensions = 2; static const int planeDimensions = 2; } +/// @category misc_types __magic_type(TextureShape3DType) __intrinsic_type($(kIROp_TextureShape3DType)) struct __Shape3D : __ITextureShape1D2D3D @@ -333,6 +365,7 @@ struct __Shape3D : __ITextureShape1D2D3D static const int dimensions = 3; static const int planeDimensions = 3; } +/// @category misc_types __magic_type(TextureShapeCubeType) __intrinsic_type($(kIROp_TextureShapeCubeType)) struct __ShapeCube : __ITextureShape @@ -341,6 +374,7 @@ struct __ShapeCube : __ITextureShape static const int dimensions = 3; static const int planeDimensions = 2; } +/// @category misc_types __magic_type(TextureShapeBufferType) __intrinsic_type($(kIROp_TextureShapeBufferType)) struct __ShapeBuffer : __ITextureShape @@ -349,6 +383,8 @@ struct __ShapeBuffer : __ITextureShape static const int dimensions = 1; static const int planeDimensions = 1; } + +//@hidden: __intrinsic_op(vectorReshape) vector<T,N> __vectorReshape<let N : int, T, let M : int>(vector<T,M> vin); @@ -356,14 +392,90 @@ __intrinsic_op(makeVector) __generic<T, let N:int> vector<T,N+1> __makeVector(vector<T,N> vec, T scalar); - +//@public: +/// A parameterized type that represents all flavors of texture types supported by the Slang language. +/// Please note that this type is not intended to be used directly in user code, and not all combinations +/// of the generic arguments are valid. +/// Instead, use the specific texture types such as `Texture1D`, `Texture2DArray` and `Sampler2D` etc. +/// This documentation is provided for reference purposes only. +/// @param T The element type of the texture. Must be a scalar or vector type. +/// @param Shape The shape of the texture. Must be one of `__Shape1D`, `__Shape2D`, `__Shape3D`, `__ShapeCube` or `__ShapeBuffer`. +/// @param isArray Indicates whether the texture is an array texture. +/// @param isMS Indicates whether the texture is a multisampled texture. +/// @param sampleCount The number of samples of a multisampled texture. +/// @param access The access mode of the texture. 0 for read-only, 1 for read-write, 2 for rasterizer-ordered, 3 for feedback. +/// @param isShadow Indicates whether the texture is a shadow texture (for combined texture-sampler only). +/// @param isCombined Indicates whether the texture is a combined texture-sampler. +/// @param format The storage format of the texture. Users should specify the format using an `[format("...")]` attribute instead. +/// @see `Texture1D`, `Texture2D`, `Texture3D`, `TextureCube`, `Texture1DArray`, +/// `Texture2DArray`, `TextureCubeArray`, `Sampler1D`, `Sampler2D`, `Sampler3D`, `SamplerCube`, `Sampler1DArray`, `Sampler2DArray`, `SamplerCubeArray`, +/// `Texture2DMS`, `Texture2DMSArray`, `RWTexture1D`, `RWTexture2D`, `RWTexture3D`, `RWTexture1DArray`, `RWTexture2DArray`, +/// `RWTexture2DMS`, `RWTexture2DMSArray`, `Buffer`, `RWBuffer`, `FeedbackTexture2D`, `FeedbackTexture2DArray`. +/// @remarks +/// HLSL texture types are implemented as typealiases to the builtin `_Texture` type. Users +/// are advised to use the HLSL-specific texture types instead of `_Texture` directly. +/// +/// For read-write textures, Slang will automatically infer `format` from `T`. +/// To explicitly specify texel storage formats for read-write textures, +/// use the `[format("formatString")]` attribute on the texture parameter declaration. +/// Allowed `formatString` values are: +/// +/// |id | Format string | Meaning | +/// |:--|:---------------------|:------------------| +/// |1 |`"rgba32f"` | 4 channel 32-bit floating point texture | +/// |2 |`"rgba16f"` | 4 channel 16-bit floating point texture | +/// |3 |`"rg32f"` | 2 channel 32-bit floating point texture | +/// |4 |`"rg16f"` | 2 channel 16-bit floating point texture | +/// |5 |`"r11f_g11f_b10f"` | 3 channel 11/11/10-bit floating point texture | +/// |6 |`"r32f"` | 1 channel 32-bit floating point texture | +/// |7 |`"r16f"` | 1 channel 16-bit floating point texture | +/// |8 |`"rgba16"` | 4 channel 16-bit normalized unsigned integer texture | +/// |9 |`"rgb10_a2"` | 4 channel 10/10/10/2-bit signed integer texture | +/// |10 |`"rgba8"` | 4 channel 8-bit normalized unsigned integer texture | +/// |11 |`"rg16"` | 2 channel 16-bit normalized unsigned integer texture | +/// |12 |`"rg8"` | 2 channel 8-bit normalized unsigned integer texture | +/// |13 |`"r16"` | 1 channel 16-bit normalized unsigned integer texture | +/// |14 |`"r8"` | 1 channel 8-bit normalized unsigned integer texture | +/// |15 |`"rgba16_snorm"` | 4 channel 16-bit normalized signed integer texture | +/// |16 |`"rgba8_snorm"` | 4 channel 8-bit normalized signed integer texture | +/// |17 |`"rg16_snorm"` | 2 channel 16-bit normalized signed integer texture | +/// |18 |`"rg8_snorm"` | 2 channel 8-bit normalized signed integer texture | +/// |19 |`"r16_snorm"` | 1 channel 16-bit normalized signed integer texture | +/// |20 |`"r8_snorm"` | 1 channel 8-bit normalized signed integer texture | +/// |21 |`"rgba32i"` | 4 channel 32-bit signed integer texture | +/// |22 |`"rgba16i"` | 4 channel 16-bit signed integer texture | +/// |23 |`"rgba8i"` | 4 channel 8-bit signed integer texture | +/// |24 |`"rg32i"` | 2 channel 32-bit signed integer texture | +/// |25 |`"rg16i"` | 2 channel 16-bit signed integer texture | +/// |26 |`"rg8i"` | 2 channel 8-bit signed integer texture | +/// |27 |`"r32i"` | 1 channel 32-bit signed integer texture | +/// |28 |`"r16i"` | 1 channel 16-bit signed integer texture | +/// |29 |`"r8i"` | 1 channel 8-bit signed integer texture | +/// |30 |`"rgba32ui"` | 4 channel 32-bit unsigned integer texture | +/// |31 |`"rgba16ui"` | 4 channel 16-bit unsigned integer texture | +/// |32 |`"rgb10_a2ui"` | 4 channel 10/10/10/2-bit unsigned integer texture | +/// |33 |`"rgba8ui"` | 4 channel 8-bit unsigned integer texture | +/// |34 |`"rg32ui"` | 2 channel 32-bit unsigned integer texture | +/// |35 |`"rg16ui"` | 2 channel 16-bit unsigned integer texture | +/// |36 |`"rg8ui"` | 2 channel 8-bit unsigned integer texture | +/// |37 |`"r32ui"` | 1 channel 32-bit unsigned integer texture | +/// |38 |`"r16ui"` | 1 channel 16-bit unsigned integer texture | +/// |39 |`"r8ui"` | 1 channel 8-bit unsigned integer texture | +/// |40 |`"r64ui"` | 1 channel 64-bit unsigned integer texture | +/// |41 |`"r64i"` | 1 channel 64-bit signed integer texture | +/// +/// When targeting Vulkan, a combined-texture-sampler type (`isCombined==1`) translates to a `OpTypeSampledImage` type in SPIR-V. +/// For other targets, the combined-texture-sampler type is translated to a pair of a `Texture` and `SamplerState`. +/// `isShadow` is only applicable to combined-texture-sampler types and must be `0` for non-combined texture types. +/// @internal +/// @category texture_types Texture types __magic_type(TextureType) __intrinsic_type($(kIROp_TextureType)) -struct __TextureImpl<T, Shape: __ITextureShape, let isArray:int, let isMS:int, let sampleCount:int, let access:int, let isShadow:int, let isCombined:int, let format:int> +struct _Texture<T, Shape: __ITextureShape, let isArray:int, let isMS:int, let sampleCount:int, let access:int, let isShadow:int, let isCombined:int, let format:int> { } - +//@hidden: // Combined texture sampler specific functions [require(glsl, texture_sm_4_1)] @@ -542,15 +654,19 @@ float __glsl_texture_offset_level_zero_1d_shadow<TTexture, TCoord, TOffset>(TTex } } +//@public: + __generic<T, Shape: __ITextureShape, let isArray:int, let isMS:int, let sampleCount:int, let isShadow:int, let format:int> -extension __TextureImpl<T,Shape,isArray,isMS,sampleCount,0,isShadow,1,format> +extension _Texture<T,Shape,isArray,isMS,sampleCount,0,isShadow,1,format> { + //@hidden: static const int access = 0; + //@public: typealias TextureCoord = vector<float, Shape.dimensions>; __intrinsic_op($(kIROp_CombinedTextureSamplerGetTexture)) - __TextureImpl<T, Shape, isArray, isMS, sampleCount, 0, isShadow, 0, format> __getTexture(); + _Texture<T, Shape, isArray, isMS, sampleCount, 0, isShadow, 0, format> __getTexture(); __intrinsic_op($(kIROp_CombinedTextureSamplerGetSampler)) SamplerState __getSampler(); @@ -608,6 +724,26 @@ extension __TextureImpl<T,Shape,isArray,isMS,sampleCount,0,isShadow,1,format> } } + /// Samples the texture at the given location. + /// + ///@param s The `SamplerState` to use for the sampling operation. This parameter is omitted when `this` is a combined texture sampler type (`isCombined == 0`). + ///@param location The location to sample the texture at. + ///@param offset Texel offset to apply. + ///@param clamp The max level of detail to use. + ///@param[out] status The result status of the operation. + /// This parameter is currently only used when targeting HLSL. + /// For other targets, the result status is always 0. + ///@return The sampled texture value. + ///@see `SampleBias`, `SampleLevel`, `SampleGrad`, `SampleCmp`, `SampleCmpLevelZero`. + ///@remarks + /// The `Sample` function is defined for all read-only texture types, including + /// `Texture1D`, `Texture2D`, `Texture3D`, `TextureCube`, + /// `Texture1DArray`, `Texture2DArray` and `TextureCubeArray`. + /// + /// The function is not available for read-write texture types. + /// + /// For HLSL/D3D targets, the texture element type must be a scalar or vector of float or half types. + /// [__readNone] [ForceInline] [require(cpp_cuda_glsl_hlsl_metal_spirv_wgsl, texture_sm_4_0_fragment)] @@ -1114,8 +1250,9 @@ extension __TextureImpl<T,Shape,isArray,isMS,sampleCount,0,isShadow,1,format> } // Non-combined texture types specific functions + __generic<T, Shape: __ITextureShape, let isArray:int, let isMS:int, let sampleCount:int, let access:int, let isShadow:int, let format:int> -extension __TextureImpl<T,Shape,isArray,isMS,sampleCount,access,isShadow,0,format> +extension _Texture<T,Shape,isArray,isMS,sampleCount,access,isShadow,0,format> { typealias TextureCoord = vector<float, Shape.dimensions>; @@ -1165,7 +1302,7 @@ extension __TextureImpl<T,Shape,isArray,isMS,sampleCount,access,isShadow,0,forma } __generic<T, Shape: __ITextureShape, let isArray:int, let isMS:int, let sampleCount:int, let isShadow:int, let format:int> -extension __TextureImpl<T,Shape,isArray,isMS,sampleCount,0,isShadow,0,format> +extension _Texture<T,Shape,isArray,isMS,sampleCount,0,isShadow,0,format> { [__readNone] [ForceInline] @@ -2166,7 +2303,7 @@ for (int isMS = 0; isMS <= 1; isMS++) { }}}} __generic<T, let sampleCount:int, let access:int, let isShadow:int, let isCombined:int, let format:int> -extension __TextureImpl<T,$(shapeTypeName),$(isArray),$(isMS),sampleCount,access,isShadow,isCombined,format> +extension _Texture<T,$(shapeTypeName),$(isArray),$(isMS),sampleCount,access,isShadow,isCombined,format> { ${{{{ textureTypeInfo.writeGetDimensionFunctions(); @@ -2179,7 +2316,7 @@ ${{{{ // Texture.GetSamplePosition(int s); __generic<T, Shape: __ITextureShape, let isArray:int, let sampleCount:int, let access:int, let isShadow:int, let isCombined:int, let format:int> -extension __TextureImpl<T,Shape,isArray,1,sampleCount,access,isShadow,isCombined,format> +extension _Texture<T,Shape,isArray,1,sampleCount,access,isShadow,isCombined,format> { [require(cpp_cuda_glsl_hlsl_spirv, texture_sm_4_1_vertex_fragment_geometry)] float2 GetSamplePosition(int s); @@ -2194,7 +2331,7 @@ __generic<TElement, T, Shape: __ITextureShape, let isArray:int, let sampleCount: [ForceInline] [require(glsl_metal_spirv_wgsl, texture_gather)] vector<TElement,4> __texture_gather( - __TextureImpl<T, Shape, isArray, 0, sampleCount, access, isShadow, 0, format> texture, + _Texture<T, Shape, isArray, 0, sampleCount, access, isShadow, 0, format> texture, SamplerState s, vector<float, Shape.dimensions+isArray> location, int component) @@ -2263,7 +2400,7 @@ __generic<TElement, T, Shape: __ITextureShape, let isArray:int, let sampleCount: [ForceInline] [require(glsl_spirv, texture_gather)] vector<TElement,4> __texture_gather( - __TextureImpl<T, Shape, isArray, 0, sampleCount, access, isShadow, 1, format> sampler, + _Texture<T, Shape, isArray, 0, sampleCount, access, isShadow, 1, format> sampler, vector<float, Shape.dimensions+isArray> location, int component) { @@ -2282,7 +2419,7 @@ __generic<TElement, T, Shape: __ITextureShape, let isArray:int, let sampleCount: [ForceInline] [require(glsl_metal_spirv_wgsl, texture_gather)] vector<TElement,4> __texture_gather_offset( - __TextureImpl<T, Shape, isArray, 0, sampleCount, access, isShadow, 0, format> texture, + _Texture<T, Shape, isArray, 0, sampleCount, access, isShadow, 0, format> texture, SamplerState s, constexpr vector<float, Shape.dimensions+isArray> location, constexpr vector<int, Shape.planeDimensions> offset, @@ -2343,7 +2480,7 @@ __generic<TElement, T, Shape: __ITextureShape, let isArray:int, let sampleCount: [ForceInline] [require(glsl_spirv, texture_gather)] vector<TElement,4> __texture_gather_offset( - __TextureImpl<T, Shape, isArray, 0, sampleCount, access, isShadow, 1, format> sampler, + _Texture<T, Shape, isArray, 0, sampleCount, access, isShadow, 1, format> sampler, vector<float, Shape.dimensions+isArray> location, constexpr vector<int, Shape.planeDimensions> offset, int component) @@ -2363,7 +2500,7 @@ __generic<TElement, T, Shape: __ITextureShape, let isArray:int, let sampleCount: [ForceInline] [require(glsl_spirv, texture_gather)] vector<TElement,4> __texture_gather_offsets( - __TextureImpl<T, Shape, isArray, 0, sampleCount, access, isShadow, 0, format> texture, + _Texture<T, Shape, isArray, 0, sampleCount, access, isShadow, 0, format> texture, SamplerState s, vector<float, Shape.dimensions+isArray> location, constexpr vector<int, Shape.planeDimensions> offset1, @@ -2390,7 +2527,7 @@ __generic<TElement, T, Shape: __ITextureShape, let isArray:int, let sampleCount: [ForceInline] [require(glsl_spirv, texture_gather)] vector<TElement,4> __texture_gather_offsets( - __TextureImpl<T, Shape, isArray, 0, sampleCount, access, isShadow, 1, format> sampler, + _Texture<T, Shape, isArray, 0, sampleCount, access, isShadow, 1, format> sampler, vector<float, Shape.dimensions+isArray> location, constexpr vector<int, Shape.planeDimensions> offset1, constexpr vector<int, Shape.planeDimensions> offset2, @@ -2415,7 +2552,7 @@ __generic<TElement, T, Shape: __ITextureShape, let isArray:int, let sampleCount: [ForceInline] [require(glsl_metal_spirv_wgsl, texture_gather)] vector<TElement,4> __texture_gatherCmp( - __TextureImpl<T, Shape, isArray, 0, sampleCount, access, isShadow, 0, format> texture, + _Texture<T, Shape, isArray, 0, sampleCount, access, isShadow, 0, format> texture, SamplerComparisonState s, vector<float, Shape.dimensions+isArray> location, TElement compareValue) @@ -2465,7 +2602,7 @@ __generic<TElement, T, Shape: __ITextureShape, let isArray:int, let sampleCount: [ForceInline] [require(glsl_spirv, texture_gather)] vector<TElement,4> __texture_gatherCmp( - __TextureImpl<T, Shape, isArray, 0, sampleCount, access, isShadow, 1, format> sampler, + _Texture<T, Shape, isArray, 0, sampleCount, access, isShadow, 1, format> sampler, vector<float, Shape.dimensions+isArray> location, TElement compareValue) { @@ -2484,7 +2621,7 @@ __generic<TElement, T, Shape: __ITextureShape, let isArray:int, let sampleCount: [ForceInline] [require(glsl_metal_spirv_wgsl, texture_gather)] vector<TElement,4> __texture_gatherCmp_offset( - __TextureImpl<T, Shape, isArray, 0, sampleCount, access, isShadow, 0, format> texture, + _Texture<T, Shape, isArray, 0, sampleCount, access, isShadow, 0, format> texture, SamplerComparisonState s, vector<float, Shape.dimensions+isArray> location, TElement compareValue, @@ -2531,7 +2668,7 @@ __generic<TElement, T, Shape: __ITextureShape, let isArray:int, let sampleCount: [ForceInline] [require(glsl_spirv, texture_gather)] vector<TElement,4> __texture_gatherCmp_offset( - __TextureImpl<T, Shape, isArray, 0, sampleCount, access, isShadow, 1, format> sampler, + _Texture<T, Shape, isArray, 0, sampleCount, access, isShadow, 1, format> sampler, vector<float, Shape.dimensions+isArray> location, TElement compareValue, constexpr vector<int, Shape.planeDimensions> offset) @@ -2551,7 +2688,7 @@ __generic<TElement, T, Shape: __ITextureShape, let isArray:int, let sampleCount: [ForceInline] [require(glsl_spirv, texture_gather)] vector<TElement,4> __texture_gatherCmp_offsets( - __TextureImpl<T, Shape, isArray, 0, sampleCount, access, isShadow, 0, format> texture, + _Texture<T, Shape, isArray, 0, sampleCount, access, isShadow, 0, format> texture, SamplerComparisonState s, vector<float, Shape.dimensions+isArray> location, TElement compareValue, @@ -2578,7 +2715,7 @@ __generic<TElement, T, Shape: __ITextureShape, let isArray:int, let sampleCount: [ForceInline] [require(glsl_spirv, texture_gather)] vector<TElement,4> __texture_gatherCmp_offsets( - __TextureImpl<T, Shape, isArray, 0, sampleCount, access, isShadow, 1, format> sampler, + _Texture<T, Shape, isArray, 0, sampleCount, access, isShadow, 1, format> sampler, vector<float, Shape.dimensions+isArray> location, TElement compareValue, vector<int, Shape.planeDimensions> offset1, @@ -2608,8 +2745,9 @@ for (int isScalarTexture = 0; isScalarTexture < 2; isScalarTexture++) }}}} // Gather for [TextureType = $(extTexType), isCombined = $(isCombined)] + __generic<T:__BuiltinArithmeticType $(extSizeParam), Shape: __ITextureShape, let isArray:int, let sampleCount:int, let isShadow:int, let format:int> -extension __TextureImpl<$(extTexType),Shape,isArray,0,sampleCount,0,isShadow,$(isCombined),format> +extension _Texture<$(extTexType),Shape,isArray,0,sampleCount,0,isShadow,$(isCombined),format> { ${{{{ for (int isShadow = 0; isShadow < 2; isShadow++) @@ -2768,11 +2906,12 @@ ${{{{ // Load/Subscript for readonly, no MS textures __generic<T, Shape: __ITextureShape, let isArray:int, let sampleCount:int, let isShadow:int, let isCombined:int, let format:int> -extension __TextureImpl<T,Shape,isArray,0,sampleCount,0,isShadow,isCombined,format> +extension _Texture<T,Shape,isArray,0,sampleCount,0,isShadow,isCombined,format> { +//@hidden: static const int isMS = 0; static const int access = $(kStdlibResourceAccessReadOnly); - +//@public: __glsl_extension(GL_EXT_samplerless_texture_functions) [__readNone] [require(glsl, texture_sm_4_1_samplerless)] @@ -3001,11 +3140,12 @@ extension __TextureImpl<T,Shape,isArray,0,sampleCount,0,isShadow,isCombined,form // Texture Load/Subscript for readonly, MS textures __generic<T, Shape: __ITextureShape, let isArray:int, let sampleCount:int, let isShadow:int, let isCombined:int, let format:int> -extension __TextureImpl<T,Shape,isArray,1,sampleCount,0,isShadow,isCombined,format> +extension _Texture<T,Shape,isArray,1,sampleCount,0,isShadow,isCombined,format> { +//@hidden: static const int access = $(kStdlibResourceAccessReadOnly); static const int isMS = 1; - +//@public: __glsl_extension(GL_EXT_samplerless_texture_functions) [__readNone] [ForceInline] @@ -3183,8 +3323,9 @@ ${{{{ const char* glslIntrinsicMS = "$cimageLoad($0, $1, $2)$z"; const char* glslIntrinsicMSOffset = "$cimageLoad($0, ($1)+($3), $2)$z"; }}}} + __generic<T, Shape: __ITextureShape, let isArray:int, let sampleCount:int, let isShadow:int, let format:int> -extension __TextureImpl<T,Shape,isArray,0,sampleCount,$(access),isShadow, 0,format> +extension _Texture<T,Shape,isArray,0,sampleCount,$(access),isShadow, 0,format> { [__readNone] [ForceInline] @@ -3527,9 +3668,11 @@ extension __TextureImpl<T,Shape,isArray,0,sampleCount,$(access),isShadow, 0,form ${{{{ if (access == kStdlibResourceAccessReadWrite) { }}}} + // RW MS textures. + __generic<T, Shape: __ITextureShape, let isArray:int, let sampleCount:int, let isShadow:int, let format:int> -extension __TextureImpl<T,Shape,isArray,1,sampleCount,$(access),isShadow, 0,format> +extension _Texture<T,Shape,isArray,1,sampleCount,$(access),isShadow, 0,format> { [__readNone] [ForceInline] @@ -3683,7 +3826,7 @@ ${{{{ // Definitions to support the legacy texture .mips[][] operator. struct __TextureMip<T, Shape : __ITextureShape, let isArray : int, let isCombined : int, let format : int> { - __TextureImpl<T, Shape, isArray, 0 /*isMS*/, 0 /*sampleCount*/, 0 /*access*/, 0 /*isShadow*/, isCombined, format> tex; + _Texture<T, Shape, isArray, 0 /*isMS*/, 0 /*sampleCount*/, 0 /*access*/, 0 /*isShadow*/, isCombined, format> tex; int mip; __subscript(vector<int, isArray + Shape.dimensions> pos)->T { @@ -3694,7 +3837,7 @@ struct __TextureMip<T, Shape : __ITextureShape, let isArray : int, let isCombine struct __TextureMips<T, Shape : __ITextureShape, let isArray : int, let isCombined : int, let format : int> { - __TextureImpl<T, Shape, isArray, 0 /*isMS*/, 0 /*sampleCount*/, 0 /*access*/, 0 /*isShadow*/, isCombined, format> tex; + _Texture<T, Shape, isArray, 0 /*isMS*/, 0 /*sampleCount*/, 0 /*access*/, 0 /*isShadow*/, isCombined, format> tex; __subscript(int mip)->__TextureMip<T, Shape, isArray, isCombined, format> { [__unsafeForceInlineEarly] @@ -3702,8 +3845,9 @@ struct __TextureMips<T, Shape : __ITextureShape, let isArray : int, let isCombin } } +//@hidden: __generic<T, Shape : __ITextureShape, let isArray : int, let isCombined : int, let format : int> -extension __TextureImpl<T, Shape, isArray, 0 /*isMS*/, 0 /*sampleCount*/, 0 /*access*/, 0 /*isShadow*/, isCombined, format> +extension _Texture<T, Shape, isArray, 0 /*isMS*/, 0 /*sampleCount*/, 0 /*access*/, 0 /*isShadow*/, isCombined, format> { property __TextureMips<T, Shape, isArray, isCombined, format> mips { @@ -3715,7 +3859,7 @@ extension __TextureImpl<T, Shape, isArray, 0 /*isMS*/, 0 /*sampleCount*/, 0 /*ac // Definitions to support the .sample[][] operator. struct __TextureSample<T, Shape : __ITextureShape, let isArray : int, let isCombined : int, let format : int> { - __TextureImpl<T, Shape, isArray, 1 /*isMS*/, 0 /*sampleCount*/, 0 /*access*/, 0 /*isShadow*/, isCombined, format> tex; + _Texture<T, Shape, isArray, 1 /*isMS*/, 0 /*sampleCount*/, 0 /*access*/, 0 /*isShadow*/, isCombined, format> tex; int sample; __subscript(vector<int, isArray + Shape.dimensions> pos)->T { @@ -3726,7 +3870,7 @@ struct __TextureSample<T, Shape : __ITextureShape, let isArray : int, let isComb struct __TextureSampleMS<T, Shape : __ITextureShape, let isArray : int, let isCombined : int, let format : int> { - __TextureImpl<T, Shape, isArray, 1 /*isMS*/, 0 /*sampleCount*/, 0 /*access*/, 0 /*isShadow*/, isCombined, format> tex; + _Texture<T, Shape, isArray, 1 /*isMS*/, 0 /*sampleCount*/, 0 /*access*/, 0 /*isShadow*/, isCombined, format> tex; __subscript(int sample)->__TextureSample<T, Shape, isArray, isCombined, format> { [__unsafeForceInlineEarly] @@ -3735,7 +3879,7 @@ struct __TextureSampleMS<T, Shape : __ITextureShape, let isArray : int, let isCo } __generic<T, Shape : __ITextureShape, let isArray : int, let isCombined : int, let format : int> -extension __TextureImpl<T, Shape, isArray, 1 /*isMS*/, 0 /*sampleCount*/, 0 /*access*/, 0 /*isShadow*/, isCombined, format> +extension _Texture<T, Shape, isArray, 1 /*isMS*/, 0 /*sampleCount*/, 0 /*access*/, 0 /*isShadow*/, isCombined, format> { property __TextureSampleMS<T, Shape, isArray, isCombined, format> sample { @@ -3744,6 +3888,8 @@ extension __TextureImpl<T, Shape, isArray, 1 /*isMS*/, 0 /*sampleCount*/, 0 /*ac } } +//@public: + // Texture type aliases. // T, Shape: __ITextureShape, let isArray:int, let isMS:int, let sampleCount:int, let access:int, let isShadow:int, let isCombined:int, let format:int ${{{{ @@ -3782,7 +3928,8 @@ ${{{{ continue; const char* textureTypeName = isCombined ? "Sampler" : "Texture"; }}}} -typealias $(accessPrefix[access])$(textureTypeName)$(shapeTypeNames[shape])$(msPostFix[isMS])$(arrayPostFix[isArray])<T=float4, let sampleCount:int=0, let format:int=0> = __TextureImpl<T, __Shape$(shapeTypeNames[shape]), $(isArray), $(isMS), sampleCount, $(access), 0, $(isCombined), format>; +/// @category texture_types +typealias $(accessPrefix[access])$(textureTypeName)$(shapeTypeNames[shape])$(msPostFix[isMS])$(arrayPostFix[isArray])<T=float4, let sampleCount:int=0, let format:int=0> = _Texture<T, __Shape$(shapeTypeNames[shape]), $(isArray), $(isMS), sampleCount, $(access), 0, $(isCombined), format>; ${{{{ } }}}} @@ -4293,6 +4440,20 @@ __intrinsic_op($(kIROp_ByteAddressBufferStore)) [require(cpp_cuda_glsl_hlsl_metal_spirv, byteaddressbuffer_rw)] void __byteAddressBufferStore<T>(RasterizerOrderedByteAddressBuffer buffer, int offset, int alignment, T value); +/** +Represents an opaque handle to a read-only structured buffer allocated in global memory. +A structured buffer can be viewed as an array of the specified element type. +@param T The element type of the buffer. +@param L The memory layout of the buffer. +@remarks +The `L` generic parameter is used to specify the memory layout of the buffer when +generating SPIRV. +`L` must be one of `DefaultDataLayout`, `Std140DataLayout`, `Std430DataLayout` or `ScalarDataLayout`. +The default value is `DefaultDataLayout`. +When generating code for other targets, this parameter is ignored and has no effect on the generated code. +@see `RWStructuredBuffer`, `AppendStructuredBuffer`, `ConsumeStructuredBuffer`, `RasterizerOrderedStructuredBuffer`. +@category buffer_types Buffer types +**/ __generic<T, L:IBufferDataLayout=DefaultDataLayout> __magic_type(HLSLStructuredBufferType) __intrinsic_type($(kIROp_HLSLStructuredBufferType)) @@ -4328,6 +4489,25 @@ struct StructuredBuffer }; }; +/** +Represents an opaque handle to a consume structured buffer allocated in global memory. +A structured buffer can be viewed as an array of the specified element type. +An append structure buffer internally maintains an atomic counter to keep track of the number of elements in the buffer, +and provide an atomic operation to append a new element to the buffer. +@param T The element type of the buffer. +@param L The memory layout of the buffer. +@remarks +This type is supported natively when targeting HLSL. +When generating code for other targets, this type is translated into a pair or an ordinary `StructuredBuffer` and +a separate `RWStructuredBuffer` that holds the atomic counter. +The `L` generic parameter is used to specify the memory layout of the buffer when +generating SPIRV. +`L` must be one of `DefaultDataLayout`, `Std140DataLayout`, `Std430DataLayout` or `ScalarDataLayout`. +The default value is `DefaultDataLayout`. +When generating code for other targets, this parameter is ignored and has no effect on the generated code. +@see `StructuredBuffer`, `AppendStructuredBuffer`, `RWStructuredBuffer`, `RasterizerOrderedStructuredBuffer`. +@category buffer_types +*/ __generic<T, L:IBufferDataLayout=DefaultDataLayout> __magic_type(HLSLConsumeStructuredBufferType) __intrinsic_type($(kIROp_HLSLConsumeStructuredBufferType)) @@ -4351,6 +4531,7 @@ struct ConsumeStructuredBuffer __intrinsic_op($(kIROp_GetElement)) T __getElement<T, U, I>(U collection, I index); +/// @category stage_io Stage IO types __generic<T, let N : int> [require(glsl_hlsl_spirv, hull)] __magic_type(HLSLInputPatchType) @@ -4374,6 +4555,7 @@ struct InputPatch } }; +/// @category stage_io __generic<T, let N : int> [require(glsl_hlsl_spirv, domain_hull)] __magic_type(HLSLOutputPatchType) @@ -4409,6 +4591,7 @@ static const struct { for(auto item : kMutableByteAddressBufferCases) { }}}} +/// @category buffer_types __magic_type(HLSL$(item.name)Type) __intrinsic_type($(item.op)) struct $(item.name) @@ -5740,6 +5923,20 @@ __generic<T, L:IBufferDataLayout=DefaultDataLayout> __magic_type(HLSL$(item.name)Type) __intrinsic_type($(item.op)) [require(cpp_cuda_glsl_hlsl_metal_spirv, structuredbuffer_rw)] +/** +Represents an opaque handle to a mutable structured buffer allocated in global memory. +A structured buffer can be viewed as an array of the specified element type. + @param T The element type of the buffer. + @param L The memory layout of the buffer. + @remarks +The `L` generic parameter is used to specify the memory layout of the buffer when +generating SPIRV. +`L` must be one of `DefaultDataLayout`, `Std140DataLayout`, `Std430DataLayout` or `ScalarDataLayout`. +The default value is `DefaultDataLayout`. +When generating code for other targets, this parameter is ignored and has no effect on the generated code. + @see `StructuredBuffer`, `AppendStructuredBuffer`, `ConsumeStructuredBuffer` + @category buffer_types +**/ struct $(item.name) { uint DecrementCounter(); @@ -5788,6 +5985,7 @@ ${{{{ } }}}} +/// @category stage_io __generic<T> [require(glsl_hlsl_spirv, geometry)] __magic_type(HLSLPointStreamType) @@ -5817,6 +6015,7 @@ struct PointStream } }; +/// @category stage_io __generic<T> [require(glsl_hlsl_spirv, geometry)] __magic_type(HLSLLineStreamType) @@ -5846,6 +6045,7 @@ struct LineStream } }; +/// @category stage_io __generic<T> [require(glsl_hlsl_spirv, geometry)] __magic_type(HLSLTriangleStreamType) @@ -5893,11 +6093,13 @@ struct TriangleStream #define MATRIX_MAP_TRINARY(TYPE, ROWS, COLS, FUNC, A, B, C) \ matrix<TYPE,ROWS,COLS> result; for(int i = 0; i < ROWS; ++i) { result[i] = FUNC(A[i], B[i], C[i]); } return result -// Try to terminate the current draw or dispatch call (HLSL SM 4.0) -void abort(); +//@public: -// Absolute value (HLSL SM 1.0) +/// Try to terminate the current draw or dispatch call (HLSL SM 4.0) +void abort(); +/// Absolute value (HLSL SM 1.0) +/// @category math __generic<T : __BuiltinIntegerType> [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv_wgsl, sm_4_0_version)] @@ -6003,6 +6205,8 @@ matrix<T,N,M> abs(matrix<T,N,M> x) } } +/// Absolute value (HLSL SM 1.0) +/// @category math __generic<T : __BuiltinFloatingPointType> [__readNone] [ForceInline] @@ -6032,8 +6236,8 @@ vector<T, N> fabs(vector<T, N> x) } -// Inverse cosine (HLSL SM 1.0) - +/// Inverse cosine (HLSL SM 1.0) +/// @category math __generic<T : __BuiltinFloatingPointType> [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv_wgsl, sm_4_0_version)] @@ -6085,8 +6289,8 @@ matrix<T, N, M> acos(matrix<T, N, M> x) } } -// Inverse hyperbolic cosine - +/// Inverse hyperbolic cosine +/// @category math __generic<T : __BuiltinFloatingPointType> [__readNone] [ForceInline] @@ -6228,7 +6432,8 @@ bool all(matrix<T,N,M> x) } } -// Barrier for writes to all memory spaces (HLSL SM 5.0) +/// Barrier for writes to all memory spaces (HLSL SM 5.0) +/// @category barrier Memory and control barriers __glsl_extension(GL_KHR_memory_scope_semantics) [require(cuda_glsl_hlsl_metal_spirv_wgsl, memorybarrier)] void AllMemoryBarrier() @@ -6247,7 +6452,8 @@ void AllMemoryBarrier() } } -// Thread-group sync and barrier for writes to all memory spaces (HLSL SM 5.0) +/// Thread-group sync and barrier for writes to all memory spaces (HLSL SM 5.0) +/// @category barrier __glsl_extension(GL_KHR_memory_scope_semantics) [require(cuda_glsl_hlsl_metal_spirv_wgsl, memorybarrier)] void AllMemoryBarrierWithGroupSync() @@ -6372,8 +6578,8 @@ bool any(matrix<T, N, M> x) } -// Reinterpret bits as a double (HLSL SM 5.0) - +/// Reinterpret bits as a double (HLSL SM 5.0) +/// @category conversion __glsl_extension(GL_ARB_gpu_shader5) [__readNone] [require(cpp_cuda_glsl_hlsl_spirv, shader5_sm_5_0)] @@ -6406,8 +6612,8 @@ double2 asdouble(uint2 lowbits, uint2 highbits) } } -// Reinterpret bits as a float (HLSL SM 4.0) - +/// Reinterpret bits as a float (HLSL SM 4.0) +/// @category conversion [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv_wgsl, shader5_sm_4_0)] float asfloat(int x) @@ -6508,7 +6714,6 @@ matrix<float,N,M> asfloat(matrix<uint,N,M> x) } } -// No op [__unsafeForceInlineEarly] [__readNone] float asfloat(float x) @@ -6526,7 +6731,8 @@ __generic<let N : int, let M : int> matrix<float,N,M> asfloat(matrix<float,N,M> x) { return x; } -// Inverse sine (HLSL SM 1.0) +/// Inverse sine (HLSL SM 1.0) +/// @category math __generic<T : __BuiltinFloatingPointType> [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv_wgsl, sm_4_0_version)] @@ -6578,8 +6784,8 @@ matrix<T, N, M> asin(matrix<T, N, M> x) } } -// Inverse hyperbolic sine - +/// Inverse hyperbolic sine. +/// @category math __generic<T : __BuiltinFloatingPointType> [__readNone] [ForceInline] @@ -6620,8 +6826,8 @@ vector<T,N> asinh(vector<T,N> x) } } -// Reinterpret bits as an int (HLSL SM 4.0) - +/// Reinterpret bits as an int (HLSL SM 4.0) +/// @category conversion [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv_wgsl, shader5_sm_4_0)] int asint(float x) @@ -6742,8 +6948,8 @@ __generic<let N : int, let M : int> matrix<int,N,M> asint(matrix<int,N,M> x) { return x; } -// Reinterpret bits of double as a uint (HLSL SM 5.0) - +/// Reinterpret bits of double as a uint (HLSL SM 5.0) +/// @category conversion __glsl_extension(GL_ARB_gpu_shader5) [__readNone] [require(cpp_cuda_glsl_hlsl_spirv, shader5_sm_4_0)] @@ -6897,14 +7103,20 @@ matrix<uint,N,M> asuint(matrix<uint,N,M> x) // Identity cases: +/// Reinterpret bits as a float16 (HLSL SM 6.2). +/// @category conversion [__unsafeForceInlineEarly][__readNone] float16_t asfloat16(float16_t value) { return value; } [__unsafeForceInlineEarly][__readNone] vector<float16_t,N> asfloat16<let N : int>(vector<float16_t,N> value) { return value; } [__unsafeForceInlineEarly][__readNone] matrix<float16_t,R,C> asfloat16<let R : int, let C : int>(matrix<float16_t,R,C> value) { return value; } +/// Reinterpret bits as a int16_t (HLSL SM 6.2). +/// @category conversion [__unsafeForceInlineEarly][__readNone] int16_t asint16(int16_t value) { return value; } [__unsafeForceInlineEarly][__readNone] vector<int16_t,N> asint16<let N : int>(vector<int16_t,N> value) { return value; } [__unsafeForceInlineEarly][__readNone] matrix<int16_t,R,C> asint16<let R : int, let C : int>(matrix<int16_t,R,C> value) { return value; } +/// Reinterpret bits as a uint16_t (HLSL SM 6.2). +/// @category conversion [__unsafeForceInlineEarly][__readNone] uint16_t asuint16(uint16_t value) { return value; } [__unsafeForceInlineEarly][__readNone] vector<uint16_t,N> asuint16<let N : int>(vector<uint16_t,N> value) { return value; } [__unsafeForceInlineEarly][__readNone] matrix<uint16_t,R,C> asuint16<let R : int, let C : int>(matrix<uint16_t,R,C> value) { return value; } @@ -7081,7 +7293,8 @@ matrix<float16_t,R,C> asfloat16<let R : int, let C : int>(matrix<int16_t,R,C> va } } -// Inverse tangent (HLSL SM 1.0) +/// Inverse tangent (HLSL SM 1.0). +/// @category math __generic<T : __BuiltinFloatingPointType> [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv_wgsl, sm_4_0_version)] @@ -7133,6 +7346,8 @@ matrix<T, N, M> atan(matrix<T, N, M> x) } } +/// Inverse tangent (HLSL SM 1.0). +/// @category math __generic<T : __BuiltinFloatingPointType> [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv_wgsl, sm_4_0_version)] @@ -7184,8 +7399,8 @@ matrix<T,N,M> atan2(matrix<T,N,M> y, matrix<T,N,M> x) } } -// Hyperbolic inverse tangent - +/// Hyperbolic inverse tangent +/// @category math __generic<T : __BuiltinFloatingPointType> [__readNone] [ForceInline] @@ -7226,7 +7441,8 @@ vector<T,N> atanh(vector<T,N> x) } } -// Ceiling (HLSL SM 1.0) +/// Ceiling (HLSL SM 1.0). +/// @category math __generic<T : __BuiltinFloatingPointType> [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv_wgsl, sm_4_0_version)] @@ -7279,7 +7495,7 @@ matrix<T, N, M> ceil(matrix<T, N, M> x) } // Copy-sign - +/// @category math __generic<let N: int> [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv)] @@ -7292,6 +7508,7 @@ vector<half,N> copysign_half(vector<half,N> x, vector<half,N> y) return reinterpret<vector<half,N>>(newX); } +/// @category math __generic<let N: int> [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv)] @@ -7304,6 +7521,7 @@ vector<float,N> copysign_float(vector<float,N> x, vector<float,N> y) return reinterpret<vector<float,N>>(newX); } +/// @category math __generic<let N: int> [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv)] @@ -7320,6 +7538,7 @@ __generic<T:__BuiltinFloatingPointType, U:__BuiltinFloatingPointType, let N : in __intrinsic_op($(kIROp_FloatCast)) vector<T,N> __real_cast(vector<U,N> val); +/// @category math __generic<T : __BuiltinFloatingPointType, let N: int> [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv)] @@ -7371,7 +7590,8 @@ bool CheckAccessFullyMapped(out uint status) } } -// Clamp (HLSL SM 1.0) +/// Clamp (HLSL SM 1.0). +/// @category math __generic<T : __BuiltinIntegerType> [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv_wgsl, sm_4_0_version)] @@ -7486,7 +7706,7 @@ matrix<T,N,M> clamp(matrix<T,N,M> x, matrix<T,N,M> minBound, matrix<T,N,M> maxBo } } -// Clip (discard) fragment conditionally +/// Clip (discard) fragment conditionally __generic<T : __BuiltinFloatingPointType> [require(cpp_cuda_glsl_hlsl_spirv, fragment)] void clip(T x) @@ -7523,7 +7743,7 @@ void clip(matrix<T,N,M> x) } } -// Cosine +/// @category math __generic<T : __BuiltinFloatingPointType> [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv_wgsl, sm_4_0_version)] @@ -7575,7 +7795,8 @@ matrix<T, N, M> cos(matrix<T, N, M> x) } } -// Hyperbolic cosine +/// Hyperbolic cosine. +/// @category math __generic<T : __BuiltinFloatingPointType> [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv_wgsl, sm_4_0_version)] @@ -7627,8 +7848,8 @@ matrix<T, N, M> cosh(matrix<T, N, M> x) } } -// Cosine degree - +/// Compute the cosine of an angle in degrees. +/// @category math __generic<T : __BuiltinFloatingPointType> [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv_wgsl, sm_4_0_version)] @@ -7656,7 +7877,8 @@ vector<T,N> cospi(vector<T,N> x) } -// Population count +/// Population count. +/// @category bitops [__readNone] [ForceInline] [require(cpp_cuda_glsl_hlsl_metal_spirv_wgsl, shader5_sm_5_0)] @@ -7703,13 +7925,14 @@ vector<uint, N> countbits(vector<uint, N> value) } } -// Cross product -// TODO: SPIRV does not support integer vectors. +/// Cross product +/// @category math __generic<T : __BuiltinFloatingPointType> [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv_wgsl, sm_4_0_version)] vector<T,3> cross(vector<T,3> left, vector<T,3> right) { + // TODO: SPIRV does not support integer vectors. __target_switch { case glsl: __intrinsic_asm "cross"; @@ -7768,6 +7991,7 @@ ${{{{ const char* diffDimensions[2] = {"x", "y"}; for (auto xOrY : diffDimensions) { }}}} +/// @category derivative Derivative functions __generic<T : __BuiltinFloatingPointType> [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv_wgsl, fragmentprocessing)] @@ -7829,6 +8053,7 @@ matrix<T, N, M> dd$(xOrY)(matrix<T, N, M> x) } } +/// @category derivative __generic<T : __BuiltinFloatingPointType> __glsl_extension(GL_ARB_derivative_control) [__readNone] @@ -7874,6 +8099,7 @@ matrix<T, N, M> dd$(xOrY)_coarse(matrix<T, N, M> x) } } +/// @category derivative __generic<T : __BuiltinFloatingPointType> __glsl_extension(GL_ARB_derivative_control) [__readNone] @@ -7924,8 +8150,8 @@ ${{{{ }}}} -// Radians to degrees - +/// Convert radians to degrees. +/// @category math __generic<T : __BuiltinFloatingPointType> [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv_wgsl)] @@ -7975,8 +8201,8 @@ matrix<T, N, M> degrees(matrix<T, N, M> x) } } -// Matrix determinant - +/// Compute matrix determinant. +/// @category math __generic<T : __BuiltinFloatingPointType, let N : int> [__readNone] [PreferCheckpoint] @@ -7995,7 +8221,8 @@ T determinant(matrix<T,N,N> m) } } -// Barrier for device memory +/// Barrier for device memory. +/// @category barrier __glsl_extension(GL_KHR_memory_scope_semantics) [require(cuda_glsl_hlsl_metal_spirv_wgsl, memorybarrier)] void DeviceMemoryBarrier() @@ -8014,6 +8241,8 @@ void DeviceMemoryBarrier() } } +/// @category barrier +/// Barrier for device memory with group synchronization. __glsl_extension(GL_KHR_memory_scope_semantics) [require(cuda_glsl_hlsl_metal_spirv_wgsl, memorybarrier)] void DeviceMemoryBarrierWithGroupSync() @@ -8033,7 +8262,7 @@ void DeviceMemoryBarrierWithGroupSync() } // Vector distance - +/// @category math __generic<T : __BuiltinFloatingPointType, let N : int> [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv_wgsl, sm_4_0_version)] @@ -8070,8 +8299,8 @@ T distance(T x, T y) } } -// fdim - +/// Computes `max(0, x-y)`. +/// @category math __generic<T : __BuiltinFloatingPointType> [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv, sm_4_0_version)] @@ -8099,7 +8328,7 @@ vector<T,N> fdim(vector<T,N> x, vector<T,N> y) } // divide - +/// @category math __generic<T : __BuiltinFloatingPointType> [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv)] @@ -8126,9 +8355,8 @@ vector<T,N> divide(vector<T,N> x, vector<T,N> y) } } - -// Vector dot product - +/// Vector dot product +/// @category math __generic<T : __BuiltinFloatingPointType> [__readNone] [ForceInline] @@ -8184,9 +8412,9 @@ T dot(vector<T, N> x, vector<T, N> y) } } - -// Helper for computing distance terms for lighting (obsolete) - +/// Helper for computing distance terms for lighting (obsolete) +/// @category math +/// @deprecated __generic<T : __BuiltinFloatingPointType> vector<T,4> dst(vector<T,4> x, vector<T,4> y); // Given a RWByteAddressBuffer allow it to be interpreted as a RWStructuredBuffer @@ -8356,8 +8584,8 @@ matrix<T,N,M> EvaluateAttributeSnapped(matrix<T,N,M> x, int2 offset) } } -// Base-e exponent - +/// Computes base-e exponent. +/// @category math __generic<T : __BuiltinFloatingPointType> [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv_wgsl, sm_4_0_version)] @@ -8377,6 +8605,7 @@ T exp(T x) } } +/// @category math __generic<T : __BuiltinFloatingPointType, let N : int> [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv_wgsl, sm_4_0_version)] @@ -8396,6 +8625,7 @@ vector<T, N> exp(vector<T, N> x) } } +/// @category math __generic<T : __BuiltinFloatingPointType, let N : int, let M : int> [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv_wgsl, sm_4_0_version)] @@ -8409,8 +8639,8 @@ matrix<T, N, M> exp(matrix<T, N, M> x) } } -// Base-2 exponent - +/// Computes base-2 exponent +/// @category math __generic<T : __BuiltinFloatingPointType> [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv_wgsl, sm_4_0_version)] @@ -8478,8 +8708,8 @@ matrix<T,N,M> exp2(matrix<T,N,M> x) } } -// Base-10 exponent - +/// Computes base-10 exponent +/// @category math __generic<T : __BuiltinFloatingPointType> [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv_wgsl, sm_4_0_version)] @@ -8509,7 +8739,8 @@ vector<T,N> exp10(vector<T,N> x) } -// Convert 16-bit float stored in low bits of integer +/// Convert 16-bit float stored in low bits of integer +/// @category conversion Conversion functions __glsl_version(420) __cuda_sm_version(6.0) [__readNone] @@ -8556,9 +8787,8 @@ vector<float, N> f16tof32(vector<uint, N> value) } } - - -// Convert to 16-bit float stored in low bits of integer +/// Convert to 16-bit float stored in low bits of integer. +/// @category conversion __glsl_version(420) __cuda_sm_version(6.0) [__readNone] @@ -8650,7 +8880,8 @@ vector<float, N> f16tof32(vector<float16_t, N> value) } } -// Convert to float16_t +/// Convert to float16_t. +/// @category conversion __glsl_version(420) [__readNone] [require(cuda_glsl_metal_spirv_wgsl, shader5_sm_5_0)] @@ -8687,7 +8918,8 @@ vector<float16_t, N> f32tof16_(vector<float, N> value) // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -// Flip surface normal to face forward, if needed +/// Flip surface normal to face forward, if needed. +/// @category math __generic<T : __BuiltinFloatingPointType, let N : int> [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv_wgsl, sm_4_0_version)] @@ -8707,7 +8939,8 @@ vector<T,N> faceforward(vector<T,N> n, vector<T,N> i, vector<T,N> ng) } } -// Find first set bit starting at high bit and working down +/// Find first set bit starting at high bit and working down. +/// @category bitops Bit operation functions [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv_wgsl, shader5_sm_5_0)] int firstbithigh(int value) @@ -8782,7 +9015,8 @@ vector<uint,N> firstbithigh(vector<uint,N> value) } } -// Find first set bit starting at low bit and working up +/// Find first set bit starting at low bit and working up. +/// @category bitops [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv_wgsl, shader5_sm_5_0)] int firstbitlow(int value) @@ -8857,8 +9091,8 @@ vector<uint,N> firstbitlow(vector<uint,N> value) } } -// Floor (HLSL SM 1.0) - +/// Floor (HLSL SM 1.0). +/// @category math __generic<T : __BuiltinFloatingPointType> [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv_wgsl, sm_4_0_version)] @@ -8910,7 +9144,8 @@ matrix<T, N, M> floor(matrix<T, N, M> x) } } -// Fused multiply-add +/// Fused multiply-add. +/// @category math __generic<T : __BuiltinFloatingPointType> [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv_wgsl, shader5_sm_5_0)] @@ -8968,7 +9203,11 @@ matrix<T, N, M> fma(matrix<T, N, M> a, matrix<T, N, M> b, matrix<T, N, M> c) } } -// Floating point remainder of x/y +/// Floating point remainder of x/y. +/// The floating-point remainder is calculated such that x = i * y + f, +/// where i is an integer, f has the same sign as x, and the absolute value +/// of f is less than the absolute value of y. +/// @category math __generic<T : __BuiltinFloatingPointType> [__readNone] [ForceInline] @@ -9073,7 +9312,8 @@ matrix<T, N, M> fmod(matrix<T, N, M> x, matrix<T, N, M> y) } } -// Fractional part +/// Extract the fractional part of a floating-point number. +/// @category math __generic<T : __BuiltinFloatingPointType> [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv_wgsl, sm_4_0_version)] @@ -9119,6 +9359,8 @@ matrix<T, N, M> frac(matrix<T, N, M> x) MATRIX_MAP_UNARY(T, N, M, frac, x); } +/// Extract the fractional part of a floating-point number. +/// @category math __generic<T : __BuiltinFloatingPointType> [__readNone] [ForceInline] @@ -9137,8 +9379,8 @@ vector<T, N> fract(vector<T, N> x) return frac(x); } - -// Split float into mantissa and exponent +/// Split float into mantissa and exponent. +/// @category math __generic<T : __BuiltinFloatingPointType> [__readNone] [ForceInline] @@ -9217,7 +9459,8 @@ matrix<T, N, M> frexp(matrix<T, N, M> x, out matrix<int, N, M, L> exp) } } -// Texture filter width +/// Texture filter width. +/// @category derivative __generic<T : __BuiltinFloatingPointType> [__readNone] [require(glsl_hlsl_metal_spirv_wgsl, fragmentprocessing)] @@ -9406,7 +9649,8 @@ float2 GetRenderTargetSamplePosition(int Index) } } -// Group memory barrier +/// Group memory barrier. Ensures that all memory accesses in the group are visible to all threads in the group. +/// @category barrier __glsl_extension(GL_KHR_memory_scope_semantics) [require(cuda_glsl_hlsl_metal_spirv_wgsl, memorybarrier)] void GroupMemoryBarrier() @@ -9443,6 +9687,8 @@ void __subgroupBarrier() } } +/// Group memory barrier. Ensures that all memory accesses in the group are visible to all threads in the group. +/// @category barrier __glsl_extension(GL_KHR_memory_scope_semantics) [require(cuda_glsl_hlsl_metal_spirv_wgsl, memorybarrier)] void GroupMemoryBarrierWithGroupSync() @@ -10018,6 +10264,7 @@ ${{{{ for(const char* T : {"int64_t", "uint64_t"}) { }}}} +/// @category atomic Atomic functions [ForceInline] [require(cuda_glsl_hlsl_spirv, atomic_glsl_hlsl_cuda_metal)] void InterlockedAdd(__ref $(T) dest, $(T) value) @@ -10058,6 +10305,7 @@ void InterlockedAdd(__ref $(T) dest, $(T) value, out $(T) original_value) } } +/// @category atomic [ForceInline] void InterlockedAnd(__ref $(T) dest, $(T) value) { @@ -10076,6 +10324,7 @@ void InterlockedAnd(__ref $(T) dest, $(T) value, out $(T) original_value) } } +/// @category atomic [ForceInline] void InterlockedCompareExchange(__ref $(T) dest, $(T) compare_value, $(T) value) { @@ -10103,6 +10352,7 @@ void InterlockedCompareStore(__ref $(T) dest, $(T) compare_value, $(T) value); } } +/// @category atomic [ForceInline] void InterlockedExchange(__ref $(T) dest, $(T) value) { @@ -10121,6 +10371,7 @@ void InterlockedExchange(__ref $(T) dest, $(T) value, out $(T) original_value) } } +/// @category atomic [ForceInline] void InterlockedMax(__ref $(T) dest, $(T) value) { @@ -10139,6 +10390,7 @@ void InterlockedMax(__ref $(T) dest, $(T) value, out $(T) original_value) } } +/// @category atomic [ForceInline] void InterlockedMin(__ref $(T) dest, $(T) value) { @@ -10157,6 +10409,7 @@ void InterlockedMin(__ref $(T) dest, $(T) value, out $(T) original_value) } } +/// @category atomic [ForceInline] void InterlockedOr(__ref $(T) dest, $(T) value) { @@ -10175,6 +10428,7 @@ void InterlockedOr(__ref $(T) dest, $(T) value, out $(T) original_value) } } +/// @category atomic [ForceInline] void InterlockedXor(__ref $(T) dest, $(T) value) { @@ -10197,6 +10451,7 @@ ${{{{ } // for(const char* T : {"int64_t", "uint64_t"}) }}}} +/// @category atomic [ForceInline] __glsl_version(430) [require(cuda_glsl_hlsl_metal_spirv, atomic_glsl_hlsl_cuda_metal)] @@ -10267,6 +10522,7 @@ void InterlockedCompareExchange(__ref uint dest, uint compare_value, uint value, } } +/// @category atomic [ForceInline] void InterlockedCompareExchangeFloatBitwise(__ref float dest, float compare_value, float value) { @@ -10295,6 +10551,7 @@ void InterlockedCompareExchangeFloatBitwise(__ref float dest, float compare_val } } +/// @category atomic [ForceInline] __glsl_version(430) [require(cuda_glsl_hlsl_metal_spirv, atomic_glsl_hlsl_cuda_metal)] @@ -10376,6 +10633,7 @@ void InterlockedCompareStore(__ref uint dest, uint compare_value, uint value) } } +/// @category atomic [ForceInline] void InterlockedCompareStoreFloatBitwise(__ref float dest, float compare_value, float value) { @@ -10385,7 +10643,7 @@ void InterlockedCompareStoreFloatBitwise(__ref float dest, float compare_value } } - +/// @category atomic [ForceInline] void InterlockedExchange(__ref float dest, float value) { @@ -10416,8 +10674,8 @@ void InterlockedExchange(__ref float dest, float value, out float original_va -// Is floating-point value finite? - +/// Test if a floating-point value finite. +/// @category math __generic<T : __BuiltinFloatingPointType> [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv, sm_4_0_version)] @@ -10467,7 +10725,8 @@ matrix<bool, N, M> isfinite(matrix<T, N, M> x) } } -// Is floating-point value infinite? +/// Test if a floating-point value infinite. +/// @category math __generic<T : __BuiltinFloatingPointType> [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv, sm_4_0_version)] @@ -10518,7 +10777,8 @@ matrix<bool, N, M> isinf(matrix<T, N, M> x) } } -// Is floating-point value not-a-number? +/// Test if a floating-point value is not-a-number. +/// @category math __generic<T : __BuiltinFloatingPointType> [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv, sm_4_0_version)] @@ -10569,8 +10829,8 @@ matrix<bool, N, M> isnan(matrix<T, N, M> x) } } -// Construct float from mantissa and exponent - +/// Construct float from mantissa and exponent. +/// @category math __generic<T : __BuiltinFloatingPointType> [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv_wgsl, sm_4_0_version)] @@ -10655,7 +10915,8 @@ vector<T, N> ldexp(vector<T, N> x, vector<E, N> exp) } -// Vector length +/// Compute the length of a vector. +/// @category math __generic<T : __BuiltinFloatingPointType, let N : int> [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv_wgsl, sm_4_0_version)] @@ -10675,7 +10936,6 @@ T length(vector<T, N> x) } } -// Scalar float length __generic<T : __BuiltinFloatingPointType> [require(cpp_cuda_glsl_hlsl_metal_spirv_wgsl, sm_4_0_version)] T length(T x) @@ -10692,7 +10952,9 @@ T length(T x) } } -// Linear interpolation +/// Computes linear interpolation. +/// @return Returns `x+(y-x)*s`. +/// @category math __generic<T : __BuiltinFloatingPointType> [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv, sm_4_0_version)] @@ -10743,6 +11005,8 @@ matrix<T,N,M> lerp(matrix<T,N,M> x, matrix<T,N,M> y, matrix<T,N,M> s) } // Legacy lighting function (obsolete) +/// @category math +/// @deprecated [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv, sm_4_0_version)] float4 lit(float n_dot_l, float n_dot_h, float m) @@ -10758,7 +11022,8 @@ float4 lit(float n_dot_l, float n_dot_h, float m) } } -// Base-e logarithm +/// Compute base-e logarithm. +/// @category math __generic<T : __BuiltinFloatingPointType> [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv_wgsl, sm_4_0_version)] @@ -10810,7 +11075,8 @@ matrix<T, N, M> log(matrix<T, N, M> x) } } -// Base-10 logarithm +/// Compute base-10 logarithm. +/// @category math __generic<T : __BuiltinFloatingPointType> [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv, sm_4_0_version)] @@ -10870,7 +11136,8 @@ matrix<T,N,M> log10(matrix<T,N,M> x) } } -// Base-2 logarithm +/// Compute base-2 logarithm. +/// @category math __generic<T : __BuiltinFloatingPointType> [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv_wgsl, sm_4_0_version)] @@ -10922,8 +11189,8 @@ matrix<T,N,M> log2(matrix<T,N,M> x) } } -// multiply-add - +/// Computes multiply-add. +/// @category math __generic<T : __BuiltinFloatingPointType> [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv, shader5_sm_5_0)] @@ -11020,8 +11287,8 @@ matrix<T, N, M> mad(matrix<T, N, M> mvalue, matrix<T, N, M> avalue, matrix<T, N, } } - // maximum +/// @category math __generic<T : __BuiltinIntegerType> [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv_wgsl, sm_4_0_version)] @@ -11058,6 +11325,7 @@ T max(T x, T y) } } +/// @category math __generic<T : __BuiltinIntegerType, let N : int> [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv_wgsl, sm_4_0_version)] @@ -11089,6 +11357,7 @@ vector<T, N> max(vector<T, N> x, vector<T, N> y) } } +/// @category math __generic<T : __BuiltinIntegerType, let N : int, let M : int> [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv_wgsl, sm_4_0_version)] @@ -11153,6 +11422,7 @@ matrix<T, N, M> max(matrix<T, N, M> x, matrix<T, N, M> y) } } +/// @category math __generic<T : __BuiltinFloatingPointType> [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv, sm_4_0_version)] @@ -11179,6 +11449,7 @@ vector<T,N> max3(vector<T,N> x, vector<T,N> y, vector<T,N> z) } } +/// @category math __generic<T : __BuiltinFloatingPointType> [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv, sm_4_0_version)] @@ -11206,6 +11477,7 @@ vector<T,N> fmax(vector<T,N> x, vector<T,N> y) } } +/// @category math __generic<T : __BuiltinFloatingPointType> [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv, sm_4_0_version)] @@ -11253,8 +11525,8 @@ vector<T,N> fmax3(vector<T,N> x, vector<T,N> y, vector<T,N> z) } } - // minimum +/// @category math __generic<T : __BuiltinIntegerType> [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv_wgsl, sm_4_0_version)] @@ -11388,6 +11660,7 @@ T min3(T x, T y, T z) } } +/// @category math __generic<T : __BuiltinFloatingPointType, let N : int> [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv, sm_4_0_version)] @@ -11401,6 +11674,7 @@ vector<T,N> min3(vector<T,N> x, vector<T,N> y, vector<T,N> z) } } +/// @category math __generic<T : __BuiltinFloatingPointType> [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv, sm_4_0_version)] @@ -11428,7 +11702,7 @@ vector<T,N> fmin(vector<T,N> x, vector<T,N> y) } } - +/// @category math __generic<T : __BuiltinFloatingPointType> [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv, sm_4_0_version)] @@ -11476,8 +11750,8 @@ vector<T,N> fmin3(vector<T,N> x, vector<T,N> y, vector<T,N> z) } } - // Median +/// @category math __generic<T : __BuiltinFloatingPointType> [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv, sm_4_0_version)] @@ -11506,6 +11780,7 @@ T median3(T x, T y, T z) } } +/// @category math __generic<T : __BuiltinFloatingPointType, let N: int> [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv, sm_4_0_version)] @@ -11525,6 +11800,7 @@ vector<T,N> median3(vector<T,N> x, vector<T,N> y, vector<T,N> z) } } +/// @category math __generic<T : __BuiltinFloatingPointType> [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv, sm_4_0_version)] @@ -11567,8 +11843,8 @@ vector<T,N> fmedian3(vector<T,N> x, vector<T,N> y, vector<T,N> z) } } - -// split into integer and fractional parts (both with same sign) +/// Split into integer and fractional parts (both with same sign). +/// @category math __generic<T : __BuiltinFloatingPointType> [__readNone] [ForceInline] @@ -11648,6 +11924,7 @@ matrix<T,N,M> modf(matrix<T,N,M> x, out matrix<T,N,M,L> ip) } // msad4 (whatever that is) +/// @category math [__readNone] [require(cpp_cuda_glsl_hlsl_spirv, sm_4_0_version)] uint4 msad4(uint reference, uint2 source, uint4 accum) @@ -11674,6 +11951,7 @@ uint4 msad4(uint reference, uint2 source, uint4 accum) // General inner products // scalar-scalar +/// @category math __generic<T : __BuiltinArithmeticType> __intrinsic_op($(kIROp_Mul)) [__readNone] @@ -11707,6 +11985,7 @@ __intrinsic_op($(kIROp_Mul)) matrix<T, N, M> mul(T x, matrix<T, N, M> y); // vector-vector (dot product) +/// @category math __generic<T : __BuiltinFloatingPointType, let N : int> [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv_wgsl, sm_4_0_version)] @@ -12022,9 +12301,8 @@ vector<T,N> nextafter(vector<T,N> x, vector<T,N> y) } } - -// noise (deprecated) - +/// @deprecated +/// @category math [__readNone] [deprecated("Always returns 0")] float noise(float x) @@ -12084,6 +12362,7 @@ T NonUniformResourceIndex(T index); T NonUniformResourceIndex<T>(T value) { return value; } // Normalize a vector +/// @category math __generic<T : __BuiltinFloatingPointType, let N : int> [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv_wgsl, sm_4_0_version)] @@ -12123,6 +12402,7 @@ T normalize(T x) } // Raise to a power +/// @category math __generic<T : __BuiltinFloatingPointType> [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv_wgsl, sm_4_0_version)] @@ -12174,6 +12454,7 @@ matrix<T,N,M> pow(matrix<T,N,M> x, matrix<T,N,M> y) } } +/// @category math __generic<T : __BuiltinFloatingPointType> [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv_wgsl, sm_4_0_version)] @@ -12252,7 +12533,7 @@ ${{{{ }}}} // Tessellation factor fixup routines - +/// @category tessellation Tessellation functions [require(hlsl, sm_5_0)] void Process2DQuadTessFactorsAvg( in float4 RawEdgeFactors, @@ -12261,6 +12542,7 @@ void Process2DQuadTessFactorsAvg( out float2 RoundedInsideTessFactors, out float2 UnroundedInsideTessFactors); +/// @category tessellation [require(hlsl, sm_5_0)] void Process2DQuadTessFactorsMax( in float4 RawEdgeFactors, @@ -12269,6 +12551,7 @@ void Process2DQuadTessFactorsMax( out float2 RoundedInsideTessFactors, out float2 UnroundedInsideTessFactors); +/// @category tessellation [require(hlsl, sm_5_0)] void Process2DQuadTessFactorsMin( in float4 RawEdgeFactors, @@ -12277,6 +12560,7 @@ void Process2DQuadTessFactorsMin( out float2 RoundedInsideTessFactors, out float2 UnroundedInsideTessFactors); +/// @category tessellation [require(hlsl, sm_5_0)] void ProcessIsolineTessFactors( in float RawDetailFactor, @@ -12284,6 +12568,7 @@ void ProcessIsolineTessFactors( out float RoundedDetailFactor, out float RoundedDensityFactor); +/// @category tessellation [require(hlsl, sm_5_0)] void ProcessQuadTessFactorsAvg( in float4 RawEdgeFactors, @@ -12292,6 +12577,7 @@ void ProcessQuadTessFactorsAvg( out float2 RoundedInsideTessFactors, out float2 UnroundedInsideTessFactors); +/// @category tessellation [require(hlsl, sm_5_0)] void ProcessQuadTessFactorsMax( in float4 RawEdgeFactors, @@ -12300,6 +12586,7 @@ void ProcessQuadTessFactorsMax( out float2 RoundedInsideTessFactors, out float2 UnroundedInsideTessFactors); +/// @category tessellation [require(hlsl, sm_5_0)] void ProcessQuadTessFactorsMin( in float4 RawEdgeFactors, @@ -12308,6 +12595,7 @@ void ProcessQuadTessFactorsMin( out float2 RoundedInsideTessFactors, out float2 UnroundedInsideTessFactors); +/// @category tessellation [require(hlsl, sm_5_0)] void ProcessTriTessFactorsAvg( in float3 RawEdgeFactors, @@ -12316,6 +12604,7 @@ void ProcessTriTessFactorsAvg( out float RoundedInsideTessFactor, out float UnroundedInsideTessFactor); +/// @category tessellation [require(hlsl, sm_5_0)] void ProcessTriTessFactorsMax( in float3 RawEdgeFactors, @@ -12324,6 +12613,7 @@ void ProcessTriTessFactorsMax( out float RoundedInsideTessFactor, out float UnroundedInsideTessFactor); +/// @category tessellation [require(hlsl, sm_5_0)] void ProcessTriTessFactorsMin( in float3 RawEdgeFactors, @@ -12332,7 +12622,8 @@ void ProcessTriTessFactorsMin( out float RoundedInsideTessFactors, out float UnroundedInsideTessFactors); -// Degrees to radians +/// Convert degrees to radians. +/// @category math __generic<T : __BuiltinFloatingPointType> [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv_wgsl, sm_4_0_version)] @@ -12382,7 +12673,8 @@ matrix<T, N, M> radians(matrix<T, N, M> x) } } -// Approximate reciprocal +/// Compute approximate reciprocal of `x`. +/// @category math __generic<T : __BuiltinFloatingPointType> [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv_wgsl, sm_4_0_version)] @@ -12426,7 +12718,8 @@ matrix<T, N, M> rcp(matrix<T, N, M> x) } } -// Reflect incident vector across plane with given normal +/// Reflect incident vector across plane with given normal. +/// @category math __generic<T : __BuiltinFloatingPointType> [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv_wgsl, sm_4_0_version)] @@ -12465,7 +12758,8 @@ vector<T,N> reflect(vector<T,N> i, vector<T,N> n) } } -// Refract incident vector given surface normal and index of refraction +/// Refract incident vector given surface normal and index of refraction. +/// @category math __generic<T : __BuiltinFloatingPointType, let N : int> [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv_wgsl, sm_4_0_version)] @@ -12510,7 +12804,8 @@ T refract(T i, T n, T eta) } } -// Reverse order of bits +/// Reverse order of bits. +/// @category bitops [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv_wgsl, shader5_sm_5_0)] uint reversebits(uint value) @@ -12551,7 +12846,8 @@ vector<uint, N> reversebits(vector<uint, N> value) } } -// round even +/// Round even. +/// @category math __generic<T : __BuiltinFloatingPointType> [__readNone] [ForceInline] @@ -12601,7 +12897,8 @@ vector<T,N> rint(vector<T,N> x) } } -// Round-to-nearest +/// Round-to-nearest. +/// @category math __generic<T : __BuiltinFloatingPointType> [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv_wgsl, sm_4_0_version)] @@ -12653,7 +12950,8 @@ matrix<T,N,M> round(matrix<T,N,M> x) } } -// Reciprocal of square root +/// Reciprocal of square root. +/// @category math __generic<T : __BuiltinFloatingPointType> [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv_wgsl, sm_4_0_version)] @@ -12705,8 +13003,8 @@ matrix<T, N, M> rsqrt(matrix<T, N, M> x) } } -// Clamp value to [0,1] range - +/// Clamp value to [0,1] range. +/// @category math __generic<T : __BuiltinFloatingPointType> [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv_wgsl, sm_4_0_version)] @@ -12760,7 +13058,8 @@ __generic<T:__BuiltinArithmeticType, U:__BuiltinArithmeticType, let N : int> __intrinsic_op($(kIROp_IntCast)) vector<T,N> __int_cast(vector<U,N> val); -// Extract sign of value +/// Extract sign of value. +/// @category math Math functions __generic<T : __BuiltinSignedArithmeticType> [__readNone] int sign(T x) @@ -12826,7 +13125,7 @@ matrix<int, N, M> sign(matrix<T, N, M> x) } // Sine - +/// @category math __generic<T : __BuiltinFloatingPointType> [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv_wgsl, sm_4_0_version)] @@ -12901,6 +13200,7 @@ vector<T,N> __sincos_metal(vector<T,N> x, out vector<T,N> c) } } +/// @category math __generic<T : __BuiltinFloatingPointType> [__readNone] [ForceInline] @@ -12955,7 +13255,8 @@ void sincos(matrix<T,N,M> x, out matrix<T,N,M,L1> s, out matrix<T,N,M,L2> c) } } -// Hyperbolic Sine +/// Hyperbolic sine. +/// @category math __generic<T : __BuiltinFloatingPointType> [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv_wgsl, sm_4_0_version)] @@ -13007,8 +13308,8 @@ matrix<T, N, M> sinh(matrix<T, N, M> x) } } -// Sine degree - +/// Compute the sine of an angle in degrees. +/// @category math __generic<T : __BuiltinFloatingPointType> [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv_wgsl, sm_4_0_version)] @@ -13036,7 +13337,8 @@ vector<T,N> sinpi(vector<T,N> x) } -// Smooth step (Hermite interpolation) +/// Smooth step (Hermite interpolation). +/// @category math __generic<T : __BuiltinFloatingPointType> [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv_wgsl, sm_4_0_version)] @@ -13089,7 +13391,8 @@ matrix<T, N, M> smoothstep(matrix<T, N, M> min, matrix<T, N, M> max, matrix<T, N } } -// Square root +/// Compute the square root of `x`. +/// @category math __generic<T : __BuiltinFloatingPointType> [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv_wgsl, sm_4_0_version)] @@ -13141,7 +13444,8 @@ matrix<T, N, M> sqrt(matrix<T, N, M> x) } } -// Step function +/// Step function. +/// @category math __generic<T : __BuiltinFloatingPointType> [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv_wgsl, sm_4_0_version)] @@ -13193,7 +13497,8 @@ matrix<T, N, M> step(matrix<T, N, M> y, matrix<T, N, M> x) } } -// Tangent +/// Compute the tangent of `x`. +/// @category math __generic<T : __BuiltinFloatingPointType> [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv_wgsl, sm_4_0_version)] @@ -13245,7 +13550,8 @@ matrix<T, N, M> tan(matrix<T, N, M> x) } } -// Hyperbolic tangent +/// Compute the hyperbolic tangent of `x`. +/// @category math __generic<T : __BuiltinFloatingPointType> [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv_wgsl, sm_4_0_version)] @@ -13297,8 +13603,8 @@ matrix<T,N,M> tanh(matrix<T,N,M> x) } } -// Tangent degree - +/// Compute the tangent of `x` in degrees. +/// @category math __generic<T : __BuiltinFloatingPointType> [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv_wgsl, sm_4_0_version)] @@ -13326,7 +13632,8 @@ vector<T,N> tanpi(vector<T,N> x) } -// Matrix transpose +/// Matrix transpose. +/// @category math __generic<T : __BuiltinFloatingPointType, let N : int, let M : int> [__readNone] [require(cpp_cuda_glsl_hlsl_spirv_wgsl, sm_4_0_version)] @@ -13395,7 +13702,8 @@ matrix<T, M, N> transpose(matrix<T, N, M> x) } } -// Truncate to integer +/// Truncate to integer. +/// @category math __generic<T : __BuiltinFloatingPointType> [__readNone] [require(cpp_cuda_glsl_hlsl_metal_spirv_wgsl, sm_4_0_version)] @@ -13449,6 +13757,7 @@ matrix<T, N, M> trunc(matrix<T, N, M> x) // Slang Specific 'Mask' Wave Intrinsics +//@hidden: typedef uint WaveMask; __glsl_extension(GL_KHR_shader_subgroup_ballot) @@ -14653,11 +14962,14 @@ matrix<T,N,M> WaveMaskPrefixBitXor(WaveMask mask, matrix<T,N,M> expr) } } +//@public: + // Shader model 6.0 stuff // Information for GLSL wave/subgroup support // https://github.com/KhronosGroup/GLSL/blob/master/extensions/khr/GL_KHR_shader_subgroup.txt +/// @category wave __generic<T : __BuiltinType> __glsl_extension(GL_KHR_shader_subgroup_quad) __spirv_version(1.3) @@ -14698,7 +15010,7 @@ vector<T,N> QuadReadLaneAt(vector<T,N> sourceValue, uint quadLaneID) } __generic<T : __BuiltinType, let N : int, let M : int> matrix<T,N,M> QuadReadLaneAt(matrix<T,N,M> sourceValue, uint quadLaneID); - +/// @category wave __generic<T : __BuiltinType> __glsl_extension(GL_KHR_shader_subgroup_quad) __spirv_version(1.3) @@ -14742,6 +15054,7 @@ vector<T,N> QuadReadAcrossX(vector<T,N> localValue) } __generic<T : __BuiltinType, let N : int, let M : int> matrix<T,N,M> QuadReadAcrossX(matrix<T,N,M> localValue); +/// @category wave __generic<T : __BuiltinType> __glsl_extension(GL_KHR_shader_subgroup_quad) __spirv_version(1.3) @@ -14785,6 +15098,7 @@ vector<T,N> QuadReadAcrossY(vector<T,N> localValue) __generic<T : __BuiltinType, let N : int, let M : int> matrix<T,N,M> QuadReadAcrossY(matrix<T,N,M> localValue); +/// @category wave __generic<T : __BuiltinType> __glsl_extension(GL_KHR_shader_subgroup_quad) __spirv_version(1.3) @@ -14833,7 +15147,7 @@ struct WaveActiveBitOpEntry { const char* hlslName; const char* glslName; const const WaveActiveBitOpEntry kWaveActiveBitOpEntries[] = {{"BitAnd", "And", "BitwiseAnd"}, {"BitOr", "Or", "BitwiseOr"}, {"BitXor", "Xor", "BitwiseXor"}}; for (auto opName : kWaveActiveBitOpEntries) { }}}} - +/// @category wave Wave and quad functions __generic<T : __BuiltinIntegerType> __glsl_extension(GL_KHR_shader_subgroup_arithmetic) __spirv_version(1.3) @@ -14895,7 +15209,7 @@ ${{{{ const char* kWaveActiveMinMaxNames[] = {"Min", "Max"}; for (const char* opName : kWaveActiveMinMaxNames) { }}}} - +/// @category wave __generic<T : __BuiltinArithmeticType> __glsl_extension(GL_KHR_shader_subgroup_arithmetic) __spirv_version(1.3) @@ -14969,7 +15283,7 @@ struct WaveActiveProductSumEntry { const char* hlslName; const char* glslName; } const WaveActiveProductSumEntry kWaveActivProductSumNames[] = {{"Product", "Mul"}, {"Sum", "Add"}}; for (auto opName : kWaveActivProductSumNames) { }}}} - +/// @category wave __generic<T : __BuiltinArithmeticType> __glsl_extension(GL_KHR_shader_subgroup_arithmetic) __spirv_version(1.3) @@ -15055,7 +15369,7 @@ matrix<T, N, M> WaveActive$(opName.hlslName)(matrix<T, N, M> expr) ${{{{ } // WaveActiveProduct/WaveActiveProductSum. }}}} - +/// @category wave __generic<T : __BuiltinType> __glsl_extension(GL_KHR_shader_subgroup_vote) __spirv_version(1.3) @@ -15114,6 +15428,7 @@ bool WaveActiveAllEqual(matrix<T, N, M> value) } } +/// @category wave __glsl_extension(GL_KHR_shader_subgroup_vote) __spirv_version(1.3) [require(cuda_glsl_hlsl_spirv, subgroup_vote)] @@ -15136,6 +15451,7 @@ bool WaveActiveAllTrue(bool condition) } } +/// @category wave __glsl_extension(GL_KHR_shader_subgroup_vote) __spirv_version(1.3) [require(cuda_glsl_hlsl_spirv, subgroup_vote)] @@ -15158,6 +15474,7 @@ bool WaveActiveAnyTrue(bool condition) } } +/// @category wave __glsl_extension(GL_KHR_shader_subgroup_ballot) __spirv_version(1.3) [NonUniformReturn] @@ -15181,6 +15498,7 @@ uint4 WaveActiveBallot(bool condition) } } +/// @category wave [require(cuda_glsl_hlsl_spirv, subgroup_basic_ballot)] uint WaveActiveCountBits(bool value) { @@ -15195,6 +15513,7 @@ uint WaveActiveCountBits(bool value) } } +/// @category wave __glsl_extension(GL_KHR_shader_subgroup_basic) __spirv_version(1.3) [NonUniformReturn] @@ -15215,6 +15534,7 @@ uint WaveGetLaneCount() } } +/// @category wave __glsl_extension(GL_KHR_shader_subgroup_basic) __spirv_version(1.3) [NonUniformReturn] @@ -15235,6 +15555,7 @@ uint WaveGetLaneIndex() } } +/// @category wave __glsl_extension(GL_KHR_shader_subgroup_basic) __spirv_version(1.3) [NonUniformReturn] @@ -15260,6 +15581,7 @@ bool WaveIsFirstLane() // It's useful to have a wave uint4 version of countbits, because some wave functions return uint4. // This implementation tries to limit the amount of work required by the actual lane count. +/// @category wave __spirv_version(1.3) [require(cpp_cuda_glsl_hlsl_spirv, subgroup_basic_ballot)] uint _WaveCountBits(uint4 value) @@ -15286,9 +15608,8 @@ uint _WaveCountBits(uint4 value) } } - // Prefix - +/// @category wave __generic<T : __BuiltinArithmeticType> __glsl_extension(GL_KHR_shader_subgroup_arithmetic) __spirv_version(1.3) @@ -15321,7 +15642,7 @@ T WavePrefixProduct(T expr) } } - +/// @category wave __generic<T : __BuiltinArithmeticType, let N : int> __glsl_extension(GL_KHR_shader_subgroup_arithmetic) __spirv_version(1.3) @@ -15350,7 +15671,7 @@ vector<T,N> WavePrefixProduct(vector<T,N> expr) return WaveMaskPrefixProduct(WaveGetActiveMask(), expr); } } - +/// @category wave __generic<T : __BuiltinArithmeticType, let N : int, let M : int> [require(cuda_glsl_hlsl_spirv, subgroup_arithmetic)] matrix<T, N, M> WavePrefixProduct(matrix<T, N, M> expr) @@ -15369,6 +15690,7 @@ matrix<T, N, M> WavePrefixProduct(matrix<T, N, M> expr) } } +/// @category wave __generic<T : __BuiltinArithmeticType> __glsl_extension(GL_KHR_shader_subgroup_arithmetic) __spirv_version(1.3) @@ -15445,6 +15767,7 @@ matrix<T,N,M> WavePrefixSum(matrix<T,N,M> expr) } } +/// @category wave __generic<T : __BuiltinType> __glsl_extension(GL_KHR_shader_subgroup_ballot) __spirv_version(1.3) @@ -15507,6 +15830,7 @@ matrix<T,N,M> WaveReadLaneFirst(matrix<T,N,M> expr) // https://github.com/KhronosGroup/GLSL/blob/master/extensions/khr/GL_KHR_shader_subgroup.txt // Versions SPIR-V greater than 1.4 loosen this restriction, and allow 'dynamic uniform' index // If that's the behavior required then client code should use WaveReadLaneAt which works this way. +/// @category wave __generic<T : __BuiltinType> __glsl_extension(GL_KHR_shader_subgroup_ballot) __spirv_version(1.3) @@ -15527,6 +15851,7 @@ T WaveBroadcastLaneAt(T value, constexpr int lane) } } +/// @category wave __generic<T : __BuiltinType, let N : int> __glsl_extension(GL_KHR_shader_subgroup_ballot) __spirv_version(1.3) @@ -15568,6 +15893,7 @@ matrix<T, N, M> WaveBroadcastLaneAt(matrix<T, N, M> value, constexpr int lane) // TODO(JS): If it can be determines that the `laneId` is constExpr, then subgroupBroadcast // could be used on GLSL. For now we just use subgroupShuffle +/// @category wave __generic<T : __BuiltinType> __glsl_extension(GL_KHR_shader_subgroup_shuffle) __spirv_version(1.3) @@ -15630,6 +15956,7 @@ matrix<T, N, M> WaveReadLaneAt(matrix<T, N, M> value, int lane) // NOTE! WaveShuffle is a NON STANDARD HLSL intrinsic! It will map to WaveReadLaneAt on HLSL // which means it will only work on hardware which allows arbitrary laneIds which is not true // in general because it breaks the HLSL standard, which requires it's 'dynamically uniform' across the Wave. +/// @category wave __generic<T : __BuiltinType> __glsl_extension(GL_KHR_shader_subgroup_shuffle) __spirv_version(1.3) @@ -15650,6 +15977,7 @@ T WaveShuffle(T value, int lane) } } +/// @category wave __generic<T : __BuiltinType, let N : int> __glsl_extension(GL_KHR_shader_subgroup_shuffle) __spirv_version(1.3) @@ -15682,6 +16010,7 @@ matrix<T, N, M> WaveShuffle(matrix<T, N, M> value, int lane) } } +/// @category wave __glsl_extension(GL_KHR_shader_subgroup_ballot) __spirv_version(1.3) [require(cuda_glsl_hlsl_spirv, subgroup_ballot)] @@ -15704,6 +16033,7 @@ uint WavePrefixCountBits(bool value) } } +/// @category wave __glsl_extension(GL_KHR_shader_subgroup_ballot) __spirv_version(1.3) [require(cuda_glsl_hlsl_spirv, subgroup_ballot)] @@ -15725,6 +16055,7 @@ uint4 WaveGetConvergedMulti() } } +/// @category wave [ForceInline] uint4 WaveGetActiveMulti() { @@ -15734,6 +16065,7 @@ uint4 WaveGetActiveMulti() // Shader model 6.5 stuff // https://github.com/microsoft/DirectX-Specs/blob/master/d3d/HLSL_ShaderModel6_5.md +/// @category wave __generic<T : __BuiltinType> [require(cuda_glsl_hlsl_spirv, subgroup_partitioned)] uint4 WaveMatch(T value) @@ -15794,6 +16126,7 @@ uint4 WaveMatch(matrix<T,N,M> value) } } +/// @category wave [require(cuda_hlsl, waveprefix)] uint WaveMultiPrefixCountBits(bool value, uint4 mask) { @@ -15804,6 +16137,7 @@ uint WaveMultiPrefixCountBits(bool value, uint4 mask) } } +/// @category wave __generic<T : __BuiltinArithmeticType> __glsl_extension(GL_KHR_shader_subgroup_arithmetic) __spirv_version(1.3) @@ -15843,6 +16177,7 @@ matrix<T,N,M> WaveMultiPrefixBitAnd(matrix<T,N,M> expr, uint4 mask) } } +/// @category wave __generic<T : __BuiltinArithmeticType> __glsl_extension(GL_KHR_shader_subgroup_arithmetic) __spirv_version(1.3) @@ -15882,6 +16217,7 @@ matrix<T,N,M> WaveMultiPrefixBitOr(matrix<T,N,M> expr, uint4 mask) } } +/// @category wave __generic<T : __BuiltinArithmeticType> __glsl_extension(GL_KHR_shader_subgroup_arithmetic) __spirv_version(1.3) @@ -15921,6 +16257,7 @@ matrix<T,N,M> WaveMultiPrefixBitXor(matrix<T,N,M> expr, uint4 mask) } } +/// @category wave __generic<T : __BuiltinArithmeticType> [require(cuda_hlsl, waveprefix)] T WaveMultiPrefixProduct(T value, uint4 mask) @@ -15954,6 +16291,7 @@ matrix<T,N,M> WaveMultiPrefixProduct(matrix<T,N,M> value, uint4 mask) } } +/// @category wave __generic<T : __BuiltinArithmeticType> [require(cuda_hlsl, waveprefix)] T WaveMultiPrefixSum(T value, uint4 mask) @@ -16006,7 +16344,9 @@ bool IsHelperLane() } // `typedef`s to help with the fact that HLSL has been sorta-kinda case insensitive at various points +//@hidden: typedef Texture2D texture2D; +//@public: ${{{{ @@ -16025,10 +16365,11 @@ static const int kBaseBufferAccessLevelCount = sizeof(kBaseBufferAccessLevels) / for (int aa = 0; aa < kBaseBufferAccessLevelCount; ++aa) { auto access = kBaseBufferAccessLevels[aa].access; + sb << "/// @category texture_types\n"; sb << "__generic<T,let format:int=0>\n"; sb << "typealias "; sb << kBaseBufferAccessLevels[aa].name; - sb << "Buffer = __TextureImpl<T, __ShapeBuffer, 0, 0, 0, " << aa << ", 0, 0, format>;\n"; + sb << "Buffer = _Texture<T, __ShapeBuffer, 0, 0, 0, " << aa << ", 0, 0, format>;\n"; bool isReadOnly = aa == 0; @@ -16041,7 +16382,7 @@ for (int aa = 0; aa < kBaseBufferAccessLevelCount; ++aa) }}}} __generic<T, let format:int> -extension __TextureImpl<T, __ShapeBuffer, 0, 0, 0, $(aa), 0, 0, format> +extension _Texture<T, __ShapeBuffer, 0, 0, 0, $(aa), 0, 0, format> { [__readNone] $(requireToSetQuery) @@ -16138,22 +16479,34 @@ ${{{{ // 10.1.1 - Ray Flags +/// @category raytracing Ray-tracing typedef uint RAY_FLAG; -static const RAY_FLAG RAY_FLAG_NONE = 0x00; -static const RAY_FLAG RAY_FLAG_FORCE_OPAQUE = 0x01; -static const RAY_FLAG RAY_FLAG_FORCE_NON_OPAQUE = 0x02; -static const RAY_FLAG RAY_FLAG_ACCEPT_FIRST_HIT_AND_END_SEARCH = 0x04; -static const RAY_FLAG RAY_FLAG_SKIP_CLOSEST_HIT_SHADER = 0x08; -static const RAY_FLAG RAY_FLAG_CULL_BACK_FACING_TRIANGLES = 0x10; -static const RAY_FLAG RAY_FLAG_CULL_FRONT_FACING_TRIANGLES = 0x20; -static const RAY_FLAG RAY_FLAG_CULL_OPAQUE = 0x40; -static const RAY_FLAG RAY_FLAG_CULL_NON_OPAQUE = 0x80; -static const RAY_FLAG RAY_FLAG_SKIP_TRIANGLES = 0x100; -static const RAY_FLAG RAY_FLAG_SKIP_PROCEDURAL_PRIMITIVES = 0x200; +/// @category raytracing +static const RAY_FLAG RAY_FLAG_NONE = 0x00; +/// @category raytracing +static const RAY_FLAG RAY_FLAG_FORCE_OPAQUE = 0x01; +/// @category raytracing +static const RAY_FLAG RAY_FLAG_FORCE_NON_OPAQUE = 0x02; +/// @category raytracing +static const RAY_FLAG RAY_FLAG_ACCEPT_FIRST_HIT_AND_END_SEARCH = 0x04; +/// @category raytracing +static const RAY_FLAG RAY_FLAG_SKIP_CLOSEST_HIT_SHADER = 0x08; +/// @category raytracing +static const RAY_FLAG RAY_FLAG_CULL_BACK_FACING_TRIANGLES = 0x10; +/// @category raytracing +static const RAY_FLAG RAY_FLAG_CULL_FRONT_FACING_TRIANGLES = 0x20; +/// @category raytracing +static const RAY_FLAG RAY_FLAG_CULL_OPAQUE = 0x40; +/// @category raytracing +static const RAY_FLAG RAY_FLAG_CULL_NON_OPAQUE = 0x80; +/// @category raytracing +static const RAY_FLAG RAY_FLAG_SKIP_TRIANGLES = 0x100; +/// @category raytracing +static const RAY_FLAG RAY_FLAG_SKIP_PROCEDURAL_PRIMITIVES = 0x200; // 10.1.2 - Ray Description Structure - +/// @category raytracing __target_intrinsic(hlsl, RayDesc) __target_intrinsic(cuda, RayDesc) struct RayDesc @@ -16176,7 +16529,7 @@ struct RayDesc }; // 10.1.3 - Ray Acceleration Structure - +/// @category raytracing __builtin __magic_type(RaytracingAccelerationStructureType) __intrinsic_type($(kIROp_RaytracingAccelerationStructureType)) @@ -16190,7 +16543,7 @@ struct RaytracingAccelerationStructure {}; // for this stuff comes across as a kludge rather than the best possible design. // 10.1.5 - Intersection Attributes Structure - +/// @category raytracing __target_intrinsic(hlsl, BuiltInTriangleIntersectionAttributes) [require(cpp_cuda_glsl_hlsl_spirv, raytracing)] struct BuiltInTriangleIntersectionAttributes @@ -16232,6 +16585,7 @@ int __callablePayloadLocation(__ref Payload payload); // targets, which maps the generic HLSL operation into the non-generic // GLSL equivalent. // +/// @category raytracing __generic<Payload> [require(glsl_hlsl_spirv, raytracing_raygen_closesthit_miss_callable)] void CallShader(uint shaderIndex, inout Payload payload) @@ -16322,6 +16676,7 @@ __generic<Payload> __intrinsic_op($(kIROp_GetVulkanRayTracingPayloadLocation)) int __rayPayloadLocation(__ref Payload payload); +/// @category raytracing [ForceInline] __generic<payload_t> [require(cuda_glsl_hlsl_spirv, raytracing_raygen_closesthit_miss)] @@ -16446,6 +16801,7 @@ void __traceMotionRay( } } +/// @category raytracing [ForceInline] [require(glsl_hlsl_spirv, raytracing_motionblur_raygen_closesthit_miss)] __generic<payload_t> @@ -16546,6 +16902,7 @@ bool __reportIntersection(float tHit, uint hitKind) } } +/// @category raytracing __generic<A> [ForceInline] [require(glsl_hlsl_spirv, raytracing_intersection)] @@ -16564,6 +16921,7 @@ bool ReportHit(float tHit, uint hitKind, A attributes) } } +/// @category raytracing __generic<each T : __BuiltinIntegerType> [ForceInline] [require(cuda_glsl_hlsl_spirv, raytracing_intersection)] @@ -16579,6 +16937,7 @@ bool ReportHitOptix(float tHit, uint hitKind, expand each T attribs) } // 10.3.4 +/// @category raytracing [require(cuda_glsl_hlsl_spirv, raytracing_anyhit)] void IgnoreHit() { @@ -16596,6 +16955,7 @@ void IgnoreHit() } // 10.3.5 +/// @category raytracing [require(cuda_glsl_hlsl_spirv, raytracing_anyhit)] void AcceptHitAndEndSearch() { @@ -16619,6 +16979,7 @@ void AcceptHitAndEndSearch() // 10.4.1 - Ray Dispatch System Values +/// @category raytracing [NonUniformReturn] [require(cuda_glsl_hlsl_spirv, raytracing_allstages)] uint3 DispatchRaysIndex() @@ -16636,6 +16997,7 @@ uint3 DispatchRaysIndex() } } +/// @category raytracing [require(cuda_glsl_hlsl_spirv, raytracing_allstages)] uint3 DispatchRaysDimensions() { @@ -16654,6 +17016,7 @@ uint3 DispatchRaysDimensions() // 10.4.2 - Ray System Values +/// @category raytracing [NonUniformReturn] [require(cuda_glsl_hlsl_spirv, raytracing_anyhit_closesthit_intersection_miss)] float3 WorldRayOrigin() @@ -16671,6 +17034,7 @@ float3 WorldRayOrigin() } } +/// @category raytracing [NonUniformReturn] [require(cuda_glsl_hlsl_spirv, raytracing_anyhit_closesthit_intersection_miss)] float3 WorldRayDirection() @@ -16688,6 +17052,7 @@ float3 WorldRayDirection() } } +/// @category raytracing [NonUniformReturn] [require(cuda_glsl_hlsl_spirv, raytracing_anyhit_closesthit_intersection_miss)] float RayTMin() @@ -16715,6 +17080,7 @@ float RayTMin() // we should simply provide two overloads here, specialized // to the appropriate Vulkan stages. // +/// @category raytracing [NonUniformReturn] [require(cuda_glsl_hlsl_spirv, raytracing_anyhit_closesthit_intersection_miss)] float RayTCurrent() @@ -16732,6 +17098,7 @@ float RayTCurrent() } } +/// @category raytracing [require(cuda_glsl_hlsl_spirv, raytracing_anyhit_closesthit_intersection_miss)] uint RayFlags() { @@ -16750,6 +17117,7 @@ uint RayFlags() // 10.4.3 - Primitive/Object Space System Values +/// @category raytracing [NonUniformReturn] [require(cuda_glsl_hlsl_spirv, raytracing_anyhit_closesthit_intersection)] uint InstanceIndex() @@ -16767,6 +17135,7 @@ uint InstanceIndex() } } +/// @category raytracing [NonUniformReturn] [require(cuda_glsl_hlsl_spirv, raytracing_anyhit_closesthit_intersection)] uint InstanceID() @@ -16784,6 +17153,7 @@ uint InstanceID() } } +/// @category raytracing [NonUniformReturn] [require(cuda_glsl_hlsl_spirv, raytracing_anyhit_closesthit_intersection)] uint PrimitiveIndex() @@ -16801,6 +17171,7 @@ uint PrimitiveIndex() } } +/// @category raytracing [NonUniformReturn] [require(cuda_glsl_hlsl_spirv, raytracing_anyhit_closesthit_intersection)] float3 ObjectRayOrigin() @@ -16818,6 +17189,7 @@ float3 ObjectRayOrigin() } } +/// @category raytracing [NonUniformReturn] [require(cuda_glsl_hlsl_spirv, raytracing_anyhit_closesthit_intersection)] float3 ObjectRayDirection() @@ -16837,6 +17209,7 @@ float3 ObjectRayDirection() // TODO: optix has an optixGetObjectToWorldTransformMatrix function that returns 12 // floats by reference. +/// @category raytracing [NonUniformReturn] [require(glsl_hlsl_spirv, raytracing_anyhit_closesthit_intersection)] float3x4 ObjectToWorld3x4() @@ -16854,6 +17227,7 @@ float3x4 ObjectToWorld3x4() } } +/// @category raytracing [NonUniformReturn] [require(glsl_hlsl_spirv, raytracing_anyhit_closesthit_intersection)] float3x4 WorldToObject3x4() @@ -16871,6 +17245,7 @@ float3x4 WorldToObject3x4() } } +/// @category raytracing [NonUniformReturn] [require(glsl_hlsl_spirv, raytracing_anyhit_closesthit_intersection)] float4x3 ObjectToWorld4x3() @@ -16887,6 +17262,7 @@ float4x3 ObjectToWorld4x3() } } +/// @category raytracing [NonUniformReturn] [require(glsl_hlsl_spirv, raytracing_anyhit_closesthit_intersection)] float4x3 WorldToObject4x3() @@ -16907,6 +17283,7 @@ float4x3 WorldToObject4x3() // The name of the following functions may change when DXR supports // a feature similar to the `GL_NV_ray_tracing_motion_blur` extension +/// @category raytracing __glsl_extension(GL_NV_ray_tracing_motion_blur) __glsl_extension(GL_EXT_ray_tracing) [NonUniformReturn] @@ -16934,10 +17311,13 @@ float RayCurrentTime() // declarations, so that users can know they aren't coding // against the final spec? // +/// @category raytracing [NonUniformReturn] float3x4 ObjectToWorld() { return ObjectToWorld3x4(); } +/// @category raytracing [NonUniformReturn] float3x4 WorldToObject() { return WorldToObject3x4(); } // 10.4.4 - Hit Specific System values +/// @category raytracing [NonUniformReturn] [require(cuda_glsl_hlsl_spirv, raytracing_anyhit_closesthit)] uint HitKind() @@ -16956,22 +17336,26 @@ uint HitKind() } // Pre-defined hit kinds (not documented explicitly) -static const uint HIT_KIND_TRIANGLE_FRONT_FACE = 254; +/// @category raytracing +static const uint HIT_KIND_TRIANGLE_FRONT_FACE = 254; +/// @category raytracing static const uint HIT_KIND_TRIANGLE_BACK_FACE = 255; // // Shader Model 6.4 // -// Treats `left` and `right` as 4-component vectors of `UInt8` and computes `dot(left, right) + acc` +/// Treats `left` and `right` as 4-component vectors of `UInt8` and computes `dot(left, right) + acc` +/// @category math uint dot4add_u8packed(uint left, uint right, uint acc); -// Treats `left` and `right` as 4-component vectors of `Int8` and computes `dot(left, right) + acc` +/// Treats `left` and `right` as 4-component vectors of `Int8` and computes `dot(left, right) + acc` +/// @category math int dot4add_i8packed(uint left, uint right, int acc); -// Computes `dot(left, right) + acc`. -// -// May not produce infinities or NaNs for intermediate results that overflow the range of `half` +/// Computes `dot(left, right) + acc`. +/// May not produce infinities or NaNs for intermediate results that overflow the range of `half` +/// @category math float dot2add(float2 left, float2 right, float acc); // @@ -16982,7 +17366,8 @@ float dot2add(float2 left, float2 right, float acc); // Mesh Shaders // -// Set the number of output vertices and primitives for a mesh shader invocation. +/// Set the number of output vertices and primitives for a mesh shader invocation. +/// @category meshshading Mesh shading __glsl_extension(GL_EXT_mesh_shader) __glsl_version(450) [require(glsl_hlsl_metal_spirv, meshshading)] @@ -17007,18 +17392,17 @@ void SetMeshOutputCounts(uint vertexCount, uint primitiveCount) } } -// Specify the number of downstream mesh shader thread groups to invoke from an amplification shader, -// and provide the values for per-mesh payload parameters. -// -// This function doesn't return. -// -// This function cannot be inlined due to a legalization pass happening mid-way through processing -// and later more processing happening to the function which requires eventual inlining. +/// Specify the number of downstream mesh shader thread groups to invoke from an amplification shader, +/// and provide the values for per-mesh payload parameters. +/// @return This function doesn't return. +/// @category meshshading [KnownBuiltin("DispatchMesh")] [require(glsl_hlsl_metal_spirv, meshshading)] [noRefInline] void DispatchMesh<P>(uint threadGroupCountX, uint threadGroupCountY, uint threadGroupCountZ, __ref P meshPayload) { + // This function cannot be inlined due to a legalization pass happening mid-way through processing + // and later more processing happening to the function which requires eventual inlining. __target_switch { case hlsl: @@ -17055,19 +17439,22 @@ void DispatchMesh<P>(uint threadGroupCountX, uint threadGroupCountY, uint thread [builtin] interface __BuiltinSamplerFeedbackType {}; +/// @category texture_types [sealed] __magic_type(FeedbackType, $(int(FeedbackType::Kind::MinMip))) __target_intrinsic(hlsl, SAMPLER_FEEDBACK_MIN_MIP) struct SAMPLER_FEEDBACK_MIN_MIP : __BuiltinSamplerFeedbackType {}; +/// @category texture_types [sealed] __magic_type(FeedbackType, $(int(FeedbackType::Kind::MipRegionUsed))) __target_intrinsic(hlsl, SAMPLER_FEEDBACK_MIP_REGION_USED) struct SAMPLER_FEEDBACK_MIP_REGION_USED : __BuiltinSamplerFeedbackType {}; // All of these objects are write-only resources that point to a special kind of unordered access view meant for sampler feedback. + __generic<T:__BuiltinSamplerFeedbackType> -extension __TextureImpl<T,__Shape2D, 0, 0, 0, $(kStdlibResourceAccessFeedback), 0, 0, 0> +extension _Texture<T,__Shape2D, 0, 0, 0, $(kStdlibResourceAccessFeedback), 0, 0, 0> { // With Clamp @@ -17147,7 +17534,7 @@ extension __TextureImpl<T,__Shape2D, 0, 0, 0, $(kStdlibResourceAccessFeedback), }; __generic<T:__BuiltinSamplerFeedbackType> -extension __TextureImpl<T,__Shape2D, 1, 0, 0, $(kStdlibResourceAccessFeedback), 0, 0, 0> +extension _Texture<T,__Shape2D, 1, 0, 0, $(kStdlibResourceAccessFeedback), 0, 0, 0> { // With Clamp @@ -17231,6 +17618,7 @@ extension __TextureImpl<T,__Shape2D, 1, 0, 0, $(kStdlibResourceAccessFeedback), // // Get the index of the geometry that was hit in an intersection, any-hit, or closest-hit shader +/// @category raytracing __glsl_extension(GL_EXT_ray_tracing) [NonUniformReturn] [require(glsl_hlsl_spirv, raytracing_anyhit_closesthit_intersection)] @@ -17246,8 +17634,9 @@ uint GeometryIndex() } } -// Get the vertex positions of the currently hit triangle in any-hit or closest-hit shader. -// https://github.com/KhronosGroup/GLSL/blob/master/extensions/ext/GLSL_EXT_ray_tracing_position_fetch.txt +/// Get the vertex positions of the currently hit triangle in any-hit or closest-hit shader. +/// https://github.com/KhronosGroup/GLSL/blob/master/extensions/ext/GLSL_EXT_ray_tracing_position_fetch.txt +/// @category raytracing __glsl_extension(GL_EXT_ray_tracing) __glsl_extension(GL_EXT_ray_tracing_position_fetch) [ForceInline] @@ -17271,71 +17660,73 @@ float3 HitTriangleVertexPosition(uint index) } } -// Status of whether a (closest) hit has been committed in a `RayQuery`. +/// Status of whether a (closest) hit has been committed in a `RayQuery`. +/// @category raytracing typedef uint COMMITTED_STATUS; -// No hit committed. +/// No hit committed. +/// @category raytracing static const COMMITTED_STATUS COMMITTED_NOTHING = 0; -// Closest hit is a triangle. -// -// This could be an opaque triangle hit found by the fixed-function -// traversal and intersection implementation, or a non-opaque -// triangle hit committed by user code with `RayQuery.CommitNonOpaqueTriangleHit` -// +/// Closest hit is a triangle. +/// This could be an opaque triangle hit found by the fixed-function +/// traversal and intersection implementation, or a non-opaque +/// triangle hit committed by user code with `RayQuery.CommitNonOpaqueTriangleHit` +/// @category raytracing static const COMMITTED_STATUS COMMITTED_TRIANGLE_HIT = 1; -// Closest hit is a procedural primitive. -// -// A procedural hit primitive is committed using `RayQuery.CommitProceduralPrimitiveHit`. +/// Closest hit is a procedural primitive. +/// A procedural hit primitive is committed using `RayQuery.CommitProceduralPrimitiveHit`. +/// @category raytracing static const COMMITTED_STATUS COMMITTED_PROCEDURAL_PRIMITIVE_HIT = 2; -// Type of candidate hit that a `RayQuery` is pausing at. -// -// A `RayQuery` can automatically commit hits with opaque triangles, -// but yields to user code for other hits to allow them to be -// dismissed or committed. -// +/// Type of candidate hit that a `RayQuery` is pausing at. +/// A `RayQuery` can automatically commit hits with opaque triangles, +/// but yields to user code for other hits to allow them to be +/// dismissed or committed. +/// @category raytracing typedef uint CANDIDATE_TYPE; -// Candidate hit is a non-opaque triangle. +/// Candidate hit is a non-opaque triangle. +/// @category raytracing static const CANDIDATE_TYPE CANDIDATE_NON_OPAQUE_TRIANGLE = 0; -// Candidate hit is a procedural primitive. +/// Candidate hit is a procedural primitive. +/// @category raytracing static const CANDIDATE_TYPE CANDIDATE_PROCEDURAL_PRIMITIVE = 1; -// Handle to state of an in-progress ray-tracing query. +/// Handle to state of an in-progress ray-tracing query. +/// The ray query is effectively a coroutine that user shader +/// code can resume to continue tracing the ray, and which yields +/// back to the user code at interesting events along the ray. // -// The ray query is effectively a coroutine that user shader -// code can resume to continue tracing the ray, and which yields -// back to the user code at interesting events along the ray. -// -// Note: The treatment of the `RayQuery` type in Slang does not -// perfectly match its semantics in vanilla HLSL in some corner -// cases. Specifically, a `RayQuery` in vanilla HLSL is an -// opaque handle to mutable storage, and assigning a `RayQuery` -// or passing one as a parameter will only copy the *handle*, -// potentially resulting in aliasing of the underlying mutable -// storage. -// -// In contrast, Slang considers a `RayQuery` to own its mutable -// state, and (because the API does not support cloning of queries), -// `RayQuery` values are non-copyable (aka "move-only"). -// -// The main place where this arises as a consideration is when -// passing a `RayQuery` down into a function that will perform -// mutating operations on it (e.g., `TraceRay` or `Proceed`): -// -// void myFunc( inout RayQuery<FLAGS> q ) -// { -// q.Proceed(); -// } -// -// In Slang, a parameter like `q` above should be declared `inout`. -// HLSL does not care about whether `q` is declared `inout` or not. -// -//cannot use a cap for struct with unequal target support -//since it will propegate rules to children +/// Note: The treatment of the `RayQuery` type in Slang does not +/// perfectly match its semantics in vanilla HLSL in some corner +/// cases. Specifically, a `RayQuery` in vanilla HLSL is an +/// opaque handle to mutable storage, and assigning a `RayQuery` +/// or passing one as a parameter will only copy the *handle*, +/// potentially resulting in aliasing of the underlying mutable +/// storage. +/// +/// In contrast, Slang considers a `RayQuery` to own its mutable +/// state, and (because the API does not support cloning of queries), +/// `RayQuery` values are non-copyable (aka "move-only"). +/// +/// The main place where this arises as a consideration is when +/// passing a `RayQuery` down into a function that will perform +/// mutating operations on it (e.g., `TraceRay` or `Proceed`): +/// ``` +/// void myFunc( inout RayQuery<FLAGS> q ) +/// { +/// q.Proceed(); +/// } +/// ``` +/// In Slang, a parameter like `q` above should be declared `inout`. +/// HLSL does not care about whether `q` is declared `inout` or not. +/// +///cannot use a cap for struct with unequal target support +///since it will propegate rules to children +/// @category raytracing Ray-tracing __glsl_extension(GL_EXT_ray_query) [__NonCopyableType] __intrinsic_type($(kIROp_RayQueryType)) @@ -18182,6 +18573,7 @@ ${{{{ // SubpassInput // +/// @category stage_io __magic_type(SubpassInputType) __intrinsic_type($(kIROp_SubpassInputType)) [require(glsl_hlsl_spirv, subpass)] @@ -18189,6 +18581,7 @@ struct __SubpassImpl<T, let isMS:int> { } +/// @category stage_io __generic<T = float4, let isMS:int=0> typealias SubpassInput = __SubpassImpl<T, isMS>; @@ -18216,6 +18609,7 @@ extension __SubpassImpl<T, 0> } } +/// @category stage_io __generic<T = float4, let isMS:int=1> typealias SubpassInputMS = __SubpassImpl<T, isMS>; @@ -18293,9 +18687,10 @@ __generic<Attributes> __intrinsic_op($(kIROp_GetVulkanRayTracingPayloadLocation)) int __hitObjectAttributesLocation(__ref Attributes attributes); - /// Immutable data type representing a ray hit or a miss. Can be used to invoke hit or miss shading, - /// or as a key in ReorderThread. Created by one of several methods described below. HitObject - /// and its related functions are available in raytracing shader types only. +/// Immutable data type representing a ray hit or a miss. Can be used to invoke hit or miss shading, +/// or as a key in ReorderThread. Created by one of several methods described below. HitObject +/// and its related functions are available in raytracing shader types only. +/// @category raytracing Ray-tracing __glsl_extension(GL_NV_shader_invocation_reorder) __glsl_extension(GL_EXT_ray_tracing) [__NonCopyableType] @@ -19959,6 +20354,7 @@ uint3 cudaBlockDim() // (This fusion takes place in the fuse-satcoop pass, and as such any changes to // the signature or behavior of this function should be adjusted for there). // +//@hidden: [KnownBuiltin("saturated_cooperation")] func saturated_cooperation<A : __BuiltinType, B, C>( cooperate : functype (A, B) -> C, @@ -20054,12 +20450,13 @@ ${ // for any resource type. } -__intrinsic_op($(kIROp_GetRegisterSpace)) uint __getRegisterSpace<T, Shape: __ITextureShape, let isArray:int, let isMS:int, let sampleCount:int, let access:int, let isShadow:int, let isCombined:int, let format:int>(__TextureImpl<T,Shape,isArray,isMS,sampleCount,access,isShadow,isCombined,format> texture); +__intrinsic_op($(kIROp_GetRegisterSpace)) uint __getRegisterSpace<T, Shape: __ITextureShape, let isArray:int, let isMS:int, let sampleCount:int, let access:int, let isShadow:int, let isCombined:int, let format:int>(_Texture<T,Shape,isArray,isMS,sampleCount,access,isShadow,isCombined,format> texture); __intrinsic_op($(kIROp_GetRegisterSpace)) uint __getRegisterSpace(SamplerState sampler); -__intrinsic_op($(kIROp_GetRegisterIndex)) uint __getRegisterIndex<T, Shape: __ITextureShape, let isArray:int, let isMS:int, let sampleCount:int, let access:int, let isShadow:int, let isCombined:int, let format:int>(__TextureImpl<T,Shape,isArray,isMS,sampleCount,access,isShadow,isCombined,format> texture); +__intrinsic_op($(kIROp_GetRegisterIndex)) uint __getRegisterIndex<T, Shape: __ITextureShape, let isArray:int, let isMS:int, let sampleCount:int, let access:int, let isShadow:int, let isCombined:int, let format:int>(_Texture<T,Shape,isArray,isMS,sampleCount,access,isShadow,isCombined,format> texture); __intrinsic_op($(kIROp_GetRegisterIndex)) uint __getRegisterIndex(SamplerState sampler); +//@public: ${{{{ // @@ -20131,6 +20528,7 @@ vector<uint, ND> __textureFootprintGetOffset<let ND:int>(__TextureFootprintData< } } +//@public: __intrinsic_type($(kIROp_TextureFootprintType)) [require(glsl_hlsl_spirv, texturefootprint)] struct __TextureFootprintData<let ND:int> @@ -20218,6 +20616,7 @@ struct __TextureFootprintData<let ND:int> } } +///@category stage_io struct TextureFootprint<let ND:int> : __TextureFootprintData<ND> { bool _isSingleLevel; @@ -20232,7 +20631,10 @@ struct TextureFootprint<let ND:int> : __TextureFootprintData<ND> } } +///@category stage_io typealias TextureFootprint2D = TextureFootprint<2>; + +///@category stage_io typealias TextureFootprint3D = TextureFootprint<3>; ${ @@ -20242,7 +20644,7 @@ ${ } __generic<T, Shape: __ITextureShape, let sampleCount:int, let isShadow:int, let format:int> -extension __TextureImpl<T,Shape,0,0,sampleCount,0,isShadow,0,format> +extension _Texture<T,Shape,0,0,sampleCount,0,isShadow,0,format> { ${ // We introduce a few convenience type aliases here, @@ -20842,10 +21244,9 @@ ${{{{ } // extension - //<T, Shape: __ITextureShape, let isArray:int, let isMS:int, let sampleCount:int, let access:int, let isShadow:int, let isCombined:int, let format:int> __generic<Shape:__ITextureShape1D2D3D, let format : int> -extension __TextureImpl<float, Shape, 0, 0, 0, $(kStdlibResourceAccessReadWrite), 0, 0, format> +extension _Texture<float, Shape, 0, 0, 0, $(kStdlibResourceAccessReadWrite), 0, 0, format> { [__requiresNVAPI] [ForceInline] @@ -20876,6 +21277,8 @@ extension __TextureImpl<float, Shape, 0, 0, 0, $(kStdlibResourceAccessReadWrite) // Buffer Pointer +//@hidden: + namespace vk { // Partial implementation of the vk::buffer_ref proposal: @@ -21025,7 +21428,7 @@ enum __DynamicResourceKind } __generic<T, Shape : __ITextureShape, let isArray : int, let isMS : int, let sampleCount : int, let access : int, let isShadow : int, let isCombined : int, let format : int> -extension __TextureImpl<T, Shape, isArray, isMS, sampleCount, access, isShadow, isCombined, format> : __IDynamicResourceCastable<__DynamicResourceKind.General> +extension _Texture<T, Shape, isArray, isMS, sampleCount, access, isShadow, isCombined, format> : __IDynamicResourceCastable<__DynamicResourceKind.General> { __intrinsic_op($(kIROp_CastDynamicResource)) __implicit_conversion($(kConversionCost_GenericParamUpcast)) diff --git a/source/slang/slang-ast-print.cpp b/source/slang/slang-ast-print.cpp index f5f99f01d..f3ed4ee0b 100644 --- a/source/slang/slang-ast-print.cpp +++ b/source/slang/slang-ast-print.cpp @@ -1,6 +1,8 @@ // slang-ast-print.cpp #include "slang-ast-print.h" +#include "core/slang-char-util.h" + #include "slang-check-impl.h" namespace Slang { @@ -81,7 +83,11 @@ void ASTPrinter::addVal(Val* val) } else { - out << getText(decl->getName()); + auto text = getText(decl->getName()); + if (text.getLength() && !(CharUtil::isAlphaOrDigit(text[0]) || text[0] == '_')) + out << "operator" << text; + else + out << text; } } @@ -140,6 +146,13 @@ void ASTPrinter::_addDeclPathRec(const DeclRef<Decl>& declRef, Index depth) { ExtensionDecl* extensionDecl = as<ExtensionDecl>(parentDeclRef.getDecl()); Type* type = extensionDecl->targetType.type; + if (m_optionFlags & OptionFlag::NoSpecializedExtensionTypeName) + { + if (auto unspecializedDeclRef = isDeclRefTypeOf<Decl>(type)) + { + type = DeclRefType::create(m_astBuilder, unspecializedDeclRef.getDecl()->getDefaultDeclRef()); + } + } addType(type); sb << toSlice("."); } diff --git a/source/slang/slang-ast-print.h b/source/slang/slang-ast-print.h index 1b61a8904..0befc89d6 100644 --- a/source/slang/slang-ast-print.h +++ b/source/slang/slang-ast-print.h @@ -20,6 +20,11 @@ public: ModuleName = 0x02, ///< Writes out module names NoInternalKeywords = 0x04, ///< Omits internal decoration keywords (e.g. __target_intrinsic). SimplifiedBuiltinType = 0x08, ///< Prints simplified builtin generic types (e.g. float3) instead of its generic form. + + /// Use the original generic type name instead of the specialized + /// type name defined on an extension when + /// printing the target type of an extension decl. + NoSpecializedExtensionTypeName = 0x10, }; }; diff --git a/source/slang/slang-capability.cpp b/source/slang/slang-capability.cpp index 00a3b6001..bae5a1c72 100644 --- a/source/slang/slang-capability.cpp +++ b/source/slang/slang-capability.cpp @@ -568,6 +568,25 @@ void CapabilitySet::nonDestructiveJoin(const CapabilitySet& other) } } +bool CapabilitySet::operator==(CapabilitySet const& that) const +{ + for (auto set : this->m_targetSets) + { + auto thatSet = that.m_targetSets.tryGetValue(set.first); + if (!thatSet) + return false; + for (auto stageSet : set.second.shaderStageSets) + { + auto thatStageSet = thatSet->shaderStageSets.tryGetValue(stageSet.first); + if (!thatStageSet) + return false; + if (stageSet.second.atomSet != thatStageSet->atomSet) + return false; + } + } + return true; +} + CapabilitySet CapabilitySet::getTargetsThisHasButOtherDoesNot(const CapabilitySet& other) { CapabilitySet newSet{}; diff --git a/source/slang/slang-compiler.h b/source/slang/slang-compiler.h index 39d0df86b..980490df5 100755 --- a/source/slang/slang-compiler.h +++ b/source/slang/slang-compiler.h @@ -3272,6 +3272,7 @@ namespace Slang SLANG_NO_THROW SlangResult SLANG_MCALL checkCompileTargetSupport(SlangCompileTarget target) override; SLANG_NO_THROW SlangResult SLANG_MCALL checkPassThroughSupport(SlangPassThrough passThrough) override; + void writeStdlibDoc(String config); SLANG_NO_THROW SlangResult SLANG_MCALL compileStdLib(slang::CompileStdLibFlags flags) override; SLANG_NO_THROW SlangResult SLANG_MCALL loadStdLib(const void* stdLib, size_t stdLibSizeInBytes) override; SLANG_NO_THROW SlangResult SLANG_MCALL saveStdLib(SlangArchiveType archiveType, ISlangBlob** outBlob) override; diff --git a/source/slang/slang-diagnostic-defs.h b/source/slang/slang-diagnostic-defs.h index 23eba5f03..3f4376eb3 100644 --- a/source/slang/slang-diagnostic-defs.h +++ b/source/slang/slang-diagnostic-defs.h @@ -904,6 +904,9 @@ DIAGNOSTIC(-1, Note, reportCheckpointVariable, "$0 bytes ($1) used to checkpoint DIAGNOSTIC(-1, Note, reportCheckpointCounter, "$0 bytes ($1) used for a loop counter here:") DIAGNOSTIC(-1, Note, reportCheckpointNone, "no checkpoint contexts to report") +// 9xxxx - Documentation generation +DIAGNOSTIC(90001, Warning, ignoredDocumentationOnOverloadCandidate, "documentation comment on overload candidate '$0' is ignored") + // // 8xxxx - Issues specific to a particular library/technology/platform/etc. // diff --git a/source/slang/slang-doc-ast.h b/source/slang/slang-doc-ast.h index a0d5367af..fb5a08986 100644 --- a/source/slang/slang-doc-ast.h +++ b/source/slang/slang-doc-ast.h @@ -25,7 +25,7 @@ public: Entry* getEntry(NodeBase* base); /// Get list of all of the entries in source order - const List<Entry>& getEntries() const { return m_entries; } + List<Entry>& getEntries() { return m_entries; } /// Attaches the markup to the AST nodes. void attachToAST(); diff --git a/source/slang/slang-doc-markdown-writer.cpp b/source/slang/slang-doc-markdown-writer.cpp index e32a738c7..86cdb6d29 100644 --- a/source/slang/slang-doc-markdown-writer.cpp +++ b/source/slang/slang-doc-markdown-writer.cpp @@ -3,6 +3,8 @@ #include "../core/slang-string-util.h" #include "../core/slang-type-text-util.h" +#include "../core/slang-char-util.h" +#include "../core/slang-token-reader.h" #include "slang-ast-builder.h" #include "slang-lookup.h" @@ -25,15 +27,50 @@ static void _getDecls(ContainerDecl* containerDecl, List<T*>& out) } template <typename T> -static void _getDeclsOfType(ContainerDecl* containerDecl, List<Decl*>& out) +static void _getDeclsOfType(DocMarkdownWriter* writer, ContainerDecl* containerDecl, List<Decl*>& out) { for (Decl* decl : containerDecl->members) { if (as<T>(decl)) { + if (!writer->isVisible(decl)) + continue; out.add(decl); } + else if (auto genericDecl = as<GenericDecl>(decl)) + { + if (as<T>(genericDecl->inner)) + { + if (!writer->isVisible(decl)) + continue; + out.add(genericDecl); + } + } + } +} + +template <typename T> +static void _getDeclsOfType(DocMarkdownWriter* writer, DocumentPage* page, List<Decl*>& out) +{ + // Collect all decls of type T from all entries for the page. + List<Decl*> declList; + for (auto entry : page->entries) + { + _getDeclsOfType<T>(writer, as<ContainerDecl>(entry->m_node), declList); + } + // Deduplicate based on name. + Dictionary<Name*, Decl*> nameDict; + for (auto decl : declList) + { + nameDict[decl->getName()] = decl; + } + // Sort by name. + for (auto pair : nameDict) + { + if (pair.first) + out.add(pair.second); } + out.sort([](Decl* a, Decl* b) -> bool { return getText(a->getName()) < getText(b->getName()); }); } template <typename T> @@ -54,61 +91,118 @@ static void _appendAsSingleLine(const UnownedStringSlice& in, StringBuilder& out StringUtil::join(lines.getBuffer(), lines.getCount(), ' ', out); } -void DocMarkdownWriter::_appendAsBullets(const List<NameAndText>& values, char wrapChar) +String getDocPath(const DocumentationConfig& config, String path) +{ + return config.rootDir + Path::getPathWithoutExt(path); +} + +void DocMarkdownWriter::_appendAsBullets(const List<NameAndText>& values, bool insertLinkForName, char wrapChar) { - auto& out = m_builder; + auto& out = *m_builder; for (const auto& value : values) { - out << "* "; - + out << "#### "; const String& name = value.name; + auto path = findLinkForToken(m_currentPage, name); if (name.getLength()) { if (wrapChar) { + if (path.getLength()) + { + out << "["; + } out.appendChar(wrapChar); out << name; out.appendChar(wrapChar); + if (path.getLength()) + { + out << "](" << getDocPath(m_config, path) << ")"; + } } else { - out << name; + if (insertLinkForName) + out << translateToMarkdownWithLinks(name); + else + { + auto spaceLoc = name.indexOf(' '); + if (spaceLoc == -1) + out << escapeMarkdownText(name); + else + { + auto first = name.getUnownedSlice().head(spaceLoc); + auto rest = name.getUnownedSlice().tail(spaceLoc + 1); + out << escapeMarkdownText(first) << " "; + out << translateToMarkdownWithLinks(rest); + } + } + } + } + if (value.decl) + { + // Add anchor ID for the decl. + if (as<GenericTypeParamDeclBase>(value.decl)) + { + out << " {#typeparam-" << getText(value.decl->getName()) << "}"; + } + else + { + out << " {#decl-" << getText(value.decl->getName()) << "}"; } } - if (value.text.getLength()) { - out.appendChar(' '); + out.appendChar('\n'); - // Hmm, we'll want to make something multiline into a single line - _appendAsSingleLine(value.text.getUnownedSlice(), out); + ParsedDescription desc; + desc.parse(value.text.getUnownedSlice()); + desc.write(this, value.decl, out); + } + else + { + out << "\n"; } - - out << "\n"; } } void DocMarkdownWriter::_appendAsBullets(const List<String>& values, char wrapChar) { - auto& out = m_builder; + auto& out = *m_builder; for (const auto& value : values) { out << "* "; + const String& name = value; - if (value.getLength()) + String path; + path = findLinkForToken(m_currentPage, name); + if (path.getLength() == 0) + { + Slang::Misc::TokenReader tokenReader(name); + if (!tokenReader.IsEnd()) + path = findLinkForToken(m_currentPage, tokenReader.ReadToken().Content); + } + if (path.getLength()) + { + out << "["; + } + if (name.getLength()) { if (wrapChar) { out.appendChar(wrapChar); - out << value; + out << escapeMarkdownText(name); out.appendChar(wrapChar); - } else { - out << value; + out << escapeMarkdownText(name); } } + if (path.getLength()) + { + out << "](" << getDocPath(m_config, path) << ")"; + } out << "\n"; } } @@ -120,6 +214,93 @@ String DocMarkdownWriter::_getName(Decl* decl) return buf.produceString(); } +String DocMarkdownWriter::_getFullName(Decl* decl) +{ + ASTPrinter printer(m_astBuilder); + printer.addDeclPath(decl); + return printer.getStringBuilder().produceString(); +} + +String _translateNameToPath(const UnownedStringSlice& name) +{ + StringBuilder buf; + for (const char c : name) + { + // Removing leading underscores to prevent url issues. + if (c == '_' && buf.getLength() == 0) + continue; + + if (c == ' ') + { + buf.appendChar('-'); + } + else if (CharUtil::isAlphaOrDigit(c) || c == '_') + { + buf.appendChar(c); + } + else + { + buf.appendChar('x'); + buf << String((int)c, 16); + } + } + return buf; +} + +String DocMarkdownWriter::_getDocFilePath(Decl* decl) +{ + if (!decl) + return ""; + + StringBuilder sb; + if (as<NamespaceDeclBase>(getParentDecl(decl))) + { + if (as<InterfaceDecl>(decl)) + { + sb << "interfaces/"; + } + else if (as<AggTypeDeclBase>(decl) || as<TypeDefDecl>(decl)) + { + sb << "types/"; + } + else + { + sb << "global-decls/"; + } + } + + if (auto extDecl = as<ExtensionDecl>(decl)) + { + if (auto declRef = isDeclRefTypeOf<Decl>(extDecl->targetType)) + { + auto name = _translateNameToPath(_getName(declRef.getDecl()).getUnownedSlice()); + sb << name; + sb << "/index.md"; + return sb.produceString(); + } + } + if (as<AggTypeDeclBase>(decl)) + { + auto name = _translateNameToPath(_getName(decl).getUnownedSlice()); + sb << name; + sb << "/index.md"; + return sb.produceString(); + } + auto parentPath = _getDocFilePath(getParentDecl(decl)); + if (parentPath.endsWith(".md")) + { + parentPath = Path::getParentDirectory(parentPath); + } + if (parentPath.getLength() > 0) + { + sb << parentPath; + sb << "/"; + } + sb << _translateNameToPath(_getName(decl).getUnownedSlice()); + sb << ".md"; + return sb.produceString(); +} + String DocMarkdownWriter::_getName(InheritanceDecl* decl) { StringBuilder buf; @@ -132,12 +313,64 @@ DocMarkdownWriter::NameAndText DocMarkdownWriter::_getNameAndText(ASTMarkup::Ent { NameAndText nameAndText; + nameAndText.decl = decl; nameAndText.name = _getName(decl); - - // We could extract different text here, but for now just do all markup - if (entry) + + StringBuilder sb; + if (auto varDeclBase = as<VarDeclBase>(decl)) + { + sb << " : " << varDeclBase->type->toString(); + + if (varDeclBase->initExpr) + { + sb << " = "; + _appendExpr(sb, varDeclBase->initExpr); + } + } + else if (auto typeParam = as<GenericTypeParamDeclBase>(decl)) + { + bool isFirst = true; + for (auto member : decl->parentDecl->members) + { + if (auto constraint = as<TypeConstraintDecl>(member)) + { + if (isDeclRefTypeOf<Decl>(getSub(m_astBuilder, constraint)).getDecl() == typeParam) + { + if (isFirst) + { + sb << ": "; + isFirst = false; + } + else + { + sb << ", "; + } + sb << constraint->getSup().type->toString(); + break; + } + } + } + if (auto genericTypeParam = as<GenericTypeParamDecl>(decl)) + { + if (genericTypeParam->initType.type) + { + sb << " = "; + sb << genericTypeParam->initType.type->toString(); + } + } + } + else if (auto enumCase = as<EnumCaseDecl>(decl)) + { + if (enumCase->tagExpr) + { + sb << " = "; + _appendExpr(sb, enumCase->tagExpr); + } + } + nameAndText.name.append(sb.produceString()); + + if (entry && entry->m_markup.getLength()) { - // For now we'll just use all markup, but really we need something more sophisticated here nameAndText.text = entry->m_markup; } @@ -172,21 +405,22 @@ List<String> DocMarkdownWriter::_getAsStringList(const List<Decl*>& in) void DocMarkdownWriter::_appendCommaList(const List<String>& strings, char wrapChar) { + auto& out = *m_builder; for (Index i = 0; i < strings.getCount(); ++i) { if (i > 0) { - m_builder << toSlice(", "); + out << toSlice(", "); } if (wrapChar) { - m_builder.appendChar(wrapChar); - m_builder << strings[i]; - m_builder.appendChar(wrapChar); + out.appendChar(wrapChar); + out << strings[i]; + out.appendChar(wrapChar); } else { - m_builder << strings[i]; + out << translateToMarkdownWithLinks(strings[i]); } } } @@ -242,35 +476,276 @@ void DocMarkdownWriter::_appendCommaList(const List<String>& strings, char wrapC } } +void escapeHTMLContent(StringBuilder& sb, UnownedStringSlice str) +{ + for (auto ch : str) + { + switch (ch) + { + case '<': sb << "<"; break; + case '>': sb << ">"; break; + case '&': sb << "&"; break; + case '"': sb << """; break; + default: sb.appendChar(ch); break; + } + } +} + void DocMarkdownWriter::writeVar(const ASTMarkup::Entry& entry, VarDecl* varDecl) { - writePreamble(entry); - auto& out = m_builder; + auto& out = *m_builder; + + ASTPrinter printer(m_astBuilder); + printer.addDeclPath(DeclRef<Decl>(varDecl)); + + out << toSlice("# ") << printer.getSlice() << toSlice("\n\n"); + + DeclDocumentation declDoc; + declDoc.parse(entry.m_markup.getUnownedSlice()); + declDoc.writeDescription(out, this, varDecl); + registerCategory(m_currentPage, declDoc); + + out << toSlice("## Signature\n"); + out << toSlice("<pre>\n"); + if (varDecl->hasModifier<HLSLStaticModifier>()) + { + out << toSlice("<span class='code_keyword'>static</span> "); + } + if (varDecl->hasModifier<ConstModifier>()) + { + out << toSlice("<span class='code_keyword'>const</span> "); + } + if (varDecl->hasModifier<ConstExprModifier>()) + { + out << toSlice("<span class='code_keyword'>constexpr</span> "); + } + if (varDecl->hasModifier<InModifier>()) + { + out << toSlice("<span class='code_keyword'>in</span> "); + } + if (varDecl->hasModifier<OutModifier>()) + { + out << toSlice("<span class='code_keyword'>out</span> "); + } + StringBuilder typeSB; + varDecl->type->toText(typeSB); + out << translateToHTMLWithLinks(varDecl, typeSB.produceString()) << toSlice(" "); + out << translateToHTMLWithLinks(varDecl, printer.getSlice()); + + if (varDecl->initExpr) + { + out << toSlice(" = "); + _appendExpr(out, varDecl->initExpr); + } + + out << toSlice(";\n</pre>\n\n"); + + declDoc.writeSection(out, this, varDecl, DocPageSection::Remarks); + declDoc.writeSection(out, this, varDecl, DocPageSection::Example); + declDoc.writeSection(out, this, varDecl, DocPageSection::SeeAlso); +} + +void DocMarkdownWriter::writeProperty(const ASTMarkup::Entry& entry, PropertyDecl* propertyDecl) +{ + auto& out = *m_builder; + out << toSlice("# property "); + + ASTPrinter printer(m_astBuilder); + printer.addDeclPath(DeclRef<Decl>(propertyDecl)); + out << escapeMarkdownText(printer.getSlice()) << toSlice("\n\n"); + + DeclDocumentation declDoc; + declDoc.parse(entry.m_markup.getUnownedSlice()); + declDoc.writeDescription(out, this, propertyDecl); + registerCategory(m_currentPage, declDoc); + + out << toSlice("## Signature\n\n"); + + out << toSlice("<pre>\n<span class='code_keyword'>property</span> "); + out << translateToHTMLWithLinks(propertyDecl, printer.getSlice()); + out << toSlice(" : "); + StringBuilder typeSB; + propertyDecl->type->toText(typeSB); + out << translateToHTMLWithLinks(propertyDecl, typeSB.produceString()); + out << "\n{\n"; + for (auto member : propertyDecl->members) + { + if (as<GetterDecl>(member)) + { + out << " get;\n"; + } + else if (as<SetterDecl>(member)) + { + out << " set;\n"; + } + else if (as<RefAccessorDecl>(member)) + { + out << " ref;\n"; + } + } + out << "}\n</pre>\n\n"; + + declDoc.writeSection(out, this, propertyDecl, DocPageSection::ReturnInfo); + declDoc.writeSection(out, this, propertyDecl, DocPageSection::Remarks); + declDoc.writeSection(out, this, propertyDecl, DocPageSection::Example); + declDoc.writeSection(out, this, propertyDecl, DocPageSection::SeeAlso); +} + +void DocMarkdownWriter::writeTypeDef(const ASTMarkup::Entry& entry, TypeDefDecl* typeDefDecl) +{ + auto& out = *m_builder; + + out << toSlice("# "); + ASTMarkup::Entry newEntry = entry; + _appendAggTypeName(newEntry, typeDefDecl); + out << toSlice("\n\n"); + + DeclDocumentation declDoc; + declDoc.parse(entry.m_markup.getUnownedSlice()); + registerCategory(m_currentPage, declDoc); + + declDoc.writeDescription(out, this, typeDefDecl); + + out << toSlice("## Signature\n\n"); + + out << toSlice("<pre>\n<span class='code_keyword'>typealias</span> "); + ASTPrinter printer(m_astBuilder); + printer.addDeclPath(typeDefDecl); + out << translateToHTMLWithLinks(typeDefDecl, printer.getSlice()); + out << toSlice(" = "); + + // Insert a line break if the type name is already long. + if (printer.getSlice().getLength() > 25) + { + out << "\n "; + } + out << translateToHTMLWithLinks(typeDefDecl, typeDefDecl->type->toString()); + out << ";\n</pre>\n\n"; + + declDoc.writeGenericParameters(out, this, typeDefDecl); + + declDoc.writeSection(out, this, typeDefDecl, DocPageSection::Remarks); + declDoc.writeSection(out, this, typeDefDecl, DocPageSection::Example); + declDoc.writeSection(out, this, typeDefDecl, DocPageSection::SeeAlso); +} + +void DocMarkdownWriter::writeExtensionConditions(StringBuilder& out, ExtensionDecl* extensionDecl, const char* prefix, bool isHtml) +{ + // Synthesize `where` clause for things defined in an extension. + auto targetTypeDeclRef = isDeclRefTypeOf<ContainerDecl>(extensionDecl->targetType); + if (!targetTypeDeclRef) + return; - out << toSlice("# ") << varDecl->getName()->text << toSlice("\n\n"); + if (auto genAppDeclRef = as<GenericAppDeclRef>(targetTypeDeclRef.declRefBase)) + { + for (Index i = 0; i < genAppDeclRef->getArgCount(); i++) + { + auto arg = genAppDeclRef->getArg(i); + Decl* genericParamDecl = nullptr; + Index parameterIndex = i; + if (auto extTypeParamDecl = isDeclRefTypeOf<GenericTypeParamDeclBase>(arg)) + { + genericParamDecl = extTypeParamDecl.getDecl(); + } + else if (auto extValueParamVal = as<GenericParamIntVal>(arg)) + { + genericParamDecl = extValueParamVal->getDeclRef().getDecl(); + } - // TODO(JS): The outputting of types this way isn't right - it doesn't handle int a[10] for example. - //ASTPrinter printer(m_astBuilder, ASTPrinter::OptionFlag::ParamNames); + // Locate the original generic parameter defined on the type being extended. + Decl* originalParamDecl = nullptr; + if (auto targetTypeParentGenericDecl = as<GenericDecl>(targetTypeDeclRef.getDecl()->parentDecl)) + { + for (auto member : targetTypeParentGenericDecl->members) + { + if (auto typeParamDecl = as<GenericTypeParamDeclBase>(member)) + { + if (typeParamDecl->parameterIndex == parameterIndex) + { + originalParamDecl = typeParamDecl; + break; + } + } + else if (auto valParamDecl = as<GenericValueParamDecl>(member)) + { + if (valParamDecl->parameterIndex == parameterIndex) + { + originalParamDecl = valParamDecl; + break; + } + } + } + } - out << toSlice("```\n"); - out << varDecl->type << toSlice(" ") << varDecl << toSlice("\n"); - out << toSlice("```\n\n"); + // If we can't find such parameter, bail. + if (!originalParamDecl) + continue; + + bool isEqualityConstraint = false; + Val* constraintVal = nullptr; + if (genericParamDecl) + { + // If we have `TargetType<T>` the member belongs to `extension<X : C> TargetType<X>`, + // We want to print a synthesized `where T : C` clause. + // Here `extTypeParamDecl` is a reference to `X`, so we need to find the corresponding `T`. - writeDescription(entry); + // Find constraints on the originalParamDecl. + for (auto member : genericParamDecl->parentDecl->members) + { + if (auto typeConstraint = as<GenericTypeConstraintDecl>(member)) + { + if (isDeclRefTypeOf<Decl>(typeConstraint->sub.type).getDecl() == genericParamDecl) + { + if (typeConstraint->isEqualityConstraint) + { + isEqualityConstraint = true; + } + constraintVal = typeConstraint->getSup().type; + break; + } + } + } + } + else + { + // If we have `extension TargetType<Y>` where `Y` does not name a generic parameter defined + // on the extension itself, we want to print a synthesized `where T == Y` clause, where + // `T` is the original generic parameter on the target type. + isEqualityConstraint = true; + constraintVal = arg; + } + if (constraintVal) + { + out << prefix; + if (isHtml) + out << translateToHTMLWithLinks(originalParamDecl, originalParamDecl->getName()->text); + else + out << translateToMarkdownWithLinks(originalParamDecl->getName()->text); + if (isEqualityConstraint) + out << " == "; + else + out << " : "; + if (isHtml) + out << translateToHTMLWithLinks(originalParamDecl, constraintVal->toString()); + else + out << translateToMarkdownWithLinks(constraintVal->toString()); + } + } + } } void DocMarkdownWriter::writeSignature(CallableDecl* callableDecl) { - auto& out = m_builder; + StringBuilder& out = *getBuilder(callableDecl); if (callableDecl->hasModifier<HLSLStaticModifier>()) { - out << "static "; + out << "<span class='code_keyword'>static</span> "; } List<ASTPrinter::Part> parts; - ASTPrinter printer(m_astBuilder, ASTPrinter::OptionFlag::ParamNames, &parts); + ASTPrinter printer(m_astBuilder, ASTPrinter::OptionFlag::ParamNames | ASTPrinter::OptionFlag::NoSpecializedExtensionTypeName, &parts); printer.addDeclSignature(makeDeclRef(callableDecl)); Signature signature; @@ -283,52 +758,34 @@ void DocMarkdownWriter::writeSignature(CallableDecl* callableDecl) const UnownedStringSlice returnType = printer.getPartSlice(signature.returnType); if (returnType.getLength() > 0) { - out << returnType << toSlice(" "); + out << translateToHTMLWithLinks(callableDecl, returnType) << toSlice(" "); } } - out << printer.getPartSlice(signature.name); - -#if 0 - if (signature.genericParams.getCount()) - { - out << toSlice("<"); - const Index count = signature.genericParams.getCount(); - for (Index i = 0; i < count; ++i) - { - const auto& genericParam = signature.genericParams[i]; - if (i > 0) - { - out << toSlice(", "); - } - out << printer.getPartSlice(genericParam.name); - - if (genericParam.type.type != Part::Type::None) - { - out << toSlice(" : "); - out << printer.getPartSlice(genericParam.type); - } - } - out << toSlice(">"); - } -#endif + out << translateToHTMLWithLinks(callableDecl, printer.getPartSlice(signature.name)); switch (paramCount) { case 0: { // Has no parameters - out << toSlice("();\n"); + out << toSlice("()"); break; } case 1: { - // Place all on single line - out.appendChar('('); - const auto& param = signature.params[0]; - out << printer.getPartSlice(param.first) << toSlice(" ") << printer.getPartSlice(param.second); - out << ");\n"; - break; + if (signature.name.end - signature.name.start < 40) + { + // Place all on single line + out.appendChar('('); + const auto& param = signature.params[0]; + out << translateToHTMLWithLinks(callableDecl, printer.getPartSlice(param.first)) << toSlice(" "); + out << translateToHTMLWithLinks(callableDecl, printer.getPartSlice(param.second)); + out << ")"; + break; + } + // If the name is already long, fall through to default. + [[fallthrough]]; } default: { @@ -339,20 +796,11 @@ void DocMarkdownWriter::writeSignature(CallableDecl* callableDecl) { const auto& param = signature.params[i]; line.clear(); - // If we want to tab these over... we'll need to know how must space I have - line << " " << printer.getPartSlice(param.first); - Index indent = 25; - if (line.getLength() < indent) - { - line.appendRepeatedChar(' ', indent - line.getLength()); - } - else - { - line.appendChar(' '); - } + line << " " << translateToHTMLWithLinks(callableDecl, printer.getPartSlice(param.first)); - line << printer.getPartSlice(param.second); + line.appendChar(' '); + line << translateToHTMLWithLinks(callableDecl, printer.getPartSlice(param.second)); if (i < paramCount - 1) { line << ",\n"; @@ -361,17 +809,53 @@ void DocMarkdownWriter::writeSignature(CallableDecl* callableDecl) out << line; } - out << ");\n"; + out << ")"; break; } } + + // Print `where` clause. + Decl* parentDecl = callableDecl; + while (parentDecl) + { + if (auto extensionDecl = as<ExtensionDecl>(parentDecl)) + { + // Synthesize `where` clause for things defined in an extension. + if (auto targetTypeDeclRef = isDeclRefTypeOf<ContainerDecl>(extensionDecl->targetType)) + { + writeExtensionConditions(out, extensionDecl, "\n <span class='code_keyword'>where</span> ", true); + // We need to follow the parent of the target type instead of the parent of the extension decl. + parentDecl = getParentDecl(targetTypeDeclRef.getDecl()); + continue; + } + } + + if (auto genericParent = as<GenericDecl>(parentDecl->parentDecl)) + { + for (auto member : genericParent->members) + { + if (auto typeConstraint = as<GenericTypeConstraintDecl>(member)) + { + out << toSlice("\n <span class='code_keyword'>where</span> "); + out << translateToHTMLWithLinks(parentDecl, getSub(m_astBuilder, typeConstraint)->toString()); + if (typeConstraint->isEqualityConstraint) + out << " == "; + else + out << toSlice(" : "); + out << translateToHTMLWithLinks(parentDecl, getSup(m_astBuilder, typeConstraint)->toString()); + } + } + } + parentDecl = getParentDecl(parentDecl); + } + out << ";\n"; } -List<DocMarkdownWriter::NameAndText> DocMarkdownWriter::_getUniqueParams(const List<Decl*>& decls) +List<DocMarkdownWriter::NameAndText> DocMarkdownWriter::_getUniqueParams(const List<Decl*>& decls, DeclDocumentation* funcDoc) { List<NameAndText> out; - Dictionary<Name*, Index> nameDict; + Dictionary<String, Index> nameDict; for (auto decl : decls) { @@ -380,231 +864,187 @@ List<DocMarkdownWriter::NameAndText> DocMarkdownWriter::_getUniqueParams(const L { continue; } - - Index index = nameDict.getOrAddValue(name, out.getCount()); + auto nameText = _getNameAndText(decl); + Index index = nameDict.getOrAddValue(nameText.name, out.getCount()); if (index >= out.getCount()) { - out.add(NameAndText{ getText(name), String() }); + out.add(nameText); } + // Extract text. NameAndText& nameAndMarkup = out[index]; if (nameAndMarkup.text.getLength() > 0) { continue; } - auto entry = m_markup->getEntry(decl); - if (entry && entry->m_markup.getLength()) + ParamDocumentation paramDoc; + if (funcDoc->parameters.tryGetValue(getText(name), paramDoc)) { - nameAndMarkup.text = entry->m_markup; + StringBuilder sb; + if (paramDoc.direction.getLength()) + sb << "\\[" << paramDoc.direction << "\\] "; + sb << paramDoc.description.ownedText; + nameAndMarkup.text = sb.produceString(); + } + else + { + auto entry = m_markup->getEntry(decl); + if (entry && entry->m_markup.getLength()) + { + nameAndMarkup.text = entry->m_markup; + } } } return out; } -static void _addRequirement(const DocMarkdownWriter::Requirement& req, List<DocMarkdownWriter::Requirement>& ioReqs) +static Index _addRequirement(const DocMarkdownWriter::Requirement& req, List<DocMarkdownWriter::Requirement>& ioReqs) { - if (ioReqs.indexOf(req) < 0) + auto index = ioReqs.indexOf(req); + if (index < 0) { ioReqs.add(req); + return ioReqs.getCount() - 1; } + return index; } -static void _addRequirement(CodeGenTarget target, const String& value, List<DocMarkdownWriter::Requirement>& ioReqs) +static Index _addRequirement(CapabilitySet set, List<DocMarkdownWriter::Requirement>& ioReqs) { - _addRequirement(DocMarkdownWriter::Requirement{ target, value }, ioReqs); + return _addRequirement(DocMarkdownWriter::Requirement{ set }, ioReqs); } -static DocMarkdownWriter::Requirement _getRequirementFromTargetToken(const Token& tok) +static Index _addRequirements(Decl* decl, List<DocMarkdownWriter::Requirement>& ioReqs) { - typedef DocMarkdownWriter::Requirement Requirement; - - if (tok.type == TokenType::Unknown) - { - return Requirement{ CodeGenTarget::None, String() }; - } - - auto targetName = tok.getContent(); - if (targetName == "spirv") - { - return Requirement{CodeGenTarget::SPIRV, UnownedStringSlice("")}; - } - - const CapabilityAtom targetCap = asAtom(findCapabilityName(targetName)); - - if (targetCap == CapabilityAtom::Invalid) - { - return Requirement{ CodeGenTarget::None, String() }; - } - SLANG_ASSERT(targetCap < CapabilityAtom::Count); - - static const CapabilityAtom rootAtoms[] = - { - CapabilityAtom::glsl, - CapabilityAtom::hlsl, - CapabilityAtom::cuda, - CapabilityAtom::cpp, - CapabilityAtom::c, - }; - - for (auto rootAtom : rootAtoms) - { - if (rootAtom == targetCap) - { - // If its one of the roots we don't need to store the name - targetName = UnownedStringSlice(); - break; - } - } + StringBuilder buf; - if (isCapabilityDerivedFrom(targetCap, CapabilityAtom::glsl)) - { - return Requirement{CodeGenTarget::GLSL, targetName}; - } - else if (isCapabilityDerivedFrom(targetCap, CapabilityAtom::hlsl)) - { - return Requirement{ CodeGenTarget::HLSL, targetName }; - } - else if (isCapabilityDerivedFrom(targetCap, CapabilityAtom::cuda)) - { - return Requirement{ CodeGenTarget::CUDASource, targetName }; - } - else if (isCapabilityDerivedFrom(targetCap, CapabilityAtom::cpp)) - { - return Requirement{ CodeGenTarget::CPPSource, targetName }; - } - else if (isCapabilityDerivedFrom(targetCap, CapabilityAtom::c)) - { - return Requirement{ CodeGenTarget::CSource, targetName }; - } - else if (isCapabilityDerivedFrom(targetCap, CapabilityAtom::metal)) - { - return Requirement{ CodeGenTarget::Metal, targetName }; - } - else if (isCapabilityDerivedFrom(targetCap, CapabilityAtom::wgsl)) + if (auto capAttr = decl->findModifier<RequireCapabilityAttribute>()) { - return Requirement{ CodeGenTarget::WGSL, targetName }; + return _addRequirement(capAttr->capabilitySet, ioReqs); } - return Requirement{ CodeGenTarget::Unknown, String() }; + return -1; } -static void _addRequirementFromTargetToken(const Token& tok, List<DocMarkdownWriter::Requirement>& ioReqs) +static String getCapabilityName(CapabilityName name) { - auto req = _getRequirementFromTargetToken(tok); - if (req.target != CodeGenTarget::None) + auto text = capabilityNameToString(name); + if (text.startsWith("_")) { - _addRequirement(req, ioReqs); + return text.tail(1); } + return text; } -static void _addRequirements(Decl* decl, List<DocMarkdownWriter::Requirement>& ioReqs) +static String getCapabilityName(CapabilityAtom atom) { - StringBuilder buf; - - if (auto spirvRequiredModifier = decl->findModifier<RequiredSPIRVVersionModifier>()) - { - buf.clear(); - buf << "SPIR-V "; - spirvRequiredModifier->version.append(buf); - _addRequirement(CodeGenTarget::GLSL, buf, ioReqs); - } - - if (auto glslRequiredModifier = decl->findModifier<RequiredGLSLVersionModifier>()) - { - buf.clear(); - buf << "GLSL" << glslRequiredModifier->versionNumberToken.getContent(); - _addRequirement(CodeGenTarget::GLSL, buf, ioReqs); - } - - if (auto cudaSMVersionModifier = decl->findModifier<RequiredCUDASMVersionModifier>()) - { - buf.clear(); - buf << "SM "; - cudaSMVersionModifier->version.append(buf); - _addRequirement(CodeGenTarget::CUDASource, buf, ioReqs); - } - - if (auto extensionModifier = decl->findModifier<RequiredGLSLExtensionModifier>()) - { - buf.clear(); - buf << extensionModifier->extensionNameToken.getContent(); - _addRequirement(CodeGenTarget::GLSL, buf, ioReqs); - } + return getCapabilityName((CapabilityName)atom); +} - if (const auto requiresNVAPIAttribute = decl->findModifier<RequiresNVAPIAttribute>()) +void DocMarkdownWriter::_appendExpr(StringBuilder& sb, Expr* expr) +{ + if (auto typeCast = as<TypeCastExpr>(expr)) + _appendExpr(sb, typeCast->arguments[0]); + else if (auto declRefExpr = as<DeclRefExpr>(expr)) { - _addRequirement(CodeGenTarget::HLSL, "NVAPI", ioReqs); + ASTPrinter printer(m_astBuilder); + printer.addDeclPath(declRefExpr->declRef); + sb << escapeMarkdownText(printer.getSlice()); } - - for (auto targetIntrinsic : decl->getModifiersOfType<TargetIntrinsicModifier>()) + else if (auto litExpr = as<LiteralExpr>(expr)) { - _addRequirementFromTargetToken(targetIntrinsic->targetToken, ioReqs); + sb << litExpr->token.getContent(); } - for (auto specializedForTarget : decl->getModifiersOfType<SpecializedForTargetModifier>()) + else { - _addRequirementFromTargetToken(specializedForTarget->targetToken, ioReqs); + sb << "..."; } } -void DocMarkdownWriter::_writeTargetRequirements(const Requirement* reqs, Index reqsCount) +void DocMarkdownWriter::_appendRequirements(const Requirement& requirement) { - if (reqsCount == 0) + auto capabilitySet = requirement.capabilitySet; + m_builder->append("Defined for the following targets:\n\n"); + for (auto targetSet : capabilitySet.getCapabilityTargetSets()) { - return; - } - - auto& out = m_builder; - - // Okay we need the name of the CodeGen target - UnownedStringSlice name = TypeTextUtil::getCompileTargetName(SlangCompileTarget(reqs->target)); + m_builder->append("#### "); + m_builder->append(getCapabilityName(targetSet.first)); + m_builder->append("\n"); - out << toSlice("**") << String(name).toUpper() << toSlice("**"); - - if (!(reqsCount == 1 && reqs[0].value.getLength() == 0)) - { - // Put in a list so we can use convenience funcs - List<String> values; - for (Index i = 0; i < reqsCount; i++) + if (targetSet.second.shaderStageSets.getCount() == kCapabilityStageCount) { - if (reqs[i].value.getLength() > 0) + m_builder->append("Available in all stages.\n"); + } + else if (targetSet.second.shaderStageSets.getCount() > 1) + { + m_builder->append("Available in stages: "); + bool isFirst = true; + for (auto& stage : targetSet.second.shaderStageSets) { - values.add(reqs[i].value); + if (!isFirst) + { + m_builder->append(", "); + } + isFirst = false; + m_builder->append("`"); + m_builder->append(getCapabilityName(stage.first)); + m_builder->append("`"); } + m_builder->append(".\n"); + } + else if (targetSet.second.shaderStageSets.getCount() == 1) + { + m_builder->append("Available in `"); + m_builder->append(getCapabilityName(targetSet.second.shaderStageSets.begin()->first)); + m_builder->append("` stage only.\n"); } - out << toSlice(" "); - _appendCommaList(values, '`'); - } - - out << toSlice(" "); -} - -void DocMarkdownWriter::_appendRequirements(const List<Requirement>& requirements) -{ - Index startIndex = 0; - CodeGenTarget curTarget = CodeGenTarget::None; - - for (Index i = 0; i < requirements.getCount(); ++i) - { - const auto& req = requirements[i]; + m_builder->append("\n"); - if (req.target != curTarget) + // TODO: We should probably print the capabilities for each stage set if the requirements differ between + // different stages, but for now we'll just print the first one, assuming the rest are the same. + // This is currently true for most if not all of our stdlib decls. + // + if (targetSet.second.shaderStageSets.getCount() > 0 && + targetSet.second.shaderStageSets.begin()->second.atomSet.has_value()) { - _writeTargetRequirements(requirements.getBuffer() + startIndex, i - startIndex); - - startIndex = i; - curTarget = req.target; + List<String> capabilities; + auto atomSet = targetSet.second.shaderStageSets.begin()->second.atomSet.value().newSetWithoutImpliedAtoms(); + for (auto atom : atomSet) + { + // If the requirement atom is the target or stage atom, don't repeat ourselves. + if ((CapabilityAtom)atom == targetSet.first) + continue; + if ((CapabilityAtom)atom == targetSet.second.shaderStageSets.begin()->first) + continue; + String capabilityName = capabilityNameToString((CapabilityName)atom); + if (!capabilityName.startsWith("_")) + { + capabilities.add(capabilityName); + } + } + if (capabilities.getCount() > 1) + { + m_builder->append("Requires capabilities: "); + _appendCommaList(capabilities, '`'); + m_builder->append(".\n"); + } + else if (capabilities.getCount() == 1) + { + m_builder->append("Requires capability: `"); + m_builder->append(capabilities[0]); + m_builder->append("`"); + m_builder->append(".\n"); + } } } - - _writeTargetRequirements(requirements.getBuffer() + startIndex, requirements.getCount() - startIndex); } -void DocMarkdownWriter::_maybeAppendRequirements(const UnownedStringSlice& title, const List<List<DocMarkdownWriter::Requirement>>& uniqueRequirements) +void DocMarkdownWriter::_maybeAppendRequirements(const UnownedStringSlice& title, const List<DocMarkdownWriter::Requirement>& uniqueRequirements) { - auto& out = m_builder; + auto& out = *m_builder; const Index uniqueCount = uniqueRequirements.getCount(); if (uniqueCount <= 0) @@ -616,12 +1056,6 @@ void DocMarkdownWriter::_maybeAppendRequirements(const UnownedStringSlice& title { const auto& reqs = uniqueRequirements[0]; - // If just HLSL on own, then ignore - if (reqs.getCount() == 0 || (reqs.getCount() == 1 && reqs[0] == Requirement{ CodeGenTarget::HLSL, String() })) - { - return; - } - out << title; _appendRequirements(reqs); @@ -633,7 +1067,7 @@ void DocMarkdownWriter::_maybeAppendRequirements(const UnownedStringSlice& title for (Index i = 0; i < uniqueCount; ++i) { - out << (i + 1) << (". "); + out << "### Capability Set " << (i + 1) << ("\n\n"); _appendRequirements(uniqueRequirements[i]); out << toSlice("\n"); } @@ -642,39 +1076,16 @@ void DocMarkdownWriter::_maybeAppendRequirements(const UnownedStringSlice& title out << toSlice("\n"); } -static Decl* _getSameNameDecl(Decl* decl) +static Decl* _getSameNameDecl(ContainerDecl* parentDecl, Decl* decl) { - auto parentDecl = decl->parentDecl; - - // Sanity check: there should always be a parent declaration. - // - SLANG_ASSERT(parentDecl); - if (!parentDecl) return nullptr; - - // If the declaration is the "inner" declaration of a generic, - // then we actually want to look one level up, because the - // peers/siblings of the declaration will belong to the same - // parent as the generic, not to the generic. - // - if (auto genericParentDecl = as<GenericDecl>(parentDecl)) - { - // Note: we need to check here to be sure `newDecl` - // is the "inner" declaration and not one of the - // generic parameters, or else we will end up - // checking them at the wrong scope. - // - if (decl == genericParentDecl->inner) - { - decl = parentDecl; - } - } - - return decl; + Decl* result = nullptr; + parentDecl->getMemberDictionary().tryGetValue(decl->getName(), result); + return result; } static bool _isFirstOverridden(Decl* decl) { - decl = _getSameNameDecl(decl); + decl = _getSameNameDecl(as<ContainerDecl>(getParentDecl(decl)), decl); ContainerDecl* parentDecl = decl->parentDecl; @@ -688,47 +1099,291 @@ static bool _isFirstOverridden(Decl* decl) return false; } -void DocMarkdownWriter::writeCallableOverridable(const ASTMarkup::Entry& entry, CallableDecl* callableDecl) +void ParsedDescription::write(DocMarkdownWriter* writer, Decl* decl, StringBuilder& out) { - auto& out = m_builder; - - writePreamble(entry); - + for (auto span : spans) { - // Output the overridable path (ie without terminal generic parameters) - ASTPrinter printer(m_astBuilder); - printer.addOverridableDeclPath(DeclRef<Decl>(callableDecl)); - // Extract the name - out << toSlice("# `") << printer.getStringBuilder() << toSlice("`\n\n"); + switch (span.kind) + { + case DocumentationSpanKind::OrdinaryText: + { + out << span.text; + break; + } + case DocumentationSpanKind::InlineCode: + { + out << "<span class='code'>" << writer->translateToHTMLWithLinks(decl, span.text) << "</span>"; + break; + } + } } +} - writeDescription(entry); - - List<CallableDecl*> sigs; +void ParsedDescription::parse(UnownedStringSlice text) +{ + text = text.trim(); + ownedText = text; + List<UnownedStringSlice> lines; + StringUtil::calcLines(text, lines); + bool isInCodeBlock = false; + for (auto line : lines) { - Decl* sameNameDecl = _getSameNameDecl(callableDecl); + line = line.trim(); + if (line.startsWith("```")) + { + isInCodeBlock = !isInCodeBlock; + spans.add({ line, DocumentationSpanKind::OrdinaryText}); + spans.add({ toSlice("\n"), DocumentationSpanKind::OrdinaryText }); + continue; + } + + if (!isInCodeBlock) + { + bool isInCode = false; + const char* currentSpanStart = line.begin(); + const char* currentSpanEnd = currentSpanStart; + for (Index i = 0; i < line.getLength(); i++) + { + if (line[i] == '`') + { + if (currentSpanEnd > currentSpanStart) + { + spans.add({ + UnownedStringSlice(currentSpanStart, line.begin() + i), + isInCode ? DocumentationSpanKind::InlineCode : DocumentationSpanKind::OrdinaryText }); + currentSpanEnd = currentSpanStart = line.begin() + i + 1; + } + isInCode = !isInCode; + } + else + { + currentSpanEnd = line.begin() + i + 1; + } + } + if (currentSpanEnd > currentSpanStart) + { + spans.add({ UnownedStringSlice(currentSpanStart, currentSpanEnd), + DocumentationSpanKind::OrdinaryText }); + } + spans.add({ toSlice("\n"), DocumentationSpanKind::OrdinaryText }); + } + else + { + spans.add({ line, DocumentationSpanKind::OrdinaryText }); + spans.add({ toSlice("\n"), DocumentationSpanKind::OrdinaryText }); + } + } +} - for (Decl* curDecl = sameNameDecl; curDecl; curDecl = curDecl->nextInContainerWithSameName) +void DeclDocumentation::parse(const UnownedStringSlice& text) +{ + List<UnownedStringSlice> lines; + StringUtil::calcLines(text, lines); + DocPageSection currentSection = DocPageSection::Description; + Dictionary<DocPageSection, StringBuilder> sectionBuilders; + for (Index ptr = 0; ptr < lines.getCount(); ptr++) + { + auto line = lines[ptr].trim(); + if (line.startsWith("@param")) { - CallableDecl* sig = nullptr; - if (GenericDecl* genericDecl = as<GenericDecl>(curDecl)) + currentSection = DocPageSection::Parameter; + line = line.tail(6).trimStart(); + UnownedStringSlice paramDirection; + UnownedStringSlice paramName; + if (line.startsWith("[")) + { + auto closingIndex = line.indexOf(']'); + if (closingIndex != -1) + { + paramDirection = line.subString(1, closingIndex - 1); + line = line.tail(closingIndex + 1).trimStart(); + } + } + auto spaceIndex = line.indexOf(' '); + if (spaceIndex != -1) + { + paramName = line.subString(0, spaceIndex); + line = line.tail(spaceIndex + 1).trimStart(); + } + StringBuilder paramSB; + paramSB << line << "\n"; + ptr++; + for (; ptr < lines.getCount(); ptr++) { - sig = as<CallableDecl>(genericDecl->inner); + auto nextLine = lines[ptr].trim(); + if (nextLine.getLength() == 0 || nextLine.startsWith("@")) + { + ptr--; + break; + } + paramSB << nextLine << "\n"; + } + ParamDocumentation paramDesc; + paramDesc.description.parse(paramSB.getUnownedSlice()); + paramDesc.name = paramName; + paramDesc.direction = paramDirection; + parameters[paramDesc.name] = paramDesc; + continue; + } + else if (line.startsWith("@return")) + { + currentSection = DocPageSection::ReturnInfo; + line = line.tail(7).trim(); + } + else if (line.startsWith("@returns")) + { + currentSection = DocPageSection::ReturnInfo; + line = line.tail(8).trim(); + } + else if (line.startsWith("@remarks")) + { + currentSection = DocPageSection::Remarks; + line = line.tail(8).trim(); + } + else if (line.startsWith("@example")) + { + currentSection = DocPageSection::Example; + line = line.tail(8).trim(); + } + else if (line.startsWith("@see")) + { + currentSection = DocPageSection::SeeAlso; + line = line.tail(4).trim(); + } + else if (line.startsWith("@experimental")) + { + currentSection = DocPageSection::ExperimentalCallout; + line = line.tail(13).trim(); + } + else if (line.startsWith("@internal")) + { + currentSection = DocPageSection::InternalCallout; + line = line.tail(9).trim(); + } + else if (line.startsWith("@deprecated")) + { + currentSection = DocPageSection::DeprecatedCallout; + line = line.tail(11).trim(); + } + else if (line.startsWith("@category")) + { + line = line.tail(9).trimStart(); + auto spaceIndex = line.indexOf(' '); + if (spaceIndex != -1) + { + categoryName = line.subString(0, spaceIndex); + categoryText = line.tail(spaceIndex + 1).trim(); } else { - sig = as<CallableDecl>(curDecl); + categoryName = line.trim(); } - - if (!sig) + continue; + } + sectionBuilders[currentSection] << line << "\n"; + + // If the current directive is a callout, set currentSection back + // to Description after processing the directive line. + switch (currentSection) + { + case DocPageSection::ExperimentalCallout: + case DocPageSection::InternalCallout: + case DocPageSection::DeprecatedCallout: + currentSection = DocPageSection::Description; + break; + } + } + for (auto& kv : sectionBuilders) + { + sections[kv.first].parse(kv.second.getUnownedSlice()); + } +} + +void DocMarkdownWriter::writeCallableOverridable(DocumentPage* page, const ASTMarkup::Entry& primaryEntry, CallableDecl* callableDecl) +{ + SLANG_UNUSED(primaryEntry); + + auto& out = *m_builder; + { + // Output the overridable path (ie without terminal generic parameters) + ASTPrinter printer(m_astBuilder, ASTPrinter::OptionFlag::NoSpecializedExtensionTypeName); + printer.addOverridableDeclPath(DeclRef<Decl>(callableDecl)); + // Extract the name + out << toSlice("# ") << escapeMarkdownText(printer.getStringBuilder()) << toSlice("\n\n"); + } + + // Collect descriptions from all overloads. + StringBuilder descriptionSB, additionalDescriptionSB; + for (auto entry : page->entries) + { + auto markup = entry->m_markup.trim(); + if (markup.getLength() == 0) + continue; + if (entry->m_markup.startsWith("@")) + { + additionalDescriptionSB << markup << "\n"; + } + else if (descriptionSB.getLength() != 0) + { + // We already have a main description, so this is potentially a duplicate. + // If the content is not the same, we will report a warning. + if (!descriptionSB.toString().startsWith(markup)) { - continue; + auto decl = as<Decl>(entry->m_node); + m_sink->diagnose(decl->loc, Diagnostics::ignoredDocumentationOnOverloadCandidate, decl); } + } + else + { + descriptionSB << markup << "\n"; + } + } + + DeclDocumentation funcDoc; + funcDoc.parse(descriptionSB.getUnownedSlice()); + funcDoc.parse(additionalDescriptionSB.getUnownedSlice()); + + registerCategory(page, funcDoc); - // Want to add only the primary sig - if (sig->primaryDecl == nullptr || sig->primaryDecl == sig) + auto& descSection = funcDoc.sections[DocPageSection::Description]; + if (descSection.ownedText.getLength() > 0) + { + out << toSlice("## Description\n\n"); + descSection.write(this, callableDecl, out); + } + + // Collect all overloads from all entries on the page. + List<CallableDecl*> sigs; + List<Requirement> requirements; + HashSet<Decl*> sigSet; + { + for (auto& entry : page->entries) + { + Decl* sameNameDecl = _getSameNameDecl(as<ContainerDecl>(getParentDecl((Decl*)entry->m_node)), callableDecl); + + for (Decl* curDecl = sameNameDecl; curDecl; curDecl = curDecl->nextInContainerWithSameName) { - sigs.add(sig); + CallableDecl* sig = nullptr; + if (GenericDecl* genericDecl = as<GenericDecl>(curDecl)) + { + sig = as<CallableDecl>(genericDecl->inner); + } + else + { + sig = as<CallableDecl>(curDecl); + } + + if (!sig) + { + continue; + } + + // Want to add only the primary sig + if (sig->primaryDecl == nullptr || sig->primaryDecl == sig) + { + if (sigSet.add(sig)) + sigs.add(sig); + } } } @@ -736,8 +1391,6 @@ void DocMarkdownWriter::writeCallableOverridable(const ASTMarkup::Entry& entry, sigs.sort([](CallableDecl* a, CallableDecl* b) -> bool { return a->loc.getRaw() < b->loc.getRaw(); }); } - // The unique requirements found - List<List<Requirement>> uniqueRequirements; // Maps a sig index to a unique requirements set List<Index> requirementsMap; @@ -746,40 +1399,17 @@ void DocMarkdownWriter::writeCallableOverridable(const ASTMarkup::Entry& entry, CallableDecl* sig = sigs[i]; // Add the requirements for all the different versions - List<Requirement> requirements; for (CallableDecl* curSig = sig; curSig; curSig = curSig->nextDecl) { - _addRequirements(sig, requirements); - } - - // TODO(JS): HACK - almost everything is available for HLSL, and is generally not marked up in stdlib - // So assume here it's available - _addRequirement(Requirement{ CodeGenTarget::HLSL, String() }, requirements); - - // We want to make the requirements set unique, so we can look it up easily in the uniqueRequirements, so we sort it - // This also has the benefit of keeping the ordering consistent - requirements.sort(); - - // See if we already have this combination of requirements - Index uniqueRequirementIndex = uniqueRequirements.indexOf(requirements); - if (uniqueRequirementIndex < 0) - { - // If not add it - uniqueRequirementIndex = uniqueRequirements.getCount(); - uniqueRequirements.add(requirements); + requirementsMap.add(_addRequirements(sig, requirements)); } - - // Add the uniqueRequirement index for this sig index - requirementsMap.add(uniqueRequirementIndex); } // Output the signature { out << toSlice("## Signature \n\n"); - out << toSlice("```\n"); + out << toSlice("<pre>\n"); - Index prevRequirementsIndex = -1; - const Int sigCount = sigs.getCount(); for (Index i = 0; i < sigCount; ++i) { @@ -788,22 +1418,18 @@ void DocMarkdownWriter::writeCallableOverridable(const ASTMarkup::Entry& entry, const Index requirementsIndex = requirementsMap[i]; // Output if needs unique requirements - if (uniqueRequirements.getCount() > 1 ) + if (requirements.getCount() > 1 && requirementsIndex != -1) { - if (requirementsIndex != prevRequirementsIndex) - { - out << toSlice("/// See Availability ") << (requirementsIndex + 1) << toSlice("\n"); - prevRequirementsIndex = requirementsIndex; - } + out << toSlice("/// Requires Capability Set ") << (requirementsIndex + 1) << toSlice(":\n"); } writeSignature(sig); + + out << "\n"; } - out << "```\n\n"; + out << "</pre>\n\n"; } - _maybeAppendRequirements(toSlice("## Availability\n\n"), uniqueRequirements); - { // We will use the first documentation found for each parameter type { @@ -822,7 +1448,7 @@ void DocMarkdownWriter::writeCallableOverridable(const ASTMarkup::Entry& entry, { for (Decl* decl : genericDecl->members) { - if (as<GenericTypeParamDecl>(decl) || + if (as<GenericTypeParamDeclBase>(decl) || as<GenericValueParamDecl>(decl)) { genericDecls.add(decl); @@ -836,26 +1462,62 @@ void DocMarkdownWriter::writeCallableOverridable(const ASTMarkup::Entry& entry, } } - if (paramDecls.getCount() > 0 || paramDecls.getCount() > 0) + if (genericDecls.getCount() > 0) + { + out << "## Generic Parameters\n\n"; + + // Document generic parameters + _appendAsBullets(_getUniqueParams(genericDecls, &funcDoc), false, 0); + + out << toSlice("\n"); + } + + if (paramDecls.getCount() > 0) { out << "## Parameters\n\n"; - // Get the unique generics - _appendAsBullets(_getUniqueParams(genericDecls), '`'); - // And parameters - _appendAsBullets(_getUniqueParams(paramDecls), '`'); + // Document ordinary parameters + _appendAsBullets(_getUniqueParams(paramDecls, &funcDoc), false, 0); out << toSlice("\n"); } } } + + auto& returnsSection = funcDoc.sections[DocPageSection::ReturnInfo]; + if (returnsSection.ownedText.getLength() > 0) + { + out << toSlice("## Return value\n"); + returnsSection.write(this, callableDecl, out); + } + + auto& remarksSection = funcDoc.sections[DocPageSection::Remarks]; + if (remarksSection.ownedText.getLength() > 0) + { + out << toSlice("## Remarks\n"); + remarksSection.write(this, callableDecl, out); + } + + auto& exampleSection = funcDoc.sections[DocPageSection::Example]; + if (exampleSection.ownedText.getLength() > 0) + { + out << toSlice("## Example\n"); + exampleSection.write(this, callableDecl, out); + } + + _maybeAppendRequirements(toSlice("## Availability and Requirements\n\n"), requirements); + + auto& seeAlsoSection = funcDoc.sections[DocPageSection::SeeAlso]; + if (seeAlsoSection.ownedText.getLength() > 0) + { + out << toSlice("## See Also\n"); + seeAlsoSection.write(this, callableDecl, out); + } } void DocMarkdownWriter::writeEnum(const ASTMarkup::Entry& entry, EnumDecl* enumDecl) { - writePreamble(entry); - - auto& out = m_builder; + auto& out = *m_builder; out << toSlice("# enum "); Name* name = enumDecl->getName(); @@ -865,16 +1527,23 @@ void DocMarkdownWriter::writeEnum(const ASTMarkup::Entry& entry, EnumDecl* enumD } out << toSlice("\n\n"); + DeclDocumentation declDoc; + declDoc.parse(entry.m_markup.getUnownedSlice()); + declDoc.writeDescription(out, this, enumDecl); + registerCategory(m_currentPage, declDoc); + out << toSlice("## Values \n\n"); - _appendAsBullets(_getAsNameAndTextList(enumDecl->getMembersOfType<EnumCaseDecl>()), '_'); + _appendAsBullets(_getAsNameAndTextList(enumDecl->getMembersOfType<EnumCaseDecl>()), false, '_'); - writeDescription(entry); + declDoc.writeSection(out, this, enumDecl, DocPageSection::Remarks); + declDoc.writeSection(out, this, enumDecl, DocPageSection::Example); + declDoc.writeSection(out, this, enumDecl, DocPageSection::SeeAlso); } void DocMarkdownWriter::_appendEscaped(const UnownedStringSlice& text) { - auto& out = m_builder; + auto& out = *m_builder; const char* start = text.begin(); const char* cur = start; @@ -918,7 +1587,7 @@ void DocMarkdownWriter::_appendEscaped(const UnownedStringSlice& text) void DocMarkdownWriter::_appendDerivedFrom(const UnownedStringSlice& prefix, AggTypeDeclBase* aggTypeDecl) { - auto& out = m_builder; + auto& out = *m_builder; List<InheritanceDecl*> inheritanceDecls; _getDecls(aggTypeDecl, inheritanceDecls); @@ -934,14 +1603,42 @@ void DocMarkdownWriter::_appendDerivedFrom(const UnownedStringSlice& prefix, Agg { out << toSlice(", "); } - out << inheritanceDecl->base; + out << escapeMarkdownText(inheritanceDecl->base->toString()); } } } -void DocMarkdownWriter::_appendAggTypeName(AggTypeDeclBase* aggTypeDecl) +void DocMarkdownWriter::_appendAggTypeName(const ASTMarkup::Entry& entry, Decl* aggTypeDecl) { - auto& out = m_builder; + SLANG_UNUSED(entry); + + auto& out = *m_builder; + +#if 0 + // For extensions, try to see if the documentation defines a more readable title. + if (as<ExtensionDecl>(aggTypeDecl)) + { + auto trimStart = String(entry.m_markup.trimStart()); + if (trimStart.startsWith("@title")) + { + List<UnownedStringSlice> lines; + StringUtil::calcLines(trimStart.getUnownedSlice(), lines); + if (lines.getCount() > 0) + { + out << escapeMarkdownText(lines[0].tail(6).trim()); + + // Remove @title directive from the description markup. + StringBuilder restSB; + for (Index i = 1; i < lines.getCount(); ++i) + { + restSB << lines[i] << "\n"; + } + entry.m_markup = restSB.produceString(); + return; + } + } + } +#endif // This could be lots of different things - struct/class/extension/interface/.. @@ -950,55 +1647,86 @@ void DocMarkdownWriter::_appendAggTypeName(AggTypeDeclBase* aggTypeDecl) if (as<StructDecl>(aggTypeDecl)) { - out << toSlice("struct ") << printer.getStringBuilder(); + out << toSlice("struct ") << escapeMarkdownText(printer.getStringBuilder().produceString()); } else if (as<ClassDecl>(aggTypeDecl)) { - out << toSlice("class ") << printer.getStringBuilder(); + out << toSlice("class ") << escapeMarkdownText(printer.getStringBuilder().produceString()); } else if (as<InterfaceDecl>(aggTypeDecl)) { - out << toSlice("interface ") << printer.getStringBuilder(); + out << toSlice("interface ") << escapeMarkdownText(printer.getStringBuilder().produceString()); } else if (ExtensionDecl* extensionDecl = as<ExtensionDecl>(aggTypeDecl)) { - out << toSlice("extension ") << extensionDecl->targetType; + out << toSlice("extension ") << escapeMarkdownText(extensionDecl->targetType->toString()); _appendDerivedFrom(toSlice(" : "), extensionDecl); } + else if (as<TypeDefDecl>(aggTypeDecl)) + { + out << toSlice("typealias ") << escapeMarkdownText(printer.getStringBuilder().produceString()); + } else { out << toSlice("?"); } } -void DocMarkdownWriter::writeAggType(const ASTMarkup::Entry& entry, AggTypeDeclBase* aggTypeDecl) +void DocMarkdownWriter::writeAggType(DocumentPage* page, const ASTMarkup::Entry& primaryEntry, AggTypeDeclBase* aggTypeDecl) { - writePreamble(entry); - - auto& out = m_builder; + auto& out = *m_builder; // We can write out he name using the printer - - ASTPrinter printer(m_astBuilder); - printer.addDeclPath(DeclRef<Decl>(aggTypeDecl)); - - out << toSlice("# `"); - _appendAggTypeName(aggTypeDecl); - out << toSlice("`\n\n"); - + out << toSlice("# "); + _appendAggTypeName(primaryEntry, aggTypeDecl); + out << toSlice("\n\n"); + List<ExtensionDecl*> conditionalConformanceExts; { List<InheritanceDecl*> inheritanceDecls; _getDecls<InheritanceDecl>(aggTypeDecl, inheritanceDecls); - - if (inheritanceDecls.getCount()) + List<String> baseTypes; + HashSet<String> conditionalBaseTypes; + baseTypes = _getAsStringList(inheritanceDecls); + for (auto entry : page->entries) + { + for (auto member : as<ContainerDecl>(entry->m_node)->members) + { + if (auto inheritanceDecl = as<InheritanceDecl>(member)) + { + if (auto extDecl = as<ExtensionDecl>(entry->m_node)) + { + conditionalConformanceExts.add(extDecl); + conditionalBaseTypes.add(inheritanceDecl->base->toString()); + } + } + } + } + if (baseTypes.getCount()) { - out << "*Implements:* "; - _appendCommaList(_getAsStringList(inheritanceDecls), '`'); + if (as<InterfaceDecl>(aggTypeDecl)) + out << "*Inherits from:* "; + else + out << "*Conforms to:* "; + _appendCommaList(baseTypes, 0); + out << toSlice("\n\n"); + } + if (conditionalBaseTypes.getCount()) + { + out << "*Conditionally conforms to:* "; + List<String> list; + for (auto t : conditionalBaseTypes) + list.add(t); + _appendCommaList(list, 0); out << toSlice("\n\n"); } } - writeDescription(entry); + DeclDocumentation declDoc; + declDoc.parse(primaryEntry.m_markup.getUnownedSlice()); + declDoc.writeDescription(out, this, aggTypeDecl); + registerCategory(page, declDoc); + + declDoc.writeGenericParameters(out, this, aggTypeDecl); { List<AssocTypeDecl*> assocTypeDecls; @@ -1009,7 +1737,7 @@ void DocMarkdownWriter::writeAggType(const ASTMarkup::Entry& entry, AggTypeDeclB out << toSlice("# Associated types\n\n"); for (AssocTypeDecl* assocTypeDecl : assocTypeDecls) - { + { out << "* _" << assocTypeDecl->getName()->text << "_ "; // Look up markup @@ -1020,8 +1748,8 @@ void DocMarkdownWriter::writeAggType(const ASTMarkup::Entry& entry, AggTypeDeclB } out << toSlice("\n"); - List<InheritanceDecl*> inheritanceDecls; - _getDecls<InheritanceDecl>(assocTypeDecl, inheritanceDecls); + List<TypeConstraintDecl*> inheritanceDecls; + _getDecls<TypeConstraintDecl>(assocTypeDecl, inheritanceDecls); if (inheritanceDecls.getCount()) { @@ -1035,101 +1763,449 @@ void DocMarkdownWriter::writeAggType(const ASTMarkup::Entry& entry, AggTypeDeclB } } - if (GenericDecl* genericDecl = as<GenericDecl>(aggTypeDecl->parentDecl)) { - // The parameters, in order - List<Decl*> params; - for (Decl* decl : genericDecl->members) + List<Decl*> fields; + _getDeclsOfType<VarDecl>(this, page, fields); + if (fields.getCount()) { - if (as<GenericTypeParamDecl>(decl) || - as<GenericValueParamDecl>(decl)) - { - params.add(decl); - } + out << toSlice("## Fields\n\n"); + _appendAsBullets(_getAsNameAndTextList(fields), true, 0); + out << toSlice("\n"); } - - if (params.getCount()) + } + + { + List<Decl*> properties; + _getDeclsOfType<PropertyDecl>(this, page, properties); + if (properties.getCount()) { - out << toSlice("## Generic Parameters\n\n"); - _appendAsBullets(_getAsNameAndTextList(params), '`'); + out << toSlice("## Properties\n\n"); + _appendAsBullets(_getAsNameAndTextList(properties), true, 0); out << toSlice("\n"); } } { - List<Decl*> fields; - _getDeclsOfType<VarDecl>(aggTypeDecl, fields); - if (fields.getCount()) + List<Decl*> uniqueMethods; + _getDeclsOfType<CallableDecl>(this, page, uniqueMethods); + + if (uniqueMethods.getCount()) { - out << toSlice("## Fields\n\n"); - _appendAsBullets(_getAsNameAndTextList(fields), '`'); + // Put in source definition order + uniqueMethods.sort([](Decl* a, Decl* b) -> bool { return a->loc.getRaw() < b->loc.getRaw(); }); + + out << "## Methods\n\n"; + _appendAsBullets(_getAsStringList(uniqueMethods), 0); out << toSlice("\n"); } } + if (conditionalConformanceExts.getCount()) { - // Make sure we've got a query-able member dictionary - auto& memberDict = aggTypeDecl->getMemberDictionary(); + out << "## Conditional Conformances\n\n"; + for (auto ext : conditionalConformanceExts) + { + for (auto member : ext->members) + { + auto inheritanceDecl = as<InheritanceDecl>(member); + if (!inheritanceDecl) + continue; + out << "### Conformance to "; + out << escapeMarkdownText(inheritanceDecl->base.type->toString()); + out << "\n"; + StringBuilder sb; + writeExtensionConditions(sb, ext, "\n", false); + List<UnownedStringSlice> lines, nonEmptyLines; + StringUtil::calcLines(sb.getUnownedSlice(), lines); + for (auto line : lines) + { + if (line.trim().getLength()) + nonEmptyLines.add(line); + } + ASTPrinter printer(m_astBuilder); + printer.addDeclPath(aggTypeDecl->getDefaultDeclRef()); + out << "`" << printer.getString() << "` additionally conforms to `"; + out << escapeMarkdownText(inheritanceDecl->base.type->toString()); + if (nonEmptyLines.getCount() != 0) + { + out << "` when the following conditions are met:\n\n"; + for (auto condition : nonEmptyLines) + { + out << " * " << condition << "\n"; + } + } + else + { + out << "`.\n"; + } + } + } + } + declDoc.writeSection(out, this, aggTypeDecl, DocPageSection::Remarks); + declDoc.writeSection(out, this, aggTypeDecl, DocPageSection::Example); + declDoc.writeSection(out, this, aggTypeDecl, DocPageSection::SeeAlso); +} - List<Decl*> uniqueMethods; - for (const auto& [_, decl] : memberDict) +String DocMarkdownWriter::escapeMarkdownText(String text) +{ + StringBuilder sb; + for (auto c : text) + { + switch (c) { - if (!shouldDocumentDecl(decl)) + case '_': + case '*': + case '[': + case ']': + case '<': + case '>': + case '|': + case '.': + case '!': + case '(': + case ')': + sb << '\\'; + sb.appendChar(c); + break; + default: + sb.appendChar(c); + break; + } + } + return sb.produceString(); +} + +void DocMarkdownWriter::ensureDeclPageCreated(ASTMarkup::Entry& entry) +{ + auto page = getPage(as<Decl>(entry.m_node)); + page->entries.add(&entry); +} + +Slang::Misc::Token treatLiteralsAsIdentifier(Slang::Misc::Token token) +{ + // If the token is a literal, we want to treat it as an identifier. + if (token.Type == Slang::Misc::TokenType::StringLiteral) + { + token.Type = Slang::Misc::TokenType::Identifier; + StringBuilder stringSB; + StringEscapeUtil::appendQuoted(StringEscapeUtil::getHandler(StringEscapeUtil::Style::Cpp), token.Content.getUnownedSlice(), stringSB); + token.Content = stringSB.produceString(); + } + else if (token.Type == Slang::Misc::TokenType::IntLiteral || + token.Type == Slang::Misc::TokenType::DoubleLiteral) + { + token.Type = Slang::Misc::TokenType::Identifier; + } + return token; +} + +String DocMarkdownWriter::translateToMarkdownWithLinks(String text, bool strictChildLookup) +{ + StringBuilder sb; + List<DocumentPage*> currentPage; + currentPage.add(m_currentPage); + Slang::Misc::TokenReader reader(text); + bool requireSpaceBeforeNextToken = false; + bool isFirstToken = true; + for (; !reader.IsEnd(); ) + { + auto token = treatLiteralsAsIdentifier(reader.ReadToken()); + + + if (token.Type == Slang::Misc::TokenType::Identifier) + { + if (requireSpaceBeforeNextToken) + sb.append(' '); + auto tokenContent = token.Content; + if (tokenContent == "operator") + { + for (;;) + { + auto operatorToken = reader.ReadToken(); + tokenContent.append(operatorToken.Content); + if (operatorToken.Type != Slang::Misc::TokenType::LParent && + operatorToken.Type != Slang::Misc::TokenType::LBracket) + { + break; + } + } + } + String sectionName; + Decl* referencedDecl = nullptr; + auto page = findPageForToken(currentPage.getLast(), tokenContent, sectionName, referencedDecl); + + if (isFirstToken && strictChildLookup && page && page->parentPage != m_currentPage) + { + // If we are performing a strict child lookup (for displaying the member list of an agg type), + // then we want to ignore any lookup results that refer to a different parent page. + page = nullptr; + } + + if (page) + { + sb.append("["); + sb << escapeMarkdownText(tokenContent.getUnownedSlice()); + sb.append("]("); + sb.append(getDocPath(m_config, page->path)); + if (sectionName.getLength()) + sb << "#" << sectionName; + sb.append(")"); + currentPage.getLast() = page; continue; - CallableDecl* callableDecl = as<CallableDecl>(decl); - if (callableDecl && isVisible(callableDecl)) + } + requireSpaceBeforeNextToken = true; + isFirstToken = false; + } + else + { + switch (token.Type) { - uniqueMethods.add(callableDecl); + case Slang::Misc::TokenType::OpLess: + case Slang::Misc::TokenType::OpGreater: + case Slang::Misc::TokenType::Comma: + case Slang::Misc::TokenType::Dot: + case Slang::Misc::TokenType::IntLiteral: + case Slang::Misc::TokenType::Semicolon: + requireSpaceBeforeNextToken = false; + break; + default: + requireSpaceBeforeNextToken = true; + sb.appendChar(' '); + break; } } - - if (uniqueMethods.getCount()) + // Maintain the `currentPage` stack so we can use the correct starting page + // to lookup things like `Foo<int>.Bar`. When we look up `Bar`, we want to start + // from the same page after looking up `Foo`, so we need to push the stack when we + // see `<` and pop the stack when we see `>`. + if (token.Type == Slang::Misc::TokenType::OpLess) { - // Put in source definition order - uniqueMethods.sort([](Decl* a, Decl* b) -> bool { return a->loc.getRaw() < b->loc.getRaw(); }); + currentPage.add(currentPage.getLast()); + } + else if (token.Type == Slang::Misc::TokenType::OpGreater) + { + if (currentPage.getCount() > 1) + currentPage.removeLast(); + } + sb << escapeMarkdownText(token.Content.getUnownedSlice()); + if (token.Type == Slang::Misc::TokenType::Comma) + sb.appendChar(' '); + } + return sb.produceString(); +} - out << "## Methods\n\n"; - _appendAsBullets(_getAsStringList(uniqueMethods), '`'); - out << toSlice("\n"); +// Implemented in slang-language-server-completion.cpp +bool isDeclKeyword(const UnownedStringSlice& slice); + +bool isKeyword(const UnownedStringSlice& slice) +{ + if (isDeclKeyword(slice)) + return true; + static const char* knownTypeNames[] = { "int", "float", "half", "double", "bool", "void", "uint" }; + for (auto typeName : knownTypeNames) + { + if (slice == typeName) + return true; + } + return false; +} + +String DocMarkdownWriter::translateToHTMLWithLinks(Decl* decl, String text) +{ + SLANG_UNUSED(decl); + StringBuilder sb; + List<DocumentPage*> currentPage; + currentPage.add(m_currentPage); + Slang::Misc::TokenReader reader(text); + bool prevIsIdentifier = false; + for (; !reader.IsEnd(); ) + { + auto token = treatLiteralsAsIdentifier(reader.ReadToken()); + + if (token.Type == Slang::Misc::TokenType::Identifier) + { + if (prevIsIdentifier) + sb.append(' '); + String sectionName; + Decl* referencedDecl = nullptr; + auto page = findPageForToken(currentPage.getLast(), token.Content, sectionName, referencedDecl); + if (page) + { + sb.append("<a href=\""); + sb.append(getDocPath(m_config, page->path)); + if (sectionName.getLength()) + sb << "#" << sectionName; + sb.append("\""); + if (isKeyword(token.Content.getUnownedSlice())) + sb.append(" class=\"code_keyword\""); + else if (as<AggTypeDeclBase>(referencedDecl) || + as<SimpleTypeDecl>(referencedDecl)) + sb.append(" class=\"code_type\""); + else if (as<ParamDecl>(referencedDecl)) + sb.append(" class=\"code_param\""); + else if (as<VarDeclBase>(referencedDecl) || as<EnumCaseDecl>(referencedDecl)) + sb.append(" class=\"code_var\""); + sb.append(">"); + escapeHTMLContent(sb, token.Content.getUnownedSlice()); + sb.append("</a>"); + currentPage.getLast() = page; + continue; + } + prevIsIdentifier = true; + } + else + { + prevIsIdentifier = false; } + // Maintain the `currentPage` stack so we can use the correct starting page + // to lookup things like `Foo<int>.Bar`. When we look up `Bar`, we want to start + // from the same page after looking up `Foo`, so we need to push the stack when we + // see `<` and pop the stack when we see `>`. + if (token.Type == Slang::Misc::TokenType::OpLess) + { + currentPage.add(m_currentPage); + } + else if (token.Type == Slang::Misc::TokenType::OpGreater) + { + if (currentPage.getCount() > 1) + currentPage.removeLast(); + } + bool shouldCloseSpan = false; + if (isKeyword(token.Content.getUnownedSlice())) + { + sb.append("<span class=\"code_keyword\">"); + shouldCloseSpan = true; + } + escapeHTMLContent(sb, token.Content.getUnownedSlice()); + if (shouldCloseSpan) + sb.append("</span>"); + if (token.Type == Slang::Misc::TokenType::Comma) + sb.appendChar(' '); } + return sb.produceString(); } -void DocMarkdownWriter::writePreamble(const ASTMarkup::Entry& entry) +void DocMarkdownWriter::writePreamble() { - SLANG_UNUSED(entry); - auto& out = m_builder; + auto& out = *m_builder; + if (out.getLength() == 0) + { + out << m_config.preamble; + out << toSlice("\n"); + } +} + +const char* getSectionTitle(DocPageSection section) +{ + switch (section) + { + case DocPageSection::Description: return "Description"; + case DocPageSection::Parameter: return "Parameters"; + case DocPageSection::ReturnInfo: return "Return value"; + case DocPageSection::Remarks: return "Remarks"; + case DocPageSection::Example: return "Example"; + case DocPageSection::SeeAlso: return "See also"; + default: return ""; + } +} - //out << toSlice("\n"); +void DeclDocumentation::writeDescription(StringBuilder& out, DocMarkdownWriter* writer, Decl* decl) +{ + // Write all callout sections first. + writeSection(out, writer, decl, DocPageSection::DeprecatedCallout); + writeSection(out, writer, decl, DocPageSection::ExperimentalCallout); + writeSection(out, writer, decl, DocPageSection::InternalCallout); - out.appendRepeatedChar('-', 80); - out << toSlice("\n"); + // Write description section. + writeSection(out, writer, decl, DocPageSection::Description); } -void DocMarkdownWriter::writeDescription(const ASTMarkup::Entry& entry) +void DeclDocumentation::writeGenericParameters(StringBuilder& out, DocMarkdownWriter* writer, Decl* decl) { - auto& out = m_builder; + GenericDecl* genericDecl = as<GenericDecl>(decl->parentDecl); + if (!genericDecl) + return; - if (entry.m_markup.getLength() > 0) + // The parameters, in order + List<Decl*> params; + for (Decl* member : genericDecl->members) { - out << toSlice("## Description\n\n"); + if (as<GenericTypeParamDeclBase>(member) || + as<GenericValueParamDecl>(member)) + { + params.add(member); + } + } - out << entry.m_markup.getUnownedSlice(); -#if 0 - UnownedStringSlice text(entry.m_markup.getUnownedSlice()), line; - while (StringUtil::extractLine(text, line)) + if (params.getCount()) + { + out << toSlice("## Generic Parameters\n\n"); + auto paramList = writer->_getAsNameAndTextList(params); + + // Append names with constraints if any. + for (Index i = 0; i < paramList.getCount(); i++) { - out << line << toSlice("\n"); + auto param = params[i]; + if (paramList[i].text.getLength() == 0) + { + ParamDocumentation paramDoc; + if (parameters.tryGetValue(getText(param->getName()), paramDoc)) + { + StringBuilder sb; + sb << paramDoc.description.ownedText; + paramList[i].text = sb.produceString(); + } + } } -#endif + writer->_appendAsBullets(paramList, false, 0); out << toSlice("\n"); } } -void DocMarkdownWriter::writeDecl(const ASTMarkup::Entry& entry, Decl* decl) +void DeclDocumentation::writeSection(StringBuilder& out, DocMarkdownWriter* writer, Decl* decl, DocPageSection section) +{ + SLANG_UNUSED(decl); + ParsedDescription* sectionDoc = sections.tryGetValue(section); + if (!sectionDoc) + return; + + switch (section) + { + case DocPageSection::DeprecatedCallout: + out << "> #### Deprecated Feature\n"; + out << "> The feature described in this page is marked as deprecated, and may be removed in a future release.\n"; + out << "> Users are advised to avoid using this feature, and to migrate to a newer alternative.\n"; + out << "\n"; + return; + case DocPageSection::ExperimentalCallout: + out << "> #### Experimental Feature\n"; + out << "> The feature described in this page is marked as experimental, and may be subject to change in future releases.\n"; + out << "> Users are advised that any code that depend on this feature may not be compilable by future versions of the compiler.\n"; + out << "\n"; + return; + case DocPageSection::InternalCallout: + out << "> #### Internal Feature\n"; + out << "> The feature described in this page is marked as an internal implementation detail, and is not intended for use by end-users.\n"; + out << "> Users are advised to avoid using this declaration directly, as it may be removed or changed in future releases.\n"; + out << "\n"; + return; + } + if (sectionDoc && sectionDoc->ownedText.getLength() > 0) + { + out << "## " << getSectionTitle(section) << "\n\n"; + sectionDoc->write(writer, decl, out); + } +} + +void DocMarkdownWriter::createPage(DocMarkdownWriter::WriteDeclMode mode, ASTMarkup::Entry& entry, Decl* decl) { // Skip these they will be output as part of their respective 'containers' - if (as<ParamDecl>(decl) || as<EnumCaseDecl>(decl) || as<AssocTypeDecl>(decl) || as<InheritanceDecl>(decl) || as<ThisTypeDecl>(decl)) + if (as<ParamDecl>(decl) || + as<EnumCaseDecl>(decl) || + as<AssocTypeDecl>(decl) || + as<TypeConstraintDecl>(decl) || + as<ThisTypeDecl>(decl) || + as<AccessorDecl>(decl)) { return; } @@ -1138,26 +2214,35 @@ void DocMarkdownWriter::writeDecl(const ASTMarkup::Entry& entry, Decl* decl) { if (_isFirstOverridden(callableDecl)) { - writeCallableOverridable(entry, callableDecl); + if (mode == WriteDeclMode::Header) + ensureDeclPageCreated(entry); } } - else if (EnumDecl* enumDecl = as<EnumDecl>(decl)) + else if (as<EnumDecl>(decl)) { - writeEnum(entry, enumDecl); + if (mode == WriteDeclMode::Header) + ensureDeclPageCreated(entry); } - else if (AggTypeDeclBase* aggType = as<AggTypeDeclBase>(decl)) + else if (as<AggTypeDeclBase>(decl)) { - writeAggType(entry, aggType); + if (mode == WriteDeclMode::Header) + ensureDeclPageCreated(entry); } - else if (VarDecl* varDecl = as<VarDecl>(decl)) + else if (as<VarDecl>(decl)) { // If part of aggregate type will be output there. - if (as<AggTypeDecl>(varDecl->parentDecl)) - { - return; - } - - writeVar(entry, varDecl); + if (mode == WriteDeclMode::Header) + ensureDeclPageCreated(entry); + } + else if (as<TypeDefDecl>(decl)) + { + if (mode == WriteDeclMode::Header) + ensureDeclPageCreated(entry); + } + else if (as<PropertyDecl>(decl)) + { + if (mode == WriteDeclMode::Header) + ensureDeclPageCreated(entry); } else if (as<GenericDecl>(decl)) { @@ -1165,9 +2250,113 @@ void DocMarkdownWriter::writeDecl(const ASTMarkup::Entry& entry, Decl* decl) } } +void DocMarkdownWriter::registerCategory(DocumentPage* page, DeclDocumentation& doc) +{ + if (doc.categoryText.getLength() != 0) + { + m_categories[doc.categoryName] = doc.categoryText; + } + else if (!m_categories.containsKey(doc.categoryName)) + { + m_categories[doc.categoryName] = doc.categoryName; + } + page->category = doc.categoryName; +} + + bool DocMarkdownWriter::isVisible(const Name* name) { - return name == nullptr || !name->text.startsWith(toSlice("__")); + return name == nullptr || !name->text.startsWith(toSlice("__")) + || m_config.visibleDeclNames.contains(getText((Name*)name)); +} + +DocumentPage* DocMarkdownWriter::findPageForToken(DocumentPage* currentPage, String token, String& outSectionName, Decl*& outDecl) +{ + while (currentPage) + { + // Are there any children pages whose short title matches `token`? + // If so, return the path of that page. + if (currentPage->shortName == token) + { + outDecl = currentPage->decl; + return currentPage; + } + if (auto rs = currentPage->findChildByShortName(token.getUnownedSlice())) + { + outDecl = rs->decl; + return rs; + } + // Is `token` documented as a section on current page? + // This will be the case for parameters and generic parameters. + if (currentPage->decl) + { + for (auto entry : currentPage->entries) + { + auto containerDecl = as<ContainerDecl>(entry->m_node); + if (!containerDecl) + continue; + if (auto genericParent = as<GenericDecl>(containerDecl->parentDecl)) + { + for (auto member : genericParent->members) + { + if (getText(member->getName()) == token) + { + outDecl = member; + if (as<GenericTypeParamDeclBase>(member)) + outSectionName = String("typeparam-") + token; + else if (as<GenericValueParamDecl>(member)) + outSectionName = String("decl-") + token; + return currentPage; + } + } + } + for (auto member : containerDecl->members) + { + if (as<ParamDecl>(member) || as<EnumCaseDecl>(member)) + { + if (getText(member->getName()) == token) + { + outDecl = member; + outSectionName = String("decl-") + token; + return currentPage; + } + } + } + } + } + + currentPage = currentPage->parentPage; + } + // Otherwise, try find in global decls. + if (auto rs = m_typesPage->findChildByShortName(token.getUnownedSlice())) + { + outDecl = rs->decl; + return rs; + } + if (auto rs = m_interfacesPage->findChildByShortName(token.getUnownedSlice())) + { + outDecl = rs->decl; + return rs; + } + if (auto rs = m_globalDeclsPage->findChildByShortName(token.getUnownedSlice())) + { + outDecl = rs->decl; + return rs; + } + return nullptr; +} + +String DocMarkdownWriter::findLinkForToken(DocumentPage* currentPage, String token) +{ + String sectionName; + Decl* decl = nullptr; + if (auto page = findPageForToken(currentPage, token, sectionName, decl)) + { + if (sectionName.getLength() == 0) + return page->path; + return page->path + "#" + sectionName; + } + return String(); } bool DocMarkdownWriter::isVisible(const ASTMarkup::Entry& entry) @@ -1179,7 +2368,7 @@ bool DocMarkdownWriter::isVisible(const ASTMarkup::Entry& entry) } Decl* decl = as<Decl>(entry.m_node); - return decl == nullptr || isVisible(decl->getName()); + return decl == nullptr || isVisible(decl); } bool DocMarkdownWriter::isVisible(Decl* decl) @@ -1188,22 +2377,362 @@ bool DocMarkdownWriter::isVisible(Decl* decl) { return false; } - + bool parentIsVisible = true; + auto parent = decl; + while (parent) + { + if (auto extDecl = as<ExtensionDecl>(parent)) + { + if (auto targetDecl = isDeclRefTypeOf<Decl>(extDecl->targetType)) + { + parentIsVisible = parentIsVisible && isVisible(targetDecl.getDecl()); + parent = targetDecl.getDecl(); + } + else + { + parent = getParentDecl(parent); + } + } + else + { + parent = getParentDecl(parent); + } + if (as<AggTypeDeclBase>(parent)) + { + parentIsVisible = parentIsVisible && isVisible(parent); + } + } auto entry = m_markup->getEntry(decl); - return entry == nullptr || entry->m_visibility == MarkupVisibility::Public; + return parentIsVisible && (entry == nullptr || entry->m_visibility == MarkupVisibility::Public); } -void DocMarkdownWriter::writeAll() +void DocumentationConfig::parse(UnownedStringSlice config) { - for (const auto& entry : m_markup->getEntries()) + List<UnownedStringSlice> lines; + StringUtil::calcLines(config, lines); + Index ptr = 0; + for (;ptr < lines.getCount(); ptr++) + { + auto line = lines[ptr]; + if (line.startsWith(toSlice("@preamble:"))) + { + ptr++; + StringBuilder preambleSB; + for (; ptr < lines.getCount(); ptr++) + { + if (lines[ptr].startsWith("@end")) + break; + preambleSB << lines[ptr] << "\n"; + } + ptr++; + preamble = preambleSB.produceString(); + } + else if (line.startsWith(toSlice("@title:"))) + { + title = line.tail(7).trim(); + } + else if (line.startsWith(toSlice("@libname:"))) + { + libName = line.tail(9).trim(); + } + else if (line.startsWith(toSlice("@rootdir:"))) + { + rootDir = line.tail(9).trim(); + } + else if (line.startsWith("@includedecl:")) + { + ptr++; + for (; ptr < lines.getCount(); ptr++) + { + if (lines[ptr].startsWith("@end")) + break; + auto name = lines[ptr].trim(); + if (name.getLength()) + visibleDeclNames.add(name); + } + ptr++; + } + } +} + +void sortPages(DocumentPage* page) +{ + page->children.sort([](DocumentPage* a, DocumentPage* b) -> bool { return a->shortName < b->shortName; }); +} + +void DocMarkdownWriter::generateSectionIndexPage(DocumentPage* page) +{ + // Generate the content for meta section index page. + StringBuilder& sb = page->get(); + sb << m_config.preamble; + sb << "# " << page->title; + sb << "\n\n"; + sb << m_config.libName; + sb << " defines the following " << String(page->title).toLower() << ":\n\n"; + sortPages(page); + + for (auto child : page->children) + { + sb << "- [" << escapeMarkdownText(child->shortName) << "](" << getDocPath(m_config, child->path) << ")\n"; + } +} + +DocumentPage* DocMarkdownWriter::writeAll(UnownedStringSlice configStr) +{ + m_config.parse(configStr); + + auto addBuiltinPage = [&](DocumentPage* parent, UnownedStringSlice path, UnownedStringSlice title, UnownedStringSlice shortTitle) + { + RefPtr<DocumentPage> page = new DocumentPage(); + page->title = title; + page->path = path; + page->shortName = shortTitle; + page->decl = nullptr; + if (parent) + { + parent->children.add(page); + } + m_output[page->path] = page; + return page.get(); + }; + m_rootPage = addBuiltinPage(nullptr, toSlice("index.md"), m_config.title.getUnownedSlice(), toSlice("Standard Library Reference")); + m_rootPage->skipWrite = true; + + m_interfacesPage = addBuiltinPage(m_rootPage.get(), toSlice("interfaces/index.md"), toSlice("Interfaces"), toSlice("Interfaces")); + m_typesPage = addBuiltinPage(m_rootPage.get(), toSlice("types/index.md"), toSlice("Types"), toSlice("Types")); + m_globalDeclsPage = addBuiltinPage(m_rootPage.get(), toSlice("global-decls/index.md"), toSlice("Global Declarations"), toSlice("Global Declarations")); + + // In the first pass, we create all the pages so we can reference them + // when writing the content. + for (auto& entry : m_markup->getEntries()) { Decl* decl = as<Decl>(entry.m_node); if (decl && isVisible(entry)) { - writeDecl(entry, decl); + createPage(WriteDeclMode::Header, entry, decl); + } + } + // In the second pass, actually writes the content to each page. + writePageRecursive(m_rootPage.get()); + + generateSectionIndexPage(m_interfacesPage); + generateSectionIndexPage(m_typesPage); + generateSectionIndexPage(m_globalDeclsPage); + + return m_rootPage.get(); +} + +void DocMarkdownWriter::writePage(DocumentPage* page) +{ + if (page->skipWrite) + return; + if (page->entries.getCount() == 0) + return; + + m_currentPage = page; + m_builder = &(page->get()); + + writePreamble(); + + Decl* decl = (Decl*)page->getFirstEntry()->m_node; + if (CallableDecl* callableDecl = as<CallableDecl>(decl)) + { + writeCallableOverridable(page, *page->getFirstEntry(), callableDecl); + } + else if (EnumDecl* enumDecl = as<EnumDecl>(decl)) + { + writeEnum(*page->getFirstEntry(), enumDecl); + } + else if (AggTypeDeclBase* aggTypeDeclBase = as<AggTypeDeclBase>(decl)) + { + // Find the primary decl. + ASTMarkup::Entry* primaryEntry = page->getFirstEntry(); + AggTypeDeclBase* primaryDecl = aggTypeDeclBase; + for (auto entry : page->entries) + { + if (auto aggTypeDecl = as<AggTypeDecl>(entry->m_node)) + { + primaryEntry = entry; + primaryDecl = aggTypeDecl; + break; + } + } + writeAggType(page, *primaryEntry, primaryDecl); + } + else if (PropertyDecl* propertyDecl = as<PropertyDecl>(decl)) + { + writeProperty(*page->getFirstEntry(), propertyDecl); + } + else if (VarDecl* varDecl = as<VarDecl>(decl)) + { + writeVar(*page->getFirstEntry(), varDecl); + } + else if (TypeDefDecl* typeDefDecl = as<TypeDefDecl>(decl)) + { + writeTypeDef(*page->getFirstEntry(), typeDefDecl); + } +} + +void DocMarkdownWriter::writePageRecursive(DocumentPage* page) +{ + writePage(page); + for (auto child : page->children) + { + writePageRecursive(child); + } +} + +void writeTOCImpl(StringBuilder& sb, DocMarkdownWriter* writer, DocumentationConfig& config, DocumentPage* page); + +void writeTOCChildren(StringBuilder& sb, DocMarkdownWriter* writer, DocumentationConfig& config, DocumentPage* page) +{ + if (page->children.getCount() == 0) + return; + + sb << R"(<ul class="toc_list">)" << "\n"; + + // Don't sort the root page. + if (page->path != "index.md") + sortPages(page); + + Dictionary<String, List<DocumentPage*>> categories; + for (auto child : page->children) + { + categories[child->category].add(child); + } + List<String> categoryNames; + for (auto& kv : categories) + { + categoryNames.add(kv.first); + } + categoryNames.sort(); + auto parentPath = Path::getParentDirectory(page->path); + parentPath.append("/"); + for (auto& cat : categoryNames) + { + // Skip non-categorized pages first. + if (cat.getLength() == 0) + continue; + sb << "<li data-link=\"" << config.rootDir << parentPath << cat << "\"><span>"; + escapeHTMLContent(sb, writer->m_categories[cat].getUnownedSlice()); + sb << "</span>\n"; + sb << "<ul class=\"toc_list\">\n"; + for (auto child : categories[cat]) + { + writeTOCImpl(sb, writer, config, child); + } + sb << "</ul>\n"; + sb << "</li>\n"; + + // Create a landing page for the category. + RefPtr<DocumentPage> landingPage = new DocumentPage(); + landingPage->title = writer->m_categories[cat]; + landingPage->path = parentPath + cat + ".md"; + landingPage->shortName = writer->m_categories[cat]; + landingPage->decl = nullptr; + landingPage->parentPage = page; + landingPage->contentSB << config.preamble; + landingPage->contentSB << "# " << landingPage->title << "\n\nThis category contains the following declarations:\n\n"; + for (auto child : categories[cat]) + { + landingPage->contentSB << "#### [" << writer->escapeMarkdownText(child->title) << "](" << + child->path << ")\n\n"; } + page->children.add(landingPage); } + + for (auto child : categories[""]) + { + writeTOCImpl(sb, writer, config, child); + } + sb << "</ul>\n"; } +void writeTOCImpl(StringBuilder& sb, DocMarkdownWriter* writer, DocumentationConfig& config, DocumentPage* page) +{ + sb << R"(<li data-link=")" << getDocPath(config, page->path) << R"("><span>)"; + escapeHTMLContent(sb, page->shortName.getUnownedSlice()); + sb << "</span>\n"; + writeTOCChildren(sb, writer, config, page); + sb << "</li>"; +} + +String DocMarkdownWriter::writeTOC() +{ + StringBuilder sb; + sb << R"(<ul class="toc_root_list"><li data-link=")" + << m_config.rootDir << R"(index"><span>)" + << m_config.title << "</span>\n"; + writeTOCChildren(sb, this, m_config, m_rootPage); + sb << "</li></ul>\n"; + return sb.produceString(); +} + +DocumentPage* DocMarkdownWriter::getPage(Decl* decl) +{ + auto path = _getDocFilePath(decl); + RefPtr<DocumentPage> page; + if (m_output.tryGetValue(path, page)) + { + return page.get(); + } + page = new DocumentPage(); + page->title = _getFullName(decl); + page->path = path; + page->shortName = _getName(decl); + page->decl = decl; + m_output[path] = page; + + // If parent page exists, add this page to it's children + if (path.endsWith("index.md")) + path = Path::getParentDirectory(path); + auto parentPath = Path::getParentDirectory(path); + parentPath = parentPath + "/index.md"; + RefPtr<DocumentPage> parentPage; + if (m_output.tryGetValue(parentPath, parentPage)) + { + parentPage->children.add(page); + page->parentPage = parentPage.get(); + } + return page.get(); +} + +StringBuilder* DocMarkdownWriter::getBuilder(Decl* decl) +{ + m_currentPage = getPage(decl); + return &(m_currentPage->get()); +} + +void writePageToDisk(DocumentPage* page) +{ + if (!page->skipWrite) + { + auto dir = Path::getParentDirectory(page->path); + if (dir.getLength()) + Path::createDirectoryRecursive(dir); + File::writeAllText(page->path, page->contentSB.toString()); + } + for (auto child : page->children) + { + writePageToDisk(child); + } +} + +void DocumentPage::writeToDisk() +{ + writePageToDisk(this); +} + +DocumentPage* DocumentPage::findChildByShortName(const UnownedStringSlice& name) +{ + for (auto child : children) + { + if (child->shortName == name) + return child; + } + return nullptr; +} + + } // namespace Slang diff --git a/source/slang/slang-doc-markdown-writer.h b/source/slang/slang-doc-markdown-writer.h index ff4c50759..813e674ae 100644 --- a/source/slang/slang-doc-markdown-writer.h +++ b/source/slang/slang-doc-markdown-writer.h @@ -11,11 +11,99 @@ namespace Slang { class ASTBuilder; +struct DocumentPage : public RefObject +{ + String title; + String shortName; + String path; + String category; + StringBuilder contentSB; + Decl* decl = nullptr; + bool skipWrite = false; + DocumentPage* parentPage = nullptr; + DocumentPage* findChildByShortName(const UnownedStringSlice& shortName); + StringBuilder& get() { return contentSB; } + List<RefPtr<DocumentPage>> children; + + // List of entries to document on this page. + OrderedHashSet<ASTMarkup::Entry*> entries; + ASTMarkup::Entry* getFirstEntry() { return *entries.begin(); } + void writeToDisk(); +}; + +struct DocumentationConfig +{ + String preamble; + String title; + String libName; + String rootDir; + HashSet<String> visibleDeclNames; + void parse(UnownedStringSlice configStr); +}; + +enum DocumentationSpanKind +{ + OrdinaryText, + InlineCode, +}; +struct ParsedDocumentationSpan +{ + String text; + DocumentationSpanKind kind; +}; +struct DocMarkdownWriter; + +struct ParsedDescription +{ + String ownedText; + List<ParsedDocumentationSpan> spans; + void parse(UnownedStringSlice text); + void write(DocMarkdownWriter* writer, Decl* decl, StringBuilder& out); +}; + +struct ParamDocumentation +{ + String name; + String direction; + ParsedDescription description; +}; + +enum class DocPageSection +{ + Description, + Parameter, + ReturnInfo, + Remarks, + Example, + SeeAlso, + InternalCallout, + ExperimentalCallout, + DeprecatedCallout, +}; + +struct DeclDocumentation +{ + Dictionary<String, ParamDocumentation> parameters; + Dictionary<DocPageSection, ParsedDescription> sections; + String categoryName; + String categoryText; + + void parse(const UnownedStringSlice& text); + void writeDescription(StringBuilder& out, DocMarkdownWriter* writer, Decl* decl); + void writeGenericParameters(StringBuilder& out, DocMarkdownWriter* writer, Decl* decl); + void writeSection(StringBuilder& sb, DocMarkdownWriter* writer, Decl* decl, DocPageSection section); +}; + struct DocMarkdownWriter { typedef ASTPrinter::Part Part; typedef ASTPrinter::PartPair PartPair; + enum WriteDeclMode + { + Header, Content + }; + struct Signature { struct GenericParam @@ -34,46 +122,59 @@ struct DocMarkdownWriter { typedef Requirement ThisType; - bool operator<(const ThisType& rhs) const { return Index(target) < Index(rhs.target) || (target == rhs.target && value < rhs.value); } + bool operator==(const ThisType& rhs) const { return capabilitySet == rhs.capabilitySet; } + SLANG_FORCE_INLINE bool operator!=(const ThisType& rhs) const { return !(capabilitySet == rhs.capabilitySet); } - bool operator==(const ThisType& rhs) const { return target == rhs.target && value == rhs.value; } - SLANG_FORCE_INLINE bool operator!=(const ThisType& rhs) const { return !(*this == rhs); } - - /// Using CodeGenTarget may not be most appropriate, perhaps it should use a CapabilityAtom - /// For now use target, and since we always go through Source -> byte code it is fairly straight forward to understand the - /// meaning. - CodeGenTarget target; - /// The 'value' requirement associated with a target. If it's empty it's just the target that is a requirement. - String value; + CapabilitySet capabilitySet; }; /// Write out all documentation to the output buffer - void writeAll(); + DocumentPage* writeAll(UnownedStringSlice configStr); + String writeTOC(); + + void ensureDeclPageCreated(ASTMarkup::Entry& entry); + String translateToHTMLWithLinks(Decl* decl, String text); + String translateToMarkdownWithLinks(String text, bool strictChildLookup = false); + String escapeMarkdownText(String text); + void generateSectionIndexPage(DocumentPage* page); + void writePageRecursive(DocumentPage* page); + void writePage(DocumentPage* page); /// This will write information about *all* of the overridden versions of a function/method - void writeCallableOverridable(const ASTMarkup::Entry& entry, CallableDecl* callable); + void writeCallableOverridable(DocumentPage* page, const ASTMarkup::Entry& entry, CallableDecl* callable); void writeEnum(const ASTMarkup::Entry& entry, EnumDecl* enumDecl); - void writeAggType(const ASTMarkup::Entry& entry, AggTypeDeclBase* aggTypeDecl); - void writeDecl(const ASTMarkup::Entry& entry, Decl* decl); + void writeAggType(DocumentPage* page, const ASTMarkup::Entry& entry, AggTypeDeclBase* aggTypeDecl); void writeVar(const ASTMarkup::Entry& entry, VarDecl* varDecl); + void writeProperty(const ASTMarkup::Entry& entry, PropertyDecl* propertyDecl); + void writeTypeDef(const ASTMarkup::Entry& entry, TypeDefDecl* typeDefDecl); - void writePreamble(const ASTMarkup::Entry& entry); - void writeDescription(const ASTMarkup::Entry& entry); + void createPage(WriteDeclMode mode, ASTMarkup::Entry& entry, Decl* decl); + void registerCategory(DocumentPage* page, DeclDocumentation& doc); + + void writePreamble(); void writeSignature(CallableDecl* callableDecl); + void writeExtensionConditions(StringBuilder& sb, ExtensionDecl* decl, const char* prefix, bool isHtml); bool isVisible(const ASTMarkup::Entry& entry); bool isVisible(Decl* decl); bool isVisible(const Name* name); + DocumentPage* findPageForToken(DocumentPage* currentPage, String token, String& outSectionName, Decl*& outDecl); + String findLinkForToken(DocumentPage* currentPage, String token); + /// Get the output string - const StringBuilder& getOutput() const { return m_builder; } + Dictionary<String, RefPtr<DocumentPage>>& getOutput() { return m_output; } + + DocumentPage* getPage(Decl* decl); + StringBuilder* getBuilder(Decl* decl); /// Ctor. - DocMarkdownWriter(ASTMarkup* markup, ASTBuilder* astBuilder) : + DocMarkdownWriter(ASTMarkup* markup, ASTBuilder* astBuilder, DiagnosticSink* sink) : m_markup(markup), - m_astBuilder(astBuilder) + m_astBuilder(astBuilder), + m_sink(sink) { } @@ -84,13 +185,16 @@ struct DocMarkdownWriter struct NameAndText { + Decl* decl = nullptr; String name; String text; }; - List<NameAndText> _getUniqueParams(const List<Decl*>& decls); + List<NameAndText> _getUniqueParams(const List<Decl*>& decls, DeclDocumentation* funcDoc); String _getName(Decl* decl); + String _getFullName(Decl* decl); + String _getDocFilePath(Decl* decl); String _getName(InheritanceDecl* decl); NameAndText _getNameAndText(ASTMarkup::Entry* entry, Decl* decl); @@ -120,24 +224,35 @@ struct DocMarkdownWriter List<NameAndText> _getAsNameAndTextList(const List<Decl*>& in); List<String> _getAsStringList(const List<Decl*>& in); - void _appendAsBullets(const List<NameAndText>& values, char wrapChar); + void _appendAsBullets(const List<NameAndText>& values, bool insertLinkForName, char wrapChar); void _appendAsBullets(const List<String>& values, char wrapChar); void _appendCommaList(const List<String>& strings, char wrapChar); - void _appendRequirements(const List<DocMarkdownWriter::Requirement>& requirements); - void _maybeAppendRequirements(const UnownedStringSlice& title, const List<List<DocMarkdownWriter::Requirement>>& uniqueRequirements); - void _writeTargetRequirements(const Requirement* reqs, Index reqsCount); + void _appendRequirements(const DocMarkdownWriter::Requirement& requirements); + void _maybeAppendRequirements(const UnownedStringSlice& title, const List<DocMarkdownWriter::Requirement>& uniqueRequirements); + + void _appendExpr(StringBuilder& sb, Expr* expr); /// Appends prefix and the list of types derived from void _appendDerivedFrom(const UnownedStringSlice& prefix, AggTypeDeclBase* aggTypeDecl); void _appendEscaped(const UnownedStringSlice& text); - void _appendAggTypeName(AggTypeDeclBase* aggTypeDecl); + void _appendAggTypeName(const ASTMarkup::Entry& entry, Decl* aggTypeDecl); ASTMarkup* m_markup; ASTBuilder* m_astBuilder; - StringBuilder m_builder; + DiagnosticSink* m_sink; + StringBuilder* m_builder = nullptr; + DocumentPage* m_currentPage = nullptr; + Dictionary<String, RefPtr<DocumentPage>> m_output; + RefPtr<DocumentPage> m_rootPage; + RefPtr<DocumentPage> m_typesPage; + RefPtr<DocumentPage> m_interfacesPage; + RefPtr<DocumentPage> m_globalDeclsPage; + + DocumentationConfig m_config; + Dictionary<String, String> m_categories; }; } // namespace Slang diff --git a/source/slang/slang-language-server-completion.cpp b/source/slang/slang-language-server-completion.cpp index 0c7f10ad7..14613d08b 100644 --- a/source/slang/slang-language-server-completion.cpp +++ b/source/slang/slang-language-server-completion.cpp @@ -23,7 +23,7 @@ static const char* kDeclKeywords[] = { "protected", "typedef", "typealias", "uniform", "export", "groupshared", "extension", "associatedtype", "namespace", "This", "using", "__generic", "__exported", "import", "enum", "cbuffer", "tbuffer", "func", - "functype", "typename", "each", "expand" }; + "functype", "typename", "each", "expand", "where" }; static const char* kStmtKeywords[] = { "if", "else", "switch", "case", "default", "return", "try", "throw", "throws", "catch", "while", "for", @@ -74,6 +74,16 @@ static const char* hlslSemanticNames[] = { "SV_ShadingRate", }; +bool isDeclKeyword(const UnownedStringSlice& slice) +{ + for (auto keyword : kDeclKeywords) + { + if (slice == keyword) + return true; + } + return false; +} + SlangResult CompletionContext::tryCompleteHLSLSemantic() { if (version->linkage->contentAssistInfo.completionSuggestions.scopeKind != diff --git a/source/slang/slang.cpp b/source/slang/slang.cpp index 5fcf20e0a..4bdbbd0aa 100644 --- a/source/slang/slang.cpp +++ b/source/slang/slang.cpp @@ -312,8 +312,39 @@ SlangResult Session::checkPassThroughSupport(SlangPassThrough inPassThrough) return checkExternalCompilerSupport(this, PassThroughMode(inPassThrough)); } +void Session::writeStdlibDoc(String config) +{ + ASTBuilder* astBuilder = getBuiltinLinkage()->getASTBuilder(); + SourceManager* sourceManager = getBuiltinSourceManager(); + + DiagnosticSink sink(sourceManager, Lexer::sourceLocationLexer); + + List<String> docStrings; + + // For all the modules add their doc output to docStrings + for (Module* stdlibModule : stdlibModules) + { + RefPtr<ASTMarkup> markup(new ASTMarkup); + ASTMarkupUtil::extract(stdlibModule->getModuleDecl(), sourceManager, &sink, markup); + + DocMarkdownWriter writer(markup, astBuilder, &sink); + auto rootPage = writer.writeAll(config.getUnownedSlice()); + File::writeAllText("toc.html", writer.writeTOC()); + rootPage->writeToDisk(); + } + ComPtr<ISlangBlob> diagnosticBlob; + sink.getBlobIfNeeded(diagnosticBlob.writeRef()); + if (diagnosticBlob && diagnosticBlob->getBufferSize() != 0) + { + // Write the diagnostic blob to stdout. + fprintf(stderr, "%s", (const char*)diagnosticBlob->getBufferPointer()); + } +} + SlangResult Session::compileStdLib(slang::CompileStdLibFlags compileFlags) { + SLANG_AST_BUILDER_RAII(m_builtinLinkage->getASTBuilder()); + if (m_builtinLinkage->mapNameToLoadedModules.getCount()) { // Already have a StdLib loaded @@ -339,40 +370,15 @@ SlangResult Session::compileStdLib(slang::CompileStdLibFlags compileFlags) if (compileFlags & slang::CompileStdLibFlag::WriteDocumentation) { - // Not 100% clear where best to get the ASTBuilder from, but from the linkage shouldn't - // cause any problems with scoping - - ASTBuilder* astBuilder = getBuiltinLinkage()->getASTBuilder(); - SourceManager* sourceManager = getBuiltinSourceManager(); - - DiagnosticSink sink(sourceManager, Lexer::sourceLocationLexer); - - List<String> docStrings; - - // For all the modules add their doc output to docStrings - for (Module* stdlibModule : stdlibModules) + // Load config file first. + String configText; + if (SLANG_FAILED(File::readAllText("config.txt", configText))) { - RefPtr<ASTMarkup> markup(new ASTMarkup); - ASTMarkupUtil::extract(stdlibModule->getModuleDecl(), sourceManager, &sink, markup); - - DocMarkdownWriter writer(markup, astBuilder); - writer.writeAll(); - docStrings.add(writer.getOutput()); + fprintf(stderr, "Error writing documentation: config file not found on current working directory.\n"); } - - // Combine all together in stdlib-doc.md output fiel + else { - String fileName("stdlib-doc.md"); - - RefPtr<FileStream> stream = new FileStream; - SLANG_RETURN_ON_FAIL(stream->init(fileName, FileMode::Create)); - StreamWriter writer; - SLANG_RETURN_ON_FAIL(writer.init(stream)); - - for (auto& docString : docStrings) - { - SLANG_RETURN_ON_FAIL(writer.write(docString)); - } + writeStdlibDoc(configText); } } @@ -3161,28 +3167,7 @@ SlangResult FrontEndCompileRequest::executeActionsInner() // After semantic checking is performed we can try and output doc information for this if (optionSet.getBoolOption(CompilerOptionName::Doc)) { - // Not 100% clear where best to get the ASTBuilder from, but from the linkage shouldn't - // cause any problems with scoping - ASTBuilder* astBuilder = getLinkage()->getASTBuilder(); - - ISlangWriter* writer = getSink()->writer; - - // Write output to the diagnostic writer - if (writer) - { - for (TranslationUnitRequest* translationUnit : translationUnits) - { - RefPtr<ASTMarkup> markup(new ASTMarkup); - ASTMarkupUtil::extract(translationUnit->getModuleDecl(), getSourceManager(), getSink(), markup); - - // Convert to markdown - DocMarkdownWriter markdownWriter(markup, astBuilder); - markdownWriter.writeAll(); - - UnownedStringSlice docText = markdownWriter.getOutput().getUnownedSlice(); - writer->write(docText.begin(), docText.getLength()); - } - } + // TODO: implement the logic to output generated documents to target directory/zip file. } // Look up all the entry points that are expected, |
