yum-mirror/slang
Making it easier to work with shaders
git clone https://git.yummers.dev/yum-mirror/slang
b118451e3
master
1#pragma once 2 3 4#include "core/slang-basic.h" 5#include "core/slang-short-list.h" 6#include "core/slang-virtual-object-pool.h" 7#include "slang-com-ptr.h" 8 9#include <d3d12.h> 10#include <dxgi.h> 11 12namespace gfx 13{ 14 15/*! \brief A simple class to manage an underlying Dx12 Descriptor Heap. Allocations are made 16linearly in order. It is not possible to free individual allocations, but all allocations can be 17deallocated with 'deallocateAll'. */ 18class D3D12DescriptorHeap 19{ 20public : 21typedef D3D12DescriptorHeap ThisType ; 22 23/// Initialize 24Slang ::Result init ( 25ID3D12Device * device , 26int size , 27D3D12_DESCRIPTOR_HEAP_TYPE type , 28D3D12_DESCRIPTOR_HEAP_FLAGS flags ); 29/// Initialize with an array of handles copying over the representation 30Slang ::Result init ( 31ID3D12Device * device , 32const D3D12_CPU_DESCRIPTOR_HANDLE * handles , 33int numHandles , 34D3D12_DESCRIPTOR_HEAP_TYPE type , 35D3D12_DESCRIPTOR_HEAP_FLAGS flags ); 36 37/// Returns the number of slots that have been used 38SLANG_FORCE_INLINE int getUsedSize ()const {return m_currentIndex ; } 39 40/// Get the total amount of descriptors possible on the heap 41SLANG_FORCE_INLINE int getTotalSize ()const {return m_totalSize ; } 42/// Allocate a descriptor. Returns the index, or -1 if none left. 43SLANG_FORCE_INLINE int allocate (); 44/// Allocate a number of descriptors. Returns the start index (or -1 if not possible) 45SLANG_FORCE_INLINE int allocate (int numDescriptors ); 46 47/// 48SLANG_FORCE_INLINE int placeAt (int index ); 49 50/// Deallocates all allocations, and starts allocation from the start of the underlying heap 51/// again 52SLANG_FORCE_INLINE void deallocateAll () {m_currentIndex = 0 ; } 53 54/// Get the size of each 55SLANG_FORCE_INLINE int getDescriptorSize ()const {return m_descriptorSize ; } 56 57/// Get the GPU heap start 58SLANG_FORCE_INLINE D3D12_GPU_DESCRIPTOR_HANDLE getGpuStart ()const 59 { 60return m_heap -> GetGPUDescriptorHandleForHeapStart (); 61 } 62/// Get the CPU heap start 63SLANG_FORCE_INLINE D3D12_CPU_DESCRIPTOR_HANDLE getCpuStart ()const 64 { 65return m_heap -> GetCPUDescriptorHandleForHeapStart (); 66 } 67 68/// Get the GPU handle at the specified index 69SLANG_FORCE_INLINE D3D12_GPU_DESCRIPTOR_HANDLE getGpuHandle (int index )const ; 70/// Get the CPU handle at the specified index 71SLANG_FORCE_INLINE D3D12_CPU_DESCRIPTOR_HANDLE getCpuHandle (int index )const ; 72 73/// Get the underlying heap 74SLANG_FORCE_INLINE ID3D12DescriptorHeap * getHeap ()const {return m_heap ; } 75 76/// Ctor 77D3D12DescriptorHeap (); 78 79protected : 80Slang ::ComPtr < ID3D12Device > m_device ; 81Slang ::ComPtr < ID3D12DescriptorHeap > m_heap ;///< The underlying heap being allocated from 82int m_totalSize ;///< Total amount of allocations available on the heap 83int m_currentIndex ;///< The current descriptor 84int m_descriptorSize ;///< The size of each descriptor 85D3D12_DESCRIPTOR_HEAP_FLAGS m_heapFlags ;///< The flags of the heap 86}; 87 88/// A d3d12 descriptor, used as "backing storage" for a view. 89/// 90/// This type is intended to be used to represent descriptors that 91/// are allocated and freed through a `D3D12GeneralDescriptorHeap`. 92struct D3D12Descriptor 93{ 94D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle ; 95}; 96 97/// An allocator for host-visible descriptors. 98/// 99/// Unlike the `D3D12DescriptorHeap` type, this class allows for both 100/// allocation and freeing of descriptors, by maintaining a free list. 101/// 102class D3D12GeneralDescriptorHeap :public Slang ::RefObject 103{ 104ID3D12Device * m_device ; 105int m_chunkSize ; 106D3D12_DESCRIPTOR_HEAP_TYPE m_type ; 107 108D3D12DescriptorHeap m_heap ; 109Slang ::VirtualObjectPool m_allocator ; 110 111public : 112int getSize () {return m_chunkSize ; } 113 114Slang ::Result init ( 115ID3D12Device * device , 116int chunkSize , 117D3D12_DESCRIPTOR_HEAP_TYPE type , 118D3D12_DESCRIPTOR_HEAP_FLAGS flag ) 119 { 120m_device = device ; 121m_chunkSize = chunkSize ; 122m_type = type ; 123 124SLANG_RETURN_ON_FAIL (m_heap .init (m_device ,m_chunkSize ,m_type ,flag )); 125m_allocator .initPool (m_chunkSize ); 126return SLANG_OK ; 127 } 128 129SLANG_FORCE_INLINE D3D12_CPU_DESCRIPTOR_HANDLE getCpuHandle (int index )const 130 { 131return m_heap .getCpuHandle (index ); 132 } 133 134SLANG_FORCE_INLINE D3D12_GPU_DESCRIPTOR_HANDLE getGpuHandle (int index )const 135 { 136return m_heap .getGpuHandle (index ); 137 } 138 139int allocate (int count ) {return m_allocator .alloc (count ); } 140 141Slang ::Result allocate (D3D12Descriptor * outDescriptor ) 142 { 143// TODO: this allocator would take some work to make thread-safe 144 145int index = m_allocator .alloc (1 ); 146if (index < 0 ) 147 { 148assert (!"descriptor allocation failed" ); 149return SLANG_FAIL ; 150 } 151 152D3D12Descriptor descriptor ; 153descriptor .cpuHandle = m_heap .getCpuHandle (index ); 154 155* outDescriptor = descriptor ; 156return SLANG_OK ; 157 } 158 159void free (int index ,int count ) {m_allocator .free (index ,count ); } 160 161void free (D3D12Descriptor descriptor ) 162 { 163 autoindex = 164( int )(descriptor. cpuHandle . ptr - m_heap. getCpuStart (). ptr ) / m_heap. getDescriptorSize (); 165free (index, 1 ); 166} 167}; 168 169class D3D12GeneralExpandingDescriptorHeap : public Slang::RefObject 170{ 171ID3D12Device * m_device; 172D3D12_DESCRIPTOR_HEAP_TYPE m_type; 173D3D12_DESCRIPTOR_HEAP_FLAGS m_flag; 174int m_chunkSize; 175Slang ::List < Slang::RefPtr < D3D12GeneralDescriptorHeap>> m_subHeaps; 176Slang ::List < int > m_subHeapStartingIndex; 177 178public : 179Slang :: Result newSubHeap () 180{ 181Slang ::RefPtr < D3D12GeneralDescriptorHeap > subHeap = new D3D12GeneralDescriptorHeap (); 182SLANG_RETURN_ON_FAIL (subHeap -> init (m_device, m_chunkSize, m_type, m_flag)); 183m_subHeaps. add (subHeap); 184if (m_subHeapStartingIndex. getCount ()) 185{ 186m_subHeapStartingIndex. add ( 187m_subHeapStartingIndex. getLast () + m_subHeaps. getLast () -> getSize ()); 188} 189else 190{ 191m_subHeapStartingIndex. add ( 0 ); 192} 193return SLANG_OK ; 194} 195 196int getSubHeapIndex ( int descriptorIndex) const 197{ 198Slang :: Index l = 0 ; 199Slang :: Index r = m_subHeapStartingIndex. getCount (); 200while (l < r - 1 ) 201{ 202Slang :: Index m = l + (r - l) / 2 ; 203if (m_subHeapStartingIndex[m] < descriptorIndex) 204l = m; 205else if (m_subHeapStartingIndex[m] > descriptorIndex) 206r = m; 207else 208return ( int )m; 209} 210assert ( 211m_subHeapStartingIndex[l] <= descriptorIndex && 212m_subHeapStartingIndex[l] + m_subHeaps[l] -> getSize () > descriptorIndex); 213return ( int )l; 214} 215 216Slang :: Result init ( 217ID3D12Device * device, 218int chunkSize, 219D3D12_DESCRIPTOR_HEAP_TYPE type, 220D3D12_DESCRIPTOR_HEAP_FLAGS flag) 221{ 222m_device = device; 223m_chunkSize = chunkSize; 224m_type = type; 225m_flag = flag; 226 227return newSubHeap (); 228} 229 230SLANG_FORCE_INLINE D3D12_CPU_DESCRIPTOR_HANDLE getCpuHandle ( int index) const 231{ 232auto subHeapIndex = getSubHeapIndex ( index ); 233return m_subHeaps[subHeapIndex] -> getCpuHandle (index - m_subHeapStartingIndex[subHeapIndex]); 234} 235 236SLANG_FORCE_INLINE D3D12_GPU_DESCRIPTOR_HANDLE getGpuHandle ( int index) const 237{ 238auto subHeapIndex = getSubHeapIndex ( index ); 239return m_subHeaps[subHeapIndex] -> getGpuHandle (index - m_subHeapStartingIndex[subHeapIndex]); 240} 241 242int allocate ( int count) 243{ 244auto result = m_subHeaps. getLast () -> allocate (count); 245if (result == -1 ) 246{ 247newSubHeap (); 248return allocate (count); 249} 250return result + m_subHeapStartingIndex. getLast (); 251} 252 253Slang :: Result allocate ( D3D12Descriptor * outDescriptor) 254{ 255int index = allocate ( 1 ); 256if (index < 0 ) 257{ 258assert (! "descriptor allocation failed" ); 259return SLANG_FAIL ; 260} 261 262D3D12Descriptor descriptor; 263descriptor. cpuHandle = getCpuHandle (index); 264 265* outDescriptor = descriptor; 266return SLANG_OK ; 267} 268 269void free ( int index, int count) 270{ 271auto subHeapIndex = getSubHeapIndex ( index ); 272m_subHeaps[subHeapIndex] -> free (index - m_subHeapStartingIndex[subHeapIndex], count); 273} 274 275void free ( D3D12Descriptor descriptor) 276{ 277for (auto & subHeap : m_subHeaps ) 278{ 279if ( descriptor .cpuHandle.ptr >= subHeap -> getCpuHandle ( 0 ).ptr) 280{ 281auto subIndex = descriptor. cpuHandle . ptr - subHeap -> getCpuHandle ( 0 ). ptr ; 282if (subIndex < ( SIZE_T )subHeap -> getSize ()) 283{ 284subHeap -> free (descriptor); 285break; 286} 287} 288} 289} 290}; 291 292class D3D12LinearExpandingDescriptorHeap : public Slang::RefObject 293{ 294ID3D12Device * m_device; 295D3D12_DESCRIPTOR_HEAP_TYPE m_type; 296D3D12_DESCRIPTOR_HEAP_FLAGS m_flag; 297int m_chunkSize; 298Slang::ShortList < D3D12DescriptorHeap, 4 > m_subHeaps; 299int32_t m_subHeapIndex; 300 301public: 302Slang::Result newSubHeap() 303{ 304m_subHeapIndex ++ ; 305if (m_subHeapIndex <= m_subHeaps. getCount ()) 306{ 307D3D12DescriptorHeap subHeap; 308SLANG_RETURN_ON_FAIL (subHeap. init (m_device, m_chunkSize, m_type, m_flag)); 309m_subHeaps. add (Slang:: _Move (subHeap)); 310} 311return SLANG_OK ; 312} 313 314Slang :: Result init ( 315ID3D12Device * device, 316int chunkSize, 317D3D12_DESCRIPTOR_HEAP_TYPE type, 318D3D12_DESCRIPTOR_HEAP_FLAGS flag) 319{ 320m_device = device; 321m_chunkSize = chunkSize; 322m_type = type; 323m_flag = flag; 324m_subHeapIndex = -1 ; 325return newSubHeap (); 326} 327 328int allocate ( int count) 329{ 330auto result = m_subHeaps[m_subHeapIndex]. allocate (count); 331if (result == -1 ) 332{ 333newSubHeap (); 334return allocate (count); 335} 336assert (result <= 0xFFFFFF ); 337assert (m_subHeapIndex <= 255 ); 338return (m_subHeapIndex << 24 ) + result; 339} 340 341SLANG_FORCE_INLINE D3D12_CPU_DESCRIPTOR_HANDLE getCpuHandle ( int index) const 342{ 343auto subHeapIndex = (( uint32_t )(index >> 24 ) & 0xFF ); 344return m_subHeaps[subHeapIndex]. getCpuHandle (index & 0xFFFFFF ); 345} 346 347void free ( int index, int count) { assert ( 0 && "not supported" ); } 348 349void free ( D3D12Descriptor descriptor) { assert ( 0 && "not supported" ); } 350 351void freeAll () 352{ 353for (auto & subHeap : m_subHeaps) 354subHeap. deallocateAll (); 355m_subHeapIndex = 0 ; 356} 357}; 358 359struct DescriptorHeapReference 360{ 361enum class Type 362{ 363Linear , 364General , 365ExpandingGeneral , 366ExpandingLinear 367}; 368union Ptr 369{ 370D3D12DescriptorHeap * linearHeap ; 371D3D12GeneralDescriptorHeap * generalHeap ; 372D3D12GeneralExpandingDescriptorHeap * generalExpandingHeap ; 373D3D12LinearExpandingDescriptorHeap * linearExpandingHeap ; 374}; 375Type type; 376Ptr ptr; 377DescriptorHeapReference () = default; 378DescriptorHeapReference (D3D12DescriptorHeap * heap) 379{ 380type = Type::Linear; 381ptr. linearHeap = heap; 382} 383DescriptorHeapReference (D3D12GeneralDescriptorHeap * heap) 384{ 385type = Type::General; 386ptr. generalHeap = heap; 387} 388DescriptorHeapReference (D3D12GeneralExpandingDescriptorHeap * heap) 389{ 390type = Type::ExpandingGeneral; 391ptr. generalExpandingHeap = heap; 392} 393DescriptorHeapReference (D3D12LinearExpandingDescriptorHeap * heap) 394{ 395type = Type::ExpandingLinear; 396ptr. linearExpandingHeap = heap; 397} 398D3D12_CPU_DESCRIPTOR_HANDLE getCpuHandle ( int index) const 399{ 400switch (type) 401{ 402case Type:: Linear : 403return ptr. linearHeap -> getCpuHandle (index); 404case Type:: General : 405return ptr. generalHeap -> getCpuHandle (index); 406case Type:: ExpandingGeneral : 407return ptr. generalExpandingHeap -> getCpuHandle (index); 408case Type:: ExpandingLinear : 409return ptr. linearExpandingHeap -> getCpuHandle (index); 410default : 411return D3D12_CPU_DESCRIPTOR_HANDLE (); 412} 413} 414D3D12_GPU_DESCRIPTOR_HANDLE getGpuHandle ( int index) const 415{ 416switch (type) 417{ 418case Type:: Linear : 419return ptr. linearHeap -> getGpuHandle (index); 420case Type:: General : 421return ptr. generalHeap -> getGpuHandle (index); 422case Type:: ExpandingGeneral : 423return ptr. generalExpandingHeap -> getGpuHandle (index); 424default : 425return D3D12_GPU_DESCRIPTOR_HANDLE (); 426} 427} 428int allocate ( int numDescriptors) 429{ 430switch (type) 431{ 432case Type:: Linear : 433return ptr. linearHeap -> allocate (numDescriptors); 434case Type:: General : 435return ptr. generalHeap -> allocate (numDescriptors); 436case Type:: ExpandingGeneral : 437return ptr. generalExpandingHeap -> allocate (numDescriptors); 438default : 439return ptr. linearExpandingHeap -> allocate (numDescriptors); 440} 441} 442void free ( int index, int count) 443{ 444switch (type) 445{ 446default : 447case Type:: Linear : 448SLANG_ASSERT (! "Linear heap does not support free()." ); 449break ; 450case Type:: General : 451return ptr. generalHeap -> free (index, count); 452case Type:: ExpandingGeneral : 453return ptr. generalExpandingHeap -> free (index, count); 454} 455} 456void freeIfSupported ( int index, int count) 457{ 458switch (type) 459{ 460case Type:: Linear : 461return ; 462case Type:: General : 463return ptr. generalHeap -> free (index, count); 464case Type:: ExpandingGeneral : 465return ptr. generalExpandingHeap -> free (index, count); 466default : 467break ; 468} 469} 470}; 471 472// --------------------------------------------------------------------------- 473int D3D12DescriptorHeap:: allocate () 474{ 475return allocate ( 1 ); 476} 477// --------------------------------------------------------------------------- 478int D3D12DescriptorHeap:: allocate ( int numDescriptors) 479{ 480if (m_currentIndex + numDescriptors <= m_totalSize) 481{ 482const int index = m_currentIndex; 483m_currentIndex += numDescriptors; 484return index; 485} 486if (m_heapFlags & D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE ) 487{ 488// No automatic resizing for GPU visible heaps. 489return -1 ; 490} 491// We don't have enough heap size, resize the heap. 492auto oldHeap = m_heap; 493auto oldSize = m_totalSize; 494auto currentIndex = m_currentIndex; 495auto desc = m_heap -> GetDesc (); 496this -> init (m_device, ( int )desc. NumDescriptors * 2 , desc. Type , desc. Flags ); 497m_device -> CopyDescriptorsSimple ( 498( UINT )currentIndex, 499m_heap -> GetCPUDescriptorHandleForHeapStart (), 500oldHeap -> GetCPUDescriptorHandleForHeapStart (), 501desc. Type ); 502m_currentIndex = currentIndex; 503// Now allocate again. 504const int index = m_currentIndex; 505m_currentIndex += numDescriptors; 506return index; 507} 508// --------------------------------------------------------------------------- 509SLANG_FORCE_INLINE int D3D12DescriptorHeap ::placeAt( int index ) 510{ 511assert (index >= 0 && index < m_totalSize); 512m_currentIndex = index + 1 ; 513return index; 514} 515 516// --------------------------------------------------------------------------- 517SLANG_FORCE_INLINE D3D12_CPU_DESCRIPTOR_HANDLE D3D12DescriptorHeap ::getCpuHandle( int index ) const 518{ 519assert (index >= 0 && index < m_totalSize); 520D3D12_CPU_DESCRIPTOR_HANDLE start = m_heap -> GetCPUDescriptorHandleForHeapStart (); 521D3D12_CPU_DESCRIPTOR_HANDLE dst; 522dst. ptr = start. ptr + m_descriptorSize * index; 523return dst; 524} 525// --------------------------------------------------------------------------- 526SLANG_FORCE_INLINE D3D12_GPU_DESCRIPTOR_HANDLE D3D12DescriptorHeap ::getGpuHandle( int index ) const 527{ 528assert (index >= 0 && index < m_totalSize); 529D3D12_GPU_DESCRIPTOR_HANDLE start = m_heap -> GetGPUDescriptorHandleForHeapStart (); 530D3D12_GPU_DESCRIPTOR_HANDLE dst; 531dst. ptr = start. ptr + m_descriptorSize * index; 532return dst; 533} 534 535} // namespace gfx