1 //===- llvm/MC/DXContainerRootSignature.cpp - RootSignature -*- C++ -*-=======//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "llvm/MC/DXContainerRootSignature.h"
10 #include "llvm/ADT/SmallString.h"
11 #include "llvm/Support/EndianStream.h"
12
13 using namespace llvm;
14 using namespace llvm::mcdxbc;
15
writePlaceholder(raw_svector_ostream & Stream)16 static uint32_t writePlaceholder(raw_svector_ostream &Stream) {
17 const uint32_t DummyValue = std::numeric_limits<uint32_t>::max();
18 uint32_t Offset = Stream.tell();
19 support::endian::write(Stream, DummyValue, llvm::endianness::little);
20 return Offset;
21 }
22
rewriteOffsetToCurrentByte(raw_svector_ostream & Stream,uint32_t Offset)23 static void rewriteOffsetToCurrentByte(raw_svector_ostream &Stream,
24 uint32_t Offset) {
25 uint32_t Value =
26 support::endian::byte_swap<uint32_t, llvm::endianness::little>(
27 Stream.tell());
28 Stream.pwrite(reinterpret_cast<const char *>(&Value), sizeof(Value), Offset);
29 }
30
getSize() const31 size_t RootSignatureDesc::getSize() const {
32 size_t Size =
33 sizeof(dxbc::RTS0::v1::RootSignatureHeader) +
34 ParametersContainer.size() * sizeof(dxbc::RTS0::v1::RootParameterHeader) +
35 StaticSamplers.size() * sizeof(dxbc::RTS0::v1::StaticSampler);
36
37 for (const RootParameterInfo &I : ParametersContainer) {
38 switch (I.Header.ParameterType) {
39 case llvm::to_underlying(dxbc::RootParameterType::Constants32Bit):
40 Size += sizeof(dxbc::RTS0::v1::RootConstants);
41 break;
42 case llvm::to_underlying(dxbc::RootParameterType::CBV):
43 case llvm::to_underlying(dxbc::RootParameterType::SRV):
44 case llvm::to_underlying(dxbc::RootParameterType::UAV):
45 if (Version == 1)
46 Size += sizeof(dxbc::RTS0::v1::RootDescriptor);
47 else
48 Size += sizeof(dxbc::RTS0::v2::RootDescriptor);
49
50 break;
51 case llvm::to_underlying(dxbc::RootParameterType::DescriptorTable):
52 const DescriptorTable &Table =
53 ParametersContainer.getDescriptorTable(I.Location);
54
55 // 4 bytes for the number of ranges in table and
56 // 4 bytes for the ranges offset
57 Size += 2 * sizeof(uint32_t);
58 if (Version == 1)
59 Size += sizeof(dxbc::RTS0::v1::DescriptorRange) * Table.Ranges.size();
60 else
61 Size += sizeof(dxbc::RTS0::v2::DescriptorRange) * Table.Ranges.size();
62 break;
63 }
64 }
65 return Size;
66 }
67
write(raw_ostream & OS) const68 void RootSignatureDesc::write(raw_ostream &OS) const {
69 SmallString<256> Storage;
70 raw_svector_ostream BOS(Storage);
71 BOS.reserveExtraSpace(getSize());
72
73 const uint32_t NumParameters = ParametersContainer.size();
74 const uint32_t NumSamplers = StaticSamplers.size();
75 support::endian::write(BOS, Version, llvm::endianness::little);
76 support::endian::write(BOS, NumParameters, llvm::endianness::little);
77 support::endian::write(BOS, RootParameterOffset, llvm::endianness::little);
78 support::endian::write(BOS, NumSamplers, llvm::endianness::little);
79 uint32_t SSO = StaticSamplersOffset;
80 if (NumSamplers > 0)
81 SSO = writePlaceholder(BOS);
82 else
83 support::endian::write(BOS, SSO, llvm::endianness::little);
84 support::endian::write(BOS, Flags, llvm::endianness::little);
85
86 SmallVector<uint32_t> ParamsOffsets;
87 for (const RootParameterInfo &P : ParametersContainer) {
88 support::endian::write(BOS, P.Header.ParameterType,
89 llvm::endianness::little);
90 support::endian::write(BOS, P.Header.ShaderVisibility,
91 llvm::endianness::little);
92
93 ParamsOffsets.push_back(writePlaceholder(BOS));
94 }
95
96 assert(NumParameters == ParamsOffsets.size());
97 for (size_t I = 0; I < NumParameters; ++I) {
98 rewriteOffsetToCurrentByte(BOS, ParamsOffsets[I]);
99 const auto &[Type, Loc] = ParametersContainer.getTypeAndLocForParameter(I);
100 switch (Type) {
101 case llvm::to_underlying(dxbc::RootParameterType::Constants32Bit): {
102 const dxbc::RTS0::v1::RootConstants &Constants =
103 ParametersContainer.getConstant(Loc);
104 support::endian::write(BOS, Constants.ShaderRegister,
105 llvm::endianness::little);
106 support::endian::write(BOS, Constants.RegisterSpace,
107 llvm::endianness::little);
108 support::endian::write(BOS, Constants.Num32BitValues,
109 llvm::endianness::little);
110 break;
111 }
112 case llvm::to_underlying(dxbc::RootParameterType::CBV):
113 case llvm::to_underlying(dxbc::RootParameterType::SRV):
114 case llvm::to_underlying(dxbc::RootParameterType::UAV): {
115 const dxbc::RTS0::v2::RootDescriptor &Descriptor =
116 ParametersContainer.getRootDescriptor(Loc);
117
118 support::endian::write(BOS, Descriptor.ShaderRegister,
119 llvm::endianness::little);
120 support::endian::write(BOS, Descriptor.RegisterSpace,
121 llvm::endianness::little);
122 if (Version > 1)
123 support::endian::write(BOS, Descriptor.Flags, llvm::endianness::little);
124 break;
125 }
126 case llvm::to_underlying(dxbc::RootParameterType::DescriptorTable): {
127 const DescriptorTable &Table =
128 ParametersContainer.getDescriptorTable(Loc);
129 support::endian::write(BOS, (uint32_t)Table.Ranges.size(),
130 llvm::endianness::little);
131 rewriteOffsetToCurrentByte(BOS, writePlaceholder(BOS));
132 for (const auto &Range : Table) {
133 support::endian::write(BOS, Range.RangeType, llvm::endianness::little);
134 support::endian::write(BOS, Range.NumDescriptors,
135 llvm::endianness::little);
136 support::endian::write(BOS, Range.BaseShaderRegister,
137 llvm::endianness::little);
138 support::endian::write(BOS, Range.RegisterSpace,
139 llvm::endianness::little);
140 if (Version > 1)
141 support::endian::write(BOS, Range.Flags, llvm::endianness::little);
142 support::endian::write(BOS, Range.OffsetInDescriptorsFromTableStart,
143 llvm::endianness::little);
144 }
145 break;
146 }
147 }
148 }
149 if (NumSamplers > 0) {
150 rewriteOffsetToCurrentByte(BOS, SSO);
151 for (const auto &S : StaticSamplers) {
152 support::endian::write(BOS, S.Filter, llvm::endianness::little);
153 support::endian::write(BOS, S.AddressU, llvm::endianness::little);
154 support::endian::write(BOS, S.AddressV, llvm::endianness::little);
155 support::endian::write(BOS, S.AddressW, llvm::endianness::little);
156 support::endian::write(BOS, S.MipLODBias, llvm::endianness::little);
157 support::endian::write(BOS, S.MaxAnisotropy, llvm::endianness::little);
158 support::endian::write(BOS, S.ComparisonFunc, llvm::endianness::little);
159 support::endian::write(BOS, S.BorderColor, llvm::endianness::little);
160 support::endian::write(BOS, S.MinLOD, llvm::endianness::little);
161 support::endian::write(BOS, S.MaxLOD, llvm::endianness::little);
162 support::endian::write(BOS, S.ShaderRegister, llvm::endianness::little);
163 support::endian::write(BOS, S.RegisterSpace, llvm::endianness::little);
164 support::endian::write(BOS, S.ShaderVisibility, llvm::endianness::little);
165 }
166 }
167 assert(Storage.size() == getSize());
168 OS.write(Storage.data(), Storage.size());
169 }
170