xref: /aosp_15_r20/external/angle/src/libANGLE/renderer/d3d/d3d11/InputLayoutCache.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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 *> &currentAttributes,
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 &currentValue =
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 *> &currentAttributes,
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