• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2002 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 
7 // VertexDataManager.h: Defines the VertexDataManager, a class that
8 // runs the Buffer translation process.
9 
10 #include "libANGLE/renderer/d3d/VertexDataManager.h"
11 
12 #include "common/bitset_utils.h"
13 #include "libANGLE/Buffer.h"
14 #include "libANGLE/Context.h"
15 #include "libANGLE/Program.h"
16 #include "libANGLE/State.h"
17 #include "libANGLE/VertexArray.h"
18 #include "libANGLE/VertexAttribute.h"
19 #include "libANGLE/formatutils.h"
20 #include "libANGLE/renderer/d3d/BufferD3D.h"
21 #include "libANGLE/renderer/d3d/ContextD3D.h"
22 #include "libANGLE/renderer/d3d/VertexBuffer.h"
23 
24 using namespace angle;
25 
26 namespace rx
27 {
28 namespace
29 {
30 enum
31 {
32     INITIAL_STREAM_BUFFER_SIZE = 1024 * 1024
33 };
34 // This has to be at least 4k or else it fails on ATI cards.
35 enum
36 {
37     CONSTANT_VERTEX_BUFFER_SIZE = 4096
38 };
39 
40 // Warning: ensure the binding matches attrib.bindingIndex before using these functions.
GetMaxAttributeByteOffsetForDraw(const gl::VertexAttribute & attrib,const gl::VertexBinding & binding,int64_t elementCount)41 int64_t GetMaxAttributeByteOffsetForDraw(const gl::VertexAttribute &attrib,
42                                          const gl::VertexBinding &binding,
43                                          int64_t elementCount)
44 {
45     CheckedNumeric<int64_t> stride = ComputeVertexAttributeStride(attrib, binding);
46     CheckedNumeric<int64_t> offset = ComputeVertexAttributeOffset(attrib, binding);
47     CheckedNumeric<int64_t> size   = ComputeVertexAttributeTypeSize(attrib);
48 
49     ASSERT(elementCount > 0);
50 
51     CheckedNumeric<int64_t> result =
52         stride * (CheckedNumeric<int64_t>(elementCount) - 1) + size + offset;
53     return result.ValueOrDefault(std::numeric_limits<int64_t>::max());
54 }
55 
56 // Warning: ensure the binding matches attrib.bindingIndex before using these functions.
ElementsInBuffer(const gl::VertexAttribute & attrib,const gl::VertexBinding & binding,unsigned int size)57 int ElementsInBuffer(const gl::VertexAttribute &attrib,
58                      const gl::VertexBinding &binding,
59                      unsigned int size)
60 {
61     // Size cannot be larger than a GLsizei
62     if (size > static_cast<unsigned int>(std::numeric_limits<int>::max()))
63     {
64         size = static_cast<unsigned int>(std::numeric_limits<int>::max());
65     }
66 
67     GLsizei stride = static_cast<GLsizei>(ComputeVertexAttributeStride(attrib, binding));
68     GLsizei offset = static_cast<GLsizei>(ComputeVertexAttributeOffset(attrib, binding));
69     return (size - offset % stride +
70             (stride - static_cast<GLsizei>(ComputeVertexAttributeTypeSize(attrib)))) /
71            stride;
72 }
73 
74 // Warning: you should ensure binding really matches attrib.bindingIndex before using this function.
DirectStoragePossible(const gl::Context * context,const gl::VertexAttribute & attrib,const gl::VertexBinding & binding)75 bool DirectStoragePossible(const gl::Context *context,
76                            const gl::VertexAttribute &attrib,
77                            const gl::VertexBinding &binding)
78 {
79     // Current value attribs may not use direct storage.
80     if (!attrib.enabled)
81     {
82         return false;
83     }
84 
85     gl::Buffer *buffer = binding.getBuffer().get();
86     if (!buffer)
87     {
88         return false;
89     }
90 
91     BufferD3D *bufferD3D = GetImplAs<BufferD3D>(buffer);
92     ASSERT(bufferD3D);
93     if (!bufferD3D->supportsDirectBinding())
94     {
95         return false;
96     }
97 
98     // Alignment restrictions: In D3D, vertex data must be aligned to the format stride, or to a
99     // 4-byte boundary, whichever is smaller. (Undocumented, and experimentally confirmed)
100     size_t alignment = 4;
101 
102     // TODO(jmadill): add VertexFormatCaps
103     BufferFactoryD3D *factory = bufferD3D->getFactory();
104 
105     angle::FormatID vertexFormatID = attrib.format->id;
106 
107     // CPU-converted vertex data must be converted (naturally).
108     if ((factory->getVertexConversionType(vertexFormatID) & VERTEX_CONVERT_CPU) != 0)
109     {
110         return false;
111     }
112 
113     if (attrib.format->vertexAttribType != gl::VertexAttribType::Float)
114     {
115         unsigned int elementSize = 0;
116         angle::Result error =
117             factory->getVertexSpaceRequired(context, attrib, binding, 1, 0, 0, &elementSize);
118         ASSERT(error == angle::Result::Continue);
119         alignment = std::min<size_t>(elementSize, 4);
120     }
121 
122     GLintptr offset = ComputeVertexAttributeOffset(attrib, binding);
123     // Final alignment check - unaligned data must be converted.
124     return (static_cast<size_t>(ComputeVertexAttributeStride(attrib, binding)) % alignment == 0) &&
125            (static_cast<size_t>(offset) % alignment == 0);
126 }
127 }  // anonymous namespace
128 
TranslatedAttribute()129 TranslatedAttribute::TranslatedAttribute()
130     : active(false),
131       attribute(nullptr),
132       binding(nullptr),
133       currentValueType(gl::VertexAttribType::InvalidEnum),
134       baseOffset(0),
135       usesFirstVertexOffset(false),
136       stride(0),
137       vertexBuffer(),
138       storage(nullptr),
139       serial(0),
140       divisor(0)
141 {}
142 
143 TranslatedAttribute::TranslatedAttribute(const TranslatedAttribute &other) = default;
144 
computeOffset(const gl::Context * context,GLint startVertex,unsigned int * offsetOut) const145 angle::Result TranslatedAttribute::computeOffset(const gl::Context *context,
146                                                  GLint startVertex,
147                                                  unsigned int *offsetOut) const
148 {
149     if (!usesFirstVertexOffset)
150     {
151         *offsetOut = baseOffset;
152         return angle::Result::Continue;
153     }
154 
155     CheckedNumeric<unsigned int> offset(baseOffset);
156     CheckedNumeric<unsigned int> checkedStride(stride);
157 
158     offset += checkedStride * static_cast<unsigned int>(startVertex);
159     ANGLE_CHECK_GL_MATH(GetImplAs<ContextD3D>(context), offset.IsValid());
160     *offsetOut = offset.ValueOrDie();
161     return angle::Result::Continue;
162 }
163 
164 // Warning: you should ensure binding really matches attrib.bindingIndex before using this function.
ClassifyAttributeStorage(const gl::Context * context,const gl::VertexAttribute & attrib,const gl::VertexBinding & binding)165 VertexStorageType ClassifyAttributeStorage(const gl::Context *context,
166                                            const gl::VertexAttribute &attrib,
167                                            const gl::VertexBinding &binding)
168 {
169     // If attribute is disabled, we use the current value.
170     if (!attrib.enabled)
171     {
172         return VertexStorageType::CURRENT_VALUE;
173     }
174 
175     // If specified with immediate data, we must use dynamic storage.
176     gl::Buffer *buffer = binding.getBuffer().get();
177     if (!buffer)
178     {
179         return VertexStorageType::DYNAMIC;
180     }
181 
182     // Check if the buffer supports direct storage.
183     if (DirectStoragePossible(context, attrib, binding))
184     {
185         return VertexStorageType::DIRECT;
186     }
187 
188     // Otherwise the storage is static or dynamic.
189     BufferD3D *bufferD3D = GetImplAs<BufferD3D>(buffer);
190     ASSERT(bufferD3D);
191     switch (bufferD3D->getUsage())
192     {
193         case D3DBufferUsage::DYNAMIC:
194             return VertexStorageType::DYNAMIC;
195         case D3DBufferUsage::STATIC:
196             return VertexStorageType::STATIC;
197         default:
198             UNREACHABLE();
199             return VertexStorageType::UNKNOWN;
200     }
201 }
202 
CurrentValueState(BufferFactoryD3D * factory)203 VertexDataManager::CurrentValueState::CurrentValueState(BufferFactoryD3D *factory)
204     : buffer(new StreamingVertexBufferInterface(factory)), offset(0)
205 {
206     data.Values.FloatValues[0] = std::numeric_limits<float>::quiet_NaN();
207     data.Values.FloatValues[1] = std::numeric_limits<float>::quiet_NaN();
208     data.Values.FloatValues[2] = std::numeric_limits<float>::quiet_NaN();
209     data.Values.FloatValues[3] = std::numeric_limits<float>::quiet_NaN();
210     data.Type                  = gl::VertexAttribType::Float;
211 }
212 
CurrentValueState(CurrentValueState && other)213 VertexDataManager::CurrentValueState::CurrentValueState(CurrentValueState &&other)
214 {
215     std::swap(buffer, other.buffer);
216     std::swap(data, other.data);
217     std::swap(offset, other.offset);
218 }
219 
~CurrentValueState()220 VertexDataManager::CurrentValueState::~CurrentValueState() {}
221 
VertexDataManager(BufferFactoryD3D * factory)222 VertexDataManager::VertexDataManager(BufferFactoryD3D *factory)
223     : mFactory(factory), mStreamingBuffer(factory)
224 {
225     for (int currentValueIndex = 0; currentValueIndex < gl::MAX_VERTEX_ATTRIBS; ++currentValueIndex)
226     {
227         mCurrentValueCache.emplace_back(factory);
228     }
229 }
230 
~VertexDataManager()231 VertexDataManager::~VertexDataManager() {}
232 
initialize(const gl::Context * context)233 angle::Result VertexDataManager::initialize(const gl::Context *context)
234 {
235     return mStreamingBuffer.initialize(context, INITIAL_STREAM_BUFFER_SIZE);
236 }
237 
deinitialize()238 void VertexDataManager::deinitialize()
239 {
240     mStreamingBuffer.reset();
241     mCurrentValueCache.clear();
242 }
243 
prepareVertexData(const gl::Context * context,GLint start,GLsizei count,std::vector<TranslatedAttribute> * translatedAttribs,GLsizei instances)244 angle::Result VertexDataManager::prepareVertexData(
245     const gl::Context *context,
246     GLint start,
247     GLsizei count,
248     std::vector<TranslatedAttribute> *translatedAttribs,
249     GLsizei instances)
250 {
251     const gl::State &state                  = context->getState();
252     const gl::ProgramExecutable *executable = state.getProgramExecutable();
253     const gl::VertexArray *vertexArray      = state.getVertexArray();
254     const auto &vertexAttributes            = vertexArray->getVertexAttributes();
255     const auto &vertexBindings              = vertexArray->getVertexBindings();
256 
257     mDynamicAttribsMaskCache.reset();
258 
259     translatedAttribs->clear();
260 
261     for (size_t attribIndex = 0; attribIndex < vertexAttributes.size(); ++attribIndex)
262     {
263         // Skip attrib locations the program doesn't use.
264         if (!executable->isAttribLocationActive(attribIndex))
265             continue;
266 
267         const auto &attrib  = vertexAttributes[attribIndex];
268         const auto &binding = vertexBindings[attrib.bindingIndex];
269 
270         // Resize automatically puts in empty attribs
271         translatedAttribs->resize(attribIndex + 1);
272 
273         TranslatedAttribute *translated = &(*translatedAttribs)[attribIndex];
274         auto currentValueData           = state.getVertexAttribCurrentValue(attribIndex);
275 
276         // Record the attribute now
277         translated->active           = true;
278         translated->attribute        = &attrib;
279         translated->binding          = &binding;
280         translated->currentValueType = currentValueData.Type;
281         translated->divisor          = binding.getDivisor();
282 
283         switch (ClassifyAttributeStorage(context, attrib, binding))
284         {
285             case VertexStorageType::STATIC:
286             {
287                 // Store static attribute.
288                 ANGLE_TRY(StoreStaticAttrib(context, translated));
289                 break;
290             }
291             case VertexStorageType::DYNAMIC:
292                 // Dynamic attributes must be handled together.
293                 mDynamicAttribsMaskCache.set(attribIndex);
294                 break;
295             case VertexStorageType::DIRECT:
296                 // Update translated data for direct attributes.
297                 StoreDirectAttrib(context, translated);
298                 break;
299             case VertexStorageType::CURRENT_VALUE:
300             {
301                 ANGLE_TRY(storeCurrentValue(context, currentValueData, translated, attribIndex));
302                 break;
303             }
304             default:
305                 UNREACHABLE();
306                 break;
307         }
308     }
309 
310     if (mDynamicAttribsMaskCache.none())
311     {
312         return angle::Result::Continue;
313     }
314 
315     // prepareVertexData is only called by Renderer9 which don't support baseInstance
316     ANGLE_TRY(storeDynamicAttribs(context, translatedAttribs, mDynamicAttribsMaskCache, start,
317                                   count, instances, 0u));
318 
319     PromoteDynamicAttribs(context, *translatedAttribs, mDynamicAttribsMaskCache, count);
320 
321     return angle::Result::Continue;
322 }
323 
324 // static
StoreDirectAttrib(const gl::Context * context,TranslatedAttribute * directAttrib)325 void VertexDataManager::StoreDirectAttrib(const gl::Context *context,
326                                           TranslatedAttribute *directAttrib)
327 {
328     ASSERT(directAttrib->attribute && directAttrib->binding);
329     const auto &attrib  = *directAttrib->attribute;
330     const auto &binding = *directAttrib->binding;
331 
332     gl::Buffer *buffer = binding.getBuffer().get();
333     ASSERT(buffer);
334     BufferD3D *bufferD3D = GetImplAs<BufferD3D>(buffer);
335 
336     ASSERT(DirectStoragePossible(context, attrib, binding));
337     directAttrib->vertexBuffer.set(nullptr);
338     directAttrib->storage = bufferD3D;
339     directAttrib->serial  = bufferD3D->getSerial();
340     directAttrib->stride = static_cast<unsigned int>(ComputeVertexAttributeStride(attrib, binding));
341     directAttrib->baseOffset =
342         static_cast<unsigned int>(ComputeVertexAttributeOffset(attrib, binding));
343 
344     // Instanced vertices do not apply the 'start' offset
345     directAttrib->usesFirstVertexOffset = (binding.getDivisor() == 0);
346 }
347 
348 // static
StoreStaticAttrib(const gl::Context * context,TranslatedAttribute * translated)349 angle::Result VertexDataManager::StoreStaticAttrib(const gl::Context *context,
350                                                    TranslatedAttribute *translated)
351 {
352     ASSERT(translated->attribute && translated->binding);
353     const auto &attrib  = *translated->attribute;
354     const auto &binding = *translated->binding;
355 
356     gl::Buffer *buffer = binding.getBuffer().get();
357     ASSERT(buffer && attrib.enabled && !DirectStoragePossible(context, attrib, binding));
358     BufferD3D *bufferD3D = GetImplAs<BufferD3D>(buffer);
359 
360     // Compute source data pointer
361     const uint8_t *sourceData = nullptr;
362     const int offset          = static_cast<int>(ComputeVertexAttributeOffset(attrib, binding));
363 
364     ANGLE_TRY(bufferD3D->getData(context, &sourceData));
365 
366     if (sourceData)
367     {
368         sourceData += offset;
369     }
370 
371     unsigned int streamOffset = 0;
372 
373     translated->storage = nullptr;
374     ANGLE_TRY(bufferD3D->getFactory()->getVertexSpaceRequired(context, attrib, binding, 1, 0, 0,
375                                                               &translated->stride));
376 
377     auto *staticBuffer = bufferD3D->getStaticVertexBuffer(attrib, binding);
378     ASSERT(staticBuffer);
379 
380     if (staticBuffer->empty())
381     {
382         // Convert the entire buffer
383         int totalCount =
384             ElementsInBuffer(attrib, binding, static_cast<unsigned int>(bufferD3D->getSize()));
385         int startIndex = offset / static_cast<int>(ComputeVertexAttributeStride(attrib, binding));
386 
387         if (totalCount > 0)
388         {
389             ANGLE_TRY(staticBuffer->storeStaticAttribute(context, attrib, binding, -startIndex,
390                                                          totalCount, 0, sourceData));
391         }
392     }
393 
394     unsigned int firstElementOffset =
395         (static_cast<unsigned int>(offset) /
396          static_cast<unsigned int>(ComputeVertexAttributeStride(attrib, binding))) *
397         translated->stride;
398 
399     VertexBuffer *vertexBuffer = staticBuffer->getVertexBuffer();
400 
401     CheckedNumeric<unsigned int> checkedOffset(streamOffset);
402     checkedOffset += firstElementOffset;
403 
404     ANGLE_CHECK_GL_MATH(GetImplAs<ContextD3D>(context), checkedOffset.IsValid());
405 
406     translated->vertexBuffer.set(vertexBuffer);
407     translated->serial     = vertexBuffer->getSerial();
408     translated->baseOffset = streamOffset + firstElementOffset;
409 
410     // Instanced vertices do not apply the 'start' offset
411     translated->usesFirstVertexOffset = (binding.getDivisor() == 0);
412 
413     return angle::Result::Continue;
414 }
415 
storeDynamicAttribs(const gl::Context * context,std::vector<TranslatedAttribute> * translatedAttribs,const gl::AttributesMask & dynamicAttribsMask,GLint start,size_t count,GLsizei instances,GLuint baseInstance)416 angle::Result VertexDataManager::storeDynamicAttribs(
417     const gl::Context *context,
418     std::vector<TranslatedAttribute> *translatedAttribs,
419     const gl::AttributesMask &dynamicAttribsMask,
420     GLint start,
421     size_t count,
422     GLsizei instances,
423     GLuint baseInstance)
424 {
425     // Instantiating this class will ensure the streaming buffer is never left mapped.
426     class StreamingBufferUnmapper final : NonCopyable
427     {
428       public:
429         StreamingBufferUnmapper(StreamingVertexBufferInterface *streamingBuffer)
430             : mStreamingBuffer(streamingBuffer)
431         {
432             ASSERT(mStreamingBuffer);
433         }
434         ~StreamingBufferUnmapper() { mStreamingBuffer->getVertexBuffer()->hintUnmapResource(); }
435 
436       private:
437         StreamingVertexBufferInterface *mStreamingBuffer;
438     };
439 
440     // Will trigger unmapping on return.
441     StreamingBufferUnmapper localUnmapper(&mStreamingBuffer);
442 
443     // Reserve the required space for the dynamic buffers.
444     for (auto attribIndex : dynamicAttribsMask)
445     {
446         const auto &dynamicAttrib = (*translatedAttribs)[attribIndex];
447         ANGLE_TRY(
448             reserveSpaceForAttrib(context, dynamicAttrib, start, count, instances, baseInstance));
449     }
450 
451     // Store dynamic attributes
452     for (auto attribIndex : dynamicAttribsMask)
453     {
454         auto *dynamicAttrib = &(*translatedAttribs)[attribIndex];
455         ANGLE_TRY(
456             storeDynamicAttrib(context, dynamicAttrib, start, count, instances, baseInstance));
457     }
458 
459     return angle::Result::Continue;
460 }
461 
PromoteDynamicAttribs(const gl::Context * context,const std::vector<TranslatedAttribute> & translatedAttribs,const gl::AttributesMask & dynamicAttribsMask,size_t count)462 void VertexDataManager::PromoteDynamicAttribs(
463     const gl::Context *context,
464     const std::vector<TranslatedAttribute> &translatedAttribs,
465     const gl::AttributesMask &dynamicAttribsMask,
466     size_t count)
467 {
468     for (auto attribIndex : dynamicAttribsMask)
469     {
470         const auto &dynamicAttrib = translatedAttribs[attribIndex];
471         ASSERT(dynamicAttrib.attribute && dynamicAttrib.binding);
472         const auto &binding = *dynamicAttrib.binding;
473 
474         gl::Buffer *buffer = binding.getBuffer().get();
475         if (buffer)
476         {
477             // Note: this multiplication can overflow. It should not be a security problem.
478             BufferD3D *bufferD3D = GetImplAs<BufferD3D>(buffer);
479             size_t typeSize      = ComputeVertexAttributeTypeSize(*dynamicAttrib.attribute);
480             bufferD3D->promoteStaticUsage(context, count * typeSize);
481         }
482     }
483 }
484 
reserveSpaceForAttrib(const gl::Context * context,const TranslatedAttribute & translatedAttrib,GLint start,size_t count,GLsizei instances,GLuint baseInstance)485 angle::Result VertexDataManager::reserveSpaceForAttrib(const gl::Context *context,
486                                                        const TranslatedAttribute &translatedAttrib,
487                                                        GLint start,
488                                                        size_t count,
489                                                        GLsizei instances,
490                                                        GLuint baseInstance)
491 {
492     ASSERT(translatedAttrib.attribute && translatedAttrib.binding);
493     const auto &attrib  = *translatedAttrib.attribute;
494     const auto &binding = *translatedAttrib.binding;
495 
496     ASSERT(!DirectStoragePossible(context, attrib, binding));
497 
498     gl::Buffer *buffer   = binding.getBuffer().get();
499     BufferD3D *bufferD3D = buffer ? GetImplAs<BufferD3D>(buffer) : nullptr;
500     ASSERT(!bufferD3D || bufferD3D->getStaticVertexBuffer(attrib, binding) == nullptr);
501 
502     size_t totalCount = gl::ComputeVertexBindingElementCount(binding.getDivisor(), count,
503                                                              static_cast<size_t>(instances));
504     // TODO(jiajia.qin@intel.com): force the index buffer to clamp any out of range indices instead
505     // of invalid operation here.
506     if (bufferD3D)
507     {
508         // Vertices do not apply the 'start' offset when the divisor is non-zero even when doing
509         // a non-instanced draw call
510         GLint firstVertexIndex = binding.getDivisor() > 0
511                                      ? UnsignedCeilDivide(baseInstance, binding.getDivisor())
512                                      : start;
513         int64_t maxVertexCount =
514             static_cast<int64_t>(firstVertexIndex) + static_cast<int64_t>(totalCount);
515 
516         int64_t maxByte = GetMaxAttributeByteOffsetForDraw(attrib, binding, maxVertexCount);
517 
518         ASSERT(bufferD3D->getSize() <= static_cast<size_t>(std::numeric_limits<int64_t>::max()));
519         ANGLE_CHECK(GetImplAs<ContextD3D>(context),
520                     maxByte <= static_cast<int64_t>(bufferD3D->getSize()),
521                     "Vertex buffer is not big enough for the draw call.", GL_INVALID_OPERATION);
522     }
523     return mStreamingBuffer.reserveVertexSpace(context, attrib, binding, totalCount, instances,
524                                                baseInstance);
525 }
526 
storeDynamicAttrib(const gl::Context * context,TranslatedAttribute * translated,GLint start,size_t count,GLsizei instances,GLuint baseInstance)527 angle::Result VertexDataManager::storeDynamicAttrib(const gl::Context *context,
528                                                     TranslatedAttribute *translated,
529                                                     GLint start,
530                                                     size_t count,
531                                                     GLsizei instances,
532                                                     GLuint baseInstance)
533 {
534     ASSERT(translated->attribute && translated->binding);
535     const auto &attrib  = *translated->attribute;
536     const auto &binding = *translated->binding;
537 
538     gl::Buffer *buffer = binding.getBuffer().get();
539     ASSERT(buffer || attrib.pointer);
540     ASSERT(attrib.enabled);
541 
542     BufferD3D *storage = buffer ? GetImplAs<BufferD3D>(buffer) : nullptr;
543 
544     // Instanced vertices do not apply the 'start' offset
545     GLint firstVertexIndex =
546         (binding.getDivisor() > 0 ? UnsignedCeilDivide(baseInstance, binding.getDivisor()) : start);
547 
548     // Compute source data pointer
549     const uint8_t *sourceData = nullptr;
550 
551     if (buffer)
552     {
553         ANGLE_TRY(storage->getData(context, &sourceData));
554         sourceData += static_cast<int>(ComputeVertexAttributeOffset(attrib, binding));
555     }
556     else
557     {
558         // Attributes using client memory ignore the VERTEX_ATTRIB_BINDING state.
559         // https://www.opengl.org/registry/specs/ARB/vertex_attrib_binding.txt
560         sourceData = static_cast<const uint8_t *>(attrib.pointer);
561     }
562 
563     unsigned int streamOffset = 0;
564 
565     translated->storage = nullptr;
566     ANGLE_TRY(
567         mFactory->getVertexSpaceRequired(context, attrib, binding, 1, 0, 0, &translated->stride));
568 
569     size_t totalCount = gl::ComputeVertexBindingElementCount(binding.getDivisor(), count,
570                                                              static_cast<size_t>(instances));
571 
572     ANGLE_TRY(mStreamingBuffer.storeDynamicAttribute(
573         context, attrib, binding, translated->currentValueType, firstVertexIndex,
574         static_cast<GLsizei>(totalCount), instances, baseInstance, &streamOffset, sourceData));
575 
576     VertexBuffer *vertexBuffer = mStreamingBuffer.getVertexBuffer();
577 
578     translated->vertexBuffer.set(vertexBuffer);
579     translated->serial                = vertexBuffer->getSerial();
580     translated->baseOffset            = streamOffset;
581     translated->usesFirstVertexOffset = false;
582 
583     return angle::Result::Continue;
584 }
585 
storeCurrentValue(const gl::Context * context,const gl::VertexAttribCurrentValueData & currentValue,TranslatedAttribute * translated,size_t attribIndex)586 angle::Result VertexDataManager::storeCurrentValue(
587     const gl::Context *context,
588     const gl::VertexAttribCurrentValueData &currentValue,
589     TranslatedAttribute *translated,
590     size_t attribIndex)
591 {
592     CurrentValueState *cachedState         = &mCurrentValueCache[attribIndex];
593     StreamingVertexBufferInterface &buffer = *cachedState->buffer;
594 
595     if (buffer.getBufferSize() == 0)
596     {
597         ANGLE_TRY(buffer.initialize(context, CONSTANT_VERTEX_BUFFER_SIZE));
598     }
599 
600     if (cachedState->data != currentValue)
601     {
602         ASSERT(translated->attribute && translated->binding);
603         const auto &attrib  = *translated->attribute;
604         const auto &binding = *translated->binding;
605 
606         ANGLE_TRY(buffer.reserveVertexSpace(context, attrib, binding, 1, 0, 0));
607 
608         const uint8_t *sourceData =
609             reinterpret_cast<const uint8_t *>(currentValue.Values.FloatValues);
610         unsigned int streamOffset;
611         ANGLE_TRY(buffer.storeDynamicAttribute(context, attrib, binding, currentValue.Type, 0, 1, 0,
612                                                0, &streamOffset, sourceData));
613 
614         buffer.getVertexBuffer()->hintUnmapResource();
615 
616         cachedState->data   = currentValue;
617         cachedState->offset = streamOffset;
618     }
619 
620     translated->vertexBuffer.set(buffer.getVertexBuffer());
621 
622     translated->storage               = nullptr;
623     translated->serial                = buffer.getSerial();
624     translated->divisor               = 0;
625     translated->stride                = 0;
626     translated->baseOffset            = static_cast<unsigned int>(cachedState->offset);
627     translated->usesFirstVertexOffset = false;
628 
629     return angle::Result::Continue;
630 }
631 
632 // VertexBufferBinding implementation
VertexBufferBinding()633 VertexBufferBinding::VertexBufferBinding() : mBoundVertexBuffer(nullptr) {}
634 
VertexBufferBinding(const VertexBufferBinding & other)635 VertexBufferBinding::VertexBufferBinding(const VertexBufferBinding &other)
636     : mBoundVertexBuffer(other.mBoundVertexBuffer)
637 {
638     if (mBoundVertexBuffer)
639     {
640         mBoundVertexBuffer->addRef();
641     }
642 }
643 
~VertexBufferBinding()644 VertexBufferBinding::~VertexBufferBinding()
645 {
646     if (mBoundVertexBuffer)
647     {
648         mBoundVertexBuffer->release();
649     }
650 }
651 
operator =(const VertexBufferBinding & other)652 VertexBufferBinding &VertexBufferBinding::operator=(const VertexBufferBinding &other)
653 {
654     mBoundVertexBuffer = other.mBoundVertexBuffer;
655     if (mBoundVertexBuffer)
656     {
657         mBoundVertexBuffer->addRef();
658     }
659     return *this;
660 }
661 
set(VertexBuffer * vertexBuffer)662 void VertexBufferBinding::set(VertexBuffer *vertexBuffer)
663 {
664     if (mBoundVertexBuffer == vertexBuffer)
665         return;
666 
667     if (mBoundVertexBuffer)
668     {
669         mBoundVertexBuffer->release();
670     }
671     if (vertexBuffer)
672     {
673         vertexBuffer->addRef();
674     }
675 
676     mBoundVertexBuffer = vertexBuffer;
677 }
678 
get() const679 VertexBuffer *VertexBufferBinding::get() const
680 {
681     return mBoundVertexBuffer;
682 }
683 
684 }  // namespace rx
685