LCOV - code coverage report
Current view: top level - gfx/layers - PersistentBufferProvider.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 210 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 22 0.0 %
Legend: Lines: hit not hit

          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 "PersistentBufferProvider.h"
       7             : 
       8             : #include "Layers.h"
       9             : #include "mozilla/layers/ShadowLayers.h"
      10             : #include "mozilla/gfx/Logging.h"
      11             : #include "pratom.h"
      12             : #include "gfxPlatform.h"
      13             : 
      14             : namespace mozilla {
      15             : 
      16             : using namespace gfx;
      17             : 
      18             : namespace layers {
      19             : 
      20           0 : PersistentBufferProviderBasic::PersistentBufferProviderBasic(DrawTarget* aDt)
      21           0 : : mDrawTarget(aDt)
      22             : {
      23           0 :   MOZ_COUNT_CTOR(PersistentBufferProviderBasic);
      24           0 : }
      25             : 
      26           0 : PersistentBufferProviderBasic::~PersistentBufferProviderBasic()
      27             : {
      28           0 :   MOZ_COUNT_DTOR(PersistentBufferProviderBasic);
      29           0 : }
      30             : 
      31             : already_AddRefed<gfx::DrawTarget>
      32           0 : PersistentBufferProviderBasic::BorrowDrawTarget(const gfx::IntRect& aPersistedRect)
      33             : {
      34           0 :   MOZ_ASSERT(!mSnapshot);
      35           0 :   RefPtr<gfx::DrawTarget> dt(mDrawTarget);
      36           0 :   return dt.forget();
      37             : }
      38             : 
      39             : bool
      40           0 : PersistentBufferProviderBasic::ReturnDrawTarget(already_AddRefed<gfx::DrawTarget> aDT)
      41             : {
      42           0 :   RefPtr<gfx::DrawTarget> dt(aDT);
      43           0 :   MOZ_ASSERT(mDrawTarget == dt);
      44           0 :   if (dt) {
      45             :     // Since SkiaGL default to storing drawing command until flush
      46             :     // we have to flush it before present.
      47           0 :     dt->Flush();
      48             :   }
      49           0 :   return true;
      50             : }
      51             : 
      52             : already_AddRefed<gfx::SourceSurface>
      53           0 : PersistentBufferProviderBasic::BorrowSnapshot()
      54             : {
      55           0 :   mSnapshot = mDrawTarget->Snapshot();
      56           0 :   RefPtr<SourceSurface> snapshot = mSnapshot;
      57           0 :   return snapshot.forget();
      58             : }
      59             : 
      60             : void
      61           0 : PersistentBufferProviderBasic::ReturnSnapshot(already_AddRefed<gfx::SourceSurface> aSnapshot)
      62             : {
      63           0 :   RefPtr<SourceSurface> snapshot = aSnapshot;
      64           0 :   MOZ_ASSERT(!snapshot || snapshot == mSnapshot);
      65           0 :   mSnapshot = nullptr;
      66           0 : }
      67             : 
      68             : //static
      69             : already_AddRefed<PersistentBufferProviderBasic>
      70           0 : PersistentBufferProviderBasic::Create(gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
      71             :                                       gfx::BackendType aBackend)
      72             : {
      73           0 :   RefPtr<DrawTarget> dt = gfxPlatform::GetPlatform()->CreateDrawTargetForBackend(aBackend, aSize, aFormat);
      74             : 
      75           0 :   if (!dt) {
      76           0 :     return nullptr;
      77             :   }
      78             : 
      79             :   RefPtr<PersistentBufferProviderBasic> provider =
      80           0 :     new PersistentBufferProviderBasic(dt);
      81             : 
      82           0 :   return provider.forget();
      83             : }
      84             : 
      85             : 
      86             : //static
      87             : already_AddRefed<PersistentBufferProviderShared>
      88           0 : PersistentBufferProviderShared::Create(gfx::IntSize aSize,
      89             :                                        gfx::SurfaceFormat aFormat,
      90             :                                        ShadowLayerForwarder* aFwd)
      91             : {
      92           0 :   if (!aFwd || !aFwd->GetTextureForwarder()->IPCOpen()) {
      93           0 :     return nullptr;
      94             :   }
      95             : 
      96           0 :   RefPtr<TextureClient> texture = TextureClient::CreateForDrawing(
      97             :     aFwd, aFormat, aSize,
      98             :     BackendSelector::Canvas,
      99             :     TextureFlags::DEFAULT,
     100             :     TextureAllocationFlags::ALLOC_DEFAULT
     101           0 :   );
     102             : 
     103           0 :   if (!texture) {
     104           0 :     return nullptr;
     105             :   }
     106             : 
     107             :   RefPtr<PersistentBufferProviderShared> provider =
     108           0 :     new PersistentBufferProviderShared(aSize, aFormat, aFwd, texture);
     109           0 :   return provider.forget();
     110             : }
     111             : 
     112           0 : PersistentBufferProviderShared::PersistentBufferProviderShared(gfx::IntSize aSize,
     113             :                                                                gfx::SurfaceFormat aFormat,
     114             :                                                                ShadowLayerForwarder* aFwd,
     115           0 :                                                                RefPtr<TextureClient>& aTexture)
     116             : 
     117             : : mSize(aSize)
     118             : , mFormat(aFormat)
     119             : , mFwd(aFwd)
     120           0 : , mFront(Nothing())
     121             : {
     122           0 :   if (mTextures.append(aTexture)) {
     123           0 :     mBack = Some<uint32_t>(0);
     124             :   }
     125           0 :   MOZ_COUNT_CTOR(PersistentBufferProviderShared);
     126           0 : }
     127             : 
     128           0 : PersistentBufferProviderShared::~PersistentBufferProviderShared()
     129             : {
     130           0 :   MOZ_COUNT_DTOR(PersistentBufferProviderShared);
     131             : 
     132           0 :   if (IsActivityTracked()) {
     133           0 :     mFwd->GetActiveResourceTracker().RemoveObject(this);
     134             :   }
     135             : 
     136           0 :   Destroy();
     137           0 : }
     138             : 
     139             : bool
     140           0 : PersistentBufferProviderShared::SetForwarder(ShadowLayerForwarder* aFwd)
     141             : {
     142           0 :   MOZ_ASSERT(aFwd);
     143           0 :   if (!aFwd) {
     144           0 :     return false;
     145             :   }
     146             : 
     147           0 :   if (mFwd == aFwd) {
     148             :     // The forwarder should not change most of the time.
     149           0 :     return true;
     150             :   }
     151             : 
     152           0 :   if (IsActivityTracked()) {
     153           0 :     mFwd->GetActiveResourceTracker().RemoveObject(this);
     154             :   }
     155             : 
     156           0 :   if (mFwd->GetTextureForwarder() != aFwd->GetTextureForwarder() ||
     157           0 :       mFwd->GetCompositorBackendType() != aFwd->GetCompositorBackendType()) {
     158             :     // We are going to be used with an different and/or incompatible forwarder.
     159             :     // This should be extremely rare. We have to copy the front buffer into a
     160             :     // texture that is compatible with the new forwarder.
     161             : 
     162             :     // Grab the current front buffer.
     163           0 :     RefPtr<TextureClient> prevTexture = GetTexture(mFront);
     164             : 
     165             :     // Get rid of everything else
     166           0 :     Destroy();
     167             : 
     168           0 :     if (prevTexture) {
     169           0 :       RefPtr<TextureClient> newTexture = TextureClient::CreateForDrawing(
     170             :         aFwd, mFormat, mSize,
     171             :         BackendSelector::Canvas,
     172             :         TextureFlags::DEFAULT,
     173             :         TextureAllocationFlags::ALLOC_DEFAULT
     174           0 :       );
     175             : 
     176           0 :       MOZ_ASSERT(newTexture);
     177           0 :       if (!newTexture) {
     178           0 :         return false;
     179             :       }
     180             : 
     181             :       // If we early-return in one of the following branches, we will
     182             :       // leave the buffer provider in an empty state, since we called
     183             :       // Destroy. Not ideal but at least we won't try to use it with a
     184             :       // an incompatible ipc channel.
     185             : 
     186           0 :       if (!newTexture->Lock(OpenMode::OPEN_WRITE)) {
     187           0 :         return false;
     188             :       }
     189             : 
     190           0 :       if (!prevTexture->Lock(OpenMode::OPEN_READ)) {
     191           0 :         newTexture->Unlock();
     192           0 :         return false;
     193             :       }
     194             : 
     195           0 :       bool success = prevTexture->CopyToTextureClient(newTexture, nullptr, nullptr);
     196             : 
     197           0 :       prevTexture->Unlock();
     198           0 :       newTexture->Unlock();
     199             : 
     200           0 :       if (!success) {
     201           0 :         return false;
     202             :       }
     203             : 
     204           0 :       if (!mTextures.append(newTexture)) {
     205           0 :         return false;
     206             :       }
     207           0 :       mFront = Some<uint32_t>(mTextures.length() - 1);
     208           0 :       mBack = mFront;
     209             :     }
     210             :   }
     211             : 
     212           0 :   mFwd = aFwd;
     213             : 
     214           0 :   return true;
     215             : }
     216             : 
     217             : TextureClient*
     218           0 : PersistentBufferProviderShared::GetTexture(const Maybe<uint32_t>& aIndex)
     219             : {
     220           0 :   if (aIndex.isNothing() || !CheckIndex(aIndex.value())) {
     221           0 :     return nullptr;
     222             :   }
     223           0 :   return mTextures[aIndex.value()];
     224             : }
     225             : 
     226             : already_AddRefed<gfx::DrawTarget>
     227           0 : PersistentBufferProviderShared::BorrowDrawTarget(const gfx::IntRect& aPersistedRect)
     228             : {
     229           0 :   if (!mFwd->GetTextureForwarder()->IPCOpen()) {
     230           0 :     return nullptr;
     231             :   }
     232             : 
     233           0 :   MOZ_ASSERT(!mSnapshot);
     234             : 
     235           0 :   if (IsActivityTracked()) {
     236           0 :     mFwd->GetActiveResourceTracker().MarkUsed(this);
     237             :   } else {
     238           0 :     mFwd->GetActiveResourceTracker().AddObject(this);
     239             :   }
     240             : 
     241           0 :   if (mDrawTarget) {
     242           0 :     RefPtr<gfx::DrawTarget> dt(mDrawTarget);
     243           0 :     return dt.forget();
     244             :   }
     245             : 
     246           0 :   auto previousBackBuffer = mBack;
     247             : 
     248           0 :   TextureClient* tex = GetTexture(mBack);
     249             : 
     250             :   // First try to reuse the current back buffer. If we can do that it means
     251             :   // we can skip copying its content to the new back buffer.
     252           0 :   if (tex && tex->IsReadLocked()) {
     253             :     // The back buffer is currently used by the compositor, we can't draw
     254             :     // into it.
     255           0 :     tex = nullptr;
     256             :   }
     257             : 
     258           0 :   if (!tex) {
     259             :     // Try to grab an already allocated texture if any is available.
     260           0 :     for (uint32_t i = 0; i < mTextures.length(); ++i) {
     261           0 :       if (!mTextures[i]->IsReadLocked()) {
     262           0 :         mBack = Some(i);
     263           0 :         tex = mTextures[i];
     264           0 :         break;
     265             :       }
     266             :     }
     267             :   }
     268             : 
     269           0 :   if (!tex) {
     270             :     // We have to allocate a new texture.
     271           0 :     if (mTextures.length() >= 4) {
     272             :       // We should never need to buffer that many textures, something's wrong.
     273             :       // In theory we throttle the main thread when the compositor can't keep up,
     274             :       // so we shoud never get in a situation where we sent 4 textures to the
     275             :       // compositor and the latter has not released any of them.
     276             :       // In practice, though, the throttling mechanism appears to have some issues,
     277             :       // especially when switching between layer managers (during tab-switch).
     278             :       // To make sure we don't get too far ahead of the compositor, we send a
     279             :       // sync ping to the compositor thread...
     280           0 :       mFwd->SyncWithCompositor();
     281             :       // ...and try again.
     282           0 :       for (uint32_t i = 0; i < mTextures.length(); ++i) {
     283           0 :         if (!mTextures[i]->IsReadLocked()) {
     284           0 :           gfxCriticalNote << "Managed to allocate after flush.";
     285           0 :           mBack = Some(i);
     286           0 :           tex = mTextures[i];
     287           0 :           break;
     288             :         }
     289             :       }
     290             : 
     291           0 :       if (!tex) {
     292           0 :         gfxCriticalError() << "Unexpected BufferProvider over-production.";
     293             :         // It would be pretty bad to keep piling textures up at this point so we
     294             :         // call NotifyInactive to remove some of our textures.
     295           0 :         NotifyInactive();
     296             :         // Give up now. The caller can fall-back to a non-shared buffer provider.
     297           0 :         return nullptr;
     298             :       }
     299             :     }
     300             : 
     301           0 :     RefPtr<TextureClient> newTexture = TextureClient::CreateForDrawing(
     302             :       mFwd, mFormat, mSize,
     303             :       BackendSelector::Canvas,
     304             :       TextureFlags::DEFAULT,
     305             :       TextureAllocationFlags::ALLOC_DEFAULT
     306           0 :     );
     307             : 
     308           0 :     MOZ_ASSERT(newTexture);
     309           0 :     if (newTexture) {
     310           0 :       if (mTextures.append(newTexture)) {
     311           0 :         tex = newTexture;
     312           0 :         mBack = Some<uint32_t>(mTextures.length() - 1);
     313             :       }
     314             :     }
     315             :   }
     316             : 
     317           0 :   if (!tex || !tex->Lock(OpenMode::OPEN_READ_WRITE)) {
     318           0 :     return nullptr;
     319             :   }
     320             : 
     321           0 :   if (mBack != previousBackBuffer && !aPersistedRect.IsEmpty()) {
     322           0 :     TextureClient* previous = GetTexture(previousBackBuffer);
     323           0 :     if (previous && previous->Lock(OpenMode::OPEN_READ)) {
     324           0 :       DebugOnly<bool> success = previous->CopyToTextureClient(tex, &aPersistedRect, nullptr);
     325           0 :       MOZ_ASSERT(success);
     326             : 
     327           0 :       previous->Unlock();
     328             :     }
     329             :   }
     330             : 
     331           0 :   mDrawTarget = tex->BorrowDrawTarget();
     332             : 
     333           0 :   RefPtr<gfx::DrawTarget> dt(mDrawTarget);
     334           0 :   return dt.forget();
     335             : }
     336             : 
     337             : bool
     338           0 : PersistentBufferProviderShared::ReturnDrawTarget(already_AddRefed<gfx::DrawTarget> aDT)
     339             : {
     340           0 :   RefPtr<gfx::DrawTarget> dt(aDT);
     341           0 :   MOZ_ASSERT(mDrawTarget == dt);
     342             :   // Can't change the current front buffer while its snapshot is borrowed!
     343           0 :   MOZ_ASSERT(!mSnapshot);
     344             : 
     345           0 :   mDrawTarget = nullptr;
     346           0 :   dt = nullptr;
     347             : 
     348           0 :   TextureClient* back = GetTexture(mBack);
     349           0 :   MOZ_ASSERT(back);
     350             : 
     351           0 :   if (back) {
     352           0 :     back->Unlock();
     353           0 :     mFront = mBack;
     354             :   }
     355             : 
     356           0 :   return !!back;
     357             : }
     358             : 
     359             : TextureClient*
     360           0 : PersistentBufferProviderShared::GetTextureClient()
     361             : {
     362             :   // Can't access the front buffer while drawing.
     363           0 :   MOZ_ASSERT(!mDrawTarget);
     364           0 :   TextureClient* texture = GetTexture(mFront);
     365           0 :   if (texture) {
     366           0 :     texture->EnableReadLock();
     367             :   } else {
     368           0 :     gfxCriticalNote << "PersistentBufferProviderShared: front buffer unavailable";
     369             :   }
     370           0 :   return texture;
     371             : }
     372             : 
     373             : already_AddRefed<gfx::SourceSurface>
     374           0 : PersistentBufferProviderShared::BorrowSnapshot()
     375             : {
     376           0 :   MOZ_ASSERT(!mDrawTarget);
     377             : 
     378           0 :   auto front = GetTexture(mFront);
     379           0 :   if (!front || front->IsLocked()) {
     380           0 :     MOZ_ASSERT(false);
     381             :     return nullptr;
     382             :   }
     383             : 
     384           0 :   if (!front->Lock(OpenMode::OPEN_READ)) {
     385           0 :     return nullptr;
     386             :   }
     387             : 
     388           0 :   RefPtr<DrawTarget> dt = front->BorrowDrawTarget();
     389             : 
     390           0 :   if (!dt) {
     391           0 :     front->Unlock();
     392           0 :     return nullptr;
     393             :   }
     394             : 
     395           0 :   mSnapshot = dt->Snapshot();
     396             : 
     397           0 :   RefPtr<SourceSurface> snapshot = mSnapshot;
     398           0 :   return snapshot.forget();
     399             : }
     400             : 
     401             : void
     402           0 : PersistentBufferProviderShared::ReturnSnapshot(already_AddRefed<gfx::SourceSurface> aSnapshot)
     403             : {
     404           0 :   RefPtr<SourceSurface> snapshot = aSnapshot;
     405           0 :   MOZ_ASSERT(!snapshot || snapshot == mSnapshot);
     406             : 
     407           0 :   mSnapshot = nullptr;
     408           0 :   snapshot = nullptr;
     409             : 
     410           0 :   auto front = GetTexture(mFront);
     411           0 :   if (front) {
     412           0 :     front->Unlock();
     413             :   }
     414           0 : }
     415             : 
     416             : void
     417           0 : PersistentBufferProviderShared::NotifyInactive()
     418             : {
     419           0 :   ClearCachedResources();
     420           0 : }
     421             : 
     422             : void
     423           0 : PersistentBufferProviderShared::ClearCachedResources()
     424             : {
     425           0 :   RefPtr<TextureClient> front = GetTexture(mFront);
     426           0 :   RefPtr<TextureClient> back = GetTexture(mBack);
     427             : 
     428             :   // Clear all textures (except the front and back ones that we just kept).
     429           0 :   mTextures.clear();
     430             : 
     431           0 :   if (back) {
     432           0 :     if (mTextures.append(back)) {
     433           0 :       mBack = Some<uint32_t>(0);
     434             :     }
     435           0 :     if (front == back) {
     436           0 :       mFront = mBack;
     437             :     }
     438             :   }
     439             : 
     440           0 :   if (front && front != back) {
     441           0 :     if (mTextures.append(front)) {
     442           0 :       mFront = Some<uint32_t>(mTextures.length() - 1);
     443             :     }
     444             :   }
     445           0 : }
     446             : 
     447             : void
     448           0 : PersistentBufferProviderShared::Destroy()
     449             : {
     450           0 :   mSnapshot = nullptr;
     451           0 :   mDrawTarget = nullptr;
     452             : 
     453           0 :   for (auto& mTexture : mTextures) {
     454           0 :     TextureClient* texture = mTexture;
     455           0 :     if (texture && texture->IsLocked()) {
     456           0 :       MOZ_ASSERT(false);
     457             :       texture->Unlock();
     458             :     }
     459             :   }
     460             : 
     461           0 :   mTextures.clear();
     462           0 : }
     463             : 
     464             : } // namespace layers
     465             : } // namespace mozilla

Generated by: LCOV version 1.13