1 //
2 // Copyright 2012 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
7 // InputLayoutCache.cpp: Defines InputLayoutCache, a class that builds and caches
8 // D3D11 input layouts.
9
10 #include "libANGLE/renderer/d3d/d3d11/InputLayoutCache.h"
11
12 #include "common/bitset_utils.h"
13 #include "common/utilities.h"
14 #include "libANGLE/Context.h"
15 #include "libANGLE/Program.h"
16 #include "libANGLE/ProgramExecutable.h"
17 #include "libANGLE/VertexArray.h"
18 #include "libANGLE/VertexAttribute.h"
19 #include "libANGLE/renderer/d3d/IndexDataManager.h"
20 #include "libANGLE/renderer/d3d/ProgramD3D.h"
21 #include "libANGLE/renderer/d3d/VertexDataManager.h"
22 #include "libANGLE/renderer/d3d/d3d11/Context11.h"
23 #include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
24 #include "libANGLE/renderer/d3d/d3d11/ShaderExecutable11.h"
25 #include "libANGLE/renderer/d3d/d3d11/VertexArray11.h"
26 #include "libANGLE/renderer/d3d/d3d11/formatutils11.h"
27
28 namespace rx
29 {
30
31 namespace
32 {
33
GetGLSLAttributeType(const std::vector<gl::ProgramInput> & shaderAttributes,size_t index)34 GLenum GetGLSLAttributeType(const std::vector<gl::ProgramInput> &shaderAttributes, size_t index)
35 {
36 // Count matrices differently
37 for (const gl::ProgramInput &attrib : shaderAttributes)
38 {
39 if (attrib.getLocation() == -1)
40 {
41 continue;
42 }
43
44 GLenum transposedType = gl::TransposeMatrixType(attrib.getType());
45 int rows = gl::VariableRowCount(transposedType);
46 int intIndex = static_cast<int>(index);
47
48 if (intIndex >= attrib.getLocation() && intIndex < attrib.getLocation() + rows)
49 {
50 return transposedType;
51 }
52 }
53
54 UNREACHABLE();
55 return GL_NONE;
56 }
57
58 struct PackedAttribute
59 {
60 uint8_t attribType;
61 uint8_t semanticIndex;
62 uint8_t vertexFormatType;
63 uint8_t unusedPadding;
64 uint32_t divisor;
65 };
66
67 } // anonymous namespace
68
PackedAttributeLayout()69 PackedAttributeLayout::PackedAttributeLayout() : numAttributes(0), flags(0), attributeData({}) {}
70
71 PackedAttributeLayout::PackedAttributeLayout(const PackedAttributeLayout &other) = default;
72
addAttributeData(GLenum glType,UINT semanticIndex,angle::FormatID vertexFormatID,unsigned int divisor)73 void PackedAttributeLayout::addAttributeData(GLenum glType,
74 UINT semanticIndex,
75 angle::FormatID vertexFormatID,
76 unsigned int divisor)
77 {
78 gl::AttributeType attribType = gl::GetAttributeType(glType);
79
80 PackedAttribute packedAttrib;
81 packedAttrib.attribType = static_cast<uint8_t>(attribType);
82 packedAttrib.semanticIndex = static_cast<uint8_t>(semanticIndex);
83 packedAttrib.vertexFormatType = static_cast<uint8_t>(vertexFormatID);
84 packedAttrib.unusedPadding = 0u;
85 packedAttrib.divisor = static_cast<uint32_t>(divisor);
86
87 ASSERT(static_cast<gl::AttributeType>(packedAttrib.attribType) == attribType);
88 ASSERT(static_cast<UINT>(packedAttrib.semanticIndex) == semanticIndex);
89 ASSERT(static_cast<angle::FormatID>(packedAttrib.vertexFormatType) == vertexFormatID);
90 ASSERT(static_cast<unsigned int>(packedAttrib.divisor) == divisor);
91
92 static_assert(sizeof(uint64_t) == sizeof(PackedAttribute),
93 "PackedAttributes must be 64-bits exactly.");
94
95 attributeData[numAttributes++] = gl::bitCast<uint64_t>(packedAttrib);
96 }
97
operator ==(const PackedAttributeLayout & other) const98 bool PackedAttributeLayout::operator==(const PackedAttributeLayout &other) const
99 {
100 return (numAttributes == other.numAttributes) && (flags == other.flags) &&
101 (attributeData == other.attributeData);
102 }
103
InputLayoutCache()104 InputLayoutCache::InputLayoutCache() : mLayoutCache(kDefaultCacheSize * 2) {}
105
~InputLayoutCache()106 InputLayoutCache::~InputLayoutCache() {}
107
clear()108 void InputLayoutCache::clear()
109 {
110 mLayoutCache.Clear();
111 }
112
getInputLayout(Context11 * context11,const gl::State & state,const std::vector<const TranslatedAttribute * > & currentAttributes,const AttribIndexArray & sortedSemanticIndices,gl::PrimitiveMode mode,GLsizei vertexCount,GLsizei instances,const d3d11::InputLayout ** inputLayoutOut)113 angle::Result InputLayoutCache::getInputLayout(
114 Context11 *context11,
115 const gl::State &state,
116 const std::vector<const TranslatedAttribute *> ¤tAttributes,
117 const AttribIndexArray &sortedSemanticIndices,
118 gl::PrimitiveMode mode,
119 GLsizei vertexCount,
120 GLsizei instances,
121 const d3d11::InputLayout **inputLayoutOut)
122 {
123 gl::ProgramExecutable *executable = state.getProgramExecutable();
124 const auto &shaderAttributes = executable->getProgramInputs();
125 PackedAttributeLayout layout;
126
127 ProgramExecutableD3D *executableD3D = GetImplAs<ProgramExecutableD3D>(executable);
128 bool programUsesInstancedPointSprites =
129 executableD3D->usesPointSize() &&
130 executableD3D->usesInstancedPointSpriteEmulation(context11->getRenderer());
131 bool instancedPointSpritesActive =
132 programUsesInstancedPointSprites && (mode == gl::PrimitiveMode::Points);
133
134 if (programUsesInstancedPointSprites)
135 {
136 layout.flags |= PackedAttributeLayout::FLAG_USES_INSTANCED_SPRITES;
137 }
138
139 if (instancedPointSpritesActive)
140 {
141 layout.flags |= PackedAttributeLayout::FLAG_INSTANCED_SPRITES_ACTIVE;
142 }
143
144 if (instances > 0)
145 {
146 layout.flags |= PackedAttributeLayout::FLAG_INSTANCED_RENDERING_ACTIVE;
147 }
148
149 const auto &attribs = state.getVertexArray()->getVertexAttributes();
150 const auto &bindings = state.getVertexArray()->getVertexBindings();
151 const auto &locationToSemantic = executableD3D->getAttribLocationToD3DSemantics();
152 int divisorMultiplier = executable->usesMultiview() ? executable->getNumViews() : 1;
153
154 for (size_t attribIndex : executable->getActiveAttribLocationsMask())
155 {
156 // Record the type of the associated vertex shader vector in our key
157 // This will prevent mismatched vertex shaders from using the same input layout
158 GLenum glslElementType = GetGLSLAttributeType(shaderAttributes, attribIndex);
159
160 const auto &attrib = attribs[attribIndex];
161 const auto &binding = bindings[attrib.bindingIndex];
162 int d3dSemantic = locationToSemantic[attribIndex];
163
164 const auto ¤tValue =
165 state.getVertexAttribCurrentValue(static_cast<unsigned int>(attribIndex));
166 angle::FormatID vertexFormatID = gl::GetVertexFormatID(attrib, currentValue.Type);
167
168 layout.addAttributeData(glslElementType, d3dSemantic, vertexFormatID,
169 binding.getDivisor() * divisorMultiplier);
170 }
171
172 if (layout.numAttributes > 0 || layout.flags != 0)
173 {
174 auto it = mLayoutCache.Get(layout);
175 if (it != mLayoutCache.end())
176 {
177 *inputLayoutOut = &it->second;
178 }
179 else
180 {
181 angle::TrimCache(mLayoutCache.max_size() / 2, kGCLimit, "input layout", &mLayoutCache);
182
183 d3d11::InputLayout newInputLayout;
184 ANGLE_TRY(createInputLayout(context11, sortedSemanticIndices, currentAttributes, mode,
185 vertexCount, instances, &newInputLayout));
186
187 auto insertIt = mLayoutCache.Put(layout, std::move(newInputLayout));
188 *inputLayoutOut = &insertIt->second;
189 }
190 }
191
192 return angle::Result::Continue;
193 }
194
createInputLayout(Context11 * context11,const AttribIndexArray & sortedSemanticIndices,const std::vector<const TranslatedAttribute * > & currentAttributes,gl::PrimitiveMode mode,GLsizei vertexCount,GLsizei instances,d3d11::InputLayout * inputLayoutOut)195 angle::Result InputLayoutCache::createInputLayout(
196 Context11 *context11,
197 const AttribIndexArray &sortedSemanticIndices,
198 const std::vector<const TranslatedAttribute *> ¤tAttributes,
199 gl::PrimitiveMode mode,
200 GLsizei vertexCount,
201 GLsizei instances,
202 d3d11::InputLayout *inputLayoutOut)
203 {
204 Renderer11 *renderer = context11->getRenderer();
205 ProgramExecutableD3D *executableD3D = renderer->getStateManager()->getProgramExecutableD3D();
206 D3D_FEATURE_LEVEL featureLevel = renderer->getRenderer11DeviceCaps().featureLevel;
207
208 bool programUsesInstancedPointSprites =
209 executableD3D->usesPointSize() &&
210 executableD3D->usesInstancedPointSpriteEmulation(renderer);
211
212 unsigned int inputElementCount = 0;
213 gl::AttribArray<D3D11_INPUT_ELEMENT_DESC> inputElements;
214
215 for (size_t attribIndex = 0; attribIndex < currentAttributes.size(); ++attribIndex)
216 {
217 const auto &attrib = *currentAttributes[attribIndex];
218 const int sortedIndex = sortedSemanticIndices[attribIndex];
219
220 D3D11_INPUT_CLASSIFICATION inputClass =
221 attrib.divisor > 0 ? D3D11_INPUT_PER_INSTANCE_DATA : D3D11_INPUT_PER_VERTEX_DATA;
222
223 angle::FormatID vertexFormatID =
224 gl::GetVertexFormatID(*attrib.attribute, attrib.currentValueType);
225 const auto &vertexFormatInfo = d3d11::GetVertexFormatInfo(vertexFormatID, featureLevel);
226
227 auto *inputElement = &inputElements[inputElementCount];
228
229 inputElement->SemanticName = "TEXCOORD";
230 inputElement->SemanticIndex = sortedIndex;
231 inputElement->Format = vertexFormatInfo.nativeFormat;
232 inputElement->InputSlot = static_cast<UINT>(attribIndex);
233 inputElement->AlignedByteOffset = 0;
234 inputElement->InputSlotClass = inputClass;
235 inputElement->InstanceDataStepRate = attrib.divisor;
236
237 inputElementCount++;
238 }
239
240 // Instanced PointSprite emulation requires additional entries in the
241 // inputlayout to support the vertices that make up the pointsprite quad.
242 // We do this even if mode != GL_POINTS, since the shader signature has these inputs, and the
243 // input layout must match the shader
244 if (programUsesInstancedPointSprites)
245 {
246 // On 9_3, we must ensure that slot 0 contains non-instanced data.
247 // If slot 0 currently contains instanced data then we swap it with a non-instanced element.
248 // Note that instancing is only available on 9_3 via ANGLE_instanced_arrays, since 9_3
249 // doesn't support OpenGL ES 3.0.
250 // As per the spec for ANGLE_instanced_arrays, not all attributes can be instanced
251 // simultaneously, so a non-instanced element must exist.
252
253 UINT numIndicesPerInstance = 0;
254 if (instances > 0)
255 {
256 // This requires that the index range is resolved.
257 // Note: Vertex indexes can be arbitrarily large.
258 numIndicesPerInstance = gl::clampCast<UINT>(vertexCount);
259 }
260
261 for (size_t elementIndex = 0; elementIndex < inputElementCount; ++elementIndex)
262 {
263 // If rendering points and instanced pointsprite emulation is being used, the
264 // inputClass is required to be configured as per instance data
265 if (mode == gl::PrimitiveMode::Points)
266 {
267 inputElements[elementIndex].InputSlotClass = D3D11_INPUT_PER_INSTANCE_DATA;
268 inputElements[elementIndex].InstanceDataStepRate = 1;
269 if (numIndicesPerInstance > 0 && currentAttributes[elementIndex]->divisor > 0)
270 {
271 inputElements[elementIndex].InstanceDataStepRate = numIndicesPerInstance;
272 }
273 }
274 inputElements[elementIndex].InputSlot++;
275 }
276
277 inputElements[inputElementCount].SemanticName = "SPRITEPOSITION";
278 inputElements[inputElementCount].SemanticIndex = 0;
279 inputElements[inputElementCount].Format = DXGI_FORMAT_R32G32B32_FLOAT;
280 inputElements[inputElementCount].InputSlot = 0;
281 inputElements[inputElementCount].AlignedByteOffset = 0;
282 inputElements[inputElementCount].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
283 inputElements[inputElementCount].InstanceDataStepRate = 0;
284 inputElementCount++;
285
286 inputElements[inputElementCount].SemanticName = "SPRITETEXCOORD";
287 inputElements[inputElementCount].SemanticIndex = 0;
288 inputElements[inputElementCount].Format = DXGI_FORMAT_R32G32_FLOAT;
289 inputElements[inputElementCount].InputSlot = 0;
290 inputElements[inputElementCount].AlignedByteOffset = sizeof(float) * 3;
291 inputElements[inputElementCount].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
292 inputElements[inputElementCount].InstanceDataStepRate = 0;
293 inputElementCount++;
294 }
295
296 ShaderExecutableD3D *shader = nullptr;
297 ANGLE_TRY(executableD3D->getVertexExecutableForCachedInputLayout(context11, renderer, &shader,
298 nullptr));
299
300 ShaderExecutableD3D *shader11 = GetAs<ShaderExecutable11>(shader);
301
302 InputElementArray inputElementArray(inputElements.data(), inputElementCount);
303 ShaderData vertexShaderData(shader11->getFunction(), shader11->getLength());
304
305 ANGLE_TRY(renderer->allocateResource(context11, inputElementArray, &vertexShaderData,
306 inputLayoutOut));
307 return angle::Result::Continue;
308 }
309
setCacheSize(size_t newCacheSize)310 void InputLayoutCache::setCacheSize(size_t newCacheSize)
311 {
312 // Forces a reset of the cache.
313 LayoutCache newCache(newCacheSize);
314 mLayoutCache.Swap(newCache);
315 }
316
317 } // namespace rx
318