yum-mirror/slang
Making it easier to work with shaders
git clone https://git.yummers.dev/yum-mirror/slang
f65d756bf
master
1#pragma once 2 3#include "core/slang-basic.h" 4#include "core/slang-com-object.h" 5#include "renderer-shared.h" 6#include "slang-gfx.h" 7 8namespace gfx 9{ 10class ShaderObjectLayoutBase ; 11 12template < typename T > 13class VersionedObjectPool 14{ 15public : 16struct ObjectVersion 17 { 18Slang ::RefPtr < T > object ; 19Slang ::RefPtr < TransientResourceHeapBase > transientHeap ; 20uint64_t transientHeapVersion ; 21bool canRecycle () {return (transientHeap -> getVersion ()!= transientHeapVersion ); } 22 }; 23Slang ::List < ObjectVersion > objects ; 24SlangInt lastAllocationIndex = -1 ; 25ObjectVersion & allocate (TransientResourceHeapBase * currentTransientHeap ) 26 { 27for (SlangInt i = 0 ;i < objects .getCount ();i ++ ) 28 { 29 auto& object = objects [i ]; 30if (object .canRecycle ()) 31 { 32object .transientHeap = currentTransientHeap ; 33object .transientHeapVersion = currentTransientHeap -> getVersion (); 34lastAllocationIndex = i ; 35return object ; 36 } 37 } 38ObjectVersion v ; 39v .transientHeap = currentTransientHeap ; 40v .transientHeapVersion = currentTransientHeap -> getVersion (); 41objects .add (v ); 42lastAllocationIndex = objects .getCount ()- 1 ; 43return objects .getLast (); 44 } 45ObjectVersion & getLastAllocation () {return objects [lastAllocationIndex ]; } 46}; 47 48class MutableShaderObjectData 49{ 50public : 51// Any "ordinary" / uniform data for this object 52Slang ::List < char > m_ordinaryData ; 53 54bool m_dirty = true; 55 56Slang ::Index getCount () {return m_ordinaryData .getCount (); } 57void setCount (Slang ::Index count ) {m_ordinaryData .setCount (count ); } 58char * getBuffer () {return m_ordinaryData .getBuffer (); } 59void markDirty () {m_dirty = true; } 60 61// We don't actually create any GPU buffers here, since they will be handled 62// by the immutable shader objects once the user calls `getCurrentVersion`. 63ResourceViewBase * getResourceView ( 64RendererBase * device , 65slang ::TypeLayoutReflection * elementLayout , 66slang ::BindingType bindingType ) 67 { 68return nullptr ; 69 } 70}; 71 72template < typename TShaderObject ,typename TShaderObjectLayoutImpl > 73class MutableShaderObject 74 :public ShaderObjectBaseImpl < TShaderObject ,TShaderObjectLayoutImpl ,MutableShaderObjectData > 75{ 76typedef ShaderObjectBaseImpl < TShaderObject ,TShaderObjectLayoutImpl ,MutableShaderObjectData > 77Super ; 78 79protected : 80Slang ::OrderedDictionary < ShaderOffset ,Slang ::RefPtr < ResourceViewBase >>m_resources ; 81Slang ::OrderedDictionary < ShaderOffset ,Slang ::RefPtr < SamplerStateBase >>m_samplers ; 82Slang ::OrderedHashSet < ShaderOffset > m_objectOffsets ; 83VersionedObjectPool < ShaderObjectBase > m_shaderObjectVersions ; 84bool m_dirty = true; 85bool isDirty () 86 { 87if (m_dirty ) 88return true; 89if (this -> m_data .m_dirty ) 90return true; 91for (auto& object :this -> m_objects ) 92 { 93if (object && object -> isDirty ()) 94return true ; 95 } 96return false; 97 } 98 99void markDirty () {m_dirty = true; } 100 101public : 102Result init (RendererBase * device ,ShaderObjectLayoutBase * layout ) 103 { 104this -> m_device = device ; 105 autolayoutImpl = static_cast < TShaderObjectLayoutImpl *> (layout); 106this -> m_layout = layoutImpl; 107Slang :: Index subObjectCount = layoutImpl -> getSubObjectCount (); 108this -> m_objects . setCount (subObjectCount); 109auto dataSize = layoutImpl -> getElementTypeLayout () -> getSize (); 110assert (dataSize >= 0 ); 111this -> m_data . setCount (dataSize); 112memset (this -> m_data . getBuffer (), 0 , dataSize); 113return SLANG_OK ; 114} 115 116public : 117virtual SLANG_NO_THROW const void * SLANG_MCALL getRawData () override 118{ 119return this -> m_data . getBuffer (); 120} 121virtual SLANG_NO_THROW size_t SLANG_MCALL getSize () override { return this -> m_data . getCount (); } 122virtual SLANG_NO_THROW Result SLANG_MCALL 123setData( ShaderOffset const & offset, void const * data, size_t size) override 124{ 125if (!size) 126return SLANG_OK ; 127if ( SlangInt (offset. uniformOffset + size) > this -> m_data . getCount ()) 128this -> m_data . setCount (offset. uniformOffset + size); 129memcpy (this -> m_data . getBuffer () + offset. uniformOffset , data, size); 130this -> m_data . markDirty (); 131markDirty (); 132return SLANG_OK ; 133} 134 135virtual SLANG_NO_THROW Result SLANG_MCALL 136setObject( ShaderOffset const & offset, IShaderObject * object) override 137{ 138Super :: setObject (offset, object); 139m_objectOffsets. add (offset); 140markDirty (); 141return SLANG_OK ; 142} 143 144virtual SLANG_NO_THROW Result SLANG_MCALL 145setResource( ShaderOffset const & offset, IResourceView * resourceView) override 146{ 147m_resources[offset] = static_cast < ResourceViewBase *> (resourceView); 148markDirty (); 149return SLANG_OK ; 150} 151 152virtual SLANG_NO_THROW Result SLANG_MCALL 153setSampler( ShaderOffset const & offset, ISamplerState * sampler) override 154{ 155m_samplers[offset] = static_cast < SamplerStateBase *> (sampler); 156markDirty (); 157return SLANG_OK ; 158} 159 160virtual SLANG_NO_THROW Result SLANG_MCALL setCombinedTextureSampler( 161ShaderOffset const & offset, 162IResourceView * textureView, 163ISamplerState * sampler) override 164{ 165m_samplers[offset] = static_cast < SamplerStateBase *> (sampler); 166m_resources[offset] = static_cast < ResourceViewBase *> (textureView); 167markDirty (); 168return SLANG_OK ; 169} 170 171virtual SLANG_NO_THROW Result SLANG_MCALL 172getCurrentVersion ( ITransientResourceHeap * transientHeap, IShaderObject ** outObject) override 173{ 174if (! isDirty ()) 175{ 176returnComPtr (outObject, getLastAllocatedShaderObject ()); 177return SLANG_OK ; 178} 179 180Slang ::RefPtr < ShaderObjectBase > object = 181allocateShaderObject (static_cast < TransientResourceHeapBase *> (transientHeap)); 182SLANG_RETURN_ON_FAIL ( 183object -> setData ( ShaderOffset (), this -> m_data . getBuffer (), this -> m_data . getCount ())); 184for (auto res : m_resources) 185SLANG_RETURN_ON_FAIL ( object -> setResource ( res .key, res .value)); 186for (auto sampler : m_samplers) 187SLANG_RETURN_ON_FAIL (object -> setSampler (sampler. key , sampler. value )); 188for (auto offset : m_objectOffsets) 189{ 190if (offset. bindingRangeIndex < 0 ) 191return SLANG_E_INVALID_ARG ; 192auto layout = this -> getLayout (); 193if (offset. bindingRangeIndex >= layout -> getBindingRangeCount ()) 194return SLANG_E_INVALID_ARG ; 195auto bindingRange = layout -> getBindingRange (offset. bindingRangeIndex ); 196 197auto subObject = 198this -> m_objects [bindingRange. subObjectIndex + offset. bindingArrayIndex ]; 199if (subObject) 200{ 201ComPtr < IShaderObject > subObjectVersion; 202SLANG_RETURN_ON_FAIL ( 203subObject -> getCurrentVersion (transientHeap, subObjectVersion. writeRef ())); 204SLANG_RETURN_ON_FAIL (object -> setObject (offset, subObjectVersion)); 205} 206} 207m_dirty = false; 208this -> m_data . m_dirty = false; 209returnComPtr (outObject, object); 210return SLANG_OK ; 211} 212 213public : 214Slang ::RefPtr < ShaderObjectBase > allocateShaderObject (TransientResourceHeapBase * transientHeap) 215{ 216auto & version = m_shaderObjectVersions. allocate (transientHeap); 217if (!version. object ) 218{ 219ComPtr < IShaderObject > shaderObject; 220SLANG_RETURN_NULL_ON_FAIL ( 221this -> m_device -> createShaderObject (this -> m_layout , shaderObject. writeRef ())); 222version. object = static_cast < ShaderObjectBase *> (shaderObject. get ()); 223} 224return version. object ; 225} 226Slang ::RefPtr < ShaderObjectBase > getLastAllocatedShaderObject () 227{ 228return m_shaderObjectVersions. getLastAllocation (). object ; 229} 230}; 231 232// A proxy shader object to hold mutable shader parameters for global scope and entry-points. 233class MutableRootShaderObject : public ShaderObjectBase 234{ 235public : 236Slang ::List < uint8_t > m_data; 237Slang ::OrderedDictionary < ShaderOffset, Slang::RefPtr < ResourceViewBase>> m_resources; 238Slang ::OrderedDictionary < ShaderOffset, Slang::RefPtr < SamplerStateBase>> m_samplers; 239Slang ::OrderedDictionary < ShaderOffset, Slang::RefPtr < ShaderObjectBase>> m_objects; 240Slang ::OrderedDictionary < ShaderOffset, Slang::List < slang::SpecializationArg>> 241m_specializationArgs; 242Slang ::List < Slang::RefPtr < MutableRootShaderObject>> m_entryPoints; 243Slang ::RefPtr < BufferResource > m_constantBufferOverride; 244slang :: TypeLayoutReflection * m_elementTypeLayout; 245 246MutableRootShaderObject (RendererBase * device, slang::TypeLayoutReflection * entryPointLayout) 247{ 248this -> m_device = device; 249m_elementTypeLayout = entryPointLayout; 250m_data. setCount (entryPointLayout -> getSize ()); 251memset (m_data. begin (), 0 , m_data. getCount ()); 252} 253 254MutableRootShaderObject (RendererBase * device, Slang::RefPtr < ShaderProgramBase > program) 255{ 256this -> m_device = device; 257auto programLayout = program -> slangGlobalScope -> getLayout (); 258SlangInt entryPointCount = programLayout -> getEntryPointCount (); 259for ( SlangInt e = 0 ; e < entryPointCount; ++ e) 260{ 261auto slangEntryPoint = programLayout -> getEntryPointByIndex (e); 262Slang ::RefPtr < MutableRootShaderObject > entryPointObject = new MutableRootShaderObject ( 263device, 264slangEntryPoint -> getTypeLayout () -> getElementTypeLayout ()); 265 266m_entryPoints. add (entryPointObject); 267} 268m_data. setCount (programLayout -> getGlobalParamsTypeLayout () -> getSize ()); 269memset (m_data. begin (), 0 , m_data. getCount ()); 270m_elementTypeLayout = programLayout -> getGlobalParamsTypeLayout (); 271} 272 273 274virtual SLANG_NO_THROW slang ::TypeLayoutReflection * SLANG_MCALL getElementTypeLayout () override 275{ 276return m_elementTypeLayout; 277} 278 279virtual SLANG_NO_THROW ShaderObjectContainerType SLANG_MCALL getContainerType () override 280{ 281return ShaderObjectContainerType::None; 282} 283 284virtual SLANG_NO_THROW GfxCount SLANG_MCALL getEntryPointCount () override 285{ 286return ( GfxCount )m_entryPoints. getCount (); 287} 288 289virtual SLANG_NO_THROW Result SLANG_MCALL 290getEntryPoint ( GfxIndex index, IShaderObject ** entryPoint) override 291{ 292returnComPtr (entryPoint, m_entryPoints[index]); 293return SLANG_OK ; 294} 295 296virtual SLANG_NO_THROW Result SLANG_MCALL 297setData( ShaderOffset const & offset, void const * data, Size size) override 298{ 299auto newSize = Slang::Index(size + offset. uniformOffset ); 300if (newSize > m_data. getCount ()) 301m_data. setCount (( Slang ::Index)newSize); 302memcpy (m_data. begin () + offset. uniformOffset , data, size); 303return SLANG_OK ; 304} 305 306virtual SLANG_NO_THROW Result SLANG_MCALL 307getObject( ShaderOffset const & offset, IShaderObject ** object) override 308{ 309* object = nullptr ; 310 311Slang ::RefPtr < ShaderObjectBase > subObject; 312if (m_objects. tryGetValue (offset, subObject)) 313{ 314returnComPtr (object, subObject); 315} 316return SLANG_OK ; 317} 318 319virtual SLANG_NO_THROW Result SLANG_MCALL 320setObject( ShaderOffset const & offset, IShaderObject * object) override 321{ 322m_objects[offset] = static_cast < ShaderObjectBase *> (object); 323return SLANG_OK ; 324} 325 326virtual SLANG_NO_THROW Result SLANG_MCALL 327setResource( ShaderOffset const & offset, IResourceView * resourceView) override 328{ 329m_resources[offset] = static_cast < ResourceViewBase *> (resourceView); 330return SLANG_OK ; 331} 332 333virtual SLANG_NO_THROW Result SLANG_MCALL 334setSampler( ShaderOffset const & offset, ISamplerState * sampler) override 335{ 336m_samplers[offset] = static_cast < SamplerStateBase *> (sampler); 337return SLANG_OK ; 338} 339virtual SLANG_NO_THROW Result SLANG_MCALL setCombinedTextureSampler( 340ShaderOffset const & offset, 341IResourceView * textureView, 342ISamplerState * sampler) override 343{ 344m_resources[offset] = static_cast < ResourceViewBase *> (textureView); 345m_samplers[offset] = static_cast < SamplerStateBase *> (sampler); 346return SLANG_OK ; 347} 348 349virtual SLANG_NO_THROW Result SLANG_MCALL setSpecializationArgs( 350ShaderOffset const & offset, 351const slang :: SpecializationArg * args, 352GfxCount count) override 353{ 354Slang ::List < slang::SpecializationArg > specArgs; 355specArgs. addRange (args, count); 356m_specializationArgs[offset] = specArgs; 357return SLANG_OK ; 358} 359 360virtual SLANG_NO_THROW Result SLANG_MCALL 361getCurrentVersion ( ITransientResourceHeap * transientHeap, IShaderObject ** outObject) override 362{ 363return SLANG_FAIL ; 364} 365 366virtual SLANG_NO_THROW Result SLANG_MCALL 367copyFrom ( IShaderObject * other, ITransientResourceHeap * transientHeap) override 368{ 369auto otherObject = static_cast < MutableRootShaderObject *> (other); 370* this = * otherObject; 371return SLANG_OK ; 372} 373 374virtual SLANG_NO_THROW const void * SLANG_MCALL getRawData () override { return m_data. begin (); } 375 376virtual SLANG_NO_THROW Size SLANG_MCALL getSize () override { return ( Size )m_data. getCount (); } 377 378virtual SLANG_NO_THROW Result SLANG_MCALL 379setConstantBufferOverride ( IBufferResource * constantBuffer) override 380{ 381m_constantBufferOverride = static_cast < BufferResource *> (constantBuffer); 382return SLANG_OK ; 383} 384 385virtual Result collectSpecializationArgs (ExtendedShaderObjectTypeList & args) override 386{ 387SLANG_UNUSED (args); 388return SLANG_OK ; 389} 390}; 391 392} // namespace gfx