diff --git a/src/context3d.cpp b/src/context3d.cpp
index 0a088898feeafaa8e71b78108541e1acc8353859..b573c171e8f171a48e16ec82c443fb53013f531a 100644
--- a/src/context3d.cpp
+++ b/src/context3d.cpp
@@ -92,7 +92,7 @@ CanvasContext::CanvasContext(QOpenGLContext *context, QSurface *surface, QQmlEng
     m_currentRenderbuffer(0),
     m_context(context),
     m_surface(surface),
-    m_error(NO_ERROR),
+    m_error(CANVAS_NO_ERRORS),
     m_map(EnumToStringMap::newInstance()),
     m_canvas(0),
     m_maxVertexAttribs(0),
@@ -210,6 +210,27 @@ void CanvasContext::logAllGLErrors(const QString &funcName)
 
     GLenum err;
     while ((err = glGetError()) != GL_NO_ERROR) {
+        // Merge any GL errors with internal errors so that we don't lose them
+        switch (err) {
+        case GL_INVALID_ENUM:
+            m_error |= CANVAS_INVALID_ENUM;
+            break;
+        case GL_INVALID_VALUE:
+            m_error |= CANVAS_INVALID_VALUE;
+            break;
+        case GL_INVALID_OPERATION:
+            m_error |= CANVAS_INVALID_OPERATION;
+            break;
+        case GL_OUT_OF_MEMORY:
+            m_error |= CANVAS_OUT_OF_MEMORY;
+            break;
+        case GL_INVALID_FRAMEBUFFER_OPERATION:
+            m_error |= CANVAS_INVALID_FRAMEBUFFER_OPERATION;
+            break;
+        default:
+            break;
+        }
+
         qCWarning(canvas3dglerrors).nospace() << "Context3D::" << funcName
                                               << ": OpenGL ERROR: "
                                               << glEnumToString(CanvasContext::glEnums(err));
@@ -408,7 +429,7 @@ void CanvasContext::deleteTexture(QJSValue texture3D)
         texture->del();
         logAllGLErrors(__FUNCTION__);
     } else {
-        m_error = INVALID_VALUE;
+        m_error |= CANVAS_INVALID_VALUE;
         qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
                                                << ":INVALID texture handle:" << texture3D.toString();
     }
@@ -516,13 +537,13 @@ void CanvasContext::generateMipmap(glEnums target)
     if (target == TEXTURE_2D) {
         if (!m_currentTexture2D) {
             qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
-                                                   << ":INVALID_OPERATION No current TEXTURE_2D bound";
-            m_error = INVALID_OPERATION;
+                                                   << ":INVALID_OPERATION:No current TEXTURE_2D bound";
+            m_error |= CANVAS_INVALID_OPERATION;
         } else if (!m_currentTexture2D->isAlive()) {
             qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
-                                                   << ":INVALID_OPERATION "
+                                                   << ":INVALID_OPERATION:"
                                                    << "Currently bound TEXTURE_2D is deleted";
-            m_error = INVALID_OPERATION;
+            m_error |= CANVAS_INVALID_OPERATION;
         } else {
             glGenerateMipmap(target);
             logAllGLErrors(__FUNCTION__);
@@ -530,14 +551,14 @@ void CanvasContext::generateMipmap(glEnums target)
     } else if (target == TEXTURE_CUBE_MAP) {
         if (!m_currentTextureCubeMap) {
             qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
-                                                   << ":INVALID_OPERATION "
+                                                   << ":INVALID_OPERATION:"
                                                    << "No current TEXTURE_CUBE_MAP bound";
-            m_error = INVALID_OPERATION;
+            m_error |= CANVAS_INVALID_OPERATION;
         } else if (!m_currentTextureCubeMap->isAlive()) {
             qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
-                                                   << ":INVALID_OPERATION "
+                                                   << ":INVALID_OPERATION:"
                                                    << "Currently bound TEXTURE_CUBE_MAP is deleted";
-            m_error = INVALID_OPERATION;
+            m_error |= CANVAS_INVALID_OPERATION;
         } else {
             glGenerateMipmap(target);
             logAllGLErrors(__FUNCTION__);
@@ -609,29 +630,29 @@ void CanvasContext::compressedTexImage2D(glEnums target, int level, glEnums inte
     if (target == TEXTURE_2D) {
         if (!m_currentTexture2D) {
             qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
-                                                   << ":INVALID_OPERATION "
+                                                   << ":INVALID_OPERATION:"
                                                    << "No current TEXTURE_2D bound";
-            m_error = INVALID_OPERATION;
+            m_error |= CANVAS_INVALID_OPERATION;
             return;
         } else if (!m_currentTexture2D->isAlive()) {
             qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
-                                                   << ":INVALID_OPERATION "
+                                                   << ":INVALID_OPERATION:"
                                                    << "Currently bound TEXTURE_2D is deleted";
-            m_error = INVALID_OPERATION;
+            m_error |= CANVAS_INVALID_OPERATION;
             return;
         }
     } else if (target == TEXTURE_CUBE_MAP) {
         if (!m_currentTextureCubeMap) {
             qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
-                                                   << ":INVALID_OPERATION "
+                                                   << ":INVALID_OPERATION:"
                                                    << "No current TEXTURE_CUBE_MAP bound";
-            m_error = INVALID_OPERATION;
+            m_error |= CANVAS_INVALID_OPERATION;
             return;
         } else if (!m_currentTextureCubeMap->isAlive()) {
             qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
-                                                   << ":INVALID_OPERATION "
+                                                   << ":INVALID_OPERATION:"
                                                    << "Currently bound TEXTURE_CUBE_MAP is deleted";
-            m_error = INVALID_OPERATION;
+            m_error |= CANVAS_INVALID_OPERATION;
             return;
         }
     }
@@ -650,8 +671,8 @@ void CanvasContext::compressedTexImage2D(glEnums target, int level, glEnums inte
         logAllGLErrors(__FUNCTION__);
     } else {
         qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
-                                               << ":INVALID_VALUE pixels must be TypedArray";
-        m_error = INVALID_VALUE;
+                                               << ":INVALID_VALUE:pixels must be TypedArray";
+        m_error |= CANVAS_INVALID_VALUE;
         return;
     }
 }
@@ -685,28 +706,29 @@ void CanvasContext::compressedTexSubImage2D(glEnums target, int level,
     if (target == TEXTURE_2D) {
         if (!m_currentTexture2D) {
             qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
-                                                   << ":INVALID_OPERATION No current TEXTURE_2D bound";
-            m_error = INVALID_OPERATION;
+                                                   << ":INVALID_OPERATION:"
+                                                   << "No current TEXTURE_2D bound";
+            m_error |= CANVAS_INVALID_OPERATION;
             return;
         } else if (!m_currentTexture2D->isAlive()) {
             qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
-                                                   << ":INVALID_OPERATION "
+                                                   << ":INVALID_OPERATION:"
                                                    << "Currently bound TEXTURE_2D is deleted";
-            m_error = INVALID_OPERATION;
+            m_error |= CANVAS_INVALID_OPERATION;
             return;
         }
     } else if (target == TEXTURE_CUBE_MAP) {
         if (!m_currentTextureCubeMap) {
             qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
-                                                   << ":INVALID_OPERATION "
+                                                   << ":INVALID_OPERATION:"
                                                    << "No current TEXTURE_CUBE_MAP bound";
-            m_error = INVALID_OPERATION;
+            m_error |= CANVAS_INVALID_OPERATION;
             return;
         } else if (!m_currentTextureCubeMap->isAlive()) {
             qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
-                                                   << ":INVALID_OPERATION "
+                                                   << ":INVALID_OPERATION:"
                                                    << "Currently bound TEXTURE_CUBE_MAP is deleted";
-            m_error = INVALID_OPERATION;
+            m_error |= CANVAS_INVALID_OPERATION;
             return;
         }
     }
@@ -726,8 +748,8 @@ void CanvasContext::compressedTexSubImage2D(glEnums target, int level,
         logAllGLErrors(__FUNCTION__);
     } else {
         qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
-                                               << ":INVALID_VALUE pixels must be TypedArray";
-        m_error = INVALID_VALUE;
+                                               << ":INVALID_VALUE:pixels must be TypedArray";
+        m_error |= CANVAS_INVALID_VALUE;
         return;
     }
 }
@@ -775,12 +797,14 @@ void CanvasContext::copyTexImage2D(glEnums target, int level, glEnums internalfo
 
     if (!m_currentTexture2D) {
         qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
-                                               << ":INVALID_OPERATION No current texture bound";
-        m_error = INVALID_OPERATION;
+                                               << ":INVALID_OPERATION:"
+                                               << "No current texture bound";
+        m_error |= CANVAS_INVALID_OPERATION;
     } else if (!m_currentTexture2D->isAlive()) {
         qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
-                                               << ":INVALID_OPERATION Currently bound texture is deleted";
-        m_error = INVALID_OPERATION;
+                                               << ":INVALID_OPERATION:"
+                                               << "Currently bound texture is deleted";
+        m_error |= CANVAS_INVALID_OPERATION;
     } else {
         glCopyTexImage2D(target, level, internalformat, x, y, width, height, border);
         logAllGLErrors(__FUNCTION__);
@@ -827,12 +851,14 @@ void CanvasContext::copyTexSubImage2D(glEnums target, int level,
 
     if (!m_currentTexture2D) {
         qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
-                                               << ":INVALID_OPERATION No current texture bound";
-        m_error = INVALID_OPERATION;
+                                               << ":INVALID_OPERATION:"
+                                               << "No current texture bound";
+        m_error |= CANVAS_INVALID_OPERATION;
     } else if (!m_currentTexture2D->isAlive()) {
         qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
-                                               << ":INVALID_OPERATION Currently bound texture is deleted";
-        m_error = INVALID_OPERATION;
+                                               << ":INVALID_OPERATION:"
+                                               << "Currently bound texture is deleted";
+        m_error |= CANVAS_INVALID_OPERATION;
     } else {
         copyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
         logAllGLErrors(__FUNCTION__);
@@ -888,14 +914,15 @@ void CanvasContext::texImage2D(glEnums target, int level, glEnums internalformat
     if (!m_currentTexture2D) {
         qCWarning(canvas3drendering).nospace() << "Context3D::"
                                                << __FUNCTION__
-                                               << ":INVALID_OPERATION No current texture bound";
-        m_error = INVALID_OPERATION;
+                                               << ":INVALID_OPERATION:"
+                                               << "No current texture bound";
+        m_error |= CANVAS_INVALID_OPERATION;
         return;
     } else if (!m_currentTexture2D->isAlive()) {
         qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
                                                << ":INVALID_OPERATION:"
-                                               << " Currently bound texture is deleted";
-        m_error = INVALID_OPERATION;
+                                               << "Currently bound texture is deleted";
+        m_error |= CANVAS_INVALID_OPERATION;
         return;
     }
 
@@ -936,7 +963,7 @@ void CanvasContext::texImage2D(glEnums target, int level, glEnums internalformat
         if (bytesPerPixel == 0) {
             m_error = INVALID_ENUM;
             qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
-                                                   << ":INVALID_ENUM Invalid format supplied "
+                                                   << ":INVALID_ENUM:Invalid format supplied "
                                                    << glEnumToString(format);
             return;
         }
@@ -947,9 +974,9 @@ void CanvasContext::texImage2D(glEnums target, int level, glEnums internalformat
         if (!srcData) {
             qCWarning(canvas3drendering).nospace() << "Context3D::"
                                                    << __FUNCTION__
-                                                   << ":INVALID_OPERATION Expected Uint8Array,"
+                                                   << ":INVALID_OPERATION:Expected Uint8Array,"
                                                    << " received " << pixels.toString();
-            m_error = INVALID_OPERATION;
+            m_error |= CANVAS_INVALID_OPERATION;
             return;
         }
 
@@ -968,9 +995,9 @@ void CanvasContext::texImage2D(glEnums target, int level, glEnums internalformat
         if (!srcData) {
             qCWarning(canvas3drendering).nospace() << "Context3D::"
                                                    << __FUNCTION__
-                                                   << ":INVALID_OPERATION Expected Uint16Array,"
+                                                   << ":INVALID_OPERATION:Expected Uint16Array,"
                                                    << " received " << pixels.toString();
-            m_error = INVALID_OPERATION;
+            m_error |= CANVAS_INVALID_OPERATION;
             return;
         }
         unpackedData = unpackPixels(srcData, false, 2, width, height);
@@ -982,7 +1009,7 @@ void CanvasContext::texImage2D(glEnums target, int level, glEnums internalformat
     default:
         qCWarning(canvas3drendering).nospace() << "Context3D::"
                                                << __FUNCTION__
-                                               << ":INVALID_ENUM Invalid type enum";
+                                               << ":INVALID_ENUM:Invalid type enum";
         m_error = INVALID_ENUM;
         break;
     }
@@ -1074,21 +1101,21 @@ void CanvasContext::texSubImage2D(glEnums target, int level,
                                          << ")";
     if (!m_currentTexture2D) {
         qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
-                                               << ":INVALID_OPERATION No current texture bound";
-        m_error = INVALID_OPERATION;
+                                               << ":INVALID_OPERATION:No current texture bound";
+        m_error |= CANVAS_INVALID_OPERATION;
         return;
     } else if (!m_currentTexture2D->isAlive()) {
         qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
                                                << ":INVALID_OPERATION:"
-                                               << " Currently bound texture is deleted";
-        m_error = INVALID_OPERATION;
+                                               << "Currently bound texture is deleted";
+        m_error |= CANVAS_INVALID_OPERATION;
         return;
     }
 
     if (pixels.isNull()) {
         qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
-                                               << ":INVALID_VALUE pixels was null";
-        m_error = INVALID_VALUE;
+                                               << ":INVALID_VALUE:pixels was null";
+        m_error |= CANVAS_INVALID_VALUE;
         return;
     }
 
@@ -1121,7 +1148,7 @@ void CanvasContext::texSubImage2D(glEnums target, int level,
         if (bytesPerPixel == 0) {
             m_error = INVALID_ENUM;
             qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
-                                                   << ":INVALID_ENUM Invalid format supplied "
+                                                   << ":INVALID_ENUM:Invalid format "
                                                    << glEnumToString(format);
             return;
         }
@@ -1130,9 +1157,9 @@ void CanvasContext::texSubImage2D(glEnums target, int level,
         if (!srcData) {
             qCWarning(canvas3drendering).nospace() << "Context3D::"
                                                    << __FUNCTION__
-                                                   << ":INVALID_OPERATION Expected Uint8Array,"
+                                                   << ":INVALID_OPERATION:Expected Uint8Array,"
                                                    << " received " << pixels.toString();
-            m_error = INVALID_OPERATION;
+            m_error |= CANVAS_INVALID_OPERATION;
             return;
         }
 
@@ -1148,9 +1175,9 @@ void CanvasContext::texSubImage2D(glEnums target, int level,
         if (!srcData) {
             qCWarning(canvas3drendering).nospace() << "Context3D::"
                                                    << __FUNCTION__
-                                                   << ":INVALID_OPERATION Expected Uint16Array, "
+                                                   << ":INVALID_OPERATION:Expected Uint16Array, "
                                                    << "received " << pixels.toString();
-            m_error = INVALID_OPERATION;
+            m_error |= CANVAS_INVALID_OPERATION;
             return;
         }
         unpackedData = unpackPixels(srcData, false, 2, width, height);
@@ -1160,7 +1187,7 @@ void CanvasContext::texSubImage2D(glEnums target, int level,
         break;
     default:
         qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
-                                               << ":INVALID_ENUM Invalid type enum";
+                                               << ":INVALID_ENUM:Invalid type enum";
         m_error = INVALID_ENUM;
         break;
     }
@@ -1253,14 +1280,14 @@ void CanvasContext::texImage2D(glEnums target, int level, glEnums internalformat
     if (!m_currentTexture2D) {
         qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
                                                << ":INVALID_OPERATION:"
-                                               << " No current texture bound";
-        m_error = INVALID_OPERATION;
+                                               << "No current texture bound";
+        m_error |= CANVAS_INVALID_OPERATION;
         return;
     } else if (!m_currentTexture2D->isAlive()) {
         qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
                                                << ":INVALID_OPERATION:"
-                                               << " Currently bound texture is deleted";
-        m_error = INVALID_OPERATION;
+                                               << "Currently bound texture is deleted";
+        m_error |= CANVAS_INVALID_OPERATION;
         return;
     }
 
@@ -1268,8 +1295,8 @@ void CanvasContext::texImage2D(glEnums target, int level, glEnums internalformat
     if (!image) {
         qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
                                                << ":INVALID_VALUE:"
-                                               << " invalid texImage " << texImage.toString();
-        m_error = INVALID_VALUE;
+                                               << "Invalid texImage " << texImage.toString();
+        m_error |= CANVAS_INVALID_VALUE;
         return;
     }
 
@@ -1285,7 +1312,7 @@ void CanvasContext::texImage2D(glEnums target, int level, glEnums internalformat
         break;
     default:
         qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
-                                               << ":INVALID_ENUM Invalid type enum";
+                                               << ":INVALID_ENUM:Invalid type enum";
         m_error = INVALID_ENUM;
         return;
     }
@@ -1359,23 +1386,23 @@ void CanvasContext::texSubImage2D(glEnums target, int level,
 
     if (!m_currentTexture2D) {
         qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
-                                               << ":INVALID_OPERATION No current texture bound";
-        m_error = INVALID_OPERATION;
+                                               << ":INVALID_OPERATION:No current texture bound";
+        m_error |= CANVAS_INVALID_OPERATION;
         return;
     } else if (!m_currentTexture2D->isAlive()) {
         qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
                                                << ":INVALID_OPERATION:"
-                                               << " Currently bound texture is deleted";
-        m_error = INVALID_OPERATION;
+                                               << "Currently bound texture is deleted";
+        m_error |= CANVAS_INVALID_OPERATION;
         return;
     }
 
     CanvasTextureImage *image = getAsTextureImage(texImage);
     if (!image) {
         qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
-                                               << ":INVALID_VALUE invalid texImage "
+                                               << ":INVALID_VALUE:invalid texImage "
                                                << texImage.toString();
-        m_error = INVALID_VALUE;
+        m_error |= CANVAS_INVALID_VALUE;
         return;
     }
 
@@ -1395,7 +1422,7 @@ void CanvasContext::texSubImage2D(glEnums target, int level,
         break;
     default:
         qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
-                                               << ":INVALID_ENUM Invalid type enum";
+                                               << ":INVALID_ENUM:Invalid type enum";
         m_error = INVALID_ENUM;
         return;
     }
@@ -1434,14 +1461,14 @@ void CanvasContext::texParameterf(glEnums target, glEnums pname, float param)
 
     if (!m_currentTexture2D) {
         qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
-                                               << ":INVALID_OPERATION No current texture bound";
-        m_error = INVALID_OPERATION;
+                                               << ":INVALID_OPERATION:No current texture bound";
+        m_error |= CANVAS_INVALID_OPERATION;
         return;
     } else if (!m_currentTexture2D->isAlive()) {
         qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
                                                << ":INVALID_OPERATION:"
                                                << " Currently bound texture is deleted";
-        m_error = INVALID_OPERATION;
+        m_error |= CANVAS_INVALID_OPERATION;
         return;
     }
 
@@ -1471,14 +1498,14 @@ void CanvasContext::texParameteri(glEnums target, glEnums pname, int param)
                                          << ")";
     if (!m_currentTexture2D) {
         qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
-                                               << ":INVALID_OPERATION No current texture bound";
-        m_error = INVALID_OPERATION;
+                                               << ":INVALID_OPERATION:No current texture bound";
+        m_error |= CANVAS_INVALID_OPERATION;
         return;
     } else if (!m_currentTexture2D->isAlive()) {
         qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
                                                << ":INVALID_OPERATION:"
                                                << " Currently bound texture is deleted";
-        m_error = INVALID_OPERATION;
+        m_error |= CANVAS_INVALID_OPERATION;
         return;
     }
 
@@ -1592,7 +1619,7 @@ CanvasContext::glEnums CanvasContext::checkFramebufferStatus(glEnums target)
     } else {
         qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
                                                << ": INVALID_OPERATION no current framebuffer bound";
-        m_error = INVALID_OPERATION;
+        m_error |= CANVAS_INVALID_OPERATION;
         return FRAMEBUFFER_UNSUPPORTED;
     }
 }
@@ -1628,7 +1655,7 @@ void CanvasContext::framebufferRenderbuffer(glEnums target, glEnums attachment,
     if (!m_currentFramebuffer) {
         qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
                                                << "(): INVALID_OPERATION no framebuffer bound";
-        m_error = INVALID_OPERATION;
+        m_error |= CANVAS_INVALID_OPERATION;
         return;
     }
 
@@ -1640,7 +1667,7 @@ void CanvasContext::framebufferRenderbuffer(glEnums target, glEnums attachment,
                                                << "(): INVALID_OPERATION attachment must be one of "
                                                << "COLOR_ATTACHMENT0, DEPTH_ATTACHMENT, "
                                                << "STENCIL_ATTACHMENT or DEPTH_STENCIL_ATTACHMENT";
-        m_error = INVALID_OPERATION;
+        m_error |= CANVAS_INVALID_OPERATION;
         return;
     }
 
@@ -1649,7 +1676,7 @@ void CanvasContext::framebufferRenderbuffer(glEnums target, glEnums attachment,
         qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
                                                << "(): INVALID_OPERATION renderbuffertarget must be"
                                                << " RENDERBUFFER for non null renderbuffers";
-        m_error = INVALID_OPERATION;
+        m_error |= CANVAS_INVALID_OPERATION;
         return;
     }
 
@@ -1694,7 +1721,7 @@ void CanvasContext::framebufferTexture2D(glEnums target, glEnums attachment, glE
         qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
                                                << "(): INVALID_OPERATION:"
                                                << " no current framebuffer bound";
-        m_error = INVALID_OPERATION;
+        m_error |= CANVAS_INVALID_OPERATION;
         return;
     }
 
@@ -1704,7 +1731,7 @@ void CanvasContext::framebufferTexture2D(glEnums target, glEnums attachment, glE
                                                << "(): INVALID_OPERATION attachment must be one of "
                                                << "COLOR_ATTACHMENT0, DEPTH_ATTACHMENT"
                                                << " or STENCIL_ATTACHMENT";
-        m_error = INVALID_OPERATION;
+        m_error |= CANVAS_INVALID_OPERATION;
         return;
     }
 
@@ -1725,14 +1752,14 @@ void CanvasContext::framebufferTexture2D(glEnums target, glEnums attachment, glE
                                                    << "TEXTURE_CUBE_MAP_NEGATIVE_X, "
                                                    << "TEXTURE_CUBE_MAP_NEGATIVE_Y or "
                                                    << "TEXTURE_CUBE_MAP_NEGATIVE_Z";
-            m_error = INVALID_OPERATION;
+            m_error |= CANVAS_INVALID_OPERATION;
             return;
         }
 
         if (level != 0) {
             qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
                                                    << "(): INVALID_VALUE level must be 0";
-            m_error = INVALID_VALUE;
+            m_error |= CANVAS_INVALID_VALUE;
             return;
         }
     }
@@ -1803,7 +1830,7 @@ void CanvasContext::deleteFramebuffer(QJSValue buffer)
         fbo->del();
         logAllGLErrors(__FUNCTION__);
     } else {
-        m_error = INVALID_VALUE;
+        m_error |= CANVAS_INVALID_VALUE;
         qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
                                                << "(): INVALID_VALUE buffer handle";
     }
@@ -1953,7 +1980,7 @@ void CanvasContext::deleteRenderbuffer(QJSValue renderbuffer3D)
         renderbuffer->del();
         logAllGLErrors(__FUNCTION__);
     } else {
-        m_error = INVALID_VALUE;
+        m_error |= CANVAS_INVALID_VALUE;
         qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
                                                << "(): INVALID_VALUE renderbuffer handle";
     }
@@ -2054,7 +2081,7 @@ void CanvasContext::deleteProgram(QJSValue program3D)
         program->del();
         logAllGLErrors(__FUNCTION__);
     } else {
-        m_error = INVALID_VALUE;
+        m_error |= CANVAS_INVALID_VALUE;
         qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
                                                << ": INVALID_VALUE program handle:"
                                                << program3D.toString();
@@ -2450,7 +2477,7 @@ void CanvasContext::blendFunc(glEnums sfactor, glEnums dfactor)
          && (dfactor == CONSTANT_ALPHA || dfactor == ONE_MINUS_CONSTANT_ALPHA))
             || ((dfactor == CONSTANT_COLOR || dfactor == ONE_MINUS_CONSTANT_COLOR)
                 && (sfactor == CONSTANT_ALPHA || sfactor == ONE_MINUS_CONSTANT_ALPHA))) {
-        m_error = INVALID_OPERATION;
+        m_error |= CANVAS_INVALID_OPERATION;
         qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
                                                << ": INVALID_OPERATION illegal combination";
         return;
@@ -2513,7 +2540,7 @@ void CanvasContext::blendFuncSeparate(glEnums srcRGB, glEnums dstRGB, glEnums sr
          && (dstRGB == CONSTANT_ALPHA || dstRGB == ONE_MINUS_CONSTANT_ALPHA ))
             || ((dstRGB == CONSTANT_COLOR || dstRGB == ONE_MINUS_CONSTANT_COLOR )
                 && (srcRGB == CONSTANT_ALPHA || srcRGB == ONE_MINUS_CONSTANT_ALPHA ))) {
-        m_error = INVALID_OPERATION;
+        m_error |= CANVAS_INVALID_OPERATION;
         qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
                                                << ": INVALID_OPERATION illegal combination";
         return;
@@ -2597,7 +2624,7 @@ QJSValue CanvasContext::createShader(glEnums type)
         return m_engine->newQObject(new CanvasShader(QOpenGLShader::Fragment, this));
     default:
         qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
-                                               << ":INVALID_ENUM unknown shader type:"
+                                               << ":INVALID_ENUM:unknown shader type:"
                                                << glEnumToString(type);
         m_error = INVALID_ENUM;
         return m_engine->newObject();
@@ -2662,9 +2689,10 @@ void CanvasContext::deleteShader(QJSValue shader3D)
         shader->del();
         logAllGLErrors(__FUNCTION__);
     } else {
-        m_error = INVALID_VALUE;
+        m_error |= CANVAS_INVALID_VALUE;
         qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
-                                               << ": invalid shader handle:" << shader3D.toString();
+                                               << ":INVALID_VALUE:"
+                                               << "Invalid shader handle:" << shader3D.toString();
     }
 }
 
@@ -2691,9 +2719,10 @@ void CanvasContext::shaderSource(QJSValue shader3D, const QString &shaderSource)
 
     CanvasShader *shader = getAsShader3D(shader3D);
     if (!shader) {
-        m_error = INVALID_VALUE;
+        m_error |= CANVAS_INVALID_VALUE;
         qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
-                                               << ": invalid shader handle:" << shader3D.toString();
+                                               << ":INVALID_VALUE:"
+                                               << "Invalid shader handle:" << shader3D.toString();
         return;
     }
 
@@ -2717,9 +2746,10 @@ QJSValue CanvasContext::getShaderSource(QJSValue shader3D)
 
     CanvasShader *shader = getAsShader3D(shader3D);
     if (!shader) {
-        m_error = INVALID_VALUE;
+        m_error |= CANVAS_INVALID_VALUE;
         qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
-                                               <<": invalid shader handle:" << shader3D.toString();
+                                               << ":INVALID_VALUE:"
+                                               << "Invalid shader handle:" << shader3D.toString();
         return m_engine->newObject();
     }
 
@@ -2740,9 +2770,10 @@ void CanvasContext::compileShader(QJSValue shader3D)
                                          << ")";
     CanvasShader *shader = getAsShader3D(shader3D);
     if (!shader) {
-        m_error = INVALID_VALUE;
+        m_error |= CANVAS_INVALID_VALUE;
         qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
-                                               << ": invalid shader handle:" << shader3D.toString();
+                                               << ":INVALID_VALUE:"
+                                               << "Invalid shader handle:" << shader3D.toString();
         return;
     }
 
@@ -3629,7 +3660,8 @@ int CanvasContext::getShaderParameter(QJSValue shader3D, glEnums pname)
     CanvasShader *shader = getAsShader3D(shader3D);
     if (!shader) {
         qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
-                                               <<": invalid shader handle:" << shader3D.toString();
+                                               << ":INVALID_VALUE:"
+                                               <<"Invalid shader handle:" << shader3D.toString();
         return 0;
     }
 
@@ -4064,24 +4096,25 @@ void CanvasContext::vertexAttribPointer(int indx, int size, glEnums type,
         qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
                                                << ":INVALID_OPERATION:"
                                                << " No ARRAY_BUFFER currently bound";
-        m_error = INVALID_OPERATION;
+        m_error |= CANVAS_INVALID_OPERATION;
         return;
     }
 
     if (offset < 0) {
         qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
-                                               << ":INVALID_VALUE: Offset must be positive, was "
+                                               << ":INVALID_VALUE:"
+                                               << "Offset must be positive, was "
                                                << offset;
-        m_error = INVALID_VALUE;
+        m_error |= CANVAS_INVALID_VALUE;
         return;
     }
 
     if (stride > 255) {
         qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
-                                               << ":INVALID_VALUE: "
+                                               << ":INVALID_VALUE:"
                                                << "stride must be less than 255, was "
                                                << stride;
-        m_error = INVALID_VALUE;
+        m_error |= CANVAS_INVALID_VALUE;
         return;
     }
 
@@ -4093,40 +4126,40 @@ void CanvasContext::vertexAttribPointer(int indx, int size, glEnums type,
     case UNSIGNED_SHORT:
         if (offset % 2 != 0) {
             qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
-                                                   << ":INVALID_OPERATION: "
+                                                   << ":INVALID_OPERATION:"
                                                    << "offset with UNSIGNED_SHORT"
                                                    << "type must be multiple of 2";
-            m_error = INVALID_OPERATION;
+            m_error |= CANVAS_INVALID_OPERATION;
             return;
         }
         if (stride % 2 != 0) {
             qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
-                                                   << ":INVALID_OPERATION: "
+                                                   << ":INVALID_OPERATION:"
                                                    << "stride with UNSIGNED_SHORT"
                                                    << "type must be multiple of 2";
-            m_error = INVALID_OPERATION;
+            m_error |= CANVAS_INVALID_OPERATION;
             return;
         }
         break;
     case FLOAT:
         if (offset % 4 != 0) {
             qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
-                                                   << ":INVALID_OPERATION: "
+                                                   << ":INVALID_OPERATION:"
                                                    << "offset with FLOAT type must be multiple of 4";
-            m_error = INVALID_OPERATION;
+            m_error |= CANVAS_INVALID_OPERATION;
             return;
         }
         if (stride % 4 != 0) {
             qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
-                                                   << ":INVALID_OPERATION: "
+                                                   << ":INVALID_OPERATION:"
                                                    << "stride with FLOAT type must be multiple of 4";
-            m_error = INVALID_OPERATION;
+            m_error |= CANVAS_INVALID_OPERATION;
             return;
         }
         break;
     default:
         qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
-                                               << ":INVALID_ENUM: "
+                                               << ":INVALID_ENUM:"
                                                << "Invalid type enumeration of "
                                                << glEnumToString(type);
         m_error = INVALID_ENUM;
@@ -4160,24 +4193,24 @@ void CanvasContext::bufferData(glEnums target, long size, glEnums usage)
     case ARRAY_BUFFER:
         if (!m_currentArrayBuffer) {
             qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
-                                                   << ":INVALID_OPERATION called "
-                                                   << "with no ARRAY_BUFFER bound";
-            m_error = INVALID_OPERATION;
+                                                   << ":INVALID_OPERATION:"
+                                                   << "called with no ARRAY_BUFFER bound";
+            m_error |= CANVAS_INVALID_OPERATION;
             return;
         }
         break;
     case ELEMENT_ARRAY_BUFFER:
         if (!m_currentElementArrayBuffer) {
             qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
-                                                   << ":INVALID_OPERATION called with no "
-                                                   << "ELEMENT_ARRAY_BUFFER bound";
-            m_error = INVALID_OPERATION;
+                                                   << ":INVALID_OPERATION:"
+                                                   << "called with no ELEMENT_ARRAY_BUFFER bound";
+            m_error |= CANVAS_INVALID_OPERATION;
             return;
         }
         break;
     default:
         qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
-                                               << ":INVALID_ENUM unknown target";
+                                               << ":INVALID_ENUM:Unknown target";
         m_error = INVALID_ENUM;
         return;
     }
@@ -4206,14 +4239,14 @@ void CanvasContext::bufferData(glEnums target, QJSValue data, glEnums usage)
 
     if (data.isNull()) {
         qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
-                                               << ": INVALID_VALUE called with null data";
-        m_error = INVALID_VALUE;
+                                               << ": INVALID_VALUE:Called with null data";
+        m_error |= CANVAS_INVALID_VALUE;
         return;
     }
 
     if (target != ARRAY_BUFFER && target != ELEMENT_ARRAY_BUFFER) {
         qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
-                                               << ":INVALID_ENUM target must be either ARRAY_BUFFER"
+                                               << ":INVALID_ENUM:Target must be either ARRAY_BUFFER"
                                                << " or ELEMENT_ARRAY_BUFFER.";
         m_error = INVALID_ENUM;
         return;
@@ -4240,9 +4273,9 @@ void CanvasContext::bufferData(glEnums target, QJSValue data, glEnums usage)
         logAllGLErrors(__FUNCTION__);
     } else {
         qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
-                                               << ":INVALID_VALUE data must be either"
+                                               << ":INVALID_VALUE:data must be either"
                                                << "TypedArray or ArrayBuffer";
-        m_error = INVALID_VALUE;
+        m_error |= CANVAS_INVALID_VALUE;
         return;
     }
 }
@@ -4266,7 +4299,7 @@ void CanvasContext::bufferSubData(glEnums target, int offset, QJSValue data)
 
     if (target != ARRAY_BUFFER && target != ELEMENT_ARRAY_BUFFER) {
         qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
-                                               << ":INVALID_ENUM target must be either ARRAY_BUFFER"
+                                               << ":INVALID_ENUM:Target must be either ARRAY_BUFFER"
                                                << " or ELEMENT_ARRAY_BUFFER.";
         m_error = INVALID_ENUM;
         return;
@@ -4274,8 +4307,8 @@ void CanvasContext::bufferSubData(glEnums target, int offset, QJSValue data)
 
     if (data.isNull()) {
         qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
-                                               << ": INVALID_VALUE called with null data";
-        m_error = INVALID_VALUE;
+                                               << ": INVALID_VALUE:Called with null data";
+        m_error |= CANVAS_INVALID_VALUE;
         return;
     }
 
@@ -4299,9 +4332,9 @@ void CanvasContext::bufferSubData(glEnums target, int offset, QJSValue data)
         logAllGLErrors(__FUNCTION__);
     } else {
         qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
-                                               << ":INVALID_VALUE data must be either"
+                                               << ":INVALID_VALUE:data must be either"
                                                << "TypedArray or ArrayBuffer";
-        m_error = INVALID_VALUE;
+        m_error |= CANVAS_INVALID_VALUE;
         return;
     }
 }
@@ -4324,7 +4357,7 @@ QJSValue CanvasContext::getBufferParameter(glEnums target, glEnums pname)
 
     if (target != ARRAY_BUFFER && target != ELEMENT_ARRAY_BUFFER) {
         qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
-                                               << ":INVALID_ENUM target must be either ARRAY_BUFFER"
+                                               << ":INVALID_ENUM:target must be either ARRAY_BUFFER"
                                                << " or ELEMENT_ARRAY_BUFFER.";
         m_error = INVALID_ENUM;
         return m_engine->newObject();
@@ -4342,7 +4375,7 @@ QJSValue CanvasContext::getBufferParameter(glEnums target, glEnums pname)
         break;
     }
 
-    qCWarning(canvas3drendering).nospace() << "getBufferParameter() : UNKNOWN pname";
+    qCWarning(canvas3drendering).nospace() << "getBufferParameter():INVALID_ENUM:Unknown pname";
     m_error = INVALID_ENUM;
     return m_engine->newObject();
 }
@@ -4418,10 +4451,64 @@ void CanvasContext::deleteBuffer(QJSValue buffer3D)
 CanvasContext::glEnums CanvasContext::getError()
 {
     qCDebug(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__;
-    glEnums retVal = m_error;
-    m_error = NO_ERROR;
-    if (retVal == NO_ERROR)
-        retVal = glEnums(glGetError());
+
+    // Merge any GL errors with internal errors
+    switch (glGetError()) {
+    case GL_NO_ERROR:
+        break;
+    case GL_INVALID_ENUM:
+        m_error |= CANVAS_INVALID_ENUM;
+        break;
+    case GL_INVALID_VALUE:
+        m_error |= CANVAS_INVALID_VALUE;
+        break;
+    case GL_INVALID_OPERATION:
+        m_error |= CANVAS_INVALID_OPERATION;
+        break;
+    case GL_OUT_OF_MEMORY:
+        m_error |= CANVAS_OUT_OF_MEMORY;
+        break;
+    case GL_INVALID_FRAMEBUFFER_OPERATION:
+        m_error |= CANVAS_INVALID_FRAMEBUFFER_OPERATION;
+        break;
+#if defined(GL_STACK_OVERFLOW)
+    case GL_STACK_OVERFLOW:
+        qCWarning(canvas3dglerrors).nospace() << "Context3D::" << __FUNCTION__
+                                              << ":GL_STACK_OVERFLOW error ignored";
+        break;
+#endif
+#if defined(GL_STACK_UNDERFLOW)
+    case GL_STACK_UNDERFLOW:
+        qCWarning(canvas3dglerrors).nospace() << "Context3D::" << __FUNCTION__
+                                              << ": GL_CANVAS_STACK_UNDERFLOW error ignored";
+        break;
+#endif
+    default:
+        break;
+    }
+
+    glEnums retVal = NO_ERROR;
+    if (m_error != CANVAS_NO_ERRORS) {
+        // Return set error flags one by one and clear the flags.
+        // Note that stack overflow/underflow flags are never returned.
+        if ((m_error & CANVAS_INVALID_ENUM) != 0) {
+            retVal = INVALID_ENUM;
+            m_error &= ~(CANVAS_INVALID_ENUM);
+        } else if ((m_error & CANVAS_INVALID_VALUE) != 0) {
+            retVal = INVALID_VALUE;
+            m_error &= ~(CANVAS_INVALID_VALUE);
+        }else if ((m_error & CANVAS_INVALID_OPERATION) != 0) {
+            retVal = INVALID_OPERATION;
+            m_error &= ~(CANVAS_INVALID_OPERATION);
+        } else if ((m_error & CANVAS_OUT_OF_MEMORY) != 0) {
+            retVal = OUT_OF_MEMORY;
+            m_error &= ~(CANVAS_OUT_OF_MEMORY);
+        } else if ((m_error & CANVAS_INVALID_FRAMEBUFFER_OPERATION) != 0) {
+            retVal = INVALID_FRAMEBUFFER_OPERATION;
+            m_error &= ~(CANVAS_INVALID_FRAMEBUFFER_OPERATION);
+        }
+    }
+
     return retVal;
 }
 
@@ -4807,7 +4894,7 @@ void CanvasContext::bindBuffer(glEnums target, QJSValue buffer3D)
 
     if (target != ARRAY_BUFFER && target != ELEMENT_ARRAY_BUFFER) {
         qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
-                                               << ":INVALID_ENUM target must be either "
+                                               << ":INVALID_ENUM:target must be either "
                                                << "ARRAY_BUFFER or ELEMENT_ARRAY_BUFFER.";
         m_error = INVALID_ENUM;
         return;
@@ -4821,9 +4908,9 @@ void CanvasContext::bindBuffer(glEnums target, QJSValue buffer3D)
 
             if (buffer->target() != CanvasBuffer::ARRAY_BUFFER) {
                 qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
-                                                       << ":INVALID_OPERATION can't rebind "
+                                                       << ":INVALID_OPERATION:can't rebind "
                                                        << "ELEMENT_ARRAY_BUFFER as ARRAY_BUFFER";
-                m_error = INVALID_OPERATION;
+                m_error |= CANVAS_INVALID_OPERATION;
                 return;
             }
             m_currentArrayBuffer = buffer;
@@ -4833,9 +4920,9 @@ void CanvasContext::bindBuffer(glEnums target, QJSValue buffer3D)
 
             if (buffer->target() != CanvasBuffer::ELEMENT_ARRAY_BUFFER) {
                 qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
-                                                       << ":INVALID_OPERATION can't rebind "
+                                                       << ":INVALID_OPERATION:can't rebind "
                                                        << "ARRAY_BUFFER as ELEMENT_ARRAY_BUFFER";
-                m_error = INVALID_OPERATION;
+                m_error |= CANVAS_INVALID_OPERATION;
                 return;
             }
             m_currentElementArrayBuffer = buffer;
@@ -5161,7 +5248,7 @@ void CanvasContext::drawElements(glEnums mode, int count, glEnums type, long off
         qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
                                                << ":INVALID_OPERATION: "
                                                << "No ELEMENT_ARRAY_BUFFER currently bound";
-        m_error = INVALID_OPERATION;
+        m_error |= CANVAS_INVALID_OPERATION;
         return;
     }
 
@@ -5173,7 +5260,7 @@ void CanvasContext::drawElements(glEnums mode, int count, glEnums type, long off
                                                    << ":INVALID_OPERATION: "
                                                    << "Offset with UNSIGNED_SHORT"
                                                    << "type must be multiple of 2";
-            m_error = INVALID_OPERATION;
+            m_error |= CANVAS_INVALID_OPERATION;
             return;
         }
     case UNSIGNED_BYTE:
@@ -5205,30 +5292,30 @@ void CanvasContext::readPixels(int x, int y, long width, long height, glEnums fo
 {
     if (format != RGBA) {
         qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
-                                               << ":INVALID_ENUM format must be RGBA.";
+                                               << ":INVALID_ENUM:format must be RGBA.";
         m_error = INVALID_ENUM;
         return;
     }
 
     if (type != UNSIGNED_BYTE) {
         qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
-                                               << ":INVALID_ENUM type must be UNSIGNED_BYTE.";
+                                               << ":INVALID_ENUM:type must be UNSIGNED_BYTE.";
         m_error = INVALID_ENUM;
         return;
     }
 
     if (pixels.isNull()) {
         qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
-                                               << ":INVALID_VALUE pixels was null.";
-        m_error = INVALID_VALUE;
+                                               << ":INVALID_VALUE:pixels was null.";
+        m_error |= CANVAS_INVALID_VALUE;
         return;
     }
 
     uchar *bufferPtr = getAsUint8ArrayRawPtr(pixels);
     if (!bufferPtr) {
         qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
-                                               << ":INVALID_OPERATION pixels must be Uint8Array.";
-        m_error = INVALID_OPERATION;
+                                               << ":INVALID_OPERATION:pixels must be Uint8Array.";
+        m_error |= CANVAS_INVALID_OPERATION;
         return;
     }
 
@@ -5652,14 +5739,14 @@ QVariant CanvasContext::getTexParameter(glEnums target, glEnums pname)
     GLint parameter = 0;
     if (!m_currentTexture2D) {
         qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
-                                               << ":INVALID_OPERATION "
+                                               << ":INVALID_OPERATION:"
                                                << "No current texture bound";
-        m_error = INVALID_OPERATION;
+        m_error |= CANVAS_INVALID_OPERATION;
     } else if (!m_currentTexture2D->isAlive()) {
         qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
-                                               << ":INVALID_OPERATION Currently"
+                                               << ":INVALID_OPERATION:Currently"
                                                << " bound texture is deleted";
-        m_error = INVALID_OPERATION;
+        m_error |= CANVAS_INVALID_OPERATION;
     } else {
         switch (pname) {
         case TEXTURE_MAG_FILTER:
@@ -5675,7 +5762,7 @@ QVariant CanvasContext::getTexParameter(glEnums target, glEnums pname)
         default:
             // Intentional flow through
             qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
-                                                   << ":INVALID_ENUM invalid pname "
+                                                   << ":INVALID_ENUM:invalid pname "
                                                    << glEnumToString(pname)
                                                    << " must be one of: TEXTURE_MAG_FILTER, "
                                                    << "TEXTURE_MIN_FILTER, TEXTURE_WRAP_S"
@@ -5713,7 +5800,7 @@ uint CanvasContext::getVertexAttribOffset(uint index, glEnums pname)
     uint offset = 0;
     if (pname != VERTEX_ATTRIB_ARRAY_POINTER) {
         qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
-                                               << ":INVALID_ENUM pname must be "
+                                               << ":INVALID_ENUM:pname must be "
                                                << "VERTEX_ATTRIB_ARRAY_POINTER";
         m_error = INVALID_ENUM;
         return 0;
@@ -5721,9 +5808,9 @@ uint CanvasContext::getVertexAttribOffset(uint index, glEnums pname)
 
     if (index >= m_maxVertexAttribs) {
         qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
-                                               << ":INVALID_VALUE index must be smaller than "
+                                               << ":INVALID_VALUE:index must be smaller than "
                                                << m_maxVertexAttribs;
-        m_error = INVALID_VALUE;
+        m_error |= CANVAS_INVALID_VALUE;
         return 0;
     }
 
@@ -5775,9 +5862,9 @@ QJSValue CanvasContext::getVertexAttrib(uint index, glEnums pname)
 
     if (index >= MAX_VERTEX_ATTRIBS) {
         qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
-                                               << ":INVALID_VALUE index must be smaller than "
+                                               << ":INVALID_VALUE:index must be smaller than "
                                                << "MAX_VERTEX_ATTRIBS = " << MAX_VERTEX_ATTRIBS;
-        m_error = INVALID_VALUE;
+        m_error |= CANVAS_INVALID_VALUE;
     } else {
         switch (pname) {
         case VERTEX_ATTRIB_ARRAY_BUFFER_BINDING: {
@@ -5838,7 +5925,7 @@ QJSValue CanvasContext::getVertexAttrib(uint index, glEnums pname)
         }
         default:
             qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
-                                                   << ":INVALID_ENUM pname " << pname;
+                                                   << ":INVALID_ENUM:pname " << pname;
             m_error = INVALID_ENUM;
         }
     }
@@ -5922,12 +6009,12 @@ QVariant CanvasContext::getUniform(QJSValue program3D, QJSValue location3D)
 
     if (!program) {
         qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
-                                               << ":INVALID_OPERATION No program was specified";
-        m_error = INVALID_OPERATION;
+                                               << ":INVALID_OPERATION:No program was specified";
+        m_error |= CANVAS_INVALID_OPERATION;
     } else  if (!location) {
         qCWarning(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
-                                               << ":INVALID_OPERATION No location3D was specified";
-        m_error = INVALID_OPERATION;
+                                               << ":INVALID_OPERATION:No location3D was specified";
+        m_error |= CANVAS_INVALID_OPERATION;
     } else {
         uint programId = program->id();
         uint locationId = location->id();
diff --git a/src/context3d_p.h b/src/context3d_p.h
index ba42a1cf4c68ea7f0d27ff33e37876af650510f7..9b2364ce4921d1ad237a2f6af58cb0f9edff8723 100644
--- a/src/context3d_p.h
+++ b/src/context3d_p.h
@@ -1214,6 +1214,15 @@ private:
 
     bool isOfType(const QJSValue &value, const QString &classname) const;
 
+    typedef enum {
+        CANVAS_NO_ERRORS = 0,
+        CANVAS_INVALID_ENUM = 1 << 0,
+        CANVAS_INVALID_VALUE = 1 << 1,
+        CANVAS_INVALID_OPERATION = 1 << 2,
+        CANVAS_OUT_OF_MEMORY = 1 << 3,
+        CANVAS_INVALID_FRAMEBUFFER_OPERATION = 1 << 4
+    } errorBits;
+
 private:
     QQmlEngine *m_engine;
     QV4::ExecutionEngine *m_v4engine;
@@ -1231,18 +1240,27 @@ private:
     QOpenGLContext *m_context;
     QSet<QByteArray> m_extensions;
     QSurface *m_surface;
-    glEnums m_error;
     CanvasContextAttributes m_contextAttributes;
     QMap<int, CanvasBuffer*> m_idToCanvasBufferMap;
     friend class Canvas;
     friend class QFBOCanvas3D;
     QString m_emptyString;
+    int m_error;
     EnumToStringMap *m_map;
     Canvas *m_canvas;
     uint m_maxVertexAttribs;
     float **m_vertexAttribPointers;
     bool m_isOpenGLES2;
 
+    bool invalidEnumFlag;
+    bool invalidValueFlag;
+    bool invalidOperationFlag;
+    bool invalidStackOverflowFlag;
+    bool invalidStackUnderflowFlag;
+    bool invalidOutOfMemoryFlag;
+    bool invalidFramebufferFlag;
+    bool invalidContextLostFlag;
+
     // EXTENSIONS
     CanvasGLStateDump *m_stateDumpExt;
     QObject *m_standardDerivatives;