Bug Summary

File:var/lib/jenkins/workspace/firefox-scan-build/gfx/layers/wr/WebRenderLayerManager.cpp
Warning:line 379, column 7
Value stored to 'builderDumpIndex' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name Unified_cpp_gfx_layers9.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -ffp-contract=off -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/gfx/layers -fcoverage-compilation-dir=/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/gfx/layers -resource-dir /usr/lib/llvm-19/lib/clang/19 -include /var/lib/jenkins/workspace/firefox-scan-build/config/gcc_hidden.h -include /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/mozilla-config.h -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/stl_wrappers -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/system_wrappers -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D DEBUG=1 -D GOOGLE_PROTOBUF_NO_RTTI -D GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER -D MOZ_APP_VERSION=132.0a1 -D D3D_DEBUG_INFO -D MOZ_HAS_MOZGLUE -D MOZILLA_INTERNAL_API -D IMPL_LIBXUL -D MOZ_SUPPORT_LEAKCHECKING -D STATIC_EXPORTABLE_JS_API -I /var/lib/jenkins/workspace/firefox-scan-build/gfx/layers -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/gfx/layers -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/ipc/ipdl/_ipdlheaders -I /var/lib/jenkins/workspace/firefox-scan-build/ipc/chromium/src -I /var/lib/jenkins/workspace/firefox-scan-build/docshell/base -I /var/lib/jenkins/workspace/firefox-scan-build/dom/canvas -I /var/lib/jenkins/workspace/firefox-scan-build/gfx/cairo/cairo/src -I /var/lib/jenkins/workspace/firefox-scan-build/layout/base -I /var/lib/jenkins/workspace/firefox-scan-build/layout/generic -I /var/lib/jenkins/workspace/firefox-scan-build/media/libyuv/libyuv/include -I /var/lib/jenkins/workspace/firefox-scan-build/gfx/skia -I /var/lib/jenkins/workspace/firefox-scan-build/gfx/skia/skia -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nspr -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nss -D MOZILLA_CLIENT -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/x86_64-linux-gnu -I /usr/include/webp -I /usr/include/gio-unix-2.0 -I /usr/include/cloudproviders -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/at-spi-2.0 -I /usr/include/dbus-1.0 -I /usr/lib/x86_64-linux-gnu/dbus-1.0/include -I /usr/include/gtk-3.0/unix-print -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/x86_64-linux-gnu/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/backward -internal-isystem /usr/lib/llvm-19/lib/clang/19/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-error=tautological-type-limit-compare -Wno-invalid-offsetof -Wno-range-loop-analysis -Wno-deprecated-anon-enum-enum-conversion -Wno-deprecated-enum-enum-conversion -Wno-deprecated-this-capture -Wno-inline-new-delete -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wno-error=atomic-alignment -Wno-error=deprecated-builtins -Wno-psabi -Wno-error=builtin-macro-redefined -Wno-vla-cxx-extension -Wno-unknown-warning-option -fdeprecated-macro -ferror-limit 19 -fstrict-flex-arrays=1 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fno-rtti -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fno-sized-deallocation -fno-aligned-allocation -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2024-09-22-115206-3586786-1 -x c++ Unified_cpp_gfx_layers9.cpp
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 "WebRenderLayerManager.h"
8
9#include "GeckoProfiler.h"
10#include "mozilla/StaticPrefs_apz.h"
11#include "mozilla/StaticPrefs_layers.h"
12#include "mozilla/dom/BrowserChild.h"
13#include "mozilla/gfx/DrawEventRecorder.h"
14#include "mozilla/layers/CompositorBridgeChild.h"
15#include "mozilla/layers/StackingContextHelper.h"
16#include "mozilla/layers/TextureClient.h"
17#include "mozilla/layers/TransactionIdAllocator.h"
18#include "mozilla/layers/WebRenderBridgeChild.h"
19#include "mozilla/layers/UpdateImageHelper.h"
20#include "mozilla/PerfStats.h"
21#include "nsDisplayList.h"
22#include "nsLayoutUtils.h"
23#include "WebRenderCanvasRenderer.h"
24#include "LayerUserData.h"
25
26#ifdef XP_WIN
27# include "gfxDWriteFonts.h"
28# include "mozilla/WindowsProcessMitigations.h"
29#endif
30
31namespace mozilla {
32
33using namespace gfx;
34
35namespace layers {
36
37WebRenderLayerManager::WebRenderLayerManager(nsIWidget* aWidget)
38 : mWidget(aWidget),
39 mLatestTransactionId{0},
40 mNeedsComposite(false),
41 mIsFirstPaint(false),
42 mDestroyed(false),
43 mTarget(nullptr),
44 mPaintSequenceNumber(0),
45 mWebRenderCommandBuilder(this) {
46 MOZ_COUNT_CTOR(WebRenderLayerManager)do { static_assert(std::is_class_v<WebRenderLayerManager>
, "Token '" "WebRenderLayerManager" "' is not a class type.")
; static_assert(!std::is_base_of<nsISupports, WebRenderLayerManager
>::value, "nsISupports classes don't need to call MOZ_COUNT_CTOR or "
"MOZ_COUNT_DTOR");; NS_LogCtor((void*)this, "WebRenderLayerManager"
, sizeof(*this)); } while (0)
;
47 mStateManager.mLayerManager = this;
48
49 if (XRE_IsContentProcess() &&
50 StaticPrefs::gfx_webrender_enable_item_cache_AtStartup()) {
51 static const size_t kInitialCacheSize = 1024;
52 static const size_t kMaximumCacheSize = 10240;
53
54 mDisplayItemCache.SetCapacity(kInitialCacheSize, kMaximumCacheSize);
55 }
56}
57
58KnowsCompositor* WebRenderLayerManager::AsKnowsCompositor() { return mWrChild; }
59
60bool WebRenderLayerManager::Initialize(
61 PCompositorBridgeChild* aCBChild, wr::PipelineId aLayersId,
62 TextureFactoryIdentifier* aTextureFactoryIdentifier, nsCString& aError) {
63 MOZ_ASSERT(mWrChild == nullptr)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mWrChild == nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mWrChild == nullptr))), 0)))
{ do { } while (false); MOZ_ReportAssertionFailure("mWrChild == nullptr"
, "/var/lib/jenkins/workspace/firefox-scan-build/gfx/layers/wr/WebRenderLayerManager.cpp"
, 63); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mWrChild == nullptr"
")"); do { *((volatile int*)__null) = 63; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
64 MOZ_ASSERT(aTextureFactoryIdentifier)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aTextureFactoryIdentifier)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aTextureFactoryIdentifier)))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("aTextureFactoryIdentifier"
, "/var/lib/jenkins/workspace/firefox-scan-build/gfx/layers/wr/WebRenderLayerManager.cpp"
, 64); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aTextureFactoryIdentifier"
")"); do { *((volatile int*)__null) = 64; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
65
66 // When we fail to initialize WebRender, it is useful to know if it has ever
67 // succeeded, or if this is the first attempt.
68 static bool hasInitialized = false;
69
70 WindowKind windowKind;
71 if (mWidget->GetWindowType() != widget::WindowType::Popup) {
72 windowKind = WindowKind::MAIN;
73 } else {
74 windowKind = WindowKind::SECONDARY;
75 }
76
77 LayoutDeviceIntSize size = mWidget->GetClientSize();
78 // Check widget size
79 if (!wr::WindowSizeSanityCheck(size.width, size.height)) {
80 gfxCriticalNoteOncestatic mozilla::gfx::CriticalLog sOnceAtLine80 = mozilla::gfx
::CriticalLog(mozilla::gfx::CriticalLog::DefaultOptions(false
))
<< "Widget size is not valid " << size
81 << " isParent: " << XRE_IsParentProcess();
82 }
83
84 PWebRenderBridgeChild* bridge =
85 aCBChild->SendPWebRenderBridgeConstructor(aLayersId, size, windowKind);
86 if (!bridge) {
87 // This should only fail if we attempt to access a layer we don't have
88 // permission for, or more likely, the GPU process crashed again during
89 // reinitialization. We can expect to be notified again to reinitialize
90 // (which may or may not be using WebRender).
91 gfxCriticalNotemozilla::gfx::CriticalLog(mozilla::gfx::CriticalLog::DefaultOptions
(false))
<< "Failed to create WebRenderBridgeChild.";
92 aError.Assign(hasInitialized
93 ? "FEATURE_FAILURE_WEBRENDER_INITIALIZE_IPDL_POST"_ns
94 : "FEATURE_FAILURE_WEBRENDER_INITIALIZE_IPDL_FIRST"_ns);
95 return false;
96 }
97
98 mWrChild = static_cast<WebRenderBridgeChild*>(bridge);
99 mHasFlushedThisChild = false;
100
101 TextureFactoryIdentifier textureFactoryIdentifier;
102 wr::MaybeIdNamespace idNamespace;
103 // Sync ipc
104 if (!WrBridge()->SendEnsureConnected(&textureFactoryIdentifier, &idNamespace,
105 &aError)) {
106 gfxCriticalNotemozilla::gfx::CriticalLog(mozilla::gfx::CriticalLog::DefaultOptions
(false))
<< "Failed as lost WebRenderBridgeChild.";
107 aError.Assign(hasInitialized
108 ? "FEATURE_FAILURE_WEBRENDER_INITIALIZE_SYNC_POST"_ns
109 : "FEATURE_FAILURE_WEBRENDER_INITIALIZE_SYNC_FIRST"_ns);
110 return false;
111 }
112
113 if (textureFactoryIdentifier.mParentBackend == LayersBackend::LAYERS_NONE ||
114 idNamespace.isNothing()) {
115 gfxCriticalNotemozilla::gfx::CriticalLog(mozilla::gfx::CriticalLog::DefaultOptions
(false))
<< "Failed to connect WebRenderBridgeChild. isParent="
116 << XRE_IsParentProcess();
117 aError.Append(hasInitialized ? "_POST"_ns : "_FIRST"_ns);
118 return false;
119 }
120
121 WrBridge()->SetWebRenderLayerManager(this);
122 WrBridge()->IdentifyTextureHost(textureFactoryIdentifier);
123 WrBridge()->SetNamespace(idNamespace.ref());
124 *aTextureFactoryIdentifier = textureFactoryIdentifier;
125
126 mDLBuilder = MakeUnique<wr::DisplayListBuilder>(
127 WrBridge()->GetPipeline(), WrBridge()->GetWebRenderBackend());
128
129 hasInitialized = true;
130 return true;
131}
132
133void WebRenderLayerManager::Destroy() { DoDestroy(/* aIsSync */ false); }
134
135void WebRenderLayerManager::DoDestroy(bool aIsSync) {
136 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "/var/lib/jenkins/workspace/firefox-scan-build/gfx/layers/wr/WebRenderLayerManager.cpp"
, 136); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 136; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
137
138 if (IsDestroyed()) {
139 return;
140 }
141
142 mDLBuilder = nullptr;
143 mUserData.Destroy();
144 mPartialPrerenderedAnimations.Clear();
145
146 mStateManager.Destroy();
147
148 if (WrBridge()) {
149 WrBridge()->Destroy(aIsSync);
150 }
151
152 mWebRenderCommandBuilder.Destroy();
153
154 if (mTransactionIdAllocator) {
155 // Make sure to notify the refresh driver just in case it's waiting on a
156 // pending transaction. Do this at the top of the event loop so we don't
157 // cause a paint to occur during compositor shutdown.
158 RefPtr<TransactionIdAllocator> allocator = mTransactionIdAllocator;
159 TransactionId id = mLatestTransactionId;
160
161 RefPtr<Runnable> task = NS_NewRunnableFunction(
162 "TransactionIdAllocator::NotifyTransactionCompleted",
163 [allocator, id]() -> void {
164 allocator->ClearPendingTransactions();
165 allocator->NotifyTransactionCompleted(id);
166 });
167 NS_DispatchToMainThread(task.forget());
168 }
169
170 // Forget the widget pointer in case we outlive our owning widget.
171 mWidget = nullptr;
172 mDestroyed = true;
173}
174
175WebRenderLayerManager::~WebRenderLayerManager() {
176 Destroy();
177 MOZ_COUNT_DTOR(WebRenderLayerManager)do { static_assert(std::is_class_v<WebRenderLayerManager>
, "Token '" "WebRenderLayerManager" "' is not a class type.")
; static_assert(!std::is_base_of<nsISupports, WebRenderLayerManager
>::value, "nsISupports classes don't need to call MOZ_COUNT_CTOR or "
"MOZ_COUNT_DTOR");; NS_LogDtor((void*)this, "WebRenderLayerManager"
, sizeof(*this)); } while (0)
;
178}
179
180CompositorBridgeChild* WebRenderLayerManager::GetCompositorBridgeChild() {
181 return WrBridge()->GetCompositorBridgeChild();
182}
183
184void WebRenderLayerManager::GetBackendName(nsAString& name) {
185 if (WrBridge()->UsingSoftwareWebRenderD3D11()) {
186 name.AssignLiteral("WebRender (Software D3D11)");
187 } else if (WrBridge()->UsingSoftwareWebRenderOpenGL()) {
188 name.AssignLiteral("WebRender (Software OpenGL)");
189 } else if (WrBridge()->UsingSoftwareWebRender()) {
190 name.AssignLiteral("WebRender (Software)");
191 } else {
192 name.AssignLiteral("WebRender");
193 }
194}
195
196uint32_t WebRenderLayerManager::StartFrameTimeRecording(int32_t aBufferSize) {
197 CompositorBridgeChild* renderer = GetCompositorBridgeChild();
198 if (renderer) {
199 uint32_t startIndex;
200 renderer->SendStartFrameTimeRecording(aBufferSize, &startIndex);
201 return startIndex;
202 }
203 return -1;
204}
205
206void WebRenderLayerManager::StopFrameTimeRecording(
207 uint32_t aStartIndex, nsTArray<float>& aFrameIntervals) {
208 CompositorBridgeChild* renderer = GetCompositorBridgeChild();
209 if (renderer) {
210 renderer->SendStopFrameTimeRecording(aStartIndex, &aFrameIntervals);
211 }
212}
213
214void WebRenderLayerManager::TakeCompositionPayloads(
215 nsTArray<CompositionPayload>& aPayloads) {
216 aPayloads.Clear();
217
218 std::swap(mPayload, aPayloads);
219}
220
221bool WebRenderLayerManager::BeginTransactionWithTarget(gfxContext* aTarget,
222 const nsCString& aURL) {
223 mTarget = aTarget;
224 bool retval = BeginTransaction(aURL);
225 if (!retval) {
226 mTarget = nullptr;
227 }
228 return retval;
229}
230
231bool WebRenderLayerManager::BeginTransaction(const nsCString& aURL) {
232 if (!WrBridge()->IPCOpen()) {
233 gfxCriticalNotemozilla::gfx::CriticalLog(mozilla::gfx::CriticalLog::DefaultOptions
(false))
<< "IPC Channel is already torn down unexpectedly\n";
234 return false;
235 }
236
237 mTransactionStart = TimeStamp::Now();
238 mURL = aURL;
239
240 // Increment the paint sequence number even if test logging isn't
241 // enabled in this process; it may be enabled in the parent process,
242 // and the parent process expects unique sequence numbers.
243 ++mPaintSequenceNumber;
244 if (StaticPrefs::apz_test_logging_enabled()) {
245 mApzTestData.StartNewPaint(mPaintSequenceNumber);
246 }
247 return true;
248}
249
250bool WebRenderLayerManager::EndEmptyTransaction(EndTransactionFlags aFlags) {
251 auto clearTarget = MakeScopeExit([&] { mTarget = nullptr; });
252
253 // If we haven't sent a display list (since creation or since the last time we
254 // sent ClearDisplayList to the parent) then we can't do an empty transaction
255 // because the parent doesn't have a display list for us and we need to send a
256 // display list first.
257 if (!WrBridge()->GetSentDisplayList()) {
258 return false;
259 }
260
261 mDisplayItemCache.SkipWaitingForPartialDisplayList();
262
263 // Don't block on hidden windows on Linux as it may block all rendering.
264 const bool throttle = mWidget->IsMapped();
265 mLatestTransactionId = mTransactionIdAllocator->GetTransactionId(throttle);
266
267 if (aFlags & EndTransactionFlags::END_NO_COMPOSITE &&
268 !mWebRenderCommandBuilder.NeedsEmptyTransaction()) {
269 if (mPendingScrollUpdates.IsEmpty()) {
270 MOZ_ASSERT(!mTarget)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mTarget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mTarget))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!mTarget", "/var/lib/jenkins/workspace/firefox-scan-build/gfx/layers/wr/WebRenderLayerManager.cpp"
, 270); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mTarget" ")"
); do { *((volatile int*)__null) = 270; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
271 WrBridge()->SendSetFocusTarget(mFocusTarget);
272 // Revoke TransactionId to trigger next paint.
273 mTransactionIdAllocator->RevokeTransactionId(mLatestTransactionId);
274 mLatestTransactionId = mLatestTransactionId.Prev();
275 return true;
276 }
277 }
278
279 LayoutDeviceIntSize size = mWidget->GetClientSize();
280 WrBridge()->BeginTransaction();
281
282 mWebRenderCommandBuilder.EmptyTransaction();
283
284 // Get the time of when the refresh driver start its tick (if available),
285 // otherwise use the time of when LayerManager::BeginTransaction was called.
286 TimeStamp refreshStart = mTransactionIdAllocator->GetTransactionStart();
287 if (!refreshStart) {
288 refreshStart = mTransactionStart;
289 }
290
291 // Skip the synchronization for buffer since we also skip the painting during
292 // device-reset status.
293 if (!gfxPlatform::GetPlatform()->DidRenderingDeviceReset()) {
294 if (WrBridge()->GetSyncObject() &&
295 WrBridge()->GetSyncObject()->IsSyncObjectValid()) {
296 WrBridge()->GetSyncObject()->Synchronize();
297 }
298 }
299
300 GetCompositorBridgeChild()->EndCanvasTransaction();
301
302 Maybe<TransactionData> transactionData;
303 if (mStateManager.mAsyncResourceUpdates || !mPendingScrollUpdates.IsEmpty() ||
304 WrBridge()->HasWebRenderParentCommands()) {
305 transactionData.emplace();
306 transactionData->mIdNamespace = WrBridge()->GetNamespace();
307 transactionData->mPaintSequenceNumber = mPaintSequenceNumber;
308 if (mStateManager.mAsyncResourceUpdates) {
309 mStateManager.mAsyncResourceUpdates->Flush(
310 transactionData->mResourceUpdates, transactionData->mSmallShmems,
311 transactionData->mLargeShmems);
312 }
313 transactionData->mScrollUpdates = std::move(mPendingScrollUpdates);
314 for (const auto& scrollId : transactionData->mScrollUpdates.Keys()) {
315 nsLayoutUtils::NotifyPaintSkipTransaction(/*scroll id=*/scrollId);
316 }
317 }
318
319 Maybe<wr::IpcResourceUpdateQueue> nothing;
320 WrBridge()->EndEmptyTransaction(mFocusTarget, std::move(transactionData),
321 mLatestTransactionId,
322 mTransactionIdAllocator->GetVsyncId(),
323 mTransactionIdAllocator->GetVsyncStart(),
324 refreshStart, mTransactionStart, mURL);
325 mTransactionStart = TimeStamp();
326
327 MakeSnapshotIfRequired(size);
328 return true;
329}
330
331void WebRenderLayerManager::EndTransactionWithoutLayer(
332 nsDisplayList* aDisplayList, nsDisplayListBuilder* aDisplayListBuilder,
333 WrFiltersHolder&& aFilters, WebRenderBackgroundData* aBackground,
334 const double aGeckoDLBuildTime) {
335 AUTO_PROFILER_TRACING_MARKER("Paint", "WrDisplayList", GRAPHICS)AutoProfilerTracing raiiObject335("Paint", "WrDisplayList", geckoprofiler
::category::GRAPHICS, mozilla::Nothing())
;
336
337 auto clearTarget = MakeScopeExit([&] { mTarget = nullptr; });
338
339 WrBridge()->BeginTransaction();
340
341 LayoutDeviceIntSize size = mWidget->GetClientSize();
342
343 mDLBuilder->Begin(&mDisplayItemCache);
344
345 wr::IpcResourceUpdateQueue resourceUpdates(WrBridge());
346 wr::usize builderDumpIndex = 0;
347 bool containsSVGGroup = false;
348 bool dumpEnabled =
349 mWebRenderCommandBuilder.ShouldDumpDisplayList(aDisplayListBuilder);
350 Maybe<AutoDisplayItemCacheSuppressor> cacheSuppressor;
351 if (dumpEnabled) {
352 cacheSuppressor.emplace(&mDisplayItemCache);
353 printf_stderr("-- WebRender display list build --\n");
354 }
355
356 if (XRE_IsContentProcess() &&
357 StaticPrefs::gfx_webrender_debug_dl_dump_content_serialized()) {
358 mDLBuilder->DumpSerializedDisplayList();
359 }
360
361 if (aDisplayList) {
362 MOZ_ASSERT(aDisplayListBuilder && !aBackground)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aDisplayListBuilder && !aBackground)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aDisplayListBuilder && !aBackground))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aDisplayListBuilder && !aBackground"
, "/var/lib/jenkins/workspace/firefox-scan-build/gfx/layers/wr/WebRenderLayerManager.cpp"
, 362); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDisplayListBuilder && !aBackground"
")"); do { *((volatile int*)__null) = 362; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
363 mDisplayItemCache.SetDisplayList(aDisplayListBuilder, aDisplayList);
364
365 mWebRenderCommandBuilder.BuildWebRenderCommands(
366 *mDLBuilder, resourceUpdates, aDisplayList, aDisplayListBuilder,
367 mScrollData, std::move(aFilters));
368
369 aDisplayListBuilder->NotifyAndClearScrollContainerFrames();
370
371 builderDumpIndex = mWebRenderCommandBuilder.GetBuilderDumpIndex();
372 containsSVGGroup = mWebRenderCommandBuilder.GetContainsSVGGroup();
373 } else {
374 // ViewToPaint does not have frame yet, then render only background clolor.
375 MOZ_ASSERT(!aDisplayListBuilder && aBackground)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aDisplayListBuilder && aBackground)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(!aDisplayListBuilder && aBackground))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("!aDisplayListBuilder && aBackground"
, "/var/lib/jenkins/workspace/firefox-scan-build/gfx/layers/wr/WebRenderLayerManager.cpp"
, 375); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aDisplayListBuilder && aBackground"
")"); do { *((volatile int*)__null) = 375; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
376 aBackground->AddWebRenderCommands(*mDLBuilder);
377 if (dumpEnabled) {
378 printf_stderr("(no display list; background only)\n");
379 builderDumpIndex =
Value stored to 'builderDumpIndex' is never read
380 mDLBuilder->Dump(/*indent*/ 1, Some(builderDumpIndex), Nothing());
381 }
382 }
383
384 if (AsyncPanZoomEnabled()) {
385 if (mIsFirstPaint) {
386 mScrollData.SetIsFirstPaint();
387 mIsFirstPaint = false;
388 }
389 mScrollData.SetPaintSequenceNumber(mPaintSequenceNumber);
390 if (dumpEnabled) {
391 std::stringstream str;
392 str << mScrollData;
393 print_stderr(str);
394 }
395 }
396
397 // Since we're sending a full mScrollData that will include the new scroll
398 // offsets, and we can throw away the pending scroll updates we had kept for
399 // an empty transaction.
400 auto scrollIdsUpdated = ClearPendingScrollInfoUpdate();
401 for (ScrollableLayerGuid::ViewID update : scrollIdsUpdated) {
402 nsLayoutUtils::NotifyPaintSkipTransaction(update);
403 }
404
405 // Don't block on hidden windows on Linux as it may block all rendering.
406 const bool throttle = mWidget->IsMapped();
407 mLatestTransactionId = mTransactionIdAllocator->GetTransactionId(throttle);
408
409 // Get the time of when the refresh driver start its tick (if available),
410 // otherwise use the time of when LayerManager::BeginTransaction was called.
411 TimeStamp refreshStart = mTransactionIdAllocator->GetTransactionStart();
412 if (!refreshStart) {
413 refreshStart = mTransactionStart;
414 }
415
416 if (mStateManager.mAsyncResourceUpdates) {
417 if (resourceUpdates.IsEmpty()) {
418 resourceUpdates.ReplaceResources(
419 std::move(mStateManager.mAsyncResourceUpdates.ref()));
420 } else {
421 WrBridge()->UpdateResources(mStateManager.mAsyncResourceUpdates.ref());
422 }
423 mStateManager.mAsyncResourceUpdates.reset();
424 }
425 mStateManager.DiscardImagesInTransaction(resourceUpdates);
426
427 WrBridge()->RemoveExpiredFontKeys(resourceUpdates);
428
429 // Skip the synchronization for buffer since we also skip the painting during
430 // device-reset status.
431 if (!gfxPlatform::GetPlatform()->DidRenderingDeviceReset()) {
432 if (WrBridge()->GetSyncObject() &&
433 WrBridge()->GetSyncObject()->IsSyncObjectValid()) {
434 WrBridge()->GetSyncObject()->Synchronize();
435 }
436 }
437
438 GetCompositorBridgeChild()->EndCanvasTransaction();
439
440 {
441 AUTO_PROFILER_TRACING_MARKER("Paint", "ForwardDPTransaction", GRAPHICS)AutoProfilerTracing raiiObject441("Paint", "ForwardDPTransaction"
, geckoprofiler::category::GRAPHICS, mozilla::Nothing())
;
442 DisplayListData dlData;
443 mDLBuilder->End(dlData);
444 resourceUpdates.Flush(dlData.mResourceUpdates, dlData.mSmallShmems,
445 dlData.mLargeShmems);
446 dlData.mRect =
447 LayoutDeviceRect(LayoutDevicePoint(), LayoutDeviceSize(size));
448 dlData.mScrollData.emplace(std::move(mScrollData));
449 dlData.mDLDesc.gecko_display_list_type =
450 aDisplayListBuilder && aDisplayListBuilder->PartialBuildFailed()
451 ? wr::GeckoDisplayListType::Full(aGeckoDLBuildTime)
452 : wr::GeckoDisplayListType::Partial(aGeckoDLBuildTime);
453
454 // convert from nanoseconds to microseconds
455 auto duration = TimeDuration::FromMicroseconds(
456 double(dlData.mDLDesc.builder_finish_time -
457 dlData.mDLDesc.builder_start_time) /
458 1000.);
459 PerfStats::RecordMeasurement(PerfStats::Metric::WrDisplayListBuilding,
460 duration);
461 bool ret = WrBridge()->EndTransaction(
462 std::move(dlData), mLatestTransactionId, containsSVGGroup,
463 mTransactionIdAllocator->GetVsyncId(),
464 mTransactionIdAllocator->GetVsyncStart(), refreshStart,
465 mTransactionStart, mURL);
466 if (!ret) {
467 // Failed to send display list, reset display item cache state.
468 mDisplayItemCache.Clear();
469 }
470
471 WrBridge()->SendSetFocusTarget(mFocusTarget);
472 mFocusTarget = FocusTarget();
473 }
474
475 // Discard animations after calling WrBridge()->EndTransaction().
476 // It updates mWrEpoch in WebRenderBridgeParent. The updated mWrEpoch is
477 // necessary for deleting animations at the correct time.
478 mStateManager.DiscardCompositorAnimations();
479
480 mTransactionStart = TimeStamp();
481
482 MakeSnapshotIfRequired(size);
483 mNeedsComposite = false;
484}
485
486void WebRenderLayerManager::SetFocusTarget(const FocusTarget& aFocusTarget) {
487 mFocusTarget = aFocusTarget;
488}
489
490bool WebRenderLayerManager::AsyncPanZoomEnabled() const {
491 return mWidget->AsyncPanZoomEnabled();
492}
493
494IntRect ToOutsideIntRect(const gfxRect& aRect) {
495 return IntRect::RoundOut(aRect.X(), aRect.Y(), aRect.Width(), aRect.Height());
496}
497
498void WebRenderLayerManager::MakeSnapshotIfRequired(LayoutDeviceIntSize aSize) {
499 auto clearTarget = MakeScopeExit([&] { mTarget = nullptr; });
500
501 if (!mTarget || !mTarget->GetDrawTarget() || aSize.IsEmpty()) {
502 return;
503 }
504
505 // XXX Add other TextureData supports.
506 // Only BufferTexture is supported now.
507
508 // TODO: fixup for proper surface format.
509 // The GLES spec only guarantees that RGBA can be used with glReadPixels,
510 // so on Android we use RGBA.
511 SurfaceFormat format =
512#ifdef MOZ_WIDGET_ANDROID
513 SurfaceFormat::R8G8B8A8;
514#else
515 SurfaceFormat::B8G8R8A8;
516#endif
517 RefPtr<TextureClient> texture = TextureClient::CreateForRawBufferAccess(
518 WrBridge(), format, aSize.ToUnknownSize(), BackendType::SKIA,
519 TextureFlags::SNAPSHOT);
520 if (!texture) {
521 return;
522 }
523
524 // The other side knows our ContentParentId and WebRenderBridgeChild will
525 // ignore the one provided here in favour of what WebRenderBridgeParent
526 // already has.
527 texture->InitIPDLActor(WrBridge(), dom::ContentParentId());
528 if (!texture->GetIPDLActor()) {
529 return;
530 }
531
532 IntRect bounds = ToOutsideIntRect(mTarget->GetClipExtents());
533 bool needsYFlip = false;
534 if (!WrBridge()->SendGetSnapshot(WrapNotNull(texture->GetIPDLActor()),
535 &needsYFlip)) {
536 return;
537 }
538
539 TextureClientAutoLock autoLock(texture, OpenMode::OPEN_READ_ONLY);
540 if (!autoLock.Succeeded()) {
541 return;
542 }
543 RefPtr<DrawTarget> drawTarget = texture->BorrowDrawTarget();
544 if (!drawTarget || !drawTarget->IsValid()) {
545 return;
546 }
547 RefPtr<SourceSurface> snapshot = drawTarget->Snapshot();
548 /*
549 static int count = 0;
550 char filename[100];
551 snprintf(filename, 100, "output%d.png", count++);
552 printf_stderr("Writing to :%s\n", filename);
553 gfxUtils::WriteAsPNG(snapshot, filename);
554 */
555
556 Rect dst(bounds.X(), bounds.Y(), bounds.Width(), bounds.Height());
557 Rect src(0, 0, bounds.Width(), bounds.Height());
558
559 Matrix m;
560 if (needsYFlip) {
561 m = Matrix::Scaling(1.0, -1.0).PostTranslate(0.0, aSize.height);
562 }
563 SurfacePattern pattern(snapshot, ExtendMode::CLAMP, m);
564 DrawTarget* dt = mTarget->GetDrawTarget();
565 MOZ_RELEASE_ASSERT(dt)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(dt)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(dt))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("dt", "/var/lib/jenkins/workspace/firefox-scan-build/gfx/layers/wr/WebRenderLayerManager.cpp"
, 565); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "dt" ")"
); do { *((volatile int*)__null) = 565; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
566 dt->FillRect(dst, pattern);
567
568 mTarget = nullptr;
569}
570
571void WebRenderLayerManager::DiscardImages() {
572 wr::IpcResourceUpdateQueue resources(WrBridge());
573 mStateManager.DiscardImagesInTransaction(resources);
574 WrBridge()->UpdateResources(resources);
575}
576
577void WebRenderLayerManager::DiscardLocalImages() {
578 mStateManager.DiscardLocalImages();
579}
580
581void WebRenderLayerManager::DidComposite(
582 TransactionId aTransactionId, const mozilla::TimeStamp& aCompositeStart,
583 const mozilla::TimeStamp& aCompositeEnd) {
584 if (IsDestroyed()) {
585 return;
586 }
587
588 MOZ_ASSERT(mWidget)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mWidget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mWidget))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mWidget", "/var/lib/jenkins/workspace/firefox-scan-build/gfx/layers/wr/WebRenderLayerManager.cpp"
, 588); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mWidget" ")"
); do { *((volatile int*)__null) = 588; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
589
590 // Notifying the observers may tick the refresh driver which can cause
591 // a lot of different things to happen that may affect the lifetime of
592 // this layer manager. So let's make sure this object stays alive until
593 // the end of the method invocation.
594 RefPtr<WebRenderLayerManager> selfRef = this;
595
596 // |aTransactionId| will be > 0 if the compositor is acknowledging a shadow
597 // layers transaction.
598 if (aTransactionId.IsValid()) {
599 nsIWidgetListener* listener = mWidget->GetWidgetListener();
600 if (listener) {
601 listener->DidCompositeWindow(aTransactionId, aCompositeStart,
602 aCompositeEnd);
603 }
604 listener = mWidget->GetAttachedWidgetListener();
605 if (listener) {
606 listener->DidCompositeWindow(aTransactionId, aCompositeStart,
607 aCompositeEnd);
608 }
609 if (mTransactionIdAllocator) {
610 mTransactionIdAllocator->NotifyTransactionCompleted(aTransactionId);
611 }
612 }
613}
614
615void WebRenderLayerManager::ClearCachedResources() {
616 if (!WrBridge()->IPCOpen()) {
617 gfxCriticalNotemozilla::gfx::CriticalLog(mozilla::gfx::CriticalLog::DefaultOptions
(false))
<< "IPC Channel is already torn down unexpectedly\n";
618 return;
619 }
620 WrBridge()->BeginClearCachedResources();
621 // We flush any pending async resource updates before we clear the display
622 // list items because some resources (e.g. images) might be shared between
623 // multiple layer managers, not get freed here, and we want to keep their
624 // states consistent.
625 mStateManager.FlushAsyncResourceUpdates();
626 mWebRenderCommandBuilder.ClearCachedResources();
627 DiscardImages();
628 mStateManager.ClearCachedResources();
629 CompositorBridgeChild* compositorBridge = GetCompositorBridgeChild();
630 if (compositorBridge) {
631 compositorBridge->ClearCachedResources();
632 }
633 WrBridge()->EndClearCachedResources();
634}
635
636void WebRenderLayerManager::ClearAnimationResources() {
637 if (!WrBridge()->IPCOpen()) {
638 gfxCriticalNotemozilla::gfx::CriticalLog(mozilla::gfx::CriticalLog::DefaultOptions
(false))
<< "IPC Channel is already torn down unexpectedly\n";
639 return;
640 }
641 WrBridge()->SendClearAnimationResources();
642}
643
644void WebRenderLayerManager::WrUpdated() {
645 ClearAsyncAnimations();
646 mStateManager.mAsyncResourceUpdates.reset();
647 mWebRenderCommandBuilder.ClearCachedResources();
648 DiscardLocalImages();
649 mDisplayItemCache.Clear();
650
651 if (mWidget) {
652 if (dom::BrowserChild* browserChild = mWidget->GetOwningBrowserChild()) {
653 browserChild->SchedulePaint();
654 }
655 }
656}
657
658void WebRenderLayerManager::UpdateTextureFactoryIdentifier(
659 const TextureFactoryIdentifier& aNewIdentifier) {
660 WrBridge()->IdentifyTextureHost(aNewIdentifier);
661}
662
663TextureFactoryIdentifier WebRenderLayerManager::GetTextureFactoryIdentifier() {
664 return WrBridge()->GetTextureFactoryIdentifier();
665}
666
667void WebRenderLayerManager::SetTransactionIdAllocator(
668 TransactionIdAllocator* aAllocator) {
669 // When changing the refresh driver, the previous refresh driver may never
670 // receive updates of pending transactions it's waiting for. So clear the
671 // waiting state before assigning another refresh driver.
672 if (mTransactionIdAllocator && (aAllocator != mTransactionIdAllocator)) {
673 mTransactionIdAllocator->ClearPendingTransactions();
674
675 // We should also reset the transaction id of the new allocator to previous
676 // allocator's last transaction id, so that completed transactions for
677 // previous allocator will be ignored and won't confuse the new allocator.
678 if (aAllocator) {
679 aAllocator->ResetInitialTransactionId(
680 mTransactionIdAllocator->LastTransactionId());
681 }
682 }
683
684 mTransactionIdAllocator = aAllocator;
685}
686
687TransactionId WebRenderLayerManager::GetLastTransactionId() {
688 return mLatestTransactionId;
689}
690
691void WebRenderLayerManager::FlushRendering(wr::RenderReasons aReasons) {
692 CompositorBridgeChild* cBridge = GetCompositorBridgeChild();
693 if (!cBridge) {
694 return;
695 }
696 MOZ_ASSERT(mWidget)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mWidget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mWidget))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mWidget", "/var/lib/jenkins/workspace/firefox-scan-build/gfx/layers/wr/WebRenderLayerManager.cpp"
, 696); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mWidget" ")"
); do { *((volatile int*)__null) = 696; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
697
698 // If widget bounds size is different from the last flush, consider
699 // this to be a resize. It's important to use GetClientSize here,
700 // because that has extra plumbing to support initial display cases
701 // where the widget doesn't yet have real bounds.
702 LayoutDeviceIntSize widgetSize = mWidget->GetClientSize();
703 bool resizing = widgetSize != mFlushWidgetSize;
704 mFlushWidgetSize = widgetSize;
705
706 if (resizing) {
707 aReasons = aReasons | wr::RenderReasons::RESIZE;
708 }
709
710 // Check for the conditions where we we force a sync flush. The first
711 // flush for this child should always be sync. Resizes should be
712 // sometimes be sync. Everything else can be async.
713 if (!mHasFlushedThisChild ||
714 (resizing && (mWidget->SynchronouslyRepaintOnResize() ||
715 StaticPrefs::layers_force_synchronous_resize()))) {
716 cBridge->SendFlushRendering(aReasons);
717 } else {
718 cBridge->SendFlushRenderingAsync(aReasons);
719 }
720
721 mHasFlushedThisChild = true;
722}
723
724void WebRenderLayerManager::WaitOnTransactionProcessed() {
725 CompositorBridgeChild* bridge = GetCompositorBridgeChild();
726 if (bridge) {
727 bridge->SendWaitOnTransactionProcessed();
728 }
729}
730
731void WebRenderLayerManager::SendInvalidRegion(const nsIntRegion& aRegion) {
732 // XXX Webrender does not support invalid region yet.
733
734#ifndef XP_WIN
735 if (WrBridge()) {
736 WrBridge()->SendInvalidateRenderedFrame();
737 }
738#endif
739}
740
741void WebRenderLayerManager::ScheduleComposite(wr::RenderReasons aReasons) {
742 WrBridge()->SendScheduleComposite(aReasons);
743}
744
745already_AddRefed<PersistentBufferProvider>
746WebRenderLayerManager::CreatePersistentBufferProvider(
747 const gfx::IntSize& aSize, gfx::SurfaceFormat aFormat,
748 bool aWillReadFrequently) {
749 // Only initialize devices if hardware acceleration may possibly be used.
750 // Remoting moves hardware usage out-of-process, while will-read-frequently
751 // avoids hardware acceleration entirely.
752 if (!aWillReadFrequently && !gfxPlatform::UseRemoteCanvas()) {
753#ifdef XP_WIN
754 // Any kind of hardware acceleration is incompatible with Win32k Lockdown
755 // We don't initialize devices here so that PersistentBufferProviderShared
756 // will fall back to using a piece of shared memory as a backing for the
757 // canvas
758 if (!IsWin32kLockedDown()) {
759 gfxPlatform::GetPlatform()->EnsureDevicesInitialized();
760 }
761#else
762 gfxPlatform::GetPlatform()->EnsureDevicesInitialized();
763#endif
764 }
765
766 RefPtr<PersistentBufferProvider> provider =
767 PersistentBufferProviderShared::Create(
768 aSize, aFormat, AsKnowsCompositor(), aWillReadFrequently);
769 if (provider) {
770 return provider.forget();
771 }
772
773 return WindowRenderer::CreatePersistentBufferProvider(aSize, aFormat);
774}
775
776void WebRenderLayerManager::ClearAsyncAnimations() {
777 mStateManager.ClearAsyncAnimations();
778}
779
780void WebRenderLayerManager::WrReleasedImages(
781 const nsTArray<wr::ExternalImageKeyPair>& aPairs) {
782 mStateManager.WrReleasedImages(aPairs);
783}
784
785void WebRenderLayerManager::GetFrameUniformity(FrameUniformityData* aOutData) {
786 WrBridge()->SendGetFrameUniformity(aOutData);
787}
788
789/*static*/
790void WebRenderLayerManager::LayerUserDataDestroy(void* data) {
791 delete static_cast<LayerUserData*>(data);
792}
793
794UniquePtr<LayerUserData> WebRenderLayerManager::RemoveUserData(void* aKey) {
795 UniquePtr<LayerUserData> d(static_cast<LayerUserData*>(
796 mUserData.Remove(static_cast<gfx::UserDataKey*>(aKey))));
797 return d;
798}
799
800std::unordered_set<ScrollableLayerGuid::ViewID>
801WebRenderLayerManager::ClearPendingScrollInfoUpdate() {
802 std::unordered_set<ScrollableLayerGuid::ViewID> scrollIds(
803 mPendingScrollUpdates.Keys().cbegin(),
804 mPendingScrollUpdates.Keys().cend());
805 mPendingScrollUpdates.Clear();
806 return scrollIds;
807}
808
809} // namespace layers
810} // namespace mozilla