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