Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/gfx/layers/PaintThread.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
7
#include "PaintThread.h"
8
9
#include <algorithm>
10
11
#include "base/task.h"
12
#include "gfxPlatform.h"
13
#include "gfxPrefs.h"
14
#include "GeckoProfiler.h"
15
#include "mozilla/layers/CompositorBridgeChild.h"
16
#include "mozilla/layers/ShadowLayers.h"
17
#include "mozilla/layers/SyncObject.h"
18
#include "mozilla/gfx/2D.h"
19
#include "mozilla/Preferences.h"
20
#include "mozilla/SharedThreadPool.h"
21
#include "mozilla/SyncRunnable.h"
22
#include "nsIPropertyBag2.h"
23
#include "nsServiceManagerUtils.h"
24
#include "prsystem.h"
25
26
// Uncomment the following line to dispatch sync runnables when
27
// painting so that rasterization happens synchronously from
28
// the perspective of the main thread
29
// #define OMTP_FORCE_SYNC
30
31
namespace mozilla {
32
namespace layers {
33
34
using namespace gfx;
35
36
void
37
PaintTask::DropTextureClients()
38
0
{
39
0
  mClients.Clear();
40
0
}
41
42
StaticAutoPtr<PaintThread> PaintThread::sSingleton;
43
StaticRefPtr<nsIThread> PaintThread::sThread;
44
PlatformThreadId PaintThread::sThreadId;
45
46
PaintThread::PaintThread()
47
0
{
48
0
}
49
50
void
51
PaintThread::Release()
52
0
{
53
0
}
54
55
void
56
PaintThread::AddRef()
57
0
{
58
0
}
59
60
/* static */ int32_t
61
PaintThread::CalculatePaintWorkerCount()
62
0
{
63
0
  int32_t cpuCores = PR_GetNumberOfProcessors();
64
0
  int32_t workerCount = gfxPrefs::LayersOMTPPaintWorkers();
65
0
66
0
  // If not manually specified, default to (cpuCores * 3) / 4, and clamp
67
0
  // between 1 and 4. If a user wants more, they can manually specify it
68
0
  if (workerCount < 1) {
69
0
    workerCount = std::min(std::max((cpuCores * 3) / 4, 1), 4);
70
0
  }
71
0
72
0
  return workerCount;
73
0
}
74
75
/* static */ void
76
PaintThread::Start()
77
0
{
78
0
  PaintThread::sSingleton = new PaintThread();
79
0
80
0
  if (!PaintThread::sSingleton->Init()) {
81
0
    gfxCriticalNote << "Unable to start paint thread";
82
0
    PaintThread::sSingleton = nullptr;
83
0
  }
84
0
}
85
86
bool
87
PaintThread::Init()
88
0
{
89
0
  MOZ_ASSERT(NS_IsMainThread());
90
0
91
0
  RefPtr<nsIThread> thread;
92
0
  nsresult rv = NS_NewNamedThread("PaintThread", getter_AddRefs(thread));
93
0
  if (NS_FAILED(rv)) {
94
0
    return false;
95
0
  }
96
0
  sThread = thread;
97
0
98
0
  // Only create paint workers for tiling if we are using tiling or could
99
0
  // expect to dynamically switch to tiling in the future
100
0
  if (gfxPlatform::GetPlatform()->UsesTiling()) {
101
0
    InitPaintWorkers();
102
0
  }
103
0
104
0
  nsCOMPtr<nsIRunnable> paintInitTask =
105
0
    NewRunnableMethod("PaintThread::InitOnPaintThread",
106
0
                      this, &PaintThread::InitOnPaintThread);
107
0
  SyncRunnable::DispatchToThread(sThread, paintInitTask);
108
0
  return true;
109
0
}
110
111
void
112
PaintThread::InitOnPaintThread()
113
0
{
114
0
  MOZ_ASSERT(!NS_IsMainThread());
115
0
  sThreadId = PlatformThread::CurrentId();
116
0
}
117
118
void
119
PaintThread::InitPaintWorkers()
120
0
{
121
0
  MOZ_ASSERT(NS_IsMainThread());
122
0
  int32_t count = PaintThread::CalculatePaintWorkerCount();
123
0
  if (count != 1) {
124
0
    mPaintWorkers = SharedThreadPool::Get(NS_LITERAL_CSTRING("PaintWorker"), count);
125
0
  }
126
0
}
127
128
void
129
DestroyPaintThread(UniquePtr<PaintThread>&& pt)
130
0
{
131
0
  MOZ_ASSERT(PaintThread::IsOnPaintThread());
132
0
  pt->ShutdownOnPaintThread();
133
0
}
134
135
/* static */ void
136
PaintThread::Shutdown()
137
0
{
138
0
  MOZ_ASSERT(NS_IsMainThread());
139
0
140
0
  UniquePtr<PaintThread> pt(sSingleton.forget());
141
0
  if (!pt) {
142
0
    return;
143
0
  }
144
0
145
0
  sThread->Dispatch(NewRunnableFunction("DestroyPaintThreadRunnable",
146
0
                                        DestroyPaintThread,
147
0
                                        std::move(pt)));
148
0
  sThread->Shutdown();
149
0
  sThread = nullptr;
150
0
}
151
152
void
153
PaintThread::ShutdownOnPaintThread()
154
0
{
155
0
  MOZ_ASSERT(IsOnPaintThread());
156
0
}
157
158
/* static */ PaintThread*
159
PaintThread::Get()
160
0
{
161
0
  return PaintThread::sSingleton.get();
162
0
}
163
164
/* static */ bool
165
PaintThread::IsOnPaintThread()
166
0
{
167
0
  return sThreadId == PlatformThread::CurrentId();
168
0
}
169
170
bool
171
PaintThread::IsOnPaintWorkerThread()
172
0
{
173
0
  return (mPaintWorkers && mPaintWorkers->IsOnCurrentThread()) ||
174
0
    (sThreadId == PlatformThread::CurrentId());
175
0
}
176
177
void
178
PaintThread::Dispatch(RefPtr<Runnable>& aRunnable)
179
0
{
180
0
#ifndef OMTP_FORCE_SYNC
181
0
  sThread->Dispatch(aRunnable.forget());
182
#else
183
  SyncRunnable::DispatchToThread(sThread, aRunnable);
184
#endif
185
}
186
187
void
188
PaintThread::UpdateRenderMode()
189
0
{
190
0
  if (!!mPaintWorkers != gfxPlatform::GetPlatform()->UsesTiling()) {
191
0
    if (mPaintWorkers) {
192
0
      mPaintWorkers = nullptr;
193
0
    } else {
194
0
      InitPaintWorkers();
195
0
    }
196
0
  }
197
0
}
198
199
void
200
PaintThread::QueuePaintTask(UniquePtr<PaintTask>&& aTask)
201
0
{
202
0
  MOZ_ASSERT(NS_IsMainThread());
203
0
  MOZ_ASSERT(aTask);
204
0
205
0
  if (gfxPrefs::LayersOMTPDumpCapture() && aTask->mCapture) {
206
0
    aTask->mCapture->Dump();
207
0
  }
208
0
209
0
  MOZ_RELEASE_ASSERT(aTask->mCapture->hasOneRef());
210
0
211
0
  RefPtr<CompositorBridgeChild> cbc(CompositorBridgeChild::Get());
212
0
  cbc->NotifyBeginAsyncPaint(aTask.get());
213
0
214
0
  RefPtr<PaintThread> self = this;
215
0
  RefPtr<Runnable> task = NS_NewRunnableFunction("PaintThread::AsyncPaintTask",
216
0
    [self, cbc, task = std::move(aTask)]() -> void
217
0
  {
218
0
    self->AsyncPaintTask(cbc, task.get());
219
0
  });
220
0
221
0
  nsIEventTarget* paintThread = mPaintWorkers ?
222
0
    static_cast<nsIEventTarget*>(mPaintWorkers.get()) :
223
0
    static_cast<nsIEventTarget*>(sThread.get());
224
0
225
0
#ifndef OMTP_FORCE_SYNC
226
0
  paintThread->Dispatch(task.forget());
227
#else
228
  SyncRunnable::DispatchToThread(paintThread, task);
229
#endif
230
}
231
232
void
233
PaintThread::AsyncPaintTask(CompositorBridgeChild* aBridge,
234
                            PaintTask* aTask)
235
0
{
236
0
  AUTO_PROFILER_LABEL("PaintThread::AsyncPaintTask", GRAPHICS);
237
0
  
238
0
  MOZ_ASSERT(IsOnPaintWorkerThread());
239
0
  MOZ_ASSERT(aTask);
240
0
241
0
  gfx::DrawTargetCapture* capture = aTask->mCapture;
242
0
  gfx::DrawTarget* target = aTask->mTarget;
243
0
244
0
  target->DrawCapturedDT(capture, Matrix());
245
0
  target->Flush();
246
0
247
0
  if (gfxPrefs::LayersOMTPReleaseCaptureOnMainThread()) {
248
0
    // This should ensure the capture drawtarget, which may hold on to UnscaledFont objects,
249
0
    // gets destroyed on the main thread (See bug 1404742). This assumes (unflushed) target
250
0
    // DrawTargets do not themselves hold on to UnscaledFonts.
251
0
    NS_ReleaseOnMainThreadSystemGroup("PaintTask::DrawTargetCapture", aTask->mCapture.forget());
252
0
  }
253
0
254
0
  if (aBridge->NotifyFinishedAsyncWorkerPaint(aTask)) {
255
0
    AsyncEndLayerTransaction(aBridge);
256
0
  }
257
0
}
258
259
void
260
PaintThread::QueueEndLayerTransaction(SyncObjectClient* aSyncObject)
261
0
{
262
0
  MOZ_ASSERT(NS_IsMainThread());
263
0
264
0
  RefPtr<CompositorBridgeChild> cbc(CompositorBridgeChild::Get());
265
0
266
0
  if (cbc->NotifyBeginAsyncEndLayerTransaction(aSyncObject)) {
267
0
    RefPtr<PaintThread> self = this;
268
0
    RefPtr<Runnable> task = NS_NewRunnableFunction("PaintThread::AsyncEndLayerTransaction",
269
0
      [self, cbc]() -> void
270
0
    {
271
0
      self->AsyncEndLayerTransaction(cbc);
272
0
    });
273
0
274
0
  #ifndef OMTP_FORCE_SYNC
275
0
    sThread->Dispatch(task.forget());
276
  #else
277
    SyncRunnable::DispatchToThread(sThread, task);
278
  #endif
279
  }
280
0
}
281
282
void
283
PaintThread::AsyncEndLayerTransaction(CompositorBridgeChild* aBridge)
284
0
{
285
0
  MOZ_ASSERT(IsOnPaintWorkerThread());
286
0
287
0
  aBridge->NotifyFinishedAsyncEndLayerTransaction();
288
0
}
289
290
} // namespace layers
291
} // namespace mozilla