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 "libGLESv2/renderer/d3d/d3d11/Buffer11.h" 10 #include "libGLESv2/renderer/d3d/d3d11/Renderer11.h" 11 #include "libGLESv2/renderer/d3d/d3d11/formatutils11.h" 12 #include "libGLESv2/main.h" 13 14 namespace rx 15 { 16 17 PackPixelsParams::PackPixelsParams() 18 : format(GL_NONE), 19 type(GL_NONE), 20 outputPitch(0), 21 packBuffer(NULL), 22 offset(0) 23 {} 24 25 PackPixelsParams::PackPixelsParams(const gl::Rectangle &areaIn, GLenum formatIn, GLenum typeIn, GLuint outputPitchIn, 26 const gl::PixelPackState &packIn, ptrdiff_t offsetIn) 27 : area(areaIn), 28 format(formatIn), 29 type(typeIn), 30 outputPitch(outputPitchIn), 31 packBuffer(packIn.pixelBuffer.get()), 32 pack(packIn.alignment, packIn.reverseRowOrder), 33 offset(offsetIn) 34 {} 35 36 namespace gl_d3d11 37 { 38 39 D3D11_MAP GetD3DMapTypeFromBits(GLbitfield access) 40 { 41 bool readBit = ((access & GL_MAP_READ_BIT) != 0); 42 bool writeBit = ((access & GL_MAP_WRITE_BIT) != 0); 43 44 ASSERT(readBit || writeBit); 45 46 // Note : we ignore the discard bit, because in D3D11, staging buffers 47 // don't accept the map-discard flag (discard only works for DYNAMIC usage) 48 49 if (readBit && !writeBit) 50 { 51 return D3D11_MAP_READ; 52 } 53 else if (writeBit && !readBit) 54 { 55 return D3D11_MAP_WRITE; 56 } 57 else if (writeBit && readBit) 58 { 59 return D3D11_MAP_READ_WRITE; 60 } 61 else 62 { 63 UNREACHABLE(); 64 return D3D11_MAP_READ; 65 } 66 } 67 68 } 69 70 // Each instance of Buffer11::BufferStorage11 is specialized for a class of D3D binding points 71 // - vertex/transform feedback buffers 72 // - index buffers 73 // - pixel unpack buffers 74 // - uniform buffers 75 class Buffer11::BufferStorage11 76 { 77 public: 78 virtual ~BufferStorage11() {} 79 80 DataRevision getDataRevision() const { return mRevision; } 81 BufferUsage getUsage() const { return mUsage; } 82 size_t getSize() const { return mBufferSize; } 83 bool isMappable() const { return (mUsage == BUFFER_USAGE_STAGING || mUsage == BUFFER_USAGE_PIXEL_PACK); } 84 85 void setDataRevision(DataRevision rev) { mRevision = rev; } 86 87 virtual bool copyFromStorage(BufferStorage11 *source, size_t sourceOffset, 88 size_t size, size_t destOffset) = 0; 89 virtual bool resize(size_t size, bool preserveData) = 0; 90 91 virtual void *map(size_t offset, size_t length, GLbitfield access) = 0; 92 virtual void unmap() = 0; 93 94 protected: 95 BufferStorage11(Renderer11 *renderer, BufferUsage usage); 96 97 Renderer11 *mRenderer; 98 DataRevision mRevision; 99 const BufferUsage mUsage; 100 size_t mBufferSize; 101 }; 102 103 // A native buffer storage represents an underlying D3D11 buffer for a particular 104 // type of storage. 105 class Buffer11::NativeBuffer11 : public Buffer11::BufferStorage11 106 { 107 public: 108 NativeBuffer11(Renderer11 *renderer, BufferUsage usage); 109 ~NativeBuffer11(); 110 111 ID3D11Buffer *getNativeBuffer() const { return mNativeBuffer; } 112 113 virtual bool copyFromStorage(BufferStorage11 *source, size_t sourceOffset, 114 size_t size, size_t destOffset); 115 virtual bool resize(size_t size, bool preserveData); 116 117 virtual void *map(size_t offset, size_t length, GLbitfield access); 118 virtual void unmap(); 119 120 bool setData(D3D11_MAP mapMode, const uint8_t *data, size_t size, size_t offset); 121 122 private: 123 ID3D11Buffer *mNativeBuffer; 124 125 static void fillBufferDesc(D3D11_BUFFER_DESC* bufferDesc, Renderer *renderer, BufferUsage usage, unsigned int bufferSize); 126 }; 127 128 // Pack storage represents internal storage for pack buffers. We implement pack buffers 129 // as CPU memory, tied to a staging texture, for asynchronous texture readback. 130 class Buffer11::PackStorage11 : public Buffer11::BufferStorage11 131 { 132 public: 133 PackStorage11(Renderer11 *renderer); 134 ~PackStorage11(); 135 136 virtual bool copyFromStorage(BufferStorage11 *source, size_t sourceOffset, 137 size_t size, size_t destOffset); 138 virtual bool resize(size_t size, bool preserveData); 139 140 virtual void *map(size_t offset, size_t length, GLbitfield access); 141 virtual void unmap(); 142 143 gl::Error packPixels(ID3D11Texture2D *srcTexure, UINT srcSubresource, const PackPixelsParams ¶ms); 144 145 private: 146 147 void flushQueuedPackCommand(); 148 149 ID3D11Texture2D *mStagingTexture; 150 DXGI_FORMAT mTextureFormat; 151 gl::Extents mTextureSize; 152 MemoryBuffer mMemoryBuffer; 153 PackPixelsParams *mQueuedPackCommand; 154 PackPixelsParams mPackParams; 155 bool mDataModified; 156 }; 157 158 159 Buffer11::Buffer11(Renderer11 *renderer) 160 : BufferD3D(), 161 mRenderer(renderer), 162 mSize(0), 163 mMappedStorage(NULL), 164 mResolvedDataRevision(0), 165 mReadUsageCount(0) 166 {} 167 168 Buffer11::~Buffer11() 169 { 170 for (auto it = mBufferStorages.begin(); it != mBufferStorages.end(); it++) 171 { 172 SafeDelete(it->second); 173 } 174 } 175 176 Buffer11 *Buffer11::makeBuffer11(BufferImpl *buffer) 177 { 178 ASSERT(HAS_DYNAMIC_TYPE(Buffer11*, buffer)); 179 return static_cast<Buffer11*>(buffer); 180 } 181 182 gl::Error Buffer11::setData(const void *data, size_t size, GLenum usage) 183 { 184 gl::Error error = setSubData(data, size, 0); 185 if (error.isError()) 186 { 187 return error; 188 } 189 190 if (usage == GL_STATIC_DRAW) 191 { 192 initializeStaticData(); 193 } 194 195 return error; 196 } 197 198 void *Buffer11::getData() 199 { 200 NativeBuffer11 *stagingBuffer = getStagingBuffer(); 201 202 if (!stagingBuffer) 203 { 204 // Out-of-memory 205 return NULL; 206 } 207 208 if (stagingBuffer->getDataRevision() > mResolvedDataRevision) 209 { 210 if (stagingBuffer->getSize() > mResolvedData.size()) 211 { 212 if (!mResolvedData.resize(stagingBuffer->getSize())) 213 { 214 return gl::error(GL_OUT_OF_MEMORY, (void*)NULL); 215 } 216 } 217 218 ID3D11DeviceContext *context = mRenderer->getDeviceContext(); 219 220 D3D11_MAPPED_SUBRESOURCE mappedResource; 221 HRESULT result = context->Map(stagingBuffer->getNativeBuffer(), 0, D3D11_MAP_READ, 0, &mappedResource); 222 if (FAILED(result)) 223 { 224 return gl::error(GL_OUT_OF_MEMORY, (void*)NULL); 225 } 226 227 memcpy(mResolvedData.data(), mappedResource.pData, stagingBuffer->getSize()); 228 229 context->Unmap(stagingBuffer->getNativeBuffer(), 0); 230 231 mResolvedDataRevision = stagingBuffer->getDataRevision(); 232 } 233 234 mReadUsageCount = 0; 235 236 // Only happens if we initialized the buffer with no data (NULL) 237 if (mResolvedData.empty()) 238 { 239 if (!mResolvedData.resize(mSize)) 240 { 241 return gl::error(GL_OUT_OF_MEMORY, (void*)NULL); 242 } 243 } 244 245 ASSERT(mResolvedData.size() >= mSize); 246 247 return mResolvedData.data(); 248 } 249 250 gl::Error Buffer11::setSubData(const void *data, size_t size, size_t offset) 251 { 252 size_t requiredSize = size + offset; 253 254 if (data && size > 0) 255 { 256 NativeBuffer11 *stagingBuffer = getStagingBuffer(); 257 258 if (!stagingBuffer) 259 { 260 return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal staging buffer."); 261 } 262 263 // Explicitly resize the staging buffer, preserving data if the new data will not 264 // completely fill the buffer 265 if (stagingBuffer->getSize() < requiredSize) 266 { 267 bool preserveData = (offset > 0); 268 if (!stagingBuffer->resize(requiredSize, preserveData)) 269 { 270 return gl::Error(GL_OUT_OF_MEMORY, "Failed to resize internal staging buffer."); 271 } 272 } 273 274 if (!stagingBuffer->setData(D3D11_MAP_WRITE, reinterpret_cast<const uint8_t *>(data), size, offset)) 275 { 276 return gl::Error(GL_OUT_OF_MEMORY, "Failed to set data on internal staging buffer."); 277 } 278 279 stagingBuffer->setDataRevision(stagingBuffer->getDataRevision() + 1); 280 } 281 282 mSize = std::max(mSize, requiredSize); 283 invalidateStaticData(); 284 285 return gl::Error(GL_NO_ERROR); 286 } 287 288 gl::Error Buffer11::copySubData(BufferImpl* source, GLintptr sourceOffset, GLintptr destOffset, GLsizeiptr size) 289 { 290 Buffer11 *sourceBuffer = makeBuffer11(source); 291 ASSERT(sourceBuffer != NULL); 292 293 BufferStorage11 *copyDest = getLatestBufferStorage(); 294 if (!copyDest) 295 { 296 copyDest = getStagingBuffer(); 297 } 298 299 BufferStorage11 *copySource = sourceBuffer->getLatestBufferStorage(); 300 301 if (!copySource || !copyDest) 302 { 303 return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal staging buffer."); 304 } 305 306 // If copying to/from a pixel pack buffer, we must have a staging or 307 // pack buffer partner, because other native buffers can't be mapped 308 if (copyDest->getUsage() == BUFFER_USAGE_PIXEL_PACK && !copySource->isMappable()) 309 { 310 copySource = sourceBuffer->getStagingBuffer(); 311 } 312 else if (copySource->getUsage() == BUFFER_USAGE_PIXEL_PACK && !copyDest->isMappable()) 313 { 314 copyDest = getStagingBuffer(); 315 } 316 317 // D3D11 does not allow overlapped copies until 11.1, and only if the 318 // device supports D3D11_FEATURE_DATA_D3D11_OPTIONS::CopyWithOverlap 319 // Get around this via a different source buffer 320 if (copySource == copyDest) 321 { 322 if (copySource->getUsage() == BUFFER_USAGE_STAGING) 323 { 324 copySource = getBufferStorage(BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK); 325 } 326 else 327 { 328 copySource = getStagingBuffer(); 329 } 330 } 331 332 copyDest->copyFromStorage(copySource, sourceOffset, size, destOffset); 333 copyDest->setDataRevision(copyDest->getDataRevision() + 1); 334 335 mSize = std::max<size_t>(mSize, destOffset + size); 336 invalidateStaticData(); 337 338 return gl::Error(GL_NO_ERROR); 339 } 340 341 gl::Error Buffer11::map(size_t offset, size_t length, GLbitfield access, GLvoid **mapPtr) 342 { 343 ASSERT(!mMappedStorage); 344 345 BufferStorage11 *latestStorage = getLatestBufferStorage(); 346 if (latestStorage && 347 (latestStorage->getUsage() == BUFFER_USAGE_PIXEL_PACK || 348 latestStorage->getUsage() == BUFFER_USAGE_STAGING)) 349 { 350 // Latest storage is mappable. 351 mMappedStorage = latestStorage; 352 } 353 else 354 { 355 // Fall back to using the staging buffer if the latest storage does 356 // not exist or is not CPU-accessible. 357 mMappedStorage = getStagingBuffer(); 358 } 359 360 if (!mMappedStorage) 361 { 362 return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate mappable internal buffer."); 363 } 364 365 if ((access & GL_MAP_WRITE_BIT) > 0) 366 { 367 // Update the data revision immediately, since the data might be changed at any time 368 mMappedStorage->setDataRevision(mMappedStorage->getDataRevision() + 1); 369 } 370 371 void *mappedBuffer = mMappedStorage->map(offset, length, access); 372 if (!mappedBuffer) 373 { 374 return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal buffer."); 375 } 376 377 *mapPtr = mappedBuffer; 378 return gl::Error(GL_NO_ERROR); 379 } 380 381 gl::Error Buffer11::unmap() 382 { 383 ASSERT(mMappedStorage); 384 mMappedStorage->unmap(); 385 mMappedStorage = NULL; 386 return gl::Error(GL_NO_ERROR); 387 } 388 389 void Buffer11::markTransformFeedbackUsage() 390 { 391 BufferStorage11 *transformFeedbackStorage = getBufferStorage(BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK); 392 393 if (transformFeedbackStorage) 394 { 395 transformFeedbackStorage->setDataRevision(transformFeedbackStorage->getDataRevision() + 1); 396 } 397 398 invalidateStaticData(); 399 } 400 401 void Buffer11::markBufferUsage() 402 { 403 mReadUsageCount++; 404 405 const unsigned int usageLimit = 5; 406 407 if (mReadUsageCount > usageLimit && mResolvedData.size() > 0) 408 { 409 mResolvedData.resize(0); 410 mResolvedDataRevision = 0; 411 } 412 } 413 414 Renderer* Buffer11::getRenderer() 415 { 416 return mRenderer; 417 } 418 419 ID3D11Buffer *Buffer11::getBuffer(BufferUsage usage) 420 { 421 markBufferUsage(); 422 423 BufferStorage11 *bufferStorage = getBufferStorage(usage); 424 425 if (!bufferStorage) 426 { 427 // Storage out-of-memory 428 return NULL; 429 } 430 431 ASSERT(HAS_DYNAMIC_TYPE(NativeBuffer11*, bufferStorage)); 432 433 return static_cast<NativeBuffer11*>(bufferStorage)->getNativeBuffer(); 434 } 435 436 ID3D11ShaderResourceView *Buffer11::getSRV(DXGI_FORMAT srvFormat) 437 { 438 BufferStorage11 *storage = getBufferStorage(BUFFER_USAGE_PIXEL_UNPACK); 439 440 if (!storage) 441 { 442 // Storage out-of-memory 443 return NULL; 444 } 445 446 ASSERT(HAS_DYNAMIC_TYPE(NativeBuffer11*, storage)); 447 ID3D11Buffer *buffer = static_cast<NativeBuffer11*>(storage)->getNativeBuffer(); 448 449 auto bufferSRVIt = mBufferResourceViews.find(srvFormat); 450 451 if (bufferSRVIt != mBufferResourceViews.end()) 452 { 453 if (bufferSRVIt->second.first == buffer) 454 { 455 return bufferSRVIt->second.second; 456 } 457 else 458 { 459 // The underlying buffer has changed since the SRV was created: recreate the SRV. 460 SafeRelease(bufferSRVIt->second.second); 461 } 462 } 463 464 ID3D11Device *device = mRenderer->getDevice(); 465 ID3D11ShaderResourceView *bufferSRV = NULL; 466 467 const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(srvFormat); 468 469 D3D11_SHADER_RESOURCE_VIEW_DESC bufferSRVDesc; 470 bufferSRVDesc.Buffer.ElementOffset = 0; 471 bufferSRVDesc.Buffer.ElementWidth = mSize / dxgiFormatInfo.pixelBytes; 472 bufferSRVDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER; 473 bufferSRVDesc.Format = srvFormat; 474 475 HRESULT result = device->CreateShaderResourceView(buffer, &bufferSRVDesc, &bufferSRV); 476 UNUSED_ASSERTION_VARIABLE(result); 477 ASSERT(SUCCEEDED(result)); 478 479 mBufferResourceViews[srvFormat] = BufferSRVPair(buffer, bufferSRV); 480 481 return bufferSRV; 482 } 483 484 gl::Error Buffer11::packPixels(ID3D11Texture2D *srcTexture, UINT srcSubresource, const PackPixelsParams ¶ms) 485 { 486 PackStorage11 *packStorage = getPackStorage(); 487 488 BufferStorage11 *latestStorage = getLatestBufferStorage(); 489 490 if (packStorage) 491 { 492 gl::Error error = packStorage->packPixels(srcTexture, srcSubresource, params); 493 if (error.isError()) 494 { 495 return error; 496 } 497 packStorage->setDataRevision(latestStorage ? latestStorage->getDataRevision() + 1 : 1); 498 } 499 500 return gl::Error(GL_NO_ERROR); 501 } 502 503 Buffer11::BufferStorage11 *Buffer11::getBufferStorage(BufferUsage usage) 504 { 505 BufferStorage11 *directBuffer = NULL; 506 auto directBufferIt = mBufferStorages.find(usage); 507 if (directBufferIt != mBufferStorages.end()) 508 { 509 directBuffer = directBufferIt->second; 510 } 511 512 if (!directBuffer) 513 { 514 if (usage == BUFFER_USAGE_PIXEL_PACK) 515 { 516 directBuffer = new PackStorage11(mRenderer); 517 } 518 else 519 { 520 // buffer is not allocated, create it 521 directBuffer = new NativeBuffer11(mRenderer, usage); 522 } 523 524 mBufferStorages.insert(std::make_pair(usage, directBuffer)); 525 } 526 527 // resize buffer 528 if (directBuffer->getSize() < mSize) 529 { 530 if (!directBuffer->resize(mSize, true)) 531 { 532 // Out of memory error 533 return NULL; 534 } 535 } 536 537 BufferStorage11 *latestBuffer = getLatestBufferStorage(); 538 if (latestBuffer && latestBuffer->getDataRevision() > directBuffer->getDataRevision()) 539 { 540 // if copying from a pack buffer to a non-staging native buffer, we must first 541 // copy through the staging buffer, because other native buffers can't be mapped 542 if (latestBuffer->getUsage() == BUFFER_USAGE_PIXEL_PACK && !directBuffer->isMappable()) 543 { 544 NativeBuffer11 *stagingBuffer = getStagingBuffer(); 545 546 stagingBuffer->copyFromStorage(latestBuffer, 0, latestBuffer->getSize(), 0); 547 directBuffer->setDataRevision(latestBuffer->getDataRevision()); 548 549 latestBuffer = stagingBuffer; 550 } 551 552 // if copyFromStorage returns true, the D3D buffer has been recreated 553 // and we should update our serial 554 if (directBuffer->copyFromStorage(latestBuffer, 0, latestBuffer->getSize(), 0)) 555 { 556 updateSerial(); 557 } 558 directBuffer->setDataRevision(latestBuffer->getDataRevision()); 559 } 560 561 return directBuffer; 562 } 563 564 Buffer11::BufferStorage11 *Buffer11::getLatestBufferStorage() const 565 { 566 // Even though we iterate over all the direct buffers, it is expected that only 567 // 1 or 2 will be present. 568 BufferStorage11 *latestStorage = NULL; 569 DataRevision latestRevision = 0; 570 for (auto it = mBufferStorages.begin(); it != mBufferStorages.end(); it++) 571 { 572 BufferStorage11 *storage = it->second; 573 if (!latestStorage || storage->getDataRevision() > latestRevision) 574 { 575 latestStorage = storage; 576 latestRevision = storage->getDataRevision(); 577 } 578 } 579 580 return latestStorage; 581 } 582 583 Buffer11::NativeBuffer11 *Buffer11::getStagingBuffer() 584 { 585 BufferStorage11 *stagingStorage = getBufferStorage(BUFFER_USAGE_STAGING); 586 587 if (!stagingStorage) 588 { 589 // Out-of-memory 590 return NULL; 591 } 592 593 ASSERT(HAS_DYNAMIC_TYPE(NativeBuffer11*, stagingStorage)); 594 return static_cast<NativeBuffer11*>(stagingStorage); 595 } 596 597 Buffer11::PackStorage11 *Buffer11::getPackStorage() 598 { 599 BufferStorage11 *packStorage = getBufferStorage(BUFFER_USAGE_PIXEL_PACK); 600 601 if (!packStorage) 602 { 603 // Out-of-memory 604 return NULL; 605 } 606 607 ASSERT(HAS_DYNAMIC_TYPE(PackStorage11*, packStorage)); 608 return static_cast<PackStorage11*>(packStorage); 609 } 610 611 bool Buffer11::supportsDirectBinding() const 612 { 613 // Do not support direct buffers for dynamic data. The streaming buffer 614 // offers better performance for data which changes every frame. 615 // Check for absence of static buffer interfaces to detect dynamic data. 616 return (mStaticVertexBuffer && mStaticIndexBuffer); 617 } 618 619 Buffer11::BufferStorage11::BufferStorage11(Renderer11 *renderer, BufferUsage usage) 620 : mRenderer(renderer), 621 mUsage(usage), 622 mRevision(0), 623 mBufferSize(0) 624 { 625 } 626 627 Buffer11::NativeBuffer11::NativeBuffer11(Renderer11 *renderer, BufferUsage usage) 628 : BufferStorage11(renderer, usage), 629 mNativeBuffer(NULL) 630 { 631 } 632 633 Buffer11::NativeBuffer11::~NativeBuffer11() 634 { 635 SafeRelease(mNativeBuffer); 636 } 637 638 // Returns true if it recreates the direct buffer 639 bool Buffer11::NativeBuffer11::copyFromStorage(BufferStorage11 *source, size_t sourceOffset, 640 size_t size, size_t destOffset) 641 { 642 ID3D11DeviceContext *context = mRenderer->getDeviceContext(); 643 644 size_t requiredSize = sourceOffset + size; 645 bool createBuffer = !mNativeBuffer || mBufferSize < requiredSize; 646 647 // (Re)initialize D3D buffer if needed 648 if (createBuffer) 649 { 650 bool preserveData = (destOffset > 0); 651 resize(source->getSize(), preserveData); 652 } 653 654 if (source->getUsage() == BUFFER_USAGE_PIXEL_PACK) 655 { 656 ASSERT(HAS_DYNAMIC_TYPE(PackStorage11*, source)); 657 658 void *sourcePointer = source->map(sourceOffset, size, GL_MAP_READ_BIT); 659 660 D3D11_MAPPED_SUBRESOURCE mappedResource; 661 HRESULT hr = context->Map(mNativeBuffer, 0, D3D11_MAP_WRITE, 0, &mappedResource); 662 UNUSED_ASSERTION_VARIABLE(hr); 663 ASSERT(SUCCEEDED(hr)); 664 665 unsigned char *destPointer = static_cast<unsigned char *>(mappedResource.pData) + destOffset; 666 667 // Offset bounds are validated at the API layer 668 ASSERT(sourceOffset + size <= destOffset + mBufferSize); 669 memcpy(destPointer, sourcePointer, size); 670 } 671 else 672 { 673 ASSERT(HAS_DYNAMIC_TYPE(NativeBuffer11*, source)); 674 675 D3D11_BOX srcBox; 676 srcBox.left = sourceOffset; 677 srcBox.right = sourceOffset + size; 678 srcBox.top = 0; 679 srcBox.bottom = 1; 680 srcBox.front = 0; 681 srcBox.back = 1; 682 683 ASSERT(HAS_DYNAMIC_TYPE(NativeBuffer11*, source)); 684 ID3D11Buffer *sourceBuffer = static_cast<NativeBuffer11*>(source)->getNativeBuffer(); 685 686 context->CopySubresourceRegion(mNativeBuffer, 0, destOffset, 0, 0, sourceBuffer, 0, &srcBox); 687 } 688 689 return createBuffer; 690 } 691 692 bool Buffer11::NativeBuffer11::resize(size_t size, bool preserveData) 693 { 694 ID3D11Device *device = mRenderer->getDevice(); 695 ID3D11DeviceContext *context = mRenderer->getDeviceContext(); 696 697 D3D11_BUFFER_DESC bufferDesc; 698 fillBufferDesc(&bufferDesc, mRenderer, mUsage, size); 699 700 ID3D11Buffer *newBuffer; 701 HRESULT result = device->CreateBuffer(&bufferDesc, NULL, &newBuffer); 702 703 if (FAILED(result)) 704 { 705 return gl::error(GL_OUT_OF_MEMORY, false); 706 } 707 708 if (mNativeBuffer && preserveData) 709 { 710 // We don't call resize if the buffer is big enough already. 711 ASSERT(mBufferSize <= size); 712 713 D3D11_BOX srcBox; 714 srcBox.left = 0; 715 srcBox.right = mBufferSize; 716 srcBox.top = 0; 717 srcBox.bottom = 1; 718 srcBox.front = 0; 719 srcBox.back = 1; 720 721 context->CopySubresourceRegion(newBuffer, 0, 0, 0, 0, mNativeBuffer, 0, &srcBox); 722 } 723 724 // No longer need the old buffer 725 SafeRelease(mNativeBuffer); 726 mNativeBuffer = newBuffer; 727 728 mBufferSize = bufferDesc.ByteWidth; 729 730 return true; 731 } 732 733 void Buffer11::NativeBuffer11::fillBufferDesc(D3D11_BUFFER_DESC* bufferDesc, Renderer *renderer, 734 BufferUsage usage, unsigned int bufferSize) 735 { 736 bufferDesc->ByteWidth = bufferSize; 737 bufferDesc->MiscFlags = 0; 738 bufferDesc->StructureByteStride = 0; 739 740 switch (usage) 741 { 742 case BUFFER_USAGE_STAGING: 743 bufferDesc->Usage = D3D11_USAGE_STAGING; 744 bufferDesc->BindFlags = 0; 745 bufferDesc->CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE; 746 break; 747 748 case BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK: 749 bufferDesc->Usage = D3D11_USAGE_DEFAULT; 750 bufferDesc->BindFlags = D3D11_BIND_VERTEX_BUFFER | D3D11_BIND_STREAM_OUTPUT; 751 bufferDesc->CPUAccessFlags = 0; 752 break; 753 754 case BUFFER_USAGE_INDEX: 755 bufferDesc->Usage = D3D11_USAGE_DEFAULT; 756 bufferDesc->BindFlags = D3D11_BIND_INDEX_BUFFER; 757 bufferDesc->CPUAccessFlags = 0; 758 break; 759 760 case BUFFER_USAGE_PIXEL_UNPACK: 761 bufferDesc->Usage = D3D11_USAGE_DEFAULT; 762 bufferDesc->BindFlags = D3D11_BIND_SHADER_RESOURCE; 763 bufferDesc->CPUAccessFlags = 0; 764 break; 765 766 case BUFFER_USAGE_UNIFORM: 767 bufferDesc->Usage = D3D11_USAGE_DYNAMIC; 768 bufferDesc->BindFlags = D3D11_BIND_CONSTANT_BUFFER; 769 bufferDesc->CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; 770 771 // Constant buffers must be of a limited size, and aligned to 16 byte boundaries 772 // For our purposes we ignore any buffer data past the maximum constant buffer size 773 bufferDesc->ByteWidth = roundUp(bufferDesc->ByteWidth, 16u); 774 bufferDesc->ByteWidth = std::min<UINT>(bufferDesc->ByteWidth, renderer->getRendererCaps().maxUniformBlockSize); 775 break; 776 777 default: 778 UNREACHABLE(); 779 } 780 } 781 782 void *Buffer11::NativeBuffer11::map(size_t offset, size_t length, GLbitfield access) 783 { 784 ASSERT(mUsage == BUFFER_USAGE_STAGING); 785 786 D3D11_MAPPED_SUBRESOURCE mappedResource; 787 ID3D11DeviceContext *context = mRenderer->getDeviceContext(); 788 D3D11_MAP d3dMapType = gl_d3d11::GetD3DMapTypeFromBits(access); 789 UINT d3dMapFlag = ((access & GL_MAP_UNSYNCHRONIZED_BIT) != 0 ? D3D11_MAP_FLAG_DO_NOT_WAIT : 0); 790 791 HRESULT result = context->Map(mNativeBuffer, 0, d3dMapType, d3dMapFlag, &mappedResource); 792 UNUSED_ASSERTION_VARIABLE(result); 793 ASSERT(SUCCEEDED(result)); 794 795 return static_cast<GLubyte*>(mappedResource.pData) + offset; 796 } 797 798 bool Buffer11::NativeBuffer11::setData(D3D11_MAP mapMode, const uint8_t *data, size_t size, size_t offset) 799 { 800 ID3D11DeviceContext *context = mRenderer->getDeviceContext(); 801 802 D3D11_MAPPED_SUBRESOURCE mappedResource; 803 HRESULT result = context->Map(mNativeBuffer, 0, mapMode, 0, &mappedResource); 804 if (FAILED(result)) 805 { 806 return gl::error(GL_OUT_OF_MEMORY, false); 807 } 808 809 uint8_t *offsetBufferPointer = reinterpret_cast<uint8_t *>(mappedResource.pData) + offset; 810 memcpy(offsetBufferPointer, data, size); 811 812 context->Unmap(mNativeBuffer, 0); 813 814 return true; 815 } 816 817 void Buffer11::NativeBuffer11::unmap() 818 { 819 ASSERT(mUsage == BUFFER_USAGE_STAGING); 820 ID3D11DeviceContext *context = mRenderer->getDeviceContext(); 821 context->Unmap(mNativeBuffer, 0); 822 } 823 824 Buffer11::PackStorage11::PackStorage11(Renderer11 *renderer) 825 : BufferStorage11(renderer, BUFFER_USAGE_PIXEL_PACK), 826 mStagingTexture(NULL), 827 mTextureFormat(DXGI_FORMAT_UNKNOWN), 828 mQueuedPackCommand(NULL), 829 mDataModified(false) 830 { 831 } 832 833 Buffer11::PackStorage11::~PackStorage11() 834 { 835 SafeRelease(mStagingTexture); 836 SafeDelete(mQueuedPackCommand); 837 } 838 839 bool Buffer11::PackStorage11::copyFromStorage(BufferStorage11 *source, size_t sourceOffset, 840 size_t size, size_t destOffset) 841 { 842 // We copy through a staging buffer when drawing with a pack buffer, 843 // or for other cases where we access the pack buffer 844 UNREACHABLE(); 845 return false; 846 } 847 848 bool Buffer11::PackStorage11::resize(size_t size, bool preserveData) 849 { 850 if (size != mBufferSize) 851 { 852 if (!mMemoryBuffer.resize(size)) 853 { 854 return false; 855 } 856 mBufferSize = size; 857 } 858 859 return true; 860 } 861 862 void *Buffer11::PackStorage11::map(size_t offset, size_t length, GLbitfield access) 863 { 864 ASSERT(offset + length <= getSize()); 865 // TODO: fast path 866 // We might be able to optimize out one or more memcpy calls by detecting when 867 // and if D3D packs the staging texture memory identically to how we would fill 868 // the pack buffer according to the current pack state. 869 870 flushQueuedPackCommand(); 871 mDataModified = (mDataModified || (access & GL_MAP_WRITE_BIT) != 0); 872 873 return mMemoryBuffer.data() + offset; 874 } 875 876 void Buffer11::PackStorage11::unmap() 877 { 878 // No-op 879 } 880 881 gl::Error Buffer11::PackStorage11::packPixels(ID3D11Texture2D *srcTexure, UINT srcSubresource, const PackPixelsParams ¶ms) 882 { 883 flushQueuedPackCommand(); 884 mQueuedPackCommand = new PackPixelsParams(params); 885 886 D3D11_TEXTURE2D_DESC textureDesc; 887 srcTexure->GetDesc(&textureDesc); 888 889 if (mStagingTexture != NULL && 890 (mTextureFormat != textureDesc.Format || 891 mTextureSize.width != params.area.width || 892 mTextureSize.height != params.area.height)) 893 { 894 SafeRelease(mStagingTexture); 895 mTextureSize.width = 0; 896 mTextureSize.height = 0; 897 mTextureFormat = DXGI_FORMAT_UNKNOWN; 898 } 899 900 if (mStagingTexture == NULL) 901 { 902 ID3D11Device *device = mRenderer->getDevice(); 903 HRESULT hr; 904 905 mTextureSize.width = params.area.width; 906 mTextureSize.height = params.area.height; 907 mTextureFormat = textureDesc.Format; 908 909 D3D11_TEXTURE2D_DESC stagingDesc; 910 stagingDesc.Width = params.area.width; 911 stagingDesc.Height = params.area.height; 912 stagingDesc.MipLevels = 1; 913 stagingDesc.ArraySize = 1; 914 stagingDesc.Format = mTextureFormat; 915 stagingDesc.SampleDesc.Count = 1; 916 stagingDesc.SampleDesc.Quality = 0; 917 stagingDesc.Usage = D3D11_USAGE_STAGING; 918 stagingDesc.BindFlags = 0; 919 stagingDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; 920 stagingDesc.MiscFlags = 0; 921 922 hr = device->CreateTexture2D(&stagingDesc, NULL, &mStagingTexture); 923 if (FAILED(hr)) 924 { 925 ASSERT(hr == E_OUTOFMEMORY); 926 return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal staging texture."); 927 } 928 } 929 930 // ReadPixels from multisampled FBOs isn't supported in current GL 931 ASSERT(textureDesc.SampleDesc.Count <= 1); 932 933 ID3D11DeviceContext *immediateContext = mRenderer->getDeviceContext(); 934 D3D11_BOX srcBox; 935 srcBox.left = params.area.x; 936 srcBox.right = params.area.x + params.area.width; 937 srcBox.top = params.area.y; 938 srcBox.bottom = params.area.y + params.area.height; 939 srcBox.front = 0; 940 srcBox.back = 1; 941 942 // Asynchronous copy 943 immediateContext->CopySubresourceRegion(mStagingTexture, 0, 0, 0, 0, srcTexure, srcSubresource, &srcBox); 944 945 return gl::Error(GL_NO_ERROR); 946 } 947 948 void Buffer11::PackStorage11::flushQueuedPackCommand() 949 { 950 ASSERT(mMemoryBuffer.size() > 0); 951 952 if (mQueuedPackCommand) 953 { 954 mRenderer->packPixels(mStagingTexture, *mQueuedPackCommand, mMemoryBuffer.data()); 955 SafeDelete(mQueuedPackCommand); 956 } 957 } 958 959 } 960