Bug 738866 - Implement WEBGL_depth_texture extension - r=jgilbert
authorAlexander Boldyrev <boldir@gmail.com>
Mon, 13 Aug 2012 18:17:55 -0700
changeset 102251 376a20e68396f0224fd1634b9b0d71af130dce08
parent 102250 4b26b044d57d99dfbc21201ba116d1c1e9afcea6
child 102252 fafcc046e839f0b428977849d7cc51fbf888c49d
push id13385
push userjgilbert@mozilla.com
push dateTue, 14 Aug 2012 01:18:18 +0000
treeherdermozilla-inbound@376a20e68396 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjgilbert
bugs738866
milestone17.0a1
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
Bug 738866 - Implement WEBGL_depth_texture extension - r=jgilbert
content/canvas/src/Makefile.in
content/canvas/src/WebGLContext.cpp
content/canvas/src/WebGLContext.h
content/canvas/src/WebGLContextGL.cpp
content/canvas/src/WebGLContextNotSupported.cpp
content/canvas/src/WebGLContextUtils.cpp
content/canvas/src/WebGLContextValidate.cpp
content/canvas/src/WebGLExtensionDepthTexture.cpp
content/canvas/src/WebGLExtensions.h
content/canvas/src/WebGLTexelConversions.h
content/canvas/test/webgl/conformance/extensions/00_test_list.txt
content/canvas/test/webgl/conformance/extensions/webgl-depth-texture.html
dom/base/nsDOMClassInfo.cpp
dom/base/nsDOMClassInfoClasses.h
dom/interfaces/canvas/nsIDOMWebGLRenderingContext.idl
dom/tests/mochitest/general/test_interfaces.html
gfx/gl/GLContext.cpp
gfx/gl/GLContext.h
js/xpconnect/src/dom_quickstubs.qsconf
--- a/content/canvas/src/Makefile.in
+++ b/content/canvas/src/Makefile.in
@@ -47,16 +47,17 @@ CPPSRCS += \
 	WebGLContextUtils.cpp \
 	WebGLContextReporter.cpp \
 	WebGLContextValidate.cpp \
 	WebGLExtensionStandardDerivatives.cpp \
 	WebGLExtensionTextureFilterAnisotropic.cpp \
 	WebGLExtensionLoseContext.cpp \
 	WebGLTexelConversions.cpp \
 	WebGLExtensionCompressedTextureS3TC.cpp \
+	WebGLExtensionDepthTexture.cpp \
 	$(NULL)
 
 DEFINES += -DUSE_ANGLE
 USE_ANGLE=1
 
 else
 
 CPPSRCS += WebGLContextNotSupported.cpp
--- a/content/canvas/src/WebGLContext.cpp
+++ b/content/canvas/src/WebGLContext.cpp
@@ -1002,16 +1002,28 @@ bool WebGLContext::IsExtensionSupported(
                 isSupported = true;
             } else if (gl->IsExtensionSupported(GLContext::EXT_texture_compression_dxt1) &&
                        gl->IsExtensionSupported(GLContext::ANGLE_texture_compression_dxt3) &&
                        gl->IsExtensionSupported(GLContext::ANGLE_texture_compression_dxt5))
             {
                 isSupported = true;
             }
             break;
+        case WEBGL_depth_texture:
+            if (gl->IsGLES2() && 
+                gl->IsExtensionSupported(GLContext::OES_packed_depth_stencil) &&
+                gl->IsExtensionSupported(GLContext::OES_depth_texture)) 
+            {
+                isSupported = true;
+            } else if (!gl->IsGLES2() &&
+                       gl->IsExtensionSupported(GLContext::EXT_packed_depth_stencil)) 
+            {
+                isSupported = true;
+            }
+            break;
         default:
             MOZ_ASSERT(false, "should not get there.");
     }
 
     return isSupported;
 }
 
 NS_IMETHODIMP
@@ -1067,16 +1079,22 @@ WebGLContext::GetExtension(const nsAStri
             ext = WEBGL_lose_context;
     }
     else if (aName.Equals(NS_LITERAL_STRING("MOZ_WEBGL_compressed_texture_s3tc"),
              nsCaseInsensitiveStringComparator()))
     {
         if (IsExtensionSupported(WEBGL_compressed_texture_s3tc))
             ext = WEBGL_compressed_texture_s3tc;
     }
+    else if (aName.Equals(NS_LITERAL_STRING("MOZ_WEBGL_depth_texture"),
+             nsCaseInsensitiveStringComparator()))
+    {
+        if (IsExtensionSupported(WEBGL_depth_texture))
+            ext = WEBGL_depth_texture;
+    }
 
     if (ext == WebGLExtensionID_unknown_extension) {
       return nullptr;
     }
 
     if (!mExtensions[ext]) {
         switch (ext) {
             case OES_standard_derivatives:
@@ -1086,16 +1104,19 @@ WebGLContext::GetExtension(const nsAStri
                 mExtensions[ext] = new WebGLExtensionTextureFilterAnisotropic(this);
                 break;
             case WEBGL_lose_context:
                 mExtensions[ext] = new WebGLExtensionLoseContext(this);
                 break;
             case WEBGL_compressed_texture_s3tc:
                 mExtensions[ext] = new WebGLExtensionCompressedTextureS3TC(this);
                 break;
+            case WEBGL_depth_texture:
+                mExtensions[ext] = new WebGLExtensionDepthTexture(this);
+                break;
             default:
                 // create a generic WebGLExtension object for any extensions that don't
                 // have any additional tokens or methods. We still need these to be separate
                 // objects in case the user might extend the corresponding JS objects with custom
                 // properties.
                 mExtensions[ext] = new WebGLExtension(this);
                 break;
         }
@@ -1662,16 +1683,18 @@ WebGLContext::GetSupportedExtensions(Nul
     if (IsExtensionSupported(EXT_texture_filter_anisotropic)) {
         arr.AppendElement(NS_LITERAL_STRING("EXT_texture_filter_anisotropic"));
         arr.AppendElement(NS_LITERAL_STRING("MOZ_EXT_texture_filter_anisotropic"));
     }
     if (IsExtensionSupported(WEBGL_lose_context))
         arr.AppendElement(NS_LITERAL_STRING("MOZ_WEBGL_lose_context"));
     if (IsExtensionSupported(WEBGL_compressed_texture_s3tc))
         arr.AppendElement(NS_LITERAL_STRING("MOZ_WEBGL_compressed_texture_s3tc"));
+    if (IsExtensionSupported(WEBGL_depth_texture))
+        arr.AppendElement(NS_LITERAL_STRING("MOZ_WEBGL_depth_texture"));
 }
 
 NS_IMETHODIMP
 WebGLContext::IsContextLost(WebGLboolean *retval)
 {
     *retval = mContextStatus != ContextStable;
     return NS_OK;
 }
--- a/content/canvas/src/WebGLContext.h
+++ b/content/canvas/src/WebGLContext.h
@@ -106,21 +106,24 @@ enum WebGLTexelFormat
     BadFormat,
     // dummy pseudo-format meaning "use the other format".
     // For example, if SrcFormat=Auto and DstFormat=RGB8, then the source
     // is implicitly treated as being RGB8 itself.
     Auto,
     // 1-channel formats
     R8,
     A8,
+    D16, // used for WEBGL_depth_texture extension
+    D32, // used for WEBGL_depth_texture extension
     R32F, // used for OES_texture_float extension
     A32F, // used for OES_texture_float extension
     // 2-channel formats
     RA8,
     RA32F,
+    D24S8, // used for WEBGL_depth_texture extension
     // 3-channel formats
     RGB8,
     BGRX8, // used for DOM elements. Source format only.
     RGB565,
     RGB32F, // used for OES_texture_float extension
     // 4-channel formats
     RGBA8,
     BGRA8, // used for DOM elements
@@ -456,16 +459,17 @@ class WebGLContext :
     public WebGLRectangleObject,
     public nsWrapperCache
 {
     friend class WebGLMemoryMultiReporterWrapper;
     friend class WebGLExtensionLoseContext;
     friend class WebGLExtensionCompressedTextureS3TC;
     friend class WebGLContextUserData;
     friend class WebGLMemoryPressureObserver;
+    friend class WebGLExtensionDepthTexture;
 
 public:
     WebGLContext();
     virtual ~WebGLContext();
 
     NS_DECL_CYCLE_COLLECTING_ISUPPORTS
 
     NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(WebGLContext,
@@ -1142,16 +1146,17 @@ protected:
 
     // extensions
     enum WebGLExtensionID {
         OES_texture_float,
         OES_standard_derivatives,
         EXT_texture_filter_anisotropic,
         WEBGL_lose_context,
         WEBGL_compressed_texture_s3tc,
+        WEBGL_depth_texture,
         WebGLExtensionID_number_of_extensions,
         WebGLExtensionID_unknown_extension
     };
     nsAutoTArray<nsRefPtr<WebGLExtension>, WebGLExtensionID_number_of_extensions> mExtensions;
 
     // returns true if the extension has been enabled by calling getExtension.
     bool IsExtensionEnabled(WebGLExtensionID ext) {
         return mExtensions[ext];
@@ -2692,18 +2697,38 @@ public:
     bool IsComplete() const {
         const WebGLRectangleObject *thisRect = RectangleObject();
 
         if (!thisRect ||
             !thisRect->Width() ||
             !thisRect->Height())
             return false;
 
-        if (mTexturePtr)
-            return mAttachmentPoint == LOCAL_GL_COLOR_ATTACHMENT0;
+        if (mTexturePtr) {
+            if (!mTexturePtr->HasImageInfoAt(0, 0))
+                return false;
+
+            WebGLenum format = mTexturePtr->ImageInfoAt(0).Format();
+            switch (mAttachmentPoint)
+            {
+                case LOCAL_GL_COLOR_ATTACHMENT0:
+                    return format == LOCAL_GL_ALPHA ||
+                           format == LOCAL_GL_LUMINANCE ||
+                           format == LOCAL_GL_LUMINANCE_ALPHA ||
+                           format == LOCAL_GL_RGB ||
+                           format == LOCAL_GL_RGBA;
+                case LOCAL_GL_DEPTH_ATTACHMENT:
+                    return format == LOCAL_GL_DEPTH_COMPONENT;
+                case LOCAL_GL_DEPTH_STENCIL_ATTACHMENT:
+                    return format == LOCAL_GL_DEPTH_STENCIL;
+
+                default:
+                    MOZ_NOT_REACHED("Invalid WebGL texture format?");
+            }
+        } 
 
         if (mRenderbufferPtr) {
             WebGLenum format = mRenderbufferPtr->InternalFormat();
             switch (mAttachmentPoint) {
                 case LOCAL_GL_COLOR_ATTACHMENT0:
                     return format == LOCAL_GL_RGB565 ||
                            format == LOCAL_GL_RGB5_A1 ||
                            format == LOCAL_GL_RGBA4;
@@ -2939,16 +2964,19 @@ public:
     NS_DECL_NSIWEBGLFRAMEBUFFER
 
     bool CheckAndInitializeRenderbuffers()
     {
         // enforce WebGL section 6.5 which is WebGL-specific, hence OpenGL itself would not
         // generate the INVALID_FRAMEBUFFER_OPERATION that we need here
         if (HasDepthStencilConflict())
             return false;
+        
+        if (HasIncompleteAttachment())
+            return false;
 
         if (!mColorAttachment.HasUninitializedRenderbuffer() &&
             !mDepthAttachment.HasUninitializedRenderbuffer() &&
             !mStencilAttachment.HasUninitializedRenderbuffer() &&
             !mDepthStencilAttachment.HasUninitializedRenderbuffer())
             return true;
 
         // ensure INVALID_FRAMEBUFFER_OPERATION in zero-size case
--- a/content/canvas/src/WebGLContextGL.cpp
+++ b/content/canvas/src/WebGLContextGL.cpp
@@ -1032,16 +1032,20 @@ WebGLContext::CopyTexImage2D(WebGLenum t
                                     internalformat == LOCAL_GL_ALPHA ||
                                     internalformat == LOCAL_GL_LUMINANCE_ALPHA;
     bool fboFormatHasAlpha = mBoundFramebuffer ? mBoundFramebuffer->ColorAttachment().HasAlpha()
                                                  : bool(gl->ActualFormat().alpha > 0);
     if (texFormatRequiresAlpha && !fboFormatHasAlpha)
         return ErrorInvalidOperation("copyTexImage2D: texture format requires an alpha channel "
                                      "but the framebuffer doesn't have one");
 
+    if (internalformat == LOCAL_GL_DEPTH_COMPONENT ||
+        internalformat == LOCAL_GL_DEPTH_STENCIL)
+        return ErrorInvalidOperation("copyTexImage2D: a base internal format of DEPTH_COMPONENT or DEPTH_STENCIL isn't supported");
+
     if (mBoundFramebuffer)
         if (!mBoundFramebuffer->CheckAndInitializeRenderbuffers())
             return ErrorInvalidFramebufferOperation("copyTexImage2D: incomplete framebuffer");
 
     WebGLTexture *tex = activeBoundTextureForTarget(target);
     if (!tex)
         return ErrorInvalidOperation("copyTexImage2D: no texture bound to this target");
 
@@ -1153,16 +1157,20 @@ WebGLContext::CopyTexSubImage2D(WebGLenu
                                   format == LOCAL_GL_LUMINANCE_ALPHA;
     bool fboFormatHasAlpha = mBoundFramebuffer ? mBoundFramebuffer->ColorAttachment().HasAlpha()
                                                  : bool(gl->ActualFormat().alpha > 0);
 
     if (texFormatRequiresAlpha && !fboFormatHasAlpha)
         return ErrorInvalidOperation("copyTexSubImage2D: texture format requires an alpha channel "
                                      "but the framebuffer doesn't have one");
 
+    if (format == LOCAL_GL_DEPTH_COMPONENT ||
+        format == LOCAL_GL_DEPTH_STENCIL)
+        return ErrorInvalidOperation("copyTexSubImage2D: a base internal format of DEPTH_COMPONENT or DEPTH_STENCIL isn't supported");
+
     if (mBoundFramebuffer)
         if (!mBoundFramebuffer->CheckAndInitializeRenderbuffers())
             return ErrorInvalidFramebufferOperation("copyTexSubImage2D: incomplete framebuffer");
 
     return CopyTexSubImage2D_base(target, level, format, xoffset, yoffset, x, y, width, height, true);
 }
 
 
@@ -2125,16 +2133,22 @@ WebGLContext::GenerateMipmap(WebGLenum t
 
     if (!tex->IsFirstImagePowerOfTwo())
         return ErrorInvalidOperation("generateMipmap: Level zero of texture does not have power-of-two width and height.");
 
     GLenum format = tex->ImageInfoAt(0, 0).Format();
     if (IsTextureFormatCompressed(format))
         return ErrorInvalidOperation("generateMipmap: Texture data at level zero is compressed.");
 
+    if (IsExtensionEnabled(WEBGL_depth_texture) && 
+        (format == LOCAL_GL_DEPTH_COMPONENT || format == LOCAL_GL_DEPTH_STENCIL))
+        return ErrorInvalidOperation("generateMipmap: "
+                                     "A texture that has a base internal format of "
+                                     "DEPTH_COMPONENT or DEPTH_STENCIL isn't supported");
+
     if (!tex->AreAllLevel0ImageInfosEqual())
         return ErrorInvalidOperation("generateMipmap: The six faces of this cube map have different dimensions, format, or type.");
 
     tex->SetGeneratedMipmap();
 
     MakeContextCurrent();
 
     if (gl->WorkAroundDriverBugs()) {
@@ -5611,16 +5625,18 @@ WebGLContext::TexImage2D_base(WebGLenum 
     }
 
     switch (format) {
         case LOCAL_GL_RGB:
         case LOCAL_GL_RGBA:
         case LOCAL_GL_ALPHA:
         case LOCAL_GL_LUMINANCE:
         case LOCAL_GL_LUMINANCE_ALPHA:
+        case LOCAL_GL_DEPTH_COMPONENT:
+        case LOCAL_GL_DEPTH_STENCIL:
             break;
         default:
             return ErrorInvalidEnumInfo("texImage2D: internal format", internalformat);
     }
 
     if (format != internalformat)
         return ErrorInvalidOperation("texImage2D: format does not match internalformat");
 
@@ -5632,16 +5648,30 @@ WebGLContext::TexImage2D_base(WebGLenum 
         if (!(is_pot_assuming_nonnegative(width) &&
               is_pot_assuming_nonnegative(height)))
             return ErrorInvalidValue("texImage2D: with level > 0, width and height must be powers of two");
     }
 
     if (border != 0)
         return ErrorInvalidValue("texImage2D: border must be 0");
 
+
+    if (format == LOCAL_GL_DEPTH_COMPONENT || format == LOCAL_GL_DEPTH_STENCIL) {
+        if (IsExtensionEnabled(WEBGL_depth_texture)) {
+            if (target != LOCAL_GL_TEXTURE_2D || data != NULL || level != 0)
+                return ErrorInvalidOperation("texImage2D: "
+                                             "with format of DEPTH_COMPONENT or DEPTH_STENCIL "
+                                             "target must be TEXTURE_2D, "
+                                             "data must be NULL, "
+                                             "level must be zero");
+        }
+        else
+            return ErrorInvalidEnumInfo("texImage2D: internal format", internalformat);
+    }
+
     uint32_t dstTexelSize = 0;
     if (!ValidateTexFormatAndType(format, type, jsArrayType, &dstTexelSize, "texImage2D"))
         return;
 
     WebGLTexelFormat dstFormat = GetWebGLTexelFormat(format, type);
     WebGLTexelFormat actualSrcFormat = srcFormat == WebGLTexelConversions::Auto ? dstFormat : srcFormat;
 
     uint32_t srcTexelSize = WebGLTexelConversions::TexelBytesForFormat(actualSrcFormat);
@@ -5844,16 +5874,21 @@ WebGLContext::TexSubImage2D_base(WebGLen
     }
 
     if (level >= 1) {
         if (!(is_pot_assuming_nonnegative(width) &&
               is_pot_assuming_nonnegative(height)))
             return ErrorInvalidValue("texSubImage2D: with level > 0, width and height must be powers of two");
     }
 
+    if (IsExtensionEnabled(WEBGL_depth_texture) && 
+        (format == LOCAL_GL_DEPTH_COMPONENT || format == LOCAL_GL_DEPTH_STENCIL)) {
+        return ErrorInvalidOperation("texSubImage2D: format");
+    }
+
     uint32_t dstTexelSize = 0;
     if (!ValidateTexFormatAndType(format, type, jsArrayType, &dstTexelSize, "texSubImage2D"))
         return;
 
     WebGLTexelFormat dstFormat = GetWebGLTexelFormat(format, type);
     WebGLTexelFormat actualSrcFormat = srcFormat == WebGLTexelConversions::Auto ? dstFormat : srcFormat;
 
     uint32_t srcTexelSize = WebGLTexelConversions::TexelBytesForFormat(actualSrcFormat);
@@ -6112,16 +6147,40 @@ BaseTypeAndSizeFromUniformType(WebGLenum
     }
 
     return true;
 }
 
 
 WebGLTexelFormat mozilla::GetWebGLTexelFormat(GLenum format, GLenum type)
 {
+    //
+    // WEBGL_depth_texture
+    if (format == LOCAL_GL_DEPTH_COMPONENT) {
+        switch (type) {
+            case LOCAL_GL_UNSIGNED_SHORT:
+                return WebGLTexelConversions::D16;
+            case LOCAL_GL_UNSIGNED_INT:
+                return WebGLTexelConversions::D32;
+            default:
+                MOZ_NOT_REACHED("Invalid WebGL texture format/type?");
+                return WebGLTexelConversions::BadFormat;
+        }
+    } else if (format == LOCAL_GL_DEPTH_STENCIL) {
+        switch (type) {
+            case LOCAL_GL_UNSIGNED_INT_24_8_EXT:
+                return WebGLTexelConversions::D24S8;
+            default:
+                MOZ_NOT_REACHED("Invalid WebGL texture format/type?");
+                NS_ABORT_IF_FALSE(false, "Coding mistake?! Should never reach this point.");
+                return WebGLTexelConversions::BadFormat;
+        }
+    }
+
+
     if (type == LOCAL_GL_UNSIGNED_BYTE) {
         switch (format) {
             case LOCAL_GL_RGBA:
                 return WebGLTexelConversions::RGBA8;
             case LOCAL_GL_RGB:
                 return WebGLTexelConversions::RGB8;
             case LOCAL_GL_ALPHA:
                 return WebGLTexelConversions::A8;
@@ -6169,16 +6228,28 @@ WebGLenum
 InternalFormatForFormatAndType(WebGLenum format, WebGLenum type, bool isGLES2)
 {
     // ES2 requires that format == internalformat; floating-point is
     // indicated purely by the type that's loaded.  For desktop GL, we
     // have to specify a floating point internal format.
     if (isGLES2)
         return format;
 
+    if (format == LOCAL_GL_DEPTH_COMPONENT) {
+        if (type == LOCAL_GL_UNSIGNED_SHORT)
+            return LOCAL_GL_DEPTH_COMPONENT16;
+        else if (type == LOCAL_GL_UNSIGNED_INT)
+            return LOCAL_GL_DEPTH_COMPONENT32;
+    } 
+    
+    if (format == LOCAL_GL_DEPTH_STENCIL) {
+        if (type == LOCAL_GL_UNSIGNED_INT_24_8_EXT)
+            return LOCAL_GL_DEPTH24_STENCIL8;
+    }
+
     switch (type) {
     case LOCAL_GL_UNSIGNED_BYTE:
     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:
         return format;
 
     case LOCAL_GL_FLOAT:
--- a/content/canvas/src/WebGLContextNotSupported.cpp
+++ b/content/canvas/src/WebGLContextNotSupported.cpp
@@ -20,8 +20,9 @@ DOMCI_DATA(WebGLRenderbuffer, void)
 DOMCI_DATA(WebGLUniformLocation, void)
 DOMCI_DATA(WebGLShaderPrecisionFormat, void)
 DOMCI_DATA(WebGLActiveInfo, void)
 DOMCI_DATA(WebGLExtension, void)
 DOMCI_DATA(WebGLExtensionStandardDerivatives, void)
 DOMCI_DATA(WebGLExtensionTextureFilterAnisotropic, void)
 DOMCI_DATA(WebGLExtensionLoseContext, void)
 DOMCI_DATA(WebGLExtensionCompressedTextureS3TC, void)
+DOMCI_DATA(WebGLExtensionDepthTexture, void)
--- a/content/canvas/src/WebGLContextUtils.cpp
+++ b/content/canvas/src/WebGLContextUtils.cpp
@@ -185,16 +185,18 @@ bool
 WebGLContext::IsTextureFormatCompressed(GLenum format)
 {
     switch(format) {
         case LOCAL_GL_RGB:
         case LOCAL_GL_RGBA:
         case LOCAL_GL_ALPHA:
         case LOCAL_GL_LUMINANCE:
         case LOCAL_GL_LUMINANCE_ALPHA:
+        case LOCAL_GL_DEPTH_COMPONENT:
+        case LOCAL_GL_DEPTH_STENCIL:
             return false;
 
         case LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
         case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
         case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
         case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
             return true;
     }
--- a/content/canvas/src/WebGLContextValidate.cpp
+++ b/content/canvas/src/WebGLContextValidate.cpp
@@ -451,16 +451,26 @@ bool WebGLContext::ValidateLevelWidthHei
 
 uint32_t WebGLContext::GetBitsPerTexel(WebGLenum format, WebGLenum type)
 {
     // If there is no defined format or type, we're not taking up any memory
     if (!format || !type) {
         return 0;
     }
 
+    if (format == LOCAL_GL_DEPTH_COMPONENT) {
+        if (type == LOCAL_GL_UNSIGNED_SHORT)
+            return 2;
+        else if (type == LOCAL_GL_UNSIGNED_INT)
+            return 4;
+    } else if (format == LOCAL_GL_DEPTH_STENCIL) {
+        if (type == LOCAL_GL_UNSIGNED_INT_24_8_EXT)
+            return 4;
+    }
+
     if (type == LOCAL_GL_UNSIGNED_BYTE || type == LOCAL_GL_FLOAT) {
         int multiplier = type == LOCAL_GL_FLOAT ? 32 : 8;
         switch (format) {
             case LOCAL_GL_ALPHA:
             case LOCAL_GL_LUMINANCE:
                 return 1 * multiplier;
             case LOCAL_GL_LUMINANCE_ALPHA:
                 return 2 * multiplier;
@@ -486,16 +496,58 @@ uint32_t WebGLContext::GetBitsPerTexel(W
 
     NS_ABORT();
     return 0;
 }
 
 bool WebGLContext::ValidateTexFormatAndType(WebGLenum format, WebGLenum type, int jsArrayType,
                                               uint32_t *texelSize, const char *info)
 {
+    if (IsExtensionEnabled(WEBGL_depth_texture)) {
+        if (format == LOCAL_GL_DEPTH_COMPONENT) {
+            if (jsArrayType != -1) {
+                if ((type == LOCAL_GL_UNSIGNED_SHORT && jsArrayType != js::ArrayBufferView::TYPE_UINT16) ||
+                    (type == LOCAL_GL_UNSIGNED_INT && jsArrayType != js::ArrayBufferView::TYPE_UINT32)) {
+                    ErrorInvalidOperation("%s: invalid typed array type for given texture data type", info);
+                    return false;
+                }
+            }
+
+            switch(type) {
+                case LOCAL_GL_UNSIGNED_SHORT:
+                    *texelSize = 2;
+                    break;
+                case LOCAL_GL_UNSIGNED_INT:
+                    *texelSize = 4;
+                    break;
+                default:
+                    ErrorInvalidOperation("%s: invalid type 0x%x", info, type);
+                    return false;
+            }
+
+            return true;
+
+        } else if (format == LOCAL_GL_DEPTH_STENCIL) {
+            if (type != LOCAL_GL_UNSIGNED_INT_24_8_EXT) {
+                ErrorInvalidOperation("%s: invalid format 0x%x", info, format);
+                return false;
+            }
+            if (jsArrayType != -1) {
+                if (jsArrayType != js::ArrayBufferView::TYPE_UINT32) {
+                    ErrorInvalidOperation("%s: invalid typed array type for given texture data type", info);
+                    return false;
+                }
+            }
+
+            *texelSize = 4;
+            return true;
+        }
+    }
+
+
     if (type == LOCAL_GL_UNSIGNED_BYTE ||
         (IsExtensionEnabled(OES_texture_float) && type == LOCAL_GL_FLOAT))
     {
         if (jsArrayType != -1) {
             if ((type == LOCAL_GL_UNSIGNED_BYTE && jsArrayType != js::ArrayBufferView::TYPE_UINT8) ||
                 (type == LOCAL_GL_FLOAT && jsArrayType != js::ArrayBufferView::TYPE_FLOAT32))
             {
                 ErrorInvalidOperation("%s: invalid typed array type for given texture data type", info);
new file mode 100644
--- /dev/null
+++ b/content/canvas/src/WebGLExtensionDepthTexture.cpp
@@ -0,0 +1,32 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "WebGLContext.h"
+#include "WebGLExtensions.h"
+
+using namespace mozilla;
+
+WebGLExtensionDepthTexture::WebGLExtensionDepthTexture(WebGLContext* context) :
+    WebGLExtension(context)
+{
+
+}
+
+WebGLExtensionDepthTexture::~WebGLExtensionDepthTexture()
+{
+
+}
+
+NS_IMPL_ADDREF_INHERITED(WebGLExtensionDepthTexture, WebGLExtension)
+NS_IMPL_RELEASE_INHERITED(WebGLExtensionDepthTexture, WebGLExtension)
+
+DOMCI_DATA(WebGLExtensionDepthTexture, WebGLExtensionDepthTexture)
+
+NS_INTERFACE_MAP_BEGIN(WebGLExtensionDepthTexture)
+  NS_INTERFACE_MAP_ENTRY(nsIWebGLExtensionDepthTexture)
+  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, WebGLExtension)
+  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(WebGLExtensionDepthTexture)
+NS_INTERFACE_MAP_END_INHERITING(WebGLExtension)
+
--- a/content/canvas/src/WebGLExtensions.h
+++ b/content/canvas/src/WebGLExtensions.h
@@ -51,11 +51,23 @@ class WebGLExtensionCompressedTextureS3T
 public:
     WebGLExtensionCompressedTextureS3TC(WebGLContext* context);
     virtual ~WebGLExtensionCompressedTextureS3TC();
 
     NS_DECL_ISUPPORTS_INHERITED
     NS_DECL_NSIWEBGLEXTENSION
 };
 
+class WebGLExtensionDepthTexture :
+    public nsIWebGLExtensionDepthTexture,
+    public WebGLExtension
+{
+public:
+    WebGLExtensionDepthTexture(WebGLContext* context);
+    virtual ~WebGLExtensionDepthTexture();
+
+    NS_DECL_ISUPPORTS_INHERITED
+    NS_DECL_NSIWEBGLEXTENSION
+};
+
 }
 
 #endif // WEBGLEXTENSIONS_H_
--- a/content/canvas/src/WebGLTexelConversions.h
+++ b/content/canvas/src/WebGLTexelConversions.h
@@ -104,24 +104,27 @@ inline size_t TexelBytesForFormat(int fo
     switch (format) {
         case WebGLTexelConversions::R8:
         case WebGLTexelConversions::A8:
             return 1;
         case WebGLTexelConversions::RA8:
         case WebGLTexelConversions::RGBA5551:
         case WebGLTexelConversions::RGBA4444:
         case WebGLTexelConversions::RGB565:
+        case WebGLTexelConversions::D16:
             return 2;
         case WebGLTexelConversions::RGB8:
             return 3;
         case WebGLTexelConversions::RGBA8:
         case WebGLTexelConversions::BGRA8:
         case WebGLTexelConversions::BGRX8:
         case WebGLTexelConversions::R32F:
         case WebGLTexelConversions::A32F:
+        case WebGLTexelConversions::D32:
+        case WebGLTexelConversions::D24S8:
             return 4;
         case WebGLTexelConversions::RA32F:
             return 8;
         case WebGLTexelConversions::RGB32F:
             return 12;
         case WebGLTexelConversions::RGBA32F:
             return 16;
         default:
--- a/content/canvas/test/webgl/conformance/extensions/00_test_list.txt
+++ b/content/canvas/test/webgl/conformance/extensions/00_test_list.txt
@@ -1,8 +1,9 @@
 oes-standard-derivatives.html
 ext-texture-filter-anisotropic.html
 oes-texture-float.html
 oes-vertex-array-object.html
 webgl-debug-renderer-info.html
 webgl-debug-shaders.html
 --min-version 1.0.2 webgl-compressed-texture-s3tc.html
+--min-version 1.0.2 webgl-depth-texture.html
 
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/conformance/extensions/webgl-depth-texture.html
@@ -0,0 +1,343 @@
+<!--
+
+/*
+** Copyright (c) 2012 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be included
+** in all copies or substantial portions of the Materials.
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+
+-->
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<link rel="stylesheet" href="../../resources/js-test-style.css"/>
+<script src="../../resources/js-test-pre.js"></script>
+<script src="../resources/webgl-test.js"></script>
+<script src="../resources/webgl-test-utils.js"></script>
+<title>WebGL WEBGL_depth_texture Conformance Tests</title>
+</head>
+<body>
+<script id="vshader" type="x-shader/x-vertex">
+attribute vec4 a_position;
+void main()
+{
+    gl_Position = a_position;
+}
+</script>
+
+<script id="fshader" type="x-shader/x-fragment">
+precision mediump float;
+uniform sampler2D u_texture;
+uniform vec2 u_resolution;
+void main()
+{
+    vec2 texcoord = gl_FragCoord.xy / u_resolution;
+    gl_FragColor = texture2D(u_texture, texcoord);
+}
+</script>
+<div id="description"></div>
+<div id="console"></div>
+<canvas id="canvas" width="8" height="8" style="width: 8px; height: 8px;"></canvas>
+<script>
+if (window.initNonKhronosFramework) {
+    window.initNonKhronosFramework(false);
+}
+description("This test verifies the functionality of the WEBGL_depth_texture extension, if it is available.");
+
+debug("");
+
+var wtu = WebGLTestUtils;
+var canvas = document.getElementById("canvas");
+var gl = wtu.create3DContext(canvas, {antialias: false});
+var program = wtu.setupTexturedQuad(gl);
+var ext = null;
+var vao = null;
+var tex;
+var name;
+var supportedFormats;
+
+if (!gl) {
+    testFailed("WebGL context does not exist");
+} else {
+    testPassed("WebGL context exists");
+
+    // Run tests with extension disabled
+    runTestDisabled();
+
+    // Query the extension and store globally so shouldBe can access it
+    ext = wtu.getExtensionWithKnownPrefixes(gl, "WEBGL_depth_texture");
+    if (!ext) {
+        testPassed("No WEBGL_depth_texture support -- this is legal");
+        runSupportedTest(false);
+    } else {
+        testPassed("Successfully enabled WEBGL_depth_texture extension");
+
+        runSupportedTest(true);
+        runTestExtension();
+    }
+}
+
+function runSupportedTest(extensionEnabled) {
+    var name = wtu.getSupportedExtensionWithKnownPrefixes(gl, "WEBGL_depth_texture");
+    if (name !== undefined) {
+        if (extensionEnabled) {
+            testPassed("WEBGL_depth_texture listed as supported and getExtension succeeded");
+        } else {
+            testFailed("WEBGL_depth_texture listed as supported but getExtension failed");
+        }
+    } else {
+        if (extensionEnabled) {
+            testFailed("WEBGL_depth_texture not listed as supported but getExtension succeeded");
+        } else {
+            testPassed("WEBGL_depth_texture not listed as supported and getExtension failed -- this is legal");
+        }
+    }
+}
+
+
+function runTestDisabled() {
+    debug("Testing binding enum with extension disabled");
+
+    var tex = gl.createTexture();
+    gl.bindTexture(gl.TEXTURE_2D, tex);
+    shouldGenerateGLError(gl, gl.INVALID_ENUM, 'gl.texImage2D(gl.TEXTURE_2D, 0, gl.DEPTH_COMPONENT, 1, 1, 0, gl.DEPTH_COMPONENT, gl.UNSIGNED_SHORT, null)');
+    shouldGenerateGLError(gl, gl.INVALID_ENUM, 'gl.texImage2D(gl.TEXTURE_2D, 0, gl.DEPTH_COMPONENT, 1, 1, 0, gl.DEPTH_COMPONENT, gl.UNSIGNED_INT, null)');
+}
+
+
+function dumpIt(gl, res, msg) {
+  return;  // comment out to debug
+  debug(msg);
+  var actualPixels = new Uint8Array(res * res * 4);
+  gl.readPixels(0, 0, res, res, gl.RGBA, gl.UNSIGNED_BYTE, actualPixels);
+
+  for (var yy = 0; yy < res; ++yy) {
+    var strs = [];
+    for (var xx = 0; xx < res; ++xx) {
+      var actual = (yy * res + xx) * 4;
+      strs.push("(" + actualPixels[actual] + "," + actualPixels[actual+1] + "," + actualPixels[actual + 2] + "," + actualPixels[actual + 3] + ")");
+    }
+    debug(strs.join(" "));
+  }
+}
+function runTestExtension() {
+    debug("Testing WEBGL_depth_texture");
+
+    var res = 8;
+
+    // make canvas for testing.
+    canvas2 = document.createElement("canvas");
+    canvas2.width = res;
+    canvas2.height = res;
+    var ctx = canvas2.getContext("2d");
+    ctx.fillStyle = "blue";
+    ctx.fillRect(0, 0, canvas2.width, canvas2.height);
+
+    var program = wtu.setupProgram(gl, ['vshader', 'fshader'], ['a_position']);
+    gl.useProgram(program);
+    gl.uniform2f(gl.getUniformLocation(program, "u_resolution"), res, res);
+
+    var buffer = gl.createBuffer();
+    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
+    gl.bufferData(
+        gl.ARRAY_BUFFER,
+        new Float32Array(
+            [   1,  1,  1,
+               -1,  1,  0,
+               -1, -1, -1,
+                1,  1,  1,
+               -1, -1, -1,
+                1, -1,  0,
+            ]),
+        gl.STATIC_DRAW);
+    gl.enableVertexAttribArray(0);
+    gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0);
+
+    var types = [
+        {obj: 'gl',  attachment: 'DEPTH_ATTACHMENT',         format: 'DEPTH_COMPONENT', type: 'UNSIGNED_SHORT',          data: 'new Uint16Array(1)' },
+        {obj: 'gl',  attachment: 'DEPTH_ATTACHMENT',         format: 'DEPTH_COMPONENT', type: 'UNSIGNED_INT',            data: 'new Uint32Array(1)' },
+        {obj: 'ext', attachment: 'DEPTH_STENCIL_ATTACHMENT', format: 'DEPTH_STENCIL',   type: 'UNSIGNED_INT_24_8_WEBGL', data: 'new Uint32Array(1)' }
+    ];
+
+    for (var ii = 0; ii < types.length; ++ii) {
+        var typeInfo = types[ii];
+        var type = typeInfo.type;
+        var typeStr = typeInfo.obj + '.' + type;
+
+        debug("");
+        debug("testing: " + type);
+
+        // check that cubemaps are not allowed.
+        var cubeTex = gl.createTexture();
+        gl.bindTexture(gl.TEXTURE_CUBE_MAP, cubeTex);
+        var targets = [
+          'TEXTURE_CUBE_MAP_POSITIVE_X',
+          'TEXTURE_CUBE_MAP_NEGATIVE_X',
+          'TEXTURE_CUBE_MAP_POSITIVE_Y',
+          'TEXTURE_CUBE_MAP_NEGATIVE_Y',
+          'TEXTURE_CUBE_MAP_POSITIVE_Z',
+          'TEXTURE_CUBE_MAP_NEGATIVE_Z'
+        ];
+        for (var tt = 0; tt < targets.length; ++tt) {
+            shouldGenerateGLError(gl, gl.INVALID_OPERATION, 'gl.texImage2D(gl.' + targets[ii] + ', 1, gl.' + typeInfo.format + ', 1, 1, 0, gl.' + typeInfo.format + ', ' + typeStr + ', null)');
+        }
+
+        // check 2d textures.
+        tex = gl.createTexture();
+        gl.bindTexture(gl.TEXTURE_2D, tex);
+        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
+        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
+
+        // test level > 0
+        shouldGenerateGLError(gl, gl.INVALID_OPERATION, 'gl.texImage2D(gl.TEXTURE_2D, 1, gl.' + typeInfo.format + ', 1, 1, 0, gl.' + typeInfo.format + ', ' + typeStr + ', null)');
+
+        // test with data
+        shouldGenerateGLError(gl, gl.INVALID_OPERATION, 'gl.texImage2D(gl.TEXTURE_2D, 0, gl.' + typeInfo.format + ', 1, 1, 0, gl.' + typeInfo.format + ', ' + typeStr + ', ' + typeInfo.data + ')');
+
+        // test with canvas
+        shouldGenerateGLError(gl, [gl.INVALID_VALUE, gl.INVALID_ENUM, gl.INVALID_OPERATION], 'gl.texImage2D(gl.TEXTURE_2D, 0, gl.' + typeInfo.format + ', gl.' + typeInfo.format + ', ' + typeStr  + ', canvas2)');
+
+        // test copyTexImage2D
+        shouldGenerateGLError(gl, [gl.INVALID_ENUM, gl.INVALID_OPERATION], 'gl.copyTexImage2D(gl.TEXTURE_2D, 0, gl.' + typeInfo.format + ', 0, 0, 1, 1, 0)');
+
+        // test real thing
+        shouldGenerateGLError(gl, gl.NO_ERROR, 'gl.texImage2D(gl.TEXTURE_2D, 0, gl.' + typeInfo.format + ', ' + res + ', ' + res + ', 0, gl.' + typeInfo.format + ', ' + typeStr + ', null)');
+
+        // test texSubImage2D
+        shouldGenerateGLError(gl, gl.INVALID_OPERATION, 'gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 1, 1, gl.' + typeInfo.format + ', ' + typeStr  + ', ' + typeInfo.data + ')');
+
+        // test copyTexSubImage2D
+        shouldGenerateGLError(gl, gl.INVALID_OPERATION, 'gl.copyTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 0, 0, 1, 1)');
+
+        // test generateMipmap
+        shouldGenerateGLError(gl, gl.INVALID_OPERATION, 'gl.generateMipmap(gl.TEXTURE_2D)');
+
+        var fbo = gl.createFramebuffer();
+        gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
+        gl.framebufferTexture2D(gl.FRAMEBUFFER, gl[typeInfo.attachment], gl.TEXTURE_2D, tex, 0);
+        // TODO: remove this check if the spec is updated to require these combinations to work.
+        if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE)
+        {
+            // try adding a color buffer.
+            var colorTex = gl.createTexture();
+            gl.bindTexture(gl.TEXTURE_2D, colorTex);
+            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
+            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
+            gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, res, res, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
+            gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, colorTex, 0);
+            shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE');
+        }
+
+        // use the default texture to render with while we return to the depth texture.
+        gl.bindTexture(gl.TEXTURE_2D, null);
+
+        // render the z-quad
+        gl.enable(gl.DEPTH_TEST);
+        gl.clearColor(1, 0, 0, 1);
+        gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+        gl.drawArrays(gl.TRIANGLES, 0, 6);
+
+        dumpIt(gl, res, "--first--");
+
+        // render the depth texture.
+        gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+        gl.bindTexture(gl.TEXTURE_2D, tex);
+        gl.clearColor(0, 0, 1, 1);
+        gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+        gl.drawArrays(gl.TRIANGLES, 0, 6);
+
+        var actualPixels = new Uint8Array(res * res * 4);
+        gl.readPixels(0, 0, res, res, gl.RGBA, gl.UNSIGNED_BYTE, actualPixels);
+
+        dumpIt(gl, res, "--depth--");
+
+        // Check that each pixel's RGB are the same and that it's value is less
+        // than the previous pixel in either direction. Basically verify we have a
+        // gradient.
+        var success = true;
+        for (var yy = 0; yy < res; ++yy) {
+          for (var xx = 0; xx < res; ++xx) {
+            var actual = (yy * res + xx) * 4;
+            var left = actual - 4;
+            var down = actual - res * 4;
+
+            if (actualPixels[actual + 0] != actualPixels[actual + 1]) {
+                testFailed('R != G');
+                success = false;
+            }
+            if (actualPixels[actual + 0] != actualPixels[actual + 2]) {
+                testFailed('R != B');
+                success = false;
+            }
+            // ALPHA is implementation dependent
+            if (actualPixels[actual + 3] != 0xFF && actualPixels[actual + 3] != actualPixels[actual + 0]) {
+                testFailed('A != 255 && A != R');
+                success = false;
+            }
+
+            if (xx > 0) {
+              if (actualPixels[actual] <= actualPixels[left]) {
+                  testFailed("actual(" + actualPixels[actual] + ") < left(" + actualPixels[left] + ")");
+                  success = false;
+              }
+            }
+            if (yy > 0) {
+                if (actualPixels[actual] <= actualPixels[down]) {
+                    testFailed("actual(" + actualPixels[actual] + ") < down(" + actualPixels[down] + ")");
+                    success = false;
+                }
+            }
+          }
+        }
+
+        // Check that bottom left corner is vastly different thatn top right.
+        if (actualPixels[(res * res - 1) * 4] - actualPixels[0] < 0xC0) {
+            testFailed("corners are not different enough");
+            success = false;
+        }
+
+        if (success) {
+            testPassed("depth texture rendered correctly.");
+        }
+
+        // check limitations
+        gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
+        gl.framebufferTexture2D(gl.FRAMEBUFFER, gl[typeInfo.attachment], gl.TEXTURE_2D, null, 0);
+        var badAttachment = typeInfo.attachment == 'DEPTH_ATTACHMENT' ? 'DEPTH_STENCIL_ATTACHMENT' : 'DEPTH_ATTACHMENT';
+        shouldGenerateGLError(gl, gl.NO_ERROR, 'gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.' + badAttachment + ', gl.TEXTURE_2D, tex, 0)');
+        shouldNotBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE');
+        shouldGenerateGLError(gl, gl.INVALID_FRAMEBUFFER_OPERATION, 'gl.clear(gl.DEPTH_BUFFER_BIT)');
+        gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+        shouldBe('gl.getError()', 'gl.NO_ERROR');
+    }
+}
+
+debug("");
+successfullyParsed = true;
+</script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
+
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -1576,16 +1576,19 @@ static nsDOMClassInfoData sClassInfoData
                            DOM_DEFAULT_SCRIPTABLE_FLAGS |
                            nsIXPCScriptable::WANT_ADDPROPERTY)
   NS_DEFINE_CLASSINFO_DATA(WebGLExtensionLoseContext, WebGLExtensionSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS |
                            nsIXPCScriptable::WANT_ADDPROPERTY)
   NS_DEFINE_CLASSINFO_DATA(WebGLExtensionCompressedTextureS3TC, WebGLExtensionSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS |
                            nsIXPCScriptable::WANT_ADDPROPERTY)
+  NS_DEFINE_CLASSINFO_DATA(WebGLExtensionDepthTexture, WebGLExtensionSH,
+                           DOM_DEFAULT_SCRIPTABLE_FLAGS |
+                           nsIXPCScriptable::WANT_ADDPROPERTY)
 
   NS_DEFINE_CLASSINFO_DATA(PaintRequest, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(PaintRequestList, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(ScrollAreaEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
@@ -4274,16 +4277,20 @@ nsDOMClassInfo::Init()
   DOM_CLASSINFO_MAP_BEGIN(WebGLExtensionLoseContext, nsIWebGLExtensionLoseContext)
     DOM_CLASSINFO_MAP_ENTRY(nsIWebGLExtensionLoseContext)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(WebGLExtensionCompressedTextureS3TC, nsIWebGLExtensionCompressedTextureS3TC)
     DOM_CLASSINFO_MAP_ENTRY(nsIWebGLExtensionCompressedTextureS3TC)
   DOM_CLASSINFO_MAP_END
 
+  DOM_CLASSINFO_MAP_BEGIN(WebGLExtensionDepthTexture, nsIWebGLExtensionDepthTexture)
+    DOM_CLASSINFO_MAP_ENTRY(nsIWebGLExtensionDepthTexture)
+  DOM_CLASSINFO_MAP_END
+
   DOM_CLASSINFO_MAP_BEGIN(PaintRequest, nsIDOMPaintRequest)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMPaintRequest)
    DOM_CLASSINFO_MAP_END
  
   DOM_CLASSINFO_MAP_BEGIN(PaintRequestList, nsIDOMPaintRequestList)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMPaintRequestList)
   DOM_CLASSINFO_MAP_END
 
--- a/dom/base/nsDOMClassInfoClasses.h
+++ b/dom/base/nsDOMClassInfoClasses.h
@@ -458,16 +458,17 @@ DOMCI_CLASS(WebGLRenderbuffer)
 DOMCI_CLASS(WebGLUniformLocation)
 DOMCI_CLASS(WebGLShaderPrecisionFormat)
 DOMCI_CLASS(WebGLActiveInfo)
 DOMCI_CLASS(WebGLExtension)
 DOMCI_CLASS(WebGLExtensionStandardDerivatives)
 DOMCI_CLASS(WebGLExtensionTextureFilterAnisotropic)
 DOMCI_CLASS(WebGLExtensionLoseContext)
 DOMCI_CLASS(WebGLExtensionCompressedTextureS3TC)
+DOMCI_CLASS(WebGLExtensionDepthTexture)
 
 DOMCI_CLASS(PaintRequest)
 DOMCI_CLASS(PaintRequestList)
 
 DOMCI_CLASS(ScrollAreaEvent)
 
 DOMCI_CLASS(EventListenerInfo)
 
--- a/dom/interfaces/canvas/nsIDOMWebGLRenderingContext.idl
+++ b/dom/interfaces/canvas/nsIDOMWebGLRenderingContext.idl
@@ -150,16 +150,22 @@ interface nsIWebGLExtensionCompressedTex
 {
     /* Compressed Texture Formats */
     const WebGLenum COMPRESSED_RGB_S3TC_DXT1_EXT        = 0x83F0;
     const WebGLenum COMPRESSED_RGBA_S3TC_DXT1_EXT       = 0x83F1;
     const WebGLenum COMPRESSED_RGBA_S3TC_DXT3_EXT       = 0x83F2;
     const WebGLenum COMPRESSED_RGBA_S3TC_DXT5_EXT       = 0x83F3;
 };
 
+[scriptable, builtinclass, uuid(ef36f000-c1b2-11e1-afa7-0800200c9a66)]
+interface nsIWebGLExtensionDepthTexture : nsIWebGLExtension
+{
+  const WebGLenum UNSIGNED_INT_24_8_WEBGL = 0x84FA;
+};
+
 [scriptable, builtinclass, uuid(a1fdfb76-6a08-4a1a-b0c9-d92ef3357cb9)]
 interface nsIDOMWebGLRenderingContext : nsISupports
 {
   //
   //  CONSTANTS
   //
 
   /* ClearBufferMask */
--- a/dom/tests/mochitest/general/test_interfaces.html
+++ b/dom/tests/mochitest/general/test_interfaces.html
@@ -260,16 +260,17 @@ var interfaceNamesInGlobalScope =
     "MozSmsMessage",
     "SVGFESpecularLightingElement",
     "StorageObsolete",
     "ContactManager",
     "NSXPathExpression",
     "SVGLineElement",
     "SVGPathSegArcRel",
     "WebGLExtension",
+    "WebGLExtensionDepthTexture",
     "XSLTProcessor",
     "SVGPathSegLinetoVerticalAbs",
     "SVGPathSegLinetoRel",
     "HTMLImageElement",
     "MozSmsEvent",
     "CustomEvent",
     "XMLHttpRequestUpload",
     "SVGFEFuncBElement",
--- a/gfx/gl/GLContext.cpp
+++ b/gfx/gl/GLContext.cpp
@@ -75,16 +75,17 @@ static const char *sExtensionNames[] = {
     "GL_ANGLE_framebuffer_multisample",
     "GL_OES_rgb8_rgba8",
     "GL_ARB_robustness",
     "GL_EXT_robustness",
     "GL_ARB_sync",
     "GL_OES_EGL_image",
     "GL_OES_EGL_sync",
     "GL_OES_EGL_image_external",
+    "GL_EXT_packed_depth_stencil",
     nullptr
 };
 
 /*
  * XXX - we should really know the ARB/EXT variants of these
  * instead of only handling the symbol if it's exposed directly.
  */
 
--- a/gfx/gl/GLContext.h
+++ b/gfx/gl/GLContext.h
@@ -1586,16 +1586,17 @@ public:
         ANGLE_framebuffer_multisample,
         OES_rgb8_rgba8,
         ARB_robustness,
         EXT_robustness,
         ARB_sync,
         OES_EGL_image,
         OES_EGL_sync,
         OES_EGL_image_external,
+        EXT_packed_depth_stencil,
         Extensions_Max
     };
 
     bool IsExtensionSupported(GLExtensions aKnownExtension) {
         return mAvailableExtensions[aKnownExtension];
     }
 
     void MarkExtensionUnsupported(GLExtensions aKnownExtension) {
--- a/js/xpconnect/src/dom_quickstubs.qsconf
+++ b/js/xpconnect/src/dom_quickstubs.qsconf
@@ -496,16 +496,17 @@ irregularFilenames = {
     'nsIWebGLShaderPrecisionFormat' : 'nsIDOMWebGLRenderingContext',
     'nsIWebGLActiveInfo': 'nsIDOMWebGLRenderingContext',
     'nsIWebGLUniformLocation': 'nsIDOMWebGLRenderingContext',
     'nsIWebGLExtension': 'nsIDOMWebGLRenderingContext',
     'nsIWebGLExtensionStandardDerivatives' : 'nsIDOMWebGLRenderingContext',
     'nsIWebGLExtensionTextureFilterAnisotropic' : 'nsIDOMWebGLRenderingContext',
     'nsIWebGLExtensionLoseContext' : 'nsIDOMWebGLRenderingContext',
     'nsIWebGLExtensionCompressedTextureS3TC' : 'nsIDOMWebGLRenderingContext',
+    'nsIWebGLExtensionDepthTexture' : 'nsIDOMWebGLRenderingContext',
 
     'nsIIndexedDatabaseUsageCallback': 'nsIIndexedDatabaseManager',
 
     'nsIDOMTouch': 'nsIDOMTouchEvent',
     'nsIDOMTouchList': 'nsIDOMTouchEvent',
 
     'nsIDOMMutationRecord': 'nsIDOMMutationObserver',