Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / angle / src / libGLESv2 / renderer / d3d / d3d11 / Buffer11.cpp
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 }