Home | History | Annotate | Download | only in d3d11
      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 &params);
    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 &params)
    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 &params)
    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