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; }
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()); }