blob: 7092dc5ddd434b0af8327cabcc1302e720e165bb [file] [log] [blame]
shannon.woods@transgaming.combdf2d802013-02-28 23:16:20 +00001#include "precompiled.h"
daniel@transgaming.comcd9458d2012-12-20 21:10:09 +00002//
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
Geoff Langd47e0fc2013-08-29 11:40:43 -040011#include "libGLESv2/renderer/d3d11/InputLayoutCache.h"
12#include "libGLESv2/renderer/d3d11/VertexBuffer11.h"
13#include "libGLESv2/renderer/d3d11/BufferStorage11.h"
14#include "libGLESv2/renderer/d3d11/ShaderExecutable11.h"
daniel@transgaming.comcd9458d2012-12-20 21:10:09 +000015#include "libGLESv2/ProgramBinary.h"
Jamie Madill87939712013-07-02 11:57:01 -040016#include "libGLESv2/VertexAttribute.h"
shannon.woods@transgaming.com486d9e92013-02-28 23:15:41 +000017#include "libGLESv2/renderer/VertexDataManager.h"
Jamie Madill7ab02fa2014-02-04 16:04:08 -050018#include "libGLESv2/renderer/d3d11/formatutils11.h"
daniel@transgaming.comcd9458d2012-12-20 21:10:09 +000019
20#include "third_party/murmurhash/MurmurHash3.h"
21
22namespace rx
23{
24
Jamie Madillc5a83002014-02-14 16:41:25 -050025static 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
daniel@transgaming.comcd9458d2012-12-20 21:10:09 +000040const unsigned int InputLayoutCache::kMaxInputLayouts = 1024;
41
42InputLayoutCache::InputLayoutCache() : mInputLayoutMap(kMaxInputLayouts, hashInputLayout, compareInputLayouts)
43{
44 mCounter = 0;
45 mDevice = NULL;
46 mDeviceContext = NULL;
Geoff Lang1f53cab2013-07-22 10:37:22 -040047 mCurrentIL = NULL;
48 for (unsigned int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
49 {
Geoff Lang7840b172014-03-13 11:20:44 -040050 mCurrentBuffers[i] = NULL;
Geoff Lang1f53cab2013-07-22 10:37:22 -040051 mCurrentVertexStrides[i] = -1;
52 mCurrentVertexOffsets[i] = -1;
53 }
daniel@transgaming.comcd9458d2012-12-20 21:10:09 +000054}
55
56InputLayoutCache::~InputLayoutCache()
57{
58 clear();
59}
60
61void InputLayoutCache::initialize(ID3D11Device *device, ID3D11DeviceContext *context)
62{
63 clear();
64 mDevice = device;
65 mDeviceContext = context;
66}
67
68void InputLayoutCache::clear()
69{
70 for (InputLayoutMap::iterator i = mInputLayoutMap.begin(); i != mInputLayoutMap.end(); i++)
71 {
Geoff Langea228632013-07-30 15:17:12 -040072 SafeRelease(i->second.inputLayout);
daniel@transgaming.comcd9458d2012-12-20 21:10:09 +000073 }
74 mInputLayoutMap.clear();
Geoff Lang1f53cab2013-07-22 10:37:22 -040075 markDirty();
76}
77
78void InputLayoutCache::markDirty()
79{
80 mCurrentIL = NULL;
81 for (unsigned int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
82 {
Geoff Lang7840b172014-03-13 11:20:44 -040083 mCurrentBuffers[i] = NULL;
Geoff Lang1f53cab2013-07-22 10:37:22 -040084 mCurrentVertexStrides[i] = -1;
85 mCurrentVertexOffsets[i] = -1;
86 }
daniel@transgaming.comcd9458d2012-12-20 21:10:09 +000087}
88
89GLenum InputLayoutCache::applyVertexBuffers(TranslatedAttribute attributes[gl::MAX_VERTEX_ATTRIBS],
90 gl::ProgramBinary *programBinary)
91{
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +000092 int sortedSemanticIndices[gl::MAX_VERTEX_ATTRIBS];
93 programBinary->sortAttributesByLayout(attributes, sortedSemanticIndices);
94
daniel@transgaming.comcd9458d2012-12-20 21:10:09 +000095 if (!mDevice || !mDeviceContext)
96 {
97 ERR("InputLayoutCache is not initialized.");
98 return GL_INVALID_OPERATION;
99 }
100
101 InputLayoutKey ilKey = { 0 };
102
daniel@transgaming.comcd9458d2012-12-20 21:10:09 +0000103 static const char* semanticName = "TEXCOORD";
104
105 for (unsigned int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
106 {
107 if (attributes[i].active)
108 {
shannon.woods@transgaming.com00032cb2013-01-25 21:56:30 +0000109 D3D11_INPUT_CLASSIFICATION inputClass = attributes[i].divisor > 0 ? D3D11_INPUT_PER_INSTANCE_DATA : D3D11_INPUT_PER_VERTEX_DATA;
Jamie Madill7ab02fa2014-02-04 16:04:08 -0500110
111 gl::VertexFormat vertexFormat(*attributes[i].attribute, attributes[i].currentValueType);
112 DXGI_FORMAT dxgiFormat = gl_d3d11::GetNativeVertexFormat(vertexFormat);
shannon.woods@transgaming.com00032cb2013-01-25 21:56:30 +0000113
shannon.woods@transgaming.com0a71ecf2013-02-28 23:15:10 +0000114 // Record the type of the associated vertex shader vector in our key
115 // This will prevent mismatched vertex shaders from using the same input layout
116 GLint attributeSize;
Al Patrick978911c2013-08-15 12:43:29 -0700117 programBinary->getActiveAttribute(ilKey.elementCount, 0, NULL, &attributeSize, &ilKey.elements[ilKey.elementCount].glslElementType, NULL);
shannon.woods@transgaming.com0a71ecf2013-02-28 23:15:10 +0000118
Al Patrick978911c2013-08-15 12:43:29 -0700119 ilKey.elements[ilKey.elementCount].desc.SemanticName = semanticName;
120 ilKey.elements[ilKey.elementCount].desc.SemanticIndex = sortedSemanticIndices[i];
121 ilKey.elements[ilKey.elementCount].desc.Format = dxgiFormat;
122 ilKey.elements[ilKey.elementCount].desc.InputSlot = i;
123 ilKey.elements[ilKey.elementCount].desc.AlignedByteOffset = 0;
124 ilKey.elements[ilKey.elementCount].desc.InputSlotClass = inputClass;
125 ilKey.elements[ilKey.elementCount].desc.InstanceDataStepRate = attributes[i].divisor;
daniel@transgaming.comcd9458d2012-12-20 21:10:09 +0000126 ilKey.elementCount++;
daniel@transgaming.comcd9458d2012-12-20 21:10:09 +0000127 }
128 }
129
130 ID3D11InputLayout *inputLayout = NULL;
131
Geoff Lang5d64caf2014-02-11 10:23:34 -0500132 InputLayoutMap::iterator keyIter = mInputLayoutMap.find(ilKey);
133 if (keyIter != mInputLayoutMap.end())
daniel@transgaming.comcd9458d2012-12-20 21:10:09 +0000134 {
Geoff Lang5d64caf2014-02-11 10:23:34 -0500135 inputLayout = keyIter->second.inputLayout;
136 keyIter->second.lastUsedTime = mCounter++;
daniel@transgaming.comcd9458d2012-12-20 21:10:09 +0000137 }
138 else
139 {
Jamie Madillc5a83002014-02-14 16:41:25 -0500140 gl::VertexFormat shaderInputLayout[gl::MAX_VERTEX_ATTRIBS];
141 GetInputLayout(attributes, shaderInputLayout);
142 ShaderExecutable11 *shader = ShaderExecutable11::makeShaderExecutable11(programBinary->getVertexExecutableForInputLayout(shaderInputLayout));
daniel@transgaming.comcd9458d2012-12-20 21:10:09 +0000143
Al Patrick978911c2013-08-15 12:43:29 -0700144 D3D11_INPUT_ELEMENT_DESC descs[gl::MAX_VERTEX_ATTRIBS];
145 for (unsigned int j = 0; j < ilKey.elementCount; ++j)
146 {
147 descs[j] = ilKey.elements[j].desc;
148 }
149
150 HRESULT result = mDevice->CreateInputLayout(descs, ilKey.elementCount, shader->getFunction(), shader->getLength(), &inputLayout);
daniel@transgaming.comcd9458d2012-12-20 21:10:09 +0000151 if (FAILED(result))
152 {
153 ERR("Failed to crate input layout, result: 0x%08x", result);
154 return GL_INVALID_OPERATION;
155 }
156
157 if (mInputLayoutMap.size() >= kMaxInputLayouts)
158 {
159 TRACE("Overflowed the limit of %u input layouts, removing the least recently used "
160 "to make room.", kMaxInputLayouts);
161
162 InputLayoutMap::iterator leastRecentlyUsed = mInputLayoutMap.begin();
163 for (InputLayoutMap::iterator i = mInputLayoutMap.begin(); i != mInputLayoutMap.end(); i++)
164 {
165 if (i->second.lastUsedTime < leastRecentlyUsed->second.lastUsedTime)
166 {
167 leastRecentlyUsed = i;
168 }
169 }
Geoff Langea228632013-07-30 15:17:12 -0400170 SafeRelease(leastRecentlyUsed->second.inputLayout);
daniel@transgaming.comcd9458d2012-12-20 21:10:09 +0000171 mInputLayoutMap.erase(leastRecentlyUsed);
172 }
173
174 InputLayoutCounterPair inputCounterPair;
175 inputCounterPair.inputLayout = inputLayout;
176 inputCounterPair.lastUsedTime = mCounter++;
177
178 mInputLayoutMap.insert(std::make_pair(ilKey, inputCounterPair));
179 }
180
Geoff Lang1f53cab2013-07-22 10:37:22 -0400181 if (inputLayout != mCurrentIL)
182 {
183 mDeviceContext->IASetInputLayout(inputLayout);
184 mCurrentIL = inputLayout;
185 }
186
Geoff Langf98e63a2014-05-12 16:45:12 -0400187 bool dirtyBuffers = false;
188 size_t minDiff = gl::MAX_VERTEX_ATTRIBS;
189 size_t maxDiff = 0;
Geoff Lang1f53cab2013-07-22 10:37:22 -0400190 for (unsigned int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
191 {
Nicolas Capensb05e3492014-04-22 15:48:00 -0400192 ID3D11Buffer *buffer = NULL;
193
194 if (attributes[i].active)
Geoff Lang1f53cab2013-07-22 10:37:22 -0400195 {
Nicolas Capensb05e3492014-04-22 15:48:00 -0400196 VertexBuffer11 *vertexBuffer = VertexBuffer11::makeVertexBuffer11(attributes[i].vertexBuffer);
197 BufferStorage11 *bufferStorage = attributes[i].storage ? BufferStorage11::makeBufferStorage11(attributes[i].storage) : NULL;
198
199 buffer = bufferStorage ? bufferStorage->getBuffer(BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK)
200 : vertexBuffer->getBuffer();
201 }
202
203 UINT vertexStride = attributes[i].stride;
204 UINT vertexOffset = attributes[i].offset;
205
206 if (buffer != mCurrentBuffers[i] || vertexStride != mCurrentVertexStrides[i] ||
207 vertexOffset != mCurrentVertexOffsets[i])
208 {
Geoff Langf98e63a2014-05-12 16:45:12 -0400209 dirtyBuffers = true;
Jamie Madill82b42272014-05-20 15:38:22 -0400210 minDiff = std::min(minDiff, static_cast<size_t>(i));
211 maxDiff = std::max(maxDiff, static_cast<size_t>(i));
Geoff Langf98e63a2014-05-12 16:45:12 -0400212
Nicolas Capensb05e3492014-04-22 15:48:00 -0400213 mCurrentBuffers[i] = buffer;
214 mCurrentVertexStrides[i] = vertexStride;
215 mCurrentVertexOffsets[i] = vertexOffset;
Geoff Lang1f53cab2013-07-22 10:37:22 -0400216 }
217 }
daniel@transgaming.comcd9458d2012-12-20 21:10:09 +0000218
Geoff Langf98e63a2014-05-12 16:45:12 -0400219 if (dirtyBuffers)
220 {
221 ASSERT(minDiff <= maxDiff && maxDiff < gl::MAX_VERTEX_ATTRIBS);
222 mDeviceContext->IASetVertexBuffers(minDiff, maxDiff - minDiff + 1, mCurrentBuffers + minDiff,
223 mCurrentVertexStrides + minDiff, mCurrentVertexOffsets + minDiff);
224 }
225
daniel@transgaming.comcd9458d2012-12-20 21:10:09 +0000226 return GL_NO_ERROR;
227}
228
229std::size_t InputLayoutCache::hashInputLayout(const InputLayoutKey &inputLayout)
230{
231 static const unsigned int seed = 0xDEADBEEF;
232
233 std::size_t hash = 0;
Al Patrick978911c2013-08-15 12:43:29 -0700234 MurmurHash3_x86_32(inputLayout.begin(), inputLayout.end() - inputLayout.begin(), seed, &hash);
daniel@transgaming.comcd9458d2012-12-20 21:10:09 +0000235 return hash;
236}
237
238bool InputLayoutCache::compareInputLayouts(const InputLayoutKey &a, const InputLayoutKey &b)
239{
Al Patrick978911c2013-08-15 12:43:29 -0700240 if (a.elementCount != b.elementCount)
241 {
242 return false;
243 }
244
245 return std::equal(a.begin(), a.end(), b.begin());
daniel@transgaming.comcd9458d2012-12-20 21:10:09 +0000246}
247
248}