yum-mirror/slang
Making it easier to work with shaders
git clone https://git.yummers.dev/yum-mirror/slang
591affaf7
master
1#pragma once 2 3#include "core/slang-basic.h" 4#include "core/slang-com-object.h" 5#include "core/slang-persistent-cache.h" 6#include "resource-desc-utils.h" 7#include "slang-context.h" 8#include "slang-gfx.h" 9 10namespace gfx 11{ 12 13struct GfxGUID 14{ 15static const Slang ::Guid IID_ISlangUnknown ; 16static const Slang ::Guid IID_IShaderProgram ; 17static const Slang ::Guid IID_ITransientResourceHeap ; 18static const Slang ::Guid IID_IPipelineState ; 19static const Slang ::Guid IID_IResourceView ; 20static const Slang ::Guid IID_IFramebuffer ; 21static const Slang ::Guid IID_IFramebufferLayout ; 22static const Slang ::Guid IID_ISwapchain ; 23static const Slang ::Guid IID_ISamplerState ; 24static const Slang ::Guid IID_IResource ; 25static const Slang ::Guid IID_IBufferResource ; 26static const Slang ::Guid IID_ITextureResource ; 27static const Slang ::Guid IID_IInputLayout ; 28static const Slang ::Guid IID_IDevice ; 29static const Slang ::Guid IID_IShaderCache ; 30static const Slang ::Guid IID_IShaderObjectLayout ; 31static const Slang ::Guid IID_IShaderObject ; 32static const Slang ::Guid IID_IRenderPassLayout ; 33static const Slang ::Guid IID_ICommandEncoder ; 34static const Slang ::Guid IID_IRenderCommandEncoder ; 35static const Slang ::Guid IID_IComputeCommandEncoder ; 36static const Slang ::Guid IID_IResourceCommandEncoder ; 37static const Slang ::Guid IID_IRayTracingCommandEncoder ; 38static const Slang ::Guid IID_ICommandBuffer ; 39static const Slang ::Guid IID_ICommandBufferD3D12 ; 40static const Slang ::Guid IID_ICommandQueue ; 41static const Slang ::Guid IID_IQueryPool ; 42static const Slang ::Guid IID_IAccelerationStructure ; 43static const Slang ::Guid IID_IFence ; 44static const Slang ::Guid IID_IShaderTable ; 45static const Slang ::Guid IID_IPipelineCreationAPIDispatcher ; 46static const Slang ::Guid IID_IVulkanPipelineCreationAPIDispatcher ; 47static const Slang ::Guid IID_ITransientResourceHeapD3D12 ; 48}; 49 50bool isGfxDebugLayerEnabled (); 51 52// We use a `BreakableReference` to avoid the cyclic reference situation in gfx implementation. 53// It is a common scenario where objects created from an `IDevice` implementation needs to hold 54// a strong reference to the device object that creates them. For example, a `Buffer` or a 55// `CommandQueue` needs to store a `m_device` member that points to the `IDevice`. At the same 56// time, the device implementation may also hold a reference to some of the objects it created 57// to represent the current device/binding state. Both parties would like to maintain a strong 58// reference to each other to achieve robustness against arbitrary ordering of destruction that 59// can be triggered by the user. However this creates cyclic reference situations that break 60// the `RefPtr` recyling mechanism. To solve this problem, we instead make each object reference 61// the device via a `BreakableReference<TDeviceImpl>` pointer. A breakable reference can be 62// turned into a weak reference via its `breakStrongReference()` call. 63// If we know there is a cyclic reference between an API object and the device/pool that creates it, 64// we can break the cycle when there is no longer any public references that come from `ComPtr`s to 65// the API object, by turning the reference to the device object from the API object to a weak 66// reference. 67// The following example illustrate how this mechanism works: 68// Suppose we have 69// ``` 70// class DeviceImpl : IDevice { RefPtr<ShaderObject> m_currentObject; }; 71// class ShaderObjectImpl : IShaderObject { BreakableReference<DeviceImpl> m_device; }; 72// ``` 73// And the user creates a device and a shader object, then somehow having the device reference 74// the shader object (this may not happen in actual implemetations, we just use it to illustrate 75// the situation): 76// ``` 77// ComPtr<IDevice> device = createDevice(); 78// ComPtr<ISomeResource> res = device->createResourceX(...); 79// device->m_currentResource = res; 80// ``` 81// This setup is robust to any destruction ordering. If user releases reference to `device` first, 82// then the device object will not be freed yet, since there is still a strong reference to the 83// device implementation via `res->m_device`. Next when the user releases reference to `res`, the 84// public reference count to `res` via `ComPtr`s will go to 0, therefore triggering the call to 85// `res->m_device.breakStrongReference()`, releasing the remaining reference to device. This will 86// cause `device` to start destruction, which will release its strong reference to `res` during 87// execution of its destructor. Finally, this will triger the actual destruction of `res`. On the 88// other hand, if the user releases reference to `res` first, then the strong reference to `device` 89// will be broken immediately, but the actual destruction of `res` will not start. Next when the 90// user releases `device`, there will no longer be any other references to `device`, so the 91// destruction of `device` will start, causing the release of the internal reference to `res`, 92// leading to its destruction. Note that the above logic only works if it is known that there is a 93// cyclic reference. If there are no such cyclic reference, then it will be incorrect to break the 94// strong reference to `IDevice` upon public reference counter dropping to 0. This is because the 95// actual destructor of `res` take place after breaking the cycle, but if the resource's strong 96// reference to the device is already the last reference, turning that reference to weak reference 97// will immediately trigger destruction of `device`, after which we can no longer destruct `res` if 98// the destructor needs `device`. Therefore we need to be careful when using `BreakableReference`, 99// and make sure we only call `breakStrongReference` only when it is known that there is a cyclic 100// reference. Luckily for all scenarios so far this is statically known. 101template < typename T > 102class BreakableReference 103{ 104private : 105Slang ::RefPtr < T > m_strongPtr ; 106T * m_weakPtr = nullptr ; 107 108public : 109BreakableReference ()= default ; 110 111BreakableReference (T * p ) {* this = p ; } 112 113BreakableReference (Slang ::RefPtr < T > const & p ) {* this = p ; } 114 115void setWeakReference (T * p ) 116 { 117m_weakPtr = p ; 118m_strongPtr = nullptr ; 119 } 120 121T & operator * ()const {return * get (); } 122 123T * operator -> () const { return get(); } 124 125T * get() const { return m_weakPtr ; } 126 127operator T * () const { return get(); } 128 129void operator = ( Slang :: RefPtr < T > const & p ) 130{ 131m_strongPtr = p ; 132m_weakPtr = p .Ptr(); 133} 134 135void operator = ( T * p ) 136{ 137m_strongPtr = p ; 138m_weakPtr = p ; 139} 140 141void breakStrongReference () { m_strongPtr = nullptr ; } 142 143void establishStrongReference () { m_strongPtr = m_weakPtr ; } 144}; 145 146// Helpers for returning an object implementation as COM pointer. 147template < typename TInterface , typename TImpl > 148void returnComPtr( TInterface ** outInterface , TImpl * rawPtr ) 149{ 150static_assert( 151! std :: is_base_of < Slang :: RefObject , TInterface > :: value , 152"TInterface must be an interface type." ); 153rawPtr -> addRef () ; 154* outInterface = rawPtr ; 155} 156 157template < typename TInterface , typename TImpl > 158void returnComPtr ( TInterface ** outInterface , const Slang :: RefPtr < TImpl >& refPtr ) 159{ 160static_assert ( 161! std :: is_base_of < Slang :: RefObject , TInterface >:: value , 162"TInterface must be an interface type." ); 163refPtr -> addRef (); 164* outInterface = refPtr . Ptr (); 165} 166 167template < typename TInterface , typename TImpl > 168void returnComPtr ( TInterface ** outInterface , Slang :: ComPtr < TImpl >& comPtr ) 169{ 170static_assert ( 171! std :: is_base_of < Slang :: RefObject , TInterface >:: value , 172"TInterface must be an interface type." ); 173* outInterface = comPtr . detach (); 174} 175 176// Helpers for returning an object implementation as RefPtr. 177template < typename TDest , typename TImpl > 178void returnRefPtr ( TDest ** outPtr , Slang :: RefPtr < TImpl >& refPtr ) 179{ 180static_assert ( 181std :: is_base_of < Slang :: RefObject , TDest >:: value , 182"TDest must be a non-interface type." ); 183static_assert ( 184std :: is_base_of < Slang :: RefObject , TImpl >:: value , 185"TImpl must be a non-interface type." ); 186* outPtr = refPtr . Ptr (); 187refPtr -> addReference (); 188} 189 190template < typename TDest , typename TImpl > 191void returnRefPtrMove ( TDest ** outPtr , Slang :: RefPtr < TImpl >& refPtr ) 192{ 193static_assert ( 194std :: is_base_of < Slang :: RefObject , TDest >:: value , 195"TDest must be a non-interface type." ); 196static_assert ( 197std :: is_base_of < Slang :: RefObject , TImpl >:: value , 198"TImpl must be a non-interface type." ); 199* outPtr = refPtr . detach (); 200} 201 202 203gfx :: StageType translateStage ( SlangStage slangStage ); 204 205class FenceBase : public IFence , public Slang :: ComObject 206{ 207public : 208SLANG_COM_OBJECT_IUNKNOWN_ALL 209IFence * getInterface ( const Slang :: Guid & guid ); 210 211protected : 212InteropHandle sharedHandle = {}; 213}; 214 215class Resource : public Slang :: ComObject 216{ 217public : 218/// Get the type 219SLANG_FORCE_INLINE IResource :: Type getType () const { return m_type ; } 220/// True if it's a texture derived type 221SLANG_FORCE_INLINE bool isTexture () const 222{ 223return int ( m_type ) >= int ( IResource :: Type :: Texture1D ); 224} 225/// True if it's a buffer derived type 226SLANG_FORCE_INLINE bool isBuffer () const { return m_type == IResource :: Type :: Buffer ; } 227 228protected : 229Resource ( IResource :: Type type ) 230: m_type ( type ) 231{ 232} 233 234IResource :: Type m_type ; 235InteropHandle sharedHandle = {}; 236Slang :: String m_debugName ; 237}; 238 239class BufferResource : public IBufferResource , public Resource 240{ 241public : 242SLANG_COM_OBJECT_IUNKNOWN_ALL 243IResource * getInterface ( const Slang :: Guid & guid ); 244 245public : 246typedef Resource Parent ; 247 248/// Ctor 249BufferResource ( const Desc & desc ) 250: Parent ( Type :: Buffer ), m_desc ( desc ) 251{ 252} 253 254virtual SLANG_NO_THROW IResource :: Type SLANG_MCALL getType () SLANG_OVERRIDE ; 255virtual SLANG_NO_THROW IBufferResource :: Desc * SLANG_MCALL getDesc () SLANG_OVERRIDE ; 256virtual SLANG_NO_THROW Result SLANG_MCALL getNativeResourceHandle ( InteropHandle * outHandle ) 257SLANG_OVERRIDE ; 258virtual SLANG_NO_THROW Result SLANG_MCALL getSharedHandle ( InteropHandle * outHandle ) 259SLANG_OVERRIDE ; 260 261virtual SLANG_NO_THROW Result SLANG_MCALL setDebugName ( const char * name ) override 262{ 263m_debugName = name ; 264return SLANG_OK ; 265} 266virtual SLANG_NO_THROW const char * SLANG_MCALL getDebugName () override 267{ 268return m_debugName . getBuffer (); 269} 270 271protected : 272Desc m_desc ; 273}; 274 275class TextureResource : public ITextureResource , public Resource 276{ 277public : 278SLANG_COM_OBJECT_IUNKNOWN_ALL 279IResource * getInterface ( const Slang :: Guid & guid ); 280 281public : 282typedef Resource Parent ; 283 284/// Ctor 285TextureResource ( const Desc & desc ) 286: Parent ( desc . type ), m_desc ( desc ) 287{ 288} 289 290virtual SLANG_NO_THROW IResource :: Type SLANG_MCALL getType () SLANG_OVERRIDE ; 291virtual SLANG_NO_THROW ITextureResource :: Desc * SLANG_MCALL getDesc () SLANG_OVERRIDE ; 292virtual SLANG_NO_THROW Result SLANG_MCALL getNativeResourceHandle ( InteropHandle * outHandle ) 293SLANG_OVERRIDE ; 294virtual SLANG_NO_THROW Result SLANG_MCALL getSharedHandle ( InteropHandle * outHandle ) 295SLANG_OVERRIDE ; 296 297virtual SLANG_NO_THROW Result SLANG_MCALL setDebugName ( const char * name ) override 298{ 299m_debugName = name ; 300return SLANG_OK ; 301} 302virtual SLANG_NO_THROW const char * SLANG_MCALL getDebugName () override 303{ 304return m_debugName . getBuffer (); 305} 306 307protected : 308Desc m_desc ; 309}; 310 311class ResourceViewInternalBase : public Slang :: ComObject 312{ 313}; 314 315class ResourceViewBase : public IResourceView , public ResourceViewInternalBase 316{ 317public : 318Desc m_desc = {}; 319SLANG_COM_OBJECT_IUNKNOWN_ALL 320IResourceView * getInterface ( const Slang :: Guid & guid ); 321virtual SLANG_NO_THROW Desc * SLANG_MCALL getViewDesc () override { return & m_desc ; } 322virtual SLANG_NO_THROW Result SLANG_MCALL getNativeHandle ( InteropHandle * outHandle ) override ; 323}; 324 325class SamplerStateBase : public ISamplerState , public Slang :: ComObject 326{ 327public : 328SLANG_COM_OBJECT_IUNKNOWN_ALL 329ISamplerState * getInterface ( const Slang :: Guid & guid ); 330virtual SLANG_NO_THROW Result SLANG_MCALL getNativeHandle ( InteropHandle * outHandle ) override ; 331}; 332 333class AccelerationStructureBase : public IAccelerationStructure , public ResourceViewInternalBase 334{ 335public : 336IResourceView :: Desc m_desc = {}; 337 338SLANG_COM_OBJECT_IUNKNOWN_ALL 339IAccelerationStructure * getInterface ( const Slang :: Guid & guid ); 340virtual SLANG_NO_THROW Desc * SLANG_MCALL getViewDesc () override { return & m_desc ; } 341}; 342 343class RendererBase ; 344 345typedef uint32_t ShaderComponentID ; 346const ShaderComponentID kInvalidComponentID = 0xFFFFFFFF ; 347 348struct ExtendedShaderObjectType 349{ 350slang :: TypeReflection * slangType ; 351ShaderComponentID componentID ; 352}; 353 354struct ExtendedShaderObjectTypeList 355{ 356Slang :: ShortList < ShaderComponentID , 16 > componentIDs ; 357Slang :: ShortList < slang :: SpecializationArg , 16 > components ; 358void add ( const ExtendedShaderObjectType & component ) 359{ 360componentIDs . add ( component . componentID ); 361components . add ( 362slang :: SpecializationArg { slang :: SpecializationArg :: Kind :: Type , { component . slangType }}); 363} 364void addRange ( const ExtendedShaderObjectTypeList & list ) 365{ 366for ( Slang :: Index i = 0 ; i < list . getCount (); i ++) 367{ 368add ( list [ i ]); 369} 370} 371ExtendedShaderObjectType operator []( Slang :: Index index ) const 372{ 373ExtendedShaderObjectType result ; 374result . componentID = componentIDs [ index ]; 375result . slangType = components [ index ]. type ; 376return result ; 377} 378void clear () 379{ 380componentIDs . clear (); 381components . clear (); 382} 383Slang :: Index getCount () const { return componentIDs . getCount (); } 384}; 385 386struct ExtendedShaderObjectTypeListObject : public ExtendedShaderObjectTypeList , 387public Slang :: RefObject 388{ 389}; 390 391class ShaderObjectLayoutBase : public Slang :: RefObject 392{ 393protected : 394// We always use a weak reference to the `IDevice` object here. 395// `ShaderObject` implementations will make sure to hold a strong reference to `IDevice` 396// while a `ShaderObjectLayout` may still be used. 397RendererBase * m_renderer ; 398slang :: TypeLayoutReflection * m_elementTypeLayout = nullptr ; 399ShaderComponentID m_componentID = 0 ; 400 401/// The container type of this shader object. When `m_containerType` is `StructuredBuffer` or 402/// `UnsizedArray`, this shader object represents a collection instead of a single object. 403ShaderObjectContainerType m_containerType = ShaderObjectContainerType :: None ; 404 405public : 406ComPtr < slang :: ISession > m_slangSession ; 407 408ShaderObjectContainerType getContainerType () { return m_containerType ; } 409 410static slang :: TypeLayoutReflection * _unwrapParameterGroups ( 411slang :: TypeLayoutReflection * typeLayout , 412ShaderObjectContainerType & outContainerType ) 413{ 414outContainerType = ShaderObjectContainerType :: None ; 415for (;;) 416{ 417if (! typeLayout -> getType ()) 418{ 419if ( auto elementTypeLayout = typeLayout -> getElementTypeLayout ()) 420typeLayout = elementTypeLayout ; 421} 422switch ( typeLayout -> getKind ()) 423{ 424case slang :: TypeReflection :: Kind :: Array : 425SLANG_ASSERT ( outContainerType == ShaderObjectContainerType :: None ); 426outContainerType = ShaderObjectContainerType :: Array ; 427typeLayout = typeLayout -> getElementTypeLayout (); 428return typeLayout ; 429case slang :: TypeReflection :: Kind :: Resource : 430{ 431if ( typeLayout -> getResourceShape () != SLANG_STRUCTURED_BUFFER ) 432break ; 433SLANG_ASSERT ( outContainerType == ShaderObjectContainerType :: None ); 434outContainerType = ShaderObjectContainerType :: StructuredBuffer ; 435typeLayout = typeLayout -> getElementTypeLayout (); 436} 437return typeLayout ; 438case slang :: TypeReflection :: Kind :: ConstantBuffer : 439case slang :: TypeReflection :: Kind :: ParameterBlock : 440typeLayout = typeLayout -> getElementTypeLayout (); 441continue ; 442default : 443return typeLayout ; 444} 445} 446} 447 448 449public : 450RendererBase * getDevice () { return m_renderer ; } 451 452slang :: TypeLayoutReflection * getElementTypeLayout () { return m_elementTypeLayout ; } 453 454ShaderComponentID getComponentID () { return m_componentID ; } 455 456void initBase ( 457RendererBase * renderer , 458slang :: ISession * session , 459slang :: TypeLayoutReflection * elementTypeLayout ); 460}; 461 462class SimpleShaderObjectData 463{ 464public : 465// Any "ordinary" / uniform data for this object 466Slang :: List < char > m_ordinaryData ; 467// The structured buffer resource used when the object represents a structured buffer. 468Slang :: RefPtr < BufferResource > m_structuredBuffer ; 469// The structured buffer resource view used when the object represents a structured buffer. 470Slang :: RefPtr < ResourceViewBase > m_structuredBufferView ; 471Slang :: RefPtr < ResourceViewBase > m_rwStructuredBufferView ; 472 473Slang :: Index getCount () { return m_ordinaryData . getCount (); } 474void setCount ( Slang :: Index count ) { m_ordinaryData . setCount ( count ); } 475char * getBuffer () { return m_ordinaryData . getBuffer (); } 476 477/// Returns a StructuredBuffer resource view for GPU access into the buffer content. 478/// Creates a StructuredBuffer resource if it has not been created. 479ResourceViewBase * getResourceView ( 480RendererBase * device , 481slang :: TypeLayoutReflection * elementLayout , 482slang :: BindingType bindingType ); 483}; 484 485bool _doesValueFitInExistentialPayload ( 486slang :: TypeLayoutReflection * concreteTypeLayout , 487slang :: TypeLayoutReflection * existentialFieldLayout ); 488 489class ShaderObjectBase : public IShaderObject , public Slang :: ComObject 490{ 491public : 492SLANG_COM_OBJECT_IUNKNOWN_ALL 493IShaderObject * getInterface ( const Slang :: Guid & guid ) 494{ 495if ( guid == GfxGUID :: IID_ISlangUnknown || guid == GfxGUID :: IID_IShaderObject ) 496return static_cast < IShaderObject *>( this ); 497return nullptr ; 498} 499 500protected : 501// A strong reference to `IDevice` to make sure the weak device reference in 502// `ShaderObjectLayout`s are valid whenever they might be used. 503BreakableReference < RendererBase > m_device ; 504 505// The shader object layout used to create this shader object. 506Slang :: RefPtr < ShaderObjectLayoutBase > m_layout = nullptr ; 507 508// The specialized shader object type. 509ExtendedShaderObjectType shaderObjectType = { nullptr , kInvalidComponentID }; 510 511Result _getSpecializedShaderObjectType ( ExtendedShaderObjectType * outType ); 512slang :: TypeLayoutReflection * _getElementTypeLayout () 513{ 514return m_layout -> getElementTypeLayout (); 515} 516 517public : 518void breakStrongReferenceToDevice () { m_device . breakStrongReference (); } 519 520public : 521ShaderComponentID getComponentID () { return shaderObjectType . componentID ; } 522 523// Get the final type this shader object represents. If the shader object's type has existential 524// fields, this function will return a specialized type using the bound sub-objects' type as 525// specialization argument. 526virtual Result getSpecializedShaderObjectType ( ExtendedShaderObjectType * outType ); 527 528virtual Result collectSpecializationArgs ( ExtendedShaderObjectTypeList & args ) = 0 ; 529 530RendererBase * getRenderer () { return m_layout -> getDevice (); } 531 532ShaderObjectLayoutBase * getLayoutBase () { return m_layout ; } 533 534/// Sets the RTTI ID and RTTI witness table fields of an existential value. 535Result setExistentialHeader ( 536slang :: TypeReflection * existentialType , 537slang :: TypeReflection * concreteType , 538ShaderOffset offset ); 539 540public : 541SLANG_NO_THROW GfxCount SLANG_MCALL getEntryPointCount () SLANG_OVERRIDE { return 0 ; } 542 543SLANG_NO_THROW Result SLANG_MCALL getEntryPoint ( GfxIndex index , IShaderObject ** outEntryPoint ) 544SLANG_OVERRIDE 545{ 546* outEntryPoint = nullptr ; 547return SLANG_OK ; 548} 549 550SLANG_NO_THROW slang :: TypeLayoutReflection * SLANG_MCALL getElementTypeLayout () SLANG_OVERRIDE 551{ 552return m_layout -> getElementTypeLayout (); 553} 554 555virtual SLANG_NO_THROW ShaderObjectContainerType SLANG_MCALL getContainerType () SLANG_OVERRIDE 556{ 557return m_layout -> getContainerType (); 558} 559 560virtual SLANG_NO_THROW Result SLANG_MCALL 561getCurrentVersion ( ITransientResourceHeap * transientHeap , IShaderObject ** outObject ) override 562{ 563returnComPtr ( outObject , this ); 564return SLANG_OK ; 565} 566 567virtual SLANG_NO_THROW Result SLANG_MCALL 568copyFrom ( IShaderObject * object , ITransientResourceHeap * transientHeap ); 569 570virtual SLANG_NO_THROW const void * SLANG_MCALL getRawData () override { return nullptr ; } 571 572virtual SLANG_NO_THROW Result SLANG_MCALL 573setConstantBufferOverride ( IBufferResource * outBuffer ) override 574{ 575return SLANG_E_NOT_AVAILABLE ; 576} 577}; 578 579template < typename TShaderObjectImpl , typename TShaderObjectLayoutImpl , typename TShaderObjectData > 580class ShaderObjectBaseImpl : public ShaderObjectBase 581{ 582protected : 583TShaderObjectData m_data ; 584Slang :: List < Slang :: RefPtr < TShaderObjectImpl >> m_objects ; 585Slang :: List < Slang :: RefPtr < ExtendedShaderObjectTypeListObject >> m_userProvidedSpecializationArgs ; 586 587// Specialization args for a StructuredBuffer object. 588ExtendedShaderObjectTypeList m_structuredBufferSpecializationArgs ; 589 590public : 591TShaderObjectLayoutImpl * getLayout () 592{ 593return static_cast < TShaderObjectLayoutImpl *>( m_layout . Ptr ()); 594} 595 596void * getBuffer () { return m_data . getBuffer (); } 597size_t getBufferSize () { return ( size_t ) m_data . getCount (); } // TODO: Change size_t to Count? 598 599virtual SLANG_NO_THROW Result SLANG_MCALL 600getObject ( ShaderOffset const & offset , IShaderObject ** outObject ) SLANG_OVERRIDE 601{ 602SLANG_ASSERT ( outObject ); 603if ( offset . bindingRangeIndex < 0 ) 604return SLANG_E_INVALID_ARG ; 605auto layout = getLayout (); 606if ( offset . bindingRangeIndex >= layout -> getBindingRangeCount ()) 607return SLANG_E_INVALID_ARG ; 608auto bindingRange = layout -> getBindingRange (offset. bindingRangeIndex ); 609 610returnComPtr (outObject, m_objects[bindingRange. subObjectIndex + offset. bindingArrayIndex ]); 611return SLANG_OK ; 612} 613 614void setSpecializationArgsForContainerElement ( ExtendedShaderObjectTypeList & specializationArgs); 615 616Slang :: Index getSubObjectIndex ( ShaderOffset offset) 617{ 618auto layout = getLayout (); 619auto bindingRange = layout -> getBindingRange (offset. bindingRangeIndex ); 620return bindingRange. subObjectIndex + offset. bindingArrayIndex ; 621} 622 623virtual SLANG_NO_THROW Result SLANG_MCALL 624setObject( ShaderOffset const & offset, IShaderObject * object) SLANG_OVERRIDE 625{ 626auto layout = getLayout (); 627auto subObject = static_cast < TShaderObjectImpl *> (object); 628// There are three different cases in `setObject`. 629// 1. `this` object represents a StructuredBuffer, and `object` is an 630// element to be written into the StructuredBuffer. 631// 2. `object` represents a StructuredBuffer and we are setting it into 632// a StructuredBuffer typed field in `this` object. 633// 3. We are setting `object` as an ordinary sub-object, e.g. an existential 634// field, a constant buffer or a parameter block. 635// We handle each case separately below. 636 637if (layout -> getContainerType () != ShaderObjectContainerType::None) 638{ 639// Case 1: 640// We are setting an element into a `StructuredBuffer` object. 641// We need to hold a reference to the element object, as well as 642// writing uniform data to the plain buffer. 643if (offset. bindingArrayIndex >= m_objects. getCount ()) 644{ 645m_objects. setCount (offset. bindingArrayIndex + 1 ); 646auto stride = layout -> getElementTypeLayout () -> getStride (); 647m_data. setCount (m_objects. getCount () * stride); 648} 649m_objects[offset. bindingArrayIndex ] = subObject; 650 651ExtendedShaderObjectTypeList specializationArgs; 652 653auto payloadOffset = offset; 654 655// If the element type of the StructuredBuffer field is an existential type, 656// we need to make sure to fill in the existential value header (RTTI ID and 657// witness table IDs). 658if (layout -> getElementTypeLayout () -> getKind () == slang::TypeReflection::Kind::Interface) 659{ 660auto existentialType = layout -> getElementTypeLayout () -> getType (); 661ExtendedShaderObjectType concreteType; 662SLANG_RETURN_ON_FAIL (subObject -> getSpecializedShaderObjectType ( & concreteType)); 663SLANG_RETURN_ON_FAIL ( 664setExistentialHeader (existentialType, concreteType. slangType , offset)); 665payloadOffset. uniformOffset += 16 ; 666 667// If this object is a `StructuredBuffer<ISomeInterface>`, then the 668// specialization argument should be the specialized type of the sub object 669// itself. 670specializationArgs. add (concreteType); 671} 672else 673{ 674// If this object is a `StructuredBuffer<SomeConcreteType>`, then the 675// specialization 676// argument should come recursively from the sub object. 677subObject -> collectSpecializationArgs (specializationArgs); 678} 679SLANG_RETURN_ON_FAIL ( setData ( 680payloadOffset, 681subObject -> m_data . getBuffer (), 682( size_t )subObject -> m_data . getCount ())); // TODO: Change size_t to Count? 683 684setSpecializationArgsForContainerElement (specializationArgs); 685return SLANG_OK ; 686} 687 688// Case 2 & 3, setting object as an StructuredBuffer, ConstantBuffer, ParameterBlock or 689// existential value. 690 691if (offset. bindingRangeIndex < 0 ) 692return SLANG_E_INVALID_ARG ; 693if (offset. bindingRangeIndex >= layout -> getBindingRangeCount ()) 694return SLANG_E_INVALID_ARG ; 695 696auto bindingRangeIndex = offset. bindingRangeIndex ; 697auto bindingRange = layout -> getBindingRange (bindingRangeIndex); 698 699m_objects[bindingRange. subObjectIndex + offset. bindingArrayIndex ] = subObject; 700 701switch (bindingRange. bindingType ) 702{ 703case slang:: BindingType :: ExistentialValue : 704{ 705// If the range being assigned into represents an interface/existential-type 706// leaf field, then we need to consider how the `object` being assigned here 707// affects specialization. We may also need to assign some data from the 708// sub-object into the ordinary data buffer for the parent object. 709// 710// A leaf field of interface type is laid out inside of the parent object 711// as a tuple of `(RTTI, WitnessTable, Payload)`. The layout of these fields 712// is a contract between the compiler and any runtime system, so we will 713// need to rely on details of the binary layout. 714 715// We start by querying the layout/type of the concrete value that the 716// application is trying to store into the field, and also the layout/type of 717// the leaf existential-type field itself. 718// 719auto concreteTypeLayout = subObject -> getElementTypeLayout (); 720auto concreteType = concreteTypeLayout -> getType (); 721// 722auto existentialTypeLayout = 723layout -> getElementTypeLayout () -> getBindingRangeLeafTypeLayout ( 724bindingRangeIndex); 725auto existentialType = existentialTypeLayout -> getType (); 726 727// Fills in the first and second field of the tuple that specify RTTI type ID 728// and witness table ID. 729SLANG_RETURN_ON_FAIL ( setExistentialHeader (existentialType, concreteType, offset)); 730 731// The third field of the tuple (offset 16) is the "payload" that is supposed to 732// hold the data for a value of the given concrete type. 733// 734auto payloadOffset = offset; 735payloadOffset. uniformOffset += 16 ; 736 737// There are two cases we need to consider here for how the payload might be 738// used: 739// 740// * If the concrete type of the value being bound is one that can "fit" into 741// the 742// available payload space, then it should be stored in the payload. 743// 744// * If the concrete type of the value cannot fit in the payload space, then it 745// will need to be stored somewhere else. 746// 747if ( _doesValueFitInExistentialPayload (concreteTypeLayout, existentialTypeLayout)) 748{ 749// If the value can fit in the payload area, then we will go ahead and copy 750// its bytes into that area. 751// 752setData ( 753payloadOffset, 754subObject -> m_data . getBuffer (), 755subObject -> m_data . getCount ()); 756} 757else 758{ 759// If the value does *not *fit in the payload area, then there is nothing 760// we can do at this point (beyond saving a reference to the sub-object, 761// which was handled above). 762// 763// Once all the sub-objects have been set into the parent object, we can 764// compute a specialized layout for it, and that specialized layout can tell 765// us where the data for these sub-objects has been laid out. 766return SLANG_E_NOT_IMPLEMENTED ; 767} 768} 769break ; 770case slang:: BindingType :: MutableRawBuffer : 771case slang:: BindingType :: RawBuffer : 772{ 773// If we are setting into a `StructuredBuffer` field, make sure we create and set 774// the StructuredBuffer resource as well. 775auto resourceView = subObject -> m_data . getResourceView ( 776getRenderer (), 777subObject -> getElementTypeLayout (), 778bindingRange. bindingType ); 779if (resourceView) 780setResource (offset, resourceView); 781} 782break ; 783} 784return SLANG_OK ; 785} 786 787Result getExtendedShaderTypeListFromSpecializationArgs ( 788ExtendedShaderObjectTypeList & list, 789const slang ::SpecializationArg * args, 790uint32_t count); 791 792virtual SLANG_NO_THROW Result SLANG_MCALL setSpecializationArgs( 793ShaderOffset const & offset, 794const slang :: SpecializationArg * args, 795GfxCount count) override 796{ 797auto layout = getLayout (); 798 799// If the shader object is a container, delegate the processing to 800// `setSpecializationArgsForContainerElements`. 801if (layout -> getContainerType () != ShaderObjectContainerType::None) 802{ 803ExtendedShaderObjectTypeList argList; 804SLANG_RETURN_ON_FAIL ( 805getExtendedShaderTypeListFromSpecializationArgs (argList, args, count)); 806setSpecializationArgsForContainerElement (argList); 807return SLANG_OK ; 808} 809 810if (offset. bindingRangeIndex < 0 ) 811return SLANG_E_INVALID_ARG ; 812if (offset. bindingRangeIndex >= layout -> getBindingRangeCount ()) 813return SLANG_E_INVALID_ARG ; 814 815auto bindingRangeIndex = offset. bindingRangeIndex ; 816auto bindingRange = layout -> getBindingRange (bindingRangeIndex); 817Slang :: Index objectIndex = bindingRange. subObjectIndex + offset. bindingArrayIndex ; 818if (objectIndex >= m_userProvidedSpecializationArgs. getCount ()) 819m_userProvidedSpecializationArgs. setCount (objectIndex + 1 ); 820if (!m_userProvidedSpecializationArgs[objectIndex]) 821{ 822m_userProvidedSpecializationArgs[objectIndex] = 823new ExtendedShaderObjectTypeListObject (); 824} 825else 826{ 827m_userProvidedSpecializationArgs[objectIndex] -> clear (); 828} 829SLANG_RETURN_ON_FAIL ( getExtendedShaderTypeListFromSpecializationArgs ( 830* m_userProvidedSpecializationArgs[objectIndex], 831args, 832count)); 833return SLANG_OK ; 834} 835 836// Appends all types that are used to specialize the element type of this shader object in 837// `args` list. 838virtual Result collectSpecializationArgs (ExtendedShaderObjectTypeList & args) override; 839}; 840 841class ShaderProgramBase : public IShaderProgram, public Slang::ComObject 842{ 843public: 844SLANG_COM_OBJECT_IUNKNOWN_ALL 845IShaderProgram * getInterface ( const Slang ::Guid & guid); 846 847Desc desc; 848 849Slang ::ComPtr < slang::IComponentType > slangGlobalScope; 850Slang ::List < ComPtr < slang::IComponentType>> slangEntryPoints; 851 852// Linked program when linkingStyle is GraphicsCompute, or the original global scope 853// when linking style is RayTracing. 854Slang ::ComPtr < slang::IComponentType > linkedProgram; 855 856// Linked program for each entry point when linkingStyle is RayTracing. 857Slang ::List < Slang::ComPtr < slang::IComponentType>> linkedEntryPoints; 858 859void init ( const IShaderProgram ::Desc & desc); 860 861bool isSpecializable () 862{ 863if (slangGlobalScope -> getSpecializationParamCount () != 0 ) 864{ 865return true; 866} 867for (auto & entryPoint : slangEntryPoints ) 868{ 869if ( entryPoint -> getSpecializationParamCount () != 0 ) 870{ 871return true; 872} 873} 874return false; 875} 876 877Slang :: Result compileShaders ( RendererBase * device); 878virtual Slang::Result createShaderModule ( 879slang ::EntryPointReflection * entryPointInfo, 880Slang ::List < Slang::ComPtr < ISlangBlob>> & kernelCodes); 881 882virtual SLANG_NO_THROW slang ::TypeReflection * SLANG_MCALL 883findTypeByName( const char * name) override 884{ 885return linkedProgram -> getLayout () -> findTypeByName (name); 886} 887 888bool isMeshShaderProgram () const ; 889}; 890 891class InputLayoutBase : public IInputLayout, public Slang::ComObject 892{ 893public: 894SLANG_COM_OBJECT_IUNKNOWN_ALL 895IInputLayout * getInterface ( const Slang ::Guid & guid); 896}; 897 898class FramebufferLayoutBase : public IFramebufferLayout, public Slang::ComObject 899{ 900public : 901SLANG_COM_OBJECT_IUNKNOWN_ALL 902IFramebufferLayout * getInterface ( const Slang ::Guid & guid); 903}; 904 905class FramebufferBase : public IFramebuffer, public Slang::ComObject 906{ 907public: 908SLANG_COM_OBJECT_IUNKNOWN_ALL 909IFramebuffer * getInterface ( const Slang ::Guid & guid); 910}; 911 912class QueryPoolBase : public IQueryPool, public Slang::ComObject 913{ 914public: 915SLANG_COM_OBJECT_IUNKNOWN_ALL 916IQueryPool * getInterface ( const Slang ::Guid & guid); 917virtual SLANG_NO_THROW Result SLANG_MCALL reset () override { return SLANG_OK ; } 918 919IQueryPool :: Desc m_desc; 920}; 921 922enum class PipelineType 923{ 924Unknown, 925Graphics, 926Compute, 927RayTracing, 928CountOf, 929}; 930 931struct OwnedHitGroupDesc 932{ 933Slang :: String hitGroupName ; 934Slang :: String closestHitEntryPoint ; 935Slang :: String anyHitEntryPoint ; 936Slang :: String intersectionEntryPoint ; 937 938void set ( const HitGroupDesc & desc) 939{ 940hitGroupName = desc.hitGroupName; 941closestHitEntryPoint = desc . closestHitEntryPoint ; 942anyHitEntryPoint = desc . anyHitEntryPoint ; 943intersectionEntryPoint = desc . intersectionEntryPoint ; 944} 945 946HitGroupDesc get () 947{ 948HitGroupDesc desc; 949desc. hitGroupName = hitGroupName. getBuffer (); 950desc. closestHitEntryPoint = closestHitEntryPoint. getBuffer (); 951desc. anyHitEntryPoint = anyHitEntryPoint. getBuffer (); 952desc. intersectionEntryPoint = intersectionEntryPoint. getBuffer (); 953return desc; 954} 955}; 956 957struct OwnedRayTracingPipelineStateDesc 958{ 959Slang :: RefPtr < ShaderProgramBase > program ; 960Slang :: List < OwnedHitGroupDesc > hitGroups ; 961Slang :: List < HitGroupDesc > hitGroupDescs ; 962int maxRecursion = 0 ; 963Size maxRayPayloadSize = 0 ; 964Size maxAttributeSizeInBytes = 8 ; 965RayTracingPipelineFlags :: Enum flags = RayTracingPipelineFlags ::None; 966 967RayTracingPipelineStateDesc get () 968{ 969RayTracingPipelineStateDesc desc ; 970desc . program = program . Ptr (); 971desc . hitGroupCount = ( int32_t )hitGroupDescs. getCount (); 972desc . hitGroups = hitGroupDescs . getBuffer (); 973desc . maxRecursion = maxRecursion ; 974desc . maxRayPayloadSize = maxRayPayloadSize ; 975desc . maxAttributeSizeInBytes = maxAttributeSizeInBytes ; 976desc . flags = flags ; 977return desc ; 978} 979 980void set ( const RayTracingPipelineStateDesc & inDesc) 981{ 982program = static_cast < ShaderProgramBase *> (inDesc. program ); 983for ( int32_t i = 0 ; i < inDesc. hitGroupCount ; i ++ ) 984{ 985OwnedHitGroupDesc ownedHitGroupDesc; 986ownedHitGroupDesc. set (inDesc. hitGroups [i]); 987hitGroups. add (ownedHitGroupDesc); 988hitGroupDescs. add (ownedHitGroupDesc. get ()); 989} 990maxRecursion = inDesc. maxRecursion ; 991maxRayPayloadSize = inDesc. maxRayPayloadSize ; 992maxAttributeSizeInBytes = inDesc. maxAttributeSizeInBytes ; 993flags = inDesc. flags ; 994} 995}; 996 997class PipelineStateBase : public IPipelineState, public Slang::ComObject 998{ 999public: 1000SLANG_COM_OBJECT_IUNKNOWN_ALL 1001IPipelineState * getInterface ( const Slang ::Guid & guid); 1002 1003struct PipelineStateDesc 1004{ 1005PipelineType type ; 1006GraphicsPipelineStateDesc graphics ; 1007ComputePipelineStateDesc compute ; 1008OwnedRayTracingPipelineStateDesc rayTracing ; 1009ShaderProgramBase * getProgram () 1010{ 1011switch ( type ) 1012{ 1013case PipelineType::Compute: 1014return static_cast < ShaderProgramBase *> (compute. program ); 1015case PipelineType ::Graphics: 1016return static_cast < ShaderProgramBase *> (graphics. program ); 1017case PipelineType ::RayTracing: 1018return static_cast < ShaderProgramBase *> (rayTracing. program ); 1019} 1020return nullptr; 1021} 1022} desc; 1023 1024// We need to hold inputLayout and framebufferLayout objects alive, since we may use it to 1025// create specialized pipeline states later. 1026Slang ::RefPtr < InputLayoutBase > inputLayout; 1027Slang ::RefPtr < FramebufferLayoutBase > framebufferLayout; 1028 1029// The pipeline state from which this pipeline state is specialized. 1030// If null, this pipeline is either an unspecialized pipeline. 1031Slang ::RefPtr < PipelineStateBase > unspecializedPipelineState = nullptr ; 1032 1033// Indicates whether this is a specializable pipeline. A specializable 1034// pipeline cannot be used directly and must be specialized first. 1035bool isSpecializable = false; 1036Slang ::RefPtr < ShaderProgramBase > m_program; 1037template < typename TProgram > 1038TProgram * getProgram () 1039{ 1040return static_cast < TProgram *> (m_program. Ptr ()); 1041} 1042 1043virtual SLANG_NO_THROW Result SLANG_MCALL getNativeHandle ( InteropHandle * outHandle) override; 1044virtual Result ensureAPIPipelineStateCreated () { return SLANG_OK ; }; 1045 1046protected : 1047void initializeBase ( const PipelineStateDesc & inDesc); 1048}; 1049 1050struct ComponentKey 1051{ 1052Slang :: UnownedStringSlice typeName ; 1053Slang :: ShortList < ShaderComponentID > specializationArgs ; 1054Slang :: HashCode hash ; 1055Slang :: HashCode getHashCode () const { return hash ; } 1056void updateHash () 1057{ 1058hash = typeName. getHashCode (); 1059for (auto & arg : specializationArgs) 1060hash = Slang:: combineHash (hash, arg); 1061} 1062}; 1063 1064struct PipelineKey 1065{ 1066PipelineStateBase * pipeline; 1067Slang::ShortList < ShaderComponentID > specializationArgs; 1068Slang::HashCode hash; 1069Slang::HashCode getHashCode () const { return hash; } 1070void updateHash () 1071{ 1072hash = Slang:: getHashCode (pipeline); 1073for (auto & arg : specializationArgs) 1074hash = Slang:: combineHash (hash, arg); 1075} 1076bool operator == ( const PipelineKey & other) const 1077{ 1078if (pipeline != other. pipeline ) 1079return false; 1080if (specializationArgs. getCount () != other. specializationArgs . getCount ()) 1081return false; 1082for (Slang::Index i = 0 ; i < other. specializationArgs . getCount (); i ++ ) 1083{ 1084if (specializationArgs[i] != other. specializationArgs [i]) 1085return false; 1086} 1087return true; 1088} 1089}; 1090 1091struct OwningComponentKey 1092{ 1093Slang::String typeName; 1094Slang::ShortList < ShaderComponentID > specializationArgs; 1095Slang::HashCode hash; 1096Slang::HashCode getHashCode() const { return hash; } 1097template < typename KeyType > 1098bool operator == ( const KeyType & other) const 1099{ 1100if (typeName != other. typeName ) 1101return false; 1102if (specializationArgs. getCount () != other. specializationArgs . getCount ()) 1103return false; 1104for ( Slang ::Index i = 0 ; i < other. specializationArgs . getCount (); i ++ ) 1105{ 1106if (specializationArgs[i] != other. specializationArgs [i]) 1107return false; 1108} 1109return true; 1110} 1111}; 1112 1113// A cache from specialization keys to a specialized `ShaderKernel`. 1114class ShaderCache : public Slang::RefObject 1115{ 1116public : 1117ShaderComponentID getComponentId ( slang ::TypeReflection * type); 1118ShaderComponentID getComponentId ( Slang ::UnownedStringSlice name); 1119ShaderComponentID getComponentId ( ComponentKey key); 1120 1121Slang ::RefPtr < PipelineStateBase > getSpecializedPipelineState (PipelineKey programKey) 1122{ 1123Slang ::RefPtr < PipelineStateBase > result; 1124if (specializedPipelines. tryGetValue (programKey, result)) 1125return result; 1126return nullptr ; 1127} 1128void addSpecializedPipeline ( 1129PipelineKey key, 1130Slang ::RefPtr < PipelineStateBase > specializedPipeline); 1131void free () 1132{ 1133specializedPipelines = decltype (specializedPipelines)(); 1134componentIds = decltype (componentIds)(); 1135} 1136 1137protected : 1138Slang ::OrderedDictionary < OwningComponentKey, ShaderComponentID > componentIds; 1139Slang ::OrderedDictionary < PipelineKey, Slang::RefPtr < PipelineStateBase>> specializedPipelines; 1140}; 1141 1142class TransientResourceHeapBase : public ITransientResourceHeap, public Slang::ComObject 1143{ 1144public: 1145uint64_t m_version = 0 ; 1146uint64_t getVersion () { return m_version; } 1147uint64_t & getVersionCounter () 1148{ 1149static uint64_t version = 1 ; 1150return version; 1151} 1152TransientResourceHeapBase () { m_version = getVersionCounter () ++ ; } 1153virtual ~ TransientResourceHeapBase () {} 1154 1155public : 1156SLANG_COM_OBJECT_IUNKNOWN_ALL 1157ITransientResourceHeap * getInterface ( const Slang ::Guid & guid) 1158{ 1159if (guid == GfxGUID::IID_ISlangUnknown || guid == GfxGUID::IID_ITransientResourceHeap) 1160return static_cast < ITransientResourceHeap *> (this); 1161return nullptr ; 1162} 1163 1164virtual SLANG_NO_THROW Result SLANG_MCALL finish () override { return SLANG_OK ; } 1165}; 1166 1167static const int kRayGenRecordSize = 64 ; // D3D12_RAYTRACING_SHADER_TABLE_BYTE_ALIGNMENT; 1168 1169class ShaderTableBase : public IShaderTable, public Slang::ComObject 1170{ 1171public: 1172Slang::List < Slang::String > m_shaderGroupNames; 1173Slang ::List < ShaderRecordOverwrite > m_recordOverwrites; 1174 1175uint32_t m_rayGenShaderCount; 1176uint32_t m_missShaderCount; 1177uint32_t m_hitGroupCount; 1178uint32_t m_callableShaderCount; 1179 1180Slang ::Dictionary < PipelineStateBase * , Slang::RefPtr < BufferResource>> m_deviceBuffers; 1181 1182SLANG_COM_OBJECT_IUNKNOWN_ALL 1183IShaderTable * getInterface ( const Slang ::Guid & guid) 1184{ 1185if (guid == GfxGUID::IID_ISlangUnknown || guid == GfxGUID::IID_IShaderTable) 1186return static_cast < IShaderTable *> (this); 1187return nullptr ; 1188} 1189 1190virtual Slang::RefPtr < BufferResource > createDeviceBuffer ( 1191PipelineStateBase * pipeline, 1192TransientResourceHeapBase * transientHeap, 1193IResourceCommandEncoder * encoder) = 0 ; 1194 1195BufferResource * getOrCreateBuffer ( 1196PipelineStateBase * pipeline, 1197TransientResourceHeapBase * transientHeap, 1198IResourceCommandEncoder * encoder) 1199{ 1200if (auto ptr = m_deviceBuffers. tryGetValue (pipeline)) 1201{ 1202return ptr -> Ptr (); 1203} 1204auto result = createDeviceBuffer ( pipeline , transientHeap , encoder ); 1205m_deviceBuffers[pipeline] = result; 1206return result; 1207} 1208 1209Result init ( const IShaderTable ::Desc & desc); 1210}; 1211 1212// Renderer implementation shared by all platforms. 1213// Responsible for shader compilation, specialization and caching. 1214class RendererBase : public IDevice, public IShaderCache, public Slang::ComObject 1215{ 1216friend class ShaderObjectBase; 1217 1218public : 1219SLANG_COM_OBJECT_IUNKNOWN_ADD_REF 1220SLANG_COM_OBJECT_IUNKNOWN_RELEASE 1221 1222virtual SLANG_NO_THROW Result SLANG_MCALL getNativeDeviceHandles ( InteropHandles * outHandles) 1223SLANG_OVERRIDE ; 1224virtual SLANG_NO_THROW Result SLANG_MCALL getFeatures ( 1225const char ** outFeatures, 1226Size bufferSize, 1227GfxCount * outFeatureCount) SLANG_OVERRIDE ; 1228virtual SLANG_NO_THROW bool SLANG_MCALL hasFeature ( const char * featureName) SLANG_OVERRIDE ; 1229virtual SLANG_NO_THROW Result SLANG_MCALL 1230getFormatSupportedResourceStates ( Format format, ResourceStateSet * outStates) override; 1231virtual SLANG_NO_THROW Result SLANG_MCALL getSlangSession ( slang :: ISession ** outSlangSession) 1232SLANG_OVERRIDE ; 1233virtual SLANG_NO_THROW SlangResult SLANG_MCALL 1234queryInterface( SlangUUID const & uuid, void ** outObject) SLANG_OVERRIDE ; 1235IDevice * getInterface ( const Slang ::Guid & guid); 1236 1237virtual SLANG_NO_THROW Result SLANG_MCALL createTextureFromNativeHandle ( 1238InteropHandle handle, 1239const ITextureResource ::Desc & srcDesc, 1240ITextureResource ** outResource) SLANG_OVERRIDE ; 1241 1242virtual SLANG_NO_THROW Result SLANG_MCALL createTextureFromSharedHandle ( 1243InteropHandle handle, 1244const ITextureResource ::Desc & srcDesc, 1245const Size size, 1246ITextureResource ** outResource) SLANG_OVERRIDE ; 1247 1248virtual SLANG_NO_THROW Result SLANG_MCALL createBufferFromNativeHandle ( 1249InteropHandle handle, 1250const IBufferResource ::Desc & srcDesc, 1251IBufferResource ** outResource) SLANG_OVERRIDE ; 1252 1253virtual SLANG_NO_THROW Result SLANG_MCALL createBufferFromSharedHandle ( 1254InteropHandle handle, 1255const IBufferResource ::Desc & srcDesc, 1256IBufferResource ** outResource) SLANG_OVERRIDE ; 1257 1258virtual SLANG_NO_THROW Result SLANG_MCALL createProgram2 ( 1259const IShaderProgram ::CreateDesc2 & desc, 1260IShaderProgram ** outProgram, 1261ISlangBlob ** outDiagnostic) override; 1262 1263virtual SLANG_NO_THROW Result SLANG_MCALL createShaderObject ( 1264slang :: TypeReflection * type, 1265ShaderObjectContainerType containerType, 1266IShaderObject ** outObject) SLANG_OVERRIDE ; 1267 1268virtual SLANG_NO_THROW Result SLANG_MCALL createShaderObject2 ( 1269slang :: ISession * session, 1270slang:: TypeReflection * type, 1271ShaderObjectContainerType containerType, 1272IShaderObject ** outObject) SLANG_OVERRIDE ; 1273 1274virtual SLANG_NO_THROW Result SLANG_MCALL createMutableShaderObject ( 1275slang :: TypeReflection * type, 1276ShaderObjectContainerType containerType, 1277IShaderObject ** outObject) SLANG_OVERRIDE ; 1278 1279virtual SLANG_NO_THROW Result SLANG_MCALL createMutableShaderObject2 ( 1280slang :: ISession * session, 1281slang:: TypeReflection * type, 1282ShaderObjectContainerType containerType, 1283IShaderObject ** outObject) SLANG_OVERRIDE ; 1284 1285virtual SLANG_NO_THROW Result SLANG_MCALL createShaderObjectFromTypeLayout ( 1286slang ::TypeLayoutReflection * typeLayout, 1287IShaderObject ** outObject) override; 1288 1289virtual SLANG_NO_THROW Result SLANG_MCALL createMutableShaderObjectFromTypeLayout ( 1290slang ::TypeLayoutReflection * typeLayout, 1291IShaderObject ** outObject) override; 1292 1293// Provides a default implementation that returns SLANG_E_NOT_AVAILABLE for platforms 1294// without ray tracing support. 1295virtual SLANG_NO_THROW Result SLANG_MCALL getAccelerationStructurePrebuildInfo ( 1296const IAccelerationStructure ::BuildInputs & buildInputs, 1297IAccelerationStructure:: PrebuildInfo * outPrebuildInfo) override; 1298 1299// Provides a default implementation that returns SLANG_E_NOT_AVAILABLE for platforms 1300// without ray tracing support. 1301virtual SLANG_NO_THROW Result SLANG_MCALL createAccelerationStructure ( 1302const IAccelerationStructure ::CreateDesc & desc, 1303IAccelerationStructure ** outView) override; 1304 1305// Provides a default implementation that returns SLANG_E_NOT_AVAILABLE for platforms 1306// without ray tracing support. 1307virtual SLANG_NO_THROW Result SLANG_MCALL 1308createShaderTable ( const IShaderTable ::Desc & desc, IShaderTable ** outTable) override; 1309 1310// Provides a default implementation that returns SLANG_E_NOT_AVAILABLE for platforms 1311// without ray tracing support. 1312virtual SLANG_NO_THROW Result SLANG_MCALL createRayTracingPipelineState( 1313const RayTracingPipelineStateDesc & desc, 1314IPipelineState ** outState) override; 1315 1316// Provides a default implementation that returns SLANG_E_NOT_AVAILABLE. 1317virtual SLANG_NO_THROW Result SLANG_MCALL 1318createMutableRootShaderObject ( IShaderProgram * program, IShaderObject ** outObject) override; 1319 1320// Provides a default implementation that returns SLANG_E_NOT_AVAILABLE. 1321virtual SLANG_NO_THROW Result SLANG_MCALL 1322createFence ( const IFence ::Desc & desc, IFence ** outFence) override; 1323 1324// Provides a default implementation that returns SLANG_E_NOT_AVAILABLE. 1325virtual SLANG_NO_THROW Result SLANG_MCALL waitForFences ( 1326GfxCount fenceCount, 1327IFence ** fences, 1328uint64_t * fenceValues, 1329bool waitForAll, 1330uint64_t timeout) override; 1331 1332// Provides a default implementation that returns SLANG_E_NOT_AVAILABLE. 1333virtual SLANG_NO_THROW Result SLANG_MCALL getTextureAllocationInfo ( 1334const ITextureResource ::Desc & desc, 1335Size * outSize, 1336Size * outAlignment) override; 1337 1338// Provides a default implementation that returns SLANG_E_NOT_AVAILABLE. 1339virtual SLANG_NO_THROW Result SLANG_MCALL getTextureRowAlignment ( size_t * outAlignment) override; 1340 1341// Provides a default implementation that returns SLANG_E_NOT_AVAILABLE. 1342virtual SLANG_NO_THROW Result SLANG_MCALL getCooperativeVectorProperties ( 1343CooperativeVectorProperties * properties, 1344uint32_t * propertyCount) override; 1345 1346Result getEntryPointCodeFromShaderCache ( 1347slang ::IComponentType * program, 1348SlangInt entryPointIndex, 1349SlangInt targetIndex, 1350slang ::IBlob ** outCode, 1351slang ::IBlob ** outDiagnostics = nullptr); 1352 1353Result getShaderObjectLayout ( 1354slang ::ISession * session, 1355slang ::TypeReflection * type, 1356ShaderObjectContainerType container, 1357ShaderObjectLayoutBase ** outLayout); 1358 1359Result getShaderObjectLayout ( 1360slang ::ISession * session, 1361slang ::TypeLayoutReflection * typeLayout, 1362ShaderObjectLayoutBase ** outLayout); 1363 1364public : 1365ExtendedShaderObjectTypeList specializationArgs; 1366// Given current pipeline and root shader object binding, generate and bind a specialized 1367// pipeline if necessary. The newly specialized pipeline is held alive by the pipeline cache so 1368// users of `outNewPipeline` do not need to maintain its lifespan. 1369Result maybeSpecializePipeline ( 1370PipelineStateBase * currentPipeline, 1371ShaderObjectBase * rootObject, 1372Slang ::RefPtr < PipelineStateBase >& outNewPipeline); 1373 1374 1375virtual Result createShaderObjectLayout ( 1376slang ::ISession * session, 1377slang ::TypeLayoutReflection * typeLayout, 1378ShaderObjectLayoutBase ** outLayout) = 0 ; 1379 1380virtual Result createShaderObject ( 1381ShaderObjectLayoutBase * layout, 1382IShaderObject ** outObject) = 0 ; 1383 1384virtual Result createMutableShaderObject ( 1385ShaderObjectLayoutBase * layout, 1386IShaderObject ** outObject) = 0 ; 1387 1388public : 1389// IShaderCache interface 1390virtual SLANG_NO_THROW Result SLANG_MCALL clearShaderCache () SLANG_OVERRIDE ; 1391virtual SLANG_NO_THROW Result SLANG_MCALL getShaderCacheStats ( ShaderCacheStats * outStats) 1392SLANG_OVERRIDE ; 1393virtual SLANG_NO_THROW Result SLANG_MCALL resetShaderCacheStats () SLANG_OVERRIDE ; 1394 1395protected: 1396virtual SLANG_NO_THROW SlangResult SLANG_MCALL initialize ( const Desc & desc); 1397 1398protected : 1399Slang::List < Slang::String > m_features; 1400std ::vector < CooperativeVectorProperties > m_cooperativeVectorProperties; 1401 1402public : 1403SlangContext slangContext; 1404ShaderCache shaderCache; 1405 1406Slang ::RefPtr < Slang::PersistentCache > persistentShaderCache; 1407 1408Slang ::Dictionary < slang::TypeLayoutReflection * , Slang::RefPtr < ShaderObjectLayoutBase>> 1409m_shaderObjectLayoutCache; 1410Slang ::ComPtr < IPipelineCreationAPIDispatcher > m_pipelineCreationAPIDispatcher; 1411}; 1412 1413bool isDepthFormat ( Format format); 1414 1415IDebugCallback *& _getDebugCallback (); 1416IDebugCallback * _getNullDebugCallback (); 1417inline IDebugCallback * getDebugCallback () 1418{ 1419auto rs = _getDebugCallback (); 1420if ( rs ) 1421{ 1422return rs; 1423} 1424else 1425{ 1426return _getNullDebugCallback (); 1427} 1428} 1429 1430 1431// Implementations that have to come after RendererBase 1432 1433//-------------------------------------------------------------------------------- 1434template < typename TShaderObjectImpl, typename TShaderObjectLayoutImpl, typename TShaderObjectData > 1435void ShaderObjectBaseImpl < TShaderObjectImpl, TShaderObjectLayoutImpl , TShaderObjectData > :: 1436setSpecializationArgsForContainerElement ( ExtendedShaderObjectTypeList & specializationArgs) 1437{ 1438// Compute specialization args for the structured buffer object. 1439// If we haven't filled anything to `m_structuredBufferSpecializationArgs` yet, 1440// use `specializationArgs` directly. 1441if (m_structuredBufferSpecializationArgs. getCount () == 0 ) 1442{ 1443m_structuredBufferSpecializationArgs = Slang:: _Move (specializationArgs); 1444} 1445else 1446{ 1447// If `m_structuredBufferSpecializationArgs` already contains some arguments, we 1448// need to check if they are the same as `specializationArgs`, and replace 1449// anything that is different with `__Dynamic` because we cannot specialize the 1450// buffer type if the element types are not the same. 1451SLANG_ASSERT ( 1452m_structuredBufferSpecializationArgs. getCount () == specializationArgs. getCount ()); 1453auto device = getRenderer (); 1454for ( Slang ::Index i = 0 ; i < m_structuredBufferSpecializationArgs. getCount (); i ++ ) 1455{ 1456if (m_structuredBufferSpecializationArgs[i]. componentID != 1457specializationArgs[i]. componentID ) 1458{ 1459auto dynamicType = device -> slangContext . session -> getDynamicType (); 1460m_structuredBufferSpecializationArgs. componentIDs [i] = 1461device -> shaderCache . getComponentId (dynamicType); 1462m_structuredBufferSpecializationArgs. components [i] = 1463slang:: SpecializationArg :: fromType (dynamicType); 1464} 1465} 1466} 1467} 1468 1469//-------------------------------------------------------------------------------- 1470template < typename TShaderObjectImpl, typename TShaderObjectLayoutImpl, typename TShaderObjectData > 1471Result ShaderObjectBaseImpl < TShaderObjectImpl, TShaderObjectLayoutImpl , TShaderObjectData > :: 1472getExtendedShaderTypeListFromSpecializationArgs ( 1473ExtendedShaderObjectTypeList & list, 1474const slang ::SpecializationArg * args, 1475uint32_t count) 1476{ 1477auto device = getRenderer (); 1478for ( uint32_t i = 0 ; i < count; i ++ ) 1479{ 1480gfx :: ExtendedShaderObjectType extendedType; 1481switch (args[i]. kind ) 1482{ 1483case slang:: SpecializationArg :: Kind :: Type : 1484extendedType. slangType = args[i]. type ; 1485extendedType. componentID = device -> shaderCache . getComponentId (args[i]. type ); 1486break ; 1487default : 1488SLANG_ASSERT (false && "Unexpected specialization argument kind." ); 1489return SLANG_FAIL ; 1490} 1491list. add (extendedType); 1492} 1493return SLANG_OK ; 1494} 1495 1496//-------------------------------------------------------------------------------- 1497template < typename TShaderObjectImpl, typename TShaderObjectLayoutImpl, typename TShaderObjectData > 1498Result ShaderObjectBaseImpl < TShaderObjectImpl, TShaderObjectLayoutImpl , TShaderObjectData > :: 1499collectSpecializationArgs ( ExtendedShaderObjectTypeList & args) 1500{ 1501if (m_layout -> getContainerType () != ShaderObjectContainerType::None) 1502{ 1503args. addRange (m_structuredBufferSpecializationArgs); 1504return SLANG_OK ; 1505} 1506 1507auto device = getRenderer (); 1508auto & subObjectRanges = getLayout () -> getSubObjectRanges (); 1509// The following logic is built on the assumption that all fields that involve 1510// existential types (and therefore require specialization) will results in a sub-object 1511// range in the type layout. This allows us to simply scan the sub-object ranges to find 1512// out all specialization arguments. 1513Slang :: Index subObjectRangeCount = subObjectRanges. getCount (); 1514 1515for ( Slang ::Index subObjectRangeIndex = 0 ; subObjectRangeIndex < subObjectRangeCount; 1516subObjectRangeIndex ++ ) 1517{ 1518auto const & subObjectRange = subObjectRanges[subObjectRangeIndex]; 1519auto const & bindingRange = getLayout () -> getBindingRange (subObjectRange. bindingRangeIndex ); 1520 1521Slang :: Index oldArgsCount = args. getCount (); 1522 1523Slang :: Index count = bindingRange. count ; 1524 1525for ( Slang ::Index subObjectIndexInRange = 0 ; subObjectIndexInRange < count; 1526subObjectIndexInRange ++ ) 1527{ 1528ExtendedShaderObjectTypeList typeArgs; 1529Slang :: Index objectIndex = bindingRange. subObjectIndex + subObjectIndexInRange; 1530auto subObject = m_objects[objectIndex]; 1531 1532if (!subObject) 1533continue ; 1534 1535if (objectIndex < m_userProvidedSpecializationArgs. getCount () && 1536m_userProvidedSpecializationArgs[objectIndex]) 1537{ 1538args. addRange ( * m_userProvidedSpecializationArgs[objectIndex]); 1539continue ; 1540} 1541 1542switch (bindingRange. bindingType ) 1543{ 1544case slang:: BindingType :: ExistentialValue : 1545{ 1546// A binding type of `ExistentialValue` means the sub-object represents a 1547// interface-typed field. In this case the specialization argument for this 1548// field is the actual specialized type of the bound shader object. If the 1549// shader object's type is an ordinary type without existential fields, then 1550// the type argument will simply be the ordinary type. But if the sub 1551// object's type is itself a specialized type, we need to make sure to use 1552// that type as the specialization argument. 1553 1554ExtendedShaderObjectType specializedSubObjType; 1555SLANG_RETURN_ON_FAIL ( 1556subObject -> getSpecializedShaderObjectType ( & specializedSubObjType)); 1557typeArgs. add (specializedSubObjType); 1558break ; 1559} 1560case slang:: BindingType :: ParameterBlock : 1561case slang:: BindingType :: ConstantBuffer : 1562case slang:: BindingType :: RawBuffer : 1563case slang:: BindingType :: MutableRawBuffer : 1564// If the field's type is `ParameterBlock<IFoo>`, we want to pull in the type 1565// argument from the sub object for specialization. 1566if (bindingRange. isSpecializable ) 1567{ 1568ExtendedShaderObjectType specializedSubObjType; 1569SLANG_RETURN_ON_FAIL ( 1570subObject -> getSpecializedShaderObjectType ( & specializedSubObjType)); 1571typeArgs. add (specializedSubObjType); 1572} 1573 1574// If field's type is `ParameterBlock<SomeStruct>` or 1575// `ConstantBuffer<SomeStruct>`, where `SomeStruct` is a struct type (not 1576// directly an interface type), we need to recursively collect the 1577// specialization arguments from the bound sub object. 1578SLANG_RETURN_ON_FAIL (subObject -> collectSpecializationArgs (typeArgs)); 1579break ; 1580} 1581 1582auto addedTypeArgCountForCurrentRange = args. getCount () - oldArgsCount; 1583if (addedTypeArgCountForCurrentRange == 0 ) 1584{ 1585args. addRange (typeArgs); 1586} 1587else 1588{ 1589// If type arguments for each elements in the array is different, use 1590// `__Dynamic` type for the differing argument to disable specialization. 1591SLANG_ASSERT (addedTypeArgCountForCurrentRange == typeArgs. getCount ()); 1592for ( Slang ::Index i = 0 ; i < addedTypeArgCountForCurrentRange; i ++ ) 1593{ 1594if (args[i + oldArgsCount]. componentID != typeArgs[i]. componentID ) 1595{ 1596auto dynamicType = device -> slangContext . session -> getDynamicType (); 1597args. componentIDs [i + oldArgsCount] = 1598device -> shaderCache . getComponentId (dynamicType); 1599args. components [i + oldArgsCount] = 1600slang:: SpecializationArg :: fromType (dynamicType); 1601} 1602} 1603} 1604} 1605} 1606return SLANG_OK ; 1607} 1608} // namespace gfx