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