// // 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. // // VertexBuffer11.cpp: Defines the D3D11 VertexBuffer implementation. #include "libANGLE/renderer/d3d/d3d11/VertexBuffer11.h" #include "libANGLE/renderer/d3d/d3d11/Buffer11.h" #include "libANGLE/renderer/d3d/d3d11/Renderer11.h" #include "libANGLE/renderer/d3d/d3d11/formatutils11.h" #include "libANGLE/Buffer.h" #include "libANGLE/VertexAttribute.h" namespace rx { VertexBuffer11::VertexBuffer11(Renderer11 *const renderer) : mRenderer(renderer) { mBuffer = NULL; mBufferSize = 0; mDynamicUsage = false; mMappedResourceData = NULL; } VertexBuffer11::~VertexBuffer11() { ASSERT(mMappedResourceData == NULL); SafeRelease(mBuffer); } gl::Error VertexBuffer11::initialize(unsigned int size, bool dynamicUsage) { SafeRelease(mBuffer); updateSerial(); if (size > 0) { ID3D11Device* dxDevice = mRenderer->getDevice(); D3D11_BUFFER_DESC bufferDesc; bufferDesc.ByteWidth = size; bufferDesc.Usage = D3D11_USAGE_DYNAMIC; bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; bufferDesc.MiscFlags = 0; bufferDesc.StructureByteStride = 0; HRESULT result = dxDevice->CreateBuffer(&bufferDesc, NULL, &mBuffer); if (FAILED(result)) { return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal vertex buffer of size, %lu.", size); } } mBufferSize = size; mDynamicUsage = dynamicUsage; return gl::Error(GL_NO_ERROR); } VertexBuffer11 *VertexBuffer11::makeVertexBuffer11(VertexBuffer *vetexBuffer) { ASSERT(HAS_DYNAMIC_TYPE(VertexBuffer11*, vetexBuffer)); return static_cast(vetexBuffer); } gl::Error VertexBuffer11::mapResource() { if (mMappedResourceData == NULL) { ID3D11DeviceContext *dxContext = mRenderer->getDeviceContext(); D3D11_MAPPED_SUBRESOURCE mappedResource; HRESULT result = dxContext->Map(mBuffer, 0, D3D11_MAP_WRITE_NO_OVERWRITE, 0, &mappedResource); if (FAILED(result)) { return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal vertex buffer, HRESULT: 0x%08x.", result); } mMappedResourceData = reinterpret_cast(mappedResource.pData); } return gl::Error(GL_NO_ERROR); } void VertexBuffer11::hintUnmapResource() { if (mMappedResourceData != NULL) { ID3D11DeviceContext *dxContext = mRenderer->getDeviceContext(); dxContext->Unmap(mBuffer, 0); mMappedResourceData = NULL; } } gl::Error VertexBuffer11::storeVertexAttributes(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData ¤tValue, GLint start, GLsizei count, GLsizei instances, unsigned int offset) { if (!mBuffer) { return gl::Error(GL_OUT_OF_MEMORY, "Internal vertex buffer is not initialized."); } gl::Buffer *buffer = attrib.buffer.get(); int inputStride = ComputeVertexAttributeStride(attrib); // This will map the resource if it isn't already mapped. gl::Error error = mapResource(); if (error.isError()) { return error; } uint8_t *output = mMappedResourceData + offset; const uint8_t *input = NULL; if (attrib.enabled) { if (buffer) { BufferD3D *storage = GetImplAs(buffer); error = storage->getData(&input); if (error.isError()) { return error; } input += static_cast(attrib.offset); } else { input = static_cast(attrib.pointer); } } else { input = reinterpret_cast(currentValue.FloatValues); } if (instances == 0 || attrib.divisor == 0) { input += inputStride * start; } gl::VertexFormat vertexFormat(attrib, currentValue.Type); const d3d11::VertexFormat &vertexFormatInfo = d3d11::GetVertexFormatInfo(vertexFormat, mRenderer->getFeatureLevel()); ASSERT(vertexFormatInfo.copyFunction != NULL); vertexFormatInfo.copyFunction(input, inputStride, count, output); return gl::Error(GL_NO_ERROR); } gl::Error VertexBuffer11::getSpaceRequired(const gl::VertexAttribute &attrib, GLsizei count, GLsizei instances, unsigned int *outSpaceRequired) const { unsigned int elementCount = 0; if (attrib.enabled) { if (instances == 0 || attrib.divisor == 0) { elementCount = count; } else { // Round up to divisor, if possible elementCount = UnsignedCeilDivide(static_cast(instances), attrib.divisor); } gl::VertexFormat vertexFormat(attrib); const d3d11::VertexFormat &vertexFormatInfo = d3d11::GetVertexFormatInfo(vertexFormat, mRenderer->getFeatureLevel()); const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(vertexFormatInfo.nativeFormat); unsigned int elementSize = dxgiFormatInfo.pixelBytes; if (elementSize <= std::numeric_limits::max() / elementCount) { if (outSpaceRequired) { *outSpaceRequired = elementSize * elementCount; } return gl::Error(GL_NO_ERROR); } else { return gl::Error(GL_OUT_OF_MEMORY, "New vertex buffer size would result in an overflow."); } } else { const unsigned int elementSize = 4; if (outSpaceRequired) { *outSpaceRequired = elementSize * 4; } return gl::Error(GL_NO_ERROR); } } unsigned int VertexBuffer11::getBufferSize() const { return mBufferSize; } gl::Error VertexBuffer11::setBufferSize(unsigned int size) { if (size > mBufferSize) { return initialize(size, mDynamicUsage); } else { return gl::Error(GL_NO_ERROR); } } gl::Error VertexBuffer11::discard() { if (!mBuffer) { return gl::Error(GL_OUT_OF_MEMORY, "Internal vertex buffer is not initialized."); } ID3D11DeviceContext *dxContext = mRenderer->getDeviceContext(); D3D11_MAPPED_SUBRESOURCE mappedResource; HRESULT result = dxContext->Map(mBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); if (FAILED(result)) { return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal buffer for discarding, HRESULT: 0x%08x", result); } dxContext->Unmap(mBuffer, 0); return gl::Error(GL_NO_ERROR); } ID3D11Buffer *VertexBuffer11::getBuffer() const { return mBuffer; } }