yum-mirror/slang
Making it easier to work with shaders
git clone https://git.yummers.dev/yum-mirror/slang
785669c87
master
1#include "renderer-shared.h" 2 3#include "../../source/core/slang-file-system.h" 4#include "../../source/core/slang-stable-hash.h" 5#include "core/slang-io.h" 6#include "core/slang-token-reader.h" 7#include "mutable-shader-object.h" 8#include "slang.h" 9 10using namespace Slang ; 11 12namespace gfx 13{ 14 15const Slang ::Guid GfxGUID ::IID_ISlangUnknown = SLANG_UUID_ISlangUnknown ; 16const Slang ::Guid GfxGUID ::IID_IShaderProgram = SLANG_UUID_IShaderProgram ; 17const Slang ::Guid GfxGUID ::IID_IInputLayout = SLANG_UUID_IInputLayout ; 18const Slang ::Guid GfxGUID ::IID_IPipelineState = SLANG_UUID_IPipelineState ; 19const Slang ::Guid GfxGUID ::IID_ITransientResourceHeap = SLANG_UUID_ITransientResourceHeap ; 20const Slang ::Guid GfxGUID ::IID_IResourceView = SLANG_UUID_IResourceView ; 21const Slang ::Guid GfxGUID ::IID_IFramebuffer = SLANG_UUID_IFrameBuffer ; 22const Slang ::Guid GfxGUID ::IID_IFramebufferLayout = SLANG_UUID_IFramebufferLayout ; 23 24const Slang ::Guid GfxGUID ::IID_ISwapchain = SLANG_UUID_ISwapchain ; 25const Slang ::Guid GfxGUID ::IID_ISamplerState = SLANG_UUID_ISamplerState ; 26const Slang ::Guid GfxGUID ::IID_IResource = SLANG_UUID_IResource ; 27const Slang ::Guid GfxGUID ::IID_IBufferResource = SLANG_UUID_IBufferResource ; 28const Slang ::Guid GfxGUID ::IID_ITextureResource = SLANG_UUID_ITextureResource ; 29const Slang ::Guid GfxGUID ::IID_IDevice = SLANG_UUID_IDevice ; 30const Slang ::Guid GfxGUID ::IID_IShaderCache = SLANG_UUID_IShaderCache ; 31const Slang ::Guid GfxGUID ::IID_IShaderObject = SLANG_UUID_IShaderObject ; 32 33const Slang ::Guid GfxGUID ::IID_IRenderPassLayout = SLANG_UUID_IRenderPassLayout ; 34const Slang ::Guid GfxGUID ::IID_IRayTracingCommandEncoder = IRayTracingCommandEncoder ::getTypeGuid (); 35const Slang ::Guid GfxGUID ::IID_IResourceCommandEncoder = IResourceCommandEncoder ::getTypeGuid (); 36const Slang ::Guid GfxGUID ::IID_IComputeCommandEncoder = IComputeCommandEncoder ::getTypeGuid (); 37const Slang ::Guid GfxGUID ::IID_IRenderCommandEncoder = IRenderCommandEncoder ::getTypeGuid (); 38 39const Slang ::Guid GfxGUID ::IID_ICommandBuffer = SLANG_UUID_ICommandBuffer ; 40const Slang ::Guid GfxGUID ::IID_ICommandBufferD3D12 = SLANG_UUID_ICommandBufferD3D12 ; 41 42const Slang ::Guid GfxGUID ::IID_ICommandQueue = SLANG_UUID_ICommandQueue ; 43const Slang ::Guid GfxGUID ::IID_IQueryPool = SLANG_UUID_IQueryPool ; 44const Slang ::Guid GfxGUID ::IID_IAccelerationStructure = SLANG_UUID_IAccelerationStructure ; 45const Slang ::Guid GfxGUID ::IID_IFence = SLANG_UUID_IFence ; 46const Slang ::Guid GfxGUID ::IID_IShaderTable = SLANG_UUID_IShaderTable ; 47const Slang ::Guid GfxGUID ::IID_IPipelineCreationAPIDispatcher = 48SLANG_UUID_IPipelineCreationAPIDispatcher ; 49const Slang ::Guid GfxGUID ::IID_IVulkanPipelineCreationAPIDispatcher = 50SLANG_UUID_IVulkanPipelineCreationAPIDispatcher ; 51const Slang ::Guid GfxGUID ::IID_ITransientResourceHeapD3D12 = SLANG_UUID_ITransientResourceHeapD3D12 ; 52 53 54StageType translateStage (SlangStage slangStage ) 55{ 56switch (slangStage ) 57 { 58default : 59SLANG_ASSERT (!"unhandled case" ); 60return gfx::StageType ::Unknown ; 61 62#define CASE (FROM ,TO ) \ 63 case SLANG_STAGE_##FROM: \ 64 return gfx::StageType::TO 65 66CASE (VERTEX ,Vertex ); 67CASE (HULL ,Hull ); 68CASE (DOMAIN ,Domain ); 69CASE (GEOMETRY ,Geometry ); 70CASE (FRAGMENT ,Fragment ); 71 72CASE (COMPUTE ,Compute ); 73 74CASE (RAY_GENERATION ,RayGeneration ); 75CASE (INTERSECTION ,Intersection ); 76CASE (ANY_HIT ,AnyHit ); 77CASE (CLOSEST_HIT ,ClosestHit ); 78CASE (MISS ,Miss ); 79CASE (CALLABLE ,Callable ); 80 81#undef CASE 82 } 83} 84 85IFence * FenceBase ::getInterface (const Slang ::Guid & guid ) 86{ 87if (guid == GfxGUID ::IID_ISlangUnknown || guid == GfxGUID ::IID_IFence ) 88return static_cast < IFence *> (this ); 89return nullptr ; 90} 91 92IResource * BufferResource ::getInterface (const Slang ::Guid & guid ) 93{ 94if (guid == GfxGUID ::IID_ISlangUnknown || guid == GfxGUID ::IID_IResource || 95guid == GfxGUID ::IID_IBufferResource ) 96return static_cast < IBufferResource *> (this ); 97return nullptr ; 98} 99 100SLANG_NO_THROW IResource ::Type SLANG_MCALL BufferResource ::getType () 101{ 102return m_type ; 103} 104SLANG_NO_THROW IBufferResource ::Desc * SLANG_MCALL BufferResource ::getDesc () 105{ 106return & m_desc ; 107} 108 109Result BufferResource ::getNativeResourceHandle (InteropHandle * outHandle ) 110{ 111outHandle -> handleValue = 0 ; 112outHandle -> api = InteropHandleAPI ::Unknown ; 113return SLANG_FAIL ; 114} 115 116Result BufferResource ::getSharedHandle (InteropHandle * outHandle ) 117{ 118outHandle -> api = InteropHandleAPI ::Unknown ; 119outHandle -> handleValue = 0 ; 120return SLANG_FAIL ; 121} 122 123IResource * TextureResource ::getInterface (const Slang ::Guid & guid ) 124{ 125if (guid == GfxGUID ::IID_ISlangUnknown || guid == GfxGUID ::IID_IResource || 126guid == GfxGUID ::IID_ITextureResource ) 127return static_cast < ITextureResource *> (this ); 128return nullptr ; 129} 130 131SLANG_NO_THROW IResource ::Type SLANG_MCALL TextureResource ::getType () 132{ 133return m_type ; 134} 135SLANG_NO_THROW ITextureResource ::Desc * SLANG_MCALL TextureResource ::getDesc () 136{ 137return & m_desc ; 138} 139 140Result TextureResource ::getNativeResourceHandle (InteropHandle * outHandle ) 141{ 142outHandle -> handleValue = 0 ; 143outHandle -> api = InteropHandleAPI ::Unknown ; 144return SLANG_FAIL ; 145} 146 147Result TextureResource ::getSharedHandle (InteropHandle * outHandle ) 148{ 149outHandle -> api = InteropHandleAPI ::Unknown ; 150outHandle -> handleValue = 0 ; 151return SLANG_OK ; 152} 153 154StageType mapStage (SlangStage stage ) 155{ 156switch (stage ) 157 { 158default : 159return StageType ::Unknown ; 160 161case SLANG_STAGE_AMPLIFICATION : 162return gfx::StageType ::Amplification ; 163case SLANG_STAGE_ANY_HIT : 164return gfx::StageType ::AnyHit ; 165case SLANG_STAGE_CALLABLE : 166return gfx::StageType ::Callable ; 167case SLANG_STAGE_CLOSEST_HIT : 168return gfx::StageType ::ClosestHit ; 169case SLANG_STAGE_COMPUTE : 170return gfx::StageType ::Compute ; 171case SLANG_STAGE_DOMAIN : 172return gfx::StageType ::Domain ; 173case SLANG_STAGE_FRAGMENT : 174return gfx::StageType ::Fragment ; 175case SLANG_STAGE_GEOMETRY : 176return gfx::StageType ::Geometry ; 177case SLANG_STAGE_HULL : 178return gfx::StageType ::Hull ; 179case SLANG_STAGE_INTERSECTION : 180return gfx::StageType ::Intersection ; 181case SLANG_STAGE_MESH : 182return gfx::StageType ::Mesh ; 183case SLANG_STAGE_MISS : 184return gfx::StageType ::Miss ; 185case SLANG_STAGE_RAY_GENERATION : 186return gfx::StageType ::RayGeneration ; 187case SLANG_STAGE_VERTEX : 188return gfx::StageType ::Vertex ; 189 } 190} 191 192IResourceView * ResourceViewBase ::getInterface (const Guid & guid ) 193{ 194if (guid == GfxGUID ::IID_ISlangUnknown || guid == GfxGUID ::IID_IResourceView ) 195return static_cast < IResourceView *> (this ); 196return nullptr ; 197} 198 199Result ResourceViewBase ::getNativeHandle (InteropHandle * outHandle ) 200{ 201outHandle -> api = InteropHandleAPI ::Unknown ; 202outHandle -> handleValue = 0 ; 203return SLANG_E_NOT_IMPLEMENTED ; 204} 205 206ISamplerState * SamplerStateBase ::getInterface (const Slang ::Guid & guid ) 207{ 208if (guid == GfxGUID ::IID_ISlangUnknown || guid == GfxGUID ::IID_ISamplerState ) 209return static_cast < ISamplerState *> (this ); 210return nullptr ; 211} 212 213Result SamplerStateBase ::getNativeHandle (InteropHandle * outHandle ) 214{ 215outHandle -> api = InteropHandleAPI ::Unknown ; 216outHandle -> handleValue = 0 ; 217return SLANG_E_NOT_IMPLEMENTED ; 218} 219 220IAccelerationStructure * AccelerationStructureBase ::getInterface (const Slang ::Guid & guid ) 221{ 222if (guid == GfxGUID ::IID_ISlangUnknown || guid == GfxGUID ::IID_IResourceView || 223guid == GfxGUID ::IID_IAccelerationStructure ) 224return static_cast < IAccelerationStructure *> (this ); 225return nullptr ; 226} 227 228bool _doesValueFitInExistentialPayload ( 229 slang::TypeLayoutReflection * concreteTypeLayout , 230 slang::TypeLayoutReflection * existentialTypeLayout ) 231{ 232// Our task here is to figure out if a value of `concreteTypeLayout` 233// can fit into an existential value using `existentialTypelayout`. 234 235// We can start by asking how many bytes the concrete type of the object consumes. 236// 237auto concreteValueSize = concreteTypeLayout -> getSize (); 238 239// We can also compute how many bytes the existential-type value provides, 240// but we need to remember that the *payload* part of that value comes after 241// the header with RTTI and witness-table IDs, so the payload is 16 bytes 242// smaller than the entire value. 243// 244auto existentialValueSize = existentialTypeLayout -> getSize (); 245auto existentialPayloadSize = existentialValueSize - 16 ; 246 247// If the concrete type consumes more ordinary bytes than we have in the payload, 248// it cannot possibly fit. 249// 250if (concreteValueSize > existentialPayloadSize ) 251return false; 252 253// It is possible that the ordinary bytes of `concreteTypeLayout` can fit 254// in the payload, but that type might also use storage other than ordinary 255// bytes. In that case, the value would *not* fit, because all the non-ordinary 256// data can't fit in the payload at all. 257// 258auto categoryCount = concreteTypeLayout -> getCategoryCount (); 259for (unsigned int i = 0 ;i < categoryCount ;++ i ) 260 { 261auto category = concreteTypeLayout -> getCategoryByIndex (i ); 262switch (category ) 263 { 264// We want to ignore any ordinary/uniform data usage, since that 265// was already checked above. 266// 267case slang::ParameterCategory ::Uniform : 268break ; 269 270// Any other kind of data consumed means the value cannot possibly fit. 271default : 272return false; 273 274// TODO: Are there any cases of resource usage that need to be ignored here? 275// E.g., if the sub-object contains its own existential-type fields (which 276// get reflected as consuming "existential value" storage) should that be 277// ignored? 278 } 279 } 280 281// If we didn't reject the concrete type above for either its ordinary 282// data or some use of non-ordinary data, then it seems like it must fit. 283// 284return true; 285} 286 287IShaderProgram * ShaderProgramBase ::getInterface (const Guid & guid ) 288{ 289if (guid == GfxGUID ::IID_ISlangUnknown || guid == GfxGUID ::IID_IShaderProgram ) 290return static_cast < IShaderProgram *> (this ); 291return nullptr ; 292} 293 294IInputLayout * InputLayoutBase ::getInterface (const Guid & guid ) 295{ 296if (guid == GfxGUID ::IID_ISlangUnknown || guid == GfxGUID ::IID_IInputLayout ) 297return static_cast < IInputLayout *> (this ); 298return nullptr ; 299} 300 301IFramebufferLayout * FramebufferLayoutBase ::getInterface (const Guid & guid ) 302{ 303if (guid == GfxGUID ::IID_ISlangUnknown || guid == GfxGUID ::IID_IFramebufferLayout ) 304return static_cast < IFramebufferLayout *> (this ); 305return nullptr ; 306} 307 308IFramebuffer * FramebufferBase ::getInterface (const Guid & guid ) 309{ 310if (guid == GfxGUID ::IID_ISlangUnknown || guid == GfxGUID ::IID_IFramebuffer ) 311return static_cast < IFramebuffer *> (this ); 312return nullptr ; 313} 314 315IQueryPool * QueryPoolBase ::getInterface (const Guid & guid ) 316{ 317if (guid == GfxGUID ::IID_ISlangUnknown || guid == GfxGUID ::IID_IQueryPool ) 318return static_cast < IQueryPool *> (this ); 319return nullptr ; 320} 321 322IPipelineState * PipelineStateBase ::getInterface (const Guid & guid ) 323{ 324if (guid == GfxGUID ::IID_ISlangUnknown || guid == GfxGUID ::IID_IPipelineState ) 325return static_cast < IPipelineState *> (this ); 326return nullptr ; 327} 328 329Result PipelineStateBase ::getNativeHandle (InteropHandle * outHandle ) 330{ 331outHandle -> api = InteropHandleAPI ::Unknown ; 332outHandle -> handleValue = 0 ; 333return SLANG_E_NOT_IMPLEMENTED ; 334} 335 336void PipelineStateBase ::initializeBase (const PipelineStateDesc & inDesc ) 337{ 338desc = inDesc ; 339 340auto program = desc .getProgram (); 341m_program = program ; 342isSpecializable = false; 343if (program -> slangGlobalScope && program -> slangGlobalScope -> getSpecializationParamCount ()!= 0 ) 344isSpecializable = true; 345for (auto & entryPoint :program -> slangEntryPoints ) 346 { 347if (entryPoint -> getSpecializationParamCount ()!= 0 ) 348 { 349isSpecializable = true; 350break ; 351 } 352 } 353// Hold a strong reference to inputLayout and framebufferLayout objects to prevent it from 354// destruction. 355if (inDesc .type == PipelineType ::Graphics ) 356 { 357inputLayout = static_cast < InputLayoutBase *> (inDesc .graphics .inputLayout ); 358framebufferLayout = static_cast < FramebufferLayoutBase *> (inDesc .graphics .framebufferLayout ); 359 } 360} 361 362Result RendererBase ::getEntryPointCodeFromShaderCache ( 363 slang::IComponentType * program , 364SlangInt entryPointIndex , 365SlangInt targetIndex , 366 slang::IBlob ** outCode , 367 slang::IBlob ** outDiagnostics ) 368{ 369// Immediately call getEntryPointCode if no shader cache has been initialized 370if (!persistentShaderCache ) 371 { 372return program -> getEntryPointCode (entryPointIndex ,targetIndex ,outCode ,outDiagnostics ); 373 } 374 375// Hash all relevant state for generating the entry point shader code to use as a key 376// for the shader cache. 377ComPtr < ISlangBlob > hashBlob ; 378program -> getEntryPointHash (entryPointIndex ,targetIndex ,hashBlob .writeRef ()); 379PersistentCache ::Key cacheKey (hashBlob ); 380 381// Query the shader cache. 382ComPtr < ISlangBlob > codeBlob ; 383if (persistentShaderCache -> readEntry (cacheKey ,codeBlob .writeRef ())!= SLANG_OK ) 384 { 385// No cached entry found. Generate the code and add it to the cache. 386SLANG_RETURN_ON_FAIL (program -> getEntryPointCode ( 387entryPointIndex , 388targetIndex , 389codeBlob .writeRef (), 390outDiagnostics )); 391persistentShaderCache -> writeEntry (cacheKey ,codeBlob ); 392 } 393 394* outCode = codeBlob .detach (); 395return SLANG_OK ; 396} 397 398SlangResult RendererBase ::queryInterface (SlangUUID const & uuid ,void ** outObject ) 399{ 400// Only return the shader cache interface if it is enabled. 401if (uuid == GfxGUID ::IID_IShaderCache && persistentShaderCache ) 402 { 403* outObject = static_cast < IShaderCache *> (this ); 404addRef (); 405return SLANG_OK ; 406 } 407 408if (IDevice * device_ptr = getInterface (uuid )) 409 { 410* outObject = device_ptr ; 411addRef (); 412return SLANG_OK ; 413 } 414return SLANG_E_NO_INTERFACE ; 415} 416 417IDevice * gfx::RendererBase ::getInterface (const Guid & guid ) 418{ 419return (guid == GfxGUID ::IID_ISlangUnknown || guid == GfxGUID ::IID_IDevice ) 420 ?static_cast < IDevice *> (this ) 421 :nullptr ; 422} 423 424SLANG_NO_THROW Result SLANG_MCALL RendererBase ::initialize (const Desc & desc ) 425{ 426// We only want to initialize the shader cache if a shader cache path was provided. 427if (desc .shaderCache .shaderCachePath ) 428 { 429PersistentCache ::Desc cacheDesc ; 430cacheDesc .directory = desc .shaderCache .shaderCachePath ; 431cacheDesc .maxEntryCount = desc .shaderCache .maxEntryCount ; 432persistentShaderCache = new PersistentCache (cacheDesc ); 433 } 434 435if (desc .apiCommandDispatcher ) 436 { 437if (desc .deviceType == DeviceType ::Vulkan ) 438 { 439desc .apiCommandDispatcher -> queryInterface ( 440GfxGUID ::IID_IVulkanPipelineCreationAPIDispatcher , 441 (void ** )m_pipelineCreationAPIDispatcher .writeRef ()); 442 } 443else 444 { 445desc .apiCommandDispatcher -> queryInterface ( 446GfxGUID ::IID_IPipelineCreationAPIDispatcher , 447 (void ** )m_pipelineCreationAPIDispatcher .writeRef ()); 448 } 449 } 450return SLANG_OK ; 451} 452 453SLANG_NO_THROW Result SLANG_MCALL RendererBase ::getNativeDeviceHandles (InteropHandles * outHandles ) 454{ 455return SLANG_OK ; 456} 457 458SLANG_NO_THROW Result SLANG_MCALL 459RendererBase ::getFeatures (const char ** outFeatures ,Size bufferSize ,GfxCount * outFeatureCount ) 460{ 461if (bufferSize >= (UInt )m_features .getCount ()) 462 { 463for (Index i = 0 ;i < m_features .getCount ();i ++ ) 464 { 465outFeatures [i ]= m_features [i ].getUnownedSlice ().begin (); 466 } 467 } 468if (outFeatureCount ) 469* outFeatureCount = (GfxCount )m_features .getCount (); 470return SLANG_OK ; 471} 472 473SLANG_NO_THROW bool SLANG_MCALL RendererBase ::hasFeature (const char * featureName ) 474{ 475return m_features .findFirstIndex ([& ](Slang ::String x ) {return x == featureName ; })!= -1 ; 476} 477 478Result RendererBase ::getFormatSupportedResourceStates (Format format ,ResourceStateSet * outStates ) 479{ 480SLANG_UNUSED (format ); 481outStates -> add (ResourceState ::AccelerationStructure ); 482outStates -> add (ResourceState ::AccelerationStructureBuildInput ); 483outStates -> add (ResourceState ::ConstantBuffer ); 484outStates -> add (ResourceState ::CopyDestination ); 485outStates -> add (ResourceState ::CopySource ); 486outStates -> add (ResourceState ::DepthRead ); 487outStates -> add (ResourceState ::DepthWrite ); 488outStates -> add (ResourceState ::IndexBuffer ); 489outStates -> add (ResourceState ::IndirectArgument ); 490outStates -> add (ResourceState ::PreInitialized ); 491outStates -> add (ResourceState ::Present ); 492outStates -> add (ResourceState ::RenderTarget ); 493outStates -> add (ResourceState ::ResolveDestination ); 494outStates -> add (ResourceState ::ResolveSource ); 495outStates -> add (ResourceState ::ShaderResource ); 496outStates -> add (ResourceState ::PixelShaderResource ); 497outStates -> add (ResourceState ::NonPixelShaderResource ); 498outStates -> add (ResourceState ::StreamOutput ); 499outStates -> add (ResourceState ::Undefined ); 500outStates -> add (ResourceState ::UnorderedAccess ); 501outStates -> add (ResourceState ::VertexBuffer ); 502return SLANG_OK ; 503} 504 505SLANG_NO_THROW Result SLANG_MCALL RendererBase ::getSlangSession (slang::ISession ** outSlangSession ) 506{ 507* outSlangSession = slangContext .session .get (); 508slangContext .session -> addRef (); 509return SLANG_OK ; 510} 511 512SLANG_NO_THROW Result SLANG_MCALL RendererBase ::createTextureFromNativeHandle ( 513InteropHandle handle , 514const ITextureResource ::Desc & srcDesc , 515ITextureResource ** outResource ) 516{ 517SLANG_UNUSED (handle ); 518SLANG_UNUSED (srcDesc ); 519SLANG_UNUSED (outResource ); 520return SLANG_E_NOT_AVAILABLE ; 521} 522 523SLANG_NO_THROW Result SLANG_MCALL RendererBase ::createTextureFromSharedHandle ( 524InteropHandle handle , 525const ITextureResource ::Desc & srcDesc , 526const Size size , 527ITextureResource ** outResource ) 528{ 529SLANG_UNUSED (handle ); 530SLANG_UNUSED (srcDesc ); 531SLANG_UNUSED (size ); 532SLANG_UNUSED (outResource ); 533return SLANG_E_NOT_AVAILABLE ; 534} 535 536SLANG_NO_THROW Result SLANG_MCALL RendererBase ::createBufferFromNativeHandle ( 537InteropHandle handle , 538const IBufferResource ::Desc & srcDesc , 539IBufferResource ** outResource ) 540{ 541SLANG_UNUSED (handle ); 542SLANG_UNUSED (srcDesc ); 543SLANG_UNUSED (outResource ); 544return SLANG_E_NOT_AVAILABLE ; 545} 546 547SLANG_NO_THROW Result SLANG_MCALL RendererBase ::createBufferFromSharedHandle ( 548InteropHandle handle , 549const IBufferResource ::Desc & srcDesc , 550IBufferResource ** outResource ) 551{ 552SLANG_UNUSED (handle ); 553SLANG_UNUSED (srcDesc ); 554SLANG_UNUSED (outResource ); 555return SLANG_E_NOT_AVAILABLE ; 556} 557 558SLANG_NO_THROW Result SLANG_MCALL RendererBase ::createShaderObject ( 559 slang::TypeReflection * type , 560ShaderObjectContainerType container , 561IShaderObject ** outObject ) 562{ 563return createShaderObject2 (slangContext .session ,type ,container ,outObject ); 564} 565 566SLANG_NO_THROW Result SLANG_MCALL RendererBase ::createShaderObject2 ( 567 slang::ISession * slangSession , 568 slang::TypeReflection * type , 569ShaderObjectContainerType container , 570IShaderObject ** outObject ) 571{ 572RefPtr < ShaderObjectLayoutBase > shaderObjectLayout ; 573SLANG_RETURN_ON_FAIL ( 574getShaderObjectLayout (slangSession ,type ,container ,shaderObjectLayout .writeRef ())); 575return createShaderObject (shaderObjectLayout ,outObject ); 576} 577 578SLANG_NO_THROW Result SLANG_MCALL RendererBase ::createMutableShaderObject ( 579 slang::TypeReflection * type , 580ShaderObjectContainerType containerType , 581IShaderObject ** outObject ) 582{ 583return createMutableShaderObject2 (slangContext .session ,type ,containerType ,outObject ); 584} 585 586SLANG_NO_THROW Result SLANG_MCALL RendererBase ::createMutableShaderObject2 ( 587 slang::ISession * slangSession , 588 slang::TypeReflection * type , 589ShaderObjectContainerType containerType , 590IShaderObject ** outObject ) 591{ 592RefPtr < ShaderObjectLayoutBase > shaderObjectLayout ; 593SLANG_RETURN_ON_FAIL ( 594getShaderObjectLayout (slangSession ,type ,containerType ,shaderObjectLayout .writeRef ())); 595return createMutableShaderObject (shaderObjectLayout ,outObject ); 596} 597 598Result RendererBase ::createProgram2 ( 599const IShaderProgram ::CreateDesc2 & desc , 600IShaderProgram ** outProgram , 601ISlangBlob ** outDiagnostic ) 602{ 603auto slangSession = slangContext .session .get (); 604 slang::IModule * module = nullptr ; 605ComPtr < slang::IBlob > diagnosticsBlob ; 606switch (desc .sourceType ) 607 { 608case ShaderModuleSourceType ::SlangSourceFile : 609 { 610auto fileName = (char * )desc .sourceData ; 611module = slangSession -> loadModule (fileName ,diagnosticsBlob .writeRef ()); 612if (!module ) 613return SLANG_FAIL ; 614break ; 615 } 616case ShaderModuleSourceType ::SlangSource : 617 { 618auto hash = getStableHashCode32 ((char * )desc .sourceData ,desc .sourceDataSize ); 619auto hashStr = String (hash ); 620auto srcBlob = UnownedRawBlob ::create (desc .sourceData ,desc .sourceDataSize ); 621module = slangSession -> loadModuleFromSource ( 622hashStr .getBuffer (), 623hashStr .getBuffer (), 624srcBlob , 625diagnosticsBlob .writeRef ()); 626if (!module ) 627return SLANG_FAIL ; 628break ; 629 } 630default : 631SLANG_RELEASE_ASSERT (false); 632 } 633 634Slang ::List < ComPtr < slang::IComponentType >> componentTypes ; 635componentTypes .add (ComPtr < slang::IComponentType > (module )); 636 637if (desc .entryPointCount == 0 ) 638 { 639for (SlangInt32 i = 0 ;i < module -> getDefinedEntryPointCount ();i ++ ) 640 { 641ComPtr < slang::IEntryPoint > entryPoint ; 642SLANG_RETURN_ON_FAIL (module -> getDefinedEntryPoint (i ,entryPoint .writeRef ())); 643componentTypes .add (ComPtr < slang::IComponentType > (entryPoint .get ())); 644 } 645 } 646else 647 { 648for (GfxCount i = 0 ;i < desc .entryPointCount ;i ++ ) 649 { 650ComPtr < slang::IEntryPoint > entryPoint ; 651SLANG_RETURN_ON_FAIL ( 652module -> findEntryPointByName (desc .entryPointNames [i ],entryPoint .writeRef ())); 653componentTypes .add (ComPtr < slang::IComponentType > (entryPoint .get ())); 654 } 655 } 656 657Slang ::List < slang::IComponentType *> rawComponentTypes ; 658for (auto & compType :componentTypes ) 659rawComponentTypes .add (compType .get ()); 660 661ComPtr < slang::IComponentType > linkedProgram ; 662SlangResult result = slangSession -> createCompositeComponentType ( 663rawComponentTypes .getBuffer (), 664rawComponentTypes .getCount (), 665linkedProgram .writeRef (), 666diagnosticsBlob .writeRef ()); 667SLANG_RETURN_ON_FAIL (result ); 668 669 gfx::IShaderProgram ::Desc programDesc = {}; 670programDesc .slangGlobalScope = linkedProgram ; 671SLANG_RETURN_ON_FAIL (createProgram (programDesc ,outProgram ,outDiagnostic )); 672 673return SLANG_OK ; 674} 675 676SLANG_NO_THROW Result SLANG_MCALL RendererBase ::createShaderObjectFromTypeLayout ( 677 slang::TypeLayoutReflection * typeLayout , 678IShaderObject ** outObject ) 679{ 680RefPtr < ShaderObjectLayoutBase > shaderObjectLayout ; 681SLANG_RETURN_ON_FAIL ( 682getShaderObjectLayout (slangContext .session ,typeLayout ,shaderObjectLayout .writeRef ())); 683return createShaderObject (shaderObjectLayout ,outObject ); 684} 685 686SLANG_NO_THROW Result SLANG_MCALL RendererBase ::createMutableShaderObjectFromTypeLayout ( 687 slang::TypeLayoutReflection * typeLayout , 688IShaderObject ** outObject ) 689{ 690RefPtr < ShaderObjectLayoutBase > shaderObjectLayout ; 691SLANG_RETURN_ON_FAIL ( 692getShaderObjectLayout (slangContext .session ,typeLayout ,shaderObjectLayout .writeRef ())); 693return createMutableShaderObject (shaderObjectLayout ,outObject ); 694} 695 696Result RendererBase ::getAccelerationStructurePrebuildInfo ( 697const IAccelerationStructure ::BuildInputs & buildInputs , 698IAccelerationStructure ::PrebuildInfo * outPrebuildInfo ) 699{ 700SLANG_UNUSED (buildInputs ); 701SLANG_UNUSED (outPrebuildInfo ); 702return SLANG_E_NOT_AVAILABLE ; 703} 704 705Result RendererBase ::createAccelerationStructure ( 706const IAccelerationStructure ::CreateDesc & desc , 707IAccelerationStructure ** outView ) 708{ 709SLANG_UNUSED (desc ); 710SLANG_UNUSED (outView ); 711return SLANG_E_NOT_AVAILABLE ; 712} 713 714Result RendererBase ::createShaderTable (const IShaderTable ::Desc & desc ,IShaderTable ** outTable ) 715{ 716SLANG_UNUSED (desc ); 717SLANG_UNUSED (outTable ); 718return SLANG_E_NOT_AVAILABLE ; 719} 720 721Result RendererBase ::createRayTracingPipelineState ( 722const RayTracingPipelineStateDesc & desc , 723IPipelineState ** outState ) 724{ 725SLANG_UNUSED (desc ); 726SLANG_UNUSED (outState ); 727return SLANG_E_NOT_AVAILABLE ; 728} 729 730Result RendererBase ::createMutableRootShaderObject ( 731IShaderProgram * program , 732IShaderObject ** outObject ) 733{ 734SLANG_UNUSED (program ); 735SLANG_UNUSED (outObject ); 736return SLANG_E_NOT_AVAILABLE ; 737} 738 739Result RendererBase ::createFence (const IFence ::Desc & desc ,IFence ** outFence ) 740{ 741SLANG_UNUSED (desc ); 742* outFence = nullptr ; 743return SLANG_E_NOT_AVAILABLE ; 744} 745 746Result RendererBase ::waitForFences ( 747GfxCount fenceCount , 748IFence ** fences , 749uint64_t * fenceValues , 750bool waitForAll , 751uint64_t timeout ) 752{ 753SLANG_UNUSED (fenceCount ); 754SLANG_UNUSED (fences ); 755SLANG_UNUSED (fenceValues ); 756SLANG_UNUSED (waitForAll ); 757SLANG_UNUSED (timeout ); 758return SLANG_E_NOT_AVAILABLE ; 759} 760 761Result RendererBase ::getTextureAllocationInfo ( 762const ITextureResource ::Desc & desc , 763Size * outSize , 764Size * outAlignment ) 765{ 766SLANG_UNUSED (desc ); 767* outSize = 0 ; 768* outAlignment = 0 ; 769return SLANG_E_NOT_AVAILABLE ; 770} 771 772Result RendererBase ::getTextureRowAlignment (Size * outAlignment ) 773{ 774* outAlignment = 0 ; 775return SLANG_E_NOT_AVAILABLE ; 776} 777 778Result RendererBase ::getCooperativeVectorProperties ( 779CooperativeVectorProperties * properties , 780uint32_t * propertyCount ) 781{ 782* propertyCount = 0 ; 783return SLANG_E_NOT_AVAILABLE ; 784} 785 786Result RendererBase ::getShaderObjectLayout ( 787 slang::ISession * session , 788 slang::TypeReflection * type , 789ShaderObjectContainerType container , 790ShaderObjectLayoutBase ** outLayout ) 791{ 792switch (container ) 793 { 794case ShaderObjectContainerType ::StructuredBuffer : 795type = session -> getContainerType (type , slang::ContainerType ::StructuredBuffer ); 796break ; 797case ShaderObjectContainerType ::Array : 798type = session -> getContainerType (type , slang::ContainerType ::UnsizedArray ); 799break ; 800default : 801break ; 802 } 803 804auto typeLayout = session -> getTypeLayout (type ); 805SLANG_RETURN_ON_FAIL (getShaderObjectLayout (session ,typeLayout ,outLayout )); 806 (* outLayout )-> m_slangSession = session ; 807return SLANG_OK ; 808} 809 810Result RendererBase ::getShaderObjectLayout ( 811 slang::ISession * session , 812 slang::TypeLayoutReflection * typeLayout , 813ShaderObjectLayoutBase ** outLayout ) 814{ 815RefPtr < ShaderObjectLayoutBase > shaderObjectLayout ; 816if (!m_shaderObjectLayoutCache .tryGetValue (typeLayout ,shaderObjectLayout )) 817 { 818SLANG_RETURN_ON_FAIL ( 819createShaderObjectLayout (session ,typeLayout ,shaderObjectLayout .writeRef ())); 820m_shaderObjectLayoutCache .add (typeLayout ,shaderObjectLayout ); 821 } 822* outLayout = shaderObjectLayout .detach (); 823return SLANG_OK ; 824} 825 826Result RendererBase ::clearShaderCache () 827{ 828SLANG_ASSERT (persistentShaderCache ); 829return persistentShaderCache -> clear (); 830} 831 832Result RendererBase ::getShaderCacheStats (ShaderCacheStats * outStats ) 833{ 834SLANG_ASSERT (persistentShaderCache ); 835if (!outStats ) 836 { 837return SLANG_E_INVALID_ARG ; 838 } 839 840const auto & stats = persistentShaderCache -> getStats (); 841outStats -> entryCount = (GfxCount )stats .entryCount ; 842outStats -> hitCount = (GfxCount )stats .hitCount ; 843outStats -> missCount = (GfxCount )stats .missCount ; 844return SLANG_OK ; 845} 846 847Result RendererBase ::resetShaderCacheStats () 848{ 849SLANG_ASSERT (persistentShaderCache ); 850persistentShaderCache -> resetStats (); 851return SLANG_OK ; 852} 853 854ShaderComponentID ShaderCache ::getComponentId (slang::TypeReflection * type ) 855{ 856ComponentKey key ; 857key .typeName = UnownedStringSlice (type -> getName ()); 858switch (type -> getKind ()) 859 { 860case slang::TypeReflection ::Kind ::Specialized : 861 { 862auto baseType = type -> getElementType (); 863 864StringBuilder builder ; 865builder .append (UnownedTerminatedStringSlice (baseType -> getName ())); 866 867auto rawType = (SlangReflectionType * )type ; 868 869builder .appendChar ('<' ); 870SlangInt argCount = spReflectionType_getSpecializedTypeArgCount (rawType ); 871for (SlangInt a = 0 ;a < argCount ;++ a ) 872 { 873if (a != 0 ) 874builder .appendChar (',' ); 875if (auto rawArgType = spReflectionType_getSpecializedTypeArgType (rawType ,a )) 876 { 877auto argType = (slang::TypeReflection * )rawArgType ; 878builder .append (argType -> getName ()); 879 } 880 } 881builder .appendChar ('>' ); 882key .typeName = builder .getUnownedSlice (); 883key .updateHash (); 884return getComponentId (key ); 885 } 886// TODO: collect specialization arguments and append them to `key`. 887SLANG_UNIMPLEMENTED_X ("specialized type" ); 888default : 889break ; 890 } 891key .updateHash (); 892return getComponentId (key ); 893} 894 895ShaderComponentID ShaderCache ::getComponentId (UnownedStringSlice name ) 896{ 897ComponentKey key ; 898key .typeName = name ; 899key .updateHash (); 900return getComponentId (key ); 901} 902 903ShaderComponentID ShaderCache ::getComponentId (ComponentKey key ) 904{ 905ShaderComponentID componentId = 0 ; 906if (componentIds .tryGetValue (key ,componentId )) 907return componentId ; 908OwningComponentKey owningTypeKey ; 909owningTypeKey .hash = key .hash ; 910owningTypeKey .typeName = key .typeName ; 911owningTypeKey .specializationArgs .addRange (key .specializationArgs ); 912ShaderComponentID resultId = static_cast < ShaderComponentID > (componentIds .getCount ()); 913componentIds [owningTypeKey ]= resultId ; 914return resultId ; 915} 916 917void ShaderCache ::addSpecializedPipeline ( 918PipelineKey key , 919Slang ::RefPtr < PipelineStateBase > specializedPipeline ) 920{ 921specializedPipelines [key ]= specializedPipeline ; 922} 923 924void ShaderObjectLayoutBase ::initBase ( 925RendererBase * renderer , 926 slang::ISession * session , 927 slang::TypeLayoutReflection * elementTypeLayout ) 928{ 929m_renderer = renderer ; 930m_slangSession = session ; 931m_elementTypeLayout = elementTypeLayout ; 932m_componentID = m_renderer -> shaderCache .getComponentId (m_elementTypeLayout -> getType ()); 933} 934 935// Get the final type this shader object represents. If the shader object's type has existential 936// fields, this function will return a specialized type using the bound sub-objects' type as 937// specialization argument. 938Result ShaderObjectBase ::getSpecializedShaderObjectType (ExtendedShaderObjectType * outType ) 939{ 940return _getSpecializedShaderObjectType (outType ); 941} 942 943Result ShaderObjectBase ::_getSpecializedShaderObjectType (ExtendedShaderObjectType * outType ) 944{ 945if (shaderObjectType .slangType ) 946* outType = shaderObjectType ; 947ExtendedShaderObjectTypeList specializationArgs ; 948SLANG_RETURN_ON_FAIL (collectSpecializationArgs (specializationArgs )); 949if (specializationArgs .getCount ()== 0 ) 950 { 951shaderObjectType .componentID = getLayoutBase ()-> getComponentID (); 952shaderObjectType .slangType = getLayoutBase ()-> getElementTypeLayout ()-> getType (); 953 } 954else 955 { 956shaderObjectType .slangType = getRenderer ()-> slangContext .session -> specializeType ( 957_getElementTypeLayout ()-> getType (), 958specializationArgs .components .getArrayView ().getBuffer (), 959specializationArgs .getCount ()); 960shaderObjectType .componentID = 961getRenderer ()-> shaderCache .getComponentId (shaderObjectType .slangType ); 962 } 963* outType = shaderObjectType ; 964return SLANG_OK ; 965} 966 967Result ShaderObjectBase ::setExistentialHeader ( 968 slang::TypeReflection * existentialType , 969 slang::TypeReflection * concreteType , 970ShaderOffset offset ) 971{ 972// The first field of the tuple (offset zero) is the run-time type information 973// (RTTI) ID for the concrete type being stored into the field. 974// 975// TODO: We need to be able to gather the RTTI type ID from `object` and then 976// use `setData(offset, &TypeID, sizeof(TypeID))`. 977 978// The second field of the tuple (offset 8) is the ID of the "witness" for the 979// conformance of the concrete type to the interface used by this field. 980// 981auto witnessTableOffset = offset ; 982witnessTableOffset .uniformOffset += 8 ; 983// 984// Conformances of a type to an interface are computed and then stored by the 985// Slang runtime, so we can look up the ID for this particular conformance (which 986// will create it on demand). 987// 988// Note: If the type doesn't actually conform to the required interface for 989// this sub-object range, then this is the point where we will detect that 990// fact and error out. 991// 992uint32_t conformanceID = 0xFFFFFFFF ; 993SLANG_RETURN_ON_FAIL (getLayoutBase ()-> m_slangSession -> getTypeConformanceWitnessSequentialID ( 994concreteType , 995existentialType , 996& conformanceID )); 997// 998// Once we have the conformance ID, then we can write it into the object 999// at the required offset. 1000// 1001SLANG_RETURN_ON_FAIL (setData (witnessTableOffset ,& conformanceID ,sizeof (conformanceID ))); 1002 1003return SLANG_OK ; 1004} 1005 1006ResourceViewBase * SimpleShaderObjectData ::getResourceView ( 1007RendererBase * device , 1008 slang::TypeLayoutReflection * elementLayout , 1009 slang::BindingType bindingType ) 1010{ 1011if (!m_structuredBuffer ) 1012 { 1013// Create structured buffer resource if it has not been created. 1014IBufferResource ::Desc desc = {}; 1015desc .allowedStates = 1016ResourceStateSet (ResourceState ::ShaderResource ,ResourceState ::UnorderedAccess ); 1017desc .defaultState = ResourceState ::ShaderResource ; 1018desc .elementSize = (int )elementLayout -> getSize (); 1019desc .format = Format ::Unknown ; 1020desc .type = IResource ::Type ::Buffer ; 1021desc .sizeInBytes = (Size )m_ordinaryData .getCount (); 1022ComPtr < IBufferResource > bufferResource ; 1023SLANG_RETURN_NULL_ON_FAIL (device -> createBufferResource ( 1024desc , 1025m_ordinaryData .getBuffer (), 1026bufferResource .writeRef ())); 1027m_structuredBuffer = static_cast < BufferResource *> (bufferResource .get ()); 1028 1029// Create read-only (shader-resource) and mutable (unordered access) views. 1030ComPtr < IResourceView > resourceView ; 1031IResourceView ::Desc viewDesc = {}; 1032viewDesc .format = Format ::Unknown ; 1033viewDesc .type = IResourceView ::Type ::ShaderResource ; 1034SLANG_RETURN_NULL_ON_FAIL (device -> createBufferView ( 1035bufferResource .get (), 1036nullptr , 1037viewDesc , 1038resourceView .writeRef ())); 1039m_structuredBufferView = static_cast < ResourceViewBase *> (resourceView .get ()); 1040viewDesc .type = IResourceView ::Type ::UnorderedAccess ; 1041SLANG_RETURN_NULL_ON_FAIL (device -> createBufferView ( 1042bufferResource .get (), 1043nullptr , 1044viewDesc , 1045resourceView .writeRef ())); 1046m_rwStructuredBufferView = static_cast < ResourceViewBase *> (resourceView .get ()); 1047 } 1048 1049switch (bindingType ) 1050 { 1051case slang::BindingType ::RawBuffer : 1052return m_structuredBufferView .Ptr (); 1053case slang::BindingType ::MutableRawBuffer : 1054return m_rwStructuredBufferView .Ptr (); 1055default : 1056SLANG_ASSERT (false&& "Invalid binding type." ); 1057return nullptr ; 1058 } 1059} 1060 1061void ShaderProgramBase ::init (const IShaderProgram ::Desc & inDesc ) 1062{ 1063desc = inDesc ; 1064 1065slangGlobalScope = desc .slangGlobalScope ; 1066for (GfxIndex i = 0 ;i < desc .entryPointCount ;i ++ ) 1067 { 1068slangEntryPoints .add (ComPtr < slang::IComponentType > (desc .slangEntryPoints [i ])); 1069 } 1070 1071auto session = desc .slangGlobalScope ?desc .slangGlobalScope -> getSession () :nullptr ; 1072if (desc .linkingStyle == IShaderProgram ::LinkingStyle ::SingleProgram ) 1073 { 1074List < slang::IComponentType *> components ; 1075if (desc .slangGlobalScope ) 1076 { 1077components .add (desc .slangGlobalScope ); 1078 } 1079for (GfxIndex i = 0 ;i < desc .entryPointCount ;i ++ ) 1080 { 1081if (!session ) 1082 { 1083session = desc .slangEntryPoints [i ]-> getSession (); 1084 } 1085components .add (desc .slangEntryPoints [i ]); 1086 } 1087session -> createCompositeComponentType ( 1088components .getBuffer (), 1089components .getCount (), 1090linkedProgram .writeRef ()); 1091 } 1092else 1093 { 1094for (GfxIndex i = 0 ;i < desc .entryPointCount ;i ++ ) 1095 { 1096if (desc .slangGlobalScope ) 1097 { 1098 slang::IComponentType * entryPointComponents [2 ]= { 1099desc .slangGlobalScope , 1100desc .slangEntryPoints [i ]}; 1101ComPtr < slang::IComponentType > linkedEntryPoint ; 1102session -> createCompositeComponentType ( 1103entryPointComponents , 11042 , 1105linkedEntryPoint .writeRef ()); 1106linkedEntryPoints .add (linkedEntryPoint ); 1107 } 1108else 1109 { 1110linkedEntryPoints .add (ComPtr < slang::IComponentType > (desc .slangEntryPoints [i ])); 1111 } 1112 } 1113linkedProgram = desc .slangGlobalScope ; 1114 } 1115} 1116 1117Result ShaderProgramBase ::compileShaders (RendererBase * device ) 1118{ 1119auto compileTarget = device -> slangContext .compileTarget ; 1120// For a fully specialized program, read and store its kernel code in `shaderProgram`. 1121auto compileShader = [& ](slang::EntryPointReflection * entryPointInfo , 1122 slang::IComponentType * entryPointComponent , 1123SlangInt entryPointIndex ) 1124 { 1125auto stage = entryPointInfo -> getStage (); 1126List < ComPtr < ISlangBlob >> kernelCodes ; 1127 { 1128ComPtr < ISlangBlob > downstreamIR ; 1129ComPtr < ISlangBlob > diagnostics ; 1130auto compileResult = device -> getEntryPointCodeFromShaderCache ( 1131entryPointComponent , 1132entryPointIndex , 11330 , 1134downstreamIR .writeRef (), 1135diagnostics .writeRef ()); 1136if (diagnostics ) 1137 { 1138DebugMessageType msgType = DebugMessageType ::Warning ; 1139if (compileResult != SLANG_OK ) 1140msgType = DebugMessageType ::Error ; 1141getDebugCallback ()-> handleMessage ( 1142msgType , 1143DebugMessageSource ::Slang , 1144 (char * )diagnostics -> getBufferPointer ()); 1145 } 1146SLANG_RETURN_ON_FAIL (compileResult ); 1147 1148kernelCodes .add (downstreamIR ); 1149 } 1150 1151// If target precompilation with deferred downstream linking is enabled, 1152// kernelCode may only represent the glue code holding together the 1153// bits of precompiled target IR. It's the application's job to pull it 1154// together. Collect those dependency target IRs too. 1155ComPtr < slang::IModulePrecompileService_Experimental > componentPrecompileService ; 1156if (this -> desc .downstreamLinkMode == DownstreamLinkMode ::Deferred && 1157entryPointComponent -> queryInterface ( 1158 slang::IModulePrecompileService_Experimental ::getTypeGuid (), 1159 (void ** )componentPrecompileService .writeRef ())== SLANG_OK ) 1160 { 1161SlangInt dependencyCount = componentPrecompileService -> getModuleDependencyCount (); 1162if (dependencyCount > 0 ) 1163 { 1164for (int dependencyIndex = 0 ;dependencyIndex < dependencyCount ;dependencyIndex ++ ) 1165 { 1166ComPtr < slang::IModule > dependencyModule ; 1167 { 1168ComPtr < slang::IBlob > diagnosticsBlob ; 1169auto result = componentPrecompileService -> getModuleDependency ( 1170dependencyIndex , 1171dependencyModule .writeRef (), 1172diagnosticsBlob .writeRef ()); 1173if (diagnosticsBlob ) 1174 { 1175DebugMessageType msgType = DebugMessageType ::Warning ; 1176if (result != SLANG_OK ) 1177msgType = DebugMessageType ::Error ; 1178getDebugCallback ()-> handleMessage ( 1179msgType , 1180DebugMessageSource ::Slang , 1181 (char * )diagnosticsBlob -> getBufferPointer ()); 1182 } 1183SLANG_RETURN_ON_FAIL (result ); 1184 } 1185 1186ComPtr < slang::IBlob > downstreamIR ; 1187 { 1188ComPtr < slang::IBlob > diagnosticsBlob ; 1189SlangResult result = SLANG_OK ; 1190ComPtr < slang::IModulePrecompileService_Experimental > precompileService ; 1191result = dependencyModule -> queryInterface ( 1192 slang::IModulePrecompileService_Experimental ::getTypeGuid (), 1193 (void ** )precompileService .writeRef ()); 1194if (result == SLANG_OK ) 1195 { 1196ComPtr < slang::IBlob > diagnosticsBlob ; 1197auto result = precompileService -> getPrecompiledTargetCode ( 1198compileTarget , 1199downstreamIR .writeRef (), 1200diagnosticsBlob .writeRef ()); 1201if (result == SLANG_OK ) 1202 { 1203kernelCodes .add (downstreamIR ); 1204 } 1205if (diagnosticsBlob ) 1206 { 1207DebugMessageType msgType = DebugMessageType ::Warning ; 1208if (result != SLANG_OK ) 1209msgType = DebugMessageType ::Error ; 1210getDebugCallback ()-> handleMessage ( 1211msgType , 1212DebugMessageSource ::Slang , 1213 (char * )diagnosticsBlob -> getBufferPointer ()); 1214 } 1215 } 1216SLANG_RETURN_ON_FAIL (result ); 1217 } 1218 } 1219 } 1220 } 1221 1222SLANG_RETURN_ON_FAIL (createShaderModule (entryPointInfo ,kernelCodes )); 1223return SLANG_OK ; 1224 }; 1225 1226if (linkedEntryPoints .getCount ()== 0 ) 1227 { 1228// If the user does not explicitly specify entry point components, find them from 1229// `linkedEntryPoints`. 1230auto programReflection = linkedProgram -> getLayout (); 1231for (SlangUInt i = 0 ;i < programReflection -> getEntryPointCount ();i ++ ) 1232 { 1233SLANG_RETURN_ON_FAIL (compileShader ( 1234programReflection -> getEntryPointByIndex (i ), 1235linkedProgram , 1236 (SlangInt )i )); 1237 } 1238 } 1239else 1240 { 1241// If the user specifies entry point components via the separated entry point array, 1242// compile code from there. 1243for (auto & entryPoint :linkedEntryPoints ) 1244 { 1245SLANG_RETURN_ON_FAIL ( 1246compileShader (entryPoint -> getLayout ()-> getEntryPointByIndex (0 ),entryPoint ,0 )); 1247 } 1248 } 1249return SLANG_OK ; 1250} 1251 1252Result ShaderProgramBase ::createShaderModule ( 1253 slang::EntryPointReflection * entryPointInfo , 1254List < ComPtr < ISlangBlob >>& kernelCodes ) 1255{ 1256SLANG_UNUSED (entryPointInfo ); 1257SLANG_UNUSED (kernelCodes ); 1258return SLANG_OK ; 1259} 1260 1261bool ShaderProgramBase ::isMeshShaderProgram ()const 1262{ 1263// Similar to above, interrogate either explicity specified entry point 1264// componenets or the ones in the linked program entry point array 1265if (linkedEntryPoints .getCount ()) 1266 { 1267for (const auto & e :linkedEntryPoints ) 1268if (e -> getLayout ()-> getEntryPointByIndex (0 )-> getStage ()== SLANG_STAGE_MESH ) 1269return true; 1270 } 1271else 1272 { 1273const auto programReflection = linkedProgram -> getLayout (); 1274for (SlangUInt i = 0 ;i < programReflection -> getEntryPointCount ();++ i ) 1275if (programReflection -> getEntryPointByIndex (i )-> getStage ()== SLANG_STAGE_MESH ) 1276return true; 1277 } 1278return false; 1279} 1280 1281Result RendererBase ::maybeSpecializePipeline ( 1282PipelineStateBase * currentPipeline , 1283ShaderObjectBase * rootObject , 1284RefPtr < PipelineStateBase >& outNewPipeline ) 1285{ 1286outNewPipeline = static_cast < PipelineStateBase *> (currentPipeline ); 1287 1288auto pipelineType = currentPipeline -> desc .type ; 1289if (currentPipeline -> unspecializedPipelineState ) 1290currentPipeline = currentPipeline -> unspecializedPipelineState ; 1291// If the currently bound pipeline is specializable, we need to specialize it based on bound 1292// shader objects. 1293if (currentPipeline -> isSpecializable ) 1294 { 1295specializationArgs .clear (); 1296SLANG_RETURN_ON_FAIL (rootObject -> collectSpecializationArgs (specializationArgs )); 1297 1298// Construct a shader cache key that represents the specialized shader kernels. 1299PipelineKey pipelineKey ; 1300pipelineKey .pipeline = currentPipeline ; 1301pipelineKey .specializationArgs .addRange (specializationArgs .componentIDs ); 1302pipelineKey .updateHash (); 1303 1304RefPtr < PipelineStateBase > specializedPipelineState = 1305shaderCache .getSpecializedPipelineState (pipelineKey ); 1306// Try to find specialized pipeline from shader cache. 1307if (!specializedPipelineState ) 1308 { 1309auto unspecializedProgram = static_cast < ShaderProgramBase *> ( 1310pipelineType == PipelineType ::Compute ?currentPipeline -> desc .compute .program 1311 :currentPipeline -> desc .graphics .program ); 1312auto unspecializedProgramLayout = unspecializedProgram -> linkedProgram -> getLayout (); 1313 1314ComPtr < slang::IComponentType > specializedComponentType ; 1315ComPtr < slang::IBlob > diagnosticBlob ; 1316auto compileRs = unspecializedProgram -> linkedProgram -> specialize ( 1317specializationArgs .components .getArrayView ().getBuffer (), 1318specializationArgs .getCount (), 1319specializedComponentType .writeRef (), 1320diagnosticBlob .writeRef ()); 1321if (diagnosticBlob ) 1322 { 1323getDebugCallback ()-> handleMessage ( 1324compileRs == SLANG_OK ?DebugMessageType ::Warning :DebugMessageType ::Error , 1325DebugMessageSource ::Slang , 1326 (char * )diagnosticBlob -> getBufferPointer ()); 1327 } 1328SLANG_RETURN_ON_FAIL (compileRs ); 1329 1330// Now create the specialized shader program using compiled binaries. 1331ComPtr < IShaderProgram > specializedProgram ; 1332IShaderProgram ::Desc specializedProgramDesc = unspecializedProgram -> desc ; 1333specializedProgramDesc .slangGlobalScope = specializedComponentType ; 1334 1335if (specializedProgramDesc .linkingStyle == IShaderProgram ::LinkingStyle ::SingleProgram ) 1336 { 1337// When linking style is GraphicsCompute, the specialized global scope already 1338// contains entry-points, so we do not need to supply them again when creating the 1339// specialized pipeline. 1340specializedProgramDesc .entryPointCount = 0 ; 1341 } 1342SLANG_RETURN_ON_FAIL ( 1343createProgram (specializedProgramDesc ,specializedProgram .writeRef ())); 1344 1345// Create specialized pipeline state. 1346ComPtr < IPipelineState > specializedPipelineComPtr ; 1347switch (pipelineType ) 1348 { 1349case PipelineType ::Compute : 1350 { 1351auto pipelineDesc = currentPipeline -> desc .compute ; 1352pipelineDesc .program = specializedProgram ; 1353SLANG_RETURN_ON_FAIL (createComputePipelineState ( 1354pipelineDesc , 1355specializedPipelineComPtr .writeRef ())); 1356break ; 1357 } 1358case PipelineType ::Graphics : 1359 { 1360auto pipelineDesc = currentPipeline -> desc .graphics ; 1361pipelineDesc .program = 1362static_cast < ShaderProgramBase *> (specializedProgram .get ()); 1363SLANG_RETURN_ON_FAIL (createGraphicsPipelineState ( 1364pipelineDesc , 1365specializedPipelineComPtr .writeRef ())); 1366break ; 1367 } 1368case PipelineType ::RayTracing : 1369 { 1370auto pipelineDesc = currentPipeline -> desc .rayTracing ; 1371pipelineDesc .program = 1372static_cast < ShaderProgramBase *> (specializedProgram .get ()); 1373SLANG_RETURN_ON_FAIL (createRayTracingPipelineState ( 1374pipelineDesc .get (), 1375specializedPipelineComPtr .writeRef ())); 1376break ; 1377 } 1378default : 1379break ; 1380 } 1381specializedPipelineState = 1382static_cast < PipelineStateBase *> (specializedPipelineComPtr .get ()); 1383specializedPipelineState -> unspecializedPipelineState = currentPipeline ; 1384shaderCache .addSpecializedPipeline (pipelineKey ,specializedPipelineState ); 1385 } 1386auto specializedPipelineStateBase = 1387static_cast < PipelineStateBase *> (specializedPipelineState .Ptr ()); 1388outNewPipeline = specializedPipelineStateBase ; 1389 } 1390return SLANG_OK ; 1391} 1392 1393IDebugCallback *& _getDebugCallback () 1394{ 1395static IDebugCallback * callback = nullptr ; 1396return callback ; 1397} 1398 1399class NullDebugCallback :public IDebugCallback 1400{ 1401public : 1402virtual SLANG_NO_THROW void SLANG_MCALL 1403handleMessage (DebugMessageType type ,DebugMessageSource source ,const char * message )override 1404 { 1405SLANG_UNUSED (type ); 1406SLANG_UNUSED (source ); 1407SLANG_UNUSED (message ); 1408 } 1409}; 1410IDebugCallback * _getNullDebugCallback () 1411{ 1412static NullDebugCallback result = {}; 1413return & result ; 1414} 1415 1416Result ShaderObjectBase ::copyFrom (IShaderObject * object ,ITransientResourceHeap * transientHeap ) 1417{ 1418if (auto srcObj = dynamic_cast < MutableRootShaderObject *> (object )) 1419 { 1420setData ( 1421 gfx::ShaderOffset (), 1422srcObj -> m_data .begin (), 1423 (size_t )srcObj -> m_data .getCount ());// TODO: Change size_t to Count? 1424for (auto & kv :srcObj -> m_objects ) 1425 { 1426ComPtr < IShaderObject > subObject ; 1427SLANG_RETURN_ON_FAIL (kv .value -> getCurrentVersion (transientHeap ,subObject .writeRef ())); 1428setObject (kv .key ,subObject ); 1429 } 1430for (auto & kv :srcObj -> m_resources ) 1431 { 1432setResource (kv .key ,kv .value .Ptr ()); 1433 } 1434for (auto & kv :srcObj -> m_samplers ) 1435 { 1436setSampler (kv .key ,kv .value .Ptr ()); 1437 } 1438for (auto & kv :srcObj -> m_specializationArgs ) 1439 { 1440setSpecializationArgs (kv .key ,kv .value .begin (), (uint32_t )kv .value .getCount ()); 1441 } 1442return SLANG_OK ; 1443 } 1444return SLANG_FAIL ; 1445} 1446 1447Result ShaderTableBase ::init (const IShaderTable ::Desc & desc ) 1448{ 1449m_rayGenShaderCount = desc .rayGenShaderCount ; 1450m_missShaderCount = desc .missShaderCount ; 1451m_hitGroupCount = desc .hitGroupCount ; 1452m_callableShaderCount = desc .callableShaderCount ; 1453m_shaderGroupNames .reserve ( 1454desc .hitGroupCount + desc .missShaderCount + desc .rayGenShaderCount + 1455desc .callableShaderCount ); 1456m_recordOverwrites .reserve ( 1457desc .hitGroupCount + desc .missShaderCount + desc .rayGenShaderCount + 1458desc .callableShaderCount ); 1459for (GfxIndex i = 0 ;i < desc .rayGenShaderCount ;i ++ ) 1460 { 1461m_shaderGroupNames .add (desc .rayGenShaderEntryPointNames [i ]); 1462if (desc .rayGenShaderRecordOverwrites ) 1463 { 1464m_recordOverwrites .add (desc .rayGenShaderRecordOverwrites [i ]); 1465 } 1466else 1467 { 1468m_recordOverwrites .add (ShaderRecordOverwrite {}); 1469 } 1470 } 1471for (GfxIndex i = 0 ;i < desc .missShaderCount ;i ++ ) 1472 { 1473m_shaderGroupNames .add (desc .missShaderEntryPointNames [i ]); 1474if (desc .missShaderRecordOverwrites ) 1475 { 1476m_recordOverwrites .add (desc .missShaderRecordOverwrites [i ]); 1477 } 1478else 1479 { 1480m_recordOverwrites .add (ShaderRecordOverwrite {}); 1481 } 1482 } 1483for (GfxIndex i = 0 ;i < desc .hitGroupCount ;i ++ ) 1484 { 1485m_shaderGroupNames .add (desc .hitGroupNames [i ]); 1486if (desc .hitGroupRecordOverwrites ) 1487 { 1488m_recordOverwrites .add (desc .hitGroupRecordOverwrites [i ]); 1489 } 1490else 1491 { 1492m_recordOverwrites .add (ShaderRecordOverwrite {}); 1493 } 1494 } 1495for (GfxIndex i = 0 ;i < desc .callableShaderCount ;i ++ ) 1496 { 1497m_shaderGroupNames .add (desc .callableShaderEntryPointNames [i ]); 1498if (desc .callableShaderRecordOverwrites ) 1499 { 1500m_recordOverwrites .add (desc .callableShaderRecordOverwrites [i ]); 1501 } 1502else 1503 { 1504m_recordOverwrites .add (ShaderRecordOverwrite {}); 1505 } 1506 } 1507return SLANG_OK ; 1508} 1509 1510bool isDepthFormat (Format format ) 1511{ 1512switch (format ) 1513 { 1514case Format ::D16_UNORM : 1515case Format ::D32_FLOAT : 1516case Format ::D32_FLOAT_S8_UINT : 1517return true; 1518default : 1519return false; 1520 } 1521} 1522 1523bool isStencilFormat (Format format ) 1524{ 1525switch (format ) 1526 { 1527case Format ::D32_FLOAT_S8_UINT : 1528return true; 1529default : 1530return false; 1531 } 1532} 1533 1534}// namespace gfx