InputLayoutCache.cpp (12547B)
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 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 68 PackedAttributeLayout::PackedAttributeLayout() : numAttributes(0), flags(0), attributeData({}) {} 69 70 PackedAttributeLayout::PackedAttributeLayout(const PackedAttributeLayout &other) = default; 71 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 97 bool PackedAttributeLayout::operator==(const PackedAttributeLayout &other) const 98 { 99 return (numAttributes == other.numAttributes) && (flags == other.flags) && 100 (attributeData == other.attributeData); 101 } 102 103 InputLayoutCache::InputLayoutCache() : mLayoutCache(kDefaultCacheSize * 2) {} 104 105 InputLayoutCache::~InputLayoutCache() {} 106 107 void InputLayoutCache::clear() 108 { 109 mLayoutCache.Clear(); 110 } 111 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 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 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