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<size_t> bufferSize(size);
62 angle::CheckedNumeric<size_t> stride = ComputeVertexAttributeStride(attrib, binding);
63 angle::CheckedNumeric<size_t> offset = ComputeVertexAttributeOffset(attrib, binding);
64 angle::CheckedNumeric<size_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 for (int currentValueIndex = 0; currentValueIndex < gl::MAX_VERTEX_ATTRIBS; ++currentValueIndex)
224 {
225 mCurrentValueCache.emplace_back(factory);
226 }
227 }
228
~VertexDataManager()229 VertexDataManager::~VertexDataManager() {}
230
initialize(const gl::Context * context)231 angle::Result VertexDataManager::initialize(const gl::Context *context)
232 {
233 return mStreamingBuffer.initialize(context, INITIAL_STREAM_BUFFER_SIZE);
234 }
235
deinitialize()236 void VertexDataManager::deinitialize()
237 {
238 mStreamingBuffer.reset();
239 mCurrentValueCache.clear();
240 }
241
prepareVertexData(const gl::Context * context,GLint start,GLsizei count,std::vector<TranslatedAttribute> * translatedAttribs,GLsizei instances)242 angle::Result VertexDataManager::prepareVertexData(
243 const gl::Context *context,
244 GLint start,
245 GLsizei count,
246 std::vector<TranslatedAttribute> *translatedAttribs,
247 GLsizei instances)
248 {
249 const gl::State &state = context->getState();
250 const gl::ProgramExecutable *executable = state.getProgramExecutable();
251 const gl::VertexArray *vertexArray = state.getVertexArray();
252 const auto &vertexAttributes = vertexArray->getVertexAttributes();
253 const auto &vertexBindings = vertexArray->getVertexBindings();
254
255 mDynamicAttribsMaskCache.reset();
256
257 translatedAttribs->clear();
258
259 for (size_t attribIndex = 0; attribIndex < vertexAttributes.size(); ++attribIndex)
260 {
261 // Skip attrib locations the program doesn't use.
262 if (!executable->isAttribLocationActive(attribIndex))
263 continue;
264
265 const auto &attrib = vertexAttributes[attribIndex];
266 const auto &binding = vertexBindings[attrib.bindingIndex];
267
268 // Resize automatically puts in empty attribs
269 translatedAttribs->resize(attribIndex + 1);
270
271 TranslatedAttribute *translated = &(*translatedAttribs)[attribIndex];
272 auto currentValueData = state.getVertexAttribCurrentValue(attribIndex);
273
274 // Record the attribute now
275 translated->active = true;
276 translated->attribute = &attrib;
277 translated->binding = &binding;
278 translated->currentValueType = currentValueData.Type;
279 translated->divisor = binding.getDivisor();
280
281 switch (ClassifyAttributeStorage(context, attrib, binding))
282 {
283 case VertexStorageType::STATIC:
284 {
285 // Store static attribute.
286 ANGLE_TRY(StoreStaticAttrib(context, translated));
287 break;
288 }
289 case VertexStorageType::DYNAMIC:
290 // Dynamic attributes must be handled together.
291 mDynamicAttribsMaskCache.set(attribIndex);
292 break;
293 case VertexStorageType::DIRECT:
294 // Update translated data for direct attributes.
295 StoreDirectAttrib(context, translated);
296 break;
297 case VertexStorageType::CURRENT_VALUE:
298 {
299 ANGLE_TRY(storeCurrentValue(context, currentValueData, translated, attribIndex));
300 break;
301 }
302 default:
303 UNREACHABLE();
304 break;
305 }
306 }
307
308 if (mDynamicAttribsMaskCache.none())
309 {
310 return angle::Result::Continue;
311 }
312
313 // prepareVertexData is only called by Renderer9 which don't support baseInstance
314 ANGLE_TRY(storeDynamicAttribs(context, translatedAttribs, mDynamicAttribsMaskCache, start,
315 count, instances, 0u));
316
317 PromoteDynamicAttribs(context, *translatedAttribs, mDynamicAttribsMaskCache, count);
318
319 return angle::Result::Continue;
320 }
321
322 // static
StoreDirectAttrib(const gl::Context * context,TranslatedAttribute * directAttrib)323 void VertexDataManager::StoreDirectAttrib(const gl::Context *context,
324 TranslatedAttribute *directAttrib)
325 {
326 ASSERT(directAttrib->attribute && directAttrib->binding);
327 const auto &attrib = *directAttrib->attribute;
328 const auto &binding = *directAttrib->binding;
329
330 gl::Buffer *buffer = binding.getBuffer().get();
331 ASSERT(buffer);
332 BufferD3D *bufferD3D = GetImplAs<BufferD3D>(buffer);
333
334 ASSERT(DirectStoragePossible(context, attrib, binding));
335 directAttrib->vertexBuffer.set(nullptr);
336 directAttrib->storage = bufferD3D;
337 directAttrib->serial = bufferD3D->getSerial();
338 directAttrib->stride = static_cast<unsigned int>(ComputeVertexAttributeStride(attrib, binding));
339 directAttrib->baseOffset =
340 static_cast<unsigned int>(ComputeVertexAttributeOffset(attrib, binding));
341
342 // Instanced vertices do not apply the 'start' offset
343 directAttrib->usesFirstVertexOffset = (binding.getDivisor() == 0);
344 }
345
346 // static
StoreStaticAttrib(const gl::Context * context,TranslatedAttribute * translated)347 angle::Result VertexDataManager::StoreStaticAttrib(const gl::Context *context,
348 TranslatedAttribute *translated)
349 {
350 ASSERT(translated->attribute && translated->binding);
351 const auto &attrib = *translated->attribute;
352 const auto &binding = *translated->binding;
353
354 gl::Buffer *buffer = binding.getBuffer().get();
355 ASSERT(buffer && attrib.enabled && !DirectStoragePossible(context, attrib, binding));
356 BufferD3D *bufferD3D = GetImplAs<BufferD3D>(buffer);
357
358 // Compute source data pointer
359 const uint8_t *sourceData = nullptr;
360 const int offset = static_cast<int>(ComputeVertexAttributeOffset(attrib, binding));
361
362 ANGLE_TRY(bufferD3D->getData(context, &sourceData));
363
364 if (sourceData)
365 {
366 sourceData += offset;
367 }
368
369 unsigned int streamOffset = 0;
370
371 translated->storage = nullptr;
372 ANGLE_TRY(bufferD3D->getFactory()->getVertexSpaceRequired(context, attrib, binding, 1, 0, 0,
373 &translated->stride));
374
375 auto *staticBuffer = bufferD3D->getStaticVertexBuffer(attrib, binding);
376 ASSERT(staticBuffer);
377
378 if (staticBuffer->empty())
379 {
380 // Convert the entire buffer
381 int totalCount =
382 ElementsInBuffer(attrib, binding, static_cast<unsigned int>(bufferD3D->getSize()));
383 int startIndex = offset / static_cast<int>(ComputeVertexAttributeStride(attrib, binding));
384
385 if (totalCount > 0)
386 {
387 ANGLE_TRY(staticBuffer->storeStaticAttribute(context, attrib, binding, -startIndex,
388 totalCount, 0, sourceData));
389 }
390 }
391
392 unsigned int firstElementOffset =
393 (static_cast<unsigned int>(offset) /
394 static_cast<unsigned int>(ComputeVertexAttributeStride(attrib, binding))) *
395 translated->stride;
396
397 VertexBuffer *vertexBuffer = staticBuffer->getVertexBuffer();
398
399 CheckedNumeric<unsigned int> checkedOffset(streamOffset);
400 checkedOffset += firstElementOffset;
401
402 ANGLE_CHECK_GL_MATH(GetImplAs<ContextD3D>(context), checkedOffset.IsValid());
403
404 translated->vertexBuffer.set(vertexBuffer);
405 translated->serial = vertexBuffer->getSerial();
406 translated->baseOffset = streamOffset + firstElementOffset;
407
408 // Instanced vertices do not apply the 'start' offset
409 translated->usesFirstVertexOffset = (binding.getDivisor() == 0);
410
411 return angle::Result::Continue;
412 }
413
storeDynamicAttribs(const gl::Context * context,std::vector<TranslatedAttribute> * translatedAttribs,const gl::AttributesMask & dynamicAttribsMask,GLint start,size_t count,GLsizei instances,GLuint baseInstance)414 angle::Result VertexDataManager::storeDynamicAttribs(
415 const gl::Context *context,
416 std::vector<TranslatedAttribute> *translatedAttribs,
417 const gl::AttributesMask &dynamicAttribsMask,
418 GLint start,
419 size_t count,
420 GLsizei instances,
421 GLuint baseInstance)
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(
446 reserveSpaceForAttrib(context, dynamicAttrib, start, count, instances, baseInstance));
447 }
448
449 // Store dynamic attributes
450 for (auto attribIndex : dynamicAttribsMask)
451 {
452 auto *dynamicAttrib = &(*translatedAttribs)[attribIndex];
453 ANGLE_TRY(
454 storeDynamicAttrib(context, dynamicAttrib, start, count, instances, baseInstance));
455 }
456
457 return angle::Result::Continue;
458 }
459
PromoteDynamicAttribs(const gl::Context * context,const std::vector<TranslatedAttribute> & translatedAttribs,const gl::AttributesMask & dynamicAttribsMask,size_t count)460 void VertexDataManager::PromoteDynamicAttribs(
461 const gl::Context *context,
462 const std::vector<TranslatedAttribute> &translatedAttribs,
463 const gl::AttributesMask &dynamicAttribsMask,
464 size_t count)
465 {
466 for (auto attribIndex : dynamicAttribsMask)
467 {
468 const auto &dynamicAttrib = translatedAttribs[attribIndex];
469 ASSERT(dynamicAttrib.attribute && dynamicAttrib.binding);
470 const auto &binding = *dynamicAttrib.binding;
471
472 gl::Buffer *buffer = binding.getBuffer().get();
473 if (buffer)
474 {
475 // Note: this multiplication can overflow. It should not be a security problem.
476 BufferD3D *bufferD3D = GetImplAs<BufferD3D>(buffer);
477 size_t typeSize = ComputeVertexAttributeTypeSize(*dynamicAttrib.attribute);
478 bufferD3D->promoteStaticUsage(context, count * typeSize);
479 }
480 }
481 }
482
reserveSpaceForAttrib(const gl::Context * context,const TranslatedAttribute & translatedAttrib,GLint start,size_t count,GLsizei instances,GLuint baseInstance)483 angle::Result VertexDataManager::reserveSpaceForAttrib(const gl::Context *context,
484 const TranslatedAttribute &translatedAttrib,
485 GLint start,
486 size_t count,
487 GLsizei instances,
488 GLuint baseInstance)
489 {
490 ASSERT(translatedAttrib.attribute && translatedAttrib.binding);
491 const auto &attrib = *translatedAttrib.attribute;
492 const auto &binding = *translatedAttrib.binding;
493
494 ASSERT(!DirectStoragePossible(context, attrib, binding));
495
496 gl::Buffer *buffer = binding.getBuffer().get();
497 BufferD3D *bufferD3D = buffer ? GetImplAs<BufferD3D>(buffer) : nullptr;
498 ASSERT(!bufferD3D || bufferD3D->getStaticVertexBuffer(attrib, binding) == nullptr);
499
500 size_t totalCount = gl::ComputeVertexBindingElementCount(binding.getDivisor(), count,
501 static_cast<size_t>(instances));
502 // TODO(jiajia.qin@intel.com): force the index buffer to clamp any out of range indices instead
503 // of invalid operation here.
504 if (bufferD3D)
505 {
506 // Vertices do not apply the 'start' offset when the divisor is non-zero even when doing
507 // a non-instanced draw call
508 GLint firstVertexIndex = binding.getDivisor() > 0
509 ? UnsignedCeilDivide(baseInstance, binding.getDivisor())
510 : start;
511 int64_t maxVertexCount =
512 static_cast<int64_t>(firstVertexIndex) + static_cast<int64_t>(totalCount);
513
514 int64_t maxByte = GetMaxAttributeByteOffsetForDraw(attrib, binding, maxVertexCount);
515
516 ASSERT(bufferD3D->getSize() <= static_cast<size_t>(std::numeric_limits<int64_t>::max()));
517 ANGLE_CHECK(GetImplAs<ContextD3D>(context),
518 maxByte <= static_cast<int64_t>(bufferD3D->getSize()),
519 "Vertex buffer is not big enough for the draw call.", GL_INVALID_OPERATION);
520 }
521 return mStreamingBuffer.reserveVertexSpace(context, attrib, binding, totalCount, instances,
522 baseInstance);
523 }
524
storeDynamicAttrib(const gl::Context * context,TranslatedAttribute * translated,GLint start,size_t count,GLsizei instances,GLuint baseInstance)525 angle::Result VertexDataManager::storeDynamicAttrib(const gl::Context *context,
526 TranslatedAttribute *translated,
527 GLint start,
528 size_t count,
529 GLsizei instances,
530 GLuint baseInstance)
531 {
532 ASSERT(translated->attribute && translated->binding);
533 const auto &attrib = *translated->attribute;
534 const auto &binding = *translated->binding;
535
536 gl::Buffer *buffer = binding.getBuffer().get();
537 ASSERT(buffer || attrib.pointer);
538 ASSERT(attrib.enabled);
539
540 BufferD3D *storage = buffer ? GetImplAs<BufferD3D>(buffer) : nullptr;
541
542 // Instanced vertices do not apply the 'start' offset
543 GLint firstVertexIndex =
544 (binding.getDivisor() > 0 ? UnsignedCeilDivide(baseInstance, binding.getDivisor()) : start);
545
546 // Compute source data pointer
547 const uint8_t *sourceData = nullptr;
548
549 if (buffer)
550 {
551 ANGLE_TRY(storage->getData(context, &sourceData));
552 sourceData += static_cast<int>(ComputeVertexAttributeOffset(attrib, binding));
553 }
554 else
555 {
556 // Attributes using client memory ignore the VERTEX_ATTRIB_BINDING state.
557 // https://www.opengl.org/registry/specs/ARB/vertex_attrib_binding.txt
558 sourceData = static_cast<const uint8_t *>(attrib.pointer);
559 }
560
561 unsigned int streamOffset = 0;
562
563 translated->storage = nullptr;
564 ANGLE_TRY(
565 mFactory->getVertexSpaceRequired(context, attrib, binding, 1, 0, 0, &translated->stride));
566
567 size_t totalCount = gl::ComputeVertexBindingElementCount(binding.getDivisor(), count,
568 static_cast<size_t>(instances));
569
570 ANGLE_TRY(mStreamingBuffer.storeDynamicAttribute(
571 context, attrib, binding, translated->currentValueType, firstVertexIndex,
572 static_cast<GLsizei>(totalCount), instances, baseInstance, &streamOffset, sourceData));
573
574 VertexBuffer *vertexBuffer = mStreamingBuffer.getVertexBuffer();
575
576 translated->vertexBuffer.set(vertexBuffer);
577 translated->serial = vertexBuffer->getSerial();
578 translated->baseOffset = streamOffset;
579 translated->usesFirstVertexOffset = false;
580
581 return angle::Result::Continue;
582 }
583
storeCurrentValue(const gl::Context * context,const gl::VertexAttribCurrentValueData & currentValue,TranslatedAttribute * translated,size_t attribIndex)584 angle::Result VertexDataManager::storeCurrentValue(
585 const gl::Context *context,
586 const gl::VertexAttribCurrentValueData ¤tValue,
587 TranslatedAttribute *translated,
588 size_t attribIndex)
589 {
590 CurrentValueState *cachedState = &mCurrentValueCache[attribIndex];
591 StreamingVertexBufferInterface &buffer = *cachedState->buffer;
592
593 if (buffer.getBufferSize() == 0)
594 {
595 ANGLE_TRY(buffer.initialize(context, CONSTANT_VERTEX_BUFFER_SIZE));
596 }
597
598 if (cachedState->data != currentValue)
599 {
600 ASSERT(translated->attribute && translated->binding);
601 const auto &attrib = *translated->attribute;
602 const auto &binding = *translated->binding;
603
604 ANGLE_TRY(buffer.reserveVertexSpace(context, attrib, binding, 1, 0, 0));
605
606 const uint8_t *sourceData =
607 reinterpret_cast<const uint8_t *>(currentValue.Values.FloatValues);
608 unsigned int streamOffset;
609 ANGLE_TRY(buffer.storeDynamicAttribute(context, attrib, binding, currentValue.Type, 0, 1, 0,
610 0, &streamOffset, sourceData));
611
612 buffer.getVertexBuffer()->hintUnmapResource();
613
614 cachedState->data = currentValue;
615 cachedState->offset = streamOffset;
616 }
617
618 translated->vertexBuffer.set(buffer.getVertexBuffer());
619
620 translated->storage = nullptr;
621 translated->serial = buffer.getSerial();
622 translated->divisor = 0;
623 translated->stride = 0;
624 translated->baseOffset = static_cast<unsigned int>(cachedState->offset);
625 translated->usesFirstVertexOffset = false;
626
627 return angle::Result::Continue;
628 }
629
630 // VertexBufferBinding implementation
VertexBufferBinding()631 VertexBufferBinding::VertexBufferBinding() : mBoundVertexBuffer(nullptr) {}
632
VertexBufferBinding(const VertexBufferBinding & other)633 VertexBufferBinding::VertexBufferBinding(const VertexBufferBinding &other)
634 : mBoundVertexBuffer(other.mBoundVertexBuffer)
635 {
636 if (mBoundVertexBuffer)
637 {
638 mBoundVertexBuffer->addRef();
639 }
640 }
641
~VertexBufferBinding()642 VertexBufferBinding::~VertexBufferBinding()
643 {
644 if (mBoundVertexBuffer)
645 {
646 mBoundVertexBuffer->release();
647 }
648 }
649
operator =(const VertexBufferBinding & other)650 VertexBufferBinding &VertexBufferBinding::operator=(const VertexBufferBinding &other)
651 {
652 mBoundVertexBuffer = other.mBoundVertexBuffer;
653 if (mBoundVertexBuffer)
654 {
655 mBoundVertexBuffer->addRef();
656 }
657 return *this;
658 }
659
set(VertexBuffer * vertexBuffer)660 void VertexBufferBinding::set(VertexBuffer *vertexBuffer)
661 {
662 if (mBoundVertexBuffer == vertexBuffer)
663 return;
664
665 if (mBoundVertexBuffer)
666 {
667 mBoundVertexBuffer->release();
668 }
669 if (vertexBuffer)
670 {
671 vertexBuffer->addRef();
672 }
673
674 mBoundVertexBuffer = vertexBuffer;
675 }
676
get() const677 VertexBuffer *VertexBufferBinding::get() const
678 {
679 return mBoundVertexBuffer;
680 }
681
682 } // namespace rx
683