xref: /aosp_15_r20/external/angle/src/libANGLE/renderer/d3d/d3d11/Buffer11.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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 // Pack storage represents internal storage for pack buffers. We implement pack buffers
226 // as CPU memory, tied to a staging texture, for asynchronous texture readback.
227 class Buffer11::PackStorage : public Buffer11::BufferStorage
228 {
229   public:
230     explicit PackStorage(Renderer11 *renderer);
231     ~PackStorage() override;
232 
isCPUAccessible(GLbitfield access) const233     bool isCPUAccessible(GLbitfield access) const override { return true; }
234 
isGPUAccessible() const235     bool isGPUAccessible() const override { return false; }
236 
237     angle::Result copyFromStorage(const gl::Context *context,
238                                   BufferStorage *source,
239                                   size_t sourceOffset,
240                                   size_t size,
241                                   size_t destOffset,
242                                   CopyResult *resultOut) override;
243     angle::Result resize(const gl::Context *context, size_t size, bool preserveData) override;
244 
245     angle::Result map(const gl::Context *context,
246                       size_t offset,
247                       size_t length,
248                       GLbitfield access,
249                       uint8_t **mapPointerOut) override;
250     void unmap() override;
251 
252     angle::Result packPixels(const gl::Context *context,
253                              const gl::FramebufferAttachment &readAttachment,
254                              const PackPixelsParams &params);
255 
256   private:
257     angle::Result flushQueuedPackCommand(const gl::Context *context);
258 
259     TextureHelper11 mStagingTexture;
260     angle::MemoryBuffer mMemoryBuffer;
261     std::unique_ptr<PackPixelsParams> mQueuedPackCommand;
262     PackPixelsParams mPackParams;
263     bool mDataModified;
264 };
265 
266 // System memory storage stores a CPU memory buffer with our buffer data.
267 // For dynamic data, it's much faster to update the CPU memory buffer than
268 // it is to update a D3D staging buffer and read it back later.
269 class Buffer11::SystemMemoryStorage : public Buffer11::BufferStorage
270 {
271   public:
272     explicit SystemMemoryStorage(Renderer11 *renderer);
~SystemMemoryStorage()273     ~SystemMemoryStorage() override {}
274 
isCPUAccessible(GLbitfield access) const275     bool isCPUAccessible(GLbitfield access) const override { return true; }
276 
isGPUAccessible() const277     bool isGPUAccessible() const override { return false; }
278 
279     angle::Result copyFromStorage(const gl::Context *context,
280                                   BufferStorage *source,
281                                   size_t sourceOffset,
282                                   size_t size,
283                                   size_t destOffset,
284                                   CopyResult *resultOut) override;
285     angle::Result resize(const gl::Context *context, size_t size, bool preserveData) override;
286 
287     angle::Result map(const gl::Context *context,
288                       size_t offset,
289                       size_t length,
290                       GLbitfield access,
291                       uint8_t **mapPointerOut) override;
292     void unmap() override;
293 
getSystemCopy()294     angle::MemoryBuffer *getSystemCopy() { return &mSystemCopy; }
295 
296   protected:
297     angle::MemoryBuffer mSystemCopy;
298 };
299 
Buffer11(const gl::BufferState & state,Renderer11 * renderer)300 Buffer11::Buffer11(const gl::BufferState &state, Renderer11 *renderer)
301     : BufferD3D(state, renderer),
302       mRenderer(renderer),
303       mSize(0),
304       mMappedStorage(nullptr),
305       mBufferStorages({}),
306       mLatestBufferStorage(nullptr),
307       mDeallocThresholds({}),
308       mIdleness({}),
309       mConstantBufferStorageAdditionalSize(0),
310       mMaxConstantBufferLruCount(0),
311       mStructuredBufferStorageAdditionalSize(0),
312       mMaxStructuredBufferLruCount(0)
313 {}
314 
~Buffer11()315 Buffer11::~Buffer11()
316 {
317     for (BufferStorage *&storage : mBufferStorages)
318     {
319         SafeDelete(storage);
320     }
321 
322     for (auto &p : mConstantBufferRangeStoragesCache)
323     {
324         SafeDelete(p.second.storage);
325     }
326 
327     for (auto &p : mStructuredBufferRangeStoragesCache)
328     {
329         SafeDelete(p.second.storage);
330     }
331 
332     mRenderer->onBufferDelete(this);
333 }
334 
setData(const gl::Context * context,gl::BufferBinding target,const void * data,size_t size,gl::BufferUsage usage)335 angle::Result Buffer11::setData(const gl::Context *context,
336                                 gl::BufferBinding target,
337                                 const void *data,
338                                 size_t size,
339                                 gl::BufferUsage usage)
340 {
341     updateD3DBufferUsage(context, usage);
342     return setSubData(context, target, data, size, 0);
343 }
344 
getData(const gl::Context * context,const uint8_t ** outData)345 angle::Result Buffer11::getData(const gl::Context *context, const uint8_t **outData)
346 {
347     if (mSize == 0)
348     {
349         // TODO(http://anglebug.com/42261543): This ensures that we don't crash or assert in robust
350         // buffer access behavior mode if there are buffers without any data. However, technically
351         // it should still be possible to draw, with fetches from this buffer returning zero.
352         return angle::Result::Stop;
353     }
354 
355     SystemMemoryStorage *systemMemoryStorage = nullptr;
356     ANGLE_TRY(getBufferStorage(context, BUFFER_USAGE_SYSTEM_MEMORY, &systemMemoryStorage));
357 
358     ASSERT(systemMemoryStorage->getSize() >= mSize);
359 
360     *outData = systemMemoryStorage->getSystemCopy()->data();
361     return angle::Result::Continue;
362 }
363 
setSubData(const gl::Context * context,gl::BufferBinding target,const void * data,size_t size,size_t offset)364 angle::Result Buffer11::setSubData(const gl::Context *context,
365                                    gl::BufferBinding target,
366                                    const void *data,
367                                    size_t size,
368                                    size_t offset)
369 {
370     size_t requiredSize = size + offset;
371 
372     if (data && size > 0)
373     {
374         // Use system memory storage for dynamic buffers.
375         // Try using a constant storage for constant buffers
376         BufferStorage *writeBuffer = nullptr;
377         if (target == gl::BufferBinding::Uniform)
378         {
379             // If we are a very large uniform buffer, keep system memory storage around so that we
380             // aren't forced to read back from a constant buffer. We also check the workaround for
381             // Intel - this requires us to use system memory so we don't end up having to copy from
382             // a constant buffer to a staging buffer.
383             // TODO(jmadill): Use Context caps.
384             if (offset == 0 && size >= mSize &&
385                 size <= static_cast<UINT>(mRenderer->getNativeCaps().maxUniformBlockSize) &&
386                 !mRenderer->getFeatures().useSystemMemoryForConstantBuffers.enabled)
387             {
388                 BufferStorage *latestStorage = nullptr;
389                 ANGLE_TRY(getLatestBufferStorage(context, &latestStorage));
390                 if (latestStorage && (latestStorage->getUsage() == BUFFER_USAGE_STRUCTURED))
391                 {
392                     ANGLE_TRY(getBufferStorage(context, BUFFER_USAGE_STRUCTURED, &writeBuffer));
393                 }
394                 else
395                 {
396                     ANGLE_TRY(getBufferStorage(context, BUFFER_USAGE_UNIFORM, &writeBuffer));
397                 }
398             }
399             else
400             {
401                 ANGLE_TRY(getBufferStorage(context, BUFFER_USAGE_SYSTEM_MEMORY, &writeBuffer));
402             }
403         }
404         else if (supportsDirectBinding())
405         {
406             ANGLE_TRY(getStagingStorage(context, &writeBuffer));
407         }
408         else
409         {
410             ANGLE_TRY(getBufferStorage(context, BUFFER_USAGE_SYSTEM_MEMORY, &writeBuffer));
411         }
412 
413         ASSERT(writeBuffer);
414 
415         // Explicitly resize the staging buffer, preserving data if the new data will not
416         // completely fill the buffer
417         if (writeBuffer->getSize() < requiredSize)
418         {
419             bool preserveData = (offset > 0);
420             ANGLE_TRY(writeBuffer->resize(context, requiredSize, preserveData));
421         }
422 
423         ANGLE_TRY(writeBuffer->setData(context, static_cast<const uint8_t *>(data), offset, size));
424         onStorageUpdate(writeBuffer);
425     }
426 
427     mSize = std::max(mSize, requiredSize);
428     invalidateStaticData(context);
429 
430     return angle::Result::Continue;
431 }
432 
copySubData(const gl::Context * context,BufferImpl * source,GLintptr sourceOffset,GLintptr destOffset,GLsizeiptr size)433 angle::Result Buffer11::copySubData(const gl::Context *context,
434                                     BufferImpl *source,
435                                     GLintptr sourceOffset,
436                                     GLintptr destOffset,
437                                     GLsizeiptr size)
438 {
439     Buffer11 *sourceBuffer = GetAs<Buffer11>(source);
440     ASSERT(sourceBuffer != nullptr);
441 
442     BufferStorage *copyDest = nullptr;
443     ANGLE_TRY(getLatestBufferStorage(context, &copyDest));
444 
445     if (!copyDest)
446     {
447         ANGLE_TRY(getStagingStorage(context, &copyDest));
448     }
449 
450     BufferStorage *copySource = nullptr;
451     ANGLE_TRY(sourceBuffer->getLatestBufferStorage(context, &copySource));
452 
453     if (!copySource)
454     {
455         ANGLE_TRY(sourceBuffer->getStagingStorage(context, &copySource));
456     }
457 
458     ASSERT(copySource && copyDest);
459 
460     // A staging buffer is needed if there is no cpu-cpu or gpu-gpu copy path avaiable.
461     if (!copyDest->isGPUAccessible() && !copySource->isCPUAccessible(GL_MAP_READ_BIT))
462     {
463         ANGLE_TRY(sourceBuffer->getStagingStorage(context, &copySource));
464     }
465     else if (!copySource->isGPUAccessible() && !copyDest->isCPUAccessible(GL_MAP_WRITE_BIT))
466     {
467         ANGLE_TRY(getStagingStorage(context, &copyDest));
468     }
469 
470     // D3D11 does not allow overlapped copies until 11.1, and only if the
471     // device supports D3D11_FEATURE_DATA_D3D11_OPTIONS::CopyWithOverlap
472     // Get around this via a different source buffer
473     if (copySource == copyDest)
474     {
475         if (copySource->getUsage() == BUFFER_USAGE_STAGING)
476         {
477             ANGLE_TRY(
478                 getBufferStorage(context, BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK, &copySource));
479         }
480         else
481         {
482             ANGLE_TRY(getStagingStorage(context, &copySource));
483         }
484     }
485 
486     CopyResult copyResult = CopyResult::NOT_RECREATED;
487     ANGLE_TRY(copyDest->copyFromStorage(context, copySource, sourceOffset, size, destOffset,
488                                         &copyResult));
489     onStorageUpdate(copyDest);
490 
491     mSize = std::max<size_t>(mSize, destOffset + size);
492     invalidateStaticData(context);
493 
494     return angle::Result::Continue;
495 }
496 
map(const gl::Context * context,GLenum access,void ** mapPtr)497 angle::Result Buffer11::map(const gl::Context *context, GLenum access, void **mapPtr)
498 {
499     // GL_OES_mapbuffer uses an enum instead of a bitfield for it's access, convert to a bitfield
500     // and call mapRange.
501     ASSERT(access == GL_WRITE_ONLY_OES);
502     return mapRange(context, 0, mSize, GL_MAP_WRITE_BIT, mapPtr);
503 }
504 
mapRange(const gl::Context * context,size_t offset,size_t length,GLbitfield access,void ** mapPtr)505 angle::Result Buffer11::mapRange(const gl::Context *context,
506                                  size_t offset,
507                                  size_t length,
508                                  GLbitfield access,
509                                  void **mapPtr)
510 {
511     ASSERT(!mMappedStorage);
512 
513     BufferStorage *latestStorage = nullptr;
514     ANGLE_TRY(getLatestBufferStorage(context, &latestStorage));
515 
516     if (latestStorage && (latestStorage->getUsage() == BUFFER_USAGE_PIXEL_PACK ||
517                           latestStorage->getUsage() == BUFFER_USAGE_STAGING))
518     {
519         // Latest storage is mappable.
520         mMappedStorage = latestStorage;
521     }
522     else
523     {
524         // Fall back to using the staging buffer if the latest storage does not exist or is not
525         // CPU-accessible.
526         ANGLE_TRY(getStagingStorage(context, &mMappedStorage));
527     }
528 
529     Context11 *context11 = GetImplAs<Context11>(context);
530     ANGLE_CHECK_GL_ALLOC(context11, mMappedStorage);
531 
532     if ((access & GL_MAP_WRITE_BIT) > 0)
533     {
534         // Update the data revision immediately, since the data might be changed at any time
535         onStorageUpdate(mMappedStorage);
536         invalidateStaticData(context);
537     }
538 
539     uint8_t *mappedBuffer = nullptr;
540     ANGLE_TRY(mMappedStorage->map(context, offset, length, access, &mappedBuffer));
541     ASSERT(mappedBuffer);
542 
543     *mapPtr = static_cast<void *>(mappedBuffer);
544     return angle::Result::Continue;
545 }
546 
unmap(const gl::Context * context,GLboolean * result)547 angle::Result Buffer11::unmap(const gl::Context *context, GLboolean *result)
548 {
549     ASSERT(mMappedStorage);
550     mMappedStorage->unmap();
551     mMappedStorage = nullptr;
552 
553     // TODO: detect if we had corruption. if so, return false.
554     *result = GL_TRUE;
555 
556     return angle::Result::Continue;
557 }
558 
markTransformFeedbackUsage(const gl::Context * context)559 angle::Result Buffer11::markTransformFeedbackUsage(const gl::Context *context)
560 {
561     ANGLE_TRY(markBufferUsage(context, BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK));
562     return angle::Result::Continue;
563 }
564 
updateDeallocThreshold(BufferUsage usage)565 void Buffer11::updateDeallocThreshold(BufferUsage usage)
566 {
567     // The following strategy was tuned on the Oort online benchmark (http://oortonline.gl/)
568     // as well as a custom microbenchmark (IndexConversionPerfTest.Run/index_range_d3d11)
569 
570     // First readback: 8 unmodified uses before we free buffer memory.
571     // After that, double the threshold each time until we reach the max.
572     if (mDeallocThresholds[usage] == 0)
573     {
574         mDeallocThresholds[usage] = 8;
575     }
576     else if (mDeallocThresholds[usage] < std::numeric_limits<unsigned int>::max() / 2u)
577     {
578         mDeallocThresholds[usage] *= 2u;
579     }
580     else
581     {
582         mDeallocThresholds[usage] = std::numeric_limits<unsigned int>::max();
583     }
584 }
585 
586 // Free the storage if we decide it isn't being used very often.
checkForDeallocation(const gl::Context * context,BufferUsage usage)587 angle::Result Buffer11::checkForDeallocation(const gl::Context *context, BufferUsage usage)
588 {
589     mIdleness[usage]++;
590 
591     BufferStorage *&storage = mBufferStorages[usage];
592     if (storage != nullptr && mIdleness[usage] > mDeallocThresholds[usage])
593     {
594         BufferStorage *latestStorage = nullptr;
595         ANGLE_TRY(getLatestBufferStorage(context, &latestStorage));
596         if (latestStorage != storage)
597         {
598             SafeDelete(storage);
599         }
600     }
601 
602     return angle::Result::Continue;
603 }
604 
605 // Keep system memory when we are using it for the canonical version of data.
canDeallocateSystemMemory() const606 bool Buffer11::canDeallocateSystemMemory() const
607 {
608     // Must keep system memory on Intel.
609     if (mRenderer->getFeatures().useSystemMemoryForConstantBuffers.enabled)
610     {
611         return false;
612     }
613 
614     return (!mBufferStorages[BUFFER_USAGE_UNIFORM] ||
615             mSize <= static_cast<size_t>(mRenderer->getNativeCaps().maxUniformBlockSize));
616 }
617 
markBufferUsage(BufferUsage usage)618 void Buffer11::markBufferUsage(BufferUsage usage)
619 {
620     mIdleness[usage] = 0;
621 }
622 
markBufferUsage(const gl::Context * context,BufferUsage usage)623 angle::Result Buffer11::markBufferUsage(const gl::Context *context, BufferUsage usage)
624 {
625     BufferStorage *bufferStorage = nullptr;
626     ANGLE_TRY(getBufferStorage(context, usage, &bufferStorage));
627 
628     if (bufferStorage)
629     {
630         onStorageUpdate(bufferStorage);
631     }
632 
633     invalidateStaticData(context);
634     return angle::Result::Continue;
635 }
636 
garbageCollection(const gl::Context * context,BufferUsage currentUsage)637 angle::Result Buffer11::garbageCollection(const gl::Context *context, BufferUsage currentUsage)
638 {
639     if (currentUsage != BUFFER_USAGE_SYSTEM_MEMORY && canDeallocateSystemMemory())
640     {
641         ANGLE_TRY(checkForDeallocation(context, BUFFER_USAGE_SYSTEM_MEMORY));
642     }
643 
644     if (currentUsage != BUFFER_USAGE_STAGING)
645     {
646         ANGLE_TRY(checkForDeallocation(context, BUFFER_USAGE_STAGING));
647     }
648 
649     return angle::Result::Continue;
650 }
651 
getBuffer(const gl::Context * context,BufferUsage usage,ID3D11Buffer ** bufferOut)652 angle::Result Buffer11::getBuffer(const gl::Context *context,
653                                   BufferUsage usage,
654                                   ID3D11Buffer **bufferOut)
655 {
656     NativeStorage *storage = nullptr;
657     ANGLE_TRY(getBufferStorage(context, usage, &storage));
658     *bufferOut = storage->getBuffer().get();
659     return angle::Result::Continue;
660 }
661 
getConstantBufferRange(const gl::Context * context,GLintptr offset,GLsizeiptr size,const d3d11::Buffer ** bufferOut,UINT * firstConstantOut,UINT * numConstantsOut)662 angle::Result Buffer11::getConstantBufferRange(const gl::Context *context,
663                                                GLintptr offset,
664                                                GLsizeiptr size,
665                                                const d3d11::Buffer **bufferOut,
666                                                UINT *firstConstantOut,
667                                                UINT *numConstantsOut)
668 {
669     NativeStorage *bufferStorage = nullptr;
670     if ((offset == 0 &&
671          size < static_cast<GLsizeiptr>(mRenderer->getNativeCaps().maxUniformBlockSize)) ||
672         mRenderer->getRenderer11DeviceCaps().supportsConstantBufferOffsets)
673     {
674         ANGLE_TRY(getBufferStorage(context, BUFFER_USAGE_UNIFORM, &bufferStorage));
675         CalculateConstantBufferParams(offset, size, firstConstantOut, numConstantsOut);
676     }
677     else
678     {
679         ANGLE_TRY(getConstantBufferRangeStorage(context, offset, size, &bufferStorage));
680         *firstConstantOut = 0;
681         *numConstantsOut  = 0;
682     }
683 
684     *bufferOut = &bufferStorage->getBuffer();
685     return angle::Result::Continue;
686 }
687 
markRawBufferUsage(const gl::Context * context)688 angle::Result Buffer11::markRawBufferUsage(const gl::Context *context)
689 {
690     ANGLE_TRY(markBufferUsage(context, BUFFER_USAGE_RAW_UAV));
691     return angle::Result::Continue;
692 }
693 
markTypedBufferUsage(const gl::Context * context)694 angle::Result Buffer11::markTypedBufferUsage(const gl::Context *context)
695 {
696     ANGLE_TRY(markBufferUsage(context, BUFFER_USAGE_TYPED_UAV));
697     return angle::Result::Continue;
698 }
699 
getRawUAVRange(const gl::Context * context,GLintptr offset,GLsizeiptr size,d3d11::UnorderedAccessView ** uavOut)700 angle::Result Buffer11::getRawUAVRange(const gl::Context *context,
701                                        GLintptr offset,
702                                        GLsizeiptr size,
703                                        d3d11::UnorderedAccessView **uavOut)
704 {
705     NativeStorage *nativeStorage = nullptr;
706     ANGLE_TRY(getBufferStorage(context, BUFFER_USAGE_RAW_UAV, &nativeStorage));
707 
708     return nativeStorage->getRawUAV(context, static_cast<unsigned int>(offset),
709                                     static_cast<unsigned int>(size), uavOut);
710 }
711 
getSRV(const gl::Context * context,DXGI_FORMAT srvFormat,const d3d11::ShaderResourceView ** srvOut)712 angle::Result Buffer11::getSRV(const gl::Context *context,
713                                DXGI_FORMAT srvFormat,
714                                const d3d11::ShaderResourceView **srvOut)
715 {
716     NativeStorage *nativeStorage = nullptr;
717     ANGLE_TRY(getBufferStorage(context, BUFFER_USAGE_PIXEL_UNPACK, &nativeStorage));
718     return nativeStorage->getSRVForFormat(context, srvFormat, srvOut);
719 }
720 
packPixels(const gl::Context * context,const gl::FramebufferAttachment & readAttachment,const PackPixelsParams & params)721 angle::Result Buffer11::packPixels(const gl::Context *context,
722                                    const gl::FramebufferAttachment &readAttachment,
723                                    const PackPixelsParams &params)
724 {
725     PackStorage *packStorage = nullptr;
726     ANGLE_TRY(getBufferStorage(context, BUFFER_USAGE_PIXEL_PACK, &packStorage));
727 
728     ASSERT(packStorage);
729     ANGLE_TRY(packStorage->packPixels(context, readAttachment, params));
730     onStorageUpdate(packStorage);
731 
732     return angle::Result::Continue;
733 }
734 
getTotalCPUBufferMemoryBytes() const735 size_t Buffer11::getTotalCPUBufferMemoryBytes() const
736 {
737     size_t allocationSize = 0;
738 
739     BufferStorage *staging = mBufferStorages[BUFFER_USAGE_STAGING];
740     allocationSize += staging ? staging->getSize() : 0;
741 
742     BufferStorage *sysMem = mBufferStorages[BUFFER_USAGE_SYSTEM_MEMORY];
743     allocationSize += sysMem ? sysMem->getSize() : 0;
744 
745     return allocationSize;
746 }
747 
748 template <typename StorageOutT>
getBufferStorage(const gl::Context * context,BufferUsage usage,StorageOutT ** storageOut)749 angle::Result Buffer11::getBufferStorage(const gl::Context *context,
750                                          BufferUsage usage,
751                                          StorageOutT **storageOut)
752 {
753     ASSERT(0 <= usage && usage < BUFFER_USAGE_COUNT);
754     BufferStorage *&newStorage = mBufferStorages[usage];
755 
756     if (!newStorage)
757     {
758         newStorage = allocateStorage(usage);
759     }
760 
761     markBufferUsage(usage);
762 
763     // resize buffer
764     if (newStorage->getSize() < mSize)
765     {
766         ANGLE_TRY(newStorage->resize(context, mSize, true));
767     }
768 
769     ASSERT(newStorage);
770 
771     ANGLE_TRY(updateBufferStorage(context, newStorage, 0, mSize));
772     ANGLE_TRY(garbageCollection(context, usage));
773 
774     *storageOut = GetAs<StorageOutT>(newStorage);
775     return angle::Result::Continue;
776 }
777 
allocateStorage(BufferUsage usage)778 Buffer11::BufferStorage *Buffer11::allocateStorage(BufferUsage usage)
779 {
780     updateDeallocThreshold(usage);
781     switch (usage)
782     {
783         case BUFFER_USAGE_PIXEL_PACK:
784             return new PackStorage(mRenderer);
785         case BUFFER_USAGE_SYSTEM_MEMORY:
786             return new SystemMemoryStorage(mRenderer);
787         case BUFFER_USAGE_INDEX:
788         case BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK:
789             return new NativeStorage(mRenderer, usage, this);
790         case BUFFER_USAGE_STRUCTURED:
791             return new StructuredBufferStorage(mRenderer, usage, nullptr);
792         default:
793             return new NativeStorage(mRenderer, usage, nullptr);
794     }
795 }
796 
getConstantBufferRangeStorage(const gl::Context * context,GLintptr offset,GLsizeiptr size,Buffer11::NativeStorage ** storageOut)797 angle::Result Buffer11::getConstantBufferRangeStorage(const gl::Context *context,
798                                                       GLintptr offset,
799                                                       GLsizeiptr size,
800                                                       Buffer11::NativeStorage **storageOut)
801 {
802     BufferStorage *newStorage;
803     {
804         // Keep the cacheEntry in a limited scope because it may be invalidated later in the code if
805         // we need to reclaim some space.
806         BufferCacheEntry *cacheEntry = &mConstantBufferRangeStoragesCache[offset];
807 
808         if (!cacheEntry->storage)
809         {
810             cacheEntry->storage  = allocateStorage(BUFFER_USAGE_UNIFORM);
811             cacheEntry->lruCount = ++mMaxConstantBufferLruCount;
812         }
813 
814         cacheEntry->lruCount = ++mMaxConstantBufferLruCount;
815         newStorage           = cacheEntry->storage;
816     }
817 
818     markBufferUsage(BUFFER_USAGE_UNIFORM);
819 
820     if (newStorage->getSize() < static_cast<size_t>(size))
821     {
822         size_t maximumAllowedAdditionalSize = 2 * getSize();
823 
824         size_t sizeDelta = size - newStorage->getSize();
825 
826         while (mConstantBufferStorageAdditionalSize + sizeDelta > maximumAllowedAdditionalSize)
827         {
828             auto iter = std::min_element(
829                 std::begin(mConstantBufferRangeStoragesCache),
830                 std::end(mConstantBufferRangeStoragesCache),
831                 [](const BufferCache::value_type &a, const BufferCache::value_type &b) {
832                     return a.second.lruCount < b.second.lruCount;
833                 });
834 
835             ASSERT(iter->second.storage != newStorage);
836             ASSERT(mConstantBufferStorageAdditionalSize >= iter->second.storage->getSize());
837 
838             mConstantBufferStorageAdditionalSize -= iter->second.storage->getSize();
839             SafeDelete(iter->second.storage);
840             mConstantBufferRangeStoragesCache.erase(iter);
841         }
842 
843         ANGLE_TRY(newStorage->resize(context, size, false));
844         mConstantBufferStorageAdditionalSize += sizeDelta;
845 
846         // We don't copy the old data when resizing the constant buffer because the data may be
847         // out-of-date therefore we reset the data revision and let updateBufferStorage() handle the
848         // copy.
849         newStorage->setDataRevision(0);
850     }
851 
852     ANGLE_TRY(updateBufferStorage(context, newStorage, offset, size));
853     ANGLE_TRY(garbageCollection(context, BUFFER_USAGE_UNIFORM));
854     *storageOut = GetAs<NativeStorage>(newStorage);
855     return angle::Result::Continue;
856 }
857 
getStructuredBufferRangeSRV(const gl::Context * context,unsigned int offset,unsigned int size,unsigned int structureByteStride,const d3d11::ShaderResourceView ** srvOut)858 angle::Result Buffer11::getStructuredBufferRangeSRV(const gl::Context *context,
859                                                     unsigned int offset,
860                                                     unsigned int size,
861                                                     unsigned int structureByteStride,
862                                                     const d3d11::ShaderResourceView **srvOut)
863 {
864     BufferStorage *newStorage;
865 
866     {
867         // Keep the cacheEntry in a limited scope because it may be invalidated later in the code if
868         // we need to reclaim some space.
869         StructuredBufferKey structuredBufferKey = StructuredBufferKey(offset, structureByteStride);
870         BufferCacheEntry *cacheEntry = &mStructuredBufferRangeStoragesCache[structuredBufferKey];
871 
872         if (!cacheEntry->storage)
873         {
874             cacheEntry->storage  = allocateStorage(BUFFER_USAGE_STRUCTURED);
875             cacheEntry->lruCount = ++mMaxStructuredBufferLruCount;
876         }
877 
878         cacheEntry->lruCount = ++mMaxStructuredBufferLruCount;
879         newStorage           = cacheEntry->storage;
880     }
881 
882     StructuredBufferStorage *structuredBufferStorage = GetAs<StructuredBufferStorage>(newStorage);
883 
884     markBufferUsage(BUFFER_USAGE_STRUCTURED);
885 
886     if (newStorage->getSize() < static_cast<size_t>(size))
887     {
888         size_t maximumAllowedAdditionalSize = 2 * getSize();
889 
890         size_t sizeDelta = static_cast<size_t>(size) - newStorage->getSize();
891 
892         while (mStructuredBufferStorageAdditionalSize + sizeDelta > maximumAllowedAdditionalSize)
893         {
894             auto iter = std::min_element(std::begin(mStructuredBufferRangeStoragesCache),
895                                          std::end(mStructuredBufferRangeStoragesCache),
896                                          [](const StructuredBufferCache::value_type &a,
897                                             const StructuredBufferCache::value_type &b) {
898                                              return a.second.lruCount < b.second.lruCount;
899                                          });
900 
901             ASSERT(iter->second.storage != newStorage);
902             ASSERT(mStructuredBufferStorageAdditionalSize >= iter->second.storage->getSize());
903 
904             mStructuredBufferStorageAdditionalSize -= iter->second.storage->getSize();
905             SafeDelete(iter->second.storage);
906             mStructuredBufferRangeStoragesCache.erase(iter);
907         }
908 
909         ANGLE_TRY(
910             structuredBufferStorage->resizeStructuredBuffer(context, size, structureByteStride));
911         mStructuredBufferStorageAdditionalSize += sizeDelta;
912 
913         // We don't copy the old data when resizing the structured buffer because the data may be
914         // out-of-date therefore we reset the data revision and let updateBufferStorage() handle the
915         // copy.
916         newStorage->setDataRevision(0);
917     }
918 
919     ANGLE_TRY(updateBufferStorage(context, newStorage, offset, static_cast<size_t>(size)));
920     ANGLE_TRY(garbageCollection(context, BUFFER_USAGE_STRUCTURED));
921     ANGLE_TRY(structuredBufferStorage->getStructuredBufferRangeSRV(context, offset, size,
922                                                                    structureByteStride, srvOut));
923     return angle::Result::Continue;
924 }
925 
updateBufferStorage(const gl::Context * context,BufferStorage * storage,size_t sourceOffset,size_t storageSize)926 angle::Result Buffer11::updateBufferStorage(const gl::Context *context,
927                                             BufferStorage *storage,
928                                             size_t sourceOffset,
929                                             size_t storageSize)
930 {
931     BufferStorage *latestBuffer = nullptr;
932     ANGLE_TRY(getLatestBufferStorage(context, &latestBuffer));
933 
934     ASSERT(storage);
935 
936     if (!latestBuffer)
937     {
938         onStorageUpdate(storage);
939         return angle::Result::Continue;
940     }
941 
942     if (latestBuffer->getDataRevision() <= storage->getDataRevision())
943     {
944         return angle::Result::Continue;
945     }
946 
947     if (latestBuffer->getSize() == 0 || storage->getSize() == 0)
948     {
949         return angle::Result::Continue;
950     }
951 
952     // Copy through a staging buffer if we're copying from or to a non-staging, mappable
953     // buffer storage. This is because we can't map a GPU buffer, and copy CPU
954     // data directly. If we're already using a staging buffer we're fine.
955     if (latestBuffer->getUsage() != BUFFER_USAGE_STAGING &&
956         storage->getUsage() != BUFFER_USAGE_STAGING &&
957         (!latestBuffer->isCPUAccessible(GL_MAP_READ_BIT) ||
958          !storage->isCPUAccessible(GL_MAP_WRITE_BIT)))
959     {
960         NativeStorage *stagingBuffer = nullptr;
961         ANGLE_TRY(getStagingStorage(context, &stagingBuffer));
962 
963         CopyResult copyResult = CopyResult::NOT_RECREATED;
964         ANGLE_TRY(stagingBuffer->copyFromStorage(context, latestBuffer, 0, latestBuffer->getSize(),
965                                                  0, &copyResult));
966         onCopyStorage(stagingBuffer, latestBuffer);
967 
968         latestBuffer = stagingBuffer;
969     }
970 
971     CopyResult copyResult = CopyResult::NOT_RECREATED;
972     ANGLE_TRY(
973         storage->copyFromStorage(context, latestBuffer, sourceOffset, storageSize, 0, &copyResult));
974     // If the D3D buffer has been recreated, we should update our serial.
975     if (copyResult == CopyResult::RECREATED)
976     {
977         updateSerial();
978     }
979     onCopyStorage(storage, latestBuffer);
980     return angle::Result::Continue;
981 }
982 
getLatestBufferStorage(const gl::Context * context,Buffer11::BufferStorage ** storageOut) const983 angle::Result Buffer11::getLatestBufferStorage(const gl::Context *context,
984                                                Buffer11::BufferStorage **storageOut) const
985 {
986     // resize buffer
987     if (mLatestBufferStorage && mLatestBufferStorage->getSize() < mSize)
988     {
989         ANGLE_TRY(mLatestBufferStorage->resize(context, mSize, true));
990     }
991 
992     *storageOut = mLatestBufferStorage;
993     return angle::Result::Continue;
994 }
995 
996 template <typename StorageOutT>
getStagingStorage(const gl::Context * context,StorageOutT ** storageOut)997 angle::Result Buffer11::getStagingStorage(const gl::Context *context, StorageOutT **storageOut)
998 {
999     return getBufferStorage(context, BUFFER_USAGE_STAGING, storageOut);
1000 }
1001 
getSize() const1002 size_t Buffer11::getSize() const
1003 {
1004     return mSize;
1005 }
1006 
supportsDirectBinding() const1007 bool Buffer11::supportsDirectBinding() const
1008 {
1009     // Do not support direct buffers for dynamic data. The streaming buffer
1010     // offers better performance for data which changes every frame.
1011     return (mUsage == D3DBufferUsage::STATIC);
1012 }
1013 
initializeStaticData(const gl::Context * context)1014 void Buffer11::initializeStaticData(const gl::Context *context)
1015 {
1016     BufferD3D::initializeStaticData(context);
1017     onStateChange(angle::SubjectMessage::SubjectChanged);
1018 }
1019 
invalidateStaticData(const gl::Context * context)1020 void Buffer11::invalidateStaticData(const gl::Context *context)
1021 {
1022     BufferD3D::invalidateStaticData(context);
1023     onStateChange(angle::SubjectMessage::SubjectChanged);
1024 }
1025 
onCopyStorage(BufferStorage * dest,BufferStorage * source)1026 void Buffer11::onCopyStorage(BufferStorage *dest, BufferStorage *source)
1027 {
1028     ASSERT(source && mLatestBufferStorage);
1029     dest->setDataRevision(source->getDataRevision());
1030 
1031     // Only update the latest buffer storage if our usage index is lower. See comment in header.
1032     if (dest->getUsage() < mLatestBufferStorage->getUsage())
1033     {
1034         mLatestBufferStorage = dest;
1035     }
1036 }
1037 
onStorageUpdate(BufferStorage * updatedStorage)1038 void Buffer11::onStorageUpdate(BufferStorage *updatedStorage)
1039 {
1040     updatedStorage->setDataRevision(updatedStorage->getDataRevision() + 1);
1041     mLatestBufferStorage = updatedStorage;
1042 }
1043 
1044 // Buffer11::BufferStorage implementation
1045 
BufferStorage(Renderer11 * renderer,BufferUsage usage)1046 Buffer11::BufferStorage::BufferStorage(Renderer11 *renderer, BufferUsage usage)
1047     : mRenderer(renderer), mRevision(0), mUsage(usage), mBufferSize(0)
1048 {}
1049 
setData(const gl::Context * context,const uint8_t * data,size_t offset,size_t size)1050 angle::Result Buffer11::BufferStorage::setData(const gl::Context *context,
1051                                                const uint8_t *data,
1052                                                size_t offset,
1053                                                size_t size)
1054 {
1055     ASSERT(isCPUAccessible(GL_MAP_WRITE_BIT));
1056 
1057     // Uniform storage can have a different internal size than the buffer size. Ensure we don't
1058     // overflow.
1059     size_t mapSize = std::min(size, mBufferSize - offset);
1060 
1061     uint8_t *writePointer = nullptr;
1062     ANGLE_TRY(map(context, offset, mapSize, GL_MAP_WRITE_BIT, &writePointer));
1063 
1064     memcpy(writePointer, data, mapSize);
1065 
1066     unmap();
1067 
1068     return angle::Result::Continue;
1069 }
1070 
1071 // Buffer11::NativeStorage implementation
1072 
NativeStorage(Renderer11 * renderer,BufferUsage usage,const angle::Subject * onStorageChanged)1073 Buffer11::NativeStorage::NativeStorage(Renderer11 *renderer,
1074                                        BufferUsage usage,
1075                                        const angle::Subject *onStorageChanged)
1076     : BufferStorage(renderer, usage), mBuffer(), mOnStorageChanged(onStorageChanged)
1077 {}
1078 
~NativeStorage()1079 Buffer11::NativeStorage::~NativeStorage()
1080 {
1081     clearSRVs();
1082     clearUAVs();
1083 }
1084 
isCPUAccessible(GLbitfield access) const1085 bool Buffer11::NativeStorage::isCPUAccessible(GLbitfield access) const
1086 {
1087     if ((access & GL_MAP_READ_BIT) != 0)
1088     {
1089         // Read is more exclusive than write mappability.
1090         return (mUsage == BUFFER_USAGE_STAGING);
1091     }
1092     ASSERT((access & GL_MAP_WRITE_BIT) != 0);
1093     return (mUsage == BUFFER_USAGE_STAGING || mUsage == BUFFER_USAGE_UNIFORM ||
1094             mUsage == BUFFER_USAGE_STRUCTURED);
1095 }
1096 
1097 // 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)1098 angle::Result Buffer11::NativeStorage::copyFromStorage(const gl::Context *context,
1099                                                        BufferStorage *source,
1100                                                        size_t sourceOffset,
1101                                                        size_t size,
1102                                                        size_t destOffset,
1103                                                        CopyResult *resultOut)
1104 {
1105     size_t requiredSize = destOffset + size;
1106 
1107     // (Re)initialize D3D buffer if needed
1108     bool preserveData = (destOffset > 0);
1109     if (!mBuffer.valid() || mBufferSize < requiredSize)
1110     {
1111         ANGLE_TRY(resize(context, requiredSize, preserveData));
1112         *resultOut = CopyResult::RECREATED;
1113     }
1114     else
1115     {
1116         *resultOut = CopyResult::NOT_RECREATED;
1117     }
1118 
1119     size_t clampedSize = size;
1120     if (mUsage == BUFFER_USAGE_UNIFORM)
1121     {
1122         clampedSize = std::min(clampedSize, mBufferSize - destOffset);
1123     }
1124 
1125     if (clampedSize == 0)
1126     {
1127         return angle::Result::Continue;
1128     }
1129 
1130     if (source->getUsage() == BUFFER_USAGE_PIXEL_PACK ||
1131         source->getUsage() == BUFFER_USAGE_SYSTEM_MEMORY)
1132     {
1133         ASSERT(source->isCPUAccessible(GL_MAP_READ_BIT) && isCPUAccessible(GL_MAP_WRITE_BIT));
1134 
1135         // Uniform buffers must be mapped with write/discard.
1136         ASSERT(!(preserveData && mUsage == BUFFER_USAGE_UNIFORM));
1137 
1138         uint8_t *sourcePointer = nullptr;
1139         ANGLE_TRY(source->map(context, sourceOffset, clampedSize, GL_MAP_READ_BIT, &sourcePointer));
1140 
1141         auto err = setData(context, sourcePointer, destOffset, clampedSize);
1142         source->unmap();
1143         ANGLE_TRY(err);
1144     }
1145     else
1146     {
1147         D3D11_BOX srcBox;
1148         srcBox.left   = static_cast<unsigned int>(sourceOffset);
1149         srcBox.right  = static_cast<unsigned int>(sourceOffset + clampedSize);
1150         srcBox.top    = 0;
1151         srcBox.bottom = 1;
1152         srcBox.front  = 0;
1153         srcBox.back   = 1;
1154 
1155         const d3d11::Buffer *sourceBuffer = &GetAs<NativeStorage>(source)->getBuffer();
1156 
1157         ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
1158         deviceContext->CopySubresourceRegion(mBuffer.get(), 0,
1159                                              static_cast<unsigned int>(destOffset), 0, 0,
1160                                              sourceBuffer->get(), 0, &srcBox);
1161     }
1162 
1163     return angle::Result::Continue;
1164 }
1165 
resize(const gl::Context * context,size_t size,bool preserveData)1166 angle::Result Buffer11::NativeStorage::resize(const gl::Context *context,
1167                                               size_t size,
1168                                               bool preserveData)
1169 {
1170     if (size == 0)
1171     {
1172         mBuffer.reset();
1173         mBufferSize = 0;
1174         return angle::Result::Continue;
1175     }
1176 
1177     D3D11_BUFFER_DESC bufferDesc;
1178     FillBufferDesc(&bufferDesc, mRenderer, mUsage, static_cast<unsigned int>(size));
1179 
1180     d3d11::Buffer newBuffer;
1181     ANGLE_TRY(
1182         mRenderer->allocateResource(SafeGetImplAs<Context11>(context), bufferDesc, &newBuffer));
1183     newBuffer.setInternalName("Buffer11::NativeStorage");
1184 
1185     if (mBuffer.valid() && preserveData)
1186     {
1187         // We don't call resize if the buffer is big enough already.
1188         ASSERT(mBufferSize <= size);
1189 
1190         D3D11_BOX srcBox;
1191         srcBox.left   = 0;
1192         srcBox.right  = static_cast<unsigned int>(mBufferSize);
1193         srcBox.top    = 0;
1194         srcBox.bottom = 1;
1195         srcBox.front  = 0;
1196         srcBox.back   = 1;
1197 
1198         ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
1199         deviceContext->CopySubresourceRegion(newBuffer.get(), 0, 0, 0, 0, mBuffer.get(), 0,
1200                                              &srcBox);
1201     }
1202 
1203     // No longer need the old buffer
1204     mBuffer = std::move(newBuffer);
1205 
1206     mBufferSize = bufferDesc.ByteWidth;
1207 
1208     // Free the SRVs.
1209     clearSRVs();
1210 
1211     // Free the UAVs.
1212     clearUAVs();
1213 
1214     // Notify that the storage has changed.
1215     if (mOnStorageChanged)
1216     {
1217         mOnStorageChanged->onStateChange(angle::SubjectMessage::SubjectChanged);
1218     }
1219 
1220     return angle::Result::Continue;
1221 }
1222 
1223 // static
FillBufferDesc(D3D11_BUFFER_DESC * bufferDesc,Renderer11 * renderer,BufferUsage usage,unsigned int bufferSize)1224 void Buffer11::NativeStorage::FillBufferDesc(D3D11_BUFFER_DESC *bufferDesc,
1225                                              Renderer11 *renderer,
1226                                              BufferUsage usage,
1227                                              unsigned int bufferSize)
1228 {
1229     bufferDesc->ByteWidth           = bufferSize;
1230     bufferDesc->MiscFlags           = 0;
1231     bufferDesc->StructureByteStride = 0;
1232 
1233     switch (usage)
1234     {
1235         case BUFFER_USAGE_STAGING:
1236             bufferDesc->Usage          = D3D11_USAGE_STAGING;
1237             bufferDesc->BindFlags      = 0;
1238             bufferDesc->CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
1239             break;
1240 
1241         case BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK:
1242             bufferDesc->Usage     = D3D11_USAGE_DEFAULT;
1243             bufferDesc->BindFlags = D3D11_BIND_VERTEX_BUFFER;
1244 
1245             if (renderer->isES3Capable())
1246             {
1247                 bufferDesc->BindFlags |= D3D11_BIND_STREAM_OUTPUT;
1248             }
1249 
1250             bufferDesc->CPUAccessFlags = 0;
1251             break;
1252 
1253         case BUFFER_USAGE_INDEX:
1254             bufferDesc->Usage          = D3D11_USAGE_DEFAULT;
1255             bufferDesc->BindFlags      = D3D11_BIND_INDEX_BUFFER;
1256             bufferDesc->CPUAccessFlags = 0;
1257             break;
1258 
1259         case BUFFER_USAGE_INDIRECT:
1260             bufferDesc->MiscFlags      = D3D11_RESOURCE_MISC_DRAWINDIRECT_ARGS;
1261             bufferDesc->Usage          = D3D11_USAGE_DEFAULT;
1262             bufferDesc->BindFlags      = 0;
1263             bufferDesc->CPUAccessFlags = 0;
1264             break;
1265 
1266         case BUFFER_USAGE_PIXEL_UNPACK:
1267             bufferDesc->Usage          = D3D11_USAGE_DEFAULT;
1268             bufferDesc->BindFlags      = D3D11_BIND_SHADER_RESOURCE;
1269             bufferDesc->CPUAccessFlags = 0;
1270             break;
1271 
1272         case BUFFER_USAGE_UNIFORM:
1273             bufferDesc->Usage          = D3D11_USAGE_DYNAMIC;
1274             bufferDesc->BindFlags      = D3D11_BIND_CONSTANT_BUFFER;
1275             bufferDesc->CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
1276 
1277             // Constant buffers must be of a limited size, and aligned to 16 byte boundaries
1278             // For our purposes we ignore any buffer data past the maximum constant buffer size
1279             bufferDesc->ByteWidth = roundUpPow2(bufferDesc->ByteWidth, 16u);
1280 
1281             // Note: it seems that D3D11 allows larger buffers on some platforms, but not all.
1282             // (Windows 10 seems to allow larger constant buffers, but not Windows 7)
1283             if (!renderer->getRenderer11DeviceCaps().supportsConstantBufferOffsets)
1284             {
1285                 bufferDesc->ByteWidth = std::min<UINT>(
1286                     bufferDesc->ByteWidth,
1287                     static_cast<UINT>(renderer->getNativeCaps().maxUniformBlockSize));
1288             }
1289             break;
1290 
1291         case BUFFER_USAGE_RAW_UAV:
1292             bufferDesc->MiscFlags      = D3D11_RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS;
1293             bufferDesc->BindFlags      = D3D11_BIND_UNORDERED_ACCESS;
1294             bufferDesc->Usage          = D3D11_USAGE_DEFAULT;
1295             bufferDesc->CPUAccessFlags = 0;
1296             break;
1297         case BUFFER_USAGE_TYPED_UAV:
1298             bufferDesc->BindFlags      = D3D11_BIND_UNORDERED_ACCESS | D3D11_BIND_SHADER_RESOURCE;
1299             bufferDesc->Usage          = D3D11_USAGE_DEFAULT;
1300             bufferDesc->CPUAccessFlags = 0;
1301             bufferDesc->MiscFlags      = 0;
1302             break;
1303 
1304         default:
1305             UNREACHABLE();
1306     }
1307 }
1308 
map(const gl::Context * context,size_t offset,size_t length,GLbitfield access,uint8_t ** mapPointerOut)1309 angle::Result Buffer11::NativeStorage::map(const gl::Context *context,
1310                                            size_t offset,
1311                                            size_t length,
1312                                            GLbitfield access,
1313                                            uint8_t **mapPointerOut)
1314 {
1315     ASSERT(isCPUAccessible(access));
1316 
1317     D3D11_MAPPED_SUBRESOURCE mappedResource;
1318     D3D11_MAP d3dMapType = gl_d3d11::GetD3DMapTypeFromBits(mUsage, access);
1319 
1320     ANGLE_TRY(mRenderer->mapResource(context, mBuffer.get(), 0, d3dMapType, 0, &mappedResource));
1321     ASSERT(mappedResource.pData);
1322     *mapPointerOut = static_cast<uint8_t *>(mappedResource.pData) + offset;
1323     return angle::Result::Continue;
1324 }
1325 
unmap()1326 void Buffer11::NativeStorage::unmap()
1327 {
1328     ASSERT(isCPUAccessible(GL_MAP_WRITE_BIT) || isCPUAccessible(GL_MAP_READ_BIT));
1329     ID3D11DeviceContext *context = mRenderer->getDeviceContext();
1330     context->Unmap(mBuffer.get(), 0);
1331 }
1332 
getSRVForFormat(const gl::Context * context,DXGI_FORMAT srvFormat,const d3d11::ShaderResourceView ** srvOut)1333 angle::Result Buffer11::NativeStorage::getSRVForFormat(const gl::Context *context,
1334                                                        DXGI_FORMAT srvFormat,
1335                                                        const d3d11::ShaderResourceView **srvOut)
1336 {
1337     auto bufferSRVIt = mBufferResourceViews.find(srvFormat);
1338 
1339     if (bufferSRVIt != mBufferResourceViews.end())
1340     {
1341         *srvOut = &bufferSRVIt->second;
1342         return angle::Result::Continue;
1343     }
1344 
1345     const d3d11::DXGIFormatSize &dxgiFormatInfo = d3d11::GetDXGIFormatSizeInfo(srvFormat);
1346 
1347     D3D11_SHADER_RESOURCE_VIEW_DESC bufferSRVDesc;
1348     bufferSRVDesc.Buffer.ElementOffset = 0;
1349     bufferSRVDesc.Buffer.ElementWidth  = static_cast<UINT>(mBufferSize) / dxgiFormatInfo.pixelBytes;
1350     bufferSRVDesc.ViewDimension        = D3D11_SRV_DIMENSION_BUFFER;
1351     bufferSRVDesc.Format               = srvFormat;
1352 
1353     ANGLE_TRY(mRenderer->allocateResource(GetImplAs<Context11>(context), bufferSRVDesc,
1354                                           mBuffer.get(), &mBufferResourceViews[srvFormat]));
1355 
1356     *srvOut = &mBufferResourceViews[srvFormat];
1357     return angle::Result::Continue;
1358 }
1359 
getRawUAV(const gl::Context * context,unsigned int offset,unsigned int size,d3d11::UnorderedAccessView ** uavOut)1360 angle::Result Buffer11::NativeStorage::getRawUAV(const gl::Context *context,
1361                                                  unsigned int offset,
1362                                                  unsigned int size,
1363                                                  d3d11::UnorderedAccessView **uavOut)
1364 {
1365     ASSERT(offset + size <= mBufferSize);
1366 
1367     auto bufferRawUAV = mBufferRawUAVs.find({offset, size});
1368     if (bufferRawUAV != mBufferRawUAVs.end())
1369     {
1370         *uavOut = &bufferRawUAV->second;
1371         return angle::Result::Continue;
1372     }
1373 
1374     D3D11_UNORDERED_ACCESS_VIEW_DESC bufferUAVDesc;
1375 
1376     // DXGI_FORMAT_R32_TYPELESS uses 4 bytes per element
1377     constexpr int kBytesToElement     = 4;
1378     bufferUAVDesc.Buffer.FirstElement = offset / kBytesToElement;
1379     bufferUAVDesc.Buffer.NumElements  = size / kBytesToElement;
1380     bufferUAVDesc.Buffer.Flags        = D3D11_BUFFER_UAV_FLAG_RAW;
1381     bufferUAVDesc.Format = DXGI_FORMAT_R32_TYPELESS;  // Format must be DXGI_FORMAT_R32_TYPELESS,
1382                                                       // when creating Raw Unordered Access View
1383     bufferUAVDesc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER;
1384 
1385     ANGLE_TRY(mRenderer->allocateResource(GetImplAs<Context11>(context), bufferUAVDesc,
1386                                           mBuffer.get(), &mBufferRawUAVs[{offset, size}]));
1387     *uavOut = &mBufferRawUAVs[{offset, size}];
1388     return angle::Result::Continue;
1389 }
1390 
clearSRVs()1391 void Buffer11::NativeStorage::clearSRVs()
1392 {
1393     mBufferResourceViews.clear();
1394 }
1395 
clearUAVs()1396 void Buffer11::NativeStorage::clearUAVs()
1397 {
1398     mBufferRawUAVs.clear();
1399 }
1400 
StructuredBufferStorage(Renderer11 * renderer,BufferUsage usage,const angle::Subject * onStorageChanged)1401 Buffer11::StructuredBufferStorage::StructuredBufferStorage(Renderer11 *renderer,
1402                                                            BufferUsage usage,
1403                                                            const angle::Subject *onStorageChanged)
1404     : NativeStorage(renderer, usage, onStorageChanged), mStructuredBufferResourceView()
1405 {}
1406 
~StructuredBufferStorage()1407 Buffer11::StructuredBufferStorage::~StructuredBufferStorage()
1408 {
1409     mStructuredBufferResourceView.reset();
1410 }
1411 
resizeStructuredBuffer(const gl::Context * context,unsigned int size,unsigned int structureByteStride)1412 angle::Result Buffer11::StructuredBufferStorage::resizeStructuredBuffer(
1413     const gl::Context *context,
1414     unsigned int size,
1415     unsigned int structureByteStride)
1416 {
1417     if (size == 0)
1418     {
1419         mBuffer.reset();
1420         mBufferSize = 0;
1421         return angle::Result::Continue;
1422     }
1423 
1424     D3D11_BUFFER_DESC bufferDesc;
1425     bufferDesc.ByteWidth           = size;
1426     bufferDesc.MiscFlags           = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED;
1427     bufferDesc.StructureByteStride = structureByteStride;
1428     bufferDesc.Usage               = D3D11_USAGE_DYNAMIC;
1429     bufferDesc.BindFlags           = D3D11_BIND_SHADER_RESOURCE;
1430     bufferDesc.CPUAccessFlags      = D3D11_CPU_ACCESS_WRITE;
1431 
1432     d3d11::Buffer newBuffer;
1433     ANGLE_TRY(
1434         mRenderer->allocateResource(SafeGetImplAs<Context11>(context), bufferDesc, &newBuffer));
1435     newBuffer.setInternalName("Buffer11::StructuredBufferStorage");
1436 
1437     // No longer need the old buffer
1438     mBuffer = std::move(newBuffer);
1439 
1440     mBufferSize = static_cast<size_t>(bufferDesc.ByteWidth);
1441 
1442     mStructuredBufferResourceView.reset();
1443 
1444     // Notify that the storage has changed.
1445     if (mOnStorageChanged)
1446     {
1447         mOnStorageChanged->onStateChange(angle::SubjectMessage::SubjectChanged);
1448     }
1449 
1450     return angle::Result::Continue;
1451 }
1452 
getStructuredBufferRangeSRV(const gl::Context * context,unsigned int offset,unsigned int size,unsigned int structureByteStride,const d3d11::ShaderResourceView ** srvOut)1453 angle::Result Buffer11::StructuredBufferStorage::getStructuredBufferRangeSRV(
1454     const gl::Context *context,
1455     unsigned int offset,
1456     unsigned int size,
1457     unsigned int structureByteStride,
1458     const d3d11::ShaderResourceView **srvOut)
1459 {
1460     if (mStructuredBufferResourceView.valid())
1461     {
1462         *srvOut = &mStructuredBufferResourceView;
1463         return angle::Result::Continue;
1464     }
1465 
1466     D3D11_SHADER_RESOURCE_VIEW_DESC bufferSRVDesc = {};
1467     bufferSRVDesc.BufferEx.NumElements = structureByteStride == 0u ? 1 : size / structureByteStride;
1468     bufferSRVDesc.BufferEx.FirstElement = 0;
1469     bufferSRVDesc.BufferEx.Flags        = 0;
1470     bufferSRVDesc.ViewDimension         = D3D11_SRV_DIMENSION_BUFFEREX;
1471     bufferSRVDesc.Format                = DXGI_FORMAT_UNKNOWN;
1472 
1473     ANGLE_TRY(mRenderer->allocateResource(GetImplAs<Context11>(context), bufferSRVDesc,
1474                                           mBuffer.get(), &mStructuredBufferResourceView));
1475 
1476     *srvOut = &mStructuredBufferResourceView;
1477     return angle::Result::Continue;
1478 }
1479 
1480 // Buffer11::PackStorage implementation
1481 
PackStorage(Renderer11 * renderer)1482 Buffer11::PackStorage::PackStorage(Renderer11 *renderer)
1483     : BufferStorage(renderer, BUFFER_USAGE_PIXEL_PACK), mStagingTexture(), mDataModified(false)
1484 {}
1485 
~PackStorage()1486 Buffer11::PackStorage::~PackStorage() {}
1487 
copyFromStorage(const gl::Context * context,BufferStorage * source,size_t sourceOffset,size_t size,size_t destOffset,CopyResult * resultOut)1488 angle::Result Buffer11::PackStorage::copyFromStorage(const gl::Context *context,
1489                                                      BufferStorage *source,
1490                                                      size_t sourceOffset,
1491                                                      size_t size,
1492                                                      size_t destOffset,
1493                                                      CopyResult *resultOut)
1494 {
1495     ANGLE_TRY(flushQueuedPackCommand(context));
1496 
1497     // For all use cases of pack buffers, we must copy through a readable buffer.
1498     ASSERT(source->isCPUAccessible(GL_MAP_READ_BIT));
1499     uint8_t *sourceData = nullptr;
1500     ANGLE_TRY(source->map(context, sourceOffset, size, GL_MAP_READ_BIT, &sourceData));
1501     ASSERT(destOffset + size <= mMemoryBuffer.size());
1502     memcpy(mMemoryBuffer.data() + destOffset, sourceData, size);
1503     source->unmap();
1504     *resultOut = CopyResult::NOT_RECREATED;
1505     return angle::Result::Continue;
1506 }
1507 
resize(const gl::Context * context,size_t size,bool preserveData)1508 angle::Result Buffer11::PackStorage::resize(const gl::Context *context,
1509                                             size_t size,
1510                                             bool preserveData)
1511 {
1512     if (size != mBufferSize)
1513     {
1514         Context11 *context11 = GetImplAs<Context11>(context);
1515         ANGLE_CHECK_GL_ALLOC(context11, mMemoryBuffer.resize(size));
1516         mBufferSize = size;
1517     }
1518 
1519     return angle::Result::Continue;
1520 }
1521 
map(const gl::Context * context,size_t offset,size_t length,GLbitfield access,uint8_t ** mapPointerOut)1522 angle::Result Buffer11::PackStorage::map(const gl::Context *context,
1523                                          size_t offset,
1524                                          size_t length,
1525                                          GLbitfield access,
1526                                          uint8_t **mapPointerOut)
1527 {
1528     ASSERT(offset + length <= getSize());
1529     // TODO: fast path
1530     //  We might be able to optimize out one or more memcpy calls by detecting when
1531     //  and if D3D packs the staging texture memory identically to how we would fill
1532     //  the pack buffer according to the current pack state.
1533 
1534     ANGLE_TRY(flushQueuedPackCommand(context));
1535 
1536     mDataModified = (mDataModified || (access & GL_MAP_WRITE_BIT) != 0);
1537 
1538     *mapPointerOut = mMemoryBuffer.data() + offset;
1539     return angle::Result::Continue;
1540 }
1541 
unmap()1542 void Buffer11::PackStorage::unmap()
1543 {
1544     // No-op
1545 }
1546 
packPixels(const gl::Context * context,const gl::FramebufferAttachment & readAttachment,const PackPixelsParams & params)1547 angle::Result Buffer11::PackStorage::packPixels(const gl::Context *context,
1548                                                 const gl::FramebufferAttachment &readAttachment,
1549                                                 const PackPixelsParams &params)
1550 {
1551     ANGLE_TRY(flushQueuedPackCommand(context));
1552 
1553     RenderTarget11 *renderTarget = nullptr;
1554     ANGLE_TRY(readAttachment.getRenderTarget(context, 0, &renderTarget));
1555 
1556     const TextureHelper11 &srcTexture = renderTarget->getTexture();
1557     ASSERT(srcTexture.valid());
1558     unsigned int srcSubresource = renderTarget->getSubresourceIndex();
1559 
1560     mQueuedPackCommand.reset(new PackPixelsParams(params));
1561 
1562     gl::Extents srcTextureSize(params.area.width, params.area.height, 1);
1563     if (!mStagingTexture.get() || mStagingTexture.getFormat() != srcTexture.getFormat() ||
1564         mStagingTexture.getExtents() != srcTextureSize)
1565     {
1566         ANGLE_TRY(mRenderer->createStagingTexture(context, srcTexture.getTextureType(),
1567                                                   srcTexture.getFormatSet(), srcTextureSize,
1568                                                   StagingAccess::READ, &mStagingTexture));
1569     }
1570 
1571     // ReadPixels from multisampled FBOs isn't supported in current GL
1572     ASSERT(srcTexture.getSampleCount() <= 1);
1573 
1574     ID3D11DeviceContext *immediateContext = mRenderer->getDeviceContext();
1575     D3D11_BOX srcBox;
1576     srcBox.left   = params.area.x;
1577     srcBox.right  = params.area.x + params.area.width;
1578     srcBox.top    = params.area.y;
1579     srcBox.bottom = params.area.y + params.area.height;
1580 
1581     // Select the correct layer from a 3D attachment
1582     srcBox.front = 0;
1583     if (mStagingTexture.is3D())
1584     {
1585         srcBox.front = static_cast<UINT>(readAttachment.layer());
1586     }
1587     srcBox.back = srcBox.front + 1;
1588 
1589     // Asynchronous copy
1590     immediateContext->CopySubresourceRegion(mStagingTexture.get(), 0, 0, 0, 0, srcTexture.get(),
1591                                             srcSubresource, &srcBox);
1592 
1593     return angle::Result::Continue;
1594 }
1595 
flushQueuedPackCommand(const gl::Context * context)1596 angle::Result Buffer11::PackStorage::flushQueuedPackCommand(const gl::Context *context)
1597 {
1598     ASSERT(mMemoryBuffer.size() > 0);
1599 
1600     if (mQueuedPackCommand)
1601     {
1602         ANGLE_TRY(mRenderer->packPixels(context, mStagingTexture, *mQueuedPackCommand,
1603                                         mMemoryBuffer.data()));
1604         mQueuedPackCommand.reset(nullptr);
1605     }
1606 
1607     return angle::Result::Continue;
1608 }
1609 
1610 // Buffer11::SystemMemoryStorage implementation
1611 
SystemMemoryStorage(Renderer11 * renderer)1612 Buffer11::SystemMemoryStorage::SystemMemoryStorage(Renderer11 *renderer)
1613     : Buffer11::BufferStorage(renderer, BUFFER_USAGE_SYSTEM_MEMORY)
1614 {}
1615 
copyFromStorage(const gl::Context * context,BufferStorage * source,size_t sourceOffset,size_t size,size_t destOffset,CopyResult * resultOut)1616 angle::Result Buffer11::SystemMemoryStorage::copyFromStorage(const gl::Context *context,
1617                                                              BufferStorage *source,
1618                                                              size_t sourceOffset,
1619                                                              size_t size,
1620                                                              size_t destOffset,
1621                                                              CopyResult *resultOut)
1622 {
1623     ASSERT(source->isCPUAccessible(GL_MAP_READ_BIT));
1624     uint8_t *sourceData = nullptr;
1625     ANGLE_TRY(source->map(context, sourceOffset, size, GL_MAP_READ_BIT, &sourceData));
1626     ASSERT(destOffset + size <= mSystemCopy.size());
1627     memcpy(mSystemCopy.data() + destOffset, sourceData, size);
1628     source->unmap();
1629     *resultOut = CopyResult::RECREATED;
1630     return angle::Result::Continue;
1631 }
1632 
resize(const gl::Context * context,size_t size,bool preserveData)1633 angle::Result Buffer11::SystemMemoryStorage::resize(const gl::Context *context,
1634                                                     size_t size,
1635                                                     bool preserveData)
1636 {
1637     if (mSystemCopy.size() < size)
1638     {
1639         Context11 *context11 = GetImplAs<Context11>(context);
1640         ANGLE_CHECK_GL_ALLOC(context11, mSystemCopy.resize(size));
1641         mBufferSize = size;
1642     }
1643 
1644     return angle::Result::Continue;
1645 }
1646 
map(const gl::Context * context,size_t offset,size_t length,GLbitfield access,uint8_t ** mapPointerOut)1647 angle::Result Buffer11::SystemMemoryStorage::map(const gl::Context *context,
1648                                                  size_t offset,
1649                                                  size_t length,
1650                                                  GLbitfield access,
1651                                                  uint8_t **mapPointerOut)
1652 {
1653     ASSERT(!mSystemCopy.empty() && offset + length <= mSystemCopy.size());
1654     *mapPointerOut = mSystemCopy.data() + offset;
1655     return angle::Result::Continue;
1656 }
1657 
unmap()1658 void Buffer11::SystemMemoryStorage::unmap()
1659 {
1660     // No-op
1661 }
1662 }  // namespace rx
1663