/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- * vim: sw=2 ts=8 et : */ /* 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 "CompositorParent.h" // for CompositorParent #include "GLContext.h" // for GLContext #include "Layers.h" // for Layer #include "RenderTrace.h" // for RenderTraceInvalidateEnd, etc #include "TiledLayerBuffer.h" // for TiledLayerComposer #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/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/ThebesLayerComposite.h" #include "mozilla/mozalloc.h" // for operator delete #include "nsDebug.h" // for NS_WARNING, NS_ASSERTION #include "nsRegion.h" // for nsIntRegion namespace mozilla { namespace layers { class BasicTiledLayerBuffer; class Compositor; template CompositableHost* AsCompositable(const T& op) { return static_cast(op.compositableParent())->GetCompositableHost(); } // 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. template bool ScheduleComposition(const T& op) { CompositableParent* comp = static_cast(op.compositableParent()); if (!comp || !comp->GetCompositorID()) { return false; } CompositorParent* cp = CompositorParent::GetCompositor(comp->GetCompositorID()); if (!cp) { return false; } cp->ScheduleComposition(); return true; } bool CompositableParentManager::ReceiveCompositableUpdate(const CompositableOperation& aEdit, EditReplyVector& replyv) { switch (aEdit.type()) { case CompositableOperation::TOpCreatedTexture: { MOZ_LAYERS_LOG(("[ParentSide] Created texture")); const OpCreatedTexture& op = aEdit.get_OpCreatedTexture(); CompositableParent* compositableParent = static_cast(op.compositableParent()); CompositableHost* compositable = compositableParent->GetCompositableHost(); compositable->EnsureDeprecatedTextureHost(op.textureId(), op.descriptor(), compositableParent->GetCompositableManager(), op.textureInfo()); break; } case CompositableOperation::TOpCreatedIncrementalTexture: { MOZ_LAYERS_LOG(("[ParentSide] Created texture")); const OpCreatedIncrementalTexture& op = aEdit.get_OpCreatedIncrementalTexture(); CompositableParent* compositableParent = static_cast(op.compositableParent()); CompositableHost* compositable = compositableParent->GetCompositableHost(); compositable->EnsureDeprecatedTextureHostIncremental(compositableParent->GetCompositableManager(), op.textureInfo(), op.bufferRect()); break; } case CompositableOperation::TOpDestroyThebesBuffer: { MOZ_LAYERS_LOG(("[ParentSide] Created double buffer")); const OpDestroyThebesBuffer& op = aEdit.get_OpDestroyThebesBuffer(); CompositableParent* compositableParent = static_cast(op.compositableParent()); DeprecatedContentHostBase* content = static_cast(compositableParent->GetCompositableHost()); content->DestroyTextures(); break; } case CompositableOperation::TOpPaintTexture: { MOZ_LAYERS_LOG(("[ParentSide] Paint Texture X")); const OpPaintTexture& op = aEdit.get_OpPaintTexture(); CompositableParent* compositableParent = static_cast(op.compositableParent()); CompositableHost* compositable = compositableParent->GetCompositableHost(); Layer* layer = compositable ? compositable->GetLayer() : nullptr; LayerComposite* shadowLayer = layer ? layer->AsLayerComposite() : nullptr; if (shadowLayer) { Compositor* compositor = static_cast(layer->Manager())->GetCompositor(); compositable->SetCompositor(compositor); compositable->SetLayer(layer); } else { // if we reach this branch, it most likely means that async textures // are coming in before we had time to attach the compositable to a // layer. Don't panic, it is okay in this case. it should not be // happening continuously, though. } if (layer) { RenderTraceInvalidateStart(layer, "FF00FF", layer->GetVisibleRegion().GetBounds()); } if (compositable) { const SurfaceDescriptor& descriptor = op.image(); compositable->EnsureDeprecatedTextureHost(op.textureId(), descriptor, compositableParent->GetCompositableManager(), TextureInfo()); MOZ_ASSERT(compositable->GetDeprecatedTextureHost()); SurfaceDescriptor newBack; bool shouldRecomposite = compositable->Update(descriptor, &newBack); if (IsSurfaceDescriptorValid(newBack)) { replyv.push_back(OpTextureSwap(compositableParent, nullptr, op.textureId(), newBack)); } if (IsAsync() && shouldRecomposite) { ScheduleComposition(op); } } if (layer) { RenderTraceInvalidateEnd(layer, "FF00FF"); } ReturnReleaseFenceIfNecessary(compositable, replyv, op.compositableParent()); break; } case CompositableOperation::TOpPaintTextureRegion: { MOZ_LAYERS_LOG(("[ParentSide] Paint ThebesLayer")); const OpPaintTextureRegion& op = aEdit.get_OpPaintTextureRegion(); CompositableParent* compositableParent = static_cast(op.compositableParent()); CompositableHost* compositable = compositableParent->GetCompositableHost(); ThebesLayerComposite* thebes = static_cast(compositable->GetLayer()); const ThebesBufferData& bufferData = op.bufferData(); RenderTraceInvalidateStart(thebes, "FF00FF", op.updatedRegion().GetBounds()); nsIntRegion frontUpdatedRegion; compositable->UpdateThebes(bufferData, op.updatedRegion(), thebes->GetValidRegion(), &frontUpdatedRegion); replyv.push_back( OpContentBufferSwap(compositableParent, nullptr, frontUpdatedRegion)); RenderTraceInvalidateEnd(thebes, "FF00FF"); ReturnReleaseFenceIfNecessary(compositable, replyv, op.compositableParent()); break; } case CompositableOperation::TOpPaintTextureIncremental: { MOZ_LAYERS_LOG(("[ParentSide] Paint ThebesLayer")); const OpPaintTextureIncremental& op = aEdit.get_OpPaintTextureIncremental(); CompositableParent* compositableParent = static_cast(op.compositableParent()); CompositableHost* compositable = compositableParent->GetCompositableHost(); SurfaceDescriptor desc = op.image(); compositable->UpdateIncremental(op.textureId(), desc, op.updatedRegion(), op.bufferRect(), op.bufferRotation()); break; } case CompositableOperation::TOpUpdatePictureRect: { const OpUpdatePictureRect& op = aEdit.get_OpUpdatePictureRect(); CompositableHost* compositable = static_cast(op.compositableParent())->GetCompositableHost(); MOZ_ASSERT(compositable); compositable->SetPictureRect(op.picture()); break; } case CompositableOperation::TOpPaintTiledLayerBuffer: { MOZ_LAYERS_LOG(("[ParentSide] Paint TiledLayerBuffer")); const OpPaintTiledLayerBuffer& op = aEdit.get_OpPaintTiledLayerBuffer(); CompositableParent* compositableParent = static_cast(op.compositableParent()); CompositableHost* compositable = compositableParent->GetCompositableHost(); TiledLayerComposer* tileComposer = compositable->AsTiledLayerComposer(); NS_ASSERTION(tileComposer, "compositable is not a tile composer"); const SurfaceDescriptorTiles& tileDesc = op.tileLayerDescriptor(); tileComposer->PaintedTiledLayerBuffer(this, tileDesc); break; } case CompositableOperation::TOpUseTexture: { const OpUseTexture& op = aEdit.get_OpUseTexture(); if (op.textureID() == 0) { NS_WARNING("Invalid texture ID"); break; } CompositableHost* compositable = AsCompositable(op); RefPtr tex = compositable->GetTextureHost(op.textureID()); MOZ_ASSERT(tex.get()); compositable->UseTextureHost(tex); if (IsAsync()) { ScheduleComposition(op); } ReturnReleaseFenceIfNecessary(compositable, replyv, op.compositableParent()); break; } case CompositableOperation::TOpAddTexture: { const OpAddTexture& op = aEdit.get_OpAddTexture(); if (op.textureID() == 0) { NS_WARNING("Invalid texture ID"); break; } CompositableHost* compositable = AsCompositable(op); RefPtr tex = TextureHost::Create(op.textureID(), op.data(), this, op.textureFlags()); MOZ_ASSERT(tex.get()); tex->SetCompositor(compositable->GetCompositor()); // set CompositableBackendSpecificData // on gonk, create EGLImage if possible. // create EGLImage during buffer swap could reduce the graphic driver's task // during rendering. compositable->AddTextureHost(tex); MOZ_ASSERT(compositable->GetTextureHost(op.textureID()) == tex.get()); break; } case CompositableOperation::TOpRemoveTexture: { const OpRemoveTexture& op = aEdit.get_OpRemoveTexture(); if (op.textureID() == 0) { NS_WARNING("Invalid texture ID"); break; } CompositableHost* compositable = AsCompositable(op); RefPtr texture = compositable->GetTextureHost(op.textureID()); MOZ_ASSERT(texture); if (!texture) { NS_WARNING("Could not find texture"); break; } TextureFlags flags = texture->GetFlags(); if (!(flags & TEXTURE_DEALLOCATE_CLIENT) && !(flags & TEXTURE_DEALLOCATE_DEFERRED)) { texture->DeallocateSharedData(); } compositable->RemoveTextureHost(texture); // if it is not the host that deallocates the shared data, then we need // to notfy the client side to tell when it is safe to deallocate or // reuse it. if (flags & TEXTURE_DEALLOCATE_CLIENT) { replyv.push_back(ReplyTextureRemoved(op.compositableParent(), nullptr, op.textureID())); } break; } case CompositableOperation::TOpUpdateTexture: { const OpUpdateTexture& op = aEdit.get_OpUpdateTexture(); if (op.textureID() == 0) { NS_WARNING("Invalid texture ID"); break; } CompositableHost* compositable = AsCompositable(op); MOZ_ASSERT(compositable); RefPtr texture = compositable->GetTextureHost(op.textureID()); MOZ_ASSERT(texture); if (!texture) { NS_WARNING("Could not find texture"); break; } texture->Updated(op.region().type() == MaybeRegion::TnsIntRegion ? &op.region().get_nsIntRegion() : nullptr); // no region means invalidate the entire surface compositable->UseTextureHost(texture); ReturnReleaseFenceIfNecessary(compositable, replyv, op.compositableParent()); break; } default: { MOZ_ASSERT(false, "bad type"); } } return true; } #if MOZ_WIDGET_GONK && ANDROID_VERSION >= 18 void CompositableParentManager::ReturnReleaseFenceIfNecessary(CompositableHost* aCompositable, EditReplyVector& replyv, PCompositableParent* aParent) { if (!aCompositable || !aCompositable->GetCompositableBackendSpecificData()) { return; } const std::vector< RefPtr > textureList = aCompositable->GetCompositableBackendSpecificData()->GetPendingReleaseFenceTextureList(); // Return pending Texture data for (size_t i = 0; i < textureList.size(); i++) { TextureHostOGL* hostOGL = textureList[i]->AsHostOGL(); if (!hostOGL) { continue; } android::sp fence = hostOGL->GetAndResetReleaseFence(); if (fence.get() && fence->isValid()) { TextureHost* host = textureList[i]->AsHost(); uint64_t id = host ? host->GetID() : 0; FenceHandle handle = FenceHandle(fence); replyv.push_back(ReturnReleaseFence(aParent, nullptr, id, handle)); // Hold ReleaseFence handle to prevent fence's file descriptor is closed before IPC happens. mPrevReleaseFenceHandles.push_back(handle); } } aCompositable->GetCompositableBackendSpecificData()->ClearPendingReleaseFenceTextureList(); } #else void CompositableParentManager::ReturnReleaseFenceIfNecessary(CompositableHost* aCompositable, EditReplyVector& replyv, PCompositableParent* aParent) { if (!aCompositable || !aCompositable->GetCompositableBackendSpecificData()) { return; } aCompositable->GetCompositableBackendSpecificData()->ClearPendingReleaseFenceTextureList(); } #endif void CompositableParentManager::ClearPrevReleaseFenceHandles() { mPrevReleaseFenceHandles.clear(); } } // namespace } // namespace