зеркало из https://github.com/mozilla/gecko-dev.git
Bug 773440 - Remove one video frame copy when using async-video. r=roc
This commit is contained in:
Родитель
0a20ff27b9
Коммит
08383d674f
|
@ -139,11 +139,45 @@ ImageContainer::~ImageContainer()
|
|||
}
|
||||
}
|
||||
|
||||
void ImageContainer::CopyPlane(uint8_t *aDst, uint8_t *aSrc,
|
||||
const gfxIntSize &aSize,
|
||||
int32_t aSrcStride, int32_t aDstStride,
|
||||
int32_t aOffset, int32_t aSkip)
|
||||
{
|
||||
if (!aOffset && !aSkip && aSrcStride == aDstStride) {
|
||||
// Fast path: planar input.
|
||||
memcpy(aDst, aSrc, aSize.height * aSrcStride);
|
||||
} else {
|
||||
int32_t height = aSize.height;
|
||||
int32_t width = aSize.width;
|
||||
for (int y = 0; y < height; ++y) {
|
||||
uint8_t *src = aSrc + aOffset;
|
||||
uint8_t *dst = aDst;
|
||||
if (!aSkip) {
|
||||
// Fast path: offset only, no per-pixel skip.
|
||||
memcpy(dst, src, width);
|
||||
} else {
|
||||
// Slow path
|
||||
for (int x = 0; x < width; ++x) {
|
||||
*dst++ = *src++;
|
||||
src += aSkip;
|
||||
}
|
||||
}
|
||||
aSrc += aSrcStride;
|
||||
aDst += aDstStride;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
already_AddRefed<Image>
|
||||
ImageContainer::CreateImage(const ImageFormat *aFormats,
|
||||
uint32_t aNumFormats)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
if (IsAsync()) {
|
||||
return mImageContainerChild->CreateImage(aFormats, aNumFormats);
|
||||
}
|
||||
return mImageFactory->CreateImage(aFormats, aNumFormats, mScaleHint, mRecycleBin);
|
||||
}
|
||||
|
||||
|
@ -411,71 +445,39 @@ PlanarYCbCrImage::AllocateBuffer(uint32_t aSize)
|
|||
return mRecycleBin->GetBuffer(aSize);
|
||||
}
|
||||
|
||||
static void
|
||||
CopyPlane(uint8_t *aDst, uint8_t *aSrc,
|
||||
const gfxIntSize &aSize, int32_t aStride,
|
||||
int32_t aOffset, int32_t aSkip)
|
||||
void PlanarYCbCrImage::Allocate(Data& aData)
|
||||
{
|
||||
if (!aOffset && !aSkip) {
|
||||
// Fast path: planar input.
|
||||
memcpy(aDst, aSrc, aSize.height * aStride);
|
||||
} else {
|
||||
int32_t height = aSize.height;
|
||||
int32_t width = aSize.width;
|
||||
for (int y = 0; y < height; ++y) {
|
||||
uint8_t *src = aSrc + aOffset;
|
||||
uint8_t *dst = aDst;
|
||||
if (!aSkip) {
|
||||
// Fast path: offset only, no per-pixel skip.
|
||||
memcpy(dst, src, width);
|
||||
} else {
|
||||
// Slow path
|
||||
for (int x = 0; x < width; ++x) {
|
||||
*dst++ = *src++;
|
||||
src += aSkip;
|
||||
}
|
||||
}
|
||||
aSrc += aStride;
|
||||
aDst += aStride;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PlanarYCbCrImage::CopyData(const Data& aData)
|
||||
{
|
||||
mData = aData;
|
||||
|
||||
// update buffer size
|
||||
mBufferSize = mData.mCbCrStride * mData.mCbCrSize.height * 2 +
|
||||
mData.mYStride * mData.mYSize.height;
|
||||
|
||||
int bufferSize = aData.mCbCrStride * aData.mCbCrSize.height * 2 +
|
||||
aData.mYStride * aData.mYSize.height;
|
||||
// get new buffer
|
||||
mBuffer = AllocateBuffer(mBufferSize);
|
||||
if (!mBuffer)
|
||||
uint8_t* buffer = AllocateBuffer(bufferSize);
|
||||
if (!buffer)
|
||||
return;
|
||||
|
||||
mData.mYChannel = mBuffer;
|
||||
mData.mCbChannel = mData.mYChannel + mData.mYStride * mData.mYSize.height;
|
||||
mData.mCrChannel = mData.mCbChannel + mData.mCbCrStride * mData.mCbCrSize.height;
|
||||
|
||||
CopyPlane(mData.mYChannel, aData.mYChannel,
|
||||
mData.mYSize, mData.mYStride,
|
||||
mData.mYOffset, mData.mYSkip);
|
||||
CopyPlane(mData.mCbChannel, aData.mCbChannel,
|
||||
mData.mCbCrSize, mData.mCbCrStride,
|
||||
mData.mCbOffset, mData.mCbSkip);
|
||||
CopyPlane(mData.mCrChannel, aData.mCrChannel,
|
||||
mData.mCbCrSize, mData.mCbCrStride,
|
||||
mData.mCrOffset, mData.mCrSkip);
|
||||
|
||||
mSize = aData.mPicSize;
|
||||
aData.mYChannel = buffer;
|
||||
aData.mCbChannel = aData.mYChannel + aData.mYStride * aData.mYSize.height;
|
||||
aData.mCrChannel = aData.mCbChannel + aData.mCbCrStride * aData.mCbCrSize.height;
|
||||
mBuffer = buffer;
|
||||
}
|
||||
|
||||
void
|
||||
PlanarYCbCrImage::SetData(const Data &aData)
|
||||
{
|
||||
CopyData(aData);
|
||||
mData = aData;
|
||||
mBufferSize = mData.mCbCrStride * mData.mCbCrSize.height * 2 +
|
||||
mData.mYStride * mData.mYSize.height;
|
||||
mSize = mData.mPicSize;
|
||||
// If mBuffer has not been allocated (through Allocate(aData)), allocate it.
|
||||
// This code path is slower than the one used when Allocate has been called
|
||||
// since it will trigger a full copy.
|
||||
if (!mBuffer) {
|
||||
mBuffer = AllocateBuffer(mBufferSize);
|
||||
NS_ASSERTION(mBuffer, "Failed to Allocate!");
|
||||
}
|
||||
if (aData.mYChannel != mBuffer) {
|
||||
memcpy(mBuffer.get(), aData.mYChannel, mBufferSize);
|
||||
}
|
||||
}
|
||||
|
||||
already_AddRefed<gfxASurface>
|
||||
|
|
|
@ -39,6 +39,7 @@ class Shmem;
|
|||
namespace layers {
|
||||
|
||||
class ImageContainerChild;
|
||||
class SharedPlanarYCbCrImage;
|
||||
|
||||
struct ImageBackendData
|
||||
{
|
||||
|
@ -483,6 +484,14 @@ public:
|
|||
*/
|
||||
RemoteImageData *GetRemoteImageData() { return mRemoteData; }
|
||||
|
||||
/**
|
||||
* Helper function to copy an image buffer respecting stride, offset and skip.
|
||||
*/
|
||||
static void CopyPlane(uint8_t *aDst, uint8_t *aSrc,
|
||||
const gfxIntSize &aSize,
|
||||
int32_t aSrcStride, int32_t aDstStride,
|
||||
int32_t aOffset, int32_t aSkip);
|
||||
|
||||
protected:
|
||||
typedef mozilla::ReentrantMonitor ReentrantMonitor;
|
||||
|
||||
|
@ -651,9 +660,15 @@ public:
|
|||
|
||||
virtual ~PlanarYCbCrImage();
|
||||
|
||||
virtual SharedPlanarYCbCrImage* AsSharedPlanarYCbCrImage()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* This makes a copy of the data buffers, in order to support functioning
|
||||
* in all different layer managers.
|
||||
* If Allocate has been invoked on aData, simply acquire aData's buffers.
|
||||
* Otherwise make a copy of the data buffers, in order to support
|
||||
* functioning in all different layer managers.
|
||||
*/
|
||||
virtual void SetData(const Data& aData);
|
||||
|
||||
|
@ -669,6 +684,23 @@ public:
|
|||
*/
|
||||
virtual const Data* GetData() { return &mData; }
|
||||
|
||||
/**
|
||||
* Allocate image buffer(s) and give aData ownership of the image by filling
|
||||
* the pointers in aData.
|
||||
* The information about the size, stride, etc. must be set in aData
|
||||
* prior to calling this method.
|
||||
*
|
||||
* This method is meant to be used with SetData in the following order:
|
||||
* - The caller first fills the necessary information in aData for the data to
|
||||
* be allocated properly.
|
||||
* - The caller invoke Allocate(aData) which will fill the remaining pointers
|
||||
* in aData with allocated memory.
|
||||
* - The caller can fill the allocated buffer with actual image data.
|
||||
* - The caller then invoke SetData(aData) with the same aData that was
|
||||
* passed in Allocate.
|
||||
*/
|
||||
virtual void Allocate(Data& aData);
|
||||
|
||||
/**
|
||||
* Return the number of bytes of heap memory used to store this image.
|
||||
*/
|
||||
|
|
|
@ -345,7 +345,7 @@ BasicShadowableImageLayer::Paint(gfxContext* aContext, Layer* aMaskLayer)
|
|||
}
|
||||
|
||||
YUVImage yuv(mBackBufferY, mBackBufferU, mBackBufferV,
|
||||
data->GetPictureRect());
|
||||
data->GetPictureRect(), 0);
|
||||
|
||||
BasicManager()->PaintedImage(BasicManager()->Hold(this),
|
||||
yuv);
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
#include "ImageContainer.h"
|
||||
#include "GonkIOSurfaceImage.h"
|
||||
#include "GrallocImages.h"
|
||||
#include "mozilla/ReentrantMonitor.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
@ -39,6 +41,135 @@ namespace layers {
|
|||
static const unsigned int POOL_MAX_SHARED_IMAGES = 5;
|
||||
static const unsigned int MAX_ACTIVE_SHARED_IMAGES = 10;
|
||||
|
||||
/**
|
||||
* A YCbCr image that stores its data in shared memory directly so that it's
|
||||
* data can be sent to the compositor without being copied.
|
||||
*/
|
||||
class SharedPlanarYCbCrImage : public PlanarYCbCrImage
|
||||
{
|
||||
friend class mozilla::layers::ImageContainerChild;
|
||||
public:
|
||||
SharedPlanarYCbCrImage(ImageContainerChild* aProtocol)
|
||||
: PlanarYCbCrImage(nullptr), mImageDataAllocator(aProtocol), mSent(false)
|
||||
{
|
||||
MOZ_COUNT_CTOR(SharedPlanarYCbCrImage);
|
||||
}
|
||||
|
||||
~SharedPlanarYCbCrImage()
|
||||
{
|
||||
if (mYSurface) {
|
||||
SharedImage* sharedImg = new SharedImage();
|
||||
ToSharedImage(sharedImg);
|
||||
mImageDataAllocator->RecycleSharedImage(sharedImg);
|
||||
}
|
||||
MOZ_COUNT_DTOR(SharedPlanarYCbCrImage);
|
||||
}
|
||||
|
||||
/**
|
||||
* To prevent a SharedPlanarYCbCrImage from being sent several times we
|
||||
* store a boolean state telling wether the image has already been sent to
|
||||
* the compositor.
|
||||
*/
|
||||
bool IsSent() const
|
||||
{
|
||||
return mSent;
|
||||
}
|
||||
|
||||
SharedPlanarYCbCrImage* AsSharedPlanarYCbCrImage() MOZ_OVERRIDE
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
void ToSharedImage(SharedImage* aImage)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(aImage, "aImage must be allocated");
|
||||
*aImage = YUVImage(mYSurface->GetShmem(),
|
||||
mCbSurface->GetShmem(),
|
||||
mCrSurface->GetShmem(),
|
||||
mData.GetPictureRect(),
|
||||
reinterpret_cast<uintptr_t>(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns nullptr because in most cases the YCbCrImage has lost ownership of
|
||||
* its data when this is called.
|
||||
*/
|
||||
already_AddRefed<gfxASurface> GetAsSurface()
|
||||
{
|
||||
if (!mYSurface) {
|
||||
return nullptr;
|
||||
}
|
||||
return PlanarYCbCrImage::GetAsSurface();
|
||||
}
|
||||
|
||||
/**
|
||||
* See PlanarYCbCrImage::SeData.
|
||||
* This proxies a synchronous call to the ImageBridgeChild thread.
|
||||
*/
|
||||
virtual void Allocate(Data& aData) MOZ_OVERRIDE
|
||||
{
|
||||
// copy aData into mData to have the sizes and strides info
|
||||
// that will be needed by the ImageContainerChild to allocate
|
||||
// shared buffers.
|
||||
mData = aData;
|
||||
// mImageDataAllocator will allocate the shared buffers and
|
||||
// place them into 'this'
|
||||
mImageDataAllocator->AllocateSharedBufferForImage(this);
|
||||
// give aData the resulting buffers
|
||||
aData.mYChannel = mYSurface->Data();
|
||||
aData.mCbChannel = mCbSurface->Data();
|
||||
aData.mCrChannel = mCrSurface->Data();
|
||||
}
|
||||
|
||||
/**
|
||||
* See PlanarYCbCrImage::SeData.
|
||||
*/
|
||||
virtual void SetData(const Data& aData)
|
||||
{
|
||||
// do not set mBuffer like in PlanarYCbCrImage because the later
|
||||
// will try to manage this memory without knowing it belongs to a
|
||||
// shmem.
|
||||
mData = aData;
|
||||
mBufferSize = mData.mCbCrStride * mData.mCbCrSize.height * 2 +
|
||||
mData.mYStride * mData.mYSize.height;
|
||||
mSize = mData.mPicSize;
|
||||
|
||||
// If m*Surface has not been allocated (through Allocate(aData)), allocate it.
|
||||
// This code path is slower than the one used when Allocate has been called
|
||||
// since it will trigger a full copy.
|
||||
if (!mYSurface) {
|
||||
Data data = aData;
|
||||
Allocate(data);
|
||||
}
|
||||
if (mYSurface->Data() != aData.mYChannel) {
|
||||
ImageContainer::CopyPlane(mYSurface->Data(), aData.mYChannel,
|
||||
aData.mYSize,
|
||||
aData.mYStride, aData.mYSize.width,
|
||||
0,0);
|
||||
ImageContainer::CopyPlane(mCbSurface->Data(), aData.mCbChannel,
|
||||
aData.mCbCrSize,
|
||||
aData.mCbCrStride, aData.mCbCrSize.width,
|
||||
0,0);
|
||||
ImageContainer::CopyPlane(mCrSurface->Data(), aData.mCrChannel,
|
||||
aData.mCbCrSize,
|
||||
aData.mCbCrStride, aData.mCbCrSize.width,
|
||||
0,0);
|
||||
}
|
||||
}
|
||||
|
||||
void MarkAsSent() {
|
||||
mSent = true;
|
||||
}
|
||||
|
||||
protected:
|
||||
nsRefPtr<gfxSharedImageSurface> mYSurface;
|
||||
nsRefPtr<gfxSharedImageSurface> mCbSurface;
|
||||
nsRefPtr<gfxSharedImageSurface> mCrSurface;
|
||||
nsRefPtr<ImageContainerChild> mImageDataAllocator;
|
||||
bool mSent;
|
||||
};
|
||||
|
||||
|
||||
ImageContainerChild::ImageContainerChild()
|
||||
: mImageContainerID(0), mActiveImageCount(0),
|
||||
mStop(false), mDispatchedDestroy(false)
|
||||
|
@ -99,15 +230,23 @@ void ImageContainerChild::StopChild()
|
|||
|
||||
bool ImageContainerChild::RecvReturnImage(const SharedImage& aImage)
|
||||
{
|
||||
SharedImage* img = new SharedImage(aImage);
|
||||
// Remove oldest image from the queue.
|
||||
if (mImageQueue.Length() > 0) {
|
||||
mImageQueue.RemoveElementAt(0);
|
||||
}
|
||||
if (!AddSharedImageToPool(img) || mStop) {
|
||||
DestroySharedImage(*img);
|
||||
delete img;
|
||||
|
||||
if (aImage.type() == SharedImage::TYUVImage &&
|
||||
aImage.get_YUVImage().imageID() != 0) {
|
||||
// if the imageID is non-zero, it means that this image's buffers
|
||||
// are used in a SharedPlanarYCbCrImage that is maybe used in the
|
||||
// main thread. In this case we let ref counting take care of
|
||||
// deciding when to recycle the shared memory.
|
||||
return true;
|
||||
}
|
||||
|
||||
SharedImage* img = new SharedImage(aImage);
|
||||
RecycleSharedImageNow(img);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -198,7 +337,8 @@ SharedImage* ImageContainerChild::CreateSharedImageFromData(Image* image)
|
|||
YUVImage(tempBufferY->GetShmem(),
|
||||
tempBufferU->GetShmem(),
|
||||
tempBufferV->GetShmem(),
|
||||
data->GetPictureRect()));
|
||||
data->GetPictureRect(),
|
||||
0));
|
||||
NS_ABORT_IF_FALSE(result->type() == SharedImage::TYUVImage,
|
||||
"SharedImage type not set correctly");
|
||||
return result;
|
||||
|
@ -321,14 +461,32 @@ SharedImage* ImageContainerChild::ImageToSharedImage(Image* aImage)
|
|||
if (mStop) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
NS_ABORT_IF_FALSE(InImageBridgeChildThread(),
|
||||
"Should be in ImageBridgeChild thread.");
|
||||
if (aImage->GetFormat() == ImageFormat::PLANAR_YCBCR) {
|
||||
SharedPlanarYCbCrImage* sharedYCbCr =
|
||||
static_cast<PlanarYCbCrImage*>(aImage)->AsSharedPlanarYCbCrImage();
|
||||
if (sharedYCbCr) {
|
||||
if (sharedYCbCr->IsSent()) {
|
||||
// don't send the same image twice
|
||||
return nullptr;
|
||||
}
|
||||
// the image is already using shared memory, this means that we don't
|
||||
// need to copy it
|
||||
SharedImage* result = new SharedImage();
|
||||
sharedYCbCr->ToSharedImage(result);
|
||||
sharedYCbCr->MarkAsSent();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
if (mActiveImageCount > (int)MAX_ACTIVE_SHARED_IMAGES) {
|
||||
// Too many active shared images, perhaps the compositor is hanging.
|
||||
// Skipping current image
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
NS_ABORT_IF_FALSE(InImageBridgeChildThread(),
|
||||
"Should be in ImageBridgeChild thread.");
|
||||
SharedImage *img = GetSharedImageFor(aImage);
|
||||
if (img) {
|
||||
CopyDataIntoSharedImage(aImage, img);
|
||||
|
@ -394,6 +552,113 @@ void ImageContainerChild::DispatchDestroy()
|
|||
NewRunnableMethod(this, &ImageContainerChild::DestroyNow));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
already_AddRefed<Image> ImageContainerChild::CreateImage(const ImageFormat *aFormats,
|
||||
uint32_t aNumFormats)
|
||||
{
|
||||
// TODO: Add more image formats
|
||||
nsRefPtr<Image> img = new SharedPlanarYCbCrImage(this);
|
||||
return img.forget();
|
||||
}
|
||||
|
||||
void ImageContainerChild::AllocateSharedBufferForImageNow(Image* aImage)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(InImageBridgeChildThread(),
|
||||
"Should be in ImageBridgeChild thread.");
|
||||
NS_ABORT_IF_FALSE(aImage && aImage->GetFormat() == ImageFormat::PLANAR_YCBCR,
|
||||
"Only YUV images supported now");
|
||||
|
||||
SharedPlanarYCbCrImage* sharedYCbCr =
|
||||
static_cast<PlanarYCbCrImage*>(aImage)->AsSharedPlanarYCbCrImage();
|
||||
|
||||
// try to reuse shared images from the pool first...
|
||||
SharedImage* fromPool = GetSharedImageFor(aImage);
|
||||
if (fromPool) {
|
||||
YUVImage yuv = fromPool->get_YUVImage();
|
||||
nsRefPtr<gfxSharedImageSurface> surfY =
|
||||
gfxSharedImageSurface::Open(yuv.Ydata());
|
||||
nsRefPtr<gfxSharedImageSurface> surfU =
|
||||
gfxSharedImageSurface::Open(yuv.Udata());
|
||||
nsRefPtr<gfxSharedImageSurface> surfV =
|
||||
gfxSharedImageSurface::Open(yuv.Vdata());
|
||||
sharedYCbCr->mYSurface = surfY;
|
||||
sharedYCbCr->mCbSurface = surfU;
|
||||
sharedYCbCr->mCrSurface = surfV;
|
||||
} else {
|
||||
// ...else Allocate a shared image
|
||||
nsRefPtr<gfxSharedImageSurface> surfY;
|
||||
nsRefPtr<gfxSharedImageSurface> surfU;
|
||||
nsRefPtr<gfxSharedImageSurface> surfV;
|
||||
const PlanarYCbCrImage::Data* data = sharedYCbCr->GetData();
|
||||
if (!AllocateSharedBuffer(this, data->mYSize, gfxASurface::CONTENT_ALPHA,
|
||||
getter_AddRefs(surfY)) ||
|
||||
!AllocateSharedBuffer(this, data->mCbCrSize, gfxASurface::CONTENT_ALPHA,
|
||||
getter_AddRefs(surfU)) ||
|
||||
!AllocateSharedBuffer(this, data->mCbCrSize, gfxASurface::CONTENT_ALPHA,
|
||||
getter_AddRefs(surfV))) {
|
||||
NS_RUNTIMEABORT("creating SharedImage failed!");
|
||||
}
|
||||
sharedYCbCr->mYSurface = surfY;
|
||||
sharedYCbCr->mCbSurface = surfU;
|
||||
sharedYCbCr->mCrSurface = surfV;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ImageContainerChild::AllocateSharedBufferForImageSync(ReentrantMonitor* aBarrier,
|
||||
bool* aDone,
|
||||
Image* aImage)
|
||||
{
|
||||
AllocateSharedBufferForImageNow(aImage);
|
||||
ReentrantMonitorAutoEnter autoMon(*aBarrier);
|
||||
*aDone = true;
|
||||
aBarrier->NotifyAll();
|
||||
}
|
||||
|
||||
|
||||
void ImageContainerChild::AllocateSharedBufferForImage(Image* aImage)
|
||||
{
|
||||
|
||||
if (InImageBridgeChildThread()) {
|
||||
AllocateSharedBufferForImageNow(aImage);
|
||||
return;
|
||||
}
|
||||
|
||||
bool done = false;
|
||||
ReentrantMonitor barrier("ImageBridgeChild::AllocateSharedBufferForImage");
|
||||
ReentrantMonitorAutoEnter autoMon(barrier);
|
||||
GetMessageLoop()->PostTask(FROM_HERE,
|
||||
NewRunnableMethod(this,
|
||||
&ImageContainerChild::AllocateSharedBufferForImageSync,
|
||||
&barrier,
|
||||
&done,
|
||||
aImage));
|
||||
while (!done) {
|
||||
barrier.Wait();
|
||||
}
|
||||
}
|
||||
|
||||
void ImageContainerChild::RecycleSharedImageNow(SharedImage* aImage)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(InImageBridgeChildThread(),"Must be in the ImageBridgeChild Thread.");
|
||||
|
||||
if (mStop || !AddSharedImageToPool(aImage)) {
|
||||
DestroySharedImage(*aImage);
|
||||
delete aImage;
|
||||
}
|
||||
}
|
||||
|
||||
void ImageContainerChild::RecycleSharedImage(SharedImage* aImage)
|
||||
{
|
||||
if (InImageBridgeChildThread()) {
|
||||
RecycleSharedImageNow(aImage);
|
||||
return;
|
||||
}
|
||||
GetMessageLoop()->PostTask(FROM_HERE,
|
||||
NewRunnableMethod(this,
|
||||
&ImageContainerChild::RecycleSharedImageNow,
|
||||
aImage));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
|
|
@ -8,8 +8,12 @@
|
|||
|
||||
#include "mozilla/layers/PImageContainerChild.h"
|
||||
#include "mozilla/layers/ImageBridgeChild.h"
|
||||
#include "ImageTypes.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class ReentrantMonitor;
|
||||
|
||||
namespace layers {
|
||||
|
||||
class ImageBridgeCopyAndSendTask;
|
||||
|
@ -116,6 +120,31 @@ public:
|
|||
*/
|
||||
void SetIdleNow();
|
||||
|
||||
/**
|
||||
* Returns an instance of Image that should be of a Shared* subclass of Image
|
||||
* and that should not need to be copied in order to be sent to the compositor.
|
||||
*/
|
||||
already_AddRefed<Image> CreateImage(const ImageFormat *aFormats,
|
||||
uint32_t aNumFormats);
|
||||
|
||||
/**
|
||||
* Allocate shared buffers for the image.
|
||||
*
|
||||
* Can be called from any thread. If not called from the ImageBridge thread,
|
||||
* it will synchronously proxy the call to the ImageBirdgeThread since shared
|
||||
* memory can only be allocated in the IPDL thread.
|
||||
*/
|
||||
void AllocateSharedBufferForImage(Image* aImage);
|
||||
|
||||
/**
|
||||
* Can be called from any thread.
|
||||
* Deallocates or places aImage in the pool.
|
||||
* If this method is not called from the ImageBridgeChild thread,
|
||||
* a task is dispatched and the recycling is done asynchronously on
|
||||
* the ImageBridgeChild thread.
|
||||
*/
|
||||
void RecycleSharedImage(SharedImage* aImage);
|
||||
|
||||
protected:
|
||||
virtual PGrallocBufferChild*
|
||||
AllocPGrallocBuffer(const gfxIntSize&, const gfxContentType&,
|
||||
|
@ -188,6 +217,28 @@ protected:
|
|||
* Called by ImageToSharedImage.
|
||||
*/
|
||||
SharedImage * CreateSharedImageFromData(Image* aImage);
|
||||
/**
|
||||
* Allocate shared buffers for the image.
|
||||
* Must be called on the ImageBridgeChild thread.
|
||||
*/
|
||||
void AllocateSharedBufferForImageNow(Image* aImage);
|
||||
|
||||
/**
|
||||
* Calls AllocateSharedBufferForImageNow and notify the barrier monitor.
|
||||
* This is meant to be called by AllocateSharedBufferForImage if the
|
||||
* call must be proxied synchronously to the ImageBridgeChild's thread.
|
||||
*/
|
||||
void AllocateSharedBufferForImageSync(ReentrantMonitor* aBarrier,
|
||||
bool* aDone,
|
||||
Image* aImage);
|
||||
|
||||
/**
|
||||
* Either deallocate or place aImage in the shared image pool.
|
||||
* Must be called on the ImageBridgeChild thread.
|
||||
* aImage should not be used after this method is called.
|
||||
*/
|
||||
void RecycleSharedImageNow(SharedImage* aImage);
|
||||
|
||||
|
||||
private:
|
||||
uint64_t mImageContainerID;
|
||||
|
|
|
@ -73,6 +73,14 @@ struct YUVImage {
|
|||
Shmem Udata;
|
||||
Shmem Vdata;
|
||||
nsIntRect picture;
|
||||
/**
|
||||
* An ID meant to tell if the shared buffers are being reference counted
|
||||
* on the content side and making it possible to find the reference counted
|
||||
* object on the content side if needed.
|
||||
* If this ID is zero, it means the data is not reference counted and can
|
||||
* be recycled right after being sent back to the content side.
|
||||
*/
|
||||
uintptr_t imageID;
|
||||
};
|
||||
|
||||
union SharedImage {
|
||||
|
|
Загрузка…
Ссылка в новой задаче