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