yum-mirror/slang
Making it easier to work with shaders
git clone https://git.yummers.dev/yum-mirror/slang
04db5a956
master
1// slang-glslang-compiler.cpp 2#include "slang-glslang-compiler.h" 3 4#include "../core/slang-blob.h" 5#include "../core/slang-char-util.h" 6#include "../core/slang-common.h" 7#include "../core/slang-io.h" 8#include "../core/slang-semantic-version.h" 9#include "../core/slang-shared-library.h" 10#include "../core/slang-string-slice-pool.h" 11#include "../core/slang-string-util.h" 12#include "slang-artifact-associated-impl.h" 13#include "slang-artifact-desc-util.h" 14#include "slang-com-helper.h" 15#include "slang-include-system.h" 16#include "slang-source-loc.h" 17 18// Enable calling through to `glslang` on 19// all platforms. 20#ifndef SLANG_ENABLE_GLSLANG_SUPPORT 21#define SLANG_ENABLE_GLSLANG_SUPPORT 1 22#endif 23 24#if SLANG_ENABLE_GLSLANG_SUPPORT 25#include "../slang-glslang/slang-glslang.h" 26#endif 27 28namespace Slang 29{ 30 31#if SLANG_ENABLE_GLSLANG_SUPPORT 32 33class GlslangDownstreamCompiler :public DownstreamCompilerBase 34{ 35public : 36typedef DownstreamCompilerBase Super ; 37 38// IDownstreamCompiler 39virtual SLANG_NO_THROW SlangResult SLANG_MCALL 40compile (const CompileOptions & options ,IArtifact ** outResult )SLANG_OVERRIDE ; 41virtual SLANG_NO_THROW bool SLANG_MCALL 42canConvert (const ArtifactDesc & from ,const ArtifactDesc & to )SLANG_OVERRIDE ; 43virtual SLANG_NO_THROW SlangResult SLANG_MCALL 44convert (IArtifact * from ,const ArtifactDesc & to ,IArtifact ** outArtifact )SLANG_OVERRIDE ; 45virtual SLANG_NO_THROW bool SLANG_MCALL isFileBased ()SLANG_OVERRIDE {return false; } 46virtual SLANG_NO_THROW SlangResult SLANG_MCALL getVersionString (slang::IBlob ** outVersionString ) 47SLANG_OVERRIDE ; 48virtual SLANG_NO_THROW SlangResult SLANG_MCALL 49validate (const uint32_t * contents ,int contentsSize )SLANG_OVERRIDE ; 50virtual SLANG_NO_THROW SlangResult SLANG_MCALL 51disassemble (const uint32_t * contents ,int contentsSize )SLANG_OVERRIDE ; 52virtual SLANG_NO_THROW SlangResult SLANG_MCALL disassembleWithResult ( 53const uint32_t * contents , 54int contentsSize , 55String & outString )SLANG_OVERRIDE ; 56virtual SLANG_NO_THROW int SLANG_MCALL link ( 57const uint32_t ** modules , 58const uint32_t * moduleSizes , 59const uint32_t moduleCount , 60IArtifact ** outArtifact )SLANG_OVERRIDE ; 61 62/// Must be called before use 63SlangResult init (ISlangSharedLibrary * library ); 64 65GlslangDownstreamCompiler (SlangPassThrough compilerType ) 66 :m_compilerType (compilerType ) 67 { 68 } 69 70protected : 71SlangResult _invoke (glslang_CompileRequest_1_2 & request ); 72 73glslang_CompileFunc_1_0 m_compile_1_0 = nullptr ; 74glslang_CompileFunc_1_1 m_compile_1_1 = nullptr ; 75glslang_CompileFunc_1_2 m_compile_1_2 = nullptr ; 76glslang_ValidateSPIRVFunc m_validate = nullptr ; 77glslang_DisassembleSPIRVFunc m_disassemble = nullptr ; 78glslang_DisassembleSPIRVWithResultFunc m_disassembleWithResult = nullptr ; 79glslang_LinkSPIRVFunc m_link = nullptr ; 80 81ComPtr < ISlangSharedLibrary > m_sharedLibrary ; 82 83SlangPassThrough m_compilerType ; 84}; 85 86SlangResult GlslangDownstreamCompiler ::init (ISlangSharedLibrary * library ) 87{ 88m_compile_1_0 = (glslang_CompileFunc_1_0 )library -> findFuncByName ("glslang_compile" ); 89m_compile_1_1 = (glslang_CompileFunc_1_1 )library -> findFuncByName ("glslang_compile_1_1" ); 90m_compile_1_2 = (glslang_CompileFunc_1_2 )library -> findFuncByName ("glslang_compile_1_2" ); 91m_validate = (glslang_ValidateSPIRVFunc )library -> findFuncByName ("glslang_validateSPIRV" ); 92m_disassemble = 93 (glslang_DisassembleSPIRVFunc )library -> findFuncByName ("glslang_disassembleSPIRV" ); 94m_disassembleWithResult = (glslang_DisassembleSPIRVWithResultFunc )library -> findFuncByName ( 95"glslang_disassembleSPIRVWithResult" ); 96m_link = (glslang_LinkSPIRVFunc )library -> findFuncByName ("glslang_linkSPIRV" ); 97 98if (m_compile_1_0 == nullptr && m_compile_1_1 == nullptr && m_compile_1_2 == nullptr ) 99 { 100return SLANG_FAIL ; 101 } 102 103m_sharedLibrary = library ; 104 105// It's not clear how to query for a version, but we can get a version number from the header 106m_desc = Desc (m_compilerType ); 107 108Slang ::String filename ; 109if (m_compile_1_2 ) 110 { 111filename = Slang ::SharedLibraryUtils ::getSharedLibraryFileName ((void * )m_compile_1_2 ); 112 } 113else if (m_compile_1_1 ) 114 { 115filename = Slang ::SharedLibraryUtils ::getSharedLibraryFileName ((void * )m_compile_1_1 ); 116 } 117else if (m_compile_1_0 ) 118 { 119filename = Slang ::SharedLibraryUtils ::getSharedLibraryFileName ((void * )m_compile_1_0 ); 120 } 121else 122 { 123return SLANG_FAIL ; 124 } 125 126return SLANG_OK ; 127} 128 129SlangResult GlslangDownstreamCompiler ::_invoke (glslang_CompileRequest_1_2 & request ) 130{ 131int err = 1 ; 132if (m_compile_1_2 ) 133 { 134err = m_compile_1_2 (& request ); 135 } 136else if (m_compile_1_1 ) 137 { 138glslang_CompileRequest_1_1 request_1_1 ; 139memcpy (& request_1_1 ,& request ,sizeof (request_1_1 )); 140request_1_1 .sizeInBytes = sizeof (request_1_1 ); 141err = m_compile_1_1 (& request_1_1 ); 142 } 143else if (m_compile_1_0 ) 144 { 145glslang_CompileRequest_1_1 request_1_1 ; 146memcpy (& request_1_1 ,& request ,sizeof (request_1_1 )); 147request_1_1 .sizeInBytes = sizeof (request_1_1 ); 148glslang_CompileRequest_1_0 request_1_0 ; 149request_1_0 .set (request_1_1 ); 150err = m_compile_1_0 (& request_1_0 ); 151 } 152 153return err ?SLANG_FAIL :SLANG_OK ; 154} 155 156static SlangResult _parseDiagnosticLine ( 157SliceAllocator & allocator , 158const UnownedStringSlice & line , 159List < UnownedStringSlice >& lineSlices , 160ArtifactDiagnostic & outDiagnostic ) 161{ 162/* ERROR: tests/diagnostics/syntax-error-intrinsic.slang:13: '@' : unexpected token */ 163 164if (lineSlices .getCount ()< 4 ) 165 { 166return SLANG_FAIL ; 167 } 168 { 169const UnownedStringSlice severitySlice = lineSlices [0 ].trim (); 170 171outDiagnostic .severity = ArtifactDiagnostic ::Severity ::Error ; 172if (severitySlice .caseInsensitiveEquals (UnownedStringSlice ::fromLiteral ("warning" ))) 173 { 174outDiagnostic .severity = ArtifactDiagnostic ::Severity ::Warning ; 175 } 176 } 177 178outDiagnostic .filePath = allocator .allocate (lineSlices [1 ]); 179 180SLANG_RETURN_ON_FAIL (StringUtil ::parseInt (lineSlices [2 ],outDiagnostic .location .line )); 181outDiagnostic .text = allocator .allocate (lineSlices [3 ].begin (),line .end ()); 182return SLANG_OK ; 183} 184 185SlangResult GlslangDownstreamCompiler ::compile ( 186const CompileOptions & inOptions , 187IArtifact ** outArtifact ) 188{ 189if (!isVersionCompatible (inOptions )) 190 { 191// Not possible to compile with this version of the interface. 192return SLANG_E_NOT_IMPLEMENTED ; 193 } 194 195CompileOptions options = getCompatibleVersion (& inOptions ); 196 197// This compiler can only handle a single artifact 198if (options .sourceArtifacts .count != 1 ) 199 { 200return SLANG_FAIL ; 201 } 202 203IArtifact * sourceArtifact = options .sourceArtifacts [0 ]; 204 205if (options .targetType != SLANG_SPIRV ) 206 { 207SLANG_ASSERT (!"Can only compile to SPIR-V" ); 208return SLANG_FAIL ; 209 } 210 211StringBuilder diagnosticOutput ; 212auto diagnosticOutputFunc = [](void const * data ,size_t size ,void * userData ) 213 { (* (StringBuilder * )userData ).append ((char const * )data , (char const * )data + size ); }; 214List < uint8_t > spirv ; 215auto outputFunc = [](void const * data ,size_t size ,void * userData ) 216 { ((List < uint8_t >* )userData )-> addRange ((uint8_t * )data ,size ); }; 217 218ComPtr < ISlangBlob > sourceBlob ; 219SLANG_RETURN_ON_FAIL (sourceArtifact -> loadBlob (ArtifactKeep ::Yes ,sourceBlob .writeRef ())); 220 221String sourcePath = ArtifactUtil ::findPath (sourceArtifact ); 222 223glslang_CompileRequest_1_2 request ; 224memset (& request ,0 ,sizeof (request )); 225request .sizeInBytes = sizeof (request ); 226 227switch (options .sourceLanguage ) 228 { 229case SLANG_SOURCE_LANGUAGE_GLSL : 230request .action = GLSLANG_ACTION_COMPILE_GLSL_TO_SPIRV ; 231break ; 232case SLANG_SOURCE_LANGUAGE_SPIRV : 233request .action = GLSLANG_ACTION_OPTIMIZE_SPIRV ; 234break ; 235default : 236SLANG_ASSERT (!"Can only handle GLSL or SPIR-V as input." ); 237return SLANG_FAIL ; 238 } 239 240request .sourcePath = sourcePath .getBuffer (); 241 242request .slangStage = options .stage ; 243 244const char * inputBegin = (const char * )sourceBlob -> getBufferPointer (); 245request .inputBegin = inputBegin ; 246request .inputEnd = inputBegin + sourceBlob -> getBufferSize (); 247 248// Find the SPIR-V version if set 249SemanticVersion spirvVersion ; 250for (const auto & capabilityVersion :options .requiredCapabilityVersions ) 251 { 252if (capabilityVersion .kind == DownstreamCompileOptions ::CapabilityVersion ::Kind ::SPIRV ) 253 { 254if (capabilityVersion .version > spirvVersion ) 255 { 256spirvVersion = capabilityVersion .version ; 257 } 258 } 259 } 260 261request .spirvVersion .major = spirvVersion .m_major ; 262request .spirvVersion .minor = spirvVersion .m_minor ; 263request .spirvVersion .patch = spirvVersion .m_patch ; 264 265request .outputFunc = outputFunc ; 266request .outputUserData = & spirv ; 267 268request .diagnosticFunc = diagnosticOutputFunc ; 269request .diagnosticUserData = & diagnosticOutput ; 270 271request .optimizationLevel = (unsigned )options .optimizationLevel ; 272request .debugInfoType = (unsigned )options .debugInfoType ; 273 274request .entryPointName = options .entryPointName .begin (); 275 276const SlangResult invokeResult = _invoke (request ); 277 278auto artifact = ArtifactUtil ::createArtifactForCompileTarget (options .targetType ); 279 280auto diagnostics = ArtifactDiagnostics ::create (); 281 282// Set the diagnostics result 283diagnostics -> setResult (invokeResult ); 284 285ArtifactUtil ::addAssociated (artifact ,diagnostics ); 286 287if (SLANG_FAILED (invokeResult )) 288 { 289diagnostics -> setRaw (SliceUtil ::asCharSlice (diagnosticOutput )); 290 291SliceAllocator allocator ; 292 293SlangResult diagnosticParseRes = ArtifactDiagnosticUtil ::parseColonDelimitedDiagnostics ( 294allocator , 295diagnosticOutput .getUnownedSlice (), 2961 , 297_parseDiagnosticLine , 298diagnostics ); 299SLANG_UNUSED (diagnosticParseRes ); 300 301diagnostics -> requireErrorDiagnostic (); 302 } 303else 304 { 305artifact -> addRepresentationUnknown (ListBlob ::moveCreate (spirv )); 306 } 307 308* outArtifact = artifact .detach (); 309return SLANG_OK ; 310} 311 312SlangResult GlslangDownstreamCompiler ::validate (const uint32_t * contents ,int contentsSize ) 313{ 314if (m_validate == nullptr ) 315 { 316return SLANG_FAIL ; 317 } 318 319if (m_validate (contents ,contentsSize )) 320 { 321return SLANG_OK ; 322 } 323return SLANG_FAIL ; 324} 325 326SlangResult GlslangDownstreamCompiler ::disassembleWithResult ( 327const uint32_t * contents , 328int contentsSize , 329String & outString ) 330{ 331if (m_disassembleWithResult == nullptr ) 332 { 333return SLANG_FAIL ; 334 } 335 336char * resultString = nullptr ; 337if (m_disassembleWithResult (contents ,contentsSize ,& resultString )) 338 { 339if (resultString ) 340 { 341outString = String (resultString ); 342return SLANG_OK ; 343 } 344 } 345return SLANG_FAIL ; 346} 347 348SlangResult GlslangDownstreamCompiler ::disassemble (const uint32_t * contents ,int contentsSize ) 349{ 350if (m_disassemble == nullptr ) 351 { 352return SLANG_FAIL ; 353 } 354 355if (m_disassemble (contents ,contentsSize )) 356 { 357return SLANG_OK ; 358 } 359return SLANG_FAIL ; 360} 361 362SlangResult GlslangDownstreamCompiler ::link ( 363const uint32_t ** modules , 364const uint32_t * moduleSizes , 365const uint32_t moduleCount , 366IArtifact ** outArtifact ) 367{ 368glslang_LinkRequest request ; 369memset (& request ,0 ,sizeof (request )); 370 371request .modules = modules ; 372request .moduleSizes = moduleSizes ; 373request .moduleCount = moduleCount ; 374 375if (!m_link (& request )) 376 { 377return SLANG_FAIL ; 378 } 379 380auto artifact = ArtifactUtil ::createArtifactForCompileTarget (SLANG_SPIRV ); 381artifact -> addRepresentationUnknown ( 382Slang ::RawBlob ::create (request .linkResult ,request .linkResultSize * sizeof (uint32_t ))); 383 384* outArtifact = artifact .detach (); 385return SLANG_OK ; 386} 387 388bool GlslangDownstreamCompiler ::canConvert (const ArtifactDesc & from ,const ArtifactDesc & to ) 389{ 390// Can only disassemble blobs that are SPIR-V 391return ArtifactDescUtil ::isDisassembly (from ,to )&& 392 ((from .payload == ArtifactPayload ::SPIRV )|| 393 (from .payload == ArtifactPayload ::WGSL_SPIRV )); 394} 395 396SlangResult GlslangDownstreamCompiler ::convert ( 397IArtifact * from , 398const ArtifactDesc & to , 399IArtifact ** outArtifact ) 400{ 401if (!canConvert (from -> getDesc (),to )) 402 { 403return SLANG_FAIL ; 404 } 405 406ComPtr < ISlangBlob > blob ; 407SLANG_RETURN_ON_FAIL (from -> loadBlob (ArtifactKeep ::No ,blob .writeRef ())); 408 409StringBuilder builder ; 410 411auto outputFunc = [](void const * data ,size_t size ,void * userData ) 412 { (* (StringBuilder * )userData ).append ((char const * )data , (char const * )data + size ); }; 413 414glslang_CompileRequest_1_2 request ; 415memset (& request ,0 ,sizeof (request )); 416request .sizeInBytes = sizeof (request ); 417 418request .action = GLSLANG_ACTION_DISSASSEMBLE_SPIRV ; 419 420request .sourcePath = nullptr ; 421 422char * blobData = (char * )blob -> getBufferPointer (); 423 424request .inputBegin = blobData ; 425request .inputEnd = blobData + blob -> getBufferSize (); 426 427request .outputFunc = outputFunc ; 428request .outputUserData = & builder ; 429 430SLANG_RETURN_ON_FAIL (_invoke (request )); 431 432auto disassemblyBlob = StringBlob ::moveCreate (builder ); 433 434auto artifact = ArtifactUtil ::createArtifact (to ); 435artifact -> addRepresentationUnknown (disassemblyBlob ); 436 437* outArtifact = artifact .detach (); 438 439return SLANG_OK ; 440} 441 442SlangResult GlslangDownstreamCompiler ::getVersionString (slang::IBlob ** outVersionString ) 443{ 444uint64_t timestamp ; 445if (m_compile_1_1 ) 446 { 447timestamp = SharedLibraryUtils ::getSharedLibraryTimestamp ((void * )m_compile_1_1 ); 448 } 449else if (m_compile_1_0 ) 450 { 451timestamp = SharedLibraryUtils ::getSharedLibraryTimestamp ((void * )m_compile_1_0 ); 452 } 453else 454 { 455return SLANG_FAIL ; 456 } 457 458auto timestampString = String (timestamp ); 459ComPtr < ISlangBlob > version = StringBlob ::create (timestampString .getBuffer ()); 460* outVersionString = version .detach (); 461return SLANG_OK ; 462} 463 464static SlangResult locateGlslangSpirvDownstreamCompiler ( 465const String & path , 466ISlangSharedLibraryLoader * loader , 467DownstreamCompilerSet * set , 468SlangPassThrough compilerType ) 469{ 470ComPtr < ISlangSharedLibrary > library ; 471 472#if SLANG_UNIX_FAMILY 473// On unix systems we need to ensure pthread is loaded first. 474// TODO(JS): 475// There is an argument that this should be performed through the loader.... 476// NOTE! We don't currently load through a dependent library, as it is *assumed* something as 477// core as 'ptheads' isn't going to be distributed with the shader compiler. 478ComPtr < ISlangSharedLibrary > pthreadLibrary ; 479DefaultSharedLibraryLoader ::load (loader ,path ,"pthread" ,pthreadLibrary .writeRef ()); 480if (!pthreadLibrary .get ()) 481 { 482DefaultSharedLibraryLoader ::load ( 483loader , 484path , 485"libpthread.so.0" , 486pthreadLibrary .writeRef ()); 487 } 488 489#endif 490 491SLANG_RETURN_ON_FAIL ( 492DownstreamCompilerUtil ::loadSharedLibrary (path ,loader ,nullptr ,"slang-glslang" ,library )); 493 494SLANG_ASSERT (library ); 495if (!library ) 496 { 497return SLANG_FAIL ; 498 } 499 500auto compiler = new GlslangDownstreamCompiler (compilerType ); 501ComPtr < IDownstreamCompiler > compilerIntf (compiler ); 502SLANG_RETURN_ON_FAIL (compiler -> init (library )); 503 504set -> addCompiler (compilerIntf ); 505return SLANG_OK ; 506} 507 508SlangResult GlslangDownstreamCompilerUtil ::locateCompilers ( 509const String & path , 510ISlangSharedLibraryLoader * loader , 511DownstreamCompilerSet * set ) 512{ 513return locateGlslangSpirvDownstreamCompiler (path ,loader ,set ,SLANG_PASS_THROUGH_GLSLANG ); 514} 515 516SlangResult SpirvOptDownstreamCompilerUtil ::locateCompilers ( 517const String & path , 518ISlangSharedLibraryLoader * loader , 519DownstreamCompilerSet * set ) 520{ 521return locateGlslangSpirvDownstreamCompiler (path ,loader ,set ,SLANG_PASS_THROUGH_SPIRV_OPT ); 522} 523 524SlangResult SpirvDisDownstreamCompilerUtil ::locateCompilers ( 525const String & path , 526ISlangSharedLibraryLoader * loader , 527DownstreamCompilerSet * set ) 528{ 529return locateGlslangSpirvDownstreamCompiler (path ,loader ,set ,SLANG_PASS_THROUGH_SPIRV_DIS ); 530} 531 532SlangResult SpirvLinkDownstreamCompilerUtil ::locateCompilers ( 533const String & path , 534ISlangSharedLibraryLoader * loader , 535DownstreamCompilerSet * set ) 536{ 537return locateGlslangSpirvDownstreamCompiler (path ,loader ,set ,SLANG_PASS_THROUGH_SPIRV_LINK ); 538} 539 540#else // SLANG_ENABLE_GLSLANG_SUPPORT 541 542/* static */ SlangResult GlslangDownstreamCompilerUtil ::locateCompilers ( 543const String & path , 544ISlangSharedLibraryLoader * loader , 545DownstreamCompilerSet * set ) 546{ 547SLANG_UNUSED (path ); 548SLANG_UNUSED (loader ); 549SLANG_UNUSED (set ); 550return SLANG_E_NOT_AVAILABLE ; 551} 552 553#endif // SLANG_ENABLE_GLSLANG_SUPPORT 554 555}// namespace Slang