summaryrefslogtreecommitdiffstats
path: root/gfx/layers/ipc/UiCompositorControllerChild.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--gfx/layers/ipc/UiCompositorControllerChild.cpp350
1 files changed, 350 insertions, 0 deletions
diff --git a/gfx/layers/ipc/UiCompositorControllerChild.cpp b/gfx/layers/ipc/UiCompositorControllerChild.cpp
new file mode 100644
index 0000000000..c1bf49bc27
--- /dev/null
+++ b/gfx/layers/ipc/UiCompositorControllerChild.cpp
@@ -0,0 +1,350 @@
+/* -*- 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 "mozilla/layers/UiCompositorControllerChild.h"
+
+#include "mozilla/dom/ContentChild.h"
+#include "mozilla/layers/CompositorThread.h"
+#include "mozilla/layers/SynchronousTask.h"
+#include "mozilla/layers/UiCompositorControllerMessageTypes.h"
+#include "mozilla/layers/UiCompositorControllerParent.h"
+#include "mozilla/gfx/GPUProcessManager.h"
+#include "mozilla/ipc/Endpoint.h"
+#include "mozilla/StaticPtr.h"
+#include "nsBaseWidget.h"
+#include "nsProxyRelease.h"
+#include "nsThreadUtils.h"
+
+#if defined(MOZ_WIDGET_ANDROID)
+# include "mozilla/widget/AndroidUiThread.h"
+
+static RefPtr<nsThread> GetUiThread() { return mozilla::GetAndroidUiThread(); }
+#else
+static RefPtr<nsThread> GetUiThread() {
+ MOZ_CRASH("Platform does not support UiCompositorController");
+ return nullptr;
+}
+#endif // defined(MOZ_WIDGET_ANDROID)
+
+namespace mozilla {
+namespace layers {
+
+// public:
+/* static */
+RefPtr<UiCompositorControllerChild>
+UiCompositorControllerChild::CreateForSameProcess(
+ const LayersId& aRootLayerTreeId, nsBaseWidget* aWidget) {
+ RefPtr<UiCompositorControllerChild> child =
+ new UiCompositorControllerChild(0, aWidget);
+ child->mParent = new UiCompositorControllerParent(aRootLayerTreeId);
+ GetUiThread()->Dispatch(
+ NewRunnableMethod(
+ "layers::UiCompositorControllerChild::OpenForSameProcess", child,
+ &UiCompositorControllerChild::OpenForSameProcess),
+ nsIThread::DISPATCH_NORMAL);
+ return child;
+}
+
+/* static */
+RefPtr<UiCompositorControllerChild>
+UiCompositorControllerChild::CreateForGPUProcess(
+ const uint64_t& aProcessToken,
+ Endpoint<PUiCompositorControllerChild>&& aEndpoint, nsBaseWidget* aWidget) {
+ RefPtr<UiCompositorControllerChild> child =
+ new UiCompositorControllerChild(aProcessToken, aWidget);
+
+ RefPtr<nsIRunnable> task =
+ NewRunnableMethod<Endpoint<PUiCompositorControllerChild>&&>(
+ "layers::UiCompositorControllerChild::OpenForGPUProcess", child,
+ &UiCompositorControllerChild::OpenForGPUProcess,
+ std::move(aEndpoint));
+
+ GetUiThread()->Dispatch(task.forget(), nsIThread::DISPATCH_NORMAL);
+ return child;
+}
+
+bool UiCompositorControllerChild::Pause() {
+ if (!mIsOpen) {
+ return false;
+ }
+ return SendPause();
+}
+
+bool UiCompositorControllerChild::Resume() {
+ if (!mIsOpen) {
+ return false;
+ }
+ bool resumed = false;
+ return SendResume(&resumed) && resumed;
+}
+
+bool UiCompositorControllerChild::ResumeAndResize(const int32_t& aX,
+ const int32_t& aY,
+ const int32_t& aWidth,
+ const int32_t& aHeight) {
+ if (!mIsOpen) {
+ mResize = Some(gfx::IntRect(aX, aY, aWidth, aHeight));
+ // Since we are caching these values, pretend the call succeeded.
+ return true;
+ }
+ bool resumed = false;
+ return SendResumeAndResize(aX, aY, aWidth, aHeight, &resumed) && resumed;
+}
+
+bool UiCompositorControllerChild::InvalidateAndRender() {
+ if (!mIsOpen) {
+ return false;
+ }
+ return SendInvalidateAndRender();
+}
+
+bool UiCompositorControllerChild::SetMaxToolbarHeight(const int32_t& aHeight) {
+ if (!mIsOpen) {
+ mMaxToolbarHeight = Some(aHeight);
+ // Since we are caching this value, pretend the call succeeded.
+ return true;
+ }
+ return SendMaxToolbarHeight(aHeight);
+}
+
+bool UiCompositorControllerChild::SetFixedBottomOffset(int32_t aOffset) {
+ return SendFixedBottomOffset(aOffset);
+}
+
+bool UiCompositorControllerChild::ToolbarAnimatorMessageFromUI(
+ const int32_t& aMessage) {
+ if (!mIsOpen) {
+ return false;
+ }
+
+ if (aMessage == IS_COMPOSITOR_CONTROLLER_OPEN) {
+ RecvToolbarAnimatorMessageFromCompositor(COMPOSITOR_CONTROLLER_OPEN);
+ }
+
+ return true;
+}
+
+bool UiCompositorControllerChild::SetDefaultClearColor(const uint32_t& aColor) {
+ if (!mIsOpen) {
+ mDefaultClearColor = Some(aColor);
+ // Since we are caching this value, pretend the call succeeded.
+ return true;
+ }
+
+ return SendDefaultClearColor(aColor);
+}
+
+bool UiCompositorControllerChild::RequestScreenPixels() {
+ if (!mIsOpen) {
+ return false;
+ }
+
+ return SendRequestScreenPixels();
+}
+
+bool UiCompositorControllerChild::EnableLayerUpdateNotifications(
+ const bool& aEnable) {
+ if (!mIsOpen) {
+ mLayerUpdateEnabled = Some(aEnable);
+ // Since we are caching this value, pretend the call succeeded.
+ return true;
+ }
+
+ return SendEnableLayerUpdateNotifications(aEnable);
+}
+
+void UiCompositorControllerChild::Destroy() {
+ MOZ_ASSERT(NS_IsMainThread());
+
+ layers::SynchronousTask task("UiCompositorControllerChild::Destroy");
+ GetUiThread()->Dispatch(NS_NewRunnableFunction(
+ "layers::UiCompositorControllerChild::Destroy", [&]() {
+ MOZ_ASSERT(GetUiThread()->IsOnCurrentThread());
+ AutoCompleteTask complete(&task);
+
+ // Clear the process token so that we don't notify the GPUProcessManager
+ // about an abnormal shutdown, thereby tearing down the GPU process.
+ mProcessToken = 0;
+
+ if (mWidget) {
+ // Dispatch mWidget to main thread to prevent it from being destructed
+ // by the ui thread.
+ RefPtr<nsIWidget> widget = std::move(mWidget);
+ NS_ReleaseOnMainThread("UiCompositorControllerChild::mWidget",
+ widget.forget());
+ }
+
+ if (mIsOpen) {
+ // Close the underlying IPC channel.
+ PUiCompositorControllerChild::Close();
+ mIsOpen = false;
+ }
+ }));
+
+ task.Wait();
+}
+
+bool UiCompositorControllerChild::DeallocPixelBuffer(Shmem& aMem) {
+ return DeallocShmem(aMem);
+}
+
+// protected:
+void UiCompositorControllerChild::ActorDestroy(ActorDestroyReason aWhy) {
+ mIsOpen = false;
+ mParent = nullptr;
+
+ if (mProcessToken) {
+ gfx::GPUProcessManager::Get()->NotifyRemoteActorDestroyed(mProcessToken);
+ mProcessToken = 0;
+ }
+}
+
+void UiCompositorControllerChild::ProcessingError(Result aCode,
+ const char* aReason) {
+ if (aCode != MsgDropped) {
+ gfxDevCrash(gfx::LogReason::ProcessingError)
+ << "Processing error in UiCompositorControllerChild: " << int(aCode);
+ }
+}
+
+void UiCompositorControllerChild::HandleFatalError(const char* aMsg) {
+ dom::ContentChild::FatalErrorIfNotUsingGPUProcess(aMsg, OtherPid());
+}
+
+mozilla::ipc::IPCResult
+UiCompositorControllerChild::RecvToolbarAnimatorMessageFromCompositor(
+ const int32_t& aMessage) {
+#if defined(MOZ_WIDGET_ANDROID)
+ if (mWidget) {
+ mWidget->RecvToolbarAnimatorMessageFromCompositor(aMessage);
+ }
+#endif // defined(MOZ_WIDGET_ANDROID)
+
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult UiCompositorControllerChild::RecvRootFrameMetrics(
+ const ScreenPoint& aScrollOffset, const CSSToScreenScale& aZoom) {
+#if defined(MOZ_WIDGET_ANDROID)
+ if (mWidget) {
+ mWidget->UpdateRootFrameMetrics(aScrollOffset, aZoom);
+ }
+#endif // defined(MOZ_WIDGET_ANDROID)
+
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult UiCompositorControllerChild::RecvScreenPixels(
+ ipc::Shmem&& aMem, const ScreenIntSize& aSize, bool aNeedsYFlip) {
+#if defined(MOZ_WIDGET_ANDROID)
+ if (mWidget) {
+ mWidget->RecvScreenPixels(std::move(aMem), aSize, aNeedsYFlip);
+ }
+#endif // defined(MOZ_WIDGET_ANDROID)
+
+ return IPC_OK();
+}
+
+// private:
+UiCompositorControllerChild::UiCompositorControllerChild(
+ const uint64_t& aProcessToken, nsBaseWidget* aWidget)
+ : mIsOpen(false), mProcessToken(aProcessToken), mWidget(aWidget) {}
+
+UiCompositorControllerChild::~UiCompositorControllerChild() = default;
+
+void UiCompositorControllerChild::OpenForSameProcess() {
+ MOZ_ASSERT(GetUiThread()->IsOnCurrentThread());
+
+ mIsOpen = Open(mParent, mozilla::layers::CompositorThread(),
+ mozilla::ipc::ChildSide);
+
+ if (!mIsOpen) {
+ mParent = nullptr;
+ return;
+ }
+
+ mParent->InitializeForSameProcess();
+ SendCachedValues();
+ // Let Ui thread know the connection is open;
+ RecvToolbarAnimatorMessageFromCompositor(COMPOSITOR_CONTROLLER_OPEN);
+}
+
+void UiCompositorControllerChild::OpenForGPUProcess(
+ Endpoint<PUiCompositorControllerChild>&& aEndpoint) {
+ MOZ_ASSERT(GetUiThread()->IsOnCurrentThread());
+
+ mIsOpen = aEndpoint.Bind(this);
+
+ if (!mIsOpen) {
+ // The GPU Process Manager might be gone if we receive ActorDestroy very
+ // late in shutdown.
+ if (gfx::GPUProcessManager* gpm = gfx::GPUProcessManager::Get()) {
+ gpm->NotifyRemoteActorDestroyed(mProcessToken);
+ }
+ return;
+ }
+
+ SendCachedValues();
+ // Let Ui thread know the connection is open;
+ RecvToolbarAnimatorMessageFromCompositor(COMPOSITOR_CONTROLLER_OPEN);
+}
+
+void UiCompositorControllerChild::SendCachedValues() {
+ MOZ_ASSERT(mIsOpen);
+ if (mResize) {
+ bool resumed;
+ SendResumeAndResize(mResize.ref().x, mResize.ref().y, mResize.ref().width,
+ mResize.ref().height, &resumed);
+ mResize.reset();
+ }
+ if (mMaxToolbarHeight) {
+ SendMaxToolbarHeight(mMaxToolbarHeight.ref());
+ mMaxToolbarHeight.reset();
+ }
+ if (mDefaultClearColor) {
+ SendDefaultClearColor(mDefaultClearColor.ref());
+ mDefaultClearColor.reset();
+ }
+ if (mLayerUpdateEnabled) {
+ SendEnableLayerUpdateNotifications(mLayerUpdateEnabled.ref());
+ mLayerUpdateEnabled.reset();
+ }
+}
+
+#ifdef MOZ_WIDGET_ANDROID
+void UiCompositorControllerChild::SetCompositorSurfaceManager(
+ java::CompositorSurfaceManager::Param aCompositorSurfaceManager) {
+ MOZ_ASSERT(!mCompositorSurfaceManager,
+ "SetCompositorSurfaceManager must only be called once.");
+ MOZ_ASSERT(mProcessToken != 0,
+ "SetCompositorSurfaceManager must only be called for GPU process "
+ "controllers.");
+ mCompositorSurfaceManager = aCompositorSurfaceManager;
+};
+
+void UiCompositorControllerChild::OnCompositorSurfaceChanged(
+ int32_t aWidgetId, java::sdk::Surface::Param aSurface) {
+ // If mCompositorSurfaceManager is not set then there is no GPU process and
+ // we do not need to do anything.
+ if (mCompositorSurfaceManager == nullptr) {
+ return;
+ }
+
+ nsresult result =
+ mCompositorSurfaceManager->OnSurfaceChanged(aWidgetId, aSurface);
+
+ // If our remote binder has died then notify the GPU process manager.
+ if (NS_FAILED(result)) {
+ if (mProcessToken) {
+ gfx::GPUProcessManager::Get()->NotifyRemoteActorDestroyed(mProcessToken);
+ mProcessToken = 0;
+ }
+ }
+}
+#endif
+
+} // namespace layers
+} // namespace mozilla