blob: 5962862ea487b2d4aa3c0429151a3ff4cb6cf429 [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 {
50 mCurrentBuffers[i] = -1;
51 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 {
83 mCurrentBuffers[i] = -1;
84 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
103 ID3D11Buffer *vertexBuffers[gl::MAX_VERTEX_ATTRIBS] = { NULL };
Geoff Lang1f53cab2013-07-22 10:37:22 -0400104 unsigned int vertexBufferSerials[gl::MAX_VERTEX_ATTRIBS] = { 0 };
daniel@transgaming.comcd9458d2012-12-20 21:10:09 +0000105 UINT vertexStrides[gl::MAX_VERTEX_ATTRIBS] = { 0 };
106 UINT vertexOffsets[gl::MAX_VERTEX_ATTRIBS] = { 0 };
107
108 static const char* semanticName = "TEXCOORD";
109
110 for (unsigned int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
111 {
112 if (attributes[i].active)
113 {
114 VertexBuffer11 *vertexBuffer = VertexBuffer11::makeVertexBuffer11(attributes[i].vertexBuffer);
shannon.woods@transgaming.comdb1899c2013-02-28 23:08:33 +0000115 BufferStorage11 *bufferStorage = attributes[i].storage ? BufferStorage11::makeBufferStorage11(attributes[i].storage) : NULL;
daniel@transgaming.comcd9458d2012-12-20 21:10:09 +0000116
shannon.woods@transgaming.com00032cb2013-01-25 21:56:30 +0000117 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 -0500118
119 gl::VertexFormat vertexFormat(*attributes[i].attribute, attributes[i].currentValueType);
120 DXGI_FORMAT dxgiFormat = gl_d3d11::GetNativeVertexFormat(vertexFormat);
shannon.woods@transgaming.com00032cb2013-01-25 21:56:30 +0000121
shannon.woods@transgaming.com0a71ecf2013-02-28 23:15:10 +0000122 // Record the type of the associated vertex shader vector in our key
123 // This will prevent mismatched vertex shaders from using the same input layout
124 GLint attributeSize;
Al Patrick978911c2013-08-15 12:43:29 -0700125 programBinary->getActiveAttribute(ilKey.elementCount, 0, NULL, &attributeSize, &ilKey.elements[ilKey.elementCount].glslElementType, NULL);
shannon.woods@transgaming.com0a71ecf2013-02-28 23:15:10 +0000126
Al Patrick978911c2013-08-15 12:43:29 -0700127 ilKey.elements[ilKey.elementCount].desc.SemanticName = semanticName;
128 ilKey.elements[ilKey.elementCount].desc.SemanticIndex = sortedSemanticIndices[i];
129 ilKey.elements[ilKey.elementCount].desc.Format = dxgiFormat;
130 ilKey.elements[ilKey.elementCount].desc.InputSlot = i;
131 ilKey.elements[ilKey.elementCount].desc.AlignedByteOffset = 0;
132 ilKey.elements[ilKey.elementCount].desc.InputSlotClass = inputClass;
133 ilKey.elements[ilKey.elementCount].desc.InstanceDataStepRate = attributes[i].divisor;
daniel@transgaming.comcd9458d2012-12-20 21:10:09 +0000134 ilKey.elementCount++;
135
Geoff Lang9c53f1e2014-01-08 13:41:47 -0500136 vertexBuffers[i] = bufferStorage ? bufferStorage->getBuffer(BUFFER_USAGE_VERTEX) : vertexBuffer->getBuffer();
Geoff Lang1f53cab2013-07-22 10:37:22 -0400137 vertexBufferSerials[i] = bufferStorage ? bufferStorage->getSerial() : vertexBuffer->getSerial();
daniel@transgaming.comcd9458d2012-12-20 21:10:09 +0000138 vertexStrides[i] = attributes[i].stride;
139 vertexOffsets[i] = attributes[i].offset;
140 }
141 }
142
143 ID3D11InputLayout *inputLayout = NULL;
144
145 InputLayoutMap::iterator i = mInputLayoutMap.find(ilKey);
146 if (i != mInputLayoutMap.end())
147 {
148 inputLayout = i->second.inputLayout;
149 i->second.lastUsedTime = mCounter++;
150 }
151 else
152 {
Jamie Madillc5a83002014-02-14 16:41:25 -0500153 gl::VertexFormat shaderInputLayout[gl::MAX_VERTEX_ATTRIBS];
154 GetInputLayout(attributes, shaderInputLayout);
155 ShaderExecutable11 *shader = ShaderExecutable11::makeShaderExecutable11(programBinary->getVertexExecutableForInputLayout(shaderInputLayout));
daniel@transgaming.comcd9458d2012-12-20 21:10:09 +0000156
Al Patrick978911c2013-08-15 12:43:29 -0700157 D3D11_INPUT_ELEMENT_DESC descs[gl::MAX_VERTEX_ATTRIBS];
158 for (unsigned int j = 0; j < ilKey.elementCount; ++j)
159 {
160 descs[j] = ilKey.elements[j].desc;
161 }
162
163 HRESULT result = mDevice->CreateInputLayout(descs, ilKey.elementCount, shader->getFunction(), shader->getLength(), &inputLayout);
daniel@transgaming.comcd9458d2012-12-20 21:10:09 +0000164 if (FAILED(result))
165 {
166 ERR("Failed to crate input layout, result: 0x%08x", result);
167 return GL_INVALID_OPERATION;
168 }
169
170 if (mInputLayoutMap.size() >= kMaxInputLayouts)
171 {
172 TRACE("Overflowed the limit of %u input layouts, removing the least recently used "
173 "to make room.", kMaxInputLayouts);
174
175 InputLayoutMap::iterator leastRecentlyUsed = mInputLayoutMap.begin();
176 for (InputLayoutMap::iterator i = mInputLayoutMap.begin(); i != mInputLayoutMap.end(); i++)
177 {
178 if (i->second.lastUsedTime < leastRecentlyUsed->second.lastUsedTime)
179 {
180 leastRecentlyUsed = i;
181 }
182 }
Geoff Langea228632013-07-30 15:17:12 -0400183 SafeRelease(leastRecentlyUsed->second.inputLayout);
daniel@transgaming.comcd9458d2012-12-20 21:10:09 +0000184 mInputLayoutMap.erase(leastRecentlyUsed);
185 }
186
187 InputLayoutCounterPair inputCounterPair;
188 inputCounterPair.inputLayout = inputLayout;
189 inputCounterPair.lastUsedTime = mCounter++;
190
191 mInputLayoutMap.insert(std::make_pair(ilKey, inputCounterPair));
192 }
193
Geoff Lang1f53cab2013-07-22 10:37:22 -0400194 if (inputLayout != mCurrentIL)
195 {
196 mDeviceContext->IASetInputLayout(inputLayout);
197 mCurrentIL = inputLayout;
198 }
199
200 for (unsigned int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
201 {
202 if (vertexBufferSerials[i] != mCurrentBuffers[i] || vertexStrides[i] != mCurrentVertexStrides[i] ||
203 vertexOffsets[i] != mCurrentVertexOffsets[i])
204 {
205 mDeviceContext->IASetVertexBuffers(i, 1, &vertexBuffers[i], &vertexStrides[i], &vertexOffsets[i]);
206 mCurrentBuffers[i] = vertexBufferSerials[i];
207 mCurrentVertexStrides[i] = vertexStrides[i];
208 mCurrentVertexOffsets[i] = vertexOffsets[i];
209 }
210 }
daniel@transgaming.comcd9458d2012-12-20 21:10:09 +0000211
212 return GL_NO_ERROR;
213}
214
215std::size_t InputLayoutCache::hashInputLayout(const InputLayoutKey &inputLayout)
216{
217 static const unsigned int seed = 0xDEADBEEF;
218
219 std::size_t hash = 0;
Al Patrick978911c2013-08-15 12:43:29 -0700220 MurmurHash3_x86_32(inputLayout.begin(), inputLayout.end() - inputLayout.begin(), seed, &hash);
daniel@transgaming.comcd9458d2012-12-20 21:10:09 +0000221 return hash;
222}
223
224bool InputLayoutCache::compareInputLayouts(const InputLayoutKey &a, const InputLayoutKey &b)
225{
Al Patrick978911c2013-08-15 12:43:29 -0700226 if (a.elementCount != b.elementCount)
227 {
228 return false;
229 }
230
231 return std::equal(a.begin(), a.end(), b.begin());
daniel@transgaming.comcd9458d2012-12-20 21:10:09 +0000232}
233
234}