2012-07-13 12:38:09 -07:00
|
|
|
/* -*- 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/. */
|
|
|
|
|
2012-08-29 05:24:48 -07:00
|
|
|
#include "base/thread.h"
|
|
|
|
|
2012-07-13 12:38:09 -07:00
|
|
|
#include "CompositorParent.h"
|
2012-08-29 05:24:48 -07:00
|
|
|
#include "ImageBridgeChild.h"
|
2012-07-13 12:38:09 -07:00
|
|
|
#include "ImageBridgeParent.h"
|
2012-08-29 05:24:48 -07:00
|
|
|
#include "ImageContainerChild.h"
|
2012-07-13 12:38:09 -07:00
|
|
|
#include "ImageLayers.h"
|
2012-08-29 05:24:48 -07:00
|
|
|
#include "gfxSharedImageSurface.h"
|
2012-08-17 03:56:55 -07:00
|
|
|
#include "mozilla/Monitor.h"
|
2012-07-13 12:38:09 -07:00
|
|
|
#include "mozilla/ReentrantMonitor.h"
|
|
|
|
#include "mozilla/layers/ShadowLayers.h"
|
2012-08-29 05:24:48 -07:00
|
|
|
#include "nsXULAppAPI.h"
|
2012-07-13 12:38:09 -07:00
|
|
|
|
|
|
|
using namespace base;
|
2012-08-29 05:24:48 -07:00
|
|
|
using namespace mozilla::ipc;
|
2012-07-13 12:38:09 -07:00
|
|
|
|
|
|
|
namespace mozilla {
|
|
|
|
namespace layers {
|
|
|
|
|
|
|
|
// Singleton
|
2012-07-30 07:20:58 -07:00
|
|
|
static ImageBridgeChild *sImageBridgeChildSingleton = nullptr;
|
|
|
|
static Thread *sImageBridgeChildThread = nullptr;
|
2012-07-13 12:38:09 -07:00
|
|
|
|
|
|
|
// 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();
|
|
|
|
|
|
|
|
int numChildren =
|
|
|
|
sImageBridgeChildSingleton->ManagedPImageContainerChild().Length();
|
|
|
|
for (int i = numChildren-1; i >= 0; --i) {
|
|
|
|
ImageContainerChild* ctn =
|
|
|
|
static_cast<ImageContainerChild*>(
|
|
|
|
sImageBridgeChildSingleton->ManagedPImageContainerChild()[i]);
|
|
|
|
ctn->StopChild();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*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.");
|
|
|
|
delete sImageBridgeChildSingleton;
|
2012-07-30 07:20:58 -07:00
|
|
|
sImageBridgeChildSingleton = nullptr;
|
2012-07-13 12:38:09 -07:00
|
|
|
*aDone = true;
|
|
|
|
aBarrier->NotifyAll();
|
|
|
|
}
|
|
|
|
|
|
|
|
// dispatched function
|
|
|
|
static void CreateContainerChildSync(nsRefPtr<ImageContainerChild>* result,
|
|
|
|
ReentrantMonitor* barrier,
|
|
|
|
bool *aDone)
|
|
|
|
{
|
|
|
|
ReentrantMonitorAutoEnter autoMon(*barrier);
|
|
|
|
*result = sImageBridgeChildSingleton->CreateImageContainerChildNow();
|
|
|
|
*aDone = true;
|
|
|
|
barrier->NotifyAll();
|
|
|
|
}
|
|
|
|
|
2012-08-17 03:56:55 -07:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
2012-07-13 12:38:09 -07:00
|
|
|
// dispatched function
|
|
|
|
static void ConnectImageBridge(ImageBridgeChild * child, ImageBridgeParent * parent)
|
|
|
|
{
|
|
|
|
MessageLoop *parentMsgLoop = parent->GetMessageLoop();
|
|
|
|
ipc::AsyncChannel *parentChannel = parent->GetIPCChannel();
|
|
|
|
child->Open(parentChannel, parentMsgLoop, mozilla::ipc::AsyncChannel::Child);
|
|
|
|
}
|
|
|
|
|
|
|
|
Thread* ImageBridgeChild::GetThread() const
|
|
|
|
{
|
|
|
|
return sImageBridgeChildThread;
|
|
|
|
}
|
|
|
|
|
|
|
|
ImageBridgeChild* ImageBridgeChild::GetSingleton()
|
|
|
|
{
|
|
|
|
return sImageBridgeChildSingleton;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ImageBridgeChild::IsCreated()
|
|
|
|
{
|
2012-07-30 07:20:58 -07:00
|
|
|
return GetSingleton() != nullptr;
|
2012-07-13 12:38:09 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void ImageBridgeChild::StartUp()
|
|
|
|
{
|
|
|
|
NS_ASSERTION(NS_IsMainThread(), "Should be on the main Thread!");
|
|
|
|
ImageBridgeChild::StartUpOnThread(new Thread("ImageBridgeChild"));
|
|
|
|
}
|
|
|
|
|
2012-08-29 05:24:48 -07:00
|
|
|
static void
|
|
|
|
ConnectImageBridgeInChildProcess(Transport* aTransport,
|
|
|
|
ProcessHandle aOtherProcess)
|
|
|
|
{
|
|
|
|
// Bind the IPC channel to the image bridge thread.
|
|
|
|
sImageBridgeChildSingleton->Open(aTransport, aOtherProcess,
|
|
|
|
XRE_GetIOMessageLoop(),
|
|
|
|
AsyncChannel::Child);
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
sImageBridgeChildSingleton = new ImageBridgeChild();
|
|
|
|
sImageBridgeChildSingleton->GetMessageLoop()->PostTask(
|
|
|
|
FROM_HERE,
|
|
|
|
NewRunnableFunction(ConnectImageBridgeInChildProcess,
|
|
|
|
aTransport, processHandle));
|
|
|
|
|
|
|
|
return sImageBridgeChildSingleton;
|
|
|
|
}
|
|
|
|
|
2012-07-13 12:38:09 -07:00
|
|
|
void ImageBridgeChild::ShutDown()
|
|
|
|
{
|
|
|
|
NS_ASSERTION(NS_IsMainThread(), "Should be on the main Thread!");
|
|
|
|
if (ImageBridgeChild::IsCreated()) {
|
|
|
|
ImageBridgeChild::DestroyBridge();
|
|
|
|
delete sImageBridgeChildThread;
|
2012-07-30 07:20:58 -07:00
|
|
|
sImageBridgeChildThread = nullptr;
|
2012-07-13 12:38:09 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ImageBridgeChild::StartUpOnThread(Thread* aThread)
|
|
|
|
{
|
|
|
|
NS_ABORT_IF_FALSE(aThread, "ImageBridge needs a thread.");
|
2012-07-30 07:20:58 -07:00
|
|
|
if (sImageBridgeChildSingleton == nullptr) {
|
2012-07-13 12:38:09 -07:00
|
|
|
sImageBridgeChildThread = aThread;
|
|
|
|
if (!aThread->IsRunning()) {
|
|
|
|
aThread->Start();
|
|
|
|
}
|
|
|
|
sImageBridgeChildSingleton = new ImageBridgeChild();
|
|
|
|
ImageBridgeParent* imageBridgeParent = new ImageBridgeParent(
|
2013-02-19 11:27:49 -08:00
|
|
|
CompositorParent::CompositorLoop(), nullptr);
|
2012-07-13 12:38:09 -07:00
|
|
|
sImageBridgeChildSingleton->ConnectAsync(imageBridgeParent);
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// Not needed, cf CreateImageContainerChildNow
|
2012-08-22 08:56:38 -07:00
|
|
|
PImageContainerChild* ImageBridgeChild::AllocPImageContainer(uint64_t* id)
|
2012-07-13 12:38:09 -07:00
|
|
|
{
|
|
|
|
NS_ABORT();
|
2012-07-30 07:20:58 -07:00
|
|
|
return nullptr;
|
2012-07-13 12:38:09 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
bool ImageBridgeChild::DeallocPImageContainer(PImageContainerChild* aImgContainerChild)
|
|
|
|
{
|
|
|
|
static_cast<ImageContainerChild*>(aImgContainerChild)->Release();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
|
|
|
already_AddRefed<ImageContainerChild> ImageBridgeChild::CreateImageContainerChild()
|
|
|
|
{
|
|
|
|
if (InImageBridgeChildThread()) {
|
|
|
|
return ImageBridgeChild::CreateImageContainerChildNow();
|
|
|
|
}
|
|
|
|
|
|
|
|
// ImageContainerChild can only be alocated on the ImageBridgeChild thread, so se
|
|
|
|
// dispatch a task to the thread and block the current thread until the task has been
|
|
|
|
// executed.
|
2012-07-30 07:20:58 -07:00
|
|
|
nsRefPtr<ImageContainerChild> result = nullptr;
|
2012-07-13 12:38:09 -07:00
|
|
|
|
|
|
|
ReentrantMonitor barrier("CreateImageContainerChild Lock");
|
|
|
|
ReentrantMonitorAutoEnter autoMon(barrier);
|
|
|
|
bool done = false;
|
|
|
|
|
|
|
|
GetMessageLoop()->PostTask(FROM_HERE, NewRunnableFunction(&CreateContainerChildSync,
|
|
|
|
&result, &barrier, &done));
|
|
|
|
|
|
|
|
// should stop the thread until the ImageContainerChild has been created on
|
|
|
|
// the other thread
|
|
|
|
while (!done) {
|
|
|
|
barrier.Wait();
|
|
|
|
}
|
|
|
|
return result.forget();
|
|
|
|
}
|
|
|
|
|
|
|
|
already_AddRefed<ImageContainerChild> ImageBridgeChild::CreateImageContainerChildNow()
|
|
|
|
{
|
|
|
|
nsRefPtr<ImageContainerChild> ctnChild = new ImageContainerChild();
|
2012-08-22 08:56:38 -07:00
|
|
|
uint64_t id = 0;
|
2012-07-13 12:38:09 -07:00
|
|
|
SendPImageContainerConstructor(ctnChild, &id);
|
|
|
|
ctnChild->SetID(id);
|
|
|
|
return ctnChild.forget();
|
|
|
|
}
|
|
|
|
|
2012-08-17 03:56:55 -07:00
|
|
|
PGrallocBufferChild*
|
|
|
|
ImageBridgeChild::AllocPGrallocBuffer(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::DeallocPGrallocBuffer(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, /* external */ 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
|
|
|
|
}
|
|
|
|
|
2012-07-13 12:38:09 -07:00
|
|
|
} // layers
|
|
|
|
} // mozilla
|