yum-mirror/slang
Making it easier to work with shaders
git clone https://git.yummers.dev/yum-mirror/slang
0d26dbaad
master
1// unit-test-translation-unit-import.cpp 2 3#include "../../source/core/slang-io.h" 4#include "../../source/core/slang-process.h" 5#include "slang-com-ptr.h" 6#include "slang.h" 7#include "unit-test/slang-unit-test.h" 8 9#include <stdio.h> 10#include <stdlib.h> 11 12using namespace Slang ; 13 14static String getTypeFullName (slang::TypeReflection * type ) 15{ 16ComPtr < ISlangBlob > blob ; 17type -> getFullName (blob .writeRef ()); 18return String ((const char * )blob -> getBufferPointer ()); 19} 20 21// Test that the reflection API provides correct info about entry point and ordinary functions. 22 23SLANG_UNIT_TEST (functionReflection ) 24{ 25// Source for a module that contains an undecorated entrypoint. 26const char * userSourceBody = R"( 27[__AttributeUsage(_AttributeTargets.Function)] 28struct MyFuncPropertyAttribute {int v;} 29 30[MyFuncProperty(1024)] 31[Differentiable] 32float ordinaryFunc(no_diff float x, int y) { return x + y; } 33 34float4 fragMain(float4 pos:SV_Position) : SV_Position 35{ 36return pos; 37} 38 39float foo(float x) { return x; } 40float foo(float x, uint i) { return x + i; } 41 42int bar1(IFloat a, IFloat b) { return 0; } 43int bar2<T>(T a, float3 b) { return 0; } 44int bar3(float3 b) { return 0; } 45int bar4<T:IFloat>(T a){return 0;} 46 47struct Foo { __init() {} } 48)" ; 49 50auto moduleName = "moduleG" + String (Process ::getId ()); 51String userSource = "import " + moduleName + ";\n" + userSourceBody ; 52ComPtr < slang::IGlobalSession > globalSession ; 53SLANG_CHECK (slang_createGlobalSession (SLANG_API_VERSION ,globalSession .writeRef ())== SLANG_OK ); 54 slang::TargetDesc targetDesc = {}; 55targetDesc .format = SLANG_HLSL ; 56targetDesc .profile = globalSession -> findProfile ("sm_5_0" ); 57 slang::SessionDesc sessionDesc = {}; 58sessionDesc .targetCount = 1 ; 59sessionDesc .targets = & targetDesc ; 60ComPtr < slang::ISession > session ; 61SLANG_CHECK (globalSession -> createSession (sessionDesc ,session .writeRef ())== SLANG_OK ); 62 63ComPtr < slang::IBlob > diagnosticBlob ; 64auto module = session -> loadModuleFromSourceString ( 65"m" , 66"m.slang" , 67userSourceBody , 68diagnosticBlob .writeRef ()); 69SLANG_CHECK (module != nullptr ); 70 71ComPtr < slang::IEntryPoint > entryPoint ; 72module -> findAndCheckEntryPoint ( 73"fragMain" , 74SLANG_STAGE_FRAGMENT , 75entryPoint .writeRef (), 76diagnosticBlob .writeRef ()); 77SLANG_CHECK (entryPoint != nullptr ); 78 79auto entryPointFuncReflection = entryPoint -> getFunctionReflection (); 80SLANG_CHECK (entryPointFuncReflection != nullptr ); 81SLANG_CHECK (UnownedStringSlice (entryPointFuncReflection -> getName ())== "fragMain" ); 82SLANG_CHECK (entryPointFuncReflection -> getParameterCount ()== 1 ); 83SLANG_CHECK ( 84UnownedStringSlice (entryPointFuncReflection -> getParameterByIndex (0 )-> getName ())== "pos" ); 85SLANG_CHECK ( 86getTypeFullName (entryPointFuncReflection -> getParameterByIndex (0 )-> getType ())== 87"vector<float,4>" ); 88 89auto funcReflection = module -> getLayout ()-> findFunctionByName ("ordinaryFunc" ); 90SLANG_CHECK (funcReflection != nullptr ); 91 92SLANG_CHECK (funcReflection -> findModifier (slang::Modifier ::Differentiable )!= nullptr ); 93SLANG_CHECK (getTypeFullName (funcReflection -> getReturnType ())== "float" ); 94SLANG_CHECK (UnownedStringSlice (funcReflection -> getName ())== "ordinaryFunc" ); 95SLANG_CHECK (funcReflection -> getParameterCount ()== 2 ); 96SLANG_CHECK (UnownedStringSlice (funcReflection -> getParameterByIndex (0 )-> getName ())== "x" ); 97SLANG_CHECK (getTypeFullName (funcReflection -> getParameterByIndex (0 )-> getType ())== "float" ); 98SLANG_CHECK ( 99funcReflection -> getParameterByIndex (0 )-> findModifier (slang::Modifier ::NoDiff )!= nullptr ); 100 101SLANG_CHECK (UnownedStringSlice (funcReflection -> getParameterByIndex (1 )-> getName ())== "y" ); 102SLANG_CHECK (getTypeFullName (funcReflection -> getParameterByIndex (1 )-> getType ())== "int" ); 103 104SLANG_CHECK (funcReflection -> getUserAttributeCount ()== 1 ); 105auto userAttribute = funcReflection -> getUserAttributeByIndex (0 ); 106SLANG_CHECK (UnownedStringSlice (userAttribute -> getName ())== "MyFuncProperty" ); 107SLANG_CHECK (userAttribute -> getArgumentCount ()== 1 ); 108SLANG_CHECK (getTypeFullName (userAttribute -> getArgumentType (0 ))== "int" ); 109int val = 0 ; 110auto result = userAttribute -> getArgumentValueInt (0 ,& val ); 111SLANG_CHECK (result == SLANG_OK ); 112SLANG_CHECK (val == 1024 ); 113SLANG_CHECK ( 114funcReflection -> findAttributeByName (globalSession .get (),"MyFuncProperty" )== 115userAttribute ); 116 117// Check overloaded method resolution 118auto overloadReflection = module -> getLayout ()-> findFunctionByName ("foo" ); 119SLANG_CHECK (overloadReflection != nullptr ); 120SLANG_CHECK (overloadReflection -> isOverloaded ()== true); 121SLANG_CHECK (overloadReflection -> getOverloadCount ()== 2 ); 122 123auto firstOverload = overloadReflection -> getOverload (0 ); 124SLANG_CHECK (firstOverload != nullptr ); 125SLANG_CHECK (UnownedStringSlice (firstOverload -> getName ())== "foo" ); 126SLANG_CHECK (firstOverload -> getParameterCount ()== 2 ); 127SLANG_CHECK (UnownedStringSlice (firstOverload -> getParameterByIndex (0 )-> getName ())== "x" ); 128SLANG_CHECK (getTypeFullName (firstOverload -> getParameterByIndex (0 )-> getType ())== "float" ); 129SLANG_CHECK (UnownedStringSlice (firstOverload -> getParameterByIndex (1 )-> getName ())== "i" ); 130SLANG_CHECK (getTypeFullName (firstOverload -> getParameterByIndex (1 )-> getType ())== "uint" ); 131 132auto secondOverload = overloadReflection -> getOverload (1 ); 133SLANG_CHECK (secondOverload != nullptr ); 134SLANG_CHECK (UnownedStringSlice (secondOverload -> getName ())== "foo" ); 135SLANG_CHECK (secondOverload -> getParameterCount ()== 1 ); 136SLANG_CHECK (UnownedStringSlice (secondOverload -> getParameterByIndex (0 )-> getName ())== "x" ); 137 138// Check overload resolution via argument types. 139 slang::TypeReflection * argTypes []= { 140module -> getLayout ()-> findTypeByName ("float" ), 141module -> getLayout ()-> findTypeByName ("uint" ), 142 }; 143auto resolvedFunctionReflection = overloadReflection -> specializeWithArgTypes (2 ,argTypes ); 144SLANG_CHECK (resolvedFunctionReflection == firstOverload ); 145 146// 147// More testing for specializeWithArgTypes 148// 149 150// bar1 (IFloat, IFloat) -> int 151// 152auto bar1Reflection = module -> getLayout ()-> findFunctionByName ("bar1" ); 153SLANG_CHECK (bar1Reflection != nullptr ); 154SLANG_CHECK (bar1Reflection -> isOverloaded ()== false); 155SLANG_CHECK (bar1Reflection -> getParameterCount ()== 2 ); 156 157auto float3Type = module -> getLayout ()-> findTypeByName ("float3" ); 158SLANG_CHECK (float3Type != nullptr ); 159argTypes [0 ]= float3Type ; 160argTypes [1 ]= float3Type ; 161 162resolvedFunctionReflection = bar1Reflection -> specializeWithArgTypes (2 ,argTypes ); 163 164SLANG_CHECK (resolvedFunctionReflection != nullptr ); 165SLANG_CHECK (resolvedFunctionReflection -> getParameterCount ()== 2 ); 166SLANG_CHECK ( 167getTypeFullName (resolvedFunctionReflection -> getParameterByIndex (0 )-> getType ())== "IFloat" ); 168SLANG_CHECK ( 169getTypeFullName (resolvedFunctionReflection -> getParameterByIndex (1 )-> getType ())== "IFloat" ); 170 171// bar2 (T : IFloat, float3) -> int 172// 173auto bar2Reflection = module -> getLayout ()-> findFunctionByName ("bar2" ); 174SLANG_CHECK (bar2Reflection != nullptr ); 175SLANG_CHECK (bar2Reflection -> isOverloaded ()== false); 176SLANG_CHECK (bar2Reflection -> getParameterCount ()== 2 ); 177 178auto floatType = module -> getLayout ()-> findTypeByName ("float" ); 179SLANG_CHECK (floatType != nullptr ); 180argTypes [0 ]= floatType ; 181argTypes [1 ]= float3Type ; 182 183resolvedFunctionReflection = bar2Reflection -> specializeWithArgTypes (2 ,argTypes ); 184 185SLANG_CHECK (resolvedFunctionReflection != nullptr ); 186SLANG_CHECK (resolvedFunctionReflection -> getParameterCount ()== 2 ); 187SLANG_CHECK ( 188getTypeFullName (resolvedFunctionReflection -> getParameterByIndex (0 )-> getType ())== "float" ); 189SLANG_CHECK ( 190getTypeFullName (resolvedFunctionReflection -> getParameterByIndex (1 )-> getType ())== 191"vector<float,3>" ); 192 193 194// failure case 195argTypes [0 ]= floatType ; 196argTypes [1 ]= module -> getLayout ()-> findTypeByName ("float2" ); 197resolvedFunctionReflection = bar2Reflection -> specializeWithArgTypes (2 ,argTypes ); 198SLANG_CHECK (resolvedFunctionReflection == nullptr );// any errors should result in a nullptr. 199 200// bar3 (float3) -> int 201// (trivial case) 202auto bar3Reflection = module -> getLayout ()-> findFunctionByName ("bar3" ); 203SLANG_CHECK (bar3Reflection != nullptr ); 204SLANG_CHECK (bar3Reflection -> isOverloaded ()== false); 205SLANG_CHECK (bar3Reflection -> getParameterCount ()== 1 ); 206 207argTypes [0 ]= float3Type ; 208resolvedFunctionReflection = bar3Reflection -> specializeWithArgTypes (1 ,argTypes ); 209SLANG_CHECK (resolvedFunctionReflection != nullptr ); 210SLANG_CHECK (resolvedFunctionReflection == bar3Reflection ); 211 212// GitHub issue #6317: bar2 is a function, not a type, so it should not be found. 213SLANG_CHECK (module -> getLayout ()-> findTypeByName ("bar4" )== nullptr ); 214 215auto fooType = module -> getLayout ()-> findTypeByName ("Foo" ); 216SLANG_CHECK_ABORT (fooType != nullptr ); 217auto ctor = module -> getLayout ()-> findFunctionByNameInType (fooType ,"$init" ); 218SLANG_CHECK (ctor != nullptr ); 219} 220 221// Test that findFunctionByNameInType finds all functions with the same name but different 222// signatures 223SLANG_UNIT_TEST (findFunctionByNameInType ) 224{ 225// Test shader with extensions that have functions with same name but different signatures 226const char * userSourceBody = R"( 227public interface IModel<float:IDifferentiable> 228{ 229public float forward(float x); 230} 231 232interface IScalarActivation<float:IDifferentiable> {} 233 234public extension<float:IDifferentiable, Act:IScalarActivation<float>> Act: IModel<float> 235{ 236public float forward(float x) { return x;} 237} 238 239public struct MyStruct<float:IDifferentiable>: IScalarActivation<float> {} 240 241public extension<float:IDifferentiable> MyStruct<float>: IModel<float[2]> 242{ 243public float[2] forward(float[2] x) { return x;} 244} 245 246[shader("compute")] 247void computeMain(uint3 tid: SV_DispatchThreadID) 248{ 249} 250)" ; 251 252auto moduleName = "moduleH" + String (Process ::getId ()); 253String userSource = "import " + moduleName + ";\n" + userSourceBody ; 254ComPtr < slang::IGlobalSession > globalSession ; 255SLANG_CHECK (slang_createGlobalSession (SLANG_API_VERSION ,globalSession .writeRef ())== SLANG_OK ); 256 slang::TargetDesc targetDesc = {}; 257targetDesc .format = SLANG_HLSL ; 258targetDesc .profile = globalSession -> findProfile ("sm_5_0" ); 259 slang::SessionDesc sessionDesc = {}; 260sessionDesc .targetCount = 1 ; 261sessionDesc .targets = & targetDesc ; 262ComPtr < slang::ISession > session ; 263SLANG_CHECK (globalSession -> createSession (sessionDesc ,session .writeRef ())== SLANG_OK ); 264 265ComPtr < slang::IBlob > diagnosticBlob ; 266auto module = session -> loadModuleFromSourceString ( 267"test_module" , 268"test_module.slang" , 269userSourceBody , 270diagnosticBlob .writeRef ()); 271SLANG_CHECK (module != nullptr ); 272 273auto myStructType = module -> getLayout ()-> findTypeByName ("MyStruct<float>" ); 274SLANG_CHECK_ABORT (myStructType != nullptr ); 275 276// Try to find the "forward" function in MyStruct<float> 277// This should find functions with different signatures from both extensions: 278// 1. float forward(float x) from the generic extension Act: IModel<float> 279// 2. float[2] forward(float[2] x) from the MyStruct-specific extension MyStruct<float>: 280// IModel<float[2]> 281auto forwardFunc = module -> getLayout ()-> findFunctionByNameInType (myStructType ,"forward" ); 282 283// With the fix, this should find functions with different signatures 284SLANG_CHECK (forwardFunc != nullptr ); 285 286// The function should be overloaded since there are multiple functions with different 287// signatures 288if (forwardFunc -> isOverloaded ()) 289 { 290// If it's overloaded, verify we can access both variants 291SLANG_CHECK (forwardFunc -> getOverloadCount () >=2 ); 292 293// We should be able to find both: 294// - One with float parameter type (from generic extension) 295// - One with float[2] parameter type (from MyStruct-specific extension) 296bool foundFloatParam = false; 297bool foundFloatArrayParam = false; 298 299for (int i = 0 ;i < forwardFunc -> getOverloadCount ();i ++ ) 300 { 301auto overload = forwardFunc -> getOverload (i ); 302// Check that each overload has the correct name 303SLANG_CHECK (UnownedStringSlice (overload -> getName ())== "forward" ); 304if (overload -> getParameterCount ()> 0 ) 305 { 306auto paramTypeName = overload -> getParameterByIndex (0 )-> getType ()-> getName (); 307if (strstr (paramTypeName ,"Array" )) 308 { 309foundFloatArrayParam = true; 310 } 311else if (strstr (paramTypeName ,"float" )) 312 { 313foundFloatParam = true; 314 } 315 } 316 } 317 318// Both variants should be found 319SLANG_CHECK (foundFloatParam ); 320SLANG_CHECK (foundFloatArrayParam ); 321 } 322else 323 { 324// The function should be overloaded since there are multiple functions with different 325// signatures. If it's not overloaded, the fix didn't work properly. 326SLANG_CHECK_ABORT (false&& "Expected function to be overloaded with multiple signatures" ); 327 } 328}