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 ¶ms);
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, ©Dest));
476
477 if (!copyDest)
478 {
479 ANGLE_TRY(getStagingStorage(context, ©Dest));
480 }
481
482 BufferStorage *copySource = nullptr;
483 ANGLE_TRY(sourceBuffer->getLatestBufferStorage(context, ©Source));
484
485 if (!copySource)
486 {
487 ANGLE_TRY(sourceBuffer->getStagingStorage(context, ©Source));
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, ©Source));
496 }
497 else if (!copySource->isGPUAccessible() && !copyDest->isCPUAccessible(GL_MAP_WRITE_BIT))
498 {
499 ANGLE_TRY(getStagingStorage(context, ©Dest));
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, ©Source));
511 }
512 else
513 {
514 ANGLE_TRY(getStagingStorage(context, ©Source));
515 }
516 }
517
518 CopyResult copyResult = CopyResult::NOT_RECREATED;
519 ANGLE_TRY(copyDest->copyFromStorage(context, copySource, sourceOffset, size, destOffset,
520 ©Result));
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 ¶ms)
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, ©Result));
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, ©Result));
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 ¶ms)
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