summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Buffer11.cpp
diff options
context:
space:
mode:
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.cpp875
1 files changed, 619 insertions, 256 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 d56b0ea7ad..0d5dc08b03 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Buffer11.cpp
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Buffer11.cpp
@@ -8,10 +8,27 @@
#include "libANGLE/renderer/d3d/d3d11/Buffer11.h"
+#include <memory>
+
#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/formatutils11.h"
+namespace
+{
+
+template <typename T>
+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
@@ -20,32 +37,33 @@ typedef enum D3D11_MAP_FLAG {
namespace rx
{
-
PackPixelsParams::PackPixelsParams()
- : format(GL_NONE),
- type(GL_NONE),
- outputPitch(0),
- packBuffer(NULL),
- offset(0)
-{}
-
-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)
-{}
+ : format(GL_NONE), type(GL_NONE), outputPitch(0), packBuffer(nullptr), offset(0)
+{
+}
+
+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)
+{
+}
namespace gl_d3d11
{
D3D11_MAP GetD3DMapTypeFromBits(GLbitfield access)
{
- bool readBit = ((access & GL_MAP_READ_BIT) != 0);
+ bool readBit = ((access & GL_MAP_READ_BIT) != 0);
bool writeBit = ((access & GL_MAP_WRITE_BIT) != 0);
ASSERT(readBit || writeBit);
@@ -71,7 +89,6 @@ D3D11_MAP GetD3DMapTypeFromBits(GLbitfield access)
return D3D11_MAP_READ;
}
}
-
}
// Each instance of Buffer11::BufferStorage is specialized for a class of D3D binding points
@@ -91,8 +108,10 @@ class Buffer11::BufferStorage : angle::NonCopyable
virtual bool isMappable() const = 0;
- virtual bool copyFromStorage(BufferStorage *source, size_t sourceOffset,
- size_t size, size_t destOffset) = 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 uint8_t *map(size_t offset, size_t length, GLbitfield access) = 0;
@@ -120,20 +139,57 @@ class Buffer11::NativeStorage : public Buffer11::BufferStorage
bool isMappable() const override { return mUsage == BUFFER_USAGE_STAGING; }
ID3D11Buffer *getNativeStorage() const { return mNativeStorage; }
-
- bool copyFromStorage(BufferStorage *source, size_t sourceOffset,
- size_t size, size_t destOffset) override;
+ bool copyFromStorage(BufferStorage *source,
+ size_t sourceOffset,
+ size_t size,
+ size_t destOffset) override;
gl::Error resize(size_t size, bool preserveData) override;
uint8_t *map(size_t offset, size_t length, GLbitfield access) override;
void unmap() override;
private:
- static void fillBufferDesc(D3D11_BUFFER_DESC* bufferDesc, Renderer11 *renderer, BufferUsage usage, unsigned int bufferSize);
+ static void fillBufferDesc(D3D11_BUFFER_DESC *bufferDesc,
+ Renderer11 *renderer,
+ BufferUsage usage,
+ unsigned int bufferSize);
ID3D11Buffer *mNativeStorage;
};
+// A emulated indexed buffer storage represents an underlying D3D11 buffer for data
+// that has been expanded to match the indices list used. This storage is only
+// used for FL9_3 pointsprite rendering emulation.
+class Buffer11::EmulatedIndexedStorage : public Buffer11::BufferStorage
+{
+ public:
+ EmulatedIndexedStorage(Renderer11 *renderer);
+ ~EmulatedIndexedStorage() override;
+
+ bool isMappable() const override { return true; }
+
+ ID3D11Buffer *getNativeStorage();
+
+ bool copyFromStorage(BufferStorage *source,
+ size_t sourceOffset,
+ size_t size,
+ size_t destOffset) override;
+
+ gl::Error resize(size_t size, bool preserveData) override;
+
+ uint8_t *map(size_t offset, size_t length, GLbitfield access) 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
+};
+
// Pack storage represents internal storage for pack buffers. We implement pack buffers
// as CPU memory, tied to a staging texture, for asynchronous texture readback.
class Buffer11::PackStorage : public Buffer11::BufferStorage
@@ -143,24 +199,24 @@ class Buffer11::PackStorage : public Buffer11::BufferStorage
~PackStorage() override;
bool isMappable() const override { return true; }
-
- bool copyFromStorage(BufferStorage *source, size_t sourceOffset,
- size_t size, size_t destOffset) override;
+ bool copyFromStorage(BufferStorage *source,
+ size_t sourceOffset,
+ size_t size,
+ size_t destOffset) override;
gl::Error resize(size_t size, bool preserveData) override;
uint8_t *map(size_t offset, size_t length, GLbitfield access) override;
void unmap() override;
- gl::Error packPixels(ID3D11Texture2D *srcTexure, UINT srcSubresource, const PackPixelsParams &params);
+ gl::Error packPixels(const gl::FramebufferAttachment &readAttachment,
+ const PackPixelsParams &params);
private:
gl::Error flushQueuedPackCommand();
- ID3D11Texture2D *mStagingTexture;
- DXGI_FORMAT mTextureFormat;
- gl::Extents mTextureSize;
+ TextureHelper11 mStagingTexture;
MemoryBuffer mMemoryBuffer;
- PackPixelsParams *mQueuedPackCommand;
+ std::unique_ptr<PackPixelsParams> mQueuedPackCommand;
PackPixelsParams mPackParams;
bool mDataModified;
};
@@ -175,9 +231,10 @@ class Buffer11::SystemMemoryStorage : public Buffer11::BufferStorage
~SystemMemoryStorage() override {}
bool isMappable() const override { return true; }
-
- bool copyFromStorage(BufferStorage *source, size_t sourceOffset,
- size_t size, size_t destOffset) override;
+ bool copyFromStorage(BufferStorage *source,
+ size_t sourceOffset,
+ size_t size,
+ size_t destOffset) override;
gl::Error resize(size_t size, bool preserveData) override;
uint8_t *map(size_t offset, size_t length, GLbitfield access) override;
@@ -193,23 +250,27 @@ Buffer11::Buffer11(Renderer11 *renderer)
: BufferD3D(renderer),
mRenderer(renderer),
mSize(0),
- mMappedStorage(NULL),
- mReadUsageCount(0),
- mHasSystemMemoryStorage(false)
-{}
+ mMappedStorage(nullptr),
+ mBufferStorages(BUFFER_USAGE_COUNT, nullptr),
+ mConstantBufferStorageAdditionalSize(0),
+ mMaxConstantBufferLruCount(0),
+ mReadUsageCount(0)
+{
+}
Buffer11::~Buffer11()
{
- for (auto it = mBufferStorages.begin(); it != mBufferStorages.end(); it++)
+ for (auto &storage : mBufferStorages)
{
- SafeDelete(it->second);
+ SafeDelete(storage);
}
-}
-Buffer11 *Buffer11::makeBuffer11(BufferImpl *buffer)
-{
- ASSERT(HAS_DYNAMIC_TYPE(Buffer11*, buffer));
- return static_cast<Buffer11*>(buffer);
+ for (auto &p : mConstantBufferRangeStoragesCache)
+ {
+ SafeDelete(p.second.storage);
+ }
+
+ mRenderer->onBufferDelete(this);
}
gl::Error Buffer11::setData(const void *data, size_t size, GLenum usage)
@@ -220,18 +281,14 @@ gl::Error Buffer11::setData(const void *data, size_t size, GLenum usage)
return error;
}
- if (usage == GL_STATIC_DRAW)
- {
- initializeStaticData();
- }
-
+ updateD3DBufferUsage(usage);
return error;
}
gl::Error Buffer11::getData(const uint8_t **outData)
{
SystemMemoryStorage *systemMemoryStorage = nullptr;
- gl::Error error = getSystemMemoryStorage(&systemMemoryStorage);
+ gl::Error error = getSystemMemoryStorage(&systemMemoryStorage);
if (error.isError())
{
@@ -310,15 +367,18 @@ gl::Error Buffer11::setSubData(const void *data, size_t size, size_t offset)
}
mSize = std::max(mSize, requiredSize);
- invalidateStaticData();
+ invalidateStaticData(D3D_BUFFER_INVALIDATE_WHOLE_CACHE);
return gl::Error(GL_NO_ERROR);
}
-gl::Error Buffer11::copySubData(BufferImpl* source, GLintptr sourceOffset, GLintptr destOffset, GLsizeiptr size)
+gl::Error Buffer11::copySubData(BufferImpl *source,
+ GLintptr sourceOffset,
+ GLintptr destOffset,
+ GLsizeiptr size)
{
- Buffer11 *sourceBuffer = makeBuffer11(source);
- ASSERT(sourceBuffer != NULL);
+ Buffer11 *sourceBuffer = GetAs<Buffer11>(source);
+ ASSERT(sourceBuffer != nullptr);
BufferStorage *copyDest = getLatestBufferStorage();
if (!copyDest)
@@ -363,19 +423,26 @@ gl::Error Buffer11::copySubData(BufferImpl* source, GLintptr sourceOffset, GLint
copyDest->setDataRevision(copyDest->getDataRevision() + 1);
mSize = std::max<size_t>(mSize, destOffset + size);
- invalidateStaticData();
+ invalidateStaticData(D3D_BUFFER_INVALIDATE_WHOLE_CACHE);
return gl::Error(GL_NO_ERROR);
}
-gl::Error Buffer11::map(size_t offset, size_t length, GLbitfield access, GLvoid **mapPtr)
+gl::Error Buffer11::map(GLenum access, GLvoid **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);
+}
+
+gl::Error Buffer11::mapRange(size_t offset, size_t length, GLbitfield access, GLvoid **mapPtr)
{
ASSERT(!mMappedStorage);
BufferStorage *latestStorage = getLatestBufferStorage();
- if (latestStorage &&
- (latestStorage->getUsage() == BUFFER_USAGE_PIXEL_PACK ||
- latestStorage->getUsage() == BUFFER_USAGE_STAGING))
+ if (latestStorage && (latestStorage->getUsage() == BUFFER_USAGE_PIXEL_PACK ||
+ latestStorage->getUsage() == BUFFER_USAGE_STAGING))
{
// Latest storage is mappable.
mMappedStorage = latestStorage;
@@ -396,6 +463,7 @@ gl::Error Buffer11::map(size_t offset, size_t length, GLbitfield access, GLvoid
{
// 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);
}
uint8_t *mappedBuffer = mMappedStorage->map(offset, length, access);
@@ -408,24 +476,29 @@ gl::Error Buffer11::map(size_t offset, size_t length, GLbitfield access, GLvoid
return gl::Error(GL_NO_ERROR);
}
-gl::Error Buffer11::unmap()
+gl::Error Buffer11::unmap(GLboolean *result)
{
ASSERT(mMappedStorage);
mMappedStorage->unmap();
- mMappedStorage = NULL;
+ mMappedStorage = nullptr;
+
+ // TODO: detect if we had corruption. if so, return false.
+ *result = GL_TRUE;
+
return gl::Error(GL_NO_ERROR);
}
void Buffer11::markTransformFeedbackUsage()
{
- BufferStorage *transformFeedbackStorage = getBufferStorage(BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK);
+ BufferStorage *transformFeedbackStorage =
+ getBufferStorage(BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK);
if (transformFeedbackStorage)
{
transformFeedbackStorage->setDataRevision(transformFeedbackStorage->getDataRevision() + 1);
}
- invalidateStaticData();
+ invalidateStaticData(D3D_BUFFER_INVALIDATE_WHOLE_CACHE);
}
void Buffer11::markBufferUsage()
@@ -435,14 +508,13 @@ void Buffer11::markBufferUsage()
// Free the system memory storage if we decide it isn't being used very often.
const unsigned int usageLimit = 5;
- if (mReadUsageCount > usageLimit && mHasSystemMemoryStorage)
+ BufferStorage *&sysMemUsage = mBufferStorages[BUFFER_USAGE_SYSTEM_MEMORY];
+ if (mReadUsageCount > usageLimit && sysMemUsage != nullptr)
{
- auto systemMemoryStorageIt = mBufferStorages.find(BUFFER_USAGE_SYSTEM_MEMORY);
- ASSERT(systemMemoryStorageIt != mBufferStorages.end());
-
- SafeDelete(systemMemoryStorageIt->second);
- mBufferStorages.erase(systemMemoryStorageIt);
- mHasSystemMemoryStorage = false;
+ if (getLatestBufferStorage() != sysMemUsage)
+ {
+ SafeDelete(sysMemUsage);
+ }
}
}
@@ -455,12 +527,59 @@ ID3D11Buffer *Buffer11::getBuffer(BufferUsage usage)
if (!bufferStorage)
{
// Storage out-of-memory
- return NULL;
+ return nullptr;
}
- ASSERT(HAS_DYNAMIC_TYPE(NativeStorage*, bufferStorage));
+ return GetAs<NativeStorage>(bufferStorage)->getNativeStorage();
+}
+
+ID3D11Buffer *Buffer11::getEmulatedIndexedBuffer(SourceIndexData *indexInfo,
+ const TranslatedAttribute *attribute)
+{
+ markBufferUsage();
+
+ assert(indexInfo != nullptr);
+ assert(attribute != nullptr);
- return static_cast<NativeStorage*>(bufferStorage)->getNativeStorage();
+ BufferStorage *bufferStorage = getBufferStorage(BUFFER_USAGE_EMULATED_INDEXED_VERTEX);
+ if (!bufferStorage)
+ {
+ // Storage out-of-memory
+ return nullptr;
+ }
+
+ EmulatedIndexedStorage *emulatedStorage = GetAs<EmulatedIndexedStorage>(bufferStorage);
+ if (!emulatedStorage->update(indexInfo, attribute))
+ {
+ // Storage out-of-memory
+ return nullptr;
+ }
+
+ return emulatedStorage->getNativeStorage();
+}
+
+ID3D11Buffer *Buffer11::getConstantBufferRange(GLintptr offset, GLsizeiptr size)
+{
+ markBufferUsage();
+
+ BufferStorage *bufferStorage;
+
+ if (offset == 0)
+ {
+ bufferStorage = getBufferStorage(BUFFER_USAGE_UNIFORM);
+ }
+ else
+ {
+ bufferStorage = getConstantBufferRangeStorage(offset, size);
+ }
+
+ if (!bufferStorage)
+ {
+ // Storage out-of-memory
+ return nullptr;
+ }
+
+ return GetAs<NativeStorage>(bufferStorage)->getNativeStorage();
}
ID3D11ShaderResourceView *Buffer11::getSRV(DXGI_FORMAT srvFormat)
@@ -470,11 +589,10 @@ ID3D11ShaderResourceView *Buffer11::getSRV(DXGI_FORMAT srvFormat)
if (!storage)
{
// Storage out-of-memory
- return NULL;
+ return nullptr;
}
- ASSERT(HAS_DYNAMIC_TYPE(NativeStorage*, storage));
- ID3D11Buffer *buffer = static_cast<NativeStorage*>(storage)->getNativeStorage();
+ ID3D11Buffer *buffer = GetAs<NativeStorage>(storage)->getNativeStorage();
auto bufferSRVIt = mBufferResourceViews.find(srvFormat);
@@ -491,16 +609,17 @@ ID3D11ShaderResourceView *Buffer11::getSRV(DXGI_FORMAT srvFormat)
}
}
- ID3D11Device *device = mRenderer->getDevice();
- ID3D11ShaderResourceView *bufferSRV = NULL;
+ ID3D11Device *device = mRenderer->getDevice();
+ ID3D11ShaderResourceView *bufferSRV = nullptr;
const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(srvFormat);
D3D11_SHADER_RESOURCE_VIEW_DESC bufferSRVDesc;
bufferSRVDesc.Buffer.ElementOffset = 0;
- bufferSRVDesc.Buffer.ElementWidth = mSize / dxgiFormatInfo.pixelBytes;
- bufferSRVDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER;
- bufferSRVDesc.Format = srvFormat;
+ 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);
@@ -511,14 +630,15 @@ ID3D11ShaderResourceView *Buffer11::getSRV(DXGI_FORMAT srvFormat)
return bufferSRV;
}
-gl::Error Buffer11::packPixels(ID3D11Texture2D *srcTexture, UINT srcSubresource, const PackPixelsParams &params)
+gl::Error Buffer11::packPixels(const gl::FramebufferAttachment &readAttachment,
+ const PackPixelsParams &params)
{
- PackStorage *packStorage = getPackStorage();
+ PackStorage *packStorage = getPackStorage();
BufferStorage *latestStorage = getLatestBufferStorage();
if (packStorage)
{
- gl::Error error = packStorage->packPixels(srcTexture, srcSubresource, params);
+ gl::Error error = packStorage->packPixels(readAttachment, params);
if (error.isError())
{
return error;
@@ -529,14 +649,23 @@ gl::Error Buffer11::packPixels(ID3D11Texture2D *srcTexture, UINT srcSubresource,
return gl::Error(GL_NO_ERROR);
}
+size_t Buffer11::getTotalCPUBufferMemoryBytes() const
+{
+ size_t allocationSize = 0;
+
+ BufferStorage *staging = mBufferStorages[BUFFER_USAGE_STAGING];
+ allocationSize += staging ? staging->getSize() : 0;
+
+ BufferStorage *sysMem = mBufferStorages[BUFFER_USAGE_SYSTEM_MEMORY];
+ allocationSize += sysMem ? sysMem->getSize() : 0;
+
+ return allocationSize;
+}
+
Buffer11::BufferStorage *Buffer11::getBufferStorage(BufferUsage usage)
{
- BufferStorage *newStorage = NULL;
- auto directBufferIt = mBufferStorages.find(usage);
- if (directBufferIt != mBufferStorages.end())
- {
- newStorage = directBufferIt->second;
- }
+ ASSERT(0 <= usage && usage < BUFFER_USAGE_COUNT);
+ BufferStorage *&newStorage = mBufferStorages[usage];
if (!newStorage)
{
@@ -547,15 +676,16 @@ Buffer11::BufferStorage *Buffer11::getBufferStorage(BufferUsage usage)
else if (usage == BUFFER_USAGE_SYSTEM_MEMORY)
{
newStorage = new SystemMemoryStorage(mRenderer);
- mHasSystemMemoryStorage = true;
+ }
+ else if (usage == BUFFER_USAGE_EMULATED_INDEXED_VERTEX)
+ {
+ newStorage = new EmulatedIndexedStorage(mRenderer);
}
else
{
// buffer is not allocated, create it
newStorage = new NativeStorage(mRenderer, usage);
}
-
- mBufferStorages.insert(std::make_pair(usage, newStorage));
}
// resize buffer
@@ -564,19 +694,88 @@ Buffer11::BufferStorage *Buffer11::getBufferStorage(BufferUsage usage)
if (newStorage->resize(mSize, true).isError())
{
// Out of memory error
- return NULL;
+ return nullptr;
+ }
+ }
+
+ updateBufferStorage(newStorage, 0, mSize);
+
+ return newStorage;
+}
+
+Buffer11::BufferStorage *Buffer11::getConstantBufferRangeStorage(GLintptr offset, GLsizeiptr size)
+{
+ BufferStorage *newStorage;
+
+ {
+ // Keep the cacheEntry in a limited scope because it may be invalidated later in the code if
+ // we need to reclaim some space.
+ ConstantBufferCacheEntry *cacheEntry = &mConstantBufferRangeStoragesCache[offset];
+
+ if (!cacheEntry->storage)
+ {
+ cacheEntry->storage = new NativeStorage(mRenderer, BUFFER_USAGE_UNIFORM);
+ cacheEntry->lruCount = ++mMaxConstantBufferLruCount;
}
+
+ cacheEntry->lruCount = ++mMaxConstantBufferLruCount;
+ newStorage = cacheEntry->storage;
}
+ if (newStorage->getSize() < static_cast<size_t>(size))
+ {
+ size_t maximumAllowedAdditionalSize = 2 * getSize();
+
+ size_t sizeDelta = size - newStorage->getSize();
+
+ while (mConstantBufferStorageAdditionalSize + sizeDelta > maximumAllowedAdditionalSize)
+ {
+ auto iter = std::min_element(std::begin(mConstantBufferRangeStoragesCache),
+ std::end(mConstantBufferRangeStoragesCache),
+ [](const ConstantBufferCache::value_type &a,
+ const ConstantBufferCache::value_type &b)
+ {
+ return a.second.lruCount < b.second.lruCount;
+ });
+
+ ASSERT(iter->second.storage != newStorage);
+ ASSERT(mConstantBufferStorageAdditionalSize >= iter->second.storage->getSize());
+
+ mConstantBufferStorageAdditionalSize -= iter->second.storage->getSize();
+ SafeDelete(iter->second.storage);
+ mConstantBufferRangeStoragesCache.erase(iter);
+ }
+
+ if (newStorage->resize(size, false).isError())
+ {
+ // Out of memory error
+ return nullptr;
+ }
+
+ mConstantBufferStorageAdditionalSize += sizeDelta;
+
+ // We don't copy the old data when resizing the constant buffer because the data may be
+ // out-of-date therefore we reset the data revision and let updateBufferStorage() handle the
+ // copy.
+ newStorage->setDataRevision(0);
+ }
+
+ updateBufferStorage(newStorage, offset, size);
+
+ return newStorage;
+}
+
+void Buffer11::updateBufferStorage(BufferStorage *storage, size_t sourceOffset, size_t storageSize)
+{
BufferStorage *latestBuffer = getLatestBufferStorage();
- if (latestBuffer && latestBuffer->getDataRevision() > newStorage->getDataRevision())
+ 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 &&
- newStorage->getUsage() != BUFFER_USAGE_STAGING &&
- (!latestBuffer->isMappable() || !newStorage->isMappable()))
+ storage->getUsage() != BUFFER_USAGE_STAGING &&
+ (!latestBuffer->isMappable() || !storage->isMappable()))
{
NativeStorage *stagingBuffer = getStagingStorage();
@@ -588,28 +787,25 @@ Buffer11::BufferStorage *Buffer11::getBufferStorage(BufferUsage usage)
// if copyFromStorage returns true, the D3D buffer has been recreated
// and we should update our serial
- if (newStorage->copyFromStorage(latestBuffer, 0, latestBuffer->getSize(), 0))
+ if (storage->copyFromStorage(latestBuffer, sourceOffset, storageSize, 0))
{
updateSerial();
}
- newStorage->setDataRevision(latestBuffer->getDataRevision());
+ storage->setDataRevision(latestBuffer->getDataRevision());
}
-
- return newStorage;
}
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 = NULL;
+ BufferStorage *latestStorage = nullptr;
DataRevision latestRevision = 0;
- for (auto it = mBufferStorages.begin(); it != mBufferStorages.end(); it++)
+ for (auto &storage : mBufferStorages)
{
- BufferStorage *storage = it->second;
- if (!latestStorage || storage->getDataRevision() > latestRevision)
+ if (storage && (!latestStorage || storage->getDataRevision() > latestRevision))
{
- latestStorage = storage;
+ latestStorage = storage;
latestRevision = storage->getDataRevision();
}
}
@@ -620,7 +816,7 @@ Buffer11::BufferStorage *Buffer11::getLatestBufferStorage() const
if (latestStorage->resize(mSize, true).isError())
{
// Out of memory error
- return NULL;
+ return nullptr;
}
}
@@ -634,11 +830,10 @@ Buffer11::NativeStorage *Buffer11::getStagingStorage()
if (!stagingStorage)
{
// Out-of-memory
- return NULL;
+ return nullptr;
}
- ASSERT(HAS_DYNAMIC_TYPE(NativeStorage*, stagingStorage));
- return static_cast<NativeStorage*>(stagingStorage);
+ return GetAs<NativeStorage>(stagingStorage);
}
Buffer11::PackStorage *Buffer11::getPackStorage()
@@ -648,11 +843,10 @@ Buffer11::PackStorage *Buffer11::getPackStorage()
if (!packStorage)
{
// Out-of-memory
- return NULL;
+ return nullptr;
}
- ASSERT(HAS_DYNAMIC_TYPE(PackStorage*, packStorage));
- return static_cast<PackStorage*>(packStorage);
+ return GetAs<PackStorage>(packStorage);
}
bool Buffer11::supportsDirectBinding() const
@@ -664,10 +858,7 @@ bool Buffer11::supportsDirectBinding() const
}
Buffer11::BufferStorage::BufferStorage(Renderer11 *renderer, BufferUsage usage)
- : mRenderer(renderer),
- mUsage(usage),
- mRevision(0),
- mBufferSize(0)
+ : mRenderer(renderer), mRevision(0), mUsage(usage), mBufferSize(0)
{
}
@@ -689,8 +880,7 @@ gl::Error Buffer11::BufferStorage::setData(const uint8_t *data, size_t offset, s
}
Buffer11::NativeStorage::NativeStorage(Renderer11 *renderer, BufferUsage usage)
- : BufferStorage(renderer, usage),
- mNativeStorage(NULL)
+ : BufferStorage(renderer, usage), mNativeStorage(nullptr)
{
}
@@ -700,19 +890,21 @@ Buffer11::NativeStorage::~NativeStorage()
}
// 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::copyFromStorage(BufferStorage *source,
+ size_t sourceOffset,
+ size_t size,
+ size_t destOffset)
{
ID3D11DeviceContext *context = mRenderer->getDeviceContext();
- size_t requiredSize = sourceOffset + size;
- bool createBuffer = !mNativeStorage || mBufferSize < requiredSize;
+ size_t requiredSize = destOffset + size;
+ bool createBuffer = !mNativeStorage || mBufferSize < requiredSize;
// (Re)initialize D3D buffer if needed
if (createBuffer)
{
bool preserveData = (destOffset > 0);
- resize(source->getSize(), preserveData);
+ resize(requiredSize, preserveData);
}
if (source->getUsage() == BUFFER_USAGE_PIXEL_PACK ||
@@ -724,8 +916,12 @@ bool Buffer11::NativeStorage::copyFromStorage(BufferStorage *source, size_t sour
D3D11_MAPPED_SUBRESOURCE mappedResource;
HRESULT hr = context->Map(mNativeStorage, 0, D3D11_MAP_WRITE, 0, &mappedResource);
- UNUSED_ASSERTION_VARIABLE(hr);
ASSERT(SUCCEEDED(hr));
+ if (FAILED(hr))
+ {
+ source->unmap();
+ return false;
+ }
uint8_t *destPointer = static_cast<uint8_t *>(mappedResource.pData) + destOffset;
@@ -738,20 +934,18 @@ bool Buffer11::NativeStorage::copyFromStorage(BufferStorage *source, size_t sour
}
else
{
- ASSERT(HAS_DYNAMIC_TYPE(NativeStorage*, source));
-
D3D11_BOX srcBox;
- srcBox.left = sourceOffset;
- srcBox.right = sourceOffset + size;
- srcBox.top = 0;
+ srcBox.left = static_cast<unsigned int>(sourceOffset);
+ srcBox.right = static_cast<unsigned int>(sourceOffset + size);
+ srcBox.top = 0;
srcBox.bottom = 1;
- srcBox.front = 0;
- srcBox.back = 1;
+ srcBox.front = 0;
+ srcBox.back = 1;
- ASSERT(HAS_DYNAMIC_TYPE(NativeStorage*, source));
- ID3D11Buffer *sourceBuffer = static_cast<NativeStorage*>(source)->getNativeStorage();
+ ID3D11Buffer *sourceBuffer = GetAs<NativeStorage>(source)->getNativeStorage();
- context->CopySubresourceRegion(mNativeStorage, 0, destOffset, 0, 0, sourceBuffer, 0, &srcBox);
+ context->CopySubresourceRegion(mNativeStorage, 0, static_cast<unsigned int>(destOffset), 0,
+ 0, sourceBuffer, 0, &srcBox);
}
return createBuffer;
@@ -759,32 +953,35 @@ bool Buffer11::NativeStorage::copyFromStorage(BufferStorage *source, size_t sour
gl::Error Buffer11::NativeStorage::resize(size_t size, bool preserveData)
{
- ID3D11Device *device = mRenderer->getDevice();
+ ID3D11Device *device = mRenderer->getDevice();
ID3D11DeviceContext *context = mRenderer->getDeviceContext();
D3D11_BUFFER_DESC bufferDesc;
- fillBufferDesc(&bufferDesc, mRenderer, mUsage, size);
+ fillBufferDesc(&bufferDesc, mRenderer, mUsage, static_cast<unsigned int>(size));
ID3D11Buffer *newBuffer;
- HRESULT result = device->CreateBuffer(&bufferDesc, NULL, &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);
+ return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal buffer, result: 0x%X.",
+ result);
}
+ d3d11::SetDebugName(newBuffer, "Buffer11::NativeStorage");
+
if (mNativeStorage && preserveData)
{
// We don't call resize if the buffer is big enough already.
ASSERT(mBufferSize <= size);
D3D11_BOX srcBox;
- srcBox.left = 0;
- srcBox.right = mBufferSize;
- srcBox.top = 0;
+ srcBox.left = 0;
+ srcBox.right = static_cast<unsigned int>(mBufferSize);
+ srcBox.top = 0;
srcBox.bottom = 1;
- srcBox.front = 0;
- srcBox.back = 1;
+ srcBox.front = 0;
+ srcBox.back = 1;
context->CopySubresourceRegion(newBuffer, 0, 0, 0, 0, mNativeStorage, 0, &srcBox);
}
@@ -798,58 +995,62 @@ gl::Error Buffer11::NativeStorage::resize(size_t size, bool preserveData)
return gl::Error(GL_NO_ERROR);
}
-void Buffer11::NativeStorage::fillBufferDesc(D3D11_BUFFER_DESC* bufferDesc, Renderer11 *renderer,
- BufferUsage usage, unsigned int bufferSize)
+void Buffer11::NativeStorage::fillBufferDesc(D3D11_BUFFER_DESC *bufferDesc,
+ Renderer11 *renderer,
+ BufferUsage usage,
+ unsigned int bufferSize)
{
- bufferDesc->ByteWidth = bufferSize;
- bufferDesc->MiscFlags = 0;
+ bufferDesc->ByteWidth = bufferSize;
+ bufferDesc->MiscFlags = 0;
bufferDesc->StructureByteStride = 0;
switch (usage)
{
- case BUFFER_USAGE_STAGING:
- bufferDesc->Usage = D3D11_USAGE_STAGING;
- bufferDesc->BindFlags = 0;
- bufferDesc->CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
- break;
+ case BUFFER_USAGE_STAGING:
+ bufferDesc->Usage = D3D11_USAGE_STAGING;
+ bufferDesc->BindFlags = 0;
+ bufferDesc->CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
+ break;
- case BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK:
- bufferDesc->Usage = D3D11_USAGE_DEFAULT;
- bufferDesc->BindFlags = D3D11_BIND_VERTEX_BUFFER;
+ case BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK:
+ bufferDesc->Usage = D3D11_USAGE_DEFAULT;
+ bufferDesc->BindFlags = D3D11_BIND_VERTEX_BUFFER;
- if (renderer->isES3Capable())
- {
- bufferDesc->BindFlags |= D3D11_BIND_STREAM_OUTPUT;
- }
+ if (renderer->isES3Capable())
+ {
+ bufferDesc->BindFlags |= D3D11_BIND_STREAM_OUTPUT;
+ }
- bufferDesc->CPUAccessFlags = 0;
- break;
-
- case BUFFER_USAGE_INDEX:
- bufferDesc->Usage = D3D11_USAGE_DEFAULT;
- bufferDesc->BindFlags = D3D11_BIND_INDEX_BUFFER;
- bufferDesc->CPUAccessFlags = 0;
- break;
-
- case BUFFER_USAGE_PIXEL_UNPACK:
- bufferDesc->Usage = D3D11_USAGE_DEFAULT;
- bufferDesc->BindFlags = D3D11_BIND_SHADER_RESOURCE;
- bufferDesc->CPUAccessFlags = 0;
- break;
-
- case BUFFER_USAGE_UNIFORM:
- bufferDesc->Usage = D3D11_USAGE_DYNAMIC;
- bufferDesc->BindFlags = D3D11_BIND_CONSTANT_BUFFER;
- bufferDesc->CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
-
- // 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);
- bufferDesc->ByteWidth = std::min<UINT>(bufferDesc->ByteWidth, renderer->getRendererCaps().maxUniformBlockSize);
- break;
-
- default:
- UNREACHABLE();
+ bufferDesc->CPUAccessFlags = 0;
+ break;
+
+ case BUFFER_USAGE_INDEX:
+ bufferDesc->Usage = D3D11_USAGE_DEFAULT;
+ bufferDesc->BindFlags = D3D11_BIND_INDEX_BUFFER;
+ bufferDesc->CPUAccessFlags = 0;
+ break;
+
+ case BUFFER_USAGE_PIXEL_UNPACK:
+ bufferDesc->Usage = D3D11_USAGE_DEFAULT;
+ bufferDesc->BindFlags = D3D11_BIND_SHADER_RESOURCE;
+ bufferDesc->CPUAccessFlags = 0;
+ break;
+
+ case BUFFER_USAGE_UNIFORM:
+ bufferDesc->Usage = D3D11_USAGE_DYNAMIC;
+ bufferDesc->BindFlags = D3D11_BIND_CONSTANT_BUFFER;
+ bufferDesc->CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
+
+ // 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);
+ bufferDesc->ByteWidth =
+ std::min<UINT>(bufferDesc->ByteWidth,
+ static_cast<UINT>(renderer->getRendererCaps().maxUniformBlockSize));
+ break;
+
+ default:
+ UNREACHABLE();
}
}
@@ -859,14 +1060,16 @@ uint8_t *Buffer11::NativeStorage::map(size_t offset, size_t length, GLbitfield a
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(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);
- UNUSED_ASSERTION_VARIABLE(result);
ASSERT(SUCCEEDED(result));
-
- return static_cast<uint8_t*>(mappedResource.pData) + offset;
+ if (FAILED(result))
+ {
+ return nullptr;
+ }
+ return static_cast<uint8_t *>(mappedResource.pData) + offset;
}
void Buffer11::NativeStorage::unmap()
@@ -876,23 +1079,189 @@ void Buffer11::NativeStorage::unmap()
context->Unmap(mNativeStorage, 0);
}
+Buffer11::EmulatedIndexedStorage::EmulatedIndexedStorage(Renderer11 *renderer)
+ : BufferStorage(renderer, BUFFER_USAGE_EMULATED_INDEXED_VERTEX), mNativeStorage(nullptr)
+{
+}
+
+Buffer11::EmulatedIndexedStorage::~EmulatedIndexedStorage()
+{
+ SafeRelease(mNativeStorage);
+}
+
+ID3D11Buffer *Buffer11::EmulatedIndexedStorage::getNativeStorage()
+{
+ if (!mNativeStorage)
+ {
+ // Expand the memory storage upon request and cache the results.
+ unsigned int expandedDataSize =
+ static_cast<unsigned int>((mIndexInfo.srcCount * mAttributeStride) + mAttributeOffset);
+ MemoryBuffer expandedData;
+ if (!expandedData.resize(expandedDataSize))
+ {
+ return nullptr;
+ }
+
+ // 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);
+
+ // Ensure that we start in the correct place for the emulated data copy operation to
+ // maintain offset behaviors.
+ curr += mAttributeOffset;
+
+ ReadIndexValueFunction readIndexValue = ReadIndexValueFromIndices<GLushort>;
+
+ switch (mIndexInfo.srcIndexType)
+ {
+ case GL_UNSIGNED_INT:
+ readIndexValue = ReadIndexValueFromIndices<GLuint>;
+ break;
+ case GL_UNSIGNED_SHORT:
+ readIndexValue = ReadIndexValueFromIndices<GLushort>;
+ break;
+ case GL_UNSIGNED_BYTE:
+ readIndexValue = ReadIndexValueFromIndices<GLubyte>;
+ break;
+ }
+
+ // Iterate over the cached index data and copy entries indicated into the emulated buffer.
+ for (GLuint i = 0; i < mIndexInfo.srcCount; i++)
+ {
+ GLuint idx = readIndexValue(ptr, i);
+ memcpy(curr, mMemoryBuffer.data() + (mAttributeStride * idx), mAttributeStride);
+ curr += mAttributeStride;
+ }
+
+ // 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;
+ bufferDesc.StructureByteStride = 0;
+ bufferDesc.Usage = D3D11_USAGE_DEFAULT;
+ bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
+ bufferDesc.CPUAccessFlags = 0;
+
+ 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");
+ }
+
+ 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;
+}
+
+bool Buffer11::EmulatedIndexedStorage::copyFromStorage(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(destOffset + size <= mMemoryBuffer.size());
+ memcpy(mMemoryBuffer.data() + destOffset, sourceData, size);
+ source->unmap();
+ return true;
+}
+
+gl::Error Buffer11::EmulatedIndexedStorage::resize(size_t size, bool preserveData)
+{
+ if (mMemoryBuffer.size() < size)
+ {
+ if (!mMemoryBuffer.resize(size))
+ {
+ return gl::Error(GL_OUT_OF_MEMORY, "Failed to resize EmulatedIndexedStorage");
+ }
+ mBufferSize = size;
+ }
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+uint8_t *Buffer11::EmulatedIndexedStorage::map(size_t offset, size_t length, GLbitfield access)
+{
+ ASSERT(!mMemoryBuffer.empty() && offset + length <= mMemoryBuffer.size());
+ return mMemoryBuffer.data() + offset;
+}
+
+void Buffer11::EmulatedIndexedStorage::unmap()
+{
+ // No-op
+}
+
Buffer11::PackStorage::PackStorage(Renderer11 *renderer)
- : BufferStorage(renderer, BUFFER_USAGE_PIXEL_PACK),
- mStagingTexture(NULL),
- mTextureFormat(DXGI_FORMAT_UNKNOWN),
- mQueuedPackCommand(NULL),
- mDataModified(false)
+ : BufferStorage(renderer, BUFFER_USAGE_PIXEL_PACK), mStagingTexture(), mDataModified(false)
{
}
Buffer11::PackStorage::~PackStorage()
{
- SafeRelease(mStagingTexture);
- SafeDelete(mQueuedPackCommand);
}
-bool Buffer11::PackStorage::copyFromStorage(BufferStorage *source, size_t sourceOffset,
- size_t size, size_t destOffset)
+bool Buffer11::PackStorage::copyFromStorage(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
@@ -925,7 +1294,7 @@ uint8_t *Buffer11::PackStorage::map(size_t offset, size_t length, GLbitfield acc
gl::Error error = flushQueuedPackCommand();
if (error.isError())
{
- return NULL;
+ return nullptr;
}
mDataModified = (mDataModified || (access & GL_MAP_WRITE_BIT) != 0);
@@ -938,7 +1307,8 @@ void Buffer11::PackStorage::unmap()
// No-op
}
-gl::Error Buffer11::PackStorage::packPixels(ID3D11Texture2D *srcTexure, UINT srcSubresource, const PackPixelsParams &params)
+gl::Error Buffer11::PackStorage::packPixels(const gl::FramebufferAttachment &readAttachment,
+ const PackPixelsParams &params)
{
gl::Error error = flushQueuedPackCommand();
if (error.isError())
@@ -946,54 +1316,37 @@ gl::Error Buffer11::PackStorage::packPixels(ID3D11Texture2D *srcTexure, UINT src
return error;
}
- mQueuedPackCommand = new PackPixelsParams(params);
-
- D3D11_TEXTURE2D_DESC textureDesc;
- srcTexure->GetDesc(&textureDesc);
-
- if (mStagingTexture != NULL &&
- (mTextureFormat != textureDesc.Format ||
- mTextureSize.width != params.area.width ||
- mTextureSize.height != params.area.height))
+ RenderTarget11 *renderTarget = nullptr;
+ error = readAttachment.getRenderTarget(&renderTarget);
+ if (error.isError())
{
- SafeRelease(mStagingTexture);
- mTextureSize.width = 0;
- mTextureSize.height = 0;
- mTextureFormat = DXGI_FORMAT_UNKNOWN;
+ return error;
}
- if (mStagingTexture == NULL)
+ ID3D11Resource *renderTargetResource = renderTarget->getTexture();
+ ASSERT(renderTargetResource);
+
+ 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() ||
+ mStagingTexture.getExtents() != srcTextureSize)
{
- ID3D11Device *device = mRenderer->getDevice();
- HRESULT hr;
-
- mTextureSize.width = params.area.width;
- mTextureSize.height = params.area.height;
- mTextureFormat = textureDesc.Format;
-
- D3D11_TEXTURE2D_DESC stagingDesc;
- stagingDesc.Width = params.area.width;
- stagingDesc.Height = params.area.height;
- stagingDesc.MipLevels = 1;
- stagingDesc.ArraySize = 1;
- stagingDesc.Format = mTextureFormat;
- stagingDesc.SampleDesc.Count = 1;
- stagingDesc.SampleDesc.Quality = 0;
- stagingDesc.Usage = D3D11_USAGE_STAGING;
- stagingDesc.BindFlags = 0;
- stagingDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
- stagingDesc.MiscFlags = 0;
-
- hr = device->CreateTexture2D(&stagingDesc, NULL, &mStagingTexture);
- if (FAILED(hr))
+ auto textureOrError =
+ CreateStagingTexture(srcTexture.getTextureType(), srcTexture.getFormat(),
+ srcTextureSize, mRenderer->getDevice());
+ if (textureOrError.isError())
{
- ASSERT(hr == E_OUTOFMEMORY);
- return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal staging texture.");
+ return textureOrError.getError();
}
+ mStagingTexture = std::move(textureOrError.getResult());
}
// ReadPixels from multisampled FBOs isn't supported in current GL
- ASSERT(textureDesc.SampleDesc.Count <= 1);
+ ASSERT(srcTexture.getSampleCount() <= 1);
ID3D11DeviceContext *immediateContext = mRenderer->getDeviceContext();
D3D11_BOX srcBox;
@@ -1001,11 +1354,18 @@ gl::Error Buffer11::PackStorage::packPixels(ID3D11Texture2D *srcTexure, UINT src
srcBox.right = params.area.x + params.area.width;
srcBox.top = params.area.y;
srcBox.bottom = params.area.y + params.area.height;
- srcBox.front = 0;
- srcBox.back = 1;
+
+ // Select the correct layer from a 3D attachment
+ srcBox.front = 0;
+ if (mStagingTexture.getTextureType() == GL_TEXTURE_3D)
+ {
+ srcBox.front = static_cast<UINT>(readAttachment.layer());
+ }
+ srcBox.back = srcBox.front + 1;
// Asynchronous copy
- immediateContext->CopySubresourceRegion(mStagingTexture, 0, 0, 0, 0, srcTexure, srcSubresource, &srcBox);
+ immediateContext->CopySubresourceRegion(mStagingTexture.getResource(), 0, 0, 0, 0,
+ srcTexture.getResource(), srcSubresource, &srcBox);
return gl::Error(GL_NO_ERROR);
}
@@ -1016,8 +1376,9 @@ gl::Error Buffer11::PackStorage::flushQueuedPackCommand()
if (mQueuedPackCommand)
{
- gl::Error error = mRenderer->packPixels(mStagingTexture, *mQueuedPackCommand, mMemoryBuffer.data());
- SafeDelete(mQueuedPackCommand);
+ gl::Error error =
+ mRenderer->packPixels(mStagingTexture, *mQueuedPackCommand, mMemoryBuffer.data());
+ mQueuedPackCommand.reset(nullptr);
if (error.isError())
{
return error;
@@ -1029,10 +1390,13 @@ gl::Error Buffer11::PackStorage::flushQueuedPackCommand()
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)
+bool Buffer11::SystemMemoryStorage::copyFromStorage(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);
@@ -1066,5 +1430,4 @@ void Buffer11::SystemMemoryStorage::unmap()
{
// No-op
}
-
}