Line data Source code
1 : /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 : * This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 :
6 : #include "LayerManagerMLGPU.h"
7 : #include "LayerTreeInvalidation.h"
8 : #include "PaintedLayerMLGPU.h"
9 : #include "ImageLayerMLGPU.h"
10 : #include "CanvasLayerMLGPU.h"
11 : #include "GeckoProfiler.h" // for profiler_*
12 : #include "MLGDevice.h"
13 : #include "RenderPassMLGPU.h"
14 : #include "RenderViewMLGPU.h"
15 : #include "ShaderDefinitionsMLGPU.h"
16 : #include "SharedBufferMLGPU.h"
17 : #include "UnitTransforms.h"
18 : #include "TextureSourceProviderMLGPU.h"
19 : #include "TreeTraversal.h"
20 : #include "FrameBuilder.h"
21 : #include "LayersLogging.h"
22 : #include "UtilityMLGPU.h"
23 : #include "mozilla/layers/Diagnostics.h"
24 : #include "mozilla/layers/TextRenderer.h"
25 :
26 : #ifdef XP_WIN
27 : #include "mozilla/widget/WinCompositorWidget.h"
28 : #include "mozilla/gfx/DeviceManagerDx.h"
29 : #endif
30 :
31 : using namespace std;
32 :
33 : namespace mozilla {
34 : namespace layers {
35 :
36 : using namespace gfx;
37 :
38 : static const int kDebugOverlayX = 2;
39 : static const int kDebugOverlayY = 5;
40 : static const int kDebugOverlayMaxWidth = 600;
41 : static const int kDebugOverlayMaxHeight = 96;
42 :
43 0 : LayerManagerMLGPU::LayerManagerMLGPU(widget::CompositorWidget* aWidget)
44 : : mWidget(aWidget),
45 : mDrawDiagnostics(false),
46 : mUsingInvalidation(false),
47 0 : mCurrentFrame(nullptr)
48 : {
49 0 : if (!aWidget) {
50 0 : return;
51 : }
52 :
53 : #ifdef WIN32
54 : mDevice = DeviceManagerDx::Get()->GetMLGDevice();
55 : #endif
56 0 : if (!mDevice || !mDevice->IsValid()) {
57 0 : gfxWarning() << "Could not acquire an MLGDevice!";
58 0 : return;
59 : }
60 :
61 0 : mSwapChain = mDevice->CreateSwapChainForWidget(aWidget);
62 0 : if (!mSwapChain) {
63 0 : gfxWarning() << "Could not acquire an MLGSwapChain!";
64 0 : return;
65 : }
66 :
67 0 : mDiagnostics = MakeUnique<Diagnostics>();
68 0 : mTextRenderer = new TextRenderer();
69 : }
70 :
71 0 : LayerManagerMLGPU::~LayerManagerMLGPU()
72 : {
73 0 : if (mTextureSourceProvider) {
74 0 : mTextureSourceProvider->Destroy();
75 : }
76 0 : }
77 :
78 : bool
79 0 : LayerManagerMLGPU::Initialize()
80 : {
81 0 : if (!mDevice || !mSwapChain) {
82 0 : return false;
83 : }
84 :
85 0 : mTextureSourceProvider = new TextureSourceProviderMLGPU(this, mDevice);
86 0 : return true;
87 : }
88 :
89 : void
90 0 : LayerManagerMLGPU::Destroy()
91 : {
92 0 : if (IsDestroyed()) {
93 0 : return;
94 : }
95 :
96 0 : LayerManager::Destroy();
97 :
98 0 : if (mDevice && mDevice->IsValid()) {
99 0 : mDevice->Flush();
100 : }
101 0 : if (mSwapChain) {
102 0 : mSwapChain->Destroy();
103 0 : mSwapChain = nullptr;
104 : }
105 0 : if (mTextureSourceProvider) {
106 0 : mTextureSourceProvider->Destroy();
107 0 : mTextureSourceProvider = nullptr;
108 : }
109 0 : mWidget = nullptr;
110 0 : mDevice = nullptr;
111 : }
112 :
113 : void
114 0 : LayerManagerMLGPU::ForcePresent()
115 : {
116 0 : if (!mDevice->IsValid()) {
117 0 : return;
118 : }
119 :
120 0 : IntSize windowSize = mWidget->GetClientSize().ToUnknownSize();
121 0 : if (mSwapChain->GetSize() != windowSize) {
122 0 : return;
123 : }
124 :
125 0 : mSwapChain->ForcePresent();
126 : }
127 :
128 : already_AddRefed<ContainerLayer>
129 0 : LayerManagerMLGPU::CreateContainerLayer()
130 : {
131 0 : return MakeAndAddRef<ContainerLayerMLGPU>(this);
132 : }
133 :
134 : already_AddRefed<ColorLayer>
135 0 : LayerManagerMLGPU::CreateColorLayer()
136 : {
137 0 : return MakeAndAddRef<ColorLayerMLGPU>(this);
138 : }
139 :
140 : already_AddRefed<RefLayer>
141 0 : LayerManagerMLGPU::CreateRefLayer()
142 : {
143 0 : return MakeAndAddRef<RefLayerMLGPU>(this);
144 : }
145 :
146 : already_AddRefed<PaintedLayer>
147 0 : LayerManagerMLGPU::CreatePaintedLayer()
148 : {
149 0 : return MakeAndAddRef<PaintedLayerMLGPU>(this);
150 : }
151 :
152 : already_AddRefed<ImageLayer>
153 0 : LayerManagerMLGPU::CreateImageLayer()
154 : {
155 0 : return MakeAndAddRef<ImageLayerMLGPU>(this);
156 : }
157 :
158 : already_AddRefed<BorderLayer>
159 0 : LayerManagerMLGPU::CreateBorderLayer()
160 : {
161 0 : MOZ_ASSERT_UNREACHABLE("Not yet implemented");
162 : return nullptr;
163 : }
164 :
165 : already_AddRefed<TextLayer>
166 0 : LayerManagerMLGPU::CreateTextLayer()
167 : {
168 0 : MOZ_ASSERT_UNREACHABLE("Not yet implemented");
169 : return nullptr;
170 : }
171 :
172 : already_AddRefed<CanvasLayer>
173 0 : LayerManagerMLGPU::CreateCanvasLayer()
174 : {
175 0 : return MakeAndAddRef<CanvasLayerMLGPU>(this);
176 : }
177 :
178 : TextureFactoryIdentifier
179 0 : LayerManagerMLGPU::GetTextureFactoryIdentifier()
180 : {
181 0 : TextureFactoryIdentifier ident;
182 0 : if (mDevice) {
183 0 : ident = mDevice->GetTextureFactoryIdentifier();
184 : }
185 0 : ident.mSupportsBackdropCopyForComponentAlpha = SupportsBackdropCopyForComponentAlpha();
186 0 : ident.mUsingAdvancedLayers = true;
187 0 : return ident;
188 : }
189 :
190 : LayersBackend
191 0 : LayerManagerMLGPU::GetBackendType()
192 : {
193 0 : return mDevice ? mDevice->GetLayersBackend() : LayersBackend::LAYERS_NONE;
194 : }
195 :
196 : void
197 0 : LayerManagerMLGPU::SetRoot(Layer* aLayer)
198 : {
199 0 : mRoot = aLayer;
200 0 : }
201 :
202 : bool
203 0 : LayerManagerMLGPU::BeginTransaction()
204 : {
205 0 : MOZ_ASSERT(!mTarget);
206 0 : return true;
207 : }
208 :
209 : void
210 0 : LayerManagerMLGPU::BeginTransactionWithDrawTarget(gfx::DrawTarget* aTarget,
211 : const gfx::IntRect& aRect)
212 : {
213 0 : MOZ_ASSERT(!mTarget);
214 :
215 0 : mTarget = aTarget;
216 0 : mTargetRect = aRect;
217 0 : return;
218 : }
219 :
220 : // Helper class for making sure textures are unlocked.
221 : class MOZ_STACK_CLASS AutoUnlockAllTextures
222 : {
223 : public:
224 0 : explicit AutoUnlockAllTextures(MLGDevice* aDevice)
225 0 : : mDevice(aDevice)
226 0 : {}
227 0 : ~AutoUnlockAllTextures() {
228 0 : mDevice->UnlockAllTextures();
229 0 : }
230 :
231 : private:
232 : RefPtr<MLGDevice> mDevice;
233 : };
234 :
235 : void
236 0 : LayerManagerMLGPU::EndTransaction(const TimeStamp& aTimeStamp, EndTransactionFlags aFlags)
237 : {
238 0 : AUTO_PROFILER_LABEL("LayerManager::EndTransaction", GRAPHICS);
239 :
240 0 : SetCompositionTime(aTimeStamp);
241 :
242 0 : TextureSourceProvider::AutoReadUnlockTextures unlock(mTextureSourceProvider);
243 :
244 0 : if (!mRoot || (aFlags & END_NO_IMMEDIATE_REDRAW) || !mWidget) {
245 0 : return;
246 : }
247 :
248 0 : mCompositionStartTime = TimeStamp::Now();
249 :
250 0 : IntSize windowSize = mWidget->GetClientSize().ToUnknownSize();
251 0 : if (windowSize.IsEmpty()) {
252 0 : return;
253 : }
254 :
255 : // Resize the window if needed.
256 0 : if (mSwapChain->GetSize() != windowSize) {
257 : // Note: all references to the backbuffer must be cleared.
258 0 : mDevice->SetRenderTarget(nullptr);
259 0 : if (!mSwapChain->ResizeBuffers(windowSize)) {
260 0 : gfxCriticalNote << "Could not resize the swapchain (" <<
261 0 : hexa(windowSize.width) << "," << hexa(windowSize.height) << ")";
262 0 : return;
263 : }
264 : }
265 :
266 : // Don't draw the diagnostic overlay if we want to snapshot the output.
267 0 : mDrawDiagnostics = gfxPrefs::LayersDrawFPS() && !mTarget;
268 0 : mUsingInvalidation = gfxPrefs::AdvancedLayersUseInvalidation();
269 :
270 : // Compute transforms - and the changed area, if enabled.
271 0 : mRoot->ComputeEffectiveTransforms(Matrix4x4());
272 0 : ComputeInvalidRegion();
273 :
274 : // Build and execute draw commands, and present.
275 0 : if (PreRender()) {
276 0 : Composite();
277 0 : PostRender();
278 : }
279 :
280 0 : mTextureSourceProvider->FlushPendingNotifyNotUsed();
281 :
282 : // Finish composition.
283 0 : mLastCompositionEndTime = TimeStamp::Now();
284 : }
285 :
286 : void
287 0 : LayerManagerMLGPU::Composite()
288 : {
289 0 : AUTO_PROFILER_LABEL("LayerManagerMLGPU::Composite", GRAPHICS);
290 :
291 : // Don't composite if we're minimized/hidden, or if there is nothing to draw.
292 0 : if (mWidget->IsHidden()) {
293 0 : return;
294 : }
295 :
296 : // Make sure the diagnostic area gets invalidated. We do this now, rather than
297 : // earlier, so we don't accidentally cause extra composites.
298 0 : Maybe<IntRect> diagnosticRect;
299 0 : if (mDrawDiagnostics) {
300 0 : diagnosticRect = Some(IntRect(
301 : kDebugOverlayX, kDebugOverlayY,
302 0 : kDebugOverlayMaxWidth, kDebugOverlayMaxHeight));
303 : }
304 :
305 : AL_LOG("Computed invalid region: %s\n", Stringify(mInvalidRegion).c_str());
306 :
307 : // Now that we have the final invalid region, give it to the swap chain which
308 : // will tell us if we still need to render.
309 0 : if (!mSwapChain->ApplyNewInvalidRegion(Move(mInvalidRegion), diagnosticRect)) {
310 0 : return;
311 : }
312 :
313 0 : AutoUnlockAllTextures autoUnlock(mDevice);
314 :
315 0 : mDevice->BeginFrame();
316 :
317 0 : RenderLayers();
318 :
319 0 : if (mDrawDiagnostics) {
320 0 : DrawDebugOverlay();
321 : }
322 :
323 0 : if (mTarget) {
324 0 : mSwapChain->CopyBackbuffer(mTarget, mTargetRect);
325 0 : mTarget = nullptr;
326 0 : mTargetRect = IntRect();
327 : }
328 0 : mSwapChain->Present();
329 :
330 : // We call this here to mimic the behavior in LayerManagerComposite, as to
331 : // not change what Talos measures. That is, we do not record an empty frame
332 : // as a frame, since we short-circuit at the top of this function.
333 0 : RecordFrame();
334 :
335 0 : mDevice->EndFrame();
336 : }
337 :
338 : void
339 0 : LayerManagerMLGPU::RenderLayers()
340 : {
341 0 : AUTO_PROFILER_LABEL("LayerManagerMLGPU::RenderLayers", GRAPHICS);
342 :
343 : // Traverse the layer tree and assign each layer to a render target.
344 0 : FrameBuilder builder(this, mSwapChain);
345 0 : mCurrentFrame = &builder;
346 :
347 0 : if (!builder.Build()) {
348 0 : return;
349 : }
350 :
351 0 : if (mDrawDiagnostics) {
352 0 : mDiagnostics->RecordPrepareTime((TimeStamp::Now() - mCompositionStartTime).ToMilliseconds());
353 : }
354 :
355 : // Make sure we acquire/release the sync object.
356 0 : if (!mDevice->Synchronize()) {
357 : // Catastrophic failure - probably a device reset.
358 0 : return;
359 : }
360 :
361 0 : TimeStamp start = TimeStamp::Now();
362 :
363 : // Upload shared buffers.
364 0 : mDevice->FinishSharedBufferUse();
365 :
366 : // Prepare the pipeline.
367 0 : if (mDrawDiagnostics) {
368 0 : IntSize size = mSwapChain->GetBackBufferInvalidRegion().GetBounds().Size();
369 0 : uint32_t numPixels = size.width * size.height;
370 0 : mDevice->StartDiagnostics(numPixels);
371 : }
372 :
373 : // Execute all render passes.
374 0 : builder.Render();
375 0 : mCurrentFrame = nullptr;
376 :
377 0 : if (mDrawDiagnostics) {
378 0 : mDiagnostics->RecordCompositeTime((TimeStamp::Now() - start).ToMilliseconds());
379 0 : mDevice->EndDiagnostics();
380 : }
381 : }
382 :
383 : void
384 0 : LayerManagerMLGPU::DrawDebugOverlay()
385 : {
386 0 : IntSize windowSize = mSwapChain->GetSize();
387 :
388 0 : GPUStats stats;
389 0 : mDevice->GetDiagnostics(&stats);
390 0 : stats.mScreenPixels = windowSize.width * windowSize.height;
391 :
392 0 : std::string text = mDiagnostics->GetFrameOverlayString(stats);
393 : RefPtr<TextureSource> texture = mTextRenderer->RenderText(
394 : mTextureSourceProvider,
395 : text,
396 : 30,
397 : 600,
398 0 : TextRenderer::FontType::FixedWidth);
399 0 : if (!texture) {
400 0 : return;
401 : }
402 :
403 0 : if (mUsingInvalidation &&
404 0 : (texture->GetSize().width > kDebugOverlayMaxWidth ||
405 0 : texture->GetSize().height > kDebugOverlayMaxHeight))
406 : {
407 0 : gfxCriticalNote << "Diagnostic overlay exceeds invalidation area: %s" << Stringify(texture->GetSize()).c_str();
408 : }
409 :
410 0 : struct DebugRect {
411 : Rect bounds;
412 : Rect texCoords;
413 : };
414 :
415 0 : if (!mDiagnosticVertices) {
416 0 : DebugRect rect;
417 0 : rect.bounds = Rect(Point(kDebugOverlayX, kDebugOverlayY), Size(texture->GetSize()));
418 0 : rect.texCoords = Rect(0.0, 0.0, 1.0, 1.0);
419 :
420 0 : VertexStagingBuffer instances;
421 0 : if (!instances.AppendItem(rect)) {
422 0 : return;
423 : }
424 :
425 0 : mDiagnosticVertices = mDevice->CreateBuffer(
426 : MLGBufferType::Vertex,
427 0 : instances.NumItems() * instances.SizeOfItem(),
428 : MLGUsage::Immutable,
429 0 : instances.GetBufferStart());
430 0 : if (!mDiagnosticVertices) {
431 0 : return;
432 : }
433 : }
434 :
435 : // Note: we rely on the world transform being correctly left bound by the
436 : // outermost render view.
437 0 : mDevice->SetScissorRect(Nothing());
438 0 : mDevice->SetDepthTestMode(MLGDepthTestMode::Disabled);
439 0 : mDevice->SetTopology(MLGPrimitiveTopology::UnitQuad);
440 0 : mDevice->SetVertexShader(VertexShaderID::DiagnosticText);
441 0 : mDevice->SetVertexBuffer(1, mDiagnosticVertices, sizeof(DebugRect));
442 0 : mDevice->SetPixelShader(PixelShaderID::DiagnosticText);
443 0 : mDevice->SetBlendState(MLGBlendState::Over);
444 0 : mDevice->SetPSTexture(0, texture);
445 0 : mDevice->SetSamplerMode(0, SamplerMode::Point);
446 0 : mDevice->DrawInstanced(4, 1, 0, 0);
447 : }
448 :
449 : void
450 0 : LayerManagerMLGPU::ComputeInvalidRegion()
451 : {
452 : // If invalidation is disabled, throw away cloned properties and redraw the
453 : // whole target area.
454 0 : if (!mUsingInvalidation) {
455 0 : mInvalidRegion = mTarget ? mTargetRect : mRenderBounds;
456 0 : mNextFrameInvalidRegion.SetEmpty();
457 0 : return;
458 : }
459 :
460 0 : nsIntRegion changed;
461 0 : if (mClonedLayerTreeProperties) {
462 0 : changed = mClonedLayerTreeProperties->ComputeDifferences(mRoot, nullptr);
463 : } else {
464 0 : changed = mRenderBounds;
465 : }
466 :
467 : // We compute the change region, but if we're painting to a target, we save
468 : // it for the next frame instead.
469 0 : if (mTarget) {
470 0 : mInvalidRegion = mTargetRect;
471 0 : mNextFrameInvalidRegion.OrWith(changed);
472 : } else {
473 0 : mInvalidRegion = Move(mNextFrameInvalidRegion);
474 0 : mInvalidRegion.OrWith(changed);
475 : }
476 :
477 : // Free the old cloned property tree, then clone a new one. Note that we do
478 : // this before compositing since our CPU-based occlusion culling will update
479 : // the visible region to contain non-occluded draw rects. If a layer will not
480 : // be drawn, it will have no visible region. LTI might save this, and if the
481 : // layer is removed next frame, LTI will invalidate the wrong area.
482 : //
483 : // Instead, we always invalidate based on the full shadow tree.
484 : //
485 : // Note that the old compositor performs CPU-based occlusion culling *before*
486 : // invalidation. This maintains consistency, but we have more accurate draw
487 : // regions.
488 0 : mClonedLayerTreeProperties = nullptr;
489 0 : mClonedLayerTreeProperties = LayerProperties::CloneFrom(mRoot);
490 : }
491 :
492 : void
493 0 : LayerManagerMLGPU::AddInvalidRegion(const nsIntRegion& aRegion)
494 : {
495 0 : mNextFrameInvalidRegion.OrWith(aRegion);
496 0 : }
497 :
498 : TextureSourceProvider*
499 0 : LayerManagerMLGPU::GetTextureSourceProvider() const
500 : {
501 0 : return mTextureSourceProvider;
502 : }
503 :
504 : bool
505 0 : LayerManagerMLGPU::IsCompositingToScreen() const
506 : {
507 0 : return !mTarget;
508 : }
509 :
510 : bool
511 0 : LayerManagerMLGPU::AreComponentAlphaLayersEnabled()
512 : {
513 0 : return LayerManager::AreComponentAlphaLayersEnabled();
514 : }
515 :
516 : bool
517 0 : LayerManagerMLGPU::BlendingRequiresIntermediateSurface()
518 : {
519 0 : return true;
520 : }
521 :
522 : bool
523 0 : LayerManagerMLGPU::SupportsBackdropCopyForComponentAlpha()
524 : {
525 0 : return false;
526 : }
527 :
528 : void
529 0 : LayerManagerMLGPU::EndTransaction(DrawPaintedLayerCallback aCallback,
530 : void* aCallbackData,
531 : EndTransactionFlags aFlags)
532 : {
533 0 : MOZ_CRASH("GFX: Use EndTransaction(aTimeStamp)");
534 : }
535 :
536 : void
537 0 : LayerManagerMLGPU::ClearCachedResources(Layer* aSubtree)
538 : {
539 0 : Layer* root = aSubtree ? aSubtree : mRoot.get();
540 0 : if (!root) {
541 0 : return;
542 : }
543 :
544 0 : ForEachNode<ForwardIterator>(root, [](Layer* aLayer) {
545 0 : LayerMLGPU* layer = aLayer->AsHostLayer()->AsLayerMLGPU();
546 0 : if (!layer) {
547 0 : return;
548 : }
549 0 : layer->ClearCachedResources();
550 0 : });
551 : }
552 :
553 : void
554 0 : LayerManagerMLGPU::NotifyShadowTreeTransaction()
555 : {
556 0 : if (gfxPrefs::LayersDrawFPS()) {
557 0 : mDiagnostics->AddTxnFrame();
558 : }
559 0 : }
560 :
561 : void
562 0 : LayerManagerMLGPU::UpdateRenderBounds(const gfx::IntRect& aRect)
563 : {
564 0 : mRenderBounds = aRect;
565 0 : }
566 :
567 : bool
568 0 : LayerManagerMLGPU::PreRender()
569 : {
570 0 : AUTO_PROFILER_LABEL("LayerManagerMLGPU::PreRender", GRAPHICS);
571 :
572 : widget::WidgetRenderingContext context;
573 0 : if (!mWidget->PreRender(&context)) {
574 0 : return false;
575 : }
576 0 : mWidgetContext = Some(context);
577 0 : return true;
578 : }
579 :
580 : void
581 0 : LayerManagerMLGPU::PostRender()
582 : {
583 0 : mWidget->PostRender(mWidgetContext.ptr());
584 0 : mWidgetContext = Nothing();
585 0 : }
586 :
587 : } // namespace layers
588 : } // namespace mozilla
|