yum-mirror/slang
Making it easier to work with shaders
git clone https://git.yummers.dev/yum-mirror/slang
dcc7c6f00
master
1 2#include "slang-render-api-util.h" 3 4#include "slang-list.h" 5#include "slang-platform.h" 6#include "slang-string-util.h" 7#include "slang.h" 8 9namespace Slang 10{ 11 12// NOTE! Must keep in same order as RenderApiType and have same amount of entries 13/* static */ const RenderApiUtil ::Info RenderApiUtil ::s_infos []= { 14 {RenderApiType ::Vulkan ,"vk,vulkan" ,"" }, 15 {RenderApiType ::D3D12 ,"dx12,d3d12" ,"" }, 16 {RenderApiType ::D3D11 ,"dx11,d3d11" ,"hlsl,hlsl-rewrite,glsl-rewrite,glsl-cross,slang" }, 17 {RenderApiType ::Metal ,"mtl,metal" ,"" }, 18 {RenderApiType ::CPU ,"cpu" ,"" }, 19 {RenderApiType ::CUDA ,"cuda" ,"cuda,ptx" }, 20 {RenderApiType ::WebGPU ,"wgpu,webgpu" ,"wgsl" }, 21}; 22 23static int _calcAvailableApis () 24{ 25int flags = 0 ; 26for (int i = 0 ;i < int (RenderApiType ::CountOf );i ++ ) 27 { 28if (RenderApiUtil ::calcHasApi (RenderApiType (i ))) 29 { 30flags |= (1 <<i ); 31 } 32 } 33 34return flags ; 35} 36 37/* static */ int RenderApiUtil ::getAvailableApis () 38{ 39static int s_availableApis = _calcAvailableApis (); 40return s_availableApis ; 41} 42 43UnownedStringSlice RenderApiUtil ::getApiName (RenderApiType type ) 44{ 45int index = int (type ); 46if (index < 0 || index >=int (RenderApiType ::CountOf )) 47 { 48return UnownedStringSlice (); 49 } 50SLANG_ASSERT (s_infos [index ].type == type ); 51return StringUtil ::getAtInSplit (UnownedStringSlice (s_infos [index ].names ),',' ,0 ); 52} 53 54/* static */ RenderApiType RenderApiUtil ::findApiTypeByName (const Slang ::UnownedStringSlice & name ) 55{ 56using namespace Slang ; 57List < UnownedStringSlice > namesList ; 58for (Index j = 0 ;j < SLANG_COUNT_OF (RenderApiUtil ::s_infos );j ++ ) 59 { 60const auto & apiInfo = RenderApiUtil ::s_infos [j ]; 61const UnownedStringSlice names (apiInfo .names ); 62 63if (names .indexOf (',' ) >=0 ) 64 { 65StringUtil ::split (names ,',' ,namesList ); 66if (namesList .indexOf (name )!= Index (-1 )) 67 { 68return apiInfo .type ; 69 } 70 } 71else if (names == name ) 72 { 73return apiInfo .type ; 74 } 75 } 76return RenderApiType ::Unknown ; 77} 78 79/* static */ Slang ::Result RenderApiUtil ::findApiFlagsByName ( 80const Slang ::UnownedStringSlice & name , 81RenderApiFlags * flagsOut ) 82{ 83// Special case 'all' 84if (name == "all" ) 85 { 86* flagsOut = RenderApiFlags (RenderApiFlag ::AllOf ); 87return SLANG_OK ; 88 } 89if (name == "none" ) 90 { 91* flagsOut = RenderApiFlags (0 ); 92return SLANG_OK ; 93 } 94RenderApiType type = findApiTypeByName (name ); 95if (type == RenderApiType ::Unknown ) 96 { 97return SLANG_FAIL ; 98 } 99* flagsOut = RenderApiFlags (1 ) <<int (type ); 100return SLANG_OK ; 101} 102 103static bool isNameStartChar (char c ) 104{ 105return (c >='a' && c <='z' )|| (c >='A' && c <='Z' )|| (c == '_' ); 106} 107 108static bool isNameNextChar (char c ) 109{ 110return (c >='a' && c <='z' )|| (c >='A' && c <='Z' )|| (c == '_' )|| (c >='0' && c <='9' ); 111} 112 113namespace 114{// anonymous 115enum class Token 116{ 117eError , 118eOp , 119eId , 120eEnd , 121}; 122}// namespace 123 124static Token nextToken (Slang ::UnownedStringSlice & textInOut ,Slang ::UnownedStringSlice & lexemeOut ) 125{ 126using namespace Slang ; 127if (textInOut .getLength () <=0 ) 128 { 129return Token ::eEnd ; 130 } 131const char * start = textInOut .begin (); 132const char * end = textInOut .end (); 133 134const char firstChar = start [0 ]; 135if (firstChar == '-' || firstChar == '+' ) 136 { 137lexemeOut = UnownedStringSlice (start ,start + 1 ); 138textInOut = UnownedStringSlice (start + 1 ,end ); 139return Token ::eOp ; 140 } 141 142if (!isNameStartChar (firstChar )) 143 { 144lexemeOut = UnownedStringSlice (start ,start + 1 ); 145return Token ::eError ; 146 } 147const char * cur = start + 1 ; 148while (cur < end && isNameNextChar (* cur )) 149 { 150cur ++ ; 151 } 152 153lexemeOut = UnownedStringSlice (start ,cur ); 154textInOut = UnownedStringSlice (cur ,end ); 155return Token ::eId ; 156} 157 158/* static */ Slang ::Result RenderApiUtil ::parseApiFlags ( 159const Slang ::UnownedStringSlice & textIn , 160RenderApiFlags initialFlags , 161RenderApiFlags * apiFlagsOut ) 162{ 163using namespace Slang ; 164 165UnownedStringSlice text (textIn ); 166UnownedStringSlice lexeme ; 167 168RenderApiFlags apiFlags = 0 ; 169 170switch (nextToken (text ,lexeme )) 171 { 172case Token ::eOp : 173 { 174// If we start with an op - we use the passed in values as the default 175// Rewind back to the start 176text = textIn ; 177apiFlags = initialFlags ; 178break ; 179 } 180case Token ::eId : 181 { 182// If we start with an Id - we use that as the starting state 183SLANG_RETURN_ON_FAIL (findApiFlagsByName (lexeme ,& apiFlags )); 184break ; 185 } 186default : 187return SLANG_FAIL ; 188 } 189 190while (true) 191 { 192// Must have an op followed by an id unless we are at the end 193switch (nextToken (text ,lexeme )) 194 { 195case Token ::eEnd : 196 { 197* apiFlagsOut = apiFlags ; 198return SLANG_OK ; 199 } 200case Token ::eOp : 201break ; 202default : 203return SLANG_FAIL ; 204 } 205 206const char op = lexeme [0 ]; 207if (nextToken (text ,lexeme )!= Token ::eId ) 208 { 209return SLANG_FAIL ; 210 } 211 212RenderApiFlags flags ; 213SLANG_RETURN_ON_FAIL (findApiFlagsByName (lexeme ,& flags )); 214 215if (op == '+' ) 216 { 217apiFlags |=flags ; 218 } 219else 220 { 221apiFlags &= ~flags ; 222 } 223 } 224} 225 226/* static */ RenderApiType RenderApiUtil ::findRenderApiType (const Slang ::UnownedStringSlice & text ) 227{ 228using namespace Slang ; 229for (Index j = 0 ;j < SLANG_COUNT_OF (RenderApiUtil ::s_infos );j ++ ) 230 { 231const auto & apiInfo = RenderApiUtil ::s_infos [j ]; 232if (StringUtil ::indexOfInSplit (UnownedStringSlice (apiInfo .names ),',' ,text ) >=0 ) 233 { 234return apiInfo .type ; 235 } 236 } 237// Didn't find any 238return RenderApiType ::Unknown ; 239} 240 241/* static */ RenderApiType RenderApiUtil ::findImplicitLanguageRenderApiType ( 242const Slang ::UnownedStringSlice & text ) 243{ 244using namespace Slang ; 245for (Index j = 0 ;j < SLANG_COUNT_OF (RenderApiUtil ::s_infos );j ++ ) 246 { 247const auto & apiInfo = RenderApiUtil ::s_infos [j ]; 248if (StringUtil ::indexOfInSplit (UnownedStringSlice (apiInfo .languageNames ),',' ,text ) >=0 ) 249 { 250return apiInfo .type ; 251 } 252 } 253// Didn't find any 254return RenderApiType ::Unknown ; 255} 256 257#if SLANG_ENABLE_DIRECTX 258static bool _canLoadSharedLibrary (const char * libName ) 259{ 260SharedLibrary ::Handle handle ; 261SlangResult res = SharedLibrary ::load (libName ,handle ); 262if (SLANG_FAILED (res )) 263 { 264return false; 265 } 266SharedLibrary ::unload (handle ); 267return true; 268} 269#endif 270 271/* static */ bool RenderApiUtil ::calcHasApi (RenderApiType type ) 272{ 273switch (type ) 274 { 275#if SLANG_WINDOWS_FAMILY 276case RenderApiType ::Vulkan : 277return _canLoadSharedLibrary ("vulkan-1" )|| _canLoadSharedLibrary ("vk_swiftshader" ); 278case RenderApiType ::WebGPU : 279return _canLoadSharedLibrary ("webgpu_dawn" )&& _canLoadSharedLibrary ("dxcompiler" )&& 280_canLoadSharedLibrary ("dxil" ); 281#elif SLANG_APPLE_FAMILY 282case RenderApiType ::Vulkan : 283return true; 284case RenderApiType ::Metal : 285return true; 286#elif SLANG_UNIX_FAMILY 287case RenderApiType ::Vulkan : 288return true; 289#endif 290 291#if SLANG_ENABLE_DIRECTX 292case RenderApiType ::D3D11 : 293return _canLoadSharedLibrary (SLANG_ENABLE_DXVK ?"dxvk_d3d11" :"d3d11" ); 294case RenderApiType ::D3D12 : 295return _canLoadSharedLibrary (SLANG_ENABLE_VKD3D ?"vkd3d-proton-d3d12" :"d3d12" ); 296#endif 297 298case RenderApiType ::CPU : 299return true; 300// We'll assume CUDA is available, and if not, trying to create it will detect it 301case RenderApiType ::CUDA : 302return true; 303default : 304break ; 305 } 306return false; 307} 308 309}// namespace Slang