void VertexArrayGL::updateAttribPointer(size_t attribIndex)
{
    const VertexAttribute &attrib = mData.getVertexAttribute(attribIndex);
    if (mAppliedAttributes[attribIndex] == attrib)
    {
        return;
    }

    updateNeedsStreaming(attribIndex);

    // If we need to stream, defer the attribPointer to the draw call.
    if (mAttributesNeedStreaming[attribIndex])
    {
        return;
    }

    mStateManager->bindVertexArray(mVertexArrayID, getAppliedElementArrayBufferID());
    const Buffer *arrayBuffer = attrib.buffer.get();
    if (arrayBuffer != nullptr)
    {
        const BufferGL *arrayBufferGL = GetImplAs<BufferGL>(arrayBuffer);
        mStateManager->bindBuffer(GL_ARRAY_BUFFER, arrayBufferGL->getBufferID());
    }
    else
    {
        mStateManager->bindBuffer(GL_ARRAY_BUFFER, 0);
    }
    mAppliedAttributes[attribIndex].buffer = attrib.buffer;

    if (attrib.pureInteger)
    {
        mFunctions->vertexAttribIPointer(static_cast<GLuint>(attribIndex), attrib.size, attrib.type,
                                         attrib.stride, attrib.pointer);
    }
    else
    {
        mFunctions->vertexAttribPointer(static_cast<GLuint>(attribIndex), attrib.size, attrib.type,
                                        attrib.normalized, attrib.stride, attrib.pointer);
    }
    mAppliedAttributes[attribIndex].size        = attrib.size;
    mAppliedAttributes[attribIndex].type        = attrib.type;
    mAppliedAttributes[attribIndex].normalized  = attrib.normalized;
    mAppliedAttributes[attribIndex].pureInteger = attrib.pureInteger;
    mAppliedAttributes[attribIndex].stride      = attrib.stride;
    mAppliedAttributes[attribIndex].pointer     = attrib.pointer;
}
Exemple #2
0
void VertexArrayGL::updateAttribEnabled(size_t attribIndex)
{
    const VertexAttribute &attrib = mData.getVertexAttribute(attribIndex);
    if (mAppliedAttributes[attribIndex].enabled == attrib.enabled)
    {
        return;
    }

    updateNeedsStreaming(attribIndex);

    mStateManager->bindVertexArray(mVertexArrayID, getAppliedElementArrayBufferID());
    if (attrib.enabled)
    {
        mFunctions->enableVertexAttribArray(static_cast<GLuint>(attribIndex));
    }
    else
    {
        mFunctions->disableVertexAttribArray(static_cast<GLuint>(attribIndex));
    }
    mAppliedAttributes[attribIndex].enabled = attrib.enabled;
}
void VertexArrayGL::updateAttribEnabled(size_t attribIndex)
{
    const bool enabled = mState.getVertexAttribute(attribIndex).enabled;
    if (mAppliedAttributes[attribIndex].enabled == enabled)
    {
        return;
    }

    updateNeedsStreaming(attribIndex);

    if (enabled)
    {
        mFunctions->enableVertexAttribArray(static_cast<GLuint>(attribIndex));
    }
    else
    {
        mFunctions->disableVertexAttribArray(static_cast<GLuint>(attribIndex));
    }

    mAppliedAttributes[attribIndex].enabled = enabled;
}
void VertexArrayGL::updateAttribPointer(const gl::Context *context, size_t attribIndex)
{
    const VertexAttribute &attrib = mState.getVertexAttribute(attribIndex);

    // According to SPEC, VertexAttribPointer should update the binding indexed attribIndex instead
    // of the binding indexed attrib.bindingIndex (unless attribIndex == attrib.bindingIndex).
    const VertexBinding &binding = mState.getVertexBinding(attribIndex);

    // Since mAttributesNeedStreaming[attribIndex] keeps the value set in the last draw, here we
    // only need to update it when the buffer has been changed. e.g. When we set an attribute to be
    // streamed in the last draw, and only change its format in this draw without calling
    // updateNeedsStreaming, it will still be streamed because the flag is already on.
    const auto &bindingBuffer = binding.getBuffer();
    if (bindingBuffer != mAppliedBindings[attribIndex].getBuffer())
    {
        updateNeedsStreaming(attribIndex);
    }

    // Early return when the vertex attribute isn't using a buffer object:
    // - If we need to stream, defer the attribPointer to the draw call.
    // - Skip the attribute that is disabled and uses a client memory pointer.
    // - Skip the attribute whose buffer is detached by BindVertexBuffer. Since it cannot have a
    //   client memory pointer either, it must be disabled and shouldn't affect the draw.
    const Buffer *arrayBuffer = bindingBuffer.get();
    if (arrayBuffer == nullptr)
    {
        // Mark the applied binding isn't using a buffer by setting its buffer to nullptr so that if
        // it starts to use a buffer later, there is no chance that the caching will skip it.
        mAppliedBindings[attribIndex].setBuffer(context, nullptr);
        return;
    }

    // We do not need to compare attrib.pointer because when we use a different client memory
    // pointer, we don't need to update mAttributesNeedStreaming by binding.buffer and we won't
    // update attribPointer in this function.
    if ((SameVertexAttribFormat(mAppliedAttributes[attribIndex], attrib)) &&
        (mAppliedAttributes[attribIndex].bindingIndex == attrib.bindingIndex) &&
        (SameVertexBuffer(mAppliedBindings[attribIndex], binding)))
    {
        return;
    }

    // Since ANGLE always uses a non-zero VAO, we cannot use a client memory pointer on it:
    // [OpenGL ES 3.0.2] Section 2.8 page 24:
    // An INVALID_OPERATION error is generated when a non-zero vertex array object is bound,
    // zero is bound to the ARRAY_BUFFER buffer object binding point, and the pointer argument
    // is not NULL.

    const BufferGL *arrayBufferGL = GetImplAs<BufferGL>(arrayBuffer);
    mStateManager->bindBuffer(gl::BufferBinding::Array, arrayBufferGL->getBufferID());
    callVertexAttribPointer(static_cast<GLuint>(attribIndex), attrib, binding.getStride(),
                            binding.getOffset());

    mAppliedAttributes[attribIndex].size        = attrib.size;
    mAppliedAttributes[attribIndex].type        = attrib.type;
    mAppliedAttributes[attribIndex].normalized  = attrib.normalized;
    mAppliedAttributes[attribIndex].pureInteger = attrib.pureInteger;

    // After VertexAttribPointer, attrib.relativeOffset is set to 0 and attrib.bindingIndex is set
    // to attribIndex in driver. If attrib.relativeOffset != 0 or attrib.bindingIndex !=
    // attribIndex, they should be set in updateAttribFormat and updateAttribBinding. The cache
    // should be consistent with driver so that we won't miss anything.
    mAppliedAttributes[attribIndex].relativeOffset = 0;
    mAppliedAttributes[attribIndex].bindingIndex   = static_cast<GLuint>(attribIndex);

    mAppliedBindings[attribIndex].setStride(binding.getStride());
    mAppliedBindings[attribIndex].setOffset(binding.getOffset());
    mAppliedBindings[attribIndex].setBuffer(context, binding.getBuffer().get());
}