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::roundUp(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                 ANGLE_TRY(getBufferStorage(context, BUFFER_USAGE_UNIFORM, &writeBuffer));
430             }
431             else
432             {
433                 ANGLE_TRY(getBufferStorage(context, BUFFER_USAGE_SYSTEM_MEMORY, &writeBuffer));
434             }
435         }
436         else if (supportsDirectBinding())
437         {
438             ANGLE_TRY(getStagingStorage(context, &writeBuffer));
439         }
440         else
441         {
442             ANGLE_TRY(getBufferStorage(context, BUFFER_USAGE_SYSTEM_MEMORY, &writeBuffer));
443         }
444 
445         ASSERT(writeBuffer);
446 
447         // Explicitly resize the staging buffer, preserving data if the new data will not
448         // completely fill the buffer
449         if (writeBuffer->getSize() < requiredSize)
450         {
451             bool preserveData = (offset > 0);
452             ANGLE_TRY(writeBuffer->resize(context, requiredSize, preserveData));
453         }
454 
455         ANGLE_TRY(writeBuffer->setData(context, static_cast<const uint8_t *>(data), offset, size));
456         onStorageUpdate(writeBuffer);
457     }
458 
459     mSize = std::max(mSize, requiredSize);
460     invalidateStaticData(context);
461 
462     return angle::Result::Continue;
463 }
464 
copySubData(const gl::Context * context,BufferImpl * source,GLintptr sourceOffset,GLintptr destOffset,GLsizeiptr size)465 angle::Result Buffer11::copySubData(const gl::Context *context,
466                                     BufferImpl *source,
467                                     GLintptr sourceOffset,
468                                     GLintptr destOffset,
469                                     GLsizeiptr size)
470 {
471     Buffer11 *sourceBuffer = GetAs<Buffer11>(source);
472     ASSERT(sourceBuffer != nullptr);
473 
474     BufferStorage *copyDest = nullptr;
475     ANGLE_TRY(getLatestBufferStorage(context, &copyDest));
476 
477     if (!copyDest)
478     {
479         ANGLE_TRY(getStagingStorage(context, &copyDest));
480     }
481 
482     BufferStorage *copySource = nullptr;
483     ANGLE_TRY(sourceBuffer->getLatestBufferStorage(context, &copySource));
484 
485     if (!copySource)
486     {
487         ANGLE_TRY(sourceBuffer->getStagingStorage(context, &copySource));
488     }
489 
490     ASSERT(copySource && copyDest);
491 
492     // A staging buffer is needed if there is no cpu-cpu or gpu-gpu copy path avaiable.
493     if (!copyDest->isGPUAccessible() && !copySource->isCPUAccessible(GL_MAP_READ_BIT))
494     {
495         ANGLE_TRY(sourceBuffer->getStagingStorage(context, &copySource));
496     }
497     else if (!copySource->isGPUAccessible() && !copyDest->isCPUAccessible(GL_MAP_WRITE_BIT))
498     {
499         ANGLE_TRY(getStagingStorage(context, &copyDest));
500     }
501 
502     // D3D11 does not allow overlapped copies until 11.1, and only if the
503     // device supports D3D11_FEATURE_DATA_D3D11_OPTIONS::CopyWithOverlap
504     // Get around this via a different source buffer
505     if (copySource == copyDest)
506     {
507         if (copySource->getUsage() == BUFFER_USAGE_STAGING)
508         {
509             ANGLE_TRY(
510                 getBufferStorage(context, BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK, &copySource));
511         }
512         else
513         {
514             ANGLE_TRY(getStagingStorage(context, &copySource));
515         }
516     }
517 
518     CopyResult copyResult = CopyResult::NOT_RECREATED;
519     ANGLE_TRY(copyDest->copyFromStorage(context, copySource, sourceOffset, size, destOffset,
520                                         &copyResult));
521     onStorageUpdate(copyDest);
522 
523     mSize = std::max<size_t>(mSize, destOffset + size);
524     invalidateStaticData(context);
525 
526     return angle::Result::Continue;
527 }
528 
map(const gl::Context * context,GLenum access,void ** mapPtr)529 angle::Result Buffer11::map(const gl::Context *context, GLenum access, void **mapPtr)
530 {
531     // GL_OES_mapbuffer uses an enum instead of a bitfield for it's access, convert to a bitfield
532     // and call mapRange.
533     ASSERT(access == GL_WRITE_ONLY_OES);
534     return mapRange(context, 0, mSize, GL_MAP_WRITE_BIT, mapPtr);
535 }
536 
mapRange(const gl::Context * context,size_t offset,size_t length,GLbitfield access,void ** mapPtr)537 angle::Result Buffer11::mapRange(const gl::Context *context,
538                                  size_t offset,
539                                  size_t length,
540                                  GLbitfield access,
541                                  void **mapPtr)
542 {
543     ASSERT(!mMappedStorage);
544 
545     BufferStorage *latestStorage = nullptr;
546     ANGLE_TRY(getLatestBufferStorage(context, &latestStorage));
547 
548     if (latestStorage && (latestStorage->getUsage() == BUFFER_USAGE_PIXEL_PACK ||
549                           latestStorage->getUsage() == BUFFER_USAGE_STAGING))
550     {
551         // Latest storage is mappable.
552         mMappedStorage = latestStorage;
553     }
554     else
555     {
556         // Fall back to using the staging buffer if the latest storage does not exist or is not
557         // CPU-accessible.
558         ANGLE_TRY(getStagingStorage(context, &mMappedStorage));
559     }
560 
561     Context11 *context11 = GetImplAs<Context11>(context);
562     ANGLE_CHECK_GL_ALLOC(context11, mMappedStorage);
563 
564     if ((access & GL_MAP_WRITE_BIT) > 0)
565     {
566         // Update the data revision immediately, since the data might be changed at any time
567         onStorageUpdate(mMappedStorage);
568         invalidateStaticData(context);
569     }
570 
571     uint8_t *mappedBuffer = nullptr;
572     ANGLE_TRY(mMappedStorage->map(context, offset, length, access, &mappedBuffer));
573     ASSERT(mappedBuffer);
574 
575     *mapPtr = static_cast<void *>(mappedBuffer);
576     return angle::Result::Continue;
577 }
578 
unmap(const gl::Context * context,GLboolean * result)579 angle::Result Buffer11::unmap(const gl::Context *context, GLboolean *result)
580 {
581     ASSERT(mMappedStorage);
582     mMappedStorage->unmap();
583     mMappedStorage = nullptr;
584 
585     // TODO: detect if we had corruption. if so, return false.
586     *result = GL_TRUE;
587 
588     return angle::Result::Continue;
589 }
590 
markTransformFeedbackUsage(const gl::Context * context)591 angle::Result Buffer11::markTransformFeedbackUsage(const gl::Context *context)
592 {
593     ANGLE_TRY(markBufferUsage(context, BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK));
594     return angle::Result::Continue;
595 }
596 
updateDeallocThreshold(BufferUsage usage)597 void Buffer11::updateDeallocThreshold(BufferUsage usage)
598 {
599     // The following strategy was tuned on the Oort online benchmark (http://oortonline.gl/)
600     // as well as a custom microbenchmark (IndexConversionPerfTest.Run/index_range_d3d11)
601 
602     // First readback: 8 unmodified uses before we free buffer memory.
603     // After that, double the threshold each time until we reach the max.
604     if (mDeallocThresholds[usage] == 0)
605     {
606         mDeallocThresholds[usage] = 8;
607     }
608     else if (mDeallocThresholds[usage] < std::numeric_limits<unsigned int>::max() / 2u)
609     {
610         mDeallocThresholds[usage] *= 2u;
611     }
612     else
613     {
614         mDeallocThresholds[usage] = std::numeric_limits<unsigned int>::max();
615     }
616 }
617 
618 // Free the storage if we decide it isn't being used very often.
checkForDeallocation(const gl::Context * context,BufferUsage usage)619 angle::Result Buffer11::checkForDeallocation(const gl::Context *context, BufferUsage usage)
620 {
621     mIdleness[usage]++;
622 
623     BufferStorage *&storage = mBufferStorages[usage];
624     if (storage != nullptr && mIdleness[usage] > mDeallocThresholds[usage])
625     {
626         BufferStorage *latestStorage = nullptr;
627         ANGLE_TRY(getLatestBufferStorage(context, &latestStorage));
628         if (latestStorage != storage)
629         {
630             SafeDelete(storage);
631         }
632     }
633 
634     return angle::Result::Continue;
635 }
636 
637 // Keep system memory when we are using it for the canonical version of data.
canDeallocateSystemMemory() const638 bool Buffer11::canDeallocateSystemMemory() const
639 {
640     // Must keep system memory on Intel.
641     if (mRenderer->getFeatures().useSystemMemoryForConstantBuffers.enabled)
642     {
643         return false;
644     }
645 
646     return (!mBufferStorages[BUFFER_USAGE_UNIFORM] ||
647             mSize <= static_cast<size_t>(mRenderer->getNativeCaps().maxUniformBlockSize));
648 }
649 
markBufferUsage(BufferUsage usage)650 void Buffer11::markBufferUsage(BufferUsage usage)
651 {
652     mIdleness[usage] = 0;
653 }
654 
markBufferUsage(const gl::Context * context,BufferUsage usage)655 angle::Result Buffer11::markBufferUsage(const gl::Context *context, BufferUsage usage)
656 {
657     BufferStorage *bufferStorage = nullptr;
658     ANGLE_TRY(getBufferStorage(context, usage, &bufferStorage));
659 
660     if (bufferStorage)
661     {
662         onStorageUpdate(bufferStorage);
663     }
664 
665     invalidateStaticData(context);
666     return angle::Result::Continue;
667 }
668 
garbageCollection(const gl::Context * context,BufferUsage currentUsage)669 angle::Result Buffer11::garbageCollection(const gl::Context *context, BufferUsage currentUsage)
670 {
671     if (currentUsage != BUFFER_USAGE_SYSTEM_MEMORY && canDeallocateSystemMemory())
672     {
673         ANGLE_TRY(checkForDeallocation(context, BUFFER_USAGE_SYSTEM_MEMORY));
674     }
675 
676     if (currentUsage != BUFFER_USAGE_STAGING)
677     {
678         ANGLE_TRY(checkForDeallocation(context, BUFFER_USAGE_STAGING));
679     }
680 
681     return angle::Result::Continue;
682 }
683 
getBuffer(const gl::Context * context,BufferUsage usage,ID3D11Buffer ** bufferOut)684 angle::Result Buffer11::getBuffer(const gl::Context *context,
685                                   BufferUsage usage,
686                                   ID3D11Buffer **bufferOut)
687 {
688     NativeStorage *storage = nullptr;
689     ANGLE_TRY(getBufferStorage(context, usage, &storage));
690     *bufferOut = storage->getBuffer().get();
691     return angle::Result::Continue;
692 }
693 
getEmulatedIndexedBuffer(const gl::Context * context,SourceIndexData * indexInfo,const TranslatedAttribute & attribute,GLint startVertex,ID3D11Buffer ** bufferOut)694 angle::Result Buffer11::getEmulatedIndexedBuffer(const gl::Context *context,
695                                                  SourceIndexData *indexInfo,
696                                                  const TranslatedAttribute &attribute,
697                                                  GLint startVertex,
698                                                  ID3D11Buffer **bufferOut)
699 {
700     ASSERT(indexInfo);
701 
702     EmulatedIndexedStorage *emulatedStorage = nullptr;
703     ANGLE_TRY(getBufferStorage(context, BUFFER_USAGE_EMULATED_INDEXED_VERTEX, &emulatedStorage));
704 
705     const d3d11::Buffer *nativeBuffer = nullptr;
706     ANGLE_TRY(
707         emulatedStorage->getBuffer(context, indexInfo, attribute, startVertex, &nativeBuffer));
708     *bufferOut = nativeBuffer->get();
709     return angle::Result::Continue;
710 }
711 
getConstantBufferRange(const gl::Context * context,GLintptr offset,GLsizeiptr size,const d3d11::Buffer ** bufferOut,UINT * firstConstantOut,UINT * numConstantsOut)712 angle::Result Buffer11::getConstantBufferRange(const gl::Context *context,
713                                                GLintptr offset,
714                                                GLsizeiptr size,
715                                                const d3d11::Buffer **bufferOut,
716                                                UINT *firstConstantOut,
717                                                UINT *numConstantsOut)
718 {
719     NativeStorage *bufferStorage = nullptr;
720     if ((offset == 0 &&
721          size < static_cast<GLsizeiptr>(mRenderer->getNativeCaps().maxUniformBlockSize)) ||
722         mRenderer->getRenderer11DeviceCaps().supportsConstantBufferOffsets)
723     {
724         ANGLE_TRY(getBufferStorage(context, BUFFER_USAGE_UNIFORM, &bufferStorage));
725         CalculateConstantBufferParams(offset, size, firstConstantOut, numConstantsOut);
726     }
727     else
728     {
729         ANGLE_TRY(getConstantBufferRangeStorage(context, offset, size, &bufferStorage));
730         *firstConstantOut = 0;
731         *numConstantsOut  = 0;
732     }
733 
734     *bufferOut = &bufferStorage->getBuffer();
735     return angle::Result::Continue;
736 }
737 
markRawBufferUsage(const gl::Context * context)738 angle::Result Buffer11::markRawBufferUsage(const gl::Context *context)
739 {
740     ANGLE_TRY(markBufferUsage(context, BUFFER_USAGE_RAW_UAV));
741     return angle::Result::Continue;
742 }
743 
getRawUAVRange(const gl::Context * context,GLintptr offset,GLsizeiptr size,d3d11::UnorderedAccessView ** uavOut)744 angle::Result Buffer11::getRawUAVRange(const gl::Context *context,
745                                        GLintptr offset,
746                                        GLsizeiptr size,
747                                        d3d11::UnorderedAccessView **uavOut)
748 {
749     NativeStorage *nativeStorage = nullptr;
750     ANGLE_TRY(getBufferStorage(context, BUFFER_USAGE_RAW_UAV, &nativeStorage));
751 
752     return nativeStorage->getRawUAV(context, static_cast<unsigned int>(offset),
753                                     static_cast<unsigned int>(size), uavOut);
754 }
755 
getSRV(const gl::Context * context,DXGI_FORMAT srvFormat,const d3d11::ShaderResourceView ** srvOut)756 angle::Result Buffer11::getSRV(const gl::Context *context,
757                                DXGI_FORMAT srvFormat,
758                                const d3d11::ShaderResourceView **srvOut)
759 {
760     NativeStorage *nativeStorage = nullptr;
761     ANGLE_TRY(getBufferStorage(context, BUFFER_USAGE_PIXEL_UNPACK, &nativeStorage));
762     return nativeStorage->getSRVForFormat(context, srvFormat, srvOut);
763 }
764 
packPixels(const gl::Context * context,const gl::FramebufferAttachment & readAttachment,const PackPixelsParams & params)765 angle::Result Buffer11::packPixels(const gl::Context *context,
766                                    const gl::FramebufferAttachment &readAttachment,
767                                    const PackPixelsParams &params)
768 {
769     PackStorage *packStorage = nullptr;
770     ANGLE_TRY(getBufferStorage(context, BUFFER_USAGE_PIXEL_PACK, &packStorage));
771 
772     ASSERT(packStorage);
773     ANGLE_TRY(packStorage->packPixels(context, readAttachment, params));
774     onStorageUpdate(packStorage);
775 
776     return angle::Result::Continue;
777 }
778 
getTotalCPUBufferMemoryBytes() const779 size_t Buffer11::getTotalCPUBufferMemoryBytes() const
780 {
781     size_t allocationSize = 0;
782 
783     BufferStorage *staging = mBufferStorages[BUFFER_USAGE_STAGING];
784     allocationSize += staging ? staging->getSize() : 0;
785 
786     BufferStorage *sysMem = mBufferStorages[BUFFER_USAGE_SYSTEM_MEMORY];
787     allocationSize += sysMem ? sysMem->getSize() : 0;
788 
789     return allocationSize;
790 }
791 
792 template <typename StorageOutT>
getBufferStorage(const gl::Context * context,BufferUsage usage,StorageOutT ** storageOut)793 angle::Result Buffer11::getBufferStorage(const gl::Context *context,
794                                          BufferUsage usage,
795                                          StorageOutT **storageOut)
796 {
797     ASSERT(0 <= usage && usage < BUFFER_USAGE_COUNT);
798     BufferStorage *&newStorage = mBufferStorages[usage];
799 
800     if (!newStorage)
801     {
802         newStorage = allocateStorage(usage);
803     }
804 
805     markBufferUsage(usage);
806 
807     // resize buffer
808     if (newStorage->getSize() < mSize)
809     {
810         ANGLE_TRY(newStorage->resize(context, mSize, true));
811     }
812 
813     ASSERT(newStorage);
814 
815     ANGLE_TRY(updateBufferStorage(context, newStorage, 0, mSize));
816     ANGLE_TRY(garbageCollection(context, usage));
817 
818     *storageOut = GetAs<StorageOutT>(newStorage);
819     return angle::Result::Continue;
820 }
821 
allocateStorage(BufferUsage usage)822 Buffer11::BufferStorage *Buffer11::allocateStorage(BufferUsage usage)
823 {
824     updateDeallocThreshold(usage);
825     switch (usage)
826     {
827         case BUFFER_USAGE_PIXEL_PACK:
828             return new PackStorage(mRenderer);
829         case BUFFER_USAGE_SYSTEM_MEMORY:
830             return new SystemMemoryStorage(mRenderer);
831         case BUFFER_USAGE_EMULATED_INDEXED_VERTEX:
832             return new EmulatedIndexedStorage(mRenderer);
833         case BUFFER_USAGE_INDEX:
834         case BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK:
835             return new NativeStorage(mRenderer, usage, this);
836         case BUFFER_USAGE_STRUCTURED:
837             return new StructuredBufferStorage(mRenderer, usage, nullptr);
838         default:
839             return new NativeStorage(mRenderer, usage, nullptr);
840     }
841 }
842 
getConstantBufferRangeStorage(const gl::Context * context,GLintptr offset,GLsizeiptr size,Buffer11::NativeStorage ** storageOut)843 angle::Result Buffer11::getConstantBufferRangeStorage(const gl::Context *context,
844                                                       GLintptr offset,
845                                                       GLsizeiptr size,
846                                                       Buffer11::NativeStorage **storageOut)
847 {
848     BufferStorage *newStorage;
849     {
850         // Keep the cacheEntry in a limited scope because it may be invalidated later in the code if
851         // we need to reclaim some space.
852         BufferCacheEntry *cacheEntry = &mConstantBufferRangeStoragesCache[offset];
853 
854         if (!cacheEntry->storage)
855         {
856             cacheEntry->storage  = allocateStorage(BUFFER_USAGE_UNIFORM);
857             cacheEntry->lruCount = ++mMaxConstantBufferLruCount;
858         }
859 
860         cacheEntry->lruCount = ++mMaxConstantBufferLruCount;
861         newStorage           = cacheEntry->storage;
862     }
863 
864     markBufferUsage(BUFFER_USAGE_UNIFORM);
865 
866     if (newStorage->getSize() < static_cast<size_t>(size))
867     {
868         size_t maximumAllowedAdditionalSize = 2 * getSize();
869 
870         size_t sizeDelta = size - newStorage->getSize();
871 
872         while (mConstantBufferStorageAdditionalSize + sizeDelta > maximumAllowedAdditionalSize)
873         {
874             auto iter = std::min_element(
875                 std::begin(mConstantBufferRangeStoragesCache),
876                 std::end(mConstantBufferRangeStoragesCache),
877                 [](const BufferCache::value_type &a, const BufferCache::value_type &b) {
878                     return a.second.lruCount < b.second.lruCount;
879                 });
880 
881             ASSERT(iter->second.storage != newStorage);
882             ASSERT(mConstantBufferStorageAdditionalSize >= iter->second.storage->getSize());
883 
884             mConstantBufferStorageAdditionalSize -= iter->second.storage->getSize();
885             SafeDelete(iter->second.storage);
886             mConstantBufferRangeStoragesCache.erase(iter);
887         }
888 
889         ANGLE_TRY(newStorage->resize(context, size, false));
890         mConstantBufferStorageAdditionalSize += sizeDelta;
891 
892         // We don't copy the old data when resizing the constant buffer because the data may be
893         // out-of-date therefore we reset the data revision and let updateBufferStorage() handle the
894         // copy.
895         newStorage->setDataRevision(0);
896     }
897 
898     ANGLE_TRY(updateBufferStorage(context, newStorage, offset, size));
899     ANGLE_TRY(garbageCollection(context, BUFFER_USAGE_UNIFORM));
900     *storageOut = GetAs<NativeStorage>(newStorage);
901     return angle::Result::Continue;
902 }
903 
getStructuredBufferRangeSRV(const gl::Context * context,unsigned int offset,unsigned int size,unsigned int structureByteStride,const d3d11::ShaderResourceView ** srvOut)904 angle::Result Buffer11::getStructuredBufferRangeSRV(const gl::Context *context,
905                                                     unsigned int offset,
906                                                     unsigned int size,
907                                                     unsigned int structureByteStride,
908                                                     const d3d11::ShaderResourceView **srvOut)
909 {
910     BufferStorage *newStorage;
911 
912     {
913         // Keep the cacheEntry in a limited scope because it may be invalidated later in the code if
914         // we need to reclaim some space.
915         StructuredBufferKey structuredBufferKey = StructuredBufferKey(offset, structureByteStride);
916         BufferCacheEntry *cacheEntry = &mStructuredBufferRangeStoragesCache[structuredBufferKey];
917 
918         if (!cacheEntry->storage)
919         {
920             cacheEntry->storage  = allocateStorage(BUFFER_USAGE_STRUCTURED);
921             cacheEntry->lruCount = ++mMaxStructuredBufferLruCount;
922         }
923 
924         cacheEntry->lruCount = ++mMaxStructuredBufferLruCount;
925         newStorage           = cacheEntry->storage;
926     }
927 
928     StructuredBufferStorage *structuredBufferStorage = GetAs<StructuredBufferStorage>(newStorage);
929 
930     markBufferUsage(BUFFER_USAGE_STRUCTURED);
931 
932     if (newStorage->getSize() < static_cast<size_t>(size))
933     {
934         size_t maximumAllowedAdditionalSize = 2 * getSize();
935 
936         size_t sizeDelta = static_cast<size_t>(size) - newStorage->getSize();
937 
938         while (mStructuredBufferStorageAdditionalSize + sizeDelta > maximumAllowedAdditionalSize)
939         {
940             auto iter = std::min_element(std::begin(mStructuredBufferRangeStoragesCache),
941                                          std::end(mStructuredBufferRangeStoragesCache),
942                                          [](const StructuredBufferCache::value_type &a,
943                                             const StructuredBufferCache::value_type &b) {
944                                              return a.second.lruCount < b.second.lruCount;
945                                          });
946 
947             ASSERT(iter->second.storage != newStorage);
948             ASSERT(mStructuredBufferStorageAdditionalSize >= iter->second.storage->getSize());
949 
950             mStructuredBufferStorageAdditionalSize -= iter->second.storage->getSize();
951             SafeDelete(iter->second.storage);
952             mStructuredBufferRangeStoragesCache.erase(iter);
953         }
954 
955         ANGLE_TRY(
956             structuredBufferStorage->resizeStructuredBuffer(context, size, structureByteStride));
957         mStructuredBufferStorageAdditionalSize += sizeDelta;
958 
959         // We don't copy the old data when resizing the structured buffer because the data may be
960         // out-of-date therefore we reset the data revision and let updateBufferStorage() handle the
961         // copy.
962         newStorage->setDataRevision(0);
963     }
964 
965     ANGLE_TRY(updateBufferStorage(context, newStorage, offset, static_cast<size_t>(size)));
966     ANGLE_TRY(garbageCollection(context, BUFFER_USAGE_STRUCTURED));
967     ANGLE_TRY(structuredBufferStorage->getStructuredBufferRangeSRV(context, offset, size,
968                                                                    structureByteStride, srvOut));
969     return angle::Result::Continue;
970 }
971 
updateBufferStorage(const gl::Context * context,BufferStorage * storage,size_t sourceOffset,size_t storageSize)972 angle::Result Buffer11::updateBufferStorage(const gl::Context *context,
973                                             BufferStorage *storage,
974                                             size_t sourceOffset,
975                                             size_t storageSize)
976 {
977     BufferStorage *latestBuffer = nullptr;
978     ANGLE_TRY(getLatestBufferStorage(context, &latestBuffer));
979 
980     ASSERT(storage);
981 
982     if (!latestBuffer)
983     {
984         onStorageUpdate(storage);
985         return angle::Result::Continue;
986     }
987 
988     if (latestBuffer->getDataRevision() <= storage->getDataRevision())
989     {
990         return angle::Result::Continue;
991     }
992 
993     // Copy through a staging buffer if we're copying from or to a non-staging, mappable
994     // buffer storage. This is because we can't map a GPU buffer, and copy CPU
995     // data directly. If we're already using a staging buffer we're fine.
996     if (latestBuffer->getUsage() != BUFFER_USAGE_STAGING &&
997         storage->getUsage() != BUFFER_USAGE_STAGING &&
998         (!latestBuffer->isCPUAccessible(GL_MAP_READ_BIT) ||
999          !storage->isCPUAccessible(GL_MAP_WRITE_BIT)))
1000     {
1001         NativeStorage *stagingBuffer = nullptr;
1002         ANGLE_TRY(getStagingStorage(context, &stagingBuffer));
1003 
1004         CopyResult copyResult = CopyResult::NOT_RECREATED;
1005         ANGLE_TRY(stagingBuffer->copyFromStorage(context, latestBuffer, 0, latestBuffer->getSize(),
1006                                                  0, &copyResult));
1007         onCopyStorage(stagingBuffer, latestBuffer);
1008 
1009         latestBuffer = stagingBuffer;
1010     }
1011 
1012     CopyResult copyResult = CopyResult::NOT_RECREATED;
1013     ANGLE_TRY(
1014         storage->copyFromStorage(context, latestBuffer, sourceOffset, storageSize, 0, &copyResult));
1015     // If the D3D buffer has been recreated, we should update our serial.
1016     if (copyResult == CopyResult::RECREATED)
1017     {
1018         updateSerial();
1019     }
1020     onCopyStorage(storage, latestBuffer);
1021     return angle::Result::Continue;
1022 }
1023 
getLatestBufferStorage(const gl::Context * context,Buffer11::BufferStorage ** storageOut) const1024 angle::Result Buffer11::getLatestBufferStorage(const gl::Context *context,
1025                                                Buffer11::BufferStorage **storageOut) const
1026 {
1027     // resize buffer
1028     if (mLatestBufferStorage && mLatestBufferStorage->getSize() < mSize)
1029     {
1030         ANGLE_TRY(mLatestBufferStorage->resize(context, mSize, true));
1031     }
1032 
1033     *storageOut = mLatestBufferStorage;
1034     return angle::Result::Continue;
1035 }
1036 
1037 template <typename StorageOutT>
getStagingStorage(const gl::Context * context,StorageOutT ** storageOut)1038 angle::Result Buffer11::getStagingStorage(const gl::Context *context, StorageOutT **storageOut)
1039 {
1040     return getBufferStorage(context, BUFFER_USAGE_STAGING, storageOut);
1041 }
1042 
getSize() const1043 size_t Buffer11::getSize() const
1044 {
1045     return mSize;
1046 }
1047 
supportsDirectBinding() const1048 bool Buffer11::supportsDirectBinding() const
1049 {
1050     // Do not support direct buffers for dynamic data. The streaming buffer
1051     // offers better performance for data which changes every frame.
1052     return (mUsage == D3DBufferUsage::STATIC);
1053 }
1054 
initializeStaticData(const gl::Context * context)1055 void Buffer11::initializeStaticData(const gl::Context *context)
1056 {
1057     BufferD3D::initializeStaticData(context);
1058     onStateChange(angle::SubjectMessage::SubjectChanged);
1059 }
1060 
invalidateStaticData(const gl::Context * context)1061 void Buffer11::invalidateStaticData(const gl::Context *context)
1062 {
1063     BufferD3D::invalidateStaticData(context);
1064     onStateChange(angle::SubjectMessage::SubjectChanged);
1065 }
1066 
onCopyStorage(BufferStorage * dest,BufferStorage * source)1067 void Buffer11::onCopyStorage(BufferStorage *dest, BufferStorage *source)
1068 {
1069     ASSERT(source && mLatestBufferStorage);
1070     dest->setDataRevision(source->getDataRevision());
1071 
1072     // Only update the latest buffer storage if our usage index is lower. See comment in header.
1073     if (dest->getUsage() < mLatestBufferStorage->getUsage())
1074     {
1075         mLatestBufferStorage = dest;
1076     }
1077 }
1078 
onStorageUpdate(BufferStorage * updatedStorage)1079 void Buffer11::onStorageUpdate(BufferStorage *updatedStorage)
1080 {
1081     updatedStorage->setDataRevision(updatedStorage->getDataRevision() + 1);
1082     mLatestBufferStorage = updatedStorage;
1083 }
1084 
1085 // Buffer11::BufferStorage implementation
1086 
BufferStorage(Renderer11 * renderer,BufferUsage usage)1087 Buffer11::BufferStorage::BufferStorage(Renderer11 *renderer, BufferUsage usage)
1088     : mRenderer(renderer), mRevision(0), mUsage(usage), mBufferSize(0)
1089 {}
1090 
setData(const gl::Context * context,const uint8_t * data,size_t offset,size_t size)1091 angle::Result Buffer11::BufferStorage::setData(const gl::Context *context,
1092                                                const uint8_t *data,
1093                                                size_t offset,
1094                                                size_t size)
1095 {
1096     ASSERT(isCPUAccessible(GL_MAP_WRITE_BIT));
1097 
1098     // Uniform storage can have a different internal size than the buffer size. Ensure we don't
1099     // overflow.
1100     size_t mapSize = std::min(size, mBufferSize - offset);
1101 
1102     uint8_t *writePointer = nullptr;
1103     ANGLE_TRY(map(context, offset, mapSize, GL_MAP_WRITE_BIT, &writePointer));
1104 
1105     memcpy(writePointer, data, mapSize);
1106 
1107     unmap();
1108 
1109     return angle::Result::Continue;
1110 }
1111 
1112 // Buffer11::NativeStorage implementation
1113 
NativeStorage(Renderer11 * renderer,BufferUsage usage,const angle::Subject * onStorageChanged)1114 Buffer11::NativeStorage::NativeStorage(Renderer11 *renderer,
1115                                        BufferUsage usage,
1116                                        const angle::Subject *onStorageChanged)
1117     : BufferStorage(renderer, usage), mBuffer(), mOnStorageChanged(onStorageChanged)
1118 {}
1119 
~NativeStorage()1120 Buffer11::NativeStorage::~NativeStorage()
1121 {
1122     clearSRVs();
1123     clearUAVs();
1124 }
1125 
isCPUAccessible(GLbitfield access) const1126 bool Buffer11::NativeStorage::isCPUAccessible(GLbitfield access) const
1127 {
1128     if ((access & GL_MAP_READ_BIT) != 0)
1129     {
1130         // Read is more exclusive than write mappability.
1131         return (mUsage == BUFFER_USAGE_STAGING);
1132     }
1133     ASSERT((access & GL_MAP_WRITE_BIT) != 0);
1134     return (mUsage == BUFFER_USAGE_STAGING || mUsage == BUFFER_USAGE_UNIFORM ||
1135             mUsage == BUFFER_USAGE_STRUCTURED);
1136 }
1137 
1138 // 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)1139 angle::Result Buffer11::NativeStorage::copyFromStorage(const gl::Context *context,
1140                                                        BufferStorage *source,
1141                                                        size_t sourceOffset,
1142                                                        size_t size,
1143                                                        size_t destOffset,
1144                                                        CopyResult *resultOut)
1145 {
1146     size_t requiredSize = destOffset + size;
1147 
1148     // (Re)initialize D3D buffer if needed
1149     bool preserveData = (destOffset > 0);
1150     if (!mBuffer.valid() || mBufferSize < requiredSize)
1151     {
1152         ANGLE_TRY(resize(context, requiredSize, preserveData));
1153         *resultOut = CopyResult::RECREATED;
1154     }
1155     else
1156     {
1157         *resultOut = CopyResult::NOT_RECREATED;
1158     }
1159 
1160     size_t clampedSize = size;
1161     if (mUsage == BUFFER_USAGE_UNIFORM)
1162     {
1163         clampedSize = std::min(clampedSize, mBufferSize - destOffset);
1164     }
1165 
1166     if (clampedSize == 0)
1167     {
1168         return angle::Result::Continue;
1169     }
1170 
1171     if (source->getUsage() == BUFFER_USAGE_PIXEL_PACK ||
1172         source->getUsage() == BUFFER_USAGE_SYSTEM_MEMORY)
1173     {
1174         ASSERT(source->isCPUAccessible(GL_MAP_READ_BIT) && isCPUAccessible(GL_MAP_WRITE_BIT));
1175 
1176         // Uniform buffers must be mapped with write/discard.
1177         ASSERT(!(preserveData && mUsage == BUFFER_USAGE_UNIFORM));
1178 
1179         uint8_t *sourcePointer = nullptr;
1180         ANGLE_TRY(source->map(context, sourceOffset, clampedSize, GL_MAP_READ_BIT, &sourcePointer));
1181 
1182         auto err = setData(context, sourcePointer, destOffset, clampedSize);
1183         source->unmap();
1184         ANGLE_TRY(err);
1185     }
1186     else
1187     {
1188         D3D11_BOX srcBox;
1189         srcBox.left   = static_cast<unsigned int>(sourceOffset);
1190         srcBox.right  = static_cast<unsigned int>(sourceOffset + clampedSize);
1191         srcBox.top    = 0;
1192         srcBox.bottom = 1;
1193         srcBox.front  = 0;
1194         srcBox.back   = 1;
1195 
1196         const d3d11::Buffer *sourceBuffer = &GetAs<NativeStorage>(source)->getBuffer();
1197 
1198         ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
1199         deviceContext->CopySubresourceRegion(mBuffer.get(), 0,
1200                                              static_cast<unsigned int>(destOffset), 0, 0,
1201                                              sourceBuffer->get(), 0, &srcBox);
1202     }
1203 
1204     return angle::Result::Continue;
1205 }
1206 
resize(const gl::Context * context,size_t size,bool preserveData)1207 angle::Result Buffer11::NativeStorage::resize(const gl::Context *context,
1208                                               size_t size,
1209                                               bool preserveData)
1210 {
1211     if (size == 0)
1212     {
1213         mBuffer.reset();
1214         mBufferSize = 0;
1215         return angle::Result::Continue;
1216     }
1217 
1218     D3D11_BUFFER_DESC bufferDesc;
1219     FillBufferDesc(&bufferDesc, mRenderer, mUsage, static_cast<unsigned int>(size));
1220 
1221     d3d11::Buffer newBuffer;
1222     ANGLE_TRY(
1223         mRenderer->allocateResource(SafeGetImplAs<Context11>(context), bufferDesc, &newBuffer));
1224     newBuffer.setDebugName("Buffer11::NativeStorage");
1225 
1226     if (mBuffer.valid() && preserveData)
1227     {
1228         // We don't call resize if the buffer is big enough already.
1229         ASSERT(mBufferSize <= size);
1230 
1231         D3D11_BOX srcBox;
1232         srcBox.left   = 0;
1233         srcBox.right  = static_cast<unsigned int>(mBufferSize);
1234         srcBox.top    = 0;
1235         srcBox.bottom = 1;
1236         srcBox.front  = 0;
1237         srcBox.back   = 1;
1238 
1239         ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
1240         deviceContext->CopySubresourceRegion(newBuffer.get(), 0, 0, 0, 0, mBuffer.get(), 0,
1241                                              &srcBox);
1242     }
1243 
1244     // No longer need the old buffer
1245     mBuffer = std::move(newBuffer);
1246 
1247     mBufferSize = bufferDesc.ByteWidth;
1248 
1249     // Free the SRVs.
1250     clearSRVs();
1251 
1252     // Free the UAVs.
1253     clearUAVs();
1254 
1255     // Notify that the storage has changed.
1256     if (mOnStorageChanged)
1257     {
1258         mOnStorageChanged->onStateChange(angle::SubjectMessage::SubjectChanged);
1259     }
1260 
1261     return angle::Result::Continue;
1262 }
1263 
1264 // static
FillBufferDesc(D3D11_BUFFER_DESC * bufferDesc,Renderer11 * renderer,BufferUsage usage,unsigned int bufferSize)1265 void Buffer11::NativeStorage::FillBufferDesc(D3D11_BUFFER_DESC *bufferDesc,
1266                                              Renderer11 *renderer,
1267                                              BufferUsage usage,
1268                                              unsigned int bufferSize)
1269 {
1270     bufferDesc->ByteWidth           = bufferSize;
1271     bufferDesc->MiscFlags           = 0;
1272     bufferDesc->StructureByteStride = 0;
1273 
1274     switch (usage)
1275     {
1276         case BUFFER_USAGE_STAGING:
1277             bufferDesc->Usage          = D3D11_USAGE_STAGING;
1278             bufferDesc->BindFlags      = 0;
1279             bufferDesc->CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
1280             break;
1281 
1282         case BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK:
1283             bufferDesc->Usage     = D3D11_USAGE_DEFAULT;
1284             bufferDesc->BindFlags = D3D11_BIND_VERTEX_BUFFER;
1285 
1286             if (renderer->isES3Capable())
1287             {
1288                 bufferDesc->BindFlags |= D3D11_BIND_STREAM_OUTPUT;
1289             }
1290 
1291             bufferDesc->CPUAccessFlags = 0;
1292             break;
1293 
1294         case BUFFER_USAGE_INDEX:
1295             bufferDesc->Usage          = D3D11_USAGE_DEFAULT;
1296             bufferDesc->BindFlags      = D3D11_BIND_INDEX_BUFFER;
1297             bufferDesc->CPUAccessFlags = 0;
1298             break;
1299 
1300         case BUFFER_USAGE_INDIRECT:
1301             bufferDesc->MiscFlags      = D3D11_RESOURCE_MISC_DRAWINDIRECT_ARGS;
1302             bufferDesc->Usage          = D3D11_USAGE_DEFAULT;
1303             bufferDesc->BindFlags      = 0;
1304             bufferDesc->CPUAccessFlags = 0;
1305             break;
1306 
1307         case BUFFER_USAGE_PIXEL_UNPACK:
1308             bufferDesc->Usage          = D3D11_USAGE_DEFAULT;
1309             bufferDesc->BindFlags      = D3D11_BIND_SHADER_RESOURCE;
1310             bufferDesc->CPUAccessFlags = 0;
1311             break;
1312 
1313         case BUFFER_USAGE_UNIFORM:
1314             bufferDesc->Usage          = D3D11_USAGE_DYNAMIC;
1315             bufferDesc->BindFlags      = D3D11_BIND_CONSTANT_BUFFER;
1316             bufferDesc->CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
1317 
1318             // Constant buffers must be of a limited size, and aligned to 16 byte boundaries
1319             // For our purposes we ignore any buffer data past the maximum constant buffer size
1320             bufferDesc->ByteWidth = roundUp(bufferDesc->ByteWidth, 16u);
1321 
1322             // Note: it seems that D3D11 allows larger buffers on some platforms, but not all.
1323             // (Windows 10 seems to allow larger constant buffers, but not Windows 7)
1324             if (!renderer->getRenderer11DeviceCaps().supportsConstantBufferOffsets)
1325             {
1326                 bufferDesc->ByteWidth = std::min<UINT>(
1327                     bufferDesc->ByteWidth,
1328                     static_cast<UINT>(renderer->getNativeCaps().maxUniformBlockSize));
1329             }
1330             break;
1331 
1332         case BUFFER_USAGE_RAW_UAV:
1333             bufferDesc->MiscFlags      = D3D11_RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS;
1334             bufferDesc->BindFlags      = D3D11_BIND_UNORDERED_ACCESS;
1335             bufferDesc->Usage          = D3D11_USAGE_DEFAULT;
1336             bufferDesc->CPUAccessFlags = 0;
1337             break;
1338 
1339         default:
1340             UNREACHABLE();
1341     }
1342 }
1343 
map(const gl::Context * context,size_t offset,size_t length,GLbitfield access,uint8_t ** mapPointerOut)1344 angle::Result Buffer11::NativeStorage::map(const gl::Context *context,
1345                                            size_t offset,
1346                                            size_t length,
1347                                            GLbitfield access,
1348                                            uint8_t **mapPointerOut)
1349 {
1350     ASSERT(isCPUAccessible(access));
1351 
1352     D3D11_MAPPED_SUBRESOURCE mappedResource;
1353     D3D11_MAP d3dMapType = gl_d3d11::GetD3DMapTypeFromBits(mUsage, access);
1354     UINT d3dMapFlag = ((access & GL_MAP_UNSYNCHRONIZED_BIT) != 0 ? D3D11_MAP_FLAG_DO_NOT_WAIT : 0);
1355 
1356     ANGLE_TRY(
1357         mRenderer->mapResource(context, mBuffer.get(), 0, d3dMapType, d3dMapFlag, &mappedResource));
1358     ASSERT(mappedResource.pData);
1359     *mapPointerOut = static_cast<uint8_t *>(mappedResource.pData) + offset;
1360     return angle::Result::Continue;
1361 }
1362 
unmap()1363 void Buffer11::NativeStorage::unmap()
1364 {
1365     ASSERT(isCPUAccessible(GL_MAP_WRITE_BIT) || isCPUAccessible(GL_MAP_READ_BIT));
1366     ID3D11DeviceContext *context = mRenderer->getDeviceContext();
1367     context->Unmap(mBuffer.get(), 0);
1368 }
1369 
getSRVForFormat(const gl::Context * context,DXGI_FORMAT srvFormat,const d3d11::ShaderResourceView ** srvOut)1370 angle::Result Buffer11::NativeStorage::getSRVForFormat(const gl::Context *context,
1371                                                        DXGI_FORMAT srvFormat,
1372                                                        const d3d11::ShaderResourceView **srvOut)
1373 {
1374     auto bufferSRVIt = mBufferResourceViews.find(srvFormat);
1375 
1376     if (bufferSRVIt != mBufferResourceViews.end())
1377     {
1378         *srvOut = &bufferSRVIt->second;
1379         return angle::Result::Continue;
1380     }
1381 
1382     const d3d11::DXGIFormatSize &dxgiFormatInfo = d3d11::GetDXGIFormatSizeInfo(srvFormat);
1383 
1384     D3D11_SHADER_RESOURCE_VIEW_DESC bufferSRVDesc;
1385     bufferSRVDesc.Buffer.ElementOffset = 0;
1386     bufferSRVDesc.Buffer.ElementWidth  = static_cast<UINT>(mBufferSize) / dxgiFormatInfo.pixelBytes;
1387     bufferSRVDesc.ViewDimension        = D3D11_SRV_DIMENSION_BUFFER;
1388     bufferSRVDesc.Format               = srvFormat;
1389 
1390     ANGLE_TRY(mRenderer->allocateResource(GetImplAs<Context11>(context), bufferSRVDesc,
1391                                           mBuffer.get(), &mBufferResourceViews[srvFormat]));
1392 
1393     *srvOut = &mBufferResourceViews[srvFormat];
1394     return angle::Result::Continue;
1395 }
1396 
getRawUAV(const gl::Context * context,unsigned int offset,unsigned int size,d3d11::UnorderedAccessView ** uavOut)1397 angle::Result Buffer11::NativeStorage::getRawUAV(const gl::Context *context,
1398                                                  unsigned int offset,
1399                                                  unsigned int size,
1400                                                  d3d11::UnorderedAccessView **uavOut)
1401 {
1402     ASSERT(offset + size <= mBufferSize);
1403 
1404     auto bufferRawUAV = mBufferRawUAVs.find({offset, size});
1405     if (bufferRawUAV != mBufferRawUAVs.end())
1406     {
1407         *uavOut = &bufferRawUAV->second;
1408         return angle::Result::Continue;
1409     }
1410 
1411     D3D11_UNORDERED_ACCESS_VIEW_DESC bufferUAVDesc;
1412 
1413     // DXGI_FORMAT_R32_TYPELESS uses 4 bytes per element
1414     constexpr int kBytesToElement     = 4;
1415     bufferUAVDesc.Buffer.FirstElement = offset / kBytesToElement;
1416     bufferUAVDesc.Buffer.NumElements  = size / kBytesToElement;
1417     bufferUAVDesc.Buffer.Flags        = D3D11_BUFFER_UAV_FLAG_RAW;
1418     bufferUAVDesc.Format = DXGI_FORMAT_R32_TYPELESS;  // Format must be DXGI_FORMAT_R32_TYPELESS,
1419                                                       // when creating Raw Unordered Access View
1420     bufferUAVDesc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER;
1421 
1422     ANGLE_TRY(mRenderer->allocateResource(GetImplAs<Context11>(context), bufferUAVDesc,
1423                                           mBuffer.get(), &mBufferRawUAVs[{offset, size}]));
1424     *uavOut = &mBufferRawUAVs[{offset, size}];
1425     return angle::Result::Continue;
1426 }
1427 
clearSRVs()1428 void Buffer11::NativeStorage::clearSRVs()
1429 {
1430     mBufferResourceViews.clear();
1431 }
1432 
clearUAVs()1433 void Buffer11::NativeStorage::clearUAVs()
1434 {
1435     mBufferRawUAVs.clear();
1436 }
1437 
StructuredBufferStorage(Renderer11 * renderer,BufferUsage usage,const angle::Subject * onStorageChanged)1438 Buffer11::StructuredBufferStorage::StructuredBufferStorage(Renderer11 *renderer,
1439                                                            BufferUsage usage,
1440                                                            const angle::Subject *onStorageChanged)
1441     : NativeStorage(renderer, usage, onStorageChanged), mStructuredBufferResourceView()
1442 {}
1443 
~StructuredBufferStorage()1444 Buffer11::StructuredBufferStorage::~StructuredBufferStorage()
1445 {
1446     mStructuredBufferResourceView.reset();
1447 }
1448 
resizeStructuredBuffer(const gl::Context * context,unsigned int size,unsigned int structureByteStride)1449 angle::Result Buffer11::StructuredBufferStorage::resizeStructuredBuffer(
1450     const gl::Context *context,
1451     unsigned int size,
1452     unsigned int structureByteStride)
1453 {
1454     if (size == 0)
1455     {
1456         mBuffer.reset();
1457         mBufferSize = 0;
1458         return angle::Result::Continue;
1459     }
1460 
1461     D3D11_BUFFER_DESC bufferDesc;
1462     bufferDesc.ByteWidth           = size;
1463     bufferDesc.MiscFlags           = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED;
1464     bufferDesc.StructureByteStride = structureByteStride;
1465     bufferDesc.Usage               = D3D11_USAGE_DYNAMIC;
1466     bufferDesc.BindFlags           = D3D11_BIND_SHADER_RESOURCE;
1467     bufferDesc.CPUAccessFlags      = D3D11_CPU_ACCESS_WRITE;
1468 
1469     d3d11::Buffer newBuffer;
1470     ANGLE_TRY(
1471         mRenderer->allocateResource(SafeGetImplAs<Context11>(context), bufferDesc, &newBuffer));
1472     newBuffer.setDebugName("Buffer11::StructuredBufferStorage");
1473 
1474     // No longer need the old buffer
1475     mBuffer = std::move(newBuffer);
1476 
1477     mBufferSize = static_cast<size_t>(bufferDesc.ByteWidth);
1478 
1479     mStructuredBufferResourceView.reset();
1480 
1481     // Notify that the storage has changed.
1482     if (mOnStorageChanged)
1483     {
1484         mOnStorageChanged->onStateChange(angle::SubjectMessage::SubjectChanged);
1485     }
1486 
1487     return angle::Result::Continue;
1488 }
1489 
getStructuredBufferRangeSRV(const gl::Context * context,unsigned int offset,unsigned int size,unsigned int structureByteStride,const d3d11::ShaderResourceView ** srvOut)1490 angle::Result Buffer11::StructuredBufferStorage::getStructuredBufferRangeSRV(
1491     const gl::Context *context,
1492     unsigned int offset,
1493     unsigned int size,
1494     unsigned int structureByteStride,
1495     const d3d11::ShaderResourceView **srvOut)
1496 {
1497     if (mStructuredBufferResourceView.valid())
1498     {
1499         *srvOut = &mStructuredBufferResourceView;
1500         return angle::Result::Continue;
1501     }
1502 
1503     D3D11_SHADER_RESOURCE_VIEW_DESC bufferSRVDesc = {};
1504     bufferSRVDesc.BufferEx.NumElements = structureByteStride == 0u ? 1 : size / structureByteStride;
1505     bufferSRVDesc.BufferEx.FirstElement = 0;
1506     bufferSRVDesc.BufferEx.Flags        = 0;
1507     bufferSRVDesc.ViewDimension         = D3D11_SRV_DIMENSION_BUFFEREX;
1508     bufferSRVDesc.Format                = DXGI_FORMAT_UNKNOWN;
1509 
1510     ANGLE_TRY(mRenderer->allocateResource(GetImplAs<Context11>(context), bufferSRVDesc,
1511                                           mBuffer.get(), &mStructuredBufferResourceView));
1512 
1513     *srvOut = &mStructuredBufferResourceView;
1514     return angle::Result::Continue;
1515 }
1516 
1517 // Buffer11::EmulatedIndexStorage implementation
EmulatedIndexedStorage(Renderer11 * renderer)1518 Buffer11::EmulatedIndexedStorage::EmulatedIndexedStorage(Renderer11 *renderer)
1519     : BufferStorage(renderer, BUFFER_USAGE_EMULATED_INDEXED_VERTEX), mBuffer()
1520 {}
1521 
~EmulatedIndexedStorage()1522 Buffer11::EmulatedIndexedStorage::~EmulatedIndexedStorage() {}
1523 
getBuffer(const gl::Context * context,SourceIndexData * indexInfo,const TranslatedAttribute & attribute,GLint startVertex,const d3d11::Buffer ** bufferOut)1524 angle::Result Buffer11::EmulatedIndexedStorage::getBuffer(const gl::Context *context,
1525                                                           SourceIndexData *indexInfo,
1526                                                           const TranslatedAttribute &attribute,
1527                                                           GLint startVertex,
1528                                                           const d3d11::Buffer **bufferOut)
1529 {
1530     Context11 *context11 = GetImplAs<Context11>(context);
1531 
1532     // If a change in the indices applied from the last draw call is detected, then the emulated
1533     // indexed buffer needs to be invalidated.  After invalidation, the change detected flag should
1534     // be cleared to avoid unnecessary recreation of the buffer.
1535     if (!mBuffer.valid() || indexInfo->srcIndicesChanged)
1536     {
1537         mBuffer.reset();
1538 
1539         // Copy the source index data. This ensures that the lifetime of the indices pointer
1540         // stays with this storage until the next time we invalidate.
1541         size_t indicesDataSize = 0;
1542         switch (indexInfo->srcIndexType)
1543         {
1544             case gl::DrawElementsType::UnsignedInt:
1545                 indicesDataSize = sizeof(GLuint) * indexInfo->srcCount;
1546                 break;
1547             case gl::DrawElementsType::UnsignedShort:
1548                 indicesDataSize = sizeof(GLushort) * indexInfo->srcCount;
1549                 break;
1550             case gl::DrawElementsType::UnsignedByte:
1551                 indicesDataSize = sizeof(GLubyte) * indexInfo->srcCount;
1552                 break;
1553             default:
1554                 indicesDataSize = sizeof(GLushort) * indexInfo->srcCount;
1555                 break;
1556         }
1557 
1558         ANGLE_CHECK_GL_ALLOC(context11, mIndicesMemoryBuffer.resize(indicesDataSize));
1559 
1560         memcpy(mIndicesMemoryBuffer.data(), indexInfo->srcIndices, indicesDataSize);
1561 
1562         indexInfo->srcIndicesChanged = false;
1563     }
1564 
1565     if (!mBuffer.valid())
1566     {
1567         unsigned int offset = 0;
1568         ANGLE_TRY(attribute.computeOffset(context, startVertex, &offset));
1569 
1570         // Expand the memory storage upon request and cache the results.
1571         unsigned int expandedDataSize =
1572             static_cast<unsigned int>((indexInfo->srcCount * attribute.stride) + offset);
1573         angle::MemoryBuffer expandedData;
1574         ANGLE_CHECK_GL_ALLOC(context11, expandedData.resize(expandedDataSize));
1575 
1576         // Clear the contents of the allocated buffer
1577         ZeroMemory(expandedData.data(), expandedDataSize);
1578 
1579         uint8_t *curr      = expandedData.data();
1580         const uint8_t *ptr = static_cast<const uint8_t *>(indexInfo->srcIndices);
1581 
1582         // Ensure that we start in the correct place for the emulated data copy operation to
1583         // maintain offset behaviors.
1584         curr += offset;
1585 
1586         ReadIndexValueFunction readIndexValue = ReadIndexValueFromIndices<GLushort>;
1587 
1588         switch (indexInfo->srcIndexType)
1589         {
1590             case gl::DrawElementsType::UnsignedInt:
1591                 readIndexValue = ReadIndexValueFromIndices<GLuint>;
1592                 break;
1593             case gl::DrawElementsType::UnsignedShort:
1594                 readIndexValue = ReadIndexValueFromIndices<GLushort>;
1595                 break;
1596             case gl::DrawElementsType::UnsignedByte:
1597                 readIndexValue = ReadIndexValueFromIndices<GLubyte>;
1598                 break;
1599             default:
1600                 UNREACHABLE();
1601                 return angle::Result::Stop;
1602         }
1603 
1604         // Iterate over the cached index data and copy entries indicated into the emulated buffer.
1605         for (GLuint i = 0; i < indexInfo->srcCount; i++)
1606         {
1607             GLuint idx = readIndexValue(ptr, i);
1608             memcpy(curr, mMemoryBuffer.data() + (attribute.stride * idx), attribute.stride);
1609             curr += attribute.stride;
1610         }
1611 
1612         // Finally, initialize the emulated indexed native storage object with the newly copied data
1613         // and free the temporary buffers used.
1614         D3D11_BUFFER_DESC bufferDesc;
1615         bufferDesc.ByteWidth           = expandedDataSize;
1616         bufferDesc.MiscFlags           = 0;
1617         bufferDesc.StructureByteStride = 0;
1618         bufferDesc.Usage               = D3D11_USAGE_DEFAULT;
1619         bufferDesc.BindFlags           = D3D11_BIND_VERTEX_BUFFER;
1620         bufferDesc.CPUAccessFlags      = 0;
1621 
1622         D3D11_SUBRESOURCE_DATA subResourceData = {expandedData.data(), 0, 0};
1623 
1624         ANGLE_TRY(mRenderer->allocateResource(GetImplAs<Context11>(context), bufferDesc,
1625                                               &subResourceData, &mBuffer));
1626         mBuffer.setDebugName("Buffer11::EmulatedIndexedStorage");
1627     }
1628 
1629     *bufferOut = &mBuffer;
1630     return angle::Result::Continue;
1631 }
1632 
copyFromStorage(const gl::Context * context,BufferStorage * source,size_t sourceOffset,size_t size,size_t destOffset,CopyResult * resultOut)1633 angle::Result Buffer11::EmulatedIndexedStorage::copyFromStorage(const gl::Context *context,
1634                                                                 BufferStorage *source,
1635                                                                 size_t sourceOffset,
1636                                                                 size_t size,
1637                                                                 size_t destOffset,
1638                                                                 CopyResult *resultOut)
1639 {
1640     ASSERT(source->isCPUAccessible(GL_MAP_READ_BIT));
1641     uint8_t *sourceData = nullptr;
1642     ANGLE_TRY(source->map(context, sourceOffset, size, GL_MAP_READ_BIT, &sourceData));
1643     ASSERT(destOffset + size <= mMemoryBuffer.size());
1644     memcpy(mMemoryBuffer.data() + destOffset, sourceData, size);
1645     source->unmap();
1646     *resultOut = CopyResult::RECREATED;
1647     return angle::Result::Continue;
1648 }
1649 
resize(const gl::Context * context,size_t size,bool preserveData)1650 angle::Result Buffer11::EmulatedIndexedStorage::resize(const gl::Context *context,
1651                                                        size_t size,
1652                                                        bool preserveData)
1653 {
1654     if (mMemoryBuffer.size() < size)
1655     {
1656         Context11 *context11 = GetImplAs<Context11>(context);
1657         ANGLE_CHECK_GL_ALLOC(context11, mMemoryBuffer.resize(size));
1658         mBufferSize = size;
1659     }
1660 
1661     return angle::Result::Continue;
1662 }
1663 
map(const gl::Context * context,size_t offset,size_t length,GLbitfield access,uint8_t ** mapPointerOut)1664 angle::Result Buffer11::EmulatedIndexedStorage::map(const gl::Context *context,
1665                                                     size_t offset,
1666                                                     size_t length,
1667                                                     GLbitfield access,
1668                                                     uint8_t **mapPointerOut)
1669 {
1670     ASSERT(!mMemoryBuffer.empty() && offset + length <= mMemoryBuffer.size());
1671     *mapPointerOut = mMemoryBuffer.data() + offset;
1672     return angle::Result::Continue;
1673 }
1674 
unmap()1675 void Buffer11::EmulatedIndexedStorage::unmap()
1676 {
1677     // No-op
1678 }
1679 
1680 // Buffer11::PackStorage implementation
1681 
PackStorage(Renderer11 * renderer)1682 Buffer11::PackStorage::PackStorage(Renderer11 *renderer)
1683     : BufferStorage(renderer, BUFFER_USAGE_PIXEL_PACK), mStagingTexture(), mDataModified(false)
1684 {}
1685 
~PackStorage()1686 Buffer11::PackStorage::~PackStorage() {}
1687 
copyFromStorage(const gl::Context * context,BufferStorage * source,size_t sourceOffset,size_t size,size_t destOffset,CopyResult * resultOut)1688 angle::Result Buffer11::PackStorage::copyFromStorage(const gl::Context *context,
1689                                                      BufferStorage *source,
1690                                                      size_t sourceOffset,
1691                                                      size_t size,
1692                                                      size_t destOffset,
1693                                                      CopyResult *resultOut)
1694 {
1695     ANGLE_TRY(flushQueuedPackCommand(context));
1696 
1697     // For all use cases of pack buffers, we must copy through a readable buffer.
1698     ASSERT(source->isCPUAccessible(GL_MAP_READ_BIT));
1699     uint8_t *sourceData = nullptr;
1700     ANGLE_TRY(source->map(context, sourceOffset, size, GL_MAP_READ_BIT, &sourceData));
1701     ASSERT(destOffset + size <= mMemoryBuffer.size());
1702     memcpy(mMemoryBuffer.data() + destOffset, sourceData, size);
1703     source->unmap();
1704     *resultOut = CopyResult::NOT_RECREATED;
1705     return angle::Result::Continue;
1706 }
1707 
resize(const gl::Context * context,size_t size,bool preserveData)1708 angle::Result Buffer11::PackStorage::resize(const gl::Context *context,
1709                                             size_t size,
1710                                             bool preserveData)
1711 {
1712     if (size != mBufferSize)
1713     {
1714         Context11 *context11 = GetImplAs<Context11>(context);
1715         ANGLE_CHECK_GL_ALLOC(context11, mMemoryBuffer.resize(size));
1716         mBufferSize = size;
1717     }
1718 
1719     return angle::Result::Continue;
1720 }
1721 
map(const gl::Context * context,size_t offset,size_t length,GLbitfield access,uint8_t ** mapPointerOut)1722 angle::Result Buffer11::PackStorage::map(const gl::Context *context,
1723                                          size_t offset,
1724                                          size_t length,
1725                                          GLbitfield access,
1726                                          uint8_t **mapPointerOut)
1727 {
1728     ASSERT(offset + length <= getSize());
1729     // TODO: fast path
1730     //  We might be able to optimize out one or more memcpy calls by detecting when
1731     //  and if D3D packs the staging texture memory identically to how we would fill
1732     //  the pack buffer according to the current pack state.
1733 
1734     ANGLE_TRY(flushQueuedPackCommand(context));
1735 
1736     mDataModified = (mDataModified || (access & GL_MAP_WRITE_BIT) != 0);
1737 
1738     *mapPointerOut = mMemoryBuffer.data() + offset;
1739     return angle::Result::Continue;
1740 }
1741 
unmap()1742 void Buffer11::PackStorage::unmap()
1743 {
1744     // No-op
1745 }
1746 
packPixels(const gl::Context * context,const gl::FramebufferAttachment & readAttachment,const PackPixelsParams & params)1747 angle::Result Buffer11::PackStorage::packPixels(const gl::Context *context,
1748                                                 const gl::FramebufferAttachment &readAttachment,
1749                                                 const PackPixelsParams &params)
1750 {
1751     ANGLE_TRY(flushQueuedPackCommand(context));
1752 
1753     RenderTarget11 *renderTarget = nullptr;
1754     ANGLE_TRY(readAttachment.getRenderTarget(context, 0, &renderTarget));
1755 
1756     const TextureHelper11 &srcTexture = renderTarget->getTexture();
1757     ASSERT(srcTexture.valid());
1758     unsigned int srcSubresource = renderTarget->getSubresourceIndex();
1759 
1760     mQueuedPackCommand.reset(new PackPixelsParams(params));
1761 
1762     gl::Extents srcTextureSize(params.area.width, params.area.height, 1);
1763     if (!mStagingTexture.get() || mStagingTexture.getFormat() != srcTexture.getFormat() ||
1764         mStagingTexture.getExtents() != srcTextureSize)
1765     {
1766         ANGLE_TRY(mRenderer->createStagingTexture(context, srcTexture.getTextureType(),
1767                                                   srcTexture.getFormatSet(), srcTextureSize,
1768                                                   StagingAccess::READ, &mStagingTexture));
1769     }
1770 
1771     // ReadPixels from multisampled FBOs isn't supported in current GL
1772     ASSERT(srcTexture.getSampleCount() <= 1);
1773 
1774     ID3D11DeviceContext *immediateContext = mRenderer->getDeviceContext();
1775     D3D11_BOX srcBox;
1776     srcBox.left   = params.area.x;
1777     srcBox.right  = params.area.x + params.area.width;
1778     srcBox.top    = params.area.y;
1779     srcBox.bottom = params.area.y + params.area.height;
1780 
1781     // Select the correct layer from a 3D attachment
1782     srcBox.front = 0;
1783     if (mStagingTexture.is3D())
1784     {
1785         srcBox.front = static_cast<UINT>(readAttachment.layer());
1786     }
1787     srcBox.back = srcBox.front + 1;
1788 
1789     // Asynchronous copy
1790     immediateContext->CopySubresourceRegion(mStagingTexture.get(), 0, 0, 0, 0, srcTexture.get(),
1791                                             srcSubresource, &srcBox);
1792 
1793     return angle::Result::Continue;
1794 }
1795 
flushQueuedPackCommand(const gl::Context * context)1796 angle::Result Buffer11::PackStorage::flushQueuedPackCommand(const gl::Context *context)
1797 {
1798     ASSERT(mMemoryBuffer.size() > 0);
1799 
1800     if (mQueuedPackCommand)
1801     {
1802         ANGLE_TRY(mRenderer->packPixels(context, mStagingTexture, *mQueuedPackCommand,
1803                                         mMemoryBuffer.data()));
1804         mQueuedPackCommand.reset(nullptr);
1805     }
1806 
1807     return angle::Result::Continue;
1808 }
1809 
1810 // Buffer11::SystemMemoryStorage implementation
1811 
SystemMemoryStorage(Renderer11 * renderer)1812 Buffer11::SystemMemoryStorage::SystemMemoryStorage(Renderer11 *renderer)
1813     : Buffer11::BufferStorage(renderer, BUFFER_USAGE_SYSTEM_MEMORY)
1814 {}
1815 
copyFromStorage(const gl::Context * context,BufferStorage * source,size_t sourceOffset,size_t size,size_t destOffset,CopyResult * resultOut)1816 angle::Result Buffer11::SystemMemoryStorage::copyFromStorage(const gl::Context *context,
1817                                                              BufferStorage *source,
1818                                                              size_t sourceOffset,
1819                                                              size_t size,
1820                                                              size_t destOffset,
1821                                                              CopyResult *resultOut)
1822 {
1823     ASSERT(source->isCPUAccessible(GL_MAP_READ_BIT));
1824     uint8_t *sourceData = nullptr;
1825     ANGLE_TRY(source->map(context, sourceOffset, size, GL_MAP_READ_BIT, &sourceData));
1826     ASSERT(destOffset + size <= mSystemCopy.size());
1827     memcpy(mSystemCopy.data() + destOffset, sourceData, size);
1828     source->unmap();
1829     *resultOut = CopyResult::RECREATED;
1830     return angle::Result::Continue;
1831 }
1832 
resize(const gl::Context * context,size_t size,bool preserveData)1833 angle::Result Buffer11::SystemMemoryStorage::resize(const gl::Context *context,
1834                                                     size_t size,
1835                                                     bool preserveData)
1836 {
1837     if (mSystemCopy.size() < size)
1838     {
1839         Context11 *context11 = GetImplAs<Context11>(context);
1840         ANGLE_CHECK_GL_ALLOC(context11, mSystemCopy.resize(size));
1841         mBufferSize = size;
1842     }
1843 
1844     return angle::Result::Continue;
1845 }
1846 
map(const gl::Context * context,size_t offset,size_t length,GLbitfield access,uint8_t ** mapPointerOut)1847 angle::Result Buffer11::SystemMemoryStorage::map(const gl::Context *context,
1848                                                  size_t offset,
1849                                                  size_t length,
1850                                                  GLbitfield access,
1851                                                  uint8_t **mapPointerOut)
1852 {
1853     ASSERT(!mSystemCopy.empty() && offset + length <= mSystemCopy.size());
1854     *mapPointerOut = mSystemCopy.data() + offset;
1855     return angle::Result::Continue;
1856 }
1857 
unmap()1858 void Buffer11::SystemMemoryStorage::unmap()
1859 {
1860     // No-op
1861 }
1862 }  // namespace rx
1863