mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 710163: fix EXT_lose_context semantics r=bjacob
The EXT_lose_context extension spec has had updates from Khronos which break our current implementation. Primarily, it is mostly asynchronous now with more heavily defined behavior. NOTE: This patch will not pass on our current copy of context-lost.html and context-lost-restored.html see bug for more info.
This commit is contained in:
parent
0824cb64ed
commit
f0ca08618c
@ -292,11 +292,13 @@ WebGLContext::WebGLContext()
|
||||
|
||||
WebGLMemoryReporter::AddWebGLContext(this);
|
||||
|
||||
mContextLost = false;
|
||||
mAllowRestore = false;
|
||||
mAllowRestore = true;
|
||||
mRobustnessTimerRunning = false;
|
||||
mDrawSinceRobustnessTimerSet = false;
|
||||
mContextRestorer = do_CreateInstance("@mozilla.org/timer;1");
|
||||
mContextStatus = ContextStable;
|
||||
mContextLostErrorSet = false;
|
||||
mContextLostDueToTest = false;
|
||||
}
|
||||
|
||||
WebGLContext::~WebGLContext()
|
||||
@ -948,7 +950,7 @@ bool WebGLContext::IsExtensionSupported(WebGLExtensionID ei)
|
||||
// We always support this extension.
|
||||
isSupported = true;
|
||||
break;
|
||||
case WebGL_WEBGL_EXT_lose_context:
|
||||
case WebGL_MOZ_WEBGL_lose_context:
|
||||
// We always support this extension.
|
||||
isSupported = true;
|
||||
break;
|
||||
@ -980,9 +982,9 @@ WebGLContext::GetExtension(const nsAString& aName, nsIWebGLExtension **retval)
|
||||
if (IsExtensionSupported(WebGL_OES_standard_derivatives))
|
||||
ei = WebGL_OES_standard_derivatives;
|
||||
}
|
||||
else if (aName.EqualsLiteral("WEBGL_EXT_lose_context")) {
|
||||
if (IsExtensionSupported(WebGL_WEBGL_EXT_lose_context))
|
||||
ei = WebGL_WEBGL_EXT_lose_context;
|
||||
else if (aName.EqualsLiteral("MOZ_WEBGL_lose_context")) {
|
||||
if (IsExtensionSupported(WebGL_MOZ_WEBGL_lose_context))
|
||||
ei = WebGL_MOZ_WEBGL_lose_context;
|
||||
}
|
||||
|
||||
if (ei != WebGLExtensionID_Max) {
|
||||
@ -991,7 +993,7 @@ WebGLContext::GetExtension(const nsAString& aName, nsIWebGLExtension **retval)
|
||||
case WebGL_OES_standard_derivatives:
|
||||
mEnabledExtensions[ei] = new WebGLExtensionStandardDerivatives(this);
|
||||
break;
|
||||
case WebGL_WEBGL_EXT_lose_context:
|
||||
case WebGL_MOZ_WEBGL_lose_context:
|
||||
mEnabledExtensions[ei] = new WebGLExtensionLoseContext(this);
|
||||
break;
|
||||
// create an extension for any types that don't
|
||||
@ -1097,10 +1099,69 @@ WebGLContext::EnsureBackbufferClearedAsNeeded()
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
// 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.
|
||||
NS_IMETHODIMP
|
||||
WebGLContext::Notify(nsITimer* timer)
|
||||
{
|
||||
TerminateRobustnessTimer();
|
||||
// If the context has been lost and we're waiting for it to be restored, do
|
||||
// that now.
|
||||
if (mContextStatus == ContextLostAwaitingEvent) {
|
||||
bool defaultAction;
|
||||
nsContentUtils::DispatchTrustedEvent(HTMLCanvasElement()->OwnerDoc(),
|
||||
(nsIDOMHTMLCanvasElement*) HTMLCanvasElement(),
|
||||
NS_LITERAL_STRING("webglcontextlost"),
|
||||
PR_TRUE,
|
||||
PR_TRUE,
|
||||
&defaultAction);
|
||||
|
||||
// If the script didn't handle the event, we don't allow restores.
|
||||
if (defaultAction)
|
||||
mAllowRestore = false;
|
||||
|
||||
// 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.
|
||||
SetupRobustnessTimer();
|
||||
} else {
|
||||
mContextStatus = ContextLost;
|
||||
}
|
||||
} else if (mContextStatus == ContextLostAwaitingRestore) {
|
||||
// Try to restore the context. If it fails, try again later.
|
||||
if (NS_FAILED(SetDimensions(mWidth, mHeight))) {
|
||||
SetupRobustnessTimer();
|
||||
return NS_OK;
|
||||
}
|
||||
mContextStatus = ContextStable;
|
||||
nsContentUtils::DispatchTrustedEvent(HTMLCanvasElement()->OwnerDoc(),
|
||||
(nsIDOMHTMLCanvasElement*) HTMLCanvasElement(),
|
||||
NS_LITERAL_STRING("webglcontextrestored"),
|
||||
PR_TRUE,
|
||||
PR_TRUE);
|
||||
// Set all flags back to the state they were in before the context was
|
||||
// lost.
|
||||
mContextLostErrorSet = false;
|
||||
mContextLostDueToTest = false;
|
||||
mAllowRestore = true;
|
||||
}
|
||||
|
||||
MaybeRestoreContext();
|
||||
return NS_OK;
|
||||
}
|
||||
@ -1108,18 +1169,25 @@ WebGLContext::Notify(nsITimer* timer)
|
||||
void
|
||||
WebGLContext::MaybeRestoreContext()
|
||||
{
|
||||
if (mContextLost || mAllowRestore)
|
||||
// Don't try to handle it if we already know it's busted.
|
||||
if (mContextStatus != ContextStable || gl == nsnull)
|
||||
return;
|
||||
|
||||
bool isEGL = gl->GetContextType() == GLContext::ContextTypeEGL,
|
||||
isANGLE = gl->IsANGLE();
|
||||
|
||||
// If was lost due to a forced context loss, don't try to handle it.
|
||||
// Also, we also don't try to handle if if we don't have robustness.
|
||||
// Note that the code in this function is used only for situations where
|
||||
// we have an actual context loss, and not a simulated one.
|
||||
if (mContextLostDueToTest ||
|
||||
(!mHasRobustness && !isEGL))
|
||||
return;
|
||||
|
||||
GLContext::ContextResetARB resetStatus = GLContext::CONTEXT_NO_ERROR;
|
||||
if (mHasRobustness) {
|
||||
gl->MakeCurrent();
|
||||
resetStatus = (GLContext::ContextResetARB) gl->fGetGraphicsResetStatus();
|
||||
// This call is safe as it does not actually interact with GL, so the
|
||||
// context does not have to be current.
|
||||
} 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,
|
||||
@ -1143,10 +1211,11 @@ WebGLContext::MaybeRestoreContext()
|
||||
// run it again some time later.
|
||||
if (mDrawSinceRobustnessTimerSet)
|
||||
SetupRobustnessTimer();
|
||||
return;
|
||||
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");
|
||||
return;
|
||||
mAllowRestore = false;
|
||||
break;
|
||||
case GLContext::CONTEXT_INNOCENT_CONTEXT_RESET_ARB:
|
||||
break;
|
||||
case GLContext::CONTEXT_UNKNOWN_CONTEXT_RESET_ARB:
|
||||
@ -1156,45 +1225,25 @@ WebGLContext::MaybeRestoreContext()
|
||||
// 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.
|
||||
return;
|
||||
mAllowRestore = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
ForceRestoreContext();
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::ForceLoseContext()
|
||||
{
|
||||
TerminateRobustnessTimer();
|
||||
|
||||
mWebGLError = LOCAL_GL_CONTEXT_LOST;
|
||||
|
||||
bool defaultAction;
|
||||
mContextLost = true;
|
||||
mContextStatus = ContextLostAwaitingEvent;
|
||||
// Queue up a task to restore the event.
|
||||
SetupRobustnessTimer();
|
||||
DestroyResourcesAndContext();
|
||||
nsContentUtils::DispatchTrustedEvent(HTMLCanvasElement()->OwnerDoc(),
|
||||
(nsIDOMHTMLCanvasElement*) HTMLCanvasElement(),
|
||||
NS_LITERAL_STRING("webglcontextlost"),
|
||||
PR_TRUE,
|
||||
PR_TRUE,
|
||||
&defaultAction);
|
||||
if (defaultAction)
|
||||
mAllowRestore = false;
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::ForceRestoreContext()
|
||||
{
|
||||
mContextLost = false;
|
||||
mAllowRestore = false;
|
||||
SetDimensions(mHeight, mWidth);
|
||||
nsContentUtils::DispatchTrustedEvent(HTMLCanvasElement()->OwnerDoc(),
|
||||
(nsIDOMHTMLCanvasElement*) HTMLCanvasElement(),
|
||||
NS_LITERAL_STRING("webglcontextrestored"),
|
||||
PR_TRUE,
|
||||
PR_TRUE);
|
||||
mContextStatus = ContextLostAwaitingRestore;
|
||||
}
|
||||
|
||||
//
|
||||
@ -1471,8 +1520,8 @@ WebGLContext::GetSupportedExtensions(nsIVariant **retval)
|
||||
extList.InsertElementAt(extList.Length(), "OES_texture_float");
|
||||
if (IsExtensionSupported(WebGL_OES_standard_derivatives))
|
||||
extList.InsertElementAt(extList.Length(), "OES_standard_derivatives");
|
||||
if (IsExtensionSupported(WebGL_WEBGL_EXT_lose_context))
|
||||
extList.InsertElementAt(extList.Length(), "WEBGL_EXT_lose_context");
|
||||
if (IsExtensionSupported(WebGL_MOZ_WEBGL_lose_context))
|
||||
extList.InsertElementAt(extList.Length(), "MOZ_WEBGL_lose_context");
|
||||
|
||||
nsresult rv;
|
||||
if (extList.Length() > 0) {
|
||||
@ -1491,7 +1540,13 @@ WebGLContext::GetSupportedExtensions(nsIVariant **retval)
|
||||
NS_IMETHODIMP
|
||||
WebGLContext::IsContextLost(WebGLboolean *retval)
|
||||
{
|
||||
*retval = mContextLost;
|
||||
*retval = mContextStatus != ContextStable;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Internalized version of IsContextLost.
|
||||
bool
|
||||
WebGLContext::IsContextStable()
|
||||
{
|
||||
return mContextStatus == ContextStable;
|
||||
}
|
||||
|
@ -575,10 +575,17 @@ public:
|
||||
return mMinCapability;
|
||||
}
|
||||
|
||||
// See the comment over WebGLContext::Notify() for more information on this.
|
||||
bool ShouldEnableRobustnessTimer() {
|
||||
return mHasRobustness ||
|
||||
IsExtensionEnabled(WebGL_MOZ_WEBGL_lose_context) ||
|
||||
(gl != nsnull && gl->GetContextType() == gl::GLContext::ContextTypeEGL);
|
||||
}
|
||||
|
||||
// Sets up the GL_ARB_robustness timer if it isn't already, so that if the
|
||||
// driver gets restarted, the context may get reset with it.
|
||||
void SetupRobustnessTimer() {
|
||||
if (mContextLost || (!mHasRobustness && gl->GetContextType() != gl::GLContext::ContextTypeEGL))
|
||||
if (!ShouldEnableRobustnessTimer())
|
||||
return;
|
||||
|
||||
// If the timer was already running, don't restart it here. Instead,
|
||||
@ -668,11 +675,30 @@ protected:
|
||||
PRInt32 mGLMaxFragmentUniformVectors;
|
||||
PRInt32 mGLMaxVertexUniformVectors;
|
||||
|
||||
// Represents current status, or state, of the context. That is, is it lost
|
||||
// or stable and what part of the context lost process are we currently at.
|
||||
// This is used to support the WebGL spec's asyncronous nature in handling
|
||||
// context loss.
|
||||
enum ContextStatus {
|
||||
// The context is stable; there either are none or we don't know of any.
|
||||
ContextStable,
|
||||
// The context has been lost, but we have not yet sent an event to the
|
||||
// script informing it of this.
|
||||
ContextLostAwaitingEvent,
|
||||
// The context has been lost, and we have sent the script an event
|
||||
// informing it of this.
|
||||
ContextLost,
|
||||
// The context is lost, an event has been sent to the script, and the
|
||||
// script correctly handled the event. We are waiting for the context to
|
||||
// be restored.
|
||||
ContextLostAwaitingRestore
|
||||
};
|
||||
|
||||
// extensions
|
||||
enum WebGLExtensionID {
|
||||
WebGL_OES_texture_float,
|
||||
WebGL_OES_standard_derivatives,
|
||||
WebGL_WEBGL_EXT_lose_context,
|
||||
WebGL_MOZ_WEBGL_lose_context,
|
||||
WebGLExtensionID_Max
|
||||
};
|
||||
nsCOMPtr<WebGLExtension> mEnabledExtensions[WebGLExtensionID_Max];
|
||||
@ -805,6 +831,7 @@ protected:
|
||||
const GLvoid *data);
|
||||
|
||||
void MaybeRestoreContext();
|
||||
bool IsContextStable();
|
||||
void ForceLoseContext();
|
||||
void ForceRestoreContext();
|
||||
|
||||
@ -861,10 +888,12 @@ protected:
|
||||
int mBackbufferClearingStatus;
|
||||
|
||||
nsCOMPtr<nsITimer> mContextRestorer;
|
||||
bool mContextLost;
|
||||
bool mAllowRestore;
|
||||
bool mRobustnessTimerRunning;
|
||||
bool mDrawSinceRobustnessTimerSet;
|
||||
ContextStatus mContextStatus;
|
||||
bool mContextLostErrorSet;
|
||||
bool mContextLostDueToTest;
|
||||
|
||||
public:
|
||||
// console logging helpers
|
||||
|
@ -2533,9 +2533,12 @@ WebGLContext::CreateTexture(nsIWebGLTexture **retval)
|
||||
NS_IMETHODIMP
|
||||
WebGLContext::GetError(WebGLenum *_retval)
|
||||
{
|
||||
if (!mContextLost) {
|
||||
if (mContextStatus == ContextStable) {
|
||||
MakeContextCurrent();
|
||||
UpdateWebGLErrorAndClearGLError();
|
||||
} else if (!mContextLostErrorSet) {
|
||||
mWebGLError = LOCAL_GL_CONTEXT_LOST;
|
||||
mContextLostErrorSet = true;
|
||||
}
|
||||
|
||||
*_retval = mWebGLError;
|
||||
@ -5145,11 +5148,10 @@ WebGLContext::TexSubImage2D_dom(WebGLenum target, WebGLint level,
|
||||
bool
|
||||
WebGLContext::LoseContext()
|
||||
{
|
||||
if (mContextLost) {
|
||||
if (mContextLost)
|
||||
return false;
|
||||
}
|
||||
|
||||
mAllowRestore = true;
|
||||
mContextLostDueToTest = true;
|
||||
ForceLoseContext();
|
||||
|
||||
return true;
|
||||
@ -5158,7 +5160,7 @@ WebGLContext::LoseContext()
|
||||
bool
|
||||
WebGLContext::RestoreContext()
|
||||
{
|
||||
if (!mContextLost || !mAllowRestore) {
|
||||
if (IsContextStable() || !mAllowRestore) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user