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 *> &currentAttributes,
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 &currentValue =
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 *> &currentAttributes,
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