UiCompositorControllerChild.cpp (11228B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "mozilla/layers/UiCompositorControllerChild.h" 8 9 #include "mozilla/dom/ContentChild.h" 10 #include "mozilla/layers/CompositorThread.h" 11 #include "mozilla/layers/SynchronousTask.h" 12 #include "mozilla/layers/UiCompositorControllerMessageTypes.h" 13 #include "mozilla/layers/UiCompositorControllerParent.h" 14 #include "mozilla/gfx/GPUProcessManager.h" 15 #include "mozilla/ipc/Endpoint.h" 16 #include "mozilla/StaticPrefs_layers.h" 17 #include "mozilla/StaticPtr.h" 18 #include "nsIWidget.h" 19 #include "nsProxyRelease.h" 20 #include "nsThreadUtils.h" 21 22 #if defined(MOZ_WIDGET_ANDROID) 23 # include "mozilla/widget/AndroidUiThread.h" 24 25 static RefPtr<nsThread> GetUiThread() { return mozilla::GetAndroidUiThread(); } 26 #else 27 static RefPtr<nsThread> GetUiThread() { 28 MOZ_CRASH("Platform does not support UiCompositorController"); 29 return nullptr; 30 } 31 #endif // defined(MOZ_WIDGET_ANDROID) 32 33 namespace mozilla { 34 namespace layers { 35 36 // public: 37 /* static */ 38 RefPtr<UiCompositorControllerChild> 39 UiCompositorControllerChild::CreateForSameProcess( 40 const LayersId& aRootLayerTreeId, nsIWidget* aWidget) { 41 RefPtr<UiCompositorControllerChild> child = 42 new UiCompositorControllerChild(0, aWidget); 43 child->mParent = new UiCompositorControllerParent(aRootLayerTreeId); 44 GetUiThread()->Dispatch( 45 NewRunnableMethod( 46 "layers::UiCompositorControllerChild::OpenForSameProcess", child, 47 &UiCompositorControllerChild::OpenForSameProcess), 48 nsIThread::DISPATCH_NORMAL); 49 return child; 50 } 51 52 /* static */ 53 RefPtr<UiCompositorControllerChild> 54 UiCompositorControllerChild::CreateForGPUProcess( 55 const uint64_t& aProcessToken, 56 Endpoint<PUiCompositorControllerChild>&& aEndpoint, nsIWidget* aWidget) { 57 RefPtr<UiCompositorControllerChild> child = 58 new UiCompositorControllerChild(aProcessToken, aWidget); 59 60 RefPtr<nsIRunnable> task = 61 NewRunnableMethod<Endpoint<PUiCompositorControllerChild>&&>( 62 "layers::UiCompositorControllerChild::OpenForGPUProcess", child, 63 &UiCompositorControllerChild::OpenForGPUProcess, 64 std::move(aEndpoint)); 65 66 GetUiThread()->Dispatch(task.forget(), nsIThread::DISPATCH_NORMAL); 67 return child; 68 } 69 70 bool UiCompositorControllerChild::Pause() { 71 if (!mIsOpen) { 72 return false; 73 } 74 return SendPause(); 75 } 76 77 bool UiCompositorControllerChild::Resume() { 78 if (!mIsOpen) { 79 return false; 80 } 81 bool resumed = false; 82 return SendResume(&resumed) && resumed; 83 } 84 85 bool UiCompositorControllerChild::ResumeAndResize(const int32_t& aX, 86 const int32_t& aY, 87 const int32_t& aWidth, 88 const int32_t& aHeight) { 89 if (!mIsOpen) { 90 mResize = Some(gfx::IntRect(aX, aY, aWidth, aHeight)); 91 // Since we are caching these values, pretend the call succeeded. 92 return true; 93 } 94 bool resumed = false; 95 return SendResumeAndResize(aX, aY, aWidth, aHeight, &resumed) && resumed; 96 } 97 98 bool UiCompositorControllerChild::InvalidateAndRender() { 99 if (!mIsOpen) { 100 return false; 101 } 102 return SendInvalidateAndRender(); 103 } 104 105 bool UiCompositorControllerChild::SetMaxToolbarHeight(const int32_t& aHeight) { 106 if (!mIsOpen) { 107 mMaxToolbarHeight = Some(aHeight); 108 // Since we are caching this value, pretend the call succeeded. 109 return true; 110 } 111 return SendMaxToolbarHeight(aHeight); 112 } 113 114 bool UiCompositorControllerChild::SetFixedBottomOffset(int32_t aOffset) { 115 return SendFixedBottomOffset(aOffset); 116 } 117 118 bool UiCompositorControllerChild::ToolbarAnimatorMessageFromUI( 119 const int32_t& aMessage) { 120 if (!mIsOpen) { 121 return false; 122 } 123 124 if (aMessage == IS_COMPOSITOR_CONTROLLER_OPEN) { 125 RecvToolbarAnimatorMessageFromCompositor(COMPOSITOR_CONTROLLER_OPEN); 126 } 127 128 return true; 129 } 130 131 bool UiCompositorControllerChild::SetDefaultClearColor(const uint32_t& aColor) { 132 if (!mIsOpen) { 133 mDefaultClearColor = Some(aColor); 134 // Since we are caching this value, pretend the call succeeded. 135 return true; 136 } 137 138 return SendDefaultClearColor(aColor); 139 } 140 141 bool UiCompositorControllerChild::RequestScreenPixels() { 142 if (!mIsOpen) { 143 return false; 144 } 145 146 return SendRequestScreenPixels(); 147 } 148 149 bool UiCompositorControllerChild::EnableLayerUpdateNotifications( 150 const bool& aEnable) { 151 if (!mIsOpen) { 152 mLayerUpdateEnabled = Some(aEnable); 153 // Since we are caching this value, pretend the call succeeded. 154 return true; 155 } 156 157 return SendEnableLayerUpdateNotifications(aEnable); 158 } 159 160 void UiCompositorControllerChild::Destroy() { 161 MOZ_ASSERT(NS_IsMainThread()); 162 163 layers::SynchronousTask task("UiCompositorControllerChild::Destroy"); 164 GetUiThread()->Dispatch(NS_NewRunnableFunction( 165 "layers::UiCompositorControllerChild::Destroy", [&]() { 166 MOZ_ASSERT(GetUiThread()->IsOnCurrentThread()); 167 AutoCompleteTask complete(&task); 168 169 // Clear the process token so that we don't notify the GPUProcessManager 170 // about an abnormal shutdown, thereby tearing down the GPU process. 171 mProcessToken = 0; 172 173 if (mWidget) { 174 // Dispatch mWidget to main thread to prevent it from being destructed 175 // by the ui thread. 176 RefPtr<nsIWidget> widget = std::move(mWidget); 177 NS_ReleaseOnMainThread("UiCompositorControllerChild::mWidget", 178 widget.forget()); 179 } 180 181 if (mIsOpen) { 182 // Close the underlying IPC channel. 183 PUiCompositorControllerChild::Close(); 184 mIsOpen = false; 185 } 186 })); 187 188 task.Wait(); 189 } 190 191 bool UiCompositorControllerChild::DeallocPixelBuffer(Shmem& aMem) { 192 return DeallocShmem(aMem); 193 } 194 195 // protected: 196 void UiCompositorControllerChild::ActorDestroy(ActorDestroyReason aWhy) { 197 mIsOpen = false; 198 mParent = nullptr; 199 200 if (mProcessToken) { 201 gfx::GPUProcessManager::Get()->NotifyRemoteActorDestroyed(mProcessToken); 202 mProcessToken = 0; 203 } 204 } 205 206 void UiCompositorControllerChild::ProcessingError(Result aCode, 207 const char* aReason) { 208 if (aCode != MsgDropped) { 209 gfxDevCrash(gfx::LogReason::ProcessingError) 210 << "Processing error in UiCompositorControllerChild: " << int(aCode); 211 } 212 } 213 214 void UiCompositorControllerChild::HandleFatalError(const char* aMsg) { 215 dom::ContentChild::FatalErrorIfNotUsingGPUProcess(aMsg, OtherChildID()); 216 } 217 218 mozilla::ipc::IPCResult 219 UiCompositorControllerChild::RecvToolbarAnimatorMessageFromCompositor( 220 const int32_t& aMessage) { 221 #if defined(MOZ_WIDGET_ANDROID) 222 if (mWidget) { 223 mWidget->RecvToolbarAnimatorMessageFromCompositor(aMessage); 224 } 225 #endif // defined(MOZ_WIDGET_ANDROID) 226 227 return IPC_OK(); 228 } 229 230 mozilla::ipc::IPCResult 231 UiCompositorControllerChild::RecvNotifyCompositorScrollUpdate( 232 const CompositorScrollUpdate& aUpdate) { 233 if (mWidget) { 234 mWidget->NotifyCompositorScrollUpdate(aUpdate); 235 } 236 237 return IPC_OK(); 238 } 239 240 mozilla::ipc::IPCResult UiCompositorControllerChild::RecvScreenPixels( 241 ipc::Shmem&& aMem, const ScreenIntSize& aSize, bool aNeedsYFlip) { 242 #if defined(MOZ_WIDGET_ANDROID) 243 if (mWidget) { 244 mWidget->RecvScreenPixels(std::move(aMem), aSize, aNeedsYFlip); 245 } 246 #endif // defined(MOZ_WIDGET_ANDROID) 247 248 return IPC_OK(); 249 } 250 251 // private: 252 UiCompositorControllerChild::UiCompositorControllerChild( 253 const uint64_t& aProcessToken, nsIWidget* aWidget) 254 : mIsOpen(false), mProcessToken(aProcessToken), mWidget(aWidget) {} 255 256 UiCompositorControllerChild::~UiCompositorControllerChild() = default; 257 258 void UiCompositorControllerChild::OpenForSameProcess() { 259 MOZ_ASSERT(GetUiThread()->IsOnCurrentThread()); 260 261 mIsOpen = Open(mParent, mozilla::layers::CompositorThread(), 262 mozilla::ipc::ChildSide); 263 264 if (!mIsOpen) { 265 mParent = nullptr; 266 return; 267 } 268 269 mParent->InitializeForSameProcess(); 270 SendCachedValues(); 271 // Let Ui thread know the connection is open; 272 RecvToolbarAnimatorMessageFromCompositor(COMPOSITOR_CONTROLLER_OPEN); 273 } 274 275 void UiCompositorControllerChild::OpenForGPUProcess( 276 Endpoint<PUiCompositorControllerChild>&& aEndpoint) { 277 MOZ_ASSERT(GetUiThread()->IsOnCurrentThread()); 278 279 mIsOpen = aEndpoint.Bind(this); 280 281 if (!mIsOpen) { 282 // The GPU Process Manager might be gone if we receive ActorDestroy very 283 // late in shutdown. 284 if (gfx::GPUProcessManager* gpm = gfx::GPUProcessManager::Get()) { 285 gpm->NotifyRemoteActorDestroyed(mProcessToken); 286 } 287 return; 288 } 289 290 SetReplyTimeout(); 291 292 SendCachedValues(); 293 // Let Ui thread know the connection is open; 294 RecvToolbarAnimatorMessageFromCompositor(COMPOSITOR_CONTROLLER_OPEN); 295 } 296 297 void UiCompositorControllerChild::SendCachedValues() { 298 MOZ_ASSERT(mIsOpen); 299 if (mResize) { 300 bool resumed; 301 SendResumeAndResize(mResize.ref().x, mResize.ref().y, mResize.ref().width, 302 mResize.ref().height, &resumed); 303 mResize.reset(); 304 } 305 if (mMaxToolbarHeight) { 306 SendMaxToolbarHeight(mMaxToolbarHeight.ref()); 307 mMaxToolbarHeight.reset(); 308 } 309 if (mDefaultClearColor) { 310 SendDefaultClearColor(mDefaultClearColor.ref()); 311 mDefaultClearColor.reset(); 312 } 313 if (mLayerUpdateEnabled) { 314 SendEnableLayerUpdateNotifications(mLayerUpdateEnabled.ref()); 315 mLayerUpdateEnabled.reset(); 316 } 317 } 318 319 #ifdef MOZ_WIDGET_ANDROID 320 void UiCompositorControllerChild::SetCompositorSurfaceManager( 321 java::CompositorSurfaceManager::Param aCompositorSurfaceManager) { 322 MOZ_ASSERT(!mCompositorSurfaceManager, 323 "SetCompositorSurfaceManager must only be called once."); 324 MOZ_ASSERT(mProcessToken != 0, 325 "SetCompositorSurfaceManager must only be called for GPU process " 326 "controllers."); 327 mCompositorSurfaceManager = aCompositorSurfaceManager; 328 }; 329 330 void UiCompositorControllerChild::OnCompositorSurfaceChanged( 331 int32_t aWidgetId, java::sdk::Surface::Param aSurface) { 332 // If mCompositorSurfaceManager is not set then there is no GPU process and 333 // we do not need to do anything. 334 if (mCompositorSurfaceManager == nullptr) { 335 return; 336 } 337 338 nsresult result = 339 mCompositorSurfaceManager->OnSurfaceChanged(aWidgetId, aSurface); 340 341 // If our remote binder has died then notify the GPU process manager. 342 if (NS_FAILED(result)) { 343 if (mProcessToken) { 344 gfx::GPUProcessManager::Get()->NotifyRemoteActorDestroyed(mProcessToken); 345 mProcessToken = 0; 346 } 347 } 348 } 349 #endif 350 351 void UiCompositorControllerChild::SetReplyTimeout() { 352 #ifndef DEBUG 353 // Add a timeout for release builds to kill GPU process when it hangs. 354 const int32_t timeout = 355 StaticPrefs::layers_gpu_process_ipc_reply_timeout_ms_AtStartup(); 356 SetReplyTimeoutMs(timeout); 357 #endif 358 } 359 360 bool UiCompositorControllerChild::ShouldContinueFromReplyTimeout() { 361 gfxCriticalNote << "Killing GPU process due to IPC reply timeout"; 362 gfx::GPUProcessManager::Get()->KillProcess(/* aGenerateMinidump */ true); 363 return false; 364 } 365 366 } // namespace layers 367 } // namespace mozilla