From 942467690c712db3bc35860508c53dfdb3f36c12 Mon Sep 17 00:00:00 2001 From: Doug Sherk Date: Wed, 26 Oct 2011 16:00:44 -0400 Subject: [PATCH] Bug 656824: Implemented ARB_robustness to detect driver resets in WebGL, only on GLX for now - r=bjacob This patch implements ARB_robustness on GLX and allows scripts to handle driver resets through events. The changes in this patch are very sweeping; they hit almost every NS_IMETHODIMP function within WebGLContextGL.cpp and WebGLContext.cpp. More work must be done on this to support EGL_CONTEXT_LOST. --- content/canvas/src/Makefile.in | 1 + content/canvas/src/WebGLContext.cpp | 136 +++++- content/canvas/src/WebGLContext.h | 34 +- content/canvas/src/WebGLContextGL.cpp | 426 +++++++++++++++++- .../canvas/src/WebGLContextNotSupported.cpp | 1 + .../canvas/src/WebGLExtensionLoseContext.cpp | 76 ++++ content/canvas/src/WebGLExtensions.h | 19 + dom/base/nsDOMClassInfo.cpp | 6 + dom/base/nsDOMClassInfoClasses.h | 1 + .../canvas/nsIDOMWebGLRenderingContext.idl | 6 + gfx/thebes/GLContext.cpp | 6 + gfx/thebes/GLContext.h | 22 + gfx/thebes/GLContextProviderGLX.cpp | 57 ++- gfx/thebes/GLContextSymbols.h | 2 + gfx/thebes/GLDefs.h | 44 ++ gfx/thebes/GLXLibrary.h | 17 +- js/xpconnect/src/dom_quickstubs.qsconf | 1 + 17 files changed, 844 insertions(+), 11 deletions(-) create mode 100644 content/canvas/src/WebGLExtensionLoseContext.cpp diff --git a/content/canvas/src/Makefile.in b/content/canvas/src/Makefile.in index c5dddf199301..620f3952ecbf 100644 --- a/content/canvas/src/Makefile.in +++ b/content/canvas/src/Makefile.in @@ -70,6 +70,7 @@ CPPSRCS += \ WebGLContextUtils.cpp \ WebGLContextValidate.cpp \ WebGLExtensionStandardDerivatives.cpp \ + WebGLExtensionLoseContext.cpp \ $(NULL) DEFINES += -DUSE_ANGLE diff --git a/content/canvas/src/WebGLContext.cpp b/content/canvas/src/WebGLContext.cpp index 650deacecf42..e0f33b445165 100644 --- a/content/canvas/src/WebGLContext.cpp +++ b/content/canvas/src/WebGLContext.cpp @@ -296,14 +296,21 @@ WebGLContext::WebGLContext() // See OpenGL ES 2.0.25 spec, 6.2 State Tables, table 6.13 mPixelStorePackAlignment = 4; mPixelStoreUnpackAlignment = 4; - + WebGLMemoryReporter::AddWebGLContext(this); + + mContextLost = false; + mAllowRestore = false; } WebGLContext::~WebGLContext() { DestroyResourcesAndContext(); WebGLMemoryReporter::RemoveWebGLContext(this); + if (mContextRestorer) { + mContextRestorer->Cancel(); + mContextRestorer = NULL; + } } static PLDHashOperator @@ -822,6 +829,9 @@ WebGLContext::GetCanvasLayer(nsDisplayListBuilder* aBuilder, CanvasLayer *aOldLayer, LayerManager *aManager) { + if (mContextLost) + return nsnull; + if (!mResetLayer && aOldLayer && aOldLayer->HasUserData(&gWebGLLayerUserData)) { NS_ADDREF(aOldLayer); @@ -885,6 +895,12 @@ WebGLContext::GetCanvasLayer(nsDisplayListBuilder* aBuilder, NS_IMETHODIMP WebGLContext::GetContextAttributes(jsval *aResult) { + if (mContextLost) + { + *aResult = OBJECT_TO_JSVAL(NULL); + return NS_OK; + } + JSContext *cx = nsContentUtils::GetCurrentJSContext(); if (!cx) return NS_ERROR_FAILURE; @@ -923,6 +939,9 @@ WebGLContext::GetContextAttributes(jsval *aResult) NS_IMETHODIMP WebGLContext::MozGetUnderlyingParamString(PRUint32 pname, nsAString& retval) { + if (mContextLost) + return NS_OK; + retval.SetIsVoid(true); MakeContextCurrent(); @@ -959,6 +978,10 @@ bool WebGLContext::IsExtensionSupported(WebGLExtensionID ei) // We always support this extension. isSupported = true; break; + case WebGL_WEBKIT_lose_context: + // We always support this extension. + isSupported = true; + break; default: isSupported = false; } @@ -970,6 +993,8 @@ NS_IMETHODIMP WebGLContext::GetExtension(const nsAString& aName, nsIWebGLExtension **retval) { *retval = nsnull; + if (mContextLost) + return NS_OK; if (mDisableExtensions) { return NS_OK; @@ -985,6 +1010,10 @@ WebGLContext::GetExtension(const nsAString& aName, nsIWebGLExtension **retval) if (IsExtensionSupported(WebGL_OES_standard_derivatives)) ei = WebGL_OES_standard_derivatives; } + else if (aName.EqualsLiteral("WEBKIT_lose_context")) { + if (IsExtensionSupported(WebGL_WEBKIT_lose_context)) + ei = WebGL_WEBKIT_lose_context; + } if (ei != WebGLExtensionID_Max) { if (!IsExtensionEnabled(ei)) { @@ -992,6 +1021,9 @@ WebGLContext::GetExtension(const nsAString& aName, nsIWebGLExtension **retval) case WebGL_OES_standard_derivatives: mEnabledExtensions[ei] = new WebGLExtensionStandardDerivatives(this); break; + case WebGL_WEBKIT_lose_context: + mEnabledExtensions[ei] = new WebGLExtensionLoseContext(this); + break; // create an extension for any types that don't // have any additional tokens or methods default: @@ -1095,6 +1127,86 @@ WebGLContext::EnsureBackbufferClearedAsNeeded() Invalidate(); } +NS_IMETHODIMP +WebGLContext::Notify(nsITimer* timer) +{ + MaybeRestoreContext(); + + if (mContextRestorer) { + mContextRestorer->Cancel(); + mContextRestorer = NULL; + } + + return NS_OK; +} + +void +WebGLContext::MaybeRestoreContext() +{ + if (mContextLost || mAllowRestore) + return; + + GLContext::ContextResetARB resetStatus = + (GLContext::ContextResetARB) gl->fGetGraphicsResetStatus(); + + 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: + return; + 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; + 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"); + break; + } + + ForceRestoreContext(); +} + +void +WebGLContext::ForceLoseContext() +{ + if (mContextRestorer) { + mContextRestorer->Cancel(); + mContextRestorer = NULL; + } + + mWebGLError = LOCAL_GL_CONTEXT_LOST; + + bool defaultAction; + mContextLost = true; + 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); +} + // // XPCOM goop // @@ -1116,6 +1228,7 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WebGLContext) NS_INTERFACE_MAP_ENTRY(nsIDOMWebGLRenderingContext) NS_INTERFACE_MAP_ENTRY(nsICanvasRenderingContextInternal) NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) + NS_INTERFACE_MAP_ENTRY(nsITimerCallback) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMWebGLRenderingContext) NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(WebGLRenderingContext) NS_INTERFACE_MAP_END @@ -1254,10 +1367,24 @@ NS_INTERFACE_MAP_BEGIN(WebGLExtensionStandardDerivatives) NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(WebGLExtensionStandardDerivatives) NS_INTERFACE_MAP_END_INHERITING(WebGLExtension) +NS_IMPL_ADDREF(WebGLExtensionLoseContext) +NS_IMPL_RELEASE(WebGLExtensionLoseContext) + +DOMCI_DATA(WebGLExtensionLoseContext, WebGLExtensionLoseContext) + +NS_INTERFACE_MAP_BEGIN(WebGLExtensionLoseContext) + NS_INTERFACE_MAP_ENTRY(nsIWebGLExtensionLoseContext) + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, WebGLExtension) + NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(WebGLExtensionLoseContext) +NS_INTERFACE_MAP_END_INHERITING(WebGLExtension) + /* readonly attribute WebGLsizei drawingBufferWidth; */ NS_IMETHODIMP WebGLContext::GetDrawingBufferWidth(WebGLsizei *aWidth) { + if (mContextLost) + return NS_OK; + *aWidth = mWidth; return NS_OK; } @@ -1266,6 +1393,9 @@ WebGLContext::GetDrawingBufferWidth(WebGLsizei *aWidth) NS_IMETHODIMP WebGLContext::GetDrawingBufferHeight(WebGLsizei *aHeight) { + if (mContextLost) + return NS_OK; + *aHeight = mHeight; return NS_OK; } @@ -1311,6 +1441,8 @@ NS_IMETHODIMP WebGLContext::GetSupportedExtensions(nsIVariant **retval) { *retval = nsnull; + if (mContextLost) + return NS_OK; if (mDisableExtensions) { return NS_OK; @@ -1343,7 +1475,7 @@ WebGLContext::GetSupportedExtensions(nsIVariant **retval) NS_IMETHODIMP WebGLContext::IsContextLost(WebGLboolean *retval) { - *retval = false; + *retval = mContextLost; return NS_OK; } diff --git a/content/canvas/src/WebGLContext.h b/content/canvas/src/WebGLContext.h index 1e4572a0b724..efb1568c913c 100644 --- a/content/canvas/src/WebGLContext.h +++ b/content/canvas/src/WebGLContext.h @@ -339,9 +339,11 @@ struct WebGLContextOptions { class WebGLContext : public nsIDOMWebGLRenderingContext, public nsICanvasRenderingContextInternal, - public nsSupportsWeakReference + public nsSupportsWeakReference, + public nsITimerCallback { friend class WebGLMemoryReporter; + friend class WebGLExtensionLoseContext; public: WebGLContext(); @@ -353,6 +355,8 @@ public: NS_DECL_NSIDOMWEBGLRENDERINGCONTEXT + NS_DECL_NSITIMERCALLBACK + // nsICanvasRenderingContextInternal NS_IMETHOD SetCanvasElement(nsHTMLCanvasElement* aParentCanvas); NS_IMETHOD SetDimensions(PRInt32 width, PRInt32 height); @@ -380,6 +384,9 @@ public: PRInt32 x, PRInt32 y, PRInt32 w, PRInt32 h) { return NS_ERROR_NOT_IMPLEMENTED; } + bool LoseContext(); + bool RestoreContext(); + nsresult SynthesizeGLError(WebGLenum err); nsresult SynthesizeGLError(WebGLenum err, const char *fmt, ...); @@ -438,6 +445,22 @@ public: return mMinCapability; } + // 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) + return; + + if (!mContextRestorer) + mContextRestorer = do_CreateInstance("@mozilla.org/timer;1"); + + // As long as there's still activity, we reset the timer each time that + // this function gets called. + mContextRestorer->InitWithCallback(static_cast(this), + PR_MillisecondsToInterval(1000), + nsITimer::TYPE_ONE_SHOT); + } + protected: void SetDontKnowIfNeedFakeBlack() { mFakeBlackStatus = DontKnowIfNeedFakeBlack; @@ -502,6 +525,7 @@ protected: enum WebGLExtensionID { WebGL_OES_texture_float, WebGL_OES_standard_derivatives, + WebGL_WEBKIT_lose_context, WebGLExtensionID_Max }; nsCOMPtr mEnabledExtensions[WebGLExtensionID_Max]; @@ -633,6 +657,10 @@ protected: GLenum type, const GLvoid *data); + void MaybeRestoreContext(); + void ForceLoseContext(); + void ForceRestoreContext(); + // the buffers bound to the current program's attribs nsTArray mAttribBuffers; @@ -691,6 +719,10 @@ protected: int mBackbufferClearingStatus; + nsCOMPtr mContextRestorer; + bool mContextLost; + bool mAllowRestore; + public: // console logging helpers static void LogMessage(const char *fmt, ...); diff --git a/content/canvas/src/WebGLContextGL.cpp b/content/canvas/src/WebGLContextGL.cpp index 177a70c7ea2f..c589f50a289e 100644 --- a/content/canvas/src/WebGLContextGL.cpp +++ b/content/canvas/src/WebGLContextGL.cpp @@ -76,36 +76,43 @@ static WebGLenum InternalFormatForFormatAndType(WebGLenum format, WebGLenum type #define GL_SAME_METHOD_0(glname, name) \ NS_IMETHODIMP WebGLContext::name() { \ + if (mContextLost) { return NS_OK; } \ MakeContextCurrent(); gl->f##glname(); return NS_OK; \ } #define GL_SAME_METHOD_1(glname, name, t1) \ NS_IMETHODIMP WebGLContext::name(t1 a1) { \ + if (mContextLost) { return NS_OK; } \ MakeContextCurrent(); gl->f##glname(a1); return NS_OK; \ } #define GL_SAME_METHOD_2(glname, name, t1, t2) \ NS_IMETHODIMP WebGLContext::name(t1 a1, t2 a2) { \ + if (mContextLost) { return NS_OK; } \ MakeContextCurrent(); gl->f##glname(a1,a2); return NS_OK; \ } #define GL_SAME_METHOD_3(glname, name, t1, t2, t3) \ NS_IMETHODIMP WebGLContext::name(t1 a1, t2 a2, t3 a3) { \ + if (mContextLost) { return NS_OK; } \ MakeContextCurrent(); gl->f##glname(a1,a2,a3); return NS_OK; \ } #define GL_SAME_METHOD_4(glname, name, t1, t2, t3, t4) \ NS_IMETHODIMP WebGLContext::name(t1 a1, t2 a2, t3 a3, t4 a4) { \ + if (mContextLost) { return NS_OK; } \ MakeContextCurrent(); gl->f##glname(a1,a2,a3,a4); return NS_OK; \ } #define GL_SAME_METHOD_5(glname, name, t1, t2, t3, t4, t5) \ NS_IMETHODIMP WebGLContext::name(t1 a1, t2 a2, t3 a3, t4 a4, t5 a5) { \ + if (mContextLost) { return NS_OK; } \ MakeContextCurrent(); gl->f##glname(a1,a2,a3,a4,a5); return NS_OK; \ } #define GL_SAME_METHOD_6(glname, name, t1, t2, t3, t4, t5, t6) \ NS_IMETHODIMP WebGLContext::name(t1 a1, t2 a2, t3 a3, t4 a4, t5 a5, t6 a6) { \ + if (mContextLost) { return NS_OK; } \ MakeContextCurrent(); gl->f##glname(a1,a2,a3,a4,a5,a6); return NS_OK; \ } @@ -135,6 +142,9 @@ WebGLProgram::GetUniformLocationObject(GLint glLocation) NS_IMETHODIMP WebGLContext::ActiveTexture(WebGLenum texture) { + if (mContextLost) + return NS_OK; + if (texture < LOCAL_GL_TEXTURE0 || texture >= LOCAL_GL_TEXTURE0+mBound2DTextures.Length()) return ErrorInvalidEnum("ActiveTexture: texture unit %d out of range (0..%d)", texture, mBound2DTextures.Length()-1); @@ -148,6 +158,9 @@ WebGLContext::ActiveTexture(WebGLenum texture) NS_IMETHODIMP WebGLContext::AttachShader(nsIWebGLProgram *pobj, nsIWebGLShader *shobj) { + if (mContextLost) + return NS_OK; + // if pobj or shobj are null/not specified, it's an error if (pobj == nsnull || shobj == nsnull) return ErrorInvalidValue("attachShader"); @@ -179,6 +192,9 @@ WebGLContext::AttachShader(nsIWebGLProgram *pobj, nsIWebGLShader *shobj) NS_IMETHODIMP WebGLContext::BindAttribLocation(nsIWebGLProgram *pobj, WebGLuint location, const nsAString& name) { + if (mContextLost) + return NS_OK; + WebGLuint progname; if (!GetGLName("bindAttribLocation: program", pobj, &progname)) return NS_OK; @@ -336,6 +352,9 @@ GL_SAME_METHOD_4(BlendColor, BlendColor, WebGLfloat, WebGLfloat, WebGLfloat, Web NS_IMETHODIMP WebGLContext::BlendEquation(WebGLenum mode) { + if (mContextLost) + return NS_OK; + if (!ValidateBlendEquationEnum(mode, "blendEquation: mode")) return NS_OK; @@ -346,6 +365,9 @@ NS_IMETHODIMP WebGLContext::BlendEquation(WebGLenum mode) NS_IMETHODIMP WebGLContext::BlendEquationSeparate(WebGLenum modeRGB, WebGLenum modeAlpha) { + if (mContextLost) + return NS_OK; + if (!ValidateBlendEquationEnum(modeRGB, "blendEquationSeparate: modeRGB") || !ValidateBlendEquationEnum(modeAlpha, "blendEquationSeparate: modeAlpha")) return NS_OK; @@ -357,6 +379,9 @@ NS_IMETHODIMP WebGLContext::BlendEquationSeparate(WebGLenum modeRGB, WebGLenum m NS_IMETHODIMP WebGLContext::BlendFunc(WebGLenum sfactor, WebGLenum dfactor) { + if (mContextLost) + return NS_OK; + if (!ValidateBlendFuncSrcEnum(sfactor, "blendFunc: sfactor") || !ValidateBlendFuncDstEnum(dfactor, "blendFunc: dfactor")) return NS_OK; @@ -373,6 +398,9 @@ NS_IMETHODIMP WebGLContext::BlendFuncSeparate(WebGLenum srcRGB, WebGLenum dstRGB, WebGLenum srcAlpha, WebGLenum dstAlpha) { + if (mContextLost) + return NS_OK; + if (!ValidateBlendFuncSrcEnum(srcRGB, "blendFuncSeparate: srcRGB") || !ValidateBlendFuncSrcEnum(srcAlpha, "blendFuncSeparate: srcAlpha") || !ValidateBlendFuncDstEnum(dstRGB, "blendFuncSeparate: dstRGB") || @@ -418,6 +446,9 @@ GLenum WebGLContext::CheckedBufferData(GLenum target, NS_IMETHODIMP WebGLContext::BufferData(PRInt32 dummy) { + if (mContextLost) + return NS_OK; + // this should never be called LogMessageIfVerbose("BufferData"); return NS_ERROR_FAILURE; @@ -426,6 +457,9 @@ WebGLContext::BufferData(PRInt32 dummy) NS_IMETHODIMP WebGLContext::BufferData_null() { + if (mContextLost) + return NS_OK; + // see http://www.khronos.org/bugzilla/show_bug.cgi?id=386 return ErrorInvalidValue("bufferData: null object passed"); } @@ -434,6 +468,9 @@ WebGLContext::BufferData_null() NS_IMETHODIMP WebGLContext::BufferData_size(WebGLenum target, WebGLsizei size, WebGLenum usage) { + if (mContextLost) + return NS_OK; + WebGLBuffer *boundBuffer = NULL; if (target == LOCAL_GL_ARRAY_BUFFER) { @@ -472,6 +509,9 @@ WebGLContext::BufferData_size(WebGLenum target, WebGLsizei size, WebGLenum usage NS_IMETHODIMP WebGLContext::BufferData_buf(WebGLenum target, JSObject *wb, WebGLenum usage) { + if (mContextLost) + return NS_OK; + WebGLBuffer *boundBuffer = NULL; if (target == LOCAL_GL_ARRAY_BUFFER) { @@ -510,6 +550,9 @@ WebGLContext::BufferData_buf(WebGLenum target, JSObject *wb, WebGLenum usage) NS_IMETHODIMP WebGLContext::BufferData_array(WebGLenum target, JSObject *wa, WebGLenum usage) { + if (mContextLost) + return NS_OK; + WebGLBuffer *boundBuffer = NULL; if (target == LOCAL_GL_ARRAY_BUFFER) { @@ -548,18 +591,27 @@ WebGLContext::BufferData_array(WebGLenum target, JSObject *wa, WebGLenum usage) NS_IMETHODIMP WebGLContext::BufferSubData(PRInt32) { + if (mContextLost) + return NS_OK; + return NS_ERROR_FAILURE; } NS_IMETHODIMP WebGLContext::BufferSubData_null() { + if (mContextLost) + return NS_OK; + return NS_OK; // see http://www.khronos.org/bugzilla/show_bug.cgi?id=386 } NS_IMETHODIMP WebGLContext::BufferSubData_buf(GLenum target, WebGLsizei byteOffset, JSObject *wb) { + if (mContextLost) + return NS_OK; + WebGLBuffer *boundBuffer = NULL; if (target == LOCAL_GL_ARRAY_BUFFER) { @@ -597,6 +649,9 @@ WebGLContext::BufferSubData_buf(GLenum target, WebGLsizei byteOffset, JSObject * NS_IMETHODIMP WebGLContext::BufferSubData_array(WebGLenum target, WebGLsizei byteOffset, JSObject *wa) { + if (mContextLost) + return NS_OK; + WebGLBuffer *boundBuffer = NULL; if (target == LOCAL_GL_ARRAY_BUFFER) { @@ -634,6 +689,12 @@ WebGLContext::BufferSubData_array(WebGLenum target, WebGLsizei byteOffset, JSObj NS_IMETHODIMP WebGLContext::CheckFramebufferStatus(WebGLenum target, WebGLenum *retval) { + if (mContextLost) + { + *retval = LOCAL_GL_FRAMEBUFFER_UNSUPPORTED; + return NS_OK; + } + *retval = 0; MakeContextCurrent(); @@ -651,6 +712,9 @@ WebGLContext::CheckFramebufferStatus(WebGLenum target, WebGLenum *retval) NS_IMETHODIMP WebGLContext::Clear(PRUint32 mask) { + if (mContextLost) + return NS_OK; + MakeContextCurrent(); PRUint32 m = mask & (LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT | LOCAL_GL_STENCIL_BUFFER_BIT); @@ -690,6 +754,9 @@ WebGLContext::Clear(PRUint32 mask) NS_IMETHODIMP WebGLContext::ClearColor(WebGLfloat r, WebGLfloat g, WebGLfloat b, WebGLfloat a) { + if (mContextLost) + return NS_OK; + MakeContextCurrent(); mColorClearValue[0] = r; mColorClearValue[1] = g; @@ -702,6 +769,9 @@ WebGLContext::ClearColor(WebGLfloat r, WebGLfloat g, WebGLfloat b, WebGLfloat a) NS_IMETHODIMP WebGLContext::ClearDepth(WebGLfloat v) { + if (mContextLost) + return NS_OK; + MakeContextCurrent(); mDepthClearValue = v; gl->fClearDepth(v); @@ -711,6 +781,9 @@ WebGLContext::ClearDepth(WebGLfloat v) NS_IMETHODIMP WebGLContext::ClearStencil(WebGLint v) { + if (mContextLost) + return NS_OK; + MakeContextCurrent(); mStencilClearValue = v; gl->fClearStencil(v); @@ -720,6 +793,9 @@ WebGLContext::ClearStencil(WebGLint v) NS_IMETHODIMP WebGLContext::ColorMask(WebGLboolean r, WebGLboolean g, WebGLboolean b, WebGLboolean a) { + if (mContextLost) + return NS_OK; + MakeContextCurrent(); mColorWriteMask[0] = r; mColorWriteMask[1] = g; @@ -829,6 +905,9 @@ WebGLContext::CopyTexImage2D(WebGLenum target, WebGLsizei height, WebGLint border) { + if (mContextLost) + return NS_OK; + switch (target) { case LOCAL_GL_TEXTURE_2D: case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X: @@ -931,6 +1010,9 @@ WebGLContext::CopyTexSubImage2D(WebGLenum target, WebGLsizei width, WebGLsizei height) { + if (mContextLost) + return NS_OK; + switch (target) { case LOCAL_GL_TEXTURE_2D: case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X: @@ -995,6 +1077,9 @@ WebGLContext::CopyTexSubImage2D(WebGLenum target, NS_IMETHODIMP WebGLContext::CreateProgram(nsIWebGLProgram **retval) { + if (mContextLost) + return NS_OK; + *retval = nsnull; MakeContextCurrent(); @@ -1011,6 +1096,9 @@ WebGLContext::CreateProgram(nsIWebGLProgram **retval) NS_IMETHODIMP WebGLContext::CreateShader(WebGLenum type, nsIWebGLShader **retval) { + if (mContextLost) + return NS_OK; + *retval = nsnull; if (type != LOCAL_GL_VERTEX_SHADER && @@ -1033,6 +1121,9 @@ WebGLContext::CreateShader(WebGLenum type, nsIWebGLShader **retval) NS_IMETHODIMP WebGLContext::CullFace(WebGLenum face) { + if (mContextLost) + return NS_OK; + if (!ValidateFaceEnum(face, "cullFace")) return NS_OK; @@ -1044,6 +1135,9 @@ WebGLContext::CullFace(WebGLenum face) NS_IMETHODIMP WebGLContext::DeleteBuffer(nsIWebGLBuffer *bobj) { + if (mContextLost) + return NS_OK; + WebGLuint bufname; WebGLBuffer *buf; bool isNull, isDeleted; @@ -1065,6 +1159,9 @@ WebGLContext::DeleteBuffer(nsIWebGLBuffer *bobj) NS_IMETHODIMP WebGLContext::DeleteFramebuffer(nsIWebGLFramebuffer *fbobj) { + if (mContextLost) + return NS_OK; + WebGLuint fbufname; WebGLFramebuffer *fbuf; bool isNull, isDeleted; @@ -1089,6 +1186,9 @@ WebGLContext::DeleteFramebuffer(nsIWebGLFramebuffer *fbobj) NS_IMETHODIMP WebGLContext::DeleteRenderbuffer(nsIWebGLRenderbuffer *rbobj) { + if (mContextLost) + return NS_OK; + WebGLuint rbufname; WebGLRenderbuffer *rbuf; bool isNull, isDeleted; @@ -1125,6 +1225,9 @@ WebGLContext::DeleteRenderbuffer(nsIWebGLRenderbuffer *rbobj) NS_IMETHODIMP WebGLContext::DeleteTexture(nsIWebGLTexture *tobj) { + if (mContextLost) + return NS_OK; + WebGLuint texname; WebGLTexture *tex; bool isNull, isDeleted; @@ -1146,6 +1249,9 @@ WebGLContext::DeleteTexture(nsIWebGLTexture *tobj) NS_IMETHODIMP WebGLContext::DeleteProgram(nsIWebGLProgram *pobj) { + if (mContextLost) + return NS_OK; + WebGLuint progname; WebGLProgram *prog; bool isNull, isDeleted; @@ -1168,6 +1274,9 @@ WebGLContext::DeleteProgram(nsIWebGLProgram *pobj) NS_IMETHODIMP WebGLContext::DeleteShader(nsIWebGLShader *sobj) { + if (mContextLost) + return NS_OK; + WebGLuint shadername; WebGLShader *shader; bool isNull, isDeleted; @@ -1189,6 +1298,9 @@ WebGLContext::DeleteShader(nsIWebGLShader *sobj) NS_IMETHODIMP WebGLContext::DetachShader(nsIWebGLProgram *pobj, nsIWebGLShader *shobj) { + if (mContextLost) + return NS_OK; + WebGLuint progname, shadername; WebGLProgram *program; WebGLShader *shader; @@ -1214,6 +1326,9 @@ WebGLContext::DetachShader(nsIWebGLProgram *pobj, nsIWebGLShader *shobj) NS_IMETHODIMP WebGLContext::DepthFunc(WebGLenum func) { + if (mContextLost) + return NS_OK; + if (!ValidateComparisonEnum(func, "depthFunc")) return NS_OK; @@ -1225,6 +1340,9 @@ WebGLContext::DepthFunc(WebGLenum func) NS_IMETHODIMP WebGLContext::DepthMask(WebGLboolean b) { + if (mContextLost) + return NS_OK; + MakeContextCurrent(); mDepthWriteMask = b; gl->fDepthMask(b); @@ -1234,6 +1352,9 @@ WebGLContext::DepthMask(WebGLboolean b) NS_IMETHODIMP WebGLContext::DepthRange(WebGLfloat zNear, WebGLfloat zFar) { + if (mContextLost) + return NS_OK; + if (zNear > zFar) return ErrorInvalidOperation("depthRange: the near value is greater than the far value!"); @@ -1245,6 +1366,9 @@ WebGLContext::DepthRange(WebGLfloat zNear, WebGLfloat zFar) NS_IMETHODIMP WebGLContext::DisableVertexAttribArray(WebGLuint index) { + if (mContextLost) + return NS_OK; + if (!ValidateAttribIndex(index, "disableVertexAttribArray")) return NS_OK; @@ -1463,6 +1587,9 @@ WebGLContext::UnbindFakeBlackTextures() NS_IMETHODIMP WebGLContext::DrawArrays(GLenum mode, WebGLint first, WebGLsizei count) { + if (mContextLost) + return NS_OK; + if (!ValidateDrawModeEnum(mode, "drawArrays: mode")) return NS_OK; @@ -1485,6 +1612,8 @@ WebGLContext::DrawArrays(GLenum mode, WebGLint first, WebGLsizei count) if (!ValidateBuffers(&maxAllowedCount, "drawArrays")) return NS_OK; + SetupRobustnessTimer(); + CheckedInt32 checked_firstPlusCount = CheckedInt32(first) + count; if (!checked_firstPlusCount.valid()) @@ -1520,6 +1649,9 @@ WebGLContext::DrawArrays(GLenum mode, WebGLint first, WebGLsizei count) NS_IMETHODIMP WebGLContext::DrawElements(WebGLenum mode, WebGLsizei count, WebGLenum type, WebGLint byteOffset) { + if (mContextLost) + return NS_OK; + if (!ValidateDrawModeEnum(mode, "drawElements: mode")) return NS_OK; @@ -1533,6 +1665,8 @@ WebGLContext::DrawElements(WebGLenum mode, WebGLsizei count, WebGLenum type, Web if (count == 0) return NS_OK; + SetupRobustnessTimer(); + CheckedUint32 checked_byteCount; if (type == LOCAL_GL_UNSIGNED_SHORT) { @@ -1626,6 +1760,9 @@ WebGLContext::DrawElements(WebGLenum mode, WebGLsizei count, WebGLenum type, Web NS_IMETHODIMP WebGLContext::Enable(WebGLenum cap) { + if (mContextLost) + return NS_OK; + if (!ValidateCapabilityEnum(cap, "enable")) return NS_OK; @@ -1645,6 +1782,9 @@ NS_IMETHODIMP WebGLContext::Enable(WebGLenum cap) NS_IMETHODIMP WebGLContext::Disable(WebGLenum cap) { + if (mContextLost) + return NS_OK; + if (!ValidateCapabilityEnum(cap, "disable")) return NS_OK; @@ -1665,6 +1805,9 @@ NS_IMETHODIMP WebGLContext::Disable(WebGLenum cap) NS_IMETHODIMP WebGLContext::EnableVertexAttribArray(WebGLuint index) { + if (mContextLost) + return NS_OK; + if (!ValidateAttribIndex(index, "enableVertexAttribArray")) return NS_OK; @@ -1679,6 +1822,9 @@ WebGLContext::EnableVertexAttribArray(WebGLuint index) NS_IMETHODIMP WebGLContext::FramebufferRenderbuffer(WebGLenum target, WebGLenum attachment, WebGLenum rbtarget, nsIWebGLRenderbuffer *rbobj) { + if (mContextLost) + return NS_OK; + if (!mBoundFramebuffer) return ErrorInvalidOperation("framebufferRenderbuffer: cannot modify framebuffer 0"); @@ -1692,6 +1838,9 @@ WebGLContext::FramebufferTexture2D(WebGLenum target, nsIWebGLTexture *tobj, WebGLint level) { + if (mContextLost) + return NS_OK; + if (mBoundFramebuffer) return mBoundFramebuffer->FramebufferTexture2D(target, attachment, textarget, tobj, level); else @@ -1705,6 +1854,9 @@ GL_SAME_METHOD_0(Finish, Finish) NS_IMETHODIMP WebGLContext::FrontFace(WebGLenum mode) { + if (mContextLost) + return NS_OK; + switch (mode) { case LOCAL_GL_CW: case LOCAL_GL_CCW: @@ -1722,6 +1874,9 @@ WebGLContext::FrontFace(WebGLenum mode) NS_IMETHODIMP WebGLContext::GetActiveAttrib(nsIWebGLProgram *pobj, PRUint32 index, nsIWebGLActiveInfo **retval) { + if (mContextLost) + return NS_OK; + *retval = nsnull; WebGLuint progname; @@ -1754,6 +1909,9 @@ WebGLContext::GetActiveAttrib(nsIWebGLProgram *pobj, PRUint32 index, nsIWebGLAct NS_IMETHODIMP WebGLContext::GenerateMipmap(WebGLenum target) { + if (mContextLost) + return NS_OK; + if (!ValidateTextureTargetEnum(target, "generateMipmap")) return NS_OK; @@ -1780,6 +1938,9 @@ WebGLContext::GenerateMipmap(WebGLenum target) NS_IMETHODIMP WebGLContext::GetActiveUniform(nsIWebGLProgram *pobj, PRUint32 index, nsIWebGLActiveInfo **retval) { + if (mContextLost) + return NS_OK; + *retval = nsnull; WebGLuint progname; @@ -1833,6 +1994,9 @@ WebGLContext::GetActiveUniform(nsIWebGLProgram *pobj, PRUint32 index, nsIWebGLAc NS_IMETHODIMP WebGLContext::GetAttachedShaders(nsIWebGLProgram *pobj, nsIVariant **retval) { + if (mContextLost) + return NS_OK; + *retval = nsnull; WebGLProgram *prog; @@ -1873,6 +2037,12 @@ WebGLContext::GetAttribLocation(nsIWebGLProgram *pobj, const nsAString& name, PRInt32 *retval) { + if (mContextLost) + { + *retval = -1; + return NS_OK; + } + *retval = 0; WebGLuint progname; @@ -1890,6 +2060,9 @@ WebGLContext::GetAttribLocation(nsIWebGLProgram *pobj, NS_IMETHODIMP WebGLContext::GetParameter(PRUint32 pname, nsIVariant **retval) { + if (mContextLost) + return NS_OK; + *retval = nsnull; nsCOMPtr wrval = do_CreateInstance("@mozilla.org/variant;1"); @@ -2200,6 +2373,9 @@ WebGLContext::GetParameter(PRUint32 pname, nsIVariant **retval) NS_IMETHODIMP WebGLContext::GetBufferParameter(WebGLenum target, WebGLenum pname, nsIVariant **retval) { + if (mContextLost) + return NS_OK; + *retval = nsnull; nsCOMPtr wrval = do_CreateInstance("@mozilla.org/variant;1"); @@ -2234,6 +2410,9 @@ WebGLContext::GetBufferParameter(WebGLenum target, WebGLenum pname, nsIVariant * NS_IMETHODIMP WebGLContext::GetFramebufferAttachmentParameter(WebGLenum target, WebGLenum attachment, WebGLenum pname, nsIVariant **retval) { + if (mContextLost) + return NS_OK; + *retval = nsnull; nsCOMPtr wrval = do_CreateInstance("@mozilla.org/variant;1"); @@ -2312,6 +2491,9 @@ WebGLContext::GetFramebufferAttachmentParameter(WebGLenum target, WebGLenum atta NS_IMETHODIMP WebGLContext::GetRenderbufferParameter(WebGLenum target, WebGLenum pname, nsIVariant **retval) { + if (mContextLost) + return NS_OK; + *retval = nsnull; nsCOMPtr wrval = do_CreateInstance("@mozilla.org/variant;1"); @@ -2360,6 +2542,9 @@ WebGLContext::GetRenderbufferParameter(WebGLenum target, WebGLenum pname, nsIVar NS_IMETHODIMP WebGLContext::CreateBuffer(nsIWebGLBuffer **retval) { + if (mContextLost) + return NS_OK; + *retval = nsnull; MakeContextCurrent(); @@ -2377,6 +2562,9 @@ WebGLContext::CreateBuffer(nsIWebGLBuffer **retval) NS_IMETHODIMP WebGLContext::CreateTexture(nsIWebGLTexture **retval) { + if (mContextLost) + return NS_OK; + *retval = nsnull; MakeContextCurrent(); @@ -2394,9 +2582,11 @@ WebGLContext::CreateTexture(nsIWebGLTexture **retval) NS_IMETHODIMP WebGLContext::GetError(WebGLenum *_retval) { - MakeContextCurrent(); + if (!mContextLost) { + MakeContextCurrent(); + UpdateWebGLErrorAndClearGLError(); + } - UpdateWebGLErrorAndClearGLError(); *_retval = mWebGLError; mWebGLError = LOCAL_GL_NO_ERROR; @@ -2406,6 +2596,9 @@ WebGLContext::GetError(WebGLenum *_retval) NS_IMETHODIMP WebGLContext::GetProgramParameter(nsIWebGLProgram *pobj, PRUint32 pname, nsIVariant **retval) { + if (mContextLost) + return NS_OK; + *retval = nsnull; WebGLuint progname; @@ -2465,6 +2658,12 @@ WebGLContext::GetProgramParameter(nsIWebGLProgram *pobj, PRUint32 pname, nsIVari NS_IMETHODIMP WebGLContext::GetProgramInfoLog(nsIWebGLProgram *pobj, nsAString& retval) { + if (mContextLost) + { + retval.SetIsVoid(true); + return NS_OK; + } + WebGLuint progname; if (!GetGLName("getProgramInfoLog: program", pobj, &progname)) return NS_OK; @@ -2587,18 +2786,27 @@ nsresult WebGLContext::TexParameter_base(WebGLenum target, WebGLenum pname, NS_IMETHODIMP WebGLContext::TexParameterf(WebGLenum target, WebGLenum pname, WebGLfloat param) { + if (mContextLost) + return NS_OK; + return TexParameter_base(target, pname, nsnull, ¶m); } NS_IMETHODIMP WebGLContext::TexParameteri(WebGLenum target, WebGLenum pname, WebGLint param) { + if (mContextLost) + return NS_OK; + return TexParameter_base(target, pname, ¶m, nsnull); } NS_IMETHODIMP WebGLContext::GetTexParameter(WebGLenum target, WebGLenum pname, nsIVariant **retval) { + if (mContextLost) + return NS_OK; + *retval = nsnull; MakeContextCurrent(); @@ -2637,6 +2845,9 @@ WebGLContext::GetTexParameter(WebGLenum target, WebGLenum pname, nsIVariant **re NS_IMETHODIMP WebGLContext::GetUniform(nsIWebGLProgram *pobj, nsIWebGLUniformLocation *ploc, nsIVariant **retval) { + if (mContextLost) + return NS_OK; + *retval = nsnull; WebGLuint progname; @@ -2756,6 +2967,9 @@ WebGLContext::GetUniform(nsIWebGLProgram *pobj, nsIWebGLUniformLocation *ploc, n NS_IMETHODIMP WebGLContext::GetUniformLocation(nsIWebGLProgram *pobj, const nsAString& name, nsIWebGLUniformLocation **retval) { + if (mContextLost) + return NS_OK; + *retval = nsnull; WebGLuint progname; @@ -2779,6 +2993,9 @@ WebGLContext::GetUniformLocation(nsIWebGLProgram *pobj, const nsAString& name, n NS_IMETHODIMP WebGLContext::GetVertexAttrib(WebGLuint index, WebGLenum pname, nsIVariant **retval) { + if (mContextLost) + return NS_OK; + *retval = nsnull; if (!ValidateAttribIndex(index, "getVertexAttrib")) @@ -2847,6 +3064,8 @@ NS_IMETHODIMP WebGLContext::GetVertexAttribOffset(WebGLuint index, WebGLenum pname, WebGLuint *retval) { *retval = 0; + if (mContextLost) + return NS_OK; if (!ValidateAttribIndex(index, "getVertexAttribOffset")) return NS_OK; @@ -2861,6 +3080,9 @@ WebGLContext::GetVertexAttribOffset(WebGLuint index, WebGLenum pname, WebGLuint NS_IMETHODIMP WebGLContext::Hint(WebGLenum target, WebGLenum mode) { + if (mContextLost) + return NS_OK; + bool isValid = false; switch (target) { @@ -2881,6 +3103,12 @@ WebGLContext::Hint(WebGLenum target, WebGLenum mode) NS_IMETHODIMP WebGLContext::IsBuffer(nsIWebGLBuffer *bobj, WebGLboolean *retval) { + if (mContextLost) + { + *retval = false; + return NS_OK; + } + bool isDeleted; WebGLuint buffername; WebGLBuffer *buffer; @@ -2899,6 +3127,12 @@ WebGLContext::IsBuffer(nsIWebGLBuffer *bobj, WebGLboolean *retval) NS_IMETHODIMP WebGLContext::IsFramebuffer(nsIWebGLFramebuffer *fbobj, WebGLboolean *retval) { + if (mContextLost) + { + *retval = false; + return NS_OK; + } + bool isDeleted; WebGLuint fbname; WebGLFramebuffer *fb; @@ -2917,6 +3151,12 @@ WebGLContext::IsFramebuffer(nsIWebGLFramebuffer *fbobj, WebGLboolean *retval) NS_IMETHODIMP WebGLContext::IsProgram(nsIWebGLProgram *pobj, WebGLboolean *retval) { + if (mContextLost) + { + *retval = false; + return NS_OK; + } + bool isDeleted; WebGLProgram *prog = nsnull; bool ok = GetConcreteObject("isProgram", pobj, &prog, nsnull, &isDeleted, false) && @@ -2929,6 +3169,12 @@ WebGLContext::IsProgram(nsIWebGLProgram *pobj, WebGLboolean *retval) NS_IMETHODIMP WebGLContext::IsRenderbuffer(nsIWebGLRenderbuffer *rbobj, WebGLboolean *retval) { + if (mContextLost) + { + *retval = false; + return NS_OK; + } + bool isDeleted; WebGLuint rbname; WebGLRenderbuffer *rb; @@ -2947,6 +3193,12 @@ WebGLContext::IsRenderbuffer(nsIWebGLRenderbuffer *rbobj, WebGLboolean *retval) NS_IMETHODIMP WebGLContext::IsShader(nsIWebGLShader *sobj, WebGLboolean *retval) { + if (mContextLost) + { + *retval = false; + return NS_OK; + } + bool isDeleted; WebGLShader *shader = nsnull; bool ok = GetConcreteObject("isShader", sobj, &shader, nsnull, &isDeleted, false) && @@ -2959,6 +3211,12 @@ WebGLContext::IsShader(nsIWebGLShader *sobj, WebGLboolean *retval) NS_IMETHODIMP WebGLContext::IsTexture(nsIWebGLTexture *tobj, WebGLboolean *retval) { + if (mContextLost) + { + *retval = false; + return NS_OK; + } + bool isDeleted; WebGLuint texname; WebGLTexture *tex; @@ -2977,6 +3235,12 @@ WebGLContext::IsTexture(nsIWebGLTexture *tobj, WebGLboolean *retval) NS_IMETHODIMP WebGLContext::IsEnabled(WebGLenum cap, WebGLboolean *retval) { + if (mContextLost) + { + *retval = false; + return NS_OK; + } + *retval = 0; if (!ValidateCapabilityEnum(cap, "isEnabled")) @@ -2992,6 +3256,9 @@ GL_SAME_METHOD_1(LineWidth, LineWidth, WebGLfloat) NS_IMETHODIMP WebGLContext::LinkProgram(nsIWebGLProgram *pobj) { + if (mContextLost) + return NS_OK; + GLuint progname; WebGLProgram *program; if (!GetConcreteObjectAndGLName("linkProgram", pobj, &program, &progname)) @@ -3024,6 +3291,9 @@ WebGLContext::LinkProgram(nsIWebGLProgram *pobj) NS_IMETHODIMP WebGLContext::PixelStorei(WebGLenum pname, WebGLint param) { + if (mContextLost) + return NS_OK; + switch (pname) { case UNPACK_FLIP_Y_WEBGL: mPixelStoreFlipY = (param != 0); @@ -3064,6 +3334,9 @@ GL_SAME_METHOD_2(PolygonOffset, PolygonOffset, WebGLfloat, WebGLfloat) NS_IMETHODIMP WebGLContext::ReadPixels(PRInt32) { + if (mContextLost) + return NS_OK; + return NS_ERROR_FAILURE; } @@ -3253,6 +3526,9 @@ NS_IMETHODIMP WebGLContext::ReadPixels_array(WebGLint x, WebGLint y, WebGLsizei width, WebGLsizei height, WebGLenum format, WebGLenum type, JSObject *pixels) { + if (mContextLost) + return NS_OK; + return ReadPixels_base(x, y, width, height, format, type, pixels ? JS_GetTypedArrayData(pixels) : 0, pixels ? JS_GetTypedArrayByteLength(pixels) : 0); @@ -3262,6 +3538,9 @@ NS_IMETHODIMP WebGLContext::ReadPixels_buf(WebGLint x, WebGLint y, WebGLsizei width, WebGLsizei height, WebGLenum format, WebGLenum type, JSObject *pixels) { + if (mContextLost) + return NS_OK; + return ReadPixels_base(x, y, width, height, format, type, pixels ? JS_GetArrayBufferData(pixels) : 0, pixels ? JS_GetArrayBufferByteLength(pixels) : 0); @@ -3270,6 +3549,8 @@ WebGLContext::ReadPixels_buf(WebGLint x, WebGLint y, WebGLsizei width, WebGLsize NS_IMETHODIMP WebGLContext::RenderbufferStorage(WebGLenum target, WebGLenum internalformat, WebGLsizei width, WebGLsizei height) { + if (mContextLost) + return NS_OK; if (!mBoundRenderbuffer || !mBoundRenderbuffer->GLName()) return ErrorInvalidOperation("renderbufferStorage called on renderbuffer 0"); @@ -3349,6 +3630,9 @@ GL_SAME_METHOD_2(SampleCoverage, SampleCoverage, WebGLfloat, WebGLboolean) NS_IMETHODIMP WebGLContext::Scissor(WebGLint x, WebGLint y, WebGLsizei width, WebGLsizei height) { + if (mContextLost) + return NS_OK; + if (width < 0 || height < 0) return ErrorInvalidValue("Scissor: negative size"); @@ -3360,6 +3644,9 @@ WebGLContext::Scissor(WebGLint x, WebGLint y, WebGLsizei width, WebGLsizei heigh NS_IMETHODIMP WebGLContext::StencilFunc(WebGLenum func, WebGLint ref, WebGLuint mask) { + if (mContextLost) + return NS_OK; + if (!ValidateComparisonEnum(func, "stencilFunc: func")) return NS_OK; @@ -3376,6 +3663,9 @@ WebGLContext::StencilFunc(WebGLenum func, WebGLint ref, WebGLuint mask) NS_IMETHODIMP WebGLContext::StencilFuncSeparate(WebGLenum face, WebGLenum func, WebGLint ref, WebGLuint mask) { + if (mContextLost) + return NS_OK; + if (!ValidateFaceEnum(face, "stencilFuncSeparate: face") || !ValidateComparisonEnum(func, "stencilFuncSeparate: func")) return NS_OK; @@ -3405,6 +3695,9 @@ WebGLContext::StencilFuncSeparate(WebGLenum face, WebGLenum func, WebGLint ref, NS_IMETHODIMP WebGLContext::StencilMask(WebGLuint mask) { + if (mContextLost) + return NS_OK; + mStencilWriteMaskFront = mask; mStencilWriteMaskBack = mask; @@ -3416,6 +3709,9 @@ WebGLContext::StencilMask(WebGLuint mask) NS_IMETHODIMP WebGLContext::StencilMaskSeparate(WebGLenum face, WebGLuint mask) { + if (mContextLost) + return NS_OK; + if (!ValidateFaceEnum(face, "stencilMaskSeparate: face")) return NS_OK; @@ -3440,6 +3736,9 @@ WebGLContext::StencilMaskSeparate(WebGLenum face, WebGLuint mask) NS_IMETHODIMP WebGLContext::StencilOp(WebGLenum sfail, WebGLenum dpfail, WebGLenum dppass) { + if (mContextLost) + return NS_OK; + if (!ValidateStencilOpEnum(sfail, "stencilOp: sfail") || !ValidateStencilOpEnum(dpfail, "stencilOp: dpfail") || !ValidateStencilOpEnum(dppass, "stencilOp: dppass")) @@ -3453,6 +3752,9 @@ WebGLContext::StencilOp(WebGLenum sfail, WebGLenum dpfail, WebGLenum dppass) NS_IMETHODIMP WebGLContext::StencilOpSeparate(WebGLenum face, WebGLenum sfail, WebGLenum dpfail, WebGLenum dppass) { + if (mContextLost) + return NS_OK; + if (!ValidateFaceEnum(face, "stencilOpSeparate: face") || !ValidateStencilOpEnum(sfail, "stencilOpSeparate: sfail") || !ValidateStencilOpEnum(dpfail, "stencilOpSeparate: dpfail") || @@ -3766,6 +4068,8 @@ WebGLContext::name(PRInt32) { \ NS_IMETHODIMP \ WebGLContext::name##_array(nsIWebGLUniformLocation *ploc, JSObject *wa) \ { \ + if (mContextLost) \ + return NS_OK; \ OBTAIN_UNIFORM_LOCATION(#name ": location") \ if (!wa || JS_GetTypedArrayType(wa) != js::TypedArray::arrayType) \ return ErrorInvalidOperation(#name ": array must be " #arrayType); \ @@ -3784,6 +4088,8 @@ WebGLContext::name(PRInt32) { \ NS_IMETHODIMP \ WebGLContext::name##_array(nsIWebGLUniformLocation *ploc, WebGLboolean transpose, JSObject *wa) \ { \ + if (mContextLost) \ + return NS_OK; \ OBTAIN_UNIFORM_LOCATION(#name ": location") \ if (!wa || JS_GetTypedArrayType(wa) != js::TypedArray::arrayType) \ return ErrorInvalidValue(#name ": array must be " #arrayType); \ @@ -3798,24 +4104,32 @@ WebGLContext::name##_array(nsIWebGLUniformLocation *ploc, WebGLboolean transpose #define SIMPLE_METHOD_UNIFORM_1(glname, name, t1) \ NS_IMETHODIMP WebGLContext::name(nsIWebGLUniformLocation *ploc, t1 a1) { \ + if (mContextLost) \ + return NS_OK; \ OBTAIN_UNIFORM_LOCATION(#name ": location") \ MakeContextCurrent(); gl->f##glname(location, a1); return NS_OK; \ } #define SIMPLE_METHOD_UNIFORM_2(glname, name, t1, t2) \ NS_IMETHODIMP WebGLContext::name(nsIWebGLUniformLocation *ploc, t1 a1, t2 a2) { \ + if (mContextLost) \ + return NS_OK; \ OBTAIN_UNIFORM_LOCATION(#name ": location") \ MakeContextCurrent(); gl->f##glname(location, a1, a2); return NS_OK; \ } #define SIMPLE_METHOD_UNIFORM_3(glname, name, t1, t2, t3) \ NS_IMETHODIMP WebGLContext::name(nsIWebGLUniformLocation *ploc, t1 a1, t2 a2, t3 a3) { \ + if (mContextLost) \ + return NS_OK; \ OBTAIN_UNIFORM_LOCATION(#name ": location") \ MakeContextCurrent(); gl->f##glname(location, a1, a2, a3); return NS_OK; \ } #define SIMPLE_METHOD_UNIFORM_4(glname, name, t1, t2, t3, t4) \ NS_IMETHODIMP WebGLContext::name(nsIWebGLUniformLocation *ploc, t1 a1, t2 a2, t3 a3, t4 a4) { \ + if (mContextLost) \ + return NS_OK; \ OBTAIN_UNIFORM_LOCATION(#name ": location") \ MakeContextCurrent(); gl->f##glname(location, a1, a2, a3, a4); return NS_OK; \ } @@ -3847,6 +4161,9 @@ SIMPLE_MATRIX_METHOD_UNIFORM(UniformMatrix4fv, 4, TYPE_FLOAT32, WebGLfloat) NS_IMETHODIMP WebGLContext::VertexAttrib1f(PRUint32 index, WebGLfloat x0) { + if (mContextLost) + return NS_OK; + MakeContextCurrent(); if (index) { @@ -3866,6 +4183,9 @@ WebGLContext::VertexAttrib1f(PRUint32 index, WebGLfloat x0) NS_IMETHODIMP WebGLContext::VertexAttrib2f(PRUint32 index, WebGLfloat x0, WebGLfloat x1) { + if (mContextLost) + return NS_OK; + MakeContextCurrent(); if (index) { @@ -3885,6 +4205,9 @@ WebGLContext::VertexAttrib2f(PRUint32 index, WebGLfloat x0, WebGLfloat x1) NS_IMETHODIMP WebGLContext::VertexAttrib3f(PRUint32 index, WebGLfloat x0, WebGLfloat x1, WebGLfloat x2) { + if (mContextLost) + return NS_OK; + MakeContextCurrent(); if (index) { @@ -3905,6 +4228,9 @@ NS_IMETHODIMP WebGLContext::VertexAttrib4f(PRUint32 index, WebGLfloat x0, WebGLfloat x1, WebGLfloat x2, WebGLfloat x3) { + if (mContextLost) + return NS_OK; + MakeContextCurrent(); if (index) { @@ -3929,6 +4255,8 @@ WebGLContext::name(PRInt32) { \ NS_IMETHODIMP \ WebGLContext::name##_array(WebGLuint idx, JSObject *wa) \ { \ + if (mContextLost) \ + return NS_OK; \ if (!wa || JS_GetTypedArrayType(wa) != js::TypedArray::arrayType) \ return ErrorInvalidOperation(#name ": array must be " #arrayType); \ if (JS_GetTypedArrayLength(wa) < cnt) \ @@ -3956,6 +4284,9 @@ SIMPLE_ARRAY_METHOD_NO_COUNT(VertexAttrib4fv, 4, TYPE_FLOAT32, WebGLfloat) NS_IMETHODIMP WebGLContext::UseProgram(nsIWebGLProgram *pobj) { + if (mContextLost) + return NS_OK; + WebGLProgram *prog; WebGLuint progname; bool isNull; @@ -3981,6 +4312,9 @@ WebGLContext::UseProgram(nsIWebGLProgram *pobj) NS_IMETHODIMP WebGLContext::ValidateProgram(nsIWebGLProgram *pobj) { + if (mContextLost) + return NS_OK; + WebGLuint progname; if (!GetGLName("validateProgram", pobj, &progname)) return NS_OK; @@ -4001,6 +4335,9 @@ WebGLContext::ValidateProgram(nsIWebGLProgram *pobj) NS_IMETHODIMP WebGLContext::CreateFramebuffer(nsIWebGLFramebuffer **retval) { + if (mContextLost) + return NS_OK; + *retval = 0; MakeContextCurrent(); @@ -4018,6 +4355,9 @@ WebGLContext::CreateFramebuffer(nsIWebGLFramebuffer **retval) NS_IMETHODIMP WebGLContext::CreateRenderbuffer(nsIWebGLRenderbuffer **retval) { + if (mContextLost) + return NS_OK; + *retval = 0; MakeContextCurrent(); @@ -4035,6 +4375,9 @@ WebGLContext::CreateRenderbuffer(nsIWebGLRenderbuffer **retval) NS_IMETHODIMP WebGLContext::Viewport(WebGLint x, WebGLint y, WebGLsizei width, WebGLsizei height) { + if (mContextLost) + return NS_OK; + if (width < 0 || height < 0) return ErrorInvalidValue("Viewport: negative size"); @@ -4052,6 +4395,9 @@ WebGLContext::Viewport(WebGLint x, WebGLint y, WebGLsizei width, WebGLsizei heig NS_IMETHODIMP WebGLContext::CompileShader(nsIWebGLShader *sobj) { + if (mContextLost) + return NS_OK; + WebGLShader *shader; WebGLuint shadername; if (!GetConcreteObjectAndGLName("compileShader", sobj, &shader, &shadername)) @@ -4158,6 +4504,9 @@ WebGLContext::CompileShader(nsIWebGLShader *sobj) NS_IMETHODIMP WebGLContext::GetShaderParameter(nsIWebGLShader *sobj, WebGLenum pname, nsIVariant **retval) { + if (mContextLost) + return NS_OK; + *retval = nsnull; WebGLShader *shader; @@ -4204,6 +4553,12 @@ WebGLContext::GetShaderParameter(nsIWebGLShader *sobj, WebGLenum pname, nsIVaria NS_IMETHODIMP WebGLContext::GetShaderInfoLog(nsIWebGLShader *sobj, nsAString& retval) { + if (mContextLost) + { + retval.SetIsVoid(true); + return NS_OK; + } + WebGLShader *shader; WebGLuint shadername; if (!GetConcreteObjectAndGLName("getShaderInfoLog: shader", sobj, &shader, &shadername)) @@ -4242,6 +4597,12 @@ WebGLContext::GetShaderInfoLog(nsIWebGLShader *sobj, nsAString& retval) NS_IMETHODIMP WebGLContext::GetShaderSource(nsIWebGLShader *sobj, nsAString& retval) { + if (mContextLost) + { + retval.SetIsVoid(true); + return NS_OK; + } + WebGLShader *shader; WebGLuint shadername; if (!GetConcreteObjectAndGLName("getShaderSource: shader", sobj, &shader, &shadername)) @@ -4255,6 +4616,9 @@ WebGLContext::GetShaderSource(nsIWebGLShader *sobj, nsAString& retval) NS_IMETHODIMP WebGLContext::ShaderSource(nsIWebGLShader *sobj, const nsAString& source) { + if (mContextLost) + return NS_OK; + WebGLShader *shader; WebGLuint shadername; if (!GetConcreteObjectAndGLName("shaderSource: shader", sobj, &shader, &shadername)) @@ -4280,6 +4644,9 @@ WebGLContext::VertexAttribPointer(WebGLuint index, WebGLint size, WebGLenum type WebGLboolean normalized, WebGLsizei stride, WebGLsizeiptr byteOffset) { + if (mContextLost) + return NS_OK; + if (mBoundArrayBuffer == nsnull) return ErrorInvalidOperation("VertexAttribPointer: must have valid GL_ARRAY_BUFFER binding"); @@ -4353,6 +4720,9 @@ WebGLContext::VertexAttribPointer(WebGLuint index, WebGLint size, WebGLenum type NS_IMETHODIMP WebGLContext::TexImage2D(PRInt32) { + if (mContextLost) + return NS_OK; + return NS_ERROR_FAILURE; } @@ -4546,6 +4916,9 @@ WebGLContext::TexImage2D_buf(WebGLenum target, WebGLint level, WebGLenum interna WebGLenum format, WebGLenum type, JSObject *pixels) { + if (mContextLost) + return NS_OK; + return TexImage2D_base(target, level, internalformat, width, height, 0, border, format, type, pixels ? JS_GetArrayBufferData(pixels) : 0, pixels ? JS_GetArrayBufferByteLength(pixels) : 0, @@ -4559,6 +4932,9 @@ WebGLContext::TexImage2D_array(WebGLenum target, WebGLint level, WebGLenum inter WebGLenum format, WebGLenum type, JSObject *pixels) { + if (mContextLost) + return NS_OK; + return TexImage2D_base(target, level, internalformat, width, height, 0, border, format, type, pixels ? JS_GetTypedArrayData(pixels) : 0, pixels ? JS_GetTypedArrayByteLength(pixels) : 0, @@ -4572,6 +4948,9 @@ WebGLContext::TexImage2D_imageData(WebGLenum target, WebGLint level, WebGLenum i WebGLenum format, WebGLenum type, JSObject *pixels) { + if (mContextLost) + return NS_OK; + return TexImage2D_base(target, level, internalformat, width, height, 4*width, border, format, type, pixels ? JS_GetTypedArrayData(pixels) : 0, pixels ? JS_GetTypedArrayByteLength(pixels) : 0, @@ -4583,6 +4962,9 @@ NS_IMETHODIMP WebGLContext::TexImage2D_dom(WebGLenum target, WebGLint level, WebGLenum internalformat, WebGLenum format, GLenum type, nsIDOMElement *elt) { + if (mContextLost) + return NS_OK; + nsRefPtr isurf; int srcFormat; @@ -4603,6 +4985,9 @@ WebGLContext::TexImage2D_dom(WebGLenum target, WebGLint level, WebGLenum interna NS_IMETHODIMP WebGLContext::TexSubImage2D(PRInt32) { + if (mContextLost) + return NS_OK; + return NS_ERROR_FAILURE; } @@ -4728,6 +5113,9 @@ WebGLContext::TexSubImage2D_buf(WebGLenum target, WebGLint level, WebGLenum format, WebGLenum type, JSObject *pixels) { + if (mContextLost) + return NS_OK; + if (!pixels) return ErrorInvalidValue("TexSubImage2D: pixels must not be null!"); @@ -4745,6 +5133,9 @@ WebGLContext::TexSubImage2D_array(WebGLenum target, WebGLint level, WebGLenum format, WebGLenum type, JSObject *pixels) { + if (mContextLost) + return NS_OK; + if (!pixels) return ErrorInvalidValue("TexSubImage2D: pixels must not be null!"); @@ -4762,6 +5153,9 @@ WebGLContext::TexSubImage2D_imageData(WebGLenum target, WebGLint level, WebGLenum format, WebGLenum type, JSObject *pixels) { + if (mContextLost) + return NS_OK; + if (!pixels) return ErrorInvalidValue("TexSubImage2D: pixels must not be null!"); @@ -4778,6 +5172,9 @@ WebGLContext::TexSubImage2D_dom(WebGLenum target, WebGLint level, WebGLenum format, WebGLenum type, nsIDOMElement *elt) { + if (mContextLost) + return NS_OK; + nsRefPtr isurf; int srcFormat; @@ -4796,6 +5193,31 @@ WebGLContext::TexSubImage2D_dom(WebGLenum target, WebGLint level, srcFormat, true); } +bool +WebGLContext::LoseContext() +{ + if (mContextLost) { + return false; + } + + mAllowRestore = true; + ForceLoseContext(); + + return true; +} + +bool +WebGLContext::RestoreContext() +{ + if (!mContextLost || !mAllowRestore) { + return false; + } + + ForceRestoreContext(); + + return true; +} + bool BaseTypeAndSizeFromUniformType(WebGLenum uType, WebGLenum *baseType, WebGLint *unitSize) { diff --git a/content/canvas/src/WebGLContextNotSupported.cpp b/content/canvas/src/WebGLContextNotSupported.cpp index 9147dc9dfe73..0df4c8476876 100644 --- a/content/canvas/src/WebGLContextNotSupported.cpp +++ b/content/canvas/src/WebGLContextNotSupported.cpp @@ -53,3 +53,4 @@ DOMCI_DATA(WebGLRenderbuffer, void) DOMCI_DATA(WebGLUniformLocation, void) DOMCI_DATA(WebGLActiveInfo, void) DOMCI_DATA(WebGLExtension, void) +DOMCI_DATA(WebGLExtensionLoseContext, void) diff --git a/content/canvas/src/WebGLExtensionLoseContext.cpp b/content/canvas/src/WebGLExtensionLoseContext.cpp new file mode 100644 index 000000000000..52d9dfb41296 --- /dev/null +++ b/content/canvas/src/WebGLExtensionLoseContext.cpp @@ -0,0 +1,76 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Doug Sherk (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include + +#include "WebGLContext.h" +#include "WebGLExtensions.h" + +#include "nsContentUtils.h" +#include "mozilla/Preferences.h" + +using namespace mozilla; + +WebGLExtensionLoseContext::WebGLExtensionLoseContext(WebGLContext* context) : + WebGLExtension(context) +{ + +} + +WebGLExtensionLoseContext::~WebGLExtensionLoseContext() +{ + +} + +NS_IMETHODIMP +WebGLExtensionLoseContext::LoseContext() +{ + if (!mContext->LoseContext()) + return mContext->mWebGLError = LOCAL_GL_INVALID_OPERATION; + + return NS_OK; +} + +NS_IMETHODIMP +WebGLExtensionLoseContext::RestoreContext() +{ + if (!mContext->RestoreContext()) + return mContext->mWebGLError = LOCAL_GL_INVALID_OPERATION; + + return NS_OK; +} diff --git a/content/canvas/src/WebGLExtensions.h b/content/canvas/src/WebGLExtensions.h index 79c2c6453030..e2cab6c026c0 100644 --- a/content/canvas/src/WebGLExtensions.h +++ b/content/canvas/src/WebGLExtensions.h @@ -41,8 +41,27 @@ namespace mozilla { +class WebGLExtensionLoseContext; class WebGLExtensionStandardDerivatives; +#define WEBGLEXTENSIONLOSECONTEXT_PRIVATE_IID \ + {0xb0afc2eb, 0x0895, 0x4509, {0x98, 0xde, 0x5c, 0x38, 0x3d, 0x16, 0x06, 0x94}} +class WebGLExtensionLoseContext : + public nsIWebGLExtensionLoseContext, + public WebGLExtension +{ +public: + WebGLExtensionLoseContext(WebGLContext*); + virtual ~WebGLExtensionLoseContext(); + + NS_DECL_ISUPPORTS + NS_DECL_NSIWEBGLEXTENSIONLOSECONTEXT + + NS_DECLARE_STATIC_IID_ACCESSOR(WEBGLEXTENSIONLOSECONTEXT_PRIVATE_IID) +}; + +NS_DEFINE_STATIC_IID_ACCESSOR(WebGLExtensionLoseContext, WEBGLACTIVEINFO_PRIVATE_IID) + #define WEBGLEXTENSIONSTANDARDDERIVATIVES_PRIVATE_IID \ {0x3de3dfd9, 0x864a, 0x4e4c, {0x98, 0x9b, 0x29, 0x77, 0xea, 0xa8, 0x0b, 0x7b}} class WebGLExtensionStandardDerivatives : diff --git a/dom/base/nsDOMClassInfo.cpp b/dom/base/nsDOMClassInfo.cpp index cf72c0e6149c..48e196b027c4 100644 --- a/dom/base/nsDOMClassInfo.cpp +++ b/dom/base/nsDOMClassInfo.cpp @@ -1450,6 +1450,8 @@ static nsDOMClassInfoData sClassInfoData[] = { DOM_DEFAULT_SCRIPTABLE_FLAGS) NS_DEFINE_CLASSINFO_DATA(WebGLExtensionStandardDerivatives, nsDOMGenericSH, DOM_DEFAULT_SCRIPTABLE_FLAGS) + NS_DEFINE_CLASSINFO_DATA(WebGLExtensionLoseContext, nsDOMGenericSH, + DOM_DEFAULT_SCRIPTABLE_FLAGS) NS_DEFINE_CLASSINFO_DATA(PaintRequest, nsDOMGenericSH, DOM_DEFAULT_SCRIPTABLE_FLAGS) @@ -3986,6 +3988,10 @@ nsDOMClassInfo::Init() DOM_CLASSINFO_MAP_ENTRY(nsIWebGLExtensionStandardDerivatives) DOM_CLASSINFO_MAP_END + DOM_CLASSINFO_MAP_BEGIN(WebGLExtensionLoseContext, nsIWebGLExtensionLoseContext) + DOM_CLASSINFO_MAP_ENTRY(nsIWebGLExtensionLoseContext) + DOM_CLASSINFO_MAP_END + DOM_CLASSINFO_MAP_BEGIN(PaintRequest, nsIDOMPaintRequest) DOM_CLASSINFO_MAP_ENTRY(nsIDOMPaintRequest) DOM_CLASSINFO_MAP_END diff --git a/dom/base/nsDOMClassInfoClasses.h b/dom/base/nsDOMClassInfoClasses.h index 7a2c9008a1f4..6c79490b18c9 100644 --- a/dom/base/nsDOMClassInfoClasses.h +++ b/dom/base/nsDOMClassInfoClasses.h @@ -472,6 +472,7 @@ DOMCI_CLASS(WebGLUniformLocation) DOMCI_CLASS(WebGLActiveInfo) DOMCI_CLASS(WebGLExtension) DOMCI_CLASS(WebGLExtensionStandardDerivatives) +DOMCI_CLASS(WebGLExtensionLoseContext) DOMCI_CLASS(PaintRequest) DOMCI_CLASS(PaintRequestList) diff --git a/dom/interfaces/canvas/nsIDOMWebGLRenderingContext.idl b/dom/interfaces/canvas/nsIDOMWebGLRenderingContext.idl index 45e5df3bb229..7962227f2695 100644 --- a/dom/interfaces/canvas/nsIDOMWebGLRenderingContext.idl +++ b/dom/interfaces/canvas/nsIDOMWebGLRenderingContext.idl @@ -153,6 +153,12 @@ interface nsIWebGLExtensionStandardDerivatives : nsIWebGLExtension const WebGLenum FRAGMENT_SHADER_DERIVATIVE_HINT_OES = 0x8B8B; }; +[scriptable, uuid(b0afc2eb-0895-4509-98de-5c383d160694)] +interface nsIWebGLExtensionLoseContext : nsIWebGLExtension +{ + void loseContext(); + void restoreContext(); +}; [scriptable, builtinclass, uuid(ef15ae85-4670-4dc4-848d-51ca81e8397a)] interface nsIDOMWebGLRenderingContext : nsISupports diff --git a/gfx/thebes/GLContext.cpp b/gfx/thebes/GLContext.cpp index 2ca6572dcaf1..ece01b1c8bd8 100644 --- a/gfx/thebes/GLContext.cpp +++ b/gfx/thebes/GLContext.cpp @@ -174,6 +174,8 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl) return true; } + mHasRobustness = IsExtensionSupported(ARB_robustness); + SymLoadStruct symbols[] = { { (PRFuncPtr*) &mSymbols.fActiveTexture, { "ActiveTexture", "ActiveTextureARB", NULL } }, { (PRFuncPtr*) &mSymbols.fAttachShader, { "AttachShader", "AttachShaderARB", NULL } }, @@ -325,6 +327,9 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl) { mIsGLES2 ? (PRFuncPtr*) NULL : (PRFuncPtr*) &mSymbols.fUnmapBuffer, { mIsGLES2 ? NULL : "UnmapBuffer", NULL } }, + { mHasRobustness ? (PRFuncPtr*) &mSymbols.fGetGraphicsResetStatus : (PRFuncPtr*) NULL, + { mHasRobustness ? "GetGraphicsResetStatusARB" : NULL, NULL } }, + { NULL, { NULL } }, }; @@ -470,6 +475,7 @@ static const char *sExtensionNames[] = { "GL_EXT_framebuffer_multisample", "GL_ANGLE_framebuffer_multisample", "GL_OES_rgb8_rgba8", + "GL_ARB_robustness", NULL }; diff --git a/gfx/thebes/GLContext.h b/gfx/thebes/GLContext.h index 6e07da088afc..7fc219aaa81f 100644 --- a/gfx/thebes/GLContext.h +++ b/gfx/thebes/GLContext.h @@ -1242,6 +1242,7 @@ public: EXT_framebuffer_multisample, ANGLE_framebuffer_multisample, OES_rgb8_rgba8, + ARB_robustness, Extensions_Max }; @@ -1278,11 +1279,24 @@ public: bool values[setlen]; }; + /** + * 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, + }; + protected: bool mInitialized; bool mIsOffscreen; bool mIsGLES2; bool mIsGlobalSharedContext; + bool mHasRobustness; PRInt32 mVendor; @@ -2498,6 +2512,14 @@ public: AFTER_GL_CALL; TRACKING_CONTEXT(DeletedRenderbuffers(this, n, names)); } + + GLenum GLAPIENTRY fGetGraphicsResetStatus() { + BEFORE_GL_CALL; + GLenum ret = mHasRobustness ? mSymbols.fGetGraphicsResetStatus() : 0; + AFTER_GL_CALL; + return ret; + } + #ifdef DEBUG void THEBES_API CreatedProgram(GLContext *aOrigin, GLuint aName); void THEBES_API CreatedShader(GLContext *aOrigin, GLuint aName); diff --git a/gfx/thebes/GLContextProviderGLX.cpp b/gfx/thebes/GLContextProviderGLX.cpp index e07f4493f398..c4e8d52b7329 100644 --- a/gfx/thebes/GLContextProviderGLX.cpp +++ b/gfx/thebes/GLContextProviderGLX.cpp @@ -183,6 +183,11 @@ GLXLibrary::EnsureInitialized() { NULL, { NULL } } }; + LibrarySymbolLoader::SymLoadStruct symbols_robustness[] = { + { (PRFuncPtr*) &xCreateContextAttribsInternal, { "glXCreateContextAttribsARB", NULL } }, + { NULL, { NULL } } + }; + if (!LibrarySymbolLoader::LoadSymbols(mOGLLibrary, &symbols[0])) { NS_WARNING("Couldn't find required entry point in OpenGL shared library"); return false; @@ -251,6 +256,17 @@ GLXLibrary::EnsureInitialized() NS_WARNING("Texture from pixmap disabled"); } + if (HasExtension(extensionsStr, "GL_ARB_robustness")) { + if (!LibrarySymbolLoader::LoadSymbols(mOGLLibrary, symbols_robustness)) { + // We have no easy way of checking whether or not this extension + // exists, so it's best to just try to load it and accept that it + // might fail. + //NS_WARNING("Couldn't load ARB_robustness symbols"); + } else { + mHasRobustness = true; + } + } + gIsATI = serverVendor && DoesVendorStringMatch(serverVendor, "ATI"); gIsChromium = (serverVendor && DoesVendorStringMatch(serverVendor, "Chromium")) || @@ -633,6 +649,23 @@ GLXLibrary::xWaitX() AFTER_GLX_CALL; } +GLXContext +GLXLibrary::xCreateContextAttribs(Display* display, + GLXFBConfig config, + GLXContext share_list, + Bool direct, + const int* attrib_list) +{ + BEFORE_GLX_CALL; + GLXContext result = xCreateContextAttribsInternal(display, + config, + share_list, + direct, + attrib_list); + AFTER_GLX_CALL; + return result; +} + GLXLibrary sGLXLibrary; class GLContextGLX : public GLContext @@ -667,11 +700,25 @@ TRY_AGAIN_NO_SHARING: error = false; - context = sGLXLibrary.xCreateNewContext(display, - cfg, - GLX_RGBA_TYPE, - shareContext ? shareContext->mContext : NULL, - True); + if (sGLXLibrary.HasRobustness()) { + int attrib_list[] = { + LOCAL_GL_CONTEXT_FLAGS_ARB, LOCAL_GL_CONTEXT_ROBUST_ACCESS_BIT_ARB, + LOCAL_GL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, LOCAL_GL_LOSE_CONTEXT_ON_RESET_ARB, + 0, + }; + + context = sGLXLibrary.xCreateContextAttribs(display, + cfg, + shareContext ? shareContext->mContext : NULL, + True, + attrib_list); + } else { + context = sGLXLibrary.xCreateNewContext(display, + cfg, + GLX_RGBA_TYPE, + shareContext ? shareContext->mContext : NULL, + True); + } if (context) { glContext = new GLContextGLX(format, diff --git a/gfx/thebes/GLContextSymbols.h b/gfx/thebes/GLContextSymbols.h index 77af7297ac85..38aac71f7f9b 100644 --- a/gfx/thebes/GLContextSymbols.h +++ b/gfx/thebes/GLContextSymbols.h @@ -373,6 +373,8 @@ struct GLContextSymbols typedef realGLboolean (GLAPIENTRY * PFNGLUNMAPBUFFER) (GLenum target); PFNGLUNMAPBUFFER fUnmapBuffer; + typedef GLenum (GLAPIENTRY * PFNGLGETGRAPHICSRESETSTATUS) (void); + PFNGLGETGRAPHICSRESETSTATUS fGetGraphicsResetStatus; }; } diff --git a/gfx/thebes/GLDefs.h b/gfx/thebes/GLDefs.h index 87c48ccb02b0..99fe58b970e6 100644 --- a/gfx/thebes/GLDefs.h +++ b/gfx/thebes/GLDefs.h @@ -178,6 +178,7 @@ typedef ptrdiff_t GLintptr; #define LOCAL_GL_STACK_OVERFLOW 0x0503 #define LOCAL_GL_STACK_UNDERFLOW 0x0504 #define LOCAL_GL_OUT_OF_MEMORY 0x0505 +#define LOCAL_GL_CONTEXT_LOST 0x9242 #define LOCAL_GL_2D 0x0600 #define LOCAL_GL_3D 0x0601 #define LOCAL_GL_3D_COLOR 0x0602 @@ -3039,6 +3040,49 @@ typedef ptrdiff_t GLintptr; #define LOCAL_GL_MAX_FRAGMENT_INPUT_COMPONENTS 0x9125 #define LOCAL_GL_MAX_VERTEX_OUTPUT_COMPONENTS 0x9122 +#define LOCAL_GL_GUILTY_CONTEXT_RESET_ARB 0x8253 +#define LOCAL_GL_INNOCENT_CONTEXT_RESET_ARB 0x8254 +#define LOCAL_GL_UNKNOWN_CONTEXT_RESET_ARB 0x8255 + +#define LOCAL_GL_RESET_NOTIFICATION_STRATEGY_ARB 0x8256 + +#define LOCAL_GL_LOSE_CONTEXT_ON_RESET_ARB 0x8252 +#define LOCAL_GL_NO_RESET_NOTIFICATION_ARB 0x8261 + +#define LOCAL_GL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256 +#define LOCAL_GL_NO_RESET_NOTIFICATION_ARB 0x8261 +#define LOCAL_GL_LOSE_CONTEXT_ON_RESET_ARB 0x8252 + +#define LOCAL_WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256 +#define LOCAL_WGL_NO_RESET_NOTIFICATION_ARB 0x8261 +#define LOCAL_WGL_LOSE_CONTEXT_ON_RESET_ARB 0x8252 + +#define LOCAL_GL_CONTEXT_MAJOR_VERSION_ARB 0x2091 +#define LOCAL_GL_CONTEXT_MINOR_VERSION_ARB 0x2092 +#define LOCAL_GL_CONTEXT_LAYER_PLANE_ARB 0x2093 +#define LOCAL_GL_CONTEXT_FLAGS_ARB 0x2094 +#define LOCAL_GL_CONTEXT_PROFILE_MASK_ARB 0x9126 + +#define LOCAL_WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091 +#define LOCAL_WGL_CONTEXT_MINOR_VERSION_ARB 0x2092 +#define LOCAL_WGL_CONTEXT_LAYER_PLANE_ARB 0x2093 +#define LOCAL_WGL_CONTEXT_FLAGS_ARB 0x2094 +#define LOCAL_WGL_CONTEXT_PROFILE_MASK_ARB 0x9126 + +#define LOCAL_GL_CONTEXT_DEBUG_BIT_ARB 0x0001 +#define LOCAL_GL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002 + +#define LOCAL_WGL_CONTEXT_DEBUG_BIT_ARB 0x0001 +#define LOCAL_WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002 + +#define LOCAL_GL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 +#define LOCAL_GL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 +#define LOCAL_GL_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004 + +#define LOCAL_WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 +#define LOCAL_WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 +#define LOCAL_WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004 + #define LOCAL_WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000 #define LOCAL_WGL_DRAW_TO_WINDOW_ARB 0x2001 #define LOCAL_WGL_DRAW_TO_BITMAP_ARB 0x2002 diff --git a/gfx/thebes/GLXLibrary.h b/gfx/thebes/GLXLibrary.h index 3029bfd2c5d3..000b98fabdd5 100644 --- a/gfx/thebes/GLXLibrary.h +++ b/gfx/thebes/GLXLibrary.h @@ -50,7 +50,7 @@ class GLXLibrary public: GLXLibrary() : mInitialized(false), mTriedInitializing(false), mHasTextureFromPixmap(false), mDebug(false), - mOGLLibrary(nsnull) {} + mHasRobustness(false), mOGLLibrary(nsnull) {} void xDestroyContext(Display* display, GLXContext context); Bool xMakeCurrent(Display* display, @@ -108,6 +108,12 @@ public: void xWaitGL(); void xWaitX(); + GLXContext xCreateContextAttribs(Display* display, + GLXFBConfig config, + GLXContext share_list, + Bool direct, + const int* attrib_list); + bool EnsureInitialized(); GLXPixmap CreatePixmap(gfxASurface* aSurface); @@ -116,6 +122,7 @@ public: void ReleaseTexImage(GLXPixmap aPixmap); bool HasTextureFromPixmap() { return mHasTextureFromPixmap; } + bool HasRobustness() { return mHasRobustness; } bool SupportsTextureFromPixmap(gfxASurface* aSurface); private: @@ -209,6 +216,13 @@ private: typedef void (GLAPIENTRY * PFNGLXWAITX) (); PFNGLXWAITGL xWaitXInternal; + typedef GLXContext (GLAPIENTRY * PFNGLXCREATECONTEXTATTRIBS) (Display *, + GLXFBConfig, + GLXContext, + Bool, + const int *); + PFNGLXCREATECONTEXTATTRIBS xCreateContextAttribsInternal; + #ifdef DEBUG void BeforeGLXCall(); void AfterGLXCall(); @@ -218,6 +232,7 @@ private: bool mTriedInitializing; bool mHasTextureFromPixmap; bool mDebug; + bool mHasRobustness; PRLibrary *mOGLLibrary; }; diff --git a/js/xpconnect/src/dom_quickstubs.qsconf b/js/xpconnect/src/dom_quickstubs.qsconf index 19a89e553c5f..47ce440d7a72 100644 --- a/js/xpconnect/src/dom_quickstubs.qsconf +++ b/js/xpconnect/src/dom_quickstubs.qsconf @@ -487,6 +487,7 @@ irregularFilenames = { 'nsIWebGLUniformLocation': 'nsIDOMWebGLRenderingContext', 'nsIWebGLExtension': 'nsIDOMWebGLRenderingContext', 'nsIWebGLExtensionStandardDerivatives' : 'nsIDOMWebGLRenderingContext', + 'nsIWebGLExtensionLoseContext' : 'nsIDOMWebGLRenderingContext', 'nsIIndexedDatabaseUsageCallback': 'nsIIndexedDatabaseManager',