yum-mirror/slang
Making it easier to work with shaders
git clone https://git.yummers.dev/yum-mirror/slang
b118451e3
master
1// d3d12-shader-object.cpp 2#include "d3d12-shader-object.h" 3 4#include "d3d12-buffer.h" 5#include "d3d12-command-encoder.h" 6#include "d3d12-device.h" 7#include "d3d12-helper-functions.h" 8#include "d3d12-resource-views.h" 9#include "d3d12-sampler.h" 10#include "d3d12-shader-object-layout.h" 11#include "d3d12-transient-heap.h" 12 13namespace gfx 14{ 15namespace d3d12 16{ 17 18using namespace Slang ; 19 20GfxCount ShaderObjectImpl ::getEntryPointCount () 21{ 22return 0 ; 23} 24 25Result ShaderObjectImpl ::getEntryPoint (GfxIndex index ,IShaderObject ** outEntryPoint ) 26{ 27* outEntryPoint = nullptr ; 28return SLANG_OK ; 29} 30 31const void * ShaderObjectImpl ::getRawData () 32{ 33return m_data .getBuffer (); 34} 35 36Size ShaderObjectImpl ::getSize () 37{ 38return (Size )m_data .getCount (); 39} 40 41// TODO: Change Index to Offset/Size? 42Result ShaderObjectImpl ::setData (ShaderOffset const & inOffset ,void const * data ,size_t inSize ) 43{ 44Index offset = inOffset .uniformOffset ; 45Index size = inSize ; 46 47char * dest = m_data .getBuffer (); 48Index availableSize = m_data .getCount (); 49 50// TODO: We really should bounds-check access rather than silently ignoring sets 51// that are too large, but we have several test cases that set more data than 52// an object actually stores on several targets... 53// 54if (offset < 0 ) 55 { 56size += offset ; 57offset = 0 ; 58 } 59if ((offset + size ) >=availableSize ) 60 { 61size = availableSize - offset ; 62 } 63 64memcpy (dest + offset ,data ,size ); 65 66m_isConstantBufferDirty = true; 67 68m_version ++ ; 69 70return SLANG_OK ; 71} 72 73Result ShaderObjectImpl ::setObject (ShaderOffset const & offset ,IShaderObject * object ) 74{ 75SLANG_RETURN_ON_FAIL (Super ::setObject (offset ,object )); 76if (m_isMutable ) 77 { 78auto subObjectIndex = getSubObjectIndex (offset ); 79if (subObjectIndex >=m_subObjectVersions .getCount ()) 80m_subObjectVersions .setCount (subObjectIndex + 1 ); 81m_subObjectVersions [subObjectIndex ]= static_cast < ShaderObjectImpl *> (object )-> m_version ; 82m_version ++ ; 83 } 84return SLANG_OK ; 85} 86 87Result ShaderObjectImpl ::setSampler (ShaderOffset const & offset ,ISamplerState * sampler ) 88{ 89if (offset .bindingRangeIndex < 0 ) 90return SLANG_E_INVALID_ARG ; 91auto layout = getLayout (); 92if (offset .bindingRangeIndex >=layout -> getBindingRangeCount ()) 93return SLANG_E_INVALID_ARG ; 94auto & bindingRange = layout -> getBindingRange (offset .bindingRangeIndex ); 95auto samplerImpl = static_cast < SamplerStateImpl *> (sampler ); 96ID3D12Device * d3dDevice = static_cast < DeviceImpl *> (getDevice ())-> m_device ; 97d3dDevice -> CopyDescriptorsSimple ( 981 , 99m_descriptorSet .samplerTable .getCpuHandle ( 100bindingRange .baseIndex + (int32_t )offset .bindingArrayIndex ), 101samplerImpl -> m_descriptor .cpuHandle , 102D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER ); 103m_version ++ ; 104return SLANG_OK ; 105} 106 107Result ShaderObjectImpl ::setCombinedTextureSampler ( 108ShaderOffset const & offset , 109IResourceView * textureView , 110ISamplerState * sampler ) 111{ 112#if 0 113if (offset .bindingRangeIndex < 0 ) 114return SLANG_E_INVALID_ARG ; 115auto layout = getLayout (); 116if (offset .bindingRangeIndex >=layout -> getBindingRangeCount ()) 117return SLANG_E_INVALID_ARG ; 118auto & bindingRange = layout -> getBindingRange (offset .bindingRangeIndex ); 119auto resourceViewImpl = static_cast < ResourceViewImpl *> (textureView ); 120ID3D12Device * d3dDevice = static_cast < DeviceImpl *> (getDevice ())-> m_device ; 121d3dDevice -> CopyDescriptorsSimple ( 1221 , 123m_resourceHeap .getCpuHandle ( 124m_descriptorSet .m_resourceTable + 125bindingRange .binding .offsetInDescriptorTable .resource + 126 (int32_t )offset .bindingArrayIndex ), 127resourceViewImpl -> m_descriptor .cpuHandle , 128D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV ); 129auto samplerImpl = static_cast < SamplerStateImpl *> (sampler ); 130d3dDevice -> CopyDescriptorsSimple ( 1311 , 132m_samplerHeap .getCpuHandle ( 133m_descriptorSet .m_samplerTable + 134bindingRange .binding .offsetInDescriptorTable .sampler + 135 (int32_t )offset .bindingArrayIndex ), 136samplerImpl -> m_descriptor .cpuHandle , 137D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER ); 138#endif 139m_version ++ ; 140return SLANG_OK ; 141} 142 143Result ShaderObjectImpl ::init ( 144DeviceImpl * device , 145ShaderObjectLayoutImpl * layout , 146DescriptorHeapReference viewHeap , 147DescriptorHeapReference samplerHeap ) 148{ 149m_device = device ; 150 151m_layout = layout ; 152 153m_cachedTransientHeap = nullptr ; 154m_cachedTransientHeapVersion = 0 ; 155m_isConstantBufferDirty = true; 156 157// If the layout tells us that there is any uniform data, 158// then we will allocate a CPU memory buffer to hold that data 159// while it is being set from the host. 160// 161// Once the user is done setting the parameters/fields of this 162// shader object, we will produce a GPU-memory version of the 163// uniform data (which includes values from this object and 164// any existential-type sub-objects). 165// 166size_t uniformSize = layout -> getElementTypeLayout ()-> getSize (); 167if (uniformSize ) 168 { 169m_data .setCount (uniformSize ); 170memset (m_data .getBuffer (),0 ,uniformSize ); 171 } 172m_rootArguments .setCount (layout -> getOwnUserRootParameterCount ()); 173memset ( 174m_rootArguments .getBuffer (), 1750 , 176sizeof (D3D12_GPU_VIRTUAL_ADDRESS )* m_rootArguments .getCount ()); 177// Each shader object will own CPU descriptor heap memory 178// for any resource or sampler descriptors it might store 179// as part of its value. 180// 181// This allocate includes a reservation for any constant 182// buffer descriptor pertaining to the ordinary data, 183// but does *not* include any descriptors that are managed 184// as part of sub-objects. 185// 186if (auto resourceCount = layout -> getResourceSlotCount ()) 187 { 188m_descriptorSet .resourceTable .allocate (viewHeap ,resourceCount ); 189 190// We must also ensure that the memory for any resources 191// referenced by descriptors in this object does not get 192// freed while the object is still live. 193// 194// The doubling here is because any buffer resource could 195// have a counter buffer associated with it, which we 196// also need to ensure isn't destroyed prematurely. 197m_boundResources .setCount (resourceCount ); 198m_boundCounterResources .setCount (resourceCount ); 199 } 200if (auto samplerCount = layout -> getSamplerSlotCount ()) 201 { 202m_descriptorSet .samplerTable .allocate (samplerHeap ,samplerCount ); 203 } 204 205// If the layout specifies that we have any sub-objects, then 206// we need to size the array to account for them. 207// 208Index subObjectCount = layout -> getSubObjectSlotCount (); 209m_objects .setCount (subObjectCount ); 210 211for (auto subObjectRangeInfo :layout -> getSubObjectRanges ()) 212 { 213auto subObjectLayout = subObjectRangeInfo .layout ; 214 215// In the case where the sub-object range represents an 216// existential-type leaf field (e.g., an `IBar`), we 217// cannot pre-allocate the object(s) to go into that 218// range, since we can't possibly know what to allocate 219// at this point. 220// 221if (!subObjectLayout ) 222continue ; 223// 224// Otherwise, we will allocate a sub-object to fill 225// in each entry in this range, based on the layout 226// information we already have. 227 228auto & bindingRangeInfo = layout -> getBindingRange (subObjectRangeInfo .bindingRangeIndex ); 229for (uint32_t i = 0 ;i < bindingRangeInfo .count ;++ i ) 230 { 231RefPtr < ShaderObjectImpl > subObject ; 232SLANG_RETURN_ON_FAIL ( 233ShaderObjectImpl ::create (device ,subObjectLayout ,subObject .writeRef ())); 234m_objects [bindingRangeInfo .subObjectIndex + i ]= subObject ; 235 } 236 } 237 238return SLANG_OK ; 239} 240 241/// Write the uniform/ordinary data of this object into the given `dest` buffer at the given 242/// `offset` 243 244Result ShaderObjectImpl ::_writeOrdinaryData ( 245PipelineCommandEncoder * encoder , 246BufferResourceImpl * buffer , 247Offset offset , 248Size destSize , 249ShaderObjectLayoutImpl * specializedLayout ) 250{ 251auto src = m_data .getBuffer (); 252auto srcSize = Size (m_data .getCount ()); 253 254SLANG_ASSERT (srcSize <=destSize ); 255 256uploadBufferDataImpl ( 257encoder -> m_device , 258encoder -> m_d3dCmdList , 259encoder -> m_transientHeap , 260buffer , 261offset , 262srcSize , 263src ); 264 265// In the case where this object has any sub-objects of 266// existential/interface type, we need to recurse on those objects 267// that need to write their state into an appropriate "pending" allocation. 268// 269// Note: Any values that could fit into the "payload" included 270// in the existential-type field itself will have already been 271// written as part of `setObject()`. This loop only needs to handle 272// those sub-objects that do not "fit." 273// 274// An implementers looking at this code might wonder if things could be changed 275// so that *all* writes related to sub-objects for interface-type fields could 276// be handled in this one location, rather than having some in `setObject()` and 277// others handled here. 278// 279Index subObjectRangeCounter = 0 ; 280for (auto const & subObjectRangeInfo :specializedLayout -> getSubObjectRanges ()) 281 { 282Index subObjectRangeIndex = subObjectRangeCounter ++ ; 283auto const & bindingRangeInfo = 284specializedLayout -> getBindingRange (subObjectRangeInfo .bindingRangeIndex ); 285 286// We only need to handle sub-object ranges for interface/existential-type fields, 287// because fields of constant-buffer or parameter-block type are responsible for 288// the ordinary/uniform data of their own existential/interface-type sub-objects. 289// 290if (bindingRangeInfo .bindingType != slang::BindingType ::ExistentialValue ) 291continue ; 292 293// Each sub-object range represents a single "leaf" field, but might be nested 294// under zero or more outer arrays, such that the number of existential values 295// in the same range can be one or more. 296// 297auto count = bindingRangeInfo .count ; 298 299// We are not concerned with the case where the existential value(s) in the range 300// git into the payload part of the leaf field. 301// 302// In the case where the value didn't fit, the Slang layout strategy would have 303// considered the requirements of the value as a "pending" allocation, and would 304// allocate storage for the ordinary/uniform part of that pending allocation inside 305// of the parent object's type layout. 306// 307// Here we assume that the Slang reflection API can provide us with a single byte 308// offset and stride for the location of the pending data allocation in the 309// specialized type layout, which will store the values for this sub-object range. 310// 311// TODO: The reflection API functions we are assuming here haven't been implemented 312// yet, so the functions being called here are stubs. 313// 314// TODO: It might not be that a single sub-object range can reliably map to a single 315// contiguous array with a single stride; we need to carefully consider what the 316// layout logic does for complex cases with multiple layers of nested arrays and 317// structures. 318// 319Offset subObjectRangePendingDataOffset = subObjectRangeInfo .offset .pendingOrdinaryData ; 320Size subObjectRangePendingDataStride = subObjectRangeInfo .stride .pendingOrdinaryData ; 321 322// If the range doesn't actually need/use the "pending" allocation at all, then 323// we need to detect that case and skip such ranges. 324// 325// TODO: This should probably be handled on a per-object basis by caching a "does it 326// fit?" bit as part of the information for bound sub-objects, given that we already 327// compute the "does it fit?" status as part of `setObject()`. 328// 329if (subObjectRangePendingDataOffset == 0 ) 330continue ; 331 332for (uint32_t i = 0 ;i < count ;++ i ) 333 { 334auto subObject = m_objects [bindingRangeInfo .subObjectIndex + i ]; 335 336RefPtr < ShaderObjectLayoutImpl > subObjectLayout ; 337SLANG_RETURN_ON_FAIL (subObject -> getSpecializedLayout (subObjectLayout .writeRef ())); 338 339auto subObjectOffset = 340subObjectRangePendingDataOffset + i * subObjectRangePendingDataStride ; 341 342subObject -> _writeOrdinaryData ( 343encoder , 344buffer , 345offset + subObjectOffset , 346destSize - subObjectOffset , 347subObjectLayout ); 348 } 349 } 350 351return SLANG_OK ; 352} 353 354bool ShaderObjectImpl ::shouldAllocateConstantBuffer (TransientResourceHeapImpl * transientHeap ) 355{ 356if (m_isConstantBufferDirty || m_cachedTransientHeap != transientHeap || 357m_cachedTransientHeapVersion != transientHeap -> getVersion ()) 358 { 359return true; 360 } 361return false; 362} 363 364/// Ensure that the `m_ordinaryDataBuffer` has been created, if it is needed 365 366Result ShaderObjectImpl ::_ensureOrdinaryDataBufferCreatedIfNeeded ( 367PipelineCommandEncoder * encoder , 368ShaderObjectLayoutImpl * specializedLayout ) 369{ 370// If data has been changed since last allocation/filling of constant buffer, 371// we will need to allocate a new one. 372// 373if (!shouldAllocateConstantBuffer (encoder -> m_transientHeap )) 374 { 375return SLANG_OK ; 376 } 377m_isConstantBufferDirty = false; 378m_cachedTransientHeap = encoder -> m_transientHeap ; 379m_cachedTransientHeapVersion = encoder -> m_transientHeap -> getVersion (); 380 381// Computing the size of the ordinary data buffer is *not* just as simple 382// as using the size of the `m_ordinayData` array that we store. The reason 383// for the added complexity is that interface-type fields may lead to the 384// storage being specialized such that it needs extra appended data to 385// store the concrete values that logically belong in those interface-type 386// fields but wouldn't fit in the fixed-size allocation we gave them. 387// 388m_constantBufferSize = specializedLayout -> getTotalOrdinaryDataSize (); 389if (m_constantBufferSize == 0 ) 390 { 391return SLANG_OK ; 392 } 393 394// Once we have computed how large the buffer should be, we can allocate 395// it from the transient resource heap. 396// 397auto alignedConstantBufferSize = D3DUtil ::calcAligned (m_constantBufferSize ,256 ); 398SLANG_RETURN_ON_FAIL (encoder -> m_commandBuffer -> m_transientHeap -> allocateConstantBuffer ( 399alignedConstantBufferSize , 400m_constantBufferWeakPtr , 401m_constantBufferOffset )); 402 403// Once the buffer is allocated, we can use `_writeOrdinaryData` to fill it in. 404// 405// Note that `_writeOrdinaryData` is potentially recursive in the case 406// where this object contains interface/existential-type fields, so we 407// don't need or want to inline it into this call site. 408// 409SLANG_RETURN_ON_FAIL (_writeOrdinaryData ( 410encoder , 411static_cast < BufferResourceImpl *> (m_constantBufferWeakPtr ), 412m_constantBufferOffset , 413m_constantBufferSize , 414specializedLayout )); 415 416 { 417// We also create and store a descriptor for our root constant buffer 418// into the descriptor table allocation that was reserved for them. 419// 420// We always know that the ordinary data buffer will be the first descriptor 421// in the table of resource views. 422// 423auto descriptorTable = m_descriptorSet .resourceTable ; 424D3D12_CONSTANT_BUFFER_VIEW_DESC viewDesc = {}; 425viewDesc .BufferLocation = static_cast < BufferResourceImpl *> (m_constantBufferWeakPtr ) 426-> m_resource .getResource () 427-> GetGPUVirtualAddress ()+ 428m_constantBufferOffset ; 429viewDesc .SizeInBytes = (UINT )alignedConstantBufferSize ; 430encoder -> m_device -> CreateConstantBufferView (& viewDesc ,descriptorTable .getCpuHandle ()); 431 } 432 433return SLANG_OK ; 434} 435 436void ShaderObjectImpl ::updateSubObjectsRecursive () 437{ 438if (!m_isMutable ) 439return ; 440auto & subObjectRanges = getLayout ()-> getSubObjectRanges (); 441for (Slang ::Index subObjectRangeIndex = 0 ;subObjectRangeIndex < subObjectRanges .getCount (); 442subObjectRangeIndex ++ ) 443 { 444auto const & subObjectRange = subObjectRanges [subObjectRangeIndex ]; 445auto const & bindingRange = getLayout ()-> getBindingRange (subObjectRange .bindingRangeIndex ); 446Slang ::Index count = bindingRange .count ; 447 448for (Slang ::Index subObjectIndexInRange = 0 ;subObjectIndexInRange < count ; 449subObjectIndexInRange ++ ) 450 { 451Slang ::Index objectIndex = bindingRange .subObjectIndex + subObjectIndexInRange ; 452auto subObject = m_objects [objectIndex ].Ptr (); 453if (!subObject ) 454continue ; 455subObject -> updateSubObjectsRecursive (); 456if (m_subObjectVersions .getCount ()> objectIndex && 457m_subObjectVersions [objectIndex ]!= m_objects [objectIndex ]-> m_version ) 458 { 459ShaderOffset offset ; 460offset .bindingRangeIndex = (GfxIndex )subObjectRange .bindingRangeIndex ; 461offset .bindingArrayIndex = (GfxIndex )subObjectIndexInRange ; 462setObject (offset ,subObject ); 463 } 464 } 465 } 466} 467 468static void bindPendingTables (BindingContext * context ) 469{ 470for (auto & binding :* context -> pendingTableBindings ) 471 { 472context -> submitter -> setRootDescriptorTable (binding .rootIndex ,binding .handle ); 473 } 474} 475 476/// Prepare to bind this object as a parameter block. 477/// 478/// This involves allocating and binding any descriptor tables necessary 479/// to to store the state of the object. The function returns a descriptor 480/// set formed from any table(s) allocated. In addition, the `ioOffset` 481/// parameter will be adjusted to be correct for binding values into 482/// the resulting descriptor set. 483/// 484/// Returns: 485/// SLANG_OK when successful, 486/// SLANG_E_OUT_OF_MEMORY when descriptor heap is full. 487/// 488 489Result ShaderObjectImpl ::prepareToBindAsParameterBlock ( 490BindingContext * context , 491BindingOffset & ioOffset , 492ShaderObjectLayoutImpl * specializedLayout , 493DescriptorSet & outDescriptorSet ) 494{ 495auto transientHeap = context -> transientHeap ; 496auto submitter = context -> submitter ; 497 498// When writing into the new descriptor set, resource and sampler 499// descriptors will need to start at index zero in the respective 500// tables. 501// 502ioOffset .resource = 0 ; 503ioOffset .sampler = 0 ; 504 505// The index of the next root parameter to bind will be maintained, 506// but needs to be incremented by the number of descriptor tables 507// we allocate (zero or one resource table and zero or one sampler 508// table). 509// 510auto & rootParamIndex = ioOffset .rootParam ; 511 512if (auto descriptorCount = specializedLayout -> getTotalResourceDescriptorCount ()) 513 { 514// There is a non-zero number of resource descriptors needed, 515// so we will allocate a table out of the appropriate heap, 516// and store it into the appropriate part of `descriptorSet`. 517// 518auto descriptorHeap = & transientHeap -> getCurrentViewHeap (); 519auto & table = outDescriptorSet .resourceTable ; 520 521// Allocate the table. 522// 523if (!table .allocate (descriptorHeap ,descriptorCount )) 524 { 525context -> outOfMemoryHeap = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV ; 526return SLANG_E_OUT_OF_MEMORY ; 527 } 528 529// Bind the table to the pipeline, consuming the next available 530// root parameter. 531// 532auto tableRootParamIndex = rootParamIndex ++ ; 533context -> pendingTableBindings -> add ( 534PendingDescriptorTableBinding {tableRootParamIndex ,table .getGpuHandle ()}); 535 } 536if (auto descriptorCount = specializedLayout -> getTotalSamplerDescriptorCount ()) 537 { 538// There is a non-zero number of sampler descriptors needed, 539// so we will allocate a table out of the appropriate heap, 540// and store it into the appropriate part of `descriptorSet`. 541// 542auto descriptorHeap = & transientHeap -> getCurrentSamplerHeap (); 543auto & table = outDescriptorSet .samplerTable ; 544 545// Allocate the table. 546// 547if (!table .allocate (descriptorHeap ,descriptorCount )) 548 { 549context -> outOfMemoryHeap = D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER ; 550return SLANG_E_OUT_OF_MEMORY ; 551 } 552 553// Bind the table to the pipeline, consuming the next available 554// root parameter. 555// 556auto tableRootParamIndex = rootParamIndex ++ ; 557context -> pendingTableBindings -> add ( 558PendingDescriptorTableBinding {tableRootParamIndex ,table .getGpuHandle ()}); 559 } 560 561return SLANG_OK ; 562} 563 564bool ShaderObjectImpl ::checkIfCachedDescriptorSetIsValidRecursive (BindingContext * context ) 565{ 566if (shouldAllocateConstantBuffer (context -> transientHeap )) 567return false; 568if (m_isMutable && m_version != m_cachedGPUDescriptorSetVersion ) 569return false; 570if (m_cachedGPUDescriptorSet .resourceTable .getDescriptorCount ()!= 0 && 571m_cachedGPUDescriptorSet .resourceTable .m_heap .ptr .linearHeap -> getHeap ()!= 572m_cachedTransientHeap -> getCurrentViewHeap ().getHeap ()) 573return false; 574if (m_cachedGPUDescriptorSet .samplerTable .getDescriptorCount ()!= 0 && 575m_cachedGPUDescriptorSet .samplerTable .m_heap .ptr .linearHeap -> getHeap ()!= 576m_cachedTransientHeap -> getCurrentSamplerHeap ().getHeap ()) 577return false; 578 579auto & subObjectRanges = getLayout ()-> getSubObjectRanges (); 580for (Slang ::Index subObjectRangeIndex = 0 ;subObjectRangeIndex < subObjectRanges .getCount (); 581subObjectRangeIndex ++ ) 582 { 583auto const & subObjectRange = subObjectRanges [subObjectRangeIndex ]; 584auto const & bindingRange = getLayout ()-> getBindingRange (subObjectRange .bindingRangeIndex ); 585if (bindingRange .bindingType != slang::BindingType ::ParameterBlock ) 586continue ; 587Slang ::Index count = bindingRange .count ; 588 589for (Slang ::Index subObjectIndexInRange = 0 ;subObjectIndexInRange < count ; 590subObjectIndexInRange ++ ) 591 { 592Slang ::Index objectIndex = bindingRange .subObjectIndex + subObjectIndexInRange ; 593auto subObject = m_objects [objectIndex ].Ptr (); 594if (!subObject ) 595continue ; 596if (subObject -> checkIfCachedDescriptorSetIsValidRecursive (context )) 597return false; 598 } 599 } 600return true; 601} 602 603/// Bind this object as a `ParameterBlock<X>` 604 605Result ShaderObjectImpl ::bindAsParameterBlock ( 606BindingContext * context , 607BindingOffset const & offset , 608ShaderObjectLayoutImpl * specializedLayout ) 609{ 610if (checkIfCachedDescriptorSetIsValidRecursive (context )) 611 { 612// If we already have a valid gpu descriptor table in the current 613// heap, bind it. 614auto rootParamIndex = offset .rootParam ; 615if (m_cachedGPUDescriptorSet .resourceTable .getDescriptorCount ()) 616 { 617auto tableRootParamIndex = rootParamIndex ++ ; 618context -> submitter -> setRootDescriptorTable ( 619tableRootParamIndex , 620m_cachedGPUDescriptorSet .resourceTable .getGpuHandle ()); 621 } 622if (m_cachedGPUDescriptorSet .samplerTable .getDescriptorCount ()) 623 { 624auto tableRootParamIndex = rootParamIndex ++ ; 625context -> submitter -> setRootDescriptorTable ( 626tableRootParamIndex , 627m_cachedGPUDescriptorSet .samplerTable .getGpuHandle ()); 628 } 629return SLANG_OK ; 630 } 631 632// The first step to binding an object as a parameter block is to allocate a descriptor 633// set (consisting of zero or one resource descriptor table and zero or one sampler 634// descriptor table) to represent its values. 635// 636BindingOffset subOffset = offset ; 637ShortList < PendingDescriptorTableBinding > pendingTableBindings ; 638auto oldPendingTableBindings = context -> pendingTableBindings ; 639context -> pendingTableBindings = & pendingTableBindings ; 640 641SLANG_RETURN_ON_FAIL (prepareToBindAsParameterBlock ( 642context , 643/* inout */ subOffset , 644specializedLayout , 645m_cachedGPUDescriptorSet )); 646 647// Next we bind the object into that descriptor set as if it were being used 648// as a `ConstantBuffer<X>`. 649// 650SLANG_RETURN_ON_FAIL ( 651bindAsConstantBuffer (context ,m_cachedGPUDescriptorSet ,subOffset ,specializedLayout )); 652 653bindPendingTables (context ); 654context -> pendingTableBindings = oldPendingTableBindings ; 655 656m_cachedGPUDescriptorSetVersion = m_version ; 657return SLANG_OK ; 658} 659 660/// Bind this object as a `ConstantBuffer<X>` 661 662Result ShaderObjectImpl ::bindAsConstantBuffer ( 663BindingContext * context , 664DescriptorSet const & descriptorSet , 665BindingOffset const & offset , 666ShaderObjectLayoutImpl * specializedLayout ) 667{ 668// If we are to bind as a constant buffer we first need to ensure that 669// the ordinary data buffer is created, if this object needs one. 670// 671SLANG_RETURN_ON_FAIL ( 672_ensureOrdinaryDataBufferCreatedIfNeeded (context -> encoder ,specializedLayout )); 673 674// Next, we need to bind all of the resource descriptors for this object 675// (including any ordinary data buffer) into the provided `descriptorSet`. 676// 677auto resourceCount = specializedLayout -> getResourceSlotCount (); 678if (resourceCount ) 679 { 680auto & dstTable = descriptorSet .resourceTable ; 681auto & srcTable = m_descriptorSet .resourceTable ; 682 683context -> device -> m_device -> CopyDescriptorsSimple ( 684UINT (resourceCount ), 685dstTable .getCpuHandle (offset .resource ), 686srcTable .getCpuHandle (), 687D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV ); 688 } 689 690// Finally, we delegate to `_bindImpl` to bind samplers and sub-objects, 691// since the logic is shared with the `bindAsValue()` case below. 692// 693SLANG_RETURN_ON_FAIL (_bindImpl (context ,descriptorSet ,offset ,specializedLayout )); 694return SLANG_OK ; 695} 696 697/// Bind this object as a value (for an interface-type parameter) 698 699Result ShaderObjectImpl ::bindAsValue ( 700BindingContext * context , 701DescriptorSet const & descriptorSet , 702BindingOffset const & offset , 703ShaderObjectLayoutImpl * specializedLayout ) 704{ 705// When binding a value for an interface-type field we do *not* want 706// to bind a buffer for the ordinary data (if there is any) because 707// ordinary data for interface-type fields gets allocated into the 708// parent object's ordinary data buffer. 709// 710// This CPU-memory descriptor table that holds resource descriptors 711// will have already been allocated to have space for an ordinary data 712// buffer (if needed), so we need to take care to skip over that 713// descriptor when copying descriptors from the CPU-memory set 714// to the GPU-memory `descriptorSet`. 715// 716auto skipResourceCount = specializedLayout -> getOrdinaryDataBufferCount (); 717auto resourceCount = specializedLayout -> getResourceSlotCount ()- skipResourceCount ; 718if (resourceCount ) 719 { 720auto & dstTable = descriptorSet .resourceTable ; 721auto & srcTable = m_descriptorSet .resourceTable ; 722 723context -> device -> m_device -> CopyDescriptorsSimple ( 724UINT (resourceCount ), 725dstTable .getCpuHandle (offset .resource ), 726srcTable .getCpuHandle (skipResourceCount ), 727D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV ); 728 } 729 730// Finally, we delegate to `_bindImpl` to bind samplers and sub-objects, 731// since the logic is shared with the `bindAsConstantBuffer()` case above. 732// 733// Note: Just like we had to do some subtle handling of the ordinary data buffer 734// above, here we need to contend with the fact that the `offset.resource` fields 735// computed for sub-object ranges were baked to take the ordinary data buffer 736// into account, so that if `skipResourceCount` is non-zero then they are all 737// too high by `skipResourceCount`. 738// 739// We will address the problem here by computing a modified offset that adjusts 740// for the ordinary data buffer that we have not bound after all. 741// 742BindingOffset subOffset = offset ; 743subOffset .resource -= skipResourceCount ; 744SLANG_RETURN_ON_FAIL (_bindImpl (context ,descriptorSet ,subOffset ,specializedLayout )); 745return SLANG_OK ; 746} 747 748/// Shared logic for `bindAsConstantBuffer()` and `bindAsValue()` 749 750Result ShaderObjectImpl ::_bindImpl ( 751BindingContext * context , 752DescriptorSet const & descriptorSet , 753BindingOffset const & offset , 754ShaderObjectLayoutImpl * specializedLayout ) 755{ 756// We start by binding all the sampler decriptors, if needed. 757// 758// Note: resource descriptors were handled in either `bindAsConstantBuffer()` 759// or `bindAsValue()` before calling into `_bindImpl()`. 760// 761if (auto samplerCount = specializedLayout -> getSamplerSlotCount ()) 762 { 763auto & dstTable = descriptorSet .samplerTable ; 764auto & srcTable = m_descriptorSet .samplerTable ; 765 766context -> device -> m_device -> CopyDescriptorsSimple ( 767UINT (samplerCount ), 768dstTable .getCpuHandle (offset .sampler ), 769srcTable .getCpuHandle (), 770D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER ); 771 } 772 773// Next we iterate over the sub-object ranges and bind anything they require. 774// 775auto & subObjectRanges = specializedLayout -> getSubObjectRanges (); 776auto subObjectRangeCount = subObjectRanges .getCount (); 777for (Index i = 0 ;i < subObjectRangeCount ;i ++ ) 778 { 779auto & subObjectRange = specializedLayout -> getSubObjectRange (i ); 780auto & bindingRange = specializedLayout -> getBindingRange (subObjectRange .bindingRangeIndex ); 781auto subObjectIndex = bindingRange .subObjectIndex ; 782auto subObjectLayout = subObjectRange .layout .Ptr (); 783 784BindingOffset rangeOffset = offset ; 785rangeOffset += subObjectRange .offset ; 786 787BindingOffset rangeStride = subObjectRange .stride ; 788 789switch (bindingRange .bindingType ) 790 { 791case slang::BindingType ::ConstantBuffer : 792 { 793auto objOffset = rangeOffset ; 794for (uint32_t j = 0 ;j < bindingRange .count ;j ++ ) 795 { 796auto & object = m_objects [subObjectIndex + j ]; 797SLANG_RETURN_ON_FAIL (object -> bindAsConstantBuffer ( 798context , 799descriptorSet , 800objOffset , 801subObjectLayout )); 802objOffset += rangeStride ; 803 } 804 } 805break ; 806 807case slang::BindingType ::ParameterBlock : 808 { 809auto objOffset = rangeOffset ; 810for (uint32_t j = 0 ;j < bindingRange .count ;j ++ ) 811 { 812auto & object = m_objects [subObjectIndex + j ]; 813SLANG_RETURN_ON_FAIL ( 814object -> bindAsParameterBlock (context ,objOffset ,subObjectLayout )); 815objOffset += rangeStride ; 816 } 817 } 818break ; 819 820case slang::BindingType ::ExistentialValue : 821if (subObjectLayout ) 822 { 823auto objOffset = rangeOffset ; 824for (uint32_t j = 0 ;j < bindingRange .count ;j ++ ) 825 { 826auto & object = m_objects [subObjectIndex + j ]; 827SLANG_RETURN_ON_FAIL ( 828object -> bindAsValue (context ,descriptorSet ,objOffset ,subObjectLayout )); 829objOffset += rangeStride ; 830 } 831 } 832break ; 833 } 834 } 835 836return SLANG_OK ; 837} 838 839Result ShaderObjectImpl ::bindRootArguments (BindingContext * context ,uint32_t & index ) 840{ 841auto layoutImpl = getLayout (); 842for (Index i = 0 ;i < m_rootArguments .getCount ();i ++ ) 843 { 844switch (layoutImpl -> getRootParameterInfo (i ).type ) 845 { 846case IResourceView ::Type ::ShaderResource : 847case IResourceView ::Type ::AccelerationStructure : 848context -> submitter -> setRootSRV (index ,m_rootArguments [i ]); 849break ; 850case IResourceView ::Type ::UnorderedAccess : 851context -> submitter -> setRootUAV (index ,m_rootArguments [i ]); 852break ; 853default : 854continue ; 855 } 856index ++ ; 857 } 858for (auto & subObject :m_objects ) 859 { 860if (subObject ) 861 { 862SLANG_RETURN_ON_FAIL (subObject -> bindRootArguments (context ,index )); 863 } 864 } 865return SLANG_OK ; 866} 867 868/// Get the layout of this shader object with specialization arguments considered 869/// 870/// This operation should only be called after the shader object has been 871/// fully filled in and finalized. 872/// 873 874Result ShaderObjectImpl ::getSpecializedLayout (ShaderObjectLayoutImpl ** outLayout ) 875{ 876if (!m_specializedLayout ) 877 { 878SLANG_RETURN_ON_FAIL (_createSpecializedLayout (m_specializedLayout .writeRef ())); 879 } 880returnRefPtr (outLayout ,m_specializedLayout ); 881return SLANG_OK ; 882} 883 884/// Create the layout for this shader object with specialization arguments considered 885/// 886/// This operation is virtual so that it can be customized by `RootShaderObject`. 887/// 888 889Result ShaderObjectImpl ::_createSpecializedLayout (ShaderObjectLayoutImpl ** outLayout ) 890{ 891ExtendedShaderObjectType extendedType ; 892SLANG_RETURN_ON_FAIL (getSpecializedShaderObjectType (& extendedType )); 893 894auto renderer = getRenderer (); 895RefPtr < ShaderObjectLayoutImpl > layout ; 896SLANG_RETURN_ON_FAIL (renderer -> getShaderObjectLayout ( 897m_layout -> m_slangSession , 898extendedType .slangType , 899m_layout -> getContainerType (), 900 (ShaderObjectLayoutBase ** )layout .writeRef ())); 901 902returnRefPtrMove (outLayout ,layout ); 903return SLANG_OK ; 904} 905 906Result ShaderObjectImpl ::setResource (ShaderOffset const & offset ,IResourceView * resourceView ) 907{ 908if (offset .bindingRangeIndex < 0 ) 909return SLANG_E_INVALID_ARG ; 910auto layout = getLayout (); 911if (offset .bindingRangeIndex >=layout -> getBindingRangeCount ()) 912return SLANG_E_INVALID_ARG ; 913 914m_version ++ ; 915 916ID3D12Device * d3dDevice = static_cast < DeviceImpl *> (getDevice ())-> m_device ; 917 918auto & bindingRange = layout -> getBindingRange (offset .bindingRangeIndex ); 919 920if (bindingRange .isRootParameter && resourceView ) 921 { 922auto & rootArg = m_rootArguments [bindingRange .baseIndex ]; 923switch (resourceView -> getViewDesc ()-> type ) 924 { 925case IResourceView ::Type ::AccelerationStructure : 926 { 927auto resourceViewImpl = static_cast < AccelerationStructureImpl *> (resourceView ); 928rootArg = resourceViewImpl -> getDeviceAddress (); 929 } 930break ; 931case IResourceView ::Type ::ShaderResource : 932case IResourceView ::Type ::UnorderedAccess : 933 { 934auto resourceViewImpl = static_cast < ResourceViewImpl *> (resourceView ); 935if (resourceViewImpl -> m_resource -> isBuffer ()) 936 { 937rootArg = static_cast < BufferResourceImpl *> (resourceViewImpl -> m_resource .Ptr ()) 938-> getDeviceAddress (); 939 } 940else 941 { 942getDebugCallback ()-> handleMessage ( 943DebugMessageType ::Error , 944DebugMessageSource ::Layer , 945"The shader parameter at the specified offset is a root parameter, and " 946"therefore can only be a buffer view." ); 947return SLANG_FAIL ; 948 } 949 } 950break ; 951 } 952return SLANG_OK ; 953 } 954 955if (resourceView == nullptr ) 956 { 957if (!bindingRange .isRootParameter ) 958 { 959// Create null descriptor for the binding. 960auto destDescriptor = m_descriptorSet .resourceTable .getCpuHandle ( 961bindingRange .baseIndex + (int32_t )offset .bindingArrayIndex ); 962return createNullDescriptor (d3dDevice ,destDescriptor ,bindingRange ); 963 } 964return SLANG_OK ; 965 } 966 967ResourceViewInternalImpl * internalResourceView = nullptr ; 968auto resourceViewImpl = static_cast < ResourceViewImpl *> (resourceView ); 969 970switch (resourceView -> getViewDesc ()-> type ) 971 { 972#if SLANG_GFX_HAS_DXR_SUPPORT 973case IResourceView ::Type ::AccelerationStructure : 974 { 975auto asImpl = static_cast < AccelerationStructureImpl *> (resourceView ); 976// Hold a reference to the resource to prevent its destruction. 977m_boundResources [bindingRange .baseIndex + offset .bindingArrayIndex ]= asImpl -> m_buffer ; 978internalResourceView = asImpl ; 979 } 980break ; 981#endif 982default : 983 { 984// Hold a reference to the resource to prevent its destruction. 985const auto resourceOffset = bindingRange .baseIndex + offset .bindingArrayIndex ; 986m_boundResources [resourceOffset ]= resourceViewImpl -> m_resource ; 987m_boundCounterResources [resourceOffset ]= resourceViewImpl -> m_counterResource ; 988internalResourceView = resourceViewImpl ; 989 } 990break ; 991 } 992 993auto descriptorSlotIndex = bindingRange .baseIndex + (int32_t )offset .bindingArrayIndex ; 994D3D12Descriptor srcDescriptor = internalResourceView -> m_descriptor ; 995 996// Buffer descriptors are created on demand. 997if (!srcDescriptor .cpuHandle .ptr ) 998 { 999SLANG_RETURN_ON_FAIL (internalResourceView -> getBufferDescriptorForBinding ( 1000static_cast < DeviceImpl *> (m_device .get ()), 1001resourceViewImpl , 1002bindingRange .bufferElementStride , 1003srcDescriptor )); 1004 } 1005 1006if (srcDescriptor .cpuHandle .ptr ) 1007 { 1008d3dDevice -> CopyDescriptorsSimple ( 10091 , 1010m_descriptorSet .resourceTable .getCpuHandle ( 1011bindingRange .baseIndex + (int32_t )offset .bindingArrayIndex ), 1012srcDescriptor .cpuHandle , 1013D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV ); 1014 } 1015else 1016 { 1017getDebugCallback ()-> handleMessage ( 1018DebugMessageType ::Error , 1019DebugMessageSource ::Layer , 1020"IShaderObject::setResource: the resource view cannot be set to this shader parameter. " 1021"A possible reason is that the view is too large to be supported by D3D12." ); 1022return SLANG_FAIL ; 1023 } 1024return SLANG_OK ; 1025} 1026 1027Result ShaderObjectImpl ::create ( 1028DeviceImpl * device , 1029ShaderObjectLayoutImpl * layout , 1030ShaderObjectImpl ** outShaderObject ) 1031{ 1032auto object = RefPtr < ShaderObjectImpl > (new ShaderObjectImpl ()); 1033SLANG_RETURN_ON_FAIL ( 1034object -> init (device ,layout ,device -> m_cpuViewHeap .Ptr (),device -> m_cpuSamplerHeap .Ptr ())); 1035returnRefPtrMove (outShaderObject ,object ); 1036return SLANG_OK ; 1037} 1038 1039ShaderObjectImpl ::~ShaderObjectImpl () 1040{ 1041m_descriptorSet .freeIfSupported (); 1042} 1043 1044RootShaderObjectLayoutImpl * RootShaderObjectImpl ::getLayout () 1045{ 1046return static_cast < RootShaderObjectLayoutImpl *> (m_layout .Ptr ()); 1047} 1048 1049GfxCount RootShaderObjectImpl ::getEntryPointCount () 1050{ 1051return (GfxCount )m_entryPoints .getCount (); 1052} 1053 1054SlangResult RootShaderObjectImpl ::getEntryPoint (GfxIndex index ,IShaderObject ** outEntryPoint ) 1055{ 1056returnComPtr (outEntryPoint ,m_entryPoints [index ]); 1057return SLANG_OK ; 1058} 1059 1060Result RootShaderObjectImpl ::collectSpecializationArgs (ExtendedShaderObjectTypeList & args ) 1061{ 1062SLANG_RETURN_ON_FAIL (ShaderObjectImpl ::collectSpecializationArgs (args )); 1063for (auto & entryPoint :m_entryPoints ) 1064 { 1065SLANG_RETURN_ON_FAIL (entryPoint -> collectSpecializationArgs (args )); 1066 } 1067return SLANG_OK ; 1068} 1069 1070Result RootShaderObjectImpl ::_createSpecializedLayout (ShaderObjectLayoutImpl ** outLayout ) 1071{ 1072ExtendedShaderObjectTypeList specializationArgs ; 1073SLANG_RETURN_ON_FAIL (collectSpecializationArgs (specializationArgs )); 1074 1075// Note: There is an important policy decision being made here that we need 1076// to approach carefully. 1077// 1078// We are doing two different things that affect the layout of a program: 1079// 1080// 1. We are *composing* one or more pieces of code (notably the shared global/module 1081// stuff and the per-entry-point stuff). 1082// 1083// 2. We are *specializing* code that includes generic/existential parameters 1084// to concrete types/values. 1085// 1086// We need to decide the relative *order* of these two steps, because of how it impacts 1087// layout. The layout for `specialize(compose(A,B), X, Y)` is potentially different 1088// form that of `compose(specialize(A,X), speciealize(B,Y))`, even when both are 1089// semantically equivalent programs. 1090// 1091// Right now we are using the first option: we are first generating a full composition 1092// of all the code we plan to use (global scope plus all entry points), and then 1093// specializing it to the concatenated specialization argumenst for all of that. 1094// 1095// In some cases, though, this model isn't appropriate. For example, when dealing with 1096// ray-tracing shaders and local root signatures, we really want the parameters of each 1097// entry point (actually, each entry-point *group*) to be allocated distinct storage, 1098// which really means we want to compute something like: 1099// 1100// SpecializedGlobals = specialize(compose(ModuleA, ModuleB, ...), X, Y, ...) 1101// 1102// SpecializedEP1 = compose(SpecializedGlobals, specialize(EntryPoint1, T, U, ...)) 1103// SpecializedEP2 = compose(SpecializedGlobals, specialize(EntryPoint2, A, B, ...)) 1104// 1105// Note how in this case all entry points agree on the layout for the shared/common 1106// parmaeters, but their layouts are also independent of one another. 1107// 1108// Furthermore, in this example, loading another entry point into the system would not 1109// rquire re-computing the layouts (or generated kernel code) for any of the entry 1110// points that had already been loaded (in contrast to a compose-then-specialize 1111// approach). 1112// 1113ComPtr < slang::IComponentType > specializedComponentType ; 1114ComPtr < slang::IBlob > diagnosticBlob ; 1115auto result = getLayout ()-> getSlangProgram ()-> specialize ( 1116specializationArgs .components .getArrayView ().getBuffer (), 1117specializationArgs .getCount (), 1118specializedComponentType .writeRef (), 1119diagnosticBlob .writeRef ()); 1120 1121if (diagnosticBlob && diagnosticBlob -> getBufferSize ()) 1122 { 1123getDebugCallback ()-> handleMessage ( 1124SLANG_FAILED (result ) ?DebugMessageType ::Error :DebugMessageType ::Info , 1125DebugMessageSource ::Layer , 1126 (const char * )diagnosticBlob -> getBufferPointer ()); 1127 } 1128 1129if (SLANG_FAILED (result )) 1130return result ; 1131 1132ComPtr < ID3DBlob > d3dDiagnosticBlob ; 1133auto slangSpecializedLayout = specializedComponentType -> getLayout (); 1134RefPtr < RootShaderObjectLayoutImpl > specializedLayout ; 1135auto rootLayoutResult = RootShaderObjectLayoutImpl ::create ( 1136static_cast < DeviceImpl *> (getRenderer ()), 1137specializedComponentType , 1138slangSpecializedLayout , 1139specializedLayout .writeRef (), 1140d3dDiagnosticBlob .writeRef ()); 1141 1142if (SLANG_FAILED (rootLayoutResult )) 1143 { 1144return rootLayoutResult ; 1145 } 1146 1147// Note: Computing the layout for the specialized program will have also computed 1148// the layouts for the entry points, and we really need to attach that information 1149// to them so that they don't go and try to compute their own specializations. 1150// 1151// TODO: Well, if we move to the specialization model described above then maybe 1152// we *will* want entry points to do their own specialization work... 1153// 1154auto entryPointCount = m_entryPoints .getCount (); 1155for (Index i = 0 ;i < entryPointCount ;++ i ) 1156 { 1157auto entryPointInfo = specializedLayout -> getEntryPoint (i ); 1158auto entryPointVars = m_entryPoints [i ]; 1159 1160entryPointVars -> m_specializedLayout = entryPointInfo .layout ; 1161 } 1162 1163returnRefPtrMove (outLayout ,specializedLayout ); 1164return SLANG_OK ; 1165} 1166 1167Result RootShaderObjectImpl ::copyFrom (IShaderObject * object ,ITransientResourceHeap * transientHeap ) 1168{ 1169if (auto srcObj = dynamic_cast < MutableRootShaderObjectImpl *> (object )) 1170 { 1171* this = * srcObj ; 1172return SLANG_OK ; 1173 } 1174return SLANG_FAIL ; 1175} 1176 1177Result RootShaderObjectImpl ::bindAsRoot ( 1178BindingContext * context , 1179RootShaderObjectLayoutImpl * specializedLayout ) 1180{ 1181// Pull updates from sub-objects when this is a mutable root shader object. 1182updateSubObjectsRecursive (); 1183 1184// A root shader object always binds as if it were a parameter block, 1185// insofar as it needs to allocate a descriptor set to hold the bindings 1186// for its own state and any sub-objects. 1187// 1188// Note: We do not direclty use `bindAsParameterBlock` here because we also 1189// need to bind the entry points into the same descriptor set that is 1190// being used for the root object. 1191 1192ShortList < PendingDescriptorTableBinding > pendingTableBindings ; 1193auto oldPendingTableBindings = context -> pendingTableBindings ; 1194context -> pendingTableBindings = & pendingTableBindings ; 1195 1196BindingOffset rootOffset ; 1197 1198// Bind all root parameters first. 1199Super ::bindRootArguments (context ,rootOffset .rootParam ); 1200 1201DescriptorSet descriptorSet ; 1202SLANG_RETURN_ON_FAIL (prepareToBindAsParameterBlock ( 1203context , 1204/* inout */ rootOffset , 1205specializedLayout , 1206descriptorSet )); 1207 1208SLANG_RETURN_ON_FAIL ( 1209Super ::bindAsConstantBuffer (context ,descriptorSet ,rootOffset ,specializedLayout )); 1210 1211auto entryPointCount = m_entryPoints .getCount (); 1212for (Index i = 0 ;i < entryPointCount ;++ i ) 1213 { 1214auto entryPoint = m_entryPoints [i ]; 1215auto & entryPointInfo = specializedLayout -> getEntryPoint (i ); 1216 1217auto entryPointOffset = rootOffset ; 1218entryPointOffset += entryPointInfo .offset ; 1219 1220entryPoint -> updateSubObjectsRecursive (); 1221 1222SLANG_RETURN_ON_FAIL (entryPoint -> bindAsConstantBuffer ( 1223context , 1224descriptorSet , 1225entryPointOffset , 1226entryPointInfo .layout )); 1227 } 1228 1229bindPendingTables (context ); 1230context -> pendingTableBindings = oldPendingTableBindings ; 1231 1232return SLANG_OK ; 1233} 1234 1235Result RootShaderObjectImpl ::resetImpl ( 1236DeviceImpl * device , 1237RootShaderObjectLayoutImpl * layout , 1238DescriptorHeapReference viewHeap , 1239DescriptorHeapReference samplerHeap , 1240bool isMutable ) 1241{ 1242SLANG_RETURN_ON_FAIL (Super ::init (device ,layout ,viewHeap ,samplerHeap )); 1243m_isMutable = isMutable ; 1244m_specializedLayout = nullptr ; 1245m_entryPoints .clear (); 1246for (auto entryPointInfo :layout -> getEntryPoints ()) 1247 { 1248RefPtr < ShaderObjectImpl > entryPoint ; 1249SLANG_RETURN_ON_FAIL ( 1250ShaderObjectImpl ::create (device ,entryPointInfo .layout ,entryPoint .writeRef ())); 1251entryPoint -> m_isMutable = isMutable ; 1252m_entryPoints .add (entryPoint ); 1253 } 1254return SLANG_OK ; 1255} 1256 1257Result RootShaderObjectImpl ::reset ( 1258DeviceImpl * device , 1259RootShaderObjectLayoutImpl * layout , 1260TransientResourceHeapImpl * heap ) 1261{ 1262return resetImpl ( 1263device , 1264layout , 1265& heap -> m_stagingCpuViewHeap , 1266& heap -> m_stagingCpuSamplerHeap , 1267 false); 1268} 1269 1270}// namespace d3d12 1271}// namespace gfx