Edit

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

Branch :

  • Show log

    Commit

  • Author : Stuart Morgan
    Date : 2019-08-14 12:25:12
    Hash : 9d737966
    Message : Standardize copyright notices to project style For all "ANGLE Project" copyrights, standardize to the format specified by the style guide. Changes: - "Copyright (c)" and "Copyright(c)" changed to just "Copyright". - Removed the second half of date ranges ("Y1Y1-Y2Y2"->"Y1Y1"). - Fixed a small number of files that had no copyright date using the initial commit year from the version control history. - Fixed one instance of copyright being "The ANGLE Project" rather than "The ANGLE Project Authors" These changes are applied both to the copyright of source file, and where applicable to copyright statements that are generated by templates. BUG=angleproject:3811 Change-Id: I973dd65e4ef9deeba232d5be74c768256a0eb2e5 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1754397 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: Jamie Madill <jmadill@chromium.org>

  • src/libANGLE/TransformFeedback.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.
    //
    
    #include "libANGLE/TransformFeedback.h"
    
    #include "common/mathutil.h"
    #include "libANGLE/Buffer.h"
    #include "libANGLE/Caps.h"
    #include "libANGLE/Context.h"
    #include "libANGLE/Program.h"
    #include "libANGLE/State.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;
    }
    
    GLsizeiptr TransformFeedbackState::getPrimitivesDrawn() const
    {
        switch (mPrimitiveMode)
        {
            case gl::PrimitiveMode::Points:
                return mVerticesDrawn;
            case gl::PrimitiveMode::Lines:
                return mVerticesDrawn / 2;
            case gl::PrimitiveMode::Triangles:
                return mVerticesDrawn / 3;
            default:
                return 0;
        }
    }
    
    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, 0, 0);
        }
    }
    
    TransformFeedback::~TransformFeedback()
    {
        SafeDelete(mImplementation);
    }
    
    void TransformFeedback::setLabel(const Context *context, const std::string &label)
    {
        mState.mLabel = label;
    }
    
    const std::string &TransformFeedback::getLabel() const
    {
        return mState.mLabel;
    }
    
    angle::Result TransformFeedback::begin(const Context *context,
                                           PrimitiveMode primitiveMode,
                                           Program *program)
    {
        ANGLE_TRY(mImplementation->begin(context, primitiveMode));
        mState.mActive        = true;
        mState.mPrimitiveMode = primitiveMode;
        mState.mPaused        = false;
        mState.mVerticesDrawn = 0;
        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;
        }
        return angle::Result::Continue;
    }
    
    angle::Result TransformFeedback::end(const Context *context)
    {
        ANGLE_TRY(mImplementation->end(context));
        mState.mActive         = false;
        mState.mPrimitiveMode  = PrimitiveMode::InvalidEnum;
        mState.mPaused         = false;
        mState.mVerticesDrawn  = 0;
        mState.mVertexCapacity = 0;
        if (mState.mProgram)
        {
            mState.mProgram->release(context);
            mState.mProgram = nullptr;
        }
        return angle::Result::Continue;
    }
    
    angle::Result TransformFeedback::pause(const Context *context)
    {
        ANGLE_TRY(mImplementation->pause(context));
        mState.mPaused = true;
        return angle::Result::Continue;
    }
    
    angle::Result TransformFeedback::resume(const Context *context)
    {
        ANGLE_TRY(mImplementation->resume(context));
        mState.mPaused = false;
        return angle::Result::Continue;
    }
    
    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->onDataChanged();
            }
        }
    }
    
    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;
    }
    
    angle::Result 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, 0, 0);
                ANGLE_TRY(
                    mImplementation->bindIndexedBuffer(context, index, mState.mIndexedBuffers[index]));
            }
        }
    
        return angle::Result::Continue;
    }
    
    angle::Result 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);
        }
    
        return mImplementation->bindIndexedBuffer(context, 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() 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