Bug 1691109 [wpt PR 27513] - Increase timeout duration for wpt/fetch/api/basic/keepal...
[gecko.git] / gfx / layers / PaintThread.cpp
blob2c85236c848d16c3b25e4c3705b816ce7f74c192
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/. */
7 #include "PaintThread.h"
9 #include <algorithm>
11 #include "base/task.h"
12 #include "gfxPlatform.h"
13 #include "GeckoProfiler.h"
14 #include "mozilla/layers/CompositorBridgeChild.h"
15 #include "mozilla/layers/ShadowLayers.h"
16 #include "mozilla/layers/SyncObject.h"
17 #include "mozilla/gfx/2D.h"
18 #include "mozilla/Preferences.h"
19 #include "mozilla/StaticPrefs_layers.h"
20 #include "mozilla/SharedThreadPool.h"
21 #include "mozilla/SyncRunnable.h"
22 #include "nsProxyRelease.h"
23 #ifdef XP_MACOSX
24 # include "nsCocoaFeatures.h"
25 #endif
26 #include "nsIThreadManager.h"
27 #include "nsServiceManagerUtils.h"
28 #include "prsystem.h"
30 // Uncomment the following line to dispatch sync runnables when
31 // painting so that rasterization happens synchronously from
32 // the perspective of the main thread
33 // #define OMTP_FORCE_SYNC
35 namespace mozilla {
36 namespace layers {
38 using namespace gfx;
40 void PaintTask::DropTextureClients() { mClients.Clear(); }
42 StaticAutoPtr<PaintThread> PaintThread::sSingleton;
43 StaticRefPtr<nsIThread> PaintThread::sThread;
44 PlatformThreadId PaintThread::sThreadId;
46 PaintThread::PaintThread() = default;
48 void PaintThread::Release() {}
50 void PaintThread::AddRef() {}
52 /* static */
53 int32_t PaintThread::CalculatePaintWorkerCount() {
54 int32_t cpuCores = PR_GetNumberOfProcessors();
55 int32_t workerCount = StaticPrefs::layers_omtp_paint_workers_AtStartup();
57 // If not manually specified, default to (cpuCores * 3) / 4, and clamp
58 // between 1 and 4. If a user wants more, they can manually specify it
59 if (workerCount < 1) {
60 workerCount = std::min(std::max((cpuCores * 3) / 4, 1), 4);
63 return workerCount;
66 /* static */
67 void PaintThread::Start() {
68 PaintThread::sSingleton = new PaintThread();
70 if (!PaintThread::sSingleton->Init()) {
71 gfxCriticalNote << "Unable to start paint thread";
72 PaintThread::sSingleton = nullptr;
76 static uint32_t GetPaintThreadStackSize() {
77 #ifndef XP_MACOSX
78 return nsIThreadManager::DEFAULT_STACK_SIZE;
79 #else
80 // Workaround bug 1578075 by increasing the stack size of paint threads
81 if (nsCocoaFeatures::OnCatalinaOrLater()) {
82 static const uint32_t kCatalinaPaintThreadStackSize = 512 * 1024;
83 static_assert(
84 kCatalinaPaintThreadStackSize >= nsIThreadManager::DEFAULT_STACK_SIZE,
85 "update default stack size of paint "
86 "workers");
87 return kCatalinaPaintThreadStackSize;
89 return nsIThreadManager::DEFAULT_STACK_SIZE;
90 #endif
93 bool PaintThread::Init() {
94 MOZ_ASSERT(NS_IsMainThread());
96 RefPtr<nsIThread> thread;
97 nsresult rv = NS_NewNamedThread("PaintThread", getter_AddRefs(thread),
98 nullptr, GetPaintThreadStackSize());
99 if (NS_FAILED(rv)) {
100 return false;
102 sThread = thread;
104 // Only create paint workers for tiling if we are using tiling or could
105 // expect to dynamically switch to tiling in the future
106 if (gfxPlatform::GetPlatform()->UsesTiling()) {
107 InitPaintWorkers();
110 nsCOMPtr<nsIRunnable> paintInitTask = NewRunnableMethod(
111 "PaintThread::InitOnPaintThread", this, &PaintThread::InitOnPaintThread);
112 SyncRunnable::DispatchToThread(sThread, paintInitTask);
113 return true;
116 void PaintThread::InitOnPaintThread() {
117 MOZ_ASSERT(!NS_IsMainThread());
118 sThreadId = PlatformThread::CurrentId();
121 void PaintThread::InitPaintWorkers() {
122 MOZ_ASSERT(NS_IsMainThread());
123 int32_t count = PaintThread::CalculatePaintWorkerCount();
124 if (count != 1) {
125 mPaintWorkers = SharedThreadPool::Get("PaintWorker"_ns, count);
126 mPaintWorkers->SetThreadStackSize(GetPaintThreadStackSize());
130 void DestroyPaintThread(UniquePtr<PaintThread>&& pt) {
131 MOZ_ASSERT(PaintThread::IsOnPaintThread());
132 pt->ShutdownOnPaintThread();
135 /* static */
136 void PaintThread::Shutdown() {
137 MOZ_ASSERT(NS_IsMainThread());
139 UniquePtr<PaintThread> pt(sSingleton.forget());
140 if (!pt) {
141 return;
144 sThread->Dispatch(NewRunnableFunction("DestroyPaintThreadRunnable",
145 DestroyPaintThread, std::move(pt)));
146 sThread->Shutdown();
147 sThread = nullptr;
150 void PaintThread::ShutdownOnPaintThread() { MOZ_ASSERT(IsOnPaintThread()); }
152 /* static */
153 PaintThread* PaintThread::Get() { return PaintThread::sSingleton.get(); }
155 /* static */
156 bool PaintThread::IsOnPaintThread() {
157 return sThreadId == PlatformThread::CurrentId();
160 bool PaintThread::IsOnPaintWorkerThread() {
161 return (mPaintWorkers && mPaintWorkers->IsOnCurrentThread()) ||
162 (sThreadId == PlatformThread::CurrentId());
165 void PaintThread::Dispatch(RefPtr<Runnable>& aRunnable) {
166 #ifndef OMTP_FORCE_SYNC
167 sThread->Dispatch(aRunnable.forget());
168 #else
169 SyncRunnable::DispatchToThread(sThread, aRunnable);
170 #endif
173 void PaintThread::UpdateRenderMode() {
174 if (!!mPaintWorkers != gfxPlatform::GetPlatform()->UsesTiling()) {
175 if (mPaintWorkers) {
176 mPaintWorkers = nullptr;
177 } else {
178 InitPaintWorkers();
183 void PaintThread::QueuePaintTask(UniquePtr<PaintTask>&& aTask) {
184 MOZ_ASSERT(NS_IsMainThread());
185 MOZ_ASSERT(aTask);
187 if (StaticPrefs::layers_omtp_dump_capture() && aTask->mCapture) {
188 aTask->mCapture->Dump();
191 MOZ_RELEASE_ASSERT(aTask->mCapture->hasOneRef());
193 RefPtr<CompositorBridgeChild> cbc(CompositorBridgeChild::Get());
194 cbc->NotifyBeginAsyncPaint(aTask.get());
196 RefPtr<PaintThread> self = this;
197 RefPtr<Runnable> task =
198 NS_NewRunnableFunction("PaintThread::AsyncPaintTask",
199 [self, cbc, task = std::move(aTask)]() -> void {
200 self->AsyncPaintTask(cbc, task.get());
203 nsIEventTarget* paintThread =
204 mPaintWorkers ? static_cast<nsIEventTarget*>(mPaintWorkers.get())
205 : static_cast<nsIEventTarget*>(sThread.get());
207 #ifndef OMTP_FORCE_SYNC
208 paintThread->Dispatch(task.forget());
209 #else
210 SyncRunnable::DispatchToThread(paintThread, task);
211 #endif
214 void PaintThread::AsyncPaintTask(CompositorBridgeChild* aBridge,
215 PaintTask* aTask) {
216 AUTO_PROFILER_LABEL("PaintThread::AsyncPaintTask", GRAPHICS);
218 MOZ_ASSERT(IsOnPaintWorkerThread());
219 MOZ_ASSERT(aTask);
221 gfx::DrawTargetCapture* capture = aTask->mCapture;
222 gfx::DrawTarget* target = aTask->mTarget;
224 if (target->IsValid()) {
225 // Do not replay to invalid targets. This can happen on device resets and
226 // the browser will ensure the graphics stack is reinitialized on the main
227 // thread.
228 target->DrawCapturedDT(capture, Matrix());
229 target->Flush();
232 if (StaticPrefs::layers_omtp_release_capture_on_main_thread()) {
233 // This should ensure the capture drawtarget, which may hold on to
234 // UnscaledFont objects, gets destroyed on the main thread (See bug
235 // 1404742). This assumes (unflushed) target DrawTargets do not themselves
236 // hold on to UnscaledFonts.
237 NS_ReleaseOnMainThread("PaintTask::DrawTargetCapture",
238 aTask->mCapture.forget());
241 if (aBridge->NotifyFinishedAsyncWorkerPaint(aTask)) {
242 AsyncEndLayerTransaction(aBridge);
246 void PaintThread::QueueEndLayerTransaction(SyncObjectClient* aSyncObject) {
247 MOZ_ASSERT(NS_IsMainThread());
249 RefPtr<CompositorBridgeChild> cbc(CompositorBridgeChild::Get());
251 if (cbc->NotifyBeginAsyncEndLayerTransaction(aSyncObject)) {
252 RefPtr<PaintThread> self = this;
253 RefPtr<Runnable> task = NS_NewRunnableFunction(
254 "PaintThread::AsyncEndLayerTransaction",
255 [self, cbc]() -> void { self->AsyncEndLayerTransaction(cbc); });
257 #ifndef OMTP_FORCE_SYNC
258 sThread->Dispatch(task.forget());
259 #else
260 SyncRunnable::DispatchToThread(sThread, task);
261 #endif
265 void PaintThread::AsyncEndLayerTransaction(CompositorBridgeChild* aBridge) {
266 MOZ_ASSERT(IsOnPaintWorkerThread());
268 aBridge->NotifyFinishedAsyncEndLayerTransaction();
271 } // namespace layers
272 } // namespace mozilla