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