diff options
Diffstat (limited to 'gfx/angle/checkout/src/libANGLE/VertexAttribute.cpp')
-rw-r--r-- | gfx/angle/checkout/src/libANGLE/VertexAttribute.cpp | 170 |
1 files changed, 170 insertions, 0 deletions
diff --git a/gfx/angle/checkout/src/libANGLE/VertexAttribute.cpp b/gfx/angle/checkout/src/libANGLE/VertexAttribute.cpp new file mode 100644 index 0000000000..f525addbba --- /dev/null +++ b/gfx/angle/checkout/src/libANGLE/VertexAttribute.cpp @@ -0,0 +1,170 @@ +// +// Copyright 2014 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. +// +// Implementation of the state classes for mananging GLES 3.1 Vertex Array Objects. +// + +#include "libANGLE/VertexAttribute.h" + +namespace gl +{ + +// [OpenGL ES 3.1] (November 3, 2016) Section 20 Page 361 +// Table 20.2: Vertex Array Object State +VertexBinding::VertexBinding() : VertexBinding(0) {} + +VertexBinding::VertexBinding(GLuint boundAttribute) : mStride(16u), mDivisor(0), mOffset(0) +{ + mBoundAttributesMask.set(boundAttribute); +} + +VertexBinding::VertexBinding(VertexBinding &&binding) +{ + *this = std::move(binding); +} + +VertexBinding::~VertexBinding() {} + +VertexBinding &VertexBinding::operator=(VertexBinding &&binding) +{ + if (this != &binding) + { + mStride = binding.mStride; + mDivisor = binding.mDivisor; + mOffset = binding.mOffset; + mBoundAttributesMask = binding.mBoundAttributesMask; + std::swap(binding.mBuffer, mBuffer); + } + return *this; +} + +void VertexBinding::onContainerBindingChanged(const Context *context, int incr) const +{ + if (mBuffer.get()) + mBuffer->onNonTFBindingChanged(incr); +} + +VertexAttribute::VertexAttribute(GLuint bindingIndex) + : enabled(false), + format(&angle::Format::Get(angle::FormatID::R32G32B32A32_FLOAT)), + pointer(nullptr), + relativeOffset(0), + vertexAttribArrayStride(0), + bindingIndex(bindingIndex), + mCachedElementLimit(0) +{} + +VertexAttribute::VertexAttribute(VertexAttribute &&attrib) + : enabled(attrib.enabled), + format(attrib.format), + pointer(attrib.pointer), + relativeOffset(attrib.relativeOffset), + vertexAttribArrayStride(attrib.vertexAttribArrayStride), + bindingIndex(attrib.bindingIndex), + mCachedElementLimit(attrib.mCachedElementLimit) +{} + +VertexAttribute &VertexAttribute::operator=(VertexAttribute &&attrib) +{ + if (this != &attrib) + { + enabled = attrib.enabled; + format = attrib.format; + pointer = attrib.pointer; + relativeOffset = attrib.relativeOffset; + vertexAttribArrayStride = attrib.vertexAttribArrayStride; + bindingIndex = attrib.bindingIndex; + mCachedElementLimit = attrib.mCachedElementLimit; + } + return *this; +} + +void VertexAttribute::updateCachedElementLimit(const VertexBinding &binding) +{ + Buffer *buffer = binding.getBuffer().get(); + if (!buffer) + { + mCachedElementLimit = 0; + return; + } + + angle::CheckedNumeric<GLint64> bufferSize(buffer->getSize()); + angle::CheckedNumeric<GLint64> bufferOffset(binding.getOffset()); + angle::CheckedNumeric<GLint64> attribOffset(relativeOffset); + angle::CheckedNumeric<GLint64> attribSize(ComputeVertexAttributeTypeSize(*this)); + + // (buffer.size - buffer.offset - attrib.relativeOffset - attrib.size) / binding.stride + angle::CheckedNumeric<GLint64> elementLimit = + (bufferSize - bufferOffset - attribOffset - attribSize); + + // Use the special integer overflow value if there was a math error. + if (!elementLimit.IsValid()) + { + static_assert(kIntegerOverflow < 0, "Unexpected value"); + mCachedElementLimit = kIntegerOverflow; + return; + } + + mCachedElementLimit = elementLimit.ValueOrDie(); + if (mCachedElementLimit < 0) + { + return; + } + + if (binding.getStride() == 0) + { + // Special case for a zero stride. If we can fit one vertex we can fit infinite vertices. + mCachedElementLimit = std::numeric_limits<GLint64>::max(); + return; + } + + angle::CheckedNumeric<GLint64> bindingStride(binding.getStride()); + elementLimit /= bindingStride; + + if (binding.getDivisor() > 0) + { + // For instanced draws, the element count is floor(instanceCount - 1) / binding.divisor. + angle::CheckedNumeric<GLint64> bindingDivisor(binding.getDivisor()); + elementLimit *= bindingDivisor; + + // We account for the floor() part rounding by adding a rounding constant. + elementLimit += bindingDivisor - 1; + } + + mCachedElementLimit = elementLimit.ValueOrDefault(kIntegerOverflow); +} + +size_t ComputeVertexAttributeStride(const VertexAttribute &attrib, const VertexBinding &binding) +{ + // In ES 3.1, VertexAttribPointer will store the type size in the binding stride. + // Hence, rendering always uses the binding's stride. + return attrib.enabled ? binding.getStride() : 16u; +} + +// Warning: you should ensure binding really matches attrib.bindingIndex before using this function. +GLintptr ComputeVertexAttributeOffset(const VertexAttribute &attrib, const VertexBinding &binding) +{ + return attrib.relativeOffset + binding.getOffset(); +} + +size_t ComputeVertexBindingElementCount(GLuint divisor, size_t drawCount, size_t instanceCount) +{ + // For instanced rendering, we draw "instanceDrawCount" sets of "vertexDrawCount" vertices. + // + // A vertex attribute with a positive divisor loads one instanced vertex for every set of + // non-instanced vertices, and the instanced vertex index advances once every "mDivisor" + // instances. + if (instanceCount > 0 && divisor > 0) + { + // When instanceDrawCount is not a multiple attrib.divisor, the division must round up. + // For instance, with 5 non-instanced vertices and a divisor equal to 3, we need 2 instanced + // vertices. + return (instanceCount + divisor - 1u) / divisor; + } + + return drawCount; +} + +} // namespace gl |