From 91dc0db35ce132b5b6e80d61ef301a7ace3f1671 Mon Sep 17 00:00:00 2001 From: Kevin Chen Date: Tue, 18 Jul 2017 23:09:00 -0400 Subject: [PATCH] Bug 1364563 - Add a path for content process only device reset. r=dvander --- gfx/ipc/GraphicsMessages.ipdlh | 1 + gfx/layers/client/ClientLayerManager.cpp | 4 +- gfx/layers/ipc/CompositorBridgeParent.h | 2 + .../CrossProcessCompositorBridgeParent.cpp | 26 +++++++++++ .../ipc/CrossProcessCompositorBridgeParent.h | 2 + gfx/layers/ipc/PCompositorBridge.ipdl | 3 ++ gfx/thebes/DeviceManagerDx.cpp | 31 +++++++++---- gfx/thebes/gfxWindowsPlatform.cpp | 46 ++++++++++++++++--- gfx/thebes/gfxWindowsPlatform.h | 1 + ipc/ipdl/sync-messages.ini | 2 + 10 files changed, 103 insertions(+), 15 deletions(-) diff --git a/gfx/ipc/GraphicsMessages.ipdlh b/gfx/ipc/GraphicsMessages.ipdlh index 56ede7488ec8..e496e0f9e4c4 100644 --- a/gfx/ipc/GraphicsMessages.ipdlh +++ b/gfx/ipc/GraphicsMessages.ipdlh @@ -21,6 +21,7 @@ struct D3D11DeviceStatus bool textureSharingWorks; uint32_t featureLevel; DxgiAdapterDesc adapter; + int32_t sequenceNumber; }; struct DevicePrefs diff --git a/gfx/layers/client/ClientLayerManager.cpp b/gfx/layers/client/ClientLayerManager.cpp index 7f623cc998ea..b8fb9f89c296 100644 --- a/gfx/layers/client/ClientLayerManager.cpp +++ b/gfx/layers/client/ClientLayerManager.cpp @@ -516,7 +516,9 @@ ClientLayerManager::DidComposite(uint64_t aTransactionId, if (listener) { listener->DidCompositeWindow(aTransactionId, aCompositeStart, aCompositeEnd); } - mTransactionIdAllocator->NotifyTransactionCompleted(aTransactionId); + if (mTransactionIdAllocator) { + mTransactionIdAllocator->NotifyTransactionCompleted(aTransactionId); + } } // These observers fire whether or not we were in a transaction. diff --git a/gfx/layers/ipc/CompositorBridgeParent.h b/gfx/layers/ipc/CompositorBridgeParent.h index 5461a03a128d..4a611d0aca3f 100644 --- a/gfx/layers/ipc/CompositorBridgeParent.h +++ b/gfx/layers/ipc/CompositorBridgeParent.h @@ -213,6 +213,8 @@ public: virtual mozilla::ipc::IPCResult RecvStartFrameTimeRecording(const int32_t& aBufferSize, uint32_t* aOutStartIndex) override; virtual mozilla::ipc::IPCResult RecvStopFrameTimeRecording(const uint32_t& aStartIndex, InfallibleTArray* intervals) override; + virtual mozilla::ipc::IPCResult RecvCheckContentOnlyTDR(const uint32_t& sequenceNum, bool* isContentOnlyTDR) override { return IPC_OK(); } + // Unused for chrome <-> compositor communication (which this class does). // @see CrossProcessCompositorBridgeParent::RecvRequestNotifyAfterRemotePaint virtual mozilla::ipc::IPCResult RecvRequestNotifyAfterRemotePaint() override { return IPC_OK(); }; diff --git a/gfx/layers/ipc/CrossProcessCompositorBridgeParent.cpp b/gfx/layers/ipc/CrossProcessCompositorBridgeParent.cpp index 78845e81ea9d..5ec31aca7ade 100644 --- a/gfx/layers/ipc/CrossProcessCompositorBridgeParent.cpp +++ b/gfx/layers/ipc/CrossProcessCompositorBridgeParent.cpp @@ -10,6 +10,9 @@ #include "base/message_loop.h" // for MessageLoop #include "base/task.h" // for CancelableTask, etc #include "base/thread.h" // for Thread +#ifdef XP_WIN +#include "mozilla/gfx/DeviceManagerDx.h"// for DeviceManagerDx +#endif #include "mozilla/ipc/Transport.h" // for Transport #include "mozilla/layers/AnimationHelper.h" // for CompositorAnimationStorage #include "mozilla/layers/APZCTreeManager.h" // for APZCTreeManager @@ -276,6 +279,29 @@ CrossProcessCompositorBridgeParent::RecvMapAndNotifyChildCreated(const uint64_t& return IPC_FAIL_NO_REASON(this); } + +mozilla::ipc::IPCResult +CrossProcessCompositorBridgeParent::RecvCheckContentOnlyTDR(const uint32_t& sequenceNum, + bool* isContentOnlyTDR) +{ + *isContentOnlyTDR = false; +#ifdef XP_WIN + ContentDeviceData compositor; + + DeviceManagerDx* dm = DeviceManagerDx::Get(); + + // Check that the D3D11 device sequence numbers match. + D3D11DeviceStatus status; + dm->ExportDeviceInfo(&status); + + if (sequenceNum == status.sequenceNumber() && !dm->HasDeviceReset()) { + *isContentOnlyTDR = true; + } + +#endif + return IPC_OK(); +}; + void CrossProcessCompositorBridgeParent::ShadowLayersUpdated( LayerTransactionParent* aLayerTree, diff --git a/gfx/layers/ipc/CrossProcessCompositorBridgeParent.h b/gfx/layers/ipc/CrossProcessCompositorBridgeParent.h index 6287b95c2ea7..d271f425c865 100644 --- a/gfx/layers/ipc/CrossProcessCompositorBridgeParent.h +++ b/gfx/layers/ipc/CrossProcessCompositorBridgeParent.h @@ -58,6 +58,8 @@ public: virtual mozilla::ipc::IPCResult RecvStartFrameTimeRecording(const int32_t& aBufferSize, uint32_t* aOutStartIndex) override { return IPC_OK(); } virtual mozilla::ipc::IPCResult RecvStopFrameTimeRecording(const uint32_t& aStartIndex, InfallibleTArray* intervals) override { return IPC_OK(); } + virtual mozilla::ipc::IPCResult RecvCheckContentOnlyTDR(const uint32_t& sequenceNum, bool* isContentOnlyTDR) override; + virtual mozilla::ipc::IPCResult RecvClearApproximatelyVisibleRegions(const uint64_t& aLayersId, const uint32_t& aPresShellId) override; diff --git a/gfx/layers/ipc/PCompositorBridge.ipdl b/gfx/layers/ipc/PCompositorBridge.ipdl index b97feb23caae..cbdd65d61828 100644 --- a/gfx/layers/ipc/PCompositorBridge.ipdl +++ b/gfx/layers/ipc/PCompositorBridge.ipdl @@ -252,6 +252,9 @@ parent: sync PWebRenderBridge(PipelineId pipelineId, LayoutDeviceIntSize aSize) returns (TextureFactoryIdentifier textureFactoryIdentifier, uint32_t idNamespace); //XXX: use the WrIdNamespace type + sync CheckContentOnlyTDR(uint32_t sequenceNum) + returns (bool isContentOnlyTDR); + child: // Send back Compositor Frame Metrics from APZCs so tiled layers can // update progressively. diff --git a/gfx/thebes/DeviceManagerDx.cpp b/gfx/thebes/DeviceManagerDx.cpp index 69cd75a1783b..2c2d033f6122 100644 --- a/gfx/thebes/DeviceManagerDx.cpp +++ b/gfx/thebes/DeviceManagerDx.cpp @@ -174,11 +174,6 @@ DeviceManagerDx::ImportDeviceInfo(const D3D11DeviceStatus& aDeviceStatus) void DeviceManagerDx::ExportDeviceInfo(D3D11DeviceStatus* aOut) { - // Even though the parent process might not own the compositor, we still - // populate DeviceManagerDx with device statistics (for simplicity). - // That means it still gets queried for compositor information. - MOZ_ASSERT(XRE_IsParentProcess() || XRE_GetProcessType() == GeckoProcessType_GPU); - if (mDeviceStatus) { *aOut = mDeviceStatus.value(); } @@ -322,6 +317,20 @@ DeviceManagerDx::CreateCompositorDeviceHelper( return true; } +// Note that it's enough for us to just use a counter for a unique ID, +// even though the counter isn't synchronized between processes. If we +// start in the GPU process and wind up in the parent process, the +// whole graphics stack is blown away anyway. But just in case, we +// make gpu process IDs negative and parent process IDs positive. +static inline int32_t +GetNextDeviceCounter() +{ + static int32_t sDeviceCounter = 0; + return XRE_IsGPUProcess() + ? --sDeviceCounter + : ++sDeviceCounter; +} + void DeviceManagerDx::CreateCompositorDevice(FeatureState& d3d11) { @@ -379,15 +388,18 @@ DeviceManagerDx::CreateCompositorDevice(FeatureState& d3d11) D3D11Checks::WarnOnAdapterMismatch(device); } - int featureLevel = device->GetFeatureLevel(); + uint32_t featureLevel = device->GetFeatureLevel(); { MutexAutoLock lock(mDeviceLock); mCompositorDevice = device; + + int32_t sequenceNumber = GetNextDeviceCounter(); mDeviceStatus = Some(D3D11DeviceStatus( false, textureSharingWorks, featureLevel, - DxgiAdapterDesc::From(desc))); + DxgiAdapterDesc::From(desc), + sequenceNumber)); } mCompositorDevice->SetExceptionMode(0); } @@ -475,11 +487,14 @@ DeviceManagerDx::CreateWARPCompositorDevice() { MutexAutoLock lock(mDeviceLock); mCompositorDevice = device; + + int32_t sequenceNumber = GetNextDeviceCounter(); mDeviceStatus = Some(D3D11DeviceStatus( true, textureSharingWorks, featureLevel, - nullAdapter)); + nullAdapter, + sequenceNumber)); } mCompositorDevice->SetExceptionMode(0); diff --git a/gfx/thebes/gfxWindowsPlatform.cpp b/gfx/thebes/gfxWindowsPlatform.cpp index f10ea9a02fa7..66e948f2d363 100755 --- a/gfx/thebes/gfxWindowsPlatform.cpp +++ b/gfx/thebes/gfxWindowsPlatform.cpp @@ -8,6 +8,7 @@ #include "cairo.h" #include "mozilla/ArrayUtils.h" +#include "mozilla/layers/CompositorBridgeChild.h" #include "gfxImageSurface.h" #include "gfxWindowsSurface.h" @@ -20,6 +21,7 @@ #include "mozilla/WindowsVersion.h" #include "nsServiceManagerUtils.h" #include "nsTArray.h" +#include "nsThreadUtils.h" #include "mozilla/Telemetry.h" #include "GeckoProfiler.h" @@ -70,7 +72,7 @@ #include "gfxConfig.h" #include "VsyncSource.h" #include "DriverCrashGuard.h" -#include "mozilla/dom/ContentParent.h" +#include "mozilla/dom/ContentChild.h" #include "mozilla/gfx/DeviceManagerDx.h" #include "mozilla/layers/DeviceAttachmentsD3D11.h" #include "D3D11Checks.h" @@ -894,12 +896,44 @@ gfxWindowsPlatform::SchedulePaintIfDeviceReset() gfxCriticalNote << "(gfxWindowsPlatform) Detected device reset: " << (int)resetReason; - // Trigger an ::OnPaint for each window. - ::EnumThreadWindows(GetCurrentThreadId(), - InvalidateWindowForDeviceReset, - 0); + if (XRE_IsParentProcess()) { + // Trigger an ::OnPaint for each window. + ::EnumThreadWindows(GetCurrentThreadId(), + InvalidateWindowForDeviceReset, + 0); + } else { + NS_DispatchToMainThread(NS_NewRunnableFunction( + "gfx::gfxWindowsPlatform::SchedulePaintIfDeviceReset", + []() -> void { + gfxWindowsPlatform::GetPlatform()->CheckForContentOnlyDeviceReset(); + } + )); + } - gfxCriticalNote << "(gfxWindowsPlatform) Finished device reset."; + gfxCriticalNote << "(gfxWindowsPlatform) scheduled device update."; +} + +void +gfxWindowsPlatform::CheckForContentOnlyDeviceReset() +{ + if (!DidRenderingDeviceReset()) { + return; + } + + bool isContentOnlyTDR; + D3D11DeviceStatus status; + + DeviceManagerDx::Get()->ExportDeviceInfo(&status); + CompositorBridgeChild::Get()->SendCheckContentOnlyTDR( + status.sequenceNumber(), &isContentOnlyTDR); + + // The parent process doesn't know about the reset yet, or the reset is + // local to our device. + if (isContentOnlyTDR) { + gfxCriticalNote << "A content-only TDR is detected."; + dom::ContentChild* cc = dom::ContentChild::GetSingleton(); + cc->RecvReinitRenderingForDeviceReset(); + } } void diff --git a/gfx/thebes/gfxWindowsPlatform.h b/gfx/thebes/gfxWindowsPlatform.h index ae0fe0400a73..e5e99a4e9e9c 100644 --- a/gfx/thebes/gfxWindowsPlatform.h +++ b/gfx/thebes/gfxWindowsPlatform.h @@ -180,6 +180,7 @@ public: bool DidRenderingDeviceReset(DeviceResetReason* aResetReason = nullptr) override; void SchedulePaintIfDeviceReset() override; + void CheckForContentOnlyDeviceReset(); mozilla::gfx::BackendType GetContentBackendFor(mozilla::layers::LayersBackend aLayers) override; diff --git a/ipc/ipdl/sync-messages.ini b/ipc/ipdl/sync-messages.ini index d40169262b97..6604a84eec23 100644 --- a/ipc/ipdl/sync-messages.ini +++ b/ipc/ipdl/sync-messages.ini @@ -993,6 +993,8 @@ description = description = [PCompositorBridge::PWebRenderBridge] description = +[PCompositorBridge::CheckContentOnlyTDR] +description = [PCompositorWidget::EnterPresentLock] description = platform = win