TextureClient* CairoImage::GetTextureClient(CompositableClient *aClient) { if (!aClient) { return nullptr; } CompositableForwarder* forwarder = aClient->GetForwarder(); RefPtr<TextureClient> textureClient = mTextureClients.Get(forwarder->GetSerial()); if (textureClient) { return textureClient; } RefPtr<SourceSurface> surface = GetAsSourceSurface(); MOZ_ASSERT(surface); if (!surface) { return nullptr; } // gfx::BackendType::NONE means default to content backend textureClient = aClient->CreateTextureClientForDrawing(surface->GetFormat(), surface->GetSize(), gfx::BackendType::NONE, TextureFlags::DEFAULT); if (!textureClient) { return nullptr; } MOZ_ASSERT(textureClient->CanExposeDrawTarget()); if (!textureClient->Lock(OpenMode::OPEN_WRITE_ONLY)) { return nullptr; } TextureClientAutoUnlock autoUnolck(textureClient); { // We must not keep a reference to the DrawTarget after it has been unlocked. DrawTarget* dt = textureClient->BorrowDrawTarget(); if (!dt) { return nullptr; } dt->CopySurface(surface, IntRect(IntPoint(), surface->GetSize()), IntPoint()); } mTextureClients.Put(forwarder->GetSerial(), textureClient); return textureClient; }
bool ImageClientSingle::UpdateImage(ImageContainer* aContainer, uint32_t aContentFlags) { AutoTArray<ImageContainer::OwningImage,4> images; uint32_t generationCounter; aContainer->GetCurrentImages(&images, &generationCounter); if (mLastUpdateGenerationCounter == generationCounter) { return true; } mLastUpdateGenerationCounter = generationCounter; for (int32_t i = images.Length() - 1; i >= 0; --i) { if (!images[i].mImage->IsValid()) { // Don't try to update to an invalid image. images.RemoveElementAt(i); } } if (images.IsEmpty()) { // This can happen if a ClearAllImages raced with SetCurrentImages from // another thread and ClearImagesFromImageBridge ran after the // SetCurrentImages call but before UpdateImageClientNow. // This can also happen if all images in the list are invalid. // We return true because the caller would attempt to recreate the // ImageClient otherwise, and that isn't going to help. return true; } nsTArray<Buffer> newBuffers; AutoTArray<CompositableForwarder::TimedTextureClient,4> textures; for (auto& img : images) { Image* image = img.mImage; #ifdef MOZ_WIDGET_GONK if (image->GetFormat() == ImageFormat::OVERLAY_IMAGE) { OverlayImage* overlayImage = static_cast<OverlayImage*>(image); OverlaySource source; if (overlayImage->GetSidebandStream().IsValid()) { // Duplicate GonkNativeHandle::NhObj for ipc, // since ParamTraits<GonkNativeHandle>::Write() absorbs native_handle_t. RefPtr<GonkNativeHandle::NhObj> nhObj = overlayImage->GetSidebandStream().GetDupNhObj(); GonkNativeHandle handle(nhObj); if (!handle.IsValid()) { gfxWarning() << "ImageClientSingle::UpdateImage failed in GetDupNhObj"; return false; } source.handle() = OverlayHandle(handle); } else { source.handle() = OverlayHandle(overlayImage->GetOverlayId()); } source.size() = overlayImage->GetSize(); GetForwarder()->UseOverlaySource(this, source, image->GetPictureRect()); continue; } #endif RefPtr<TextureClient> texture = image->GetTextureClient(this); const bool hasTextureClient = !!texture; for (int32_t i = mBuffers.Length() - 1; i >= 0; --i) { if (mBuffers[i].mImageSerial == image->GetSerial()) { if (hasTextureClient) { MOZ_ASSERT(image->GetTextureClient(this) == mBuffers[i].mTextureClient); } else { texture = mBuffers[i].mTextureClient; } // Remove this element from mBuffers so mBuffers only contains // images that aren't present in 'images' mBuffers.RemoveElementAt(i); } } if (!texture) { // Slow path, we should not be hitting it very often and if we do it means // we are using an Image class that is not backed by textureClient and we // should fix it. if (image->GetFormat() == ImageFormat::PLANAR_YCBCR) { PlanarYCbCrImage* ycbcr = static_cast<PlanarYCbCrImage*>(image); const PlanarYCbCrData* data = ycbcr->GetData(); if (!data) { return false; } texture = TextureClient::CreateForYCbCr(GetForwarder(), data->mYSize, data->mCbCrSize, data->mStereoMode, TextureFlags::DEFAULT | mTextureFlags ); if (!texture) { return false; } TextureClientAutoLock autoLock(texture, OpenMode::OPEN_WRITE_ONLY); if (!autoLock.Succeeded()) { return false; } bool status = UpdateYCbCrTextureClient(texture, *data); MOZ_ASSERT(status); if (!status) { return false; } } else if (image->GetFormat() == ImageFormat::SURFACE_TEXTURE || image->GetFormat() == ImageFormat::EGLIMAGE) { gfx::IntSize size = image->GetSize(); if (image->GetFormat() == ImageFormat::EGLIMAGE) { EGLImageImage* typedImage = image->AsEGLImageImage(); texture = EGLImageTextureData::CreateTextureClient( typedImage, size, GetForwarder(), mTextureFlags); #ifdef MOZ_WIDGET_ANDROID } else if (image->GetFormat() == ImageFormat::SURFACE_TEXTURE) { SurfaceTextureImage* typedImage = image->AsSurfaceTextureImage(); texture = AndroidSurfaceTextureData::CreateTextureClient( typedImage->GetSurfaceTexture(), size, typedImage->GetOriginPos(), GetForwarder(), mTextureFlags ); #endif } else { MOZ_ASSERT(false, "Bad ImageFormat."); } } else { RefPtr<gfx::SourceSurface> surface = image->GetAsSourceSurface(); MOZ_ASSERT(surface); texture = CreateTextureClientForDrawing(surface->GetFormat(), image->GetSize(), BackendSelector::Content, mTextureFlags); if (!texture) { return false; } MOZ_ASSERT(texture->CanExposeDrawTarget()); if (!texture->Lock(OpenMode::OPEN_WRITE_ONLY)) { return false; } { // We must not keep a reference to the DrawTarget after it has been unlocked. DrawTarget* dt = texture->BorrowDrawTarget(); if (!dt) { gfxWarning() << "ImageClientSingle::UpdateImage failed in BorrowDrawTarget"; return false; } MOZ_ASSERT(surface.get()); dt->CopySurface(surface, IntRect(IntPoint(), surface->GetSize()), IntPoint()); } texture->Unlock(); } } if (!texture || !AddTextureClient(texture)) { return false; } CompositableForwarder::TimedTextureClient* t = textures.AppendElement(); t->mTextureClient = texture; t->mTimeStamp = img.mTimeStamp; t->mPictureRect = image->GetPictureRect(); t->mFrameID = img.mFrameID; t->mProducerID = img.mProducerID; Buffer* newBuf = newBuffers.AppendElement(); newBuf->mImageSerial = image->GetSerial(); newBuf->mTextureClient = texture; texture->SyncWithObject(GetForwarder()->GetSyncObject()); } GetForwarder()->UseTextures(this, textures); for (auto& b : mBuffers) { RemoveTexture(b.mTextureClient); } mBuffers.SwapElements(newBuffers); return true; }
/* static */ already_AddRefed<TextureClient> ImageClient::CreateTextureClientForImage(Image* aImage, KnowsCompositor* aForwarder) { RefPtr<TextureClient> texture; if (aImage->GetFormat() == ImageFormat::PLANAR_YCBCR) { PlanarYCbCrImage* ycbcr = static_cast<PlanarYCbCrImage*>(aImage); const PlanarYCbCrData* data = ycbcr->GetData(); if (!data) { return nullptr; } texture = TextureClient::CreateForYCbCr(aForwarder, data->mYSize, data->mYStride, data->mCbCrSize, data->mCbCrStride, data->mStereoMode, data->mColorDepth, data->mYUVColorSpace, TextureFlags::DEFAULT); if (!texture) { return nullptr; } TextureClientAutoLock autoLock(texture, OpenMode::OPEN_WRITE_ONLY); if (!autoLock.Succeeded()) { return nullptr; } bool status = UpdateYCbCrTextureClient(texture, *data); MOZ_ASSERT(status); if (!status) { return nullptr; } #ifdef MOZ_WIDGET_ANDROID } else if (aImage->GetFormat() == ImageFormat::SURFACE_TEXTURE) { gfx::IntSize size = aImage->GetSize(); SurfaceTextureImage* typedImage = aImage->AsSurfaceTextureImage(); texture = AndroidSurfaceTextureData::CreateTextureClient( typedImage->GetHandle(), size, typedImage->GetContinuous(), typedImage->GetOriginPos(), aForwarder->GetTextureForwarder(), TextureFlags::DEFAULT); #endif } else { RefPtr<gfx::SourceSurface> surface = aImage->GetAsSourceSurface(); MOZ_ASSERT(surface); texture = TextureClient::CreateForDrawing(aForwarder, surface->GetFormat(), aImage->GetSize(), BackendSelector::Content, TextureFlags::DEFAULT); if (!texture) { return nullptr; } MOZ_ASSERT(texture->CanExposeDrawTarget()); if (!texture->Lock(OpenMode::OPEN_WRITE_ONLY)) { return nullptr; } { // We must not keep a reference to the DrawTarget after it has been unlocked. DrawTarget* dt = texture->BorrowDrawTarget(); if (!dt) { gfxWarning() << "ImageClientSingle::UpdateImage failed in BorrowDrawTarget"; return nullptr; } MOZ_ASSERT(surface.get()); dt->CopySurface(surface, IntRect(IntPoint(), surface->GetSize()), IntPoint()); } texture->Unlock(); } return texture.forget(); }
bool ImageClientSingle::UpdateImage(ImageContainer* aContainer, uint32_t aContentFlags) { AutoLockImage autoLock(aContainer); Image *image = autoLock.GetImage(); if (!image) { return false; } // Don't try to update to an invalid image. We return true because the caller // would attempt to recreate the ImageClient otherwise, and that isn't going // to help. if (!image->IsValid()) { return true; } if (mLastPaintedImageSerial == image->GetSerial()) { return true; } RefPtr<TextureClient> texture = image->GetTextureClient(this); AutoRemoveTexture autoRemoveTexture(this); if (texture != mFrontBuffer) { autoRemoveTexture.mTexture = mFrontBuffer; mFrontBuffer = nullptr; } if (!texture) { // Slow path, we should not be hitting it very often and if we do it means // we are using an Image class that is not backed by textureClient and we // should fix it. if (image->GetFormat() == ImageFormat::PLANAR_YCBCR) { PlanarYCbCrImage* ycbcr = static_cast<PlanarYCbCrImage*>(image); const PlanarYCbCrData* data = ycbcr->GetData(); if (!data) { return false; } texture = TextureClient::CreateForYCbCr(GetForwarder(), data->mYSize, data->mCbCrSize, data->mStereoMode, TextureFlags::DEFAULT | mTextureFlags ); if (!texture || !texture->Lock(OpenMode::OPEN_WRITE_ONLY)) { return false; } bool status = texture->AsTextureClientYCbCr()->UpdateYCbCr(*data); MOZ_ASSERT(status); texture->Unlock(); if (!status) { return false; } } else if (image->GetFormat() == ImageFormat::SURFACE_TEXTURE || image->GetFormat() == ImageFormat::EGLIMAGE) { gfx::IntSize size = image->GetSize(); if (image->GetFormat() == ImageFormat::EGLIMAGE) { EGLImageImage* typedImage = static_cast<EGLImageImage*>(image); texture = new EGLImageTextureClient(GetForwarder(), mTextureFlags, typedImage, size); #ifdef MOZ_WIDGET_ANDROID } else if (image->GetFormat() == ImageFormat::SURFACE_TEXTURE) { SurfaceTextureImage* typedImage = static_cast<SurfaceTextureImage*>(image); const SurfaceTextureImage::Data* data = typedImage->GetData(); texture = new SurfaceTextureClient(GetForwarder(), mTextureFlags, data->mSurfTex, size, data->mOriginPos); #endif } else { MOZ_ASSERT(false, "Bad ImageFormat."); } } else { RefPtr<gfx::SourceSurface> surface = image->GetAsSourceSurface(); MOZ_ASSERT(surface); texture = CreateTextureClientForDrawing(surface->GetFormat(), image->GetSize(), gfx::BackendType::NONE, mTextureFlags); if (!texture) { return false; } MOZ_ASSERT(texture->CanExposeDrawTarget()); if (!texture->Lock(OpenMode::OPEN_WRITE_ONLY)) { return false; } { // We must not keep a reference to the DrawTarget after it has been unlocked. DrawTarget* dt = texture->BorrowDrawTarget(); if (!dt) { gfxWarning() << "ImageClientSingle::UpdateImage failed in BorrowDrawTarget"; return false; } MOZ_ASSERT(surface.get()); dt->CopySurface(surface, IntRect(IntPoint(), surface->GetSize()), IntPoint()); } texture->Unlock(); } } if (!texture || !AddTextureClient(texture)) { return false; } mFrontBuffer = texture; GetForwarder()->UseTexture(this, texture); UpdatePictureRect(image->GetPictureRect()); mLastPaintedImageSerial = image->GetSerial(); aContainer->NotifyPaintedImage(image); texture->SyncWithObject(GetForwarder()->GetSyncObject()); return true; }
TextureClient* CairoImage::GetTextureClient(CompositableClient *aClient) { if (!aClient) { return nullptr; } CompositableForwarder* forwarder = aClient->GetForwarder(); RefPtr<TextureClient> textureClient = mTextureClients.Get(forwarder->GetSerial()); if (textureClient) { return textureClient; } RefPtr<SourceSurface> surface = GetAsSourceSurface(); MOZ_ASSERT(surface); if (!surface) { return nullptr; } // XXX windows' TextureClients do not hold ISurfaceAllocator, // recycler does not work on windows. #ifndef XP_WIN // XXX only gonk ensure when TextureClient is recycled, // TextureHost is not used by CompositableHost. #ifdef MOZ_WIDGET_GONK RefPtr<TextureClientRecycleAllocator> recycler = aClient->GetTextureClientRecycler(); if (recycler) { textureClient = recycler->CreateOrRecycleForDrawing(surface->GetFormat(), surface->GetSize(), gfx::BackendType::NONE, aClient->GetTextureFlags()); } #endif #endif if (!textureClient) { // gfx::BackendType::NONE means default to content backend textureClient = aClient->CreateTextureClientForDrawing(surface->GetFormat(), surface->GetSize(), gfx::BackendType::NONE, TextureFlags::DEFAULT); } if (!textureClient) { return nullptr; } MOZ_ASSERT(textureClient->CanExposeDrawTarget()); if (!textureClient->Lock(OpenMode::OPEN_WRITE_ONLY)) { return nullptr; } TextureClientAutoUnlock autoUnolck(textureClient); { // We must not keep a reference to the DrawTarget after it has been unlocked. DrawTarget* dt = textureClient->BorrowDrawTarget(); if (!dt) { return nullptr; } dt->CopySurface(surface, IntRect(IntPoint(), surface->GetSize()), IntPoint()); } mTextureClients.Put(forwarder->GetSerial(), textureClient); return textureClient; }
bool ImageClientSingle::UpdateImageInternal(ImageContainer* aContainer, uint32_t aContentFlags, bool* aIsSwapped) { AutoLockImage autoLock(aContainer); *aIsSwapped = false; Image *image = autoLock.GetImage(); if (!image) { return false; } if (mLastPaintedImageSerial == image->GetSerial()) { return true; } AutoRemoveTexture autoRemoveTexture(this); if (image->AsSharedImage() && image->AsSharedImage()->GetTextureClient(this)) { // fast path: no need to allocate and/or copy image data RefPtr<TextureClient> texture = image->AsSharedImage()->GetTextureClient(this); autoRemoveTexture.mTexture = mFrontBuffer; mFrontBuffer = texture; if (!AddTextureClient(texture)) { mFrontBuffer = nullptr; return false; } GetForwarder()->UpdatedTexture(this, texture, nullptr); GetForwarder()->UseTexture(this, texture); } else if (image->GetFormat() == ImageFormat::PLANAR_YCBCR) { PlanarYCbCrImage* ycbcr = static_cast<PlanarYCbCrImage*>(image); const PlanarYCbCrData* data = ycbcr->GetData(); if (!data) { return false; } if (mFrontBuffer && mFrontBuffer->IsImmutable()) { autoRemoveTexture.mTexture = mFrontBuffer; mFrontBuffer = nullptr; } bool bufferCreated = false; if (!mFrontBuffer) { gfx::IntSize ySize(data->mYSize.width, data->mYSize.height); gfx::IntSize cbCrSize(data->mCbCrSize.width, data->mCbCrSize.height); mFrontBuffer = TextureClient::CreateForYCbCr(GetForwarder(), ySize, cbCrSize, data->mStereoMode, TextureFlags::DEFAULT|mTextureFlags); if (!mFrontBuffer) { return false; } bufferCreated = true; } if (!mFrontBuffer->Lock(OpenMode::OPEN_WRITE_ONLY)) { mFrontBuffer = nullptr; return false; } bool status = mFrontBuffer->AsTextureClientYCbCr()->UpdateYCbCr(*data); mFrontBuffer->Unlock(); if (bufferCreated) { if (!AddTextureClient(mFrontBuffer)) { mFrontBuffer = nullptr; return false; } } if (status) { GetForwarder()->UpdatedTexture(this, mFrontBuffer, nullptr); GetForwarder()->UseTexture(this, mFrontBuffer); } else { MOZ_ASSERT(false); return false; } } else if (image->GetFormat() == ImageFormat::SHARED_TEXTURE) { SharedTextureImage* sharedImage = static_cast<SharedTextureImage*>(image); const SharedTextureImage::Data *data = sharedImage->GetData(); gfx::IntSize size = gfx::IntSize(image->GetSize().width, image->GetSize().height); if (mFrontBuffer) { autoRemoveTexture.mTexture = mFrontBuffer; mFrontBuffer = nullptr; } RefPtr<SharedTextureClientOGL> buffer = new SharedTextureClientOGL(mTextureFlags); buffer->InitWith(data->mHandle, size, data->mShareType, data->mInverted); mFrontBuffer = buffer; if (!AddTextureClient(mFrontBuffer)) { mFrontBuffer = nullptr; return false; } GetForwarder()->UseTexture(this, mFrontBuffer); } else { RefPtr<gfx::SourceSurface> surface = image->GetAsSourceSurface(); MOZ_ASSERT(surface); gfx::IntSize size = image->GetSize(); if (mFrontBuffer && (mFrontBuffer->IsImmutable() || mFrontBuffer->GetSize() != size)) { autoRemoveTexture.mTexture = mFrontBuffer; mFrontBuffer = nullptr; } bool bufferCreated = false; if (!mFrontBuffer) { gfxImageFormat format = gfxPlatform::GetPlatform()->OptimalFormatForContent(gfx::ContentForFormat(surface->GetFormat())); mFrontBuffer = CreateTextureClientForDrawing(gfx::ImageFormatToSurfaceFormat(format), size, gfx::BackendType::NONE, mTextureFlags); if (!mFrontBuffer) { return false; } MOZ_ASSERT(mFrontBuffer->CanExposeDrawTarget()); bufferCreated = true; } if (!mFrontBuffer->Lock(OpenMode::OPEN_WRITE_ONLY)) { mFrontBuffer = nullptr; return false; } { // We must not keep a reference to the DrawTarget after it has been unlocked. DrawTarget* dt = mFrontBuffer->BorrowDrawTarget(); MOZ_ASSERT(surface.get()); dt->CopySurface(surface, IntRect(IntPoint(), surface->GetSize()), IntPoint()); } mFrontBuffer->Unlock(); if (bufferCreated) { if (!AddTextureClient(mFrontBuffer)) { mFrontBuffer = nullptr; return false; } } GetForwarder()->UpdatedTexture(this, mFrontBuffer, nullptr); GetForwarder()->UseTexture(this, mFrontBuffer); } UpdatePictureRect(image->GetPictureRect()); mLastPaintedImageSerial = image->GetSerial(); aContainer->NotifyPaintedImage(image); *aIsSwapped = true; return true; }