gfx/layers/composite/ContainerLayerComposite.cpp

branch
TOR_BUG_9701
changeset 8
97036ab72558
equal deleted inserted replaced
-1:000000000000 0:9f8ee54052ac
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 "ContainerLayerComposite.h"
7 #include <algorithm> // for min
8 #include "FrameMetrics.h" // for FrameMetrics
9 #include "Units.h" // for LayerRect, LayerPixel, etc
10 #include "gfx2DGlue.h" // for ToMatrix4x4
11 #include "gfx3DMatrix.h" // for gfx3DMatrix
12 #include "gfxPrefs.h" // for gfxPrefs
13 #include "gfxUtils.h" // for gfxUtils, etc
14 #include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
15 #include "mozilla/RefPtr.h" // for RefPtr
16 #include "mozilla/gfx/BaseRect.h" // for BaseRect
17 #include "mozilla/gfx/Matrix.h" // for Matrix4x4
18 #include "mozilla/gfx/Point.h" // for Point, IntPoint
19 #include "mozilla/gfx/Rect.h" // for IntRect, Rect
20 #include "mozilla/layers/Compositor.h" // for Compositor, etc
21 #include "mozilla/layers/CompositorTypes.h" // for DIAGNOSTIC_CONTAINER
22 #include "mozilla/layers/Effects.h" // for Effect, EffectChain, etc
23 #include "mozilla/layers/TextureHost.h" // for CompositingRenderTarget
24 #include "mozilla/mozalloc.h" // for operator delete, etc
25 #include "nsAutoPtr.h" // for nsRefPtr
26 #include "nsDebug.h" // for NS_ASSERTION
27 #include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc
28 #include "nsISupportsUtils.h" // for NS_ADDREF, NS_RELEASE
29 #include "nsPoint.h" // for nsIntPoint
30 #include "nsRect.h" // for nsIntRect
31 #include "nsRegion.h" // for nsIntRegion
32 #include "nsTArray.h" // for nsAutoTArray
33 #include "TextRenderer.h" // for TextRenderer
34 #include <vector>
35
36 namespace mozilla {
37 namespace layers {
38
39 /**
40 * Returns a rectangle of content painted opaquely by aLayer. Very consertative;
41 * bails by returning an empty rect in any tricky situations.
42 */
43 static nsIntRect
44 GetOpaqueRect(Layer* aLayer)
45 {
46 nsIntRect result;
47 gfx::Matrix matrix;
48 bool is2D = aLayer->GetBaseTransform().Is2D(&matrix);
49
50 // Just bail if there's anything difficult to handle.
51 if (!is2D || aLayer->GetMaskLayer() ||
52 aLayer->GetEffectiveOpacity() != 1.0f ||
53 matrix.HasNonIntegerTranslation()) {
54 return result;
55 }
56
57 if (aLayer->GetContentFlags() & Layer::CONTENT_OPAQUE) {
58 result = aLayer->GetEffectiveVisibleRegion().GetLargestRectangle();
59 } else {
60 // Drill down into RefLayers because that's what we particularly care about;
61 // layer construction for aLayer will not have known about the opaqueness
62 // of any RefLayer subtrees.
63 RefLayer* refLayer = aLayer->AsRefLayer();
64 if (refLayer && refLayer->GetFirstChild()) {
65 result = GetOpaqueRect(refLayer->GetFirstChild());
66 }
67 }
68
69 // Translate our opaque region to cover the child
70 gfx::Point point = matrix.GetTranslation();
71 result.MoveBy(static_cast<int>(point.x), static_cast<int>(point.y));
72
73 const nsIntRect* clipRect = aLayer->GetEffectiveClipRect();
74 if (clipRect) {
75 result.IntersectRect(result, *clipRect);
76 }
77
78 return result;
79 }
80
81 struct LayerVelocityUserData : public LayerUserData {
82 public:
83 LayerVelocityUserData() {
84 MOZ_COUNT_CTOR(LayerVelocityUserData);
85 }
86 ~LayerVelocityUserData() {
87 MOZ_COUNT_DTOR(LayerVelocityUserData);
88 }
89
90 struct VelocityData {
91 VelocityData(TimeStamp frameTime, int scrollX, int scrollY)
92 : mFrameTime(frameTime)
93 , mPoint(scrollX, scrollY)
94 {}
95
96 TimeStamp mFrameTime;
97 gfx::Point mPoint;
98 };
99 std::vector<VelocityData> mData;
100 };
101
102 static gfx::Point GetScrollData(Layer* aLayer) {
103 gfx::Matrix matrix;
104 if (aLayer->GetLocalTransform().Is2D(&matrix)) {
105 return matrix.GetTranslation();
106 }
107
108 gfx::Point origin;
109 return origin;
110 }
111
112 static void DrawLayerInfo(const nsIntRect& aClipRect,
113 LayerManagerComposite* aManager,
114 Layer* aLayer)
115 {
116
117 if (aLayer->GetType() == Layer::LayerType::TYPE_CONTAINER) {
118 // XXX - should figure out a way to render this, but for now this
119 // is hard to do, since it will often get superimposed over the first
120 // child of the layer, which is bad.
121 return;
122 }
123
124 nsAutoCString layerInfo;
125 aLayer->PrintInfo(layerInfo, "");
126
127 nsIntRegion visibleRegion = aLayer->GetVisibleRegion();
128
129 uint32_t maxWidth = std::min<uint32_t>(visibleRegion.GetBounds().width, 500);
130
131 nsIntPoint topLeft = visibleRegion.GetBounds().TopLeft();
132 aManager->GetTextRenderer()->RenderText(layerInfo.get(), gfx::IntPoint(topLeft.x, topLeft.y),
133 aLayer->GetEffectiveTransform(), 16,
134 maxWidth);
135
136 }
137
138 static LayerVelocityUserData* GetVelocityData(Layer* aLayer) {
139 static char sLayerVelocityUserDataKey;
140 void* key = reinterpret_cast<void*>(&sLayerVelocityUserDataKey);
141 if (!aLayer->HasUserData(key)) {
142 LayerVelocityUserData* newData = new LayerVelocityUserData();
143 aLayer->SetUserData(key, newData);
144 }
145
146 return static_cast<LayerVelocityUserData*>(aLayer->GetUserData(key));
147 }
148
149 static void DrawVelGraph(const nsIntRect& aClipRect,
150 LayerManagerComposite* aManager,
151 Layer* aLayer) {
152 Compositor* compositor = aManager->GetCompositor();
153 gfx::Rect clipRect(aClipRect.x, aClipRect.y,
154 aClipRect.width, aClipRect.height);
155
156 TimeStamp now = TimeStamp::Now();
157 LayerVelocityUserData* velocityData = GetVelocityData(aLayer);
158
159 if (velocityData->mData.size() >= 1 &&
160 now > velocityData->mData[velocityData->mData.size() - 1].mFrameTime +
161 TimeDuration::FromMilliseconds(200)) {
162 // clear stale data
163 velocityData->mData.clear();
164 }
165
166 const gfx::Point layerTransform = GetScrollData(aLayer);
167 velocityData->mData.push_back(
168 LayerVelocityUserData::VelocityData(now,
169 static_cast<int>(layerTransform.x), static_cast<int>(layerTransform.y)));
170
171 // TODO: dump to file
172 // XXX: Uncomment these lines to enable ScrollGraph logging. This is
173 // useful for HVGA phones or to output the data to accurate
174 // graphing software.
175 // printf_stderr("ScrollGraph (%p): %f, %f\n",
176 // aLayer, layerTransform.x, layerTransform.y);
177
178 // Keep a circular buffer of 100.
179 size_t circularBufferSize = 100;
180 if (velocityData->mData.size() > circularBufferSize) {
181 velocityData->mData.erase(velocityData->mData.begin());
182 }
183
184 if (velocityData->mData.size() == 1) {
185 return;
186 }
187
188 // Clear and disable the graph when it's flat
189 for (size_t i = 1; i < velocityData->mData.size(); i++) {
190 if (velocityData->mData[i - 1].mPoint != velocityData->mData[i].mPoint) {
191 break;
192 }
193 if (i == velocityData->mData.size() - 1) {
194 velocityData->mData.clear();
195 return;
196 }
197 }
198
199 if (aLayer->GetEffectiveVisibleRegion().GetBounds().width < 300 ||
200 aLayer->GetEffectiveVisibleRegion().GetBounds().height < 300) {
201 // Don't want a graph for smaller layers
202 return;
203 }
204
205 aManager->SetDebugOverlayWantsNextFrame(true);
206
207 const gfx::Matrix4x4& transform = aLayer->GetEffectiveTransform();
208 nsIntRect bounds = aLayer->GetEffectiveVisibleRegion().GetBounds();
209 gfx::Rect graphBounds = gfx::Rect(bounds.x, bounds.y,
210 bounds.width, bounds.height);
211 gfx::Rect graphRect = gfx::Rect(bounds.x, bounds.y, 200, 100);
212
213 float opacity = 1.0;
214 EffectChain effects;
215 effects.mPrimaryEffect = new EffectSolidColor(gfx::Color(0.2f,0,0,1));
216 compositor->DrawQuad(graphRect,
217 clipRect,
218 effects,
219 opacity,
220 transform);
221
222 std::vector<gfx::Point> graph;
223 int yScaleFactor = 3;
224 for (int32_t i = (int32_t)velocityData->mData.size() - 2; i >= 0; i--) {
225 const gfx::Point& p1 = velocityData->mData[i+1].mPoint;
226 const gfx::Point& p2 = velocityData->mData[i].mPoint;
227 int vel = sqrt((p1.x - p2.x) * (p1.x - p2.x) +
228 (p1.y - p2.y) * (p1.y - p2.y));
229 graph.push_back(
230 gfx::Point(bounds.x + graphRect.width / circularBufferSize * i,
231 graphBounds.y + graphRect.height - vel/yScaleFactor));
232 }
233
234 compositor->DrawLines(graph, clipRect, gfx::Color(0,1,0,1),
235 opacity, transform);
236 }
237
238 // ContainerRender is shared between RefLayer and ContainerLayer
239 template<class ContainerT> void
240 ContainerRender(ContainerT* aContainer,
241 LayerManagerComposite* aManager,
242 const nsIntRect& aClipRect)
243 {
244 /**
245 * Setup our temporary surface for rendering the contents of this container.
246 */
247 RefPtr<CompositingRenderTarget> surface;
248
249 Compositor* compositor = aManager->GetCompositor();
250
251 RefPtr<CompositingRenderTarget> previousTarget = compositor->GetCurrentRenderTarget();
252
253 nsIntRect visibleRect = aContainer->GetEffectiveVisibleRegion().GetBounds();
254
255 aContainer->mSupportsComponentAlphaChildren = false;
256
257 float opacity = aContainer->GetEffectiveOpacity();
258
259 bool needsSurface = aContainer->UseIntermediateSurface();
260 if (needsSurface) {
261 SurfaceInitMode mode = INIT_MODE_CLEAR;
262 bool surfaceCopyNeeded = false;
263 gfx::IntRect surfaceRect = gfx::IntRect(visibleRect.x, visibleRect.y,
264 visibleRect.width, visibleRect.height);
265 gfx::IntPoint sourcePoint = gfx::IntPoint(visibleRect.x, visibleRect.y);
266 // we're about to create a framebuffer backed by textures to use as an intermediate
267 // surface. What to do if its size (as given by framebufferRect) would exceed the
268 // maximum texture size supported by the GL? The present code chooses the compromise
269 // of just clamping the framebuffer's size to the max supported size.
270 // This gives us a lower resolution rendering of the intermediate surface (children layers).
271 // See bug 827170 for a discussion.
272 int32_t maxTextureSize = compositor->GetMaxTextureSize();
273 surfaceRect.width = std::min(maxTextureSize, surfaceRect.width);
274 surfaceRect.height = std::min(maxTextureSize, surfaceRect.height);
275 if (aContainer->GetEffectiveVisibleRegion().GetNumRects() == 1 &&
276 (aContainer->GetContentFlags() & Layer::CONTENT_OPAQUE))
277 {
278 // don't need a background, we're going to paint all opaque stuff
279 aContainer->mSupportsComponentAlphaChildren = true;
280 mode = INIT_MODE_NONE;
281 } else {
282 const gfx::Matrix4x4& transform3D = aContainer->GetEffectiveTransform();
283 gfx::Matrix transform;
284 // If we have an opaque ancestor layer, then we can be sure that
285 // all the pixels we draw into are either opaque already or will be
286 // covered by something opaque. Otherwise copying up the background is
287 // not safe.
288 if (ContainerLayer::HasOpaqueAncestorLayer(aContainer) &&
289 transform3D.Is2D(&transform) && !ThebesMatrix(transform).HasNonIntegerTranslation()) {
290 surfaceCopyNeeded = gfxPrefs::ComponentAlphaEnabled();
291 sourcePoint.x += transform._31;
292 sourcePoint.y += transform._32;
293 aContainer->mSupportsComponentAlphaChildren
294 = gfxPrefs::ComponentAlphaEnabled();
295 }
296 }
297
298 sourcePoint -= compositor->GetCurrentRenderTarget()->GetOrigin();
299 if (surfaceCopyNeeded) {
300 surface = compositor->CreateRenderTargetFromSource(surfaceRect, previousTarget, sourcePoint);
301 } else {
302 surface = compositor->CreateRenderTarget(surfaceRect, mode);
303 }
304
305 if (!surface) {
306 return;
307 }
308
309 compositor->SetRenderTarget(surface);
310 } else {
311 surface = previousTarget;
312 aContainer->mSupportsComponentAlphaChildren = (aContainer->GetContentFlags() & Layer::CONTENT_OPAQUE) ||
313 (aContainer->GetParent() && aContainer->GetParent()->SupportsComponentAlphaChildren());
314 }
315
316 nsAutoTArray<Layer*, 12> children;
317 aContainer->SortChildrenBy3DZOrder(children);
318
319 /**
320 * Render this container's contents.
321 */
322 for (uint32_t i = 0; i < children.Length(); i++) {
323 LayerComposite* layerToRender = static_cast<LayerComposite*>(children.ElementAt(i)->ImplData());
324
325 if (layerToRender->GetLayer()->GetEffectiveVisibleRegion().IsEmpty() &&
326 !layerToRender->GetLayer()->AsContainerLayer()) {
327 continue;
328 }
329
330 nsIntRect clipRect = layerToRender->GetLayer()->
331 CalculateScissorRect(aClipRect, &aManager->GetWorldTransform());
332 if (clipRect.IsEmpty()) {
333 continue;
334 }
335
336 nsIntRegion savedVisibleRegion;
337 bool restoreVisibleRegion = false;
338 if (i + 1 < children.Length() &&
339 layerToRender->GetLayer()->GetEffectiveTransform().IsIdentity()) {
340 LayerComposite* nextLayer = static_cast<LayerComposite*>(children.ElementAt(i + 1)->ImplData());
341 nsIntRect nextLayerOpaqueRect;
342 if (nextLayer && nextLayer->GetLayer()) {
343 nextLayerOpaqueRect = GetOpaqueRect(nextLayer->GetLayer());
344 }
345 if (!nextLayerOpaqueRect.IsEmpty()) {
346 savedVisibleRegion = layerToRender->GetShadowVisibleRegion();
347 nsIntRegion visibleRegion;
348 visibleRegion.Sub(savedVisibleRegion, nextLayerOpaqueRect);
349 if (visibleRegion.IsEmpty()) {
350 continue;
351 }
352 layerToRender->SetShadowVisibleRegion(visibleRegion);
353 restoreVisibleRegion = true;
354 }
355 }
356
357 if (layerToRender->HasLayerBeenComposited()) {
358 // Composer2D will compose this layer so skip GPU composition
359 // this time & reset composition flag for next composition phase
360 layerToRender->SetLayerComposited(false);
361 nsIntRect clearRect = layerToRender->GetClearRect();
362 if (!clearRect.IsEmpty()) {
363 // Clear layer's visible rect on FrameBuffer with transparent pixels
364 gfx::Rect fbRect(clearRect.x, clearRect.y, clearRect.width, clearRect.height);
365 compositor->ClearRect(fbRect);
366 layerToRender->SetClearRect(nsIntRect(0, 0, 0, 0));
367 }
368 } else {
369 layerToRender->RenderLayer(clipRect);
370 }
371
372 if (restoreVisibleRegion) {
373 // Restore the region in case it's not covered by opaque content next time
374 layerToRender->SetShadowVisibleRegion(savedVisibleRegion);
375 }
376
377 if (gfxPrefs::LayersScrollGraph()) {
378 DrawVelGraph(clipRect, aManager, layerToRender->GetLayer());
379 }
380
381 if (gfxPrefs::DrawLayerInfo()) {
382 DrawLayerInfo(clipRect, aManager, layerToRender->GetLayer());
383 }
384 // invariant: our GL context should be current here, I don't think we can
385 // assert it though
386 }
387
388 if (needsSurface) {
389 // Unbind the current surface and rebind the previous one.
390 #ifdef MOZ_DUMP_PAINTING
391 if (gfxUtils::sDumpPainting) {
392 RefPtr<gfx::DataSourceSurface> surf = surface->Dump(aManager->GetCompositor());
393 WriteSnapshotToDumpFile(aContainer, surf);
394 }
395 #endif
396
397 compositor->SetRenderTarget(previousTarget);
398 EffectChain effectChain(aContainer);
399 LayerManagerComposite::AutoAddMaskEffect autoMaskEffect(aContainer->GetMaskLayer(),
400 effectChain,
401 !aContainer->GetTransform().CanDraw2D());
402
403 effectChain.mPrimaryEffect = new EffectRenderTarget(surface);
404
405 gfx::Rect rect(visibleRect.x, visibleRect.y, visibleRect.width, visibleRect.height);
406 gfx::Rect clipRect(aClipRect.x, aClipRect.y, aClipRect.width, aClipRect.height);
407 aManager->GetCompositor()->DrawQuad(rect, clipRect, effectChain, opacity,
408 aContainer->GetEffectiveTransform());
409 }
410
411 if (aContainer->GetFrameMetrics().IsScrollable()) {
412 const FrameMetrics& frame = aContainer->GetFrameMetrics();
413 LayerRect layerBounds = ParentLayerRect(frame.mCompositionBounds) * ParentLayerToLayerScale(1.0);
414 gfx::Rect rect(layerBounds.x, layerBounds.y, layerBounds.width, layerBounds.height);
415 gfx::Rect clipRect(aClipRect.x, aClipRect.y, aClipRect.width, aClipRect.height);
416 aManager->GetCompositor()->DrawDiagnostics(DIAGNOSTIC_CONTAINER,
417 rect, clipRect,
418 aContainer->GetEffectiveTransform());
419 }
420 }
421
422 ContainerLayerComposite::ContainerLayerComposite(LayerManagerComposite *aManager)
423 : ContainerLayer(aManager, nullptr)
424 , LayerComposite(aManager)
425 {
426 MOZ_COUNT_CTOR(ContainerLayerComposite);
427 mImplData = static_cast<LayerComposite*>(this);
428 }
429
430 ContainerLayerComposite::~ContainerLayerComposite()
431 {
432 MOZ_COUNT_DTOR(ContainerLayerComposite);
433
434 // We don't Destroy() on destruction here because this destructor
435 // can be called after remote content has crashed, and it may not be
436 // safe to free the IPC resources of our children. Those resources
437 // are automatically cleaned up by IPDL-generated code.
438 //
439 // In the common case of normal shutdown, either
440 // LayerManagerComposite::Destroy(), a parent
441 // *ContainerLayerComposite::Destroy(), or Disconnect() will trigger
442 // cleanup of our resources.
443 while (mFirstChild) {
444 RemoveChild(mFirstChild);
445 }
446 }
447
448 void
449 ContainerLayerComposite::Destroy()
450 {
451 if (!mDestroyed) {
452 while (mFirstChild) {
453 static_cast<LayerComposite*>(GetFirstChild()->ImplData())->Destroy();
454 RemoveChild(mFirstChild);
455 }
456 mDestroyed = true;
457 }
458 }
459
460 LayerComposite*
461 ContainerLayerComposite::GetFirstChildComposite()
462 {
463 if (!mFirstChild) {
464 return nullptr;
465 }
466 return static_cast<LayerComposite*>(mFirstChild->ImplData());
467 }
468
469 void
470 ContainerLayerComposite::RenderLayer(const nsIntRect& aClipRect)
471 {
472 ContainerRender(this, mCompositeManager, aClipRect);
473 }
474
475 void
476 ContainerLayerComposite::CleanupResources()
477 {
478 for (Layer* l = GetFirstChild(); l; l = l->GetNextSibling()) {
479 LayerComposite* layerToCleanup = static_cast<LayerComposite*>(l->ImplData());
480 layerToCleanup->CleanupResources();
481 }
482 }
483
484 RefLayerComposite::RefLayerComposite(LayerManagerComposite* aManager)
485 : RefLayer(aManager, nullptr)
486 , LayerComposite(aManager)
487 {
488 mImplData = static_cast<LayerComposite*>(this);
489 }
490
491 RefLayerComposite::~RefLayerComposite()
492 {
493 Destroy();
494 }
495
496 void
497 RefLayerComposite::Destroy()
498 {
499 MOZ_ASSERT(!mFirstChild);
500 mDestroyed = true;
501 }
502
503 LayerComposite*
504 RefLayerComposite::GetFirstChildComposite()
505 {
506 if (!mFirstChild) {
507 return nullptr;
508 }
509 return static_cast<LayerComposite*>(mFirstChild->ImplData());
510 }
511
512 void
513 RefLayerComposite::RenderLayer(const nsIntRect& aClipRect)
514 {
515 ContainerRender(this, mCompositeManager, aClipRect);
516 }
517
518 void
519 RefLayerComposite::CleanupResources()
520 {
521 }
522
523 } /* layers */
524 } /* mozilla */

mercurial