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
14namespace rx
15{
16
17PackPixelsParams::PackPixelsParams()
18  : format(GL_NONE),
19    type(GL_NONE),
20    outputPitch(0),
21    packBuffer(NULL),
22    offset(0)
23{}
24
25PackPixelsParams::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
36namespace gl_d3d11
37{
38
39D3D11_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
75class 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.
105class 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.
130class 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
159Buffer11::Buffer11(Renderer11 *renderer)
160    : BufferD3D(),
161      mRenderer(renderer),
162      mSize(0),
163      mMappedStorage(NULL),
164      mResolvedDataRevision(0),
165      mReadUsageCount(0)
166{}
167
168Buffer11::~Buffer11()
169{
170    for (auto it = mBufferStorages.begin(); it != mBufferStorages.end(); it++)
171    {
172        SafeDelete(it->second);
173    }
174}
175
176Buffer11 *Buffer11::makeBuffer11(BufferImpl *buffer)
177{
178    ASSERT(HAS_DYNAMIC_TYPE(Buffer11*, buffer));
179    return static_cast<Buffer11*>(buffer);
180}
181
182gl::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
198void *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
250gl::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
288gl::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
341gl::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
381gl::Error Buffer11::unmap()
382{
383    ASSERT(mMappedStorage);
384    mMappedStorage->unmap();
385    mMappedStorage = NULL;
386    return gl::Error(GL_NO_ERROR);
387}
388
389void 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
401void 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
414Renderer* Buffer11::getRenderer()
415{
416    return mRenderer;
417}
418
419ID3D11Buffer *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
436ID3D11ShaderResourceView *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
484gl::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
503Buffer11::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
564Buffer11::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
583Buffer11::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
597Buffer11::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
611bool 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
619Buffer11::BufferStorage11::BufferStorage11(Renderer11 *renderer, BufferUsage usage)
620    : mRenderer(renderer),
621      mUsage(usage),
622      mRevision(0),
623      mBufferSize(0)
624{
625}
626
627Buffer11::NativeBuffer11::NativeBuffer11(Renderer11 *renderer, BufferUsage usage)
628    : BufferStorage11(renderer, usage),
629      mNativeBuffer(NULL)
630{
631}
632
633Buffer11::NativeBuffer11::~NativeBuffer11()
634{
635    SafeRelease(mNativeBuffer);
636}
637
638// Returns true if it recreates the direct buffer
639bool 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
692bool 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
733void 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
782void *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
798bool 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
817void Buffer11::NativeBuffer11::unmap()
818{
819    ASSERT(mUsage == BUFFER_USAGE_STAGING);
820    ID3D11DeviceContext *context = mRenderer->getDeviceContext();
821    context->Unmap(mNativeBuffer, 0);
822}
823
824Buffer11::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
833Buffer11::PackStorage11::~PackStorage11()
834{
835    SafeRelease(mStagingTexture);
836    SafeDelete(mQueuedPackCommand);
837}
838
839bool 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
848bool 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
862void *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
876void Buffer11::PackStorage11::unmap()
877{
878    // No-op
879}
880
881gl::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
948void 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