/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "CompositableTransactionParent.h" #include "CompositableHost.h" // for CompositableParent, etc #include "CompositorBridgeParent.h" // for CompositorBridgeParent #include "GLContext.h" // for GLContext #include "Layers.h" // for Layer #include "RenderTrace.h" // for RenderTraceInvalidateEnd, etc #include "mozilla/Assertions.h" // for MOZ_ASSERT, etc #include "mozilla/RefPtr.h" // for RefPtr #include "mozilla/layers/CompositorTypes.h" #include "mozilla/layers/ContentHost.h" // for ContentHostBase #include "mozilla/layers/ImageBridgeParent.h" // for ImageBridgeParent #include "mozilla/layers/LayerManagerComposite.h" #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/TiledContentHost.h" #include "mozilla/layers/PaintedLayerComposite.h" #include "mozilla/mozalloc.h" // for operator delete #include "mozilla/Unused.h" #include "nsDebug.h" // for NS_WARNING, NS_ASSERTION #include "nsRegion.h" // for nsIntRegion #ifdef MOZ_WIDGET_ANDROID # include "mozilla/layers/AndroidHardwareBuffer.h" #endif namespace mozilla { namespace layers { class ClientTiledLayerBuffer; class Compositor; // This function can in some cases fail and return false without it being a bug. // This can theoretically happen if the ImageBridge sends frames before // we created the layer tree. Since we can't enforce that the layer // tree is already created before ImageBridge operates, there isn't much // we can do about it, but in practice it is very rare. // Typically when a tab with a video is dragged from a window to another, // there can be a short time when the video is still sending frames // asynchonously while the layer tree is not reconstructed. It's not a // big deal. // Note that Layers transactions do not need to call this because they always // schedule the composition, in LayerManagerComposite::EndTransaction. static bool ScheduleComposition(CompositableHost* aCompositable) { uint64_t id = aCompositable->GetCompositorBridgeID(); if (!id) { return false; } CompositorBridgeParent* cp = CompositorBridgeParent::GetCompositorBridgeParent(id); if (!cp) { return false; } cp->ScheduleComposition(); return true; } bool CompositableParentManager::ReceiveCompositableUpdate( const CompositableOperation& aEdit) { // Ignore all operations on compositables created on stale compositors. We // return true because the child is unable to handle errors. RefPtr compositable = FindCompositable(aEdit.compositable()); if (!compositable) { return false; } return ReceiveCompositableUpdate(aEdit.detail(), WrapNotNull(compositable)); } bool CompositableParentManager::ReceiveCompositableUpdate( const CompositableOperationDetail& aDetail, NotNull aCompositable) { if (TextureSourceProvider* provider = aCompositable->GetTextureSourceProvider()) { if (!provider->IsValid()) { return false; } } switch (aDetail.type()) { case CompositableOperationDetail::TOpPaintTextureRegion: { MOZ_LAYERS_LOG(("[ParentSide] Paint PaintedLayer")); const OpPaintTextureRegion& op = aDetail.get_OpPaintTextureRegion(); Layer* layer = aCompositable->GetLayer(); if (!layer || layer->GetType() != Layer::TYPE_PAINTED) { return false; } PaintedLayerComposite* thebes = static_cast(layer); const ThebesBufferData& bufferData = op.bufferData(); RenderTraceInvalidateStart(thebes, "FF00FF", op.updatedRegion().GetBounds()); if (!aCompositable->UpdateThebes(bufferData, op.updatedRegion(), thebes->GetValidRegion())) { return false; } RenderTraceInvalidateEnd(thebes, "FF00FF"); break; } case CompositableOperationDetail::TOpUseTiledLayerBuffer: { MOZ_LAYERS_LOG(("[ParentSide] Paint TiledLayerBuffer")); const OpUseTiledLayerBuffer& op = aDetail.get_OpUseTiledLayerBuffer(); TiledContentHost* tiledHost = aCompositable->AsTiledContentHost(); NS_ASSERTION(tiledHost, "The compositable is not tiled"); const SurfaceDescriptorTiles& tileDesc = op.tileLayerDescriptor(); bool success = tiledHost->UseTiledLayerBuffer(this, tileDesc); const nsTArray& tileDescriptors = tileDesc.tiles(); for (size_t i = 0; i < tileDescriptors.Length(); i++) { const TileDescriptor& tileDesc = tileDescriptors[i]; if (tileDesc.type() != TileDescriptor::TTexturedTileDescriptor) { continue; } const TexturedTileDescriptor& texturedDesc = tileDesc.get_TexturedTileDescriptor(); RefPtr texture = TextureHost::AsTextureHost(texturedDesc.textureParent()); if (texture) { texture->SetLastFwdTransactionId(mFwdTransactionId); // Make sure that each texture was handled by the compositable // because the recycling logic depends on it. MOZ_ASSERT(texture->NumCompositableRefs() > 0); } if (texturedDesc.textureOnWhiteParent().isSome()) { texture = TextureHost::AsTextureHost( texturedDesc.textureOnWhiteParent().ref()); if (texture) { texture->SetLastFwdTransactionId(mFwdTransactionId); // Make sure that each texture was handled by the compositable // because the recycling logic depends on it. MOZ_ASSERT(texture->NumCompositableRefs() > 0); } } } if (!success) { return false; } break; } case CompositableOperationDetail::TOpRemoveTexture: { const OpRemoveTexture& op = aDetail.get_OpRemoveTexture(); RefPtr tex = TextureHost::AsTextureHost(op.textureParent()); MOZ_ASSERT(tex.get()); aCompositable->RemoveTextureHost(tex); break; } case CompositableOperationDetail::TOpUseTexture: { const OpUseTexture& op = aDetail.get_OpUseTexture(); AutoTArray textures; for (auto& timedTexture : op.textures()) { CompositableHost::TimedTexture* t = textures.AppendElement(); t->mTexture = TextureHost::AsTextureHost(timedTexture.textureParent()); MOZ_ASSERT(t->mTexture); t->mTimeStamp = timedTexture.timeStamp(); t->mPictureRect = timedTexture.picture(); t->mFrameID = timedTexture.frameID(); t->mProducerID = timedTexture.producerID(); if (timedTexture.readLocked()) { t->mTexture->SetReadLocked(); } } if (textures.Length() > 0) { aCompositable->UseTextureHost(textures); for (auto& timedTexture : op.textures()) { RefPtr texture = TextureHost::AsTextureHost(timedTexture.textureParent()); if (texture) { texture->SetLastFwdTransactionId(mFwdTransactionId); // Make sure that each texture was handled by the compositable // because the recycling logic depends on it. MOZ_ASSERT(texture->NumCompositableRefs() > 0); } } } if (UsesImageBridge() && aCompositable->GetLayer()) { ScheduleComposition(aCompositable); } break; } case CompositableOperationDetail::TOpUseComponentAlphaTextures: { const OpUseComponentAlphaTextures& op = aDetail.get_OpUseComponentAlphaTextures(); RefPtr texOnBlack = TextureHost::AsTextureHost(op.textureOnBlackParent()); RefPtr texOnWhite = TextureHost::AsTextureHost(op.textureOnWhiteParent()); if (op.readLockedBlack()) { texOnBlack->SetReadLocked(); } if (op.readLockedWhite()) { texOnWhite->SetReadLocked(); } MOZ_ASSERT(texOnBlack && texOnWhite); aCompositable->UseComponentAlphaTextures(texOnBlack, texOnWhite); if (texOnBlack) { texOnBlack->SetLastFwdTransactionId(mFwdTransactionId); // Make sure that each texture was handled by the compositable // because the recycling logic depends on it. MOZ_ASSERT(texOnBlack->NumCompositableRefs() > 0); } if (texOnWhite) { texOnWhite->SetLastFwdTransactionId(mFwdTransactionId); // Make sure that each texture was handled by the compositable // because the recycling logic depends on it. MOZ_ASSERT(texOnWhite->NumCompositableRefs() > 0); } if (UsesImageBridge()) { ScheduleComposition(aCompositable); } break; } case CompositableOperationDetail::TOpDeliverAcquireFence: { const OpDeliverAcquireFence& op = aDetail.get_OpDeliverAcquireFence(); RefPtr tex = TextureHost::AsTextureHost(op.textureParent()); MOZ_ASSERT(tex.get()); MOZ_ASSERT(tex->AsAndroidHardwareBufferTextureHost()); auto fenceFd = op.fenceFd(); tex->SetAcquireFence(std::move(fenceFd)); break; } default: { MOZ_ASSERT(false, "bad type"); } } return true; } void CompositableParentManager::DestroyActor(const OpDestroy& aOp) { switch (aOp.type()) { case OpDestroy::TPTextureParent: { auto actor = aOp.get_PTextureParent(); TextureHost::ReceivedDestroy(actor); break; } case OpDestroy::TCompositableHandle: { ReleaseCompositable(aOp.get_CompositableHandle()); break; } default: { MOZ_ASSERT(false, "unsupported type"); } } } RefPtr CompositableParentManager::AddCompositable( const CompositableHandle& aHandle, const TextureInfo& aInfo, bool aUseWebRender) { if (mCompositables.find(aHandle.Value()) != mCompositables.end()) { NS_ERROR("Client should not allocate duplicate handles"); return nullptr; } if (!aHandle) { NS_ERROR("Client should not allocate 0 as a handle"); return nullptr; } RefPtr host = CompositableHost::Create(aInfo, aUseWebRender); if (!host) { return nullptr; } mCompositables[aHandle.Value()] = host; return host; } RefPtr CompositableParentManager::FindCompositable( const CompositableHandle& aHandle, bool aAllowDisablingWebRender) { auto iter = mCompositables.find(aHandle.Value()); if (iter == mCompositables.end()) { return nullptr; } RefPtr host = iter->second; if (!aAllowDisablingWebRender) { return host; } if (!host->AsWebRenderImageHost() || !host->GetAsyncRef()) { return host; } // Try to replace WebRenderImageHost of ImageBridge to ImageHost. RefPtr newHost = CompositableHost::Create( host->GetTextureInfo(), /* aUseWebRender */ false); if (!newHost || !newHost->AsImageHost()) { MOZ_ASSERT_UNREACHABLE("unexpected to be called"); return host; } newHost->SetAsyncRef(host->GetAsyncRef()); mCompositables[aHandle.Value()] = newHost; return newHost; } void CompositableParentManager::ReleaseCompositable( const CompositableHandle& aHandle) { auto iter = mCompositables.find(aHandle.Value()); if (iter == mCompositables.end()) { return; } RefPtr host = iter->second; mCompositables.erase(iter); host->Detach(nullptr, CompositableHost::FORCE_DETACH); } } // namespace layers } // namespace mozilla