• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include "precompiled.h"
2 //
3 // Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
4 // Use of this source code is governed by a BSD-style license that can be
5 // found in the LICENSE file.
6 //
7 
8 // InputLayoutCache.cpp: Defines InputLayoutCache, a class that builds and caches
9 // D3D11 input layouts.
10 
11 #include "libGLESv2/renderer/InputLayoutCache.h"
12 #include "libGLESv2/renderer/VertexBuffer11.h"
13 #include "libGLESv2/renderer/BufferStorage11.h"
14 #include "libGLESv2/renderer/ShaderExecutable11.h"
15 #include "libGLESv2/ProgramBinary.h"
16 #include "libGLESv2/Context.h"
17 #include "libGLESv2/renderer/VertexDataManager.h"
18 
19 #include "third_party/murmurhash/MurmurHash3.h"
20 
21 namespace rx
22 {
23 
24 const unsigned int InputLayoutCache::kMaxInputLayouts = 1024;
25 
InputLayoutCache()26 InputLayoutCache::InputLayoutCache() : mInputLayoutMap(kMaxInputLayouts, hashInputLayout, compareInputLayouts)
27 {
28     mCounter = 0;
29     mDevice = NULL;
30     mDeviceContext = NULL;
31     mCurrentIL = NULL;
32     for (unsigned int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
33     {
34         mCurrentBuffers[i] = -1;
35         mCurrentVertexStrides[i] = -1;
36         mCurrentVertexOffsets[i] = -1;
37     }
38 }
39 
~InputLayoutCache()40 InputLayoutCache::~InputLayoutCache()
41 {
42     clear();
43 }
44 
initialize(ID3D11Device * device,ID3D11DeviceContext * context)45 void InputLayoutCache::initialize(ID3D11Device *device, ID3D11DeviceContext *context)
46 {
47     clear();
48     mDevice = device;
49     mDeviceContext = context;
50 }
51 
clear()52 void InputLayoutCache::clear()
53 {
54     for (InputLayoutMap::iterator i = mInputLayoutMap.begin(); i != mInputLayoutMap.end(); i++)
55     {
56         i->second.inputLayout->Release();
57     }
58     mInputLayoutMap.clear();
59     markDirty();
60 }
61 
markDirty()62 void InputLayoutCache::markDirty()
63 {
64     mCurrentIL = NULL;
65     for (unsigned int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
66     {
67         mCurrentBuffers[i] = -1;
68         mCurrentVertexStrides[i] = -1;
69         mCurrentVertexOffsets[i] = -1;
70     }
71 }
72 
applyVertexBuffers(TranslatedAttribute attributes[gl::MAX_VERTEX_ATTRIBS],gl::ProgramBinary * programBinary)73 GLenum InputLayoutCache::applyVertexBuffers(TranslatedAttribute attributes[gl::MAX_VERTEX_ATTRIBS],
74                                             gl::ProgramBinary *programBinary)
75 {
76     int sortedSemanticIndices[gl::MAX_VERTEX_ATTRIBS];
77     programBinary->sortAttributesByLayout(attributes, sortedSemanticIndices);
78 
79     if (!mDevice || !mDeviceContext)
80     {
81         ERR("InputLayoutCache is not initialized.");
82         return GL_INVALID_OPERATION;
83     }
84 
85     InputLayoutKey ilKey = { 0 };
86 
87     ID3D11Buffer *vertexBuffers[gl::MAX_VERTEX_ATTRIBS] = { NULL };
88     unsigned int vertexBufferSerials[gl::MAX_VERTEX_ATTRIBS] = { 0 };
89     UINT vertexStrides[gl::MAX_VERTEX_ATTRIBS] = { 0 };
90     UINT vertexOffsets[gl::MAX_VERTEX_ATTRIBS] = { 0 };
91 
92     static const char* semanticName = "TEXCOORD";
93 
94     for (unsigned int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
95     {
96         if (attributes[i].active)
97         {
98             VertexBuffer11 *vertexBuffer = VertexBuffer11::makeVertexBuffer11(attributes[i].vertexBuffer);
99             BufferStorage11 *bufferStorage = attributes[i].storage ? BufferStorage11::makeBufferStorage11(attributes[i].storage) : NULL;
100 
101             D3D11_INPUT_CLASSIFICATION inputClass = attributes[i].divisor > 0 ? D3D11_INPUT_PER_INSTANCE_DATA : D3D11_INPUT_PER_VERTEX_DATA;
102 
103             // Record the type of the associated vertex shader vector in our key
104             // This will prevent mismatched vertex shaders from using the same input layout
105             GLint attributeSize;
106             programBinary->getActiveAttribute(ilKey.elementCount, 0, NULL, &attributeSize, &ilKey.elements[ilKey.elementCount].glslElementType, NULL);
107 
108             ilKey.elements[ilKey.elementCount].desc.SemanticName = semanticName;
109             ilKey.elements[ilKey.elementCount].desc.SemanticIndex = sortedSemanticIndices[i];
110             ilKey.elements[ilKey.elementCount].desc.Format = attributes[i].attribute->mArrayEnabled ? vertexBuffer->getDXGIFormat(*attributes[i].attribute) : DXGI_FORMAT_R32G32B32A32_FLOAT;
111             ilKey.elements[ilKey.elementCount].desc.InputSlot = i;
112             ilKey.elements[ilKey.elementCount].desc.AlignedByteOffset = 0;
113             ilKey.elements[ilKey.elementCount].desc.InputSlotClass = inputClass;
114             ilKey.elements[ilKey.elementCount].desc.InstanceDataStepRate = attributes[i].divisor;
115             ilKey.elementCount++;
116 
117             vertexBuffers[i] = bufferStorage ? bufferStorage->getBuffer() : vertexBuffer->getBuffer();
118             vertexBufferSerials[i] = bufferStorage ? bufferStorage->getSerial() : vertexBuffer->getSerial();
119             vertexStrides[i] = attributes[i].stride;
120             vertexOffsets[i] = attributes[i].offset;
121         }
122     }
123 
124     ID3D11InputLayout *inputLayout = NULL;
125 
126     InputLayoutMap::iterator i = mInputLayoutMap.find(ilKey);
127     if (i != mInputLayoutMap.end())
128     {
129         inputLayout = i->second.inputLayout;
130         i->second.lastUsedTime = mCounter++;
131     }
132     else
133     {
134         ShaderExecutable11 *shader = ShaderExecutable11::makeShaderExecutable11(programBinary->getVertexExecutable());
135 
136         D3D11_INPUT_ELEMENT_DESC descs[gl::MAX_VERTEX_ATTRIBS];
137         for (unsigned int j = 0; j < ilKey.elementCount; ++j)
138         {
139             descs[j] = ilKey.elements[j].desc;
140         }
141 
142         HRESULT result = mDevice->CreateInputLayout(descs, ilKey.elementCount, shader->getFunction(), shader->getLength(), &inputLayout);
143         if (FAILED(result))
144         {
145             ERR("Failed to crate input layout, result: 0x%08x", result);
146             return GL_INVALID_OPERATION;
147         }
148 
149         if (mInputLayoutMap.size() >= kMaxInputLayouts)
150         {
151             TRACE("Overflowed the limit of %u input layouts, removing the least recently used "
152                   "to make room.", kMaxInputLayouts);
153 
154             InputLayoutMap::iterator leastRecentlyUsed = mInputLayoutMap.begin();
155             for (InputLayoutMap::iterator i = mInputLayoutMap.begin(); i != mInputLayoutMap.end(); i++)
156             {
157                 if (i->second.lastUsedTime < leastRecentlyUsed->second.lastUsedTime)
158                 {
159                     leastRecentlyUsed = i;
160                 }
161             }
162             leastRecentlyUsed->second.inputLayout->Release();
163             mInputLayoutMap.erase(leastRecentlyUsed);
164         }
165 
166         InputLayoutCounterPair inputCounterPair;
167         inputCounterPair.inputLayout = inputLayout;
168         inputCounterPair.lastUsedTime = mCounter++;
169 
170         mInputLayoutMap.insert(std::make_pair(ilKey, inputCounterPair));
171     }
172 
173     if (inputLayout != mCurrentIL)
174     {
175         mDeviceContext->IASetInputLayout(inputLayout);
176         mCurrentIL = inputLayout;
177     }
178 
179     for (unsigned int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
180     {
181         if (vertexBufferSerials[i] != mCurrentBuffers[i] || vertexStrides[i] != mCurrentVertexStrides[i] ||
182             vertexOffsets[i] != mCurrentVertexOffsets[i])
183         {
184             mDeviceContext->IASetVertexBuffers(i, 1, &vertexBuffers[i], &vertexStrides[i], &vertexOffsets[i]);
185             mCurrentBuffers[i] = vertexBufferSerials[i];
186             mCurrentVertexStrides[i] = vertexStrides[i];
187             mCurrentVertexOffsets[i] = vertexOffsets[i];
188         }
189     }
190 
191     return GL_NO_ERROR;
192 }
193 
hashInputLayout(const InputLayoutKey & inputLayout)194 std::size_t InputLayoutCache::hashInputLayout(const InputLayoutKey &inputLayout)
195 {
196     static const unsigned int seed = 0xDEADBEEF;
197 
198     std::size_t hash = 0;
199     MurmurHash3_x86_32(inputLayout.begin(), inputLayout.end() - inputLayout.begin(), seed, &hash);
200     return hash;
201 }
202 
compareInputLayouts(const InputLayoutKey & a,const InputLayoutKey & b)203 bool InputLayoutCache::compareInputLayouts(const InputLayoutKey &a, const InputLayoutKey &b)
204 {
205     if (a.elementCount != b.elementCount)
206     {
207         return false;
208     }
209 
210     return std::equal(a.begin(), a.end(), b.begin());
211 }
212 
213 }
214