From 2866aaced4ad01b5e40ea3c08d265e252a3546d5 Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Wed, 2 Mar 2011 15:50:36 -0500 Subject: [PATCH] Bug 627464 - Annotate crash reports if the forced-enabled prefs are set - r=jrmuizel, a=joe --- content/canvas/src/WebGLContext.cpp | 5 + gfx/layers/d3d10/LayerManagerD3D10.cpp | 5 + gfx/layers/d3d9/LayerManagerD3D9.cpp | 5 + gfx/layers/opengl/LayerManagerOGL.cpp | 5 + gfx/src/Makefile.in | 4 +- gfx/src/gfxCrashReporterUtils.cpp | 125 +++++++++++++++++++++++++ gfx/src/gfxCrashReporterUtils.h | 75 +++++++++++++++ gfx/thebes/GLContext.cpp | 14 ++- gfx/thebes/GLContextProviderEGL.cpp | 5 + gfx/thebes/GLContextProviderGLX.cpp | 14 ++- gfx/thebes/GLContextProviderOSMesa.cpp | 2 + gfx/thebes/GLContextProviderWGL.cpp | 5 + gfx/thebes/gfxWindowsPlatform.cpp | 11 +++ 13 files changed, 268 insertions(+), 7 deletions(-) create mode 100644 gfx/src/gfxCrashReporterUtils.cpp create mode 100644 gfx/src/gfxCrashReporterUtils.h diff --git a/content/canvas/src/WebGLContext.cpp b/content/canvas/src/WebGLContext.cpp index 5f6948ce1b3c..1b3c7c26c178 100644 --- a/content/canvas/src/WebGLContext.cpp +++ b/content/canvas/src/WebGLContext.cpp @@ -61,6 +61,8 @@ #include "GLContextProvider.h" +#include "gfxCrashReporterUtils.h" + #ifdef MOZ_SVG #include "nsSVGEffects.h" #endif @@ -349,6 +351,8 @@ WebGLContext::SetContextOptions(nsIPropertyBag *aOptions) NS_IMETHODIMP WebGLContext::SetDimensions(PRInt32 width, PRInt32 height) { + ScopedGfxFeatureReporter reporter("WebGL"); + if (mWidth == width && mHeight == height) return NS_OK; @@ -527,6 +531,7 @@ WebGLContext::SetDimensions(PRInt32 width, PRInt32 height) gl->fClearStencil(0); gl->fClear(LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT | LOCAL_GL_STENCIL_BUFFER_BIT); + reporter.SetSuccessful(); return NS_OK; } diff --git a/gfx/layers/d3d10/LayerManagerD3D10.cpp b/gfx/layers/d3d10/LayerManagerD3D10.cpp index a880bd9ad7fe..c7a25a67acc0 100644 --- a/gfx/layers/d3d10/LayerManagerD3D10.cpp +++ b/gfx/layers/d3d10/LayerManagerD3D10.cpp @@ -52,6 +52,8 @@ #include "../d3d9/Nv3DVUtils.h" +#include "gfxCrashReporterUtils.h" + namespace mozilla { namespace layers { @@ -119,6 +121,8 @@ LayerManagerD3D10::~LayerManagerD3D10() bool LayerManagerD3D10::Initialize() { + ScopedGfxFeatureReporter reporter("D3D10 Layers"); + HRESULT hr; /* Create an Nv3DVUtils instance */ @@ -270,6 +274,7 @@ LayerManagerD3D10::Initialize() // We need this because we don't want DXGI to respond to Alt+Enter. dxgiFactory->MakeWindowAssociation(swapDesc.OutputWindow, DXGI_MWA_NO_WINDOW_CHANGES); + reporter.SetSuccessful(); return true; } diff --git a/gfx/layers/d3d9/LayerManagerD3D9.cpp b/gfx/layers/d3d9/LayerManagerD3D9.cpp index f23b2803b4d1..80aa7c123678 100644 --- a/gfx/layers/d3d9/LayerManagerD3D9.cpp +++ b/gfx/layers/d3d9/LayerManagerD3D9.cpp @@ -50,6 +50,8 @@ #include "nsIPrefBranch2.h" #include "gfxFailure.h" +#include "gfxCrashReporterUtils.h" + namespace mozilla { namespace layers { @@ -71,6 +73,8 @@ LayerManagerD3D9::~LayerManagerD3D9() PRBool LayerManagerD3D9::Initialize() { + ScopedGfxFeatureReporter reporter("D3D9 Layers"); + nsCOMPtr prefs = do_GetService(NS_PREFSERVICE_CONTRACTID); /* XXX: this preference and blacklist code should move out of the layer manager */ @@ -113,6 +117,7 @@ LayerManagerD3D9::Initialize() return PR_FALSE; } + reporter.SetSuccessful(); return PR_TRUE; } diff --git a/gfx/layers/opengl/LayerManagerOGL.cpp b/gfx/layers/opengl/LayerManagerOGL.cpp index a3fdcb296f73..5e8401ed6be5 100644 --- a/gfx/layers/opengl/LayerManagerOGL.cpp +++ b/gfx/layers/opengl/LayerManagerOGL.cpp @@ -61,6 +61,8 @@ #include "nsIPrefService.h" #include "nsIPrefBranch2.h" +#include "gfxCrashReporterUtils.h" + namespace mozilla { namespace layers { @@ -172,6 +174,8 @@ LayerManagerOGL::CreateContext() PRBool LayerManagerOGL::Initialize(nsRefPtr aContext) { + ScopedGfxFeatureReporter reporter("GL Layers"); + // Do not allow double intiailization NS_ABORT_IF_FALSE(mGLContext == nsnull, "Don't reiniailize layer managers"); @@ -354,6 +358,7 @@ LayerManagerOGL::Initialize(nsRefPtr aContext) console->LogStringMessage(msg.get()); } + reporter.SetSuccessful(); return true; } diff --git a/gfx/src/Makefile.in b/gfx/src/Makefile.in index 8c83a5cce7fe..b05b1cd57f27 100644 --- a/gfx/src/Makefile.in +++ b/gfx/src/Makefile.in @@ -75,6 +75,7 @@ EXPORTS = \ nsIRegion.h \ nsITheme.h \ nsThemeConstants.h \ + gfxCrashReporterUtils.h \ $(NULL) ifdef MOZ_X11 @@ -89,7 +90,8 @@ CPPSRCS = \ nsRegion.cpp \ nsTransform2D.cpp \ nsScriptableRegion.cpp \ - $(NULL) + gfxCrashReporterUtils.cpp \ + $(NULL) EXTRA_DSO_LDOPTS = \ $(MOZ_UNICHARUTIL_LIBS) \ diff --git a/gfx/src/gfxCrashReporterUtils.cpp b/gfx/src/gfxCrashReporterUtils.cpp new file mode 100644 index 000000000000..874675cca94d --- /dev/null +++ b/gfx/src/gfxCrashReporterUtils.cpp @@ -0,0 +1,125 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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 Corporation code. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "gfxCrashReporterUtils.h" + +#if defined(MOZ_CRASHREPORTER) && defined(MOZ_ENABLE_LIBXUL) +#define MOZ_GFXFEATUREREPORTER 1 +#endif + +#ifdef MOZ_GFXFEATUREREPORTER +#include "nsExceptionHandler.h" +#include "nsString.h" +#include "nsIObserverService.h" +#include "nsIObserver.h" +#include "nsAutoPtr.h" +#include "nsServiceManagerUtils.h" +#include "mozilla/Services.h" + +namespace mozilla { + +static nsTArray *gFeaturesAlreadyReported = nsnull; + +class ObserverToDestroyFeaturesAlreadyReported : public nsIObserver +{ + +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIOBSERVER + + ObserverToDestroyFeaturesAlreadyReported() {} + virtual ~ObserverToDestroyFeaturesAlreadyReported() {} +}; + +NS_IMPL_ISUPPORTS1(ObserverToDestroyFeaturesAlreadyReported, + nsIObserver) + +NS_IMETHODIMP +ObserverToDestroyFeaturesAlreadyReported::Observe(nsISupports* aSubject, + const char* aTopic, + const PRUnichar* aData) +{ + if (!strcmp(aTopic, "xpcom-shutdown")) { + if (gFeaturesAlreadyReported) { + delete gFeaturesAlreadyReported; + gFeaturesAlreadyReported = nsnull; + } + } + return NS_OK; +} + + +void +ScopedGfxFeatureReporter::WriteAppNote(char statusChar) +{ + // LeakLog made me do this. Basically, I just wanted gFeaturesAlreadyReported to be a static nsTArray, + // and LeakLog was complaining about leaks like this: + // leaked 1 instance of nsTArray_base with size 8 bytes + // leaked 7 instances of nsStringBuffer with size 8 bytes each (56 bytes total) + // So this is a work-around using a pointer, and using a nsIObserver to deallocate on xpcom shutdown. + // Yay for fighting bloat. + if (!gFeaturesAlreadyReported) { + nsCOMPtr observerService = mozilla::services::GetObserverService(); + if (!observerService) + return; + nsRefPtr observer = new ObserverToDestroyFeaturesAlreadyReported; + nsresult rv = observerService->AddObserver(observer, "xpcom-shutdown", PR_FALSE); + if (NS_FAILED(rv)) { + observer = nsnull; + return; + } + gFeaturesAlreadyReported = new nsTArray; + } + + nsCAutoString featureString; + featureString.AppendPrintf("%s%c%c", + mFeature, + statusChar, + statusChar == '?' ? ' ' : '\n'); + + if (!gFeaturesAlreadyReported->Contains(featureString)) { + gFeaturesAlreadyReported->AppendElement(featureString); + CrashReporter::AppendAppNotesToCrashReport(featureString); + } +} + +} // end namespace mozilla + +#else + +namespace mozilla { +void ScopedGfxFeatureReporter::WriteAppNote(char) {} +} + +#endif diff --git a/gfx/src/gfxCrashReporterUtils.h b/gfx/src/gfxCrashReporterUtils.h new file mode 100644 index 000000000000..87a3a742e248 --- /dev/null +++ b/gfx/src/gfxCrashReporterUtils.h @@ -0,0 +1,75 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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 Corporation code. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifndef gfxCrashReporterUtils_h__ +#define gfxCrashReporterUtils_h__ + +#include "gfxCore.h" + +namespace mozilla { + +/** \class ScopedGfxFeatureReporter + * + * On creation, adds "FeatureName?" to AppNotes + * On destruction, adds "FeatureName-", or "FeatureName+" if you called SetSuccessful(). + * + * Any such string is added at most once to AppNotes, and is subsequently skipped. + * + * This ScopedGfxFeatureReporter class is designed to be fool-proof to use in functions that + * have many exit points. We don't want to encourage having function with many exit points. + * It just happens that our graphics features initialization functions are like that. + */ +class NS_GFX ScopedGfxFeatureReporter +{ +public: + ScopedGfxFeatureReporter(const char *aFeature) : mFeature(aFeature), mStatusChar('-') + { + WriteAppNote('?'); + } + ~ScopedGfxFeatureReporter() { + WriteAppNote(mStatusChar); + } + void SetSuccessful() { mStatusChar = '+'; } + +protected: + const char *mFeature; + char mStatusChar; + +private: + void WriteAppNote(char statusChar); +}; + +} // end namespace mozilla + +#endif // gfxCrashReporterUtils_h__ diff --git a/gfx/thebes/GLContext.cpp b/gfx/thebes/GLContext.cpp index c0036e7a16c6..a351b71a7f80 100644 --- a/gfx/thebes/GLContext.cpp +++ b/gfx/thebes/GLContext.cpp @@ -51,6 +51,8 @@ #include "GLContext.h" #include "GLContextProvider.h" +#include "gfxCrashReporterUtils.h" + namespace mozilla { namespace gl { @@ -162,7 +164,10 @@ LibrarySymbolLoader::LoadSymbols(PRLibrary *lib, PRBool GLContext::InitWithPrefix(const char *prefix, PRBool trygl) { + ScopedGfxFeatureReporter reporter("GL Context"); + if (mInitialized) { + reporter.SetSuccessful(); return PR_TRUE; } @@ -396,9 +401,12 @@ GLContext::InitWithPrefix(const char *prefix, PRBool trygl) mDebugMode |= DebugAbortOnError; #endif - // if initialization fails, ensure all symbols are zero, to avoid hard-to-understand bugs - if (!mInitialized) - mSymbols.Zero(); + if (mInitialized) + reporter.SetSuccessful(); + else { + // if initialization fails, ensure all symbols are zero, to avoid hard-to-understand bugs + mSymbols.Zero(); + } return mInitialized; } diff --git a/gfx/thebes/GLContextProviderEGL.cpp b/gfx/thebes/GLContextProviderEGL.cpp index 039b5e798f35..3a85f234b2c9 100644 --- a/gfx/thebes/GLContextProviderEGL.cpp +++ b/gfx/thebes/GLContextProviderEGL.cpp @@ -149,6 +149,8 @@ public: #include "nsIWidget.h" +#include "gfxCrashReporterUtils.h" + #ifdef MOZ_PLATFORM_MAEMO static bool gUseBackingSurface = true; #else @@ -310,6 +312,8 @@ public: return PR_TRUE; } + mozilla::ScopedGfxFeatureReporter reporter("EGL"); + #ifdef XP_WIN // Allow for explicitly specifying the location of libEGL.dll and // libGLESv2.dll. @@ -487,6 +491,7 @@ public: } mInitialized = PR_TRUE; + reporter.SetSuccessful(); return PR_TRUE; } diff --git a/gfx/thebes/GLContextProviderGLX.cpp b/gfx/thebes/GLContextProviderGLX.cpp index 3cf4d21e1037..a13649ce7b60 100644 --- a/gfx/thebes/GLContextProviderGLX.cpp +++ b/gfx/thebes/GLContextProviderGLX.cpp @@ -60,6 +60,8 @@ #include "gfxPlatform.h" #include "GLContext.h" +#include "gfxCrashReporterUtils.h" + namespace mozilla { namespace gl { @@ -96,11 +98,17 @@ GLXLibrary::EnsureInitialized() mTriedInitializing = PR_TRUE; if (!mOGLLibrary) { - mOGLLibrary = PR_LoadLibrary("libGL.so.1"); + // see e.g. bug 608526: it is intrinsically interesting to know whether we have dynamically linked to libGL.so.1 + // because at least the NVIDIA implementation requires an executable stack, which causes mprotect calls, + // which trigger glibc bug http://sourceware.org/bugzilla/show_bug.cgi?id=12225 + const char *libGLfilename = "libGL.so.1"; + ScopedGfxFeatureReporter reporter(libGLfilename); + mOGLLibrary = PR_LoadLibrary(libGLfilename); if (!mOGLLibrary) { - NS_WARNING("Couldn't load OpenGL shared library."); - return PR_FALSE; + NS_WARNING("Couldn't load OpenGL shared library."); + return PR_FALSE; } + reporter.SetSuccessful(); } LibrarySymbolLoader::SymLoadStruct symbols[] = { diff --git a/gfx/thebes/GLContextProviderOSMesa.cpp b/gfx/thebes/GLContextProviderOSMesa.cpp index c10bf6bff09a..1f48c569b55a 100644 --- a/gfx/thebes/GLContextProviderOSMesa.cpp +++ b/gfx/thebes/GLContextProviderOSMesa.cpp @@ -47,6 +47,8 @@ #include "gfxASurface.h" #include "gfxImageSurface.h" +#include "gfxCrashReporterUtils.h" + // from GL/osmesa.h. We don't include that file so as to avoid having a build-time dependency on OSMesa. #define OSMESA_RGBA GL_RGBA #define OSMESA_BGRA 0x1 diff --git a/gfx/thebes/GLContextProviderWGL.cpp b/gfx/thebes/GLContextProviderWGL.cpp index 9fa7b9c9c890..411534a300de 100644 --- a/gfx/thebes/GLContextProviderWGL.cpp +++ b/gfx/thebes/GLContextProviderWGL.cpp @@ -44,6 +44,8 @@ #include "gfxPlatform.h" #include "gfxWindowsSurface.h" +#include "gfxCrashReporterUtils.h" + #include "prenv.h" namespace mozilla { @@ -124,6 +126,8 @@ WGLLibrary::EnsureInitialized() if (mInitialized) return PR_TRUE; + mozilla::ScopedGfxFeatureReporter reporter("WGL"); + if (!mOGLLibrary) { mOGLLibrary = PR_LoadLibrary("Opengl32.dll"); if (!mOGLLibrary) { @@ -212,6 +216,7 @@ WGLLibrary::EnsureInitialized() return PR_FALSE; } + reporter.SetSuccessful(); return PR_TRUE; } diff --git a/gfx/thebes/gfxWindowsPlatform.cpp b/gfx/thebes/gfxWindowsPlatform.cpp index eb9217904ed5..1c51d2c04ed0 100644 --- a/gfx/thebes/gfxWindowsPlatform.cpp +++ b/gfx/thebes/gfxWindowsPlatform.cpp @@ -58,6 +58,8 @@ #include "nsIGfxInfo.h" +#include "gfxCrashReporterUtils.h" + #ifdef MOZ_FT2_FONTS #include "ft2build.h" #include FT_FREETYPE_H @@ -326,6 +328,7 @@ gfxWindowsPlatform::UpdateRenderMode() // Enable when it's preffed on -and- we're using Vista or higher. Or when // we're going to use D2D. if (!mDWriteFactory && (mUseDirectWrite && isVistaOrHigher)) { + mozilla::ScopedGfxFeatureReporter reporter("DWrite"); DWriteCreateFactoryFunc createDWriteFactory = (DWriteCreateFactoryFunc) GetProcAddress(LoadLibraryW(L"dwrite.dll"), "DWriteCreateFactory"); @@ -342,6 +345,9 @@ gfxWindowsPlatform::UpdateRenderMode() reinterpret_cast(&factory)); mDWriteFactory = factory; factory->Release(); + + if (hr == S_OK) + reporter.SetSuccessful(); } } #endif @@ -360,6 +366,8 @@ gfxWindowsPlatform::VerifyD2DDevice(PRBool aAttemptForce) mD2DDevice = nsnull; } + mozilla::ScopedGfxFeatureReporter reporter("D2D"); + HMODULE d3d10module = LoadLibraryA("d3d10_1.dll"); D3D10CreateDevice1Func createD3DDevice = (D3D10CreateDevice1Func) GetProcAddress(d3d10module, "D3D10CreateDevice1"); @@ -405,6 +413,9 @@ gfxWindowsPlatform::VerifyD2DDevice(PRBool aAttemptForce) if (!mD2DDevice && aAttemptForce) { mD2DDevice = cairo_d2d_create_device(); } + + if (mD2DDevice) + reporter.SetSuccessful(); #endif }