Bug 595277 - Part 4: Delay Direct3D 9 usage when possible. r=roc a=blocking-final
authorBas Schouten <bschouten@mozilla.com>
Tue, 07 Dec 2010 03:06:31 +0100
changeset 58741 b4178761c42e93669af892a176d6a16643ba4278
parent 58740 558125e5f84fd99eb26f975e9191b0b34baf0ae3
child 58742 a99f870ea8b7c9333d6b417280a26cdc87991418
child 58753 3054bd366ed614984163c80e5e537053049b76b8
push id1
push usershaver@mozilla.com
push dateTue, 04 Jan 2011 17:58:04 +0000
reviewersroc, blocking-final
bugs595277
milestone2.0b8pre
Bug 595277 - Part 4: Delay Direct3D 9 usage 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
@@ -3226,17 +3230,22 @@ nsWindow::GetLayerManager(LayerManagerPe
           gfxWindowsPlatform::GetPlatform()->GetD3D10Device())
       {
         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",
@@ -3265,27 +3274,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) {
@@ -7517,16 +7532,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