Bug 595277 - Part 4: Delay Direct3D 9 initialization when possible. r=roc a=blocking-final
authorBas Schouten <bschouten@mozilla.com>
Tue, 07 Dec 2010 03:06:31 +0100
changeset 58814 aa593835cb8de54a6250539a96f58239b8e18ceb
parent 58813 a54c3af4c33d75d739ad9a56043460def6d99e5e
child 58876 a89f24bf179869eab5697ac82c0c42b626d87e4c
push id17439
push userbschouten@mozilla.com
push dateWed, 08 Dec 2010 02:25:42 +0000
treeherdermozilla-central@aa593835cb8d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc, blocking-final
bugs595277
milestone2.0b8pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 595277 - Part 4: Delay Direct3D 9 initialization when possible. r=roc a=blocking-final
widget/src/windows/nsToolkit.cpp
widget/src/windows/nsToolkit.h
widget/src/windows/nsWindow.cpp
widget/src/windows/nsWindow.h
--- a/widget/src/windows/nsToolkit.cpp
+++ b/widget/src/windows/nsToolkit.cpp
@@ -64,16 +64,24 @@ NS_IMPL_ISUPPORTS1(nsToolkit, nsIToolkit
 //
 static PRUintn gToolkitTLSIndex = 0;
 
 
 HINSTANCE nsToolkit::mDllInstance = 0;
 PRBool    nsToolkit::mIsWinXP     = PR_FALSE;
 static PRBool dummy = nsToolkit::InitVersionInfo();
 
+static const unsigned long kD3DUsageDelay = 5000;
+
+static void
+StartAllowingD3D9(nsITimer *aTimer, void *aClosure)
+{
+  nsWindow::StartAllowingD3D9(true);
+}
+
 #if !defined(MOZ_STATIC_COMPONENT_LIBS) && !defined(MOZ_ENABLE_LIBXUL)
 //
 // Dll entry point. Keep the dll instance
 //
 
 #if defined(__GNUC__)
 // If DllMain gets name mangled, it won't be seen.
 extern "C" {
@@ -234,16 +242,24 @@ void
 nsToolkit::Shutdown()
 {
     // Crashes on certain XP machines/profiles - see bug 448104 for details
     //nsUXThemeData::Teardown();
     //VERIFY(::UnregisterClass("nsToolkitClass", nsToolkit::mDllInstance));
     ::UnregisterClassW(L"nsToolkitClass", nsToolkit::mDllInstance);
 }
 
+void
+nsToolkit::StartAllowingD3D9()
+{
+  nsIToolkit *toolkit;
+  NS_GetCurrentToolkit(&toolkit);
+  static_cast<nsToolkit*>(toolkit)->mD3D9Timer->Cancel();
+  nsWindow::StartAllowingD3D9(false);
+}
 
 //-------------------------------------------------------------------------
 //
 // Register the window class for the internal window and create the window
 //
 //-------------------------------------------------------------------------
 void nsToolkit::CreateInternalWindow(PRThread *aThread)
 {
@@ -314,16 +330,22 @@ NS_METHOD nsToolkit::Init(PRThread *aThr
     // If no thread is provided create one
     if (NULL != aThread) {
         CreateInternalWindow(aThread);
     } else {
         // create a thread where the message pump will run
         CreateUIThread();
     }
 
+    mD3D9Timer = do_CreateInstance("@mozilla.org/timer;1");
+    mD3D9Timer->InitWithFuncCallback(::StartAllowingD3D9,
+                                     NULL,
+                                     kD3DUsageDelay,
+                                     nsITimer::TYPE_ONE_SHOT);
+
     nsWidgetAtoms::RegisterAtoms();
 
     return NS_OK;
 }
 
 //-------------------------------------------------------------------------
 //
 // nsToolkit WindowProc. Used to call methods on the "main GUI thread"...
--- a/widget/src/windows/nsToolkit.h
+++ b/widget/src/windows/nsToolkit.h
@@ -95,25 +95,27 @@ public:
                                         WPARAM WParam, 
                                         LPARAM lParam);
 
 protected:
     // Handle of the window used to receive dispatch messages.
     HWND        mDispatchWnd;
     // Thread Id of the "main" Gui thread.
     PRThread    *mGuiThread;
+    nsCOMPtr<nsITimer> mD3D9Timer;
 
 public:
     static HINSTANCE mDllInstance;
     // OS flag
     static PRBool    mIsWinXP;
 
     static PRBool InitVersionInfo();
     static void Startup(HINSTANCE hModule);
     static void Shutdown();
+    static void StartAllowingD3D9();
 
     static MouseTrailer *gMouseTrailer;
 };
 
 class  nsWindow;
 
 /**
  * Makes sure exit/enter mouse messages are always dispatched.
--- a/widget/src/windows/nsWindow.cpp
+++ b/widget/src/windows/nsWindow.cpp
@@ -154,16 +154,18 @@
 #include "nsXPIDLString.h"
 #include "nsWidgetsCID.h"
 #include "nsTHashtable.h"
 #include "nsHashKeys.h"
 #include "nsString.h"
 #include "mozilla/Services.h"
 #include "nsNativeThemeWin.h"
 #include "nsWindowsDllInterceptor.h"
+#include "nsIWindowMediator.h"
+#include "nsIServiceManager.h"
 
 #if defined(WINCE)
 #include "nsWindowCE.h"
 #endif
 
 #if defined(WINCE_WINDOWS_MOBILE)
 #define KILL_PRIORITY_ID 2444
 #endif
@@ -291,16 +293,18 @@ BYTE            nsWindow::sLastMouseButt
 // Trim heap on minimize. (initialized, but still true.)
 int             nsWindow::sTrimOnMinimize         = 2;
 
 // Default value for Trackpoint hack (used when the pref is set to -1).
 PRBool          nsWindow::sDefaultTrackPointHack  = PR_FALSE;
 // Default value for general window class (used when the pref is the empty string).
 const char*     nsWindow::sDefaultMainWindowClass = kClassNameGeneral;
 
+// If we're using D3D9, this will not be allowed during initial 5 seconds.
+bool            nsWindow::sAllowD3D9              = false;
 
 #ifdef ACCESSIBILITY
 BOOL            nsWindow::sIsAccessibilityOn      = FALSE;
 // Accessibility wm_getobject handler
 HINSTANCE       nsWindow::sAccLib                 = 0;
 LPFNLRESULTFROMOBJECT 
                 nsWindow::sLresultFromObject      = 0;
 #endif // ACCESSIBILITY
@@ -3227,17 +3231,22 @@ nsWindow::GetLayerManager(LayerManagerPe
       {
         mLayerManager->Destroy();
         mLayerManager = nsnull;
       }
     }
   }
 #endif
 
-  if (!mLayerManager) {
+  if (!mLayerManager ||
+      (!sAllowD3D9 && aPersistence == LAYER_MANAGER_PERSISTENT &&
+        mLayerManager->GetBackendType() == 
+        mozilla::layers::LayerManager::LAYERS_BASIC)) {
+    // If D3D9 is not currently allowed but the permanent manager is required,
+    // -and- we're currently using basic layers, run through this check.
     nsCOMPtr<nsIPrefBranch2> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
 
     PRBool accelerateByDefault = PR_TRUE;
     PRBool disableAcceleration = PR_FALSE;
     PRBool preferOpenGL = PR_FALSE;
     PRBool preferD3D9 = PR_FALSE;
     if (prefs) {
       prefs->GetBoolPref("layers.accelerate-all",
@@ -3266,27 +3275,33 @@ nsWindow::GetLayerManager(LayerManagerPe
       xr->GetInSafeMode(&safeMode);
 
     if (disableAcceleration || safeMode)
       mUseAcceleratedRendering = PR_FALSE;
     else if (accelerateByDefault)
       mUseAcceleratedRendering = PR_TRUE;
 
     if (mUseAcceleratedRendering) {
+      if (aPersistence == LAYER_MANAGER_PERSISTENT && !sAllowD3D9) {
+        // This will clear out our existing layer manager if we have one since
+        // if we hit this with a LayerManager we're always using BasicLayers.
+        nsToolkit::StartAllowingD3D9();
+      }
+
 #ifdef MOZ_ENABLE_D3D10_LAYER
       if (!preferD3D9) {
         nsRefPtr<mozilla::layers::LayerManagerD3D10> layerManager =
           new mozilla::layers::LayerManagerD3D10(this);
         if (layerManager->Initialize()) {
           mLayerManager = layerManager;
         }
       }
 #endif
 #ifdef MOZ_ENABLE_D3D9_LAYER
-      if (!preferOpenGL && !mLayerManager) {
+      if (!preferOpenGL && !mLayerManager && sAllowD3D9) {
         nsRefPtr<mozilla::layers::LayerManagerD3D9> layerManager =
           new mozilla::layers::LayerManagerD3D9(this);
         if (layerManager->Initialize()) {
           mLayerManager = layerManager;
         }
       }
 #endif
       if (!mLayerManager && preferOpenGL) {
@@ -7518,16 +7533,47 @@ PRBool nsWindow::OnScroll(UINT aMsg, WPA
 }
 
 // Can be overriden. Controls auto-erase of background.
 PRBool nsWindow::AutoErase(HDC dc)
 {
   return PR_FALSE;
 }
 
+void
+nsWindow::AllowD3D9Callback(nsWindow *aWindow)
+{
+  if (aWindow->mLayerManager) {
+    aWindow->mLayerManager->Destroy();
+    aWindow->mLayerManager = NULL;
+  }
+}
+
+void
+nsWindow::AllowD3D9WithReinitializeCallback(nsWindow *aWindow)
+{
+  if (aWindow->mLayerManager) {
+    aWindow->mLayerManager->Destroy();
+    aWindow->mLayerManager = NULL;
+    (void) aWindow->GetLayerManager();
+  }
+}
+
+void
+nsWindow::StartAllowingD3D9(bool aReinitialize)
+{
+  sAllowD3D9 = true;
+
+  if (aReinitialize) {
+    EnumAllWindows(AllowD3D9WithReinitializeCallback);
+  } else {
+    EnumAllWindows(AllowD3D9Callback);
+  }
+}
+
 /**************************************************************
  **************************************************************
  **
  ** BLOCK: IME management and accessibility
  **
  ** Handles managing IME input and accessibility.
  **
  **************************************************************
--- a/widget/src/windows/nsWindow.h
+++ b/widget/src/windows/nsWindow.h
@@ -54,16 +54,17 @@
 #include "nsdefs.h"
 #include "nsIdleService.h"
 #include "nsToolkit.h"
 #include "nsString.h"
 #include "nsTArray.h"
 #include "gfxWindowsSurface.h"
 #include "nsWindowDbg.h"
 #include "cairo.h"
+#include "nsITimer.h"
 #ifdef CAIRO_HAS_D2D_SURFACE
 #include "gfxD2DSurface.h"
 #endif
 
 #if !defined(WINCE)
 #include "nsWinGesture.h"
 #endif
 
@@ -254,16 +255,25 @@ public:
   /**
    * Misc.
    */
   virtual PRBool          AutoErase(HDC dc);
   nsIntPoint*             GetLastPoint() { return &mLastPoint; }
   // needed in nsIMM32Handler.cpp
   PRBool                  PluginHasFocus() { return mIMEContext.mStatus == nsIWidget::IME_STATUS_PLUGIN; }
   PRBool                  IsTopLevelWidget() { return mIsTopWidgetWindow; }
+  /**
+   * Start allowing Direct3D9 to be used by widgets when GetLayerManager is
+   * called.
+   *
+   * @param aReinitialize Call GetLayerManager on widgets to ensure D3D9 is
+   *                      initialized, this is usually called when this function
+   *                      is triggered by timeout and not user/web interaction.
+   */
+  static void             StartAllowingD3D9(bool aReinitialize);
 
 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
   PRBool HasTaskbarIconBeenCreated() { return mHasTaskbarIconBeenCreated; }
   // Called when either the nsWindow or an nsITaskbarTabPreview receives the noticiation that this window
   // has its icon placed on the taskbar.
   void SetHasTaskbarIconBeenCreated(PRBool created = PR_TRUE) { mHasTaskbarIconBeenCreated = created; }
 
   // Getter/setter for the nsITaskbarWindowPreview for this nsWindow
@@ -292,16 +302,18 @@ protected:
 #endif
   static LRESULT CALLBACK MozSpecialMsgFilter(int code, WPARAM wParam, LPARAM lParam);
   static LRESULT CALLBACK MozSpecialWndProc(int code, WPARAM wParam, LPARAM lParam);
   static LRESULT CALLBACK MozSpecialMouseProc(int code, WPARAM wParam, LPARAM lParam);
   static VOID    CALLBACK HookTimerForPopups( HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime );
   static BOOL    CALLBACK ClearResourcesCallback(HWND aChild, LPARAM aParam);
   static BOOL    CALLBACK EnumAllChildWindProc(HWND aWnd, LPARAM aParam);
   static BOOL    CALLBACK EnumAllThreadWindowProc(HWND aWnd, LPARAM aParam);
+  static void             AllowD3D9Callback(nsWindow *aWindow);
+  static void             AllowD3D9WithReinitializeCallback(nsWindow *aWindow);
 
   /**
    * Window utilities
    */
   static BOOL             SetNSWindowPtr(HWND aWnd, nsWindow * ptr);
   LPARAM                  lParamToScreen(LPARAM lParam);
   LPARAM                  lParamToClient(LPARAM lParam);
   virtual void            SubclassWindow(BOOL bState);
@@ -499,16 +511,17 @@ protected:
   static HCURSOR        sHCursor;
   static imgIContainer* sCursorImgContainer;
   static PRBool         sSwitchKeyboardLayout;
   static PRBool         sJustGotDeactivate;
   static PRBool         sJustGotActivate;
   static int            sTrimOnMinimize;
   static PRBool         sDefaultTrackPointHack;
   static const char*    sDefaultMainWindowClass;
+  static bool           sAllowD3D9;
 #ifdef MOZ_IPC
   static PRUint32       sOOPPPluginFocusEvent;
 #endif
 
   // Non-client margin settings
   // Pre-calculated outward offset applied to default frames
   nsIntMargin           mNonClientOffset;
   // Margins set by the owner