VertexDataManager.cpp (24631B)
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. 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. 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. 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 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 143 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. 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 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 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 218 VertexDataManager::CurrentValueState::~CurrentValueState() {} 219 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 230 VertexDataManager::~VertexDataManager() {} 231 232 angle::Result VertexDataManager::initialize(const gl::Context *context) 233 { 234 return mStreamingBuffer.initialize(context, INITIAL_STREAM_BUFFER_SIZE); 235 } 236 237 void VertexDataManager::deinitialize() 238 { 239 mStreamingBuffer.reset(); 240 mCurrentValueCache.clear(); 241 } 242 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 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 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 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 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 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 size_t totalCount = gl::ComputeVertexBindingElementCount(binding.getDivisor(), count, 502 static_cast<size_t>(instances)); 503 // TODO(jiajia.qin@intel.com): force the index buffer to clamp any out of range indices instead 504 // of invalid operation here. 505 if (bufferD3D) 506 { 507 // Vertices do not apply the 'start' offset when the divisor is non-zero even when doing 508 // a non-instanced draw call 509 GLint firstVertexIndex = binding.getDivisor() > 0 510 ? UnsignedCeilDivide(baseInstance, binding.getDivisor()) 511 : start; 512 int64_t maxVertexCount = 513 static_cast<int64_t>(firstVertexIndex) + static_cast<int64_t>(totalCount); 514 515 int64_t maxByte = GetMaxAttributeByteOffsetForDraw(attrib, binding, maxVertexCount); 516 517 ASSERT(bufferD3D->getSize() <= static_cast<size_t>(std::numeric_limits<int64_t>::max())); 518 ANGLE_CHECK(GetImplAs<ContextD3D>(context), 519 maxByte <= static_cast<int64_t>(bufferD3D->getSize()), 520 "Vertex buffer is not big enough for the draw call.", GL_INVALID_OPERATION); 521 } 522 return mStreamingBuffer.reserveVertexSpace(context, attrib, binding, totalCount, instances, 523 baseInstance); 524 } 525 526 angle::Result VertexDataManager::storeDynamicAttrib(const gl::Context *context, 527 TranslatedAttribute *translated, 528 GLint start, 529 size_t count, 530 GLsizei instances, 531 GLuint baseInstance) 532 { 533 ASSERT(translated->attribute && translated->binding); 534 const auto &attrib = *translated->attribute; 535 const auto &binding = *translated->binding; 536 537 gl::Buffer *buffer = binding.getBuffer().get(); 538 ASSERT(buffer || attrib.pointer); 539 ASSERT(attrib.enabled); 540 541 BufferD3D *storage = buffer ? GetImplAs<BufferD3D>(buffer) : nullptr; 542 543 // Instanced vertices do not apply the 'start' offset 544 GLint firstVertexIndex = 545 (binding.getDivisor() > 0 ? UnsignedCeilDivide(baseInstance, binding.getDivisor()) : start); 546 547 // Compute source data pointer 548 const uint8_t *sourceData = nullptr; 549 550 if (buffer) 551 { 552 ANGLE_TRY(storage->getData(context, &sourceData)); 553 sourceData += static_cast<int>(ComputeVertexAttributeOffset(attrib, binding)); 554 } 555 else 556 { 557 // Attributes using client memory ignore the VERTEX_ATTRIB_BINDING state. 558 // https://www.opengl.org/registry/specs/ARB/vertex_attrib_binding.txt 559 sourceData = static_cast<const uint8_t *>(attrib.pointer); 560 } 561 562 unsigned int streamOffset = 0; 563 564 translated->storage = nullptr; 565 ANGLE_TRY( 566 mFactory->getVertexSpaceRequired(context, attrib, binding, 1, 0, 0, &translated->stride)); 567 568 size_t totalCount = gl::ComputeVertexBindingElementCount(binding.getDivisor(), count, 569 static_cast<size_t>(instances)); 570 571 ANGLE_TRY(mStreamingBuffer.storeDynamicAttribute( 572 context, attrib, binding, translated->currentValueType, firstVertexIndex, 573 static_cast<GLsizei>(totalCount), instances, baseInstance, &streamOffset, sourceData)); 574 575 VertexBuffer *vertexBuffer = mStreamingBuffer.getVertexBuffer(); 576 577 translated->vertexBuffer.set(vertexBuffer); 578 translated->serial = vertexBuffer->getSerial(); 579 translated->baseOffset = streamOffset; 580 translated->usesFirstVertexOffset = false; 581 582 return angle::Result::Continue; 583 } 584 585 angle::Result VertexDataManager::storeCurrentValue( 586 const gl::Context *context, 587 const gl::VertexAttribCurrentValueData ¤tValue, 588 TranslatedAttribute *translated, 589 size_t attribIndex) 590 { 591 CurrentValueState *cachedState = &mCurrentValueCache[attribIndex]; 592 StreamingVertexBufferInterface &buffer = *cachedState->buffer; 593 594 if (buffer.getBufferSize() == 0) 595 { 596 ANGLE_TRY(buffer.initialize(context, CONSTANT_VERTEX_BUFFER_SIZE)); 597 } 598 599 if (cachedState->data != currentValue) 600 { 601 ASSERT(translated->attribute && translated->binding); 602 const auto &attrib = *translated->attribute; 603 const auto &binding = *translated->binding; 604 605 ANGLE_TRY(buffer.reserveVertexSpace(context, attrib, binding, 1, 0, 0)); 606 607 const uint8_t *sourceData = 608 reinterpret_cast<const uint8_t *>(currentValue.Values.FloatValues); 609 unsigned int streamOffset; 610 ANGLE_TRY(buffer.storeDynamicAttribute(context, attrib, binding, currentValue.Type, 0, 1, 0, 611 0, &streamOffset, sourceData)); 612 613 buffer.getVertexBuffer()->hintUnmapResource(); 614 615 cachedState->data = currentValue; 616 cachedState->offset = streamOffset; 617 } 618 619 translated->vertexBuffer.set(buffer.getVertexBuffer()); 620 621 translated->storage = nullptr; 622 translated->serial = buffer.getSerial(); 623 translated->divisor = 0; 624 translated->stride = 0; 625 translated->baseOffset = static_cast<unsigned int>(cachedState->offset); 626 translated->usesFirstVertexOffset = false; 627 628 return angle::Result::Continue; 629 } 630 631 // VertexBufferBinding implementation 632 VertexBufferBinding::VertexBufferBinding() : mBoundVertexBuffer(nullptr) {} 633 634 VertexBufferBinding::VertexBufferBinding(const VertexBufferBinding &other) 635 : mBoundVertexBuffer(other.mBoundVertexBuffer) 636 { 637 if (mBoundVertexBuffer) 638 { 639 mBoundVertexBuffer->addRef(); 640 } 641 } 642 643 VertexBufferBinding::~VertexBufferBinding() 644 { 645 if (mBoundVertexBuffer) 646 { 647 mBoundVertexBuffer->release(); 648 } 649 } 650 651 VertexBufferBinding &VertexBufferBinding::operator=(const VertexBufferBinding &other) 652 { 653 mBoundVertexBuffer = other.mBoundVertexBuffer; 654 if (mBoundVertexBuffer) 655 { 656 mBoundVertexBuffer->addRef(); 657 } 658 return *this; 659 } 660 661 void VertexBufferBinding::set(VertexBuffer *vertexBuffer) 662 { 663 if (mBoundVertexBuffer == vertexBuffer) 664 return; 665 666 if (mBoundVertexBuffer) 667 { 668 mBoundVertexBuffer->release(); 669 } 670 if (vertexBuffer) 671 { 672 vertexBuffer->addRef(); 673 } 674 675 mBoundVertexBuffer = vertexBuffer; 676 } 677 678 VertexBuffer *VertexBufferBinding::get() const 679 { 680 return mBoundVertexBuffer; 681 } 682 683 } // namespace rx