diff --git a/include/ShaderAST/Expr/EnumIntrinsic.hpp b/include/ShaderAST/Expr/EnumIntrinsic.hpp index c6392c7e..e0ce0252 100644 --- a/include/ShaderAST/Expr/EnumIntrinsic.hpp +++ b/include/ShaderAST/Expr/EnumIntrinsic.hpp @@ -1349,6 +1349,40 @@ namespace ast::expr eSubgroupQuadSwapDiagonal3D, eSubgroupQuadSwapDiagonal4D, + //Shader Invocation Group Functions + eReadInvocation1F, + eReadInvocation2F, + eReadInvocation3F, + eReadInvocation4F, + eReadInvocation1I, + eReadInvocation2I, + eReadInvocation3I, + eReadInvocation4I, + eReadInvocation1U, + eReadInvocation2U, + eReadInvocation3U, + eReadInvocation4U, + eReadInvocation1D, + eReadInvocation2D, + eReadInvocation3D, + eReadInvocation4D, + eReadFirstInvocation1F, + eReadFirstInvocation2F, + eReadFirstInvocation3F, + eReadFirstInvocation4F, + eReadFirstInvocation1I, + eReadFirstInvocation2I, + eReadFirstInvocation3I, + eReadFirstInvocation4I, + eReadFirstInvocation1U, + eReadFirstInvocation2U, + eReadFirstInvocation3U, + eReadFirstInvocation4U, + eReadFirstInvocation1D, + eReadFirstInvocation2D, + eReadFirstInvocation3D, + eReadFirstInvocation4D, + // Boundaries, eCount, eInvalid = ~( 0u ), diff --git a/include/ShaderAST/Expr/GetIntrinsicName.hpp b/include/ShaderAST/Expr/GetIntrinsicName.hpp index 5b5fc280..7fb527cf 100644 --- a/include/ShaderAST/Expr/GetIntrinsicName.hpp +++ b/include/ShaderAST/Expr/GetIntrinsicName.hpp @@ -5267,6 +5267,136 @@ namespace ast::expr result = "SUBGROUPQUADSWAPDIAGONAL4D"; break; + + //Shader Invocation Group Functions + case Intrinsic::eReadInvocation1F: + result = "READINVOCATION1F"; + break; + + case Intrinsic::eReadInvocation2F: + result = "READINVOCATION2F"; + break; + + case Intrinsic::eReadInvocation3F: + result = "READINVOCATION3F"; + break; + + case Intrinsic::eReadInvocation4F: + result = "READINVOCATION4F"; + break; + + case Intrinsic::eReadInvocation1I: + result = "READINVOCATION1I"; + break; + + case Intrinsic::eReadInvocation2I: + result = "READINVOCATION2I"; + break; + + case Intrinsic::eReadInvocation3I: + result = "READINVOCATION3I"; + break; + + case Intrinsic::eReadInvocation4I: + result = "READINVOCATION4I"; + break; + + case Intrinsic::eReadInvocation1U: + result = "READINVOCATION1U"; + break; + + case Intrinsic::eReadInvocation2U: + result = "READINVOCATION2U"; + break; + + case Intrinsic::eReadInvocation3U: + result = "READINVOCATION3U"; + break; + + case Intrinsic::eReadInvocation4U: + result = "READINVOCATION4U"; + break; + + case Intrinsic::eReadInvocation1D: + result = "READINVOCATION1D"; + break; + + case Intrinsic::eReadInvocation2D: + result = "READINVOCATION2D"; + break; + + case Intrinsic::eReadInvocation3D: + result = "READINVOCATION3D"; + break; + + case Intrinsic::eReadInvocation4D: + result = "READINVOCATION4D"; + break; + + case Intrinsic::eReadFirstInvocation1F: + result = "READFIRSTINVOCATION1F"; + break; + + case Intrinsic::eReadFirstInvocation2F: + result = "READFIRSTINVOCATION2F"; + break; + + case Intrinsic::eReadFirstInvocation3F: + result = "READFIRSTINVOCATION3F"; + break; + + case Intrinsic::eReadFirstInvocation4F: + result = "READFIRSTINVOCATION4F"; + break; + + case Intrinsic::eReadFirstInvocation1I: + result = "READFIRSTINVOCATION1I"; + break; + + case Intrinsic::eReadFirstInvocation2I: + result = "READFIRSTINVOCATION2I"; + break; + + case Intrinsic::eReadFirstInvocation3I: + result = "READFIRSTINVOCATION3I"; + break; + + case Intrinsic::eReadFirstInvocation4I: + result = "READFIRSTINVOCATION4I"; + break; + + case Intrinsic::eReadFirstInvocation1U: + result = "READFIRSTINVOCATION1U"; + break; + + case Intrinsic::eReadFirstInvocation2U: + result = "READFIRSTINVOCATION2U"; + break; + + case Intrinsic::eReadFirstInvocation3U: + result = "READFIRSTINVOCATION3U"; + break; + + case Intrinsic::eReadFirstInvocation4U: + result = "READFIRSTINVOCATION4U"; + break; + + case Intrinsic::eReadFirstInvocation1D: + result = "READFIRSTINVOCATION1D"; + break; + + case Intrinsic::eReadFirstInvocation2D: + result = "READFIRSTINVOCATION2D"; + break; + + case Intrinsic::eReadFirstInvocation3D: + result = "READFIRSTINVOCATION3D"; + break; + + case Intrinsic::eReadFirstInvocation4D: + result = "READFIRSTINVOCATION4D"; + break; + default: throw std::runtime_error{ "Unsupported Intrinsic type." }; } diff --git a/include/ShaderAST/Expr/Intrinsic.enum b/include/ShaderAST/Expr/Intrinsic.enum index 0159da86..6d3232b9 100644 --- a/include/ShaderAST/Expr/Intrinsic.enum +++ b/include/ShaderAST/Expr/Intrinsic.enum @@ -1337,4 +1337,38 @@ ASTIntrDecl( Intrinsic ) ASTIntrValue( type::Kind::eVec2D, ASTIntrName( subgroupQuadSwapDiagonal, SubgroupQuadSwapDiagonal, 2, D ), ASTIntrParams( ASTIntrParam( type::Kind::eVec2D, value ) ) ) ASTIntrValue( type::Kind::eVec3D, ASTIntrName( subgroupQuadSwapDiagonal, SubgroupQuadSwapDiagonal, 3, D ), ASTIntrParams( ASTIntrParam( type::Kind::eVec3D, value ) ) ) ASTIntrValue( type::Kind::eVec4D, ASTIntrName( subgroupQuadSwapDiagonal, SubgroupQuadSwapDiagonal, 4, D ), ASTIntrParams( ASTIntrParam( type::Kind::eVec4D, value ) ) ) + + //Shader Invocation Group Functions + ASTIntrValue( type::Kind::eFloat, ASTIntrName( readInvocation, ReadInvocation, 1, F ), ASTIntrParams( ASTIntrParam( type::Kind::eFloat, value ), ASTIntrParam( type::Kind::eUInt, invocationIndex ) ) ) + ASTIntrValue( type::Kind::eVec2F, ASTIntrName( readInvocation, ReadInvocation, 2, F ), ASTIntrParams( ASTIntrParam( type::Kind::eVec2F, value ), ASTIntrParam( type::Kind::eUInt, invocationIndex ) ) ) + ASTIntrValue( type::Kind::eVec3F, ASTIntrName( readInvocation, ReadInvocation, 3, F ), ASTIntrParams( ASTIntrParam( type::Kind::eVec3F, value ), ASTIntrParam( type::Kind::eUInt, invocationIndex ) ) ) + ASTIntrValue( type::Kind::eVec4F, ASTIntrName( readInvocation, ReadInvocation, 4, F ), ASTIntrParams( ASTIntrParam( type::Kind::eVec4F, value ), ASTIntrParam( type::Kind::eUInt, invocationIndex ) ) ) + ASTIntrValue( type::Kind::eInt32, ASTIntrName( readInvocation, ReadInvocation, 1, I ), ASTIntrParams( ASTIntrParam( type::Kind::eInt32, value ), ASTIntrParam( type::Kind::eUInt, invocationIndex ) ) ) + ASTIntrValue( type::Kind::eVec2I32, ASTIntrName( readInvocation, ReadInvocation, 2, I ), ASTIntrParams( ASTIntrParam( type::Kind::eVec2I32, value ), ASTIntrParam( type::Kind::eUInt, invocationIndex ) ) ) + ASTIntrValue( type::Kind::eVec3I32, ASTIntrName( readInvocation, ReadInvocation, 3, I ), ASTIntrParams( ASTIntrParam( type::Kind::eVec3I32, value ), ASTIntrParam( type::Kind::eUInt, invocationIndex ) ) ) + ASTIntrValue( type::Kind::eVec4I32, ASTIntrName( readInvocation, ReadInvocation, 4, I ), ASTIntrParams( ASTIntrParam( type::Kind::eVec4I32, value ), ASTIntrParam( type::Kind::eUInt, invocationIndex ) ) ) + ASTIntrValue( type::Kind::eUInt32, ASTIntrName( readInvocation, ReadInvocation, 1, U ), ASTIntrParams( ASTIntrParam( type::Kind::eUInt32, value ), ASTIntrParam( type::Kind::eUInt, invocationIndex ) ) ) + ASTIntrValue( type::Kind::eVec2U32, ASTIntrName( readInvocation, ReadInvocation, 2, U ), ASTIntrParams( ASTIntrParam( type::Kind::eVec2U32, value ), ASTIntrParam( type::Kind::eUInt, invocationIndex ) ) ) + ASTIntrValue( type::Kind::eVec3U32, ASTIntrName( readInvocation, ReadInvocation, 3, U ), ASTIntrParams( ASTIntrParam( type::Kind::eVec3U32, value ), ASTIntrParam( type::Kind::eUInt, invocationIndex ) ) ) + ASTIntrValue( type::Kind::eVec4U32, ASTIntrName( readInvocation, ReadInvocation, 4, U ), ASTIntrParams( ASTIntrParam( type::Kind::eVec4U32, value ), ASTIntrParam( type::Kind::eUInt, invocationIndex ) ) ) + ASTIntrValue( type::Kind::eDouble, ASTIntrName( readInvocation, ReadInvocation, 1, D ), ASTIntrParams( ASTIntrParam( type::Kind::eDouble, value ), ASTIntrParam( type::Kind::eUInt, invocationIndex ) ) ) + ASTIntrValue( type::Kind::eVec2D, ASTIntrName( readInvocation, ReadInvocation, 2, D ), ASTIntrParams( ASTIntrParam( type::Kind::eVec2D, value ), ASTIntrParam( type::Kind::eUInt, invocationIndex ) ) ) + ASTIntrValue( type::Kind::eVec3D, ASTIntrName( readInvocation, ReadInvocation, 3, D ), ASTIntrParams( ASTIntrParam( type::Kind::eVec3D, value ), ASTIntrParam( type::Kind::eUInt, invocationIndex ) ) ) + ASTIntrValue( type::Kind::eVec4D, ASTIntrName( readInvocation, ReadInvocation, 4, D ), ASTIntrParams( ASTIntrParam( type::Kind::eVec4D, value ), ASTIntrParam( type::Kind::eUInt, invocationIndex ) ) ) + ASTIntrValue( type::Kind::eFloat, ASTIntrName( readFirstInvocation, ReadFirstInvocation, 1, F ), ASTIntrParams( ASTIntrParam( type::Kind::eFloat, value ) ) ) + ASTIntrValue( type::Kind::eVec2F, ASTIntrName( readFirstInvocation, ReadFirstInvocation, 2, F ), ASTIntrParams( ASTIntrParam( type::Kind::eVec2F, value ) ) ) + ASTIntrValue( type::Kind::eVec3F, ASTIntrName( readFirstInvocation, ReadFirstInvocation, 3, F ), ASTIntrParams( ASTIntrParam( type::Kind::eVec3F, value ) ) ) + ASTIntrValue( type::Kind::eVec4F, ASTIntrName( readFirstInvocation, ReadFirstInvocation, 4, F ), ASTIntrParams( ASTIntrParam( type::Kind::eVec4F, value ) ) ) + ASTIntrValue( type::Kind::eInt32, ASTIntrName( readFirstInvocation, ReadFirstInvocation, 1, I ), ASTIntrParams( ASTIntrParam( type::Kind::eInt32, value ) ) ) + ASTIntrValue( type::Kind::eVec2I32, ASTIntrName( readFirstInvocation, ReadFirstInvocation, 2, I ), ASTIntrParams( ASTIntrParam( type::Kind::eVec2I32, value ) ) ) + ASTIntrValue( type::Kind::eVec3I32, ASTIntrName( readFirstInvocation, ReadFirstInvocation, 3, I ), ASTIntrParams( ASTIntrParam( type::Kind::eVec3I32, value ) ) ) + ASTIntrValue( type::Kind::eVec4I32, ASTIntrName( readFirstInvocation, ReadFirstInvocation, 4, I ), ASTIntrParams( ASTIntrParam( type::Kind::eVec4I32, value ) ) ) + ASTIntrValue( type::Kind::eUInt32, ASTIntrName( readFirstInvocation, ReadFirstInvocation, 1, U ), ASTIntrParams( ASTIntrParam( type::Kind::eUInt32, value ) ) ) + ASTIntrValue( type::Kind::eVec2U32, ASTIntrName( readFirstInvocation, ReadFirstInvocation, 2, U ), ASTIntrParams( ASTIntrParam( type::Kind::eVec2U32, value ) ) ) + ASTIntrValue( type::Kind::eVec3U32, ASTIntrName( readFirstInvocation, ReadFirstInvocation, 3, U ), ASTIntrParams( ASTIntrParam( type::Kind::eVec3U32, value ) ) ) + ASTIntrValue( type::Kind::eVec4U32, ASTIntrName( readFirstInvocation, ReadFirstInvocation, 4, U ), ASTIntrParams( ASTIntrParam( type::Kind::eVec4U32, value ) ) ) + ASTIntrValue( type::Kind::eDouble, ASTIntrName( readFirstInvocation, ReadFirstInvocation, 1, D ), ASTIntrParams( ASTIntrParam( type::Kind::eDouble, value ) ) ) + ASTIntrValue( type::Kind::eVec2D, ASTIntrName( readFirstInvocation, ReadFirstInvocation, 2, D ), ASTIntrParams( ASTIntrParam( type::Kind::eVec2D, value ) ) ) + ASTIntrValue( type::Kind::eVec3D, ASTIntrName( readFirstInvocation, ReadFirstInvocation, 3, D ), ASTIntrParams( ASTIntrParam( type::Kind::eVec3D, value ) ) ) + ASTIntrValue( type::Kind::eVec4D, ASTIntrName( readFirstInvocation, ReadFirstInvocation, 4, D ), ASTIntrParams( ASTIntrParam( type::Kind::eVec4D, value ) ) ) ASTIntrEnd diff --git a/include/ShaderAST/Expr/MakeIntrinsic.hpp b/include/ShaderAST/Expr/MakeIntrinsic.hpp index 8af69f53..369e802a 100644 --- a/include/ShaderAST/Expr/MakeIntrinsic.hpp +++ b/include/ShaderAST/Expr/MakeIntrinsic.hpp @@ -22865,6 +22865,568 @@ namespace ast::expr , Intrinsic::eSubgroupQuadSwapDiagonal4D , std::move( value ) ); } + //Shader Invocation Group Functions + + /** + *@return + * float + *@param[in] value + * float + *@param[in] invocationIndex + * uint + */ + inline IntrinsicCallPtr makeReadInvocation1F( ExprCache & exprCache + , type::TypesCache & typesCache + , ExprPtr value + , ExprPtr invocationIndex ) + { + assert( value->getType()->getRawKind() == type::Kind::eFloat ); + assert( invocationIndex->getType()->getRawKind() == type::Kind::eUInt ); + return exprCache.makeIntrinsicCall( typesCache.getBasicType( type::Kind::eFloat ) + , Intrinsic::eReadInvocation1F + , std::move( value ) + , std::move( invocationIndex ) ); + } + /** + *@return + * vec2f + *@param[in] value + * vec2f + *@param[in] invocationIndex + * uint + */ + inline IntrinsicCallPtr makeReadInvocation2F( ExprCache & exprCache + , type::TypesCache & typesCache + , ExprPtr value + , ExprPtr invocationIndex ) + { + assert( value->getType()->getRawKind() == type::Kind::eVec2F ); + assert( invocationIndex->getType()->getRawKind() == type::Kind::eUInt ); + return exprCache.makeIntrinsicCall( typesCache.getBasicType( type::Kind::eVec2F ) + , Intrinsic::eReadInvocation2F + , std::move( value ) + , std::move( invocationIndex ) ); + } + /** + *@return + * vec3f + *@param[in] value + * vec3f + *@param[in] invocationIndex + * uint + */ + inline IntrinsicCallPtr makeReadInvocation3F( ExprCache & exprCache + , type::TypesCache & typesCache + , ExprPtr value + , ExprPtr invocationIndex ) + { + assert( value->getType()->getRawKind() == type::Kind::eVec3F ); + assert( invocationIndex->getType()->getRawKind() == type::Kind::eUInt ); + return exprCache.makeIntrinsicCall( typesCache.getBasicType( type::Kind::eVec3F ) + , Intrinsic::eReadInvocation3F + , std::move( value ) + , std::move( invocationIndex ) ); + } + /** + *@return + * vec4f + *@param[in] value + * vec4f + *@param[in] invocationIndex + * uint + */ + inline IntrinsicCallPtr makeReadInvocation4F( ExprCache & exprCache + , type::TypesCache & typesCache + , ExprPtr value + , ExprPtr invocationIndex ) + { + assert( value->getType()->getRawKind() == type::Kind::eVec4F ); + assert( invocationIndex->getType()->getRawKind() == type::Kind::eUInt ); + return exprCache.makeIntrinsicCall( typesCache.getBasicType( type::Kind::eVec4F ) + , Intrinsic::eReadInvocation4F + , std::move( value ) + , std::move( invocationIndex ) ); + } + /** + *@return + * int32 + *@param[in] value + * int32 + *@param[in] invocationIndex + * uint + */ + inline IntrinsicCallPtr makeReadInvocation1I( ExprCache & exprCache + , type::TypesCache & typesCache + , ExprPtr value + , ExprPtr invocationIndex ) + { + assert( value->getType()->getRawKind() == type::Kind::eInt32 ); + assert( invocationIndex->getType()->getRawKind() == type::Kind::eUInt ); + return exprCache.makeIntrinsicCall( typesCache.getBasicType( type::Kind::eInt32 ) + , Intrinsic::eReadInvocation1I + , std::move( value ) + , std::move( invocationIndex ) ); + } + /** + *@return + * vec2i32 + *@param[in] value + * vec2i32 + *@param[in] invocationIndex + * uint + */ + inline IntrinsicCallPtr makeReadInvocation2I( ExprCache & exprCache + , type::TypesCache & typesCache + , ExprPtr value + , ExprPtr invocationIndex ) + { + assert( value->getType()->getRawKind() == type::Kind::eVec2I32 ); + assert( invocationIndex->getType()->getRawKind() == type::Kind::eUInt ); + return exprCache.makeIntrinsicCall( typesCache.getBasicType( type::Kind::eVec2I32 ) + , Intrinsic::eReadInvocation2I + , std::move( value ) + , std::move( invocationIndex ) ); + } + /** + *@return + * vec3i32 + *@param[in] value + * vec3i32 + *@param[in] invocationIndex + * uint + */ + inline IntrinsicCallPtr makeReadInvocation3I( ExprCache & exprCache + , type::TypesCache & typesCache + , ExprPtr value + , ExprPtr invocationIndex ) + { + assert( value->getType()->getRawKind() == type::Kind::eVec3I32 ); + assert( invocationIndex->getType()->getRawKind() == type::Kind::eUInt ); + return exprCache.makeIntrinsicCall( typesCache.getBasicType( type::Kind::eVec3I32 ) + , Intrinsic::eReadInvocation3I + , std::move( value ) + , std::move( invocationIndex ) ); + } + /** + *@return + * vec4i32 + *@param[in] value + * vec4i32 + *@param[in] invocationIndex + * uint + */ + inline IntrinsicCallPtr makeReadInvocation4I( ExprCache & exprCache + , type::TypesCache & typesCache + , ExprPtr value + , ExprPtr invocationIndex ) + { + assert( value->getType()->getRawKind() == type::Kind::eVec4I32 ); + assert( invocationIndex->getType()->getRawKind() == type::Kind::eUInt ); + return exprCache.makeIntrinsicCall( typesCache.getBasicType( type::Kind::eVec4I32 ) + , Intrinsic::eReadInvocation4I + , std::move( value ) + , std::move( invocationIndex ) ); + } + /** + *@return + * uint32 + *@param[in] value + * uint32 + *@param[in] invocationIndex + * uint + */ + inline IntrinsicCallPtr makeReadInvocation1U( ExprCache & exprCache + , type::TypesCache & typesCache + , ExprPtr value + , ExprPtr invocationIndex ) + { + assert( value->getType()->getRawKind() == type::Kind::eUInt32 ); + assert( invocationIndex->getType()->getRawKind() == type::Kind::eUInt ); + return exprCache.makeIntrinsicCall( typesCache.getBasicType( type::Kind::eUInt32 ) + , Intrinsic::eReadInvocation1U + , std::move( value ) + , std::move( invocationIndex ) ); + } + /** + *@return + * vec2u32 + *@param[in] value + * vec2u32 + *@param[in] invocationIndex + * uint + */ + inline IntrinsicCallPtr makeReadInvocation2U( ExprCache & exprCache + , type::TypesCache & typesCache + , ExprPtr value + , ExprPtr invocationIndex ) + { + assert( value->getType()->getRawKind() == type::Kind::eVec2U32 ); + assert( invocationIndex->getType()->getRawKind() == type::Kind::eUInt ); + return exprCache.makeIntrinsicCall( typesCache.getBasicType( type::Kind::eVec2U32 ) + , Intrinsic::eReadInvocation2U + , std::move( value ) + , std::move( invocationIndex ) ); + } + /** + *@return + * vec3u32 + *@param[in] value + * vec3u32 + *@param[in] invocationIndex + * uint + */ + inline IntrinsicCallPtr makeReadInvocation3U( ExprCache & exprCache + , type::TypesCache & typesCache + , ExprPtr value + , ExprPtr invocationIndex ) + { + assert( value->getType()->getRawKind() == type::Kind::eVec3U32 ); + assert( invocationIndex->getType()->getRawKind() == type::Kind::eUInt ); + return exprCache.makeIntrinsicCall( typesCache.getBasicType( type::Kind::eVec3U32 ) + , Intrinsic::eReadInvocation3U + , std::move( value ) + , std::move( invocationIndex ) ); + } + /** + *@return + * vec4u32 + *@param[in] value + * vec4u32 + *@param[in] invocationIndex + * uint + */ + inline IntrinsicCallPtr makeReadInvocation4U( ExprCache & exprCache + , type::TypesCache & typesCache + , ExprPtr value + , ExprPtr invocationIndex ) + { + assert( value->getType()->getRawKind() == type::Kind::eVec4U32 ); + assert( invocationIndex->getType()->getRawKind() == type::Kind::eUInt ); + return exprCache.makeIntrinsicCall( typesCache.getBasicType( type::Kind::eVec4U32 ) + , Intrinsic::eReadInvocation4U + , std::move( value ) + , std::move( invocationIndex ) ); + } + /** + *@return + * double + *@param[in] value + * double + *@param[in] invocationIndex + * uint + */ + inline IntrinsicCallPtr makeReadInvocation1D( ExprCache & exprCache + , type::TypesCache & typesCache + , ExprPtr value + , ExprPtr invocationIndex ) + { + assert( value->getType()->getRawKind() == type::Kind::eDouble ); + assert( invocationIndex->getType()->getRawKind() == type::Kind::eUInt ); + return exprCache.makeIntrinsicCall( typesCache.getBasicType( type::Kind::eDouble ) + , Intrinsic::eReadInvocation1D + , std::move( value ) + , std::move( invocationIndex ) ); + } + /** + *@return + * vec2d + *@param[in] value + * vec2d + *@param[in] invocationIndex + * uint + */ + inline IntrinsicCallPtr makeReadInvocation2D( ExprCache & exprCache + , type::TypesCache & typesCache + , ExprPtr value + , ExprPtr invocationIndex ) + { + assert( value->getType()->getRawKind() == type::Kind::eVec2D ); + assert( invocationIndex->getType()->getRawKind() == type::Kind::eUInt ); + return exprCache.makeIntrinsicCall( typesCache.getBasicType( type::Kind::eVec2D ) + , Intrinsic::eReadInvocation2D + , std::move( value ) + , std::move( invocationIndex ) ); + } + /** + *@return + * vec3d + *@param[in] value + * vec3d + *@param[in] invocationIndex + * uint + */ + inline IntrinsicCallPtr makeReadInvocation3D( ExprCache & exprCache + , type::TypesCache & typesCache + , ExprPtr value + , ExprPtr invocationIndex ) + { + assert( value->getType()->getRawKind() == type::Kind::eVec3D ); + assert( invocationIndex->getType()->getRawKind() == type::Kind::eUInt ); + return exprCache.makeIntrinsicCall( typesCache.getBasicType( type::Kind::eVec3D ) + , Intrinsic::eReadInvocation3D + , std::move( value ) + , std::move( invocationIndex ) ); + } + /** + *@return + * vec4d + *@param[in] value + * vec4d + *@param[in] invocationIndex + * uint + */ + inline IntrinsicCallPtr makeReadInvocation4D( ExprCache & exprCache + , type::TypesCache & typesCache + , ExprPtr value + , ExprPtr invocationIndex ) + { + assert( value->getType()->getRawKind() == type::Kind::eVec4D ); + assert( invocationIndex->getType()->getRawKind() == type::Kind::eUInt ); + return exprCache.makeIntrinsicCall( typesCache.getBasicType( type::Kind::eVec4D ) + , Intrinsic::eReadInvocation4D + , std::move( value ) + , std::move( invocationIndex ) ); + } + /** + *@return + * float + *@param[in] value + * float + */ + inline IntrinsicCallPtr makeReadFirstInvocation1F( ExprCache & exprCache + , type::TypesCache & typesCache + , ExprPtr value ) + { + assert( value->getType()->getRawKind() == type::Kind::eFloat ); + return exprCache.makeIntrinsicCall( typesCache.getBasicType( type::Kind::eFloat ) + , Intrinsic::eReadFirstInvocation1F + , std::move( value ) ); + } + /** + *@return + * vec2f + *@param[in] value + * vec2f + */ + inline IntrinsicCallPtr makeReadFirstInvocation2F( ExprCache & exprCache + , type::TypesCache & typesCache + , ExprPtr value ) + { + assert( value->getType()->getRawKind() == type::Kind::eVec2F ); + return exprCache.makeIntrinsicCall( typesCache.getBasicType( type::Kind::eVec2F ) + , Intrinsic::eReadFirstInvocation2F + , std::move( value ) ); + } + /** + *@return + * vec3f + *@param[in] value + * vec3f + */ + inline IntrinsicCallPtr makeReadFirstInvocation3F( ExprCache & exprCache + , type::TypesCache & typesCache + , ExprPtr value ) + { + assert( value->getType()->getRawKind() == type::Kind::eVec3F ); + return exprCache.makeIntrinsicCall( typesCache.getBasicType( type::Kind::eVec3F ) + , Intrinsic::eReadFirstInvocation3F + , std::move( value ) ); + } + /** + *@return + * vec4f + *@param[in] value + * vec4f + */ + inline IntrinsicCallPtr makeReadFirstInvocation4F( ExprCache & exprCache + , type::TypesCache & typesCache + , ExprPtr value ) + { + assert( value->getType()->getRawKind() == type::Kind::eVec4F ); + return exprCache.makeIntrinsicCall( typesCache.getBasicType( type::Kind::eVec4F ) + , Intrinsic::eReadFirstInvocation4F + , std::move( value ) ); + } + /** + *@return + * int32 + *@param[in] value + * int32 + */ + inline IntrinsicCallPtr makeReadFirstInvocation1I( ExprCache & exprCache + , type::TypesCache & typesCache + , ExprPtr value ) + { + assert( value->getType()->getRawKind() == type::Kind::eInt32 ); + return exprCache.makeIntrinsicCall( typesCache.getBasicType( type::Kind::eInt32 ) + , Intrinsic::eReadFirstInvocation1I + , std::move( value ) ); + } + /** + *@return + * vec2i32 + *@param[in] value + * vec2i32 + */ + inline IntrinsicCallPtr makeReadFirstInvocation2I( ExprCache & exprCache + , type::TypesCache & typesCache + , ExprPtr value ) + { + assert( value->getType()->getRawKind() == type::Kind::eVec2I32 ); + return exprCache.makeIntrinsicCall( typesCache.getBasicType( type::Kind::eVec2I32 ) + , Intrinsic::eReadFirstInvocation2I + , std::move( value ) ); + } + /** + *@return + * vec3i32 + *@param[in] value + * vec3i32 + */ + inline IntrinsicCallPtr makeReadFirstInvocation3I( ExprCache & exprCache + , type::TypesCache & typesCache + , ExprPtr value ) + { + assert( value->getType()->getRawKind() == type::Kind::eVec3I32 ); + return exprCache.makeIntrinsicCall( typesCache.getBasicType( type::Kind::eVec3I32 ) + , Intrinsic::eReadFirstInvocation3I + , std::move( value ) ); + } + /** + *@return + * vec4i32 + *@param[in] value + * vec4i32 + */ + inline IntrinsicCallPtr makeReadFirstInvocation4I( ExprCache & exprCache + , type::TypesCache & typesCache + , ExprPtr value ) + { + assert( value->getType()->getRawKind() == type::Kind::eVec4I32 ); + return exprCache.makeIntrinsicCall( typesCache.getBasicType( type::Kind::eVec4I32 ) + , Intrinsic::eReadFirstInvocation4I + , std::move( value ) ); + } + /** + *@return + * uint32 + *@param[in] value + * uint32 + */ + inline IntrinsicCallPtr makeReadFirstInvocation1U( ExprCache & exprCache + , type::TypesCache & typesCache + , ExprPtr value ) + { + assert( value->getType()->getRawKind() == type::Kind::eUInt32 ); + return exprCache.makeIntrinsicCall( typesCache.getBasicType( type::Kind::eUInt32 ) + , Intrinsic::eReadFirstInvocation1U + , std::move( value ) ); + } + /** + *@return + * vec2u32 + *@param[in] value + * vec2u32 + */ + inline IntrinsicCallPtr makeReadFirstInvocation2U( ExprCache & exprCache + , type::TypesCache & typesCache + , ExprPtr value ) + { + assert( value->getType()->getRawKind() == type::Kind::eVec2U32 ); + return exprCache.makeIntrinsicCall( typesCache.getBasicType( type::Kind::eVec2U32 ) + , Intrinsic::eReadFirstInvocation2U + , std::move( value ) ); + } + /** + *@return + * vec3u32 + *@param[in] value + * vec3u32 + */ + inline IntrinsicCallPtr makeReadFirstInvocation3U( ExprCache & exprCache + , type::TypesCache & typesCache + , ExprPtr value ) + { + assert( value->getType()->getRawKind() == type::Kind::eVec3U32 ); + return exprCache.makeIntrinsicCall( typesCache.getBasicType( type::Kind::eVec3U32 ) + , Intrinsic::eReadFirstInvocation3U + , std::move( value ) ); + } + /** + *@return + * vec4u32 + *@param[in] value + * vec4u32 + */ + inline IntrinsicCallPtr makeReadFirstInvocation4U( ExprCache & exprCache + , type::TypesCache & typesCache + , ExprPtr value ) + { + assert( value->getType()->getRawKind() == type::Kind::eVec4U32 ); + return exprCache.makeIntrinsicCall( typesCache.getBasicType( type::Kind::eVec4U32 ) + , Intrinsic::eReadFirstInvocation4U + , std::move( value ) ); + } + /** + *@return + * double + *@param[in] value + * double + */ + inline IntrinsicCallPtr makeReadFirstInvocation1D( ExprCache & exprCache + , type::TypesCache & typesCache + , ExprPtr value ) + { + assert( value->getType()->getRawKind() == type::Kind::eDouble ); + return exprCache.makeIntrinsicCall( typesCache.getBasicType( type::Kind::eDouble ) + , Intrinsic::eReadFirstInvocation1D + , std::move( value ) ); + } + /** + *@return + * vec2d + *@param[in] value + * vec2d + */ + inline IntrinsicCallPtr makeReadFirstInvocation2D( ExprCache & exprCache + , type::TypesCache & typesCache + , ExprPtr value ) + { + assert( value->getType()->getRawKind() == type::Kind::eVec2D ); + return exprCache.makeIntrinsicCall( typesCache.getBasicType( type::Kind::eVec2D ) + , Intrinsic::eReadFirstInvocation2D + , std::move( value ) ); + } + /** + *@return + * vec3d + *@param[in] value + * vec3d + */ + inline IntrinsicCallPtr makeReadFirstInvocation3D( ExprCache & exprCache + , type::TypesCache & typesCache + , ExprPtr value ) + { + assert( value->getType()->getRawKind() == type::Kind::eVec3D ); + return exprCache.makeIntrinsicCall( typesCache.getBasicType( type::Kind::eVec3D ) + , Intrinsic::eReadFirstInvocation3D + , std::move( value ) ); + } + /** + *@return + * vec4d + *@param[in] value + * vec4d + */ + inline IntrinsicCallPtr makeReadFirstInvocation4D( ExprCache & exprCache + , type::TypesCache & typesCache + , ExprPtr value ) + { + assert( value->getType()->getRawKind() == type::Kind::eVec4D ); + return exprCache.makeIntrinsicCall( typesCache.getBasicType( type::Kind::eVec4D ) + , Intrinsic::eReadFirstInvocation4D + , std::move( value ) ); + } } #endif diff --git a/include/ShaderWriter/Intrinsics/IntrinsicFunctions.hpp b/include/ShaderWriter/Intrinsics/IntrinsicFunctions.hpp index 7301f23e..4c0b3c88 100644 --- a/include/ShaderWriter/Intrinsics/IntrinsicFunctions.hpp +++ b/include/ShaderWriter/Intrinsics/IntrinsicFunctions.hpp @@ -2718,6 +2718,54 @@ namespace sdw SDW_API RetDVec4 subgroupQuadSwapDiagonal( DVec4 const value ); /**@}*/ #pragma endregion +#pragma region readInvocation + /** + *name + * readInvocation + */ + /**@{*/ + SDW_API RetFloat readInvocation( Float const value, UInt const invocationIndex ); + SDW_API RetVec2 readInvocation( Vec2 const value, UInt const invocationIndex ); + SDW_API RetVec3 readInvocation( Vec3 const value, UInt const invocationIndex ); + SDW_API RetVec4 readInvocation( Vec4 const value, UInt const invocationIndex ); + SDW_API RetInt32 readInvocation( Int32 const value, UInt const invocationIndex ); + SDW_API RetI32Vec2 readInvocation( I32Vec2 const value, UInt const invocationIndex ); + SDW_API RetI32Vec3 readInvocation( I32Vec3 const value, UInt const invocationIndex ); + SDW_API RetI32Vec4 readInvocation( I32Vec4 const value, UInt const invocationIndex ); + SDW_API RetUInt32 readInvocation( UInt32 const value, UInt const invocationIndex ); + SDW_API RetU32Vec2 readInvocation( U32Vec2 const value, UInt const invocationIndex ); + SDW_API RetU32Vec3 readInvocation( U32Vec3 const value, UInt const invocationIndex ); + SDW_API RetU32Vec4 readInvocation( U32Vec4 const value, UInt const invocationIndex ); + SDW_API RetDouble readInvocation( Double const value, UInt const invocationIndex ); + SDW_API RetDVec2 readInvocation( DVec2 const value, UInt const invocationIndex ); + SDW_API RetDVec3 readInvocation( DVec3 const value, UInt const invocationIndex ); + SDW_API RetDVec4 readInvocation( DVec4 const value, UInt const invocationIndex ); + /**@}*/ +#pragma endregion +#pragma region readFirstInvocation + /** + *name + * readFirstInvocation + */ + /**@{*/ + SDW_API RetFloat readFirstInvocation( Float const value ); + SDW_API RetVec2 readFirstInvocation( Vec2 const value ); + SDW_API RetVec3 readFirstInvocation( Vec3 const value ); + SDW_API RetVec4 readFirstInvocation( Vec4 const value ); + SDW_API RetInt32 readFirstInvocation( Int32 const value ); + SDW_API RetI32Vec2 readFirstInvocation( I32Vec2 const value ); + SDW_API RetI32Vec3 readFirstInvocation( I32Vec3 const value ); + SDW_API RetI32Vec4 readFirstInvocation( I32Vec4 const value ); + SDW_API RetUInt32 readFirstInvocation( UInt32 const value ); + SDW_API RetU32Vec2 readFirstInvocation( U32Vec2 const value ); + SDW_API RetU32Vec3 readFirstInvocation( U32Vec3 const value ); + SDW_API RetU32Vec4 readFirstInvocation( U32Vec4 const value ); + SDW_API RetDouble readFirstInvocation( Double const value ); + SDW_API RetDVec2 readFirstInvocation( DVec2 const value ); + SDW_API RetDVec3 readFirstInvocation( DVec3 const value ); + SDW_API RetDVec4 readFirstInvocation( DVec4 const value ); + /**@}*/ +#pragma endregion } #endif diff --git a/source/CompilerGlsl/GlslExprConfigFiller.cpp b/source/CompilerGlsl/GlslExprConfigFiller.cpp index 42c20048..c61b9d71 100644 --- a/source/CompilerGlsl/GlslExprConfigFiller.cpp +++ b/source/CompilerGlsl/GlslExprConfigFiller.cpp @@ -254,6 +254,12 @@ namespace glsl m_config.requiredExtensions.insert( KHR_shader_subgroup ); m_config.requiredExtensions.insert( KHR_shader_subgroup_quad ); } + else if ( expr->getIntrinsic() >= ast::expr::Intrinsic::eReadInvocation1F + && expr->getIntrinsic() <= ast::expr::Intrinsic::eReadFirstInvocation4D ) + { + m_config.requiredExtensions.insert( KHR_vulkan_glsl ); + m_config.requiredExtensions.insert( ARB_shader_ballot ); + } else if ( expr->getIntrinsic() == ast::expr::Intrinsic::eControlBarrier || expr->getIntrinsic() == ast::expr::Intrinsic::eMemoryBarrier ) { diff --git a/source/CompilerGlsl/GlslIntrinsicNames.hpp b/source/CompilerGlsl/GlslIntrinsicNames.hpp index 0315ad81..9e55cf9d 100644 --- a/source/CompilerGlsl/GlslIntrinsicNames.hpp +++ b/source/CompilerGlsl/GlslIntrinsicNames.hpp @@ -1847,7 +1847,45 @@ namespace glsl result = "subgroupQuadSwapDiagonal"; break; + case ast::expr::Intrinsic::eReadInvocation1F: + case ast::expr::Intrinsic::eReadInvocation2F: + case ast::expr::Intrinsic::eReadInvocation3F: + case ast::expr::Intrinsic::eReadInvocation4F: + case ast::expr::Intrinsic::eReadInvocation1I: + case ast::expr::Intrinsic::eReadInvocation2I: + case ast::expr::Intrinsic::eReadInvocation3I: + case ast::expr::Intrinsic::eReadInvocation4I: + case ast::expr::Intrinsic::eReadInvocation1U: + case ast::expr::Intrinsic::eReadInvocation2U: + case ast::expr::Intrinsic::eReadInvocation3U: + case ast::expr::Intrinsic::eReadInvocation4U: + result = "readInvocationARB"; + break; + + case ast::expr::Intrinsic::eReadFirstInvocation1F: + case ast::expr::Intrinsic::eReadFirstInvocation2F: + case ast::expr::Intrinsic::eReadFirstInvocation3F: + case ast::expr::Intrinsic::eReadFirstInvocation4F: + case ast::expr::Intrinsic::eReadFirstInvocation1I: + case ast::expr::Intrinsic::eReadFirstInvocation2I: + case ast::expr::Intrinsic::eReadFirstInvocation3I: + case ast::expr::Intrinsic::eReadFirstInvocation4I: + case ast::expr::Intrinsic::eReadFirstInvocation1U: + case ast::expr::Intrinsic::eReadFirstInvocation2U: + case ast::expr::Intrinsic::eReadFirstInvocation3U: + case ast::expr::Intrinsic::eReadFirstInvocation4U: + result = "readFirstInvocationARB"; + break; + default: + case ast::expr::Intrinsic::eReadInvocation1D: + case ast::expr::Intrinsic::eReadInvocation2D: + case ast::expr::Intrinsic::eReadInvocation3D: + case ast::expr::Intrinsic::eReadInvocation4D: + case ast::expr::Intrinsic::eReadFirstInvocation1D: + case ast::expr::Intrinsic::eReadFirstInvocation2D: + case ast::expr::Intrinsic::eReadFirstInvocation3D: + case ast::expr::Intrinsic::eReadFirstInvocation4D: throw std::runtime_error{ "Unsupported Intrinsic type." }; } diff --git a/source/CompilerHlsl/HlslIntrinsicConfig.hpp b/source/CompilerHlsl/HlslIntrinsicConfig.hpp index 41988a68..2abbcc65 100644 --- a/source/CompilerHlsl/HlslIntrinsicConfig.hpp +++ b/source/CompilerHlsl/HlslIntrinsicConfig.hpp @@ -971,6 +971,41 @@ namespace hlsl case ast::expr::Intrinsic::eSubgroupQuadBroadcast4D: config.requiresWaveOps = true; break; + + case ast::expr::Intrinsic::eReadInvocation1F: + case ast::expr::Intrinsic::eReadInvocation2F: + case ast::expr::Intrinsic::eReadInvocation3F: + case ast::expr::Intrinsic::eReadInvocation4F: + case ast::expr::Intrinsic::eReadInvocation1I: + case ast::expr::Intrinsic::eReadInvocation2I: + case ast::expr::Intrinsic::eReadInvocation3I: + case ast::expr::Intrinsic::eReadInvocation4I: + case ast::expr::Intrinsic::eReadInvocation1U: + case ast::expr::Intrinsic::eReadInvocation2U: + case ast::expr::Intrinsic::eReadInvocation3U: + case ast::expr::Intrinsic::eReadInvocation4U: + case ast::expr::Intrinsic::eReadInvocation1D: + case ast::expr::Intrinsic::eReadInvocation2D: + case ast::expr::Intrinsic::eReadInvocation3D: + case ast::expr::Intrinsic::eReadInvocation4D: + case ast::expr::Intrinsic::eReadFirstInvocation1F: + case ast::expr::Intrinsic::eReadFirstInvocation2F: + case ast::expr::Intrinsic::eReadFirstInvocation3F: + case ast::expr::Intrinsic::eReadFirstInvocation4F: + case ast::expr::Intrinsic::eReadFirstInvocation1I: + case ast::expr::Intrinsic::eReadFirstInvocation2I: + case ast::expr::Intrinsic::eReadFirstInvocation3I: + case ast::expr::Intrinsic::eReadFirstInvocation4I: + case ast::expr::Intrinsic::eReadFirstInvocation1U: + case ast::expr::Intrinsic::eReadFirstInvocation2U: + case ast::expr::Intrinsic::eReadFirstInvocation3U: + case ast::expr::Intrinsic::eReadFirstInvocation4U: + case ast::expr::Intrinsic::eReadFirstInvocation1D: + case ast::expr::Intrinsic::eReadFirstInvocation2D: + case ast::expr::Intrinsic::eReadFirstInvocation3D: + case ast::expr::Intrinsic::eReadFirstInvocation4D: + config.requiresWaveOps = true; + break; case ast::expr::Intrinsic::eSubgroupInverseBallot: case ast::expr::Intrinsic::eSubgroupBallotBitExtract: diff --git a/source/CompilerHlsl/HlslIntrinsicNames.hpp b/source/CompilerHlsl/HlslIntrinsicNames.hpp index 81ed11c3..35ebdda6 100644 --- a/source/CompilerHlsl/HlslIntrinsicNames.hpp +++ b/source/CompilerHlsl/HlslIntrinsicNames.hpp @@ -1137,6 +1137,22 @@ namespace hlsl case ast::expr::Intrinsic::eSubgroupBroadcast2D: case ast::expr::Intrinsic::eSubgroupBroadcast3D: case ast::expr::Intrinsic::eSubgroupBroadcast4D: + case ast::expr::Intrinsic::eReadInvocation1F: + case ast::expr::Intrinsic::eReadInvocation2F: + case ast::expr::Intrinsic::eReadInvocation3F: + case ast::expr::Intrinsic::eReadInvocation4F: + case ast::expr::Intrinsic::eReadInvocation1I: + case ast::expr::Intrinsic::eReadInvocation2I: + case ast::expr::Intrinsic::eReadInvocation3I: + case ast::expr::Intrinsic::eReadInvocation4I: + case ast::expr::Intrinsic::eReadInvocation1U: + case ast::expr::Intrinsic::eReadInvocation2U: + case ast::expr::Intrinsic::eReadInvocation3U: + case ast::expr::Intrinsic::eReadInvocation4U: + case ast::expr::Intrinsic::eReadInvocation1D: + case ast::expr::Intrinsic::eReadInvocation2D: + case ast::expr::Intrinsic::eReadInvocation3D: + case ast::expr::Intrinsic::eReadInvocation4D: result = "WaveReadLaneAt"; break; @@ -1160,6 +1176,22 @@ namespace hlsl case ast::expr::Intrinsic::eSubgroupBroadcastFirst2D: case ast::expr::Intrinsic::eSubgroupBroadcastFirst3D: case ast::expr::Intrinsic::eSubgroupBroadcastFirst4D: + case ast::expr::Intrinsic::eReadFirstInvocation1F: + case ast::expr::Intrinsic::eReadFirstInvocation2F: + case ast::expr::Intrinsic::eReadFirstInvocation3F: + case ast::expr::Intrinsic::eReadFirstInvocation4F: + case ast::expr::Intrinsic::eReadFirstInvocation1I: + case ast::expr::Intrinsic::eReadFirstInvocation2I: + case ast::expr::Intrinsic::eReadFirstInvocation3I: + case ast::expr::Intrinsic::eReadFirstInvocation4I: + case ast::expr::Intrinsic::eReadFirstInvocation1U: + case ast::expr::Intrinsic::eReadFirstInvocation2U: + case ast::expr::Intrinsic::eReadFirstInvocation3U: + case ast::expr::Intrinsic::eReadFirstInvocation4U: + case ast::expr::Intrinsic::eReadFirstInvocation1D: + case ast::expr::Intrinsic::eReadFirstInvocation2D: + case ast::expr::Intrinsic::eReadFirstInvocation3D: + case ast::expr::Intrinsic::eReadFirstInvocation4D: result = "WaveReadLaneFirst"; break; diff --git a/source/CompilerSpirV/SpirvExprConfigFiller.cpp b/source/CompilerSpirV/SpirvExprConfigFiller.cpp index 9eafc996..11b03133 100644 --- a/source/CompilerSpirV/SpirvExprConfigFiller.cpp +++ b/source/CompilerSpirV/SpirvExprConfigFiller.cpp @@ -110,6 +110,11 @@ namespace spirv { config.registerCapability( spv::CapabilityGroupNonUniformQuad ); } + else if ( kind >= ast::expr::Intrinsic::eReadInvocation1F + && kind <= ast::expr::Intrinsic::eReadFirstInvocation4D ) + { + config.registerCapability( spv::CapabilitySubgroupBallotKHR ); + } else if ( kind >= ast::expr::Intrinsic::eControlBarrier && kind <= ast::expr::Intrinsic::eMemoryBarrier ) { diff --git a/source/CompilerSpirV/SpirvHelpers.cpp b/source/CompilerSpirV/SpirvHelpers.cpp index dfdee956..38c21321 100644 --- a/source/CompilerSpirV/SpirvHelpers.cpp +++ b/source/CompilerSpirV/SpirvHelpers.cpp @@ -3090,6 +3090,12 @@ namespace spirv return makeInstruction< IntrinsicInstructionT< spv::OpGroupNonUniformBitwiseXor > >( returnTypeId, resultId, operands ); case spv::OpGroupNonUniformLogicalXor: return makeInstruction< IntrinsicInstructionT< spv::OpGroupNonUniformLogicalXor > >( returnTypeId, resultId, operands ); + case spv::OpSubgroupBallotKHR: + return makeInstruction< IntrinsicInstructionT< spv::OpSubgroupBallotKHR > >( returnTypeId, resultId, operands ); + case spv::OpSubgroupReadInvocationKHR: + return makeInstruction< IntrinsicInstructionT< spv::OpSubgroupReadInvocationKHR > >( returnTypeId, resultId, operands ); + case spv::OpSubgroupFirstInvocationKHR: + return makeInstruction< IntrinsicInstructionT< spv::OpSubgroupFirstInvocationKHR > >( returnTypeId, resultId, operands ); case spv::OpGroupNonUniformQuadBroadcast: return makeInstruction< GroupNonUniformQuadBroadcastInstruction >( returnTypeId, resultId, operands ); case spv::OpGroupNonUniformQuadSwap: diff --git a/source/CompilerSpirV/SpirvInstruction.hpp b/source/CompilerSpirV/SpirvInstruction.hpp index 1b7c5858..f5b02a03 100644 --- a/source/CompilerSpirV/SpirvInstruction.hpp +++ b/source/CompilerSpirV/SpirvInstruction.hpp @@ -412,7 +412,7 @@ namespace spirv using GroupNonUniformBroadcastFirstInstruction = InstructionT< spv::OpGroupNonUniformBroadcastFirst, true, true, 2u, false, false >; using GroupNonUniformBallotInstruction = InstructionT< spv::OpGroupNonUniformBallot, true, true, 2u, false, false >; using GroupNonUniformInverseBallotInstruction = InstructionT< spv::OpGroupNonUniformInverseBallot, true, true, 2u, false, false >; - using GroupNonUniformBallotBitExtractInstruction = InstructionT< spv::OpGroupNonUniformBallotBitExtract, true, true, 2u, false, false >; + using GroupNonUniformBallotBitExtractInstruction = InstructionT< spv::OpGroupNonUniformBallotBitExtract, true, true, 3u, false, false >; using GroupNonUniformBallotBitCountInstruction = InstructionT< spv::OpGroupNonUniformBallotBitCount, true, true, 3u, false, false >; using GroupNonUniformBallotFindLSBInstruction = InstructionT< spv::OpGroupNonUniformBallotFindLSB, true, true, 2u, false, false >; using GroupNonUniformBallotFindMSBInstruction = InstructionT< spv::OpGroupNonUniformBallotFindMSB, true, true, 2u, false, false >; diff --git a/source/CompilerSpirV/SpirvIntrinsicConfig.hpp b/source/CompilerSpirV/SpirvIntrinsicConfig.hpp index 7a9f33de..87c379f2 100644 --- a/source/CompilerSpirV/SpirvIntrinsicConfig.hpp +++ b/source/CompilerSpirV/SpirvIntrinsicConfig.hpp @@ -1695,6 +1695,43 @@ namespace spirv config.isExtension = false; break; + + //Shader Invocation Group Functions + case ast::expr::Intrinsic::eReadInvocation1F: + case ast::expr::Intrinsic::eReadInvocation2F: + case ast::expr::Intrinsic::eReadInvocation3F: + case ast::expr::Intrinsic::eReadInvocation4F: + case ast::expr::Intrinsic::eReadInvocation1I: + case ast::expr::Intrinsic::eReadInvocation2I: + case ast::expr::Intrinsic::eReadInvocation3I: + case ast::expr::Intrinsic::eReadInvocation4I: + case ast::expr::Intrinsic::eReadInvocation1U: + case ast::expr::Intrinsic::eReadInvocation2U: + case ast::expr::Intrinsic::eReadInvocation3U: + case ast::expr::Intrinsic::eReadInvocation4U: + case ast::expr::Intrinsic::eReadInvocation1D: + case ast::expr::Intrinsic::eReadInvocation2D: + case ast::expr::Intrinsic::eReadInvocation3D: + case ast::expr::Intrinsic::eReadInvocation4D: + case ast::expr::Intrinsic::eReadFirstInvocation1F: + case ast::expr::Intrinsic::eReadFirstInvocation2F: + case ast::expr::Intrinsic::eReadFirstInvocation3F: + case ast::expr::Intrinsic::eReadFirstInvocation4F: + case ast::expr::Intrinsic::eReadFirstInvocation1I: + case ast::expr::Intrinsic::eReadFirstInvocation2I: + case ast::expr::Intrinsic::eReadFirstInvocation3I: + case ast::expr::Intrinsic::eReadFirstInvocation4I: + case ast::expr::Intrinsic::eReadFirstInvocation1U: + case ast::expr::Intrinsic::eReadFirstInvocation2U: + case ast::expr::Intrinsic::eReadFirstInvocation3U: + case ast::expr::Intrinsic::eReadFirstInvocation4U: + case ast::expr::Intrinsic::eReadFirstInvocation1D: + case ast::expr::Intrinsic::eReadFirstInvocation2D: + case ast::expr::Intrinsic::eReadFirstInvocation3D: + case ast::expr::Intrinsic::eReadFirstInvocation4D: + config.isExtension = false; + break; + default: throw std::runtime_error{ "Unsupported Intrinsic type." }; } diff --git a/source/CompilerSpirV/SpirvIntrinsicNames.hpp b/source/CompilerSpirV/SpirvIntrinsicNames.hpp index aa5fc12d..22a2e464 100644 --- a/source/CompilerSpirV/SpirvIntrinsicNames.hpp +++ b/source/CompilerSpirV/SpirvIntrinsicNames.hpp @@ -1880,6 +1880,46 @@ namespace spirv result = spv::Id( spv::OpGroupNonUniformQuadSwap ); break; + + //Shader Invocation Group Functions + case ast::expr::Intrinsic::eReadInvocation1F: + case ast::expr::Intrinsic::eReadInvocation2F: + case ast::expr::Intrinsic::eReadInvocation3F: + case ast::expr::Intrinsic::eReadInvocation4F: + case ast::expr::Intrinsic::eReadInvocation1I: + case ast::expr::Intrinsic::eReadInvocation2I: + case ast::expr::Intrinsic::eReadInvocation3I: + case ast::expr::Intrinsic::eReadInvocation4I: + case ast::expr::Intrinsic::eReadInvocation1U: + case ast::expr::Intrinsic::eReadInvocation2U: + case ast::expr::Intrinsic::eReadInvocation3U: + case ast::expr::Intrinsic::eReadInvocation4U: + case ast::expr::Intrinsic::eReadInvocation1D: + case ast::expr::Intrinsic::eReadInvocation2D: + case ast::expr::Intrinsic::eReadInvocation3D: + case ast::expr::Intrinsic::eReadInvocation4D: + result = spv::Id( spv::OpSubgroupReadInvocationKHR ); + break; + + case ast::expr::Intrinsic::eReadFirstInvocation1F: + case ast::expr::Intrinsic::eReadFirstInvocation2F: + case ast::expr::Intrinsic::eReadFirstInvocation3F: + case ast::expr::Intrinsic::eReadFirstInvocation4F: + case ast::expr::Intrinsic::eReadFirstInvocation1I: + case ast::expr::Intrinsic::eReadFirstInvocation2I: + case ast::expr::Intrinsic::eReadFirstInvocation3I: + case ast::expr::Intrinsic::eReadFirstInvocation4I: + case ast::expr::Intrinsic::eReadFirstInvocation1U: + case ast::expr::Intrinsic::eReadFirstInvocation2U: + case ast::expr::Intrinsic::eReadFirstInvocation3U: + case ast::expr::Intrinsic::eReadFirstInvocation4U: + case ast::expr::Intrinsic::eReadFirstInvocation1D: + case ast::expr::Intrinsic::eReadFirstInvocation2D: + case ast::expr::Intrinsic::eReadFirstInvocation3D: + case ast::expr::Intrinsic::eReadFirstInvocation4D: + result = spv::Id( spv::OpSubgroupFirstInvocationKHR ); + break; + default: throw std::runtime_error{ "Unsupported Intrinsic type." }; } diff --git a/source/ShaderWriter/Intrinsics/IntrinsicFunctions.cpp b/source/ShaderWriter/Intrinsics/IntrinsicFunctions.cpp index 251fb5e1..4ac4ea0b 100644 --- a/source/ShaderWriter/Intrinsics/IntrinsicFunctions.cpp +++ b/source/ShaderWriter/Intrinsics/IntrinsicFunctions.cpp @@ -13151,4 +13151,308 @@ namespace sdw } /**@}*/ #pragma endregion +#pragma region readInvocation + /** + *name + * readInvocation + */ + /**@{*/ + RetFloat readInvocation( Float const value + , UInt const invocationIndex ) + { + return RetFloat{ *findWriter( value, invocationIndex ) + , expr::makeReadInvocation1F( findExprCache( value, invocationIndex ) + , findTypesCache( value, invocationIndex ) + , makeExpr( value ) + , makeExpr( invocationIndex ) ) + , areOptionalEnabled( value, invocationIndex ) }; + } + RetVec2 readInvocation( Vec2 const value + , UInt const invocationIndex ) + { + return RetVec2{ *findWriter( value, invocationIndex ) + , expr::makeReadInvocation2F( findExprCache( value, invocationIndex ) + , findTypesCache( value, invocationIndex ) + , makeExpr( value ) + , makeExpr( invocationIndex ) ) + , areOptionalEnabled( value, invocationIndex ) }; + } + RetVec3 readInvocation( Vec3 const value + , UInt const invocationIndex ) + { + return RetVec3{ *findWriter( value, invocationIndex ) + , expr::makeReadInvocation3F( findExprCache( value, invocationIndex ) + , findTypesCache( value, invocationIndex ) + , makeExpr( value ) + , makeExpr( invocationIndex ) ) + , areOptionalEnabled( value, invocationIndex ) }; + } + RetVec4 readInvocation( Vec4 const value + , UInt const invocationIndex ) + { + return RetVec4{ *findWriter( value, invocationIndex ) + , expr::makeReadInvocation4F( findExprCache( value, invocationIndex ) + , findTypesCache( value, invocationIndex ) + , makeExpr( value ) + , makeExpr( invocationIndex ) ) + , areOptionalEnabled( value, invocationIndex ) }; + } + RetInt32 readInvocation( Int32 const value + , UInt const invocationIndex ) + { + return RetInt32{ *findWriter( value, invocationIndex ) + , expr::makeReadInvocation1I( findExprCache( value, invocationIndex ) + , findTypesCache( value, invocationIndex ) + , makeExpr( value ) + , makeExpr( invocationIndex ) ) + , areOptionalEnabled( value, invocationIndex ) }; + } + RetI32Vec2 readInvocation( I32Vec2 const value + , UInt const invocationIndex ) + { + return RetI32Vec2{ *findWriter( value, invocationIndex ) + , expr::makeReadInvocation2I( findExprCache( value, invocationIndex ) + , findTypesCache( value, invocationIndex ) + , makeExpr( value ) + , makeExpr( invocationIndex ) ) + , areOptionalEnabled( value, invocationIndex ) }; + } + RetI32Vec3 readInvocation( I32Vec3 const value + , UInt const invocationIndex ) + { + return RetI32Vec3{ *findWriter( value, invocationIndex ) + , expr::makeReadInvocation3I( findExprCache( value, invocationIndex ) + , findTypesCache( value, invocationIndex ) + , makeExpr( value ) + , makeExpr( invocationIndex ) ) + , areOptionalEnabled( value, invocationIndex ) }; + } + RetI32Vec4 readInvocation( I32Vec4 const value + , UInt const invocationIndex ) + { + return RetI32Vec4{ *findWriter( value, invocationIndex ) + , expr::makeReadInvocation4I( findExprCache( value, invocationIndex ) + , findTypesCache( value, invocationIndex ) + , makeExpr( value ) + , makeExpr( invocationIndex ) ) + , areOptionalEnabled( value, invocationIndex ) }; + } + RetUInt32 readInvocation( UInt32 const value + , UInt const invocationIndex ) + { + return RetUInt32{ *findWriter( value, invocationIndex ) + , expr::makeReadInvocation1U( findExprCache( value, invocationIndex ) + , findTypesCache( value, invocationIndex ) + , makeExpr( value ) + , makeExpr( invocationIndex ) ) + , areOptionalEnabled( value, invocationIndex ) }; + } + RetU32Vec2 readInvocation( U32Vec2 const value + , UInt const invocationIndex ) + { + return RetU32Vec2{ *findWriter( value, invocationIndex ) + , expr::makeReadInvocation2U( findExprCache( value, invocationIndex ) + , findTypesCache( value, invocationIndex ) + , makeExpr( value ) + , makeExpr( invocationIndex ) ) + , areOptionalEnabled( value, invocationIndex ) }; + } + RetU32Vec3 readInvocation( U32Vec3 const value + , UInt const invocationIndex ) + { + return RetU32Vec3{ *findWriter( value, invocationIndex ) + , expr::makeReadInvocation3U( findExprCache( value, invocationIndex ) + , findTypesCache( value, invocationIndex ) + , makeExpr( value ) + , makeExpr( invocationIndex ) ) + , areOptionalEnabled( value, invocationIndex ) }; + } + RetU32Vec4 readInvocation( U32Vec4 const value + , UInt const invocationIndex ) + { + return RetU32Vec4{ *findWriter( value, invocationIndex ) + , expr::makeReadInvocation4U( findExprCache( value, invocationIndex ) + , findTypesCache( value, invocationIndex ) + , makeExpr( value ) + , makeExpr( invocationIndex ) ) + , areOptionalEnabled( value, invocationIndex ) }; + } + RetDouble readInvocation( Double const value + , UInt const invocationIndex ) + { + return RetDouble{ *findWriter( value, invocationIndex ) + , expr::makeReadInvocation1D( findExprCache( value, invocationIndex ) + , findTypesCache( value, invocationIndex ) + , makeExpr( value ) + , makeExpr( invocationIndex ) ) + , areOptionalEnabled( value, invocationIndex ) }; + } + RetDVec2 readInvocation( DVec2 const value + , UInt const invocationIndex ) + { + return RetDVec2{ *findWriter( value, invocationIndex ) + , expr::makeReadInvocation2D( findExprCache( value, invocationIndex ) + , findTypesCache( value, invocationIndex ) + , makeExpr( value ) + , makeExpr( invocationIndex ) ) + , areOptionalEnabled( value, invocationIndex ) }; + } + RetDVec3 readInvocation( DVec3 const value + , UInt const invocationIndex ) + { + return RetDVec3{ *findWriter( value, invocationIndex ) + , expr::makeReadInvocation3D( findExprCache( value, invocationIndex ) + , findTypesCache( value, invocationIndex ) + , makeExpr( value ) + , makeExpr( invocationIndex ) ) + , areOptionalEnabled( value, invocationIndex ) }; + } + RetDVec4 readInvocation( DVec4 const value + , UInt const invocationIndex ) + { + return RetDVec4{ *findWriter( value, invocationIndex ) + , expr::makeReadInvocation4D( findExprCache( value, invocationIndex ) + , findTypesCache( value, invocationIndex ) + , makeExpr( value ) + , makeExpr( invocationIndex ) ) + , areOptionalEnabled( value, invocationIndex ) }; + } + /**@}*/ +#pragma endregion +#pragma region readFirstInvocation + /** + *name + * readFirstInvocation + */ + /**@{*/ + RetFloat readFirstInvocation( Float const value ) + { + return RetFloat{ *findWriter( value ) + , expr::makeReadFirstInvocation1F( findExprCache( value ) + , findTypesCache( value ) + , makeExpr( value ) ) + , areOptionalEnabled( value ) }; + } + RetVec2 readFirstInvocation( Vec2 const value ) + { + return RetVec2{ *findWriter( value ) + , expr::makeReadFirstInvocation2F( findExprCache( value ) + , findTypesCache( value ) + , makeExpr( value ) ) + , areOptionalEnabled( value ) }; + } + RetVec3 readFirstInvocation( Vec3 const value ) + { + return RetVec3{ *findWriter( value ) + , expr::makeReadFirstInvocation3F( findExprCache( value ) + , findTypesCache( value ) + , makeExpr( value ) ) + , areOptionalEnabled( value ) }; + } + RetVec4 readFirstInvocation( Vec4 const value ) + { + return RetVec4{ *findWriter( value ) + , expr::makeReadFirstInvocation4F( findExprCache( value ) + , findTypesCache( value ) + , makeExpr( value ) ) + , areOptionalEnabled( value ) }; + } + RetInt32 readFirstInvocation( Int32 const value ) + { + return RetInt32{ *findWriter( value ) + , expr::makeReadFirstInvocation1I( findExprCache( value ) + , findTypesCache( value ) + , makeExpr( value ) ) + , areOptionalEnabled( value ) }; + } + RetI32Vec2 readFirstInvocation( I32Vec2 const value ) + { + return RetI32Vec2{ *findWriter( value ) + , expr::makeReadFirstInvocation2I( findExprCache( value ) + , findTypesCache( value ) + , makeExpr( value ) ) + , areOptionalEnabled( value ) }; + } + RetI32Vec3 readFirstInvocation( I32Vec3 const value ) + { + return RetI32Vec3{ *findWriter( value ) + , expr::makeReadFirstInvocation3I( findExprCache( value ) + , findTypesCache( value ) + , makeExpr( value ) ) + , areOptionalEnabled( value ) }; + } + RetI32Vec4 readFirstInvocation( I32Vec4 const value ) + { + return RetI32Vec4{ *findWriter( value ) + , expr::makeReadFirstInvocation4I( findExprCache( value ) + , findTypesCache( value ) + , makeExpr( value ) ) + , areOptionalEnabled( value ) }; + } + RetUInt32 readFirstInvocation( UInt32 const value ) + { + return RetUInt32{ *findWriter( value ) + , expr::makeReadFirstInvocation1U( findExprCache( value ) + , findTypesCache( value ) + , makeExpr( value ) ) + , areOptionalEnabled( value ) }; + } + RetU32Vec2 readFirstInvocation( U32Vec2 const value ) + { + return RetU32Vec2{ *findWriter( value ) + , expr::makeReadFirstInvocation2U( findExprCache( value ) + , findTypesCache( value ) + , makeExpr( value ) ) + , areOptionalEnabled( value ) }; + } + RetU32Vec3 readFirstInvocation( U32Vec3 const value ) + { + return RetU32Vec3{ *findWriter( value ) + , expr::makeReadFirstInvocation3U( findExprCache( value ) + , findTypesCache( value ) + , makeExpr( value ) ) + , areOptionalEnabled( value ) }; + } + RetU32Vec4 readFirstInvocation( U32Vec4 const value ) + { + return RetU32Vec4{ *findWriter( value ) + , expr::makeReadFirstInvocation4U( findExprCache( value ) + , findTypesCache( value ) + , makeExpr( value ) ) + , areOptionalEnabled( value ) }; + } + RetDouble readFirstInvocation( Double const value ) + { + return RetDouble{ *findWriter( value ) + , expr::makeReadFirstInvocation1D( findExprCache( value ) + , findTypesCache( value ) + , makeExpr( value ) ) + , areOptionalEnabled( value ) }; + } + RetDVec2 readFirstInvocation( DVec2 const value ) + { + return RetDVec2{ *findWriter( value ) + , expr::makeReadFirstInvocation2D( findExprCache( value ) + , findTypesCache( value ) + , makeExpr( value ) ) + , areOptionalEnabled( value ) }; + } + RetDVec3 readFirstInvocation( DVec3 const value ) + { + return RetDVec3{ *findWriter( value ) + , expr::makeReadFirstInvocation3D( findExprCache( value ) + , findTypesCache( value ) + , makeExpr( value ) ) + , areOptionalEnabled( value ) }; + } + RetDVec4 readFirstInvocation( DVec4 const value ) + { + return RetDVec4{ *findWriter( value ) + , expr::makeReadFirstInvocation4D( findExprCache( value ) + , findTypesCache( value ) + , makeExpr( value ) ) + , areOptionalEnabled( value ) }; + } + /**@}*/ +#pragma endregion } diff --git a/test/ShaderWriter/TestWriterIntrinsics.cpp b/test/ShaderWriter/TestWriterIntrinsics.cpp index 20adac04..bab06cc6 100644 --- a/test/ShaderWriter/TestWriterIntrinsics.cpp +++ b/test/ShaderWriter/TestWriterIntrinsics.cpp @@ -5500,6 +5500,90 @@ namespace testSubgroupQuadSwapDiagonalT< sdw::BVec3 >( "3B", testCounts ); testSubgroupQuadSwapDiagonalT< sdw::BVec4 >( "4B", testCounts ); } + + template< typename ValueT > + void testReadInvocationT( std::string const & name + , test::sdw_test::TestCounts & testCounts ) + { + using namespace sdw; + testBegin( "testReadInvocation" + name ); + { + sdw::ComputeWriter writer{ &testCounts.allocator }; + writer.implementMainT< VoidT >( 32u + , [&]( ComputeIn ) + { + auto op = writer.declLocale< ValueT >( "op" + , test::getDefault< ValueT >( writer ) ); + auto res = writer.declLocale( "res" + , readInvocation( op, 1_u ) ); + } ); + test::writeShader( writer + , testCounts, CurrentCompilers ); + } + testEnd(); + } + + void testReadInvocation( test::sdw_test::TestCounts & testCounts ) + { + testReadInvocationT< sdw::Float >( "1F", testCounts ); + testReadInvocationT< sdw::Vec2 >( "2F", testCounts ); + testReadInvocationT< sdw::Vec3 >( "3F", testCounts ); + testReadInvocationT< sdw::Vec4 >( "4F", testCounts ); + testReadInvocationT< sdw::Double >( "1D", testCounts ); + testReadInvocationT< sdw::DVec2 >( "2D", testCounts ); + testReadInvocationT< sdw::DVec3 >( "3D", testCounts ); + testReadInvocationT< sdw::DVec4 >( "4D", testCounts ); + testReadInvocationT< sdw::Int >( "1I", testCounts ); + testReadInvocationT< sdw::IVec2 >( "2I", testCounts ); + testReadInvocationT< sdw::IVec3 >( "3I", testCounts ); + testReadInvocationT< sdw::IVec4 >( "4I", testCounts ); + testReadInvocationT< sdw::UInt >( "1U", testCounts ); + testReadInvocationT< sdw::UVec2 >( "2U", testCounts ); + testReadInvocationT< sdw::UVec3 >( "3U", testCounts ); + testReadInvocationT< sdw::UVec4 >( "4U", testCounts ); + } + + template< typename ValueT > + void testReadFirstInvocationT( std::string const & name + , test::sdw_test::TestCounts & testCounts ) + { + using namespace sdw; + testBegin( "testReadFirstInvocation" + name ); + { + sdw::ComputeWriter writer{ &testCounts.allocator }; + writer.implementMainT< VoidT >( 32u + , [&]( ComputeIn ) + { + auto op = writer.declLocale< ValueT >( "op" + , test::getDefault< ValueT >( writer ) ); + auto res = writer.declLocale( "res" + , readFirstInvocation( op ) ); + } ); + test::writeShader( writer + , testCounts, CurrentCompilers ); + } + testEnd(); + } + + void testReadFirstInvocation( test::sdw_test::TestCounts & testCounts ) + { + testReadFirstInvocationT< sdw::Float >( "1F", testCounts ); + testReadFirstInvocationT< sdw::Vec2 >( "2F", testCounts ); + testReadFirstInvocationT< sdw::Vec3 >( "3F", testCounts ); + testReadFirstInvocationT< sdw::Vec4 >( "4F", testCounts ); + testReadFirstInvocationT< sdw::Double >( "1D", testCounts ); + testReadFirstInvocationT< sdw::DVec2 >( "2D", testCounts ); + testReadFirstInvocationT< sdw::DVec3 >( "3D", testCounts ); + testReadFirstInvocationT< sdw::DVec4 >( "4D", testCounts ); + testReadFirstInvocationT< sdw::Int >( "1I", testCounts ); + testReadFirstInvocationT< sdw::IVec2 >( "2I", testCounts ); + testReadFirstInvocationT< sdw::IVec3 >( "3I", testCounts ); + testReadFirstInvocationT< sdw::IVec4 >( "4I", testCounts ); + testReadFirstInvocationT< sdw::UInt >( "1U", testCounts ); + testReadFirstInvocationT< sdw::UVec2 >( "2U", testCounts ); + testReadFirstInvocationT< sdw::UVec3 >( "3U", testCounts ); + testReadFirstInvocationT< sdw::UVec4 >( "4U", testCounts ); + } } sdwTestSuiteMain( TestWriterIntrinsics ) @@ -5687,6 +5771,8 @@ sdwTestSuiteMain( TestWriterIntrinsics ) testSubgroupQuadSwapHorizontal( testCounts ); testSubgroupQuadSwapVertical( testCounts ); testSubgroupQuadSwapDiagonal( testCounts ); + testReadInvocation( testCounts ); + testReadFirstInvocation( testCounts ); sdwTestSuiteEnd(); }