author | Brian Hackett <bhackett1024@gmail.com> |
Sun, 22 Jul 2018 12:02:26 +0000 | |
changeset 469502 | 7e4f6f3985d0caf63dd852f26dec16156782caa2 |
parent 469501 | a0ee9e803ff24c59245322da5c2f692d803300e1 |
child 469503 | 1ac6543017416f0899dbac1c785cc2b48637b900 |
push id | unknown |
push user | unknown |
push date | unknown |
reviewers | nical |
bugs | 1465466 |
milestone | 63.0a1 |
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
|
--- a/dom/ipc/TabChild.h +++ b/dom/ipc/TabChild.h @@ -654,16 +654,18 @@ public: const FrameMetrics::ViewID& aViewId, const CSSRect& aRect, const uint32_t& aFlags); // Request that the docshell be marked as active. void PaintWhileInterruptingJS(uint64_t aLayerObserverEpoch, bool aForceRepaint); + uint64_t LayerObserverEpoch() const { return mLayerObserverEpoch; } + #if defined(XP_WIN) && defined(ACCESSIBILITY) uintptr_t GetNativeWindowHandle() const { return mNativeWindowHandle; } #endif // These methods return `true` if this TabChild is currently awaiting a // Large-Allocation header. bool StopAwaitingLargeAlloc(); bool IsAwaitingLargeAlloc();
--- a/gfx/layers/ipc/CompositorBridgeParent.h +++ b/gfx/layers/ipc/CompositorBridgeParent.h @@ -166,16 +166,20 @@ public: uint32_t aApzcId) override; bool StopSharingMetrics(FrameMetrics::ViewID aScrollId, uint32_t aApzcId) override; virtual bool IsRemote() const { return false; } + virtual void ForceComposeToTarget(gfx::DrawTarget* aTarget, const gfx::IntRect* aRect = nullptr) { + MOZ_CRASH(); + } + protected: ~CompositorBridgeParentBase() override; bool mCanSend; private: RefPtr<CompositorManagerParent> mCompositorManager; }; @@ -441,17 +445,17 @@ public: /** * Used by the profiler to denote when a vsync occured */ static void PostInsertVsyncProfilerMarker(mozilla::TimeStamp aVsyncTimestamp); widget::CompositorWidget* GetWidget() { return mWidget; } - void ForceComposeToTarget(gfx::DrawTarget* aTarget, const gfx::IntRect* aRect = nullptr); + virtual void ForceComposeToTarget(gfx::DrawTarget* aTarget, const gfx::IntRect* aRect = nullptr) override; PAPZCTreeManagerParent* AllocPAPZCTreeManagerParent(const LayersId& aLayersId) override; bool DeallocPAPZCTreeManagerParent(PAPZCTreeManagerParent* aActor) override; // Helper method so that we don't have to expose mApzcTreeManager to // CrossProcessCompositorBridgeParent. void AllocateAPZCTreeManagerParent(const MonitorAutoLock& aProofOfLayerTreeStateLock, const LayersId& aLayersId,
--- a/gfx/layers/ipc/LayerTransactionParent.cpp +++ b/gfx/layers/ipc/LayerTransactionParent.cpp @@ -157,16 +157,22 @@ LayerTransactionParent::RecvPaintTime(co { mCompositorBridge->UpdatePaintTime(this, aPaintTime); return IPC_OK(); } mozilla::ipc::IPCResult LayerTransactionParent::RecvUpdate(const TransactionInfo& aInfo) { + auto guard = MakeScopeExit([&] { + if (recordreplay::IsRecordingOrReplaying()) { + recordreplay::child::NotifyPaintComplete(); + } + }); + AUTO_PROFILER_TRACING("Paint", "LayerTransaction"); AUTO_PROFILER_LABEL("LayerTransactionParent::RecvUpdate", GRAPHICS); TimeStamp updateStart = TimeStamp::Now(); MOZ_LAYERS_LOG(("[ParentSide] received txn with %zu edits", aInfo.cset().Length())); UpdateFwdTransactionId(aInfo.fwdTransactionId()); @@ -484,16 +490,21 @@ LayerTransactionParent::RecvUpdate(const printf_stderr("LayerTransactionParent::RecvUpdate transaction from process %d took %f ms", OtherPid(), latency.ToMilliseconds()); } mLayerManager->RecordUpdateTime((TimeStamp::Now() - updateStart).ToMilliseconds()); } + // Compose after every update when recording/replaying. + if (recordreplay::IsRecordingOrReplaying()) { + mCompositorBridge->ForceComposeToTarget(nullptr); + } + return IPC_OK(); } bool LayerTransactionParent::SetLayerAttributes(const OpSetLayerAttributes& aOp) { Layer* layer = AsLayer(aOp.layer()); if (!layer) {
--- a/gfx/layers/ipc/ShadowLayers.cpp +++ b/gfx/layers/ipc/ShadowLayers.cpp @@ -762,23 +762,31 @@ ShadowLayerForwarder::EndTransaction(con mPaintTiming.serializeMs() = (TimeStamp::Now() - startTime.value()).ToMilliseconds(); startTime = Some(TimeStamp::Now()); } // We delay at the last possible minute, to give the paint thread a chance to // finish. If it does we don't have to delay messages at all. GetCompositorBridgeChild()->PostponeMessagesIfAsyncPainting(); + if (recordreplay::IsRecordingOrReplaying()) { + recordreplay::child::NotifyPaintStart(); + } + MOZ_LAYERS_LOG(("[LayersForwarder] sending transaction...")); RenderTraceScope rendertrace3("Forward Transaction", "000093"); if (!mShadowManager->SendUpdate(info)) { MOZ_LAYERS_LOG(("[LayersForwarder] WARNING: sending transaction failed!")); return false; } + if (recordreplay::IsRecordingOrReplaying()) { + recordreplay::child::WaitForPaintToComplete(); + } + if (startTime) { mPaintTiming.sendMs() = (TimeStamp::Now() - startTime.value()).ToMilliseconds(); mShadowManager->SendRecordPaintTimes(mPaintTiming); } *aSent = true; mIsFirstPaint = false; mFocusTarget = FocusTarget();
--- a/toolkit/recordreplay/ipc/ChildIPC.cpp +++ b/toolkit/recordreplay/ipc/ChildIPC.cpp @@ -343,16 +343,116 @@ void NotifyAlwaysMarkMajorCheckpoints() { if (IsActiveChild()) { gChannel->SendMessage(AlwaysMarkMajorCheckpointsMessage()); } } /////////////////////////////////////////////////////////////////////////////// +// Vsyncs +/////////////////////////////////////////////////////////////////////////////// + +static VsyncObserver* gVsyncObserver; + +void +SetVsyncObserver(VsyncObserver* aObserver) +{ + MOZ_RELEASE_ASSERT(!gVsyncObserver || !aObserver); + gVsyncObserver = aObserver; +} + +void +NotifyVsyncObserver() +{ + if (gVsyncObserver) { + gVsyncObserver->NotifyVsync(TimeStamp::Now()); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// Painting +/////////////////////////////////////////////////////////////////////////////// + +// Graphics memory is only written on the compositor thread and read on the +// main thread and by the middleman. The gPendingPaint flag is used to +// synchronize access, so that data is not read until the paint has completed. +static Maybe<PaintMessage> gPaintMessage; +static bool gPendingPaint; + +// Target buffer for the draw target created by the child process widget. +static void* gDrawTargetBuffer; +static size_t gDrawTargetBufferSize; + +already_AddRefed<gfx::DrawTarget> +DrawTargetForRemoteDrawing(LayoutDeviceIntSize aSize) +{ + MOZ_RELEASE_ASSERT(!NS_IsMainThread()); + + gPaintMessage = Some(PaintMessage(aSize.width, aSize.height)); + + gfx::IntSize size(aSize.width, aSize.height); + size_t bufferSize = layers::ImageDataSerializer::ComputeRGBBufferSize(size, gSurfaceFormat); + MOZ_RELEASE_ASSERT(bufferSize <= parent::GraphicsMemorySize); + + if (bufferSize != gDrawTargetBufferSize) { + free(gDrawTargetBuffer); + gDrawTargetBuffer = malloc(bufferSize); + gDrawTargetBufferSize = bufferSize; + } + + size_t stride = layers::ImageDataSerializer::ComputeRGBStride(gSurfaceFormat, aSize.width); + RefPtr<gfx::DrawTarget> drawTarget = + gfx::Factory::CreateDrawTargetForData(gfx::BackendType::SKIA, (uint8_t*) gDrawTargetBuffer, + size, stride, gSurfaceFormat, + /* aUninitialized = */ true); + if (!drawTarget) { + MOZ_CRASH(); + } + + return drawTarget.forget(); +} + +void +NotifyPaintStart() +{ + MOZ_RELEASE_ASSERT(NS_IsMainThread()); + + NewCheckpoint(/* aTemporary = */ false); + + gPendingPaint = true; +} + +void +WaitForPaintToComplete() +{ + MOZ_RELEASE_ASSERT(NS_IsMainThread()); + + MonitorAutoLock lock(*gMonitor); + while (gPendingPaint) { + gMonitor->Wait(); + } + if (IsActiveChild() && gPaintMessage.isSome()) { + memcpy(gGraphicsShmem, gDrawTargetBuffer, gDrawTargetBufferSize); + gChannel->SendMessage(gPaintMessage.ref()); + } +} + +void +NotifyPaintComplete() +{ + MOZ_RELEASE_ASSERT(!NS_IsMainThread()); + + MonitorAutoLock lock(*gMonitor); + MOZ_RELEASE_ASSERT(gPendingPaint); + gPendingPaint = false; + gMonitor->Notify(); +} + +/////////////////////////////////////////////////////////////////////////////// // Checkpoint Messages /////////////////////////////////////////////////////////////////////////////// // When recording, the time when the last HitCheckpoint message was sent. static double gLastCheckpointTime; // When recording and we are idle, the time when we became idle. static double gIdleTimeStart;
--- a/toolkit/recordreplay/ipc/ChildIPC.h +++ b/toolkit/recordreplay/ipc/ChildIPC.h @@ -3,18 +3,23 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef mozilla_recordreplay_ChildIPC_h #define mozilla_recordreplay_ChildIPC_h #include "base/process.h" +#include "mozilla/gfx/2D.h" +#include "Units.h" namespace mozilla { + +class VsyncObserver; + namespace recordreplay { namespace child { // Naively replaying a child process execution will not perform any IPC. When // the replaying process attempts to make system calls that communicate with // the parent, function redirections are invoked that simply replay the values // which those calls produced in the original recording. // @@ -37,16 +42,26 @@ namespace child { void InitRecordingOrReplayingProcess(int* aArgc, char*** aArgv); // Get the contents of the prefs shmem as conveyed to the middleman process. char* PrefsShmemContents(size_t aPrefsLen); base::ProcessId MiddlemanProcessId(); base::ProcessId ParentProcessId(); +void SetVsyncObserver(VsyncObserver* aObserver); +void NotifyVsyncObserver(); + +void NotifyPaint(); +void NotifyPaintStart(); +void NotifyPaintComplete(); +void WaitForPaintToComplete(); + +already_AddRefed<gfx::DrawTarget> DrawTargetForRemoteDrawing(LayoutDeviceIntSize aSize); + // Notify the middleman that the recording was flushed. void NotifyFlushedRecording(); // Notify the middleman about an AlwaysMarkMajorCheckpoints directive. void NotifyAlwaysMarkMajorCheckpoints(); // Report a fatal error to the middleman process. void ReportFatalError(const char* aFormat, ...);