b=573705; fix computation of texel sizes and refactor WebGLenum validation functions; r=vladimir
authorBenoit Jacob <bjacob@mozilla.com>
Wed, 30 Jun 2010 11:49:59 -0400
changeset 46443 1b2684b1c906f24b669c895e57ef92f0e4339220
parent 46442 ef93c10b7d972b54ee291efcc979869f5923ddeb
child 46444 f2b92415cef33d8f4124db18e50aae5d72e24707
push id14191
push userbjacob@mozilla.com
push dateWed, 30 Jun 2010 15:54:52 +0000
treeherdermozilla-central@c6b9defb1972 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersvladimir
bugs573705
milestone2.0b2pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
b=573705; fix computation of texel sizes and refactor WebGLenum validation functions; r=vladimir
content/canvas/src/WebGLContext.h
content/canvas/src/WebGLContextGL.cpp
content/canvas/src/WebGLContextValidate.cpp
--- a/content/canvas/src/WebGLContext.h
+++ b/content/canvas/src/WebGLContext.h
@@ -285,16 +285,19 @@ public:
     NS_IMETHOD SetIsOpaque(PRBool b) { return NS_OK; };
 
     nsresult SynthesizeGLError(WebGLenum err);
     nsresult SynthesizeGLError(WebGLenum err, const char *fmt, ...);
 
     nsresult ErrorInvalidEnum(const char *fmt = 0, ...);
     nsresult ErrorInvalidOperation(const char *fmt = 0, ...);
     nsresult ErrorInvalidValue(const char *fmt = 0, ...);
+    nsresult ErrorInvalidEnumInfo(const char *info) {
+        return ErrorInvalidEnum("%s: invalid enum value", info);
+    }
 
     already_AddRefed<CanvasLayer> GetCanvasLayer(LayerManager *manager);
     void MarkContextClean() { }
 
     // a number that increments every time we have an event that causes
     // all context resources to be lost.
     PRUint32 Generation() { return mGeneration; }
 protected:
@@ -311,24 +314,26 @@ protected:
     PRBool mInvalidated;
 
     WebGLuint mActiveTexture;
     WebGLenum mSynthesizedGLError;
 
     PRBool SafeToCreateCanvas3DContext(nsHTMLCanvasElement *canvasElement);
     PRBool InitAndValidateGL();
     PRBool ValidateBuffers(PRUint32 count);
-    static PRBool ValidateCapabilityEnum(WebGLenum cap);
-    static PRBool ValidateBlendEquationEnum(WebGLuint cap);
-    static PRBool ValidateBlendFuncDstEnum(WebGLuint mode);
-    static PRBool ValidateBlendFuncSrcEnum(WebGLuint mode);
-    static PRBool ValidateTextureTargetEnum(WebGLenum target);
-    static PRBool ValidateComparisonEnum(WebGLenum target);
-    static PRBool ValidateStencilOpEnum(WebGLenum action);
-    static PRBool ValidateFaceEnum(WebGLenum target);
+    PRBool ValidateCapabilityEnum(WebGLenum cap, const char *info);
+    PRBool ValidateBlendEquationEnum(WebGLuint cap, const char *info);
+    PRBool ValidateBlendFuncDstEnum(WebGLuint mode, const char *info);
+    PRBool ValidateBlendFuncSrcEnum(WebGLuint mode, const char *info);
+    PRBool ValidateTextureTargetEnum(WebGLenum target, const char *info);
+    PRBool ValidateComparisonEnum(WebGLenum target, const char *info);
+    PRBool ValidateStencilOpEnum(WebGLenum action, const char *info);
+    PRBool ValidateFaceEnum(WebGLenum target, const char *info);
+    PRBool ValidateTexFormatAndType(WebGLenum format, WebGLenum type,
+                                      PRUint32 *texelSize, const char *info);
 
     void Invalidate();
 
     void MakeContextCurrent() { gl->MakeCurrent(); }
 
     // helpers
     nsresult TexImage2D_base(WebGLenum target, WebGLint level, WebGLenum internalformat,
                              WebGLsizei width, WebGLsizei height, WebGLint border,
--- a/content/canvas/src/WebGLContextGL.cpp
+++ b/content/canvas/src/WebGLContextGL.cpp
@@ -291,57 +291,55 @@ WebGLContext::BindTexture(WebGLenum targ
 
     return NS_OK;
 }
 
 GL_SAME_METHOD_4(BlendColor, BlendColor, float, float, float, float)
 
 NS_IMETHODIMP WebGLContext::BlendEquation(WebGLenum mode)
 {
-    if (!ValidateBlendEquationEnum(mode))
-        return ErrorInvalidEnum("BlendEquation: invalid mode");
+    if (!ValidateBlendEquationEnum(mode, "blendEquation: mode"))
+        return NS_OK;
 
     MakeContextCurrent();
     gl->fBlendEquation(mode);
     return NS_OK;
 }
 
 NS_IMETHODIMP WebGLContext::BlendEquationSeparate(WebGLenum modeRGB, WebGLenum modeAlpha)
 {
-    if (!ValidateBlendEquationEnum(modeRGB) ||
-        !ValidateBlendEquationEnum(modeAlpha))
-        return ErrorInvalidEnum("BlendEquationSeparate: invalid mode");
+    if (!ValidateBlendEquationEnum(modeRGB, "blendEquationSeparate: modeRGB") ||
+        !ValidateBlendEquationEnum(modeAlpha, "blendEquationSeparate: modeAlpha"))
+        return NS_OK;
 
     MakeContextCurrent();
     gl->fBlendEquationSeparate(modeRGB, modeAlpha);
     return NS_OK;
 }
 
 NS_IMETHODIMP WebGLContext::BlendFunc(WebGLenum sfactor, WebGLenum dfactor)
 {
-    if (!ValidateBlendFuncSrcEnum(sfactor))
-        return ErrorInvalidEnum("BlendFunc: invalid source factor");
-    if (!ValidateBlendFuncDstEnum(dfactor))
-        return ErrorInvalidEnum("BlendFunc: invalid destination factor");
+    if (!ValidateBlendFuncSrcEnum(sfactor, "blendFunc: sfactor") ||
+        !ValidateBlendFuncDstEnum(dfactor, "blendFunc: dfactor"))
+        return NS_OK;
 
     MakeContextCurrent();
     gl->fBlendFunc(sfactor, dfactor);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 WebGLContext::BlendFuncSeparate(WebGLenum srcRGB, WebGLenum dstRGB,
                                 WebGLenum srcAlpha, WebGLenum dstAlpha)
 {
-    if (!ValidateBlendFuncSrcEnum(srcRGB) ||
-        !ValidateBlendFuncSrcEnum(srcAlpha))
-        return ErrorInvalidEnum("BlendFuncSeparate: invalid source factor");
-    if (!ValidateBlendFuncDstEnum(dstRGB) ||
-        !ValidateBlendFuncDstEnum(dstAlpha))
-        return ErrorInvalidEnum("BlendFuncSeparate: invalid destination factor");
+    if (!ValidateBlendFuncSrcEnum(srcRGB, "blendFuncSeparate: srcRGB") ||
+        !ValidateBlendFuncSrcEnum(srcAlpha, "blendFuncSeparate: srcAlpha") ||
+        !ValidateBlendFuncDstEnum(dstRGB, "blendFuncSeparate: dstRGB") ||
+        !ValidateBlendFuncDstEnum(dstAlpha, "blendFuncSeparate: dstAlpha"))
+        return NS_OK;
 
     MakeContextCurrent();
     gl->fBlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 WebGLContext::BufferData(PRInt32 dummy)
@@ -802,18 +800,18 @@ WebGLContext::DetachShader(nsIWebGLProgr
     gl->fDetachShader(progname, shadername);
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 WebGLContext::DepthFunc(WebGLenum func)
 {
-    if (!ValidateComparisonEnum(func))
-        return ErrorInvalidEnum("DepthFunc: invalid function enum");
+    if (!ValidateComparisonEnum(func, "depthFunc"))
+        return NS_OK;
 
     MakeContextCurrent();
     gl->fDepthFunc(func);
     return NS_OK;
 }
 
 GL_SAME_METHOD_1(DepthMask, DepthMask, WebGLboolean)
 
@@ -950,28 +948,28 @@ WebGLContext::DrawElements(WebGLenum mod
 
     Invalidate();
 
     return NS_OK;
 }
 
 NS_IMETHODIMP WebGLContext::Enable(WebGLenum cap)
 {
-    if (!ValidateCapabilityEnum(cap))
-        return ErrorInvalidEnum("Enable: invalid capability enum");
+    if (!ValidateCapabilityEnum(cap, "enable"))
+        return NS_OK;
 
     MakeContextCurrent();
     gl->fEnable(cap);
     return NS_OK;
 }
 
 NS_IMETHODIMP WebGLContext::Disable(WebGLenum cap)
 {
-    if (!ValidateCapabilityEnum(cap))
-        return ErrorInvalidEnum("Disable: invalid capability enum");
+    if (!ValidateCapabilityEnum(cap, "disable"))
+        return NS_OK;
 
     MakeContextCurrent();
     gl->fDisable(cap);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 WebGLContext::EnableVertexAttribArray(WebGLuint index)
@@ -1126,18 +1124,18 @@ WebGLContext::GetActiveAttrib(nsIWebGLPr
     js.SetRetVal(retobj);
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 WebGLContext::GenerateMipmap(WebGLenum target)
 {
-    if (!ValidateTextureTargetEnum(target))
-        return ErrorInvalidEnum("GenerateMipmap: invalid target");
+    if (!ValidateTextureTargetEnum(target, "generateMipmap"))
+        return NS_OK;
 
     MakeContextCurrent();
     gl->fGenerateMipmap(target);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 WebGLContext::GetActiveUniform(nsIWebGLProgram *pobj, PRUint32 index, nsIWebGLActiveInfo **retval)
@@ -1850,33 +1848,33 @@ WebGLContext::TexParameter()
 NS_IMETHODIMP
 WebGLContext::GetTexParameter(WebGLenum target, WebGLenum pname, nsIVariant **retval)
 {
     nsCOMPtr<nsIWritableVariant> wrval = do_CreateInstance("@mozilla.org/variant;1");
     NS_ENSURE_TRUE(wrval, NS_ERROR_FAILURE);
 
     MakeContextCurrent();
 
-    if (!ValidateTextureTargetEnum(target))
-        return ErrorInvalidEnum("GetTexParameter: invalid target");
+    if (!ValidateTextureTargetEnum(target, "getTexParameter: target"))
+        return NS_OK;
 
     switch (pname) {
         case LOCAL_GL_TEXTURE_MIN_FILTER:
         case LOCAL_GL_TEXTURE_MAG_FILTER:
         case LOCAL_GL_TEXTURE_WRAP_S:
         case LOCAL_GL_TEXTURE_WRAP_T:
         {
             GLint i = 0;
             gl->fGetTexParameteriv(target, pname, &i);
             wrval->SetAsInt32(i);
         }
             break;
 
         default:
-            return ErrorInvalidEnum("GetTexParameter: invalid parameter");
+            return ErrorInvalidEnum("getTexParameter: invalid parameter");
     }
 
     *retval = wrval.forget().get();
 
     return NS_OK;
 }
 
 /* any getUniform(in WebGLProgram program, in WebGLUniformLocation location) raises(DOMException); */
@@ -2104,19 +2102,19 @@ WebGLContext::IsTexture(nsIWebGLTexture 
     *retval = CheckConversion<WebGLTexture>(tobj, 0, &isDeleted) && !isDeleted;
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 WebGLContext::IsEnabled(WebGLenum cap, WebGLboolean *retval)
 {
-    if (!ValidateCapabilityEnum(cap)) {
+    if (!ValidateCapabilityEnum(cap, "isEnabled")) {
         *retval = 0; // as per the OpenGL ES spec
-        return ErrorInvalidEnum("IsEnabled: invalid capability enum");
+        return NS_OK;
     }
 
     MakeContextCurrent();
     *retval = gl->fIsEnabled(cap);
     return NS_OK;
 }
 
 GL_SAME_METHOD_1(LineWidth, LineWidth, float)
@@ -2408,73 +2406,70 @@ WebGLContext::Scissor(WebGLint x, WebGLi
     MakeContextCurrent();
     gl->fScissor(x, y, width, height);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 WebGLContext::StencilFunc(WebGLenum func, WebGLint ref, WebGLuint mask)
 {
-    if (!ValidateComparisonEnum(func))
-        return ErrorInvalidEnum("StencilFunc: invalid function enum");
+    if (!ValidateComparisonEnum(func, "stencilFunc: func"))
+        return NS_OK;
 
     MakeContextCurrent();
     gl->fStencilFunc(func, ref, mask);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 WebGLContext::StencilFuncSeparate(WebGLenum face, WebGLenum func, WebGLint ref, WebGLuint mask)
 {
-    if (!ValidateFaceEnum(face))
-        return ErrorInvalidEnum("StencilFuncSeparate: invalid face enum");
-    if (!ValidateComparisonEnum(func))
-        return ErrorInvalidEnum("StencilFuncSeparate: invalid function enum");
+    if (!ValidateFaceEnum(face, "stencilFuncSeparate: face") ||
+        !ValidateComparisonEnum(func, "stencilFuncSeparate: func"))
+        return NS_OK;
 
     MakeContextCurrent();
     gl->fStencilFuncSeparate(face, func, ref, mask);
     return NS_OK;
 }
 
 GL_SAME_METHOD_1(StencilMask, StencilMask, WebGLuint)
 
 NS_IMETHODIMP
 WebGLContext::StencilMaskSeparate(WebGLenum face, WebGLuint mask)
 {
-    if (!ValidateFaceEnum(face))
-        return ErrorInvalidEnum("StencilFuncSeparate: invalid face enum");
+    if (!ValidateFaceEnum(face, "stencilMaskSeparate: face"))
+        return NS_OK;
 
     MakeContextCurrent();
     gl->fStencilMaskSeparate(face, mask);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 WebGLContext::StencilOp(WebGLenum sfail, WebGLenum dpfail, WebGLenum dppass)
 {
-    if (!ValidateStencilOpEnum(sfail) ||
-        !ValidateStencilOpEnum(dpfail) ||
-        !ValidateStencilOpEnum(dppass))
-        return ErrorInvalidEnum("StencilOp: invalid action enum");
+    if (!ValidateStencilOpEnum(sfail, "stencilOp: sfail") ||
+        !ValidateStencilOpEnum(dpfail, "stencilOp: dpfail") ||
+        !ValidateStencilOpEnum(dppass, "stencilOp: dppass"))
+        return NS_OK;
 
     MakeContextCurrent();
     gl->fStencilOp(sfail, dpfail, dppass);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 WebGLContext::StencilOpSeparate(WebGLenum face, WebGLenum sfail, WebGLenum dpfail, WebGLenum dppass)
 {
-    if (!ValidateFaceEnum(face))
-        return ErrorInvalidEnum("StencilOpSeparate: invalid face enum");
-
-    if (!ValidateStencilOpEnum(sfail) ||
-        !ValidateStencilOpEnum(dpfail) ||
-        !ValidateStencilOpEnum(dppass))
-        return ErrorInvalidEnum("StencilOpSeparate: invalid action enum");
+    if (!ValidateFaceEnum(face, "stencilOpSeparate: face") ||
+        !ValidateStencilOpEnum(sfail, "stencilOpSeparate: sfail") ||
+        !ValidateStencilOpEnum(dpfail, "stencilOpSeparate: dpfail") ||
+        !ValidateStencilOpEnum(dppass, "stencilOpSeparate: dppass"))
+        return NS_OK;
 
     MakeContextCurrent();
     gl->fStencilOpSeparate(face, sfail, dpfail, dppass);
     return NS_OK;
 }
 
 template<int format>
 inline void convert_pixel(PRUint8* dst, const PRUint8* src)
@@ -3008,72 +3003,31 @@ WebGLContext::TexImage2D_base(WebGLenum 
     switch (internalformat) {
         case LOCAL_GL_RGB:
         case LOCAL_GL_RGBA:
         case LOCAL_GL_ALPHA:
         case LOCAL_GL_LUMINANCE:
         case LOCAL_GL_LUMINANCE_ALPHA:
             break;
         default:
-            return ErrorInvalidValue("TexImage2D: internal format not supported");
+            return ErrorInvalidEnum("TexImage2D: invalid internal format");
     }
 
     if (width < 0 || height < 0)
         return ErrorInvalidValue("TexImage2D: width and height must be >= 0");
 
     if (border != 0)
         return ErrorInvalidValue("TexImage2D: border must be 0");
 
-    // number of bytes per pixel
-    uint32 bufferPixelSize = 0;
-    switch (format) {
-        case LOCAL_GL_RED:
-        case LOCAL_GL_GREEN:
-        case LOCAL_GL_BLUE:
-        case LOCAL_GL_ALPHA:
-        case LOCAL_GL_LUMINANCE:
-            bufferPixelSize = 1;
-            break;
-        case LOCAL_GL_LUMINANCE_ALPHA:
-            bufferPixelSize = 2;
-            break;
-        case LOCAL_GL_RGB:
-            bufferPixelSize = 3;
-            break;
-        case LOCAL_GL_RGBA:
-            bufferPixelSize = 4;
-            break;
-        default:
-            return ErrorInvalidEnum("TexImage2D: pixel format not supported");
-    }
-
-    switch (type) {
-        case LOCAL_GL_BYTE:
-        case LOCAL_GL_UNSIGNED_BYTE:
-            break;
-        case LOCAL_GL_SHORT:
-        case LOCAL_GL_UNSIGNED_SHORT:
-            bufferPixelSize *= 2;
-            break;
-        case LOCAL_GL_INT:
-        case LOCAL_GL_UNSIGNED_INT:
-        case LOCAL_GL_FLOAT:
-            bufferPixelSize *= 4;
-            break;
-        case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
-        case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
-        case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
-            bufferPixelSize *= 2;
-            break;
-        default:
-            return ErrorInvalidEnum("TexImage2D: invalid type argument");
-    }
+    PRUint32 texelSize = 0;
+    if (!ValidateTexFormatAndType(format, type, &texelSize, "texImage2D"))
+        return NS_OK;
 
     // XXX overflow!
-    uint32 bytesNeeded = width * height * bufferPixelSize;
+    uint32 bytesNeeded = width * height * texelSize;
 
     if (byteLength && byteLength < bytesNeeded)
         return ErrorInvalidValue("TexImage2D: not enough data for operation (need %d, have %d)",
                                  bytesNeeded, byteLength);
 
     MakeContextCurrent();
 
     if (byteLength) {
@@ -3188,66 +3142,25 @@ WebGLContext::TexSubImage2D_base(WebGLen
     }
 
     if (level < 0)
         return ErrorInvalidValue("TexSubImage2D: level must be >= 0");
 
     if (width < 0 || height < 0)
         return ErrorInvalidValue("TexSubImage2D: width and height must be > 0!");
 
+    PRUint32 texelSize = 0;
+    if (!ValidateTexFormatAndType(format, type, &texelSize, "texSubImage2D"))
+        return NS_OK;
+
     if (width == 0 || height == 0)
         return NS_OK; // ES 2.0 says it has no effect, we better return right now
 
-    // number of bytes per pixel
-    uint32 bufferPixelSize = 0;
-    switch (format) {
-        case LOCAL_GL_RED:
-        case LOCAL_GL_GREEN:
-        case LOCAL_GL_BLUE:
-        case LOCAL_GL_ALPHA:
-        case LOCAL_GL_LUMINANCE:
-            bufferPixelSize = 1;
-            break;
-        case LOCAL_GL_LUMINANCE_ALPHA:
-            bufferPixelSize = 2;
-            break;
-        case LOCAL_GL_RGB:
-            bufferPixelSize = 3;
-            break;
-        case LOCAL_GL_RGBA:
-            bufferPixelSize = 4;
-            break;
-        default:
-            return ErrorInvalidEnum("TexImage2D: pixel format not supported");
-    }
-
-    switch (type) {
-        case LOCAL_GL_BYTE:
-        case LOCAL_GL_UNSIGNED_BYTE:
-            break;
-        case LOCAL_GL_SHORT:
-        case LOCAL_GL_UNSIGNED_SHORT:
-            bufferPixelSize *= 2;
-            break;
-        case LOCAL_GL_INT:
-        case LOCAL_GL_UNSIGNED_INT:
-        case LOCAL_GL_FLOAT:
-            bufferPixelSize *= 4;
-            break;
-        case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
-        case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
-        case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
-            bufferPixelSize *= 2;
-            break;
-        default:
-            return ErrorInvalidEnum("TexImage2D: invalid type argument");
-    }
-
     // XXX overflow!
-    uint32 bytesNeeded = width * height * bufferPixelSize;
+    uint32 bytesNeeded = width * height * texelSize;
     if (byteLength < bytesNeeded)
         return ErrorInvalidValue("TexSubImage2D: not enough data for operation (need %d, have %d)", bytesNeeded, byteLength);
 
     MakeContextCurrent();
 
     gl->fTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels);
 
     return NS_OK;
--- a/content/canvas/src/WebGLContextValidate.cpp
+++ b/content/canvas/src/WebGLContextValidate.cpp
@@ -120,47 +120,49 @@ WebGLContext::ValidateBuffers(PRUint32 c
             LogMessage("VBO too small for bound attrib index %d: need at least %d bytes, but have only %d", i, needed, vd.buf->ByteLength());
             return PR_FALSE;
         }
     }
 
     return PR_TRUE;
 }
 
-PRBool WebGLContext::ValidateCapabilityEnum(WebGLenum cap)
+PRBool WebGLContext::ValidateCapabilityEnum(WebGLenum cap, const char *info)
 {
     switch (cap) {
         case LOCAL_GL_BLEND:
         case LOCAL_GL_CULL_FACE:
         case LOCAL_GL_DEPTH_TEST:
         case LOCAL_GL_DITHER:
         case LOCAL_GL_POLYGON_OFFSET_FILL:
         case LOCAL_GL_SAMPLE_ALPHA_TO_COVERAGE:
         case LOCAL_GL_SAMPLE_COVERAGE:
         case LOCAL_GL_SCISSOR_TEST:
         case LOCAL_GL_STENCIL_TEST:
             return PR_TRUE;
         default:
+            ErrorInvalidEnumInfo(info);
             return PR_FALSE;
     }
 }
 
-PRBool WebGLContext::ValidateBlendEquationEnum(WebGLenum mode)
+PRBool WebGLContext::ValidateBlendEquationEnum(WebGLenum mode, const char *info)
 {
     switch (mode) {
         case LOCAL_GL_FUNC_ADD:
         case LOCAL_GL_FUNC_SUBTRACT:
         case LOCAL_GL_FUNC_REVERSE_SUBTRACT:
             return PR_TRUE;
         default:
+            ErrorInvalidEnumInfo(info);
             return PR_FALSE;
     }
 }
 
-PRBool WebGLContext::ValidateBlendFuncDstEnum(WebGLenum factor)
+PRBool WebGLContext::ValidateBlendFuncDstEnum(WebGLenum factor, const char *info)
 {
     switch (factor) {
         case LOCAL_GL_ZERO:
         case LOCAL_GL_ONE:
         case LOCAL_GL_SRC_COLOR:
         case LOCAL_GL_ONE_MINUS_SRC_COLOR:
         case LOCAL_GL_DST_COLOR:
         case LOCAL_GL_ONE_MINUS_DST_COLOR:
@@ -169,85 +171,142 @@ PRBool WebGLContext::ValidateBlendFuncDs
         case LOCAL_GL_DST_ALPHA:
         case LOCAL_GL_ONE_MINUS_DST_ALPHA:
         case LOCAL_GL_CONSTANT_COLOR:
         case LOCAL_GL_ONE_MINUS_CONSTANT_COLOR:
         case LOCAL_GL_CONSTANT_ALPHA:
         case LOCAL_GL_ONE_MINUS_CONSTANT_ALPHA:
             return PR_TRUE;
         default:
+            ErrorInvalidEnumInfo(info);
             return PR_FALSE;
     }
 }
 
-PRBool WebGLContext::ValidateBlendFuncSrcEnum(WebGLenum factor)
+PRBool WebGLContext::ValidateBlendFuncSrcEnum(WebGLenum factor, const char *info)
 {
-    if(factor == LOCAL_GL_SRC_ALPHA_SATURATE)
+    if (factor == LOCAL_GL_SRC_ALPHA_SATURATE)
         return PR_TRUE;
     else
-        return ValidateBlendFuncDstEnum(factor);
+        return ValidateBlendFuncDstEnum(factor, info);
 }
 
-PRBool WebGLContext::ValidateTextureTargetEnum(WebGLenum target)
+PRBool WebGLContext::ValidateTextureTargetEnum(WebGLenum target, const char *info)
 {
     switch (target) {
         case LOCAL_GL_TEXTURE_2D:
         case LOCAL_GL_TEXTURE_CUBE_MAP:
             return PR_TRUE;
         default:
+            ErrorInvalidEnumInfo(info);
             return PR_FALSE;
     }
 }
 
-PRBool WebGLContext::ValidateComparisonEnum(WebGLenum target)
+PRBool WebGLContext::ValidateComparisonEnum(WebGLenum target, const char *info)
 {
     switch (target) {
         case LOCAL_GL_NEVER:
         case LOCAL_GL_LESS:
         case LOCAL_GL_LEQUAL:
         case LOCAL_GL_GREATER:
         case LOCAL_GL_GEQUAL:
         case LOCAL_GL_EQUAL:
         case LOCAL_GL_NOTEQUAL:
         case LOCAL_GL_ALWAYS:
             return PR_TRUE;
         default:
+            ErrorInvalidEnumInfo(info);
             return PR_FALSE;
     }
 }
 
-PRBool WebGLContext::ValidateStencilOpEnum(WebGLenum action)
+PRBool WebGLContext::ValidateStencilOpEnum(WebGLenum action, const char *info)
 {
     switch (action) {
         case LOCAL_GL_KEEP:
         case LOCAL_GL_ZERO:
         case LOCAL_GL_REPLACE:
         case LOCAL_GL_INCR:
         case LOCAL_GL_INCR_WRAP:
         case LOCAL_GL_DECR:
         case LOCAL_GL_DECR_WRAP:
         case LOCAL_GL_INVERT:
             return PR_TRUE;
         default:
+            ErrorInvalidEnumInfo(info);
             return PR_FALSE;
     }
 }
 
-PRBool WebGLContext::ValidateFaceEnum(WebGLenum target)
+PRBool WebGLContext::ValidateFaceEnum(WebGLenum target, const char *info)
 {
     switch (target) {
         case LOCAL_GL_FRONT:
         case LOCAL_GL_BACK:
         case LOCAL_GL_FRONT_AND_BACK:
             return PR_TRUE;
         default:
+            ErrorInvalidEnumInfo(info);
             return PR_FALSE;
     }
 }
 
+PRBool WebGLContext::ValidateTexFormatAndType(WebGLenum format, WebGLenum type,
+                                                PRUint32 *texelSize, const char *info)
+{
+    if (type == LOCAL_GL_UNSIGNED_BYTE)
+    {
+        switch (format) {
+            case LOCAL_GL_RED:
+            case LOCAL_GL_GREEN:
+            case LOCAL_GL_BLUE:
+            case LOCAL_GL_ALPHA:
+            case LOCAL_GL_LUMINANCE:
+                *texelSize = 1;
+                return PR_TRUE;
+            case LOCAL_GL_LUMINANCE_ALPHA:
+                *texelSize = 2;
+                return PR_TRUE;
+            case LOCAL_GL_RGB:
+                *texelSize = 3;
+                return PR_TRUE;
+            case LOCAL_GL_RGBA:
+                *texelSize = 4;
+                return PR_TRUE;
+            default:
+                ErrorInvalidEnum("%s: invalid format", info);
+                return PR_FALSE;
+        }
+    } else {
+        switch (type) {
+            case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
+            case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
+                if (format == LOCAL_GL_RGBA) {
+                    *texelSize = 2;
+                    return PR_TRUE;
+                } else {
+                    ErrorInvalidOperation("%s: mutually incompatible format and type", info);
+                    return PR_FALSE;
+                }
+            case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
+                if (format == LOCAL_GL_RGB) {
+                    *texelSize = 2;
+                    return PR_TRUE;
+                } else {
+                    ErrorInvalidOperation("%s: mutually incompatible format and type", info);
+                    return PR_FALSE;
+                }
+            default:
+                ErrorInvalidEnum("%s: invalid type", info);
+                return PR_FALSE;
+        }
+    }
+}
+
 PRBool
 WebGLContext::InitAndValidateGL()
 {
     if (!gl) return PR_FALSE;
 
     mActiveTexture = 0;
     mSynthesizedGLError = LOCAL_GL_NO_ERROR;