yum-mirror/slang
Making it easier to work with shaders
git clone https://git.yummers.dev/yum-mirror/slang
43d0c2100
master
1#include "core/slang-basic.h" 2#include "core/slang-blob.h" 3#include "gfx-test-util.h" 4#include "unit-test/slang-unit-test.h" 5 6#include <slang-rhi.h> 7#include <slang-rhi/shader-cursor.h> 8 9using namespace rhi ; 10 11namespace gfx_test 12{ 13static Slang ::Result loadProgram ( 14IDevice * device , 15Slang ::ComPtr < IShaderProgram >& outShaderProgram , 16const char * mainModuleName , 17const char * libModuleName , 18const char * entryPointName , 19 slang::ProgramLayout *& slangReflection ) 20{ 21Slang ::ComPtr < slang::ISession > slangSession ; 22SLANG_RETURN_ON_FAIL (device -> getSlangSession (slangSession .writeRef ())); 23Slang ::ComPtr < slang::IBlob > diagnosticsBlob ; 24 25// Load main module 26 slang::IModule * mainModule = 27slangSession -> loadModule (mainModuleName ,diagnosticsBlob .writeRef ()); 28diagnoseIfNeeded (diagnosticsBlob ); 29if (!mainModule ) 30return SLANG_FAIL ; 31 32// Load library module with constants 33 slang::IModule * libModule = slangSession -> loadModule (libModuleName ,diagnosticsBlob .writeRef ()); 34diagnoseIfNeeded (diagnosticsBlob ); 35if (!libModule ) 36return SLANG_FAIL ; 37 38// Find entry point 39ComPtr < slang::IEntryPoint > computeEntryPoint ; 40SLANG_RETURN_ON_FAIL ( 41mainModule -> findEntryPointByName (entryPointName ,computeEntryPoint .writeRef ())); 42 43// Compose program from modules 44Slang ::List < slang::IComponentType *> componentTypes ; 45componentTypes .add (mainModule ); 46componentTypes .add (libModule ); 47componentTypes .add (computeEntryPoint ); 48 49Slang ::ComPtr < slang::IComponentType > composedProgram ; 50SlangResult result = slangSession -> createCompositeComponentType ( 51componentTypes .getBuffer (), 52componentTypes .getCount (), 53composedProgram .writeRef (), 54diagnosticsBlob .writeRef ()); 55diagnoseIfNeeded (diagnosticsBlob ); 56SLANG_RETURN_ON_FAIL (result ); 57 58// Link program 59ComPtr < slang::IComponentType > linkedProgram ; 60result = composedProgram -> link (linkedProgram .writeRef (),diagnosticsBlob .writeRef ()); 61diagnoseIfNeeded (diagnosticsBlob ); 62SLANG_RETURN_ON_FAIL (result ); 63 64composedProgram = linkedProgram ; 65slangReflection = composedProgram -> getLayout (); 66 67// Create shader program 68ShaderProgramDesc programDesc = {}; 69programDesc .slangGlobalScope = composedProgram .get (); 70 71auto shaderProgram = device -> createShaderProgram (programDesc ); 72 73outShaderProgram = shaderProgram ; 74return SLANG_OK ; 75} 76 77// Function to validate the array size in struct S 78static void validateArraySizeInStruct ( 79UnitTestContext * context , 80 slang::ProgramLayout * slangReflection , 81int expectedSize ) 82{ 83// Check reflection is available 84SLANG_CHECK_ABORT (slangReflection != nullptr ); 85 86// Get the global scope layout 87auto globalScope = slangReflection -> getGlobalParamsVarLayout (); 88SLANG_CHECK_ABORT (globalScope != nullptr ); 89 90auto typeLayout = globalScope -> getTypeLayout (); 91SLANG_CHECK_ABORT (typeLayout != nullptr ); 92 93// Check if the global scope is a struct type 94auto kind = typeLayout -> getKind (); 95SLANG_CHECK_ABORT (kind == slang::TypeReflection ::Kind ::Struct ); 96 97// Find the buffer resource 'b' 98bool foundBuffer = false; 99auto fieldCount = typeLayout -> getFieldCount (); 100 101for (unsigned int i = 0 ;i < fieldCount ;i ++ ) 102 { 103auto fieldLayout = typeLayout -> getFieldByIndex (i ); 104const char * fieldName = fieldLayout -> getName (); 105 106if (fieldName && strcmp (fieldName ,"b" )== 0 ) 107 { 108foundBuffer = true; 109 110// Get the type layout of the field 111auto fieldTypeLayout = fieldLayout -> getTypeLayout (); 112SLANG_CHECK_MSG (fieldTypeLayout != nullptr ,"Field has no type layout" ); 113 114// Get the element type of the structured buffer 115auto elementTypeLayout = fieldTypeLayout -> getElementTypeLayout (); 116SLANG_CHECK_MSG ( 117elementTypeLayout != nullptr , 118"Structured buffer has no element type layout" ); 119// Check if it's a struct type 120auto elementKind = elementTypeLayout -> getKind (); 121SLANG_CHECK_MSG ( 122elementKind == slang::TypeReflection ::Kind ::Struct , 123"Buffer element is not a struct type" ); 124 125// Get the field count of the struct 126auto structFieldCount = elementTypeLayout -> getFieldCount (); 127SLANG_CHECK_MSG (structFieldCount >=1 ,"Struct has no fields" ); 128 129// Check for the 'xs' field 130bool foundXsField = false; 131for (unsigned int j = 0 ;j < structFieldCount ;j ++ ) 132 { 133auto structField = elementTypeLayout -> getFieldByIndex (j ); 134const char * structFieldName = structField -> getName (); 135 136if (structFieldName && strcmp (structFieldName ,"xs" )== 0 ) 137 { 138foundXsField = true; 139 140// Check that it's an array type 141auto structFieldTypeLayout = structField -> getTypeLayout (); 142auto structFieldTypeKind = structFieldTypeLayout -> getKind (); 143 144SLANG_CHECK_MSG ( 145structFieldTypeKind == slang::TypeReflection ::Kind ::Array , 146"Field 'xs' is not an array type" ); 147 148// Check the array size 149auto arraySize = structFieldTypeLayout -> getElementCount (); 150// 0 becuase we haven't resolved the constant 151SLANG_CHECK_MSG ( 152arraySize == 0 , 153"Field 'xs' array size does not match expected size" ); 154 155// 4 because we're resolving it 156const auto resolvedArraySize = 157structFieldTypeLayout -> getElementCount (slangReflection ); 158SLANG_CHECK_MSG ( 159resolvedArraySize == expectedSize , 160"Field 'xs' array size does not match expected size" ); 161 162break ; 163 } 164 } 165 166SLANG_CHECK_MSG (foundXsField ,"Could not find field 'xs' in struct S" ); 167break ; 168 } 169 } 170 171SLANG_CHECK_MSG (foundBuffer ,"Could not find buffer 'b' in global scope" ); 172} 173 174 175void linkTimeConstantArraySizeTestImpl (IDevice * device ,UnitTestContext * context ) 176{ 177// Load and link program 178ComPtr < IShaderProgram > shaderProgram ; 179 slang::ProgramLayout * slangReflection ; 180GFX_CHECK_CALL_ABORT (loadProgram ( 181device , 182shaderProgram , 183"link-time-constant-array-size-main" , 184"link-time-constant-array-size-lib" , 185"computeMain" , 186slangReflection )); 187 188// Check array size through reflection 189const int N = 4 ;// This should match the constant in lib.slang 190 191validateArraySizeInStruct (context ,slangReflection ,N ); 192 193// Create compute pipeline 194ComputePipelineDesc pipelineDesc = {}; 195pipelineDesc .program = shaderProgram .get (); 196ComPtr < IComputePipeline > pipelineState ; 197GFX_CHECK_CALL_ABORT (device -> createComputePipeline (pipelineDesc ,pipelineState .writeRef ())); 198 199// Create buffer for struct S with array of size N 200int32_t initialData []= {1 ,2 ,3 ,4 }; 201BufferDesc bufferDesc = {}; 202bufferDesc .size = N * sizeof (int32_t ); 203bufferDesc .format = Format ::Undefined ; 204bufferDesc .elementSize = sizeof (int32_t ); 205bufferDesc .usage = BufferUsage ::ShaderResource |BufferUsage ::UnorderedAccess | 206BufferUsage ::CopyDestination |BufferUsage ::CopySource ; 207bufferDesc .defaultState = ResourceState ::UnorderedAccess ; 208bufferDesc .memoryType = MemoryType ::DeviceLocal ; 209 210ComPtr < IBuffer > numbersBuffer ; 211GFX_CHECK_CALL_ABORT ( 212device -> createBuffer (bufferDesc , (void * )initialData ,numbersBuffer .writeRef ())); 213 214// Record and execute command buffer 215 { 216auto queue = device -> getQueue (QueueType ::Graphics ); 217auto commandEncoder = queue -> createCommandEncoder (); 218auto encoder = commandEncoder -> beginComputePass (); 219 220auto rootObject = encoder -> bindPipeline (pipelineState ); 221 222ShaderCursor rootCursor (rootObject ); 223rootCursor .getPath ("b" ).setBinding (Binding (numbersBuffer )); 224 225encoder -> dispatchCompute (1 ,1 ,1 ); 226encoder -> end (); 227queue -> submit (commandEncoder -> finish ()); 228queue -> waitOnHost (); 229 } 230 231// Expected results: each element is input * N 232// With N=4 and inputs [1,2,3,4], expected output is [4,8,12,16] 233compareComputeResult (device ,numbersBuffer , std::array {4 ,8 ,12 ,16 }); 234} 235 236SLANG_UNIT_TEST (linkTimeConstantArraySizeD3D12 ) 237{ 238runTestImpl (linkTimeConstantArraySizeTestImpl ,unitTestContext ,DeviceType ::D3D12 ); 239} 240 241SLANG_UNIT_TEST (linkTimeConstantArraySizeVulkan ) 242{ 243runTestImpl (linkTimeConstantArraySizeTestImpl ,unitTestContext ,DeviceType ::Vulkan ); 244} 245 246}// namespace gfx_test