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 |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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 | |
31 | namespace mozilla { |
32 | |
33 | using namespace gfx; |
34 | |
35 | namespace layers { |
36 | |
37 | WebRenderLayerManager::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 | |
58 | KnowsCompositor* WebRenderLayerManager::AsKnowsCompositor() { return mWrChild; } |
59 | |
60 | bool 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 | |
133 | void WebRenderLayerManager::Destroy() { DoDestroy(/* aIsSync */ false); } |
134 | |
135 | void 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 | |
175 | WebRenderLayerManager::~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 | |
180 | CompositorBridgeChild* WebRenderLayerManager::GetCompositorBridgeChild() { |
181 | return WrBridge()->GetCompositorBridgeChild(); |
182 | } |
183 | |
184 | void 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 | |
196 | uint32_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 | |
206 | void WebRenderLayerManager::StopFrameTimeRecording( |
207 | uint32_t aStartIndex, nsTArray<float>& aFrameIntervals) { |
208 | CompositorBridgeChild* renderer = GetCompositorBridgeChild(); |
209 | if (renderer) { |
210 | renderer->SendStopFrameTimeRecording(aStartIndex, &aFrameIntervals); |
211 | } |
212 | } |
213 | |
214 | void WebRenderLayerManager::TakeCompositionPayloads( |
215 | nsTArray<CompositionPayload>& aPayloads) { |
216 | aPayloads.Clear(); |
217 | |
218 | std::swap(mPayload, aPayloads); |
219 | } |
220 | |
221 | bool 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 | |
231 | bool 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 | |
250 | bool 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 | |
331 | void 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 | |
486 | void WebRenderLayerManager::SetFocusTarget(const FocusTarget& aFocusTarget) { |
487 | mFocusTarget = aFocusTarget; |
488 | } |
489 | |
490 | bool WebRenderLayerManager::AsyncPanZoomEnabled() const { |
491 | return mWidget->AsyncPanZoomEnabled(); |
492 | } |
493 | |
494 | IntRect ToOutsideIntRect(const gfxRect& aRect) { |
495 | return IntRect::RoundOut(aRect.X(), aRect.Y(), aRect.Width(), aRect.Height()); |
496 | } |
497 | |
498 | void 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 | |
571 | void WebRenderLayerManager::DiscardImages() { |
572 | wr::IpcResourceUpdateQueue resources(WrBridge()); |
573 | mStateManager.DiscardImagesInTransaction(resources); |
574 | WrBridge()->UpdateResources(resources); |
575 | } |
576 | |
577 | void WebRenderLayerManager::DiscardLocalImages() { |
578 | mStateManager.DiscardLocalImages(); |
579 | } |
580 | |
581 | void 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 | |
615 | void 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 | |
636 | void 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 | |
644 | void 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 | |
658 | void WebRenderLayerManager::UpdateTextureFactoryIdentifier( |
659 | const TextureFactoryIdentifier& aNewIdentifier) { |
660 | WrBridge()->IdentifyTextureHost(aNewIdentifier); |
661 | } |
662 | |
663 | TextureFactoryIdentifier WebRenderLayerManager::GetTextureFactoryIdentifier() { |
664 | return WrBridge()->GetTextureFactoryIdentifier(); |
665 | } |
666 | |
667 | void 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 | |
687 | TransactionId WebRenderLayerManager::GetLastTransactionId() { |
688 | return mLatestTransactionId; |
689 | } |
690 | |
691 | void 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 | |
724 | void WebRenderLayerManager::WaitOnTransactionProcessed() { |
725 | CompositorBridgeChild* bridge = GetCompositorBridgeChild(); |
726 | if (bridge) { |
727 | bridge->SendWaitOnTransactionProcessed(); |
728 | } |
729 | } |
730 | |
731 | void 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 | |
741 | void WebRenderLayerManager::ScheduleComposite(wr::RenderReasons aReasons) { |
742 | WrBridge()->SendScheduleComposite(aReasons); |
743 | } |
744 | |
745 | already_AddRefed<PersistentBufferProvider> |
746 | WebRenderLayerManager::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 | |
776 | void WebRenderLayerManager::ClearAsyncAnimations() { |
777 | mStateManager.ClearAsyncAnimations(); |
778 | } |
779 | |
780 | void WebRenderLayerManager::WrReleasedImages( |
781 | const nsTArray<wr::ExternalImageKeyPair>& aPairs) { |
782 | mStateManager.WrReleasedImages(aPairs); |
783 | } |
784 | |
785 | void WebRenderLayerManager::GetFrameUniformity(FrameUniformityData* aOutData) { |
786 | WrBridge()->SendGetFrameUniformity(aOutData); |
787 | } |
788 | |
789 | /*static*/ |
790 | void WebRenderLayerManager::LayerUserDataDestroy(void* data) { |
791 | delete static_cast<LayerUserData*>(data); |
792 | } |
793 | |
794 | UniquePtr<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 | |
800 | std::unordered_set<ScrollableLayerGuid::ViewID> |
801 | WebRenderLayerManager::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 |