Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set sw=2 sts=2 ts=8 et tw=99 : */
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 : #include "CompositorThread.h"
7 : #include "MainThreadUtils.h"
8 : #include "nsThreadUtils.h"
9 : #include "CompositorBridgeParent.h"
10 : #include "mozilla/layers/ImageBridgeParent.h"
11 : #include "mozilla/media/MediaSystemResourceService.h"
12 :
13 : namespace mozilla {
14 :
15 : namespace gfx {
16 : // See VRManagerChild.cpp
17 : void ReleaseVRManagerParentSingleton();
18 : } // namespace gfx
19 :
20 : namespace layers {
21 :
22 3 : static StaticRefPtr<CompositorThreadHolder> sCompositorThreadHolder;
23 : static bool sFinishedCompositorShutDown = false;
24 :
25 : // See ImageBridgeChild.cpp
26 : void ReleaseImageBridgeParentSingleton();
27 :
28 1 : CompositorThreadHolder* GetCompositorThreadHolder()
29 : {
30 1 : return sCompositorThreadHolder;
31 : }
32 :
33 : base::Thread*
34 22300 : CompositorThread()
35 : {
36 : return sCompositorThreadHolder
37 22300 : ? sCompositorThreadHolder->GetCompositorThread()
38 44600 : : nullptr;
39 : }
40 :
41 : /* static */ MessageLoop*
42 1101 : CompositorThreadHolder::Loop()
43 : {
44 1101 : return CompositorThread() ? CompositorThread()->message_loop() : nullptr;
45 : }
46 :
47 : CompositorThreadHolder*
48 5 : CompositorThreadHolder::GetSingleton()
49 : {
50 5 : return sCompositorThreadHolder;
51 : }
52 :
53 1 : CompositorThreadHolder::CompositorThreadHolder()
54 1 : : mCompositorThread(CreateCompositorThread())
55 : {
56 1 : MOZ_ASSERT(NS_IsMainThread());
57 1 : }
58 :
59 0 : CompositorThreadHolder::~CompositorThreadHolder()
60 : {
61 0 : MOZ_ASSERT(NS_IsMainThread());
62 :
63 0 : DestroyCompositorThread(mCompositorThread);
64 0 : }
65 :
66 : /* static */ void
67 0 : CompositorThreadHolder::DestroyCompositorThread(base::Thread* aCompositorThread)
68 : {
69 0 : MOZ_ASSERT(NS_IsMainThread());
70 :
71 0 : MOZ_ASSERT(!sCompositorThreadHolder, "We shouldn't be destroying the compositor thread yet.");
72 :
73 0 : CompositorBridgeParent::Shutdown();
74 0 : delete aCompositorThread;
75 0 : sFinishedCompositorShutDown = true;
76 0 : }
77 :
78 : /* static */ base::Thread*
79 1 : CompositorThreadHolder::CreateCompositorThread()
80 : {
81 1 : MOZ_ASSERT(NS_IsMainThread());
82 :
83 1 : MOZ_ASSERT(!sCompositorThreadHolder, "The compositor thread has already been started!");
84 :
85 1 : base::Thread* compositorThread = new base::Thread("Compositor");
86 :
87 1 : base::Thread::Options options;
88 : /* Timeout values are powers-of-two to enable us get better data.
89 : 128ms is chosen for transient hangs because 8Hz should be the minimally
90 : acceptable goal for Compositor responsiveness (normal goal is 60Hz). */
91 1 : options.transient_hang_timeout = 128; // milliseconds
92 : /* 2048ms is chosen for permanent hangs because it's longer than most
93 : * Compositor hangs seen in the wild, but is short enough to not miss getting
94 : * native hang stacks. */
95 1 : options.permanent_hang_timeout = 2048; // milliseconds
96 : #if defined(_WIN32)
97 : /* With d3d9 the compositor thread creates native ui, see DeviceManagerD3D9. As
98 : * such the thread is a gui thread, and must process a windows message queue or
99 : * risk deadlocks. Chromium message loop TYPE_UI does exactly what we need. */
100 : options.message_loop_type = MessageLoop::TYPE_UI;
101 : #endif
102 :
103 1 : if (!compositorThread->StartWithOptions(options)) {
104 0 : delete compositorThread;
105 0 : return nullptr;
106 : }
107 :
108 1 : CompositorBridgeParent::Setup();
109 1 : ImageBridgeParent::Setup();
110 :
111 1 : return compositorThread;
112 : }
113 :
114 : void
115 1 : CompositorThreadHolder::Start()
116 : {
117 1 : MOZ_ASSERT(NS_IsMainThread(), "Should be on the main Thread!");
118 1 : MOZ_ASSERT(!sCompositorThreadHolder, "The compositor thread has already been started!");
119 :
120 1 : sCompositorThreadHolder = new CompositorThreadHolder();
121 1 : }
122 :
123 : void
124 0 : CompositorThreadHolder::Shutdown()
125 : {
126 0 : MOZ_ASSERT(NS_IsMainThread(), "Should be on the main Thread!");
127 0 : MOZ_ASSERT(sCompositorThreadHolder, "The compositor thread has already been shut down!");
128 :
129 0 : ReleaseImageBridgeParentSingleton();
130 0 : gfx::ReleaseVRManagerParentSingleton();
131 0 : MediaSystemResourceService::Shutdown();
132 :
133 0 : sCompositorThreadHolder = nullptr;
134 :
135 : // No locking is needed around sFinishedCompositorShutDown because it is only
136 : // ever accessed on the main thread.
137 0 : SpinEventLoopUntil([&]() { return sFinishedCompositorShutDown; });
138 :
139 0 : CompositorBridgeParent::FinishShutdown();
140 0 : }
141 :
142 : /* static */ bool
143 10298 : CompositorThreadHolder::IsInCompositorThread()
144 : {
145 20097 : return CompositorThread() &&
146 20097 : CompositorThread()->thread_id() == PlatformThread::CurrentId();
147 : }
148 :
149 : } // namespace mozilla
150 : } // namespace layers
151 :
152 : bool
153 9350 : NS_IsInCompositorThread()
154 : {
155 9350 : return mozilla::layers::CompositorThreadHolder::IsInCompositorThread();
156 : }
|