already_AddRefed<ImageContainerChild> ImageBridgeChild::CreateImageContainerChild() { if (InImageBridgeChildThread()) { return ImageBridgeChild::CreateImageContainerChildNow(); } // ImageContainerChild can only be alocated on the ImageBridgeChild thread, so se // dispatch a task to the thread and block the current thread until the task has been // executed. nsRefPtr<ImageContainerChild> result = nullptr; ReentrantMonitor barrier("CreateImageContainerChild Lock"); ReentrantMonitorAutoEnter autoMon(barrier); bool done = false; GetMessageLoop()->PostTask(FROM_HERE, NewRunnableFunction(&CreateContainerChildSync, &result, &barrier, &done)); // should stop the thread until the ImageContainerChild has been created on // the other thread while (!done) { barrier.Wait(); } return result.forget(); }
void AsyncTransactionWaiter::WaitComplete() { MOZ_ASSERT(!InImageBridgeChildThread()); MonitorAutoLock mon(mCompletedMonitor); int count = 0; const int maxCount = 5; while (mWaitCount > 0 && (count < maxCount)) { if (!NS_SUCCEEDED(mCompletedMonitor.Wait(PR_MillisecondsToInterval(10000)))) { NS_WARNING("Failed to wait Monitor"); return; } if (count > 1) { printf_stderr("Waiting async transaction complete.\n"); } count++; } if (mWaitCount > 0) { printf_stderr("Timeout of waiting transaction complete."); } if (count == maxCount) { gfxDevCrash(gfx::LogReason::AsyncTransactionTimeout) << "Bug 1244883: AsyncTransactionWaiter timed out."; } }
void ImageContainerChild::SendImageNow(Image* aImage) { NS_ABORT_IF_FALSE(InImageBridgeChildThread(), "Should be in ImageBridgeChild thread."); if (mStop) { return; } bool needsCopy = false; // If the image can be converted to a shared image, no need to do a copy. SharedImage* img = AsSharedImage(aImage); if (!img) { needsCopy = true; // Try to get a compatible shared image from the pool img = GetSharedImageFor(aImage); if (!img && mActiveImageCount < (int)MAX_ACTIVE_SHARED_IMAGES) { // If no shared image available, allocate a new one img = AllocateSharedImageFor(aImage); } } if (img && (!needsCopy || CopyDataIntoSharedImage(aImage, img))) { // Keep a reference to the image we sent to compositor to maintain a // correct reference count. mImageQueue.AppendElement(aImage); SendPublishImage(*img); } else { NS_WARNING("Failed to send an image to the compositor"); } delete img; return; }
void ImageContainerChild::SendImageAsync(ImageContainer* aContainer, Image* aImage) { if(!aContainer || !aImage) { return; } if (mStop) { return; } if (InImageBridgeChildThread()) { SharedImage *img = ImageToSharedImage(aImage); if (img) { SendPublishImage(*img); } else { NS_WARNING("Failed to create a shared image!"); } delete img; return; } // Sending images and (potentially) allocating shmems must be done // on the ImageBridgeChild thread. Task *t = new ImageBridgeCopyAndSendTask(this, aContainer, aImage); GetMessageLoop()->PostTask(FROM_HERE, t); }
// dispatched function static void ImageBridgeShutdownStep1(ReentrantMonitor *aBarrier, bool *aDone) { ReentrantMonitorAutoEnter autoMon(*aBarrier); MOZ_ASSERT(InImageBridgeChildThread(), "Should be in ImageBridgeChild thread."); MediaSystemResourceManager::Shutdown(); if (sImageBridgeChildSingleton) { // Force all managed protocols to shut themselves down cleanly InfallibleTArray<PCompositableChild*> compositables; sImageBridgeChildSingleton->ManagedPCompositableChild(compositables); for (int i = compositables.Length() - 1; i >= 0; --i) { CompositableClient::FromIPDLActor(compositables[i])->Destroy(); } InfallibleTArray<PTextureChild*> textures; sImageBridgeChildSingleton->ManagedPTextureChild(textures); for (int i = textures.Length() - 1; i >= 0; --i) { TextureClient* client = TextureClient::AsTextureClient(textures[i]); if (client) { client->ForceRemove(); } } sImageBridgeChildSingleton->SendWillStop(); sImageBridgeChildSingleton->MarkShutDown(); // From now on, no message can be sent through the image bridge from the // client side except the final Stop message. } *aDone = true; aBarrier->NotifyAll(); }
void ImageBridgeChild::DestroyBridge() { NS_ABORT_IF_FALSE(!InImageBridgeChildThread(), "This method must not be called in this thread."); // ...because we are about to dispatch synchronous messages to the // ImageBridgeChild thread. if (!IsCreated()) { return; } ReentrantMonitor barrier("ImageBridgeDestroyTask lock"); ReentrantMonitorAutoEnter autoMon(barrier); bool done = false; sImageBridgeChildSingleton->GetMessageLoop()->PostTask(FROM_HERE, NewRunnableFunction(&StopImageBridgeSync, &barrier, &done)); while (!done) { barrier.Wait(); } done = false; sImageBridgeChildSingleton->GetMessageLoop()->PostTask(FROM_HERE, NewRunnableFunction(&DeleteImageBridgeSync, &barrier, &done)); while (!done) { barrier.Wait(); } }
void ImageContainerChild::DestroySharedImage(const SharedImage& aImage) { NS_ABORT_IF_FALSE(InImageBridgeChildThread(), "Should be in ImageBridgeChild thread."); --mActiveImageCount; DeallocSharedImageData(this, aImage); }
SharedImage* ImageContainerChild::CreateSharedImageFromData(Image* image) { NS_ABORT_IF_FALSE(InImageBridgeChildThread(), "Should be in ImageBridgeChild thread."); ++mActiveImageCount; // TODO: I don't test for BasicManager()->IsCompositingCheap() here, // is this a problem? (the equvivalent code in PCompositor does that) if (image->GetFormat() == Image::PLANAR_YCBCR ) { PlanarYCbCrImage *YCbCrImage = static_cast<PlanarYCbCrImage*>(image); const PlanarYCbCrImage::Data *data = YCbCrImage->GetData(); NS_ASSERTION(data, "Must be able to retrieve yuv data from image!"); nsRefPtr<gfxSharedImageSurface> tempBufferY; nsRefPtr<gfxSharedImageSurface> tempBufferU; nsRefPtr<gfxSharedImageSurface> tempBufferV; if (!this->AllocBuffer(data->mYSize, gfxASurface::CONTENT_ALPHA, getter_AddRefs(tempBufferY)) || !this->AllocBuffer(data->mCbCrSize, gfxASurface::CONTENT_ALPHA, getter_AddRefs(tempBufferU)) || !this->AllocBuffer(data->mCbCrSize, gfxASurface::CONTENT_ALPHA, getter_AddRefs(tempBufferV))) { NS_RUNTIMEABORT("creating SharedImage failed!"); } for (int i = 0; i < data->mYSize.height; i++) { memcpy(tempBufferY->Data() + i * tempBufferY->Stride(), data->mYChannel + i * data->mYStride, data->mYSize.width); } for (int i = 0; i < data->mCbCrSize.height; i++) { memcpy(tempBufferU->Data() + i * tempBufferU->Stride(), data->mCbChannel + i * data->mCbCrStride, data->mCbCrSize.width); memcpy(tempBufferV->Data() + i * tempBufferV->Stride(), data->mCrChannel + i * data->mCbCrStride, data->mCbCrSize.width); } SharedImage* result = new SharedImage( *(new YUVImage(tempBufferY->GetShmem(), tempBufferU->GetShmem(), tempBufferV->GetShmem(), data->GetPictureRect()))); NS_ABORT_IF_FALSE(result->type() == SharedImage::TYUVImage, "SharedImage type not set correctly"); return result; } else if (image->GetFormat() == Image::GONK_IO_SURFACE) { GonkIOSurfaceImage* gonkImage = static_cast<GonkIOSurfaceImage*>(image); SharedImage* result = new SharedImage(gonkImage->GetSurfaceDescriptor()); return result; } else { NS_RUNTIMEABORT("TODO: Only YUVImage is supported here right now."); } return nsnull; }
void ImageContainerChild::ClearSharedImagePool() { NS_ABORT_IF_FALSE(InImageBridgeChildThread(), "Should be in ImageBridgeChild thread."); for(unsigned int i = 0; i < mSharedImagePool.Length(); ++i) { DeallocSharedImageData(this, *mSharedImagePool[i]); } mSharedImagePool.Clear(); }
void ImageContainerChild::DestroyNow() { NS_ABORT_IF_FALSE(InImageBridgeChildThread(), "Should be in ImageBridgeChild thread."); ClearSharedImagePool(); Send__delete__(this); }
SharedRGBImage::~SharedRGBImage() { MOZ_COUNT_DTOR(SharedRGBImage); if (mCompositable->GetAsyncID() != 0 && !InImageBridgeChildThread()) { ImageBridgeChild::DispatchReleaseTextureClient(mTextureClient.forget().drop()); ImageBridgeChild::DispatchReleaseImageClient(mCompositable.forget().drop()); } }
bool ImageBridgeChild::AllocShmem(size_t aSize, ipc::SharedMemory::SharedMemoryType aType, ipc::Shmem* aShmem) { if (InImageBridgeChildThread()) { return PImageBridgeChild::AllocShmem(aSize, aType, aShmem); } else { return DispatchAllocShmemInternal(aSize, aType, aShmem, false); // false: unsafe } }
// dispatched function static void DeleteImageBridgeSync(ReentrantMonitor *aBarrier, bool *aDone) { ReentrantMonitorAutoEnter autoMon(*aBarrier); NS_ABORT_IF_FALSE(InImageBridgeChildThread(), "Should be in ImageBridgeChild thread."); delete sImageBridgeChildSingleton; sImageBridgeChildSingleton = nullptr; *aDone = true; aBarrier->NotifyAll(); }
static void ReleaseImageClientNow(ImageClient* aClient, PImageContainerChild* aChild) { MOZ_ASSERT(InImageBridgeChildThread()); if (aClient) { aClient->Release(); } if (aChild) { aChild->SendAsyncDelete(); } }
//static void ImageBridgeChild::FlushAllImages(ImageClient* aClient, ImageContainer* aContainer, bool aExceptFront) { if (!IsCreated()) { return; } MOZ_ASSERT(aClient); MOZ_ASSERT(!sImageBridgeChildSingleton->mShuttingDown); MOZ_ASSERT(!InImageBridgeChildThread()); if (InImageBridgeChildThread()) { NS_ERROR("ImageBridgeChild::FlushAllImages() is called on ImageBridge thread."); return; } RefPtr<AsyncTransactionTracker> status = aClient->PrepareFlushAllImages(); sImageBridgeChildSingleton->GetMessageLoop()->PostTask( FROM_HERE, NewRunnableFunction(&FlushAllImagesSync, aClient, aContainer, aExceptFront, status)); status->WaitComplete(); }
// dispatched function static void ImageBridgeShutdownStep2(ReentrantMonitor *aBarrier, bool *aDone) { ReentrantMonitorAutoEnter autoMon(*aBarrier); MOZ_ASSERT(InImageBridgeChildThread(), "Should be in ImageBridgeChild thread."); sImageBridgeChildSingleton->SendStop(); *aDone = true; aBarrier->NotifyAll(); }
// dispatched function static void StopImageBridgeSync(ReentrantMonitor *aBarrier, bool *aDone) { ReentrantMonitorAutoEnter autoMon(*aBarrier); NS_ABORT_IF_FALSE(InImageBridgeChildThread(), "Should be in ImageBridgeChild thread."); if (sImageBridgeChildSingleton) { sImageBridgeChildSingleton->SendStop(); } *aDone = true; aBarrier->NotifyAll(); }
void ImageContainerChild::DestroyNow() { NS_ABORT_IF_FALSE(InImageBridgeChildThread(), "Should be in ImageBridgeChild thread."); NS_ABORT_IF_FALSE(mDispatchedDestroy, "Incorrect state in the destruction sequence."); ClearSharedImagePool(); mImageQueue.Clear(); // will decrease the refcount and, in most cases, delete the ImageContainerChild Send__delete__(this); Release(); // corresponds to the AddRef in DispatchDestroy }
//static void ImageBridgeChild::DispatchImageClientUpdate(ImageClient* aClient, ImageContainer* aContainer) { if (InImageBridgeChildThread()) { UpdateImageClientNow(aClient, aContainer); return; } sImageBridgeChildSingleton->GetMessageLoop()->PostTask( FROM_HERE, NewRunnableFunction< void (*)(ImageClient*, ImageContainer*), ImageClient*, nsRefPtr<ImageContainer> >(&UpdateImageClientNow, aClient, aContainer)); }
//static void ImageBridgeChild::FlushAllImages(ImageClient* aClient, ImageContainer* aContainer) { if (!IsCreated()) { return; } MOZ_ASSERT(aClient); MOZ_ASSERT(!sImageBridgeChildSingleton->mShuttingDown); MOZ_ASSERT(!InImageBridgeChildThread()); if (InImageBridgeChildThread()) { NS_ERROR("ImageBridgeChild::FlushAllImages() is called on ImageBridge thread."); return; } RefPtr<AsyncTransactionWaiter> waiter = new AsyncTransactionWaiter(); // This increment is balanced by the decrement in FlushAllImagesSync waiter->IncrementWaitCount(); sImageBridgeChildSingleton->GetMessageLoop()->PostTask( FROM_HERE, NewRunnableFunction(&FlushAllImagesSync, aClient, aContainer, waiter)); waiter->WaitComplete(); }
bool ImageContainerChild::AddSharedImageToPool(SharedImage* img) { NS_ABORT_IF_FALSE(InImageBridgeChildThread(), "AddSharedImageToPool must be called in the ImageBridgeChild thread"); if (mStop) { return false; } if (mSharedImagePool.Length() >= POOL_MAX_SHARED_IMAGES) { return false; } if (img->type() == SharedImage::TYCbCrImage) { mSharedImagePool.AppendElement(img); return true; } return false; // TODO accept more image formats in the pool }
void ImageContainerChild::Destroy() { if (mStop) return; mStop = true; if (mImageContainer) { mImageContainer->SetImageContainerChild(nsnull); } if (InImageBridgeChildThread()) { DestroyNow(); return; } // destruction must be done on the ImageBridgeChild thread Task * t = new ImageContainerChildDestroyTask(this); GetMessageLoop()->PostTask(FROM_HERE, t); }
void ImageContainerChild::SetIdle() { if (mStop) return; if (InImageBridgeChildThread()) { return SetIdleNow(); } Monitor barrier("SetIdle Lock"); MonitorAutoLock autoMon(barrier); bool done = false; GetMessageLoop()->PostTask(FROM_HERE, NewRunnableMethod(this, &ImageContainerChild::SetIdleSync, &barrier, &done)); while (!done) { barrier.Wait(); } }
SharedImage* ImageContainerChild::AllocateSharedImageFor(Image* image) { NS_ABORT_IF_FALSE(InImageBridgeChildThread(), "Should be in ImageBridgeChild thread."); if (!image) { return nullptr; } if (image->GetFormat() == PLANAR_YCBCR ) { PlanarYCbCrImage *planarYCbCrImage = static_cast<PlanarYCbCrImage*>(image); const PlanarYCbCrImage::Data *data = planarYCbCrImage->GetData(); NS_ASSERTION(data, "Must be able to retrieve yuv data from image!"); if (!data) { return nullptr; } SharedMemory::SharedMemoryType shmType = OptimalShmemType(); size_t size = ShmemYCbCrImage::ComputeMinBufferSize(data->mYSize, data->mCbCrSize); Shmem shmem; if (!AllocUnsafeShmem(size, shmType, &shmem)) { return nullptr; } ShmemYCbCrImage::InitializeBufferInfo(shmem.get<uint8_t>(), data->mYSize, data->mCbCrSize); ShmemYCbCrImage shmemImage(shmem); if (!shmemImage.IsValid()) { NS_WARNING("Failed to properly allocate image data!"); DeallocShmem(shmem); return nullptr; } ++mActiveImageCount; return new SharedImage(YCbCrImage(shmem, 0, data->GetPictureRect())); } else { NS_RUNTIMEABORT("TODO: Only YCbCrImage is supported here right now."); } return nullptr; }
void ImageContainerChild::SendImageAsync(ImageContainer* aContainer, Image* aImage) { if(!aContainer || !aImage) { return; } if (mStop) { return; } if (InImageBridgeChildThread()) { SendImageNow(aImage); } // Sending images and (potentially) allocating shmems must be done // on the ImageBridgeChild thread. Task *t = new ImageBridgeCopyAndSendTask(this, aContainer, aImage); GetMessageLoop()->PostTask(FROM_HERE, t); }
bool ImageBridgeChild::DeallocSurfaceDescriptorGralloc(const SurfaceDescriptor& aBuffer) { if (InImageBridgeChildThread()) { return ImageBridgeChild::DeallocSurfaceDescriptorGrallocNow(aBuffer); } Monitor barrier("DeallocSurfaceDescriptor Lock"); MonitorAutoLock autoMon(barrier); bool done = false; GetMessageLoop()->PostTask(FROM_HERE, NewRunnableFunction(&DeallocSurfaceDescriptorGrallocSync, aBuffer, &barrier, &done)); while (!done) { barrier.Wait(); } return true; }
// static void ImageBridgeChild::DispatchImageClientUpdate(ImageClient* aClient, ImageContainer* aContainer) { if (!ImageBridgeChild::IsCreated() || ImageBridgeChild::IsShutDown()) { NS_WARNING("Something is holding on to graphics resources after the shutdown" "of the graphics subsystem!"); return; } if (!aClient || !aContainer || !IsCreated()) { return; } if (InImageBridgeChildThread()) { UpdateImageClientNow(aClient, aContainer); return; } sImageBridgeChildSingleton->GetMessageLoop()->PostTask( FROM_HERE, NewRunnableFunction(&UpdateImageClientNow, aClient, RefPtr<ImageContainer>(aContainer))); }
SharedImage* ImageContainerChild::ImageToSharedImage(Image* aImage) { if (mStop) return nsnull; if (mActiveImageCount > MAX_ACTIVE_SHARED_IMAGES) { // Too many active shared images, perhaps the compositor is hanging. // Skipping current image return nsnull; } NS_ABORT_IF_FALSE(InImageBridgeChildThread(), "Should be in ImageBridgeChild thread."); SharedImage* img = PopSharedImageFromPool(); if (img) { CopyDataIntoSharedImage(aImage, img); } else { img = CreateSharedImageFromData(aImage); } mImageQueue.AppendElement(aImage); return img; }
TemporaryRef<ImageClient> ImageBridgeChild::CreateImageClient(CompositableType aType) { if (InImageBridgeChildThread()) { return CreateImageClientNow(aType); } ReentrantMonitor barrier("CreateImageClient Lock"); ReentrantMonitorAutoEnter autoMon(barrier); bool done = false; RefPtr<ImageClient> result = nullptr; GetMessageLoop()->PostTask(FROM_HERE, NewRunnableFunction(&CreateImageClientSync, &result, &barrier, aType, &done)); // should stop the thread until the ImageClient has been created on // the other thread while (!done) { barrier.Wait(); } return result.forget(); }
void ImageBridgeChild::DeallocShmem(ipc::Shmem& aShmem) { if (InImageBridgeChildThread()) { PImageBridgeChild::DeallocShmem(aShmem); } else { ReentrantMonitor barrier("AllocatorProxy Dealloc"); ReentrantMonitorAutoEnter autoMon(barrier); bool done = false; GetMessageLoop()->PostTask(FROM_HERE, NewRunnableFunction(&ProxyDeallocShmemNow, this, &aShmem, &barrier, &done)); while (!done) { barrier.Wait(); } } }