diff --git a/examples/canvas3d/texturedcube/qml/texturedcube/main.qml b/examples/canvas3d/texturedcube/qml/texturedcube/main.qml
index 7645f2158c9b4c8c510b8b4943dc0a1888827b3a..f159c88ad27b62fb837d886d7349588e58f84ecf 100644
--- a/examples/canvas3d/texturedcube/qml/texturedcube/main.qml
+++ b/examples/canvas3d/texturedcube/qml/texturedcube/main.qml
@@ -59,7 +59,6 @@ Item {
         property double xRotAnim: 0
         property double yRotAnim: 0
         property double zRotAnim: 0
-        property bool isRunning: true
 
         //! [1]
         // Emitted when one time initializations should happen
diff --git a/src/buffer3d.cpp b/src/buffer3d.cpp
index 576f4a7eca67f0db1f9eb2b7a3ef432d295e6b75..1f5992fc4287c3b5f66420e779ad09ce59f2df71 100644
--- a/src/buffer3d.cpp
+++ b/src/buffer3d.cpp
@@ -55,12 +55,26 @@
  */
 CanvasBuffer::CanvasBuffer(QObject *parent) :
     CanvasAbstractObject(parent),
+    QOpenGLFunctions(),
     m_bindTarget(CanvasBuffer::UNINITIALIZED)
 {
     initializeOpenGLFunctions();
     glGenBuffers(1, &m_bufferId);
 }
 
+/*!
+ * \internal
+ */
+CanvasBuffer::CanvasBuffer(const CanvasBuffer& other) :
+    CanvasAbstractObject(), // Copying a QObject, leave it parentless..
+    QOpenGLFunctions(),
+    m_bufferId(other.m_bufferId),
+    m_bindTarget(other.m_bindTarget)
+{
+    initializeOpenGLFunctions();
+}
+
+
 /*!
  * \internal
  */
diff --git a/src/buffer3d_p.h b/src/buffer3d_p.h
index 7f808cf394b7c7a46581f4ed9a17ca1d1317ac00..5f8665243ce66601425ceb4e0319a684993330d1 100644
--- a/src/buffer3d_p.h
+++ b/src/buffer3d_p.h
@@ -64,6 +64,7 @@ public:
     };
 
     explicit CanvasBuffer(QObject *parent = 0);
+    CanvasBuffer(const CanvasBuffer& other);
     virtual ~CanvasBuffer();
 
     void del();
diff --git a/src/context3d.cpp b/src/context3d.cpp
index b6582e3ec6ae8ba97db21f867e6173413c3b6633..6889c2802a38a394ec5e1deb90b78e469b55b32f 100644
--- a/src/context3d.cpp
+++ b/src/context3d.cpp
@@ -92,9 +92,15 @@ CanvasContext::CanvasContext(QOpenGLContext *context, int width, int height, QOb
     m_error(NO_ERROR),
     m_currentFramebuffer(0),
     m_map(EnumToStringMap::newInstance()),
-    m_canvas(0)
+    m_canvas(0),
+    m_maxVertexAttribs(0)
 {
     m_context = context;
+
+    int value = 0;
+    glGetIntegerv(MAX_VERTEX_ATTRIBS, &value);
+    m_maxVertexAttribs = uint(value);
+
 #ifndef QT_NO_DEBUG
     const GLubyte *version = glGetString(GL_VERSION);
     qDebug() << "Context3D::" << __FUNCTION__
@@ -3117,6 +3123,7 @@ int CanvasContext::getShaderParameter(CanvasShader *shader, glEnums pname)
 CanvasBuffer *CanvasContext::createBuffer()
 {
     CanvasBuffer *newBuffer = new CanvasBuffer(this);
+    m_idToCanvasBufferMap[newBuffer->id()] = newBuffer;
     if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << ":" << newBuffer;
 
     // Returning a pointer to QObject that has parent set
@@ -3440,7 +3447,6 @@ void CanvasContext::vertexAttribPointer(int indx, int size, glEnums type,
                                 << ", offset:" << offset
                                 << ")";
 
-    // TODO: Fix offset
     glVertexAttribPointer(indx, size, GLenum(type), normalized, stride, (GLvoid *)offset);
 }
 
@@ -3742,6 +3748,7 @@ void CanvasContext::deleteBuffer(CanvasBuffer *buffer)
         return;
     }
 
+    m_idToCanvasBufferMap.remove(buffer->id());
     buffer->del();
 }
 
@@ -4687,8 +4694,159 @@ QVariant CanvasContext::getTexParameter(glEnums target, glEnums pname)
     return QVariant::fromValue(parameter);
 }
 
+
+/*!
+ * \qmlmethod int Context3D::getVertexAttribOffset(int index, glEnums pname)
+ * Returns the offset of the specified generic vertex attribute pointer \a index. \a pname must be
+ * \c{Context3D.VERTEX_ATTRIB_ARRAY_POINTER}
+ * \list
+ * \li \c{Context3D.TEXTURE_MAG_FILTER}
+ * \li \c{Context3D.TEXTURE_MIN_FILTER}
+ * \li \c{Context3D.TEXTURE_WRAP_S}
+ * \li \c{Context3D.TEXTURE_WRAP_T}
+ * \endlist
+ */
+/*!
+ * \internal
+ */
+uint CanvasContext::getVertexAttribOffset(uint index, glEnums pname)
+{
+    if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__
+                                << "(index" << index
+                                << ", pname:" << glEnumToString(pname)
+                                << ")";
+
+    uint offset = 0;
+    if (pname != VERTEX_ATTRIB_ARRAY_POINTER) {
+        if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__
+                                     << ":INVALID_ENUM pname must be "
+                                     << "VERTEX_ATTRIB_ARRAY_POINTER";
+        m_error = INVALID_ENUM;
+        return 0;
+    }
+
+    if (index >= m_maxVertexAttribs) {
+        if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__
+                                     << ":INVALID_VALUE index must be smaller than "
+                                     << m_maxVertexAttribs;
+        m_error = INVALID_VALUE;
+        return 0;
+    }
+
+    glGetVertexAttribPointerv(index, GLenum(pname), (GLvoid**) &offset);
+    return offset;
+}
+
+/*!
+ * \qmlmethod variant Context3D::getVertexAttrib(int index, glEnums pname)
+ * Returns the requested parameter \a pname of the specified generic vertex attribute pointer
+ * \a index. The type returned is dependent on the requested \a pname, as shown in the table:
+ * \table
+ * \header
+ *   \li pname
+ *   \li Returned Type
+ * \row
+ *   \li \c{Context3D.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING}
+ *   \li \c{CanvasBuffer}
+ * \row
+ *   \li \c{Context3D.VERTEX_ATTRIB_ARRAY_ENABLED}
+ *   \li \c{boolean}
+ * \row
+ *   \li \c{Context3D.VERTEX_ATTRIB_ARRAY_SIZE}
+ *   \li \c{int}
+ * \row
+ *   \li \c{Context3D.VERTEX_ATTRIB_ARRAY_STRIDE}
+ *   \li \c{int}
+ * \row
+ *   \li \c{Context3D.VERTEX_ATTRIB_ARRAY_TYPE}
+ *   \li \c{glEnums}
+ * \row
+ *   \li \c{Context3D.VERTEX_ATTRIB_ARRAY_NORMALIZED}
+ *   \li \c{boolean}
+ * \row
+ *   \li \c{Context3D.CURRENT_VERTEX_ATTRIB}
+ *   \li \c{sequence<float>} (with 4 elements)
+ *  \endtable
+ */
+/*!
+ * \internal
+ */
+QVariant CanvasContext::getVertexAttrib(uint index, glEnums pname)
+{
+    if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__
+                                << "(index" << index
+                                << ", pname:" << glEnumToString(pname)
+                                << ")";
+
+    if (index >= MAX_VERTEX_ATTRIBS) {
+        if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__
+                                     << ":INVALID_VALUE index must be smaller than "
+                                     << "MAX_VERTEX_ATTRIBS = " << MAX_VERTEX_ATTRIBS;
+        m_error = INVALID_VALUE;
+    } else {
+        switch (pname) {
+        case VERTEX_ATTRIB_ARRAY_BUFFER_BINDING: {
+            GLint value = 0;
+            glGetVertexAttribiv(index, GLenum(pname), &value);
+            if (value == 0 || !m_idToCanvasBufferMap.contains(value))
+                return QVariant();
+
+            return QVariant::fromValue(m_idToCanvasBufferMap[value]);
+        }
+        break;
+        case VERTEX_ATTRIB_ARRAY_ENABLED: {
+            GLint value = 0;
+            glGetVertexAttribiv(index, GLenum(pname), &value);
+            return QVariant::fromValue( bool(value));
+        }
+        break;
+        case VERTEX_ATTRIB_ARRAY_SIZE: {
+            GLint value = 0;
+            glGetVertexAttribiv(index, GLenum(pname), &value);
+            return QVariant::fromValue(value);
+        }
+        break;
+        case VERTEX_ATTRIB_ARRAY_STRIDE: {
+            GLint value = 0;
+            glGetVertexAttribiv(index, GLenum(pname), &value);
+            return QVariant::fromValue(value);
+        }
+        break;
+        case VERTEX_ATTRIB_ARRAY_TYPE: {
+            GLint value = 0;
+            glGetVertexAttribiv(index, GLenum(pname), &value);
+            return QVariant::fromValue(value);
+        }
+        case VERTEX_ATTRIB_ARRAY_NORMALIZED: {
+            GLint value = 0;
+            glGetVertexAttribiv(index, GLenum(pname), &value);
+            return QVariant::fromValue( bool(value));
+        }
+        case CURRENT_VERTEX_ATTRIB: {
+            // TODO: Should be Float32Array
+            GLfloat values[4];
+            glGetVertexAttribfv(index, GLenum(pname), values);
+
+            QList<float> floatList;
+            floatList.push_back(values[0]);
+            floatList.push_back(values[1]);
+            floatList.push_back(values[2]);
+            floatList.push_back(values[3]);
+            return QVariant::fromValue(floatList);
+            }
+        default:
+            if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__
+                                         << ":INVALID_ENUM index must be smaller than "
+                                         << "MAX_VERTEX_ATTRIBS = " << MAX_VERTEX_ATTRIBS;
+            m_error = INVALID_ENUM;
+        }
+    }
+
+    return QVariant();
+}
+
 /*!
- * \qmlmethod list<variant> Context3D::getUniform(Program3D program, UniformLocation3D location)
+ * \qmlmethod variant Context3D::getUniform(Program3D program, UniformLocation3D location)
  * Returns the uniform value at the given \a location in the \a program.
  * The type returned is dependent on the uniform type, as shown in the table:
  * \table
@@ -4751,7 +4909,7 @@ QVariant CanvasContext::getTexParameter(glEnums target, glEnums pname)
 /*!
  * \internal
  */
-QVariantList CanvasContext::getUniform(CanvasProgram *program, CanvasUniformLocation *location)
+QVariant CanvasContext::getUniform(CanvasProgram *program, CanvasUniformLocation *location)
 {
     if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__
                                 << "(program" << program
@@ -4779,9 +4937,11 @@ QVariantList CanvasContext::getUniform(CanvasProgram *program, CanvasUniformLoca
             // Intentional flow through
         case SAMPLER_CUBE:
             // Intentional flow through
-        case INT:
-            numValues--;
-            // Intentional flow through
+        case INT: {
+            GLint value = 0;
+            glGetUniformiv(programId, locationId, &value);
+            return QVariant::fromValue(value);
+        }
         case INT_VEC2:
             numValues--;
             // Intentional flow through
@@ -4789,17 +4949,22 @@ QVariantList CanvasContext::getUniform(CanvasProgram *program, CanvasUniformLoca
             numValues--;
             // Intentional flow through
         case INT_VEC4: {
-            // TODO: Should return Int32Array
+            numValues--;
             GLint *value = new GLint[numValues];
             glGetUniformiv(programId, locationId, value);
-            QVariantList list;
+
+            QList<float> intList;
             for (int i = 0; i < numValues; i++)
-                list << QVariant(value[i]);
-            return list;
+                intList << value[i];
+
+            // TODO: Should return Int32Array
+            return QVariant::fromValue(intList);
+        }
+        case FLOAT: {
+            GLfloat value = 0;
+            glGetUniformfv(programId, locationId, &value);
+            return QVariant::fromValue(value);
         }
-        case FLOAT:
-            numValues--;
-            // Intentional flow through
         case FLOAT_VEC2:
             numValues--;
             // Intentional flow through
@@ -4807,18 +4972,23 @@ QVariantList CanvasContext::getUniform(CanvasProgram *program, CanvasUniformLoca
             numValues--;
             // Intentional flow through
         case FLOAT_VEC4: {
-            // TODO: Should return Float32Array
+            numValues--;
             GLfloat *value = new GLfloat[numValues];
+
             glGetUniformfv(programId, locationId, value);
-            QVariantList list;
-            for (int i = 0; i < numValues; i++) {
-                list << QVariant(value[i]);
-            }
-            return list;
+
+            QList<float> floatList;
+            for (int i = 0; i < numValues; i++)
+                floatList << value[i];
+
+            // TODO: Should return Float32Array
+            return QVariant::fromValue(floatList);
+        }
+        case BOOL: {
+            GLint value = 0;
+            glGetUniformiv(programId, locationId, &value);
+            return QVariant::fromValue(bool(value));
         }
-        case BOOL:
-            numValues--;
-            // Intentional flow through
         case BOOL_VEC2:
             numValues--;
             // Intentional flow through
@@ -4826,12 +4996,16 @@ QVariantList CanvasContext::getUniform(CanvasProgram *program, CanvasUniformLoca
             numValues--;
             // Intentional flow through
         case BOOL_VEC4: {
+            numValues--;
             GLint *value = new GLint[numValues];
+
             glGetUniformiv(programId, locationId, value);
-            QVariantList list;
+
+            QList<bool> boolList;
             for (int i = 0; i < numValues; i++)
-                list << QVariant(bool(value[i]));
-            return list;
+                boolList << value[i];
+
+            return QVariant::fromValue(boolList);
         }
         case FLOAT_MAT2:
             numValues--;
@@ -4841,19 +5015,21 @@ QVariantList CanvasContext::getUniform(CanvasProgram *program, CanvasUniformLoca
             // Intentional flow through
         case FLOAT_MAT4: {
             numValues = numValues * numValues;
-            // TODO: Should return Float32Array
-            qDebug() << "Context3D::" << __FUNCTION__ << " numValues = " << numValues;
             GLfloat *value = new GLfloat[numValues];
+
             glGetUniformfv(programId, locationId, value);
-            QVariantList list;
+
+            QList<float> floatList;
             for (int i = 0; i < numValues; i++)
-                list << QVariant(value[i]);
-            return list;
+                floatList << value[i];
+
+            // TODO: Should return Float32Array
+            return QVariant::fromValue(floatList);
         }
         default:
             break;
         }
     }
 
-    return QVariantList();
+    return QVariant();
 }
diff --git a/src/context3d_p.h b/src/context3d_p.h
index 8e762e7280b4756622bd1f2e108d10768550c4b0..19a45c5baa6ce1dd448984a25c7357786924b824 100644
--- a/src/context3d_p.h
+++ b/src/context3d_p.h
@@ -1170,7 +1170,9 @@ public:
     Q_INVOKABLE int getFramebufferAttachmentParameter(glEnums target, glEnums attachment, glEnums pname);
     Q_INVOKABLE int getRenderbufferParameter(glEnums target, glEnums pname);
     Q_INVOKABLE QVariant getTexParameter(glEnums target, glEnums pname);
-    Q_INVOKABLE QVariantList getUniform(CanvasProgram *program, CanvasUniformLocation *location);
+    Q_INVOKABLE QVariant getUniform(CanvasProgram *program, CanvasUniformLocation *location);
+    Q_INVOKABLE uint getVertexAttribOffset(uint index, glEnums pname);
+    Q_INVOKABLE QVariant getVertexAttrib(uint index, glEnums pname);
 
     QString glEnumToString(glEnums value) const;
     float devicePixelRatio();
@@ -1181,12 +1183,6 @@ public:
     QRect glViewportRect() const;
     GLuint currentFramebuffer();
 
-    /*
-    TODO: Add these missing functions
-    any getVertexAttrib(GLuint index, GLenum pname);
-    GLsizeiptr getVertexAttribOffset(GLuint index, GLenum pname);
-    */
-
     void setLogAllCalls(bool logCalls);
     bool logAllCalls() const;
     void setLogAllErrors(bool logErrors);
@@ -1203,7 +1199,6 @@ signals:
     void drawingBufferHeightChanged();
 
 private:
-
     bool m_unpackFlipYEnabled;
     bool m_unpackPremultiplyAlphaEnabled;
     glEnums m_unpackColorspaceConversion;
@@ -1212,6 +1207,7 @@ private:
     bool m_logAllErrors;
     QRect m_glViewportRect;
 
+
     qreal m_devicePixelRatio;
     CanvasProgram *m_currentProgram;
     CanvasBuffer *m_currentArrayBuffer;
@@ -1222,11 +1218,14 @@ private:
     CanvasFrameBuffer *m_currentFramebuffer;
     CanvasRenderBuffer *m_currentRenderbuffer;
     CanvasContextAttributes m_contextAttributes;
+    QMap<int, CanvasBuffer*> m_idToCanvasBufferMap;
     friend class Canvas;
     friend class QFBOCanvas3D;
     QString m_emptyString;
     EnumToStringMap *m_map;
     Canvas *m_canvas;
+    uint m_maxVertexAttribs;
+    float **m_vertexAttribPointers;
 };
 
 #endif // CONTEXT3D_P_H
diff --git a/src/qcanvas3d_plugin.h b/src/qcanvas3d_plugin.h
index 7b7f43df3ed63264699ef2d74cad0cbe68c59186..72f9d81d2557edf4ab044721dff33391b984b5b8 100644
--- a/src/qcanvas3d_plugin.h
+++ b/src/qcanvas3d_plugin.h
@@ -67,6 +67,8 @@
 
 #include <QQmlExtensionPlugin>
 
+Q_DECLARE_METATYPE(CanvasBuffer)
+
 QML_DECLARE_TYPE(Canvas)
 //QML_DECLARE_TYPE(QFBOCanvas3D)
 QML_DECLARE_TYPE(CanvasContext)
diff --git a/src/teximage3dloader.cpp b/src/teximage3dloader.cpp
index a7125f33808810627d9f67f7cf2322fc421c0129..049b14673d0f4ebaa3b2b211328a21ae6015eace 100644
--- a/src/teximage3dloader.cpp
+++ b/src/teximage3dloader.cpp
@@ -72,7 +72,9 @@
 CanvasTextureImageLoader::CanvasTextureImageLoader(QObject *parent) :
     QObject(parent),
     m_logAllCalls(false),
-    m_logAllErrors(true)
+    m_logAllErrors(true),
+    m_image(0),
+    m_canvas(0)
 {
 }