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), 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) && (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::ProgramExecutable *executable = state.getProgramExecutable();
123 const auto &shaderAttributes = executable->getProgramInputs();
124 PackedAttributeLayout layout;
125
126 ProgramExecutableD3D *executableD3D = GetImplAs<ProgramExecutableD3D>(executable);
127 const auto &attribs = state.getVertexArray()->getVertexAttributes();
128 const auto &bindings = state.getVertexArray()->getVertexBindings();
129 const auto &locationToSemantic = executableD3D->getAttribLocationToD3DSemantics();
130 int divisorMultiplier = executable->usesMultiview() ? executable->getNumViews() : 1;
131
132 for (size_t attribIndex : executable->getActiveAttribLocationsMask())
133 {
134 // Record the type of the associated vertex shader vector in our key
135 // This will prevent mismatched vertex shaders from using the same input layout
136 GLenum glslElementType = GetGLSLAttributeType(shaderAttributes, attribIndex);
137
138 const auto &attrib = attribs[attribIndex];
139 const auto &binding = bindings[attrib.bindingIndex];
140 int d3dSemantic = locationToSemantic[attribIndex];
141
142 const auto ¤tValue =
143 state.getVertexAttribCurrentValue(static_cast<unsigned int>(attribIndex));
144 angle::FormatID vertexFormatID = gl::GetVertexFormatID(attrib, currentValue.Type);
145
146 layout.addAttributeData(glslElementType, d3dSemantic, vertexFormatID,
147 binding.getDivisor() * divisorMultiplier);
148 }
149
150 if (layout.numAttributes > 0)
151 {
152 auto it = mLayoutCache.Get(layout);
153 if (it != mLayoutCache.end())
154 {
155 *inputLayoutOut = &it->second;
156 }
157 else
158 {
159 angle::TrimCache(mLayoutCache.max_size() / 2, kGCLimit, "input layout", &mLayoutCache);
160
161 d3d11::InputLayout newInputLayout;
162 ANGLE_TRY(createInputLayout(context11, sortedSemanticIndices, currentAttributes, mode,
163 vertexCount, instances, &newInputLayout));
164
165 auto insertIt = mLayoutCache.Put(layout, std::move(newInputLayout));
166 *inputLayoutOut = &insertIt->second;
167 }
168 }
169
170 return angle::Result::Continue;
171 }
172
createInputLayout(Context11 * context11,const AttribIndexArray & sortedSemanticIndices,const std::vector<const TranslatedAttribute * > & currentAttributes,gl::PrimitiveMode mode,GLsizei vertexCount,GLsizei instances,d3d11::InputLayout * inputLayoutOut)173 angle::Result InputLayoutCache::createInputLayout(
174 Context11 *context11,
175 const AttribIndexArray &sortedSemanticIndices,
176 const std::vector<const TranslatedAttribute *> ¤tAttributes,
177 gl::PrimitiveMode mode,
178 GLsizei vertexCount,
179 GLsizei instances,
180 d3d11::InputLayout *inputLayoutOut)
181 {
182 Renderer11 *renderer = context11->getRenderer();
183 ProgramExecutableD3D *executableD3D = renderer->getStateManager()->getProgramExecutableD3D();
184 D3D_FEATURE_LEVEL featureLevel = renderer->getRenderer11DeviceCaps().featureLevel;
185
186 unsigned int inputElementCount = 0;
187 gl::AttribArray<D3D11_INPUT_ELEMENT_DESC> inputElements;
188
189 for (size_t attribIndex = 0; attribIndex < currentAttributes.size(); ++attribIndex)
190 {
191 const auto &attrib = *currentAttributes[attribIndex];
192 const int sortedIndex = sortedSemanticIndices[attribIndex];
193
194 D3D11_INPUT_CLASSIFICATION inputClass =
195 attrib.divisor > 0 ? D3D11_INPUT_PER_INSTANCE_DATA : D3D11_INPUT_PER_VERTEX_DATA;
196
197 angle::FormatID vertexFormatID =
198 gl::GetVertexFormatID(*attrib.attribute, attrib.currentValueType);
199 const auto &vertexFormatInfo = d3d11::GetVertexFormatInfo(vertexFormatID, featureLevel);
200
201 auto *inputElement = &inputElements[inputElementCount];
202
203 inputElement->SemanticName = "TEXCOORD";
204 inputElement->SemanticIndex = sortedIndex;
205 inputElement->Format = vertexFormatInfo.nativeFormat;
206 inputElement->InputSlot = static_cast<UINT>(attribIndex);
207 inputElement->AlignedByteOffset = 0;
208 inputElement->InputSlotClass = inputClass;
209 inputElement->InstanceDataStepRate = attrib.divisor;
210
211 inputElementCount++;
212 }
213
214 ShaderExecutableD3D *shader = nullptr;
215 ANGLE_TRY(executableD3D->getVertexExecutableForCachedInputLayout(context11, renderer, &shader,
216 nullptr));
217
218 ShaderExecutableD3D *shader11 = GetAs<ShaderExecutable11>(shader);
219
220 InputElementArray inputElementArray(inputElements.data(), inputElementCount);
221 ShaderData vertexShaderData(shader11->getFunction(), shader11->getLength());
222
223 ANGLE_TRY(renderer->allocateResource(context11, inputElementArray, &vertexShaderData,
224 inputLayoutOut));
225 return angle::Result::Continue;
226 }
227
setCacheSize(size_t newCacheSize)228 void InputLayoutCache::setCacheSize(size_t newCacheSize)
229 {
230 // Forces a reset of the cache.
231 LayoutCache newCache(newCacheSize);
232 mLayoutCache.Swap(newCache);
233 }
234
235 } // namespace rx
236