зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
e6a4589c5b
Коммит
11d1005390
|
@ -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();
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче