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 angle::CheckedNumeric<int64_t> bufferSize(size);
62 angle::CheckedNumeric<int64_t> stride = ComputeVertexAttributeStride(attrib, binding);
63 angle::CheckedNumeric<int64_t> offset = ComputeVertexAttributeOffset(attrib, binding);
64 angle::CheckedNumeric<int64_t> elementSize = ComputeVertexAttributeTypeSize(attrib);
65
66 auto elementsInBuffer = (bufferSize - (offset % stride) + (stride - elementSize)) / stride;
67 auto elementsInBufferInt = elementsInBuffer.Cast<int>();
68
69 return elementsInBufferInt.ValueOrDefault(0);
70 }
71
72 // 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)73 bool DirectStoragePossible(const gl::Context *context,
74 const gl::VertexAttribute &attrib,
75 const gl::VertexBinding &binding)
76 {
77 // Current value attribs may not use direct storage.
78 if (!attrib.enabled)
79 {
80 return false;
81 }
82
83 gl::Buffer *buffer = binding.getBuffer().get();
84 if (!buffer)
85 {
86 return false;
87 }
88
89 BufferD3D *bufferD3D = GetImplAs<BufferD3D>(buffer);
90 ASSERT(bufferD3D);
91 if (!bufferD3D->supportsDirectBinding())
92 {
93 return false;
94 }
95
96 // Alignment restrictions: In D3D, vertex data must be aligned to the format stride, or to a
97 // 4-byte boundary, whichever is smaller. (Undocumented, and experimentally confirmed)
98 size_t alignment = 4;
99
100 // TODO(jmadill): add VertexFormatCaps
101 BufferFactoryD3D *factory = bufferD3D->getFactory();
102
103 angle::FormatID vertexFormatID = attrib.format->id;
104
105 // CPU-converted vertex data must be converted (naturally).
106 if ((factory->getVertexConversionType(vertexFormatID) & VERTEX_CONVERT_CPU) != 0)
107 {
108 return false;
109 }
110
111 if (attrib.format->vertexAttribType != gl::VertexAttribType::Float)
112 {
113 unsigned int elementSize = 0;
114 angle::Result error =
115 factory->getVertexSpaceRequired(context, attrib, binding, 1, 0, 0, &elementSize);
116 ASSERT(error == angle::Result::Continue);
117 alignment = std::min<size_t>(elementSize, 4);
118 }
119
120 GLintptr offset = ComputeVertexAttributeOffset(attrib, binding);
121 // Final alignment check - unaligned data must be converted.
122 return (static_cast<size_t>(ComputeVertexAttributeStride(attrib, binding)) % alignment == 0) &&
123 (static_cast<size_t>(offset) % alignment == 0);
124 }
125 } // anonymous namespace
126
TranslatedAttribute()127 TranslatedAttribute::TranslatedAttribute()
128 : active(false),
129 attribute(nullptr),
130 binding(nullptr),
131 currentValueType(gl::VertexAttribType::InvalidEnum),
132 baseOffset(0),
133 usesFirstVertexOffset(false),
134 stride(0),
135 vertexBuffer(),
136 storage(nullptr),
137 serial(0),
138 divisor(0)
139 {}
140
141 TranslatedAttribute::TranslatedAttribute(const TranslatedAttribute &other) = default;
142
computeOffset(const gl::Context * context,GLint startVertex,unsigned int * offsetOut) const143 angle::Result TranslatedAttribute::computeOffset(const gl::Context *context,
144 GLint startVertex,
145 unsigned int *offsetOut) const
146 {
147 if (!usesFirstVertexOffset)
148 {
149 *offsetOut = baseOffset;
150 return angle::Result::Continue;
151 }
152
153 CheckedNumeric<unsigned int> offset(baseOffset);
154 CheckedNumeric<unsigned int> checkedStride(stride);
155
156 offset += checkedStride * static_cast<unsigned int>(startVertex);
157 ANGLE_CHECK_GL_MATH(GetImplAs<ContextD3D>(context), offset.IsValid());
158 *offsetOut = offset.ValueOrDie();
159 return angle::Result::Continue;
160 }
161
162 // 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)163 VertexStorageType ClassifyAttributeStorage(const gl::Context *context,
164 const gl::VertexAttribute &attrib,
165 const gl::VertexBinding &binding)
166 {
167 // If attribute is disabled, we use the current value.
168 if (!attrib.enabled)
169 {
170 return VertexStorageType::CURRENT_VALUE;
171 }
172
173 // If specified with immediate data, we must use dynamic storage.
174 gl::Buffer *buffer = binding.getBuffer().get();
175 if (!buffer)
176 {
177 return VertexStorageType::DYNAMIC;
178 }
179
180 // Check if the buffer supports direct storage.
181 if (DirectStoragePossible(context, attrib, binding))
182 {
183 return VertexStorageType::DIRECT;
184 }
185
186 // Otherwise the storage is static or dynamic.
187 BufferD3D *bufferD3D = GetImplAs<BufferD3D>(buffer);
188 ASSERT(bufferD3D);
189 switch (bufferD3D->getUsage())
190 {
191 case D3DBufferUsage::DYNAMIC:
192 return VertexStorageType::DYNAMIC;
193 case D3DBufferUsage::STATIC:
194 return VertexStorageType::STATIC;
195 default:
196 UNREACHABLE();
197 return VertexStorageType::UNKNOWN;
198 }
199 }
200
CurrentValueState(BufferFactoryD3D * factory)201 VertexDataManager::CurrentValueState::CurrentValueState(BufferFactoryD3D *factory)
202 : buffer(new StreamingVertexBufferInterface(factory)), offset(0)
203 {
204 data.Values.FloatValues[0] = std::numeric_limits<float>::quiet_NaN();
205 data.Values.FloatValues[1] = std::numeric_limits<float>::quiet_NaN();
206 data.Values.FloatValues[2] = std::numeric_limits<float>::quiet_NaN();
207 data.Values.FloatValues[3] = std::numeric_limits<float>::quiet_NaN();
208 data.Type = gl::VertexAttribType::Float;
209 }
210
CurrentValueState(CurrentValueState && other)211 VertexDataManager::CurrentValueState::CurrentValueState(CurrentValueState &&other)
212 {
213 std::swap(buffer, other.buffer);
214 std::swap(data, other.data);
215 std::swap(offset, other.offset);
216 }
217
~CurrentValueState()218 VertexDataManager::CurrentValueState::~CurrentValueState() {}
219
VertexDataManager(BufferFactoryD3D * factory)220 VertexDataManager::VertexDataManager(BufferFactoryD3D *factory)
221 : mFactory(factory), mStreamingBuffer(factory)
222 {
223 mCurrentValueCache.reserve(gl::MAX_VERTEX_ATTRIBS);
224 for (int currentValueIndex = 0; currentValueIndex < gl::MAX_VERTEX_ATTRIBS; ++currentValueIndex)
225 {
226 mCurrentValueCache.emplace_back(factory);
227 }
228 }
229
~VertexDataManager()230 VertexDataManager::~VertexDataManager() {}
231
initialize(const gl::Context * context)232 angle::Result VertexDataManager::initialize(const gl::Context *context)
233 {
234 return mStreamingBuffer.initialize(context, INITIAL_STREAM_BUFFER_SIZE);
235 }
236
deinitialize()237 void VertexDataManager::deinitialize()
238 {
239 mStreamingBuffer.reset();
240 mCurrentValueCache.clear();
241 }
242
prepareVertexData(const gl::Context * context,GLint start,GLsizei count,std::vector<TranslatedAttribute> * translatedAttribs,GLsizei instances)243 angle::Result VertexDataManager::prepareVertexData(
244 const gl::Context *context,
245 GLint start,
246 GLsizei count,
247 std::vector<TranslatedAttribute> *translatedAttribs,
248 GLsizei instances)
249 {
250 const gl::State &state = context->getState();
251 const gl::ProgramExecutable *executable = state.getProgramExecutable();
252 const gl::VertexArray *vertexArray = state.getVertexArray();
253 const auto &vertexAttributes = vertexArray->getVertexAttributes();
254 const auto &vertexBindings = vertexArray->getVertexBindings();
255
256 mDynamicAttribsMaskCache.reset();
257
258 translatedAttribs->clear();
259
260 for (size_t attribIndex = 0; attribIndex < vertexAttributes.size(); ++attribIndex)
261 {
262 // Skip attrib locations the program doesn't use.
263 if (!executable->isAttribLocationActive(attribIndex))
264 continue;
265
266 const auto &attrib = vertexAttributes[attribIndex];
267 const auto &binding = vertexBindings[attrib.bindingIndex];
268
269 // Resize automatically puts in empty attribs
270 translatedAttribs->resize(attribIndex + 1);
271
272 TranslatedAttribute *translated = &(*translatedAttribs)[attribIndex];
273 auto currentValueData = state.getVertexAttribCurrentValue(attribIndex);
274
275 // Record the attribute now
276 translated->active = true;
277 translated->attribute = &attrib;
278 translated->binding = &binding;
279 translated->currentValueType = currentValueData.Type;
280 translated->divisor = binding.getDivisor();
281
282 switch (ClassifyAttributeStorage(context, attrib, binding))
283 {
284 case VertexStorageType::STATIC:
285 {
286 // Store static attribute.
287 ANGLE_TRY(StoreStaticAttrib(context, translated));
288 break;
289 }
290 case VertexStorageType::DYNAMIC:
291 // Dynamic attributes must be handled together.
292 mDynamicAttribsMaskCache.set(attribIndex);
293 break;
294 case VertexStorageType::DIRECT:
295 // Update translated data for direct attributes.
296 StoreDirectAttrib(context, translated);
297 break;
298 case VertexStorageType::CURRENT_VALUE:
299 {
300 ANGLE_TRY(storeCurrentValue(context, currentValueData, translated, attribIndex));
301 break;
302 }
303 default:
304 UNREACHABLE();
305 break;
306 }
307 }
308
309 if (mDynamicAttribsMaskCache.none())
310 {
311 return angle::Result::Continue;
312 }
313
314 // prepareVertexData is only called by Renderer9 which don't support baseInstance
315 ANGLE_TRY(storeDynamicAttribs(context, translatedAttribs, mDynamicAttribsMaskCache, start,
316 count, instances, 0u));
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, 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,GLuint baseInstance)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 GLuint baseInstance)
423 {
424 // Instantiating this class will ensure the streaming buffer is never left mapped.
425 class StreamingBufferUnmapper final : NonCopyable
426 {
427 public:
428 StreamingBufferUnmapper(StreamingVertexBufferInterface *streamingBuffer)
429 : mStreamingBuffer(streamingBuffer)
430 {
431 ASSERT(mStreamingBuffer);
432 }
433 ~StreamingBufferUnmapper() { mStreamingBuffer->getVertexBuffer()->hintUnmapResource(); }
434
435 private:
436 StreamingVertexBufferInterface *mStreamingBuffer;
437 };
438
439 // Will trigger unmapping on return.
440 StreamingBufferUnmapper localUnmapper(&mStreamingBuffer);
441
442 // Reserve the required space for the dynamic buffers.
443 for (auto attribIndex : dynamicAttribsMask)
444 {
445 const auto &dynamicAttrib = (*translatedAttribs)[attribIndex];
446 ANGLE_TRY(
447 reserveSpaceForAttrib(context, dynamicAttrib, start, count, instances, baseInstance));
448 }
449
450 // Store dynamic attributes
451 for (auto attribIndex : dynamicAttribsMask)
452 {
453 auto *dynamicAttrib = &(*translatedAttribs)[attribIndex];
454 ANGLE_TRY(
455 storeDynamicAttrib(context, dynamicAttrib, start, count, instances, baseInstance));
456 }
457
458 return angle::Result::Continue;
459 }
460
PromoteDynamicAttribs(const gl::Context * context,const std::vector<TranslatedAttribute> & translatedAttribs,const gl::AttributesMask & dynamicAttribsMask,size_t count)461 void VertexDataManager::PromoteDynamicAttribs(
462 const gl::Context *context,
463 const std::vector<TranslatedAttribute> &translatedAttribs,
464 const gl::AttributesMask &dynamicAttribsMask,
465 size_t count)
466 {
467 for (auto attribIndex : dynamicAttribsMask)
468 {
469 const auto &dynamicAttrib = translatedAttribs[attribIndex];
470 ASSERT(dynamicAttrib.attribute && dynamicAttrib.binding);
471 const auto &binding = *dynamicAttrib.binding;
472
473 gl::Buffer *buffer = binding.getBuffer().get();
474 if (buffer)
475 {
476 // Note: this multiplication can overflow. It should not be a security problem.
477 BufferD3D *bufferD3D = GetImplAs<BufferD3D>(buffer);
478 size_t typeSize = ComputeVertexAttributeTypeSize(*dynamicAttrib.attribute);
479 bufferD3D->promoteStaticUsage(context, count * typeSize);
480 }
481 }
482 }
483
reserveSpaceForAttrib(const gl::Context * context,const TranslatedAttribute & translatedAttrib,GLint start,size_t count,GLsizei instances,GLuint baseInstance)484 angle::Result VertexDataManager::reserveSpaceForAttrib(const gl::Context *context,
485 const TranslatedAttribute &translatedAttrib,
486 GLint start,
487 size_t count,
488 GLsizei instances,
489 GLuint baseInstance)
490 {
491 ASSERT(translatedAttrib.attribute && translatedAttrib.binding);
492 const auto &attrib = *translatedAttrib.attribute;
493 const auto &binding = *translatedAttrib.binding;
494
495 ASSERT(!DirectStoragePossible(context, attrib, binding));
496
497 gl::Buffer *buffer = binding.getBuffer().get();
498 BufferD3D *bufferD3D = buffer ? GetImplAs<BufferD3D>(buffer) : nullptr;
499 ASSERT(!bufferD3D || bufferD3D->getStaticVertexBuffer(attrib, binding) == nullptr);
500
501 // Make sure we always pass at least one instance count to gl::ComputeVertexBindingElementCount.
502 // Even if this is not an instanced draw call, some attributes can still be instanced if they
503 // have a non-zero divisor.
504 size_t totalCount = gl::ComputeVertexBindingElementCount(
505 binding.getDivisor(), count, static_cast<size_t>(std::max(instances, 1)));
506 // TODO([email protected]): force the index buffer to clamp any out of range indices instead
507 // of invalid operation here.
508 if (bufferD3D)
509 {
510 // Vertices do not apply the 'start' offset when the divisor is non-zero even when doing
511 // a non-instanced draw call
512 GLint firstVertexIndex = binding.getDivisor() > 0
513 ? UnsignedCeilDivide(baseInstance, binding.getDivisor())
514 : start;
515 int64_t maxVertexCount =
516 static_cast<int64_t>(firstVertexIndex) + static_cast<int64_t>(totalCount);
517
518 int64_t maxByte = GetMaxAttributeByteOffsetForDraw(attrib, binding, maxVertexCount);
519
520 ASSERT(bufferD3D->getSize() <= static_cast<size_t>(std::numeric_limits<int64_t>::max()));
521 ANGLE_CHECK(GetImplAs<ContextD3D>(context),
522 maxByte <= static_cast<int64_t>(bufferD3D->getSize()),
523 "Vertex buffer is not big enough for the draw call.", GL_INVALID_OPERATION);
524 }
525 return mStreamingBuffer.reserveVertexSpace(context, attrib, binding, totalCount, instances,
526 baseInstance);
527 }
528
storeDynamicAttrib(const gl::Context * context,TranslatedAttribute * translated,GLint start,size_t count,GLsizei instances,GLuint baseInstance)529 angle::Result VertexDataManager::storeDynamicAttrib(const gl::Context *context,
530 TranslatedAttribute *translated,
531 GLint start,
532 size_t count,
533 GLsizei instances,
534 GLuint baseInstance)
535 {
536 ASSERT(translated->attribute && translated->binding);
537 const auto &attrib = *translated->attribute;
538 const auto &binding = *translated->binding;
539
540 gl::Buffer *buffer = binding.getBuffer().get();
541 ASSERT(buffer || attrib.pointer);
542 ASSERT(attrib.enabled);
543
544 BufferD3D *storage = buffer ? GetImplAs<BufferD3D>(buffer) : nullptr;
545
546 // Instanced vertices do not apply the 'start' offset
547 GLint firstVertexIndex =
548 (binding.getDivisor() > 0 ? UnsignedCeilDivide(baseInstance, binding.getDivisor()) : start);
549
550 // Compute source data pointer
551 const uint8_t *sourceData = nullptr;
552
553 if (buffer)
554 {
555 ANGLE_TRY(storage->getData(context, &sourceData));
556 sourceData += static_cast<int>(ComputeVertexAttributeOffset(attrib, binding));
557 }
558 else
559 {
560 // Attributes using client memory ignore the VERTEX_ATTRIB_BINDING state.
561 // https://www.opengl.org/registry/specs/ARB/vertex_attrib_binding.txt
562 sourceData = static_cast<const uint8_t *>(attrib.pointer);
563 }
564
565 unsigned int streamOffset = 0;
566
567 translated->storage = nullptr;
568 ANGLE_TRY(
569 mFactory->getVertexSpaceRequired(context, attrib, binding, 1, 0, 0, &translated->stride));
570
571 size_t totalCount = gl::ComputeVertexBindingElementCount(
572 binding.getDivisor(), count, static_cast<size_t>(std::max(instances, 1)));
573
574 ANGLE_TRY(mStreamingBuffer.storeDynamicAttribute(
575 context, attrib, binding, translated->currentValueType, firstVertexIndex,
576 static_cast<GLsizei>(totalCount), instances, baseInstance, &streamOffset, sourceData));
577
578 VertexBuffer *vertexBuffer = mStreamingBuffer.getVertexBuffer();
579
580 translated->vertexBuffer.set(vertexBuffer);
581 translated->serial = vertexBuffer->getSerial();
582 translated->baseOffset = streamOffset;
583 translated->usesFirstVertexOffset = false;
584
585 return angle::Result::Continue;
586 }
587
storeCurrentValue(const gl::Context * context,const gl::VertexAttribCurrentValueData & currentValue,TranslatedAttribute * translated,size_t attribIndex)588 angle::Result VertexDataManager::storeCurrentValue(
589 const gl::Context *context,
590 const gl::VertexAttribCurrentValueData ¤tValue,
591 TranslatedAttribute *translated,
592 size_t attribIndex)
593 {
594 CurrentValueState *cachedState = &mCurrentValueCache[attribIndex];
595 StreamingVertexBufferInterface &buffer = *cachedState->buffer;
596
597 if (buffer.getBufferSize() == 0)
598 {
599 ANGLE_TRY(buffer.initialize(context, CONSTANT_VERTEX_BUFFER_SIZE));
600 }
601
602 if (cachedState->data != currentValue)
603 {
604 ASSERT(translated->attribute && translated->binding);
605 const auto &attrib = *translated->attribute;
606 const auto &binding = *translated->binding;
607
608 ANGLE_TRY(buffer.reserveVertexSpace(context, attrib, binding, 1, 0, 0));
609
610 const uint8_t *sourceData =
611 reinterpret_cast<const uint8_t *>(currentValue.Values.FloatValues);
612 unsigned int streamOffset;
613 ANGLE_TRY(buffer.storeDynamicAttribute(context, attrib, binding, currentValue.Type, 0, 1, 0,
614 0, &streamOffset, sourceData));
615
616 buffer.getVertexBuffer()->hintUnmapResource();
617
618 cachedState->data = currentValue;
619 cachedState->offset = streamOffset;
620 }
621
622 translated->vertexBuffer.set(buffer.getVertexBuffer());
623
624 translated->storage = nullptr;
625 translated->serial = buffer.getSerial();
626 translated->divisor = 0;
627 translated->stride = 0;
628 translated->baseOffset = static_cast<unsigned int>(cachedState->offset);
629 translated->usesFirstVertexOffset = false;
630
631 return angle::Result::Continue;
632 }
633
634 // VertexBufferBinding implementation
VertexBufferBinding()635 VertexBufferBinding::VertexBufferBinding() : mBoundVertexBuffer(nullptr) {}
636
VertexBufferBinding(const VertexBufferBinding & other)637 VertexBufferBinding::VertexBufferBinding(const VertexBufferBinding &other)
638 : mBoundVertexBuffer(other.mBoundVertexBuffer)
639 {
640 if (mBoundVertexBuffer)
641 {
642 mBoundVertexBuffer->addRef();
643 }
644 }
645
~VertexBufferBinding()646 VertexBufferBinding::~VertexBufferBinding()
647 {
648 if (mBoundVertexBuffer)
649 {
650 mBoundVertexBuffer->release();
651 }
652 }
653
operator =(const VertexBufferBinding & other)654 VertexBufferBinding &VertexBufferBinding::operator=(const VertexBufferBinding &other)
655 {
656 mBoundVertexBuffer = other.mBoundVertexBuffer;
657 if (mBoundVertexBuffer)
658 {
659 mBoundVertexBuffer->addRef();
660 }
661 return *this;
662 }
663
set(VertexBuffer * vertexBuffer)664 void VertexBufferBinding::set(VertexBuffer *vertexBuffer)
665 {
666 if (mBoundVertexBuffer == vertexBuffer)
667 return;
668
669 if (mBoundVertexBuffer)
670 {
671 mBoundVertexBuffer->release();
672 }
673 if (vertexBuffer)
674 {
675 vertexBuffer->addRef();
676 }
677
678 mBoundVertexBuffer = vertexBuffer;
679 }
680
get() const681 VertexBuffer *VertexBufferBinding::get() const
682 {
683 return mBoundVertexBuffer;
684 }
685
686 } // namespace rx
687