Buffer11.cpp (70341B)
1 // 2 // Copyright 2014 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 // Buffer11.cpp Defines the Buffer11 class. 8 9 #include "libANGLE/renderer/d3d/d3d11/Buffer11.h" 10 11 #include <memory> 12 13 #include "common/MemoryBuffer.h" 14 #include "libANGLE/Context.h" 15 #include "libANGLE/renderer/d3d/IndexDataManager.h" 16 #include "libANGLE/renderer/d3d/VertexDataManager.h" 17 #include "libANGLE/renderer/d3d/d3d11/Context11.h" 18 #include "libANGLE/renderer/d3d/d3d11/RenderTarget11.h" 19 #include "libANGLE/renderer/d3d/d3d11/Renderer11.h" 20 #include "libANGLE/renderer/d3d/d3d11/formatutils11.h" 21 #include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" 22 #include "libANGLE/renderer/renderer_utils.h" 23 24 namespace rx 25 { 26 27 namespace 28 { 29 30 template <typename T> 31 GLuint ReadIndexValueFromIndices(const uint8_t *data, size_t index) 32 { 33 return reinterpret_cast<const T *>(data)[index]; 34 } 35 typedef GLuint (*ReadIndexValueFunction)(const uint8_t *data, size_t index); 36 37 enum class CopyResult 38 { 39 RECREATED, 40 NOT_RECREATED, 41 }; 42 43 void CalculateConstantBufferParams(GLintptr offset, 44 GLsizeiptr size, 45 UINT *outFirstConstant, 46 UINT *outNumConstants) 47 { 48 // The offset must be aligned to 256 bytes (should have been enforced by glBindBufferRange). 49 ASSERT(offset % 256 == 0); 50 51 // firstConstant and numConstants are expressed in constants of 16-bytes. Furthermore they must 52 // be a multiple of 16 constants. 53 *outFirstConstant = static_cast<UINT>(offset / 16); 54 55 // The GL size is not required to be aligned to a 256 bytes boundary. 56 // Round the size up to a 256 bytes boundary then express the results in constants of 16-bytes. 57 *outNumConstants = static_cast<UINT>(rx::roundUpPow2(size, static_cast<GLsizeiptr>(256)) / 16); 58 59 // Since the size is rounded up, firstConstant + numConstants may be bigger than the actual size 60 // of the buffer. This behaviour is explictly allowed according to the documentation on 61 // ID3D11DeviceContext1::PSSetConstantBuffers1 62 // https://msdn.microsoft.com/en-us/library/windows/desktop/hh404649%28v=vs.85%29.aspx 63 } 64 65 } // anonymous namespace 66 67 namespace gl_d3d11 68 { 69 70 D3D11_MAP GetD3DMapTypeFromBits(BufferUsage usage, GLbitfield access) 71 { 72 bool readBit = ((access & GL_MAP_READ_BIT) != 0); 73 bool writeBit = ((access & GL_MAP_WRITE_BIT) != 0); 74 75 ASSERT(readBit || writeBit); 76 77 // Note : we ignore the discard bit, because in D3D11, staging buffers 78 // don't accept the map-discard flag (discard only works for DYNAMIC usage) 79 80 if (readBit && !writeBit) 81 { 82 return D3D11_MAP_READ; 83 } 84 else if (writeBit && !readBit) 85 { 86 // Special case for uniform storage - we only allow full buffer updates. 87 return usage == BUFFER_USAGE_UNIFORM || usage == BUFFER_USAGE_STRUCTURED 88 ? D3D11_MAP_WRITE_DISCARD 89 : D3D11_MAP_WRITE; 90 } 91 else if (writeBit && readBit) 92 { 93 return D3D11_MAP_READ_WRITE; 94 } 95 else 96 { 97 UNREACHABLE(); 98 return D3D11_MAP_READ; 99 } 100 } 101 } // namespace gl_d3d11 102 103 // Each instance of Buffer11::BufferStorage is specialized for a class of D3D binding points 104 // - vertex/transform feedback buffers 105 // - index buffers 106 // - pixel unpack buffers 107 // - uniform buffers 108 class Buffer11::BufferStorage : angle::NonCopyable 109 { 110 public: 111 virtual ~BufferStorage() {} 112 113 DataRevision getDataRevision() const { return mRevision; } 114 BufferUsage getUsage() const { return mUsage; } 115 size_t getSize() const { return mBufferSize; } 116 void setDataRevision(DataRevision rev) { mRevision = rev; } 117 118 virtual bool isCPUAccessible(GLbitfield access) const = 0; 119 120 virtual bool isGPUAccessible() const = 0; 121 122 virtual angle::Result copyFromStorage(const gl::Context *context, 123 BufferStorage *source, 124 size_t sourceOffset, 125 size_t size, 126 size_t destOffset, 127 CopyResult *resultOut) = 0; 128 virtual angle::Result resize(const gl::Context *context, size_t size, bool preserveData) = 0; 129 130 virtual angle::Result map(const gl::Context *context, 131 size_t offset, 132 size_t length, 133 GLbitfield access, 134 uint8_t **mapPointerOut) = 0; 135 virtual void unmap() = 0; 136 137 angle::Result setData(const gl::Context *context, 138 const uint8_t *data, 139 size_t offset, 140 size_t size); 141 142 void setStructureByteStride(unsigned int structureByteStride); 143 144 protected: 145 BufferStorage(Renderer11 *renderer, BufferUsage usage); 146 147 Renderer11 *mRenderer; 148 DataRevision mRevision; 149 const BufferUsage mUsage; 150 size_t mBufferSize; 151 }; 152 153 // A native buffer storage represents an underlying D3D11 buffer for a particular 154 // type of storage. 155 class Buffer11::NativeStorage : public Buffer11::BufferStorage 156 { 157 public: 158 NativeStorage(Renderer11 *renderer, BufferUsage usage, const angle::Subject *onStorageChanged); 159 ~NativeStorage() override; 160 161 bool isCPUAccessible(GLbitfield access) const override; 162 163 bool isGPUAccessible() const override { return true; } 164 165 const d3d11::Buffer &getBuffer() const { return mBuffer; } 166 angle::Result copyFromStorage(const gl::Context *context, 167 BufferStorage *source, 168 size_t sourceOffset, 169 size_t size, 170 size_t destOffset, 171 CopyResult *resultOut) override; 172 angle::Result resize(const gl::Context *context, size_t size, bool preserveData) override; 173 174 angle::Result map(const gl::Context *context, 175 size_t offset, 176 size_t length, 177 GLbitfield access, 178 uint8_t **mapPointerOut) override; 179 void unmap() override; 180 181 angle::Result getSRVForFormat(const gl::Context *context, 182 DXGI_FORMAT srvFormat, 183 const d3d11::ShaderResourceView **srvOut); 184 angle::Result getRawUAV(const gl::Context *context, 185 unsigned int offset, 186 unsigned int size, 187 d3d11::UnorderedAccessView **uavOut); 188 189 protected: 190 d3d11::Buffer mBuffer; 191 const angle::Subject *mOnStorageChanged; 192 193 private: 194 static void FillBufferDesc(D3D11_BUFFER_DESC *bufferDesc, 195 Renderer11 *renderer, 196 BufferUsage usage, 197 unsigned int bufferSize); 198 void clearSRVs(); 199 void clearUAVs(); 200 201 std::map<DXGI_FORMAT, d3d11::ShaderResourceView> mBufferResourceViews; 202 std::map<std::pair<unsigned int, unsigned int>, d3d11::UnorderedAccessView> mBufferRawUAVs; 203 }; 204 205 class Buffer11::StructuredBufferStorage : public Buffer11::NativeStorage 206 { 207 public: 208 StructuredBufferStorage(Renderer11 *renderer, 209 BufferUsage usage, 210 const angle::Subject *onStorageChanged); 211 ~StructuredBufferStorage() override; 212 angle::Result resizeStructuredBuffer(const gl::Context *context, 213 unsigned int size, 214 unsigned int structureByteStride); 215 angle::Result getStructuredBufferRangeSRV(const gl::Context *context, 216 unsigned int offset, 217 unsigned int size, 218 unsigned int structureByteStride, 219 const d3d11::ShaderResourceView **bufferOut); 220 221 private: 222 d3d11::ShaderResourceView mStructuredBufferResourceView; 223 }; 224 225 // A emulated indexed buffer storage represents an underlying D3D11 buffer for data 226 // that has been expanded to match the indices list used. This storage is only 227 // used for FL9_3 pointsprite rendering emulation. 228 class Buffer11::EmulatedIndexedStorage : public Buffer11::BufferStorage 229 { 230 public: 231 EmulatedIndexedStorage(Renderer11 *renderer); 232 ~EmulatedIndexedStorage() override; 233 234 bool isCPUAccessible(GLbitfield access) const override { return true; } 235 236 bool isGPUAccessible() const override { return false; } 237 238 angle::Result getBuffer(const gl::Context *context, 239 SourceIndexData *indexInfo, 240 const TranslatedAttribute &attribute, 241 GLint startVertex, 242 const d3d11::Buffer **bufferOut); 243 244 angle::Result copyFromStorage(const gl::Context *context, 245 BufferStorage *source, 246 size_t sourceOffset, 247 size_t size, 248 size_t destOffset, 249 CopyResult *resultOut) override; 250 251 angle::Result resize(const gl::Context *context, size_t size, bool preserveData) override; 252 253 angle::Result map(const gl::Context *context, 254 size_t offset, 255 size_t length, 256 GLbitfield access, 257 uint8_t **mapPointerOut) override; 258 void unmap() override; 259 260 private: 261 d3d11::Buffer mBuffer; // contains expanded data for use by D3D 262 angle::MemoryBuffer mMemoryBuffer; // original data (not expanded) 263 angle::MemoryBuffer mIndicesMemoryBuffer; // indices data 264 }; 265 266 // Pack storage represents internal storage for pack buffers. We implement pack buffers 267 // as CPU memory, tied to a staging texture, for asynchronous texture readback. 268 class Buffer11::PackStorage : public Buffer11::BufferStorage 269 { 270 public: 271 explicit PackStorage(Renderer11 *renderer); 272 ~PackStorage() override; 273 274 bool isCPUAccessible(GLbitfield access) const override { return true; } 275 276 bool isGPUAccessible() const override { return false; } 277 278 angle::Result copyFromStorage(const gl::Context *context, 279 BufferStorage *source, 280 size_t sourceOffset, 281 size_t size, 282 size_t destOffset, 283 CopyResult *resultOut) override; 284 angle::Result resize(const gl::Context *context, size_t size, bool preserveData) override; 285 286 angle::Result map(const gl::Context *context, 287 size_t offset, 288 size_t length, 289 GLbitfield access, 290 uint8_t **mapPointerOut) override; 291 void unmap() override; 292 293 angle::Result packPixels(const gl::Context *context, 294 const gl::FramebufferAttachment &readAttachment, 295 const PackPixelsParams ¶ms); 296 297 private: 298 angle::Result flushQueuedPackCommand(const gl::Context *context); 299 300 TextureHelper11 mStagingTexture; 301 angle::MemoryBuffer mMemoryBuffer; 302 std::unique_ptr<PackPixelsParams> mQueuedPackCommand; 303 PackPixelsParams mPackParams; 304 bool mDataModified; 305 }; 306 307 // System memory storage stores a CPU memory buffer with our buffer data. 308 // For dynamic data, it's much faster to update the CPU memory buffer than 309 // it is to update a D3D staging buffer and read it back later. 310 class Buffer11::SystemMemoryStorage : public Buffer11::BufferStorage 311 { 312 public: 313 explicit SystemMemoryStorage(Renderer11 *renderer); 314 ~SystemMemoryStorage() override {} 315 316 bool isCPUAccessible(GLbitfield access) const override { return true; } 317 318 bool isGPUAccessible() const override { return false; } 319 320 angle::Result copyFromStorage(const gl::Context *context, 321 BufferStorage *source, 322 size_t sourceOffset, 323 size_t size, 324 size_t destOffset, 325 CopyResult *resultOut) override; 326 angle::Result resize(const gl::Context *context, size_t size, bool preserveData) override; 327 328 angle::Result map(const gl::Context *context, 329 size_t offset, 330 size_t length, 331 GLbitfield access, 332 uint8_t **mapPointerOut) override; 333 void unmap() override; 334 335 angle::MemoryBuffer *getSystemCopy() { return &mSystemCopy; } 336 337 protected: 338 angle::MemoryBuffer mSystemCopy; 339 }; 340 341 Buffer11::Buffer11(const gl::BufferState &state, Renderer11 *renderer) 342 : BufferD3D(state, renderer), 343 mRenderer(renderer), 344 mSize(0), 345 mMappedStorage(nullptr), 346 mBufferStorages({}), 347 mLatestBufferStorage(nullptr), 348 mDeallocThresholds({}), 349 mIdleness({}), 350 mConstantBufferStorageAdditionalSize(0), 351 mMaxConstantBufferLruCount(0), 352 mStructuredBufferStorageAdditionalSize(0), 353 mMaxStructuredBufferLruCount(0) 354 {} 355 356 Buffer11::~Buffer11() 357 { 358 for (BufferStorage *&storage : mBufferStorages) 359 { 360 SafeDelete(storage); 361 } 362 363 for (auto &p : mConstantBufferRangeStoragesCache) 364 { 365 SafeDelete(p.second.storage); 366 } 367 368 for (auto &p : mStructuredBufferRangeStoragesCache) 369 { 370 SafeDelete(p.second.storage); 371 } 372 373 mRenderer->onBufferDelete(this); 374 } 375 376 angle::Result Buffer11::setData(const gl::Context *context, 377 gl::BufferBinding target, 378 const void *data, 379 size_t size, 380 gl::BufferUsage usage) 381 { 382 updateD3DBufferUsage(context, usage); 383 return setSubData(context, target, data, size, 0); 384 } 385 386 angle::Result Buffer11::getData(const gl::Context *context, const uint8_t **outData) 387 { 388 if (mSize == 0) 389 { 390 // TODO(http://anglebug.com/2840): This ensures that we don't crash or assert in robust 391 // buffer access behavior mode if there are buffers without any data. However, technically 392 // it should still be possible to draw, with fetches from this buffer returning zero. 393 return angle::Result::Stop; 394 } 395 396 SystemMemoryStorage *systemMemoryStorage = nullptr; 397 ANGLE_TRY(getBufferStorage(context, BUFFER_USAGE_SYSTEM_MEMORY, &systemMemoryStorage)); 398 399 ASSERT(systemMemoryStorage->getSize() >= mSize); 400 401 *outData = systemMemoryStorage->getSystemCopy()->data(); 402 return angle::Result::Continue; 403 } 404 405 angle::Result Buffer11::setSubData(const gl::Context *context, 406 gl::BufferBinding target, 407 const void *data, 408 size_t size, 409 size_t offset) 410 { 411 size_t requiredSize = size + offset; 412 413 if (data && size > 0) 414 { 415 // Use system memory storage for dynamic buffers. 416 // Try using a constant storage for constant buffers 417 BufferStorage *writeBuffer = nullptr; 418 if (target == gl::BufferBinding::Uniform) 419 { 420 // If we are a very large uniform buffer, keep system memory storage around so that we 421 // aren't forced to read back from a constant buffer. We also check the workaround for 422 // Intel - this requires us to use system memory so we don't end up having to copy from 423 // a constant buffer to a staging buffer. 424 // TODO(jmadill): Use Context caps. 425 if (offset == 0 && size >= mSize && 426 size <= static_cast<UINT>(mRenderer->getNativeCaps().maxUniformBlockSize) && 427 !mRenderer->getFeatures().useSystemMemoryForConstantBuffers.enabled) 428 { 429 BufferStorage *latestStorage = nullptr; 430 ANGLE_TRY(getLatestBufferStorage(context, &latestStorage)); 431 if (latestStorage && (latestStorage->getUsage() == BUFFER_USAGE_STRUCTURED)) 432 { 433 ANGLE_TRY(getBufferStorage(context, BUFFER_USAGE_STRUCTURED, &writeBuffer)); 434 } 435 else 436 { 437 ANGLE_TRY(getBufferStorage(context, BUFFER_USAGE_UNIFORM, &writeBuffer)); 438 } 439 } 440 else 441 { 442 ANGLE_TRY(getBufferStorage(context, BUFFER_USAGE_SYSTEM_MEMORY, &writeBuffer)); 443 } 444 } 445 else if (supportsDirectBinding()) 446 { 447 ANGLE_TRY(getStagingStorage(context, &writeBuffer)); 448 } 449 else 450 { 451 ANGLE_TRY(getBufferStorage(context, BUFFER_USAGE_SYSTEM_MEMORY, &writeBuffer)); 452 } 453 454 ASSERT(writeBuffer); 455 456 // Explicitly resize the staging buffer, preserving data if the new data will not 457 // completely fill the buffer 458 if (writeBuffer->getSize() < requiredSize) 459 { 460 bool preserveData = (offset > 0); 461 ANGLE_TRY(writeBuffer->resize(context, requiredSize, preserveData)); 462 } 463 464 ANGLE_TRY(writeBuffer->setData(context, static_cast<const uint8_t *>(data), offset, size)); 465 onStorageUpdate(writeBuffer); 466 } 467 468 mSize = std::max(mSize, requiredSize); 469 invalidateStaticData(context); 470 471 return angle::Result::Continue; 472 } 473 474 angle::Result Buffer11::copySubData(const gl::Context *context, 475 BufferImpl *source, 476 GLintptr sourceOffset, 477 GLintptr destOffset, 478 GLsizeiptr size) 479 { 480 Buffer11 *sourceBuffer = GetAs<Buffer11>(source); 481 ASSERT(sourceBuffer != nullptr); 482 483 BufferStorage *copyDest = nullptr; 484 ANGLE_TRY(getLatestBufferStorage(context, ©Dest)); 485 486 if (!copyDest) 487 { 488 ANGLE_TRY(getStagingStorage(context, ©Dest)); 489 } 490 491 BufferStorage *copySource = nullptr; 492 ANGLE_TRY(sourceBuffer->getLatestBufferStorage(context, ©Source)); 493 494 if (!copySource) 495 { 496 ANGLE_TRY(sourceBuffer->getStagingStorage(context, ©Source)); 497 } 498 499 ASSERT(copySource && copyDest); 500 501 // A staging buffer is needed if there is no cpu-cpu or gpu-gpu copy path avaiable. 502 if (!copyDest->isGPUAccessible() && !copySource->isCPUAccessible(GL_MAP_READ_BIT)) 503 { 504 ANGLE_TRY(sourceBuffer->getStagingStorage(context, ©Source)); 505 } 506 else if (!copySource->isGPUAccessible() && !copyDest->isCPUAccessible(GL_MAP_WRITE_BIT)) 507 { 508 ANGLE_TRY(getStagingStorage(context, ©Dest)); 509 } 510 511 // D3D11 does not allow overlapped copies until 11.1, and only if the 512 // device supports D3D11_FEATURE_DATA_D3D11_OPTIONS::CopyWithOverlap 513 // Get around this via a different source buffer 514 if (copySource == copyDest) 515 { 516 if (copySource->getUsage() == BUFFER_USAGE_STAGING) 517 { 518 ANGLE_TRY( 519 getBufferStorage(context, BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK, ©Source)); 520 } 521 else 522 { 523 ANGLE_TRY(getStagingStorage(context, ©Source)); 524 } 525 } 526 527 CopyResult copyResult = CopyResult::NOT_RECREATED; 528 ANGLE_TRY(copyDest->copyFromStorage(context, copySource, sourceOffset, size, destOffset, 529 ©Result)); 530 onStorageUpdate(copyDest); 531 532 mSize = std::max<size_t>(mSize, destOffset + size); 533 invalidateStaticData(context); 534 535 return angle::Result::Continue; 536 } 537 538 angle::Result Buffer11::map(const gl::Context *context, GLenum access, void **mapPtr) 539 { 540 // GL_OES_mapbuffer uses an enum instead of a bitfield for it's access, convert to a bitfield 541 // and call mapRange. 542 ASSERT(access == GL_WRITE_ONLY_OES); 543 return mapRange(context, 0, mSize, GL_MAP_WRITE_BIT, mapPtr); 544 } 545 546 angle::Result Buffer11::mapRange(const gl::Context *context, 547 size_t offset, 548 size_t length, 549 GLbitfield access, 550 void **mapPtr) 551 { 552 ASSERT(!mMappedStorage); 553 554 BufferStorage *latestStorage = nullptr; 555 ANGLE_TRY(getLatestBufferStorage(context, &latestStorage)); 556 557 if (latestStorage && (latestStorage->getUsage() == BUFFER_USAGE_PIXEL_PACK || 558 latestStorage->getUsage() == BUFFER_USAGE_STAGING)) 559 { 560 // Latest storage is mappable. 561 mMappedStorage = latestStorage; 562 } 563 else 564 { 565 // Fall back to using the staging buffer if the latest storage does not exist or is not 566 // CPU-accessible. 567 ANGLE_TRY(getStagingStorage(context, &mMappedStorage)); 568 } 569 570 Context11 *context11 = GetImplAs<Context11>(context); 571 ANGLE_CHECK_GL_ALLOC(context11, mMappedStorage); 572 573 if ((access & GL_MAP_WRITE_BIT) > 0) 574 { 575 // Update the data revision immediately, since the data might be changed at any time 576 onStorageUpdate(mMappedStorage); 577 invalidateStaticData(context); 578 } 579 580 uint8_t *mappedBuffer = nullptr; 581 ANGLE_TRY(mMappedStorage->map(context, offset, length, access, &mappedBuffer)); 582 ASSERT(mappedBuffer); 583 584 *mapPtr = static_cast<void *>(mappedBuffer); 585 return angle::Result::Continue; 586 } 587 588 angle::Result Buffer11::unmap(const gl::Context *context, GLboolean *result) 589 { 590 ASSERT(mMappedStorage); 591 mMappedStorage->unmap(); 592 mMappedStorage = nullptr; 593 594 // TODO: detect if we had corruption. if so, return false. 595 *result = GL_TRUE; 596 597 return angle::Result::Continue; 598 } 599 600 angle::Result Buffer11::markTransformFeedbackUsage(const gl::Context *context) 601 { 602 ANGLE_TRY(markBufferUsage(context, BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK)); 603 return angle::Result::Continue; 604 } 605 606 void Buffer11::updateDeallocThreshold(BufferUsage usage) 607 { 608 // The following strategy was tuned on the Oort online benchmark (http://oortonline.gl/) 609 // as well as a custom microbenchmark (IndexConversionPerfTest.Run/index_range_d3d11) 610 611 // First readback: 8 unmodified uses before we free buffer memory. 612 // After that, double the threshold each time until we reach the max. 613 if (mDeallocThresholds[usage] == 0) 614 { 615 mDeallocThresholds[usage] = 8; 616 } 617 else if (mDeallocThresholds[usage] < std::numeric_limits<unsigned int>::max() / 2u) 618 { 619 mDeallocThresholds[usage] *= 2u; 620 } 621 else 622 { 623 mDeallocThresholds[usage] = std::numeric_limits<unsigned int>::max(); 624 } 625 } 626 627 // Free the storage if we decide it isn't being used very often. 628 angle::Result Buffer11::checkForDeallocation(const gl::Context *context, BufferUsage usage) 629 { 630 mIdleness[usage]++; 631 632 BufferStorage *&storage = mBufferStorages[usage]; 633 if (storage != nullptr && mIdleness[usage] > mDeallocThresholds[usage]) 634 { 635 BufferStorage *latestStorage = nullptr; 636 ANGLE_TRY(getLatestBufferStorage(context, &latestStorage)); 637 if (latestStorage != storage) 638 { 639 SafeDelete(storage); 640 } 641 } 642 643 return angle::Result::Continue; 644 } 645 646 // Keep system memory when we are using it for the canonical version of data. 647 bool Buffer11::canDeallocateSystemMemory() const 648 { 649 // Must keep system memory on Intel. 650 if (mRenderer->getFeatures().useSystemMemoryForConstantBuffers.enabled) 651 { 652 return false; 653 } 654 655 return (!mBufferStorages[BUFFER_USAGE_UNIFORM] || 656 mSize <= static_cast<size_t>(mRenderer->getNativeCaps().maxUniformBlockSize)); 657 } 658 659 void Buffer11::markBufferUsage(BufferUsage usage) 660 { 661 mIdleness[usage] = 0; 662 } 663 664 angle::Result Buffer11::markBufferUsage(const gl::Context *context, BufferUsage usage) 665 { 666 BufferStorage *bufferStorage = nullptr; 667 ANGLE_TRY(getBufferStorage(context, usage, &bufferStorage)); 668 669 if (bufferStorage) 670 { 671 onStorageUpdate(bufferStorage); 672 } 673 674 invalidateStaticData(context); 675 return angle::Result::Continue; 676 } 677 678 angle::Result Buffer11::garbageCollection(const gl::Context *context, BufferUsage currentUsage) 679 { 680 if (currentUsage != BUFFER_USAGE_SYSTEM_MEMORY && canDeallocateSystemMemory()) 681 { 682 ANGLE_TRY(checkForDeallocation(context, BUFFER_USAGE_SYSTEM_MEMORY)); 683 } 684 685 if (currentUsage != BUFFER_USAGE_STAGING) 686 { 687 ANGLE_TRY(checkForDeallocation(context, BUFFER_USAGE_STAGING)); 688 } 689 690 return angle::Result::Continue; 691 } 692 693 angle::Result Buffer11::getBuffer(const gl::Context *context, 694 BufferUsage usage, 695 ID3D11Buffer **bufferOut) 696 { 697 NativeStorage *storage = nullptr; 698 ANGLE_TRY(getBufferStorage(context, usage, &storage)); 699 *bufferOut = storage->getBuffer().get(); 700 return angle::Result::Continue; 701 } 702 703 angle::Result Buffer11::getEmulatedIndexedBuffer(const gl::Context *context, 704 SourceIndexData *indexInfo, 705 const TranslatedAttribute &attribute, 706 GLint startVertex, 707 ID3D11Buffer **bufferOut) 708 { 709 ASSERT(indexInfo); 710 711 EmulatedIndexedStorage *emulatedStorage = nullptr; 712 ANGLE_TRY(getBufferStorage(context, BUFFER_USAGE_EMULATED_INDEXED_VERTEX, &emulatedStorage)); 713 714 const d3d11::Buffer *nativeBuffer = nullptr; 715 ANGLE_TRY( 716 emulatedStorage->getBuffer(context, indexInfo, attribute, startVertex, &nativeBuffer)); 717 *bufferOut = nativeBuffer->get(); 718 return angle::Result::Continue; 719 } 720 721 angle::Result Buffer11::getConstantBufferRange(const gl::Context *context, 722 GLintptr offset, 723 GLsizeiptr size, 724 const d3d11::Buffer **bufferOut, 725 UINT *firstConstantOut, 726 UINT *numConstantsOut) 727 { 728 NativeStorage *bufferStorage = nullptr; 729 if ((offset == 0 && 730 size < static_cast<GLsizeiptr>(mRenderer->getNativeCaps().maxUniformBlockSize)) || 731 mRenderer->getRenderer11DeviceCaps().supportsConstantBufferOffsets) 732 { 733 ANGLE_TRY(getBufferStorage(context, BUFFER_USAGE_UNIFORM, &bufferStorage)); 734 CalculateConstantBufferParams(offset, size, firstConstantOut, numConstantsOut); 735 } 736 else 737 { 738 ANGLE_TRY(getConstantBufferRangeStorage(context, offset, size, &bufferStorage)); 739 *firstConstantOut = 0; 740 *numConstantsOut = 0; 741 } 742 743 *bufferOut = &bufferStorage->getBuffer(); 744 return angle::Result::Continue; 745 } 746 747 angle::Result Buffer11::markRawBufferUsage(const gl::Context *context) 748 { 749 ANGLE_TRY(markBufferUsage(context, BUFFER_USAGE_RAW_UAV)); 750 return angle::Result::Continue; 751 } 752 753 angle::Result Buffer11::markTypedBufferUsage(const gl::Context *context) 754 { 755 ANGLE_TRY(markBufferUsage(context, BUFFER_USAGE_TYPED_UAV)); 756 return angle::Result::Continue; 757 } 758 759 angle::Result Buffer11::getRawUAVRange(const gl::Context *context, 760 GLintptr offset, 761 GLsizeiptr size, 762 d3d11::UnorderedAccessView **uavOut) 763 { 764 NativeStorage *nativeStorage = nullptr; 765 ANGLE_TRY(getBufferStorage(context, BUFFER_USAGE_RAW_UAV, &nativeStorage)); 766 767 return nativeStorage->getRawUAV(context, static_cast<unsigned int>(offset), 768 static_cast<unsigned int>(size), uavOut); 769 } 770 771 angle::Result Buffer11::getSRV(const gl::Context *context, 772 DXGI_FORMAT srvFormat, 773 const d3d11::ShaderResourceView **srvOut) 774 { 775 NativeStorage *nativeStorage = nullptr; 776 ANGLE_TRY(getBufferStorage(context, BUFFER_USAGE_PIXEL_UNPACK, &nativeStorage)); 777 return nativeStorage->getSRVForFormat(context, srvFormat, srvOut); 778 } 779 780 angle::Result Buffer11::packPixels(const gl::Context *context, 781 const gl::FramebufferAttachment &readAttachment, 782 const PackPixelsParams ¶ms) 783 { 784 PackStorage *packStorage = nullptr; 785 ANGLE_TRY(getBufferStorage(context, BUFFER_USAGE_PIXEL_PACK, &packStorage)); 786 787 ASSERT(packStorage); 788 ANGLE_TRY(packStorage->packPixels(context, readAttachment, params)); 789 onStorageUpdate(packStorage); 790 791 return angle::Result::Continue; 792 } 793 794 size_t Buffer11::getTotalCPUBufferMemoryBytes() const 795 { 796 size_t allocationSize = 0; 797 798 BufferStorage *staging = mBufferStorages[BUFFER_USAGE_STAGING]; 799 allocationSize += staging ? staging->getSize() : 0; 800 801 BufferStorage *sysMem = mBufferStorages[BUFFER_USAGE_SYSTEM_MEMORY]; 802 allocationSize += sysMem ? sysMem->getSize() : 0; 803 804 return allocationSize; 805 } 806 807 template <typename StorageOutT> 808 angle::Result Buffer11::getBufferStorage(const gl::Context *context, 809 BufferUsage usage, 810 StorageOutT **storageOut) 811 { 812 ASSERT(0 <= usage && usage < BUFFER_USAGE_COUNT); 813 BufferStorage *&newStorage = mBufferStorages[usage]; 814 815 if (!newStorage) 816 { 817 newStorage = allocateStorage(usage); 818 } 819 820 markBufferUsage(usage); 821 822 // resize buffer 823 if (newStorage->getSize() < mSize) 824 { 825 ANGLE_TRY(newStorage->resize(context, mSize, true)); 826 } 827 828 ASSERT(newStorage); 829 830 ANGLE_TRY(updateBufferStorage(context, newStorage, 0, mSize)); 831 ANGLE_TRY(garbageCollection(context, usage)); 832 833 *storageOut = GetAs<StorageOutT>(newStorage); 834 return angle::Result::Continue; 835 } 836 837 Buffer11::BufferStorage *Buffer11::allocateStorage(BufferUsage usage) 838 { 839 updateDeallocThreshold(usage); 840 switch (usage) 841 { 842 case BUFFER_USAGE_PIXEL_PACK: 843 return new PackStorage(mRenderer); 844 case BUFFER_USAGE_SYSTEM_MEMORY: 845 return new SystemMemoryStorage(mRenderer); 846 case BUFFER_USAGE_EMULATED_INDEXED_VERTEX: 847 return new EmulatedIndexedStorage(mRenderer); 848 case BUFFER_USAGE_INDEX: 849 case BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK: 850 return new NativeStorage(mRenderer, usage, this); 851 case BUFFER_USAGE_STRUCTURED: 852 return new StructuredBufferStorage(mRenderer, usage, nullptr); 853 default: 854 return new NativeStorage(mRenderer, usage, nullptr); 855 } 856 } 857 858 angle::Result Buffer11::getConstantBufferRangeStorage(const gl::Context *context, 859 GLintptr offset, 860 GLsizeiptr size, 861 Buffer11::NativeStorage **storageOut) 862 { 863 BufferStorage *newStorage; 864 { 865 // Keep the cacheEntry in a limited scope because it may be invalidated later in the code if 866 // we need to reclaim some space. 867 BufferCacheEntry *cacheEntry = &mConstantBufferRangeStoragesCache[offset]; 868 869 if (!cacheEntry->storage) 870 { 871 cacheEntry->storage = allocateStorage(BUFFER_USAGE_UNIFORM); 872 cacheEntry->lruCount = ++mMaxConstantBufferLruCount; 873 } 874 875 cacheEntry->lruCount = ++mMaxConstantBufferLruCount; 876 newStorage = cacheEntry->storage; 877 } 878 879 markBufferUsage(BUFFER_USAGE_UNIFORM); 880 881 if (newStorage->getSize() < static_cast<size_t>(size)) 882 { 883 size_t maximumAllowedAdditionalSize = 2 * getSize(); 884 885 size_t sizeDelta = size - newStorage->getSize(); 886 887 while (mConstantBufferStorageAdditionalSize + sizeDelta > maximumAllowedAdditionalSize) 888 { 889 auto iter = std::min_element( 890 std::begin(mConstantBufferRangeStoragesCache), 891 std::end(mConstantBufferRangeStoragesCache), 892 [](const BufferCache::value_type &a, const BufferCache::value_type &b) { 893 return a.second.lruCount < b.second.lruCount; 894 }); 895 896 ASSERT(iter->second.storage != newStorage); 897 ASSERT(mConstantBufferStorageAdditionalSize >= iter->second.storage->getSize()); 898 899 mConstantBufferStorageAdditionalSize -= iter->second.storage->getSize(); 900 SafeDelete(iter->second.storage); 901 mConstantBufferRangeStoragesCache.erase(iter); 902 } 903 904 ANGLE_TRY(newStorage->resize(context, size, false)); 905 mConstantBufferStorageAdditionalSize += sizeDelta; 906 907 // We don't copy the old data when resizing the constant buffer because the data may be 908 // out-of-date therefore we reset the data revision and let updateBufferStorage() handle the 909 // copy. 910 newStorage->setDataRevision(0); 911 } 912 913 ANGLE_TRY(updateBufferStorage(context, newStorage, offset, size)); 914 ANGLE_TRY(garbageCollection(context, BUFFER_USAGE_UNIFORM)); 915 *storageOut = GetAs<NativeStorage>(newStorage); 916 return angle::Result::Continue; 917 } 918 919 angle::Result Buffer11::getStructuredBufferRangeSRV(const gl::Context *context, 920 unsigned int offset, 921 unsigned int size, 922 unsigned int structureByteStride, 923 const d3d11::ShaderResourceView **srvOut) 924 { 925 BufferStorage *newStorage; 926 927 { 928 // Keep the cacheEntry in a limited scope because it may be invalidated later in the code if 929 // we need to reclaim some space. 930 StructuredBufferKey structuredBufferKey = StructuredBufferKey(offset, structureByteStride); 931 BufferCacheEntry *cacheEntry = &mStructuredBufferRangeStoragesCache[structuredBufferKey]; 932 933 if (!cacheEntry->storage) 934 { 935 cacheEntry->storage = allocateStorage(BUFFER_USAGE_STRUCTURED); 936 cacheEntry->lruCount = ++mMaxStructuredBufferLruCount; 937 } 938 939 cacheEntry->lruCount = ++mMaxStructuredBufferLruCount; 940 newStorage = cacheEntry->storage; 941 } 942 943 StructuredBufferStorage *structuredBufferStorage = GetAs<StructuredBufferStorage>(newStorage); 944 945 markBufferUsage(BUFFER_USAGE_STRUCTURED); 946 947 if (newStorage->getSize() < static_cast<size_t>(size)) 948 { 949 size_t maximumAllowedAdditionalSize = 2 * getSize(); 950 951 size_t sizeDelta = static_cast<size_t>(size) - newStorage->getSize(); 952 953 while (mStructuredBufferStorageAdditionalSize + sizeDelta > maximumAllowedAdditionalSize) 954 { 955 auto iter = std::min_element(std::begin(mStructuredBufferRangeStoragesCache), 956 std::end(mStructuredBufferRangeStoragesCache), 957 [](const StructuredBufferCache::value_type &a, 958 const StructuredBufferCache::value_type &b) { 959 return a.second.lruCount < b.second.lruCount; 960 }); 961 962 ASSERT(iter->second.storage != newStorage); 963 ASSERT(mStructuredBufferStorageAdditionalSize >= iter->second.storage->getSize()); 964 965 mStructuredBufferStorageAdditionalSize -= iter->second.storage->getSize(); 966 SafeDelete(iter->second.storage); 967 mStructuredBufferRangeStoragesCache.erase(iter); 968 } 969 970 ANGLE_TRY( 971 structuredBufferStorage->resizeStructuredBuffer(context, size, structureByteStride)); 972 mStructuredBufferStorageAdditionalSize += sizeDelta; 973 974 // We don't copy the old data when resizing the structured buffer because the data may be 975 // out-of-date therefore we reset the data revision and let updateBufferStorage() handle the 976 // copy. 977 newStorage->setDataRevision(0); 978 } 979 980 ANGLE_TRY(updateBufferStorage(context, newStorage, offset, static_cast<size_t>(size))); 981 ANGLE_TRY(garbageCollection(context, BUFFER_USAGE_STRUCTURED)); 982 ANGLE_TRY(structuredBufferStorage->getStructuredBufferRangeSRV(context, offset, size, 983 structureByteStride, srvOut)); 984 return angle::Result::Continue; 985 } 986 987 angle::Result Buffer11::updateBufferStorage(const gl::Context *context, 988 BufferStorage *storage, 989 size_t sourceOffset, 990 size_t storageSize) 991 { 992 BufferStorage *latestBuffer = nullptr; 993 ANGLE_TRY(getLatestBufferStorage(context, &latestBuffer)); 994 995 ASSERT(storage); 996 997 if (!latestBuffer) 998 { 999 onStorageUpdate(storage); 1000 return angle::Result::Continue; 1001 } 1002 1003 if (latestBuffer->getDataRevision() <= storage->getDataRevision()) 1004 { 1005 return angle::Result::Continue; 1006 } 1007 1008 if (latestBuffer->getSize() == 0 || storage->getSize() == 0) 1009 { 1010 return angle::Result::Continue; 1011 } 1012 1013 // Copy through a staging buffer if we're copying from or to a non-staging, mappable 1014 // buffer storage. This is because we can't map a GPU buffer, and copy CPU 1015 // data directly. If we're already using a staging buffer we're fine. 1016 if (latestBuffer->getUsage() != BUFFER_USAGE_STAGING && 1017 storage->getUsage() != BUFFER_USAGE_STAGING && 1018 (!latestBuffer->isCPUAccessible(GL_MAP_READ_BIT) || 1019 !storage->isCPUAccessible(GL_MAP_WRITE_BIT))) 1020 { 1021 NativeStorage *stagingBuffer = nullptr; 1022 ANGLE_TRY(getStagingStorage(context, &stagingBuffer)); 1023 1024 CopyResult copyResult = CopyResult::NOT_RECREATED; 1025 ANGLE_TRY(stagingBuffer->copyFromStorage(context, latestBuffer, 0, latestBuffer->getSize(), 1026 0, ©Result)); 1027 onCopyStorage(stagingBuffer, latestBuffer); 1028 1029 latestBuffer = stagingBuffer; 1030 } 1031 1032 CopyResult copyResult = CopyResult::NOT_RECREATED; 1033 ANGLE_TRY( 1034 storage->copyFromStorage(context, latestBuffer, sourceOffset, storageSize, 0, ©Result)); 1035 // If the D3D buffer has been recreated, we should update our serial. 1036 if (copyResult == CopyResult::RECREATED) 1037 { 1038 updateSerial(); 1039 } 1040 onCopyStorage(storage, latestBuffer); 1041 return angle::Result::Continue; 1042 } 1043 1044 angle::Result Buffer11::getLatestBufferStorage(const gl::Context *context, 1045 Buffer11::BufferStorage **storageOut) const 1046 { 1047 // resize buffer 1048 if (mLatestBufferStorage && mLatestBufferStorage->getSize() < mSize) 1049 { 1050 ANGLE_TRY(mLatestBufferStorage->resize(context, mSize, true)); 1051 } 1052 1053 *storageOut = mLatestBufferStorage; 1054 return angle::Result::Continue; 1055 } 1056 1057 template <typename StorageOutT> 1058 angle::Result Buffer11::getStagingStorage(const gl::Context *context, StorageOutT **storageOut) 1059 { 1060 return getBufferStorage(context, BUFFER_USAGE_STAGING, storageOut); 1061 } 1062 1063 size_t Buffer11::getSize() const 1064 { 1065 return mSize; 1066 } 1067 1068 bool Buffer11::supportsDirectBinding() const 1069 { 1070 // Do not support direct buffers for dynamic data. The streaming buffer 1071 // offers better performance for data which changes every frame. 1072 return (mUsage == D3DBufferUsage::STATIC); 1073 } 1074 1075 void Buffer11::initializeStaticData(const gl::Context *context) 1076 { 1077 BufferD3D::initializeStaticData(context); 1078 onStateChange(angle::SubjectMessage::SubjectChanged); 1079 } 1080 1081 void Buffer11::invalidateStaticData(const gl::Context *context) 1082 { 1083 BufferD3D::invalidateStaticData(context); 1084 onStateChange(angle::SubjectMessage::SubjectChanged); 1085 } 1086 1087 void Buffer11::onCopyStorage(BufferStorage *dest, BufferStorage *source) 1088 { 1089 ASSERT(source && mLatestBufferStorage); 1090 dest->setDataRevision(source->getDataRevision()); 1091 1092 // Only update the latest buffer storage if our usage index is lower. See comment in header. 1093 if (dest->getUsage() < mLatestBufferStorage->getUsage()) 1094 { 1095 mLatestBufferStorage = dest; 1096 } 1097 } 1098 1099 void Buffer11::onStorageUpdate(BufferStorage *updatedStorage) 1100 { 1101 updatedStorage->setDataRevision(updatedStorage->getDataRevision() + 1); 1102 mLatestBufferStorage = updatedStorage; 1103 } 1104 1105 // Buffer11::BufferStorage implementation 1106 1107 Buffer11::BufferStorage::BufferStorage(Renderer11 *renderer, BufferUsage usage) 1108 : mRenderer(renderer), mRevision(0), mUsage(usage), mBufferSize(0) 1109 {} 1110 1111 angle::Result Buffer11::BufferStorage::setData(const gl::Context *context, 1112 const uint8_t *data, 1113 size_t offset, 1114 size_t size) 1115 { 1116 ASSERT(isCPUAccessible(GL_MAP_WRITE_BIT)); 1117 1118 // Uniform storage can have a different internal size than the buffer size. Ensure we don't 1119 // overflow. 1120 size_t mapSize = std::min(size, mBufferSize - offset); 1121 1122 uint8_t *writePointer = nullptr; 1123 ANGLE_TRY(map(context, offset, mapSize, GL_MAP_WRITE_BIT, &writePointer)); 1124 1125 memcpy(writePointer, data, mapSize); 1126 1127 unmap(); 1128 1129 return angle::Result::Continue; 1130 } 1131 1132 // Buffer11::NativeStorage implementation 1133 1134 Buffer11::NativeStorage::NativeStorage(Renderer11 *renderer, 1135 BufferUsage usage, 1136 const angle::Subject *onStorageChanged) 1137 : BufferStorage(renderer, usage), mBuffer(), mOnStorageChanged(onStorageChanged) 1138 {} 1139 1140 Buffer11::NativeStorage::~NativeStorage() 1141 { 1142 clearSRVs(); 1143 clearUAVs(); 1144 } 1145 1146 bool Buffer11::NativeStorage::isCPUAccessible(GLbitfield access) const 1147 { 1148 if ((access & GL_MAP_READ_BIT) != 0) 1149 { 1150 // Read is more exclusive than write mappability. 1151 return (mUsage == BUFFER_USAGE_STAGING); 1152 } 1153 ASSERT((access & GL_MAP_WRITE_BIT) != 0); 1154 return (mUsage == BUFFER_USAGE_STAGING || mUsage == BUFFER_USAGE_UNIFORM || 1155 mUsage == BUFFER_USAGE_STRUCTURED); 1156 } 1157 1158 // Returns true if it recreates the direct buffer 1159 angle::Result Buffer11::NativeStorage::copyFromStorage(const gl::Context *context, 1160 BufferStorage *source, 1161 size_t sourceOffset, 1162 size_t size, 1163 size_t destOffset, 1164 CopyResult *resultOut) 1165 { 1166 size_t requiredSize = destOffset + size; 1167 1168 // (Re)initialize D3D buffer if needed 1169 bool preserveData = (destOffset > 0); 1170 if (!mBuffer.valid() || mBufferSize < requiredSize) 1171 { 1172 ANGLE_TRY(resize(context, requiredSize, preserveData)); 1173 *resultOut = CopyResult::RECREATED; 1174 } 1175 else 1176 { 1177 *resultOut = CopyResult::NOT_RECREATED; 1178 } 1179 1180 size_t clampedSize = size; 1181 if (mUsage == BUFFER_USAGE_UNIFORM) 1182 { 1183 clampedSize = std::min(clampedSize, mBufferSize - destOffset); 1184 } 1185 1186 if (clampedSize == 0) 1187 { 1188 return angle::Result::Continue; 1189 } 1190 1191 if (source->getUsage() == BUFFER_USAGE_PIXEL_PACK || 1192 source->getUsage() == BUFFER_USAGE_SYSTEM_MEMORY) 1193 { 1194 ASSERT(source->isCPUAccessible(GL_MAP_READ_BIT) && isCPUAccessible(GL_MAP_WRITE_BIT)); 1195 1196 // Uniform buffers must be mapped with write/discard. 1197 ASSERT(!(preserveData && mUsage == BUFFER_USAGE_UNIFORM)); 1198 1199 uint8_t *sourcePointer = nullptr; 1200 ANGLE_TRY(source->map(context, sourceOffset, clampedSize, GL_MAP_READ_BIT, &sourcePointer)); 1201 1202 auto err = setData(context, sourcePointer, destOffset, clampedSize); 1203 source->unmap(); 1204 ANGLE_TRY(err); 1205 } 1206 else 1207 { 1208 D3D11_BOX srcBox; 1209 srcBox.left = static_cast<unsigned int>(sourceOffset); 1210 srcBox.right = static_cast<unsigned int>(sourceOffset + clampedSize); 1211 srcBox.top = 0; 1212 srcBox.bottom = 1; 1213 srcBox.front = 0; 1214 srcBox.back = 1; 1215 1216 const d3d11::Buffer *sourceBuffer = &GetAs<NativeStorage>(source)->getBuffer(); 1217 1218 ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); 1219 deviceContext->CopySubresourceRegion(mBuffer.get(), 0, 1220 static_cast<unsigned int>(destOffset), 0, 0, 1221 sourceBuffer->get(), 0, &srcBox); 1222 } 1223 1224 return angle::Result::Continue; 1225 } 1226 1227 angle::Result Buffer11::NativeStorage::resize(const gl::Context *context, 1228 size_t size, 1229 bool preserveData) 1230 { 1231 if (size == 0) 1232 { 1233 mBuffer.reset(); 1234 mBufferSize = 0; 1235 return angle::Result::Continue; 1236 } 1237 1238 D3D11_BUFFER_DESC bufferDesc; 1239 FillBufferDesc(&bufferDesc, mRenderer, mUsage, static_cast<unsigned int>(size)); 1240 1241 d3d11::Buffer newBuffer; 1242 ANGLE_TRY( 1243 mRenderer->allocateResource(SafeGetImplAs<Context11>(context), bufferDesc, &newBuffer)); 1244 newBuffer.setInternalName("Buffer11::NativeStorage"); 1245 1246 if (mBuffer.valid() && preserveData) 1247 { 1248 // We don't call resize if the buffer is big enough already. 1249 ASSERT(mBufferSize <= size); 1250 1251 D3D11_BOX srcBox; 1252 srcBox.left = 0; 1253 srcBox.right = static_cast<unsigned int>(mBufferSize); 1254 srcBox.top = 0; 1255 srcBox.bottom = 1; 1256 srcBox.front = 0; 1257 srcBox.back = 1; 1258 1259 ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); 1260 deviceContext->CopySubresourceRegion(newBuffer.get(), 0, 0, 0, 0, mBuffer.get(), 0, 1261 &srcBox); 1262 } 1263 1264 // No longer need the old buffer 1265 mBuffer = std::move(newBuffer); 1266 1267 mBufferSize = bufferDesc.ByteWidth; 1268 1269 // Free the SRVs. 1270 clearSRVs(); 1271 1272 // Free the UAVs. 1273 clearUAVs(); 1274 1275 // Notify that the storage has changed. 1276 if (mOnStorageChanged) 1277 { 1278 mOnStorageChanged->onStateChange(angle::SubjectMessage::SubjectChanged); 1279 } 1280 1281 return angle::Result::Continue; 1282 } 1283 1284 // static 1285 void Buffer11::NativeStorage::FillBufferDesc(D3D11_BUFFER_DESC *bufferDesc, 1286 Renderer11 *renderer, 1287 BufferUsage usage, 1288 unsigned int bufferSize) 1289 { 1290 bufferDesc->ByteWidth = bufferSize; 1291 bufferDesc->MiscFlags = 0; 1292 bufferDesc->StructureByteStride = 0; 1293 1294 switch (usage) 1295 { 1296 case BUFFER_USAGE_STAGING: 1297 bufferDesc->Usage = D3D11_USAGE_STAGING; 1298 bufferDesc->BindFlags = 0; 1299 bufferDesc->CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE; 1300 break; 1301 1302 case BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK: 1303 bufferDesc->Usage = D3D11_USAGE_DEFAULT; 1304 bufferDesc->BindFlags = D3D11_BIND_VERTEX_BUFFER; 1305 1306 if (renderer->isES3Capable()) 1307 { 1308 bufferDesc->BindFlags |= D3D11_BIND_STREAM_OUTPUT; 1309 } 1310 1311 bufferDesc->CPUAccessFlags = 0; 1312 break; 1313 1314 case BUFFER_USAGE_INDEX: 1315 bufferDesc->Usage = D3D11_USAGE_DEFAULT; 1316 bufferDesc->BindFlags = D3D11_BIND_INDEX_BUFFER; 1317 bufferDesc->CPUAccessFlags = 0; 1318 break; 1319 1320 case BUFFER_USAGE_INDIRECT: 1321 bufferDesc->MiscFlags = D3D11_RESOURCE_MISC_DRAWINDIRECT_ARGS; 1322 bufferDesc->Usage = D3D11_USAGE_DEFAULT; 1323 bufferDesc->BindFlags = 0; 1324 bufferDesc->CPUAccessFlags = 0; 1325 break; 1326 1327 case BUFFER_USAGE_PIXEL_UNPACK: 1328 bufferDesc->Usage = D3D11_USAGE_DEFAULT; 1329 bufferDesc->BindFlags = D3D11_BIND_SHADER_RESOURCE; 1330 bufferDesc->CPUAccessFlags = 0; 1331 break; 1332 1333 case BUFFER_USAGE_UNIFORM: 1334 bufferDesc->Usage = D3D11_USAGE_DYNAMIC; 1335 bufferDesc->BindFlags = D3D11_BIND_CONSTANT_BUFFER; 1336 bufferDesc->CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; 1337 1338 // Constant buffers must be of a limited size, and aligned to 16 byte boundaries 1339 // For our purposes we ignore any buffer data past the maximum constant buffer size 1340 bufferDesc->ByteWidth = roundUpPow2(bufferDesc->ByteWidth, 16u); 1341 1342 // Note: it seems that D3D11 allows larger buffers on some platforms, but not all. 1343 // (Windows 10 seems to allow larger constant buffers, but not Windows 7) 1344 if (!renderer->getRenderer11DeviceCaps().supportsConstantBufferOffsets) 1345 { 1346 bufferDesc->ByteWidth = std::min<UINT>( 1347 bufferDesc->ByteWidth, 1348 static_cast<UINT>(renderer->getNativeCaps().maxUniformBlockSize)); 1349 } 1350 break; 1351 1352 case BUFFER_USAGE_RAW_UAV: 1353 bufferDesc->MiscFlags = D3D11_RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS; 1354 bufferDesc->BindFlags = D3D11_BIND_UNORDERED_ACCESS; 1355 bufferDesc->Usage = D3D11_USAGE_DEFAULT; 1356 bufferDesc->CPUAccessFlags = 0; 1357 break; 1358 case BUFFER_USAGE_TYPED_UAV: 1359 bufferDesc->BindFlags = D3D11_BIND_UNORDERED_ACCESS | D3D11_BIND_SHADER_RESOURCE; 1360 bufferDesc->Usage = D3D11_USAGE_DEFAULT; 1361 bufferDesc->CPUAccessFlags = 0; 1362 bufferDesc->MiscFlags = 0; 1363 break; 1364 1365 default: 1366 UNREACHABLE(); 1367 } 1368 } 1369 1370 angle::Result Buffer11::NativeStorage::map(const gl::Context *context, 1371 size_t offset, 1372 size_t length, 1373 GLbitfield access, 1374 uint8_t **mapPointerOut) 1375 { 1376 ASSERT(isCPUAccessible(access)); 1377 1378 D3D11_MAPPED_SUBRESOURCE mappedResource; 1379 D3D11_MAP d3dMapType = gl_d3d11::GetD3DMapTypeFromBits(mUsage, access); 1380 UINT d3dMapFlag = ((access & GL_MAP_UNSYNCHRONIZED_BIT) != 0 ? D3D11_MAP_FLAG_DO_NOT_WAIT : 0); 1381 1382 ANGLE_TRY( 1383 mRenderer->mapResource(context, mBuffer.get(), 0, d3dMapType, d3dMapFlag, &mappedResource)); 1384 ASSERT(mappedResource.pData); 1385 *mapPointerOut = static_cast<uint8_t *>(mappedResource.pData) + offset; 1386 return angle::Result::Continue; 1387 } 1388 1389 void Buffer11::NativeStorage::unmap() 1390 { 1391 ASSERT(isCPUAccessible(GL_MAP_WRITE_BIT) || isCPUAccessible(GL_MAP_READ_BIT)); 1392 ID3D11DeviceContext *context = mRenderer->getDeviceContext(); 1393 context->Unmap(mBuffer.get(), 0); 1394 } 1395 1396 angle::Result Buffer11::NativeStorage::getSRVForFormat(const gl::Context *context, 1397 DXGI_FORMAT srvFormat, 1398 const d3d11::ShaderResourceView **srvOut) 1399 { 1400 auto bufferSRVIt = mBufferResourceViews.find(srvFormat); 1401 1402 if (bufferSRVIt != mBufferResourceViews.end()) 1403 { 1404 *srvOut = &bufferSRVIt->second; 1405 return angle::Result::Continue; 1406 } 1407 1408 const d3d11::DXGIFormatSize &dxgiFormatInfo = d3d11::GetDXGIFormatSizeInfo(srvFormat); 1409 1410 D3D11_SHADER_RESOURCE_VIEW_DESC bufferSRVDesc; 1411 bufferSRVDesc.Buffer.ElementOffset = 0; 1412 bufferSRVDesc.Buffer.ElementWidth = static_cast<UINT>(mBufferSize) / dxgiFormatInfo.pixelBytes; 1413 bufferSRVDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER; 1414 bufferSRVDesc.Format = srvFormat; 1415 1416 ANGLE_TRY(mRenderer->allocateResource(GetImplAs<Context11>(context), bufferSRVDesc, 1417 mBuffer.get(), &mBufferResourceViews[srvFormat])); 1418 1419 *srvOut = &mBufferResourceViews[srvFormat]; 1420 return angle::Result::Continue; 1421 } 1422 1423 angle::Result Buffer11::NativeStorage::getRawUAV(const gl::Context *context, 1424 unsigned int offset, 1425 unsigned int size, 1426 d3d11::UnorderedAccessView **uavOut) 1427 { 1428 ASSERT(offset + size <= mBufferSize); 1429 1430 auto bufferRawUAV = mBufferRawUAVs.find({offset, size}); 1431 if (bufferRawUAV != mBufferRawUAVs.end()) 1432 { 1433 *uavOut = &bufferRawUAV->second; 1434 return angle::Result::Continue; 1435 } 1436 1437 D3D11_UNORDERED_ACCESS_VIEW_DESC bufferUAVDesc; 1438 1439 // DXGI_FORMAT_R32_TYPELESS uses 4 bytes per element 1440 constexpr int kBytesToElement = 4; 1441 bufferUAVDesc.Buffer.FirstElement = offset / kBytesToElement; 1442 bufferUAVDesc.Buffer.NumElements = size / kBytesToElement; 1443 bufferUAVDesc.Buffer.Flags = D3D11_BUFFER_UAV_FLAG_RAW; 1444 bufferUAVDesc.Format = DXGI_FORMAT_R32_TYPELESS; // Format must be DXGI_FORMAT_R32_TYPELESS, 1445 // when creating Raw Unordered Access View 1446 bufferUAVDesc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER; 1447 1448 ANGLE_TRY(mRenderer->allocateResource(GetImplAs<Context11>(context), bufferUAVDesc, 1449 mBuffer.get(), &mBufferRawUAVs[{offset, size}])); 1450 *uavOut = &mBufferRawUAVs[{offset, size}]; 1451 return angle::Result::Continue; 1452 } 1453 1454 void Buffer11::NativeStorage::clearSRVs() 1455 { 1456 mBufferResourceViews.clear(); 1457 } 1458 1459 void Buffer11::NativeStorage::clearUAVs() 1460 { 1461 mBufferRawUAVs.clear(); 1462 } 1463 1464 Buffer11::StructuredBufferStorage::StructuredBufferStorage(Renderer11 *renderer, 1465 BufferUsage usage, 1466 const angle::Subject *onStorageChanged) 1467 : NativeStorage(renderer, usage, onStorageChanged), mStructuredBufferResourceView() 1468 {} 1469 1470 Buffer11::StructuredBufferStorage::~StructuredBufferStorage() 1471 { 1472 mStructuredBufferResourceView.reset(); 1473 } 1474 1475 angle::Result Buffer11::StructuredBufferStorage::resizeStructuredBuffer( 1476 const gl::Context *context, 1477 unsigned int size, 1478 unsigned int structureByteStride) 1479 { 1480 if (size == 0) 1481 { 1482 mBuffer.reset(); 1483 mBufferSize = 0; 1484 return angle::Result::Continue; 1485 } 1486 1487 D3D11_BUFFER_DESC bufferDesc; 1488 bufferDesc.ByteWidth = size; 1489 bufferDesc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED; 1490 bufferDesc.StructureByteStride = structureByteStride; 1491 bufferDesc.Usage = D3D11_USAGE_DYNAMIC; 1492 bufferDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE; 1493 bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; 1494 1495 d3d11::Buffer newBuffer; 1496 ANGLE_TRY( 1497 mRenderer->allocateResource(SafeGetImplAs<Context11>(context), bufferDesc, &newBuffer)); 1498 newBuffer.setInternalName("Buffer11::StructuredBufferStorage"); 1499 1500 // No longer need the old buffer 1501 mBuffer = std::move(newBuffer); 1502 1503 mBufferSize = static_cast<size_t>(bufferDesc.ByteWidth); 1504 1505 mStructuredBufferResourceView.reset(); 1506 1507 // Notify that the storage has changed. 1508 if (mOnStorageChanged) 1509 { 1510 mOnStorageChanged->onStateChange(angle::SubjectMessage::SubjectChanged); 1511 } 1512 1513 return angle::Result::Continue; 1514 } 1515 1516 angle::Result Buffer11::StructuredBufferStorage::getStructuredBufferRangeSRV( 1517 const gl::Context *context, 1518 unsigned int offset, 1519 unsigned int size, 1520 unsigned int structureByteStride, 1521 const d3d11::ShaderResourceView **srvOut) 1522 { 1523 if (mStructuredBufferResourceView.valid()) 1524 { 1525 *srvOut = &mStructuredBufferResourceView; 1526 return angle::Result::Continue; 1527 } 1528 1529 D3D11_SHADER_RESOURCE_VIEW_DESC bufferSRVDesc = {}; 1530 bufferSRVDesc.BufferEx.NumElements = structureByteStride == 0u ? 1 : size / structureByteStride; 1531 bufferSRVDesc.BufferEx.FirstElement = 0; 1532 bufferSRVDesc.BufferEx.Flags = 0; 1533 bufferSRVDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFEREX; 1534 bufferSRVDesc.Format = DXGI_FORMAT_UNKNOWN; 1535 1536 ANGLE_TRY(mRenderer->allocateResource(GetImplAs<Context11>(context), bufferSRVDesc, 1537 mBuffer.get(), &mStructuredBufferResourceView)); 1538 1539 *srvOut = &mStructuredBufferResourceView; 1540 return angle::Result::Continue; 1541 } 1542 1543 // Buffer11::EmulatedIndexStorage implementation 1544 Buffer11::EmulatedIndexedStorage::EmulatedIndexedStorage(Renderer11 *renderer) 1545 : BufferStorage(renderer, BUFFER_USAGE_EMULATED_INDEXED_VERTEX), mBuffer() 1546 {} 1547 1548 Buffer11::EmulatedIndexedStorage::~EmulatedIndexedStorage() {} 1549 1550 angle::Result Buffer11::EmulatedIndexedStorage::getBuffer(const gl::Context *context, 1551 SourceIndexData *indexInfo, 1552 const TranslatedAttribute &attribute, 1553 GLint startVertex, 1554 const d3d11::Buffer **bufferOut) 1555 { 1556 Context11 *context11 = GetImplAs<Context11>(context); 1557 1558 // If a change in the indices applied from the last draw call is detected, then the emulated 1559 // indexed buffer needs to be invalidated. After invalidation, the change detected flag should 1560 // be cleared to avoid unnecessary recreation of the buffer. 1561 if (!mBuffer.valid() || indexInfo->srcIndicesChanged) 1562 { 1563 mBuffer.reset(); 1564 1565 // Copy the source index data. This ensures that the lifetime of the indices pointer 1566 // stays with this storage until the next time we invalidate. 1567 size_t indicesDataSize = 0; 1568 switch (indexInfo->srcIndexType) 1569 { 1570 case gl::DrawElementsType::UnsignedInt: 1571 indicesDataSize = sizeof(GLuint) * indexInfo->srcCount; 1572 break; 1573 case gl::DrawElementsType::UnsignedShort: 1574 indicesDataSize = sizeof(GLushort) * indexInfo->srcCount; 1575 break; 1576 case gl::DrawElementsType::UnsignedByte: 1577 indicesDataSize = sizeof(GLubyte) * indexInfo->srcCount; 1578 break; 1579 default: 1580 indicesDataSize = sizeof(GLushort) * indexInfo->srcCount; 1581 break; 1582 } 1583 1584 ANGLE_CHECK_GL_ALLOC(context11, mIndicesMemoryBuffer.resize(indicesDataSize)); 1585 1586 memcpy(mIndicesMemoryBuffer.data(), indexInfo->srcIndices, indicesDataSize); 1587 1588 indexInfo->srcIndicesChanged = false; 1589 } 1590 1591 if (!mBuffer.valid()) 1592 { 1593 unsigned int offset = 0; 1594 ANGLE_TRY(attribute.computeOffset(context, startVertex, &offset)); 1595 1596 // Expand the memory storage upon request and cache the results. 1597 unsigned int expandedDataSize = 1598 static_cast<unsigned int>((indexInfo->srcCount * attribute.stride) + offset); 1599 angle::MemoryBuffer expandedData; 1600 ANGLE_CHECK_GL_ALLOC(context11, expandedData.resize(expandedDataSize)); 1601 1602 // Clear the contents of the allocated buffer 1603 ZeroMemory(expandedData.data(), expandedDataSize); 1604 1605 uint8_t *curr = expandedData.data(); 1606 const uint8_t *ptr = static_cast<const uint8_t *>(indexInfo->srcIndices); 1607 1608 // Ensure that we start in the correct place for the emulated data copy operation to 1609 // maintain offset behaviors. 1610 curr += offset; 1611 1612 ReadIndexValueFunction readIndexValue = ReadIndexValueFromIndices<GLushort>; 1613 1614 switch (indexInfo->srcIndexType) 1615 { 1616 case gl::DrawElementsType::UnsignedInt: 1617 readIndexValue = ReadIndexValueFromIndices<GLuint>; 1618 break; 1619 case gl::DrawElementsType::UnsignedShort: 1620 readIndexValue = ReadIndexValueFromIndices<GLushort>; 1621 break; 1622 case gl::DrawElementsType::UnsignedByte: 1623 readIndexValue = ReadIndexValueFromIndices<GLubyte>; 1624 break; 1625 default: 1626 UNREACHABLE(); 1627 return angle::Result::Stop; 1628 } 1629 1630 // Iterate over the cached index data and copy entries indicated into the emulated buffer. 1631 for (GLuint i = 0; i < indexInfo->srcCount; i++) 1632 { 1633 GLuint idx = readIndexValue(ptr, i); 1634 memcpy(curr, mMemoryBuffer.data() + (attribute.stride * idx), attribute.stride); 1635 curr += attribute.stride; 1636 } 1637 1638 // Finally, initialize the emulated indexed native storage object with the newly copied data 1639 // and free the temporary buffers used. 1640 D3D11_BUFFER_DESC bufferDesc; 1641 bufferDesc.ByteWidth = expandedDataSize; 1642 bufferDesc.MiscFlags = 0; 1643 bufferDesc.StructureByteStride = 0; 1644 bufferDesc.Usage = D3D11_USAGE_DEFAULT; 1645 bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; 1646 bufferDesc.CPUAccessFlags = 0; 1647 1648 D3D11_SUBRESOURCE_DATA subResourceData = {expandedData.data(), 0, 0}; 1649 1650 ANGLE_TRY(mRenderer->allocateResource(GetImplAs<Context11>(context), bufferDesc, 1651 &subResourceData, &mBuffer)); 1652 mBuffer.setInternalName("Buffer11::EmulatedIndexedStorage"); 1653 } 1654 1655 *bufferOut = &mBuffer; 1656 return angle::Result::Continue; 1657 } 1658 1659 angle::Result Buffer11::EmulatedIndexedStorage::copyFromStorage(const gl::Context *context, 1660 BufferStorage *source, 1661 size_t sourceOffset, 1662 size_t size, 1663 size_t destOffset, 1664 CopyResult *resultOut) 1665 { 1666 ASSERT(source->isCPUAccessible(GL_MAP_READ_BIT)); 1667 uint8_t *sourceData = nullptr; 1668 ANGLE_TRY(source->map(context, sourceOffset, size, GL_MAP_READ_BIT, &sourceData)); 1669 ASSERT(destOffset + size <= mMemoryBuffer.size()); 1670 memcpy(mMemoryBuffer.data() + destOffset, sourceData, size); 1671 source->unmap(); 1672 *resultOut = CopyResult::RECREATED; 1673 return angle::Result::Continue; 1674 } 1675 1676 angle::Result Buffer11::EmulatedIndexedStorage::resize(const gl::Context *context, 1677 size_t size, 1678 bool preserveData) 1679 { 1680 if (mMemoryBuffer.size() < size) 1681 { 1682 Context11 *context11 = GetImplAs<Context11>(context); 1683 ANGLE_CHECK_GL_ALLOC(context11, mMemoryBuffer.resize(size)); 1684 mBufferSize = size; 1685 } 1686 1687 return angle::Result::Continue; 1688 } 1689 1690 angle::Result Buffer11::EmulatedIndexedStorage::map(const gl::Context *context, 1691 size_t offset, 1692 size_t length, 1693 GLbitfield access, 1694 uint8_t **mapPointerOut) 1695 { 1696 ASSERT(!mMemoryBuffer.empty() && offset + length <= mMemoryBuffer.size()); 1697 *mapPointerOut = mMemoryBuffer.data() + offset; 1698 return angle::Result::Continue; 1699 } 1700 1701 void Buffer11::EmulatedIndexedStorage::unmap() 1702 { 1703 // No-op 1704 } 1705 1706 // Buffer11::PackStorage implementation 1707 1708 Buffer11::PackStorage::PackStorage(Renderer11 *renderer) 1709 : BufferStorage(renderer, BUFFER_USAGE_PIXEL_PACK), mStagingTexture(), mDataModified(false) 1710 {} 1711 1712 Buffer11::PackStorage::~PackStorage() {} 1713 1714 angle::Result Buffer11::PackStorage::copyFromStorage(const gl::Context *context, 1715 BufferStorage *source, 1716 size_t sourceOffset, 1717 size_t size, 1718 size_t destOffset, 1719 CopyResult *resultOut) 1720 { 1721 ANGLE_TRY(flushQueuedPackCommand(context)); 1722 1723 // For all use cases of pack buffers, we must copy through a readable buffer. 1724 ASSERT(source->isCPUAccessible(GL_MAP_READ_BIT)); 1725 uint8_t *sourceData = nullptr; 1726 ANGLE_TRY(source->map(context, sourceOffset, size, GL_MAP_READ_BIT, &sourceData)); 1727 ASSERT(destOffset + size <= mMemoryBuffer.size()); 1728 memcpy(mMemoryBuffer.data() + destOffset, sourceData, size); 1729 source->unmap(); 1730 *resultOut = CopyResult::NOT_RECREATED; 1731 return angle::Result::Continue; 1732 } 1733 1734 angle::Result Buffer11::PackStorage::resize(const gl::Context *context, 1735 size_t size, 1736 bool preserveData) 1737 { 1738 if (size != mBufferSize) 1739 { 1740 Context11 *context11 = GetImplAs<Context11>(context); 1741 ANGLE_CHECK_GL_ALLOC(context11, mMemoryBuffer.resize(size)); 1742 mBufferSize = size; 1743 } 1744 1745 return angle::Result::Continue; 1746 } 1747 1748 angle::Result Buffer11::PackStorage::map(const gl::Context *context, 1749 size_t offset, 1750 size_t length, 1751 GLbitfield access, 1752 uint8_t **mapPointerOut) 1753 { 1754 ASSERT(offset + length <= getSize()); 1755 // TODO: fast path 1756 // We might be able to optimize out one or more memcpy calls by detecting when 1757 // and if D3D packs the staging texture memory identically to how we would fill 1758 // the pack buffer according to the current pack state. 1759 1760 ANGLE_TRY(flushQueuedPackCommand(context)); 1761 1762 mDataModified = (mDataModified || (access & GL_MAP_WRITE_BIT) != 0); 1763 1764 *mapPointerOut = mMemoryBuffer.data() + offset; 1765 return angle::Result::Continue; 1766 } 1767 1768 void Buffer11::PackStorage::unmap() 1769 { 1770 // No-op 1771 } 1772 1773 angle::Result Buffer11::PackStorage::packPixels(const gl::Context *context, 1774 const gl::FramebufferAttachment &readAttachment, 1775 const PackPixelsParams ¶ms) 1776 { 1777 ANGLE_TRY(flushQueuedPackCommand(context)); 1778 1779 RenderTarget11 *renderTarget = nullptr; 1780 ANGLE_TRY(readAttachment.getRenderTarget(context, 0, &renderTarget)); 1781 1782 const TextureHelper11 &srcTexture = renderTarget->getTexture(); 1783 ASSERT(srcTexture.valid()); 1784 unsigned int srcSubresource = renderTarget->getSubresourceIndex(); 1785 1786 mQueuedPackCommand.reset(new PackPixelsParams(params)); 1787 1788 gl::Extents srcTextureSize(params.area.width, params.area.height, 1); 1789 if (!mStagingTexture.get() || mStagingTexture.getFormat() != srcTexture.getFormat() || 1790 mStagingTexture.getExtents() != srcTextureSize) 1791 { 1792 ANGLE_TRY(mRenderer->createStagingTexture(context, srcTexture.getTextureType(), 1793 srcTexture.getFormatSet(), srcTextureSize, 1794 StagingAccess::READ, &mStagingTexture)); 1795 } 1796 1797 // ReadPixels from multisampled FBOs isn't supported in current GL 1798 ASSERT(srcTexture.getSampleCount() <= 1); 1799 1800 ID3D11DeviceContext *immediateContext = mRenderer->getDeviceContext(); 1801 D3D11_BOX srcBox; 1802 srcBox.left = params.area.x; 1803 srcBox.right = params.area.x + params.area.width; 1804 srcBox.top = params.area.y; 1805 srcBox.bottom = params.area.y + params.area.height; 1806 1807 // Select the correct layer from a 3D attachment 1808 srcBox.front = 0; 1809 if (mStagingTexture.is3D()) 1810 { 1811 srcBox.front = static_cast<UINT>(readAttachment.layer()); 1812 } 1813 srcBox.back = srcBox.front + 1; 1814 1815 // Asynchronous copy 1816 immediateContext->CopySubresourceRegion(mStagingTexture.get(), 0, 0, 0, 0, srcTexture.get(), 1817 srcSubresource, &srcBox); 1818 1819 return angle::Result::Continue; 1820 } 1821 1822 angle::Result Buffer11::PackStorage::flushQueuedPackCommand(const gl::Context *context) 1823 { 1824 ASSERT(mMemoryBuffer.size() > 0); 1825 1826 if (mQueuedPackCommand) 1827 { 1828 ANGLE_TRY(mRenderer->packPixels(context, mStagingTexture, *mQueuedPackCommand, 1829 mMemoryBuffer.data())); 1830 mQueuedPackCommand.reset(nullptr); 1831 } 1832 1833 return angle::Result::Continue; 1834 } 1835 1836 // Buffer11::SystemMemoryStorage implementation 1837 1838 Buffer11::SystemMemoryStorage::SystemMemoryStorage(Renderer11 *renderer) 1839 : Buffer11::BufferStorage(renderer, BUFFER_USAGE_SYSTEM_MEMORY) 1840 {} 1841 1842 angle::Result Buffer11::SystemMemoryStorage::copyFromStorage(const gl::Context *context, 1843 BufferStorage *source, 1844 size_t sourceOffset, 1845 size_t size, 1846 size_t destOffset, 1847 CopyResult *resultOut) 1848 { 1849 ASSERT(source->isCPUAccessible(GL_MAP_READ_BIT)); 1850 uint8_t *sourceData = nullptr; 1851 ANGLE_TRY(source->map(context, sourceOffset, size, GL_MAP_READ_BIT, &sourceData)); 1852 ASSERT(destOffset + size <= mSystemCopy.size()); 1853 memcpy(mSystemCopy.data() + destOffset, sourceData, size); 1854 source->unmap(); 1855 *resultOut = CopyResult::RECREATED; 1856 return angle::Result::Continue; 1857 } 1858 1859 angle::Result Buffer11::SystemMemoryStorage::resize(const gl::Context *context, 1860 size_t size, 1861 bool preserveData) 1862 { 1863 if (mSystemCopy.size() < size) 1864 { 1865 Context11 *context11 = GetImplAs<Context11>(context); 1866 ANGLE_CHECK_GL_ALLOC(context11, mSystemCopy.resize(size)); 1867 mBufferSize = size; 1868 } 1869 1870 return angle::Result::Continue; 1871 } 1872 1873 angle::Result Buffer11::SystemMemoryStorage::map(const gl::Context *context, 1874 size_t offset, 1875 size_t length, 1876 GLbitfield access, 1877 uint8_t **mapPointerOut) 1878 { 1879 ASSERT(!mSystemCopy.empty() && offset + length <= mSystemCopy.size()); 1880 *mapPointerOut = mSystemCopy.data() + offset; 1881 return angle::Result::Continue; 1882 } 1883 1884 void Buffer11::SystemMemoryStorage::unmap() 1885 { 1886 // No-op 1887 } 1888 } // namespace rx