yum-mirror/slang
Making it easier to work with shaders
git clone https://git.yummers.dev/yum-mirror/slang
43d0c2100
master
1#pragma once 2 3#include "core/slang-basic.h" 4#include "core/slang-blob.h" 5#include "core/slang-render-api-util.h" 6#include "core/slang-test-tool-util.h" 7#include "slang-rhi.h" 8#include "span.h" 9#include "unit-test/slang-unit-test.h" 10 11// GFX_CHECK_CALL and GFX_CHECK_CALL_ABORT are used to check SlangResult 12#define GFX_CHECK_CALL (x ) SLANG_CHECK(!SLANG_FAILED(x)) 13#define GFX_CHECK_CALL_ABORT (x ) SLANG_CHECK_ABORT(!SLANG_FAILED(x)) 14 15using namespace rhi ; 16 17namespace gfx_test 18{ 19enum class PrecompilationMode 20{ 21None , 22SlangIR , 23InternalLink , 24ExternalLink , 25}; 26/// Helper function for print out diagnostic messages output by Slang compiler. 27void diagnoseIfNeeded (slang ::IBlob * diagnosticsBlob ); 28 29/// Loads a compute shader module and produces a `rhi::IShaderProgram`. 30Slang ::Result loadComputeProgram ( 31rhi ::IDevice * device , 32Slang ::ComPtr < rhi ::IShaderProgram >& outShaderProgram , 33const char * shaderModuleName , 34const char * entryPointName , 35slang ::ProgramLayout *& slangReflection ); 36 37Slang ::Result loadComputeProgram ( 38rhi ::IDevice * device , 39slang ::ISession * slangSession , 40Slang ::ComPtr < rhi ::IShaderProgram >& outShaderProgram , 41const char * shaderModuleName , 42const char * entryPointName , 43slang ::ProgramLayout *& slangReflection ); 44 45Slang ::Result loadComputeProgramFromSource ( 46rhi ::IDevice * device , 47Slang ::ComPtr < rhi ::IShaderProgram >& outShaderProgram , 48std ::string_view source ); 49 50Slang ::Result loadGraphicsProgram ( 51rhi ::IDevice * device , 52Slang ::ComPtr < rhi ::IShaderProgram >& outShaderProgram , 53const char * shaderModuleName , 54const char * vertexEntryPointName , 55const char * fragmentEntryPointName , 56slang ::ProgramLayout *& slangReflection ); 57 58template < typename T > 59void compareResultFuzzy (const T * result ,const T * expectedResult ,size_t count ) 60{ 61for (size_t i = 0 ;i < count ;++ i ) 62 { 63SLANG_CHECK (abs (result [i ]- expectedResult [i ])< 0.01f ); 64 } 65} 66 67template < typename T > 68void compareResult (const T * result ,const T * expectedResult ,size_t count ) 69{ 70for (size_t i = 0 ;i < count ;i ++ ) 71 { 72SLANG_CHECK (result [i ]== expectedResult [i ]); 73 } 74} 75 76template < typename T > 77void compareComputeResult (rhi ::IDevice * device ,rhi ::IBuffer * buffer ,span < T > expectedResult ) 78{ 79size_t bufferSize = expectedResult .size ()* sizeof (T ); 80// Read back the results.` 81ComPtr < ISlangBlob > bufferData ; 82SLANG_CHECK ( SLANG_SUCCEEDED ( device -> readBuffer ( buffer , 0 , bufferSize , bufferData . writeRef ()))); 83SLANG_CHECK ( bufferData -> getBufferSize () == bufferSize ); 84const T * result = reinterpret_cast < const T *>( bufferData -> getBufferPointer ()); 85 86if constexpr ( std :: is_same < T , float >:: value || std :: is_same < T , double >:: value ) 87compareResultFuzzy ( result , expectedResult . data (), expectedResult . size ()); 88else 89compareResult < T >( result , expectedResult . data (), expectedResult . size ()); 90} 91 92template < typename T , size_t Count > 93void compareComputeResult ( 94rhi :: IDevice * device , 95rhi :: IBuffer * buffer , 96std :: array < T , Count > expectedResult ) 97{ 98compareComputeResult ( device , buffer , span < T >( expectedResult . data (), Count )); 99} 100 101template < typename T > 102void compareComputeResult ( 103rhi :: IDevice * device , 104rhi :: ITexture * texture , 105uint32_t layer , 106uint32_t mip , 107span < T > expectedResult ) 108{ 109size_t bufferSize = expectedResult . size () * sizeof ( T ); 110// Read back the results. 111ComPtr < ISlangBlob > textureData ; 112rhi :: SubresourceLayout layout ; 113SLANG_CHECK ( 114SLANG_SUCCEEDED ( device -> readTexture ( texture , layer , mip , textureData . writeRef (), & layout ))); 115SLANG_CHECK ( textureData -> getBufferSize () >= bufferSize ); 116 117uint8_t * buffer = ( uint8_t *) textureData -> getBufferPointer (); 118for ( uint32_t z = 0 ; z < layout . size . depth ; z ++) 119{ 120for ( uint32_t y = 0 ; y < layout . size . height ; y ++) 121{ 122for ( uint32_t x = 0 ; x < layout . size . width ; x ++) 123{ 124const uint8_t * src = reinterpret_cast < const uint8_t *>( 125buffer + z * layout . slicePitch + y * layout . rowPitch + x * layout . colPitch ); 126uint8_t * dst = reinterpret_cast < uint8_t *>( 127buffer + 128((( z * layout . size . depth + y ) * layout . size . width ) + x ) * layout . colPitch ); 129:: memcpy ( dst , src , layout . colPitch ); 130} 131} 132} 133 134const T * result = reinterpret_cast < const T *>( textureData -> getBufferPointer ()); 135 136if constexpr ( std :: is_same < T , float >:: value ) 137compareResultFuzzy ( result , expectedResult . data (), expectedResult . size ()); 138else 139compareResult < T >( result , expectedResult . data (), expectedResult . size ()); 140} 141 142template < typename T , size_t Count > 143void compareComputeResult ( 144rhi :: IDevice * device , 145rhi :: ITexture * texture , 146uint32_t layer , 147uint32_t mip , 148std :: array < T , Count > expectedResult ) 149{ 150compareComputeResult ( device , texture , layer , mip , span < T >( expectedResult . data (), Count )); 151} 152 153Slang :: ComPtr < rhi :: IDevice > createTestingDevice ( 154UnitTestContext * context , 155rhi :: DeviceType deviceType , 156Slang :: List < const char *> additionalSearchPaths = {}); 157 158Slang :: List < const char *> getSlangSearchPaths (); 159 160void initializeRenderDoc (); 161void renderDocBeginFrame (); 162void renderDocEndFrame (); 163 164template < typename T , typename ... Args > 165auto makeArray ( Args ... args ) 166{ 167return std :: array < T , sizeof ...( Args )>{ static_cast < T >( args )...}; 168} 169 170inline bool deviceTypeInEnabledApis ( rhi :: DeviceType deviceType , Slang :: RenderApiFlags enabledApis ) 171{ 172switch ( deviceType ) 173{ 174case rhi :: DeviceType :: Default : 175return true; 176case rhi :: DeviceType :: CPU : 177return enabledApis & Slang :: RenderApiFlag :: CPU ; 178case rhi :: DeviceType :: CUDA : 179return enabledApis & Slang :: RenderApiFlag :: CUDA ; 180case rhi :: DeviceType :: Metal : 181return enabledApis & Slang :: RenderApiFlag :: Metal ; 182case rhi :: DeviceType :: WGPU : 183return enabledApis & Slang :: RenderApiFlag :: WebGPU ; 184case rhi :: DeviceType :: Vulkan : 185return enabledApis & Slang :: RenderApiFlag :: Vulkan ; 186case rhi :: DeviceType :: D3D11 : 187return enabledApis & Slang :: RenderApiFlag :: D3D11 ; 188case rhi :: DeviceType :: D3D12 : 189return enabledApis & Slang :: RenderApiFlag :: D3D12 ; 190} 191return true; 192} 193 194 195template < typename ImplFunc > 196void runTestImpl ( 197const ImplFunc & f , 198UnitTestContext * context , 199rhi :: DeviceType deviceType , 200Slang :: List < const char *> searchPaths = {}) 201{ 202if (! deviceTypeInEnabledApis ( deviceType , context -> enabledApis )) 203{ 204SLANG_IGNORE_TEST 205} 206 207auto device = createTestingDevice ( context , deviceType , searchPaths ); 208if (! device ) 209{ 210SLANG_IGNORE_TEST 211} 212#if SLANG_WIN32 213// Skip d3d12 tests on x86 now since dxc doesn't function correctly there on Windows 11. 214if ( rhi :: DeviceType == rhi :: DeviceType :: D3D12 ) 215{ 216SLANG_IGNORE_TEST 217} 218#endif 219// Skip d3d11 tests when we don't have DXBC support as they're bound to 220// fail without a backend compiler 221if ( deviceType == rhi :: DeviceType :: D3D11 && ! SLANG_ENABLE_DXBC_SUPPORT ) 222{ 223SLANG_IGNORE_TEST 224} 225try 226{ 227renderDocBeginFrame (); 228f ( device , context ); 229} 230catch ( AbortTestException & e ) 231{ 232renderDocEndFrame (); 233throw e ; 234} 235renderDocEndFrame (); 236} 237 238} // namespace gfx_test