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