• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 *> &currentAttributes,
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 &currentValue =
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 *> &currentAttributes,
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