1 //
2 // Copyright 2021 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // ShaderInterfaceVariableInfoMap: Maps shader interface variable SPIR-V ids to their Vulkan
7 // mapping.
8 //
9
10 #include "libANGLE/renderer/vulkan/ShaderInterfaceVariableInfoMap.h"
11
12 namespace rx
13 {
14 namespace
15 {
HashSPIRVId(uint32_t id)16 uint32_t HashSPIRVId(uint32_t id)
17 {
18 ASSERT(id >= sh::vk::spirv::kIdShaderVariablesBegin);
19 return id - sh::vk::spirv::kIdShaderVariablesBegin;
20 }
21
LoadShaderInterfaceVariableXfbInfo(gl::BinaryInputStream * stream,ShaderInterfaceVariableXfbInfo * xfb)22 void LoadShaderInterfaceVariableXfbInfo(gl::BinaryInputStream *stream,
23 ShaderInterfaceVariableXfbInfo *xfb)
24 {
25 stream->readStruct(&xfb->pod);
26 xfb->arrayElements.resize(stream->readInt<size_t>());
27 for (ShaderInterfaceVariableXfbInfo &arrayElement : xfb->arrayElements)
28 {
29 LoadShaderInterfaceVariableXfbInfo(stream, &arrayElement);
30 }
31 }
32
SaveShaderInterfaceVariableXfbInfo(const ShaderInterfaceVariableXfbInfo & xfb,gl::BinaryOutputStream * stream)33 void SaveShaderInterfaceVariableXfbInfo(const ShaderInterfaceVariableXfbInfo &xfb,
34 gl::BinaryOutputStream *stream)
35 {
36 stream->writeStruct(xfb.pod);
37 stream->writeInt(xfb.arrayElements.size());
38 for (const ShaderInterfaceVariableXfbInfo &arrayElement : xfb.arrayElements)
39 {
40 SaveShaderInterfaceVariableXfbInfo(arrayElement, stream);
41 }
42 }
43 } // anonymous namespace
44
45 // ShaderInterfaceVariableInfoMap implementation.
ShaderInterfaceVariableInfoMap()46 ShaderInterfaceVariableInfoMap::ShaderInterfaceVariableInfoMap()
47 {
48 // Reserve storage for most common use case
49 mData.reserve(64);
50 }
51
52 ShaderInterfaceVariableInfoMap::~ShaderInterfaceVariableInfoMap() = default;
53
clear()54 void ShaderInterfaceVariableInfoMap::clear()
55 {
56 mData.clear();
57 mXFBData.clear();
58 memset(&mPod, 0, sizeof(mPod));
59 for (gl::ShaderType shaderType : gl::AllShaderTypes())
60 {
61 mIdToIndexMap[shaderType].clear();
62 }
63 }
64
save(gl::BinaryOutputStream * stream)65 void ShaderInterfaceVariableInfoMap::save(gl::BinaryOutputStream *stream)
66 {
67 ASSERT(mXFBData.size() <= mData.size());
68 stream->writeStruct(mPod);
69
70 for (const IdToIndexMap &idToIndexMap : mIdToIndexMap)
71 {
72 stream->writeInt(idToIndexMap.size());
73 if (idToIndexMap.size() > 0)
74 {
75 stream->writeBytes(reinterpret_cast<const uint8_t *>(idToIndexMap.data()),
76 idToIndexMap.size() * sizeof(*idToIndexMap.data()));
77 }
78 }
79
80 stream->writeVector(mData);
81 if (mPod.xfbInfoCount > 0)
82 {
83 uint32_t xfbInfoCount = 0;
84 for (size_t xfbIndex = 0; xfbIndex < mXFBData.size(); xfbIndex++)
85 {
86 if (!mXFBData[xfbIndex])
87 {
88 continue;
89 }
90 stream->writeInt(xfbIndex);
91 xfbInfoCount++;
92 XFBInterfaceVariableInfo &info = *mXFBData[xfbIndex];
93 SaveShaderInterfaceVariableXfbInfo(info.xfb, stream);
94 stream->writeInt(info.fieldXfb.size());
95 for (const ShaderInterfaceVariableXfbInfo &xfb : info.fieldXfb)
96 {
97 SaveShaderInterfaceVariableXfbInfo(xfb, stream);
98 }
99 }
100 ASSERT(xfbInfoCount == mPod.xfbInfoCount);
101 }
102 }
load(gl::BinaryInputStream * stream)103 void ShaderInterfaceVariableInfoMap::load(gl::BinaryInputStream *stream)
104 {
105 stream->readStruct(&mPod);
106
107 for (IdToIndexMap &idToIndexMap : mIdToIndexMap)
108 {
109 // ASSERT(idToIndexMap.empty());
110 size_t count = stream->readInt<size_t>();
111 if (count > 0)
112 {
113 idToIndexMap.resetWithRawData(count,
114 stream->getBytes(count * sizeof(*idToIndexMap.data())));
115 }
116 }
117
118 stream->readVector(&mData);
119 ASSERT(mXFBData.empty());
120 ASSERT(mPod.xfbInfoCount <= mData.size());
121 if (mPod.xfbInfoCount > 0)
122 {
123 mXFBData.resize(mData.size());
124 for (uint32_t i = 0; i < mPod.xfbInfoCount; ++i)
125 {
126 size_t xfbIndex = stream->readInt<size_t>();
127 mXFBData[xfbIndex] = std::make_unique<XFBInterfaceVariableInfo>();
128
129 XFBInterfaceVariableInfo &info = *mXFBData[xfbIndex];
130 LoadShaderInterfaceVariableXfbInfo(stream, &info.xfb);
131 info.fieldXfb.resize(stream->readInt<size_t>());
132 for (ShaderInterfaceVariableXfbInfo &xfb : info.fieldXfb)
133 {
134 LoadShaderInterfaceVariableXfbInfo(stream, &xfb);
135 }
136 }
137 }
138 }
139
setInputPerVertexActiveMembers(gl::ShaderType shaderType,gl::PerVertexMemberBitSet activeMembers)140 void ShaderInterfaceVariableInfoMap::setInputPerVertexActiveMembers(
141 gl::ShaderType shaderType,
142 gl::PerVertexMemberBitSet activeMembers)
143 {
144 // Input gl_PerVertex is only meaningful for tessellation and geometry stages
145 ASSERT(shaderType == gl::ShaderType::TessControl ||
146 shaderType == gl::ShaderType::TessEvaluation || shaderType == gl::ShaderType::Geometry ||
147 activeMembers.none());
148 mPod.inputPerVertexActiveMembers[shaderType] = activeMembers;
149 }
150
setOutputPerVertexActiveMembers(gl::ShaderType shaderType,gl::PerVertexMemberBitSet activeMembers)151 void ShaderInterfaceVariableInfoMap::setOutputPerVertexActiveMembers(
152 gl::ShaderType shaderType,
153 gl::PerVertexMemberBitSet activeMembers)
154 {
155 // Output gl_PerVertex is only meaningful for vertex, tessellation and geometry stages
156 ASSERT(shaderType == gl::ShaderType::Vertex || shaderType == gl::ShaderType::TessControl ||
157 shaderType == gl::ShaderType::TessEvaluation || shaderType == gl::ShaderType::Geometry ||
158 activeMembers.none());
159 mPod.outputPerVertexActiveMembers[shaderType] = activeMembers;
160 }
161
setVariableIndex(gl::ShaderType shaderType,uint32_t id,VariableIndex index)162 void ShaderInterfaceVariableInfoMap::setVariableIndex(gl::ShaderType shaderType,
163 uint32_t id,
164 VariableIndex index)
165 {
166 mIdToIndexMap[shaderType][HashSPIRVId(id)] = index;
167 }
168
getVariableIndex(gl::ShaderType shaderType,uint32_t id) const169 const VariableIndex &ShaderInterfaceVariableInfoMap::getVariableIndex(gl::ShaderType shaderType,
170 uint32_t id) const
171 {
172 return mIdToIndexMap[shaderType].at(HashSPIRVId(id));
173 }
174
getMutable(gl::ShaderType shaderType,uint32_t id)175 ShaderInterfaceVariableInfo &ShaderInterfaceVariableInfoMap::getMutable(gl::ShaderType shaderType,
176 uint32_t id)
177 {
178 ASSERT(hasVariable(shaderType, id));
179 uint32_t index = getVariableIndex(shaderType, id).index;
180 return mData[index];
181 }
182
getXFBMutable(gl::ShaderType shaderType,uint32_t id)183 XFBInterfaceVariableInfo *ShaderInterfaceVariableInfoMap::getXFBMutable(gl::ShaderType shaderType,
184 uint32_t id)
185 {
186 ASSERT(hasVariable(shaderType, id));
187 uint32_t index = getVariableIndex(shaderType, id).index;
188 if (index >= mXFBData.size())
189 {
190 mXFBData.resize(index + 1);
191 }
192 if (!mXFBData[index])
193 {
194 mXFBData[index] = std::make_unique<XFBInterfaceVariableInfo>();
195 mData[index].hasTransformFeedback = true;
196 mPod.xfbInfoCount++;
197 }
198 return mXFBData[index].get();
199 }
200
add(gl::ShaderType shaderType,uint32_t id)201 ShaderInterfaceVariableInfo &ShaderInterfaceVariableInfoMap::add(gl::ShaderType shaderType,
202 uint32_t id)
203 {
204 ASSERT(!hasVariable(shaderType, id));
205 uint32_t index = static_cast<uint32_t>(mData.size());
206 setVariableIndex(shaderType, id, {index});
207 mData.resize(index + 1);
208 return mData[index];
209 }
210
addResource(gl::ShaderBitSet shaderTypes,const gl::ShaderMap<uint32_t> & idInShaderTypes,uint32_t descriptorSet,uint32_t binding)211 void ShaderInterfaceVariableInfoMap::addResource(gl::ShaderBitSet shaderTypes,
212 const gl::ShaderMap<uint32_t> &idInShaderTypes,
213 uint32_t descriptorSet,
214 uint32_t binding)
215 {
216 uint32_t index = static_cast<uint32_t>(mData.size());
217 mData.resize(index + 1);
218 ShaderInterfaceVariableInfo *info = &mData[index];
219
220 info->descriptorSet = descriptorSet;
221 info->binding = binding;
222 info->activeStages = shaderTypes;
223
224 for (const gl::ShaderType shaderType : shaderTypes)
225 {
226 const uint32_t id = idInShaderTypes[shaderType];
227 ASSERT(!hasVariable(shaderType, id));
228 setVariableIndex(shaderType, id, {index});
229 }
230 }
231
addOrGet(gl::ShaderType shaderType,uint32_t id)232 ShaderInterfaceVariableInfo &ShaderInterfaceVariableInfoMap::addOrGet(gl::ShaderType shaderType,
233 uint32_t id)
234 {
235 if (!hasVariable(shaderType, id))
236 {
237 return add(shaderType, id);
238 }
239 else
240 {
241 uint32_t index = getVariableIndex(shaderType, id).index;
242 return mData[index];
243 }
244 }
245
hasVariable(gl::ShaderType shaderType,uint32_t id) const246 bool ShaderInterfaceVariableInfoMap::hasVariable(gl::ShaderType shaderType, uint32_t id) const
247 {
248 const uint32_t hashedId = HashSPIRVId(id);
249 return hashedId < mIdToIndexMap[shaderType].size() &&
250 mIdToIndexMap[shaderType].at(hashedId).index != VariableIndex::kInvalid;
251 }
252
hasTransformFeedbackInfo(gl::ShaderType shaderType,uint32_t bufferIndex) const253 bool ShaderInterfaceVariableInfoMap::hasTransformFeedbackInfo(gl::ShaderType shaderType,
254 uint32_t bufferIndex) const
255 {
256 return hasVariable(shaderType, SpvGetXfbBufferBlockId(bufferIndex));
257 }
258 } // namespace rx
259