yum-mirror/slang
Making it easier to work with shaders
git clone https://git.yummers.dev/yum-mirror/slang
d50c3f34a
master
1#ifndef SLANG_DOWNSTREAM_COMPILER_H 2#define SLANG_DOWNSTREAM_COMPILER_H 3 4#include "../core/slang-common.h" 5#include "../core/slang-io.h" 6#include "../core/slang-platform.h" 7#include "../core/slang-process-util.h" 8#include "../core/slang-semantic-version.h" 9#include "../core/slang-string.h" 10#include "slang-artifact-associated.h" 11#include "slang-artifact.h" 12#include "slang-com-ptr.h" 13 14#include <type_traits> 15 16namespace Slang 17{ 18 19struct SourceManager ; 20 21// Compiler description 22struct DownstreamCompilerDesc 23{ 24typedef DownstreamCompilerDesc ThisType ; 25 26HashCode getHashCode ()const {return combineHash (HashCode (type ),version .getHashCode ()); } 27bool operator == (const ThisType & rhs )const 28 { 29return type == rhs .type && version == rhs .version ; 30 } 31bool operator != (const ThisType & rhs )const {return !(* this == rhs ); } 32 33/// Get the version as a value 34Int getVersionValue ()const {return version .m_major * 100 + version .m_minor ; } 35 36/// true if has a version set 37bool hasVersion ()const {return version .isSet (); } 38 39/// Ctor 40explicit DownstreamCompilerDesc ( 41SlangPassThrough inType = SLANG_PASS_THROUGH_NONE , 42Int inMajorVersion = 0 , 43Int inMinorVersion = 0 ) 44 :type (inType ),version (int (inMajorVersion ),int (inMinorVersion )) 45 { 46 } 47explicit DownstreamCompilerDesc (SlangPassThrough inType ,const SemanticVersion & inVersion ) 48 :type (inType ),version (inVersion ) 49 { 50 } 51 52SlangPassThrough type ;///< The type of the compiler 53SemanticVersion version ;///< The version of the compiler 54}; 55 56/* Placed at the start of structs that are versioned. 57The id uniquely identifies a compatible set of versions. 58The size indicates the struct size. It should be considered as a kind of version number. 59The larger the number for the target the newer the *compatible* version (assuming the identifiers 60match). 61 62Note that size versioning *only* works, if adding a field *doesn't* use any existing unused "pad" 63bytes. This implies that any new members *must* take into account padding/alignment. Any additions 64that have alignment *less* than the alignment of struct may need padding. 65*/ 66struct VersionedStruct 67{ 68typedef VersionedStruct ThisType ; 69VersionedStruct (uint32_t inIdentifier ,size_t inSize ) 70 :identifier (inIdentifier ),size (uint32_t (inSize )) 71 { 72 } 73 74/// True if the versions are identical 75bool operator == (const ThisType & rhs )const 76 { 77return identifier == rhs .identifier && size == rhs .size ; 78 } 79bool operator != (const ThisType & rhs )const {return !(* this == rhs ); } 80 81VersionedStruct (const ThisType & rhs )= default; 82ThisType & operator = ( const ThisType & rhs) = default; 83 84uint32_t identifier; 85uint32_t size; 86}; 87 88template < typename T > 89T getCompatibleVersion( const T * inT) 90{ 91const VersionedStruct * in = & inT -> version ; 92 93// It must be at the start of the struct 94SLANG_ASSERT (( void * )in == ( void * )inT); 95 96// Note that the struct is passed in by pointer rather than reference, because 97// we must ensure that it is not sliced. 98 99// Must match 100SLANG_ASSERT ( T ::kVersionIdentifier == in -> identifier ); 101 102// If the same size we can just use what we have 103if (in -> size == sizeof ( T )) 104{ 105return * inT; 106} 107 108// Initialize a new T to copy into 109T t; 110 111// Keep a copy of the version as will be overwritten 112const auto currentVersion = t. version ; 113 114// If the size is smaller we just copy the bytes that we have. 115// NOTE! This only works if care is taken with padding/end bytes of previous versions 116// see above on VersionedStruct 117if (in -> size < sizeof ( T )) 118{ 119// Copy up the size that's stored 120:: memcpy ( & t, in, in -> size ); 121} 122else 123{ 124t = * inT; 125} 126 127t. version = currentVersion; 128return t; 129} 130 131template < typename T > 132bool isVersionCompatible( const VersionedStruct & ver) 133{ 134return ver. identifier == T ::kVersionIdentifier; 135} 136 137template < typename T > 138bool isVersionCompatible( const T & in) 139{ 140return isVersionCompatible < T > (in. version ); 141} 142 143/* Downstream compile options 144 145NOTE! This type is trafficed across shared library boundaries and *versioned*. 146In particular 147 148* The struct can only contain types that can be trivially memcpyd (checked by static_assert); 149* New fields can only be added to the end of the struct 150* New fields must take into account alignment/padding such that they do not share bytes in previous 151version sizes 152*/ 153struct DownstreamCompileOptions 154{ 155typedef DownstreamCompileOptions ThisType; 156 157// A unique identifer for this particular struct kind. If the struct become incompatible 158// a new id should be used to identify a specific style. If the change is only to add members 159// to the end, this should be handled via the version size at use sites. 160static const uint32_t kVersionIdentifier = 0x34296897 ; 161 162typedef uint32_t Flags; 163struct Flag 164{ 165enum Enum : Flags 166{ 167EnableExceptionHandling = 1680x01 , ///< Enables exception handling support (say as optionally supported by C++) 169Verbose = 0x02 , ///< Give more verbose diagnostics 170EnableSecurityChecks = 0x04 , ///< Enable runtime security checks (such as for buffer 171///< overruns) - enabling typically decreases performance 172EnableFloat16 = 0x08 , ///< If set compiles with support for float16/half 173}; 174}; 175 176enum class OptimizationLevel : uint8_t 177{ 178None, ///< Don't optimize at all. 179Default , ///< Default optimization level: balance code quality and compilation time. 180High , ///< Optimize aggressively. 181Maximal , ///< Include optimizations that may take a very long time, or may involve severe 182///< space-vs-speed tradeoffs 183}; 184 185enum class DebugInfoType : uint8_t 186{ 187None, ///< Don't emit debug information at all. 188Minimal , ///< Emit as little debug information as possible, while still supporting stack 189///< traces. 190Standard , ///< Emit whatever is the standard level of debug information for each target. 191Maximal , ///< Emit as much debug information as possible for each target. 192}; 193enum class FloatingPointMode : uint8_t 194{ 195Default, 196Fast , 197Precise , 198}; 199 200enum class FloatingPointDenormalMode : uint8_t 201{ 202Any, 203Preserve , 204FlushToZero , 205}; 206 207enum PipelineType : uint8_t 208{ 209Unknown, 210Compute, 211Rasterization, 212RayTracing, 213}; 214 215struct Define 216{ 217TerminatedCharSlice nameWithSig ; ///< If macro takes parameters include in brackets 218TerminatedCharSlice value ; 219}; 220 221struct CapabilityVersion 222{ 223enum class Kind : uint8_t 224{ 225CUDASM , ///< What the version is for 226SPIRV , 227}; 228Kind kind ; 229SemanticVersion version ; 230}; 231 232// These members must be the first members of the struct! 233VersionedStruct version = VersionedStruct ( kVersionIdentifier , sizeof ( ThisType )); 234 235OptimizationLevel optimizationLevel = OptimizationLevel::Default; 236DebugInfoType debugInfoType = DebugInfoType::Standard; 237SlangCompileTarget targetType = SLANG_HOST_EXECUTABLE ; 238SlangSourceLanguage sourceLanguage = SLANG_SOURCE_LANGUAGE_CPP ; 239FloatingPointMode floatingPointMode = FloatingPointMode::Default; 240PipelineType pipelineType = PipelineType::Unknown; 241SlangMatrixLayoutMode matrixLayout = SLANG_MATRIX_LAYOUT_MODE_UNKNOWN ; 242 243Flags flags = Flag::EnableExceptionHandling; 244 245PlatformKind platform = PlatformKind ::Unknown; 246 247/// The path/name of the output module. Should not have the extension, as that will be added for 248/// each of the target types. If not set a module path will be internally generated internally 249/// on a command line based compiler 250TerminatedCharSlice modulePath ; 251 252Slice < Define > defines ; 253 254/// The source artifacts 255Slice < IArtifact *> sourceArtifacts ; 256 257Slice < TerminatedCharSlice > includePaths ; 258Slice < TerminatedCharSlice > libraryPaths ; 259 260/// Libraries to link against. 261Slice < IArtifact *> libraries ; 262 263Slice < CapabilityVersion > requiredCapabilityVersions ; 264 265/// For compilers/compiles that require an entry point name, else can be empty 266TerminatedCharSlice entryPointName ; 267/// Profile name to use, only required for compiles that need to compile against a a specific 268/// profiles. Profile names are tied to compilers and targets. 269TerminatedCharSlice profileName ; 270// According to DirectX Raytracing Specification, PAQs are supported in Shader Model 6.7 and 271// above 272bool enablePAQ = false; 273 274/// The stage being compiled for 275SlangStage stage = SLANG_STAGE_NONE ; 276 277/// Arguments that are specific to a particular compiler implementation. 278Slice < TerminatedCharSlice > compilerSpecificArguments ; 279 280/// NOTE! Not all downstream compilers can use the fileSystemExt/sourceManager. This option will 281/// be ignored in those scenarios. 282ISlangFileSystemExt * fileSystemExt = nullptr; 283SourceManager * sourceManager = nullptr; 284 285// The debug info format to use. 286SlangDebugInfoFormat m_debugInfoFormat = SLANG_DEBUG_INFO_FORMAT_DEFAULT ; 287 288// The floating point denormal handling mode to use for each floating point precision 289FloatingPointDenormalMode denormalModeFp16 = FloatingPointDenormalMode ::Any; 290FloatingPointDenormalMode denormalModeFp32 = FloatingPointDenormalMode ::Any; 291FloatingPointDenormalMode denormalModeFp64 = FloatingPointDenormalMode ::Any; 292}; 293static_assert ( std ::is_trivially_copyable_v < DownstreamCompileOptions > ); 294 295#define SLANG_ALIAS_DEPRECATED_VERSION (name, id, firstField, lastField) \ 296struct name##_AliasDeprecated##id \ 297{ \ 298static const ptrdiff_t kStart = SLANG_OFFSET_OF(name, firstField); \ 299static const ptrdiff_t kEnd = SLANG_OFFSET_OF(name, lastField) + sizeof(name::lastField); \ 300}; 301 302/* Used to indicate what kind of products are expected to be produced for a compilation. */ 303typedef uint32_t DownstreamProductFlags ; 304struct DownstreamProductFlag 305{ 306enum Enum : DownstreamProductFlags 307{ 308Debug = 0x1 , ///< Used by debugger during execution 309Execution = 0x2 , ///< Required for execution 310Compile = 0x4 , ///< A product *required* for compilation 311Miscellaneous = 0x8 , ///< Anything else 312}; 313enum Mask : DownstreamProductFlags 314{ 315All = 0xf , ///< All the flags 316}; 317}; 318 319class IDownstreamCompiler : public ICastable 320{ 321public : 322SLANG_COM_INTERFACE ( 3230x167b8ba7 , 3240xbd41 , 3250x469a , 326{ 0x92 , 0x28 , 0xb8 , 0x53 , 0xc8 , 0xea , 0x56 , 0x6d }) 327 328typedef DownstreamCompilerDesc Desc ; 329typedef DownstreamCompileOptions CompileOptions ; 330 331typedef CompileOptions :: OptimizationLevel OptimizationLevel ; 332typedef CompileOptions :: DebugInfoType DebugInfoType ; 333typedef CompileOptions :: FloatingPointMode FloatingPointMode ; 334typedef CompileOptions :: PipelineType PipelineType ; 335typedef CompileOptions :: Define Define ; 336typedef CompileOptions :: CapabilityVersion CapabilityVersion ; 337 338/// Get the desc of this compiler 339virtual SLANG_NO_THROW const Desc & SLANG_MCALL getDesc () = 0 ; 340/// Compile using the specified options. The result is in resOut 341virtual SLANG_NO_THROW SlangResult SLANG_MCALL 342compile( const CompileOptions & options, IArtifact ** outArtifact) = 0 ; 343/// Returns true if compiler can do a transformation of `from` to `to` Artifact types 344virtual SLANG_NO_THROW bool SLANG_MCALL 345canConvert( const ArtifactDesc & from, const ArtifactDesc & to) = 0 ; 346/// Converts an artifact `from` to a desc of `to` and puts the result in outArtifact 347virtual SLANG_NO_THROW SlangResult SLANG_MCALL 348convert ( IArtifact * from, const ArtifactDesc & to, IArtifact ** outArtifact) = 0 ; 349/// Get the version of this compiler 350virtual SLANG_NO_THROW SlangResult SLANG_MCALL 351getVersionString ( slang :: IBlob ** outVersionString) = 0 ; 352/// Validate and return the result 353virtual SLANG_NO_THROW SlangResult SLANG_MCALL 354validate ( const uint32_t * contents, int contentsSize) = 0 ; 355/// Disassemble and print to stdout 356virtual SLANG_NO_THROW SlangResult SLANG_MCALL 357disassemble ( const uint32_t * contents, int contentsSize) = 0 ; 358/// Disassemble and return the result as a string 359virtual SLANG_NO_THROW SlangResult SLANG_MCALL 360disassembleWithResult ( const uint32_t * contents, int contentsSize, String & outString) = 0 ; 361 362/// True if underlying compiler uses file system to communicate source 363virtual SLANG_NO_THROW bool SLANG_MCALL isFileBased () = 0 ; 364 365virtual SLANG_NO_THROW int SLANG_MCALL link ( 366const uint32_t ** modules, 367const uint32_t * moduleSizes, 368const uint32_t moduleCount, 369IArtifact ** outArtifact) 370{ 371SLANG_UNREFERENCED_PARAMETER (modules); 372SLANG_UNREFERENCED_PARAMETER (moduleSizes); 373SLANG_UNREFERENCED_PARAMETER (moduleCount); 374SLANG_UNREFERENCED_PARAMETER (outArtifact); 375return 0 ; 376} 377}; 378 379class DownstreamCompilerBase : public ComBaseObject, public IDownstreamCompiler 380{ 381public : 382SLANG_COM_BASE_IUNKNOWN_ALL 383 384// ICastable 385virtual SLANG_NO_THROW void * SLANG_MCALL castAs( const Guid & guid) SLANG_OVERRIDE ; 386 387// IDownstreamCompiler 388virtual SLANG_NO_THROW const Desc & SLANG_MCALL getDesc () SLANG_OVERRIDE { return m_desc; } 389virtual SLANG_NO_THROW bool SLANG_MCALL 390canConvert( const ArtifactDesc & from, const ArtifactDesc & to) SLANG_OVERRIDE 391{ 392SLANG_UNUSED (from); 393SLANG_UNUSED (to); 394return false; 395} 396virtual SLANG_NO_THROW SlangResult SLANG_MCALL 397convert ( IArtifact * from, const ArtifactDesc & to, IArtifact ** outArtifact) SLANG_OVERRIDE ; 398virtual SLANG_NO_THROW SlangResult SLANG_MCALL getVersionString ( slang :: IBlob ** outVersionString) 399SLANG_OVERRIDE 400{ 401* outVersionString = nullptr ; 402return SLANG_FAIL ; 403} 404virtual SLANG_NO_THROW SlangResult SLANG_MCALL 405validate ( const uint32_t * contents, int contentsSize) SLANG_OVERRIDE 406{ 407SLANG_UNUSED (contents); 408SLANG_UNUSED (contentsSize); 409return SLANG_FAIL ; 410} 411virtual SLANG_NO_THROW SlangResult SLANG_MCALL 412disassemble ( const uint32_t * contents, int contentsSize) SLANG_OVERRIDE 413{ 414SLANG_UNUSED (contents); 415SLANG_UNUSED (contentsSize); 416return SLANG_FAIL ; 417} 418 419virtual SLANG_NO_THROW SlangResult SLANG_MCALL disassembleWithResult ( 420const uint32_t * contents, 421int contentsSize, 422String & outString) SLANG_OVERRIDE 423{ 424SLANG_UNUSED (contents); 425SLANG_UNUSED (contentsSize); 426SLANG_UNUSED (outString); 427return SLANG_FAIL ; 428} 429 430DownstreamCompilerBase( const Desc & desc) 431: m_desc ( desc ) 432{ 433} 434DownstreamCompilerBase () {} 435 436void * getInterface ( const Guid & guid); 437void * getObject ( const Guid & guid); 438 439Desc m_desc; 440}; 441 442class CommandLineDownstreamCompiler : public DownstreamCompilerBase 443{ 444public : 445typedef DownstreamCompilerBase Super; 446 447// IDownstreamCompiler 448virtual SLANG_NO_THROW SlangResult SLANG_MCALL 449compile( const CompileOptions & options, IArtifact ** outArtifact) SLANG_OVERRIDE ; 450virtual SLANG_NO_THROW bool SLANG_MCALL isFileBased () SLANG_OVERRIDE { return true; } 451 452// Functions to be implemented for a specific CommandLine 453 454/// Given options determines the paths to products produced (including the 'moduleFilePath'). 455/// Note that does *not* guarentee all products were or should be produced. Just aims to include 456/// all that could be produced, such that can be removed on completion. 457virtual SlangResult calcCompileProducts( 458const CompileOptions & options, 459DownstreamProductFlags flags, 460IOSFileArtifactRepresentation * lockFile, 461List < ComPtr < IArtifact>> & outArtifacts) = 0 ; 462 463virtual SlangResult calcArgs( const CompileOptions & options, CommandLine & cmdLine) = 0 ; 464virtual SlangResult parseOutput( 465const ExecuteResult & exeResult, 466IArtifactDiagnostics * diagnostics) = 0 ; 467 468CommandLineDownstreamCompiler( const Desc & desc, const ExecutableLocation & exe) 469: Super (desc) 470{ 471m_cmdLine. setExecutableLocation (exe); 472} 473 474CommandLineDownstreamCompiler( const Desc & desc, const CommandLine & cmdLine) 475: Super (desc), m_cmdLine (cmdLine) 476{ 477} 478 479CommandLineDownstreamCompiler( const Desc & desc) 480: Super ( desc ) 481{ 482} 483 484CommandLine m_cmdLine; 485}; 486 487/* Only purpose of having base-class here is to make all the DownstreamCompiler types available 488* directly in derived Utils */ 489struct DownstreamCompilerUtilBase 490{ 491typedef DownstreamCompileOptions CompileOptions ; 492 493typedef CompileOptions ::OptimizationLevel OptimizationLevel; 494typedef CompileOptions ::DebugInfoType DebugInfoType; 495 496typedef CompileOptions ::FloatingPointMode FloatingPointMode; 497typedef CompileOptions ::FloatingPointDenormalMode FloatingPointDenormalMode; 498 499typedef DownstreamProductFlag ProductFlag ; 500typedef DownstreamProductFlags ProductFlags ; 501}; 502 503} // namespace Slang 504 505#endif