Edit

kc3-lang/angle/src/libANGLE/VertexAttribute.cpp

Branch :

  • Show log

    Commit

  • Author : Jamie Madill
    Date : 2019-07-04 08:51:34
    Hash : ee21a187
    Message : Store angle::Format in gl::VertexAttribute. Instead of storing type/size/normalized/pureInteger we instead store a pointer to the angle::Format. This makes some code logic simpler and will let us more easily check if a vertex attribute format changes in calls to VertexAttribPointer or VertexAttribFormat. This CL adds extra information to angle::Format to represent the vertex format info needed. It also caches the channel count so that it can be queried faster. Also renames "Int" -> "Sint" in UtilsVk for consistency. Bug: angleproject:3256 Change-Id: I5ef9b983dad8a58c341113c802500b89ce081566 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1684293 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: Jonah Ryan-Davis <jonahr@google.com>

  • src/libANGLE/VertexAttribute.cpp
  • //
    // 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