//===- llvm/MC/DXContainerRootSignature.cpp - RootSignature -*- C++ -*-=======// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "llvm/MC/DXContainerRootSignature.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/EndianStream.h" using namespace llvm; using namespace llvm::mcdxbc; static uint32_t writePlaceholder(raw_svector_ostream &Stream) { const uint32_t DummyValue = std::numeric_limits::max(); uint32_t Offset = Stream.tell(); support::endian::write(Stream, DummyValue, llvm::endianness::little); return Offset; } static uint32_t rewriteOffsetToCurrentByte(raw_svector_ostream &Stream, uint32_t Offset) { uint32_t ByteOffset = Stream.tell(); uint32_t Value = support::endian::byte_swap( ByteOffset); Stream.pwrite(reinterpret_cast(&Value), sizeof(Value), Offset); return ByteOffset; } size_t RootSignatureDesc::getSize() const { uint32_t StaticSamplersOffset = computeStaticSamplersOffset(); size_t StaticSamplersSize = StaticSamplers.size() * sizeof(dxbc::RTS0::v1::StaticSampler); return size_t(StaticSamplersOffset) + StaticSamplersSize; } uint32_t RootSignatureDesc::computeRootParametersOffset() const { return sizeof(dxbc::RTS0::v1::RootSignatureHeader); } uint32_t RootSignatureDesc::computeStaticSamplersOffset() const { uint32_t Offset = computeRootParametersOffset(); for (const RootParameterInfo &I : ParametersContainer) { Offset += sizeof(dxbc::RTS0::v1::RootParameterHeader); switch (I.Type) { case dxbc::RootParameterType::Constants32Bit: Offset += sizeof(dxbc::RTS0::v1::RootConstants); break; case dxbc::RootParameterType::CBV: case dxbc::RootParameterType::SRV: case dxbc::RootParameterType::UAV: if (Version == 1) Offset += sizeof(dxbc::RTS0::v1::RootDescriptor); else Offset += sizeof(dxbc::RTS0::v2::RootDescriptor); break; case dxbc::RootParameterType::DescriptorTable: const DescriptorTable &Table = ParametersContainer.getDescriptorTable(I.Location); // 4 bytes for the number of ranges in table and // 4 bytes for the ranges offset Offset += 2 * sizeof(uint32_t); if (Version == 1) Offset += sizeof(dxbc::RTS0::v1::DescriptorRange) * Table.Ranges.size(); else Offset += sizeof(dxbc::RTS0::v2::DescriptorRange) * Table.Ranges.size(); break; } } return Offset; } void RootSignatureDesc::write(raw_ostream &OS) const { SmallString<256> Storage; raw_svector_ostream BOS(Storage); BOS.reserveExtraSpace(getSize()); const uint32_t NumParameters = ParametersContainer.size(); const uint32_t NumSamplers = StaticSamplers.size(); support::endian::write(BOS, Version, llvm::endianness::little); support::endian::write(BOS, NumParameters, llvm::endianness::little); support::endian::write(BOS, RootParameterOffset, llvm::endianness::little); support::endian::write(BOS, NumSamplers, llvm::endianness::little); uint32_t SSO = writePlaceholder(BOS); support::endian::write(BOS, Flags, llvm::endianness::little); SmallVector ParamsOffsets; for (const RootParameterInfo &I : ParametersContainer) { support::endian::write(BOS, I.Type, llvm::endianness::little); support::endian::write(BOS, I.Visibility, llvm::endianness::little); ParamsOffsets.push_back(writePlaceholder(BOS)); } assert(NumParameters == ParamsOffsets.size()); for (size_t I = 0; I < NumParameters; ++I) { rewriteOffsetToCurrentByte(BOS, ParamsOffsets[I]); const RootParameterInfo &Info = ParametersContainer.getInfo(I); switch (Info.Type) { case dxbc::RootParameterType::Constants32Bit: { const mcdxbc::RootConstants &Constants = ParametersContainer.getConstant(Info.Location); support::endian::write(BOS, Constants.ShaderRegister, llvm::endianness::little); support::endian::write(BOS, Constants.RegisterSpace, llvm::endianness::little); support::endian::write(BOS, Constants.Num32BitValues, llvm::endianness::little); break; } case dxbc::RootParameterType::CBV: case dxbc::RootParameterType::SRV: case dxbc::RootParameterType::UAV: { const mcdxbc::RootDescriptor &Descriptor = ParametersContainer.getRootDescriptor(Info.Location); support::endian::write(BOS, Descriptor.ShaderRegister, llvm::endianness::little); support::endian::write(BOS, Descriptor.RegisterSpace, llvm::endianness::little); if (Version > 1) support::endian::write(BOS, Descriptor.Flags, llvm::endianness::little); break; } case dxbc::RootParameterType::DescriptorTable: { const DescriptorTable &Table = ParametersContainer.getDescriptorTable(Info.Location); support::endian::write(BOS, (uint32_t)Table.Ranges.size(), llvm::endianness::little); rewriteOffsetToCurrentByte(BOS, writePlaceholder(BOS)); for (const auto &Range : Table) { support::endian::write(BOS, static_cast(Range.RangeType), llvm::endianness::little); support::endian::write(BOS, Range.NumDescriptors, llvm::endianness::little); support::endian::write(BOS, Range.BaseShaderRegister, llvm::endianness::little); support::endian::write(BOS, Range.RegisterSpace, llvm::endianness::little); if (Version > 1) support::endian::write(BOS, Range.Flags, llvm::endianness::little); support::endian::write(BOS, Range.OffsetInDescriptorsFromTableStart, llvm::endianness::little); } break; } } } [[maybe_unused]] uint32_t Offset = rewriteOffsetToCurrentByte(BOS, SSO); assert(Offset == computeStaticSamplersOffset() && "Computed offset does not match written offset"); for (const auto &S : StaticSamplers) { support::endian::write(BOS, S.Filter, llvm::endianness::little); support::endian::write(BOS, S.AddressU, llvm::endianness::little); support::endian::write(BOS, S.AddressV, llvm::endianness::little); support::endian::write(BOS, S.AddressW, llvm::endianness::little); support::endian::write(BOS, S.MipLODBias, llvm::endianness::little); support::endian::write(BOS, S.MaxAnisotropy, llvm::endianness::little); support::endian::write(BOS, S.ComparisonFunc, llvm::endianness::little); support::endian::write(BOS, S.BorderColor, llvm::endianness::little); support::endian::write(BOS, S.MinLOD, llvm::endianness::little); support::endian::write(BOS, S.MaxLOD, llvm::endianness::little); support::endian::write(BOS, S.ShaderRegister, llvm::endianness::little); support::endian::write(BOS, S.RegisterSpace, llvm::endianness::little); support::endian::write(BOS, S.ShaderVisibility, llvm::endianness::little); } assert(Storage.size() == getSize()); OS.write(Storage.data(), Storage.size()); }