mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-26 06:11:37 +00:00
Bug 959089 - Part 1: Implement a new protocol for manage shared buffers' allocation. r=vlad, r=gal
This commit is contained in:
parent
7fdf15b4dd
commit
81e92dcc54
29
gfx/layers/ipc/PSharedBufferManager.ipdl
Normal file
29
gfx/layers/ipc/PSharedBufferManager.ipdl
Normal file
@ -0,0 +1,29 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
include LayersSurfaces;
|
||||
include ProtocolTypes;
|
||||
|
||||
include "mozilla/GfxMessageUtils.h";
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
/**
|
||||
* This is a dedicated protocol to track/allocate/deallocate gralloc buffers.
|
||||
*/
|
||||
|
||||
sync protocol PSharedBufferManager {
|
||||
parent:
|
||||
sync AllocateGrallocBuffer(IntSize size, uint32_t format, uint32_t usage)
|
||||
returns (MaybeMagicGrallocBufferHandle handle);
|
||||
both:
|
||||
async DropGrallocBuffer(MaybeMagicGrallocBufferHandle handle);
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
339
gfx/layers/ipc/SharedBufferManagerChild.cpp
Normal file
339
gfx/layers/ipc/SharedBufferManagerChild.cpp
Normal file
@ -0,0 +1,339 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
#include "base/task.h" // for NewRunnableFunction, etc
|
||||
#include "base/thread.h" // for Thread
|
||||
#include "base/tracked.h" // for FROM_HERE
|
||||
#include "mozilla/layers/SharedBufferManagerChild.h"
|
||||
#include "mozilla/layers/SharedBufferManagerParent.h"
|
||||
#include "mozilla/StaticPtr.h" // for StaticRefPtr
|
||||
#include "mozilla/ReentrantMonitor.h" // for ReentrantMonitor, etc
|
||||
#include "nsThreadUtils.h" // fo NS_IsMainThread
|
||||
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
#include "ipc/Nuwa.h"
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "SBMChild", ## args)
|
||||
#endif
|
||||
|
||||
using namespace mozilla::gfx;
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
// Singleton
|
||||
SharedBufferManagerChild* SharedBufferManagerChild::sSharedBufferManagerChildSingleton = nullptr;
|
||||
SharedBufferManagerParent* SharedBufferManagerChild::sSharedBufferManagerParentSingleton = nullptr;
|
||||
base::Thread* SharedBufferManagerChild::sSharedBufferManagerChildThread = nullptr;
|
||||
|
||||
SharedBufferManagerChild::SharedBufferManagerChild()
|
||||
#ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
|
||||
: mBufferMutex("BufferMonitor")
|
||||
#endif
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static bool
|
||||
InSharedBufferManagerChildThread()
|
||||
{
|
||||
return SharedBufferManagerChild::sSharedBufferManagerChildThread->thread_id() == PlatformThread::CurrentId();
|
||||
}
|
||||
|
||||
// dispatched function
|
||||
static void
|
||||
DeleteSharedBufferManagerSync(ReentrantMonitor *aBarrier, bool *aDone)
|
||||
{
|
||||
ReentrantMonitorAutoEnter autoMon(*aBarrier);
|
||||
|
||||
NS_ABORT_IF_FALSE(InSharedBufferManagerChildThread(),
|
||||
"Should be in SharedBufferManagerChild thread.");
|
||||
SharedBufferManagerChild::sSharedBufferManagerChildSingleton = nullptr;
|
||||
SharedBufferManagerChild::sSharedBufferManagerParentSingleton = nullptr;
|
||||
*aDone = true;
|
||||
aBarrier->NotifyAll();
|
||||
}
|
||||
|
||||
// dispatched function
|
||||
static void
|
||||
ConnectSharedBufferManager(SharedBufferManagerChild *child, SharedBufferManagerParent *parent)
|
||||
{
|
||||
MessageLoop *parentMsgLoop = parent->GetMessageLoop();
|
||||
ipc::MessageChannel *parentChannel = parent->GetIPCChannel();
|
||||
child->Open(parentChannel, parentMsgLoop, mozilla::ipc::ChildSide);
|
||||
}
|
||||
|
||||
base::Thread*
|
||||
SharedBufferManagerChild::GetThread() const
|
||||
{
|
||||
return sSharedBufferManagerChildThread;
|
||||
}
|
||||
|
||||
SharedBufferManagerChild*
|
||||
SharedBufferManagerChild::GetSingleton()
|
||||
{
|
||||
return sSharedBufferManagerChildSingleton;
|
||||
}
|
||||
|
||||
bool
|
||||
SharedBufferManagerChild::IsCreated()
|
||||
{
|
||||
return GetSingleton() != nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
SharedBufferManagerChild::StartUp()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Should be on the main Thread!");
|
||||
SharedBufferManagerChild::StartUpOnThread(new base::Thread("BufferMgrChild"));
|
||||
}
|
||||
|
||||
static void
|
||||
ConnectSharedBufferManagerInChildProcess(mozilla::ipc::Transport* aTransport,
|
||||
base::ProcessHandle aOtherProcess)
|
||||
{
|
||||
// Bind the IPC channel to the shared buffer manager thread.
|
||||
SharedBufferManagerChild::sSharedBufferManagerChildSingleton->Open(aTransport, aOtherProcess,
|
||||
XRE_GetIOMessageLoop(),
|
||||
ipc::ChildSide);
|
||||
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
if (IsNuwaProcess()) {
|
||||
SharedBufferManagerChild::sSharedBufferManagerChildThread
|
||||
->message_loop()->PostTask(FROM_HERE,
|
||||
NewRunnableFunction(NuwaMarkCurrentThread,
|
||||
(void (*)(void *))nullptr,
|
||||
(void *)nullptr));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
PSharedBufferManagerChild*
|
||||
SharedBufferManagerChild::StartUpInChildProcess(Transport* aTransport,
|
||||
base::ProcessId aOtherProcess)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Should be on the main Thread!");
|
||||
|
||||
ProcessHandle processHandle;
|
||||
if (!base::OpenProcessHandle(aOtherProcess, &processHandle)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
sSharedBufferManagerChildThread = new base::Thread("BufferMgrChild");
|
||||
if (!sSharedBufferManagerChildThread->Start()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
sSharedBufferManagerChildSingleton = new SharedBufferManagerChild();
|
||||
sSharedBufferManagerChildSingleton->GetMessageLoop()->PostTask(
|
||||
FROM_HERE,
|
||||
NewRunnableFunction(ConnectSharedBufferManagerInChildProcess,
|
||||
aTransport, processHandle));
|
||||
|
||||
return sSharedBufferManagerChildSingleton;
|
||||
}
|
||||
|
||||
void
|
||||
SharedBufferManagerChild::ShutDown()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Should be on the main Thread!");
|
||||
if (IsCreated()) {
|
||||
SharedBufferManagerChild::DestroyManager();
|
||||
delete sSharedBufferManagerChildThread;
|
||||
sSharedBufferManagerChildThread = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
SharedBufferManagerChild::StartUpOnThread(base::Thread* aThread)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(aThread, "SharedBufferManager needs a thread.");
|
||||
if (sSharedBufferManagerChildSingleton != nullptr)
|
||||
return false;
|
||||
|
||||
sSharedBufferManagerChildThread = aThread;
|
||||
if (!aThread->IsRunning()) {
|
||||
aThread->Start();
|
||||
}
|
||||
sSharedBufferManagerChildSingleton = new SharedBufferManagerChild();
|
||||
char thrname[128];
|
||||
base::snprintf(thrname, 128, "BufMgrParent#%d", base::Process::Current().pid());
|
||||
sSharedBufferManagerParentSingleton = new SharedBufferManagerParent(
|
||||
nullptr, base::Process::Current().pid(), new base::Thread(thrname));
|
||||
sSharedBufferManagerChildSingleton->ConnectAsync(sSharedBufferManagerParentSingleton);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
SharedBufferManagerChild::DestroyManager()
|
||||
{
|
||||
NS_ABORT_IF_FALSE(!InSharedBufferManagerChildThread(),
|
||||
"This method must not be called in this thread.");
|
||||
// ...because we are about to dispatch synchronous messages to the
|
||||
// BufferManagerChild thread.
|
||||
|
||||
if (!IsCreated()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ReentrantMonitor barrier("BufferManagerDestroyTask lock");
|
||||
ReentrantMonitorAutoEnter autoMon(barrier);
|
||||
|
||||
bool done = false;
|
||||
sSharedBufferManagerChildSingleton->GetMessageLoop()->PostTask(FROM_HERE,
|
||||
NewRunnableFunction(&DeleteSharedBufferManagerSync, &barrier, &done));
|
||||
while (!done) {
|
||||
barrier.Wait();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
MessageLoop *
|
||||
SharedBufferManagerChild::GetMessageLoop() const
|
||||
{
|
||||
return sSharedBufferManagerChildThread != nullptr ?
|
||||
sSharedBufferManagerChildThread->message_loop() :
|
||||
nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
SharedBufferManagerChild::ConnectAsync(SharedBufferManagerParent* aParent)
|
||||
{
|
||||
GetMessageLoop()->PostTask(FROM_HERE, NewRunnableFunction(&ConnectSharedBufferManager,
|
||||
this, aParent));
|
||||
}
|
||||
|
||||
// dispatched function
|
||||
void
|
||||
SharedBufferManagerChild::AllocGrallocBufferSync(const GrallocParam& aParam,
|
||||
Monitor* aBarrier,
|
||||
bool* aDone)
|
||||
{
|
||||
MonitorAutoLock autoMon(*aBarrier);
|
||||
|
||||
sSharedBufferManagerChildSingleton->AllocGrallocBufferNow(aParam.size,
|
||||
aParam.format,
|
||||
aParam.usage,
|
||||
aParam.buffer);
|
||||
*aDone = true;
|
||||
aBarrier->NotifyAll();
|
||||
}
|
||||
|
||||
// dispatched function
|
||||
void
|
||||
SharedBufferManagerChild::DeallocGrallocBufferSync(const mozilla::layers::MaybeMagicGrallocBufferHandle& aBuffer)
|
||||
{
|
||||
SharedBufferManagerChild::sSharedBufferManagerChildSingleton->
|
||||
DeallocGrallocBufferNow(aBuffer);
|
||||
}
|
||||
|
||||
bool
|
||||
SharedBufferManagerChild::AllocGrallocBuffer(const gfx::IntSize& aSize,
|
||||
const uint32_t& aFormat,
|
||||
const uint32_t& aUsage,
|
||||
mozilla::layers::MaybeMagicGrallocBufferHandle* aBuffer)
|
||||
{
|
||||
if (InSharedBufferManagerChildThread()) {
|
||||
return SharedBufferManagerChild::AllocGrallocBufferNow(aSize, aFormat, aUsage, aBuffer);
|
||||
}
|
||||
|
||||
Monitor barrier("AllocSurfaceDescriptorGralloc Lock");
|
||||
MonitorAutoLock autoMon(barrier);
|
||||
bool done = false;
|
||||
|
||||
GetMessageLoop()->PostTask(
|
||||
FROM_HERE,
|
||||
NewRunnableFunction(&AllocGrallocBufferSync,
|
||||
GrallocParam(aSize, aFormat, aUsage, aBuffer), &barrier, &done));
|
||||
|
||||
while (!done) {
|
||||
barrier.Wait();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
SharedBufferManagerChild::AllocGrallocBufferNow(const IntSize& aSize,
|
||||
const uint32_t& aFormat,
|
||||
const uint32_t& aUsage,
|
||||
mozilla::layers::MaybeMagicGrallocBufferHandle* aHandle)
|
||||
{
|
||||
#ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
|
||||
mozilla::layers::MaybeMagicGrallocBufferHandle handle;
|
||||
SendAllocateGrallocBuffer(aSize, aFormat, aUsage, &handle);
|
||||
if (handle.type() != mozilla::layers::MaybeMagicGrallocBufferHandle::TMagicGrallocBufferHandle)
|
||||
return false;
|
||||
*aHandle = handle.get_MagicGrallocBufferHandle().mRef;
|
||||
|
||||
{
|
||||
MutexAutoLock lock(mBufferMutex);
|
||||
mBuffers[handle.get_MagicGrallocBufferHandle().mRef.mKey] = handle.get_MagicGrallocBufferHandle().mGraphicBuffer;
|
||||
}
|
||||
return true;
|
||||
#else
|
||||
NS_RUNTIMEABORT("No GrallocBuffer for you");
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
SharedBufferManagerChild::DeallocGrallocBuffer(const mozilla::layers::MaybeMagicGrallocBufferHandle& aBuffer)
|
||||
{
|
||||
if (InSharedBufferManagerChildThread()) {
|
||||
return SharedBufferManagerChild::DeallocGrallocBufferNow(aBuffer);
|
||||
}
|
||||
|
||||
GetMessageLoop()->PostTask(FROM_HERE, NewRunnableFunction(&DeallocGrallocBufferSync,
|
||||
aBuffer));
|
||||
}
|
||||
|
||||
void
|
||||
SharedBufferManagerChild::DeallocGrallocBufferNow(const mozilla::layers::MaybeMagicGrallocBufferHandle& aBuffer)
|
||||
{
|
||||
#ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
|
||||
NS_ASSERTION(aBuffer.type() == mozilla::layers::MaybeMagicGrallocBufferHandle::TMagicGrallocBufferHandle, "We shouldn't trying to do IPC with real buffer");
|
||||
|
||||
{
|
||||
MutexAutoLock lock(mBufferMutex);
|
||||
mBuffers.erase(aBuffer.get_GrallocBufferRef().mKey);
|
||||
}
|
||||
SendDropGrallocBuffer(aBuffer);
|
||||
#else
|
||||
NS_RUNTIMEABORT("No GrallocBuffer for you");
|
||||
#endif
|
||||
}
|
||||
|
||||
bool SharedBufferManagerChild::RecvDropGrallocBuffer(const mozilla::layers::MaybeMagicGrallocBufferHandle& handle)
|
||||
{
|
||||
#ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
|
||||
NS_ASSERTION(handle.type() == mozilla::layers::MaybeMagicGrallocBufferHandle::TGrallocBufferRef, "shouldn't go this way");
|
||||
int bufferKey = handle.get_GrallocBufferRef().mKey;
|
||||
|
||||
{
|
||||
MutexAutoLock lock(mBufferMutex);
|
||||
NS_ASSERTION(mBuffers.count(bufferKey) != 0, "Not my buffer");
|
||||
mBuffers.erase(bufferKey);
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
|
||||
android::sp<android::GraphicBuffer>
|
||||
SharedBufferManagerChild::GetGraphicBuffer(int key)
|
||||
{
|
||||
MutexAutoLock lock(mBufferMutex);
|
||||
if (mBuffers.count(key) == 0)
|
||||
return nullptr;
|
||||
return mBuffers[key];
|
||||
}
|
||||
#endif
|
||||
|
||||
} /* namespace layers */
|
||||
} /* namespace mozilla */
|
165
gfx/layers/ipc/SharedBufferManagerChild.h
Normal file
165
gfx/layers/ipc/SharedBufferManagerChild.h
Normal file
@ -0,0 +1,165 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set sw=2 ts=8 et 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/. */
|
||||
|
||||
#ifndef SharedBufferManagerCHILD_H_
|
||||
#define SharedBufferManagerCHILD_H_
|
||||
|
||||
#include "mozilla/layers/PSharedBufferManagerChild.h"
|
||||
#ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
|
||||
#include "mozilla/Mutex.h"
|
||||
#endif
|
||||
|
||||
namespace base {
|
||||
class Thread;
|
||||
}
|
||||
|
||||
namespace mozilla {
|
||||
#ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
|
||||
class Mutex;
|
||||
#endif
|
||||
|
||||
namespace layers {
|
||||
class SharedBufferManagerParent;
|
||||
|
||||
struct GrallocParam {
|
||||
gfx::IntSize size;
|
||||
uint32_t format;
|
||||
uint32_t usage;
|
||||
mozilla::layers::MaybeMagicGrallocBufferHandle* buffer;
|
||||
|
||||
GrallocParam(const gfx::IntSize& aSize,
|
||||
const uint32_t& aFormat,
|
||||
const uint32_t& aUsage,
|
||||
mozilla::layers::MaybeMagicGrallocBufferHandle* aBuffer)
|
||||
: size(aSize)
|
||||
, format(aFormat)
|
||||
, usage(aUsage)
|
||||
, buffer(aBuffer)
|
||||
{}
|
||||
};
|
||||
|
||||
class SharedBufferManagerChild : public PSharedBufferManagerChild {
|
||||
public:
|
||||
SharedBufferManagerChild();
|
||||
/**
|
||||
* Creates the gralloc buffer manager with a dedicated thread for SharedBufferManagerChild.
|
||||
*
|
||||
* We may want to use a specific thread in the future. In this case, use
|
||||
* CreateWithThread instead.
|
||||
*/
|
||||
static void StartUp();
|
||||
|
||||
static PSharedBufferManagerChild*
|
||||
StartUpInChildProcess(Transport* aTransport, ProcessId aOtherProcess);
|
||||
|
||||
/**
|
||||
* Creates the SharedBufferManagerChild manager protocol.
|
||||
*/
|
||||
static bool StartUpOnThread(base::Thread* aThread);
|
||||
|
||||
/**
|
||||
* Destroys The SharedBufferManager protocol.
|
||||
*
|
||||
* The actual destruction happens synchronously on the SharedBufferManagerChild thread
|
||||
* which means that if this function is called from another thread, the current
|
||||
* thread will be paused until the destruction is done.
|
||||
*/
|
||||
static void DestroyManager();
|
||||
|
||||
/**
|
||||
* Destroys the grallob buffer manager calling DestroyManager, and destroys the
|
||||
* SharedBufferManager's thread.
|
||||
*
|
||||
* If you don't want to destroy the thread, call DestroyManager directly
|
||||
* instead.
|
||||
*/
|
||||
static void ShutDown();
|
||||
|
||||
/**
|
||||
* returns the singleton instance.
|
||||
*
|
||||
* can be called from any thread.
|
||||
*/
|
||||
static SharedBufferManagerChild* GetSingleton();
|
||||
|
||||
/**
|
||||
* Dispatches a task to the SharedBufferManagerChild thread to do the connection
|
||||
*/
|
||||
void ConnectAsync(SharedBufferManagerParent* aParent);
|
||||
|
||||
/**
|
||||
* Allocate GrallocBuffer remotely.
|
||||
*/
|
||||
bool
|
||||
AllocGrallocBuffer(const gfx::IntSize&, const uint32_t&, const uint32_t&, mozilla::layers::MaybeMagicGrallocBufferHandle*);
|
||||
|
||||
/**
|
||||
* Deallocate a remotely allocated gralloc buffer.
|
||||
* As gralloc buffer life cycle controlled by sp, this just break the sharing status of the underlying buffer
|
||||
* and decrease the reference count on both side.
|
||||
*/
|
||||
void
|
||||
DeallocGrallocBuffer(const mozilla::layers::MaybeMagicGrallocBufferHandle& aBuffer);
|
||||
|
||||
virtual bool RecvDropGrallocBuffer(const mozilla::layers::MaybeMagicGrallocBufferHandle& handle);
|
||||
|
||||
#ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
|
||||
android::sp<android::GraphicBuffer> GetGraphicBuffer(int index);
|
||||
#endif
|
||||
|
||||
base::Thread* GetThread() const;
|
||||
|
||||
MessageLoop* GetMessageLoop() const;
|
||||
|
||||
static bool IsCreated();
|
||||
|
||||
static base::Thread* sSharedBufferManagerChildThread;
|
||||
static SharedBufferManagerChild* sSharedBufferManagerChildSingleton;
|
||||
static SharedBufferManagerParent* sSharedBufferManagerParentSingleton; // Only available in Chrome process
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Part of the allocation of gralloc SurfaceDescriptor that is
|
||||
* executed on the SharedBufferManagerChild thread after invoking
|
||||
* AllocSurfaceDescriptorGralloc.
|
||||
*
|
||||
* Must be called from the SharedBufferManagerChild thread.
|
||||
*/
|
||||
bool
|
||||
AllocGrallocBufferNow(const gfx::IntSize& aSize,
|
||||
const uint32_t& aFormat,
|
||||
const uint32_t& aUsage,
|
||||
mozilla::layers::MaybeMagicGrallocBufferHandle* aBuffer);
|
||||
|
||||
// Dispatched function
|
||||
static void
|
||||
AllocGrallocBufferSync(const GrallocParam& aParam,
|
||||
Monitor* aBarrier,
|
||||
bool* aDone);
|
||||
|
||||
/**
|
||||
* Part of the deallocation of gralloc SurfaceDescriptor that is
|
||||
* executed on the SharedBufferManagerChild thread after invoking
|
||||
* DeallocSurfaceDescriptorGralloc.
|
||||
*
|
||||
* Must be called from the SharedBufferManagerChild thread.
|
||||
*/
|
||||
void
|
||||
DeallocGrallocBufferNow(const mozilla::layers::MaybeMagicGrallocBufferHandle& handle);
|
||||
|
||||
// dispatched function
|
||||
static void
|
||||
DeallocGrallocBufferSync(const mozilla::layers::MaybeMagicGrallocBufferHandle& handle);
|
||||
|
||||
#ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
|
||||
std::map<int, android::sp<android::GraphicBuffer> > mBuffers;
|
||||
Mutex mBufferMutex;
|
||||
#endif
|
||||
};
|
||||
|
||||
} /* namespace layers */
|
||||
} /* namespace mozilla */
|
||||
#endif /* SharedBufferManagerCHILD_H_*/
|
282
gfx/layers/ipc/SharedBufferManagerParent.cpp
Normal file
282
gfx/layers/ipc/SharedBufferManagerParent.cpp
Normal file
@ -0,0 +1,282 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set sw=2 ts=8 et 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 "mozilla/layers/SharedBufferManagerParent.h"
|
||||
#include "base/message_loop.h" // for MessageLoop
|
||||
#include "base/process.h" // for ProcessHandle
|
||||
#include "base/process_util.h" // for OpenProcessHandle
|
||||
#include "base/task.h" // for CancelableTask, DeleteTask, etc
|
||||
#include "base/tracked.h" // for FROM_HERE
|
||||
#include "base/thread.h"
|
||||
#include "mozilla/ipc/MessageChannel.h" // for MessageChannel, etc
|
||||
#include "mozilla/ipc/ProtocolUtils.h"
|
||||
#include "mozilla/ipc/Transport.h" // for Transport
|
||||
#include "nsIMemoryReporter.h"
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
#include "ui/PixelFormat.h"
|
||||
#endif
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
using namespace mozilla::ipc;
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
using android::sp;
|
||||
using android::GraphicBuffer;
|
||||
#endif
|
||||
using std::map;
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
class GrallocReporter MOZ_FINAL : public nsIMemoryReporter
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
GrallocReporter()
|
||||
{
|
||||
#ifdef DEBUG
|
||||
// There must be only one instance of this class, due to |sAmount|
|
||||
// being static. Assert this.
|
||||
static bool hasRun = false;
|
||||
MOZ_ASSERT(!hasRun);
|
||||
hasRun = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
|
||||
nsISupports* aData)
|
||||
{
|
||||
return MOZ_COLLECT_REPORT(
|
||||
"gralloc", KIND_OTHER, UNITS_BYTES, sAmount,
|
||||
"Special RAM that can be shared between processes and directly accessed by "
|
||||
"both the CPU and GPU. Gralloc memory is usually a relatively precious "
|
||||
"resource, with much less available than generic RAM. When it's exhausted, "
|
||||
"graphics performance can suffer. This value can be incorrect because of race "
|
||||
"conditions.");
|
||||
}
|
||||
|
||||
static int64_t sAmount;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(GrallocReporter, nsIMemoryReporter)
|
||||
|
||||
int64_t GrallocReporter::sAmount = 0;
|
||||
|
||||
void InitGralloc() {
|
||||
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
|
||||
RegisterStrongMemoryReporter(new GrallocReporter());
|
||||
}
|
||||
|
||||
map<base::ProcessId, SharedBufferManagerParent* > SharedBufferManagerParent::sManagers;
|
||||
StaticAutoPtr<Monitor> SharedBufferManagerParent::sManagerMonitor;
|
||||
int SharedBufferManagerParent::sBufferKey = 0;
|
||||
|
||||
SharedBufferManagerParent::SharedBufferManagerParent(Transport* aTransport, base::ProcessId aOwner, base::Thread* aThread)
|
||||
: mTransport(aTransport)
|
||||
, mThread(aThread)
|
||||
#ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
|
||||
, mBuffersMutex("BuffersMonitor")
|
||||
#endif
|
||||
{
|
||||
if (!sManagerMonitor)
|
||||
sManagerMonitor = new Monitor("Manager Monitor");
|
||||
|
||||
MonitorAutoLock lock(*sManagerMonitor.get());
|
||||
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread");
|
||||
if (!aThread->IsRunning())
|
||||
aThread->Start();
|
||||
mOwner = aOwner;
|
||||
sManagers[aOwner] = this;
|
||||
}
|
||||
|
||||
SharedBufferManagerParent::~SharedBufferManagerParent()
|
||||
{
|
||||
MonitorAutoLock lock(*sManagerMonitor.get());
|
||||
if (mTransport) {
|
||||
XRE_GetIOMessageLoop()->PostTask(FROM_HERE,
|
||||
new DeleteTask<Transport>(mTransport));
|
||||
}
|
||||
sManagers.erase(mOwner);
|
||||
delete mThread;
|
||||
}
|
||||
|
||||
void
|
||||
SharedBufferManagerParent::ActorDestroy(ActorDestroyReason aWhy)
|
||||
{
|
||||
#ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
|
||||
mBuffers.clear();
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
ConnectSharedBufferManagerInParentProcess(SharedBufferManagerParent* aManager,
|
||||
Transport* aTransport,
|
||||
base::ProcessHandle aOtherProcess)
|
||||
{
|
||||
aManager->Open(aTransport, aOtherProcess, XRE_GetIOMessageLoop(), ipc::ParentSide);
|
||||
}
|
||||
|
||||
PSharedBufferManagerParent* SharedBufferManagerParent::Create(Transport* aTransport, ProcessId aOtherProcess)
|
||||
{
|
||||
ProcessHandle processHandle;
|
||||
if (!base::OpenProcessHandle(aOtherProcess, &processHandle)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
base::Thread* thread = nullptr;
|
||||
if (sManagers.count(aOtherProcess) == 1) {
|
||||
thread = sManagers[aOtherProcess]->mThread;
|
||||
}
|
||||
else {
|
||||
char thrname[128];
|
||||
base::snprintf(thrname, 128, "BufMgrParent#%d", aOtherProcess);
|
||||
thread = new base::Thread(thrname);
|
||||
}
|
||||
SharedBufferManagerParent* manager = new SharedBufferManagerParent(aTransport, aOtherProcess, thread);
|
||||
if (!thread->IsRunning())
|
||||
thread->Start();
|
||||
thread->message_loop()->PostTask(FROM_HERE,
|
||||
NewRunnableFunction(ConnectSharedBufferManagerInParentProcess,
|
||||
manager, aTransport, processHandle));
|
||||
return manager;
|
||||
}
|
||||
|
||||
bool SharedBufferManagerParent::RecvAllocateGrallocBuffer(const IntSize& aSize, const uint32_t& aFormat, const uint32_t& aUsage, mozilla::layers::MaybeMagicGrallocBufferHandle* aHandle)
|
||||
{
|
||||
#ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
|
||||
sp<GraphicBuffer> outgoingBuffer = new GraphicBuffer(aSize.width, aSize.height, aFormat, aUsage);
|
||||
|
||||
GrallocBufferRef ref;
|
||||
ref.mOwner = mOwner;
|
||||
ref.mKey = ++sBufferKey;
|
||||
*aHandle = MagicGrallocBufferHandle(outgoingBuffer, ref);
|
||||
|
||||
int bpp = 0;
|
||||
bpp = android::bytesPerPixel(outgoingBuffer->getPixelFormat());
|
||||
if (bpp > 0)
|
||||
GrallocReporter::sAmount += outgoingBuffer->getStride() * outgoingBuffer->getHeight() * bpp;
|
||||
else // Specical case for BSP specific formats(mainly YUV formats, count it as normal YUV buffer)
|
||||
GrallocReporter::sAmount += outgoingBuffer->getStride() * outgoingBuffer->getHeight() * 3 / 2;
|
||||
|
||||
{
|
||||
MutexAutoLock lock(mBuffersMutex);
|
||||
mBuffers[sBufferKey] = outgoingBuffer;
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SharedBufferManagerParent::RecvDropGrallocBuffer(const mozilla::layers::MaybeMagicGrallocBufferHandle& handle)
|
||||
{
|
||||
#ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
|
||||
NS_ASSERTION(handle.type() == MaybeMagicGrallocBufferHandle::TGrallocBufferRef, "We shouldn't interact with the real buffer!");
|
||||
int bufferKey = handle.get_GrallocBufferRef().mKey;
|
||||
sp<GraphicBuffer> buf = GetGraphicBuffer(bufferKey);
|
||||
MutexAutoLock lock(mBuffersMutex);
|
||||
NS_ASSERTION(mBuffers.count(bufferKey) == 0, "How can you drop others buffer");
|
||||
mBuffers.erase(bufferKey);
|
||||
|
||||
int bpp = 0;
|
||||
bpp = android::bytesPerPixel(buf->getPixelFormat());
|
||||
if (bpp > 0)
|
||||
GrallocReporter::sAmount -= buf->getStride() * buf->getHeight() * bpp;
|
||||
else // Specical case for BSP specific formats(mainly YUV formats, count it as normal YUV buffer)
|
||||
GrallocReporter::sAmount -= buf->getStride() * buf->getHeight() * 3 / 2;
|
||||
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
void SharedBufferManagerParent::DropGrallocBufferSync(SharedBufferManagerParent* mgr, mozilla::layers::SurfaceDescriptor aDesc)
|
||||
{
|
||||
mgr->DropGrallocBufferImpl(aDesc);
|
||||
}
|
||||
|
||||
void SharedBufferManagerParent::DropGrallocBuffer(mozilla::layers::SurfaceDescriptor aDesc)
|
||||
{
|
||||
if (aDesc.type() != SurfaceDescriptor::TNewSurfaceDescriptorGralloc)
|
||||
return;
|
||||
|
||||
if (PlatformThread::CurrentId() == mThread->thread_id()) {
|
||||
DropGrallocBufferImpl(aDesc);
|
||||
} else {
|
||||
mThread->message_loop()->PostTask(FROM_HERE,
|
||||
NewRunnableFunction(&DropGrallocBufferSync, this, aDesc));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void SharedBufferManagerParent::DropGrallocBufferImpl(mozilla::layers::SurfaceDescriptor aDesc)
|
||||
{
|
||||
#ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
|
||||
MutexAutoLock lock(mBuffersMutex);
|
||||
int key = -1;
|
||||
MaybeMagicGrallocBufferHandle handle;
|
||||
if (aDesc.type() == SurfaceDescriptor::TNewSurfaceDescriptorGralloc)
|
||||
handle = aDesc.get_NewSurfaceDescriptorGralloc().buffer();
|
||||
else
|
||||
return;
|
||||
|
||||
if (handle.type() == MaybeMagicGrallocBufferHandle::TGrallocBufferRef)
|
||||
key = handle.get_GrallocBufferRef().mKey;
|
||||
else if (handle.type() == MaybeMagicGrallocBufferHandle::TMagicGrallocBufferHandle)
|
||||
key = handle.get_MagicGrallocBufferHandle().mRef.mKey;
|
||||
|
||||
NS_ASSERTION(key != -1, "Invalid buffer key");
|
||||
NS_ASSERTION(mBuffers.count(key) == 0, "How can you drop others buffer");
|
||||
mBuffers.erase(key);
|
||||
SendDropGrallocBuffer(handle);
|
||||
#endif
|
||||
}
|
||||
|
||||
MessageLoop* SharedBufferManagerParent::GetMessageLoop()
|
||||
{
|
||||
return mThread->message_loop();
|
||||
}
|
||||
|
||||
SharedBufferManagerParent* SharedBufferManagerParent::GetInstance(ProcessId id)
|
||||
{
|
||||
MonitorAutoLock lock(*sManagerMonitor.get());
|
||||
NS_ASSERTION(sManagers.count(id) == 0, "No BufferManager for the process");
|
||||
return sManagers[id];
|
||||
}
|
||||
|
||||
#ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
|
||||
android::sp<android::GraphicBuffer>
|
||||
SharedBufferManagerParent::GetGraphicBuffer(int key)
|
||||
{
|
||||
MutexAutoLock lock(mBuffersMutex);
|
||||
NS_ASSERTION(mBuffers.count(key) == 0, "No such buffer, or the buffer is belongs to other session");
|
||||
return mBuffers[key];
|
||||
}
|
||||
|
||||
android::sp<android::GraphicBuffer>
|
||||
SharedBufferManagerParent::GetGraphicBuffer(GrallocBufferRef aRef)
|
||||
{
|
||||
return GetInstance(aRef.mOwner)->GetGraphicBuffer(aRef.mKey);
|
||||
}
|
||||
#endif
|
||||
|
||||
IToplevelProtocol*
|
||||
SharedBufferManagerParent::CloneToplevel(const InfallibleTArray<ProtocolFdMapping>& aFds,
|
||||
base::ProcessHandle aPeerProcess,
|
||||
mozilla::ipc::ProtocolCloneContext* aCtx)
|
||||
{
|
||||
for (unsigned int i = 0; i < aFds.Length(); i++) {
|
||||
if (aFds[i].protocolId() == unsigned(GetProtocolId())) {
|
||||
Transport* transport = OpenDescriptor(aFds[i].fd(),
|
||||
Transport::MODE_SERVER);
|
||||
PSharedBufferManagerParent* bufferManager = Create(transport, base::GetProcId(aPeerProcess));
|
||||
bufferManager->CloneManagees(this, aCtx);
|
||||
bufferManager->IToplevelProtocol::SetTransport(transport);
|
||||
return bufferManager;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} /* namespace layers */
|
||||
} /* namespace mozilla */
|
109
gfx/layers/ipc/SharedBufferManagerParent.h
Normal file
109
gfx/layers/ipc/SharedBufferManagerParent.h
Normal file
@ -0,0 +1,109 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set sw=2 ts=8 et 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/. */
|
||||
|
||||
#ifndef SharedBufferManagerPARENT_H_
|
||||
#define SharedBufferManagerPARENT_H_
|
||||
|
||||
#include "mozilla/layers/PSharedBufferManagerParent.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
|
||||
#ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
|
||||
#include "mozilla/ipc/ProtocolUtils.h"
|
||||
#include "mozilla/Mutex.h" // for Mutex
|
||||
|
||||
namespace android {
|
||||
class GraphicBuffer;
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace base {
|
||||
class Thread;
|
||||
}
|
||||
|
||||
namespace mozilla {
|
||||
#ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
|
||||
class Mutex;
|
||||
#endif
|
||||
|
||||
namespace layers {
|
||||
|
||||
class SharedBufferManagerParent : public PSharedBufferManagerParent
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Create a SharedBufferManagerParent for child process, and link to the child side before leaving
|
||||
*/
|
||||
static PSharedBufferManagerParent* Create(Transport* aTransport, ProcessId aOtherProcess);
|
||||
|
||||
/**
|
||||
* Function for find the buffer owner, most buffer passing on IPC contains only owner/key pair.
|
||||
* Use these function to access the real buffer.
|
||||
*/
|
||||
static SharedBufferManagerParent* GetInstance(ProcessId id);
|
||||
#ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
|
||||
android::sp<android::GraphicBuffer> GetGraphicBuffer(int key);
|
||||
static android::sp<android::GraphicBuffer> GetGraphicBuffer(GrallocBufferRef aRef);
|
||||
#endif
|
||||
/**
|
||||
* Create a SharedBufferManagerParent but do not open the link
|
||||
*/
|
||||
SharedBufferManagerParent(Transport* aTransport, ProcessId aOwner, base::Thread* aThread);
|
||||
virtual ~SharedBufferManagerParent();
|
||||
|
||||
/**
|
||||
* When the IPC channel down or something bad make this Manager die, clear all the buffer reference!
|
||||
*/
|
||||
virtual void ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool RecvAllocateGrallocBuffer(const IntSize&, const uint32_t&, const uint32_t&, mozilla::layers::MaybeMagicGrallocBufferHandle*);
|
||||
virtual bool RecvDropGrallocBuffer(const mozilla::layers::MaybeMagicGrallocBufferHandle& handle);
|
||||
|
||||
/**
|
||||
* Break the buffer's sharing state, decrease buffer reference for both side
|
||||
*/
|
||||
void DropGrallocBuffer(mozilla::layers::SurfaceDescriptor aDesc);
|
||||
|
||||
// Overriden from IToplevelProtocol
|
||||
IToplevelProtocol*
|
||||
CloneToplevel(const InfallibleTArray<ProtocolFdMapping>& aFds,
|
||||
base::ProcessHandle aPeerProcess,
|
||||
mozilla::ipc::ProtocolCloneContext* aCtx) MOZ_OVERRIDE;
|
||||
MessageLoop* GetMessageLoop();
|
||||
|
||||
protected:
|
||||
/**
|
||||
* All living SharedBufferManager instances used to find the buffer owner, and parent->child IPCs
|
||||
*/
|
||||
static std::map<base::ProcessId, SharedBufferManagerParent*> sManagers;
|
||||
|
||||
/**
|
||||
* Break the buffer's sharing state, decrease buffer reference for both side
|
||||
*
|
||||
* Must be called from SharedBufferManagerParent's thread
|
||||
*/
|
||||
void DropGrallocBufferImpl(mozilla::layers::SurfaceDescriptor aDesc);
|
||||
|
||||
// dispatched function
|
||||
static void DropGrallocBufferSync(SharedBufferManagerParent* mgr, mozilla::layers::SurfaceDescriptor aDesc);
|
||||
|
||||
#ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
|
||||
/**
|
||||
* Buffers owned by this SharedBufferManager pair
|
||||
*/
|
||||
std::map<int, android::sp<android::GraphicBuffer> > mBuffers;
|
||||
Mutex mBuffersMutex;
|
||||
#endif
|
||||
|
||||
Transport* mTransport;
|
||||
base::ProcessId mOwner;
|
||||
base::Thread* mThread;
|
||||
static int sBufferKey;
|
||||
static StaticAutoPtr<Monitor> sManagerMonitor;
|
||||
};
|
||||
|
||||
} /* namespace layers */
|
||||
} /* namespace mozilla */
|
||||
#endif /* SharedBufferManagerPARENT_H_ */
|
Loading…
Reference in New Issue
Block a user