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
13using namespace llvm;
14using namespace llvm::mcdxbc;
15
16static 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(os&: Stream, value: DummyValue, endian: llvm::endianness::little);
20 return Offset;
21}
22
23static uint32_t rewriteOffsetToCurrentByte(raw_svector_ostream &Stream,
24 uint32_t Offset) {
25 uint32_t ByteOffset = Stream.tell();
26 uint32_t Value = support::endian::byte_swap<uint32_t>(
27 value: ByteOffset, endian: llvm::endianness::little);
28 Stream.pwrite(Ptr: reinterpret_cast<const char *>(&Value), Size: sizeof(Value), Offset);
29 return ByteOffset;
30}
31
32size_t RootSignatureDesc::getSize() const {
33 uint32_t StaticSamplersOffset = computeStaticSamplersOffset();
34 size_t StaticSamplersSize = sizeof(dxbc::RTS0::v1::StaticSampler);
35 if (Version > 2)
36 StaticSamplersSize = sizeof(dxbc::RTS0::v3::StaticSampler);
37
38 return size_t(StaticSamplersOffset) +
39 (StaticSamplersSize * StaticSamplers.size());
40}
41
42uint32_t RootSignatureDesc::computeRootParametersOffset() const {
43 return sizeof(dxbc::RTS0::v1::RootSignatureHeader);
44}
45
46uint32_t RootSignatureDesc::computeStaticSamplersOffset() const {
47 uint32_t Offset = computeRootParametersOffset();
48
49 for (const RootParameterInfo &I : ParametersContainer) {
50 Offset += sizeof(dxbc::RTS0::v1::RootParameterHeader);
51 switch (I.Type) {
52 case dxbc::RootParameterType::Constants32Bit:
53 Offset += sizeof(dxbc::RTS0::v1::RootConstants);
54 break;
55 case dxbc::RootParameterType::CBV:
56 case dxbc::RootParameterType::SRV:
57 case dxbc::RootParameterType::UAV:
58 if (Version == 1)
59 Offset += sizeof(dxbc::RTS0::v1::RootDescriptor);
60 else
61 Offset += sizeof(dxbc::RTS0::v2::RootDescriptor);
62
63 break;
64 case dxbc::RootParameterType::DescriptorTable:
65 const DescriptorTable &Table =
66 ParametersContainer.getDescriptorTable(Index: I.Location);
67
68 // 4 bytes for the number of ranges in table and
69 // 4 bytes for the ranges offset
70 Offset += 2 * sizeof(uint32_t);
71 if (Version == 1)
72 Offset += sizeof(dxbc::RTS0::v1::DescriptorRange) * Table.Ranges.size();
73 else
74 Offset += sizeof(dxbc::RTS0::v2::DescriptorRange) * Table.Ranges.size();
75 break;
76 }
77 }
78
79 return Offset;
80}
81
82void RootSignatureDesc::write(raw_ostream &OS) const {
83 SmallString<256> Storage;
84 raw_svector_ostream BOS(Storage);
85 BOS.reserveExtraSpace(ExtraSize: getSize());
86
87 const uint32_t NumParameters = ParametersContainer.size();
88 const uint32_t NumSamplers = StaticSamplers.size();
89 support::endian::write(os&: BOS, value: Version, endian: llvm::endianness::little);
90 support::endian::write(os&: BOS, value: NumParameters, endian: llvm::endianness::little);
91 support::endian::write(os&: BOS, value: RootParameterOffset, endian: llvm::endianness::little);
92 support::endian::write(os&: BOS, value: NumSamplers, endian: llvm::endianness::little);
93 uint32_t SSO = writePlaceholder(Stream&: BOS);
94 support::endian::write(os&: BOS, value: Flags, endian: llvm::endianness::little);
95
96 SmallVector<uint32_t> ParamsOffsets;
97 for (const RootParameterInfo &I : ParametersContainer) {
98 support::endian::write(os&: BOS, value: I.Type, endian: llvm::endianness::little);
99 support::endian::write(os&: BOS, value: I.Visibility, endian: llvm::endianness::little);
100
101 ParamsOffsets.push_back(Elt: writePlaceholder(Stream&: BOS));
102 }
103
104 assert(NumParameters == ParamsOffsets.size());
105 for (size_t I = 0; I < NumParameters; ++I) {
106 rewriteOffsetToCurrentByte(Stream&: BOS, Offset: ParamsOffsets[I]);
107 const RootParameterInfo &Info = ParametersContainer.getInfo(Location: I);
108 switch (Info.Type) {
109 case dxbc::RootParameterType::Constants32Bit: {
110 const mcdxbc::RootConstants &Constants =
111 ParametersContainer.getConstant(Index: Info.Location);
112 support::endian::write(os&: BOS, value: Constants.ShaderRegister,
113 endian: llvm::endianness::little);
114 support::endian::write(os&: BOS, value: Constants.RegisterSpace,
115 endian: llvm::endianness::little);
116 support::endian::write(os&: BOS, value: Constants.Num32BitValues,
117 endian: llvm::endianness::little);
118 break;
119 }
120 case dxbc::RootParameterType::CBV:
121 case dxbc::RootParameterType::SRV:
122 case dxbc::RootParameterType::UAV: {
123 const mcdxbc::RootDescriptor &Descriptor =
124 ParametersContainer.getRootDescriptor(Index: Info.Location);
125
126 support::endian::write(os&: BOS, value: Descriptor.ShaderRegister,
127 endian: llvm::endianness::little);
128 support::endian::write(os&: BOS, value: Descriptor.RegisterSpace,
129 endian: llvm::endianness::little);
130 if (Version > 1)
131 support::endian::write(os&: BOS, value: Descriptor.Flags, endian: llvm::endianness::little);
132 break;
133 }
134 case dxbc::RootParameterType::DescriptorTable: {
135 const DescriptorTable &Table =
136 ParametersContainer.getDescriptorTable(Index: Info.Location);
137 support::endian::write(os&: BOS, value: (uint32_t)Table.Ranges.size(),
138 endian: llvm::endianness::little);
139 rewriteOffsetToCurrentByte(Stream&: BOS, Offset: writePlaceholder(Stream&: BOS));
140 for (const auto &Range : Table) {
141 support::endian::write(os&: BOS, value: static_cast<uint32_t>(Range.RangeType),
142 endian: llvm::endianness::little);
143 support::endian::write(os&: BOS, value: Range.NumDescriptors,
144 endian: llvm::endianness::little);
145 support::endian::write(os&: BOS, value: Range.BaseShaderRegister,
146 endian: llvm::endianness::little);
147 support::endian::write(os&: BOS, value: Range.RegisterSpace,
148 endian: llvm::endianness::little);
149 if (Version > 1)
150 support::endian::write(os&: BOS, value: Range.Flags, endian: llvm::endianness::little);
151 support::endian::write(os&: BOS, value: Range.OffsetInDescriptorsFromTableStart,
152 endian: llvm::endianness::little);
153 }
154 break;
155 }
156 }
157 }
158 [[maybe_unused]] uint32_t Offset = rewriteOffsetToCurrentByte(Stream&: BOS, Offset: SSO);
159 assert(Offset == computeStaticSamplersOffset() &&
160 "Computed offset does not match written offset");
161 for (const auto &S : StaticSamplers) {
162 support::endian::write(os&: BOS, value: S.Filter, endian: llvm::endianness::little);
163 support::endian::write(os&: BOS, value: S.AddressU, endian: llvm::endianness::little);
164 support::endian::write(os&: BOS, value: S.AddressV, endian: llvm::endianness::little);
165 support::endian::write(os&: BOS, value: S.AddressW, endian: llvm::endianness::little);
166 support::endian::write(os&: BOS, value: S.MipLODBias, endian: llvm::endianness::little);
167 support::endian::write(os&: BOS, value: S.MaxAnisotropy, endian: llvm::endianness::little);
168 support::endian::write(os&: BOS, value: S.ComparisonFunc, endian: llvm::endianness::little);
169 support::endian::write(os&: BOS, value: S.BorderColor, endian: llvm::endianness::little);
170 support::endian::write(os&: BOS, value: S.MinLOD, endian: llvm::endianness::little);
171 support::endian::write(os&: BOS, value: S.MaxLOD, endian: llvm::endianness::little);
172 support::endian::write(os&: BOS, value: S.ShaderRegister, endian: llvm::endianness::little);
173 support::endian::write(os&: BOS, value: S.RegisterSpace, endian: llvm::endianness::little);
174 support::endian::write(os&: BOS, value: S.ShaderVisibility, endian: llvm::endianness::little);
175
176 if (Version > 2)
177 support::endian::write(os&: BOS, value: S.Flags, endian: llvm::endianness::little);
178 }
179 assert(Storage.size() == getSize());
180 OS.write(Ptr: Storage.data(), Size: Storage.size());
181}
182