Merge m-c to fx-team.
authorRyan VanderMeulen <ryanvm@gmail.com>
Thu, 29 May 2014 14:37:13 -0400
changeset 204942 20987367996183a3d13c835fb6935defe376cb35
parent 204941 5251f3425c4a64885dc1769c3bc28f2ab69838d8 (current diff)
parent 204825 b85b57f05fdae10e36ab79a92eab1c5cea1fe41c (diff)
child 204943 2c1b825d4bdf203aaa82db84897000768bff7283
push id3741
push userasasaki@mozilla.com
push dateMon, 21 Jul 2014 20:25:18 +0000
treeherdermozilla-beta@4d6f46f5af68 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone32.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
Merge m-c to fx-team.
--- a/content/canvas/src/WebGLContext.cpp
+++ b/content/canvas/src/WebGLContext.cpp
@@ -78,31 +78,28 @@ WebGLMemoryPressureObserver::Observe(nsI
 {
     if (strcmp(aTopic, "memory-pressure"))
         return NS_OK;
 
     bool wantToLoseContext = true;
 
     if (!mContext->mCanLoseContextInForeground &&
         ProcessPriorityManager::CurrentProcessIsForeground())
-    {
         wantToLoseContext = false;
-    } else if (!nsCRT::strcmp(aSomeData,
-                              MOZ_UTF16("heap-minimize")))
-    {
+    else if (!nsCRT::strcmp(aSomeData,
+                            MOZ_UTF16("heap-minimize")))
         wantToLoseContext = mContext->mLoseContextOnHeapMinimize;
-    }
 
-    if (wantToLoseContext) {
+    if (wantToLoseContext)
         mContext->ForceLoseContext();
-    }
 
     return NS_OK;
 }
 
+
 WebGLContextOptions::WebGLContextOptions()
     : alpha(true), depth(true), stencil(false),
       premultipliedAlpha(true), antialias(true),
       preserveDrawingBuffer(false)
 {
     // Set default alpha state based on preference.
     if (Preferences::GetBool("webgl.default-no-alpha", false))
         alpha = false;
@@ -166,22 +163,22 @@ WebGLContext::WebGLContext()
     mGLMaxTransformFeedbackSeparateAttribs = 0;
 
     // See OpenGL ES 2.0.25 spec, 6.2 State Tables, table 6.13
     mPixelStorePackAlignment = 4;
     mPixelStoreUnpackAlignment = 4;
 
     WebGLMemoryTracker::AddWebGLContext(this);
 
-    mAllowContextRestore = true;
-    mLastLossWasSimulated = false;
+    mAllowRestore = true;
     mContextLossTimerRunning = false;
-    mRunContextLossTimerAgain = false;
+    mDrawSinceContextLossTimerSet = false;
     mContextRestorer = do_CreateInstance("@mozilla.org/timer;1");
     mContextStatus = ContextNotLost;
+    mContextLostErrorSet = false;
     mLoseContextOnHeapMinimize = false;
     mCanLoseContextInForeground = true;
 
     mAlreadyGeneratedWarnings = 0;
     mAlreadyWarnedAboutFakeVertexAttrib0 = false;
     mAlreadyWarnedAboutViewportLargerThanDest = false;
     mMaxWarnings = Preferences::GetInt("webgl.max-warnings-per-context", 32);
     if (mMaxWarnings < -1)
@@ -569,18 +566,21 @@ WebGLContext::SetDimensions(int32_t widt
 
     mWidth = width;
     mHeight = height;
     mViewportWidth = width;
     mViewportHeight = height;
     mResetLayer = true;
     mOptionsFrozen = true;
 
+    mHasRobustness = gl->HasRobustness();
+
     // increment the generation number
     ++mGeneration;
+
 #if 0
     if (mGeneration > 0) {
         // XXX dispatch context lost event
     }
 #endif
 
     MakeContextCurrent();
 
@@ -1110,238 +1110,162 @@ WebGLContext::PresentScreenBuffer()
 void
 WebGLContext::DummyFramebufferOperation(const char *info)
 {
     GLenum status = CheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
     if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE)
         ErrorInvalidFramebufferOperation("%s: incomplete framebuffer", info);
 }
 
-static bool
-CheckContextLost(GLContext* gl, bool* out_isGuilty)
-{
-    MOZ_ASSERT(gl);
-    MOZ_ASSERT(out_isGuilty);
-
-    bool isEGL = gl->GetContextType() == gl::GLContextType::EGL;
-
-    GLenum resetStatus = LOCAL_GL_NO_ERROR;
-    if (gl->HasRobustness()) {
-        gl->MakeCurrent();
-        resetStatus = gl->fGetGraphicsResetStatus();
-    } else if (isEGL) {
-        // Simulate a ARB_robustness guilty context loss for when we
-        // get an EGL_CONTEXT_LOST error. It may not actually be guilty,
-        // but we can't make any distinction.
-        if (!gl->MakeCurrent(true) && gl->IsContextLost()) {
-            resetStatus = LOCAL_GL_UNKNOWN_CONTEXT_RESET_ARB;
-        }
-    }
-
-    if (resetStatus == LOCAL_GL_NO_ERROR) {
-        *out_isGuilty = false;
-        return false;
-    }
-
-    // Assume guilty unless we find otherwise!
-    bool isGuilty = true;
-    switch (resetStatus) {
-    case LOCAL_GL_INNOCENT_CONTEXT_RESET_ARB:
-        // Either nothing wrong, or not our fault.
-        isGuilty = false;
-        break;
-    case LOCAL_GL_GUILTY_CONTEXT_RESET_ARB:
-        NS_WARNING("WebGL content on the page definitely caused the graphics"
-                   " card to reset.");
-        break;
-    case LOCAL_GL_UNKNOWN_CONTEXT_RESET_ARB:
-        NS_WARNING("WebGL content on the page might have caused the graphics"
-                   " card to reset");
-        // If we can't tell, assume guilty.
-        break;
-    default:
-        MOZ_ASSERT(false, "Unreachable.");
-        // If we do get here, let's pretend to be guilty as an escape plan.
-        break;
-    }
-
-    if (isGuilty) {
-        NS_WARNING("WebGL context on this page is considered guilty, and will"
-                   " not be restored.");
-    }
-
-    *out_isGuilty = isGuilty;
-    return true;
-}
-
-bool
-WebGLContext::TryToRestoreContext()
-{
-    if (NS_FAILED(SetDimensions(mWidth, mHeight)))
-        return false;
-
-    return true;
-}
-
-class UpdateContextLossStatusTask : public nsRunnable
-{
-    WebGLContext* const mContext;
-
-public:
-    UpdateContextLossStatusTask(WebGLContext* context)
-        : mContext(context)
-    {
-    }
-
-    NS_IMETHOD Run() {
-        mContext->UpdateContextLossStatus();
-
-        return NS_OK;
-    }
-};
-
-void
-WebGLContext::EnqueueUpdateContextLossStatus()
-{
-    nsCOMPtr<nsIRunnable> task = new UpdateContextLossStatusTask(this);
-    NS_DispatchToCurrentThread(task);
-}
-
 // We use this timer for many things. Here are the things that it is activated for:
 // 1) If a script is using the MOZ_WEBGL_lose_context extension.
 // 2) If we are using EGL and _NOT ANGLE_, we query periodically to see if the
 //    CONTEXT_LOST_WEBGL error has been triggered.
 // 3) If we are using ANGLE, or anything that supports ARB_robustness, query the
 //    GPU periodically to see if the reset status bit has been set.
 // In all of these situations, we use this timer to send the script context lost
 // and restored events asynchronously. For example, if it triggers a context loss,
 // the webglcontextlost event will be sent to it the next time the robustness timer
 // fires.
 // Note that this timer mechanism is not used unless one of these 3 criteria
 // are met.
 // At a bare minimum, from context lost to context restores, it would take 3
 // full timer iterations: detection, webglcontextlost, webglcontextrestored.
 void
-WebGLContext::UpdateContextLossStatus()
+WebGLContext::RobustnessTimerCallback(nsITimer* timer)
 {
+    TerminateContextLossTimer();
+
     if (!mCanvasElement) {
         // the canvas is gone. That happens when the page was closed before we got
         // this timer event. In this case, there's nothing to do here, just don't crash.
         return;
     }
-    if (mContextStatus == ContextNotLost) {
-        // We don't know that we're lost, but we might be, so we need to
-        // check. If we're guilty, don't allow restores, though.
 
-        bool isGuilty = true;
-        bool isContextLost = CheckContextLost(gl, &isGuilty);
-
-        if (isContextLost) {
-            if (isGuilty)
-                mAllowContextRestore = false;
-
-            ForceLoseContext();
-        }
-
-        // Fall through.
-    }
-
+    // If the context has been lost and we're waiting for it to be restored, do
+    // that now.
     if (mContextStatus == ContextLostAwaitingEvent) {
-        // The context has been lost and we haven't yet triggered the
-        // callback, so do that now.
-
-        bool useDefaultHandler;
+        bool defaultAction;
         nsContentUtils::DispatchTrustedEvent(mCanvasElement->OwnerDoc(),
                                              static_cast<nsIDOMHTMLCanvasElement*>(mCanvasElement),
                                              NS_LITERAL_STRING("webglcontextlost"),
                                              true,
                                              true,
-                                             &useDefaultHandler);
-        // We sent the callback, so we're just 'regular lost' now.
-        mContextStatus = ContextLost;
-        // If we're told to use the default handler, it means the script
-        // didn't bother to handle the event. In this case, we shouldn't
-        // auto-restore the context.
-        if (useDefaultHandler)
-            mAllowContextRestore = false;
+                                             &defaultAction);
 
-        // Fall through.
-    }
-
-    if (mContextStatus == ContextLost) {
-        // Context is lost, and we've already sent the callback. We
-        // should try to restore the context if we're both allowed to,
-        // and supposed to.
+        // If the script didn't handle the event, we don't allow restores.
+        if (defaultAction)
+            mAllowRestore = false;
 
-        // Are we allowed to restore the context?
-        if (!mAllowContextRestore)
-            return;
-
-        // If we're only simulated-lost, we shouldn't auto-restore, and
-        // instead we should wait for restoreContext() to be called.
-        if (mLastLossWasSimulated)
-            return;
-
-        ForceRestoreContext();
-        return;
-    }
-
-    if (mContextStatus == ContextLostAwaitingRestore) {
-        // Context is lost, but we should try to restore it.
-
-        if (!mAllowContextRestore) {
-            // We might decide this after thinking we'd be OK restoring
-            // the context, so downgrade.
+        // If the script handled the event and we are allowing restores, then
+        // mark it to be restored. Otherwise, leave it as context lost
+        // (unusable).
+        if (!defaultAction && mAllowRestore) {
+            ForceRestoreContext();
+            // Restart the timer so that it will be restored on the next
+            // callback.
+            SetupContextLossTimer();
+        } else {
             mContextStatus = ContextLost;
+        }
+    } else if (mContextStatus == ContextLostAwaitingRestore) {
+        // Try to restore the context. If it fails, try again later.
+        if (NS_FAILED(SetDimensions(mWidth, mHeight))) {
+            SetupContextLossTimer();
             return;
         }
-
-        if (!TryToRestoreContext()) {
-            // Failed to restore. Try again later.
-            RunContextLossTimer();
-            return;
-        }
-
-        // Revival!
         mContextStatus = ContextNotLost;
         nsContentUtils::DispatchTrustedEvent(mCanvasElement->OwnerDoc(),
                                              static_cast<nsIDOMHTMLCanvasElement*>(mCanvasElement),
                                              NS_LITERAL_STRING("webglcontextrestored"),
                                              true,
                                              true);
+        // Set all flags back to the state they were in before the context was
+        // lost.
         mEmitContextLostErrorOnce = true;
+        mAllowRestore = true;
+    }
+
+    MaybeRestoreContext();
+    return;
+}
+
+void
+WebGLContext::MaybeRestoreContext()
+{
+    // Don't try to handle it if we already know it's busted.
+    if (mContextStatus != ContextNotLost || gl == nullptr)
         return;
+
+    bool isEGL = gl->GetContextType() == gl::GLContextType::EGL,
+         isANGLE = gl->IsANGLE();
+
+    GLContext::ContextResetARB resetStatus = GLContext::CONTEXT_NO_ERROR;
+    if (mHasRobustness) {
+        gl->MakeCurrent();
+        resetStatus = (GLContext::ContextResetARB) gl->fGetGraphicsResetStatus();
+    } else if (isEGL) {
+        // Simulate a ARB_robustness guilty context loss for when we
+        // get an EGL_CONTEXT_LOST error. It may not actually be guilty,
+        // but we can't make any distinction, so we must assume the worst
+        // case.
+        if (!gl->MakeCurrent(true) && gl->IsContextLost()) {
+            resetStatus = GLContext::CONTEXT_GUILTY_CONTEXT_RESET_ARB;
+        }
+    }
+
+    if (resetStatus != GLContext::CONTEXT_NO_ERROR) {
+        // It's already lost, but clean up after it and signal to JS that it is
+        // lost.
+        ForceLoseContext();
+    }
+
+    switch (resetStatus) {
+        case GLContext::CONTEXT_NO_ERROR:
+            // If there has been activity since the timer was set, it's possible
+            // that we did or are going to miss something, so clear this flag and
+            // run it again some time later.
+            if (mDrawSinceContextLossTimerSet)
+                SetupContextLossTimer();
+            break;
+        case GLContext::CONTEXT_GUILTY_CONTEXT_RESET_ARB:
+            NS_WARNING("WebGL content on the page caused the graphics card to reset; not restoring the context");
+            mAllowRestore = false;
+            break;
+        case GLContext::CONTEXT_INNOCENT_CONTEXT_RESET_ARB:
+            break;
+        case GLContext::CONTEXT_UNKNOWN_CONTEXT_RESET_ARB:
+            NS_WARNING("WebGL content on the page might have caused the graphics card to reset");
+            if (isEGL && isANGLE) {
+                // If we're using ANGLE, we ONLY get back UNKNOWN context resets, including for guilty contexts.
+                // This means that we can't restore it or risk restoring a guilty context. Should this ever change,
+                // we can get rid of the whole IsANGLE() junk from GLContext.h since, as of writing, this is the
+                // only use for it. See ANGLE issue 261.
+                mAllowRestore = false;
+            }
+            break;
     }
 }
 
 void
 WebGLContext::ForceLoseContext()
 {
-    printf_stderr("WebGL(%p)::ForceLoseContext\n", this);
-    MOZ_ASSERT(!IsContextLost());
-    mContextStatus = ContextLostAwaitingEvent;
-    mContextLostErrorSet = false;
-    mLastLossWasSimulated = false;
+    if (mContextStatus == ContextLostAwaitingEvent)
+        return;
 
-    // Burn it all!
+    mContextStatus = ContextLostAwaitingEvent;
+    // Queue up a task to restore the event.
+    SetupContextLossTimer();
     DestroyResourcesAndContext();
-
-    // Queue up a task, since we know the status changed.
-    EnqueueUpdateContextLossStatus();
 }
 
 void
 WebGLContext::ForceRestoreContext()
 {
-    printf_stderr("WebGL(%p)::ForceRestoreContext\n", this);
     mContextStatus = ContextLostAwaitingRestore;
-    mAllowContextRestore = true; // Hey, you did say 'force'.
-
-    // Queue up a task, since we know the status changed.
-    EnqueueUpdateContextLossStatus();
 }
 
 void
 WebGLContext::MakeContextCurrent() const { gl->MakeCurrent(); }
 
 mozilla::TemporaryRef<mozilla::gfx::SourceSurface>
 WebGLContext::GetSurfaceSnapshot(bool* aPremultAlpha)
 {
--- a/content/canvas/src/WebGLContext.h
+++ b/content/canvas/src/WebGLContext.h
@@ -197,16 +197,19 @@ public:
     NS_IMETHOD Redraw(const gfxRect&) { return NS_ERROR_NOT_IMPLEMENTED; }
     NS_IMETHOD Swap(mozilla::ipc::Shmem& aBack,
                     int32_t x, int32_t y, int32_t w, int32_t h)
                     { return NS_ERROR_NOT_IMPLEMENTED; }
     NS_IMETHOD Swap(uint32_t nativeID,
                     int32_t x, int32_t y, int32_t w, int32_t h)
                     { return NS_ERROR_NOT_IMPLEMENTED; }
 
+    bool LoseContext();
+    bool RestoreContext();
+
     void SynthesizeGLError(GLenum err);
     void SynthesizeGLError(GLenum err, const char *fmt, ...);
 
     void ErrorInvalidEnum(const char *fmt = 0, ...);
     void ErrorInvalidOperation(const char *fmt = 0, ...);
     void ErrorInvalidValue(const char *fmt = 0, ...);
     void ErrorInvalidFramebufferOperation(const char *fmt = 0, ...);
     void ErrorInvalidEnumInfo(const char *info, GLenum enumvalue);
@@ -253,24 +256,21 @@ public:
     void ForceClearFramebufferWithDefaultValues(GLbitfield mask, const bool colorAttachmentsMask[kMaxColorAttachments]);
 
     // Calls ForceClearFramebufferWithDefaultValues() for the Context's 'screen'.
     void ClearScreen();
     void ClearBackbufferIfNeeded();
 
     bool MinCapabilityMode() const { return mMinCapability; }
 
-    void UpdateContextLossStatus();
-    void EnqueueUpdateContextLossStatus();
-    static void ContextLossCallbackStatic(nsITimer* timer, void* thisPointer);
-    void RunContextLossTimer();
+    void RobustnessTimerCallback(nsITimer* timer);
+    static void RobustnessTimerCallbackStatic(nsITimer* timer, void *thisPointer);
+    void SetupContextLossTimer();
     void TerminateContextLossTimer();
 
-    bool TryToRestoreContext();
-
     void AssertCachedBindings();
     void AssertCachedState();
 
     // WebIDL WebGLRenderingContext API
     dom::HTMLCanvasElement* GetCanvas() const { return mCanvasElement; }
     GLsizei DrawingBufferWidth() const { return IsContextLost() ? 0 : mWidth; }
     GLsizei DrawingBufferHeight() const { return IsContextLost() ? 0 : mHeight; }
 
@@ -661,22 +661,18 @@ public:
                                           GLint& location, uint32_t& numElementsToUpload, uint32_t arrayLength,
                                           WebGLboolean aTranspose);
     bool ValidateUniformSetter(const char* name, WebGLUniformLocation *location_object, GLint& location);
     void ValidateProgram(WebGLProgram *prog);
     bool ValidateUniformLocation(const char* info, WebGLUniformLocation *location_object);
     bool ValidateSamplerUniformSetter(const char* info,
                                     WebGLUniformLocation *location,
                                     GLint value);
+
     void Viewport(GLint x, GLint y, GLsizei width, GLsizei height);
-// -----------------------------------------------------------------------------
-// WEBGL_lose_context
-public:
-    void LoseContext();
-    void RestoreContext();
 
 // -----------------------------------------------------------------------------
 // Asynchronous Queries (WebGLContextAsyncQueries.cpp)
 public:
     already_AddRefed<WebGLQuery> CreateQuery();
     void DeleteQuery(WebGLQuery *query);
     void BeginQuery(GLenum target, WebGLQuery *query);
     void EndQuery(GLenum target);
@@ -868,16 +864,17 @@ protected:
 
     WebGLContextOptions mOptions;
 
     bool mInvalidated;
     bool mResetLayer;
     bool mOptionsFrozen;
     bool mMinCapability;
     bool mDisableExtensions;
+    bool mHasRobustness;
     bool mIsMesa;
     bool mLoseContextOnHeapMinimize;
     bool mCanLoseContextInForeground;
     bool mShouldPresent;
     bool mBackbufferNeedsClear;
     bool mDisableFragHighP;
 
     template<typename WebGLObjectType>
@@ -1114,16 +1111,17 @@ protected:
                              GLenum internalFormat,
                              GLsizei width,
                              GLsizei height,
                              GLint border,
                              GLenum format,
                              GLenum type,
                              const GLvoid *data);
 
+    void MaybeRestoreContext();
     void ForceLoseContext();
     void ForceRestoreContext();
 
     nsTArray<WebGLRefPtr<WebGLTexture> > mBound2DTextures;
     nsTArray<WebGLRefPtr<WebGLTexture> > mBoundCubeMapTextures;
 
     WebGLRefPtr<WebGLProgram> mCurrentProgram;
 
@@ -1175,34 +1173,33 @@ protected:
     GLfloat mVertexAttrib0Vector[4];
     GLfloat mFakeVertexAttrib0BufferObjectVector[4];
     size_t mFakeVertexAttrib0BufferObjectSize;
     GLuint mFakeVertexAttrib0BufferObject;
     WebGLVertexAttrib0Status mFakeVertexAttrib0BufferStatus;
 
     GLint mStencilRefFront, mStencilRefBack;
     GLuint mStencilValueMaskFront, mStencilValueMaskBack,
-           mStencilWriteMaskFront, mStencilWriteMaskBack;
+              mStencilWriteMaskFront, mStencilWriteMaskBack;
     realGLboolean mColorWriteMask[4];
     realGLboolean mDepthWriteMask;
     GLfloat mColorClearValue[4];
     GLint mStencilClearValue;
     GLfloat mDepthClearValue;
 
     GLint mViewportX;
     GLint mViewportY;
     GLsizei mViewportWidth;
     GLsizei mViewportHeight;
     bool mAlreadyWarnedAboutViewportLargerThanDest;
 
     nsCOMPtr<nsITimer> mContextRestorer;
-    bool mAllowContextRestore;
-    bool mLastLossWasSimulated;
+    bool mAllowRestore;
     bool mContextLossTimerRunning;
-    bool mRunContextLossTimerAgain;
+    bool mDrawSinceContextLossTimerSet;
     ContextStatus mContextStatus;
     bool mContextLostErrorSet;
 
     // Used for some hardware (particularly Tegra 2 and 4) that likes to
     // be Flushed while doing hundreds of draw calls.
     int mDrawCallsSinceLastFlush;
 
     int mAlreadyGeneratedWarnings;
--- a/content/canvas/src/WebGLContextDraw.cpp
+++ b/content/canvas/src/WebGLContextDraw.cpp
@@ -123,17 +123,17 @@ WebGLContext::DrawArrays(GLenum mode, GL
         return;
 
     if (!ValidateDrawModeEnum(mode, "drawArrays: mode"))
         return;
 
     if (!DrawArrays_check(first, count, 1, "drawArrays"))
         return;
 
-    RunContextLossTimer();
+    SetupContextLossTimer();
     gl->fDrawArrays(mode, first, count);
 
     Draw_cleanup();
 }
 
 void
 WebGLContext::DrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei primcount)
 {
@@ -144,17 +144,17 @@ WebGLContext::DrawArraysInstanced(GLenum
         return;
 
     if (!DrawArrays_check(first, count, primcount, "drawArraysInstanced"))
         return;
 
     if (!DrawInstanced_check("drawArraysInstanced"))
         return;
 
-    RunContextLossTimer();
+    SetupContextLossTimer();
     gl->fDrawArraysInstanced(mode, first, count, primcount);
 
     Draw_cleanup();
 }
 
 bool
 WebGLContext::DrawElements_check(GLsizei count, GLenum type,
                                  WebGLintptr byteOffset, GLsizei primcount,
@@ -291,17 +291,17 @@ WebGLContext::DrawElements(GLenum mode, 
 
     GLuint upperBound = UINT_MAX;
     if (!DrawElements_check(count, type, byteOffset, 1, "drawElements",
                             &upperBound))
     {
         return;
     }
 
-    RunContextLossTimer();
+    SetupContextLossTimer();
 
     if (gl->IsSupported(gl::GLFeature::draw_range_elements)) {
         gl->fDrawRangeElements(mode, 0, upperBound,
                                count, type, reinterpret_cast<GLvoid*>(byteOffset));
     } else {
         gl->fDrawElements(mode, count, type, reinterpret_cast<GLvoid*>(byteOffset));
     }
 
@@ -319,17 +319,17 @@ WebGLContext::DrawElementsInstanced(GLen
         return;
 
     if (!DrawElements_check(count, type, byteOffset, primcount, "drawElementsInstanced"))
         return;
 
     if (!DrawInstanced_check("drawElementsInstanced"))
         return;
 
-    RunContextLossTimer();
+    SetupContextLossTimer();
     gl->fDrawElementsInstanced(mode, count, type, reinterpret_cast<GLvoid*>(byteOffset), primcount);
 
     Draw_cleanup();
 }
 
 void WebGLContext::Draw_cleanup()
 {
     UndoFakeVertexAttrib0();
--- a/content/canvas/src/WebGLContextGL.cpp
+++ b/content/canvas/src/WebGLContextGL.cpp
@@ -3852,44 +3852,37 @@ WebGLContext::TexSubImage2D(GLenum targe
     return TexSubImage2D_base(target, level, xoffset, yoffset,
                               pixels->Width(), pixels->Height(),
                               4*pixels->Width(), format, type,
                               arr.Data(), arr.Length(),
                               -1,
                               WebGLTexelFormat::RGBA8, false);
 }
 
-void
+bool
 WebGLContext::LoseContext()
 {
     if (IsContextLost())
-        return ErrorInvalidOperation("loseContext: Context is already lost.");
+        return false;
 
     ForceLoseContext();
-    mLastLossWasSimulated = true;
+
+    return true;
 }
 
-void
+bool
 WebGLContext::RestoreContext()
 {
-    if (!IsContextLost())
-        return ErrorInvalidOperation("restoreContext: Context is not lost.");
-
-    if (!mLastLossWasSimulated) {
-        return ErrorInvalidOperation("restoreContext: Context loss was not simulated."
-                                     " Cannot simulate restore.");
+    if (!IsContextLost() || !mAllowRestore) {
+        return false;
     }
-    // If we're currently lost, and the last loss was simulated, then
-    // we're currently only simulated-lost, allowing us to call
-    // restoreContext().
-
-    if (!mAllowContextRestore)
-        return ErrorInvalidOperation("restoreContext: Context cannot be restored.");
 
     ForceRestoreContext();
+
+    return true;
 }
 
 bool
 BaseTypeAndSizeFromUniformType(GLenum uType, GLenum *baseType, GLint *unitSize)
 {
     switch (uType) {
         case LOCAL_GL_INT:
         case LOCAL_GL_INT_VEC2:
--- a/content/canvas/src/WebGLContextLossTimer.cpp
+++ b/content/canvas/src/WebGLContextLossTimer.cpp
@@ -3,50 +3,38 @@
  * 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"
 
 using namespace mozilla;
 
 /* static */ void
-WebGLContext::ContextLossCallbackStatic(nsITimer* timer, void* thisPointer)
-{
-    (void)timer;
-    WebGLContext* context = static_cast<WebGLContext*>(thisPointer);
-
-    context->TerminateContextLossTimer();
-
-    context->UpdateContextLossStatus();
+WebGLContext::RobustnessTimerCallbackStatic(nsITimer* timer, void *thisPointer) {
+    static_cast<WebGLContext*>(thisPointer)->RobustnessTimerCallback(timer);
 }
 
 void
-WebGLContext::RunContextLossTimer()
-{
+WebGLContext::SetupContextLossTimer() {
     // If the timer was already running, don't restart it here. Instead,
     // wait until the previous call is done, then fire it one more time.
-    // This is an optimization to prevent unnecessary
-    // cross-communication between threads.
+    // This is an optimization to prevent unnecessary cross-communication
+    // between threads.
     if (mContextLossTimerRunning) {
-        mRunContextLossTimerAgain = true;
+        mDrawSinceContextLossTimerSet = true;
         return;
     }
-    mContextRestorer->InitWithFuncCallback(ContextLossCallbackStatic,
-                                           static_cast<void*>(this),
-                                           1000,
-                                           nsITimer::TYPE_ONE_SHOT);
+
+    mContextRestorer->InitWithFuncCallback(RobustnessTimerCallbackStatic,
+                                            static_cast<void*>(this),
+                                            1000,
+                                            nsITimer::TYPE_ONE_SHOT);
     mContextLossTimerRunning = true;
-    mRunContextLossTimerAgain = false;
+    mDrawSinceContextLossTimerSet = false;
 }
 
 void
-WebGLContext::TerminateContextLossTimer()
-{
-    if (!mContextLossTimerRunning)
-        return;
-
-    mContextRestorer->Cancel();
-    mContextLossTimerRunning = false;
-
-    if (mRunContextLossTimerAgain) {
-        RunContextLossTimer();
+WebGLContext::TerminateContextLossTimer() {
+    if (mContextLossTimerRunning) {
+        mContextRestorer->Cancel();
+        mContextLossTimerRunning = false;
     }
 }
--- a/content/canvas/src/WebGLExtensionLoseContext.cpp
+++ b/content/canvas/src/WebGLExtensionLoseContext.cpp
@@ -16,18 +16,20 @@ WebGLExtensionLoseContext::WebGLExtensio
 
 WebGLExtensionLoseContext::~WebGLExtensionLoseContext()
 {
 }
 
 void
 WebGLExtensionLoseContext::LoseContext()
 {
-    mContext->LoseContext();
+    if (!mContext->LoseContext())
+        mContext->mWebGLError = LOCAL_GL_INVALID_OPERATION;
 }
 
-void
+void 
 WebGLExtensionLoseContext::RestoreContext()
 {
-    mContext->RestoreContext();
+    if (!mContext->RestoreContext())
+        mContext->mWebGLError = LOCAL_GL_INVALID_OPERATION;
 }
 
 IMPL_WEBGL_EXTENSION_GOOP(WebGLExtensionLoseContext)
--- a/content/canvas/test/webgl-conformance/conformance/context/context-lost-restored.html
+++ b/content/canvas/test/webgl-conformance/conformance/context/context-lost-restored.html
@@ -94,17 +94,17 @@ function testLosingAndRestoringContext()
     debug("");
     debug("Test losing and restoring a context.");
 
     canvas.addEventListener("webglcontextlost", function(e) {
       testLostContext(e);
       // restore the context after this event has exited.
       setTimeout(function() {
         shouldGenerateGLError(gl, gl.NO_ERROR, "extension.restoreContext()");
-        // The context should still be lost. It will not get restored until the
+        // The context should still be lost. It will not get restored until the 
         // webglrestorecontext event is fired.
         shouldBeTrue("gl.isContextLost()");
         shouldBe("gl.getError()", "gl.NO_ERROR");
         // gl methods should still be no-ops
         shouldGenerateGLError(gl, gl.NO_ERROR, "gl.blendFunc(gl.TEXTURE_2D, gl.TEXTURE_CUBE_MAP)");
       }, 0);
     });
     canvas.addEventListener("webglcontextrestored", function() {
--- a/gfx/gl/GLContext.h
+++ b/gfx/gl/GLContext.h
@@ -2695,16 +2695,29 @@ public:
 
     // Shared code for GL extensions and GLX extensions.
     static bool ListHasExtension(const GLubyte *extensions,
                                  const char *extension);
 
     GLint GetMaxTextureImageSize() { return mMaxTextureImageSize; }
 
 public:
+    /**
+     * Context reset constants.
+     * These are used to determine who is guilty when a context reset
+     * happens.
+     */
+    enum ContextResetARB {
+        CONTEXT_NO_ERROR = 0,
+        CONTEXT_GUILTY_CONTEXT_RESET_ARB = 0x8253,
+        CONTEXT_INNOCENT_CONTEXT_RESET_ARB = 0x8254,
+        CONTEXT_UNKNOWN_CONTEXT_RESET_ARB = 0x8255
+    };
+
+public:
     std::map<GLuint, SharedSurface_GL*> mFBOMapping;
 
     enum {
         DebugEnabled = 1 << 0,
         DebugTrace = 1 << 1,
         DebugAbortOnError = 1 << 2
     };
 
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -3006,16 +3006,17 @@ nsHttpChannel::OnCacheEntryCheck(nsICach
     if (mCachedContentIsValid || mDidReval) {
         rv = OpenCacheInputStream(entry, mCachedContentIsValid);
         if (NS_FAILED(rv)) {
             // If we can't get the entity then we have to act as though we
             // don't have the cache entry.
             if (mDidReval) {
                 // Make the request unconditional again.
                 mRequestHead.ClearHeader(nsHttp::If_Modified_Since);
+                mRequestHead.ClearHeader(nsHttp::If_None_Match);
                 mRequestHead.ClearHeader(nsHttp::ETag);
                 mDidReval = false;
             }
             mCachedContentIsValid = false;
         }
     }
 
     if (mDidReval)