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, &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     ANGLE_TRY(storeDynamicAttribs(context, translatedAttribs, mDynamicAttribsMaskCache, start,
316                                   count, instances));
317 
318     PromoteDynamicAttribs(context, *translatedAttribs, mDynamicAttribsMaskCache, count);
319 
320     return angle::Result::Continue;
321 }
322 
323 // static
StoreDirectAttrib(const gl::Context * context,TranslatedAttribute * directAttrib)324 void VertexDataManager::StoreDirectAttrib(const gl::Context *context,
325                                           TranslatedAttribute *directAttrib)
326 {
327     ASSERT(directAttrib->attribute && directAttrib->binding);
328     const auto &attrib  = *directAttrib->attribute;
329     const auto &binding = *directAttrib->binding;
330 
331     gl::Buffer *buffer = binding.getBuffer().get();
332     ASSERT(buffer);
333     BufferD3D *bufferD3D = GetImplAs<BufferD3D>(buffer);
334 
335     ASSERT(DirectStoragePossible(context, attrib, binding));
336     directAttrib->vertexBuffer.set(nullptr);
337     directAttrib->storage = bufferD3D;
338     directAttrib->serial  = bufferD3D->getSerial();
339     directAttrib->stride = static_cast<unsigned int>(ComputeVertexAttributeStride(attrib, binding));
340     directAttrib->baseOffset =
341         static_cast<unsigned int>(ComputeVertexAttributeOffset(attrib, binding));
342 
343     // Instanced vertices do not apply the 'start' offset
344     directAttrib->usesFirstVertexOffset = (binding.getDivisor() == 0);
345 }
346 
347 // static
StoreStaticAttrib(const gl::Context * context,TranslatedAttribute * translated)348 angle::Result VertexDataManager::StoreStaticAttrib(const gl::Context *context,
349                                                    TranslatedAttribute *translated)
350 {
351     ASSERT(translated->attribute && translated->binding);
352     const auto &attrib  = *translated->attribute;
353     const auto &binding = *translated->binding;
354 
355     gl::Buffer *buffer = binding.getBuffer().get();
356     ASSERT(buffer && attrib.enabled && !DirectStoragePossible(context, attrib, binding));
357     BufferD3D *bufferD3D = GetImplAs<BufferD3D>(buffer);
358 
359     // Compute source data pointer
360     const uint8_t *sourceData = nullptr;
361     const int offset          = static_cast<int>(ComputeVertexAttributeOffset(attrib, binding));
362 
363     ANGLE_TRY(bufferD3D->getData(context, &sourceData));
364 
365     if (sourceData)
366     {
367         sourceData += offset;
368     }
369 
370     unsigned int streamOffset = 0;
371 
372     translated->storage = nullptr;
373     ANGLE_TRY(bufferD3D->getFactory()->getVertexSpaceRequired(context, attrib, binding, 1, 0,
374                                                               &translated->stride));
375 
376     auto *staticBuffer = bufferD3D->getStaticVertexBuffer(attrib, binding);
377     ASSERT(staticBuffer);
378 
379     if (staticBuffer->empty())
380     {
381         // Convert the entire buffer
382         int totalCount =
383             ElementsInBuffer(attrib, binding, static_cast<unsigned int>(bufferD3D->getSize()));
384         int startIndex = offset / static_cast<int>(ComputeVertexAttributeStride(attrib, binding));
385 
386         if (totalCount > 0)
387         {
388             ANGLE_TRY(staticBuffer->storeStaticAttribute(context, attrib, binding, -startIndex,
389                                                          totalCount, 0, sourceData));
390         }
391     }
392 
393     unsigned int firstElementOffset =
394         (static_cast<unsigned int>(offset) /
395          static_cast<unsigned int>(ComputeVertexAttributeStride(attrib, binding))) *
396         translated->stride;
397 
398     VertexBuffer *vertexBuffer = staticBuffer->getVertexBuffer();
399 
400     CheckedNumeric<unsigned int> checkedOffset(streamOffset);
401     checkedOffset += firstElementOffset;
402 
403     ANGLE_CHECK_GL_MATH(GetImplAs<ContextD3D>(context), checkedOffset.IsValid());
404 
405     translated->vertexBuffer.set(vertexBuffer);
406     translated->serial     = vertexBuffer->getSerial();
407     translated->baseOffset = streamOffset + firstElementOffset;
408 
409     // Instanced vertices do not apply the 'start' offset
410     translated->usesFirstVertexOffset = (binding.getDivisor() == 0);
411 
412     return angle::Result::Continue;
413 }
414 
storeDynamicAttribs(const gl::Context * context,std::vector<TranslatedAttribute> * translatedAttribs,const gl::AttributesMask & dynamicAttribsMask,GLint start,size_t count,GLsizei instances)415 angle::Result VertexDataManager::storeDynamicAttribs(
416     const gl::Context *context,
417     std::vector<TranslatedAttribute> *translatedAttribs,
418     const gl::AttributesMask &dynamicAttribsMask,
419     GLint start,
420     size_t count,
421     GLsizei instances)
422 {
423     // Instantiating this class will ensure the streaming buffer is never left mapped.
424     class StreamingBufferUnmapper final : NonCopyable
425     {
426       public:
427         StreamingBufferUnmapper(StreamingVertexBufferInterface *streamingBuffer)
428             : mStreamingBuffer(streamingBuffer)
429         {
430             ASSERT(mStreamingBuffer);
431         }
432         ~StreamingBufferUnmapper() { mStreamingBuffer->getVertexBuffer()->hintUnmapResource(); }
433 
434       private:
435         StreamingVertexBufferInterface *mStreamingBuffer;
436     };
437 
438     // Will trigger unmapping on return.
439     StreamingBufferUnmapper localUnmapper(&mStreamingBuffer);
440 
441     // Reserve the required space for the dynamic buffers.
442     for (auto attribIndex : dynamicAttribsMask)
443     {
444         const auto &dynamicAttrib = (*translatedAttribs)[attribIndex];
445         ANGLE_TRY(reserveSpaceForAttrib(context, dynamicAttrib, start, count, instances));
446     }
447 
448     // Store dynamic attributes
449     for (auto attribIndex : dynamicAttribsMask)
450     {
451         auto *dynamicAttrib = &(*translatedAttribs)[attribIndex];
452         ANGLE_TRY(storeDynamicAttrib(context, dynamicAttrib, start, count, instances));
453     }
454 
455     return angle::Result::Continue;
456 }
457 
PromoteDynamicAttribs(const gl::Context * context,const std::vector<TranslatedAttribute> & translatedAttribs,const gl::AttributesMask & dynamicAttribsMask,size_t count)458 void VertexDataManager::PromoteDynamicAttribs(
459     const gl::Context *context,
460     const std::vector<TranslatedAttribute> &translatedAttribs,
461     const gl::AttributesMask &dynamicAttribsMask,
462     size_t count)
463 {
464     for (auto attribIndex : dynamicAttribsMask)
465     {
466         const auto &dynamicAttrib = translatedAttribs[attribIndex];
467         ASSERT(dynamicAttrib.attribute && dynamicAttrib.binding);
468         const auto &binding = *dynamicAttrib.binding;
469 
470         gl::Buffer *buffer = binding.getBuffer().get();
471         if (buffer)
472         {
473             // Note: this multiplication can overflow. It should not be a security problem.
474             BufferD3D *bufferD3D = GetImplAs<BufferD3D>(buffer);
475             size_t typeSize      = ComputeVertexAttributeTypeSize(*dynamicAttrib.attribute);
476             bufferD3D->promoteStaticUsage(context, count * typeSize);
477         }
478     }
479 }
480 
reserveSpaceForAttrib(const gl::Context * context,const TranslatedAttribute & translatedAttrib,GLint start,size_t count,GLsizei instances)481 angle::Result VertexDataManager::reserveSpaceForAttrib(const gl::Context *context,
482                                                        const TranslatedAttribute &translatedAttrib,
483                                                        GLint start,
484                                                        size_t count,
485                                                        GLsizei instances)
486 {
487     ASSERT(translatedAttrib.attribute && translatedAttrib.binding);
488     const auto &attrib  = *translatedAttrib.attribute;
489     const auto &binding = *translatedAttrib.binding;
490 
491     ASSERT(!DirectStoragePossible(context, attrib, binding));
492 
493     gl::Buffer *buffer   = binding.getBuffer().get();
494     BufferD3D *bufferD3D = buffer ? GetImplAs<BufferD3D>(buffer) : nullptr;
495     ASSERT(!bufferD3D || bufferD3D->getStaticVertexBuffer(attrib, binding) == nullptr);
496 
497     size_t totalCount = gl::ComputeVertexBindingElementCount(binding.getDivisor(), count,
498                                                              static_cast<size_t>(instances));
499     // TODO(jiajia.qin@intel.com): force the index buffer to clamp any out of range indices instead
500     // of invalid operation here.
501     if (bufferD3D)
502     {
503         // Vertices do not apply the 'start' offset when the divisor is non-zero even when doing
504         // a non-instanced draw call
505         GLint firstVertexIndex = binding.getDivisor() > 0 ? 0 : start;
506         int64_t maxVertexCount =
507             static_cast<int64_t>(firstVertexIndex) + static_cast<int64_t>(totalCount);
508 
509         int64_t maxByte = GetMaxAttributeByteOffsetForDraw(attrib, binding, maxVertexCount);
510 
511         ASSERT(bufferD3D->getSize() <= static_cast<size_t>(std::numeric_limits<int64_t>::max()));
512         ANGLE_CHECK(GetImplAs<ContextD3D>(context),
513                     maxByte <= static_cast<int64_t>(bufferD3D->getSize()),
514                     "Vertex buffer is not big enough for the draw call.", GL_INVALID_OPERATION);
515     }
516     return mStreamingBuffer.reserveVertexSpace(context, attrib, binding, totalCount, instances);
517 }
518 
storeDynamicAttrib(const gl::Context * context,TranslatedAttribute * translated,GLint start,size_t count,GLsizei instances)519 angle::Result VertexDataManager::storeDynamicAttrib(const gl::Context *context,
520                                                     TranslatedAttribute *translated,
521                                                     GLint start,
522                                                     size_t count,
523                                                     GLsizei instances)
524 {
525     ASSERT(translated->attribute && translated->binding);
526     const auto &attrib  = *translated->attribute;
527     const auto &binding = *translated->binding;
528 
529     gl::Buffer *buffer = binding.getBuffer().get();
530     ASSERT(buffer || attrib.pointer);
531     ASSERT(attrib.enabled);
532 
533     BufferD3D *storage = buffer ? GetImplAs<BufferD3D>(buffer) : nullptr;
534 
535     // Instanced vertices do not apply the 'start' offset
536     GLint firstVertexIndex = (binding.getDivisor() > 0 ? 0 : start);
537 
538     // Compute source data pointer
539     const uint8_t *sourceData = nullptr;
540 
541     if (buffer)
542     {
543         ANGLE_TRY(storage->getData(context, &sourceData));
544         sourceData += static_cast<int>(ComputeVertexAttributeOffset(attrib, binding));
545     }
546     else
547     {
548         // Attributes using client memory ignore the VERTEX_ATTRIB_BINDING state.
549         // https://www.opengl.org/registry/specs/ARB/vertex_attrib_binding.txt
550         sourceData = static_cast<const uint8_t *>(attrib.pointer);
551     }
552 
553     unsigned int streamOffset = 0;
554 
555     translated->storage = nullptr;
556     ANGLE_TRY(
557         mFactory->getVertexSpaceRequired(context, attrib, binding, 1, 0, &translated->stride));
558 
559     size_t totalCount = gl::ComputeVertexBindingElementCount(binding.getDivisor(), count,
560                                                              static_cast<size_t>(instances));
561 
562     ANGLE_TRY(mStreamingBuffer.storeDynamicAttribute(
563         context, attrib, binding, translated->currentValueType, firstVertexIndex,
564         static_cast<GLsizei>(totalCount), instances, &streamOffset, sourceData));
565 
566     VertexBuffer *vertexBuffer = mStreamingBuffer.getVertexBuffer();
567 
568     translated->vertexBuffer.set(vertexBuffer);
569     translated->serial                = vertexBuffer->getSerial();
570     translated->baseOffset            = streamOffset;
571     translated->usesFirstVertexOffset = false;
572 
573     return angle::Result::Continue;
574 }
575 
storeCurrentValue(const gl::Context * context,const gl::VertexAttribCurrentValueData & currentValue,TranslatedAttribute * translated,size_t attribIndex)576 angle::Result VertexDataManager::storeCurrentValue(
577     const gl::Context *context,
578     const gl::VertexAttribCurrentValueData &currentValue,
579     TranslatedAttribute *translated,
580     size_t attribIndex)
581 {
582     CurrentValueState *cachedState         = &mCurrentValueCache[attribIndex];
583     StreamingVertexBufferInterface &buffer = *cachedState->buffer;
584 
585     if (buffer.getBufferSize() == 0)
586     {
587         ANGLE_TRY(buffer.initialize(context, CONSTANT_VERTEX_BUFFER_SIZE));
588     }
589 
590     if (cachedState->data != currentValue)
591     {
592         ASSERT(translated->attribute && translated->binding);
593         const auto &attrib  = *translated->attribute;
594         const auto &binding = *translated->binding;
595 
596         ANGLE_TRY(buffer.reserveVertexSpace(context, attrib, binding, 1, 0));
597 
598         const uint8_t *sourceData =
599             reinterpret_cast<const uint8_t *>(currentValue.Values.FloatValues);
600         unsigned int streamOffset;
601         ANGLE_TRY(buffer.storeDynamicAttribute(context, attrib, binding, currentValue.Type, 0, 1, 0,
602                                                &streamOffset, sourceData));
603 
604         buffer.getVertexBuffer()->hintUnmapResource();
605 
606         cachedState->data   = currentValue;
607         cachedState->offset = streamOffset;
608     }
609 
610     translated->vertexBuffer.set(buffer.getVertexBuffer());
611 
612     translated->storage               = nullptr;
613     translated->serial                = buffer.getSerial();
614     translated->divisor               = 0;
615     translated->stride                = 0;
616     translated->baseOffset            = static_cast<unsigned int>(cachedState->offset);
617     translated->usesFirstVertexOffset = false;
618 
619     return angle::Result::Continue;
620 }
621 
622 // VertexBufferBinding implementation
VertexBufferBinding()623 VertexBufferBinding::VertexBufferBinding() : mBoundVertexBuffer(nullptr) {}
624 
VertexBufferBinding(const VertexBufferBinding & other)625 VertexBufferBinding::VertexBufferBinding(const VertexBufferBinding &other)
626     : mBoundVertexBuffer(other.mBoundVertexBuffer)
627 {
628     if (mBoundVertexBuffer)
629     {
630         mBoundVertexBuffer->addRef();
631     }
632 }
633 
~VertexBufferBinding()634 VertexBufferBinding::~VertexBufferBinding()
635 {
636     if (mBoundVertexBuffer)
637     {
638         mBoundVertexBuffer->release();
639     }
640 }
641 
operator =(const VertexBufferBinding & other)642 VertexBufferBinding &VertexBufferBinding::operator=(const VertexBufferBinding &other)
643 {
644     mBoundVertexBuffer = other.mBoundVertexBuffer;
645     if (mBoundVertexBuffer)
646     {
647         mBoundVertexBuffer->addRef();
648     }
649     return *this;
650 }
651 
set(VertexBuffer * vertexBuffer)652 void VertexBufferBinding::set(VertexBuffer *vertexBuffer)
653 {
654     if (mBoundVertexBuffer == vertexBuffer)
655         return;
656 
657     if (mBoundVertexBuffer)
658     {
659         mBoundVertexBuffer->release();
660     }
661     if (vertexBuffer)
662     {
663         vertexBuffer->addRef();
664     }
665 
666     mBoundVertexBuffer = vertexBuffer;
667 }
668 
get() const669 VertexBuffer *VertexBufferBinding::get() const
670 {
671     return mBoundVertexBuffer;
672 }
673 
674 }  // namespace rx
675