yum-mirror/slang
Making it easier to work with shaders
git clone https://git.yummers.dev/yum-mirror/slang
d50c3f34a
master
1// slang-dxc-compiler.cpp 2#include "slang-dxc-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-artifact-diagnostic-util.h" 15#include "slang-artifact-util.h" 16#include "slang-com-helper.h" 17#include "slang-include-system.h" 18#include "slang-source-loc.h" 19 20// Enable DXIL by default unless told not to 21#ifndef SLANG_ENABLE_DXIL_SUPPORT 22#if SLANG_APPLE_FAMILY 23#define SLANG_ENABLE_DXIL_SUPPORT 0 24#else 25#define SLANG_ENABLE_DXIL_SUPPORT 1 26#endif 27#endif 28 29// Enable calling through to `dxc` to 30// generate code on Windows. 31#if SLANG_ENABLE_DXIL_SUPPORT 32 33#ifdef _WIN32 34#include <unknwn.h> 35#include <windows.h> 36#endif 37 38#include "../../external/dxc/dxcapi.h" 39 40#ifndef _WIN32 41#ifdef __uuidof 42// DXC's WinAdapter.h defines __uuidof(T) over types, but the existing 43// usage in this file is over values (both are accepted on MSVC.) 44// We also need to decay through Slang::ComPtr, hence the helper struct 45template < typename T > 46struct StripSlangComPtr 47{ 48using type = T ; 49}; 50template < typename T > 51struct StripSlangComPtr < Slang ::ComPtr < T >> 52{ 53using type = T ; 54}; 55#undef __uuidof 56#define __uuidof (x ) __emulated_uuidof<StripSlangComPtr<std::decay_t<decltype(x)>>::type>() 57#endif 58#endif 59#endif 60 61namespace Slang 62{ 63 64#if SLANG_ENABLE_DXIL_SUPPORT 65 66static UnownedStringSlice _getSlice (IDxcBlob * blob ) 67{ 68return StringUtil ::getSlice ((ISlangBlob * )blob ); 69} 70 71// IDxcIncludeHandler 72// 7f61fc7d-950d-467f-b3e3-3c02fb49187c 73static const Guid IID_IDxcIncludeHandler = 74 {0x7f61fc7d ,0x950d ,0x467f , {0x3c ,0x02 ,0xfb ,0x49 ,0x18 ,0x7c }}; 75 76static UnownedStringSlice _addName (const UnownedStringSlice & inSlice ,StringSlicePool & pool ) 77{ 78UnownedStringSlice slice = inSlice ; 79if (slice .getLength ()== 0 ) 80 { 81slice = UnownedStringSlice ::fromLiteral ("unnamed" ); 82 } 83 84StringBuilder buf ; 85const Index length = slice .getLength (); 86buf <<slice ; 87 88for (Index i = 0 ;;++ i ) 89 { 90buf .reduceLength (length ); 91 92if (i > 0 ) 93 { 94buf <<"_" <<i ; 95 } 96 97StringSlicePool ::Handle handle ; 98if (!pool .findOrAdd (buf .getUnownedSlice (),handle )) 99 { 100return pool .getSlice (handle ); 101 } 102 } 103} 104 105static UnownedStringSlice _addName (IArtifact * artifact ,StringSlicePool & pool ) 106{ 107return _addName (ArtifactUtil ::findName (artifact ),pool ); 108} 109 110class DxcIncludeHandler :public IDxcIncludeHandler 111{ 112public : 113// Implement IUnknown 114SLANG_NO_THROW HRESULT SLANG_MCALL QueryInterface (const IID & uuid ,void ** out )override 115 { 116ISlangUnknown * intf = getInterface (reinterpret_cast < const Guid &> (uuid )); 117if (intf ) 118 { 119* out = intf ; 120return SLANG_OK ; 121 } 122return SLANG_E_NO_INTERFACE ; 123 } 124SLANG_NO_THROW ULONG SLANG_MCALL AddRef ()SLANG_OVERRIDE {return 1 ; } 125SLANG_NO_THROW ULONG SLANG_MCALL Release ()SLANG_OVERRIDE {return 1 ; } 126 127// Implement IDxcIncludeHandler 128virtual HRESULT SLANG_MCALL LoadSource (LPCWSTR inFilename ,IDxcBlob ** outSource )SLANG_OVERRIDE 129 { 130// Hmm DXC does something a bit odd - when it sees a path, it just passes that in with ./ in 131// front!! NOTE! It doesn't make any difference if it is "" or <> quoted. 132 133// So we just do a work around where we strip if we see a path starting with ./ 134String filePath = String ::fromWString (inFilename ); 135 136// If it starts with ./ then attempt to strip it 137if (filePath .startsWith ("./" )) 138 { 139const String remaining = filePath .getUnownedSlice ().tail (2 ); 140 141// Okay if we strip ./ and what we have is absolute, then it's the absolute path that we 142// care about, otherwise we just leave as is. 143if (Path ::isAbsolute (remaining )) 144 { 145filePath = remaining ; 146 } 147 } 148 149ComPtr < ISlangBlob > blob ; 150PathInfo pathInfo ; 151SlangResult res = m_system .findAndLoadFile (filePath ,String (),pathInfo ,blob ); 152 153// NOTE! This only works because ISlangBlob is *binary compatible* with IDxcBlob, if either 154// change things could go boom 155* outSource = (IDxcBlob * )blob .detach (); 156return res ; 157 } 158 159DxcIncludeHandler ( 160SearchDirectoryList * searchDirectories , 161ISlangFileSystemExt * fileSystemExt , 162SourceManager * sourceManager = nullptr ) 163 :m_system (searchDirectories ,fileSystemExt ,sourceManager ) 164 { 165 } 166 167protected : 168// Used by QueryInterface for casting 169ISlangUnknown * getInterface (const Guid & guid ) 170 { 171if (guid == ISlangUnknown ::getTypeGuid ()|| guid == IID_IDxcIncludeHandler ) 172 { 173return (ISlangUnknown * )(static_cast < IDxcIncludeHandler *> (this )); 174 } 175return nullptr ; 176 } 177 178IncludeSystem m_system ; 179}; 180 181class DXCDownstreamCompiler :public DownstreamCompilerBase 182{ 183public : 184typedef DownstreamCompilerBase Super ; 185 186// IDownstreamCompiler 187virtual SLANG_NO_THROW SlangResult SLANG_MCALL 188compile (const CompileOptions & options ,IArtifact ** outArtifact )SLANG_OVERRIDE ; 189virtual SLANG_NO_THROW bool SLANG_MCALL 190canConvert (const ArtifactDesc & from ,const ArtifactDesc & to )SLANG_OVERRIDE ; 191virtual SLANG_NO_THROW SlangResult SLANG_MCALL 192convert (IArtifact * from ,const ArtifactDesc & to ,IArtifact ** outArtifact )SLANG_OVERRIDE ; 193virtual SLANG_NO_THROW bool SLANG_MCALL isFileBased ()SLANG_OVERRIDE {return false; } 194virtual SLANG_NO_THROW SlangResult SLANG_MCALL getVersionString (slang::IBlob ** outVersionString ) 195SLANG_OVERRIDE ; 196 197/// Must be called before use 198SlangResult init (ISlangSharedLibrary * library ); 199 200DXCDownstreamCompiler () {} 201 202protected : 203DxcCreateInstanceProc m_createInstance = nullptr ; 204 205/// The commit hash associated with the DXC dll used 206/// If 0 length, no hash was found 207String m_commitHash ; 208/// The commit count. 0 if not set 209uint32_t m_commitCount = 0 ; 210 211ComPtr < ISlangSharedLibrary > m_sharedLibrary ; 212}; 213 214static String _moveTaskMemAllocatedToString (char * chars ) 215{ 216if (chars ) 217 { 218const String str (chars ); 219 ::CoTaskMemFree (chars ); 220return str ; 221 } 222return String (); 223} 224 225SlangResult DXCDownstreamCompiler ::init (ISlangSharedLibrary * library ) 226{ 227m_sharedLibrary = library ; 228 229m_createInstance = (DxcCreateInstanceProc )library -> findFuncByName ("DxcCreateInstance" ); 230if (!m_createInstance ) 231 { 232return SLANG_FAIL ; 233 } 234 235// Must be able to create the compiler. We inly do this here, because we want to get the 236// compiler version. 237ComPtr < IDxcCompiler > dxcCompiler ; 238SLANG_RETURN_ON_FAIL (m_createInstance ( 239CLSID_DxcCompiler , 240__uuidof (dxcCompiler ), 241 (LPVOID * )dxcCompiler .writeRef ())); 242 243uint32_t major = 0 ; 244uint32_t minor = 0 ; 245uint32_t patch = 0 ; 246 247// Get the version info 248 { 249ComPtr < IDxcVersionInfo > versionInfo ; 250if (SLANG_SUCCEEDED (dxcCompiler -> QueryInterface (versionInfo .writeRef ()))) 251 { 252versionInfo -> GetVersion (& major ,& minor ); 253 } 254 } 255 256// Get the commit hash 257 { 258 259ComPtr < IDxcVersionInfo2 > versionInfo ; 260if (SLANG_SUCCEEDED (dxcCompiler -> QueryInterface (versionInfo .writeRef ()))) 261 { 262char * commitHash = nullptr ; 263versionInfo -> GetCommitInfo (& m_commitCount ,& commitHash ); 264m_commitHash = _moveTaskMemAllocatedToString (commitHash ); 265 } 266 } 267 268// Try and get the custom build string, as we can potentially get the patch version from that. 269if (patch == 0 ) 270 { 271ComPtr < IDxcVersionInfo3 > versionInfo ; 272 273if (SLANG_SUCCEEDED (dxcCompiler -> QueryInterface (versionInfo .writeRef ()))) 274 { 275char * customVersionCString = nullptr ; 276versionInfo -> GetCustomVersionString (& customVersionCString ); 277 278const String customVersionString = _moveTaskMemAllocatedToString (customVersionCString ); 279 280SemanticVersion semanticVersion (int (major ),int (minor ),0 ); 281StringBuilder buf ; 282semanticVersion .append (buf ); 283 284if (customVersionString .startsWith (buf )&& 285customVersionString .getLength ()> buf .getLength ()+ 2 && 286customVersionString [buf .getLength ()]== '.' ) 287 { 288// Get the patch slice 289UnownedStringSlice patchSlice = 290StringUtil ::getAtInSplit (customVersionString .getUnownedSlice (),'.' ,2 ); 291 292Int patchValue ; 293if (SLANG_SUCCEEDED (StringUtil ::parseInt (patchSlice ,patchValue ))&& patchValue > 0 ) 294 { 295patch = uint32_t (patchValue ); 296 } 297 } 298 } 299 } 300 301m_desc = Desc (SLANG_PASS_THROUGH_DXC ,SemanticVersion (int (major ),int (minor ),int (patch ))); 302 303return SLANG_OK ; 304} 305 306static SlangResult _parseDiagnosticLine ( 307SliceAllocator & allocator , 308const UnownedStringSlice & line , 309List < UnownedStringSlice >& lineSlices , 310IArtifactDiagnostics ::Diagnostic & outDiagnostic ) 311{ 312/* tests/diagnostics/syntax-error-intrinsic.slang:14:2: error: expected expression */ 313if (lineSlices .getCount ()< 5 ) 314 { 315return SLANG_FAIL ; 316 } 317 318outDiagnostic .filePath = allocator .allocate (lineSlices [0 ]); 319 320SLANG_RETURN_ON_FAIL (StringUtil ::parseInt (lineSlices [1 ],outDiagnostic .location .line )); 321 322// Int lineCol; 323// SLANG_RETURN_ON_FAIL(StringUtil::parseInt(lineSlices[2], lineCol)); 324 325UnownedStringSlice severitySlice = lineSlices [3 ].trim (); 326 327outDiagnostic .severity = ArtifactDiagnostic ::Severity ::Error ; 328if (severitySlice == UnownedStringSlice ::fromLiteral ("warning" )) 329 { 330outDiagnostic .severity = ArtifactDiagnostic ::Severity ::Warning ; 331 } 332 333// The rest of the line 334outDiagnostic .text = allocator .allocate (lineSlices [4 ].begin (),line .end ()); 335return SLANG_OK ; 336} 337 338static SlangResult _handleOperationResult ( 339IDxcOperationResult * dxcResult , 340IArtifactDiagnostics * diagnostics , 341ComPtr < IDxcBlob >& outBlob ) 342{ 343// Retrieve result. 344HRESULT resultCode = S_OK ; 345SLANG_RETURN_ON_FAIL (dxcResult -> GetStatus (& resultCode )); 346 347// Note: it seems like the dxcompiler interface 348// doesn't support querying diagnostic output 349// *unless* the compile failed (no way to get 350// warnings out!?). 351 352if (SLANG_SUCCEEDED (diagnostics -> getResult ())) 353 { 354diagnostics -> setResult (resultCode ); 355 } 356 357// Try getting the error/diagnostics blob 358ComPtr < IDxcBlobEncoding > dxcErrorBlob ; 359dxcResult -> GetErrorBuffer (dxcErrorBlob .writeRef ()); 360 361if (dxcErrorBlob ) 362 { 363const UnownedStringSlice diagnosticsSlice = _getSlice (dxcErrorBlob ); 364if (diagnosticsSlice .getLength ()) 365 { 366diagnostics -> appendRaw (asCharSlice (diagnosticsSlice )); 367 368SliceAllocator allocator ; 369List < IArtifactDiagnostics ::Diagnostic > parsedDiagnostics ; 370SlangResult diagnosticParseRes = ArtifactDiagnosticUtil ::parseColonDelimitedDiagnostics ( 371allocator , 372diagnosticsSlice , 3730 , 374_parseDiagnosticLine , 375diagnostics ); 376 377SLANG_UNUSED (diagnosticParseRes ); 378SLANG_ASSERT (SLANG_SUCCEEDED (diagnosticParseRes )); 379 } 380 } 381 382// If it failed, make sure we have an error in the diagnostics 383if (SLANG_FAILED (resultCode )) 384 { 385// In case the parsing failed, we still have an error -> so require there is one in the 386// diagnostics 387diagnostics -> requireErrorDiagnostic (); 388 } 389else 390 { 391// Okay, the compile supposedly succeeded, so we 392// just need to grab the buffer with the output DXIL. 393SLANG_RETURN_ON_FAIL (dxcResult -> GetResult (outBlob .writeRef ())); 394 } 395 396return SLANG_OK ; 397} 398 399SlangResult DXCDownstreamCompiler ::compile (const CompileOptions & inOptions ,IArtifact ** outArtifact ) 400{ 401if (!isVersionCompatible (inOptions )) 402 { 403// Not possible to compile with this version of the interface. 404return SLANG_E_NOT_IMPLEMENTED ; 405 } 406 407CompileOptions options = getCompatibleVersion (& inOptions ); 408 409// This compiler can only deal at most, a single source code artifact 410// Should be okay to link together multiple libraries without any source artifacts (assuming 411// that means source code) 412if (options .sourceArtifacts .count > 1 ) 413 { 414return SLANG_FAIL ; 415 } 416 417bool hasSource = options .sourceArtifacts .count > 0 ; 418 419IArtifact * sourceArtifact = hasSource ?options .sourceArtifacts [0 ] :nullptr ; 420 421if (hasSource ) 422 { 423if (options .sourceLanguage != SLANG_SOURCE_LANGUAGE_HLSL || 424options .targetType != SLANG_DXIL ) 425 { 426SLANG_ASSERT (!"Can only compile HLSL to DXIL" ); 427return SLANG_FAIL ; 428 } 429 } 430 431// Find all of the libraries 432List < IArtifact *> libraries ; 433for (IArtifact * library :options .libraries ) 434 { 435const auto desc = library -> getDesc (); 436 437if (desc .kind == ArtifactKind ::Library && desc .payload == ArtifactPayload ::DXIL ) 438 { 439// Make sure they all have blobs 440ComPtr < ISlangBlob > libraryBlob ; 441SLANG_RETURN_ON_FAIL (library -> loadBlob (ArtifactKeep ::Yes ,libraryBlob .writeRef ())); 442 443libraries .add (library ); 444 } 445 } 446 447ComPtr < IDxcCompiler > dxcCompiler ; 448SLANG_RETURN_ON_FAIL (m_createInstance ( 449CLSID_DxcCompiler , 450__uuidof (dxcCompiler ), 451 (LPVOID * )dxcCompiler .writeRef ())); 452ComPtr < IDxcLibrary > dxcLibrary ; 453SLANG_RETURN_ON_FAIL ( 454m_createInstance (CLSID_DxcLibrary ,__uuidof (dxcLibrary ), (LPVOID * )dxcLibrary .writeRef ())); 455 456ComPtr < IDxcBlobEncoding > dxcSourceBlob = nullptr ; 457ComPtr < ISlangBlob > sourceBlob ; 458if (hasSource ) 459 { 460SLANG_RETURN_ON_FAIL (sourceArtifact -> loadBlob (ArtifactKeep ::Yes ,sourceBlob .writeRef ())); 461 462// Create blob from the string 463SLANG_RETURN_ON_FAIL (dxcLibrary -> CreateBlobWithEncodingFromPinned ( 464 (LPBYTE )sourceBlob -> getBufferPointer (), 465 (UINT32 )sourceBlob -> getBufferSize (), 4660 , 467dxcSourceBlob .writeRef ())); 468 } 469 470List < const WCHAR *> args ; 471 472// Add all compiler specific options 473List < OSString > compilerSpecific ; 474compilerSpecific .setCount (options .compilerSpecificArguments .count ); 475 476for (Index i = 0 ;i < options .compilerSpecificArguments .count ;++ i ) 477 { 478compilerSpecific [i ]= asString (options .compilerSpecificArguments [i ]).toWString (); 479args .add (compilerSpecific [i ]); 480 } 481 482bool enablePAQs = options .enablePAQ ; 483if (!enablePAQs ) 484args .add (L"-disable-payload-qualifiers" ); 485else 486args .add (L"-enable-payload-qualifiers" ); 487 488// TODO: deal with 489bool treatWarningsAsErrors = false; 490if (treatWarningsAsErrors ) 491 { 492args .add (L"-WX" ); 493 } 494 495switch (options .matrixLayout ) 496 { 497default : 498break ; 499 500case SLANG_MATRIX_LAYOUT_ROW_MAJOR : 501args .add (L"-Zpr" ); 502break ; 503 } 504 505switch (options .floatingPointMode ) 506 { 507default : 508break ; 509 510case FloatingPointMode ::Precise : 511args .add (L"-Gis" );// "force IEEE strictness" 512break ; 513 } 514 515switch (options .denormalModeFp32 ) 516 { 517default : 518case CompileOptions ::FloatingPointDenormalMode ::Any : 519break ; 520 521case CompileOptions ::FloatingPointDenormalMode ::Preserve : 522args .add (L"-denorm" ); 523args .add (L"preserve" ); 524break ; 525 526case CompileOptions ::FloatingPointDenormalMode ::FlushToZero : 527args .add (L"-denorm" ); 528args .add (L"ftz" ); 529break ; 530 } 531 532switch (options .optimizationLevel ) 533 { 534default : 535break ; 536 537case OptimizationLevel ::None : 538args .add (L"-Od" ); 539break ; 540case OptimizationLevel ::Default : 541args .add (L"-O1" ); 542break ; 543case OptimizationLevel ::High : 544args .add (L"-O2" ); 545break ; 546case OptimizationLevel ::Maximal : 547args .add (L"-O3" ); 548break ; 549 } 550 551switch (options .debugInfoType ) 552 { 553case DebugInfoType ::None : 554break ; 555 556default : 557args .add (L"-Zi" ); 558break ; 559 } 560 561// Slang strives to produce correct code, and by default 562// we do not show the user warnings produced by a downstream 563// compiler. When the downstream compiler *does* produce an 564// error, then we dump its entire diagnostic log, which can 565// include many distracting spurious warnings that have nothing 566// to do with the user's code, and just relate to the idiomatic 567// way that Slang outputs HLSL. 568// 569// It would be nice to use fine-grained flags to disable specific 570// warnings here, so that we keep ourselves honest (e.g., only 571// use `-Wno-parentheses` to eliminate that class of false positives), 572// but alas dxc doesn't support these options even though they 573// work on mainline Clang. Thus the only option we have available 574// is the big hammer of turning off *all* warnings coming from dxc. 575// 576args .add (L"-no-warnings" ); 577 578String profileName = asString (options .profileName ); 579// If we are going to link we have to compile in the lib profile style 580if (libraries .getCount ()&& hasSource ) 581 { 582if (!profileName .startsWith ("lib" )) 583 { 584const Index index = profileName .indexOf ('_' ); 585if (index < 0 ) 586 { 587profileName = "lib_6_3" ; 588 } 589else 590 { 591StringBuilder buf ; 592buf <<"lib" <<profileName .getUnownedSlice ().tail (index ); 593profileName = buf ; 594 } 595 } 596 } 597 598OSString wideEntryPointName = asString (options .entryPointName ).toWString (); 599OSString wideProfileName = profileName .toWString (); 600 601if (options .flags & CompileOptions ::Flag ::EnableFloat16 ) 602 { 603args .add (L"-enable-16bit-types" ); 604 } 605 606SearchDirectoryList searchDirectories ; 607for (const auto & includePath :options .includePaths ) 608 { 609searchDirectories .searchDirectories .add (asString (includePath )); 610 } 611 612 { 613// Specify -HV 2021 when using a DXC version that supports the newer language model. 614const SemanticVersion firstHlsl2021Version (1 ,7 ); 615 616if (m_desc .version >=firstHlsl2021Version ) 617 { 618args .add (L"-HV" ); 619args .add (L"2021" ); 620 } 621 } 622 623String sourcePath ; 624ComPtr < IDxcBlob > dxcResultBlob = nullptr ; 625auto diagnostics = ArtifactDiagnostics ::create (); 626ComPtr < IDxcOperationResult > dxcOperationResult = nullptr ; 627if (hasSource ) 628 { 629sourcePath = ArtifactUtil ::findPath (sourceArtifact ); 630OSString wideSourcePath = sourcePath .toWString (); 631 632DxcIncludeHandler includeHandler ( 633& searchDirectories , 634options .fileSystemExt , 635options .sourceManager ); 636 637SLANG_RETURN_ON_FAIL (dxcCompiler -> Compile ( 638dxcSourceBlob , 639wideSourcePath .begin (), 640wideEntryPointName .begin (), 641wideProfileName .begin (), 642args .getBuffer (), 643UINT32 (args .getCount ()), 644nullptr ,// `#define`s 6450 ,// `#define` count 646& includeHandler ,// `#include` handler 647dxcOperationResult .writeRef ())); 648 649SLANG_RETURN_ON_FAIL ( 650_handleOperationResult (dxcOperationResult ,diagnostics ,dxcResultBlob )); 651 } 652 653// If we have libraries then we need to link... 654if (libraries .getCount ()) 655 { 656ComPtr < IDxcLinker > linker ; 657SLANG_RETURN_ON_FAIL ( 658m_createInstance (CLSID_DxcLinker ,__uuidof (linker ), (void ** )linker .writeRef ())); 659 660StringSlicePool pool (StringSlicePool ::Style ::Default ); 661 662List < ComPtr < ISlangBlob >> libraryBlobs ; 663List < OSString > libraryNames ; 664 665for (IArtifact * library :libraries ) 666 { 667ComPtr < ISlangBlob > blob ; 668SLANG_RETURN_ON_FAIL (library -> loadBlob (ArtifactKeep ::Yes ,blob .writeRef ())); 669 670libraryBlobs .add (blob ); 671libraryNames .add (String (_addName (library ,pool )).toWString ()); 672 } 673 674if (hasSource ) 675 { 676// Add the compiled blob name 677String name ; 678if (options .modulePath .count ) 679 { 680name = Path ::getFileNameWithoutExt (asString (options .modulePath )); 681 } 682else if (sourcePath .getLength ()) 683 { 684name = Path ::getFileNameWithoutExt (sourcePath ); 685 } 686 687// Add the blob with name 688 { 689auto blob = (ISlangBlob * )dxcResultBlob .get (); 690libraryBlobs .add (ComPtr < ISlangBlob > (blob )); 691libraryNames .add (String (_addName (name .getUnownedSlice (),pool )).toWString ()); 692 } 693 } 694 695const Index librariesCount = libraryNames .getCount (); 696SLANG_ASSERT (libraryBlobs .getCount ()== librariesCount ); 697SLANG_ASSERT (libraryNames .getCount ()== librariesCount ); 698 699List < const wchar_t *> linkLibraryNames ; 700 701linkLibraryNames .setCount (librariesCount ); 702 703for (Index i = 0 ;i < librariesCount ;++ i ) 704 { 705linkLibraryNames [i ]= libraryNames [i ].begin (); 706 707// Register the library 708SLANG_RETURN_ON_FAIL ( 709linker -> RegisterLibrary (linkLibraryNames [i ], (IDxcBlob * )libraryBlobs [i ].get ())); 710 } 711 712// Use the original profile name 713wideProfileName = asString (options .profileName ).toWString (); 714 715ComPtr < IDxcOperationResult > linkDxcResult ; 716SLANG_RETURN_ON_FAIL (linker -> Link ( 717wideEntryPointName .begin (), 718wideProfileName .begin (), 719linkLibraryNames .getBuffer (), 720UINT32 (librariesCount ), 721nullptr , 7220 , 723linkDxcResult .writeRef ())); 724 725ComPtr < IDxcBlob > linkedBlob ; 726SLANG_RETURN_ON_FAIL (_handleOperationResult (linkDxcResult ,diagnostics ,linkedBlob )); 727 728// When we've linked we make that the overall operation result 729// As presumably it can contain pdb and perhaps other information 730dxcOperationResult = linkDxcResult ; 731 732// Set the result blob 733dxcResultBlob = linkedBlob ; 734 } 735 736auto artifact = ArtifactUtil ::createArtifactForCompileTarget (options .targetType ); 737 738ArtifactUtil ::addAssociated (artifact ,diagnostics ); 739 740if (dxcResultBlob ) 741 { 742artifact -> addRepresentationUnknown ((ISlangBlob * )dxcResultBlob .get ()); 743 } 744 745// If asking for PDB extract it. 746if (options .m_debugInfoFormat == SLANG_DEBUG_INFO_FORMAT_PDB ) 747 { 748ComPtr < IDxcResult > dxcResult ; 749if (SLANG_SUCCEEDED (dxcOperationResult -> QueryInterface (dxcResult .writeRef ()))) 750 { 751if (dxcResult -> HasOutput (DXC_OUT_PDB )) 752 { 753ComPtr < IDxcBlob > pdbBlob ; 754ComPtr < IDxcBlobWide > nameBlob ; 755 756if (SLANG_SUCCEEDED (dxcResult -> GetOutput ( 757DXC_OUT_PDB , 758__uuidof (pdbBlob ), 759 (void ** )pdbBlob .writeRef (), 760nameBlob .writeRef ()))) 761 { 762auto pdbArtifact = ArtifactUtil ::createArtifact (ArtifactDesc ::make ( 763ArtifactDesc ::Kind ::BinaryFormat , 764ArtifactDesc ::Payload ::PdbDebugInfo )); 765 766if (nameBlob ) 767 { 768const auto wideName = (const WCHAR * )nameBlob -> GetBufferPointer (); 769 770const auto name = String ::fromWString (wideName ); 771if (name .getLength ()) 772 { 773// Set the name on the artifact. This is the name that must be used for 774// the PDB to be loadable as a file by other tooling. 775pdbArtifact -> setName (name .getBuffer ()); 776 } 777 } 778 779pdbArtifact -> addRepresentationUnknown ((ISlangBlob * )pdbBlob .get ()); 780 781// Associate it 782artifact -> addAssociated (pdbArtifact ); 783 } 784 } 785 } 786 } 787 788* outArtifact = artifact .detach (); 789return SLANG_OK ; 790} 791 792bool DXCDownstreamCompiler ::canConvert (const ArtifactDesc & from ,const ArtifactDesc & to ) 793{ 794return ArtifactDescUtil ::isDisassembly (from ,to )&& from .payload == ArtifactPayload ::DXIL ; 795} 796 797SlangResult DXCDownstreamCompiler ::convert ( 798IArtifact * from , 799const ArtifactDesc & to , 800IArtifact ** outArtifact ) 801{ 802// Can only disassemble blobs that are DXIL 803if (!canConvert (from -> getDesc (),to )) 804 { 805return SLANG_FAIL ; 806 } 807 808ComPtr < ISlangBlob > dxilBlob ; 809SLANG_RETURN_ON_FAIL (from -> loadBlob (ArtifactKeep ::No ,dxilBlob .writeRef ())); 810 811ComPtr < IDxcCompiler > dxcCompiler ; 812SLANG_RETURN_ON_FAIL (m_createInstance ( 813CLSID_DxcCompiler , 814__uuidof (dxcCompiler ), 815 (LPVOID * )dxcCompiler .writeRef ())); 816ComPtr < IDxcLibrary > dxcLibrary ; 817SLANG_RETURN_ON_FAIL ( 818m_createInstance (CLSID_DxcLibrary ,__uuidof (dxcLibrary ), (LPVOID * )dxcLibrary .writeRef ())); 819 820// Create blob from the input data 821ComPtr < IDxcBlobEncoding > dxcSourceBlob ; 822SLANG_RETURN_ON_FAIL (dxcLibrary -> CreateBlobWithEncodingFromPinned ( 823 (LPBYTE )dxilBlob -> getBufferPointer (), 824 (UINT32 )dxilBlob -> getBufferSize (), 8250 , 826dxcSourceBlob .writeRef ())); 827 828ComPtr < IDxcBlobEncoding > dxcResultBlob ; 829SLANG_RETURN_ON_FAIL (dxcCompiler -> Disassemble (dxcSourceBlob ,dxcResultBlob .writeRef ())); 830 831auto artifact = ArtifactUtil ::createArtifact (to ); 832 833// Is compatible with ISlangBlob 834ISlangBlob * disassemblyBlob = (ISlangBlob * )dxcResultBlob .get (); 835artifact -> addRepresentationUnknown (disassemblyBlob ); 836 837* outArtifact = artifact .detach (); 838return SLANG_OK ; 839} 840 841SlangResult DXCDownstreamCompiler ::getVersionString (slang::IBlob ** outVersionString ) 842{ 843StringBuilder versionString ; 844// Append the version 845m_desc .version .append (versionString ); 846 847if (m_commitHash .getLength ()) 848 { 849versionString <<"#" <<m_commitHash ; 850 } 851else 852 { 853// If we don't have the commitHash, we use the library timestamp, to uniquely identify. 854versionString <<" " 855 <<SharedLibraryUtils ::getSharedLibraryTimestamp ( 856reinterpret_cast < void *> (m_createInstance )); 857 } 858 859* outVersionString = StringBlob ::moveCreate (versionString ).detach (); 860return SLANG_OK ; 861} 862 863/* static */ SlangResult DXCDownstreamCompilerUtil ::locateCompilers ( 864const String & path , 865ISlangSharedLibraryLoader * loader , 866DownstreamCompilerSet * set ) 867{ 868ComPtr < ISlangSharedLibrary > library ; 869 870const char * dependentNames []= {"dxil" ,nullptr }; 871SLANG_RETURN_ON_FAIL (DownstreamCompilerUtil ::loadSharedLibrary ( 872path , 873loader , 874dependentNames , 875"dxcompiler" , 876library )); 877 878SLANG_ASSERT (library ); 879if (!library ) 880 { 881return SLANG_FAIL ; 882 } 883 884auto compiler = new DXCDownstreamCompiler ; 885ComPtr < IDownstreamCompiler > compilerIntf (compiler ); 886SLANG_RETURN_ON_FAIL (compiler -> init (library )); 887 888set -> addCompiler (compilerIntf ); 889return SLANG_OK ; 890} 891 892#else // SLANG_ENABLE_DXIL_SUPPORT 893 894/* static */ SlangResult DXCDownstreamCompilerUtil ::locateCompilers ( 895const String & path , 896ISlangSharedLibraryLoader * loader , 897DownstreamCompilerSet * set ) 898{ 899SLANG_UNUSED (path ); 900SLANG_UNUSED (loader ); 901SLANG_UNUSED (set ); 902return SLANG_E_NOT_AVAILABLE ; 903} 904 905#endif // SLANG_ENABLE_DXIL_SUPPORT 906 907}// namespace Slang