/* -*- 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 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; } if (TextureSourceProvider* provider = compositable->GetTextureSourceProvider()) { if (!provider->IsValid()) { return false; } } switch (aEdit.detail().type()) { case CompositableOperationDetail::TOpPaintTextureRegion: { MOZ_LAYERS_LOG(("[ParentSide] Paint PaintedLayer")); const OpPaintTextureRegion& op = aEdit.detail().get_OpPaintTextureRegion(); Layer* layer = compositable->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 (!compositable->UpdateThebes(bufferData, op.updatedRegion(), thebes->GetValidRegion())) { return false; } RenderTraceInvalidateEnd(thebes, "FF00FF"); break; } case CompositableOperationDetail::TOpUseTiledLayerBuffer: { MOZ_LAYERS_LOG(("[ParentSide] Paint TiledLayerBuffer")); const OpUseTiledLayerBuffer& op = aEdit.detail().get_OpUseTiledLayerBuffer(); TiledContentHost* tiledHost = compositable->AsTiledContentHost(); NS_ASSERTION(tiledHost, "The compositable is not tiled"); const SurfaceDescriptorTiles& tileDesc = op.tileLayerDescriptor(); bool success = tiledHost->UseTiledLayerBuffer(this, tileDesc); const InfallibleTArray& 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.textureOnWhite().type() == MaybeTexture::TPTextureParent) { texture = TextureHost::AsTextureHost(texturedDesc.textureOnWhite().get_PTextureParent()); 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 = aEdit.detail().get_OpRemoveTexture(); RefPtr tex = TextureHost::AsTextureHost(op.textureParent()); MOZ_ASSERT(tex.get()); compositable->RemoveTextureHost(tex); break; } case CompositableOperationDetail::TOpUseTexture: { const OpUseTexture& op = aEdit.detail().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) { compositable->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() && compositable->GetLayer()) { ScheduleComposition(compositable); } break; } case CompositableOperationDetail::TOpUseComponentAlphaTextures: { const OpUseComponentAlphaTextures& op = aEdit.detail().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); compositable->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(compositable); } 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) { auto iter = mCompositables.find(aHandle.Value()); if (iter == mCompositables.end()) { return nullptr; } return iter->second; } 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