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 (auto iter = dirtyBits.begin(), endIter = dirtyBits.end(); iter != endIter; ++iter)
87 {
88 size_t dirtyBit = *iter;
89 switch (dirtyBit)
90 {
91 case gl::VertexArray::DIRTY_BIT_LOST_OBSERVATION:
92 {
93 // If vertex array was not observing while unbound, we need to check buffer's
94 // internal storage and take action if buffer has changed while not observing.
95 // For now we just simply assume buffer storage has changed and always dirty all
96 // binding points.
97 iter.setLaterBits(
98 gl::VertexArray::DirtyBits(mState.getBufferBindingMask().to_ulong()
99 << gl::VertexArray::DIRTY_BIT_BINDING_0));
100 break;
101 }
102
103 case gl::VertexArray::DIRTY_BIT_ELEMENT_ARRAY_BUFFER:
104 case gl::VertexArray::DIRTY_BIT_ELEMENT_ARRAY_BUFFER_DATA:
105 {
106 mLastDrawElementsType.reset();
107 mLastDrawElementsIndices.reset();
108 mLastPrimitiveRestartEnabled.reset();
109 mCachedIndexInfo.reset();
110 break;
111 }
112
113 ANGLE_VERTEX_INDEX_CASES(ANGLE_VERTEX_DIRTY_ATTRIB_FUNC)
114 ANGLE_VERTEX_INDEX_CASES(ANGLE_VERTEX_DIRTY_BINDING_FUNC)
115 ANGLE_VERTEX_INDEX_CASES(ANGLE_VERTEX_DIRTY_BUFFER_DATA_FUNC)
116
117 default:
118 UNREACHABLE();
119 break;
120 }
121 }
122
123 for (size_t attribIndex : attributesToUpdate)
124 {
125 updateVertexAttribStorage(context, stateManager, attribIndex);
126 }
127
128 if (invalidateVertexBuffer)
129 {
130 // TODO(jmadill): Individual attribute invalidation.
131 stateManager->invalidateVertexBuffer();
132 }
133
134 return angle::Result::Continue;
135 }
136
syncStateForDraw(const gl::Context * context,GLint firstVertex,GLsizei vertexOrIndexCount,gl::DrawElementsType indexTypeOrInvalid,const void * indices,GLsizei instances,GLint baseVertex,GLuint baseInstance,bool promoteDynamic)137 angle::Result VertexArray11::syncStateForDraw(const gl::Context *context,
138 GLint firstVertex,
139 GLsizei vertexOrIndexCount,
140 gl::DrawElementsType indexTypeOrInvalid,
141 const void *indices,
142 GLsizei instances,
143 GLint baseVertex,
144 GLuint baseInstance,
145 bool promoteDynamic)
146 {
147 Renderer11 *renderer = GetImplAs<Context11>(context)->getRenderer();
148 StateManager11 *stateManager = renderer->getStateManager();
149
150 const gl::State &glState = context->getState();
151 const gl::Program *program = glState.getProgram();
152 ASSERT(program);
153 const gl::ProgramExecutable &executable = program->getExecutable();
154
155 mAppliedNumViewsToDivisor = (program->usesMultiview() ? program->getNumViews() : 1);
156
157 if (mAttribsToTranslate.any())
158 {
159 const gl::AttributesMask &activeLocations = executable.getActiveAttribLocationsMask();
160 gl::AttributesMask activeDirtyAttribs = (mAttribsToTranslate & activeLocations);
161 if (activeDirtyAttribs.any())
162 {
163 ANGLE_TRY(updateDirtyAttribs(context, activeDirtyAttribs));
164 stateManager->invalidateInputLayout();
165 }
166 }
167
168 if (mDynamicAttribsMask.any())
169 {
170 const gl::AttributesMask &activeLocations = executable.getActiveAttribLocationsMask();
171 gl::AttributesMask activeDynamicAttribs = (mDynamicAttribsMask & activeLocations);
172
173 if (activeDynamicAttribs.any())
174 {
175 ANGLE_TRY(updateDynamicAttribs(context, stateManager->getVertexDataManager(),
176 firstVertex, vertexOrIndexCount, indexTypeOrInvalid,
177 indices, instances, baseVertex, baseInstance,
178 promoteDynamic, activeDynamicAttribs));
179 stateManager->invalidateInputLayout();
180 }
181 }
182
183 if (indexTypeOrInvalid != gl::DrawElementsType::InvalidEnum)
184 {
185 bool restartEnabled = context->getState().isPrimitiveRestartEnabled();
186 if (!mLastDrawElementsType.valid() || mLastDrawElementsType.value() != indexTypeOrInvalid ||
187 mLastDrawElementsIndices.value() != indices ||
188 mLastPrimitiveRestartEnabled.value() != restartEnabled)
189 {
190 mLastDrawElementsType = indexTypeOrInvalid;
191 mLastDrawElementsIndices = indices;
192 mLastPrimitiveRestartEnabled = restartEnabled;
193
194 ANGLE_TRY(updateElementArrayStorage(context, vertexOrIndexCount, indexTypeOrInvalid,
195 indices, restartEnabled));
196 stateManager->invalidateIndexBuffer();
197 }
198 else if (mCurrentElementArrayStorage == IndexStorageType::Dynamic)
199 {
200 stateManager->invalidateIndexBuffer();
201 }
202 }
203
204 return angle::Result::Continue;
205 }
206
updateElementArrayStorage(const gl::Context * context,GLsizei indexCount,gl::DrawElementsType indexType,const void * indices,bool restartEnabled)207 angle::Result VertexArray11::updateElementArrayStorage(const gl::Context *context,
208 GLsizei indexCount,
209 gl::DrawElementsType indexType,
210 const void *indices,
211 bool restartEnabled)
212 {
213 bool usePrimitiveRestartWorkaround = UsePrimitiveRestartWorkaround(restartEnabled, indexType);
214
215 ANGLE_TRY(GetIndexTranslationDestType(context, indexCount, indexType, indices,
216 usePrimitiveRestartWorkaround,
217 &mCachedDestinationIndexType));
218
219 unsigned int offset = static_cast<unsigned int>(reinterpret_cast<uintptr_t>(indices));
220
221 mCurrentElementArrayStorage =
222 ClassifyIndexStorage(context->getState(), mState.getElementArrayBuffer(), indexType,
223 mCachedDestinationIndexType, offset);
224
225 return angle::Result::Continue;
226 }
227
updateVertexAttribStorage(const gl::Context * context,StateManager11 * stateManager,size_t attribIndex)228 void VertexArray11::updateVertexAttribStorage(const gl::Context *context,
229 StateManager11 *stateManager,
230 size_t attribIndex)
231 {
232 const gl::VertexAttribute &attrib = mState.getVertexAttribute(attribIndex);
233 const gl::VertexBinding &binding = mState.getBindingFromAttribIndex(attribIndex);
234
235 VertexStorageType newStorageType = ClassifyAttributeStorage(context, attrib, binding);
236
237 // Note: having an unchanged storage type doesn't mean the attribute is clean.
238 mAttribsToTranslate.set(attribIndex, newStorageType != VertexStorageType::DYNAMIC);
239
240 if (mAttributeStorageTypes[attribIndex] == newStorageType)
241 return;
242
243 mAttributeStorageTypes[attribIndex] = newStorageType;
244 mDynamicAttribsMask.set(attribIndex, newStorageType == VertexStorageType::DYNAMIC);
245
246 if (newStorageType == VertexStorageType::CURRENT_VALUE)
247 {
248 stateManager->invalidateCurrentValueAttrib(attribIndex);
249 }
250 }
251
hasActiveDynamicAttrib(const gl::Context * context)252 bool VertexArray11::hasActiveDynamicAttrib(const gl::Context *context)
253 {
254 const auto &activeLocations =
255 context->getState().getProgramExecutable()->getActiveAttribLocationsMask();
256 gl::AttributesMask activeDynamicAttribs = (mDynamicAttribsMask & activeLocations);
257 return activeDynamicAttribs.any();
258 }
259
updateDirtyAttribs(const gl::Context * context,const gl::AttributesMask & activeDirtyAttribs)260 angle::Result VertexArray11::updateDirtyAttribs(const gl::Context *context,
261 const gl::AttributesMask &activeDirtyAttribs)
262 {
263 const auto &glState = context->getState();
264 const auto &attribs = mState.getVertexAttributes();
265 const auto &bindings = mState.getVertexBindings();
266
267 for (size_t dirtyAttribIndex : activeDirtyAttribs)
268 {
269 auto *translatedAttrib = &mTranslatedAttribs[dirtyAttribIndex];
270 const auto ¤tValue = glState.getVertexAttribCurrentValue(dirtyAttribIndex);
271
272 // Record basic attrib info
273 translatedAttrib->attribute = &attribs[dirtyAttribIndex];
274 translatedAttrib->binding = &bindings[translatedAttrib->attribute->bindingIndex];
275 translatedAttrib->currentValueType = currentValue.Type;
276 translatedAttrib->divisor =
277 translatedAttrib->binding->getDivisor() * mAppliedNumViewsToDivisor;
278
279 switch (mAttributeStorageTypes[dirtyAttribIndex])
280 {
281 case VertexStorageType::DIRECT:
282 VertexDataManager::StoreDirectAttrib(context, translatedAttrib);
283 break;
284 case VertexStorageType::STATIC:
285 {
286 ANGLE_TRY(VertexDataManager::StoreStaticAttrib(context, translatedAttrib));
287 break;
288 }
289 case VertexStorageType::CURRENT_VALUE:
290 // Current value attribs are managed by the StateManager11.
291 break;
292 default:
293 UNREACHABLE();
294 break;
295 }
296
297 // Make sure we reset the dirty bit after the switch because STATIC can early exit.
298 mAttribsToTranslate.reset(dirtyAttribIndex);
299 }
300
301 return angle::Result::Continue;
302 }
303
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)304 angle::Result VertexArray11::updateDynamicAttribs(const gl::Context *context,
305 VertexDataManager *vertexDataManager,
306 GLint firstVertex,
307 GLsizei vertexOrIndexCount,
308 gl::DrawElementsType indexTypeOrInvalid,
309 const void *indices,
310 GLsizei instances,
311 GLint baseVertex,
312 GLuint baseInstance,
313 bool promoteDynamic,
314 const gl::AttributesMask &activeDynamicAttribs)
315 {
316 const auto &glState = context->getState();
317 const auto &attribs = mState.getVertexAttributes();
318 const auto &bindings = mState.getVertexBindings();
319
320 GLint startVertex;
321 size_t vertexCount;
322 ANGLE_TRY(GetVertexRangeInfo(context, firstVertex, vertexOrIndexCount, indexTypeOrInvalid,
323 indices, baseVertex, &startVertex, &vertexCount));
324
325 for (size_t dynamicAttribIndex : activeDynamicAttribs)
326 {
327 auto *dynamicAttrib = &mTranslatedAttribs[dynamicAttribIndex];
328 const auto ¤tValue = glState.getVertexAttribCurrentValue(dynamicAttribIndex);
329
330 // Record basic attrib info
331 dynamicAttrib->attribute = &attribs[dynamicAttribIndex];
332 dynamicAttrib->binding = &bindings[dynamicAttrib->attribute->bindingIndex];
333 dynamicAttrib->currentValueType = currentValue.Type;
334 dynamicAttrib->divisor = dynamicAttrib->binding->getDivisor() * mAppliedNumViewsToDivisor;
335 }
336
337 ANGLE_TRY(vertexDataManager->storeDynamicAttribs(context, &mTranslatedAttribs,
338 activeDynamicAttribs, startVertex, vertexCount,
339 instances, baseInstance));
340
341 if (promoteDynamic)
342 {
343 VertexDataManager::PromoteDynamicAttribs(context, mTranslatedAttribs, activeDynamicAttribs,
344 vertexCount);
345 }
346
347 return angle::Result::Continue;
348 }
349
getTranslatedAttribs() const350 const std::vector<TranslatedAttribute> &VertexArray11::getTranslatedAttribs() const
351 {
352 return mTranslatedAttribs;
353 }
354
markAllAttributeDivisorsForAdjustment(int numViews)355 void VertexArray11::markAllAttributeDivisorsForAdjustment(int numViews)
356 {
357 if (mAppliedNumViewsToDivisor != numViews)
358 {
359 mAppliedNumViewsToDivisor = numViews;
360 mAttribsToTranslate.set();
361 // mDynamicAttribsMask may have already been set (updateVertexAttribStorage
362 // We don't want to override DYNAMIC attribs as they will be handled separately.
363 mAttribsToTranslate = mAttribsToTranslate ^ mDynamicAttribsMask;
364 }
365 }
366
getCachedIndexInfo() const367 const TranslatedIndexData &VertexArray11::getCachedIndexInfo() const
368 {
369 ASSERT(mCachedIndexInfo.valid());
370 return mCachedIndexInfo.value();
371 }
372
updateCachedIndexInfo(const TranslatedIndexData & indexInfo)373 void VertexArray11::updateCachedIndexInfo(const TranslatedIndexData &indexInfo)
374 {
375 mCachedIndexInfo = indexInfo;
376 }
377
isCachedIndexInfoValid() const378 bool VertexArray11::isCachedIndexInfoValid() const
379 {
380 return mCachedIndexInfo.valid();
381 }
382
getCachedDestinationIndexType() const383 gl::DrawElementsType VertexArray11::getCachedDestinationIndexType() const
384 {
385 return mCachedDestinationIndexType;
386 }
387
388 } // namespace rx
389