Edit

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

Branch :

  • Show log

    Commit

  • Author : James Darpinian
    Date : 2018-01-04 18:02:24
    Hash : e8a93c6e
    Message : New transform feedback buffer binding rules Detects undefined behavior when a buffer is bound to a transform feedback binding point and a non transform feedback binding point at the same time. Also moves the transform feedback buffer generic binding point out of the transform feedback object and into the context's global state, to match driver behavior. This way binding a new transform feedback object does not affect GL_TRANSFORM_FEEDBACK_BUFFER_BINDING which is similar to how VAOs work with GL_ARRAY_BUFFER_BINDING. Bug: 696345 Change-Id: If3b9306cde7cd2197a8ce35e10c3af9ee58da0b8 Reviewed-on: https://chromium-review.googlesource.com/853130 Commit-Queue: James Darpinian <jdarpinian@chromium.org> Reviewed-by: Jamie Madill <jmadill@chromium.org> Reviewed-by: Geoff Lang <geofflang@chromium.org>

  • src/libANGLE/VertexArray.cpp
  • //
    // Copyright (c) 2013 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 class for mananging GLES 3 Vertex Array Objects.
    //
    
    #include "libANGLE/VertexArray.h"
    #include "libANGLE/Buffer.h"
    #include "libANGLE/Context.h"
    #include "libANGLE/renderer/GLImplFactory.h"
    #include "libANGLE/renderer/VertexArrayImpl.h"
    
    namespace gl
    {
    
    VertexArrayState::VertexArrayState(size_t maxAttribs, size_t maxAttribBindings)
        : mLabel(), mVertexBindings(maxAttribBindings)
    {
        ASSERT(maxAttribs <= maxAttribBindings);
    
        for (size_t i = 0; i < maxAttribs; i++)
        {
            mVertexAttributes.emplace_back(static_cast<GLuint>(i));
        }
    }
    
    VertexArrayState::~VertexArrayState()
    {
    }
    
    VertexArray::VertexArray(rx::GLImplFactory *factory,
                             GLuint id,
                             size_t maxAttribs,
                             size_t maxAttribBindings)
        : mId(id),
          mState(maxAttribs, maxAttribBindings),
          mVertexArray(factory->createVertexArray(mState))
    {
    }
    
    void VertexArray::onDestroy(const Context *context)
    {
        bool isBound = context->isCurrentVertexArray(this);
        for (auto &binding : mState.mVertexBindings)
        {
            binding.setBuffer(context, nullptr, isBound);
        }
        if (isBound && mState.mElementArrayBuffer.get())
            mState.mElementArrayBuffer->onBindingChanged(false, BufferBinding::ElementArray);
        mState.mElementArrayBuffer.set(context, nullptr);
        mVertexArray->destroy(context);
        SafeDelete(mVertexArray);
        delete this;
    }
    
    VertexArray::~VertexArray()
    {
        ASSERT(!mVertexArray);
    }
    
    GLuint VertexArray::id() const
    {
        return mId;
    }
    
    void VertexArray::setLabel(const std::string &label)
    {
        mState.mLabel = label;
    }
    
    const std::string &VertexArray::getLabel() const
    {
        return mState.mLabel;
    }
    
    void VertexArray::detachBuffer(const Context *context, GLuint bufferName)
    {
        bool isBound = context->isCurrentVertexArray(this);
        for (auto &binding : mState.mVertexBindings)
        {
            if (binding.getBuffer().id() == bufferName)
            {
                binding.setBuffer(context, nullptr, isBound);
            }
        }
    
        if (mState.mElementArrayBuffer.id() == bufferName)
        {
            if (isBound && mState.mElementArrayBuffer.get())
                mState.mElementArrayBuffer->onBindingChanged(false, BufferBinding::Array);
            mState.mElementArrayBuffer.set(context, nullptr);
        }
    }
    
    const VertexAttribute &VertexArray::getVertexAttribute(size_t attribIndex) const
    {
        ASSERT(attribIndex < getMaxAttribs());
        return mState.mVertexAttributes[attribIndex];
    }
    
    const VertexBinding &VertexArray::getVertexBinding(size_t bindingIndex) const
    {
        ASSERT(bindingIndex < getMaxBindings());
        return mState.mVertexBindings[bindingIndex];
    }
    
    size_t VertexArray::GetVertexIndexFromDirtyBit(size_t dirtyBit)
    {
        static_assert(gl::MAX_VERTEX_ATTRIBS == gl::MAX_VERTEX_ATTRIB_BINDINGS,
                      "The stride of vertex attributes should equal to that of vertex bindings.");
        ASSERT(dirtyBit > DIRTY_BIT_ELEMENT_ARRAY_BUFFER);
        return (dirtyBit - DIRTY_BIT_ATTRIB_0_ENABLED) % gl::MAX_VERTEX_ATTRIBS;
    }
    
    void VertexArray::bindVertexBufferImpl(const Context *context,
                                           size_t bindingIndex,
                                           Buffer *boundBuffer,
                                           GLintptr offset,
                                           GLsizei stride)
    {
        ASSERT(bindingIndex < getMaxBindings());
        bool isBound = context->isCurrentVertexArray(this);
    
        VertexBinding *binding = &mState.mVertexBindings[bindingIndex];
    
        binding->setBuffer(context, boundBuffer, isBound);
        binding->setOffset(offset);
        binding->setStride(stride);
    }
    
    void VertexArray::bindVertexBuffer(const Context *context,
                                       size_t bindingIndex,
                                       Buffer *boundBuffer,
                                       GLintptr offset,
                                       GLsizei stride)
    {
        bindVertexBufferImpl(context, bindingIndex, boundBuffer, offset, stride);
    
        mDirtyBits.set(DIRTY_BIT_BINDING_0_BUFFER + bindingIndex);
    }
    
    void VertexArray::setVertexAttribBinding(const Context *context,
                                             size_t attribIndex,
                                             GLuint bindingIndex)
    {
        ASSERT(attribIndex < getMaxAttribs() && bindingIndex < getMaxBindings());
    
        if (mState.mVertexAttributes[attribIndex].bindingIndex != bindingIndex)
        {
            // In ES 3.0 contexts, the binding cannot change, hence the code below is unreachable.
            ASSERT(context->getClientVersion() >= ES_3_1);
            mState.mVertexAttributes[attribIndex].bindingIndex = bindingIndex;
    
            mDirtyBits.set(DIRTY_BIT_ATTRIB_0_BINDING + attribIndex);
        }
    }
    
    void VertexArray::setVertexBindingDivisor(size_t bindingIndex, GLuint divisor)
    {
        ASSERT(bindingIndex < getMaxBindings());
    
        mState.mVertexBindings[bindingIndex].setDivisor(divisor);
    
        mDirtyBits.set(DIRTY_BIT_BINDING_0_DIVISOR + bindingIndex);
    }
    
    void VertexArray::setVertexAttribFormatImpl(size_t attribIndex,
                                                GLint size,
                                                GLenum type,
                                                bool normalized,
                                                bool pureInteger,
                                                GLuint relativeOffset)
    {
        ASSERT(attribIndex < getMaxAttribs());
    
        VertexAttribute *attrib = &mState.mVertexAttributes[attribIndex];
    
        attrib->size           = size;
        attrib->type           = type;
        attrib->normalized     = normalized;
        attrib->pureInteger    = pureInteger;
        attrib->relativeOffset = relativeOffset;
        mState.mVertexAttributesTypeMask.setIndex(GetVertexAttributeBaseType(*attrib), attribIndex);
        mState.mEnabledAttributesMask.set(attribIndex);
    }
    
    void VertexArray::setVertexAttribFormat(size_t attribIndex,
                                            GLint size,
                                            GLenum type,
                                            bool normalized,
                                            bool pureInteger,
                                            GLuint relativeOffset)
    {
        setVertexAttribFormatImpl(attribIndex, size, type, normalized, pureInteger, relativeOffset);
    
        mDirtyBits.set(DIRTY_BIT_ATTRIB_0_FORMAT + attribIndex);
    }
    
    void VertexArray::setVertexAttribDivisor(const Context *context, size_t attribIndex, GLuint divisor)
    {
        ASSERT(attribIndex < getMaxAttribs());
    
        setVertexAttribBinding(context, attribIndex, static_cast<GLuint>(attribIndex));
        setVertexBindingDivisor(attribIndex, divisor);
    }
    
    void VertexArray::enableAttribute(size_t attribIndex, bool enabledState)
    {
        ASSERT(attribIndex < getMaxAttribs());
    
        mState.mVertexAttributes[attribIndex].enabled = enabledState;
        mState.mVertexAttributesTypeMask.setIndex(
            GetVertexAttributeBaseType(mState.mVertexAttributes[attribIndex]), attribIndex);
    
        mDirtyBits.set(DIRTY_BIT_ATTRIB_0_ENABLED + attribIndex);
    
        // Update state cache
        mState.mEnabledAttributesMask.set(attribIndex, enabledState);
    }
    
    void VertexArray::setVertexAttribPointer(const Context *context,
                                             size_t attribIndex,
                                             gl::Buffer *boundBuffer,
                                             GLint size,
                                             GLenum type,
                                             bool normalized,
                                             bool pureInteger,
                                             GLsizei stride,
                                             const void *pointer)
    {
        ASSERT(attribIndex < getMaxAttribs());
    
        GLintptr offset = boundBuffer ? reinterpret_cast<GLintptr>(pointer) : 0;
    
        setVertexAttribFormatImpl(attribIndex, size, type, normalized, pureInteger, 0);
        setVertexAttribBinding(context, attribIndex, static_cast<GLuint>(attribIndex));
    
        VertexAttribute &attrib = mState.mVertexAttributes[attribIndex];
    
        GLsizei effectiveStride =
            stride != 0 ? stride : static_cast<GLsizei>(ComputeVertexAttributeTypeSize(attrib));
        attrib.pointer                 = pointer;
        attrib.vertexAttribArrayStride = stride;
    
        bindVertexBufferImpl(context, attribIndex, boundBuffer, offset, effectiveStride);
    
        mDirtyBits.set(DIRTY_BIT_ATTRIB_0_POINTER + attribIndex);
    }
    
    void VertexArray::setElementArrayBuffer(const Context *context, Buffer *buffer)
    {
        bool isBound = context->isCurrentVertexArray(this);
        if (isBound && mState.mElementArrayBuffer.get())
            mState.mElementArrayBuffer->onBindingChanged(false, BufferBinding::ElementArray);
        mState.mElementArrayBuffer.set(context, buffer);
        if (isBound && mState.mElementArrayBuffer.get())
            mState.mElementArrayBuffer->onBindingChanged(true, BufferBinding::ElementArray);
        mDirtyBits.set(DIRTY_BIT_ELEMENT_ARRAY_BUFFER);
    }
    
    void VertexArray::syncState(const Context *context)
    {
        if (mDirtyBits.any())
        {
            mVertexArray->syncState(context, mDirtyBits);
            mDirtyBits.reset();
        }
    }
    
    void VertexArray::onBindingChanged(bool bound)
    {
        if (mState.mElementArrayBuffer.get())
            mState.mElementArrayBuffer->onBindingChanged(bound, BufferBinding::ElementArray);
        for (auto &binding : mState.mVertexBindings)
        {
            binding.onContainerBindingChanged(bound);
        }
    }
    
    }  // namespace gl