1 //
2 // Copyright 2016 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 // VertexArray11:
7 // Implementation of rx::VertexArray11.
8 //
9
10 #include "libANGLE/renderer/d3d/d3d11/VertexArray11.h"
11
12 #include "common/bitset_utils.h"
13 #include "libANGLE/Context.h"
14 #include "libANGLE/renderer/d3d/IndexBuffer.h"
15 #include "libANGLE/renderer/d3d/d3d11/Buffer11.h"
16 #include "libANGLE/renderer/d3d/d3d11/Context11.h"
17
18 using namespace angle;
19
20 namespace rx
21 {
VertexArray11(const gl::VertexArrayState & data)22 VertexArray11::VertexArray11(const gl::VertexArrayState &data)
23 : VertexArrayImpl(data),
24 mAttributeStorageTypes(data.getMaxAttribs(), VertexStorageType::CURRENT_VALUE),
25 mTranslatedAttribs(data.getMaxAttribs()),
26 mAppliedNumViewsToDivisor(1),
27 mCurrentElementArrayStorage(IndexStorageType::Invalid),
28 mCachedDestinationIndexType(gl::DrawElementsType::InvalidEnum)
29 {}
30
~VertexArray11()31 VertexArray11::~VertexArray11() {}
32
destroy(const gl::Context * context)33 void VertexArray11::destroy(const gl::Context *context) {}
34
35 // As VertexAttribPointer can modify both attribute and binding, we should also set other attributes
36 // that are also using this binding dirty.
37 #define ANGLE_VERTEX_DIRTY_ATTRIB_FUNC(INDEX) \
38 case gl::VertexArray::DIRTY_BIT_ATTRIB_0 + INDEX: \
39 if ((*attribBits)[INDEX][gl::VertexArray::DirtyAttribBitType::DIRTY_ATTRIB_POINTER]) \
40 { \
41 attributesToUpdate |= mState.getBindingToAttributesMask(INDEX); \
42 } \
43 else \
44 { \
45 attributesToUpdate.set(INDEX); \
46 } \
47 invalidateVertexBuffer = true; \
48 (*attribBits)[INDEX].reset(); \
49 break;
50
51 #define ANGLE_VERTEX_DIRTY_BINDING_FUNC(INDEX) \
52 case gl::VertexArray::DIRTY_BIT_BINDING_0 + INDEX: \
53 attributesToUpdate |= mState.getBindingToAttributesMask(INDEX); \
54 invalidateVertexBuffer = true; \
55 (*bindingBits)[INDEX].reset(); \
56 break;
57
58 #define ANGLE_VERTEX_DIRTY_BUFFER_DATA_FUNC(INDEX) \
59 case gl::VertexArray::DIRTY_BIT_BUFFER_DATA_0 + INDEX: \
60 if (mAttributeStorageTypes[INDEX] == VertexStorageType::STATIC) \
61 { \
62 invalidateVertexBuffer = true; \
63 mAttribsToTranslate.set(INDEX); \
64 } \
65 break;
66
syncState(const gl::Context * context,const gl::VertexArray::DirtyBits & dirtyBits,gl::VertexArray::DirtyAttribBitsArray * attribBits,gl::VertexArray::DirtyBindingBitsArray * bindingBits)67 angle::Result VertexArray11::syncState(const gl::Context *context,
68 const gl::VertexArray::DirtyBits &dirtyBits,
69 gl::VertexArray::DirtyAttribBitsArray *attribBits,
70 gl::VertexArray::DirtyBindingBitsArray *bindingBits)
71 {
72 ASSERT(dirtyBits.any());
73
74 Renderer11 *renderer = GetImplAs<Context11>(context)->getRenderer();
75 StateManager11 *stateManager = renderer->getStateManager();
76
77 // Generate a state serial. This serial is used in the program class to validate the cached
78 // input layout, and skip recomputation in the fast path.
79 mCurrentStateSerial = renderer->generateSerial();
80
81 bool invalidateVertexBuffer = false;
82
83 gl::AttributesMask attributesToUpdate;
84
85 // Make sure we trigger re-translation for static index or vertex data.
86 for (size_t dirtyBit : dirtyBits)
87 {
88 switch (dirtyBit)
89 {
90 case gl::VertexArray::DIRTY_BIT_ELEMENT_ARRAY_BUFFER:
91 case gl::VertexArray::DIRTY_BIT_ELEMENT_ARRAY_BUFFER_DATA:
92 {
93 mLastDrawElementsType.reset();
94 mLastDrawElementsIndices.reset();
95 mLastPrimitiveRestartEnabled.reset();
96 mCachedIndexInfo.reset();
97 break;
98 }
99
100 ANGLE_VERTEX_INDEX_CASES(ANGLE_VERTEX_DIRTY_ATTRIB_FUNC)
101 ANGLE_VERTEX_INDEX_CASES(ANGLE_VERTEX_DIRTY_BINDING_FUNC)
102 ANGLE_VERTEX_INDEX_CASES(ANGLE_VERTEX_DIRTY_BUFFER_DATA_FUNC)
103
104 default:
105 UNREACHABLE();
106 break;
107 }
108 }
109
110 for (size_t attribIndex : attributesToUpdate)
111 {
112 updateVertexAttribStorage(context, stateManager, attribIndex);
113 }
114
115 if (invalidateVertexBuffer)
116 {
117 // TODO(jmadill): Individual attribute invalidation.
118 stateManager->invalidateVertexBuffer();
119 }
120
121 return angle::Result::Continue;
122 }
123
syncStateForDraw(const gl::Context * context,GLint firstVertex,GLsizei vertexOrIndexCount,gl::DrawElementsType indexTypeOrInvalid,const void * indices,GLsizei instances,GLint baseVertex,GLuint baseInstance,bool promoteDynamic)124 angle::Result VertexArray11::syncStateForDraw(const gl::Context *context,
125 GLint firstVertex,
126 GLsizei vertexOrIndexCount,
127 gl::DrawElementsType indexTypeOrInvalid,
128 const void *indices,
129 GLsizei instances,
130 GLint baseVertex,
131 GLuint baseInstance,
132 bool promoteDynamic)
133 {
134 Renderer11 *renderer = GetImplAs<Context11>(context)->getRenderer();
135 StateManager11 *stateManager = renderer->getStateManager();
136
137 const gl::State &glState = context->getState();
138 const gl::Program *program = glState.getProgram();
139 ASSERT(program);
140 const gl::ProgramExecutable &executable = program->getExecutable();
141
142 mAppliedNumViewsToDivisor = (program->usesMultiview() ? program->getNumViews() : 1);
143
144 if (mAttribsToTranslate.any())
145 {
146 const gl::AttributesMask &activeLocations = executable.getActiveAttribLocationsMask();
147 gl::AttributesMask activeDirtyAttribs = (mAttribsToTranslate & activeLocations);
148 if (activeDirtyAttribs.any())
149 {
150 ANGLE_TRY(updateDirtyAttribs(context, activeDirtyAttribs));
151 stateManager->invalidateInputLayout();
152 }
153 }
154
155 if (mDynamicAttribsMask.any())
156 {
157 const gl::AttributesMask &activeLocations = executable.getActiveAttribLocationsMask();
158 gl::AttributesMask activeDynamicAttribs = (mDynamicAttribsMask & activeLocations);
159
160 if (activeDynamicAttribs.any())
161 {
162 ANGLE_TRY(updateDynamicAttribs(context, stateManager->getVertexDataManager(),
163 firstVertex, vertexOrIndexCount, indexTypeOrInvalid,
164 indices, instances, baseVertex, baseInstance,
165 promoteDynamic, activeDynamicAttribs));
166 stateManager->invalidateInputLayout();
167 }
168 }
169
170 if (indexTypeOrInvalid != gl::DrawElementsType::InvalidEnum)
171 {
172 bool restartEnabled = context->getState().isPrimitiveRestartEnabled();
173 if (!mLastDrawElementsType.valid() || mLastDrawElementsType.value() != indexTypeOrInvalid ||
174 mLastDrawElementsIndices.value() != indices ||
175 mLastPrimitiveRestartEnabled.value() != restartEnabled)
176 {
177 mLastDrawElementsType = indexTypeOrInvalid;
178 mLastDrawElementsIndices = indices;
179 mLastPrimitiveRestartEnabled = restartEnabled;
180
181 ANGLE_TRY(updateElementArrayStorage(context, vertexOrIndexCount, indexTypeOrInvalid,
182 indices, restartEnabled));
183 stateManager->invalidateIndexBuffer();
184 }
185 else if (mCurrentElementArrayStorage == IndexStorageType::Dynamic)
186 {
187 stateManager->invalidateIndexBuffer();
188 }
189 }
190
191 return angle::Result::Continue;
192 }
193
updateElementArrayStorage(const gl::Context * context,GLsizei indexCount,gl::DrawElementsType indexType,const void * indices,bool restartEnabled)194 angle::Result VertexArray11::updateElementArrayStorage(const gl::Context *context,
195 GLsizei indexCount,
196 gl::DrawElementsType indexType,
197 const void *indices,
198 bool restartEnabled)
199 {
200 bool usePrimitiveRestartWorkaround = UsePrimitiveRestartWorkaround(restartEnabled, indexType);
201
202 ANGLE_TRY(GetIndexTranslationDestType(context, indexCount, indexType, indices,
203 usePrimitiveRestartWorkaround,
204 &mCachedDestinationIndexType));
205
206 unsigned int offset = static_cast<unsigned int>(reinterpret_cast<uintptr_t>(indices));
207
208 mCurrentElementArrayStorage =
209 ClassifyIndexStorage(context->getState(), mState.getElementArrayBuffer(), indexType,
210 mCachedDestinationIndexType, offset);
211
212 return angle::Result::Continue;
213 }
214
updateVertexAttribStorage(const gl::Context * context,StateManager11 * stateManager,size_t attribIndex)215 void VertexArray11::updateVertexAttribStorage(const gl::Context *context,
216 StateManager11 *stateManager,
217 size_t attribIndex)
218 {
219 const gl::VertexAttribute &attrib = mState.getVertexAttribute(attribIndex);
220 const gl::VertexBinding &binding = mState.getBindingFromAttribIndex(attribIndex);
221
222 VertexStorageType newStorageType = ClassifyAttributeStorage(context, attrib, binding);
223
224 // Note: having an unchanged storage type doesn't mean the attribute is clean.
225 mAttribsToTranslate.set(attribIndex, newStorageType != VertexStorageType::DYNAMIC);
226
227 if (mAttributeStorageTypes[attribIndex] == newStorageType)
228 return;
229
230 mAttributeStorageTypes[attribIndex] = newStorageType;
231 mDynamicAttribsMask.set(attribIndex, newStorageType == VertexStorageType::DYNAMIC);
232
233 if (newStorageType == VertexStorageType::CURRENT_VALUE)
234 {
235 stateManager->invalidateCurrentValueAttrib(attribIndex);
236 }
237 }
238
hasActiveDynamicAttrib(const gl::Context * context)239 bool VertexArray11::hasActiveDynamicAttrib(const gl::Context *context)
240 {
241 const auto &activeLocations =
242 context->getState().getProgramExecutable()->getActiveAttribLocationsMask();
243 gl::AttributesMask activeDynamicAttribs = (mDynamicAttribsMask & activeLocations);
244 return activeDynamicAttribs.any();
245 }
246
updateDirtyAttribs(const gl::Context * context,const gl::AttributesMask & activeDirtyAttribs)247 angle::Result VertexArray11::updateDirtyAttribs(const gl::Context *context,
248 const gl::AttributesMask &activeDirtyAttribs)
249 {
250 const auto &glState = context->getState();
251 const auto &attribs = mState.getVertexAttributes();
252 const auto &bindings = mState.getVertexBindings();
253
254 for (size_t dirtyAttribIndex : activeDirtyAttribs)
255 {
256 auto *translatedAttrib = &mTranslatedAttribs[dirtyAttribIndex];
257 const auto ¤tValue = glState.getVertexAttribCurrentValue(dirtyAttribIndex);
258
259 // Record basic attrib info
260 translatedAttrib->attribute = &attribs[dirtyAttribIndex];
261 translatedAttrib->binding = &bindings[translatedAttrib->attribute->bindingIndex];
262 translatedAttrib->currentValueType = currentValue.Type;
263 translatedAttrib->divisor =
264 translatedAttrib->binding->getDivisor() * mAppliedNumViewsToDivisor;
265
266 switch (mAttributeStorageTypes[dirtyAttribIndex])
267 {
268 case VertexStorageType::DIRECT:
269 VertexDataManager::StoreDirectAttrib(context, translatedAttrib);
270 break;
271 case VertexStorageType::STATIC:
272 {
273 ANGLE_TRY(VertexDataManager::StoreStaticAttrib(context, translatedAttrib));
274 break;
275 }
276 case VertexStorageType::CURRENT_VALUE:
277 // Current value attribs are managed by the StateManager11.
278 break;
279 default:
280 UNREACHABLE();
281 break;
282 }
283
284 // Make sure we reset the dirty bit after the switch because STATIC can early exit.
285 mAttribsToTranslate.reset(dirtyAttribIndex);
286 }
287
288 return angle::Result::Continue;
289 }
290
updateDynamicAttribs(const gl::Context * context,VertexDataManager * vertexDataManager,GLint firstVertex,GLsizei vertexOrIndexCount,gl::DrawElementsType indexTypeOrInvalid,const void * indices,GLsizei instances,GLint baseVertex,GLuint baseInstance,bool promoteDynamic,const gl::AttributesMask & activeDynamicAttribs)291 angle::Result VertexArray11::updateDynamicAttribs(const gl::Context *context,
292 VertexDataManager *vertexDataManager,
293 GLint firstVertex,
294 GLsizei vertexOrIndexCount,
295 gl::DrawElementsType indexTypeOrInvalid,
296 const void *indices,
297 GLsizei instances,
298 GLint baseVertex,
299 GLuint baseInstance,
300 bool promoteDynamic,
301 const gl::AttributesMask &activeDynamicAttribs)
302 {
303 const auto &glState = context->getState();
304 const auto &attribs = mState.getVertexAttributes();
305 const auto &bindings = mState.getVertexBindings();
306
307 GLint startVertex;
308 size_t vertexCount;
309 ANGLE_TRY(GetVertexRangeInfo(context, firstVertex, vertexOrIndexCount, indexTypeOrInvalid,
310 indices, baseVertex, &startVertex, &vertexCount));
311
312 for (size_t dynamicAttribIndex : activeDynamicAttribs)
313 {
314 auto *dynamicAttrib = &mTranslatedAttribs[dynamicAttribIndex];
315 const auto ¤tValue = glState.getVertexAttribCurrentValue(dynamicAttribIndex);
316
317 // Record basic attrib info
318 dynamicAttrib->attribute = &attribs[dynamicAttribIndex];
319 dynamicAttrib->binding = &bindings[dynamicAttrib->attribute->bindingIndex];
320 dynamicAttrib->currentValueType = currentValue.Type;
321 dynamicAttrib->divisor = dynamicAttrib->binding->getDivisor() * mAppliedNumViewsToDivisor;
322 }
323
324 ANGLE_TRY(vertexDataManager->storeDynamicAttribs(context, &mTranslatedAttribs,
325 activeDynamicAttribs, startVertex, vertexCount,
326 instances, baseInstance));
327
328 if (promoteDynamic)
329 {
330 VertexDataManager::PromoteDynamicAttribs(context, mTranslatedAttribs, activeDynamicAttribs,
331 vertexCount);
332 }
333
334 return angle::Result::Continue;
335 }
336
getTranslatedAttribs() const337 const std::vector<TranslatedAttribute> &VertexArray11::getTranslatedAttribs() const
338 {
339 return mTranslatedAttribs;
340 }
341
markAllAttributeDivisorsForAdjustment(int numViews)342 void VertexArray11::markAllAttributeDivisorsForAdjustment(int numViews)
343 {
344 if (mAppliedNumViewsToDivisor != numViews)
345 {
346 mAppliedNumViewsToDivisor = numViews;
347 mAttribsToTranslate.set();
348 // mDynamicAttribsMask may have already been set (updateVertexAttribStorage
349 // We don't want to override DYNAMIC attribs as they will be handled separately.
350 mAttribsToTranslate = mAttribsToTranslate ^ mDynamicAttribsMask;
351 }
352 }
353
getCachedIndexInfo() const354 const TranslatedIndexData &VertexArray11::getCachedIndexInfo() const
355 {
356 ASSERT(mCachedIndexInfo.valid());
357 return mCachedIndexInfo.value();
358 }
359
updateCachedIndexInfo(const TranslatedIndexData & indexInfo)360 void VertexArray11::updateCachedIndexInfo(const TranslatedIndexData &indexInfo)
361 {
362 mCachedIndexInfo = indexInfo;
363 }
364
isCachedIndexInfoValid() const365 bool VertexArray11::isCachedIndexInfoValid() const
366 {
367 return mCachedIndexInfo.valid();
368 }
369
getCachedDestinationIndexType() const370 gl::DrawElementsType VertexArray11::getCachedDestinationIndexType() const
371 {
372 return mCachedDestinationIndexType;
373 }
374
375 } // namespace rx
376