void
WebGL2Context::InvalidateSubFramebuffer(GLenum target, const dom::Sequence<GLenum>& attachments,
                                        GLint x, GLint y, GLsizei width, GLsizei height,
                                        ErrorResult& rv)
{
    if (IsContextLost())
        return;

    MakeContextCurrent();

    if (!ValidateFramebufferTarget(target, "framebufferRenderbuffer"))
        return;

    const WebGLFramebuffer* fb;
    bool isDefaultFB;
    switch (target) {
    case LOCAL_GL_FRAMEBUFFER:
    case LOCAL_GL_DRAW_FRAMEBUFFER:
        fb = mBoundDrawFramebuffer;
        isDefaultFB = gl->Screen()->IsDrawFramebufferDefault();
        break;

    case LOCAL_GL_READ_FRAMEBUFFER:
        fb = mBoundReadFramebuffer;
        isDefaultFB = gl->Screen()->IsReadFramebufferDefault();
        break;

    default:
        MOZ_CRASH("Bad target.");
    }

    for (size_t i = 0; i < attachments.Length(); i++) {
        if (!ValidateFramebufferAttachment(fb, attachments[i],
                                           "invalidateSubFramebuffer"))
        {
            return;
        }
    }

    // InvalidateFramebuffer is a hint to the driver. Should be OK to
    // skip calls if not supported, for example by OSX 10.9 GL
    // drivers.
    static bool invalidateFBSupported = gl->IsSupported(gl::GLFeature::invalidate_framebuffer);
    if (!invalidateFBSupported)
        return;

    if (!fb && !isDefaultFB) {
        dom::Sequence<GLenum> tmpAttachments;
        if (!TranslateDefaultAttachments(attachments, &tmpAttachments)) {
            rv.Throw(NS_ERROR_OUT_OF_MEMORY);
            return;
        }

        gl->fInvalidateSubFramebuffer(target, tmpAttachments.Length(), tmpAttachments.Elements(),
                                      x, y, width, height);
    } else {
        gl->fInvalidateSubFramebuffer(target, attachments.Length(), attachments.Elements(),
                                      x, y, width, height);
    }
}
void
WebGL2Context::FramebufferTextureLayer(GLenum target, GLenum attachment,
                                       WebGLTexture* texture, GLint level, GLint layer)
{
    if (IsContextLost())
        return;

    if (!ValidateFramebufferTarget(target, "framebufferTextureLayer"))
        return;

    if (!ValidateTextureLayerAttachment(attachment))
        return ErrorInvalidEnumInfo("framebufferTextureLayer: attachment:", attachment);

    if (texture) {
        if (texture->IsDeleted()) {
            return ErrorInvalidValue("framebufferTextureLayer: texture must be a valid "
                                     "texture object.");
        }

        if (layer < 0)
            return ErrorInvalidValue("framebufferTextureLayer: layer must be >= 0.");

        if (level < 0)
            return ErrorInvalidValue("framebufferTextureLayer: level must be >= 0.");

        switch (texture->Target().get()) {
        case LOCAL_GL_TEXTURE_3D:
            if (uint32_t(layer) >= mImplMax3DTextureSize) {
                return ErrorInvalidValue("framebufferTextureLayer: layer must be < "
                                         "MAX_3D_TEXTURE_SIZE");
            }

            if (uint32_t(level) > FloorLog2(mImplMax3DTextureSize)) {
                return ErrorInvalidValue("framebufferTextureLayer: layer mube be <= "
                                         "log2(MAX_3D_TEXTURE_SIZE");
            }
            break;

        case LOCAL_GL_TEXTURE_2D_ARRAY:
            if (uint32_t(layer) >= mImplMaxArrayTextureLayers) {
                return ErrorInvalidValue("framebufferTextureLayer: layer must be < "
                                         "MAX_ARRAY_TEXTURE_LAYERS");
            }

            if (uint32_t(level) > FloorLog2(mImplMaxTextureSize)) {
                return ErrorInvalidValue("framebufferTextureLayer: layer mube be <= "
                                         "log2(MAX_TEXTURE_SIZE");
            }
            break;

        default:
            return ErrorInvalidOperation("framebufferTextureLayer: texture must be an "
                                         "existing 3D texture, or a 2D texture array.");
        }
    }

    WebGLFramebuffer* fb;
    switch (target) {
    case LOCAL_GL_FRAMEBUFFER:
    case LOCAL_GL_DRAW_FRAMEBUFFER:
        fb = mBoundDrawFramebuffer;
        break;

    case LOCAL_GL_READ_FRAMEBUFFER:
        fb = mBoundReadFramebuffer;
        break;

    default:
        MOZ_CRASH("Bad target.");
    }

    if (!fb) {
        return ErrorInvalidOperation("framebufferTextureLayer: cannot modify"
                                     " framebuffer 0.");
    }

    fb->FramebufferTextureLayer(attachment, texture, level, layer);
}