Bug 1464032 Part 12: Add CanvasParent, CanvasChild and RecordedTextureData. r=mattwoodrow, jld

RecordedTextureData records TextureData calls for play back in the GPU process.
CanvasChild and CanvasParent set up the recorder and translator.
They also help to manage the starting of translation and co-ordinating the
translation with the frame transactions.
This patch also includes other changes to wire up recording and playback.
This commit is contained in:
Bob Owen 2018-12-02 14:19:11 +00:00
parent 2853ef8068
commit 387477fb68
27 changed files with 864 additions and 39 deletions

View File

@ -1611,19 +1611,13 @@ UniquePtr<uint8_t[]> CanvasRenderingContext2D::GetImageBuffer(
*aFormat = 0;
RefPtr<SourceSurface> snapshot;
if (mTarget) {
snapshot = mTarget->Snapshot();
} else if (mBufferProvider) {
snapshot = mBufferProvider->BorrowSnapshot();
} else {
EnsureTarget();
if (!IsTargetValid()) {
if (!mBufferProvider) {
if (!EnsureTarget()) {
return nullptr;
}
snapshot = mTarget->Snapshot();
}
RefPtr<SourceSurface> snapshot = mBufferProvider->BorrowSnapshot();
if (snapshot) {
RefPtr<DataSourceSurface> data = snapshot->GetDataSurface();
if (data && data->GetSize() == GetSize()) {
@ -1632,9 +1626,7 @@ UniquePtr<uint8_t[]> CanvasRenderingContext2D::GetImageBuffer(
}
}
if (!mTarget && mBufferProvider) {
mBufferProvider->ReturnSnapshot(snapshot.forget());
}
mBufferProvider->ReturnSnapshot(snapshot.forget());
return ret;
}
@ -1672,6 +1664,29 @@ CanvasRenderingContext2D::GetInputStream(const char* aMimeType,
aStream);
}
already_AddRefed<mozilla::gfx::SourceSurface>
CanvasRenderingContext2D::GetSurfaceSnapshot(gfxAlphaType* aOutAlphaType) {
if (!mBufferProvider) {
if (!EnsureTarget()) {
return nullptr;
}
}
RefPtr<SourceSurface> snapshot = mBufferProvider->BorrowSnapshot();
if (!snapshot) {
return nullptr;
}
RefPtr<DataSourceSurface> dataSurface = snapshot->GetDataSurface();
mBufferProvider->ReturnSnapshot(snapshot.forget());
if (aOutAlphaType) {
*aOutAlphaType = (mOpaque ? gfxAlphaType::Opaque : gfxAlphaType::Premult);
}
return dataSurface.forget();
}
SurfaceFormat CanvasRenderingContext2D::GetSurfaceFormat() const {
return mOpaque ? SurfaceFormat::B8G8R8X8 : SurfaceFormat::B8G8R8A8;
}
@ -4920,27 +4935,21 @@ nsresult CanvasRenderingContext2D::GetImageDataArray(
return NS_OK;
}
RefPtr<DataSourceSurface> readback;
DataSourceSurface::MappedSurface rawData;
RefPtr<SourceSurface> snapshot;
if (!mTarget && mBufferProvider) {
snapshot = mBufferProvider->BorrowSnapshot();
} else {
EnsureTarget();
if (!IsTargetValid()) {
return NS_ERROR_FAILURE;
if (!mBufferProvider) {
if (!EnsureTarget()) {
return NS_ERROR_OUT_OF_MEMORY;
}
snapshot = mTarget->Snapshot();
}
if (snapshot) {
readback = snapshot->GetDataSurface();
RefPtr<SourceSurface> snapshot = mBufferProvider->BorrowSnapshot();
if (!snapshot) {
return NS_ERROR_OUT_OF_MEMORY;
}
if (!mTarget && mBufferProvider) {
mBufferProvider->ReturnSnapshot(snapshot.forget());
}
RefPtr<DataSourceSurface> readback = snapshot->GetDataSurface();
mBufferProvider->ReturnSnapshot(snapshot.forget());
DataSourceSurface::MappedSurface rawData;
if (!readback || !readback->Map(DataSourceSurface::READ, &rawData)) {
return NS_ERROR_OUT_OF_MEMORY;
}

View File

@ -409,13 +409,7 @@ class CanvasRenderingContext2D final : public nsICanvasRenderingContextInternal,
nsIInputStream** aStream) override;
already_AddRefed<mozilla::gfx::SourceSurface> GetSurfaceSnapshot(
gfxAlphaType* aOutAlphaType = nullptr) override {
EnsureTarget();
if (aOutAlphaType) {
*aOutAlphaType = (mOpaque ? gfxAlphaType::Opaque : gfxAlphaType::Premult);
}
return mTarget->Snapshot();
}
gfxAlphaType* aOutAlphaType = nullptr) override;
virtual void SetOpaqueValueFromOpaqueAttr(bool aOpaqueAttrValue) override;
bool GetIsOpaque() override { return mOpaque; }

View File

@ -425,13 +425,18 @@ TextureClient* PersistentBufferProviderShared::GetTextureClient() {
already_AddRefed<gfx::SourceSurface>
PersistentBufferProviderShared::BorrowSnapshot() {
MOZ_ASSERT(!mDrawTarget);
if (mPreviousSnapshot) {
mSnapshot = mPreviousSnapshot;
return do_AddRef(mSnapshot);
}
if (mDrawTarget) {
auto back = GetTexture(mBack);
MOZ_ASSERT(back && back->IsLocked());
mSnapshot = back->BorrowSnapshot();
return do_AddRef(mSnapshot);
}
auto front = GetTexture(mFront);
if (!front || front->IsLocked()) {
MOZ_ASSERT(false);
@ -455,7 +460,7 @@ void PersistentBufferProviderShared::ReturnSnapshot(
mSnapshot = nullptr;
snapshot = nullptr;
if (mPreviousSnapshot) {
if (mPreviousSnapshot || mDrawTarget) {
return;
}

View File

@ -665,6 +665,8 @@ void ClientLayerManager::ForwardTransaction(bool aScheduleComposite) {
AUTO_PROFILER_TRACING("Paint", "ForwardTransaction", GRAPHICS);
TimeStamp start = TimeStamp::Now();
GetCompositorBridgeChild()->EndCanvasTransaction();
// Skip the synchronization for buffer since we also skip the painting during
// device-reset status. With OMTP, we have to wait for async paints
// before we synchronize and it's done on the paint thread.

View File

@ -20,6 +20,7 @@
#include "mozilla/layers/ImageDataSerializer.h"
#include "mozilla/layers/PaintThread.h"
#include "mozilla/layers/TextureClientRecycleAllocator.h"
#include "mozilla/layers/TextureRecorded.h"
#include "mozilla/Mutex.h"
#include "nsDebug.h" // for NS_ASSERTION, NS_WARNING, etc
#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc
@ -343,7 +344,11 @@ TextureData::Create(TextureForwarder* aAllocator, gfx::SurfaceFormat aFormat,
aAllocFlags);
if (ShouldRemoteTextureType(textureType, aSelector)) {
// TODO: return a recording texture data here.
RefPtr<CanvasChild> canvasChild = aAllocator->GetCanvasChild();
if (canvasChild) {
return new RecordedTextureData(canvasChild.forget(), aSize, aFormat,
textureType);
}
}
switch(textureType) {

View File

@ -0,0 +1,110 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#include "TextureRecorded.h"
#include "RecordedCanvasEventImpl.h"
namespace mozilla {
namespace layers {
class SourceSurfaceCanvasRecording final : public gfx::SourceSurface {
public:
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SourceSurfaceCanvasRecording, final)
SourceSurfaceCanvasRecording(RefPtr<gfx::SourceSurface>& aRecordedSuface,
RefPtr<CanvasChild>& aCanvasChild)
: mRecordedSurface(aRecordedSuface), mCanvasChild(aCanvasChild) {}
gfx::SurfaceType GetType() const final { return mRecordedSurface->GetType(); }
gfx::IntSize GetSize() const final { return mRecordedSurface->GetSize(); }
gfx::SurfaceFormat GetFormat() const final {
return mRecordedSurface->GetFormat();
}
already_AddRefed<gfx::DataSourceSurface> GetDataSurface() final {
if (!mDataSourceSurface) {
mDataSourceSurface = mCanvasChild->GetDataSurface(mRecordedSurface);
}
return do_AddRef(mDataSourceSurface);
}
RefPtr<gfx::SourceSurface> mRecordedSurface;
RefPtr<CanvasChild> mCanvasChild;
RefPtr<gfx::DataSourceSurface> mDataSourceSurface;
};
RecordedTextureData::RecordedTextureData(
already_AddRefed<CanvasChild> aCanvasChild, gfx::IntSize aSize,
gfx::SurfaceFormat aFormat, TextureType aTextureType)
: mCanvasChild(aCanvasChild), mSize(aSize), mFormat(aFormat) {
mCanvasChild->EnsureRecorder(aTextureType);
}
RecordedTextureData::~RecordedTextureData() {}
void RecordedTextureData::FillInfo(TextureData::Info& aInfo) const {
aInfo.size = mSize;
aInfo.format = mFormat;
aInfo.supportsMoz2D = true;
aInfo.hasIntermediateBuffer = false;
aInfo.hasSynchronization = true;
}
bool RecordedTextureData::Lock(OpenMode aMode) {
mCanvasChild->EnsureBeginTransaction();
if (!mDT) {
mDT = mCanvasChild->CreateDrawTarget(mSize, mFormat);
// We lock the TextureData when we create it to get the remote DrawTarget.
mCanvasChild->OnTextureWriteLock();
return true;
}
mCanvasChild->RecordEvent(RecordedTextureLock(mDT.get(), aMode));
if (aMode & OpenMode::OPEN_WRITE) {
mCanvasChild->OnTextureWriteLock();
mSnapshot = nullptr;
}
return true;
}
void RecordedTextureData::Unlock() {
mCanvasChild->RecordEvent(RecordedTextureUnlock(mDT.get()));
}
already_AddRefed<gfx::DrawTarget> RecordedTextureData::BorrowDrawTarget() {
return do_AddRef(mDT);
}
already_AddRefed<gfx::SourceSurface> RecordedTextureData::BorrowSnapshot() {
MOZ_ASSERT(mDT);
mSnapshot = mDT->Snapshot();
return MakeAndAddRef<SourceSurfaceCanvasRecording>(mSnapshot, mCanvasChild);
}
void RecordedTextureData::Deallocate(LayersIPCChannel* aAllocator) {}
bool RecordedTextureData::Serialize(SurfaceDescriptor& aDescriptor) {
SurfaceDescriptorRecorded descriptor;
descriptor.drawTarget() = reinterpret_cast<uintptr_t>(mDT.get());
aDescriptor = std::move(descriptor);
return true;
}
void RecordedTextureData::OnForwardedToHost() {
mCanvasChild->OnTextureForwarded();
if (mSnapshot && mCanvasChild->ShouldCacheDataSurface()) {
mCanvasChild->RecordEvent(RecordedCacheDataSurface(mSnapshot.get()));
}
}
} // namespace layers
} // namespace mozilla

View File

@ -0,0 +1,53 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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 https://mozilla.org/MPL/2.0/. */
#ifndef mozilla_layers_TextureRecorded_h
#define mozilla_layers_TextureRecorded_h
#include "TextureClient.h"
#include "mozilla/layers/CanvasChild.h"
namespace mozilla {
namespace layers {
class RecordedTextureData final : public TextureData {
public:
RecordedTextureData(already_AddRefed<CanvasChild> aCanvasChild,
gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
TextureType aTextureType);
void FillInfo(TextureData::Info& aInfo) const final;
bool Lock(OpenMode aMode) final;
void Unlock() final;
already_AddRefed<gfx::DrawTarget> BorrowDrawTarget() final;
already_AddRefed<gfx::SourceSurface> BorrowSnapshot() final;
void Deallocate(LayersIPCChannel* aAllocator) final;
bool Serialize(SurfaceDescriptor& aDescriptor) final;
void OnForwardedToHost() final;
private:
DISALLOW_COPY_AND_ASSIGN(RecordedTextureData);
~RecordedTextureData() override;
RefPtr<CanvasChild> mCanvasChild;
gfx::IntSize mSize;
gfx::SurfaceFormat mFormat;
RefPtr<gfx::DrawTarget> mDT;
RefPtr<gfx::SourceSurface> mSnapshot;
};
} // namespace layers
} // namespace mozilla
#endif // mozilla_layers_TextureRecorded_h

View File

@ -216,6 +216,16 @@ already_AddRefed<TextureHost> TextureHost::Create(
result = CreateTextureHostD3D11(aDesc, aDeallocator, aBackend, aFlags);
break;
#endif
case SurfaceDescriptor::TSurfaceDescriptorRecorded: {
const SurfaceDescriptorRecorded& desc =
aDesc.get_SurfaceDescriptorRecorded();
UniquePtr<SurfaceDescriptor> realDesc =
aDeallocator->AsCompositorBridgeParentBase()
->LookupSurfaceDescriptorForClientDrawTarget(desc.drawTarget());
result = TextureHost::Create(*realDesc, aReadLock, aDeallocator, aBackend,
aFlags, aExternalImageId);
return result.forget();
}
default:
MOZ_CRASH("GFX: Unsupported Surface type host");
}

View File

@ -728,7 +728,8 @@ already_AddRefed<TextureHost> CreateTextureHostD3D11(
}
already_AddRefed<DrawTarget> D3D11TextureData::BorrowDrawTarget() {
MOZ_ASSERT(NS_IsMainThread() || PaintThread::IsOnPaintThread());
MOZ_ASSERT(NS_IsMainThread() || PaintThread::IsOnPaintThread() ||
NS_IsInCanvasThread());
if (!mDrawTarget && mTexture) {
// This may return a null DrawTarget

View File

@ -0,0 +1,150 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#include "CanvasChild.h"
#include "MainThreadUtils.h"
#include "mozilla/gfx/DrawTargetRecording.h"
#include "mozilla/gfx/Tools.h"
#include "mozilla/layers/CanvasDrawEventRecorder.h"
#include "RecordedCanvasEventImpl.h"
namespace mozilla {
namespace layers {
static const TimeDuration kLockWaitTimeout =
TimeDuration::FromMilliseconds(100);
static const TimeDuration kGetDataTimeout = TimeDuration::FromMilliseconds(500);
CanvasChild::CanvasChild(Endpoint<PCanvasChild>&& aEndpoint) {
aEndpoint.Bind(this);
mCanSend = true;
}
CanvasChild::~CanvasChild() {}
void CanvasChild::EnsureRecorder(TextureType aTextureType) {
if (!mRecorder) {
MOZ_ASSERT(mTextureType == TextureType::Unknown);
mTextureType = aTextureType;
mRecorder = MakeAndAddRef<CanvasDrawEventRecorder>();
SharedMemoryBasic::Handle handle;
CrossProcessSemaphoreHandle readerSem;
CrossProcessSemaphoreHandle writerSem;
RefPtr<CanvasChild> thisRef = this;
mRecorder->Init(OtherPid(), &handle, &readerSem, &writerSem,
[cc = std::move(thisRef)] { cc->ResumeTranslation(); });
if (mCanSend) {
Unused << SendCreateTranslator(mTextureType, handle, readerSem,
writerSem);
}
}
MOZ_RELEASE_ASSERT(mTextureType == aTextureType,
"We only support one remote TextureType currently.");
}
void CanvasChild::ActorDestroy(ActorDestroyReason aWhy) {
mCanSend = false;
// Explicitly drop our reference to the recorder, because it holds a reference
// to us via the ResumeTranslation callback.
mRecorder = nullptr;
}
void CanvasChild::ResumeTranslation() {
if (mCanSend) {
SendResumeTranslation();
}
}
void CanvasChild::Destroy() { Close(); }
void CanvasChild::OnTextureWriteLock() {
mHasOutstandingWriteLock = true;
mLastWriteLockCheckpoint = mRecorder->CreateCheckpoint();
}
void CanvasChild::OnTextureForwarded() {
if (mHasOutstandingWriteLock) {
mRecorder->RecordEvent(RecordedCanvasFlush());
if (!mRecorder->WaitForCheckpoint(mLastWriteLockCheckpoint,
kLockWaitTimeout)) {
gfxWarning() << "Timed out waiting for last write lock to be processed.";
}
mHasOutstandingWriteLock = false;
}
}
void CanvasChild::EnsureBeginTransaction() {
if (!mIsInTransaction) {
mRecorder->RecordEvent(RecordedCanvasBeginTransaction());
mIsInTransaction = true;
}
}
void CanvasChild::EndTransaction() {
if (mIsInTransaction) {
mRecorder->RecordEvent(RecordedCanvasEndTransaction());
mIsInTransaction = false;
}
++mTransactionsSinceGetDataSurface;
}
already_AddRefed<gfx::DrawTarget> CanvasChild::CreateDrawTarget(
gfx::IntSize aSize, gfx::SurfaceFormat aFormat) {
MOZ_ASSERT(mRecorder);
RefPtr<gfx::DrawTarget> dummyDt = gfx::Factory::CreateDrawTarget(
gfx::BackendType::SKIA, gfx::IntSize(1, 1), aFormat);
RefPtr<gfx::DrawTarget> dt =
MakeAndAddRef<gfx::DrawTargetRecording>(mRecorder, dummyDt, aSize);
return dt.forget();
}
void CanvasChild::RecordEvent(const gfx::RecordedEvent& aEvent) {
mRecorder->RecordEvent(aEvent);
}
already_AddRefed<gfx::DataSourceSurface> CanvasChild::GetDataSurface(
const gfx::SourceSurface* aSurface) {
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aSurface);
mTransactionsSinceGetDataSurface = 0;
EnsureBeginTransaction();
mRecorder->RecordEvent(RecordedPrepareDataForSurface(aSurface));
uint32_t checkpoint = mRecorder->CreateCheckpoint();
gfx::IntSize ssSize = aSurface->GetSize();
gfx::SurfaceFormat ssFormat = aSurface->GetFormat();
size_t dataFormatWidth = ssSize.width * BytesPerPixel(ssFormat);
RefPtr<gfx::DataSourceSurface> dataSurface =
gfx::Factory::CreateDataSourceSurfaceWithStride(ssSize, ssFormat,
dataFormatWidth);
if (!dataSurface) {
gfxWarning() << "Failed to create DataSourceSurface.";
return nullptr;
}
gfx::DataSourceSurface::ScopedMap map(dataSurface,
gfx::DataSourceSurface::READ_WRITE);
char* dest = reinterpret_cast<char*>(map.GetData());
if (!mRecorder->WaitForCheckpoint(checkpoint, kGetDataTimeout)) {
gfxWarning() << "Timed out preparing data for DataSourceSurface.";
return dataSurface.forget();
}
mRecorder->RecordEvent(RecordedGetDataForSurface(aSurface));
mRecorder->ReturnRead(dest, ssSize.height * dataFormatWidth);
return dataSurface.forget();
}
} // namespace layers
} // namespace mozilla

View File

@ -0,0 +1,117 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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 https://mozilla.org/MPL/2.0/. */
#ifndef mozilla_layers_CanvasChild_h
#define mozilla_layers_CanvasChild_h
#include "mozilla/gfx/RecordedEvent.h"
#include "mozilla/ipc/CrossProcessSemaphore.h"
#include "mozilla/layers/PCanvasChild.h"
#include "mozilla/layers/SourceSurfaceSharedData.h"
#include "nsRefPtrHashtable.h"
#include "nsTArray.h"
namespace mozilla {
namespace gfx {
class SourceSurface;
}
namespace layers {
class CanvasDrawEventRecorder;
class CanvasChild final : public PCanvasChild {
public:
NS_INLINE_DECL_REFCOUNTING(CanvasChild)
explicit CanvasChild(Endpoint<PCanvasChild>&& aEndpoint);
/**
* Ensures that the DrawEventRecorder has been created.
*
* @params aTextureType the TextureType to create in the CanvasTranslator.
*/
void EnsureRecorder(TextureType aTextureType);
/**
* Send a messsage to our CanvasParent to resume translation.
*/
void ResumeTranslation();
/**
* Clean up IPDL actor.
*/
void Destroy();
/**
* Called when a RecordedTextureData is write locked.
*/
void OnTextureWriteLock();
/**
* Called when a RecordedTextureData is forwarded to the compositor.
*/
void OnTextureForwarded();
/**
* @returns true if we should be caching data surfaces in the GPU process.
*/
bool ShouldCacheDataSurface() const {
return mTransactionsSinceGetDataSurface < kCacheDataSurfaceThreshold;
}
/**
* Ensures that we have sent a begin transaction event, since the last
* end transaction.
*/
void EnsureBeginTransaction();
/**
* Send an end transaction event to indicate the end of events for this frame.
*/
void EndTransaction();
/**
* Create a DrawTargetRecording for a canvas texture.
* @param aSize size for the DrawTarget
* @param aFormat SurfaceFormat for the DrawTarget
* @returns newly created DrawTargetRecording
*/
already_AddRefed<gfx::DrawTarget> CreateDrawTarget(
gfx::IntSize aSize, gfx::SurfaceFormat aFormat);
/**
* Record an event for processing by the CanvasParent's CanvasTranslator.
* @param aEvent the event to record
*/
void RecordEvent(const gfx::RecordedEvent& aEvent);
already_AddRefed<gfx::DataSourceSurface> GetDataSurface(
const gfx::SourceSurface* aSurface);
protected:
void ActorDestroy(ActorDestroyReason aWhy) final;
private:
DISALLOW_COPY_AND_ASSIGN(CanvasChild);
~CanvasChild() final;
static const uint32_t kCacheDataSurfaceThreshold = 10;
RefPtr<CanvasDrawEventRecorder> mRecorder;
TextureType mTextureType = TextureType::Unknown;
uint32_t mLastWriteLockCheckpoint = 0;
uint32_t mTransactionsSinceGetDataSurface = kCacheDataSurfaceThreshold;
bool mCanSend = false;
bool mIsInTransaction = false;
bool mHasOutstandingWriteLock = false;
};
} // namespace layers
} // namespace mozilla
#endif // mozilla_layers_CanvasChild_h

View File

@ -0,0 +1,125 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#include "CanvasParent.h"
#include "base/thread.h"
#include "mozilla/layers/SourceSurfaceSharedData.h"
#include "mozilla/layers/TextureClient.h"
#if defined(XP_WIN)
# include "mozilla/gfx/DeviceManagerDx.h"
# include "mozilla/layers/DeviceAttachmentsD3D11.h"
#endif
bool NS_IsInCanvasThread() {
return mozilla::layers::CanvasParent::IsInCanvasThread();
}
namespace mozilla {
namespace layers {
static base::Thread* sCanvasThread = nullptr;
static MessageLoop* CanvasPlaybackLoop() {
if (!sCanvasThread) {
MOZ_ASSERT(NS_IsInCompositorThread());
base::Thread* canvasThread = new base::Thread("Canvas");
if (canvasThread->Start()) {
sCanvasThread = canvasThread;
}
}
return sCanvasThread ? sCanvasThread->message_loop() : MessageLoop::current();
}
/* static */
already_AddRefed<CanvasParent> CanvasParent::Create(
ipc::Endpoint<PCanvasParent>&& aEndpoint) {
MOZ_ASSERT(NS_IsInCompositorThread());
RefPtr<CanvasParent> canvasParent = new CanvasParent();
if (CanvasPlaybackLoop()->IsAcceptingTasks()) {
RefPtr<Runnable> runnable = NewRunnableMethod<Endpoint<PCanvasParent>&&>(
"CanvasParent::Bind", canvasParent, &CanvasParent::Bind,
std::move(aEndpoint));
CanvasPlaybackLoop()->PostTask(runnable.forget());
}
return do_AddRef(canvasParent);
}
/* static */ bool CanvasParent::IsInCanvasThread() {
return sCanvasThread &&
sCanvasThread->thread_id() == PlatformThread::CurrentId();
}
/* static */ void CanvasParent::Shutdown() {
if (sCanvasThread) {
delete sCanvasThread;
sCanvasThread = nullptr;
}
}
CanvasParent::CanvasParent() {}
CanvasParent::~CanvasParent() {}
void CanvasParent::Bind(Endpoint<PCanvasParent>&& aEndpoint) {
if (!aEndpoint.Bind(this)) {
return;
}
mSelfRef = this;
}
mozilla::ipc::IPCResult CanvasParent::RecvCreateTranslator(
const TextureType& aTextureType,
const ipc::SharedMemoryBasic::Handle& aReadHandle,
const CrossProcessSemaphoreHandle& aReaderSem,
const CrossProcessSemaphoreHandle& aWriterSem) {
mTranslator = CanvasTranslator::Create(aTextureType, aReadHandle, aReaderSem,
aWriterSem);
return RecvResumeTranslation();
}
ipc::IPCResult CanvasParent::RecvResumeTranslation() {
MOZ_ASSERT(mTranslator);
if (!mTranslator->IsValid()) {
return IPC_FAIL(this, "Canvas Translation failed.");
}
PostStartTranslationTask();
return IPC_OK();
}
void CanvasParent::PostStartTranslationTask() {
if (MessageLoop::current()->IsAcceptingTasks()) {
RefPtr<Runnable> runnable =
NewRunnableMethod("CanvasParent::StartTranslation", this,
&CanvasParent::StartTranslation);
MessageLoop::current()->PostTask(runnable.forget());
}
}
void CanvasParent::StartTranslation() {
if (!mTranslator->TranslateRecording()) {
PostStartTranslationTask();
}
}
UniquePtr<SurfaceDescriptor>
CanvasParent::LookupSurfaceDescriptorForClientDrawTarget(
const uintptr_t aDrawTarget) {
return mTranslator->WaitForSurfaceDescriptor(
reinterpret_cast<void*>(aDrawTarget));
}
void CanvasParent::DeallocPCanvasParent() { mSelfRef = nullptr; }
} // namespace layers
} // namespace mozilla

View File

@ -0,0 +1,97 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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 https://mozilla.org/MPL/2.0/. */
#ifndef mozilla_layers_CanvasParent_h
#define mozilla_layers_CanvasParent_h
#include "mozilla/ipc/CrossProcessSemaphore.h"
#include "mozilla/layers/CanvasTranslator.h"
#include "mozilla/layers/PCanvasParent.h"
#include "mozilla/UniquePtr.h"
namespace mozilla {
namespace layers {
class TextureData;
class CanvasParent final : public PCanvasParent {
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CanvasParent)
friend class PProtocolParent;
/**
* Create a CanvasParent and bind it to the given endpoint on the
* CanvasPlaybackLoop.
*
* @params aEndpoint the endpoint to bind to
* @returns the new CanvasParent
*/
static already_AddRefed<CanvasParent> Create(
Endpoint<PCanvasParent>&& aEndpoint);
static bool IsInCanvasThread();
/**
* Shutdown the canvas thread.
*/
static void Shutdown();
/**
* Create a canvas translator for a particular TextureType, which translates
* events from a CanvasEventRingBuffer.
*
* @param aTextureType the TextureType the translator will create
* @param aReadHandle handle to the shared memory for the
* CanvasEventRingBuffer
* @param aReaderSem reading blocked semaphore for the CanvasEventRingBuffer
* @param aWriterSem writing blocked semaphore for the CanvasEventRingBuffer
*/
ipc::IPCResult RecvCreateTranslator(
const TextureType& aTextureType,
const ipc::SharedMemoryBasic::Handle& aReadHandle,
const CrossProcessSemaphoreHandle& aReaderSem,
const CrossProcessSemaphoreHandle& aWriterSem);
/**
* Used to tell the CanvasTranslator to start translating again after it has
* stopped due to a timeout waiting for events.
*/
ipc::IPCResult RecvResumeTranslation();
void ActorDestroy(ActorDestroyReason why) final {}
void DeallocPCanvasParent();
/**
* Used by the compositor thread to get the SurfaceDescriptor associated with
* the DrawTarget from another process.
*
* @param aDrawTarget the key to find the TextureData
* @returns the SurfaceDescriptor associated with the key
*/
UniquePtr<SurfaceDescriptor> LookupSurfaceDescriptorForClientDrawTarget(
const uintptr_t aDrawTarget);
private:
CanvasParent();
~CanvasParent() final;
DISALLOW_COPY_AND_ASSIGN(CanvasParent);
void Bind(Endpoint<PCanvasParent>&& aEndpoint);
void PostStartTranslationTask();
void StartTranslation();
RefPtr<CanvasParent> mSelfRef;
UniquePtr<CanvasTranslator> mTranslator;
};
} // namespace layers
} // namespace mozilla
#endif // mozilla_layers_CanvasParent_h

View File

@ -18,6 +18,7 @@
#include "mozilla/layers/APZChild.h"
#include "mozilla/layers/IAPZCTreeManager.h"
#include "mozilla/layers/APZCTreeManagerChild.h"
#include "mozilla/layers/CanvasChild.h"
#include "mozilla/layers/LayerTransactionChild.h"
#include "mozilla/layers/PaintThread.h"
#include "mozilla/layers/PLayerTransactionChild.h"
@ -117,6 +118,10 @@ void CompositorBridgeChild::AfterDestroy() {
mActorDestroyed = true;
}
if (mCanvasChild) {
mCanvasChild->Destroy();
}
if (sCompositorBridge == this) {
sCompositorBridge = nullptr;
}
@ -245,6 +250,18 @@ void CompositorBridgeChild::InitForContent(uint32_t aNamespace) {
mCanSend = true;
mIdNamespace = aNamespace;
if (gfx::gfxVars::RemoteCanvasEnabled()) {
ipc::Endpoint<PCanvasParent> parentEndpoint;
ipc::Endpoint<PCanvasChild> childEndpoint;
nsresult rv = PCanvas::CreateEndpoints(OtherPid(), base::GetCurrentProcId(),
&parentEndpoint, &childEndpoint);
if (NS_SUCCEEDED(rv)) {
Unused << SendInitPCanvasParent(std::move(parentEndpoint));
mCanvasChild = new CanvasChild(std::move(childEndpoint));
}
}
sCompositorBridge = this;
}
@ -918,6 +935,16 @@ PTextureChild* CompositorBridgeChild::CreateTexture(
LayersId{0} /* FIXME? */, aSerial, aExternalImageId);
}
already_AddRefed<CanvasChild> CompositorBridgeChild::GetCanvasChild() {
return do_AddRef(mCanvasChild);
}
void CompositorBridgeChild::EndCanvasTransaction() {
if (mCanvasChild) {
mCanvasChild->EndTransaction();
}
}
bool CompositorBridgeChild::AllocUnsafeShmem(
size_t aSize, ipc::SharedMemory::SharedMemoryType aType,
ipc::Shmem* aShmem) {

View File

@ -41,6 +41,7 @@ using mozilla::dom::BrowserChild;
class IAPZCTreeManager;
class APZCTreeManagerChild;
class CanvasChild;
class ClientLayerManager;
class CompositorBridgeParent;
class CompositorManagerChild;
@ -122,6 +123,10 @@ class CompositorBridgeChild final : public PCompositorBridgeChild,
wr::MaybeExternalImageId& aExternalImageId,
nsIEventTarget* aTarget) override;
already_AddRefed<CanvasChild> GetCanvasChild() final;
void EndCanvasTransaction();
/**
* Request that the parent tell us when graphics are ready on GPU.
* When we get that message, we bounce it to the BrowserParent via
@ -391,6 +396,8 @@ class CompositorBridgeChild final : public PCompositorBridgeChild,
uintptr_t mSlowFlushCount;
uintptr_t mTotalFlushCount;
RefPtr<CanvasChild> mCanvasChild;
};
} // namespace layers

View File

@ -2283,6 +2283,11 @@ bool CompositorBridgeParent::DeallocPTextureParent(PTextureParent* actor) {
return TextureHost::DestroyIPDLActor(actor);
}
mozilla::ipc::IPCResult CompositorBridgeParent::RecvInitPCanvasParent(
Endpoint<PCanvasParent>&& aEndpoint) {
MOZ_CRASH("PCanvasParent shouldn't be created via CompositorBridgeParent.");
}
bool CompositorBridgeParent::IsSameProcess() const {
return OtherPid() == base::GetCurrentProcId();
}

View File

@ -85,6 +85,7 @@ class PAPZParent;
class ContentCompositorBridgeParent;
class CompositorThreadHolder;
class InProcessCompositorSession;
class TextureData;
class WebRenderBridgeParent;
struct ScopedLayerTreeRegistration {
@ -188,6 +189,11 @@ class CompositorBridgeParentBase : public PCompositorBridgeParent,
virtual bool IsRemote() const { return false; }
virtual UniquePtr<SurfaceDescriptor>
LookupSurfaceDescriptorForClientDrawTarget(const uintptr_t aDrawTarget) {
MOZ_CRASH("Should only be called on ContentCompositorBridgeParent.");
}
virtual void ForceComposeToTarget(gfx::DrawTarget* aTarget,
const gfx::IntRect* aRect = nullptr) {
MOZ_CRASH();
@ -265,6 +271,8 @@ class CompositorBridgeParentBase : public PCompositorBridgeParent,
const uint32_t& startIndex, nsTArray<float>* intervals) = 0;
virtual mozilla::ipc::IPCResult RecvCheckContentOnlyTDR(
const uint32_t& sequenceNum, bool* isContentOnlyTDR) = 0;
virtual mozilla::ipc::IPCResult RecvInitPCanvasParent(
Endpoint<PCanvasParent>&& aEndpoint) = 0;
bool mCanSend;
@ -388,6 +396,9 @@ class CompositorBridgeParent final : public CompositorBridgeParentBase,
const wr::MaybeExternalImageId& aExternalImageId) override;
bool DeallocPTextureParent(PTextureParent* actor) override;
mozilla::ipc::IPCResult RecvInitPCanvasParent(
Endpoint<PCanvasParent>&& aEndpoint) final;
bool IsSameProcess() const override;
void NotifyWebRenderContextPurge();

View File

@ -7,6 +7,7 @@
#include "MainThreadUtils.h"
#include "nsThreadUtils.h"
#include "CompositorBridgeParent.h"
#include "mozilla/layers/CanvasParent.h"
#include "mozilla/layers/CompositorManagerParent.h"
#include "mozilla/layers/ImageBridgeParent.h"
#include "mozilla/media/MediaSystemResourceService.h"
@ -127,6 +128,7 @@ void CompositorThreadHolder::Shutdown() {
gfx::ReleaseVRManagerParentSingleton();
MediaSystemResourceService::Shutdown();
CompositorManagerParent::Shutdown();
CanvasParent::Shutdown();
sCompositorThreadHolder = nullptr;

View File

@ -22,6 +22,7 @@
#include "mozilla/layers/APZCTreeManagerParent.h" // for APZCTreeManagerParent
#include "mozilla/layers/APZUpdater.h" // for APZUpdater
#include "mozilla/layers/AsyncCompositionManager.h"
#include "mozilla/layers/CanvasParent.h"
#include "mozilla/layers/CompositorOptions.h"
#include "mozilla/layers/CompositorThread.h"
#include "mozilla/layers/LayerManagerComposite.h"
@ -614,6 +615,22 @@ bool ContentCompositorBridgeParent::DeallocPTextureParent(
return TextureHost::DestroyIPDLActor(actor);
}
mozilla::ipc::IPCResult ContentCompositorBridgeParent::RecvInitPCanvasParent(
Endpoint<PCanvasParent>&& aEndpoint) {
MOZ_RELEASE_ASSERT(!mCanvasParent,
"Canvas Parent should only be created once per "
"CrossProcessCompositorBridgeParent.");
mCanvasParent = CanvasParent::Create(std::move(aEndpoint));
return IPC_OK();
}
UniquePtr<SurfaceDescriptor>
ContentCompositorBridgeParent::LookupSurfaceDescriptorForClientDrawTarget(
const uintptr_t aDrawTarget) {
return mCanvasParent->LookupSurfaceDescriptorForClientDrawTarget(aDrawTarget);
}
bool ContentCompositorBridgeParent::IsSameProcess() const {
return OtherPid() == base::GetCurrentProcId();
}

View File

@ -9,10 +9,12 @@
#include "mozilla/layers/CompositorBridgeParent.h"
#include "mozilla/layers/CompositorThread.h"
#include "mozilla/UniquePtr.h"
namespace mozilla {
namespace layers {
class CanvasParent;
class CompositorOptions;
/**
@ -153,6 +155,9 @@ class ContentCompositorBridgeParent final : public CompositorBridgeParentBase {
bool DeallocPTextureParent(PTextureParent* actor) override;
mozilla::ipc::IPCResult RecvInitPCanvasParent(
Endpoint<PCanvasParent>&& aEndpoint) final;
bool IsSameProcess() const override;
PCompositorWidgetParent* AllocPCompositorWidgetParent(
@ -188,6 +193,9 @@ class ContentCompositorBridgeParent final : public CompositorBridgeParentBase {
bool IsRemote() const override { return true; }
UniquePtr<SurfaceDescriptor> LookupSurfaceDescriptorForClientDrawTarget(
const uintptr_t aDrawTarget) final;
private:
// Private destructor, to discourage deletion outside of Release():
virtual ~ContentCompositorBridgeParent();
@ -203,6 +211,8 @@ class ContentCompositorBridgeParent final : public CompositorBridgeParentBase {
// transaction is received
bool mNotifyAfterRemotePaint;
bool mDestroyCalled;
RefPtr<CanvasParent> mCanvasParent;
};
} // namespace layers

View File

@ -133,6 +133,10 @@ struct SurfaceDescriptorShared
Handle handle;
};
struct SurfaceDescriptorRecorded {
uintptr_t drawTarget;
};
union SurfaceDescriptor {
SurfaceDescriptorBuffer;
SurfaceDescriptorDIB;
@ -145,6 +149,7 @@ union SurfaceDescriptor {
SurfaceDescriptorMacIOSurface;
SurfaceDescriptorSharedGLTexture;
SurfaceDescriptorGPUVideo;
SurfaceDescriptorRecorded;
null_t;
};

View File

@ -0,0 +1,37 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: sw=2 ts=8 et : */
/* 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/. */
using mozilla::CrossProcessSemaphoreHandle from "mozilla/ipc/CrossProcessSemaphore.h";
using mozilla::layers::TextureType from "mozilla/layers/LayersTypes.h";
using mozilla::ipc::SharedMemoryBasic::Handle from "mozilla/ipc/SharedMemoryBasic.h";
namespace mozilla {
namespace layers {
/**
* PCanvas is the IPDL for recorded Canvas drawing.
*/
sync protocol PCanvas {
parent:
/**
* Create a CanvasTranslator for a particular TextureType, which translates
* events from a CanvasEventRingBuffer. aReadHandle is the shared memory
* handle for the ring buffer. aReaderSem and aWriterSem are handles for the
* semaphores to handle waiting on either side.
*/
async CreateTranslator(TextureType aTextureType, Handle aReadHandle,
CrossProcessSemaphoreHandle aReaderSem,
CrossProcessSemaphoreHandle aWriterSem);
/**
* Used to tell the CanvasTranslator to start translating again after it has
* stopped due to a timeout waiting for events.
*/
async ResumeTranslation();
};
} // layers
} // mozilla

View File

@ -11,6 +11,7 @@ include PlatformWidgetTypes;
include protocol PAPZ;
include protocol PAPZCTreeManager;
include protocol PBrowser;
include protocol PCanvas;
include protocol PCompositorManager;
include protocol PCompositorWidget;
include protocol PLayerTransaction;
@ -255,6 +256,8 @@ parent:
async PTexture(SurfaceDescriptor aSharedData, ReadLockDescriptor aReadLock, LayersBackend aBackend, TextureFlags aTextureFlags, LayersId id, uint64_t aSerial, MaybeExternalImageId aExternalImageId);
async InitPCanvasParent(Endpoint<PCanvasParent> aEndpoint);
sync SyncWithCompositor();
// The pipelineId is the same as the layersId

View File

@ -19,6 +19,7 @@ namespace ipc {
class IShmemAllocator;
}
namespace layers {
class CanvasChild;
/**
* An abstract interface for classes that implement the autogenerated
@ -78,6 +79,11 @@ class TextureForwarder : public LayersIPCChannel {
LayersBackend aLayersBackend, TextureFlags aFlags, uint64_t aSerial,
wr::MaybeExternalImageId& aExternalImageId,
nsIEventTarget* aTarget = nullptr) = 0;
/**
* Returns the CanvasChild for this TextureForwarder.
*/
virtual already_AddRefed<CanvasChild> GetCanvasChild() { return nullptr; };
};
} // namespace layers

View File

@ -130,7 +130,9 @@ EXPORTS.mozilla.layers += [
'basic/TextureHostBasic.h',
'BSPTree.h',
'BufferTexture.h',
'CanvasDrawEventRecorder.h',
'CanvasRenderer.h',
'CanvasTranslator.h',
'client/CanvasClient.h',
'client/CompositableClient.h',
'client/ContentClient.h',
@ -142,6 +144,7 @@ EXPORTS.mozilla.layers += [
'client/TextureClientPool.h',
'client/TextureClientRecycleAllocator.h',
'client/TextureClientSharedSurface.h',
'client/TextureRecorded.h',
'client/TiledContentClient.h',
'composite/AsyncCompositionManager.h',
'composite/CanvasLayerComposite.h',
@ -176,6 +179,8 @@ EXPORTS.mozilla.layers += [
'ipc/APZCTreeManagerParent.h',
'ipc/APZInputBridgeChild.h',
'ipc/APZInputBridgeParent.h',
'ipc/CanvasChild.h',
'ipc/CanvasParent.h',
'ipc/CompositableForwarder.h',
'ipc/CompositableTransactionParent.h',
'ipc/CompositorBridgeChild.h',
@ -371,7 +376,9 @@ UNIFIED_SOURCES += [
'basic/TextureHostBasic.cpp',
'BSPTree.cpp',
'BufferTexture.cpp',
'CanvasDrawEventRecorder.cpp',
'CanvasRenderer.cpp',
'CanvasTranslator.cpp',
'client/CanvasClient.cpp',
'client/ClientCanvasLayer.cpp',
'client/ClientCanvasRenderer.cpp',
@ -391,6 +398,7 @@ UNIFIED_SOURCES += [
'client/TextureClientPool.cpp',
'client/TextureClientRecycleAllocator.cpp',
'client/TextureClientSharedSurface.cpp',
'client/TextureRecorded.cpp',
'client/TiledContentClient.cpp',
'composite/AsyncCompositionManager.cpp',
'composite/CanvasLayerComposite.cpp',
@ -424,6 +432,8 @@ UNIFIED_SOURCES += [
'ipc/APZCTreeManagerParent.cpp',
'ipc/APZInputBridgeChild.cpp',
'ipc/APZInputBridgeParent.cpp',
'ipc/CanvasChild.cpp',
'ipc/CanvasParent.cpp',
'ipc/CompositableTransactionParent.cpp',
'ipc/CompositorBench.cpp',
'ipc/CompositorBridgeChild.cpp',
@ -540,6 +550,7 @@ IPDL_SOURCES += [
'ipc/PAPZ.ipdl',
'ipc/PAPZCTreeManager.ipdl',
'ipc/PAPZInputBridge.ipdl',
'ipc/PCanvas.ipdl',
'ipc/PCompositorBridge.ipdl',
'ipc/PCompositorManager.ipdl',
'ipc/PImageBridge.ipdl',

View File

@ -245,6 +245,8 @@ bool WebRenderLayerManager::EndEmptyTransaction(EndTransactionFlags aFlags) {
}
}
GetCompositorBridgeChild()->EndCanvasTransaction();
AutoTArray<RenderRootUpdates, wr::kRenderRootCount> renderRootUpdates;
for (auto& stateManager : mStateManagers) {
auto renderRoot = stateManager.GetRenderRoot();
@ -428,6 +430,8 @@ void WebRenderLayerManager::EndTransactionWithoutLayer(
}
}
GetCompositorBridgeChild()->EndCanvasTransaction();
{
AUTO_PROFILER_TRACING("Paint", "ForwardDPTransaction", GRAPHICS);
InfallibleTArray<RenderRootDisplayListData> renderRootDLs;

View File

@ -369,6 +369,8 @@ bool SpinEventLoopUntil(Pred&& aPredicate, nsIThread* aThread = nullptr) {
*/
extern bool NS_IsInCompositorThread();
extern bool NS_IsInCanvasThread();
extern bool NS_IsInVRThread();
//-----------------------------------------------------------------------------