Edit

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

Branch :

  • Show log

    Commit

  • Author : Jamie Madill
    Date : 2018-10-10 16:13:02
    Hash : 1c7f08c3
    Message : Inline RefCountObject::release. Also don't return errors from the object release methods. Not returning errors reduces the amount of code generated. Also we shouldn't be exiting early from destructor type functions. Increases object binding performance. Bug: angleproject:2877 Change-Id: Ieb8120d885b946915e355419825e1f52f31d7b49 Reviewed-on: https://chromium-review.googlesource.com/c/1270218 Reviewed-by: Geoff Lang <geofflang@chromium.org> Commit-Queue: Jamie Madill <jmadill@chromium.org>

  • src/libANGLE/TransformFeedback.cpp
  • //
    // Copyright (c) 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.
    //
    
    #include "libANGLE/TransformFeedback.h"
    
    #include "common/mathutil.h"
    #include "libANGLE/Buffer.h"
    #include "libANGLE/Caps.h"
    #include "libANGLE/Context.h"
    #include "libANGLE/ContextState.h"
    #include "libANGLE/Program.h"
    #include "libANGLE/renderer/GLImplFactory.h"
    #include "libANGLE/renderer/TransformFeedbackImpl.h"
    
    #include <limits>
    
    namespace gl
    {
    
    angle::CheckedNumeric<GLsizeiptr> GetVerticesNeededForDraw(PrimitiveMode primitiveMode,
                                                               GLsizei count,
                                                               GLsizei primcount)
    {
        if (count < 0 || primcount < 0)
        {
            return 0;
        }
        // Transform feedback only outputs complete primitives, so we need to round down to the nearest
        // complete primitive before multiplying by the number of instances.
        angle::CheckedNumeric<GLsizeiptr> checkedCount     = count;
        angle::CheckedNumeric<GLsizeiptr> checkedPrimcount = primcount;
        switch (primitiveMode)
        {
            case PrimitiveMode::Triangles:
                return checkedPrimcount * (checkedCount - checkedCount % 3);
            case PrimitiveMode::Lines:
                return checkedPrimcount * (checkedCount - checkedCount % 2);
            case PrimitiveMode::Points:
                return checkedPrimcount * checkedCount;
            default:
                UNREACHABLE();
                return checkedPrimcount * checkedCount;
        }
    }
    
    TransformFeedbackState::TransformFeedbackState(size_t maxIndexedBuffers)
        : mLabel(),
          mActive(false),
          mPrimitiveMode(PrimitiveMode::InvalidEnum),
          mPaused(false),
          mVerticesDrawn(0),
          mVertexCapacity(0),
          mProgram(nullptr),
          mIndexedBuffers(maxIndexedBuffers)
    {
    }
    
    TransformFeedbackState::~TransformFeedbackState()
    {
    }
    
    const OffsetBindingPointer<Buffer> &TransformFeedbackState::getIndexedBuffer(size_t idx) const
    {
        return mIndexedBuffers[idx];
    }
    
    const std::vector<OffsetBindingPointer<Buffer>> &TransformFeedbackState::getIndexedBuffers() const
    {
        return mIndexedBuffers;
    }
    
    TransformFeedback::TransformFeedback(rx::GLImplFactory *implFactory, GLuint id, const Caps &caps)
        : RefCountObject(id),
          mState(caps.maxTransformFeedbackSeparateAttributes),
          mImplementation(implFactory->createTransformFeedback(mState))
    {
        ASSERT(mImplementation != nullptr);
    }
    
    void TransformFeedback::onDestroy(const Context *context)
    {
        ASSERT(!context || !context->isCurrentTransformFeedback(this));
        if (mState.mProgram)
        {
            mState.mProgram->release(context);
            mState.mProgram = nullptr;
        }
    
        ASSERT(!mState.mProgram);
        for (size_t i = 0; i < mState.mIndexedBuffers.size(); i++)
        {
            mState.mIndexedBuffers[i].set(context, nullptr);
        }
    }
    
    TransformFeedback::~TransformFeedback()
    {
        SafeDelete(mImplementation);
    }
    
    void TransformFeedback::setLabel(const std::string &label)
    {
        mState.mLabel = label;
    }
    
    const std::string &TransformFeedback::getLabel() const
    {
        return mState.mLabel;
    }
    
    void TransformFeedback::begin(const Context *context, PrimitiveMode primitiveMode, Program *program)
    {
        mState.mActive        = true;
        mState.mPrimitiveMode = primitiveMode;
        mState.mPaused        = false;
        mState.mVerticesDrawn = 0;
        mImplementation->begin(primitiveMode);
        bindProgram(context, program);
    
        if (program)
        {
            // Compute the number of vertices we can draw before overflowing the bound buffers.
            auto strides = program->getTransformFeedbackStrides();
            ASSERT(strides.size() <= mState.mIndexedBuffers.size() && !strides.empty());
            GLsizeiptr minCapacity = std::numeric_limits<GLsizeiptr>::max();
            for (size_t index = 0; index < strides.size(); index++)
            {
                GLsizeiptr capacity =
                    GetBoundBufferAvailableSize(mState.mIndexedBuffers[index]) / strides[index];
                minCapacity = std::min(minCapacity, capacity);
            }
            mState.mVertexCapacity = minCapacity;
        }
        else
        {
            mState.mVertexCapacity = 0;
        }
    }
    
    void TransformFeedback::end(const Context *context)
    {
        mState.mActive         = false;
        mState.mPrimitiveMode  = PrimitiveMode::InvalidEnum;
        mState.mPaused         = false;
        mState.mVerticesDrawn  = 0;
        mState.mVertexCapacity = 0;
        mImplementation->end();
        if (mState.mProgram)
        {
            mState.mProgram->release(context);
            mState.mProgram = nullptr;
        }
    }
    
    void TransformFeedback::pause()
    {
        mState.mPaused = true;
        mImplementation->pause();
    }
    
    void TransformFeedback::resume()
    {
        mState.mPaused = false;
        mImplementation->resume();
    }
    
    bool TransformFeedback::isPaused() const
    {
        return mState.mPaused;
    }
    
    PrimitiveMode TransformFeedback::getPrimitiveMode() const
    {
        return mState.mPrimitiveMode;
    }
    
    bool TransformFeedback::checkBufferSpaceForDraw(GLsizei count, GLsizei primcount) const
    {
        auto vertices =
            mState.mVerticesDrawn + GetVerticesNeededForDraw(mState.mPrimitiveMode, count, primcount);
        return vertices.IsValid() && vertices.ValueOrDie() <= mState.mVertexCapacity;
    }
    
    void TransformFeedback::onVerticesDrawn(const Context *context, GLsizei count, GLsizei primcount)
    {
        ASSERT(mState.mActive && !mState.mPaused);
        // All draws should be validated with checkBufferSpaceForDraw so ValueOrDie should never fail.
        mState.mVerticesDrawn =
            (mState.mVerticesDrawn + GetVerticesNeededForDraw(mState.mPrimitiveMode, count, primcount))
                .ValueOrDie();
    
        for (auto &buffer : mState.mIndexedBuffers)
        {
            if (buffer.get() != nullptr)
            {
                buffer->onTransformFeedback(context);
            }
        }
    }
    
    void TransformFeedback::bindProgram(const Context *context, Program *program)
    {
        if (mState.mProgram != program)
        {
            if (mState.mProgram != nullptr)
            {
                mState.mProgram->release(context);
            }
            mState.mProgram = program;
            if (mState.mProgram != nullptr)
            {
                mState.mProgram->addRef();
            }
        }
    }
    
    bool TransformFeedback::hasBoundProgram(GLuint program) const
    {
        return mState.mProgram != nullptr && mState.mProgram->id() == program;
    }
    
    void TransformFeedback::detachBuffer(const Context *context, GLuint bufferName)
    {
        bool isBound = context->isCurrentTransformFeedback(this);
        for (size_t index = 0; index < mState.mIndexedBuffers.size(); index++)
        {
            if (mState.mIndexedBuffers[index].id() == bufferName)
            {
                if (isBound)
                {
                    mState.mIndexedBuffers[index]->onTFBindingChanged(context, false, true);
                }
                mState.mIndexedBuffers[index].set(context, nullptr);
                mImplementation->bindIndexedBuffer(index, mState.mIndexedBuffers[index]);
            }
        }
    }
    
    void TransformFeedback::bindIndexedBuffer(const Context *context,
                                              size_t index,
                                              Buffer *buffer,
                                              size_t offset,
                                              size_t size)
    {
        ASSERT(index < mState.mIndexedBuffers.size());
        bool isBound = context && context->isCurrentTransformFeedback(this);
        if (isBound && mState.mIndexedBuffers[index].get())
        {
            mState.mIndexedBuffers[index]->onTFBindingChanged(context, false, true);
        }
        mState.mIndexedBuffers[index].set(context, buffer, offset, size);
        if (isBound && buffer)
        {
            buffer->onTFBindingChanged(context, true, true);
        }
    
        mImplementation->bindIndexedBuffer(index, mState.mIndexedBuffers[index]);
    }
    
    const OffsetBindingPointer<Buffer> &TransformFeedback::getIndexedBuffer(size_t index) const
    {
        ASSERT(index < mState.mIndexedBuffers.size());
        return mState.mIndexedBuffers[index];
    }
    
    size_t TransformFeedback::getIndexedBufferCount() const
    {
        return mState.mIndexedBuffers.size();
    }
    
    bool TransformFeedback::buffersBoundForOtherUse() const
    {
        for (auto &buffer : mState.mIndexedBuffers)
        {
            if (buffer.get() && buffer->isBoundForTransformFeedbackAndOtherUse())
            {
                return true;
            }
        }
        return false;
    }
    
    rx::TransformFeedbackImpl *TransformFeedback::getImplementation()
    {
        return mImplementation;
    }
    
    const rx::TransformFeedbackImpl *TransformFeedback::getImplementation() const
    {
        return mImplementation;
    }
    
    void TransformFeedback::onBindingChanged(const Context *context, bool bound)
    {
        for (auto &buffer : mState.mIndexedBuffers)
        {
            if (buffer.get())
            {
                buffer->onTFBindingChanged(context, bound, true);
            }
        }
    }
    }  // namespace gl