michael@0: #include "precompiled.h" michael@0: // michael@0: // Copyright (c) 2002-2012 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: // VertexBuffer.cpp: Defines the abstract VertexBuffer class and VertexBufferInterface michael@0: // class with derivations, classes that perform graphics API agnostic vertex buffer operations. michael@0: michael@0: #include "libGLESv2/renderer/VertexBuffer.h" michael@0: #include "libGLESv2/renderer/Renderer.h" michael@0: #include "libGLESv2/Context.h" michael@0: michael@0: namespace rx michael@0: { michael@0: michael@0: unsigned int VertexBuffer::mNextSerial = 1; michael@0: michael@0: VertexBuffer::VertexBuffer() michael@0: { michael@0: updateSerial(); michael@0: } michael@0: michael@0: VertexBuffer::~VertexBuffer() michael@0: { michael@0: } michael@0: michael@0: void VertexBuffer::updateSerial() michael@0: { michael@0: mSerial = mNextSerial++; michael@0: } michael@0: michael@0: unsigned int VertexBuffer::getSerial() const michael@0: { michael@0: return mSerial; michael@0: } michael@0: michael@0: VertexBufferInterface::VertexBufferInterface(rx::Renderer *renderer, bool dynamic) : mRenderer(renderer) michael@0: { michael@0: mDynamic = dynamic; michael@0: mWritePosition = 0; michael@0: mReservedSpace = 0; michael@0: michael@0: mVertexBuffer = renderer->createVertexBuffer(); michael@0: } michael@0: michael@0: VertexBufferInterface::~VertexBufferInterface() michael@0: { michael@0: delete mVertexBuffer; michael@0: } michael@0: michael@0: unsigned int VertexBufferInterface::getSerial() const michael@0: { michael@0: return mVertexBuffer->getSerial(); michael@0: } michael@0: michael@0: unsigned int VertexBufferInterface::getBufferSize() const michael@0: { michael@0: return mVertexBuffer->getBufferSize(); michael@0: } michael@0: michael@0: bool VertexBufferInterface::setBufferSize(unsigned int size) michael@0: { michael@0: if (mVertexBuffer->getBufferSize() == 0) michael@0: { michael@0: return mVertexBuffer->initialize(size, mDynamic); michael@0: } michael@0: else michael@0: { michael@0: return mVertexBuffer->setBufferSize(size); michael@0: } michael@0: } michael@0: michael@0: unsigned int VertexBufferInterface::getWritePosition() const michael@0: { michael@0: return mWritePosition; michael@0: } michael@0: michael@0: void VertexBufferInterface::setWritePosition(unsigned int writePosition) michael@0: { michael@0: mWritePosition = writePosition; michael@0: } michael@0: michael@0: bool VertexBufferInterface::discard() michael@0: { michael@0: return mVertexBuffer->discard(); michael@0: } michael@0: michael@0: bool VertexBufferInterface::storeVertexAttributes(const gl::VertexAttribute &attrib, GLint start, GLsizei count, GLsizei instances, michael@0: unsigned int *outStreamOffset) michael@0: { michael@0: unsigned int spaceRequired; michael@0: if (!mVertexBuffer->getSpaceRequired(attrib, count, instances, &spaceRequired)) michael@0: { michael@0: return false; michael@0: } michael@0: michael@0: if (mWritePosition + spaceRequired < mWritePosition) michael@0: { michael@0: return false; michael@0: } michael@0: michael@0: if (!reserveSpace(mReservedSpace)) michael@0: { michael@0: return false; michael@0: } michael@0: mReservedSpace = 0; michael@0: michael@0: if (!mVertexBuffer->storeVertexAttributes(attrib, start, count, instances, mWritePosition)) michael@0: { michael@0: return false; michael@0: } michael@0: michael@0: if (outStreamOffset) michael@0: { michael@0: *outStreamOffset = mWritePosition; michael@0: } michael@0: michael@0: mWritePosition += spaceRequired; michael@0: michael@0: return true; michael@0: } michael@0: michael@0: bool VertexBufferInterface::storeRawData(const void* data, unsigned int size, unsigned int *outStreamOffset) michael@0: { michael@0: if (mWritePosition + size < mWritePosition) michael@0: { michael@0: return false; michael@0: } michael@0: michael@0: if (!reserveSpace(mReservedSpace)) michael@0: { michael@0: return false; michael@0: } michael@0: mReservedSpace = 0; michael@0: michael@0: if (!mVertexBuffer->storeRawData(data, size, mWritePosition)) michael@0: { michael@0: return false; michael@0: } michael@0: michael@0: if (outStreamOffset) michael@0: { michael@0: *outStreamOffset = mWritePosition; michael@0: } michael@0: michael@0: mWritePosition += size; michael@0: michael@0: return true; michael@0: } michael@0: michael@0: bool VertexBufferInterface::reserveVertexSpace(const gl::VertexAttribute &attribute, GLsizei count, GLsizei instances) michael@0: { michael@0: unsigned int requiredSpace; michael@0: if (!mVertexBuffer->getSpaceRequired(attribute, count, instances, &requiredSpace)) michael@0: { michael@0: return false; michael@0: } michael@0: michael@0: // Protect against integer overflow michael@0: if (mReservedSpace + requiredSpace < mReservedSpace) michael@0: { michael@0: return false; michael@0: } michael@0: michael@0: mReservedSpace += requiredSpace; michael@0: return true; michael@0: } michael@0: michael@0: bool VertexBufferInterface::reserveRawDataSpace(unsigned int size) michael@0: { michael@0: // Protect against integer overflow michael@0: if (mReservedSpace + size < mReservedSpace) michael@0: { michael@0: return false; michael@0: } michael@0: michael@0: mReservedSpace += size; michael@0: return true; michael@0: } michael@0: michael@0: VertexBuffer* VertexBufferInterface::getVertexBuffer() const michael@0: { michael@0: return mVertexBuffer; michael@0: } michael@0: michael@0: michael@0: StreamingVertexBufferInterface::StreamingVertexBufferInterface(rx::Renderer *renderer, std::size_t initialSize) : VertexBufferInterface(renderer, true) michael@0: { michael@0: setBufferSize(initialSize); michael@0: } michael@0: michael@0: StreamingVertexBufferInterface::~StreamingVertexBufferInterface() michael@0: { michael@0: } michael@0: michael@0: bool StreamingVertexBufferInterface::reserveSpace(unsigned int size) michael@0: { michael@0: bool result = true; michael@0: unsigned int curBufferSize = getBufferSize(); michael@0: if (size > curBufferSize) michael@0: { michael@0: result = setBufferSize(std::max(size, 3 * curBufferSize / 2)); michael@0: setWritePosition(0); michael@0: } michael@0: else if (getWritePosition() + size > curBufferSize) michael@0: { michael@0: if (!discard()) michael@0: { michael@0: return false; michael@0: } michael@0: setWritePosition(0); michael@0: } michael@0: michael@0: return result; michael@0: } michael@0: michael@0: StaticVertexBufferInterface::StaticVertexBufferInterface(rx::Renderer *renderer) : VertexBufferInterface(renderer, false) michael@0: { michael@0: } michael@0: michael@0: StaticVertexBufferInterface::~StaticVertexBufferInterface() michael@0: { michael@0: } michael@0: michael@0: bool StaticVertexBufferInterface::lookupAttribute(const gl::VertexAttribute &attribute, unsigned int *outStreamOffset) michael@0: { michael@0: for (unsigned int element = 0; element < mCache.size(); element++) michael@0: { michael@0: if (mCache[element].type == attribute.mType && michael@0: mCache[element].size == attribute.mSize && michael@0: mCache[element].stride == attribute.stride() && michael@0: mCache[element].normalized == attribute.mNormalized) michael@0: { michael@0: if (mCache[element].attributeOffset == attribute.mOffset % attribute.stride()) michael@0: { michael@0: if (outStreamOffset) michael@0: { michael@0: *outStreamOffset = mCache[element].streamOffset; michael@0: } michael@0: return true; michael@0: } michael@0: } michael@0: } michael@0: michael@0: return false; michael@0: } michael@0: michael@0: bool StaticVertexBufferInterface::reserveSpace(unsigned int size) michael@0: { michael@0: unsigned int curSize = getBufferSize(); michael@0: if (curSize == 0) michael@0: { michael@0: setBufferSize(size); michael@0: return true; michael@0: } michael@0: else if (curSize >= size) michael@0: { michael@0: return true; michael@0: } michael@0: else michael@0: { michael@0: UNREACHABLE(); // Static vertex buffers can't be resized michael@0: return false; michael@0: } michael@0: } michael@0: michael@0: bool StaticVertexBufferInterface::storeVertexAttributes(const gl::VertexAttribute &attrib, GLint start, GLsizei count, GLsizei instances, michael@0: unsigned int *outStreamOffset) michael@0: { michael@0: unsigned int streamOffset; michael@0: if (VertexBufferInterface::storeVertexAttributes(attrib, start, count, instances, &streamOffset)) michael@0: { michael@0: int attributeOffset = attrib.mOffset % attrib.stride(); michael@0: VertexElement element = { attrib.mType, attrib.mSize, attrib.stride(), attrib.mNormalized, attributeOffset, streamOffset }; michael@0: mCache.push_back(element); michael@0: michael@0: if (outStreamOffset) michael@0: { michael@0: *outStreamOffset = streamOffset; michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: else michael@0: { michael@0: return false; michael@0: } michael@0: } michael@0: michael@0: }