Bug 1278403 - Choose GLContext::DebugFlags based on ContextCreateFlags. - r=jrmuizel draft
authorJeff Gilbert <jgilbert@mozilla.com>
Mon, 06 Jun 2016 16:29:08 -0700
changeset 379687 62dab06f36f831cd37a8a2116cab45417f8440f2
parent 379686 7c47c162bb19f1610c59001aa794c4a509e6d3b0
child 379688 6f8d02e3ec323e4833db96fc092ea23a6d181585
push id21022
push userbmo:jgilbert@mozilla.com
push dateThu, 16 Jun 2016 15:24:56 +0000
reviewersjrmuizel
bugs1278403
milestone50.0a1
Bug 1278403 - Choose GLContext::DebugFlags based on ContextCreateFlags. - r=jrmuizel MozReview-Commit-ID: KSjIhu8I20C
dom/canvas/WebGLContext.cpp
gfx/gl/GLBlitHelper.cpp
gfx/gl/GLContext.cpp
gfx/gl/GLContext.h
gfx/gl/GLContextProviderGLX.cpp
gfx/gl/GLLibraryEGL.cpp
gfx/gl/GLReadTexImageHelper.cpp
--- a/dom/canvas/WebGLContext.cpp
+++ b/dom/canvas/WebGLContext.cpp
@@ -294,20 +294,19 @@ WebGLContext::DestroyResourcesAndContext
             continue;
 
         mExtensions[extension]->MarkLost();
         mExtensions[extension] = nullptr;
     }
 
     // We just got rid of everything, so the context had better
     // have been going away.
-#ifdef DEBUG
-    if (gl->DebugMode())
+    if (GLContext::ShouldSpew()) {
         printf_stderr("--- WebGL context destroyed: %p\n", gl.get());
-#endif
+    }
 
     gl = nullptr;
 }
 
 void
 WebGLContext::Invalidate()
 {
     if (!mCanvasElement)
@@ -956,20 +955,19 @@ WebGLContext::SetDimensions(int32_t sign
     if (!ResizeBackbuffer(width, height)) {
         Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_FAILURE_ID,
                               NS_LITERAL_CSTRING("FEATURE_FAILURE_WEBGL_RESIZE"));
         const nsLiteralCString text("Initializing WebGL backbuffer failed.");
         ThrowEvent_WebGLContextCreationError(text);
         return NS_ERROR_FAILURE;
     }
 
-#ifdef DEBUG
-    if (gl->DebugMode())
+    if (GLContext::ShouldSpew()) {
         printf_stderr("--- WebGL context created: %p\n", gl.get());
-#endif
+    }
 
     mResetLayer = true;
     mOptionsFrozen = true;
 
     // Update our internal stuff:
     if (gl->WorkAroundDriverBugs()) {
         if (!mOptions.alpha && gl->Caps().alpha)
             mNeedsFakeNoAlpha = true;
--- a/gfx/gl/GLBlitHelper.cpp
+++ b/gfx/gl/GLBlitHelper.cpp
@@ -324,17 +324,17 @@ GLBlitHelper::InitTexQuadProgram(BlitTyp
         mGL->fCompileShader(fragShader);
 
         program = mGL->fCreateProgram();
         mGL->fAttachShader(program, mTexBlit_VertShader);
         mGL->fAttachShader(program, fragShader);
         mGL->fBindAttribLocation(program, 0, "aPosition");
         mGL->fLinkProgram(program);
 
-        if (mGL->DebugMode()) {
+        if (GLContext::ShouldSpew()) {
             GLint status = 0;
             mGL->fGetShaderiv(mTexBlit_VertShader, LOCAL_GL_COMPILE_STATUS, &status);
             if (status != LOCAL_GL_TRUE) {
                 NS_ERROR("Vert shader compilation failed.");
 
                 GLint length = 0;
                 mGL->fGetShaderiv(mTexBlit_VertShader, LOCAL_GL_INFO_LOG_LENGTH, &length);
                 if (!length) {
@@ -367,17 +367,17 @@ GLBlitHelper::InitTexQuadProgram(BlitTyp
                 printf_stderr("Shader info log (%d bytes): %s\n", length, buffer.get());
                 break;
             }
         }
 
         GLint status = 0;
         mGL->fGetProgramiv(program, LOCAL_GL_LINK_STATUS, &status);
         if (status != LOCAL_GL_TRUE) {
-            if (mGL->DebugMode()) {
+            if (GLContext::ShouldSpew()) {
                 NS_ERROR("Linking blit program failed.");
                 GLint length = 0;
                 mGL->fGetProgramiv(program, LOCAL_GL_INFO_LOG_LENGTH, &length);
                 if (!length) {
                     printf_stderr("No program info log available.\n");
                     break;
                 }
 
--- a/gfx/gl/GLContext.cpp
+++ b/gfx/gl/GLContext.cpp
@@ -50,18 +50,16 @@ namespace gl {
 
 using namespace mozilla::gfx;
 using namespace mozilla::layers;
 
 #ifdef MOZ_GL_DEBUG
 unsigned GLContext::sCurrentGLContextTLS = -1;
 #endif
 
-uint32_t GLContext::sDebugMode = 0;
-
 // If adding defines, don't forget to undefine symbols. See #undef block below.
 #define CORE_SYMBOL(x) { (PRFuncPtr*) &mSymbols.f##x, { #x, nullptr } }
 #define CORE_EXT_SYMBOL2(x,y,z) { (PRFuncPtr*) &mSymbols.f##x, { #x, #x #y, #x #z, nullptr } }
 #define EXT_SYMBOL2(x,y,z) { (PRFuncPtr*) &mSymbols.f##x, { #x #y, #x #z, nullptr } }
 #define EXT_SYMBOL3(x,y,z,w) { (PRFuncPtr*) &mSymbols.f##x, { #x #y, #x #z, #x #w, nullptr } }
 #define END_SYMBOLS { nullptr, { nullptr } }
 
 // should match the order of GLExtensions, and be null-terminated.
@@ -395,26 +393,68 @@ ParseGLVersion(GLContext* gl, uint32_t* 
         MOZ_ASSERT(false, "Invalid minor version.");
         return false;
     }
 
     *out_version = (uint32_t)majorVersion * 100 + (uint32_t)minorVersion * 10;
     return true;
 }
 
+static uint8_t
+ChooseDebugFlags(CreateContextFlags createFlags)
+{
+    uint8_t debugFlags = 0;
+
+#ifdef MOZ_GL_DEBUG
+    if (gfxEnv::GlDebug()) {
+        debugFlags |= GLContext::DebugFlagEnabled;
+    }
+
+    // Enables extra verbose output, informing of the start and finish of every GL call.
+    // Useful e.g. to record information to investigate graphics system crashes/lockups
+    if (gfxEnv::GlDebugVerbose()) {
+        debugFlags |= GLContext::DebugFlagTrace;
+    }
+
+    // Aborts on GL error. Can be useful to debug quicker code that is known not to
+    // generate any GL error in principle.
+    bool abortOnError = false;
+
+    if (createFlags & CreateContextFlags::NO_VALIDATION) {
+        abortOnError = true;
+
+        const auto fnStringsMatch = [](const char* a, const char* b) {
+            return strcmp(a, b) == 0;
+        };
+
+        const char* envAbortOnError = PR_GetEnv("MOZ_GL_DEBUG_ABORT_ON_ERROR");
+        if (envAbortOnError && fnStringsMatch(envAbortOnError, "0")) {
+           abortOnError = false;
+        }
+    }
+
+    if (abortOnError) {
+        debugFlags |= GLContext::DebugFlagAbortOnError;
+    }
+#endif
+
+    return debugFlags;
+}
+
 GLContext::GLContext(CreateContextFlags flags, const SurfaceCaps& caps,
                      GLContext* sharedContext, bool isOffscreen)
   : mIsOffscreen(isOffscreen),
     mContextLost(false),
     mVersion(0),
     mProfile(ContextProfile::Unknown),
     mShadingLanguageVersion(0),
     mVendor(GLVendor::Other),
     mRenderer(GLRenderer::Other),
     mTopError(LOCAL_GL_NO_ERROR),
+    mDebugFlags(ChooseDebugFlags(flags)),
     mSharedContext(sharedContext),
     mCaps(caps),
     mScreen(nullptr),
     mLockedSurface(nullptr),
     mMaxTextureSize(0),
     mMaxCubeMapTextureSize(0),
     mMaxTextureImageSize(0),
     mMaxRenderbufferSize(0),
@@ -525,30 +565,16 @@ GLContext::LoadFeatureSymbols(const char
     return true;
 };
 
 bool
 GLContext::InitWithPrefixImpl(const char* prefix, bool trygl)
 {
     mWorkAroundDriverBugs = gfxPrefs::WorkAroundDriverBugs();
 
-#ifdef MOZ_GL_DEBUG
-    if (gfxEnv::GlDebug())
-        sDebugMode |= DebugEnabled;
-
-    // enables extra verbose output, informing of the start and finish of every GL call.
-    // useful e.g. to record information to investigate graphics system crashes/lockups
-    if (gfxEnv::GlDebugVerbose())
-        sDebugMode |= DebugTrace;
-
-    // aborts on GL error. Can be useful to debug quicker code that is known not to generate any GL error in principle.
-    if (gfxEnv::GlDebugAbortOnError())
-        sDebugMode |= DebugAbortOnError;
-#endif
-
     const SymLoadStruct coreSymbols[] = {
         { (PRFuncPtr*) &mSymbols.fActiveTexture, { "ActiveTexture", "ActiveTextureARB", nullptr } },
         { (PRFuncPtr*) &mSymbols.fAttachShader, { "AttachShader", "AttachShaderARB", nullptr } },
         { (PRFuncPtr*) &mSymbols.fBindAttribLocation, { "BindAttribLocation", "BindAttribLocationARB", nullptr } },
         { (PRFuncPtr*) &mSymbols.fBindBuffer, { "BindBuffer", "BindBufferARB", nullptr } },
         { (PRFuncPtr*) &mSymbols.fBindTexture, { "BindTexture", "BindTextureARB", nullptr } },
         { (PRFuncPtr*) &mSymbols.fBlendColor, { "BlendColor", nullptr } },
         { (PRFuncPtr*) &mSymbols.fBlendEquation, { "BlendEquation", nullptr } },
@@ -1045,17 +1071,17 @@ GLContext::InitWithPrefixImpl(const char
         mCaps.color = true;
         mCaps.alpha = false;
     }
 
     mTexGarbageBin = new TextureGarbageBin(this);
 
     MOZ_ASSERT(IsCurrent());
 
-    if (DebugMode() && IsExtensionSupported(KHR_debug)) {
+    if (ShouldSpew() && IsExtensionSupported(KHR_debug)) {
         fEnable(LOCAL_GL_DEBUG_OUTPUT);
         fDisable(LOCAL_GL_DEBUG_OUTPUT_SYNCHRONOUS);
         fDebugMessageCallback(&StaticDebugCallback, (void*)this);
         fDebugMessageControl(LOCAL_GL_DONT_CARE,
                              LOCAL_GL_DONT_CARE,
                              LOCAL_GL_DONT_CARE,
                              0, nullptr,
                              true);
@@ -1586,17 +1612,17 @@ GLContext::LoadMoreSymbols(const char* p
     }
 
     // Load developer symbols, don't fail if we can't find them.
     const SymLoadStruct devSymbols[] = {
             { (PRFuncPtr*) &mSymbols.fGetTexImage, { "GetTexImage", nullptr } },
             { (PRFuncPtr*) &mSymbols.fGetTexLevelParameteriv, { "GetTexLevelParameteriv", nullptr } },
             END_SYMBOLS
     };
-    const bool warnOnFailures = DebugMode();
+    const bool warnOnFailures = ShouldSpew();
     LoadSymbols(devSymbols, trygl, prefix, warnOnFailures);
 }
 
 #undef CORE_SYMBOL
 #undef CORE_EXT_SYMBOL2
 #undef EXT_SYMBOL2
 #undef EXT_SYMBOL3
 #undef END_SYMBOLS
@@ -2038,27 +2064,27 @@ GLContext::AssembleOffscreenFBs(const GL
 
     // We should be all resized.  Check for framebuffer completeness.
     GLenum status;
     bool isComplete = true;
 
     if (!IsFramebufferComplete(drawFB, &status)) {
         NS_WARNING("DrawFBO: Incomplete");
   #ifdef MOZ_GL_DEBUG
-        if (DebugMode()) {
+        if (ShouldSpew()) {
             printf_stderr("Framebuffer status: %X\n", status);
         }
   #endif
         isComplete = false;
     }
 
     if (!IsFramebufferComplete(readFB, &status)) {
         NS_WARNING("ReadFBO: Incomplete");
   #ifdef MOZ_GL_DEBUG
-        if (DebugMode()) {
+        if (ShouldSpew()) {
             printf_stderr("Framebuffer status: %X\n", status);
         }
   #endif
         isComplete = false;
     }
 
     if (drawFB_out) {
         *drawFB_out = drawFB;
--- a/gfx/gl/GLContext.h
+++ b/gfx/gl/GLContext.h
@@ -716,53 +716,54 @@ private:
 # else
 #  define MOZ_FUNCTION_NAME __func__  // defined in C99, supported in various C++ compilers. Just raw function name.
 # endif
 #endif
 
     void BeforeGLCall(const char* funcName) {
         MOZ_ASSERT(IsCurrent());
 
-        if (DebugMode()) {
+        if (mDebugFlags) {
             FlushErrors();
 
-            if (DebugMode() & DebugTrace)
+            if (mDebugFlags & DebugFlagTrace) {
                 printf_stderr("[gl:%p] > %s\n", this, funcName);
+            }
 
             GLContext* tlsContext = (GLContext*)PR_GetThreadPrivate(sCurrentGLContextTLS);
             if (this != tlsContext) {
                 printf_stderr("Fatal: %s called on non-current context %p. The"
                               " current context for this thread is %p.\n",
                               funcName, this, tlsContext);
                 MOZ_CRASH("GFX: GLContext is not current.");
             }
         }
     }
 
     void AfterGLCall(const char* funcName) {
-        if (DebugMode()) {
+        if (mDebugFlags) {
             // calling fFinish() immediately after every GL call makes sure that if this GL command crashes,
             // the stack trace will actually point to it. Otherwise, OpenGL being an asynchronous API, stack traces
             // tend to be meaningless
             mSymbols.fFinish();
             GLenum err = FlushErrors();
 
-            if (DebugMode() & DebugTrace) {
+            if (mDebugFlags & DebugFlagTrace) {
                 printf_stderr("[gl:%p] < %s [%s (0x%04x)]\n", this, funcName,
                               GLErrorToString(err), err);
             }
 
             if (err != LOCAL_GL_NO_ERROR &&
                 !mLocalErrorScopeStack.size())
             {
                 printf_stderr("[gl:%p] %s: Generated unexpected %s error."
                               " (0x%04x)\n", this, funcName,
                               GLErrorToString(err), err);
 
-                if (DebugMode() & DebugAbortOnError)
+                if (mDebugFlags & DebugFlagAbortOnError)
                     MOZ_CRASH("MOZ_GL_DEBUG_ABORT_ON_ERROR");
             }
         }
     }
 
     GLContext *TrackingContext()
     {
         GLContext *tip = this;
@@ -3347,45 +3348,37 @@ public:
                                  const char *extension);
 
     GLint GetMaxTextureImageSize() { return mMaxTextureImageSize; }
 
 public:
     std::map<GLuint, SharedSurface*> mFBOMapping;
 
     enum {
-        DebugEnabled = 1 << 0,
-        DebugTrace = 1 << 1,
-        DebugAbortOnError = 1 << 2
+        DebugFlagEnabled = 1 << 0,
+        DebugFlagTrace = 1 << 1,
+        DebugFlagAbortOnError = 1 << 2
     };
 
-    static uint32_t sDebugMode;
-
-    static uint32_t DebugMode() {
-#ifdef MOZ_GL_DEBUG
-        return sDebugMode;
-#else
-        return 0;
-#endif
-    }
+    const uint8_t mDebugFlags;
 
 protected:
     RefPtr<GLContext> mSharedContext;
 
     // The thread id which this context was created.
     PlatformThreadId mOwningThreadId;
 
     GLContextSymbols mSymbols;
 
 #ifdef MOZ_GL_DEBUG
-    // GLDebugMode will check that we don't send call
+    // Non-zero debug flags will check that we don't send call
     // to a GLContext that isn't current on the current
     // thread.
     // Store the current context when binding to thread local
-    // storage to support DebugMode on an arbitrary thread.
+    // storage to support debug flags on an arbitrary thread.
     static unsigned sCurrentGLContextTLS;
 #endif
 
     UniquePtr<GLBlitHelper> mBlitHelper;
     UniquePtr<GLReadTexImageHelper> mReadTexImageHelper;
 
 public:
     GLBlitHelper* BlitHelper();
--- a/gfx/gl/GLContextProviderGLX.cpp
+++ b/gfx/gl/GLContextProviderGLX.cpp
@@ -791,21 +791,19 @@ GLContextGLX::CreateGLContext(CreateCont
                   ContextProfile profile)
 {
     GLXLibrary& glx = sGLXLibrary;
 
     int db = 0;
     int err = glx.xGetFBConfigAttrib(display, cfg,
                                       LOCAL_GLX_DOUBLEBUFFER, &db);
     if (LOCAL_GLX_BAD_ATTRIBUTE != err) {
-#ifdef DEBUG
-        if (DebugMode()) {
+        if (ShouldSpew()) {
             printf("[GLX] FBConfig is %sdouble-buffered\n", db ? "" : "not ");
         }
-#endif
     }
 
     GLXContext context;
     RefPtr<GLContextGLX> glContext;
     bool error;
 
     ScopedXErrorHandler xErrorHandler;
 
--- a/gfx/gl/GLLibraryEGL.cpp
+++ b/gfx/gl/GLLibraryEGL.cpp
@@ -671,37 +671,43 @@ void
 GLLibraryEGL::DumpEGLConfigs()
 {
     int nc = 0;
     fGetConfigs(mEGLDisplay, nullptr, 0, &nc);
     EGLConfig *ec = new EGLConfig[nc];
     fGetConfigs(mEGLDisplay, ec, nc, &nc);
 
     for (int i = 0; i < nc; ++i) {
-        printf_stderr ("========= EGL Config %d ========\n", i);
+        printf_stderr("========= EGL Config %d ========\n", i);
         DumpEGLConfig(ec[i]);
     }
 
     delete [] ec;
 }
 
 #ifdef DEBUG
+static bool
+ShouldTrace()
+{
+    static bool ret = gfxEnv::GlDebugVerbose();
+    return ret;
+}
+
 /*static*/ void
 GLLibraryEGL::BeforeGLCall(const char* glFunction)
 {
-    if (GLContext::DebugMode()) {
-        if (GLContext::DebugMode() & GLContext::DebugTrace)
-            printf_stderr("[egl] > %s\n", glFunction);
+    if (ShouldTrace()) {
+        printf_stderr("[egl] > %s\n", glFunction);
     }
 }
 
 /*static*/ void
 GLLibraryEGL::AfterGLCall(const char* glFunction)
 {
-    if (GLContext::DebugMode() & GLContext::DebugTrace) {
+    if (ShouldTrace()) {
         printf_stderr("[egl] < %s\n", glFunction);
     }
 }
 #endif
 
 } /* namespace gl */
 } /* namespace mozilla */
 
--- a/gfx/gl/GLReadTexImageHelper.cpp
+++ b/gfx/gl/GLReadTexImageHelper.cpp
@@ -327,17 +327,17 @@ ReadPixelsIntoDataSurface(GLContext* gl,
     DataSourceSurface* readSurf = dest;
     int readAlignment = GuessAlignment(dest->GetSize().width,
                                        destPixelSize,
                                        dest->Stride());
     if (!readAlignment) {
         needsTempSurf = true;
     }
     if (needsTempSurf) {
-        if (gl->DebugMode()) {
+        if (GLContext::ShouldSpew()) {
             NS_WARNING("Needing intermediary surface for ReadPixels. This will be slow!");
         }
         SurfaceFormat readFormatGFX;
 
         switch (readFormat) {
             case LOCAL_GL_RGBA: {
                 readFormatGFX = hasAlpha ? SurfaceFormat::R8G8B8A8
                                          : SurfaceFormat::R8G8B8X8;