Implement basic functionality in VertexArrayGL.

No support for raw vertex data pointers yet.

BUG=angle:880

Change-Id: Ifa8099b0f49028a1465edecde495ba725ac79598
Reviewed-on: https://chromium-review.googlesource.com/252801
Reviewed-by: Kenneth Russell <kbr@chromium.org>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Tested-by: Geoff Lang <geofflang@chromium.org>
diff --git a/src/libANGLE/renderer/gl/VertexArrayGL.cpp b/src/libANGLE/renderer/gl/VertexArrayGL.cpp
index 7745e7f..e66844c 100644
--- a/src/libANGLE/renderer/gl/VertexArrayGL.cpp
+++ b/src/libANGLE/renderer/gl/VertexArrayGL.cpp
@@ -9,35 +9,146 @@
 #include "libANGLE/renderer/gl/VertexArrayGL.h"
 
 #include "common/debug.h"
+#include "libANGLE/angletypes.h"
+#include "libANGLE/renderer/gl/BufferGL.h"
+#include "libANGLE/renderer/gl/FunctionsGL.h"
+#include "libANGLE/renderer/gl/StateManagerGL.h"
 
 namespace rx
 {
 
-VertexArrayGL::VertexArrayGL()
-    : VertexArrayImpl()
-{}
+VertexArrayGL::VertexArrayGL(const FunctionsGL *functions, StateManagerGL *stateManager)
+    : VertexArrayImpl(),
+      mFunctions(functions),
+      mStateManager(stateManager),
+      mVertexArrayID(0),
+      mAppliedElementArrayBuffer(0),
+      mAppliedAttributes()
+{
+    ASSERT(mFunctions);
+    ASSERT(mStateManager);
+    mFunctions->genVertexArrays(1, &mVertexArrayID);
+
+    // Set the cached vertex attribute array size
+    GLint maxVertexAttribs;
+    mFunctions->getIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxVertexAttribs);
+    mAppliedAttributes.resize(maxVertexAttribs);
+}
 
 VertexArrayGL::~VertexArrayGL()
-{}
+{
+    if (mVertexArrayID != 0)
+    {
+        mFunctions->deleteVertexArrays(1, &mVertexArrayID);
+        mVertexArrayID = 0;
+    }
+
+    for (size_t idx = 0; idx < mAppliedAttributes.size(); idx++)
+    {
+        mAppliedAttributes[idx].buffer.set(NULL);
+    }
+}
 
 void VertexArrayGL::setElementArrayBuffer(const gl::Buffer *buffer)
 {
-    //UNIMPLEMENTED();
+    GLuint elementArrayBufferID = 0;
+    if (buffer != nullptr)
+    {
+        const BufferGL *bufferGL = GetImplAs<BufferGL>(buffer);
+        elementArrayBufferID = bufferGL->getBufferID();
+    }
+
+    if (elementArrayBufferID != mAppliedElementArrayBuffer)
+    {
+        mStateManager->bindVertexArray(mVertexArrayID);
+        mStateManager->bindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementArrayBufferID);
+        mStateManager->bindVertexArray(0);
+
+        mAppliedElementArrayBuffer = elementArrayBufferID;
+    }
 }
 
 void VertexArrayGL::setAttribute(size_t idx, const gl::VertexAttribute &attr)
 {
-    UNIMPLEMENTED();
+    if (mAppliedAttributes[idx].type != attr.type ||
+        mAppliedAttributes[idx].size != attr.size ||
+        mAppliedAttributes[idx].normalized != attr.normalized ||
+        mAppliedAttributes[idx].pureInteger != attr.pureInteger ||
+        mAppliedAttributes[idx].stride != attr.stride ||
+        mAppliedAttributes[idx].pointer != attr.pointer ||
+        mAppliedAttributes[idx].buffer.get() != attr.buffer.get())
+    {
+        mStateManager->bindVertexArray(mVertexArrayID);
+
+        const gl::Buffer *arrayBuffer = attr.buffer.get();
+        if (arrayBuffer != nullptr)
+        {
+            const BufferGL *arrayBufferGL = GetImplAs<BufferGL>(arrayBuffer);
+            mStateManager->bindBuffer(GL_ARRAY_BUFFER, arrayBufferGL->getBufferID());
+        }
+        else
+        {
+            // This will take some extra work, core OpenGL doesn't support binding raw data pointers
+            // to VAOs
+            UNIMPLEMENTED();
+        }
+
+        if (attr.pureInteger)
+        {
+            mFunctions->vertexAttribIPointer(idx, attr.size, attr.type, attr.stride, attr.pointer);
+        }
+        else
+        {
+            mFunctions->vertexAttribPointer(idx, attr.size, attr.type, attr.normalized, attr.stride, attr.pointer);
+        }
+        mAppliedAttributes[idx].type = attr.type;
+        mAppliedAttributes[idx].size = attr.size;
+        mAppliedAttributes[idx].normalized = attr.normalized;
+        mAppliedAttributes[idx].pureInteger = attr.pureInteger;
+        mAppliedAttributes[idx].stride = attr.stride;
+        mAppliedAttributes[idx].pointer = attr.pointer;
+        mAppliedAttributes[idx].buffer.set(attr.buffer.get());
+
+        mStateManager->bindVertexArray(0);
+    }
 }
 
 void VertexArrayGL::setAttributeDivisor(size_t idx, GLuint divisor)
 {
-    UNIMPLEMENTED();
+    if (mAppliedAttributes[idx].divisor != divisor)
+    {
+        mStateManager->bindVertexArray(mVertexArrayID);
+
+        mFunctions->vertexAttribDivisor(idx, divisor);
+        mAppliedAttributes[idx].divisor = divisor;
+
+        mStateManager->bindVertexArray(0);
+    }
 }
 
 void VertexArrayGL::enableAttribute(size_t idx, bool enabledState)
 {
-    UNIMPLEMENTED();
+    if (mAppliedAttributes[idx].enabled != enabledState)
+    {
+        mStateManager->bindVertexArray(mVertexArrayID);
+
+        if (enabledState)
+        {
+            mFunctions->enableVertexAttribArray(idx);
+        }
+        else
+        {
+            mFunctions->disableVertexAttribArray(idx);
+        }
+        mAppliedAttributes[idx].enabled = enabledState;
+
+        mStateManager->bindVertexArray(0);
+    }
+}
+
+GLuint VertexArrayGL::getVertexArrayID() const
+{
+    return mVertexArrayID;
 }
 
 }