michael@0: #include "precompiled.h" michael@0: // michael@0: // Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. michael@0: // Use of this source code is governed by a BSD-style license that can be michael@0: // found in the LICENSE file. michael@0: // michael@0: michael@0: // BufferStorage11.cpp Defines the BufferStorage11 class. michael@0: michael@0: #include "libGLESv2/renderer/BufferStorage11.h" michael@0: #include "libGLESv2/main.h" michael@0: #include "libGLESv2/renderer/Renderer11.h" michael@0: michael@0: namespace rx michael@0: { michael@0: michael@0: BufferStorage11::BufferStorage11(Renderer11 *renderer) michael@0: { michael@0: mRenderer = renderer; michael@0: michael@0: mStagingBuffer = NULL; michael@0: mStagingBufferSize = 0; michael@0: michael@0: mBuffer = NULL; michael@0: mBufferSize = 0; michael@0: michael@0: mSize = 0; michael@0: michael@0: mResolvedData = NULL; michael@0: mResolvedDataSize = 0; michael@0: mResolvedDataValid = false; michael@0: michael@0: mReadUsageCount = 0; michael@0: mWriteUsageCount = 0; michael@0: } michael@0: michael@0: BufferStorage11::~BufferStorage11() michael@0: { michael@0: if (mStagingBuffer) michael@0: { michael@0: mStagingBuffer->Release(); michael@0: mStagingBuffer = NULL; michael@0: } michael@0: michael@0: if (mBuffer) michael@0: { michael@0: mBuffer->Release(); michael@0: mBuffer = NULL; michael@0: } michael@0: michael@0: if (mResolvedData) michael@0: { michael@0: free(mResolvedData); michael@0: mResolvedData = NULL; michael@0: } michael@0: } michael@0: michael@0: BufferStorage11 *BufferStorage11::makeBufferStorage11(BufferStorage *bufferStorage) michael@0: { michael@0: ASSERT(HAS_DYNAMIC_TYPE(BufferStorage11*, bufferStorage)); michael@0: return static_cast(bufferStorage); michael@0: } michael@0: michael@0: void *BufferStorage11::getData() michael@0: { michael@0: if (!mResolvedDataValid) michael@0: { michael@0: ID3D11Device *device = mRenderer->getDevice(); michael@0: ID3D11DeviceContext *context = mRenderer->getDeviceContext(); michael@0: HRESULT result; michael@0: michael@0: if (!mStagingBuffer || mStagingBufferSize < mBufferSize) michael@0: { michael@0: if (mStagingBuffer) michael@0: { michael@0: mStagingBuffer->Release(); michael@0: mStagingBuffer = NULL; michael@0: mStagingBufferSize = 0; michael@0: } michael@0: michael@0: D3D11_BUFFER_DESC bufferDesc; michael@0: bufferDesc.ByteWidth = mSize; michael@0: bufferDesc.Usage = D3D11_USAGE_STAGING; michael@0: bufferDesc.BindFlags = 0; michael@0: bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE; michael@0: bufferDesc.MiscFlags = 0; michael@0: bufferDesc.StructureByteStride = 0; michael@0: michael@0: result = device->CreateBuffer(&bufferDesc, NULL, &mStagingBuffer); michael@0: if (FAILED(result)) michael@0: { michael@0: return gl::error(GL_OUT_OF_MEMORY, (void*)NULL); michael@0: } michael@0: michael@0: mStagingBufferSize = bufferDesc.ByteWidth; michael@0: } michael@0: michael@0: if (!mResolvedData || mResolvedDataSize < mBufferSize) michael@0: { michael@0: free(mResolvedData); michael@0: mResolvedData = malloc(mSize); michael@0: mResolvedDataSize = mSize; michael@0: } michael@0: michael@0: D3D11_BOX srcBox; michael@0: srcBox.left = 0; michael@0: srcBox.right = mSize; michael@0: srcBox.top = 0; michael@0: srcBox.bottom = 1; michael@0: srcBox.front = 0; michael@0: srcBox.back = 1; michael@0: michael@0: context->CopySubresourceRegion(mStagingBuffer, 0, 0, 0, 0, mBuffer, 0, &srcBox); michael@0: michael@0: D3D11_MAPPED_SUBRESOURCE mappedResource; michael@0: result = context->Map(mStagingBuffer, 0, D3D11_MAP_READ, 0, &mappedResource); michael@0: if (FAILED(result)) michael@0: { michael@0: return gl::error(GL_OUT_OF_MEMORY, (void*)NULL); michael@0: } michael@0: michael@0: memcpy(mResolvedData, mappedResource.pData, mSize); michael@0: michael@0: context->Unmap(mStagingBuffer, 0); michael@0: michael@0: mResolvedDataValid = true; michael@0: } michael@0: michael@0: mReadUsageCount = 0; michael@0: michael@0: return mResolvedData; michael@0: } michael@0: michael@0: void BufferStorage11::setData(const void* data, unsigned int size, unsigned int offset) michael@0: { michael@0: ID3D11Device *device = mRenderer->getDevice(); michael@0: ID3D11DeviceContext *context = mRenderer->getDeviceContext(); michael@0: HRESULT result; michael@0: michael@0: unsigned int requiredBufferSize = size + offset; michael@0: unsigned int requiredStagingSize = size; michael@0: bool directInitialization = offset == 0 && (!mBuffer || mBufferSize < size + offset); michael@0: michael@0: if (!directInitialization) michael@0: { michael@0: if (!mStagingBuffer || mStagingBufferSize < requiredStagingSize) michael@0: { michael@0: if (mStagingBuffer) michael@0: { michael@0: mStagingBuffer->Release(); michael@0: mStagingBuffer = NULL; michael@0: mStagingBufferSize = 0; michael@0: } michael@0: michael@0: D3D11_BUFFER_DESC bufferDesc; michael@0: bufferDesc.ByteWidth = size; michael@0: bufferDesc.Usage = D3D11_USAGE_STAGING; michael@0: bufferDesc.BindFlags = 0; michael@0: bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE; michael@0: bufferDesc.MiscFlags = 0; michael@0: bufferDesc.StructureByteStride = 0; michael@0: michael@0: if (data) michael@0: { michael@0: D3D11_SUBRESOURCE_DATA initialData; michael@0: initialData.pSysMem = data; michael@0: initialData.SysMemPitch = size; michael@0: initialData.SysMemSlicePitch = 0; michael@0: michael@0: result = device->CreateBuffer(&bufferDesc, &initialData, &mStagingBuffer); michael@0: } michael@0: else michael@0: { michael@0: result = device->CreateBuffer(&bufferDesc, NULL, &mStagingBuffer); michael@0: } michael@0: michael@0: if (FAILED(result)) michael@0: { michael@0: return gl::error(GL_OUT_OF_MEMORY); michael@0: } michael@0: michael@0: mStagingBufferSize = size; michael@0: } michael@0: else if (data) michael@0: { michael@0: D3D11_MAPPED_SUBRESOURCE mappedResource; michael@0: result = context->Map(mStagingBuffer, 0, D3D11_MAP_WRITE, 0, &mappedResource); michael@0: if (FAILED(result)) michael@0: { michael@0: return gl::error(GL_OUT_OF_MEMORY); michael@0: } michael@0: michael@0: memcpy(mappedResource.pData, data, size); michael@0: michael@0: context->Unmap(mStagingBuffer, 0); michael@0: } michael@0: } michael@0: michael@0: if (!mBuffer || mBufferSize < size + offset) michael@0: { michael@0: D3D11_BUFFER_DESC bufferDesc; michael@0: bufferDesc.ByteWidth = requiredBufferSize; michael@0: bufferDesc.Usage = D3D11_USAGE_DEFAULT; michael@0: bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER | D3D11_BIND_INDEX_BUFFER; michael@0: bufferDesc.CPUAccessFlags = 0; michael@0: bufferDesc.MiscFlags = 0; michael@0: bufferDesc.StructureByteStride = 0; michael@0: michael@0: if (directInitialization) michael@0: { michael@0: // Since the data will fill the entire buffer (being larger than the initial size and having michael@0: // no offset), the buffer can be initialized with the data so no staging buffer is required michael@0: michael@0: // No longer need the old buffer michael@0: if (mBuffer) michael@0: { michael@0: mBuffer->Release(); michael@0: mBuffer = NULL; michael@0: mBufferSize = 0; michael@0: } michael@0: michael@0: if (data) michael@0: { michael@0: D3D11_SUBRESOURCE_DATA initialData; michael@0: initialData.pSysMem = data; michael@0: initialData.SysMemPitch = size; michael@0: initialData.SysMemSlicePitch = 0; michael@0: michael@0: result = device->CreateBuffer(&bufferDesc, &initialData, &mBuffer); michael@0: } michael@0: else michael@0: { michael@0: result = device->CreateBuffer(&bufferDesc, NULL, &mBuffer); michael@0: } michael@0: michael@0: if (FAILED(result)) michael@0: { michael@0: return gl::error(GL_OUT_OF_MEMORY); michael@0: } michael@0: } michael@0: else if (mBuffer && offset > 0) michael@0: { michael@0: // If offset is greater than zero and the buffer is non-null, need to preserve the data from michael@0: // the old buffer up to offset michael@0: ID3D11Buffer *newBuffer = NULL; michael@0: michael@0: result = device->CreateBuffer(&bufferDesc, NULL, &newBuffer); michael@0: if (FAILED(result)) michael@0: { michael@0: return gl::error(GL_OUT_OF_MEMORY); michael@0: } michael@0: michael@0: D3D11_BOX srcBox; michael@0: srcBox.left = 0; michael@0: srcBox.right = std::min(offset, mBufferSize); michael@0: srcBox.top = 0; michael@0: srcBox.bottom = 1; michael@0: srcBox.front = 0; michael@0: srcBox.back = 1; michael@0: michael@0: context->CopySubresourceRegion(newBuffer, 0, 0, 0, 0, mBuffer, 0, &srcBox); michael@0: michael@0: mBuffer->Release(); michael@0: mBuffer = newBuffer; michael@0: } michael@0: else michael@0: { michael@0: // Simple case, nothing needs to be copied from the old buffer to the new one, just create michael@0: // a new buffer michael@0: michael@0: // No longer need the old buffer michael@0: if (mBuffer) michael@0: { michael@0: mBuffer->Release(); michael@0: mBuffer = NULL; michael@0: mBufferSize = 0; michael@0: } michael@0: michael@0: // Create a new buffer for data storage michael@0: result = device->CreateBuffer(&bufferDesc, NULL, &mBuffer); michael@0: if (FAILED(result)) michael@0: { michael@0: return gl::error(GL_OUT_OF_MEMORY); michael@0: } michael@0: } michael@0: michael@0: updateSerial(); michael@0: mBufferSize = bufferDesc.ByteWidth; michael@0: } michael@0: michael@0: if (!directInitialization) michael@0: { michael@0: ASSERT(mStagingBuffer && mStagingBufferSize >= requiredStagingSize); michael@0: michael@0: // Data is already put into the staging buffer, copy it over to the data buffer michael@0: D3D11_BOX srcBox; michael@0: srcBox.left = 0; michael@0: srcBox.right = size; michael@0: srcBox.top = 0; michael@0: srcBox.bottom = 1; michael@0: srcBox.front = 0; michael@0: srcBox.back = 1; michael@0: michael@0: context->CopySubresourceRegion(mBuffer, 0, offset, 0, 0, mStagingBuffer, 0, &srcBox); michael@0: } michael@0: michael@0: mSize = std::max(mSize, offset + size); michael@0: michael@0: mWriteUsageCount = 0; michael@0: michael@0: mResolvedDataValid = false; michael@0: } michael@0: michael@0: void BufferStorage11::clear() michael@0: { michael@0: mResolvedDataValid = false; michael@0: mSize = 0; michael@0: } michael@0: michael@0: unsigned int BufferStorage11::getSize() const michael@0: { michael@0: return mSize; michael@0: } michael@0: michael@0: bool BufferStorage11::supportsDirectBinding() const michael@0: { michael@0: return true; michael@0: } michael@0: michael@0: void BufferStorage11::markBufferUsage() michael@0: { michael@0: mReadUsageCount++; michael@0: mWriteUsageCount++; michael@0: michael@0: static const unsigned int usageLimit = 5; michael@0: michael@0: if (mReadUsageCount > usageLimit && mResolvedData) michael@0: { michael@0: free(mResolvedData); michael@0: mResolvedData = NULL; michael@0: mResolvedDataSize = 0; michael@0: mResolvedDataValid = false; michael@0: } michael@0: michael@0: if (mReadUsageCount > usageLimit && mWriteUsageCount > usageLimit && mStagingBuffer) michael@0: { michael@0: mStagingBuffer->Release(); michael@0: mStagingBuffer = NULL; michael@0: mStagingBufferSize = 0; michael@0: } michael@0: } michael@0: michael@0: ID3D11Buffer *BufferStorage11::getBuffer() const michael@0: { michael@0: return mBuffer; michael@0: } michael@0: michael@0: }