diff options
Diffstat (limited to 'src/3rdparty/angle/src/libGLESv2/renderer/d3d11/BufferStorage11.cpp')
-rw-r--r-- | src/3rdparty/angle/src/libGLESv2/renderer/d3d11/BufferStorage11.cpp | 366 |
1 files changed, 366 insertions, 0 deletions
diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/BufferStorage11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/BufferStorage11.cpp new file mode 100644 index 0000000000..31d5b8b886 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/BufferStorage11.cpp @@ -0,0 +1,366 @@ +#include "precompiled.h" +// +// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// BufferStorage11.cpp Defines the BufferStorage11 class. + +#include "libGLESv2/renderer/d3d11/BufferStorage11.h" +#include "libGLESv2/main.h" +#include "libGLESv2/renderer/d3d11/Renderer11.h" + +namespace rx +{ + +BufferStorage11::BufferStorage11(Renderer11 *renderer) +{ + 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); + } +} + +BufferStorage11 *BufferStorage11::makeBufferStorage11(BufferStorage *bufferStorage) +{ + ASSERT(HAS_DYNAMIC_TYPE(BufferStorage11*, bufferStorage)); + return static_cast<BufferStorage11*>(bufferStorage); +} + +void *BufferStorage11::getData() +{ + ASSERT(mStagingBuffer); + + if (!mResolvedDataValid) + { + ID3D11Device *device = mRenderer->getDevice(); + ID3D11DeviceContext *context = mRenderer->getDeviceContext(); + HRESULT result; + + if (!mResolvedData || mResolvedDataSize < mStagingBufferSize) + { + free(mResolvedData); + mResolvedData = malloc(mSize); + mResolvedDataSize = mSize; + } + + D3D11_MAPPED_SUBRESOURCE mappedResource; + result = context->Map(mStagingBuffer, 0, D3D11_MAP_READ, 0, &mappedResource); + if (FAILED(result)) + { + return gl::error(GL_OUT_OF_MEMORY, (void*)NULL); + } + + memcpy(mResolvedData, mappedResource.pData, mSize); + + context->Unmap(mStagingBuffer, 0); + + mResolvedDataValid = true; + } + + mReadUsageCount = 0; + + return mResolvedData; +} + +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; + + if (createStagingBuffer) + { + 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; + } + + if (data && (offset != 0 || !createStagingBuffer)) + { + D3D11_MAPPED_SUBRESOURCE mappedResource; + result = context->Map(mStagingBuffer, 0, D3D11_MAP_WRITE, 0, &mappedResource); + if (FAILED(result)) + { + return gl::error(GL_OUT_OF_MEMORY); + } + + 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(); + } + + mSize = std::max(mSize, requiredStagingBufferSize); + mWriteUsageCount = 0; + + mResolvedDataValid = false; +} + +void BufferStorage11::copyData(BufferStorage* sourceStorage, unsigned int size, + unsigned int sourceOffset, unsigned int destOffset) +{ + BufferStorage11* source = makeBufferStorage11(sourceStorage); + if (source) + { + ID3D11DeviceContext *context = mRenderer->getDeviceContext(); + + D3D11_BOX srcBox; + srcBox.left = sourceOffset; + srcBox.right = sourceOffset + size; + srcBox.top = 0; + srcBox.bottom = 1; + srcBox.front = 0; + srcBox.back = 1; + + ASSERT(mStagingBuffer && source->mStagingBuffer); + context->CopySubresourceRegion(mStagingBuffer, 0, destOffset, 0, 0, source->mStagingBuffer, 0, &srcBox); + } +} + +void BufferStorage11::clear() +{ + mResolvedDataValid = false; + mSize = 0; +} + +unsigned int BufferStorage11::getSize() const +{ + return mSize; +} + +bool BufferStorage11::supportsDirectBinding() const +{ + return true; +} + +void BufferStorage11::markBufferUsage() +{ + mReadUsageCount++; + mWriteUsageCount++; + + const unsigned int usageLimit = 5; + + if (mReadUsageCount > usageLimit && mResolvedData) + { + free(mResolvedData); + mResolvedData = NULL; + mResolvedDataSize = 0; + mResolvedDataValid = false; + } +} + +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(); +} + +DirectBufferStorage11::DirectBufferStorage11(Renderer11 *renderer, BufferUsage usage) + : mRenderer(renderer), + mUsage(usage), + mDirectBuffer(NULL), + mBufferSize(0), + mDirty(false) +{ +} + +DirectBufferStorage11::~DirectBufferStorage11() +{ + SafeRelease(mDirectBuffer); +} + +BufferUsage DirectBufferStorage11::getUsage() const +{ + return mUsage; +} + +// Returns true if it recreates the direct buffer +bool DirectBufferStorage11::updateFromStagingBuffer(ID3D11Buffer *stagingBuffer, size_t size, 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, 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; + } + + // 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, Renderer *renderer, BufferUsage usage, unsigned int bufferSize) +{ + bufferDesc->ByteWidth = bufferSize; + bufferDesc->MiscFlags = 0; + bufferDesc->StructureByteStride = 0; + + switch (usage) + { + case BUFFER_USAGE_VERTEX: + bufferDesc->Usage = D3D11_USAGE_DEFAULT; + bufferDesc->BindFlags = D3D11_BIND_VERTEX_BUFFER; + bufferDesc->CPUAccessFlags = 0; + break; + + case BUFFER_USAGE_INDEX: + bufferDesc->Usage = D3D11_USAGE_DEFAULT; + bufferDesc->BindFlags = D3D11_BIND_INDEX_BUFFER; + bufferDesc->CPUAccessFlags = 0; + break; + + default: + UNREACHABLE(); + } +} + +} |