gfx/layers/composite/LayerManagerComposite.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

michael@0 1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #include "LayerManagerComposite.h"
michael@0 7 #include <stddef.h> // for size_t
michael@0 8 #include <stdint.h> // for uint16_t, uint32_t
michael@0 9 #include "CanvasLayerComposite.h" // for CanvasLayerComposite
michael@0 10 #include "ColorLayerComposite.h" // for ColorLayerComposite
michael@0 11 #include "Composer2D.h" // for Composer2D
michael@0 12 #include "CompositableHost.h" // for CompositableHost
michael@0 13 #include "ContainerLayerComposite.h" // for ContainerLayerComposite, etc
michael@0 14 #include "FPSCounter.h" // for FPSState, FPSCounter
michael@0 15 #include "FrameMetrics.h" // for FrameMetrics
michael@0 16 #include "GeckoProfiler.h" // for profiler_set_frame_number, etc
michael@0 17 #include "ImageLayerComposite.h" // for ImageLayerComposite
michael@0 18 #include "Layers.h" // for Layer, ContainerLayer, etc
michael@0 19 #include "ThebesLayerComposite.h" // for ThebesLayerComposite
michael@0 20 #include "TiledLayerBuffer.h" // for TiledLayerComposer
michael@0 21 #include "Units.h" // for ScreenIntRect
michael@0 22 #include "gfx2DGlue.h" // for ToMatrix4x4
michael@0 23 #include "gfx3DMatrix.h" // for gfx3DMatrix
michael@0 24 #include "gfxPrefs.h" // for gfxPrefs
michael@0 25 #ifdef XP_MACOSX
michael@0 26 #include "gfxPlatformMac.h"
michael@0 27 #endif
michael@0 28 #include "gfxRect.h" // for gfxRect
michael@0 29 #include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
michael@0 30 #include "mozilla/RefPtr.h" // for RefPtr, TemporaryRef
michael@0 31 #include "mozilla/gfx/2D.h" // for DrawTarget
michael@0 32 #include "mozilla/gfx/Matrix.h" // for Matrix4x4
michael@0 33 #include "mozilla/gfx/Point.h" // for IntSize, Point
michael@0 34 #include "mozilla/gfx/Rect.h" // for Rect
michael@0 35 #include "mozilla/gfx/Types.h" // for Color, SurfaceFormat
michael@0 36 #include "mozilla/layers/Compositor.h" // for Compositor
michael@0 37 #include "mozilla/layers/CompositorTypes.h"
michael@0 38 #include "mozilla/layers/Effects.h" // for Effect, EffectChain, etc
michael@0 39 #include "mozilla/layers/LayersTypes.h" // for etc
michael@0 40 #include "ipc/ShadowLayerUtils.h"
michael@0 41 #include "mozilla/mozalloc.h" // for operator new, etc
michael@0 42 #include "nsAutoPtr.h" // for nsRefPtr
michael@0 43 #include "nsCOMPtr.h" // for already_AddRefed
michael@0 44 #include "nsDebug.h" // for NS_WARNING, NS_RUNTIMEABORT, etc
michael@0 45 #include "nsISupportsImpl.h" // for Layer::AddRef, etc
michael@0 46 #include "nsIWidget.h" // for nsIWidget
michael@0 47 #include "nsPoint.h" // for nsIntPoint
michael@0 48 #include "nsRect.h" // for nsIntRect
michael@0 49 #include "nsRegion.h" // for nsIntRegion, etc
michael@0 50 #ifdef MOZ_WIDGET_ANDROID
michael@0 51 #include <android/log.h>
michael@0 52 #endif
michael@0 53 #include "GeckoProfiler.h"
michael@0 54 #include "TextRenderer.h" // for TextRenderer
michael@0 55
michael@0 56 class gfxContext;
michael@0 57 struct nsIntSize;
michael@0 58
michael@0 59
michael@0 60 namespace mozilla {
michael@0 61 namespace layers {
michael@0 62
michael@0 63 class ImageLayer;
michael@0 64
michael@0 65 using namespace mozilla::gfx;
michael@0 66 using namespace mozilla::gl;
michael@0 67
michael@0 68 static LayerComposite*
michael@0 69 ToLayerComposite(Layer* aLayer)
michael@0 70 {
michael@0 71 return static_cast<LayerComposite*>(aLayer->ImplData());
michael@0 72 }
michael@0 73
michael@0 74 static void ClearSubtree(Layer* aLayer)
michael@0 75 {
michael@0 76 ToLayerComposite(aLayer)->CleanupResources();
michael@0 77 for (Layer* child = aLayer->GetFirstChild(); child;
michael@0 78 child = child->GetNextSibling()) {
michael@0 79 ClearSubtree(child);
michael@0 80 }
michael@0 81 }
michael@0 82
michael@0 83 void
michael@0 84 LayerManagerComposite::ClearCachedResources(Layer* aSubtree)
michael@0 85 {
michael@0 86 MOZ_ASSERT(!aSubtree || aSubtree->Manager() == this);
michael@0 87 Layer* subtree = aSubtree ? aSubtree : mRoot.get();
michael@0 88 if (!subtree) {
michael@0 89 return;
michael@0 90 }
michael@0 91
michael@0 92 ClearSubtree(subtree);
michael@0 93 // FIXME [bjacob]
michael@0 94 // XXX the old LayerManagerOGL code had a mMaybeInvalidTree that it set to true here.
michael@0 95 // Do we need that?
michael@0 96 }
michael@0 97
michael@0 98 /**
michael@0 99 * LayerManagerComposite
michael@0 100 */
michael@0 101 LayerManagerComposite::LayerManagerComposite(Compositor* aCompositor)
michael@0 102 : mCompositor(aCompositor)
michael@0 103 , mInTransaction(false)
michael@0 104 , mIsCompositorReady(false)
michael@0 105 , mDebugOverlayWantsNextFrame(false)
michael@0 106 , mGeometryChanged(true)
michael@0 107 {
michael@0 108 mTextRenderer = new TextRenderer(aCompositor);
michael@0 109 MOZ_ASSERT(aCompositor);
michael@0 110 }
michael@0 111
michael@0 112 LayerManagerComposite::~LayerManagerComposite()
michael@0 113 {
michael@0 114 Destroy();
michael@0 115 }
michael@0 116
michael@0 117
michael@0 118 bool
michael@0 119 LayerManagerComposite::Initialize()
michael@0 120 {
michael@0 121 bool result = mCompositor->Initialize();
michael@0 122 return result;
michael@0 123 }
michael@0 124
michael@0 125 void
michael@0 126 LayerManagerComposite::Destroy()
michael@0 127 {
michael@0 128 if (!mDestroyed) {
michael@0 129 mCompositor->GetWidget()->CleanupWindowEffects();
michael@0 130 if (mRoot) {
michael@0 131 RootLayer()->Destroy();
michael@0 132 }
michael@0 133 mRoot = nullptr;
michael@0 134
michael@0 135 mCompositor->Destroy();
michael@0 136
michael@0 137 mDestroyed = true;
michael@0 138 }
michael@0 139 }
michael@0 140
michael@0 141 void
michael@0 142 LayerManagerComposite::UpdateRenderBounds(const nsIntRect& aRect)
michael@0 143 {
michael@0 144 mRenderBounds = aRect;
michael@0 145 }
michael@0 146
michael@0 147 void
michael@0 148 LayerManagerComposite::BeginTransaction()
michael@0 149 {
michael@0 150 mInTransaction = true;
michael@0 151
michael@0 152 if (!mCompositor->Ready()) {
michael@0 153 return;
michael@0 154 }
michael@0 155
michael@0 156 mIsCompositorReady = true;
michael@0 157
michael@0 158 if (Compositor::GetBackend() == LayersBackend::LAYERS_OPENGL ||
michael@0 159 Compositor::GetBackend() == LayersBackend::LAYERS_BASIC) {
michael@0 160 mClonedLayerTreeProperties = LayerProperties::CloneFrom(GetRoot());
michael@0 161 }
michael@0 162 }
michael@0 163
michael@0 164 void
michael@0 165 LayerManagerComposite::BeginTransactionWithDrawTarget(DrawTarget* aTarget)
michael@0 166 {
michael@0 167 mInTransaction = true;
michael@0 168
michael@0 169 if (!mCompositor->Ready()) {
michael@0 170 return;
michael@0 171 }
michael@0 172
michael@0 173 #ifdef MOZ_LAYERS_HAVE_LOG
michael@0 174 MOZ_LAYERS_LOG(("[----- BeginTransaction"));
michael@0 175 Log();
michael@0 176 #endif
michael@0 177
michael@0 178 if (mDestroyed) {
michael@0 179 NS_WARNING("Call on destroyed layer manager");
michael@0 180 return;
michael@0 181 }
michael@0 182
michael@0 183 mIsCompositorReady = true;
michael@0 184 mCompositor->SetTargetContext(aTarget);
michael@0 185 mTarget = aTarget;
michael@0 186 }
michael@0 187
michael@0 188 bool
michael@0 189 LayerManagerComposite::EndEmptyTransaction(EndTransactionFlags aFlags)
michael@0 190 {
michael@0 191 NS_ASSERTION(mInTransaction, "Didn't call BeginTransaction?");
michael@0 192 if (!mRoot) {
michael@0 193 mInTransaction = false;
michael@0 194 mIsCompositorReady = false;
michael@0 195 return false;
michael@0 196 }
michael@0 197
michael@0 198 EndTransaction(nullptr, nullptr);
michael@0 199 return true;
michael@0 200 }
michael@0 201
michael@0 202 void
michael@0 203 LayerManagerComposite::EndTransaction(DrawThebesLayerCallback aCallback,
michael@0 204 void* aCallbackData,
michael@0 205 EndTransactionFlags aFlags)
michael@0 206 {
michael@0 207 NS_ASSERTION(mInTransaction, "Didn't call BeginTransaction?");
michael@0 208 NS_ASSERTION(!aCallback && !aCallbackData, "Not expecting callbacks here");
michael@0 209 mInTransaction = false;
michael@0 210
michael@0 211 if (!mIsCompositorReady) {
michael@0 212 return;
michael@0 213 }
michael@0 214 mIsCompositorReady = false;
michael@0 215
michael@0 216 #ifdef MOZ_LAYERS_HAVE_LOG
michael@0 217 MOZ_LAYERS_LOG((" ----- (beginning paint)"));
michael@0 218 Log();
michael@0 219 #endif
michael@0 220
michael@0 221 if (mDestroyed) {
michael@0 222 NS_WARNING("Call on destroyed layer manager");
michael@0 223 return;
michael@0 224 }
michael@0 225
michael@0 226 if (mRoot && mClonedLayerTreeProperties) {
michael@0 227 nsIntRegion invalid =
michael@0 228 mClonedLayerTreeProperties->ComputeDifferences(mRoot, nullptr, &mGeometryChanged);
michael@0 229 mClonedLayerTreeProperties = nullptr;
michael@0 230
michael@0 231 mInvalidRegion.Or(mInvalidRegion, invalid);
michael@0 232 } else {
michael@0 233 mInvalidRegion.Or(mInvalidRegion, mRenderBounds);
michael@0 234 }
michael@0 235
michael@0 236 if (mRoot && !(aFlags & END_NO_IMMEDIATE_REDRAW)) {
michael@0 237 if (aFlags & END_NO_COMPOSITE) {
michael@0 238 // Apply pending tree updates before recomputing effective
michael@0 239 // properties.
michael@0 240 mRoot->ApplyPendingUpdatesToSubtree();
michael@0 241 }
michael@0 242
michael@0 243 // The results of our drawing always go directly into a pixel buffer,
michael@0 244 // so we don't need to pass any global transform here.
michael@0 245 mRoot->ComputeEffectiveTransforms(gfx::Matrix4x4());
michael@0 246
michael@0 247 Render();
michael@0 248 mGeometryChanged = false;
michael@0 249 }
michael@0 250
michael@0 251 mCompositor->SetTargetContext(nullptr);
michael@0 252 mTarget = nullptr;
michael@0 253
michael@0 254 #ifdef MOZ_LAYERS_HAVE_LOG
michael@0 255 Log();
michael@0 256 MOZ_LAYERS_LOG(("]----- EndTransaction"));
michael@0 257 #endif
michael@0 258 }
michael@0 259
michael@0 260 TemporaryRef<DrawTarget>
michael@0 261 LayerManagerComposite::CreateOptimalMaskDrawTarget(const IntSize &aSize)
michael@0 262 {
michael@0 263 NS_RUNTIMEABORT("Should only be called on the drawing side");
michael@0 264 return nullptr;
michael@0 265 }
michael@0 266
michael@0 267 already_AddRefed<ThebesLayer>
michael@0 268 LayerManagerComposite::CreateThebesLayer()
michael@0 269 {
michael@0 270 NS_RUNTIMEABORT("Should only be called on the drawing side");
michael@0 271 return nullptr;
michael@0 272 }
michael@0 273
michael@0 274 already_AddRefed<ContainerLayer>
michael@0 275 LayerManagerComposite::CreateContainerLayer()
michael@0 276 {
michael@0 277 NS_RUNTIMEABORT("Should only be called on the drawing side");
michael@0 278 return nullptr;
michael@0 279 }
michael@0 280
michael@0 281 already_AddRefed<ImageLayer>
michael@0 282 LayerManagerComposite::CreateImageLayer()
michael@0 283 {
michael@0 284 NS_RUNTIMEABORT("Should only be called on the drawing side");
michael@0 285 return nullptr;
michael@0 286 }
michael@0 287
michael@0 288 already_AddRefed<ColorLayer>
michael@0 289 LayerManagerComposite::CreateColorLayer()
michael@0 290 {
michael@0 291 NS_RUNTIMEABORT("Should only be called on the drawing side");
michael@0 292 return nullptr;
michael@0 293 }
michael@0 294
michael@0 295 already_AddRefed<CanvasLayer>
michael@0 296 LayerManagerComposite::CreateCanvasLayer()
michael@0 297 {
michael@0 298 NS_RUNTIMEABORT("Should only be called on the drawing side");
michael@0 299 return nullptr;
michael@0 300 }
michael@0 301
michael@0 302 LayerComposite*
michael@0 303 LayerManagerComposite::RootLayer() const
michael@0 304 {
michael@0 305 if (mDestroyed) {
michael@0 306 NS_WARNING("Call on destroyed layer manager");
michael@0 307 return nullptr;
michael@0 308 }
michael@0 309
michael@0 310 return ToLayerComposite(mRoot);
michael@0 311 }
michael@0 312
michael@0 313 // Size of the builtin font.
michael@0 314 static const float FontHeight = 7.f;
michael@0 315 static const float FontWidth = 4.f;
michael@0 316 static const float FontStride = 4.f;
michael@0 317
michael@0 318 // Scale the font when drawing it to the viewport for better readability.
michael@0 319 static const float FontScaleX = 2.f;
michael@0 320 static const float FontScaleY = 3.f;
michael@0 321
michael@0 322 static void DrawDigits(unsigned int aValue,
michael@0 323 int aOffsetX, int aOffsetY,
michael@0 324 Compositor* aCompositor,
michael@0 325 EffectChain& aEffectChain)
michael@0 326 {
michael@0 327 if (aValue > 999) {
michael@0 328 aValue = 999;
michael@0 329 }
michael@0 330
michael@0 331 unsigned int divisor = 100;
michael@0 332 float textureWidth = FontWidth * 10;
michael@0 333 gfx::Float opacity = 1;
michael@0 334 gfx::Matrix4x4 transform;
michael@0 335 transform.Scale(FontScaleX, FontScaleY, 1);
michael@0 336
michael@0 337 for (size_t n = 0; n < 3; ++n) {
michael@0 338 unsigned int digit = aValue % (divisor * 10) / divisor;
michael@0 339 divisor /= 10;
michael@0 340
michael@0 341 RefPtr<TexturedEffect> texturedEffect = static_cast<TexturedEffect*>(aEffectChain.mPrimaryEffect.get());
michael@0 342 texturedEffect->mTextureCoords = Rect(float(digit * FontWidth) / textureWidth, 0, FontWidth / textureWidth, 1.0f);
michael@0 343
michael@0 344 Rect drawRect = Rect(aOffsetX + n * FontWidth, aOffsetY, FontWidth, FontHeight);
michael@0 345 Rect clipRect = Rect(0, 0, 300, 100);
michael@0 346 aCompositor->DrawQuad(drawRect, clipRect,
michael@0 347 aEffectChain, opacity, transform);
michael@0 348 }
michael@0 349 }
michael@0 350
michael@0 351 void FPSState::DrawFPS(TimeStamp aNow,
michael@0 352 unsigned int aFillRatio,
michael@0 353 Compositor* aCompositor)
michael@0 354 {
michael@0 355 if (!mFPSTextureSource) {
michael@0 356 const char *text =
michael@0 357 " "
michael@0 358 " XXX XX XXX XXX X X XXX XXX XXX XXX XXX"
michael@0 359 " X X X X X X X X X X X X X X"
michael@0 360 " X X X XXX XXX XXX XXX XXX X XXX XXX"
michael@0 361 " X X X X X X X X X X X X X"
michael@0 362 " XXX XXX XXX XXX X XXX XXX X XXX X"
michael@0 363 " ";
michael@0 364
michael@0 365 // Convert the text encoding above to RGBA.
michael@0 366 int w = FontWidth * 10;
michael@0 367 int h = FontHeight;
michael@0 368 uint32_t* buf = (uint32_t *) malloc(w * h * sizeof(uint32_t));
michael@0 369 for (int i = 0; i < h; i++) {
michael@0 370 for (int j = 0; j < w; j++) {
michael@0 371 uint32_t purple = 0xfff000ff;
michael@0 372 uint32_t white = 0xffffffff;
michael@0 373 buf[i * w + j] = (text[i * w + j] == ' ') ? purple : white;
michael@0 374 }
michael@0 375 }
michael@0 376
michael@0 377 int bytesPerPixel = 4;
michael@0 378 RefPtr<DataSourceSurface> fpsSurface = Factory::CreateWrappingDataSourceSurface(
michael@0 379 reinterpret_cast<uint8_t*>(buf), w * bytesPerPixel, IntSize(w, h), SurfaceFormat::B8G8R8A8);
michael@0 380 mFPSTextureSource = aCompositor->CreateDataTextureSource();
michael@0 381 mFPSTextureSource->Update(fpsSurface);
michael@0 382 }
michael@0 383
michael@0 384 EffectChain effectChain;
michael@0 385 effectChain.mPrimaryEffect = CreateTexturedEffect(SurfaceFormat::B8G8R8A8, mFPSTextureSource, Filter::POINT);
michael@0 386
michael@0 387 unsigned int fps = unsigned(mCompositionFps.AddFrameAndGetFps(aNow));
michael@0 388 unsigned int txnFps = unsigned(mTransactionFps.GetFpsAt(aNow));
michael@0 389
michael@0 390 DrawDigits(fps, 0, 0, aCompositor, effectChain);
michael@0 391 DrawDigits(txnFps, FontWidth * 4, 0, aCompositor, effectChain);
michael@0 392 DrawDigits(aFillRatio, FontWidth * 8, 0, aCompositor, effectChain);
michael@0 393 }
michael@0 394
michael@0 395 static uint16_t sFrameCount = 0;
michael@0 396 void
michael@0 397 LayerManagerComposite::RenderDebugOverlay(const Rect& aBounds)
michael@0 398 {
michael@0 399 if (gfxPrefs::LayersDrawFPS()) {
michael@0 400 if (!mFPS) {
michael@0 401 mFPS = new FPSState();
michael@0 402 }
michael@0 403
michael@0 404 float fillRatio = mCompositor->GetFillRatio();
michael@0 405 mFPS->DrawFPS(TimeStamp::Now(), unsigned(fillRatio), mCompositor);
michael@0 406 } else {
michael@0 407 mFPS = nullptr;
michael@0 408 }
michael@0 409
michael@0 410 if (gfxPrefs::DrawFrameCounter()) {
michael@0 411 profiler_set_frame_number(sFrameCount);
michael@0 412
michael@0 413 uint16_t frameNumber = sFrameCount;
michael@0 414 const uint16_t bitWidth = 3;
michael@0 415 float opacity = 1.0;
michael@0 416 gfx::Rect clip(0,0, bitWidth*16, bitWidth);
michael@0 417 for (size_t i = 0; i < 16; i++) {
michael@0 418
michael@0 419 gfx::Color bitColor;
michael@0 420 if ((frameNumber >> i) & 0x1) {
michael@0 421 bitColor = gfx::Color(0, 0, 0, 1.0);
michael@0 422 } else {
michael@0 423 bitColor = gfx::Color(1.0, 1.0, 1.0, 1.0);
michael@0 424 }
michael@0 425 EffectChain effects;
michael@0 426 effects.mPrimaryEffect = new EffectSolidColor(bitColor);
michael@0 427 mCompositor->DrawQuad(gfx::Rect(bitWidth*i, 0, bitWidth, bitWidth),
michael@0 428 clip,
michael@0 429 effects,
michael@0 430 opacity,
michael@0 431 gfx::Matrix4x4());
michael@0 432 }
michael@0 433 // We intentionally overflow at 2^16.
michael@0 434 sFrameCount++;
michael@0 435 }
michael@0 436 }
michael@0 437
michael@0 438 void
michael@0 439 LayerManagerComposite::Render()
michael@0 440 {
michael@0 441 PROFILER_LABEL("LayerManagerComposite", "Render");
michael@0 442 if (mDestroyed) {
michael@0 443 NS_WARNING("Call on destroyed layer manager");
michael@0 444 return;
michael@0 445 }
michael@0 446
michael@0 447 if (gfxPrefs::LayersDump()) {
michael@0 448 this->Dump();
michael@0 449 }
michael@0 450
michael@0 451 /** Our more efficient but less powerful alter ego, if one is available. */
michael@0 452 nsRefPtr<Composer2D> composer2D = mCompositor->GetWidget()->GetComposer2D();
michael@0 453
michael@0 454 if (!mTarget && composer2D && composer2D->TryRender(mRoot, mWorldMatrix, mGeometryChanged)) {
michael@0 455 if (mFPS) {
michael@0 456 double fps = mFPS->mCompositionFps.AddFrameAndGetFps(TimeStamp::Now());
michael@0 457 if (gfxPrefs::LayersDrawFPS()) {
michael@0 458 printf_stderr("HWComposer: FPS is %g\n", fps);
michael@0 459 }
michael@0 460 }
michael@0 461 mCompositor->EndFrameForExternalComposition(mWorldMatrix);
michael@0 462 return;
michael@0 463 }
michael@0 464
michael@0 465 {
michael@0 466 PROFILER_LABEL("LayerManagerComposite", "PreRender");
michael@0 467 if (!mCompositor->GetWidget()->PreRender(this)) {
michael@0 468 return;
michael@0 469 }
michael@0 470 }
michael@0 471
michael@0 472 nsIntRect clipRect;
michael@0 473 Rect bounds(mRenderBounds.x, mRenderBounds.y, mRenderBounds.width, mRenderBounds.height);
michael@0 474 Rect actualBounds;
michael@0 475 if (mRoot->GetClipRect()) {
michael@0 476 clipRect = *mRoot->GetClipRect();
michael@0 477 WorldTransformRect(clipRect);
michael@0 478 Rect rect(clipRect.x, clipRect.y, clipRect.width, clipRect.height);
michael@0 479 mCompositor->BeginFrame(mInvalidRegion, &rect, mWorldMatrix, bounds, nullptr, &actualBounds);
michael@0 480 } else {
michael@0 481 gfx::Rect rect;
michael@0 482 mCompositor->BeginFrame(mInvalidRegion, nullptr, mWorldMatrix, bounds, &rect, &actualBounds);
michael@0 483 clipRect = nsIntRect(rect.x, rect.y, rect.width, rect.height);
michael@0 484 }
michael@0 485
michael@0 486 // Reset the invalid region now that we've begun compositing.
michael@0 487 mInvalidRegion.SetEmpty();
michael@0 488
michael@0 489 if (actualBounds.IsEmpty()) {
michael@0 490 mCompositor->GetWidget()->PostRender(this);
michael@0 491 return;
michael@0 492 }
michael@0 493
michael@0 494 // Allow widget to render a custom background.
michael@0 495 mCompositor->GetWidget()->DrawWindowUnderlay(this, nsIntRect(actualBounds.x,
michael@0 496 actualBounds.y,
michael@0 497 actualBounds.width,
michael@0 498 actualBounds.height));
michael@0 499
michael@0 500 // Render our layers.
michael@0 501 RootLayer()->RenderLayer(clipRect);
michael@0 502
michael@0 503 if (!mRegionToClear.IsEmpty()) {
michael@0 504 nsIntRegionRectIterator iter(mRegionToClear);
michael@0 505 const nsIntRect *r;
michael@0 506 while ((r = iter.Next())) {
michael@0 507 mCompositor->ClearRect(Rect(r->x, r->y, r->width, r->height));
michael@0 508 }
michael@0 509 }
michael@0 510
michael@0 511 // Allow widget to render a custom foreground.
michael@0 512 mCompositor->GetWidget()->DrawWindowOverlay(this, nsIntRect(actualBounds.x,
michael@0 513 actualBounds.y,
michael@0 514 actualBounds.width,
michael@0 515 actualBounds.height));
michael@0 516
michael@0 517 // Debugging
michael@0 518 RenderDebugOverlay(actualBounds);
michael@0 519
michael@0 520 {
michael@0 521 PROFILER_LABEL("LayerManagerComposite", "EndFrame");
michael@0 522 mCompositor->EndFrame();
michael@0 523 mCompositor->SetFBAcquireFence(mRoot);
michael@0 524 }
michael@0 525
michael@0 526 mCompositor->GetWidget()->PostRender(this);
michael@0 527
michael@0 528 RecordFrame();
michael@0 529 }
michael@0 530
michael@0 531 void
michael@0 532 LayerManagerComposite::SetWorldTransform(const gfx::Matrix& aMatrix)
michael@0 533 {
michael@0 534 NS_ASSERTION(aMatrix.PreservesAxisAlignedRectangles(),
michael@0 535 "SetWorldTransform only accepts matrices that satisfy PreservesAxisAlignedRectangles");
michael@0 536 NS_ASSERTION(!aMatrix.HasNonIntegerScale(),
michael@0 537 "SetWorldTransform only accepts matrices with integer scale");
michael@0 538
michael@0 539 mWorldMatrix = aMatrix;
michael@0 540 }
michael@0 541
michael@0 542 gfx::Matrix&
michael@0 543 LayerManagerComposite::GetWorldTransform(void)
michael@0 544 {
michael@0 545 return mWorldMatrix;
michael@0 546 }
michael@0 547
michael@0 548 void
michael@0 549 LayerManagerComposite::WorldTransformRect(nsIntRect& aRect)
michael@0 550 {
michael@0 551 gfx::Rect grect(aRect.x, aRect.y, aRect.width, aRect.height);
michael@0 552 grect = mWorldMatrix.TransformBounds(grect);
michael@0 553 aRect.SetRect(grect.X(), grect.Y(), grect.Width(), grect.Height());
michael@0 554 }
michael@0 555
michael@0 556 static void
michael@0 557 SubtractTransformedRegion(nsIntRegion& aRegion,
michael@0 558 const nsIntRegion& aRegionToSubtract,
michael@0 559 const gfx3DMatrix& aTransform)
michael@0 560 {
michael@0 561 if (aRegionToSubtract.IsEmpty()) {
michael@0 562 return;
michael@0 563 }
michael@0 564
michael@0 565 // For each rect in the region, find out its bounds in screen space and
michael@0 566 // subtract it from the screen region.
michael@0 567 nsIntRegionRectIterator it(aRegionToSubtract);
michael@0 568 while (const nsIntRect* rect = it.Next()) {
michael@0 569 gfxRect incompleteRect = aTransform.TransformBounds(gfxRect(*rect));
michael@0 570 aRegion.Sub(aRegion, nsIntRect(incompleteRect.x,
michael@0 571 incompleteRect.y,
michael@0 572 incompleteRect.width,
michael@0 573 incompleteRect.height));
michael@0 574 }
michael@0 575 }
michael@0 576
michael@0 577 /* static */ void
michael@0 578 LayerManagerComposite::ComputeRenderIntegrityInternal(Layer* aLayer,
michael@0 579 nsIntRegion& aScreenRegion,
michael@0 580 nsIntRegion& aLowPrecisionScreenRegion,
michael@0 581 const gfx3DMatrix& aTransform)
michael@0 582 {
michael@0 583 if (aLayer->GetOpacity() <= 0.f ||
michael@0 584 (aScreenRegion.IsEmpty() && aLowPrecisionScreenRegion.IsEmpty())) {
michael@0 585 return;
michael@0 586 }
michael@0 587
michael@0 588 // If the layer's a container, recurse into all of its children
michael@0 589 ContainerLayer* container = aLayer->AsContainerLayer();
michael@0 590 if (container) {
michael@0 591 // Accumulate the transform of intermediate surfaces
michael@0 592 gfx3DMatrix transform = aTransform;
michael@0 593 if (container->UseIntermediateSurface()) {
michael@0 594 gfx::To3DMatrix(aLayer->GetEffectiveTransform(), transform);
michael@0 595 transform.PreMultiply(aTransform);
michael@0 596 }
michael@0 597 for (Layer* child = aLayer->GetFirstChild(); child;
michael@0 598 child = child->GetNextSibling()) {
michael@0 599 ComputeRenderIntegrityInternal(child, aScreenRegion, aLowPrecisionScreenRegion, transform);
michael@0 600 }
michael@0 601 return;
michael@0 602 }
michael@0 603
michael@0 604 // Only thebes layers can be incomplete
michael@0 605 ThebesLayer* thebesLayer = aLayer->AsThebesLayer();
michael@0 606 if (!thebesLayer) {
michael@0 607 return;
michael@0 608 }
michael@0 609
michael@0 610 // See if there's any incomplete rendering
michael@0 611 nsIntRegion incompleteRegion = aLayer->GetEffectiveVisibleRegion();
michael@0 612 incompleteRegion.Sub(incompleteRegion, thebesLayer->GetValidRegion());
michael@0 613
michael@0 614 if (!incompleteRegion.IsEmpty()) {
michael@0 615 // Calculate the transform to get between screen and layer space
michael@0 616 gfx3DMatrix transformToScreen;
michael@0 617 To3DMatrix(aLayer->GetEffectiveTransform(), transformToScreen);
michael@0 618 transformToScreen.PreMultiply(aTransform);
michael@0 619
michael@0 620 SubtractTransformedRegion(aScreenRegion, incompleteRegion, transformToScreen);
michael@0 621
michael@0 622 // See if there's any incomplete low-precision rendering
michael@0 623 TiledLayerComposer* composer = nullptr;
michael@0 624 LayerComposite* shadow = aLayer->AsLayerComposite();
michael@0 625 if (shadow) {
michael@0 626 composer = shadow->GetTiledLayerComposer();
michael@0 627 if (composer) {
michael@0 628 incompleteRegion.Sub(incompleteRegion, composer->GetValidLowPrecisionRegion());
michael@0 629 if (!incompleteRegion.IsEmpty()) {
michael@0 630 SubtractTransformedRegion(aLowPrecisionScreenRegion, incompleteRegion, transformToScreen);
michael@0 631 }
michael@0 632 }
michael@0 633 }
michael@0 634
michael@0 635 // If we can't get a valid low precision region, assume it's the same as
michael@0 636 // the high precision region.
michael@0 637 if (!composer) {
michael@0 638 SubtractTransformedRegion(aLowPrecisionScreenRegion, incompleteRegion, transformToScreen);
michael@0 639 }
michael@0 640 }
michael@0 641 }
michael@0 642
michael@0 643 #ifdef MOZ_ANDROID_OMTC
michael@0 644 static float
michael@0 645 GetDisplayportCoverage(const CSSRect& aDisplayPort,
michael@0 646 const gfx3DMatrix& aTransformToScreen,
michael@0 647 const nsIntRect& aScreenRect)
michael@0 648 {
michael@0 649 gfxRect transformedDisplayport =
michael@0 650 aTransformToScreen.TransformBounds(gfxRect(aDisplayPort.x,
michael@0 651 aDisplayPort.y,
michael@0 652 aDisplayPort.width,
michael@0 653 aDisplayPort.height));
michael@0 654 transformedDisplayport.RoundOut();
michael@0 655 nsIntRect displayport = nsIntRect(transformedDisplayport.x,
michael@0 656 transformedDisplayport.y,
michael@0 657 transformedDisplayport.width,
michael@0 658 transformedDisplayport.height);
michael@0 659 if (!displayport.Contains(aScreenRect)) {
michael@0 660 nsIntRegion coveredRegion;
michael@0 661 coveredRegion.And(aScreenRect, displayport);
michael@0 662 return coveredRegion.Area() / (float)(aScreenRect.width * aScreenRect.height);
michael@0 663 }
michael@0 664
michael@0 665 return 1.0f;
michael@0 666 }
michael@0 667 #endif // MOZ_ANDROID_OMTC
michael@0 668
michael@0 669 float
michael@0 670 LayerManagerComposite::ComputeRenderIntegrity()
michael@0 671 {
michael@0 672 // We only ever have incomplete rendering when progressive tiles are enabled.
michael@0 673 Layer* root = GetRoot();
michael@0 674 if (!gfxPrefs::UseProgressiveTilePainting() || !root) {
michael@0 675 return 1.f;
michael@0 676 }
michael@0 677
michael@0 678 const FrameMetrics& rootMetrics = root->AsContainerLayer()->GetFrameMetrics();
michael@0 679 nsIntRect screenRect(rootMetrics.mCompositionBounds.x,
michael@0 680 rootMetrics.mCompositionBounds.y,
michael@0 681 rootMetrics.mCompositionBounds.width,
michael@0 682 rootMetrics.mCompositionBounds.height);
michael@0 683
michael@0 684 float lowPrecisionMultiplier = 1.0f;
michael@0 685 float highPrecisionMultiplier = 1.0f;
michael@0 686
michael@0 687 #ifdef MOZ_ANDROID_OMTC
michael@0 688 // Use the transform on the primary scrollable layer and its FrameMetrics
michael@0 689 // to find out how much of the viewport the current displayport covers
michael@0 690 Layer* primaryScrollable = GetPrimaryScrollableLayer();
michael@0 691 if (primaryScrollable) {
michael@0 692 // This is derived from the code in
michael@0 693 // AsyncCompositionManager::TransformScrollableLayer
michael@0 694 const FrameMetrics& metrics = primaryScrollable->AsContainerLayer()->GetFrameMetrics();
michael@0 695 gfx3DMatrix transform;
michael@0 696 gfx::To3DMatrix(primaryScrollable->GetEffectiveTransform(), transform);
michael@0 697 transform.ScalePost(metrics.mResolution.scale, metrics.mResolution.scale, 1);
michael@0 698
michael@0 699 // Clip the screen rect to the document bounds
michael@0 700 gfxRect documentBounds =
michael@0 701 transform.TransformBounds(gfxRect(metrics.mScrollableRect.x - metrics.GetScrollOffset().x,
michael@0 702 metrics.mScrollableRect.y - metrics.GetScrollOffset().y,
michael@0 703 metrics.mScrollableRect.width,
michael@0 704 metrics.mScrollableRect.height));
michael@0 705 documentBounds.RoundOut();
michael@0 706 screenRect = screenRect.Intersect(nsIntRect(documentBounds.x, documentBounds.y,
michael@0 707 documentBounds.width, documentBounds.height));
michael@0 708
michael@0 709 // If the screen rect is empty, the user has scrolled entirely into
michael@0 710 // over-scroll and so we can be considered to have full integrity.
michael@0 711 if (screenRect.IsEmpty()) {
michael@0 712 return 1.0f;
michael@0 713 }
michael@0 714
michael@0 715 // Work out how much of the critical display-port covers the screen
michael@0 716 bool hasLowPrecision = false;
michael@0 717 if (!metrics.mCriticalDisplayPort.IsEmpty()) {
michael@0 718 hasLowPrecision = true;
michael@0 719 highPrecisionMultiplier =
michael@0 720 GetDisplayportCoverage(metrics.mCriticalDisplayPort, transform, screenRect);
michael@0 721 }
michael@0 722
michael@0 723 // Work out how much of the display-port covers the screen
michael@0 724 if (!metrics.mDisplayPort.IsEmpty()) {
michael@0 725 if (hasLowPrecision) {
michael@0 726 lowPrecisionMultiplier =
michael@0 727 GetDisplayportCoverage(metrics.mDisplayPort, transform, screenRect);
michael@0 728 } else {
michael@0 729 lowPrecisionMultiplier = highPrecisionMultiplier =
michael@0 730 GetDisplayportCoverage(metrics.mDisplayPort, transform, screenRect);
michael@0 731 }
michael@0 732 }
michael@0 733 }
michael@0 734
michael@0 735 // If none of the screen is covered, we have zero integrity.
michael@0 736 if (highPrecisionMultiplier <= 0.0f && lowPrecisionMultiplier <= 0.0f) {
michael@0 737 return 0.0f;
michael@0 738 }
michael@0 739 #endif // MOZ_ANDROID_OMTC
michael@0 740
michael@0 741 nsIntRegion screenRegion(screenRect);
michael@0 742 nsIntRegion lowPrecisionScreenRegion(screenRect);
michael@0 743 gfx3DMatrix transform;
michael@0 744 ComputeRenderIntegrityInternal(root, screenRegion,
michael@0 745 lowPrecisionScreenRegion, transform);
michael@0 746
michael@0 747 if (!screenRegion.IsEqual(screenRect)) {
michael@0 748 // Calculate the area of the region. All rects in an nsRegion are
michael@0 749 // non-overlapping.
michael@0 750 float screenArea = screenRect.width * screenRect.height;
michael@0 751 float highPrecisionIntegrity = screenRegion.Area() / screenArea;
michael@0 752 float lowPrecisionIntegrity = 1.f;
michael@0 753 if (!lowPrecisionScreenRegion.IsEqual(screenRect)) {
michael@0 754 lowPrecisionIntegrity = lowPrecisionScreenRegion.Area() / screenArea;
michael@0 755 }
michael@0 756
michael@0 757 return ((highPrecisionIntegrity * highPrecisionMultiplier) +
michael@0 758 (lowPrecisionIntegrity * lowPrecisionMultiplier)) / 2;
michael@0 759 }
michael@0 760
michael@0 761 return 1.f;
michael@0 762 }
michael@0 763
michael@0 764 already_AddRefed<ThebesLayerComposite>
michael@0 765 LayerManagerComposite::CreateThebesLayerComposite()
michael@0 766 {
michael@0 767 if (mDestroyed) {
michael@0 768 NS_WARNING("Call on destroyed layer manager");
michael@0 769 return nullptr;
michael@0 770 }
michael@0 771 return nsRefPtr<ThebesLayerComposite>(new ThebesLayerComposite(this)).forget();
michael@0 772 }
michael@0 773
michael@0 774 already_AddRefed<ContainerLayerComposite>
michael@0 775 LayerManagerComposite::CreateContainerLayerComposite()
michael@0 776 {
michael@0 777 if (mDestroyed) {
michael@0 778 NS_WARNING("Call on destroyed layer manager");
michael@0 779 return nullptr;
michael@0 780 }
michael@0 781 return nsRefPtr<ContainerLayerComposite>(new ContainerLayerComposite(this)).forget();
michael@0 782 }
michael@0 783
michael@0 784 already_AddRefed<ImageLayerComposite>
michael@0 785 LayerManagerComposite::CreateImageLayerComposite()
michael@0 786 {
michael@0 787 if (mDestroyed) {
michael@0 788 NS_WARNING("Call on destroyed layer manager");
michael@0 789 return nullptr;
michael@0 790 }
michael@0 791 return nsRefPtr<ImageLayerComposite>(new ImageLayerComposite(this)).forget();
michael@0 792 }
michael@0 793
michael@0 794 already_AddRefed<ColorLayerComposite>
michael@0 795 LayerManagerComposite::CreateColorLayerComposite()
michael@0 796 {
michael@0 797 if (LayerManagerComposite::mDestroyed) {
michael@0 798 NS_WARNING("Call on destroyed layer manager");
michael@0 799 return nullptr;
michael@0 800 }
michael@0 801 return nsRefPtr<ColorLayerComposite>(new ColorLayerComposite(this)).forget();
michael@0 802 }
michael@0 803
michael@0 804 already_AddRefed<CanvasLayerComposite>
michael@0 805 LayerManagerComposite::CreateCanvasLayerComposite()
michael@0 806 {
michael@0 807 if (LayerManagerComposite::mDestroyed) {
michael@0 808 NS_WARNING("Call on destroyed layer manager");
michael@0 809 return nullptr;
michael@0 810 }
michael@0 811 return nsRefPtr<CanvasLayerComposite>(new CanvasLayerComposite(this)).forget();
michael@0 812 }
michael@0 813
michael@0 814 already_AddRefed<RefLayerComposite>
michael@0 815 LayerManagerComposite::CreateRefLayerComposite()
michael@0 816 {
michael@0 817 if (LayerManagerComposite::mDestroyed) {
michael@0 818 NS_WARNING("Call on destroyed layer manager");
michael@0 819 return nullptr;
michael@0 820 }
michael@0 821 return nsRefPtr<RefLayerComposite>(new RefLayerComposite(this)).forget();
michael@0 822 }
michael@0 823
michael@0 824 LayerManagerComposite::AutoAddMaskEffect::AutoAddMaskEffect(Layer* aMaskLayer,
michael@0 825 EffectChain& aEffects,
michael@0 826 bool aIs3D)
michael@0 827 : mCompositable(nullptr)
michael@0 828 {
michael@0 829 if (!aMaskLayer) {
michael@0 830 return;
michael@0 831 }
michael@0 832
michael@0 833 mCompositable = ToLayerComposite(aMaskLayer)->GetCompositableHost();
michael@0 834 if (!mCompositable) {
michael@0 835 NS_WARNING("Mask layer with no compositable host");
michael@0 836 return;
michael@0 837 }
michael@0 838
michael@0 839 if (!mCompositable->AddMaskEffect(aEffects, aMaskLayer->GetEffectiveTransform(), aIs3D)) {
michael@0 840 mCompositable = nullptr;
michael@0 841 }
michael@0 842 }
michael@0 843
michael@0 844 LayerManagerComposite::AutoAddMaskEffect::~AutoAddMaskEffect()
michael@0 845 {
michael@0 846 if (!mCompositable) {
michael@0 847 return;
michael@0 848 }
michael@0 849
michael@0 850 mCompositable->RemoveMaskEffect();
michael@0 851 }
michael@0 852
michael@0 853 TemporaryRef<DrawTarget>
michael@0 854 LayerManagerComposite::CreateDrawTarget(const IntSize &aSize,
michael@0 855 SurfaceFormat aFormat)
michael@0 856 {
michael@0 857 #ifdef XP_MACOSX
michael@0 858 // We don't want to accelerate if the surface is too small which indicates
michael@0 859 // that it's likely used for an icon/static image. We also don't want to
michael@0 860 // accelerate anything that is above the maximum texture size of weakest gpu.
michael@0 861 // Safari uses 5000 area as the minimum for acceleration, we decided 64^2 is more logical.
michael@0 862 bool useAcceleration = aSize.width <= 4096 && aSize.height <= 4096 &&
michael@0 863 aSize.width > 64 && aSize.height > 64 &&
michael@0 864 gfxPlatformMac::GetPlatform()->UseAcceleratedCanvas();
michael@0 865 if (useAcceleration) {
michael@0 866 return Factory::CreateDrawTarget(BackendType::COREGRAPHICS_ACCELERATED,
michael@0 867 aSize, aFormat);
michael@0 868 }
michael@0 869 #endif
michael@0 870 return LayerManager::CreateDrawTarget(aSize, aFormat);
michael@0 871 }
michael@0 872
michael@0 873 LayerComposite::LayerComposite(LayerManagerComposite *aManager)
michael@0 874 : mCompositeManager(aManager)
michael@0 875 , mCompositor(aManager->GetCompositor())
michael@0 876 , mShadowOpacity(1.0)
michael@0 877 , mUseShadowClipRect(false)
michael@0 878 , mShadowTransformSetByAnimation(false)
michael@0 879 , mDestroyed(false)
michael@0 880 , mLayerComposited(false)
michael@0 881 { }
michael@0 882
michael@0 883 LayerComposite::~LayerComposite()
michael@0 884 {
michael@0 885 }
michael@0 886
michael@0 887 void
michael@0 888 LayerComposite::Destroy()
michael@0 889 {
michael@0 890 if (!mDestroyed) {
michael@0 891 mDestroyed = true;
michael@0 892 CleanupResources();
michael@0 893 }
michael@0 894 }
michael@0 895
michael@0 896 bool
michael@0 897 LayerManagerComposite::CanUseCanvasLayerForSize(const IntSize &aSize)
michael@0 898 {
michael@0 899 return mCompositor->CanUseCanvasLayerForSize(gfx::IntSize(aSize.width,
michael@0 900 aSize.height));
michael@0 901 }
michael@0 902
michael@0 903 void
michael@0 904 LayerManagerComposite::NotifyShadowTreeTransaction()
michael@0 905 {
michael@0 906 if (mFPS) {
michael@0 907 mFPS->NotifyShadowTreeTransaction();
michael@0 908 }
michael@0 909 }
michael@0 910
michael@0 911 #ifndef MOZ_HAVE_PLATFORM_SPECIFIC_LAYER_BUFFERS
michael@0 912
michael@0 913 /*static*/ bool
michael@0 914 LayerManagerComposite::SupportsDirectTexturing()
michael@0 915 {
michael@0 916 return false;
michael@0 917 }
michael@0 918
michael@0 919 /*static*/ void
michael@0 920 LayerManagerComposite::PlatformSyncBeforeReplyUpdate()
michael@0 921 {
michael@0 922 }
michael@0 923
michael@0 924 #endif // !defined(MOZ_HAVE_PLATFORM_SPECIFIC_LAYER_BUFFERS)
michael@0 925
michael@0 926 } /* layers */
michael@0 927 } /* mozilla */

mercurial