Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/gfx/layers/mlgpu/ContainerLayerMLGPU.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 "ContainerLayerMLGPU.h"
8
#include "gfxPrefs.h"
9
#include "LayersLogging.h"
10
#include "LayerManagerMLGPU.h"
11
#include "MLGDevice.h"
12
#include "mozilla/gfx/Rect.h"
13
#include "mozilla/gfx/Types.h"
14
#include "UnitTransforms.h"
15
#include "UtilityMLGPU.h"
16
17
namespace mozilla {
18
namespace layers {
19
20
using namespace gfx;
21
22
ContainerLayerMLGPU::ContainerLayerMLGPU(LayerManagerMLGPU* aManager)
23
 : ContainerLayer(aManager, nullptr),
24
   LayerMLGPU(aManager),
25
   mInvalidateEntireSurface(false),
26
   mSurfaceCopyNeeded(false),
27
   mView(nullptr)
28
0
{
29
0
}
30
31
ContainerLayerMLGPU::~ContainerLayerMLGPU()
32
0
{
33
0
  while (mFirstChild) {
34
0
    RemoveChild(mFirstChild);
35
0
  }
36
0
}
37
38
bool
39
ContainerLayerMLGPU::OnPrepareToRender(FrameBuilder* aBuilder)
40
0
{
41
0
  mView = nullptr;
42
0
43
0
  if (!UseIntermediateSurface()) {
44
0
    // Set this so we invalidate the entire cached render target (if any)
45
0
    // if our container uses an intermediate surface again later.
46
0
    mInvalidateEntireSurface = true;
47
0
    return true;
48
0
  }
49
0
50
0
  mChildrenChanged = false;
51
0
52
0
  mTargetOffset = GetIntermediateSurfaceRect().TopLeft().ToUnknownPoint();
53
0
  mTargetSize = GetIntermediateSurfaceRect().Size().ToUnknownSize();
54
0
55
0
  if (mRenderTarget && mRenderTarget->GetSize() != mTargetSize) {
56
0
    mRenderTarget = nullptr;
57
0
  }
58
0
59
0
  // Note that if a surface copy is needed, we always redraw the
60
0
  // whole surface (on-demand). This is a rare case - the old
61
0
  // Compositor already does this - and it saves us having to
62
0
  // do much more complicated invalidation.
63
0
  bool surfaceCopyNeeded = false;
64
0
  DefaultComputeSupportsComponentAlphaChildren(&surfaceCopyNeeded);
65
0
  if (surfaceCopyNeeded != mSurfaceCopyNeeded ||
66
0
      surfaceCopyNeeded)
67
0
  {
68
0
    mInvalidateEntireSurface = true;
69
0
  }
70
0
  mSurfaceCopyNeeded = surfaceCopyNeeded;
71
0
72
0
  gfx::IntRect viewport(gfx::IntPoint(0, 0), mTargetSize);
73
0
  if (!mRenderTarget ||
74
0
      !gfxPrefs::AdvancedLayersUseInvalidation() ||
75
0
      mInvalidateEntireSurface)
76
0
  {
77
0
    // Fine-grained invalidation is disabled, invalidate everything.
78
0
    mInvalidRect = viewport;
79
0
  } else {
80
0
    // Clamp the invalid rect to the viewport.
81
0
    mInvalidRect -= mTargetOffset;
82
0
    mInvalidRect = mInvalidRect.Intersect(viewport);
83
0
  }
84
0
85
0
  mInvalidateEntireSurface = false;
86
0
  return true;
87
0
}
88
89
static IntRect
90
GetTransformedBounds(Layer* aLayer)
91
0
{
92
0
  IntRect bounds = aLayer->GetLocalVisibleRegion().GetBounds().ToUnknownRect();
93
0
  if (bounds.IsEmpty()) {
94
0
    return bounds;
95
0
  }
96
0
97
0
  const Matrix4x4& transform = aLayer->GetEffectiveTransform();
98
0
  Rect rect = transform.TransformAndClipBounds(Rect(bounds), Rect::MaxIntRect());
99
0
  rect.RoundOut();
100
0
  rect.ToIntRect(&bounds);
101
0
  return bounds;
102
0
}
103
104
/* static */ Maybe<IntRect>
105
ContainerLayerMLGPU::FindVisibleBounds(Layer* aLayer, const Maybe<RenderTargetIntRect>& aClip)
106
0
{
107
0
  AL_LOG("  visiting child %p\n", aLayer);
108
0
  AL_LOG_IF(aClip, "  parent clip: %s\n", Stringify(aClip.value()).c_str());
109
0
110
0
  ContainerLayer* container = aLayer->AsContainerLayer();
111
0
  if (container) {
112
0
    if (container->UseIntermediateSurface()) {
113
0
      container->AsHostLayer()->AsLayerMLGPU()->AsContainerLayerMLGPU()->ComputeIntermediateSurfaceBounds();
114
0
    } else {
115
0
      Maybe<IntRect> accumulated = Some(IntRect());
116
0
117
0
      // Traverse children.
118
0
      for (Layer* child = container->GetFirstChild(); child; child = child->GetNextSibling()) {
119
0
        Maybe<RenderTargetIntRect> clip = aClip;
120
0
        if (const Maybe<ParentLayerIntRect>& childClip = child->AsHostLayer()->GetShadowClipRect()) {
121
0
          RenderTargetIntRect rtChildClip =
122
0
            TransformBy(ViewAs<ParentLayerToRenderTargetMatrix4x4>(
123
0
                          aLayer->GetEffectiveTransform(),
124
0
                          PixelCastJustification::RenderTargetIsParentLayerForRoot),
125
0
                        childClip.value());
126
0
          clip = IntersectMaybeRects(clip, Some(rtChildClip));
127
0
          AL_LOG("    target clip: %s\n", Stringify(rtChildClip).c_str());
128
0
          AL_LOG_IF(clip, "    full clip: %s\n", Stringify(clip.value()).c_str());
129
0
        }
130
0
131
0
        Maybe<IntRect> childBounds = FindVisibleBounds(child, clip);
132
0
        if (!childBounds) {
133
0
          return Nothing();
134
0
        }
135
0
136
0
        accumulated = accumulated->SafeUnion(childBounds.value());
137
0
        if (!accumulated) {
138
0
          return Nothing();
139
0
        }
140
0
      }
141
0
      return accumulated;
142
0
    }
143
0
  }
144
0
145
0
  IntRect bounds = GetTransformedBounds(aLayer);
146
0
  AL_LOG("    layer bounds: %s\n", Stringify(bounds).c_str());
147
0
148
0
  if (aClip) {
149
0
    bounds = bounds.Intersect(aClip.value().ToUnknownRect());
150
0
    AL_LOG("    clipped bounds: %s\n", Stringify(bounds).c_str());
151
0
  }
152
0
  return Some(bounds);
153
0
}
154
155
void
156
ContainerLayerMLGPU::ComputeIntermediateSurfaceBounds()
157
0
{
158
0
  Maybe<IntRect> bounds = Some(IntRect());
159
0
  for (Layer* child = GetFirstChild(); child; child = child->GetNextSibling()) {
160
0
    Maybe<RenderTargetIntRect> clip =
161
0
       ViewAs<RenderTargetPixel>(child->AsHostLayer()->GetShadowClipRect(),
162
0
                                 PixelCastJustification::RenderTargetIsParentLayerForRoot);
163
0
    Maybe<IntRect> childBounds = FindVisibleBounds(child, clip);
164
0
    if (!childBounds) {
165
0
      return;
166
0
    }
167
0
168
0
    bounds = bounds->SafeUnion(childBounds.value());
169
0
    if (!bounds) {
170
0
      return;
171
0
    }
172
0
  }
173
0
174
0
  SetShadowVisibleRegion(LayerIntRect::FromUnknownRect(bounds.value()));
175
0
}
176
177
void
178
ContainerLayerMLGPU::OnLayerManagerChange(LayerManagerMLGPU* aManager)
179
0
{
180
0
  ClearCachedResources();
181
0
}
182
183
RefPtr<MLGRenderTarget>
184
ContainerLayerMLGPU::UpdateRenderTarget(MLGDevice* aDevice, MLGRenderTargetFlags aFlags)
185
0
{
186
0
  if (mRenderTarget) {
187
0
    return mRenderTarget;
188
0
  }
189
0
190
0
  mRenderTarget = aDevice->CreateRenderTarget(mTargetSize, aFlags);
191
0
  if (!mRenderTarget) {
192
0
    gfxWarning() << "Failed to create an intermediate render target for ContainerLayer";
193
0
    return nullptr;
194
0
  }
195
0
196
0
  return mRenderTarget;
197
0
}
198
199
void
200
ContainerLayerMLGPU::SetInvalidCompositeRect(const gfx::IntRect* aRect)
201
0
{
202
0
  // For simplicity we only track the bounds of the invalid area, since regions
203
0
  // are expensive.
204
0
  //
205
0
  // Note we add the bounds to the invalid rect from the last frame, since we
206
0
  // only clear the area that we actually paint. If this overflows we use the
207
0
  // last render target size, since if that changes we'll invalidate everything
208
0
  // anyway.
209
0
  if (aRect) {
210
0
    if (Maybe<gfx::IntRect> result = mInvalidRect.SafeUnion(*aRect)) {
211
0
      mInvalidRect = result.value();
212
0
    } else {
213
0
      mInvalidateEntireSurface = true;
214
0
    }
215
0
  } else {
216
0
    mInvalidateEntireSurface = true;
217
0
  }
218
0
}
219
220
void
221
ContainerLayerMLGPU::ClearCachedResources()
222
0
{
223
0
  mRenderTarget = nullptr;
224
0
}
225
226
bool
227
ContainerLayerMLGPU::IsContentOpaque()
228
0
{
229
0
  if (GetMixBlendMode() != gfx::CompositionOp::OP_OVER) {
230
0
    // We need to read from what's underneath us, so we consider our content to
231
0
    // be not opaque.
232
0
    return false;
233
0
  }
234
0
  return LayerMLGPU::IsContentOpaque();
235
0
}
236
237
const LayerIntRegion&
238
ContainerLayerMLGPU::GetShadowVisibleRegion()
239
0
{
240
0
  if (!UseIntermediateSurface()) {
241
0
    RecomputeShadowVisibleRegionFromChildren();
242
0
  }
243
0
244
0
  return mShadowVisibleRegion;
245
0
}
246
247
const LayerIntRegion&
248
RefLayerMLGPU::GetShadowVisibleRegion()
249
0
{
250
0
  if (!UseIntermediateSurface()) {
251
0
    RecomputeShadowVisibleRegionFromChildren();
252
0
  }
253
0
254
0
  return mShadowVisibleRegion;
255
0
}
256
257
} // namespace layers
258
} // namespace mozilla