Bug 957323 - Handle android's fence on gonk r=nical,doublec,pchang

This commit is contained in:
Sotaro Ikeda 2014-02-24 20:23:41 -08:00
parent 4ef6fc1b7b
commit c0ff94d478
31 changed files with 654 additions and 77 deletions

View File

@ -15,6 +15,9 @@
#include <stagefright/OMXClient.h>
#include <stagefright/OMXCodec.h>
#include <OMX.h>
#if MOZ_WIDGET_GONK && ANDROID_VERSION >= 18
#include <ui/Fence.h>
#endif
#include "mozilla/Preferences.h"
#include "mozilla/Types.h"
@ -213,7 +216,7 @@ VideoGraphicBuffer::Unlock()
// The message is delivered to OmxDecoder on ALooper thread.
// MediaBuffer::release() could take a very long time.
// PostReleaseVideoBuffer() prevents long time locking.
omxDecoder->PostReleaseVideoBuffer(mMediaBuffer);
omxDecoder->PostReleaseVideoBuffer(mMediaBuffer, mReleaseFenceHandle);
} else {
NS_WARNING("OmxDecoder is not present");
if (mMediaBuffer) {
@ -794,7 +797,7 @@ bool OmxDecoder::ReadVideo(VideoFrame *aFrame, int64_t aTimeUs,
{
Mutex::Autolock autoLock(mSeekLock);
mIsVideoSeeking = false;
ReleaseAllPendingVideoBuffersLocked();
PostReleaseVideoBuffer(nullptr, FenceHandle());
}
aDoSeek = false;
@ -841,6 +844,9 @@ bool OmxDecoder::ReadVideo(VideoFrame *aFrame, int64_t aTimeUs,
aFrame->mKeyFrame = keyFrame;
aFrame->Y.mWidth = mVideoWidth;
aFrame->Y.mHeight = mVideoHeight;
// Release to hold video buffer in OmxDecoder more.
// MediaBuffer's ref count is changed from 2 to 1.
ReleaseVideoBuffer();
} else if (mVideoBuffer->range_length() > 0) {
char *data = static_cast<char *>(mVideoBuffer->data()) + mVideoBuffer->range_offset();
size_t length = mVideoBuffer->range_length();
@ -1022,11 +1028,13 @@ void OmxDecoder::onMessageReceived(const sp<AMessage> &msg)
}
}
void OmxDecoder::PostReleaseVideoBuffer(MediaBuffer *aBuffer)
void OmxDecoder::PostReleaseVideoBuffer(MediaBuffer *aBuffer, const FenceHandle& aReleaseFenceHandle)
{
{
Mutex::Autolock autoLock(mPendingVideoBuffersLock);
mPendingVideoBuffers.push(aBuffer);
if (aBuffer) {
mPendingVideoBuffers.push(BufferItem(aBuffer, aReleaseFenceHandle));
}
}
sp<AMessage> notify =
@ -1037,14 +1045,13 @@ void OmxDecoder::PostReleaseVideoBuffer(MediaBuffer *aBuffer)
void OmxDecoder::ReleaseAllPendingVideoBuffersLocked()
{
Vector<MediaBuffer *> releasingVideoBuffers;
Vector<BufferItem> releasingVideoBuffers;
{
Mutex::Autolock autoLock(mPendingVideoBuffersLock);
int size = mPendingVideoBuffers.size();
for (int i = 0; i < size; i++) {
MediaBuffer *buffer = mPendingVideoBuffers[i];
releasingVideoBuffers.push(buffer);
releasingVideoBuffers.push(mPendingVideoBuffers[i]);
}
mPendingVideoBuffers.clear();
}
@ -1052,7 +1059,28 @@ void OmxDecoder::ReleaseAllPendingVideoBuffersLocked()
int size = releasingVideoBuffers.size();
for (int i = 0; i < size; i++) {
MediaBuffer *buffer;
buffer = releasingVideoBuffers[i];
buffer = releasingVideoBuffers[i].mMediaBuffer;
#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 18
android::sp<Fence> fence;
int fenceFd = -1;
fence = releasingVideoBuffers[i].mReleaseFenceHandle.mFence;
if (fence.get() && fence->isValid()) {
fenceFd = fence->dup();
}
MOZ_ASSERT(buffer->refcount() == 1);
// This code expect MediaBuffer's ref count is 1.
// Return gralloc buffer to ANativeWindow
ANativeWindow* window = static_cast<ANativeWindow*>(mNativeWindowClient.get());
window->cancelBuffer(window,
buffer->graphicBuffer().get(),
fenceFd);
// Mark MediaBuffer as rendered.
// When gralloc buffer is directly returned to ANativeWindow,
// this mark is necesary.
sp<MetaData> metaData = buffer->meta_data();
metaData->setInt32(kKeyRendered, 1);
#endif
// Return MediaBuffer to OMXCodec.
buffer->release();
}
releasingVideoBuffers.clear();

View File

@ -10,6 +10,7 @@
#include "GonkNativeWindow.h"
#include "GonkNativeWindowClient.h"
#include "GrallocImages.h"
#include "mozilla/layers/FenceUtils.h"
#include "MP3FrameParser.h"
#include "MPAPI.h"
#include "MediaResource.h"
@ -83,6 +84,7 @@ class OmxDecoder : public OMXCodecProxy::EventListener {
typedef mozilla::MP3FrameParser MP3FrameParser;
typedef mozilla::MediaResource MediaResource;
typedef mozilla::AbstractMediaDecoder AbstractMediaDecoder;
typedef mozilla::layers::FenceHandle FenceHandle;
enum {
kPreferSoftwareCodecs = 1,
@ -122,11 +124,26 @@ class OmxDecoder : public OMXCodecProxy::EventListener {
MediaBuffer *mVideoBuffer;
MediaBuffer *mAudioBuffer;
struct BufferItem {
BufferItem()
: mMediaBuffer(nullptr)
{
}
BufferItem(MediaBuffer* aMediaBuffer, const FenceHandle& aReleaseFenceHandle)
: mMediaBuffer(aMediaBuffer)
, mReleaseFenceHandle(aReleaseFenceHandle) {
}
MediaBuffer* mMediaBuffer;
// a fence will signal when the current buffer is no longer being read.
FenceHandle mReleaseFenceHandle;
};
// Hold video's MediaBuffers that are released during video seeking.
// The holded MediaBuffers are released soon after seek completion.
// OMXCodec does not accept MediaBuffer during seeking. If MediaBuffer is
// returned to OMXCodec during seeking, OMXCodec calls assert.
Vector<MediaBuffer *> mPendingVideoBuffers;
Vector<BufferItem> mPendingVideoBuffers;
// The lock protects mPendingVideoBuffers.
Mutex mPendingVideoBuffersLock;
@ -235,7 +252,7 @@ public:
void Pause();
// Post kNotifyPostReleaseVideoBuffer message to OmxDecoder via ALooper.
void PostReleaseVideoBuffer(MediaBuffer *aBuffer);
void PostReleaseVideoBuffer(MediaBuffer *aBuffer, const FenceHandle& aReleaseFenceHandle);
// Receive a message from AHandlerReflector.
// Called on ALooper thread.
void onMessageReceived(const sp<AMessage> &msg);

View File

@ -8,11 +8,12 @@
#ifdef MOZ_WIDGET_GONK
#include "mozilla/layers/AtomicRefCountedWithFinalize.h"
#include "mozilla/layers/LayersSurfaces.h"
#include "mozilla/gfx/Point.h"
#include "ImageLayers.h"
#include "ImageContainer.h"
#include "mozilla/gfx/Point.h"
#include "mozilla/layers/AtomicRefCountedWithFinalize.h"
#include "mozilla/layers/FenceUtils.h"
#include "mozilla/layers/LayersSurfaces.h"
#include <ui/GraphicBuffer.h>
@ -46,6 +47,16 @@ public:
return mSurfaceDescriptor;
}
void SetReleaseFenceHandle(const FenceHandle& aReleaseFenceHandle)
{
mReleaseFenceHandle = aReleaseFenceHandle;
}
const FenceHandle& GetReleaseFenceHandle() const
{
return mReleaseFenceHandle;
}
protected:
virtual void Unlock() {}
@ -65,6 +76,7 @@ private:
protected:
SurfaceDescriptor mSurfaceDescriptor;
FenceHandle mReleaseFenceHandle;
};
/**

View File

@ -38,6 +38,7 @@ class GraphicBuffer;
namespace mozilla {
namespace layers {
class TextureHost;
typedef uint32_t TextureFlags;
@ -88,18 +89,20 @@ enum LayerRenderStateFlags {
struct LayerRenderState {
LayerRenderState()
#ifdef MOZ_WIDGET_GONK
: mSurface(nullptr), mFlags(0), mHasOwnOffset(false)
: mSurface(nullptr), mFlags(0), mHasOwnOffset(false), mTexture(nullptr)
#endif
{}
#ifdef MOZ_WIDGET_GONK
LayerRenderState(android::GraphicBuffer* aSurface,
const nsIntSize& aSize,
uint32_t aFlags)
uint32_t aFlags,
TextureHost* aTexture)
: mSurface(aSurface)
, mSize(aSize)
, mFlags(aFlags)
, mHasOwnOffset(false)
, mTexture(aTexture)
{}
bool YFlipped() const
@ -123,6 +126,7 @@ struct LayerRenderState {
android::sp<android::GraphicBuffer> mSurface;
// size of mSurface
nsIntSize mSize;
TextureHost* mTexture;
#endif
// see LayerRenderStateFlags
uint32_t mFlags;

View File

@ -378,6 +378,20 @@ ClientLayerManager::ForwardTransaction(bool aScheduleComposite)
->SetDescriptorFromReply(ots.textureId(), ots.image());
break;
}
case EditReply::TReturnReleaseFence: {
const ReturnReleaseFence& rep = reply.get_ReturnReleaseFence();
FenceHandle fence = rep.fence();
PTextureChild* child = rep.textureChild();
if (!fence.IsValid() || !child) {
break;
}
RefPtr<TextureClient> texture = TextureClient::AsTextureClient(child);
if (texture) {
texture->SetReleaseFenceHandle(fence);
}
break;
}
default:
NS_RUNTIMEABORT("not reached");

View File

@ -20,7 +20,6 @@
#include "mozilla/layers/ShadowLayers.h" // for ShadowLayerForwarder
#include "mozilla/layers/SharedPlanarYCbCrImage.h"
#include "mozilla/layers/YCbCrImageDataSerializer.h"
#include "mozilla/layers/PTextureChild.h"
#include "nsDebug.h" // for NS_ASSERTION, NS_WARNING, etc
#include "nsTraceRefcnt.h" // for MOZ_COUNT_CTOR, etc
#include "ImageContainer.h" // for PlanarYCbCrImage, etc
@ -159,6 +158,13 @@ TextureClient::DestroyIPDLActor(PTextureChild* actor)
return true;
}
// static
TextureClient*
TextureClient::AsTextureClient(PTextureChild* actor)
{
return actor? static_cast<TextureChild*>(actor)->mTextureClient : nullptr;
}
bool
TextureClient::InitIPDLActor(CompositableForwarder* aForwarder)
{

View File

@ -17,10 +17,12 @@
#include "mozilla/gfx/2D.h" // for DrawTarget
#include "mozilla/gfx/Point.h" // for IntSize
#include "mozilla/gfx/Types.h" // for SurfaceFormat
#include "mozilla/layers/FenceUtils.h" // for FenceHandle
#include "mozilla/ipc/Shmem.h" // for Shmem
#include "mozilla/layers/AtomicRefCountedWithFinalize.h"
#include "mozilla/layers/CompositorTypes.h" // for TextureFlags, etc
#include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor
#include "mozilla/layers/PTextureChild.h" // for PTextureChild
#include "mozilla/mozalloc.h" // for operator delete
#include "nsAutoPtr.h" // for nsRefPtr
#include "nsCOMPtr.h" // for already_AddRefed
@ -230,6 +232,11 @@ public:
static PTextureChild* CreateIPDLActor();
static bool DestroyIPDLActor(PTextureChild* actor);
/**
* Get the TextureClient corresponding to the actor passed in parameter.
*/
static TextureClient* AsTextureClient(PTextureChild* actor);
virtual bool IsAllocated() const = 0;
virtual bool ToSurfaceDescriptor(SurfaceDescriptor& aDescriptor) = 0;
@ -287,6 +294,13 @@ public:
*/
void ForceRemove();
virtual void SetReleaseFenceHandle(FenceHandle aReleaseFenceHandle) {}
const FenceHandle& GetReleaseFenceHandle() const
{
return mReleaseFenceHandle;
}
private:
/**
* Called once, just before the destructor.
@ -325,6 +339,7 @@ protected:
TextureFlags mFlags;
bool mShared;
bool mValid;
FenceHandle mReleaseFenceHandle;
friend class TextureChild;
};

View File

@ -36,6 +36,9 @@ CompositableHost::CompositableHost(const TextureInfo& aTextureInfo)
CompositableHost::~CompositableHost()
{
MOZ_COUNT_DTOR(CompositableHost);
if (mBackendData) {
mBackendData->ClearData();
}
}
void
@ -62,6 +65,8 @@ CompositableHost::UseComponentAlphaTextures(TextureHost* aTextureOnBlack,
void
CompositableHost::RemoveTextureHost(TextureHost* aTexture)
{
// Clear strong refrence to CompositableBackendSpecificData
aTexture->SetCompositableBackendSpecificData(nullptr);
}
void

View File

@ -19,6 +19,7 @@
#include "mozilla/layers/CompositorTypes.h" // for TextureInfo, etc
#include "mozilla/layers/LayersTypes.h" // for LayerRenderState, etc
#include "mozilla/layers/PCompositableParent.h"
#include "mozilla/layers/TextureHost.h" // for TextureHost
#include "mozilla/mozalloc.h" // for operator delete
#include "nsCOMPtr.h" // for already_AddRefed
#include "nsRegion.h" // for nsIntRegion
@ -46,7 +47,6 @@ struct TiledLayerProperties
class Layer;
class DeprecatedTextureHost;
class TextureHost;
class SurfaceDescriptor;
class Compositor;
class ISurfaceAllocator;
@ -70,7 +70,45 @@ public:
MOZ_COUNT_DTOR(CompositableBackendSpecificData);
}
virtual void SetCompositor(Compositor* aCompositor) {}
virtual void ClearData() {}
virtual void ClearData()
{
mCurrentReleaseFenceTexture = nullptr;
ClearPendingReleaseFenceTextureList();
}
/**
* Store a texture currently used for Composition.
* This function is called when the texutre might receive ReleaseFence
* as a result of Composition.
*/
void SetCurrentReleaseFenceTexture(TextureHost* aTexture)
{
if (mCurrentReleaseFenceTexture) {
mPendingReleaseFenceTextures.push_back(mCurrentReleaseFenceTexture);
}
mCurrentReleaseFenceTexture = aTexture;
}
virtual std::vector< RefPtr<TextureHost> >& GetPendingReleaseFenceTextureList()
{
return mPendingReleaseFenceTextures;
}
virtual void ClearPendingReleaseFenceTextureList()
{
return mPendingReleaseFenceTextures.clear();
}
protected:
/**
* Store a TextureHost currently used for Composition
* and it might receive ReleaseFence for the texutre.
*/
RefPtr<TextureHost> mCurrentReleaseFenceTexture;
/**
* Store TextureHosts that might have ReleaseFence to be delivered
* to TextureClient by CompositableHost.
*/
std::vector< RefPtr<TextureHost> > mPendingReleaseFenceTextures;
};
/**

View File

@ -89,6 +89,12 @@ TextureHost::AsTextureHost(PTextureParent* actor)
return actor? static_cast<TextureParent*>(actor)->mTextureHost : nullptr;
}
PTextureParent*
TextureHost::GetIPDLActor()
{
return mActor;
}
// implemented in TextureOGL.cpp
TemporaryRef<DeprecatedTextureHost> CreateDeprecatedTextureHostOGL(SurfaceDescriptorType aDescriptorType,
uint32_t aDeprecatedTextureHostFlags,
@ -242,7 +248,8 @@ TextureHost::SetCompositableBackendSpecificData(CompositableBackendSpecificData*
TextureHost::TextureHost(TextureFlags aFlags)
: mFlags(aFlags)
: mActor(nullptr)
, mFlags(aFlags)
{}
TextureHost::~TextureHost()
@ -723,6 +730,7 @@ TextureParent::Init(const SurfaceDescriptor& aSharedData,
mTextureHost = TextureHost::Create(aSharedData,
mAllocator,
aFlags);
mTextureHost->mActor = this;
return !!mTextureHost;
}
@ -760,6 +768,8 @@ TextureParent::ActorDestroy(ActorDestroyReason why)
if (mTextureHost->GetFlags() & TEXTURE_DEALLOCATE_CLIENT) {
mTextureHost->ForgetSharedData();
}
mTextureHost->mActor = nullptr;
mTextureHost = nullptr;
}

View File

@ -43,6 +43,7 @@ class CompositableHost;
class CompositableBackendSpecificData;
class SurfaceDescriptor;
class ISurfaceAllocator;
class TextureHostOGL;
class TextureSourceOGL;
class TextureSourceD3D9;
class TextureSourceD3D11;
@ -273,7 +274,6 @@ class TextureHost
void Finalize();
friend class AtomicRefCountedWithFinalize<TextureHost>;
public:
TextureHost(TextureFlags aFlags);
@ -395,6 +395,14 @@ public:
*/
static TextureHost* AsTextureHost(PTextureParent* actor);
/**
* Return a pointer to the IPDLActor.
*
* This is to be used with IPDL messages only. Do not store the returned
* pointer.
*/
PTextureParent* GetIPDLActor();
/**
* Specific to B2G's Composer2D
* XXX - more doc here
@ -418,9 +426,17 @@ public:
virtual const char *Name() { return "TextureHost"; }
virtual void PrintInfo(nsACString& aTo, const char* aPrefix);
/**
* Cast to a TextureHost for each backend.
*/
virtual TextureHostOGL* AsHostOGL() { return nullptr; }
protected:
PTextureParent* mActor;
TextureFlags mFlags;
RefPtr<CompositableBackendSpecificData> mCompositableBackendData;
friend class TextureParent;
};
/**

View File

@ -8,6 +8,7 @@
#include "CompositableTransactionParent.h"
#include "CompositableHost.h" // for CompositableParent, etc
#include "CompositorParent.h" // for CompositorParent
#include "GLContext.h" // for GLContext
#include "Layers.h" // for Layer
#include "RenderTrace.h" // for RenderTraceInvalidateEnd, etc
#include "TiledLayerBuffer.h" // for TiledLayerComposer
@ -19,6 +20,7 @@
#include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor
#include "mozilla/layers/LayersTypes.h" // for MOZ_LAYERS_LOG
#include "mozilla/layers/TextureHost.h" // for TextureHost
#include "mozilla/layers/TextureHostOGL.h" // for TextureHostOGL
#include "mozilla/layers/ThebesLayerComposite.h"
#include "mozilla/mozalloc.h" // for operator delete
#include "nsDebug.h" // for NS_WARNING, NS_ASSERTION
@ -159,6 +161,8 @@ CompositableParentManager::ReceiveCompositableUpdate(const CompositableOperation
RenderTraceInvalidateEnd(layer, "FF00FF");
}
// return texure data to client if necessary
ReturnTextureDataIfNecessary(compositable, replyv, op.compositableParent());
break;
}
case CompositableOperation::TOpPaintTextureRegion: {
@ -190,6 +194,8 @@ CompositableParentManager::ReceiveCompositableUpdate(const CompositableOperation
OpContentBufferSwap(compositableParent, nullptr, frontUpdatedRegion));
RenderTraceInvalidateEnd(thebes, "FF00FF");
// return texure data to client if necessary
ReturnTextureDataIfNecessary(compositable, replyv, op.compositableParent());
break;
}
case CompositableOperation::TOpPaintTextureIncremental: {
@ -239,6 +245,8 @@ CompositableParentManager::ReceiveCompositableUpdate(const CompositableOperation
MOZ_ASSERT(tex.get());
compositable->RemoveTextureHost(tex);
// return texure data to client if necessary
ReturnTextureDataIfNecessary(compositable, replyv, op.compositableParent());
break;
}
case CompositableOperation::TOpUseTexture: {
@ -257,6 +265,8 @@ CompositableParentManager::ReceiveCompositableUpdate(const CompositableOperation
compositable->GetLayer()->SetInvalidRectToVisibleRegion();
}
}
// return texure data to client if necessary
ReturnTextureDataIfNecessary(compositable, replyv, op.compositableParent());
break;
}
case CompositableOperation::TOpUseComponentAlphaTextures: {
@ -271,6 +281,8 @@ CompositableParentManager::ReceiveCompositableUpdate(const CompositableOperation
if (IsAsync()) {
ScheduleComposition(op);
}
// return texure data to client if necessary
ReturnTextureDataIfNecessary(compositable, replyv, op.compositableParent());
break;
}
case CompositableOperation::TOpUpdateTexture: {
@ -281,7 +293,6 @@ CompositableParentManager::ReceiveCompositableUpdate(const CompositableOperation
texture->Updated(op.region().type() == MaybeRegion::TnsIntRegion
? &op.region().get_nsIntRegion()
: nullptr); // no region means invalidate the entire surface
break;
}
@ -293,6 +304,54 @@ CompositableParentManager::ReceiveCompositableUpdate(const CompositableOperation
return true;
}
#if MOZ_WIDGET_GONK && ANDROID_VERSION >= 18
void
CompositableParentManager::ReturnTextureDataIfNecessary(CompositableHost* aCompositable,
EditReplyVector& replyv,
PCompositableParent* aParent)
{
if (!aCompositable || !aCompositable->GetCompositableBackendSpecificData()) {
return;
}
const std::vector< RefPtr<TextureHost> > textureList =
aCompositable->GetCompositableBackendSpecificData()->GetPendingReleaseFenceTextureList();
// Return pending Texture data
for (size_t i = 0; i < textureList.size(); i++) {
TextureHostOGL* hostOGL = textureList[i]->AsHostOGL();
PTextureParent* actor = textureList[i]->GetIPDLActor();
if (!hostOGL || !actor) {
continue;
}
android::sp<android::Fence> fence = hostOGL->GetAndResetReleaseFence();
if (fence.get() && fence->isValid()) {
FenceHandle handle = FenceHandle(fence);
replyv.push_back(ReturnReleaseFence(aParent, nullptr, actor, nullptr, handle));
// Hold fence handle to prevent fence's file descriptor is closed before IPC happens.
mPrevFenceHandles.push_back(handle);
}
}
aCompositable->GetCompositableBackendSpecificData()->ClearPendingReleaseFenceTextureList();
}
#else
void
CompositableParentManager::ReturnTextureDataIfNecessary(CompositableHost* aCompositable,
EditReplyVector& replyv,
PCompositableParent* aParent)
{
if (!aCompositable || !aCompositable->GetCompositableBackendSpecificData()) {
return;
}
aCompositable->GetCompositableBackendSpecificData()->ClearPendingReleaseFenceTextureList();
}
#endif
void
CompositableParentManager::ClearPrevFenceHandles()
{
mPrevFenceHandles.clear();
}
} // namespace
} // namespace

View File

@ -16,6 +16,8 @@
namespace mozilla {
namespace layers {
class CompositableHost;
typedef std::vector<mozilla::layers::EditReply> EditReplyVector;
// Since PCompositble has two potential manager protocols, we can't just call
@ -37,6 +39,14 @@ protected:
* thread (ImageBridge for instance).
*/
virtual bool IsAsync() const { return false; }
void ReturnTextureDataIfNecessary(CompositableHost* aCompositable,
EditReplyVector& replyv,
PCompositableParent* aParent);
void ClearPrevFenceHandles();
protected:
std::vector<FenceHandle> mPrevFenceHandles;
};
} // namespace

View File

@ -0,0 +1,43 @@
/* -*- 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/. */
#ifndef IPC_FencerUtils_h
#define IPC_FencerUtils_h
#include "ipc/IPCMessageUtils.h"
/**
* FenceHandle is used for delivering Fence object via ipc.
*/
#if MOZ_WIDGET_GONK && ANDROID_VERSION >= 18
# include "mozilla/layers/FenceUtilsGonk.h"
#else
namespace mozilla {
namespace layers {
struct FenceHandle {
bool operator==(const FenceHandle&) const { return false; }
bool IsValid() const { return false; }
};
} // namespace layers
} // namespace mozilla
#endif // MOZ_WIDGET_GONK && ANDROID_VERSION >= 18
namespace IPC {
#if MOZ_WIDGET_GONK && ANDROID_VERSION >= 18
#else
template <>
struct ParamTraits<mozilla::layers::FenceHandle> {
typedef mozilla::layers::FenceHandle paramType;
static void Write(Message*, const paramType&) {}
static bool Read(const Message*, void**, paramType*) { return false; }
};
#endif // MOZ_WIDGET_GONK && ANDROID_VERSION >= 18
} // namespace IPC
#endif // IPC_FencerUtils_h

View File

@ -0,0 +1,96 @@
/* -*- 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 "GLContext.h"
#include "mozilla/unused.h"
#include "nsXULAppAPI.h"
#include "FenceUtilsGonk.h"
using namespace android;
using namespace base;
using namespace mozilla::layers;
namespace IPC {
void
ParamTraits<FenceHandle>::Write(Message* aMsg,
const paramType& aParam)
{
Flattenable *flattenable = aParam.mFence.get();
size_t nbytes = flattenable->getFlattenedSize();
size_t nfds = flattenable->getFdCount();
char data[nbytes];
int fds[nfds];
flattenable->flatten(data, nbytes, fds, nfds);
aMsg->WriteSize(nbytes);
aMsg->WriteSize(nfds);
aMsg->WriteBytes(data, nbytes);
for (size_t n = 0; n < nfds; ++n) {
// These buffers can't die in transit because they're created
// synchonously and the parent-side buffer can only be dropped if
// there's a crash.
aMsg->WriteFileDescriptor(FileDescriptor(fds[n], false));
}
}
bool
ParamTraits<FenceHandle>::Read(const Message* aMsg,
void** aIter, paramType* aResult)
{
size_t nbytes;
size_t nfds;
const char* data;
if (!aMsg->ReadSize(aIter, &nbytes) ||
!aMsg->ReadSize(aIter, &nfds) ||
!aMsg->ReadBytes(aIter, &data, nbytes)) {
return false;
}
int fds[nfds];
for (size_t n = 0; n < nfds; ++n) {
FileDescriptor fd;
if (!aMsg->ReadFileDescriptor(aIter, &fd)) {
return false;
}
// If the GraphicBuffer was shared cross-process, SCM_RIGHTS does
// the right thing and dup's the fd. If it's shared cross-thread,
// SCM_RIGHTS doesn't dup the fd. That's surprising, but we just
// deal with it here. NB: only the "default" (master) process can
// alloc gralloc buffers.
bool sameProcess = (XRE_GetProcessType() == GeckoProcessType_Default);
int dupFd = sameProcess ? dup(fd.fd) : fd.fd;
fds[n] = dupFd;
}
sp<Fence> buffer(new Fence());
Flattenable *flattenable = buffer.get();
if (NO_ERROR == flattenable->unflatten(data, nbytes, fds, nfds)) {
aResult->mFence = buffer;
return true;
}
return false;
}
} // namespace IPC
namespace mozilla {
namespace layers {
FenceHandle::FenceHandle(const sp<Fence>& aFence)
: mFence(aFence)
{
}
} // namespace layers
} // namespace mozilla

View File

@ -0,0 +1,53 @@
/* -*- 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/. */
#ifndef mozilla_layers_FenceUtilsGonk_h
#define mozilla_layers_FenceUtilsGonk_h
#include <unistd.h>
#include <ui/Fence.h>
#include "ipc/IPCMessageUtils.h"
namespace mozilla {
namespace layers {
struct FenceHandle {
typedef android::Fence Fence;
FenceHandle()
{ }
FenceHandle(const android::sp<Fence>& aFence);
bool operator==(const FenceHandle& aOther) const {
return mFence.get() == aOther.mFence.get();
}
bool IsValid() const
{
return mFence.get() && mFence->isValid();
}
android::sp<Fence> mFence;
};
} // namespace layers
} // namespace mozilla
namespace IPC {
template <>
struct ParamTraits<mozilla::layers::FenceHandle> {
typedef mozilla::layers::FenceHandle paramType;
static void Write(Message* aMsg, const paramType& aParam);
static bool Read(const Message* aMsg, void** aIter, paramType* aResult);
};
} // namespace IPC
#endif // mozilla_layers_FenceUtilsGonk_h

View File

@ -516,6 +516,20 @@ ImageBridgeChild::EndTransaction()
->SetDescriptorFromReply(ots.textureId(), ots.image());
break;
}
case EditReply::TReturnReleaseFence: {
const ReturnReleaseFence& rep = reply.get_ReturnReleaseFence();
FenceHandle fence = rep.fence();
PTextureChild* child = rep.textureChild();
if (!fence.IsValid() || !child) {
break;
}
RefPtr<TextureClient> texture = TextureClient::AsTextureClient(child);
if (texture) {
texture->SetReleaseFenceHandle(fence);
}
break;
}
default:
NS_RUNTIMEABORT("not reached");
}

View File

@ -75,6 +75,9 @@ ImageBridgeParent::RecvUpdate(const EditArray& aEdits, EditReplyArray* aReply)
return true;
}
// Clear fence handles used in previsou transaction.
ClearPrevFenceHandles();
EditReplyVector replyv;
for (EditArray::index_type i = 0; i < aEdits.Length(); ++i) {
ReceiveCompositableUpdate(aEdits[i], replyv);

View File

@ -204,6 +204,9 @@ LayerTransactionParent::RecvUpdate(const InfallibleTArray<Edit>& cset,
return true;
}
// Clear fence handles used in previsou transaction.
ClearPrevFenceHandles();
EditReplyVector replyv;
{

View File

@ -39,6 +39,7 @@ using mozilla::layers::ScaleMode from "mozilla/layers/LayersTypes.h";
using mozilla::layers::EventRegions from "mozilla/layers/LayersTypes.h";
using mozilla::layers::DiagnosticTypes from "mozilla/layers/CompositorTypes.h";
using struct mozilla::layers::FrameMetrics from "FrameMetrics.h";
using struct mozilla::layers::FenceHandle from "mozilla/layers/FenceUtils.h";
namespace mozilla {
namespace layers {
@ -396,11 +397,19 @@ struct OpTextureSwap {
SurfaceDescriptor image;
};
struct ReturnReleaseFence {
PCompositable compositable;
PTexture texture;
FenceHandle fence;
};
// Unit of a "changeset reply". This is a weird abstraction, probably
// only to be used for buffer swapping.
union EditReply {
OpContentBufferSwap;
OpTextureSwap;
ReturnReleaseFence;
};
} // namespace

View File

@ -129,6 +129,7 @@ EXPORTS.mozilla.layers += [
'ipc/CompositableTransactionParent.h',
'ipc/CompositorChild.h',
'ipc/CompositorParent.h',
'ipc/FenceUtils.h',
'ipc/GeckoContentController.h',
'ipc/GestureEventListener.h',
'ipc/ImageBridgeChild.h',
@ -202,6 +203,14 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
'ipc/ShadowLayerUtilsGralloc.cpp',
]
if CONFIG['ANDROID_VERSION'] in ('18'):
EXPORTS.mozilla.layers += [
'ipc/FenceUtilsGonk.h',
]
SOURCES += [
'ipc/FenceUtilsGonk.cpp',
]
UNIFIED_SOURCES += [
'basic/BasicCanvasLayer.cpp',
'basic/BasicColorLayer.cpp',

View File

@ -196,6 +196,16 @@ GrallocTextureClientOGL::UpdateSurface(gfxASurface* aSurface)
return true;
}
void
GrallocTextureClientOGL::SetReleaseFenceHandle(FenceHandle aReleaseFenceHandle)
{
if (mBufferLocked) {
mBufferLocked->SetReleaseFenceHandle(aReleaseFenceHandle);
} else {
mReleaseFenceHandle = aReleaseFenceHandle;
}
}
bool
GrallocTextureClientOGL::Lock(OpenMode aMode)
{
@ -207,6 +217,15 @@ GrallocTextureClientOGL::Lock(OpenMode aMode)
if (mMappedBuffer) {
return true;
}
#if MOZ_WIDGET_GONK && ANDROID_VERSION >= 18
if (mReleaseFenceHandle.IsValid()) {
android::sp<Fence> fence = mReleaseFenceHandle.mFence;
fence->waitForever("GrallocTextureClientOGL::Lock");
mReleaseFenceHandle = FenceHandle();
}
#endif
uint32_t usage = 0;
if (aMode & OPEN_READ) {
usage |= GRALLOC_USAGE_SW_READ_OFTEN;

View File

@ -9,6 +9,7 @@
#include "mozilla/layers/TextureClient.h"
#include "ISurfaceAllocator.h" // For IsSurfaceDescriptorValid
#include "mozilla/layers/FenceUtils.h" // for FenceHandle
#include "mozilla/layers/ShadowLayerUtilsGralloc.h"
#include <ui/GraphicBuffer.h>
@ -59,6 +60,13 @@ public:
virtual TextureClientData* DropTextureData() MOZ_OVERRIDE;
virtual void SetReleaseFenceHandle(FenceHandle aReleaseFenceHandle) MOZ_OVERRIDE;
const FenceHandle& GetReleaseFenceHandle() const
{
return mReleaseFenceHandle;
}
void InitWith(GrallocBufferActor* aActor, gfx::IntSize aSize);
void SetTextureFlags(TextureFlags aFlags) { AddFlags(aFlags); }

View File

@ -332,7 +332,8 @@ GrallocTextureHostOGL::GetRenderState()
}
return LayerRenderState(mTextureSource->mGraphicBuffer.get(),
gfx::ThebesIntSize(mSize),
flags);
flags,
this);
}
return LayerRenderState();
@ -379,6 +380,11 @@ GrallocTextureHostOGL::SetCompositableBackendSpecificData(CompositableBackendSpe
if (mTextureSource) {
mTextureSource->SetCompositableBackendSpecificData(aBackendData);
}
// Register this object to CompositableBackendSpecificData
// as current TextureHost.
if (aBackendData) {
aBackendData->SetCurrentReleaseFenceTexture(this);
}
}
} // namepsace layers

View File

@ -71,6 +71,9 @@ protected:
};
class GrallocTextureHostOGL : public TextureHost
#if MOZ_WIDGET_GONK && ANDROID_VERSION >= 18
, public TextureHostOGL
#endif
{
friend class GrallocBufferActor;
public:
@ -104,6 +107,13 @@ public:
return mTextureSource;
}
#if MOZ_WIDGET_GONK && ANDROID_VERSION >= 18
virtual TextureHostOGL* AsHostOGL() MOZ_OVERRIDE
{
return this;
}
#endif
virtual TemporaryRef<gfx::DataSourceSurface> GetAsSurface() MOZ_OVERRIDE;
virtual void SetCompositableBackendSpecificData(CompositableBackendSpecificData* aBackendData) MOZ_OVERRIDE;

View File

@ -176,6 +176,7 @@ void CompositableDataGonkOGL::SetCompositor(Compositor* aCompositor)
void CompositableDataGonkOGL::ClearData()
{
CompositableBackendSpecificData::ClearData();
DeleteTextureIfPresent();
}
@ -200,6 +201,41 @@ CompositableDataGonkOGL::DeleteTextureIfPresent()
}
}
#if MOZ_WIDGET_GONK && ANDROID_VERSION >= 18
bool
TextureHostOGL::SetReleaseFence(const android::sp<android::Fence>& aReleaseFence)
{
if (!aReleaseFence.get() || !aReleaseFence->isValid()) {
return false;
}
if (!mReleaseFence.get()) {
mReleaseFence = aReleaseFence;
} else {
android::sp<android::Fence> mergedFence = android::Fence::merge(
android::String8::format("TextureHostOGL"),
mReleaseFence, aReleaseFence);
if (!mergedFence.get()) {
// synchronization is broken, the best we can do is hope fences
// signal in order so the new fence will act like a union.
// This error handling is same as android::ConsumerBase does.
mReleaseFence = aReleaseFence;
return false;
}
mReleaseFence = mergedFence;
}
return true;
}
android::sp<android::Fence>
TextureHostOGL::GetAndResetReleaseFence()
{
android::sp<android::Fence> fence = mReleaseFence;
mReleaseFence = android::Fence::NO_FENCE;
return fence;
}
#endif
bool
TextureImageTextureSourceOGL::Update(gfx::DataSourceSurface* aSurface,
nsIntRegion* aDestRegion,
@ -1155,7 +1191,8 @@ GrallocDeprecatedTextureHostOGL::GetRenderState()
return LayerRenderState(mGraphicBuffer.get(),
bufferSize,
flags);
flags,
nullptr);
}
return LayerRenderState();

View File

@ -32,6 +32,9 @@
#include "OGLShaderProgram.h" // for ShaderProgramType, etc
#ifdef MOZ_WIDGET_GONK
#include <ui/GraphicBuffer.h>
#if ANDROID_VERSION >= 18
#include <ui/Fence.h>
#endif
#endif
class gfxImageSurface;
@ -117,6 +120,29 @@ public:
virtual TextureImageDeprecatedTextureHostOGL* AsTextureImageDeprecatedTextureHost() { return nullptr; }
};
/**
* TextureHostOGL provides the necessary API for platform specific composition.
*/
class TextureHostOGL
{
public:
#if MOZ_WIDGET_GONK && ANDROID_VERSION >= 18
/**
* Store a fence that will signal when the current buffer is no longer being read.
* Similar to android's GLConsumer::setReleaseFence()
*/
virtual bool SetReleaseFence(const android::sp<android::Fence>& aReleaseFence);
/**
* Return a releaseFence's Fence and clear a reference to the Fence.
*/
virtual android::sp<android::Fence> GetAndResetReleaseFence();
protected:
android::sp<android::Fence> mReleaseFence;
#endif
};
/**
* A TextureSource backed by a TextureImage.
*

View File

@ -19,11 +19,13 @@
#include "libdisplay/GonkDisplay.h"
#include "Framebuffer.h"
#include "GLContext.h" // for GLContext
#include "HwcUtils.h"
#include "HwcComposer2D.h"
#include "mozilla/layers/LayerManagerComposite.h"
#include "mozilla/layers/PLayerTransaction.h"
#include "mozilla/layers/ShadowLayerUtilsGralloc.h"
#include "mozilla/layers/TextureHostOGL.h" // for TextureHostOGL
#include "mozilla/StaticPtr.h"
#include "cutils/properties.h"
#include "gfx2DGlue.h"
@ -67,7 +69,10 @@ HwcComposer2D::HwcComposer2D()
, mHwc(nullptr)
, mColorFill(false)
, mRBSwapSupport(false)
, mPrevRetireFence(-1)
#if ANDROID_VERSION >= 18
, mPrevRetireFence(Fence::NO_FENCE)
, mPrevDisplayFence(Fence::NO_FENCE)
#endif
, mPrepared(false)
{
}
@ -649,36 +654,29 @@ HwcComposer2D::Commit()
int err = mHwc->set(mHwc, HWC_NUM_DISPLAY_TYPES, displays);
// To avoid tearing, workaround for missing releaseFenceFd
// waits in Gecko layers, see Bug 925444.
if (!mPrevReleaseFds.IsEmpty()) {
// Wait for previous retire Fence to signal.
// Denotes contents on display have been replaced.
// For buffer-sync, framework should not over-write
// prev buffers until we close prev releaseFenceFds
sp<Fence> fence = new Fence(mPrevRetireFence);
if (fence->wait(1000) == -ETIME) {
LOGE("Wait timed-out for retireFenceFd %d", mPrevRetireFence);
}
for (int i = 0; i < mPrevReleaseFds.Length(); i++) {
close(mPrevReleaseFds[i]);
}
close(mPrevRetireFence);
mPrevReleaseFds.Clear();
}
mPrevDisplayFence = mPrevRetireFence;
mPrevRetireFence = Fence::NO_FENCE;
for (uint32_t j=0; j < (mList->numHwLayers - 1); j++) {
if (mList->hwLayers[j].releaseFenceFd >= 0) {
mPrevReleaseFds.AppendElement(mList->hwLayers[j].releaseFenceFd);
}
}
int fd = mList->hwLayers[j].releaseFenceFd;
mList->hwLayers[j].releaseFenceFd = -1;
sp<Fence> fence = new Fence(fd);
LayerRenderState state = mHwcLayerMap[j]->GetLayer()->GetRenderState();
if (!state.mTexture) {
continue;
}
TextureHostOGL* texture = state.mTexture->AsHostOGL();
if (!texture) {
continue;
}
texture->SetReleaseFence(fence);
}
}
if (mList->retireFenceFd >= 0) {
if (!mPrevReleaseFds.IsEmpty()) {
mPrevRetireFence = mList->retireFenceFd;
} else { // GPU Composition
close(mList->retireFenceFd);
}
mPrevRetireFence = new Fence(mList->retireFenceFd);
}
mPrepared = false;

View File

@ -23,6 +23,9 @@
#include <list>
#include <hardware/hwcomposer.h>
#if ANDROID_VERSION >= 18
#include <ui/Fence.h>
#endif
namespace mozilla {
@ -83,8 +86,10 @@ private:
//Holds all the dynamically allocated RectVectors needed
//to render the current frame
std::list<RectVector> mVisibleRegions;
nsTArray<int> mPrevReleaseFds;
int mPrevRetireFence;
#if ANDROID_VERSION >= 18
android::sp<android::Fence> mPrevRetireFence;
android::sp<android::Fence> mPrevDisplayFence;
#endif
nsTArray<layers::LayerComposite*> mHwcLayerMap;
bool mPrepared;
};

View File

@ -105,8 +105,7 @@ status_t GonkNativeWindow::setDefaultBufferFormat(uint32_t defaultFormat) {
}
already_AddRefed<GraphicBufferLocked>
GonkNativeWindow::getCurrentBuffer()
{
GonkNativeWindow::getCurrentBuffer() {
Mutex::Autolock _l(mMutex);
GonkBufferQueue::BufferItem item;
@ -123,17 +122,20 @@ GonkNativeWindow::getCurrentBuffer()
}
bool
GonkNativeWindow::returnBuffer(uint32_t aIndex, uint32_t aGeneration) {
BI_LOGD("GonkNativeWindow::returnBuffer: slot=%d (generation=%d)", aIndex, aGeneration);
GonkNativeWindow::returnBuffer(uint32_t index, uint32_t generation, const sp<Fence>& fence) {
BI_LOGD("GonkNativeWindow::returnBuffer: slot=%d (generation=%d)", index, generation);
Mutex::Autolock lock(mMutex);
if (aGeneration != mBufferQueue->getGeneration()) {
if (generation != mBufferQueue->getGeneration()) {
BI_LOGD("returnBuffer: buffer is from generation %d (current is %d)",
aGeneration, mBufferQueue->getGeneration());
generation, mBufferQueue->getGeneration());
return false;
}
status_t err = releaseBufferLocked(aIndex);
status_t err;
err = addReleaseFenceLocked(index, fence);
err = releaseBufferLocked(index);
if (err != NO_ERROR) {
return false;
}
@ -141,8 +143,7 @@ GonkNativeWindow::returnBuffer(uint32_t aIndex, uint32_t aGeneration) {
}
mozilla::layers::SurfaceDescriptor *
GonkNativeWindow::getSurfaceDescriptorFromBuffer(ANativeWindowBuffer* buffer)
{
GonkNativeWindow::getSurfaceDescriptorFromBuffer(ANativeWindowBuffer* buffer) {
Mutex::Autolock lock(mMutex);
return mBufferQueue->getSurfaceDescriptorFromBuffer(buffer);
}
@ -161,4 +162,22 @@ void GonkNativeWindow::onFrameAvailable() {
}
}
void CameraGraphicBuffer::Unlock() {
if (mLocked) {
android::sp<android::Fence> fence;
fence = mReleaseFenceHandle.IsValid() ? mReleaseFenceHandle.mFence : Fence::NO_FENCE;
// The window might have been destroyed. The buffer is no longer
// valid at that point.
sp<GonkNativeWindow> window = mNativeWindow.promote();
if (window.get() && window->returnBuffer(mIndex, mGeneration, fence)) {
mLocked = false;
} else {
// If the window doesn't exist any more, release the buffer
// directly.
ImageBridgeChild *ibc = ImageBridgeChild::GetSingleton();
ibc->DeallocSurfaceDescriptorGralloc(mSurfaceDescriptor);
}
}
}
} // namespace android

View File

@ -116,7 +116,7 @@ class GonkNativeWindow: public GonkConsumerBase
// Return the buffer to the queue and mark it as FREE. After that
// the buffer is useable again for the decoder.
bool returnBuffer(uint32_t index, uint32_t generation);
bool returnBuffer(uint32_t index, uint32_t generation, const sp<Fence>& fence);
SurfaceDescriptor* getSurfaceDescriptorFromBuffer(ANativeWindowBuffer* buffer);
@ -157,22 +157,7 @@ public:
protected:
// Unlock either returns the buffer to the native window or
// destroys the buffer if the window is already released.
virtual void Unlock() MOZ_OVERRIDE
{
if (mLocked) {
// The window might have been destroyed. The buffer is no longer
// valid at that point.
sp<GonkNativeWindow> window = mNativeWindow.promote();
if (window.get() && window->returnBuffer(mIndex, mGeneration)) {
mLocked = false;
} else {
// If the window doesn't exist any more, release the buffer
// directly.
ImageBridgeChild *ibc = ImageBridgeChild::GetSingleton();
ibc->DeallocSurfaceDescriptorGralloc(mSurfaceDescriptor);
}
}
}
virtual void Unlock() MOZ_OVERRIDE;
protected:
wp<GonkNativeWindow> mNativeWindow;