yum-mirror/slang
Making it easier to work with shaders
git clone https://git.yummers.dev/yum-mirror/slang
0d16228ae
master
1// slang-artifact.h 2#ifndef SLANG_ARTIFACT_H 3#define SLANG_ARTIFACT_H 4 5#include "../core/slang-basic.h" 6#include "slang-com-helper.h" 7 8#include <type_traits> 9 10namespace Slang 11{ 12 13/* Simplest slice types. We can't use UnownedStringSlice etc, because they implement functionality 14in libraries, and we want to use these types in headers. If we wanted a C implementation it would be 15easy to use a macro to generate the functionality */ 16 17template < typename T > 18struct Slice 19{ 20const T * begin ()const {return data ; } 21const T * end ()const {return data + count ; } 22 23const T & operator [](Index index )const 24 { 25SLANG_ASSERT (index >=0 && index < count ); 26return data [index ]; 27 } 28 29Slice () 30 :count (0 ),data (nullptr ) 31 { 32 } 33Slice (const T * inData ,Count inCount ) 34 :data (inData ),count (inCount ) 35 { 36 } 37 38const T * data ; 39Count count ; 40}; 41 42template < typename T > 43SLANG_FORCE_INLINE Slice < T > makeSlice (const T * inData ,Count inCount ) 44{ 45return Slice < T > (inData ,inCount ); 46} 47 48struct CharSlice :public Slice < char > 49{ 50typedef CharSlice ThisType ; 51typedef Slice < char > Super ; 52 53bool operator == (const ThisType & rhs )const 54 { 55return count == rhs .count && (data == rhs .data || ::memcmp (data ,rhs .data ,count )== 0 ); 56 } 57bool operator != (const ThisType & rhs )const {return !(* this == rhs ); } 58 59explicit CharSlice (const char * in ) 60 :Super (in , ::strlen (in )) 61 { 62 } 63CharSlice (const char * in ,Count inCount ) 64 :Super (in ,inCount ) 65 { 66 } 67CharSlice () 68 :Super (nullptr ,0 ) 69 { 70 } 71explicit CharSlice (const String & s ) 72 :CharSlice (s .begin (),s .getLength ()){}; 73}; 74static_assert (std ::is_trivially_copyable_v < CharSlice > ); 75 76struct TerminatedCharSlice :public CharSlice 77{ 78typedef TerminatedCharSlice ThisType ; 79typedef CharSlice Super ; 80 81SLANG_FORCE_INLINE bool operator == (const ThisType & rhs )const {return Super ::operator == (rhs ); } 82SLANG_FORCE_INLINE bool operator != (const ThisType & rhs )const {return !(* this == rhs ); } 83 84/// Make convertable to char* 85SLANG_FORCE_INLINE operator const char * ()const { return data; } 86 87explicit TerminatedCharSlice ( const char * in) 88: Super (in) 89{ 90} 91TerminatedCharSlice( const char * in, Count inCount) 92: Super ( in , inCount ) 93{ 94SLANG_ASSERT ( in [inCount] == 0 ); 95} 96TerminatedCharSlice () 97: Super ( "" , 0 ) 98{ 99} 100}; 101static_assert ( std ::is_trivially_copyable_v < TerminatedCharSlice > ); 102 103/* As a rule of thumb, if we can define some aspect in a hierarchy then we should do so at the 104highest level. If some aspect can apply to multiple items identically we move that to a separate 105enum. 106 107NOTE! 108New Kinds must be added at the end. Values can be deprecated, or disabled 109but never removed, without breaking binary compatability. 110 111Any change requires a change to SLANG_ARTIFACT_KIND 112*/ 113enum class ArtifactKind : uint8_t 114{ 115Invalid, ///< Invalid 116Base, ///< Base kind of all valid kinds 117 118None, ///< Doesn't contain anything 119Unknown, ///< Unknown 120 121BinaryFormat, ///< A generic binary format. 122 123Container, ///< Container like types 124Zip, ///< Zip container 125RiffContainer, ///< Riff container 126RiffLz4Container, ///< Riff container using Lz4 compression 127RiffDeflateContainer, ///< Riff container using deflate compression 128 129Text, ///< Representation is text. Encoding is utf8, unless prefixed with 'encoding'. 130 131Source, ///< Source (Source type is in payload) 132Assembly, ///< Assembly (Type is in payload) 133HumanText, ///< Text for human consumption 134 135CompileBinary, ///< Kinds which are 'binary like' - can be executed, linked with and so forth. 136 137ObjectCode, ///< Object file 138Library, ///< Library (collection of object code) 139Executable, ///< Executable 140SharedLibrary, ///< Shared library - can be dynamically linked 141HostCallable, ///< Code can be executed directly on the host 142 143Instance, ///< Primary representation is an interface/class instance 144 145Json, ///< It's JSON 146 147CountOf, 148}; 149 150/* Payload. 151 152SlangIR and LLVMIR can be GPU or CPU orientated, so put in own category. 153 154NOTE! 155New Payloads must be added at the end. Values can be deprecated, or disabled 156but never removed, without breaking binary compatability. 157 158Any change requires a change to SLANG_ARTIFACT_PAYLOAD 159*/ 160enum class ArtifactPayload : uint8_t 161{ 162Invalid, ///< Is invalid - indicates some kind of problem 163Base, ///< The base of the hierarchy 164 165None, ///< Doesn't have a payload 166Unknown, ///< Unknown but probably valid 167 168Source, ///< Source code 169 170C , ///< C source 171Cpp, ///< C++ source 172HLSL , ///< HLSL source 173GLSL , ///< GLSL source 174CUDA , ///< CUDA source 175Metal, ///< Metal source 176Slang, ///< Slang source 177WGSL , ///< WGSL source 178 179KernelLike, ///< GPU Kernel like 180 181DXIL , ///< DXIL 182DXBC , ///< DXBC 183SPIRV , ///< SPIR-V 184PTX , ///< PTX. NOTE! PTX is a text format, but is handable to CUDA API. 185MetalAIR, ///< Metal AIR 186CuBin, ///< CUDA binary 187WGSL_SPIRV , ///< SPIR-V derived via WebGPU shading language 188 189CPULike, ///< CPU code 190 191UnknownCPU, ///< CPU code for unknown/undetermined type 192X86 , ///< X86 193X86_64 , ///< X86_64 194Aarch, ///< 32 bit arm 195Aarch64, ///< Aarch64 196HostCPU, ///< HostCPU 197UniversalCPU, ///< CPU code for multiple CPU types 198 199GeneralIR, ///< General purpose IR representation (IR) 200 201SlangIR, ///< Slang IR 202LLVMIR , ///< LLVM IR 203 204AST , ///< Abstract syntax tree (AST) 205 206SlangAST, ///< Slang AST 207 208CompileResults, ///< Payload is a collection of compilation results 209 210Metadata, ///< Metadata 211 212DebugInfo, ///< Debugging information 213Diagnostics, ///< Diagnostics information 214 215Miscellaneous, ///< Category for miscellaneous payloads (like Log/Lock) 216 217Log, ///< Log file 218Lock, ///< Typically some kind of 'lock' file. Contents is typically not important. 219 220PdbDebugInfo, ///< PDB debug info 221 222SourceMap, ///< A source map 223 224PostEmitMetadata, ///< Metadata from post emit (binding information) 225 226CountOf, 227}; 228 229/* Style. 230 231NOTE! 232New Styles must be added at the end. Values can be deprecated, or disabled 233but never removed, without breaking binary compatability. 234 235Any change requires a change to SLANG_ARTIFACT_STYLE 236*/ 237enum class ArtifactStyle : uint8_t 238{ 239Invalid, ///< Invalid style (indicating an error) 240Base, 241 242None, ///< A style is not applicable 243 244Unknown, ///< Unknown 245 246CodeLike, ///< For styles that are 'code like' such as 'kernel' or 'host'. 247 248Kernel, ///< Compiled as `GPU kernel` style. 249Host, ///< Compiled in `host` style 250Obfuscated, ///< Holds something specific to obfuscation, such as an obfuscated source map 251 252CountOf, 253}; 254 255typedef uint8_t ArtifactFlags ; 256struct ArtifactFlag 257{ 258enum Enum : ArtifactFlags 259{ 260// Don't currently have any flags 261}; 262}; 263 264/** 265A value type to describe aspects of the contents of an Artifact. 266**/ 267struct ArtifactDesc 268{ 269public : 270typedef ArtifactDesc ThisType; 271 272typedef ArtifactKind Kind ; 273typedef ArtifactPayload Payload ; 274typedef ArtifactStyle Style ; 275typedef ArtifactFlags Flags ; 276 277typedef uint32_t PackedBacking; 278enum class Packed : PackedBacking ; 279 280/// Get in packed format 281inline Packed getPacked() const ; 282 283bool operator == ( const ThisType & rhs) const 284{ 285return kind == rhs.kind && payload == rhs.payload && style == rhs.style && 286flags == rhs.flags; 287} 288bool operator != ( const ThisType & rhs ) const { return !( * this == rhs ); } 289 290/// Construct from the elements 291static ThisType make ( 292Kind inKind , 293Payload inPayload , 294Style inStyle = Style :: Unknown , 295Flags flags = 0 ) 296{ 297return ThisType { inKind , inPayload , inStyle , flags }; 298} 299static ThisType make ( Kind inKind , Payload inPayload , const ThisType & base ) 300{ 301return ThisType { inKind , inPayload , base .style, base .flags}; 302} 303 304/// Construct from the packed format 305inline static ThisType make ( Packed inPacked ); 306 307Kind kind ; 308Payload payload ; 309Style style ; 310Flags flags ; 311}; 312 313// -------------------------------------------------------------------------- 314inline ArtifactDesc :: Packed ArtifactDesc :: getPacked () const 315{ 316typedef PackedBacking IntType ; 317return Packed (( IntType ( kind ) << 24 ) | ( IntType ( payload ) << 16 ) | ( IntType ( style ) << 8 ) | flags ); 318} 319 320// -------------------------------------------------------------------------- 321inline /* static */ ArtifactDesc ArtifactDesc :: make ( Packed inPacked ) 322{ 323const PackedBacking packed = PackedBacking ( inPacked ); 324 325ThisType r ; 326r .kind = Kind ( packed >> 24 ); 327r .payload = Payload ( uint8_t ( packed >> 16 )); 328r .style = Style ( uint8_t ( packed >> 8 )); 329r .flags = uint8_t ( packed ); 330 331return r ; 332} 333 334// Forward declare 335class IOSFileArtifactRepresentation ; 336class IPathArtifactRepresentation ; 337 338class IArtifactRepresentation ; 339 340// Controls what items can be kept. 341enum class ArtifactKeep 342{ 343No , ///< Don't keep the item 344Yes , ///< Yes keep the final item 345All , ///< Keep the final item and any intermediataries 346}; 347 348/// True if can keep an intermediate item 349SLANG_INLINE bool canKeepIntermediate ( ArtifactKeep keep ) 350{ 351return keep == ArtifactKeep :: All ; 352} 353/// True if can keep 354SLANG_INLINE bool canKeep ( ArtifactKeep keep ) 355{ 356return Index ( keep ) >= Index ( ArtifactKeep :: Yes ); 357} 358/// Returns the keep type for an intermediate 359SLANG_INLINE ArtifactKeep getIntermediateKeep ( ArtifactKeep keep ) 360{ 361return ( keep == ArtifactKeep :: All ) ? ArtifactKeep :: All : ArtifactKeep :: No ; 362} 363 364/* Forward define */ 365class IArtifactHandler ; 366 367/* The IArtifact interface is designed to represent some Artifact of compilation. It could be input 368to or output from a compilation. 369 370An abstraction is desirable here, because depending on the compiler the artifact/s could be 371 372* A file on the file system 373* A blob 374* Multiple files 375* Some other (perhaps multiple) in memory representations 376* A name 377 378The artifact uses the Blob as the canonical in memory representation. 379 380Some downstream compilers require the artifact to be available as a file system file, or to produce 381artifacts that are files. The IArtifact type allows to abstract away this difference, including the 382ability to turn an in memory representation into a temporary file on the file system. 383 384The mechanism also allows for 'Containers' which allow for Artifacts to contain other Artifacts 385(amongst other things). Those artifacts may be other files. For example a downstream compilation 386that produces results as well as temporary files could be a Container containing artifacts for 387 388* Diagnostics 389* Temporary files (of known and unknown types) 390* Files that contain known types 391* Callable interface (an ISlangSharedLibrary) 392 393There are several types of ways to associate data with an artifact: 394 395* A representation 396* An associated artifact 397* A child artifact 398 399A `representation` has to wholly represent the artifact. That representation could be a blob, a file 400on the file system, an in memory representation. There are two classes of `Representation` - ones 401that can be turned into blobs (and therefore derive from IArtifactRepresentation) and ones that are 402in of themselves a representation (such as a blob or or ISlangSharedLibrary). 403 404`Associated artifacts` hold information that is associated with the artifact. It could be part 405of the representation, or useful for the implementation of a representation. Could also be 406considered as a kind of side channel to associate arbitrary data including temporary data with an 407artifact. 408 409A `child artifact` belongs to the artifact, within the hierarchy of artifacts. 410 411This also uses the ICompileResult interface to more easily allow the Slang API to retrieve 412multiple associated artifacts in cases where both base and debug spirv are needed. 413*/ 414class IArtifact : public slang :: ICompileResult 415{ 416public : 417SLANG_COM_INTERFACE ( 4180xf90acdb0 , 4190x9a4a , 4200x414e , 421{ 0x85 , 0x45 , 0x8b , 0x26 , 0xc9 , 0x2d , 0x94 , 0x42 }) 422 423enum class ContainedKind 424{ 425Representation , 426Associated , 427Children , 428}; 429 430typedef ArtifactDesc Desc ; 431 432typedef ArtifactKind Kind ; 433typedef ArtifactPayload Payload ; 434typedef ArtifactStyle Style ; 435typedef ArtifactFlags Flags ; 436 437typedef ArtifactKeep Keep ; 438 439/// Get the Desc defining the contents of the artifact 440virtual SLANG_NO_THROW Desc SLANG_MCALL getDesc () = 0 ; 441 442/// Returns true if the artifact in principal exists 443virtual SLANG_NO_THROW bool SLANG_MCALL exists () = 0 ; 444 445/// Load as a blob 446virtual SLANG_NO_THROW SlangResult SLANG_MCALL loadBlob ( Keep keep , ISlangBlob ** outBlob ) = 0 ; 447 448/// Require artifact is available as a file. 449/// NOTE! May need to serialize and write as a temporary file. 450virtual SLANG_NO_THROW SlangResult SLANG_MCALL 451requireFile ( Keep keep , IOSFileArtifactRepresentation ** outFileRep ) = 0 ; 452 453/// Load the artifact as a shared library 454virtual SLANG_NO_THROW SlangResult SLANG_MCALL 455loadSharedLibrary ( ArtifactKeep keep , ISlangSharedLibrary ** outSharedLibrary ) = 0 ; 456 457/// Get the name of the artifact. This can be empty. 458virtual SLANG_NO_THROW const char * SLANG_MCALL getName () = 0 ; 459/// Set the name associated with the artifact 460virtual SLANG_NO_THROW void SLANG_MCALL setName ( const char * name ) = 0 ; 461 462/// Add associated artifacts with this artifact 463virtual SLANG_NO_THROW void SLANG_MCALL addAssociated ( IArtifact * artifact ) = 0 ; 464/// Get the list of associated items 465virtual SLANG_NO_THROW Slice < IArtifact *> SLANG_MCALL getAssociated () = 0 ; 466 467/// Add a representation 468virtual SLANG_NO_THROW void SLANG_MCALL addRepresentation ( ICastable * castable ) = 0 ; 469/// Add a representation that doesn't derive from IArtifactRepresentation 470virtual SLANG_NO_THROW void SLANG_MCALL addRepresentationUnknown ( ISlangUnknown * rep ) = 0 ; 471/// Get all the representations 472virtual SLANG_NO_THROW Slice < ICastable *> SLANG_MCALL getRepresentations () = 0 ; 473 474/// Given a typeGuid representing the desired type get or create the representation. 475/// If found outCastable holds an entity that *must* be castable to typeGuid 476/// Use the keep parameter to determine if the representation should be cached on the artifact/s 477/// or not. 478virtual SLANG_NO_THROW SlangResult SLANG_MCALL 479getOrCreateRepresentation ( const Guid & typeGuid , ArtifactKeep keep , ICastable ** outCastable ) = 0 ; 480 481/// Get the handler used for this artifact. If nullptr means the default handler will be used. 482virtual SLANG_NO_THROW IArtifactHandler * SLANG_MCALL getHandler () = 0 ; 483/// Set the handler associated with this artifact. Setting nullptr will use the default handler. 484virtual SLANG_NO_THROW void SLANG_MCALL setHandler ( IArtifactHandler * handler ) = 0 ; 485 486/// Returns the result of expansion. Will return SLANG_E_UNINITIALIZED if expansion hasn't 487/// happened 488virtual SLANG_NO_THROW SlangResult SLANG_MCALL getExpandChildrenResult () = 0 ; 489/// Sets all of the children, will set the expansion state to SLANG_OK 490virtual SLANG_NO_THROW void SLANG_MCALL 491setChildren ( IArtifact * const * children , Count count ) = 0 ; 492/// Will be called implicitly on access to children 493virtual SLANG_NO_THROW SlangResult SLANG_MCALL expandChildren () = 0 ; 494 495/// Add the artifact to the list 496virtual SLANG_NO_THROW void SLANG_MCALL addChild ( IArtifact * artifact ) = 0 ; 497/// Get the children, will only remain valid if no mutation of children list 498virtual SLANG_NO_THROW Slice < IArtifact *> SLANG_MCALL getChildren () = 0 ; 499 500/// Find a represention from the specified list 501virtual SLANG_NO_THROW void * SLANG_MCALL 502findRepresentation ( ContainedKind kind , const Guid & guid ) = 0 ; 503/// Clear all of the contained kind 504virtual SLANG_NO_THROW void SLANG_MCALL clear ( ContainedKind kind ) = 0 ; 505/// Remove entry at index for the specified kind 506virtual SLANG_NO_THROW void SLANG_MCALL removeAt ( ContainedKind kind , Index i ) = 0 ; 507}; 508 509template < typename T > 510SLANG_FORCE_INLINE T * findRepresentation ( IArtifact * artifact ) 511{ 512return reinterpret_cast < T *> ( 513artifact -> findRepresentation ( IArtifact :: ContainedKind :: Representation , T :: getTypeGuid ())); 514} 515 516template < typename T > 517SLANG_FORCE_INLINE T * findAssociatedRepresentation ( IArtifact * artifact ) 518{ 519return reinterpret_cast < T *> ( 520artifact -> findRepresentation ( IArtifact :: ContainedKind :: Associated , T :: getTypeGuid ())); 521} 522 523template < typename T > 524SLANG_FORCE_INLINE T * findChildRepresentation ( IArtifact * artifact ) 525{ 526return reinterpret_cast < T *> ( 527artifact -> findRepresentation ( IArtifact :: ContainedKind :: Children , T :: getTypeGuid ())); 528} 529 530/* The IArtifactRepresentation interface represents a single representation that can be part of an 531artifact. It's special in so far as 532 533* IArtifactRepresentation can be queried for it's underlying object class 534* Can determine if the representation exists (for example if it's on the file system) 535* Can optionally serialize into a blob 536*/ 537class IArtifactRepresentation : public ICastable 538{ 539SLANG_COM_INTERFACE ( 0xa3790eb , 0x22b9 , 0x430e , { 0xbf , 0xc6 , 0x24 , 0x6c , 0x5b , 0x5c , 0xcd , 0x0 }) 540 541/// Create a representation of the specified typeGuid interface. 542/// Calling castAs on the castable will return the specific type 543/// Returns SLANG_E_NOT_IMPLEMENTED if an implementation doesn't implement 544virtual SLANG_NO_THROW SlangResult SLANG_MCALL 545createRepresentation ( const Guid & typeGuid , ICastable ** outCastable ) = 0 ; 546 547/// Returns true if this representation exists and is available for use. 548virtual SLANG_NO_THROW bool SLANG_MCALL exists () = 0 ; 549}; 550 551/* Handler provides functionality external to the artifact */ 552class IArtifactHandler : public ICastable 553{ 554SLANG_COM_INTERFACE ( 5550x6a646f57 , 5560xb3ac , 5570x4c6a , 558{ 0xb6 , 0xf1 , 0x33 , 0xb6 , 0xef , 0x60 , 0xa6 , 0xae }); 559 560/// Given an artifact expands children 561virtual SLANG_NO_THROW SlangResult SLANG_MCALL expandChildren ( IArtifact * container ) = 0 ; 562/// Given an artifact gets or creates a representation. 563virtual SLANG_NO_THROW SlangResult SLANG_MCALL getOrCreateRepresentation ( 564IArtifact * artifact , 565const Guid & guid , 566ArtifactKeep keep , 567ICastable ** outCastable ) = 0 ; 568}; 569 570} // namespace Slang 571 572#endif