Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / third_party / angle / src / libGLESv2 / renderer / d3d / d3d11 / InputLayoutCache.cpp
1 //
2 // Copyright (c) 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 "libGLESv2/renderer/d3d/d3d11/InputLayoutCache.h"
11 #include "libGLESv2/renderer/d3d/d3d11/VertexBuffer11.h"
12 #include "libGLESv2/renderer/d3d/d3d11/Buffer11.h"
13 #include "libGLESv2/renderer/d3d/d3d11/ShaderExecutable11.h"
14 #include "libGLESv2/renderer/d3d/d3d11/formatutils11.h"
15 #include "libGLESv2/renderer/d3d/ProgramD3D.h"
16 #include "libGLESv2/renderer/d3d/VertexDataManager.h"
17 #include "libGLESv2/ProgramBinary.h"
18 #include "libGLESv2/VertexAttribute.h"
19
20 #include "third_party/murmurhash/MurmurHash3.h"
21
22 namespace rx
23 {
24
25 static void GetInputLayout(const TranslatedAttribute translatedAttributes[gl::MAX_VERTEX_ATTRIBS],
26                            gl::VertexFormat inputLayout[gl::MAX_VERTEX_ATTRIBS])
27 {
28     for (unsigned int attributeIndex = 0; attributeIndex < gl::MAX_VERTEX_ATTRIBS; attributeIndex++)
29     {
30         const TranslatedAttribute &translatedAttribute = translatedAttributes[attributeIndex];
31
32         if (translatedAttributes[attributeIndex].active)
33         {
34             inputLayout[attributeIndex] = gl::VertexFormat(*translatedAttribute.attribute,
35                                                            translatedAttribute.currentValueType);
36         }
37     }
38 }
39
40 const unsigned int InputLayoutCache::kMaxInputLayouts = 1024;
41
42 InputLayoutCache::InputLayoutCache() : mInputLayoutMap(kMaxInputLayouts, hashInputLayout, compareInputLayouts)
43 {
44     mCounter = 0;
45     mDevice = NULL;
46     mDeviceContext = NULL;
47     mCurrentIL = NULL;
48     for (unsigned int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
49     {
50         mCurrentBuffers[i] = NULL;
51         mCurrentVertexStrides[i] = -1;
52         mCurrentVertexOffsets[i] = -1;
53     }
54 }
55
56 InputLayoutCache::~InputLayoutCache()
57 {
58     clear();
59 }
60
61 void InputLayoutCache::initialize(ID3D11Device *device, ID3D11DeviceContext *context)
62 {
63     clear();
64     mDevice = device;
65     mDeviceContext = context;
66 }
67
68 void InputLayoutCache::clear()
69 {
70     for (InputLayoutMap::iterator i = mInputLayoutMap.begin(); i != mInputLayoutMap.end(); i++)
71     {
72         SafeRelease(i->second.inputLayout);
73     }
74     mInputLayoutMap.clear();
75     markDirty();
76 }
77
78 void InputLayoutCache::markDirty()
79 {
80     mCurrentIL = NULL;
81     for (unsigned int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
82     {
83         mCurrentBuffers[i] = NULL;
84         mCurrentVertexStrides[i] = -1;
85         mCurrentVertexOffsets[i] = -1;
86     }
87 }
88
89 gl::Error InputLayoutCache::applyVertexBuffers(TranslatedAttribute attributes[gl::MAX_VERTEX_ATTRIBS],
90                                                gl::ProgramBinary *programBinary)
91 {
92     int sortedSemanticIndices[gl::MAX_VERTEX_ATTRIBS];
93     programBinary->sortAttributesByLayout(attributes, sortedSemanticIndices);
94
95     if (!mDevice || !mDeviceContext)
96     {
97         return gl::Error(GL_OUT_OF_MEMORY, "Internal input layout cache is not initialized.");
98     }
99
100     InputLayoutKey ilKey = { 0 };
101
102     static const char* semanticName = "TEXCOORD";
103
104     for (unsigned int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
105     {
106         if (attributes[i].active)
107         {
108             D3D11_INPUT_CLASSIFICATION inputClass = attributes[i].divisor > 0 ? D3D11_INPUT_PER_INSTANCE_DATA : D3D11_INPUT_PER_VERTEX_DATA;
109
110             gl::VertexFormat vertexFormat(*attributes[i].attribute, attributes[i].currentValueType);
111             const d3d11::VertexFormat &vertexFormatInfo = d3d11::GetVertexFormatInfo(vertexFormat);
112
113             // Record the type of the associated vertex shader vector in our key
114             // This will prevent mismatched vertex shaders from using the same input layout
115             GLint attributeSize;
116             programBinary->getActiveAttribute(ilKey.elementCount, 0, NULL, &attributeSize, &ilKey.elements[ilKey.elementCount].glslElementType, NULL);
117
118             ilKey.elements[ilKey.elementCount].desc.SemanticName = semanticName;
119             ilKey.elements[ilKey.elementCount].desc.SemanticIndex = sortedSemanticIndices[i];
120             ilKey.elements[ilKey.elementCount].desc.Format = vertexFormatInfo.nativeFormat;
121             ilKey.elements[ilKey.elementCount].desc.InputSlot = i;
122             ilKey.elements[ilKey.elementCount].desc.AlignedByteOffset = 0;
123             ilKey.elements[ilKey.elementCount].desc.InputSlotClass = inputClass;
124             ilKey.elements[ilKey.elementCount].desc.InstanceDataStepRate = attributes[i].divisor;
125             ilKey.elementCount++;
126         }
127     }
128
129     ID3D11InputLayout *inputLayout = NULL;
130
131     InputLayoutMap::iterator keyIter = mInputLayoutMap.find(ilKey);
132     if (keyIter != mInputLayoutMap.end())
133     {
134         inputLayout = keyIter->second.inputLayout;
135         keyIter->second.lastUsedTime = mCounter++;
136     }
137     else
138     {
139         gl::VertexFormat shaderInputLayout[gl::MAX_VERTEX_ATTRIBS];
140         GetInputLayout(attributes, shaderInputLayout);
141         ProgramD3D *programD3D = ProgramD3D::makeProgramD3D(programBinary->getImplementation());
142
143         ShaderExecutable *shader = NULL;
144         gl::Error error = programD3D->getVertexExecutableForInputLayout(shaderInputLayout, &shader);
145         if (error.isError())
146         {
147             return error;
148         }
149
150         ShaderExecutable *shader11 = ShaderExecutable11::makeShaderExecutable11(shader);
151
152         D3D11_INPUT_ELEMENT_DESC descs[gl::MAX_VERTEX_ATTRIBS];
153         for (unsigned int j = 0; j < ilKey.elementCount; ++j)
154         {
155             descs[j] = ilKey.elements[j].desc;
156         }
157
158         HRESULT result = mDevice->CreateInputLayout(descs, ilKey.elementCount, shader11->getFunction(), shader11->getLength(), &inputLayout);
159         if (FAILED(result))
160         {
161             return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal input layout, HRESULT: 0x%08x", result);
162         }
163
164         if (mInputLayoutMap.size() >= kMaxInputLayouts)
165         {
166             TRACE("Overflowed the limit of %u input layouts, removing the least recently used "
167                   "to make room.", kMaxInputLayouts);
168
169             InputLayoutMap::iterator leastRecentlyUsed = mInputLayoutMap.begin();
170             for (InputLayoutMap::iterator i = mInputLayoutMap.begin(); i != mInputLayoutMap.end(); i++)
171             {
172                 if (i->second.lastUsedTime < leastRecentlyUsed->second.lastUsedTime)
173                 {
174                     leastRecentlyUsed = i;
175                 }
176             }
177             SafeRelease(leastRecentlyUsed->second.inputLayout);
178             mInputLayoutMap.erase(leastRecentlyUsed);
179         }
180
181         InputLayoutCounterPair inputCounterPair;
182         inputCounterPair.inputLayout = inputLayout;
183         inputCounterPair.lastUsedTime = mCounter++;
184
185         mInputLayoutMap.insert(std::make_pair(ilKey, inputCounterPair));
186     }
187
188     if (inputLayout != mCurrentIL)
189     {
190         mDeviceContext->IASetInputLayout(inputLayout);
191         mCurrentIL = inputLayout;
192     }
193
194     bool dirtyBuffers = false;
195     size_t minDiff = gl::MAX_VERTEX_ATTRIBS;
196     size_t maxDiff = 0;
197     for (unsigned int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
198     {
199         ID3D11Buffer *buffer = NULL;
200
201         if (attributes[i].active)
202         {
203             VertexBuffer11 *vertexBuffer = VertexBuffer11::makeVertexBuffer11(attributes[i].vertexBuffer);
204             Buffer11 *bufferStorage = attributes[i].storage ? Buffer11::makeBuffer11(attributes[i].storage) : NULL;
205
206             buffer = bufferStorage ? bufferStorage->getBuffer(BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK)
207                                    : vertexBuffer->getBuffer();
208         }
209
210         UINT vertexStride = attributes[i].stride;
211         UINT vertexOffset = attributes[i].offset;
212
213         if (buffer != mCurrentBuffers[i] || vertexStride != mCurrentVertexStrides[i] ||
214             vertexOffset != mCurrentVertexOffsets[i])
215         {
216             dirtyBuffers = true;
217             minDiff = std::min(minDiff, static_cast<size_t>(i));
218             maxDiff = std::max(maxDiff, static_cast<size_t>(i));
219
220             mCurrentBuffers[i] = buffer;
221             mCurrentVertexStrides[i] = vertexStride;
222             mCurrentVertexOffsets[i] = vertexOffset;
223         }
224     }
225
226     if (dirtyBuffers)
227     {
228         ASSERT(minDiff <= maxDiff && maxDiff < gl::MAX_VERTEX_ATTRIBS);
229         mDeviceContext->IASetVertexBuffers(minDiff, maxDiff - minDiff + 1, mCurrentBuffers + minDiff,
230                                            mCurrentVertexStrides + minDiff, mCurrentVertexOffsets + minDiff);
231     }
232
233     return gl::Error(GL_NO_ERROR);
234 }
235
236 std::size_t InputLayoutCache::hashInputLayout(const InputLayoutKey &inputLayout)
237 {
238     static const unsigned int seed = 0xDEADBEEF;
239
240     std::size_t hash = 0;
241     MurmurHash3_x86_32(inputLayout.begin(), inputLayout.end() - inputLayout.begin(), seed, &hash);
242     return hash;
243 }
244
245 bool InputLayoutCache::compareInputLayouts(const InputLayoutKey &a, const InputLayoutKey &b)
246 {
247     if (a.elementCount != b.elementCount)
248     {
249         return false;
250     }
251
252     return std::equal(a.begin(), a.end(), b.begin());
253 }
254
255 }