xref: /aosp_15_r20/external/angle/src/libANGLE/renderer/d3d/d3d11/VertexArray11.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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::ProgramExecutable *executable = glState.getProgramExecutable();
152     ASSERT(executable);
153 
154     mAppliedNumViewsToDivisor = executable->usesMultiview() ? executable->getNumViews() : 1;
155 
156     if (mAttribsToTranslate.any())
157     {
158         const gl::AttributesMask &activeLocations = executable->getActiveAttribLocationsMask();
159         gl::AttributesMask activeDirtyAttribs     = (mAttribsToTranslate & activeLocations);
160         if (activeDirtyAttribs.any())
161         {
162             ANGLE_TRY(updateDirtyAttribs(context, activeDirtyAttribs));
163             stateManager->invalidateInputLayout();
164         }
165     }
166 
167     if (mDynamicAttribsMask.any())
168     {
169         const gl::AttributesMask &activeLocations = executable->getActiveAttribLocationsMask();
170         gl::AttributesMask activeDynamicAttribs   = (mDynamicAttribsMask & activeLocations);
171 
172         if (activeDynamicAttribs.any())
173         {
174             ANGLE_TRY(updateDynamicAttribs(context, stateManager->getVertexDataManager(),
175                                            firstVertex, vertexOrIndexCount, indexTypeOrInvalid,
176                                            indices, instances, baseVertex, baseInstance,
177                                            promoteDynamic, activeDynamicAttribs));
178             stateManager->invalidateInputLayout();
179         }
180     }
181 
182     if (indexTypeOrInvalid != gl::DrawElementsType::InvalidEnum)
183     {
184         bool restartEnabled = context->getState().isPrimitiveRestartEnabled();
185         if (!mLastDrawElementsType.valid() || mLastDrawElementsType.value() != indexTypeOrInvalid ||
186             mLastDrawElementsIndices.value() != indices ||
187             mLastPrimitiveRestartEnabled.value() != restartEnabled)
188         {
189             mLastDrawElementsType        = indexTypeOrInvalid;
190             mLastDrawElementsIndices     = indices;
191             mLastPrimitiveRestartEnabled = restartEnabled;
192 
193             ANGLE_TRY(updateElementArrayStorage(context, vertexOrIndexCount, indexTypeOrInvalid,
194                                                 indices, restartEnabled));
195             stateManager->invalidateIndexBuffer();
196         }
197         else if (mCurrentElementArrayStorage == IndexStorageType::Dynamic)
198         {
199             stateManager->invalidateIndexBuffer();
200         }
201     }
202 
203     return angle::Result::Continue;
204 }
205 
updateElementArrayStorage(const gl::Context * context,GLsizei indexCount,gl::DrawElementsType indexType,const void * indices,bool restartEnabled)206 angle::Result VertexArray11::updateElementArrayStorage(const gl::Context *context,
207                                                        GLsizei indexCount,
208                                                        gl::DrawElementsType indexType,
209                                                        const void *indices,
210                                                        bool restartEnabled)
211 {
212     bool usePrimitiveRestartWorkaround = UsePrimitiveRestartWorkaround(restartEnabled, indexType);
213 
214     ANGLE_TRY(GetIndexTranslationDestType(context, indexCount, indexType, indices,
215                                           usePrimitiveRestartWorkaround,
216                                           &mCachedDestinationIndexType));
217 
218     unsigned int offset = static_cast<unsigned int>(reinterpret_cast<uintptr_t>(indices));
219 
220     mCurrentElementArrayStorage =
221         ClassifyIndexStorage(context->getState(), mState.getElementArrayBuffer(), indexType,
222                              mCachedDestinationIndexType, offset);
223 
224     return angle::Result::Continue;
225 }
226 
updateVertexAttribStorage(const gl::Context * context,StateManager11 * stateManager,size_t attribIndex)227 void VertexArray11::updateVertexAttribStorage(const gl::Context *context,
228                                               StateManager11 *stateManager,
229                                               size_t attribIndex)
230 {
231     const gl::VertexAttribute &attrib = mState.getVertexAttribute(attribIndex);
232     const gl::VertexBinding &binding  = mState.getBindingFromAttribIndex(attribIndex);
233 
234     VertexStorageType newStorageType = ClassifyAttributeStorage(context, attrib, binding);
235 
236     // Note: having an unchanged storage type doesn't mean the attribute is clean.
237     mAttribsToTranslate.set(attribIndex, newStorageType != VertexStorageType::DYNAMIC);
238 
239     if (mAttributeStorageTypes[attribIndex] == newStorageType)
240         return;
241 
242     mAttributeStorageTypes[attribIndex] = newStorageType;
243     mDynamicAttribsMask.set(attribIndex, newStorageType == VertexStorageType::DYNAMIC);
244 
245     if (newStorageType == VertexStorageType::CURRENT_VALUE)
246     {
247         stateManager->invalidateCurrentValueAttrib(attribIndex);
248     }
249 }
250 
hasActiveDynamicAttrib(const gl::Context * context)251 bool VertexArray11::hasActiveDynamicAttrib(const gl::Context *context)
252 {
253     const auto &activeLocations =
254         context->getState().getProgramExecutable()->getActiveAttribLocationsMask();
255     gl::AttributesMask activeDynamicAttribs = (mDynamicAttribsMask & activeLocations);
256     return activeDynamicAttribs.any();
257 }
258 
updateDirtyAttribs(const gl::Context * context,const gl::AttributesMask & activeDirtyAttribs)259 angle::Result VertexArray11::updateDirtyAttribs(const gl::Context *context,
260                                                 const gl::AttributesMask &activeDirtyAttribs)
261 {
262     const auto &glState  = context->getState();
263     const auto &attribs  = mState.getVertexAttributes();
264     const auto &bindings = mState.getVertexBindings();
265 
266     for (size_t dirtyAttribIndex : activeDirtyAttribs)
267     {
268         auto *translatedAttrib   = &mTranslatedAttribs[dirtyAttribIndex];
269         const auto &currentValue = glState.getVertexAttribCurrentValue(dirtyAttribIndex);
270 
271         // Record basic attrib info
272         translatedAttrib->attribute        = &attribs[dirtyAttribIndex];
273         translatedAttrib->binding          = &bindings[translatedAttrib->attribute->bindingIndex];
274         translatedAttrib->currentValueType = currentValue.Type;
275         translatedAttrib->divisor =
276             translatedAttrib->binding->getDivisor() * mAppliedNumViewsToDivisor;
277 
278         switch (mAttributeStorageTypes[dirtyAttribIndex])
279         {
280             case VertexStorageType::DIRECT:
281                 VertexDataManager::StoreDirectAttrib(context, translatedAttrib);
282                 break;
283             case VertexStorageType::STATIC:
284             {
285                 ANGLE_TRY(VertexDataManager::StoreStaticAttrib(context, translatedAttrib));
286                 break;
287             }
288             case VertexStorageType::CURRENT_VALUE:
289                 // Current value attribs are managed by the StateManager11.
290                 break;
291             default:
292                 UNREACHABLE();
293                 break;
294         }
295 
296         // Make sure we reset the dirty bit after the switch because STATIC can early exit.
297         mAttribsToTranslate.reset(dirtyAttribIndex);
298     }
299 
300     return angle::Result::Continue;
301 }
302 
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)303 angle::Result VertexArray11::updateDynamicAttribs(const gl::Context *context,
304                                                   VertexDataManager *vertexDataManager,
305                                                   GLint firstVertex,
306                                                   GLsizei vertexOrIndexCount,
307                                                   gl::DrawElementsType indexTypeOrInvalid,
308                                                   const void *indices,
309                                                   GLsizei instances,
310                                                   GLint baseVertex,
311                                                   GLuint baseInstance,
312                                                   bool promoteDynamic,
313                                                   const gl::AttributesMask &activeDynamicAttribs)
314 {
315     const auto &glState  = context->getState();
316     const auto &attribs  = mState.getVertexAttributes();
317     const auto &bindings = mState.getVertexBindings();
318 
319     GLint startVertex;
320     size_t vertexCount;
321     ANGLE_TRY(GetVertexRangeInfo(context, firstVertex, vertexOrIndexCount, indexTypeOrInvalid,
322                                  indices, baseVertex, &startVertex, &vertexCount));
323 
324     for (size_t dynamicAttribIndex : activeDynamicAttribs)
325     {
326         auto *dynamicAttrib      = &mTranslatedAttribs[dynamicAttribIndex];
327         const auto &currentValue = glState.getVertexAttribCurrentValue(dynamicAttribIndex);
328 
329         // Record basic attrib info
330         dynamicAttrib->attribute        = &attribs[dynamicAttribIndex];
331         dynamicAttrib->binding          = &bindings[dynamicAttrib->attribute->bindingIndex];
332         dynamicAttrib->currentValueType = currentValue.Type;
333         dynamicAttrib->divisor = dynamicAttrib->binding->getDivisor() * mAppliedNumViewsToDivisor;
334     }
335 
336     ANGLE_TRY(vertexDataManager->storeDynamicAttribs(context, &mTranslatedAttribs,
337                                                      activeDynamicAttribs, startVertex, vertexCount,
338                                                      instances, baseInstance));
339 
340     if (promoteDynamic)
341     {
342         VertexDataManager::PromoteDynamicAttribs(context, mTranslatedAttribs, activeDynamicAttribs,
343                                                  vertexCount);
344     }
345 
346     return angle::Result::Continue;
347 }
348 
getTranslatedAttribs() const349 const std::vector<TranslatedAttribute> &VertexArray11::getTranslatedAttribs() const
350 {
351     return mTranslatedAttribs;
352 }
353 
markAllAttributeDivisorsForAdjustment(int numViews)354 void VertexArray11::markAllAttributeDivisorsForAdjustment(int numViews)
355 {
356     if (mAppliedNumViewsToDivisor != numViews)
357     {
358         mAppliedNumViewsToDivisor = numViews;
359         mAttribsToTranslate.set();
360         // mDynamicAttribsMask may have already been set (updateVertexAttribStorage
361         // We don't want to override DYNAMIC attribs as they will be handled separately.
362         mAttribsToTranslate = mAttribsToTranslate ^ mDynamicAttribsMask;
363     }
364 }
365 
getCachedIndexInfo() const366 const TranslatedIndexData &VertexArray11::getCachedIndexInfo() const
367 {
368     ASSERT(mCachedIndexInfo.valid());
369     return mCachedIndexInfo.value();
370 }
371 
updateCachedIndexInfo(const TranslatedIndexData & indexInfo)372 void VertexArray11::updateCachedIndexInfo(const TranslatedIndexData &indexInfo)
373 {
374     mCachedIndexInfo = indexInfo;
375 }
376 
isCachedIndexInfoValid() const377 bool VertexArray11::isCachedIndexInfoValid() const
378 {
379     return mCachedIndexInfo.valid();
380 }
381 
getCachedDestinationIndexType() const382 gl::DrawElementsType VertexArray11::getCachedDestinationIndexType() const
383 {
384     return mCachedDestinationIndexType;
385 }
386 
387 }  // namespace rx
388