Redesign BufferStorage11 to support simultaneously managing constant buffers and…

Redesign BufferStorage11 to support simultaneously managing constant buffers and vertex/index buffers. TRAC #22852 Signed-off-by: Geoff Lang Signed-off-by: Nicolas Capens Author: Jamie Madill git-svn-id: https://angleproject.googlecode.com/svn/branches/es3proto@2287 736b8ea6-26fd-11df-bfd4-992fa37f6226
parent 06d4e84f
......@@ -21,9 +21,6 @@ BufferStorage11::BufferStorage11(Renderer11 *renderer)
mStagingBuffer = NULL;
mStagingBufferSize = 0;
mBuffer = NULL;
mBufferSize = 0;
mSize = 0;
mResolvedData = NULL;
......@@ -36,23 +33,18 @@ BufferStorage11::BufferStorage11(Renderer11 *renderer)
BufferStorage11::~BufferStorage11()
{
if (mStagingBuffer)
{
mStagingBuffer->Release();
mStagingBuffer = NULL;
}
if (mBuffer)
{
mBuffer->Release();
mBuffer = NULL;
}
SafeRelease(mStagingBuffer);
if (mResolvedData)
{
free(mResolvedData);
mResolvedData = NULL;
}
for (DirectBufferList::iterator it = mDirectBuffers.begin(); it != mDirectBuffers.end(); it++)
{
delete *it;
}
}
BufferStorage11 *BufferStorage11::makeBufferStorage11(BufferStorage *bufferStorage)
......@@ -63,55 +55,21 @@ BufferStorage11 *BufferStorage11::makeBufferStorage11(BufferStorage *bufferStora
void *BufferStorage11::getData()
{
ASSERT(mStagingBuffer);
if (!mResolvedDataValid)
{
ID3D11Device *device = mRenderer->getDevice();
ID3D11DeviceContext *context = mRenderer->getDeviceContext();
HRESULT result;
if (!mStagingBuffer || mStagingBufferSize < mBufferSize)
{
if (mStagingBuffer)
{
mStagingBuffer->Release();
mStagingBuffer = NULL;
mStagingBufferSize = 0;
}
D3D11_BUFFER_DESC bufferDesc;
bufferDesc.ByteWidth = mSize;
bufferDesc.Usage = D3D11_USAGE_STAGING;
bufferDesc.BindFlags = 0;
bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
bufferDesc.MiscFlags = 0;
bufferDesc.StructureByteStride = 0;
result = device->CreateBuffer(&bufferDesc, NULL, &mStagingBuffer);
if (FAILED(result))
{
return gl::error(GL_OUT_OF_MEMORY, (void*)NULL);
}
mStagingBufferSize = bufferDesc.ByteWidth;
}
if (!mResolvedData || mResolvedDataSize < mBufferSize)
if (!mResolvedData || mResolvedDataSize < mStagingBufferSize)
{
free(mResolvedData);
mResolvedData = malloc(mSize);
mResolvedDataSize = mSize;
}
D3D11_BOX srcBox;
srcBox.left = 0;
srcBox.right = mSize;
srcBox.top = 0;
srcBox.bottom = 1;
srcBox.front = 0;
srcBox.back = 1;
context->CopySubresourceRegion(mStagingBuffer, 0, 0, 0, 0, mBuffer, 0, &srcBox);
D3D11_MAPPED_SUBRESOURCE mappedResource;
result = context->Map(mStagingBuffer, 0, D3D11_MAP_READ, 0, &mappedResource);
if (FAILED(result))
......@@ -137,175 +95,86 @@ void BufferStorage11::setData(const void* data, unsigned int size, unsigned int
ID3D11DeviceContext *context = mRenderer->getDeviceContext();
HRESULT result;
unsigned int requiredBufferSize = size + offset;
unsigned int requiredStagingSize = size;
bool directInitialization = offset == 0 && (!mBuffer || mBufferSize < size + offset);
const unsigned int requiredStagingBufferSize = size + offset;
const bool createStagingBuffer = !mStagingBuffer || mStagingBufferSize < requiredStagingBufferSize;
if (!directInitialization)
if (createStagingBuffer)
{
if (!mStagingBuffer || mStagingBufferSize < requiredStagingSize)
{
if (mStagingBuffer)
{
mStagingBuffer->Release();
mStagingBuffer = NULL;
mStagingBufferSize = 0;
}
D3D11_BUFFER_DESC bufferDesc;
bufferDesc.ByteWidth = size;
bufferDesc.Usage = D3D11_USAGE_STAGING;
bufferDesc.BindFlags = 0;
bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
bufferDesc.MiscFlags = 0;
bufferDesc.StructureByteStride = 0;
if (data)
{
D3D11_SUBRESOURCE_DATA initialData;
initialData.pSysMem = data;
initialData.SysMemPitch = size;
initialData.SysMemSlicePitch = 0;
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;
result = device->CreateBuffer(&bufferDesc, &initialData, &mStagingBuffer);
}
else
{
result = device->CreateBuffer(&bufferDesc, NULL, &mStagingBuffer);
}
HRESULT result;
ID3D11Device *device = mRenderer->getDevice();
ID3D11DeviceContext *context = mRenderer->getDeviceContext();
ID3D11Buffer *newStagingBuffer;
if (FAILED(result))
{
return gl::error(GL_OUT_OF_MEMORY);
}
if (data && offset == 0)
{
D3D11_SUBRESOURCE_DATA initialData;
initialData.pSysMem = data;
initialData.SysMemPitch = requiredStagingBufferSize;
initialData.SysMemSlicePitch = 0;
mStagingBufferSize = size;
result = device->CreateBuffer(&bufferDesc, &initialData, &newStagingBuffer);
}
else
{
D3D11_MAPPED_SUBRESOURCE mappedResource;
result = context->Map(mStagingBuffer, 0, D3D11_MAP_WRITE, 0, &mappedResource);
if (FAILED(result))
{
return gl::error(GL_OUT_OF_MEMORY);
}
memcpy(mappedResource.pData, data, size);
context->Unmap(mStagingBuffer, 0);
result = device->CreateBuffer(&bufferDesc, NULL, &newStagingBuffer);
}
}
if (!mBuffer || mBufferSize < size + offset)
{
D3D11_BUFFER_DESC bufferDesc;
bufferDesc.ByteWidth = requiredBufferSize;
bufferDesc.Usage = D3D11_USAGE_DEFAULT;
bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER | D3D11_BIND_INDEX_BUFFER;
bufferDesc.CPUAccessFlags = 0;
bufferDesc.MiscFlags = 0;
bufferDesc.StructureByteStride = 0;
if (directInitialization)
if (FAILED(result))
{
// Since the data will fill the entire buffer (being larger than the initial size and having
// no offset), the buffer can be initialized with the data so no staging buffer is required
// No longer need the old buffer
if (mBuffer)
{
mBuffer->Release();
mBuffer = NULL;
mBufferSize = 0;
}
if (data)
{
D3D11_SUBRESOURCE_DATA initialData;
initialData.pSysMem = data;
initialData.SysMemPitch = size;
initialData.SysMemSlicePitch = 0;
mStagingBufferSize = 0;
return gl::error(GL_OUT_OF_MEMORY);
}
result = device->CreateBuffer(&bufferDesc, &initialData, &mBuffer);
}
else
{
result = device->CreateBuffer(&bufferDesc, NULL, &mBuffer);
}
mStagingBufferSize = requiredStagingBufferSize;
if (FAILED(result))
{
return gl::error(GL_OUT_OF_MEMORY);
}
}
else if (mBuffer && offset > 0)
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
ID3D11Buffer *newBuffer = NULL;
result = device->CreateBuffer(&bufferDesc, NULL, &newBuffer);
if (FAILED(result))
{
return gl::error(GL_OUT_OF_MEMORY);
}
D3D11_BOX srcBox;
srcBox.left = 0;
srcBox.right = std::min(offset, mBufferSize);
srcBox.right = std::min(offset, requiredStagingBufferSize);
srcBox.top = 0;
srcBox.bottom = 1;
srcBox.front = 0;
srcBox.back = 1;
context->CopySubresourceRegion(newBuffer, 0, 0, 0, 0, mBuffer, 0, &srcBox);
mBuffer->Release();
mBuffer = newBuffer;
}
else
{
// Simple case, nothing needs to be copied from the old buffer to the new one, just create
// a new buffer
// No longer need the old buffer
if (mBuffer)
{
mBuffer->Release();
mBuffer = NULL;
mBufferSize = 0;
}
// Create a new buffer for data storage
result = device->CreateBuffer(&bufferDesc, NULL, &mBuffer);
if (FAILED(result))
{
return gl::error(GL_OUT_OF_MEMORY);
}
context->CopySubresourceRegion(newStagingBuffer, 0, 0, 0, 0, mStagingBuffer, 0, &srcBox);
}
updateSerial();
mBufferSize = bufferDesc.ByteWidth;
SafeRelease(mStagingBuffer);
mStagingBuffer = newStagingBuffer;
}
if (!directInitialization)
if (offset != 0 || !createStagingBuffer)
{
ASSERT(mStagingBuffer && mStagingBufferSize >= requiredStagingSize);
D3D11_MAPPED_SUBRESOURCE mappedResource;
result = context->Map(mStagingBuffer, 0, D3D11_MAP_WRITE, 0, &mappedResource);
if (FAILED(result))
{
return gl::error(GL_OUT_OF_MEMORY);
}
// Data is already put into the staging buffer, copy it over to the data buffer
D3D11_BOX srcBox;
srcBox.left = 0;
srcBox.right = size;
srcBox.top = 0;
srcBox.bottom = 1;
srcBox.front = 0;
srcBox.back = 1;
unsigned char *offsetBufferPointer = reinterpret_cast<unsigned char *>(mappedResource.pData) + offset;
memcpy(offsetBufferPointer, data, size);
context->CopySubresourceRegion(mBuffer, 0, offset, 0, 0, mStagingBuffer, 0, &srcBox);
context->Unmap(mStagingBuffer, 0);
}
mSize = std::max(mSize, offset + size);
for (DirectBufferList::iterator it = mDirectBuffers.begin(); it != mDirectBuffers.end(); it++)
{
(*it)->markDirty();
}
mSize = std::max(mSize, requiredStagingBufferSize);
mWriteUsageCount = 0;
mResolvedDataValid = false;
......@@ -327,7 +196,8 @@ void BufferStorage11::copyData(BufferStorage* sourceStorage, unsigned int size,
srcBox.front = 0;
srcBox.back = 1;
context->CopySubresourceRegion(mBuffer, 0, destOffset, 0, 0, source->mBuffer, 0, &srcBox);
ASSERT(mStagingBuffer && source->mStagingBuffer);
context->CopySubresourceRegion(mStagingBuffer, 0, destOffset, 0, 0, source->mStagingBuffer, 0, &srcBox);
}
}
......@@ -361,18 +231,137 @@ void BufferStorage11::markBufferUsage()
mResolvedDataSize = 0;
mResolvedDataValid = false;
}
}
if (mReadUsageCount > usageLimit && mWriteUsageCount > usageLimit && mStagingBuffer)
ID3D11Buffer *BufferStorage11::getBuffer(GLenum usage)
{
for (DirectBufferList::iterator it = mDirectBuffers.begin(); it != mDirectBuffers.end(); it++)
{
mStagingBuffer->Release();
mStagingBuffer = NULL;
mStagingBufferSize = 0;
DirectBufferStorage11 *directBuffer = *it;
if (directBuffer->hasTarget(usage))
{
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();
}
}
return directBuffer->getD3DBuffer();
}
}
// buffer is not allocated, create it
DirectBufferStorage11 *directBuffer = new DirectBufferStorage11(mRenderer, usage);
directBuffer->updateFromStagingBuffer(mStagingBuffer, mSize, 0);
mDirectBuffers.push_back(directBuffer);
updateSerial();
return directBuffer->getD3DBuffer();
}
ID3D11Buffer *BufferStorage11::getBuffer() const
DirectBufferStorage11::DirectBufferStorage11(Renderer11 *renderer, const GLenum target)
: mRenderer(renderer)
, mTarget(target)
, mDirectBuffer(NULL)
, mBufferSize(0)
, mDirty(false)
{
return mBuffer;
}
DirectBufferStorage11::~DirectBufferStorage11()
{
SafeRelease(mDirectBuffer);
}
bool DirectBufferStorage11::hasTarget(const GLenum target) const
{
switch (target)
{
case GL_ELEMENT_ARRAY_BUFFER:
case GL_ARRAY_BUFFER:
return mTarget == GL_ELEMENT_ARRAY_BUFFER || mTarget == GL_ARRAY_BUFFER;
default:
return target == mTarget;
}
}
// Returns true if it recreates the direct buffer
bool DirectBufferStorage11::updateFromStagingBuffer(ID3D11Buffer *stagingBuffer, const size_t size, const size_t offset)
{
ID3D11Device *device = mRenderer->getDevice();
ID3D11DeviceContext *context = mRenderer->getDeviceContext();
// unused for now
ASSERT(offset == 0);
unsigned int requiredBufferSize = size + offset;
bool createBuffer = !mDirectBuffer || mBufferSize < requiredBufferSize;
// (Re)initialize D3D buffer if needed
if (createBuffer)
{
D3D11_BUFFER_DESC bufferDesc;
fillBufferDesc(&bufferDesc, 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;
}
else
{
mBufferSize = requiredBufferSize;
}
// Copy data via staging buffer
D3D11_BOX srcBox;
srcBox.left = 0;
srcBox.right = 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;
return createBuffer;
}
void DirectBufferStorage11::fillBufferDesc(D3D11_BUFFER_DESC* bufferDesc, unsigned int bufferSize)
{
bufferDesc->ByteWidth = bufferSize;
bufferDesc->MiscFlags = 0;
bufferDesc->StructureByteStride = 0;
switch (mTarget)
{
case GL_ELEMENT_ARRAY_BUFFER:
case GL_ARRAY_BUFFER:
bufferDesc->Usage = D3D11_USAGE_DEFAULT;
bufferDesc->BindFlags = D3D11_BIND_INDEX_BUFFER | D3D11_BIND_VERTEX_BUFFER;
bufferDesc->CPUAccessFlags = 0;
break;
default:
UNREACHABLE();
break;
}
}
}
......@@ -14,6 +14,7 @@
namespace rx
{
class Renderer11;
class DirectBufferStorage11;
class BufferStorage11 : public BufferStorage
{
......@@ -32,7 +33,7 @@ class BufferStorage11 : public BufferStorage
virtual bool supportsDirectBinding() const;
virtual void markBufferUsage();
ID3D11Buffer *getBuffer() const;
ID3D11Buffer *getBuffer(GLenum usage);
private:
Renderer11 *mRenderer;
......@@ -40,9 +41,8 @@ class BufferStorage11 : public BufferStorage
ID3D11Buffer *mStagingBuffer;
unsigned int mStagingBufferSize;
ID3D11Buffer *mBuffer;
unsigned int mBufferSize;
typedef std::vector<DirectBufferStorage11*> DirectBufferList;
DirectBufferList mDirectBuffers;
unsigned int mSize;
void *mResolvedData;
......@@ -53,6 +53,33 @@ class BufferStorage11 : public BufferStorage
unsigned int mWriteUsageCount;
};
// Each instance of BufferStorageD3DBuffer11 is specialized for a class of D3D binding points
// - vertex/index buffers
// - uniform buffers
// - (possibly in the future, transform feedback buffers)
class DirectBufferStorage11
{
public:
DirectBufferStorage11(Renderer11 *renderer, const GLenum target);
~DirectBufferStorage11();
bool hasTarget(const GLenum target) const;
bool updateFromStagingBuffer(ID3D11Buffer *stagingBuffer, const size_t size, const size_t offset);
ID3D11Buffer *getD3DBuffer() { return mDirectBuffer; }
bool isDirty() const { return mDirty; }
void markDirty() { mDirty = true; }
private:
Renderer11 *mRenderer;
const GLenum mTarget;
ID3D11Buffer *mDirectBuffer;
size_t mBufferSize;
bool mDirty;
void fillBufferDesc(D3D11_BUFFER_DESC* bufferDesc, unsigned int bufferSize);
};
}
#endif // LIBGLESV2_RENDERER_BUFFERSTORAGE11_H_
......@@ -94,7 +94,7 @@ GLenum InputLayoutCache::applyVertexBuffers(TranslatedAttribute attributes[gl::M
ilKey.elements[ilKey.elementCount].InstanceDataStepRate = attributes[i].divisor;
ilKey.elementCount++;
vertexBuffers[i] = bufferStorage ? bufferStorage->getBuffer() : vertexBuffer->getBuffer();
vertexBuffers[i] = bufferStorage ? bufferStorage->getBuffer(GL_ARRAY_BUFFER) : vertexBuffer->getBuffer();
vertexStrides[i] = attributes[i].stride;
vertexOffsets[i] = attributes[i].offset;
}
......
......@@ -1043,7 +1043,7 @@ GLenum Renderer11::applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementAr
BufferStorage11 *storage = BufferStorage11::makeBufferStorage11(indexInfo->storage);
IndexBuffer11* indexBuffer = IndexBuffer11::makeIndexBuffer11(indexInfo->indexBuffer);
mDeviceContext->IASetIndexBuffer(storage->getBuffer(), indexBuffer->getIndexFormat(), indexInfo->startOffset);
mDeviceContext->IASetIndexBuffer(storage->getBuffer(GL_ELEMENT_ARRAY_BUFFER), indexBuffer->getIndexFormat(), indexInfo->startOffset);
mAppliedIBSerial = 0;
mAppliedStorageIBSerial = storage->getSerial();
......
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