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