Commit ecc8b6f4 by Geoff Lang

Refactor BufferStorage11.

In preparation for transform feedback, BufferStorage11 needs to be able to handle a non-staging buffer being updated. Each D3D11 buffer now has an incrementing data revision associated with it so the most up-to-date buffer is always known. Staging buffers are now represented like any other DirectBuffer. Change-Id: I6e881867cb2bd02d600213d08cce3ebba316c525 Reviewed-on: https://chromium-review.googlesource.com/184395Tested-by: 's avatarGeoff Lang <geofflang@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarShannon Woods <shannonwoods@chromium.org>
parent e53c98ba
......@@ -16,32 +16,16 @@ namespace rx
{
BufferStorage11::BufferStorage11(Renderer11 *renderer)
: mRenderer(renderer),
mResolvedDataRevision(0),
mReadUsageCount(0),
mWriteUsageCount(0),
mSize(0)
{
mRenderer = renderer;
mStagingBuffer = NULL;
mStagingBufferSize = 0;
mSize = 0;
mResolvedData = NULL;
mResolvedDataSize = 0;
mResolvedDataValid = false;
mReadUsageCount = 0;
mWriteUsageCount = 0;
}
BufferStorage11::~BufferStorage11()
{
SafeRelease(mStagingBuffer);
if (mResolvedData)
{
free(mResolvedData);
mResolvedData = NULL;
}
for (auto it = mDirectBuffers.begin(); it != mDirectBuffers.end(); it++)
{
SafeDelete(it->second);
......@@ -56,109 +40,52 @@ BufferStorage11 *BufferStorage11::makeBufferStorage11(BufferStorage *bufferStora
void *BufferStorage11::getData()
{
ASSERT(mStagingBuffer);
if (!mResolvedDataValid)
DirectBufferStorage11 *stagingBuffer = getStorage(BUFFER_USAGE_STAGING);
if (stagingBuffer->getDataRevision() > mResolvedDataRevision)
{
ID3D11Device *device = mRenderer->getDevice();
ID3D11DeviceContext *context = mRenderer->getDeviceContext();
HRESULT result;
if (!mResolvedData || mResolvedDataSize < mStagingBufferSize)
if (stagingBuffer->getSize() > mResolvedData.size())
{
free(mResolvedData);
mResolvedData = malloc(mSize);
mResolvedDataSize = mSize;
mResolvedData.resize(stagingBuffer->getSize());
}
ID3D11DeviceContext *context = mRenderer->getDeviceContext();
D3D11_MAPPED_SUBRESOURCE mappedResource;
result = context->Map(mStagingBuffer, 0, D3D11_MAP_READ, 0, &mappedResource);
HRESULT result = context->Map(stagingBuffer->getD3DBuffer(), 0, D3D11_MAP_READ, 0, &mappedResource);
if (FAILED(result))
{
return gl::error(GL_OUT_OF_MEMORY, (void*)NULL);
}
memcpy(mResolvedData, mappedResource.pData, mSize);
memcpy(mResolvedData.data(), mappedResource.pData, stagingBuffer->getSize());
context->Unmap(mStagingBuffer, 0);
context->Unmap(stagingBuffer->getD3DBuffer(), 0);
mResolvedDataValid = true;
mResolvedDataRevision = stagingBuffer->getDataRevision();
}
mReadUsageCount = 0;
return mResolvedData;
return mResolvedData.data();
}
void BufferStorage11::setData(const void* data, unsigned int size, unsigned int offset)
{
ID3D11Device *device = mRenderer->getDevice();
ID3D11DeviceContext *context = mRenderer->getDeviceContext();
HRESULT result;
const unsigned int requiredStagingBufferSize = size + offset;
const bool createStagingBuffer = !mStagingBuffer || mStagingBufferSize < requiredStagingBufferSize;
DirectBufferStorage11 *stagingBuffer = getStorage(BUFFER_USAGE_STAGING);
if (createStagingBuffer)
// Explicitly resize the staging buffer, preserving data if the new data will not
// completely fill the buffer
size_t requiredSize = size + offset;
if (stagingBuffer->getSize() < requiredSize)
{
D3D11_BUFFER_DESC bufferDesc;
bufferDesc.ByteWidth = requiredStagingBufferSize;
bufferDesc.Usage = D3D11_USAGE_STAGING;
bufferDesc.BindFlags = 0;
bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
bufferDesc.MiscFlags = 0;
bufferDesc.StructureByteStride = 0;
HRESULT result;
ID3D11Device *device = mRenderer->getDevice();
ID3D11DeviceContext *context = mRenderer->getDeviceContext();
ID3D11Buffer *newStagingBuffer;
if (data && offset == 0)
{
D3D11_SUBRESOURCE_DATA initialData;
initialData.pSysMem = data;
initialData.SysMemPitch = requiredStagingBufferSize;
initialData.SysMemSlicePitch = 0;
result = device->CreateBuffer(&bufferDesc, &initialData, &newStagingBuffer);
}
else
{
result = device->CreateBuffer(&bufferDesc, NULL, &newStagingBuffer);
}
if (FAILED(result))
{
mStagingBufferSize = 0;
return gl::error(GL_OUT_OF_MEMORY);
}
mStagingBufferSize = requiredStagingBufferSize;
if (mStagingBuffer && offset > 0)
{
// If offset is greater than zero and the buffer is non-null, need to preserve the data from
// the old buffer up to offset
D3D11_BOX srcBox;
srcBox.left = 0;
srcBox.right = std::min(offset, requiredStagingBufferSize);
srcBox.top = 0;
srcBox.bottom = 1;
srcBox.front = 0;
srcBox.back = 1;
context->CopySubresourceRegion(newStagingBuffer, 0, 0, 0, 0, mStagingBuffer, 0, &srcBox);
}
SafeRelease(mStagingBuffer);
mStagingBuffer = newStagingBuffer;
bool preserveData = (offset > 0);
stagingBuffer->resize(requiredSize, preserveData);
}
if (data && (offset != 0 || !createStagingBuffer))
if (data)
{
ID3D11DeviceContext *context = mRenderer->getDeviceContext();
D3D11_MAPPED_SUBRESOURCE mappedResource;
result = context->Map(mStagingBuffer, 0, D3D11_MAP_WRITE, 0, &mappedResource);
HRESULT result = context->Map(stagingBuffer->getD3DBuffer(), 0, D3D11_MAP_WRITE, 0, &mappedResource);
if (FAILED(result))
{
return gl::error(GL_OUT_OF_MEMORY);
......@@ -167,45 +94,41 @@ void BufferStorage11::setData(const void* data, unsigned int size, unsigned int
unsigned char *offsetBufferPointer = reinterpret_cast<unsigned char *>(mappedResource.pData) + offset;
memcpy(offsetBufferPointer, data, size);
context->Unmap(mStagingBuffer, 0);
}
for (auto it = mDirectBuffers.begin(); it != mDirectBuffers.end(); it++)
{
it->second->markDirty();
context->Unmap(stagingBuffer->getD3DBuffer(), 0);
}
mSize = std::max(mSize, requiredStagingBufferSize);
stagingBuffer->setDataRevision(stagingBuffer->getDataRevision() + 1);
mWriteUsageCount = 0;
mResolvedDataValid = false;
mSize = std::max(mSize, requiredSize);
}
void BufferStorage11::copyData(BufferStorage* sourceStorage, unsigned int size,
unsigned int sourceOffset, unsigned int destOffset)
{
BufferStorage11* source = makeBufferStorage11(sourceStorage);
if (source)
BufferStorage11* sourceStorage11 = makeBufferStorage11(sourceStorage);
if (sourceStorage11)
{
ID3D11DeviceContext *context = mRenderer->getDeviceContext();
DirectBufferStorage11 *dest = getLatestStorage();
if (!dest)
{
dest = getStorage(BUFFER_USAGE_STAGING);
}
D3D11_BOX srcBox;
srcBox.left = sourceOffset;
srcBox.right = sourceOffset + size;
srcBox.top = 0;
srcBox.bottom = 1;
srcBox.front = 0;
srcBox.back = 1;
DirectBufferStorage11 *source = sourceStorage11->getLatestStorage();
if (source && dest)
{
dest->copyFromStorage(source, sourceOffset, size, destOffset);
dest->setDataRevision(dest->getDataRevision() + 1);
}
ASSERT(mStagingBuffer && source->mStagingBuffer);
context->CopySubresourceRegion(mStagingBuffer, 0, destOffset, 0, 0, source->mStagingBuffer, 0, &srcBox);
mSize = std::max(mSize, destOffset + size);
}
}
void BufferStorage11::clear()
{
mResolvedDataValid = false;
mSize = 0;
mResolvedDataRevision = 0;
}
unsigned int BufferStorage11::getSize() const
......@@ -225,54 +148,23 @@ void BufferStorage11::markBufferUsage()
const unsigned int usageLimit = 5;
if (mReadUsageCount > usageLimit && mResolvedData)
if (mReadUsageCount > usageLimit && mResolvedData.size() > 0)
{
free(mResolvedData);
mResolvedData = NULL;
mResolvedDataSize = 0;
mResolvedDataValid = false;
mResolvedData.resize(0);
mResolvedDataRevision = 0;
}
}
ID3D11Buffer *BufferStorage11::getBuffer(BufferUsage usage)
{
markBufferUsage();
DirectBufferStorage11 *directBuffer = NULL;
auto directBufferIt = mDirectBuffers.find(usage);
if (directBufferIt != mDirectBuffers.end())
{
directBuffer = directBufferIt->second;
}
if (directBuffer)
{
if (directBuffer->isDirty())
{
// if updateFromStagingBuffer returns true, the D3D buffer has been recreated
// and we should update our serial
if (directBuffer->updateFromStagingBuffer(mStagingBuffer, mSize, 0))
{
updateSerial();
}
}
}
else
{
// buffer is not allocated, create it
directBuffer = new DirectBufferStorage11(mRenderer, usage);
directBuffer->updateFromStagingBuffer(mStagingBuffer, mSize, 0);
mDirectBuffers.insert(std::make_pair(usage, directBuffer));
updateSerial();
}
return directBuffer->getD3DBuffer();
return getStorage(usage)->getD3DBuffer();
}
ID3D11ShaderResourceView *BufferStorage11::getSRV(DXGI_FORMAT srvFormat)
{
ID3D11Buffer *buffer = getBuffer(BUFFER_USAGE_PIXEL);
DirectBufferStorage11 *storage = getStorage(BUFFER_USAGE_PIXEL_UNPACK);
ID3D11Buffer *buffer = storage->getD3DBuffer();
auto bufferSRVIt = mBufferResourceViews.find(srvFormat);
......@@ -306,12 +198,62 @@ ID3D11ShaderResourceView *BufferStorage11::getSRV(DXGI_FORMAT srvFormat)
return bufferSRV;
}
DirectBufferStorage11 *BufferStorage11::getStorage(BufferUsage usage)
{
DirectBufferStorage11 *directBuffer = NULL;
auto directBufferIt = mDirectBuffers.find(usage);
if (directBufferIt != mDirectBuffers.end())
{
directBuffer = directBufferIt->second;
}
if (!directBuffer)
{
// buffer is not allocated, create it
directBuffer = new DirectBufferStorage11(mRenderer, usage);
mDirectBuffers.insert(std::make_pair(usage, directBuffer));
}
DirectBufferStorage11 *latestBuffer = getLatestStorage();
if (latestBuffer && latestBuffer->getDataRevision() > directBuffer->getDataRevision())
{
// if copyFromStorage returns true, the D3D buffer has been recreated
// and we should update our serial
if (directBuffer->copyFromStorage(latestBuffer, 0, latestBuffer->getSize(), 0))
{
updateSerial();
}
directBuffer->setDataRevision(latestBuffer->getDataRevision());
}
return directBuffer;
}
DirectBufferStorage11 *BufferStorage11::getLatestStorage() const
{
// Even though we iterate over all the direct buffers, it is expected that only
// 1 or 2 will be present.
DirectBufferStorage11 *latestStorage = NULL;
DataRevision latestRevision = 0;
for (auto it = mDirectBuffers.begin(); it != mDirectBuffers.end(); it++)
{
DirectBufferStorage11 *storage = it->second;
if (storage->getDataRevision() > latestRevision)
{
latestStorage = storage;
latestRevision = storage->getDataRevision();
}
}
return latestStorage;
}
DirectBufferStorage11::DirectBufferStorage11(Renderer11 *renderer, BufferUsage usage)
: mRenderer(renderer),
mUsage(usage),
mRevision(0),
mDirectBuffer(NULL),
mBufferSize(0),
mDirty(false)
mBufferSize(0)
{
}
......@@ -326,54 +268,69 @@ BufferUsage DirectBufferStorage11::getUsage() const
}
// Returns true if it recreates the direct buffer
bool DirectBufferStorage11::updateFromStagingBuffer(ID3D11Buffer *stagingBuffer, size_t size, size_t offset)
bool DirectBufferStorage11::copyFromStorage(DirectBufferStorage11 *source, size_t sourceOffset, size_t size, size_t destOffset)
{
ID3D11Device *device = mRenderer->getDevice();
ID3D11DeviceContext *context = mRenderer->getDeviceContext();
// unused for now
ASSERT(offset == 0);
unsigned int requiredBufferSize = size + offset;
bool createBuffer = !mDirectBuffer || mBufferSize < requiredBufferSize;
size_t requiredSize = sourceOffset + size;
bool createBuffer = !mDirectBuffer || mBufferSize < requiredSize;
// (Re)initialize D3D buffer if needed
if (createBuffer)
{
D3D11_BUFFER_DESC bufferDesc;
fillBufferDesc(&bufferDesc, mRenderer, mUsage, requiredBufferSize);
ID3D11Buffer *newBuffer;
HRESULT result = device->CreateBuffer(&bufferDesc, NULL, &newBuffer);
if (FAILED(result))
{
return gl::error(GL_OUT_OF_MEMORY, false);
}
// No longer need the old buffer
SafeRelease(mDirectBuffer);
mDirectBuffer = newBuffer;
mBufferSize = bufferDesc.ByteWidth;
bool preserveData = (destOffset > 0);
resize(source->getSize(), preserveData);
}
// Copy data via staging buffer
D3D11_BOX srcBox;
srcBox.left = 0;
srcBox.right = size;
srcBox.left = sourceOffset;
srcBox.right = sourceOffset + size;
srcBox.top = 0;
srcBox.bottom = 1;
srcBox.front = 0;
srcBox.back = 1;
context->CopySubresourceRegion(mDirectBuffer, 0, offset, 0, 0, stagingBuffer, 0, &srcBox);
mDirty = false;
context->CopySubresourceRegion(mDirectBuffer, 0, destOffset, 0, 0, source->getD3DBuffer(), 0, &srcBox);
return createBuffer;
}
void DirectBufferStorage11::resize(size_t size, bool preserveData)
{
ID3D11Device *device = mRenderer->getDevice();
ID3D11DeviceContext *context = mRenderer->getDeviceContext();
D3D11_BUFFER_DESC bufferDesc;
fillBufferDesc(&bufferDesc, mRenderer, mUsage, size);
ID3D11Buffer *newBuffer;
HRESULT result = device->CreateBuffer(&bufferDesc, NULL, &newBuffer);
if (FAILED(result))
{
return gl::error(GL_OUT_OF_MEMORY);
}
if (mDirectBuffer && preserveData)
{
D3D11_BOX srcBox;
srcBox.left = 0;
srcBox.right = size;
srcBox.top = 0;
srcBox.bottom = 1;
srcBox.front = 0;
srcBox.back = 1;
context->CopySubresourceRegion(newBuffer, 0, 0, 0, 0, mDirectBuffer, 0, &srcBox);
}
// No longer need the old buffer
SafeRelease(mDirectBuffer);
mDirectBuffer = newBuffer;
mBufferSize = bufferDesc.ByteWidth;
}
void DirectBufferStorage11::fillBufferDesc(D3D11_BUFFER_DESC* bufferDesc, Renderer *renderer, BufferUsage usage, unsigned int bufferSize)
{
bufferDesc->ByteWidth = bufferSize;
......@@ -382,6 +339,12 @@ void DirectBufferStorage11::fillBufferDesc(D3D11_BUFFER_DESC* bufferDesc, Render
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_VERTEX:
bufferDesc->Usage = D3D11_USAGE_DEFAULT;
bufferDesc->BindFlags = D3D11_BIND_VERTEX_BUFFER;
......@@ -394,7 +357,7 @@ void DirectBufferStorage11::fillBufferDesc(D3D11_BUFFER_DESC* bufferDesc, Render
bufferDesc->CPUAccessFlags = 0;
break;
case BUFFER_USAGE_PIXEL:
case BUFFER_USAGE_PIXEL_UNPACK:
bufferDesc->Usage = D3D11_USAGE_DEFAULT;
bufferDesc->BindFlags = D3D11_BIND_SHADER_RESOURCE;
bufferDesc->CPUAccessFlags = 0;
......
......@@ -19,12 +19,15 @@ class DirectBufferStorage11;
enum BufferUsage
{
BUFFER_USAGE_VERTEX,
BUFFER_USAGE_INDEX,
BUFFER_USAGE_PIXEL,
BUFFER_USAGE_UNIFORM,
BUFFER_USAGE_STAGING = 0,
BUFFER_USAGE_VERTEX = 1,
BUFFER_USAGE_INDEX = 2,
BUFFER_USAGE_PIXEL_UNPACK = 3,
BUFFER_USAGE_UNIFORM = 4,
};
typedef size_t DataRevision;
class BufferStorage11 : public BufferStorage
{
public:
......@@ -47,30 +50,30 @@ class BufferStorage11 : public BufferStorage
private:
Renderer11 *mRenderer;
ID3D11Buffer *mStagingBuffer;
unsigned int mStagingBufferSize;
std::map<BufferUsage, DirectBufferStorage11*> mDirectBuffers;
typedef std::pair<ID3D11Buffer *, ID3D11ShaderResourceView *> BufferSRVPair;
std::map<DXGI_FORMAT, BufferSRVPair> mBufferResourceViews;
unsigned int mSize;
void *mResolvedData;
unsigned int mResolvedDataSize;
bool mResolvedDataValid;
std::vector<unsigned char> mResolvedData;
DataRevision mResolvedDataRevision;
unsigned int mReadUsageCount;
unsigned int mWriteUsageCount;
size_t mSize;
void markBufferUsage();
DirectBufferStorage11 *getStorage(BufferUsage usage);
DirectBufferStorage11 *getLatestStorage() const;
};
// Each instance of BufferStorageD3DBuffer11 is specialized for a class of D3D binding points
// - vertex/index buffers
// - vertex/transform feedback buffers
// - index buffers
// - pixel unpack buffers
// - uniform buffers
// - (possibly in the future, transform feedback buffers)
class DirectBufferStorage11
{
public:
......@@ -78,18 +81,22 @@ class DirectBufferStorage11
~DirectBufferStorage11();
BufferUsage getUsage() const;
bool updateFromStagingBuffer(ID3D11Buffer *stagingBuffer, size_t size, size_t offset);
ID3D11Buffer *getD3DBuffer() const { return mDirectBuffer; }
size_t getSize() const {return mBufferSize; }
bool copyFromStorage(DirectBufferStorage11 *source, size_t sourceOffset, size_t size, size_t destOffset);
void resize(size_t size, bool preserveData);
ID3D11Buffer *getD3DBuffer() { return mDirectBuffer; }
bool isDirty() const { return mDirty; }
void markDirty() { mDirty = true; }
DataRevision getDataRevision() const { return mRevision; }
void setDataRevision(DataRevision rev) { mRevision = rev; }
private:
Renderer11 *mRenderer;
const BufferUsage mUsage;
DataRevision mRevision;
ID3D11Buffer *mDirectBuffer;
size_t mBufferSize;
bool mDirty;
static void fillBufferDesc(D3D11_BUFFER_DESC* bufferDesc, Renderer *renderer, BufferUsage usage, unsigned int bufferSize);
};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment