yum-mirror/slang
Making it easier to work with shaders
git clone https://git.yummers.dev/yum-mirror/slang
b118451e3
master
1// d3d11-shader-object-layout.cpp 2#include "d3d11-shader-object-layout.h" 3 4namespace gfx 5{ 6 7using namespace Slang ; 8 9namespace d3d11 10{ 11 12ShaderObjectLayoutImpl ::SubObjectRangeOffset ::SubObjectRangeOffset ( 13 slang::VariableLayoutReflection * varLayout ) 14 :BindingOffset (varLayout ) 15{ 16if (auto pendingLayout = varLayout -> getPendingDataLayout ()) 17 { 18pendingOrdinaryData = (uint32_t )pendingLayout -> getOffset (SLANG_PARAMETER_CATEGORY_UNIFORM ); 19 } 20} 21 22ShaderObjectLayoutImpl ::SubObjectRangeStride ::SubObjectRangeStride ( 23 slang::TypeLayoutReflection * typeLayout ) 24 :BindingOffset (typeLayout ) 25{ 26if (auto pendingLayout = typeLayout -> getPendingDataTypeLayout ()) 27 { 28pendingOrdinaryData = (uint32_t )typeLayout -> getStride (); 29 } 30} 31 32Result ShaderObjectLayoutImpl ::Builder ::setElementTypeLayout ( 33 slang::TypeLayoutReflection * typeLayout ) 34{ 35typeLayout = _unwrapParameterGroups (typeLayout ,m_containerType ); 36 37m_elementTypeLayout = typeLayout ; 38 39m_totalOrdinaryDataSize = (uint32_t )typeLayout -> getSize (); 40 41// Compute the binding ranges that are used to store 42// the logical contents of the object in memory. 43 44SlangInt bindingRangeCount = typeLayout -> getBindingRangeCount (); 45for (SlangInt r = 0 ;r < bindingRangeCount ;++ r ) 46 { 47 slang::BindingType slangBindingType = typeLayout -> getBindingRangeType (r ); 48SlangInt count = typeLayout -> getBindingRangeBindingCount (r ); 49 slang::TypeLayoutReflection * slangLeafTypeLayout = 50typeLayout -> getBindingRangeLeafTypeLayout (r ); 51 52BindingRangeInfo bindingRangeInfo ; 53bindingRangeInfo .bindingType = slangBindingType ; 54bindingRangeInfo .count = count ; 55bindingRangeInfo .isSpecializable = typeLayout -> isBindingRangeSpecializable (r ); 56switch (slangBindingType ) 57 { 58case slang::BindingType ::ConstantBuffer : 59case slang::BindingType ::ParameterBlock : 60case slang::BindingType ::ExistentialValue : 61bindingRangeInfo .baseIndex = m_subObjectCount ; 62bindingRangeInfo .subObjectIndex = m_subObjectCount ; 63m_subObjectCount += count ; 64break ; 65case slang::BindingType ::RawBuffer : 66case slang::BindingType ::MutableRawBuffer : 67if (slangLeafTypeLayout -> getType ()-> getElementType ()!= nullptr ) 68 { 69// A structured buffer occupies both a resource slot and 70// a sub-object slot. 71bindingRangeInfo .subObjectIndex = m_subObjectCount ; 72m_subObjectCount += count ; 73 } 74if (slangBindingType == slang::BindingType ::RawBuffer ) 75 { 76bindingRangeInfo .baseIndex = m_srvCount ; 77m_srvCount += count ; 78m_srvRanges .add (r ); 79 } 80else 81 { 82bindingRangeInfo .baseIndex = m_uavCount ; 83m_uavCount += count ; 84m_uavRanges .add (r ); 85 } 86break ; 87case slang::BindingType ::Sampler : 88bindingRangeInfo .baseIndex = m_samplerCount ; 89m_samplerCount += count ; 90m_samplerRanges .add (r ); 91break ; 92 93case slang::BindingType ::CombinedTextureSampler : 94break ; 95case slang::BindingType ::MutableTexture : 96case slang::BindingType ::MutableTypedBuffer : 97bindingRangeInfo .baseIndex = m_uavCount ; 98m_uavCount += count ; 99m_uavRanges .add (r ); 100break ; 101 102case slang::BindingType ::VaryingInput : 103break ; 104 105case slang::BindingType ::VaryingOutput : 106break ; 107 108default : 109bindingRangeInfo .baseIndex = m_srvCount ; 110m_srvCount += count ; 111m_srvRanges .add (r ); 112break ; 113 } 114 115// We'd like to extract the information on the D3D11 shader 116// register that this range should bind into. 117// 118// A binding range represents a logical member of the shader 119// object type, and it may encompass zero or more *descriptor 120// ranges* that describe how it is physically bound to pipeline 121// state. 122// 123// If the current bindign range is backed by at least one descriptor 124// range then we can query the register offset of that descriptor 125// range. We expect that in the common case there will be exactly 126// one descriptor range, and we can extract the information easily. 127// 128// TODO: we might eventually need to special-case our handling 129// of combined texture-sampler ranges since they will need to 130// store two different offsets. 131// 132if (typeLayout -> getBindingRangeDescriptorRangeCount (r )!= 0 ) 133 { 134// The Slang reflection information organizes the descriptor ranges 135// into "descriptor sets" but D3D11 has no notion like that so we 136// expect all ranges belong to a single set. 137// 138SlangInt descriptorSetIndex = typeLayout -> getBindingRangeDescriptorSetIndex (r ); 139SLANG_ASSERT (descriptorSetIndex == 0 ); 140 141SlangInt descriptorRangeIndex = typeLayout -> getBindingRangeFirstDescriptorRangeIndex (r ); 142auto registerOffset = typeLayout -> getDescriptorSetDescriptorRangeIndexOffset ( 143descriptorSetIndex , 144descriptorRangeIndex ); 145 146bindingRangeInfo .registerOffset = (uint32_t )registerOffset ; 147 } 148 149m_bindingRanges .add (bindingRangeInfo ); 150 } 151 152SlangInt subObjectRangeCount = typeLayout -> getSubObjectRangeCount (); 153for (SlangInt r = 0 ;r < subObjectRangeCount ;++ r ) 154 { 155SlangInt bindingRangeIndex = typeLayout -> getSubObjectRangeBindingRangeIndex (r ); 156auto & bindingRange = m_bindingRanges [bindingRangeIndex ]; 157 158auto slangBindingType = typeLayout -> getBindingRangeType (bindingRangeIndex ); 159 slang::TypeLayoutReflection * slangLeafTypeLayout = 160typeLayout -> getBindingRangeLeafTypeLayout (bindingRangeIndex ); 161 162SubObjectRangeInfo subObjectRange ; 163subObjectRange .bindingRangeIndex = bindingRangeIndex ; 164 165// We will use Slang reflection information to extract the offset and stride 166// information for each sub-object range. 167// 168subObjectRange .offset = SubObjectRangeOffset (typeLayout -> getSubObjectRangeOffset (r )); 169subObjectRange .stride = SubObjectRangeStride (slangLeafTypeLayout ); 170 171// A sub-object range can either represent a sub-object of a known 172// type, like a `ConstantBuffer<Foo>` or `ParameterBlock<Foo>` 173// *or* it can represent a sub-object of some existential type (e.g., `IBar`). 174// 175RefPtr < ShaderObjectLayoutImpl > subObjectLayout ; 176switch (slangBindingType ) 177 { 178default : 179 { 180// In the case of `ConstantBuffer<X>` or `ParameterBlock<X>` 181// we can construct a layout from the element type directly. 182// 183auto elementTypeLayout = slangLeafTypeLayout -> getElementTypeLayout (); 184createForElementType ( 185m_renderer , 186m_session , 187elementTypeLayout , 188subObjectLayout .writeRef ()); 189 } 190break ; 191 192case slang::BindingType ::ExistentialValue : 193// In the case of an interface-type sub-object range, we can only 194// construct a layout if we have static specialization information 195// that tells us what type we expect to find in that range. 196// 197// The static specialization information is expected to take the 198// form of a "pending" type layotu attached to the interface type 199// of the leaf type layout. 200// 201if (auto pendingTypeLayout = slangLeafTypeLayout -> getPendingDataTypeLayout ()) 202 { 203createForElementType ( 204m_renderer , 205m_session , 206pendingTypeLayout , 207subObjectLayout .writeRef ()); 208 209// An interface-type range that includes ordinary data can 210// increase the size of the ordinary data buffer we need to 211// allocate for the parent object. 212// 213uint32_t ordinaryDataEnd = 214subObjectRange .offset .pendingOrdinaryData + 215 (uint32_t )bindingRange .count * subObjectRange .stride .pendingOrdinaryData ; 216 217if (ordinaryDataEnd > m_totalOrdinaryDataSize ) 218 { 219m_totalOrdinaryDataSize = ordinaryDataEnd ; 220 } 221 } 222 } 223subObjectRange .layout = subObjectLayout ; 224 225m_subObjectRanges .add (subObjectRange ); 226 } 227return SLANG_OK ; 228} 229 230SlangResult ShaderObjectLayoutImpl ::Builder ::build (ShaderObjectLayoutImpl ** outLayout ) 231{ 232auto layout = RefPtr < ShaderObjectLayoutImpl > (new ShaderObjectLayoutImpl ()); 233SLANG_RETURN_ON_FAIL (layout -> _init (this )); 234 235returnRefPtrMove (outLayout ,layout ); 236return SLANG_OK ; 237} 238 239Result ShaderObjectLayoutImpl ::createForElementType ( 240RendererBase * renderer , 241 slang::ISession * session , 242 slang::TypeLayoutReflection * elementType , 243ShaderObjectLayoutImpl ** outLayout ) 244{ 245Builder builder (renderer ,session ); 246builder .setElementTypeLayout (elementType ); 247return builder .build (outLayout ); 248} 249 250Result ShaderObjectLayoutImpl ::_init (Builder const * builder ) 251{ 252auto renderer = builder -> m_renderer ; 253 254initBase (renderer ,builder -> m_session ,builder -> m_elementTypeLayout ); 255 256m_bindingRanges = builder -> m_bindingRanges ; 257m_srvRanges = builder -> m_srvRanges ; 258m_uavRanges = builder -> m_uavRanges ; 259m_samplerRanges = builder -> m_samplerRanges ; 260 261m_srvCount = builder -> m_srvCount ; 262m_samplerCount = builder -> m_samplerCount ; 263m_uavCount = builder -> m_uavCount ; 264m_subObjectCount = builder -> m_subObjectCount ; 265m_subObjectRanges = builder -> m_subObjectRanges ; 266 267m_totalOrdinaryDataSize = builder -> m_totalOrdinaryDataSize ; 268 269m_containerType = builder -> m_containerType ; 270return SLANG_OK ; 271} 272 273Result RootShaderObjectLayoutImpl ::Builder ::build (RootShaderObjectLayoutImpl ** outLayout ) 274{ 275RefPtr < RootShaderObjectLayoutImpl > layout = new RootShaderObjectLayoutImpl (); 276SLANG_RETURN_ON_FAIL (layout -> _init (this )); 277 278returnRefPtrMove (outLayout ,layout ); 279return SLANG_OK ; 280} 281 282void RootShaderObjectLayoutImpl ::Builder ::addGlobalParams ( 283 slang::VariableLayoutReflection * globalsLayout ) 284{ 285setElementTypeLayout (globalsLayout -> getTypeLayout ()); 286m_pendingDataOffset = BindingOffset (globalsLayout ).pending ; 287} 288 289void RootShaderObjectLayoutImpl ::Builder ::addEntryPoint ( 290SlangStage stage , 291ShaderObjectLayoutImpl * entryPointLayout , 292 slang::EntryPointLayout * slangEntryPoint ) 293{ 294EntryPointInfo info ; 295info .layout = entryPointLayout ; 296info .offset = BindingOffset (slangEntryPoint -> getVarLayout ()); 297m_entryPoints .add (info ); 298} 299 300Result RootShaderObjectLayoutImpl ::create ( 301RendererBase * renderer , 302 slang::IComponentType * program , 303 slang::ProgramLayout * programLayout , 304RootShaderObjectLayoutImpl ** outLayout ) 305{ 306RootShaderObjectLayoutImpl ::Builder builder (renderer ,program ,programLayout ); 307builder .addGlobalParams (programLayout -> getGlobalParamsVarLayout ()); 308 309SlangInt entryPointCount = programLayout -> getEntryPointCount (); 310for (SlangInt e = 0 ;e < entryPointCount ;++ e ) 311 { 312auto slangEntryPoint = programLayout -> getEntryPointByIndex (e ); 313RefPtr < ShaderObjectLayoutImpl > entryPointLayout ; 314SLANG_RETURN_ON_FAIL (ShaderObjectLayoutImpl ::createForElementType ( 315renderer , 316program -> getSession (), 317slangEntryPoint -> getTypeLayout (), 318entryPointLayout .writeRef ())); 319builder .addEntryPoint (slangEntryPoint -> getStage (),entryPointLayout ,slangEntryPoint ); 320 } 321 322SLANG_RETURN_ON_FAIL (builder .build (outLayout )); 323 324return SLANG_OK ; 325} 326 327Result RootShaderObjectLayoutImpl ::_init (Builder const * builder ) 328{ 329auto renderer = builder -> m_renderer ; 330 331SLANG_RETURN_ON_FAIL (Super ::_init (builder )); 332 333m_program = builder -> m_program ; 334m_programLayout = builder -> m_programLayout ; 335m_entryPoints = builder -> m_entryPoints ; 336m_pendingDataOffset = builder -> m_pendingDataOffset ; 337m_slangSession = m_program -> getSession (); 338 339return SLANG_OK ; 340} 341 342}// namespace d3d11 343}// namespace gfx