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 ¤tValue = 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 ¤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 =
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