diff options
Diffstat (limited to 'src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Buffer11.cpp')
-rw-r--r-- | src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Buffer11.cpp | 1379 |
1 files changed, 773 insertions, 606 deletions
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Buffer11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Buffer11.cpp index 0d5dc08b03..2317c9abdb 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Buffer11.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Buffer11.cpp @@ -13,10 +13,14 @@ #include "common/MemoryBuffer.h" #include "libANGLE/renderer/d3d/IndexDataManager.h" #include "libANGLE/renderer/d3d/VertexDataManager.h" -#include "libANGLE/renderer/d3d/d3d11/Renderer11.h" #include "libANGLE/renderer/d3d/d3d11/RenderTarget11.h" -#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" +#include "libANGLE/renderer/d3d/d3d11/Renderer11.h" #include "libANGLE/renderer/d3d/d3d11/formatutils11.h" +#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" +#include "libANGLE/renderer/renderer_utils.h" + +namespace rx +{ namespace { @@ -27,41 +31,41 @@ GLuint ReadIndexValueFromIndices(const uint8_t *data, size_t index) return reinterpret_cast<const T *>(data)[index]; } typedef GLuint (*ReadIndexValueFunction)(const uint8_t *data, size_t index); -} - -#if defined(ANGLE_MINGW32_COMPAT) -typedef enum D3D11_MAP_FLAG { - D3D11_MAP_FLAG_DO_NOT_WAIT = 0x100000 -} D3D11_MAP_FLAG; -#endif -namespace rx -{ -PackPixelsParams::PackPixelsParams() - : format(GL_NONE), type(GL_NONE), outputPitch(0), packBuffer(nullptr), offset(0) +enum class CopyResult { -} + RECREATED, + NOT_RECREATED, +}; -PackPixelsParams::PackPixelsParams(const gl::Rectangle &areaIn, - GLenum formatIn, - GLenum typeIn, - GLuint outputPitchIn, - const gl::PixelPackState &packIn, - ptrdiff_t offsetIn) - : area(areaIn), - format(formatIn), - type(typeIn), - outputPitch(outputPitchIn), - packBuffer(packIn.pixelBuffer.get()), - pack(packIn.alignment, packIn.reverseRowOrder), - offset(offsetIn) +void CalculateConstantBufferParams(GLintptr offset, + GLsizeiptr size, + UINT *outFirstConstant, + UINT *outNumConstants) { + // The offset must be aligned to 256 bytes (should have been enforced by glBindBufferRange). + ASSERT(offset % 256 == 0); + + // firstConstant and numConstants are expressed in constants of 16-bytes. Furthermore they must + // be a multiple of 16 constants. + *outFirstConstant = static_cast<UINT>(offset / 16); + + // The GL size is not required to be aligned to a 256 bytes boundary. + // Round the size up to a 256 bytes boundary then express the results in constants of 16-bytes. + *outNumConstants = static_cast<UINT>(rx::roundUp(size, static_cast<GLsizeiptr>(256)) / 16); + + // Since the size is rounded up, firstConstant + numConstants may be bigger than the actual size + // of the buffer. This behaviour is explictly allowed according to the documentation on + // ID3D11DeviceContext1::PSSetConstantBuffers1 + // https://msdn.microsoft.com/en-us/library/windows/desktop/hh404649%28v=vs.85%29.aspx } +} // anonymous namespace + namespace gl_d3d11 { -D3D11_MAP GetD3DMapTypeFromBits(GLbitfield access) +D3D11_MAP GetD3DMapTypeFromBits(BufferUsage usage, GLbitfield access) { bool readBit = ((access & GL_MAP_READ_BIT) != 0); bool writeBit = ((access & GL_MAP_WRITE_BIT) != 0); @@ -77,7 +81,8 @@ D3D11_MAP GetD3DMapTypeFromBits(GLbitfield access) } else if (writeBit && !readBit) { - return D3D11_MAP_WRITE; + // Special case for uniform storage - we only allow full buffer updates. + return usage == BUFFER_USAGE_UNIFORM ? D3D11_MAP_WRITE_DISCARD : D3D11_MAP_WRITE; } else if (writeBit && readBit) { @@ -89,7 +94,7 @@ D3D11_MAP GetD3DMapTypeFromBits(GLbitfield access) return D3D11_MAP_READ; } } -} +} // namespace gl_d3d11 // Each instance of Buffer11::BufferStorage is specialized for a class of D3D binding points // - vertex/transform feedback buffers @@ -106,16 +111,22 @@ class Buffer11::BufferStorage : angle::NonCopyable size_t getSize() const { return mBufferSize; } void setDataRevision(DataRevision rev) { mRevision = rev; } - virtual bool isMappable() const = 0; + virtual bool isCPUAccessible(GLbitfield access) const = 0; + + virtual bool isGPUAccessible() const = 0; - virtual bool copyFromStorage(BufferStorage *source, - size_t sourceOffset, - size_t size, - size_t destOffset) = 0; - virtual gl::Error resize(size_t size, bool preserveData) = 0; + virtual gl::ErrorOrResult<CopyResult> copyFromStorage(const gl::Context *context, + BufferStorage *source, + size_t sourceOffset, + size_t size, + size_t destOffset) = 0; + virtual gl::Error resize(const gl::Context *context, size_t size, bool preserveData) = 0; - virtual uint8_t *map(size_t offset, size_t length, GLbitfield access) = 0; - virtual void unmap() = 0; + virtual gl::Error map(size_t offset, + size_t length, + GLbitfield access, + uint8_t **mapPointerOut) = 0; + virtual void unmap() = 0; gl::Error setData(const uint8_t *data, size_t offset, size_t size); @@ -133,28 +144,41 @@ class Buffer11::BufferStorage : angle::NonCopyable class Buffer11::NativeStorage : public Buffer11::BufferStorage { public: - NativeStorage(Renderer11 *renderer, BufferUsage usage); + NativeStorage(Renderer11 *renderer, + BufferUsage usage, + const OnBufferDataDirtyChannel *onStorageChanged); ~NativeStorage() override; - bool isMappable() const override { return mUsage == BUFFER_USAGE_STAGING; } + bool isCPUAccessible(GLbitfield access) const override; + + bool isGPUAccessible() const override { return true; } - ID3D11Buffer *getNativeStorage() const { return mNativeStorage; } - bool copyFromStorage(BufferStorage *source, - size_t sourceOffset, - size_t size, - size_t destOffset) override; - gl::Error resize(size_t size, bool preserveData) override; + const d3d11::Buffer &getBuffer() const { return mBuffer; } + gl::ErrorOrResult<CopyResult> copyFromStorage(const gl::Context *context, + BufferStorage *source, + size_t sourceOffset, + size_t size, + size_t destOffset) override; + gl::Error resize(const gl::Context *context, size_t size, bool preserveData) override; - uint8_t *map(size_t offset, size_t length, GLbitfield access) override; + gl::Error map(size_t offset, + size_t length, + GLbitfield access, + uint8_t **mapPointerOut) override; void unmap() override; + gl::ErrorOrResult<const d3d11::ShaderResourceView *> getSRVForFormat(DXGI_FORMAT srvFormat); + private: - static void fillBufferDesc(D3D11_BUFFER_DESC *bufferDesc, + static void FillBufferDesc(D3D11_BUFFER_DESC *bufferDesc, Renderer11 *renderer, BufferUsage usage, unsigned int bufferSize); + void clearSRVs(); - ID3D11Buffer *mNativeStorage; + d3d11::Buffer mBuffer; + const OnBufferDataDirtyChannel *mOnStorageChanged; + std::map<DXGI_FORMAT, d3d11::ShaderResourceView> mBufferResourceViews; }; // A emulated indexed buffer storage represents an underlying D3D11 buffer for data @@ -166,28 +190,32 @@ class Buffer11::EmulatedIndexedStorage : public Buffer11::BufferStorage EmulatedIndexedStorage(Renderer11 *renderer); ~EmulatedIndexedStorage() override; - bool isMappable() const override { return true; } + bool isCPUAccessible(GLbitfield access) const override { return true; } + + bool isGPUAccessible() const override { return false; } - ID3D11Buffer *getNativeStorage(); + gl::ErrorOrResult<const d3d11::Buffer *> getBuffer(SourceIndexData *indexInfo, + const TranslatedAttribute &attribute, + GLint startVertex); - bool copyFromStorage(BufferStorage *source, - size_t sourceOffset, - size_t size, - size_t destOffset) override; + gl::ErrorOrResult<CopyResult> copyFromStorage(const gl::Context *context, + BufferStorage *source, + size_t sourceOffset, + size_t size, + size_t destOffset) override; - gl::Error resize(size_t size, bool preserveData) override; + gl::Error resize(const gl::Context *context, size_t size, bool preserveData) override; - uint8_t *map(size_t offset, size_t length, GLbitfield access) override; + gl::Error map(size_t offset, + size_t length, + GLbitfield access, + uint8_t **mapPointerOut) override; void unmap() override; - bool update(SourceIndexData *indexInfo, const TranslatedAttribute *attribute); private: - ID3D11Buffer *mNativeStorage; // contains expanded data for use by D3D - MemoryBuffer mMemoryBuffer; // original data (not expanded) - MemoryBuffer mIndicesMemoryBuffer; // indices data - SourceIndexData mIndexInfo; // indices information - size_t mAttributeStride; // per element stride in bytes - size_t mAttributeOffset; // starting offset + d3d11::Buffer mBuffer; // contains expanded data for use by D3D + angle::MemoryBuffer mMemoryBuffer; // original data (not expanded) + angle::MemoryBuffer mIndicesMemoryBuffer; // indices data }; // Pack storage represents internal storage for pack buffers. We implement pack buffers @@ -198,24 +226,32 @@ class Buffer11::PackStorage : public Buffer11::BufferStorage explicit PackStorage(Renderer11 *renderer); ~PackStorage() override; - bool isMappable() const override { return true; } - bool copyFromStorage(BufferStorage *source, - size_t sourceOffset, - size_t size, - size_t destOffset) override; - gl::Error resize(size_t size, bool preserveData) override; + bool isCPUAccessible(GLbitfield access) const override { return true; } - uint8_t *map(size_t offset, size_t length, GLbitfield access) override; + bool isGPUAccessible() const override { return false; } + + gl::ErrorOrResult<CopyResult> copyFromStorage(const gl::Context *context, + BufferStorage *source, + size_t sourceOffset, + size_t size, + size_t destOffset) override; + gl::Error resize(const gl::Context *context, size_t size, bool preserveData) override; + + gl::Error map(size_t offset, + size_t length, + GLbitfield access, + uint8_t **mapPointerOut) override; void unmap() override; - gl::Error packPixels(const gl::FramebufferAttachment &readAttachment, + gl::Error packPixels(const gl::Context *context, + const gl::FramebufferAttachment &readAttachment, const PackPixelsParams ¶ms); private: gl::Error flushQueuedPackCommand(); TextureHelper11 mStagingTexture; - MemoryBuffer mMemoryBuffer; + angle::MemoryBuffer mMemoryBuffer; std::unique_ptr<PackPixelsParams> mQueuedPackCommand; PackPixelsParams mPackParams; bool mDataModified; @@ -230,37 +266,46 @@ class Buffer11::SystemMemoryStorage : public Buffer11::BufferStorage explicit SystemMemoryStorage(Renderer11 *renderer); ~SystemMemoryStorage() override {} - bool isMappable() const override { return true; } - bool copyFromStorage(BufferStorage *source, - size_t sourceOffset, - size_t size, - size_t destOffset) override; - gl::Error resize(size_t size, bool preserveData) override; + bool isCPUAccessible(GLbitfield access) const override { return true; } + + bool isGPUAccessible() const override { return false; } - uint8_t *map(size_t offset, size_t length, GLbitfield access) override; + gl::ErrorOrResult<CopyResult> copyFromStorage(const gl::Context *context, + BufferStorage *source, + size_t sourceOffset, + size_t size, + size_t destOffset) override; + gl::Error resize(const gl::Context *context, size_t size, bool preserveData) override; + + gl::Error map(size_t offset, + size_t length, + GLbitfield access, + uint8_t **mapPointerOut) override; void unmap() override; - MemoryBuffer *getSystemCopy() { return &mSystemCopy; } + angle::MemoryBuffer *getSystemCopy() { return &mSystemCopy; } protected: - MemoryBuffer mSystemCopy; + angle::MemoryBuffer mSystemCopy; }; -Buffer11::Buffer11(Renderer11 *renderer) - : BufferD3D(renderer), +Buffer11::Buffer11(const gl::BufferState &state, Renderer11 *renderer) + : BufferD3D(state, renderer), mRenderer(renderer), mSize(0), mMappedStorage(nullptr), - mBufferStorages(BUFFER_USAGE_COUNT, nullptr), + mBufferStorages({}), + mLatestBufferStorage(nullptr), + mDeallocThresholds({}), + mIdleness({}), mConstantBufferStorageAdditionalSize(0), - mMaxConstantBufferLruCount(0), - mReadUsageCount(0) + mMaxConstantBufferLruCount(0) { } Buffer11::~Buffer11() { - for (auto &storage : mBufferStorages) + for (BufferStorage *&storage : mBufferStorages) { SafeDelete(storage); } @@ -273,79 +318,74 @@ Buffer11::~Buffer11() mRenderer->onBufferDelete(this); } -gl::Error Buffer11::setData(const void *data, size_t size, GLenum usage) +gl::Error Buffer11::setData(const gl::Context *context, + gl::BufferBinding target, + const void *data, + size_t size, + gl::BufferUsage usage) { - gl::Error error = setSubData(data, size, 0); - if (error.isError()) - { - return error; - } - - updateD3DBufferUsage(usage); - return error; + updateD3DBufferUsage(context, usage); + ANGLE_TRY(setSubData(context, target, data, size, 0)); + return gl::NoError(); } -gl::Error Buffer11::getData(const uint8_t **outData) +gl::Error Buffer11::getData(const gl::Context *context, const uint8_t **outData) { SystemMemoryStorage *systemMemoryStorage = nullptr; - gl::Error error = getSystemMemoryStorage(&systemMemoryStorage); - - if (error.isError()) - { - *outData = nullptr; - return error; - } - - mReadUsageCount = 0; + ANGLE_TRY_RESULT(getSystemMemoryStorage(context), systemMemoryStorage); ASSERT(systemMemoryStorage->getSize() >= mSize); *outData = systemMemoryStorage->getSystemCopy()->data(); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error Buffer11::getSystemMemoryStorage(SystemMemoryStorage **storageOut) +gl::ErrorOrResult<Buffer11::SystemMemoryStorage *> Buffer11::getSystemMemoryStorage( + const gl::Context *context) { - BufferStorage *memStorageUntyped = getBufferStorage(BUFFER_USAGE_SYSTEM_MEMORY); - - if (memStorageUntyped == nullptr) - { - // TODO(jmadill): convert all to errors - return gl::Error(GL_OUT_OF_MEMORY); - } - - *storageOut = GetAs<SystemMemoryStorage>(memStorageUntyped); - return gl::Error(GL_NO_ERROR); + BufferStorage *storage = nullptr; + ANGLE_TRY_RESULT(getBufferStorage(context, BUFFER_USAGE_SYSTEM_MEMORY), storage); + return GetAs<SystemMemoryStorage>(storage); } -gl::Error Buffer11::setSubData(const void *data, size_t size, size_t offset) +gl::Error Buffer11::setSubData(const gl::Context *context, + gl::BufferBinding target, + const void *data, + size_t size, + size_t offset) { size_t requiredSize = size + offset; if (data && size > 0) { // Use system memory storage for dynamic buffers. - + // Try using a constant storage for constant buffers BufferStorage *writeBuffer = nullptr; - if (supportsDirectBinding()) + if (target == gl::BufferBinding::Uniform) { - writeBuffer = getStagingStorage(); - - if (!writeBuffer) + // If we are a very large uniform buffer, keep system memory storage around so that we + // aren't forced to read back from a constant buffer. We also check the workaround for + // Intel - this requires us to use system memory so we don't end up having to copy from + // a constant buffer to a staging buffer. + // TODO(jmadill): Use Context caps. + if (offset == 0 && size >= mSize && + size <= static_cast<UINT>(mRenderer->getNativeCaps().maxUniformBlockSize) && + !mRenderer->getWorkarounds().useSystemMemoryForConstantBuffers) + { + ANGLE_TRY_RESULT(getBufferStorage(context, BUFFER_USAGE_UNIFORM), writeBuffer); + } + else { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal buffer."); + ANGLE_TRY_RESULT(getSystemMemoryStorage(context), writeBuffer); } } + else if (supportsDirectBinding()) + { + ANGLE_TRY_RESULT(getStagingStorage(context), writeBuffer); + } else { - SystemMemoryStorage *systemMemoryStorage = nullptr; - gl::Error error = getSystemMemoryStorage(&systemMemoryStorage); - if (error.isError()) - { - return error; - } - - writeBuffer = systemMemoryStorage; + ANGLE_TRY_RESULT(getSystemMemoryStorage(context), writeBuffer); } ASSERT(writeBuffer); @@ -355,24 +395,25 @@ gl::Error Buffer11::setSubData(const void *data, size_t size, size_t offset) if (writeBuffer->getSize() < requiredSize) { bool preserveData = (offset > 0); - gl::Error error = writeBuffer->resize(requiredSize, preserveData); - if (error.isError()) - { - return error; - } + ANGLE_TRY(writeBuffer->resize(context, requiredSize, preserveData)); } - writeBuffer->setData(static_cast<const uint8_t *>(data), offset, size); - writeBuffer->setDataRevision(writeBuffer->getDataRevision() + 1); + ANGLE_TRY(writeBuffer->setData(static_cast<const uint8_t *>(data), offset, size)); + onStorageUpdate(writeBuffer); + + // Notify any vertex arrays that we have dirty data. + // TODO(jmadill): Use a more fine grained notification for data updates. + mDirectBroadcastChannel.signal(context); } mSize = std::max(mSize, requiredSize); - invalidateStaticData(D3D_BUFFER_INVALIDATE_WHOLE_CACHE); + invalidateStaticData(context); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error Buffer11::copySubData(BufferImpl *source, +gl::Error Buffer11::copySubData(const gl::Context *context, + BufferImpl *source, GLintptr sourceOffset, GLintptr destOffset, GLsizeiptr size) @@ -380,28 +421,32 @@ gl::Error Buffer11::copySubData(BufferImpl *source, Buffer11 *sourceBuffer = GetAs<Buffer11>(source); ASSERT(sourceBuffer != nullptr); - BufferStorage *copyDest = getLatestBufferStorage(); + BufferStorage *copyDest = nullptr; + ANGLE_TRY_RESULT(getLatestBufferStorage(context), copyDest); + if (!copyDest) { - copyDest = getStagingStorage(); + ANGLE_TRY_RESULT(getStagingStorage(context), copyDest); } - BufferStorage *copySource = sourceBuffer->getLatestBufferStorage(); + BufferStorage *copySource = nullptr; + ANGLE_TRY_RESULT(sourceBuffer->getLatestBufferStorage(context), copySource); - if (!copySource || !copyDest) + if (!copySource) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal staging buffer."); + ANGLE_TRY_RESULT(sourceBuffer->getStagingStorage(context), copySource); } - // If copying to/from a pixel pack buffer, we must have a staging or - // pack buffer partner, because other native buffers can't be mapped - if (copyDest->getUsage() == BUFFER_USAGE_PIXEL_PACK && !copySource->isMappable()) + ASSERT(copySource && copyDest); + + // A staging buffer is needed if there is no cpu-cpu or gpu-gpu copy path avaiable. + if (!copyDest->isGPUAccessible() && !copySource->isCPUAccessible(GL_MAP_READ_BIT)) { - copySource = sourceBuffer->getStagingStorage(); + ANGLE_TRY_RESULT(sourceBuffer->getStagingStorage(context), copySource); } - else if (copySource->getUsage() == BUFFER_USAGE_PIXEL_PACK && !copyDest->isMappable()) + else if (!copySource->isGPUAccessible() && !copyDest->isCPUAccessible(GL_MAP_WRITE_BIT)) { - copyDest = getStagingStorage(); + ANGLE_TRY_RESULT(getStagingStorage(context), copyDest); } // D3D11 does not allow overlapped copies until 11.1, and only if the @@ -411,36 +456,48 @@ gl::Error Buffer11::copySubData(BufferImpl *source, { if (copySource->getUsage() == BUFFER_USAGE_STAGING) { - copySource = getBufferStorage(BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK); + ANGLE_TRY_RESULT(getBufferStorage(context, BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK), + copySource); } else { - copySource = getStagingStorage(); + ANGLE_TRY_RESULT(getStagingStorage(context), copySource); } } - copyDest->copyFromStorage(copySource, sourceOffset, size, destOffset); - copyDest->setDataRevision(copyDest->getDataRevision() + 1); + CopyResult copyResult = CopyResult::NOT_RECREATED; + ANGLE_TRY_RESULT(copyDest->copyFromStorage(context, copySource, sourceOffset, size, destOffset), + copyResult); + onStorageUpdate(copyDest); mSize = std::max<size_t>(mSize, destOffset + size); - invalidateStaticData(D3D_BUFFER_INVALIDATE_WHOLE_CACHE); + invalidateStaticData(context); + + // Also notify that direct buffers are dirty. + mDirectBroadcastChannel.signal(context); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -gl::Error Buffer11::map(GLenum access, GLvoid **mapPtr) +gl::Error Buffer11::map(const gl::Context *context, GLenum access, void **mapPtr) { // GL_OES_mapbuffer uses an enum instead of a bitfield for it's access, convert to a bitfield // and call mapRange. ASSERT(access == GL_WRITE_ONLY_OES); - return mapRange(0, mSize, GL_MAP_WRITE_BIT, mapPtr); + return mapRange(context, 0, mSize, GL_MAP_WRITE_BIT, mapPtr); } -gl::Error Buffer11::mapRange(size_t offset, size_t length, GLbitfield access, GLvoid **mapPtr) +gl::Error Buffer11::mapRange(const gl::Context *context, + size_t offset, + size_t length, + GLbitfield access, + void **mapPtr) { ASSERT(!mMappedStorage); - BufferStorage *latestStorage = getLatestBufferStorage(); + BufferStorage *latestStorage = nullptr; + ANGLE_TRY_RESULT(getLatestBufferStorage(context), latestStorage); + if (latestStorage && (latestStorage->getUsage() == BUFFER_USAGE_PIXEL_PACK || latestStorage->getUsage() == BUFFER_USAGE_STAGING)) { @@ -449,34 +506,32 @@ gl::Error Buffer11::mapRange(size_t offset, size_t length, GLbitfield access, GL } else { - // Fall back to using the staging buffer if the latest storage does - // not exist or is not CPU-accessible. - mMappedStorage = getStagingStorage(); + // Fall back to using the staging buffer if the latest storage does not exist or is not + // CPU-accessible. + ANGLE_TRY_RESULT(getStagingStorage(context), mMappedStorage); } if (!mMappedStorage) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate mappable internal buffer."); + return gl::OutOfMemory() << "Failed to allocate mappable internal buffer."; } if ((access & GL_MAP_WRITE_BIT) > 0) { // Update the data revision immediately, since the data might be changed at any time - mMappedStorage->setDataRevision(mMappedStorage->getDataRevision() + 1); - invalidateStaticData(D3D_BUFFER_INVALIDATE_WHOLE_CACHE); + onStorageUpdate(mMappedStorage); + invalidateStaticData(context); } - uint8_t *mappedBuffer = mMappedStorage->map(offset, length, access); - if (!mappedBuffer) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal buffer."); - } + uint8_t *mappedBuffer = nullptr; + ANGLE_TRY(mMappedStorage->map(offset, length, access, &mappedBuffer)); + ASSERT(mappedBuffer); - *mapPtr = static_cast<GLvoid *>(mappedBuffer); - return gl::Error(GL_NO_ERROR); + *mapPtr = static_cast<void *>(mappedBuffer); + return gl::NoError(); } -gl::Error Buffer11::unmap(GLboolean *result) +gl::Error Buffer11::unmap(const gl::Context *context, GLboolean *result) { ASSERT(mMappedStorage); mMappedStorage->unmap(); @@ -485,168 +540,171 @@ gl::Error Buffer11::unmap(GLboolean *result) // TODO: detect if we had corruption. if so, return false. *result = GL_TRUE; - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -void Buffer11::markTransformFeedbackUsage() +gl::Error Buffer11::markTransformFeedbackUsage(const gl::Context *context) { - BufferStorage *transformFeedbackStorage = - getBufferStorage(BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK); + BufferStorage *transformFeedbackStorage = nullptr; + ANGLE_TRY_RESULT(getBufferStorage(context, BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK), + transformFeedbackStorage); if (transformFeedbackStorage) { - transformFeedbackStorage->setDataRevision(transformFeedbackStorage->getDataRevision() + 1); + onStorageUpdate(transformFeedbackStorage); } - invalidateStaticData(D3D_BUFFER_INVALIDATE_WHOLE_CACHE); + invalidateStaticData(context); + return gl::NoError(); } -void Buffer11::markBufferUsage() +void Buffer11::updateDeallocThreshold(BufferUsage usage) { - mReadUsageCount++; + // The following strategy was tuned on the Oort online benchmark (http://oortonline.gl/) + // as well as a custom microbenchmark (IndexConversionPerfTest.Run/index_range_d3d11) + + // First readback: 8 unmodified uses before we free buffer memory. + // After that, double the threshold each time until we reach the max. + if (mDeallocThresholds[usage] == 0) + { + mDeallocThresholds[usage] = 8; + } + else if (mDeallocThresholds[usage] < std::numeric_limits<unsigned int>::max() / 2u) + { + mDeallocThresholds[usage] *= 2u; + } + else + { + mDeallocThresholds[usage] = std::numeric_limits<unsigned int>::max(); + } +} - // Free the system memory storage if we decide it isn't being used very often. - const unsigned int usageLimit = 5; +// Free the storage if we decide it isn't being used very often. +gl::Error Buffer11::checkForDeallocation(const gl::Context *context, BufferUsage usage) +{ + mIdleness[usage]++; - BufferStorage *&sysMemUsage = mBufferStorages[BUFFER_USAGE_SYSTEM_MEMORY]; - if (mReadUsageCount > usageLimit && sysMemUsage != nullptr) + BufferStorage *&storage = mBufferStorages[usage]; + if (storage != nullptr && mIdleness[usage] > mDeallocThresholds[usage]) { - if (getLatestBufferStorage() != sysMemUsage) + BufferStorage *latestStorage = nullptr; + ANGLE_TRY_RESULT(getLatestBufferStorage(context), latestStorage); + if (latestStorage != storage) { - SafeDelete(sysMemUsage); + SafeDelete(storage); } } + + return gl::NoError(); } -ID3D11Buffer *Buffer11::getBuffer(BufferUsage usage) +// Keep system memory when we are using it for the canonical version of data. +bool Buffer11::canDeallocateSystemMemory() const { - markBufferUsage(); - - BufferStorage *bufferStorage = getBufferStorage(usage); - - if (!bufferStorage) + // Must keep system memory on Intel. + if (mRenderer->getWorkarounds().useSystemMemoryForConstantBuffers) { - // Storage out-of-memory - return nullptr; + return false; } - return GetAs<NativeStorage>(bufferStorage)->getNativeStorage(); + return (!mBufferStorages[BUFFER_USAGE_UNIFORM] || + mSize <= mRenderer->getNativeCaps().maxUniformBlockSize); } -ID3D11Buffer *Buffer11::getEmulatedIndexedBuffer(SourceIndexData *indexInfo, - const TranslatedAttribute *attribute) +void Buffer11::markBufferUsage(BufferUsage usage) { - markBufferUsage(); - - assert(indexInfo != nullptr); - assert(attribute != nullptr); + mIdleness[usage] = 0; +} - BufferStorage *bufferStorage = getBufferStorage(BUFFER_USAGE_EMULATED_INDEXED_VERTEX); - if (!bufferStorage) +gl::Error Buffer11::garbageCollection(const gl::Context *context, BufferUsage currentUsage) +{ + if (currentUsage != BUFFER_USAGE_SYSTEM_MEMORY && canDeallocateSystemMemory()) { - // Storage out-of-memory - return nullptr; + ANGLE_TRY(checkForDeallocation(context, BUFFER_USAGE_SYSTEM_MEMORY)); } - EmulatedIndexedStorage *emulatedStorage = GetAs<EmulatedIndexedStorage>(bufferStorage); - if (!emulatedStorage->update(indexInfo, attribute)) + if (currentUsage != BUFFER_USAGE_STAGING) { - // Storage out-of-memory - return nullptr; + ANGLE_TRY(checkForDeallocation(context, BUFFER_USAGE_STAGING)); } - return emulatedStorage->getNativeStorage(); + return gl::NoError(); } -ID3D11Buffer *Buffer11::getConstantBufferRange(GLintptr offset, GLsizeiptr size) +gl::ErrorOrResult<ID3D11Buffer *> Buffer11::getBuffer(const gl::Context *context, BufferUsage usage) { - markBufferUsage(); + BufferStorage *storage = nullptr; + ANGLE_TRY_RESULT(getBufferStorage(context, usage), storage); + return GetAs<NativeStorage>(storage)->getBuffer().get(); +} - BufferStorage *bufferStorage; +gl::ErrorOrResult<ID3D11Buffer *> Buffer11::getEmulatedIndexedBuffer( + const gl::Context *context, + SourceIndexData *indexInfo, + const TranslatedAttribute &attribute, + GLint startVertex) +{ + ASSERT(indexInfo); - if (offset == 0) - { - bufferStorage = getBufferStorage(BUFFER_USAGE_UNIFORM); - } - else - { - bufferStorage = getConstantBufferRangeStorage(offset, size); - } + BufferStorage *untypedStorage = nullptr; + ANGLE_TRY_RESULT(getBufferStorage(context, BUFFER_USAGE_EMULATED_INDEXED_VERTEX), + untypedStorage); - if (!bufferStorage) - { - // Storage out-of-memory - return nullptr; - } + EmulatedIndexedStorage *emulatedStorage = GetAs<EmulatedIndexedStorage>(untypedStorage); + + const d3d11::Buffer *nativeStorage = nullptr; + ANGLE_TRY_RESULT(emulatedStorage->getBuffer(indexInfo, attribute, startVertex), nativeStorage); - return GetAs<NativeStorage>(bufferStorage)->getNativeStorage(); + return nativeStorage->get(); } -ID3D11ShaderResourceView *Buffer11::getSRV(DXGI_FORMAT srvFormat) +gl::Error Buffer11::getConstantBufferRange(const gl::Context *context, + GLintptr offset, + GLsizeiptr size, + const d3d11::Buffer **bufferOut, + UINT *firstConstantOut, + UINT *numConstantsOut) { - BufferStorage *storage = getBufferStorage(BUFFER_USAGE_PIXEL_UNPACK); + BufferStorage *bufferStorage = nullptr; - if (!storage) + if (offset == 0 || mRenderer->getRenderer11DeviceCaps().supportsConstantBufferOffsets) { - // Storage out-of-memory - return nullptr; + ANGLE_TRY_RESULT(getBufferStorage(context, BUFFER_USAGE_UNIFORM), bufferStorage); + CalculateConstantBufferParams(offset, size, firstConstantOut, numConstantsOut); } - - ID3D11Buffer *buffer = GetAs<NativeStorage>(storage)->getNativeStorage(); - - auto bufferSRVIt = mBufferResourceViews.find(srvFormat); - - if (bufferSRVIt != mBufferResourceViews.end()) + else { - if (bufferSRVIt->second.first == buffer) - { - return bufferSRVIt->second.second; - } - else - { - // The underlying buffer has changed since the SRV was created: recreate the SRV. - SafeRelease(bufferSRVIt->second.second); - } + ANGLE_TRY_RESULT(getConstantBufferRangeStorage(context, offset, size), bufferStorage); + *firstConstantOut = 0; + *numConstantsOut = 0; } - ID3D11Device *device = mRenderer->getDevice(); - ID3D11ShaderResourceView *bufferSRV = nullptr; - - const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(srvFormat); + *bufferOut = &GetAs<NativeStorage>(bufferStorage)->getBuffer(); - D3D11_SHADER_RESOURCE_VIEW_DESC bufferSRVDesc; - bufferSRVDesc.Buffer.ElementOffset = 0; - bufferSRVDesc.Buffer.ElementWidth = - static_cast<unsigned int>(mSize) / dxgiFormatInfo.pixelBytes; - bufferSRVDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER; - bufferSRVDesc.Format = srvFormat; - - HRESULT result = device->CreateShaderResourceView(buffer, &bufferSRVDesc, &bufferSRV); - UNUSED_ASSERTION_VARIABLE(result); - ASSERT(SUCCEEDED(result)); - - mBufferResourceViews[srvFormat] = BufferSRVPair(buffer, bufferSRV); + return gl::NoError(); +} - return bufferSRV; +gl::ErrorOrResult<const d3d11::ShaderResourceView *> Buffer11::getSRV(const gl::Context *context, + DXGI_FORMAT srvFormat) +{ + BufferStorage *storage = nullptr; + ANGLE_TRY_RESULT(getBufferStorage(context, BUFFER_USAGE_PIXEL_UNPACK), storage); + NativeStorage *nativeStorage = GetAs<NativeStorage>(storage); + return nativeStorage->getSRVForFormat(srvFormat); } -gl::Error Buffer11::packPixels(const gl::FramebufferAttachment &readAttachment, +gl::Error Buffer11::packPixels(const gl::Context *context, + const gl::FramebufferAttachment &readAttachment, const PackPixelsParams ¶ms) { - PackStorage *packStorage = getPackStorage(); - BufferStorage *latestStorage = getLatestBufferStorage(); + PackStorage *packStorage = nullptr; + ANGLE_TRY_RESULT(getPackStorage(context), packStorage); - if (packStorage) - { - gl::Error error = packStorage->packPixels(readAttachment, params); - if (error.isError()) - { - return error; - } - packStorage->setDataRevision(latestStorage ? latestStorage->getDataRevision() + 1 : 1); - } + ASSERT(packStorage); + ANGLE_TRY(packStorage->packPixels(context, readAttachment, params)); + onStorageUpdate(packStorage); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } size_t Buffer11::getTotalCPUBufferMemoryBytes() const @@ -662,48 +720,56 @@ size_t Buffer11::getTotalCPUBufferMemoryBytes() const return allocationSize; } -Buffer11::BufferStorage *Buffer11::getBufferStorage(BufferUsage usage) +gl::ErrorOrResult<Buffer11::BufferStorage *> Buffer11::getBufferStorage(const gl::Context *context, + BufferUsage usage) { ASSERT(0 <= usage && usage < BUFFER_USAGE_COUNT); BufferStorage *&newStorage = mBufferStorages[usage]; if (!newStorage) { - if (usage == BUFFER_USAGE_PIXEL_PACK) - { - newStorage = new PackStorage(mRenderer); - } - else if (usage == BUFFER_USAGE_SYSTEM_MEMORY) - { - newStorage = new SystemMemoryStorage(mRenderer); - } - else if (usage == BUFFER_USAGE_EMULATED_INDEXED_VERTEX) - { - newStorage = new EmulatedIndexedStorage(mRenderer); - } - else - { - // buffer is not allocated, create it - newStorage = new NativeStorage(mRenderer, usage); - } + newStorage = allocateStorage(usage); } + markBufferUsage(usage); + // resize buffer if (newStorage->getSize() < mSize) { - if (newStorage->resize(mSize, true).isError()) - { - // Out of memory error - return nullptr; - } + ANGLE_TRY(newStorage->resize(context, mSize, true)); } - updateBufferStorage(newStorage, 0, mSize); + ASSERT(newStorage); + + ANGLE_TRY(updateBufferStorage(context, newStorage, 0, mSize)); + ANGLE_TRY(garbageCollection(context, usage)); return newStorage; } -Buffer11::BufferStorage *Buffer11::getConstantBufferRangeStorage(GLintptr offset, GLsizeiptr size) +Buffer11::BufferStorage *Buffer11::allocateStorage(BufferUsage usage) +{ + updateDeallocThreshold(usage); + switch (usage) + { + case BUFFER_USAGE_PIXEL_PACK: + return new PackStorage(mRenderer); + case BUFFER_USAGE_SYSTEM_MEMORY: + return new SystemMemoryStorage(mRenderer); + case BUFFER_USAGE_EMULATED_INDEXED_VERTEX: + return new EmulatedIndexedStorage(mRenderer); + case BUFFER_USAGE_INDEX: + case BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK: + return new NativeStorage(mRenderer, usage, &mDirectBroadcastChannel); + default: + return new NativeStorage(mRenderer, usage, nullptr); + } +} + +gl::ErrorOrResult<Buffer11::BufferStorage *> Buffer11::getConstantBufferRangeStorage( + const gl::Context *context, + GLintptr offset, + GLsizeiptr size) { BufferStorage *newStorage; @@ -714,7 +780,7 @@ Buffer11::BufferStorage *Buffer11::getConstantBufferRangeStorage(GLintptr offset if (!cacheEntry->storage) { - cacheEntry->storage = new NativeStorage(mRenderer, BUFFER_USAGE_UNIFORM); + cacheEntry->storage = allocateStorage(BUFFER_USAGE_UNIFORM); cacheEntry->lruCount = ++mMaxConstantBufferLruCount; } @@ -722,6 +788,8 @@ Buffer11::BufferStorage *Buffer11::getConstantBufferRangeStorage(GLintptr offset newStorage = cacheEntry->storage; } + markBufferUsage(BUFFER_USAGE_UNIFORM); + if (newStorage->getSize() < static_cast<size_t>(size)) { size_t maximumAllowedAdditionalSize = 2 * getSize(); @@ -733,8 +801,7 @@ Buffer11::BufferStorage *Buffer11::getConstantBufferRangeStorage(GLintptr offset auto iter = std::min_element(std::begin(mConstantBufferRangeStoragesCache), std::end(mConstantBufferRangeStoragesCache), [](const ConstantBufferCache::value_type &a, - const ConstantBufferCache::value_type &b) - { + const ConstantBufferCache::value_type &b) { return a.second.lruCount < b.second.lruCount; }); @@ -746,12 +813,7 @@ Buffer11::BufferStorage *Buffer11::getConstantBufferRangeStorage(GLintptr offset mConstantBufferRangeStoragesCache.erase(iter); } - if (newStorage->resize(size, false).isError()) - { - // Out of memory error - return nullptr; - } - + ANGLE_TRY(newStorage->resize(context, size, false)); mConstantBufferStorageAdditionalSize += sizeDelta; // We don't copy the old data when resizing the constant buffer because the data may be @@ -760,103 +822,148 @@ Buffer11::BufferStorage *Buffer11::getConstantBufferRangeStorage(GLintptr offset newStorage->setDataRevision(0); } - updateBufferStorage(newStorage, offset, size); - + ANGLE_TRY(updateBufferStorage(context, newStorage, offset, size)); + ANGLE_TRY(garbageCollection(context, BUFFER_USAGE_UNIFORM)); return newStorage; } -void Buffer11::updateBufferStorage(BufferStorage *storage, size_t sourceOffset, size_t storageSize) +gl::Error Buffer11::updateBufferStorage(const gl::Context *context, + BufferStorage *storage, + size_t sourceOffset, + size_t storageSize) { - BufferStorage *latestBuffer = getLatestBufferStorage(); - if (latestBuffer && latestBuffer->getDataRevision() > storage->getDataRevision()) - { - // Copy through a staging buffer if we're copying from or to a non-staging, mappable - // buffer storage. This is because we can't map a GPU buffer, and copy CPU - // data directly. If we're already using a staging buffer we're fine. - if (latestBuffer->getUsage() != BUFFER_USAGE_STAGING && - storage->getUsage() != BUFFER_USAGE_STAGING && - (!latestBuffer->isMappable() || !storage->isMappable())) - { - NativeStorage *stagingBuffer = getStagingStorage(); + BufferStorage *latestBuffer = nullptr; + ANGLE_TRY_RESULT(getLatestBufferStorage(context), latestBuffer); - stagingBuffer->copyFromStorage(latestBuffer, 0, latestBuffer->getSize(), 0); - stagingBuffer->setDataRevision(latestBuffer->getDataRevision()); - - latestBuffer = stagingBuffer; - } + ASSERT(storage); - // if copyFromStorage returns true, the D3D buffer has been recreated - // and we should update our serial - if (storage->copyFromStorage(latestBuffer, sourceOffset, storageSize, 0)) - { - updateSerial(); - } - storage->setDataRevision(latestBuffer->getDataRevision()); + if (!latestBuffer) + { + onStorageUpdate(storage); + return gl::NoError(); } -} -Buffer11::BufferStorage *Buffer11::getLatestBufferStorage() const -{ - // Even though we iterate over all the direct buffers, it is expected that only - // 1 or 2 will be present. - BufferStorage *latestStorage = nullptr; - DataRevision latestRevision = 0; - for (auto &storage : mBufferStorages) + if (latestBuffer->getDataRevision() <= storage->getDataRevision()) { - if (storage && (!latestStorage || storage->getDataRevision() > latestRevision)) - { - latestStorage = storage; - latestRevision = storage->getDataRevision(); - } + return gl::NoError(); } - // resize buffer - if (latestStorage && latestStorage->getSize() < mSize) + // Copy through a staging buffer if we're copying from or to a non-staging, mappable + // buffer storage. This is because we can't map a GPU buffer, and copy CPU + // data directly. If we're already using a staging buffer we're fine. + if (latestBuffer->getUsage() != BUFFER_USAGE_STAGING && + storage->getUsage() != BUFFER_USAGE_STAGING && + (!latestBuffer->isCPUAccessible(GL_MAP_READ_BIT) || + !storage->isCPUAccessible(GL_MAP_WRITE_BIT))) { - if (latestStorage->resize(mSize, true).isError()) - { - // Out of memory error - return nullptr; - } + NativeStorage *stagingBuffer = nullptr; + ANGLE_TRY_RESULT(getStagingStorage(context), stagingBuffer); + + CopyResult copyResult = CopyResult::NOT_RECREATED; + ANGLE_TRY_RESULT( + stagingBuffer->copyFromStorage(context, latestBuffer, 0, latestBuffer->getSize(), 0), + copyResult); + onCopyStorage(stagingBuffer, latestBuffer); + + latestBuffer = stagingBuffer; } - return latestStorage; + CopyResult copyResult = CopyResult::NOT_RECREATED; + ANGLE_TRY_RESULT(storage->copyFromStorage(context, latestBuffer, sourceOffset, storageSize, 0), + copyResult); + // If the D3D buffer has been recreated, we should update our serial. + if (copyResult == CopyResult::RECREATED) + { + updateSerial(); + } + onCopyStorage(storage, latestBuffer); + return gl::NoError(); } -Buffer11::NativeStorage *Buffer11::getStagingStorage() +gl::ErrorOrResult<Buffer11::BufferStorage *> Buffer11::getLatestBufferStorage( + const gl::Context *context) const { - BufferStorage *stagingStorage = getBufferStorage(BUFFER_USAGE_STAGING); - - if (!stagingStorage) + // resize buffer + if (mLatestBufferStorage && mLatestBufferStorage->getSize() < mSize) { - // Out-of-memory - return nullptr; + ANGLE_TRY(mLatestBufferStorage->resize(context, mSize, true)); } - return GetAs<NativeStorage>(stagingStorage); + return mLatestBufferStorage; } -Buffer11::PackStorage *Buffer11::getPackStorage() +gl::ErrorOrResult<Buffer11::NativeStorage *> Buffer11::getStagingStorage(const gl::Context *context) { - BufferStorage *packStorage = getBufferStorage(BUFFER_USAGE_PIXEL_PACK); - - if (!packStorage) - { - // Out-of-memory - return nullptr; - } + BufferStorage *stagingStorage = nullptr; + ANGLE_TRY_RESULT(getBufferStorage(context, BUFFER_USAGE_STAGING), stagingStorage); + return GetAs<NativeStorage>(stagingStorage); +} +gl::ErrorOrResult<Buffer11::PackStorage *> Buffer11::getPackStorage(const gl::Context *context) +{ + BufferStorage *packStorage = nullptr; + ANGLE_TRY_RESULT(getBufferStorage(context, BUFFER_USAGE_PIXEL_PACK), packStorage); return GetAs<PackStorage>(packStorage); } +size_t Buffer11::getSize() const +{ + return mSize; +} + bool Buffer11::supportsDirectBinding() const { // Do not support direct buffers for dynamic data. The streaming buffer // offers better performance for data which changes every frame. - // Check for absence of static buffer interfaces to detect dynamic data. - return (mStaticVertexBuffer && mStaticIndexBuffer); + return (mUsage == D3DBufferUsage::STATIC); +} + +void Buffer11::initializeStaticData(const gl::Context *context) +{ + BufferD3D::initializeStaticData(context); + + // Notify when static data changes. + mStaticBroadcastChannel.signal(context); } +void Buffer11::invalidateStaticData(const gl::Context *context) +{ + BufferD3D::invalidateStaticData(context); + + // Notify when static data changes. + mStaticBroadcastChannel.signal(context); +} + +OnBufferDataDirtyChannel *Buffer11::getStaticBroadcastChannel() +{ + return &mStaticBroadcastChannel; +} + +OnBufferDataDirtyChannel *Buffer11::getDirectBroadcastChannel() +{ + return &mDirectBroadcastChannel; +} + +void Buffer11::onCopyStorage(BufferStorage *dest, BufferStorage *source) +{ + ASSERT(source && mLatestBufferStorage); + dest->setDataRevision(source->getDataRevision()); + + // Only update the latest buffer storage if our usage index is lower. See comment in header. + if (dest->getUsage() < mLatestBufferStorage->getUsage()) + { + mLatestBufferStorage = dest; + } +} + +void Buffer11::onStorageUpdate(BufferStorage *updatedStorage) +{ + updatedStorage->setDataRevision(updatedStorage->getDataRevision() + 1); + mLatestBufferStorage = updatedStorage; +} + +// Buffer11::BufferStorage implementation + Buffer11::BufferStorage::BufferStorage(Renderer11 *renderer, BufferUsage usage) : mRenderer(renderer), mRevision(0), mUsage(usage), mBufferSize(0) { @@ -864,113 +971,118 @@ Buffer11::BufferStorage::BufferStorage(Renderer11 *renderer, BufferUsage usage) gl::Error Buffer11::BufferStorage::setData(const uint8_t *data, size_t offset, size_t size) { - ASSERT(isMappable()); + ASSERT(isCPUAccessible(GL_MAP_WRITE_BIT)); - uint8_t *writePointer = map(offset, size, GL_MAP_WRITE_BIT); - if (!writePointer) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal buffer."); - } + // Uniform storage can have a different internal size than the buffer size. Ensure we don't + // overflow. + size_t mapSize = std::min(size, mBufferSize - offset); + + uint8_t *writePointer = nullptr; + ANGLE_TRY(map(offset, mapSize, GL_MAP_WRITE_BIT, &writePointer)); - memcpy(writePointer, data, size); + memcpy(writePointer, data, mapSize); unmap(); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -Buffer11::NativeStorage::NativeStorage(Renderer11 *renderer, BufferUsage usage) - : BufferStorage(renderer, usage), mNativeStorage(nullptr) +// Buffer11::NativeStorage implementation + +Buffer11::NativeStorage::NativeStorage(Renderer11 *renderer, + BufferUsage usage, + const OnBufferDataDirtyChannel *onStorageChanged) + : BufferStorage(renderer, usage), mBuffer(), mOnStorageChanged(onStorageChanged) { } Buffer11::NativeStorage::~NativeStorage() { - SafeRelease(mNativeStorage); + clearSRVs(); } -// Returns true if it recreates the direct buffer -bool Buffer11::NativeStorage::copyFromStorage(BufferStorage *source, - size_t sourceOffset, - size_t size, - size_t destOffset) +bool Buffer11::NativeStorage::isCPUAccessible(GLbitfield access) const { - ID3D11DeviceContext *context = mRenderer->getDeviceContext(); + if ((access & GL_MAP_READ_BIT) != 0) + { + // Read is more exclusive than write mappability. + return (mUsage == BUFFER_USAGE_STAGING); + } + ASSERT((access & GL_MAP_WRITE_BIT) != 0); + return (mUsage == BUFFER_USAGE_STAGING || mUsage == BUFFER_USAGE_UNIFORM); +} +// Returns true if it recreates the direct buffer +gl::ErrorOrResult<CopyResult> Buffer11::NativeStorage::copyFromStorage(const gl::Context *context, + BufferStorage *source, + size_t sourceOffset, + size_t size, + size_t destOffset) +{ size_t requiredSize = destOffset + size; - bool createBuffer = !mNativeStorage || mBufferSize < requiredSize; + bool createBuffer = !mBuffer.valid() || mBufferSize < requiredSize; // (Re)initialize D3D buffer if needed + bool preserveData = (destOffset > 0); if (createBuffer) { - bool preserveData = (destOffset > 0); - resize(requiredSize, preserveData); + ANGLE_TRY(resize(context, requiredSize, preserveData)); + } + + size_t clampedSize = size; + if (mUsage == BUFFER_USAGE_UNIFORM) + { + clampedSize = std::min(clampedSize, mBufferSize - destOffset); } if (source->getUsage() == BUFFER_USAGE_PIXEL_PACK || source->getUsage() == BUFFER_USAGE_SYSTEM_MEMORY) { - ASSERT(source->isMappable()); - - uint8_t *sourcePointer = source->map(sourceOffset, size, GL_MAP_READ_BIT); - - D3D11_MAPPED_SUBRESOURCE mappedResource; - HRESULT hr = context->Map(mNativeStorage, 0, D3D11_MAP_WRITE, 0, &mappedResource); - ASSERT(SUCCEEDED(hr)); - if (FAILED(hr)) - { - source->unmap(); - return false; - } + ASSERT(source->isCPUAccessible(GL_MAP_READ_BIT) && isCPUAccessible(GL_MAP_WRITE_BIT)); - uint8_t *destPointer = static_cast<uint8_t *>(mappedResource.pData) + destOffset; + // Uniform buffers must be mapped with write/discard. + ASSERT(!(preserveData && mUsage == BUFFER_USAGE_UNIFORM)); - // Offset bounds are validated at the API layer - ASSERT(sourceOffset + size <= destOffset + mBufferSize); - memcpy(destPointer, sourcePointer, size); + uint8_t *sourcePointer = nullptr; + ANGLE_TRY(source->map(sourceOffset, clampedSize, GL_MAP_READ_BIT, &sourcePointer)); - context->Unmap(mNativeStorage, 0); + auto err = setData(sourcePointer, destOffset, clampedSize); source->unmap(); + ANGLE_TRY(err); } else { D3D11_BOX srcBox; srcBox.left = static_cast<unsigned int>(sourceOffset); - srcBox.right = static_cast<unsigned int>(sourceOffset + size); + srcBox.right = static_cast<unsigned int>(sourceOffset + clampedSize); srcBox.top = 0; srcBox.bottom = 1; srcBox.front = 0; srcBox.back = 1; - ID3D11Buffer *sourceBuffer = GetAs<NativeStorage>(source)->getNativeStorage(); + const d3d11::Buffer *sourceBuffer = &GetAs<NativeStorage>(source)->getBuffer(); - context->CopySubresourceRegion(mNativeStorage, 0, static_cast<unsigned int>(destOffset), 0, - 0, sourceBuffer, 0, &srcBox); + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + deviceContext->CopySubresourceRegion(mBuffer.get(), 0, + static_cast<unsigned int>(destOffset), 0, 0, + sourceBuffer->get(), 0, &srcBox); } - return createBuffer; + return createBuffer ? CopyResult::RECREATED : CopyResult::NOT_RECREATED; } -gl::Error Buffer11::NativeStorage::resize(size_t size, bool preserveData) +gl::Error Buffer11::NativeStorage::resize(const gl::Context *context, + size_t size, + bool preserveData) { - ID3D11Device *device = mRenderer->getDevice(); - ID3D11DeviceContext *context = mRenderer->getDeviceContext(); - D3D11_BUFFER_DESC bufferDesc; - fillBufferDesc(&bufferDesc, mRenderer, mUsage, static_cast<unsigned int>(size)); - - ID3D11Buffer *newBuffer; - HRESULT result = device->CreateBuffer(&bufferDesc, nullptr, &newBuffer); - - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal buffer, result: 0x%X.", - result); - } + FillBufferDesc(&bufferDesc, mRenderer, mUsage, static_cast<unsigned int>(size)); - d3d11::SetDebugName(newBuffer, "Buffer11::NativeStorage"); + d3d11::Buffer newBuffer; + ANGLE_TRY(mRenderer->allocateResource(bufferDesc, &newBuffer)); + newBuffer.setDebugName("Buffer11::NativeStorage"); - if (mNativeStorage && preserveData) + if (mBuffer.valid() && preserveData) { // We don't call resize if the buffer is big enough already. ASSERT(mBufferSize <= size); @@ -983,19 +1095,30 @@ gl::Error Buffer11::NativeStorage::resize(size_t size, bool preserveData) srcBox.front = 0; srcBox.back = 1; - context->CopySubresourceRegion(newBuffer, 0, 0, 0, 0, mNativeStorage, 0, &srcBox); + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + deviceContext->CopySubresourceRegion(newBuffer.get(), 0, 0, 0, 0, mBuffer.get(), 0, + &srcBox); } // No longer need the old buffer - SafeRelease(mNativeStorage); - mNativeStorage = newBuffer; + mBuffer = std::move(newBuffer); mBufferSize = bufferDesc.ByteWidth; - return gl::Error(GL_NO_ERROR); + // Free the SRVs. + clearSRVs(); + + // Notify that the storage has changed. + if (mOnStorageChanged) + { + mOnStorageChanged->signal(context); + } + + return gl::NoError(); } -void Buffer11::NativeStorage::fillBufferDesc(D3D11_BUFFER_DESC *bufferDesc, +// static +void Buffer11::NativeStorage::FillBufferDesc(D3D11_BUFFER_DESC *bufferDesc, Renderer11 *renderer, BufferUsage usage, unsigned int bufferSize) @@ -1030,6 +1153,13 @@ void Buffer11::NativeStorage::fillBufferDesc(D3D11_BUFFER_DESC *bufferDesc, bufferDesc->CPUAccessFlags = 0; break; + case BUFFER_USAGE_INDIRECT: + bufferDesc->MiscFlags = D3D11_RESOURCE_MISC_DRAWINDIRECT_ARGS; + bufferDesc->Usage = D3D11_USAGE_DEFAULT; + bufferDesc->BindFlags = 0; + bufferDesc->CPUAccessFlags = 0; + break; + case BUFFER_USAGE_PIXEL_UNPACK: bufferDesc->Usage = D3D11_USAGE_DEFAULT; bufferDesc->BindFlags = D3D11_BIND_SHADER_RESOURCE; @@ -1044,9 +1174,12 @@ void Buffer11::NativeStorage::fillBufferDesc(D3D11_BUFFER_DESC *bufferDesc, // Constant buffers must be of a limited size, and aligned to 16 byte boundaries // For our purposes we ignore any buffer data past the maximum constant buffer size bufferDesc->ByteWidth = roundUp(bufferDesc->ByteWidth, 16u); + + // Note: it seems that D3D11 allows larger buffers on some platforms, but not all. + // (Windows 10 seems to allow larger constant buffers, but not Windows 7) bufferDesc->ByteWidth = std::min<UINT>(bufferDesc->ByteWidth, - static_cast<UINT>(renderer->getRendererCaps().maxUniformBlockSize)); + static_cast<UINT>(renderer->getNativeCaps().maxUniformBlockSize)); break; default: @@ -1054,67 +1187,146 @@ void Buffer11::NativeStorage::fillBufferDesc(D3D11_BUFFER_DESC *bufferDesc, } } -uint8_t *Buffer11::NativeStorage::map(size_t offset, size_t length, GLbitfield access) +gl::Error Buffer11::NativeStorage::map(size_t offset, + size_t length, + GLbitfield access, + uint8_t **mapPointerOut) { - ASSERT(mUsage == BUFFER_USAGE_STAGING); + ASSERT(isCPUAccessible(access)); D3D11_MAPPED_SUBRESOURCE mappedResource; ID3D11DeviceContext *context = mRenderer->getDeviceContext(); - D3D11_MAP d3dMapType = gl_d3d11::GetD3DMapTypeFromBits(access); - UINT d3dMapFlag = ((access & GL_MAP_UNSYNCHRONIZED_BIT) != 0 ? D3D11_MAP_FLAG_DO_NOT_WAIT : 0); + D3D11_MAP d3dMapType = gl_d3d11::GetD3DMapTypeFromBits(mUsage, access); + UINT d3dMapFlag = ((access & GL_MAP_UNSYNCHRONIZED_BIT) != 0 ? D3D11_MAP_FLAG_DO_NOT_WAIT : 0); - HRESULT result = context->Map(mNativeStorage, 0, d3dMapType, d3dMapFlag, &mappedResource); + HRESULT result = context->Map(mBuffer.get(), 0, d3dMapType, d3dMapFlag, &mappedResource); ASSERT(SUCCEEDED(result)); if (FAILED(result)) { - return nullptr; + return gl::OutOfMemory() << "Failed to map native storage in Buffer11::NativeStorage::map"; } - return static_cast<uint8_t *>(mappedResource.pData) + offset; + ASSERT(mappedResource.pData); + *mapPointerOut = static_cast<uint8_t *>(mappedResource.pData) + offset; + return gl::NoError(); } void Buffer11::NativeStorage::unmap() { - ASSERT(mUsage == BUFFER_USAGE_STAGING); + ASSERT(isCPUAccessible(GL_MAP_WRITE_BIT) || isCPUAccessible(GL_MAP_READ_BIT)); ID3D11DeviceContext *context = mRenderer->getDeviceContext(); - context->Unmap(mNativeStorage, 0); + context->Unmap(mBuffer.get(), 0); +} + +gl::ErrorOrResult<const d3d11::ShaderResourceView *> Buffer11::NativeStorage::getSRVForFormat( + DXGI_FORMAT srvFormat) +{ + auto bufferSRVIt = mBufferResourceViews.find(srvFormat); + + if (bufferSRVIt != mBufferResourceViews.end()) + { + return &bufferSRVIt->second; + } + + const d3d11::DXGIFormatSize &dxgiFormatInfo = d3d11::GetDXGIFormatSizeInfo(srvFormat); + + D3D11_SHADER_RESOURCE_VIEW_DESC bufferSRVDesc; + bufferSRVDesc.Buffer.ElementOffset = 0; + bufferSRVDesc.Buffer.ElementWidth = static_cast<UINT>(mBufferSize) / dxgiFormatInfo.pixelBytes; + bufferSRVDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER; + bufferSRVDesc.Format = srvFormat; + + ANGLE_TRY(mRenderer->allocateResource(bufferSRVDesc, mBuffer.get(), + &mBufferResourceViews[srvFormat])); + + return &mBufferResourceViews[srvFormat]; +} + +void Buffer11::NativeStorage::clearSRVs() +{ + mBufferResourceViews.clear(); } +// Buffer11::EmulatedIndexStorage implementation + Buffer11::EmulatedIndexedStorage::EmulatedIndexedStorage(Renderer11 *renderer) - : BufferStorage(renderer, BUFFER_USAGE_EMULATED_INDEXED_VERTEX), mNativeStorage(nullptr) + : BufferStorage(renderer, BUFFER_USAGE_EMULATED_INDEXED_VERTEX), mBuffer() { } Buffer11::EmulatedIndexedStorage::~EmulatedIndexedStorage() { - SafeRelease(mNativeStorage); } -ID3D11Buffer *Buffer11::EmulatedIndexedStorage::getNativeStorage() +gl::ErrorOrResult<const d3d11::Buffer *> Buffer11::EmulatedIndexedStorage::getBuffer( + SourceIndexData *indexInfo, + const TranslatedAttribute &attribute, + GLint startVertex) { - if (!mNativeStorage) + // If a change in the indices applied from the last draw call is detected, then the emulated + // indexed buffer needs to be invalidated. After invalidation, the change detected flag should + // be cleared to avoid unnecessary recreation of the buffer. + if (!mBuffer.valid() || indexInfo->srcIndicesChanged) + { + mBuffer.reset(); + + // Copy the source index data. This ensures that the lifetime of the indices pointer + // stays with this storage until the next time we invalidate. + size_t indicesDataSize = 0; + switch (indexInfo->srcIndexType) + { + case GL_UNSIGNED_INT: + indicesDataSize = sizeof(GLuint) * indexInfo->srcCount; + break; + case GL_UNSIGNED_SHORT: + indicesDataSize = sizeof(GLushort) * indexInfo->srcCount; + break; + case GL_UNSIGNED_BYTE: + indicesDataSize = sizeof(GLubyte) * indexInfo->srcCount; + break; + default: + indicesDataSize = sizeof(GLushort) * indexInfo->srcCount; + break; + } + + if (!mIndicesMemoryBuffer.resize(indicesDataSize)) + { + return gl::OutOfMemory() << "Error resizing index memory buffer in " + "Buffer11::EmulatedIndexedStorage::getBuffer"; + } + + memcpy(mIndicesMemoryBuffer.data(), indexInfo->srcIndices, indicesDataSize); + + indexInfo->srcIndicesChanged = false; + } + + if (!mBuffer.valid()) { + unsigned int offset = 0; + ANGLE_TRY_RESULT(attribute.computeOffset(startVertex), offset); + // Expand the memory storage upon request and cache the results. unsigned int expandedDataSize = - static_cast<unsigned int>((mIndexInfo.srcCount * mAttributeStride) + mAttributeOffset); - MemoryBuffer expandedData; + static_cast<unsigned int>((indexInfo->srcCount * attribute.stride) + offset); + angle::MemoryBuffer expandedData; if (!expandedData.resize(expandedDataSize)) { - return nullptr; + return gl::OutOfMemory() + << "Error resizing buffer in Buffer11::EmulatedIndexedStorage::getBuffer"; } // Clear the contents of the allocated buffer ZeroMemory(expandedData.data(), expandedDataSize); uint8_t *curr = expandedData.data(); - const uint8_t *ptr = static_cast<const uint8_t *>(mIndexInfo.srcIndices); + const uint8_t *ptr = static_cast<const uint8_t *>(indexInfo->srcIndices); // Ensure that we start in the correct place for the emulated data copy operation to // maintain offset behaviors. - curr += mAttributeOffset; + curr += offset; ReadIndexValueFunction readIndexValue = ReadIndexValueFromIndices<GLushort>; - switch (mIndexInfo.srcIndexType) + switch (indexInfo->srcIndexType) { case GL_UNSIGNED_INT: readIndexValue = ReadIndexValueFromIndices<GLuint>; @@ -1128,17 +1340,15 @@ ID3D11Buffer *Buffer11::EmulatedIndexedStorage::getNativeStorage() } // Iterate over the cached index data and copy entries indicated into the emulated buffer. - for (GLuint i = 0; i < mIndexInfo.srcCount; i++) + for (GLuint i = 0; i < indexInfo->srcCount; i++) { GLuint idx = readIndexValue(ptr, i); - memcpy(curr, mMemoryBuffer.data() + (mAttributeStride * idx), mAttributeStride); - curr += mAttributeStride; + memcpy(curr, mMemoryBuffer.data() + (attribute.stride * idx), attribute.stride); + curr += attribute.stride; } // Finally, initialize the emulated indexed native storage object with the newly copied data // and free the temporary buffers used. - ID3D11Device *device = mRenderer->getDevice(); - D3D11_BUFFER_DESC bufferDesc; bufferDesc.ByteWidth = expandedDataSize; bufferDesc.MiscFlags = 0; @@ -1149,99 +1359,53 @@ ID3D11Buffer *Buffer11::EmulatedIndexedStorage::getNativeStorage() D3D11_SUBRESOURCE_DATA subResourceData = {expandedData.data(), 0, 0}; - HRESULT result = device->CreateBuffer(&bufferDesc, &subResourceData, &mNativeStorage); - if (FAILED(result)) - { - ERR("Could not create emulated index data buffer: %08lX", result); - return nullptr; - } - d3d11::SetDebugName(mNativeStorage, "Buffer11::EmulatedIndexedStorage"); + ANGLE_TRY(mRenderer->allocateResource(bufferDesc, &subResourceData, &mBuffer)); + mBuffer.setDebugName("Buffer11::EmulatedIndexedStorage"); } - return mNativeStorage; -} - -bool Buffer11::EmulatedIndexedStorage::update(SourceIndexData *indexInfo, - const TranslatedAttribute *attribute) -{ - // If a change in the indices applied from the last draw call is detected, then the emulated - // indexed buffer needs to be invalidated. After invalidation, the change detected flag should - // be cleared to avoid unnecessary recreation of the buffer. - if (mNativeStorage == nullptr || indexInfo->srcIndicesChanged) - { - SafeRelease(mNativeStorage); - - // Copy attribute offset and stride information - mAttributeStride = attribute->stride; - mAttributeOffset = attribute->offset; - - // Copy the source index data. This ensures that the lifetime of the indices pointer - // stays with this storage until the next time we invalidate. - size_t indicesDataSize = 0; - switch (indexInfo->srcIndexType) - { - case GL_UNSIGNED_INT: - indicesDataSize = sizeof(GLuint) * indexInfo->srcCount; - break; - case GL_UNSIGNED_SHORT: - indicesDataSize = sizeof(GLushort) * indexInfo->srcCount; - break; - case GL_UNSIGNED_BYTE: - indicesDataSize = sizeof(GLubyte) * indexInfo->srcCount; - break; - default: - indicesDataSize = sizeof(GLushort) * indexInfo->srcCount; - break; - } - - if (!mIndicesMemoryBuffer.resize(indicesDataSize)) - { - return false; - } - - memcpy(mIndicesMemoryBuffer.data(), indexInfo->srcIndices, indicesDataSize); - - // Copy the source index data description and update the srcIndices pointer to point - // to our cached index data. - mIndexInfo = *indexInfo; - mIndexInfo.srcIndices = mIndicesMemoryBuffer.data(); - - indexInfo->srcIndicesChanged = false; - } - return true; + return &mBuffer; } -bool Buffer11::EmulatedIndexedStorage::copyFromStorage(BufferStorage *source, - size_t sourceOffset, - size_t size, - size_t destOffset) +gl::ErrorOrResult<CopyResult> Buffer11::EmulatedIndexedStorage::copyFromStorage( + const gl::Context *context, + BufferStorage *source, + size_t sourceOffset, + size_t size, + size_t destOffset) { - ASSERT(source->isMappable()); - const uint8_t *sourceData = source->map(sourceOffset, size, GL_MAP_READ_BIT); + ASSERT(source->isCPUAccessible(GL_MAP_READ_BIT)); + uint8_t *sourceData = nullptr; + ANGLE_TRY(source->map(sourceOffset, size, GL_MAP_READ_BIT, &sourceData)); ASSERT(destOffset + size <= mMemoryBuffer.size()); memcpy(mMemoryBuffer.data() + destOffset, sourceData, size); source->unmap(); - return true; + return CopyResult::RECREATED; } -gl::Error Buffer11::EmulatedIndexedStorage::resize(size_t size, bool preserveData) +gl::Error Buffer11::EmulatedIndexedStorage::resize(const gl::Context *context, + size_t size, + bool preserveData) { if (mMemoryBuffer.size() < size) { if (!mMemoryBuffer.resize(size)) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to resize EmulatedIndexedStorage"); + return gl::OutOfMemory() << "Failed to resize EmulatedIndexedStorage"; } mBufferSize = size; } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -uint8_t *Buffer11::EmulatedIndexedStorage::map(size_t offset, size_t length, GLbitfield access) +gl::Error Buffer11::EmulatedIndexedStorage::map(size_t offset, + size_t length, + GLbitfield access, + uint8_t **mapPointerOut) { ASSERT(!mMemoryBuffer.empty() && offset + length <= mMemoryBuffer.size()); - return mMemoryBuffer.data() + offset; + *mapPointerOut = mMemoryBuffer.data() + offset; + return gl::NoError(); } void Buffer11::EmulatedIndexedStorage::unmap() @@ -1249,6 +1413,8 @@ void Buffer11::EmulatedIndexedStorage::unmap() // No-op } +// Buffer11::PackStorage implementation + Buffer11::PackStorage::PackStorage(Renderer11 *renderer) : BufferStorage(renderer, BUFFER_USAGE_PIXEL_PACK), mStagingTexture(), mDataModified(false) { @@ -1258,32 +1424,42 @@ Buffer11::PackStorage::~PackStorage() { } -bool Buffer11::PackStorage::copyFromStorage(BufferStorage *source, - size_t sourceOffset, - size_t size, - size_t destOffset) +gl::ErrorOrResult<CopyResult> Buffer11::PackStorage::copyFromStorage(const gl::Context *context, + BufferStorage *source, + size_t sourceOffset, + size_t size, + size_t destOffset) { - // We copy through a staging buffer when drawing with a pack buffer, - // or for other cases where we access the pack buffer - UNREACHABLE(); - return false; + ANGLE_TRY(flushQueuedPackCommand()); + + // For all use cases of pack buffers, we must copy through a readable buffer. + ASSERT(source->isCPUAccessible(GL_MAP_READ_BIT)); + uint8_t *sourceData = nullptr; + ANGLE_TRY(source->map(sourceOffset, size, GL_MAP_READ_BIT, &sourceData)); + ASSERT(destOffset + size <= mMemoryBuffer.size()); + memcpy(mMemoryBuffer.data() + destOffset, sourceData, size); + source->unmap(); + return CopyResult::NOT_RECREATED; } -gl::Error Buffer11::PackStorage::resize(size_t size, bool preserveData) +gl::Error Buffer11::PackStorage::resize(const gl::Context *context, size_t size, bool preserveData) { if (size != mBufferSize) { if (!mMemoryBuffer.resize(size)) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to resize internal buffer storage."); + return gl::OutOfMemory() << "Failed to resize internal buffer storage."; } mBufferSize = size; } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -uint8_t *Buffer11::PackStorage::map(size_t offset, size_t length, GLbitfield access) +gl::Error Buffer11::PackStorage::map(size_t offset, + size_t length, + GLbitfield access, + uint8_t **mapPointerOut) { ASSERT(offset + length <= getSize()); // TODO: fast path @@ -1291,15 +1467,12 @@ uint8_t *Buffer11::PackStorage::map(size_t offset, size_t length, GLbitfield acc // and if D3D packs the staging texture memory identically to how we would fill // the pack buffer according to the current pack state. - gl::Error error = flushQueuedPackCommand(); - if (error.isError()) - { - return nullptr; - } + ANGLE_TRY(flushQueuedPackCommand()); mDataModified = (mDataModified || (access & GL_MAP_WRITE_BIT) != 0); - return mMemoryBuffer.data() + offset; + *mapPointerOut = mMemoryBuffer.data() + offset; + return gl::NoError(); } void Buffer11::PackStorage::unmap() @@ -1307,42 +1480,29 @@ void Buffer11::PackStorage::unmap() // No-op } -gl::Error Buffer11::PackStorage::packPixels(const gl::FramebufferAttachment &readAttachment, +gl::Error Buffer11::PackStorage::packPixels(const gl::Context *context, + const gl::FramebufferAttachment &readAttachment, const PackPixelsParams ¶ms) { - gl::Error error = flushQueuedPackCommand(); - if (error.isError()) - { - return error; - } + ANGLE_TRY(flushQueuedPackCommand()); RenderTarget11 *renderTarget = nullptr; - error = readAttachment.getRenderTarget(&renderTarget); - if (error.isError()) - { - return error; - } - - ID3D11Resource *renderTargetResource = renderTarget->getTexture(); - ASSERT(renderTargetResource); + ANGLE_TRY(readAttachment.getRenderTarget(context, &renderTarget)); + const TextureHelper11 &srcTexture = renderTarget->getTexture(); + ASSERT(srcTexture.valid()); unsigned int srcSubresource = renderTarget->getSubresourceIndex(); - TextureHelper11 srcTexture = TextureHelper11::MakeAndReference(renderTargetResource); mQueuedPackCommand.reset(new PackPixelsParams(params)); gl::Extents srcTextureSize(params.area.width, params.area.height, 1); - if (!mStagingTexture.getResource() || mStagingTexture.getFormat() != srcTexture.getFormat() || + if (!mStagingTexture.get() || mStagingTexture.getFormat() != srcTexture.getFormat() || mStagingTexture.getExtents() != srcTextureSize) { - auto textureOrError = - CreateStagingTexture(srcTexture.getTextureType(), srcTexture.getFormat(), - srcTextureSize, mRenderer->getDevice()); - if (textureOrError.isError()) - { - return textureOrError.getError(); - } - mStagingTexture = std::move(textureOrError.getResult()); + ANGLE_TRY_RESULT( + mRenderer->createStagingTexture(srcTexture.getTextureType(), srcTexture.getFormatSet(), + srcTextureSize, StagingAccess::READ), + mStagingTexture); } // ReadPixels from multisampled FBOs isn't supported in current GL @@ -1357,17 +1517,17 @@ gl::Error Buffer11::PackStorage::packPixels(const gl::FramebufferAttachment &rea // Select the correct layer from a 3D attachment srcBox.front = 0; - if (mStagingTexture.getTextureType() == GL_TEXTURE_3D) + if (mStagingTexture.is3D()) { srcBox.front = static_cast<UINT>(readAttachment.layer()); } srcBox.back = srcBox.front + 1; // Asynchronous copy - immediateContext->CopySubresourceRegion(mStagingTexture.getResource(), 0, 0, 0, 0, - srcTexture.getResource(), srcSubresource, &srcBox); + immediateContext->CopySubresourceRegion(mStagingTexture.get(), 0, 0, 0, 0, srcTexture.get(), + srcSubresource, &srcBox); - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } gl::Error Buffer11::PackStorage::flushQueuedPackCommand() @@ -1376,58 +1536,65 @@ gl::Error Buffer11::PackStorage::flushQueuedPackCommand() if (mQueuedPackCommand) { - gl::Error error = - mRenderer->packPixels(mStagingTexture, *mQueuedPackCommand, mMemoryBuffer.data()); + ANGLE_TRY( + mRenderer->packPixels(mStagingTexture, *mQueuedPackCommand, mMemoryBuffer.data())); mQueuedPackCommand.reset(nullptr); - if (error.isError()) - { - return error; - } } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } +// Buffer11::SystemMemoryStorage implementation + Buffer11::SystemMemoryStorage::SystemMemoryStorage(Renderer11 *renderer) : Buffer11::BufferStorage(renderer, BUFFER_USAGE_SYSTEM_MEMORY) { } -bool Buffer11::SystemMemoryStorage::copyFromStorage(BufferStorage *source, - size_t sourceOffset, - size_t size, - size_t destOffset) +gl::ErrorOrResult<CopyResult> Buffer11::SystemMemoryStorage::copyFromStorage( + const gl::Context *context, + BufferStorage *source, + size_t sourceOffset, + size_t size, + size_t destOffset) { - ASSERT(source->isMappable()); - const uint8_t *sourceData = source->map(sourceOffset, size, GL_MAP_READ_BIT); + ASSERT(source->isCPUAccessible(GL_MAP_READ_BIT)); + uint8_t *sourceData = nullptr; + ANGLE_TRY(source->map(sourceOffset, size, GL_MAP_READ_BIT, &sourceData)); ASSERT(destOffset + size <= mSystemCopy.size()); memcpy(mSystemCopy.data() + destOffset, sourceData, size); source->unmap(); - return true; + return CopyResult::RECREATED; } -gl::Error Buffer11::SystemMemoryStorage::resize(size_t size, bool preserveData) +gl::Error Buffer11::SystemMemoryStorage::resize(const gl::Context *context, + size_t size, + bool preserveData) { if (mSystemCopy.size() < size) { if (!mSystemCopy.resize(size)) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to resize SystemMemoryStorage"); + return gl::OutOfMemory() << "Failed to resize SystemMemoryStorage"; } mBufferSize = size; } - return gl::Error(GL_NO_ERROR); + return gl::NoError(); } -uint8_t *Buffer11::SystemMemoryStorage::map(size_t offset, size_t length, GLbitfield access) +gl::Error Buffer11::SystemMemoryStorage::map(size_t offset, + size_t length, + GLbitfield access, + uint8_t **mapPointerOut) { ASSERT(!mSystemCopy.empty() && offset + length <= mSystemCopy.size()); - return mSystemCopy.data() + offset; + *mapPointerOut = mSystemCopy.data() + offset; + return gl::NoError(); } void Buffer11::SystemMemoryStorage::unmap() { // No-op } -} +} // namespace rx |