| // |
| // Copyright 2002 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. |
| // |
| |
| // VertexBuffer.cpp: Defines the abstract VertexBuffer class and VertexBufferInterface |
| // class with derivations, classes that perform graphics API agnostic vertex buffer operations. |
| |
| #include "libANGLE/renderer/d3d/VertexBuffer.h" |
| |
| #include "common/mathutil.h" |
| #include "libANGLE/Context.h" |
| #include "libANGLE/VertexAttribute.h" |
| #include "libANGLE/renderer/d3d/BufferD3D.h" |
| #include "libANGLE/renderer/d3d/ContextD3D.h" |
| |
| namespace rx |
| { |
| |
| // VertexBuffer Implementation |
| unsigned int VertexBuffer::mNextSerial = 1; |
| |
| VertexBuffer::VertexBuffer() : mRefCount(1) |
| { |
| updateSerial(); |
| } |
| |
| VertexBuffer::~VertexBuffer() {} |
| |
| void VertexBuffer::updateSerial() |
| { |
| mSerial = mNextSerial++; |
| } |
| |
| unsigned int VertexBuffer::getSerial() const |
| { |
| return mSerial; |
| } |
| |
| void VertexBuffer::addRef() |
| { |
| mRefCount++; |
| } |
| |
| void VertexBuffer::release() |
| { |
| ASSERT(mRefCount > 0); |
| mRefCount--; |
| |
| if (mRefCount == 0) |
| { |
| delete this; |
| } |
| } |
| |
| // VertexBufferInterface Implementation |
| VertexBufferInterface::VertexBufferInterface(BufferFactoryD3D *factory, bool dynamic) |
| : mFactory(factory), mVertexBuffer(factory->createVertexBuffer()), mDynamic(dynamic) |
| {} |
| |
| VertexBufferInterface::~VertexBufferInterface() |
| { |
| if (mVertexBuffer) |
| { |
| mVertexBuffer->release(); |
| mVertexBuffer = nullptr; |
| } |
| } |
| |
| unsigned int VertexBufferInterface::getSerial() const |
| { |
| ASSERT(mVertexBuffer); |
| return mVertexBuffer->getSerial(); |
| } |
| |
| unsigned int VertexBufferInterface::getBufferSize() const |
| { |
| ASSERT(mVertexBuffer); |
| return mVertexBuffer->getBufferSize(); |
| } |
| |
| angle::Result VertexBufferInterface::setBufferSize(const gl::Context *context, unsigned int size) |
| { |
| ASSERT(mVertexBuffer); |
| if (mVertexBuffer->getBufferSize() == 0) |
| { |
| return mVertexBuffer->initialize(context, size, mDynamic); |
| } |
| |
| return mVertexBuffer->setBufferSize(context, size); |
| } |
| |
| angle::Result VertexBufferInterface::getSpaceRequired(const gl::Context *context, |
| const gl::VertexAttribute &attrib, |
| const gl::VertexBinding &binding, |
| size_t count, |
| GLsizei instances, |
| unsigned int *spaceInBytesOut) const |
| { |
| unsigned int spaceRequired = 0; |
| ANGLE_TRY(mFactory->getVertexSpaceRequired(context, attrib, binding, count, instances, |
| &spaceRequired)); |
| |
| // Align to 16-byte boundary |
| unsigned int alignedSpaceRequired = roundUpPow2(spaceRequired, 16u); |
| ANGLE_CHECK_GL_ALLOC(GetImplAs<ContextD3D>(context), alignedSpaceRequired >= spaceRequired); |
| |
| *spaceInBytesOut = alignedSpaceRequired; |
| return angle::Result::Continue; |
| } |
| |
| angle::Result VertexBufferInterface::discard(const gl::Context *context) |
| { |
| ASSERT(mVertexBuffer); |
| return mVertexBuffer->discard(context); |
| } |
| |
| VertexBuffer *VertexBufferInterface::getVertexBuffer() const |
| { |
| ASSERT(mVertexBuffer); |
| return mVertexBuffer; |
| } |
| |
| // StreamingVertexBufferInterface Implementation |
| StreamingVertexBufferInterface::StreamingVertexBufferInterface(BufferFactoryD3D *factory) |
| : VertexBufferInterface(factory, true), mWritePosition(0), mReservedSpace(0) |
| {} |
| |
| angle::Result StreamingVertexBufferInterface::initialize(const gl::Context *context, |
| std::size_t initialSize) |
| { |
| return setBufferSize(context, static_cast<unsigned int>(initialSize)); |
| } |
| |
| void StreamingVertexBufferInterface::reset() |
| { |
| if (mVertexBuffer) |
| { |
| mVertexBuffer->release(); |
| mVertexBuffer = mFactory->createVertexBuffer(); |
| } |
| } |
| |
| StreamingVertexBufferInterface::~StreamingVertexBufferInterface() {} |
| |
| angle::Result StreamingVertexBufferInterface::reserveSpace(const gl::Context *context, |
| unsigned int size) |
| { |
| unsigned int curBufferSize = getBufferSize(); |
| if (size > curBufferSize) |
| { |
| ANGLE_TRY(setBufferSize(context, std::max(size, 3 * curBufferSize / 2))); |
| mWritePosition = 0; |
| } |
| else if (mWritePosition + size > curBufferSize) |
| { |
| ANGLE_TRY(discard(context)); |
| mWritePosition = 0; |
| } |
| |
| mReservedSpace = size; |
| return angle::Result::Continue; |
| } |
| |
| angle::Result StreamingVertexBufferInterface::storeDynamicAttribute( |
| const gl::Context *context, |
| const gl::VertexAttribute &attrib, |
| const gl::VertexBinding &binding, |
| gl::VertexAttribType currentValueType, |
| GLint start, |
| size_t count, |
| GLsizei instances, |
| unsigned int *outStreamOffset, |
| const uint8_t *sourceData) |
| { |
| unsigned int spaceRequired = 0; |
| ANGLE_TRY(getSpaceRequired(context, attrib, binding, count, instances, &spaceRequired)); |
| |
| // Protect against integer overflow |
| angle::CheckedNumeric<unsigned int> checkedPosition(mWritePosition); |
| checkedPosition += spaceRequired; |
| ANGLE_CHECK_GL_ALLOC(GetImplAs<ContextD3D>(context), checkedPosition.IsValid()); |
| |
| mReservedSpace = 0; |
| |
| ANGLE_TRY(mVertexBuffer->storeVertexAttributes(context, attrib, binding, currentValueType, |
| start, count, instances, mWritePosition, |
| sourceData)); |
| |
| if (outStreamOffset) |
| { |
| *outStreamOffset = mWritePosition; |
| } |
| |
| mWritePosition += spaceRequired; |
| |
| return angle::Result::Continue; |
| } |
| |
| angle::Result StreamingVertexBufferInterface::reserveVertexSpace(const gl::Context *context, |
| const gl::VertexAttribute &attrib, |
| const gl::VertexBinding &binding, |
| size_t count, |
| GLsizei instances) |
| { |
| unsigned int requiredSpace = 0; |
| ANGLE_TRY(mFactory->getVertexSpaceRequired(context, attrib, binding, count, instances, |
| &requiredSpace)); |
| |
| // Align to 16-byte boundary |
| auto alignedRequiredSpace = rx::CheckedRoundUp(requiredSpace, 16u); |
| alignedRequiredSpace += mReservedSpace; |
| |
| // Protect against integer overflow |
| ANGLE_CHECK_GL_ALLOC(GetImplAs<ContextD3D>(context), alignedRequiredSpace.IsValid()); |
| |
| ANGLE_TRY(reserveSpace(context, alignedRequiredSpace.ValueOrDie())); |
| |
| return angle::Result::Continue; |
| } |
| |
| // StaticVertexBufferInterface Implementation |
| StaticVertexBufferInterface::AttributeSignature::AttributeSignature() |
| : formatID(angle::FormatID::NONE), stride(0), offset(0) |
| {} |
| |
| bool StaticVertexBufferInterface::AttributeSignature::matchesAttribute( |
| const gl::VertexAttribute &attrib, |
| const gl::VertexBinding &binding) const |
| { |
| size_t attribStride = ComputeVertexAttributeStride(attrib, binding); |
| |
| if (formatID != attrib.format->id || static_cast<GLuint>(stride) != attribStride) |
| { |
| return false; |
| } |
| |
| size_t attribOffset = |
| (static_cast<size_t>(ComputeVertexAttributeOffset(attrib, binding)) % attribStride); |
| return (offset == attribOffset); |
| } |
| |
| void StaticVertexBufferInterface::AttributeSignature::set(const gl::VertexAttribute &attrib, |
| const gl::VertexBinding &binding) |
| { |
| formatID = attrib.format->id; |
| offset = stride = static_cast<GLuint>(ComputeVertexAttributeStride(attrib, binding)); |
| offset = static_cast<size_t>(ComputeVertexAttributeOffset(attrib, binding)) % |
| ComputeVertexAttributeStride(attrib, binding); |
| } |
| |
| StaticVertexBufferInterface::StaticVertexBufferInterface(BufferFactoryD3D *factory) |
| : VertexBufferInterface(factory, false) |
| {} |
| |
| StaticVertexBufferInterface::~StaticVertexBufferInterface() {} |
| |
| bool StaticVertexBufferInterface::matchesAttribute(const gl::VertexAttribute &attrib, |
| const gl::VertexBinding &binding) const |
| { |
| return mSignature.matchesAttribute(attrib, binding); |
| } |
| |
| void StaticVertexBufferInterface::setAttribute(const gl::VertexAttribute &attrib, |
| const gl::VertexBinding &binding) |
| { |
| return mSignature.set(attrib, binding); |
| } |
| |
| angle::Result StaticVertexBufferInterface::storeStaticAttribute(const gl::Context *context, |
| const gl::VertexAttribute &attrib, |
| const gl::VertexBinding &binding, |
| GLint start, |
| GLsizei count, |
| GLsizei instances, |
| const uint8_t *sourceData) |
| { |
| unsigned int spaceRequired = 0; |
| ANGLE_TRY(getSpaceRequired(context, attrib, binding, count, instances, &spaceRequired)); |
| ANGLE_TRY(setBufferSize(context, spaceRequired)); |
| |
| ASSERT(attrib.enabled); |
| ANGLE_TRY(mVertexBuffer->storeVertexAttributes(context, attrib, binding, |
| gl::VertexAttribType::InvalidEnum, start, count, |
| instances, 0, sourceData)); |
| |
| mSignature.set(attrib, binding); |
| mVertexBuffer->hintUnmapResource(); |
| return angle::Result::Continue; |
| } |
| |
| } // namespace rx |