diff options
Diffstat (limited to 'tools')
| -rw-r--r-- | tools/gfx-util/shader-cursor.cpp | 50 | ||||
| -rw-r--r-- | tools/gfx/d3d12/render-d3d12.cpp | 466 | ||||
| -rw-r--r-- | tools/render-test/render-test-main.cpp | 28 | ||||
| -rw-r--r-- | tools/render-test/shader-input-layout.cpp | 11 | ||||
| -rw-r--r-- | tools/render-test/slang-support.cpp | 4 |
5 files changed, 363 insertions, 196 deletions
diff --git a/tools/gfx-util/shader-cursor.cpp b/tools/gfx-util/shader-cursor.cpp index c2c34f5a5..b188901ec 100644 --- a/tools/gfx-util/shader-cursor.cpp +++ b/tools/gfx-util/shader-cursor.cpp @@ -145,19 +145,45 @@ Result ShaderCursor::getField(const char* name, const char* nameEnd, ShaderCurso ShaderCursor ShaderCursor::getElement(SlangInt index) const { // TODO: need to auto-dereference various buffer types... - - if (m_typeLayout->getKind() == slang::TypeReflection::Kind::Array) + switch( m_typeLayout->getKind() ) { - ShaderCursor elementCursor; - elementCursor.m_baseObject = m_baseObject; - elementCursor.m_typeLayout = m_typeLayout->getElementTypeLayout(); - elementCursor.m_offset.uniformOffset = - m_offset.uniformOffset + - index * m_typeLayout->getElementStride(SLANG_PARAMETER_CATEGORY_UNIFORM); - elementCursor.m_offset.bindingRangeIndex = m_offset.bindingRangeIndex; - elementCursor.m_offset.bindingArrayIndex = - m_offset.bindingArrayIndex * m_typeLayout->getElementCount() + index; - return elementCursor; + case slang::TypeReflection::Kind::Array: + { + ShaderCursor elementCursor; + elementCursor.m_baseObject = m_baseObject; + elementCursor.m_typeLayout = m_typeLayout->getElementTypeLayout(); + elementCursor.m_offset.uniformOffset = + m_offset.uniformOffset + + index * m_typeLayout->getElementStride(SLANG_PARAMETER_CATEGORY_UNIFORM); + elementCursor.m_offset.bindingRangeIndex = m_offset.bindingRangeIndex; + elementCursor.m_offset.bindingArrayIndex = + m_offset.bindingArrayIndex * m_typeLayout->getElementCount() + index; + return elementCursor; + } + break; + + case slang::TypeReflection::Kind::Struct: + { + // The logic here is similar to `getField()` except that we don't + // need to look up the field index based on a name first. + // + auto fieldIndex = index; + slang::VariableLayoutReflection* fieldLayout = + m_typeLayout->getFieldByIndex((unsigned int)fieldIndex); + if(!fieldLayout) + return ShaderCursor(); + + ShaderCursor fieldCursor; + fieldCursor.m_baseObject = m_baseObject; + fieldCursor.m_typeLayout = fieldLayout->getTypeLayout(); + fieldCursor.m_offset.uniformOffset = m_offset.uniformOffset + fieldLayout->getOffset(); + fieldCursor.m_offset.bindingRangeIndex = + m_offset.bindingRangeIndex + m_typeLayout->getFieldBindingRangeOffset(fieldIndex); + fieldCursor.m_offset.bindingArrayIndex = m_offset.bindingArrayIndex; + + return fieldCursor; + } + break; } return ShaderCursor(); diff --git a/tools/gfx/d3d12/render-d3d12.cpp b/tools/gfx/d3d12/render-d3d12.cpp index 6b818f100..891077a8b 100644 --- a/tools/gfx/d3d12/render-d3d12.cpp +++ b/tools/gfx/d3d12/render-d3d12.cpp @@ -1059,83 +1059,88 @@ public: } } + /// Stores offset information to apply to the reflected register/space for a descriptor range. + /// struct BindingRegisterOffset { - // The index to the physical descriptor set that stores the binding. - uint32_t descriptorSetIndex; - - uint32_t spaceOffset; // The `space` index as specified in shader. - uint32_t textureOffset; // `t` registers - uint32_t samplerOffset; // `s` registers - uint32_t constantBufferOffset; // `b` registers - uint32_t uavOffset; // `u` registers - void set(D3D12_DESCRIPTOR_RANGE_TYPE type, uint32_t value) + uint32_t spaceOffset = 0; // The `space` index as specified in shader. + + /// An offset to apply for each D3D12 register class, as given + /// by a `D3D12_DESCRIPTOR_RANGE_TYPE`. + /// + /// Note that the `D3D12_DESCRIPTOR_RANGE_TYPE` enumeration has + /// values between 0 and 3, inclusive. + /// + uint32_t offsetForRangeType[4] = {0, 0, 0, 0}; + + uint32_t& operator[](D3D12_DESCRIPTOR_RANGE_TYPE type) { - switch (type) - { - case D3D12_DESCRIPTOR_RANGE_TYPE_CBV: - constantBufferOffset = value; - return; - case D3D12_DESCRIPTOR_RANGE_TYPE_UAV: - uavOffset = value; - return; - case D3D12_DESCRIPTOR_RANGE_TYPE_SRV: - textureOffset = value; - return; - case D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER: - samplerOffset = value; - return; - default: - break; - } + return offsetForRangeType[int(type)]; } - uint32_t get(D3D12_DESCRIPTOR_RANGE_TYPE type) + + uint32_t operator[](D3D12_DESCRIPTOR_RANGE_TYPE type) const { - switch (type) - { - case D3D12_DESCRIPTOR_RANGE_TYPE_CBV: - return constantBufferOffset; - case D3D12_DESCRIPTOR_RANGE_TYPE_UAV: - return uavOffset; - case D3D12_DESCRIPTOR_RANGE_TYPE_SRV: - return textureOffset; - case D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER: - return samplerOffset; - default: - return 0; - } + return offsetForRangeType[int(type)]; } }; - void addDescriptorRange( - slang::TypeLayoutReflection* typeLayout, - D3D12_DESCRIPTOR_RANGE_TYPE rangeType, - Index bindingRangeIndex, - BindingRegisterOffset* offset, - BindingRegisterOffset* newOffset) + /// Add a new descriptor set to the layout being computed. + /// + /// Note that a "descriptor set" in the layout may amount to + /// zero, one, or two different descriptor *tables* in the + /// final D3D12 root signature. Each descriptor set may + /// contain zero or more view ranges (CBV/SRV/UAV) and zero + /// or more sampler ranges. It maps to a view descriptor table + /// if the number of view ranges is non-zero and to a sampler + /// descriptor table if the number of sampler ranges is non-zero. + /// + uint32_t addDescriptorSet() + { + auto result = (uint32_t) m_descriptorSets.getCount(); + m_descriptorSets.add(DescriptorSetLayout{}); + return result; + } + + /// Add one descriptor range as specified in Slang reflection information to the layout. + /// + /// The layout information is taken from `typeLayout` for the descriptor + /// range with the given `descriptorRangeIndex` within the logical + /// descriptor set (reflected by Slang) with the given `logicalDescriptorSetIndex`. + /// + /// The `physicalDescriptorSetIndex` is the index in the `m_descriptorSets` array of + /// the descriptor set that the range should be added to. + /// + /// The `offset` encodes information about space and/or register offsets that + /// should be applied to descrptor ranges. + /// + /// This operation can fail if the given descriptor range encodes a range that + /// doesn't map to anything directly supported by D3D12. Higher-level routines + /// will often want to ignore such failures. + /// + Result addDescriptorRange( + slang::TypeLayoutReflection* typeLayout, + Index physicalDescriptorSetIndex, + BindingRegisterOffset const& offset, + Index logicalDescriptorSetIndex, + Index descriptorRangeIndex) { + auto& descriptorSet = m_descriptorSets[physicalDescriptorSetIndex]; + + auto bindingType = typeLayout->getDescriptorSetDescriptorRangeType(logicalDescriptorSetIndex, descriptorRangeIndex); + auto count = typeLayout->getDescriptorSetDescriptorRangeDescriptorCount(logicalDescriptorSetIndex, descriptorRangeIndex); + auto index = typeLayout->getDescriptorSetDescriptorRangeIndexOffset(logicalDescriptorSetIndex, descriptorRangeIndex); + auto space = typeLayout->getDescriptorSetSpaceOffset(logicalDescriptorSetIndex); + + D3D12_DESCRIPTOR_RANGE_TYPE rangeType; + SLANG_RETURN_ON_FAIL(translateDescriptorRangeType(bindingType, &rangeType)); + D3D12_DESCRIPTOR_RANGE range = {}; range.RangeType = rangeType; - auto descriptorRangeIndex = - typeLayout->getBindingRangeFirstDescriptorRangeIndex(bindingRangeIndex); - auto relativeSpaceIndex = - (uint32_t)typeLayout->getBindingRangeDescriptorSetIndex(bindingRangeIndex); - auto space = offset->spaceOffset + relativeSpaceIndex; - // Update descriptor range descs in current descriptor set. - auto& descriptorSet = m_descriptorSets[offset->descriptorSetIndex]; - range.NumDescriptors = - (UINT)typeLayout->getDescriptorSetDescriptorRangeDescriptorCount( - relativeSpaceIndex, descriptorRangeIndex); - range.BaseShaderRegister = - (UINT)typeLayout->getDescriptorSetDescriptorRangeIndexOffset( - relativeSpaceIndex, descriptorRangeIndex) + - offset->get(range.RangeType); - newOffset->set( - range.RangeType, - Math::Max(range.BaseShaderRegister + 1, newOffset->get(range.RangeType))); + range.NumDescriptors = (UINT) count; + range.BaseShaderRegister = (UINT) index + offset[rangeType]; + range.RegisterSpace = (UINT) space; range.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND; - range.RegisterSpace = space; if (range.RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER) { descriptorSet.m_samplerRanges.add(range); @@ -1146,110 +1151,204 @@ public: descriptorSet.m_resourceRanges.add(range); descriptorSet.m_resourceCount += range.NumDescriptors; } + + return SLANG_OK; } - void addObject(slang::TypeLayoutReflection* typeLayout, BindingRegisterOffset* offset) + /// Add one binding range to the computed layout. + /// + /// The layout information is taken from `typeLayout` for the binding + /// range with the given `bindingRangeIndex`. + /// + /// The `physicalDescriptorSetIndex` is the index in the `m_descriptorSets` array of + /// the descriptor set that the range should be added to. + /// + /// The `offset` encodes information about space and/or register offsets that + /// should be applied to descrptor ranges. + /// + /// Note that a single binding range may encompass zero or more descriptor ranges. + /// + void addBindingRange( + slang::TypeLayoutReflection* typeLayout, + Index physicalDescriptorSetIndex, + BindingRegisterOffset const& offset, + Index bindingRangeIndex) { - typeLayout = _unwrapParameterGroups(typeLayout); - SlangInt bindingRangeCount = typeLayout->getBindingRangeCount(); - // `register` and `space` index offset of future sub-objects. - BindingRegisterOffset subObjectOffset = *offset; - for (SlangInt i = 0; i < bindingRangeCount; i++) + auto logicalDescriptorSetIndex = typeLayout->getBindingRangeDescriptorSetIndex(bindingRangeIndex); + auto firstDescriptorRangeIndex = typeLayout->getBindingRangeFirstDescriptorRangeIndex(bindingRangeIndex); + Index descriptorRangeCount = typeLayout->getBindingRangeDescriptorRangeCount(bindingRangeIndex); + for( Index i = 0; i < descriptorRangeCount; ++i ) + { + auto descriptorRangeIndex = firstDescriptorRangeIndex + i; + + // Note: we ignore the `Result` returned by `addDescriptorRange()` because we + // want to silently skip any ranges that represent kinds of bindings that + // don't actually exist in D3D12. + // + addDescriptorRange(typeLayout, physicalDescriptorSetIndex, offset, logicalDescriptorSetIndex, descriptorRangeIndex); + } + } + + /// Add binding ranges and parameter blocks to the root signature. + /// + /// The layout information is taken from `varLayout` which should + /// be a layout for either a program or an entry point. + /// + /// The `physicalDescriptorSetIndex` is the index in the `m_descriptorSets` array of + /// the descriptor set that binding ranges not belonging to nested + /// parameter blocks should be added to. + /// + /// This routine will use absolute offset information computed from `varLayout` + /// to apply appropriate space/register offsets to the bindings and parameter + /// blocks inside the layout. + /// + void addBindingRangesAndParameterBlocks( + slang::VariableLayoutReflection* varLayout, + Index physicalDescriptorSetIndex) + { + BindingRegisterOffset offset; + offset.spaceOffset = (UINT) varLayout->getOffset(SLANG_PARAMETER_CATEGORY_REGISTER_SPACE); + offset[D3D12_DESCRIPTOR_RANGE_TYPE_CBV] = (UINT) varLayout->getOffset(SLANG_PARAMETER_CATEGORY_CONSTANT_BUFFER); + offset[D3D12_DESCRIPTOR_RANGE_TYPE_SRV] = (UINT) varLayout->getOffset(SLANG_PARAMETER_CATEGORY_SHADER_RESOURCE); + offset[D3D12_DESCRIPTOR_RANGE_TYPE_UAV] = (UINT) varLayout->getOffset(SLANG_PARAMETER_CATEGORY_UNORDERED_ACCESS); + offset[D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER] = (UINT) varLayout->getOffset(SLANG_PARAMETER_CATEGORY_SAMPLER_STATE); + + addBindingRangesAndParameterBlocks(varLayout->getTypeLayout(), physicalDescriptorSetIndex, offset); + } + + /// Add binding ranges and parameter blocks to the root signature. + /// + /// The layout information is taken from `typeLayout` which should + /// be a layout for either a program or an entry point. + /// + /// The `physicalDescriptorSetIndex` is the index in the `m_descriptorSets` array of + /// the descriptor set that binding ranges not belonging to nested + /// parameter blocks should be added to. + /// + /// The `offset` encodes information about space and/or register offsets that + /// should be applied to descrptor ranges. + /// + void addBindingRangesAndParameterBlocks( + slang::TypeLayoutReflection* typeLayout, + Index physicalDescriptorSetIndex, + BindingRegisterOffset const& offset) + { + // Our first task is to add the binding ranges for stuff that is + // directly contained in `typeLayout` rather than via sub-objects. + // + // Our goal is to have the descriptors for directly-contained views/samplers + // always be contiguous in CPU and GPU memory, so that we can write + // to them easily with a single operaiton. + // + Index bindingRangeCount = typeLayout->getBindingRangeCount(); + for (Index bindingRangeIndex = 0; bindingRangeIndex < bindingRangeCount; bindingRangeIndex++) { - auto bindingType = typeLayout->getBindingRangeType(i); - D3D12_DESCRIPTOR_RANGE_TYPE rangeType; - if (translateDescriptorRangeType(bindingType, &rangeType) != SLANG_OK) + // We will look at the type of each binding range and intentionally + // skip those that represent sub-objects. + // + auto bindingType = typeLayout->getBindingRangeType(bindingRangeIndex); + switch(bindingType) { - // Ignore all descriptor ranges that does not map directly into a - // d3d descriptor. + case slang::BindingType::ConstantBuffer: + case slang::BindingType::ParameterBlock: + case slang::BindingType::ExistentialValue: continue; + + default: + break; } - // The CBV descriptor range, along with any additional descriptor ranges associated - // with the constant buffer binding range, will be appended to the end of this object's - // descriptor table, so we skip them now. - if (bindingType == slang::BindingType::ConstantBuffer) - continue; - addDescriptorRange(typeLayout, rangeType, i, offset, &subObjectOffset); + + // For binding ranges that don't represent sub-objects, we will add + // all of the descriptor ranges they encompass to the root signature. + // + addBindingRange(typeLayout, physicalDescriptorSetIndex, offset, bindingRangeIndex); } - auto subObjectCount = typeLayout->getSubObjectRangeCount(); - for (SlangInt i = 0; i < subObjectCount; i++) + + // Next we need to recurse on the various sub-objects that the type might contain. + // + Index subObjectCount = typeLayout->getSubObjectRangeCount(); + for (Index subObjectRangeIndex = 0; subObjectRangeIndex < subObjectCount; subObjectRangeIndex++) { - auto rangeIndex = typeLayout->getSubObjectRangeBindingRangeIndex(i); - switch (typeLayout->getBindingRangeType(rangeIndex)) + // There are a few different concerns being tackled at once here, which depend on + // the type of each sub-object range. + // + auto bindingRangeIndex = typeLayout->getSubObjectRangeBindingRangeIndex(subObjectRangeIndex); + auto bindingType = typeLayout->getBindingRangeType(bindingRangeIndex); + switch (bindingType) { case slang::BindingType::ConstantBuffer: { - auto subObjectType = typeLayout->getBindingRangeLeafTypeLayout(rangeIndex); - auto subObjectElementType = _unwrapParameterGroups(subObjectType); - if (subObjectElementType->getSize(SLANG_PARAMETER_CATEGORY_UNIFORM) != 0) - { - addDescriptorRange( - typeLayout, - D3D12_DESCRIPTOR_RANGE_TYPE_CBV, - rangeIndex, - offset, - &subObjectOffset); - } - addObject(subObjectType, &subObjectOffset); + // Constant buffer ranges (for `ConstantBuffer<ConcreteType>`) will "leak" their + // binding ranges into the surrounding type, so we can add them here like any other + // binding range. + // + // Note: It would be valid to allow `slang::BindingType::ConstantBuffer` to be handled + // in the earlier loop, but that would mean that descriptor ranges coming directly + // from the fields of `typeLayout` could be broken up with ranges coming from constant-buffer + // sub-objects. By moving the handling of constant buffers to this later loop, we + // guarantee that the descritpors used by non-sub-object binding ranges are all + // contiguous. + // + addBindingRange(typeLayout, physicalDescriptorSetIndex, offset, bindingRangeIndex); } break; + case slang::BindingType::ParameterBlock: { - BindingRegisterOffset newOffset = {}; - newOffset.descriptorSetIndex = (uint32_t)m_descriptorSets.getCount(); - m_descriptorSets.add(DescriptorSetLayout{}); - newOffset.spaceOffset = - offset->spaceOffset + - (uint32_t)typeLayout->getBindingRangeDescriptorSetIndex(rangeIndex); - auto subObjectType = - typeLayout->getBindingRangeLeafTypeLayout(rangeIndex); - addObject(subObjectType, &newOffset); + // A parameter block (`ParameterBlock<ConcreteType>`) will always map to a distinct + // descriptor set, and its contained view/sampler binding ranges will be bound + // through that set. + // + auto blockPhysicalDescriptorSetIndex = addDescriptorSet(); + + // We will need to recursively add the binding ranges implied by the type of + // the parameter block. + // + auto blockTypeLayout = typeLayout->getBindingRangeLeafTypeLayout(bindingRangeIndex); + + // One important detail is that the `blockTypeLayout` does not know the base register + // space that the contents of the block should use. All descriptor ranges stored in + // that layout will by default use a space offset of zero. + // + // We need to compute the space offset to apply when recursing into that block type + // based on the binding range we are processing here. + // + auto blockLogicalDescriptorSetIndex = typeLayout->getBindingRangeDescriptorSetIndex(bindingRangeIndex); + auto blockSpaceOffset = typeLayout->getDescriptorSetSpaceOffset(blockLogicalDescriptorSetIndex); + + // The space offset for this binding range should be added to any additional space + // offset that was being passed down from above this layer. + // + // Any other offset information (register offsets) should be ignored at this point, + // because `register` offsets from outside of the block don't affect layout within + // the block. + // + BindingRegisterOffset blockOffset; + blockOffset.spaceOffset = offset.spaceOffset + (uint32_t) blockSpaceOffset; + + // Once we have all the details worked out, we can write the binding ranges for the + // block's type into the newly-allocated descriptor set. + // + // Note: there is an important subtlety going on here. We are passing in the type + // `blockTypeLayout` which corresponds to `ParameterBlock<ConcreteType>` and *not* to + // `ConcreteType` alone. Because of that detail, the binding/descriptor ranges will + // include any "default constant buffer" range that needed to be allocated based + // on `ConcreteType`. + // + // TODO: validate that this logic is right. + // + addBindingRangesAndParameterBlocks(blockTypeLayout, blockPhysicalDescriptorSetIndex, blockOffset); } break; - } - } - *offset = subObjectOffset; - } - - static BindingRegisterOffset getOffsetFromVarLayout( - slang::VariableLayoutReflection* varLayout) - { - BindingRegisterOffset offset; - offset.descriptorSetIndex = 0; - offset.spaceOffset = - (uint32_t)varLayout->getOffset(SLANG_PARAMETER_CATEGORY_REGISTER_SPACE); - offset.samplerOffset = - (uint32_t)varLayout->getOffset(SLANG_PARAMETER_CATEGORY_SAMPLER_STATE); - offset.textureOffset = - (uint32_t)varLayout->getOffset(SLANG_PARAMETER_CATEGORY_SHADER_RESOURCE); - offset.constantBufferOffset = - (uint32_t)varLayout->getOffset(SLANG_PARAMETER_CATEGORY_CONSTANT_BUFFER); - offset.uavOffset = - (uint32_t)varLayout->getOffset(SLANG_PARAMETER_CATEGORY_UNORDERED_ACCESS); - return offset; - } - void addObject( - slang::TypeLayoutReflection* typeLayout, - slang::VariableLayoutReflection* varLayout) - { - auto offset = getOffsetFromVarLayout(varLayout); - addObject(typeLayout, &offset); - } + case slang::BindingType::ExistentialValue: + // TODO: Need to handle this case here. + break; - void addEntryPoint(slang::EntryPointReflection* entryPoint) - { - BindingRegisterOffset offset = getOffsetFromVarLayout(entryPoint->getVarLayout()); - if (entryPoint->hasDefaultConstantBuffer()) - { - addDescriptorRange( - entryPoint->getTypeLayout(), - D3D12_DESCRIPTOR_RANGE_TYPE_CBV, - 0, - &offset, - &offset); + default: + break; + } } - addObject(entryPoint->getTypeLayout(), &offset); } D3D12_ROOT_SIGNATURE_DESC& build( @@ -1307,19 +1406,46 @@ public: ID3D12RootSignature** outRootSignature, List<DescriptorSetInfo>& outRootDescriptorSetInfos) { + // We are going to build up the root signature by adding + // binding/descritpor ranges and nested parameter blocks + // based on the computed layout information for `program`. + // RootSignatureDescBuilder builder; - builder.m_descriptorSets.add(DescriptorSetLayout{}); - auto layout = program->getLayout(); - auto globalParamLayout = layout->getGlobalParamsTypeLayout(); - auto globalVarLayout = layout->getGlobalParamsVarLayout(); - builder.addObject(globalParamLayout, globalVarLayout); + // The layout information computed by Slang breaks up shader + // parameters into what we can think of as "logical" descriptor + // sets based on whether or not parameters have the same `space`. + // + // We want to basically ignore that decomposition and generate a + // single descriptor set to hold all top-level parameters, and only + // generate distinct descriptor sets when the shader has opted in + // via explicit parameter blocks. + // + // To achieve this goal, we will manually allocate a default descriptor + // set for root parameters in our signature, and then recursively + // add all the binding/descriptor ranges implied by the global-scope + // parameters. + // + auto rootDescriptorSetIndex = builder.addDescriptorSet(); + builder.addBindingRangesAndParameterBlocks(layout->getGlobalParamsVarLayout(), rootDescriptorSetIndex); for (SlangUInt i = 0; i < layout->getEntryPointCount(); i++) { + // Entry-point parameters should also be added to the default root + // descriptor set. + // + // We add the parameters using the "variable layout" for the entry point + // and not just its type layout, to ensure that any offset information is + // applied correctly to the `register` and `space` information for entry-point + // parameters. + // + // Note: When we start to support DXR we will need to handle entry-point parameters + // differently because they will need to map to local root signatures rather than + // being included in the global root signature as is being done here. + // auto entryPoint = layout->getEntryPointByIndex(i); - builder.addEntryPoint(entryPoint); + builder.addBindingRangesAndParameterBlocks(entryPoint->getVarLayout(), rootDescriptorSetIndex); } auto& rootSignatureDesc = builder.build(outRootDescriptorSetInfos); @@ -2034,21 +2160,13 @@ public: SLANG_RETURN_ON_FAIL(_writeOrdinaryData( encoder, m_ordinaryDataBuffer, 0, specializedOrdinaryDataSize, specializedLayout)); - return SLANG_OK; - } - - /// Bind the buffer for ordinary/uniform data, if needed - Result _bindOrdinaryDataBufferIfNeeded(PipelineCommandEncoder* encoder) - { - // We start by ensuring that the buffer is created, if it is needed. - // - SLANG_RETURN_ON_FAIL(_ensureOrdinaryDataBufferCreatedIfNeeded(encoder)); - - // If we did indeed need/create a buffer, then we must bind it - // into root binding state. - // - if (m_ordinaryDataBuffer) { + // We also create and store a descriptor for our root constant buffer + // into the descriptor table allocation that was reserved for them. + // + // We always know that the ordinary data buffer will be the first descriptor + // in the table of resource views. + // auto descriptorTable = m_descriptorSet.m_resourceTable; D3D12_CONSTANT_BUFFER_VIEW_DESC viewDesc = {}; viewDesc.BufferLocation = @@ -2067,7 +2185,7 @@ public: virtual Result bindObject(PipelineCommandEncoder* encoder, RootBindingState* bindingState) { ShaderObjectLayoutImpl* layout = getLayout(); - SLANG_RETURN_ON_FAIL(_bindOrdinaryDataBufferIfNeeded(encoder)); + SLANG_RETURN_ON_FAIL(_ensureOrdinaryDataBufferCreatedIfNeeded(encoder)); uint32_t descTableIndex = bindingState->rootParamIndex; auto& descSet = m_descriptorSet; if (descSet.m_resourceCount) @@ -2677,7 +2795,10 @@ public: // Submit - setting for graphics { GraphicsSubmitter submitter(m_d3dCmdList); - _bindRenderState(&submitter); + if(SLANG_FAILED(_bindRenderState(&submitter))) + { + assert(!"Failed to bind render state"); + } } m_d3dCmdList->IASetPrimitiveTopology(m_primitiveTopology); @@ -2844,7 +2965,10 @@ public: // Submit binding for compute { ComputeSubmitter submitter(m_d3dCmdList); - _bindRenderState(&submitter); + if(SLANG_FAILED(_bindRenderState(&submitter))) + { + assert(!"Failed to bind render state"); + } } m_d3dCmdList->Dispatch(x, y, z); } @@ -3238,7 +3362,7 @@ Result D3D12Device::PipelineCommandEncoder::_bindRenderState(Submitter* submitte submitter->setRootSignature(programImpl->m_rootObjectLayout->m_rootSignature); ShortList<DescriptorTable, kMaxDescriptorSetCount> descriptorTables; RefPtr<ShaderObjectLayoutImpl> specializedRootLayout; - rootObjectImpl->getSpecializedLayout(specializedRootLayout.writeRef()); + SLANG_RETURN_ON_FAIL(rootObjectImpl->getSpecializedLayout(specializedRootLayout.writeRef())); RootShaderObjectLayoutImpl* rootLayoutImpl = static_cast<RootShaderObjectLayoutImpl*>(specializedRootLayout.Ptr()); for (auto& descSet : rootLayoutImpl->m_gpuDescriptorSetInfos) diff --git a/tools/render-test/render-test-main.cpp b/tools/render-test/render-test-main.cpp index 27311d67a..db51339f1 100644 --- a/tools/render-test/render-test-main.cpp +++ b/tools/render-test/render-test-main.cpp @@ -274,19 +274,25 @@ struct AssignValsFromLayoutContext if(field.name.getLength() == 0) { - StdWriters::getError().print("error: entries in `ShaderInputLayout` must include a name\n"); - return SLANG_E_INVALID_ARG; + // If no name was given, assume by-indexing matching is requested + auto fieldCursor = dstCursor.getElement(fieldIndex); + if(!fieldCursor.isValid()) + { + StdWriters::getError().print("error: could not find shader parameter at index %d\n", (int)fieldIndex); + return SLANG_E_INVALID_ARG; + } + SLANG_RETURN_ON_FAIL(assign(fieldCursor, field.val)); } - - auto fieldCursor = dstCursor.getPath(field.name.getBuffer()); - - if(!fieldCursor.isValid()) + else { - StdWriters::getError().print("error: could not find shader parameter matching '%s'\n", field.name.begin()); - return SLANG_E_INVALID_ARG; + auto fieldCursor = dstCursor.getPath(field.name.getBuffer()); + if(!fieldCursor.isValid()) + { + StdWriters::getError().print("error: could not find shader parameter matching '%s'\n", field.name.begin()); + return SLANG_E_INVALID_ARG; + } + SLANG_RETURN_ON_FAIL(assign(fieldCursor, field.val)); } - - assign(fieldCursor, field.val); } return SLANG_OK; } @@ -329,7 +335,7 @@ struct AssignValsFromLayoutContext ComPtr<IShaderObject> shaderObject = device->createShaderObject(slangType); - assign(ShaderCursor(shaderObject), srcVal->contentVal); + SLANG_RETURN_ON_FAIL(assign(ShaderCursor(shaderObject), srcVal->contentVal)); dstCursor.setObject(shaderObject); return SLANG_OK; diff --git a/tools/render-test/shader-input-layout.cpp b/tools/render-test/shader-input-layout.cpp index c5f1cb6dd..4febc4bd5 100644 --- a/tools/render-test/shader-input-layout.cpp +++ b/tools/render-test/shader-input-layout.cpp @@ -504,10 +504,17 @@ namespace renderer_test val->contentVal = parseValExpr(parser); return val; } + else if( parser.AdvanceIf("out") ) + { + auto val = parseValExpr(parser); + val->isOutput = true; + return val; + } else { - // TODO: other named cases - throw ShaderInputLayoutFormatException(String("Unexpected '") + parser.NextToken().Content + String("' at line") + String(parser.NextToken().Position.Line)); + // We assume that any other word is introducing one of the other + // cases for a parse-able value. + return parseVal(parser); } } break; diff --git a/tools/render-test/slang-support.cpp b/tools/render-test/slang-support.cpp index aca354763..840b0d3e2 100644 --- a/tools/render-test/slang-support.cpp +++ b/tools/render-test/slang-support.cpp @@ -135,6 +135,10 @@ void ShaderCompilerUtil::Output::reset() { spSetPassThrough(slangRequest, input.passThrough); } + else + { + spSetCompileFlags(slangRequest, SLANG_COMPILE_FLAG_NO_CODEGEN); + } // Process any additional command-line options specified for Slang using // the `-xslang <arg>` option to `render-test`. |
