mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
f9166936cb
Backed out changeset 11ad8608bc27 (bug 897452) Backed out changeset 6bcc629e76f9 (bug 897452) Backed out changeset b91c858a43f5 (bug 897452) Backed out changeset 38ba49ee3e97 (bug 897452) Backed out changeset ea184ef84762 (bug 897452) Backed out changeset 686cc5122149 (bug 897452) Backed out changeset 3685a8018e49 (bug 897452) Backed out changeset be7ef6240068 (bug 897452) Backed out changeset f95c20e70947 (bug 897452) Backed out changeset 4a370d2a1c62 (bug 897452) Backed out changeset 1222f6ab66d2 (bug 897452) Backed out changeset 5e9d3c681ee9 (bug 897452) Backed out changeset 3b9ddce12b7a (bug 897452) Backed out changeset 7aec6387f3e9 (bug 897452) Backed out changeset eb1fe464fdaf (bug 897452) Backed out changeset 07deaa53b6fd (bug 897452) Backed out changeset ddab7d071d69 (bug 897452)
945 lines
28 KiB
C++
945 lines
28 KiB
C++
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
* 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 "ImageBridgeChild.h"
|
|
#include <vector> // for vector
|
|
#include "CompositorParent.h" // for CompositorParent
|
|
#include "ImageBridgeParent.h" // for ImageBridgeParent
|
|
#include "ImageContainer.h" // for ImageContainer
|
|
#include "Layers.h" // for Layer, etc
|
|
#include "ShadowLayers.h" // for ShadowLayerForwarder
|
|
#include "base/message_loop.h" // for MessageLoop
|
|
#include "base/platform_thread.h" // for PlatformThread
|
|
#include "base/process.h" // for ProcessHandle
|
|
#include "base/process_util.h" // for OpenProcessHandle
|
|
#include "base/task.h" // for NewRunnableFunction, etc
|
|
#include "base/thread.h" // for Thread
|
|
#include "base/tracked.h" // for FROM_HERE
|
|
#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
|
|
#include "mozilla/Monitor.h" // for Monitor, MonitorAutoLock
|
|
#include "mozilla/ReentrantMonitor.h" // for ReentrantMonitor, etc
|
|
#include "mozilla/ipc/MessageChannel.h" // for MessageChannel, etc
|
|
#include "mozilla/ipc/Transport.h" // for Transport
|
|
#include "mozilla/layers/CompositableClient.h" // for CompositableChild, etc
|
|
#include "mozilla/layers/ISurfaceAllocator.h" // for ISurfaceAllocator
|
|
#include "mozilla/layers/ImageClient.h" // for ImageClient
|
|
#include "mozilla/layers/LayersMessages.h" // for CompositableOperation
|
|
#include "mozilla/layers/PCompositableChild.h" // for PCompositableChild
|
|
#include "mozilla/layers/TextureClient.h" // for TextureClient
|
|
#include "mozilla/mozalloc.h" // for operator new, etc
|
|
#include "nsAutoPtr.h" // for nsRefPtr
|
|
#include "nsISupportsImpl.h" // for ImageContainer::AddRef, etc
|
|
#include "nsTArray.h" // for nsAutoTArray, nsTArray, etc
|
|
#include "nsTArrayForwardDeclare.h" // for AutoInfallibleTArray
|
|
#include "nsThreadUtils.h" // for NS_IsMainThread
|
|
#include "nsXULAppAPI.h" // for XRE_GetIOMessageLoop
|
|
#include "mozilla/StaticPtr.h" // for StaticRefPtr
|
|
|
|
struct nsIntRect;
|
|
|
|
using namespace base;
|
|
using namespace mozilla::ipc;
|
|
|
|
namespace mozilla {
|
|
namespace ipc {
|
|
class Shmem;
|
|
}
|
|
|
|
namespace layers {
|
|
|
|
class PGrallocBufferChild;
|
|
typedef std::vector<CompositableOperation> OpVector;
|
|
|
|
struct CompositableTransaction
|
|
{
|
|
CompositableTransaction()
|
|
: mSwapRequired(false)
|
|
, mFinished(true)
|
|
{}
|
|
~CompositableTransaction()
|
|
{
|
|
End();
|
|
}
|
|
bool Finished() const
|
|
{
|
|
return mFinished;
|
|
}
|
|
void Begin()
|
|
{
|
|
MOZ_ASSERT(mFinished);
|
|
mFinished = false;
|
|
}
|
|
void End()
|
|
{
|
|
mFinished = true;
|
|
mSwapRequired = false;
|
|
mOperations.clear();
|
|
}
|
|
bool IsEmpty() const
|
|
{
|
|
return mOperations.empty();
|
|
}
|
|
void AddNoSwapEdit(const CompositableOperation& op)
|
|
{
|
|
NS_ABORT_IF_FALSE(!Finished(), "forgot BeginTransaction?");
|
|
mOperations.push_back(op);
|
|
}
|
|
void AddEdit(const CompositableOperation& op)
|
|
{
|
|
AddNoSwapEdit(op);
|
|
mSwapRequired = true;
|
|
}
|
|
|
|
OpVector mOperations;
|
|
bool mSwapRequired;
|
|
bool mFinished;
|
|
};
|
|
|
|
struct AutoEndTransaction {
|
|
AutoEndTransaction(CompositableTransaction* aTxn) : mTxn(aTxn) {}
|
|
~AutoEndTransaction() { mTxn->End(); }
|
|
CompositableTransaction* mTxn;
|
|
};
|
|
|
|
bool
|
|
ImageBridgeChild::AddTexture(CompositableClient* aCompositable,
|
|
TextureClient* aTexture)
|
|
{
|
|
SurfaceDescriptor descriptor;
|
|
if (!aTexture->ToSurfaceDescriptor(descriptor)) {
|
|
NS_WARNING("ImageBridge: Failed to serialize a TextureClient");
|
|
return false;
|
|
}
|
|
mTxn->AddEdit(OpAddTexture(nullptr, aCompositable->GetIPDLActor(),
|
|
aTexture->GetID(),
|
|
descriptor,
|
|
aTexture->GetFlags()));
|
|
return true;
|
|
}
|
|
|
|
void
|
|
ImageBridgeChild::RemoveTexture(CompositableClient* aCompositable,
|
|
uint64_t aTexture,
|
|
TextureFlags aFlags)
|
|
{
|
|
if (aFlags & TEXTURE_DEALLOCATE_CLIENT) {
|
|
// if deallocation happens on the host side, we need the transaction
|
|
// to be synchronous.
|
|
mTxn->AddEdit(OpRemoveTexture(nullptr, aCompositable->GetIPDLActor(),
|
|
aTexture,
|
|
aFlags));
|
|
} else {
|
|
mTxn->AddNoSwapEdit(OpRemoveTexture(nullptr, aCompositable->GetIPDLActor(),
|
|
aTexture,
|
|
aFlags));
|
|
}
|
|
}
|
|
|
|
void
|
|
ImageBridgeChild::UseTexture(CompositableClient* aCompositable,
|
|
TextureClient* aTexture)
|
|
{
|
|
mTxn->AddNoSwapEdit(OpUseTexture(nullptr, aCompositable->GetIPDLActor(),
|
|
aTexture->GetID()));
|
|
}
|
|
|
|
void
|
|
ImageBridgeChild::UpdatedTexture(CompositableClient* aCompositable,
|
|
TextureClient* aTexture,
|
|
nsIntRegion* aRegion)
|
|
{
|
|
MaybeRegion region = aRegion ? MaybeRegion(*aRegion)
|
|
: MaybeRegion(null_t());
|
|
mTxn->AddNoSwapEdit(OpUpdateTexture(nullptr, aCompositable->GetIPDLActor(),
|
|
aTexture->GetID(),
|
|
region));
|
|
}
|
|
|
|
void
|
|
ImageBridgeChild::UpdateTexture(CompositableClient* aCompositable,
|
|
TextureIdentifier aTextureId,
|
|
SurfaceDescriptor* aDescriptor)
|
|
{
|
|
if (aDescriptor->type() != SurfaceDescriptor::T__None &&
|
|
aDescriptor->type() != SurfaceDescriptor::Tnull_t) {
|
|
MOZ_ASSERT(aCompositable);
|
|
MOZ_ASSERT(aCompositable->GetIPDLActor());
|
|
mTxn->AddEdit(OpPaintTexture(nullptr, aCompositable->GetIPDLActor(), 1,
|
|
SurfaceDescriptor(*aDescriptor)));
|
|
*aDescriptor = SurfaceDescriptor();
|
|
} else {
|
|
NS_WARNING("Trying to send a null SurfaceDescriptor.");
|
|
}
|
|
}
|
|
|
|
void
|
|
ImageBridgeChild::UpdateTextureNoSwap(CompositableClient* aCompositable,
|
|
TextureIdentifier aTextureId,
|
|
SurfaceDescriptor* aDescriptor)
|
|
{
|
|
if (aDescriptor->type() != SurfaceDescriptor::T__None &&
|
|
aDescriptor->type() != SurfaceDescriptor::Tnull_t) {
|
|
MOZ_ASSERT(aCompositable);
|
|
MOZ_ASSERT(aCompositable->GetIPDLActor());
|
|
mTxn->AddNoSwapEdit(OpPaintTexture(nullptr, aCompositable->GetIPDLActor(), 1,
|
|
SurfaceDescriptor(*aDescriptor)));
|
|
*aDescriptor = SurfaceDescriptor();
|
|
} else {
|
|
NS_WARNING("Trying to send a null SurfaceDescriptor.");
|
|
}
|
|
}
|
|
|
|
void
|
|
ImageBridgeChild::UpdatePictureRect(CompositableClient* aCompositable,
|
|
const nsIntRect& aRect)
|
|
{
|
|
mTxn->AddNoSwapEdit(OpUpdatePictureRect(nullptr, aCompositable->GetIPDLActor(), aRect));
|
|
}
|
|
|
|
// Singleton
|
|
static StaticRefPtr<ImageBridgeChild> sImageBridgeChildSingleton;
|
|
static StaticRefPtr<ImageBridgeParent> sImageBridgeParentSingleton;
|
|
static Thread *sImageBridgeChildThread = nullptr;
|
|
|
|
// dispatched function
|
|
static void StopImageBridgeSync(ReentrantMonitor *aBarrier, bool *aDone)
|
|
{
|
|
ReentrantMonitorAutoEnter autoMon(*aBarrier);
|
|
|
|
NS_ABORT_IF_FALSE(InImageBridgeChildThread(),
|
|
"Should be in ImageBridgeChild thread.");
|
|
if (sImageBridgeChildSingleton) {
|
|
|
|
sImageBridgeChildSingleton->SendStop();
|
|
}
|
|
*aDone = true;
|
|
aBarrier->NotifyAll();
|
|
}
|
|
|
|
// dispatched function
|
|
static void DeleteImageBridgeSync(ReentrantMonitor *aBarrier, bool *aDone)
|
|
{
|
|
ReentrantMonitorAutoEnter autoMon(*aBarrier);
|
|
|
|
NS_ABORT_IF_FALSE(InImageBridgeChildThread(),
|
|
"Should be in ImageBridgeChild thread.");
|
|
sImageBridgeChildSingleton = nullptr;
|
|
sImageBridgeParentSingleton = nullptr;
|
|
*aDone = true;
|
|
aBarrier->NotifyAll();
|
|
}
|
|
|
|
// dispatched function
|
|
static void CreateImageClientSync(RefPtr<ImageClient>* result,
|
|
ReentrantMonitor* barrier,
|
|
CompositableType aType,
|
|
bool *aDone)
|
|
{
|
|
ReentrantMonitorAutoEnter autoMon(*barrier);
|
|
*result = sImageBridgeChildSingleton->CreateImageClientNow(aType);
|
|
*aDone = true;
|
|
barrier->NotifyAll();
|
|
}
|
|
|
|
|
|
struct GrallocParam {
|
|
gfxIntSize size;
|
|
uint32_t format;
|
|
uint32_t usage;
|
|
SurfaceDescriptor* buffer;
|
|
|
|
GrallocParam(const gfxIntSize& aSize,
|
|
const uint32_t& aFormat,
|
|
const uint32_t& aUsage,
|
|
SurfaceDescriptor* aBuffer)
|
|
: size(aSize)
|
|
, format(aFormat)
|
|
, usage(aUsage)
|
|
, buffer(aBuffer)
|
|
{}
|
|
};
|
|
|
|
// dispatched function
|
|
static void AllocSurfaceDescriptorGrallocSync(const GrallocParam& aParam,
|
|
Monitor* aBarrier,
|
|
bool* aDone)
|
|
{
|
|
MonitorAutoLock autoMon(*aBarrier);
|
|
|
|
sImageBridgeChildSingleton->AllocSurfaceDescriptorGrallocNow(aParam.size,
|
|
aParam.format,
|
|
aParam.usage,
|
|
aParam.buffer);
|
|
*aDone = true;
|
|
aBarrier->NotifyAll();
|
|
}
|
|
|
|
// dispatched function
|
|
static void DeallocSurfaceDescriptorGrallocSync(const SurfaceDescriptor& aBuffer,
|
|
Monitor* aBarrier,
|
|
bool* aDone)
|
|
{
|
|
MonitorAutoLock autoMon(*aBarrier);
|
|
|
|
sImageBridgeChildSingleton->DeallocSurfaceDescriptorGrallocNow(aBuffer);
|
|
*aDone = true;
|
|
aBarrier->NotifyAll();
|
|
}
|
|
|
|
// dispatched function
|
|
static void ConnectImageBridge(ImageBridgeChild * child, ImageBridgeParent * parent)
|
|
{
|
|
MessageLoop *parentMsgLoop = parent->GetMessageLoop();
|
|
ipc::MessageChannel *parentChannel = parent->GetIPCChannel();
|
|
child->Open(parentChannel, parentMsgLoop, mozilla::ipc::ChildSide);
|
|
}
|
|
|
|
ImageBridgeChild::ImageBridgeChild()
|
|
{
|
|
mTxn = new CompositableTransaction();
|
|
}
|
|
ImageBridgeChild::~ImageBridgeChild()
|
|
{
|
|
delete mTxn;
|
|
}
|
|
|
|
void
|
|
ImageBridgeChild::Connect(CompositableClient* aCompositable)
|
|
{
|
|
MOZ_ASSERT(aCompositable);
|
|
uint64_t id = 0;
|
|
CompositableChild* child = static_cast<CompositableChild*>(
|
|
SendPCompositableConstructor(aCompositable->GetTextureInfo(), &id));
|
|
MOZ_ASSERT(child);
|
|
child->SetAsyncID(id);
|
|
aCompositable->SetIPDLActor(child);
|
|
MOZ_ASSERT(child->GetAsyncID() == id);
|
|
child->SetClient(aCompositable);
|
|
}
|
|
|
|
PCompositableChild*
|
|
ImageBridgeChild::AllocPCompositableChild(const TextureInfo& aInfo, uint64_t* aID)
|
|
{
|
|
return new CompositableChild();
|
|
}
|
|
|
|
bool
|
|
ImageBridgeChild::DeallocPCompositableChild(PCompositableChild* aActor)
|
|
{
|
|
delete aActor;
|
|
return true;
|
|
}
|
|
|
|
|
|
Thread* ImageBridgeChild::GetThread() const
|
|
{
|
|
return sImageBridgeChildThread;
|
|
}
|
|
|
|
ImageBridgeChild* ImageBridgeChild::GetSingleton()
|
|
{
|
|
return sImageBridgeChildSingleton;
|
|
}
|
|
|
|
bool ImageBridgeChild::IsCreated()
|
|
{
|
|
return GetSingleton() != nullptr;
|
|
}
|
|
|
|
void ImageBridgeChild::StartUp()
|
|
{
|
|
NS_ASSERTION(NS_IsMainThread(), "Should be on the main Thread!");
|
|
ImageBridgeChild::StartUpOnThread(new Thread("ImageBridgeChild"));
|
|
}
|
|
|
|
static void
|
|
ConnectImageBridgeInChildProcess(Transport* aTransport,
|
|
ProcessHandle aOtherProcess)
|
|
{
|
|
// Bind the IPC channel to the image bridge thread.
|
|
sImageBridgeChildSingleton->Open(aTransport, aOtherProcess,
|
|
XRE_GetIOMessageLoop(),
|
|
ipc::ChildSide);
|
|
}
|
|
|
|
#ifdef MOZ_NUWA_PROCESS
|
|
#include "ipc/Nuwa.h"
|
|
#endif
|
|
|
|
static void ReleaseImageClientNow(ImageClient* aClient)
|
|
{
|
|
MOZ_ASSERT(InImageBridgeChildThread());
|
|
aClient->Release();
|
|
}
|
|
|
|
// static
|
|
void ImageBridgeChild::DispatchReleaseImageClient(ImageClient* aClient)
|
|
{
|
|
sImageBridgeChildSingleton->GetMessageLoop()->PostTask(
|
|
FROM_HERE,
|
|
NewRunnableFunction(&ReleaseImageClientNow, aClient));
|
|
}
|
|
|
|
static void ReleaseTextureClientNow(TextureClient* aClient)
|
|
{
|
|
MOZ_ASSERT(InImageBridgeChildThread());
|
|
aClient->Release();
|
|
}
|
|
|
|
// static
|
|
void ImageBridgeChild::DispatchReleaseTextureClient(TextureClient* aClient)
|
|
{
|
|
sImageBridgeChildSingleton->GetMessageLoop()->PostTask(
|
|
FROM_HERE,
|
|
NewRunnableFunction(&ReleaseTextureClientNow, aClient));
|
|
}
|
|
|
|
static void UpdateImageClientNow(ImageClient* aClient, ImageContainer* aContainer)
|
|
{
|
|
MOZ_ASSERT(aClient);
|
|
MOZ_ASSERT(aContainer);
|
|
sImageBridgeChildSingleton->BeginTransaction();
|
|
aClient->UpdateImage(aContainer, Layer::CONTENT_OPAQUE);
|
|
aClient->OnTransaction();
|
|
sImageBridgeChildSingleton->EndTransaction();
|
|
}
|
|
|
|
//static
|
|
void ImageBridgeChild::DispatchImageClientUpdate(ImageClient* aClient,
|
|
ImageContainer* aContainer)
|
|
{
|
|
if (InImageBridgeChildThread()) {
|
|
UpdateImageClientNow(aClient, aContainer);
|
|
return;
|
|
}
|
|
sImageBridgeChildSingleton->GetMessageLoop()->PostTask(
|
|
FROM_HERE,
|
|
NewRunnableFunction<
|
|
void (*)(ImageClient*, ImageContainer*),
|
|
ImageClient*,
|
|
nsRefPtr<ImageContainer> >(&UpdateImageClientNow, aClient, aContainer));
|
|
}
|
|
|
|
static void FlushAllImagesSync(ImageClient* aClient, ImageContainer* aContainer, bool aExceptFront, ReentrantMonitor* aBarrier, bool* aDone)
|
|
{
|
|
ImageBridgeChild::FlushAllImagesNow(aClient, aContainer, aExceptFront);
|
|
|
|
ReentrantMonitorAutoEnter autoMon(*aBarrier);
|
|
*aDone = true;
|
|
aBarrier->NotifyAll();
|
|
}
|
|
|
|
//static
|
|
void ImageBridgeChild::FlushAllImages(ImageClient* aClient, ImageContainer* aContainer, bool aExceptFront)
|
|
{
|
|
if (InImageBridgeChildThread()) {
|
|
FlushAllImagesNow(aClient, aContainer, aExceptFront);
|
|
return;
|
|
}
|
|
|
|
ReentrantMonitor barrier("CreateImageClient Lock");
|
|
ReentrantMonitorAutoEnter autoMon(barrier);
|
|
bool done = false;
|
|
|
|
sImageBridgeChildSingleton->GetMessageLoop()->PostTask(
|
|
FROM_HERE,
|
|
NewRunnableFunction(&FlushAllImagesSync, aClient, aContainer, aExceptFront, &barrier, &done));
|
|
|
|
// should stop the thread until the ImageClient has been created on
|
|
// the other thread
|
|
while (!done) {
|
|
barrier.Wait();
|
|
}
|
|
}
|
|
|
|
//static
|
|
void ImageBridgeChild::FlushAllImagesNow(ImageClient* aClient, ImageContainer* aContainer, bool aExceptFront)
|
|
{
|
|
MOZ_ASSERT(aClient);
|
|
sImageBridgeChildSingleton->BeginTransaction();
|
|
if (aContainer && !aExceptFront) {
|
|
aContainer->ClearCurrentImage();
|
|
}
|
|
aClient->FlushAllImages(aExceptFront);
|
|
aClient->OnTransaction();
|
|
sImageBridgeChildSingleton->EndTransaction();
|
|
aClient->FlushTexturesToRemoveCallbacks();
|
|
}
|
|
|
|
void
|
|
ImageBridgeChild::BeginTransaction()
|
|
{
|
|
MOZ_ASSERT(mTxn->Finished(), "uncommitted txn?");
|
|
mTxn->Begin();
|
|
}
|
|
|
|
void
|
|
ImageBridgeChild::EndTransaction()
|
|
{
|
|
MOZ_ASSERT(!mTxn->Finished(), "forgot BeginTransaction?");
|
|
|
|
AutoEndTransaction _(mTxn);
|
|
|
|
if (mTxn->IsEmpty()) {
|
|
return;
|
|
}
|
|
|
|
AutoInfallibleTArray<CompositableOperation, 10> cset;
|
|
cset.SetCapacity(mTxn->mOperations.size());
|
|
if (!mTxn->mOperations.empty()) {
|
|
cset.AppendElements(&mTxn->mOperations.front(), mTxn->mOperations.size());
|
|
}
|
|
ShadowLayerForwarder::PlatformSyncBeforeUpdate();
|
|
|
|
AutoInfallibleTArray<EditReply, 10> replies;
|
|
|
|
if (mTxn->mSwapRequired) {
|
|
if (!SendUpdate(cset, &replies)) {
|
|
NS_WARNING("could not send async texture transaction");
|
|
return;
|
|
}
|
|
} else {
|
|
// If we don't require a swap we can call SendUpdateNoSwap which
|
|
// assumes that aReplies is empty (DEBUG assertion)
|
|
if (!SendUpdateNoSwap(cset)) {
|
|
NS_WARNING("could not send async texture transaction (no swap)");
|
|
return;
|
|
}
|
|
}
|
|
for (nsTArray<EditReply>::size_type i = 0; i < replies.Length(); ++i) {
|
|
const EditReply& reply = replies[i];
|
|
switch (reply.type()) {
|
|
case EditReply::TOpTextureSwap: {
|
|
const OpTextureSwap& ots = reply.get_OpTextureSwap();
|
|
|
|
CompositableChild* compositableChild =
|
|
static_cast<CompositableChild*>(ots.compositableChild());
|
|
|
|
MOZ_ASSERT(compositableChild);
|
|
|
|
compositableChild->GetCompositableClient()
|
|
->SetDescriptorFromReply(ots.textureId(), ots.image());
|
|
break;
|
|
}
|
|
case EditReply::TReplyTextureRemoved: {
|
|
// We receive this reply when a Texture is removed and when it is not
|
|
// the responsibility of the compositor side to deallocate memory.
|
|
// This would be, for instance, the place to implement a mechanism to
|
|
// notify the B2G camera that the gralloc buffer is not used by the
|
|
// compositor anymore and that it can be recycled.
|
|
const ReplyTextureRemoved& rep = reply.get_ReplyTextureRemoved();
|
|
CompositableClient* compositable
|
|
= static_cast<CompositableChild*>(rep.compositableChild())->GetCompositableClient();
|
|
compositable->OnReplyTextureRemoved(rep.textureId());
|
|
break;
|
|
}
|
|
default:
|
|
NS_RUNTIMEABORT("not reached");
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
PImageBridgeChild*
|
|
ImageBridgeChild::StartUpInChildProcess(Transport* aTransport,
|
|
ProcessId aOtherProcess)
|
|
{
|
|
NS_ASSERTION(NS_IsMainThread(), "Should be on the main Thread!");
|
|
|
|
ProcessHandle processHandle;
|
|
if (!base::OpenProcessHandle(aOtherProcess, &processHandle)) {
|
|
return nullptr;
|
|
}
|
|
|
|
sImageBridgeChildThread = new Thread("ImageBridgeChild");
|
|
if (!sImageBridgeChildThread->Start()) {
|
|
return nullptr;
|
|
}
|
|
|
|
#ifdef MOZ_NUWA_PROCESS
|
|
if (IsNuwaProcess()) {
|
|
sImageBridgeChildThread
|
|
->message_loop()->PostTask(FROM_HERE,
|
|
NewRunnableFunction(NuwaMarkCurrentThread,
|
|
(void (*)(void *))nullptr,
|
|
(void *)nullptr));
|
|
}
|
|
#endif
|
|
|
|
sImageBridgeChildSingleton = new ImageBridgeChild();
|
|
sImageBridgeChildSingleton->GetMessageLoop()->PostTask(
|
|
FROM_HERE,
|
|
NewRunnableFunction(ConnectImageBridgeInChildProcess,
|
|
aTransport, processHandle));
|
|
|
|
return sImageBridgeChildSingleton;
|
|
}
|
|
|
|
void ImageBridgeChild::ShutDown()
|
|
{
|
|
NS_ASSERTION(NS_IsMainThread(), "Should be on the main Thread!");
|
|
if (ImageBridgeChild::IsCreated()) {
|
|
ImageBridgeChild::DestroyBridge();
|
|
delete sImageBridgeChildThread;
|
|
sImageBridgeChildThread = nullptr;
|
|
}
|
|
}
|
|
|
|
bool ImageBridgeChild::StartUpOnThread(Thread* aThread)
|
|
{
|
|
NS_ABORT_IF_FALSE(aThread, "ImageBridge needs a thread.");
|
|
if (sImageBridgeChildSingleton == nullptr) {
|
|
sImageBridgeChildThread = aThread;
|
|
if (!aThread->IsRunning()) {
|
|
aThread->Start();
|
|
}
|
|
sImageBridgeChildSingleton = new ImageBridgeChild();
|
|
sImageBridgeParentSingleton = new ImageBridgeParent(
|
|
CompositorParent::CompositorLoop(), nullptr);
|
|
sImageBridgeChildSingleton->ConnectAsync(sImageBridgeParentSingleton);
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
void ImageBridgeChild::DestroyBridge()
|
|
{
|
|
NS_ABORT_IF_FALSE(!InImageBridgeChildThread(),
|
|
"This method must not be called in this thread.");
|
|
// ...because we are about to dispatch synchronous messages to the
|
|
// ImageBridgeChild thread.
|
|
|
|
if (!IsCreated()) {
|
|
return;
|
|
}
|
|
|
|
ReentrantMonitor barrier("ImageBridgeDestroyTask lock");
|
|
ReentrantMonitorAutoEnter autoMon(barrier);
|
|
|
|
bool done = false;
|
|
sImageBridgeChildSingleton->GetMessageLoop()->PostTask(FROM_HERE,
|
|
NewRunnableFunction(&StopImageBridgeSync, &barrier, &done));
|
|
while (!done) {
|
|
barrier.Wait();
|
|
}
|
|
|
|
done = false;
|
|
sImageBridgeChildSingleton->GetMessageLoop()->PostTask(FROM_HERE,
|
|
NewRunnableFunction(&DeleteImageBridgeSync, &barrier, &done));
|
|
while (!done) {
|
|
barrier.Wait();
|
|
}
|
|
|
|
}
|
|
|
|
bool InImageBridgeChildThread()
|
|
{
|
|
return sImageBridgeChildThread->thread_id() == PlatformThread::CurrentId();
|
|
}
|
|
|
|
MessageLoop * ImageBridgeChild::GetMessageLoop() const
|
|
{
|
|
return sImageBridgeChildThread->message_loop();
|
|
}
|
|
|
|
void ImageBridgeChild::ConnectAsync(ImageBridgeParent* aParent)
|
|
{
|
|
GetMessageLoop()->PostTask(FROM_HERE, NewRunnableFunction(&ConnectImageBridge,
|
|
this, aParent));
|
|
}
|
|
|
|
void
|
|
ImageBridgeChild::IdentifyCompositorTextureHost(const TextureFactoryIdentifier& aIdentifier)
|
|
{
|
|
if (sImageBridgeChildSingleton) {
|
|
sImageBridgeChildSingleton->IdentifyTextureHost(aIdentifier);
|
|
}
|
|
}
|
|
|
|
TemporaryRef<ImageClient>
|
|
ImageBridgeChild::CreateImageClient(CompositableType aType)
|
|
{
|
|
if (InImageBridgeChildThread()) {
|
|
return CreateImageClientNow(aType);
|
|
}
|
|
ReentrantMonitor barrier("CreateImageClient Lock");
|
|
ReentrantMonitorAutoEnter autoMon(barrier);
|
|
bool done = false;
|
|
|
|
RefPtr<ImageClient> result = nullptr;
|
|
GetMessageLoop()->PostTask(FROM_HERE, NewRunnableFunction(&CreateImageClientSync,
|
|
&result, &barrier, aType, &done));
|
|
// should stop the thread until the ImageClient has been created on
|
|
// the other thread
|
|
while (!done) {
|
|
barrier.Wait();
|
|
}
|
|
return result.forget();
|
|
}
|
|
|
|
TemporaryRef<ImageClient>
|
|
ImageBridgeChild::CreateImageClientNow(CompositableType aType)
|
|
{
|
|
RefPtr<ImageClient> client
|
|
= ImageClient::CreateImageClient(aType, this, 0);
|
|
MOZ_ASSERT(client, "failed to create ImageClient");
|
|
if (client) {
|
|
client->Connect();
|
|
}
|
|
return client.forget();
|
|
}
|
|
|
|
PGrallocBufferChild*
|
|
ImageBridgeChild::AllocPGrallocBufferChild(const gfxIntSize&, const uint32_t&, const uint32_t&,
|
|
MaybeMagicGrallocBufferHandle*)
|
|
{
|
|
#ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
|
|
return GrallocBufferActor::Create();
|
|
#else
|
|
NS_RUNTIMEABORT("No gralloc buffers for you");
|
|
return nullptr;
|
|
#endif
|
|
}
|
|
|
|
bool
|
|
ImageBridgeChild::DeallocPGrallocBufferChild(PGrallocBufferChild* actor)
|
|
{
|
|
#ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
|
|
delete actor;
|
|
return true;
|
|
#else
|
|
NS_RUNTIMEABORT("Um, how did we get here?");
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
bool
|
|
ImageBridgeChild::AllocSurfaceDescriptorGralloc(const gfxIntSize& aSize,
|
|
const uint32_t& aFormat,
|
|
const uint32_t& aUsage,
|
|
SurfaceDescriptor* aBuffer)
|
|
{
|
|
if (InImageBridgeChildThread()) {
|
|
return ImageBridgeChild::AllocSurfaceDescriptorGrallocNow(aSize, aFormat, aUsage, aBuffer);
|
|
}
|
|
|
|
Monitor barrier("AllocSurfaceDescriptorGralloc Lock");
|
|
MonitorAutoLock autoMon(barrier);
|
|
bool done = false;
|
|
|
|
GetMessageLoop()->PostTask(
|
|
FROM_HERE,
|
|
NewRunnableFunction(&AllocSurfaceDescriptorGrallocSync,
|
|
GrallocParam(aSize, aFormat, aUsage, aBuffer), &barrier, &done));
|
|
|
|
while (!done) {
|
|
barrier.Wait();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
ImageBridgeChild::AllocSurfaceDescriptorGrallocNow(const gfxIntSize& aSize,
|
|
const uint32_t& aFormat,
|
|
const uint32_t& aUsage,
|
|
SurfaceDescriptor* aBuffer)
|
|
{
|
|
#ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
|
|
MaybeMagicGrallocBufferHandle handle;
|
|
PGrallocBufferChild* gc = SendPGrallocBufferConstructor(aSize, aFormat, aUsage, &handle);
|
|
if (handle.Tnull_t == handle.type()) {
|
|
PGrallocBufferChild::Send__delete__(gc);
|
|
return false;
|
|
}
|
|
|
|
GrallocBufferActor* gba = static_cast<GrallocBufferActor*>(gc);
|
|
gba->InitFromHandle(handle.get_MagicGrallocBufferHandle());
|
|
|
|
*aBuffer = SurfaceDescriptorGralloc(nullptr, gc, aSize, /* external */ false, /* swapRB */ false);
|
|
return true;
|
|
#else
|
|
NS_RUNTIMEABORT("No gralloc buffers for you");
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
bool
|
|
ImageBridgeChild::DeallocSurfaceDescriptorGralloc(const SurfaceDescriptor& aBuffer)
|
|
{
|
|
if (InImageBridgeChildThread()) {
|
|
return ImageBridgeChild::DeallocSurfaceDescriptorGrallocNow(aBuffer);
|
|
}
|
|
|
|
Monitor barrier("DeallocSurfaceDescriptor Lock");
|
|
MonitorAutoLock autoMon(barrier);
|
|
bool done = false;
|
|
|
|
GetMessageLoop()->PostTask(FROM_HERE, NewRunnableFunction(&DeallocSurfaceDescriptorGrallocSync,
|
|
aBuffer, &barrier, &done));
|
|
|
|
while (!done) {
|
|
barrier.Wait();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
ImageBridgeChild::DeallocSurfaceDescriptorGrallocNow(const SurfaceDescriptor& aBuffer)
|
|
{
|
|
#ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
|
|
PGrallocBufferChild* gbp =
|
|
aBuffer.get_SurfaceDescriptorGralloc().bufferChild();
|
|
PGrallocBufferChild::Send__delete__(gbp);
|
|
|
|
return true;
|
|
#else
|
|
NS_RUNTIMEABORT("Um, how did we get here?");
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
bool
|
|
ImageBridgeChild::AllocUnsafeShmem(size_t aSize,
|
|
ipc::SharedMemory::SharedMemoryType aType,
|
|
ipc::Shmem* aShmem)
|
|
{
|
|
if (InImageBridgeChildThread()) {
|
|
return PImageBridgeChild::AllocUnsafeShmem(aSize, aType, aShmem);
|
|
} else {
|
|
return DispatchAllocShmemInternal(aSize, aType, aShmem, true); // true: unsafe
|
|
}
|
|
}
|
|
|
|
bool
|
|
ImageBridgeChild::AllocShmem(size_t aSize,
|
|
ipc::SharedMemory::SharedMemoryType aType,
|
|
ipc::Shmem* aShmem)
|
|
{
|
|
if (InImageBridgeChildThread()) {
|
|
return PImageBridgeChild::AllocShmem(aSize, aType, aShmem);
|
|
} else {
|
|
return DispatchAllocShmemInternal(aSize, aType, aShmem, false); // false: unsafe
|
|
}
|
|
}
|
|
|
|
// NewRunnableFunction accepts a limited number of parameters so we need a
|
|
// struct here
|
|
struct AllocShmemParams {
|
|
RefPtr<ISurfaceAllocator> mAllocator;
|
|
size_t mSize;
|
|
ipc::SharedMemory::SharedMemoryType mType;
|
|
ipc::Shmem* mShmem;
|
|
bool mUnsafe;
|
|
bool mSuccess;
|
|
};
|
|
|
|
static void ProxyAllocShmemNow(AllocShmemParams* aParams,
|
|
ReentrantMonitor* aBarrier,
|
|
bool* aDone)
|
|
{
|
|
MOZ_ASSERT(aParams);
|
|
MOZ_ASSERT(aDone);
|
|
MOZ_ASSERT(aBarrier);
|
|
|
|
if (aParams->mUnsafe) {
|
|
aParams->mSuccess = aParams->mAllocator->AllocUnsafeShmem(aParams->mSize,
|
|
aParams->mType,
|
|
aParams->mShmem);
|
|
} else {
|
|
aParams->mSuccess = aParams->mAllocator->AllocShmem(aParams->mSize,
|
|
aParams->mType,
|
|
aParams->mShmem);
|
|
}
|
|
|
|
ReentrantMonitorAutoEnter autoMon(*aBarrier);
|
|
*aDone = true;
|
|
aBarrier->NotifyAll();
|
|
}
|
|
|
|
bool
|
|
ImageBridgeChild::DispatchAllocShmemInternal(size_t aSize,
|
|
SharedMemory::SharedMemoryType aType,
|
|
ipc::Shmem* aShmem,
|
|
bool aUnsafe)
|
|
{
|
|
ReentrantMonitor barrier("AllocatorProxy alloc");
|
|
ReentrantMonitorAutoEnter autoMon(barrier);
|
|
|
|
AllocShmemParams params = {
|
|
this, aSize, aType, aShmem, aUnsafe, true
|
|
};
|
|
bool done = false;
|
|
|
|
GetMessageLoop()->PostTask(FROM_HERE,
|
|
NewRunnableFunction(&ProxyAllocShmemNow,
|
|
¶ms,
|
|
&barrier,
|
|
&done));
|
|
while (!done) {
|
|
barrier.Wait();
|
|
}
|
|
return params.mSuccess;
|
|
}
|
|
|
|
static void ProxyDeallocShmemNow(ISurfaceAllocator* aAllocator,
|
|
ipc::Shmem* aShmem,
|
|
ReentrantMonitor* aBarrier,
|
|
bool* aDone)
|
|
{
|
|
MOZ_ASSERT(aShmem);
|
|
MOZ_ASSERT(aDone);
|
|
MOZ_ASSERT(aBarrier);
|
|
|
|
aAllocator->DeallocShmem(*aShmem);
|
|
|
|
ReentrantMonitorAutoEnter autoMon(*aBarrier);
|
|
*aDone = true;
|
|
aBarrier->NotifyAll();
|
|
}
|
|
|
|
void
|
|
ImageBridgeChild::DeallocShmem(ipc::Shmem& aShmem)
|
|
{
|
|
if (InImageBridgeChildThread()) {
|
|
PImageBridgeChild::DeallocShmem(aShmem);
|
|
} else {
|
|
ReentrantMonitor barrier("AllocatorProxy Dealloc");
|
|
ReentrantMonitorAutoEnter autoMon(barrier);
|
|
|
|
bool done = false;
|
|
GetMessageLoop()->PostTask(FROM_HERE,
|
|
NewRunnableFunction(&ProxyDeallocShmemNow,
|
|
this,
|
|
&aShmem,
|
|
&barrier,
|
|
&done));
|
|
while (!done) {
|
|
barrier.Wait();
|
|
}
|
|
}
|
|
}
|
|
|
|
PGrallocBufferChild*
|
|
ImageBridgeChild::AllocGrallocBuffer(const gfxIntSize& aSize,
|
|
uint32_t aFormat,
|
|
uint32_t aUsage,
|
|
MaybeMagicGrallocBufferHandle* aHandle)
|
|
{
|
|
#ifdef MOZ_WIDGET_GONK
|
|
return SendPGrallocBufferConstructor(aSize,
|
|
aFormat,
|
|
aUsage,
|
|
aHandle);
|
|
#else
|
|
NS_RUNTIMEABORT("not implemented");
|
|
return nullptr;
|
|
#endif
|
|
}
|
|
|
|
} // layers
|
|
} // mozilla
|