Coverage Report

Created: 2018-09-25 14:53

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