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 "libANGLE/renderer/d3d/d3d11/Buffer11.h"
10 
11 #include <memory>
12 
13 #include "common/MemoryBuffer.h"
14 #include "libANGLE/renderer/d3d/IndexDataManager.h"
15 #include "libANGLE/renderer/d3d/VertexDataManager.h"
16 #include "libANGLE/renderer/d3d/d3d11/RenderTarget11.h"
17 #include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
18 #include "libANGLE/renderer/d3d/d3d11/formatutils11.h"
19 #include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h"
20 #include "libANGLE/renderer/renderer_utils.h"
21 
22 namespace rx
23 {
24 
25 namespace
26 {
27 
28 template <typename T>
ReadIndexValueFromIndices(const uint8_t * data,size_t index)29 GLuint ReadIndexValueFromIndices(const uint8_t *data, size_t index)
30 {
31     return reinterpret_cast<const T *>(data)[index];
32 }
33 typedef GLuint (*ReadIndexValueFunction)(const uint8_t *data, size_t index);
34 
35 enum class CopyResult
36 {
37     RECREATED,
38     NOT_RECREATED,
39 };
40 
CalculateConstantBufferParams(GLintptr offset,GLsizeiptr size,UINT * outFirstConstant,UINT * outNumConstants)41 void CalculateConstantBufferParams(GLintptr offset,
42                                    GLsizeiptr size,
43                                    UINT *outFirstConstant,
44                                    UINT *outNumConstants)
45 {
46     // The offset must be aligned to 256 bytes (should have been enforced by glBindBufferRange).
47     ASSERT(offset % 256 == 0);
48 
49     // firstConstant and numConstants are expressed in constants of 16-bytes. Furthermore they must
50     // be a multiple of 16 constants.
51     *outFirstConstant = static_cast<UINT>(offset / 16);
52 
53     // The GL size is not required to be aligned to a 256 bytes boundary.
54     // Round the size up to a 256 bytes boundary then express the results in constants of 16-bytes.
55     *outNumConstants = static_cast<UINT>(rx::roundUp(size, static_cast<GLsizeiptr>(256)) / 16);
56 
57     // Since the size is rounded up, firstConstant + numConstants may be bigger than the actual size
58     // of the buffer. This behaviour is explictly allowed according to the documentation on
59     // ID3D11DeviceContext1::PSSetConstantBuffers1
60     // https://msdn.microsoft.com/en-us/library/windows/desktop/hh404649%28v=vs.85%29.aspx
61 }
62 
63 }  // anonymous namespace
64 
65 namespace gl_d3d11
66 {
67 
GetD3DMapTypeFromBits(BufferUsage usage,GLbitfield access)68 D3D11_MAP GetD3DMapTypeFromBits(BufferUsage usage, GLbitfield access)
69 {
70     bool readBit  = ((access & GL_MAP_READ_BIT) != 0);
71     bool writeBit = ((access & GL_MAP_WRITE_BIT) != 0);
72 
73     ASSERT(readBit || writeBit);
74 
75     // Note : we ignore the discard bit, because in D3D11, staging buffers
76     //  don't accept the map-discard flag (discard only works for DYNAMIC usage)
77 
78     if (readBit && !writeBit)
79     {
80         return D3D11_MAP_READ;
81     }
82     else if (writeBit && !readBit)
83     {
84         // Special case for uniform storage - we only allow full buffer updates.
85         return usage == BUFFER_USAGE_UNIFORM ? D3D11_MAP_WRITE_DISCARD : D3D11_MAP_WRITE;
86     }
87     else if (writeBit && readBit)
88     {
89         return D3D11_MAP_READ_WRITE;
90     }
91     else
92     {
93         UNREACHABLE();
94         return D3D11_MAP_READ;
95     }
96 }
97 }  // namespace gl_d3d11
98 
99 // Each instance of Buffer11::BufferStorage is specialized for a class of D3D binding points
100 // - vertex/transform feedback buffers
101 // - index buffers
102 // - pixel unpack buffers
103 // - uniform buffers
104 class Buffer11::BufferStorage : angle::NonCopyable
105 {
106   public:
~BufferStorage()107     virtual ~BufferStorage() {}
108 
getDataRevision() const109     DataRevision getDataRevision() const { return mRevision; }
getUsage() const110     BufferUsage getUsage() const { return mUsage; }
getSize() const111     size_t getSize() const { return mBufferSize; }
setDataRevision(DataRevision rev)112     void setDataRevision(DataRevision rev) { mRevision = rev; }
113 
114     virtual bool isCPUAccessible(GLbitfield access) const = 0;
115 
116     virtual bool isGPUAccessible() const = 0;
117 
118     virtual gl::ErrorOrResult<CopyResult> copyFromStorage(const gl::Context *context,
119                                                           BufferStorage *source,
120                                                           size_t sourceOffset,
121                                                           size_t size,
122                                                           size_t destOffset) = 0;
123     virtual gl::Error resize(const gl::Context *context, size_t size, bool preserveData) = 0;
124 
125     virtual gl::Error map(size_t offset,
126                           size_t length,
127                           GLbitfield access,
128                           uint8_t **mapPointerOut) = 0;
129     virtual void unmap()                           = 0;
130 
131     gl::Error setData(const uint8_t *data, size_t offset, size_t size);
132 
133   protected:
134     BufferStorage(Renderer11 *renderer, BufferUsage usage);
135 
136     Renderer11 *mRenderer;
137     DataRevision mRevision;
138     const BufferUsage mUsage;
139     size_t mBufferSize;
140 };
141 
142 // A native buffer storage represents an underlying D3D11 buffer for a particular
143 // type of storage.
144 class Buffer11::NativeStorage : public Buffer11::BufferStorage
145 {
146   public:
147     NativeStorage(Renderer11 *renderer,
148                   BufferUsage usage,
149                   const OnBufferDataDirtyChannel *onStorageChanged);
150     ~NativeStorage() override;
151 
152     bool isCPUAccessible(GLbitfield access) const override;
153 
isGPUAccessible() const154     bool isGPUAccessible() const override { return true; }
155 
getBuffer() const156     const d3d11::Buffer &getBuffer() const { return mBuffer; }
157     gl::ErrorOrResult<CopyResult> copyFromStorage(const gl::Context *context,
158                                                   BufferStorage *source,
159                                                   size_t sourceOffset,
160                                                   size_t size,
161                                                   size_t destOffset) override;
162     gl::Error resize(const gl::Context *context, size_t size, bool preserveData) override;
163 
164     gl::Error map(size_t offset,
165                   size_t length,
166                   GLbitfield access,
167                   uint8_t **mapPointerOut) override;
168     void unmap() override;
169 
170     gl::ErrorOrResult<const d3d11::ShaderResourceView *> getSRVForFormat(DXGI_FORMAT srvFormat);
171 
172   private:
173     static void FillBufferDesc(D3D11_BUFFER_DESC *bufferDesc,
174                                Renderer11 *renderer,
175                                BufferUsage usage,
176                                unsigned int bufferSize);
177     void clearSRVs();
178 
179     d3d11::Buffer mBuffer;
180     const OnBufferDataDirtyChannel *mOnStorageChanged;
181     std::map<DXGI_FORMAT, d3d11::ShaderResourceView> mBufferResourceViews;
182 };
183 
184 // A emulated indexed buffer storage represents an underlying D3D11 buffer for data
185 // that has been expanded to match the indices list used. This storage is only
186 // used for FL9_3 pointsprite rendering emulation.
187 class Buffer11::EmulatedIndexedStorage : public Buffer11::BufferStorage
188 {
189   public:
190     EmulatedIndexedStorage(Renderer11 *renderer);
191     ~EmulatedIndexedStorage() override;
192 
isCPUAccessible(GLbitfield access) const193     bool isCPUAccessible(GLbitfield access) const override { return true; }
194 
isGPUAccessible() const195     bool isGPUAccessible() const override { return false; }
196 
197     gl::ErrorOrResult<const d3d11::Buffer *> getBuffer(SourceIndexData *indexInfo,
198                                                        const TranslatedAttribute &attribute,
199                                                        GLint startVertex);
200 
201     gl::ErrorOrResult<CopyResult> copyFromStorage(const gl::Context *context,
202                                                   BufferStorage *source,
203                                                   size_t sourceOffset,
204                                                   size_t size,
205                                                   size_t destOffset) override;
206 
207     gl::Error resize(const gl::Context *context, size_t size, bool preserveData) override;
208 
209     gl::Error map(size_t offset,
210                   size_t length,
211                   GLbitfield access,
212                   uint8_t **mapPointerOut) override;
213     void unmap() override;
214 
215   private:
216     d3d11::Buffer mBuffer;                     // contains expanded data for use by D3D
217     angle::MemoryBuffer mMemoryBuffer;         // original data (not expanded)
218     angle::MemoryBuffer mIndicesMemoryBuffer;  // indices data
219 };
220 
221 // Pack storage represents internal storage for pack buffers. We implement pack buffers
222 // as CPU memory, tied to a staging texture, for asynchronous texture readback.
223 class Buffer11::PackStorage : public Buffer11::BufferStorage
224 {
225   public:
226     explicit PackStorage(Renderer11 *renderer);
227     ~PackStorage() override;
228 
isCPUAccessible(GLbitfield access) const229     bool isCPUAccessible(GLbitfield access) const override { return true; }
230 
isGPUAccessible() const231     bool isGPUAccessible() const override { return false; }
232 
233     gl::ErrorOrResult<CopyResult> copyFromStorage(const gl::Context *context,
234                                                   BufferStorage *source,
235                                                   size_t sourceOffset,
236                                                   size_t size,
237                                                   size_t destOffset) override;
238     gl::Error resize(const gl::Context *context, size_t size, bool preserveData) override;
239 
240     gl::Error map(size_t offset,
241                   size_t length,
242                   GLbitfield access,
243                   uint8_t **mapPointerOut) override;
244     void unmap() override;
245 
246     gl::Error packPixels(const gl::Context *context,
247                          const gl::FramebufferAttachment &readAttachment,
248                          const PackPixelsParams &params);
249 
250   private:
251     gl::Error flushQueuedPackCommand();
252 
253     TextureHelper11 mStagingTexture;
254     angle::MemoryBuffer mMemoryBuffer;
255     std::unique_ptr<PackPixelsParams> mQueuedPackCommand;
256     PackPixelsParams mPackParams;
257     bool mDataModified;
258 };
259 
260 // System memory storage stores a CPU memory buffer with our buffer data.
261 // For dynamic data, it's much faster to update the CPU memory buffer than
262 // it is to update a D3D staging buffer and read it back later.
263 class Buffer11::SystemMemoryStorage : public Buffer11::BufferStorage
264 {
265   public:
266     explicit SystemMemoryStorage(Renderer11 *renderer);
~SystemMemoryStorage()267     ~SystemMemoryStorage() override {}
268 
isCPUAccessible(GLbitfield access) const269     bool isCPUAccessible(GLbitfield access) const override { return true; }
270 
isGPUAccessible() const271     bool isGPUAccessible() const override { return false; }
272 
273     gl::ErrorOrResult<CopyResult> copyFromStorage(const gl::Context *context,
274                                                   BufferStorage *source,
275                                                   size_t sourceOffset,
276                                                   size_t size,
277                                                   size_t destOffset) override;
278     gl::Error resize(const gl::Context *context, size_t size, bool preserveData) override;
279 
280     gl::Error map(size_t offset,
281                   size_t length,
282                   GLbitfield access,
283                   uint8_t **mapPointerOut) override;
284     void unmap() override;
285 
getSystemCopy()286     angle::MemoryBuffer *getSystemCopy() { return &mSystemCopy; }
287 
288   protected:
289     angle::MemoryBuffer mSystemCopy;
290 };
291 
Buffer11(const gl::BufferState & state,Renderer11 * renderer)292 Buffer11::Buffer11(const gl::BufferState &state, Renderer11 *renderer)
293     : BufferD3D(state, renderer),
294       mRenderer(renderer),
295       mSize(0),
296       mMappedStorage(nullptr),
297       mBufferStorages({}),
298       mLatestBufferStorage(nullptr),
299       mDeallocThresholds({}),
300       mIdleness({}),
301       mConstantBufferStorageAdditionalSize(0),
302       mMaxConstantBufferLruCount(0)
303 {
304 }
305 
~Buffer11()306 Buffer11::~Buffer11()
307 {
308     for (BufferStorage *&storage : mBufferStorages)
309     {
310         SafeDelete(storage);
311     }
312 
313     for (auto &p : mConstantBufferRangeStoragesCache)
314     {
315         SafeDelete(p.second.storage);
316     }
317 
318     mRenderer->onBufferDelete(this);
319 }
320 
setData(const gl::Context * context,gl::BufferBinding target,const void * data,size_t size,gl::BufferUsage usage)321 gl::Error Buffer11::setData(const gl::Context *context,
322                             gl::BufferBinding target,
323                             const void *data,
324                             size_t size,
325                             gl::BufferUsage usage)
326 {
327     updateD3DBufferUsage(context, usage);
328     ANGLE_TRY(setSubData(context, target, data, size, 0));
329     return gl::NoError();
330 }
331 
getData(const gl::Context * context,const uint8_t ** outData)332 gl::Error Buffer11::getData(const gl::Context *context, const uint8_t **outData)
333 {
334     SystemMemoryStorage *systemMemoryStorage = nullptr;
335     ANGLE_TRY_RESULT(getSystemMemoryStorage(context), systemMemoryStorage);
336 
337     ASSERT(systemMemoryStorage->getSize() >= mSize);
338 
339     *outData = systemMemoryStorage->getSystemCopy()->data();
340     return gl::NoError();
341 }
342 
getSystemMemoryStorage(const gl::Context * context)343 gl::ErrorOrResult<Buffer11::SystemMemoryStorage *> Buffer11::getSystemMemoryStorage(
344     const gl::Context *context)
345 {
346     BufferStorage *storage = nullptr;
347     ANGLE_TRY_RESULT(getBufferStorage(context, BUFFER_USAGE_SYSTEM_MEMORY), storage);
348     return GetAs<SystemMemoryStorage>(storage);
349 }
350 
setSubData(const gl::Context * context,gl::BufferBinding target,const void * data,size_t size,size_t offset)351 gl::Error Buffer11::setSubData(const gl::Context *context,
352                                gl::BufferBinding target,
353                                const void *data,
354                                size_t size,
355                                size_t offset)
356 {
357     size_t requiredSize = size + offset;
358 
359     if (data && size > 0)
360     {
361         // Use system memory storage for dynamic buffers.
362         // Try using a constant storage for constant buffers
363         BufferStorage *writeBuffer = nullptr;
364         if (target == gl::BufferBinding::Uniform)
365         {
366             // If we are a very large uniform buffer, keep system memory storage around so that we
367             // aren't forced to read back from a constant buffer. We also check the workaround for
368             // Intel - this requires us to use system memory so we don't end up having to copy from
369             // a constant buffer to a staging buffer.
370             // TODO(jmadill): Use Context caps.
371             if (offset == 0 && size >= mSize &&
372                 size <= static_cast<UINT>(mRenderer->getNativeCaps().maxUniformBlockSize) &&
373                 !mRenderer->getWorkarounds().useSystemMemoryForConstantBuffers)
374             {
375                 ANGLE_TRY_RESULT(getBufferStorage(context, BUFFER_USAGE_UNIFORM), writeBuffer);
376             }
377             else
378             {
379                 ANGLE_TRY_RESULT(getSystemMemoryStorage(context), writeBuffer);
380             }
381         }
382         else if (supportsDirectBinding())
383         {
384             ANGLE_TRY_RESULT(getStagingStorage(context), writeBuffer);
385         }
386         else
387         {
388             ANGLE_TRY_RESULT(getSystemMemoryStorage(context), writeBuffer);
389         }
390 
391         ASSERT(writeBuffer);
392 
393         // Explicitly resize the staging buffer, preserving data if the new data will not
394         // completely fill the buffer
395         if (writeBuffer->getSize() < requiredSize)
396         {
397             bool preserveData = (offset > 0);
398             ANGLE_TRY(writeBuffer->resize(context, requiredSize, preserveData));
399         }
400 
401         ANGLE_TRY(writeBuffer->setData(static_cast<const uint8_t *>(data), offset, size));
402         onStorageUpdate(writeBuffer);
403 
404         // Notify any vertex arrays that we have dirty data.
405         // TODO(jmadill): Use a more fine grained notification for data updates.
406         mDirectBroadcastChannel.signal(context);
407     }
408 
409     mSize = std::max(mSize, requiredSize);
410     invalidateStaticData(context);
411 
412     return gl::NoError();
413 }
414 
copySubData(const gl::Context * context,BufferImpl * source,GLintptr sourceOffset,GLintptr destOffset,GLsizeiptr size)415 gl::Error Buffer11::copySubData(const gl::Context *context,
416                                 BufferImpl *source,
417                                 GLintptr sourceOffset,
418                                 GLintptr destOffset,
419                                 GLsizeiptr size)
420 {
421     Buffer11 *sourceBuffer = GetAs<Buffer11>(source);
422     ASSERT(sourceBuffer != nullptr);
423 
424     BufferStorage *copyDest = nullptr;
425     ANGLE_TRY_RESULT(getLatestBufferStorage(context), copyDest);
426 
427     if (!copyDest)
428     {
429         ANGLE_TRY_RESULT(getStagingStorage(context), copyDest);
430     }
431 
432     BufferStorage *copySource = nullptr;
433     ANGLE_TRY_RESULT(sourceBuffer->getLatestBufferStorage(context), copySource);
434 
435     if (!copySource)
436     {
437         ANGLE_TRY_RESULT(sourceBuffer->getStagingStorage(context), copySource);
438     }
439 
440     ASSERT(copySource && copyDest);
441 
442     // A staging buffer is needed if there is no cpu-cpu or gpu-gpu copy path avaiable.
443     if (!copyDest->isGPUAccessible() && !copySource->isCPUAccessible(GL_MAP_READ_BIT))
444     {
445         ANGLE_TRY_RESULT(sourceBuffer->getStagingStorage(context), copySource);
446     }
447     else if (!copySource->isGPUAccessible() && !copyDest->isCPUAccessible(GL_MAP_WRITE_BIT))
448     {
449         ANGLE_TRY_RESULT(getStagingStorage(context), copyDest);
450     }
451 
452     // D3D11 does not allow overlapped copies until 11.1, and only if the
453     // device supports D3D11_FEATURE_DATA_D3D11_OPTIONS::CopyWithOverlap
454     // Get around this via a different source buffer
455     if (copySource == copyDest)
456     {
457         if (copySource->getUsage() == BUFFER_USAGE_STAGING)
458         {
459             ANGLE_TRY_RESULT(getBufferStorage(context, BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK),
460                              copySource);
461         }
462         else
463         {
464             ANGLE_TRY_RESULT(getStagingStorage(context), copySource);
465         }
466     }
467 
468     CopyResult copyResult = CopyResult::NOT_RECREATED;
469     ANGLE_TRY_RESULT(copyDest->copyFromStorage(context, copySource, sourceOffset, size, destOffset),
470                      copyResult);
471     onStorageUpdate(copyDest);
472 
473     mSize = std::max<size_t>(mSize, destOffset + size);
474     invalidateStaticData(context);
475 
476     // Also notify that direct buffers are dirty.
477     mDirectBroadcastChannel.signal(context);
478 
479     return gl::NoError();
480 }
481 
map(const gl::Context * context,GLenum access,void ** mapPtr)482 gl::Error Buffer11::map(const gl::Context *context, GLenum access, void **mapPtr)
483 {
484     // GL_OES_mapbuffer uses an enum instead of a bitfield for it's access, convert to a bitfield
485     // and call mapRange.
486     ASSERT(access == GL_WRITE_ONLY_OES);
487     return mapRange(context, 0, mSize, GL_MAP_WRITE_BIT, mapPtr);
488 }
489 
mapRange(const gl::Context * context,size_t offset,size_t length,GLbitfield access,void ** mapPtr)490 gl::Error Buffer11::mapRange(const gl::Context *context,
491                              size_t offset,
492                              size_t length,
493                              GLbitfield access,
494                              void **mapPtr)
495 {
496     ASSERT(!mMappedStorage);
497 
498     BufferStorage *latestStorage = nullptr;
499     ANGLE_TRY_RESULT(getLatestBufferStorage(context), latestStorage);
500 
501     if (latestStorage && (latestStorage->getUsage() == BUFFER_USAGE_PIXEL_PACK ||
502                           latestStorage->getUsage() == BUFFER_USAGE_STAGING))
503     {
504         // Latest storage is mappable.
505         mMappedStorage = latestStorage;
506     }
507     else
508     {
509         // Fall back to using the staging buffer if the latest storage does not exist or is not
510         // CPU-accessible.
511         ANGLE_TRY_RESULT(getStagingStorage(context), mMappedStorage);
512     }
513 
514     if (!mMappedStorage)
515     {
516         return gl::OutOfMemory() << "Failed to allocate mappable internal buffer.";
517     }
518 
519     if ((access & GL_MAP_WRITE_BIT) > 0)
520     {
521         // Update the data revision immediately, since the data might be changed at any time
522         onStorageUpdate(mMappedStorage);
523         invalidateStaticData(context);
524     }
525 
526     uint8_t *mappedBuffer = nullptr;
527     ANGLE_TRY(mMappedStorage->map(offset, length, access, &mappedBuffer));
528     ASSERT(mappedBuffer);
529 
530     *mapPtr = static_cast<void *>(mappedBuffer);
531     return gl::NoError();
532 }
533 
unmap(const gl::Context * context,GLboolean * result)534 gl::Error Buffer11::unmap(const gl::Context *context, GLboolean *result)
535 {
536     ASSERT(mMappedStorage);
537     mMappedStorage->unmap();
538     mMappedStorage = nullptr;
539 
540     // TODO: detect if we had corruption. if so, return false.
541     *result = GL_TRUE;
542 
543     return gl::NoError();
544 }
545 
markTransformFeedbackUsage(const gl::Context * context)546 gl::Error Buffer11::markTransformFeedbackUsage(const gl::Context *context)
547 {
548     BufferStorage *transformFeedbackStorage = nullptr;
549     ANGLE_TRY_RESULT(getBufferStorage(context, BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK),
550                      transformFeedbackStorage);
551 
552     if (transformFeedbackStorage)
553     {
554         onStorageUpdate(transformFeedbackStorage);
555     }
556 
557     invalidateStaticData(context);
558     return gl::NoError();
559 }
560 
updateDeallocThreshold(BufferUsage usage)561 void Buffer11::updateDeallocThreshold(BufferUsage usage)
562 {
563     // The following strategy was tuned on the Oort online benchmark (http://oortonline.gl/)
564     // as well as a custom microbenchmark (IndexConversionPerfTest.Run/index_range_d3d11)
565 
566     // First readback: 8 unmodified uses before we free buffer memory.
567     // After that, double the threshold each time until we reach the max.
568     if (mDeallocThresholds[usage] == 0)
569     {
570         mDeallocThresholds[usage] = 8;
571     }
572     else if (mDeallocThresholds[usage] < std::numeric_limits<unsigned int>::max() / 2u)
573     {
574         mDeallocThresholds[usage] *= 2u;
575     }
576     else
577     {
578         mDeallocThresholds[usage] = std::numeric_limits<unsigned int>::max();
579     }
580 }
581 
582 // Free the storage if we decide it isn't being used very often.
checkForDeallocation(const gl::Context * context,BufferUsage usage)583 gl::Error Buffer11::checkForDeallocation(const gl::Context *context, BufferUsage usage)
584 {
585     mIdleness[usage]++;
586 
587     BufferStorage *&storage = mBufferStorages[usage];
588     if (storage != nullptr && mIdleness[usage] > mDeallocThresholds[usage])
589     {
590         BufferStorage *latestStorage = nullptr;
591         ANGLE_TRY_RESULT(getLatestBufferStorage(context), latestStorage);
592         if (latestStorage != storage)
593         {
594             SafeDelete(storage);
595         }
596     }
597 
598     return gl::NoError();
599 }
600 
601 // Keep system memory when we are using it for the canonical version of data.
canDeallocateSystemMemory() const602 bool Buffer11::canDeallocateSystemMemory() const
603 {
604     // Must keep system memory on Intel.
605     if (mRenderer->getWorkarounds().useSystemMemoryForConstantBuffers)
606     {
607         return false;
608     }
609 
610     return (!mBufferStorages[BUFFER_USAGE_UNIFORM] ||
611             mSize <= mRenderer->getNativeCaps().maxUniformBlockSize);
612 }
613 
markBufferUsage(BufferUsage usage)614 void Buffer11::markBufferUsage(BufferUsage usage)
615 {
616     mIdleness[usage] = 0;
617 }
618 
garbageCollection(const gl::Context * context,BufferUsage currentUsage)619 gl::Error Buffer11::garbageCollection(const gl::Context *context, BufferUsage currentUsage)
620 {
621     if (currentUsage != BUFFER_USAGE_SYSTEM_MEMORY && canDeallocateSystemMemory())
622     {
623         ANGLE_TRY(checkForDeallocation(context, BUFFER_USAGE_SYSTEM_MEMORY));
624     }
625 
626     if (currentUsage != BUFFER_USAGE_STAGING)
627     {
628         ANGLE_TRY(checkForDeallocation(context, BUFFER_USAGE_STAGING));
629     }
630 
631     return gl::NoError();
632 }
633 
getBuffer(const gl::Context * context,BufferUsage usage)634 gl::ErrorOrResult<ID3D11Buffer *> Buffer11::getBuffer(const gl::Context *context, BufferUsage usage)
635 {
636     BufferStorage *storage = nullptr;
637     ANGLE_TRY_RESULT(getBufferStorage(context, usage), storage);
638     return GetAs<NativeStorage>(storage)->getBuffer().get();
639 }
640 
getEmulatedIndexedBuffer(const gl::Context * context,SourceIndexData * indexInfo,const TranslatedAttribute & attribute,GLint startVertex)641 gl::ErrorOrResult<ID3D11Buffer *> Buffer11::getEmulatedIndexedBuffer(
642     const gl::Context *context,
643     SourceIndexData *indexInfo,
644     const TranslatedAttribute &attribute,
645     GLint startVertex)
646 {
647     ASSERT(indexInfo);
648 
649     BufferStorage *untypedStorage = nullptr;
650     ANGLE_TRY_RESULT(getBufferStorage(context, BUFFER_USAGE_EMULATED_INDEXED_VERTEX),
651                      untypedStorage);
652 
653     EmulatedIndexedStorage *emulatedStorage = GetAs<EmulatedIndexedStorage>(untypedStorage);
654 
655     const d3d11::Buffer *nativeStorage = nullptr;
656     ANGLE_TRY_RESULT(emulatedStorage->getBuffer(indexInfo, attribute, startVertex), nativeStorage);
657 
658     return nativeStorage->get();
659 }
660 
getConstantBufferRange(const gl::Context * context,GLintptr offset,GLsizeiptr size,const d3d11::Buffer ** bufferOut,UINT * firstConstantOut,UINT * numConstantsOut)661 gl::Error Buffer11::getConstantBufferRange(const gl::Context *context,
662                                            GLintptr offset,
663                                            GLsizeiptr size,
664                                            const d3d11::Buffer **bufferOut,
665                                            UINT *firstConstantOut,
666                                            UINT *numConstantsOut)
667 {
668     BufferStorage *bufferStorage = nullptr;
669 
670     if (offset == 0 || mRenderer->getRenderer11DeviceCaps().supportsConstantBufferOffsets)
671     {
672         ANGLE_TRY_RESULT(getBufferStorage(context, BUFFER_USAGE_UNIFORM), bufferStorage);
673         CalculateConstantBufferParams(offset, size, firstConstantOut, numConstantsOut);
674     }
675     else
676     {
677         ANGLE_TRY_RESULT(getConstantBufferRangeStorage(context, offset, size), bufferStorage);
678         *firstConstantOut = 0;
679         *numConstantsOut  = 0;
680     }
681 
682     *bufferOut = &GetAs<NativeStorage>(bufferStorage)->getBuffer();
683 
684     return gl::NoError();
685 }
686 
getSRV(const gl::Context * context,DXGI_FORMAT srvFormat)687 gl::ErrorOrResult<const d3d11::ShaderResourceView *> Buffer11::getSRV(const gl::Context *context,
688                                                                       DXGI_FORMAT srvFormat)
689 {
690     BufferStorage *storage = nullptr;
691     ANGLE_TRY_RESULT(getBufferStorage(context, BUFFER_USAGE_PIXEL_UNPACK), storage);
692     NativeStorage *nativeStorage = GetAs<NativeStorage>(storage);
693     return nativeStorage->getSRVForFormat(srvFormat);
694 }
695 
packPixels(const gl::Context * context,const gl::FramebufferAttachment & readAttachment,const PackPixelsParams & params)696 gl::Error Buffer11::packPixels(const gl::Context *context,
697                                const gl::FramebufferAttachment &readAttachment,
698                                const PackPixelsParams &params)
699 {
700     PackStorage *packStorage = nullptr;
701     ANGLE_TRY_RESULT(getPackStorage(context), packStorage);
702 
703     ASSERT(packStorage);
704     ANGLE_TRY(packStorage->packPixels(context, readAttachment, params));
705     onStorageUpdate(packStorage);
706 
707     return gl::NoError();
708 }
709 
getTotalCPUBufferMemoryBytes() const710 size_t Buffer11::getTotalCPUBufferMemoryBytes() const
711 {
712     size_t allocationSize = 0;
713 
714     BufferStorage *staging = mBufferStorages[BUFFER_USAGE_STAGING];
715     allocationSize += staging ? staging->getSize() : 0;
716 
717     BufferStorage *sysMem = mBufferStorages[BUFFER_USAGE_SYSTEM_MEMORY];
718     allocationSize += sysMem ? sysMem->getSize() : 0;
719 
720     return allocationSize;
721 }
722 
getBufferStorage(const gl::Context * context,BufferUsage usage)723 gl::ErrorOrResult<Buffer11::BufferStorage *> Buffer11::getBufferStorage(const gl::Context *context,
724                                                                         BufferUsage usage)
725 {
726     ASSERT(0 <= usage && usage < BUFFER_USAGE_COUNT);
727     BufferStorage *&newStorage = mBufferStorages[usage];
728 
729     if (!newStorage)
730     {
731         newStorage = allocateStorage(usage);
732     }
733 
734     markBufferUsage(usage);
735 
736     // resize buffer
737     if (newStorage->getSize() < mSize)
738     {
739         ANGLE_TRY(newStorage->resize(context, mSize, true));
740     }
741 
742     ASSERT(newStorage);
743 
744     ANGLE_TRY(updateBufferStorage(context, newStorage, 0, mSize));
745     ANGLE_TRY(garbageCollection(context, usage));
746 
747     return newStorage;
748 }
749 
allocateStorage(BufferUsage usage)750 Buffer11::BufferStorage *Buffer11::allocateStorage(BufferUsage usage)
751 {
752     updateDeallocThreshold(usage);
753     switch (usage)
754     {
755         case BUFFER_USAGE_PIXEL_PACK:
756             return new PackStorage(mRenderer);
757         case BUFFER_USAGE_SYSTEM_MEMORY:
758             return new SystemMemoryStorage(mRenderer);
759         case BUFFER_USAGE_EMULATED_INDEXED_VERTEX:
760             return new EmulatedIndexedStorage(mRenderer);
761         case BUFFER_USAGE_INDEX:
762         case BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK:
763             return new NativeStorage(mRenderer, usage, &mDirectBroadcastChannel);
764         default:
765             return new NativeStorage(mRenderer, usage, nullptr);
766     }
767 }
768 
getConstantBufferRangeStorage(const gl::Context * context,GLintptr offset,GLsizeiptr size)769 gl::ErrorOrResult<Buffer11::BufferStorage *> Buffer11::getConstantBufferRangeStorage(
770     const gl::Context *context,
771     GLintptr offset,
772     GLsizeiptr size)
773 {
774     BufferStorage *newStorage;
775 
776     {
777         // Keep the cacheEntry in a limited scope because it may be invalidated later in the code if
778         // we need to reclaim some space.
779         ConstantBufferCacheEntry *cacheEntry = &mConstantBufferRangeStoragesCache[offset];
780 
781         if (!cacheEntry->storage)
782         {
783             cacheEntry->storage  = allocateStorage(BUFFER_USAGE_UNIFORM);
784             cacheEntry->lruCount = ++mMaxConstantBufferLruCount;
785         }
786 
787         cacheEntry->lruCount = ++mMaxConstantBufferLruCount;
788         newStorage           = cacheEntry->storage;
789     }
790 
791     markBufferUsage(BUFFER_USAGE_UNIFORM);
792 
793     if (newStorage->getSize() < static_cast<size_t>(size))
794     {
795         size_t maximumAllowedAdditionalSize = 2 * getSize();
796 
797         size_t sizeDelta = size - newStorage->getSize();
798 
799         while (mConstantBufferStorageAdditionalSize + sizeDelta > maximumAllowedAdditionalSize)
800         {
801             auto iter = std::min_element(std::begin(mConstantBufferRangeStoragesCache),
802                                          std::end(mConstantBufferRangeStoragesCache),
803                                          [](const ConstantBufferCache::value_type &a,
804                                             const ConstantBufferCache::value_type &b) {
805                                              return a.second.lruCount < b.second.lruCount;
806                                          });
807 
808             ASSERT(iter->second.storage != newStorage);
809             ASSERT(mConstantBufferStorageAdditionalSize >= iter->second.storage->getSize());
810 
811             mConstantBufferStorageAdditionalSize -= iter->second.storage->getSize();
812             SafeDelete(iter->second.storage);
813             mConstantBufferRangeStoragesCache.erase(iter);
814         }
815 
816         ANGLE_TRY(newStorage->resize(context, size, false));
817         mConstantBufferStorageAdditionalSize += sizeDelta;
818 
819         // We don't copy the old data when resizing the constant buffer because the data may be
820         // out-of-date therefore we reset the data revision and let updateBufferStorage() handle the
821         // copy.
822         newStorage->setDataRevision(0);
823     }
824 
825     ANGLE_TRY(updateBufferStorage(context, newStorage, offset, size));
826     ANGLE_TRY(garbageCollection(context, BUFFER_USAGE_UNIFORM));
827     return newStorage;
828 }
829 
updateBufferStorage(const gl::Context * context,BufferStorage * storage,size_t sourceOffset,size_t storageSize)830 gl::Error Buffer11::updateBufferStorage(const gl::Context *context,
831                                         BufferStorage *storage,
832                                         size_t sourceOffset,
833                                         size_t storageSize)
834 {
835     BufferStorage *latestBuffer = nullptr;
836     ANGLE_TRY_RESULT(getLatestBufferStorage(context), latestBuffer);
837 
838     ASSERT(storage);
839 
840     if (!latestBuffer)
841     {
842         onStorageUpdate(storage);
843         return gl::NoError();
844     }
845 
846     if (latestBuffer->getDataRevision() <= storage->getDataRevision())
847     {
848         return gl::NoError();
849     }
850 
851     // Copy through a staging buffer if we're copying from or to a non-staging, mappable
852     // buffer storage. This is because we can't map a GPU buffer, and copy CPU
853     // data directly. If we're already using a staging buffer we're fine.
854     if (latestBuffer->getUsage() != BUFFER_USAGE_STAGING &&
855         storage->getUsage() != BUFFER_USAGE_STAGING &&
856         (!latestBuffer->isCPUAccessible(GL_MAP_READ_BIT) ||
857          !storage->isCPUAccessible(GL_MAP_WRITE_BIT)))
858     {
859         NativeStorage *stagingBuffer = nullptr;
860         ANGLE_TRY_RESULT(getStagingStorage(context), stagingBuffer);
861 
862         CopyResult copyResult = CopyResult::NOT_RECREATED;
863         ANGLE_TRY_RESULT(
864             stagingBuffer->copyFromStorage(context, latestBuffer, 0, latestBuffer->getSize(), 0),
865             copyResult);
866         onCopyStorage(stagingBuffer, latestBuffer);
867 
868         latestBuffer = stagingBuffer;
869     }
870 
871     CopyResult copyResult = CopyResult::NOT_RECREATED;
872     ANGLE_TRY_RESULT(storage->copyFromStorage(context, latestBuffer, sourceOffset, storageSize, 0),
873                      copyResult);
874     // If the D3D buffer has been recreated, we should update our serial.
875     if (copyResult == CopyResult::RECREATED)
876     {
877         updateSerial();
878     }
879     onCopyStorage(storage, latestBuffer);
880     return gl::NoError();
881 }
882 
getLatestBufferStorage(const gl::Context * context) const883 gl::ErrorOrResult<Buffer11::BufferStorage *> Buffer11::getLatestBufferStorage(
884     const gl::Context *context) const
885 {
886     // resize buffer
887     if (mLatestBufferStorage && mLatestBufferStorage->getSize() < mSize)
888     {
889         ANGLE_TRY(mLatestBufferStorage->resize(context, mSize, true));
890     }
891 
892     return mLatestBufferStorage;
893 }
894 
getStagingStorage(const gl::Context * context)895 gl::ErrorOrResult<Buffer11::NativeStorage *> Buffer11::getStagingStorage(const gl::Context *context)
896 {
897     BufferStorage *stagingStorage = nullptr;
898     ANGLE_TRY_RESULT(getBufferStorage(context, BUFFER_USAGE_STAGING), stagingStorage);
899     return GetAs<NativeStorage>(stagingStorage);
900 }
901 
getPackStorage(const gl::Context * context)902 gl::ErrorOrResult<Buffer11::PackStorage *> Buffer11::getPackStorage(const gl::Context *context)
903 {
904     BufferStorage *packStorage = nullptr;
905     ANGLE_TRY_RESULT(getBufferStorage(context, BUFFER_USAGE_PIXEL_PACK), packStorage);
906     return GetAs<PackStorage>(packStorage);
907 }
908 
getSize() const909 size_t Buffer11::getSize() const
910 {
911     return mSize;
912 }
913 
supportsDirectBinding() const914 bool Buffer11::supportsDirectBinding() const
915 {
916     // Do not support direct buffers for dynamic data. The streaming buffer
917     // offers better performance for data which changes every frame.
918     return (mUsage == D3DBufferUsage::STATIC);
919 }
920 
initializeStaticData(const gl::Context * context)921 void Buffer11::initializeStaticData(const gl::Context *context)
922 {
923     BufferD3D::initializeStaticData(context);
924 
925     // Notify when static data changes.
926     mStaticBroadcastChannel.signal(context);
927 }
928 
invalidateStaticData(const gl::Context * context)929 void Buffer11::invalidateStaticData(const gl::Context *context)
930 {
931     BufferD3D::invalidateStaticData(context);
932 
933     // Notify when static data changes.
934     mStaticBroadcastChannel.signal(context);
935 }
936 
getStaticBroadcastChannel()937 OnBufferDataDirtyChannel *Buffer11::getStaticBroadcastChannel()
938 {
939     return &mStaticBroadcastChannel;
940 }
941 
getDirectBroadcastChannel()942 OnBufferDataDirtyChannel *Buffer11::getDirectBroadcastChannel()
943 {
944     return &mDirectBroadcastChannel;
945 }
946 
onCopyStorage(BufferStorage * dest,BufferStorage * source)947 void Buffer11::onCopyStorage(BufferStorage *dest, BufferStorage *source)
948 {
949     ASSERT(source && mLatestBufferStorage);
950     dest->setDataRevision(source->getDataRevision());
951 
952     // Only update the latest buffer storage if our usage index is lower. See comment in header.
953     if (dest->getUsage() < mLatestBufferStorage->getUsage())
954     {
955         mLatestBufferStorage = dest;
956     }
957 }
958 
onStorageUpdate(BufferStorage * updatedStorage)959 void Buffer11::onStorageUpdate(BufferStorage *updatedStorage)
960 {
961     updatedStorage->setDataRevision(updatedStorage->getDataRevision() + 1);
962     mLatestBufferStorage = updatedStorage;
963 }
964 
965 // Buffer11::BufferStorage implementation
966 
BufferStorage(Renderer11 * renderer,BufferUsage usage)967 Buffer11::BufferStorage::BufferStorage(Renderer11 *renderer, BufferUsage usage)
968     : mRenderer(renderer), mRevision(0), mUsage(usage), mBufferSize(0)
969 {
970 }
971 
setData(const uint8_t * data,size_t offset,size_t size)972 gl::Error Buffer11::BufferStorage::setData(const uint8_t *data, size_t offset, size_t size)
973 {
974     ASSERT(isCPUAccessible(GL_MAP_WRITE_BIT));
975 
976     // Uniform storage can have a different internal size than the buffer size. Ensure we don't
977     // overflow.
978     size_t mapSize = std::min(size, mBufferSize - offset);
979 
980     uint8_t *writePointer = nullptr;
981     ANGLE_TRY(map(offset, mapSize, GL_MAP_WRITE_BIT, &writePointer));
982 
983     memcpy(writePointer, data, mapSize);
984 
985     unmap();
986 
987     return gl::NoError();
988 }
989 
990 // Buffer11::NativeStorage implementation
991 
NativeStorage(Renderer11 * renderer,BufferUsage usage,const OnBufferDataDirtyChannel * onStorageChanged)992 Buffer11::NativeStorage::NativeStorage(Renderer11 *renderer,
993                                        BufferUsage usage,
994                                        const OnBufferDataDirtyChannel *onStorageChanged)
995     : BufferStorage(renderer, usage), mBuffer(), mOnStorageChanged(onStorageChanged)
996 {
997 }
998 
~NativeStorage()999 Buffer11::NativeStorage::~NativeStorage()
1000 {
1001     clearSRVs();
1002 }
1003 
isCPUAccessible(GLbitfield access) const1004 bool Buffer11::NativeStorage::isCPUAccessible(GLbitfield access) const
1005 {
1006     if ((access & GL_MAP_READ_BIT) != 0)
1007     {
1008         // Read is more exclusive than write mappability.
1009         return (mUsage == BUFFER_USAGE_STAGING);
1010     }
1011     ASSERT((access & GL_MAP_WRITE_BIT) != 0);
1012     return (mUsage == BUFFER_USAGE_STAGING || mUsage == BUFFER_USAGE_UNIFORM);
1013 }
1014 
1015 // Returns true if it recreates the direct buffer
copyFromStorage(const gl::Context * context,BufferStorage * source,size_t sourceOffset,size_t size,size_t destOffset)1016 gl::ErrorOrResult<CopyResult> Buffer11::NativeStorage::copyFromStorage(const gl::Context *context,
1017                                                                        BufferStorage *source,
1018                                                                        size_t sourceOffset,
1019                                                                        size_t size,
1020                                                                        size_t destOffset)
1021 {
1022     size_t requiredSize = destOffset + size;
1023     bool createBuffer   = !mBuffer.valid() || mBufferSize < requiredSize;
1024 
1025     // (Re)initialize D3D buffer if needed
1026     bool preserveData = (destOffset > 0);
1027     if (createBuffer)
1028     {
1029         ANGLE_TRY(resize(context, requiredSize, preserveData));
1030     }
1031 
1032     size_t clampedSize = size;
1033     if (mUsage == BUFFER_USAGE_UNIFORM)
1034     {
1035         clampedSize = std::min(clampedSize, mBufferSize - destOffset);
1036     }
1037 
1038     if (source->getUsage() == BUFFER_USAGE_PIXEL_PACK ||
1039         source->getUsage() == BUFFER_USAGE_SYSTEM_MEMORY)
1040     {
1041         ASSERT(source->isCPUAccessible(GL_MAP_READ_BIT) && isCPUAccessible(GL_MAP_WRITE_BIT));
1042 
1043         // Uniform buffers must be mapped with write/discard.
1044         ASSERT(!(preserveData && mUsage == BUFFER_USAGE_UNIFORM));
1045 
1046         uint8_t *sourcePointer = nullptr;
1047         ANGLE_TRY(source->map(sourceOffset, clampedSize, GL_MAP_READ_BIT, &sourcePointer));
1048 
1049         auto err = setData(sourcePointer, destOffset, clampedSize);
1050         source->unmap();
1051         ANGLE_TRY(err);
1052     }
1053     else
1054     {
1055         D3D11_BOX srcBox;
1056         srcBox.left   = static_cast<unsigned int>(sourceOffset);
1057         srcBox.right  = static_cast<unsigned int>(sourceOffset + clampedSize);
1058         srcBox.top    = 0;
1059         srcBox.bottom = 1;
1060         srcBox.front  = 0;
1061         srcBox.back   = 1;
1062 
1063         const d3d11::Buffer *sourceBuffer = &GetAs<NativeStorage>(source)->getBuffer();
1064 
1065         ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
1066         deviceContext->CopySubresourceRegion(mBuffer.get(), 0,
1067                                              static_cast<unsigned int>(destOffset), 0, 0,
1068                                              sourceBuffer->get(), 0, &srcBox);
1069     }
1070 
1071     return createBuffer ? CopyResult::RECREATED : CopyResult::NOT_RECREATED;
1072 }
1073 
resize(const gl::Context * context,size_t size,bool preserveData)1074 gl::Error Buffer11::NativeStorage::resize(const gl::Context *context,
1075                                           size_t size,
1076                                           bool preserveData)
1077 {
1078     D3D11_BUFFER_DESC bufferDesc;
1079     FillBufferDesc(&bufferDesc, mRenderer, mUsage, static_cast<unsigned int>(size));
1080 
1081     d3d11::Buffer newBuffer;
1082     ANGLE_TRY(mRenderer->allocateResource(bufferDesc, &newBuffer));
1083     newBuffer.setDebugName("Buffer11::NativeStorage");
1084 
1085     if (mBuffer.valid() && preserveData)
1086     {
1087         // We don't call resize if the buffer is big enough already.
1088         ASSERT(mBufferSize <= size);
1089 
1090         D3D11_BOX srcBox;
1091         srcBox.left   = 0;
1092         srcBox.right  = static_cast<unsigned int>(mBufferSize);
1093         srcBox.top    = 0;
1094         srcBox.bottom = 1;
1095         srcBox.front  = 0;
1096         srcBox.back   = 1;
1097 
1098         ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
1099         deviceContext->CopySubresourceRegion(newBuffer.get(), 0, 0, 0, 0, mBuffer.get(), 0,
1100                                              &srcBox);
1101     }
1102 
1103     // No longer need the old buffer
1104     mBuffer = std::move(newBuffer);
1105 
1106     mBufferSize = bufferDesc.ByteWidth;
1107 
1108     // Free the SRVs.
1109     clearSRVs();
1110 
1111     // Notify that the storage has changed.
1112     if (mOnStorageChanged)
1113     {
1114         mOnStorageChanged->signal(context);
1115     }
1116 
1117     return gl::NoError();
1118 }
1119 
1120 // static
FillBufferDesc(D3D11_BUFFER_DESC * bufferDesc,Renderer11 * renderer,BufferUsage usage,unsigned int bufferSize)1121 void Buffer11::NativeStorage::FillBufferDesc(D3D11_BUFFER_DESC *bufferDesc,
1122                                              Renderer11 *renderer,
1123                                              BufferUsage usage,
1124                                              unsigned int bufferSize)
1125 {
1126     bufferDesc->ByteWidth           = bufferSize;
1127     bufferDesc->MiscFlags           = 0;
1128     bufferDesc->StructureByteStride = 0;
1129 
1130     switch (usage)
1131     {
1132         case BUFFER_USAGE_STAGING:
1133             bufferDesc->Usage          = D3D11_USAGE_STAGING;
1134             bufferDesc->BindFlags      = 0;
1135             bufferDesc->CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
1136             break;
1137 
1138         case BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK:
1139             bufferDesc->Usage     = D3D11_USAGE_DEFAULT;
1140             bufferDesc->BindFlags = D3D11_BIND_VERTEX_BUFFER;
1141 
1142             if (renderer->isES3Capable())
1143             {
1144                 bufferDesc->BindFlags |= D3D11_BIND_STREAM_OUTPUT;
1145             }
1146 
1147             bufferDesc->CPUAccessFlags = 0;
1148             break;
1149 
1150         case BUFFER_USAGE_INDEX:
1151             bufferDesc->Usage          = D3D11_USAGE_DEFAULT;
1152             bufferDesc->BindFlags      = D3D11_BIND_INDEX_BUFFER;
1153             bufferDesc->CPUAccessFlags = 0;
1154             break;
1155 
1156         case BUFFER_USAGE_INDIRECT:
1157             bufferDesc->MiscFlags      = D3D11_RESOURCE_MISC_DRAWINDIRECT_ARGS;
1158             bufferDesc->Usage          = D3D11_USAGE_DEFAULT;
1159             bufferDesc->BindFlags      = 0;
1160             bufferDesc->CPUAccessFlags = 0;
1161             break;
1162 
1163         case BUFFER_USAGE_PIXEL_UNPACK:
1164             bufferDesc->Usage          = D3D11_USAGE_DEFAULT;
1165             bufferDesc->BindFlags      = D3D11_BIND_SHADER_RESOURCE;
1166             bufferDesc->CPUAccessFlags = 0;
1167             break;
1168 
1169         case BUFFER_USAGE_UNIFORM:
1170             bufferDesc->Usage          = D3D11_USAGE_DYNAMIC;
1171             bufferDesc->BindFlags      = D3D11_BIND_CONSTANT_BUFFER;
1172             bufferDesc->CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
1173 
1174             // Constant buffers must be of a limited size, and aligned to 16 byte boundaries
1175             // For our purposes we ignore any buffer data past the maximum constant buffer size
1176             bufferDesc->ByteWidth = roundUp(bufferDesc->ByteWidth, 16u);
1177 
1178             // Note: it seems that D3D11 allows larger buffers on some platforms, but not all.
1179             // (Windows 10 seems to allow larger constant buffers, but not Windows 7)
1180             bufferDesc->ByteWidth =
1181                 std::min<UINT>(bufferDesc->ByteWidth,
1182                                static_cast<UINT>(renderer->getNativeCaps().maxUniformBlockSize));
1183             break;
1184 
1185         default:
1186             UNREACHABLE();
1187     }
1188 }
1189 
map(size_t offset,size_t length,GLbitfield access,uint8_t ** mapPointerOut)1190 gl::Error Buffer11::NativeStorage::map(size_t offset,
1191                                        size_t length,
1192                                        GLbitfield access,
1193                                        uint8_t **mapPointerOut)
1194 {
1195     ASSERT(isCPUAccessible(access));
1196 
1197     D3D11_MAPPED_SUBRESOURCE mappedResource;
1198     ID3D11DeviceContext *context = mRenderer->getDeviceContext();
1199     D3D11_MAP d3dMapType         = gl_d3d11::GetD3DMapTypeFromBits(mUsage, access);
1200     UINT d3dMapFlag = ((access & GL_MAP_UNSYNCHRONIZED_BIT) != 0 ? D3D11_MAP_FLAG_DO_NOT_WAIT : 0);
1201 
1202     HRESULT result = context->Map(mBuffer.get(), 0, d3dMapType, d3dMapFlag, &mappedResource);
1203     ASSERT(SUCCEEDED(result));
1204     if (FAILED(result))
1205     {
1206         return gl::OutOfMemory() << "Failed to map native storage in Buffer11::NativeStorage::map";
1207     }
1208     ASSERT(mappedResource.pData);
1209     *mapPointerOut = static_cast<uint8_t *>(mappedResource.pData) + offset;
1210     return gl::NoError();
1211 }
1212 
unmap()1213 void Buffer11::NativeStorage::unmap()
1214 {
1215     ASSERT(isCPUAccessible(GL_MAP_WRITE_BIT) || isCPUAccessible(GL_MAP_READ_BIT));
1216     ID3D11DeviceContext *context = mRenderer->getDeviceContext();
1217     context->Unmap(mBuffer.get(), 0);
1218 }
1219 
getSRVForFormat(DXGI_FORMAT srvFormat)1220 gl::ErrorOrResult<const d3d11::ShaderResourceView *> Buffer11::NativeStorage::getSRVForFormat(
1221     DXGI_FORMAT srvFormat)
1222 {
1223     auto bufferSRVIt = mBufferResourceViews.find(srvFormat);
1224 
1225     if (bufferSRVIt != mBufferResourceViews.end())
1226     {
1227         return &bufferSRVIt->second;
1228     }
1229 
1230     const d3d11::DXGIFormatSize &dxgiFormatInfo = d3d11::GetDXGIFormatSizeInfo(srvFormat);
1231 
1232     D3D11_SHADER_RESOURCE_VIEW_DESC bufferSRVDesc;
1233     bufferSRVDesc.Buffer.ElementOffset = 0;
1234     bufferSRVDesc.Buffer.ElementWidth  = static_cast<UINT>(mBufferSize) / dxgiFormatInfo.pixelBytes;
1235     bufferSRVDesc.ViewDimension        = D3D11_SRV_DIMENSION_BUFFER;
1236     bufferSRVDesc.Format               = srvFormat;
1237 
1238     ANGLE_TRY(mRenderer->allocateResource(bufferSRVDesc, mBuffer.get(),
1239                                           &mBufferResourceViews[srvFormat]));
1240 
1241     return &mBufferResourceViews[srvFormat];
1242 }
1243 
clearSRVs()1244 void Buffer11::NativeStorage::clearSRVs()
1245 {
1246     mBufferResourceViews.clear();
1247 }
1248 
1249 // Buffer11::EmulatedIndexStorage implementation
1250 
EmulatedIndexedStorage(Renderer11 * renderer)1251 Buffer11::EmulatedIndexedStorage::EmulatedIndexedStorage(Renderer11 *renderer)
1252     : BufferStorage(renderer, BUFFER_USAGE_EMULATED_INDEXED_VERTEX), mBuffer()
1253 {
1254 }
1255 
~EmulatedIndexedStorage()1256 Buffer11::EmulatedIndexedStorage::~EmulatedIndexedStorage()
1257 {
1258 }
1259 
getBuffer(SourceIndexData * indexInfo,const TranslatedAttribute & attribute,GLint startVertex)1260 gl::ErrorOrResult<const d3d11::Buffer *> Buffer11::EmulatedIndexedStorage::getBuffer(
1261     SourceIndexData *indexInfo,
1262     const TranslatedAttribute &attribute,
1263     GLint startVertex)
1264 {
1265     // If a change in the indices applied from the last draw call is detected, then the emulated
1266     // indexed buffer needs to be invalidated.  After invalidation, the change detected flag should
1267     // be cleared to avoid unnecessary recreation of the buffer.
1268     if (!mBuffer.valid() || indexInfo->srcIndicesChanged)
1269     {
1270         mBuffer.reset();
1271 
1272         // Copy the source index data. This ensures that the lifetime of the indices pointer
1273         // stays with this storage until the next time we invalidate.
1274         size_t indicesDataSize = 0;
1275         switch (indexInfo->srcIndexType)
1276         {
1277             case GL_UNSIGNED_INT:
1278                 indicesDataSize = sizeof(GLuint) * indexInfo->srcCount;
1279                 break;
1280             case GL_UNSIGNED_SHORT:
1281                 indicesDataSize = sizeof(GLushort) * indexInfo->srcCount;
1282                 break;
1283             case GL_UNSIGNED_BYTE:
1284                 indicesDataSize = sizeof(GLubyte) * indexInfo->srcCount;
1285                 break;
1286             default:
1287                 indicesDataSize = sizeof(GLushort) * indexInfo->srcCount;
1288                 break;
1289         }
1290 
1291         if (!mIndicesMemoryBuffer.resize(indicesDataSize))
1292         {
1293             return gl::OutOfMemory() << "Error resizing index memory buffer in "
1294                                         "Buffer11::EmulatedIndexedStorage::getBuffer";
1295         }
1296 
1297         memcpy(mIndicesMemoryBuffer.data(), indexInfo->srcIndices, indicesDataSize);
1298 
1299         indexInfo->srcIndicesChanged = false;
1300     }
1301 
1302     if (!mBuffer.valid())
1303     {
1304         unsigned int offset = 0;
1305         ANGLE_TRY_RESULT(attribute.computeOffset(startVertex), offset);
1306 
1307         // Expand the memory storage upon request and cache the results.
1308         unsigned int expandedDataSize =
1309             static_cast<unsigned int>((indexInfo->srcCount * attribute.stride) + offset);
1310         angle::MemoryBuffer expandedData;
1311         if (!expandedData.resize(expandedDataSize))
1312         {
1313             return gl::OutOfMemory()
1314                    << "Error resizing buffer in Buffer11::EmulatedIndexedStorage::getBuffer";
1315         }
1316 
1317         // Clear the contents of the allocated buffer
1318         ZeroMemory(expandedData.data(), expandedDataSize);
1319 
1320         uint8_t *curr      = expandedData.data();
1321         const uint8_t *ptr = static_cast<const uint8_t *>(indexInfo->srcIndices);
1322 
1323         // Ensure that we start in the correct place for the emulated data copy operation to
1324         // maintain offset behaviors.
1325         curr += offset;
1326 
1327         ReadIndexValueFunction readIndexValue = ReadIndexValueFromIndices<GLushort>;
1328 
1329         switch (indexInfo->srcIndexType)
1330         {
1331             case GL_UNSIGNED_INT:
1332                 readIndexValue = ReadIndexValueFromIndices<GLuint>;
1333                 break;
1334             case GL_UNSIGNED_SHORT:
1335                 readIndexValue = ReadIndexValueFromIndices<GLushort>;
1336                 break;
1337             case GL_UNSIGNED_BYTE:
1338                 readIndexValue = ReadIndexValueFromIndices<GLubyte>;
1339                 break;
1340         }
1341 
1342         // Iterate over the cached index data and copy entries indicated into the emulated buffer.
1343         for (GLuint i = 0; i < indexInfo->srcCount; i++)
1344         {
1345             GLuint idx = readIndexValue(ptr, i);
1346             memcpy(curr, mMemoryBuffer.data() + (attribute.stride * idx), attribute.stride);
1347             curr += attribute.stride;
1348         }
1349 
1350         // Finally, initialize the emulated indexed native storage object with the newly copied data
1351         // and free the temporary buffers used.
1352         D3D11_BUFFER_DESC bufferDesc;
1353         bufferDesc.ByteWidth           = expandedDataSize;
1354         bufferDesc.MiscFlags           = 0;
1355         bufferDesc.StructureByteStride = 0;
1356         bufferDesc.Usage               = D3D11_USAGE_DEFAULT;
1357         bufferDesc.BindFlags           = D3D11_BIND_VERTEX_BUFFER;
1358         bufferDesc.CPUAccessFlags      = 0;
1359 
1360         D3D11_SUBRESOURCE_DATA subResourceData = {expandedData.data(), 0, 0};
1361 
1362         ANGLE_TRY(mRenderer->allocateResource(bufferDesc, &subResourceData, &mBuffer));
1363         mBuffer.setDebugName("Buffer11::EmulatedIndexedStorage");
1364     }
1365 
1366     return &mBuffer;
1367 }
1368 
copyFromStorage(const gl::Context * context,BufferStorage * source,size_t sourceOffset,size_t size,size_t destOffset)1369 gl::ErrorOrResult<CopyResult> Buffer11::EmulatedIndexedStorage::copyFromStorage(
1370     const gl::Context *context,
1371     BufferStorage *source,
1372     size_t sourceOffset,
1373     size_t size,
1374     size_t destOffset)
1375 {
1376     ASSERT(source->isCPUAccessible(GL_MAP_READ_BIT));
1377     uint8_t *sourceData = nullptr;
1378     ANGLE_TRY(source->map(sourceOffset, size, GL_MAP_READ_BIT, &sourceData));
1379     ASSERT(destOffset + size <= mMemoryBuffer.size());
1380     memcpy(mMemoryBuffer.data() + destOffset, sourceData, size);
1381     source->unmap();
1382     return CopyResult::RECREATED;
1383 }
1384 
resize(const gl::Context * context,size_t size,bool preserveData)1385 gl::Error Buffer11::EmulatedIndexedStorage::resize(const gl::Context *context,
1386                                                    size_t size,
1387                                                    bool preserveData)
1388 {
1389     if (mMemoryBuffer.size() < size)
1390     {
1391         if (!mMemoryBuffer.resize(size))
1392         {
1393             return gl::OutOfMemory() << "Failed to resize EmulatedIndexedStorage";
1394         }
1395         mBufferSize = size;
1396     }
1397 
1398     return gl::NoError();
1399 }
1400 
map(size_t offset,size_t length,GLbitfield access,uint8_t ** mapPointerOut)1401 gl::Error Buffer11::EmulatedIndexedStorage::map(size_t offset,
1402                                                 size_t length,
1403                                                 GLbitfield access,
1404                                                 uint8_t **mapPointerOut)
1405 {
1406     ASSERT(!mMemoryBuffer.empty() && offset + length <= mMemoryBuffer.size());
1407     *mapPointerOut = mMemoryBuffer.data() + offset;
1408     return gl::NoError();
1409 }
1410 
unmap()1411 void Buffer11::EmulatedIndexedStorage::unmap()
1412 {
1413     // No-op
1414 }
1415 
1416 // Buffer11::PackStorage implementation
1417 
PackStorage(Renderer11 * renderer)1418 Buffer11::PackStorage::PackStorage(Renderer11 *renderer)
1419     : BufferStorage(renderer, BUFFER_USAGE_PIXEL_PACK), mStagingTexture(), mDataModified(false)
1420 {
1421 }
1422 
~PackStorage()1423 Buffer11::PackStorage::~PackStorage()
1424 {
1425 }
1426 
copyFromStorage(const gl::Context * context,BufferStorage * source,size_t sourceOffset,size_t size,size_t destOffset)1427 gl::ErrorOrResult<CopyResult> Buffer11::PackStorage::copyFromStorage(const gl::Context *context,
1428                                                                      BufferStorage *source,
1429                                                                      size_t sourceOffset,
1430                                                                      size_t size,
1431                                                                      size_t destOffset)
1432 {
1433     ANGLE_TRY(flushQueuedPackCommand());
1434 
1435     // For all use cases of pack buffers, we must copy through a readable buffer.
1436     ASSERT(source->isCPUAccessible(GL_MAP_READ_BIT));
1437     uint8_t *sourceData = nullptr;
1438     ANGLE_TRY(source->map(sourceOffset, size, GL_MAP_READ_BIT, &sourceData));
1439     ASSERT(destOffset + size <= mMemoryBuffer.size());
1440     memcpy(mMemoryBuffer.data() + destOffset, sourceData, size);
1441     source->unmap();
1442     return CopyResult::NOT_RECREATED;
1443 }
1444 
resize(const gl::Context * context,size_t size,bool preserveData)1445 gl::Error Buffer11::PackStorage::resize(const gl::Context *context, size_t size, bool preserveData)
1446 {
1447     if (size != mBufferSize)
1448     {
1449         if (!mMemoryBuffer.resize(size))
1450         {
1451             return gl::OutOfMemory() << "Failed to resize internal buffer storage.";
1452         }
1453         mBufferSize = size;
1454     }
1455 
1456     return gl::NoError();
1457 }
1458 
map(size_t offset,size_t length,GLbitfield access,uint8_t ** mapPointerOut)1459 gl::Error Buffer11::PackStorage::map(size_t offset,
1460                                      size_t length,
1461                                      GLbitfield access,
1462                                      uint8_t **mapPointerOut)
1463 {
1464     ASSERT(offset + length <= getSize());
1465     // TODO: fast path
1466     //  We might be able to optimize out one or more memcpy calls by detecting when
1467     //  and if D3D packs the staging texture memory identically to how we would fill
1468     //  the pack buffer according to the current pack state.
1469 
1470     ANGLE_TRY(flushQueuedPackCommand());
1471 
1472     mDataModified = (mDataModified || (access & GL_MAP_WRITE_BIT) != 0);
1473 
1474     *mapPointerOut = mMemoryBuffer.data() + offset;
1475     return gl::NoError();
1476 }
1477 
unmap()1478 void Buffer11::PackStorage::unmap()
1479 {
1480     // No-op
1481 }
1482 
packPixels(const gl::Context * context,const gl::FramebufferAttachment & readAttachment,const PackPixelsParams & params)1483 gl::Error Buffer11::PackStorage::packPixels(const gl::Context *context,
1484                                             const gl::FramebufferAttachment &readAttachment,
1485                                             const PackPixelsParams &params)
1486 {
1487     ANGLE_TRY(flushQueuedPackCommand());
1488 
1489     RenderTarget11 *renderTarget = nullptr;
1490     ANGLE_TRY(readAttachment.getRenderTarget(context, &renderTarget));
1491 
1492     const TextureHelper11 &srcTexture = renderTarget->getTexture();
1493     ASSERT(srcTexture.valid());
1494     unsigned int srcSubresource = renderTarget->getSubresourceIndex();
1495 
1496     mQueuedPackCommand.reset(new PackPixelsParams(params));
1497 
1498     gl::Extents srcTextureSize(params.area.width, params.area.height, 1);
1499     if (!mStagingTexture.get() || mStagingTexture.getFormat() != srcTexture.getFormat() ||
1500         mStagingTexture.getExtents() != srcTextureSize)
1501     {
1502         ANGLE_TRY_RESULT(
1503             mRenderer->createStagingTexture(srcTexture.getTextureType(), srcTexture.getFormatSet(),
1504                                             srcTextureSize, StagingAccess::READ),
1505             mStagingTexture);
1506     }
1507 
1508     // ReadPixels from multisampled FBOs isn't supported in current GL
1509     ASSERT(srcTexture.getSampleCount() <= 1);
1510 
1511     ID3D11DeviceContext *immediateContext = mRenderer->getDeviceContext();
1512     D3D11_BOX srcBox;
1513     srcBox.left   = params.area.x;
1514     srcBox.right  = params.area.x + params.area.width;
1515     srcBox.top    = params.area.y;
1516     srcBox.bottom = params.area.y + params.area.height;
1517 
1518     // Select the correct layer from a 3D attachment
1519     srcBox.front = 0;
1520     if (mStagingTexture.is3D())
1521     {
1522         srcBox.front = static_cast<UINT>(readAttachment.layer());
1523     }
1524     srcBox.back = srcBox.front + 1;
1525 
1526     // Asynchronous copy
1527     immediateContext->CopySubresourceRegion(mStagingTexture.get(), 0, 0, 0, 0, srcTexture.get(),
1528                                             srcSubresource, &srcBox);
1529 
1530     return gl::NoError();
1531 }
1532 
flushQueuedPackCommand()1533 gl::Error Buffer11::PackStorage::flushQueuedPackCommand()
1534 {
1535     ASSERT(mMemoryBuffer.size() > 0);
1536 
1537     if (mQueuedPackCommand)
1538     {
1539         ANGLE_TRY(
1540             mRenderer->packPixels(mStagingTexture, *mQueuedPackCommand, mMemoryBuffer.data()));
1541         mQueuedPackCommand.reset(nullptr);
1542     }
1543 
1544     return gl::NoError();
1545 }
1546 
1547 // Buffer11::SystemMemoryStorage implementation
1548 
SystemMemoryStorage(Renderer11 * renderer)1549 Buffer11::SystemMemoryStorage::SystemMemoryStorage(Renderer11 *renderer)
1550     : Buffer11::BufferStorage(renderer, BUFFER_USAGE_SYSTEM_MEMORY)
1551 {
1552 }
1553 
copyFromStorage(const gl::Context * context,BufferStorage * source,size_t sourceOffset,size_t size,size_t destOffset)1554 gl::ErrorOrResult<CopyResult> Buffer11::SystemMemoryStorage::copyFromStorage(
1555     const gl::Context *context,
1556     BufferStorage *source,
1557     size_t sourceOffset,
1558     size_t size,
1559     size_t destOffset)
1560 {
1561     ASSERT(source->isCPUAccessible(GL_MAP_READ_BIT));
1562     uint8_t *sourceData = nullptr;
1563     ANGLE_TRY(source->map(sourceOffset, size, GL_MAP_READ_BIT, &sourceData));
1564     ASSERT(destOffset + size <= mSystemCopy.size());
1565     memcpy(mSystemCopy.data() + destOffset, sourceData, size);
1566     source->unmap();
1567     return CopyResult::RECREATED;
1568 }
1569 
resize(const gl::Context * context,size_t size,bool preserveData)1570 gl::Error Buffer11::SystemMemoryStorage::resize(const gl::Context *context,
1571                                                 size_t size,
1572                                                 bool preserveData)
1573 {
1574     if (mSystemCopy.size() < size)
1575     {
1576         if (!mSystemCopy.resize(size))
1577         {
1578             return gl::OutOfMemory() << "Failed to resize SystemMemoryStorage";
1579         }
1580         mBufferSize = size;
1581     }
1582 
1583     return gl::NoError();
1584 }
1585 
map(size_t offset,size_t length,GLbitfield access,uint8_t ** mapPointerOut)1586 gl::Error Buffer11::SystemMemoryStorage::map(size_t offset,
1587                                              size_t length,
1588                                              GLbitfield access,
1589                                              uint8_t **mapPointerOut)
1590 {
1591     ASSERT(!mSystemCopy.empty() && offset + length <= mSystemCopy.size());
1592     *mapPointerOut = mSystemCopy.data() + offset;
1593     return gl::NoError();
1594 }
1595 
unmap()1596 void Buffer11::SystemMemoryStorage::unmap()
1597 {
1598     // No-op
1599 }
1600 }  // namespace rx
1601