Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/gfx/layers/ipc/CompositorThread.cpp
Line
Count
Source (jump to first uncovered line)
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
#include "CompositorThread.h"
7
#include "MainThreadUtils.h"
8
#include "nsThreadUtils.h"
9
#include "CompositorBridgeParent.h"
10
#include "mozilla/layers/CompositorManagerParent.h"
11
#include "mozilla/layers/ImageBridgeParent.h"
12
#include "mozilla/media/MediaSystemResourceService.h"
13
14
namespace mozilla {
15
16
namespace gfx {
17
// See VRManagerChild.cpp
18
void ReleaseVRManagerParentSingleton();
19
} // namespace gfx
20
21
namespace layers {
22
23
static StaticRefPtr<CompositorThreadHolder> sCompositorThreadHolder;
24
static bool sFinishedCompositorShutDown = false;
25
26
CompositorThreadHolder* GetCompositorThreadHolder()
27
0
{
28
0
  return sCompositorThreadHolder;
29
0
}
30
31
base::Thread*
32
CompositorThread()
33
0
{
34
0
  return sCompositorThreadHolder
35
0
         ? sCompositorThreadHolder->GetCompositorThread()
36
0
         : nullptr;
37
0
}
38
39
/* static */ MessageLoop*
40
CompositorThreadHolder::Loop()
41
0
{
42
0
  return CompositorThread() ? CompositorThread()->message_loop() : nullptr;
43
0
}
44
45
CompositorThreadHolder*
46
CompositorThreadHolder::GetSingleton()
47
0
{
48
0
  return sCompositorThreadHolder;
49
0
}
50
51
CompositorThreadHolder::CompositorThreadHolder()
52
  : mCompositorThread(CreateCompositorThread())
53
0
{
54
0
  MOZ_ASSERT(NS_IsMainThread());
55
0
}
56
57
CompositorThreadHolder::~CompositorThreadHolder()
58
0
{
59
0
  MOZ_ASSERT(NS_IsMainThread());
60
0
  if (mCompositorThread) {
61
0
    DestroyCompositorThread(mCompositorThread);
62
0
  }
63
0
}
64
65
/* static */ void
66
CompositorThreadHolder::DestroyCompositorThread(base::Thread* aCompositorThread)
67
0
{
68
0
  MOZ_ASSERT(NS_IsMainThread());
69
0
70
0
  MOZ_ASSERT(!sCompositorThreadHolder, "We shouldn't be destroying the compositor thread yet.");
71
0
72
0
  delete aCompositorThread;
73
0
  sFinishedCompositorShutDown = true;
74
0
}
75
76
/* static */ base::Thread*
77
CompositorThreadHolder::CreateCompositorThread()
78
0
{
79
0
  MOZ_ASSERT(NS_IsMainThread());
80
0
81
0
  MOZ_ASSERT(!sCompositorThreadHolder, "The compositor thread has already been started!");
82
0
83
0
  base::Thread* compositorThread = new base::Thread("Compositor");
84
0
85
0
  base::Thread::Options options;
86
0
  /* Timeout values are powers-of-two to enable us get better data.
87
0
     128ms is chosen for transient hangs because 8Hz should be the minimally
88
0
     acceptable goal for Compositor responsiveness (normal goal is 60Hz). */
89
0
  options.transient_hang_timeout = 128; // milliseconds
90
0
  /* 2048ms is chosen for permanent hangs because it's longer than most
91
0
   * Compositor hangs seen in the wild, but is short enough to not miss getting
92
0
   * native hang stacks. */
93
0
  options.permanent_hang_timeout = 2048; // milliseconds
94
#if defined(_WIN32)
95
  /* With d3d9 the compositor thread creates native ui, see DeviceManagerD3D9. As
96
   * such the thread is a gui thread, and must process a windows message queue or
97
   * risk deadlocks. Chromium message loop TYPE_UI does exactly what we need. */
98
  options.message_loop_type = MessageLoop::TYPE_UI;
99
#endif
100
101
0
  if (!compositorThread->StartWithOptions(options)) {
102
0
    delete compositorThread;
103
0
    return nullptr;
104
0
  }
105
0
106
0
  CompositorBridgeParent::Setup();
107
0
  ImageBridgeParent::Setup();
108
0
109
0
  return compositorThread;
110
0
}
111
112
void
113
CompositorThreadHolder::Start()
114
0
{
115
0
  MOZ_ASSERT(NS_IsMainThread(), "Should be on the main Thread!");
116
0
  MOZ_ASSERT(!sCompositorThreadHolder, "The compositor thread has already been started!");
117
0
118
0
  // We unset the holder instead of asserting because failing to start the
119
0
  // compositor thread may not be a fatal error. As long as this succeeds in
120
0
  // either the GPU process or the UI process, the user will have a usable
121
0
  // browser. If we get neither, it will crash as soon as we try to post to the
122
0
  // compositor thread for the first time.
123
0
  sCompositorThreadHolder = new CompositorThreadHolder();
124
0
  if (!sCompositorThreadHolder->GetCompositorThread()) {
125
0
    gfxCriticalNote << "Compositor thread not started (" << XRE_IsParentProcess() << ")";
126
0
    sCompositorThreadHolder = nullptr;
127
0
  }
128
0
}
129
130
void
131
CompositorThreadHolder::Shutdown()
132
0
{
133
0
  MOZ_ASSERT(NS_IsMainThread(), "Should be on the main Thread!");
134
0
  if (!sCompositorThreadHolder) {
135
0
    // We've already shutdown or never started.
136
0
    return;
137
0
  }
138
0
139
0
  ImageBridgeParent::Shutdown();
140
0
  gfx::ReleaseVRManagerParentSingleton();
141
0
  MediaSystemResourceService::Shutdown();
142
0
  CompositorManagerParent::Shutdown();
143
0
144
0
  sCompositorThreadHolder = nullptr;
145
0
146
0
  // No locking is needed around sFinishedCompositorShutDown because it is only
147
0
  // ever accessed on the main thread.
148
0
  SpinEventLoopUntil([&]() { return sFinishedCompositorShutDown; });
149
0
150
0
  CompositorBridgeParent::FinishShutdown();
151
0
}
152
153
/* static */ bool
154
CompositorThreadHolder::IsInCompositorThread()
155
0
{
156
0
  return CompositorThread() &&
157
0
         CompositorThread()->thread_id() == PlatformThread::CurrentId();
158
0
}
159
160
} // namespace mozilla
161
} // namespace layers
162
163
bool
164
NS_IsInCompositorThread()
165
0
{
166
0
  return mozilla::layers::CompositorThreadHolder::IsInCompositorThread();
167
0
}