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