Bug 1465466 Part 2 - Synchronously composite into a graphics shmem buffer when recording/replaying, r=nical.

--HG--
extra : rebase_source : a89c5fd8f87f82e5a93f9b3311617317a67b3333
This commit is contained in:
Brian Hackett 2018-07-22 12:02:26 +00:00
Родитель e6a4589c5b
Коммит 11d1005390
6 изменённых файлов: 141 добавлений и 1 удалений

Просмотреть файл

@ -659,6 +659,8 @@ public:
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

Просмотреть файл

@ -171,6 +171,10 @@ public:
return false;
}
virtual void ForceComposeToTarget(gfx::DrawTarget* aTarget, const gfx::IntRect* aRect = nullptr) {
MOZ_CRASH();
}
protected:
~CompositorBridgeParentBase() override;
@ -446,7 +450,7 @@ public:
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;

Просмотреть файл

@ -162,6 +162,12 @@ LayerTransactionParent::RecvPaintTime(const TransactionId& aTransactionId,
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);
@ -489,6 +495,11 @@ LayerTransactionParent::RecvUpdate(const TransactionInfo& aInfo)
mLayerManager->RecordUpdateTime((TimeStamp::Now() - updateStart).ToMilliseconds());
}
// Compose after every update when recording/replaying.
if (recordreplay::IsRecordingOrReplaying()) {
mCompositorBridge->ForceComposeToTarget(nullptr);
}
return IPC_OK();
}

Просмотреть файл

@ -767,6 +767,10 @@ ShadowLayerForwarder::EndTransaction(const nsIntRegion& aRegionToClear,
// 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)) {
@ -774,6 +778,10 @@ ShadowLayerForwarder::EndTransaction(const nsIntRegion& aRegionToClear,
return false;
}
if (recordreplay::IsRecordingOrReplaying()) {
recordreplay::child::WaitForPaintToComplete();
}
if (startTime) {
mPaintTiming.sendMs() = (TimeStamp::Now() - startTime.value()).ToMilliseconds();
mShadowManager->SendRecordPaintTimes(mPaintTiming);

Просмотреть файл

@ -347,6 +347,106 @@ NotifyAlwaysMarkMajorCheckpoints()
}
}
///////////////////////////////////////////////////////////////////////////////
// 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
///////////////////////////////////////////////////////////////////////////////

Просмотреть файл

@ -8,8 +8,13 @@
#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 {
@ -42,6 +47,16 @@ 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();