diff options
| author | Yong He <yonghe@outlook.com> | 2021-05-21 16:38:33 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-05-21 16:38:33 -0700 |
| commit | 7f8a9994d0bd99a171a1daa0bce46d92c02ccffd (patch) | |
| tree | 0b187e63ab5b9ce6f5ab41266fedaec44091a217 /tools/gfx/d3d12/render-d3d12.cpp | |
| parent | 172538fdb418f7a2faab1f5a410f3b2cb8e18ba5 (diff) | |
[gfx] Support StructuredBuffer<IInterface>. (#1851)
Co-authored-by: T. Foley <tfoleyNV@users.noreply.github.com>
Diffstat (limited to 'tools/gfx/d3d12/render-d3d12.cpp')
| -rw-r--r-- | tools/gfx/d3d12/render-d3d12.cpp | 293 |
1 files changed, 55 insertions, 238 deletions
diff --git a/tools/gfx/d3d12/render-d3d12.cpp b/tools/gfx/d3d12/render-d3d12.cpp index da169c03b..26b774b1a 100644 --- a/tools/gfx/d3d12/render-d3d12.cpp +++ b/tools/gfx/d3d12/render-d3d12.cpp @@ -232,17 +232,9 @@ public: } }; - class ResourceViewImpl : public IResourceView, public ComObject + class ResourceViewImpl : public ResourceViewBase { public: - SLANG_COM_OBJECT_IUNKNOWN_ALL - IResourceView* getInterface(const Guid& guid) - { - if (guid == GfxGUID::IID_ISlangUnknown || guid == GfxGUID::IID_IResourceView) - return static_cast<IResourceView*>(this); - return nullptr; - } - public: RefPtr<Resource> m_resource; D3D12Descriptor m_descriptor; RefPtr<D3D12GeneralDescriptorHeap> m_allocator; @@ -718,7 +710,11 @@ public: uint32_t count; /// A "flat" index for this range in whatever array provides backing storage for it - uint32_t flatIndex; + uint32_t baseIndex; + + /// An index into the sub-object array if this binding range is treated + /// as a sub-object. + uint32_t subObjectIndex; }; /// Offset information for a sub-object range @@ -802,12 +798,17 @@ public: /// The number of root parameter consumed by (transitive) sub-objects uint32_t m_childRootParameterCount = 0; - /// The total size in bytes of the ordinary data for this object and transitive sub-objects + /// The total size in bytes of the ordinary data for this object and transitive sub-object. uint32_t m_totalOrdinaryDataSize = 0; + /// The container type of this shader object. When `m_containerType` is + /// `StructuredBuffer` or `UnsizedArray`, this shader object represents a collection + /// instead of a single object. + ShaderObjectContainerType m_containerType = ShaderObjectContainerType::None; + Result setElementTypeLayout(slang::TypeLayoutReflection* typeLayout) { - typeLayout = _unwrapParameterGroups(typeLayout); + typeLayout = _unwrapParameterGroups(typeLayout, m_containerType); m_elementTypeLayout = typeLayout; // If the type contains any ordinary data, then we must reserve a buffer @@ -849,12 +850,24 @@ public: case slang::BindingType::ConstantBuffer: case slang::BindingType::ParameterBlock: case slang::BindingType::ExistentialValue: - bindingRangeInfo.flatIndex = m_subObjectCount; + bindingRangeInfo.baseIndex = m_subObjectCount; + bindingRangeInfo.subObjectIndex = m_subObjectCount; m_subObjectCount += count; break; - + case slang::BindingType::RawBuffer: + case slang::BindingType::MutableRawBuffer: + if (slangLeafTypeLayout->getType()->getElementType() != nullptr) + { + // A structured buffer occupies both a resource slot and + // a sub-object slot. + bindingRangeInfo.subObjectIndex = m_subObjectCount; + m_subObjectCount += count; + } + bindingRangeInfo.baseIndex = m_ownCounts.resource; + m_ownCounts.resource += count; + break; case slang::BindingType::Sampler: - bindingRangeInfo.flatIndex = m_ownCounts.sampler; + bindingRangeInfo.baseIndex = m_ownCounts.sampler; m_ownCounts.sampler += count; break; @@ -867,7 +880,7 @@ public: break; default: - bindingRangeInfo.flatIndex = m_ownCounts.resource; + bindingRangeInfo.baseIndex = m_ownCounts.resource; m_ownCounts.resource += count; break; } @@ -1092,8 +1105,6 @@ public: BindingRangeInfo const& getBindingRange(Index index) { return m_bindingRanges[index]; } - slang::TypeLayoutReflection* getElementTypeLayout() { return m_elementTypeLayout; } - uint32_t getResourceSlotCount() { return m_ownCounts.resource; } uint32_t getSamplerSlotCount() { return m_ownCounts.sampler; } Index getSubObjectSlotCount() { return m_subObjectCount; } @@ -1128,6 +1139,8 @@ public: initBase(renderer, builder->m_elementTypeLayout); + m_containerType = builder->m_containerType; + m_bindingRanges = _Move(builder->m_bindingRanges); m_subObjectRanges = builder->m_subObjectRanges; @@ -2033,7 +2046,11 @@ public: RefPtr<RootShaderObjectLayoutImpl> m_rootObjectLayout; }; - class ShaderObjectImpl : public ShaderObjectBase + class ShaderObjectImpl + : public ShaderObjectBaseImpl< + ShaderObjectImpl, + ShaderObjectLayoutImpl, + SimpleShaderObjectData> { public: static Result create( @@ -2064,25 +2081,14 @@ public: return SLANG_OK; } - ShaderObjectLayoutImpl* getLayout() - { - return static_cast<ShaderObjectLayoutImpl*>(m_layout.Ptr()); - } - - SLANG_NO_THROW slang::TypeLayoutReflection* SLANG_MCALL getElementTypeLayout() - SLANG_OVERRIDE - { - return m_layout->getElementTypeLayout(); - } - SLANG_NO_THROW Result SLANG_MCALL setData(ShaderOffset const& inOffset, void const* data, size_t inSize) SLANG_OVERRIDE { Index offset = inOffset.uniformOffset; Index size = inSize; - char* dest = m_ordinaryData.getBuffer(); - Index availableSize = m_ordinaryData.getCount(); + char* dest = m_data.getBuffer(); + Index availableSize = m_data.getCount(); // TODO: We really should bounds-check access rather than silently ignoring sets // that are too large, but we have several test cases that set more data than @@ -2103,133 +2109,6 @@ public: return SLANG_OK; } - virtual SLANG_NO_THROW Result SLANG_MCALL - setObject(ShaderOffset const& offset, IShaderObject* object) SLANG_OVERRIDE - { - if (offset.bindingRangeIndex < 0) - return SLANG_E_INVALID_ARG; - auto layout = getLayout(); - if (offset.bindingRangeIndex >= layout->getBindingRangeCount()) - return SLANG_E_INVALID_ARG; - - auto subObject = static_cast<ShaderObjectImpl*>(object); - - auto bindingRangeIndex = offset.bindingRangeIndex; - auto& bindingRange = layout->getBindingRange(bindingRangeIndex); - - m_objects[bindingRange.flatIndex + offset.bindingArrayIndex] = subObject; - - // If the range being assigned into represents an interface/existential-type leaf field, - // then we need to consider how the `object` being assigned here affects specialization. - // We may also need to assign some data from the sub-object into the ordinary data - // buffer for the parent object. - // - if (bindingRange.bindingType == slang::BindingType::ExistentialValue) - { - // A leaf field of interface type is laid out inside of the parent object - // as a tuple of `(RTTI, WitnessTable, Payload)`. The layout of these fields - // is a contract between the compiler and any runtime system, so we will - // need to rely on details of the binary layout. - - // We start by querying the layout/type of the concrete value that the application - // is trying to store into the field, and also the layout/type of the leaf - // existential-type field itself. - // - auto concreteTypeLayout = subObject->getElementTypeLayout(); - auto concreteType = concreteTypeLayout->getType(); - // - auto existentialTypeLayout = - layout->getElementTypeLayout()->getBindingRangeLeafTypeLayout( - bindingRangeIndex); - auto existentialType = existentialTypeLayout->getType(); - - // The first field of the tuple (offset zero) is the run-time type information - // (RTTI) ID for the concrete type being stored into the field. - // - // TODO: We need to be able to gather the RTTI type ID from `object` and then - // use `setData(offset, &TypeID, sizeof(TypeID))`. - - // The second field of the tuple (offset 8) is the ID of the "witness" for the - // conformance of the concrete type to the interface used by this field. - // - auto witnessTableOffset = offset; - witnessTableOffset.uniformOffset += 8; - // - // Conformances of a type to an interface are computed and then stored by the - // Slang runtime, so we can look up the ID for this particular conformance (which - // will create it on demand). - // - ComPtr<slang::ISession> slangSession; - SLANG_RETURN_ON_FAIL(getRenderer()->getSlangSession(slangSession.writeRef())); - // - // Note: If the type doesn't actually conform to the required interface for - // this sub-object range, then this is the point where we will detect that - // fact and error out. - // - uint32_t conformanceID = 0xFFFFFFFF; - SLANG_RETURN_ON_FAIL(slangSession->getTypeConformanceWitnessSequentialID( - concreteType, existentialType, &conformanceID)); - // - // Once we have the conformance ID, then we can write it into the object - // at the required offset. - // - SLANG_RETURN_ON_FAIL( - setData(witnessTableOffset, &conformanceID, sizeof(conformanceID))); - - // The third field of the tuple (offset 16) is the "payload" that is supposed to - // hold the data for a value of the given concrete type. - // - auto payloadOffset = offset; - payloadOffset.uniformOffset += 16; - - // There are two cases we need to consider here for how the payload might be used: - // - // * If the concrete type of the value being bound is one that can "fit" into the - // available payload space, then it should be stored in the payload. - // - // * If the concrete type of the value cannot fit in the payload space, then it - // will need to be stored somewhere else. - // - if (_doesValueFitInExistentialPayload(concreteTypeLayout, existentialTypeLayout)) - { - // If the value can fit in the payload area, then we will go ahead and copy - // its bytes into that area. - // - setData( - payloadOffset, - subObject->m_ordinaryData.getBuffer(), - subObject->m_ordinaryData.getCount()); - } - else - { - // If the value does *not *fit in the payload area, then there is nothing - // we can do at this point (beyond saving a reference to the sub-object, which - // was handled above). - // - // Once all the sub-objects have been set into the parent object, we can - // compute a specialized layout for it, and that specialized layout can tell - // us where the data for these sub-objects has been laid out. - return SLANG_E_NOT_IMPLEMENTED; - } - } - return SLANG_OK; - } - - virtual SLANG_NO_THROW Result SLANG_MCALL - getObject(ShaderOffset const& offset, IShaderObject** outObject) SLANG_OVERRIDE - { - SLANG_ASSERT(outObject); - if (offset.bindingRangeIndex < 0) - return SLANG_E_INVALID_ARG; - auto layout = getLayout(); - if (offset.bindingRangeIndex >= layout->getBindingRangeCount()) - return SLANG_E_INVALID_ARG; - auto& bindingRange = layout->getBindingRange(offset.bindingRangeIndex); - - returnComPtr(outObject, m_objects[bindingRange.flatIndex + offset.bindingArrayIndex]); - return SLANG_OK; - } - SLANG_NO_THROW Result SLANG_MCALL setResource(ShaderOffset const& offset, IResourceView* resourceView) SLANG_OVERRIDE { @@ -2242,15 +2121,15 @@ public: auto resourceViewImpl = static_cast<ResourceViewImpl*>(resourceView); auto& bindingRange = layout->getBindingRange(offset.bindingRangeIndex); - auto descriptorSlotIndex = bindingRange.flatIndex + (int32_t)offset.bindingArrayIndex; + auto descriptorSlotIndex = bindingRange.baseIndex + (int32_t)offset.bindingArrayIndex; // Hold a reference to the resource to prevent its destruction. - m_boundResources[bindingRange.flatIndex + offset.bindingArrayIndex] = + m_boundResources[bindingRange.baseIndex + offset.bindingArrayIndex] = resourceViewImpl->m_resource; ID3D12Device* d3dDevice = static_cast<D3D12Device*>(getDevice())->m_device; d3dDevice->CopyDescriptorsSimple( 1, m_descriptorSet.resourceTable.getCpuHandle( - bindingRange.flatIndex + (int32_t)offset.bindingArrayIndex), + bindingRange.baseIndex + (int32_t)offset.bindingArrayIndex), resourceViewImpl->m_descriptor.cpuHandle, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); return SLANG_OK; @@ -2270,7 +2149,7 @@ public: d3dDevice->CopyDescriptorsSimple( 1, m_descriptorSet.samplerTable.getCpuHandle( - bindingRange.flatIndex + + bindingRange.baseIndex + (int32_t)offset.bindingArrayIndex), samplerImpl->m_descriptor.cpuHandle, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER); @@ -2313,66 +2192,6 @@ public: } public: - // Appends all types that are used to specialize the element type of this shader object in - // `args` list. - virtual Result collectSpecializationArgs(ExtendedShaderObjectTypeList& args) override - { - auto& subObjectRanges = getLayout()->getSubObjectRanges(); - // The following logic is built on the assumption that all fields that involve - // existential types (and therefore require specialization) will results in a sub-object - // range in the type layout. This allows us to simply scan the sub-object ranges to find - // out all specialization arguments. - Index subObjectRangeCount = subObjectRanges.getCount(); - for (Index subObjectRangeIndex = 0; subObjectRangeIndex < subObjectRangeCount; - subObjectRangeIndex++) - { - auto const& subObjectRange = subObjectRanges[subObjectRangeIndex]; - auto const& bindingRange = - getLayout()->getBindingRange(subObjectRange.bindingRangeIndex); - - Index count = bindingRange.count; - SLANG_ASSERT(count == 1); - - Index subObjectIndexInRange = 0; - auto subObject = m_objects[bindingRange.flatIndex + subObjectIndexInRange]; - - switch (bindingRange.bindingType) - { - case slang::BindingType::ExistentialValue: - { - // A binding type of `ExistentialValue` means the sub-object represents a - // interface-typed field. In this case the specialization argument for this - // field is the actual specialized type of the bound shader object. If the - // shader object's type is an ordinary type without existential fields, then - // the type argument will simply be the ordinary type. But if the sub - // object's type is itself a specialized type, we need to make sure to use - // that type as the specialization argument. - - ExtendedShaderObjectType specializedSubObjType; - SLANG_RETURN_ON_FAIL( - subObject->getSpecializedShaderObjectType(&specializedSubObjType)); - args.add(specializedSubObjType); - break; - } - case slang::BindingType::ParameterBlock: - case slang::BindingType::ConstantBuffer: - // Currently we only handle the case where the field's type is - // `ParameterBlock<SomeStruct>` or `ConstantBuffer<SomeStruct>`, where - // `SomeStruct` is a struct type (not directly an interface type). In this case, - // we just recursively collect the specialization arguments from the bound sub - // object. - SLANG_RETURN_ON_FAIL(subObject->collectSpecializationArgs(args)); - // TODO: we need to handle the case where the field is of the form - // `ParameterBlock<IFoo>`. We should treat this case the same way as the - // `ExistentialValue` case here, but currently we lack a mechanism to - // distinguish the two scenarios. - break; - } - // TODO: need to handle another case where specialization happens on resources - // fields e.g. `StructuredBuffer<IFoo>`. - } - return SLANG_OK; - } protected: Result init( @@ -2399,8 +2218,8 @@ public: size_t uniformSize = layout->getElementTypeLayout()->getSize(); if (uniformSize) { - m_ordinaryData.setCount(uniformSize); - memset(m_ordinaryData.getBuffer(), 0, uniformSize); + m_data.setCount(uniformSize); + memset(m_data.getBuffer(), 0, uniformSize); } // Each shader object will own CPU descriptor heap memory @@ -2458,7 +2277,7 @@ public: RefPtr<ShaderObjectImpl> subObject; SLANG_RETURN_ON_FAIL( ShaderObjectImpl::create(device, subObjectLayout, subObject.writeRef())); - m_objects[bindingRangeInfo.flatIndex + i] = subObject; + m_objects[bindingRangeInfo.subObjectIndex + i] = subObject; } } @@ -2474,8 +2293,8 @@ public: size_t destSize, ShaderObjectLayoutImpl* specializedLayout) { - auto src = m_ordinaryData.getBuffer(); - auto srcSize = size_t(m_ordinaryData.getCount()); + auto src = m_data.getBuffer(); + auto srcSize = size_t(m_data.getCount()); SLANG_ASSERT(srcSize <= destSize); @@ -2550,7 +2369,7 @@ public: for (uint32_t i = 0; i < count; ++i) { - auto subObject = m_objects[bindingRangeInfo.flatIndex + i]; + auto subObject = m_objects[bindingRangeInfo.subObjectIndex + i]; RefPtr<ShaderObjectLayoutImpl> subObjectLayout; SLANG_RETURN_ON_FAIL( @@ -2863,7 +2682,7 @@ public: { auto& subObjectRange = specializedLayout->getSubObjectRange(i); auto& bindingRange = specializedLayout->getBindingRange(subObjectRange.bindingRangeIndex); - auto baseIndex = bindingRange.flatIndex; + auto subObjectIndex = bindingRange.subObjectIndex; auto subObjectLayout = subObjectRange.layout.Ptr(); BindingOffset rangeOffset = offset; @@ -2878,7 +2697,7 @@ public: auto objOffset = rangeOffset; for (uint32_t j = 0; j < bindingRange.count; j++) { - auto& object = m_objects[baseIndex + j]; + auto& object = m_objects[subObjectIndex + j]; object->bindAsConstantBuffer(context, descriptorSet, objOffset, subObjectLayout); objOffset += rangeStride; } @@ -2890,7 +2709,7 @@ public: auto objOffset = rangeOffset; for (uint32_t j = 0; j < bindingRange.count; j++) { - auto& object = m_objects[baseIndex + j]; + auto& object = m_objects[subObjectIndex + j]; object->bindAsParameterBlock(context, objOffset, subObjectLayout); objOffset += rangeStride; } @@ -2903,7 +2722,7 @@ public: auto objOffset = rangeOffset; for (uint32_t j = 0; j < bindingRange.count; j++) { - auto& object = m_objects[baseIndex + j]; + auto& object = m_objects[subObjectIndex + j]; object->bindAsValue(context, descriptorSet, objOffset, subObjectLayout); objOffset += rangeStride; } @@ -2915,10 +2734,6 @@ public: return SLANG_OK; } - /// Any "ordinary" / uniform data for this object - List<char> m_ordinaryData; - - List<RefPtr<ShaderObjectImpl>> m_objects; /// A CPU-memory descriptor set holding any descriptors used to represent the resources/samplers in this object's state DescriptorSet m_descriptorSet; @@ -2967,7 +2782,9 @@ public: auto renderer = getRenderer(); RefPtr<ShaderObjectLayoutImpl> layout; SLANG_RETURN_ON_FAIL(renderer->getShaderObjectLayout( - extendedType.slangType, (ShaderObjectLayoutBase**)layout.writeRef())); + extendedType.slangType, + m_layout->getContainerType(), + (ShaderObjectLayoutBase**)layout.writeRef())); returnRefPtrMove(outLayout, layout); return SLANG_OK; |
