summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexBuffer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexBuffer.cpp')
-rw-r--r--src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexBuffer.cpp311
1 files changed, 311 insertions, 0 deletions
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexBuffer.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexBuffer.cpp
new file mode 100644
index 0000000000..19bd548fce
--- /dev/null
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexBuffer.cpp
@@ -0,0 +1,311 @@
+//
+// Copyright (c) 2002-2012 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 "libANGLE/renderer/d3d/BufferD3D.h"
+#include "libANGLE/renderer/d3d/RendererD3D.h"
+#include "libANGLE/VertexAttribute.h"
+
+#include "common/mathutil.h"
+
+namespace rx
+{
+
+unsigned int VertexBuffer::mNextSerial = 1;
+
+VertexBuffer::VertexBuffer()
+{
+ updateSerial();
+}
+
+VertexBuffer::~VertexBuffer()
+{
+}
+
+void VertexBuffer::updateSerial()
+{
+ mSerial = mNextSerial++;
+}
+
+unsigned int VertexBuffer::getSerial() const
+{
+ return mSerial;
+}
+
+VertexBufferInterface::VertexBufferInterface(BufferFactoryD3D *factory, bool dynamic)
+ : mFactory(factory)
+{
+ mDynamic = dynamic;
+ mWritePosition = 0;
+ mReservedSpace = 0;
+
+ mVertexBuffer = factory->createVertexBuffer();
+}
+
+VertexBufferInterface::~VertexBufferInterface()
+{
+ delete mVertexBuffer;
+}
+
+unsigned int VertexBufferInterface::getSerial() const
+{
+ return mVertexBuffer->getSerial();
+}
+
+unsigned int VertexBufferInterface::getBufferSize() const
+{
+ return mVertexBuffer->getBufferSize();
+}
+
+gl::Error VertexBufferInterface::setBufferSize(unsigned int size)
+{
+ if (mVertexBuffer->getBufferSize() == 0)
+ {
+ return mVertexBuffer->initialize(size, mDynamic);
+ }
+ else
+ {
+ return mVertexBuffer->setBufferSize(size);
+ }
+}
+
+unsigned int VertexBufferInterface::getWritePosition() const
+{
+ return mWritePosition;
+}
+
+void VertexBufferInterface::setWritePosition(unsigned int writePosition)
+{
+ mWritePosition = writePosition;
+}
+
+gl::Error VertexBufferInterface::discard()
+{
+ return mVertexBuffer->discard();
+}
+
+gl::Error VertexBufferInterface::storeVertexAttributes(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData &currentValue,
+ GLint start, GLsizei count, GLsizei instances, unsigned int *outStreamOffset)
+{
+ gl::Error error(GL_NO_ERROR);
+
+ unsigned int spaceRequired;
+ error = mVertexBuffer->getSpaceRequired(attrib, count, instances, &spaceRequired);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ if (mWritePosition + spaceRequired < mWritePosition)
+ {
+ return gl::Error(GL_OUT_OF_MEMORY, "Internal error, new vertex buffer write position would overflow.");
+ }
+
+ error = reserveSpace(mReservedSpace);
+ if (error.isError())
+ {
+ return error;
+ }
+ mReservedSpace = 0;
+
+ error = mVertexBuffer->storeVertexAttributes(attrib, currentValue, start, count, instances, mWritePosition);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ if (outStreamOffset)
+ {
+ *outStreamOffset = mWritePosition;
+ }
+
+ mWritePosition += spaceRequired;
+
+ // Align to 16-byte boundary
+ mWritePosition = roundUp(mWritePosition, 16u);
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error VertexBufferInterface::reserveVertexSpace(const gl::VertexAttribute &attrib, GLsizei count, GLsizei instances)
+{
+ gl::Error error(GL_NO_ERROR);
+
+ unsigned int requiredSpace;
+ error = mVertexBuffer->getSpaceRequired(attrib, count, instances, &requiredSpace);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ // Protect against integer overflow
+ if (mReservedSpace + requiredSpace < mReservedSpace)
+ {
+ return gl::Error(GL_OUT_OF_MEMORY, "Unable to reserve %u extra bytes in internal vertex buffer, "
+ "it would result in an overflow.", requiredSpace);
+ }
+
+ mReservedSpace += requiredSpace;
+
+ // Align to 16-byte boundary
+ mReservedSpace = roundUp(mReservedSpace, 16u);
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+VertexBuffer* VertexBufferInterface::getVertexBuffer() const
+{
+ return mVertexBuffer;
+}
+
+bool VertexBufferInterface::directStoragePossible(const gl::VertexAttribute &attrib,
+ const gl::VertexAttribCurrentValueData &currentValue) const
+{
+ gl::Buffer *buffer = attrib.buffer.get();
+ BufferD3D *storage = buffer ? GetImplAs<BufferD3D>(buffer) : NULL;
+
+ if (!storage || !storage->supportsDirectBinding())
+ {
+ return false;
+ }
+
+ // Alignment restrictions: In D3D, vertex data must be aligned to
+ // the format stride, or to a 4-byte boundary, whichever is smaller.
+ // (Undocumented, and experimentally confirmed)
+ size_t alignment = 4;
+ bool requiresConversion = false;
+
+ if (attrib.type != GL_FLOAT)
+ {
+ gl::VertexFormat vertexFormat(attrib, currentValue.Type);
+
+ unsigned int outputElementSize;
+ getVertexBuffer()->getSpaceRequired(attrib, 1, 0, &outputElementSize);
+ alignment = std::min<size_t>(outputElementSize, 4);
+
+ // TODO(jmadill): add VertexFormatCaps
+ requiresConversion = (mFactory->getVertexConversionType(vertexFormat) & VERTEX_CONVERT_CPU) != 0;
+ }
+
+ bool isAligned = (static_cast<size_t>(ComputeVertexAttributeStride(attrib)) % alignment == 0) &&
+ (static_cast<size_t>(attrib.offset) % alignment == 0);
+
+ return !requiresConversion && isAligned;
+}
+
+StreamingVertexBufferInterface::StreamingVertexBufferInterface(BufferFactoryD3D *factory, std::size_t initialSize)
+ : VertexBufferInterface(factory, true)
+{
+ setBufferSize(initialSize);
+}
+
+StreamingVertexBufferInterface::~StreamingVertexBufferInterface()
+{
+}
+
+gl::Error StreamingVertexBufferInterface::reserveSpace(unsigned int size)
+{
+ unsigned int curBufferSize = getBufferSize();
+ if (size > curBufferSize)
+ {
+ gl::Error error = setBufferSize(std::max(size, 3 * curBufferSize / 2));
+ if (error.isError())
+ {
+ return error;
+ }
+ setWritePosition(0);
+ }
+ else if (getWritePosition() + size > curBufferSize)
+ {
+ gl::Error error = discard();
+ if (error.isError())
+ {
+ return error;
+ }
+ setWritePosition(0);
+ }
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+StaticVertexBufferInterface::StaticVertexBufferInterface(BufferFactoryD3D *factory)
+ : VertexBufferInterface(factory, false)
+{
+}
+
+StaticVertexBufferInterface::~StaticVertexBufferInterface()
+{
+}
+
+bool StaticVertexBufferInterface::lookupAttribute(const gl::VertexAttribute &attrib, unsigned int *outStreamOffset)
+{
+ for (unsigned int element = 0; element < mCache.size(); element++)
+ {
+ if (mCache[element].type == attrib.type &&
+ mCache[element].size == attrib.size &&
+ mCache[element].stride == ComputeVertexAttributeStride(attrib) &&
+ mCache[element].normalized == attrib.normalized &&
+ mCache[element].pureInteger == attrib.pureInteger)
+ {
+ size_t offset = (static_cast<size_t>(attrib.offset) % ComputeVertexAttributeStride(attrib));
+ if (mCache[element].attributeOffset == offset)
+ {
+ if (outStreamOffset)
+ {
+ *outStreamOffset = mCache[element].streamOffset;
+ }
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+gl::Error StaticVertexBufferInterface::reserveSpace(unsigned int size)
+{
+ unsigned int curSize = getBufferSize();
+ if (curSize == 0)
+ {
+ return setBufferSize(size);
+ }
+ else if (curSize >= size)
+ {
+ return gl::Error(GL_NO_ERROR);
+ }
+ else
+ {
+ UNREACHABLE();
+ return gl::Error(GL_INVALID_OPERATION, "Internal error, Static vertex buffers can't be resized.");
+ }
+}
+
+gl::Error StaticVertexBufferInterface::storeVertexAttributes(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData &currentValue,
+ GLint start, GLsizei count, GLsizei instances, unsigned int *outStreamOffset)
+{
+ unsigned int streamOffset;
+ gl::Error error = VertexBufferInterface::storeVertexAttributes(attrib, currentValue, start, count, instances, &streamOffset);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ size_t attributeOffset = static_cast<size_t>(attrib.offset) % ComputeVertexAttributeStride(attrib);
+ VertexElement element = { attrib.type, attrib.size, static_cast<GLuint>(ComputeVertexAttributeStride(attrib)), attrib.normalized, attrib.pureInteger, attributeOffset, streamOffset };
+ mCache.push_back(element);
+
+ if (outStreamOffset)
+ {
+ *outStreamOffset = streamOffset;
+ }
+
+ return gl::Error(GL_NO_ERROR);
+}
+
+}