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/d3d11/Buffer11.h"
15 #include "libANGLE/renderer/d3d/d3d11/Context11.h"
16 
17 using namespace angle;
18 
19 namespace rx
20 {
21 
22 namespace
23 {
GetBufferBroadcastChannel(Buffer11 * buffer11,IndexStorageType storageType)24 OnBufferDataDirtyChannel *GetBufferBroadcastChannel(Buffer11 *buffer11,
25                                                     IndexStorageType storageType)
26 {
27     switch (storageType)
28     {
29         case IndexStorageType::Direct:
30             return buffer11->getDirectBroadcastChannel();
31         case IndexStorageType::Static:
32             return buffer11->getStaticBroadcastChannel();
33         case IndexStorageType::Dynamic:
34             return buffer11 ? buffer11->getStaticBroadcastChannel() : nullptr;
35         default:
36             UNREACHABLE();
37             return nullptr;
38     }
39 }
40 }  // anonymous namespace
41 
VertexArray11(const gl::VertexArrayState & data)42 VertexArray11::VertexArray11(const gl::VertexArrayState &data)
43     : VertexArrayImpl(data),
44       mAttributeStorageTypes(data.getMaxAttribs(), VertexStorageType::CURRENT_VALUE),
45       mTranslatedAttribs(data.getMaxAttribs()),
46       mCurrentArrayBuffers(data.getMaxAttribs()),
47       mCurrentElementArrayBuffer(),
48       mOnArrayBufferDataDirty(),
49       mOnElementArrayBufferDataDirty(this, mCurrentArrayBuffers.size()),
50       mAppliedNumViewsToDivisor(1),
51       mLastElementType(GL_NONE),
52       mLastDrawElementsOffset(0),
53       mCurrentElementArrayStorage(IndexStorageType::Invalid),
54       mCachedIndexInfoValid(false)
55 {
56     for (size_t attribIndex = 0; attribIndex < mCurrentArrayBuffers.size(); ++attribIndex)
57     {
58         mOnArrayBufferDataDirty.emplace_back(this, attribIndex);
59     }
60 }
61 
~VertexArray11()62 VertexArray11::~VertexArray11()
63 {
64 }
65 
destroy(const gl::Context * context)66 void VertexArray11::destroy(const gl::Context *context)
67 {
68     for (auto &buffer : mCurrentArrayBuffers)
69     {
70         if (buffer.get())
71         {
72             buffer.set(context, nullptr);
73         }
74     }
75 
76     mCurrentElementArrayBuffer.set(context, nullptr);
77 }
78 
syncState(const gl::Context * context,const gl::VertexArray::DirtyBits & dirtyBits)79 void VertexArray11::syncState(const gl::Context *context,
80                               const gl::VertexArray::DirtyBits &dirtyBits)
81 {
82     ASSERT(dirtyBits.any());
83 
84     // Generate a state serial. This serial is used in the program class to validate the cached
85     // input layout, and skip recomputation in the fast path.
86     Renderer11 *renderer = GetImplAs<Context11>(context)->getRenderer();
87     mCurrentStateSerial = renderer->generateSerial();
88 
89     // TODO(jmadill): Individual attribute invalidation.
90     renderer->getStateManager()->invalidateVertexBuffer();
91 
92     for (auto dirtyBit : dirtyBits)
93     {
94         if (dirtyBit == gl::VertexArray::DIRTY_BIT_ELEMENT_ARRAY_BUFFER)
95         {
96             mCachedIndexInfoValid = false;
97             mLastElementType      = GL_NONE;
98         }
99         else
100         {
101             size_t index = gl::VertexArray::GetVertexIndexFromDirtyBit(dirtyBit);
102             // TODO(jiawei.shao@intel.com): Vertex Attrib Bindings
103             ASSERT(index == mState.getBindingIndexFromAttribIndex(index));
104             mAttribsToUpdate.set(index);
105         }
106     }
107 }
108 
flushAttribUpdates(const gl::Context * context)109 bool VertexArray11::flushAttribUpdates(const gl::Context *context)
110 {
111     if (mAttribsToUpdate.any())
112     {
113         const auto &activeLocations =
114             context->getGLState().getProgram()->getActiveAttribLocationsMask();
115 
116         // Skip attrib locations the program doesn't use.
117         gl::AttributesMask activeToUpdate = mAttribsToUpdate & activeLocations;
118 
119         for (auto toUpdateIndex : activeToUpdate)
120         {
121             mAttribsToUpdate.reset(toUpdateIndex);
122             updateVertexAttribStorage(context, toUpdateIndex);
123         }
124 
125         return true;
126     }
127 
128     return false;
129 }
130 
updateElementArrayStorage(const gl::Context * context,GLenum elementType,GLenum destElementType,const void * indices)131 bool VertexArray11::updateElementArrayStorage(const gl::Context *context,
132                                               GLenum elementType,
133                                               GLenum destElementType,
134                                               const void *indices)
135 {
136     unsigned int offset = static_cast<unsigned int>(reinterpret_cast<uintptr_t>(indices));
137 
138     if (mCachedIndexInfoValid && mLastElementType == elementType &&
139         offset == mLastDrawElementsOffset)
140     {
141         // Dynamic index buffers must be re-streamed every draw.
142         return (mCurrentElementArrayStorage == IndexStorageType::Dynamic);
143     }
144 
145     gl::Buffer *newBuffer           = mState.getElementArrayBuffer().get();
146     gl::Buffer *oldBuffer           = mCurrentElementArrayBuffer.get();
147     bool needsTranslation           = false;
148     IndexStorageType newStorageType = ClassifyIndexStorage(
149         context->getGLState(), newBuffer, elementType, destElementType, offset, &needsTranslation);
150 
151     if (newBuffer != oldBuffer)
152     {
153         mCurrentElementArrayBuffer.set(context, newBuffer);
154     }
155 
156     if (newStorageType != mCurrentElementArrayStorage || newBuffer != oldBuffer)
157     {
158         Buffer11 *newBuffer11 = SafeGetImplAs<Buffer11>(newBuffer);
159 
160         auto *newChannel = GetBufferBroadcastChannel(newBuffer11, newStorageType);
161 
162         mCurrentElementArrayStorage = newStorageType;
163         mOnElementArrayBufferDataDirty.bind(newChannel);
164         needsTranslation = true;
165     }
166 
167     if (mLastDrawElementsOffset != offset)
168     {
169         needsTranslation        = true;
170         mLastDrawElementsOffset = offset;
171     }
172 
173     if (mLastElementType != elementType)
174     {
175         needsTranslation = true;
176         mLastElementType = elementType;
177     }
178 
179     // TODO(jmadill): We should probably promote static usage immediately, because this can change
180     // the storage type for dynamic buffers.
181     return needsTranslation || !mCachedIndexInfoValid;
182 }
183 
updateVertexAttribStorage(const gl::Context * context,size_t attribIndex)184 void VertexArray11::updateVertexAttribStorage(const gl::Context *context, size_t attribIndex)
185 {
186     const auto &attrib  = mState.getVertexAttribute(attribIndex);
187     const auto &binding = mState.getBindingFromAttribIndex(attribIndex);
188 
189     // Note: having an unchanged storage type doesn't mean the attribute is clean.
190     auto oldStorageType = mAttributeStorageTypes[attribIndex];
191     auto newStorageType = ClassifyAttributeStorage(attrib, binding);
192 
193     mAttributeStorageTypes[attribIndex] = newStorageType;
194 
195     StateManager11 *stateManager = GetImplAs<Context11>(context)->getRenderer()->getStateManager();
196 
197     if (newStorageType == VertexStorageType::DYNAMIC)
198     {
199         if (oldStorageType != VertexStorageType::DYNAMIC)
200         {
201             // Sync dynamic attribs in a different set.
202             mAttribsToTranslate.reset(attribIndex);
203             mDynamicAttribsMask.set(attribIndex);
204         }
205     }
206     else
207     {
208         mAttribsToTranslate.set(attribIndex);
209         stateManager->invalidateVertexAttributeTranslation();
210 
211         if (oldStorageType == VertexStorageType::DYNAMIC)
212         {
213             ASSERT(mDynamicAttribsMask[attribIndex]);
214             mDynamicAttribsMask.reset(attribIndex);
215         }
216     }
217 
218     gl::Buffer *oldBufferGL = mCurrentArrayBuffers[attribIndex].get();
219     gl::Buffer *newBufferGL = binding.getBuffer().get();
220     Buffer11 *oldBuffer11   = oldBufferGL ? GetImplAs<Buffer11>(oldBufferGL) : nullptr;
221     Buffer11 *newBuffer11   = newBufferGL ? GetImplAs<Buffer11>(newBufferGL) : nullptr;
222 
223     if (oldBuffer11 != newBuffer11 || oldStorageType != newStorageType)
224     {
225         OnBufferDataDirtyChannel *newChannel = nullptr;
226 
227         if (newStorageType == VertexStorageType::CURRENT_VALUE)
228         {
229             stateManager->invalidateCurrentValueAttrib(attribIndex);
230         }
231         else if (newBuffer11 != nullptr)
232         {
233             // Note that for static callbacks, promotion to a static buffer from a dynamic buffer
234             // means we need to tag dynamic buffers with static callbacks.
235             switch (newStorageType)
236             {
237                 case VertexStorageType::DIRECT:
238                     newChannel = newBuffer11->getDirectBroadcastChannel();
239                     break;
240                 case VertexStorageType::STATIC:
241                 case VertexStorageType::DYNAMIC:
242                     newChannel = newBuffer11->getStaticBroadcastChannel();
243                     break;
244                 default:
245                     UNREACHABLE();
246                     break;
247             }
248         }
249 
250         mOnArrayBufferDataDirty[attribIndex].bind(newChannel);
251         mCurrentArrayBuffers[attribIndex].set(context, binding.getBuffer().get());
252     }
253 }
254 
hasActiveDynamicAttrib(const gl::Context * context)255 bool VertexArray11::hasActiveDynamicAttrib(const gl::Context *context)
256 {
257     flushAttribUpdates(context);
258     const auto &activeLocations =
259         context->getGLState().getProgram()->getActiveAttribLocationsMask();
260     auto activeDynamicAttribs = (mDynamicAttribsMask & activeLocations);
261     return activeDynamicAttribs.any();
262 }
263 
updateDirtyAndDynamicAttribs(const gl::Context * context,VertexDataManager * vertexDataManager,const DrawCallVertexParams & vertexParams)264 gl::Error VertexArray11::updateDirtyAndDynamicAttribs(const gl::Context *context,
265                                                       VertexDataManager *vertexDataManager,
266                                                       const DrawCallVertexParams &vertexParams)
267 {
268     flushAttribUpdates(context);
269 
270     const auto &glState         = context->getGLState();
271     const gl::Program *program  = glState.getProgram();
272     const auto &activeLocations = program->getActiveAttribLocationsMask();
273     const auto &attribs         = mState.getVertexAttributes();
274     const auto &bindings        = mState.getVertexBindings();
275     mAppliedNumViewsToDivisor =
276         (program != nullptr && program->usesMultiview()) ? program->getNumViews() : 1;
277 
278     if (mAttribsToTranslate.any())
279     {
280         // Skip attrib locations the program doesn't use, saving for the next frame.
281         gl::AttributesMask dirtyActiveAttribs = (mAttribsToTranslate & activeLocations);
282 
283         for (auto dirtyAttribIndex : dirtyActiveAttribs)
284         {
285             mAttribsToTranslate.reset(dirtyAttribIndex);
286 
287             auto *translatedAttrib = &mTranslatedAttribs[dirtyAttribIndex];
288             const auto &currentValue = glState.getVertexAttribCurrentValue(dirtyAttribIndex);
289 
290             // Record basic attrib info
291             translatedAttrib->attribute = &attribs[dirtyAttribIndex];
292             translatedAttrib->binding   = &bindings[translatedAttrib->attribute->bindingIndex];
293             translatedAttrib->currentValueType = currentValue.Type;
294             translatedAttrib->divisor =
295                 translatedAttrib->binding->getDivisor() * mAppliedNumViewsToDivisor;
296 
297             switch (mAttributeStorageTypes[dirtyAttribIndex])
298             {
299                 case VertexStorageType::DIRECT:
300                     VertexDataManager::StoreDirectAttrib(translatedAttrib);
301                     break;
302                 case VertexStorageType::STATIC:
303                 {
304                     ANGLE_TRY(VertexDataManager::StoreStaticAttrib(context, translatedAttrib));
305                     break;
306                 }
307                 case VertexStorageType::CURRENT_VALUE:
308                     // Current value attribs are managed by the StateManager11.
309                     break;
310                 default:
311                     UNREACHABLE();
312                     break;
313             }
314         }
315     }
316 
317     if (mDynamicAttribsMask.any())
318     {
319         auto activeDynamicAttribs = (mDynamicAttribsMask & activeLocations);
320         if (activeDynamicAttribs.none())
321         {
322             return gl::NoError();
323         }
324 
325         for (auto dynamicAttribIndex : activeDynamicAttribs)
326         {
327             auto *dynamicAttrib = &mTranslatedAttribs[dynamicAttribIndex];
328             const auto &currentValue = 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 =
335                 dynamicAttrib->binding->getDivisor() * mAppliedNumViewsToDivisor;
336         }
337 
338         ANGLE_TRY(vertexDataManager->storeDynamicAttribs(
339             context, &mTranslatedAttribs, activeDynamicAttribs, vertexParams.firstVertex(),
340             vertexParams.vertexCount(), vertexParams.instances()));
341     }
342 
343     return gl::NoError();
344 }
345 
getTranslatedAttribs() const346 const std::vector<TranslatedAttribute> &VertexArray11::getTranslatedAttribs() const
347 {
348     return mTranslatedAttribs;
349 }
350 
signal(size_t channelID,const gl::Context * context)351 void VertexArray11::signal(size_t channelID, const gl::Context *context)
352 {
353     if (channelID == mAttributeStorageTypes.size())
354     {
355         mCachedIndexInfoValid   = false;
356         mLastElementType        = GL_NONE;
357         mLastDrawElementsOffset = 0;
358     }
359     else
360     {
361         ASSERT(mAttributeStorageTypes[channelID] != VertexStorageType::CURRENT_VALUE);
362 
363         // This can change a buffer's storage, we'll need to re-check.
364         mAttribsToUpdate.set(channelID);
365 
366         // Changing the vertex attribute state can affect the vertex shader.
367         Renderer11 *renderer = GetImplAs<Context11>(context)->getRenderer();
368         renderer->getStateManager()->invalidateShaders();
369     }
370 }
371 
clearDirtyAndPromoteDynamicAttribs(const gl::Context * context,const DrawCallVertexParams & vertexParams)372 void VertexArray11::clearDirtyAndPromoteDynamicAttribs(const gl::Context *context,
373                                                        const DrawCallVertexParams &vertexParams)
374 {
375     const gl::State &state      = context->getGLState();
376     const gl::Program *program  = state.getProgram();
377     const auto &activeLocations = program->getActiveAttribLocationsMask();
378     mAttribsToUpdate &= ~activeLocations;
379 
380     // Promote to static after we clear the dirty attributes, otherwise we can lose dirtyness.
381     auto activeDynamicAttribs = (mDynamicAttribsMask & activeLocations);
382     if (activeDynamicAttribs.any())
383     {
384         VertexDataManager::PromoteDynamicAttribs(context, mTranslatedAttribs, activeDynamicAttribs,
385                                                  vertexParams.vertexCount());
386     }
387 }
388 
markAllAttributeDivisorsForAdjustment(int numViews)389 void VertexArray11::markAllAttributeDivisorsForAdjustment(int numViews)
390 {
391     if (mAppliedNumViewsToDivisor != numViews)
392     {
393         mAppliedNumViewsToDivisor = numViews;
394         mAttribsToUpdate.set();
395     }
396 }
397 
getCachedIndexInfo()398 TranslatedIndexData *VertexArray11::getCachedIndexInfo()
399 {
400     return &mCachedIndexInfo;
401 }
402 
setCachedIndexInfoValid()403 void VertexArray11::setCachedIndexInfoValid()
404 {
405     mCachedIndexInfoValid = true;
406 }
407 
isCachedIndexInfoValid() const408 bool VertexArray11::isCachedIndexInfoValid() const
409 {
410     return mCachedIndexInfoValid;
411 }
412 
413 }  // namespace rx
414